diff mbox series

Add support for copy specifier to fnspec

Message ID 20201109211508.GA4651@kam.mff.cuni.cz
State New
Headers show
Series Add support for copy specifier to fnspec | expand

Commit Message

Jan Hubicka Nov. 9, 2020, 9:15 p.m. UTC
Hi,
this patch adds 'c' and 'C' fnspec for parameter that is copied to different
parameter.  Main motivation is to get rid of wrong EAF_NOESCAPE flag on
the memcpy argument #2. I however also added arg_copies_to_arg_p
predicate that can be eventually used by tree-ssa-structalias instead of
special casing all builtins.

I noticed that we can no longer describe STRNCAT precisely.  I am not
sure how important it is.  We can either special case it on the three
places (in tree-ssa-alias and in ipa-modref) or use 1-9 in place of 'c'
and 'C' so the second character would be still available for size
specifier, so strncat would become

"1cW 13"
instead of
"1cW C1"

Not sure how important this is.
Bootstrapped/regtested x86_64-linux, OK?

Honza

2020-11-09  Jan Hubicka  <hubicka@ucw.cz>

	* attr-fnspec.h: Add 'c' and 'C' specifiers to the toplevel comment.
	(attr_fnspec::arg_direct_p): Add 'C'.
	(attr_fnspec::arg_not_written_p): Handle 'c' and 'C'.
	(attr_fnspec::arg_max_access_size_given_by_arg_p): Handle 'c' and 'C'.
	(attr_fnspec::arg_access_size_given_by_type_p): Add comment about 'c'
	and 'C'.
	(attr_fnspec::arg_copied_to_arg_p): New.
	* builtins.c (attr_fnspec::builtin_fnspec): Update fnspec of string
	functions that copies argument.
	* tree-ssa-alias.c (attr_fnspec::verify): Add 'c' and 'C'; be more
	struct on arg specifiers.

Comments

Richard Biener Nov. 11, 2020, 10:03 a.m. UTC | #1
On Mon, 9 Nov 2020, Jan Hubicka wrote:

> Hi,
> this patch adds 'c' and 'C' fnspec for parameter that is copied to different
> parameter.  Main motivation is to get rid of wrong EAF_NOESCAPE flag on
> the memcpy argument #2. I however also added arg_copies_to_arg_p
> predicate that can be eventually used by tree-ssa-structalias instead of
> special casing all builtins.
> 
> I noticed that we can no longer describe STRNCAT precisely.  I am not
> sure how important it is.  We can either special case it on the three
> places (in tree-ssa-alias and in ipa-modref) or use 1-9 in place of 'c'
> and 'C' so the second character would be still available for size
> specifier, so strncat would become
> 
> "1cW 13"
> instead of
> "1cW C1"
> 
> Not sure how important this is.

I guess it's an interesting idea and it also gets around the issue
I have with the patch, that you allow 'c' where the semantics are not
at all clear.  So if we go with the patch as-is please disallow 'c'.
Otherwise using 1-9 in place of 'C' works for me as well and also
avoids the overload of the second char.  The description should
also mention that 'C' implies read-only and no escaping (besides
to the specified parameter).  So I guess it should be documented
as "same as 'R'" besides the copying, noting that this means
it "escapes" to the other parameter.

Either OK with disallowing 'c' and adjusted docs or if you want
to rework as '1'-'9' ...

Richard.

