flags.h: Don't include flag-types.h or options.h.
[gcc.git] / gcc / c / c-array-notation.c
1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2 This file contains routines to handle Array Notation expression
3 handling routines in the C Compiler.
4 Copyright (C) 2013-2015 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 /* The Array Notation Transformation Technique:
25
26 An array notation expression has 4 major components:
27 1. The array name
28 2. Start Index
29 3. Number of elements we need to acess (we call it length)
30 4. Stride
31
32 For example, A[0:5:2], implies that we are accessing A[0], A[2], A[4],
33 A[6] and A[8]. The user is responsible to make sure the access length does
34 not step outside the array's size.
35
36 In this section, I highlight the overall method on how array notations are
37 broken up into C/C++ code. Almost all the functions follows this overall
38 technique:
39
40 Let's say we have an array notation in a statement like this:
41
42 A[St1:Ln:Str1] = B[St2:Ln:Str2] + <NON ARRAY_NOTATION_STMT>
43
44 where St{1,2} = Starting index,
45 Ln = Number of elements we need to access,
46 and Str{1,2} = the stride.
47 Note: The length of both the array notation expressions must be the same.
48
49 The above expression is broken into the following
50 (with the help of c_finish_loop function from c-typeck.c):
51
52 Tmp_Var = 0;
53 goto compare_label:
54 body_label:
55
56 A[St1+Tmp_Var*Str1] = B[St1+Tmp_Var*Str2] + <NON ARRAY_NOTATION_STMT>;
57 Tmp_Var++;
58
59 compare_label:
60 if (Tmp_Var < Ln)
61 goto body_label;
62 else
63 goto exit_label;
64 exit_label:
65
66 */
67
68 #include "config.h"
69 #include "system.h"
70 #include "coretypes.h"
71 #include "tree.h"
72 #include "alias.h"
73 #include "c-tree.h"
74 #include "gimple-expr.h"
75 #include "tree-iterator.h"
76 #include "opts.h"
77 #include "c-family/c-common.h"
78
79 /* If *VALUE is not of type INTEGER_CST, PARM_DECL or VAR_DECL, then map it
80 to a variable and then set *VALUE to the new variable. */
81
82 static inline void
83 make_triplet_val_inv (location_t loc, tree *value)
84 {
85 tree var, new_exp;
86 if (TREE_CODE (*value) != INTEGER_CST
87 && TREE_CODE (*value) != PARM_DECL
88 && !VAR_P (*value))
89 {
90 var = build_decl (loc, VAR_DECL, NULL_TREE, integer_type_node);
91 new_exp = build_modify_expr (loc, var, TREE_TYPE (var), NOP_EXPR, loc,
92 *value, TREE_TYPE (*value));
93 add_stmt (new_exp);
94 *value = var;
95 }
96 }
97
98 /* Populates the INCR and CMP vectors with the increment (of type POSTINCREMENT
99 or POSTDECREMENT) and comparison (of TYPE GT_EXPR or LT_EXPR) expressions,
100 using data from LENGTH, COUNT_DOWN, and VAR. INCR and CMP vectors are of
101 size RANK. */
102
103 static void
104 create_cmp_incr (location_t loc, vec<an_loop_parts> *node, size_t rank,
105 vec<vec<an_parts> > an_info)
106 {
107 for (size_t ii = 0; ii < rank; ii++)
108 {
109 tree var = (*node)[ii].var;
110 tree length = an_info[0][ii].length;
111 (*node)[ii].incr = build_unary_op (loc, POSTINCREMENT_EXPR, var, 0);
112 (*node)[ii].cmp = build2 (LT_EXPR, boolean_type_node, var, length);
113 }
114 }
115
116 /* Returns a vector of size RANK that contains an array ref that is derived from
117 array notation triplet parameters stored in VALUE, START, STRIDE. IS_VECTOR
118 is used to check if the data stored at its corresponding location is an
119 array notation. VAR is the induction variable passed in by the caller.
120
121 For example: For an array notation A[5:10:2], the vector start will be
122 of size 1 holding '5', stride of same size as start but holding the value of
123 as 2, is_vector as true and count_down as false. Let's assume VAR is 'x'
124 This function returns a vector of size 1 with the following data:
125 A[5 + (x * 2)] .
126 */
127
128 static vec<tree, va_gc> *
129 create_array_refs (location_t loc, vec<vec<an_parts> > an_info,
130 vec<an_loop_parts> an_loop_info, size_t size, size_t rank)
131 {
132 tree ind_mult, ind_incr;
133 vec<tree, va_gc> *array_operand = NULL;
134 for (size_t ii = 0; ii < size; ii++)
135 if (an_info[ii][0].is_vector)
136 {
137 tree array_opr = an_info[ii][rank - 1].value;
138 for (int s_jj = rank - 1; s_jj >= 0; s_jj--)
139 {
140 tree var = an_loop_info[s_jj].var;
141 tree stride = an_info[ii][s_jj].stride;
142 tree start = an_info[ii][s_jj].start;
143 ind_mult = build2 (MULT_EXPR, TREE_TYPE (var), var, stride);
144 ind_incr = build2 (PLUS_EXPR, TREE_TYPE (var), start, ind_mult);
145 array_opr = build_array_ref (loc, array_opr, ind_incr);
146 }
147 vec_safe_push (array_operand, array_opr);
148 }
149 else
150 /* This is just a dummy node to make sure both the list sizes for both
151 array list and array operand list are the same. */
152 vec_safe_push (array_operand, integer_one_node);
153 return array_operand;
154 }
155
156 /* Replaces all the scalar expressions in *NODE. Returns a STATEMENT_LIST that
157 holds the NODE along with variables that holds the results of the invariant
158 expressions. */
159
160 tree
161 replace_invariant_exprs (tree *node)
162 {
163 size_t ix = 0;
164 tree node_list = NULL_TREE;
165 tree t = NULL_TREE, new_var = NULL_TREE, new_node;
166 struct inv_list data;
167
168 data.list_values = NULL;
169 data.replacement = NULL;
170 data.additional_tcodes = NULL;
171 walk_tree (node, find_inv_trees, (void *)&data, NULL);
172
173 if (vec_safe_length (data.list_values))
174 {
175 node_list = push_stmt_list ();
176 for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++)
177 {
178 new_var = build_decl (EXPR_LOCATION (t), VAR_DECL, NULL_TREE,
179 TREE_TYPE (t));
180 gcc_assert (new_var != NULL_TREE && new_var != error_mark_node);
181 new_node = build2 (MODIFY_EXPR, TREE_TYPE (t), new_var, t);
182 add_stmt (new_node);
183 vec_safe_push (data.replacement, new_var);
184 }
185 walk_tree (node, replace_inv_trees, (void *)&data, NULL);
186 node_list = pop_stmt_list (node_list);
187 }
188 return node_list;
189 }
190
191 /* Given a CALL_EXPR to an array notation built-in function in
192 AN_BUILTIN_FN, replace the call with the appropriate loop and
193 computation. Return the computation in *NEW_VAR.
194
195 The return value in *NEW_VAR will always be a scalar. If the
196 built-in is __sec_reduce_mutating, *NEW_VAR is set to NULL_TREE. */
197
198 static tree
199 fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var)
200 {
201 tree new_var_type = NULL_TREE, func_parm, new_expr, new_yes_expr, new_no_expr;
202 tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list;
203 tree new_yes_list, new_cond_expr, new_var_init = NULL_TREE;
204 tree new_exp_init = NULL_TREE;
205 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
206 size_t list_size = 0, rank = 0, ii = 0;
207 tree loop_init, array_op0;
208 tree identity_value = NULL_TREE, call_fn = NULL_TREE, new_call_expr, body;
209 location_t location = UNKNOWN_LOCATION;
210 tree loop_with_init = alloc_stmt_list ();
211 vec<vec<an_parts> > an_info = vNULL;
212 vec<an_loop_parts> an_loop_info = vNULL;
213 enum built_in_function an_type =
214 is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn));
215 if (an_type == BUILT_IN_NONE)
216 return NULL_TREE;
217
218 /* Builtin call should contain at least one argument. */
219 if (call_expr_nargs (an_builtin_fn) == 0)
220 {
221 error_at (EXPR_LOCATION (an_builtin_fn), "Invalid builtin arguments");
222 return error_mark_node;
223 }
224
225 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE
226 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
227 {
228 call_fn = CALL_EXPR_ARG (an_builtin_fn, 2);
229 if (TREE_CODE (call_fn) == ADDR_EXPR)
230 call_fn = TREE_OPERAND (call_fn, 0);
231 identity_value = CALL_EXPR_ARG (an_builtin_fn, 0);
232 func_parm = CALL_EXPR_ARG (an_builtin_fn, 1);
233 }
234 else
235 func_parm = CALL_EXPR_ARG (an_builtin_fn, 0);
236
237 /* Fully fold any EXCESSIVE_PRECISION EXPR that can occur in the function
238 parameter. */
239 func_parm = c_fully_fold (func_parm, false, NULL);
240 if (func_parm == error_mark_node)
241 return error_mark_node;
242
243 location = EXPR_LOCATION (an_builtin_fn);
244
245 if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank))
246 return error_mark_node;
247
248 if (rank == 0)
249 {
250 error_at (location, "Invalid builtin arguments");
251 return error_mark_node;
252 }
253 else if (rank > 1
254 && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
255 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND))
256 {
257 error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot"
258 " have arrays with dimension greater than 1");
259 return error_mark_node;
260 }
261
262 extract_array_notation_exprs (func_parm, true, &array_list);
263 list_size = vec_safe_length (array_list);
264 switch (an_type)
265 {
266 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
267 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
268 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
269 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
270 new_var_type = TREE_TYPE ((*array_list)[0]);
271 break;
272 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
273 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
274 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
275 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
276 new_var_type = integer_type_node;
277 break;
278 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
279 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
280 new_var_type = integer_type_node;
281 break;
282 case BUILT_IN_CILKPLUS_SEC_REDUCE:
283 if (call_fn && identity_value)
284 new_var_type = TREE_TYPE ((*array_list)[0]);
285 break;
286 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
287 new_var_type = NULL_TREE;
288 break;
289 default:
290 gcc_unreachable ();
291 }
292
293 an_loop_info.safe_grow_cleared (rank);
294 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
295 loop_init = alloc_stmt_list ();
296
297 for (ii = 0; ii < rank; ii++)
298 {
299 an_loop_info[ii].var = create_tmp_var (integer_type_node);
300 an_loop_info[ii].ind_init =
301 build_modify_expr (location, an_loop_info[ii].var,
302 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
303 location,
304 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
305 TREE_TYPE (an_loop_info[ii].var));
306 }
307 array_operand = create_array_refs (location, an_info, an_loop_info,
308 list_size, rank);
309 replace_array_notations (&func_parm, true, array_list, array_operand);
310
311 create_cmp_incr (location, &an_loop_info, rank, an_info);
312 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
313 {
314 *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type);
315 gcc_assert (*new_var && *new_var != error_mark_node);
316 }
317 else
318 *new_var = NULL_TREE;
319
320 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
321 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
322 array_ind_value = build_decl (location, VAR_DECL, NULL_TREE,
323 TREE_TYPE (func_parm));
324 array_op0 = (*array_operand)[0];
325 if (INDIRECT_REF_P (array_op0))
326 array_op0 = TREE_OPERAND (array_op0, 0);
327 switch (an_type)
328 {
329 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
330 new_var_init = build_modify_expr
331 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
332 location, build_zero_cst (new_var_type), new_var_type);
333 new_expr = build_modify_expr
334 (location, *new_var, TREE_TYPE (*new_var), PLUS_EXPR,
335 location, func_parm, TREE_TYPE (func_parm));
336 break;
337 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
338 new_var_init = build_modify_expr
339 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
340 location, build_one_cst (new_var_type), new_var_type);
341 new_expr = build_modify_expr
342 (location, *new_var, TREE_TYPE (*new_var), MULT_EXPR,
343 location, func_parm, TREE_TYPE (func_parm));
344 break;
345 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
346 new_var_init = build_modify_expr
347 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
348 location, build_one_cst (new_var_type), new_var_type);
349 /* Initially you assume everything is zero, now if we find a case where
350 it is NOT true, then we set the result to false. Otherwise
351 we just keep the previous value. */
352 new_yes_expr = build_modify_expr
353 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
354 location, build_zero_cst (TREE_TYPE (*new_var)),
355 TREE_TYPE (*new_var));
356 new_no_expr = build_modify_expr
357 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
358 location, *new_var, TREE_TYPE (*new_var));
359 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
360 build_zero_cst (TREE_TYPE (func_parm)));
361 new_expr = build_conditional_expr
362 (location, new_cond_expr, false, new_yes_expr,
363 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
364 break;
365 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
366 new_var_init = build_modify_expr
367 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
368 location, build_one_cst (new_var_type), new_var_type);
369 /* Initially you assume everything is non-zero, now if we find a case
370 where it is NOT true, then we set the result to false. Otherwise
371 we just keep the previous value. */
372 new_yes_expr = build_modify_expr
373 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
374 location, build_zero_cst (TREE_TYPE (*new_var)),
375 TREE_TYPE (*new_var));
376 new_no_expr = build_modify_expr
377 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
378 location, *new_var, TREE_TYPE (*new_var));
379 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
380 build_zero_cst (TREE_TYPE (func_parm)));
381 new_expr = build_conditional_expr
382 (location, new_cond_expr, false, new_yes_expr,
383 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
384 break;
385 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
386 new_var_init = build_modify_expr
387 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
388 location, build_zero_cst (new_var_type), new_var_type);
389 /* Initially we assume there are NO zeros in the list. When we find
390 a non-zero, we keep the previous value. If we find a zero, we
391 set the value to true. */
392 new_yes_expr = build_modify_expr
393 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
394 location, build_one_cst (new_var_type), new_var_type);
395 new_no_expr = build_modify_expr
396 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
397 location, *new_var, TREE_TYPE (*new_var));
398 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
399 build_zero_cst (TREE_TYPE (func_parm)));
400 new_expr = build_conditional_expr
401 (location, new_cond_expr, false, new_yes_expr,
402 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
403 break;
404 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
405 new_var_init = build_modify_expr
406 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
407 location, build_zero_cst (new_var_type), new_var_type);
408 /* Initially we assume there are NO non-zeros in the list. When we find
409 a zero, we keep the previous value. If we find a non-zero, we set
410 the value to true. */
411 new_yes_expr = build_modify_expr
412 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
413 location, build_one_cst (new_var_type), new_var_type);
414 new_no_expr = build_modify_expr
415 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
416 location, *new_var, TREE_TYPE (*new_var));
417 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
418 build_zero_cst (TREE_TYPE (func_parm)));
419 new_expr = build_conditional_expr
420 (location, new_cond_expr, false, new_yes_expr,
421 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
422 break;
423 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
424 if (TYPE_MIN_VALUE (new_var_type))
425 new_var_init = build_modify_expr
426 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
427 location, TYPE_MIN_VALUE (new_var_type), new_var_type);
428 else
429 new_var_init = build_modify_expr
430 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
431 location, func_parm, new_var_type);
432 new_no_expr = build_modify_expr
433 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
434 location, *new_var, TREE_TYPE (*new_var));
435 new_yes_expr = build_modify_expr
436 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
437 location, func_parm, TREE_TYPE (*new_var));
438 new_expr = build_conditional_expr
439 (location,
440 build2 (LT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
441 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
442 break;
443 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
444 if (TYPE_MAX_VALUE (new_var_type))
445 new_var_init = build_modify_expr
446 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
447 location, TYPE_MAX_VALUE (new_var_type), new_var_type);
448 else
449 new_var_init = build_modify_expr
450 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
451 location, func_parm, new_var_type);
452 new_no_expr = build_modify_expr
453 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
454 location, *new_var, TREE_TYPE (*new_var));
455 new_yes_expr = build_modify_expr
456 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
457 location, func_parm, TREE_TYPE (*new_var));
458 new_expr = build_conditional_expr
459 (location,
460 build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
461 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
462 break;
463 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
464 new_var_init = build_modify_expr
465 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
466 location, build_zero_cst (new_var_type), new_var_type);
467 new_exp_init = build_modify_expr
468 (location, array_ind_value, TREE_TYPE (array_ind_value),
469 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
470 new_no_ind = build_modify_expr
471 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
472 location, *new_var, TREE_TYPE (*new_var));
473 new_no_expr = build_modify_expr
474 (location, array_ind_value, TREE_TYPE (array_ind_value),
475 NOP_EXPR,
476 location, array_ind_value, TREE_TYPE (array_ind_value));
477 if (list_size > 1)
478 {
479 new_yes_ind = build_modify_expr
480 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
481 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
482 new_yes_expr = build_modify_expr
483 (location, array_ind_value, TREE_TYPE (array_ind_value),
484 NOP_EXPR,
485 location, func_parm, TREE_TYPE ((*array_operand)[0]));
486 }
487 else
488 {
489 new_yes_ind = build_modify_expr
490 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
491 location, TREE_OPERAND (array_op0, 1),
492 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
493 new_yes_expr = build_modify_expr
494 (location, array_ind_value, TREE_TYPE (array_ind_value),
495 NOP_EXPR,
496 location, func_parm, TREE_OPERAND (array_op0, 1));
497 }
498 new_yes_list = alloc_stmt_list ();
499 append_to_statement_list (new_yes_ind, &new_yes_list);
500 append_to_statement_list (new_yes_expr, &new_yes_list);
501
502 new_no_list = alloc_stmt_list ();
503 append_to_statement_list (new_no_ind, &new_no_list);
504 append_to_statement_list (new_no_expr, &new_no_list);
505
506 new_expr = build_conditional_expr
507 (location,
508 build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
509 func_parm),
510 false,
511 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
512 break;
513 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
514 new_var_init = build_modify_expr
515 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
516 location, build_zero_cst (new_var_type), new_var_type);
517 new_exp_init = build_modify_expr
518 (location, array_ind_value, TREE_TYPE (array_ind_value),
519 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
520 new_no_ind = build_modify_expr
521 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
522 location, *new_var, TREE_TYPE (*new_var));
523 new_no_expr = build_modify_expr
524 (location, array_ind_value, TREE_TYPE (array_ind_value),
525 NOP_EXPR,
526 location, array_ind_value, TREE_TYPE (array_ind_value));
527 if (list_size > 1)
528 {
529 new_yes_ind = build_modify_expr
530 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
531 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
532 new_yes_expr = build_modify_expr
533 (location, array_ind_value, TREE_TYPE (array_ind_value),
534 NOP_EXPR,
535 location, func_parm, TREE_TYPE (array_op0));
536 }
537 else
538 {
539 new_yes_ind = build_modify_expr
540 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
541 location, TREE_OPERAND (array_op0, 1),
542 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
543 new_yes_expr = build_modify_expr
544 (location, array_ind_value, TREE_TYPE (array_ind_value),
545 NOP_EXPR,
546 location, func_parm, TREE_OPERAND (array_op0, 1));
547 }
548 new_yes_list = alloc_stmt_list ();
549 append_to_statement_list (new_yes_ind, &new_yes_list);
550 append_to_statement_list (new_yes_expr, &new_yes_list);
551
552 new_no_list = alloc_stmt_list ();
553 append_to_statement_list (new_no_ind, &new_no_list);
554 append_to_statement_list (new_no_expr, &new_no_list);
555
556 new_expr = build_conditional_expr
557 (location,
558 build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
559 func_parm),
560 false,
561 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
562 break;
563 case BUILT_IN_CILKPLUS_SEC_REDUCE:
564 new_var_init = build_modify_expr
565 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
566 location, identity_value, new_var_type);
567 new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm);
568 new_expr = build_modify_expr
569 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
570 location, new_call_expr, TREE_TYPE (*new_var));
571 break;
572 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
573 new_expr = build_call_expr (call_fn, 2, identity_value, func_parm);
574 break;
575 default:
576 gcc_unreachable ();
577 break;
578 }
579
580 for (ii = 0; ii < rank; ii++)
581 append_to_statement_list (an_loop_info[ii].ind_init, &loop_init);
582
583 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
584 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
585 append_to_statement_list (new_exp_init, &loop_init);
586 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
587 append_to_statement_list (new_var_init, &loop_init);
588
589 append_to_statement_list_force (loop_init, &loop_with_init);
590 body = new_expr;
591 for (ii = 0; ii < rank; ii++)
592 {
593 tree new_loop = push_stmt_list ();
594 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
595 body, NULL_TREE, NULL_TREE, true);
596 body = pop_stmt_list (new_loop);
597 }
598 append_to_statement_list_force (body, &loop_with_init);
599
600 an_info.release ();
601 an_loop_info.release ();
602
603 return loop_with_init;
604 }
605
606 /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
607 The LHS and/or RHS will be array notation expressions that have a MODIFYCODE
608 Their locations are specified by LHS_LOC, RHS_LOC. The location of the
609 modify expression is location. The original type of LHS and RHS are passed
610 in LHS_ORIGTYPE and RHS_ORIGTYPE. */
611
612 tree
613 build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
614 enum tree_code modifycode, location_t rhs_loc,
615 tree rhs, tree rhs_origtype)
616 {
617 bool found_builtin_fn = false;
618 tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
619 tree array_expr = NULL_TREE;
620 tree an_init = NULL_TREE;
621 vec<tree> cond_expr = vNULL;
622 tree body, loop_with_init = alloc_stmt_list();
623 tree scalar_mods = NULL_TREE;
624 vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL;
625 size_t lhs_rank = 0, rhs_rank = 0;
626 size_t ii = 0;
627 vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL;
628 tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE;
629 size_t rhs_list_size = 0, lhs_list_size = 0;
630 vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
631 vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL;
632
633 /* If either of this is true, an error message must have been send out
634 already. Not necessary to send out multiple error messages. */
635 if (lhs == error_mark_node || rhs == error_mark_node)
636 return error_mark_node;
637
638 if (!find_rank (location, rhs, rhs, false, &rhs_rank))
639 return error_mark_node;
640
641 extract_array_notation_exprs (rhs, false, &rhs_list);
642 rhs_list_size = vec_safe_length (rhs_list);
643 an_init = push_stmt_list ();
644 if (rhs_rank)
645 {
646 scalar_mods = replace_invariant_exprs (&rhs);
647 if (scalar_mods)
648 add_stmt (scalar_mods);
649 }
650 for (ii = 0; ii < rhs_list_size; ii++)
651 {
652 tree rhs_node = (*rhs_list)[ii];
653 if (TREE_CODE (rhs_node) == CALL_EXPR)
654 {
655 builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
656 if (builtin_loop == error_mark_node)
657 {
658 pop_stmt_list (an_init);
659 return error_mark_node;
660 }
661 else if (builtin_loop)
662 {
663 add_stmt (builtin_loop);
664 found_builtin_fn = true;
665 if (new_var)
666 {
667 vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
668 vec_safe_push (rhs_sub_list, rhs_node);
669 vec_safe_push (new_var_list, new_var);
670 replace_array_notations (&rhs, false, rhs_sub_list,
671 new_var_list);
672 }
673 }
674 }
675 }
676
677 lhs_rank = 0;
678 rhs_rank = 0;
679 if (!find_rank (location, lhs, lhs, true, &lhs_rank))
680 {
681 pop_stmt_list (an_init);
682 return error_mark_node;
683 }
684
685 if (!find_rank (location, rhs, rhs, true, &rhs_rank))
686 {
687 pop_stmt_list (an_init);
688 return error_mark_node;
689 }
690
691 if (lhs_rank == 0 && rhs_rank == 0)
692 {
693 if (found_builtin_fn)
694 {
695 new_modify_expr = build_modify_expr (location, lhs, lhs_origtype,
696 modifycode, rhs_loc, rhs,
697 rhs_origtype);
698 add_stmt (new_modify_expr);
699 pop_stmt_list (an_init);
700 return an_init;
701 }
702 else
703 {
704 pop_stmt_list (an_init);
705 return NULL_TREE;
706 }
707 }
708 rhs_list_size = 0;
709 rhs_list = NULL;
710 extract_array_notation_exprs (rhs, true, &rhs_list);
711 extract_array_notation_exprs (lhs, true, &lhs_list);
712 rhs_list_size = vec_safe_length (rhs_list);
713 lhs_list_size = vec_safe_length (lhs_list);
714
715 if (lhs_rank == 0 && rhs_rank != 0)
716 {
717 tree rhs_base = rhs;
718 if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
719 {
720 for (ii = 0; ii < (size_t) rhs_rank; ii++)
721 rhs_base = ARRAY_NOTATION_ARRAY (rhs);
722
723 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
724 rhs_base);
725 return error_mark_node;
726 }
727 else
728 {
729 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
730 rhs_base);
731 return error_mark_node;
732 }
733 }
734 if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
735 {
736 error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
737 pop_stmt_list (an_init);
738 return error_mark_node;
739 }
740
741 /* Here we assign the array notation components to variable so that we can
742 satisfy the exec once rule. */
743 for (ii = 0; ii < lhs_list_size; ii++)
744 {
745 tree array_node = (*lhs_list)[ii];
746 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
747 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
748 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
749 }
750 for (ii = 0; ii < rhs_list_size; ii++)
751 if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
752 {
753 tree array_node = (*rhs_list)[ii];
754 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
755 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
756 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
757 }
758
759 cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
760
761 lhs_an_loop_info.safe_grow_cleared (lhs_rank);
762 if (rhs_rank)
763 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
764
765 cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
766 &lhs_an_info);
767 if (rhs_rank)
768 {
769 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
770 cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
771 &rhs_an_info);
772 }
773 if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
774 || (rhs_rank
775 && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info)))
776 {
777 pop_stmt_list (an_init);
778 return error_mark_node;
779 }
780 if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
781 && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST
782 && rhs_an_info[0][0].length
783 && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST)
784 {
785 HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length);
786 HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length);
787 /* Length can be negative or positive. As long as the magnitude is OK,
788 then the array notation is valid. */
789 if (absu_hwi (l_length) != absu_hwi (r_length))
790 {
791 error_at (location, "length mismatch between LHS and RHS");
792 pop_stmt_list (an_init);
793 return error_mark_node;
794 }
795 }
796 for (ii = 0; ii < lhs_rank; ii++)
797 if (lhs_an_info[0][ii].is_vector)
798 {
799 lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
800 lhs_an_loop_info[ii].ind_init = build_modify_expr
801 (location, lhs_an_loop_info[ii].var,
802 TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR,
803 location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)),
804 TREE_TYPE (lhs_an_loop_info[ii].var));
805 }
806 for (ii = 0; ii < rhs_rank; ii++)
807 {
808 /* When we have a polynomial, we assume that the indices are of type
809 integer. */
810 rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
811 rhs_an_loop_info[ii].ind_init = build_modify_expr
812 (location, rhs_an_loop_info[ii].var,
813 TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR,
814 location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0),
815 TREE_TYPE (rhs_an_loop_info[ii].var));
816 }
817 if (lhs_rank)
818 {
819 lhs_array_operand = create_array_refs
820 (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank);
821 replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
822 array_expr_lhs = lhs;
823 }
824 if (rhs_array_operand)
825 vec_safe_truncate (rhs_array_operand, 0);
826 if (rhs_rank)
827 {
828 rhs_array_operand = create_array_refs
829 (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank);
830 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
831 vec_safe_truncate (rhs_array_operand, 0);
832 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
833 rhs_an_loop_info, rhs_rank,
834 rhs);
835 if (!rhs_array_operand)
836 return error_mark_node;
837 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
838 }
839 else if (rhs_list_size > 0)
840 {
841 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
842 lhs_an_loop_info, lhs_rank,
843 lhs);
844 if (!rhs_array_operand)
845 return error_mark_node;
846 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
847 }
848 array_expr_lhs = lhs;
849 array_expr_rhs = rhs;
850 array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype,
851 modifycode, rhs_loc, array_expr_rhs,
852 rhs_origtype);
853 create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info);
854 if (rhs_rank)
855 create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info);
856
857 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
858 if (ii < lhs_rank && ii < rhs_rank)
859 cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node,
860 lhs_an_loop_info[ii].cmp,
861 rhs_an_loop_info[ii].cmp);
862 else if (ii < lhs_rank && ii >= rhs_rank)
863 cond_expr[ii] = lhs_an_loop_info[ii].cmp;
864 else
865 gcc_unreachable ();
866
867 an_init = pop_stmt_list (an_init);
868 append_to_statement_list_force (an_init, &loop_with_init);
869 body = array_expr;
870 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
871 {
872 tree incr_list = alloc_stmt_list ();
873 tree new_loop = push_stmt_list ();
874 if (lhs_rank)
875 add_stmt (lhs_an_loop_info[ii].ind_init);
876 if (rhs_rank)
877 add_stmt (rhs_an_loop_info[ii].ind_init);
878 if (lhs_rank)
879 append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list);
880 if (rhs_rank && rhs_an_loop_info[ii].incr)
881 append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list);
882 c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE,
883 NULL_TREE, true);
884 body = pop_stmt_list (new_loop);
885 }
886 append_to_statement_list_force (body, &loop_with_init);
887
888 lhs_an_info.release ();
889 lhs_an_loop_info.release ();
890 if (rhs_rank)
891 {
892 rhs_an_info.release ();
893 rhs_an_loop_info.release ();
894 }
895 cond_expr.release ();
896 return loop_with_init;
897 }
898
899 /* Helper function for fix_conditional_array_notations. Encloses the
900 conditional statement passed in STMT with a loop around it
901 and replaces the condition in STMT with a ARRAY_REF tree-node to the array.
902 The condition must have an ARRAY_NOTATION_REF tree. An expansion of array
903 notation in STMT is returned in a STATEMENT_LIST. */
904
905 static tree
906 fix_conditional_array_notations_1 (tree stmt)
907 {
908 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
909 size_t list_size = 0;
910 tree cond = NULL_TREE, builtin_loop = NULL_TREE, new_var = NULL_TREE;
911 size_t rank = 0, ii = 0;
912 tree loop_init;
913 location_t location = EXPR_LOCATION (stmt);
914 tree body = NULL_TREE, loop_with_init = alloc_stmt_list ();
915 vec<vec<an_parts> > an_info = vNULL;
916 vec<an_loop_parts> an_loop_info = vNULL;
917
918 if (TREE_CODE (stmt) == COND_EXPR)
919 cond = COND_EXPR_COND (stmt);
920 else if (TREE_CODE (stmt) == SWITCH_EXPR)
921 cond = SWITCH_COND (stmt);
922 else if (truth_value_p (TREE_CODE (stmt)))
923 cond = TREE_OPERAND (stmt, 0);
924 else
925 /* Otherwise dont even touch the statement. */
926 return stmt;
927
928 if (!find_rank (location, cond, cond, false, &rank))
929 return error_mark_node;
930
931 extract_array_notation_exprs (stmt, false, &array_list);
932 loop_init = push_stmt_list ();
933 for (ii = 0; ii < vec_safe_length (array_list); ii++)
934 {
935 tree array_node = (*array_list)[ii];
936 if (TREE_CODE (array_node) == CALL_EXPR)
937 {
938 builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var);
939 if (builtin_loop == error_mark_node)
940 {
941 add_stmt (error_mark_node);
942 pop_stmt_list (loop_init);
943 return loop_init;
944 }
945 else if (builtin_loop)
946 {
947 vec <tree, va_gc>* sub_list = NULL, *new_var_list = NULL;
948 vec_safe_push (sub_list, array_node);
949 vec_safe_push (new_var_list, new_var);
950 add_stmt (builtin_loop);
951 replace_array_notations (&stmt, false, sub_list, new_var_list);
952 }
953 }
954 }
955 if (!find_rank (location, stmt, stmt, true, &rank))
956 {
957 pop_stmt_list (loop_init);
958 return error_mark_node;
959 }
960 if (rank == 0)
961 {
962 add_stmt (stmt);
963 pop_stmt_list (loop_init);
964 return loop_init;
965 }
966 extract_array_notation_exprs (stmt, true, &array_list);
967
968 if (vec_safe_length (array_list) == 0)
969 return stmt;
970
971 list_size = vec_safe_length (array_list);
972 an_loop_info.safe_grow_cleared (rank);
973
974 for (ii = 0; ii < list_size; ii++)
975 if ((*array_list)[ii]
976 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
977 {
978 tree array_node = (*array_list)[ii];
979 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
980 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
981 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
982 }
983 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
984 for (ii = 0; ii < rank; ii++)
985 {
986 an_loop_info[ii].var = create_tmp_var (integer_type_node);
987 an_loop_info[ii].ind_init =
988 build_modify_expr (location, an_loop_info[ii].var,
989 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
990 location,
991 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
992 TREE_TYPE (an_loop_info[ii].var));
993 }
994 array_operand = create_array_refs (location, an_info, an_loop_info,
995 list_size, rank);
996 replace_array_notations (&stmt, true, array_list, array_operand);
997 create_cmp_incr (location, &an_loop_info, rank, an_info);
998
999 loop_init = pop_stmt_list (loop_init);
1000 body = stmt;
1001 append_to_statement_list_force (loop_init, &loop_with_init);
1002
1003 for (ii = 0; ii < rank; ii++)
1004 {
1005 tree new_loop = push_stmt_list ();
1006 add_stmt (an_loop_info[ii].ind_init);
1007 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1008 body, NULL_TREE, NULL_TREE, true);
1009 body = pop_stmt_list (new_loop);
1010 }
1011 append_to_statement_list_force (body, &loop_with_init);
1012
1013 an_loop_info.release ();
1014 an_info.release ();
1015
1016 return loop_with_init;
1017 }
1018
1019 /* Top-level function to replace ARRAY_NOTATION_REF in a conditional statement
1020 in STMT. An expansion of array notation in STMT is returned as a
1021 STATEMENT_LIST. */
1022
1023 tree
1024 fix_conditional_array_notations (tree stmt)
1025 {
1026 if (TREE_CODE (stmt) == STATEMENT_LIST)
1027 {
1028 tree_stmt_iterator tsi;
1029 for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi))
1030 {
1031 tree single_stmt = *tsi_stmt_ptr (tsi);
1032 *tsi_stmt_ptr (tsi) =
1033 fix_conditional_array_notations_1 (single_stmt);
1034 }
1035 return stmt;
1036 }
1037 else
1038 return fix_conditional_array_notations_1 (stmt);
1039 }
1040
1041 /* Create a struct c_expr that contains a loop with ARRAY_REF expr at location
1042 LOCATION with the tree_code CODE and the array notation expr is
1043 passed in ARG. Returns the fixed c_expr in ARG itself. */
1044
1045 struct c_expr
1046 fix_array_notation_expr (location_t location, enum tree_code code,
1047 struct c_expr arg)
1048 {
1049
1050 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1051 size_t list_size = 0, rank = 0, ii = 0;
1052 tree loop_init;
1053 tree body, loop_with_init = alloc_stmt_list ();
1054 vec<vec<an_parts> > an_info = vNULL;
1055 vec<an_loop_parts> an_loop_info = vNULL;
1056
1057 if (!find_rank (location, arg.value, arg.value, false, &rank))
1058 {
1059 /* If this function returns a NULL, we convert the tree value in the
1060 structure to error_mark_node and the parser should take care of the
1061 rest. */
1062 arg.value = error_mark_node;
1063 return arg;
1064 }
1065
1066 if (rank == 0)
1067 return arg;
1068
1069 extract_array_notation_exprs (arg.value, true, &array_list);
1070
1071 if (vec_safe_length (array_list) == 0)
1072 return arg;
1073
1074 list_size = vec_safe_length (array_list);
1075
1076 an_loop_info.safe_grow_cleared (rank);
1077 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1078
1079 loop_init = push_stmt_list ();
1080 for (ii = 0; ii < rank; ii++)
1081 {
1082 an_loop_info[ii].var = create_tmp_var (integer_type_node);
1083 an_loop_info[ii].ind_init =
1084 build_modify_expr (location, an_loop_info[ii].var,
1085 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
1086 location,
1087 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1088 TREE_TYPE (an_loop_info[ii].var));;
1089
1090 }
1091 array_operand = create_array_refs (location, an_info, an_loop_info,
1092 list_size, rank);
1093 replace_array_notations (&arg.value, true, array_list, array_operand);
1094 create_cmp_incr (location, &an_loop_info, rank, an_info);
1095
1096 arg = default_function_array_read_conversion (location, arg);
1097 if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
1098 arg.value = build_unary_op (location, code, arg.value, 0);
1099 else if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
1100 arg = parser_build_unary_op (location, code, arg);
1101
1102 loop_init = pop_stmt_list (loop_init);
1103 append_to_statement_list_force (loop_init, &loop_with_init);
1104 body = arg.value;
1105
1106 for (ii = 0; ii < rank; ii++)
1107 {
1108 tree new_loop = push_stmt_list ();
1109 add_stmt (an_loop_info[ii].ind_init);
1110 c_finish_loop (location, an_loop_info[ii].cmp,
1111 an_loop_info[ii].incr, body, NULL_TREE,
1112 NULL_TREE, true);
1113 body = pop_stmt_list (new_loop);
1114 }
1115 append_to_statement_list_force (body, &loop_with_init);
1116 arg.value = loop_with_init;
1117 an_info.release ();
1118 an_loop_info.release ();
1119 return arg;
1120 }
1121
1122 /* Replaces array notations in a void function call arguments in ARG and returns
1123 a STATEMENT_LIST. */
1124
1125 static tree
1126 fix_array_notation_call_expr (tree arg)
1127 {
1128 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1129 tree new_var = NULL_TREE;
1130 size_t list_size = 0, rank = 0, ii = 0;
1131 tree loop_init;
1132 tree body, loop_with_init = alloc_stmt_list ();
1133 location_t location = UNKNOWN_LOCATION;
1134 vec<vec<an_parts> > an_info = vNULL;
1135 vec<an_loop_parts> an_loop_info = vNULL;
1136
1137 if (TREE_CODE (arg) == CALL_EXPR
1138 && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg)))
1139 {
1140 loop_init = fix_builtin_array_notation_fn (arg, &new_var);
1141 /* We are ignoring the new var because either the user does not want to
1142 capture it OR he is using sec_reduce_mutating function. */
1143 return loop_init;
1144 }
1145 if (!find_rank (location, arg, arg, false, &rank))
1146 return error_mark_node;
1147
1148 if (rank == 0)
1149 return arg;
1150
1151 extract_array_notation_exprs (arg, true, &array_list);
1152 if (vec_safe_length (array_list) == 0)
1153 return arg;
1154
1155 list_size = vec_safe_length (array_list);
1156 location = EXPR_LOCATION (arg);
1157 an_loop_info.safe_grow_cleared (rank);
1158
1159 loop_init = push_stmt_list ();
1160 for (ii = 0; ii < list_size; ii++)
1161 if ((*array_list)[ii]
1162 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
1163 {
1164 tree array_node = (*array_list)[ii];
1165 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
1166 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
1167 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
1168 }
1169 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1170 if (length_mismatch_in_expr_p (location, an_info))
1171 {
1172 pop_stmt_list (loop_init);
1173 return error_mark_node;
1174 }
1175 for (ii = 0; ii < rank; ii++)
1176 {
1177 an_loop_info[ii].var = create_tmp_var (integer_type_node);
1178 an_loop_info[ii].ind_init =
1179 build_modify_expr (location, an_loop_info[ii].var,
1180 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location,
1181 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1182 TREE_TYPE (an_loop_info[ii].var));
1183
1184 }
1185 array_operand = create_array_refs (location, an_info, an_loop_info,
1186 list_size, rank);
1187 replace_array_notations (&arg, true, array_list, array_operand);
1188 create_cmp_incr (location, &an_loop_info, rank, an_info);
1189 loop_init = pop_stmt_list (loop_init);
1190 append_to_statement_list_force (loop_init, &loop_with_init);
1191 body = arg;
1192 for (ii = 0; ii < rank; ii++)
1193 {
1194 tree new_loop = push_stmt_list ();
1195 add_stmt (an_loop_info[ii].ind_init);
1196 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1197 body, NULL_TREE, NULL_TREE, true);
1198 body = pop_stmt_list (new_loop);
1199 }
1200 append_to_statement_list_force (body, &loop_with_init);
1201 an_loop_info.release ();
1202 an_info.release ();
1203 return loop_with_init;
1204 }
1205
1206 /* Expands the built-in functions in a return. EXPR is a RETURN_EXPR with
1207 a built-in reduction function. This function returns the expansion code for
1208 the built-in function. */
1209
1210 static tree
1211 fix_return_expr (tree expr)
1212 {
1213 tree new_mod_list, new_var, new_mod, retval_expr, retval_type;
1214 location_t loc = EXPR_LOCATION (expr);
1215
1216 new_mod_list = alloc_stmt_list ();
1217 retval_expr = TREE_OPERAND (expr, 0);
1218 retval_type = TREE_TYPE (TREE_OPERAND (retval_expr, 1));
1219 new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr));
1220 new_mod = build_array_notation_expr (loc, new_var, TREE_TYPE (new_var),
1221 NOP_EXPR, loc,
1222 TREE_OPERAND (retval_expr, 1),
1223 retval_type);
1224 TREE_OPERAND (retval_expr, 1) = new_var;
1225 TREE_OPERAND (expr, 0) = retval_expr;
1226 append_to_statement_list_force (new_mod, &new_mod_list);
1227 append_to_statement_list_force (expr, &new_mod_list);
1228 return new_mod_list;
1229 }
1230
1231 /* Callback for walk_tree. Expands all array notations in *TP. *WALK_SUBTREES
1232 is set to 1 unless *TP contains no array notation expressions. */
1233
1234 static tree
1235 expand_array_notations (tree *tp, int *walk_subtrees, void *)
1236 {
1237 if (!contains_array_notation_expr (*tp))
1238 {
1239 *walk_subtrees = 0;
1240 return NULL_TREE;
1241 }
1242 *walk_subtrees = 1;
1243
1244 switch (TREE_CODE (*tp))
1245 {
1246 case TRUTH_ORIF_EXPR:
1247 case TRUTH_ANDIF_EXPR:
1248 case TRUTH_OR_EXPR:
1249 case TRUTH_AND_EXPR:
1250 case TRUTH_XOR_EXPR:
1251 case TRUTH_NOT_EXPR:
1252 case COND_EXPR:
1253 *tp = fix_conditional_array_notations (*tp);
1254 break;
1255 case MODIFY_EXPR:
1256 {
1257 location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) :
1258 UNKNOWN_LOCATION;
1259 tree lhs = TREE_OPERAND (*tp, 0);
1260 tree rhs = TREE_OPERAND (*tp, 1);
1261 location_t rhs_loc = EXPR_HAS_LOCATION (rhs) ? EXPR_LOCATION (rhs) :
1262 UNKNOWN_LOCATION;
1263 *tp = build_array_notation_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR,
1264 rhs_loc, rhs, TREE_TYPE (rhs));
1265 }
1266 break;
1267 case DECL_EXPR:
1268 {
1269 tree x = DECL_EXPR_DECL (*tp);
1270 if (DECL_INITIAL (x))
1271 {
1272 location_t loc = DECL_SOURCE_LOCATION (x);
1273 tree lhs = x;
1274 tree rhs = DECL_INITIAL (x);
1275 DECL_INITIAL (x) = NULL;
1276 tree new_modify_expr = build_modify_expr (loc, lhs,
1277 TREE_TYPE (lhs),
1278 NOP_EXPR,
1279 loc, rhs,
1280 TREE_TYPE(rhs));
1281 expand_array_notations (&new_modify_expr, walk_subtrees, NULL);
1282 *tp = new_modify_expr;
1283 }
1284 }
1285 break;
1286 case CALL_EXPR:
1287 *tp = fix_array_notation_call_expr (*tp);
1288 break;
1289 case RETURN_EXPR:
1290 *tp = fix_return_expr (*tp);
1291 break;
1292 case COMPOUND_EXPR:
1293 if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR)
1294 {
1295 /* In here we are calling expand_array_notations because
1296 we need to be able to catch the return value and check if
1297 it is an error_mark_node. */
1298 expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL);
1299
1300 /* SAVE_EXPR cannot have an error_mark_node inside it. This check
1301 will make sure that if there is an error in expanding of
1302 array notations (e.g. rank mismatch) then replace the entire
1303 SAVE_EXPR with an error_mark_node. */
1304 if (TREE_OPERAND (*tp, 1) == error_mark_node)
1305 *tp = error_mark_node;
1306 }
1307 break;
1308 case ARRAY_NOTATION_REF:
1309 /* If we are here, then we are dealing with cases like this:
1310 A[:];
1311 A[x:y:z];
1312 A[x:y];
1313 Replace those with just void zero node. */
1314 *tp = void_node;
1315 default:
1316 break;
1317 }
1318 return NULL_TREE;
1319 }
1320
1321 /* Walks through tree node T and expands all array notations in its subtrees.
1322 The return value is the same type as T but with all array notations
1323 replaced with appropriate ARRAY_REFS with a loop around it. */
1324
1325 tree
1326 expand_array_notation_exprs (tree t)
1327 {
1328 walk_tree (&t, expand_array_notations, NULL, NULL);
1329 return t;
1330 }
1331
1332 /* This handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which
1333 denotes an array notation expression. If a is a variable or a member, then
1334 we generate a ARRAY_NOTATION_REF front-end tree and return it.
1335 This tree is broken down to ARRAY_REF toward the end of parsing.
1336 ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE
1337 of ARRAY_REF. Restrictions on START_INDEX, LENGTH and STRIDE is same as that
1338 of the index field passed into ARRAY_REF. The only additional restriction
1339 is that, unlike index in ARRAY_REF, stride, length and start_index cannot
1340 contain ARRAY_NOTATIONS. */
1341
1342 tree
1343 build_array_notation_ref (location_t loc, tree array, tree start_index,
1344 tree length, tree stride, tree type)
1345 {
1346 tree array_ntn_tree = NULL_TREE;
1347 size_t stride_rank = 0, length_rank = 0, start_rank = 0;
1348
1349 if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
1350 {
1351 error_at (loc,
1352 "start-index of array notation triplet is not an integer");
1353 return error_mark_node;
1354 }
1355 if (!INTEGRAL_TYPE_P (TREE_TYPE (length)))
1356 {
1357 error_at (loc, "length of array notation triplet is not an integer");
1358 return error_mark_node;
1359 }
1360
1361 /* The stride is an optional field. */
1362 if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
1363 {
1364 error_at (loc, "stride of array notation triplet is not an integer");
1365 return error_mark_node;
1366 }
1367 if (!stride)
1368 {
1369 if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length)
1370 && tree_int_cst_lt (length, start_index))
1371 stride = build_int_cst (TREE_TYPE (start_index), -1);
1372 else
1373 stride = build_int_cst (TREE_TYPE (start_index), 1);
1374 }
1375
1376 if (!find_rank (loc, start_index, start_index, false, &start_rank))
1377 return error_mark_node;
1378 if (!find_rank (loc, length, length, false, &length_rank))
1379 return error_mark_node;
1380 if (!find_rank (loc, stride, stride, false, &stride_rank))
1381 return error_mark_node;
1382
1383 if (start_rank != 0)
1384 {
1385 error_at (loc, "rank of an array notation triplet's start-index is not "
1386 "zero");
1387 return error_mark_node;
1388 }
1389 if (length_rank != 0)
1390 {
1391 error_at (loc, "rank of an array notation triplet's length is not zero");
1392 return error_mark_node;
1393 }
1394 if (stride_rank != 0)
1395 {
1396 error_at (loc, "rank of array notation triplet's stride is not zero");
1397 return error_mark_node;
1398 }
1399 array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE,
1400 NULL_TREE, NULL_TREE);
1401 ARRAY_NOTATION_ARRAY (array_ntn_tree) = array;
1402 ARRAY_NOTATION_START (array_ntn_tree) = start_index;
1403 ARRAY_NOTATION_LENGTH (array_ntn_tree) = length;
1404 ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride;
1405 TREE_TYPE (array_ntn_tree) = type;
1406
1407 return array_ntn_tree;
1408 }