]>
Commit | Line | Data |
---|---|---|
05d39f0d | 1 | /* Handling of fnspec attribute specifiers |
a945c346 | 2 | Copyright (C) 2008-2024 Free Software Foundation, Inc. |
05d39f0d JH |
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. | |
762cca00 JH |
28 | character 1 specifies additional function properties |
29 | ' ' specifies that nothing is known | |
4f8cfb42 JH |
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. | |
05d39f0d | 35 | |
762cca00 | 36 | character 2+2i specifies properties of argument number i as follows: |
05d39f0d | 37 | 'x' or 'X' specifies that parameter is unused. |
6b55fa29 JH |
38 | 'r' or 'R' specifies that the memory pointed to by the parameter is only |
39 | read and does not escape | |
4f8cfb42 JH |
40 | 'o' or 'O' specifies that the memory pointed to by the parameter is only |
41 | written and does not escape | |
6b55fa29 JH |
42 | 'w' or 'W' specifies that the memory pointed to by the parameter does not |
43 | escape | |
071a31a5 JH |
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). | |
05d39f0d | 47 | '.' specifies that nothing is known. |
6b55fa29 JH |
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. | |
762cca00 JH |
51 | |
52 | character 3+2i specifies additional properties of argument number i | |
53 | as follows: | |
54 | ' ' nothing is known | |
4f8cfb42 JH |
55 | 't' the size of value written/read corresponds to the size of |
56 | of the pointed-to type of the argument type | |
e8d00353 | 57 | '1'...'9' specifies the size of value written/read is bound by the |
071a31a5 | 58 | specified argument |
762cca00 | 59 | */ |
05d39f0d JH |
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. */ | |
762cca00 | 72 | const unsigned int return_desc_size = 2; |
05d39f0d | 73 | /* Number of characters specifying size. */ |
762cca00 | 74 | const unsigned int arg_desc_size = 2; |
05d39f0d JH |
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 | } | |
4f8cfb42 JH |
89 | attr_fnspec (const char *str) |
90 | : str (str), len (strlen (str)) | |
91 | { | |
92 | if (flag_checking) | |
93 | verify (); | |
94 | } | |
05d39f0d JH |
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 | } | |
4f8cfb42 JH |
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 | } | |
05d39f0d JH |
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 + 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)); | |
071a31a5 JH |
128 | return str[idx] == 'R' || str[idx] == 'O' |
129 | || str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9'); | |
05d39f0d JH |
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)); | |
8fca8142 | 147 | return str[idx] == 'r' || str[idx] == 'R' || (str[idx] >= '1' && str[idx] <= '9'); |
05d39f0d JH |
148 | } |
149 | ||
4f8cfb42 JH |
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' | |
071a31a5 | 168 | && (str[idx] < '1' || str[idx] > '9') |
4f8cfb42 JH |
169 | && str[idx] != 'x' && str[idx] != 'X'; |
170 | } | |
171 | ||
e8d00353 | 172 | /* Return true if load of memory pointed to by argument I is bound |
4f8cfb42 JH |
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 | ||
071a31a5 JH |
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 | ||
05d39f0d JH |
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' | |
4f8cfb42 JH |
220 | || str[idx] == 'r' || str[idx] == 'R' |
221 | || str[idx] == 'o' || str[idx] == 'O'; | |
05d39f0d JH |
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 | ||
4f8cfb42 JH |
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 | ||
071a31a5 | 253 | /* Return true if all memory written by the function |
4f8cfb42 JH |
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 | ||
e2dd12ab JH |
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 | ||
05d39f0d JH |
290 | /* Check validity of the string. */ |
291 | void verify (); | |
6cef01c3 JH |
292 | |
293 | /* Return the fnspec string. */ | |
294 | const char * | |
295 | get_str () | |
296 | { | |
297 | return str; | |
298 | } | |
05d39f0d JH |
299 | }; |
300 | ||
4f8cfb42 JH |
301 | extern attr_fnspec gimple_call_fnspec (const gcall *stmt); |
302 | extern attr_fnspec builtin_fnspec (tree); | |
303 | ||
05d39f0d | 304 | #endif /* ATTR_FNSPEC_H */ |