> Bootstrapped/regtested x86_64-linux, OK?
> 
> Honza
> 
> 2020-11-09  Jan Hubicka  <hubicka@ucw.cz>
> 
> 	* attr-fnspec.h: Add 'c' and 'C' specifiers to the toplevel comment.
> 	(attr_fnspec::arg_direct_p): Add 'C'.
> 	(attr_fnspec::arg_not_written_p): Handle 'c' and 'C'.
> 	(attr_fnspec::arg_max_access_size_given_by_arg_p): Handle 'c' and 'C'.
> 	(attr_fnspec::arg_access_size_given_by_type_p): Add comment about 'c'
> 	and 'C'.
> 	(attr_fnspec::arg_copied_to_arg_p): New.
> 	* builtins.c (attr_fnspec::builtin_fnspec): Update fnspec of string
> 	functions that copies argument.
> 	* tree-ssa-alias.c (attr_fnspec::verify): Add 'c' and 'C'; be more
> 	struct on arg specifiers.
> 
> diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
> index 28135328437..97405dbdd78 100644
> --- a/gcc/attr-fnspec.h
> +++ b/gcc/attr-fnspec.h
> @@ -41,6 +41,13 @@
>  		written and does not escape
>       'w' or 'W' specifies that the memory pointed to by the parameter does not
>  		escape
> +     'c' or 'C' specifies that the memory pointed to by the parameter is
> +		copied to memory pointed to by different parameter
> +		(as in memcpy).  The index of the destination parmeter is
> +		specified by following character i.e. "C1" means that memory is
> +		copied to parameter pointed to by parameter 1.
> +		Size of block copied is determined by size specifier of the
> +		destination parameter.
>       '.'	specifies that nothing is known.
>     The uppercase letter in addition specifies that the memory pointed to
>     by the parameter is not dereferenced.  For 'r' only read applies
> @@ -51,8 +58,11 @@
>       ' '        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
> +     '1'...'9'  preceeded by 'o', 'O', 'w' or 'W'
> +		specifies the size of value written/read is given by the
> +		specified argument
> +     '1'...'9'  preceeded by 'c', or 'c'
> +		specifies the argument data is copied to
>   */
>  
>  #ifndef ATTR_FNSPEC_H
> @@ -122,7 +132,8 @@ public:
>    {
>      unsigned int idx = arg_idx (i);
>      gcc_checking_assert (arg_specified_p (i));
> -    return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'W';
> +    return str[idx] == 'R' || str[idx] == 'O'
> +	   || str[idx] == 'W' || str[idx] == 'C';
>    }
>  
>    /* True if argument is used.  */
> @@ -161,6 +172,7 @@ public:
>      unsigned int idx = arg_idx (i);
>      gcc_checking_assert (arg_specified_p (i));
>      return str[idx] != 'r' && str[idx] != 'R'
> +	   && str[idx] != 'c' && str[idx] != 'C'
>  	   && str[idx] != 'x' && str[idx] != 'X';
>    }
>  
> @@ -171,6 +183,8 @@ public:
>    {
>      unsigned int idx = arg_idx (i);
>      gcc_checking_assert (arg_specified_p (i));
> +    if (str[idx] == 'c' || str[idx] == 'C')
> +      return arg_max_access_size_given_by_arg_p (str[idx + 1] - '1', arg);
>      if (str[idx + 1] >= '1' && str[idx + 1] <= '9')
>        {
>  	*arg = str[idx + 1] - '1';
> @@ -187,9 +201,26 @@ public:
>    {
>      unsigned int idx = arg_idx (i);
>      gcc_checking_assert (arg_specified_p (i));
> +    /* We could handle 'c' 'C' but then we would need to have way to check
> +       that both points to sizes are same.  */
>      return str[idx + 1] == 't';
>    }
>  
> +  /* Return true if memory pointer to by argument is copied to a memory
> +     pointed to by a different argument (as in memcpy).
> +     In this case set ARG.  */
> +  bool
> +  arg_copied_to_arg_p (unsigned int i, unsigned int *arg)
> +  {
> +    unsigned int idx = arg_idx (i);
> +    gcc_checking_assert (arg_specified_p (i));
> +    if (str[idx] != 'c' && str[idx] == 'C')
> +      return false;
> +    *arg = str[idx + 1] - '1';
> +    return true;
> +  }
> +
> +
>    /* True if the argument does not escape.  */
>    bool
>    arg_noescape_p (unsigned int i)
> @@ -230,7 +261,7 @@ public:
>      return str[1] != 'c' && str[1] != 'C';
>    }
>  
> -  /* Return true if all memory written by the function 
> +  /* Return true if all memory written by the function
>       is specified by fnspec.  */
>    bool
>    global_memory_written_p ()
> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index da25343beb1..51f2365d971 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -12939,16 +12939,15 @@ builtin_fnspec (tree callee)
>  	 argument.  */
>        case BUILT_IN_STRCAT:
>        case BUILT_IN_STRCAT_CHK:
> -	return "1cW R ";
>        case BUILT_IN_STRNCAT:
>        case BUILT_IN_STRNCAT_CHK:
> -	return "1cW R3";
> +	return "1cW C1";
>        case BUILT_IN_STRCPY:
>        case BUILT_IN_STRCPY_CHK:
> -	return "1cO R ";
> +	return "1cO C1";
>        case BUILT_IN_STPCPY:
>        case BUILT_IN_STPCPY_CHK:
> -	return ".cO R ";
> +	return ".cO C1";
>        case BUILT_IN_STRNCPY:
>        case BUILT_IN_MEMCPY:
>        case BUILT_IN_MEMMOVE:
> @@ -12957,15 +12956,15 @@ builtin_fnspec (tree callee)
>        case BUILT_IN_STRNCPY_CHK:
>        case BUILT_IN_MEMCPY_CHK:
>        case BUILT_IN_MEMMOVE_CHK:
> -	return "1cO3R3";
> +	return "1cO3C1";
>        case BUILT_IN_MEMPCPY:
>        case BUILT_IN_MEMPCPY_CHK:
> -	return ".cO3R3";
> +	return ".cO3C1";
>        case BUILT_IN_STPNCPY:
>        case BUILT_IN_STPNCPY_CHK:
> -	return ".cO3R3";
> +	return ".cO3C1";
>        case BUILT_IN_BCOPY:
> -	return ".cR3O3";
> +	return ".cC2O3";
>        case BUILT_IN_BZERO:
>  	return ".cO2";
>        case BUILT_IN_MEMCMP:
> diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> index e64011d04df..09c622ce918 100644
> --- a/gcc/tree-ssa-alias.c
> +++ b/gcc/tree-ssa-alias.c
> @@ -3797,6 +3797,8 @@ attr_fnspec::verify ()
>        default:
>  	err = true;
>      }
> +  if (err)
> +    internal_error ("invalid fn spec attribute \"%s\"", str);
>  
>    /* Now check all parameters.  */
>    for (unsigned int i = 0; arg_specified_p (i); i++)
> @@ -3813,21 +3815,39 @@ attr_fnspec::verify ()
>  	  case 'w':
>  	  case 'W':
>  	  case '.':
> +	    if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
> +		|| str[idx + 1] == 't')
> +	      {
> +		if (str[idx] != 'r' && str[idx] != 'R'
> +		    && str[idx] != 'w' && str[idx] != 'W'
> +		    && str[idx] != 'o' && str[idx] != 'O')
> +		  err = true;
> +		if (str[idx] != 't'
> +		    /* Size specified is scalar, so it should be described
> +		       by ". " if specified at all.  */
> +		    && (arg_specified_p (str[idx + 1] - '1')
> +			&& str[arg_idx (str[idx + 1] - '1')] != '.'))
> +		  err = true;
> +	      }
> +	    else if (str[idx + 1] != ' ')
> +	      err = true;
> +	    break;
> +	  case 'c':
> +	  case 'C':
> +	    /* Copied arugment should specify the argument being copied
> +	       that should be specified output argument.  */
> +	    if (str[idx + 1] < '1' || str[idx + 1] > '9'
> +		|| !arg_specified_p (str[idx + 1] - '1')
> +		|| (str[arg_idx (str[idx + 1] - '1')] != 'W'
> +		    && str[arg_idx (str[idx + 1] - '1')] != 'w'
> +		    && str[arg_idx (str[idx + 1] - '1')] != 'O'
> +		    && str[arg_idx (str[idx + 1] - '1')] != 'o'))
> +	      err = true;
>  	    break;
>  	  default:
>  	    err = true;
>  	}
> -      if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
> -	  || str[idx + 1] == 't')
> -	{
> -	  if (str[idx] != 'r' && str[idx] != 'R'
> -	      && str[idx] != 'w' && str[idx] != 'W'
> -	      && str[idx] != 'o' && str[idx] != 'O')
> -	    err = true;
> -	}
> -      else if (str[idx + 1] != ' ')
> -	err = true;
> +      if (err)
> +	internal_error ("invalid fn spec attribute \"%s\" arg %i", str, i);
>      }
> -  if (err)
> -    internal_error ("invalid fn spec attribute \"%s\"", str);
>  }
>
Jan Hubicka Nov. 12, 2020, 12:40 p.m. UTC | #2
Hi,
here is updated patch that replaces 'C' by '1'...'9' so we still have
place to specify size.
As discussed on IRC, this seems better alternative.

