1 /* General types and functions that are useful for processing of OpenMP,
2 OpenACC and similar directives at various stages of compilation.
4 Copyright (C) 2005-2024 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/>. */
24 #include "coretypes.h"
30 #include "diagnostic-core.h"
31 #include "fold-const.h"
32 #include "langhooks.h"
33 #include "omp-general.h"
34 #include "stringpool.h"
38 #include "alloc-pool.h"
39 #include "symbol-summary.h"
40 #include "tree-pass.h"
41 #include "omp-device-properties.h"
42 #include "tree-iterator.h"
43 #include "data-streamer.h"
44 #include "streamer-hooks.h"
46 #include "tree-pretty-print.h"
48 enum omp_requires omp_requires_mask
;
50 /* Find an OMP clause of type KIND within CLAUSES. */
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
119 || TREE_CODE (TREE_TYPE (v
)) == BITINT_TYPE
)
121 if (integer_onep (step
))
122 *cond_code
= LT_EXPR
;
125 gcc_assert (integer_minus_onep (step
));
126 *cond_code
= GT_EXPR
;
131 tree unit
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v
)));
132 gcc_assert (TREE_CODE (unit
) == INTEGER_CST
);
133 if (tree_int_cst_equal (unit
, step
))
134 *cond_code
= LT_EXPR
;
137 gcc_assert (wi::neg (wi::to_widest (unit
))
138 == wi::to_widest (step
));
139 *cond_code
= GT_EXPR
;
146 if (POINTER_TYPE_P (TREE_TYPE (*n2
)))
148 tree unit
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v
)));
149 gcc_assert (TREE_CODE (unit
) == INTEGER_CST
);
150 *n2
= fold_build_pointer_plus_loc (loc
, *n2
, unit
);
153 *n2
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (*n2
), *n2
,
154 build_int_cst (TREE_TYPE (*n2
), 1));
155 *cond_code
= LT_EXPR
;
158 if (POINTER_TYPE_P (TREE_TYPE (*n2
)))
160 tree unit
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v
)));
161 gcc_assert (TREE_CODE (unit
) == INTEGER_CST
);
162 unit
= convert_to_ptrofftype_loc (loc
, unit
);
163 unit
= fold_build1_loc (loc
, NEGATE_EXPR
, TREE_TYPE (unit
),
165 *n2
= fold_build_pointer_plus_loc (loc
, *n2
, unit
);
168 *n2
= fold_build2_loc (loc
, MINUS_EXPR
, TREE_TYPE (*n2
), *n2
,
169 build_int_cst (TREE_TYPE (*n2
), 1));
170 *cond_code
= GT_EXPR
;
177 /* Return the looping step from INCR, extracted from the step of a gimple omp
181 omp_get_for_step_from_incr (location_t loc
, tree incr
)
184 switch (TREE_CODE (incr
))
187 step
= TREE_OPERAND (incr
, 1);
189 case POINTER_PLUS_EXPR
:
190 step
= fold_convert (ssizetype
, TREE_OPERAND (incr
, 1));
193 step
= TREE_OPERAND (incr
, 1);
194 step
= fold_build1_loc (loc
, NEGATE_EXPR
, TREE_TYPE (step
), step
);
202 /* Extract the header elements of parallel loop FOR_STMT and store
206 omp_extract_for_data (gomp_for
*for_stmt
, struct omp_for_data
*fd
,
207 struct omp_for_data_loop
*loops
)
209 tree t
, var
, *collapse_iter
, *collapse_count
;
210 tree count
= NULL_TREE
, iter_type
= long_integer_type_node
;
211 struct omp_for_data_loop
*loop
;
213 struct omp_for_data_loop dummy_loop
;
214 location_t loc
= gimple_location (for_stmt
);
215 bool simd
= gimple_omp_for_kind (for_stmt
) == GF_OMP_FOR_KIND_SIMD
;
216 bool distribute
= gimple_omp_for_kind (for_stmt
)
217 == GF_OMP_FOR_KIND_DISTRIBUTE
;
218 bool taskloop
= gimple_omp_for_kind (for_stmt
)
219 == GF_OMP_FOR_KIND_TASKLOOP
;
220 bool order_reproducible
= false;
223 fd
->for_stmt
= for_stmt
;
225 fd
->have_nowait
= distribute
|| simd
;
226 fd
->have_ordered
= false;
227 fd
->have_reductemp
= false;
228 fd
->have_pointer_condtemp
= false;
229 fd
->have_scantemp
= false;
230 fd
->have_nonctrl_scantemp
= false;
231 fd
->non_rect
= false;
232 fd
->lastprivate_conditional
= 0;
233 fd
->tiling
= NULL_TREE
;
236 fd
->first_nonrect
= -1;
237 fd
->last_nonrect
= -1;
238 fd
->sched_kind
= OMP_CLAUSE_SCHEDULE_STATIC
;
239 fd
->sched_modifiers
= 0;
240 fd
->chunk_size
= NULL_TREE
;
241 fd
->simd_schedule
= false;
242 fd
->first_inner_iterations
= NULL_TREE
;
243 fd
->factor
= NULL_TREE
;
244 fd
->adjn1
= NULL_TREE
;
245 collapse_iter
= NULL
;
246 collapse_count
= NULL
;
248 for (t
= gimple_omp_for_clauses (for_stmt
); t
; t
= OMP_CLAUSE_CHAIN (t
))
249 switch (OMP_CLAUSE_CODE (t
))
251 case OMP_CLAUSE_NOWAIT
:
252 fd
->have_nowait
= true;
254 case OMP_CLAUSE_ORDERED
:
255 fd
->have_ordered
= true;
256 if (OMP_CLAUSE_ORDERED_DOACROSS (t
))
258 if (OMP_CLAUSE_ORDERED_EXPR (t
))
259 fd
->ordered
= tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t
));
264 case OMP_CLAUSE_SCHEDULE
:
265 gcc_assert (!distribute
&& !taskloop
);
267 = (enum omp_clause_schedule_kind
)
268 (OMP_CLAUSE_SCHEDULE_KIND (t
) & OMP_CLAUSE_SCHEDULE_MASK
);
269 fd
->sched_modifiers
= (OMP_CLAUSE_SCHEDULE_KIND (t
)
270 & ~OMP_CLAUSE_SCHEDULE_MASK
);
271 fd
->chunk_size
= OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t
);
272 fd
->simd_schedule
= OMP_CLAUSE_SCHEDULE_SIMD (t
);
274 case OMP_CLAUSE_DIST_SCHEDULE
:
275 gcc_assert (distribute
);
276 fd
->chunk_size
= OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t
);
278 case OMP_CLAUSE_COLLAPSE
:
279 fd
->collapse
= tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t
));
280 if (fd
->collapse
> 1)
282 collapse_iter
= &OMP_CLAUSE_COLLAPSE_ITERVAR (t
);
283 collapse_count
= &OMP_CLAUSE_COLLAPSE_COUNT (t
);
286 case OMP_CLAUSE_TILE
:
287 fd
->tiling
= OMP_CLAUSE_TILE_LIST (t
);
288 fd
->collapse
= list_length (fd
->tiling
);
289 gcc_assert (fd
->collapse
);
290 collapse_iter
= &OMP_CLAUSE_TILE_ITERVAR (t
);
291 collapse_count
= &OMP_CLAUSE_TILE_COUNT (t
);
293 case OMP_CLAUSE__REDUCTEMP_
:
294 fd
->have_reductemp
= true;
296 case OMP_CLAUSE_LASTPRIVATE
:
297 if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (t
))
298 fd
->lastprivate_conditional
++;
300 case OMP_CLAUSE__CONDTEMP_
:
301 if (POINTER_TYPE_P (TREE_TYPE (OMP_CLAUSE_DECL (t
))))
302 fd
->have_pointer_condtemp
= true;
304 case OMP_CLAUSE__SCANTEMP_
:
305 fd
->have_scantemp
= true;
306 if (!OMP_CLAUSE__SCANTEMP__ALLOC (t
)
307 && !OMP_CLAUSE__SCANTEMP__CONTROL (t
))
308 fd
->have_nonctrl_scantemp
= true;
310 case OMP_CLAUSE_ORDER
:
311 /* FIXME: For OpenMP 5.2 this should change to
312 if (OMP_CLAUSE_ORDER_REPRODUCIBLE (t))
313 (with the exception of loop construct but that lowers to
314 no schedule/dist_schedule clauses currently). */
315 if (!OMP_CLAUSE_ORDER_UNCONSTRAINED (t
))
316 order_reproducible
= true;
321 if (fd
->ordered
== -1)
322 fd
->ordered
= fd
->collapse
;
324 /* For order(reproducible:concurrent) schedule ({dynamic,guided,runtime})
325 we have either the option to expensively remember at runtime how we've
326 distributed work from first loop and reuse that in following loops with
327 the same number of iterations and schedule, or just force static schedule.
328 OpenMP API calls etc. aren't allowed in order(concurrent) bodies so
329 users can't observe it easily anyway. */
330 if (order_reproducible
)
331 fd
->sched_kind
= OMP_CLAUSE_SCHEDULE_STATIC
;
332 if (fd
->collapse
> 1 || fd
->tiling
)
335 fd
->loops
= &fd
->loop
;
337 if (fd
->ordered
&& fd
->collapse
== 1 && loops
!= NULL
)
342 collapse_iter
= &iterv
;
343 collapse_count
= &countv
;
346 /* FIXME: for now map schedule(auto) to schedule(static).
347 There should be analysis to determine whether all iterations
348 are approximately the same amount of work (then schedule(static)
349 is best) or if it varies (then schedule(dynamic,N) is better). */
350 if (fd
->sched_kind
== OMP_CLAUSE_SCHEDULE_AUTO
)
352 fd
->sched_kind
= OMP_CLAUSE_SCHEDULE_STATIC
;
353 gcc_assert (fd
->chunk_size
== NULL
);
355 gcc_assert ((fd
->collapse
== 1 && !fd
->tiling
) || collapse_iter
!= NULL
);
357 fd
->sched_kind
= OMP_CLAUSE_SCHEDULE_RUNTIME
;
358 if (fd
->sched_kind
== OMP_CLAUSE_SCHEDULE_RUNTIME
)
359 gcc_assert (fd
->chunk_size
== NULL
);
360 else if (fd
->chunk_size
== NULL
)
362 /* We only need to compute a default chunk size for ordered
363 static loops and dynamic loops. */
364 if (fd
->sched_kind
!= OMP_CLAUSE_SCHEDULE_STATIC
366 fd
->chunk_size
= (fd
->sched_kind
== OMP_CLAUSE_SCHEDULE_STATIC
)
367 ? integer_zero_node
: integer_one_node
;
370 int cnt
= fd
->ordered
? fd
->ordered
: fd
->collapse
;
371 int single_nonrect
= -1;
372 tree single_nonrect_count
= NULL_TREE
;
373 enum tree_code single_nonrect_cond_code
= ERROR_MARK
;
374 for (i
= 1; i
< cnt
; i
++)
376 tree n1
= gimple_omp_for_initial (for_stmt
, i
);
377 tree n2
= gimple_omp_for_final (for_stmt
, i
);
378 if (TREE_CODE (n1
) == TREE_VEC
)
385 for (int j
= i
- 1; j
>= 0; j
--)
386 if (TREE_VEC_ELT (n1
, 0) == gimple_omp_for_index (for_stmt
, j
))
393 else if (TREE_CODE (n2
) == TREE_VEC
)
400 for (int j
= i
- 1; j
>= 0; j
--)
401 if (TREE_VEC_ELT (n2
, 0) == gimple_omp_for_index (for_stmt
, j
))
409 for (i
= 0; i
< cnt
; i
++)
414 && (fd
->ordered
== 0 || loops
== NULL
))
416 else if (loops
!= NULL
)
421 loop
->v
= gimple_omp_for_index (for_stmt
, i
);
422 gcc_assert (SSA_VAR_P (loop
->v
));
423 gcc_assert (TREE_CODE (TREE_TYPE (loop
->v
)) == INTEGER_TYPE
424 || TREE_CODE (TREE_TYPE (loop
->v
)) == BITINT_TYPE
425 || TREE_CODE (TREE_TYPE (loop
->v
)) == POINTER_TYPE
);
426 var
= TREE_CODE (loop
->v
) == SSA_NAME
? SSA_NAME_VAR (loop
->v
) : loop
->v
;
427 loop
->n1
= gimple_omp_for_initial (for_stmt
, i
);
428 loop
->m1
= NULL_TREE
;
429 loop
->m2
= NULL_TREE
;
431 loop
->non_rect_referenced
= false;
432 if (TREE_CODE (loop
->n1
) == TREE_VEC
)
434 for (int j
= i
- 1; j
>= 0; j
--)
435 if (TREE_VEC_ELT (loop
->n1
, 0) == gimple_omp_for_index (for_stmt
, j
))
439 loops
[j
].non_rect_referenced
= true;
440 if (fd
->first_nonrect
== -1 || fd
->first_nonrect
> j
)
441 fd
->first_nonrect
= j
;
444 gcc_assert (loop
->outer
);
445 loop
->m1
= TREE_VEC_ELT (loop
->n1
, 1);
446 loop
->n1
= TREE_VEC_ELT (loop
->n1
, 2);
448 fd
->last_nonrect
= i
;
451 loop
->cond_code
= gimple_omp_for_cond (for_stmt
, i
);
452 loop
->n2
= gimple_omp_for_final (for_stmt
, i
);
453 gcc_assert (loop
->cond_code
!= NE_EXPR
454 || (gimple_omp_for_kind (for_stmt
)
455 != GF_OMP_FOR_KIND_OACC_LOOP
));
456 if (TREE_CODE (loop
->n2
) == TREE_VEC
)
459 gcc_assert (TREE_VEC_ELT (loop
->n2
, 0)
460 == gimple_omp_for_index (for_stmt
, i
- loop
->outer
));
462 for (int j
= i
- 1; j
>= 0; j
--)
463 if (TREE_VEC_ELT (loop
->n2
, 0) == gimple_omp_for_index (for_stmt
, j
))
467 loops
[j
].non_rect_referenced
= true;
468 if (fd
->first_nonrect
== -1 || fd
->first_nonrect
> j
)
469 fd
->first_nonrect
= j
;
472 gcc_assert (loop
->outer
);
473 loop
->m2
= TREE_VEC_ELT (loop
->n2
, 1);
474 loop
->n2
= TREE_VEC_ELT (loop
->n2
, 2);
476 fd
->last_nonrect
= i
;
479 t
= gimple_omp_for_incr (for_stmt
, i
);
480 gcc_assert (TREE_OPERAND (t
, 0) == var
);
481 loop
->step
= omp_get_for_step_from_incr (loc
, t
);
483 omp_adjust_for_condition (loc
, &loop
->cond_code
, &loop
->n2
, loop
->v
,
487 || (fd
->sched_kind
== OMP_CLAUSE_SCHEDULE_STATIC
488 && !fd
->have_ordered
))
490 if (fd
->collapse
== 1 && !fd
->tiling
)
491 iter_type
= TREE_TYPE (loop
->v
);
493 || TYPE_PRECISION (iter_type
)
494 < TYPE_PRECISION (TREE_TYPE (loop
->v
)))
496 if (TREE_CODE (iter_type
) == BITINT_TYPE
497 || TREE_CODE (TREE_TYPE (loop
->v
)) == BITINT_TYPE
)
499 = build_bitint_type (TYPE_PRECISION (TREE_TYPE (loop
->v
)),
503 = build_nonstandard_integer_type
504 (TYPE_PRECISION (TREE_TYPE (loop
->v
)), 1);
507 else if (iter_type
!= long_long_unsigned_type_node
)
509 if (POINTER_TYPE_P (TREE_TYPE (loop
->v
)))
510 iter_type
= long_long_unsigned_type_node
;
511 else if (TYPE_UNSIGNED (TREE_TYPE (loop
->v
))
512 && TYPE_PRECISION (TREE_TYPE (loop
->v
))
513 >= TYPE_PRECISION (iter_type
))
517 if (loop
->cond_code
== LT_EXPR
)
518 n
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (loop
->v
),
519 loop
->n2
, loop
->step
);
524 || TREE_CODE (n
) != INTEGER_CST
525 || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type
), n
))
526 iter_type
= long_long_unsigned_type_node
;
528 else if (TYPE_PRECISION (TREE_TYPE (loop
->v
))
529 > TYPE_PRECISION (iter_type
))
533 if (loop
->cond_code
== LT_EXPR
)
536 n2
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (loop
->v
),
537 loop
->n2
, loop
->step
);
541 n1
= fold_build2_loc (loc
, MINUS_EXPR
, TREE_TYPE (loop
->v
),
542 loop
->n2
, loop
->step
);
547 || TREE_CODE (n1
) != INTEGER_CST
548 || TREE_CODE (n2
) != INTEGER_CST
549 || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type
), n1
)
550 || !tree_int_cst_lt (n2
, TYPE_MAX_VALUE (iter_type
)))
551 iter_type
= long_long_unsigned_type_node
;
555 if (i
>= fd
->collapse
)
558 if (collapse_count
&& *collapse_count
== NULL
)
560 if (count
&& integer_zerop (count
))
562 tree n1first
= NULL_TREE
, n2first
= NULL_TREE
;
563 tree n1last
= NULL_TREE
, n2last
= NULL_TREE
;
564 tree ostep
= NULL_TREE
;
565 if (loop
->m1
|| loop
->m2
)
567 if (count
== NULL_TREE
)
569 if (single_nonrect
== -1
570 || (loop
->m1
&& TREE_CODE (loop
->m1
) != INTEGER_CST
)
571 || (loop
->m2
&& TREE_CODE (loop
->m2
) != INTEGER_CST
)
572 || TREE_CODE (loop
->n1
) != INTEGER_CST
573 || TREE_CODE (loop
->n2
) != INTEGER_CST
574 || TREE_CODE (loop
->step
) != INTEGER_CST
)
579 tree var
= gimple_omp_for_initial (for_stmt
, single_nonrect
);
580 tree itype
= TREE_TYPE (var
);
581 tree first
= gimple_omp_for_initial (for_stmt
, single_nonrect
);
582 t
= gimple_omp_for_incr (for_stmt
, single_nonrect
);
583 ostep
= omp_get_for_step_from_incr (loc
, t
);
584 t
= fold_binary (MINUS_EXPR
, long_long_unsigned_type_node
,
585 single_nonrect_count
,
586 build_one_cst (long_long_unsigned_type_node
));
587 t
= fold_convert (itype
, t
);
588 first
= fold_convert (itype
, first
);
589 ostep
= fold_convert (itype
, ostep
);
590 tree last
= fold_binary (PLUS_EXPR
, itype
, first
,
591 fold_binary (MULT_EXPR
, itype
, t
,
593 if (TREE_CODE (first
) != INTEGER_CST
594 || TREE_CODE (last
) != INTEGER_CST
)
601 tree m1
= fold_convert (itype
, loop
->m1
);
602 tree n1
= fold_convert (itype
, loop
->n1
);
603 n1first
= fold_binary (PLUS_EXPR
, itype
,
604 fold_binary (MULT_EXPR
, itype
,
606 n1last
= fold_binary (PLUS_EXPR
, itype
,
607 fold_binary (MULT_EXPR
, itype
,
611 n1first
= n1last
= loop
->n1
;
614 tree n2
= fold_convert (itype
, loop
->n2
);
615 tree m2
= fold_convert (itype
, loop
->m2
);
616 n2first
= fold_binary (PLUS_EXPR
, itype
,
617 fold_binary (MULT_EXPR
, itype
,
619 n2last
= fold_binary (PLUS_EXPR
, itype
,
620 fold_binary (MULT_EXPR
, itype
,
624 n2first
= n2last
= loop
->n2
;
625 n1first
= fold_convert (TREE_TYPE (loop
->v
), n1first
);
626 n2first
= fold_convert (TREE_TYPE (loop
->v
), n2first
);
627 n1last
= fold_convert (TREE_TYPE (loop
->v
), n1last
);
628 n2last
= fold_convert (TREE_TYPE (loop
->v
), n2last
);
629 t
= fold_binary (loop
->cond_code
, boolean_type_node
,
631 tree t2
= fold_binary (loop
->cond_code
, boolean_type_node
,
633 if (t
&& t2
&& integer_nonzerop (t
) && integer_nonzerop (t2
))
634 /* All outer loop iterators have at least one inner loop
635 iteration. Try to compute the count at compile time. */
637 else if (t
&& t2
&& integer_zerop (t
) && integer_zerop (t2
))
638 /* No iterations of the inner loop. count will be set to
640 else if (TYPE_UNSIGNED (itype
)
643 || TREE_CODE (t
) != INTEGER_CST
644 || TREE_CODE (t2
) != INTEGER_CST
)
646 /* Punt (for now). */
652 /* Some iterations of the outer loop have zero iterations
653 of the inner loop, while others have at least one.
654 In this case, we need to adjust one of those outer
655 loop bounds. If ADJ_FIRST, we need to adjust outer n1
656 (first), otherwise outer n2 (last). */
657 bool adj_first
= integer_zerop (t
);
658 tree n1
= fold_convert (itype
, loop
->n1
);
659 tree n2
= fold_convert (itype
, loop
->n2
);
660 tree m1
= loop
->m1
? fold_convert (itype
, loop
->m1
)
661 : build_zero_cst (itype
);
662 tree m2
= loop
->m2
? fold_convert (itype
, loop
->m2
)
663 : build_zero_cst (itype
);
664 t
= fold_binary (MINUS_EXPR
, itype
, n1
, n2
);
665 t2
= fold_binary (MINUS_EXPR
, itype
, m2
, m1
);
666 t
= fold_binary (TRUNC_DIV_EXPR
, itype
, t
, t2
);
667 t2
= fold_binary (MINUS_EXPR
, itype
, t
, first
);
668 t2
= fold_binary (TRUNC_MOD_EXPR
, itype
, t2
, ostep
);
669 t
= fold_binary (MINUS_EXPR
, itype
, t
, t2
);
671 = fold_binary (PLUS_EXPR
, itype
, n1
,
672 fold_binary (MULT_EXPR
, itype
, m1
, t
));
674 = fold_binary (PLUS_EXPR
, itype
, n2
,
675 fold_binary (MULT_EXPR
, itype
, m2
, t
));
676 t2
= fold_binary (loop
->cond_code
, boolean_type_node
,
678 tree t3
= fold_binary (MULT_EXPR
, itype
, m1
, ostep
);
679 tree t4
= fold_binary (MULT_EXPR
, itype
, m2
, ostep
);
684 if (integer_nonzerop (t2
))
691 t3
= fold_binary (MINUS_EXPR
, itype
, n1cur
, t3
);
692 t4
= fold_binary (MINUS_EXPR
, itype
, n2cur
, t4
);
693 t3
= fold_binary (loop
->cond_code
,
694 boolean_type_node
, t3
, t4
);
695 gcc_assert (integer_zerop (t3
));
700 t3
= fold_binary (PLUS_EXPR
, itype
, n1cur
, t3
);
701 t4
= fold_binary (PLUS_EXPR
, itype
, n2cur
, t4
);
702 new_first
= fold_binary (PLUS_EXPR
, itype
, t
, ostep
);
707 t3
= fold_binary (loop
->cond_code
,
708 boolean_type_node
, t3
, t4
);
709 gcc_assert (integer_nonzerop (t3
));
712 diff
= fold_binary (MINUS_EXPR
, itype
, new_first
, first
);
719 if (integer_zerop (t2
))
721 t3
= fold_binary (MINUS_EXPR
, itype
, n1cur
, t3
);
722 t4
= fold_binary (MINUS_EXPR
, itype
, n2cur
, t4
);
723 new_last
= fold_binary (MINUS_EXPR
, itype
, t
, ostep
);
728 t3
= fold_binary (loop
->cond_code
,
729 boolean_type_node
, t3
, t4
);
730 gcc_assert (integer_nonzerop (t3
));
740 t3
= fold_binary (PLUS_EXPR
, itype
, n1cur
, t3
);
741 t4
= fold_binary (PLUS_EXPR
, itype
, n2cur
, t4
);
742 t3
= fold_binary (loop
->cond_code
,
743 boolean_type_node
, t3
, t4
);
744 gcc_assert (integer_zerop (t3
));
747 diff
= fold_binary (MINUS_EXPR
, itype
, last
, new_last
);
749 if (TYPE_UNSIGNED (itype
)
750 && single_nonrect_cond_code
== GT_EXPR
)
751 diff
= fold_binary (TRUNC_DIV_EXPR
, itype
,
752 fold_unary (NEGATE_EXPR
, itype
, diff
),
753 fold_unary (NEGATE_EXPR
, itype
,
756 diff
= fold_binary (TRUNC_DIV_EXPR
, itype
, diff
, ostep
);
757 diff
= fold_convert (long_long_unsigned_type_node
, diff
);
759 = fold_binary (MINUS_EXPR
, long_long_unsigned_type_node
,
760 single_nonrect_count
, diff
);
765 t
= fold_binary (loop
->cond_code
, boolean_type_node
,
766 fold_convert (TREE_TYPE (loop
->v
), loop
->n1
),
767 fold_convert (TREE_TYPE (loop
->v
), loop
->n2
));
768 if (t
&& integer_zerop (t
))
769 count
= build_zero_cst (long_long_unsigned_type_node
);
770 else if ((i
== 0 || count
!= NULL_TREE
)
771 && (TREE_CODE (TREE_TYPE (loop
->v
)) == INTEGER_TYPE
772 || TREE_CODE (TREE_TYPE (loop
->v
)) == BITINT_TYPE
)
773 && TREE_CONSTANT (loop
->n1
)
774 && TREE_CONSTANT (loop
->n2
)
775 && TREE_CODE (loop
->step
) == INTEGER_CST
)
777 tree itype
= TREE_TYPE (loop
->v
);
779 if (POINTER_TYPE_P (itype
))
780 itype
= signed_type_for (itype
);
781 t
= build_int_cst (itype
, (loop
->cond_code
== LT_EXPR
? -1 : 1));
782 t
= fold_build2 (PLUS_EXPR
, itype
,
783 fold_convert (itype
, loop
->step
), t
);
786 if (loop
->m1
|| loop
->m2
)
788 gcc_assert (single_nonrect
!= -1);
792 t
= fold_build2 (PLUS_EXPR
, itype
, t
, fold_convert (itype
, n2
));
793 t
= fold_build2 (MINUS_EXPR
, itype
, t
, fold_convert (itype
, n1
));
794 tree step
= fold_convert_loc (loc
, itype
, loop
->step
);
795 if (TYPE_UNSIGNED (itype
) && loop
->cond_code
== GT_EXPR
)
796 t
= fold_build2 (TRUNC_DIV_EXPR
, itype
,
797 fold_build1 (NEGATE_EXPR
, itype
, t
),
798 fold_build1 (NEGATE_EXPR
, itype
, step
));
800 t
= fold_build2 (TRUNC_DIV_EXPR
, itype
, t
, step
);
801 tree llutype
= long_long_unsigned_type_node
;
802 t
= fold_convert (llutype
, t
);
803 if (loop
->m1
|| loop
->m2
)
805 /* t is number of iterations of inner loop at either first
806 or last value of the outer iterator (the one with fewer
808 Compute t2 = ((m2 - m1) * ostep) / step
809 and niters = outer_count * t
810 + t2 * ((outer_count - 1) * outer_count / 2)
812 tree m1
= loop
->m1
? loop
->m1
: integer_zero_node
;
813 tree m2
= loop
->m2
? loop
->m2
: integer_zero_node
;
814 m1
= fold_convert (itype
, m1
);
815 m2
= fold_convert (itype
, m2
);
816 tree t2
= fold_build2 (MINUS_EXPR
, itype
, m2
, m1
);
817 t2
= fold_build2 (MULT_EXPR
, itype
, t2
, ostep
);
818 if (TYPE_UNSIGNED (itype
) && loop
->cond_code
== GT_EXPR
)
819 t2
= fold_build2 (TRUNC_DIV_EXPR
, itype
,
820 fold_build1 (NEGATE_EXPR
, itype
, t2
),
821 fold_build1 (NEGATE_EXPR
, itype
, step
));
823 t2
= fold_build2 (TRUNC_DIV_EXPR
, itype
, t2
, step
);
824 t2
= fold_convert (llutype
, t2
);
825 fd
->first_inner_iterations
= t
;
827 t
= fold_build2 (MULT_EXPR
, llutype
, t
,
828 single_nonrect_count
);
829 tree t3
= fold_build2 (MINUS_EXPR
, llutype
,
830 single_nonrect_count
,
831 build_one_cst (llutype
));
832 t3
= fold_build2 (MULT_EXPR
, llutype
, t3
,
833 single_nonrect_count
);
834 t3
= fold_build2 (TRUNC_DIV_EXPR
, llutype
, t3
,
835 build_int_cst (llutype
, 2));
836 t2
= fold_build2 (MULT_EXPR
, llutype
, t2
, t3
);
837 t
= fold_build2 (PLUS_EXPR
, llutype
, t
, t2
);
839 if (i
== single_nonrect
)
841 if (integer_zerop (t
) || TREE_CODE (t
) != INTEGER_CST
)
845 single_nonrect_count
= t
;
846 single_nonrect_cond_code
= loop
->cond_code
;
847 if (count
== NULL_TREE
)
848 count
= build_one_cst (llutype
);
851 else if (count
!= NULL_TREE
)
852 count
= fold_build2 (MULT_EXPR
, llutype
, count
, t
);
855 if (TREE_CODE (count
) != INTEGER_CST
)
858 else if (count
&& !integer_zerop (count
))
865 && (fd
->sched_kind
!= OMP_CLAUSE_SCHEDULE_STATIC
866 || fd
->have_ordered
))
868 if (!tree_int_cst_lt (count
, TYPE_MAX_VALUE (long_integer_type_node
)))
869 iter_type
= long_long_unsigned_type_node
;
871 iter_type
= long_integer_type_node
;
873 else if (collapse_iter
&& *collapse_iter
!= NULL
)
874 iter_type
= TREE_TYPE (*collapse_iter
);
875 fd
->iter_type
= iter_type
;
876 if (collapse_iter
&& *collapse_iter
== NULL
)
877 *collapse_iter
= create_tmp_var (iter_type
, ".iter");
878 if (collapse_count
&& *collapse_count
== NULL
)
882 *collapse_count
= fold_convert_loc (loc
, iter_type
, count
);
883 if (fd
->first_inner_iterations
&& fd
->factor
)
885 t
= make_tree_vec (4);
886 TREE_VEC_ELT (t
, 0) = *collapse_count
;
887 TREE_VEC_ELT (t
, 1) = fd
->first_inner_iterations
;
888 TREE_VEC_ELT (t
, 2) = fd
->factor
;
889 TREE_VEC_ELT (t
, 3) = fd
->adjn1
;
894 *collapse_count
= create_tmp_var (iter_type
, ".count");
897 if (fd
->collapse
> 1 || fd
->tiling
|| (fd
->ordered
&& loops
))
899 fd
->loop
.v
= *collapse_iter
;
900 fd
->loop
.n1
= build_int_cst (TREE_TYPE (fd
->loop
.v
), 0);
901 fd
->loop
.n2
= *collapse_count
;
902 if (TREE_CODE (fd
->loop
.n2
) == TREE_VEC
)
904 gcc_assert (fd
->non_rect
);
905 fd
->first_inner_iterations
= TREE_VEC_ELT (fd
->loop
.n2
, 1);
906 fd
->factor
= TREE_VEC_ELT (fd
->loop
.n2
, 2);
907 fd
->adjn1
= TREE_VEC_ELT (fd
->loop
.n2
, 3);
908 fd
->loop
.n2
= TREE_VEC_ELT (fd
->loop
.n2
, 0);
910 fd
->loop
.step
= build_int_cst (TREE_TYPE (fd
->loop
.v
), 1);
911 fd
->loop
.m1
= NULL_TREE
;
912 fd
->loop
.m2
= NULL_TREE
;
914 fd
->loop
.cond_code
= LT_EXPR
;
920 /* Build a call to GOMP_barrier. */
923 omp_build_barrier (tree lhs
)
925 tree fndecl
= builtin_decl_explicit (lhs
? BUILT_IN_GOMP_BARRIER_CANCEL
926 : BUILT_IN_GOMP_BARRIER
);
927 gcall
*g
= gimple_build_call (fndecl
, 0);
929 gimple_call_set_lhs (g
, lhs
);
933 /* Find OMP_FOR resp. OMP_SIMD with non-NULL OMP_FOR_INIT. Also, fill in pdata
934 array, pdata[0] non-NULL if there is anything non-trivial in between,
935 pdata[1] is address of OMP_PARALLEL in between if any, pdata[2] is address
936 of OMP_FOR in between if any and pdata[3] is address of the inner
940 find_combined_omp_for (tree
*tp
, int *walk_subtrees
, void *data
)
942 tree
**pdata
= (tree
**) data
;
944 switch (TREE_CODE (*tp
))
947 if (OMP_FOR_INIT (*tp
) != NULL_TREE
)
956 if (OMP_FOR_INIT (*tp
) != NULL_TREE
)
963 if (BIND_EXPR_VARS (*tp
)
964 || (BIND_EXPR_BLOCK (*tp
)
965 && BLOCK_VARS (BIND_EXPR_BLOCK (*tp
))))
970 if (!tsi_one_before_end_p (tsi_start (*tp
)))
974 case TRY_FINALLY_EXPR
:
975 case CLEANUP_POINT_EXPR
:
989 /* Return maximum possible vectorization factor for the target. */
996 || !flag_tree_loop_optimize
997 || (!flag_tree_loop_vectorize
998 && OPTION_SET_P (flag_tree_loop_vectorize
)))
1001 auto_vector_modes modes
;
1002 targetm
.vectorize
.autovectorize_vector_modes (&modes
, true);
1003 if (!modes
.is_empty ())
1006 for (unsigned int i
= 0; i
< modes
.length (); ++i
)
1007 /* The returned modes use the smallest element size (and thus
1008 the largest nunits) for the vectorization approach that they
1010 vf
= ordered_max (vf
, GET_MODE_NUNITS (modes
[i
]));
1014 machine_mode vqimode
= targetm
.vectorize
.preferred_simd_mode (QImode
);
1015 if (GET_MODE_CLASS (vqimode
) == MODE_VECTOR_INT
)
1016 return GET_MODE_NUNITS (vqimode
);
1021 /* Return maximum SIMT width if offloading may target SIMT hardware. */
1024 omp_max_simt_vf (void)
1028 if (ENABLE_OFFLOADING
)
1029 for (const char *c
= getenv ("OFFLOAD_TARGET_NAMES"); c
;)
1031 if (startswith (c
, "nvptx"))
1033 else if ((c
= strchr (c
, ':')))
1039 /* Store the construct selectors as tree codes from last to first.
1040 CTX is a list of trait selectors, nconstructs must be equal to its
1041 length, and the array CONSTRUCTS holds the output. */
1044 omp_construct_traits_to_codes (tree ctx
, int nconstructs
,
1045 enum tree_code
*constructs
)
1047 int i
= nconstructs
- 1;
1049 /* Order must match the OMP_TRAIT_CONSTRUCT_* enumerators in
1050 enum omp_ts_code. */
1051 static enum tree_code code_map
[]
1052 = { OMP_TARGET
, OMP_TEAMS
, OMP_PARALLEL
, OMP_FOR
, OMP_SIMD
};
1054 for (tree ts
= ctx
; ts
; ts
= TREE_CHAIN (ts
), i
--)
1056 enum omp_ts_code sel
= OMP_TS_CODE (ts
);
1057 int j
= (int)sel
- (int)OMP_TRAIT_CONSTRUCT_TARGET
;
1058 gcc_assert (j
>= 0 && (unsigned int) j
< ARRAY_SIZE (code_map
));
1059 constructs
[i
] = code_map
[j
];
1061 gcc_assert (i
== -1);
1064 /* Return true if PROP is possibly present in one of the offloading target's
1065 OpenMP contexts. The format of PROPS string is always offloading target's
1066 name terminated by '\0', followed by properties for that offloading
1067 target separated by '\0' and terminated by another '\0'. The strings
1068 are created from omp-device-properties installed files of all configured
1069 offloading targets. */
1072 omp_offload_device_kind_arch_isa (const char *props
, const char *prop
)
1074 const char *names
= getenv ("OFFLOAD_TARGET_NAMES");
1075 if (names
== NULL
|| *names
== '\0')
1077 while (*props
!= '\0')
1079 size_t name_len
= strlen (props
);
1080 bool matches
= false;
1081 for (const char *c
= names
; c
; )
1083 if (strncmp (props
, c
, name_len
) == 0
1084 && (c
[name_len
] == '\0'
1085 || c
[name_len
] == ':'
1086 || c
[name_len
] == '='))
1091 else if ((c
= strchr (c
, ':')))
1094 props
= props
+ name_len
+ 1;
1095 while (*props
!= '\0')
1097 if (matches
&& strcmp (props
, prop
) == 0)
1099 props
= strchr (props
, '\0') + 1;
1106 /* Return true if the current code location is or might be offloaded.
1107 Return true in declare target functions, or when nested in a target
1108 region or when unsure, return false otherwise. */
1111 omp_maybe_offloaded (void)
1113 if (!ENABLE_OFFLOADING
)
1115 const char *names
= getenv ("OFFLOAD_TARGET_NAMES");
1116 if (names
== NULL
|| *names
== '\0')
1119 if (symtab
->state
== PARSING
)
1122 if (cfun
&& cfun
->after_inlining
)
1124 if (current_function_decl
1125 && lookup_attribute ("omp declare target",
1126 DECL_ATTRIBUTES (current_function_decl
)))
1128 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) == 0)
1130 enum tree_code construct
= OMP_TARGET
;
1131 if (omp_construct_selector_matches (&construct
, 1, NULL
))
1137 /* Lookup tables for context selectors. */
1138 const char *omp_tss_map
[] =
1148 /* Arrays of property candidates must be null-terminated. */
1149 static const char *const kind_properties
[] =
1150 { "host", "nohost", "cpu", "gpu", "fpga", "any", NULL
};
1151 static const char *const vendor_properties
[] =
1152 { "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "hpe", "ibm", "intel",
1153 "llvm", "nvidia", "pgi", "ti", "unknown", NULL
};
1154 static const char *const extension_properties
[] =
1156 static const char *const atomic_default_mem_order_properties
[] =
1157 { "seq_cst", "relaxed", "acq_rel", "acquire", "release", NULL
};
1159 struct omp_ts_info omp_ts_map
[] =
1162 (1 << OMP_TRAIT_SET_DEVICE
) | (1 << OMP_TRAIT_SET_TARGET_DEVICE
),
1163 OMP_TRAIT_PROPERTY_NAME_LIST
, false,
1167 (1 << OMP_TRAIT_SET_DEVICE
) | (1 << OMP_TRAIT_SET_TARGET_DEVICE
),
1168 OMP_TRAIT_PROPERTY_NAME_LIST
, false,
1172 (1 << OMP_TRAIT_SET_DEVICE
) | (1 << OMP_TRAIT_SET_TARGET_DEVICE
),
1173 OMP_TRAIT_PROPERTY_NAME_LIST
, false,
1177 (1 << OMP_TRAIT_SET_TARGET_DEVICE
),
1178 OMP_TRAIT_PROPERTY_DEV_NUM_EXPR
, false,
1182 (1 << OMP_TRAIT_SET_IMPLEMENTATION
),
1183 OMP_TRAIT_PROPERTY_NAME_LIST
, true,
1187 (1 << OMP_TRAIT_SET_IMPLEMENTATION
),
1188 OMP_TRAIT_PROPERTY_NAME_LIST
, true,
1189 extension_properties
,
1191 { "atomic_default_mem_order",
1192 (1 << OMP_TRAIT_SET_IMPLEMENTATION
),
1193 OMP_TRAIT_PROPERTY_ID
, true,
1194 atomic_default_mem_order_properties
,
1197 (1 << OMP_TRAIT_SET_IMPLEMENTATION
),
1198 OMP_TRAIT_PROPERTY_CLAUSE_LIST
, true,
1201 { "unified_address",
1202 (1 << OMP_TRAIT_SET_IMPLEMENTATION
),
1203 OMP_TRAIT_PROPERTY_NONE
, true,
1206 { "unified_shared_memory",
1207 (1 << OMP_TRAIT_SET_IMPLEMENTATION
),
1208 OMP_TRAIT_PROPERTY_NONE
, true,
1212 (1 << OMP_TRAIT_SET_IMPLEMENTATION
),
1213 OMP_TRAIT_PROPERTY_NONE
, true,
1216 { "dynamic_allocators",
1217 (1 << OMP_TRAIT_SET_IMPLEMENTATION
),
1218 OMP_TRAIT_PROPERTY_NONE
, true,
1221 { "reverse_offload",
1222 (1 << OMP_TRAIT_SET_IMPLEMENTATION
),
1223 OMP_TRAIT_PROPERTY_NONE
, true,
1227 (1 << OMP_TRAIT_SET_USER
),
1228 OMP_TRAIT_PROPERTY_BOOL_EXPR
, true,
1232 (1 << OMP_TRAIT_SET_CONSTRUCT
),
1233 OMP_TRAIT_PROPERTY_NONE
, false,
1237 (1 << OMP_TRAIT_SET_CONSTRUCT
),
1238 OMP_TRAIT_PROPERTY_NONE
, false,
1242 (1 << OMP_TRAIT_SET_CONSTRUCT
),
1243 OMP_TRAIT_PROPERTY_NONE
, false,
1247 (1 << OMP_TRAIT_SET_CONSTRUCT
),
1248 OMP_TRAIT_PROPERTY_NONE
, false,
1252 (1 << OMP_TRAIT_SET_CONSTRUCT
),
1253 OMP_TRAIT_PROPERTY_CLAUSE_LIST
, false,
1256 { NULL
, 0, OMP_TRAIT_PROPERTY_NONE
, false, NULL
} /* OMP_TRAIT_LAST */
1260 /* Return a name from PROP, a property in selectors accepting
1264 omp_context_name_list_prop (tree prop
)
1266 gcc_assert (OMP_TP_NAME (prop
) == OMP_TP_NAMELIST_NODE
);
1267 tree val
= OMP_TP_VALUE (prop
);
1268 switch (TREE_CODE (val
))
1270 case IDENTIFIER_NODE
:
1271 return IDENTIFIER_POINTER (val
);
1274 const char *ret
= TREE_STRING_POINTER (val
);
1275 if ((size_t) TREE_STRING_LENGTH (val
)
1276 == strlen (ret
) + (lang_GNU_Fortran () ? 0 : 1))
1285 /* Diagnose errors in an OpenMP context selector, return CTX if
1286 it is correct or error_mark_node otherwise. */
1289 omp_check_context_selector (location_t loc
, tree ctx
)
1291 bool tss_seen
[OMP_TRAIT_SET_LAST
], ts_seen
[OMP_TRAIT_LAST
];
1293 memset (tss_seen
, 0, sizeof (tss_seen
));
1294 for (tree tss
= ctx
; tss
; tss
= TREE_CHAIN (tss
))
1296 enum omp_tss_code tss_code
= OMP_TSS_CODE (tss
);
1297 bool saw_any_prop
= false;
1298 bool saw_other_prop
= false;
1300 /* We can parse this, but not handle it yet. */
1301 if (tss_code
== OMP_TRAIT_SET_TARGET_DEVICE
)
1302 sorry_at (loc
, "%<target_device%> selector set is not supported yet");
1304 /* Each trait-set-selector-name can only be specified once. */
1305 if (tss_seen
[tss_code
])
1307 error_at (loc
, "selector set %qs specified more than once",
1308 OMP_TSS_NAME (tss
));
1309 return error_mark_node
;
1312 tss_seen
[tss_code
] = true;
1314 memset (ts_seen
, 0, sizeof (ts_seen
));
1315 for (tree ts
= OMP_TSS_TRAIT_SELECTORS (tss
); ts
; ts
= TREE_CHAIN (ts
))
1317 enum omp_ts_code ts_code
= OMP_TS_CODE (ts
);
1319 /* Ignore unknown traits. */
1320 if (ts_code
== OMP_TRAIT_INVALID
)
1323 /* Each trait-selector-name can only be specified once. */
1324 if (ts_seen
[ts_code
])
1327 "selector %qs specified more than once in set %qs",
1329 OMP_TSS_NAME (tss
));
1330 return error_mark_node
;
1333 ts_seen
[ts_code
] = true;
1335 /* If trait-property "any" is specified in the "kind"
1336 trait-selector of the "device" selector set or the
1337 "target_device" selector sets, no other trait-property
1338 may be specified in the same selector set. */
1339 if (ts_code
== OMP_TRAIT_DEVICE_KIND
)
1340 for (tree p
= OMP_TS_PROPERTIES (ts
); p
; p
= TREE_CHAIN (p
))
1342 const char *prop
= omp_context_name_list_prop (p
);
1345 else if (strcmp (prop
, "any") == 0)
1346 saw_any_prop
= true;
1348 saw_other_prop
= true;
1350 /* It seems slightly suspicious that the spec's language covers
1351 the device_num selector too, but
1352 target_device={device_num(whatever),kind(any)}
1353 is probably not terribly useful anyway. */
1354 else if (ts_code
== OMP_TRAIT_DEVICE_ARCH
1355 || ts_code
== OMP_TRAIT_DEVICE_ISA
1356 || ts_code
== OMP_TRAIT_DEVICE_NUM
)
1357 saw_other_prop
= true;
1359 /* Each trait-property can only be specified once in a trait-selector
1360 other than the construct selector set. FIXME: only handles
1361 name-list properties, not clause-list properties, since the
1362 "requires" selector is not implemented yet (PR 113067). */
1363 if (tss_code
!= OMP_TRAIT_SET_CONSTRUCT
)
1364 for (tree p1
= OMP_TS_PROPERTIES (ts
); p1
; p1
= TREE_CHAIN (p1
))
1366 if (OMP_TP_NAME (p1
) != OMP_TP_NAMELIST_NODE
)
1368 const char *n1
= omp_context_name_list_prop (p1
);
1371 for (tree p2
= TREE_CHAIN (p1
); p2
; p2
= TREE_CHAIN (p2
))
1373 const char *n2
= omp_context_name_list_prop (p2
);
1376 if (!strcmp (n1
, n2
))
1379 "trait-property %qs specified more "
1380 "than once in %qs selector",
1381 n1
, OMP_TS_NAME (ts
));
1382 return error_mark_node
;
1387 /* Check for unknown properties. */
1388 if (omp_ts_map
[ts_code
].valid_properties
== NULL
)
1390 for (tree p
= OMP_TS_PROPERTIES (ts
); p
; p
= TREE_CHAIN (p
))
1391 for (unsigned j
= 0; ; j
++)
1393 const char *candidate
1394 = omp_ts_map
[ts_code
].valid_properties
[j
];
1395 if (candidate
== NULL
)
1397 /* We've reached the end of the candidate array. */
1398 if (ts_code
== OMP_TRAIT_IMPLEMENTATION_ADMO
)
1399 /* FIXME: not sure why this is an error vs warnings
1400 for the others, + incorrect/unknown wording? */
1403 "incorrect property %qs of %qs selector",
1404 IDENTIFIER_POINTER (OMP_TP_NAME (p
)),
1405 "atomic_default_mem_order");
1406 return error_mark_node
;
1408 if (OMP_TP_NAME (p
) == OMP_TP_NAMELIST_NODE
1409 && (TREE_CODE (OMP_TP_VALUE (p
)) == STRING_CST
))
1410 warning_at (loc
, OPT_Wopenmp
,
1411 "unknown property %qE of %qs selector",
1414 else if (OMP_TP_NAME (p
) == OMP_TP_NAMELIST_NODE
)
1415 warning_at (loc
, OPT_Wopenmp
,
1416 "unknown property %qs of %qs selector",
1417 omp_context_name_list_prop (p
),
1419 else if (OMP_TP_NAME (p
))
1420 warning_at (loc
, OPT_Wopenmp
,
1421 "unknown property %qs of %qs selector",
1422 IDENTIFIER_POINTER (OMP_TP_NAME (p
)),
1426 else if (OMP_TP_NAME (p
) == OMP_TP_NAMELIST_NODE
)
1427 /* Property-list traits. */
1429 const char *str
= omp_context_name_list_prop (p
);
1430 if (str
&& !strcmp (str
, candidate
))
1433 else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p
)),
1435 /* Identifier traits. */
1440 if (saw_any_prop
&& saw_other_prop
)
1443 "no other trait-property may be specified "
1444 "in the same selector set with %<kind(\"any\")%>");
1445 return error_mark_node
;
1452 /* Register VARIANT as variant of some base function marked with
1453 #pragma omp declare variant. CONSTRUCT is corresponding list of
1454 trait-selectors for the construct selector set. This is stashed as the
1455 value of the "omp declare variant variant" attribute on VARIANT. */
1457 omp_mark_declare_variant (location_t loc
, tree variant
, tree construct
)
1459 /* Ignore this variant if it contains unknown construct selectors.
1460 It will never match, and the front ends have already issued a warning
1462 for (tree c
= construct
; c
; c
= TREE_CHAIN (c
))
1463 if (OMP_TS_CODE (c
) == OMP_TRAIT_INVALID
)
1466 tree attr
= lookup_attribute ("omp declare variant variant",
1467 DECL_ATTRIBUTES (variant
));
1468 if (attr
== NULL_TREE
)
1470 attr
= tree_cons (get_identifier ("omp declare variant variant"),
1471 unshare_expr (construct
),
1472 DECL_ATTRIBUTES (variant
));
1473 DECL_ATTRIBUTES (variant
) = attr
;
1476 if ((TREE_VALUE (attr
) != NULL_TREE
) != (construct
!= NULL_TREE
)
1477 || (construct
!= NULL_TREE
1478 && omp_context_selector_set_compare (OMP_TRAIT_SET_CONSTRUCT
,
1481 error_at (loc
, "%qD used as a variant with incompatible %<construct%> "
1482 "selector sets", variant
);
1486 /* Constructors for context selectors. */
1489 make_trait_set_selector (enum omp_tss_code code
, tree selectors
, tree chain
)
1491 return tree_cons (build_int_cst (integer_type_node
, code
),
1496 make_trait_selector (enum omp_ts_code code
, tree score
, tree properties
,
1499 if (score
== NULL_TREE
)
1500 return tree_cons (build_int_cst (integer_type_node
, code
),
1503 return tree_cons (build_int_cst (integer_type_node
, code
),
1504 tree_cons (OMP_TS_SCORE_NODE
, score
, properties
),
1509 make_trait_property (tree name
, tree value
, tree chain
)
1511 return tree_cons (name
, value
, chain
);
1514 /* Return 1 if context selector matches the current OpenMP context, 0
1515 if it does not and -1 if it is unknown and need to be determined later.
1516 Some properties can be checked right away during parsing (this routine),
1517 others need to wait until the whole TU is parsed, others need to wait until
1518 IPA, others until vectorization. */
1521 omp_context_selector_matches (tree ctx
)
1524 for (tree tss
= ctx
; tss
; tss
= TREE_CHAIN (tss
))
1526 enum omp_tss_code set
= OMP_TSS_CODE (tss
);
1527 tree selectors
= OMP_TSS_TRAIT_SELECTORS (tss
);
1529 /* Immediately reject the match if there are any ignored
1530 selectors present. */
1531 for (tree ts
= selectors
; ts
; ts
= TREE_CHAIN (ts
))
1532 if (OMP_TS_CODE (ts
) == OMP_TRAIT_INVALID
)
1535 if (set
== OMP_TRAIT_SET_CONSTRUCT
)
1537 /* For now, ignore the construct set. While something can be
1538 determined already during parsing, we don't know until end of TU
1539 whether additional constructs aren't added through declare variant
1540 unless "omp declare variant variant" attribute exists already
1541 (so in most of the cases), and we'd need to maintain set of
1542 surrounding OpenMP constructs, which is better handled during
1544 if (symtab
->state
== PARSING
)
1550 int nconstructs
= list_length (selectors
);
1551 enum tree_code
*constructs
= NULL
;
1554 /* Even though this alloca appears in a loop over selector
1555 sets, it does not repeatedly grow the stack, because
1556 there can be only one construct selector set specified.
1557 This is enforced by omp_check_context_selector. */
1559 = (enum tree_code
*) alloca (nconstructs
1560 * sizeof (enum tree_code
));
1561 omp_construct_traits_to_codes (selectors
, nconstructs
,
1565 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1567 if (!cfun
->after_inlining
)
1573 for (i
= 0; i
< nconstructs
; ++i
)
1574 if (constructs
[i
] == OMP_SIMD
)
1576 if (i
< nconstructs
)
1581 /* If there is no simd, assume it is ok after IPA,
1582 constructs should have been checked before. */
1586 int r
= omp_construct_selector_matches (constructs
, nconstructs
,
1594 for (tree ts
= selectors
; ts
; ts
= TREE_CHAIN (ts
))
1596 enum omp_ts_code sel
= OMP_TS_CODE (ts
);
1599 case OMP_TRAIT_IMPLEMENTATION_VENDOR
:
1600 if (set
== OMP_TRAIT_SET_IMPLEMENTATION
)
1601 for (tree p
= OMP_TS_PROPERTIES (ts
); p
; p
= TREE_CHAIN (p
))
1603 const char *prop
= omp_context_name_list_prop (p
);
1606 if (!strcmp (prop
, "gnu"))
1611 case OMP_TRAIT_IMPLEMENTATION_EXTENSION
:
1612 if (set
== OMP_TRAIT_SET_IMPLEMENTATION
)
1613 /* We don't support any extensions right now. */
1616 case OMP_TRAIT_IMPLEMENTATION_ADMO
:
1617 if (set
== OMP_TRAIT_SET_IMPLEMENTATION
)
1619 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1622 enum omp_memory_order omo
1623 = ((enum omp_memory_order
)
1625 & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER
));
1626 if (omo
== OMP_MEMORY_ORDER_UNSPECIFIED
)
1628 /* We don't know yet, until end of TU. */
1629 if (symtab
->state
== PARSING
)
1635 omo
= OMP_MEMORY_ORDER_RELAXED
;
1637 tree p
= OMP_TS_PROPERTIES (ts
);
1638 const char *prop
= IDENTIFIER_POINTER (OMP_TP_NAME (p
));
1639 if (!strcmp (prop
, "relaxed")
1640 && omo
!= OMP_MEMORY_ORDER_RELAXED
)
1642 else if (!strcmp (prop
, "seq_cst")
1643 && omo
!= OMP_MEMORY_ORDER_SEQ_CST
)
1645 else if (!strcmp (prop
, "acq_rel")
1646 && omo
!= OMP_MEMORY_ORDER_ACQ_REL
)
1648 else if (!strcmp (prop
, "acquire")
1649 && omo
!= OMP_MEMORY_ORDER_ACQUIRE
)
1651 else if (!strcmp (prop
, "release")
1652 && omo
!= OMP_MEMORY_ORDER_RELEASE
)
1656 case OMP_TRAIT_DEVICE_ARCH
:
1657 if (set
== OMP_TRAIT_SET_DEVICE
)
1658 for (tree p
= OMP_TS_PROPERTIES (ts
); p
; p
= TREE_CHAIN (p
))
1660 const char *arch
= omp_context_name_list_prop (p
);
1664 if (targetm
.omp
.device_kind_arch_isa
!= NULL
)
1665 r
= targetm
.omp
.device_kind_arch_isa (omp_device_arch
,
1667 if (r
== 0 || (r
== -1 && symtab
->state
!= PARSING
))
1669 /* If we are or might be in a target region or
1670 declare target function, need to take into account
1671 also offloading values. */
1672 if (!omp_maybe_offloaded ())
1674 if (ENABLE_OFFLOADING
)
1676 const char *arches
= omp_offload_device_arch
;
1677 if (omp_offload_device_kind_arch_isa (arches
,
1688 /* If arch matches on the host, it still might not match
1689 in the offloading region. */
1690 else if (omp_maybe_offloaded ())
1694 case OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS
:
1695 if (set
== OMP_TRAIT_SET_IMPLEMENTATION
)
1697 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1700 if ((omp_requires_mask
& OMP_REQUIRES_UNIFIED_ADDRESS
) == 0)
1702 if (symtab
->state
== PARSING
)
1709 case OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY
:
1710 if (set
== OMP_TRAIT_SET_IMPLEMENTATION
)
1712 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1715 if ((omp_requires_mask
1716 & OMP_REQUIRES_UNIFIED_SHARED_MEMORY
) == 0)
1718 if (symtab
->state
== PARSING
)
1725 case OMP_TRAIT_IMPLEMENTATION_SELF_MAPS
:
1726 if (set
== OMP_TRAIT_SET_IMPLEMENTATION
)
1728 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1731 if ((omp_requires_mask
1732 & OMP_REQUIRES_SELF_MAPS
) == 0)
1734 if (symtab
->state
== PARSING
)
1741 case OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS
:
1742 if (set
== OMP_TRAIT_SET_IMPLEMENTATION
)
1744 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1747 if ((omp_requires_mask
1748 & OMP_REQUIRES_DYNAMIC_ALLOCATORS
) == 0)
1750 if (symtab
->state
== PARSING
)
1757 case OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD
:
1758 if (set
== OMP_TRAIT_SET_IMPLEMENTATION
)
1760 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
1763 if ((omp_requires_mask
& OMP_REQUIRES_REVERSE_OFFLOAD
) == 0)
1765 if (symtab
->state
== PARSING
)
1772 case OMP_TRAIT_DEVICE_KIND
:
1773 if (set
== OMP_TRAIT_SET_DEVICE
)
1774 for (tree p
= OMP_TS_PROPERTIES (ts
); p
; p
= TREE_CHAIN (p
))
1776 const char *prop
= omp_context_name_list_prop (p
);
1779 if (!strcmp (prop
, "any"))
1781 if (!strcmp (prop
, "host"))
1783 #ifdef ACCEL_COMPILER
1786 if (omp_maybe_offloaded ())
1791 if (!strcmp (prop
, "nohost"))
1793 #ifndef ACCEL_COMPILER
1794 if (omp_maybe_offloaded ())
1802 if (targetm
.omp
.device_kind_arch_isa
!= NULL
)
1803 r
= targetm
.omp
.device_kind_arch_isa (omp_device_kind
,
1806 r
= strcmp (prop
, "cpu") == 0;
1807 if (r
== 0 || (r
== -1 && symtab
->state
!= PARSING
))
1809 /* If we are or might be in a target region or
1810 declare target function, need to take into account
1811 also offloading values. */
1812 if (!omp_maybe_offloaded ())
1814 if (ENABLE_OFFLOADING
)
1816 const char *kinds
= omp_offload_device_kind
;
1817 if (omp_offload_device_kind_arch_isa (kinds
, prop
))
1827 /* If kind matches on the host, it still might not match
1828 in the offloading region. */
1829 else if (omp_maybe_offloaded ())
1833 case OMP_TRAIT_DEVICE_ISA
:
1834 if (set
== OMP_TRAIT_SET_DEVICE
)
1835 for (tree p
= OMP_TS_PROPERTIES (ts
); p
; p
= TREE_CHAIN (p
))
1837 const char *isa
= omp_context_name_list_prop (p
);
1841 if (targetm
.omp
.device_kind_arch_isa
!= NULL
)
1842 r
= targetm
.omp
.device_kind_arch_isa (omp_device_isa
,
1844 if (r
== 0 || (r
== -1 && symtab
->state
!= PARSING
))
1846 /* If isa is valid on the target, but not in the
1847 current function and current function has
1848 #pragma omp declare simd on it, some simd clones
1849 might have the isa added later on. */
1851 && targetm
.simd_clone
.compute_vecsize_and_simdlen
1852 && (cfun
== NULL
|| !cfun
->after_inlining
))
1855 = DECL_ATTRIBUTES (current_function_decl
);
1856 if (lookup_attribute ("omp declare simd", attrs
))
1862 /* If we are or might be in a target region or
1863 declare target function, need to take into account
1864 also offloading values. */
1865 if (!omp_maybe_offloaded ())
1867 if (ENABLE_OFFLOADING
)
1869 const char *isas
= omp_offload_device_isa
;
1870 if (omp_offload_device_kind_arch_isa (isas
, isa
))
1880 /* If isa matches on the host, it still might not match
1881 in the offloading region. */
1882 else if (omp_maybe_offloaded ())
1886 case OMP_TRAIT_USER_CONDITION
:
1887 if (set
== OMP_TRAIT_SET_USER
)
1888 for (tree p
= OMP_TS_PROPERTIES (ts
); p
; p
= TREE_CHAIN (p
))
1889 if (OMP_TP_NAME (p
) == NULL_TREE
)
1891 if (integer_zerop (OMP_TP_VALUE (p
)))
1893 if (integer_nonzerop (OMP_TP_VALUE (p
)))
1906 /* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as
1907 in omp_context_selector_set_compare. */
1910 omp_construct_simd_compare (tree clauses1
, tree clauses2
)
1912 if (clauses1
== NULL_TREE
)
1913 return clauses2
== NULL_TREE
? 0 : -1;
1914 if (clauses2
== NULL_TREE
)
1918 struct declare_variant_simd_data
{
1919 bool inbranch
, notinbranch
;
1921 auto_vec
<tree
,16> data_sharing
;
1922 auto_vec
<tree
,16> aligned
;
1923 declare_variant_simd_data ()
1924 : inbranch(false), notinbranch(false), simdlen(NULL_TREE
) {}
1927 for (i
= 0; i
< 2; i
++)
1928 for (tree c
= i
? clauses2
: clauses1
; c
; c
= OMP_CLAUSE_CHAIN (c
))
1931 switch (OMP_CLAUSE_CODE (c
))
1933 case OMP_CLAUSE_INBRANCH
:
1934 data
[i
].inbranch
= true;
1936 case OMP_CLAUSE_NOTINBRANCH
:
1937 data
[i
].notinbranch
= true;
1939 case OMP_CLAUSE_SIMDLEN
:
1940 data
[i
].simdlen
= OMP_CLAUSE_SIMDLEN_EXPR (c
);
1942 case OMP_CLAUSE_UNIFORM
:
1943 case OMP_CLAUSE_LINEAR
:
1944 v
= &data
[i
].data_sharing
;
1946 case OMP_CLAUSE_ALIGNED
:
1947 v
= &data
[i
].aligned
;
1952 unsigned HOST_WIDE_INT argno
= tree_to_uhwi (OMP_CLAUSE_DECL (c
));
1953 if (argno
>= v
->length ())
1954 v
->safe_grow_cleared (argno
+ 1, true);
1957 /* Here, r is used as a bitmask, 2 is set if CLAUSES1 has something
1958 CLAUSES2 doesn't, 1 is set if CLAUSES2 has something CLAUSES1
1959 doesn't. Thus, r == 3 implies return value 2, r == 1 implies
1960 -1, r == 2 implies 1 and r == 0 implies 0. */
1961 if (data
[0].inbranch
!= data
[1].inbranch
)
1962 r
|= data
[0].inbranch
? 2 : 1;
1963 if (data
[0].notinbranch
!= data
[1].notinbranch
)
1964 r
|= data
[0].notinbranch
? 2 : 1;
1965 if (!simple_cst_equal (data
[0].simdlen
, data
[1].simdlen
))
1967 if (data
[0].simdlen
&& data
[1].simdlen
)
1969 r
|= data
[0].simdlen
? 2 : 1;
1971 if (data
[0].data_sharing
.length () < data
[1].data_sharing
.length ()
1972 || data
[0].aligned
.length () < data
[1].aligned
.length ())
1975 FOR_EACH_VEC_ELT (data
[0].data_sharing
, i
, c1
)
1977 c2
= (i
< data
[1].data_sharing
.length ()
1978 ? data
[1].data_sharing
[i
] : NULL_TREE
);
1979 if ((c1
== NULL_TREE
) != (c2
== NULL_TREE
))
1981 r
|= c1
!= NULL_TREE
? 2 : 1;
1984 if (c1
== NULL_TREE
)
1986 if (OMP_CLAUSE_CODE (c1
) != OMP_CLAUSE_CODE (c2
))
1988 if (OMP_CLAUSE_CODE (c1
) != OMP_CLAUSE_LINEAR
)
1990 if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1
)
1991 != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2
))
1993 if (OMP_CLAUSE_LINEAR_KIND (c1
) != OMP_CLAUSE_LINEAR_KIND (c2
))
1995 if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1
),
1996 OMP_CLAUSE_LINEAR_STEP (c2
)))
1999 FOR_EACH_VEC_ELT (data
[0].aligned
, i
, c1
)
2001 c2
= i
< data
[1].aligned
.length () ? data
[1].aligned
[i
] : NULL_TREE
;
2002 if ((c1
== NULL_TREE
) != (c2
== NULL_TREE
))
2004 r
|= c1
!= NULL_TREE
? 2 : 1;
2007 if (c1
== NULL_TREE
)
2009 if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1
),
2010 OMP_CLAUSE_ALIGNED_ALIGNMENT (c2
)))
2019 default: gcc_unreachable ();
2023 /* Compare properties of selectors SEL from SET other than construct.
2024 CTX1 and CTX2 are the lists of properties to compare.
2025 Return 0/-1/1/2 as in omp_context_selector_set_compare.
2026 Unlike set names or selector names, properties can have duplicates. */
2029 omp_context_selector_props_compare (enum omp_tss_code set
,
2030 enum omp_ts_code sel
,
2031 tree ctx1
, tree ctx2
)
2034 for (int pass
= 0; pass
< 2; pass
++)
2035 for (tree p1
= pass
? ctx2
: ctx1
; p1
; p1
= TREE_CHAIN (p1
))
2038 for (p2
= pass
? ctx1
: ctx2
; p2
; p2
= TREE_CHAIN (p2
))
2039 if (OMP_TP_NAME (p1
) == OMP_TP_NAME (p2
))
2041 if (OMP_TP_NAME (p1
) == NULL_TREE
)
2043 if (set
== OMP_TRAIT_SET_USER
2044 && sel
== OMP_TRAIT_USER_CONDITION
)
2046 if (integer_zerop (OMP_TP_VALUE (p1
))
2047 != integer_zerop (OMP_TP_VALUE (p2
)))
2051 if (simple_cst_equal (OMP_TP_VALUE (p1
), OMP_TP_VALUE (p2
)))
2054 else if (OMP_TP_NAME (p1
) == OMP_TP_NAMELIST_NODE
)
2056 /* Handle string constant vs identifier comparison for
2057 name-list properties. */
2058 const char *n1
= omp_context_name_list_prop (p1
);
2059 const char *n2
= omp_context_name_list_prop (p2
);
2060 if (n1
&& n2
&& !strcmp (n1
, n2
))
2066 if (p2
== NULL_TREE
)
2068 int r
= pass
? -1 : 1;
2069 if (ret
&& ret
!= r
)
2083 /* Compare single context selector sets CTX1 and CTX2 with SET name.
2084 CTX1 and CTX2 are lists of trait-selectors.
2085 Return 0 if CTX1 is equal to CTX2,
2086 -1 if CTX1 is a strict subset of CTX2,
2087 1 if CTX2 is a strict subset of CTX1, or
2088 2 if neither context is a subset of another one. */
2091 omp_context_selector_set_compare (enum omp_tss_code set
, tree ctx1
, tree ctx2
)
2094 /* If either list includes an ignored selector trait, neither can
2095 be a subset of the other. */
2096 for (tree ts
= ctx1
; ts
; ts
= TREE_CHAIN (ts
))
2097 if (OMP_TS_CODE (ts
) == OMP_TRAIT_INVALID
)
2099 for (tree ts
= ctx2
; ts
; ts
= TREE_CHAIN (ts
))
2100 if (OMP_TS_CODE (ts
) == OMP_TRAIT_INVALID
)
2103 bool swapped
= false;
2105 int len1
= list_length (ctx1
);
2106 int len2
= list_length (ctx2
);
2111 std::swap (ctx1
, ctx2
);
2112 std::swap (len1
, len2
);
2115 if (set
== OMP_TRAIT_SET_CONSTRUCT
)
2119 /* Handle construct set specially. In this case the order
2120 of the selector matters too. */
2121 for (ts1
= ctx1
; ts1
; ts1
= TREE_CHAIN (ts1
))
2122 if (OMP_TS_CODE (ts1
) == OMP_TS_CODE (ts2
))
2125 if (OMP_TS_CODE (ts1
) == OMP_TRAIT_CONSTRUCT_SIMD
)
2126 r
= omp_construct_simd_compare (OMP_TS_PROPERTIES (ts1
),
2127 OMP_TS_PROPERTIES (ts2
));
2128 if (r
== 2 || (ret
&& r
&& (ret
< 0) != (r
< 0)))
2132 ts2
= TREE_CHAIN (ts2
);
2133 if (ts2
== NULL_TREE
)
2135 ts1
= TREE_CHAIN (ts1
);
2143 if (ts2
!= NULL_TREE
)
2145 if (ts1
!= NULL_TREE
)
2153 return swapped
? -ret
: ret
;
2155 for (tree ts1
= ctx1
; ts1
; ts1
= TREE_CHAIN (ts1
))
2157 enum omp_ts_code sel
= OMP_TS_CODE (ts1
);
2159 for (ts2
= ctx2
; ts2
; ts2
= TREE_CHAIN (ts2
))
2160 if (sel
== OMP_TS_CODE (ts2
))
2162 tree score1
= OMP_TS_SCORE (ts1
);
2163 tree score2
= OMP_TS_SCORE (ts2
);
2164 if (score1
&& score2
&& !simple_cst_equal (score1
, score2
))
2167 int r
= omp_context_selector_props_compare (set
, OMP_TS_CODE (ts1
),
2168 OMP_TS_PROPERTIES (ts1
),
2169 OMP_TS_PROPERTIES (ts2
));
2170 if (r
== 2 || (ret
&& r
&& (ret
< 0) != (r
< 0)))
2177 if (ts2
== NULL_TREE
)
2188 return swapped
? -ret
: ret
;
2191 /* Compare whole context selector specification CTX1 and CTX2.
2192 Return 0 if CTX1 is equal to CTX2,
2193 -1 if CTX1 is a strict subset of CTX2,
2194 1 if CTX2 is a strict subset of CTX1, or
2195 2 if neither context is a subset of another one. */
2198 omp_context_selector_compare (tree ctx1
, tree ctx2
)
2200 bool swapped
= false;
2202 int len1
= list_length (ctx1
);
2203 int len2
= list_length (ctx2
);
2208 std::swap (ctx1
, ctx2
);
2209 std::swap (len1
, len2
);
2211 for (tree tss1
= ctx1
; tss1
; tss1
= TREE_CHAIN (tss1
))
2213 enum omp_tss_code set
= OMP_TSS_CODE (tss1
);
2215 for (tss2
= ctx2
; tss2
; tss2
= TREE_CHAIN (tss2
))
2216 if (set
== OMP_TSS_CODE (tss2
))
2219 = omp_context_selector_set_compare
2220 (set
, OMP_TSS_TRAIT_SELECTORS (tss1
),
2221 OMP_TSS_TRAIT_SELECTORS (tss2
));
2222 if (r
== 2 || (ret
&& r
&& (ret
< 0) != (r
< 0)))
2229 if (tss2
== NULL_TREE
)
2240 return swapped
? -ret
: ret
;
2243 /* From context selector CTX, return trait-selector with name SEL in
2244 trait-selector-set with name SET if any, or NULL_TREE if not found. */
2246 omp_get_context_selector (tree ctx
, enum omp_tss_code set
,
2247 enum omp_ts_code sel
)
2249 for (tree tss
= ctx
; tss
; tss
= TREE_CHAIN (tss
))
2250 if (OMP_TSS_CODE (tss
) == set
)
2251 for (tree ts
= OMP_TSS_TRAIT_SELECTORS (tss
); ts
; ts
= TREE_CHAIN (ts
))
2252 if (OMP_TS_CODE (ts
) == sel
)
2257 /* Similar, but returns the whole trait-selector list for SET in CTX. */
2259 omp_get_context_selector_list (tree ctx
, enum omp_tss_code set
)
2261 for (tree tss
= ctx
; tss
; tss
= TREE_CHAIN (tss
))
2262 if (OMP_TSS_CODE (tss
) == set
)
2263 return OMP_TSS_TRAIT_SELECTORS (tss
);
2267 /* Map string S onto a trait selector set code. */
2269 omp_lookup_tss_code (const char * s
)
2271 for (int i
= 0; i
< OMP_TRAIT_SET_LAST
; i
++)
2272 if (strcmp (s
, omp_tss_map
[i
]) == 0)
2273 return (enum omp_tss_code
) i
;
2274 return OMP_TRAIT_SET_INVALID
;
2277 /* Map string S onto a trait selector code for set SET. */
2279 omp_lookup_ts_code (enum omp_tss_code set
, const char *s
)
2281 unsigned int mask
= 1 << set
;
2282 for (int i
= 0; i
< OMP_TRAIT_LAST
; i
++)
2283 if ((mask
& omp_ts_map
[i
].tss_mask
) != 0
2284 && strcmp (s
, omp_ts_map
[i
].name
) == 0)
2285 return (enum omp_ts_code
) i
;
2286 return OMP_TRAIT_INVALID
;
2289 /* Needs to be a GC-friendly widest_int variant, but precision is
2290 desirable to be the same on all targets. */
2291 typedef generic_wide_int
<fixed_wide_int_storage
<1024> > score_wide_int
;
2293 /* Compute *SCORE for context selector CTX. Return true if the score
2294 would be different depending on whether it is a declare simd clone or
2295 not. DECLARE_SIMD should be true for the case when it would be
2296 a declare simd clone. */
2299 omp_context_compute_score (tree ctx
, score_wide_int
*score
, bool declare_simd
)
2302 = omp_get_context_selector_list (ctx
, OMP_TRAIT_SET_CONSTRUCT
);
2303 bool has_kind
= omp_get_context_selector (ctx
, OMP_TRAIT_SET_DEVICE
,
2304 OMP_TRAIT_DEVICE_KIND
);
2305 bool has_arch
= omp_get_context_selector (ctx
, OMP_TRAIT_SET_DEVICE
,
2306 OMP_TRAIT_DEVICE_ARCH
);
2307 bool has_isa
= omp_get_context_selector (ctx
, OMP_TRAIT_SET_DEVICE
,
2308 OMP_TRAIT_DEVICE_ISA
);
2311 for (tree tss
= ctx
; tss
; tss
= TREE_CHAIN (tss
))
2312 if (OMP_TSS_TRAIT_SELECTORS (tss
) != selectors
)
2313 for (tree ts
= OMP_TSS_TRAIT_SELECTORS (tss
); ts
; ts
= TREE_CHAIN (ts
))
2315 tree s
= OMP_TS_SCORE (ts
);
2316 if (s
&& TREE_CODE (s
) == INTEGER_CST
)
2317 *score
+= score_wide_int::from (wi::to_wide (s
),
2318 TYPE_SIGN (TREE_TYPE (s
)));
2321 if (selectors
|| has_kind
|| has_arch
|| has_isa
)
2323 int nconstructs
= list_length (selectors
);
2324 enum tree_code
*constructs
= NULL
;
2328 = (enum tree_code
*) alloca (nconstructs
2329 * sizeof (enum tree_code
));
2330 omp_construct_traits_to_codes (selectors
, nconstructs
, constructs
);
2333 = (int *) alloca ((2 * nconstructs
+ 2) * sizeof (int));
2334 if (omp_construct_selector_matches (constructs
, nconstructs
, scores
)
2337 int b
= declare_simd
? nconstructs
+ 1 : 0;
2338 if (scores
[b
+ nconstructs
] + 4U < score
->get_precision ())
2340 for (int n
= 0; n
< nconstructs
; ++n
)
2342 if (scores
[b
+ n
] < 0)
2347 *score
+= wi::shifted_mask
<score_wide_int
> (scores
[b
+ n
], 1, false);
2350 *score
+= wi::shifted_mask
<score_wide_int
> (scores
[b
+ nconstructs
],
2353 *score
+= wi::shifted_mask
<score_wide_int
> (scores
[b
+ nconstructs
] + 1,
2356 *score
+= wi::shifted_mask
<score_wide_int
> (scores
[b
+ nconstructs
] + 2,
2359 else /* FIXME: Implement this. */
2365 /* Class describing a single variant. */
2366 struct GTY(()) omp_declare_variant_entry
{
2367 /* NODE of the variant. */
2368 cgraph_node
*variant
;
2369 /* Score if not in declare simd clone. */
2370 score_wide_int score
;
2371 /* Score if in declare simd clone. */
2372 score_wide_int score_in_declare_simd_clone
;
2373 /* Context selector for the variant. */
2375 /* True if the context selector is known to match already. */
2379 /* Class describing a function with variants. */
2380 struct GTY((for_user
)) omp_declare_variant_base_entry
{
2381 /* NODE of the base function. */
2383 /* NODE of the artificial function created for the deferred variant
2386 /* Vector of the variants. */
2387 vec
<omp_declare_variant_entry
, va_gc
> *variants
;
2390 struct omp_declare_variant_hasher
2391 : ggc_ptr_hash
<omp_declare_variant_base_entry
> {
2392 static hashval_t
hash (omp_declare_variant_base_entry
*);
2393 static bool equal (omp_declare_variant_base_entry
*,
2394 omp_declare_variant_base_entry
*);
2398 omp_declare_variant_hasher::hash (omp_declare_variant_base_entry
*x
)
2400 inchash::hash hstate
;
2401 hstate
.add_int (DECL_UID (x
->base
->decl
));
2402 hstate
.add_int (x
->variants
->length ());
2403 omp_declare_variant_entry
*variant
;
2405 FOR_EACH_VEC_SAFE_ELT (x
->variants
, i
, variant
)
2407 hstate
.add_int (DECL_UID (variant
->variant
->decl
));
2408 hstate
.add_wide_int (variant
->score
);
2409 hstate
.add_wide_int (variant
->score_in_declare_simd_clone
);
2410 hstate
.add_ptr (variant
->ctx
);
2411 hstate
.add_int (variant
->matches
);
2413 return hstate
.end ();
2417 omp_declare_variant_hasher::equal (omp_declare_variant_base_entry
*x
,
2418 omp_declare_variant_base_entry
*y
)
2420 if (x
->base
!= y
->base
2421 || x
->variants
->length () != y
->variants
->length ())
2423 omp_declare_variant_entry
*variant
;
2425 FOR_EACH_VEC_SAFE_ELT (x
->variants
, i
, variant
)
2426 if (variant
->variant
!= (*y
->variants
)[i
].variant
2427 || variant
->score
!= (*y
->variants
)[i
].score
2428 || (variant
->score_in_declare_simd_clone
2429 != (*y
->variants
)[i
].score_in_declare_simd_clone
)
2430 || variant
->ctx
!= (*y
->variants
)[i
].ctx
2431 || variant
->matches
!= (*y
->variants
)[i
].matches
)
2436 static GTY(()) hash_table
<omp_declare_variant_hasher
> *omp_declare_variants
;
2438 struct omp_declare_variant_alt_hasher
2439 : ggc_ptr_hash
<omp_declare_variant_base_entry
> {
2440 static hashval_t
hash (omp_declare_variant_base_entry
*);
2441 static bool equal (omp_declare_variant_base_entry
*,
2442 omp_declare_variant_base_entry
*);
2446 omp_declare_variant_alt_hasher::hash (omp_declare_variant_base_entry
*x
)
2448 return DECL_UID (x
->node
->decl
);
2452 omp_declare_variant_alt_hasher::equal (omp_declare_variant_base_entry
*x
,
2453 omp_declare_variant_base_entry
*y
)
2455 return x
->node
== y
->node
;
2458 static GTY(()) hash_table
<omp_declare_variant_alt_hasher
>
2459 *omp_declare_variant_alt
;
2461 /* Try to resolve declare variant after gimplification. */
2464 omp_resolve_late_declare_variant (tree alt
)
2466 cgraph_node
*node
= cgraph_node::get (alt
);
2467 cgraph_node
*cur_node
= cgraph_node::get (cfun
->decl
);
2469 || !node
->declare_variant_alt
2470 || !cfun
->after_inlining
)
2473 omp_declare_variant_base_entry entry
;
2476 entry
.variants
= NULL
;
2477 omp_declare_variant_base_entry
*entryp
2478 = omp_declare_variant_alt
->find_with_hash (&entry
, DECL_UID (alt
));
2481 omp_declare_variant_entry
*varentry1
, *varentry2
;
2482 auto_vec
<bool, 16> matches
;
2483 unsigned int nmatches
= 0;
2484 FOR_EACH_VEC_SAFE_ELT (entryp
->variants
, i
, varentry1
)
2486 if (varentry1
->matches
)
2488 /* This has been checked to be ok already. */
2489 matches
.safe_push (true);
2493 switch (omp_context_selector_matches (varentry1
->ctx
))
2496 matches
.safe_push (false);
2501 matches
.safe_push (true);
2508 return entryp
->base
->decl
;
2510 /* A context selector that is a strict subset of another context selector
2511 has a score of zero. */
2512 FOR_EACH_VEC_SAFE_ELT (entryp
->variants
, i
, varentry1
)
2516 vec_safe_iterate (entryp
->variants
, j
, &varentry2
); ++j
)
2519 int r
= omp_context_selector_compare (varentry1
->ctx
,
2523 /* ctx1 is a strict subset of ctx2, ignore ctx1. */
2528 /* ctx2 is a strict subset of ctx1, remove ctx2. */
2533 score_wide_int max_score
= -1;
2535 FOR_EACH_VEC_SAFE_ELT (entryp
->variants
, i
, varentry1
)
2538 score_wide_int score
2539 = (cur_node
->simdclone
? varentry1
->score_in_declare_simd_clone
2540 : varentry1
->score
);
2541 if (score
> max_score
)
2544 varentry2
= varentry1
;
2547 return varentry2
->variant
->decl
;
2550 /* Hook to adjust hash tables on cgraph_node removal. */
2553 omp_declare_variant_remove_hook (struct cgraph_node
*node
, void *)
2555 if (!node
->declare_variant_alt
)
2558 /* Drop this hash table completely. */
2559 omp_declare_variants
= NULL
;
2560 /* And remove node from the other hash table. */
2561 if (omp_declare_variant_alt
)
2563 omp_declare_variant_base_entry entry
;
2566 entry
.variants
= NULL
;
2567 omp_declare_variant_alt
->remove_elt_with_hash (&entry
,
2568 DECL_UID (node
->decl
));
2572 /* Try to resolve declare variant, return the variant decl if it should
2573 be used instead of base, or base otherwise. */
2576 omp_resolve_declare_variant (tree base
)
2578 tree variant1
= NULL_TREE
, variant2
= NULL_TREE
;
2579 if (cfun
&& (cfun
->curr_properties
& PROP_gimple_any
) != 0)
2580 return omp_resolve_late_declare_variant (base
);
2582 auto_vec
<tree
, 16> variants
;
2583 auto_vec
<bool, 16> defer
;
2584 bool any_deferred
= false;
2585 for (tree attr
= DECL_ATTRIBUTES (base
); attr
; attr
= TREE_CHAIN (attr
))
2587 attr
= lookup_attribute ("omp declare variant base", attr
);
2588 if (attr
== NULL_TREE
)
2590 if (TREE_CODE (TREE_PURPOSE (TREE_VALUE (attr
))) != FUNCTION_DECL
)
2592 cgraph_node
*node
= cgraph_node::get (base
);
2593 /* If this is already a magic decl created by this function,
2594 don't process it again. */
2595 if (node
&& node
->declare_variant_alt
)
2597 switch (omp_context_selector_matches (TREE_VALUE (TREE_VALUE (attr
))))
2600 /* No match, ignore. */
2603 /* Needs to be deferred. */
2604 any_deferred
= true;
2605 variants
.safe_push (attr
);
2606 defer
.safe_push (true);
2609 variants
.safe_push (attr
);
2610 defer
.safe_push (false);
2614 if (variants
.length () == 0)
2619 score_wide_int max_score1
= 0;
2620 score_wide_int max_score2
= 0;
2624 omp_declare_variant_base_entry entry
;
2625 entry
.base
= cgraph_node::get_create (base
);
2627 vec_alloc (entry
.variants
, variants
.length ());
2628 FOR_EACH_VEC_ELT (variants
, i
, attr1
)
2630 score_wide_int score1
;
2631 score_wide_int score2
;
2633 tree ctx
= TREE_VALUE (TREE_VALUE (attr1
));
2634 need_two
= omp_context_compute_score (ctx
, &score1
, false);
2636 omp_context_compute_score (ctx
, &score2
, true);
2642 max_score1
= score1
;
2643 max_score2
= score2
;
2652 if (max_score1
== score1
)
2653 variant1
= NULL_TREE
;
2654 else if (score1
> max_score1
)
2656 max_score1
= score1
;
2657 variant1
= defer
[i
] ? NULL_TREE
: attr1
;
2659 if (max_score2
== score2
)
2660 variant2
= NULL_TREE
;
2661 else if (score2
> max_score2
)
2663 max_score2
= score2
;
2664 variant2
= defer
[i
] ? NULL_TREE
: attr1
;
2667 omp_declare_variant_entry varentry
;
2669 = cgraph_node::get_create (TREE_PURPOSE (TREE_VALUE (attr1
)));
2670 varentry
.score
= score1
;
2671 varentry
.score_in_declare_simd_clone
= score2
;
2673 varentry
.matches
= !defer
[i
];
2674 entry
.variants
->quick_push (varentry
);
2677 /* If there is a clear winner variant with the score which is not
2678 deferred, verify it is not a strict subset of any other context
2679 selector and if it is not, it is the best alternative no matter
2680 whether the others do or don't match. */
2681 if (variant1
&& variant1
== variant2
)
2683 tree ctx1
= TREE_VALUE (TREE_VALUE (variant1
));
2684 FOR_EACH_VEC_ELT (variants
, i
, attr2
)
2686 if (attr2
== variant1
)
2688 tree ctx2
= TREE_VALUE (TREE_VALUE (attr2
));
2689 int r
= omp_context_selector_compare (ctx1
, ctx2
);
2692 /* The winner is a strict subset of ctx2, can't
2694 variant1
= NULL_TREE
;
2700 vec_free (entry
.variants
);
2701 return TREE_PURPOSE (TREE_VALUE (variant1
));
2705 static struct cgraph_node_hook_list
*node_removal_hook_holder
;
2706 if (!node_removal_hook_holder
)
2707 node_removal_hook_holder
2708 = symtab
->add_cgraph_removal_hook (omp_declare_variant_remove_hook
,
2711 if (omp_declare_variants
== NULL
)
2712 omp_declare_variants
2713 = hash_table
<omp_declare_variant_hasher
>::create_ggc (64);
2714 omp_declare_variant_base_entry
**slot
2715 = omp_declare_variants
->find_slot (&entry
, INSERT
);
2718 vec_free (entry
.variants
);
2719 return (*slot
)->node
->decl
;
2722 *slot
= ggc_cleared_alloc
<omp_declare_variant_base_entry
> ();
2723 (*slot
)->base
= entry
.base
;
2724 (*slot
)->node
= entry
.base
;
2725 (*slot
)->variants
= entry
.variants
;
2726 tree alt
= build_decl (DECL_SOURCE_LOCATION (base
), FUNCTION_DECL
,
2727 DECL_NAME (base
), TREE_TYPE (base
));
2728 DECL_ARTIFICIAL (alt
) = 1;
2729 DECL_IGNORED_P (alt
) = 1;
2730 TREE_STATIC (alt
) = 1;
2731 tree attributes
= DECL_ATTRIBUTES (base
);
2732 if (lookup_attribute ("noipa", attributes
) == NULL
)
2734 attributes
= tree_cons (get_identifier ("noipa"), NULL
, attributes
);
2735 if (lookup_attribute ("noinline", attributes
) == NULL
)
2736 attributes
= tree_cons (get_identifier ("noinline"), NULL
,
2738 if (lookup_attribute ("noclone", attributes
) == NULL
)
2739 attributes
= tree_cons (get_identifier ("noclone"), NULL
,
2741 if (lookup_attribute ("no_icf", attributes
) == NULL
)
2742 attributes
= tree_cons (get_identifier ("no_icf"), NULL
,
2745 DECL_ATTRIBUTES (alt
) = attributes
;
2746 DECL_INITIAL (alt
) = error_mark_node
;
2747 (*slot
)->node
= cgraph_node::create (alt
);
2748 (*slot
)->node
->declare_variant_alt
= 1;
2749 (*slot
)->node
->create_reference (entry
.base
, IPA_REF_ADDR
);
2750 omp_declare_variant_entry
*varentry
;
2751 FOR_EACH_VEC_SAFE_ELT (entry
.variants
, i
, varentry
)
2752 (*slot
)->node
->create_reference (varentry
->variant
, IPA_REF_ADDR
);
2753 if (omp_declare_variant_alt
== NULL
)
2754 omp_declare_variant_alt
2755 = hash_table
<omp_declare_variant_alt_hasher
>::create_ggc (64);
2756 *omp_declare_variant_alt
->find_slot_with_hash (*slot
, DECL_UID (alt
),
2761 if (variants
.length () == 1)
2762 return TREE_PURPOSE (TREE_VALUE (variants
[0]));
2764 /* A context selector that is a strict subset of another context selector
2765 has a score of zero. */
2768 FOR_EACH_VEC_ELT (variants
, i
, attr1
)
2771 tree ctx1
= TREE_VALUE (TREE_VALUE (attr1
));
2772 FOR_EACH_VEC_ELT_FROM (variants
, j
, attr2
, i
+ 1)
2775 tree ctx2
= TREE_VALUE (TREE_VALUE (attr2
));
2776 int r
= omp_context_selector_compare (ctx1
, ctx2
);
2779 /* ctx1 is a strict subset of ctx2, remove
2780 attr1 from the vector. */
2781 variants
[i
] = NULL_TREE
;
2785 /* ctx2 is a strict subset of ctx1, remove attr2
2787 variants
[j
] = NULL_TREE
;
2790 score_wide_int max_score1
= 0;
2791 score_wide_int max_score2
= 0;
2793 FOR_EACH_VEC_ELT (variants
, i
, attr1
)
2798 score_wide_int score1
;
2799 score_wide_int score2
;
2805 ctx
= TREE_VALUE (TREE_VALUE (variant1
));
2806 need_two
= omp_context_compute_score (ctx
, &max_score1
, false);
2808 omp_context_compute_score (ctx
, &max_score2
, true);
2810 max_score2
= max_score1
;
2812 ctx
= TREE_VALUE (TREE_VALUE (attr1
));
2813 need_two
= omp_context_compute_score (ctx
, &score1
, false);
2815 omp_context_compute_score (ctx
, &score2
, true);
2818 if (score1
> max_score1
)
2820 max_score1
= score1
;
2823 if (score2
> max_score2
)
2825 max_score2
= score2
;
2835 /* If there is a disagreement on which variant has the highest score
2836 depending on whether it will be in a declare simd clone or not,
2837 punt for now and defer until after IPA where we will know that. */
2838 return ((variant1
&& variant1
== variant2
)
2839 ? TREE_PURPOSE (TREE_VALUE (variant1
)) : base
);
2843 omp_lto_output_declare_variant_alt (lto_simple_output_block
*ob
,
2845 lto_symtab_encoder_t encoder
)
2847 gcc_assert (node
->declare_variant_alt
);
2849 omp_declare_variant_base_entry entry
;
2852 entry
.variants
= NULL
;
2853 omp_declare_variant_base_entry
*entryp
2854 = omp_declare_variant_alt
->find_with_hash (&entry
, DECL_UID (node
->decl
));
2855 gcc_assert (entryp
);
2857 int nbase
= lto_symtab_encoder_lookup (encoder
, entryp
->base
);
2858 gcc_assert (nbase
!= LCC_NOT_FOUND
);
2859 streamer_write_hwi_stream (ob
->main_stream
, nbase
);
2861 streamer_write_hwi_stream (ob
->main_stream
, entryp
->variants
->length ());
2864 omp_declare_variant_entry
*varentry
;
2865 FOR_EACH_VEC_SAFE_ELT (entryp
->variants
, i
, varentry
)
2867 int nvar
= lto_symtab_encoder_lookup (encoder
, varentry
->variant
);
2868 gcc_assert (nvar
!= LCC_NOT_FOUND
);
2869 streamer_write_hwi_stream (ob
->main_stream
, nvar
);
2871 for (score_wide_int
*w
= &varentry
->score
; ;
2872 w
= &varentry
->score_in_declare_simd_clone
)
2874 unsigned len
= w
->get_len ();
2875 streamer_write_hwi_stream (ob
->main_stream
, len
);
2876 const HOST_WIDE_INT
*val
= w
->get_val ();
2877 for (unsigned j
= 0; j
< len
; j
++)
2878 streamer_write_hwi_stream (ob
->main_stream
, val
[j
]);
2879 if (w
== &varentry
->score_in_declare_simd_clone
)
2883 HOST_WIDE_INT cnt
= -1;
2884 HOST_WIDE_INT i
= varentry
->matches
? 1 : 0;
2885 for (tree attr
= DECL_ATTRIBUTES (entryp
->base
->decl
);
2886 attr
; attr
= TREE_CHAIN (attr
), i
+= 2)
2888 attr
= lookup_attribute ("omp declare variant base", attr
);
2889 if (attr
== NULL_TREE
)
2892 if (varentry
->ctx
== TREE_VALUE (TREE_VALUE (attr
)))
2899 gcc_assert (cnt
!= -1);
2900 streamer_write_hwi_stream (ob
->main_stream
, cnt
);
2905 omp_lto_input_declare_variant_alt (lto_input_block
*ib
, cgraph_node
*node
,
2906 vec
<symtab_node
*> nodes
)
2908 gcc_assert (node
->declare_variant_alt
);
2909 omp_declare_variant_base_entry
*entryp
2910 = ggc_cleared_alloc
<omp_declare_variant_base_entry
> ();
2911 entryp
->base
= dyn_cast
<cgraph_node
*> (nodes
[streamer_read_hwi (ib
)]);
2912 entryp
->node
= node
;
2913 unsigned int len
= streamer_read_hwi (ib
);
2914 vec_alloc (entryp
->variants
, len
);
2916 for (unsigned int i
= 0; i
< len
; i
++)
2918 omp_declare_variant_entry varentry
;
2920 = dyn_cast
<cgraph_node
*> (nodes
[streamer_read_hwi (ib
)]);
2921 for (score_wide_int
*w
= &varentry
.score
; ;
2922 w
= &varentry
.score_in_declare_simd_clone
)
2924 unsigned len2
= streamer_read_hwi (ib
);
2925 HOST_WIDE_INT arr
[WIDE_INT_MAX_HWIS (1024)];
2926 gcc_assert (len2
<= WIDE_INT_MAX_HWIS (1024));
2927 for (unsigned int j
= 0; j
< len2
; j
++)
2928 arr
[j
] = streamer_read_hwi (ib
);
2929 *w
= score_wide_int::from_array (arr
, len2
, true);
2930 if (w
== &varentry
.score_in_declare_simd_clone
)
2934 HOST_WIDE_INT cnt
= streamer_read_hwi (ib
);
2935 HOST_WIDE_INT j
= 0;
2936 varentry
.ctx
= NULL_TREE
;
2937 varentry
.matches
= (cnt
& 1) ? true : false;
2938 cnt
&= ~HOST_WIDE_INT_1
;
2939 for (tree attr
= DECL_ATTRIBUTES (entryp
->base
->decl
);
2940 attr
; attr
= TREE_CHAIN (attr
), j
+= 2)
2942 attr
= lookup_attribute ("omp declare variant base", attr
);
2943 if (attr
== NULL_TREE
)
2948 varentry
.ctx
= TREE_VALUE (TREE_VALUE (attr
));
2952 gcc_assert (varentry
.ctx
!= NULL_TREE
);
2953 entryp
->variants
->quick_push (varentry
);
2955 if (omp_declare_variant_alt
== NULL
)
2956 omp_declare_variant_alt
2957 = hash_table
<omp_declare_variant_alt_hasher
>::create_ggc (64);
2958 *omp_declare_variant_alt
->find_slot_with_hash (entryp
, DECL_UID (node
->decl
),
2962 /* Encode an oacc launch argument. This matches the GOMP_LAUNCH_PACK
2963 macro on gomp-constants.h. We do not check for overflow. */
2966 oacc_launch_pack (unsigned code
, tree device
, unsigned op
)
2970 res
= build_int_cst (unsigned_type_node
, GOMP_LAUNCH_PACK (code
, 0, op
));
2973 device
= fold_build2 (LSHIFT_EXPR
, unsigned_type_node
,
2974 device
, build_int_cst (unsigned_type_node
,
2975 GOMP_LAUNCH_DEVICE_SHIFT
));
2976 res
= fold_build2 (BIT_IOR_EXPR
, unsigned_type_node
, res
, device
);
2981 /* Openacc compute grid dimension clauses are converted to an attribute
2982 attached to the function. This permits the target-side code to (a) massage
2983 the dimensions, (b) emit that data and (c) optimize. Non-constant
2984 dimensions are pushed onto ARGS.
2986 The attribute value is a TREE_LIST. A set of dimensions is
2987 represented as a list of INTEGER_CST. Those that are runtime
2988 exprs are represented as an INTEGER_CST of zero.
2990 TODO: Normally the attribute will just contain a single such list. If
2991 however it contains a list of lists, this will represent the use of
2992 device_type. Each member of the outer list is an assoc list of
2993 dimensions, keyed by the device type. The first entry will be the
2994 default. Well, that's the plan. */
2996 /* Replace any existing oacc fn attribute in ATTRIBS with updated
3000 oacc_replace_fn_attrib_attr (tree attribs
, tree dims
)
3002 tree ident
= get_identifier (OACC_FN_ATTRIB
);
3004 /* If we happen to be present as the first attrib, drop it. */
3005 if (attribs
&& TREE_PURPOSE (attribs
) == ident
)
3006 attribs
= TREE_CHAIN (attribs
);
3007 return tree_cons (ident
, dims
, attribs
);
3010 /* Replace any existing oacc fn attribute on FN with updated
3014 oacc_replace_fn_attrib (tree fn
, tree dims
)
3016 DECL_ATTRIBUTES (fn
)
3017 = oacc_replace_fn_attrib_attr (DECL_ATTRIBUTES (fn
), dims
);
3020 /* Scan CLAUSES for launch dimensions and attach them to the oacc
3021 function attribute. Push any that are non-constant onto the ARGS
3022 list, along with an appropriate GOMP_LAUNCH_DIM tag. */
3025 oacc_set_fn_attrib (tree fn
, tree clauses
, vec
<tree
> *args
)
3027 /* Must match GOMP_DIM ordering. */
3028 static const omp_clause_code ids
[]
3029 = { OMP_CLAUSE_NUM_GANGS
, OMP_CLAUSE_NUM_WORKERS
,
3030 OMP_CLAUSE_VECTOR_LENGTH
};
3032 tree dims
[GOMP_DIM_MAX
];
3034 tree attr
= NULL_TREE
;
3035 unsigned non_const
= 0;
3037 for (ix
= GOMP_DIM_MAX
; ix
--;)
3039 tree clause
= omp_find_clause (clauses
, ids
[ix
]);
3040 tree dim
= NULL_TREE
;
3043 dim
= OMP_CLAUSE_EXPR (clause
, ids
[ix
]);
3045 if (dim
&& TREE_CODE (dim
) != INTEGER_CST
)
3047 dim
= integer_zero_node
;
3048 non_const
|= GOMP_DIM_MASK (ix
);
3050 attr
= tree_cons (NULL_TREE
, dim
, attr
);
3053 oacc_replace_fn_attrib (fn
, attr
);
3057 /* Push a dynamic argument set. */
3058 args
->safe_push (oacc_launch_pack (GOMP_LAUNCH_DIM
,
3059 NULL_TREE
, non_const
));
3060 for (unsigned ix
= 0; ix
!= GOMP_DIM_MAX
; ix
++)
3061 if (non_const
& GOMP_DIM_MASK (ix
))
3062 args
->safe_push (dims
[ix
]);
3066 /* Verify OpenACC routine clauses.
3068 Returns 0 if FNDECL should be marked with an OpenACC 'routine' directive, 1
3069 if it has already been marked in compatible way, and -1 if incompatible.
3070 Upon returning, the chain of clauses will contain exactly one clause
3071 specifying the level of parallelism. */
3074 oacc_verify_routine_clauses (tree fndecl
, tree
*clauses
, location_t loc
,
3075 const char *routine_str
)
3077 tree c_level
= NULL_TREE
;
3078 tree c_nohost
= NULL_TREE
;
3079 tree c_p
= NULL_TREE
;
3080 for (tree c
= *clauses
; c
; c_p
= c
, c
= OMP_CLAUSE_CHAIN (c
))
3081 switch (OMP_CLAUSE_CODE (c
))
3083 case OMP_CLAUSE_GANG
:
3084 case OMP_CLAUSE_WORKER
:
3085 case OMP_CLAUSE_VECTOR
:
3086 case OMP_CLAUSE_SEQ
:
3087 if (c_level
== NULL_TREE
)
3089 else if (OMP_CLAUSE_CODE (c
) == OMP_CLAUSE_CODE (c_level
))
3091 /* This has already been diagnosed in the front ends. */
3092 /* Drop the duplicate clause. */
3093 gcc_checking_assert (c_p
!= NULL_TREE
);
3094 OMP_CLAUSE_CHAIN (c_p
) = OMP_CLAUSE_CHAIN (c
);
3099 error_at (OMP_CLAUSE_LOCATION (c
),
3100 "%qs specifies a conflicting level of parallelism",
3101 omp_clause_code_name
[OMP_CLAUSE_CODE (c
)]);
3102 inform (OMP_CLAUSE_LOCATION (c_level
),
3103 "... to the previous %qs clause here",
3104 omp_clause_code_name
[OMP_CLAUSE_CODE (c_level
)]);
3105 /* Drop the conflicting clause. */
3106 gcc_checking_assert (c_p
!= NULL_TREE
);
3107 OMP_CLAUSE_CHAIN (c_p
) = OMP_CLAUSE_CHAIN (c
);
3111 case OMP_CLAUSE_NOHOST
:
3112 /* Don't worry about duplicate clauses here. */
3118 if (c_level
== NULL_TREE
)
3120 /* Default to an implicit 'seq' clause. */
3121 c_level
= build_omp_clause (loc
, OMP_CLAUSE_SEQ
);
3122 OMP_CLAUSE_CHAIN (c_level
) = *clauses
;
3125 /* In *clauses, we now have exactly one clause specifying the level of
3129 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl
));
3130 if (attr
!= NULL_TREE
)
3132 /* Diagnose if "#pragma omp declare target" has also been applied. */
3133 if (TREE_VALUE (attr
) == NULL_TREE
)
3135 /* See <https://gcc.gnu.org/PR93465>; the semantics of combining
3136 OpenACC and OpenMP 'target' are not clear. */
3138 "cannot apply %<%s%> to %qD, which has also been"
3139 " marked with an OpenMP 'declare target' directive",
3140 routine_str
, fndecl
);
3145 /* If a "#pragma acc routine" has already been applied, just verify
3146 this one for compatibility. */
3147 /* Collect previous directive's clauses. */
3148 tree c_level_p
= NULL_TREE
;
3149 tree c_nohost_p
= NULL_TREE
;
3150 for (tree c
= TREE_VALUE (attr
); c
; c
= OMP_CLAUSE_CHAIN (c
))
3151 switch (OMP_CLAUSE_CODE (c
))
3153 case OMP_CLAUSE_GANG
:
3154 case OMP_CLAUSE_WORKER
:
3155 case OMP_CLAUSE_VECTOR
:
3156 case OMP_CLAUSE_SEQ
:
3157 gcc_checking_assert (c_level_p
== NULL_TREE
);
3160 case OMP_CLAUSE_NOHOST
:
3161 gcc_checking_assert (c_nohost_p
== NULL_TREE
);
3167 gcc_checking_assert (c_level_p
!= NULL_TREE
);
3168 /* ..., and compare to current directive's, which we've already collected
3172 /* Matching level of parallelism? */
3173 if (OMP_CLAUSE_CODE (c_level
) != OMP_CLAUSE_CODE (c_level_p
))
3176 c_diag_p
= c_level_p
;
3179 /* Matching 'nohost' clauses? */
3180 if ((c_nohost
== NULL_TREE
) != (c_nohost_p
== NULL_TREE
))
3183 c_diag_p
= c_nohost_p
;
3190 if (c_diag
!= NULL_TREE
)
3191 error_at (OMP_CLAUSE_LOCATION (c_diag
),
3192 "incompatible %qs clause when applying"
3193 " %<%s%> to %qD, which has already been"
3194 " marked with an OpenACC 'routine' directive",
3195 omp_clause_code_name
[OMP_CLAUSE_CODE (c_diag
)],
3196 routine_str
, fndecl
);
3197 else if (c_diag_p
!= NULL_TREE
)
3199 "missing %qs clause when applying"
3200 " %<%s%> to %qD, which has already been"
3201 " marked with an OpenACC 'routine' directive",
3202 omp_clause_code_name
[OMP_CLAUSE_CODE (c_diag_p
)],
3203 routine_str
, fndecl
);
3206 if (c_diag_p
!= NULL_TREE
)
3207 inform (OMP_CLAUSE_LOCATION (c_diag_p
),
3208 "... with %qs clause here",
3209 omp_clause_code_name
[OMP_CLAUSE_CODE (c_diag_p
)]);
3212 /* In the front ends, we don't preserve location information for the
3213 OpenACC routine directive itself. However, that of c_level_p
3215 location_t loc_routine
= OMP_CLAUSE_LOCATION (c_level_p
);
3216 inform (loc_routine
, "... without %qs clause near to here",
3217 omp_clause_code_name
[OMP_CLAUSE_CODE (c_diag
)]);
3226 /* Process the OpenACC 'routine' directive clauses to generate an attribute
3227 for the level of parallelism. All dimensions have a size of zero
3228 (dynamic). TREE_PURPOSE is set to indicate whether that dimension
3229 can have a loop partitioned on it. non-zero indicates
3230 yes, zero indicates no. By construction once a non-zero has been
3231 reached, further inner dimensions must also be non-zero. We set
3232 TREE_VALUE to zero for the dimensions that may be partitioned and
3233 1 for the other ones -- if a loop is (erroneously) spawned at
3234 an outer level, we don't want to try and partition it. */
3237 oacc_build_routine_dims (tree clauses
)
3239 /* Must match GOMP_DIM ordering. */
3240 static const omp_clause_code ids
[]
3241 = {OMP_CLAUSE_GANG
, OMP_CLAUSE_WORKER
, OMP_CLAUSE_VECTOR
, OMP_CLAUSE_SEQ
};
3245 for (; clauses
; clauses
= OMP_CLAUSE_CHAIN (clauses
))
3246 for (ix
= GOMP_DIM_MAX
+ 1; ix
--;)
3247 if (OMP_CLAUSE_CODE (clauses
) == ids
[ix
])
3252 gcc_checking_assert (level
>= 0);
3254 tree dims
= NULL_TREE
;
3256 for (ix
= GOMP_DIM_MAX
; ix
--;)
3257 dims
= tree_cons (build_int_cst (boolean_type_node
, ix
>= level
),
3258 build_int_cst (integer_type_node
, ix
< level
), dims
);
3263 /* Retrieve the oacc function attrib and return it. Non-oacc
3264 functions will return NULL. */
3267 oacc_get_fn_attrib (tree fn
)
3269 return lookup_attribute (OACC_FN_ATTRIB
, DECL_ATTRIBUTES (fn
));
3272 /* Return true if FN is an OpenMP or OpenACC offloading function. */
3275 offloading_function_p (tree fn
)
3277 tree attrs
= DECL_ATTRIBUTES (fn
);
3278 return (lookup_attribute ("omp declare target", attrs
)
3279 || lookup_attribute ("omp target entrypoint", attrs
));
3282 /* Extract an oacc execution dimension from FN. FN must be an
3283 offloaded function or routine that has already had its execution
3284 dimensions lowered to the target-specific values. */
3287 oacc_get_fn_dim_size (tree fn
, int axis
)
3289 tree attrs
= oacc_get_fn_attrib (fn
);
3291 gcc_assert (axis
< GOMP_DIM_MAX
);
3293 tree dims
= TREE_VALUE (attrs
);
3295 dims
= TREE_CHAIN (dims
);
3297 int size
= TREE_INT_CST_LOW (TREE_VALUE (dims
));
3302 /* Extract the dimension axis from an IFN_GOACC_DIM_POS or
3303 IFN_GOACC_DIM_SIZE call. */
3306 oacc_get_ifn_dim_arg (const gimple
*stmt
)
3308 gcc_checking_assert (gimple_call_internal_fn (stmt
) == IFN_GOACC_DIM_SIZE
3309 || gimple_call_internal_fn (stmt
) == IFN_GOACC_DIM_POS
);
3310 tree arg
= gimple_call_arg (stmt
, 0);
3311 HOST_WIDE_INT axis
= TREE_INT_CST_LOW (arg
);
3313 gcc_checking_assert (axis
>= 0 && axis
< GOMP_DIM_MAX
);
3317 /* Build COMPONENT_REF and set TREE_THIS_VOLATILE and TREE_READONLY on it
3321 omp_build_component_ref (tree obj
, tree field
)
3323 tree ret
= build3 (COMPONENT_REF
, TREE_TYPE (field
), obj
, field
, NULL
);
3324 if (TREE_THIS_VOLATILE (field
))
3325 TREE_THIS_VOLATILE (ret
) |= 1;
3326 if (TREE_READONLY (field
))
3327 TREE_READONLY (ret
) |= 1;
3331 /* Return true if NAME is the name of an omp_* runtime API call. */
3333 omp_runtime_api_procname (const char *name
)
3335 if (!startswith (name
, "omp_"))
3338 static const char *omp_runtime_apis
[] =
3340 /* This array has 3 sections. First omp_* calls that don't
3341 have any suffixes. */
3350 "get_num_interop_properties",
3353 "target_associate_ptr",
3354 "target_disassociate_ptr",
3356 "target_is_accessible",
3357 "target_is_present",
3359 "target_memcpy_async",
3360 "target_memcpy_rect",
3361 "target_memcpy_rect_async",
3363 /* Now omp_* calls that are available as omp_* and omp_*_; however, the
3364 DECL_NAME is always omp_* without tailing underscore. */
3366 "destroy_allocator",
3368 "destroy_nest_lock",
3372 "get_affinity_format",
3374 "get_default_allocator",
3375 "get_default_device",
3376 "get_device_from_uid",
3379 "get_initial_device",
3381 "get_interop_rc_desc",
3383 "get_interop_type_desc",
3385 "get_max_active_levels",
3386 "get_max_task_priority",
3395 "get_partition_num_places",
3398 "get_supported_active_levels",
3400 "get_teams_thread_limit",
3410 "is_initial_device",
3412 "pause_resource_all",
3413 "set_affinity_format",
3414 "set_default_allocator",
3422 /* And finally calls available as omp_*, omp_*_ and omp_*_8_; however,
3423 as DECL_NAME only omp_* and omp_*_8 appear. */
3425 "get_ancestor_thread_num",
3426 "get_uid_from_device",
3427 "get_partition_place_nums",
3428 "get_place_num_procs",
3429 "get_place_proc_ids",
3433 "set_default_device",
3435 "set_max_active_levels",
3440 "set_teams_thread_limit"
3444 for (unsigned i
= 0; i
< ARRAY_SIZE (omp_runtime_apis
); i
++)
3446 if (omp_runtime_apis
[i
] == NULL
)
3451 size_t len
= strlen (omp_runtime_apis
[i
]);
3452 if (strncmp (name
+ 4, omp_runtime_apis
[i
], len
) == 0
3453 && (name
[4 + len
] == '\0'
3454 || (mode
> 1 && strcmp (name
+ 4 + len
, "_8") == 0)))
3460 /* Return true if FNDECL is an omp_* runtime API call. */
3463 omp_runtime_api_call (const_tree fndecl
)
3465 tree declname
= DECL_NAME (fndecl
);
3467 || (DECL_CONTEXT (fndecl
) != NULL_TREE
3468 && TREE_CODE (DECL_CONTEXT (fndecl
)) != TRANSLATION_UNIT_DECL
)
3469 || !TREE_PUBLIC (fndecl
))
3471 return omp_runtime_api_procname (IDENTIFIER_POINTER (declname
));
3474 /* See "Additional Definitions for the OpenMP API Specification" document;
3475 associated IDs are 1, 2, ... */
3476 static const char* omp_interop_fr_str
[] = {"cuda", "cuda_driver", "opencl",
3477 "sycl", "hip", "level_zero", "hsa"};
3479 /* Returns the foreign-runtime ID if found or 0 otherwise. */
3482 omp_get_fr_id_from_name (const char *str
)
3484 static_assert (GOMP_INTEROP_IFR_LAST
== ARRAY_SIZE (omp_interop_fr_str
), "");
3486 for (unsigned i
= 0; i
< ARRAY_SIZE (omp_interop_fr_str
); ++i
)
3487 if (!strcmp (str
, omp_interop_fr_str
[i
]))
3492 /* Returns the string value to a foreign-runtime integer value or NULL if value
3496 omp_get_name_from_fr_id (int fr_id
)
3498 if (fr_id
< 1 || fr_id
> (int) ARRAY_SIZE (omp_interop_fr_str
))
3500 return omp_interop_fr_str
[fr_id
-1];
3503 namespace omp_addr_tokenizer
{
3505 /* We scan an expression by recursive descent, and build a vector of
3506 "omp_addr_token *" pointers representing a "parsed" version of the
3507 expression. The grammar we use is something like this:
3510 expr [section-access]
3513 structured-expr access-method
3514 | array-base access-method
3517 structure-base component-selector
3524 | structured-expr access-method
3525 | arbitrary-expr access-method
3537 | REF_TO_POINTER_OFFSET
3539 | INDEXED_REF_TO_ARRAY
3543 INDEX_EXPR access-method
3545 component-selector::
3546 component-selector COMPONENT_REF
3547 | component-selector ARRAY_REF
3550 This tokenized form is then used both in parsing, for OpenMP clause
3551 expansion (for C and C++) and in gimplify.cc for sibling-list handling
3552 (for C, C++ and Fortran). */
3554 omp_addr_token::omp_addr_token (token_type t
, tree e
)
3559 omp_addr_token::omp_addr_token (access_method_kinds k
, tree e
)
3560 : type(ACCESS_METHOD
), expr(e
)
3565 omp_addr_token::omp_addr_token (token_type t
, structure_base_kinds k
, tree e
)
3568 u
.structure_base_kind
= k
;
3572 omp_parse_component_selector (tree
*expr0
)
3575 tree last_component
= NULL_TREE
;
3577 while (TREE_CODE (expr
) == COMPONENT_REF
3578 || TREE_CODE (expr
) == ARRAY_REF
)
3580 if (TREE_CODE (expr
) == COMPONENT_REF
)
3581 last_component
= expr
;
3583 expr
= TREE_OPERAND (expr
, 0);
3585 if (TREE_CODE (TREE_TYPE (expr
)) == REFERENCE_TYPE
)
3589 if (!last_component
)
3592 *expr0
= last_component
;
3596 /* This handles references that have had convert_from_reference called on
3597 them, and also those that haven't. */
3600 omp_parse_ref (tree
*expr0
)
3604 if (TREE_CODE (TREE_TYPE (expr
)) == REFERENCE_TYPE
)
3606 else if ((TREE_CODE (expr
) == INDIRECT_REF
3607 || (TREE_CODE (expr
) == MEM_REF
3608 && integer_zerop (TREE_OPERAND (expr
, 1))))
3609 && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr
, 0))) == REFERENCE_TYPE
)
3611 *expr0
= TREE_OPERAND (expr
, 0);
3619 omp_parse_pointer (tree
*expr0
, bool *has_offset
)
3623 *has_offset
= false;
3625 if ((TREE_CODE (expr
) == INDIRECT_REF
3626 || (TREE_CODE (expr
) == MEM_REF
3627 && integer_zerop (TREE_OPERAND (expr
, 1))))
3628 && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr
, 0))) == POINTER_TYPE
)
3630 expr
= TREE_OPERAND (expr
, 0);
3632 /* The Fortran FE sometimes emits a no-op cast here. */
3637 if (TREE_CODE (expr
) == COMPOUND_EXPR
)
3639 expr
= TREE_OPERAND (expr
, 1);
3642 else if (TREE_CODE (expr
) == SAVE_EXPR
)
3643 expr
= TREE_OPERAND (expr
, 0);
3644 else if (TREE_CODE (expr
) == POINTER_PLUS_EXPR
)
3647 expr
= TREE_OPERAND (expr
, 0);
3663 omp_parse_access_method (tree
*expr0
, enum access_method_kinds
*kind
)
3668 if (omp_parse_ref (&expr
))
3670 else if (omp_parse_pointer (&expr
, &has_offset
))
3672 if (omp_parse_ref (&expr
))
3673 *kind
= has_offset
? ACCESS_REF_TO_POINTER_OFFSET
3674 : ACCESS_REF_TO_POINTER
;
3676 *kind
= has_offset
? ACCESS_POINTER_OFFSET
: ACCESS_POINTER
;
3678 else if (TREE_CODE (expr
) == ARRAY_REF
)
3680 while (TREE_CODE (expr
) == ARRAY_REF
)
3681 expr
= TREE_OPERAND (expr
, 0);
3682 if (omp_parse_ref (&expr
))
3683 *kind
= ACCESS_INDEXED_REF_TO_ARRAY
;
3685 *kind
= ACCESS_INDEXED_ARRAY
;
3688 *kind
= ACCESS_DIRECT
;
3697 omp_parse_access_methods (vec
<omp_addr_token
*> &addr_tokens
, tree
*expr0
)
3700 enum access_method_kinds kind
;
3703 if (omp_parse_access_method (&expr
, &kind
))
3706 if (TREE_CODE (expr
) == INDIRECT_REF
3707 || TREE_CODE (expr
) == MEM_REF
3708 || TREE_CODE (expr
) == ARRAY_REF
)
3709 omp_parse_access_methods (addr_tokens
, &expr
);
3711 addr_tokens
.safe_push (new omp_addr_token (kind
, am_expr
));
3717 static bool omp_parse_structured_expr (vec
<omp_addr_token
*> &, tree
*);
3720 omp_parse_structure_base (vec
<omp_addr_token
*> &addr_tokens
,
3721 tree
*expr0
, structure_base_kinds
*kind
,
3722 vec
<omp_addr_token
*> &base_access_tokens
,
3723 bool allow_structured
= true)
3727 if (allow_structured
)
3728 omp_parse_access_methods (base_access_tokens
, &expr
);
3736 if (allow_structured
&& omp_parse_structured_expr (addr_tokens
, &expr
))
3738 *kind
= BASE_COMPONENT_EXPR
;
3743 *kind
= BASE_ARBITRARY_EXPR
;
3749 omp_parse_structured_expr (vec
<omp_addr_token
*> &addr_tokens
, tree
*expr0
)
3752 tree base_component
= NULL_TREE
;
3753 structure_base_kinds struct_base_kind
;
3754 auto_vec
<omp_addr_token
*> base_access_tokens
;
3756 if (omp_parse_component_selector (&expr
))
3757 base_component
= expr
;
3761 gcc_assert (TREE_CODE (expr
) == COMPONENT_REF
);
3762 expr
= TREE_OPERAND (expr
, 0);
3764 tree structure_base
= expr
;
3766 if (!omp_parse_structure_base (addr_tokens
, &expr
, &struct_base_kind
,
3767 base_access_tokens
))
3770 addr_tokens
.safe_push (new omp_addr_token (STRUCTURE_BASE
, struct_base_kind
,
3772 addr_tokens
.safe_splice (base_access_tokens
);
3773 addr_tokens
.safe_push (new omp_addr_token (COMPONENT_SELECTOR
,
3782 omp_parse_array_expr (vec
<omp_addr_token
*> &addr_tokens
, tree
*expr0
)
3785 structure_base_kinds s_kind
;
3786 auto_vec
<omp_addr_token
*> base_access_tokens
;
3788 if (!omp_parse_structure_base (addr_tokens
, &expr
, &s_kind
,
3789 base_access_tokens
, false))
3792 addr_tokens
.safe_push (new omp_addr_token (ARRAY_BASE
, s_kind
, expr
));
3793 addr_tokens
.safe_splice (base_access_tokens
);
3799 /* Return TRUE if the ACCESS_METHOD token at index 'i' has a further
3800 ACCESS_METHOD chained after it (e.g., if we're processing an expression
3801 containing multiple pointer indirections). */
3804 omp_access_chain_p (vec
<omp_addr_token
*> &addr_tokens
, unsigned i
)
3806 gcc_assert (addr_tokens
[i
]->type
== ACCESS_METHOD
);
3807 return (i
+ 1 < addr_tokens
.length ()
3808 && addr_tokens
[i
+ 1]->type
== ACCESS_METHOD
);
3811 /* Return the address of the object accessed by the ACCESS_METHOD token
3812 at 'i': either of the next access method's expr, or of EXPR if we're at
3813 the end of the list of tokens. */
3816 omp_accessed_addr (vec
<omp_addr_token
*> &addr_tokens
, unsigned i
, tree expr
)
3818 if (i
+ 1 < addr_tokens
.length ())
3819 return build_fold_addr_expr (addr_tokens
[i
+ 1]->expr
);
3821 return build_fold_addr_expr (expr
);
3824 } /* namespace omp_addr_tokenizer. */
3827 omp_parse_expr (vec
<omp_addr_token
*> &addr_tokens
, tree expr
)
3829 using namespace omp_addr_tokenizer
;
3830 auto_vec
<omp_addr_token
*> expr_access_tokens
;
3832 if (!omp_parse_access_methods (expr_access_tokens
, &expr
))
3835 if (omp_parse_structured_expr (addr_tokens
, &expr
))
3837 else if (omp_parse_array_expr (addr_tokens
, &expr
))
3842 addr_tokens
.safe_splice (expr_access_tokens
);
3848 debug_omp_tokenized_addr (vec
<omp_addr_token
*> &addr_tokens
,
3851 using namespace omp_addr_tokenizer
;
3852 const char *sep
= with_exprs
? " " : "";
3854 for (auto e
: addr_tokens
)
3856 const char *pfx
= "";
3858 fputs (sep
, stderr
);
3862 case COMPONENT_SELECTOR
:
3863 fputs ("component_selector", stderr
);
3866 switch (e
->u
.access_kind
)
3869 fputs ("access_direct", stderr
);
3872 fputs ("access_ref", stderr
);
3874 case ACCESS_POINTER
:
3875 fputs ("access_pointer", stderr
);
3877 case ACCESS_POINTER_OFFSET
:
3878 fputs ("access_pointer_offset", stderr
);
3880 case ACCESS_REF_TO_POINTER
:
3881 fputs ("access_ref_to_pointer", stderr
);
3883 case ACCESS_REF_TO_POINTER_OFFSET
:
3884 fputs ("access_ref_to_pointer_offset", stderr
);
3886 case ACCESS_INDEXED_ARRAY
:
3887 fputs ("access_indexed_array", stderr
);
3889 case ACCESS_INDEXED_REF_TO_ARRAY
:
3890 fputs ("access_indexed_ref_to_array", stderr
);
3895 case STRUCTURE_BASE
:
3896 pfx
= e
->type
== ARRAY_BASE
? "array_" : "struct_";
3897 switch (e
->u
.structure_base_kind
)
3900 fprintf (stderr
, "%sbase_decl", pfx
);
3902 case BASE_COMPONENT_EXPR
:
3903 fputs ("base_component_expr", stderr
);
3905 case BASE_ARBITRARY_EXPR
:
3906 fprintf (stderr
, "%sbase_arbitrary_expr", pfx
);
3913 fputs (" [", stderr
);
3914 print_generic_expr (stderr
, e
->expr
);
3915 fputc (']', stderr
);
3922 fputs ("\n", stderr
);
3925 /* Return number of iterations of loop I in FOR_STMT. If PSTEP is non-NULL,
3926 *PSTEP will be the loop step. */
3929 omp_loop_number_of_iterations (tree for_stmt
, int i
, tree
*pstep
)
3931 tree t
= TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), i
);
3932 gcc_assert (TREE_CODE (t
) == MODIFY_EXPR
);
3933 tree decl
= TREE_OPERAND (t
, 0);
3934 tree n1
= TREE_OPERAND (t
, 1);
3935 tree type
= TREE_TYPE (decl
);
3936 tree cond
= TREE_VEC_ELT (OMP_FOR_COND (for_stmt
), i
);
3937 gcc_assert (COMPARISON_CLASS_P (cond
));
3938 gcc_assert (TREE_OPERAND (cond
, 0) == decl
);
3939 tree_code cond_code
= TREE_CODE (cond
);
3940 tree n2
= TREE_OPERAND (cond
, 1);
3941 t
= TREE_VEC_ELT (OMP_FOR_INCR (for_stmt
), i
);
3942 tree step
= NULL_TREE
;
3943 switch (TREE_CODE (t
))
3945 case PREINCREMENT_EXPR
:
3946 case POSTINCREMENT_EXPR
:
3947 gcc_assert (!POINTER_TYPE_P (type
));
3948 gcc_assert (TREE_OPERAND (t
, 0) == decl
);
3949 step
= build_int_cst (type
, 1);
3951 case PREDECREMENT_EXPR
:
3952 case POSTDECREMENT_EXPR
:
3953 gcc_assert (!POINTER_TYPE_P (type
));
3954 gcc_assert (TREE_OPERAND (t
, 0) == decl
);
3955 step
= build_int_cst (type
, -1);
3958 gcc_assert (TREE_OPERAND (t
, 0) == decl
);
3959 t
= TREE_OPERAND (t
, 1);
3960 switch (TREE_CODE (t
))
3963 if (TREE_OPERAND (t
, 1) == decl
)
3965 TREE_OPERAND (t
, 1) = TREE_OPERAND (t
, 0);
3966 TREE_OPERAND (t
, 0) = decl
;
3969 case POINTER_PLUS_EXPR
:
3971 step
= omp_get_for_step_from_incr (EXPR_LOCATION (t
), t
);
3980 omp_adjust_for_condition (EXPR_LOCATION (for_stmt
), &cond_code
, &n2
,
3984 if (INTEGRAL_TYPE_P (type
)
3985 && TYPE_PRECISION (type
) < TYPE_PRECISION (long_long_integer_type_node
))
3987 n1
= fold_convert (long_long_integer_type_node
, n1
);
3988 n2
= fold_convert (long_long_integer_type_node
, n2
);
3989 step
= fold_convert (long_long_integer_type_node
, step
);
3991 if (cond_code
== LT_EXPR
3992 || POINTER_TYPE_P (type
)
3993 || !TYPE_UNSIGNED (TREE_TYPE (n1
)))
3995 if (POINTER_TYPE_P (type
))
3996 t
= fold_build2 (POINTER_DIFF_EXPR
, ssizetype
, n2
, n1
);
3998 t
= fold_build2 (MINUS_EXPR
, TREE_TYPE (n1
), n2
, n1
);
3999 t
= fold_build2 (CEIL_DIV_EXPR
, TREE_TYPE (t
), t
, step
);
4003 t
= fold_build2 (MINUS_EXPR
, type
, n1
, n2
);
4004 t
= fold_build2 (CEIL_DIV_EXPR
, type
, t
,
4005 fold_build1 (NEGATE_EXPR
, type
, step
));
4010 /* Tile transformation:
4013 #pragma omp tile sizes(16, 32)
4014 for (i = 0; i < k; ++i)
4015 for (j = 0; j < 128; j += 2)
4021 #pragma omp tile sizes(16, 32)
4022 for (i.0 = 0; i.0 < k; i.0 += 16)
4023 for (j.0 = 0; j.0 < 128; j.0 += 64)
4026 i.1 = MIN_EXPR <i.0 + 16, k>;
4038 if (j < j.1) goto <D.2785>; else goto <D.2787>;
4042 if (i < i.1) goto <D.2782>; else goto <D.2784>;
4046 where the grid loops have canonical form, but the inner
4047 loops don't and so are immediately lowered. */
4050 omp_apply_tile (tree for_stmt
, tree sizes
, int size
)
4052 tree pre_body
= NULL_TREE
, post_body
= NULL_TREE
;
4053 tree orig_sizes
= sizes
;
4054 if (OMP_FOR_NON_RECTANGULAR (for_stmt
))
4056 error_at (EXPR_LOCATION (for_stmt
), "non-rectangular %<tile%>");
4059 for (int i
= 0; i
< TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt
)); i
++)
4063 size
= tree_to_uhwi (TREE_VALUE (sizes
));
4064 sizes
= TREE_CHAIN (sizes
);
4068 if (OMP_FOR_ORIG_DECLS (for_stmt
) == NULL_TREE
)
4070 OMP_FOR_ORIG_DECLS (for_stmt
)
4071 = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt
)));
4072 for (int j
= 0; j
< TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt
)); j
++)
4074 gcc_assert (TREE_CODE (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), j
))
4076 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt
), j
)
4077 = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), j
), 0);
4081 tree iters
= omp_loop_number_of_iterations (for_stmt
, i
, &step
);
4082 tree t
= TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), i
);
4083 tree decl
= TREE_OPERAND (t
, 0);
4084 tree type
= TREE_TYPE (decl
);
4085 tree griddecl
= create_tmp_var_raw (type
);
4086 DECL_CONTEXT (griddecl
) = current_function_decl
;
4087 t
= build1 (DECL_EXPR
, void_type_node
, griddecl
);
4088 append_to_statement_list (t
, &OMP_FOR_PRE_BODY (for_stmt
));
4089 TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), i
), 0) = griddecl
;
4090 TREE_PRIVATE (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), i
)) = 1;
4091 tree cond
= TREE_VEC_ELT (OMP_FOR_COND (for_stmt
), i
);
4092 TREE_OPERAND (cond
, 0) = griddecl
;
4093 tree ub
= save_expr (TREE_OPERAND (cond
, 1));
4094 TREE_OPERAND (cond
, 1) = ub
;
4095 t
= TREE_VEC_ELT (OMP_FOR_INCR (for_stmt
), i
);
4096 if (TREE_CODE (cond
) == NE_EXPR
)
4098 tree_code cond_code
= TREE_CODE (cond
);
4099 omp_adjust_for_condition (EXPR_LOCATION (for_stmt
), &cond_code
,
4100 &ub
, griddecl
, step
);
4101 TREE_SET_CODE (cond
, cond_code
);
4103 step
= save_expr (step
);
4104 tree gridstep
= fold_build2 (MULT_EXPR
, TREE_TYPE (step
),
4105 step
, build_int_cst (TREE_TYPE (step
),
4107 if (POINTER_TYPE_P (type
))
4108 t
= build2 (POINTER_PLUS_EXPR
, type
, griddecl
,
4109 fold_convert (sizetype
, gridstep
));
4111 t
= build2 (PLUS_EXPR
, type
, griddecl
, gridstep
);
4112 t
= build2 (MODIFY_EXPR
, type
, griddecl
, t
);
4113 TREE_VEC_ELT (OMP_FOR_INCR (for_stmt
), i
) = t
;
4114 t
= build2 (MODIFY_EXPR
, type
, decl
, griddecl
);
4115 append_to_statement_list (t
, &pre_body
);
4116 if (POINTER_TYPE_P (type
))
4117 t
= build2 (POINTER_PLUS_EXPR
, type
, griddecl
,
4118 fold_convert (sizetype
, gridstep
));
4120 t
= build2 (PLUS_EXPR
, type
, griddecl
, gridstep
);
4121 bool minmax_needed
= true;
4122 if (TREE_CODE (iters
) == INTEGER_CST
)
4124 wide_int witers
= wi::to_wide (iters
);
4125 wide_int wsize
= wide_int::from (size
, witers
.get_precision (),
4126 TYPE_SIGN (TREE_TYPE (iters
)));
4127 if (wi::multiple_of_p (witers
, wsize
, TYPE_SIGN (TREE_TYPE (iters
))))
4128 minmax_needed
= false;
4131 switch (TREE_CODE (cond
))
4134 if (POINTER_TYPE_P (type
))
4135 t
= build2 (MIN_EXPR
, type
, t
,
4136 build2 (POINTER_PLUS_EXPR
, type
, ub
, size_int (1)));
4138 t
= build2 (MIN_EXPR
, type
, t
,
4139 build2 (PLUS_EXPR
, type
, ub
, build_one_cst (type
)));
4142 t
= build2 (MIN_EXPR
, type
, t
, ub
);
4145 if (POINTER_TYPE_P (type
))
4146 t
= build2 (MAX_EXPR
, type
, t
,
4147 build2 (POINTER_PLUS_EXPR
, type
, ub
, size_int (-1)));
4149 t
= build2 (MAX_EXPR
, type
, t
,
4150 build2 (PLUS_EXPR
, type
, ub
,
4151 build_minus_one_cst (type
)));
4154 t
= build2 (MAX_EXPR
, type
, t
, ub
);
4159 tree end
= create_tmp_var_raw (type
);
4160 DECL_CONTEXT (end
) = current_function_decl
;
4161 end
= build4 (TARGET_EXPR
, type
, end
, t
, NULL_TREE
, NULL_TREE
);
4162 TREE_SIDE_EFFECTS (end
) = 1;
4163 append_to_statement_list (end
, &pre_body
);
4164 tree lab1
= create_artificial_label (UNKNOWN_LOCATION
);
4165 tree lab2
= create_artificial_label (UNKNOWN_LOCATION
);
4166 t
= build1 (GOTO_EXPR
, void_type_node
, lab2
);
4167 append_to_statement_list (t
, &pre_body
);
4168 t
= build1 (LABEL_EXPR
, void_type_node
, lab1
);
4169 append_to_statement_list (t
, &pre_body
);
4170 tree this_post_body
= NULL_TREE
;
4171 if (POINTER_TYPE_P (type
))
4172 t
= build2 (POINTER_PLUS_EXPR
, type
, decl
,
4173 fold_convert (sizetype
, step
));
4175 t
= build2 (PLUS_EXPR
, type
, decl
, step
);
4176 t
= build2 (MODIFY_EXPR
, type
, decl
, t
);
4177 append_to_statement_list (t
, &this_post_body
);
4178 t
= build1 (LABEL_EXPR
, void_type_node
, lab2
);
4179 append_to_statement_list (t
, &this_post_body
);
4180 t
= build2 ((TREE_CODE (cond
) == LT_EXPR
|| TREE_CODE (cond
) == LE_EXPR
)
4181 ? LT_EXPR
: GT_EXPR
, boolean_type_node
, decl
, end
);
4182 if (orig_sizes
== NULL_TREE
)
4184 gcc_assert (i
== 0);
4185 t
= build3 (ANNOTATE_EXPR
, TREE_TYPE (t
), t
,
4186 build_int_cst (integer_type_node
,
4187 annot_expr_unroll_kind
),
4188 build_int_cst (integer_type_node
, size
));
4190 t
= build3 (COND_EXPR
, void_type_node
, t
,
4191 build1 (GOTO_EXPR
, void_type_node
, lab1
), NULL_TREE
);
4192 append_to_statement_list (t
, &this_post_body
);
4193 append_to_statement_list (post_body
, &this_post_body
);
4194 post_body
= this_post_body
;
4196 if (pre_body
|| post_body
)
4198 append_to_statement_list (OMP_FOR_BODY (for_stmt
), &pre_body
);
4199 append_to_statement_list (post_body
, &pre_body
);
4200 OMP_FOR_BODY (for_stmt
) = pre_body
;
4204 /* Callback for walk_tree to find nested loop transforming construct. */
4207 find_nested_loop_xform (tree
*tp
, int *walk_subtrees
, void *data
)
4209 tree
**pdata
= (tree
**) data
;
4211 switch (TREE_CODE (*tp
))
4218 if (BIND_EXPR_VARS (*tp
)
4219 || (BIND_EXPR_BLOCK (*tp
)
4220 && BLOCK_VARS (BIND_EXPR_BLOCK (*tp
))))
4224 case STATEMENT_LIST
:
4225 if (!tsi_one_before_end_p (tsi_start (*tp
)))
4229 case TRY_FINALLY_EXPR
:
4230 case CLEANUP_POINT_EXPR
:
4240 /* Main entry point for performing OpenMP loop transformations. */
4243 omp_maybe_apply_loop_xforms (tree
*expr_p
, tree for_clauses
)
4245 tree for_stmt
= *expr_p
;
4247 switch (TREE_CODE (for_stmt
))
4251 if (OMP_LOOPXFORM_LOWERED (for_stmt
))
4258 tree
*inner_expr_p
= expr_p
;
4259 tree inner_for_stmt
= for_stmt
;
4260 for (int i
= 0; i
< TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt
)); i
++)
4262 /* If some loop nest needs one or more loops in canonical form
4263 from nested loop transforming constructs, first perform the
4264 loop transformation on the nested construct and then move over
4265 the corresponding loops in canonical form from the inner construct
4266 to the outer one. */
4267 if (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), i
) == NULL_TREE
)
4269 if (inner_for_stmt
== for_stmt
4270 && omp_find_clause (for_clauses
? for_clauses
4271 : OMP_FOR_CLAUSES (for_stmt
),
4272 OMP_CLAUSE_ORDERED
))
4274 error_at (EXPR_LOCATION (for_stmt
),
4275 "%<ordered%> clause used with generated loops");
4276 *expr_p
= void_node
;
4279 tree
*data
[2] = { NULL
, NULL
};
4280 walk_tree (&OMP_FOR_BODY (inner_for_stmt
),
4281 find_nested_loop_xform
, &data
, NULL
);
4282 gcc_assert (data
[1]);
4285 /* If there is a BIND_EXPR declaring some vars, or statement
4286 list with more than one stmt etc., move the intervening
4287 code around the outermost loop. */
4288 tree t
= *inner_expr_p
;
4289 *inner_expr_p
= OMP_FOR_BODY (inner_for_stmt
);
4290 OMP_FOR_BODY (inner_for_stmt
) = *data
[1];
4292 inner_expr_p
= data
[1];
4293 data
[1] = &OMP_FOR_BODY (inner_for_stmt
);
4295 inner_for_stmt
= *data
[1];
4297 omp_maybe_apply_loop_xforms (data
[1], NULL_TREE
);
4298 if (*data
[1] != inner_for_stmt
)
4300 tree
*data2
[2] = { NULL
, NULL
};
4301 walk_tree (data
[1], find_nested_loop_xform
, &data2
, NULL
);
4302 gcc_assert (data2
[1]
4303 && *data2
[1] == inner_for_stmt
4305 tree t
= *inner_expr_p
;
4306 *inner_expr_p
= *data
[1];
4307 *data
[1] = *data2
[1];
4309 inner_expr_p
= data2
[1];
4311 tree clauses
= OMP_FOR_CLAUSES (inner_for_stmt
);
4312 gcc_checking_assert (TREE_CODE (inner_for_stmt
) != OMP_UNROLL
4313 || omp_find_clause (clauses
,
4314 OMP_CLAUSE_PARTIAL
));
4315 append_to_statement_list (OMP_FOR_PRE_BODY (inner_for_stmt
),
4316 &OMP_FOR_PRE_BODY (for_stmt
));
4317 OMP_FOR_PRE_BODY (inner_for_stmt
) = NULL_TREE
;
4318 if (OMP_FOR_ORIG_DECLS (for_stmt
) == NULL_TREE
4319 && OMP_FOR_ORIG_DECLS (inner_for_stmt
) != NULL_TREE
)
4321 OMP_FOR_ORIG_DECLS (for_stmt
)
4322 = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt
)));
4323 for (int j
= 0; j
< TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt
));
4326 if (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), j
) == NULL_TREE
)
4328 gcc_assert (TREE_CODE (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
),
4329 j
)) == MODIFY_EXPR
);
4330 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt
), j
)
4331 = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), j
),
4335 for (int j
= 0; j
< TREE_VEC_LENGTH (OMP_FOR_INIT (inner_for_stmt
));
4338 if (i
+ j
== TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt
)))
4340 if (OMP_FOR_ORIG_DECLS (for_stmt
))
4342 if (OMP_FOR_ORIG_DECLS (inner_for_stmt
))
4344 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt
), i
+ j
)
4345 = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt
),
4347 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt
), j
)
4352 tree t
= TREE_VEC_ELT (OMP_FOR_INIT (inner_for_stmt
), j
);
4353 gcc_assert (TREE_CODE (t
) == MODIFY_EXPR
);
4354 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt
), i
+ j
)
4355 = TREE_OPERAND (t
, 0);
4358 TREE_VEC_ELT (OMP_FOR_INIT (for_stmt
), i
+ j
)
4359 = TREE_VEC_ELT (OMP_FOR_INIT (inner_for_stmt
), j
);
4360 TREE_VEC_ELT (OMP_FOR_COND (for_stmt
), i
+ j
)
4361 = TREE_VEC_ELT (OMP_FOR_COND (inner_for_stmt
), j
);
4362 TREE_VEC_ELT (OMP_FOR_INCR (for_stmt
), i
+ j
)
4363 = TREE_VEC_ELT (OMP_FOR_INCR (inner_for_stmt
), j
);
4364 TREE_VEC_ELT (OMP_FOR_INIT (inner_for_stmt
), j
) = NULL_TREE
;
4365 TREE_VEC_ELT (OMP_FOR_COND (inner_for_stmt
), j
) = NULL_TREE
;
4366 TREE_VEC_ELT (OMP_FOR_INCR (inner_for_stmt
), j
) = NULL_TREE
;
4371 switch (TREE_CODE (for_stmt
))
4375 sizes
= omp_find_clause (OMP_FOR_CLAUSES (for_stmt
), OMP_CLAUSE_SIZES
);
4376 omp_apply_tile (for_stmt
, OMP_CLAUSE_SIZES_LIST (sizes
), 0);
4377 OMP_LOOPXFORM_LOWERED (for_stmt
) = 1;
4381 partial
= omp_find_clause (OMP_FOR_CLAUSES (for_stmt
),
4382 OMP_CLAUSE_PARTIAL
);
4384 omp_apply_tile (for_stmt
, NULL_TREE
,
4385 OMP_CLAUSE_PARTIAL_EXPR (partial
)
4386 ? tree_to_shwi (OMP_CLAUSE_PARTIAL_EXPR (partial
))
4388 else if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt
), OMP_CLAUSE_FULL
))
4390 tree iters
= omp_loop_number_of_iterations (for_stmt
, 0, NULL
);
4391 if (TREE_CODE (iters
) != INTEGER_CST
)
4392 error_at (EXPR_LOCATION (for_stmt
),
4393 "non-constant iteration count of %<unroll full%> loop");
4395 OMP_LOOPXFORM_LOWERED (for_stmt
) = 1;
4402 #include "gt-omp-general.h"