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