gcc/c/
[official-gcc.git] / gcc / c / c-array-notation.c
blobb4015b84ee92009d34a0d6eb1829f2b3bb0aa0f1
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-2014 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 "tree.h"
72 #include "c-tree.h"
73 #include "gimple-expr.h"
74 #include "tree-iterator.h"
75 #include "opts.h"
76 #include "c-family/c-common.h"
78 /* If *VALUE is not of type INTEGER_CST, PARM_DECL or VAR_DECL, then map it
79 to a variable and then set *VALUE to the new variable. */
81 static inline void
82 make_triplet_val_inv (location_t loc, tree *value)
84 tree var, new_exp;
85 if (TREE_CODE (*value) != INTEGER_CST
86 && TREE_CODE (*value) != PARM_DECL
87 && TREE_CODE (*value) != VAR_DECL)
89 var = build_decl (loc, VAR_DECL, NULL_TREE, integer_type_node);
90 new_exp = build_modify_expr (loc, var, TREE_TYPE (var), NOP_EXPR, loc,
91 *value, TREE_TYPE (*value));
92 add_stmt (new_exp);
93 *value = var;
97 /* Populates the INCR and CMP vectors with the increment (of type POSTINCREMENT
98 or POSTDECREMENT) and comparison (of TYPE GT_EXPR or LT_EXPR) expressions,
99 using data from LENGTH, COUNT_DOWN, and VAR. INCR and CMP vectors are of
100 size RANK. */
102 static void
103 create_cmp_incr (location_t loc, vec<an_loop_parts> *node, size_t rank,
104 vec<vec<an_parts> > an_info)
106 for (size_t ii = 0; ii < rank; ii++)
108 tree var = (*node)[ii].var;
109 tree length = an_info[0][ii].length;
110 (*node)[ii].incr = build_unary_op (loc, POSTINCREMENT_EXPR, var, 0);
111 (*node)[ii].cmp = build2 (LT_EXPR, boolean_type_node, var, length);
115 /* Returns a vector of size RANK that contains an array ref that is derived from
116 array notation triplet parameters stored in VALUE, START, STRIDE. IS_VECTOR
117 is used to check if the data stored at its corresponding location is an
118 array notation. VAR is the induction variable passed in by the caller.
120 For example: For an array notation A[5:10:2], the vector start will be
121 of size 1 holding '5', stride of same size as start but holding the value of
122 as 2, is_vector as true and count_down as false. Let's assume VAR is 'x'
123 This function returns a vector of size 1 with the following data:
124 A[5 + (x * 2)] .
127 static vec<tree, va_gc> *
128 create_array_refs (location_t loc, vec<vec<an_parts> > an_info,
129 vec<an_loop_parts> an_loop_info, size_t size, size_t rank)
131 tree ind_mult, ind_incr;
132 vec<tree, va_gc> *array_operand = NULL;
133 for (size_t ii = 0; ii < size; ii++)
134 if (an_info[ii][0].is_vector)
136 tree array_opr = an_info[ii][rank - 1].value;
137 for (int s_jj = rank - 1; s_jj >= 0; s_jj--)
139 tree var = an_loop_info[s_jj].var;
140 tree stride = an_info[ii][s_jj].stride;
141 tree start = an_info[ii][s_jj].start;
142 ind_mult = build2 (MULT_EXPR, TREE_TYPE (var), var, stride);
143 ind_incr = build2 (PLUS_EXPR, TREE_TYPE (var), start, ind_mult);
144 array_opr = build_array_ref (loc, array_opr, ind_incr);
146 vec_safe_push (array_operand, array_opr);
148 else
149 /* This is just a dummy node to make sure both the list sizes for both
150 array list and array operand list are the same. */
151 vec_safe_push (array_operand, integer_one_node);
152 return array_operand;
155 /* Replaces all the scalar expressions in *NODE. Returns a STATEMENT_LIST that
156 holds the NODE along with variables that holds the results of the invariant
157 expressions. */
159 tree
160 replace_invariant_exprs (tree *node)
162 size_t ix = 0;
163 tree node_list = NULL_TREE;
164 tree t = NULL_TREE, new_var = NULL_TREE, new_node;
165 struct inv_list data;
167 data.list_values = NULL;
168 data.replacement = NULL;
169 data.additional_tcodes = NULL;
170 walk_tree (node, find_inv_trees, (void *)&data, NULL);
172 if (vec_safe_length (data.list_values))
174 node_list = push_stmt_list ();
175 for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++)
177 new_var = build_decl (EXPR_LOCATION (t), VAR_DECL, NULL_TREE,
178 TREE_TYPE (t));
179 gcc_assert (new_var != NULL_TREE && new_var != error_mark_node);
180 new_node = build2 (MODIFY_EXPR, TREE_TYPE (t), new_var, t);
181 add_stmt (new_node);
182 vec_safe_push (data.replacement, new_var);
184 walk_tree (node, replace_inv_trees, (void *)&data, NULL);
185 node_list = pop_stmt_list (node_list);
187 return node_list;
190 /* Given a CALL_EXPR to an array notation built-in function in
191 AN_BUILTIN_FN, replace the call with the appropriate loop and
192 computation. Return the computation in *NEW_VAR.
194 The return value in *NEW_VAR will always be a scalar. If the
195 built-in is __sec_reduce_mutating, *NEW_VAR is set to NULL_TREE. */
197 static tree
198 fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var)
200 tree new_var_type = NULL_TREE, func_parm, new_expr, new_yes_expr, new_no_expr;
201 tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list;
202 tree new_yes_list, new_cond_expr, new_var_init = NULL_TREE;
203 tree new_exp_init = NULL_TREE;
204 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
205 size_t list_size = 0, rank = 0, ii = 0;
206 tree loop_init, array_op0;
207 tree identity_value = NULL_TREE, call_fn = NULL_TREE, new_call_expr, body;
208 location_t location = UNKNOWN_LOCATION;
209 tree loop_with_init = alloc_stmt_list ();
210 vec<vec<an_parts> > an_info = vNULL;
211 vec<an_loop_parts> an_loop_info = vNULL;
212 enum built_in_function an_type =
213 is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn));
214 if (an_type == BUILT_IN_NONE)
215 return NULL_TREE;
217 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE
218 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
220 call_fn = CALL_EXPR_ARG (an_builtin_fn, 2);
221 if (TREE_CODE (call_fn) == ADDR_EXPR)
222 call_fn = TREE_OPERAND (call_fn, 0);
223 identity_value = CALL_EXPR_ARG (an_builtin_fn, 0);
224 func_parm = CALL_EXPR_ARG (an_builtin_fn, 1);
226 else
227 func_parm = CALL_EXPR_ARG (an_builtin_fn, 0);
229 /* Fully fold any EXCESSIVE_PRECISION EXPR that can occur in the function
230 parameter. */
231 func_parm = c_fully_fold (func_parm, false, NULL);
232 if (func_parm == error_mark_node)
233 return error_mark_node;
235 location = EXPR_LOCATION (an_builtin_fn);
237 if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank))
238 return error_mark_node;
240 if (rank == 0)
241 return an_builtin_fn;
242 else if (rank > 1
243 && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
244 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND))
246 error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot"
247 " have arrays with dimension greater than 1");
248 return error_mark_node;
251 extract_array_notation_exprs (func_parm, true, &array_list);
252 list_size = vec_safe_length (array_list);
253 switch (an_type)
255 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
256 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
257 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
258 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
259 new_var_type = TREE_TYPE ((*array_list)[0]);
260 break;
261 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
262 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
263 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
264 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
265 new_var_type = integer_type_node;
266 break;
267 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
268 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
269 new_var_type = integer_type_node;
270 break;
271 case BUILT_IN_CILKPLUS_SEC_REDUCE:
272 if (call_fn && identity_value)
273 new_var_type = TREE_TYPE ((*array_list)[0]);
274 break;
275 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
276 new_var_type = NULL_TREE;
277 break;
278 default:
279 gcc_unreachable ();
282 an_loop_info.safe_grow_cleared (rank);
283 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
284 loop_init = alloc_stmt_list ();
286 for (ii = 0; ii < rank; ii++)
288 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
289 an_loop_info[ii].ind_init =
290 build_modify_expr (location, an_loop_info[ii].var,
291 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
292 location,
293 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
294 TREE_TYPE (an_loop_info[ii].var));
296 array_operand = create_array_refs (location, an_info, an_loop_info,
297 list_size, rank);
298 replace_array_notations (&func_parm, true, array_list, array_operand);
300 create_cmp_incr (location, &an_loop_info, rank, an_info);
301 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
303 *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type);
304 gcc_assert (*new_var && *new_var != error_mark_node);
306 else
307 *new_var = NULL_TREE;
309 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
310 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
311 array_ind_value = build_decl (location, VAR_DECL, NULL_TREE,
312 TREE_TYPE (func_parm));
313 array_op0 = (*array_operand)[0];
314 if (TREE_CODE (array_op0) == INDIRECT_REF)
315 array_op0 = TREE_OPERAND (array_op0, 0);
316 switch (an_type)
318 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
319 new_var_init = build_modify_expr
320 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
321 location, build_zero_cst (new_var_type), new_var_type);
322 new_expr = build_modify_expr
323 (location, *new_var, TREE_TYPE (*new_var), PLUS_EXPR,
324 location, func_parm, TREE_TYPE (func_parm));
325 break;
326 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
327 new_var_init = build_modify_expr
328 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
329 location, build_one_cst (new_var_type), new_var_type);
330 new_expr = build_modify_expr
331 (location, *new_var, TREE_TYPE (*new_var), MULT_EXPR,
332 location, func_parm, TREE_TYPE (func_parm));
333 break;
334 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
335 new_var_init = build_modify_expr
336 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
337 location, build_one_cst (new_var_type), new_var_type);
338 /* Initially you assume everything is zero, now if we find a case where
339 it is NOT true, then we set the result to false. Otherwise
340 we just keep the previous value. */
341 new_yes_expr = build_modify_expr
342 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
343 location, build_zero_cst (TREE_TYPE (*new_var)),
344 TREE_TYPE (*new_var));
345 new_no_expr = build_modify_expr
346 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
347 location, *new_var, TREE_TYPE (*new_var));
348 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
349 build_zero_cst (TREE_TYPE (func_parm)));
350 new_expr = build_conditional_expr
351 (location, new_cond_expr, false, new_yes_expr,
352 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
353 break;
354 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
355 new_var_init = build_modify_expr
356 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
357 location, build_one_cst (new_var_type), new_var_type);
358 /* Initially you assume everything is non-zero, now if we find a case
359 where it is NOT true, then we set the result to false. Otherwise
360 we just keep the previous value. */
361 new_yes_expr = build_modify_expr
362 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
363 location, build_zero_cst (TREE_TYPE (*new_var)),
364 TREE_TYPE (*new_var));
365 new_no_expr = build_modify_expr
366 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
367 location, *new_var, TREE_TYPE (*new_var));
368 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
369 build_zero_cst (TREE_TYPE (func_parm)));
370 new_expr = build_conditional_expr
371 (location, new_cond_expr, false, new_yes_expr,
372 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
373 break;
374 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
375 new_var_init = build_modify_expr
376 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
377 location, build_zero_cst (new_var_type), new_var_type);
378 /* Initially we assume there are NO zeros in the list. When we find
379 a non-zero, we keep the previous value. If we find a zero, we
380 set the value to true. */
381 new_yes_expr = build_modify_expr
382 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
383 location, build_one_cst (new_var_type), new_var_type);
384 new_no_expr = build_modify_expr
385 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
386 location, *new_var, TREE_TYPE (*new_var));
387 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
388 build_zero_cst (TREE_TYPE (func_parm)));
389 new_expr = build_conditional_expr
390 (location, new_cond_expr, false, new_yes_expr,
391 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
392 break;
393 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
394 new_var_init = build_modify_expr
395 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
396 location, build_zero_cst (new_var_type), new_var_type);
397 /* Initially we assume there are NO non-zeros in the list. When we find
398 a zero, we keep the previous value. If we find a non-zero, we set
399 the value to true. */
400 new_yes_expr = build_modify_expr
401 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
402 location, build_one_cst (new_var_type), new_var_type);
403 new_no_expr = build_modify_expr
404 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
405 location, *new_var, TREE_TYPE (*new_var));
406 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
407 build_zero_cst (TREE_TYPE (func_parm)));
408 new_expr = build_conditional_expr
409 (location, new_cond_expr, false, new_yes_expr,
410 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
411 break;
412 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
413 if (TYPE_MIN_VALUE (new_var_type))
414 new_var_init = build_modify_expr
415 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
416 location, TYPE_MIN_VALUE (new_var_type), new_var_type);
417 else
418 new_var_init = build_modify_expr
419 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
420 location, func_parm, new_var_type);
421 new_no_expr = build_modify_expr
422 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
423 location, *new_var, TREE_TYPE (*new_var));
424 new_yes_expr = build_modify_expr
425 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
426 location, func_parm, TREE_TYPE (*new_var));
427 new_expr = build_conditional_expr
428 (location,
429 build2 (LT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
430 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
431 break;
432 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
433 if (TYPE_MAX_VALUE (new_var_type))
434 new_var_init = build_modify_expr
435 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
436 location, TYPE_MAX_VALUE (new_var_type), new_var_type);
437 else
438 new_var_init = build_modify_expr
439 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
440 location, func_parm, new_var_type);
441 new_no_expr = build_modify_expr
442 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
443 location, *new_var, TREE_TYPE (*new_var));
444 new_yes_expr = build_modify_expr
445 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
446 location, func_parm, TREE_TYPE (*new_var));
447 new_expr = build_conditional_expr
448 (location,
449 build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
450 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
451 break;
452 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
453 new_var_init = build_modify_expr
454 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
455 location, build_zero_cst (new_var_type), new_var_type);
456 new_exp_init = build_modify_expr
457 (location, array_ind_value, TREE_TYPE (array_ind_value),
458 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
459 new_no_ind = build_modify_expr
460 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
461 location, *new_var, TREE_TYPE (*new_var));
462 new_no_expr = build_modify_expr
463 (location, array_ind_value, TREE_TYPE (array_ind_value),
464 NOP_EXPR,
465 location, array_ind_value, TREE_TYPE (array_ind_value));
466 if (list_size > 1)
468 new_yes_ind = build_modify_expr
469 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
470 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
471 new_yes_expr = build_modify_expr
472 (location, array_ind_value, TREE_TYPE (array_ind_value),
473 NOP_EXPR,
474 location, func_parm, TREE_TYPE ((*array_operand)[0]));
476 else
478 new_yes_ind = build_modify_expr
479 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
480 location, TREE_OPERAND (array_op0, 1),
481 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
482 new_yes_expr = build_modify_expr
483 (location, array_ind_value, TREE_TYPE (array_ind_value),
484 NOP_EXPR,
485 location, func_parm, TREE_OPERAND (array_op0, 1));
487 new_yes_list = alloc_stmt_list ();
488 append_to_statement_list (new_yes_ind, &new_yes_list);
489 append_to_statement_list (new_yes_expr, &new_yes_list);
491 new_no_list = alloc_stmt_list ();
492 append_to_statement_list (new_no_ind, &new_no_list);
493 append_to_statement_list (new_no_expr, &new_no_list);
495 new_expr = build_conditional_expr
496 (location,
497 build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
498 func_parm),
499 false,
500 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
501 break;
502 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
503 new_var_init = build_modify_expr
504 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
505 location, build_zero_cst (new_var_type), new_var_type);
506 new_exp_init = build_modify_expr
507 (location, array_ind_value, TREE_TYPE (array_ind_value),
508 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
509 new_no_ind = build_modify_expr
510 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
511 location, *new_var, TREE_TYPE (*new_var));
512 new_no_expr = build_modify_expr
513 (location, array_ind_value, TREE_TYPE (array_ind_value),
514 NOP_EXPR,
515 location, array_ind_value, TREE_TYPE (array_ind_value));
516 if (list_size > 1)
518 new_yes_ind = build_modify_expr
519 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
520 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
521 new_yes_expr = build_modify_expr
522 (location, array_ind_value, TREE_TYPE (array_ind_value),
523 NOP_EXPR,
524 location, func_parm, TREE_TYPE (array_op0));
526 else
528 new_yes_ind = build_modify_expr
529 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
530 location, TREE_OPERAND (array_op0, 1),
531 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
532 new_yes_expr = build_modify_expr
533 (location, array_ind_value, TREE_TYPE (array_ind_value),
534 NOP_EXPR,
535 location, func_parm, TREE_OPERAND (array_op0, 1));
537 new_yes_list = alloc_stmt_list ();
538 append_to_statement_list (new_yes_ind, &new_yes_list);
539 append_to_statement_list (new_yes_expr, &new_yes_list);
541 new_no_list = alloc_stmt_list ();
542 append_to_statement_list (new_no_ind, &new_no_list);
543 append_to_statement_list (new_no_expr, &new_no_list);
545 new_expr = build_conditional_expr
546 (location,
547 build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
548 func_parm),
549 false,
550 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
551 break;
552 case BUILT_IN_CILKPLUS_SEC_REDUCE:
553 new_var_init = build_modify_expr
554 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
555 location, identity_value, new_var_type);
556 new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm);
557 new_expr = build_modify_expr
558 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
559 location, new_call_expr, TREE_TYPE (*new_var));
560 break;
561 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
562 new_expr = build_call_expr (call_fn, 2, identity_value, func_parm);
563 break;
564 default:
565 gcc_unreachable ();
566 break;
569 for (ii = 0; ii < rank; ii++)
570 append_to_statement_list (an_loop_info[ii].ind_init, &loop_init);
572 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
573 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
574 append_to_statement_list (new_exp_init, &loop_init);
575 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
576 append_to_statement_list (new_var_init, &loop_init);
578 append_to_statement_list_force (loop_init, &loop_with_init);
579 body = new_expr;
580 for (ii = 0; ii < rank; ii++)
582 tree new_loop = push_stmt_list ();
583 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
584 body, NULL_TREE, NULL_TREE, true);
585 body = pop_stmt_list (new_loop);
587 append_to_statement_list_force (body, &loop_with_init);
589 an_info.release ();
590 an_loop_info.release ();
592 return loop_with_init;
595 /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
596 The LHS and/or RHS will be array notation expressions that have a MODIFYCODE
597 Their locations are specified by LHS_LOC, RHS_LOC. The location of the
598 modify expression is location. The original type of LHS and RHS are passed
599 in LHS_ORIGTYPE and RHS_ORIGTYPE. */
601 tree
602 build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
603 enum tree_code modifycode, location_t rhs_loc,
604 tree rhs, tree rhs_origtype)
606 bool found_builtin_fn = false;
607 tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
608 tree array_expr = NULL_TREE;
609 tree an_init = NULL_TREE;
610 vec<tree> cond_expr = vNULL;
611 tree body, loop_with_init = alloc_stmt_list();
612 tree scalar_mods = NULL_TREE;
613 vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL;
614 size_t lhs_rank = 0, rhs_rank = 0;
615 size_t ii = 0;
616 vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL;
617 tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE;
618 size_t rhs_list_size = 0, lhs_list_size = 0;
619 vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
620 vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL;
622 /* If either of this is true, an error message must have been send out
623 already. Not necessary to send out multiple error messages. */
624 if (lhs == error_mark_node || rhs == error_mark_node)
625 return error_mark_node;
627 if (!find_rank (location, rhs, rhs, false, &rhs_rank))
628 return error_mark_node;
630 extract_array_notation_exprs (rhs, false, &rhs_list);
631 rhs_list_size = vec_safe_length (rhs_list);
632 an_init = push_stmt_list ();
633 if (rhs_rank)
635 scalar_mods = replace_invariant_exprs (&rhs);
636 if (scalar_mods)
637 add_stmt (scalar_mods);
639 for (ii = 0; ii < rhs_list_size; ii++)
641 tree rhs_node = (*rhs_list)[ii];
642 if (TREE_CODE (rhs_node) == CALL_EXPR)
644 builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
645 if (builtin_loop == error_mark_node)
647 pop_stmt_list (an_init);
648 return error_mark_node;
650 else if (builtin_loop)
652 add_stmt (builtin_loop);
653 found_builtin_fn = true;
654 if (new_var)
656 vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
657 vec_safe_push (rhs_sub_list, rhs_node);
658 vec_safe_push (new_var_list, new_var);
659 replace_array_notations (&rhs, false, rhs_sub_list,
660 new_var_list);
666 lhs_rank = 0;
667 rhs_rank = 0;
668 if (!find_rank (location, lhs, lhs, true, &lhs_rank))
670 pop_stmt_list (an_init);
671 return error_mark_node;
674 if (!find_rank (location, rhs, rhs, true, &rhs_rank))
676 pop_stmt_list (an_init);
677 return error_mark_node;
680 if (lhs_rank == 0 && rhs_rank == 0)
682 if (found_builtin_fn)
684 new_modify_expr = build_modify_expr (location, lhs, lhs_origtype,
685 modifycode, rhs_loc, rhs,
686 rhs_origtype);
687 add_stmt (new_modify_expr);
688 pop_stmt_list (an_init);
689 return an_init;
691 else
693 pop_stmt_list (an_init);
694 return NULL_TREE;
697 rhs_list_size = 0;
698 rhs_list = NULL;
699 extract_array_notation_exprs (rhs, true, &rhs_list);
700 extract_array_notation_exprs (lhs, true, &lhs_list);
701 rhs_list_size = vec_safe_length (rhs_list);
702 lhs_list_size = vec_safe_length (lhs_list);
704 if (lhs_rank == 0 && rhs_rank != 0)
706 tree rhs_base = rhs;
707 if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
709 for (ii = 0; ii < (size_t) rhs_rank; ii++)
710 rhs_base = ARRAY_NOTATION_ARRAY (rhs);
712 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
713 rhs_base);
714 return error_mark_node;
716 else
718 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
719 rhs_base);
720 return error_mark_node;
723 if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
725 error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
726 pop_stmt_list (an_init);
727 return error_mark_node;
730 /* Here we assign the array notation components to variable so that we can
731 satisfy the exec once rule. */
732 for (ii = 0; ii < lhs_list_size; ii++)
734 tree array_node = (*lhs_list)[ii];
735 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
736 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
737 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
739 for (ii = 0; ii < rhs_list_size; ii++)
740 if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
742 tree array_node = (*rhs_list)[ii];
743 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
744 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
745 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
748 cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
750 lhs_an_loop_info.safe_grow_cleared (lhs_rank);
751 if (rhs_rank)
752 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
754 cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
755 &lhs_an_info);
756 if (rhs_rank)
758 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
759 cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
760 &rhs_an_info);
762 if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
763 || (rhs_rank
764 && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info)))
766 pop_stmt_list (an_init);
767 return error_mark_node;
769 if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
770 && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST
771 && rhs_an_info[0][0].length
772 && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST)
774 HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length);
775 HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length);
776 /* Length can be negative or positive. As long as the magnitude is OK,
777 then the array notation is valid. */
778 if (absu_hwi (l_length) != absu_hwi (r_length))
780 error_at (location, "length mismatch between LHS and RHS");
781 pop_stmt_list (an_init);
782 return error_mark_node;
785 for (ii = 0; ii < lhs_rank; ii++)
786 if (lhs_an_info[0][ii].is_vector)
788 lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node,
789 NULL);
790 lhs_an_loop_info[ii].ind_init = build_modify_expr
791 (location, lhs_an_loop_info[ii].var,
792 TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR,
793 location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)),
794 TREE_TYPE (lhs_an_loop_info[ii].var));
796 for (ii = 0; ii < rhs_rank; ii++)
798 /* When we have a polynomial, we assume that the indices are of type
799 integer. */
800 rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node,
801 NULL);
802 rhs_an_loop_info[ii].ind_init = build_modify_expr
803 (location, rhs_an_loop_info[ii].var,
804 TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR,
805 location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0),
806 TREE_TYPE (rhs_an_loop_info[ii].var));
808 if (lhs_rank)
810 lhs_array_operand = create_array_refs
811 (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank);
812 replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
813 array_expr_lhs = lhs;
815 if (rhs_array_operand)
816 vec_safe_truncate (rhs_array_operand, 0);
817 if (rhs_rank)
819 rhs_array_operand = create_array_refs
820 (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank);
821 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
822 vec_safe_truncate (rhs_array_operand, 0);
823 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
824 rhs_an_loop_info, rhs_rank,
825 rhs);
826 if (!rhs_array_operand)
827 return error_mark_node;
828 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
830 else if (rhs_list_size > 0)
832 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
833 lhs_an_loop_info, lhs_rank,
834 lhs);
835 if (!rhs_array_operand)
836 return error_mark_node;
837 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
839 array_expr_lhs = lhs;
840 array_expr_rhs = rhs;
841 array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype,
842 modifycode, rhs_loc, array_expr_rhs,
843 rhs_origtype);
844 create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info);
845 if (rhs_rank)
846 create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info);
848 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
849 if (ii < lhs_rank && ii < rhs_rank)
850 cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node,
851 lhs_an_loop_info[ii].cmp,
852 rhs_an_loop_info[ii].cmp);
853 else if (ii < lhs_rank && ii >= rhs_rank)
854 cond_expr[ii] = lhs_an_loop_info[ii].cmp;
855 else
856 gcc_unreachable ();
858 an_init = pop_stmt_list (an_init);
859 append_to_statement_list_force (an_init, &loop_with_init);
860 body = array_expr;
861 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
863 tree incr_list = alloc_stmt_list ();
864 tree new_loop = push_stmt_list ();
865 if (lhs_rank)
866 add_stmt (lhs_an_loop_info[ii].ind_init);
867 if (rhs_rank)
868 add_stmt (rhs_an_loop_info[ii].ind_init);
869 if (lhs_rank)
870 append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list);
871 if (rhs_rank && rhs_an_loop_info[ii].incr)
872 append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list);
873 c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE,
874 NULL_TREE, true);
875 body = pop_stmt_list (new_loop);
877 append_to_statement_list_force (body, &loop_with_init);
879 lhs_an_info.release ();
880 lhs_an_loop_info.release ();
881 if (rhs_rank)
883 rhs_an_info.release ();
884 rhs_an_loop_info.release ();
886 cond_expr.release ();
887 return loop_with_init;
890 /* Helper function for fix_conditional_array_notations. Encloses the
891 conditional statement passed in STMT with a loop around it
892 and replaces the condition in STMT with a ARRAY_REF tree-node to the array.
893 The condition must have an ARRAY_NOTATION_REF tree. An expansion of array
894 notation in STMT is returned in a STATEMENT_LIST. */
896 static tree
897 fix_conditional_array_notations_1 (tree stmt)
899 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
900 size_t list_size = 0;
901 tree cond = NULL_TREE, builtin_loop = NULL_TREE, new_var = NULL_TREE;
902 size_t rank = 0, ii = 0;
903 tree loop_init;
904 location_t location = EXPR_LOCATION (stmt);
905 tree body = NULL_TREE, loop_with_init = alloc_stmt_list ();
906 vec<vec<an_parts> > an_info = vNULL;
907 vec<an_loop_parts> an_loop_info = vNULL;
909 if (TREE_CODE (stmt) == COND_EXPR)
910 cond = COND_EXPR_COND (stmt);
911 else if (TREE_CODE (stmt) == SWITCH_EXPR)
912 cond = SWITCH_COND (stmt);
913 else if (truth_value_p (TREE_CODE (stmt)))
914 cond = TREE_OPERAND (stmt, 0);
915 else
916 /* Otherwise dont even touch the statement. */
917 return stmt;
919 if (!find_rank (location, cond, cond, false, &rank))
920 return error_mark_node;
922 extract_array_notation_exprs (stmt, false, &array_list);
923 loop_init = push_stmt_list ();
924 for (ii = 0; ii < vec_safe_length (array_list); ii++)
926 tree array_node = (*array_list)[ii];
927 if (TREE_CODE (array_node) == CALL_EXPR)
929 builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var);
930 if (builtin_loop == error_mark_node)
932 add_stmt (error_mark_node);
933 pop_stmt_list (loop_init);
934 return loop_init;
936 else if (builtin_loop)
938 vec <tree, va_gc>* sub_list = NULL, *new_var_list = NULL;
939 vec_safe_push (sub_list, array_node);
940 vec_safe_push (new_var_list, new_var);
941 add_stmt (builtin_loop);
942 replace_array_notations (&stmt, false, sub_list, new_var_list);
946 if (!find_rank (location, stmt, stmt, true, &rank))
948 pop_stmt_list (loop_init);
949 return error_mark_node;
951 if (rank == 0)
953 add_stmt (stmt);
954 pop_stmt_list (loop_init);
955 return loop_init;
957 extract_array_notation_exprs (stmt, true, &array_list);
959 if (vec_safe_length (array_list) == 0)
960 return stmt;
962 list_size = vec_safe_length (array_list);
963 an_loop_info.safe_grow_cleared (rank);
965 for (ii = 0; ii < list_size; ii++)
966 if ((*array_list)[ii]
967 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
969 tree array_node = (*array_list)[ii];
970 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
971 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
972 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
974 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
975 for (ii = 0; ii < rank; ii++)
977 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
978 an_loop_info[ii].ind_init =
979 build_modify_expr (location, an_loop_info[ii].var,
980 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
981 location,
982 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
983 TREE_TYPE (an_loop_info[ii].var));
985 array_operand = create_array_refs (location, an_info, an_loop_info,
986 list_size, rank);
987 replace_array_notations (&stmt, true, array_list, array_operand);
988 create_cmp_incr (location, &an_loop_info, rank, an_info);
990 loop_init = pop_stmt_list (loop_init);
991 body = stmt;
992 append_to_statement_list_force (loop_init, &loop_with_init);
994 for (ii = 0; ii < rank; ii++)
996 tree new_loop = push_stmt_list ();
997 add_stmt (an_loop_info[ii].ind_init);
998 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
999 body, NULL_TREE, NULL_TREE, true);
1000 body = pop_stmt_list (new_loop);
1002 append_to_statement_list_force (body, &loop_with_init);
1004 an_loop_info.release ();
1005 an_info.release ();
1007 return loop_with_init;
1010 /* Top-level function to replace ARRAY_NOTATION_REF in a conditional statement
1011 in STMT. An expansion of array notation in STMT is returned as a
1012 STATEMENT_LIST. */
1014 tree
1015 fix_conditional_array_notations (tree stmt)
1017 if (TREE_CODE (stmt) == STATEMENT_LIST)
1019 tree_stmt_iterator tsi;
1020 for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi))
1022 tree single_stmt = *tsi_stmt_ptr (tsi);
1023 *tsi_stmt_ptr (tsi) =
1024 fix_conditional_array_notations_1 (single_stmt);
1026 return stmt;
1028 else
1029 return fix_conditional_array_notations_1 (stmt);
1032 /* Create a struct c_expr that contains a loop with ARRAY_REF expr at location
1033 LOCATION with the tree_code CODE and the array notation expr is
1034 passed in ARG. Returns the fixed c_expr in ARG itself. */
1036 struct c_expr
1037 fix_array_notation_expr (location_t location, enum tree_code code,
1038 struct c_expr arg)
1041 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1042 size_t list_size = 0, rank = 0, ii = 0;
1043 tree loop_init;
1044 tree body, loop_with_init = alloc_stmt_list ();
1045 vec<vec<an_parts> > an_info = vNULL;
1046 vec<an_loop_parts> an_loop_info = vNULL;
1048 if (!find_rank (location, arg.value, arg.value, false, &rank))
1050 /* If this function returns a NULL, we convert the tree value in the
1051 structure to error_mark_node and the parser should take care of the
1052 rest. */
1053 arg.value = error_mark_node;
1054 return arg;
1057 if (rank == 0)
1058 return arg;
1060 extract_array_notation_exprs (arg.value, true, &array_list);
1062 if (vec_safe_length (array_list) == 0)
1063 return arg;
1065 list_size = vec_safe_length (array_list);
1067 an_loop_info.safe_grow_cleared (rank);
1068 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1070 loop_init = push_stmt_list ();
1071 for (ii = 0; ii < rank; ii++)
1073 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
1074 an_loop_info[ii].ind_init =
1075 build_modify_expr (location, an_loop_info[ii].var,
1076 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
1077 location,
1078 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1079 TREE_TYPE (an_loop_info[ii].var));;
1082 array_operand = create_array_refs (location, an_info, an_loop_info,
1083 list_size, rank);
1084 replace_array_notations (&arg.value, true, array_list, array_operand);
1085 create_cmp_incr (location, &an_loop_info, rank, an_info);
1087 arg = default_function_array_read_conversion (location, arg);
1088 if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
1089 arg.value = build_unary_op (location, code, arg.value, 0);
1090 else if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
1091 arg = parser_build_unary_op (location, code, arg);
1093 loop_init = pop_stmt_list (loop_init);
1094 append_to_statement_list_force (loop_init, &loop_with_init);
1095 body = arg.value;
1097 for (ii = 0; ii < rank; ii++)
1099 tree new_loop = push_stmt_list ();
1100 add_stmt (an_loop_info[ii].ind_init);
1101 c_finish_loop (location, an_loop_info[ii].cmp,
1102 an_loop_info[ii].incr, body, NULL_TREE,
1103 NULL_TREE, true);
1104 body = pop_stmt_list (new_loop);
1106 append_to_statement_list_force (body, &loop_with_init);
1107 arg.value = loop_with_init;
1108 an_info.release ();
1109 an_loop_info.release ();
1110 return arg;
1113 /* Replaces array notations in a void function call arguments in ARG and returns
1114 a STATEMENT_LIST. */
1116 static tree
1117 fix_array_notation_call_expr (tree arg)
1119 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1120 tree new_var = NULL_TREE;
1121 size_t list_size = 0, rank = 0, ii = 0;
1122 tree loop_init;
1123 tree body, loop_with_init = alloc_stmt_list ();
1124 location_t location = UNKNOWN_LOCATION;
1125 vec<vec<an_parts> > an_info = vNULL;
1126 vec<an_loop_parts> an_loop_info = vNULL;
1128 if (TREE_CODE (arg) == CALL_EXPR
1129 && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg)))
1131 loop_init = fix_builtin_array_notation_fn (arg, &new_var);
1132 /* We are ignoring the new var because either the user does not want to
1133 capture it OR he is using sec_reduce_mutating function. */
1134 return loop_init;
1136 if (!find_rank (location, arg, arg, false, &rank))
1137 return error_mark_node;
1139 if (rank == 0)
1140 return arg;
1142 extract_array_notation_exprs (arg, true, &array_list);
1143 if (vec_safe_length (array_list) == 0)
1144 return arg;
1146 list_size = vec_safe_length (array_list);
1147 location = EXPR_LOCATION (arg);
1148 an_loop_info.safe_grow_cleared (rank);
1150 loop_init = push_stmt_list ();
1151 for (ii = 0; ii < list_size; ii++)
1152 if ((*array_list)[ii]
1153 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
1155 tree array_node = (*array_list)[ii];
1156 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
1157 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
1158 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
1160 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1161 if (length_mismatch_in_expr_p (location, an_info))
1163 pop_stmt_list (loop_init);
1164 return error_mark_node;
1166 for (ii = 0; ii < rank; ii++)
1168 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
1169 an_loop_info[ii].ind_init =
1170 build_modify_expr (location, an_loop_info[ii].var,
1171 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location,
1172 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1173 TREE_TYPE (an_loop_info[ii].var));
1176 array_operand = create_array_refs (location, an_info, an_loop_info,
1177 list_size, rank);
1178 replace_array_notations (&arg, true, array_list, array_operand);
1179 create_cmp_incr (location, &an_loop_info, rank, an_info);
1180 loop_init = pop_stmt_list (loop_init);
1181 append_to_statement_list_force (loop_init, &loop_with_init);
1182 body = arg;
1183 for (ii = 0; ii < rank; ii++)
1185 tree new_loop = push_stmt_list ();
1186 add_stmt (an_loop_info[ii].ind_init);
1187 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1188 body, NULL_TREE, NULL_TREE, true);
1189 body = pop_stmt_list (new_loop);
1191 append_to_statement_list_force (body, &loop_with_init);
1192 an_loop_info.release ();
1193 an_info.release ();
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 CALL_EXPR:
1259 *tp = fix_array_notation_call_expr (*tp);
1260 break;
1261 case RETURN_EXPR:
1262 *tp = fix_return_expr (*tp);
1263 break;
1264 case COMPOUND_EXPR:
1265 if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR)
1267 /* In here we are calling expand_array_notations because
1268 we need to be able to catch the return value and check if
1269 it is an error_mark_node. */
1270 expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL);
1272 /* SAVE_EXPR cannot have an error_mark_node inside it. This check
1273 will make sure that if there is an error in expanding of
1274 array notations (e.g. rank mismatch) then replace the entire
1275 SAVE_EXPR with an error_mark_node. */
1276 if (TREE_OPERAND (*tp, 1) == error_mark_node)
1277 *tp = error_mark_node;
1279 break;
1280 case ARRAY_NOTATION_REF:
1281 /* If we are here, then we are dealing with cases like this:
1282 A[:];
1283 A[x:y:z];
1284 A[x:y];
1285 Replace those with just void zero node. */
1286 *tp = void_node;
1287 default:
1288 break;
1290 return NULL_TREE;
1293 /* Walks through tree node T and expands all array notations in its subtrees.
1294 The return value is the same type as T but with all array notations
1295 replaced with appropriate ARRAY_REFS with a loop around it. */
1297 tree
1298 expand_array_notation_exprs (tree t)
1300 walk_tree (&t, expand_array_notations, NULL, NULL);
1301 return t;
1304 /* This handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which
1305 denotes an array notation expression. If a is a variable or a member, then
1306 we generate a ARRAY_NOTATION_REF front-end tree and return it.
1307 This tree is broken down to ARRAY_REF toward the end of parsing.
1308 ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE
1309 of ARRAY_REF. Restrictions on START_INDEX, LENGTH and STRIDE is same as that
1310 of the index field passed into ARRAY_REF. The only additional restriction
1311 is that, unlike index in ARRAY_REF, stride, length and start_index cannot
1312 contain ARRAY_NOTATIONS. */
1314 tree
1315 build_array_notation_ref (location_t loc, tree array, tree start_index,
1316 tree length, tree stride, tree type)
1318 tree array_ntn_tree = NULL_TREE;
1319 size_t stride_rank = 0, length_rank = 0, start_rank = 0;
1321 if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
1323 error_at (loc,
1324 "start-index of array notation triplet is not an integer");
1325 return error_mark_node;
1327 if (!INTEGRAL_TYPE_P (TREE_TYPE (length)))
1329 error_at (loc, "length of array notation triplet is not an integer");
1330 return error_mark_node;
1333 /* The stride is an optional field. */
1334 if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
1336 error_at (loc, "stride of array notation triplet is not an integer");
1337 return error_mark_node;
1339 if (!stride)
1341 if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length)
1342 && tree_int_cst_lt (length, start_index))
1343 stride = build_int_cst (TREE_TYPE (start_index), -1);
1344 else
1345 stride = build_int_cst (TREE_TYPE (start_index), 1);
1348 if (!find_rank (loc, start_index, start_index, false, &start_rank))
1349 return error_mark_node;
1350 if (!find_rank (loc, length, length, false, &length_rank))
1351 return error_mark_node;
1352 if (!find_rank (loc, stride, stride, false, &stride_rank))
1353 return error_mark_node;
1355 if (start_rank != 0)
1357 error_at (loc, "rank of an array notation triplet's start-index is not "
1358 "zero");
1359 return error_mark_node;
1361 if (length_rank != 0)
1363 error_at (loc, "rank of an array notation triplet's length is not zero");
1364 return error_mark_node;
1366 if (stride_rank != 0)
1368 error_at (loc, "rank of array notation triplet's stride is not zero");
1369 return error_mark_node;
1371 array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE,
1372 NULL_TREE, NULL_TREE);
1373 ARRAY_NOTATION_ARRAY (array_ntn_tree) = array;
1374 ARRAY_NOTATION_START (array_ntn_tree) = start_index;
1375 ARRAY_NOTATION_LENGTH (array_ntn_tree) = length;
1376 ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride;
1377 TREE_TYPE (array_ntn_tree) = type;
1379 return array_ntn_tree;