1 /* General types and functions that are uselful for processing of OpenMP,
2 OpenACC and similar directivers at various stages of compilation.
4 Copyright (C) 2005-2023 Free Software Foundation, Inc.
6 This file is part of GCC.
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
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
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/>. */
22 /* Find an OMP clause of type KIND within CLAUSES. */
26 #include "coretypes.h"
32 #include "diagnostic-core.h"
33 #include "fold-const.h"
34 #include "langhooks.h"
35 #include "omp-general.h"
36 #include "stringpool.h"
40 #include "alloc-pool.h"
41 #include "symbol-summary.h"
42 #include "tree-pass.h"
43 #include "omp-device-properties.h"
44 #include "tree-iterator.h"
45 #include "data-streamer.h"
46 #include "streamer-hooks.h"
49 enum omp_requires omp_requires_mask
;
52 omp_find_clause (tree clauses
, enum omp_clause_code kind
)
54 for (; clauses
; clauses
= OMP_CLAUSE_CHAIN (clauses
))
55 if (OMP_CLAUSE_CODE (clauses
) == kind
)
61 /* True if OpenMP should regard this DECL as being a scalar which has Fortran's
62 allocatable or pointer attribute. */
64 omp_is_allocatable_or_ptr (tree decl
)
66 return lang_hooks
.decls
.omp_is_allocatable_or_ptr (decl
);
69 /* Check whether this DECL belongs to a Fortran optional argument.
70 With 'for_present_check' set to false, decls which are optional parameters
71 themselve are returned as tree - or a NULL_TREE otherwise. Those decls are
72 always pointers. With 'for_present_check' set to true, the decl for checking
73 whether an argument is present is returned; for arguments with value
74 attribute this is the hidden argument and of BOOLEAN_TYPE. If the decl is
75 unrelated to optional arguments, NULL_TREE is returned. */
78 omp_check_optional_argument (tree decl
, bool for_present_check
)
80 return lang_hooks
.decls
.omp_check_optional_argument (decl
, for_present_check
);
83 /* Return true if TYPE is an OpenMP mappable type. */
86 omp_mappable_type (tree type
)
88 /* Mappable type has to be complete. */
89 if (type
== error_mark_node
|| !COMPLETE_TYPE_P (type
))
94 /* True if OpenMP should privatize what this DECL points to rather
95 than the DECL itself. */
98 omp_privatize_by_reference (tree decl
)
100 return lang_hooks
.decls
.omp_privatize_by_reference (decl
);
103 /* Adjust *COND_CODE and *N2 so that the former is either LT_EXPR or GT_EXPR,
104 given that V is the loop index variable and STEP is loop step. */
107 omp_adjust_for_condition (location_t loc
, enum tree_code
*cond_code
, tree
*n2
,
117 gcc_assert (TREE_CODE (step
) == INTEGER_CST
);
118 if (TREE_CODE (TREE_TYPE (v
)) == INTEGER_TYPE
)
120 if (integer_onep (step
))
121 *cond_code
= LT_EXPR
;
124 gcc_assert (integer_minus_onep (step
));
125 *cond_code
= GT_EXPR
;
130 tree unit
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v
)));
131 gcc_assert (TREE_CODE (unit
) == INTEGER_CST
);
132 if (tree_int_cst_equal (unit
, step
))
133 *cond_code
= LT_EXPR
;
136 gcc_assert (wi::neg (wi::to_widest (unit
))
137 == wi::to_widest (step
));
138 *cond_code
= GT_EXPR
;
145 if (POINTER_TYPE_P (TREE_TYPE (*n2
)))
146 *n2
= fold_build_pointer_plus_hwi_loc (loc
, *n2
, 1);
148 *n2
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (*n2
), *n2
,
149 build_int_cst (TREE_TYPE (*n2
), 1));
150 *cond_code
= LT_EXPR
;
153 if (POINTER_TYPE_P (TREE_TYPE (*n2
)))
154 *n2
= fold_build_pointer_plus_hwi_loc (loc
, *n2
, -1);
156 *n2
= fold_build2_loc (loc
, MINUS_EXPR
, TREE_TYPE (*n2
), *n2
,
157 build_int_cst (TREE_TYPE (*n2
), 1));
158 *cond_code
= GT_EXPR
;
165 /* Return the looping step from INCR, extracted from the step of a gimple omp
169 omp_get_for_step_from_incr (location_t loc
, tree incr
)
172 switch (TREE_CODE (incr
))
175 step
= TREE_OPERAND (incr
, 1);
177 case POINTER_PLUS_EXPR
:
178 step
= fold_convert (ssizetype
, TREE_OPERAND (incr
, 1));
181 step
= TREE_OPERAND (incr
, 1);
182 step
= fold_build1_loc (loc
, NEGATE_EXPR
, TREE_TYPE (step
), step
);
190 /* Extract the header elements of parallel loop FOR_STMT and store
194 omp_extract_for_data (gomp_for
*for_stmt
, struct omp_for_data
*fd
,
195 struct omp_for_data_loop
*loops
)
197 tree t
, var
, *collapse_iter
, *collapse_count
;
198 tree count
= NULL_TREE
, iter_type
= long_integer_type_node
;
199 struct omp_for_data_loop
*loop
;
201 struct omp_for_data_loop dummy_loop
;
202 location_t loc
= gimple_location (for_stmt
);
203 bool simd
= gimple_omp_for_kind (for_stmt
) == GF_OMP_FOR_KIND_SIMD
;
204 bool distribute
= gimple_omp_for_kind (for_stmt
)
205 == GF_OMP_FOR_KIND_DISTRIBUTE
;
206 bool taskloop
= gimple_omp_for_kind (for_stmt
)
207 == GF_OMP_FOR_KIND_TASKLOOP
;
208 bool order_reproducible
= false;
211 fd
->for_stmt
= for_stmt
;
213 fd
->have_nowait
= distribute
|| simd
;
214 fd
->have_ordered
= false;
215 fd
->have_reductemp
= false;
216 fd
->have_pointer_condtemp
= false;
217 fd
->have_scantemp
= false;
218 fd
->have_nonctrl_scantemp
= false;
219 fd
->non_rect
= false;
220 fd
->lastprivate_conditional
= 0;
221 fd
->tiling
= NULL_TREE
;
224 fd
->first_nonrect
= -1;
225 fd
->last_nonrect
= -1;
226 fd
->sched_kind
= OMP_CLAUSE_SCHEDULE_STATIC
;
227 fd
->sched_modifiers
= 0;
228 fd
->chunk_size
= NULL_TREE
;
229 fd
->simd_schedule
= false;
230 fd
->first_inner_iterations
= NULL_TREE
;
231 fd
->factor
= NULL_TREE
;
232 fd
->adjn1
= NULL_TREE
;
233 collapse_iter
= NULL
;
234 collapse_count
= NULL
;
236 for (t
= gimple_omp_for_clauses (for_stmt
); t
; t
= OMP_CLAUSE_CHAIN (t
))
237 switch (OMP_CLAUSE_CODE (t
))
239 case OMP_CLAUSE_NOWAIT
:
240 fd
->have_nowait
= true;
242 case OMP_CLAUSE_ORDERED
:
243 fd
->have_ordered
= true;
244 if (OMP_CLAUSE_ORDERED_DOACROSS (t
))
246 if (OMP_CLAUSE_ORDERED_EXPR (t
))
247 fd
->ordered
= tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t
));
252 case OMP_CLAUSE_SCHEDULE
:
253 gcc_assert (!distribute
&& !taskloop
);
255 = (enum omp_clause_schedule_kind
)
256 (OMP_CLAUSE_SCHEDULE_KIND (t
) & OMP_CLAUSE_SCHEDULE_MASK
);
257 fd
->sched_modifiers
= (OMP_CLAUSE_SCHEDULE_KIND (t
)
258 & ~OMP_CLAUSE_SCHEDULE_MASK
);
259 fd
->chunk_size
= OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t
);
260 fd
->simd_schedule
= OMP_CLAUSE_SCHEDULE_SIMD (t
);
262 case OMP_CLAUSE_DIST_SCHEDULE
:
263 gcc_assert (distribute
);
264 fd
->chunk_size
= OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t
);
266 case OMP_CLAUSE_COLLAPSE
:
267 fd
->collapse
= tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t
));
268 if (fd
->collapse
> 1)
270 collapse_iter
= &OMP_CLAUSE_COLLAPSE_ITERVAR (t
);
271 collapse_count
= &OMP_CLAUSE_COLLAPSE_COUNT (t
);
274 case OMP_CLAUSE_TILE
:
275 fd
->tiling
= OMP_CLAUSE_TILE_LIST (t
);
276 fd
->collapse
= list_length (fd
->tiling
);
277 gcc_assert (fd
->collapse
);
278 collapse_iter
= &OMP_CLAUSE_TILE_ITERVAR (t
);
279 collapse_count
= &OMP_CLAUSE_TILE_COUNT (t
);
281 case OMP_CLAUSE__REDUCTEMP_
:
282 fd
->have_reductemp
= true;
284 case OMP_CLAUSE_LASTPRIVATE
:
285 if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (t
))
286 fd
->lastprivate_conditional
++;
288 case OMP_CLAUSE__CONDTEMP_
:
289 if (POINTER_TYPE_P (TREE_TYPE (OMP_CLAUSE_DECL (t
))))
290 fd
->have_pointer_condtemp
= true;
292 case OMP_CLAUSE__SCANTEMP_
:
293 fd
->have_scantemp
= true;
294 if (!OMP_CLAUSE__SCANTEMP__ALLOC (t
)
295 && !OMP_CLAUSE__SCANTEMP__CONTROL (t
))
296 fd
->have_nonctrl_scantemp
= true;
298 case OMP_CLAUSE_ORDER
:
299 /* FIXME: For OpenMP 5.2 this should change to
300 if (OMP_CLAUSE_ORDER_REPRODUCIBLE (t))
301 (with the exception of loop construct but that lowers to
302 no schedule/dist_schedule clauses currently). */
303 if (!OMP_CLAUSE_ORDER_UNCONSTRAINED (t
))
304 order_reproducible
= true;
309 if (fd
->ordered
== -1)
310 fd
->ordered
= fd
->collapse
;
312 /* For order(reproducible:concurrent) schedule ({dynamic,guided,runtime})
313 we have either the option to expensively remember at runtime how we've
314 distributed work from first loop and reuse that in following loops with
315 the same number of iterations and schedule, or just force static schedule.
316 OpenMP API calls etc. aren't allowed in order(concurrent) bodies so
317 users can't observe it easily anyway. */
318 if (order_reproducible
)
319 fd
->sched_kind
= OMP_CLAUSE_SCHEDULE_STATIC
;
320 if (fd
->collapse
> 1 || fd
->tiling
)
323 fd
->loops
= &fd
->loop
;
325 if (fd
->ordered
&& fd
->collapse
== 1 && loops
!= NULL
)
330 collapse_iter
= &iterv
;
331 collapse_count
= &countv
;
334 /* FIXME: for now map schedule(auto) to schedule(static).
335 There should be analysis to determine whether all iterations
336 are approximately the same amount of work (then schedule(static)
337 is best) or if it varies (then schedule(dynamic,N) is better). */
338 if (fd
->sched_kind
== OMP_CLAUSE_SCHEDULE_AUTO
)
340 fd
->sched_kind
= OMP_CLAUSE_SCHEDULE_STATIC
;
341 gcc_assert (fd
->chunk_size
== NULL
);
343 gcc_assert ((fd
->collapse
== 1 && !fd
->tiling
) || collapse_iter
!= NULL
);
345 fd
->sched_kind
= OMP_CLAUSE_SCHEDULE_RUNTIME
;
346 if (fd
->sched_kind
== OMP_CLAUSE_SCHEDULE_RUNTIME
)
347 gcc_assert (fd
->chunk_size
== NULL
);
348 else if (fd
->chunk_size
== NULL
)
350 /* We only need to compute a default chunk size for ordered
351 static loops and dynamic loops. */
352 if (fd
->sched_kind
!= OMP_CLAUSE_SCHEDULE_STATIC
354 fd
->chunk_size
= (fd
->sched_kind
== OMP_CLAUSE_SCHEDULE_STATIC
)
355 ? integer_zero_node
: integer_one_node
;
358 int cnt
= fd
->ordered
? fd
->ordered
: fd
->collapse
;
359 int single_nonrect
= -1;
360 tree single_nonrect_count
= NULL_TREE
;
361 enum tree_code single_nonrect_cond_code
= ERROR_MARK
;
362 for (i
= 1; i
< cnt
; i
++)
364 tree n1
= gimple_omp_for_initial (for_stmt
, i
);
365 tree n2
= gimple_omp_for_final (for_stmt
, i
);
366 if (TREE_CODE (n1
) == TREE_VEC
)
373 for (int j
= i
- 1; j
>= 0; j
--)
374 if (TREE_VEC_ELT (n1
, 0) == gimple_omp_for_index (for_stmt
, j
))
381 else if (TREE_CODE (n2
) == TREE_VEC
)
388 for (int j
= i
- 1; j
>= 0; j
--)
389 if (TREE_VEC_ELT (n2
, 0) == gimple_omp_for_index (for_stmt
, j
))
397 for (i
= 0; i
< cnt
; i
++)
402 && (fd
->ordered
== 0 || loops
== NULL
))
404 else if (loops
!= NULL
)
409 loop
->v
= gimple_omp_for_index (for_stmt
, i
);
410 gcc_assert (SSA_VAR_P (loop
->v
));
411 gcc_assert (TREE_CODE (TREE_TYPE (loop
->v
)) == INTEGER_TYPE
412 || TREE_CODE (TREE_TYPE (loop
->v
)) == POINTER_TYPE
);
413 var
= TREE_CODE (loop
->v
) == SSA_NAME
? SSA_NAME_VAR (loop
->v
) : loop
->v
;
414 loop
->n1
= gimple_omp_for_initial (for_stmt
, i
);
415 loop
->m1
= NULL_TREE
;
416 loop
->m2
= NULL_TREE
;
418 loop
->non_rect_referenced
= false;
419 if (TREE_CODE (loop
->n1
) == TREE_VEC
)
421 for (int j
= i
- 1; j
>= 0; j
--)
422 if (TREE_VEC_ELT (loop
->n1
, 0) == gimple_omp_for_index (for_stmt
, j
))
426 loops
[j
].non_rect_referenced
= true;
427 if (fd
->first_nonrect
== -1 || fd
->first_nonrect
> j
)
428 fd
->first_nonrect
= j
;
431 gcc_assert (loop
->outer
);
432 loop
->m1
= TREE_VEC_ELT (loop
->n1
, 1);
433 loop
->n1
= TREE_VEC_ELT (loop
->n1
, 2);
435 fd
->last_nonrect
= i
;
438 loop
->cond_code
= gimple_omp_for_cond (for_stmt
, i
);
439 loop
->n2
= gimple_omp_for_final (for_stmt
, i
);
440 gcc_assert (loop
->cond_code
!= NE_EXPR
441 || (gimple_omp_for_kind (for_stmt
)
442 != GF_OMP_FOR_KIND_OACC_LOOP
));
443 if (TREE_CODE (loop
->n2
) == TREE_VEC
)
446 gcc_assert (TREE_VEC_ELT (loop
->n2
, 0)
447 == gimple_omp_for_index (for_stmt
, i
- loop
->outer
));
449 for (int j
= i
- 1; j
>= 0; j
--)
450 if (TREE_VEC_ELT (loop
->n2
, 0) == gimple_omp_for_index (for_stmt
, j
))
454 loops
[j
].non_rect_referenced
= true;
455 if (fd
->first_nonrect
== -1 || fd
->first_nonrect
> j
)
456 fd
->first_nonrect
= j
;
459 gcc_assert (loop
->outer
);
460 loop
->m2
= TREE_VEC_ELT (loop
->n2
, 1);
461 loop
->n2
= TREE_VEC_ELT (loop
->n2
, 2);
463 fd
->last_nonrect
= i
;
466 t
= gimple_omp_for_incr (for_stmt
, i
);
467 gcc_assert (TREE_OPERAND (t
, 0) == var
);
468 loop
->step
= omp_get_for_step_from_incr (loc
, t
);
470 omp_adjust_for_condition (loc
, &loop
->cond_code
, &loop
->n2
, loop
->v
,
474 || (fd
->sched_kind
== OMP_CLAUSE_SCHEDULE_STATIC
475 && !fd
->have_ordered
))
477 if (fd
->collapse
== 1 && !fd
->tiling
)
478 iter_type
= TREE_TYPE (loop
->v
);
480 || TYPE_PRECISION (iter_type
)
481 < TYPE_PRECISION (TREE_TYPE (loop
->v
)))
483 = build_nonstandard_integer_type
484 (TYPE_PRECISION (TREE_TYPE (loop
->v
)), 1);
486 else if (iter_type
!= long_long_unsigned_type_node
)
488 if (POINTER_TYPE_P (TREE_TYPE (loop
->v
)))
489 iter_type
= long_long_unsigned_type_node
;
490 else if (TYPE_UNSIGNED (TREE_TYPE (loop
->v
))
491 && TYPE_PRECISION (TREE_TYPE (loop
->v
))
492 >= TYPE_PRECISION (iter_type
))
496 if (loop
->cond_code
== LT_EXPR
)
497 n
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (loop
->v
),
498 loop
->n2
, loop
->step
);
503 || TREE_CODE (n
) != INTEGER_CST
504 || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type
), n
))
505 iter_type
= long_long_unsigned_type_node
;
507 else if (TYPE_PRECISION (TREE_TYPE (loop
->v
))
508 > TYPE_PRECISION (iter_type
))
512 if (loop
->cond_code
== LT_EXPR
)
515 n2
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (loop
->v
),
516 loop
->n2
, loop
->step
);
520 n1
= fold_build2_loc (loc
, MINUS_EXPR
, TREE_TYPE (loop
->v
),
521 loop
->n2
, loop
->step
);
526 || TREE_CODE (n1
) != INTEGER_CST
527 || TREE_CODE (n2
) != INTEGER_CST
528 || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type
), n1
)
529 || !tree_int_cst_lt (n2
, TYPE_MAX_VALUE (iter_type
)))
530 iter_type
= long_long_unsigned_type_node
;
534 if (i
>= fd
->collapse
)
537 if (collapse_count
&& *collapse_count
== NULL
)
539 if (count
&& integer_zerop (count
))
541 tree n1first
= NULL_TREE
, n2first
= NULL_TREE
;
542 tree n1last
= NULL_TREE
, n2last
= NULL_TREE
;
543 tree ostep
= NULL_TREE
;
544 if (loop
->m1
|| loop
->m2
)
546 if (count
== NULL_TREE
)
548 if (single_nonrect
== -1
549 || (loop
->m1
&& TREE_CODE (loop
->m1
) != INTEGER_CST
)
550 || (loop
->m2
&& TREE_CODE (loop
->m2
) != INTEGER_CST
)
551 || TREE_CODE (loop
->n1
) != INTEGER_CST
552 || TREE_CODE (loop
->n2
) != INTEGER_CST
553 || TREE_CODE (loop
->step
) != INTEGER_CST
)
558 tree var
= gimple_omp_for_initial (for_stmt
, single_nonrect
);
559 tree itype
= TREE_TYPE (var
);
560 tree first
= gimple_omp_for_initial (for_stmt
, single_nonrect
);
561 t
= gimple_omp_for_incr (for_stmt
, single_nonrect
);
562 ostep
= omp_get_for_step_from_incr (loc
, t
);
563 t
= fold_binary (MINUS_EXPR
, long_long_unsigned_type_node
,
564 single_nonrect_count
,
565 build_one_cst (long_long_unsigned_type_node
));
566 t
= fold_convert (itype
, t
);
567 first
= fold_convert (itype
, first
);
568 ostep
= fold_convert (itype
, ostep
);
569 tree last
= fold_binary (PLUS_EXPR
, itype
, first
,
570 fold_binary (MULT_EXPR
, itype
, t
,
572 if (TREE_CODE (first
) != INTEGER_CST
573 || TREE_CODE (last
) != INTEGER_CST
)
580 tree m1
= fold_convert (itype
, loop
->m1
);
581 tree n1
= fold_convert (itype
, loop
->n1
);
582 n1first
= fold_binary (PLUS_EXPR
, itype
,
583 fold_binary (MULT_EXPR
, itype
,
585 n1last
= fold_binary (PLUS_EXPR
, itype
,
586 fold_binary (MULT_EXPR
, itype
,
590 n1first
= n1last
= loop
->n1
;
593 tree n2
= fold_convert (itype
, loop
->n2
);
594 tree m2
= fold_convert (itype
, loop
->m2
);
595 n2first
= fold_binary (PLUS_EXPR
, itype
,
596 fold_binary (MULT_EXPR
, itype
,
598 n2last
= fold_binary (PLUS_EXPR
, itype
,
599 fold_binary (MULT_EXPR
, itype
,
603 n2first
= n2last
= loop
->n2
;
604 n1first
= fold_convert (TREE_TYPE (loop
->v
), n1first
);
605 n2first
= fold_convert (TREE_TYPE (loop
->v
), n2first
);
606 n1last
= fold_convert (TREE_TYPE (loop
->v
), n1last
);
607 n2last
= fold_convert (TREE_TYPE (loop
->v
), n2last
);
608 t
= fold_binary (loop
->cond_code
, boolean_type_node
,
610 tree t2
= fold_binary (loop
->cond_code
, boolean_type_node
,
612 if (t
&& t2
&& integer_nonzerop (t
) && integer_nonzerop (t2
))
613 /* All outer loop iterators have at least one inner loop
614 iteration. Try to compute the count at compile time. */
616 else if (t
&& t2
&& integer_zerop (t
) && integer_zerop (t2
))
617 /* No iterations of the inner loop. count will be set to
619 else if (TYPE_UNSIGNED (itype
)
622 || TREE_CODE (t
) != INTEGER_CST
623 || TREE_CODE (t2
) != INTEGER_CST
)
625 /* Punt (for now). */
631 /* Some iterations of the outer loop have zero iterations
632 of the inner loop, while others have at least one.
633 In this case, we need to adjust one of those outer
634 loop bounds. If ADJ_FIRST, we need to adjust outer n1
635 (first), otherwise outer n2 (last). */
636 bool adj_first
= integer_zerop (t
);
637 tree n1
= fold_convert (itype
, loop
->n1
);
638 tree n2
= fold_convert (itype
, loop
->n2
);
639 tree m1
= loop
->m1
? fold_convert (itype
, loop
->m1
)
640 : build_zero_cst (itype
);
641 tree m2
= loop
->m2
? fold_convert (itype
, loop
->m2
)
642 : build_zero_cst (itype
);
643 t
= fold_binary (MINUS_EXPR
, itype
, n1
, n2
);
644 t2
= fold_binary (MINUS_EXPR
, itype
, m2
, m1
);
645 t
= fold_binary (TRUNC_DIV_EXPR
, itype
, t
, t2
);
646 t2
= fold_binary (MINUS_EXPR
, itype
, t
, first
);
647 t2
= fold_binary (TRUNC_MOD_EXPR
, itype
, t2
, ostep
);
648 t
= fold_binary (MINUS_EXPR
, itype
, t
, t2
);
650 = fold_binary (PLUS_EXPR
, itype
, n1
,
651 fold_binary (MULT_EXPR
, itype
, m1
, t
));
653 = fold_binary (PLUS_EXPR
, itype
, n2
,
654 fold_binary (MULT_EXPR
, itype
, m2
, t
));
655 t2
= fold_binary (loop
->cond_code
, boolean_type_node
,
657 tree t3
= fold_binary (MULT_EXPR
, itype
, m1
, ostep
);
658 tree t4
= fold_binary (MULT_EXPR
, itype
, m2
, ostep
);
663 if (integer_nonzerop (t2
))
670 t3
= fold_binary (MINUS_EXPR
, itype
, n1cur
, t3
);
671 t4
= fold_binary (MINUS_EXPR
, itype
, n2cur
, t4
);
672 t3
= fold_binary (loop
->cond_code
,
673 boolean_type_node
, t3
, t4
);
674 gcc_assert (integer_zerop (t3
));
679 t3
= fold_binary (PLUS_EXPR
, itype
, n1cur
, t3
);
680 t4
= fold_binary (PLUS_EXPR
, itype
, n2cur
, t4
);
681 new_first
= fold_binary (PLUS_EXPR
, itype
, t
, ostep
);
686 t3
= fold_binary (loop
->cond_code
,
687 boolean_type_node
, t3
, t4
);
688 gcc_assert (integer_nonzerop (t3
));
691 diff
= fold_binary (MINUS_EXPR
, itype
, new_first
, first
);
698 if (integer_zerop (t2
))
700 t3
= fold_binary (MINUS_EXPR
, itype
, n1cur
, t3
);
701 t4
= fold_binary (MINUS_EXPR
, itype
, n2cur
, t4
);
702 new_last
= fold_binary (MINUS_EXPR
, itype
, t
, ostep
);
707 t3
= fold_binary (loop
->cond_code
,
708 boolean_type_node
, t3
, t4
);
709 gcc_assert (integer_nonzerop (t3
));
719 t3
= fold_binary (PLUS_EXPR
, itype
, n1cur
, t3
);
720 t4
= fold_binary (PLUS_EXPR
, itype
, n2cur
, t4
);
721 t3
= fold_binary (loop
->cond_code
,
722 boolean_type_node
, t3
, t4
);
723 gcc_assert (integer_zerop (t3
));
726 diff
= fold_binary (MINUS_EXPR
, itype
, last
, new_last
);
728 if (TYPE_UNSIGNED (itype
)
729 && single_nonrect_cond_code
== GT_EXPR
)
730 diff
= fold_binary (TRUNC_DIV_EXPR
, itype
,
731 fold_unary (NEGATE_EXPR
, itype
, diff
),
732 fold_unary (NEGATE_EXPR
, itype
,
735 diff
= fold_binary (TRUNC_DIV_EXPR
, itype
, diff
, ostep
);
736 diff
= fold_convert (long_long_unsigned_type_node
, diff
);
738 = fold_binary (MINUS_EXPR
, long_long_unsigned_type_node
,
739 single_nonrect_count
, diff
);
744 t
= fold_binary (loop
->cond_code
, boolean_type_node
,
745 fold_convert (TREE_TYPE (loop
->v
), loop
->n1
),
746 fold_convert (TREE_TYPE (loop
->v
), loop
->n2
));
747 if (t
&& integer_zerop (t
))
748 count
= build_zero_cst (long_long_unsigned_type_node
);
749 else if ((i
== 0 || count
!= NULL_TREE
)
750 && TREE_CODE (TREE_TYPE (loop
->v
)) == INTEGER_TYPE
751 && TREE_CONSTANT (loop
->n1
)
752 && TREE_CONSTANT (loop
->n2
)
753 && TREE_CODE (loop
->step
) == INTEGER_CST
)
755 tree itype
= TREE_TYPE (loop
->v
);
757 if (POINTER_TYPE_P (itype
))
758 itype
= signed_type_for (itype
);
759 t
= build_int_cst (itype
, (loop
->cond_code
== LT_EXPR
? -1 : 1));
760 t
= fold_build2 (PLUS_EXPR
, itype
,
761 fold_convert (itype
, loop
->step
), t
);
764 if (loop
->m1
|| loop
->m2
)
766 gcc_assert (single_nonrect
!= -1);
770 t
= fold_build2 (PLUS_EXPR
, itype
, t
, fold_convert (itype
, n2
));
771 t
= fold_build2 (MINUS_EXPR
, itype
, t
, fold_convert (itype
, n1
));
772 tree step
= fold_convert_loc (loc
, itype
, loop
->step
);
773 if (TYPE_UNSIGNED (itype
) && loop
->cond_code
== GT_EXPR
)
774 t
= fold_build2 (TRUNC_DIV_EXPR
, itype
,
775 fold_build1 (NEGATE_EXPR
, itype
, t
),
776 fold_build1 (NEGATE_EXPR
, itype
, step
));
778 t
= fold_build2 (TRUNC_DIV_EXPR
, itype
, t
, step
);
779 tree llutype
= long_long_unsigned_type_node
;
780 t
= fold_convert (llutype
, t
);
781 if (loop
->m1
|| loop
->m2
)
783 /* t is number of iterations of inner loop at either first
784 or last value of the outer iterator (the one with fewer
786 Compute t2 = ((m2 - m1) * ostep) / step
787 and niters = outer_count * t
788 + t2 * ((outer_count - 1) * outer_count / 2)
790 tree m1
= loop
->m1
? loop
->m1
: integer_zero_node
;
791 tree m2
= loop
->m2
? loop
->m2
: integer_zero_node
;
792 m1
= fold_convert (itype
, m1
);
793 m2
= fold_convert (itype
, m2
);
794 tree t2
= fold_build2 (MINUS_EXPR
, itype
, m2
, m1
);
795 t2
= fold_build2 (MULT_EXPR
, itype
, t2
, ostep
);
796 if (TYPE_UNSIGNED (itype
) && loop
->cond_code
== GT_EXPR
)
797 t2
= fold_build2 (TRUNC_DIV_EXPR
, itype
,
798 fold_build1 (NEGATE_EXPR
, itype
, t2
),
799 fold_build1 (NEGATE_EXPR
, itype
, step
));
801 t2
= fold_build2 (TRUNC_DIV_EXPR
, itype
, t2
, step
);
802 t2
= fold_convert (llutype
, t2
);
803 fd
->first_inner_iterations
= t
;
805 t
= fold_build2 (MULT_EXPR
, llutype
, t
,
806 single_nonrect_count
);
807 tree t3
= fold_build2 (MINUS_EXPR
, llutype
,
808 single_nonrect_count
,
809 build_one_cst (llutype
));
810 t3
= fold_build2 (MULT_EXPR
, llutype
, t3
,
811 single_nonrect_count
);
812 t3
= fold_build2 (TRUNC_DIV_EXPR
, llutype
, t3
,
813 build_int_cst (llutype
, 2));
814 t2
= fold_build2 (MULT_EXPR
, llutype
, t2
, t3
);
815 t
= fold_build2 (PLUS_EXPR
, llutype
, t
, t2
);
817 if (i
== single_nonrect
)
819 if (integer_zerop (t
) || TREE_CODE (t
) != INTEGER_CST
)
823 single_nonrect_count
= t
;
824 single_nonrect_cond_code
= loop
->cond_code
;
825 if (count
== NULL_TREE
)
826 count
= build_one_cst (llutype
);
829 else if (count
!= NULL_TREE
)
830 count
= fold_build2 (MULT_EXPR
, llutype
, count
, t
);
833 if (TREE_CODE (count
) != INTEGER_CST
)
836 else if (count
&& !integer_zerop (count
))
843 && (fd
->sched_kind
!= OMP_CLAUSE_SCHEDULE_STATIC
844 || fd
->have_ordered
))
846 if (!tree_int_cst_lt (count
, TYPE_MAX_VALUE (long_integer_type_node
)))
847 iter_type
= long_long_unsigned_type_node
;
849 iter_type
= long_integer_type_node
;
851 else if (collapse_iter
&& *collapse_iter
!= NULL
)
852 iter_type
= TREE_TYPE (*collapse_iter
);
853 fd
->iter_type
= iter_type
;
854 if (collapse_iter
&& *collapse_iter
== NULL
)
855 *collapse_iter
= create_tmp_var (iter_type
, ".iter");
856 if (collapse_count
&& *collapse_count
== NULL
)
860 *collapse_count
= fold_convert_loc (loc
, iter_type
, count
);
861 if (fd
->first_inner_iterations
&& fd
->factor
)
863 t
= make_tree_vec (4);
864 TREE_VEC_ELT (t
, 0) = *collapse_count
;
865 TREE_VEC_ELT (t
, 1) = fd
->first_inner_iterations
;
866 TREE_VEC_ELT (t
, 2) = fd
->factor
;
867 TREE_VEC_ELT (t
, 3) = fd
->adjn1
;
872 *collapse_count
= create_tmp_var (iter_type
, ".count");
875 if (fd
->collapse
> 1 || fd
->tiling
|| (fd
->ordered
&& loops
))
877 fd
->loop
.v
= *collapse_iter
;
878 fd
->loop
.n1
= build_int_cst (TREE_TYPE (fd
->loop
.v
), 0);
879 fd
->loop
.n2
= *collapse_count
;
880 if (TREE_CODE (fd
->loop
.n2
) == TREE_VEC
)
882 gcc_assert (fd
->non_rect
);
883 fd
->first_inner_iterations
= TREE_VEC_ELT (fd
->loop
.n2
, 1);
884 fd
->factor
= TREE_VEC_ELT (fd
->loop
.n2
, 2);
885 fd
->adjn1
= TREE_VEC_ELT (fd
->loop
.n2
, 3);
886 fd
->loop
.n2
= TREE_VEC_ELT (fd
->loop
.n2
, 0);
888 fd
->loop
.step
= build_int_cst (TREE_TYPE (fd
->loop
.v
), 1);
889 fd
->loop
.m1
= NULL_TREE
;
890 fd
->loop
.m2
= NULL_TREE
;
892 fd
->loop
.cond_code
= LT_EXPR
;
898 /* Build a call to GOMP_barrier. */
901 omp_build_barrier (tree lhs
)
903 tree fndecl
= builtin_decl_explicit (lhs
? BUILT_IN_GOMP_BARRIER_CANCEL
904 : BUILT_IN_GOMP_BARRIER
);
905 gcall
*g
= gimple_build_call (fndecl
, 0);
907 gimple_call_set_lhs (g
, lhs
);
911 /* Find OMP_FOR resp. OMP_SIMD with non-NULL OMP_FOR_INIT. Also, fill in pdata
912 array, pdata[0] non-NULL if there is anything non-trivial in between,
913 pdata[1] is address of OMP_PARALLEL in between if any, pdata[2] is address
914 of OMP_FOR in between if any and pdata[3] is address of the inner
918 find_combined_omp_for (tree
*tp
, int *walk_subtrees
, void *data
)
920 tree
**pdata
= (tree
**) data
;
922 switch (TREE_CODE (*tp
))
925 if (OMP_FOR_INIT (*tp
) != NULL_TREE
)
934 if (OMP_FOR_INIT (*tp
) != NULL_TREE
)
941 if (BIND_EXPR_VARS (*tp
)
942 || (BIND_EXPR_BLOCK (*tp
)
943 && BLOCK_VARS (BIND_EXPR_BLOCK (*tp
))))
948 if (!tsi_one_before_end_p (tsi_start (*tp
)))
952 case TRY_FINALLY_EXPR
:
966 /* Return maximum possible vectorization factor for the target. */
973 || !flag_tree_loop_optimize
974 || (!flag_tree_loop_vectorize
975 && OPTION_SET_P (flag_tree_loop_vectorize
)))
978 auto_vector_modes modes
;
979 targetm
.vectorize
.autovectorize_vector_modes (&modes
, true);
980 if (!modes
.is_empty ())
983 for (unsigned int i
= 0; i
< modes
.length (); ++i
)
984 /* The returned modes use the smallest element size (and thus
985 the largest nunits) for the vectorization approach that they
987 vf
= ordered_max (vf
, GET_MODE_NUNITS (modes
[i
]));
991 machine_mode vqimode
= targetm
.vectorize
.preferred_simd_mode (QImode
);
992 if (GET_MODE_CLASS (vqimode
) == MODE_VECTOR_INT
)
993 return GET_MODE_NUNITS (vqimode
);
998 /* Return maximum SIMT width if offloading may target SIMT hardware. */
1001 omp_max_simt_vf (void)
1005 if (ENABLE_OFFLOADING
)
1006 for (const char *c
= getenv ("OFFLOAD_TARGET_NAMES"); c
;)
1008 if (startswith (c
, "nvptx"))
1010 else if ((c
= strchr (c
, ':')))
1016 /* Store the construct selectors as tree codes from last to first,
1017 return their number. */
1020 omp_constructor_traits_to_codes (tree ctx
, enum tree_code
*constructs
)
1022 int nconstructs
= list_length (ctx
);
1023 int i
= nconstructs
- 1;
1024 for (tree t2
= ctx
; t2
; t2
= TREE_CHAIN (t2
), i
--)
1026 const char *sel
= IDENTIFIER_POINTER (TREE_PURPOSE (t2
));
1027 if (!strcmp (sel
, "target"))
1028 constructs
[i
] = OMP_TARGET
;
1029 else if (!strcmp (sel
, "teams"))
1030 constructs
[i
] = OMP_TEAMS
;
1031 else if (!strcmp (sel
, "parallel"))
1032 constructs
[i
] = OMP_PARALLEL
;
1033 else if (!strcmp (sel
, "for") || !strcmp (sel
, "do"))
1034 constructs
[i
] = OMP_FOR
;
1035 else if (!strcmp (sel
, "simd"))
1036 constructs
[i
] = OMP_SIMD
;
1040 gcc_assert (i
== -1);
1044 /* Return true if PROP is possibly present in one of the offloading target's
1045 OpenMP contexts. The format of PROPS string is always offloading target's
1046 name terminated by '\0', followed by properties for that offloading
1047 target separated by '\0' and terminated by another '\0'. The strings
1048 are created from omp-device-properties installed files of all configured
1049 offloading targets. */
1052 omp_offload_device_kind_arch_isa (const char *props
, const char *prop
)
1054 const char *names
= getenv ("OFFLOAD_TARGET_NAMES");
1055 if (names
== NULL
|| *names
== '\0')
1057 while (*props
!= '\0')
1059 size_t name_len
= strlen (props
);
1060 bool matches
= false;
1061 for (const char *c
= names
; c
; )
1063 if (strncmp (props
, c
, name_len
) == 0
1064 && (c
[name_len
] == '\0'
1065 || c
[name_len
] == ':'
1066 || c
[name_len
] == '='))
1071 else if ((c
= strchr (c
, ':')))
1074 props
= props
+ name_len
+ 1;
1075 while (*props
!= '\0')
1077 if (matches
&& strcmp (props
, prop
) == 0)
1079 props
= strchr (props
, '\0') + 1;
1086 /* Return true if the current code location is or might be offloaded.
1087 Return true in declare target functions, or when nested in a target
1088 region or when unsure, return false otherwise. */
1091 omp_maybe_offloaded (void)
1093 if (!ENABLE_OFFLOADING
)
1095 const char *names
= getenv ("OFFLOAD_TARGET_NAMES");
1096 if (names
== NULL
|| *names
== '\0')
1099 if (symtab
->state
== PARSING
)
1102 if (cfun
&& cfun
->after_inlining
)
1104 if (current_function_decl
1105 && lookup_attribute ("omp declare target",
1106 DECL_ATTRIBUTES (current_function_decl
)))
1108 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) == 0)
1110 enum tree_code construct
= OMP_TARGET
;
1111 if (omp_construct_selector_matches (&construct
, 1, NULL
))
1118 /* Diagnose errors in an OpenMP context selector, return CTX if
1119 it is correct or error_mark_node otherwise. */
1122 omp_check_context_selector (location_t loc
, tree ctx
)
1124 /* Each trait-set-selector-name can only be specified once.
1125 There are just 4 set names. */
1126 for (tree t1
= ctx
; t1
; t1
= TREE_CHAIN (t1
))
1127 for (tree t2
= TREE_CHAIN (t1
); t2
; t2
= TREE_CHAIN (t2
))
1128 if (TREE_PURPOSE (t1
) == TREE_PURPOSE (t2
))
1130 error_at (loc
, "selector set %qs specified more than once",
1131 IDENTIFIER_POINTER (TREE_PURPOSE (t1
)));
1132 return error_mark_node
;
1134 for (tree t
= ctx
; t
; t
= TREE_CHAIN (t
))
1136 /* Each trait-selector-name can only be specified once. */
1137 if (list_length (TREE_VALUE (t
)) < 5)
1139 for (tree t1
= TREE_VALUE (t
); t1
; t1
= TREE_CHAIN (t1
))
1140 for (tree t2
= TREE_CHAIN (t1
); t2
; t2
= TREE_CHAIN (t2
))
1141 if (TREE_PURPOSE (t1
) == TREE_PURPOSE (t2
))
1144 "selector %qs specified more than once in set %qs",
1145 IDENTIFIER_POINTER (TREE_PURPOSE (t1
)),
1146 IDENTIFIER_POINTER (TREE_PURPOSE (t
)));
1147 return error_mark_node
;
1152 hash_set
<tree
> pset
;
1153 for (tree t1
= TREE_VALUE (t
); t1
; t1
= TREE_CHAIN (t1
))
1154 if (pset
.add (TREE_PURPOSE (t1
)))
1157 "selector %qs specified more than once in set %qs",
1158 IDENTIFIER_POINTER (TREE_PURPOSE (t1
)),
1159 IDENTIFIER_POINTER (TREE_PURPOSE (t
)));
1160 return error_mark_node
;
1164 static const char *const kind
[] = {
1165 "host", "nohost", "cpu", "gpu", "fpga", "any", NULL
};
1166 static const char *const vendor
[] = {
1167 "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
1168 "llvm", "nvidia", "pgi", "ti", "unknown", NULL
};
1169 static const char *const extension
[] = { NULL
};
1170 static const char *const atomic_default_mem_order
[] = {
1171 "seq_cst", "relaxed", "acq_rel", NULL
};
1172 struct known_properties
{ const char *set
; const char *selector
;
1173 const char *const *props
; };
1174 known_properties props
[] = {
1175 { "device", "kind", kind
},
1176 { "implementation", "vendor", vendor
},
1177 { "implementation", "extension", extension
},
1178 { "implementation", "atomic_default_mem_order",
1179 atomic_default_mem_order
} };
1180 for (tree t1
= TREE_VALUE (t
); t1
; t1
= TREE_CHAIN (t1
))
1181 for (unsigned i
= 0; i
< ARRAY_SIZE (props
); i
++)
1182 if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t1
)),
1184 && !strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t
)),
1186 for (tree t2
= TREE_VALUE (t1
); t2
; t2
= TREE_CHAIN (t2
))
1187 for (unsigned j
= 0; ; j
++)
1189 if (props
[i
].props
[j
] == NULL
)
1191 if (TREE_PURPOSE (t2
)
1192 && !strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t2
)),
1195 if (props
[i
].props
== atomic_default_mem_order
)
1198 "incorrect property %qs of %qs selector",
1199 IDENTIFIER_POINTER (TREE_PURPOSE (t2
)),
1200 "atomic_default_mem_order");
1201 return error_mark_node
;
1203 else if (TREE_PURPOSE (t2
))
1205 "unknown property %qs of %qs selector",
1206 IDENTIFIER_POINTER (TREE_PURPOSE (t2
)),
1210 "unknown property %qE of %qs selector",
1211 TREE_VALUE (t2
), props
[i
].selector
);
1214 else if (TREE_PURPOSE (t2
) == NULL_TREE
)
1216 const char *str
= TREE_STRING_POINTER (TREE_VALUE (t2
));
1217 if (!strcmp (str
, props
[i
].props
[j
])
1218 && ((size_t) TREE_STRING_LENGTH (TREE_VALUE (t2
))
1219 == strlen (str
) + (lang_GNU_Fortran () ? 0 : 1)))
1222 else if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t2
)),
1231 /* Register VARIANT as variant of some base function marked with
1232 #pragma omp declare variant. CONSTRUCT is corresponding construct
1236 omp_mark_declare_variant (location_t loc
, tree variant
, tree construct
)
1238 tree attr
= lookup_attribute ("omp declare variant variant",
1239 DECL_ATTRIBUTES (variant
));
1240 if (attr
== NULL_TREE
)
1242 attr
= tree_cons (get_identifier ("omp declare variant variant"),
1243 unshare_expr (construct
),
1244 DECL_ATTRIBUTES (variant
));
1245 DECL_ATTRIBUTES (variant
) = attr
;
1248 if ((TREE_VALUE (attr
) != NULL_TREE
) != (construct
!= NULL_TREE
)
1249 || (construct
!= NULL_TREE
1250 && omp_context_selector_set_compare ("construct", TREE_VALUE (attr
),
1252 error_at (loc
, "%qD used as a variant with incompatible %<construct%> "
1253 "selector sets", variant
);
1257 /* Return a name from PROP, a property in selectors accepting
1261 omp_context_name_list_prop (tree prop
)
1263 if (TREE_PURPOSE (prop
))
1264 return IDENTIFIER_POINTER (TREE_PURPOSE (prop
));
1267 const char *ret
= TREE_STRING_POINTER (TREE_VALUE (prop
));
1268 if ((size_t) TREE_STRING_LENGTH (TREE_VALUE (prop
))
1269 == strlen (ret
) + (lang_GNU_Fortran () ? 0 : 1))
1275 /* Return 1 if context selector matches the current OpenMP context, 0
1276 if it does not and -1 if it is unknown and need to be determined later.
1277 Some properties can be checked right away during parsing (this routine),
1278 others need to wait until the whole TU is parsed, others need to wait until
1279 IPA, others until vectorization. */
1282 omp_context_selector_matches (tree ctx
)
1285 for (tree t1
= ctx
; t1
; t1
= TREE_CHAIN (t1
))
1287 char set
= IDENTIFIER_POINTER (TREE_PURPOSE (t1
))[0];
1290 /* For now, ignore the construct set. While something can be
1291 determined already during parsing, we don't know until end of TU
1292 whether additional constructs aren't added through declare variant
1293 unless "omp declare variant variant" attribute exists already
1294 (so in most of the cases), and we'd need to maintain set of
1295 surrounding OpenMP constructs, which is better handled during
1297 if (symtab
->state
== PARSING
)
1303 enum tree_code constructs
[5];
1305 = omp_constructor_traits_to_codes (TREE_VALUE (t1
), constructs
);
1307 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1309 if (!cfun
->after_inlining
)
1315 for (i
= 0; i
< nconstructs
; ++i
)
1316 if (constructs
[i
] == OMP_SIMD
)
1318 if (i
< nconstructs
)
1323 /* If there is no simd, assume it is ok after IPA,
1324 constructs should have been checked before. */
1328 int r
= omp_construct_selector_matches (constructs
, nconstructs
,
1336 for (tree t2
= TREE_VALUE (t1
); t2
; t2
= TREE_CHAIN (t2
))
1338 const char *sel
= IDENTIFIER_POINTER (TREE_PURPOSE (t2
));
1342 if (set
== 'i' && !strcmp (sel
, "vendor"))
1343 for (tree t3
= TREE_VALUE (t2
); t3
; t3
= TREE_CHAIN (t3
))
1345 const char *prop
= omp_context_name_list_prop (t3
);
1348 if ((!strcmp (prop
, " score") && TREE_PURPOSE (t3
))
1349 || !strcmp (prop
, "gnu"))
1355 if (set
== 'i' && !strcmp (sel
, "extension"))
1356 /* We don't support any extensions right now. */
1360 if (set
== 'i' && !strcmp (sel
, "atomic_default_mem_order"))
1362 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1365 enum omp_memory_order omo
1366 = ((enum omp_memory_order
)
1368 & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER
));
1369 if (omo
== OMP_MEMORY_ORDER_UNSPECIFIED
)
1371 /* We don't know yet, until end of TU. */
1372 if (symtab
->state
== PARSING
)
1378 omo
= OMP_MEMORY_ORDER_RELAXED
;
1380 tree t3
= TREE_VALUE (t2
);
1381 const char *prop
= IDENTIFIER_POINTER (TREE_PURPOSE (t3
));
1382 if (!strcmp (prop
, " score"))
1384 t3
= TREE_CHAIN (t3
);
1385 prop
= IDENTIFIER_POINTER (TREE_PURPOSE (t3
));
1387 if (!strcmp (prop
, "relaxed")
1388 && omo
!= OMP_MEMORY_ORDER_RELAXED
)
1390 else if (!strcmp (prop
, "seq_cst")
1391 && omo
!= OMP_MEMORY_ORDER_SEQ_CST
)
1393 else if (!strcmp (prop
, "acq_rel")
1394 && omo
!= OMP_MEMORY_ORDER_ACQ_REL
)
1397 if (set
== 'd' && !strcmp (sel
, "arch"))
1398 for (tree t3
= TREE_VALUE (t2
); t3
; t3
= TREE_CHAIN (t3
))
1400 const char *arch
= omp_context_name_list_prop (t3
);
1404 if (targetm
.omp
.device_kind_arch_isa
!= NULL
)
1405 r
= targetm
.omp
.device_kind_arch_isa (omp_device_arch
,
1407 if (r
== 0 || (r
== -1 && symtab
->state
!= PARSING
))
1409 /* If we are or might be in a target region or
1410 declare target function, need to take into account
1411 also offloading values. */
1412 if (!omp_maybe_offloaded ())
1414 if (ENABLE_OFFLOADING
)
1416 const char *arches
= omp_offload_device_arch
;
1417 if (omp_offload_device_kind_arch_isa (arches
,
1428 /* If arch matches on the host, it still might not match
1429 in the offloading region. */
1430 else if (omp_maybe_offloaded ())
1435 if (set
== 'i' && !strcmp (sel
, "unified_address"))
1437 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1440 if ((omp_requires_mask
& OMP_REQUIRES_UNIFIED_ADDRESS
) == 0)
1442 if (symtab
->state
== PARSING
)
1449 if (set
== 'i' && !strcmp (sel
, "unified_shared_memory"))
1451 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1454 if ((omp_requires_mask
1455 & OMP_REQUIRES_UNIFIED_SHARED_MEMORY
) == 0)
1457 if (symtab
->state
== PARSING
)
1466 if (set
== 'i' && !strcmp (sel
, "dynamic_allocators"))
1468 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1471 if ((omp_requires_mask
1472 & OMP_REQUIRES_DYNAMIC_ALLOCATORS
) == 0)
1474 if (symtab
->state
== PARSING
)
1483 if (set
== 'i' && !strcmp (sel
, "reverse_offload"))
1485 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1488 if ((omp_requires_mask
& OMP_REQUIRES_REVERSE_OFFLOAD
) == 0)
1490 if (symtab
->state
== PARSING
)
1499 if (set
== 'd' && !strcmp (sel
, "kind"))
1500 for (tree t3
= TREE_VALUE (t2
); t3
; t3
= TREE_CHAIN (t3
))
1502 const char *prop
= omp_context_name_list_prop (t3
);
1505 if (!strcmp (prop
, "any"))
1507 if (!strcmp (prop
, "host"))
1509 #ifdef ACCEL_COMPILER
1512 if (omp_maybe_offloaded ())
1517 if (!strcmp (prop
, "nohost"))
1519 #ifndef ACCEL_COMPILER
1520 if (omp_maybe_offloaded ())
1528 if (targetm
.omp
.device_kind_arch_isa
!= NULL
)
1529 r
= targetm
.omp
.device_kind_arch_isa (omp_device_kind
,
1532 r
= strcmp (prop
, "cpu") == 0;
1533 if (r
== 0 || (r
== -1 && symtab
->state
!= PARSING
))
1535 /* If we are or might be in a target region or
1536 declare target function, need to take into account
1537 also offloading values. */
1538 if (!omp_maybe_offloaded ())
1540 if (ENABLE_OFFLOADING
)
1542 const char *kinds
= omp_offload_device_kind
;
1543 if (omp_offload_device_kind_arch_isa (kinds
, prop
))
1553 /* If kind matches on the host, it still might not match
1554 in the offloading region. */
1555 else if (omp_maybe_offloaded ())
1560 if (set
== 'd' && !strcmp (sel
, "isa"))
1561 for (tree t3
= TREE_VALUE (t2
); t3
; t3
= TREE_CHAIN (t3
))
1563 const char *isa
= omp_context_name_list_prop (t3
);
1567 if (targetm
.omp
.device_kind_arch_isa
!= NULL
)
1568 r
= targetm
.omp
.device_kind_arch_isa (omp_device_isa
,
1570 if (r
== 0 || (r
== -1 && symtab
->state
!= PARSING
))
1572 /* If isa is valid on the target, but not in the
1573 current function and current function has
1574 #pragma omp declare simd on it, some simd clones
1575 might have the isa added later on. */
1577 && targetm
.simd_clone
.compute_vecsize_and_simdlen
1578 && (cfun
== NULL
|| !cfun
->after_inlining
))
1581 = DECL_ATTRIBUTES (current_function_decl
);
1582 if (lookup_attribute ("omp declare simd", attrs
))
1588 /* If we are or might be in a target region or
1589 declare target function, need to take into account
1590 also offloading values. */
1591 if (!omp_maybe_offloaded ())
1593 if (ENABLE_OFFLOADING
)
1595 const char *isas
= omp_offload_device_isa
;
1596 if (omp_offload_device_kind_arch_isa (isas
, isa
))
1606 /* If isa matches on the host, it still might not match
1607 in the offloading region. */
1608 else if (omp_maybe_offloaded ())
1613 if (set
== 'u' && !strcmp (sel
, "condition"))
1614 for (tree t3
= TREE_VALUE (t2
); t3
; t3
= TREE_CHAIN (t3
))
1615 if (TREE_PURPOSE (t3
) == NULL_TREE
)
1617 if (integer_zerop (TREE_VALUE (t3
)))
1619 if (integer_nonzerop (TREE_VALUE (t3
)))
1632 /* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as
1633 in omp_context_selector_set_compare. */
1636 omp_construct_simd_compare (tree clauses1
, tree clauses2
)
1638 if (clauses1
== NULL_TREE
)
1639 return clauses2
== NULL_TREE
? 0 : -1;
1640 if (clauses2
== NULL_TREE
)
1644 struct declare_variant_simd_data
{
1645 bool inbranch
, notinbranch
;
1647 auto_vec
<tree
,16> data_sharing
;
1648 auto_vec
<tree
,16> aligned
;
1649 declare_variant_simd_data ()
1650 : inbranch(false), notinbranch(false), simdlen(NULL_TREE
) {}
1653 for (i
= 0; i
< 2; i
++)
1654 for (tree c
= i
? clauses2
: clauses1
; c
; c
= OMP_CLAUSE_CHAIN (c
))
1657 switch (OMP_CLAUSE_CODE (c
))
1659 case OMP_CLAUSE_INBRANCH
:
1660 data
[i
].inbranch
= true;
1662 case OMP_CLAUSE_NOTINBRANCH
:
1663 data
[i
].notinbranch
= true;
1665 case OMP_CLAUSE_SIMDLEN
:
1666 data
[i
].simdlen
= OMP_CLAUSE_SIMDLEN_EXPR (c
);
1668 case OMP_CLAUSE_UNIFORM
:
1669 case OMP_CLAUSE_LINEAR
:
1670 v
= &data
[i
].data_sharing
;
1672 case OMP_CLAUSE_ALIGNED
:
1673 v
= &data
[i
].aligned
;
1678 unsigned HOST_WIDE_INT argno
= tree_to_uhwi (OMP_CLAUSE_DECL (c
));
1679 if (argno
>= v
->length ())
1680 v
->safe_grow_cleared (argno
+ 1, true);
1683 /* Here, r is used as a bitmask, 2 is set if CLAUSES1 has something
1684 CLAUSES2 doesn't, 1 is set if CLAUSES2 has something CLAUSES1
1685 doesn't. Thus, r == 3 implies return value 2, r == 1 implies
1686 -1, r == 2 implies 1 and r == 0 implies 0. */
1687 if (data
[0].inbranch
!= data
[1].inbranch
)
1688 r
|= data
[0].inbranch
? 2 : 1;
1689 if (data
[0].notinbranch
!= data
[1].notinbranch
)
1690 r
|= data
[0].notinbranch
? 2 : 1;
1691 if (!simple_cst_equal (data
[0].simdlen
, data
[1].simdlen
))
1693 if (data
[0].simdlen
&& data
[1].simdlen
)
1695 r
|= data
[0].simdlen
? 2 : 1;
1697 if (data
[0].data_sharing
.length () < data
[1].data_sharing
.length ()
1698 || data
[0].aligned
.length () < data
[1].aligned
.length ())
1701 FOR_EACH_VEC_ELT (data
[0].data_sharing
, i
, c1
)
1703 c2
= (i
< data
[1].data_sharing
.length ()
1704 ? data
[1].data_sharing
[i
] : NULL_TREE
);
1705 if ((c1
== NULL_TREE
) != (c2
== NULL_TREE
))
1707 r
|= c1
!= NULL_TREE
? 2 : 1;
1710 if (c1
== NULL_TREE
)
1712 if (OMP_CLAUSE_CODE (c1
) != OMP_CLAUSE_CODE (c2
))
1714 if (OMP_CLAUSE_CODE (c1
) != OMP_CLAUSE_LINEAR
)
1716 if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1
)
1717 != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2
))
1719 if (OMP_CLAUSE_LINEAR_KIND (c1
) != OMP_CLAUSE_LINEAR_KIND (c2
))
1721 if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1
),
1722 OMP_CLAUSE_LINEAR_STEP (c2
)))
1725 FOR_EACH_VEC_ELT (data
[0].aligned
, i
, c1
)
1727 c2
= i
< data
[1].aligned
.length () ? data
[1].aligned
[i
] : NULL_TREE
;
1728 if ((c1
== NULL_TREE
) != (c2
== NULL_TREE
))
1730 r
|= c1
!= NULL_TREE
? 2 : 1;
1733 if (c1
== NULL_TREE
)
1735 if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1
),
1736 OMP_CLAUSE_ALIGNED_ALIGNMENT (c2
)))
1745 default: gcc_unreachable ();
1749 /* Compare properties of selectors SEL from SET other than construct.
1750 Return 0/-1/1/2 as in omp_context_selector_set_compare.
1751 Unlike set names or selector names, properties can have duplicates. */
1754 omp_context_selector_props_compare (const char *set
, const char *sel
,
1755 tree ctx1
, tree ctx2
)
1758 for (int pass
= 0; pass
< 2; pass
++)
1759 for (tree t1
= pass
? ctx2
: ctx1
; t1
; t1
= TREE_CHAIN (t1
))
1762 for (t2
= pass
? ctx1
: ctx2
; t2
; t2
= TREE_CHAIN (t2
))
1763 if (TREE_PURPOSE (t1
) == TREE_PURPOSE (t2
))
1765 if (TREE_PURPOSE (t1
) == NULL_TREE
)
1767 if (set
[0] == 'u' && strcmp (sel
, "condition") == 0)
1769 if (integer_zerop (TREE_VALUE (t1
))
1770 != integer_zerop (TREE_VALUE (t2
)))
1774 if (simple_cst_equal (TREE_VALUE (t1
), TREE_VALUE (t2
)))
1777 else if (strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t1
)),
1780 if (!simple_cst_equal (TREE_VALUE (t1
), TREE_VALUE (t2
)))
1787 else if (TREE_PURPOSE (t1
)
1788 && TREE_PURPOSE (t2
) == NULL_TREE
1789 && TREE_CODE (TREE_VALUE (t2
)) == STRING_CST
)
1791 const char *p1
= omp_context_name_list_prop (t1
);
1792 const char *p2
= omp_context_name_list_prop (t2
);
1794 && strcmp (p1
, p2
) == 0
1795 && strcmp (p1
, " score"))
1798 else if (TREE_PURPOSE (t1
) == NULL_TREE
1799 && TREE_PURPOSE (t2
)
1800 && TREE_CODE (TREE_VALUE (t1
)) == STRING_CST
)
1802 const char *p1
= omp_context_name_list_prop (t1
);
1803 const char *p2
= omp_context_name_list_prop (t2
);
1805 && strcmp (p1
, p2
) == 0
1806 && strcmp (p1
, " score"))
1809 if (t2
== NULL_TREE
)
1811 int r
= pass
? -1 : 1;
1812 if (ret
&& ret
!= r
)
1826 /* Compare single context selector sets CTX1 and CTX2 with SET name.
1827 Return 0 if CTX1 is equal to CTX2,
1828 -1 if CTX1 is a strict subset of CTX2,
1829 1 if CTX2 is a strict subset of CTX1, or
1830 2 if neither context is a subset of another one. */
1833 omp_context_selector_set_compare (const char *set
, tree ctx1
, tree ctx2
)
1835 bool swapped
= false;
1837 int len1
= list_length (ctx1
);
1838 int len2
= list_length (ctx2
);
1843 std::swap (ctx1
, ctx2
);
1844 std::swap (len1
, len2
);
1850 tree simd
= get_identifier ("simd");
1851 /* Handle construct set specially. In this case the order
1852 of the selector matters too. */
1853 for (t1
= ctx1
; t1
; t1
= TREE_CHAIN (t1
))
1854 if (TREE_PURPOSE (t1
) == TREE_PURPOSE (t2
))
1857 if (TREE_PURPOSE (t1
) == simd
)
1858 r
= omp_construct_simd_compare (TREE_VALUE (t1
),
1860 if (r
== 2 || (ret
&& r
&& (ret
< 0) != (r
< 0)))
1864 t2
= TREE_CHAIN (t2
);
1865 if (t2
== NULL_TREE
)
1867 t1
= TREE_CHAIN (t1
);
1875 if (t2
!= NULL_TREE
)
1877 if (t1
!= NULL_TREE
)
1885 return swapped
? -ret
: ret
;
1887 for (tree t1
= ctx1
; t1
; t1
= TREE_CHAIN (t1
))
1890 for (t2
= ctx2
; t2
; t2
= TREE_CHAIN (t2
))
1891 if (TREE_PURPOSE (t1
) == TREE_PURPOSE (t2
))
1893 const char *sel
= IDENTIFIER_POINTER (TREE_PURPOSE (t1
));
1894 int r
= omp_context_selector_props_compare (set
, sel
,
1897 if (r
== 2 || (ret
&& r
&& (ret
< 0) != (r
< 0)))
1904 if (t2
== NULL_TREE
)
1915 return swapped
? -ret
: ret
;
1918 /* Compare whole context selector specification CTX1 and CTX2.
1919 Return 0 if CTX1 is equal to CTX2,
1920 -1 if CTX1 is a strict subset of CTX2,
1921 1 if CTX2 is a strict subset of CTX1, or
1922 2 if neither context is a subset of another one. */
1925 omp_context_selector_compare (tree ctx1
, tree ctx2
)
1927 bool swapped
= false;
1929 int len1
= list_length (ctx1
);
1930 int len2
= list_length (ctx2
);
1935 std::swap (ctx1
, ctx2
);
1936 std::swap (len1
, len2
);
1938 for (tree t1
= ctx1
; t1
; t1
= TREE_CHAIN (t1
))
1941 for (t2
= ctx2
; t2
; t2
= TREE_CHAIN (t2
))
1942 if (TREE_PURPOSE (t1
) == TREE_PURPOSE (t2
))
1944 const char *set
= IDENTIFIER_POINTER (TREE_PURPOSE (t1
));
1945 int r
= omp_context_selector_set_compare (set
, TREE_VALUE (t1
),
1947 if (r
== 2 || (ret
&& r
&& (ret
< 0) != (r
< 0)))
1954 if (t2
== NULL_TREE
)
1965 return swapped
? -ret
: ret
;
1968 /* From context selector CTX, return trait-selector with name SEL in
1969 trait-selector-set with name SET if any, or NULL_TREE if not found.
1970 If SEL is NULL, return the list of trait-selectors in SET. */
1973 omp_get_context_selector (tree ctx
, const char *set
, const char *sel
)
1975 tree setid
= get_identifier (set
);
1976 tree selid
= sel
? get_identifier (sel
) : NULL_TREE
;
1977 for (tree t1
= ctx
; t1
; t1
= TREE_CHAIN (t1
))
1978 if (TREE_PURPOSE (t1
) == setid
)
1981 return TREE_VALUE (t1
);
1982 for (tree t2
= TREE_VALUE (t1
); t2
; t2
= TREE_CHAIN (t2
))
1983 if (TREE_PURPOSE (t2
) == selid
)
1989 /* Compute *SCORE for context selector CTX. Return true if the score
1990 would be different depending on whether it is a declare simd clone or
1991 not. DECLARE_SIMD should be true for the case when it would be
1992 a declare simd clone. */
1995 omp_context_compute_score (tree ctx
, widest_int
*score
, bool declare_simd
)
1997 tree construct
= omp_get_context_selector (ctx
, "construct", NULL
);
1998 bool has_kind
= omp_get_context_selector (ctx
, "device", "kind");
1999 bool has_arch
= omp_get_context_selector (ctx
, "device", "arch");
2000 bool has_isa
= omp_get_context_selector (ctx
, "device", "isa");
2003 for (tree t1
= ctx
; t1
; t1
= TREE_CHAIN (t1
))
2004 if (TREE_VALUE (t1
) != construct
)
2005 for (tree t2
= TREE_VALUE (t1
); t2
; t2
= TREE_CHAIN (t2
))
2006 if (tree t3
= TREE_VALUE (t2
))
2007 if (TREE_PURPOSE (t3
)
2008 && strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t3
)), " score") == 0
2009 && TREE_CODE (TREE_VALUE (t3
)) == INTEGER_CST
)
2010 *score
+= wi::to_widest (TREE_VALUE (t3
));
2011 if (construct
|| has_kind
|| has_arch
|| has_isa
)
2014 enum tree_code constructs
[5];
2015 int nconstructs
= 0;
2017 nconstructs
= omp_constructor_traits_to_codes (construct
, constructs
);
2018 if (omp_construct_selector_matches (constructs
, nconstructs
, scores
)
2021 int b
= declare_simd
? nconstructs
+ 1 : 0;
2022 if (scores
[b
+ nconstructs
] + 4U < score
->get_precision ())
2024 for (int n
= 0; n
< nconstructs
; ++n
)
2026 if (scores
[b
+ n
] < 0)
2031 *score
+= wi::shifted_mask
<widest_int
> (scores
[b
+ n
], 1, false);
2034 *score
+= wi::shifted_mask
<widest_int
> (scores
[b
+ nconstructs
],
2037 *score
+= wi::shifted_mask
<widest_int
> (scores
[b
+ nconstructs
] + 1,
2040 *score
+= wi::shifted_mask
<widest_int
> (scores
[b
+ nconstructs
] + 2,
2043 else /* FIXME: Implement this. */
2049 /* Class describing a single variant. */
2050 struct GTY(()) omp_declare_variant_entry
{
2051 /* NODE of the variant. */
2052 cgraph_node
*variant
;
2053 /* Score if not in declare simd clone. */
2055 /* Score if in declare simd clone. */
2056 widest_int score_in_declare_simd_clone
;
2057 /* Context selector for the variant. */
2059 /* True if the context selector is known to match already. */
2063 /* Class describing a function with variants. */
2064 struct GTY((for_user
)) omp_declare_variant_base_entry
{
2065 /* NODE of the base function. */
2067 /* NODE of the artificial function created for the deferred variant
2070 /* Vector of the variants. */
2071 vec
<omp_declare_variant_entry
, va_gc
> *variants
;
2074 struct omp_declare_variant_hasher
2075 : ggc_ptr_hash
<omp_declare_variant_base_entry
> {
2076 static hashval_t
hash (omp_declare_variant_base_entry
*);
2077 static bool equal (omp_declare_variant_base_entry
*,
2078 omp_declare_variant_base_entry
*);
2082 omp_declare_variant_hasher::hash (omp_declare_variant_base_entry
*x
)
2084 inchash::hash hstate
;
2085 hstate
.add_int (DECL_UID (x
->base
->decl
));
2086 hstate
.add_int (x
->variants
->length ());
2087 omp_declare_variant_entry
*variant
;
2089 FOR_EACH_VEC_SAFE_ELT (x
->variants
, i
, variant
)
2091 hstate
.add_int (DECL_UID (variant
->variant
->decl
));
2092 hstate
.add_wide_int (variant
->score
);
2093 hstate
.add_wide_int (variant
->score_in_declare_simd_clone
);
2094 hstate
.add_ptr (variant
->ctx
);
2095 hstate
.add_int (variant
->matches
);
2097 return hstate
.end ();
2101 omp_declare_variant_hasher::equal (omp_declare_variant_base_entry
*x
,
2102 omp_declare_variant_base_entry
*y
)
2104 if (x
->base
!= y
->base
2105 || x
->variants
->length () != y
->variants
->length ())
2107 omp_declare_variant_entry
*variant
;
2109 FOR_EACH_VEC_SAFE_ELT (x
->variants
, i
, variant
)
2110 if (variant
->variant
!= (*y
->variants
)[i
].variant
2111 || variant
->score
!= (*y
->variants
)[i
].score
2112 || (variant
->score_in_declare_simd_clone
2113 != (*y
->variants
)[i
].score_in_declare_simd_clone
)
2114 || variant
->ctx
!= (*y
->variants
)[i
].ctx
2115 || variant
->matches
!= (*y
->variants
)[i
].matches
)
2120 static GTY(()) hash_table
<omp_declare_variant_hasher
> *omp_declare_variants
;
2122 struct omp_declare_variant_alt_hasher
2123 : ggc_ptr_hash
<omp_declare_variant_base_entry
> {
2124 static hashval_t
hash (omp_declare_variant_base_entry
*);
2125 static bool equal (omp_declare_variant_base_entry
*,
2126 omp_declare_variant_base_entry
*);
2130 omp_declare_variant_alt_hasher::hash (omp_declare_variant_base_entry
*x
)
2132 return DECL_UID (x
->node
->decl
);
2136 omp_declare_variant_alt_hasher::equal (omp_declare_variant_base_entry
*x
,
2137 omp_declare_variant_base_entry
*y
)
2139 return x
->node
== y
->node
;
2142 static GTY(()) hash_table
<omp_declare_variant_alt_hasher
>
2143 *omp_declare_variant_alt
;
2145 /* Try to resolve declare variant after gimplification. */
2148 omp_resolve_late_declare_variant (tree alt
)
2150 cgraph_node
*node
= cgraph_node::get (alt
);
2151 cgraph_node
*cur_node
= cgraph_node::get (cfun
->decl
);
2153 || !node
->declare_variant_alt
2154 || !cfun
->after_inlining
)
2157 omp_declare_variant_base_entry entry
;
2160 entry
.variants
= NULL
;
2161 omp_declare_variant_base_entry
*entryp
2162 = omp_declare_variant_alt
->find_with_hash (&entry
, DECL_UID (alt
));
2165 omp_declare_variant_entry
*varentry1
, *varentry2
;
2166 auto_vec
<bool, 16> matches
;
2167 unsigned int nmatches
= 0;
2168 FOR_EACH_VEC_SAFE_ELT (entryp
->variants
, i
, varentry1
)
2170 if (varentry1
->matches
)
2172 /* This has been checked to be ok already. */
2173 matches
.safe_push (true);
2177 switch (omp_context_selector_matches (varentry1
->ctx
))
2180 matches
.safe_push (false);
2185 matches
.safe_push (true);
2192 return entryp
->base
->decl
;
2194 /* A context selector that is a strict subset of another context selector
2195 has a score of zero. */
2196 FOR_EACH_VEC_SAFE_ELT (entryp
->variants
, i
, varentry1
)
2200 vec_safe_iterate (entryp
->variants
, j
, &varentry2
); ++j
)
2203 int r
= omp_context_selector_compare (varentry1
->ctx
,
2207 /* ctx1 is a strict subset of ctx2, ignore ctx1. */
2212 /* ctx2 is a strict subset of ctx1, remove ctx2. */
2217 widest_int max_score
= -1;
2219 FOR_EACH_VEC_SAFE_ELT (entryp
->variants
, i
, varentry1
)
2223 = (cur_node
->simdclone
? varentry1
->score_in_declare_simd_clone
2224 : varentry1
->score
);
2225 if (score
> max_score
)
2228 varentry2
= varentry1
;
2231 return varentry2
->variant
->decl
;
2234 /* Hook to adjust hash tables on cgraph_node removal. */
2237 omp_declare_variant_remove_hook (struct cgraph_node
*node
, void *)
2239 if (!node
->declare_variant_alt
)
2242 /* Drop this hash table completely. */
2243 omp_declare_variants
= NULL
;
2244 /* And remove node from the other hash table. */
2245 if (omp_declare_variant_alt
)
2247 omp_declare_variant_base_entry entry
;
2250 entry
.variants
= NULL
;
2251 omp_declare_variant_alt
->remove_elt_with_hash (&entry
,
2252 DECL_UID (node
->decl
));
2256 /* Try to resolve declare variant, return the variant decl if it should
2257 be used instead of base, or base otherwise. */
2260 omp_resolve_declare_variant (tree base
)
2262 tree variant1
= NULL_TREE
, variant2
= NULL_TREE
;
2263 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
2264 return omp_resolve_late_declare_variant (base
);
2266 auto_vec
<tree
, 16> variants
;
2267 auto_vec
<bool, 16> defer
;
2268 bool any_deferred
= false;
2269 for (tree attr
= DECL_ATTRIBUTES (base
); attr
; attr
= TREE_CHAIN (attr
))
2271 attr
= lookup_attribute ("omp declare variant base", attr
);
2272 if (attr
== NULL_TREE
)
2274 if (TREE_CODE (TREE_PURPOSE (TREE_VALUE (attr
))) != FUNCTION_DECL
)
2276 cgraph_node
*node
= cgraph_node::get (base
);
2277 /* If this is already a magic decl created by this function,
2278 don't process it again. */
2279 if (node
&& node
->declare_variant_alt
)
2281 switch (omp_context_selector_matches (TREE_VALUE (TREE_VALUE (attr
))))
2284 /* No match, ignore. */
2287 /* Needs to be deferred. */
2288 any_deferred
= true;
2289 variants
.safe_push (attr
);
2290 defer
.safe_push (true);
2293 variants
.safe_push (attr
);
2294 defer
.safe_push (false);
2298 if (variants
.length () == 0)
2303 widest_int max_score1
= 0;
2304 widest_int max_score2
= 0;
2308 omp_declare_variant_base_entry entry
;
2309 entry
.base
= cgraph_node::get_create (base
);
2311 vec_alloc (entry
.variants
, variants
.length ());
2312 FOR_EACH_VEC_ELT (variants
, i
, attr1
)
2317 tree ctx
= TREE_VALUE (TREE_VALUE (attr1
));
2318 need_two
= omp_context_compute_score (ctx
, &score1
, false);
2320 omp_context_compute_score (ctx
, &score2
, true);
2326 max_score1
= score1
;
2327 max_score2
= score2
;
2336 if (max_score1
== score1
)
2337 variant1
= NULL_TREE
;
2338 else if (score1
> max_score1
)
2340 max_score1
= score1
;
2341 variant1
= defer
[i
] ? NULL_TREE
: attr1
;
2343 if (max_score2
== score2
)
2344 variant2
= NULL_TREE
;
2345 else if (score2
> max_score2
)
2347 max_score2
= score2
;
2348 variant2
= defer
[i
] ? NULL_TREE
: attr1
;
2351 omp_declare_variant_entry varentry
;
2353 = cgraph_node::get_create (TREE_PURPOSE (TREE_VALUE (attr1
)));
2354 varentry
.score
= score1
;
2355 varentry
.score_in_declare_simd_clone
= score2
;
2357 varentry
.matches
= !defer
[i
];
2358 entry
.variants
->quick_push (varentry
);
2361 /* If there is a clear winner variant with the score which is not
2362 deferred, verify it is not a strict subset of any other context
2363 selector and if it is not, it is the best alternative no matter
2364 whether the others do or don't match. */
2365 if (variant1
&& variant1
== variant2
)
2367 tree ctx1
= TREE_VALUE (TREE_VALUE (variant1
));
2368 FOR_EACH_VEC_ELT (variants
, i
, attr2
)
2370 if (attr2
== variant1
)
2372 tree ctx2
= TREE_VALUE (TREE_VALUE (attr2
));
2373 int r
= omp_context_selector_compare (ctx1
, ctx2
);
2376 /* The winner is a strict subset of ctx2, can't
2378 variant1
= NULL_TREE
;
2384 vec_free (entry
.variants
);
2385 return TREE_PURPOSE (TREE_VALUE (variant1
));
2389 static struct cgraph_node_hook_list
*node_removal_hook_holder
;
2390 if (!node_removal_hook_holder
)
2391 node_removal_hook_holder
2392 = symtab
->add_cgraph_removal_hook (omp_declare_variant_remove_hook
,
2395 if (omp_declare_variants
== NULL
)
2396 omp_declare_variants
2397 = hash_table
<omp_declare_variant_hasher
>::create_ggc (64);
2398 omp_declare_variant_base_entry
**slot
2399 = omp_declare_variants
->find_slot (&entry
, INSERT
);
2402 vec_free (entry
.variants
);
2403 return (*slot
)->node
->decl
;
2406 *slot
= ggc_cleared_alloc
<omp_declare_variant_base_entry
> ();
2407 (*slot
)->base
= entry
.base
;
2408 (*slot
)->node
= entry
.base
;
2409 (*slot
)->variants
= entry
.variants
;
2410 tree alt
= build_decl (DECL_SOURCE_LOCATION (base
), FUNCTION_DECL
,
2411 DECL_NAME (base
), TREE_TYPE (base
));
2412 DECL_ARTIFICIAL (alt
) = 1;
2413 DECL_IGNORED_P (alt
) = 1;
2414 TREE_STATIC (alt
) = 1;
2415 tree attributes
= DECL_ATTRIBUTES (base
);
2416 if (lookup_attribute ("noipa", attributes
) == NULL
)
2418 attributes
= tree_cons (get_identifier ("noipa"), NULL
, attributes
);
2419 if (lookup_attribute ("noinline", attributes
) == NULL
)
2420 attributes
= tree_cons (get_identifier ("noinline"), NULL
,
2422 if (lookup_attribute ("noclone", attributes
) == NULL
)
2423 attributes
= tree_cons (get_identifier ("noclone"), NULL
,
2425 if (lookup_attribute ("no_icf", attributes
) == NULL
)
2426 attributes
= tree_cons (get_identifier ("no_icf"), NULL
,
2429 DECL_ATTRIBUTES (alt
) = attributes
;
2430 DECL_INITIAL (alt
) = error_mark_node
;
2431 (*slot
)->node
= cgraph_node::create (alt
);
2432 (*slot
)->node
->declare_variant_alt
= 1;
2433 (*slot
)->node
->create_reference (entry
.base
, IPA_REF_ADDR
);
2434 omp_declare_variant_entry
*varentry
;
2435 FOR_EACH_VEC_SAFE_ELT (entry
.variants
, i
, varentry
)
2436 (*slot
)->node
->create_reference (varentry
->variant
, IPA_REF_ADDR
);
2437 if (omp_declare_variant_alt
== NULL
)
2438 omp_declare_variant_alt
2439 = hash_table
<omp_declare_variant_alt_hasher
>::create_ggc (64);
2440 *omp_declare_variant_alt
->find_slot_with_hash (*slot
, DECL_UID (alt
),
2445 if (variants
.length () == 1)
2446 return TREE_PURPOSE (TREE_VALUE (variants
[0]));
2448 /* A context selector that is a strict subset of another context selector
2449 has a score of zero. */
2452 FOR_EACH_VEC_ELT (variants
, i
, attr1
)
2455 tree ctx1
= TREE_VALUE (TREE_VALUE (attr1
));
2456 FOR_EACH_VEC_ELT_FROM (variants
, j
, attr2
, i
+ 1)
2459 tree ctx2
= TREE_VALUE (TREE_VALUE (attr2
));
2460 int r
= omp_context_selector_compare (ctx1
, ctx2
);
2463 /* ctx1 is a strict subset of ctx2, remove
2464 attr1 from the vector. */
2465 variants
[i
] = NULL_TREE
;
2469 /* ctx2 is a strict subset of ctx1, remove attr2
2471 variants
[j
] = NULL_TREE
;
2474 widest_int max_score1
= 0;
2475 widest_int max_score2
= 0;
2477 FOR_EACH_VEC_ELT (variants
, i
, attr1
)
2489 ctx
= TREE_VALUE (TREE_VALUE (variant1
));
2490 need_two
= omp_context_compute_score (ctx
, &max_score1
, false);
2492 omp_context_compute_score (ctx
, &max_score2
, true);
2494 max_score2
= max_score1
;
2496 ctx
= TREE_VALUE (TREE_VALUE (attr1
));
2497 need_two
= omp_context_compute_score (ctx
, &score1
, false);
2499 omp_context_compute_score (ctx
, &score2
, true);
2502 if (score1
> max_score1
)
2504 max_score1
= score1
;
2507 if (score2
> max_score2
)
2509 max_score2
= score2
;
2519 /* If there is a disagreement on which variant has the highest score
2520 depending on whether it will be in a declare simd clone or not,
2521 punt for now and defer until after IPA where we will know that. */
2522 return ((variant1
&& variant1
== variant2
)
2523 ? TREE_PURPOSE (TREE_VALUE (variant1
)) : base
);
2527 omp_lto_output_declare_variant_alt (lto_simple_output_block
*ob
,
2529 lto_symtab_encoder_t encoder
)
2531 gcc_assert (node
->declare_variant_alt
);
2533 omp_declare_variant_base_entry entry
;
2536 entry
.variants
= NULL
;
2537 omp_declare_variant_base_entry
*entryp
2538 = omp_declare_variant_alt
->find_with_hash (&entry
, DECL_UID (node
->decl
));
2539 gcc_assert (entryp
);
2541 int nbase
= lto_symtab_encoder_lookup (encoder
, entryp
->base
);
2542 gcc_assert (nbase
!= LCC_NOT_FOUND
);
2543 streamer_write_hwi_stream (ob
->main_stream
, nbase
);
2545 streamer_write_hwi_stream (ob
->main_stream
, entryp
->variants
->length ());
2548 omp_declare_variant_entry
*varentry
;
2549 FOR_EACH_VEC_SAFE_ELT (entryp
->variants
, i
, varentry
)
2551 int nvar
= lto_symtab_encoder_lookup (encoder
, varentry
->variant
);
2552 gcc_assert (nvar
!= LCC_NOT_FOUND
);
2553 streamer_write_hwi_stream (ob
->main_stream
, nvar
);
2555 for (widest_int
*w
= &varentry
->score
; ;
2556 w
= &varentry
->score_in_declare_simd_clone
)
2558 unsigned len
= w
->get_len ();
2559 streamer_write_hwi_stream (ob
->main_stream
, len
);
2560 const HOST_WIDE_INT
*val
= w
->get_val ();
2561 for (unsigned j
= 0; j
< len
; j
++)
2562 streamer_write_hwi_stream (ob
->main_stream
, val
[j
]);
2563 if (w
== &varentry
->score_in_declare_simd_clone
)
2567 HOST_WIDE_INT cnt
= -1;
2568 HOST_WIDE_INT i
= varentry
->matches
? 1 : 0;
2569 for (tree attr
= DECL_ATTRIBUTES (entryp
->base
->decl
);
2570 attr
; attr
= TREE_CHAIN (attr
), i
+= 2)
2572 attr
= lookup_attribute ("omp declare variant base", attr
);
2573 if (attr
== NULL_TREE
)
2576 if (varentry
->ctx
== TREE_VALUE (TREE_VALUE (attr
)))
2583 gcc_assert (cnt
!= -1);
2584 streamer_write_hwi_stream (ob
->main_stream
, cnt
);
2589 omp_lto_input_declare_variant_alt (lto_input_block
*ib
, cgraph_node
*node
,
2590 vec
<symtab_node
*> nodes
)
2592 gcc_assert (node
->declare_variant_alt
);
2593 omp_declare_variant_base_entry
*entryp
2594 = ggc_cleared_alloc
<omp_declare_variant_base_entry
> ();
2595 entryp
->base
= dyn_cast
<cgraph_node
*> (nodes
[streamer_read_hwi (ib
)]);
2596 entryp
->node
= node
;
2597 unsigned int len
= streamer_read_hwi (ib
);
2598 vec_alloc (entryp
->variants
, len
);
2600 for (unsigned int i
= 0; i
< len
; i
++)
2602 omp_declare_variant_entry varentry
;
2604 = dyn_cast
<cgraph_node
*> (nodes
[streamer_read_hwi (ib
)]);
2605 for (widest_int
*w
= &varentry
.score
; ;
2606 w
= &varentry
.score_in_declare_simd_clone
)
2608 unsigned len2
= streamer_read_hwi (ib
);
2609 HOST_WIDE_INT arr
[WIDE_INT_MAX_ELTS
];
2610 gcc_assert (len2
<= WIDE_INT_MAX_ELTS
);
2611 for (unsigned int j
= 0; j
< len2
; j
++)
2612 arr
[j
] = streamer_read_hwi (ib
);
2613 *w
= widest_int::from_array (arr
, len2
, true);
2614 if (w
== &varentry
.score_in_declare_simd_clone
)
2618 HOST_WIDE_INT cnt
= streamer_read_hwi (ib
);
2619 HOST_WIDE_INT j
= 0;
2620 varentry
.ctx
= NULL_TREE
;
2621 varentry
.matches
= (cnt
& 1) ? true : false;
2622 cnt
&= ~HOST_WIDE_INT_1
;
2623 for (tree attr
= DECL_ATTRIBUTES (entryp
->base
->decl
);
2624 attr
; attr
= TREE_CHAIN (attr
), j
+= 2)
2626 attr
= lookup_attribute ("omp declare variant base", attr
);
2627 if (attr
== NULL_TREE
)
2632 varentry
.ctx
= TREE_VALUE (TREE_VALUE (attr
));
2636 gcc_assert (varentry
.ctx
!= NULL_TREE
);
2637 entryp
->variants
->quick_push (varentry
);
2639 if (omp_declare_variant_alt
== NULL
)
2640 omp_declare_variant_alt
2641 = hash_table
<omp_declare_variant_alt_hasher
>::create_ggc (64);
2642 *omp_declare_variant_alt
->find_slot_with_hash (entryp
, DECL_UID (node
->decl
),
2646 /* Encode an oacc launch argument. This matches the GOMP_LAUNCH_PACK
2647 macro on gomp-constants.h. We do not check for overflow. */
2650 oacc_launch_pack (unsigned code
, tree device
, unsigned op
)
2654 res
= build_int_cst (unsigned_type_node
, GOMP_LAUNCH_PACK (code
, 0, op
));
2657 device
= fold_build2 (LSHIFT_EXPR
, unsigned_type_node
,
2658 device
, build_int_cst (unsigned_type_node
,
2659 GOMP_LAUNCH_DEVICE_SHIFT
));
2660 res
= fold_build2 (BIT_IOR_EXPR
, unsigned_type_node
, res
, device
);
2665 /* FIXME: What is the following comment for? */
2666 /* Look for compute grid dimension clauses and convert to an attribute
2667 attached to FN. This permits the target-side code to (a) massage
2668 the dimensions, (b) emit that data and (c) optimize. Non-constant
2669 dimensions are pushed onto ARGS.
2671 The attribute value is a TREE_LIST. A set of dimensions is
2672 represented as a list of INTEGER_CST. Those that are runtime
2673 exprs are represented as an INTEGER_CST of zero.
2675 TODO: Normally the attribute will just contain a single such list. If
2676 however it contains a list of lists, this will represent the use of
2677 device_type. Each member of the outer list is an assoc list of
2678 dimensions, keyed by the device type. The first entry will be the
2679 default. Well, that's the plan. */
2681 /* Replace any existing oacc fn attribute with updated dimensions. */
2683 /* Variant working on a list of attributes. */
2686 oacc_replace_fn_attrib_attr (tree attribs
, tree dims
)
2688 tree ident
= get_identifier (OACC_FN_ATTRIB
);
2690 /* If we happen to be present as the first attrib, drop it. */
2691 if (attribs
&& TREE_PURPOSE (attribs
) == ident
)
2692 attribs
= TREE_CHAIN (attribs
);
2693 return tree_cons (ident
, dims
, attribs
);
2696 /* Variant working on a function decl. */
2699 oacc_replace_fn_attrib (tree fn
, tree dims
)
2701 DECL_ATTRIBUTES (fn
)
2702 = oacc_replace_fn_attrib_attr (DECL_ATTRIBUTES (fn
), dims
);
2705 /* Scan CLAUSES for launch dimensions and attach them to the oacc
2706 function attribute. Push any that are non-constant onto the ARGS
2707 list, along with an appropriate GOMP_LAUNCH_DIM tag. */
2710 oacc_set_fn_attrib (tree fn
, tree clauses
, vec
<tree
> *args
)
2712 /* Must match GOMP_DIM ordering. */
2713 static const omp_clause_code ids
[]
2714 = { OMP_CLAUSE_NUM_GANGS
, OMP_CLAUSE_NUM_WORKERS
,
2715 OMP_CLAUSE_VECTOR_LENGTH
};
2717 tree dims
[GOMP_DIM_MAX
];
2719 tree attr
= NULL_TREE
;
2720 unsigned non_const
= 0;
2722 for (ix
= GOMP_DIM_MAX
; ix
--;)
2724 tree clause
= omp_find_clause (clauses
, ids
[ix
]);
2725 tree dim
= NULL_TREE
;
2728 dim
= OMP_CLAUSE_EXPR (clause
, ids
[ix
]);
2730 if (dim
&& TREE_CODE (dim
) != INTEGER_CST
)
2732 dim
= integer_zero_node
;
2733 non_const
|= GOMP_DIM_MASK (ix
);
2735 attr
= tree_cons (NULL_TREE
, dim
, attr
);
2738 oacc_replace_fn_attrib (fn
, attr
);
2742 /* Push a dynamic argument set. */
2743 args
->safe_push (oacc_launch_pack (GOMP_LAUNCH_DIM
,
2744 NULL_TREE
, non_const
));
2745 for (unsigned ix
= 0; ix
!= GOMP_DIM_MAX
; ix
++)
2746 if (non_const
& GOMP_DIM_MASK (ix
))
2747 args
->safe_push (dims
[ix
]);
2751 /* Verify OpenACC routine clauses.
2753 Returns 0 if FNDECL should be marked with an OpenACC 'routine' directive, 1
2754 if it has already been marked in compatible way, and -1 if incompatible.
2755 Upon returning, the chain of clauses will contain exactly one clause
2756 specifying the level of parallelism. */
2759 oacc_verify_routine_clauses (tree fndecl
, tree
*clauses
, location_t loc
,
2760 const char *routine_str
)
2762 tree c_level
= NULL_TREE
;
2763 tree c_nohost
= NULL_TREE
;
2764 tree c_p
= NULL_TREE
;
2765 for (tree c
= *clauses
; c
; c_p
= c
, c
= OMP_CLAUSE_CHAIN (c
))
2766 switch (OMP_CLAUSE_CODE (c
))
2768 case OMP_CLAUSE_GANG
:
2769 case OMP_CLAUSE_WORKER
:
2770 case OMP_CLAUSE_VECTOR
:
2771 case OMP_CLAUSE_SEQ
:
2772 if (c_level
== NULL_TREE
)
2774 else if (OMP_CLAUSE_CODE (c
) == OMP_CLAUSE_CODE (c_level
))
2776 /* This has already been diagnosed in the front ends. */
2777 /* Drop the duplicate clause. */
2778 gcc_checking_assert (c_p
!= NULL_TREE
);
2779 OMP_CLAUSE_CHAIN (c_p
) = OMP_CLAUSE_CHAIN (c
);
2784 error_at (OMP_CLAUSE_LOCATION (c
),
2785 "%qs specifies a conflicting level of parallelism",
2786 omp_clause_code_name
[OMP_CLAUSE_CODE (c
)]);
2787 inform (OMP_CLAUSE_LOCATION (c_level
),
2788 "... to the previous %qs clause here",
2789 omp_clause_code_name
[OMP_CLAUSE_CODE (c_level
)]);
2790 /* Drop the conflicting clause. */
2791 gcc_checking_assert (c_p
!= NULL_TREE
);
2792 OMP_CLAUSE_CHAIN (c_p
) = OMP_CLAUSE_CHAIN (c
);
2796 case OMP_CLAUSE_NOHOST
:
2797 /* Don't worry about duplicate clauses here. */
2803 if (c_level
== NULL_TREE
)
2805 /* Default to an implicit 'seq' clause. */
2806 c_level
= build_omp_clause (loc
, OMP_CLAUSE_SEQ
);
2807 OMP_CLAUSE_CHAIN (c_level
) = *clauses
;
2810 /* In *clauses, we now have exactly one clause specifying the level of
2814 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl
));
2815 if (attr
!= NULL_TREE
)
2817 /* Diagnose if "#pragma omp declare target" has also been applied. */
2818 if (TREE_VALUE (attr
) == NULL_TREE
)
2820 /* See <https://gcc.gnu.org/PR93465>; the semantics of combining
2821 OpenACC and OpenMP 'target' are not clear. */
2823 "cannot apply %<%s%> to %qD, which has also been"
2824 " marked with an OpenMP 'declare target' directive",
2825 routine_str
, fndecl
);
2830 /* If a "#pragma acc routine" has already been applied, just verify
2831 this one for compatibility. */
2832 /* Collect previous directive's clauses. */
2833 tree c_level_p
= NULL_TREE
;
2834 tree c_nohost_p
= NULL_TREE
;
2835 for (tree c
= TREE_VALUE (attr
); c
; c
= OMP_CLAUSE_CHAIN (c
))
2836 switch (OMP_CLAUSE_CODE (c
))
2838 case OMP_CLAUSE_GANG
:
2839 case OMP_CLAUSE_WORKER
:
2840 case OMP_CLAUSE_VECTOR
:
2841 case OMP_CLAUSE_SEQ
:
2842 gcc_checking_assert (c_level_p
== NULL_TREE
);
2845 case OMP_CLAUSE_NOHOST
:
2846 gcc_checking_assert (c_nohost_p
== NULL_TREE
);
2852 gcc_checking_assert (c_level_p
!= NULL_TREE
);
2853 /* ..., and compare to current directive's, which we've already collected
2857 /* Matching level of parallelism? */
2858 if (OMP_CLAUSE_CODE (c_level
) != OMP_CLAUSE_CODE (c_level_p
))
2861 c_diag_p
= c_level_p
;
2864 /* Matching 'nohost' clauses? */
2865 if ((c_nohost
== NULL_TREE
) != (c_nohost_p
== NULL_TREE
))
2868 c_diag_p
= c_nohost_p
;
2875 if (c_diag
!= NULL_TREE
)
2876 error_at (OMP_CLAUSE_LOCATION (c_diag
),
2877 "incompatible %qs clause when applying"
2878 " %<%s%> to %qD, which has already been"
2879 " marked with an OpenACC 'routine' directive",
2880 omp_clause_code_name
[OMP_CLAUSE_CODE (c_diag
)],
2881 routine_str
, fndecl
);
2882 else if (c_diag_p
!= NULL_TREE
)
2884 "missing %qs clause when applying"
2885 " %<%s%> to %qD, which has already been"
2886 " marked with an OpenACC 'routine' directive",
2887 omp_clause_code_name
[OMP_CLAUSE_CODE (c_diag_p
)],
2888 routine_str
, fndecl
);
2891 if (c_diag_p
!= NULL_TREE
)
2892 inform (OMP_CLAUSE_LOCATION (c_diag_p
),
2893 "... with %qs clause here",
2894 omp_clause_code_name
[OMP_CLAUSE_CODE (c_diag_p
)]);
2897 /* In the front ends, we don't preserve location information for the
2898 OpenACC routine directive itself. However, that of c_level_p
2900 location_t loc_routine
= OMP_CLAUSE_LOCATION (c_level_p
);
2901 inform (loc_routine
, "... without %qs clause near to here",
2902 omp_clause_code_name
[OMP_CLAUSE_CODE (c_diag
)]);
2911 /* Process the OpenACC 'routine' directive clauses to generate an attribute
2912 for the level of parallelism. All dimensions have a size of zero
2913 (dynamic). TREE_PURPOSE is set to indicate whether that dimension
2914 can have a loop partitioned on it. non-zero indicates
2915 yes, zero indicates no. By construction once a non-zero has been
2916 reached, further inner dimensions must also be non-zero. We set
2917 TREE_VALUE to zero for the dimensions that may be partitioned and
2918 1 for the other ones -- if a loop is (erroneously) spawned at
2919 an outer level, we don't want to try and partition it. */
2922 oacc_build_routine_dims (tree clauses
)
2924 /* Must match GOMP_DIM ordering. */
2925 static const omp_clause_code ids
[]
2926 = {OMP_CLAUSE_GANG
, OMP_CLAUSE_WORKER
, OMP_CLAUSE_VECTOR
, OMP_CLAUSE_SEQ
};
2930 for (; clauses
; clauses
= OMP_CLAUSE_CHAIN (clauses
))
2931 for (ix
= GOMP_DIM_MAX
+ 1; ix
--;)
2932 if (OMP_CLAUSE_CODE (clauses
) == ids
[ix
])
2937 gcc_checking_assert (level
>= 0);
2939 tree dims
= NULL_TREE
;
2941 for (ix
= GOMP_DIM_MAX
; ix
--;)
2942 dims
= tree_cons (build_int_cst (boolean_type_node
, ix
>= level
),
2943 build_int_cst (integer_type_node
, ix
< level
), dims
);
2948 /* Retrieve the oacc function attrib and return it. Non-oacc
2949 functions will return NULL. */
2952 oacc_get_fn_attrib (tree fn
)
2954 return lookup_attribute (OACC_FN_ATTRIB
, DECL_ATTRIBUTES (fn
));
2957 /* Return true if FN is an OpenMP or OpenACC offloading function. */
2960 offloading_function_p (tree fn
)
2962 tree attrs
= DECL_ATTRIBUTES (fn
);
2963 return (lookup_attribute ("omp declare target", attrs
)
2964 || lookup_attribute ("omp target entrypoint", attrs
));
2967 /* Extract an oacc execution dimension from FN. FN must be an
2968 offloaded function or routine that has already had its execution
2969 dimensions lowered to the target-specific values. */
2972 oacc_get_fn_dim_size (tree fn
, int axis
)
2974 tree attrs
= oacc_get_fn_attrib (fn
);
2976 gcc_assert (axis
< GOMP_DIM_MAX
);
2978 tree dims
= TREE_VALUE (attrs
);
2980 dims
= TREE_CHAIN (dims
);
2982 int size
= TREE_INT_CST_LOW (TREE_VALUE (dims
));
2987 /* Extract the dimension axis from an IFN_GOACC_DIM_POS or
2988 IFN_GOACC_DIM_SIZE call. */
2991 oacc_get_ifn_dim_arg (const gimple
*stmt
)
2993 gcc_checking_assert (gimple_call_internal_fn (stmt
) == IFN_GOACC_DIM_SIZE
2994 || gimple_call_internal_fn (stmt
) == IFN_GOACC_DIM_POS
);
2995 tree arg
= gimple_call_arg (stmt
, 0);
2996 HOST_WIDE_INT axis
= TREE_INT_CST_LOW (arg
);
2998 gcc_checking_assert (axis
>= 0 && axis
< GOMP_DIM_MAX
);
3002 /* Build COMPONENT_REF and set TREE_THIS_VOLATILE and TREE_READONLY on it
3006 omp_build_component_ref (tree obj
, tree field
)
3008 tree ret
= build3 (COMPONENT_REF
, TREE_TYPE (field
), obj
, field
, NULL
);
3009 if (TREE_THIS_VOLATILE (field
))
3010 TREE_THIS_VOLATILE (ret
) |= 1;
3011 if (TREE_READONLY (field
))
3012 TREE_READONLY (ret
) |= 1;
3016 #include "gt-omp-general.h"