From: Jan Hubicka Date: Fri, 2 Oct 2020 11:31:05 +0000 (+0200) Subject: Commonize handling of attr-fnspec X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=05d39f0de9ee0455d7b2b60f314f4231bc9a87c1;p=gcc.git Commonize handling of attr-fnspec * 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. --- diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h new file mode 100644 index 00000000000..607c0cf0f54 --- /dev/null +++ b/gcc/attr-fnspec.h @@ -0,0 +1,145 @@ +/* Handling of fnspec attribute specifiers + Copyright (C) 2008-2020 Free Software Foundation, Inc. + Contributed by Richard Guenther + + 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 + . */ + +/* 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 */ diff --git a/gcc/calls.c b/gcc/calls.c index ed4363811c8..93da3d6256e 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -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. */ diff --git a/gcc/gimple.c b/gcc/gimple.c index 523d845de89..f19e24d29b3 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -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; } diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c index 0d016134774..1493b323956 100644 --- a/gcc/tree-into-ssa.c +++ b/gcc/tree-into-ssa.c @@ -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) diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 9e5c3eee500..52aeaebf476 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -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); +}