1 | /* Handling of fnspec attribute specifiers |
2 | Copyright (C) 2008-2023 Free Software Foundation, Inc. |
3 | Contributed by Richard Guenther <rguenther@suse.de> |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify |
8 | under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 3 of the License, or |
10 | (at your option) any later version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | /* Parse string of attribute "fn spec". This is an internal attribute |
22 | describing side effects of a function as follows: |
23 | |
24 | character 0 specifies properties of return values as follows: |
25 | '1'...'4' specifies number of argument function returns (as in memset) |
26 | 'm' specifies that returned value is noalias (as in malloc) |
27 | '.' specifies that nothing is known. |
28 | character 1 specifies additional function properties |
29 | ' ' specifies that nothing is known |
30 | 'p' or 'P' specifies that function is pure except for described side |
31 | effects. |
32 | 'c' or 'C' specifies that function is const except for described side |
33 | effects. |
34 | The uppercase letter in addition specifies that function clobbers errno. |
35 | |
36 | character 2+2i specifies properties of argument number i as follows: |
37 | 'x' or 'X' specifies that parameter is unused. |
38 | 'r' or 'R' specifies that the memory pointed to by the parameter is only |
39 | read and does not escape |
40 | 'o' or 'O' specifies that the memory pointed to by the parameter is only |
41 | written and does not escape |
42 | 'w' or 'W' specifies that the memory pointed to by the parameter does not |
43 | escape |
44 | '1'....'9' specifies that the memory pointed to by the parameter is |
45 | copied to memory pointed to by different parameter |
46 | (as in memcpy). |
47 | '.' specifies that nothing is known. |
48 | The uppercase letter in addition specifies that the memory pointed to |
49 | by the parameter is not dereferenced. For 'r' only read applies |
50 | transitively to pointers read from the pointed-to memory. |
51 | |
52 | character 3+2i specifies additional properties of argument number i |
53 | as follows: |
54 | ' ' nothing is known |
55 | 't' the size of value written/read corresponds to the size of |
56 | of the pointed-to type of the argument type |
57 | '1'...'9' specifies the size of value written/read is bound by the |
58 | specified argument |
59 | */ |
60 | |
61 | #ifndef ATTR_FNSPEC_H |
62 | #define ATTR_FNSPEC_H |
63 | |
64 | class attr_fnspec |
65 | { |
66 | private: |
67 | /* fn spec attribute string. */ |
68 | const char *str; |
69 | /* length of the fn spec string. */ |
70 | const unsigned len; |
71 | /* Number of characters specifying return value. */ |
72 | const unsigned int return_desc_size = 2; |
73 | /* Number of characters specifying size. */ |
74 | const unsigned int arg_desc_size = 2; |
75 | |
76 | /* Return start of specifier of arg i. */ |
77 | unsigned int arg_idx (int i) |
78 | { |
79 | return return_desc_size + arg_desc_size * i; |
80 | } |
81 | |
82 | public: |
83 | attr_fnspec (const char *str, unsigned len) |
84 | : str (str), len (len) |
85 | { |
86 | if (flag_checking) |
87 | verify (); |
88 | } |
89 | attr_fnspec (const char *str) |
90 | : str (str), len (strlen (s: str)) |
91 | { |
92 | if (flag_checking) |
93 | verify (); |
94 | } |
95 | attr_fnspec (const_tree identifier) |
96 | : str (TREE_STRING_POINTER (identifier)), |
97 | len (TREE_STRING_LENGTH (identifier)) |
98 | { |
99 | if (flag_checking) |
100 | verify (); |
101 | } |
102 | attr_fnspec () |
103 | : str (NULL), len (0) |
104 | { |
105 | } |
106 | |
107 | /* Return true if fn spec is known. */ |
108 | bool |
109 | known_p () |
110 | { |
111 | return len; |
112 | } |
113 | |
114 | /* Return true if arg I is specified. */ |
115 | bool |
116 | arg_specified_p (unsigned int i) |
117 | { |
118 | return len >= arg_idx (i: i + 1); |
119 | } |
120 | |
121 | /* True if the argument is not dereferenced recursively, thus only |
122 | directly reachable memory is read or written. */ |
123 | bool |
124 | arg_direct_p (unsigned int i) |
125 | { |
126 | unsigned int idx = arg_idx (i); |
127 | gcc_checking_assert (arg_specified_p (i)); |
128 | return str[idx] == 'R' || str[idx] == 'O' |
129 | || str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9'); |
130 | } |
131 | |
132 | /* True if argument is used. */ |
133 | bool |
134 | arg_used_p (unsigned int i) |
135 | { |
136 | unsigned int idx = arg_idx (i); |
137 | gcc_checking_assert (arg_specified_p (i)); |
138 | return str[idx] != 'x' && str[idx] != 'X'; |
139 | } |
140 | |
141 | /* True if memory reached by the argument is readonly (not clobbered). */ |
142 | bool |
143 | arg_readonly_p (unsigned int i) |
144 | { |
145 | unsigned int idx = arg_idx (i); |
146 | gcc_checking_assert (arg_specified_p (i)); |
147 | return str[idx] == 'r' || str[idx] == 'R' || (str[idx] >= '1' && str[idx] <= '9'); |
148 | } |
149 | |
150 | /* True if memory reached by the argument is read (directly or indirectly) */ |
151 | bool |
152 | arg_maybe_read_p (unsigned int i) |
153 | { |
154 | unsigned int idx = arg_idx (i); |
155 | gcc_checking_assert (arg_specified_p (i)); |
156 | return str[idx] != 'o' && str[idx] != 'O' |
157 | && str[idx] != 'x' && str[idx] != 'X'; |
158 | } |
159 | |
160 | /* True if memory reached by the argument is written. |
161 | (directly or indirectly) */ |
162 | bool |
163 | arg_maybe_written_p (unsigned int i) |
164 | { |
165 | unsigned int idx = arg_idx (i); |
166 | gcc_checking_assert (arg_specified_p (i)); |
167 | return str[idx] != 'r' && str[idx] != 'R' |
168 | && (str[idx] < '1' || str[idx] > '9') |
169 | && str[idx] != 'x' && str[idx] != 'X'; |
170 | } |
171 | |
172 | /* Return true if load of memory pointed to by argument I is bound |
173 | by another argument. In this case set ARG. */ |
174 | bool |
175 | arg_max_access_size_given_by_arg_p (unsigned int i, unsigned int *arg) |
176 | { |
177 | unsigned int idx = arg_idx (i); |
178 | gcc_checking_assert (arg_specified_p (i)); |
179 | if (str[idx + 1] >= '1' && str[idx + 1] <= '9') |
180 | { |
181 | *arg = str[idx + 1] - '1'; |
182 | return true; |
183 | } |
184 | else |
185 | return false; |
186 | } |
187 | |
188 | /* Return true if the pointed-to type of the argument correspond to the |
189 | size of the memory acccess. */ |
190 | bool |
191 | arg_access_size_given_by_type_p (unsigned int i) |
192 | { |
193 | unsigned int idx = arg_idx (i); |
194 | gcc_checking_assert (arg_specified_p (i)); |
195 | return str[idx + 1] == 't'; |
196 | } |
197 | |
198 | /* Return true if memory pointer to by argument is copied to a memory |
199 | pointed to by a different argument (as in memcpy). |
200 | In this case set ARG. */ |
201 | bool |
202 | arg_copied_to_arg_p (unsigned int i, unsigned int *arg) |
203 | { |
204 | unsigned int idx = arg_idx (i); |
205 | gcc_checking_assert (arg_specified_p (i)); |
206 | if (str[idx] < '1' || str[idx] > '9') |
207 | return false; |
208 | *arg = str[idx] - '1'; |
209 | return true; |
210 | } |
211 | |
212 | |
213 | /* True if the argument does not escape. */ |
214 | bool |
215 | arg_noescape_p (unsigned int i) |
216 | { |
217 | unsigned int idx = arg_idx (i); |
218 | gcc_checking_assert (arg_specified_p (i)); |
219 | return str[idx] == 'w' || str[idx] == 'W' |
220 | || str[idx] == 'r' || str[idx] == 'R' |
221 | || str[idx] == 'o' || str[idx] == 'O'; |
222 | } |
223 | |
224 | /* Return true if function returns value of its parameter. If ARG_NO is |
225 | non-NULL return initialize it to the argument returned. */ |
226 | bool |
227 | returns_arg (unsigned int *arg_no) |
228 | { |
229 | if (str[0] >= '1' && str[0] <= '4') |
230 | { |
231 | if (arg_no) |
232 | *arg_no = str[0] - '1'; |
233 | return true; |
234 | } |
235 | return false; |
236 | } |
237 | |
238 | /* Nonzero if the return value does not alias with anything. Functions |
239 | with the malloc attribute have this set on their return value. */ |
240 | bool |
241 | returns_noalias_p () |
242 | { |
243 | return str[0] == 'm'; |
244 | } |
245 | |
246 | /* Return true if all memory read by the function is specified by fnspec. */ |
247 | bool |
248 | global_memory_read_p () |
249 | { |
250 | return str[1] != 'c' && str[1] != 'C'; |
251 | } |
252 | |
253 | /* Return true if all memory written by the function |
254 | is specified by fnspec. */ |
255 | bool |
256 | global_memory_written_p () |
257 | { |
258 | return str[1] != 'c' && str[1] != 'C' && str[1] != 'p' && str[1] != 'P'; |
259 | } |
260 | |
261 | bool |
262 | errno_maybe_written_p () |
263 | { |
264 | return str[1] == 'C' || str[1] == 'P'; |
265 | } |
266 | |
267 | /* Return EAF flags for arg I. */ |
268 | int |
269 | arg_eaf_flags (unsigned int i) |
270 | { |
271 | int flags = 0; |
272 | |
273 | if (!arg_specified_p (i)) |
274 | ; |
275 | else if (!arg_used_p (i)) |
276 | flags = EAF_UNUSED; |
277 | else |
278 | { |
279 | if (arg_direct_p (i)) |
280 | flags |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_ESCAPE |
281 | | EAF_NOT_RETURNED_INDIRECTLY | EAF_NO_INDIRECT_CLOBBER; |
282 | if (arg_noescape_p (i)) |
283 | flags |= EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE; |
284 | if (arg_readonly_p (i)) |
285 | flags |= EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER; |
286 | } |
287 | return flags; |
288 | } |
289 | |
290 | /* Check validity of the string. */ |
291 | void verify (); |
292 | |
293 | /* Return the fnspec string. */ |
294 | const char * |
295 | get_str () |
296 | { |
297 | return str; |
298 | } |
299 | }; |
300 | |
301 | extern attr_fnspec gimple_call_fnspec (const gcall *stmt); |
302 | extern attr_fnspec builtin_fnspec (tree); |
303 | |
304 | #endif /* ATTR_FNSPEC_H */ |
305 | |