2014-04-14 Martin Jambor <mjambor@suse.cz>
[official-gcc.git] / gcc / c / c-array-notation.c
blob0ac6ba8e119c523c50828e2562d26074dec2aab1
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);
233 location = EXPR_LOCATION (an_builtin_fn);
235 if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank))
236 return error_mark_node;
238 if (rank == 0)
239 return an_builtin_fn;
240 else if (rank > 1
241 && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
242 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND))
244 error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot"
245 " have arrays with dimension greater than 1");
246 return error_mark_node;
249 extract_array_notation_exprs (func_parm, true, &array_list);
250 list_size = vec_safe_length (array_list);
251 switch (an_type)
253 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
254 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
255 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
256 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
257 new_var_type = TREE_TYPE ((*array_list)[0]);
258 break;
259 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
260 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
261 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
262 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
263 new_var_type = integer_type_node;
264 break;
265 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
266 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
267 new_var_type = integer_type_node;
268 break;
269 case BUILT_IN_CILKPLUS_SEC_REDUCE:
270 if (call_fn && identity_value)
271 new_var_type = TREE_TYPE ((*array_list)[0]);
272 break;
273 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
274 new_var_type = NULL_TREE;
275 break;
276 default:
277 gcc_unreachable ();
280 an_loop_info.safe_grow_cleared (rank);
281 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
282 loop_init = alloc_stmt_list ();
284 for (ii = 0; ii < rank; ii++)
286 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
287 an_loop_info[ii].ind_init =
288 build_modify_expr (location, an_loop_info[ii].var,
289 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
290 location,
291 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
292 TREE_TYPE (an_loop_info[ii].var));
294 array_operand = create_array_refs (location, an_info, an_loop_info,
295 list_size, rank);
296 replace_array_notations (&func_parm, true, array_list, array_operand);
298 create_cmp_incr (location, &an_loop_info, rank, an_info);
299 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
301 *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type);
302 gcc_assert (*new_var && *new_var != error_mark_node);
304 else
305 *new_var = NULL_TREE;
307 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
308 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
309 array_ind_value = build_decl (location, VAR_DECL, NULL_TREE,
310 TREE_TYPE (func_parm));
311 array_op0 = (*array_operand)[0];
312 switch (an_type)
314 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
315 new_var_init = build_modify_expr
316 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
317 location, build_zero_cst (new_var_type), new_var_type);
318 new_expr = build_modify_expr
319 (location, *new_var, TREE_TYPE (*new_var), PLUS_EXPR,
320 location, func_parm, TREE_TYPE (func_parm));
321 break;
322 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
323 new_var_init = build_modify_expr
324 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
325 location, build_one_cst (new_var_type), new_var_type);
326 new_expr = build_modify_expr
327 (location, *new_var, TREE_TYPE (*new_var), MULT_EXPR,
328 location, func_parm, TREE_TYPE (func_parm));
329 break;
330 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
331 new_var_init = build_modify_expr
332 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
333 location, build_one_cst (new_var_type), new_var_type);
334 /* Initially you assume everything is zero, now if we find a case where
335 it is NOT true, then we set the result to false. Otherwise
336 we just keep the previous value. */
337 new_yes_expr = build_modify_expr
338 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
339 location, build_zero_cst (TREE_TYPE (*new_var)),
340 TREE_TYPE (*new_var));
341 new_no_expr = build_modify_expr
342 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
343 location, *new_var, TREE_TYPE (*new_var));
344 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
345 build_zero_cst (TREE_TYPE (func_parm)));
346 new_expr = build_conditional_expr
347 (location, new_cond_expr, false, new_yes_expr,
348 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
349 break;
350 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
351 new_var_init = build_modify_expr
352 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
353 location, build_one_cst (new_var_type), new_var_type);
354 /* Initially you assume everything is non-zero, now if we find a case
355 where it is NOT true, then we set the result to false. Otherwise
356 we just keep the previous value. */
357 new_yes_expr = build_modify_expr
358 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
359 location, build_zero_cst (TREE_TYPE (*new_var)),
360 TREE_TYPE (*new_var));
361 new_no_expr = build_modify_expr
362 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
363 location, *new_var, TREE_TYPE (*new_var));
364 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
365 build_zero_cst (TREE_TYPE (func_parm)));
366 new_expr = build_conditional_expr
367 (location, new_cond_expr, false, new_yes_expr,
368 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
369 break;
370 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
371 new_var_init = build_modify_expr
372 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
373 location, build_zero_cst (new_var_type), new_var_type);
374 /* Initially we assume there are NO zeros in the list. When we find
375 a non-zero, we keep the previous value. If we find a zero, we
376 set the value to true. */
377 new_yes_expr = build_modify_expr
378 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
379 location, build_one_cst (new_var_type), new_var_type);
380 new_no_expr = build_modify_expr
381 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
382 location, *new_var, TREE_TYPE (*new_var));
383 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
384 build_zero_cst (TREE_TYPE (func_parm)));
385 new_expr = build_conditional_expr
386 (location, new_cond_expr, false, new_yes_expr,
387 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
388 break;
389 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
390 new_var_init = build_modify_expr
391 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
392 location, build_zero_cst (new_var_type), new_var_type);
393 /* Initially we assume there are NO non-zeros in the list. When we find
394 a zero, we keep the previous value. If we find a non-zero, we set
395 the value to true. */
396 new_yes_expr = build_modify_expr
397 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
398 location, build_one_cst (new_var_type), new_var_type);
399 new_no_expr = build_modify_expr
400 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
401 location, *new_var, TREE_TYPE (*new_var));
402 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
403 build_zero_cst (TREE_TYPE (func_parm)));
404 new_expr = build_conditional_expr
405 (location, new_cond_expr, false, new_yes_expr,
406 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
407 break;
408 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
409 if (TYPE_MIN_VALUE (new_var_type))
410 new_var_init = build_modify_expr
411 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
412 location, TYPE_MIN_VALUE (new_var_type), new_var_type);
413 else
414 new_var_init = build_modify_expr
415 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
416 location, func_parm, new_var_type);
417 new_no_expr = build_modify_expr
418 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
419 location, *new_var, TREE_TYPE (*new_var));
420 new_yes_expr = build_modify_expr
421 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
422 location, func_parm, TREE_TYPE (*new_var));
423 new_expr = build_conditional_expr
424 (location,
425 build2 (LT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
426 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
427 break;
428 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
429 if (TYPE_MAX_VALUE (new_var_type))
430 new_var_init = build_modify_expr
431 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
432 location, TYPE_MAX_VALUE (new_var_type), new_var_type);
433 else
434 new_var_init = build_modify_expr
435 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
436 location, func_parm, new_var_type);
437 new_no_expr = build_modify_expr
438 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
439 location, *new_var, TREE_TYPE (*new_var));
440 new_yes_expr = build_modify_expr
441 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
442 location, func_parm, TREE_TYPE (*new_var));
443 new_expr = build_conditional_expr
444 (location,
445 build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
446 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
447 break;
448 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
449 new_var_init = build_modify_expr
450 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
451 location, build_zero_cst (new_var_type), new_var_type);
452 new_exp_init = build_modify_expr
453 (location, array_ind_value, TREE_TYPE (array_ind_value),
454 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
455 new_no_ind = build_modify_expr
456 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
457 location, *new_var, TREE_TYPE (*new_var));
458 new_no_expr = build_modify_expr
459 (location, array_ind_value, TREE_TYPE (array_ind_value),
460 NOP_EXPR,
461 location, array_ind_value, TREE_TYPE (array_ind_value));
462 if (list_size > 1)
464 new_yes_ind = build_modify_expr
465 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
466 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
467 new_yes_expr = build_modify_expr
468 (location, array_ind_value, TREE_TYPE (array_ind_value),
469 NOP_EXPR,
470 location, func_parm, TREE_TYPE ((*array_operand)[0]));
472 else
474 new_yes_ind = build_modify_expr
475 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
476 location, TREE_OPERAND (array_op0, 1),
477 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
478 new_yes_expr = build_modify_expr
479 (location, array_ind_value, TREE_TYPE (array_ind_value),
480 NOP_EXPR,
481 location, func_parm, TREE_OPERAND (array_op0, 1));
483 new_yes_list = alloc_stmt_list ();
484 append_to_statement_list (new_yes_ind, &new_yes_list);
485 append_to_statement_list (new_yes_expr, &new_yes_list);
487 new_no_list = alloc_stmt_list ();
488 append_to_statement_list (new_no_ind, &new_no_list);
489 append_to_statement_list (new_no_expr, &new_no_list);
491 new_expr = build_conditional_expr
492 (location,
493 build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
494 func_parm),
495 false,
496 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
497 break;
498 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
499 new_var_init = build_modify_expr
500 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
501 location, build_zero_cst (new_var_type), new_var_type);
502 new_exp_init = build_modify_expr
503 (location, array_ind_value, TREE_TYPE (array_ind_value),
504 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
505 new_no_ind = build_modify_expr
506 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
507 location, *new_var, TREE_TYPE (*new_var));
508 new_no_expr = build_modify_expr
509 (location, array_ind_value, TREE_TYPE (array_ind_value),
510 NOP_EXPR,
511 location, array_ind_value, TREE_TYPE (array_ind_value));
512 if (list_size > 1)
514 new_yes_ind = build_modify_expr
515 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
516 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
517 new_yes_expr = build_modify_expr
518 (location, array_ind_value, TREE_TYPE (array_ind_value),
519 NOP_EXPR,
520 location, func_parm, TREE_TYPE (array_op0));
522 else
524 new_yes_ind = build_modify_expr
525 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
526 location, TREE_OPERAND (array_op0, 1),
527 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
528 new_yes_expr = build_modify_expr
529 (location, array_ind_value, TREE_TYPE (array_ind_value),
530 NOP_EXPR,
531 location, func_parm, TREE_OPERAND (array_op0, 1));
533 new_yes_list = alloc_stmt_list ();
534 append_to_statement_list (new_yes_ind, &new_yes_list);
535 append_to_statement_list (new_yes_expr, &new_yes_list);
537 new_no_list = alloc_stmt_list ();
538 append_to_statement_list (new_no_ind, &new_no_list);
539 append_to_statement_list (new_no_expr, &new_no_list);
541 new_expr = build_conditional_expr
542 (location,
543 build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
544 func_parm),
545 false,
546 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
547 break;
548 case BUILT_IN_CILKPLUS_SEC_REDUCE:
549 new_var_init = build_modify_expr
550 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
551 location, identity_value, new_var_type);
552 new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm);
553 new_expr = build_modify_expr
554 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
555 location, new_call_expr, TREE_TYPE (*new_var));
556 break;
557 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
558 new_expr = build_call_expr (call_fn, 2, identity_value, func_parm);
559 break;
560 default:
561 gcc_unreachable ();
562 break;
565 for (ii = 0; ii < rank; ii++)
566 append_to_statement_list (an_loop_info[ii].ind_init, &loop_init);
568 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
569 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
570 append_to_statement_list (new_exp_init, &loop_init);
571 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
572 append_to_statement_list (new_var_init, &loop_init);
574 append_to_statement_list_force (loop_init, &loop_with_init);
575 body = new_expr;
576 for (ii = 0; ii < rank; ii++)
578 tree new_loop = push_stmt_list ();
579 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
580 body, NULL_TREE, NULL_TREE, true);
581 body = pop_stmt_list (new_loop);
583 append_to_statement_list_force (body, &loop_with_init);
585 an_info.release ();
586 an_loop_info.release ();
588 return loop_with_init;
591 /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
592 The LHS and/or RHS will be array notation expressions that have a MODIFYCODE
593 Their locations are specified by LHS_LOC, RHS_LOC. The location of the
594 modify expression is location. The original type of LHS and RHS are passed
595 in LHS_ORIGTYPE and RHS_ORIGTYPE. */
597 tree
598 build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
599 enum tree_code modifycode, location_t rhs_loc,
600 tree rhs, tree rhs_origtype)
602 bool found_builtin_fn = false;
603 tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
604 tree array_expr = NULL_TREE;
605 tree an_init = NULL_TREE;
606 vec<tree> cond_expr = vNULL;
607 tree body, loop_with_init = alloc_stmt_list();
608 tree scalar_mods = NULL_TREE;
609 vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL;
610 size_t lhs_rank = 0, rhs_rank = 0;
611 size_t ii = 0;
612 vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL;
613 tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE;
614 size_t rhs_list_size = 0, lhs_list_size = 0;
615 vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
616 vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL;
618 /* If either of this is true, an error message must have been send out
619 already. Not necessary to send out multiple error messages. */
620 if (lhs == error_mark_node || rhs == error_mark_node)
621 return error_mark_node;
623 if (!find_rank (location, rhs, rhs, false, &rhs_rank))
624 return error_mark_node;
626 extract_array_notation_exprs (rhs, false, &rhs_list);
627 rhs_list_size = vec_safe_length (rhs_list);
628 an_init = push_stmt_list ();
629 if (rhs_rank)
631 scalar_mods = replace_invariant_exprs (&rhs);
632 if (scalar_mods)
633 add_stmt (scalar_mods);
635 for (ii = 0; ii < rhs_list_size; ii++)
637 tree rhs_node = (*rhs_list)[ii];
638 if (TREE_CODE (rhs_node) == CALL_EXPR)
640 builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
641 if (builtin_loop == error_mark_node)
643 pop_stmt_list (an_init);
644 return error_mark_node;
646 else if (builtin_loop)
648 add_stmt (builtin_loop);
649 found_builtin_fn = true;
650 if (new_var)
652 vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
653 vec_safe_push (rhs_sub_list, rhs_node);
654 vec_safe_push (new_var_list, new_var);
655 replace_array_notations (&rhs, false, rhs_sub_list,
656 new_var_list);
662 lhs_rank = 0;
663 rhs_rank = 0;
664 if (!find_rank (location, lhs, lhs, true, &lhs_rank))
666 pop_stmt_list (an_init);
667 return error_mark_node;
670 if (!find_rank (location, rhs, rhs, true, &rhs_rank))
672 pop_stmt_list (an_init);
673 return error_mark_node;
676 if (lhs_rank == 0 && rhs_rank == 0)
678 if (found_builtin_fn)
680 new_modify_expr = build_modify_expr (location, lhs, lhs_origtype,
681 modifycode, rhs_loc, rhs,
682 rhs_origtype);
683 add_stmt (new_modify_expr);
684 pop_stmt_list (an_init);
685 return an_init;
687 else
689 pop_stmt_list (an_init);
690 return NULL_TREE;
693 rhs_list_size = 0;
694 rhs_list = NULL;
695 extract_array_notation_exprs (rhs, true, &rhs_list);
696 extract_array_notation_exprs (lhs, true, &lhs_list);
697 rhs_list_size = vec_safe_length (rhs_list);
698 lhs_list_size = vec_safe_length (lhs_list);
700 if (lhs_rank == 0 && rhs_rank != 0)
702 tree rhs_base = rhs;
703 if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
705 for (ii = 0; ii < (size_t) rhs_rank; ii++)
706 rhs_base = ARRAY_NOTATION_ARRAY (rhs);
708 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
709 rhs_base);
710 return error_mark_node;
712 else
714 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
715 rhs_base);
716 return error_mark_node;
719 if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
721 error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
722 pop_stmt_list (an_init);
723 return error_mark_node;
726 /* Here we assign the array notation components to variable so that we can
727 satisfy the exec once rule. */
728 for (ii = 0; ii < lhs_list_size; ii++)
730 tree array_node = (*lhs_list)[ii];
731 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
732 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
733 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
735 for (ii = 0; ii < rhs_list_size; ii++)
736 if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
738 tree array_node = (*rhs_list)[ii];
739 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
740 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
741 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
744 cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
746 lhs_an_loop_info.safe_grow_cleared (lhs_rank);
747 if (rhs_rank)
748 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
750 cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
751 &lhs_an_info);
752 if (rhs_rank)
754 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
755 cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
756 &rhs_an_info);
758 if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
759 || (rhs_rank
760 && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info)))
762 pop_stmt_list (an_init);
763 return error_mark_node;
765 if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
766 && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST
767 && rhs_an_info[0][0].length
768 && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST)
770 HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length);
771 HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length);
772 /* Length can be negative or positive. As long as the magnitude is OK,
773 then the array notation is valid. */
774 if (absu_hwi (l_length) != absu_hwi (r_length))
776 error_at (location, "length mismatch between LHS and RHS");
777 pop_stmt_list (an_init);
778 return error_mark_node;
781 for (ii = 0; ii < lhs_rank; ii++)
782 if (lhs_an_info[0][ii].is_vector)
784 lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node,
785 NULL);
786 lhs_an_loop_info[ii].ind_init = build_modify_expr
787 (location, lhs_an_loop_info[ii].var,
788 TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR,
789 location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)),
790 TREE_TYPE (lhs_an_loop_info[ii].var));
792 for (ii = 0; ii < rhs_rank; ii++)
794 /* When we have a polynomial, we assume that the indices are of type
795 integer. */
796 rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node,
797 NULL);
798 rhs_an_loop_info[ii].ind_init = build_modify_expr
799 (location, rhs_an_loop_info[ii].var,
800 TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR,
801 location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0),
802 TREE_TYPE (rhs_an_loop_info[ii].var));
804 if (lhs_rank)
806 lhs_array_operand = create_array_refs
807 (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank);
808 replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
809 array_expr_lhs = lhs;
811 if (rhs_array_operand)
812 vec_safe_truncate (rhs_array_operand, 0);
813 if (rhs_rank)
815 rhs_array_operand = create_array_refs
816 (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank);
817 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
818 vec_safe_truncate (rhs_array_operand, 0);
819 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
820 rhs_an_loop_info, rhs_rank,
821 rhs);
822 if (!rhs_array_operand)
823 return error_mark_node;
824 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
826 else if (rhs_list_size > 0)
828 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
829 lhs_an_loop_info, lhs_rank,
830 lhs);
831 if (!rhs_array_operand)
832 return error_mark_node;
833 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
835 array_expr_lhs = lhs;
836 array_expr_rhs = rhs;
837 array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype,
838 modifycode, rhs_loc, array_expr_rhs,
839 rhs_origtype);
840 create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info);
841 if (rhs_rank)
842 create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info);
844 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
845 if (ii < lhs_rank && ii < rhs_rank)
846 cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node,
847 lhs_an_loop_info[ii].cmp,
848 rhs_an_loop_info[ii].cmp);
849 else if (ii < lhs_rank && ii >= rhs_rank)
850 cond_expr[ii] = lhs_an_loop_info[ii].cmp;
851 else
852 gcc_unreachable ();
854 an_init = pop_stmt_list (an_init);
855 append_to_statement_list_force (an_init, &loop_with_init);
856 body = array_expr;
857 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
859 tree incr_list = alloc_stmt_list ();
860 tree new_loop = push_stmt_list ();
861 if (lhs_rank)
862 add_stmt (lhs_an_loop_info[ii].ind_init);
863 if (rhs_rank)
864 add_stmt (rhs_an_loop_info[ii].ind_init);
865 if (lhs_rank)
866 append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list);
867 if (rhs_rank && rhs_an_loop_info[ii].incr)
868 append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list);
869 c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE,
870 NULL_TREE, true);
871 body = pop_stmt_list (new_loop);
873 append_to_statement_list_force (body, &loop_with_init);
875 lhs_an_info.release ();
876 lhs_an_loop_info.release ();
877 if (rhs_rank)
879 rhs_an_info.release ();
880 rhs_an_loop_info.release ();
882 cond_expr.release ();
883 return loop_with_init;
886 /* Helper function for fix_conditional_array_notations. Encloses the
887 conditional statement passed in STMT with a loop around it
888 and replaces the condition in STMT with a ARRAY_REF tree-node to the array.
889 The condition must have an ARRAY_NOTATION_REF tree. An expansion of array
890 notation in STMT is returned in a STATEMENT_LIST. */
892 static tree
893 fix_conditional_array_notations_1 (tree stmt)
895 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
896 size_t list_size = 0;
897 tree cond = NULL_TREE, builtin_loop = NULL_TREE, new_var = NULL_TREE;
898 size_t rank = 0, ii = 0;
899 tree loop_init;
900 location_t location = EXPR_LOCATION (stmt);
901 tree body = NULL_TREE, loop_with_init = alloc_stmt_list ();
902 vec<vec<an_parts> > an_info = vNULL;
903 vec<an_loop_parts> an_loop_info = vNULL;
905 if (TREE_CODE (stmt) == COND_EXPR)
906 cond = COND_EXPR_COND (stmt);
907 else if (TREE_CODE (stmt) == SWITCH_EXPR)
908 cond = SWITCH_COND (stmt);
909 else if (truth_value_p (TREE_CODE (stmt)))
910 cond = TREE_OPERAND (stmt, 0);
911 else
912 /* Otherwise dont even touch the statement. */
913 return stmt;
915 if (!find_rank (location, cond, cond, false, &rank))
916 return error_mark_node;
918 extract_array_notation_exprs (stmt, false, &array_list);
919 loop_init = push_stmt_list ();
920 for (ii = 0; ii < vec_safe_length (array_list); ii++)
922 tree array_node = (*array_list)[ii];
923 if (TREE_CODE (array_node) == CALL_EXPR)
925 builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var);
926 if (builtin_loop == error_mark_node)
928 add_stmt (error_mark_node);
929 pop_stmt_list (loop_init);
930 return loop_init;
932 else if (builtin_loop)
934 vec <tree, va_gc>* sub_list = NULL, *new_var_list = NULL;
935 vec_safe_push (sub_list, array_node);
936 vec_safe_push (new_var_list, new_var);
937 add_stmt (builtin_loop);
938 replace_array_notations (&stmt, false, sub_list, new_var_list);
942 if (!find_rank (location, stmt, stmt, true, &rank))
944 pop_stmt_list (loop_init);
945 return error_mark_node;
947 if (rank == 0)
949 add_stmt (stmt);
950 pop_stmt_list (loop_init);
951 return loop_init;
953 extract_array_notation_exprs (stmt, true, &array_list);
955 if (vec_safe_length (array_list) == 0)
956 return stmt;
958 list_size = vec_safe_length (array_list);
959 an_loop_info.safe_grow_cleared (rank);
961 for (ii = 0; ii < list_size; ii++)
962 if ((*array_list)[ii]
963 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
965 tree array_node = (*array_list)[ii];
966 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
967 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
968 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
970 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
971 for (ii = 0; ii < rank; ii++)
973 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
974 an_loop_info[ii].ind_init =
975 build_modify_expr (location, an_loop_info[ii].var,
976 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
977 location,
978 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
979 TREE_TYPE (an_loop_info[ii].var));
981 array_operand = create_array_refs (location, an_info, an_loop_info,
982 list_size, rank);
983 replace_array_notations (&stmt, true, array_list, array_operand);
984 create_cmp_incr (location, &an_loop_info, rank, an_info);
986 loop_init = pop_stmt_list (loop_init);
987 body = stmt;
988 append_to_statement_list_force (loop_init, &loop_with_init);
990 for (ii = 0; ii < rank; ii++)
992 tree new_loop = push_stmt_list ();
993 add_stmt (an_loop_info[ii].ind_init);
994 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
995 body, NULL_TREE, NULL_TREE, true);
996 body = pop_stmt_list (new_loop);
998 append_to_statement_list_force (body, &loop_with_init);
1000 an_loop_info.release ();
1001 an_info.release ();
1003 return loop_with_init;
1006 /* Top-level function to replace ARRAY_NOTATION_REF in a conditional statement
1007 in STMT. An expansion of array notation in STMT is returned as a
1008 STATEMENT_LIST. */
1010 tree
1011 fix_conditional_array_notations (tree stmt)
1013 if (TREE_CODE (stmt) == STATEMENT_LIST)
1015 tree_stmt_iterator tsi;
1016 for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi))
1018 tree single_stmt = *tsi_stmt_ptr (tsi);
1019 *tsi_stmt_ptr (tsi) =
1020 fix_conditional_array_notations_1 (single_stmt);
1022 return stmt;
1024 else
1025 return fix_conditional_array_notations_1 (stmt);
1028 /* Create a struct c_expr that contains a loop with ARRAY_REF expr at location
1029 LOCATION with the tree_code CODE and the array notation expr is
1030 passed in ARG. Returns the fixed c_expr in ARG itself. */
1032 struct c_expr
1033 fix_array_notation_expr (location_t location, enum tree_code code,
1034 struct c_expr arg)
1037 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1038 size_t list_size = 0, rank = 0, ii = 0;
1039 tree loop_init;
1040 tree body, loop_with_init = alloc_stmt_list ();
1041 vec<vec<an_parts> > an_info = vNULL;
1042 vec<an_loop_parts> an_loop_info = vNULL;
1044 if (!find_rank (location, arg.value, arg.value, false, &rank))
1046 /* If this function returns a NULL, we convert the tree value in the
1047 structure to error_mark_node and the parser should take care of the
1048 rest. */
1049 arg.value = error_mark_node;
1050 return arg;
1053 if (rank == 0)
1054 return arg;
1056 extract_array_notation_exprs (arg.value, true, &array_list);
1058 if (vec_safe_length (array_list) == 0)
1059 return arg;
1061 list_size = vec_safe_length (array_list);
1063 an_loop_info.safe_grow_cleared (rank);
1064 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1066 loop_init = push_stmt_list ();
1067 for (ii = 0; ii < rank; ii++)
1069 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
1070 an_loop_info[ii].ind_init =
1071 build_modify_expr (location, an_loop_info[ii].var,
1072 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
1073 location,
1074 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1075 TREE_TYPE (an_loop_info[ii].var));;
1078 array_operand = create_array_refs (location, an_info, an_loop_info,
1079 list_size, rank);
1080 replace_array_notations (&arg.value, true, array_list, array_operand);
1081 create_cmp_incr (location, &an_loop_info, rank, an_info);
1083 arg = default_function_array_read_conversion (location, arg);
1084 if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
1085 arg.value = build_unary_op (location, code, arg.value, 0);
1086 else if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
1087 arg = parser_build_unary_op (location, code, arg);
1089 loop_init = pop_stmt_list (loop_init);
1090 append_to_statement_list_force (loop_init, &loop_with_init);
1091 body = arg.value;
1093 for (ii = 0; ii < rank; ii++)
1095 tree new_loop = push_stmt_list ();
1096 add_stmt (an_loop_info[ii].ind_init);
1097 c_finish_loop (location, an_loop_info[ii].cmp,
1098 an_loop_info[ii].incr, body, NULL_TREE,
1099 NULL_TREE, true);
1100 body = pop_stmt_list (new_loop);
1102 append_to_statement_list_force (body, &loop_with_init);
1103 arg.value = loop_with_init;
1104 an_info.release ();
1105 an_loop_info.release ();
1106 return arg;
1109 /* Replaces array notations in a void function call arguments in ARG and returns
1110 a STATEMENT_LIST. */
1112 static tree
1113 fix_array_notation_call_expr (tree arg)
1115 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1116 tree new_var = NULL_TREE;
1117 size_t list_size = 0, rank = 0, ii = 0;
1118 tree loop_init;
1119 tree body, loop_with_init = alloc_stmt_list ();
1120 location_t location = UNKNOWN_LOCATION;
1121 vec<vec<an_parts> > an_info = vNULL;
1122 vec<an_loop_parts> an_loop_info = vNULL;
1124 if (TREE_CODE (arg) == CALL_EXPR
1125 && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg)))
1127 loop_init = fix_builtin_array_notation_fn (arg, &new_var);
1128 /* We are ignoring the new var because either the user does not want to
1129 capture it OR he is using sec_reduce_mutating function. */
1130 return loop_init;
1132 if (!find_rank (location, arg, arg, false, &rank))
1133 return error_mark_node;
1135 if (rank == 0)
1136 return arg;
1138 extract_array_notation_exprs (arg, true, &array_list);
1139 if (vec_safe_length (array_list) == 0)
1140 return arg;
1142 list_size = vec_safe_length (array_list);
1143 location = EXPR_LOCATION (arg);
1144 an_loop_info.safe_grow_cleared (rank);
1146 loop_init = push_stmt_list ();
1147 for (ii = 0; ii < list_size; ii++)
1148 if ((*array_list)[ii]
1149 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
1151 tree array_node = (*array_list)[ii];
1152 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
1153 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
1154 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
1156 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1157 if (length_mismatch_in_expr_p (location, an_info))
1159 pop_stmt_list (loop_init);
1160 return error_mark_node;
1162 for (ii = 0; ii < rank; ii++)
1164 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
1165 an_loop_info[ii].ind_init =
1166 build_modify_expr (location, an_loop_info[ii].var,
1167 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location,
1168 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1169 TREE_TYPE (an_loop_info[ii].var));
1172 array_operand = create_array_refs (location, an_info, an_loop_info,
1173 list_size, rank);
1174 replace_array_notations (&arg, true, array_list, array_operand);
1175 create_cmp_incr (location, &an_loop_info, rank, an_info);
1176 loop_init = pop_stmt_list (loop_init);
1177 append_to_statement_list_force (loop_init, &loop_with_init);
1178 body = arg;
1179 for (ii = 0; ii < rank; ii++)
1181 tree new_loop = push_stmt_list ();
1182 add_stmt (an_loop_info[ii].ind_init);
1183 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1184 body, NULL_TREE, NULL_TREE, true);
1185 body = pop_stmt_list (new_loop);
1187 append_to_statement_list_force (body, &loop_with_init);
1188 an_loop_info.release ();
1189 an_info.release ();
1190 return loop_with_init;
1193 /* Expands the built-in functions in a return. EXPR is a RETURN_EXPR with
1194 a built-in reduction function. This function returns the expansion code for
1195 the built-in function. */
1197 static tree
1198 fix_return_expr (tree expr)
1200 tree new_mod_list, new_var, new_mod, retval_expr, retval_type;
1201 location_t loc = EXPR_LOCATION (expr);
1203 new_mod_list = alloc_stmt_list ();
1204 retval_expr = TREE_OPERAND (expr, 0);
1205 retval_type = TREE_TYPE (TREE_OPERAND (retval_expr, 1));
1206 new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr));
1207 new_mod = build_array_notation_expr (loc, new_var, TREE_TYPE (new_var),
1208 NOP_EXPR, loc,
1209 TREE_OPERAND (retval_expr, 1),
1210 retval_type);
1211 TREE_OPERAND (retval_expr, 1) = new_var;
1212 TREE_OPERAND (expr, 0) = retval_expr;
1213 append_to_statement_list_force (new_mod, &new_mod_list);
1214 append_to_statement_list_force (expr, &new_mod_list);
1215 return new_mod_list;
1218 /* Callback for walk_tree. Expands all array notations in *TP. *WALK_SUBTREES
1219 is set to 1 unless *TP contains no array notation expressions. */
1221 static tree
1222 expand_array_notations (tree *tp, int *walk_subtrees, void *)
1224 if (!contains_array_notation_expr (*tp))
1226 *walk_subtrees = 0;
1227 return NULL_TREE;
1229 *walk_subtrees = 1;
1231 switch (TREE_CODE (*tp))
1233 case TRUTH_ORIF_EXPR:
1234 case TRUTH_ANDIF_EXPR:
1235 case TRUTH_OR_EXPR:
1236 case TRUTH_AND_EXPR:
1237 case TRUTH_XOR_EXPR:
1238 case TRUTH_NOT_EXPR:
1239 case COND_EXPR:
1240 *tp = fix_conditional_array_notations (*tp);
1241 break;
1242 case MODIFY_EXPR:
1244 location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) :
1245 UNKNOWN_LOCATION;
1246 tree lhs = TREE_OPERAND (*tp, 0);
1247 tree rhs = TREE_OPERAND (*tp, 1);
1248 location_t rhs_loc = EXPR_HAS_LOCATION (rhs) ? EXPR_LOCATION (rhs) :
1249 UNKNOWN_LOCATION;
1250 *tp = build_array_notation_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR,
1251 rhs_loc, rhs, TREE_TYPE (rhs));
1253 break;
1254 case CALL_EXPR:
1255 *tp = fix_array_notation_call_expr (*tp);
1256 break;
1257 case RETURN_EXPR:
1258 *tp = fix_return_expr (*tp);
1259 break;
1260 case COMPOUND_EXPR:
1261 if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR)
1263 /* In here we are calling expand_array_notations because
1264 we need to be able to catch the return value and check if
1265 it is an error_mark_node. */
1266 expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL);
1268 /* SAVE_EXPR cannot have an error_mark_node inside it. This check
1269 will make sure that if there is an error in expanding of
1270 array notations (e.g. rank mismatch) then replace the entire
1271 SAVE_EXPR with an error_mark_node. */
1272 if (TREE_OPERAND (*tp, 1) == error_mark_node)
1273 *tp = error_mark_node;
1275 break;
1276 case ARRAY_NOTATION_REF:
1277 /* If we are here, then we are dealing with cases like this:
1278 A[:];
1279 A[x:y:z];
1280 A[x:y];
1281 Replace those with just void zero node. */
1282 *tp = void_zero_node;
1283 default:
1284 break;
1286 return NULL_TREE;
1289 /* Walks through tree node T and expands all array notations in its subtrees.
1290 The return value is the same type as T but with all array notations
1291 replaced with appropriate ARRAY_REFS with a loop around it. */
1293 tree
1294 expand_array_notation_exprs (tree t)
1296 walk_tree (&t, expand_array_notations, NULL, NULL);
1297 return t;
1300 /* This handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which
1301 denotes an array notation expression. If a is a variable or a member, then
1302 we generate a ARRAY_NOTATION_REF front-end tree and return it.
1303 This tree is broken down to ARRAY_REF toward the end of parsing.
1304 ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE
1305 of ARRAY_REF. Restrictions on START_INDEX, LENGTH and STRIDE is same as that
1306 of the index field passed into ARRAY_REF. The only additional restriction
1307 is that, unlike index in ARRAY_REF, stride, length and start_index cannot
1308 contain ARRAY_NOTATIONS. */
1310 tree
1311 build_array_notation_ref (location_t loc, tree array, tree start_index,
1312 tree length, tree stride, tree type)
1314 tree array_ntn_tree = NULL_TREE;
1315 size_t stride_rank = 0, length_rank = 0, start_rank = 0;
1317 if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
1319 error_at (loc,
1320 "start-index of array notation triplet is not an integer");
1321 return error_mark_node;
1323 if (!INTEGRAL_TYPE_P (TREE_TYPE (length)))
1325 error_at (loc, "length of array notation triplet is not an integer");
1326 return error_mark_node;
1329 /* The stride is an optional field. */
1330 if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
1332 error_at (loc, "stride of array notation triplet is not an integer");
1333 return error_mark_node;
1335 if (!stride)
1337 if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length)
1338 && tree_int_cst_lt (length, start_index))
1339 stride = build_int_cst (TREE_TYPE (start_index), -1);
1340 else
1341 stride = build_int_cst (TREE_TYPE (start_index), 1);
1344 if (!find_rank (loc, start_index, start_index, false, &start_rank))
1345 return error_mark_node;
1346 if (!find_rank (loc, length, length, false, &length_rank))
1347 return error_mark_node;
1348 if (!find_rank (loc, stride, stride, false, &stride_rank))
1349 return error_mark_node;
1351 if (start_rank != 0)
1353 error_at (loc, "rank of an array notation triplet's start-index is not "
1354 "zero");
1355 return error_mark_node;
1357 if (length_rank != 0)
1359 error_at (loc, "rank of an array notation triplet's length is not zero");
1360 return error_mark_node;
1362 if (stride_rank != 0)
1364 error_at (loc, "rank of array notation triplet's stride is not zero");
1365 return error_mark_node;
1367 array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE,
1368 NULL_TREE, NULL_TREE);
1369 ARRAY_NOTATION_ARRAY (array_ntn_tree) = array;
1370 ARRAY_NOTATION_START (array_ntn_tree) = start_index;
1371 ARRAY_NOTATION_LENGTH (array_ntn_tree) = length;
1372 ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride;
1373 TREE_TYPE (array_ntn_tree) = type;
1375 return array_ntn_tree;