On Thu, Jul 4, 2019 at 10:19 AM Alexandre Oliva <ol...@adacore.com> wrote: > > On Jul 1, 2019, Richard Biener <richard.guent...@gmail.com> wrote: > > > On Fri, Jun 28, 2019 at 5:21 AM Alexandre Oliva <ol...@adacore.com> wrote: > >> > >> On Jun 27, 2019, Richard Biener <richard.guent...@gmail.com> wrote: > >> > >> > On Thu, Jun 27, 2019 at 10:18 AM Alexandre Oliva <ol...@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