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