comparison gcc/cp/cp-array-notation.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children
comparison
equal deleted inserted replaced
68:561a7518be6b 111:04ced10e8804
1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2 It contains routines to handle Array Notation expression
3 handling routines in the C++ Compiler.
4 Copyright (C) 2013-2017 Free Software Foundation, Inc.
5 Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
6 Intel Corporation
7
8 This file is part of GCC.
9
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.
14
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.
19
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/>. */
23
24 /* The Array Notation Transformation Technique:
25
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 access (we call it length)
30 4. Stride
31
32 So, if we have something like A[0:5:2], 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.
35
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 step:
38
39 Let's say the user has used the array notation in a statement like this:
40
41 A[St1:Ln:Str1] = B[St2:Ln:Str2] + <NON ARRAY_NOT STMT>
42
43 where St{1,2} = Starting index, Ln = Number of elements we need to access,
44 and Str{1,2} = the stride.
45 Note: The length of both the array notation expressions must be the same.
46
47 The above expression is broken into the following:
48
49 for (Tmp_Var = 0; Tmp_Var < Ln; Tmp_Var++)
50 A[St1 + Tmp_Var * Str1] = B[St1 + Tmp_Var * Str2] + <NON_ARRAY_NOT_STMT>;
51 */
52
53 #include "config.h"
54 #include "system.h"
55 #include "coretypes.h"
56 #include "cp-tree.h"
57 #include "tree-iterator.h"
58
59 /* Creates a FOR_STMT with INIT, COND, INCR and BODY as the initializer,
60 condition, increment expression and the loop-body, respectively. */
61
62 static void
63 create_an_loop (tree init, tree cond, tree incr, tree body)
64 {
65 tree for_stmt;
66
67 finish_expr_stmt (init);
68 for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
69 finish_init_stmt (for_stmt);
70 finish_for_cond (cond, for_stmt, false);
71 finish_for_expr (incr, for_stmt);
72 finish_expr_stmt (body);
73 finish_for_stmt (for_stmt);
74 }
75
76 /* If *VALUE is not a constant integer, then this function replaces it with
77 a variable to make it loop invariant for array notations. */
78
79 static inline void
80 make_triplet_val_inv (tree *value)
81 {
82 if (TREE_CODE (*value) != INTEGER_CST
83 && TREE_CODE (*value) != PARM_DECL
84 && !VAR_P (*value))
85 *value = get_temp_regvar (ptrdiff_type_node, *value);
86 }
87
88 /* Returns a vector of size RANK that contains an ARRAY_REF. This vector is
89 created using array notation-triplet information stored in AN_INFO. The
90 induction var is taken from AN_LOOP_INFO.
91
92 For example: For an array notation A[5:10:2], the vector start will be
93 of size 1 holding '5', stride of same size as start but holding the value of
94 as 2, and is_vector as true. Let's assume VAR is 'x'
95 This function returns a vector of size 1 with the following data:
96 A[5 + (x * 2)] .
97 */
98
99 static vec<tree, va_gc> *
100 create_array_refs (location_t loc, vec<vec<an_parts> > an_info,
101 vec<an_loop_parts> an_loop_info, size_t size, size_t rank)
102 {
103 tree ind_mult, ind_incr;
104 vec<tree, va_gc> *array_operand = NULL;
105
106 for (size_t ii = 0; ii < size; ii++)
107 if (an_info[ii][0].is_vector)
108 {
109 tree array_opr = an_info[ii][rank - 1].value;
110 for (int s_jj = rank -1; s_jj >= 0; s_jj--)
111 {
112 tree start = cp_fold_convert (ptrdiff_type_node,
113 an_info[ii][s_jj].start);
114 tree stride = cp_fold_convert (ptrdiff_type_node,
115 an_info[ii][s_jj].stride);
116 tree var = cp_fold_convert (ptrdiff_type_node,
117 an_loop_info[s_jj].var);
118
119 ind_mult = build2 (MULT_EXPR, TREE_TYPE (var), var, stride);
120 ind_incr = build2 (PLUS_EXPR, TREE_TYPE (var), start, ind_mult);
121 /* Array [ start_index + (induction_var * stride)] */
122 array_opr = grok_array_decl (loc, array_opr, ind_incr, false);
123 }
124 vec_safe_push (array_operand, array_opr);
125 }
126 else
127 vec_safe_push (array_operand, integer_one_node);
128 return array_operand;
129 }
130
131 /* Populates the INCR and CMP fields in *NODE with the increment
132 (of type POSTINCREMENT) and comparison (of TYPE LT_EXPR) expressions, using
133 data from AN_INFO. */
134
135 void
136 create_cmp_incr (location_t loc, vec <an_loop_parts> *node, size_t rank,
137 vec<vec<an_parts> > an_info, tsubst_flags_t complain)
138 {
139 for (size_t ii = 0; ii < rank; ii++)
140 {
141 (*node)[ii].incr = build_x_unary_op (loc, POSTINCREMENT_EXPR,
142 (*node)[ii].var, complain);
143 (*node)[ii].cmp = build_x_binary_op (loc, LT_EXPR, (*node)[ii].var,
144 TREE_CODE ((*node)[ii].var),
145 an_info[0][ii].length,
146 TREE_CODE (an_info[0][ii].length),
147 NULL, complain);
148 }
149 }
150
151 /* Replaces all the scalar expressions in *NODE. Returns a STATEMENT LIST that
152 holds the NODE along with the variables that hold the results of the
153 invariant expressions. */
154
155 static tree
156 replace_invariant_exprs (tree *node)
157 {
158 size_t ix = 0;
159 tree node_list = NULL_TREE;
160 tree t = NULL_TREE, new_var = NULL_TREE;
161 struct inv_list data;
162
163 data.list_values = NULL;
164 data.replacement = NULL;
165 data.additional_tcodes = NULL;
166 cp_walk_tree (node, find_inv_trees, (void *) &data, NULL);
167
168 if (vec_safe_length (data.list_values))
169 {
170 node_list = push_stmt_list ();
171 for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++)
172 {
173 /* Sometimes, when comma_expr has a function call in it, it will
174 typecast it to void. Find_inv_trees finds those nodes and so
175 if it void type, then don't bother creating a new var to hold
176 the return value. */
177 if (VOID_TYPE_P (TREE_TYPE (t)))
178 {
179 finish_expr_stmt (t);
180 new_var = void_node;
181 }
182 else
183 new_var = get_temp_regvar (TREE_TYPE (t), t);
184 vec_safe_push (data.replacement, new_var);
185 }
186 cp_walk_tree (node, replace_inv_trees, (void *) &data, NULL);
187 node_list = pop_stmt_list (node_list);
188 }
189 return node_list;
190 }
191
192 /* Replace array notation's built-in function passed in AN_BUILTIN_FN with
193 the appropriate loop and computation (all stored in variable LOOP of type
194 tree node). The output of the function is always a scalar and that
195 result is returned in *NEW_VAR. *NEW_VAR is NULL_TREE if the function is
196 __sec_reduce_mutating. */
197
198 static tree
199 expand_sec_reduce_builtin (tree an_builtin_fn, tree *new_var)
200 {
201 tree new_var_type = NULL_TREE, func_parm, new_yes_expr, new_no_expr;
202 tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list;
203 tree new_yes_list, new_cond_expr, new_expr = 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 body, an_init, loop_with_init = alloc_stmt_list ();
207 tree array_op0, comp_node = NULL_TREE;
208 tree call_fn = NULL_TREE, identity_value = NULL_TREE;
209 tree init = NULL_TREE, cond_init = NULL_TREE;
210 enum tree_code code = NOP_EXPR;
211 location_t location = UNKNOWN_LOCATION;
212 vec<vec<an_parts> > an_info = vNULL;
213 auto_vec<an_loop_parts> an_loop_info;
214 enum built_in_function an_type =
215 is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn));
216 vec <tree, va_gc> *func_args;
217
218 if (an_type == BUILT_IN_NONE)
219 return NULL_TREE;
220
221 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE
222 && an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
223 func_parm = CALL_EXPR_ARG (an_builtin_fn, 0);
224 else
225 {
226 call_fn = CALL_EXPR_ARG (an_builtin_fn, 2);
227
228 /* We need to do this because we are "faking" the builtin function types,
229 so the compiler does a bunch of typecasts and this will get rid of
230 all that! */
231 STRIP_NOPS (call_fn);
232 if (TREE_CODE (call_fn) != OVERLOAD
233 && TREE_CODE (call_fn) != FUNCTION_DECL)
234 call_fn = TREE_OPERAND (call_fn, 0);
235 identity_value = CALL_EXPR_ARG (an_builtin_fn, 0);
236 func_parm = CALL_EXPR_ARG (an_builtin_fn, 1);
237 STRIP_NOPS (identity_value);
238 }
239 STRIP_NOPS (func_parm);
240
241 location = EXPR_LOCATION (an_builtin_fn);
242
243 /* Note about using find_rank (): If find_rank returns false, then it must
244 have already reported an error, thus we just return an error_mark_node
245 without any doing any error emission. */
246 if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank))
247 return error_mark_node;
248 if (rank == 0)
249 {
250 error_at (location, "Invalid builtin arguments");
251 return error_mark_node;
252 }
253 else if (rank > 1
254 && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
255 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND))
256 {
257 error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot "
258 "have arrays with dimension greater than 1");
259 return error_mark_node;
260 }
261
262 extract_array_notation_exprs (func_parm, true, &array_list);
263 list_size = vec_safe_length (array_list);
264 switch (an_type)
265 {
266 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
267 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
268 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
269 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
270 new_var_type = TREE_TYPE ((*array_list)[0]);
271 break;
272 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
273 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
274 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
275 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
276 new_var_type = boolean_type_node;
277 break;
278 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
279 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
280 new_var_type = size_type_node;
281 break;
282 case BUILT_IN_CILKPLUS_SEC_REDUCE:
283 if (call_fn && identity_value)
284 new_var_type = TREE_TYPE ((*array_list)[0]);
285 break;
286 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
287 new_var_type = NULL_TREE;
288 break;
289 default:
290 gcc_unreachable ();
291 }
292
293 if (new_var_type && TREE_CODE (new_var_type) == ARRAY_TYPE)
294 new_var_type = TREE_TYPE (new_var_type);
295 an_loop_info.safe_grow_cleared (rank);
296
297 an_init = push_stmt_list ();
298
299 /* Assign the array notation components to variable so that they can satisfy
300 the exec-once rule. */
301 for (ii = 0; ii < list_size; ii++)
302 if (TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
303 {
304 tree anode = (*array_list)[ii];
305 make_triplet_val_inv (&ARRAY_NOTATION_START (anode));
306 make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode));
307 make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode));
308 }
309 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
310 for (ii = 0; ii < rank; ii++)
311 {
312 tree typ = ptrdiff_type_node;
313
314 /* In this place, we are using get_temp_regvar instead of
315 create_temporary_var if an_type is SEC_REDUCE_MAX/MIN_IND because
316 the array_ind_value depends on this value being initalized to 0. */
317 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
318 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
319 an_loop_info[ii].var = get_temp_regvar (typ, build_zero_cst (typ));
320 else
321 {
322 an_loop_info[ii].var = create_temporary_var (typ);
323 add_decl_expr (an_loop_info[ii].var);
324 }
325 an_loop_info[ii].ind_init =
326 build_x_modify_expr (location, an_loop_info[ii].var, INIT_EXPR,
327 build_zero_cst (typ), tf_warning_or_error);
328 }
329 array_operand = create_array_refs (location, an_info, an_loop_info,
330 list_size, rank);
331 replace_array_notations (&func_parm, true, array_list, array_operand);
332
333 if (!TREE_TYPE (func_parm))
334 TREE_TYPE (func_parm) = TREE_TYPE ((*array_list)[0]);
335
336 create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error);
337 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
338 || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
339 array_ind_value = get_temp_regvar (TREE_TYPE (func_parm), func_parm);
340
341 array_op0 = (*array_operand)[0];
342 if (INDIRECT_REF_P (array_op0))
343 array_op0 = TREE_OPERAND (array_op0, 0);
344 switch (an_type)
345 {
346 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
347 code = PLUS_EXPR;
348 init = build_zero_cst (new_var_type);
349 break;
350 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
351 code = MULT_EXPR;
352 init = build_one_cst (new_var_type);
353 break;
354 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
355 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
356 code = ((an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO) ? EQ_EXPR
357 : NE_EXPR);
358 init = build_zero_cst (new_var_type);
359 cond_init = build_one_cst (new_var_type);
360 comp_node = build_zero_cst (TREE_TYPE (func_parm));
361 break;
362 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
363 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
364 code = ((an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO) ? NE_EXPR
365 : EQ_EXPR);
366 init = build_one_cst (new_var_type);
367 cond_init = build_zero_cst (new_var_type);
368 comp_node = build_zero_cst (TREE_TYPE (func_parm));
369 break;
370 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
371 code = MAX_EXPR;
372 init = (TYPE_MIN_VALUE (new_var_type) ? TYPE_MIN_VALUE (new_var_type)
373 : func_parm);
374 break;
375 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
376 code = MIN_EXPR;
377 init = (TYPE_MAX_VALUE (new_var_type) ? TYPE_MAX_VALUE (new_var_type)
378 : func_parm);
379 break;
380 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
381 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
382 code = (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND ? LE_EXPR
383 : GE_EXPR);
384 init = an_loop_info[0].var;
385 break;
386 case BUILT_IN_CILKPLUS_SEC_REDUCE:
387 init = identity_value;
388 break;
389 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
390 init = NULL_TREE;
391 break;
392 default:
393 gcc_unreachable ();
394 }
395
396 if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
397 *new_var = get_temp_regvar (new_var_type, init);
398 else
399 *new_var = NULL_TREE;
400
401 switch (an_type)
402 {
403 case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
404 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
405 new_expr = build_x_modify_expr (location, *new_var, code, func_parm,
406 tf_warning_or_error);
407 break;
408 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
409 case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
410 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
411 case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
412 /* In all these cases, assume the false case is true and as soon as
413 we find a true case, set the true flag on and latch it in. */
414 new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
415 cond_init, tf_warning_or_error);
416 new_no_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
417 *new_var, tf_warning_or_error);
418 new_cond_expr = build_x_binary_op
419 (location, code, func_parm, TREE_CODE (func_parm), comp_node,
420 TREE_CODE (comp_node), NULL, tf_warning_or_error);
421 new_expr = build_x_conditional_expr (location, new_cond_expr,
422 new_yes_expr, new_no_expr,
423 tf_warning_or_error);
424 break;
425 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
426 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
427 new_cond_expr = build_x_binary_op
428 (location, code, *new_var, TREE_CODE (*new_var), func_parm,
429 TREE_CODE (func_parm), NULL, tf_warning_or_error);
430 new_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, func_parm,
431 tf_warning_or_error);
432 break;
433 case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
434 case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
435 new_yes_expr = build_x_modify_expr (location, array_ind_value, NOP_EXPR,
436 func_parm, tf_warning_or_error);
437 new_no_expr = build_x_modify_expr (location, array_ind_value, NOP_EXPR,
438 array_ind_value, tf_warning_or_error);
439 if (list_size > 1)
440 new_yes_ind = build_x_modify_expr (location, *new_var, NOP_EXPR,
441 an_loop_info[0].var,
442 tf_warning_or_error);
443 else
444 new_yes_ind = build_x_modify_expr (location, *new_var, NOP_EXPR,
445 TREE_OPERAND (array_op0, 1),
446 tf_warning_or_error);
447 new_no_ind = build_x_modify_expr (location, *new_var, NOP_EXPR, *new_var,
448 tf_warning_or_error);
449 new_yes_list = alloc_stmt_list ();
450 append_to_statement_list (new_yes_ind, &new_yes_list);
451 append_to_statement_list (new_yes_expr, &new_yes_list);
452
453 new_no_list = alloc_stmt_list ();
454 append_to_statement_list (new_no_ind, &new_no_list);
455 append_to_statement_list (new_no_expr, &new_no_list);
456
457 new_cond_expr = build_x_binary_op (location, code, array_ind_value,
458 TREE_CODE (array_ind_value), func_parm,
459 TREE_CODE (func_parm), NULL,
460 tf_warning_or_error);
461 new_expr = build_x_conditional_expr (location, new_cond_expr,
462 new_yes_list, new_no_list,
463 tf_warning_or_error);
464 break;
465 case BUILT_IN_CILKPLUS_SEC_REDUCE:
466 case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
467 func_args = make_tree_vector ();
468 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE)
469 vec_safe_push (func_args, *new_var);
470 else
471 vec_safe_push (func_args, identity_value);
472 vec_safe_push (func_args, func_parm);
473
474 new_expr = finish_call_expr (call_fn, &func_args, false, true,
475 tf_warning_or_error);
476 if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE)
477 new_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, new_expr,
478 tf_warning_or_error);
479 release_tree_vector (func_args);
480 break;
481 default:
482 gcc_unreachable ();
483 }
484 an_init = pop_stmt_list (an_init);
485 append_to_statement_list (an_init, &loop_with_init);
486 body = new_expr;
487
488 for (ii = 0; ii < rank; ii++)
489 {
490 tree new_loop = push_stmt_list ();
491 create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp,
492 an_loop_info[ii].incr, body);
493 body = pop_stmt_list (new_loop);
494 }
495 append_to_statement_list (body, &loop_with_init);
496
497 release_vec_vec (an_info);
498
499 return loop_with_init;
500 }
501
502 /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
503 The LHS and/or RHS will be array notation expressions that have a
504 MODIFYCODE. The location of the variable is specified by LOCATION. */
505
506 static tree
507 expand_an_in_modify_expr (location_t location, tree lhs,
508 enum tree_code modifycode, tree rhs,
509 tsubst_flags_t complain)
510 {
511 tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
512 tree array_expr = NULL_TREE;
513 tree body = NULL_TREE;
514 auto_vec<tree> cond_expr;
515 vec<tree, va_gc> *lhs_array_operand = NULL, *rhs_array_operand = NULL;
516 size_t lhs_rank = 0, rhs_rank = 0, ii = 0;
517 vec<tree, va_gc> *rhs_list = NULL, *lhs_list = NULL;
518 size_t rhs_list_size = 0, lhs_list_size = 0;
519 tree new_modify_expr, new_var = NULL_TREE, builtin_loop, scalar_mods;
520 bool found_builtin_fn = false;
521 tree an_init, loop_with_init = alloc_stmt_list ();
522 vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
523 auto_vec<an_loop_parts> lhs_an_loop_info, rhs_an_loop_info;
524 tree lhs_len, rhs_len;
525
526 if (!find_rank (location, rhs, rhs, false, &rhs_rank))
527 return error_mark_node;
528 extract_array_notation_exprs (rhs, false, &rhs_list);
529 rhs_list_size = vec_safe_length (rhs_list);
530 an_init = push_stmt_list ();
531 if (rhs_rank)
532 {
533 scalar_mods = replace_invariant_exprs (&rhs);
534 if (scalar_mods)
535 finish_expr_stmt (scalar_mods);
536 }
537 for (ii = 0; ii < rhs_list_size; ii++)
538 {
539 tree rhs_node = (*rhs_list)[ii];
540 if (TREE_CODE (rhs_node) == CALL_EXPR)
541 {
542 builtin_loop = expand_sec_reduce_builtin (rhs_node, &new_var);
543 if (builtin_loop == error_mark_node)
544 return error_mark_node;
545 else if (builtin_loop)
546 {
547 finish_expr_stmt (builtin_loop);
548 found_builtin_fn = true;
549 if (new_var)
550 {
551 vec <tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
552 vec_safe_push (rhs_sub_list, rhs_node);
553 vec_safe_push (new_var_list, new_var);
554 replace_array_notations (&rhs, false, rhs_sub_list,
555 new_var_list);
556 }
557 }
558 }
559 }
560 lhs_rank = 0;
561 rhs_rank = 0;
562 if (!find_rank (location, lhs, lhs, true, &lhs_rank)
563 || !find_rank (location, rhs, rhs, true, &rhs_rank))
564 {
565 pop_stmt_list (an_init);
566 return error_mark_node;
567 }
568
569 /* If both are scalar, then the only reason why we will get this far is if
570 there is some array notations inside it and was using a builtin array
571 notation functions. If so, we have already broken those guys up and now
572 a simple build_x_modify_expr would do. */
573 if (lhs_rank == 0 && rhs_rank == 0)
574 {
575 if (found_builtin_fn)
576 {
577 new_modify_expr = build_x_modify_expr (location, lhs,
578 modifycode, rhs, complain);
579 finish_expr_stmt (new_modify_expr);
580 pop_stmt_list (an_init);
581 return an_init;
582 }
583 else
584 gcc_unreachable ();
585 }
586
587 /* If for some reason location is not set, then find if LHS or RHS has
588 location info. If so, then use that so we atleast have an idea. */
589 if (location == UNKNOWN_LOCATION)
590 {
591 if (EXPR_LOCATION (lhs) != UNKNOWN_LOCATION)
592 location = EXPR_LOCATION (lhs);
593 else if (EXPR_LOCATION (rhs) != UNKNOWN_LOCATION)
594 location = EXPR_LOCATION (rhs);
595 }
596
597 /* We need this when we have a scatter issue. */
598 extract_array_notation_exprs (lhs, true, &lhs_list);
599 rhs_list = NULL;
600 extract_array_notation_exprs (rhs, true, &rhs_list);
601 rhs_list_size = vec_safe_length (rhs_list);
602 lhs_list_size = vec_safe_length (lhs_list);
603
604 if (lhs_rank == 0 && rhs_rank != 0)
605 {
606 error_at (location, "%qE cannot be scalar when %qE is not", lhs, rhs);
607 return error_mark_node;
608 }
609 if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
610 {
611 error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
612 return error_mark_node;
613 }
614
615 /* Assign the array notation components to variable so that they can satisfy
616 the execute-once rule. */
617 for (ii = 0; ii < lhs_list_size; ii++)
618 {
619 tree anode = (*lhs_list)[ii];
620 make_triplet_val_inv (&ARRAY_NOTATION_START (anode));
621 make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode));
622 make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode));
623 }
624 for (ii = 0; ii < rhs_list_size; ii++)
625 if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
626 {
627 tree aa = (*rhs_list)[ii];
628 make_triplet_val_inv (&ARRAY_NOTATION_START (aa));
629 make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (aa));
630 make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (aa));
631 }
632 lhs_an_loop_info.safe_grow_cleared (lhs_rank);
633
634 if (rhs_rank)
635 rhs_an_loop_info.safe_grow_cleared (rhs_rank);
636
637 cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
638 cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
639 &lhs_an_info);
640 if (rhs_list)
641 cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
642 &rhs_an_info);
643 if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
644 || (rhs_list && length_mismatch_in_expr_p (EXPR_LOCATION (rhs),
645 rhs_an_info)))
646 {
647 pop_stmt_list (an_init);
648 goto error;
649 }
650 rhs_len = ((rhs_list_size > 0 && rhs_rank > 0) ?
651 rhs_an_info[0][0].length : NULL_TREE);
652 lhs_len = ((lhs_list_size > 0 && lhs_rank > 0) ?
653 lhs_an_info[0][0].length : NULL_TREE);
654 if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
655 && TREE_CODE (lhs_len) == INTEGER_CST && rhs_len
656 && TREE_CODE (rhs_len) == INTEGER_CST
657 && !tree_int_cst_equal (rhs_len, lhs_len))
658 {
659 error_at (location, "length mismatch between LHS and RHS");
660 pop_stmt_list (an_init);
661 goto error;
662 }
663 for (ii = 0; ii < lhs_rank; ii++)
664 {
665 tree typ = ptrdiff_type_node;
666 lhs_an_loop_info[ii].var = create_temporary_var (typ);
667 add_decl_expr (lhs_an_loop_info[ii].var);
668 lhs_an_loop_info[ii].ind_init = build_x_modify_expr
669 (location, lhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ),
670 complain);
671 }
672
673 if (rhs_list_size > 0)
674 {
675 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
676 lhs_an_loop_info, lhs_rank,
677 lhs);
678 if (!rhs_array_operand)
679 goto error;
680 }
681 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
682 rhs_list_size = 0;
683 rhs_list = NULL;
684 extract_array_notation_exprs (rhs, true, &rhs_list);
685 rhs_list_size = vec_safe_length (rhs_list);
686
687 for (ii = 0; ii < rhs_rank; ii++)
688 {
689 tree typ = ptrdiff_type_node;
690 rhs_an_loop_info[ii].var = create_temporary_var (typ);
691 add_decl_expr (rhs_an_loop_info[ii].var);
692 rhs_an_loop_info[ii].ind_init = build_x_modify_expr
693 (location, rhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ),
694 complain);
695 }
696
697 if (lhs_rank)
698 {
699 lhs_array_operand =
700 create_array_refs (location, lhs_an_info, lhs_an_loop_info,
701 lhs_list_size, lhs_rank);
702 replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
703 }
704
705 if (rhs_array_operand)
706 vec_safe_truncate (rhs_array_operand, 0);
707 if (rhs_rank)
708 {
709 rhs_array_operand = create_array_refs (location, rhs_an_info,
710 rhs_an_loop_info, rhs_list_size,
711 rhs_rank);
712 /* Replace all the array refs created by the above function because this
713 variable is blown away by the fix_sec_implicit_args function below. */
714 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
715 vec_safe_truncate (rhs_array_operand , 0);
716 rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
717 rhs_an_loop_info, rhs_rank,
718 rhs);
719 if (!rhs_array_operand)
720 goto error;
721 replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
722 }
723
724 array_expr_rhs = rhs;
725 array_expr_lhs = lhs;
726
727 array_expr = build_x_modify_expr (location, array_expr_lhs, modifycode,
728 array_expr_rhs, complain);
729 create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info,
730 complain);
731 if (rhs_rank)
732 create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info,
733 complain);
734 for (ii = 0; ii < MAX (rhs_rank, lhs_rank); ii++)
735 if (ii < lhs_rank && ii < rhs_rank)
736 cond_expr[ii] = build_x_binary_op
737 (location, TRUTH_ANDIF_EXPR, lhs_an_loop_info[ii].cmp,
738 TREE_CODE (lhs_an_loop_info[ii].cmp), rhs_an_loop_info[ii].cmp,
739 TREE_CODE (rhs_an_loop_info[ii].cmp), NULL, complain);
740 else if (ii < lhs_rank && ii >= rhs_rank)
741 cond_expr[ii] = lhs_an_loop_info[ii].cmp;
742 else
743 /* No need to compare ii < rhs_rank && ii >= lhs_rank because in a valid
744 Array notation expression, rank of RHS cannot be greater than LHS. */
745 gcc_unreachable ();
746
747 an_init = pop_stmt_list (an_init);
748 append_to_statement_list (an_init, &loop_with_init);
749 body = array_expr;
750 for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
751 {
752 tree incr_list = alloc_stmt_list ();
753 tree init_list = alloc_stmt_list ();
754 tree new_loop = push_stmt_list ();
755
756 if (lhs_rank)
757 {
758 append_to_statement_list (lhs_an_loop_info[ii].ind_init, &init_list);
759 append_to_statement_list (lhs_an_loop_info[ii].incr, &incr_list);
760 }
761 if (rhs_rank)
762 {
763 append_to_statement_list (rhs_an_loop_info[ii].ind_init, &init_list);
764 append_to_statement_list (rhs_an_loop_info[ii].incr, &incr_list);
765 }
766 create_an_loop (init_list, cond_expr[ii], incr_list, body);
767 body = pop_stmt_list (new_loop);
768 }
769 append_to_statement_list (body, &loop_with_init);
770
771 release_vec_vec (lhs_an_info);
772 release_vec_vec (rhs_an_info);
773
774 return loop_with_init;
775
776 error:
777 release_vec_vec (lhs_an_info);
778 release_vec_vec (rhs_an_info);
779
780 return error_mark_node;
781 }
782
783 /* Helper function for expand_conditonal_array_notations. Encloses the
784 conditional statement passed in ORIG_STMT with a loop around it and
785 replaces the condition in STMT with a ARRAY_REF tree-node to the array.
786 The condition must have a ARRAY_NOTATION_REF tree. */
787
788 static tree
789 cp_expand_cond_array_notations (tree orig_stmt)
790 {
791 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
792 size_t list_size = 0;
793 size_t rank = 0, ii = 0;
794 tree an_init, body, stmt = NULL_TREE;
795 tree builtin_loop, new_var = NULL_TREE;
796 tree loop_with_init = alloc_stmt_list ();
797 location_t location = UNKNOWN_LOCATION;
798 vec<vec<an_parts> > an_info = vNULL;
799 auto_vec<an_loop_parts> an_loop_info;
800
801 if (TREE_CODE (orig_stmt) == COND_EXPR)
802 {
803 size_t cond_rank = 0, yes_rank = 0, no_rank = 0;
804 tree yes_expr = COND_EXPR_THEN (orig_stmt);
805 tree no_expr = COND_EXPR_ELSE (orig_stmt);
806 tree cond = COND_EXPR_COND (orig_stmt);
807 if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
808 || !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
809 &yes_rank)
810 || !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
811 &no_rank))
812 return error_mark_node;
813 /* If the condition has a zero rank, then handle array notations in body
814 separately. */
815 if (cond_rank == 0)
816 return orig_stmt;
817 if (cond_rank != yes_rank && yes_rank != 0)
818 {
819 error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
820 " expression of parent if-statement");
821 return error_mark_node;
822 }
823 else if (cond_rank != no_rank && no_rank != 0)
824 {
825 error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
826 "expression of parent if-statement");
827 return error_mark_node;
828 }
829 }
830 else if (TREE_CODE (orig_stmt) == IF_STMT)
831 {
832 size_t cond_rank = 0, yes_rank = 0, no_rank = 0;
833 tree yes_expr = THEN_CLAUSE (orig_stmt);
834 tree no_expr = ELSE_CLAUSE (orig_stmt);
835 tree cond = IF_COND (orig_stmt);
836 if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
837 || (yes_expr
838 && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
839 &yes_rank))
840 || (no_expr
841 && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
842 &no_rank)))
843 return error_mark_node;
844
845 /* Same reasoning as for COND_EXPR. */
846 if (cond_rank == 0)
847 return orig_stmt;
848 else if (cond_rank != yes_rank && yes_rank != 0)
849 {
850 error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
851 " expression of parent if-statement");
852 return error_mark_node;
853 }
854 else if (cond_rank != no_rank && no_rank != 0)
855 {
856 error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
857 "expression of parent if-statement");
858 return error_mark_node;
859 }
860 }
861 else if (truth_value_p (TREE_CODE (orig_stmt)))
862 {
863 size_t left_rank = 0, right_rank = 0;
864 tree left_expr = TREE_OPERAND (orig_stmt, 0);
865 tree right_expr = TREE_OPERAND (orig_stmt, 1);
866 if (!find_rank (EXPR_LOCATION (left_expr), left_expr, left_expr, true,
867 &left_rank)
868 || !find_rank (EXPR_LOCATION (right_expr), right_expr, right_expr,
869 true, &right_rank))
870 return error_mark_node;
871 if (right_rank == 0 && left_rank == 0)
872 return orig_stmt;
873 }
874
875 if (!find_rank (EXPR_LOCATION (orig_stmt), orig_stmt, orig_stmt, true,
876 &rank))
877 return error_mark_node;
878 if (rank == 0)
879 return orig_stmt;
880
881 extract_array_notation_exprs (orig_stmt, false, &array_list);
882 stmt = alloc_stmt_list ();
883 for (ii = 0; ii < vec_safe_length (array_list); ii++)
884 {
885 tree array_node = (*array_list)[ii];
886 if (TREE_CODE (array_node) == CALL_EXPR
887 || TREE_CODE (array_node) == AGGR_INIT_EXPR)
888 {
889 builtin_loop = expand_sec_reduce_builtin (array_node, &new_var);
890 if (builtin_loop == error_mark_node)
891 finish_expr_stmt (error_mark_node);
892 else if (new_var)
893 {
894 vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL;
895 vec_safe_push (sub_list, array_node);
896 vec_safe_push (new_var_list, new_var);
897 replace_array_notations (&orig_stmt, false, sub_list,
898 new_var_list);
899 append_to_statement_list (builtin_loop, &stmt);
900 }
901 }
902 }
903 append_to_statement_list (orig_stmt, &stmt);
904 rank = 0;
905 array_list = NULL;
906 if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank))
907 return error_mark_node;
908 if (rank == 0)
909 return stmt;
910
911 extract_array_notation_exprs (stmt, true, &array_list);
912 list_size = vec_safe_length (array_list);
913 if (list_size == 0)
914 return stmt;
915
916 location = EXPR_LOCATION (orig_stmt);
917 list_size = vec_safe_length (array_list);
918 an_loop_info.safe_grow_cleared (rank);
919
920 an_init = push_stmt_list ();
921
922 /* Assign the array notation components to variable so that they can
923 satisfy the exec-once rule. */
924 for (ii = 0; ii < list_size; ii++)
925 {
926 tree anode = (*array_list)[ii];
927 make_triplet_val_inv (&ARRAY_NOTATION_START (anode));
928 make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode));
929 make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode));
930 }
931 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
932
933 for (ii = 0; ii < rank; ii++)
934 {
935 tree typ = ptrdiff_type_node;
936 an_loop_info[ii].var = create_temporary_var (typ);
937 add_decl_expr (an_loop_info[ii].var);
938 an_loop_info[ii].ind_init =
939 build_x_modify_expr (location, an_loop_info[ii].var, INIT_EXPR,
940 build_zero_cst (typ), tf_warning_or_error);
941 }
942 array_operand = create_array_refs (location, an_info, an_loop_info,
943 list_size, rank);
944 replace_array_notations (&stmt, true, array_list, array_operand);
945 create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error);
946
947 an_init = pop_stmt_list (an_init);
948 append_to_statement_list (an_init, &loop_with_init);
949 body = stmt;
950
951 for (ii = 0; ii < rank; ii++)
952 {
953 tree new_loop = push_stmt_list ();
954 create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp,
955 an_loop_info[ii].incr, body);
956 body = pop_stmt_list (new_loop);
957 }
958 append_to_statement_list (body, &loop_with_init);
959
960 release_vec_vec (an_info);
961
962 return loop_with_init;
963 }
964
965 /* Transforms array notations inside unary expression ORIG_STMT with an
966 appropriate loop and ARRAY_REF (and returns all this as a super-tree called
967 LOOP). */
968
969 static tree
970 expand_unary_array_notation_exprs (tree orig_stmt)
971 {
972 vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
973 size_t list_size = 0, rank = 0, ii = 0;
974 tree body;
975 tree builtin_loop, stmt = NULL_TREE, new_var = NULL_TREE;
976 location_t location = EXPR_LOCATION (orig_stmt);
977 tree an_init, loop_with_init = alloc_stmt_list ();
978 vec<vec<an_parts> > an_info = vNULL;
979 auto_vec<an_loop_parts> an_loop_info;
980
981 if (!find_rank (location, orig_stmt, orig_stmt, true, &rank))
982 return error_mark_node;
983 if (rank == 0)
984 return orig_stmt;
985
986 extract_array_notation_exprs (orig_stmt, false, &array_list);
987 list_size = vec_safe_length (array_list);
988 location = EXPR_LOCATION (orig_stmt);
989 stmt = NULL_TREE;
990 for (ii = 0; ii < list_size; ii++)
991 if (TREE_CODE ((*array_list)[ii]) == CALL_EXPR
992 || TREE_CODE ((*array_list)[ii]) == AGGR_INIT_EXPR)
993 {
994 tree list_node = (*array_list)[ii];
995 builtin_loop = expand_sec_reduce_builtin (list_node, &new_var);
996 if (builtin_loop == error_mark_node)
997 return error_mark_node;
998 else if (builtin_loop)
999 {
1000 vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL;
1001 stmt = alloc_stmt_list ();
1002 append_to_statement_list (builtin_loop, &stmt);
1003 vec_safe_push (sub_list, list_node);
1004 vec_safe_push (new_var_list, new_var);
1005 replace_array_notations (&orig_stmt, false, sub_list, new_var_list);
1006 }
1007 }
1008 if (stmt != NULL_TREE)
1009 append_to_statement_list (finish_expr_stmt (orig_stmt), &stmt);
1010 else
1011 stmt = orig_stmt;
1012 rank = 0;
1013 list_size = 0;
1014 array_list = NULL;
1015 extract_array_notation_exprs (stmt, true, &array_list);
1016 list_size = vec_safe_length (array_list);
1017
1018 if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank))
1019 return error_mark_node;
1020 if (rank == 0 || list_size == 0)
1021 return stmt;
1022 an_loop_info.safe_grow_cleared (rank);
1023 an_init = push_stmt_list ();
1024 /* Assign the array notation components to variable so that they can satisfy
1025 the exec-once rule. */
1026 for (ii = 0; ii < list_size; ii++)
1027 {
1028 tree array_node = (*array_list)[ii];
1029 make_triplet_val_inv (&ARRAY_NOTATION_START (array_node));
1030 make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (array_node));
1031 make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (array_node));
1032 }
1033 cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1034
1035 for (ii = 0; ii < rank; ii++)
1036 {
1037 tree typ = ptrdiff_type_node;
1038 an_loop_info[ii].var = create_temporary_var (typ);
1039 add_decl_expr (an_loop_info[ii].var);
1040 an_loop_info[ii].ind_init = build_x_modify_expr
1041 (location, an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ),
1042 tf_warning_or_error);
1043 }
1044 array_operand = create_array_refs (location, an_info, an_loop_info,
1045 list_size, rank);
1046 replace_array_notations (&stmt, true, array_list, array_operand);
1047 create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error);
1048
1049 an_init = pop_stmt_list (an_init);
1050 append_to_statement_list (an_init, &loop_with_init);
1051 body = stmt;
1052
1053 for (ii = 0; ii < rank; ii++)
1054 {
1055 tree new_loop = push_stmt_list ();
1056 create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp,
1057 an_loop_info[ii].incr, body);
1058 body = pop_stmt_list (new_loop);
1059 }
1060 append_to_statement_list (body, &loop_with_init);
1061
1062 release_vec_vec (an_info);
1063
1064 return loop_with_init;
1065 }
1066
1067 /* Expands the array notation's builtin reduction function in EXPR
1068 (of type RETURN_EXPR) and returns a STATEMENT_LIST that contains a loop
1069 with the builtin function expansion and a return statement at the end. */
1070
1071 static tree
1072 expand_return_expr (tree expr)
1073 {
1074 tree new_mod_list, new_var, new_mod, retval_expr;
1075 size_t rank = 0;
1076 location_t loc = EXPR_LOCATION (expr);
1077 if (TREE_CODE (expr) != RETURN_EXPR)
1078 return expr;
1079
1080 if (!find_rank (loc, expr, expr, false, &rank))
1081 return error_mark_node;
1082
1083 /* If the return expression contains array notations, then flag it as
1084 error. */
1085 if (rank >= 1)
1086 {
1087 error_at (loc, "array notation expression cannot be used as a return "
1088 "value");
1089 return error_mark_node;
1090 }
1091
1092 new_mod_list = push_stmt_list ();
1093 retval_expr = TREE_OPERAND (expr, 0);
1094 new_var = create_temporary_var (TREE_TYPE (retval_expr));
1095 add_decl_expr (new_var);
1096 new_mod = expand_an_in_modify_expr (loc, new_var, NOP_EXPR,
1097 TREE_OPERAND (retval_expr, 1),
1098 tf_warning_or_error);
1099 TREE_OPERAND (retval_expr, 1) = new_var;
1100 TREE_OPERAND (expr, 0) = retval_expr;
1101 add_stmt (new_mod);
1102 add_stmt (expr);
1103 new_mod_list = pop_stmt_list (new_mod_list);
1104 return new_mod_list;
1105 }
1106
1107 /* Expands ARRAY_NOTATION_REF and builtin functions in a compound statement,
1108 STMT. Returns the STMT with expanded array notations. */
1109
1110 tree
1111 expand_array_notation_exprs (tree t)
1112 {
1113 enum tree_code code;
1114 bool is_expr;
1115 location_t loc = UNKNOWN_LOCATION;
1116
1117 if (!t)
1118 return t;
1119
1120 loc = EXPR_LOCATION (t);
1121
1122 code = TREE_CODE (t);
1123 is_expr = IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code));
1124 switch (code)
1125 {
1126 case ERROR_MARK:
1127 case IDENTIFIER_NODE:
1128 case VOID_CST:
1129 case INTEGER_CST:
1130 case REAL_CST:
1131 case FIXED_CST:
1132 case STRING_CST:
1133 case BLOCK:
1134 case PLACEHOLDER_EXPR:
1135 case FIELD_DECL:
1136 case VOID_TYPE:
1137 case REAL_TYPE:
1138 case SSA_NAME:
1139 case LABEL_DECL:
1140 case RESULT_DECL:
1141 case VAR_DECL:
1142 case PARM_DECL:
1143 case NON_LVALUE_EXPR:
1144 case NOP_EXPR:
1145 case ADDR_EXPR:
1146 case ARRAY_REF:
1147 case BIT_FIELD_REF:
1148 case VECTOR_CST:
1149 case COMPLEX_CST:
1150 return t;
1151 case INIT_EXPR:
1152 case MODIFY_EXPR:
1153 if (contains_array_notation_expr (t))
1154 t = expand_an_in_modify_expr (loc, TREE_OPERAND (t, 0), NOP_EXPR,
1155 TREE_OPERAND (t, 1),
1156 tf_warning_or_error);
1157 return t;
1158 case MODOP_EXPR:
1159 if (contains_array_notation_expr (t) && !processing_template_decl)
1160 t = expand_an_in_modify_expr
1161 (loc, TREE_OPERAND (t, 0), TREE_CODE (TREE_OPERAND (t, 1)),
1162 TREE_OPERAND (t, 2), tf_warning_or_error);
1163 return t;
1164 case CONSTRUCTOR:
1165 return t;
1166 case BIND_EXPR:
1167 {
1168 BIND_EXPR_BODY (t) =
1169 expand_array_notation_exprs (BIND_EXPR_BODY (t));
1170 return t;
1171 }
1172 case DECL_EXPR:
1173 if (contains_array_notation_expr (t))
1174 {
1175 tree x = DECL_EXPR_DECL (t);
1176 if (DECL_INITIAL (x))
1177 {
1178 location_t loc = DECL_SOURCE_LOCATION (x);
1179 tree lhs = x;
1180 tree rhs = DECL_INITIAL (x);
1181 DECL_INITIAL (x) = NULL;
1182 tree new_modify_expr = build_modify_expr (loc, lhs,
1183 TREE_TYPE (lhs),
1184 NOP_EXPR,
1185 loc, rhs,
1186 TREE_TYPE(rhs));
1187 t = expand_array_notation_exprs (new_modify_expr);
1188 }
1189 }
1190 return t;
1191 case STATEMENT_LIST:
1192 {
1193 tree_stmt_iterator i;
1194 for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
1195 *tsi_stmt_ptr (i) =
1196 expand_array_notation_exprs (*tsi_stmt_ptr (i));
1197 return t;
1198 }
1199
1200 case OMP_PARALLEL:
1201 OMP_PARALLEL_BODY (t)
1202 = expand_array_notation_exprs (OMP_PARALLEL_BODY (t));
1203 return t;
1204
1205 case OMP_TASK:
1206 case OMP_FOR:
1207 case OMP_SINGLE:
1208 case OMP_SECTION:
1209 case OMP_SECTIONS:
1210 case OMP_MASTER:
1211 case OMP_TASKGROUP:
1212 case OMP_ORDERED:
1213 case OMP_CRITICAL:
1214 case OMP_ATOMIC:
1215 case OMP_CLAUSE:
1216 case TARGET_EXPR:
1217 case INTEGER_TYPE:
1218 case ENUMERAL_TYPE:
1219 case BOOLEAN_TYPE:
1220 case POINTER_TYPE:
1221 case ARRAY_TYPE:
1222 case RECORD_TYPE:
1223 case METHOD_TYPE:
1224 return t;
1225 case RETURN_EXPR:
1226 if (contains_array_notation_expr (t))
1227 t = expand_return_expr (t);
1228 return t;
1229 case PREDECREMENT_EXPR:
1230 case PREINCREMENT_EXPR:
1231 case POSTDECREMENT_EXPR:
1232 case POSTINCREMENT_EXPR:
1233 case AGGR_INIT_EXPR:
1234 case CALL_EXPR:
1235 t = expand_unary_array_notation_exprs (t);
1236 return t;
1237 case CONVERT_EXPR:
1238 case CLEANUP_POINT_EXPR:
1239 case EXPR_STMT:
1240 TREE_OPERAND (t, 0) = expand_array_notation_exprs (TREE_OPERAND (t, 0));
1241 /* It is not necessary to wrap error_mark_node in EXPR_STMT. */
1242 if (TREE_OPERAND (t, 0) == error_mark_node)
1243 return TREE_OPERAND (t, 0);
1244 return t;
1245 case TRUTH_ANDIF_EXPR:
1246 case TRUTH_ORIF_EXPR:
1247 case TRUTH_AND_EXPR:
1248 case TRUTH_OR_EXPR:
1249 case TRUTH_XOR_EXPR:
1250 case TRUTH_NOT_EXPR:
1251 case COND_EXPR:
1252 t = cp_expand_cond_array_notations (t);
1253 if (TREE_CODE (t) == COND_EXPR)
1254 {
1255 COND_EXPR_THEN (t) =
1256 expand_array_notation_exprs (COND_EXPR_THEN (t));
1257 COND_EXPR_ELSE (t) =
1258 expand_array_notation_exprs (COND_EXPR_ELSE (t));
1259 }
1260 return t;
1261 case FOR_STMT:
1262 if (contains_array_notation_expr (FOR_COND (t)))
1263 {
1264 error_at (EXPR_LOCATION (FOR_COND (t)),
1265 "array notation cannot be used in a condition for "
1266 "a for-loop");
1267 return error_mark_node;
1268 }
1269 /* FIXME: Add a check for CILK_FOR_STMT here when we add Cilk tasking
1270 keywords. */
1271 if (TREE_CODE (t) == FOR_STMT)
1272 {
1273 FOR_BODY (t) = expand_array_notation_exprs (FOR_BODY (t));
1274 FOR_EXPR (t) = expand_array_notation_exprs (FOR_EXPR (t));
1275 }
1276 else
1277 t = expand_array_notation_exprs (t);
1278 return t;
1279 case IF_STMT:
1280 t = cp_expand_cond_array_notations (t);
1281 /* If the above function added some extra instructions above the original
1282 if statement, then we can't assume it is still IF_STMT so we have to
1283 check again. */
1284 if (TREE_CODE (t) == IF_STMT)
1285 {
1286 if (THEN_CLAUSE (t))
1287 THEN_CLAUSE (t) = expand_array_notation_exprs (THEN_CLAUSE (t));
1288 if (ELSE_CLAUSE (t))
1289 ELSE_CLAUSE (t) = expand_array_notation_exprs (ELSE_CLAUSE (t));
1290 }
1291 else
1292 t = expand_array_notation_exprs (t);
1293 return t;
1294 case SWITCH_STMT:
1295 if (contains_array_notation_expr (SWITCH_STMT_COND (t)))
1296 {
1297 error_at (EXPR_LOCATION (SWITCH_STMT_COND (t)),
1298 "array notation cannot be used as a condition for "
1299 "switch statement");
1300 return error_mark_node;
1301 }
1302 if (SWITCH_STMT_BODY (t))
1303 SWITCH_STMT_BODY (t) =
1304 expand_array_notation_exprs (SWITCH_STMT_BODY (t));
1305 return t;
1306 case WHILE_STMT:
1307 if (contains_array_notation_expr (WHILE_COND (t)))
1308 {
1309 if (EXPR_LOCATION (WHILE_COND (t)) != UNKNOWN_LOCATION)
1310 loc = EXPR_LOCATION (WHILE_COND (t));
1311 error_at (loc, "array notation cannot be used as a condition for "
1312 "while statement");
1313 return error_mark_node;
1314 }
1315 if (WHILE_BODY (t))
1316 WHILE_BODY (t) = expand_array_notation_exprs (WHILE_BODY (t));
1317 return t;
1318 case DO_STMT:
1319 if (contains_array_notation_expr (DO_COND (t)))
1320 {
1321 error_at (EXPR_LOCATION (DO_COND (t)),
1322 "array notation cannot be used as a condition for a "
1323 "do-while statement");
1324 return error_mark_node;
1325 }
1326 if (DO_BODY (t))
1327 DO_BODY (t) = expand_array_notation_exprs (DO_BODY (t));
1328 return t;
1329 default:
1330 if (is_expr)
1331 {
1332 int i, len;
1333
1334 /* Walk over all the sub-trees of this operand. */
1335 len = TREE_CODE_LENGTH (code);
1336
1337 /* Go through the subtrees. We need to do this in forward order so
1338 that the scope of a FOR_EXPR is handled properly. */
1339 for (i = 0; i < len; ++i)
1340 TREE_OPERAND (t, i) =
1341 expand_array_notation_exprs (TREE_OPERAND (t, i));
1342 }
1343 return t;
1344 }
1345 return t;
1346 }
1347
1348 /* Given the base of an array (ARRAY), the START (start_index), the number of
1349 elements to be accessed (LENGTH) and the STRIDE, construct an
1350 ARRAY_NOTATION_REF tree of type TYPE and return it. Restrictions on START,
1351 LENGTH and STRIDE are the same as that of index field passed into ARRAY_REF.
1352 The only additional restriction is that, unlike index in ARRAY_REF, stride,
1353 length and start_index cannot contain array notations. */
1354
1355 tree
1356 build_array_notation_ref (location_t loc, tree array, tree start, tree length,
1357 tree stride, tree type)
1358 {
1359 tree array_ntn_expr = NULL_TREE;
1360
1361 /* If we enter the then-case of the if-statement below, we have hit a case
1362 like this: ARRAY [:]. */
1363 if (!start && !length)
1364 {
1365 if (TREE_CODE (type) != ARRAY_TYPE)
1366 {
1367 error_at (loc, "start-index and length fields necessary for "
1368 "using array notation in pointers or records");
1369 return error_mark_node;
1370 }
1371 tree domain = TYPE_DOMAIN (type);
1372 if (!domain)
1373 {
1374 error_at (loc, "start-index and length fields necessary for "
1375 "using array notation with array of unknown bound");
1376 return error_mark_node;
1377 }
1378 start = cp_fold_convert (ptrdiff_type_node, TYPE_MIN_VALUE (domain));
1379 length = size_binop (PLUS_EXPR, TYPE_MAX_VALUE (domain), size_one_node);
1380 length = cp_fold_convert (ptrdiff_type_node, length);
1381 }
1382
1383 if (!stride)
1384 stride = build_one_cst (ptrdiff_type_node);
1385
1386 stride = maybe_constant_value (stride);
1387 length = maybe_constant_value (length);
1388 if (start)
1389 start = maybe_constant_value (start);
1390
1391 /* When dealing with templates, triplet type-checking will be done in pt.c
1392 after type substitution. */
1393 if (processing_template_decl
1394 && (type_dependent_expression_p (array)
1395 || type_dependent_expression_p (length)
1396 || type_dependent_expression_p (start)
1397 || type_dependent_expression_p (stride)))
1398 array_ntn_expr = build_min_nt_loc (loc, ARRAY_NOTATION_REF, array, start,
1399 length, stride, NULL_TREE);
1400 else
1401 {
1402 if (!cilkplus_an_triplet_types_ok_p (loc, start, length, stride, type))
1403 return error_mark_node;
1404 array_ntn_expr = build4 (ARRAY_NOTATION_REF, NULL_TREE, array, start,
1405 length, stride);
1406 }
1407 if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == POINTER_TYPE)
1408 TREE_TYPE (array_ntn_expr) = TREE_TYPE (type);
1409 else
1410 {
1411 error_at (loc, "base of array section must be pointer or array type");
1412 return error_mark_node;
1413 }
1414
1415 SET_EXPR_LOCATION (array_ntn_expr, loc);
1416 return array_ntn_expr;
1417 }
1418
1419 /* Returns false if any of the Array notation triplet values: START_INDEX,
1420 LENGTH and STRIDE, are not of integral type and have a rank greater than
1421 zero. */
1422
1423 bool
1424 cilkplus_an_triplet_types_ok_p (location_t loc, tree start_index, tree length,
1425 tree stride, tree type)
1426 {
1427 size_t stride_rank = 0, length_rank = 0, start_rank = 0;
1428 if (!TREE_TYPE (start_index) || !INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
1429 {
1430 error_at (loc, "start-index of array notation triplet is not an integer");
1431 return false;
1432 }
1433 if (!TREE_TYPE (length) || !INTEGRAL_TYPE_P (TREE_TYPE (length)))
1434 {
1435 error_at (loc, "length of array notation triplet is not an integer");
1436 return false;
1437 }
1438 if (!TREE_TYPE (stride) || !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
1439 {
1440 error_at (loc, "stride of array notation triplet is not an integer");
1441 return false;
1442 }
1443 if (TREE_CODE (type) == FUNCTION_TYPE)
1444 {
1445 error_at (loc, "array notation cannot be used with function type");
1446 return false;
1447 }
1448 if (!find_rank (loc, start_index, start_index, false, &start_rank)
1449 || !find_rank (loc, length, length, false, &length_rank)
1450 || !find_rank (loc, stride, stride, false, &stride_rank))
1451 return false;
1452
1453 if (start_rank != 0)
1454 {
1455 error_at (loc, "rank of an array notation triplet%'s start-index is not "
1456 "zero");
1457 return false;
1458 }
1459 if (length_rank != 0)
1460 {
1461 error_at (loc, "rank of an array notation triplet%'s length is not zero");
1462 return false;
1463 }
1464 if (stride_rank != 0)
1465 {
1466 error_at (loc, "rank of array notation triplet%'s stride is not zero");
1467 return false;
1468 }
1469 return true;
1470 }