Commonize handling of attr-fnspec
authorJan Hubicka <jh@suse.cz>
Fri, 2 Oct 2020 11:31:05 +0000 (13:31 +0200)
committerJan Hubicka <jh@suse.cz>
Fri, 2 Oct 2020 11:31:05 +0000 (13:31 +0200)
* attr-fnspec.h: New file.
* calls.c (decl_return_flags): Use attr_fnspec.
* gimple.c (gimple_call_arg_flags): Use attr_fnspec.
(gimple_call_return_flags): Use attr_fnspec.
* tree-into-ssa.c (pass_build_ssa::execute): Use attr_fnspec.
* tree-ssa-alias.c (attr_fnspec::verify): New member fuction.

gcc/attr-fnspec.h [new file with mode: 0644]
gcc/calls.c
gcc/gimple.c
gcc/tree-into-ssa.c
gcc/tree-ssa-alias.c

diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
new file mode 100644 (file)
index 0000000..607c0cf
--- /dev/null
@@ -0,0 +1,145 @@
+/* Handling of fnspec attribute specifiers
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   Contributed by Richard Guenther  <rguenther@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)
+  {
+    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';
+  }
+
+  /* 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';
+  }
+
+  /* Return true if function returns value of its parameter.  If ARG_NO is
+     non-NULL return initialize it to the argument returned.  */
+  bool
+  returns_arg (unsigned int *arg_no)
+  {
+    if (str[0] >= '1' && str[0] <= '4')
+      {
+       if (arg_no)
+         *arg_no = str[0] - '1';
+       return true;
+      }
+    return false;
+  }
+
+  /* Nonzero if the return value does not alias with anything.  Functions
+     with the malloc attribute have this set on their return value.  */
+  bool
+  returns_noalias_p ()
+  {
+    return str[0] == 'm';
+  }
+
+  /* Check validity of the string.  */
+  void verify ();
+};
+
+#endif /* ATTR_FNSPEC_H  */
index ed43638..93da3d6 100644 (file)
@@ -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;
+  unsigned int arg;
+  if (fnspec.returns_arg (&arg))
+    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.  */
index 523d845..f19e24d 100644 (file)
@@ -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
@@ -1512,31 +1513,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.  */
@@ -1550,24 +1546,17 @@ 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;
+  unsigned int arg_no;
+  if (fnspec.returns_arg (&arg_no))
+    return ERF_RETURNS_ARG | arg_no;
 
-    case '.':
-    default:
-      return 0;
-    }
+  if (fnspec.returns_noalias_p ())
+    return ERF_NOALIAS;
+  return 0;
 }
 
 
index 0d01613..1493b32 100644 (file)
@@ -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)
index 9e5c3ee..52aeaeb 100644 (file)
@@ -40,6 +40,8 @@ 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"
+#include "errors.h"
 
 /* Broad overview of how alias analysis on gimple works:
 
@@ -4012,3 +4014,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);
+}