diff mbox series

introduce EH_ELSE tree and gimplifier

Message ID ord0iz32j2.fsf@lxoliva.fsfla.org
State New
Headers show
Series introduce EH_ELSE tree and gimplifier | expand

Commit Message

Alexandre Oliva June 27, 2019, 7:34 a.m. UTC
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 tree, and logic to dump
it and to gimplify it.

Regstrapped on x86_64-linux-gnu.  Ok to install?


for  gcc/ChangeLog

	* doc/generic.texi (Cleanups): Document EH_ELSE.
	* 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): Introduce.
---
 gcc/doc/generic.texi    |    5 +++++
 gcc/except.c            |   12 ++++++------
 gcc/expr.c              |    1 +
 gcc/gimplify.c          |   18 +++++++++++++++++-
 gcc/tree-dump.c         |    1 +
 gcc/tree-pretty-print.c |   11 +++++++++++
 gcc/tree.c              |    3 +++
 gcc/tree.def            |    7 +++++++
 8 files changed, 51 insertions(+), 7 deletions(-)

Comments

Richard Biener June 27, 2019, 9:39 a.m. UTC | #1
On Thu, Jun 27, 2019 at 10:18 AM Alexandre Oliva <oliva@adacore.com> wrote:
>
> 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 tree, and logic to dump
> it and to gimplify it.
>
> Regstrapped on x86_64-linux-gnu.  Ok to install?
>
>
> for  gcc/ChangeLog
>
>         * doc/generic.texi (Cleanups): Document EH_ELSE.
>         * 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): Introduce.
> ---
>  gcc/doc/generic.texi    |    5 +++++
>  gcc/except.c            |   12 ++++++------
>  gcc/expr.c              |    1 +
>  gcc/gimplify.c          |   18 +++++++++++++++++-
>  gcc/tree-dump.c         |    1 +
>  gcc/tree-pretty-print.c |   11 +++++++++++
>  gcc/tree.c              |    3 +++
>  gcc/tree.def            |    7 +++++++
>  8 files changed, 51 insertions(+), 7 deletions(-)
>
> diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
> index 67f7ad53af6b..1d0e3cfec1d6 100644
> --- a/gcc/doc/generic.texi
> +++ b/gcc/doc/generic.texi
> @@ -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} 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
> diff --git a/gcc/except.c b/gcc/except.c
> index edaeeb4cfd1b..76cd099749f3 100644
> --- a/gcc/except.c
> +++ b/gcc/except.c
> @@ -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, 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.
> diff --git a/gcc/expr.c b/gcc/expr.c
> index c78bc74c0d9f..70fb721a9621 100644
> --- a/gcc/expr.c
> +++ b/gcc/expr.c
> @@ -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:
>        /* Lowered by tree-eh.c.  */
>        gcc_unreachable ();
>
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index 0b25e7100cde..de4cb66e2b65 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -13074,7 +13074,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)
> +             {
> +               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))
>               {
> @@ -13632,6 +13647,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
>                   && code != OACC_PARALLEL
>                   && code != OACC_KERNELS
>                   && code != OACC_DATA
> diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c
> index 58cb1ee5a729..f7c89c3374ff 100644
> --- a/gcc/tree-dump.c
> +++ b/gcc/tree-dump.c
> @@ -604,6 +604,7 @@ dequeue_and_dump (dump_info_p di)
>        break;
>
>      case TRY_FINALLY_EXPR:
> +    case EH_ELSE:
>        dump_child ("op 0", TREE_OPERAND (t, 0));
>        dump_child ("op 1", TREE_OPERAND (t, 1));
>        break;
> diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
> index 329cc6fceeb2..663616d0a0f3 100644
> --- a/gcc/tree-pretty-print.c
> +++ b/gcc/tree-pretty-print.c
> @@ -2823,6 +2823,17 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
>        is_expr = false;
>        break;
>
> +    case EH_ELSE:
> +      pp_string (pp, "<<normal>>:");
> +      newline_and_indent (pp, spc+2);
> +      dump_generic_node (pp, TREE_OPERAND (node, 0), spc+2, flags, true);
> +      newline_and_indent (pp, spc);
> +      pp_string (pp, "<<except>>:");
> +      newline_and_indent (pp, spc+2);
> +      dump_generic_node (pp, TREE_OPERAND (node, 1), spc+2, flags, true);
> +      is_expr = false;
> +      break;
> +
>      case CATCH_EXPR:
>        pp_string (pp, "catch (");
>        dump_generic_node (pp, CATCH_TYPES (node), spc+2, flags, false);
> diff --git a/gcc/tree.c b/gcc/tree.c
> index c97facd7ce50..8f6f6c43b6ce 100644
> --- a/gcc/tree.c
> +++ b/gcc/tree.c
> @@ -13408,6 +13408,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:
> +      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);
> diff --git a/gcc/tree.def b/gcc/tree.def
> index 10a14fc23b0c..9cf53964f8eb 100644
> --- a/gcc/tree.def
> +++ b/gcc/tree.def
> @@ -909,6 +909,13 @@ DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", tcc_statement, 2)
>     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)
> +
> +/* 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 is used as a cleanup, otherwise the second operand is
> +   used.  */
> +DEFTREECODE (EH_ELSE, "eh_else", tcc_statement, 2)

