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