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).


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
> 

Reply via email to