On Mon, 3 May 2021, Michael Matz wrote:

> Hello,
> 
> On Mon, 3 May 2021, Jan Hubicka wrote:
> 
> > > (it should not abort).  The documentation of 'pure' must be read
> > > as that 'pure' is not valid for 'foo' since throwing an exception
> > > is obviously an observable effect on the state of the program
> > > (in particular for the testcase at hand).  But for example
> > > IPA pure const does not cause us to infer nothrow on pure
> > > declared functions and the C++ program
> > > 
> > > ...
> > > 
> > > So - what is it?  Are pure functions allowed to throw or not?
> > 
> > I was one adding pure functions and it was really intended to be same
> > thing as const+reading memory.  So does const function throw or not?
> 
> I really want to say that const/pure and throw are mutually exclusive.  
> But in reality they are orthogonal, so a const function may throw.  (It 
> certainly can in C++).
> 
> This is because while we implement exceptions with memory state, that 
> state in not accessible to the application.  Exceptions could for instance 
> also be implemented via return type extension.  And then, as long as other 
> guarantees of const or pure functions are adhered to (same input -> same 
> output), throwing an exception from a const function would be completely 
> natural.  E.g. if a const function, given a specific set of arguments, 
> always throws the same value that would still allow to CSE two calls to it 
> in a row, and it would still allow to assume that no reachable memory was 
> changed by that call.
> 
> So, I think const and pure functions may validly throw (but then must 
> always do so given the same inputs).

I've filed PR100394 since it appearantly never worked (for C++).

Richard.

