On Thu, 1 Oct 2020, Jan Hubicka wrote:

> Hi
> > > +  if (!fnspec.arg_specified_p (arg))
> > > +    ;
> > > +  else if (!fnspec.arg_used_p (arg))
> > > +    flags = EAF_UNUSED;
> > > +  else
> > > +    {
> > > +      if (!fnspec.arg_direct_p (arg))
> > 
> > negated test
> > 
> > > + flags |= EAF_DIRECT;
> > > +      if (!fnspec.arg_noescape_p (arg))
> > > + flags |= EAF_NOESCAPE;
> > 
> > likewise.
> > 
> > > +      if (!fnspec.arg_readonly_p (arg))
> > > + flags |= EAF_NOCLOBBER;
> > 
> > 
> > likewise.
> 
> Oops, sorry for that.  I got carried away trying to make sense of
> fortran specifiers. Thanks for catching this. I wonder how that chould
> have passed testing.
> > 
> > >      }
> > > +  return flags;
> > >  }
> > >  
> > >  /* Detects return flags for the call STMT.  */
> > > @@ -1546,24 +1542,16 @@ gimple_call_return_flags (const gcall *stmt)
> > >      return ERF_NOALIAS;
> > >  
> > >    attr = gimple_call_fnspec (stmt);
> > > -  if (!attr || TREE_STRING_LENGTH (attr) < 1)
> > > +  if (!attr)
> > >      return 0;
> > > +  attr_fnspec fnspec (attr);
> > >  
> > > -  switch (TREE_STRING_POINTER (attr)[0])
> > > -    {
> > > -    case '1':
> > > -    case '2':
> > > -    case '3':
> > > -    case '4':
> > > -      return ERF_RETURNS_ARG | (TREE_STRING_POINTER (attr)[0] - '1');
> > > -
> > > -    case 'm':
> > > -      return ERF_NOALIAS;
> > > +  if (fnspec.returns_arg () >= 0)
> > > +    return ERF_RETURNS_ARG | fnspec.returns_arg ();
> > 
> > hmm, maybe
> > 
> >      if (fnspec.returns_arg_p (&arg))
> >        return ERF_RETURNS_ARG | arg;
> 
> I added arg variable, but I think returning -1 for unknown arg is kind
> of more consistent with what we do elsewhere (plus referneces are not
> cool)
> > > +  /* True if memory reached is only written into (but not read).  */
> > > +  bool
> > > +  arg_writeonly_p (unsigned int i)
> > 
> > This is actually arg_readwrite_p (), there's no flag for write-only.
> > wW are merely for noescape & only direct read/write.
> 
> I dropped this for now, but for tree-ssa-alias we will need to have way
> to specify that parameter is only written into.
> > 
> > Currently all specified args imply noescape btw.
> 
> Yep, but I think we may want to change this, so I think it is safer to
> list those that do.
> 
> This is updated patch I am re-testing. Does it look OK?
> 
> Next I would like to proceed by blowing up all specifiers to double of
> size (without functional changes) and then add the extra letters.
> 
> I was wondering if we want to use ' ' instead of '.' for the second
> char.  It may make it easier to read ". . . R " than "......R." but it
> also may be bit misleading in a way that the there must be precisely one
> space.
> 
> Honza
> 
> gcc/ChangeLog:
> 
> 2020-10-01  Jan Hubicka  <hubi...@ucw.cz>
> 
>       * attr-fnspec.h: New file.
>       * calls.c (decl_return_flags): Implement using attr_fnspec.
>       * gimple.c (gimple_call_arg_flags): Likewise
>       (gimple_call_return_flags): Likewise
>       * tree-into-ssa.c (pass_build_ssa::execute): Likewise.
>       * tree-ssa-alias.c (attr_fnspec::verify): New
> 
> diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
> new file mode 100644
> index 00000000000..4ad4b8758e0
> --- /dev/null
> +++ b/gcc/attr-fnspec.h
> @@ -0,0 +1,141 @@
> +/* Handling of fnspec attribute specifiers
> +   Copyright (C) 2008-2020 Free Software Foundation, Inc.
> +   Contributed by Richard Guenther  <rguent...@suse.de>
> +
> +   This file is part of GCC.
> +
> +   GCC is free software; you can redistribute it and/or modify
> +   under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   GCC is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with GCC; see the file COPYING3.  If not see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +/* Parse string of attribute "fn spec".  This is an internal attribute
> +   describing side effects of a function as follows:
> +
> +   character 0  specifies properties of return values as follows:
> +     '1'...'4'  specifies number of argument function returns (as in memset)
> +     'm'     specifies that returned value is noalias (as in malloc)
> +     '.'     specifies that nothing is known.
> +
> +   character 1+i specifies properties of argument number i as follows:
> +     'x' or 'X' specifies that parameter is unused.
> +     'r' or 'R' specifies that parameter is only read and memory pointed to 
> is
> +             never dereferenced.
> +     'w' or 'W' specifies that parameter is only written to.
> +     '.'     specifies that nothing is known.
> +   The uppercase letter in addition specifies that parameter
> +   is non-escaping.  */
> +
> +#ifndef ATTR_FNSPEC_H
> +#define ATTR_FNSPEC_H
> +
> +class attr_fnspec
> +{
> +private:
> +  /* fn spec attribute string.  */
> +  const char *str;
> +  /* length of the fn spec string.  */
> +  const unsigned len;
> +  /* Number of characters specifying return value.  */
> +  const unsigned int return_desc_size = 1;
> +  /* Number of characters specifying size.  */
> +  const unsigned int arg_desc_size = 1;
> +
> +  /* Return start of specifier of arg i.  */
> +  unsigned int arg_idx (int i)
> +  {
> +    return return_desc_size + arg_desc_size * i;
> +  }
> +
> +public:
> +  attr_fnspec (const char *str, unsigned len)
> +  : str (str), len (len)
> +  {
> +    if (flag_checking)
> +      verify ();
> +  }
> +  attr_fnspec (const_tree identifier)
> +  : str (TREE_STRING_POINTER (identifier)),
> +    len (TREE_STRING_LENGTH (identifier))
> +  {
> +    if (flag_checking)
> +      verify ();
> +  }
> +
> +  /* Return true if arg I is specified.  */
> +  bool
> +  arg_specified_p (unsigned int i)
> +  {
> +    return len >= arg_idx (i + 1);
> +  }
> +
> +  /* True if the argument is not dereferenced recursively, thus only
> +     directly reachable memory is read or written.  */
> +  bool
> +  arg_direct_p (unsigned int i)

maybe better arg_direct_only_p, you differ with
arg_readonly_p from EAF_NOCLOBBER as well.  It's all just
names of course.

> +  {
> +    unsigned int idx = arg_idx (i);
> +    gcc_checking_assert (arg_specified_p (i));
> +    return str[idx] == 'R' || str[idx] == 'W';
> +  }
> +
> +  /* True if argument is used.  */
> +  bool
> +  arg_used_p (unsigned int i)
> +  {
> +    unsigned int idx = arg_idx (i);
> +    gcc_checking_assert (arg_specified_p (i));
> +    return str[idx] != 'x' && str[idx] != 'X';
> +  }

Hmm, I guess !arg_used_p also implies arg_noescape_p (not "correctly"
handled by gimple_call_arg_flag currently either).  So the question
is what "used"/"unused" means - does it mean the argument is
'inspected'?  That is, can we have an argument escape but not
read or written to?

Guess this can be sorted out in a followup, your patch doesn't
change current beahvior.

> +  /* True if memory reached by the argument is readonly (not clobbered).  */
> +  bool
> +  arg_readonly_p (unsigned int i)
> +  {
> +    unsigned int idx = arg_idx (i);
> +    gcc_checking_assert (arg_specified_p (i));
> +    return str[idx] == 'r' || str[idx] == 'R';
> +  }
> +
> +  /* True if the argument does not escape.  */
> +  bool
> +  arg_noescape_p (unsigned int i)
> +  {
> +    unsigned int idx = arg_idx (i);
> +    gcc_checking_assert (arg_specified_p (i));
> +    return str[idx] == 'w' || str[idx] == 'W'
> +        || str[idx] == 'R' || str[idx] == 'r';
> +  }
> +
> +  /* If not equal to -1 then it specifies number of argument returned by
> +     the function.  */
> +  int
> +  returns_arg ()
> +  {
> +    if (str[0] >= '1' && str[0] <= '4')
> +      return str[0]-'1';
> +    return -1;
> +  }
> +
> +  /* Nonzero if the return value does not alias with anything.  Functions
> +     with the malloc attribute have this set on their return value.  */
> +  int

bool?

OK with this change at least.

Richard.

> +  returns_noalias_p ()
> +  {
> +    return str[0] == 'm';
> +  }
> +
> +  /* Check validity of the string.  */
> +  void verify ();
> +};
> +
> +#endif /* ATTR_FNSPEC_H  */
> diff --git a/gcc/calls.c b/gcc/calls.c
> index ed4363811c8..40f4863a89b 100644
> --- a/gcc/calls.c
> +++ b/gcc/calls.c
> @@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "attribs.h"
>  #include "builtins.h"
>  #include "gimple-fold.h"
> +#include "attr-fnspec.h"
>  
>  #include "tree-pretty-print.h"
>  
> @@ -642,25 +643,15 @@ decl_return_flags (tree fndecl)
>    if (!attr)
>      return 0;
>  
> -  attr = TREE_VALUE (TREE_VALUE (attr));
> -  if (!attr || TREE_STRING_LENGTH (attr) < 1)
> -    return 0;
> -
> -  switch (TREE_STRING_POINTER (attr)[0])
> -    {
> -    case '1':
> -    case '2':
> -    case '3':
> -    case '4':
> -      return ERF_RETURNS_ARG | (TREE_STRING_POINTER (attr)[0] - '1');
> +  attr_fnspec fnspec (TREE_VALUE (TREE_VALUE (attr)));
>  
> -    case 'm':
> -      return ERF_NOALIAS;
> +  int arg = fnspec.returns_arg ();
> +  if (arg >= 0)
> +    return ERF_RETURNS_ARG | arg;
>  
> -    case '.':
> -    default:
> -      return 0;
> -    }
> +  if (fnspec.returns_noalias_p ())
> +    return ERF_NOALIAS;
> +  return 0;
>  }
>  
>  /* Return nonzero when FNDECL represents a call to setjmp.  */
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index fd4e0fac0d4..8fb82570374 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "attribs.h"
>  #include "asan.h"
>  #include "langhooks.h"
> +#include "attr-fnspec.h"
>  
>  
>  /* All the tuples have their operand vector (if present) at the very bottom
> @@ -1508,31 +1509,26 @@ gimple_call_arg_flags (const gcall *stmt, unsigned 
> arg)
>  {
>    const_tree attr = gimple_call_fnspec (stmt);
>  
> -  if (!attr || 1 + arg >= (unsigned) TREE_STRING_LENGTH (attr))
> +  if (!attr)
>      return 0;
>  
> -  switch (TREE_STRING_POINTER (attr)[1 + arg])
> -    {
> -    case 'x':
> -    case 'X':
> -      return EAF_UNUSED;
> -
> -    case 'R':
> -      return EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
> -
> -    case 'r':
> -      return EAF_NOCLOBBER | EAF_NOESCAPE;
> -
> -    case 'W':
> -      return EAF_DIRECT | EAF_NOESCAPE;
> -
> -    case 'w':
> -      return EAF_NOESCAPE;
> +  int flags = 0;
> +  attr_fnspec fnspec (attr);
>  
> -    case '.':
> -    default:
> -      return 0;
> +  if (!fnspec.arg_specified_p (arg))
> +    ;
> +  else if (!fnspec.arg_used_p (arg))
> +    flags = EAF_UNUSED;
> +  else
> +    {
> +      if (fnspec.arg_direct_p (arg))
> +     flags |= EAF_DIRECT;
> +      if (fnspec.arg_noescape_p (arg))
> +     flags |= EAF_NOESCAPE;
> +      if (fnspec.arg_readonly_p (arg))
> +     flags |= EAF_NOCLOBBER;
>      }
> +  return flags;
>  }
>  
>  /* Detects return flags for the call STMT.  */
> @@ -1546,24 +1542,16 @@ gimple_call_return_flags (const gcall *stmt)
>      return ERF_NOALIAS;
>  
>    attr = gimple_call_fnspec (stmt);
> -  if (!attr || TREE_STRING_LENGTH (attr) < 1)
> +  if (!attr)
>      return 0;
> +  attr_fnspec fnspec (attr);
>  
> -  switch (TREE_STRING_POINTER (attr)[0])
> -    {
> -    case '1':
> -    case '2':
> -    case '3':
> -    case '4':
> -      return ERF_RETURNS_ARG | (TREE_STRING_POINTER (attr)[0] - '1');
> -
> -    case 'm':
> -      return ERF_NOALIAS;
> +  if (fnspec.returns_arg () >= 0)
> +    return ERF_RETURNS_ARG | fnspec.returns_arg ();
>  
> -    case '.':
> -    default:
> -      return 0;
> -    }
> +  if (fnspec.returns_noalias_p ())
> +    return ERF_NOALIAS;
> +  return 0;
>  }
>  
>  
> diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c
> index 0d016134774..1493b323956 100644
> --- a/gcc/tree-into-ssa.c
> +++ b/gcc/tree-into-ssa.c
> @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "stringpool.h"
>  #include "attribs.h"
>  #include "asan.h"
> +#include "attr-fnspec.h"
>  
>  #define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y))
>  
> @@ -2492,19 +2493,19 @@ pass_build_ssa::execute (function *fun)
>      }
>  
>    /* Initialize SSA_NAME_POINTS_TO_READONLY_MEMORY.  */
> -  tree fnspec = lookup_attribute ("fn spec",
> -                               TYPE_ATTRIBUTES (TREE_TYPE (fun->decl)));
> -  if (fnspec)
> +  tree fnspec_tree
> +      = lookup_attribute ("fn spec",
> +                          TYPE_ATTRIBUTES (TREE_TYPE (fun->decl)));
> +  if (fnspec_tree)
>      {
> -      fnspec = TREE_VALUE (TREE_VALUE (fnspec));
> -      unsigned i = 1;
> +      attr_fnspec fnspec (TREE_VALUE (TREE_VALUE (fnspec_tree)));
> +      unsigned i = 0;
>        for (tree arg = DECL_ARGUMENTS (cfun->decl);
>          arg; arg = DECL_CHAIN (arg), ++i)
>       {
> -       if (i >= (unsigned) TREE_STRING_LENGTH (fnspec))
> -         break;
> -       if (TREE_STRING_POINTER (fnspec)[i]  == 'R'
> -           || TREE_STRING_POINTER (fnspec)[i] == 'r')
> +       if (!fnspec.arg_specified_p (i))
> +        break;
> +       if (fnspec.arg_readonly_p (i))
>           {
>             tree name = ssa_default_def (fun, arg);
>             if (name)
> diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> index fe390d4ffbe..2b2d53ebb88 100644
> --- a/gcc/tree-ssa-alias.c
> +++ b/gcc/tree-ssa-alias.c
> @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "varasm.h"
>  #include "ipa-modref-tree.h"
>  #include "ipa-modref.h"
> +#include "attr-fnspec.h"
>  
>  /* Broad overview of how alias analysis on gimple works:
>  
> @@ -3984,3 +3985,42 @@ walk_aliased_vdefs (ao_ref *ref, tree vdef,
>    return ret;
>  }
>  
> +/* Verify validity of the fnspec string.
> +   See attr-fnspec.h for details.  */
> +
> +void
> +attr_fnspec::verify ()
> +{
> +  /* FIXME: Fortran trans-decl.c contains multiple wrong fnspec strings.
> +     re-enable verification after these are fixed.  */
> +  return;
> +  bool err = false;
> +
> +  /* Check return value specifier.  */
> +  if (len < return_desc_size)
> +    err = true;
> +  else if (str[0] < '1' || str[0] > '4')
> +        && str[0] != '.' && str[0] != 'm')
> +    err = true;
> +
> +  /* Now check all parameters.  */
> +  for (unsigned int i = 0; arg_specified_p (i); i++)
> +    {
> +      unsigned int idx = arg_idx (i);
> +      switch (str[idx])
> +     {
> +       case 'x':
> +       case 'X':
> +       case 'r':
> +       case 'R':
> +       case 'w':
> +       case 'W':
> +       case '.':
> +         break;
> +       default:
> +         err = true;
> +     }
> +    }
> +  if (err)
> +    internal_error ("invalid fn spec attribute %s", str);
> +}
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imend

Reply via email to