Bootstrapped/regtested x86_64-linux, OK?

Honza

gcc/ChangeLog:

2020-11-12  Jan Hubicka  <hubicka@ucw.cz>

	* attr-fnspec.h: Update topleve comment.
	(attr_fnspec::arg_direct_p): Accept 1...9.
	(attr_fnspec::arg_maybe_written_p): Reject 1...9.
	(attr_fnspec::arg_copied_to_arg_p): New member function.
	* builtins.c (builtin_fnspec): Update fnspec of block copy.
	* tree-ssa-alias.c (attr_fnspec::verify): Update.

diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
index 28135328437..766414a2520 100644
--- a/gcc/attr-fnspec.h
+++ b/gcc/attr-fnspec.h
@@ -41,6 +41,9 @@
 		written and does not escape
      'w' or 'W' specifies that the memory pointed to by the parameter does not
 		escape
+     '1'....'9' specifies that the memory pointed to by the parameter is
+		copied to memory pointed to by different parameter
+		(as in memcpy).
      '.'	specifies that nothing is known.
    The uppercase letter in addition specifies that the memory pointed to
    by the parameter is not dereferenced.  For 'r' only read applies
@@ -51,8 +54,8 @@
      ' '        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
+     '1'...'9'  specifies the size of value written/read is given by the
+		specified argument
  */
 
 #ifndef ATTR_FNSPEC_H
