Add support for copy specifier to fnspec

Jan Hubicka hubicka@ucw.cz
Thu Nov 12 12:40:29 GMT 2020


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);
 }


More information about the Gcc-patches mailing list