2014-01-24 Ed Smith-Rowland <3dw4rd@verizon.net>
[official-gcc.git] / gcc / c / c-array-notation.c
blob6a5631c3b6f530b134f1364734d74cd7111f79aa
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 "tree-iterator.h"
74 #include "opts.h"
75 #include "c-family/c-common.h"
77 /* If *VALUE is not of type INTEGER_CST, PARM_DECL or VAR_DECL, then map it
78 to a variable and then set *VALUE to the new variable. */
80 static inline void
81 make_triplet_val_inv (location_t loc, tree *value)
83 tree var, new_exp;
84 if (TREE_CODE (*value) != INTEGER_CST
85 && TREE_CODE (*value) != PARM_DECL
86 && TREE_CODE (*value) != VAR_DECL)
88 var = build_decl (loc, VAR_DECL, NULL_TREE, integer_type_node);
89 new_exp = build_modify_expr (loc, var, TREE_TYPE (var), NOP_EXPR, loc,
90 *value, TREE_TYPE (*value));
91 add_stmt (new_exp);
92 *value = var;
96 /* Populates the INCR and CMP vectors with the increment (of type POSTINCREMENT
97 or POSTDECREMENT) and comparison (of TYPE GT_EXPR or LT_EXPR) expressions,
98 using data from LENGTH, COUNT_DOWN, and VAR. INCR and CMP vectors are of
99 size RANK. */
101 static void
102 create_cmp_incr (location_t loc, vec<an_loop_parts> *node, size_t rank,
103 vec<vec<an_parts> > an_info)
105 for (size_t ii = 0; ii < rank; ii++)
107 tree var = (*node)[ii].var;
108 tree length = an_info[0][ii].length;
109 (*node)[ii].incr = build_unary_op (loc, POSTINCREMENT_EXPR, var, 0);
110 (*node)[ii].cmp = build2 (LT_EXPR, boolean_type_node, var, length);
114 /* Returns a vector of size RANK that contains an array ref that is derived from
115 array notation triplet parameters stored in VALUE, START, STRIDE. IS_VECTOR
116 is used to check if the data stored at its corresponding location is an
117 array notation. VAR is the induction variable passed in by the caller.
119 For example: For an array notation A[5:10:2], the vector start will be
120 of size 1 holding '5', stride of same size as start but holding the value of
121 as 2, is_vector as true and count_down as false. Let's assume VAR is 'x'
122 This function returns a vector of size 1 with the following data:
123 A[5 + (x * 2)] .
126 static vec<tree, va_gc> *
127 create_array_refs (location_t loc, vec<vec<an_parts> > an_info,
128 vec<an_loop_parts> an_loop_info, size_t size, size_t rank)
130 tree ind_mult, ind_incr;
131 vec<tree, va_gc> *array_operand = NULL;
132 for (size_t ii = 0; ii < size; ii++)
133 if (an_info[ii][0].is_vector)
135 tree array_opr = an_info[ii][rank - 1].value;
136 for (int s_jj = rank - 1; s_jj >= 0; s_jj--)
138 tree var = an_loop_info[s_jj].var;
139 tree stride = an_info[ii][s_jj].stride;
140 tree start = an_info[ii][s_jj].start;
141 ind_mult = build2 (MULT_EXPR, TREE_TYPE (var), var, stride);
142 ind_incr = build2 (PLUS_EXPR, TREE_TYPE (var), start, ind_mult);
143 array_opr = build_array_ref (loc, array_opr, ind_incr);
145 vec_safe_push (array_operand, array_opr);
147 else
148 /* This is just a dummy node to make sure both the list sizes for both
149 array list and array operand list are the same. */
150 vec_safe_push (array_operand, integer_one_node);
151 return array_operand;
154 /* Replaces all the scalar expressions in *NODE. Returns a STATEMENT_LIST that
155 holds the NODE along with variables that holds the results of the invariant
156 expressions. */
158 tree
159 replace_invariant_exprs (tree *node)
161 size_t ix = 0;
162 tree node_list = NULL_TREE;
163 tree t = NULL_TREE, new_var = NULL_TREE, new_node;
164 struct inv_list data;
166 data.list_values = NULL;
167 data.replacement = NULL;
168 data.additional_tcodes = NULL;
169 walk_tree (node, find_inv_trees, (void *)&data, NULL);
171 if (vec_safe_length (data.list_values))
173 node_list = push_stmt_list ();
174 for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++)
176 new_var = build_decl (EXPR_LOCATION (t), VAR_DECL, NULL_TREE,
177 TREE_TYPE (t));
178 gcc_assert (new_var != NULL_TREE && new_var != error_mark_node);
179 new_node = build2 (MODIFY_EXPR, TREE_TYPE (t), new_var, t);
180 add_stmt (new_node);
181 vec_safe_push (data.replacement, new_var);
183 walk_tree (node, replace_inv_trees, (void *)&data, NULL);
184 node_list = pop_stmt_list (node_list);
186 return node_list;
189 /* Given a CALL_EXPR to an array notation built-in function in
190 AN_BUILTIN_FN, replace the call with the appropriate loop and
191 computation. Return the computation in *NEW_VAR.
193 The return value in *NEW_VAR will always be a scalar. If the
194 built-in is __sec_reduce_mutating, *NEW_VAR is set to NULL_TREE. */
196 static tree
197 fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var)
199 tree new_var_type = NULL_TREE, func_parm, new_expr, new_yes_expr, new_no_expr;
200 tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list;
201 tree new_yes_list, new_cond_expr, new_var_init = NULL_TREE;
202 tree new_exp_init = NULL_TREE;
203 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
204 size_t list_size = 0, rank = 0, ii = 0;
205 tree loop_init, array_op0;
206 tree identity_value = NULL_TREE, call_fn = NULL_TREE, new_call_expr, body;
207 location_t location = UNKNOWN_LOCATION;
208 tree loop_with_init = alloc_stmt_list ();
209 vec<vec<an_parts> > an_info = vNULL;
210 vec<an_loop_parts> an_loop_info = vNULL;
211 enum built_in_function an_type =
212 is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn));
213 if (an_type == BUILT_IN_NONE)
214 return NULL_TREE;
216 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE
217 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
219 call_fn = CALL_EXPR_ARG (an_builtin_fn, 2);
220 if (TREE_CODE (call_fn) == ADDR_EXPR)
221 call_fn = TREE_OPERAND (call_fn, 0);
222 identity_value = CALL_EXPR_ARG (an_builtin_fn, 0);
223 func_parm = CALL_EXPR_ARG (an_builtin_fn, 1);
225 else
226 func_parm = CALL_EXPR_ARG (an_builtin_fn, 0);
228 /* Fully fold any EXCESSIVE_PRECISION EXPR that can occur in the function
229 parameter. */
230 func_parm = c_fully_fold (func_parm, false, NULL);
232 location = EXPR_LOCATION (an_builtin_fn);
234 if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank))
235 return error_mark_node;
237 if (rank == 0)
238 return an_builtin_fn;
239 else if (rank > 1
240 && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
241 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND))
243 error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot"
244 " have arrays with dimension greater than 1");
245 return error_mark_node;
248 extract_array_notation_exprs (func_parm, true, &array_list);
249 list_size = vec_safe_length (array_list);
250 switch (an_type)
252 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
253 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
254 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
255 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
256 new_var_type = TREE_TYPE ((*array_list)[0]);
257 break;
258 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
259 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
260 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
261 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
262 new_var_type = integer_type_node;
263 break;
264 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
265 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
266 new_var_type = integer_type_node;
267 break;
268 case BUILT_IN_CILKPLUS_SEC_REDUCE:
269 if (call_fn && identity_value)
270 new_var_type = TREE_TYPE ((*array_list)[0]);
271 break;
272 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
273 new_var_type = NULL_TREE;
274 break;
275 default:
276 gcc_unreachable ();
279 an_loop_info.safe_grow_cleared (rank);
280 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
281 loop_init = alloc_stmt_list ();
283 for (ii = 0; ii < rank; ii++)
285 an_loop_info[ii].var = build_decl (location, VAR_DECL, NULL_TREE,
286 integer_type_node);
287 an_loop_info[ii].ind_init =
288 build_modify_expr (location, an_loop_info[ii].var,
289 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
290 location,
291 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
292 TREE_TYPE (an_loop_info[ii].var));
294 array_operand = create_array_refs (location, an_info, an_loop_info,
295 list_size, rank);
296 replace_array_notations (&func_parm, true, array_list, array_operand);
298 create_cmp_incr (location, &an_loop_info, rank, an_info);
299 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
301 *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type);
302 gcc_assert (*new_var && *new_var != error_mark_node);
304 else
305 *new_var = NULL_TREE;
307 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
308 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
309 array_ind_value = build_decl (location, VAR_DECL, NULL_TREE,
310 TREE_TYPE (func_parm));
311 array_op0 = (*array_operand)[0];
312 switch (an_type)
314 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
315 new_var_init = build_modify_expr
316 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
317 location, build_zero_cst (new_var_type), new_var_type);
318 new_expr = build_modify_expr
319 (location, *new_var, TREE_TYPE (*new_var), PLUS_EXPR,
320 location, func_parm, TREE_TYPE (func_parm));
321 break;
322 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
323 new_var_init = build_modify_expr
324 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
325 location, build_one_cst (new_var_type), new_var_type);
326 new_expr = build_modify_expr
327 (location, *new_var, TREE_TYPE (*new_var), MULT_EXPR,
328 location, func_parm, TREE_TYPE (func_parm));
329 break;
330 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
331 new_var_init = build_modify_expr
332 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
333 location, build_one_cst (new_var_type), new_var_type);
334 /* Initially you assume everything is zero, now if we find a case where
335 it is NOT true, then we set the result to false. Otherwise
336 we just keep the previous value. */
337 new_yes_expr = build_modify_expr
338 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
339 location, build_zero_cst (TREE_TYPE (*new_var)),
340 TREE_TYPE (*new_var));
341 new_no_expr = build_modify_expr
342 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
343 location, *new_var, TREE_TYPE (*new_var));
344 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
345 build_zero_cst (TREE_TYPE (func_parm)));
346 new_expr = build_conditional_expr
347 (location, new_cond_expr, false, new_yes_expr,
348 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
349 break;
350 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
351 new_var_init = build_modify_expr
352 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
353 location, build_one_cst (new_var_type), new_var_type);
354 /* Initially you assume everything is non-zero, now if we find a case
355 where it is NOT true, then we set the result to false. Otherwise
356 we just keep the previous value. */
357 new_yes_expr = build_modify_expr
358 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
359 location, build_zero_cst (TREE_TYPE (*new_var)),
360 TREE_TYPE (*new_var));
361 new_no_expr = build_modify_expr
362 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
363 location, *new_var, TREE_TYPE (*new_var));
364 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
365 build_zero_cst (TREE_TYPE (func_parm)));
366 new_expr = build_conditional_expr
367 (location, new_cond_expr, false, new_yes_expr,
368 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
369 break;
370 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
371 new_var_init = build_modify_expr
372 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
373 location, build_zero_cst (new_var_type), new_var_type);
374 /* Initially we assume there are NO zeros in the list. When we find
375 a non-zero, we keep the previous value. If we find a zero, we
376 set the value to true. */
377 new_yes_expr = build_modify_expr
378 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
379 location, build_one_cst (new_var_type), new_var_type);
380 new_no_expr = build_modify_expr
381 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
382 location, *new_var, TREE_TYPE (*new_var));
383 new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
384 build_zero_cst (TREE_TYPE (func_parm)));
385 new_expr = build_conditional_expr
386 (location, new_cond_expr, false, new_yes_expr,
387 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
388 break;
389 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
390 new_var_init = build_modify_expr
391 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
392 location, build_zero_cst (new_var_type), new_var_type);
393 /* Initially we assume there are NO non-zeros in the list. When we find
394 a zero, we keep the previous value. If we find a non-zero, we set
395 the value to true. */
396 new_yes_expr = build_modify_expr
397 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
398 location, build_one_cst (new_var_type), new_var_type);
399 new_no_expr = build_modify_expr
400 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
401 location, *new_var, TREE_TYPE (*new_var));
402 new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
403 build_zero_cst (TREE_TYPE (func_parm)));
404 new_expr = build_conditional_expr
405 (location, new_cond_expr, false, new_yes_expr,
406 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
407 break;
408 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
409 if (TYPE_MIN_VALUE (new_var_type))
410 new_var_init = build_modify_expr
411 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
412 location, TYPE_MIN_VALUE (new_var_type), new_var_type);
413 else
414 new_var_init = build_modify_expr
415 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
416 location, func_parm, new_var_type);
417 new_no_expr = build_modify_expr
418 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
419 location, *new_var, TREE_TYPE (*new_var));
420 new_yes_expr = build_modify_expr
421 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
422 location, func_parm, TREE_TYPE (*new_var));
423 new_expr = build_conditional_expr
424 (location,
425 build2 (LT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
426 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
427 break;
428 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
429 if (TYPE_MAX_VALUE (new_var_type))
430 new_var_init = build_modify_expr
431 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
432 location, TYPE_MAX_VALUE (new_var_type), new_var_type);
433 else
434 new_var_init = build_modify_expr
435 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
436 location, func_parm, new_var_type);
437 new_no_expr = build_modify_expr
438 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
439 location, *new_var, TREE_TYPE (*new_var));
440 new_yes_expr = build_modify_expr
441 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
442 location, func_parm, TREE_TYPE (*new_var));
443 new_expr = build_conditional_expr
444 (location,
445 build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
446 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
447 break;
448 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
449 new_var_init = build_modify_expr
450 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
451 location, build_zero_cst (new_var_type), new_var_type);
452 new_exp_init = build_modify_expr
453 (location, array_ind_value, TREE_TYPE (array_ind_value),
454 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
455 new_no_ind = build_modify_expr
456 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
457 location, *new_var, TREE_TYPE (*new_var));
458 new_no_expr = build_modify_expr
459 (location, array_ind_value, TREE_TYPE (array_ind_value),
460 NOP_EXPR,
461 location, array_ind_value, TREE_TYPE (array_ind_value));
462 if (list_size > 1)
464 new_yes_ind = build_modify_expr
465 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
466 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
467 new_yes_expr = build_modify_expr
468 (location, array_ind_value, TREE_TYPE (array_ind_value),
469 NOP_EXPR,
470 location, func_parm, TREE_TYPE ((*array_operand)[0]));
472 else
474 new_yes_ind = build_modify_expr
475 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
476 location, TREE_OPERAND (array_op0, 1),
477 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
478 new_yes_expr = build_modify_expr
479 (location, array_ind_value, TREE_TYPE (array_ind_value),
480 NOP_EXPR,
481 location, func_parm, TREE_OPERAND (array_op0, 1));
483 new_yes_list = alloc_stmt_list ();
484 append_to_statement_list (new_yes_ind, &new_yes_list);
485 append_to_statement_list (new_yes_expr, &new_yes_list);
487 new_no_list = alloc_stmt_list ();
488 append_to_statement_list (new_no_ind, &new_no_list);
489 append_to_statement_list (new_no_expr, &new_no_list);
491 new_expr = build_conditional_expr
492 (location,
493 build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
494 func_parm),
495 false,
496 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
497 break;
498 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
499 new_var_init = build_modify_expr
500 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
501 location, build_zero_cst (new_var_type), new_var_type);
502 new_exp_init = build_modify_expr
503 (location, array_ind_value, TREE_TYPE (array_ind_value),
504 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
505 new_no_ind = build_modify_expr
506 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
507 location, *new_var, TREE_TYPE (*new_var));
508 new_no_expr = build_modify_expr
509 (location, array_ind_value, TREE_TYPE (array_ind_value),
510 NOP_EXPR,
511 location, array_ind_value, TREE_TYPE (array_ind_value));
512 if (list_size > 1)
514 new_yes_ind = build_modify_expr
515 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
516 location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
517 new_yes_expr = build_modify_expr
518 (location, array_ind_value, TREE_TYPE (array_ind_value),
519 NOP_EXPR,
520 location, func_parm, TREE_TYPE (array_op0));
522 else
524 new_yes_ind = build_modify_expr
525 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
526 location, TREE_OPERAND (array_op0, 1),
527 TREE_TYPE (TREE_OPERAND (array_op0, 1)));
528 new_yes_expr = build_modify_expr
529 (location, array_ind_value, TREE_TYPE (array_ind_value),
530 NOP_EXPR,
531 location, func_parm, TREE_OPERAND (array_op0, 1));
533 new_yes_list = alloc_stmt_list ();
534 append_to_statement_list (new_yes_ind, &new_yes_list);
535 append_to_statement_list (new_yes_expr, &new_yes_list);
537 new_no_list = alloc_stmt_list ();
538 append_to_statement_list (new_no_ind, &new_no_list);
539 append_to_statement_list (new_no_expr, &new_no_list);
541 new_expr = build_conditional_expr
542 (location,
543 build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
544 func_parm),
545 false,
546 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
547 break;
548 case BUILT_IN_CILKPLUS_SEC_REDUCE:
549 new_var_init = build_modify_expr
550 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
551 location, identity_value, new_var_type);
552 new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm);
553 new_expr = build_modify_expr
554 (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
555 location, new_call_expr, TREE_TYPE (*new_var));
556 break;
557 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
558 new_expr = build_call_expr (call_fn, 2, identity_value, func_parm);
559 break;
560 default:
561 gcc_unreachable ();
562 break;
565 for (ii = 0; ii < rank; ii++)
566 append_to_statement_list (an_loop_info[ii].ind_init, &loop_init);
568 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
569 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
570 append_to_statement_list (new_exp_init, &loop_init);
571 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
572 append_to_statement_list (new_var_init, &loop_init);
574 append_to_statement_list_force (loop_init, &loop_with_init);
575 body = new_expr;
576 for (ii = 0; ii < rank; ii++)
578 tree new_loop = push_stmt_list ();
579 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
580 body, NULL_TREE, NULL_TREE, true);
581 body = pop_stmt_list (new_loop);
583 append_to_statement_list_force (body, &loop_with_init);
585 an_info.release ();
586 an_loop_info.release ();
588 return loop_with_init;
591 /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
592 The LHS and/or RHS will be array notation expressions that have a MODIFYCODE
593 Their locations are specified by LHS_LOC, RHS_LOC. The location of the
594 modify expression is location. The original type of LHS and RHS are passed
595 in LHS_ORIGTYPE and RHS_ORIGTYPE. */
597 tree
598 build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
599 enum tree_code modifycode, location_t rhs_loc,
600 tree rhs, tree rhs_origtype)
602 bool found_builtin_fn = false;
603 tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
604 tree array_expr = NULL_TREE;
605 tree an_init = NULL_TREE;
606 vec<tree> cond_expr = vNULL;
607 tree body, loop_with_init = alloc_stmt_list();
608 tree scalar_mods = NULL_TREE;
609 vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL;
610 size_t lhs_rank = 0, rhs_rank = 0;
611 size_t ii = 0;
612 vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL;
613 tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE;
614 size_t rhs_list_size = 0, lhs_list_size = 0;
615 vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
616 vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL;
618 /* If either of this is true, an error message must have been send out
619 already. Not necessary to send out multiple error messages. */
620 if (lhs == error_mark_node || rhs == error_mark_node)
621 return error_mark_node;
623 if (!find_rank (location, rhs, rhs, false, &rhs_rank))
624 return error_mark_node;
626 extract_array_notation_exprs (rhs, false, &rhs_list);
627 rhs_list_size = vec_safe_length (rhs_list);
628 an_init = push_stmt_list ();
629 if (rhs_rank)
631 scalar_mods = replace_invariant_exprs (&rhs);
632 if (scalar_mods)
633 add_stmt (scalar_mods);
635 for (ii = 0; ii < rhs_list_size; ii++)
637 tree rhs_node = (*rhs_list)[ii];
638 if (TREE_CODE (rhs_node) == CALL_EXPR)
640 builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
641 if (builtin_loop == error_mark_node)
643 pop_stmt_list (an_init);
644 return error_mark_node;
646 else if (builtin_loop)
648 add_stmt (builtin_loop);
649 found_builtin_fn = true;
650 if (new_var)
652 vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
653 vec_safe_push (rhs_sub_list, rhs_node);
654 vec_safe_push (new_var_list, new_var);
655 replace_array_notations (&rhs, false, rhs_sub_list,
656 new_var_list);
662 lhs_rank = 0;
663 rhs_rank = 0;
664 if (!find_rank (location, lhs, lhs, true, &lhs_rank))
666 pop_stmt_list (an_init);
667 return error_mark_node;
670 if (!find_rank (location, rhs, rhs, true, &rhs_rank))
672 pop_stmt_list (an_init);
673 return error_mark_node;
676 if (lhs_rank == 0 && rhs_rank == 0)
678 if (found_builtin_fn)
680 new_modify_expr = build_modify_expr (location, lhs, lhs_origtype,
681 modifycode, rhs_loc, rhs,
682 rhs_origtype);
683 add_stmt (new_modify_expr);
684 pop_stmt_list (an_init);
685 return an_init;
687 else
689 pop_stmt_list (an_init);
690 return NULL_TREE;
693 rhs_list_size = 0;
694 rhs_list = NULL;
695 extract_array_notation_exprs (rhs, true, &rhs_list);
696 extract_array_notation_exprs (lhs, true, &lhs_list);
697 rhs_list_size = vec_safe_length (rhs_list);
698 lhs_list_size = vec_safe_length (lhs_list);
700 if (lhs_rank == 0 && rhs_rank != 0)
702 tree rhs_base = rhs;
703 if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
705 for (ii = 0; ii < (size_t) rhs_rank; ii++)
706 rhs_base = ARRAY_NOTATION_ARRAY (rhs);
708 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
709 rhs_base);
710 return error_mark_node;
712 else
714 error_at (location, "%qE cannot be scalar when %qE is not", lhs,
715 rhs_base);
716 return error_mark_node;
719 if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
721 error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
722 pop_stmt_list (an_init);
723 return error_mark_node;
726 /* Here we assign the array notation components to variable so that we can
727 satisfy the exec once rule. */
728 for (ii = 0; ii < lhs_list_size; ii++)
730 tree array_node = (*lhs_list)[ii];
731 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
732 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
733 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
735 for (ii = 0; ii < rhs_list_size; ii++)
736 if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
738 tree array_node = (*rhs_list)[ii];
739 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
740 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
741 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
744 cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
746 lhs_an_loop_info.safe_grow_cleared (lhs_rank);
747 if (rhs_rank)
748 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
750 cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
751 &lhs_an_info);
752 if (rhs_rank)
754 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
755 cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
756 &rhs_an_info);
758 if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
759 || (rhs_rank
760 && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info)))
762 pop_stmt_list (an_init);
763 return error_mark_node;
765 if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
766 && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST
767 && rhs_an_info[0][0].length
768 && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST)
770 HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length);
771 HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length);
772 /* Length can be negative or positive. As long as the magnitude is OK,
773 then the array notation is valid. */
774 if (absu_hwi (l_length) != absu_hwi (r_length))
776 error_at (location, "length mismatch between LHS and RHS");
777 pop_stmt_list (an_init);
778 return error_mark_node;
781 for (ii = 0; ii < lhs_rank; ii++)
782 if (lhs_an_info[0][ii].is_vector)
784 lhs_an_loop_info[ii].var = build_decl (location, VAR_DECL, NULL_TREE,
785 integer_type_node);
786 lhs_an_loop_info[ii].ind_init = build_modify_expr
787 (location, lhs_an_loop_info[ii].var,
788 TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR,
789 location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)),
790 TREE_TYPE (lhs_an_loop_info[ii].var));
792 for (ii = 0; ii < rhs_rank; ii++)
794 /* When we have a polynomial, we assume that the indices are of type
795 integer. */
796 rhs_an_loop_info[ii].var = build_decl (location, VAR_DECL, NULL_TREE,
797 integer_type_node);
798 rhs_an_loop_info[ii].ind_init = build_modify_expr
799 (location, rhs_an_loop_info[ii].var,
800 TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR,
801 location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0),
802 TREE_TYPE (rhs_an_loop_info[ii].var));
804 if (lhs_rank)
806 lhs_array_operand = create_array_refs
807 (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank);
808 replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
809 array_expr_lhs = lhs;
811 if (rhs_array_operand)
812 vec_safe_truncate (rhs_array_operand, 0);
813 if (rhs_rank)
815 rhs_array_operand = create_array_refs
816 (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank);
817 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
818 vec_safe_truncate (rhs_array_operand, 0);
819 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
820 rhs_an_loop_info, rhs_rank,
821 rhs);
822 if (!rhs_array_operand)
823 return error_mark_node;
824 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
826 else if (rhs_list_size > 0)
828 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
829 lhs_an_loop_info, lhs_rank,
830 lhs);
831 if (!rhs_array_operand)
832 return error_mark_node;
833 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
835 array_expr_lhs = lhs;
836 array_expr_rhs = rhs;
837 array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype,
838 modifycode, rhs_loc, array_expr_rhs,
839 rhs_origtype);
840 create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info);
841 if (rhs_rank)
842 create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info);
844 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
845 if (ii < lhs_rank && ii < rhs_rank)
846 cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node,
847 lhs_an_loop_info[ii].cmp,
848 rhs_an_loop_info[ii].cmp);
849 else if (ii < lhs_rank && ii >= rhs_rank)
850 cond_expr[ii] = lhs_an_loop_info[ii].cmp;
851 else
852 gcc_unreachable ();
854 an_init = pop_stmt_list (an_init);
855 append_to_statement_list_force (an_init, &loop_with_init);
856 body = array_expr;
857 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
859 tree incr_list = alloc_stmt_list ();
860 tree new_loop = push_stmt_list ();
861 if (lhs_rank)
862 add_stmt (lhs_an_loop_info[ii].ind_init);
863 if (rhs_rank)
864 add_stmt (rhs_an_loop_info[ii].ind_init);
865 if (lhs_rank)
866 append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list);
867 if (rhs_rank && rhs_an_loop_info[ii].incr)
868 append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list);
869 c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE,
870 NULL_TREE, true);
871 body = pop_stmt_list (new_loop);
873 append_to_statement_list_force (body, &loop_with_init);
875 lhs_an_info.release ();
876 lhs_an_loop_info.release ();
877 if (rhs_rank)
879 rhs_an_info.release ();
880 rhs_an_loop_info.release ();
882 cond_expr.release ();
883 return loop_with_init;
886 /* Helper function for fix_conditional_array_notations. Encloses the
887 conditional statement passed in STMT with a loop around it
888 and replaces the condition in STMT with a ARRAY_REF tree-node to the array.
889 The condition must have an ARRAY_NOTATION_REF tree. An expansion of array
890 notation in STMT is returned in a STATEMENT_LIST. */
892 static tree
893 fix_conditional_array_notations_1 (tree stmt)
895 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
896 size_t list_size = 0;
897 tree cond = NULL_TREE, builtin_loop = NULL_TREE, new_var = NULL_TREE;
898 size_t rank = 0, ii = 0;
899 tree loop_init;
900 location_t location = EXPR_LOCATION (stmt);
901 tree body = NULL_TREE, loop_with_init = alloc_stmt_list ();
902 vec<vec<an_parts> > an_info = vNULL;
903 vec<an_loop_parts> an_loop_info = vNULL;
905 if (TREE_CODE (stmt) == COND_EXPR)
906 cond = COND_EXPR_COND (stmt);
907 else if (TREE_CODE (stmt) == SWITCH_EXPR)
908 cond = SWITCH_COND (stmt);
909 else if (truth_value_p (TREE_CODE (stmt)))
910 cond = TREE_OPERAND (stmt, 0);
911 else
912 /* Otherwise dont even touch the statement. */
913 return stmt;
915 if (!find_rank (location, cond, cond, false, &rank))
916 return error_mark_node;
918 extract_array_notation_exprs (stmt, false, &array_list);
919 loop_init = push_stmt_list ();
920 for (ii = 0; ii < vec_safe_length (array_list); ii++)
922 tree array_node = (*array_list)[ii];
923 if (TREE_CODE (array_node) == CALL_EXPR)
925 builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var);
926 if (builtin_loop == error_mark_node)
928 add_stmt (error_mark_node);
929 pop_stmt_list (loop_init);
930 return loop_init;
932 else if (builtin_loop)
934 vec <tree, va_gc>* sub_list = NULL, *new_var_list = NULL;
935 vec_safe_push (sub_list, array_node);
936 vec_safe_push (new_var_list, new_var);
937 add_stmt (builtin_loop);
938 replace_array_notations (&stmt, false, sub_list, new_var_list);
942 if (!find_rank (location, stmt, stmt, true, &rank))
944 pop_stmt_list (loop_init);
945 return error_mark_node;
947 if (rank == 0)
949 add_stmt (stmt);
950 pop_stmt_list (loop_init);
951 return loop_init;
953 extract_array_notation_exprs (stmt, true, &array_list);
955 if (vec_safe_length (array_list) == 0)
956 return stmt;
958 list_size = vec_safe_length (array_list);
959 an_loop_info.safe_grow_cleared (rank);
961 for (ii = 0; ii < list_size; ii++)
962 if ((*array_list)[ii]
963 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
965 tree array_node = (*array_list)[ii];
966 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
967 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
968 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
970 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
971 for (ii = 0; ii < rank; ii++)
973 an_loop_info[ii].var = build_decl (location, VAR_DECL, NULL_TREE,
974 integer_type_node);
975 an_loop_info[ii].ind_init =
976 build_modify_expr (location, an_loop_info[ii].var,
977 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
978 location,
979 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
980 TREE_TYPE (an_loop_info[ii].var));
982 array_operand = create_array_refs (location, an_info, an_loop_info,
983 list_size, rank);
984 replace_array_notations (&stmt, true, array_list, array_operand);
985 create_cmp_incr (location, &an_loop_info, rank, an_info);
987 loop_init = pop_stmt_list (loop_init);
988 body = stmt;
989 append_to_statement_list_force (loop_init, &loop_with_init);
991 for (ii = 0; ii < rank; ii++)
993 tree new_loop = push_stmt_list ();
994 add_stmt (an_loop_info[ii].ind_init);
995 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
996 body, NULL_TREE, NULL_TREE, true);
997 body = pop_stmt_list (new_loop);
999 append_to_statement_list_force (body, &loop_with_init);
1001 an_loop_info.release ();
1002 an_info.release ();
1004 return loop_with_init;
1007 /* Top-level function to replace ARRAY_NOTATION_REF in a conditional statement
1008 in STMT. An expansion of array notation in STMT is returned as a
1009 STATEMENT_LIST. */
1011 tree
1012 fix_conditional_array_notations (tree stmt)
1014 if (TREE_CODE (stmt) == STATEMENT_LIST)
1016 tree_stmt_iterator tsi;
1017 for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi))
1019 tree single_stmt = *tsi_stmt_ptr (tsi);
1020 *tsi_stmt_ptr (tsi) =
1021 fix_conditional_array_notations_1 (single_stmt);
1023 return stmt;
1025 else
1026 return fix_conditional_array_notations_1 (stmt);
1029 /* Create a struct c_expr that contains a loop with ARRAY_REF expr at location
1030 LOCATION with the tree_code CODE and the array notation expr is
1031 passed in ARG. Returns the fixed c_expr in ARG itself. */
1033 struct c_expr
1034 fix_array_notation_expr (location_t location, enum tree_code code,
1035 struct c_expr arg)
1038 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1039 size_t list_size = 0, rank = 0, ii = 0;
1040 tree loop_init;
1041 tree body, loop_with_init = alloc_stmt_list ();
1042 vec<vec<an_parts> > an_info = vNULL;
1043 vec<an_loop_parts> an_loop_info = vNULL;
1045 if (!find_rank (location, arg.value, arg.value, false, &rank))
1047 /* If this function returns a NULL, we convert the tree value in the
1048 structure to error_mark_node and the parser should take care of the
1049 rest. */
1050 arg.value = error_mark_node;
1051 return arg;
1054 if (rank == 0)
1055 return arg;
1057 extract_array_notation_exprs (arg.value, true, &array_list);
1059 if (vec_safe_length (array_list) == 0)
1060 return arg;
1062 list_size = vec_safe_length (array_list);
1064 an_loop_info.safe_grow_cleared (rank);
1065 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1067 loop_init = push_stmt_list ();
1068 for (ii = 0; ii < rank; ii++)
1070 an_loop_info[ii].var = build_decl (location, VAR_DECL, NULL_TREE,
1071 integer_type_node);
1072 an_loop_info[ii].ind_init =
1073 build_modify_expr (location, an_loop_info[ii].var,
1074 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
1075 location,
1076 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1077 TREE_TYPE (an_loop_info[ii].var));;
1080 array_operand = create_array_refs (location, an_info, an_loop_info,
1081 list_size, rank);
1082 replace_array_notations (&arg.value, true, array_list, array_operand);
1083 create_cmp_incr (location, &an_loop_info, rank, an_info);
1085 arg = default_function_array_read_conversion (location, arg);
1086 if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
1087 arg.value = build_unary_op (location, code, arg.value, 0);
1088 else if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
1089 arg = parser_build_unary_op (location, code, arg);
1091 loop_init = pop_stmt_list (loop_init);
1092 append_to_statement_list_force (loop_init, &loop_with_init);
1093 body = arg.value;
1095 for (ii = 0; ii < rank; ii++)
1097 tree new_loop = push_stmt_list ();
1098 add_stmt (an_loop_info[ii].ind_init);
1099 c_finish_loop (location, an_loop_info[ii].cmp,
1100 an_loop_info[ii].incr, body, NULL_TREE,
1101 NULL_TREE, true);
1102 body = pop_stmt_list (new_loop);
1104 append_to_statement_list_force (body, &loop_with_init);
1105 arg.value = loop_with_init;
1106 an_info.release ();
1107 an_loop_info.release ();
1108 return arg;
1111 /* Replaces array notations in a void function call arguments in ARG and returns
1112 a STATEMENT_LIST. */
1114 static tree
1115 fix_array_notation_call_expr (tree arg)
1117 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1118 tree new_var = NULL_TREE;
1119 size_t list_size = 0, rank = 0, ii = 0;
1120 tree loop_init;
1121 tree body, loop_with_init = alloc_stmt_list ();
1122 location_t location = UNKNOWN_LOCATION;
1123 vec<vec<an_parts> > an_info = vNULL;
1124 vec<an_loop_parts> an_loop_info = vNULL;
1126 if (TREE_CODE (arg) == CALL_EXPR
1127 && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg)))
1129 loop_init = fix_builtin_array_notation_fn (arg, &new_var);
1130 /* We are ignoring the new var because either the user does not want to
1131 capture it OR he is using sec_reduce_mutating function. */
1132 return loop_init;
1134 if (!find_rank (location, arg, arg, false, &rank))
1135 return error_mark_node;
1137 if (rank == 0)
1138 return arg;
1140 extract_array_notation_exprs (arg, true, &array_list);
1141 if (vec_safe_length (array_list) == 0)
1142 return arg;
1144 list_size = vec_safe_length (array_list);
1145 location = EXPR_LOCATION (arg);
1146 an_loop_info.safe_grow_cleared (rank);
1148 loop_init = push_stmt_list ();
1149 for (ii = 0; ii < list_size; ii++)
1150 if ((*array_list)[ii]
1151 && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
1153 tree array_node = (*array_list)[ii];
1154 make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
1155 make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
1156 make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
1158 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1159 if (length_mismatch_in_expr_p (location, an_info))
1161 pop_stmt_list (loop_init);
1162 return error_mark_node;
1164 for (ii = 0; ii < rank; ii++)
1166 an_loop_info[ii].var = build_decl (location, VAR_DECL, NULL_TREE,
1167 integer_type_node);
1168 an_loop_info[ii].ind_init =
1169 build_modify_expr (location, an_loop_info[ii].var,
1170 TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location,
1171 build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1172 TREE_TYPE (an_loop_info[ii].var));
1175 array_operand = create_array_refs (location, an_info, an_loop_info,
1176 list_size, rank);
1177 replace_array_notations (&arg, true, array_list, array_operand);
1178 create_cmp_incr (location, &an_loop_info, rank, an_info);
1179 loop_init = pop_stmt_list (loop_init);
1180 append_to_statement_list_force (loop_init, &loop_with_init);
1181 body = arg;
1182 for (ii = 0; ii < rank; ii++)
1184 tree new_loop = push_stmt_list ();
1185 add_stmt (an_loop_info[ii].ind_init);
1186 c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1187 body, NULL_TREE, NULL_TREE, true);
1188 body = pop_stmt_list (new_loop);
1190 append_to_statement_list_force (body, &loop_with_init);
1191 an_loop_info.release ();
1192 an_info.release ();
1193 return loop_with_init;
1196 /* Expands the built-in functions in a return. EXPR is a RETURN_EXPR with
1197 a built-in reduction function. This function returns the expansion code for
1198 the built-in function. */
1200 static tree
1201 fix_return_expr (tree expr)
1203 tree new_mod_list, new_var, new_mod, retval_expr, retval_type;
1204 location_t loc = EXPR_LOCATION (expr);
1206 new_mod_list = alloc_stmt_list ();
1207 retval_expr = TREE_OPERAND (expr, 0);
1208 retval_type = TREE_TYPE (TREE_OPERAND (retval_expr, 1));
1209 new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr));
1210 new_mod = build_array_notation_expr (loc, new_var, TREE_TYPE (new_var),
1211 NOP_EXPR, loc,
1212 TREE_OPERAND (retval_expr, 1),
1213 retval_type);
1214 TREE_OPERAND (retval_expr, 1) = new_var;
1215 TREE_OPERAND (expr, 0) = retval_expr;
1216 append_to_statement_list_force (new_mod, &new_mod_list);
1217 append_to_statement_list_force (expr, &new_mod_list);
1218 return new_mod_list;
1221 /* Callback for walk_tree. Expands all array notations in *TP. *WALK_SUBTREES
1222 is set to 1 unless *TP contains no array notation expressions. */
1224 static tree
1225 expand_array_notations (tree *tp, int *walk_subtrees, void *)
1227 if (!contains_array_notation_expr (*tp))
1229 *walk_subtrees = 0;
1230 return NULL_TREE;
1232 *walk_subtrees = 1;
1234 switch (TREE_CODE (*tp))
1236 case TRUTH_ORIF_EXPR:
1237 case TRUTH_ANDIF_EXPR:
1238 case TRUTH_OR_EXPR:
1239 case TRUTH_AND_EXPR:
1240 case TRUTH_XOR_EXPR:
1241 case TRUTH_NOT_EXPR:
1242 case COND_EXPR:
1243 *tp = fix_conditional_array_notations (*tp);
1244 break;
1245 case MODIFY_EXPR:
1247 location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) :
1248 UNKNOWN_LOCATION;
1249 tree lhs = TREE_OPERAND (*tp, 0);
1250 tree rhs = TREE_OPERAND (*tp, 1);
1251 location_t rhs_loc = EXPR_HAS_LOCATION (rhs) ? EXPR_LOCATION (rhs) :
1252 UNKNOWN_LOCATION;
1253 *tp = build_array_notation_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR,
1254 rhs_loc, rhs, TREE_TYPE (rhs));
1256 break;
1257 case CALL_EXPR:
1258 *tp = fix_array_notation_call_expr (*tp);
1259 break;
1260 case RETURN_EXPR:
1261 *tp = fix_return_expr (*tp);
1262 break;
1263 case COMPOUND_EXPR:
1264 if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR)
1266 /* In here we are calling expand_array_notations because
1267 we need to be able to catch the return value and check if
1268 it is an error_mark_node. */
1269 expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL);
1271 /* SAVE_EXPR cannot have an error_mark_node inside it. This check
1272 will make sure that if there is an error in expanding of
1273 array notations (e.g. rank mismatch) then replace the entire
1274 SAVE_EXPR with an error_mark_node. */
1275 if (TREE_OPERAND (*tp, 1) == error_mark_node)
1276 *tp = error_mark_node;
1278 break;
1279 case ARRAY_NOTATION_REF:
1280 /* If we are here, then we are dealing with cases like this:
1281 A[:];
1282 A[x:y:z];
1283 A[x:y];
1284 Replace those with just void zero node. */
1285 *tp = void_zero_node;
1286 default:
1287 break;
1289 return NULL_TREE;
1292 /* Walks through tree node T and expands all array notations in its subtrees.
1293 The return value is the same type as T but with all array notations
1294 replaced with appropriate ARRAY_REFS with a loop around it. */
1296 tree
1297 expand_array_notation_exprs (tree t)
1299 walk_tree (&t, expand_array_notations, NULL, NULL);
1300 return t;
1303 /* This handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which
1304 denotes an array notation expression. If a is a variable or a member, then
1305 we generate a ARRAY_NOTATION_REF front-end tree and return it.
1306 This tree is broken down to ARRAY_REF toward the end of parsing.
1307 ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE
1308 of ARRAY_REF. Restrictions on START_INDEX, LENGTH and STRIDE is same as that
1309 of the index field passed into ARRAY_REF. The only additional restriction
1310 is that, unlike index in ARRAY_REF, stride, length and start_index cannot
1311 contain ARRAY_NOTATIONS. */
1313 tree
1314 build_array_notation_ref (location_t loc, tree array, tree start_index,
1315 tree length, tree stride, tree type)
1317 tree array_ntn_tree = NULL_TREE;
1318 size_t stride_rank = 0, length_rank = 0, start_rank = 0;
1320 if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
1322 error_at (loc,
1323 "start-index of array notation triplet is not an integer");
1324 return error_mark_node;
1326 if (!INTEGRAL_TYPE_P (TREE_TYPE (length)))
1328 error_at (loc, "length of array notation triplet is not an integer");
1329 return error_mark_node;
1332 /* The stride is an optional field. */
1333 if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
1335 error_at (loc, "stride of array notation triplet is not an integer");
1336 return error_mark_node;
1338 if (!stride)
1340 if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length)
1341 && tree_int_cst_lt (length, start_index))
1342 stride = build_int_cst (TREE_TYPE (start_index), -1);
1343 else
1344 stride = build_int_cst (TREE_TYPE (start_index), 1);
1347 if (!find_rank (loc, start_index, start_index, false, &start_rank))
1348 return error_mark_node;
1349 if (!find_rank (loc, length, length, false, &length_rank))
1350 return error_mark_node;
1351 if (!find_rank (loc, stride, stride, false, &stride_rank))
1352 return error_mark_node;
1354 if (start_rank != 0)
1356 error_at (loc, "rank of an array notation triplet's start-index is not "
1357 "zero");
1358 return error_mark_node;
1360 if (length_rank != 0)
1362 error_at (loc, "rank of an array notation triplet's length is not zero");
1363 return error_mark_node;
1365 if (stride_rank != 0)
1367 error_at (loc, "rank of array notation triplet's stride is not zero");
1368 return error_mark_node;
1370 array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE,
1371 NULL_TREE, NULL_TREE);
1372 ARRAY_NOTATION_ARRAY (array_ntn_tree) = array;
1373 ARRAY_NOTATION_START (array_ntn_tree) = start_index;
1374 ARRAY_NOTATION_LENGTH (array_ntn_tree) = length;
1375 ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride;
1376 TREE_TYPE (array_ntn_tree) = type;
1378 return array_ntn_tree;