Import pre-release gcc-5.0 to new vendor branch
[dragonfly.git] / contrib / gcc-5.0 / 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 }