Merge aosp-toolchain/gcc/gcc-4_9 changes.
[official-gcc.git] / gcc-4_9-mobile / gcc / c / c-array-notation.c
blobbe08f532ee2a61da2eb8fd500afbc6ca49745dc0
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 /* Builtin call should contain at least one argument. */
218 if (call_expr_nargs (an_builtin_fn) == 0)
220 error_at (EXPR_LOCATION (an_builtin_fn), "Invalid builtin arguments");
221 return error_mark_node;
224 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE
225 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
227 call_fn = CALL_EXPR_ARG (an_builtin_fn, 2);
228 if (TREE_CODE (call_fn) == ADDR_EXPR)
229 call_fn = TREE_OPERAND (call_fn, 0);
230 identity_value = CALL_EXPR_ARG (an_builtin_fn, 0);
231 func_parm = CALL_EXPR_ARG (an_builtin_fn, 1);
233 else
234 func_parm = CALL_EXPR_ARG (an_builtin_fn, 0);
236 /* Fully fold any EXCESSIVE_PRECISION EXPR that can occur in the function
237 parameter. */
238 func_parm = c_fully_fold (func_parm, false, NULL);
239 if (func_parm == error_mark_node)
240 return error_mark_node;
242 location = EXPR_LOCATION (an_builtin_fn);
244 if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank))
245 return error_mark_node;
247 if (rank == 0)
249 error_at (location, "Invalid builtin arguments");
250 return error_mark_node;
252 else if (rank > 1
253 && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
254 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND))
256 error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot"
257 " have arrays with dimension greater than 1");
258 return error_mark_node;
261 extract_array_notation_exprs (func_parm, true, &array_list);
262 list_size = vec_safe_length (array_list);
263 switch (an_type)
265 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
266 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
267 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
268 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
269 new_var_type = TREE_TYPE ((*array_list)[0]);
270 break;
271 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
272 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
273 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
274 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
275 new_var_type = integer_type_node;
276 break;
277 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
278 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
279 new_var_type = integer_type_node;
280 break;
281 case BUILT_IN_CILKPLUS_SEC_REDUCE:
282 if (call_fn && identity_value)
283 new_var_type = TREE_TYPE ((*array_list)[0]);
284 break;
285 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
286 new_var_type = NULL_TREE;
287 break;
288 default:
289 gcc_unreachable ();
292 an_loop_info.safe_grow_cleared (rank);
293 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
294 loop_init = alloc_stmt_list ();
296 for (ii = 0; ii < rank; ii++)
298 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
299 an_loop_info[ii].ind_init =
300 build_modify_expr (location, an_loop_info[ii].var,
301 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
302 location,
303 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
304 TREE_TYPE (an_loop_info[ii].var));
306 array_operand = create_array_refs (location, an_info, an_loop_info,
307 list_size, rank);
308 replace_array_notations (&func_parm, true, array_list, array_operand);
310 create_cmp_incr (location, &an_loop_info, rank, an_info);
311 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
313 *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type);
314 gcc_assert (*new_var && *new_var != error_mark_node);
316 else
317 *new_var = NULL_TREE;
319 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
320 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
321 array_ind_value = build_decl (location, VAR_DECL, NULL_TREE,
322 TREE_TYPE (func_parm));
323 array_op0 = (*array_operand)[0];
324 if (TREE_CODE (array_op0) == INDIRECT_REF)
325 array_op0 = TREE_OPERAND (array_op0, 0);
326 switch (an_type)
328 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
329 new_var_init = build_modify_expr
330 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
331 location, build_zero_cst (new_var_type), new_var_type);
332 new_expr = build_modify_expr
333 (location, *new_var, TREE_TYPE (*new_var), PLUS_EXPR,
334 location, func_parm, TREE_TYPE (func_parm));
335 break;
336 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
337 new_var_init = build_modify_expr
338 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
339 location, build_one_cst (new_var_type), new_var_type);
340 new_expr = build_modify_expr
341 (location, *new_var, TREE_TYPE (*new_var), MULT_EXPR,
342 location, func_parm, TREE_TYPE (func_parm));
343 break;
344 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
345 new_var_init = build_modify_expr
346 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
347 location, build_one_cst (new_var_type), new_var_type);
348 /* Initially you assume everything is zero, now if we find a case where
349 it is NOT true, then we set the result to false. Otherwise
350 we just keep the previous value. */
351 new_yes_expr = build_modify_expr
352 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
353 location, build_zero_cst (TREE_TYPE (*new_var)),
354 TREE_TYPE (*new_var));
355 new_no_expr = build_modify_expr
356 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
357 location, *new_var, TREE_TYPE (*new_var));
358 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
359 build_zero_cst (TREE_TYPE (func_parm)));
360 new_expr = build_conditional_expr
361 (location, new_cond_expr, false, new_yes_expr,
362 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
363 break;
364 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
365 new_var_init = build_modify_expr
366 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
367 location, build_one_cst (new_var_type), new_var_type);
368 /* Initially you assume everything is non-zero, now if we find a case
369 where it is NOT true, then we set the result to false. Otherwise
370 we just keep the previous value. */
371 new_yes_expr = build_modify_expr
372 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
373 location, build_zero_cst (TREE_TYPE (*new_var)),
374 TREE_TYPE (*new_var));
375 new_no_expr = build_modify_expr
376 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
377 location, *new_var, TREE_TYPE (*new_var));
378 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
379 build_zero_cst (TREE_TYPE (func_parm)));
380 new_expr = build_conditional_expr
381 (location, new_cond_expr, false, new_yes_expr,
382 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
383 break;
384 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
385 new_var_init = build_modify_expr
386 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
387 location, build_zero_cst (new_var_type), new_var_type);
388 /* Initially we assume there are NO zeros in the list. When we find
389 a non-zero, we keep the previous value. If we find a zero, we
390 set the value to true. */
391 new_yes_expr = build_modify_expr
392 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
393 location, build_one_cst (new_var_type), new_var_type);
394 new_no_expr = build_modify_expr
395 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
396 location, *new_var, TREE_TYPE (*new_var));
397 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
398 build_zero_cst (TREE_TYPE (func_parm)));
399 new_expr = build_conditional_expr
400 (location, new_cond_expr, false, new_yes_expr,
401 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
402 break;
403 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
404 new_var_init = build_modify_expr
405 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
406 location, build_zero_cst (new_var_type), new_var_type);
407 /* Initially we assume there are NO non-zeros in the list. When we find
408 a zero, we keep the previous value. If we find a non-zero, we set
409 the value to true. */
410 new_yes_expr = build_modify_expr
411 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
412 location, build_one_cst (new_var_type), new_var_type);
413 new_no_expr = build_modify_expr
414 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
415 location, *new_var, TREE_TYPE (*new_var));
416 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
417 build_zero_cst (TREE_TYPE (func_parm)));
418 new_expr = build_conditional_expr
419 (location, new_cond_expr, false, new_yes_expr,
420 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
421 break;
422 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
423 if (TYPE_MIN_VALUE (new_var_type))
424 new_var_init = build_modify_expr
425 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
426 location, TYPE_MIN_VALUE (new_var_type), new_var_type);
427 else
428 new_var_init = build_modify_expr
429 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
430 location, func_parm, new_var_type);
431 new_no_expr = build_modify_expr
432 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
433 location, *new_var, TREE_TYPE (*new_var));
434 new_yes_expr = build_modify_expr
435 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
436 location, func_parm, TREE_TYPE (*new_var));
437 new_expr = build_conditional_expr
438 (location,
439 build2 (LT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
440 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
441 break;
442 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
443 if (TYPE_MAX_VALUE (new_var_type))
444 new_var_init = build_modify_expr
445 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
446 location, TYPE_MAX_VALUE (new_var_type), new_var_type);
447 else
448 new_var_init = build_modify_expr
449 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
450 location, func_parm, new_var_type);
451 new_no_expr = build_modify_expr
452 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
453 location, *new_var, TREE_TYPE (*new_var));
454 new_yes_expr = build_modify_expr
455 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
456 location, func_parm, TREE_TYPE (*new_var));
457 new_expr = build_conditional_expr
458 (location,
459 build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
460 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
461 break;
462 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
463 new_var_init = build_modify_expr
464 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
465 location, build_zero_cst (new_var_type), new_var_type);
466 new_exp_init = build_modify_expr
467 (location, array_ind_value, TREE_TYPE (array_ind_value),
468 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
469 new_no_ind = build_modify_expr
470 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
471 location, *new_var, TREE_TYPE (*new_var));
472 new_no_expr = build_modify_expr
473 (location, array_ind_value, TREE_TYPE (array_ind_value),
474 NOP_EXPR,
475 location, array_ind_value, TREE_TYPE (array_ind_value));
476 if (list_size > 1)
478 new_yes_ind = build_modify_expr
479 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
480 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
481 new_yes_expr = build_modify_expr
482 (location, array_ind_value, TREE_TYPE (array_ind_value),
483 NOP_EXPR,
484 location, func_parm, TREE_TYPE ((*array_operand)[0]));
486 else
488 new_yes_ind = build_modify_expr
489 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
490 location, TREE_OPERAND (array_op0, 1),
491 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
492 new_yes_expr = build_modify_expr
493 (location, array_ind_value, TREE_TYPE (array_ind_value),
494 NOP_EXPR,
495 location, func_parm, TREE_OPERAND (array_op0, 1));
497 new_yes_list = alloc_stmt_list ();
498 append_to_statement_list (new_yes_ind, &new_yes_list);
499 append_to_statement_list (new_yes_expr, &new_yes_list);
501 new_no_list = alloc_stmt_list ();
502 append_to_statement_list (new_no_ind, &new_no_list);
503 append_to_statement_list (new_no_expr, &new_no_list);
505 new_expr = build_conditional_expr
506 (location,
507 build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
508 func_parm),
509 false,
510 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
511 break;
512 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
513 new_var_init = build_modify_expr
514 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
515 location, build_zero_cst (new_var_type), new_var_type);
516 new_exp_init = build_modify_expr
517 (location, array_ind_value, TREE_TYPE (array_ind_value),
518 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
519 new_no_ind = build_modify_expr
520 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
521 location, *new_var, TREE_TYPE (*new_var));
522 new_no_expr = build_modify_expr
523 (location, array_ind_value, TREE_TYPE (array_ind_value),
524 NOP_EXPR,
525 location, array_ind_value, TREE_TYPE (array_ind_value));
526 if (list_size > 1)
528 new_yes_ind = build_modify_expr
529 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
530 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
531 new_yes_expr = build_modify_expr
532 (location, array_ind_value, TREE_TYPE (array_ind_value),
533 NOP_EXPR,
534 location, func_parm, TREE_TYPE (array_op0));
536 else
538 new_yes_ind = build_modify_expr
539 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
540 location, TREE_OPERAND (array_op0, 1),
541 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
542 new_yes_expr = build_modify_expr
543 (location, array_ind_value, TREE_TYPE (array_ind_value),
544 NOP_EXPR,
545 location, func_parm, TREE_OPERAND (array_op0, 1));
547 new_yes_list = alloc_stmt_list ();
548 append_to_statement_list (new_yes_ind, &new_yes_list);
549 append_to_statement_list (new_yes_expr, &new_yes_list);
551 new_no_list = alloc_stmt_list ();
552 append_to_statement_list (new_no_ind, &new_no_list);
553 append_to_statement_list (new_no_expr, &new_no_list);
555 new_expr = build_conditional_expr
556 (location,
557 build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
558 func_parm),
559 false,
560 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
561 break;
562 case BUILT_IN_CILKPLUS_SEC_REDUCE:
563 new_var_init = build_modify_expr
564 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
565 location, identity_value, new_var_type);
566 new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm);
567 new_expr = build_modify_expr
568 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
569 location, new_call_expr, TREE_TYPE (*new_var));
570 break;
571 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
572 new_expr = build_call_expr (call_fn, 2, identity_value, func_parm);
573 break;
574 default:
575 gcc_unreachable ();
576 break;
579 for (ii = 0; ii < rank; ii++)
580 append_to_statement_list (an_loop_info[ii].ind_init, &loop_init);
582 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
583 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
584 append_to_statement_list (new_exp_init, &loop_init);
585 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
586 append_to_statement_list (new_var_init, &loop_init);
588 append_to_statement_list_force (loop_init, &loop_with_init);
589 body = new_expr;
590 for (ii = 0; ii < rank; ii++)
592 tree new_loop = push_stmt_list ();
593 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
594 body, NULL_TREE, NULL_TREE, true);
595 body = pop_stmt_list (new_loop);
597 append_to_statement_list_force (body, &loop_with_init);
599 an_info.release ();
600 an_loop_info.release ();
602 return loop_with_init;
605 /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
606 The LHS and/or RHS will be array notation expressions that have a MODIFYCODE
607 Their locations are specified by LHS_LOC, RHS_LOC. The location of the
608 modify expression is location. The original type of LHS and RHS are passed
609 in LHS_ORIGTYPE and RHS_ORIGTYPE. */
611 tree
612 build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
613 enum tree_code modifycode, location_t rhs_loc,
614 tree rhs, tree rhs_origtype)
616 bool found_builtin_fn = false;
617 tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
618 tree array_expr = NULL_TREE;
619 tree an_init = NULL_TREE;
620 vec<tree> cond_expr = vNULL;
621 tree body, loop_with_init = alloc_stmt_list();
622 tree scalar_mods = NULL_TREE;
623 vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL;
624 size_t lhs_rank = 0, rhs_rank = 0;
625 size_t ii = 0;
626 vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL;
627 tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE;
628 size_t rhs_list_size = 0, lhs_list_size = 0;
629 vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
630 vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL;
632 /* If either of this is true, an error message must have been send out
633 already. Not necessary to send out multiple error messages. */
634 if (lhs == error_mark_node || rhs == error_mark_node)
635 return error_mark_node;
637 if (!find_rank (location, rhs, rhs, false, &rhs_rank))
638 return error_mark_node;
640 extract_array_notation_exprs (rhs, false, &rhs_list);
641 rhs_list_size = vec_safe_length (rhs_list);
642 an_init = push_stmt_list ();
643 if (rhs_rank)
645 scalar_mods = replace_invariant_exprs (&rhs);
646 if (scalar_mods)
647 add_stmt (scalar_mods);
649 for (ii = 0; ii < rhs_list_size; ii++)
651 tree rhs_node = (*rhs_list)[ii];
652 if (TREE_CODE (rhs_node) == CALL_EXPR)
654 builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
655 if (builtin_loop == error_mark_node)
657 pop_stmt_list (an_init);
658 return error_mark_node;
660 else if (builtin_loop)
662 add_stmt (builtin_loop);
663 found_builtin_fn = true;
664 if (new_var)
666 vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
667 vec_safe_push (rhs_sub_list, rhs_node);
668 vec_safe_push (new_var_list, new_var);
669 replace_array_notations (&rhs, false, rhs_sub_list,
670 new_var_list);
676 lhs_rank = 0;
677 rhs_rank = 0;
678 if (!find_rank (location, lhs, lhs, true, &lhs_rank))
680 pop_stmt_list (an_init);
681 return error_mark_node;
684 if (!find_rank (location, rhs, rhs, true, &rhs_rank))
686 pop_stmt_list (an_init);
687 return error_mark_node;
690 if (lhs_rank == 0 && rhs_rank == 0)
692 if (found_builtin_fn)
694 new_modify_expr = build_modify_expr (location, lhs, lhs_origtype,
695 modifycode, rhs_loc, rhs,
696 rhs_origtype);
697 add_stmt (new_modify_expr);
698 pop_stmt_list (an_init);
699 return an_init;
701 else
703 pop_stmt_list (an_init);
704 return NULL_TREE;
707 rhs_list_size = 0;
708 rhs_list = NULL;
709 extract_array_notation_exprs (rhs, true, &rhs_list);
710 extract_array_notation_exprs (lhs, true, &lhs_list);
711 rhs_list_size = vec_safe_length (rhs_list);
712 lhs_list_size = vec_safe_length (lhs_list);
714 if (lhs_rank == 0 && rhs_rank != 0)
716 tree rhs_base = rhs;
717 if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
719 for (ii = 0; ii < (size_t) rhs_rank; ii++)
720 rhs_base = ARRAY_NOTATION_ARRAY (rhs);
722 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
723 rhs_base);
724 return error_mark_node;
726 else
728 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
729 rhs_base);
730 return error_mark_node;
733 if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
735 error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
736 pop_stmt_list (an_init);
737 return error_mark_node;
740 /* Here we assign the array notation components to variable so that we can
741 satisfy the exec once rule. */
742 for (ii = 0; ii < lhs_list_size; ii++)
744 tree array_node = (*lhs_list)[ii];
745 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
746 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
747 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
749 for (ii = 0; ii < rhs_list_size; ii++)
750 if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
752 tree array_node = (*rhs_list)[ii];
753 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
754 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
755 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
758 cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
760 lhs_an_loop_info.safe_grow_cleared (lhs_rank);
761 if (rhs_rank)
762 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
764 cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
765 &lhs_an_info);
766 if (rhs_rank)
768 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
769 cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
770 &rhs_an_info);
772 if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
773 || (rhs_rank
774 && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info)))
776 pop_stmt_list (an_init);
777 return error_mark_node;
779 if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
780 && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST
781 && rhs_an_info[0][0].length
782 && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST)
784 HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length);
785 HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length);
786 /* Length can be negative or positive. As long as the magnitude is OK,
787 then the array notation is valid. */
788 if (absu_hwi (l_length) != absu_hwi (r_length))
790 error_at (location, "length mismatch between LHS and RHS");
791 pop_stmt_list (an_init);
792 return error_mark_node;
795 for (ii = 0; ii < lhs_rank; ii++)
796 if (lhs_an_info[0][ii].is_vector)
798 lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node,
799 NULL);
800 lhs_an_loop_info[ii].ind_init = build_modify_expr
801 (location, lhs_an_loop_info[ii].var,
802 TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR,
803 location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)),
804 TREE_TYPE (lhs_an_loop_info[ii].var));
806 for (ii = 0; ii < rhs_rank; ii++)
808 /* When we have a polynomial, we assume that the indices are of type
809 integer. */
810 rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node,
811 NULL);
812 rhs_an_loop_info[ii].ind_init = build_modify_expr
813 (location, rhs_an_loop_info[ii].var,
814 TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR,
815 location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0),
816 TREE_TYPE (rhs_an_loop_info[ii].var));
818 if (lhs_rank)
820 lhs_array_operand = create_array_refs
821 (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank);
822 replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
823 array_expr_lhs = lhs;
825 if (rhs_array_operand)
826 vec_safe_truncate (rhs_array_operand, 0);
827 if (rhs_rank)
829 rhs_array_operand = create_array_refs
830 (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank);
831 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
832 vec_safe_truncate (rhs_array_operand, 0);
833 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
834 rhs_an_loop_info, rhs_rank,
835 rhs);
836 if (!rhs_array_operand)
837 return error_mark_node;
838 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
840 else if (rhs_list_size > 0)
842 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
843 lhs_an_loop_info, lhs_rank,
844 lhs);
845 if (!rhs_array_operand)
846 return error_mark_node;
847 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
849 array_expr_lhs = lhs;
850 array_expr_rhs = rhs;
851 array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype,
852 modifycode, rhs_loc, array_expr_rhs,
853 rhs_origtype);
854 create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info);
855 if (rhs_rank)
856 create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info);
858 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
859 if (ii < lhs_rank && ii < rhs_rank)
860 cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node,
861 lhs_an_loop_info[ii].cmp,
862 rhs_an_loop_info[ii].cmp);
863 else if (ii < lhs_rank && ii >= rhs_rank)
864 cond_expr[ii] = lhs_an_loop_info[ii].cmp;
865 else
866 gcc_unreachable ();
868 an_init = pop_stmt_list (an_init);
869 append_to_statement_list_force (an_init, &loop_with_init);
870 body = array_expr;
871 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
873 tree incr_list = alloc_stmt_list ();
874 tree new_loop = push_stmt_list ();
875 if (lhs_rank)
876 add_stmt (lhs_an_loop_info[ii].ind_init);
877 if (rhs_rank)
878 add_stmt (rhs_an_loop_info[ii].ind_init);
879 if (lhs_rank)
880 append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list);
881 if (rhs_rank && rhs_an_loop_info[ii].incr)
882 append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list);
883 c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE,
884 NULL_TREE, true);
885 body = pop_stmt_list (new_loop);
887 append_to_statement_list_force (body, &loop_with_init);
889 lhs_an_info.release ();
890 lhs_an_loop_info.release ();
891 if (rhs_rank)
893 rhs_an_info.release ();
894 rhs_an_loop_info.release ();
896 cond_expr.release ();
897 return loop_with_init;
900 /* Helper function for fix_conditional_array_notations. Encloses the
901 conditional statement passed in STMT with a loop around it
902 and replaces the condition in STMT with a ARRAY_REF tree-node to the array.
903 The condition must have an ARRAY_NOTATION_REF tree. An expansion of array
904 notation in STMT is returned in a STATEMENT_LIST. */
906 static tree
907 fix_conditional_array_notations_1 (tree stmt)
909 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
910 size_t list_size = 0;
911 tree cond = NULL_TREE, builtin_loop = NULL_TREE, new_var = NULL_TREE;
912 size_t rank = 0, ii = 0;
913 tree loop_init;
914 location_t location = EXPR_LOCATION (stmt);
915 tree body = NULL_TREE, loop_with_init = alloc_stmt_list ();
916 vec<vec<an_parts> > an_info = vNULL;
917 vec<an_loop_parts> an_loop_info = vNULL;
919 if (TREE_CODE (stmt) == COND_EXPR)
920 cond = COND_EXPR_COND (stmt);
921 else if (TREE_CODE (stmt) == SWITCH_EXPR)
922 cond = SWITCH_COND (stmt);
923 else if (truth_value_p (TREE_CODE (stmt)))
924 cond = TREE_OPERAND (stmt, 0);
925 else
926 /* Otherwise dont even touch the statement. */
927 return stmt;
929 if (!find_rank (location, cond, cond, false, &rank))
930 return error_mark_node;
932 extract_array_notation_exprs (stmt, false, &array_list);
933 loop_init = push_stmt_list ();
934 for (ii = 0; ii < vec_safe_length (array_list); ii++)
936 tree array_node = (*array_list)[ii];
937 if (TREE_CODE (array_node) == CALL_EXPR)
939 builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var);
940 if (builtin_loop == error_mark_node)
942 add_stmt (error_mark_node);
943 pop_stmt_list (loop_init);
944 return loop_init;
946 else if (builtin_loop)
948 vec <tree, va_gc>* sub_list = NULL, *new_var_list = NULL;
949 vec_safe_push (sub_list, array_node);
950 vec_safe_push (new_var_list, new_var);
951 add_stmt (builtin_loop);
952 replace_array_notations (&stmt, false, sub_list, new_var_list);
956 if (!find_rank (location, stmt, stmt, true, &rank))
958 pop_stmt_list (loop_init);
959 return error_mark_node;
961 if (rank == 0)
963 add_stmt (stmt);
964 pop_stmt_list (loop_init);
965 return loop_init;
967 extract_array_notation_exprs (stmt, true, &array_list);
969 if (vec_safe_length (array_list) == 0)
970 return stmt;
972 list_size = vec_safe_length (array_list);
973 an_loop_info.safe_grow_cleared (rank);
975 for (ii = 0; ii < list_size; ii++)
976 if ((*array_list)[ii]
977 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
979 tree array_node = (*array_list)[ii];
980 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
981 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
982 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
984 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
985 for (ii = 0; ii < rank; ii++)
987 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
988 an_loop_info[ii].ind_init =
989 build_modify_expr (location, an_loop_info[ii].var,
990 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
991 location,
992 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
993 TREE_TYPE (an_loop_info[ii].var));
995 array_operand = create_array_refs (location, an_info, an_loop_info,
996 list_size, rank);
997 replace_array_notations (&stmt, true, array_list, array_operand);
998 create_cmp_incr (location, &an_loop_info, rank, an_info);
1000 loop_init = pop_stmt_list (loop_init);
1001 body = stmt;
1002 append_to_statement_list_force (loop_init, &loop_with_init);
1004 for (ii = 0; ii < rank; ii++)
1006 tree new_loop = push_stmt_list ();
1007 add_stmt (an_loop_info[ii].ind_init);
1008 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1009 body, NULL_TREE, NULL_TREE, true);
1010 body = pop_stmt_list (new_loop);
1012 append_to_statement_list_force (body, &loop_with_init);
1014 an_loop_info.release ();
1015 an_info.release ();
1017 return loop_with_init;
1020 /* Top-level function to replace ARRAY_NOTATION_REF in a conditional statement
1021 in STMT. An expansion of array notation in STMT is returned as a
1022 STATEMENT_LIST. */
1024 tree
1025 fix_conditional_array_notations (tree stmt)
1027 if (TREE_CODE (stmt) == STATEMENT_LIST)
1029 tree_stmt_iterator tsi;
1030 for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi))
1032 tree single_stmt = *tsi_stmt_ptr (tsi);
1033 *tsi_stmt_ptr (tsi) =
1034 fix_conditional_array_notations_1 (single_stmt);
1036 return stmt;
1038 else
1039 return fix_conditional_array_notations_1 (stmt);
1042 /* Create a struct c_expr that contains a loop with ARRAY_REF expr at location
1043 LOCATION with the tree_code CODE and the array notation expr is
1044 passed in ARG. Returns the fixed c_expr in ARG itself. */
1046 struct c_expr
1047 fix_array_notation_expr (location_t location, enum tree_code code,
1048 struct c_expr arg)
1051 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1052 size_t list_size = 0, rank = 0, ii = 0;
1053 tree loop_init;
1054 tree body, loop_with_init = alloc_stmt_list ();
1055 vec<vec<an_parts> > an_info = vNULL;
1056 vec<an_loop_parts> an_loop_info = vNULL;
1058 if (!find_rank (location, arg.value, arg.value, false, &rank))
1060 /* If this function returns a NULL, we convert the tree value in the
1061 structure to error_mark_node and the parser should take care of the
1062 rest. */
1063 arg.value = error_mark_node;
1064 return arg;
1067 if (rank == 0)
1068 return arg;
1070 extract_array_notation_exprs (arg.value, true, &array_list);
1072 if (vec_safe_length (array_list) == 0)
1073 return arg;
1075 list_size = vec_safe_length (array_list);
1077 an_loop_info.safe_grow_cleared (rank);
1078 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1080 loop_init = push_stmt_list ();
1081 for (ii = 0; ii < rank; ii++)
1083 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
1084 an_loop_info[ii].ind_init =
1085 build_modify_expr (location, an_loop_info[ii].var,
1086 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
1087 location,
1088 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1089 TREE_TYPE (an_loop_info[ii].var));;
1092 array_operand = create_array_refs (location, an_info, an_loop_info,
1093 list_size, rank);
1094 replace_array_notations (&arg.value, true, array_list, array_operand);
1095 create_cmp_incr (location, &an_loop_info, rank, an_info);
1097 arg = default_function_array_read_conversion (location, arg);
1098 if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
1099 arg.value = build_unary_op (location, code, arg.value, 0);
1100 else if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
1101 arg = parser_build_unary_op (location, code, arg);
1103 loop_init = pop_stmt_list (loop_init);
1104 append_to_statement_list_force (loop_init, &loop_with_init);
1105 body = arg.value;
1107 for (ii = 0; ii < rank; ii++)
1109 tree new_loop = push_stmt_list ();
1110 add_stmt (an_loop_info[ii].ind_init);
1111 c_finish_loop (location, an_loop_info[ii].cmp,
1112 an_loop_info[ii].incr, body, NULL_TREE,
1113 NULL_TREE, true);
1114 body = pop_stmt_list (new_loop);
1116 append_to_statement_list_force (body, &loop_with_init);
1117 arg.value = loop_with_init;
1118 an_info.release ();
1119 an_loop_info.release ();
1120 return arg;
1123 /* Replaces array notations in a void function call arguments in ARG and returns
1124 a STATEMENT_LIST. */
1126 static tree
1127 fix_array_notation_call_expr (tree arg)
1129 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1130 tree new_var = NULL_TREE;
1131 size_t list_size = 0, rank = 0, ii = 0;
1132 tree loop_init;
1133 tree body, loop_with_init = alloc_stmt_list ();
1134 location_t location = UNKNOWN_LOCATION;
1135 vec<vec<an_parts> > an_info = vNULL;
1136 vec<an_loop_parts> an_loop_info = vNULL;
1138 if (TREE_CODE (arg) == CALL_EXPR
1139 && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg)))
1141 loop_init = fix_builtin_array_notation_fn (arg, &new_var);
1142 /* We are ignoring the new var because either the user does not want to
1143 capture it OR he is using sec_reduce_mutating function. */
1144 return loop_init;
1146 if (!find_rank (location, arg, arg, false, &rank))
1147 return error_mark_node;
1149 if (rank == 0)
1150 return arg;
1152 extract_array_notation_exprs (arg, true, &array_list);
1153 if (vec_safe_length (array_list) == 0)
1154 return arg;
1156 list_size = vec_safe_length (array_list);
1157 location = EXPR_LOCATION (arg);
1158 an_loop_info.safe_grow_cleared (rank);
1160 loop_init = push_stmt_list ();
1161 for (ii = 0; ii < list_size; ii++)
1162 if ((*array_list)[ii]
1163 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
1165 tree array_node = (*array_list)[ii];
1166 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
1167 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
1168 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
1170 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1171 if (length_mismatch_in_expr_p (location, an_info))
1173 pop_stmt_list (loop_init);
1174 return error_mark_node;
1176 for (ii = 0; ii < rank; ii++)
1178 an_loop_info[ii].var = create_tmp_var (integer_type_node, NULL);
1179 an_loop_info[ii].ind_init =
1180 build_modify_expr (location, an_loop_info[ii].var,
1181 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location,
1182 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1183 TREE_TYPE (an_loop_info[ii].var));
1186 array_operand = create_array_refs (location, an_info, an_loop_info,
1187 list_size, rank);
1188 replace_array_notations (&arg, true, array_list, array_operand);
1189 create_cmp_incr (location, &an_loop_info, rank, an_info);
1190 loop_init = pop_stmt_list (loop_init);
1191 append_to_statement_list_force (loop_init, &loop_with_init);
1192 body = arg;
1193 for (ii = 0; ii < rank; ii++)
1195 tree new_loop = push_stmt_list ();
1196 add_stmt (an_loop_info[ii].ind_init);
1197 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1198 body, NULL_TREE, NULL_TREE, true);
1199 body = pop_stmt_list (new_loop);
1201 append_to_statement_list_force (body, &loop_with_init);
1202 an_loop_info.release ();
1203 an_info.release ();
1204 return loop_with_init;
1207 /* Expands the built-in functions in a return. EXPR is a RETURN_EXPR with
1208 a built-in reduction function. This function returns the expansion code for
1209 the built-in function. */
1211 static tree
1212 fix_return_expr (tree expr)
1214 tree new_mod_list, new_var, new_mod, retval_expr, retval_type;
1215 location_t loc = EXPR_LOCATION (expr);
1217 new_mod_list = alloc_stmt_list ();
1218 retval_expr = TREE_OPERAND (expr, 0);
1219 retval_type = TREE_TYPE (TREE_OPERAND (retval_expr, 1));
1220 new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr));
1221 new_mod = build_array_notation_expr (loc, new_var, TREE_TYPE (new_var),
1222 NOP_EXPR, loc,
1223 TREE_OPERAND (retval_expr, 1),
1224 retval_type);
1225 TREE_OPERAND (retval_expr, 1) = new_var;
1226 TREE_OPERAND (expr, 0) = retval_expr;
1227 append_to_statement_list_force (new_mod, &new_mod_list);
1228 append_to_statement_list_force (expr, &new_mod_list);
1229 return new_mod_list;
1232 /* Callback for walk_tree. Expands all array notations in *TP. *WALK_SUBTREES
1233 is set to 1 unless *TP contains no array notation expressions. */
1235 static tree
1236 expand_array_notations (tree *tp, int *walk_subtrees, void *)
1238 if (!contains_array_notation_expr (*tp))
1240 *walk_subtrees = 0;
1241 return NULL_TREE;
1243 *walk_subtrees = 1;
1245 switch (TREE_CODE (*tp))
1247 case TRUTH_ORIF_EXPR:
1248 case TRUTH_ANDIF_EXPR:
1249 case TRUTH_OR_EXPR:
1250 case TRUTH_AND_EXPR:
1251 case TRUTH_XOR_EXPR:
1252 case TRUTH_NOT_EXPR:
1253 case COND_EXPR:
1254 *tp = fix_conditional_array_notations (*tp);
1255 break;
1256 case MODIFY_EXPR:
1258 location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) :
1259 UNKNOWN_LOCATION;
1260 tree lhs = TREE_OPERAND (*tp, 0);
1261 tree rhs = TREE_OPERAND (*tp, 1);
1262 location_t rhs_loc = EXPR_HAS_LOCATION (rhs) ? EXPR_LOCATION (rhs) :
1263 UNKNOWN_LOCATION;
1264 *tp = build_array_notation_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR,
1265 rhs_loc, rhs, TREE_TYPE (rhs));
1267 break;
1268 case DECL_EXPR:
1270 tree x = DECL_EXPR_DECL (*tp);
1271 if (DECL_INITIAL (x))
1273 location_t loc = DECL_SOURCE_LOCATION (x);
1274 tree lhs = x;
1275 tree rhs = DECL_INITIAL (x);
1276 DECL_INITIAL (x) = NULL;
1277 tree new_modify_expr = build_modify_expr (loc, lhs,
1278 TREE_TYPE (lhs),
1279 NOP_EXPR,
1280 loc, rhs,
1281 TREE_TYPE(rhs));
1282 expand_array_notations (&new_modify_expr, walk_subtrees, NULL);
1283 *tp = new_modify_expr;
1286 break;
1287 case CALL_EXPR:
1288 *tp = fix_array_notation_call_expr (*tp);
1289 break;
1290 case RETURN_EXPR:
1291 *tp = fix_return_expr (*tp);
1292 break;
1293 case COMPOUND_EXPR:
1294 if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR)
1296 /* In here we are calling expand_array_notations because
1297 we need to be able to catch the return value and check if
1298 it is an error_mark_node. */
1299 expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL);
1301 /* SAVE_EXPR cannot have an error_mark_node inside it. This check
1302 will make sure that if there is an error in expanding of
1303 array notations (e.g. rank mismatch) then replace the entire
1304 SAVE_EXPR with an error_mark_node. */
1305 if (TREE_OPERAND (*tp, 1) == error_mark_node)
1306 *tp = error_mark_node;
1308 break;
1309 case ARRAY_NOTATION_REF:
1310 /* If we are here, then we are dealing with cases like this:
1311 A[:];
1312 A[x:y:z];
1313 A[x:y];
1314 Replace those with just void zero node. */
1315 *tp = void_zero_node;
1316 default:
1317 break;
1319 return NULL_TREE;
1322 /* Walks through tree node T and expands all array notations in its subtrees.
1323 The return value is the same type as T but with all array notations
1324 replaced with appropriate ARRAY_REFS with a loop around it. */
1326 tree
1327 expand_array_notation_exprs (tree t)
1329 walk_tree (&t, expand_array_notations, NULL, NULL);
1330 return t;
1333 /* This handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which
1334 denotes an array notation expression. If a is a variable or a member, then
1335 we generate a ARRAY_NOTATION_REF front-end tree and return it.
1336 This tree is broken down to ARRAY_REF toward the end of parsing.
1337 ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE
1338 of ARRAY_REF. Restrictions on START_INDEX, LENGTH and STRIDE is same as that
1339 of the index field passed into ARRAY_REF. The only additional restriction
1340 is that, unlike index in ARRAY_REF, stride, length and start_index cannot
1341 contain ARRAY_NOTATIONS. */
1343 tree
1344 build_array_notation_ref (location_t loc, tree array, tree start_index,
1345 tree length, tree stride, tree type)
1347 tree array_ntn_tree = NULL_TREE;
1348 size_t stride_rank = 0, length_rank = 0, start_rank = 0;
1350 if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
1352 error_at (loc,
1353 "start-index of array notation triplet is not an integer");
1354 return error_mark_node;
1356 if (!INTEGRAL_TYPE_P (TREE_TYPE (length)))
1358 error_at (loc, "length of array notation triplet is not an integer");
1359 return error_mark_node;
1362 /* The stride is an optional field. */
1363 if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
1365 error_at (loc, "stride of array notation triplet is not an integer");
1366 return error_mark_node;
1368 if (!stride)
1370 if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length)
1371 && tree_int_cst_lt (length, start_index))
1372 stride = build_int_cst (TREE_TYPE (start_index), -1);
1373 else
1374 stride = build_int_cst (TREE_TYPE (start_index), 1);
1377 if (!find_rank (loc, start_index, start_index, false, &start_rank))
1378 return error_mark_node;
1379 if (!find_rank (loc, length, length, false, &length_rank))
1380 return error_mark_node;
1381 if (!find_rank (loc, stride, stride, false, &stride_rank))
1382 return error_mark_node;
1384 if (start_rank != 0)
1386 error_at (loc, "rank of an array notation triplet's start-index is not "
1387 "zero");
1388 return error_mark_node;
1390 if (length_rank != 0)
1392 error_at (loc, "rank of an array notation triplet's length is not zero");
1393 return error_mark_node;
1395 if (stride_rank != 0)
1397 error_at (loc, "rank of array notation triplet's stride is not zero");
1398 return error_mark_node;
1400 array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE,
1401 NULL_TREE, NULL_TREE);
1402 ARRAY_NOTATION_ARRAY (array_ntn_tree) = array;
1403 ARRAY_NOTATION_START (array_ntn_tree) = start_index;
1404 ARRAY_NOTATION_LENGTH (array_ntn_tree) = length;
1405 ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride;
1406 TREE_TYPE (array_ntn_tree) = type;
1408 return array_ntn_tree;