1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2    This file contains the builtin functions for Array
3    notations.
4    Copyright (C) 2013-2016 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 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "options.h"
28 #include "c-family/c-common.h"
29 #include "tree-iterator.h"
30 
31 /* Returns true if the function call in FNDECL is  __sec_implicit_index.  */
32 
33 bool
is_sec_implicit_index_fn(tree fndecl)34 is_sec_implicit_index_fn (tree fndecl)
35 {
36   if (!fndecl)
37     return false;
38 
39   if (TREE_CODE (fndecl) == ADDR_EXPR)
40     fndecl = TREE_OPERAND (fndecl, 0);
41 
42   return
43     (TREE_CODE (fndecl) == FUNCTION_DECL
44      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
45      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CILKPLUS_SEC_IMPLICIT_INDEX);
46 }
47 
48 /* Returns the first and only argument for FN, which should be a
49    sec_implicit_index function.  FN's location in the source file is as
50    indicated by LOCATION.  The argument to FN must be a constant integer
51    expression, otherwise returns -1.  */
52 
53 HOST_WIDE_INT
extract_sec_implicit_index_arg(location_t location,tree fn)54 extract_sec_implicit_index_arg (location_t location, tree fn)
55 {
56   tree fn_arg;
57   HOST_WIDE_INT return_int = 0;
58 
59   if (TREE_CODE (fn) == CALL_EXPR)
60     {
61       fn_arg = CALL_EXPR_ARG (fn, 0);
62       if (TREE_CODE (fn_arg) == INTEGER_CST)
63 	return_int = int_cst_value (fn_arg);
64       else
65 	{
66 	  /* If the location is unknown, and if fn has a location, then use that
67 	     information so that the user has a better idea where the error
68 	     could be.  */
69 	  if (location == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (fn))
70 	    location = EXPR_LOCATION (fn);
71 	  error_at (location, "__sec_implicit_index parameter must be an "
72 		    "integer constant expression");
73 	  return -1;
74 	}
75     }
76   return return_int;
77 }
78 
79 /* Returns true if there is a length mismatch among exprssions that are at the
80    same dimension and one the same side of the equal sign.  The Array notation
81    lengths (LIST->LENGTH) is passed in as a 2D vector of trees.  */
82 
83 bool
length_mismatch_in_expr_p(location_t loc,vec<vec<an_parts>> list)84 length_mismatch_in_expr_p (location_t loc, vec<vec<an_parts> >list)
85 {
86   size_t ii, jj;
87   tree length = NULL_TREE;
88 
89   size_t x = list.length ();
90   size_t y = list[0].length ();
91 
92   for (jj = 0; jj < y; jj++)
93     {
94       length = NULL_TREE;
95       for (ii = 0; ii < x; ii++)
96 	{
97 	  if (!length)
98 	    length = list[ii][jj].length;
99 	  else if (TREE_CODE (length) == INTEGER_CST)
100 	    {
101 	      /* If length is a INTEGER, and list[ii][jj] is an integer then
102 		 check if they are equal.  If they are not equal then return
103 		 true.  */
104 	      if (TREE_CODE (list[ii][jj].length) == INTEGER_CST
105 		  && !tree_int_cst_equal (list[ii][jj].length, length))
106 		{
107 		  error_at (loc, "length mismatch in expression");
108 		  return true;
109 		}
110 	    }
111 	  else
112 	    /* We set the length node as the current node just in case it turns
113 	       out to be an integer.  */
114 	    length = list[ii][jj].length;
115 	}
116     }
117   return false;
118 }
119 
120 /* Given an FNDECL of type FUNCTION_DECL or ADDR_EXPR, return the corresponding
121    BUILT_IN_CILKPLUS_SEC_REDUCE_* being called.  If none, return
122    BUILT_IN_NONE.  */
123 
124 enum built_in_function
is_cilkplus_reduce_builtin(tree fndecl)125 is_cilkplus_reduce_builtin (tree fndecl)
126 {
127   if (!fndecl)
128     return BUILT_IN_NONE;
129   if (TREE_CODE (fndecl) == ADDR_EXPR)
130     fndecl = TREE_OPERAND (fndecl, 0);
131 
132   if (TREE_CODE (fndecl) == FUNCTION_DECL
133       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
134     switch (DECL_FUNCTION_CODE (fndecl))
135       {
136       case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
137       case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
138       case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
139       case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
140       case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
141       case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
142       case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
143       case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
144       case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
145       case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
146       case BUILT_IN_CILKPLUS_SEC_REDUCE:
147       case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
148 	return DECL_FUNCTION_CODE (fndecl);
149       default:
150 	break;
151       }
152 
153   return BUILT_IN_NONE;
154 }
155 
156 /* This function will recurse into EXPR finding any
157    ARRAY_NOTATION_EXPRs and calculate the overall rank of EXPR,
158    storing it in *RANK. LOC is the location of the original expression.
159 
160    ORIG_EXPR is the original expression used to display if any rank
161    mismatch errors are found.
162 
163    Upon entry, *RANK must be either 0, or the rank of a parent
164    expression that must have the same rank as the one being
165    calculated.  It is illegal to have multiple array notation with different
166    rank in the same expression (see examples below for clarification).
167 
168    If there were any rank mismatches while calculating the rank, an
169    error will be issued, and FALSE will be returned.  Otherwise, TRUE
170    is returned.
171 
172    If IGNORE_BUILTIN_FN is TRUE, ignore array notation specific
173    built-in functions (__sec_reduce_*, etc).
174 
175    Here are some examples of array notations and their rank:
176 
177    Expression			    RANK
178    5				    0
179    X (a variable)		    0
180    *Y (a pointer)		    0
181    A[5]				    0
182    B[5][10]			    0
183    A[:]				    1
184    B[0:10]			    1
185    C[0:10:2]			    1
186    D[5][0:10:2]			    1 (since D[5] is considered "scalar")
187    D[5][:][10]			    1
188    E[:] + 5			    1
189    F[:][:][:] + 5 + X		    3
190    F[:][:][:] + E[:] + 5 + X	    RANKMISMATCH-ERROR since rank (E[:]) = 1 and
191                                     rank (F[:][:][:]) = 3.  They must be equal
192 				    or have a rank of zero.
193    F[:][5][10] + E[:] * 5 + *Y      1
194 
195    int func (int);
196    func (A[:])			    1
197    func (B[:][:][:][:])             4
198 
199    int func2 (int, int)
200    func2 (A[:], B[:][:][:][:])	    RANKMISMATCH-ERROR -- Since Rank (A[:]) = 1
201 				    and Rank (B[:][:][:][:]) = 4
202 
203    A[:] + func (B[:][:][:][:])	    RANKMISMATCH-ERROR
204    func2 (A[:], B[:]) + func (A)    1
205 
206  */
207 
208 bool
find_rank(location_t loc,tree orig_expr,tree expr,bool ignore_builtin_fn,size_t * rank)209 find_rank (location_t loc, tree orig_expr, tree expr, bool ignore_builtin_fn,
210 	   size_t *rank)
211 {
212   tree ii_tree;
213   size_t ii = 0, current_rank = 0;
214 
215   if (TREE_CODE (expr) == ARRAY_NOTATION_REF)
216     {
217       ii_tree = expr;
218       while (ii_tree)
219 	{
220 	  if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF)
221 	    {
222 	      current_rank++;
223 	      ii_tree = ARRAY_NOTATION_ARRAY (ii_tree);
224 	    }
225 	  else if (handled_component_p (ii_tree)
226 		   || INDIRECT_REF_P (ii_tree))
227 	    ii_tree = TREE_OPERAND (ii_tree, 0);
228 	  else if (TREE_CODE (ii_tree) == PARM_DECL
229 		   || VAR_P (ii_tree))
230 	    break;
231 	  else
232 	    gcc_unreachable ();
233 	}
234       if (*rank == 0)
235 	/* In this case, all the expressions this function has encountered thus
236 	   far have been scalars or expressions with zero rank.  Please see
237 	   header comment for examples of such expression.  */
238 	*rank = current_rank;
239       else if (*rank != current_rank)
240 	{
241 	  /* In this case, find rank is being recursed through a set of
242 	     expression of the form A <OPERATION> B, where A and B both have
243 	     array notations in them and the rank of A is not equal to rank of
244 	     B.
245 	     A simple example of such case is the following: X[:] + Y[:][:] */
246 	  *rank = current_rank;
247 	  return false;
248 	}
249     }
250   else if (TREE_CODE (expr) == STATEMENT_LIST)
251     {
252       tree_stmt_iterator ii_tsi;
253       for (ii_tsi = tsi_start (expr); !tsi_end_p (ii_tsi);
254 	   tsi_next (&ii_tsi))
255 	if (!find_rank (loc, orig_expr, *tsi_stmt_ptr (ii_tsi),
256 			ignore_builtin_fn, rank))
257 	  return false;
258     }
259   else
260     {
261       if (TREE_CODE (expr) == CALL_EXPR)
262 	{
263 	  tree func_name = CALL_EXPR_FN (expr);
264 	  tree prev_arg = NULL_TREE, arg;
265 	  call_expr_arg_iterator iter;
266 	  size_t prev_rank = 0;
267 	  if (TREE_CODE (func_name) == ADDR_EXPR)
268 	    if (!ignore_builtin_fn)
269 	      if (is_cilkplus_reduce_builtin (func_name))
270 		/* If it is a built-in function, then we know it returns a
271 		   scalar.  */
272 		return true;
273 	  if (!find_rank (loc, orig_expr, func_name, ignore_builtin_fn, rank))
274 	    return false;
275 	  FOR_EACH_CALL_EXPR_ARG (arg, iter, expr)
276 	    {
277 	      if (!find_rank (loc, orig_expr, arg, ignore_builtin_fn, rank))
278 		{
279 		  if (prev_arg && EXPR_HAS_LOCATION (prev_arg)
280 		      && prev_rank != *rank)
281 		    error_at (EXPR_LOCATION (prev_arg),
282 			      "rank mismatch between %qE and %qE", prev_arg,
283 			      arg);
284 		  else if (prev_arg && prev_rank != *rank)
285 		    /* Here the original expression is printed as a "heads-up"
286 		       to the programmer.  This is because since there is no
287 		       location information for the offending argument, the
288 		       error could be in some internally generated code that is
289 		       not visible for the programmer.  Thus, the correct fix
290 		       may lie in the original expression.  */
291 		    error_at (loc, "rank mismatch in expression %qE",
292 			      orig_expr);
293 		  return false;
294 		}
295 	      prev_arg = arg;
296 	      prev_rank = *rank;
297 	    }
298 	}
299       else
300 	{
301 	  tree prev_arg = NULL_TREE;
302 	  for (ii = 0; ii < TREE_CODE_LENGTH (TREE_CODE (expr)); ii++)
303 	    {
304 	      if (TREE_OPERAND (expr, ii)
305 		  && !find_rank (loc, orig_expr, TREE_OPERAND (expr, ii),
306 				 ignore_builtin_fn, rank))
307 		{
308 		  if (prev_arg && EXPR_HAS_LOCATION (prev_arg))
309 		    error_at (EXPR_LOCATION (prev_arg),
310 			      "rank mismatch between %qE and %qE", prev_arg,
311 			      TREE_OPERAND (expr, ii));
312 		  return false;
313 		}
314 	      prev_arg = TREE_OPERAND (expr, ii);
315 	    }
316 	}
317     }
318   return true;
319 }
320 
321 /* Extracts all array notations in NODE and stores them in ARRAY_LIST.  If
322    IGNORE_BUILTIN_FN is set, then array notations inside array notation
323    specific built-in functions are ignored.  The NODE can be constants,
324    VAR_DECL, PARM_DECLS, STATEMENT_LISTS or full expressions.   */
325 
326 void
extract_array_notation_exprs(tree node,bool ignore_builtin_fn,vec<tree,va_gc> ** array_list)327 extract_array_notation_exprs (tree node, bool ignore_builtin_fn,
328 			      vec<tree, va_gc> **array_list)
329 {
330   size_t ii = 0;
331 
332   if (!node)
333     return;
334   if (TREE_CODE (node) == ARRAY_NOTATION_REF)
335     {
336       vec_safe_push (*array_list, node);
337       return;
338     }
339   if (TREE_CODE (node) == DECL_EXPR)
340     {
341       tree x = DECL_EXPR_DECL (node);
342       if (DECL_INITIAL (x))
343 	extract_array_notation_exprs (DECL_INITIAL (x),
344 				      ignore_builtin_fn,
345 				      array_list);
346     }
347   else if (TREE_CODE (node) == STATEMENT_LIST)
348     {
349       tree_stmt_iterator ii_tsi;
350       for (ii_tsi = tsi_start (node); !tsi_end_p (ii_tsi); tsi_next (&ii_tsi))
351 	extract_array_notation_exprs (*tsi_stmt_ptr (ii_tsi),
352 				      ignore_builtin_fn, array_list);
353     }
354   else if (TREE_CODE (node) == CALL_EXPR)
355     {
356       tree arg;
357       call_expr_arg_iterator iter;
358       if (is_cilkplus_reduce_builtin (CALL_EXPR_FN (node)))
359 	{
360 	  if (ignore_builtin_fn)
361 	    return;
362 	  else
363 	    {
364 	      vec_safe_push (*array_list, node);
365 	      return;
366 	    }
367 	}
368       if (is_sec_implicit_index_fn (CALL_EXPR_FN (node)))
369 	{
370 	  vec_safe_push (*array_list, node);
371 	  return;
372 	}
373       /* This will extract array notations in function pointers.  */
374       extract_array_notation_exprs (CALL_EXPR_FN (node), ignore_builtin_fn,
375 				    array_list);
376       FOR_EACH_CALL_EXPR_ARG (arg, iter, node)
377 	extract_array_notation_exprs (arg, ignore_builtin_fn, array_list);
378     }
379   else
380     for (ii = 0; ii < TREE_CODE_LENGTH (TREE_CODE (node)); ii++)
381       if (TREE_OPERAND (node, ii))
382 	extract_array_notation_exprs (TREE_OPERAND (node, ii),
383 				      ignore_builtin_fn, array_list);
384   return;
385 }
386 
387 /* LIST contains all the array notations found in *ORIG and ARRAY_OPERAND
388    contains the expanded ARRAY_REF.  E.g., if LIST[<some_index>] contains
389    an array_notation expression, then ARRAY_OPERAND[<some_index>] contains its
390    expansion.  If *ORIG matches LIST[<some_index>] then *ORIG is set to
391    ARRAY_OPERAND[<some_index>].  This function recursively steps through
392    all the sub-trees of *ORIG, if it is larger than a single
393    ARRAY_NOTATION_REF.  */
394 
395 void
replace_array_notations(tree * orig,bool ignore_builtin_fn,vec<tree,va_gc> * list,vec<tree,va_gc> * array_operand)396 replace_array_notations (tree *orig, bool ignore_builtin_fn,
397 			 vec<tree, va_gc> *list,
398 			 vec<tree, va_gc> *array_operand)
399 {
400   size_t ii = 0;
401   extern tree build_c_cast (location_t, tree, tree);
402   tree node = NULL_TREE, node_replacement = NULL_TREE;
403 
404   if (vec_safe_length (list) == 0)
405     return;
406 
407   if (TREE_CODE (*orig) == ARRAY_NOTATION_REF)
408     {
409       for (ii = 0; vec_safe_iterate (list, ii, &node); ii++)
410 	if (*orig == node)
411 	  {
412 	    node_replacement = (*array_operand)[ii];
413 	    *orig = node_replacement;
414 	  }
415     }
416   else if (TREE_CODE (*orig) == STATEMENT_LIST)
417     {
418       tree_stmt_iterator ii_tsi;
419       for (ii_tsi = tsi_start (*orig); !tsi_end_p (ii_tsi); tsi_next (&ii_tsi))
420 	replace_array_notations (tsi_stmt_ptr (ii_tsi), ignore_builtin_fn, list,
421 				 array_operand);
422     }
423   else if (TREE_CODE (*orig) == CALL_EXPR)
424     {
425       tree arg;
426       call_expr_arg_iterator iter;
427       if (is_cilkplus_reduce_builtin (CALL_EXPR_FN (*orig)))
428 	{
429 	  if (!ignore_builtin_fn)
430 	    {
431 	      for (ii = 0; vec_safe_iterate (list, ii, &node); ii++)
432 		if (*orig == node)
433 		  {
434 		    node_replacement = (*array_operand)[ii];
435 		    *orig = node_replacement;
436 		  }
437 	    }
438 	  return;
439 	}
440       if (is_sec_implicit_index_fn (CALL_EXPR_FN (*orig)))
441 	{
442 	  for (ii = 0; vec_safe_iterate (list, ii, &node); ii++)
443 	    if (*orig == node)
444 	      {
445 		node_replacement = (*array_operand)[ii];
446 		*orig = build_c_cast (EXPR_LOCATION (*orig),
447 				      TREE_TYPE (*orig), node_replacement);
448 	      }
449 	  return;
450 	}
451       /* Fixes array notations in array notations in function pointers.  */
452       replace_array_notations (&CALL_EXPR_FN (*orig), ignore_builtin_fn, list,
453 			       array_operand);
454       ii = 0;
455       FOR_EACH_CALL_EXPR_ARG (arg, iter, *orig)
456 	{
457 	  replace_array_notations (&arg, ignore_builtin_fn, list,
458 				   array_operand);
459 	  CALL_EXPR_ARG (*orig, ii) = arg;
460 	  ii++;
461 	}
462     }
463   else
464     {
465       for (ii = 0; ii < (size_t) TREE_CODE_LENGTH (TREE_CODE (*orig)); ii++)
466 	if (TREE_OPERAND (*orig, ii))
467 	  replace_array_notations (&TREE_OPERAND (*orig, ii), ignore_builtin_fn,
468 				   list, array_operand);
469     }
470   return;
471 }
472 
473 /* Callback for walk_tree.  Find all the scalar expressions in *TP and push
474    them in DATA struct, typecasted to (void *).  If *WALK_SUBTREES is set to 0
475    then do not go into the *TP's subtrees.  Since this function steps through
476    all the subtrees, *TP and TP can be NULL_TREE and NULL, respectively.  The
477    function returns NULL_TREE unconditionally.  */
478 
479 tree
find_inv_trees(tree * tp,int * walk_subtrees,void * data)480 find_inv_trees (tree *tp, int *walk_subtrees, void *data)
481 {
482   struct inv_list *i_list = (struct inv_list *) data;
483   unsigned int ii = 0;
484 
485   if (!tp || !*tp)
486     return NULL_TREE;
487   if (TREE_CONSTANT (*tp))
488     return NULL_TREE; /* No need to save constant to a variable.  */
489   if (TREE_CODE (*tp) != COMPOUND_EXPR && !contains_array_notation_expr (*tp))
490     {
491       vec_safe_push (i_list->list_values, *tp);
492       *walk_subtrees = 0;
493     }
494   else if (TREE_CODE (*tp) == ARRAY_NOTATION_REF
495 	   || TREE_CODE (*tp) == ARRAY_REF
496 	   || TREE_CODE (*tp) == CALL_EXPR)
497     /* No need to step through the internals of array notation.  */
498     *walk_subtrees = 0;
499   else
500     {
501       *walk_subtrees = 1;
502 
503       /* This function is used by C and C++ front-ends.  In C++, additional
504 	 tree codes such as TARGET_EXPR must be eliminated.  These codes are
505 	 passed into additional_tcodes and are walked through and checked.  */
506       for (ii = 0; ii < vec_safe_length (i_list->additional_tcodes); ii++)
507 	if (TREE_CODE (*tp) == (*(i_list->additional_tcodes))[ii])
508 	  *walk_subtrees = 0;
509     }
510   return NULL_TREE;
511 }
512 
513 /* Callback for walk_tree.  Replace all the scalar expressions in *TP with the
514    appropriate replacement stored in the struct *DATA (typecasted to void*).
515    The subtrees are not touched if *WALK_SUBTREES is set to zero.  */
516 
517 tree
replace_inv_trees(tree * tp,int * walk_subtrees,void * data)518 replace_inv_trees (tree *tp, int *walk_subtrees, void *data)
519 {
520   size_t ii = 0;
521   tree t, r;
522   struct inv_list *i_list = (struct inv_list *) data;
523 
524   if (vec_safe_length (i_list->list_values))
525     {
526       for (ii = 0; vec_safe_iterate (i_list->list_values, ii, &t); ii++)
527 	if (simple_cst_equal (*tp, t) == 1)
528 	  {
529 	    vec_safe_iterate (i_list->replacement, ii, &r);
530 	    gcc_assert (r != NULL_TREE);
531 	    *tp = r;
532 	    *walk_subtrees = 0;
533 	  }
534     }
535   else
536     *walk_subtrees = 0;
537   return NULL_TREE;
538 }
539 
540 /* Returns true if EXPR or any of its subtrees contain ARRAY_NOTATION_EXPR
541    node.  */
542 
543 bool
contains_array_notation_expr(tree expr)544 contains_array_notation_expr (tree expr)
545 {
546   vec<tree, va_gc> *array_list = NULL;
547 
548   if (!expr)
549     return false;
550   if (TREE_CODE (expr) == FUNCTION_DECL)
551     if (is_cilkplus_reduce_builtin (expr))
552       return true;
553 
554   extract_array_notation_exprs (expr, false, &array_list);
555   if (vec_safe_length (array_list) == 0)
556     return false;
557   else
558     return true;
559 }
560 
561 /* This function will check if OP is a CALL_EXPR that is a built-in array
562    notation function.  If so, then we will return its type to be the type of
563    the array notation inside.  */
564 
565 tree
find_correct_array_notation_type(tree op)566 find_correct_array_notation_type (tree op)
567 {
568   tree fn_arg, return_type = NULL_TREE;
569 
570   if (op)
571     {
572       return_type = TREE_TYPE (op); /* This is the default case.  */
573       if (TREE_CODE (op) == CALL_EXPR)
574 	if (is_cilkplus_reduce_builtin (CALL_EXPR_FN (op)))
575 	  {
576 	    fn_arg = CALL_EXPR_ARG (op, 0);
577 	    if (fn_arg)
578 	      return_type = TREE_TYPE (fn_arg);
579 	  }
580     }
581   return return_type;
582 }
583 
584 /* Extracts all the array notation triplet information from LIST and stores
585    them in the following fields of the 2-D array NODE(size x rank):
586    START, LENGTH and STRIDE, holding the starting index, length, and stride,
587    respectively.  In addition, it also sets two bool fields, IS_VECTOR and
588    COUNT_DOWN, in NODE indicating whether a certain value at a certain field
589    is a vector and if the array is accessed from high to low.  */
590 
591 void
cilkplus_extract_an_triplets(vec<tree,va_gc> * list,size_t size,size_t rank,vec<vec<struct cilkplus_an_parts>> * node)592 cilkplus_extract_an_triplets (vec<tree, va_gc> *list, size_t size, size_t rank,
593 			      vec<vec<struct cilkplus_an_parts> > *node)
594 {
595   vec<vec<tree> > array_exprs = vNULL;
596 
597   node->safe_grow_cleared (size);
598   array_exprs.safe_grow_cleared (size);
599 
600   if (rank > 0)
601     for (size_t ii = 0; ii < size; ii++)
602       {
603 	(*node)[ii].safe_grow_cleared (rank);
604 	array_exprs[ii].safe_grow_cleared (rank);
605       }
606   for (size_t ii = 0; ii < size; ii++)
607     {
608       size_t jj = 0;
609       tree ii_tree = (*list)[ii];
610       while (ii_tree)
611 	{
612 	  if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF)
613 	    {
614 	      array_exprs[ii][jj] = ii_tree;
615 	      jj++;
616 	      ii_tree = ARRAY_NOTATION_ARRAY (ii_tree);
617 	    }
618 	  else if (TREE_CODE (ii_tree) == ARRAY_REF)
619 	    ii_tree = TREE_OPERAND (ii_tree, 0);
620 	  else
621 	    break;
622 	}
623     }
624     for (size_t ii = 0; ii < size; ii++)
625       if (TREE_CODE ((*list)[ii]) == ARRAY_NOTATION_REF)
626 	for (size_t jj = 0; jj < rank; jj++)
627 	  {
628 	    tree ii_tree = array_exprs[ii][jj];
629 	    (*node)[ii][jj].is_vector = true;
630 	    (*node)[ii][jj].value = ARRAY_NOTATION_ARRAY (ii_tree);
631 	    (*node)[ii][jj].start = ARRAY_NOTATION_START (ii_tree);
632 	    (*node)[ii][jj].length =
633 	      fold_build1 (CONVERT_EXPR, integer_type_node,
634 			   ARRAY_NOTATION_LENGTH (ii_tree));
635 	    (*node)[ii][jj].stride =
636 	      fold_build1 (CONVERT_EXPR, integer_type_node,
637 			   ARRAY_NOTATION_STRIDE (ii_tree));
638 	  }
639 
640   release_vec_vec (array_exprs);
641 }
642 
643 /* Replaces all the __sec_implicit_arg functions in LIST with the induction
644    variable stored in VAR at the appropriate location pointed by the
645    __sec_implicit_arg's first parameter.  Emits an error if the parameter is
646    not between 0 and RANK.  */
647 
648 vec <tree, va_gc> *
fix_sec_implicit_args(location_t loc,vec<tree,va_gc> * list,vec<an_loop_parts> an_loop_info,size_t rank,tree orig_stmt)649 fix_sec_implicit_args (location_t loc, vec <tree, va_gc> *list,
650 		       vec<an_loop_parts> an_loop_info, size_t rank,
651 		       tree orig_stmt)
652 {
653   vec <tree, va_gc> *array_operand = NULL;
654   for (size_t ii = 0; ii < vec_safe_length (list); ii++)
655     if (TREE_CODE ((*list)[ii]) == CALL_EXPR
656 	&& is_sec_implicit_index_fn (CALL_EXPR_FN ((*list)[ii])))
657       {
658 	int idx = extract_sec_implicit_index_arg (loc, (*list)[ii]);
659 	if (idx < 0)
660 	  /* In this case, the returning function would have emitted an
661 	     error thus it is not necessary to do so again.  */
662 	  return NULL;
663 	else if (idx < (int) rank)
664 	  vec_safe_push (array_operand, an_loop_info[idx].var);
665 	else
666 	  {
667 	    error_at (loc, "__sec_implicit_index argument %d must be "
668 		      "less than the rank of %qE", idx, orig_stmt);
669 	    return NULL;
670 	  }
671       }
672     else
673       /* Save the existing value into the array operand.  */
674       vec_safe_push (array_operand, (*list)[ii]);
675   return array_operand;
676 }
677 
678 /* Returns true if NAME is an IDENTIFIER_NODE with identifier "vector",
679    "__vector", or "__vector__".  */
680 
681 bool
is_cilkplus_vector_p(tree name)682 is_cilkplus_vector_p (tree name)
683 {
684   return flag_cilkplus && is_attribute_p ("vector", name);
685 }
686