1 /* General types and functions that are uselful for processing of OpenMP,
2    OpenACC and similar directivers at various stages of compilation.
3 
4    Copyright (C) 2005-2018 Free Software Foundation, Inc.
5 
6 This file is part of GCC.
7 
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12 
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3.  If not see
20 <http://www.gnu.org/licenses/>.  */
21 
22 /* Find an OMP clause of type KIND within CLAUSES.  */
23 
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "backend.h"
28 #include "target.h"
29 #include "tree.h"
30 #include "gimple.h"
31 #include "ssa.h"
32 #include "diagnostic-core.h"
33 #include "fold-const.h"
34 #include "langhooks.h"
35 #include "omp-general.h"
36 #include "stringpool.h"
37 #include "attribs.h"
38 
39 tree
omp_find_clause(tree clauses,enum omp_clause_code kind)40 omp_find_clause (tree clauses, enum omp_clause_code kind)
41 {
42   for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
43     if (OMP_CLAUSE_CODE (clauses) == kind)
44       return clauses;
45 
46   return NULL_TREE;
47 }
48 
49 /* Return true if DECL is a reference type.  */
50 
51 bool
omp_is_reference(tree decl)52 omp_is_reference (tree decl)
53 {
54   return lang_hooks.decls.omp_privatize_by_reference (decl);
55 }
56 
57 /* Adjust *COND_CODE and *N2 so that the former is either LT_EXPR or
58    GT_EXPR.  */
59 
60 void
omp_adjust_for_condition(location_t loc,enum tree_code * cond_code,tree * n2)61 omp_adjust_for_condition (location_t loc, enum tree_code *cond_code, tree *n2)
62 {
63   switch (*cond_code)
64     {
65     case LT_EXPR:
66     case GT_EXPR:
67     case NE_EXPR:
68       break;
69     case LE_EXPR:
70       if (POINTER_TYPE_P (TREE_TYPE (*n2)))
71 	*n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, 1);
72       else
73 	*n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (*n2), *n2,
74 			       build_int_cst (TREE_TYPE (*n2), 1));
75       *cond_code = LT_EXPR;
76       break;
77     case GE_EXPR:
78       if (POINTER_TYPE_P (TREE_TYPE (*n2)))
79 	*n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, -1);
80       else
81 	*n2 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (*n2), *n2,
82 			       build_int_cst (TREE_TYPE (*n2), 1));
83       *cond_code = GT_EXPR;
84       break;
85     default:
86       gcc_unreachable ();
87     }
88 }
89 
90 /* Return the looping step from INCR, extracted from the step of a gimple omp
91    for statement.  */
92 
93 tree
omp_get_for_step_from_incr(location_t loc,tree incr)94 omp_get_for_step_from_incr (location_t loc, tree incr)
95 {
96   tree step;
97   switch (TREE_CODE (incr))
98     {
99     case PLUS_EXPR:
100       step = TREE_OPERAND (incr, 1);
101       break;
102     case POINTER_PLUS_EXPR:
103       step = fold_convert (ssizetype, TREE_OPERAND (incr, 1));
104       break;
105     case MINUS_EXPR:
106       step = TREE_OPERAND (incr, 1);
107       step = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (step), step);
108       break;
109     default:
110       gcc_unreachable ();
111     }
112   return step;
113 }
114 
115 /* Extract the header elements of parallel loop FOR_STMT and store
116    them into *FD.  */
117 
118 void
omp_extract_for_data(gomp_for * for_stmt,struct omp_for_data * fd,struct omp_for_data_loop * loops)119 omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
120 		      struct omp_for_data_loop *loops)
121 {
122   tree t, var, *collapse_iter, *collapse_count;
123   tree count = NULL_TREE, iter_type = long_integer_type_node;
124   struct omp_for_data_loop *loop;
125   int i;
126   struct omp_for_data_loop dummy_loop;
127   location_t loc = gimple_location (for_stmt);
128   bool simd = gimple_omp_for_kind (for_stmt) & GF_OMP_FOR_SIMD;
129   bool distribute = gimple_omp_for_kind (for_stmt)
130 		    == GF_OMP_FOR_KIND_DISTRIBUTE;
131   bool taskloop = gimple_omp_for_kind (for_stmt)
132 		  == GF_OMP_FOR_KIND_TASKLOOP;
133   tree iterv, countv;
134 
135   fd->for_stmt = for_stmt;
136   fd->pre = NULL;
137   fd->have_nowait = distribute || simd;
138   fd->have_ordered = false;
139   fd->tiling = NULL_TREE;
140   fd->collapse = 1;
141   fd->ordered = 0;
142   fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
143   fd->sched_modifiers = 0;
144   fd->chunk_size = NULL_TREE;
145   fd->simd_schedule = false;
146   collapse_iter = NULL;
147   collapse_count = NULL;
148 
149   for (t = gimple_omp_for_clauses (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t))
150     switch (OMP_CLAUSE_CODE (t))
151       {
152       case OMP_CLAUSE_NOWAIT:
153 	fd->have_nowait = true;
154 	break;
155       case OMP_CLAUSE_ORDERED:
156 	fd->have_ordered = true;
157 	if (OMP_CLAUSE_ORDERED_EXPR (t))
158 	  fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t));
159 	break;
160       case OMP_CLAUSE_SCHEDULE:
161 	gcc_assert (!distribute && !taskloop);
162 	fd->sched_kind
163 	  = (enum omp_clause_schedule_kind)
164 	    (OMP_CLAUSE_SCHEDULE_KIND (t) & OMP_CLAUSE_SCHEDULE_MASK);
165 	fd->sched_modifiers = (OMP_CLAUSE_SCHEDULE_KIND (t)
166 			       & ~OMP_CLAUSE_SCHEDULE_MASK);
167 	fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
168 	fd->simd_schedule = OMP_CLAUSE_SCHEDULE_SIMD (t);
169 	break;
170       case OMP_CLAUSE_DIST_SCHEDULE:
171 	gcc_assert (distribute);
172 	fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t);
173 	break;
174       case OMP_CLAUSE_COLLAPSE:
175 	fd->collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t));
176 	if (fd->collapse > 1)
177 	  {
178 	    collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t);
179 	    collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t);
180 	  }
181 	break;
182       case OMP_CLAUSE_TILE:
183 	fd->tiling = OMP_CLAUSE_TILE_LIST (t);
184 	fd->collapse = list_length (fd->tiling);
185 	gcc_assert (fd->collapse);
186 	collapse_iter = &OMP_CLAUSE_TILE_ITERVAR (t);
187 	collapse_count = &OMP_CLAUSE_TILE_COUNT (t);
188 	break;
189       default:
190 	break;
191       }
192 
193   if (fd->collapse > 1 || fd->tiling)
194     fd->loops = loops;
195   else
196     fd->loops = &fd->loop;
197 
198   if (fd->ordered && fd->collapse == 1 && loops != NULL)
199     {
200       fd->loops = loops;
201       iterv = NULL_TREE;
202       countv = NULL_TREE;
203       collapse_iter = &iterv;
204       collapse_count = &countv;
205     }
206 
207   /* FIXME: for now map schedule(auto) to schedule(static).
208      There should be analysis to determine whether all iterations
209      are approximately the same amount of work (then schedule(static)
210      is best) or if it varies (then schedule(dynamic,N) is better).  */
211   if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO)
212     {
213       fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
214       gcc_assert (fd->chunk_size == NULL);
215     }
216   gcc_assert ((fd->collapse == 1 && !fd->tiling) || collapse_iter != NULL);
217   if (taskloop)
218     fd->sched_kind = OMP_CLAUSE_SCHEDULE_RUNTIME;
219   if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
220     gcc_assert (fd->chunk_size == NULL);
221   else if (fd->chunk_size == NULL)
222     {
223       /* We only need to compute a default chunk size for ordered
224 	 static loops and dynamic loops.  */
225       if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
226 	  || fd->have_ordered)
227 	fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
228 			 ? integer_zero_node : integer_one_node;
229     }
230 
231   int cnt = fd->ordered ? fd->ordered : fd->collapse;
232   for (i = 0; i < cnt; i++)
233     {
234       if (i == 0
235 	  && fd->collapse == 1
236 	  && !fd->tiling
237 	  && (fd->ordered == 0 || loops == NULL))
238 	loop = &fd->loop;
239       else if (loops != NULL)
240 	loop = loops + i;
241       else
242 	loop = &dummy_loop;
243 
244       loop->v = gimple_omp_for_index (for_stmt, i);
245       gcc_assert (SSA_VAR_P (loop->v));
246       gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
247 		  || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
248       var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
249       loop->n1 = gimple_omp_for_initial (for_stmt, i);
250 
251       loop->cond_code = gimple_omp_for_cond (for_stmt, i);
252       loop->n2 = gimple_omp_for_final (for_stmt, i);
253       gcc_assert (loop->cond_code != NE_EXPR);
254       omp_adjust_for_condition (loc, &loop->cond_code, &loop->n2);
255 
256       t = gimple_omp_for_incr (for_stmt, i);
257       gcc_assert (TREE_OPERAND (t, 0) == var);
258       loop->step = omp_get_for_step_from_incr (loc, t);
259 
260       if (simd
261 	  || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
262 	      && !fd->have_ordered))
263 	{
264 	  if (fd->collapse == 1 && !fd->tiling)
265 	    iter_type = TREE_TYPE (loop->v);
266 	  else if (i == 0
267 		   || TYPE_PRECISION (iter_type)
268 		      < TYPE_PRECISION (TREE_TYPE (loop->v)))
269 	    iter_type
270 	      = build_nonstandard_integer_type
271 		  (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
272 	}
273       else if (iter_type != long_long_unsigned_type_node)
274 	{
275 	  if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
276 	    iter_type = long_long_unsigned_type_node;
277 	  else if (TYPE_UNSIGNED (TREE_TYPE (loop->v))
278 		   && TYPE_PRECISION (TREE_TYPE (loop->v))
279 		      >= TYPE_PRECISION (iter_type))
280 	    {
281 	      tree n;
282 
283 	      if (loop->cond_code == LT_EXPR)
284 		n = fold_build2_loc (loc,
285 				 PLUS_EXPR, TREE_TYPE (loop->v),
286 				 loop->n2, loop->step);
287 	      else
288 		n = loop->n1;
289 	      if (TREE_CODE (n) != INTEGER_CST
290 		  || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n))
291 		iter_type = long_long_unsigned_type_node;
292 	    }
293 	  else if (TYPE_PRECISION (TREE_TYPE (loop->v))
294 		   > TYPE_PRECISION (iter_type))
295 	    {
296 	      tree n1, n2;
297 
298 	      if (loop->cond_code == LT_EXPR)
299 		{
300 		  n1 = loop->n1;
301 		  n2 = fold_build2_loc (loc,
302 				    PLUS_EXPR, TREE_TYPE (loop->v),
303 				    loop->n2, loop->step);
304 		}
305 	      else
306 		{
307 		  n1 = fold_build2_loc (loc,
308 				    MINUS_EXPR, TREE_TYPE (loop->v),
309 				    loop->n2, loop->step);
310 		  n2 = loop->n1;
311 		}
312 	      if (TREE_CODE (n1) != INTEGER_CST
313 		  || TREE_CODE (n2) != INTEGER_CST
314 		  || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1)
315 		  || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type)))
316 		iter_type = long_long_unsigned_type_node;
317 	    }
318 	}
319 
320       if (i >= fd->collapse)
321 	continue;
322 
323       if (collapse_count && *collapse_count == NULL)
324 	{
325 	  t = fold_binary (loop->cond_code, boolean_type_node,
326 			   fold_convert (TREE_TYPE (loop->v), loop->n1),
327 			   fold_convert (TREE_TYPE (loop->v), loop->n2));
328 	  if (t && integer_zerop (t))
329 	    count = build_zero_cst (long_long_unsigned_type_node);
330 	  else if ((i == 0 || count != NULL_TREE)
331 		   && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
332 		   && TREE_CONSTANT (loop->n1)
333 		   && TREE_CONSTANT (loop->n2)
334 		   && TREE_CODE (loop->step) == INTEGER_CST)
335 	    {
336 	      tree itype = TREE_TYPE (loop->v);
337 
338 	      if (POINTER_TYPE_P (itype))
339 		itype = signed_type_for (itype);
340 	      t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1));
341 	      t = fold_build2_loc (loc,
342 			       PLUS_EXPR, itype,
343 			       fold_convert_loc (loc, itype, loop->step), t);
344 	      t = fold_build2_loc (loc, PLUS_EXPR, itype, t,
345 			       fold_convert_loc (loc, itype, loop->n2));
346 	      t = fold_build2_loc (loc, MINUS_EXPR, itype, t,
347 			       fold_convert_loc (loc, itype, loop->n1));
348 	      if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
349 		t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype,
350 				 fold_build1_loc (loc, NEGATE_EXPR, itype, t),
351 				 fold_build1_loc (loc, NEGATE_EXPR, itype,
352 					      fold_convert_loc (loc, itype,
353 								loop->step)));
354 	      else
355 		t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, t,
356 				 fold_convert_loc (loc, itype, loop->step));
357 	      t = fold_convert_loc (loc, long_long_unsigned_type_node, t);
358 	      if (count != NULL_TREE)
359 		count = fold_build2_loc (loc,
360 				     MULT_EXPR, long_long_unsigned_type_node,
361 				     count, t);
362 	      else
363 		count = t;
364 	      if (TREE_CODE (count) != INTEGER_CST)
365 		count = NULL_TREE;
366 	    }
367 	  else if (count && !integer_zerop (count))
368 	    count = NULL_TREE;
369 	}
370     }
371 
372   if (count
373       && !simd
374       && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
375 	  || fd->have_ordered))
376     {
377       if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
378 	iter_type = long_long_unsigned_type_node;
379       else
380 	iter_type = long_integer_type_node;
381     }
382   else if (collapse_iter && *collapse_iter != NULL)
383     iter_type = TREE_TYPE (*collapse_iter);
384   fd->iter_type = iter_type;
385   if (collapse_iter && *collapse_iter == NULL)
386     *collapse_iter = create_tmp_var (iter_type, ".iter");
387   if (collapse_count && *collapse_count == NULL)
388     {
389       if (count)
390 	*collapse_count = fold_convert_loc (loc, iter_type, count);
391       else
392 	*collapse_count = create_tmp_var (iter_type, ".count");
393     }
394 
395   if (fd->collapse > 1 || fd->tiling || (fd->ordered && loops))
396     {
397       fd->loop.v = *collapse_iter;
398       fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
399       fd->loop.n2 = *collapse_count;
400       fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
401       fd->loop.cond_code = LT_EXPR;
402     }
403   else if (loops)
404     loops[0] = fd->loop;
405 }
406 
407 /* Build a call to GOMP_barrier.  */
408 
409 gimple *
omp_build_barrier(tree lhs)410 omp_build_barrier (tree lhs)
411 {
412   tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL
413 					   : BUILT_IN_GOMP_BARRIER);
414   gcall *g = gimple_build_call (fndecl, 0);
415   if (lhs)
416     gimple_call_set_lhs (g, lhs);
417   return g;
418 }
419 
420 /* Return maximum possible vectorization factor for the target.  */
421 
422 poly_uint64
omp_max_vf(void)423 omp_max_vf (void)
424 {
425   if (!optimize
426       || optimize_debug
427       || !flag_tree_loop_optimize
428       || (!flag_tree_loop_vectorize
429 	  && global_options_set.x_flag_tree_loop_vectorize))
430     return 1;
431 
432   auto_vector_sizes sizes;
433   targetm.vectorize.autovectorize_vector_sizes (&sizes);
434   if (!sizes.is_empty ())
435     {
436       poly_uint64 vf = 0;
437       for (unsigned int i = 0; i < sizes.length (); ++i)
438 	vf = ordered_max (vf, sizes[i]);
439       return vf;
440     }
441 
442   machine_mode vqimode = targetm.vectorize.preferred_simd_mode (QImode);
443   if (GET_MODE_CLASS (vqimode) == MODE_VECTOR_INT)
444     return GET_MODE_NUNITS (vqimode);
445 
446   return 1;
447 }
448 
449 /* Return maximum SIMT width if offloading may target SIMT hardware.  */
450 
451 int
omp_max_simt_vf(void)452 omp_max_simt_vf (void)
453 {
454   if (!optimize)
455     return 0;
456   if (ENABLE_OFFLOADING)
457     for (const char *c = getenv ("OFFLOAD_TARGET_NAMES"); c;)
458       {
459 	if (!strncmp (c, "nvptx", strlen ("nvptx")))
460 	  return 32;
461 	else if ((c = strchr (c, ',')))
462 	  c++;
463       }
464   return 0;
465 }
466 
467 /* Encode an oacc launch argument.  This matches the GOMP_LAUNCH_PACK
468    macro on gomp-constants.h.  We do not check for overflow.  */
469 
470 tree
oacc_launch_pack(unsigned code,tree device,unsigned op)471 oacc_launch_pack (unsigned code, tree device, unsigned op)
472 {
473   tree res;
474 
475   res = build_int_cst (unsigned_type_node, GOMP_LAUNCH_PACK (code, 0, op));
476   if (device)
477     {
478       device = fold_build2 (LSHIFT_EXPR, unsigned_type_node,
479 			    device, build_int_cst (unsigned_type_node,
480 						   GOMP_LAUNCH_DEVICE_SHIFT));
481       res = fold_build2 (BIT_IOR_EXPR, unsigned_type_node, res, device);
482     }
483   return res;
484 }
485 
486 /* FIXME: What is the following comment for? */
487 /* Look for compute grid dimension clauses and convert to an attribute
488    attached to FN.  This permits the target-side code to (a) massage
489    the dimensions, (b) emit that data and (c) optimize.  Non-constant
490    dimensions are pushed onto ARGS.
491 
492    The attribute value is a TREE_LIST.  A set of dimensions is
493    represented as a list of INTEGER_CST.  Those that are runtime
494    exprs are represented as an INTEGER_CST of zero.
495 
496    TODO: Normally the attribute will just contain a single such list.  If
497    however it contains a list of lists, this will represent the use of
498    device_type.  Each member of the outer list is an assoc list of
499    dimensions, keyed by the device type.  The first entry will be the
500    default.  Well, that's the plan.  */
501 
502 /* Replace any existing oacc fn attribute with updated dimensions.  */
503 
504 void
oacc_replace_fn_attrib(tree fn,tree dims)505 oacc_replace_fn_attrib (tree fn, tree dims)
506 {
507   tree ident = get_identifier (OACC_FN_ATTRIB);
508   tree attribs = DECL_ATTRIBUTES (fn);
509 
510   /* If we happen to be present as the first attrib, drop it.  */
511   if (attribs && TREE_PURPOSE (attribs) == ident)
512     attribs = TREE_CHAIN (attribs);
513   DECL_ATTRIBUTES (fn) = tree_cons (ident, dims, attribs);
514 }
515 
516 /* Scan CLAUSES for launch dimensions and attach them to the oacc
517    function attribute.  Push any that are non-constant onto the ARGS
518    list, along with an appropriate GOMP_LAUNCH_DIM tag.  */
519 
520 void
oacc_set_fn_attrib(tree fn,tree clauses,vec<tree> * args)521 oacc_set_fn_attrib (tree fn, tree clauses, vec<tree> *args)
522 {
523   /* Must match GOMP_DIM ordering.  */
524   static const omp_clause_code ids[]
525     = { OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS,
526 	OMP_CLAUSE_VECTOR_LENGTH };
527   unsigned ix;
528   tree dims[GOMP_DIM_MAX];
529 
530   tree attr = NULL_TREE;
531   unsigned non_const = 0;
532 
533   for (ix = GOMP_DIM_MAX; ix--;)
534     {
535       tree clause = omp_find_clause (clauses, ids[ix]);
536       tree dim = NULL_TREE;
537 
538       if (clause)
539 	dim = OMP_CLAUSE_EXPR (clause, ids[ix]);
540       dims[ix] = dim;
541       if (dim && TREE_CODE (dim) != INTEGER_CST)
542 	{
543 	  dim = integer_zero_node;
544 	  non_const |= GOMP_DIM_MASK (ix);
545 	}
546       attr = tree_cons (NULL_TREE, dim, attr);
547     }
548 
549   oacc_replace_fn_attrib (fn, attr);
550 
551   if (non_const)
552     {
553       /* Push a dynamic argument set.  */
554       args->safe_push (oacc_launch_pack (GOMP_LAUNCH_DIM,
555 					 NULL_TREE, non_const));
556       for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++)
557 	if (non_const & GOMP_DIM_MASK (ix))
558 	  args->safe_push (dims[ix]);
559     }
560 }
561 
562 /*  Process the routine's dimension clauess to generate an attribute
563     value.  Issue diagnostics as appropriate.  We default to SEQ
564     (OpenACC 2.5 clarifies this). All dimensions have a size of zero
565     (dynamic).  TREE_PURPOSE is set to indicate whether that dimension
566     can have a loop partitioned on it.  non-zero indicates
567     yes, zero indicates no.  By construction once a non-zero has been
568     reached, further inner dimensions must also be non-zero.  We set
569     TREE_VALUE to zero for the dimensions that may be partitioned and
570     1 for the other ones -- if a loop is (erroneously) spawned at
571     an outer level, we don't want to try and partition it.  */
572 
573 tree
oacc_build_routine_dims(tree clauses)574 oacc_build_routine_dims (tree clauses)
575 {
576   /* Must match GOMP_DIM ordering.  */
577   static const omp_clause_code ids[]
578     = {OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ};
579   int ix;
580   int level = -1;
581 
582   for (; clauses; clauses = OMP_CLAUSE_CHAIN (clauses))
583     for (ix = GOMP_DIM_MAX + 1; ix--;)
584       if (OMP_CLAUSE_CODE (clauses) == ids[ix])
585 	{
586 	  if (level >= 0)
587 	    error_at (OMP_CLAUSE_LOCATION (clauses),
588 		      "multiple loop axes specified for routine");
589 	  level = ix;
590 	  break;
591 	}
592 
593   /* Default to SEQ.  */
594   if (level < 0)
595     level = GOMP_DIM_MAX;
596 
597   tree dims = NULL_TREE;
598 
599   for (ix = GOMP_DIM_MAX; ix--;)
600     dims = tree_cons (build_int_cst (boolean_type_node, ix >= level),
601 		      build_int_cst (integer_type_node, ix < level), dims);
602 
603   return dims;
604 }
605 
606 /* Retrieve the oacc function attrib and return it.  Non-oacc
607    functions will return NULL.  */
608 
609 tree
oacc_get_fn_attrib(tree fn)610 oacc_get_fn_attrib (tree fn)
611 {
612   return lookup_attribute (OACC_FN_ATTRIB, DECL_ATTRIBUTES (fn));
613 }
614 
615 /* Return true if FN is an OpenMP or OpenACC offloading function.  */
616 
617 bool
offloading_function_p(tree fn)618 offloading_function_p (tree fn)
619 {
620   tree attrs = DECL_ATTRIBUTES (fn);
621   return (lookup_attribute ("omp declare target", attrs)
622 	  || lookup_attribute ("omp target entrypoint", attrs));
623 }
624 
625 /* Extract an oacc execution dimension from FN.  FN must be an
626    offloaded function or routine that has already had its execution
627    dimensions lowered to the target-specific values.  */
628 
629 int
oacc_get_fn_dim_size(tree fn,int axis)630 oacc_get_fn_dim_size (tree fn, int axis)
631 {
632   tree attrs = oacc_get_fn_attrib (fn);
633 
634   gcc_assert (axis < GOMP_DIM_MAX);
635 
636   tree dims = TREE_VALUE (attrs);
637   while (axis--)
638     dims = TREE_CHAIN (dims);
639 
640   int size = TREE_INT_CST_LOW (TREE_VALUE (dims));
641 
642   return size;
643 }
644 
645 /* Extract the dimension axis from an IFN_GOACC_DIM_POS or
646    IFN_GOACC_DIM_SIZE call.  */
647 
648 int
oacc_get_ifn_dim_arg(const gimple * stmt)649 oacc_get_ifn_dim_arg (const gimple *stmt)
650 {
651   gcc_checking_assert (gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_SIZE
652 		       || gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_POS);
653   tree arg = gimple_call_arg (stmt, 0);
654   HOST_WIDE_INT axis = TREE_INT_CST_LOW (arg);
655 
656   gcc_checking_assert (axis >= 0 && axis < GOMP_DIM_MAX);
657   return (int) axis;
658 }
659