Daily bump.
[official-gcc.git] / gcc / omp-general.cc
blobbd4648f196f67380a50bb3a54a995fe8f068fc59
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
11 version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "backend.h"
26 #include "target.h"
27 #include "tree.h"
28 #include "gimple.h"
29 #include "ssa.h"
30 #include "diagnostic-core.h"
31 #include "fold-const.h"
32 #include "langhooks.h"
33 #include "omp-general.h"
34 #include "stringpool.h"
35 #include "attribs.h"
36 #include "gimplify.h"
37 #include "cgraph.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"
45 #include "opts.h"
46 #include "tree-pretty-print.h"
48 enum omp_requires omp_requires_mask;
50 /* Find an OMP clause of type KIND within CLAUSES. */
51 tree
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)
56 return clauses;
58 return NULL_TREE;
61 /* True if OpenMP should regard this DECL as being a scalar which has Fortran's
62 allocatable or pointer attribute. */
63 bool
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. */
77 tree
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. */
85 bool
86 omp_mappable_type (tree type)
88 /* Mappable type has to be complete. */
89 if (type == error_mark_node || !COMPLETE_TYPE_P (type))
90 return false;
91 return true;
94 /* True if OpenMP should privatize what this DECL points to rather
95 than the DECL itself. */
97 bool
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. */
106 void
107 omp_adjust_for_condition (location_t loc, enum tree_code *cond_code, tree *n2,
108 tree v, tree step)
110 switch (*cond_code)
112 case LT_EXPR:
113 case GT_EXPR:
114 break;
116 case NE_EXPR:
117 gcc_assert (TREE_CODE (step) == INTEGER_CST);
118 if (TREE_CODE (TREE_TYPE (v)) == INTEGER_TYPE)
120 if (integer_onep (step))
121 *cond_code = LT_EXPR;
122 else
124 gcc_assert (integer_minus_onep (step));
125 *cond_code = GT_EXPR;
128 else
130 tree unit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v)));
131 gcc_assert (TREE_CODE (unit) == INTEGER_CST);
132 if (tree_int_cst_equal (unit, step))
133 *cond_code = LT_EXPR;
134 else
136 gcc_assert (wi::neg (wi::to_widest (unit))
137 == wi::to_widest (step));
138 *cond_code = GT_EXPR;
142 break;
144 case LE_EXPR:
145 if (POINTER_TYPE_P (TREE_TYPE (*n2)))
146 *n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, 1);
147 else
148 *n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (*n2), *n2,
149 build_int_cst (TREE_TYPE (*n2), 1));
150 *cond_code = LT_EXPR;
151 break;
152 case GE_EXPR:
153 if (POINTER_TYPE_P (TREE_TYPE (*n2)))
154 *n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, -1);
155 else
156 *n2 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (*n2), *n2,
157 build_int_cst (TREE_TYPE (*n2), 1));
158 *cond_code = GT_EXPR;
159 break;
160 default:
161 gcc_unreachable ();
165 /* Return the looping step from INCR, extracted from the step of a gimple omp
166 for statement. */
168 tree
169 omp_get_for_step_from_incr (location_t loc, tree incr)
171 tree step;
172 switch (TREE_CODE (incr))
174 case PLUS_EXPR:
175 step = TREE_OPERAND (incr, 1);
176 break;
177 case POINTER_PLUS_EXPR:
178 step = fold_convert (ssizetype, TREE_OPERAND (incr, 1));
179 break;
180 case MINUS_EXPR:
181 step = TREE_OPERAND (incr, 1);
182 step = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (step), step);
183 break;
184 default:
185 gcc_unreachable ();
187 return step;
190 /* Extract the header elements of parallel loop FOR_STMT and store
191 them into *FD. */
193 void
194 omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
195 struct omp_for_data_loop *loops)
197 tree t, var, *collapse_iter, *collapse_count;
198 tree count = NULL_TREE, iter_type = long_integer_type_node;
199 struct omp_for_data_loop *loop;
200 int i;
201 struct omp_for_data_loop dummy_loop;
202 location_t loc = gimple_location (for_stmt);
203 bool simd = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD;
204 bool distribute = gimple_omp_for_kind (for_stmt)
205 == GF_OMP_FOR_KIND_DISTRIBUTE;
206 bool taskloop = gimple_omp_for_kind (for_stmt)
207 == GF_OMP_FOR_KIND_TASKLOOP;
208 bool order_reproducible = false;
209 tree iterv, countv;
211 fd->for_stmt = for_stmt;
212 fd->pre = NULL;
213 fd->have_nowait = distribute || simd;
214 fd->have_ordered = false;
215 fd->have_reductemp = false;
216 fd->have_pointer_condtemp = false;
217 fd->have_scantemp = false;
218 fd->have_nonctrl_scantemp = false;
219 fd->non_rect = false;
220 fd->lastprivate_conditional = 0;
221 fd->tiling = NULL_TREE;
222 fd->collapse = 1;
223 fd->ordered = 0;
224 fd->first_nonrect = -1;
225 fd->last_nonrect = -1;
226 fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
227 fd->sched_modifiers = 0;
228 fd->chunk_size = NULL_TREE;
229 fd->simd_schedule = false;
230 fd->first_inner_iterations = NULL_TREE;
231 fd->factor = NULL_TREE;
232 fd->adjn1 = NULL_TREE;
233 collapse_iter = NULL;
234 collapse_count = NULL;
236 for (t = gimple_omp_for_clauses (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t))
237 switch (OMP_CLAUSE_CODE (t))
239 case OMP_CLAUSE_NOWAIT:
240 fd->have_nowait = true;
241 break;
242 case OMP_CLAUSE_ORDERED:
243 fd->have_ordered = true;
244 if (OMP_CLAUSE_ORDERED_DOACROSS (t))
246 if (OMP_CLAUSE_ORDERED_EXPR (t))
247 fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t));
248 else
249 fd->ordered = -1;
251 break;
252 case OMP_CLAUSE_SCHEDULE:
253 gcc_assert (!distribute && !taskloop);
254 fd->sched_kind
255 = (enum omp_clause_schedule_kind)
256 (OMP_CLAUSE_SCHEDULE_KIND (t) & OMP_CLAUSE_SCHEDULE_MASK);
257 fd->sched_modifiers = (OMP_CLAUSE_SCHEDULE_KIND (t)
258 & ~OMP_CLAUSE_SCHEDULE_MASK);
259 fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
260 fd->simd_schedule = OMP_CLAUSE_SCHEDULE_SIMD (t);
261 break;
262 case OMP_CLAUSE_DIST_SCHEDULE:
263 gcc_assert (distribute);
264 fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t);
265 break;
266 case OMP_CLAUSE_COLLAPSE:
267 fd->collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t));
268 if (fd->collapse > 1)
270 collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t);
271 collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t);
273 break;
274 case OMP_CLAUSE_TILE:
275 fd->tiling = OMP_CLAUSE_TILE_LIST (t);
276 fd->collapse = list_length (fd->tiling);
277 gcc_assert (fd->collapse);
278 collapse_iter = &OMP_CLAUSE_TILE_ITERVAR (t);
279 collapse_count = &OMP_CLAUSE_TILE_COUNT (t);
280 break;
281 case OMP_CLAUSE__REDUCTEMP_:
282 fd->have_reductemp = true;
283 break;
284 case OMP_CLAUSE_LASTPRIVATE:
285 if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (t))
286 fd->lastprivate_conditional++;
287 break;
288 case OMP_CLAUSE__CONDTEMP_:
289 if (POINTER_TYPE_P (TREE_TYPE (OMP_CLAUSE_DECL (t))))
290 fd->have_pointer_condtemp = true;
291 break;
292 case OMP_CLAUSE__SCANTEMP_:
293 fd->have_scantemp = true;
294 if (!OMP_CLAUSE__SCANTEMP__ALLOC (t)
295 && !OMP_CLAUSE__SCANTEMP__CONTROL (t))
296 fd->have_nonctrl_scantemp = true;
297 break;
298 case OMP_CLAUSE_ORDER:
299 /* FIXME: For OpenMP 5.2 this should change to
300 if (OMP_CLAUSE_ORDER_REPRODUCIBLE (t))
301 (with the exception of loop construct but that lowers to
302 no schedule/dist_schedule clauses currently). */
303 if (!OMP_CLAUSE_ORDER_UNCONSTRAINED (t))
304 order_reproducible = true;
305 default:
306 break;
309 if (fd->ordered == -1)
310 fd->ordered = fd->collapse;
312 /* For order(reproducible:concurrent) schedule ({dynamic,guided,runtime})
313 we have either the option to expensively remember at runtime how we've
314 distributed work from first loop and reuse that in following loops with
315 the same number of iterations and schedule, or just force static schedule.
316 OpenMP API calls etc. aren't allowed in order(concurrent) bodies so
317 users can't observe it easily anyway. */
318 if (order_reproducible)
319 fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
320 if (fd->collapse > 1 || fd->tiling)
321 fd->loops = loops;
322 else
323 fd->loops = &fd->loop;
325 if (fd->ordered && fd->collapse == 1 && loops != NULL)
327 fd->loops = loops;
328 iterv = NULL_TREE;
329 countv = NULL_TREE;
330 collapse_iter = &iterv;
331 collapse_count = &countv;
334 /* FIXME: for now map schedule(auto) to schedule(static).
335 There should be analysis to determine whether all iterations
336 are approximately the same amount of work (then schedule(static)
337 is best) or if it varies (then schedule(dynamic,N) is better). */
338 if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO)
340 fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
341 gcc_assert (fd->chunk_size == NULL);
343 gcc_assert ((fd->collapse == 1 && !fd->tiling) || collapse_iter != NULL);
344 if (taskloop)
345 fd->sched_kind = OMP_CLAUSE_SCHEDULE_RUNTIME;
346 if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
347 gcc_assert (fd->chunk_size == NULL);
348 else if (fd->chunk_size == NULL)
350 /* We only need to compute a default chunk size for ordered
351 static loops and dynamic loops. */
352 if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
353 || fd->have_ordered)
354 fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
355 ? integer_zero_node : integer_one_node;
358 int cnt = fd->ordered ? fd->ordered : fd->collapse;
359 int single_nonrect = -1;
360 tree single_nonrect_count = NULL_TREE;
361 enum tree_code single_nonrect_cond_code = ERROR_MARK;
362 for (i = 1; i < cnt; i++)
364 tree n1 = gimple_omp_for_initial (for_stmt, i);
365 tree n2 = gimple_omp_for_final (for_stmt, i);
366 if (TREE_CODE (n1) == TREE_VEC)
368 if (fd->non_rect)
370 single_nonrect = -1;
371 break;
373 for (int j = i - 1; j >= 0; j--)
374 if (TREE_VEC_ELT (n1, 0) == gimple_omp_for_index (for_stmt, j))
376 single_nonrect = j;
377 break;
379 fd->non_rect = true;
381 else if (TREE_CODE (n2) == TREE_VEC)
383 if (fd->non_rect)
385 single_nonrect = -1;
386 break;
388 for (int j = i - 1; j >= 0; j--)
389 if (TREE_VEC_ELT (n2, 0) == gimple_omp_for_index (for_stmt, j))
391 single_nonrect = j;
392 break;
394 fd->non_rect = true;
397 for (i = 0; i < cnt; i++)
399 if (i == 0
400 && fd->collapse == 1
401 && !fd->tiling
402 && (fd->ordered == 0 || loops == NULL))
403 loop = &fd->loop;
404 else if (loops != NULL)
405 loop = loops + i;
406 else
407 loop = &dummy_loop;
409 loop->v = gimple_omp_for_index (for_stmt, i);
410 gcc_assert (SSA_VAR_P (loop->v));
411 gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
412 || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
413 var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
414 loop->n1 = gimple_omp_for_initial (for_stmt, i);
415 loop->m1 = NULL_TREE;
416 loop->m2 = NULL_TREE;
417 loop->outer = 0;
418 loop->non_rect_referenced = false;
419 if (TREE_CODE (loop->n1) == TREE_VEC)
421 for (int j = i - 1; j >= 0; j--)
422 if (TREE_VEC_ELT (loop->n1, 0) == gimple_omp_for_index (for_stmt, j))
424 loop->outer = i - j;
425 if (loops != NULL)
426 loops[j].non_rect_referenced = true;
427 if (fd->first_nonrect == -1 || fd->first_nonrect > j)
428 fd->first_nonrect = j;
429 break;
431 gcc_assert (loop->outer);
432 loop->m1 = TREE_VEC_ELT (loop->n1, 1);
433 loop->n1 = TREE_VEC_ELT (loop->n1, 2);
434 fd->non_rect = true;
435 fd->last_nonrect = i;
438 loop->cond_code = gimple_omp_for_cond (for_stmt, i);
439 loop->n2 = gimple_omp_for_final (for_stmt, i);
440 gcc_assert (loop->cond_code != NE_EXPR
441 || (gimple_omp_for_kind (for_stmt)
442 != GF_OMP_FOR_KIND_OACC_LOOP));
443 if (TREE_CODE (loop->n2) == TREE_VEC)
445 if (loop->outer)
446 gcc_assert (TREE_VEC_ELT (loop->n2, 0)
447 == gimple_omp_for_index (for_stmt, i - loop->outer));
448 else
449 for (int j = i - 1; j >= 0; j--)
450 if (TREE_VEC_ELT (loop->n2, 0) == gimple_omp_for_index (for_stmt, j))
452 loop->outer = i - j;
453 if (loops != NULL)
454 loops[j].non_rect_referenced = true;
455 if (fd->first_nonrect == -1 || fd->first_nonrect > j)
456 fd->first_nonrect = j;
457 break;
459 gcc_assert (loop->outer);
460 loop->m2 = TREE_VEC_ELT (loop->n2, 1);
461 loop->n2 = TREE_VEC_ELT (loop->n2, 2);
462 fd->non_rect = true;
463 fd->last_nonrect = i;
466 t = gimple_omp_for_incr (for_stmt, i);
467 gcc_assert (TREE_OPERAND (t, 0) == var);
468 loop->step = omp_get_for_step_from_incr (loc, t);
470 omp_adjust_for_condition (loc, &loop->cond_code, &loop->n2, loop->v,
471 loop->step);
473 if (simd
474 || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
475 && !fd->have_ordered))
477 if (fd->collapse == 1 && !fd->tiling)
478 iter_type = TREE_TYPE (loop->v);
479 else if (i == 0
480 || TYPE_PRECISION (iter_type)
481 < TYPE_PRECISION (TREE_TYPE (loop->v)))
482 iter_type
483 = build_nonstandard_integer_type
484 (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
486 else if (iter_type != long_long_unsigned_type_node)
488 if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
489 iter_type = long_long_unsigned_type_node;
490 else if (TYPE_UNSIGNED (TREE_TYPE (loop->v))
491 && TYPE_PRECISION (TREE_TYPE (loop->v))
492 >= TYPE_PRECISION (iter_type))
494 tree n;
496 if (loop->cond_code == LT_EXPR)
497 n = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v),
498 loop->n2, loop->step);
499 else
500 n = loop->n1;
501 if (loop->m1
502 || loop->m2
503 || TREE_CODE (n) != INTEGER_CST
504 || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n))
505 iter_type = long_long_unsigned_type_node;
507 else if (TYPE_PRECISION (TREE_TYPE (loop->v))
508 > TYPE_PRECISION (iter_type))
510 tree n1, n2;
512 if (loop->cond_code == LT_EXPR)
514 n1 = loop->n1;
515 n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v),
516 loop->n2, loop->step);
518 else
520 n1 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (loop->v),
521 loop->n2, loop->step);
522 n2 = loop->n1;
524 if (loop->m1
525 || loop->m2
526 || TREE_CODE (n1) != INTEGER_CST
527 || TREE_CODE (n2) != INTEGER_CST
528 || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1)
529 || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type)))
530 iter_type = long_long_unsigned_type_node;
534 if (i >= fd->collapse)
535 continue;
537 if (collapse_count && *collapse_count == NULL)
539 if (count && integer_zerop (count))
540 continue;
541 tree n1first = NULL_TREE, n2first = NULL_TREE;
542 tree n1last = NULL_TREE, n2last = NULL_TREE;
543 tree ostep = NULL_TREE;
544 if (loop->m1 || loop->m2)
546 if (count == NULL_TREE)
547 continue;
548 if (single_nonrect == -1
549 || (loop->m1 && TREE_CODE (loop->m1) != INTEGER_CST)
550 || (loop->m2 && TREE_CODE (loop->m2) != INTEGER_CST)
551 || TREE_CODE (loop->n1) != INTEGER_CST
552 || TREE_CODE (loop->n2) != INTEGER_CST
553 || TREE_CODE (loop->step) != INTEGER_CST)
555 count = NULL_TREE;
556 continue;
558 tree var = gimple_omp_for_initial (for_stmt, single_nonrect);
559 tree itype = TREE_TYPE (var);
560 tree first = gimple_omp_for_initial (for_stmt, single_nonrect);
561 t = gimple_omp_for_incr (for_stmt, single_nonrect);
562 ostep = omp_get_for_step_from_incr (loc, t);
563 t = fold_binary (MINUS_EXPR, long_long_unsigned_type_node,
564 single_nonrect_count,
565 build_one_cst (long_long_unsigned_type_node));
566 t = fold_convert (itype, t);
567 first = fold_convert (itype, first);
568 ostep = fold_convert (itype, ostep);
569 tree last = fold_binary (PLUS_EXPR, itype, first,
570 fold_binary (MULT_EXPR, itype, t,
571 ostep));
572 if (TREE_CODE (first) != INTEGER_CST
573 || TREE_CODE (last) != INTEGER_CST)
575 count = NULL_TREE;
576 continue;
578 if (loop->m1)
580 tree m1 = fold_convert (itype, loop->m1);
581 tree n1 = fold_convert (itype, loop->n1);
582 n1first = fold_binary (PLUS_EXPR, itype,
583 fold_binary (MULT_EXPR, itype,
584 first, m1), n1);
585 n1last = fold_binary (PLUS_EXPR, itype,
586 fold_binary (MULT_EXPR, itype,
587 last, m1), n1);
589 else
590 n1first = n1last = loop->n1;
591 if (loop->m2)
593 tree n2 = fold_convert (itype, loop->n2);
594 tree m2 = fold_convert (itype, loop->m2);
595 n2first = fold_binary (PLUS_EXPR, itype,
596 fold_binary (MULT_EXPR, itype,
597 first, m2), n2);
598 n2last = fold_binary (PLUS_EXPR, itype,
599 fold_binary (MULT_EXPR, itype,
600 last, m2), n2);
602 else
603 n2first = n2last = loop->n2;
604 n1first = fold_convert (TREE_TYPE (loop->v), n1first);
605 n2first = fold_convert (TREE_TYPE (loop->v), n2first);
606 n1last = fold_convert (TREE_TYPE (loop->v), n1last);
607 n2last = fold_convert (TREE_TYPE (loop->v), n2last);
608 t = fold_binary (loop->cond_code, boolean_type_node,
609 n1first, n2first);
610 tree t2 = fold_binary (loop->cond_code, boolean_type_node,
611 n1last, n2last);
612 if (t && t2 && integer_nonzerop (t) && integer_nonzerop (t2))
613 /* All outer loop iterators have at least one inner loop
614 iteration. Try to compute the count at compile time. */
615 t = NULL_TREE;
616 else if (t && t2 && integer_zerop (t) && integer_zerop (t2))
617 /* No iterations of the inner loop. count will be set to
618 zero cst below. */;
619 else if (TYPE_UNSIGNED (itype)
620 || t == NULL_TREE
621 || t2 == NULL_TREE
622 || TREE_CODE (t) != INTEGER_CST
623 || TREE_CODE (t2) != INTEGER_CST)
625 /* Punt (for now). */
626 count = NULL_TREE;
627 continue;
629 else
631 /* Some iterations of the outer loop have zero iterations
632 of the inner loop, while others have at least one.
633 In this case, we need to adjust one of those outer
634 loop bounds. If ADJ_FIRST, we need to adjust outer n1
635 (first), otherwise outer n2 (last). */
636 bool adj_first = integer_zerop (t);
637 tree n1 = fold_convert (itype, loop->n1);
638 tree n2 = fold_convert (itype, loop->n2);
639 tree m1 = loop->m1 ? fold_convert (itype, loop->m1)
640 : build_zero_cst (itype);
641 tree m2 = loop->m2 ? fold_convert (itype, loop->m2)
642 : build_zero_cst (itype);
643 t = fold_binary (MINUS_EXPR, itype, n1, n2);
644 t2 = fold_binary (MINUS_EXPR, itype, m2, m1);
645 t = fold_binary (TRUNC_DIV_EXPR, itype, t, t2);
646 t2 = fold_binary (MINUS_EXPR, itype, t, first);
647 t2 = fold_binary (TRUNC_MOD_EXPR, itype, t2, ostep);
648 t = fold_binary (MINUS_EXPR, itype, t, t2);
649 tree n1cur
650 = fold_binary (PLUS_EXPR, itype, n1,
651 fold_binary (MULT_EXPR, itype, m1, t));
652 tree n2cur
653 = fold_binary (PLUS_EXPR, itype, n2,
654 fold_binary (MULT_EXPR, itype, m2, t));
655 t2 = fold_binary (loop->cond_code, boolean_type_node,
656 n1cur, n2cur);
657 tree t3 = fold_binary (MULT_EXPR, itype, m1, ostep);
658 tree t4 = fold_binary (MULT_EXPR, itype, m2, ostep);
659 tree diff;
660 if (adj_first)
662 tree new_first;
663 if (integer_nonzerop (t2))
665 new_first = t;
666 n1first = n1cur;
667 n2first = n2cur;
668 if (flag_checking)
670 t3 = fold_binary (MINUS_EXPR, itype, n1cur, t3);
671 t4 = fold_binary (MINUS_EXPR, itype, n2cur, t4);
672 t3 = fold_binary (loop->cond_code,
673 boolean_type_node, t3, t4);
674 gcc_assert (integer_zerop (t3));
677 else
679 t3 = fold_binary (PLUS_EXPR, itype, n1cur, t3);
680 t4 = fold_binary (PLUS_EXPR, itype, n2cur, t4);
681 new_first = fold_binary (PLUS_EXPR, itype, t, ostep);
682 n1first = t3;
683 n2first = t4;
684 if (flag_checking)
686 t3 = fold_binary (loop->cond_code,
687 boolean_type_node, t3, t4);
688 gcc_assert (integer_nonzerop (t3));
691 diff = fold_binary (MINUS_EXPR, itype, new_first, first);
692 first = new_first;
693 fd->adjn1 = first;
695 else
697 tree new_last;
698 if (integer_zerop (t2))
700 t3 = fold_binary (MINUS_EXPR, itype, n1cur, t3);
701 t4 = fold_binary (MINUS_EXPR, itype, n2cur, t4);
702 new_last = fold_binary (MINUS_EXPR, itype, t, ostep);
703 n1last = t3;
704 n2last = t4;
705 if (flag_checking)
707 t3 = fold_binary (loop->cond_code,
708 boolean_type_node, t3, t4);
709 gcc_assert (integer_nonzerop (t3));
712 else
714 new_last = t;
715 n1last = n1cur;
716 n2last = n2cur;
717 if (flag_checking)
719 t3 = fold_binary (PLUS_EXPR, itype, n1cur, t3);
720 t4 = fold_binary (PLUS_EXPR, itype, n2cur, t4);
721 t3 = fold_binary (loop->cond_code,
722 boolean_type_node, t3, t4);
723 gcc_assert (integer_zerop (t3));
726 diff = fold_binary (MINUS_EXPR, itype, last, new_last);
728 if (TYPE_UNSIGNED (itype)
729 && single_nonrect_cond_code == GT_EXPR)
730 diff = fold_binary (TRUNC_DIV_EXPR, itype,
731 fold_unary (NEGATE_EXPR, itype, diff),
732 fold_unary (NEGATE_EXPR, itype,
733 ostep));
734 else
735 diff = fold_binary (TRUNC_DIV_EXPR, itype, diff, ostep);
736 diff = fold_convert (long_long_unsigned_type_node, diff);
737 single_nonrect_count
738 = fold_binary (MINUS_EXPR, long_long_unsigned_type_node,
739 single_nonrect_count, diff);
740 t = NULL_TREE;
743 else
744 t = fold_binary (loop->cond_code, boolean_type_node,
745 fold_convert (TREE_TYPE (loop->v), loop->n1),
746 fold_convert (TREE_TYPE (loop->v), loop->n2));
747 if (t && integer_zerop (t))
748 count = build_zero_cst (long_long_unsigned_type_node);
749 else if ((i == 0 || count != NULL_TREE)
750 && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
751 && TREE_CONSTANT (loop->n1)
752 && TREE_CONSTANT (loop->n2)
753 && TREE_CODE (loop->step) == INTEGER_CST)
755 tree itype = TREE_TYPE (loop->v);
757 if (POINTER_TYPE_P (itype))
758 itype = signed_type_for (itype);
759 t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1));
760 t = fold_build2 (PLUS_EXPR, itype,
761 fold_convert (itype, loop->step), t);
762 tree n1 = loop->n1;
763 tree n2 = loop->n2;
764 if (loop->m1 || loop->m2)
766 gcc_assert (single_nonrect != -1);
767 n1 = n1first;
768 n2 = n2first;
770 t = fold_build2 (PLUS_EXPR, itype, t, fold_convert (itype, n2));
771 t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1));
772 tree step = fold_convert_loc (loc, itype, loop->step);
773 if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
774 t = fold_build2 (TRUNC_DIV_EXPR, itype,
775 fold_build1 (NEGATE_EXPR, itype, t),
776 fold_build1 (NEGATE_EXPR, itype, step));
777 else
778 t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step);
779 tree llutype = long_long_unsigned_type_node;
780 t = fold_convert (llutype, t);
781 if (loop->m1 || loop->m2)
783 /* t is number of iterations of inner loop at either first
784 or last value of the outer iterator (the one with fewer
785 iterations).
786 Compute t2 = ((m2 - m1) * ostep) / step
787 and niters = outer_count * t
788 + t2 * ((outer_count - 1) * outer_count / 2)
790 tree m1 = loop->m1 ? loop->m1 : integer_zero_node;
791 tree m2 = loop->m2 ? loop->m2 : integer_zero_node;
792 m1 = fold_convert (itype, m1);
793 m2 = fold_convert (itype, m2);
794 tree t2 = fold_build2 (MINUS_EXPR, itype, m2, m1);
795 t2 = fold_build2 (MULT_EXPR, itype, t2, ostep);
796 if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
797 t2 = fold_build2 (TRUNC_DIV_EXPR, itype,
798 fold_build1 (NEGATE_EXPR, itype, t2),
799 fold_build1 (NEGATE_EXPR, itype, step));
800 else
801 t2 = fold_build2 (TRUNC_DIV_EXPR, itype, t2, step);
802 t2 = fold_convert (llutype, t2);
803 fd->first_inner_iterations = t;
804 fd->factor = t2;
805 t = fold_build2 (MULT_EXPR, llutype, t,
806 single_nonrect_count);
807 tree t3 = fold_build2 (MINUS_EXPR, llutype,
808 single_nonrect_count,
809 build_one_cst (llutype));
810 t3 = fold_build2 (MULT_EXPR, llutype, t3,
811 single_nonrect_count);
812 t3 = fold_build2 (TRUNC_DIV_EXPR, llutype, t3,
813 build_int_cst (llutype, 2));
814 t2 = fold_build2 (MULT_EXPR, llutype, t2, t3);
815 t = fold_build2 (PLUS_EXPR, llutype, t, t2);
817 if (i == single_nonrect)
819 if (integer_zerop (t) || TREE_CODE (t) != INTEGER_CST)
820 count = t;
821 else
823 single_nonrect_count = t;
824 single_nonrect_cond_code = loop->cond_code;
825 if (count == NULL_TREE)
826 count = build_one_cst (llutype);
829 else if (count != NULL_TREE)
830 count = fold_build2 (MULT_EXPR, llutype, count, t);
831 else
832 count = t;
833 if (TREE_CODE (count) != INTEGER_CST)
834 count = NULL_TREE;
836 else if (count && !integer_zerop (count))
837 count = NULL_TREE;
841 if (count
842 && !simd
843 && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
844 || fd->have_ordered))
846 if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
847 iter_type = long_long_unsigned_type_node;
848 else
849 iter_type = long_integer_type_node;
851 else if (collapse_iter && *collapse_iter != NULL)
852 iter_type = TREE_TYPE (*collapse_iter);
853 fd->iter_type = iter_type;
854 if (collapse_iter && *collapse_iter == NULL)
855 *collapse_iter = create_tmp_var (iter_type, ".iter");
856 if (collapse_count && *collapse_count == NULL)
858 if (count)
860 *collapse_count = fold_convert_loc (loc, iter_type, count);
861 if (fd->first_inner_iterations && fd->factor)
863 t = make_tree_vec (4);
864 TREE_VEC_ELT (t, 0) = *collapse_count;
865 TREE_VEC_ELT (t, 1) = fd->first_inner_iterations;
866 TREE_VEC_ELT (t, 2) = fd->factor;
867 TREE_VEC_ELT (t, 3) = fd->adjn1;
868 *collapse_count = t;
871 else
872 *collapse_count = create_tmp_var (iter_type, ".count");
875 if (fd->collapse > 1 || fd->tiling || (fd->ordered && loops))
877 fd->loop.v = *collapse_iter;
878 fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
879 fd->loop.n2 = *collapse_count;
880 if (TREE_CODE (fd->loop.n2) == TREE_VEC)
882 gcc_assert (fd->non_rect);
883 fd->first_inner_iterations = TREE_VEC_ELT (fd->loop.n2, 1);
884 fd->factor = TREE_VEC_ELT (fd->loop.n2, 2);
885 fd->adjn1 = TREE_VEC_ELT (fd->loop.n2, 3);
886 fd->loop.n2 = TREE_VEC_ELT (fd->loop.n2, 0);
888 fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
889 fd->loop.m1 = NULL_TREE;
890 fd->loop.m2 = NULL_TREE;
891 fd->loop.outer = 0;
892 fd->loop.cond_code = LT_EXPR;
894 else if (loops)
895 loops[0] = fd->loop;
898 /* Build a call to GOMP_barrier. */
900 gimple *
901 omp_build_barrier (tree lhs)
903 tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL
904 : BUILT_IN_GOMP_BARRIER);
905 gcall *g = gimple_build_call (fndecl, 0);
906 if (lhs)
907 gimple_call_set_lhs (g, lhs);
908 return g;
911 /* Find OMP_FOR resp. OMP_SIMD with non-NULL OMP_FOR_INIT. Also, fill in pdata
912 array, pdata[0] non-NULL if there is anything non-trivial in between,
913 pdata[1] is address of OMP_PARALLEL in between if any, pdata[2] is address
914 of OMP_FOR in between if any and pdata[3] is address of the inner
915 OMP_FOR/OMP_SIMD. */
917 tree
918 find_combined_omp_for (tree *tp, int *walk_subtrees, void *data)
920 tree **pdata = (tree **) data;
921 *walk_subtrees = 0;
922 switch (TREE_CODE (*tp))
924 case OMP_FOR:
925 if (OMP_FOR_INIT (*tp) != NULL_TREE)
927 pdata[3] = tp;
928 return *tp;
930 pdata[2] = tp;
931 *walk_subtrees = 1;
932 break;
933 case OMP_SIMD:
934 if (OMP_FOR_INIT (*tp) != NULL_TREE)
936 pdata[3] = tp;
937 return *tp;
939 break;
940 case BIND_EXPR:
941 if (BIND_EXPR_VARS (*tp)
942 || (BIND_EXPR_BLOCK (*tp)
943 && BLOCK_VARS (BIND_EXPR_BLOCK (*tp))))
944 pdata[0] = tp;
945 *walk_subtrees = 1;
946 break;
947 case STATEMENT_LIST:
948 if (!tsi_one_before_end_p (tsi_start (*tp)))
949 pdata[0] = tp;
950 *walk_subtrees = 1;
951 break;
952 case TRY_FINALLY_EXPR:
953 pdata[0] = tp;
954 *walk_subtrees = 1;
955 break;
956 case OMP_PARALLEL:
957 pdata[1] = tp;
958 *walk_subtrees = 1;
959 break;
960 default:
961 break;
963 return NULL_TREE;
966 /* Return maximum possible vectorization factor for the target. */
968 poly_uint64
969 omp_max_vf (void)
971 if (!optimize
972 || optimize_debug
973 || !flag_tree_loop_optimize
974 || (!flag_tree_loop_vectorize
975 && OPTION_SET_P (flag_tree_loop_vectorize)))
976 return 1;
978 auto_vector_modes modes;
979 targetm.vectorize.autovectorize_vector_modes (&modes, true);
980 if (!modes.is_empty ())
982 poly_uint64 vf = 0;
983 for (unsigned int i = 0; i < modes.length (); ++i)
984 /* The returned modes use the smallest element size (and thus
985 the largest nunits) for the vectorization approach that they
986 represent. */
987 vf = ordered_max (vf, GET_MODE_NUNITS (modes[i]));
988 return vf;
991 machine_mode vqimode = targetm.vectorize.preferred_simd_mode (QImode);
992 if (GET_MODE_CLASS (vqimode) == MODE_VECTOR_INT)
993 return GET_MODE_NUNITS (vqimode);
995 return 1;
998 /* Return maximum SIMT width if offloading may target SIMT hardware. */
1001 omp_max_simt_vf (void)
1003 if (!optimize)
1004 return 0;
1005 if (ENABLE_OFFLOADING)
1006 for (const char *c = getenv ("OFFLOAD_TARGET_NAMES"); c;)
1008 if (startswith (c, "nvptx"))
1009 return 32;
1010 else if ((c = strchr (c, ':')))
1011 c++;
1013 return 0;
1016 /* Store the construct selectors as tree codes from last to first.
1017 CTX is a list of trait selectors, nconstructs must be equal to its
1018 length, and the array CONSTRUCTS holds the output. */
1020 void
1021 omp_construct_traits_to_codes (tree ctx, int nconstructs,
1022 enum tree_code *constructs)
1024 int i = nconstructs - 1;
1026 /* Order must match the OMP_TRAIT_CONSTRUCT_* enumerators in
1027 enum omp_ts_code. */
1028 static enum tree_code code_map[]
1029 = { OMP_TARGET, OMP_TEAMS, OMP_PARALLEL, OMP_FOR, OMP_SIMD };
1031 for (tree ts = ctx; ts; ts = TREE_CHAIN (ts), i--)
1033 enum omp_ts_code sel = OMP_TS_CODE (ts);
1034 int j = (int)sel - (int)OMP_TRAIT_CONSTRUCT_TARGET;
1035 gcc_assert (j >= 0 && (unsigned int) j < ARRAY_SIZE (code_map));
1036 constructs[i] = code_map[j];
1038 gcc_assert (i == -1);
1041 /* Return true if PROP is possibly present in one of the offloading target's
1042 OpenMP contexts. The format of PROPS string is always offloading target's
1043 name terminated by '\0', followed by properties for that offloading
1044 target separated by '\0' and terminated by another '\0'. The strings
1045 are created from omp-device-properties installed files of all configured
1046 offloading targets. */
1048 static bool
1049 omp_offload_device_kind_arch_isa (const char *props, const char *prop)
1051 const char *names = getenv ("OFFLOAD_TARGET_NAMES");
1052 if (names == NULL || *names == '\0')
1053 return false;
1054 while (*props != '\0')
1056 size_t name_len = strlen (props);
1057 bool matches = false;
1058 for (const char *c = names; c; )
1060 if (strncmp (props, c, name_len) == 0
1061 && (c[name_len] == '\0'
1062 || c[name_len] == ':'
1063 || c[name_len] == '='))
1065 matches = true;
1066 break;
1068 else if ((c = strchr (c, ':')))
1069 c++;
1071 props = props + name_len + 1;
1072 while (*props != '\0')
1074 if (matches && strcmp (props, prop) == 0)
1075 return true;
1076 props = strchr (props, '\0') + 1;
1078 props++;
1080 return false;
1083 /* Return true if the current code location is or might be offloaded.
1084 Return true in declare target functions, or when nested in a target
1085 region or when unsure, return false otherwise. */
1087 static bool
1088 omp_maybe_offloaded (void)
1090 if (!ENABLE_OFFLOADING)
1091 return false;
1092 const char *names = getenv ("OFFLOAD_TARGET_NAMES");
1093 if (names == NULL || *names == '\0')
1094 return false;
1096 if (symtab->state == PARSING)
1097 /* Maybe. */
1098 return true;
1099 if (cfun && cfun->after_inlining)
1100 return false;
1101 if (current_function_decl
1102 && lookup_attribute ("omp declare target",
1103 DECL_ATTRIBUTES (current_function_decl)))
1104 return true;
1105 if (cfun && (cfun->curr_properties & PROP_gimple_any) == 0)
1107 enum tree_code construct = OMP_TARGET;
1108 if (omp_construct_selector_matches (&construct, 1, NULL))
1109 return true;
1111 return false;
1114 /* Lookup tables for context selectors. */
1115 const char *omp_tss_map[] =
1117 "construct",
1118 "device",
1119 "target_device",
1120 "implementation",
1121 "user",
1122 NULL
1125 /* Arrays of property candidates must be null-terminated. */
1126 static const char *const kind_properties[] =
1127 { "host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
1128 static const char *const vendor_properties[] =
1129 { "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "hpe", "ibm", "intel",
1130 "llvm", "nvidia", "pgi", "ti", "unknown", NULL };
1131 static const char *const extension_properties[] =
1132 { NULL };
1133 static const char *const atomic_default_mem_order_properties[] =
1134 { "seq_cst", "relaxed", "acq_rel", "acquire", "release", NULL };
1136 struct omp_ts_info omp_ts_map[] =
1138 { "kind",
1139 (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1140 OMP_TRAIT_PROPERTY_NAME_LIST, false,
1141 kind_properties
1143 { "isa",
1144 (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1145 OMP_TRAIT_PROPERTY_NAME_LIST, false,
1146 NULL
1148 { "arch",
1149 (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1150 OMP_TRAIT_PROPERTY_NAME_LIST, false,
1151 NULL
1153 { "device_num",
1154 (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1155 OMP_TRAIT_PROPERTY_EXPR, false,
1156 NULL
1158 { "vendor",
1159 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1160 OMP_TRAIT_PROPERTY_NAME_LIST, true,
1161 vendor_properties,
1163 { "extension",
1164 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1165 OMP_TRAIT_PROPERTY_NAME_LIST, true,
1166 extension_properties,
1168 { "atomic_default_mem_order",
1169 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1170 OMP_TRAIT_PROPERTY_ID, true,
1171 atomic_default_mem_order_properties,
1173 { "requires",
1174 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1175 OMP_TRAIT_PROPERTY_CLAUSE_LIST, true,
1176 NULL
1178 { "unified_address",
1179 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1180 OMP_TRAIT_PROPERTY_NONE, true,
1181 NULL
1183 { "unified_shared_memory",
1184 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1185 OMP_TRAIT_PROPERTY_NONE, true,
1186 NULL
1188 { "dynamic_allocators",
1189 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1190 OMP_TRAIT_PROPERTY_NONE, true,
1191 NULL
1193 { "reverse_offload",
1194 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1195 OMP_TRAIT_PROPERTY_NONE, true,
1196 NULL
1198 { "condition",
1199 (1 << OMP_TRAIT_SET_USER),
1200 OMP_TRAIT_PROPERTY_EXPR, true,
1201 NULL
1203 { "target",
1204 (1 << OMP_TRAIT_SET_CONSTRUCT),
1205 OMP_TRAIT_PROPERTY_NONE, false,
1206 NULL
1208 { "teams",
1209 (1 << OMP_TRAIT_SET_CONSTRUCT),
1210 OMP_TRAIT_PROPERTY_NONE, false,
1211 NULL
1213 { "parallel",
1214 (1 << OMP_TRAIT_SET_CONSTRUCT),
1215 OMP_TRAIT_PROPERTY_NONE, false,
1216 NULL
1218 { "for",
1219 (1 << OMP_TRAIT_SET_CONSTRUCT),
1220 OMP_TRAIT_PROPERTY_NONE, false,
1221 NULL
1223 { "simd",
1224 (1 << OMP_TRAIT_SET_CONSTRUCT),
1225 OMP_TRAIT_PROPERTY_CLAUSE_LIST, false,
1226 NULL
1228 { NULL, 0, OMP_TRAIT_PROPERTY_NONE, false, NULL } /* OMP_TRAIT_LAST */
1232 /* Return a name from PROP, a property in selectors accepting
1233 name lists. */
1235 const char *
1236 omp_context_name_list_prop (tree prop)
1238 gcc_assert (OMP_TP_NAME (prop) == OMP_TP_NAMELIST_NODE);
1239 tree val = OMP_TP_VALUE (prop);
1240 switch (TREE_CODE (val))
1242 case IDENTIFIER_NODE:
1243 return IDENTIFIER_POINTER (val);
1244 case STRING_CST:
1246 const char *ret = TREE_STRING_POINTER (val);
1247 if ((size_t) TREE_STRING_LENGTH (val)
1248 == strlen (ret) + (lang_GNU_Fortran () ? 0 : 1))
1249 return ret;
1250 return NULL;
1252 default:
1253 return NULL;
1257 /* Diagnose errors in an OpenMP context selector, return CTX if
1258 it is correct or error_mark_node otherwise. */
1260 tree
1261 omp_check_context_selector (location_t loc, tree ctx)
1263 bool tss_seen[OMP_TRAIT_SET_LAST], ts_seen[OMP_TRAIT_LAST];
1265 memset (tss_seen, 0, sizeof (tss_seen));
1266 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
1268 enum omp_tss_code tss_code = OMP_TSS_CODE (tss);
1270 /* We can parse this, but not handle it yet. */
1271 if (tss_code == OMP_TRAIT_SET_TARGET_DEVICE)
1272 sorry_at (loc, "%<target_device%> selector set is not supported yet");
1274 /* Each trait-set-selector-name can only be specified once. */
1275 if (tss_seen[tss_code])
1277 error_at (loc, "selector set %qs specified more than once",
1278 OMP_TSS_NAME (tss));
1279 return error_mark_node;
1281 else
1282 tss_seen[tss_code] = true;
1284 memset (ts_seen, 0, sizeof (ts_seen));
1285 for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
1287 enum omp_ts_code ts_code = OMP_TS_CODE (ts);
1289 /* Ignore unknown traits. */
1290 if (ts_code == OMP_TRAIT_INVALID)
1291 continue;
1293 /* Each trait-selector-name can only be specified once. */
1294 if (ts_seen[ts_code])
1296 error_at (loc,
1297 "selector %qs specified more than once in set %qs",
1298 OMP_TS_NAME (ts),
1299 OMP_TSS_NAME (tss));
1300 return error_mark_node;
1302 else
1303 ts_seen[ts_code] = true;
1305 if (omp_ts_map[ts_code].valid_properties == NULL)
1306 continue;
1308 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1309 for (unsigned j = 0; ; j++)
1311 const char *candidate
1312 = omp_ts_map[ts_code].valid_properties[j];
1313 if (candidate == NULL)
1315 /* We've reached the end of the candidate array. */
1316 if (ts_code == OMP_TRAIT_IMPLEMENTATION_ADMO)
1317 /* FIXME: not sure why this is an error vs warnings
1318 for the others, + incorrect/unknown wording? */
1320 error_at (loc,
1321 "incorrect property %qs of %qs selector",
1322 IDENTIFIER_POINTER (OMP_TP_NAME (p)),
1323 "atomic_default_mem_order");
1324 return error_mark_node;
1326 if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
1327 && (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
1328 warning_at (loc, OPT_Wopenmp,
1329 "unknown property %qE of %qs selector",
1330 OMP_TP_VALUE (p),
1331 OMP_TS_NAME (ts));
1332 else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
1333 warning_at (loc, OPT_Wopenmp,
1334 "unknown property %qs of %qs selector",
1335 omp_context_name_list_prop (p),
1336 OMP_TS_NAME (ts));
1337 else if (OMP_TP_NAME (p))
1338 warning_at (loc, OPT_Wopenmp,
1339 "unknown property %qs of %qs selector",
1340 IDENTIFIER_POINTER (OMP_TP_NAME (p)),
1341 OMP_TS_NAME (ts));
1342 break;
1344 else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
1345 /* Property-list traits. */
1347 const char *str = omp_context_name_list_prop (p);
1348 if (str && !strcmp (str, candidate))
1349 break;
1351 else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
1352 candidate))
1353 /* Identifier traits. */
1354 break;
1358 return ctx;
1362 /* Register VARIANT as variant of some base function marked with
1363 #pragma omp declare variant. CONSTRUCT is corresponding list of
1364 trait-selectors for the construct selector set. This is stashed as the
1365 value of the "omp declare variant variant" attribute on VARIANT. */
1366 void
1367 omp_mark_declare_variant (location_t loc, tree variant, tree construct)
1369 /* Ignore this variant if it contains unknown construct selectors.
1370 It will never match, and the front ends have already issued a warning
1371 about it. */
1372 for (tree c = construct; c; c = TREE_CHAIN (c))
1373 if (OMP_TS_CODE (c) == OMP_TRAIT_INVALID)
1374 return;
1376 tree attr = lookup_attribute ("omp declare variant variant",
1377 DECL_ATTRIBUTES (variant));
1378 if (attr == NULL_TREE)
1380 attr = tree_cons (get_identifier ("omp declare variant variant"),
1381 unshare_expr (construct),
1382 DECL_ATTRIBUTES (variant));
1383 DECL_ATTRIBUTES (variant) = attr;
1384 return;
1386 if ((TREE_VALUE (attr) != NULL_TREE) != (construct != NULL_TREE)
1387 || (construct != NULL_TREE
1388 && omp_context_selector_set_compare (OMP_TRAIT_SET_CONSTRUCT,
1389 TREE_VALUE (attr),
1390 construct)))
1391 error_at (loc, "%qD used as a variant with incompatible %<construct%> "
1392 "selector sets", variant);
1396 /* Constructors for context selectors. */
1398 tree
1399 make_trait_set_selector (enum omp_tss_code code, tree selectors, tree chain)
1401 return tree_cons (build_int_cst (integer_type_node, code),
1402 selectors, chain);
1405 tree
1406 make_trait_selector (enum omp_ts_code code, tree score, tree properties,
1407 tree chain)
1409 if (score == NULL_TREE)
1410 return tree_cons (build_int_cst (integer_type_node, code),
1411 properties, chain);
1412 else
1413 return tree_cons (build_int_cst (integer_type_node, code),
1414 tree_cons (OMP_TS_SCORE_NODE, score, properties),
1415 chain);
1418 tree
1419 make_trait_property (tree name, tree value, tree chain)
1421 return tree_cons (name, value, chain);
1424 /* Return 1 if context selector matches the current OpenMP context, 0
1425 if it does not and -1 if it is unknown and need to be determined later.
1426 Some properties can be checked right away during parsing (this routine),
1427 others need to wait until the whole TU is parsed, others need to wait until
1428 IPA, others until vectorization. */
1431 omp_context_selector_matches (tree ctx)
1433 int ret = 1;
1434 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
1436 enum omp_tss_code set = OMP_TSS_CODE (tss);
1437 tree selectors = OMP_TSS_TRAIT_SELECTORS (tss);
1439 /* Immediately reject the match if there are any ignored
1440 selectors present. */
1441 for (tree ts = selectors; ts; ts = TREE_CHAIN (ts))
1442 if (OMP_TS_CODE (ts) == OMP_TRAIT_INVALID)
1443 return 0;
1445 if (set == OMP_TRAIT_SET_CONSTRUCT)
1447 /* For now, ignore the construct set. While something can be
1448 determined already during parsing, we don't know until end of TU
1449 whether additional constructs aren't added through declare variant
1450 unless "omp declare variant variant" attribute exists already
1451 (so in most of the cases), and we'd need to maintain set of
1452 surrounding OpenMP constructs, which is better handled during
1453 gimplification. */
1454 if (symtab->state == PARSING)
1456 ret = -1;
1457 continue;
1460 int nconstructs = list_length (selectors);
1461 enum tree_code *constructs = NULL;
1462 if (nconstructs)
1464 /* Even though this alloca appears in a loop over selector
1465 sets, it does not repeatedly grow the stack, because
1466 there can be only one construct selector set specified.
1467 This is enforced by omp_check_context_selector. */
1468 constructs
1469 = (enum tree_code *) alloca (nconstructs
1470 * sizeof (enum tree_code));
1471 omp_construct_traits_to_codes (selectors, nconstructs,
1472 constructs);
1475 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1477 if (!cfun->after_inlining)
1479 ret = -1;
1480 continue;
1482 int i;
1483 for (i = 0; i < nconstructs; ++i)
1484 if (constructs[i] == OMP_SIMD)
1485 break;
1486 if (i < nconstructs)
1488 ret = -1;
1489 continue;
1491 /* If there is no simd, assume it is ok after IPA,
1492 constructs should have been checked before. */
1493 continue;
1496 int r = omp_construct_selector_matches (constructs, nconstructs,
1497 NULL);
1498 if (r == 0)
1499 return 0;
1500 if (r == -1)
1501 ret = -1;
1502 continue;
1504 for (tree ts = selectors; ts; ts = TREE_CHAIN (ts))
1506 enum omp_ts_code sel = OMP_TS_CODE (ts);
1507 switch (sel)
1509 case OMP_TRAIT_IMPLEMENTATION_VENDOR:
1510 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1511 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1513 const char *prop = omp_context_name_list_prop (p);
1514 if (prop == NULL)
1515 return 0;
1516 if (!strcmp (prop, "gnu"))
1517 continue;
1518 return 0;
1520 break;
1521 case OMP_TRAIT_IMPLEMENTATION_EXTENSION:
1522 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1523 /* We don't support any extensions right now. */
1524 return 0;
1525 break;
1526 case OMP_TRAIT_IMPLEMENTATION_ADMO:
1527 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1529 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1530 break;
1532 enum omp_memory_order omo
1533 = ((enum omp_memory_order)
1534 (omp_requires_mask
1535 & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER));
1536 if (omo == OMP_MEMORY_ORDER_UNSPECIFIED)
1538 /* We don't know yet, until end of TU. */
1539 if (symtab->state == PARSING)
1541 ret = -1;
1542 break;
1544 else
1545 omo = OMP_MEMORY_ORDER_RELAXED;
1547 tree p = OMP_TS_PROPERTIES (ts);
1548 const char *prop = IDENTIFIER_POINTER (OMP_TP_NAME (p));
1549 if (!strcmp (prop, "relaxed")
1550 && omo != OMP_MEMORY_ORDER_RELAXED)
1551 return 0;
1552 else if (!strcmp (prop, "seq_cst")
1553 && omo != OMP_MEMORY_ORDER_SEQ_CST)
1554 return 0;
1555 else if (!strcmp (prop, "acq_rel")
1556 && omo != OMP_MEMORY_ORDER_ACQ_REL)
1557 return 0;
1558 else if (!strcmp (prop, "acquire")
1559 && omo != OMP_MEMORY_ORDER_ACQUIRE)
1560 return 0;
1561 else if (!strcmp (prop, "release")
1562 && omo != OMP_MEMORY_ORDER_RELEASE)
1563 return 0;
1565 break;
1566 case OMP_TRAIT_DEVICE_ARCH:
1567 if (set == OMP_TRAIT_SET_DEVICE)
1568 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1570 const char *arch = omp_context_name_list_prop (p);
1571 if (arch == NULL)
1572 return 0;
1573 int r = 0;
1574 if (targetm.omp.device_kind_arch_isa != NULL)
1575 r = targetm.omp.device_kind_arch_isa (omp_device_arch,
1576 arch);
1577 if (r == 0 || (r == -1 && symtab->state != PARSING))
1579 /* If we are or might be in a target region or
1580 declare target function, need to take into account
1581 also offloading values. */
1582 if (!omp_maybe_offloaded ())
1583 return 0;
1584 if (ENABLE_OFFLOADING)
1586 const char *arches = omp_offload_device_arch;
1587 if (omp_offload_device_kind_arch_isa (arches,
1588 arch))
1590 ret = -1;
1591 continue;
1594 return 0;
1596 else if (r == -1)
1597 ret = -1;
1598 /* If arch matches on the host, it still might not match
1599 in the offloading region. */
1600 else if (omp_maybe_offloaded ())
1601 ret = -1;
1603 break;
1604 case OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS:
1605 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1607 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1608 break;
1610 if ((omp_requires_mask & OMP_REQUIRES_UNIFIED_ADDRESS) == 0)
1612 if (symtab->state == PARSING)
1613 ret = -1;
1614 else
1615 return 0;
1618 break;
1619 case OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY:
1620 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1622 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1623 break;
1625 if ((omp_requires_mask
1626 & OMP_REQUIRES_UNIFIED_SHARED_MEMORY) == 0)
1628 if (symtab->state == PARSING)
1629 ret = -1;
1630 else
1631 return 0;
1634 break;
1635 case OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS:
1636 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1638 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1639 break;
1641 if ((omp_requires_mask
1642 & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0)
1644 if (symtab->state == PARSING)
1645 ret = -1;
1646 else
1647 return 0;
1650 break;
1651 case OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD:
1652 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1654 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1655 break;
1657 if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0)
1659 if (symtab->state == PARSING)
1660 ret = -1;
1661 else
1662 return 0;
1665 break;
1666 case OMP_TRAIT_DEVICE_KIND:
1667 if (set == OMP_TRAIT_SET_DEVICE)
1668 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1670 const char *prop = omp_context_name_list_prop (p);
1671 if (prop == NULL)
1672 return 0;
1673 if (!strcmp (prop, "any"))
1674 continue;
1675 if (!strcmp (prop, "host"))
1677 #ifdef ACCEL_COMPILER
1678 return 0;
1679 #else
1680 if (omp_maybe_offloaded ())
1681 ret = -1;
1682 continue;
1683 #endif
1685 if (!strcmp (prop, "nohost"))
1687 #ifndef ACCEL_COMPILER
1688 if (omp_maybe_offloaded ())
1689 ret = -1;
1690 else
1691 return 0;
1692 #endif
1693 continue;
1695 int r = 0;
1696 if (targetm.omp.device_kind_arch_isa != NULL)
1697 r = targetm.omp.device_kind_arch_isa (omp_device_kind,
1698 prop);
1699 else
1700 r = strcmp (prop, "cpu") == 0;
1701 if (r == 0 || (r == -1 && symtab->state != PARSING))
1703 /* If we are or might be in a target region or
1704 declare target function, need to take into account
1705 also offloading values. */
1706 if (!omp_maybe_offloaded ())
1707 return 0;
1708 if (ENABLE_OFFLOADING)
1710 const char *kinds = omp_offload_device_kind;
1711 if (omp_offload_device_kind_arch_isa (kinds, prop))
1713 ret = -1;
1714 continue;
1717 return 0;
1719 else if (r == -1)
1720 ret = -1;
1721 /* If kind matches on the host, it still might not match
1722 in the offloading region. */
1723 else if (omp_maybe_offloaded ())
1724 ret = -1;
1726 break;
1727 case OMP_TRAIT_DEVICE_ISA:
1728 if (set == OMP_TRAIT_SET_DEVICE)
1729 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1731 const char *isa = omp_context_name_list_prop (p);
1732 if (isa == NULL)
1733 return 0;
1734 int r = 0;
1735 if (targetm.omp.device_kind_arch_isa != NULL)
1736 r = targetm.omp.device_kind_arch_isa (omp_device_isa,
1737 isa);
1738 if (r == 0 || (r == -1 && symtab->state != PARSING))
1740 /* If isa is valid on the target, but not in the
1741 current function and current function has
1742 #pragma omp declare simd on it, some simd clones
1743 might have the isa added later on. */
1744 if (r == -1
1745 && targetm.simd_clone.compute_vecsize_and_simdlen
1746 && (cfun == NULL || !cfun->after_inlining))
1748 tree attrs
1749 = DECL_ATTRIBUTES (current_function_decl);
1750 if (lookup_attribute ("omp declare simd", attrs))
1752 ret = -1;
1753 continue;
1756 /* If we are or might be in a target region or
1757 declare target function, need to take into account
1758 also offloading values. */
1759 if (!omp_maybe_offloaded ())
1760 return 0;
1761 if (ENABLE_OFFLOADING)
1763 const char *isas = omp_offload_device_isa;
1764 if (omp_offload_device_kind_arch_isa (isas, isa))
1766 ret = -1;
1767 continue;
1770 return 0;
1772 else if (r == -1)
1773 ret = -1;
1774 /* If isa matches on the host, it still might not match
1775 in the offloading region. */
1776 else if (omp_maybe_offloaded ())
1777 ret = -1;
1779 break;
1780 case OMP_TRAIT_USER_CONDITION:
1781 if (set == OMP_TRAIT_SET_USER)
1782 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1783 if (OMP_TP_NAME (p) == NULL_TREE)
1785 if (integer_zerop (OMP_TP_VALUE (p)))
1786 return 0;
1787 if (integer_nonzerop (OMP_TP_VALUE (p)))
1788 break;
1789 ret = -1;
1791 break;
1792 default:
1793 break;
1797 return ret;
1800 /* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as
1801 in omp_context_selector_set_compare. */
1803 static int
1804 omp_construct_simd_compare (tree clauses1, tree clauses2)
1806 if (clauses1 == NULL_TREE)
1807 return clauses2 == NULL_TREE ? 0 : -1;
1808 if (clauses2 == NULL_TREE)
1809 return 1;
1811 int r = 0;
1812 struct declare_variant_simd_data {
1813 bool inbranch, notinbranch;
1814 tree simdlen;
1815 auto_vec<tree,16> data_sharing;
1816 auto_vec<tree,16> aligned;
1817 declare_variant_simd_data ()
1818 : inbranch(false), notinbranch(false), simdlen(NULL_TREE) {}
1819 } data[2];
1820 unsigned int i;
1821 for (i = 0; i < 2; i++)
1822 for (tree c = i ? clauses2 : clauses1; c; c = OMP_CLAUSE_CHAIN (c))
1824 vec<tree> *v;
1825 switch (OMP_CLAUSE_CODE (c))
1827 case OMP_CLAUSE_INBRANCH:
1828 data[i].inbranch = true;
1829 continue;
1830 case OMP_CLAUSE_NOTINBRANCH:
1831 data[i].notinbranch = true;
1832 continue;
1833 case OMP_CLAUSE_SIMDLEN:
1834 data[i].simdlen = OMP_CLAUSE_SIMDLEN_EXPR (c);
1835 continue;
1836 case OMP_CLAUSE_UNIFORM:
1837 case OMP_CLAUSE_LINEAR:
1838 v = &data[i].data_sharing;
1839 break;
1840 case OMP_CLAUSE_ALIGNED:
1841 v = &data[i].aligned;
1842 break;
1843 default:
1844 gcc_unreachable ();
1846 unsigned HOST_WIDE_INT argno = tree_to_uhwi (OMP_CLAUSE_DECL (c));
1847 if (argno >= v->length ())
1848 v->safe_grow_cleared (argno + 1, true);
1849 (*v)[argno] = c;
1851 /* Here, r is used as a bitmask, 2 is set if CLAUSES1 has something
1852 CLAUSES2 doesn't, 1 is set if CLAUSES2 has something CLAUSES1
1853 doesn't. Thus, r == 3 implies return value 2, r == 1 implies
1854 -1, r == 2 implies 1 and r == 0 implies 0. */
1855 if (data[0].inbranch != data[1].inbranch)
1856 r |= data[0].inbranch ? 2 : 1;
1857 if (data[0].notinbranch != data[1].notinbranch)
1858 r |= data[0].notinbranch ? 2 : 1;
1859 if (!simple_cst_equal (data[0].simdlen, data[1].simdlen))
1861 if (data[0].simdlen && data[1].simdlen)
1862 return 2;
1863 r |= data[0].simdlen ? 2 : 1;
1865 if (data[0].data_sharing.length () < data[1].data_sharing.length ()
1866 || data[0].aligned.length () < data[1].aligned.length ())
1867 r |= 1;
1868 tree c1, c2;
1869 FOR_EACH_VEC_ELT (data[0].data_sharing, i, c1)
1871 c2 = (i < data[1].data_sharing.length ()
1872 ? data[1].data_sharing[i] : NULL_TREE);
1873 if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
1875 r |= c1 != NULL_TREE ? 2 : 1;
1876 continue;
1878 if (c1 == NULL_TREE)
1879 continue;
1880 if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_CODE (c2))
1881 return 2;
1882 if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_LINEAR)
1883 continue;
1884 if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1)
1885 != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2))
1886 return 2;
1887 if (OMP_CLAUSE_LINEAR_KIND (c1) != OMP_CLAUSE_LINEAR_KIND (c2))
1888 return 2;
1889 if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1),
1890 OMP_CLAUSE_LINEAR_STEP (c2)))
1891 return 2;
1893 FOR_EACH_VEC_ELT (data[0].aligned, i, c1)
1895 c2 = i < data[1].aligned.length () ? data[1].aligned[i] : NULL_TREE;
1896 if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
1898 r |= c1 != NULL_TREE ? 2 : 1;
1899 continue;
1901 if (c1 == NULL_TREE)
1902 continue;
1903 if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1),
1904 OMP_CLAUSE_ALIGNED_ALIGNMENT (c2)))
1905 return 2;
1907 switch (r)
1909 case 0: return 0;
1910 case 1: return -1;
1911 case 2: return 1;
1912 case 3: return 2;
1913 default: gcc_unreachable ();
1917 /* Compare properties of selectors SEL from SET other than construct.
1918 CTX1 and CTX2 are the lists of properties to compare.
1919 Return 0/-1/1/2 as in omp_context_selector_set_compare.
1920 Unlike set names or selector names, properties can have duplicates. */
1922 static int
1923 omp_context_selector_props_compare (enum omp_tss_code set,
1924 enum omp_ts_code sel,
1925 tree ctx1, tree ctx2)
1927 int ret = 0;
1928 for (int pass = 0; pass < 2; pass++)
1929 for (tree p1 = pass ? ctx2 : ctx1; p1; p1 = TREE_CHAIN (p1))
1931 tree p2;
1932 for (p2 = pass ? ctx1 : ctx2; p2; p2 = TREE_CHAIN (p2))
1933 if (OMP_TP_NAME (p1) == OMP_TP_NAME (p2))
1935 if (OMP_TP_NAME (p1) == NULL_TREE)
1937 if (set == OMP_TRAIT_SET_USER
1938 && sel == OMP_TRAIT_USER_CONDITION)
1940 if (integer_zerop (OMP_TP_VALUE (p1))
1941 != integer_zerop (OMP_TP_VALUE (p2)))
1942 return 2;
1943 break;
1945 if (simple_cst_equal (OMP_TP_VALUE (p1), OMP_TP_VALUE (p2)))
1946 break;
1948 else if (OMP_TP_NAME (p1) == OMP_TP_NAMELIST_NODE)
1950 /* Handle string constant vs identifier comparison for
1951 name-list properties. */
1952 const char *n1 = omp_context_name_list_prop (p1);
1953 const char *n2 = omp_context_name_list_prop (p2);
1954 if (n1 && n2 && !strcmp (n1, n2))
1955 break;
1957 else
1958 break;
1960 if (p2 == NULL_TREE)
1962 int r = pass ? -1 : 1;
1963 if (ret && ret != r)
1964 return 2;
1965 else if (pass)
1966 return r;
1967 else
1969 ret = r;
1970 break;
1974 return ret;
1977 /* Compare single context selector sets CTX1 and CTX2 with SET name.
1978 CTX1 and CTX2 are lists of trait-selectors.
1979 Return 0 if CTX1 is equal to CTX2,
1980 -1 if CTX1 is a strict subset of CTX2,
1981 1 if CTX2 is a strict subset of CTX1, or
1982 2 if neither context is a subset of another one. */
1985 omp_context_selector_set_compare (enum omp_tss_code set, tree ctx1, tree ctx2)
1988 /* If either list includes an ignored selector trait, neither can
1989 be a subset of the other. */
1990 for (tree ts = ctx1; ts; ts = TREE_CHAIN (ts))
1991 if (OMP_TS_CODE (ts) == OMP_TRAIT_INVALID)
1992 return 2;
1993 for (tree ts = ctx2; ts; ts = TREE_CHAIN (ts))
1994 if (OMP_TS_CODE (ts) == OMP_TRAIT_INVALID)
1995 return 2;
1997 bool swapped = false;
1998 int ret = 0;
1999 int len1 = list_length (ctx1);
2000 int len2 = list_length (ctx2);
2001 int cnt = 0;
2002 if (len1 < len2)
2004 swapped = true;
2005 std::swap (ctx1, ctx2);
2006 std::swap (len1, len2);
2009 if (set == OMP_TRAIT_SET_CONSTRUCT)
2011 tree ts1;
2012 tree ts2 = ctx2;
2013 /* Handle construct set specially. In this case the order
2014 of the selector matters too. */
2015 for (ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
2016 if (OMP_TS_CODE (ts1) == OMP_TS_CODE (ts2))
2018 int r = 0;
2019 if (OMP_TS_CODE (ts1) == OMP_TRAIT_CONSTRUCT_SIMD)
2020 r = omp_construct_simd_compare (OMP_TS_PROPERTIES (ts1),
2021 OMP_TS_PROPERTIES (ts2));
2022 if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
2023 return 2;
2024 if (ret == 0)
2025 ret = r;
2026 ts2 = TREE_CHAIN (ts2);
2027 if (ts2 == NULL_TREE)
2029 ts1 = TREE_CHAIN (ts1);
2030 break;
2033 else if (ret < 0)
2034 return 2;
2035 else
2036 ret = 1;
2037 if (ts2 != NULL_TREE)
2038 return 2;
2039 if (ts1 != NULL_TREE)
2041 if (ret < 0)
2042 return 2;
2043 ret = 1;
2045 if (ret == 0)
2046 return 0;
2047 return swapped ? -ret : ret;
2049 for (tree ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
2051 enum omp_ts_code sel = OMP_TS_CODE (ts1);
2052 tree ts2;
2053 for (ts2 = ctx2; ts2; ts2 = TREE_CHAIN (ts2))
2054 if (sel == OMP_TS_CODE (ts2))
2056 tree score1 = OMP_TS_SCORE (ts1);
2057 tree score2 = OMP_TS_SCORE (ts2);
2058 if (score1 && score2 && !simple_cst_equal (score1, score2))
2059 return 2;
2061 int r = omp_context_selector_props_compare (set, OMP_TS_CODE (ts1),
2062 OMP_TS_PROPERTIES (ts1),
2063 OMP_TS_PROPERTIES (ts2));
2064 if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
2065 return 2;
2066 if (ret == 0)
2067 ret = r;
2068 cnt++;
2069 break;
2071 if (ts2 == NULL_TREE)
2073 if (ret == -1)
2074 return 2;
2075 ret = 1;
2078 if (cnt < len2)
2079 return 2;
2080 if (ret == 0)
2081 return 0;
2082 return swapped ? -ret : ret;
2085 /* Compare whole context selector specification CTX1 and CTX2.
2086 Return 0 if CTX1 is equal to CTX2,
2087 -1 if CTX1 is a strict subset of CTX2,
2088 1 if CTX2 is a strict subset of CTX1, or
2089 2 if neither context is a subset of another one. */
2091 static int
2092 omp_context_selector_compare (tree ctx1, tree ctx2)
2094 bool swapped = false;
2095 int ret = 0;
2096 int len1 = list_length (ctx1);
2097 int len2 = list_length (ctx2);
2098 int cnt = 0;
2099 if (len1 < len2)
2101 swapped = true;
2102 std::swap (ctx1, ctx2);
2103 std::swap (len1, len2);
2105 for (tree tss1 = ctx1; tss1; tss1 = TREE_CHAIN (tss1))
2107 enum omp_tss_code set = OMP_TSS_CODE (tss1);
2108 tree tss2;
2109 for (tss2 = ctx2; tss2; tss2 = TREE_CHAIN (tss2))
2110 if (set == OMP_TSS_CODE (tss2))
2112 int r
2113 = omp_context_selector_set_compare
2114 (set, OMP_TSS_TRAIT_SELECTORS (tss1),
2115 OMP_TSS_TRAIT_SELECTORS (tss2));
2116 if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
2117 return 2;
2118 if (ret == 0)
2119 ret = r;
2120 cnt++;
2121 break;
2123 if (tss2 == NULL_TREE)
2125 if (ret == -1)
2126 return 2;
2127 ret = 1;
2130 if (cnt < len2)
2131 return 2;
2132 if (ret == 0)
2133 return 0;
2134 return swapped ? -ret : ret;
2137 /* From context selector CTX, return trait-selector with name SEL in
2138 trait-selector-set with name SET if any, or NULL_TREE if not found. */
2139 tree
2140 omp_get_context_selector (tree ctx, enum omp_tss_code set,
2141 enum omp_ts_code sel)
2143 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
2144 if (OMP_TSS_CODE (tss) == set)
2145 for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
2146 if (OMP_TS_CODE (ts) == sel)
2147 return ts;
2148 return NULL_TREE;
2151 /* Similar, but returns the whole trait-selector list for SET in CTX. */
2152 tree
2153 omp_get_context_selector_list (tree ctx, enum omp_tss_code set)
2155 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
2156 if (OMP_TSS_CODE (tss) == set)
2157 return OMP_TSS_TRAIT_SELECTORS (tss);
2158 return NULL_TREE;
2161 /* Map string S onto a trait selector set code. */
2162 enum omp_tss_code
2163 omp_lookup_tss_code (const char * s)
2165 for (int i = 0; i < OMP_TRAIT_SET_LAST; i++)
2166 if (strcmp (s, omp_tss_map[i]) == 0)
2167 return (enum omp_tss_code) i;
2168 return OMP_TRAIT_SET_INVALID;
2171 /* Map string S onto a trait selector code for set SET. */
2172 enum omp_ts_code
2173 omp_lookup_ts_code (enum omp_tss_code set, const char *s)
2175 unsigned int mask = 1 << set;
2176 for (int i = 0; i < OMP_TRAIT_LAST; i++)
2177 if ((mask & omp_ts_map[i].tss_mask) != 0
2178 && strcmp (s, omp_ts_map[i].name) == 0)
2179 return (enum omp_ts_code) i;
2180 return OMP_TRAIT_INVALID;
2183 /* Needs to be a GC-friendly widest_int variant, but precision is
2184 desirable to be the same on all targets. */
2185 typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
2187 /* Compute *SCORE for context selector CTX. Return true if the score
2188 would be different depending on whether it is a declare simd clone or
2189 not. DECLARE_SIMD should be true for the case when it would be
2190 a declare simd clone. */
2192 static bool
2193 omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
2195 tree selectors
2196 = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
2197 bool has_kind = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
2198 OMP_TRAIT_DEVICE_KIND);
2199 bool has_arch = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
2200 OMP_TRAIT_DEVICE_ARCH);
2201 bool has_isa = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
2202 OMP_TRAIT_DEVICE_ISA);
2203 bool ret = false;
2204 *score = 1;
2205 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
2206 if (OMP_TSS_TRAIT_SELECTORS (tss) != selectors)
2207 for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
2209 tree s = OMP_TS_SCORE (ts);
2210 if (s && TREE_CODE (s) == INTEGER_CST)
2211 *score += score_wide_int::from (wi::to_wide (s),
2212 TYPE_SIGN (TREE_TYPE (s)));
2215 if (selectors || has_kind || has_arch || has_isa)
2217 int nconstructs = list_length (selectors);
2218 enum tree_code *constructs = NULL;
2219 if (nconstructs)
2221 constructs
2222 = (enum tree_code *) alloca (nconstructs
2223 * sizeof (enum tree_code));
2224 omp_construct_traits_to_codes (selectors, nconstructs, constructs);
2226 int *scores
2227 = (int *) alloca ((2 * nconstructs + 2) * sizeof (int));
2228 if (omp_construct_selector_matches (constructs, nconstructs, scores)
2229 == 2)
2230 ret = true;
2231 int b = declare_simd ? nconstructs + 1 : 0;
2232 if (scores[b + nconstructs] + 4U < score->get_precision ())
2234 for (int n = 0; n < nconstructs; ++n)
2236 if (scores[b + n] < 0)
2238 *score = -1;
2239 return ret;
2241 *score += wi::shifted_mask <score_wide_int> (scores[b + n], 1, false);
2243 if (has_kind)
2244 *score += wi::shifted_mask <score_wide_int> (scores[b + nconstructs],
2245 1, false);
2246 if (has_arch)
2247 *score += wi::shifted_mask <score_wide_int> (scores[b + nconstructs] + 1,
2248 1, false);
2249 if (has_isa)
2250 *score += wi::shifted_mask <score_wide_int> (scores[b + nconstructs] + 2,
2251 1, false);
2253 else /* FIXME: Implement this. */
2254 gcc_unreachable ();
2256 return ret;
2259 /* Class describing a single variant. */
2260 struct GTY(()) omp_declare_variant_entry {
2261 /* NODE of the variant. */
2262 cgraph_node *variant;
2263 /* Score if not in declare simd clone. */
2264 score_wide_int score;
2265 /* Score if in declare simd clone. */
2266 score_wide_int score_in_declare_simd_clone;
2267 /* Context selector for the variant. */
2268 tree ctx;
2269 /* True if the context selector is known to match already. */
2270 bool matches;
2273 /* Class describing a function with variants. */
2274 struct GTY((for_user)) omp_declare_variant_base_entry {
2275 /* NODE of the base function. */
2276 cgraph_node *base;
2277 /* NODE of the artificial function created for the deferred variant
2278 resolution. */
2279 cgraph_node *node;
2280 /* Vector of the variants. */
2281 vec<omp_declare_variant_entry, va_gc> *variants;
2284 struct omp_declare_variant_hasher
2285 : ggc_ptr_hash<omp_declare_variant_base_entry> {
2286 static hashval_t hash (omp_declare_variant_base_entry *);
2287 static bool equal (omp_declare_variant_base_entry *,
2288 omp_declare_variant_base_entry *);
2291 hashval_t
2292 omp_declare_variant_hasher::hash (omp_declare_variant_base_entry *x)
2294 inchash::hash hstate;
2295 hstate.add_int (DECL_UID (x->base->decl));
2296 hstate.add_int (x->variants->length ());
2297 omp_declare_variant_entry *variant;
2298 unsigned int i;
2299 FOR_EACH_VEC_SAFE_ELT (x->variants, i, variant)
2301 hstate.add_int (DECL_UID (variant->variant->decl));
2302 hstate.add_wide_int (variant->score);
2303 hstate.add_wide_int (variant->score_in_declare_simd_clone);
2304 hstate.add_ptr (variant->ctx);
2305 hstate.add_int (variant->matches);
2307 return hstate.end ();
2310 bool
2311 omp_declare_variant_hasher::equal (omp_declare_variant_base_entry *x,
2312 omp_declare_variant_base_entry *y)
2314 if (x->base != y->base
2315 || x->variants->length () != y->variants->length ())
2316 return false;
2317 omp_declare_variant_entry *variant;
2318 unsigned int i;
2319 FOR_EACH_VEC_SAFE_ELT (x->variants, i, variant)
2320 if (variant->variant != (*y->variants)[i].variant
2321 || variant->score != (*y->variants)[i].score
2322 || (variant->score_in_declare_simd_clone
2323 != (*y->variants)[i].score_in_declare_simd_clone)
2324 || variant->ctx != (*y->variants)[i].ctx
2325 || variant->matches != (*y->variants)[i].matches)
2326 return false;
2327 return true;
2330 static GTY(()) hash_table<omp_declare_variant_hasher> *omp_declare_variants;
2332 struct omp_declare_variant_alt_hasher
2333 : ggc_ptr_hash<omp_declare_variant_base_entry> {
2334 static hashval_t hash (omp_declare_variant_base_entry *);
2335 static bool equal (omp_declare_variant_base_entry *,
2336 omp_declare_variant_base_entry *);
2339 hashval_t
2340 omp_declare_variant_alt_hasher::hash (omp_declare_variant_base_entry *x)
2342 return DECL_UID (x->node->decl);
2345 bool
2346 omp_declare_variant_alt_hasher::equal (omp_declare_variant_base_entry *x,
2347 omp_declare_variant_base_entry *y)
2349 return x->node == y->node;
2352 static GTY(()) hash_table<omp_declare_variant_alt_hasher>
2353 *omp_declare_variant_alt;
2355 /* Try to resolve declare variant after gimplification. */
2357 static tree
2358 omp_resolve_late_declare_variant (tree alt)
2360 cgraph_node *node = cgraph_node::get (alt);
2361 cgraph_node *cur_node = cgraph_node::get (cfun->decl);
2362 if (node == NULL
2363 || !node->declare_variant_alt
2364 || !cfun->after_inlining)
2365 return alt;
2367 omp_declare_variant_base_entry entry;
2368 entry.base = NULL;
2369 entry.node = node;
2370 entry.variants = NULL;
2371 omp_declare_variant_base_entry *entryp
2372 = omp_declare_variant_alt->find_with_hash (&entry, DECL_UID (alt));
2374 unsigned int i, j;
2375 omp_declare_variant_entry *varentry1, *varentry2;
2376 auto_vec <bool, 16> matches;
2377 unsigned int nmatches = 0;
2378 FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
2380 if (varentry1->matches)
2382 /* This has been checked to be ok already. */
2383 matches.safe_push (true);
2384 nmatches++;
2385 continue;
2387 switch (omp_context_selector_matches (varentry1->ctx))
2389 case 0:
2390 matches.safe_push (false);
2391 break;
2392 case -1:
2393 return alt;
2394 default:
2395 matches.safe_push (true);
2396 nmatches++;
2397 break;
2401 if (nmatches == 0)
2402 return entryp->base->decl;
2404 /* A context selector that is a strict subset of another context selector
2405 has a score of zero. */
2406 FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
2407 if (matches[i])
2409 for (j = i + 1;
2410 vec_safe_iterate (entryp->variants, j, &varentry2); ++j)
2411 if (matches[j])
2413 int r = omp_context_selector_compare (varentry1->ctx,
2414 varentry2->ctx);
2415 if (r == -1)
2417 /* ctx1 is a strict subset of ctx2, ignore ctx1. */
2418 matches[i] = false;
2419 break;
2421 else if (r == 1)
2422 /* ctx2 is a strict subset of ctx1, remove ctx2. */
2423 matches[j] = false;
2427 score_wide_int max_score = -1;
2428 varentry2 = NULL;
2429 FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
2430 if (matches[i])
2432 score_wide_int score
2433 = (cur_node->simdclone ? varentry1->score_in_declare_simd_clone
2434 : varentry1->score);
2435 if (score > max_score)
2437 max_score = score;
2438 varentry2 = varentry1;
2441 return varentry2->variant->decl;
2444 /* Hook to adjust hash tables on cgraph_node removal. */
2446 static void
2447 omp_declare_variant_remove_hook (struct cgraph_node *node, void *)
2449 if (!node->declare_variant_alt)
2450 return;
2452 /* Drop this hash table completely. */
2453 omp_declare_variants = NULL;
2454 /* And remove node from the other hash table. */
2455 if (omp_declare_variant_alt)
2457 omp_declare_variant_base_entry entry;
2458 entry.base = NULL;
2459 entry.node = node;
2460 entry.variants = NULL;
2461 omp_declare_variant_alt->remove_elt_with_hash (&entry,
2462 DECL_UID (node->decl));
2466 /* Try to resolve declare variant, return the variant decl if it should
2467 be used instead of base, or base otherwise. */
2469 tree
2470 omp_resolve_declare_variant (tree base)
2472 tree variant1 = NULL_TREE, variant2 = NULL_TREE;
2473 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
2474 return omp_resolve_late_declare_variant (base);
2476 auto_vec <tree, 16> variants;
2477 auto_vec <bool, 16> defer;
2478 bool any_deferred = false;
2479 for (tree attr = DECL_ATTRIBUTES (base); attr; attr = TREE_CHAIN (attr))
2481 attr = lookup_attribute ("omp declare variant base", attr);
2482 if (attr == NULL_TREE)
2483 break;
2484 if (TREE_CODE (TREE_PURPOSE (TREE_VALUE (attr))) != FUNCTION_DECL)
2485 continue;
2486 cgraph_node *node = cgraph_node::get (base);
2487 /* If this is already a magic decl created by this function,
2488 don't process it again. */
2489 if (node && node->declare_variant_alt)
2490 return base;
2491 switch (omp_context_selector_matches (TREE_VALUE (TREE_VALUE (attr))))
2493 case 0:
2494 /* No match, ignore. */
2495 break;
2496 case -1:
2497 /* Needs to be deferred. */
2498 any_deferred = true;
2499 variants.safe_push (attr);
2500 defer.safe_push (true);
2501 break;
2502 default:
2503 variants.safe_push (attr);
2504 defer.safe_push (false);
2505 break;
2508 if (variants.length () == 0)
2509 return base;
2511 if (any_deferred)
2513 score_wide_int max_score1 = 0;
2514 score_wide_int max_score2 = 0;
2515 bool first = true;
2516 unsigned int i;
2517 tree attr1, attr2;
2518 omp_declare_variant_base_entry entry;
2519 entry.base = cgraph_node::get_create (base);
2520 entry.node = NULL;
2521 vec_alloc (entry.variants, variants.length ());
2522 FOR_EACH_VEC_ELT (variants, i, attr1)
2524 score_wide_int score1;
2525 score_wide_int score2;
2526 bool need_two;
2527 tree ctx = TREE_VALUE (TREE_VALUE (attr1));
2528 need_two = omp_context_compute_score (ctx, &score1, false);
2529 if (need_two)
2530 omp_context_compute_score (ctx, &score2, true);
2531 else
2532 score2 = score1;
2533 if (first)
2535 first = false;
2536 max_score1 = score1;
2537 max_score2 = score2;
2538 if (!defer[i])
2540 variant1 = attr1;
2541 variant2 = attr1;
2544 else
2546 if (max_score1 == score1)
2547 variant1 = NULL_TREE;
2548 else if (score1 > max_score1)
2550 max_score1 = score1;
2551 variant1 = defer[i] ? NULL_TREE : attr1;
2553 if (max_score2 == score2)
2554 variant2 = NULL_TREE;
2555 else if (score2 > max_score2)
2557 max_score2 = score2;
2558 variant2 = defer[i] ? NULL_TREE : attr1;
2561 omp_declare_variant_entry varentry;
2562 varentry.variant
2563 = cgraph_node::get_create (TREE_PURPOSE (TREE_VALUE (attr1)));
2564 varentry.score = score1;
2565 varentry.score_in_declare_simd_clone = score2;
2566 varentry.ctx = ctx;
2567 varentry.matches = !defer[i];
2568 entry.variants->quick_push (varentry);
2571 /* If there is a clear winner variant with the score which is not
2572 deferred, verify it is not a strict subset of any other context
2573 selector and if it is not, it is the best alternative no matter
2574 whether the others do or don't match. */
2575 if (variant1 && variant1 == variant2)
2577 tree ctx1 = TREE_VALUE (TREE_VALUE (variant1));
2578 FOR_EACH_VEC_ELT (variants, i, attr2)
2580 if (attr2 == variant1)
2581 continue;
2582 tree ctx2 = TREE_VALUE (TREE_VALUE (attr2));
2583 int r = omp_context_selector_compare (ctx1, ctx2);
2584 if (r == -1)
2586 /* The winner is a strict subset of ctx2, can't
2587 decide now. */
2588 variant1 = NULL_TREE;
2589 break;
2592 if (variant1)
2594 vec_free (entry.variants);
2595 return TREE_PURPOSE (TREE_VALUE (variant1));
2599 static struct cgraph_node_hook_list *node_removal_hook_holder;
2600 if (!node_removal_hook_holder)
2601 node_removal_hook_holder
2602 = symtab->add_cgraph_removal_hook (omp_declare_variant_remove_hook,
2603 NULL);
2605 if (omp_declare_variants == NULL)
2606 omp_declare_variants
2607 = hash_table<omp_declare_variant_hasher>::create_ggc (64);
2608 omp_declare_variant_base_entry **slot
2609 = omp_declare_variants->find_slot (&entry, INSERT);
2610 if (*slot != NULL)
2612 vec_free (entry.variants);
2613 return (*slot)->node->decl;
2616 *slot = ggc_cleared_alloc<omp_declare_variant_base_entry> ();
2617 (*slot)->base = entry.base;
2618 (*slot)->node = entry.base;
2619 (*slot)->variants = entry.variants;
2620 tree alt = build_decl (DECL_SOURCE_LOCATION (base), FUNCTION_DECL,
2621 DECL_NAME (base), TREE_TYPE (base));
2622 DECL_ARTIFICIAL (alt) = 1;
2623 DECL_IGNORED_P (alt) = 1;
2624 TREE_STATIC (alt) = 1;
2625 tree attributes = DECL_ATTRIBUTES (base);
2626 if (lookup_attribute ("noipa", attributes) == NULL)
2628 attributes = tree_cons (get_identifier ("noipa"), NULL, attributes);
2629 if (lookup_attribute ("noinline", attributes) == NULL)
2630 attributes = tree_cons (get_identifier ("noinline"), NULL,
2631 attributes);
2632 if (lookup_attribute ("noclone", attributes) == NULL)
2633 attributes = tree_cons (get_identifier ("noclone"), NULL,
2634 attributes);
2635 if (lookup_attribute ("no_icf", attributes) == NULL)
2636 attributes = tree_cons (get_identifier ("no_icf"), NULL,
2637 attributes);
2639 DECL_ATTRIBUTES (alt) = attributes;
2640 DECL_INITIAL (alt) = error_mark_node;
2641 (*slot)->node = cgraph_node::create (alt);
2642 (*slot)->node->declare_variant_alt = 1;
2643 (*slot)->node->create_reference (entry.base, IPA_REF_ADDR);
2644 omp_declare_variant_entry *varentry;
2645 FOR_EACH_VEC_SAFE_ELT (entry.variants, i, varentry)
2646 (*slot)->node->create_reference (varentry->variant, IPA_REF_ADDR);
2647 if (omp_declare_variant_alt == NULL)
2648 omp_declare_variant_alt
2649 = hash_table<omp_declare_variant_alt_hasher>::create_ggc (64);
2650 *omp_declare_variant_alt->find_slot_with_hash (*slot, DECL_UID (alt),
2651 INSERT) = *slot;
2652 return alt;
2655 if (variants.length () == 1)
2656 return TREE_PURPOSE (TREE_VALUE (variants[0]));
2658 /* A context selector that is a strict subset of another context selector
2659 has a score of zero. */
2660 tree attr1, attr2;
2661 unsigned int i, j;
2662 FOR_EACH_VEC_ELT (variants, i, attr1)
2663 if (attr1)
2665 tree ctx1 = TREE_VALUE (TREE_VALUE (attr1));
2666 FOR_EACH_VEC_ELT_FROM (variants, j, attr2, i + 1)
2667 if (attr2)
2669 tree ctx2 = TREE_VALUE (TREE_VALUE (attr2));
2670 int r = omp_context_selector_compare (ctx1, ctx2);
2671 if (r == -1)
2673 /* ctx1 is a strict subset of ctx2, remove
2674 attr1 from the vector. */
2675 variants[i] = NULL_TREE;
2676 break;
2678 else if (r == 1)
2679 /* ctx2 is a strict subset of ctx1, remove attr2
2680 from the vector. */
2681 variants[j] = NULL_TREE;
2684 score_wide_int max_score1 = 0;
2685 score_wide_int max_score2 = 0;
2686 bool first = true;
2687 FOR_EACH_VEC_ELT (variants, i, attr1)
2688 if (attr1)
2690 if (variant1)
2692 score_wide_int score1;
2693 score_wide_int score2;
2694 bool need_two;
2695 tree ctx;
2696 if (first)
2698 first = false;
2699 ctx = TREE_VALUE (TREE_VALUE (variant1));
2700 need_two = omp_context_compute_score (ctx, &max_score1, false);
2701 if (need_two)
2702 omp_context_compute_score (ctx, &max_score2, true);
2703 else
2704 max_score2 = max_score1;
2706 ctx = TREE_VALUE (TREE_VALUE (attr1));
2707 need_two = omp_context_compute_score (ctx, &score1, false);
2708 if (need_two)
2709 omp_context_compute_score (ctx, &score2, true);
2710 else
2711 score2 = score1;
2712 if (score1 > max_score1)
2714 max_score1 = score1;
2715 variant1 = attr1;
2717 if (score2 > max_score2)
2719 max_score2 = score2;
2720 variant2 = attr1;
2723 else
2725 variant1 = attr1;
2726 variant2 = attr1;
2729 /* If there is a disagreement on which variant has the highest score
2730 depending on whether it will be in a declare simd clone or not,
2731 punt for now and defer until after IPA where we will know that. */
2732 return ((variant1 && variant1 == variant2)
2733 ? TREE_PURPOSE (TREE_VALUE (variant1)) : base);
2736 void
2737 omp_lto_output_declare_variant_alt (lto_simple_output_block *ob,
2738 cgraph_node *node,
2739 lto_symtab_encoder_t encoder)
2741 gcc_assert (node->declare_variant_alt);
2743 omp_declare_variant_base_entry entry;
2744 entry.base = NULL;
2745 entry.node = node;
2746 entry.variants = NULL;
2747 omp_declare_variant_base_entry *entryp
2748 = omp_declare_variant_alt->find_with_hash (&entry, DECL_UID (node->decl));
2749 gcc_assert (entryp);
2751 int nbase = lto_symtab_encoder_lookup (encoder, entryp->base);
2752 gcc_assert (nbase != LCC_NOT_FOUND);
2753 streamer_write_hwi_stream (ob->main_stream, nbase);
2755 streamer_write_hwi_stream (ob->main_stream, entryp->variants->length ());
2757 unsigned int i;
2758 omp_declare_variant_entry *varentry;
2759 FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry)
2761 int nvar = lto_symtab_encoder_lookup (encoder, varentry->variant);
2762 gcc_assert (nvar != LCC_NOT_FOUND);
2763 streamer_write_hwi_stream (ob->main_stream, nvar);
2765 for (score_wide_int *w = &varentry->score; ;
2766 w = &varentry->score_in_declare_simd_clone)
2768 unsigned len = w->get_len ();
2769 streamer_write_hwi_stream (ob->main_stream, len);
2770 const HOST_WIDE_INT *val = w->get_val ();
2771 for (unsigned j = 0; j < len; j++)
2772 streamer_write_hwi_stream (ob->main_stream, val[j]);
2773 if (w == &varentry->score_in_declare_simd_clone)
2774 break;
2777 HOST_WIDE_INT cnt = -1;
2778 HOST_WIDE_INT i = varentry->matches ? 1 : 0;
2779 for (tree attr = DECL_ATTRIBUTES (entryp->base->decl);
2780 attr; attr = TREE_CHAIN (attr), i += 2)
2782 attr = lookup_attribute ("omp declare variant base", attr);
2783 if (attr == NULL_TREE)
2784 break;
2786 if (varentry->ctx == TREE_VALUE (TREE_VALUE (attr)))
2788 cnt = i;
2789 break;
2793 gcc_assert (cnt != -1);
2794 streamer_write_hwi_stream (ob->main_stream, cnt);
2798 void
2799 omp_lto_input_declare_variant_alt (lto_input_block *ib, cgraph_node *node,
2800 vec<symtab_node *> nodes)
2802 gcc_assert (node->declare_variant_alt);
2803 omp_declare_variant_base_entry *entryp
2804 = ggc_cleared_alloc<omp_declare_variant_base_entry> ();
2805 entryp->base = dyn_cast<cgraph_node *> (nodes[streamer_read_hwi (ib)]);
2806 entryp->node = node;
2807 unsigned int len = streamer_read_hwi (ib);
2808 vec_alloc (entryp->variants, len);
2810 for (unsigned int i = 0; i < len; i++)
2812 omp_declare_variant_entry varentry;
2813 varentry.variant
2814 = dyn_cast<cgraph_node *> (nodes[streamer_read_hwi (ib)]);
2815 for (score_wide_int *w = &varentry.score; ;
2816 w = &varentry.score_in_declare_simd_clone)
2818 unsigned len2 = streamer_read_hwi (ib);
2819 HOST_WIDE_INT arr[WIDE_INT_MAX_HWIS (1024)];
2820 gcc_assert (len2 <= WIDE_INT_MAX_HWIS (1024));
2821 for (unsigned int j = 0; j < len2; j++)
2822 arr[j] = streamer_read_hwi (ib);
2823 *w = score_wide_int::from_array (arr, len2, true);
2824 if (w == &varentry.score_in_declare_simd_clone)
2825 break;
2828 HOST_WIDE_INT cnt = streamer_read_hwi (ib);
2829 HOST_WIDE_INT j = 0;
2830 varentry.ctx = NULL_TREE;
2831 varentry.matches = (cnt & 1) ? true : false;
2832 cnt &= ~HOST_WIDE_INT_1;
2833 for (tree attr = DECL_ATTRIBUTES (entryp->base->decl);
2834 attr; attr = TREE_CHAIN (attr), j += 2)
2836 attr = lookup_attribute ("omp declare variant base", attr);
2837 if (attr == NULL_TREE)
2838 break;
2840 if (cnt == j)
2842 varentry.ctx = TREE_VALUE (TREE_VALUE (attr));
2843 break;
2846 gcc_assert (varentry.ctx != NULL_TREE);
2847 entryp->variants->quick_push (varentry);
2849 if (omp_declare_variant_alt == NULL)
2850 omp_declare_variant_alt
2851 = hash_table<omp_declare_variant_alt_hasher>::create_ggc (64);
2852 *omp_declare_variant_alt->find_slot_with_hash (entryp, DECL_UID (node->decl),
2853 INSERT) = entryp;
2856 /* Encode an oacc launch argument. This matches the GOMP_LAUNCH_PACK
2857 macro on gomp-constants.h. We do not check for overflow. */
2859 tree
2860 oacc_launch_pack (unsigned code, tree device, unsigned op)
2862 tree res;
2864 res = build_int_cst (unsigned_type_node, GOMP_LAUNCH_PACK (code, 0, op));
2865 if (device)
2867 device = fold_build2 (LSHIFT_EXPR, unsigned_type_node,
2868 device, build_int_cst (unsigned_type_node,
2869 GOMP_LAUNCH_DEVICE_SHIFT));
2870 res = fold_build2 (BIT_IOR_EXPR, unsigned_type_node, res, device);
2872 return res;
2875 /* Openacc compute grid dimension clauses are converted to an attribute
2876 attached to the function. This permits the target-side code to (a) massage
2877 the dimensions, (b) emit that data and (c) optimize. Non-constant
2878 dimensions are pushed onto ARGS.
2880 The attribute value is a TREE_LIST. A set of dimensions is
2881 represented as a list of INTEGER_CST. Those that are runtime
2882 exprs are represented as an INTEGER_CST of zero.
2884 TODO: Normally the attribute will just contain a single such list. If
2885 however it contains a list of lists, this will represent the use of
2886 device_type. Each member of the outer list is an assoc list of
2887 dimensions, keyed by the device type. The first entry will be the
2888 default. Well, that's the plan. */
2890 /* Replace any existing oacc fn attribute in ATTRIBS with updated
2891 dimensions. */
2893 tree
2894 oacc_replace_fn_attrib_attr (tree attribs, tree dims)
2896 tree ident = get_identifier (OACC_FN_ATTRIB);
2898 /* If we happen to be present as the first attrib, drop it. */
2899 if (attribs && TREE_PURPOSE (attribs) == ident)
2900 attribs = TREE_CHAIN (attribs);
2901 return tree_cons (ident, dims, attribs);
2904 /* Replace any existing oacc fn attribute on FN with updated
2905 dimensions. */
2907 void
2908 oacc_replace_fn_attrib (tree fn, tree dims)
2910 DECL_ATTRIBUTES (fn)
2911 = oacc_replace_fn_attrib_attr (DECL_ATTRIBUTES (fn), dims);
2914 /* Scan CLAUSES for launch dimensions and attach them to the oacc
2915 function attribute. Push any that are non-constant onto the ARGS
2916 list, along with an appropriate GOMP_LAUNCH_DIM tag. */
2918 void
2919 oacc_set_fn_attrib (tree fn, tree clauses, vec<tree> *args)
2921 /* Must match GOMP_DIM ordering. */
2922 static const omp_clause_code ids[]
2923 = { OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS,
2924 OMP_CLAUSE_VECTOR_LENGTH };
2925 unsigned ix;
2926 tree dims[GOMP_DIM_MAX];
2928 tree attr = NULL_TREE;
2929 unsigned non_const = 0;
2931 for (ix = GOMP_DIM_MAX; ix--;)
2933 tree clause = omp_find_clause (clauses, ids[ix]);
2934 tree dim = NULL_TREE;
2936 if (clause)
2937 dim = OMP_CLAUSE_EXPR (clause, ids[ix]);
2938 dims[ix] = dim;
2939 if (dim && TREE_CODE (dim) != INTEGER_CST)
2941 dim = integer_zero_node;
2942 non_const |= GOMP_DIM_MASK (ix);
2944 attr = tree_cons (NULL_TREE, dim, attr);
2947 oacc_replace_fn_attrib (fn, attr);
2949 if (non_const)
2951 /* Push a dynamic argument set. */
2952 args->safe_push (oacc_launch_pack (GOMP_LAUNCH_DIM,
2953 NULL_TREE, non_const));
2954 for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++)
2955 if (non_const & GOMP_DIM_MASK (ix))
2956 args->safe_push (dims[ix]);
2960 /* Verify OpenACC routine clauses.
2962 Returns 0 if FNDECL should be marked with an OpenACC 'routine' directive, 1
2963 if it has already been marked in compatible way, and -1 if incompatible.
2964 Upon returning, the chain of clauses will contain exactly one clause
2965 specifying the level of parallelism. */
2968 oacc_verify_routine_clauses (tree fndecl, tree *clauses, location_t loc,
2969 const char *routine_str)
2971 tree c_level = NULL_TREE;
2972 tree c_nohost = NULL_TREE;
2973 tree c_p = NULL_TREE;
2974 for (tree c = *clauses; c; c_p = c, c = OMP_CLAUSE_CHAIN (c))
2975 switch (OMP_CLAUSE_CODE (c))
2977 case OMP_CLAUSE_GANG:
2978 case OMP_CLAUSE_WORKER:
2979 case OMP_CLAUSE_VECTOR:
2980 case OMP_CLAUSE_SEQ:
2981 if (c_level == NULL_TREE)
2982 c_level = c;
2983 else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_CODE (c_level))
2985 /* This has already been diagnosed in the front ends. */
2986 /* Drop the duplicate clause. */
2987 gcc_checking_assert (c_p != NULL_TREE);
2988 OMP_CLAUSE_CHAIN (c_p) = OMP_CLAUSE_CHAIN (c);
2989 c = c_p;
2991 else
2993 error_at (OMP_CLAUSE_LOCATION (c),
2994 "%qs specifies a conflicting level of parallelism",
2995 omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
2996 inform (OMP_CLAUSE_LOCATION (c_level),
2997 "... to the previous %qs clause here",
2998 omp_clause_code_name[OMP_CLAUSE_CODE (c_level)]);
2999 /* Drop the conflicting clause. */
3000 gcc_checking_assert (c_p != NULL_TREE);
3001 OMP_CLAUSE_CHAIN (c_p) = OMP_CLAUSE_CHAIN (c);
3002 c = c_p;
3004 break;
3005 case OMP_CLAUSE_NOHOST:
3006 /* Don't worry about duplicate clauses here. */
3007 c_nohost = c;
3008 break;
3009 default:
3010 gcc_unreachable ();
3012 if (c_level == NULL_TREE)
3014 /* Default to an implicit 'seq' clause. */
3015 c_level = build_omp_clause (loc, OMP_CLAUSE_SEQ);
3016 OMP_CLAUSE_CHAIN (c_level) = *clauses;
3017 *clauses = c_level;
3019 /* In *clauses, we now have exactly one clause specifying the level of
3020 parallelism. */
3022 tree attr
3023 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl));
3024 if (attr != NULL_TREE)
3026 /* Diagnose if "#pragma omp declare target" has also been applied. */
3027 if (TREE_VALUE (attr) == NULL_TREE)
3029 /* See <https://gcc.gnu.org/PR93465>; the semantics of combining
3030 OpenACC and OpenMP 'target' are not clear. */
3031 error_at (loc,
3032 "cannot apply %<%s%> to %qD, which has also been"
3033 " marked with an OpenMP 'declare target' directive",
3034 routine_str, fndecl);
3035 /* Incompatible. */
3036 return -1;
3039 /* If a "#pragma acc routine" has already been applied, just verify
3040 this one for compatibility. */
3041 /* Collect previous directive's clauses. */
3042 tree c_level_p = NULL_TREE;
3043 tree c_nohost_p = NULL_TREE;
3044 for (tree c = TREE_VALUE (attr); c; c = OMP_CLAUSE_CHAIN (c))
3045 switch (OMP_CLAUSE_CODE (c))
3047 case OMP_CLAUSE_GANG:
3048 case OMP_CLAUSE_WORKER:
3049 case OMP_CLAUSE_VECTOR:
3050 case OMP_CLAUSE_SEQ:
3051 gcc_checking_assert (c_level_p == NULL_TREE);
3052 c_level_p = c;
3053 break;
3054 case OMP_CLAUSE_NOHOST:
3055 gcc_checking_assert (c_nohost_p == NULL_TREE);
3056 c_nohost_p = c;
3057 break;
3058 default:
3059 gcc_unreachable ();
3061 gcc_checking_assert (c_level_p != NULL_TREE);
3062 /* ..., and compare to current directive's, which we've already collected
3063 above. */
3064 tree c_diag;
3065 tree c_diag_p;
3066 /* Matching level of parallelism? */
3067 if (OMP_CLAUSE_CODE (c_level) != OMP_CLAUSE_CODE (c_level_p))
3069 c_diag = c_level;
3070 c_diag_p = c_level_p;
3071 goto incompatible;
3073 /* Matching 'nohost' clauses? */
3074 if ((c_nohost == NULL_TREE) != (c_nohost_p == NULL_TREE))
3076 c_diag = c_nohost;
3077 c_diag_p = c_nohost_p;
3078 goto incompatible;
3080 /* Compatible. */
3081 return 1;
3083 incompatible:
3084 if (c_diag != NULL_TREE)
3085 error_at (OMP_CLAUSE_LOCATION (c_diag),
3086 "incompatible %qs clause when applying"
3087 " %<%s%> to %qD, which has already been"
3088 " marked with an OpenACC 'routine' directive",
3089 omp_clause_code_name[OMP_CLAUSE_CODE (c_diag)],
3090 routine_str, fndecl);
3091 else if (c_diag_p != NULL_TREE)
3092 error_at (loc,
3093 "missing %qs clause when applying"
3094 " %<%s%> to %qD, which has already been"
3095 " marked with an OpenACC 'routine' directive",
3096 omp_clause_code_name[OMP_CLAUSE_CODE (c_diag_p)],
3097 routine_str, fndecl);
3098 else
3099 gcc_unreachable ();
3100 if (c_diag_p != NULL_TREE)
3101 inform (OMP_CLAUSE_LOCATION (c_diag_p),
3102 "... with %qs clause here",
3103 omp_clause_code_name[OMP_CLAUSE_CODE (c_diag_p)]);
3104 else
3106 /* In the front ends, we don't preserve location information for the
3107 OpenACC routine directive itself. However, that of c_level_p
3108 should be close. */
3109 location_t loc_routine = OMP_CLAUSE_LOCATION (c_level_p);
3110 inform (loc_routine, "... without %qs clause near to here",
3111 omp_clause_code_name[OMP_CLAUSE_CODE (c_diag)]);
3113 /* Incompatible. */
3114 return -1;
3117 return 0;
3120 /* Process the OpenACC 'routine' directive clauses to generate an attribute
3121 for the level of parallelism. All dimensions have a size of zero
3122 (dynamic). TREE_PURPOSE is set to indicate whether that dimension
3123 can have a loop partitioned on it. non-zero indicates
3124 yes, zero indicates no. By construction once a non-zero has been
3125 reached, further inner dimensions must also be non-zero. We set
3126 TREE_VALUE to zero for the dimensions that may be partitioned and
3127 1 for the other ones -- if a loop is (erroneously) spawned at
3128 an outer level, we don't want to try and partition it. */
3130 tree
3131 oacc_build_routine_dims (tree clauses)
3133 /* Must match GOMP_DIM ordering. */
3134 static const omp_clause_code ids[]
3135 = {OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ};
3136 int ix;
3137 int level = -1;
3139 for (; clauses; clauses = OMP_CLAUSE_CHAIN (clauses))
3140 for (ix = GOMP_DIM_MAX + 1; ix--;)
3141 if (OMP_CLAUSE_CODE (clauses) == ids[ix])
3143 level = ix;
3144 break;
3146 gcc_checking_assert (level >= 0);
3148 tree dims = NULL_TREE;
3150 for (ix = GOMP_DIM_MAX; ix--;)
3151 dims = tree_cons (build_int_cst (boolean_type_node, ix >= level),
3152 build_int_cst (integer_type_node, ix < level), dims);
3154 return dims;
3157 /* Retrieve the oacc function attrib and return it. Non-oacc
3158 functions will return NULL. */
3160 tree
3161 oacc_get_fn_attrib (tree fn)
3163 return lookup_attribute (OACC_FN_ATTRIB, DECL_ATTRIBUTES (fn));
3166 /* Return true if FN is an OpenMP or OpenACC offloading function. */
3168 bool
3169 offloading_function_p (tree fn)
3171 tree attrs = DECL_ATTRIBUTES (fn);
3172 return (lookup_attribute ("omp declare target", attrs)
3173 || lookup_attribute ("omp target entrypoint", attrs));
3176 /* Extract an oacc execution dimension from FN. FN must be an
3177 offloaded function or routine that has already had its execution
3178 dimensions lowered to the target-specific values. */
3181 oacc_get_fn_dim_size (tree fn, int axis)
3183 tree attrs = oacc_get_fn_attrib (fn);
3185 gcc_assert (axis < GOMP_DIM_MAX);
3187 tree dims = TREE_VALUE (attrs);
3188 while (axis--)
3189 dims = TREE_CHAIN (dims);
3191 int size = TREE_INT_CST_LOW (TREE_VALUE (dims));
3193 return size;
3196 /* Extract the dimension axis from an IFN_GOACC_DIM_POS or
3197 IFN_GOACC_DIM_SIZE call. */
3200 oacc_get_ifn_dim_arg (const gimple *stmt)
3202 gcc_checking_assert (gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_SIZE
3203 || gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_POS);
3204 tree arg = gimple_call_arg (stmt, 0);
3205 HOST_WIDE_INT axis = TREE_INT_CST_LOW (arg);
3207 gcc_checking_assert (axis >= 0 && axis < GOMP_DIM_MAX);
3208 return (int) axis;
3211 /* Build COMPONENT_REF and set TREE_THIS_VOLATILE and TREE_READONLY on it
3212 as appropriate. */
3214 tree
3215 omp_build_component_ref (tree obj, tree field)
3217 tree ret = build3 (COMPONENT_REF, TREE_TYPE (field), obj, field, NULL);
3218 if (TREE_THIS_VOLATILE (field))
3219 TREE_THIS_VOLATILE (ret) |= 1;
3220 if (TREE_READONLY (field))
3221 TREE_READONLY (ret) |= 1;
3222 return ret;
3225 /* Return true if NAME is the name of an omp_* runtime API call. */
3226 bool
3227 omp_runtime_api_procname (const char *name)
3229 if (!startswith (name, "omp_"))
3230 return false;
3232 static const char *omp_runtime_apis[] =
3234 /* This array has 3 sections. First omp_* calls that don't
3235 have any suffixes. */
3236 "aligned_alloc",
3237 "aligned_calloc",
3238 "alloc",
3239 "calloc",
3240 "free",
3241 "get_mapped_ptr",
3242 "realloc",
3243 "target_alloc",
3244 "target_associate_ptr",
3245 "target_disassociate_ptr",
3246 "target_free",
3247 "target_is_accessible",
3248 "target_is_present",
3249 "target_memcpy",
3250 "target_memcpy_async",
3251 "target_memcpy_rect",
3252 "target_memcpy_rect_async",
3253 NULL,
3254 /* Now omp_* calls that are available as omp_* and omp_*_; however, the
3255 DECL_NAME is always omp_* without tailing underscore. */
3256 "capture_affinity",
3257 "destroy_allocator",
3258 "destroy_lock",
3259 "destroy_nest_lock",
3260 "display_affinity",
3261 "fulfill_event",
3262 "get_active_level",
3263 "get_affinity_format",
3264 "get_cancellation",
3265 "get_default_allocator",
3266 "get_default_device",
3267 "get_device_num",
3268 "get_dynamic",
3269 "get_initial_device",
3270 "get_level",
3271 "get_max_active_levels",
3272 "get_max_task_priority",
3273 "get_max_teams",
3274 "get_max_threads",
3275 "get_nested",
3276 "get_num_devices",
3277 "get_num_places",
3278 "get_num_procs",
3279 "get_num_teams",
3280 "get_num_threads",
3281 "get_partition_num_places",
3282 "get_place_num",
3283 "get_proc_bind",
3284 "get_supported_active_levels",
3285 "get_team_num",
3286 "get_teams_thread_limit",
3287 "get_thread_limit",
3288 "get_thread_num",
3289 "get_wtick",
3290 "get_wtime",
3291 "in_explicit_task",
3292 "in_final",
3293 "in_parallel",
3294 "init_lock",
3295 "init_nest_lock",
3296 "is_initial_device",
3297 "pause_resource",
3298 "pause_resource_all",
3299 "set_affinity_format",
3300 "set_default_allocator",
3301 "set_lock",
3302 "set_nest_lock",
3303 "test_lock",
3304 "test_nest_lock",
3305 "unset_lock",
3306 "unset_nest_lock",
3307 NULL,
3308 /* And finally calls available as omp_*, omp_*_ and omp_*_8_; however,
3309 as DECL_NAME only omp_* and omp_*_8 appear. */
3310 "display_env",
3311 "get_ancestor_thread_num",
3312 "init_allocator",
3313 "get_partition_place_nums",
3314 "get_place_num_procs",
3315 "get_place_proc_ids",
3316 "get_schedule",
3317 "get_team_size",
3318 "set_default_device",
3319 "set_dynamic",
3320 "set_max_active_levels",
3321 "set_nested",
3322 "set_num_teams",
3323 "set_num_threads",
3324 "set_schedule",
3325 "set_teams_thread_limit"
3328 int mode = 0;
3329 for (unsigned i = 0; i < ARRAY_SIZE (omp_runtime_apis); i++)
3331 if (omp_runtime_apis[i] == NULL)
3333 mode++;
3334 continue;
3336 size_t len = strlen (omp_runtime_apis[i]);
3337 if (strncmp (name + 4, omp_runtime_apis[i], len) == 0
3338 && (name[4 + len] == '\0'
3339 || (mode > 1 && strcmp (name + 4 + len, "_8") == 0)))
3340 return true;
3342 return false;
3345 /* Return true if FNDECL is an omp_* runtime API call. */
3347 bool
3348 omp_runtime_api_call (const_tree fndecl)
3350 tree declname = DECL_NAME (fndecl);
3351 if (!declname
3352 || (DECL_CONTEXT (fndecl) != NULL_TREE
3353 && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL)
3354 || !TREE_PUBLIC (fndecl))
3355 return false;
3356 return omp_runtime_api_procname (IDENTIFIER_POINTER (declname));
3359 namespace omp_addr_tokenizer {
3361 /* We scan an expression by recursive descent, and build a vector of
3362 "omp_addr_token *" pointers representing a "parsed" version of the
3363 expression. The grammar we use is something like this:
3365 expr0::
3366 expr [section-access]
3368 expr::
3369 structured-expr access-method
3370 | array-base access-method
3372 structured-expr::
3373 structure-base component-selector
3375 arbitrary-expr::
3376 (anything else)
3378 structure-base::
3379 DECL access-method
3380 | structured-expr access-method
3381 | arbitrary-expr access-method
3383 array-base::
3384 DECL
3385 | arbitrary-expr
3387 access-method::
3388 DIRECT
3389 | REF
3390 | POINTER
3391 | REF_TO_POINTER
3392 | POINTER_OFFSET
3393 | REF_TO_POINTER_OFFSET
3394 | INDEXED_ARRAY
3395 | INDEXED_REF_TO_ARRAY
3396 | index-expr
3398 index-expr::
3399 INDEX_EXPR access-method
3401 component-selector::
3402 component-selector COMPONENT_REF
3403 | component-selector ARRAY_REF
3404 | COMPONENT_REF
3406 This tokenized form is then used both in parsing, for OpenMP clause
3407 expansion (for C and C++) and in gimplify.cc for sibling-list handling
3408 (for C, C++ and Fortran). */
3410 omp_addr_token::omp_addr_token (token_type t, tree e)
3411 : type(t), expr(e)
3415 omp_addr_token::omp_addr_token (access_method_kinds k, tree e)
3416 : type(ACCESS_METHOD), expr(e)
3418 u.access_kind = k;
3421 omp_addr_token::omp_addr_token (token_type t, structure_base_kinds k, tree e)
3422 : type(t), expr(e)
3424 u.structure_base_kind = k;
3427 static bool
3428 omp_parse_component_selector (tree *expr0)
3430 tree expr = *expr0;
3431 tree last_component = NULL_TREE;
3433 while (TREE_CODE (expr) == COMPONENT_REF
3434 || TREE_CODE (expr) == ARRAY_REF)
3436 if (TREE_CODE (expr) == COMPONENT_REF)
3437 last_component = expr;
3439 expr = TREE_OPERAND (expr, 0);
3441 if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE)
3442 break;
3445 if (!last_component)
3446 return false;
3448 *expr0 = last_component;
3449 return true;
3452 /* This handles references that have had convert_from_reference called on
3453 them, and also those that haven't. */
3455 static bool
3456 omp_parse_ref (tree *expr0)
3458 tree expr = *expr0;
3460 if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE)
3461 return true;
3462 else if ((TREE_CODE (expr) == INDIRECT_REF
3463 || (TREE_CODE (expr) == MEM_REF
3464 && integer_zerop (TREE_OPERAND (expr, 1))))
3465 && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
3467 *expr0 = TREE_OPERAND (expr, 0);
3468 return true;
3471 return false;
3474 static bool
3475 omp_parse_pointer (tree *expr0, bool *has_offset)
3477 tree expr = *expr0;
3479 *has_offset = false;
3481 if ((TREE_CODE (expr) == INDIRECT_REF
3482 || (TREE_CODE (expr) == MEM_REF
3483 && integer_zerop (TREE_OPERAND (expr, 1))))
3484 && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == POINTER_TYPE)
3486 expr = TREE_OPERAND (expr, 0);
3488 /* The Fortran FE sometimes emits a no-op cast here. */
3489 STRIP_NOPS (expr);
3491 while (1)
3493 if (TREE_CODE (expr) == COMPOUND_EXPR)
3495 expr = TREE_OPERAND (expr, 1);
3496 STRIP_NOPS (expr);
3498 else if (TREE_CODE (expr) == SAVE_EXPR)
3499 expr = TREE_OPERAND (expr, 0);
3500 else if (TREE_CODE (expr) == POINTER_PLUS_EXPR)
3502 *has_offset = true;
3503 expr = TREE_OPERAND (expr, 0);
3505 else
3506 break;
3509 STRIP_NOPS (expr);
3511 *expr0 = expr;
3512 return true;
3515 return false;
3518 static bool
3519 omp_parse_access_method (tree *expr0, enum access_method_kinds *kind)
3521 tree expr = *expr0;
3522 bool has_offset;
3524 if (omp_parse_ref (&expr))
3525 *kind = ACCESS_REF;
3526 else if (omp_parse_pointer (&expr, &has_offset))
3528 if (omp_parse_ref (&expr))
3529 *kind = has_offset ? ACCESS_REF_TO_POINTER_OFFSET
3530 : ACCESS_REF_TO_POINTER;
3531 else
3532 *kind = has_offset ? ACCESS_POINTER_OFFSET : ACCESS_POINTER;
3534 else if (TREE_CODE (expr) == ARRAY_REF)
3536 while (TREE_CODE (expr) == ARRAY_REF)
3537 expr = TREE_OPERAND (expr, 0);
3538 if (omp_parse_ref (&expr))
3539 *kind = ACCESS_INDEXED_REF_TO_ARRAY;
3540 else
3541 *kind = ACCESS_INDEXED_ARRAY;
3543 else
3544 *kind = ACCESS_DIRECT;
3546 STRIP_NOPS (expr);
3548 *expr0 = expr;
3549 return true;
3552 static bool
3553 omp_parse_access_methods (vec<omp_addr_token *> &addr_tokens, tree *expr0)
3555 tree expr = *expr0;
3556 enum access_method_kinds kind;
3557 tree am_expr;
3559 if (omp_parse_access_method (&expr, &kind))
3560 am_expr = expr;
3562 if (TREE_CODE (expr) == INDIRECT_REF
3563 || TREE_CODE (expr) == MEM_REF
3564 || TREE_CODE (expr) == ARRAY_REF)
3565 omp_parse_access_methods (addr_tokens, &expr);
3567 addr_tokens.safe_push (new omp_addr_token (kind, am_expr));
3569 *expr0 = expr;
3570 return true;
3573 static bool omp_parse_structured_expr (vec<omp_addr_token *> &, tree *);
3575 static bool
3576 omp_parse_structure_base (vec<omp_addr_token *> &addr_tokens,
3577 tree *expr0, structure_base_kinds *kind,
3578 vec<omp_addr_token *> &base_access_tokens,
3579 bool allow_structured = true)
3581 tree expr = *expr0;
3583 if (allow_structured)
3584 omp_parse_access_methods (base_access_tokens, &expr);
3586 if (DECL_P (expr))
3588 *kind = BASE_DECL;
3589 return true;
3592 if (allow_structured && omp_parse_structured_expr (addr_tokens, &expr))
3594 *kind = BASE_COMPONENT_EXPR;
3595 *expr0 = expr;
3596 return true;
3599 *kind = BASE_ARBITRARY_EXPR;
3600 *expr0 = expr;
3601 return true;
3604 static bool
3605 omp_parse_structured_expr (vec<omp_addr_token *> &addr_tokens, tree *expr0)
3607 tree expr = *expr0;
3608 tree base_component = NULL_TREE;
3609 structure_base_kinds struct_base_kind;
3610 auto_vec<omp_addr_token *> base_access_tokens;
3612 if (omp_parse_component_selector (&expr))
3613 base_component = expr;
3614 else
3615 return false;
3617 gcc_assert (TREE_CODE (expr) == COMPONENT_REF);
3618 expr = TREE_OPERAND (expr, 0);
3620 tree structure_base = expr;
3622 if (!omp_parse_structure_base (addr_tokens, &expr, &struct_base_kind,
3623 base_access_tokens))
3624 return false;
3626 addr_tokens.safe_push (new omp_addr_token (STRUCTURE_BASE, struct_base_kind,
3627 structure_base));
3628 addr_tokens.safe_splice (base_access_tokens);
3629 addr_tokens.safe_push (new omp_addr_token (COMPONENT_SELECTOR,
3630 base_component));
3632 *expr0 = expr;
3634 return true;
3637 static bool
3638 omp_parse_array_expr (vec<omp_addr_token *> &addr_tokens, tree *expr0)
3640 tree expr = *expr0;
3641 structure_base_kinds s_kind;
3642 auto_vec<omp_addr_token *> base_access_tokens;
3644 if (!omp_parse_structure_base (addr_tokens, &expr, &s_kind,
3645 base_access_tokens, false))
3646 return false;
3648 addr_tokens.safe_push (new omp_addr_token (ARRAY_BASE, s_kind, expr));
3649 addr_tokens.safe_splice (base_access_tokens);
3651 *expr0 = expr;
3652 return true;
3655 /* Return TRUE if the ACCESS_METHOD token at index 'i' has a further
3656 ACCESS_METHOD chained after it (e.g., if we're processing an expression
3657 containing multiple pointer indirections). */
3659 bool
3660 omp_access_chain_p (vec<omp_addr_token *> &addr_tokens, unsigned i)
3662 gcc_assert (addr_tokens[i]->type == ACCESS_METHOD);
3663 return (i + 1 < addr_tokens.length ()
3664 && addr_tokens[i + 1]->type == ACCESS_METHOD);
3667 /* Return the address of the object accessed by the ACCESS_METHOD token
3668 at 'i': either of the next access method's expr, or of EXPR if we're at
3669 the end of the list of tokens. */
3671 tree
3672 omp_accessed_addr (vec<omp_addr_token *> &addr_tokens, unsigned i, tree expr)
3674 if (i + 1 < addr_tokens.length ())
3675 return build_fold_addr_expr (addr_tokens[i + 1]->expr);
3676 else
3677 return build_fold_addr_expr (expr);
3680 } /* namespace omp_addr_tokenizer. */
3682 bool
3683 omp_parse_expr (vec<omp_addr_token *> &addr_tokens, tree expr)
3685 using namespace omp_addr_tokenizer;
3686 auto_vec<omp_addr_token *> expr_access_tokens;
3688 if (!omp_parse_access_methods (expr_access_tokens, &expr))
3689 return false;
3691 if (omp_parse_structured_expr (addr_tokens, &expr))
3693 else if (omp_parse_array_expr (addr_tokens, &expr))
3695 else
3696 return false;
3698 addr_tokens.safe_splice (expr_access_tokens);
3700 return true;
3703 DEBUG_FUNCTION void
3704 debug_omp_tokenized_addr (vec<omp_addr_token *> &addr_tokens,
3705 bool with_exprs)
3707 using namespace omp_addr_tokenizer;
3708 const char *sep = with_exprs ? " " : "";
3710 for (auto e : addr_tokens)
3712 const char *pfx = "";
3714 fputs (sep, stderr);
3716 switch (e->type)
3718 case COMPONENT_SELECTOR:
3719 fputs ("component_selector", stderr);
3720 break;
3721 case ACCESS_METHOD:
3722 switch (e->u.access_kind)
3724 case ACCESS_DIRECT:
3725 fputs ("access_direct", stderr);
3726 break;
3727 case ACCESS_REF:
3728 fputs ("access_ref", stderr);
3729 break;
3730 case ACCESS_POINTER:
3731 fputs ("access_pointer", stderr);
3732 break;
3733 case ACCESS_POINTER_OFFSET:
3734 fputs ("access_pointer_offset", stderr);
3735 break;
3736 case ACCESS_REF_TO_POINTER:
3737 fputs ("access_ref_to_pointer", stderr);
3738 break;
3739 case ACCESS_REF_TO_POINTER_OFFSET:
3740 fputs ("access_ref_to_pointer_offset", stderr);
3741 break;
3742 case ACCESS_INDEXED_ARRAY:
3743 fputs ("access_indexed_array", stderr);
3744 break;
3745 case ACCESS_INDEXED_REF_TO_ARRAY:
3746 fputs ("access_indexed_ref_to_array", stderr);
3747 break;
3749 break;
3750 case ARRAY_BASE:
3751 case STRUCTURE_BASE:
3752 pfx = e->type == ARRAY_BASE ? "array_" : "struct_";
3753 switch (e->u.structure_base_kind)
3755 case BASE_DECL:
3756 fprintf (stderr, "%sbase_decl", pfx);
3757 break;
3758 case BASE_COMPONENT_EXPR:
3759 fputs ("base_component_expr", stderr);
3760 break;
3761 case BASE_ARBITRARY_EXPR:
3762 fprintf (stderr, "%sbase_arbitrary_expr", pfx);
3763 break;
3765 break;
3767 if (with_exprs)
3769 fputs (" [", stderr);
3770 print_generic_expr (stderr, e->expr);
3771 fputc (']', stderr);
3772 sep = ",\n ";
3774 else
3775 sep = " ";
3778 fputs ("\n", stderr);
3782 #include "gt-omp-general.h"