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