@@ -122,7 +125,8 @@ public:
   {
     unsigned int idx = arg_idx (i);
     gcc_checking_assert (arg_specified_p (i));
-    return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'W';
+    return str[idx] == 'R' || str[idx] == 'O'
+	   || str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9');
   }
 
   /* True if argument is used.  */
@@ -161,6 +165,7 @@ public:
     unsigned int idx = arg_idx (i);
     gcc_checking_assert (arg_specified_p (i));
     return str[idx] != 'r' && str[idx] != 'R'
+	   && (str[idx] < '1' || str[idx] > '9')
 	   && str[idx] != 'x' && str[idx] != 'X';
   }
 
@@ -190,6 +195,21 @@ public:
     return str[idx + 1] == 't';
   }
 
+  /* Return true if memory pointer to by argument is copied to a memory
+     pointed to by a different argument (as in memcpy).
+     In this case set ARG.  */
+  bool
+  arg_copied_to_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' || str[idx] > '9')
+      return false;
+    *arg = str[idx] - '1';
+    return true;
+  }
+
+
   /* True if the argument does not escape.  */
   bool
   arg_noescape_p (unsigned int i)
@@ -230,7 +250,7 @@ public:
     return str[1] != 'c' && str[1] != 'C';
   }
 
-  /* Return true if all memory written by the function 
+  /* Return true if all memory written by the function
      is specified by fnspec.  */
   bool
   global_memory_written_p ()
diff --git a/gcc/builtins.c b/gcc/builtins.c
index da25343beb1..4ec1766cffd 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -12939,16 +12939,16 @@ builtin_fnspec (tree callee)
 	 argument.  */
       case BUILT_IN_STRCAT:
       case BUILT_IN_STRCAT_CHK:
-	return "1cW R ";
+	return "1cW 1 ";
       case BUILT_IN_STRNCAT:
       case BUILT_IN_STRNCAT_CHK:
-	return "1cW R3";
+	return "1cW 13";
       case BUILT_IN_STRCPY:
       case BUILT_IN_STRCPY_CHK:
-	return "1cO R ";
+	return "1cO 1 ";
       case BUILT_IN_STPCPY:
       case BUILT_IN_STPCPY_CHK:
-	return ".cO R ";
+	return ".cO 1 ";
       case BUILT_IN_STRNCPY:
       case BUILT_IN_MEMCPY:
       case BUILT_IN_MEMMOVE:
@@ -12957,15 +12957,15 @@ builtin_fnspec (tree callee)
       case BUILT_IN_STRNCPY_CHK:
       case BUILT_IN_MEMCPY_CHK:
       case BUILT_IN_MEMMOVE_CHK:
-	return "1cO3R3";
+	return "1cO313";
       case BUILT_IN_MEMPCPY:
       case BUILT_IN_MEMPCPY_CHK:
-	return ".cO3R3";
+	return ".cO313";
       case BUILT_IN_STPNCPY:
       case BUILT_IN_STPNCPY_CHK:
