xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/omp-general.c (revision d90047b5d07facf36e6c01dcc0bded8997ce9cc2)
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-2017 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 
37 
38 tree
39 omp_find_clause (tree clauses, enum omp_clause_code kind)
40 {
41   for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
42     if (OMP_CLAUSE_CODE (clauses) == kind)
43       return clauses;
44 
45   return NULL_TREE;
46 }
47 
48 /* Return true if DECL is a reference type.  */
49 
50 bool
51 omp_is_reference (tree decl)
52 {
53   return lang_hooks.decls.omp_privatize_by_reference (decl);
54 }
55 
56 /* Adjust *COND_CODE and *N2 so that the former is either LT_EXPR or
57    GT_EXPR.  */
58 
59 void
60 omp_adjust_for_condition (location_t loc, enum tree_code *cond_code, tree *n2)
61 {
62   switch (*cond_code)
63     {
64     case LT_EXPR:
65     case GT_EXPR:
66     case NE_EXPR:
67       break;
68     case LE_EXPR:
69       if (POINTER_TYPE_P (TREE_TYPE (*n2)))
70 	*n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, 1);
71       else
72 	*n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (*n2), *n2,
73 			       build_int_cst (TREE_TYPE (*n2), 1));
74       *cond_code = LT_EXPR;
75       break;
76     case GE_EXPR:
77       if (POINTER_TYPE_P (TREE_TYPE (*n2)))
78 	*n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, -1);
79       else
80 	*n2 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (*n2), *n2,
81 			       build_int_cst (TREE_TYPE (*n2), 1));
82       *cond_code = GT_EXPR;
83       break;
84     default:
85       gcc_unreachable ();
86     }
87 }
88 
89 /* Return the looping step from INCR, extracted from the step of a gimple omp
90    for statement.  */
91 
92 tree
93 omp_get_for_step_from_incr (location_t loc, tree incr)
94 {
95   tree step;
96   switch (TREE_CODE (incr))
97     {
98     case PLUS_EXPR:
99       step = TREE_OPERAND (incr, 1);
100       break;
101     case POINTER_PLUS_EXPR:
102       step = fold_convert (ssizetype, TREE_OPERAND (incr, 1));
103       break;
104     case MINUS_EXPR:
105       step = TREE_OPERAND (incr, 1);
106       step = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (step), step);
107       break;
108     default:
109       gcc_unreachable ();
110     }
111   return step;
112 }
113 
114 /* Extract the header elements of parallel loop FOR_STMT and store
115    them into *FD.  */
116 
117 void
118 omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
119 		      struct omp_for_data_loop *loops)
120 {
121   tree t, var, *collapse_iter, *collapse_count;
122   tree count = NULL_TREE, iter_type = long_integer_type_node;
123   struct omp_for_data_loop *loop;
124   int i;
125   struct omp_for_data_loop dummy_loop;
126   location_t loc = gimple_location (for_stmt);
127   bool simd = gimple_omp_for_kind (for_stmt) & GF_OMP_FOR_SIMD;
128   bool distribute = gimple_omp_for_kind (for_stmt)
129 		    == GF_OMP_FOR_KIND_DISTRIBUTE;
130   bool taskloop = gimple_omp_for_kind (for_stmt)
131 		  == GF_OMP_FOR_KIND_TASKLOOP;
132   tree iterv, countv;
133 
134   fd->for_stmt = for_stmt;
135   fd->pre = NULL;
136   fd->have_nowait = distribute || simd;
137   fd->have_ordered = false;
138   fd->tiling = NULL_TREE;
139   fd->collapse = 1;
140   fd->ordered = 0;
141   fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
142   fd->sched_modifiers = 0;
143   fd->chunk_size = NULL_TREE;
144   fd->simd_schedule = false;
145   if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_CILKFOR)
146     fd->sched_kind = OMP_CLAUSE_SCHEDULE_CILKFOR;
147   collapse_iter = NULL;
148   collapse_count = NULL;
149 
150   for (t = gimple_omp_for_clauses (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t))
151     switch (OMP_CLAUSE_CODE (t))
152       {
153       case OMP_CLAUSE_NOWAIT:
154 	fd->have_nowait = true;
155 	break;
156       case OMP_CLAUSE_ORDERED:
157 	fd->have_ordered = true;
158 	if (OMP_CLAUSE_ORDERED_EXPR (t))
159 	  fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t));
160 	break;
161       case OMP_CLAUSE_SCHEDULE:
162 	gcc_assert (!distribute && !taskloop);
163 	fd->sched_kind
164 	  = (enum omp_clause_schedule_kind)
165 	    (OMP_CLAUSE_SCHEDULE_KIND (t) & OMP_CLAUSE_SCHEDULE_MASK);
166 	fd->sched_modifiers = (OMP_CLAUSE_SCHEDULE_KIND (t)
167 			       & ~OMP_CLAUSE_SCHEDULE_MASK);
168 	fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
169 	fd->simd_schedule = OMP_CLAUSE_SCHEDULE_SIMD (t);
170 	break;
171       case OMP_CLAUSE_DIST_SCHEDULE:
172 	gcc_assert (distribute);
173 	fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t);
174 	break;
175       case OMP_CLAUSE_COLLAPSE:
176 	fd->collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t));
177 	if (fd->collapse > 1)
178 	  {
179 	    collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t);
180 	    collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t);
181 	  }
182 	break;
183       case OMP_CLAUSE_TILE:
184 	fd->tiling = OMP_CLAUSE_TILE_LIST (t);
185 	fd->collapse = list_length (fd->tiling);
186 	gcc_assert (fd->collapse);
187 	collapse_iter = &OMP_CLAUSE_TILE_ITERVAR (t);
188 	collapse_count = &OMP_CLAUSE_TILE_COUNT (t);
189 	break;
190       default:
191 	break;
192       }
193 
194   if (fd->collapse > 1 || fd->tiling)
195     fd->loops = loops;
196   else
197     fd->loops = &fd->loop;
198 
199   if (fd->ordered && fd->collapse == 1 && loops != NULL)
200     {
201       fd->loops = loops;
202       iterv = NULL_TREE;
203       countv = NULL_TREE;
204       collapse_iter = &iterv;
205       collapse_count = &countv;
206     }
207 
208   /* FIXME: for now map schedule(auto) to schedule(static).
209      There should be analysis to determine whether all iterations
210      are approximately the same amount of work (then schedule(static)
211      is best) or if it varies (then schedule(dynamic,N) is better).  */
212   if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO)
213     {
214       fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
215       gcc_assert (fd->chunk_size == NULL);
216     }
217   gcc_assert ((fd->collapse == 1 && !fd->tiling) || collapse_iter != NULL);
218   if (taskloop)
219     fd->sched_kind = OMP_CLAUSE_SCHEDULE_RUNTIME;
220   if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
221     gcc_assert (fd->chunk_size == NULL);
222   else if (fd->chunk_size == NULL)
223     {
224       /* We only need to compute a default chunk size for ordered
225 	 static loops and dynamic loops.  */
226       if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
227 	  || fd->have_ordered)
228 	fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
229 			 ? integer_zero_node : integer_one_node;
230     }
231 
232   int cnt = fd->ordered ? fd->ordered : fd->collapse;
233   for (i = 0; i < cnt; i++)
234     {
235       if (i == 0
236 	  && fd->collapse == 1
237 	  && !fd->tiling
238 	  && (fd->ordered == 0 || loops == NULL))
239 	loop = &fd->loop;
240       else if (loops != NULL)
241 	loop = loops + i;
242       else
243 	loop = &dummy_loop;
244 
245       loop->v = gimple_omp_for_index (for_stmt, i);
246       gcc_assert (SSA_VAR_P (loop->v));
247       gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
248 		  || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
249       var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
250       loop->n1 = gimple_omp_for_initial (for_stmt, i);
251 
252       loop->cond_code = gimple_omp_for_cond (for_stmt, i);
253       loop->n2 = gimple_omp_for_final (for_stmt, i);
254       gcc_assert (loop->cond_code != NE_EXPR
255 		  || gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKSIMD
256 		  || gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKFOR);
257       omp_adjust_for_condition (loc, &loop->cond_code, &loop->n2);
258 
259       t = gimple_omp_for_incr (for_stmt, i);
260       gcc_assert (TREE_OPERAND (t, 0) == var);
261       loop->step = omp_get_for_step_from_incr (loc, t);
262 
263       if (simd
264 	  || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
265 	      && !fd->have_ordered))
266 	{
267 	  if (fd->collapse == 1 && !fd->tiling)
268 	    iter_type = TREE_TYPE (loop->v);
269 	  else if (i == 0
270 		   || TYPE_PRECISION (iter_type)
271 		      < TYPE_PRECISION (TREE_TYPE (loop->v)))
272 	    iter_type
273 	      = build_nonstandard_integer_type
274 		  (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
275 	}
276       else if (iter_type != long_long_unsigned_type_node)
277 	{
278 	  if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
279 	    iter_type = long_long_unsigned_type_node;
280 	  else if (TYPE_UNSIGNED (TREE_TYPE (loop->v))
281 		   && TYPE_PRECISION (TREE_TYPE (loop->v))
282 		      >= TYPE_PRECISION (iter_type))
283 	    {
284 	      tree n;
285 
286 	      if (loop->cond_code == LT_EXPR)
287 		n = fold_build2_loc (loc,
288 				 PLUS_EXPR, TREE_TYPE (loop->v),
289 				 loop->n2, loop->step);
290 	      else
291 		n = loop->n1;
292 	      if (TREE_CODE (n) != INTEGER_CST
293 		  || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n))
294 		iter_type = long_long_unsigned_type_node;
295 	    }
296 	  else if (TYPE_PRECISION (TREE_TYPE (loop->v))
297 		   > TYPE_PRECISION (iter_type))
298 	    {
299 	      tree n1, n2;
300 
301 	      if (loop->cond_code == LT_EXPR)
302 		{
303 		  n1 = loop->n1;
304 		  n2 = fold_build2_loc (loc,
305 				    PLUS_EXPR, TREE_TYPE (loop->v),
306 				    loop->n2, loop->step);
307 		}
308 	      else
309 		{
310 		  n1 = fold_build2_loc (loc,
311 				    MINUS_EXPR, TREE_TYPE (loop->v),
312 				    loop->n2, loop->step);
313 		  n2 = loop->n1;
314 		}
315 	      if (TREE_CODE (n1) != INTEGER_CST
316 		  || TREE_CODE (n2) != INTEGER_CST
317 		  || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1)
318 		  || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type)))
319 		iter_type = long_long_unsigned_type_node;
320 	    }
321 	}
322 
323       if (i >= fd->collapse)
324 	continue;
325 
326       if (collapse_count && *collapse_count == NULL)
327 	{
328 	  t = fold_binary (loop->cond_code, boolean_type_node,
329 			   fold_convert (TREE_TYPE (loop->v), loop->n1),
330 			   fold_convert (TREE_TYPE (loop->v), loop->n2));
331 	  if (t && integer_zerop (t))
332 	    count = build_zero_cst (long_long_unsigned_type_node);
333 	  else if ((i == 0 || count != NULL_TREE)
334 		   && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
335 		   && TREE_CONSTANT (loop->n1)
336 		   && TREE_CONSTANT (loop->n2)
337 		   && TREE_CODE (loop->step) == INTEGER_CST)
338 	    {
339 	      tree itype = TREE_TYPE (loop->v);
340 
341 	      if (POINTER_TYPE_P (itype))
342 		itype = signed_type_for (itype);
343 	      t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1));
344 	      t = fold_build2_loc (loc,
345 			       PLUS_EXPR, itype,
346 			       fold_convert_loc (loc, itype, loop->step), t);
347 	      t = fold_build2_loc (loc, PLUS_EXPR, itype, t,
348 			       fold_convert_loc (loc, itype, loop->n2));
349 	      t = fold_build2_loc (loc, MINUS_EXPR, itype, t,
350 			       fold_convert_loc (loc, itype, loop->n1));
351 	      if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
352 		t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype,
353 				 fold_build1_loc (loc, NEGATE_EXPR, itype, t),
354 				 fold_build1_loc (loc, NEGATE_EXPR, itype,
355 					      fold_convert_loc (loc, itype,
356 								loop->step)));
357 	      else
358 		t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, t,
359 				 fold_convert_loc (loc, itype, loop->step));
360 	      t = fold_convert_loc (loc, long_long_unsigned_type_node, t);
361 	      if (count != NULL_TREE)
362 		count = fold_build2_loc (loc,
363 				     MULT_EXPR, long_long_unsigned_type_node,
364 				     count, t);
365 	      else
366 		count = t;
367 	      if (TREE_CODE (count) != INTEGER_CST)
368 		count = NULL_TREE;
369 	    }
370 	  else if (count && !integer_zerop (count))
371 	    count = NULL_TREE;
372 	}
373     }
374 
375   if (count
376       && !simd
377       && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
378 	  || fd->have_ordered))
379     {
380       if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
381 	iter_type = long_long_unsigned_type_node;
382       else
383 	iter_type = long_integer_type_node;
384     }
385   else if (collapse_iter && *collapse_iter != NULL)
386     iter_type = TREE_TYPE (*collapse_iter);
387   fd->iter_type = iter_type;
388   if (collapse_iter && *collapse_iter == NULL)
389     *collapse_iter = create_tmp_var (iter_type, ".iter");
390   if (collapse_count && *collapse_count == NULL)
391     {
392       if (count)
393 	*collapse_count = fold_convert_loc (loc, iter_type, count);
394       else
395 	*collapse_count = create_tmp_var (iter_type, ".count");
396     }
397 
398   if (fd->collapse > 1 || fd->tiling || (fd->ordered && loops))
399     {
400       fd->loop.v = *collapse_iter;
401       fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
402       fd->loop.n2 = *collapse_count;
403       fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
404       fd->loop.cond_code = LT_EXPR;
405     }
406   else if (loops)
407     loops[0] = fd->loop;
408 }
409 
410 /* Build a call to GOMP_barrier.  */
411 
412 gimple *
413 omp_build_barrier (tree lhs)
414 {
415   tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL
416 					   : BUILT_IN_GOMP_BARRIER);
417   gcall *g = gimple_build_call (fndecl, 0);
418   if (lhs)
419     gimple_call_set_lhs (g, lhs);
420   return g;
421 }
422 
423 /* Return maximum possible vectorization factor for the target.  */
424 
425 int
426 omp_max_vf (void)
427 {
428   if (!optimize
429       || optimize_debug
430       || !flag_tree_loop_optimize
431       || (!flag_tree_loop_vectorize
432 	  && (global_options_set.x_flag_tree_loop_vectorize
433 	      || global_options_set.x_flag_tree_vectorize)))
434     return 1;
435 
436   int vf = 1;
437   int vs = targetm.vectorize.autovectorize_vector_sizes ();
438   if (vs)
439     vf = 1 << floor_log2 (vs);
440   else
441     {
442       machine_mode vqimode = targetm.vectorize.preferred_simd_mode (QImode);
443       if (GET_MODE_CLASS (vqimode) == MODE_VECTOR_INT)
444 	vf = GET_MODE_NUNITS (vqimode);
445     }
446   return vf;
447 }
448 
449 /* Return maximum SIMT width if offloading may target SIMT hardware.  */
450 
451 int
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
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
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.  IS_KERNEL is
519    true, if these are for a kernels region offload function.  */
520 
521 void
522 oacc_set_fn_attrib (tree fn, tree clauses, bool is_kernel, vec<tree> *args)
523 {
524   /* Must match GOMP_DIM ordering.  */
525   static const omp_clause_code ids[]
526     = { OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS,
527 	OMP_CLAUSE_VECTOR_LENGTH };
528   unsigned ix;
529   tree dims[GOMP_DIM_MAX];
530 
531   tree attr = NULL_TREE;
532   unsigned non_const = 0;
533 
534   for (ix = GOMP_DIM_MAX; ix--;)
535     {
536       tree clause = omp_find_clause (clauses, ids[ix]);
537       tree dim = NULL_TREE;
538 
539       if (clause)
540 	dim = OMP_CLAUSE_EXPR (clause, ids[ix]);
541       dims[ix] = dim;
542       if (dim && TREE_CODE (dim) != INTEGER_CST)
543 	{
544 	  dim = integer_zero_node;
545 	  non_const |= GOMP_DIM_MASK (ix);
546 	}
547       attr = tree_cons (NULL_TREE, dim, attr);
548       /* Note kernelness with TREE_PUBLIC.  */
549       if (is_kernel)
550 	TREE_PUBLIC (attr) = 1;
551     }
552 
553   oacc_replace_fn_attrib (fn, attr);
554 
555   if (non_const)
556     {
557       /* Push a dynamic argument set.  */
558       args->safe_push (oacc_launch_pack (GOMP_LAUNCH_DIM,
559 					 NULL_TREE, non_const));
560       for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++)
561 	if (non_const & GOMP_DIM_MASK (ix))
562 	  args->safe_push (dims[ix]);
563     }
564 }
565 
566 /*  Process the routine's dimension clauess to generate an attribute
567     value.  Issue diagnostics as appropriate.  We default to SEQ
568     (OpenACC 2.5 clarifies this). All dimensions have a size of zero
569     (dynamic).  TREE_PURPOSE is set to indicate whether that dimension
570     can have a loop partitioned on it.  non-zero indicates
571     yes, zero indicates no.  By construction once a non-zero has been
572     reached, further inner dimensions must also be non-zero.  We set
573     TREE_VALUE to zero for the dimensions that may be partitioned and
574     1 for the other ones -- if a loop is (erroneously) spawned at
575     an outer level, we don't want to try and partition it.  */
576 
577 tree
578 oacc_build_routine_dims (tree clauses)
579 {
580   /* Must match GOMP_DIM ordering.  */
581   static const omp_clause_code ids[]
582     = {OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ};
583   int ix;
584   int level = -1;
585 
586   for (; clauses; clauses = OMP_CLAUSE_CHAIN (clauses))
587     for (ix = GOMP_DIM_MAX + 1; ix--;)
588       if (OMP_CLAUSE_CODE (clauses) == ids[ix])
589 	{
590 	  if (level >= 0)
591 	    error_at (OMP_CLAUSE_LOCATION (clauses),
592 		      "multiple loop axes specified for routine");
593 	  level = ix;
594 	  break;
595 	}
596 
597   /* Default to SEQ.  */
598   if (level < 0)
599     level = GOMP_DIM_MAX;
600 
601   tree dims = NULL_TREE;
602 
603   for (ix = GOMP_DIM_MAX; ix--;)
604     dims = tree_cons (build_int_cst (boolean_type_node, ix >= level),
605 		      build_int_cst (integer_type_node, ix < level), dims);
606 
607   return dims;
608 }
609 
610 /* Retrieve the oacc function attrib and return it.  Non-oacc
611    functions will return NULL.  */
612 
613 tree
614 oacc_get_fn_attrib (tree fn)
615 {
616   return lookup_attribute (OACC_FN_ATTRIB, DECL_ATTRIBUTES (fn));
617 }
618 
619 /* Return true if this oacc fn attrib is for a kernels offload
620    region.  We use the TREE_PUBLIC flag of each dimension -- only
621    need to check the first one.  */
622 
623 bool
624 oacc_fn_attrib_kernels_p (tree attr)
625 {
626   return TREE_PUBLIC (TREE_VALUE (attr));
627 }
628 
629 /* Extract an oacc execution dimension from FN.  FN must be an
630    offloaded function or routine that has already had its execution
631    dimensions lowered to the target-specific values.  */
632 
633 int
634 oacc_get_fn_dim_size (tree fn, int axis)
635 {
636   tree attrs = oacc_get_fn_attrib (fn);
637 
638   gcc_assert (axis < GOMP_DIM_MAX);
639 
640   tree dims = TREE_VALUE (attrs);
641   while (axis--)
642     dims = TREE_CHAIN (dims);
643 
644   int size = TREE_INT_CST_LOW (TREE_VALUE (dims));
645 
646   return size;
647 }
648 
649 /* Extract the dimension axis from an IFN_GOACC_DIM_POS or
650    IFN_GOACC_DIM_SIZE call.  */
651 
652 int
653 oacc_get_ifn_dim_arg (const gimple *stmt)
654 {
655   gcc_checking_assert (gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_SIZE
656 		       || gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_POS);
657   tree arg = gimple_call_arg (stmt, 0);
658   HOST_WIDE_INT axis = TREE_INT_CST_LOW (arg);
659 
660   gcc_checking_assert (axis >= 0 && axis < GOMP_DIM_MAX);
661   return (int) axis;
662 }
663