| /* Handling of fnspec attribute specifiers |
| Copyright (C) 2008-2022 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 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. |
| 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 |
| '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 |
| transitively to pointers read from the pointed-to memory. |
| |
| 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' specifies the size of value written/read is given by the |
| specified argument |
| */ |
| |
| #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 = 2; |
| /* Number of characters specifying size. */ |
| const unsigned int arg_desc_size = 2; |
| |
| /* 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 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)) |
| { |
| 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 |
| 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] == 'O' |
| || str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9'); |
| } |
| |
| /* 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' || (str[idx] >= '1' && str[idx] <= '9'); |
| } |
| |
| /* True if memory reached by the argument is read (directly or indirectly) */ |
| bool |
| arg_maybe_read_p (unsigned int i) |
| { |
| unsigned int idx = arg_idx (i); |
| gcc_checking_assert (arg_specified_p (i)); |
| return str[idx] != 'o' && str[idx] != 'O' |
| && str[idx] != 'x' && str[idx] != 'X'; |
| } |
| |
| /* True if memory reached by the argument is written. |
| (directly or indirectly) */ |
| bool |
| arg_maybe_written_p (unsigned int i) |
| { |
| 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'; |
| } |
| |
| /* Return true if load of memory pointed to by argument I is specified |
| by another argument. In this case set ARG. */ |
| bool |
| arg_max_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_access_size_given_by_type_p (unsigned int i) |
| { |
| unsigned int idx = arg_idx (i); |
| gcc_checking_assert (arg_specified_p (i)); |
| 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) |
| { |
| 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] == 'o' || str[idx] == 'O'; |
| } |
| |
| /* 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'; |
| } |
| |
| /* Return true if all memory read by the function is specified by fnspec. */ |
| bool |
| global_memory_read_p () |
| { |
| return str[1] != 'c' && str[1] != 'C'; |
| } |
| |
| /* Return true if all memory written by the function |
| is specified by fnspec. */ |
| bool |
| global_memory_written_p () |
| { |
| return str[1] != 'c' && str[1] != 'C' && str[1] != 'p' && str[1] != 'P'; |
| } |
| |
| bool |
| errno_maybe_written_p () |
| { |
| return str[1] == 'C' || str[1] == 'P'; |
| } |
| |
| /* Return EAF flags for arg I. */ |
| int |
| arg_eaf_flags (unsigned int i) |
| { |
| int flags = 0; |
| |
| if (!arg_specified_p (i)) |
| ; |
| else if (!arg_used_p (i)) |
| flags = EAF_UNUSED; |
| else |
| { |
| if (arg_direct_p (i)) |
| flags |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_ESCAPE |
| | EAF_NOT_RETURNED_INDIRECTLY | EAF_NO_INDIRECT_CLOBBER; |
| if (arg_noescape_p (i)) |
| flags |= EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE; |
| if (arg_readonly_p (i)) |
| flags |= EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER; |
| } |
| return flags; |
| } |
| |
| /* Check validity of the string. */ |
| void verify (); |
| |
| /* Return the fnspec string. */ |
| const char * |
| get_str () |
| { |
| return str; |
| } |
| }; |
| |
| extern attr_fnspec gimple_call_fnspec (const gcall *stmt); |
| extern attr_fnspec builtin_fnspec (tree); |
| |
| #endif /* ATTR_FNSPEC_H */ |