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
76static void
77create_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
93static inline void
94make_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
113static vec<tree, va_gc> *
114create_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
149void
150create_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
169static tree
170replace_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
212static tree
213expand_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
521static tree
522expand_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
802static tree
803cp_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
984static tree
985expand_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
1087static tree
1088expand_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
1126tree
1127expand_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
1367tree
1368build_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
1430bool
1431cilkplus_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}
1478