-	return ".cO3R3";
+	return ".cO313";
       case BUILT_IN_BCOPY:
-	return ".cR3O3";
+	return ".c23O3";
       case BUILT_IN_BZERO:
 	return ".cO2";
       case BUILT_IN_MEMCMP:
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index e64011d04df..b1e8e5b5352 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -3797,6 +3797,8 @@ attr_fnspec::verify ()
       default:
 	err = true;
     }
+  if (err)
+    internal_error ("invalid fn spec attribute \"%s\"", str);
 
   /* Now check all parameters.  */
   for (unsigned int i = 0; arg_specified_p (i); i++)
@@ -3813,21 +3815,28 @@ attr_fnspec::verify ()
 	  case 'w':
 	  case 'W':
 	  case '.':
+	    if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
+		|| str[idx + 1] == 't')
+	      {
+		if (str[idx] != 'r' && str[idx] != 'R'
+		    && str[idx] != 'w' && str[idx] != 'W'
+		    && str[idx] != 'o' && str[idx] != 'O')
+		  err = true;
+		if (str[idx] != 't'
+		    /* Size specified is scalar, so it should be described
+		       by ". " if specified at all.  */
+		    && (arg_specified_p (str[idx + 1] - '1')
+			&& str[arg_idx (str[idx + 1] - '1')] != '.'))
+		  err = true;
+	      }
+	    else if (str[idx + 1] != ' ')
+	      err = true;
 	    break;
 	  default:
-	    err = true;
+	    if (str[idx] < '1' || str[idx] > '9')
+	      err = true;
 	}
-      if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
-	  || str[idx + 1] == 't')
-	{
-	  if (str[idx] != 'r' && str[idx] != 'R'
-	      && str[idx] != 'w' && str[idx] != 'W'
-	      && str[idx] != 'o' && str[idx] != 'O')
-	    err = true;
-	}
-      else if (str[idx + 1] != ' ')
-	err = true;
+      if (err)
+	internal_error ("invalid fn spec attribute \"%s\" arg %i", str, i);
     }
-  if (err)
-    internal_error ("invalid fn spec attribute \"%s\"", str);
 }
Richard Biener Nov. 12, 2020, 1:38 p.m. UTC | #3
On Thu, 12 Nov 2020, Jan Hubicka wrote:

> Hi,
> here is updated patch that replaces 'C' by '1'...'9' so we still have
> place to specify size.
> As discussed on IRC, this seems better alternative.
> 
> Bootstrapped/regtested x86_64-linux, OK?

OK.

Richard.

