On Thu, Jun 27, 2019 at 10:18 AM Alexandre Oliva <ol...@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

Reply via email to