* cfgloopmanip.c (duplicate_loop_to_header_edge): Cleanup profile
[official-gcc.git] / gcc / c / c-array-notation.c
blob40f1cfdabb82b7fddf62247ffc07ad8f949fd700
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 access (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,
359 new_yes_expr, TREE_TYPE (new_yes_expr), location,
360 new_no_expr, TREE_TYPE (new_no_expr), location);
361 break;
362 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
363 new_var_init = build_modify_expr
364 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
365 location, build_one_cst (new_var_type), new_var_type);
366 /* Initially you assume everything is non-zero, now if we find a case
367 where it is NOT true, then we set the result to false. Otherwise
368 we just keep the previous value. */
369 new_yes_expr = build_modify_expr
370 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
371 location, build_zero_cst (TREE_TYPE (*new_var)),
372 TREE_TYPE (*new_var));
373 new_no_expr = build_modify_expr
374 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
375 location, *new_var, TREE_TYPE (*new_var));
376 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
377 build_zero_cst (TREE_TYPE (func_parm)));
378 new_expr = build_conditional_expr
379 (location, new_cond_expr, false,
380 new_yes_expr, TREE_TYPE (new_yes_expr), location,
381 new_no_expr, TREE_TYPE (new_no_expr), location);
382 break;
383 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
384 new_var_init = build_modify_expr
385 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
386 location, build_zero_cst (new_var_type), new_var_type);
387 /* Initially we assume there are NO zeros in the list. When we find
388 a non-zero, we keep the previous value. If we find a zero, we
389 set the value to true. */
390 new_yes_expr = build_modify_expr
391 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
392 location, build_one_cst (new_var_type), new_var_type);
393 new_no_expr = build_modify_expr
394 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
395 location, *new_var, TREE_TYPE (*new_var));
396 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
397 build_zero_cst (TREE_TYPE (func_parm)));
398 new_expr = build_conditional_expr
399 (location, new_cond_expr, false,
400 new_yes_expr, TREE_TYPE (new_yes_expr), location,
401 new_no_expr, TREE_TYPE (new_no_expr), location);
402 break;
403 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
404 new_var_init = build_modify_expr
405 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
406 location, build_zero_cst (new_var_type), new_var_type);
407 /* Initially we assume there are NO non-zeros in the list. When we find
408 a zero, we keep the previous value. If we find a non-zero, we set
409 the value to true. */
410 new_yes_expr = build_modify_expr
411 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
412 location, build_one_cst (new_var_type), new_var_type);
413 new_no_expr = build_modify_expr
414 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
415 location, *new_var, TREE_TYPE (*new_var));
416 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
417 build_zero_cst (TREE_TYPE (func_parm)));
418 new_expr = build_conditional_expr
419 (location, new_cond_expr, false,
420 new_yes_expr, TREE_TYPE (new_yes_expr), location,
421 new_no_expr, TREE_TYPE (new_no_expr), location);
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), location,
442 new_no_expr, TREE_TYPE (*new_var), location);
443 break;
444 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
445 if (TYPE_MAX_VALUE (new_var_type))
446 new_var_init = build_modify_expr
447 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
448 location, TYPE_MAX_VALUE (new_var_type), new_var_type);
449 else
450 new_var_init = build_modify_expr
451 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
452 location, func_parm, new_var_type);
453 new_no_expr = build_modify_expr
454 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
455 location, *new_var, TREE_TYPE (*new_var));
456 new_yes_expr = build_modify_expr
457 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
458 location, func_parm, TREE_TYPE (*new_var));
459 new_expr = build_conditional_expr
460 (location,
461 build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
462 new_yes_expr, TREE_TYPE (*new_var), location,
463 new_no_expr, TREE_TYPE (*new_var), location);
464 break;
465 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
466 new_var_init = build_modify_expr
467 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
468 location, build_zero_cst (new_var_type), new_var_type);
469 new_exp_init = build_modify_expr
470 (location, array_ind_value, TREE_TYPE (array_ind_value),
471 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
472 new_no_ind = build_modify_expr
473 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
474 location, *new_var, TREE_TYPE (*new_var));
475 new_no_expr = build_modify_expr
476 (location, array_ind_value, TREE_TYPE (array_ind_value),
477 NOP_EXPR,
478 location, array_ind_value, TREE_TYPE (array_ind_value));
479 if (list_size > 1)
481 new_yes_ind = build_modify_expr
482 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
483 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
484 new_yes_expr = build_modify_expr
485 (location, array_ind_value, TREE_TYPE (array_ind_value),
486 NOP_EXPR,
487 location, func_parm, TREE_TYPE ((*array_operand)[0]));
489 else
491 new_yes_ind = build_modify_expr
492 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
493 location, TREE_OPERAND (array_op0, 1),
494 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
495 new_yes_expr = build_modify_expr
496 (location, array_ind_value, TREE_TYPE (array_ind_value),
497 NOP_EXPR,
498 location, func_parm, TREE_TYPE (TREE_OPERAND (array_op0, 1)));
500 new_yes_list = alloc_stmt_list ();
501 append_to_statement_list (new_yes_ind, &new_yes_list);
502 append_to_statement_list (new_yes_expr, &new_yes_list);
504 new_no_list = alloc_stmt_list ();
505 append_to_statement_list (new_no_ind, &new_no_list);
506 append_to_statement_list (new_no_expr, &new_no_list);
508 new_expr = build_conditional_expr
509 (location,
510 build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
511 func_parm),
512 false,
513 new_yes_list, TREE_TYPE (*new_var), location,
514 new_no_list, TREE_TYPE (*new_var), location);
515 break;
516 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
517 new_var_init = build_modify_expr
518 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
519 location, build_zero_cst (new_var_type), new_var_type);
520 new_exp_init = build_modify_expr
521 (location, array_ind_value, TREE_TYPE (array_ind_value),
522 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
523 new_no_ind = build_modify_expr
524 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
525 location, *new_var, TREE_TYPE (*new_var));
526 new_no_expr = build_modify_expr
527 (location, array_ind_value, TREE_TYPE (array_ind_value),
528 NOP_EXPR,
529 location, array_ind_value, TREE_TYPE (array_ind_value));
530 if (list_size > 1)
532 new_yes_ind = build_modify_expr
533 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
534 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
535 new_yes_expr = build_modify_expr
536 (location, array_ind_value, TREE_TYPE (array_ind_value),
537 NOP_EXPR,
538 location, func_parm, TREE_TYPE (array_op0));
540 else
542 new_yes_ind = build_modify_expr
543 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
544 location, TREE_OPERAND (array_op0, 1),
545 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
546 new_yes_expr = build_modify_expr
547 (location, array_ind_value, TREE_TYPE (array_ind_value),
548 NOP_EXPR,
549 location, func_parm, TREE_TYPE (TREE_OPERAND (array_op0, 1)));
551 new_yes_list = alloc_stmt_list ();
552 append_to_statement_list (new_yes_ind, &new_yes_list);
553 append_to_statement_list (new_yes_expr, &new_yes_list);
555 new_no_list = alloc_stmt_list ();
556 append_to_statement_list (new_no_ind, &new_no_list);
557 append_to_statement_list (new_no_expr, &new_no_list);
559 new_expr = build_conditional_expr
560 (location,
561 build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
562 func_parm),
563 false,
564 new_yes_list, TREE_TYPE (*new_var), location,
565 new_no_list, TREE_TYPE (*new_var), location);
566 break;
567 case BUILT_IN_CILKPLUS_SEC_REDUCE:
568 new_var_init = build_modify_expr
569 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
570 location, identity_value, new_var_type);
571 new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm);
572 new_expr = build_modify_expr
573 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
574 location, new_call_expr, TREE_TYPE (*new_var));
575 break;
576 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
577 new_expr = build_call_expr (call_fn, 2, identity_value, func_parm);
578 break;
579 default:
580 gcc_unreachable ();
581 break;
584 for (ii = 0; ii < rank; ii++)
585 append_to_statement_list (an_loop_info[ii].ind_init, &loop_init);
587 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
588 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
589 append_to_statement_list (new_exp_init, &loop_init);
590 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
591 append_to_statement_list (new_var_init, &loop_init);
593 append_to_statement_list_force (loop_init, &loop_with_init);
594 body = new_expr;
595 for (ii = 0; ii < rank; ii++)
597 tree new_loop = push_stmt_list ();
598 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
599 body, NULL_TREE, NULL_TREE, true);
600 body = pop_stmt_list (new_loop);
602 append_to_statement_list_force (body, &loop_with_init);
604 release_vec_vec (an_info);
606 return loop_with_init;
609 /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
610 The LHS and/or RHS will be array notation expressions that have a MODIFYCODE
611 Their locations are specified by LHS_LOC, RHS_LOC. The location of the
612 modify expression is location. The original type of LHS and RHS are passed
613 in LHS_ORIGTYPE and RHS_ORIGTYPE. */
615 tree
616 build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
617 enum tree_code modifycode, location_t rhs_loc,
618 tree rhs, tree rhs_origtype)
620 bool found_builtin_fn = false;
621 tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
622 tree array_expr = NULL_TREE;
623 tree an_init = NULL_TREE;
624 auto_vec<tree> cond_expr;
625 tree body, loop_with_init = alloc_stmt_list();
626 tree scalar_mods = NULL_TREE;
627 vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL;
628 size_t lhs_rank = 0, rhs_rank = 0;
629 size_t ii = 0;
630 vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL;
631 tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE;
632 size_t rhs_list_size = 0, lhs_list_size = 0;
633 vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
634 auto_vec<an_loop_parts> lhs_an_loop_info, rhs_an_loop_info;
636 /* If either of this is true, an error message must have been send out
637 already. Not necessary to send out multiple error messages. */
638 if (lhs == error_mark_node || rhs == error_mark_node)
639 return error_mark_node;
641 if (!find_rank (location, rhs, rhs, false, &rhs_rank))
642 return error_mark_node;
644 extract_array_notation_exprs (rhs, false, &rhs_list);
645 rhs_list_size = vec_safe_length (rhs_list);
646 an_init = push_stmt_list ();
647 if (rhs_rank)
649 scalar_mods = replace_invariant_exprs (&rhs);
650 if (scalar_mods)
651 add_stmt (scalar_mods);
653 for (ii = 0; ii < rhs_list_size; ii++)
655 tree rhs_node = (*rhs_list)[ii];
656 if (TREE_CODE (rhs_node) == CALL_EXPR)
658 builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
659 if (builtin_loop == error_mark_node)
661 pop_stmt_list (an_init);
662 return error_mark_node;
664 else if (builtin_loop)
666 add_stmt (builtin_loop);
667 found_builtin_fn = true;
668 if (new_var)
670 vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
671 vec_safe_push (rhs_sub_list, rhs_node);
672 vec_safe_push (new_var_list, new_var);
673 replace_array_notations (&rhs, false, rhs_sub_list,
674 new_var_list);
680 lhs_rank = 0;
681 rhs_rank = 0;
682 if (!find_rank (location, lhs, lhs, true, &lhs_rank))
684 pop_stmt_list (an_init);
685 return error_mark_node;
688 if (!find_rank (location, rhs, rhs, true, &rhs_rank))
690 pop_stmt_list (an_init);
691 return error_mark_node;
694 if (lhs_rank == 0 && rhs_rank == 0)
696 if (found_builtin_fn)
698 new_modify_expr = build_modify_expr (location, lhs, lhs_origtype,
699 modifycode, rhs_loc, rhs,
700 rhs_origtype);
701 add_stmt (new_modify_expr);
702 pop_stmt_list (an_init);
703 return an_init;
705 else
707 pop_stmt_list (an_init);
708 return NULL_TREE;
711 rhs_list_size = 0;
712 rhs_list = NULL;
713 extract_array_notation_exprs (rhs, true, &rhs_list);
714 extract_array_notation_exprs (lhs, true, &lhs_list);
715 rhs_list_size = vec_safe_length (rhs_list);
716 lhs_list_size = vec_safe_length (lhs_list);
718 if (lhs_rank == 0 && rhs_rank != 0)
720 tree rhs_base = rhs;
721 if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
723 for (ii = 0; ii < (size_t) rhs_rank; ii++)
724 rhs_base = ARRAY_NOTATION_ARRAY (rhs);
726 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
727 rhs_base);
728 return error_mark_node;
730 else
732 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
733 rhs_base);
734 return error_mark_node;
737 if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
739 error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
740 pop_stmt_list (an_init);
741 return error_mark_node;
744 /* Here we assign the array notation components to variable so that we can
745 satisfy the exec once rule. */
746 for (ii = 0; ii < lhs_list_size; ii++)
748 tree array_node = (*lhs_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));
753 for (ii = 0; ii < rhs_list_size; ii++)
754 if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
756 tree array_node = (*rhs_list)[ii];
757 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
758 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
759 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
762 cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
764 lhs_an_loop_info.safe_grow_cleared (lhs_rank);
765 if (rhs_rank)
766 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
768 cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
769 &lhs_an_info);
770 if (rhs_rank)
772 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
773 cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
774 &rhs_an_info);
776 if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
777 || (rhs_rank
778 && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info)))
780 pop_stmt_list (an_init);
781 goto error;
783 if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
784 && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST
785 && rhs_an_info[0][0].length
786 && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST)
788 HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length);
789 HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length);
790 /* Length can be negative or positive. As long as the magnitude is OK,
791 then the array notation is valid. */
792 if (absu_hwi (l_length) != absu_hwi (r_length))
794 error_at (location, "length mismatch between LHS and RHS");
795 pop_stmt_list (an_init);
796 goto error;
799 for (ii = 0; ii < lhs_rank; ii++)
800 if (lhs_an_info[0][ii].is_vector)
802 lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
803 lhs_an_loop_info[ii].ind_init = build_modify_expr
804 (location, lhs_an_loop_info[ii].var,
805 TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR,
806 location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)),
807 TREE_TYPE (lhs_an_loop_info[ii].var));
809 for (ii = 0; ii < rhs_rank; ii++)
811 /* When we have a polynomial, we assume that the indices are of type
812 integer. */
813 rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
814 rhs_an_loop_info[ii].ind_init = build_modify_expr
815 (location, rhs_an_loop_info[ii].var,
816 TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR,
817 location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0),
818 TREE_TYPE (rhs_an_loop_info[ii].var));
820 if (lhs_rank)
822 lhs_array_operand = create_array_refs
823 (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank);
824 replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
825 array_expr_lhs = lhs;
827 if (rhs_array_operand)
828 vec_safe_truncate (rhs_array_operand, 0);
829 if (rhs_rank)
831 rhs_array_operand = create_array_refs
832 (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank);
833 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
834 vec_safe_truncate (rhs_array_operand, 0);
835 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
836 rhs_an_loop_info, rhs_rank,
837 rhs);
838 if (!rhs_array_operand)
839 goto error;
840 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
842 else if (rhs_list_size > 0)
844 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
845 lhs_an_loop_info, lhs_rank,
846 lhs);
847 if (!rhs_array_operand)
848 goto error;
849 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
851 array_expr_lhs = lhs;
852 array_expr_rhs = rhs;
853 array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype,
854 modifycode, rhs_loc, array_expr_rhs,
855 rhs_origtype);
856 create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info);
857 if (rhs_rank)
858 create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info);
860 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
861 if (ii < lhs_rank && ii < rhs_rank)
862 cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node,
863 lhs_an_loop_info[ii].cmp,
864 rhs_an_loop_info[ii].cmp);
865 else if (ii < lhs_rank && ii >= rhs_rank)
866 cond_expr[ii] = lhs_an_loop_info[ii].cmp;
867 else
868 gcc_unreachable ();
870 an_init = pop_stmt_list (an_init);
871 append_to_statement_list_force (an_init, &loop_with_init);
872 body = array_expr;
873 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
875 tree incr_list = alloc_stmt_list ();
876 tree new_loop = push_stmt_list ();
877 if (lhs_rank)
878 add_stmt (lhs_an_loop_info[ii].ind_init);
879 if (rhs_rank)
880 add_stmt (rhs_an_loop_info[ii].ind_init);
881 if (lhs_rank)
882 append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list);
883 if (rhs_rank && rhs_an_loop_info[ii].incr)
884 append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list);
885 c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE,
886 NULL_TREE, true);
887 body = pop_stmt_list (new_loop);
889 append_to_statement_list_force (body, &loop_with_init);
891 release_vec_vec (lhs_an_info);
892 release_vec_vec (rhs_an_info);
893 return loop_with_init;
895 error:
896 release_vec_vec (lhs_an_info);
897 release_vec_vec (rhs_an_info);
899 return error_mark_node;
902 /* Helper function for fix_conditional_array_notations. Encloses the
903 conditional statement passed in STMT with a loop around it
904 and replaces the condition in STMT with a ARRAY_REF tree-node to the array.
905 The condition must have an ARRAY_NOTATION_REF tree. An expansion of array
906 notation in STMT is returned in a STATEMENT_LIST. */
908 static tree
909 fix_conditional_array_notations_1 (tree stmt)
911 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
912 size_t list_size = 0;
913 tree cond = NULL_TREE, builtin_loop = NULL_TREE, new_var = NULL_TREE;
914 size_t rank = 0, ii = 0;
915 tree loop_init;
916 location_t location = EXPR_LOCATION (stmt);
917 tree body = NULL_TREE, loop_with_init = alloc_stmt_list ();
918 vec<vec<an_parts> > an_info = vNULL;
919 auto_vec<an_loop_parts> an_loop_info;
921 if (TREE_CODE (stmt) == COND_EXPR)
922 cond = COND_EXPR_COND (stmt);
923 else if (TREE_CODE (stmt) == SWITCH_EXPR)
924 cond = SWITCH_COND (stmt);
925 else if (truth_value_p (TREE_CODE (stmt)))
926 cond = TREE_OPERAND (stmt, 0);
927 else
928 /* Otherwise dont even touch the statement. */
929 return stmt;
931 if (!find_rank (location, cond, cond, false, &rank))
932 return error_mark_node;
934 extract_array_notation_exprs (stmt, false, &array_list);
935 loop_init = push_stmt_list ();
936 for (ii = 0; ii < vec_safe_length (array_list); ii++)
938 tree array_node = (*array_list)[ii];
939 if (TREE_CODE (array_node) == CALL_EXPR)
941 builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var);
942 if (builtin_loop == error_mark_node)
944 add_stmt (error_mark_node);
945 pop_stmt_list (loop_init);
946 return loop_init;
948 else if (builtin_loop)
950 vec <tree, va_gc>* sub_list = NULL, *new_var_list = NULL;
951 vec_safe_push (sub_list, array_node);
952 vec_safe_push (new_var_list, new_var);
953 add_stmt (builtin_loop);
954 replace_array_notations (&stmt, false, sub_list, new_var_list);
958 if (!find_rank (location, stmt, stmt, true, &rank))
960 pop_stmt_list (loop_init);
961 return error_mark_node;
963 if (rank == 0)
965 add_stmt (stmt);
966 pop_stmt_list (loop_init);
967 return loop_init;
969 extract_array_notation_exprs (stmt, true, &array_list);
971 if (vec_safe_length (array_list) == 0)
972 return stmt;
974 list_size = vec_safe_length (array_list);
975 an_loop_info.safe_grow_cleared (rank);
977 for (ii = 0; ii < list_size; ii++)
978 if ((*array_list)[ii]
979 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
981 tree array_node = (*array_list)[ii];
982 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
983 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
984 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
986 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
987 for (ii = 0; ii < rank; ii++)
989 an_loop_info[ii].var = create_tmp_var (integer_type_node);
990 an_loop_info[ii].ind_init =
991 build_modify_expr (location, an_loop_info[ii].var,
992 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
993 location,
994 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
995 TREE_TYPE (an_loop_info[ii].var));
997 array_operand = create_array_refs (location, an_info, an_loop_info,
998 list_size, rank);
999 replace_array_notations (&stmt, true, array_list, array_operand);
1000 create_cmp_incr (location, &an_loop_info, rank, an_info);
1002 loop_init = pop_stmt_list (loop_init);
1003 body = stmt;
1004 append_to_statement_list_force (loop_init, &loop_with_init);
1006 for (ii = 0; ii < rank; ii++)
1008 tree new_loop = push_stmt_list ();
1009 add_stmt (an_loop_info[ii].ind_init);
1010 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1011 body, NULL_TREE, NULL_TREE, true);
1012 body = pop_stmt_list (new_loop);
1014 append_to_statement_list_force (body, &loop_with_init);
1015 release_vec_vec (an_info);
1017 return loop_with_init;
1020 /* Top-level function to replace ARRAY_NOTATION_REF in a conditional statement
1021 in STMT. An expansion of array notation in STMT is returned as a
1022 STATEMENT_LIST. */
1024 tree
1025 fix_conditional_array_notations (tree stmt)
1027 if (TREE_CODE (stmt) == STATEMENT_LIST)
1029 tree_stmt_iterator tsi;
1030 for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi))
1032 tree single_stmt = *tsi_stmt_ptr (tsi);
1033 *tsi_stmt_ptr (tsi) =
1034 fix_conditional_array_notations_1 (single_stmt);
1036 return stmt;
1038 else
1039 return fix_conditional_array_notations_1 (stmt);
1042 /* Create a struct c_expr that contains a loop with ARRAY_REF expr at location
1043 LOCATION with the tree_code CODE and the array notation expr is
1044 passed in ARG. Returns the fixed c_expr in ARG itself. */
1046 struct c_expr
1047 fix_array_notation_expr (location_t location, enum tree_code code,
1048 struct c_expr arg)
1051 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1052 size_t list_size = 0, rank = 0, ii = 0;
1053 tree loop_init;
1054 tree body, loop_with_init = alloc_stmt_list ();
1055 vec<vec<an_parts> > an_info = vNULL;
1056 auto_vec<an_loop_parts> an_loop_info;
1058 if (!find_rank (location, arg.value, arg.value, false, &rank))
1060 /* If this function returns a NULL, we convert the tree value in the
1061 structure to error_mark_node and the parser should take care of the
1062 rest. */
1063 arg.value = error_mark_node;
1064 return arg;
1067 if (rank == 0)
1068 return arg;
1070 extract_array_notation_exprs (arg.value, true, &array_list);
1072 if (vec_safe_length (array_list) == 0)
1073 return arg;
1075 list_size = vec_safe_length (array_list);
1077 an_loop_info.safe_grow_cleared (rank);
1078 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1080 loop_init = push_stmt_list ();
1081 for (ii = 0; ii < rank; ii++)
1083 an_loop_info[ii].var = create_tmp_var (integer_type_node);
1084 an_loop_info[ii].ind_init =
1085 build_modify_expr (location, an_loop_info[ii].var,
1086 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
1087 location,
1088 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1089 TREE_TYPE (an_loop_info[ii].var));;
1092 array_operand = create_array_refs (location, an_info, an_loop_info,
1093 list_size, rank);
1094 replace_array_notations (&arg.value, true, array_list, array_operand);
1095 create_cmp_incr (location, &an_loop_info, rank, an_info);
1097 arg = default_function_array_read_conversion (location, arg);
1098 if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
1099 arg.value = build_unary_op (location, code, arg.value, false);
1100 else if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
1101 arg = parser_build_unary_op (location, code, arg);
1103 loop_init = pop_stmt_list (loop_init);
1104 append_to_statement_list_force (loop_init, &loop_with_init);
1105 body = arg.value;
1107 for (ii = 0; ii < rank; ii++)
1109 tree new_loop = push_stmt_list ();
1110 add_stmt (an_loop_info[ii].ind_init);
1111 c_finish_loop (location, an_loop_info[ii].cmp,
1112 an_loop_info[ii].incr, body, NULL_TREE,
1113 NULL_TREE, true);
1114 body = pop_stmt_list (new_loop);
1116 append_to_statement_list_force (body, &loop_with_init);
1117 arg.value = loop_with_init;
1118 release_vec_vec (an_info);
1119 return arg;
1122 /* Replaces array notations in a void function call arguments in ARG and returns
1123 a STATEMENT_LIST. */
1125 static tree
1126 fix_array_notation_call_expr (tree arg)
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 auto_vec<an_loop_parts> an_loop_info;
1137 if (TREE_CODE (arg) == CALL_EXPR
1138 && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg)))
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;
1145 if (!find_rank (location, arg, arg, false, &rank))
1146 return error_mark_node;
1148 if (rank == 0)
1149 return arg;
1151 extract_array_notation_exprs (arg, true, &array_list);
1152 if (vec_safe_length (array_list) == 0)
1153 return arg;
1155 list_size = vec_safe_length (array_list);
1156 location = EXPR_LOCATION (arg);
1157 an_loop_info.safe_grow_cleared (rank);
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)
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));
1169 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1170 if (length_mismatch_in_expr_p (location, an_info))
1172 pop_stmt_list (loop_init);
1173 return error_mark_node;
1175 for (ii = 0; ii < rank; ii++)
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));
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++)
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);
1200 append_to_statement_list_force (body, &loop_with_init);
1201 release_vec_vec (an_info);
1202 return loop_with_init;
1205 /* Expands the built-in functions in a return. EXPR is a RETURN_EXPR with
1206 a built-in reduction function. This function returns the expansion code for
1207 the built-in function. */
1209 static tree
1210 fix_return_expr (tree expr)
1212 tree new_mod_list, new_var, new_mod, retval_expr, retval_type;
1213 location_t loc = EXPR_LOCATION (expr);
1215 new_mod_list = alloc_stmt_list ();
1216 retval_expr = TREE_OPERAND (expr, 0);
1217 retval_type = TREE_TYPE (TREE_OPERAND (retval_expr, 1));
1218 new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr));
1219 new_mod = build_array_notation_expr (loc, new_var, TREE_TYPE (new_var),
1220 NOP_EXPR, loc,
1221 TREE_OPERAND (retval_expr, 1),
1222 retval_type);
1223 TREE_OPERAND (retval_expr, 1) = new_var;
1224 TREE_OPERAND (expr, 0) = retval_expr;
1225 append_to_statement_list_force (new_mod, &new_mod_list);
1226 append_to_statement_list_force (expr, &new_mod_list);
1227 return new_mod_list;
1230 /* Callback for walk_tree. Expands all array notations in *TP. *WALK_SUBTREES
1231 is set to 1 unless *TP contains no array notation expressions. */
1233 static tree
1234 expand_array_notations (tree *tp, int *walk_subtrees, void *)
1236 if (!contains_array_notation_expr (*tp))
1238 *walk_subtrees = 0;
1239 return NULL_TREE;
1241 *walk_subtrees = 1;
1243 switch (TREE_CODE (*tp))
1245 case TRUTH_ORIF_EXPR:
1246 case TRUTH_ANDIF_EXPR:
1247 case TRUTH_OR_EXPR:
1248 case TRUTH_AND_EXPR:
1249 case TRUTH_XOR_EXPR:
1250 case TRUTH_NOT_EXPR:
1251 case COND_EXPR:
1252 *tp = fix_conditional_array_notations (*tp);
1253 break;
1254 case MODIFY_EXPR:
1256 location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) :
1257 UNKNOWN_LOCATION;
1258 tree lhs = TREE_OPERAND (*tp, 0);
1259 tree rhs = TREE_OPERAND (*tp, 1);
1260 location_t rhs_loc = EXPR_HAS_LOCATION (rhs) ? EXPR_LOCATION (rhs) :
1261 UNKNOWN_LOCATION;
1262 *tp = build_array_notation_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR,
1263 rhs_loc, rhs, TREE_TYPE (rhs));
1265 break;
1266 case DECL_EXPR:
1268 tree x = DECL_EXPR_DECL (*tp);
1269 if (DECL_INITIAL (x))
1271 location_t loc = DECL_SOURCE_LOCATION (x);
1272 tree lhs = x;
1273 tree rhs = DECL_INITIAL (x);
1274 DECL_INITIAL (x) = NULL;
1275 tree new_modify_expr = build_modify_expr (loc, lhs,
1276 TREE_TYPE (lhs),
1277 NOP_EXPR,
1278 loc, rhs,
1279 TREE_TYPE(rhs));
1280 expand_array_notations (&new_modify_expr, walk_subtrees, NULL);
1281 *tp = new_modify_expr;
1284 break;
1285 case CALL_EXPR:
1286 *tp = fix_array_notation_call_expr (*tp);
1287 break;
1288 case RETURN_EXPR:
1289 *tp = fix_return_expr (*tp);
1290 break;
1291 case COMPOUND_EXPR:
1292 if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR)
1294 /* In here we are calling expand_array_notations because
1295 we need to be able to catch the return value and check if
1296 it is an error_mark_node. */
1297 expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL);
1299 /* SAVE_EXPR cannot have an error_mark_node inside it. This check
1300 will make sure that if there is an error in expanding of
1301 array notations (e.g. rank mismatch) then replace the entire
1302 SAVE_EXPR with an error_mark_node. */
1303 if (TREE_OPERAND (*tp, 1) == error_mark_node)
1304 *tp = error_mark_node;
1306 break;
1307 case ARRAY_NOTATION_REF:
1308 /* If we are here, then we are dealing with cases like this:
1309 A[:];
1310 A[x:y:z];
1311 A[x:y];
1312 Replace those with just void zero node. */
1313 *tp = void_node;
1314 default:
1315 break;
1317 return NULL_TREE;
1320 /* Walks through tree node T and expands all array notations in its subtrees.
1321 The return value is the same type as T but with all array notations
1322 replaced with appropriate ARRAY_REFS with a loop around it. */
1324 tree
1325 expand_array_notation_exprs (tree t)
1327 walk_tree (&t, expand_array_notations, NULL, NULL);
1328 return t;
1331 /* This handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which
1332 denotes an array notation expression. If a is a variable or a member, then
1333 we generate a ARRAY_NOTATION_REF front-end tree and return it.
1334 This tree is broken down to ARRAY_REF toward the end of parsing.
1335 ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE
1336 of ARRAY_REF. Restrictions on START_INDEX, LENGTH and STRIDE is same as that
1337 of the index field passed into ARRAY_REF. The only additional restriction
1338 is that, unlike index in ARRAY_REF, stride, length and start_index cannot
1339 contain ARRAY_NOTATIONS. */
1341 tree
1342 build_array_notation_ref (location_t loc, tree array, tree start_index,
1343 tree length, tree stride, tree type)
1345 tree array_ntn_tree = NULL_TREE;
1346 size_t stride_rank = 0, length_rank = 0, start_rank = 0;
1348 if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
1350 error_at (loc,
1351 "start-index of array notation triplet is not an integer");
1352 return error_mark_node;
1354 if (!INTEGRAL_TYPE_P (TREE_TYPE (length)))
1356 error_at (loc, "length of array notation triplet is not an integer");
1357 return error_mark_node;
1360 /* The stride is an optional field. */
1361 if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
1363 error_at (loc, "stride of array notation triplet is not an integer");
1364 return error_mark_node;
1366 if (!stride)
1368 if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length)
1369 && tree_int_cst_lt (length, start_index))
1370 stride = build_int_cst (TREE_TYPE (start_index), -1);
1371 else
1372 stride = build_int_cst (TREE_TYPE (start_index), 1);
1375 if (!find_rank (loc, start_index, start_index, false, &start_rank))
1376 return error_mark_node;
1377 if (!find_rank (loc, length, length, false, &length_rank))
1378 return error_mark_node;
1379 if (!find_rank (loc, stride, stride, false, &stride_rank))
1380 return error_mark_node;
1382 if (start_rank != 0)
1384 error_at (loc, "rank of an array notation triplet's start-index is not "
1385 "zero");
1386 return error_mark_node;
1388 if (length_rank != 0)
1390 error_at (loc, "rank of an array notation triplet's length is not zero");
1391 return error_mark_node;
1393 if (stride_rank != 0)
1395 error_at (loc, "rank of array notation triplet's stride is not zero");
1396 return error_mark_node;
1398 array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE,
1399 NULL_TREE, NULL_TREE);
1400 ARRAY_NOTATION_ARRAY (array_ntn_tree) = array;
1401 ARRAY_NOTATION_START (array_ntn_tree) = start_index;
1402 ARRAY_NOTATION_LENGTH (array_ntn_tree) = length;
1403 ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride;
1404 TREE_TYPE (array_ntn_tree) = type;
1406 return array_ntn_tree;