> Honza
> 
> gcc/ChangeLog:
> 
> 2020-11-12  Jan Hubicka  <hubicka@ucw.cz>
> 
> 	* attr-fnspec.h: Update topleve comment.
> 	(attr_fnspec::arg_direct_p): Accept 1...9.
> 	(attr_fnspec::arg_maybe_written_p): Reject 1...9.
> 	(attr_fnspec::arg_copied_to_arg_p): New member function.
> 	* builtins.c (builtin_fnspec): Update fnspec of block copy.
> 	* tree-ssa-alias.c (attr_fnspec::verify): Update.
> 
> diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
> index 28135328437..766414a2520 100644
> --- a/gcc/attr-fnspec.h
> +++ b/gcc/attr-fnspec.h
> @@ -41,6 +41,9 @@
>  		written and does not escape
>       'w' or 'W' specifies that the memory pointed to by the parameter does not
>  		escape
> +     '1'....'9' specifies that the memory pointed to by the parameter is
> +		copied to memory pointed to by different parameter
> +		(as in memcpy).
>       '.'	specifies that nothing is known.
>     The uppercase letter in addition specifies that the memory pointed to
>     by the parameter is not dereferenced.  For 'r' only read applies
> @@ -51,8 +54,8 @@
>       ' '        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
> +     '1'...'9'  specifies the size of value written/read is given by the
> +		specified argument
>   */
>  
>  #ifndef ATTR_FNSPEC_H
> @@ -122,7 +125,8 @@ public:
>    {
>      unsigned int idx = arg_idx (i);
>      gcc_checking_assert (arg_specified_p (i));
> -    return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'W';
> +    return str[idx] == 'R' || str[idx] == 'O'
> +	   || str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9');
>    }
>  
>    /* True if argument is used.  */
> @@ -161,6 +165,7 @@ public:
>      unsigned int idx = arg_idx (i);
>      gcc_checking_assert (arg_specified_p (i));
>      return str[idx] != 'r' && str[idx] != 'R'
> +	   && (str[idx] < '1' || str[idx] > '9')
>  	   && str[idx] != 'x' && str[idx] != 'X';
>    }
>  
> @@ -190,6 +195,21 @@ public:
>      return str[idx + 1] == 't';
>    }
>  
> +  /* Return true if memory pointer to by argument is copied to a memory
> +     pointed to by a different argument (as in memcpy).
> +     In this case set ARG.  */
> +  bool
> +  arg_copied_to_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' || str[idx] > '9')
> +      return false;
> +    *arg = str[idx] - '1';
> +    return true;
> +  }
> +
> +
>    /* True if the argument does not escape.  */
>    bool
>    arg_noescape_p (unsigned int i)
> @@ -230,7 +250,7 @@ public:
>      return str[1] != 'c' && str[1] != 'C';
>    }
>  
> -  /* Return true if all memory written by the function 
> +  /* Return true if all memory written by the function
>       is specified by fnspec.  */
>    bool
>    global_memory_written_p ()
> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index da25343beb1..4ec1766cffd 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -12939,16 +12939,16 @@ builtin_fnspec (tree callee)
>  	 argument.  */
>        case BUILT_IN_STRCAT:
>        case BUILT_IN_STRCAT_CHK:
> -	return "1cW R ";
> +	return "1cW 1 ";
>        case BUILT_IN_STRNCAT:
>        case BUILT_IN_STRNCAT_CHK:
> -	return "1cW R3";
> +	return "1cW 13";
>        case BUILT_IN_STRCPY:
>        case BUILT_IN_STRCPY_CHK:
> -	return "1cO R ";
> +	return "1cO 1 ";
>        case BUILT_IN_STPCPY:
>        case BUILT_IN_STPCPY_CHK:
> -	return ".cO R ";
> +	return ".cO 1 ";
>        case BUILT_IN_STRNCPY:
>        case BUILT_IN_MEMCPY:
>        case BUILT_IN_MEMMOVE:
> @@ -12957,15 +12957,15 @@ builtin_fnspec (tree callee)
>        case BUILT_IN_STRNCPY_CHK:
>        case BUILT_IN_MEMCPY_CHK:
>        case BUILT_IN_MEMMOVE_CHK:
> -	return "1cO3R3";
> +	return "1cO313";
>        case BUILT_IN_MEMPCPY:
>        case BUILT_IN_MEMPCPY_CHK:
> -	return ".cO3R3";
> +	return ".cO313";
>        case BUILT_IN_STPNCPY:
>        case BUILT_IN_STPNCPY_CHK:
> -	return ".cO3R3";
> +	return ".cO313";
>        case BUILT_IN_BCOPY:
> -	return ".cR3O3";
> +	return ".c23O3";
>        case BUILT_IN_BZERO:
>  	return ".cO2";
>        case BUILT_IN_MEMCMP:
> diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> index e64011d04df..b1e8e5b5352 100644
> --- a/gcc/tree-ssa-alias.c
> +++ b/gcc/tree-ssa-alias.c
> @@ -3797,6 +3797,8 @@ attr_fnspec::verify ()
>        default:
>  	err = true;
>      }
> +  if (err)
> +    internal_error ("invalid fn spec attribute \"%s\"", str);
>  
>    /* Now check all parameters.  */
>    for (unsigned int i = 0; arg_specified_p (i); i++)
> @@ -3813,21 +3815,28 @@ attr_fnspec::verify ()
>  	  case 'w':
>  	  case 'W':
>  	  case '.':
> +	    if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
> +		|| str[idx + 1] == 't')
> +	      {
> +		if (str[idx] != 'r' && str[idx] != 'R'
> +		    && str[idx] != 'w' && str[idx] != 'W'
> +		    && str[idx] != 'o' && str[idx] != 'O')
> +		  err = true;
> +		if (str[idx] != 't'
> +		    /* Size specified is scalar, so it should be described
> +		       by ". " if specified at all.  */
> +		    && (arg_specified_p (str[idx + 1] - '1')
> +			&& str[arg_idx (str[idx + 1] - '1')] != '.'))
> +		  err = true;
> +	      }
> +	    else if (str[idx + 1] != ' ')
> +	      err = true;
>  	    break;
>  	  default:
> -	    err = true;
> +	    if (str[idx] < '1' || str[idx] > '9')
> +	      err = true;
>  	}
> -      if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
> -	  || str[idx + 1] == 't')
> -	{
> -	  if (str[idx] != 'r' && str[idx] != 'R'
> -	      && str[idx] != 'w' && str[idx] != 'W'
> -	      && str[idx] != 'o' && str[idx] != 'O')
> -	    err = true;
> -	}
> -      else if (str[idx + 1] != ' ')
> -	err = true;
> +      if (err)
> +	internal_error ("invalid fn spec attribute \"%s\" arg %i", str, i);
>      }
> -  if (err)
> -    internal_error ("invalid fn spec attribute \"%s\"", str);
>  }
>
diff mbox series

