2015-05-05 Yvan Roux <yvan.roux@linaro.org>
[official-gcc.git] / gcc / c / c-array-notation.c
blobc77e751d0933c7d6497a4a198ab999c67e887596
1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2 This file contains routines to handle Array Notation expression
3 handling routines in the C Compiler.
4 Copyright (C) 2013-2015 Free Software Foundation, Inc.
5 Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
6 Intel Corporation.
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 "hash-set.h"
72 #include "vec.h"
73 #include "symtab.h"
74 #include "input.h"
75 #include "alias.h"
76 #include "double-int.h"
77 #include "machmode.h"
78 #include "flags.h"
79 #include "inchash.h"
80 #include "tree.h"
81 #include "c-tree.h"
82 #include "gimple-expr.h"
83 #include "tree-iterator.h"
84 #include "opts.h"
85 #include "c-family/c-common.h"
87 /* If *VALUE is not of type INTEGER_CST, PARM_DECL or VAR_DECL, then map it
88 to a variable and then set *VALUE to the new variable. */
90 static inline void
91 make_triplet_val_inv (location_t loc, tree *value)
93 tree var, new_exp;
94 if (TREE_CODE (*value) != INTEGER_CST
95 && TREE_CODE (*value) != PARM_DECL
96 && TREE_CODE (*value) != VAR_DECL)
98 var = build_decl (loc, VAR_DECL, NULL_TREE, integer_type_node);
99 new_exp = build_modify_expr (loc, var, TREE_TYPE (var), NOP_EXPR, loc,
100 *value, TREE_TYPE (*value));
101 add_stmt (new_exp);
102 *value = var;
106 /* Populates the INCR and CMP vectors with the increment (of type POSTINCREMENT
107 or POSTDECREMENT) and comparison (of TYPE GT_EXPR or LT_EXPR) expressions,
108 using data from LENGTH, COUNT_DOWN, and VAR. INCR and CMP vectors are of
109 size RANK. */
111 static void
112 create_cmp_incr (location_t loc, vec<an_loop_parts> *node, size_t rank,
113 vec<vec<an_parts> > an_info)
115 for (size_t ii = 0; ii < rank; ii++)
117 tree var = (*node)[ii].var;
118 tree length = an_info[0][ii].length;
119 (*node)[ii].incr = build_unary_op (loc, POSTINCREMENT_EXPR, var, 0);
120 (*node)[ii].cmp = build2 (LT_EXPR, boolean_type_node, var, length);
124 /* Returns a vector of size RANK that contains an array ref that is derived from
125 array notation triplet parameters stored in VALUE, START, STRIDE. IS_VECTOR
126 is used to check if the data stored at its corresponding location is an
127 array notation. VAR is the induction variable passed in by the caller.
129 For example: For an array notation A[5:10:2], the vector start will be
130 of size 1 holding '5', stride of same size as start but holding the value of
131 as 2, is_vector as true and count_down as false. Let's assume VAR is 'x'
132 This function returns a vector of size 1 with the following data:
133 A[5 + (x * 2)] .
136 static vec<tree, va_gc> *
137 create_array_refs (location_t loc, vec<vec<an_parts> > an_info,
138 vec<an_loop_parts> an_loop_info, size_t size, size_t rank)
140 tree ind_mult, ind_incr;
141 vec<tree, va_gc> *array_operand = NULL;
142 for (size_t ii = 0; ii < size; ii++)
143 if (an_info[ii][0].is_vector)
145 tree array_opr = an_info[ii][rank - 1].value;
146 for (int s_jj = rank - 1; s_jj >= 0; s_jj--)
148 tree var = an_loop_info[s_jj].var;
149 tree stride = an_info[ii][s_jj].stride;
150 tree start = an_info[ii][s_jj].start;
151 ind_mult = build2 (MULT_EXPR, TREE_TYPE (var), var, stride);
152 ind_incr = build2 (PLUS_EXPR, TREE_TYPE (var), start, ind_mult);
153 array_opr = build_array_ref (loc, array_opr, ind_incr);
155 vec_safe_push (array_operand, array_opr);
157 else
158 /* This is just a dummy node to make sure both the list sizes for both
159 array list and array operand list are the same. */
160 vec_safe_push (array_operand, integer_one_node);
161 return array_operand;
164 /* Replaces all the scalar expressions in *NODE. Returns a STATEMENT_LIST that
165 holds the NODE along with variables that holds the results of the invariant
166 expressions. */
168 tree
169 replace_invariant_exprs (tree *node)
171 size_t ix = 0;
172 tree node_list = NULL_TREE;
173 tree t = NULL_TREE, new_var = NULL_TREE, new_node;
174 struct inv_list data;
176 data.list_values = NULL;
177 data.replacement = NULL;
178 data.additional_tcodes = NULL;
179 walk_tree (node, find_inv_trees, (void *)&data, NULL);
181 if (vec_safe_length (data.list_values))
183 node_list = push_stmt_list ();
184 for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++)
186 new_var = build_decl (EXPR_LOCATION (t), VAR_DECL, NULL_TREE,
187 TREE_TYPE (t));
188 gcc_assert (new_var != NULL_TREE && new_var != error_mark_node);
189 new_node = build2 (MODIFY_EXPR, TREE_TYPE (t), new_var, t);
190 add_stmt (new_node);
191 vec_safe_push (data.replacement, new_var);
193 walk_tree (node, replace_inv_trees, (void *)&data, NULL);
194 node_list = pop_stmt_list (node_list);
196 return node_list;
199 /* Given a CALL_EXPR to an array notation built-in function in
200 AN_BUILTIN_FN, replace the call with the appropriate loop and
201 computation. Return the computation in *NEW_VAR.
203 The return value in *NEW_VAR will always be a scalar. If the
204 built-in is __sec_reduce_mutating, *NEW_VAR is set to NULL_TREE. */
206 static tree
207 fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var)
209 tree new_var_type = NULL_TREE, func_parm, new_expr, new_yes_expr, new_no_expr;
210 tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list;
211 tree new_yes_list, new_cond_expr, new_var_init = NULL_TREE;
212 tree new_exp_init = NULL_TREE;
213 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
214 size_t list_size = 0, rank = 0, ii = 0;
215 tree loop_init, array_op0;
216 tree identity_value = NULL_TREE, call_fn = NULL_TREE, new_call_expr, body;
217 location_t location = UNKNOWN_LOCATION;
218 tree loop_with_init = alloc_stmt_list ();
219 vec<vec<an_parts> > an_info = vNULL;
220 vec<an_loop_parts> an_loop_info = vNULL;
221 enum built_in_function an_type =
222 is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn));
223 if (an_type == BUILT_IN_NONE)
224 return NULL_TREE;
226 /* Builtin call should contain at least one argument. */
227 if (call_expr_nargs (an_builtin_fn) == 0)
229 error_at (EXPR_LOCATION (an_builtin_fn), "Invalid builtin arguments");
230 return error_mark_node;
233 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE
234 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
236 call_fn = CALL_EXPR_ARG (an_builtin_fn, 2);
237 if (TREE_CODE (call_fn) == ADDR_EXPR)
238 call_fn = TREE_OPERAND (call_fn, 0);
239 identity_value = CALL_EXPR_ARG (an_builtin_fn, 0);
240 func_parm = CALL_EXPR_ARG (an_builtin_fn, 1);
242 else
243 func_parm = CALL_EXPR_ARG (an_builtin_fn, 0);
245 /* Fully fold any EXCESSIVE_PRECISION EXPR that can occur in the function
246 parameter. */
247 func_parm = c_fully_fold (func_parm, false, NULL);
248 if (func_parm == error_mark_node)
249 return error_mark_node;
251 location = EXPR_LOCATION (an_builtin_fn);
253 if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank))
254 return error_mark_node;
256 if (rank == 0)
258 error_at (location, "Invalid builtin arguments");
259 return error_mark_node;
261 else if (rank > 1
262 && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
263 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND))
265 error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot"
266 " have arrays with dimension greater than 1");
267 return error_mark_node;
270 extract_array_notation_exprs (func_parm, true, &array_list);
271 list_size = vec_safe_length (array_list);
272 switch (an_type)
274 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
275 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
276 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
277 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
278 new_var_type = TREE_TYPE ((*array_list)[0]);
279 break;
280 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
281 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
282 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
283 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
284 new_var_type = integer_type_node;
285 break;
286 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
287 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
288 new_var_type = integer_type_node;
289 break;
290 case BUILT_IN_CILKPLUS_SEC_REDUCE:
291 if (call_fn && identity_value)
292 new_var_type = TREE_TYPE ((*array_list)[0]);
293 break;
294 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
295 new_var_type = NULL_TREE;
296 break;
297 default:
298 gcc_unreachable ();
301 an_loop_info.safe_grow_cleared (rank);
302 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
303 loop_init = alloc_stmt_list ();
305 for (ii = 0; ii < rank; ii++)
307 an_loop_info[ii].var = create_tmp_var (integer_type_node);
308 an_loop_info[ii].ind_init =
309 build_modify_expr (location, an_loop_info[ii].var,
310 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
311 location,
312 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
313 TREE_TYPE (an_loop_info[ii].var));
315 array_operand = create_array_refs (location, an_info, an_loop_info,
316 list_size, rank);
317 replace_array_notations (&func_parm, true, array_list, array_operand);
319 create_cmp_incr (location, &an_loop_info, rank, an_info);
320 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
322 *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type);
323 gcc_assert (*new_var && *new_var != error_mark_node);
325 else
326 *new_var = NULL_TREE;
328 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
329 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
330 array_ind_value = build_decl (location, VAR_DECL, NULL_TREE,
331 TREE_TYPE (func_parm));
332 array_op0 = (*array_operand)[0];
333 if (TREE_CODE (array_op0) == INDIRECT_REF)
334 array_op0 = TREE_OPERAND (array_op0, 0);
335 switch (an_type)
337 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
338 new_var_init = build_modify_expr
339 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
340 location, build_zero_cst (new_var_type), new_var_type);
341 new_expr = build_modify_expr
342 (location, *new_var, TREE_TYPE (*new_var), PLUS_EXPR,
343 location, func_parm, TREE_TYPE (func_parm));
344 break;
345 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
346 new_var_init = build_modify_expr
347 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
348 location, build_one_cst (new_var_type), new_var_type);
349 new_expr = build_modify_expr
350 (location, *new_var, TREE_TYPE (*new_var), MULT_EXPR,
351 location, func_parm, TREE_TYPE (func_parm));
352 break;
353 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
354 new_var_init = build_modify_expr
355 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
356 location, build_one_cst (new_var_type), new_var_type);
357 /* Initially you assume everything is zero, now if we find a case where
358 it is NOT true, then we set the result to false. Otherwise
359 we just keep the previous value. */
360 new_yes_expr = build_modify_expr
361 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
362 location, build_zero_cst (TREE_TYPE (*new_var)),
363 TREE_TYPE (*new_var));
364 new_no_expr = build_modify_expr
365 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
366 location, *new_var, TREE_TYPE (*new_var));
367 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
368 build_zero_cst (TREE_TYPE (func_parm)));
369 new_expr = build_conditional_expr
370 (location, new_cond_expr, false, new_yes_expr,
371 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
372 break;
373 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
374 new_var_init = build_modify_expr
375 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
376 location, build_one_cst (new_var_type), new_var_type);
377 /* Initially you assume everything is non-zero, now if we find a case
378 where it is NOT true, then we set the result to false. Otherwise
379 we just keep the previous value. */
380 new_yes_expr = build_modify_expr
381 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
382 location, build_zero_cst (TREE_TYPE (*new_var)),
383 TREE_TYPE (*new_var));
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_ZERO:
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 zeros in the list. When we find
398 a non-zero, we keep the previous value. If we find a zero, we
399 set 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 (EQ_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_ANY_NONZERO:
413 new_var_init = build_modify_expr
414 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
415 location, build_zero_cst (new_var_type), new_var_type);
416 /* Initially we assume there are NO non-zeros in the list. When we find
417 a zero, we keep the previous value. If we find a non-zero, we set
418 the value to true. */
419 new_yes_expr = build_modify_expr
420 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
421 location, build_one_cst (new_var_type), new_var_type);
422 new_no_expr = build_modify_expr
423 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
424 location, *new_var, TREE_TYPE (*new_var));
425 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
426 build_zero_cst (TREE_TYPE (func_parm)));
427 new_expr = build_conditional_expr
428 (location, new_cond_expr, false, new_yes_expr,
429 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
430 break;
431 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
432 if (TYPE_MIN_VALUE (new_var_type))
433 new_var_init = build_modify_expr
434 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
435 location, TYPE_MIN_VALUE (new_var_type), new_var_type);
436 else
437 new_var_init = build_modify_expr
438 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
439 location, func_parm, new_var_type);
440 new_no_expr = build_modify_expr
441 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
442 location, *new_var, TREE_TYPE (*new_var));
443 new_yes_expr = build_modify_expr
444 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
445 location, func_parm, TREE_TYPE (*new_var));
446 new_expr = build_conditional_expr
447 (location,
448 build2 (LT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
449 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
450 break;
451 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
452 if (TYPE_MAX_VALUE (new_var_type))
453 new_var_init = build_modify_expr
454 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
455 location, TYPE_MAX_VALUE (new_var_type), new_var_type);
456 else
457 new_var_init = build_modify_expr
458 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
459 location, func_parm, new_var_type);
460 new_no_expr = build_modify_expr
461 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
462 location, *new_var, TREE_TYPE (*new_var));
463 new_yes_expr = build_modify_expr
464 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
465 location, func_parm, TREE_TYPE (*new_var));
466 new_expr = build_conditional_expr
467 (location,
468 build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
469 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
470 break;
471 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
472 new_var_init = build_modify_expr
473 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
474 location, build_zero_cst (new_var_type), new_var_type);
475 new_exp_init = build_modify_expr
476 (location, array_ind_value, TREE_TYPE (array_ind_value),
477 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
478 new_no_ind = build_modify_expr
479 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
480 location, *new_var, TREE_TYPE (*new_var));
481 new_no_expr = build_modify_expr
482 (location, array_ind_value, TREE_TYPE (array_ind_value),
483 NOP_EXPR,
484 location, array_ind_value, TREE_TYPE (array_ind_value));
485 if (list_size > 1)
487 new_yes_ind = build_modify_expr
488 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
489 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
490 new_yes_expr = build_modify_expr
491 (location, array_ind_value, TREE_TYPE (array_ind_value),
492 NOP_EXPR,
493 location, func_parm, TREE_TYPE ((*array_operand)[0]));
495 else
497 new_yes_ind = build_modify_expr
498 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
499 location, TREE_OPERAND (array_op0, 1),
500 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
501 new_yes_expr = build_modify_expr
502 (location, array_ind_value, TREE_TYPE (array_ind_value),
503 NOP_EXPR,
504 location, func_parm, TREE_OPERAND (array_op0, 1));
506 new_yes_list = alloc_stmt_list ();
507 append_to_statement_list (new_yes_ind, &new_yes_list);
508 append_to_statement_list (new_yes_expr, &new_yes_list);
510 new_no_list = alloc_stmt_list ();
511 append_to_statement_list (new_no_ind, &new_no_list);
512 append_to_statement_list (new_no_expr, &new_no_list);
514 new_expr = build_conditional_expr
515 (location,
516 build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
517 func_parm),
518 false,
519 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
520 break;
521 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
522 new_var_init = build_modify_expr
523 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
524 location, build_zero_cst (new_var_type), new_var_type);
525 new_exp_init = build_modify_expr
526 (location, array_ind_value, TREE_TYPE (array_ind_value),
527 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
528 new_no_ind = build_modify_expr
529 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
530 location, *new_var, TREE_TYPE (*new_var));
531 new_no_expr = build_modify_expr
532 (location, array_ind_value, TREE_TYPE (array_ind_value),
533 NOP_EXPR,
534 location, array_ind_value, TREE_TYPE (array_ind_value));
535 if (list_size > 1)
537 new_yes_ind = build_modify_expr
538 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
539 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
540 new_yes_expr = build_modify_expr
541 (location, array_ind_value, TREE_TYPE (array_ind_value),
542 NOP_EXPR,
543 location, func_parm, TREE_TYPE (array_op0));
545 else
547 new_yes_ind = build_modify_expr
548 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
549 location, TREE_OPERAND (array_op0, 1),
550 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
551 new_yes_expr = build_modify_expr
552 (location, array_ind_value, TREE_TYPE (array_ind_value),
553 NOP_EXPR,
554 location, func_parm, TREE_OPERAND (array_op0, 1));
556 new_yes_list = alloc_stmt_list ();
557 append_to_statement_list (new_yes_ind, &new_yes_list);
558 append_to_statement_list (new_yes_expr, &new_yes_list);
560 new_no_list = alloc_stmt_list ();
561 append_to_statement_list (new_no_ind, &new_no_list);
562 append_to_statement_list (new_no_expr, &new_no_list);
564 new_expr = build_conditional_expr
565 (location,
566 build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
567 func_parm),
568 false,
569 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
570 break;
571 case BUILT_IN_CILKPLUS_SEC_REDUCE:
572 new_var_init = build_modify_expr
573 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
574 location, identity_value, new_var_type);
575 new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm);
576 new_expr = build_modify_expr
577 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
578 location, new_call_expr, TREE_TYPE (*new_var));
579 break;
580 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
581 new_expr = build_call_expr (call_fn, 2, identity_value, func_parm);
582 break;
583 default:
584 gcc_unreachable ();
585 break;
588 for (ii = 0; ii < rank; ii++)
589 append_to_statement_list (an_loop_info[ii].ind_init, &loop_init);
591 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
592 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
593 append_to_statement_list (new_exp_init, &loop_init);
594 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
595 append_to_statement_list (new_var_init, &loop_init);
597 append_to_statement_list_force (loop_init, &loop_with_init);
598 body = new_expr;
599 for (ii = 0; ii < rank; ii++)
601 tree new_loop = push_stmt_list ();
602 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
603 body, NULL_TREE, NULL_TREE, true);
604 body = pop_stmt_list (new_loop);
606 append_to_statement_list_force (body, &loop_with_init);
608 an_info.release ();
609 an_loop_info.release ();
611 return loop_with_init;
614 /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
615 The LHS and/or RHS will be array notation expressions that have a MODIFYCODE
616 Their locations are specified by LHS_LOC, RHS_LOC. The location of the
617 modify expression is location. The original type of LHS and RHS are passed
618 in LHS_ORIGTYPE and RHS_ORIGTYPE. */
620 tree
621 build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
622 enum tree_code modifycode, location_t rhs_loc,
623 tree rhs, tree rhs_origtype)
625 bool found_builtin_fn = false;
626 tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
627 tree array_expr = NULL_TREE;
628 tree an_init = NULL_TREE;
629 vec<tree> cond_expr = vNULL;
630 tree body, loop_with_init = alloc_stmt_list();
631 tree scalar_mods = NULL_TREE;
632 vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL;
633 size_t lhs_rank = 0, rhs_rank = 0;
634 size_t ii = 0;
635 vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL;
636 tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE;
637 size_t rhs_list_size = 0, lhs_list_size = 0;
638 vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
639 vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL;
641 /* If either of this is true, an error message must have been send out
642 already. Not necessary to send out multiple error messages. */
643 if (lhs == error_mark_node || rhs == error_mark_node)
644 return error_mark_node;
646 if (!find_rank (location, rhs, rhs, false, &rhs_rank))
647 return error_mark_node;
649 extract_array_notation_exprs (rhs, false, &rhs_list);
650 rhs_list_size = vec_safe_length (rhs_list);
651 an_init = push_stmt_list ();
652 if (rhs_rank)
654 scalar_mods = replace_invariant_exprs (&rhs);
655 if (scalar_mods)
656 add_stmt (scalar_mods);
658 for (ii = 0; ii < rhs_list_size; ii++)
660 tree rhs_node = (*rhs_list)[ii];
661 if (TREE_CODE (rhs_node) == CALL_EXPR)
663 builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
664 if (builtin_loop == error_mark_node)
666 pop_stmt_list (an_init);
667 return error_mark_node;
669 else if (builtin_loop)
671 add_stmt (builtin_loop);
672 found_builtin_fn = true;
673 if (new_var)
675 vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
676 vec_safe_push (rhs_sub_list, rhs_node);
677 vec_safe_push (new_var_list, new_var);
678 replace_array_notations (&rhs, false, rhs_sub_list,
679 new_var_list);
685 lhs_rank = 0;
686 rhs_rank = 0;
687 if (!find_rank (location, lhs, lhs, true, &lhs_rank))
689 pop_stmt_list (an_init);
690 return error_mark_node;
693 if (!find_rank (location, rhs, rhs, true, &rhs_rank))
695 pop_stmt_list (an_init);
696 return error_mark_node;
699 if (lhs_rank == 0 && rhs_rank == 0)
701 if (found_builtin_fn)
703 new_modify_expr = build_modify_expr (location, lhs, lhs_origtype,
704 modifycode, rhs_loc, rhs,
705 rhs_origtype);
706 add_stmt (new_modify_expr);
707 pop_stmt_list (an_init);
708 return an_init;
710 else
712 pop_stmt_list (an_init);
713 return NULL_TREE;
716 rhs_list_size = 0;
717 rhs_list = NULL;
718 extract_array_notation_exprs (rhs, true, &rhs_list);
719 extract_array_notation_exprs (lhs, true, &lhs_list);
720 rhs_list_size = vec_safe_length (rhs_list);
721 lhs_list_size = vec_safe_length (lhs_list);
723 if (lhs_rank == 0 && rhs_rank != 0)
725 tree rhs_base = rhs;
726 if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
728 for (ii = 0; ii < (size_t) rhs_rank; ii++)
729 rhs_base = ARRAY_NOTATION_ARRAY (rhs);
731 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
732 rhs_base);
733 return error_mark_node;
735 else
737 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
738 rhs_base);
739 return error_mark_node;
742 if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
744 error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
745 pop_stmt_list (an_init);
746 return error_mark_node;
749 /* Here we assign the array notation components to variable so that we can
750 satisfy the exec once rule. */
751 for (ii = 0; ii < lhs_list_size; ii++)
753 tree array_node = (*lhs_list)[ii];
754 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
755 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
756 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
758 for (ii = 0; ii < rhs_list_size; ii++)
759 if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
761 tree array_node = (*rhs_list)[ii];
762 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
763 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
764 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
767 cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
769 lhs_an_loop_info.safe_grow_cleared (lhs_rank);
770 if (rhs_rank)
771 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
773 cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
774 &lhs_an_info);
775 if (rhs_rank)
777 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
778 cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
779 &rhs_an_info);
781 if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
782 || (rhs_rank
783 && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info)))
785 pop_stmt_list (an_init);
786 return error_mark_node;
788 if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
789 && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST
790 && rhs_an_info[0][0].length
791 && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST)
793 HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length);
794 HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length);
795 /* Length can be negative or positive. As long as the magnitude is OK,
796 then the array notation is valid. */
797 if (absu_hwi (l_length) != absu_hwi (r_length))
799 error_at (location, "length mismatch between LHS and RHS");
800 pop_stmt_list (an_init);
801 return error_mark_node;
804 for (ii = 0; ii < lhs_rank; ii++)
805 if (lhs_an_info[0][ii].is_vector)
807 lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
808 lhs_an_loop_info[ii].ind_init = build_modify_expr
809 (location, lhs_an_loop_info[ii].var,
810 TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR,
811 location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)),
812 TREE_TYPE (lhs_an_loop_info[ii].var));
814 for (ii = 0; ii < rhs_rank; ii++)
816 /* When we have a polynomial, we assume that the indices are of type
817 integer. */
818 rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
819 rhs_an_loop_info[ii].ind_init = build_modify_expr
820 (location, rhs_an_loop_info[ii].var,
821 TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR,
822 location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0),
823 TREE_TYPE (rhs_an_loop_info[ii].var));
825 if (lhs_rank)
827 lhs_array_operand = create_array_refs
828 (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank);
829 replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
830 array_expr_lhs = lhs;
832 if (rhs_array_operand)
833 vec_safe_truncate (rhs_array_operand, 0);
834 if (rhs_rank)
836 rhs_array_operand = create_array_refs
837 (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank);
838 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
839 vec_safe_truncate (rhs_array_operand, 0);
840 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
841 rhs_an_loop_info, rhs_rank,
842 rhs);
843 if (!rhs_array_operand)
844 return error_mark_node;
845 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
847 else if (rhs_list_size > 0)
849 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
850 lhs_an_loop_info, lhs_rank,
851 lhs);
852 if (!rhs_array_operand)
853 return error_mark_node;
854 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
856 array_expr_lhs = lhs;
857 array_expr_rhs = rhs;
858 array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype,
859 modifycode, rhs_loc, array_expr_rhs,
860 rhs_origtype);
861 create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info);
862 if (rhs_rank)
863 create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info);
865 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
866 if (ii < lhs_rank && ii < rhs_rank)
867 cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node,
868 lhs_an_loop_info[ii].cmp,
869 rhs_an_loop_info[ii].cmp);
870 else if (ii < lhs_rank && ii >= rhs_rank)
871 cond_expr[ii] = lhs_an_loop_info[ii].cmp;
872 else
873 gcc_unreachable ();
875 an_init = pop_stmt_list (an_init);
876 append_to_statement_list_force (an_init, &loop_with_init);
877 body = array_expr;
878 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
880 tree incr_list = alloc_stmt_list ();
881 tree new_loop = push_stmt_list ();
882 if (lhs_rank)
883 add_stmt (lhs_an_loop_info[ii].ind_init);
884 if (rhs_rank)
885 add_stmt (rhs_an_loop_info[ii].ind_init);
886 if (lhs_rank)
887 append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list);
888 if (rhs_rank && rhs_an_loop_info[ii].incr)
889 append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list);
890 c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE,
891 NULL_TREE, true);
892 body = pop_stmt_list (new_loop);
894 append_to_statement_list_force (body, &loop_with_init);
896 lhs_an_info.release ();
897 lhs_an_loop_info.release ();
898 if (rhs_rank)
900 rhs_an_info.release ();
901 rhs_an_loop_info.release ();
903 cond_expr.release ();
904 return loop_with_init;
907 /* Helper function for fix_conditional_array_notations. Encloses the
908 conditional statement passed in STMT with a loop around it
909 and replaces the condition in STMT with a ARRAY_REF tree-node to the array.
910 The condition must have an ARRAY_NOTATION_REF tree. An expansion of array
911 notation in STMT is returned in a STATEMENT_LIST. */
913 static tree
914 fix_conditional_array_notations_1 (tree stmt)
916 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
917 size_t list_size = 0;
918 tree cond = NULL_TREE, builtin_loop = NULL_TREE, new_var = NULL_TREE;
919 size_t rank = 0, ii = 0;
920 tree loop_init;
921 location_t location = EXPR_LOCATION (stmt);
922 tree body = NULL_TREE, loop_with_init = alloc_stmt_list ();
923 vec<vec<an_parts> > an_info = vNULL;
924 vec<an_loop_parts> an_loop_info = vNULL;
926 if (TREE_CODE (stmt) == COND_EXPR)
927 cond = COND_EXPR_COND (stmt);
928 else if (TREE_CODE (stmt) == SWITCH_EXPR)
929 cond = SWITCH_COND (stmt);
930 else if (truth_value_p (TREE_CODE (stmt)))
931 cond = TREE_OPERAND (stmt, 0);
932 else
933 /* Otherwise dont even touch the statement. */
934 return stmt;
936 if (!find_rank (location, cond, cond, false, &rank))
937 return error_mark_node;
939 extract_array_notation_exprs (stmt, false, &array_list);
940 loop_init = push_stmt_list ();
941 for (ii = 0; ii < vec_safe_length (array_list); ii++)
943 tree array_node = (*array_list)[ii];
944 if (TREE_CODE (array_node) == CALL_EXPR)
946 builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var);
947 if (builtin_loop == error_mark_node)
949 add_stmt (error_mark_node);
950 pop_stmt_list (loop_init);
951 return loop_init;
953 else if (builtin_loop)
955 vec <tree, va_gc>* sub_list = NULL, *new_var_list = NULL;
956 vec_safe_push (sub_list, array_node);
957 vec_safe_push (new_var_list, new_var);
958 add_stmt (builtin_loop);
959 replace_array_notations (&stmt, false, sub_list, new_var_list);
963 if (!find_rank (location, stmt, stmt, true, &rank))
965 pop_stmt_list (loop_init);
966 return error_mark_node;
968 if (rank == 0)
970 add_stmt (stmt);
971 pop_stmt_list (loop_init);
972 return loop_init;
974 extract_array_notation_exprs (stmt, true, &array_list);
976 if (vec_safe_length (array_list) == 0)
977 return stmt;
979 list_size = vec_safe_length (array_list);
980 an_loop_info.safe_grow_cleared (rank);
982 for (ii = 0; ii < list_size; ii++)
983 if ((*array_list)[ii]
984 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
986 tree array_node = (*array_list)[ii];
987 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
988 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
989 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
991 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
992 for (ii = 0; ii < rank; ii++)
994 an_loop_info[ii].var = create_tmp_var (integer_type_node);
995 an_loop_info[ii].ind_init =
996 build_modify_expr (location, an_loop_info[ii].var,
997 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
998 location,
999 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1000 TREE_TYPE (an_loop_info[ii].var));
1002 array_operand = create_array_refs (location, an_info, an_loop_info,
1003 list_size, rank);
1004 replace_array_notations (&stmt, true, array_list, array_operand);
1005 create_cmp_incr (location, &an_loop_info, rank, an_info);
1007 loop_init = pop_stmt_list (loop_init);
1008 body = stmt;
1009 append_to_statement_list_force (loop_init, &loop_with_init);
1011 for (ii = 0; ii < rank; ii++)
1013 tree new_loop = push_stmt_list ();
1014 add_stmt (an_loop_info[ii].ind_init);
1015 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1016 body, NULL_TREE, NULL_TREE, true);
1017 body = pop_stmt_list (new_loop);
1019 append_to_statement_list_force (body, &loop_with_init);
1021 an_loop_info.release ();
1022 an_info.release ();
1024 return loop_with_init;
1027 /* Top-level function to replace ARRAY_NOTATION_REF in a conditional statement
1028 in STMT. An expansion of array notation in STMT is returned as a
1029 STATEMENT_LIST. */
1031 tree
1032 fix_conditional_array_notations (tree stmt)
1034 if (TREE_CODE (stmt) == STATEMENT_LIST)
1036 tree_stmt_iterator tsi;
1037 for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi))
1039 tree single_stmt = *tsi_stmt_ptr (tsi);
1040 *tsi_stmt_ptr (tsi) =
1041 fix_conditional_array_notations_1 (single_stmt);
1043 return stmt;
1045 else
1046 return fix_conditional_array_notations_1 (stmt);
1049 /* Create a struct c_expr that contains a loop with ARRAY_REF expr at location
1050 LOCATION with the tree_code CODE and the array notation expr is
1051 passed in ARG. Returns the fixed c_expr in ARG itself. */
1053 struct c_expr
1054 fix_array_notation_expr (location_t location, enum tree_code code,
1055 struct c_expr arg)
1058 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1059 size_t list_size = 0, rank = 0, ii = 0;
1060 tree loop_init;
1061 tree body, loop_with_init = alloc_stmt_list ();
1062 vec<vec<an_parts> > an_info = vNULL;
1063 vec<an_loop_parts> an_loop_info = vNULL;
1065 if (!find_rank (location, arg.value, arg.value, false, &rank))
1067 /* If this function returns a NULL, we convert the tree value in the
1068 structure to error_mark_node and the parser should take care of the
1069 rest. */
1070 arg.value = error_mark_node;
1071 return arg;
1074 if (rank == 0)
1075 return arg;
1077 extract_array_notation_exprs (arg.value, true, &array_list);
1079 if (vec_safe_length (array_list) == 0)
1080 return arg;
1082 list_size = vec_safe_length (array_list);
1084 an_loop_info.safe_grow_cleared (rank);
1085 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1087 loop_init = push_stmt_list ();
1088 for (ii = 0; ii < rank; ii++)
1090 an_loop_info[ii].var = create_tmp_var (integer_type_node);
1091 an_loop_info[ii].ind_init =
1092 build_modify_expr (location, an_loop_info[ii].var,
1093 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
1094 location,
1095 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1096 TREE_TYPE (an_loop_info[ii].var));;
1099 array_operand = create_array_refs (location, an_info, an_loop_info,
1100 list_size, rank);
1101 replace_array_notations (&arg.value, true, array_list, array_operand);
1102 create_cmp_incr (location, &an_loop_info, rank, an_info);
1104 arg = default_function_array_read_conversion (location, arg);
1105 if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
1106 arg.value = build_unary_op (location, code, arg.value, 0);
1107 else if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
1108 arg = parser_build_unary_op (location, code, arg);
1110 loop_init = pop_stmt_list (loop_init);
1111 append_to_statement_list_force (loop_init, &loop_with_init);
1112 body = arg.value;
1114 for (ii = 0; ii < rank; ii++)
1116 tree new_loop = push_stmt_list ();
1117 add_stmt (an_loop_info[ii].ind_init);
1118 c_finish_loop (location, an_loop_info[ii].cmp,
1119 an_loop_info[ii].incr, body, NULL_TREE,
1120 NULL_TREE, true);
1121 body = pop_stmt_list (new_loop);
1123 append_to_statement_list_force (body, &loop_with_init);
1124 arg.value = loop_with_init;
1125 an_info.release ();
1126 an_loop_info.release ();
1127 return arg;
1130 /* Replaces array notations in a void function call arguments in ARG and returns
1131 a STATEMENT_LIST. */
1133 static tree
1134 fix_array_notation_call_expr (tree arg)
1136 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1137 tree new_var = NULL_TREE;
1138 size_t list_size = 0, rank = 0, ii = 0;
1139 tree loop_init;
1140 tree body, loop_with_init = alloc_stmt_list ();
1141 location_t location = UNKNOWN_LOCATION;
1142 vec<vec<an_parts> > an_info = vNULL;
1143 vec<an_loop_parts> an_loop_info = vNULL;
1145 if (TREE_CODE (arg) == CALL_EXPR
1146 && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg)))
1148 loop_init = fix_builtin_array_notation_fn (arg, &new_var);
1149 /* We are ignoring the new var because either the user does not want to
1150 capture it OR he is using sec_reduce_mutating function. */
1151 return loop_init;
1153 if (!find_rank (location, arg, arg, false, &rank))
1154 return error_mark_node;
1156 if (rank == 0)
1157 return arg;
1159 extract_array_notation_exprs (arg, true, &array_list);
1160 if (vec_safe_length (array_list) == 0)
1161 return arg;
1163 list_size = vec_safe_length (array_list);
1164 location = EXPR_LOCATION (arg);
1165 an_loop_info.safe_grow_cleared (rank);
1167 loop_init = push_stmt_list ();
1168 for (ii = 0; ii < list_size; ii++)
1169 if ((*array_list)[ii]
1170 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
1172 tree array_node = (*array_list)[ii];
1173 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
1174 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
1175 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
1177 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1178 if (length_mismatch_in_expr_p (location, an_info))
1180 pop_stmt_list (loop_init);
1181 return error_mark_node;
1183 for (ii = 0; ii < rank; ii++)
1185 an_loop_info[ii].var = create_tmp_var (integer_type_node);
1186 an_loop_info[ii].ind_init =
1187 build_modify_expr (location, an_loop_info[ii].var,
1188 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location,
1189 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1190 TREE_TYPE (an_loop_info[ii].var));
1193 array_operand = create_array_refs (location, an_info, an_loop_info,
1194 list_size, rank);
1195 replace_array_notations (&arg, true, array_list, array_operand);
1196 create_cmp_incr (location, &an_loop_info, rank, an_info);
1197 loop_init = pop_stmt_list (loop_init);
1198 append_to_statement_list_force (loop_init, &loop_with_init);
1199 body = arg;
1200 for (ii = 0; ii < rank; ii++)
1202 tree new_loop = push_stmt_list ();
1203 add_stmt (an_loop_info[ii].ind_init);
1204 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1205 body, NULL_TREE, NULL_TREE, true);
1206 body = pop_stmt_list (new_loop);
1208 append_to_statement_list_force (body, &loop_with_init);
1209 an_loop_info.release ();
1210 an_info.release ();
1211 return loop_with_init;
1214 /* Expands the built-in functions in a return. EXPR is a RETURN_EXPR with
1215 a built-in reduction function. This function returns the expansion code for
1216 the built-in function. */
1218 static tree
1219 fix_return_expr (tree expr)
1221 tree new_mod_list, new_var, new_mod, retval_expr, retval_type;
1222 location_t loc = EXPR_LOCATION (expr);
1224 new_mod_list = alloc_stmt_list ();
1225 retval_expr = TREE_OPERAND (expr, 0);
1226 retval_type = TREE_TYPE (TREE_OPERAND (retval_expr, 1));
1227 new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr));
1228 new_mod = build_array_notation_expr (loc, new_var, TREE_TYPE (new_var),
1229 NOP_EXPR, loc,
1230 TREE_OPERAND (retval_expr, 1),
1231 retval_type);
1232 TREE_OPERAND (retval_expr, 1) = new_var;
1233 TREE_OPERAND (expr, 0) = retval_expr;
1234 append_to_statement_list_force (new_mod, &new_mod_list);
1235 append_to_statement_list_force (expr, &new_mod_list);
1236 return new_mod_list;
1239 /* Callback for walk_tree. Expands all array notations in *TP. *WALK_SUBTREES
1240 is set to 1 unless *TP contains no array notation expressions. */
1242 static tree
1243 expand_array_notations (tree *tp, int *walk_subtrees, void *)
1245 if (!contains_array_notation_expr (*tp))
1247 *walk_subtrees = 0;
1248 return NULL_TREE;
1250 *walk_subtrees = 1;
1252 switch (TREE_CODE (*tp))
1254 case TRUTH_ORIF_EXPR:
1255 case TRUTH_ANDIF_EXPR:
1256 case TRUTH_OR_EXPR:
1257 case TRUTH_AND_EXPR:
1258 case TRUTH_XOR_EXPR:
1259 case TRUTH_NOT_EXPR:
1260 case COND_EXPR:
1261 *tp = fix_conditional_array_notations (*tp);
1262 break;
1263 case MODIFY_EXPR:
1265 location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) :
1266 UNKNOWN_LOCATION;
1267 tree lhs = TREE_OPERAND (*tp, 0);
1268 tree rhs = TREE_OPERAND (*tp, 1);
1269 location_t rhs_loc = EXPR_HAS_LOCATION (rhs) ? EXPR_LOCATION (rhs) :
1270 UNKNOWN_LOCATION;
1271 *tp = build_array_notation_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR,
1272 rhs_loc, rhs, TREE_TYPE (rhs));
1274 break;
1275 case DECL_EXPR:
1277 tree x = DECL_EXPR_DECL (*tp);
1278 if (DECL_INITIAL (x))
1280 location_t loc = DECL_SOURCE_LOCATION (x);
1281 tree lhs = x;
1282 tree rhs = DECL_INITIAL (x);
1283 DECL_INITIAL (x) = NULL;
1284 tree new_modify_expr = build_modify_expr (loc, lhs,
1285 TREE_TYPE (lhs),
1286 NOP_EXPR,
1287 loc, rhs,
1288 TREE_TYPE(rhs));
1289 expand_array_notations (&new_modify_expr, walk_subtrees, NULL);
1290 *tp = new_modify_expr;
1293 break;
1294 case CALL_EXPR:
1295 *tp = fix_array_notation_call_expr (*tp);
1296 break;
1297 case RETURN_EXPR:
1298 *tp = fix_return_expr (*tp);
1299 break;
1300 case COMPOUND_EXPR:
1301 if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR)
1303 /* In here we are calling expand_array_notations because
1304 we need to be able to catch the return value and check if
1305 it is an error_mark_node. */
1306 expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL);
1308 /* SAVE_EXPR cannot have an error_mark_node inside it. This check
1309 will make sure that if there is an error in expanding of
1310 array notations (e.g. rank mismatch) then replace the entire
1311 SAVE_EXPR with an error_mark_node. */
1312 if (TREE_OPERAND (*tp, 1) == error_mark_node)
1313 *tp = error_mark_node;
1315 break;
1316 case ARRAY_NOTATION_REF:
1317 /* If we are here, then we are dealing with cases like this:
1318 A[:];
1319 A[x:y:z];
1320 A[x:y];
1321 Replace those with just void zero node. */
1322 *tp = void_node;
1323 default:
1324 break;
1326 return NULL_TREE;
1329 /* Walks through tree node T and expands all array notations in its subtrees.
1330 The return value is the same type as T but with all array notations
1331 replaced with appropriate ARRAY_REFS with a loop around it. */
1333 tree
1334 expand_array_notation_exprs (tree t)
1336 walk_tree (&t, expand_array_notations, NULL, NULL);
1337 return t;
1340 /* This handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which
1341 denotes an array notation expression. If a is a variable or a member, then
1342 we generate a ARRAY_NOTATION_REF front-end tree and return it.
1343 This tree is broken down to ARRAY_REF toward the end of parsing.
1344 ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE
1345 of ARRAY_REF. Restrictions on START_INDEX, LENGTH and STRIDE is same as that
1346 of the index field passed into ARRAY_REF. The only additional restriction
1347 is that, unlike index in ARRAY_REF, stride, length and start_index cannot
1348 contain ARRAY_NOTATIONS. */
1350 tree
1351 build_array_notation_ref (location_t loc, tree array, tree start_index,
1352 tree length, tree stride, tree type)
1354 tree array_ntn_tree = NULL_TREE;
1355 size_t stride_rank = 0, length_rank = 0, start_rank = 0;
1357 if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
1359 error_at (loc,
1360 "start-index of array notation triplet is not an integer");
1361 return error_mark_node;
1363 if (!INTEGRAL_TYPE_P (TREE_TYPE (length)))
1365 error_at (loc, "length of array notation triplet is not an integer");
1366 return error_mark_node;
1369 /* The stride is an optional field. */
1370 if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
1372 error_at (loc, "stride of array notation triplet is not an integer");
1373 return error_mark_node;
1375 if (!stride)
1377 if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length)
1378 && tree_int_cst_lt (length, start_index))
1379 stride = build_int_cst (TREE_TYPE (start_index), -1);
1380 else
1381 stride = build_int_cst (TREE_TYPE (start_index), 1);
1384 if (!find_rank (loc, start_index, start_index, false, &start_rank))
1385 return error_mark_node;
1386 if (!find_rank (loc, length, length, false, &length_rank))
1387 return error_mark_node;
1388 if (!find_rank (loc, stride, stride, false, &stride_rank))
1389 return error_mark_node;
1391 if (start_rank != 0)
1393 error_at (loc, "rank of an array notation triplet's start-index is not "
1394 "zero");
1395 return error_mark_node;
1397 if (length_rank != 0)
1399 error_at (loc, "rank of an array notation triplet's length is not zero");
1400 return error_mark_node;
1402 if (stride_rank != 0)
1404 error_at (loc, "rank of array notation triplet's stride is not zero");
1405 return error_mark_node;
1407 array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE,
1408 NULL_TREE, NULL_TREE);
1409 ARRAY_NOTATION_ARRAY (array_ntn_tree) = array;
1410 ARRAY_NOTATION_START (array_ntn_tree) = start_index;
1411 ARRAY_NOTATION_LENGTH (array_ntn_tree) = length;
1412 ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride;
1413 TREE_TYPE (array_ntn_tree) = type;
1415 return array_ntn_tree;