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