Patch

diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
index 28135328437..97405dbdd78 100644
--- a/gcc/attr-fnspec.h
+++ b/gcc/attr-fnspec.h
@@ -41,6 +41,13 @@ 
 		written and does not escape
      'w' or 'W' specifies that the memory pointed to by the parameter does not
 		escape
+     'c' or 'C' specifies that the memory pointed to by the parameter is
+		copied to memory pointed to by different parameter
+		(as in memcpy).  The index of the destination parmeter is
+		specified by following character i.e. "C1" means that memory is
+		copied to parameter pointed to by parameter 1.
+		Size of block copied is determined by size specifier of the
+		destination parameter.
      '.'	specifies that nothing is known.
    The uppercase letter in addition specifies that the memory pointed to
    by the parameter is not dereferenced.  For 'r' only read applies
@@ -51,8 +58,11 @@ 
      ' '        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
+     '1'...'9'  preceeded by 'o', 'O', 'w' or 'W'
+		specifies the size of value written/read is given by the
+		specified argument
+     '1'...'9'  preceeded by 'c', or 'c'
+		specifies the argument data is copied to
  */
 
 #ifndef ATTR_FNSPEC_H
@@ -122,7 +132,8 @@  public:
   {
     unsigned int idx = arg_idx (i);
     gcc_checking_assert (arg_specified_p (i));
-    return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'W';
+    return str[idx] == 'R' || str[idx] == 'O'
+	   || str[idx] == 'W' || str[idx] == 'C';
   }
 
   /* True if argument is used.  */
@@ -161,6 +172,7 @@  public:
     unsigned int idx = arg_idx (i);
     gcc_checking_assert (arg_specified_p (i));
     return str[idx] != 'r' && str[idx] != 'R'
+	   && str[idx] != 'c' && str[idx] != 'C'
 	   && str[idx] != 'x' && str[idx] != 'X';
   }
 