> 
> Ciao,
> Michael.
> 
> 
> > Internally we definitly want to make this separate - with symbol
> > summaries it is now reasonably easy to do.  I was thinking of doing
> > similar summary as modref handles to pass down separate info tracked by
> > pure-const patch rather than trying to re-synthetize it to rather random
> > attributes we have now...
> > 
> > Honza
> > > 
> > > 2021-05-03  Richard Biener  <rguent...@suse.de>
> > > 
> > >   * calls.c (expand_call): Preserve possibly throwing calls.
> > >   * cfgexpand.c (expand_call_stmt): When a call can throw signal
> > >   RTL expansion there are side-effects.
> > >   * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Simplify.
> > >   * tree-ssa-dse.c (pass_dse::execute): Preserve exceptions unless
> > >   -fdelete-dead-exceptions.
> > > 
> > >   * g++.dg/tree-ssa/pr100382.C: New testcase.
> > > ---
> > >  gcc/calls.c                              |  1 +
> > >  gcc/cfgexpand.c                          |  5 ++++-
> > >  gcc/testsuite/g++.dg/tree-ssa/pr100382.C | 25 ++++++++++++++++++++++++
> > >  gcc/tree-ssa-dce.c                       | 21 +++-----------------
> > >  gcc/tree-ssa-dse.c                       |  3 ++-
> > >  5 files changed, 35 insertions(+), 20 deletions(-)
> > >  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr100382.C
> > > 
> > > diff --git a/gcc/calls.c b/gcc/calls.c
> > > index 883d08ba5f2..f3da1839dc5 100644
> > > --- a/gcc/calls.c
> > > +++ b/gcc/calls.c
> > > @@ -3808,6 +3808,7 @@ expand_call (tree exp, rtx target, int ignore)
> > >       side-effects.  */
> > >    if ((flags & (ECF_CONST | ECF_PURE))
> > >        && (!(flags & ECF_LOOPING_CONST_OR_PURE))
> > > +      && (flags & ECF_NOTHROW)
> > >        && (ignore || target == const0_rtx
> > >     || TYPE_MODE (rettype) == VOIDmode))
> > >      {
> > > diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
> > > index a6b48d3e48f..556a0b22ed6 100644
> > > --- a/gcc/cfgexpand.c
> > > +++ b/gcc/cfgexpand.c
> > > @@ -2795,7 +2795,10 @@ expand_call_stmt (gcall *stmt)
> > >        CALL_EXPR_ARG (exp, i) = arg;
> > >      }
> > >  
> > > -  if (gimple_has_side_effects (stmt))
> > > +  if (gimple_has_side_effects (stmt)
> > > +      /* ???  Downstream in expand_expr_real_1 we assume that expressions
> > > +  w/o side-effects do not throw so work around this here.  */
> > > +      || stmt_could_throw_p (cfun, stmt))
> > >      TREE_SIDE_EFFECTS (exp) = 1;
> > >  
> > >    if (gimple_call_nothrow_p (stmt))
> > > diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr100382.C 
> > > b/gcc/testsuite/g++.dg/tree-ssa/pr100382.C
> > > new file mode 100644
> > > index 00000000000..b9948d3034a
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/tree-ssa/pr100382.C
> > > @@ -0,0 +1,25 @@
> > > +// { dg-do run }
> > > +// { dg-options "-O2" }
> > > +
> > > +int x, y;
> > > +int __attribute__((pure,noinline)) foo () { if (x) throw; return y; }
> > > +
> > > +int __attribute__((noinline)) bar()
> > > +{
> > > +  int a[2];
> > > +  x = 1;
> > > +  try {
> > > +    int res = foo ();
> > > +    a[0] = res;
> > > +  } catch (...) {
> > > +      return 0;
> > > +  }
> > > +  return 1;
> > > +}
> > > +
> > > +int main()
> > > +{
> > > +  if (bar ())
> > > +    __builtin_abort ();
> > > +  return 0;
> > > +}
> > > diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
> > > index 096cfc8721d..ff0389af36f 100644
> > > --- a/gcc/tree-ssa-dce.c
> > > +++ b/gcc/tree-ssa-dce.c
> > > @@ -250,14 +250,6 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool 
> > > aggressive)
> > >       && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee))
> > >     return;
> > >  
> > > - /* Most, but not all function calls are required.  Function calls that
> > > -    produce no result and have no side effects (i.e. const pure
> > > -    functions) are unnecessary.  */
> > > - if (gimple_has_side_effects (stmt))
> > > -   {
> > > -     mark_stmt_necessary (stmt, true);
> > > -     return;
> > > -   }
> > >   /* IFN_GOACC_LOOP calls are necessary in that they are used to
> > >      represent parameter (i.e. step, bound) of a lowered OpenACC
> > >      partitioned loop.  But this kind of partitioned loop might not
> > > @@ -269,8 +261,6 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool 
> > > aggressive)
> > >       mark_stmt_necessary (stmt, true);
> > >       return;
> > >     }
> > > - if (!gimple_call_lhs (stmt))
> > > -   return;
> > >   break;
> > >        }
> > >  
> > > @@ -312,19 +302,14 @@ mark_stmt_if_obviously_necessary (gimple *stmt, 
> > > bool aggressive)
> > >    /* If the statement has volatile operands, it needs to be preserved.
> > >       Same for statements that can alter control flow in unpredictable
> > >       ways.  */
> > > -  if (gimple_has_volatile_ops (stmt) || is_ctrl_altering_stmt (stmt))
> > > -    {
> > > -      mark_stmt_necessary (stmt, true);
> > > -      return;
> > > -    }
> > > -
> > > -  if (stmt_may_clobber_global_p (stmt))
> > > +  if (gimple_has_side_effects (stmt) || is_ctrl_altering_stmt (stmt))
> > >      {
> > >        mark_stmt_necessary (stmt, true);
> > >        return;
> > >      }
> > >  
> > > -  if (gimple_vdef (stmt) && keep_all_vdefs_p ())
> > > +  if ((gimple_vdef (stmt) && keep_all_vdefs_p ())
> > > +      || stmt_may_clobber_global_p (stmt))
> > >      {
> > >        mark_stmt_necessary (stmt, true);
> > >        return;
> > > diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c
> > > index dfa6d314727..386667b9f7f 100644
> > > --- a/gcc/tree-ssa-dse.c
> > > +++ b/gcc/tree-ssa-dse.c
> > > @@ -1219,7 +1219,8 @@ pass_dse::execute (function *fun)
> > >            dead SSA defs.  */
> > >         if (has_zero_uses (DEF_FROM_PTR (def_p))
> > >             && !gimple_has_side_effects (stmt)
> > > -           && !stmt_unremovable_because_of_non_call_eh_p (cfun, stmt))
> > > +           && (!stmt_could_throw_p (fun, stmt)
> > > +               || fun->can_delete_dead_exceptions))
> > >           {
> > >             if (dump_file && (dump_flags & TDF_DETAILS))
> > >               {
> > > -- 
> > > 2.26.2
> > 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

Reply via email to