1/* This file is part of the Intel(R) Cilk(TM) Plus support
2   This file 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 acess (we call it length)
30   4. Stride
31
32   For example, A[0:5:2], implies that 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 overall
38   technique:
39
40   Let's say we have an array notation in a statement like this:
41
42   A[St1:Ln:Str1] = B[St2:Ln:Str2] + <NON ARRAY_NOTATION_STMT>
43
44   where St{1,2} = Starting index,
45   Ln = Number of elements we need to access,
46   and Str{1,2} = the stride.
47   Note: The length of both the array notation expressions must be the same.
48
49   The above expression is broken into the following
50   (with the help of c_finish_loop function from c-typeck.c):
51
52   Tmp_Var = 0;
53   goto compare_label:
54   body_label:
55
56   A[St1+Tmp_Var*Str1] = B[St1+Tmp_Var*Str2] + <NON ARRAY_NOTATION_STMT>;
57   Tmp_Var++;
58
59   compare_label:
60     if (Tmp_Var < Ln)
61       goto body_label;
62     else
63       goto exit_label;
64   exit_label:
65
66*/
67
68#include "config.h"
69#include "system.h"
70#include "coretypes.h"
71#include "hash-set.h"
72#include "vec.h"
73#include "symtab.h"
74#include "input.h"
75#include "alias.h"
76#include "double-int.h"
77#include "machmode.h"
78#include "flags.h"
79#include "inchash.h"
80#include "tree.h"
81#include "c-tree.h"
82#include "gimple-expr.h"
83#include "tree-iterator.h"
84#include "opts.h"
85#include "c-family/c-common.h"
86
87/* If *VALUE is not of type INTEGER_CST, PARM_DECL or VAR_DECL, then map it
88   to a variable and then set *VALUE to the new variable.  */
89
90static inline void
91make_triplet_val_inv (location_t loc, tree *value)
92{
93  tree var, new_exp;
94  if (TREE_CODE (*value) != INTEGER_CST
95      && TREE_CODE (*value) != PARM_DECL
96      && TREE_CODE (*value) != VAR_DECL)
97    {
98      var = build_decl (loc, VAR_DECL, NULL_TREE, integer_type_node);
99      new_exp = build_modify_expr (loc, var, TREE_TYPE (var), NOP_EXPR, loc,
100				   *value, TREE_TYPE (*value));
101      add_stmt (new_exp);
102      *value = var;
103    }
104}
105
106/* Populates the INCR and CMP vectors with the increment (of type POSTINCREMENT
107   or POSTDECREMENT) and comparison (of TYPE GT_EXPR or LT_EXPR) expressions,
108   using data from LENGTH, COUNT_DOWN, and VAR.  INCR and CMP vectors are of
109   size RANK.  */
110
111static void
112create_cmp_incr (location_t loc, vec<an_loop_parts> *node, size_t rank,
113		 vec<vec<an_parts> > an_info)
114{
115  for (size_t ii = 0; ii < rank; ii++)
116    {
117      tree var = (*node)[ii].var;
118      tree length = an_info[0][ii].length;
119      (*node)[ii].incr = build_unary_op (loc, POSTINCREMENT_EXPR, var, 0);
120      (*node)[ii].cmp = build2 (LT_EXPR, boolean_type_node, var, length);
121    }
122}
123
124/* Returns a vector of size RANK that contains an array ref that is derived from
125   array notation triplet parameters stored in VALUE, START, STRIDE.  IS_VECTOR
126   is used to check if the data stored at its corresponding location is an
127   array notation. VAR is the induction variable passed in by the caller.
128
129   For example: For an array notation A[5:10:2], the vector start  will be
130   of size 1 holding '5', stride of same size as start but holding the value of
131   as 2, is_vector as true and count_down as false. Let's assume VAR is 'x'
132   This function returns a vector of size 1 with the following data:
133   A[5 + (x * 2)] .
134*/
135
136static vec<tree, va_gc> *
137create_array_refs (location_t loc, vec<vec<an_parts> > an_info,
138		   vec<an_loop_parts> an_loop_info, size_t size, size_t rank)
139{
140  tree ind_mult, ind_incr;
141  vec<tree, va_gc> *array_operand = NULL;
142  for (size_t ii = 0; ii < size; ii++)
143    if (an_info[ii][0].is_vector)
144      {
145	tree array_opr = an_info[ii][rank - 1].value;
146	for (int s_jj = rank - 1; s_jj >= 0; s_jj--)
147	  {
148	    tree var = an_loop_info[s_jj].var;
149	    tree stride = an_info[ii][s_jj].stride;
150	    tree start = an_info[ii][s_jj].start;
151	    ind_mult = build2 (MULT_EXPR, TREE_TYPE (var), var, stride);
152	    ind_incr = build2 (PLUS_EXPR, TREE_TYPE (var), start, ind_mult);
153	    array_opr = build_array_ref (loc, array_opr, ind_incr);
154	  }
155	vec_safe_push (array_operand, array_opr);
156      }
157    else
158      /* This is just a dummy node to make sure both the list sizes for both
159	 array list and array operand list are the same.  */
160      vec_safe_push (array_operand, integer_one_node);
161  return array_operand;
162}
163
164/* Replaces all the scalar expressions in *NODE.  Returns a STATEMENT_LIST that
165   holds the NODE along with variables that holds the results of the invariant
166   expressions.  */
167
168tree
169replace_invariant_exprs (tree *node)
170{
171  size_t ix = 0;
172  tree node_list = NULL_TREE;
173  tree t = NULL_TREE, new_var = NULL_TREE, new_node;
174  struct inv_list data;
175
176  data.list_values = NULL;
177  data.replacement = NULL;
178  data.additional_tcodes = NULL;
179  walk_tree (node, find_inv_trees, (void *)&data, NULL);
180
181  if (vec_safe_length (data.list_values))
182    {
183      node_list = push_stmt_list ();
184      for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++)
185	{
186	  new_var = build_decl (EXPR_LOCATION (t), VAR_DECL, NULL_TREE,
187				TREE_TYPE (t));
188	  gcc_assert (new_var != NULL_TREE && new_var != error_mark_node);
189	  new_node = build2 (MODIFY_EXPR, TREE_TYPE (t), new_var, t);
190	  add_stmt (new_node);
191	  vec_safe_push (data.replacement, new_var);
192	}
193      walk_tree (node, replace_inv_trees, (void *)&data, NULL);
194      node_list = pop_stmt_list (node_list);
195    }
196  return node_list;
197}
198
199/* Given a CALL_EXPR to an array notation built-in function in
200   AN_BUILTIN_FN, replace the call with the appropriate loop and
201   computation.  Return the computation in *NEW_VAR.
202
203   The return value in *NEW_VAR will always be a scalar.  If the
204   built-in is __sec_reduce_mutating, *NEW_VAR is set to NULL_TREE.  */
205
206static tree
207fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var)
208{
209  tree new_var_type = NULL_TREE, func_parm, new_expr, new_yes_expr, new_no_expr;
210  tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list;
211  tree new_yes_list, new_cond_expr, new_var_init = NULL_TREE;
212  tree new_exp_init = NULL_TREE;
213  vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
214  size_t list_size = 0, rank = 0, ii = 0;
215  tree loop_init, array_op0;
216  tree identity_value = NULL_TREE, call_fn = NULL_TREE, new_call_expr, body;
217  location_t location = UNKNOWN_LOCATION;
218  tree loop_with_init = alloc_stmt_list ();
219  vec<vec<an_parts> > an_info = vNULL;
220  vec<an_loop_parts> an_loop_info = vNULL;
221  enum built_in_function an_type =
222    is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn));
223  if (an_type == BUILT_IN_NONE)
224    return NULL_TREE;
225
226  /* Builtin call should contain at least one argument.  */
227  if (call_expr_nargs (an_builtin_fn) == 0)
228    {
229      error_at (EXPR_LOCATION (an_builtin_fn), "Invalid builtin arguments");
230      return error_mark_node;
231    }
232
233  if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE
234      || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
235    {
236      call_fn = CALL_EXPR_ARG (an_builtin_fn, 2);
237      if (TREE_CODE (call_fn) == ADDR_EXPR)
238	call_fn = TREE_OPERAND (call_fn, 0);
239      identity_value = CALL_EXPR_ARG (an_builtin_fn, 0);
240      func_parm = CALL_EXPR_ARG (an_builtin_fn, 1);
241    }
242  else
243    func_parm = CALL_EXPR_ARG (an_builtin_fn, 0);
244
245  /* Fully fold any EXCESSIVE_PRECISION EXPR that can occur in the function
246     parameter.  */
247  func_parm = c_fully_fold (func_parm, false, NULL);
248  if (func_parm == error_mark_node)
249    return error_mark_node;
250
251  location = EXPR_LOCATION (an_builtin_fn);
252
253  if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank))
254    return error_mark_node;
255
256  if (rank == 0)
257    {
258      error_at (location, "Invalid builtin arguments");
259      return error_mark_node;
260    }
261  else if (rank > 1
262	   && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
263	       || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND))
264    {
265      error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot"
266		" have arrays with dimension greater than 1");
267      return error_mark_node;
268    }
269
270  extract_array_notation_exprs (func_parm, true, &array_list);
271  list_size = vec_safe_length (array_list);
272  switch (an_type)
273    {
274    case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
275    case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
276    case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
277    case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
278      new_var_type = TREE_TYPE ((*array_list)[0]);
279      break;
280    case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
281    case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
282    case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
283    case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
284      new_var_type = integer_type_node;
285      break;
286    case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
287    case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
288      new_var_type = integer_type_node;
289      break;
290    case BUILT_IN_CILKPLUS_SEC_REDUCE:
291      if (call_fn && identity_value)
292	new_var_type = TREE_TYPE ((*array_list)[0]);
293      break;
294    case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
295      new_var_type = NULL_TREE;
296      break;
297    default:
298      gcc_unreachable ();
299    }
300
301  an_loop_info.safe_grow_cleared (rank);
302  cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
303  loop_init = alloc_stmt_list ();
304
305  for (ii = 0; ii < rank; ii++)
306    {
307      an_loop_info[ii].var = create_tmp_var (integer_type_node);
308      an_loop_info[ii].ind_init =
309	build_modify_expr (location, an_loop_info[ii].var,
310			   TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
311			   location,
312			   build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
313			   TREE_TYPE (an_loop_info[ii].var));
314    }
315  array_operand = create_array_refs (location, an_info, an_loop_info,
316				     list_size, rank);
317  replace_array_notations (&func_parm, true, array_list, array_operand);
318
319  create_cmp_incr (location, &an_loop_info, rank, an_info);
320  if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
321    {
322      *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type);
323      gcc_assert (*new_var && *new_var != error_mark_node);
324    }
325  else
326    *new_var = NULL_TREE;
327
328  if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
329      || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
330    array_ind_value = build_decl (location, VAR_DECL, NULL_TREE,
331				  TREE_TYPE (func_parm));
332  array_op0 = (*array_operand)[0];
333  if (TREE_CODE (array_op0) == INDIRECT_REF)
334    array_op0 = TREE_OPERAND (array_op0, 0);
335  switch (an_type)
336    {
337    case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
338      new_var_init = build_modify_expr
339	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
340	 location, build_zero_cst (new_var_type), new_var_type);
341      new_expr = build_modify_expr
342	(location, *new_var, TREE_TYPE (*new_var), PLUS_EXPR,
343	 location, func_parm, TREE_TYPE (func_parm));
344      break;
345    case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
346      new_var_init = build_modify_expr
347	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
348	 location, build_one_cst (new_var_type), new_var_type);
349      new_expr = build_modify_expr
350	(location, *new_var, TREE_TYPE (*new_var), MULT_EXPR,
351	 location, func_parm, TREE_TYPE (func_parm));
352      break;
353    case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
354      new_var_init = build_modify_expr
355	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
356	 location, build_one_cst (new_var_type), new_var_type);
357      /* Initially you assume everything is zero, now if we find a case where
358	 it is NOT true, then we set the result to false. Otherwise
359	 we just keep the previous value.  */
360      new_yes_expr = build_modify_expr
361	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
362	 location, build_zero_cst (TREE_TYPE (*new_var)),
363	 TREE_TYPE (*new_var));
364      new_no_expr = build_modify_expr
365	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
366	 location, *new_var, TREE_TYPE (*new_var));
367      new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
368			      build_zero_cst (TREE_TYPE (func_parm)));
369      new_expr = build_conditional_expr
370	(location, new_cond_expr, false, new_yes_expr,
371	 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
372      break;
373    case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
374      new_var_init = build_modify_expr
375	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
376	 location, build_one_cst (new_var_type), new_var_type);
377      /* Initially you assume everything is non-zero, now if we find a case
378	 where it is NOT true, then we set the result to false.  Otherwise
379	 we just keep the previous value.  */
380      new_yes_expr = build_modify_expr
381	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
382	 location, build_zero_cst (TREE_TYPE (*new_var)),
383	 TREE_TYPE (*new_var));
384      new_no_expr = build_modify_expr
385	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
386	 location, *new_var, TREE_TYPE (*new_var));
387      new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
388			      build_zero_cst (TREE_TYPE (func_parm)));
389      new_expr = build_conditional_expr
390	(location, new_cond_expr, false, new_yes_expr,
391	 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
392      break;
393    case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
394      new_var_init = build_modify_expr
395	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
396	 location, build_zero_cst (new_var_type), new_var_type);
397      /* Initially we assume there are NO zeros in the list. When we find
398	 a non-zero, we keep the previous value.  If we find a zero, we
399	 set the value to true.  */
400      new_yes_expr = build_modify_expr
401	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
402	 location, build_one_cst (new_var_type), new_var_type);
403      new_no_expr = build_modify_expr
404	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
405	 location, *new_var, TREE_TYPE (*new_var));
406      new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm,
407			      build_zero_cst (TREE_TYPE (func_parm)));
408      new_expr = build_conditional_expr
409	(location, new_cond_expr, false, new_yes_expr,
410	 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
411      break;
412    case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
413      new_var_init = build_modify_expr
414	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
415	 location, build_zero_cst (new_var_type), new_var_type);
416      /* Initially we assume there are NO non-zeros in the list. When we find
417	 a zero, we keep the previous value.  If we find a non-zero, we set
418	 the value to true.  */
419      new_yes_expr = build_modify_expr
420	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
421	 location, build_one_cst (new_var_type), new_var_type);
422      new_no_expr = build_modify_expr
423	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
424	 location, *new_var, TREE_TYPE (*new_var));
425      new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm,
426			      build_zero_cst (TREE_TYPE (func_parm)));
427      new_expr = build_conditional_expr
428	(location, new_cond_expr, false, new_yes_expr,
429	 TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr));
430      break;
431    case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
432      if (TYPE_MIN_VALUE (new_var_type))
433	new_var_init = build_modify_expr
434	  (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
435	   location, TYPE_MIN_VALUE (new_var_type), new_var_type);
436      else
437	new_var_init = build_modify_expr
438	  (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
439	   location, func_parm, new_var_type);
440      new_no_expr = build_modify_expr
441	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
442	 location, *new_var, TREE_TYPE (*new_var));
443      new_yes_expr = build_modify_expr
444	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
445	 location, func_parm, TREE_TYPE (*new_var));
446      new_expr = build_conditional_expr
447	(location,
448	 build2 (LT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
449	 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
450      break;
451    case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
452      if (TYPE_MAX_VALUE (new_var_type))
453	new_var_init = build_modify_expr
454	  (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
455	   location, TYPE_MAX_VALUE (new_var_type), new_var_type);
456      else
457	new_var_init = build_modify_expr
458	  (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
459	   location, func_parm, new_var_type);
460      new_no_expr = build_modify_expr
461	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
462	 location, *new_var, TREE_TYPE (*new_var));
463      new_yes_expr = build_modify_expr
464	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
465	 location, func_parm, TREE_TYPE (*new_var));
466      new_expr = build_conditional_expr
467	(location,
468	 build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false,
469	 new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var));
470      break;
471    case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
472      new_var_init = build_modify_expr
473	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
474	 location, build_zero_cst (new_var_type), new_var_type);
475      new_exp_init = build_modify_expr
476	(location, array_ind_value, TREE_TYPE (array_ind_value),
477	 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
478      new_no_ind = build_modify_expr
479	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
480	 location, *new_var, TREE_TYPE (*new_var));
481      new_no_expr = build_modify_expr
482	(location, array_ind_value, TREE_TYPE (array_ind_value),
483	 NOP_EXPR,
484	 location, array_ind_value, TREE_TYPE (array_ind_value));
485      if (list_size > 1)
486	{
487	  new_yes_ind = build_modify_expr
488	    (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
489	     location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
490	  new_yes_expr = build_modify_expr
491	    (location, array_ind_value, TREE_TYPE (array_ind_value),
492	     NOP_EXPR,
493	     location, func_parm, TREE_TYPE ((*array_operand)[0]));
494	}
495      else
496	{
497	  new_yes_ind = build_modify_expr
498	    (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
499	     location, TREE_OPERAND (array_op0, 1),
500	     TREE_TYPE (TREE_OPERAND (array_op0, 1)));
501	  new_yes_expr = build_modify_expr
502	    (location, array_ind_value, TREE_TYPE (array_ind_value),
503	     NOP_EXPR,
504	     location, func_parm, TREE_OPERAND (array_op0, 1));
505	}
506      new_yes_list = alloc_stmt_list ();
507      append_to_statement_list (new_yes_ind, &new_yes_list);
508      append_to_statement_list (new_yes_expr, &new_yes_list);
509
510      new_no_list = alloc_stmt_list ();
511      append_to_statement_list (new_no_ind, &new_no_list);
512      append_to_statement_list (new_no_expr, &new_no_list);
513
514      new_expr = build_conditional_expr
515	(location,
516	 build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
517		 func_parm),
518	 false,
519	 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
520      break;
521    case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
522      new_var_init = build_modify_expr
523	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
524	 location, build_zero_cst (new_var_type), new_var_type);
525      new_exp_init = build_modify_expr
526	(location, array_ind_value, TREE_TYPE (array_ind_value),
527	 NOP_EXPR, location, func_parm, TREE_TYPE (func_parm));
528      new_no_ind = build_modify_expr
529	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
530	 location, *new_var, TREE_TYPE (*new_var));
531      new_no_expr = build_modify_expr
532	(location, array_ind_value, TREE_TYPE (array_ind_value),
533	 NOP_EXPR,
534	 location, array_ind_value, TREE_TYPE (array_ind_value));
535      if (list_size > 1)
536	{
537	  new_yes_ind = build_modify_expr
538	    (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
539	     location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var));
540	  new_yes_expr = build_modify_expr
541	    (location, array_ind_value, TREE_TYPE (array_ind_value),
542	     NOP_EXPR,
543	     location, func_parm, TREE_TYPE (array_op0));
544	}
545      else
546	{
547	  new_yes_ind = build_modify_expr
548	    (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
549	     location, TREE_OPERAND (array_op0, 1),
550	     TREE_TYPE (TREE_OPERAND (array_op0, 1)));
551	  new_yes_expr = build_modify_expr
552	    (location, array_ind_value, TREE_TYPE (array_ind_value),
553	     NOP_EXPR,
554	     location, func_parm, TREE_OPERAND (array_op0, 1));
555	}
556      new_yes_list = alloc_stmt_list ();
557      append_to_statement_list (new_yes_ind, &new_yes_list);
558      append_to_statement_list (new_yes_expr, &new_yes_list);
559
560      new_no_list = alloc_stmt_list ();
561      append_to_statement_list (new_no_ind, &new_no_list);
562      append_to_statement_list (new_no_expr, &new_no_list);
563
564      new_expr = build_conditional_expr
565	(location,
566	 build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value,
567		 func_parm),
568	 false,
569	 new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var));
570      break;
571    case BUILT_IN_CILKPLUS_SEC_REDUCE:
572      new_var_init = build_modify_expr
573	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
574	 location, identity_value, new_var_type);
575      new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm);
576      new_expr = build_modify_expr
577	(location, *new_var, TREE_TYPE (*new_var), NOP_EXPR,
578	 location, new_call_expr, TREE_TYPE (*new_var));
579      break;
580    case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
581      new_expr = build_call_expr (call_fn, 2, identity_value, func_parm);
582      break;
583    default:
584      gcc_unreachable ();
585      break;
586    }
587
588  for (ii = 0; ii < rank; ii++)
589    append_to_statement_list (an_loop_info[ii].ind_init, &loop_init);
590
591  if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
592      || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
593    append_to_statement_list (new_exp_init, &loop_init);
594  if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
595    append_to_statement_list (new_var_init, &loop_init);
596
597  append_to_statement_list_force (loop_init, &loop_with_init);
598  body = new_expr;
599  for (ii = 0; ii < rank; ii++)
600    {
601      tree new_loop = push_stmt_list ();
602      c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
603		     body, NULL_TREE, NULL_TREE, true);
604      body = pop_stmt_list (new_loop);
605    }
606  append_to_statement_list_force (body, &loop_with_init);
607
608  an_info.release ();
609  an_loop_info.release ();
610
611  return loop_with_init;
612}
613
614/* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
615   The LHS and/or RHS will be array notation expressions that have a MODIFYCODE
616   Their locations are specified by LHS_LOC, RHS_LOC.  The location of the
617   modify expression is location.  The original type of LHS and RHS are passed
618   in LHS_ORIGTYPE and RHS_ORIGTYPE.  */
619
620tree
621build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
622			   enum tree_code modifycode, location_t rhs_loc,
623			   tree rhs, tree rhs_origtype)
624{
625  bool found_builtin_fn = false;
626  tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
627  tree array_expr = NULL_TREE;
628  tree an_init = NULL_TREE;
629  vec<tree> cond_expr = vNULL;
630  tree body, loop_with_init = alloc_stmt_list();
631  tree scalar_mods = NULL_TREE;
632  vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL;
633  size_t lhs_rank = 0, rhs_rank = 0;
634  size_t ii = 0;
635  vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL;
636  tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE;
637  size_t rhs_list_size = 0, lhs_list_size = 0;
638  vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
639  vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL;
640
641  /* If either of this is true, an error message must have been send out
642     already.  Not necessary to send out multiple error messages.  */
643  if (lhs == error_mark_node || rhs == error_mark_node)
644    return error_mark_node;
645
646  if (!find_rank (location, rhs, rhs, false, &rhs_rank))
647    return error_mark_node;
648
649  extract_array_notation_exprs (rhs, false, &rhs_list);
650  rhs_list_size = vec_safe_length (rhs_list);
651  an_init = push_stmt_list ();
652  if (rhs_rank)
653    {
654      scalar_mods = replace_invariant_exprs (&rhs);
655      if (scalar_mods)
656	add_stmt (scalar_mods);
657    }
658  for (ii = 0; ii < rhs_list_size; ii++)
659    {
660      tree rhs_node = (*rhs_list)[ii];
661      if (TREE_CODE (rhs_node) == CALL_EXPR)
662	{
663	  builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
664	  if (builtin_loop == error_mark_node)
665	    {
666	      pop_stmt_list (an_init);
667	      return error_mark_node;
668	    }
669	  else if (builtin_loop)
670	    {
671	      add_stmt (builtin_loop);
672	      found_builtin_fn = true;
673	      if (new_var)
674		{
675		  vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
676		  vec_safe_push (rhs_sub_list, rhs_node);
677		  vec_safe_push (new_var_list, new_var);
678		  replace_array_notations (&rhs, false, rhs_sub_list,
679					   new_var_list);
680		}
681	    }
682	}
683    }
684
685  lhs_rank = 0;
686  rhs_rank = 0;
687  if (!find_rank (location, lhs, lhs, true, &lhs_rank))
688    {
689      pop_stmt_list (an_init);
690      return error_mark_node;
691    }
692
693  if (!find_rank (location, rhs, rhs, true, &rhs_rank))
694    {
695      pop_stmt_list (an_init);
696      return error_mark_node;
697    }
698
699  if (lhs_rank == 0 && rhs_rank == 0)
700    {
701      if (found_builtin_fn)
702	{
703	  new_modify_expr = build_modify_expr (location, lhs, lhs_origtype,
704					       modifycode, rhs_loc, rhs,
705					       rhs_origtype);
706	  add_stmt (new_modify_expr);
707	  pop_stmt_list (an_init);
708	  return an_init;
709	}
710      else
711	{
712	  pop_stmt_list (an_init);
713	  return NULL_TREE;
714	}
715    }
716  rhs_list_size = 0;
717  rhs_list = NULL;
718  extract_array_notation_exprs (rhs, true, &rhs_list);
719  extract_array_notation_exprs (lhs, true, &lhs_list);
720  rhs_list_size = vec_safe_length (rhs_list);
721  lhs_list_size = vec_safe_length (lhs_list);
722
723  if (lhs_rank == 0 && rhs_rank != 0)
724    {
725      tree rhs_base = rhs;
726      if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
727	{
728	  for (ii = 0; ii < (size_t) rhs_rank; ii++)
729	    rhs_base = ARRAY_NOTATION_ARRAY (rhs);
730
731	  error_at (location, "%qE cannot be scalar when %qE is not", lhs,
732		    rhs_base);
733	  return error_mark_node;
734	}
735      else
736	{
737	  error_at (location, "%qE cannot be scalar when %qE is not", lhs,
738		    rhs_base);
739	  return error_mark_node;
740	}
741    }
742  if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
743    {
744      error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
745      pop_stmt_list (an_init);
746      return error_mark_node;
747    }
748
749  /* Here we assign the array notation components to variable so that we can
750     satisfy the exec once rule.  */
751  for (ii = 0; ii < lhs_list_size; ii++)
752    {
753      tree array_node = (*lhs_list)[ii];
754      make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
755      make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
756      make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
757    }
758  for (ii = 0; ii < rhs_list_size; ii++)
759    if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
760      {
761	tree array_node = (*rhs_list)[ii];
762	make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
763	make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
764	make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
765      }
766
767  cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
768
769  lhs_an_loop_info.safe_grow_cleared (lhs_rank);
770  if (rhs_rank)
771    rhs_an_loop_info.safe_grow_cleared (rhs_rank);
772
773  cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
774				&lhs_an_info);
775  if (rhs_rank)
776    {
777      rhs_an_loop_info.safe_grow_cleared (rhs_rank);
778      cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
779				    &rhs_an_info);
780    }
781  if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
782      || (rhs_rank
783	  && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info)))
784    {
785      pop_stmt_list (an_init);
786      return error_mark_node;
787    }
788  if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
789      && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST
790      && rhs_an_info[0][0].length
791      && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST)
792    {
793      HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length);
794      HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length);
795      /* Length can be negative or positive.  As long as the magnitude is OK,
796	 then the array notation is valid.  */
797      if (absu_hwi (l_length) != absu_hwi (r_length))
798	{
799	  error_at (location, "length mismatch between LHS and RHS");
800	  pop_stmt_list (an_init);
801	  return error_mark_node;
802	}
803    }
804  for (ii = 0; ii < lhs_rank; ii++)
805    if (lhs_an_info[0][ii].is_vector)
806      {
807	lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
808	lhs_an_loop_info[ii].ind_init = build_modify_expr
809	  (location, lhs_an_loop_info[ii].var,
810	   TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR,
811	   location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)),
812	   TREE_TYPE (lhs_an_loop_info[ii].var));
813      }
814  for (ii = 0; ii < rhs_rank; ii++)
815    {
816      /* When we have a polynomial, we assume that the indices are of type
817	 integer.  */
818      rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
819      rhs_an_loop_info[ii].ind_init = build_modify_expr
820	(location, rhs_an_loop_info[ii].var,
821	 TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR,
822	 location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0),
823	 TREE_TYPE (rhs_an_loop_info[ii].var));
824    }
825  if (lhs_rank)
826    {
827      lhs_array_operand = create_array_refs
828	(location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank);
829      replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
830      array_expr_lhs = lhs;
831    }
832  if (rhs_array_operand)
833    vec_safe_truncate (rhs_array_operand, 0);
834  if (rhs_rank)
835    {
836      rhs_array_operand = create_array_refs
837	(location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank);
838      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
839      vec_safe_truncate (rhs_array_operand, 0);
840      rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
841						 rhs_an_loop_info, rhs_rank,
842						 rhs);
843      if (!rhs_array_operand)
844	return error_mark_node;
845      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
846    }
847  else if (rhs_list_size > 0)
848    {
849      rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
850						 lhs_an_loop_info, lhs_rank,
851						 lhs);
852      if (!rhs_array_operand)
853	return error_mark_node;
854      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
855    }
856  array_expr_lhs = lhs;
857  array_expr_rhs = rhs;
858  array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype,
859				  modifycode, rhs_loc, array_expr_rhs,
860				  rhs_origtype);
861  create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info);
862  if (rhs_rank)
863    create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info);
864
865  for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
866    if (ii < lhs_rank && ii < rhs_rank)
867      cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node,
868			      lhs_an_loop_info[ii].cmp,
869			      rhs_an_loop_info[ii].cmp);
870    else if (ii < lhs_rank && ii >= rhs_rank)
871      cond_expr[ii] = lhs_an_loop_info[ii].cmp;
872    else
873      gcc_unreachable ();
874
875  an_init = pop_stmt_list (an_init);
876  append_to_statement_list_force (an_init, &loop_with_init);
877  body = array_expr;
878  for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
879    {
880      tree incr_list = alloc_stmt_list ();
881      tree new_loop = push_stmt_list ();
882      if (lhs_rank)
883	add_stmt (lhs_an_loop_info[ii].ind_init);
884      if (rhs_rank)
885	add_stmt (rhs_an_loop_info[ii].ind_init);
886      if (lhs_rank)
887	append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list);
888      if (rhs_rank && rhs_an_loop_info[ii].incr)
889	append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list);
890      c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE,
891		     NULL_TREE, true);
892      body = pop_stmt_list (new_loop);
893    }
894  append_to_statement_list_force (body, &loop_with_init);
895
896  lhs_an_info.release ();
897  lhs_an_loop_info.release ();
898  if (rhs_rank)
899    {
900      rhs_an_info.release ();
901      rhs_an_loop_info.release ();
902    }
903  cond_expr.release ();
904  return loop_with_init;
905}
906
907/* Helper function for fix_conditional_array_notations.  Encloses the
908   conditional statement passed in STMT with a loop around it
909   and replaces the condition in STMT with a ARRAY_REF tree-node to the array.
910   The condition must have an ARRAY_NOTATION_REF tree.  An expansion of array
911   notation in STMT is returned in a STATEMENT_LIST.  */
912
913static tree
914fix_conditional_array_notations_1 (tree stmt)
915{
916  vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
917  size_t list_size = 0;
918  tree cond = NULL_TREE, builtin_loop = NULL_TREE, new_var = NULL_TREE;
919  size_t rank = 0, ii = 0;
920  tree loop_init;
921  location_t location = EXPR_LOCATION (stmt);
922  tree body = NULL_TREE, loop_with_init = alloc_stmt_list ();
923  vec<vec<an_parts> > an_info = vNULL;
924  vec<an_loop_parts> an_loop_info = vNULL;
925
926  if (TREE_CODE (stmt) == COND_EXPR)
927    cond = COND_EXPR_COND (stmt);
928  else if (TREE_CODE (stmt) == SWITCH_EXPR)
929    cond = SWITCH_COND (stmt);
930  else if (truth_value_p (TREE_CODE (stmt)))
931    cond = TREE_OPERAND (stmt, 0);
932  else
933    /* Otherwise dont even touch the statement.  */
934    return stmt;
935
936  if (!find_rank (location, cond, cond, false, &rank))
937    return error_mark_node;
938
939  extract_array_notation_exprs (stmt, false, &array_list);
940  loop_init = push_stmt_list ();
941  for (ii = 0; ii < vec_safe_length (array_list); ii++)
942    {
943      tree array_node = (*array_list)[ii];
944      if (TREE_CODE (array_node) == CALL_EXPR)
945	{
946	  builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var);
947	  if (builtin_loop == error_mark_node)
948	    {
949	      add_stmt (error_mark_node);
950	      pop_stmt_list (loop_init);
951	      return loop_init;
952	    }
953	  else if (builtin_loop)
954	    {
955	      vec <tree, va_gc>* sub_list = NULL, *new_var_list = NULL;
956	      vec_safe_push (sub_list, array_node);
957	      vec_safe_push (new_var_list, new_var);
958	      add_stmt (builtin_loop);
959	      replace_array_notations (&stmt, false, sub_list, new_var_list);
960	    }
961	}
962    }
963  if (!find_rank (location, stmt, stmt, true, &rank))
964    {
965      pop_stmt_list (loop_init);
966      return error_mark_node;
967    }
968  if (rank == 0)
969    {
970      add_stmt (stmt);
971      pop_stmt_list (loop_init);
972      return loop_init;
973    }
974  extract_array_notation_exprs (stmt, true, &array_list);
975
976  if (vec_safe_length (array_list) == 0)
977    return stmt;
978
979  list_size = vec_safe_length (array_list);
980  an_loop_info.safe_grow_cleared (rank);
981
982  for (ii = 0; ii < list_size; ii++)
983    if ((*array_list)[ii]
984	&& TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
985      {
986	tree array_node = (*array_list)[ii];
987	make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
988	make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
989	make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
990      }
991  cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
992  for (ii = 0; ii < rank; ii++)
993    {
994      an_loop_info[ii].var = create_tmp_var (integer_type_node);
995      an_loop_info[ii].ind_init =
996	build_modify_expr (location, an_loop_info[ii].var,
997			   TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
998			   location,
999			   build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1000			   TREE_TYPE (an_loop_info[ii].var));
1001    }
1002  array_operand = create_array_refs (location, an_info, an_loop_info,
1003				     list_size, rank);
1004  replace_array_notations (&stmt, true, array_list, array_operand);
1005  create_cmp_incr (location, &an_loop_info, rank, an_info);
1006
1007  loop_init = pop_stmt_list (loop_init);
1008  body = stmt;
1009  append_to_statement_list_force (loop_init, &loop_with_init);
1010
1011  for (ii = 0; ii < rank; ii++)
1012    {
1013      tree new_loop = push_stmt_list ();
1014      add_stmt (an_loop_info[ii].ind_init);
1015      c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1016		     body, NULL_TREE, NULL_TREE, true);
1017      body = pop_stmt_list (new_loop);
1018    }
1019  append_to_statement_list_force (body, &loop_with_init);
1020
1021  an_loop_info.release ();
1022  an_info.release ();
1023
1024  return loop_with_init;
1025}
1026
1027/* Top-level function to replace ARRAY_NOTATION_REF in a conditional statement
1028   in STMT.   An expansion of array notation in STMT is returned as a
1029   STATEMENT_LIST.  */
1030
1031tree
1032fix_conditional_array_notations (tree stmt)
1033{
1034  if (TREE_CODE (stmt) == STATEMENT_LIST)
1035    {
1036      tree_stmt_iterator tsi;
1037      for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi))
1038	{
1039	  tree single_stmt = *tsi_stmt_ptr (tsi);
1040	  *tsi_stmt_ptr (tsi) =
1041	    fix_conditional_array_notations_1 (single_stmt);
1042	}
1043      return stmt;
1044    }
1045  else
1046    return fix_conditional_array_notations_1 (stmt);
1047}
1048
1049/* Create a struct c_expr that contains a loop with ARRAY_REF expr at location
1050   LOCATION with the tree_code CODE and the array notation expr is
1051   passed in ARG.  Returns the fixed c_expr in ARG itself.  */
1052
1053struct c_expr
1054fix_array_notation_expr (location_t location, enum tree_code code,
1055			 struct c_expr arg)
1056{
1057
1058  vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1059  size_t list_size = 0, rank = 0, ii = 0;
1060  tree loop_init;
1061  tree body, loop_with_init = alloc_stmt_list ();
1062  vec<vec<an_parts> > an_info = vNULL;
1063  vec<an_loop_parts> an_loop_info = vNULL;
1064
1065  if (!find_rank (location, arg.value, arg.value, false, &rank))
1066    {
1067      /* If this function returns a NULL, we convert the tree value in the
1068	 structure to error_mark_node and the parser should take care of the
1069	 rest.  */
1070      arg.value = error_mark_node;
1071      return arg;
1072    }
1073
1074  if (rank == 0)
1075    return arg;
1076
1077  extract_array_notation_exprs (arg.value, true, &array_list);
1078
1079  if (vec_safe_length (array_list) == 0)
1080    return arg;
1081
1082  list_size = vec_safe_length (array_list);
1083
1084  an_loop_info.safe_grow_cleared (rank);
1085  cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1086
1087  loop_init = push_stmt_list ();
1088  for (ii = 0; ii < rank; ii++)
1089    {
1090      an_loop_info[ii].var = create_tmp_var (integer_type_node);
1091      an_loop_info[ii].ind_init =
1092	build_modify_expr (location, an_loop_info[ii].var,
1093			   TREE_TYPE (an_loop_info[ii].var), NOP_EXPR,
1094			   location,
1095			   build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1096			   TREE_TYPE (an_loop_info[ii].var));;
1097
1098    }
1099  array_operand = create_array_refs (location, an_info, an_loop_info,
1100				     list_size, rank);
1101  replace_array_notations (&arg.value, true, array_list, array_operand);
1102  create_cmp_incr (location, &an_loop_info, rank, an_info);
1103
1104  arg = default_function_array_read_conversion (location, arg);
1105  if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
1106    arg.value = build_unary_op (location, code, arg.value, 0);
1107  else if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
1108    arg = parser_build_unary_op (location, code, arg);
1109
1110  loop_init = pop_stmt_list (loop_init);
1111  append_to_statement_list_force (loop_init, &loop_with_init);
1112  body = arg.value;
1113
1114  for (ii = 0; ii < rank; ii++)
1115    {
1116      tree new_loop = push_stmt_list ();
1117      add_stmt (an_loop_info[ii].ind_init);
1118      c_finish_loop (location, an_loop_info[ii].cmp,
1119		     an_loop_info[ii].incr, body, NULL_TREE,
1120		     NULL_TREE, true);
1121      body = pop_stmt_list (new_loop);
1122    }
1123  append_to_statement_list_force (body, &loop_with_init);
1124  arg.value = loop_with_init;
1125  an_info.release ();
1126  an_loop_info.release ();
1127  return arg;
1128}
1129
1130/* Replaces array notations in a void function call arguments in ARG and returns
1131   a STATEMENT_LIST.  */
1132
1133static tree
1134fix_array_notation_call_expr (tree arg)
1135{
1136  vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
1137  tree new_var = NULL_TREE;
1138  size_t list_size = 0, rank = 0, ii = 0;
1139  tree loop_init;
1140  tree body, loop_with_init = alloc_stmt_list ();
1141  location_t location = UNKNOWN_LOCATION;
1142  vec<vec<an_parts> > an_info = vNULL;
1143  vec<an_loop_parts> an_loop_info = vNULL;
1144
1145  if (TREE_CODE (arg) == CALL_EXPR
1146      && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg)))
1147    {
1148      loop_init = fix_builtin_array_notation_fn (arg, &new_var);
1149      /* We are ignoring the new var because either the user does not want to
1150	 capture it OR he is using sec_reduce_mutating function.  */
1151      return loop_init;
1152    }
1153  if (!find_rank (location, arg, arg, false, &rank))
1154    return error_mark_node;
1155
1156  if (rank == 0)
1157    return arg;
1158
1159  extract_array_notation_exprs (arg, true, &array_list);
1160  if (vec_safe_length (array_list) == 0)
1161    return arg;
1162
1163  list_size = vec_safe_length (array_list);
1164  location = EXPR_LOCATION (arg);
1165  an_loop_info.safe_grow_cleared (rank);
1166
1167  loop_init = push_stmt_list ();
1168  for (ii = 0; ii < list_size; ii++)
1169    if ((*array_list)[ii]
1170	&& TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
1171	{
1172	  tree array_node = (*array_list)[ii];
1173	  make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
1174	  make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
1175	  make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
1176	}
1177  cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
1178  if (length_mismatch_in_expr_p (location, an_info))
1179    {
1180      pop_stmt_list (loop_init);
1181      return error_mark_node;
1182    }
1183  for (ii = 0; ii < rank; ii++)
1184    {
1185      an_loop_info[ii].var = create_tmp_var (integer_type_node);
1186      an_loop_info[ii].ind_init =
1187	build_modify_expr (location, an_loop_info[ii].var,
1188			   TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location,
1189			   build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
1190			   TREE_TYPE (an_loop_info[ii].var));
1191
1192    }
1193  array_operand = create_array_refs (location, an_info, an_loop_info,
1194				     list_size, rank);
1195  replace_array_notations (&arg, true, array_list, array_operand);
1196  create_cmp_incr (location, &an_loop_info, rank, an_info);
1197  loop_init = pop_stmt_list (loop_init);
1198  append_to_statement_list_force (loop_init, &loop_with_init);
1199  body = arg;
1200  for (ii = 0; ii < rank; ii++)
1201    {
1202      tree new_loop = push_stmt_list ();
1203      add_stmt (an_loop_info[ii].ind_init);
1204      c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
1205		     body, NULL_TREE, NULL_TREE, true);
1206      body = pop_stmt_list (new_loop);
1207    }
1208  append_to_statement_list_force (body, &loop_with_init);
1209  an_loop_info.release ();
1210  an_info.release ();
1211  return loop_with_init;
1212}
1213
1214/* Expands the built-in functions in a return.  EXPR is a RETURN_EXPR with
1215   a built-in reduction function.  This function returns the expansion code for
1216   the built-in function.  */
1217
1218static tree
1219fix_return_expr (tree expr)
1220{
1221  tree new_mod_list, new_var, new_mod, retval_expr, retval_type;
1222  location_t loc = EXPR_LOCATION (expr);
1223
1224  new_mod_list = alloc_stmt_list ();
1225  retval_expr = TREE_OPERAND (expr, 0);
1226  retval_type = TREE_TYPE (TREE_OPERAND (retval_expr, 1));
1227  new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr));
1228  new_mod = build_array_notation_expr (loc, new_var, TREE_TYPE (new_var),
1229				       NOP_EXPR, loc,
1230				       TREE_OPERAND (retval_expr, 1),
1231				       retval_type);
1232  TREE_OPERAND (retval_expr, 1) = new_var;
1233  TREE_OPERAND (expr, 0) = retval_expr;
1234  append_to_statement_list_force (new_mod, &new_mod_list);
1235  append_to_statement_list_force (expr, &new_mod_list);
1236  return new_mod_list;
1237}
1238
1239/* Callback for walk_tree.  Expands all array notations in *TP.  *WALK_SUBTREES
1240   is set to 1 unless *TP contains no array notation expressions.  */
1241
1242static tree
1243expand_array_notations (tree *tp, int *walk_subtrees, void *)
1244{
1245  if (!contains_array_notation_expr (*tp))
1246    {
1247      *walk_subtrees = 0;
1248      return NULL_TREE;
1249    }
1250  *walk_subtrees = 1;
1251
1252  switch (TREE_CODE (*tp))
1253    {
1254    case TRUTH_ORIF_EXPR:
1255    case TRUTH_ANDIF_EXPR:
1256    case TRUTH_OR_EXPR:
1257    case TRUTH_AND_EXPR:
1258    case TRUTH_XOR_EXPR:
1259    case TRUTH_NOT_EXPR:
1260    case COND_EXPR:
1261      *tp = fix_conditional_array_notations (*tp);
1262      break;
1263    case MODIFY_EXPR:
1264      {
1265	location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) :
1266	  UNKNOWN_LOCATION;
1267	tree lhs = TREE_OPERAND (*tp, 0);
1268	tree rhs = TREE_OPERAND (*tp, 1);
1269	location_t rhs_loc = EXPR_HAS_LOCATION (rhs) ? EXPR_LOCATION (rhs) :
1270	  UNKNOWN_LOCATION;
1271	*tp = build_array_notation_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR,
1272					 rhs_loc, rhs, TREE_TYPE (rhs));
1273      }
1274      break;
1275    case DECL_EXPR:
1276      {
1277	tree x = DECL_EXPR_DECL (*tp);
1278	if (DECL_INITIAL (x))
1279	  {
1280	    location_t loc = DECL_SOURCE_LOCATION (x);
1281	    tree lhs = x;
1282	    tree rhs = DECL_INITIAL (x);
1283	    DECL_INITIAL (x) = NULL;
1284	    tree new_modify_expr = build_modify_expr (loc, lhs,
1285						      TREE_TYPE (lhs),
1286						      NOP_EXPR,
1287						      loc, rhs,
1288						      TREE_TYPE(rhs));
1289	    expand_array_notations (&new_modify_expr, walk_subtrees, NULL);
1290	    *tp = new_modify_expr;
1291	  }
1292      }
1293      break;
1294    case CALL_EXPR:
1295      *tp = fix_array_notation_call_expr (*tp);
1296      break;
1297    case RETURN_EXPR:
1298      *tp = fix_return_expr (*tp);
1299      break;
1300    case COMPOUND_EXPR:
1301      if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR)
1302	{
1303	  /* In here we are calling expand_array_notations because
1304	     we need to be able to catch the return value and check if
1305	     it is an error_mark_node.  */
1306	  expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL);
1307
1308	  /* SAVE_EXPR cannot have an error_mark_node inside it.  This check
1309	     will make sure that if there is an error in expanding of
1310	     array notations (e.g. rank mismatch) then replace the entire
1311	     SAVE_EXPR with an error_mark_node.  */
1312	  if (TREE_OPERAND (*tp, 1) == error_mark_node)
1313	    *tp = error_mark_node;
1314	}
1315      break;
1316    case ARRAY_NOTATION_REF:
1317      /* If we are here, then we are dealing with cases like this:
1318	 A[:];
1319	 A[x:y:z];
1320	 A[x:y];
1321	 Replace those with just void zero node.  */
1322      *tp = void_node;
1323    default:
1324      break;
1325    }
1326  return NULL_TREE;
1327}
1328
1329/* Walks through tree node T and expands all array notations in its subtrees.
1330   The return value is the same type as T but with all array notations
1331   replaced with appropriate ARRAY_REFS with a loop around it.  */
1332
1333tree
1334expand_array_notation_exprs (tree t)
1335{
1336  walk_tree (&t, expand_array_notations, NULL, NULL);
1337  return t;
1338}
1339
1340/* This handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which
1341   denotes an array notation expression.  If a is a variable or a member, then
1342   we generate a ARRAY_NOTATION_REF front-end tree and return it.
1343   This tree is broken down to ARRAY_REF toward the end of parsing.
1344   ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE
1345   of ARRAY_REF.  Restrictions on START_INDEX, LENGTH and STRIDE is same as that
1346   of the index field passed into ARRAY_REF.  The only additional restriction
1347   is that, unlike index in ARRAY_REF, stride, length and start_index cannot
1348   contain ARRAY_NOTATIONS.   */
1349
1350tree
1351build_array_notation_ref (location_t loc, tree array, tree start_index,
1352			  tree length, tree stride, tree type)
1353{
1354  tree array_ntn_tree = NULL_TREE;
1355  size_t stride_rank = 0, length_rank = 0, start_rank = 0;
1356
1357  if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
1358    {
1359      error_at (loc,
1360		"start-index of array notation triplet is not an integer");
1361      return error_mark_node;
1362    }
1363  if (!INTEGRAL_TYPE_P (TREE_TYPE (length)))
1364    {
1365      error_at (loc, "length of array notation triplet is not an integer");
1366      return error_mark_node;
1367    }
1368
1369  /* The stride is an optional field.  */
1370  if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
1371    {
1372      error_at (loc, "stride of array notation triplet is not an integer");
1373      return error_mark_node;
1374    }
1375  if (!stride)
1376    {
1377      if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length)
1378	  && tree_int_cst_lt (length, start_index))
1379	stride = build_int_cst (TREE_TYPE (start_index), -1);
1380      else
1381	stride = build_int_cst (TREE_TYPE (start_index), 1);
1382    }
1383
1384  if (!find_rank (loc, start_index, start_index, false, &start_rank))
1385    return error_mark_node;
1386  if (!find_rank (loc, length, length, false, &length_rank))
1387    return error_mark_node;
1388  if (!find_rank (loc, stride, stride, false, &stride_rank))
1389    return error_mark_node;
1390
1391  if (start_rank != 0)
1392    {
1393      error_at (loc, "rank of an array notation triplet's start-index is not "
1394		"zero");
1395      return error_mark_node;
1396    }
1397  if (length_rank != 0)
1398    {
1399      error_at (loc, "rank of an array notation triplet's length is not zero");
1400      return error_mark_node;
1401    }
1402  if (stride_rank != 0)
1403    {
1404      error_at (loc, "rank of array notation triplet's stride is not zero");
1405      return error_mark_node;
1406    }
1407  array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE,
1408			   NULL_TREE, NULL_TREE);
1409  ARRAY_NOTATION_ARRAY (array_ntn_tree) = array;
1410  ARRAY_NOTATION_START (array_ntn_tree) = start_index;
1411  ARRAY_NOTATION_LENGTH (array_ntn_tree) = length;
1412  ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride;
1413  TREE_TYPE (array_ntn_tree) = type;
1414
1415  return array_ntn_tree;
1416}
1417