On Thu, Oct 15, 2020 at 11:50:28PM +0200, Jan Hubicka wrote:
> Hi,
> this patch implements the discussed change to fnspecs to make it
> possible to specify parameters that are read and written.  In addition
> to original plan I ended up adding 'b' for functions that are barriers
> (since those alias even with local refs) and 'o','O' for parameters that
> are written only (output parameters) so there is diffence betwen strcat
> and memcpy, for example.
> 
> Bootstrapped/regtested x86_64-linux, OK?
> 
> Honza
> 
> 2020-10-15  Jan Hubicka  <hubi...@ucw.cz>
> 
>       * attr-fnspec.h: Update toplevel comment.
>       (attr_fnspec::attr_fnspec): New constructor.
>       (attr_fnspec::arg_read_p,
>       attr_fnspec::arg_written_p,
>       attr_fnspec::arg_access_size_given_by_arg_p,
>       attr_fnspec::arg_single_access_p
>       attr_fnspec::loads_known_p
>       attr_fnspec::stores_known_p,
>       attr_fnspec::clobbers_errno_p): New member functions.
>       (gimple_call_fnspec): Declare.
>       (builtin_fnspec): Declare.
>       * builtins.c: Include attr-fnspec.h
>       (builtin_fnspec): New function.
>       * builtins.def (BUILT_IN_MEMCPY): Do not specify RET1 fnspec.
>       (BUILT_IN_MEMMOVE): Do not specify RET1 fnspec.
>       (BUILT_IN_MEMSET): Do not specify RET1 fnspec.
>       (BUILT_IN_STRCAT): Do not specify RET1 fnspec.
>       (BUILT_IN_STRCPY): Do not specify RET1 fnspec.
>       (BUILT_IN_STRNCAT): Do not specify RET1 fnspec.
>       (BUILT_IN_STRNCPY): Do not specify RET1 fnspec.
>       (BUILT_IN_MEMCPY_CHK): Do not specify RET1 fnspec.
>       (BUILT_IN_MEMMOVE_CHK): Do not specify RET1 fnspec.
>       (BUILT_IN_MEMSET_CHK): Do not specify RET1 fnspec.
>       (BUILT_IN_STRCAT_CHK): Do not specify RET1 fnspec.
>       (BUILT_IN_STRCPY_CHK): Do not specify RET1 fnspec.
>       (BUILT_IN_STRNCAT_CHK): Do not specify RET1 fnspec.
>       (BUILT_IN_STRNCPY_CHK): Do not specify RET1 fnspec.
>       * gimple.c (gimple_call_fnspec): Return attr_fnspec.
>       (gimple_call_arg_flags): Update.
>       (gimple_call_return_flags): Update.
>       * tree-ssa-alias.c (check_fnspec): New function.
>       (ref_maybe_used_by_call_p_1): Use fnspec for builtin handling.
>       (call_may_clobber_ref_p_1): Likewise.
>       (attr_fnspec::verify): Update verifier.
>       * calls.c (decl_fnspec): New function.
>       (decl_return_flags): Use it.
> diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
> index d38b84a969e..e524798c4ca 100644
> --- a/gcc/attr-fnspec.h
> +++ b/gcc/attr-fnspec.h
> @@ -27,11 +27,19 @@
>       '.'     specifies that nothing is known.
>     character 1  specifies additional function properties
>       ' '        specifies that nothing is known
> +     'p' or 'P' specifies that function is pure except for described side
> +             effects.
> +     'c' or 'C' specifies that function is const except for described side
> +             effects.
> +     'b'     specifies that functions is a memory barrier.
> +   The uppercase letter in addition specifies that function clobbers errno.
>  
>     character 2+2i specifies properties of argument number i as follows:
>       'x' or 'X' specifies that parameter is unused.
>       'r' or 'R' specifies that the memory pointed to by the parameter is only
>               read and does not escape
> +     'o' or 'O' specifies that the memory pointed to by the parameter is only
> +             written and does not escape
>       'w' or 'W' specifies that the memory pointed to by the parameter does 
> not
>               escape
>       '.'     specifies that nothing is known.
> @@ -42,6 +50,10 @@
>     character 3+2i specifies additional properties of argument number i
>     as follows:
>       ' '        nothing is known
> +     't'     the size of value written/read corresponds to the size of
> +             of the pointed-to type of the argument type
> +     '1'...'9'  the size of value written/read is given by the specified
> +             argument
>   */
>  
>  #ifndef ATTR_FNSPEC_H
> @@ -72,6 +84,12 @@ public:
>      if (flag_checking)
>        verify ();
>    }
> +  attr_fnspec (const char *str)
> +  : str (str), len (strlen (str))
> +  {
> +    if (flag_checking)
> +      verify ();
> +  }
>    attr_fnspec (const_tree identifier)
>    : str (TREE_STRING_POINTER (identifier)),
>      len (TREE_STRING_LENGTH (identifier))
> @@ -79,6 +97,17 @@ public:
>      if (flag_checking)
>        verify ();
>    }
> +  attr_fnspec ()
> +  : str (NULL), len (0)
> +  {
> +  }
> +
> +  /* Return true if fn spec is known.  */
> +  bool
> +  known_p ()
> +  {
> +    return len;
> +  }
>  
>    /* Return true if arg I is specified.  */
>    bool
> @@ -94,7 +123,7 @@ public:
>    {
>      unsigned int idx = arg_idx (i);
>      gcc_checking_assert (arg_specified_p (i));
> -    return str[idx] == 'R' || str[idx] == 'W';
> +    return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'W';
>    }
>  
>    /* True if argument is used.  */
> @@ -115,6 +144,56 @@ public:
>      return str[idx] == 'r' || str[idx] == 'R';
>    }
>  
> +  /* True if memory reached by the argument is read.
> +     Valid only if all loads are known.  */
> +  bool
> +  arg_read_p (unsigned int i)
> +  {
> +    unsigned int idx = arg_idx (i);
> +    gcc_checking_assert (arg_specified_p (i));
> +    gcc_checking_assert (loads_known_p ());
> +    return str[idx] == 'r' || str[idx] == 'R'
> +        || str[idx] == 'w' || str[idx] == 'W';
> +  }
> +
> +  /* True if memory reached by the argument is read.
> +     Valid only if all loads are known.  */
> +  bool
> +  arg_written_p (unsigned int i)
> +  {
> +    unsigned int idx = arg_idx (i);
> +    gcc_checking_assert (arg_specified_p (i));
> +    gcc_checking_assert (stores_known_p ());
> +    return str[idx] == 'w' || str[idx] == 'W'
> +        || str[idx] == 'o' || str[idx] == 'O';
> +  }
> +
> +  /* Return true if load of memory pointed to by argument I is specified
> +     by another argument.  In this case set ARG.  */
> +  bool
> +  arg_access_size_given_by_arg_p (unsigned int i, unsigned int *arg)
> +  {
> +    unsigned int idx = arg_idx (i);
> +    gcc_checking_assert (arg_specified_p (i));
> +    if (str[idx + 1] >= '1' && str[idx + 1] <= '9')
> +      {
> +     *arg = str[idx + 1] - '1';
> +     return true;
> +      }
> +    else
> +      return false;
> +  }
> +
> +  /* Return true if the pointed-to type of the argument correspond to the
> +     size of the memory acccess.  */
> +  bool
> +  arg_single_access_p (unsigned int i)
> +  {
> +    unsigned int idx = arg_idx (i);
> +    gcc_checking_assert (arg_specified_p (i));
> +    return str[idx + 1] == 't';
> +  }
> +
>    /* True if the argument does not escape.  */
>    bool
>    arg_noescape_p (unsigned int i)
> @@ -122,7 +201,8 @@ public:
>      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';
> +        || str[idx] == 'r' || str[idx] == 'R'
> +        || str[idx] == 'o' || str[idx] == 'o';

Did you mean 

  || str[idx] == 'o' || str[idx] == 'O';

here?

Marek

Reply via email to