It's a bit weird that this is a tcc_statement as opposed to tcc_expression,
also I'd have called it EH_ELSE_EXPR for clarity.

I also wonder why TRY_FINALLY_EXPR didn't just get a third optional
operand?

Richard.

>
>  /* These types of expressions have no useful value,
>     and always have side effects.  */
>
>
> --
> Alexandre Oliva, freedom fighter  he/him   https://FSFLA.org/blogs/lxo
> Be the change, be Free!                 FSF Latin America board member
> GNU Toolchain Engineer                        Free Software Evangelist
> Hay que enGNUrecerse, pero sin perder la terGNUra jamás - Che GNUevara
Alexandre Oliva June 28, 2019, 3:21 a.m. UTC | #2
On Jun 27, 2019, Richard Biener <richard.guenther@gmail.com> wrote:

> On Thu, Jun 27, 2019 at 10:18 AM Alexandre Oliva <oliva@adacore.com> wrote:

>> @@ -909,6 +909,13 @@ DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", tcc_statement, 2)
>> 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)
>> +
>> +/* 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 is used as a cleanup, otherwise the second operand is
>> +   used.  */
>> +DEFTREECODE (EH_ELSE, "eh_else", tcc_statement, 2)

> It's a bit weird that this is a tcc_statement as opposed to tcc_expression,

Erhm...  What's weird about it?  It is not something that belongs in an
arbitrary expr, it's a lot more like a top-level statement, like
try_finally, having side effects but no useful value.

> also I'd have called it EH_ELSE_EXPR for clarity.

Now *that* would be weird IMHO.  No offense intended, but I'd have
dropped the _EXPR from TRY_FINALLY_EXPR to make it match the
"try_finally" string.

What reasons are there for them to deserve the _EXPR suffix?

If I rename it to EH_ELSE_EXPR, should GIMPLE_EH_ELSE also get a _EXPR
suffix?


> I also wonder why TRY_FINALLY_EXPR didn't just get a third optional
> operand?

I considered that possibility, but I didn't expect EH_ELSE to be used
often enough to bloat every TRY_FINALLY_EXPR with another operand, plus
a flag or some other means to remove ambiguity between same-cleanup and
no-else-cleanup.
Richard Biener July 1, 2019, 11:12 a.m. UTC | #3
On Fri, Jun 28, 2019 at 5:21 AM Alexandre Oliva <oliva@adacore.com> wrote:
>
> On Jun 27, 2019, Richard Biener <richard.guenther@gmail.com> wrote:
>
> > On Thu, Jun 27, 2019 at 10:18 AM Alexandre Oliva <oliva@adacore.com> wrote:
>
> >> @@ -909,6 +909,13 @@ DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", tcc_statement, 2)
> >> 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)
> >> +
> >> +/* 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 is used as a cleanup, otherwise the second operand is
> >> +   used.  */
> >> +DEFTREECODE (EH_ELSE, "eh_else", tcc_statement, 2)
>
> > It's a bit weird that this is a tcc_statement as opposed to tcc_expression,
>
> Erhm...  What's weird about it?  It is not something that belongs in an
> arbitrary expr, it's a lot more like a top-level statement, like
> try_finally, having side effects but no useful value.

It's weird because it appears in a TRY_FINALLY statement operand.
But I guess the line between statements and expressions in GENERIC
is muddy...

> > also I'd have called it EH_ELSE_EXPR for clarity.
>
> Now *that* would be weird IMHO.  No offense intended, but I'd have
> dropped the _EXPR from TRY_FINALLY_EXPR to make it match the
> "try_finally" string.

