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