]>
Commit | Line | Data |
---|---|---|
3c6d4197 | 1 | /* This file is part of the Intel(R) Cilk(TM) Plus support |
2 | This file contains the builtin functions for Array | |
3 | notations. | |
d353bf18 | 4 | Copyright (C) 2013-2015 Free Software Foundation, Inc. |
3c6d4197 | 5 | Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>, |
6 | Intel Corporation | |
7 | ||
8 | This file is part of GCC. | |
9 | ||
10 | GCC is free software; you can redistribute it and/or modify it | |
11 | under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 3, or (at your option) | |
13 | any later version. | |
14 | ||
15 | GCC is distributed in the hope that it will be useful, but | |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
21 | along with GCC; see the file COPYING3. If not see | |
22 | <http://www.gnu.org/licenses/>. */ | |
23 | ||
24 | #include "config.h" | |
25 | #include "system.h" | |
26 | #include "coretypes.h" | |
b20a8bb4 | 27 | #include "alias.h" |
3c6d4197 | 28 | #include "tree.h" |
9ef16211 | 29 | #include "options.h" |
3c6d4197 | 30 | #include "langhooks.h" |
31 | #include "tree-iterator.h" | |
09970d67 | 32 | #include "c-family/c-common.h" |
3c6d4197 | 33 | #include "diagnostic-core.h" |
34 | ||
3c6d4197 | 35 | /* Returns true if the function call in FNDECL is __sec_implicit_index. */ |
36 | ||
37 | bool | |
38 | is_sec_implicit_index_fn (tree fndecl) | |
39 | { | |
8315e35e | 40 | if (!fndecl) |
41 | return false; | |
42 | ||
3c6d4197 | 43 | if (TREE_CODE (fndecl) == ADDR_EXPR) |
44 | fndecl = TREE_OPERAND (fndecl, 0); | |
45 | ||
46 | return | |
47 | (TREE_CODE (fndecl) == FUNCTION_DECL | |
48 | && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL | |
49 | && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CILKPLUS_SEC_IMPLICIT_INDEX); | |
50 | } | |
51 | ||
52 | /* Returns the first and only argument for FN, which should be a | |
53 | sec_implicit_index function. FN's location in the source file is as | |
54 | indicated by LOCATION. The argument to FN must be a constant integer | |
55 | expression, otherwise returns -1. */ | |
56 | ||
57 | HOST_WIDE_INT | |
58 | extract_sec_implicit_index_arg (location_t location, tree fn) | |
59 | { | |
60 | tree fn_arg; | |
61 | HOST_WIDE_INT return_int = 0; | |
62 | ||
63 | if (TREE_CODE (fn) == CALL_EXPR) | |
64 | { | |
65 | fn_arg = CALL_EXPR_ARG (fn, 0); | |
66 | if (TREE_CODE (fn_arg) == INTEGER_CST) | |
67 | return_int = int_cst_value (fn_arg); | |
68 | else | |
69 | { | |
70 | /* If the location is unknown, and if fn has a location, then use that | |
71 | information so that the user has a better idea where the error | |
72 | could be. */ | |
73 | if (location == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (fn)) | |
74 | location = EXPR_LOCATION (fn); | |
75 | error_at (location, "__sec_implicit_index parameter must be an " | |
76 | "integer constant expression"); | |
77 | return -1; | |
78 | } | |
79 | } | |
80 | return return_int; | |
81 | } | |
09970d67 | 82 | |
50acebe0 | 83 | /* Returns true if there is a length mismatch among exprssions that are at the |
84 | same dimension and one the same side of the equal sign. The Array notation | |
85 | lengths (LIST->LENGTH) is passed in as a 2D vector of trees. */ | |
09970d67 | 86 | |
87 | bool | |
50acebe0 | 88 | length_mismatch_in_expr_p (location_t loc, vec<vec<an_parts> >list) |
09970d67 | 89 | { |
90 | size_t ii, jj; | |
50acebe0 | 91 | tree length = NULL_TREE; |
50acebe0 | 92 | |
93 | size_t x = list.length (); | |
94 | size_t y = list[0].length (); | |
95 | ||
09970d67 | 96 | for (jj = 0; jj < y; jj++) |
97 | { | |
50acebe0 | 98 | length = NULL_TREE; |
09970d67 | 99 | for (ii = 0; ii < x; ii++) |
100 | { | |
50acebe0 | 101 | if (!length) |
102 | length = list[ii][jj].length; | |
103 | else if (TREE_CODE (length) == INTEGER_CST) | |
09970d67 | 104 | { |
50acebe0 | 105 | /* If length is a INTEGER, and list[ii][jj] is an integer then |
09970d67 | 106 | check if they are equal. If they are not equal then return |
107 | true. */ | |
936c3081 | 108 | if (TREE_CODE (list[ii][jj].length) == INTEGER_CST |
109 | && !tree_int_cst_equal (list[ii][jj].length, length)) | |
110 | { | |
111 | error_at (loc, "length mismatch in expression"); | |
112 | return true; | |
09970d67 | 113 | } |
114 | } | |
115 | else | |
50acebe0 | 116 | /* We set the length node as the current node just in case it turns |
09970d67 | 117 | out to be an integer. */ |
50acebe0 | 118 | length = list[ii][jj].length; |
09970d67 | 119 | } |
120 | } | |
121 | return false; | |
122 | } | |
123 | ||
124 | /* Given an FNDECL of type FUNCTION_DECL or ADDR_EXPR, return the corresponding | |
125 | BUILT_IN_CILKPLUS_SEC_REDUCE_* being called. If none, return | |
126 | BUILT_IN_NONE. */ | |
127 | ||
128 | enum built_in_function | |
129 | is_cilkplus_reduce_builtin (tree fndecl) | |
130 | { | |
131 | if (!fndecl) | |
132 | return BUILT_IN_NONE; | |
133 | if (TREE_CODE (fndecl) == ADDR_EXPR) | |
134 | fndecl = TREE_OPERAND (fndecl, 0); | |
135 | ||
136 | if (TREE_CODE (fndecl) == FUNCTION_DECL | |
137 | && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) | |
138 | switch (DECL_FUNCTION_CODE (fndecl)) | |
139 | { | |
140 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: | |
141 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: | |
142 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: | |
143 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: | |
144 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: | |
145 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: | |
146 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: | |
147 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: | |
148 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: | |
149 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: | |
150 | case BUILT_IN_CILKPLUS_SEC_REDUCE: | |
151 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: | |
152 | return DECL_FUNCTION_CODE (fndecl); | |
153 | default: | |
154 | break; | |
155 | } | |
156 | ||
157 | return BUILT_IN_NONE; | |
158 | } | |
159 | ||
160 | /* This function will recurse into EXPR finding any | |
161 | ARRAY_NOTATION_EXPRs and calculate the overall rank of EXPR, | |
162 | storing it in *RANK. LOC is the location of the original expression. | |
163 | ||
164 | ORIG_EXPR is the original expression used to display if any rank | |
165 | mismatch errors are found. | |
166 | ||
167 | Upon entry, *RANK must be either 0, or the rank of a parent | |
168 | expression that must have the same rank as the one being | |
169 | calculated. It is illegal to have multiple array notation with different | |
170 | rank in the same expression (see examples below for clarification). | |
171 | ||
172 | If there were any rank mismatches while calculating the rank, an | |
173 | error will be issued, and FALSE will be returned. Otherwise, TRUE | |
174 | is returned. | |
175 | ||
176 | If IGNORE_BUILTIN_FN is TRUE, ignore array notation specific | |
177 | built-in functions (__sec_reduce_*, etc). | |
178 | ||
179 | Here are some examples of array notations and their rank: | |
180 | ||
181 | Expression RANK | |
182 | 5 0 | |
183 | X (a variable) 0 | |
184 | *Y (a pointer) 0 | |
185 | A[5] 0 | |
186 | B[5][10] 0 | |
187 | A[:] 1 | |
188 | B[0:10] 1 | |
189 | C[0:10:2] 1 | |
190 | D[5][0:10:2] 1 (since D[5] is considered "scalar") | |
191 | D[5][:][10] 1 | |
192 | E[:] + 5 1 | |
193 | F[:][:][:] + 5 + X 3 | |
194 | F[:][:][:] + E[:] + 5 + X RANKMISMATCH-ERROR since rank (E[:]) = 1 and | |
195 | rank (F[:][:][:]) = 3. They must be equal | |
196 | or have a rank of zero. | |
197 | F[:][5][10] + E[:] * 5 + *Y 1 | |
198 | ||
199 | int func (int); | |
200 | func (A[:]) 1 | |
201 | func (B[:][:][:][:]) 4 | |
202 | ||
203 | int func2 (int, int) | |
204 | func2 (A[:], B[:][:][:][:]) RANKMISMATCH-ERROR -- Since Rank (A[:]) = 1 | |
205 | and Rank (B[:][:][:][:]) = 4 | |
206 | ||
207 | A[:] + func (B[:][:][:][:]) RANKMISMATCH-ERROR | |
208 | func2 (A[:], B[:]) + func (A) 1 | |
209 | ||
210 | */ | |
211 | ||
212 | bool | |
213 | find_rank (location_t loc, tree orig_expr, tree expr, bool ignore_builtin_fn, | |
214 | size_t *rank) | |
215 | { | |
216 | tree ii_tree; | |
217 | size_t ii = 0, current_rank = 0; | |
218 | ||
219 | if (TREE_CODE (expr) == ARRAY_NOTATION_REF) | |
220 | { | |
221 | ii_tree = expr; | |
222 | while (ii_tree) | |
223 | { | |
224 | if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF) | |
225 | { | |
226 | current_rank++; | |
227 | ii_tree = ARRAY_NOTATION_ARRAY (ii_tree); | |
228 | } | |
d271ec7e | 229 | else if (handled_component_p (ii_tree) |
aa3e402e | 230 | || INDIRECT_REF_P (ii_tree)) |
09970d67 | 231 | ii_tree = TREE_OPERAND (ii_tree, 0); |
232 | else if (TREE_CODE (ii_tree) == PARM_DECL | |
f48c7f4a | 233 | || VAR_P (ii_tree)) |
09970d67 | 234 | break; |
d271ec7e | 235 | else |
236 | gcc_unreachable (); | |
09970d67 | 237 | } |
238 | if (*rank == 0) | |
239 | /* In this case, all the expressions this function has encountered thus | |
240 | far have been scalars or expressions with zero rank. Please see | |
241 | header comment for examples of such expression. */ | |
242 | *rank = current_rank; | |
243 | else if (*rank != current_rank) | |
244 | { | |
245 | /* In this case, find rank is being recursed through a set of | |
246 | expression of the form A <OPERATION> B, where A and B both have | |
247 | array notations in them and the rank of A is not equal to rank of | |
248 | B. | |
249 | A simple example of such case is the following: X[:] + Y[:][:] */ | |
250 | *rank = current_rank; | |
251 | return false; | |
252 | } | |
253 | } | |
254 | else if (TREE_CODE (expr) == STATEMENT_LIST) | |
255 | { | |
256 | tree_stmt_iterator ii_tsi; | |
257 | for (ii_tsi = tsi_start (expr); !tsi_end_p (ii_tsi); | |
258 | tsi_next (&ii_tsi)) | |
259 | if (!find_rank (loc, orig_expr, *tsi_stmt_ptr (ii_tsi), | |
260 | ignore_builtin_fn, rank)) | |
261 | return false; | |
262 | } | |
263 | else | |
264 | { | |
265 | if (TREE_CODE (expr) == CALL_EXPR) | |
266 | { | |
267 | tree func_name = CALL_EXPR_FN (expr); | |
268 | tree prev_arg = NULL_TREE, arg; | |
269 | call_expr_arg_iterator iter; | |
270 | size_t prev_rank = 0; | |
271 | if (TREE_CODE (func_name) == ADDR_EXPR) | |
272 | if (!ignore_builtin_fn) | |
273 | if (is_cilkplus_reduce_builtin (func_name)) | |
274 | /* If it is a built-in function, then we know it returns a | |
275 | scalar. */ | |
276 | return true; | |
936c3081 | 277 | if (!find_rank (loc, orig_expr, func_name, ignore_builtin_fn, rank)) |
278 | return false; | |
09970d67 | 279 | FOR_EACH_CALL_EXPR_ARG (arg, iter, expr) |
280 | { | |
281 | if (!find_rank (loc, orig_expr, arg, ignore_builtin_fn, rank)) | |
282 | { | |
283 | if (prev_arg && EXPR_HAS_LOCATION (prev_arg) | |
284 | && prev_rank != *rank) | |
285 | error_at (EXPR_LOCATION (prev_arg), | |
286 | "rank mismatch between %qE and %qE", prev_arg, | |
287 | arg); | |
288 | else if (prev_arg && prev_rank != *rank) | |
289 | /* Here the original expression is printed as a "heads-up" | |
290 | to the programmer. This is because since there is no | |
291 | location information for the offending argument, the | |
292 | error could be in some internally generated code that is | |
293 | not visible for the programmer. Thus, the correct fix | |
294 | may lie in the original expression. */ | |
295 | error_at (loc, "rank mismatch in expression %qE", | |
296 | orig_expr); | |
297 | return false; | |
298 | } | |
299 | prev_arg = arg; | |
300 | prev_rank = *rank; | |
301 | } | |
302 | } | |
303 | else | |
304 | { | |
305 | tree prev_arg = NULL_TREE; | |
306 | for (ii = 0; ii < TREE_CODE_LENGTH (TREE_CODE (expr)); ii++) | |
307 | { | |
308 | if (TREE_OPERAND (expr, ii) | |
309 | && !find_rank (loc, orig_expr, TREE_OPERAND (expr, ii), | |
310 | ignore_builtin_fn, rank)) | |
311 | { | |
312 | if (prev_arg && EXPR_HAS_LOCATION (prev_arg)) | |
313 | error_at (EXPR_LOCATION (prev_arg), | |
314 | "rank mismatch between %qE and %qE", prev_arg, | |
315 | TREE_OPERAND (expr, ii)); | |
316 | return false; | |
317 | } | |
318 | prev_arg = TREE_OPERAND (expr, ii); | |
319 | } | |
320 | } | |
321 | } | |
322 | return true; | |
323 | } | |
324 | ||
325 | /* Extracts all array notations in NODE and stores them in ARRAY_LIST. If | |
326 | IGNORE_BUILTIN_FN is set, then array notations inside array notation | |
327 | specific built-in functions are ignored. The NODE can be constants, | |
328 | VAR_DECL, PARM_DECLS, STATEMENT_LISTS or full expressions. */ | |
329 | ||
330 | void | |
331 | extract_array_notation_exprs (tree node, bool ignore_builtin_fn, | |
332 | vec<tree, va_gc> **array_list) | |
333 | { | |
334 | size_t ii = 0; | |
8315e35e | 335 | |
336 | if (!node) | |
337 | return; | |
09970d67 | 338 | if (TREE_CODE (node) == ARRAY_NOTATION_REF) |
339 | { | |
340 | vec_safe_push (*array_list, node); | |
341 | return; | |
342 | } | |
3394c80c | 343 | if (TREE_CODE (node) == DECL_EXPR) |
344 | { | |
345 | tree x = DECL_EXPR_DECL (node); | |
346 | if (DECL_INITIAL (x)) | |
347 | extract_array_notation_exprs (DECL_INITIAL (x), | |
348 | ignore_builtin_fn, | |
349 | array_list); | |
350 | } | |
09970d67 | 351 | else if (TREE_CODE (node) == STATEMENT_LIST) |
352 | { | |
353 | tree_stmt_iterator ii_tsi; | |
354 | for (ii_tsi = tsi_start (node); !tsi_end_p (ii_tsi); tsi_next (&ii_tsi)) | |
355 | extract_array_notation_exprs (*tsi_stmt_ptr (ii_tsi), | |
356 | ignore_builtin_fn, array_list); | |
357 | } | |
358 | else if (TREE_CODE (node) == CALL_EXPR) | |
359 | { | |
360 | tree arg; | |
361 | call_expr_arg_iterator iter; | |
362 | if (is_cilkplus_reduce_builtin (CALL_EXPR_FN (node))) | |
363 | { | |
364 | if (ignore_builtin_fn) | |
365 | return; | |
366 | else | |
367 | { | |
368 | vec_safe_push (*array_list, node); | |
369 | return; | |
370 | } | |
371 | } | |
372 | if (is_sec_implicit_index_fn (CALL_EXPR_FN (node))) | |
373 | { | |
374 | vec_safe_push (*array_list, node); | |
375 | return; | |
376 | } | |
936c3081 | 377 | /* This will extract array notations in function pointers. */ |
378 | extract_array_notation_exprs (CALL_EXPR_FN (node), ignore_builtin_fn, | |
379 | array_list); | |
09970d67 | 380 | FOR_EACH_CALL_EXPR_ARG (arg, iter, node) |
381 | extract_array_notation_exprs (arg, ignore_builtin_fn, array_list); | |
382 | } | |
383 | else | |
384 | for (ii = 0; ii < TREE_CODE_LENGTH (TREE_CODE (node)); ii++) | |
385 | if (TREE_OPERAND (node, ii)) | |
386 | extract_array_notation_exprs (TREE_OPERAND (node, ii), | |
387 | ignore_builtin_fn, array_list); | |
388 | return; | |
389 | } | |
390 | ||
391 | /* LIST contains all the array notations found in *ORIG and ARRAY_OPERAND | |
392 | contains the expanded ARRAY_REF. E.g., if LIST[<some_index>] contains | |
393 | an array_notation expression, then ARRAY_OPERAND[<some_index>] contains its | |
394 | expansion. If *ORIG matches LIST[<some_index>] then *ORIG is set to | |
395 | ARRAY_OPERAND[<some_index>]. This function recursively steps through | |
396 | all the sub-trees of *ORIG, if it is larger than a single | |
397 | ARRAY_NOTATION_REF. */ | |
398 | ||
399 | void | |
400 | replace_array_notations (tree *orig, bool ignore_builtin_fn, | |
401 | vec<tree, va_gc> *list, | |
402 | vec<tree, va_gc> *array_operand) | |
403 | { | |
404 | size_t ii = 0; | |
405 | extern tree build_c_cast (location_t, tree, tree); | |
406 | tree node = NULL_TREE, node_replacement = NULL_TREE; | |
407 | ||
408 | if (vec_safe_length (list) == 0) | |
409 | return; | |
410 | ||
411 | if (TREE_CODE (*orig) == ARRAY_NOTATION_REF) | |
412 | { | |
413 | for (ii = 0; vec_safe_iterate (list, ii, &node); ii++) | |
414 | if (*orig == node) | |
415 | { | |
416 | node_replacement = (*array_operand)[ii]; | |
417 | *orig = node_replacement; | |
418 | } | |
419 | } | |
420 | else if (TREE_CODE (*orig) == STATEMENT_LIST) | |
421 | { | |
422 | tree_stmt_iterator ii_tsi; | |
423 | for (ii_tsi = tsi_start (*orig); !tsi_end_p (ii_tsi); tsi_next (&ii_tsi)) | |
424 | replace_array_notations (tsi_stmt_ptr (ii_tsi), ignore_builtin_fn, list, | |
425 | array_operand); | |
426 | } | |
427 | else if (TREE_CODE (*orig) == CALL_EXPR) | |
428 | { | |
429 | tree arg; | |
430 | call_expr_arg_iterator iter; | |
431 | if (is_cilkplus_reduce_builtin (CALL_EXPR_FN (*orig))) | |
432 | { | |
433 | if (!ignore_builtin_fn) | |
434 | { | |
435 | for (ii = 0; vec_safe_iterate (list, ii, &node); ii++) | |
436 | if (*orig == node) | |
437 | { | |
438 | node_replacement = (*array_operand)[ii]; | |
439 | *orig = node_replacement; | |
440 | } | |
441 | } | |
442 | return; | |
443 | } | |
444 | if (is_sec_implicit_index_fn (CALL_EXPR_FN (*orig))) | |
445 | { | |
446 | for (ii = 0; vec_safe_iterate (list, ii, &node); ii++) | |
447 | if (*orig == node) | |
448 | { | |
449 | node_replacement = (*array_operand)[ii]; | |
450 | *orig = build_c_cast (EXPR_LOCATION (*orig), | |
451 | TREE_TYPE (*orig), node_replacement); | |
452 | } | |
453 | return; | |
454 | } | |
936c3081 | 455 | /* Fixes array notations in array notations in function pointers. */ |
456 | replace_array_notations (&CALL_EXPR_FN (*orig), ignore_builtin_fn, list, | |
457 | array_operand); | |
09970d67 | 458 | ii = 0; |
459 | FOR_EACH_CALL_EXPR_ARG (arg, iter, *orig) | |
460 | { | |
461 | replace_array_notations (&arg, ignore_builtin_fn, list, | |
462 | array_operand); | |
463 | CALL_EXPR_ARG (*orig, ii) = arg; | |
464 | ii++; | |
465 | } | |
466 | } | |
467 | else | |
468 | { | |
469 | for (ii = 0; ii < (size_t) TREE_CODE_LENGTH (TREE_CODE (*orig)); ii++) | |
470 | if (TREE_OPERAND (*orig, ii)) | |
471 | replace_array_notations (&TREE_OPERAND (*orig, ii), ignore_builtin_fn, | |
472 | list, array_operand); | |
473 | } | |
474 | return; | |
475 | } | |
476 | ||
477 | /* Callback for walk_tree. Find all the scalar expressions in *TP and push | |
478 | them in DATA struct, typecasted to (void *). If *WALK_SUBTREES is set to 0 | |
479 | then do not go into the *TP's subtrees. Since this function steps through | |
480 | all the subtrees, *TP and TP can be NULL_TREE and NULL, respectively. The | |
481 | function returns NULL_TREE unconditionally. */ | |
482 | ||
483 | tree | |
484 | find_inv_trees (tree *tp, int *walk_subtrees, void *data) | |
485 | { | |
486 | struct inv_list *i_list = (struct inv_list *) data; | |
487 | unsigned int ii = 0; | |
488 | ||
489 | if (!tp || !*tp) | |
490 | return NULL_TREE; | |
491 | if (TREE_CONSTANT (*tp)) | |
492 | return NULL_TREE; /* No need to save constant to a variable. */ | |
493 | if (TREE_CODE (*tp) != COMPOUND_EXPR && !contains_array_notation_expr (*tp)) | |
494 | { | |
495 | vec_safe_push (i_list->list_values, *tp); | |
496 | *walk_subtrees = 0; | |
497 | } | |
498 | else if (TREE_CODE (*tp) == ARRAY_NOTATION_REF | |
499 | || TREE_CODE (*tp) == ARRAY_REF | |
500 | || TREE_CODE (*tp) == CALL_EXPR) | |
501 | /* No need to step through the internals of array notation. */ | |
502 | *walk_subtrees = 0; | |
503 | else | |
504 | { | |
505 | *walk_subtrees = 1; | |
506 | ||
507 | /* This function is used by C and C++ front-ends. In C++, additional | |
508 | tree codes such as TARGET_EXPR must be eliminated. These codes are | |
509 | passed into additional_tcodes and are walked through and checked. */ | |
510 | for (ii = 0; ii < vec_safe_length (i_list->additional_tcodes); ii++) | |
a9c99fc4 | 511 | if (TREE_CODE (*tp) == (*(i_list->additional_tcodes))[ii]) |
09970d67 | 512 | *walk_subtrees = 0; |
513 | } | |
514 | return NULL_TREE; | |
515 | } | |
516 | ||
517 | /* Callback for walk_tree. Replace all the scalar expressions in *TP with the | |
518 | appropriate replacement stored in the struct *DATA (typecasted to void*). | |
519 | The subtrees are not touched if *WALK_SUBTREES is set to zero. */ | |
520 | ||
521 | tree | |
522 | replace_inv_trees (tree *tp, int *walk_subtrees, void *data) | |
523 | { | |
524 | size_t ii = 0; | |
525 | tree t, r; | |
526 | struct inv_list *i_list = (struct inv_list *) data; | |
527 | ||
528 | if (vec_safe_length (i_list->list_values)) | |
529 | { | |
530 | for (ii = 0; vec_safe_iterate (i_list->list_values, ii, &t); ii++) | |
531 | if (simple_cst_equal (*tp, t) == 1) | |
532 | { | |
533 | vec_safe_iterate (i_list->replacement, ii, &r); | |
534 | gcc_assert (r != NULL_TREE); | |
535 | *tp = r; | |
536 | *walk_subtrees = 0; | |
537 | } | |
538 | } | |
539 | else | |
540 | *walk_subtrees = 0; | |
541 | return NULL_TREE; | |
542 | } | |
543 | ||
544 | /* Returns true if EXPR or any of its subtrees contain ARRAY_NOTATION_EXPR | |
545 | node. */ | |
546 | ||
547 | bool | |
548 | contains_array_notation_expr (tree expr) | |
549 | { | |
550 | vec<tree, va_gc> *array_list = NULL; | |
551 | ||
552 | if (!expr) | |
553 | return false; | |
554 | if (TREE_CODE (expr) == FUNCTION_DECL) | |
555 | if (is_cilkplus_reduce_builtin (expr)) | |
556 | return true; | |
557 | ||
558 | extract_array_notation_exprs (expr, false, &array_list); | |
559 | if (vec_safe_length (array_list) == 0) | |
560 | return false; | |
561 | else | |
562 | return true; | |
563 | } | |
564 | ||
565 | /* This function will check if OP is a CALL_EXPR that is a built-in array | |
566 | notation function. If so, then we will return its type to be the type of | |
567 | the array notation inside. */ | |
568 | ||
569 | tree | |
570 | find_correct_array_notation_type (tree op) | |
571 | { | |
572 | tree fn_arg, return_type = NULL_TREE; | |
573 | ||
574 | if (op) | |
575 | { | |
576 | return_type = TREE_TYPE (op); /* This is the default case. */ | |
577 | if (TREE_CODE (op) == CALL_EXPR) | |
578 | if (is_cilkplus_reduce_builtin (CALL_EXPR_FN (op))) | |
579 | { | |
580 | fn_arg = CALL_EXPR_ARG (op, 0); | |
581 | if (fn_arg) | |
582 | return_type = TREE_TYPE (fn_arg); | |
583 | } | |
584 | } | |
585 | return return_type; | |
586 | } | |
e9331eab | 587 | |
588 | /* Extracts all the array notation triplet information from LIST and stores | |
589 | them in the following fields of the 2-D array NODE(size x rank): | |
590 | START, LENGTH and STRIDE, holding the starting index, length, and stride, | |
591 | respectively. In addition, it also sets two bool fields, IS_VECTOR and | |
592 | COUNT_DOWN, in NODE indicating whether a certain value at a certain field | |
593 | is a vector and if the array is accessed from high to low. */ | |
594 | ||
595 | void | |
596 | cilkplus_extract_an_triplets (vec<tree, va_gc> *list, size_t size, size_t rank, | |
597 | vec<vec<struct cilkplus_an_parts> > *node) | |
598 | { | |
599 | vec<vec<tree> > array_exprs = vNULL; | |
936c3081 | 600 | |
e9331eab | 601 | node->safe_grow_cleared (size); |
602 | array_exprs.safe_grow_cleared (size); | |
936c3081 | 603 | |
604 | if (rank > 0) | |
605 | for (size_t ii = 0; ii < size; ii++) | |
e9331eab | 606 | { |
936c3081 | 607 | (*node)[ii].safe_grow_cleared (rank); |
608 | array_exprs[ii].safe_grow_cleared (rank); | |
e9331eab | 609 | } |
e9331eab | 610 | for (size_t ii = 0; ii < size; ii++) |
611 | { | |
612 | size_t jj = 0; | |
613 | tree ii_tree = (*list)[ii]; | |
614 | while (ii_tree) | |
936c3081 | 615 | { |
616 | if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF) | |
617 | { | |
618 | array_exprs[ii][jj] = ii_tree; | |
619 | jj++; | |
620 | ii_tree = ARRAY_NOTATION_ARRAY (ii_tree); | |
621 | } | |
622 | else if (TREE_CODE (ii_tree) == ARRAY_REF) | |
623 | ii_tree = TREE_OPERAND (ii_tree, 0); | |
624 | else | |
625 | break; | |
626 | } | |
e9331eab | 627 | } |
628 | for (size_t ii = 0; ii < size; ii++) | |
629 | if (TREE_CODE ((*list)[ii]) == ARRAY_NOTATION_REF) | |
630 | for (size_t jj = 0; jj < rank; jj++) | |
936c3081 | 631 | { |
632 | tree ii_tree = array_exprs[ii][jj]; | |
633 | (*node)[ii][jj].is_vector = true; | |
634 | (*node)[ii][jj].value = ARRAY_NOTATION_ARRAY (ii_tree); | |
635 | (*node)[ii][jj].start = ARRAY_NOTATION_START (ii_tree); | |
636 | (*node)[ii][jj].length = | |
637 | fold_build1 (CONVERT_EXPR, integer_type_node, | |
638 | ARRAY_NOTATION_LENGTH (ii_tree)); | |
639 | (*node)[ii][jj].stride = | |
640 | fold_build1 (CONVERT_EXPR, integer_type_node, | |
641 | ARRAY_NOTATION_STRIDE (ii_tree)); | |
642 | } | |
e9331eab | 643 | } |
644 | ||
645 | /* Replaces all the __sec_implicit_arg functions in LIST with the induction | |
646 | variable stored in VAR at the appropriate location pointed by the | |
647 | __sec_implicit_arg's first parameter. Emits an error if the parameter is | |
648 | not between 0 and RANK. */ | |
649 | ||
650 | vec <tree, va_gc> * | |
651 | fix_sec_implicit_args (location_t loc, vec <tree, va_gc> *list, | |
652 | vec<an_loop_parts> an_loop_info, size_t rank, | |
653 | tree orig_stmt) | |
654 | { | |
655 | vec <tree, va_gc> *array_operand = NULL; | |
656 | for (size_t ii = 0; ii < vec_safe_length (list); ii++) | |
657 | if (TREE_CODE ((*list)[ii]) == CALL_EXPR | |
e9331eab | 658 | && is_sec_implicit_index_fn (CALL_EXPR_FN ((*list)[ii]))) |
659 | { | |
660 | int idx = extract_sec_implicit_index_arg (loc, (*list)[ii]); | |
936c3081 | 661 | if (idx < 0) |
e9331eab | 662 | /* In this case, the returning function would have emitted an |
663 | error thus it is not necessary to do so again. */ | |
664 | return NULL; | |
936c3081 | 665 | else if (idx < (int) rank) |
666 | vec_safe_push (array_operand, an_loop_info[idx].var); | |
e9331eab | 667 | else |
668 | { | |
669 | error_at (loc, "__sec_implicit_index argument %d must be " | |
670 | "less than the rank of %qE", idx, orig_stmt); | |
671 | return NULL; | |
672 | } | |
673 | } | |
674 | else | |
675 | /* Save the existing value into the array operand. */ | |
676 | vec_safe_push (array_operand, (*list)[ii]); | |
677 | return array_operand; | |
678 | } |