OK, let me say for consistency then ...

> What reasons are there for them to deserve the _EXPR suffix?

History I guess?  All 'old' tcc_statement are _EXPR.

> If I rename it to EH_ELSE_EXPR, should GIMPLE_EH_ELSE also get a _EXPR
> suffix?
>
>
> > I also wonder why TRY_FINALLY_EXPR didn't just get a third optional
> > operand?
>
> I considered that possibility, but I didn't expect EH_ELSE to be used
> often enough to bloat every TRY_FINALLY_EXPR with another operand, plus
> a flag or some other means to remove ambiguity between same-cleanup and
> no-else-cleanup.

Fair enough.

Richard.

>
> --
> Alexandre Oliva, freedom fighter  he/him   https://FSFLA.org/blogs/lxo
> Be the change, be Free!                 FSF Latin America board member
> GNU Toolchain Engineer                        Free Software Evangelist
> Hay que enGNUrecerse, pero sin perder la terGNUra jamás - Che GNUevara
Alexandre Oliva July 4, 2019, 8:18 a.m. UTC | #4
On Jul  1, 2019, Richard Biener <richard.guenther@gmail.com> wrote:

> On Fri, Jun 28, 2019 at 5:21 AM Alexandre Oliva <oliva@adacore.com> wrote:
>> 
>> On Jun 27, 2019, Richard Biener <richard.guenther@gmail.com> wrote:
>> 
>> > On Thu, Jun 27, 2019 at 10:18 AM Alexandre Oliva <oliva@adacore.com> wrote:
>> 
>> >> @@ -909,6 +909,13 @@ DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", tcc_statement, 2)
>> >> 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)
>> >> +
>> >> +/* 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 is used as a cleanup, otherwise the second operand is
>> >> +   used.  */
>> >> +DEFTREECODE (EH_ELSE, "eh_else", tcc_statement, 2)
>> 
>> > It's a bit weird that this is a tcc_statement as opposed to tcc_expression,

>> Erhm...  What's weird about it?  It is not something that belongs in an
>> arbitrary expr, it's a lot more like a top-level statement, like
>> try_finally, having side effects but no useful value.

> It's weird because it appears in a TRY_FINALLY statement operand.

The other operand could be a nested TRY_FINALLY, but that doesn't make
TRY_FINALLY a tcc_expression.

> But I guess the line between statements and expressions in GENERIC
> is muddy...

My understanding of the general rule is that tcc_expressions have
values, whereas tcc_statements don't.

>> > also I'd have called it EH_ELSE_EXPR for clarity.

>> Now *that* would be weird IMHO.  No offense intended, but I'd have
>> dropped the _EXPR from TRY_FINALLY_EXPR to make it match the
>> "try_finally" string.

> OK, let me say for consistency then ...

Ok, I like that one ;-) I've adjusted the "try_finally" string, and
changed EH_ELSE to EH_ELSE_EXPR all over (but not in GIMPLE_EH_ELSE).

I've also changed the way TRY_FINALLY_EXPR/EH_ELSE_EXPR are output in
generic and gimple dumps, using the notation try/finally/else (this is
the notation I started using in my unfinished gimplefe attempt, to avoid
adding more keywords; more in another message).  I've retained the
ability to dump GIMPLE_EH_EXPR separately, because I'm not entirely sure
it could never be separated from the enclosing TRY_FINALLY_EXPR.


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.

Regstrapped on x86_64-linux-gnu.  Ok to install?



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.
---
 gcc/doc/generic.texi      |    5 +++++
 gcc/except.c              |   12 ++++++------
 gcc/expr.c                |    1 +
 gcc/gimple-pretty-print.c |   20 +++++++++++++++++++-
 gcc/gimplify.c            |   18 +++++++++++++++++-
 gcc/tree-dump.c           |    1 +
 gcc/tree-pretty-print.c   |   28 +++++++++++++++++++++++++---
 gcc/tree.c                |    3 +++
 gcc/tree.def              |    9 ++++++++-
 9 files changed, 85 insertions(+), 12 deletions(-)

diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index 67f7ad53af6b..8901d5f357e2 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -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
diff --git a/gcc/except.c b/gcc/except.c
index edaeeb4cfd1b..29f333912d15 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -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.
diff --git a/gcc/expr.c b/gcc/expr.c
index 4acf250dd3ce..c922aaa45b9b 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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 ();
 
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 0ccbd6c63527..ea845492b0be 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1228,6 +1228,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);
@@ -1241,12 +1243,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);
     }
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 9e5e42309412..a3792d16742e 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -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
diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c
index 58cb1ee5a729..51c0965861f8 100644
--- a/gcc/tree-dump.c
+++ b/gcc/tree-dump.c
@@ -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;
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index dacda7bd0534..742c2840cd53 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -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;
diff --git a/gcc/tree.c b/gcc/tree.c
index 76d94c6578a5..563af6fbdda6 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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);
diff --git a/gcc/tree.def b/gcc/tree.def
index 10a14fc23b0c..d2e693892cd6 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -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.  */
Richard Biener July 4, 2019, 10:47 a.m. UTC | #5
On Thu, Jul 4, 2019 at 10:19 AM Alexandre Oliva <oliva@adacore.com> wrote:
>
> On Jul  1, 2019, Richard Biener <richard.guenther@gmail.com> wrote:
>
> > On Fri, Jun 28, 2019 at 5:21 AM Alexandre Oliva <oliva@adacore.com> wrote:
> >>
> >> On Jun 27, 2019, Richard Biener <richard.guenther@gmail.com> wrote:
> >>
> >> > On Thu, Jun 27, 2019 at 10:18 AM Alexandre Oliva <oliva@adacore.com> wrote:
> >>
> >> >> @@ -909,6 +909,13 @@ DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", tcc_statement, 2)
> >> >> 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)
> >> >> +
> >> >> +/* 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 is used as a cleanup, otherwise the second operand is
> >> >> +   used.  */
> >> >> +DEFTREECODE (EH_ELSE, "eh_else", tcc_statement, 2)
> >>
> >> > It's a bit weird that this is a tcc_statement as opposed to tcc_expression,
>
> >> Erhm...  What's weird about it?  It is not something that belongs in an
> >> arbitrary expr, it's a lot more like a top-level statement, like
> >> try_finally, having side effects but no useful value.
>
> > It's weird because it appears in a TRY_FINALLY statement operand.
>
> The other operand could be a nested TRY_FINALLY, but that doesn't make
> TRY_FINALLY a tcc_expression.
>
> > But I guess the line between statements and expressions in GENERIC
> > is muddy...
>
> My understanding of the general rule is that tcc_expressions have
> values, whereas tcc_statements don't.

Oh, that makes sense indeed.

> >> > also I'd have called it EH_ELSE_EXPR for clarity.
>
> >> Now *that* would be weird IMHO.  No offense intended, but I'd have
> >> dropped the _EXPR from TRY_FINALLY_EXPR to make it match the
> >> "try_finally" string.
>
> > OK, let me say for consistency then ...
>
> Ok, I like that one ;-) I've adjusted the "try_finally" string, and
> changed EH_ELSE to EH_ELSE_EXPR all over (but not in GIMPLE_EH_ELSE).
>
> I've also changed the way TRY_FINALLY_EXPR/EH_ELSE_EXPR are output in
> generic and gimple dumps, using the notation try/finally/else (this is
> the notation I started using in my unfinished gimplefe attempt, to avoid
> adding more keywords; more in another message).  I've retained the
> ability to dump GIMPLE_EH_EXPR separately, because I'm not entirely sure
> it could never be separated from the enclosing TRY_FINALLY_EXPR.
>
>
> 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.
>
> Regstrapped on x86_64-linux-gnu.  Ok to install?

OK.

Thanks,
Richard.