@@ -171,6 +183,8 @@  public:
   {
     unsigned int idx = arg_idx (i);
     gcc_checking_assert (arg_specified_p (i));
+    if (str[idx] == 'c' || str[idx] == 'C')
+      return arg_max_access_size_given_by_arg_p (str[idx + 1] - '1', arg);
     if (str[idx + 1] >= '1' && str[idx + 1] <= '9')
       {
 	*arg = str[idx + 1] - '1';
@@ -187,9 +201,26 @@  public:
   {
     unsigned int idx = arg_idx (i);
     gcc_checking_assert (arg_specified_p (i));
+    /* We could handle 'c' 'C' but then we would need to have way to check
+       that both points to sizes are same.  */
     return str[idx + 1] == 't';
   }
 
+  /* Return true if memory pointer to by argument is copied to a memory
+     pointed to by a different argument (as in memcpy).
+     In this case set ARG.  */
+  bool
+  arg_copied_to_arg_p (unsigned int i, unsigned int *arg)
+  {
+    unsigned int idx = arg_idx (i);
+    gcc_checking_assert (arg_specified_p (i));
+    if (str[idx] != 'c' && str[idx] == 'C')
+      return false;
+    *arg = str[idx + 1] - '1';
+    return true;
+  }
+
+
   /* True if the argument does not escape.  */
   bool
   arg_noescape_p (unsigned int i)
@@ -230,7 +261,7 @@  public:
     return str[1] != 'c' && str[1] != 'C';
   }
 
-  /* Return true if all memory written by the function 
+  /* Return true if all memory written by the function
      is specified by fnspec.  */
   bool
   global_memory_written_p ()
diff --git a/gcc/builtins.c b/gcc/builtins.c
index da25343beb1..51f2365d971 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -12939,16 +12939,15 @@  builtin_fnspec (tree callee)
 	 argument.  */
       case BUILT_IN_STRCAT:
       case BUILT_IN_STRCAT_CHK:
-	return "1cW R ";
       case BUILT_IN_STRNCAT:
       case BUILT_IN_STRNCAT_CHK:
-	return "1cW R3";
+	return "1cW C1";
       case BUILT_IN_STRCPY:
       case BUILT_IN_STRCPY_CHK:
-	return "1cO R ";
+	return "1cO C1";
       case BUILT_IN_STPCPY:
       case BUILT_IN_STPCPY_CHK:
-	return ".cO R ";
+	return ".cO C1";
       case BUILT_IN_STRNCPY:
       case BUILT_IN_MEMCPY:
       case BUILT_IN_MEMMOVE:
@@ -12957,15 +12956,15 @@  builtin_fnspec (tree callee)
       case BUILT_IN_STRNCPY_CHK:
       case BUILT_IN_MEMCPY_CHK:
       case BUILT_IN_MEMMOVE_CHK:
-	return "1cO3R3";
+	return "1cO3C1";
       case BUILT_IN_MEMPCPY:
       case BUILT_IN_MEMPCPY_CHK:
-	return ".cO3R3";
+	return ".cO3C1";
       case BUILT_IN_STPNCPY:
       case BUILT_IN_STPNCPY_CHK:
-	return ".cO3R3";
+	return ".cO3C1";
       case BUILT_IN_BCOPY:
-	return ".cR3O3";
+	return ".cC2O3";
       case BUILT_IN_BZERO:
 	return ".cO2";
       case BUILT_IN_MEMCMP:
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index e64011d04df..09c622ce918 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -3797,6 +3797,8 @@  attr_fnspec::verify ()
       default:
 	err = true;
     }
+  if (err)
+    internal_error ("invalid fn spec attribute \"%s\"", str);
 
   /* Now check all parameters.  */
   for (unsigned int i = 0; arg_specified_p (i); i++)
@@ -3813,21 +3815,39 @@  attr_fnspec::verify ()
 	  case 'w':
 	  case 'W':
 	  case '.':
+	    if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
+		|| str[idx + 1] == 't')
+	      {
+		if (str[idx] != 'r' && str[idx] != 'R'
+		    && str[idx] != 'w' && str[idx] != 'W'
+		    && str[idx] != 'o' && str[idx] != 'O')
+		  err = true;
+		if (str[idx] != 't'
+		    /* Size specified is scalar, so it should be described
+		       by ". " if specified at all.  */
+		    && (arg_specified_p (str[idx + 1] - '1')
+			&& str[arg_idx (str[idx + 1] - '1')] != '.'))
+		  err = true;
+	      }
+	    else if (str[idx + 1] != ' ')
+	      err = true;
+	    break;
+	  case 'c':
+	  case 'C':
+	    /* Copied arugment should specify the argument being copied
+	       that should be specified output argument.  */
+	    if (str[idx + 1] < '1' || str[idx + 1] > '9'
+		|| !arg_specified_p (str[idx + 1] - '1')
+		|| (str[arg_idx (str[idx + 1] - '1')] != 'W'
+		    && str[arg_idx (str[idx + 1] - '1')] != 'w'
+		    && str[arg_idx (str[idx + 1] - '1')] != 'O'
+		    && str[arg_idx (str[idx + 1] - '1')] != 'o'))
+	      err = true;
 	    break;
 	  default:
 	    err = true;
 	}
-      if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
-	  || str[idx + 1] == 't')
-	{
-	  if (str[idx] != 'r' && str[idx] != 'R'
-	      && str[idx] != 'w' && str[idx] != 'W'
-	      && str[idx] != 'o' && str[idx] != 'O')
-	    err = true;
-	}
-      else if (str[idx + 1] != ' ')
-	err = true;
+      if (err)
+	internal_error ("invalid fn spec attribute \"%s\" arg %i", str, i);
     }
-  if (err)
-    internal_error ("invalid fn spec attribute \"%s\"", str);
 }