gcc80: Handle TZ specific "%+" format in strftime.
[dragonfly.git] / contrib / gcc-8.0 / gcc / omp-general.c
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
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
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
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
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
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 *
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
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
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.  */
519
520 void
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
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
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
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
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
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 }