>
>
> 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.
> ---
>  gcc/doc/generic.texi      |    5 +++++
>  gcc/except.c              |   12 ++++++------
>  gcc/expr.c                |    1 +
>  gcc/gimple-pretty-print.c |   20 +++++++++++++++++++-
>  gcc/gimplify.c            |   18 +++++++++++++++++-
>  gcc/tree-dump.c           |    1 +
>  gcc/tree-pretty-print.c   |   28 +++++++++++++++++++++++++---
>  gcc/tree.c                |    3 +++
>  gcc/tree.def              |    9 ++++++++-
>  9 files changed, 85 insertions(+), 12 deletions(-)
>
> diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
> index 67f7ad53af6b..8901d5f357e2 100644
> --- a/gcc/doc/generic.texi
> +++ b/gcc/doc/generic.texi
> @@ -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
> diff --git a/gcc/except.c b/gcc/except.c
> index edaeeb4cfd1b..29f333912d15 100644
> --- a/gcc/except.c
> +++ b/gcc/except.c
> @@ -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.
> diff --git a/gcc/expr.c b/gcc/expr.c
> index 4acf250dd3ce..c922aaa45b9b 100644
> --- a/gcc/expr.c
> +++ b/gcc/expr.c
> @@ -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 ();
>
> diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
> index 0ccbd6c63527..ea845492b0be 100644
> --- a/gcc/gimple-pretty-print.c
> +++ b/gcc/gimple-pretty-print.c
> @@ -1228,6 +1228,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);
> @@ -1241,12 +1243,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);
>      }
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index 9e5e42309412..a3792d16742e 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -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
> diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c
> index 58cb1ee5a729..51c0965861f8 100644
> --- a/gcc/tree-dump.c
> +++ b/gcc/tree-dump.c
> @@ -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;
> diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
> index dacda7bd0534..742c2840cd53 100644
> --- a/gcc/tree-pretty-print.c
> +++ b/gcc/tree-pretty-print.c
> @@ -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;
> diff --git a/gcc/tree.c b/gcc/tree.c
> index 76d94c6578a5..563af6fbdda6 100644
> --- a/gcc/tree.c
> +++ b/gcc/tree.c
> @@ -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);
> diff --git a/gcc/tree.def b/gcc/tree.def
> index 10a14fc23b0c..d2e693892cd6 100644
> --- a/gcc/tree.def
> +++ b/gcc/tree.def
> @@ -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.  */
>
>
> --
> Alexandre Oliva, freedom fighter  he/him   https://FSFLA.org/blogs/lxo
> Be the change, be Free!                 FSF Latin America board member
> GNU Toolchain Engineer                        Free Software Evangelist
> Hay que enGNUrecerse, pero sin perder la terGNUra jamás - Che GNUevara
diff mbox series

Patch

diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index 67f7ad53af6b..1d0e3cfec1d6 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -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} 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
diff --git a/gcc/except.c b/gcc/except.c
index edaeeb4cfd1b..76cd099749f3 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -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, 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.
diff --git a/gcc/expr.c b/gcc/expr.c
index c78bc74c0d9f..70fb721a9621 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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:
       /* Lowered by tree-eh.c.  */
       gcc_unreachable ();
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 0b25e7100cde..de4cb66e2b65 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -13074,7 +13074,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)
+	      {
+		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))
 	      {
@@ -13632,6 +13647,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
 		  && code != OACC_PARALLEL
 		  && code != OACC_KERNELS
 		  && code != OACC_DATA
diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c
index 58cb1ee5a729..f7c89c3374ff 100644
--- a/gcc/tree-dump.c
+++ b/gcc/tree-dump.c
@@ -604,6 +604,7 @@  dequeue_and_dump (dump_info_p di)
       break;
 
     case TRY_FINALLY_EXPR:
+    case EH_ELSE:
       dump_child ("op 0", TREE_OPERAND (t, 0));
       dump_child ("op 1", TREE_OPERAND (t, 1));
       break;
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 329cc6fceeb2..663616d0a0f3 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -2823,6 +2823,17 @@  dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
       is_expr = false;
       break;
 
+    case EH_ELSE:
+      pp_string (pp, "<<normal>>:");
+      newline_and_indent (pp, spc+2);
+      dump_generic_node (pp, TREE_OPERAND (node, 0), spc+2, flags, true);
+      newline_and_indent (pp, spc);
+      pp_string (pp, "<<except>>:");
+      newline_and_indent (pp, spc+2);
+      dump_generic_node (pp, TREE_OPERAND (node, 1), spc+2, flags, true);
+      is_expr = false;
+      break;
+
     case CATCH_EXPR:
       pp_string (pp, "catch (");
       dump_generic_node (pp, CATCH_TYPES (node), spc+2, flags, false);
diff --git a/gcc/tree.c b/gcc/tree.c
index c97facd7ce50..8f6f6c43b6ce 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -13408,6 +13408,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:
+      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);
diff --git a/gcc/tree.def b/gcc/tree.def
index 10a14fc23b0c..9cf53964f8eb 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -909,6 +909,13 @@  DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", tcc_statement, 2)
    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)
+
+/* 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 is used as a cleanup, otherwise the second operand is
+   used.  */
+DEFTREECODE (EH_ELSE, "eh_else", tcc_statement, 2)
 
 /* These types of expressions have no useful value,
    and always have side effects.  */