Daily bump.
[official-gcc.git] / gcc / omp-general.cc
blobf4c5f5770474536adc14af866e04e3cef71eeede
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
119 || TREE_CODE (TREE_TYPE (v)) == BITINT_TYPE)
121 if (integer_onep (step))
122 *cond_code = LT_EXPR;
123 else
125 gcc_assert (integer_minus_onep (step));
126 *cond_code = GT_EXPR;
129 else
131 tree unit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v)));
132 gcc_assert (TREE_CODE (unit) == INTEGER_CST);
133 if (tree_int_cst_equal (unit, step))
134 *cond_code = LT_EXPR;
135 else
137 gcc_assert (wi::neg (wi::to_widest (unit))
138 == wi::to_widest (step));
139 *cond_code = GT_EXPR;
143 break;
145 case LE_EXPR:
146 if (POINTER_TYPE_P (TREE_TYPE (*n2)))
148 tree unit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v)));
149 gcc_assert (TREE_CODE (unit) == INTEGER_CST);
150 *n2 = fold_build_pointer_plus_loc (loc, *n2, unit);
152 else
153 *n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (*n2), *n2,
154 build_int_cst (TREE_TYPE (*n2), 1));
155 *cond_code = LT_EXPR;
156 break;
157 case GE_EXPR:
158 if (POINTER_TYPE_P (TREE_TYPE (*n2)))
160 tree unit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v)));
161 gcc_assert (TREE_CODE (unit) == INTEGER_CST);
162 unit = convert_to_ptrofftype_loc (loc, unit);
163 unit = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (unit),
164 unit);
165 *n2 = fold_build_pointer_plus_loc (loc, *n2, unit);
167 else
168 *n2 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (*n2), *n2,
169 build_int_cst (TREE_TYPE (*n2), 1));
170 *cond_code = GT_EXPR;
171 break;
172 default:
173 gcc_unreachable ();
177 /* Return the looping step from INCR, extracted from the step of a gimple omp
178 for statement. */
180 tree
181 omp_get_for_step_from_incr (location_t loc, tree incr)
183 tree step;
184 switch (TREE_CODE (incr))
186 case PLUS_EXPR:
187 step = TREE_OPERAND (incr, 1);
188 break;
189 case POINTER_PLUS_EXPR:
190 step = fold_convert (ssizetype, TREE_OPERAND (incr, 1));
191 break;
192 case MINUS_EXPR:
193 step = TREE_OPERAND (incr, 1);
194 step = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (step), step);
195 break;
196 default:
197 gcc_unreachable ();
199 return step;
202 /* Extract the header elements of parallel loop FOR_STMT and store
203 them into *FD. */
205 void
206 omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
207 struct omp_for_data_loop *loops)
209 tree t, var, *collapse_iter, *collapse_count;
210 tree count = NULL_TREE, iter_type = long_integer_type_node;
211 struct omp_for_data_loop *loop;
212 int i;
213 struct omp_for_data_loop dummy_loop;
214 location_t loc = gimple_location (for_stmt);
215 bool simd = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD;
216 bool distribute = gimple_omp_for_kind (for_stmt)
217 == GF_OMP_FOR_KIND_DISTRIBUTE;
218 bool taskloop = gimple_omp_for_kind (for_stmt)
219 == GF_OMP_FOR_KIND_TASKLOOP;
220 bool order_reproducible = false;
221 tree iterv, countv;
223 fd->for_stmt = for_stmt;
224 fd->pre = NULL;
225 fd->have_nowait = distribute || simd;
226 fd->have_ordered = false;
227 fd->have_reductemp = false;
228 fd->have_pointer_condtemp = false;
229 fd->have_scantemp = false;
230 fd->have_nonctrl_scantemp = false;
231 fd->non_rect = false;
232 fd->lastprivate_conditional = 0;
233 fd->tiling = NULL_TREE;
234 fd->collapse = 1;
235 fd->ordered = 0;
236 fd->first_nonrect = -1;
237 fd->last_nonrect = -1;
238 fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
239 fd->sched_modifiers = 0;
240 fd->chunk_size = NULL_TREE;
241 fd->simd_schedule = false;
242 fd->first_inner_iterations = NULL_TREE;
243 fd->factor = NULL_TREE;
244 fd->adjn1 = NULL_TREE;
245 collapse_iter = NULL;
246 collapse_count = NULL;
248 for (t = gimple_omp_for_clauses (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t))
249 switch (OMP_CLAUSE_CODE (t))
251 case OMP_CLAUSE_NOWAIT:
252 fd->have_nowait = true;
253 break;
254 case OMP_CLAUSE_ORDERED:
255 fd->have_ordered = true;
256 if (OMP_CLAUSE_ORDERED_DOACROSS (t))
258 if (OMP_CLAUSE_ORDERED_EXPR (t))
259 fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t));
260 else
261 fd->ordered = -1;
263 break;
264 case OMP_CLAUSE_SCHEDULE:
265 gcc_assert (!distribute && !taskloop);
266 fd->sched_kind
267 = (enum omp_clause_schedule_kind)
268 (OMP_CLAUSE_SCHEDULE_KIND (t) & OMP_CLAUSE_SCHEDULE_MASK);
269 fd->sched_modifiers = (OMP_CLAUSE_SCHEDULE_KIND (t)
270 & ~OMP_CLAUSE_SCHEDULE_MASK);
271 fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
272 fd->simd_schedule = OMP_CLAUSE_SCHEDULE_SIMD (t);
273 break;
274 case OMP_CLAUSE_DIST_SCHEDULE:
275 gcc_assert (distribute);
276 fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t);
277 break;
278 case OMP_CLAUSE_COLLAPSE:
279 fd->collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t));
280 if (fd->collapse > 1)
282 collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t);
283 collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t);
285 break;
286 case OMP_CLAUSE_TILE:
287 fd->tiling = OMP_CLAUSE_TILE_LIST (t);
288 fd->collapse = list_length (fd->tiling);
289 gcc_assert (fd->collapse);
290 collapse_iter = &OMP_CLAUSE_TILE_ITERVAR (t);
291 collapse_count = &OMP_CLAUSE_TILE_COUNT (t);
292 break;
293 case OMP_CLAUSE__REDUCTEMP_:
294 fd->have_reductemp = true;
295 break;
296 case OMP_CLAUSE_LASTPRIVATE:
297 if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (t))
298 fd->lastprivate_conditional++;
299 break;
300 case OMP_CLAUSE__CONDTEMP_:
301 if (POINTER_TYPE_P (TREE_TYPE (OMP_CLAUSE_DECL (t))))
302 fd->have_pointer_condtemp = true;
303 break;
304 case OMP_CLAUSE__SCANTEMP_:
305 fd->have_scantemp = true;
306 if (!OMP_CLAUSE__SCANTEMP__ALLOC (t)
307 && !OMP_CLAUSE__SCANTEMP__CONTROL (t))
308 fd->have_nonctrl_scantemp = true;
309 break;
310 case OMP_CLAUSE_ORDER:
311 /* FIXME: For OpenMP 5.2 this should change to
312 if (OMP_CLAUSE_ORDER_REPRODUCIBLE (t))
313 (with the exception of loop construct but that lowers to
314 no schedule/dist_schedule clauses currently). */
315 if (!OMP_CLAUSE_ORDER_UNCONSTRAINED (t))
316 order_reproducible = true;
317 default:
318 break;
321 if (fd->ordered == -1)
322 fd->ordered = fd->collapse;
324 /* For order(reproducible:concurrent) schedule ({dynamic,guided,runtime})
325 we have either the option to expensively remember at runtime how we've
326 distributed work from first loop and reuse that in following loops with
327 the same number of iterations and schedule, or just force static schedule.
328 OpenMP API calls etc. aren't allowed in order(concurrent) bodies so
329 users can't observe it easily anyway. */
330 if (order_reproducible)
331 fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
332 if (fd->collapse > 1 || fd->tiling)
333 fd->loops = loops;
334 else
335 fd->loops = &fd->loop;
337 if (fd->ordered && fd->collapse == 1 && loops != NULL)
339 fd->loops = loops;
340 iterv = NULL_TREE;
341 countv = NULL_TREE;
342 collapse_iter = &iterv;
343 collapse_count = &countv;
346 /* FIXME: for now map schedule(auto) to schedule(static).
347 There should be analysis to determine whether all iterations
348 are approximately the same amount of work (then schedule(static)
349 is best) or if it varies (then schedule(dynamic,N) is better). */
350 if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO)
352 fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
353 gcc_assert (fd->chunk_size == NULL);
355 gcc_assert ((fd->collapse == 1 && !fd->tiling) || collapse_iter != NULL);
356 if (taskloop)
357 fd->sched_kind = OMP_CLAUSE_SCHEDULE_RUNTIME;
358 if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
359 gcc_assert (fd->chunk_size == NULL);
360 else if (fd->chunk_size == NULL)
362 /* We only need to compute a default chunk size for ordered
363 static loops and dynamic loops. */
364 if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
365 || fd->have_ordered)
366 fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
367 ? integer_zero_node : integer_one_node;
370 int cnt = fd->ordered ? fd->ordered : fd->collapse;
371 int single_nonrect = -1;
372 tree single_nonrect_count = NULL_TREE;
373 enum tree_code single_nonrect_cond_code = ERROR_MARK;
374 for (i = 1; i < cnt; i++)
376 tree n1 = gimple_omp_for_initial (for_stmt, i);
377 tree n2 = gimple_omp_for_final (for_stmt, i);
378 if (TREE_CODE (n1) == TREE_VEC)
380 if (fd->non_rect)
382 single_nonrect = -1;
383 break;
385 for (int j = i - 1; j >= 0; j--)
386 if (TREE_VEC_ELT (n1, 0) == gimple_omp_for_index (for_stmt, j))
388 single_nonrect = j;
389 break;
391 fd->non_rect = true;
393 else if (TREE_CODE (n2) == TREE_VEC)
395 if (fd->non_rect)
397 single_nonrect = -1;
398 break;
400 for (int j = i - 1; j >= 0; j--)
401 if (TREE_VEC_ELT (n2, 0) == gimple_omp_for_index (for_stmt, j))
403 single_nonrect = j;
404 break;
406 fd->non_rect = true;
409 for (i = 0; i < cnt; i++)
411 if (i == 0
412 && fd->collapse == 1
413 && !fd->tiling
414 && (fd->ordered == 0 || loops == NULL))
415 loop = &fd->loop;
416 else if (loops != NULL)
417 loop = loops + i;
418 else
419 loop = &dummy_loop;
421 loop->v = gimple_omp_for_index (for_stmt, i);
422 gcc_assert (SSA_VAR_P (loop->v));
423 gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
424 || TREE_CODE (TREE_TYPE (loop->v)) == BITINT_TYPE
425 || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
426 var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
427 loop->n1 = gimple_omp_for_initial (for_stmt, i);
428 loop->m1 = NULL_TREE;
429 loop->m2 = NULL_TREE;
430 loop->outer = 0;
431 loop->non_rect_referenced = false;
432 if (TREE_CODE (loop->n1) == TREE_VEC)
434 for (int j = i - 1; j >= 0; j--)
435 if (TREE_VEC_ELT (loop->n1, 0) == gimple_omp_for_index (for_stmt, j))
437 loop->outer = i - j;
438 if (loops != NULL)
439 loops[j].non_rect_referenced = true;
440 if (fd->first_nonrect == -1 || fd->first_nonrect > j)
441 fd->first_nonrect = j;
442 break;
444 gcc_assert (loop->outer);
445 loop->m1 = TREE_VEC_ELT (loop->n1, 1);
446 loop->n1 = TREE_VEC_ELT (loop->n1, 2);
447 fd->non_rect = true;
448 fd->last_nonrect = i;
451 loop->cond_code = gimple_omp_for_cond (for_stmt, i);
452 loop->n2 = gimple_omp_for_final (for_stmt, i);
453 gcc_assert (loop->cond_code != NE_EXPR
454 || (gimple_omp_for_kind (for_stmt)
455 != GF_OMP_FOR_KIND_OACC_LOOP));
456 if (TREE_CODE (loop->n2) == TREE_VEC)
458 if (loop->outer)
459 gcc_assert (TREE_VEC_ELT (loop->n2, 0)
460 == gimple_omp_for_index (for_stmt, i - loop->outer));
461 else
462 for (int j = i - 1; j >= 0; j--)
463 if (TREE_VEC_ELT (loop->n2, 0) == gimple_omp_for_index (for_stmt, j))
465 loop->outer = i - j;
466 if (loops != NULL)
467 loops[j].non_rect_referenced = true;
468 if (fd->first_nonrect == -1 || fd->first_nonrect > j)
469 fd->first_nonrect = j;
470 break;
472 gcc_assert (loop->outer);
473 loop->m2 = TREE_VEC_ELT (loop->n2, 1);
474 loop->n2 = TREE_VEC_ELT (loop->n2, 2);
475 fd->non_rect = true;
476 fd->last_nonrect = i;
479 t = gimple_omp_for_incr (for_stmt, i);
480 gcc_assert (TREE_OPERAND (t, 0) == var);
481 loop->step = omp_get_for_step_from_incr (loc, t);
483 omp_adjust_for_condition (loc, &loop->cond_code, &loop->n2, loop->v,
484 loop->step);
486 if (simd
487 || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
488 && !fd->have_ordered))
490 if (fd->collapse == 1 && !fd->tiling)
491 iter_type = TREE_TYPE (loop->v);
492 else if (i == 0
493 || TYPE_PRECISION (iter_type)
494 < TYPE_PRECISION (TREE_TYPE (loop->v)))
496 if (TREE_CODE (iter_type) == BITINT_TYPE
497 || TREE_CODE (TREE_TYPE (loop->v)) == BITINT_TYPE)
498 iter_type
499 = build_bitint_type (TYPE_PRECISION (TREE_TYPE (loop->v)),
501 else
502 iter_type
503 = build_nonstandard_integer_type
504 (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
507 else if (iter_type != long_long_unsigned_type_node)
509 if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
510 iter_type = long_long_unsigned_type_node;
511 else if (TYPE_UNSIGNED (TREE_TYPE (loop->v))
512 && TYPE_PRECISION (TREE_TYPE (loop->v))
513 >= TYPE_PRECISION (iter_type))
515 tree n;
517 if (loop->cond_code == LT_EXPR)
518 n = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v),
519 loop->n2, loop->step);
520 else
521 n = loop->n1;
522 if (loop->m1
523 || loop->m2
524 || TREE_CODE (n) != INTEGER_CST
525 || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n))
526 iter_type = long_long_unsigned_type_node;
528 else if (TYPE_PRECISION (TREE_TYPE (loop->v))
529 > TYPE_PRECISION (iter_type))
531 tree n1, n2;
533 if (loop->cond_code == LT_EXPR)
535 n1 = loop->n1;
536 n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v),
537 loop->n2, loop->step);
539 else
541 n1 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (loop->v),
542 loop->n2, loop->step);
543 n2 = loop->n1;
545 if (loop->m1
546 || loop->m2
547 || TREE_CODE (n1) != INTEGER_CST
548 || TREE_CODE (n2) != INTEGER_CST
549 || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1)
550 || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type)))
551 iter_type = long_long_unsigned_type_node;
555 if (i >= fd->collapse)
556 continue;
558 if (collapse_count && *collapse_count == NULL)
560 if (count && integer_zerop (count))
561 continue;
562 tree n1first = NULL_TREE, n2first = NULL_TREE;
563 tree n1last = NULL_TREE, n2last = NULL_TREE;
564 tree ostep = NULL_TREE;
565 if (loop->m1 || loop->m2)
567 if (count == NULL_TREE)
568 continue;
569 if (single_nonrect == -1
570 || (loop->m1 && TREE_CODE (loop->m1) != INTEGER_CST)
571 || (loop->m2 && TREE_CODE (loop->m2) != INTEGER_CST)
572 || TREE_CODE (loop->n1) != INTEGER_CST
573 || TREE_CODE (loop->n2) != INTEGER_CST
574 || TREE_CODE (loop->step) != INTEGER_CST)
576 count = NULL_TREE;
577 continue;
579 tree var = gimple_omp_for_initial (for_stmt, single_nonrect);
580 tree itype = TREE_TYPE (var);
581 tree first = gimple_omp_for_initial (for_stmt, single_nonrect);
582 t = gimple_omp_for_incr (for_stmt, single_nonrect);
583 ostep = omp_get_for_step_from_incr (loc, t);
584 t = fold_binary (MINUS_EXPR, long_long_unsigned_type_node,
585 single_nonrect_count,
586 build_one_cst (long_long_unsigned_type_node));
587 t = fold_convert (itype, t);
588 first = fold_convert (itype, first);
589 ostep = fold_convert (itype, ostep);
590 tree last = fold_binary (PLUS_EXPR, itype, first,
591 fold_binary (MULT_EXPR, itype, t,
592 ostep));
593 if (TREE_CODE (first) != INTEGER_CST
594 || TREE_CODE (last) != INTEGER_CST)
596 count = NULL_TREE;
597 continue;
599 if (loop->m1)
601 tree m1 = fold_convert (itype, loop->m1);
602 tree n1 = fold_convert (itype, loop->n1);
603 n1first = fold_binary (PLUS_EXPR, itype,
604 fold_binary (MULT_EXPR, itype,
605 first, m1), n1);
606 n1last = fold_binary (PLUS_EXPR, itype,
607 fold_binary (MULT_EXPR, itype,
608 last, m1), n1);
610 else
611 n1first = n1last = loop->n1;
612 if (loop->m2)
614 tree n2 = fold_convert (itype, loop->n2);
615 tree m2 = fold_convert (itype, loop->m2);
616 n2first = fold_binary (PLUS_EXPR, itype,
617 fold_binary (MULT_EXPR, itype,
618 first, m2), n2);
619 n2last = fold_binary (PLUS_EXPR, itype,
620 fold_binary (MULT_EXPR, itype,
621 last, m2), n2);
623 else
624 n2first = n2last = loop->n2;
625 n1first = fold_convert (TREE_TYPE (loop->v), n1first);
626 n2first = fold_convert (TREE_TYPE (loop->v), n2first);
627 n1last = fold_convert (TREE_TYPE (loop->v), n1last);
628 n2last = fold_convert (TREE_TYPE (loop->v), n2last);
629 t = fold_binary (loop->cond_code, boolean_type_node,
630 n1first, n2first);
631 tree t2 = fold_binary (loop->cond_code, boolean_type_node,
632 n1last, n2last);
633 if (t && t2 && integer_nonzerop (t) && integer_nonzerop (t2))
634 /* All outer loop iterators have at least one inner loop
635 iteration. Try to compute the count at compile time. */
636 t = NULL_TREE;
637 else if (t && t2 && integer_zerop (t) && integer_zerop (t2))
638 /* No iterations of the inner loop. count will be set to
639 zero cst below. */;
640 else if (TYPE_UNSIGNED (itype)
641 || t == NULL_TREE
642 || t2 == NULL_TREE
643 || TREE_CODE (t) != INTEGER_CST
644 || TREE_CODE (t2) != INTEGER_CST)
646 /* Punt (for now). */
647 count = NULL_TREE;
648 continue;
650 else
652 /* Some iterations of the outer loop have zero iterations
653 of the inner loop, while others have at least one.
654 In this case, we need to adjust one of those outer
655 loop bounds. If ADJ_FIRST, we need to adjust outer n1
656 (first), otherwise outer n2 (last). */
657 bool adj_first = integer_zerop (t);
658 tree n1 = fold_convert (itype, loop->n1);
659 tree n2 = fold_convert (itype, loop->n2);
660 tree m1 = loop->m1 ? fold_convert (itype, loop->m1)
661 : build_zero_cst (itype);
662 tree m2 = loop->m2 ? fold_convert (itype, loop->m2)
663 : build_zero_cst (itype);
664 t = fold_binary (MINUS_EXPR, itype, n1, n2);
665 t2 = fold_binary (MINUS_EXPR, itype, m2, m1);
666 t = fold_binary (TRUNC_DIV_EXPR, itype, t, t2);
667 t2 = fold_binary (MINUS_EXPR, itype, t, first);
668 t2 = fold_binary (TRUNC_MOD_EXPR, itype, t2, ostep);
669 t = fold_binary (MINUS_EXPR, itype, t, t2);
670 tree n1cur
671 = fold_binary (PLUS_EXPR, itype, n1,
672 fold_binary (MULT_EXPR, itype, m1, t));
673 tree n2cur
674 = fold_binary (PLUS_EXPR, itype, n2,
675 fold_binary (MULT_EXPR, itype, m2, t));
676 t2 = fold_binary (loop->cond_code, boolean_type_node,
677 n1cur, n2cur);
678 tree t3 = fold_binary (MULT_EXPR, itype, m1, ostep);
679 tree t4 = fold_binary (MULT_EXPR, itype, m2, ostep);
680 tree diff;
681 if (adj_first)
683 tree new_first;
684 if (integer_nonzerop (t2))
686 new_first = t;
687 n1first = n1cur;
688 n2first = n2cur;
689 if (flag_checking)
691 t3 = fold_binary (MINUS_EXPR, itype, n1cur, t3);
692 t4 = fold_binary (MINUS_EXPR, itype, n2cur, t4);
693 t3 = fold_binary (loop->cond_code,
694 boolean_type_node, t3, t4);
695 gcc_assert (integer_zerop (t3));
698 else
700 t3 = fold_binary (PLUS_EXPR, itype, n1cur, t3);
701 t4 = fold_binary (PLUS_EXPR, itype, n2cur, t4);
702 new_first = fold_binary (PLUS_EXPR, itype, t, ostep);
703 n1first = t3;
704 n2first = 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 diff = fold_binary (MINUS_EXPR, itype, new_first, first);
713 first = new_first;
714 fd->adjn1 = first;
716 else
718 tree new_last;
719 if (integer_zerop (t2))
721 t3 = fold_binary (MINUS_EXPR, itype, n1cur, t3);
722 t4 = fold_binary (MINUS_EXPR, itype, n2cur, t4);
723 new_last = fold_binary (MINUS_EXPR, itype, t, ostep);
724 n1last = t3;
725 n2last = t4;
726 if (flag_checking)
728 t3 = fold_binary (loop->cond_code,
729 boolean_type_node, t3, t4);
730 gcc_assert (integer_nonzerop (t3));
733 else
735 new_last = t;
736 n1last = n1cur;
737 n2last = n2cur;
738 if (flag_checking)
740 t3 = fold_binary (PLUS_EXPR, itype, n1cur, t3);
741 t4 = fold_binary (PLUS_EXPR, itype, n2cur, t4);
742 t3 = fold_binary (loop->cond_code,
743 boolean_type_node, t3, t4);
744 gcc_assert (integer_zerop (t3));
747 diff = fold_binary (MINUS_EXPR, itype, last, new_last);
749 if (TYPE_UNSIGNED (itype)
750 && single_nonrect_cond_code == GT_EXPR)
751 diff = fold_binary (TRUNC_DIV_EXPR, itype,
752 fold_unary (NEGATE_EXPR, itype, diff),
753 fold_unary (NEGATE_EXPR, itype,
754 ostep));
755 else
756 diff = fold_binary (TRUNC_DIV_EXPR, itype, diff, ostep);
757 diff = fold_convert (long_long_unsigned_type_node, diff);
758 single_nonrect_count
759 = fold_binary (MINUS_EXPR, long_long_unsigned_type_node,
760 single_nonrect_count, diff);
761 t = NULL_TREE;
764 else
765 t = fold_binary (loop->cond_code, boolean_type_node,
766 fold_convert (TREE_TYPE (loop->v), loop->n1),
767 fold_convert (TREE_TYPE (loop->v), loop->n2));
768 if (t && integer_zerop (t))
769 count = build_zero_cst (long_long_unsigned_type_node);
770 else if ((i == 0 || count != NULL_TREE)
771 && (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
772 || TREE_CODE (TREE_TYPE (loop->v)) == BITINT_TYPE)
773 && TREE_CONSTANT (loop->n1)
774 && TREE_CONSTANT (loop->n2)
775 && TREE_CODE (loop->step) == INTEGER_CST)
777 tree itype = TREE_TYPE (loop->v);
779 if (POINTER_TYPE_P (itype))
780 itype = signed_type_for (itype);
781 t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1));
782 t = fold_build2 (PLUS_EXPR, itype,
783 fold_convert (itype, loop->step), t);
784 tree n1 = loop->n1;
785 tree n2 = loop->n2;
786 if (loop->m1 || loop->m2)
788 gcc_assert (single_nonrect != -1);
789 n1 = n1first;
790 n2 = n2first;
792 t = fold_build2 (PLUS_EXPR, itype, t, fold_convert (itype, n2));
793 t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1));
794 tree step = fold_convert_loc (loc, itype, loop->step);
795 if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
796 t = fold_build2 (TRUNC_DIV_EXPR, itype,
797 fold_build1 (NEGATE_EXPR, itype, t),
798 fold_build1 (NEGATE_EXPR, itype, step));
799 else
800 t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step);
801 tree llutype = long_long_unsigned_type_node;
802 t = fold_convert (llutype, t);
803 if (loop->m1 || loop->m2)
805 /* t is number of iterations of inner loop at either first
806 or last value of the outer iterator (the one with fewer
807 iterations).
808 Compute t2 = ((m2 - m1) * ostep) / step
809 and niters = outer_count * t
810 + t2 * ((outer_count - 1) * outer_count / 2)
812 tree m1 = loop->m1 ? loop->m1 : integer_zero_node;
813 tree m2 = loop->m2 ? loop->m2 : integer_zero_node;
814 m1 = fold_convert (itype, m1);
815 m2 = fold_convert (itype, m2);
816 tree t2 = fold_build2 (MINUS_EXPR, itype, m2, m1);
817 t2 = fold_build2 (MULT_EXPR, itype, t2, ostep);
818 if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
819 t2 = fold_build2 (TRUNC_DIV_EXPR, itype,
820 fold_build1 (NEGATE_EXPR, itype, t2),
821 fold_build1 (NEGATE_EXPR, itype, step));
822 else
823 t2 = fold_build2 (TRUNC_DIV_EXPR, itype, t2, step);
824 t2 = fold_convert (llutype, t2);
825 fd->first_inner_iterations = t;
826 fd->factor = t2;
827 t = fold_build2 (MULT_EXPR, llutype, t,
828 single_nonrect_count);
829 tree t3 = fold_build2 (MINUS_EXPR, llutype,
830 single_nonrect_count,
831 build_one_cst (llutype));
832 t3 = fold_build2 (MULT_EXPR, llutype, t3,
833 single_nonrect_count);
834 t3 = fold_build2 (TRUNC_DIV_EXPR, llutype, t3,
835 build_int_cst (llutype, 2));
836 t2 = fold_build2 (MULT_EXPR, llutype, t2, t3);
837 t = fold_build2 (PLUS_EXPR, llutype, t, t2);
839 if (i == single_nonrect)
841 if (integer_zerop (t) || TREE_CODE (t) != INTEGER_CST)
842 count = t;
843 else
845 single_nonrect_count = t;
846 single_nonrect_cond_code = loop->cond_code;
847 if (count == NULL_TREE)
848 count = build_one_cst (llutype);
851 else if (count != NULL_TREE)
852 count = fold_build2 (MULT_EXPR, llutype, count, t);
853 else
854 count = t;
855 if (TREE_CODE (count) != INTEGER_CST)
856 count = NULL_TREE;
858 else if (count && !integer_zerop (count))
859 count = NULL_TREE;
863 if (count
864 && !simd
865 && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
866 || fd->have_ordered))
868 if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
869 iter_type = long_long_unsigned_type_node;
870 else
871 iter_type = long_integer_type_node;
873 else if (collapse_iter && *collapse_iter != NULL)
874 iter_type = TREE_TYPE (*collapse_iter);
875 fd->iter_type = iter_type;
876 if (collapse_iter && *collapse_iter == NULL)
877 *collapse_iter = create_tmp_var (iter_type, ".iter");
878 if (collapse_count && *collapse_count == NULL)
880 if (count)
882 *collapse_count = fold_convert_loc (loc, iter_type, count);
883 if (fd->first_inner_iterations && fd->factor)
885 t = make_tree_vec (4);
886 TREE_VEC_ELT (t, 0) = *collapse_count;
887 TREE_VEC_ELT (t, 1) = fd->first_inner_iterations;
888 TREE_VEC_ELT (t, 2) = fd->factor;
889 TREE_VEC_ELT (t, 3) = fd->adjn1;
890 *collapse_count = t;
893 else
894 *collapse_count = create_tmp_var (iter_type, ".count");
897 if (fd->collapse > 1 || fd->tiling || (fd->ordered && loops))
899 fd->loop.v = *collapse_iter;
900 fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
901 fd->loop.n2 = *collapse_count;
902 if (TREE_CODE (fd->loop.n2) == TREE_VEC)
904 gcc_assert (fd->non_rect);
905 fd->first_inner_iterations = TREE_VEC_ELT (fd->loop.n2, 1);
906 fd->factor = TREE_VEC_ELT (fd->loop.n2, 2);
907 fd->adjn1 = TREE_VEC_ELT (fd->loop.n2, 3);
908 fd->loop.n2 = TREE_VEC_ELT (fd->loop.n2, 0);
910 fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
911 fd->loop.m1 = NULL_TREE;
912 fd->loop.m2 = NULL_TREE;
913 fd->loop.outer = 0;
914 fd->loop.cond_code = LT_EXPR;
916 else if (loops)
917 loops[0] = fd->loop;
920 /* Build a call to GOMP_barrier. */
922 gimple *
923 omp_build_barrier (tree lhs)
925 tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL
926 : BUILT_IN_GOMP_BARRIER);
927 gcall *g = gimple_build_call (fndecl, 0);
928 if (lhs)
929 gimple_call_set_lhs (g, lhs);
930 return g;
933 /* Find OMP_FOR resp. OMP_SIMD with non-NULL OMP_FOR_INIT. Also, fill in pdata
934 array, pdata[0] non-NULL if there is anything non-trivial in between,
935 pdata[1] is address of OMP_PARALLEL in between if any, pdata[2] is address
936 of OMP_FOR in between if any and pdata[3] is address of the inner
937 OMP_FOR/OMP_SIMD. */
939 tree
940 find_combined_omp_for (tree *tp, int *walk_subtrees, void *data)
942 tree **pdata = (tree **) data;
943 *walk_subtrees = 0;
944 switch (TREE_CODE (*tp))
946 case OMP_FOR:
947 if (OMP_FOR_INIT (*tp) != NULL_TREE)
949 pdata[3] = tp;
950 return *tp;
952 pdata[2] = tp;
953 *walk_subtrees = 1;
954 break;
955 case OMP_SIMD:
956 if (OMP_FOR_INIT (*tp) != NULL_TREE)
958 pdata[3] = tp;
959 return *tp;
961 break;
962 case BIND_EXPR:
963 if (BIND_EXPR_VARS (*tp)
964 || (BIND_EXPR_BLOCK (*tp)
965 && BLOCK_VARS (BIND_EXPR_BLOCK (*tp))))
966 pdata[0] = tp;
967 *walk_subtrees = 1;
968 break;
969 case STATEMENT_LIST:
970 if (!tsi_one_before_end_p (tsi_start (*tp)))
971 pdata[0] = tp;
972 *walk_subtrees = 1;
973 break;
974 case TRY_FINALLY_EXPR:
975 case CLEANUP_POINT_EXPR:
976 pdata[0] = tp;
977 *walk_subtrees = 1;
978 break;
979 case OMP_PARALLEL:
980 pdata[1] = tp;
981 *walk_subtrees = 1;
982 break;
983 default:
984 break;
986 return NULL_TREE;
989 /* Return maximum possible vectorization factor for the target. */
991 poly_uint64
992 omp_max_vf (void)
994 if (!optimize
995 || optimize_debug
996 || !flag_tree_loop_optimize
997 || (!flag_tree_loop_vectorize
998 && OPTION_SET_P (flag_tree_loop_vectorize)))
999 return 1;
1001 auto_vector_modes modes;
1002 targetm.vectorize.autovectorize_vector_modes (&modes, true);
1003 if (!modes.is_empty ())
1005 poly_uint64 vf = 0;
1006 for (unsigned int i = 0; i < modes.length (); ++i)
1007 /* The returned modes use the smallest element size (and thus
1008 the largest nunits) for the vectorization approach that they
1009 represent. */
1010 vf = ordered_max (vf, GET_MODE_NUNITS (modes[i]));
1011 return vf;
1014 machine_mode vqimode = targetm.vectorize.preferred_simd_mode (QImode);
1015 if (GET_MODE_CLASS (vqimode) == MODE_VECTOR_INT)
1016 return GET_MODE_NUNITS (vqimode);
1018 return 1;
1021 /* Return maximum SIMT width if offloading may target SIMT hardware. */
1024 omp_max_simt_vf (void)
1026 if (!optimize)
1027 return 0;
1028 if (ENABLE_OFFLOADING)
1029 for (const char *c = getenv ("OFFLOAD_TARGET_NAMES"); c;)
1031 if (startswith (c, "nvptx"))
1032 return 32;
1033 else if ((c = strchr (c, ':')))
1034 c++;
1036 return 0;
1039 /* Store the construct selectors as tree codes from last to first.
1040 CTX is a list of trait selectors, nconstructs must be equal to its
1041 length, and the array CONSTRUCTS holds the output. */
1043 void
1044 omp_construct_traits_to_codes (tree ctx, int nconstructs,
1045 enum tree_code *constructs)
1047 int i = nconstructs - 1;
1049 /* Order must match the OMP_TRAIT_CONSTRUCT_* enumerators in
1050 enum omp_ts_code. */
1051 static enum tree_code code_map[]
1052 = { OMP_TARGET, OMP_TEAMS, OMP_PARALLEL, OMP_FOR, OMP_SIMD };
1054 for (tree ts = ctx; ts; ts = TREE_CHAIN (ts), i--)
1056 enum omp_ts_code sel = OMP_TS_CODE (ts);
1057 int j = (int)sel - (int)OMP_TRAIT_CONSTRUCT_TARGET;
1058 gcc_assert (j >= 0 && (unsigned int) j < ARRAY_SIZE (code_map));
1059 constructs[i] = code_map[j];
1061 gcc_assert (i == -1);
1064 /* Return true if PROP is possibly present in one of the offloading target's
1065 OpenMP contexts. The format of PROPS string is always offloading target's
1066 name terminated by '\0', followed by properties for that offloading
1067 target separated by '\0' and terminated by another '\0'. The strings
1068 are created from omp-device-properties installed files of all configured
1069 offloading targets. */
1071 static bool
1072 omp_offload_device_kind_arch_isa (const char *props, const char *prop)
1074 const char *names = getenv ("OFFLOAD_TARGET_NAMES");
1075 if (names == NULL || *names == '\0')
1076 return false;
1077 while (*props != '\0')
1079 size_t name_len = strlen (props);
1080 bool matches = false;
1081 for (const char *c = names; c; )
1083 if (strncmp (props, c, name_len) == 0
1084 && (c[name_len] == '\0'
1085 || c[name_len] == ':'
1086 || c[name_len] == '='))
1088 matches = true;
1089 break;
1091 else if ((c = strchr (c, ':')))
1092 c++;
1094 props = props + name_len + 1;
1095 while (*props != '\0')
1097 if (matches && strcmp (props, prop) == 0)
1098 return true;
1099 props = strchr (props, '\0') + 1;
1101 props++;
1103 return false;
1106 /* Return true if the current code location is or might be offloaded.
1107 Return true in declare target functions, or when nested in a target
1108 region or when unsure, return false otherwise. */
1110 static bool
1111 omp_maybe_offloaded (void)
1113 if (!ENABLE_OFFLOADING)
1114 return false;
1115 const char *names = getenv ("OFFLOAD_TARGET_NAMES");
1116 if (names == NULL || *names == '\0')
1117 return false;
1119 if (symtab->state == PARSING)
1120 /* Maybe. */
1121 return true;
1122 if (cfun && cfun->after_inlining)
1123 return false;
1124 if (current_function_decl
1125 && lookup_attribute ("omp declare target",
1126 DECL_ATTRIBUTES (current_function_decl)))
1127 return true;
1128 if (cfun && (cfun->curr_properties & PROP_gimple_any) == 0)
1130 enum tree_code construct = OMP_TARGET;
1131 if (omp_construct_selector_matches (&construct, 1, NULL))
1132 return true;
1134 return false;
1137 /* Lookup tables for context selectors. */
1138 const char *omp_tss_map[] =
1140 "construct",
1141 "device",
1142 "target_device",
1143 "implementation",
1144 "user",
1145 NULL
1148 /* Arrays of property candidates must be null-terminated. */
1149 static const char *const kind_properties[] =
1150 { "host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
1151 static const char *const vendor_properties[] =
1152 { "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "hpe", "ibm", "intel",
1153 "llvm", "nvidia", "pgi", "ti", "unknown", NULL };
1154 static const char *const extension_properties[] =
1155 { NULL };
1156 static const char *const atomic_default_mem_order_properties[] =
1157 { "seq_cst", "relaxed", "acq_rel", "acquire", "release", NULL };
1159 struct omp_ts_info omp_ts_map[] =
1161 { "kind",
1162 (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1163 OMP_TRAIT_PROPERTY_NAME_LIST, false,
1164 kind_properties
1166 { "isa",
1167 (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1168 OMP_TRAIT_PROPERTY_NAME_LIST, false,
1169 NULL
1171 { "arch",
1172 (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1173 OMP_TRAIT_PROPERTY_NAME_LIST, false,
1174 NULL
1176 { "device_num",
1177 (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1178 OMP_TRAIT_PROPERTY_DEV_NUM_EXPR, false,
1179 NULL
1181 { "vendor",
1182 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1183 OMP_TRAIT_PROPERTY_NAME_LIST, true,
1184 vendor_properties,
1186 { "extension",
1187 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1188 OMP_TRAIT_PROPERTY_NAME_LIST, true,
1189 extension_properties,
1191 { "atomic_default_mem_order",
1192 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1193 OMP_TRAIT_PROPERTY_ID, true,
1194 atomic_default_mem_order_properties,
1196 { "requires",
1197 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1198 OMP_TRAIT_PROPERTY_CLAUSE_LIST, true,
1199 NULL
1201 { "unified_address",
1202 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1203 OMP_TRAIT_PROPERTY_NONE, true,
1204 NULL
1206 { "unified_shared_memory",
1207 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1208 OMP_TRAIT_PROPERTY_NONE, true,
1209 NULL
1211 { "self_maps",
1212 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1213 OMP_TRAIT_PROPERTY_NONE, true,
1214 NULL
1216 { "dynamic_allocators",
1217 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1218 OMP_TRAIT_PROPERTY_NONE, true,
1219 NULL
1221 { "reverse_offload",
1222 (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1223 OMP_TRAIT_PROPERTY_NONE, true,
1224 NULL
1226 { "condition",
1227 (1 << OMP_TRAIT_SET_USER),
1228 OMP_TRAIT_PROPERTY_BOOL_EXPR, true,
1229 NULL
1231 { "target",
1232 (1 << OMP_TRAIT_SET_CONSTRUCT),
1233 OMP_TRAIT_PROPERTY_NONE, false,
1234 NULL
1236 { "teams",
1237 (1 << OMP_TRAIT_SET_CONSTRUCT),
1238 OMP_TRAIT_PROPERTY_NONE, false,
1239 NULL
1241 { "parallel",
1242 (1 << OMP_TRAIT_SET_CONSTRUCT),
1243 OMP_TRAIT_PROPERTY_NONE, false,
1244 NULL
1246 { "for",
1247 (1 << OMP_TRAIT_SET_CONSTRUCT),
1248 OMP_TRAIT_PROPERTY_NONE, false,
1249 NULL
1251 { "simd",
1252 (1 << OMP_TRAIT_SET_CONSTRUCT),
1253 OMP_TRAIT_PROPERTY_CLAUSE_LIST, false,
1254 NULL
1256 { NULL, 0, OMP_TRAIT_PROPERTY_NONE, false, NULL } /* OMP_TRAIT_LAST */
1260 /* Return a name from PROP, a property in selectors accepting
1261 name lists. */
1263 const char *
1264 omp_context_name_list_prop (tree prop)
1266 gcc_assert (OMP_TP_NAME (prop) == OMP_TP_NAMELIST_NODE);
1267 tree val = OMP_TP_VALUE (prop);
1268 switch (TREE_CODE (val))
1270 case IDENTIFIER_NODE:
1271 return IDENTIFIER_POINTER (val);
1272 case STRING_CST:
1274 const char *ret = TREE_STRING_POINTER (val);
1275 if ((size_t) TREE_STRING_LENGTH (val)
1276 == strlen (ret) + (lang_GNU_Fortran () ? 0 : 1))
1277 return ret;
1278 return NULL;
1280 default:
1281 return NULL;
1285 /* Diagnose errors in an OpenMP context selector, return CTX if
1286 it is correct or error_mark_node otherwise. */
1288 tree
1289 omp_check_context_selector (location_t loc, tree ctx)
1291 bool tss_seen[OMP_TRAIT_SET_LAST], ts_seen[OMP_TRAIT_LAST];
1293 memset (tss_seen, 0, sizeof (tss_seen));
1294 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
1296 enum omp_tss_code tss_code = OMP_TSS_CODE (tss);
1297 bool saw_any_prop = false;
1298 bool saw_other_prop = false;
1300 /* We can parse this, but not handle it yet. */
1301 if (tss_code == OMP_TRAIT_SET_TARGET_DEVICE)
1302 sorry_at (loc, "%<target_device%> selector set is not supported yet");
1304 /* Each trait-set-selector-name can only be specified once. */
1305 if (tss_seen[tss_code])
1307 error_at (loc, "selector set %qs specified more than once",
1308 OMP_TSS_NAME (tss));
1309 return error_mark_node;
1311 else
1312 tss_seen[tss_code] = true;
1314 memset (ts_seen, 0, sizeof (ts_seen));
1315 for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
1317 enum omp_ts_code ts_code = OMP_TS_CODE (ts);
1319 /* Ignore unknown traits. */
1320 if (ts_code == OMP_TRAIT_INVALID)
1321 continue;
1323 /* Each trait-selector-name can only be specified once. */
1324 if (ts_seen[ts_code])
1326 error_at (loc,
1327 "selector %qs specified more than once in set %qs",
1328 OMP_TS_NAME (ts),
1329 OMP_TSS_NAME (tss));
1330 return error_mark_node;
1332 else
1333 ts_seen[ts_code] = true;
1335 /* If trait-property "any" is specified in the "kind"
1336 trait-selector of the "device" selector set or the
1337 "target_device" selector sets, no other trait-property
1338 may be specified in the same selector set. */
1339 if (ts_code == OMP_TRAIT_DEVICE_KIND)
1340 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1342 const char *prop = omp_context_name_list_prop (p);
1343 if (!prop)
1344 continue;
1345 else if (strcmp (prop, "any") == 0)
1346 saw_any_prop = true;
1347 else
1348 saw_other_prop = true;
1350 /* It seems slightly suspicious that the spec's language covers
1351 the device_num selector too, but
1352 target_device={device_num(whatever),kind(any)}
1353 is probably not terribly useful anyway. */
1354 else if (ts_code == OMP_TRAIT_DEVICE_ARCH
1355 || ts_code == OMP_TRAIT_DEVICE_ISA
1356 || ts_code == OMP_TRAIT_DEVICE_NUM)
1357 saw_other_prop = true;
1359 /* Each trait-property can only be specified once in a trait-selector
1360 other than the construct selector set. FIXME: only handles
1361 name-list properties, not clause-list properties, since the
1362 "requires" selector is not implemented yet (PR 113067). */
1363 if (tss_code != OMP_TRAIT_SET_CONSTRUCT)
1364 for (tree p1 = OMP_TS_PROPERTIES (ts); p1; p1 = TREE_CHAIN (p1))
1366 if (OMP_TP_NAME (p1) != OMP_TP_NAMELIST_NODE)
1367 break;
1368 const char *n1 = omp_context_name_list_prop (p1);
1369 if (!n1)
1370 continue;
1371 for (tree p2 = TREE_CHAIN (p1); p2; p2 = TREE_CHAIN (p2))
1373 const char *n2 = omp_context_name_list_prop (p2);
1374 if (!n2)
1375 continue;
1376 if (!strcmp (n1, n2))
1378 error_at (loc,
1379 "trait-property %qs specified more "
1380 "than once in %qs selector",
1381 n1, OMP_TS_NAME (ts));
1382 return error_mark_node;
1387 /* Check for unknown properties. */
1388 if (omp_ts_map[ts_code].valid_properties == NULL)
1389 continue;
1390 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1391 for (unsigned j = 0; ; j++)
1393 const char *candidate
1394 = omp_ts_map[ts_code].valid_properties[j];
1395 if (candidate == NULL)
1397 /* We've reached the end of the candidate array. */
1398 if (ts_code == OMP_TRAIT_IMPLEMENTATION_ADMO)
1399 /* FIXME: not sure why this is an error vs warnings
1400 for the others, + incorrect/unknown wording? */
1402 error_at (loc,
1403 "incorrect property %qs of %qs selector",
1404 IDENTIFIER_POINTER (OMP_TP_NAME (p)),
1405 "atomic_default_mem_order");
1406 return error_mark_node;
1408 if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
1409 && (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
1410 warning_at (loc, OPT_Wopenmp,
1411 "unknown property %qE of %qs selector",
1412 OMP_TP_VALUE (p),
1413 OMP_TS_NAME (ts));
1414 else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
1415 warning_at (loc, OPT_Wopenmp,
1416 "unknown property %qs of %qs selector",
1417 omp_context_name_list_prop (p),
1418 OMP_TS_NAME (ts));
1419 else if (OMP_TP_NAME (p))
1420 warning_at (loc, OPT_Wopenmp,
1421 "unknown property %qs of %qs selector",
1422 IDENTIFIER_POINTER (OMP_TP_NAME (p)),
1423 OMP_TS_NAME (ts));
1424 break;
1426 else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
1427 /* Property-list traits. */
1429 const char *str = omp_context_name_list_prop (p);
1430 if (str && !strcmp (str, candidate))
1431 break;
1433 else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
1434 candidate))
1435 /* Identifier traits. */
1436 break;
1440 if (saw_any_prop && saw_other_prop)
1442 error_at (loc,
1443 "no other trait-property may be specified "
1444 "in the same selector set with %<kind(\"any\")%>");
1445 return error_mark_node;
1448 return ctx;
1452 /* Register VARIANT as variant of some base function marked with
1453 #pragma omp declare variant. CONSTRUCT is corresponding list of
1454 trait-selectors for the construct selector set. This is stashed as the
1455 value of the "omp declare variant variant" attribute on VARIANT. */
1456 void
1457 omp_mark_declare_variant (location_t loc, tree variant, tree construct)
1459 /* Ignore this variant if it contains unknown construct selectors.
1460 It will never match, and the front ends have already issued a warning
1461 about it. */
1462 for (tree c = construct; c; c = TREE_CHAIN (c))
1463 if (OMP_TS_CODE (c) == OMP_TRAIT_INVALID)
1464 return;
1466 tree attr = lookup_attribute ("omp declare variant variant",
1467 DECL_ATTRIBUTES (variant));
1468 if (attr == NULL_TREE)
1470 attr = tree_cons (get_identifier ("omp declare variant variant"),
1471 unshare_expr (construct),
1472 DECL_ATTRIBUTES (variant));
1473 DECL_ATTRIBUTES (variant) = attr;
1474 return;
1476 if ((TREE_VALUE (attr) != NULL_TREE) != (construct != NULL_TREE)
1477 || (construct != NULL_TREE
1478 && omp_context_selector_set_compare (OMP_TRAIT_SET_CONSTRUCT,
1479 TREE_VALUE (attr),
1480 construct)))
1481 error_at (loc, "%qD used as a variant with incompatible %<construct%> "
1482 "selector sets", variant);
1486 /* Constructors for context selectors. */
1488 tree
1489 make_trait_set_selector (enum omp_tss_code code, tree selectors, tree chain)
1491 return tree_cons (build_int_cst (integer_type_node, code),
1492 selectors, chain);
1495 tree
1496 make_trait_selector (enum omp_ts_code code, tree score, tree properties,
1497 tree chain)
1499 if (score == NULL_TREE)
1500 return tree_cons (build_int_cst (integer_type_node, code),
1501 properties, chain);
1502 else
1503 return tree_cons (build_int_cst (integer_type_node, code),
1504 tree_cons (OMP_TS_SCORE_NODE, score, properties),
1505 chain);
1508 tree
1509 make_trait_property (tree name, tree value, tree chain)
1511 return tree_cons (name, value, chain);
1514 /* Return 1 if context selector matches the current OpenMP context, 0
1515 if it does not and -1 if it is unknown and need to be determined later.
1516 Some properties can be checked right away during parsing (this routine),
1517 others need to wait until the whole TU is parsed, others need to wait until
1518 IPA, others until vectorization. */
1521 omp_context_selector_matches (tree ctx)
1523 int ret = 1;
1524 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
1526 enum omp_tss_code set = OMP_TSS_CODE (tss);
1527 tree selectors = OMP_TSS_TRAIT_SELECTORS (tss);
1529 /* Immediately reject the match if there are any ignored
1530 selectors present. */
1531 for (tree ts = selectors; ts; ts = TREE_CHAIN (ts))
1532 if (OMP_TS_CODE (ts) == OMP_TRAIT_INVALID)
1533 return 0;
1535 if (set == OMP_TRAIT_SET_CONSTRUCT)
1537 /* For now, ignore the construct set. While something can be
1538 determined already during parsing, we don't know until end of TU
1539 whether additional constructs aren't added through declare variant
1540 unless "omp declare variant variant" attribute exists already
1541 (so in most of the cases), and we'd need to maintain set of
1542 surrounding OpenMP constructs, which is better handled during
1543 gimplification. */
1544 if (symtab->state == PARSING)
1546 ret = -1;
1547 continue;
1550 int nconstructs = list_length (selectors);
1551 enum tree_code *constructs = NULL;
1552 if (nconstructs)
1554 /* Even though this alloca appears in a loop over selector
1555 sets, it does not repeatedly grow the stack, because
1556 there can be only one construct selector set specified.
1557 This is enforced by omp_check_context_selector. */
1558 constructs
1559 = (enum tree_code *) alloca (nconstructs
1560 * sizeof (enum tree_code));
1561 omp_construct_traits_to_codes (selectors, nconstructs,
1562 constructs);
1565 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1567 if (!cfun->after_inlining)
1569 ret = -1;
1570 continue;
1572 int i;
1573 for (i = 0; i < nconstructs; ++i)
1574 if (constructs[i] == OMP_SIMD)
1575 break;
1576 if (i < nconstructs)
1578 ret = -1;
1579 continue;
1581 /* If there is no simd, assume it is ok after IPA,
1582 constructs should have been checked before. */
1583 continue;
1586 int r = omp_construct_selector_matches (constructs, nconstructs,
1587 NULL);
1588 if (r == 0)
1589 return 0;
1590 if (r == -1)
1591 ret = -1;
1592 continue;
1594 for (tree ts = selectors; ts; ts = TREE_CHAIN (ts))
1596 enum omp_ts_code sel = OMP_TS_CODE (ts);
1597 switch (sel)
1599 case OMP_TRAIT_IMPLEMENTATION_VENDOR:
1600 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1601 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1603 const char *prop = omp_context_name_list_prop (p);
1604 if (prop == NULL)
1605 return 0;
1606 if (!strcmp (prop, "gnu"))
1607 continue;
1608 return 0;
1610 break;
1611 case OMP_TRAIT_IMPLEMENTATION_EXTENSION:
1612 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1613 /* We don't support any extensions right now. */
1614 return 0;
1615 break;
1616 case OMP_TRAIT_IMPLEMENTATION_ADMO:
1617 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1619 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1620 break;
1622 enum omp_memory_order omo
1623 = ((enum omp_memory_order)
1624 (omp_requires_mask
1625 & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER));
1626 if (omo == OMP_MEMORY_ORDER_UNSPECIFIED)
1628 /* We don't know yet, until end of TU. */
1629 if (symtab->state == PARSING)
1631 ret = -1;
1632 break;
1634 else
1635 omo = OMP_MEMORY_ORDER_RELAXED;
1637 tree p = OMP_TS_PROPERTIES (ts);
1638 const char *prop = IDENTIFIER_POINTER (OMP_TP_NAME (p));
1639 if (!strcmp (prop, "relaxed")
1640 && omo != OMP_MEMORY_ORDER_RELAXED)
1641 return 0;
1642 else if (!strcmp (prop, "seq_cst")
1643 && omo != OMP_MEMORY_ORDER_SEQ_CST)
1644 return 0;
1645 else if (!strcmp (prop, "acq_rel")
1646 && omo != OMP_MEMORY_ORDER_ACQ_REL)
1647 return 0;
1648 else if (!strcmp (prop, "acquire")
1649 && omo != OMP_MEMORY_ORDER_ACQUIRE)
1650 return 0;
1651 else if (!strcmp (prop, "release")
1652 && omo != OMP_MEMORY_ORDER_RELEASE)
1653 return 0;
1655 break;
1656 case OMP_TRAIT_DEVICE_ARCH:
1657 if (set == OMP_TRAIT_SET_DEVICE)
1658 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1660 const char *arch = omp_context_name_list_prop (p);
1661 if (arch == NULL)
1662 return 0;
1663 int r = 0;
1664 if (targetm.omp.device_kind_arch_isa != NULL)
1665 r = targetm.omp.device_kind_arch_isa (omp_device_arch,
1666 arch);
1667 if (r == 0 || (r == -1 && symtab->state != PARSING))
1669 /* If we are or might be in a target region or
1670 declare target function, need to take into account
1671 also offloading values. */
1672 if (!omp_maybe_offloaded ())
1673 return 0;
1674 if (ENABLE_OFFLOADING)
1676 const char *arches = omp_offload_device_arch;
1677 if (omp_offload_device_kind_arch_isa (arches,
1678 arch))
1680 ret = -1;
1681 continue;
1684 return 0;
1686 else if (r == -1)
1687 ret = -1;
1688 /* If arch matches on the host, it still might not match
1689 in the offloading region. */
1690 else if (omp_maybe_offloaded ())
1691 ret = -1;
1693 break;
1694 case OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS:
1695 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1697 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1698 break;
1700 if ((omp_requires_mask & OMP_REQUIRES_UNIFIED_ADDRESS) == 0)
1702 if (symtab->state == PARSING)
1703 ret = -1;
1704 else
1705 return 0;
1708 break;
1709 case OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY:
1710 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1712 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1713 break;
1715 if ((omp_requires_mask
1716 & OMP_REQUIRES_UNIFIED_SHARED_MEMORY) == 0)
1718 if (symtab->state == PARSING)
1719 ret = -1;
1720 else
1721 return 0;
1724 break;
1725 case OMP_TRAIT_IMPLEMENTATION_SELF_MAPS:
1726 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1728 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1729 break;
1731 if ((omp_requires_mask
1732 & OMP_REQUIRES_SELF_MAPS) == 0)
1734 if (symtab->state == PARSING)
1735 ret = -1;
1736 else
1737 return 0;
1740 break;
1741 case OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS:
1742 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1744 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1745 break;
1747 if ((omp_requires_mask
1748 & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0)
1750 if (symtab->state == PARSING)
1751 ret = -1;
1752 else
1753 return 0;
1756 break;
1757 case OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD:
1758 if (set == OMP_TRAIT_SET_IMPLEMENTATION)
1760 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1761 break;
1763 if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0)
1765 if (symtab->state == PARSING)
1766 ret = -1;
1767 else
1768 return 0;
1771 break;
1772 case OMP_TRAIT_DEVICE_KIND:
1773 if (set == OMP_TRAIT_SET_DEVICE)
1774 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1776 const char *prop = omp_context_name_list_prop (p);
1777 if (prop == NULL)
1778 return 0;
1779 if (!strcmp (prop, "any"))
1780 continue;
1781 if (!strcmp (prop, "host"))
1783 #ifdef ACCEL_COMPILER
1784 return 0;
1785 #else
1786 if (omp_maybe_offloaded ())
1787 ret = -1;
1788 continue;
1789 #endif
1791 if (!strcmp (prop, "nohost"))
1793 #ifndef ACCEL_COMPILER
1794 if (omp_maybe_offloaded ())
1795 ret = -1;
1796 else
1797 return 0;
1798 #endif
1799 continue;
1801 int r = 0;
1802 if (targetm.omp.device_kind_arch_isa != NULL)
1803 r = targetm.omp.device_kind_arch_isa (omp_device_kind,
1804 prop);
1805 else
1806 r = strcmp (prop, "cpu") == 0;
1807 if (r == 0 || (r == -1 && symtab->state != PARSING))
1809 /* If we are or might be in a target region or
1810 declare target function, need to take into account
1811 also offloading values. */
1812 if (!omp_maybe_offloaded ())
1813 return 0;
1814 if (ENABLE_OFFLOADING)
1816 const char *kinds = omp_offload_device_kind;
1817 if (omp_offload_device_kind_arch_isa (kinds, prop))
1819 ret = -1;
1820 continue;
1823 return 0;
1825 else if (r == -1)
1826 ret = -1;
1827 /* If kind matches on the host, it still might not match
1828 in the offloading region. */
1829 else if (omp_maybe_offloaded ())
1830 ret = -1;
1832 break;
1833 case OMP_TRAIT_DEVICE_ISA:
1834 if (set == OMP_TRAIT_SET_DEVICE)
1835 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1837 const char *isa = omp_context_name_list_prop (p);
1838 if (isa == NULL)
1839 return 0;
1840 int r = 0;
1841 if (targetm.omp.device_kind_arch_isa != NULL)
1842 r = targetm.omp.device_kind_arch_isa (omp_device_isa,
1843 isa);
1844 if (r == 0 || (r == -1 && symtab->state != PARSING))
1846 /* If isa is valid on the target, but not in the
1847 current function and current function has
1848 #pragma omp declare simd on it, some simd clones
1849 might have the isa added later on. */
1850 if (r == -1
1851 && targetm.simd_clone.compute_vecsize_and_simdlen
1852 && (cfun == NULL || !cfun->after_inlining))
1854 tree attrs
1855 = DECL_ATTRIBUTES (current_function_decl);
1856 if (lookup_attribute ("omp declare simd", attrs))
1858 ret = -1;
1859 continue;
1862 /* If we are or might be in a target region or
1863 declare target function, need to take into account
1864 also offloading values. */
1865 if (!omp_maybe_offloaded ())
1866 return 0;
1867 if (ENABLE_OFFLOADING)
1869 const char *isas = omp_offload_device_isa;
1870 if (omp_offload_device_kind_arch_isa (isas, isa))
1872 ret = -1;
1873 continue;
1876 return 0;
1878 else if (r == -1)
1879 ret = -1;
1880 /* If isa matches on the host, it still might not match
1881 in the offloading region. */
1882 else if (omp_maybe_offloaded ())
1883 ret = -1;
1885 break;
1886 case OMP_TRAIT_USER_CONDITION:
1887 if (set == OMP_TRAIT_SET_USER)
1888 for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1889 if (OMP_TP_NAME (p) == NULL_TREE)
1891 if (integer_zerop (OMP_TP_VALUE (p)))
1892 return 0;
1893 if (integer_nonzerop (OMP_TP_VALUE (p)))
1894 break;
1895 ret = -1;
1897 break;
1898 default:
1899 break;
1903 return ret;
1906 /* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as
1907 in omp_context_selector_set_compare. */
1909 static int
1910 omp_construct_simd_compare (tree clauses1, tree clauses2)
1912 if (clauses1 == NULL_TREE)
1913 return clauses2 == NULL_TREE ? 0 : -1;
1914 if (clauses2 == NULL_TREE)
1915 return 1;
1917 int r = 0;
1918 struct declare_variant_simd_data {
1919 bool inbranch, notinbranch;
1920 tree simdlen;
1921 auto_vec<tree,16> data_sharing;
1922 auto_vec<tree,16> aligned;
1923 declare_variant_simd_data ()
1924 : inbranch(false), notinbranch(false), simdlen(NULL_TREE) {}
1925 } data[2];
1926 unsigned int i;
1927 for (i = 0; i < 2; i++)
1928 for (tree c = i ? clauses2 : clauses1; c; c = OMP_CLAUSE_CHAIN (c))
1930 vec<tree> *v;
1931 switch (OMP_CLAUSE_CODE (c))
1933 case OMP_CLAUSE_INBRANCH:
1934 data[i].inbranch = true;
1935 continue;
1936 case OMP_CLAUSE_NOTINBRANCH:
1937 data[i].notinbranch = true;
1938 continue;
1939 case OMP_CLAUSE_SIMDLEN:
1940 data[i].simdlen = OMP_CLAUSE_SIMDLEN_EXPR (c);
1941 continue;
1942 case OMP_CLAUSE_UNIFORM:
1943 case OMP_CLAUSE_LINEAR:
1944 v = &data[i].data_sharing;
1945 break;
1946 case OMP_CLAUSE_ALIGNED:
1947 v = &data[i].aligned;
1948 break;
1949 default:
1950 gcc_unreachable ();
1952 unsigned HOST_WIDE_INT argno = tree_to_uhwi (OMP_CLAUSE_DECL (c));
1953 if (argno >= v->length ())
1954 v->safe_grow_cleared (argno + 1, true);
1955 (*v)[argno] = c;
1957 /* Here, r is used as a bitmask, 2 is set if CLAUSES1 has something
1958 CLAUSES2 doesn't, 1 is set if CLAUSES2 has something CLAUSES1
1959 doesn't. Thus, r == 3 implies return value 2, r == 1 implies
1960 -1, r == 2 implies 1 and r == 0 implies 0. */
1961 if (data[0].inbranch != data[1].inbranch)
1962 r |= data[0].inbranch ? 2 : 1;
1963 if (data[0].notinbranch != data[1].notinbranch)
1964 r |= data[0].notinbranch ? 2 : 1;
1965 if (!simple_cst_equal (data[0].simdlen, data[1].simdlen))
1967 if (data[0].simdlen && data[1].simdlen)
1968 return 2;
1969 r |= data[0].simdlen ? 2 : 1;
1971 if (data[0].data_sharing.length () < data[1].data_sharing.length ()
1972 || data[0].aligned.length () < data[1].aligned.length ())
1973 r |= 1;
1974 tree c1, c2;
1975 FOR_EACH_VEC_ELT (data[0].data_sharing, i, c1)
1977 c2 = (i < data[1].data_sharing.length ()
1978 ? data[1].data_sharing[i] : NULL_TREE);
1979 if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
1981 r |= c1 != NULL_TREE ? 2 : 1;
1982 continue;
1984 if (c1 == NULL_TREE)
1985 continue;
1986 if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_CODE (c2))
1987 return 2;
1988 if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_LINEAR)
1989 continue;
1990 if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1)
1991 != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2))
1992 return 2;
1993 if (OMP_CLAUSE_LINEAR_KIND (c1) != OMP_CLAUSE_LINEAR_KIND (c2))
1994 return 2;
1995 if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1),
1996 OMP_CLAUSE_LINEAR_STEP (c2)))
1997 return 2;
1999 FOR_EACH_VEC_ELT (data[0].aligned, i, c1)
2001 c2 = i < data[1].aligned.length () ? data[1].aligned[i] : NULL_TREE;
2002 if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
2004 r |= c1 != NULL_TREE ? 2 : 1;
2005 continue;
2007 if (c1 == NULL_TREE)
2008 continue;
2009 if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1),
2010 OMP_CLAUSE_ALIGNED_ALIGNMENT (c2)))
2011 return 2;
2013 switch (r)
2015 case 0: return 0;
2016 case 1: return -1;
2017 case 2: return 1;
2018 case 3: return 2;
2019 default: gcc_unreachable ();
2023 /* Compare properties of selectors SEL from SET other than construct.
2024 CTX1 and CTX2 are the lists of properties to compare.
2025 Return 0/-1/1/2 as in omp_context_selector_set_compare.
2026 Unlike set names or selector names, properties can have duplicates. */
2028 static int
2029 omp_context_selector_props_compare (enum omp_tss_code set,
2030 enum omp_ts_code sel,
2031 tree ctx1, tree ctx2)
2033 int ret = 0;
2034 for (int pass = 0; pass < 2; pass++)
2035 for (tree p1 = pass ? ctx2 : ctx1; p1; p1 = TREE_CHAIN (p1))
2037 tree p2;
2038 for (p2 = pass ? ctx1 : ctx2; p2; p2 = TREE_CHAIN (p2))
2039 if (OMP_TP_NAME (p1) == OMP_TP_NAME (p2))
2041 if (OMP_TP_NAME (p1) == NULL_TREE)
2043 if (set == OMP_TRAIT_SET_USER
2044 && sel == OMP_TRAIT_USER_CONDITION)
2046 if (integer_zerop (OMP_TP_VALUE (p1))
2047 != integer_zerop (OMP_TP_VALUE (p2)))
2048 return 2;
2049 break;
2051 if (simple_cst_equal (OMP_TP_VALUE (p1), OMP_TP_VALUE (p2)))
2052 break;
2054 else if (OMP_TP_NAME (p1) == OMP_TP_NAMELIST_NODE)
2056 /* Handle string constant vs identifier comparison for
2057 name-list properties. */
2058 const char *n1 = omp_context_name_list_prop (p1);
2059 const char *n2 = omp_context_name_list_prop (p2);
2060 if (n1 && n2 && !strcmp (n1, n2))
2061 break;
2063 else
2064 break;
2066 if (p2 == NULL_TREE)
2068 int r = pass ? -1 : 1;
2069 if (ret && ret != r)
2070 return 2;
2071 else if (pass)
2072 return r;
2073 else
2075 ret = r;
2076 break;
2080 return ret;
2083 /* Compare single context selector sets CTX1 and CTX2 with SET name.
2084 CTX1 and CTX2 are lists of trait-selectors.
2085 Return 0 if CTX1 is equal to CTX2,
2086 -1 if CTX1 is a strict subset of CTX2,
2087 1 if CTX2 is a strict subset of CTX1, or
2088 2 if neither context is a subset of another one. */
2091 omp_context_selector_set_compare (enum omp_tss_code set, tree ctx1, tree ctx2)
2094 /* If either list includes an ignored selector trait, neither can
2095 be a subset of the other. */
2096 for (tree ts = ctx1; ts; ts = TREE_CHAIN (ts))
2097 if (OMP_TS_CODE (ts) == OMP_TRAIT_INVALID)
2098 return 2;
2099 for (tree ts = ctx2; ts; ts = TREE_CHAIN (ts))
2100 if (OMP_TS_CODE (ts) == OMP_TRAIT_INVALID)
2101 return 2;
2103 bool swapped = false;
2104 int ret = 0;
2105 int len1 = list_length (ctx1);
2106 int len2 = list_length (ctx2);
2107 int cnt = 0;
2108 if (len1 < len2)
2110 swapped = true;
2111 std::swap (ctx1, ctx2);
2112 std::swap (len1, len2);
2115 if (set == OMP_TRAIT_SET_CONSTRUCT)
2117 tree ts1;
2118 tree ts2 = ctx2;
2119 /* Handle construct set specially. In this case the order
2120 of the selector matters too. */
2121 for (ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
2122 if (OMP_TS_CODE (ts1) == OMP_TS_CODE (ts2))
2124 int r = 0;
2125 if (OMP_TS_CODE (ts1) == OMP_TRAIT_CONSTRUCT_SIMD)
2126 r = omp_construct_simd_compare (OMP_TS_PROPERTIES (ts1),
2127 OMP_TS_PROPERTIES (ts2));
2128 if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
2129 return 2;
2130 if (ret == 0)
2131 ret = r;
2132 ts2 = TREE_CHAIN (ts2);
2133 if (ts2 == NULL_TREE)
2135 ts1 = TREE_CHAIN (ts1);
2136 break;
2139 else if (ret < 0)
2140 return 2;
2141 else
2142 ret = 1;
2143 if (ts2 != NULL_TREE)
2144 return 2;
2145 if (ts1 != NULL_TREE)
2147 if (ret < 0)
2148 return 2;
2149 ret = 1;
2151 if (ret == 0)
2152 return 0;
2153 return swapped ? -ret : ret;
2155 for (tree ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
2157 enum omp_ts_code sel = OMP_TS_CODE (ts1);
2158 tree ts2;
2159 for (ts2 = ctx2; ts2; ts2 = TREE_CHAIN (ts2))
2160 if (sel == OMP_TS_CODE (ts2))
2162 tree score1 = OMP_TS_SCORE (ts1);
2163 tree score2 = OMP_TS_SCORE (ts2);
2164 if (score1 && score2 && !simple_cst_equal (score1, score2))
2165 return 2;
2167 int r = omp_context_selector_props_compare (set, OMP_TS_CODE (ts1),
2168 OMP_TS_PROPERTIES (ts1),
2169 OMP_TS_PROPERTIES (ts2));
2170 if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
2171 return 2;
2172 if (ret == 0)
2173 ret = r;
2174 cnt++;
2175 break;
2177 if (ts2 == NULL_TREE)
2179 if (ret == -1)
2180 return 2;
2181 ret = 1;
2184 if (cnt < len2)
2185 return 2;
2186 if (ret == 0)
2187 return 0;
2188 return swapped ? -ret : ret;
2191 /* Compare whole context selector specification CTX1 and CTX2.
2192 Return 0 if CTX1 is equal to CTX2,
2193 -1 if CTX1 is a strict subset of CTX2,
2194 1 if CTX2 is a strict subset of CTX1, or
2195 2 if neither context is a subset of another one. */
2197 static int
2198 omp_context_selector_compare (tree ctx1, tree ctx2)
2200 bool swapped = false;
2201 int ret = 0;
2202 int len1 = list_length (ctx1);
2203 int len2 = list_length (ctx2);
2204 int cnt = 0;
2205 if (len1 < len2)
2207 swapped = true;
2208 std::swap (ctx1, ctx2);
2209 std::swap (len1, len2);
2211 for (tree tss1 = ctx1; tss1; tss1 = TREE_CHAIN (tss1))
2213 enum omp_tss_code set = OMP_TSS_CODE (tss1);
2214 tree tss2;
2215 for (tss2 = ctx2; tss2; tss2 = TREE_CHAIN (tss2))
2216 if (set == OMP_TSS_CODE (tss2))
2218 int r
2219 = omp_context_selector_set_compare
2220 (set, OMP_TSS_TRAIT_SELECTORS (tss1),
2221 OMP_TSS_TRAIT_SELECTORS (tss2));
2222 if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
2223 return 2;
2224 if (ret == 0)
2225 ret = r;
2226 cnt++;
2227 break;
2229 if (tss2 == NULL_TREE)
2231 if (ret == -1)
2232 return 2;
2233 ret = 1;
2236 if (cnt < len2)
2237 return 2;
2238 if (ret == 0)
2239 return 0;
2240 return swapped ? -ret : ret;
2243 /* From context selector CTX, return trait-selector with name SEL in
2244 trait-selector-set with name SET if any, or NULL_TREE if not found. */
2245 tree
2246 omp_get_context_selector (tree ctx, enum omp_tss_code set,
2247 enum omp_ts_code sel)
2249 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
2250 if (OMP_TSS_CODE (tss) == set)
2251 for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
2252 if (OMP_TS_CODE (ts) == sel)
2253 return ts;
2254 return NULL_TREE;
2257 /* Similar, but returns the whole trait-selector list for SET in CTX. */
2258 tree
2259 omp_get_context_selector_list (tree ctx, enum omp_tss_code set)
2261 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
2262 if (OMP_TSS_CODE (tss) == set)
2263 return OMP_TSS_TRAIT_SELECTORS (tss);
2264 return NULL_TREE;
2267 /* Map string S onto a trait selector set code. */
2268 enum omp_tss_code
2269 omp_lookup_tss_code (const char * s)
2271 for (int i = 0; i < OMP_TRAIT_SET_LAST; i++)
2272 if (strcmp (s, omp_tss_map[i]) == 0)
2273 return (enum omp_tss_code) i;
2274 return OMP_TRAIT_SET_INVALID;
2277 /* Map string S onto a trait selector code for set SET. */
2278 enum omp_ts_code
2279 omp_lookup_ts_code (enum omp_tss_code set, const char *s)
2281 unsigned int mask = 1 << set;
2282 for (int i = 0; i < OMP_TRAIT_LAST; i++)
2283 if ((mask & omp_ts_map[i].tss_mask) != 0
2284 && strcmp (s, omp_ts_map[i].name) == 0)
2285 return (enum omp_ts_code) i;
2286 return OMP_TRAIT_INVALID;
2289 /* Needs to be a GC-friendly widest_int variant, but precision is
2290 desirable to be the same on all targets. */
2291 typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
2293 /* Compute *SCORE for context selector CTX. Return true if the score
2294 would be different depending on whether it is a declare simd clone or
2295 not. DECLARE_SIMD should be true for the case when it would be
2296 a declare simd clone. */
2298 static bool
2299 omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
2301 tree selectors
2302 = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
2303 bool has_kind = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
2304 OMP_TRAIT_DEVICE_KIND);
2305 bool has_arch = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
2306 OMP_TRAIT_DEVICE_ARCH);
2307 bool has_isa = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
2308 OMP_TRAIT_DEVICE_ISA);
2309 bool ret = false;
2310 *score = 1;
2311 for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
2312 if (OMP_TSS_TRAIT_SELECTORS (tss) != selectors)
2313 for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
2315 tree s = OMP_TS_SCORE (ts);
2316 if (s && TREE_CODE (s) == INTEGER_CST)
2317 *score += score_wide_int::from (wi::to_wide (s),
2318 TYPE_SIGN (TREE_TYPE (s)));
2321 if (selectors || has_kind || has_arch || has_isa)
2323 int nconstructs = list_length (selectors);
2324 enum tree_code *constructs = NULL;
2325 if (nconstructs)
2327 constructs
2328 = (enum tree_code *) alloca (nconstructs
2329 * sizeof (enum tree_code));
2330 omp_construct_traits_to_codes (selectors, nconstructs, constructs);
2332 int *scores
2333 = (int *) alloca ((2 * nconstructs + 2) * sizeof (int));
2334 if (omp_construct_selector_matches (constructs, nconstructs, scores)
2335 == 2)
2336 ret = true;
2337 int b = declare_simd ? nconstructs + 1 : 0;
2338 if (scores[b + nconstructs] + 4U < score->get_precision ())
2340 for (int n = 0; n < nconstructs; ++n)
2342 if (scores[b + n] < 0)
2344 *score = -1;
2345 return ret;
2347 *score += wi::shifted_mask <score_wide_int> (scores[b + n], 1, false);
2349 if (has_kind)
2350 *score += wi::shifted_mask <score_wide_int> (scores[b + nconstructs],
2351 1, false);
2352 if (has_arch)
2353 *score += wi::shifted_mask <score_wide_int> (scores[b + nconstructs] + 1,
2354 1, false);
2355 if (has_isa)
2356 *score += wi::shifted_mask <score_wide_int> (scores[b + nconstructs] + 2,
2357 1, false);
2359 else /* FIXME: Implement this. */
2360 gcc_unreachable ();
2362 return ret;
2365 /* Class describing a single variant. */
2366 struct GTY(()) omp_declare_variant_entry {
2367 /* NODE of the variant. */
2368 cgraph_node *variant;
2369 /* Score if not in declare simd clone. */
2370 score_wide_int score;
2371 /* Score if in declare simd clone. */
2372 score_wide_int score_in_declare_simd_clone;
2373 /* Context selector for the variant. */
2374 tree ctx;
2375 /* True if the context selector is known to match already. */
2376 bool matches;
2379 /* Class describing a function with variants. */
2380 struct GTY((for_user)) omp_declare_variant_base_entry {
2381 /* NODE of the base function. */
2382 cgraph_node *base;
2383 /* NODE of the artificial function created for the deferred variant
2384 resolution. */
2385 cgraph_node *node;
2386 /* Vector of the variants. */
2387 vec<omp_declare_variant_entry, va_gc> *variants;
2390 struct omp_declare_variant_hasher
2391 : ggc_ptr_hash<omp_declare_variant_base_entry> {
2392 static hashval_t hash (omp_declare_variant_base_entry *);
2393 static bool equal (omp_declare_variant_base_entry *,
2394 omp_declare_variant_base_entry *);
2397 hashval_t
2398 omp_declare_variant_hasher::hash (omp_declare_variant_base_entry *x)
2400 inchash::hash hstate;
2401 hstate.add_int (DECL_UID (x->base->decl));
2402 hstate.add_int (x->variants->length ());
2403 omp_declare_variant_entry *variant;
2404 unsigned int i;
2405 FOR_EACH_VEC_SAFE_ELT (x->variants, i, variant)
2407 hstate.add_int (DECL_UID (variant->variant->decl));
2408 hstate.add_wide_int (variant->score);
2409 hstate.add_wide_int (variant->score_in_declare_simd_clone);
2410 hstate.add_ptr (variant->ctx);
2411 hstate.add_int (variant->matches);
2413 return hstate.end ();
2416 bool
2417 omp_declare_variant_hasher::equal (omp_declare_variant_base_entry *x,
2418 omp_declare_variant_base_entry *y)
2420 if (x->base != y->base
2421 || x->variants->length () != y->variants->length ())
2422 return false;
2423 omp_declare_variant_entry *variant;
2424 unsigned int i;
2425 FOR_EACH_VEC_SAFE_ELT (x->variants, i, variant)
2426 if (variant->variant != (*y->variants)[i].variant
2427 || variant->score != (*y->variants)[i].score
2428 || (variant->score_in_declare_simd_clone
2429 != (*y->variants)[i].score_in_declare_simd_clone)
2430 || variant->ctx != (*y->variants)[i].ctx
2431 || variant->matches != (*y->variants)[i].matches)
2432 return false;
2433 return true;
2436 static GTY(()) hash_table<omp_declare_variant_hasher> *omp_declare_variants;
2438 struct omp_declare_variant_alt_hasher
2439 : ggc_ptr_hash<omp_declare_variant_base_entry> {
2440 static hashval_t hash (omp_declare_variant_base_entry *);
2441 static bool equal (omp_declare_variant_base_entry *,
2442 omp_declare_variant_base_entry *);
2445 hashval_t
2446 omp_declare_variant_alt_hasher::hash (omp_declare_variant_base_entry *x)
2448 return DECL_UID (x->node->decl);
2451 bool
2452 omp_declare_variant_alt_hasher::equal (omp_declare_variant_base_entry *x,
2453 omp_declare_variant_base_entry *y)
2455 return x->node == y->node;
2458 static GTY(()) hash_table<omp_declare_variant_alt_hasher>
2459 *omp_declare_variant_alt;
2461 /* Try to resolve declare variant after gimplification. */
2463 static tree
2464 omp_resolve_late_declare_variant (tree alt)
2466 cgraph_node *node = cgraph_node::get (alt);
2467 cgraph_node *cur_node = cgraph_node::get (cfun->decl);
2468 if (node == NULL
2469 || !node->declare_variant_alt
2470 || !cfun->after_inlining)
2471 return alt;
2473 omp_declare_variant_base_entry entry;
2474 entry.base = NULL;
2475 entry.node = node;
2476 entry.variants = NULL;
2477 omp_declare_variant_base_entry *entryp
2478 = omp_declare_variant_alt->find_with_hash (&entry, DECL_UID (alt));
2480 unsigned int i, j;
2481 omp_declare_variant_entry *varentry1, *varentry2;
2482 auto_vec <bool, 16> matches;
2483 unsigned int nmatches = 0;
2484 FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
2486 if (varentry1->matches)
2488 /* This has been checked to be ok already. */
2489 matches.safe_push (true);
2490 nmatches++;
2491 continue;
2493 switch (omp_context_selector_matches (varentry1->ctx))
2495 case 0:
2496 matches.safe_push (false);
2497 break;
2498 case -1:
2499 return alt;
2500 default:
2501 matches.safe_push (true);
2502 nmatches++;
2503 break;
2507 if (nmatches == 0)
2508 return entryp->base->decl;
2510 /* A context selector that is a strict subset of another context selector
2511 has a score of zero. */
2512 FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
2513 if (matches[i])
2515 for (j = i + 1;
2516 vec_safe_iterate (entryp->variants, j, &varentry2); ++j)
2517 if (matches[j])
2519 int r = omp_context_selector_compare (varentry1->ctx,
2520 varentry2->ctx);
2521 if (r == -1)
2523 /* ctx1 is a strict subset of ctx2, ignore ctx1. */
2524 matches[i] = false;
2525 break;
2527 else if (r == 1)
2528 /* ctx2 is a strict subset of ctx1, remove ctx2. */
2529 matches[j] = false;
2533 score_wide_int max_score = -1;
2534 varentry2 = NULL;
2535 FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
2536 if (matches[i])
2538 score_wide_int score
2539 = (cur_node->simdclone ? varentry1->score_in_declare_simd_clone
2540 : varentry1->score);
2541 if (score > max_score)
2543 max_score = score;
2544 varentry2 = varentry1;
2547 return varentry2->variant->decl;
2550 /* Hook to adjust hash tables on cgraph_node removal. */
2552 static void
2553 omp_declare_variant_remove_hook (struct cgraph_node *node, void *)
2555 if (!node->declare_variant_alt)
2556 return;
2558 /* Drop this hash table completely. */
2559 omp_declare_variants = NULL;
2560 /* And remove node from the other hash table. */
2561 if (omp_declare_variant_alt)
2563 omp_declare_variant_base_entry entry;
2564 entry.base = NULL;
2565 entry.node = node;
2566 entry.variants = NULL;
2567 omp_declare_variant_alt->remove_elt_with_hash (&entry,
2568 DECL_UID (node->decl));
2572 /* Try to resolve declare variant, return the variant decl if it should
2573 be used instead of base, or base otherwise. */
2575 tree
2576 omp_resolve_declare_variant (tree base)
2578 tree variant1 = NULL_TREE, variant2 = NULL_TREE;
2579 if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
2580 return omp_resolve_late_declare_variant (base);
2582 auto_vec <tree, 16> variants;
2583 auto_vec <bool, 16> defer;
2584 bool any_deferred = false;
2585 for (tree attr = DECL_ATTRIBUTES (base); attr; attr = TREE_CHAIN (attr))
2587 attr = lookup_attribute ("omp declare variant base", attr);
2588 if (attr == NULL_TREE)
2589 break;
2590 if (TREE_CODE (TREE_PURPOSE (TREE_VALUE (attr))) != FUNCTION_DECL)
2591 continue;
2592 cgraph_node *node = cgraph_node::get (base);
2593 /* If this is already a magic decl created by this function,
2594 don't process it again. */
2595 if (node && node->declare_variant_alt)
2596 return base;
2597 switch (omp_context_selector_matches (TREE_VALUE (TREE_VALUE (attr))))
2599 case 0:
2600 /* No match, ignore. */
2601 break;
2602 case -1:
2603 /* Needs to be deferred. */
2604 any_deferred = true;
2605 variants.safe_push (attr);
2606 defer.safe_push (true);
2607 break;
2608 default:
2609 variants.safe_push (attr);
2610 defer.safe_push (false);
2611 break;
2614 if (variants.length () == 0)
2615 return base;
2617 if (any_deferred)
2619 score_wide_int max_score1 = 0;
2620 score_wide_int max_score2 = 0;
2621 bool first = true;
2622 unsigned int i;
2623 tree attr1, attr2;
2624 omp_declare_variant_base_entry entry;
2625 entry.base = cgraph_node::get_create (base);
2626 entry.node = NULL;
2627 vec_alloc (entry.variants, variants.length ());
2628 FOR_EACH_VEC_ELT (variants, i, attr1)
2630 score_wide_int score1;
2631 score_wide_int score2;
2632 bool need_two;
2633 tree ctx = TREE_VALUE (TREE_VALUE (attr1));
2634 need_two = omp_context_compute_score (ctx, &score1, false);
2635 if (need_two)
2636 omp_context_compute_score (ctx, &score2, true);
2637 else
2638 score2 = score1;
2639 if (first)
2641 first = false;
2642 max_score1 = score1;
2643 max_score2 = score2;
2644 if (!defer[i])
2646 variant1 = attr1;
2647 variant2 = attr1;
2650 else
2652 if (max_score1 == score1)
2653 variant1 = NULL_TREE;
2654 else if (score1 > max_score1)
2656 max_score1 = score1;
2657 variant1 = defer[i] ? NULL_TREE : attr1;
2659 if (max_score2 == score2)
2660 variant2 = NULL_TREE;
2661 else if (score2 > max_score2)
2663 max_score2 = score2;
2664 variant2 = defer[i] ? NULL_TREE : attr1;
2667 omp_declare_variant_entry varentry;
2668 varentry.variant
2669 = cgraph_node::get_create (TREE_PURPOSE (TREE_VALUE (attr1)));
2670 varentry.score = score1;
2671 varentry.score_in_declare_simd_clone = score2;
2672 varentry.ctx = ctx;
2673 varentry.matches = !defer[i];
2674 entry.variants->quick_push (varentry);
2677 /* If there is a clear winner variant with the score which is not
2678 deferred, verify it is not a strict subset of any other context
2679 selector and if it is not, it is the best alternative no matter
2680 whether the others do or don't match. */
2681 if (variant1 && variant1 == variant2)
2683 tree ctx1 = TREE_VALUE (TREE_VALUE (variant1));
2684 FOR_EACH_VEC_ELT (variants, i, attr2)
2686 if (attr2 == variant1)
2687 continue;
2688 tree ctx2 = TREE_VALUE (TREE_VALUE (attr2));
2689 int r = omp_context_selector_compare (ctx1, ctx2);
2690 if (r == -1)
2692 /* The winner is a strict subset of ctx2, can't
2693 decide now. */
2694 variant1 = NULL_TREE;
2695 break;
2698 if (variant1)
2700 vec_free (entry.variants);
2701 return TREE_PURPOSE (TREE_VALUE (variant1));
2705 static struct cgraph_node_hook_list *node_removal_hook_holder;
2706 if (!node_removal_hook_holder)
2707 node_removal_hook_holder
2708 = symtab->add_cgraph_removal_hook (omp_declare_variant_remove_hook,
2709 NULL);
2711 if (omp_declare_variants == NULL)
2712 omp_declare_variants
2713 = hash_table<omp_declare_variant_hasher>::create_ggc (64);
2714 omp_declare_variant_base_entry **slot
2715 = omp_declare_variants->find_slot (&entry, INSERT);
2716 if (*slot != NULL)
2718 vec_free (entry.variants);
2719 return (*slot)->node->decl;
2722 *slot = ggc_cleared_alloc<omp_declare_variant_base_entry> ();
2723 (*slot)->base = entry.base;
2724 (*slot)->node = entry.base;
2725 (*slot)->variants = entry.variants;
2726 tree alt = build_decl (DECL_SOURCE_LOCATION (base), FUNCTION_DECL,
2727 DECL_NAME (base), TREE_TYPE (base));
2728 DECL_ARTIFICIAL (alt) = 1;
2729 DECL_IGNORED_P (alt) = 1;
2730 TREE_STATIC (alt) = 1;
2731 tree attributes = DECL_ATTRIBUTES (base);
2732 if (lookup_attribute ("noipa", attributes) == NULL)
2734 attributes = tree_cons (get_identifier ("noipa"), NULL, attributes);
2735 if (lookup_attribute ("noinline", attributes) == NULL)
2736 attributes = tree_cons (get_identifier ("noinline"), NULL,
2737 attributes);
2738 if (lookup_attribute ("noclone", attributes) == NULL)
2739 attributes = tree_cons (get_identifier ("noclone"), NULL,
2740 attributes);
2741 if (lookup_attribute ("no_icf", attributes) == NULL)
2742 attributes = tree_cons (get_identifier ("no_icf"), NULL,
2743 attributes);
2745 DECL_ATTRIBUTES (alt) = attributes;
2746 DECL_INITIAL (alt) = error_mark_node;
2747 (*slot)->node = cgraph_node::create (alt);
2748 (*slot)->node->declare_variant_alt = 1;
2749 (*slot)->node->create_reference (entry.base, IPA_REF_ADDR);
2750 omp_declare_variant_entry *varentry;
2751 FOR_EACH_VEC_SAFE_ELT (entry.variants, i, varentry)
2752 (*slot)->node->create_reference (varentry->variant, IPA_REF_ADDR);
2753 if (omp_declare_variant_alt == NULL)
2754 omp_declare_variant_alt
2755 = hash_table<omp_declare_variant_alt_hasher>::create_ggc (64);
2756 *omp_declare_variant_alt->find_slot_with_hash (*slot, DECL_UID (alt),
2757 INSERT) = *slot;
2758 return alt;
2761 if (variants.length () == 1)
2762 return TREE_PURPOSE (TREE_VALUE (variants[0]));
2764 /* A context selector that is a strict subset of another context selector
2765 has a score of zero. */
2766 tree attr1, attr2;
2767 unsigned int i, j;
2768 FOR_EACH_VEC_ELT (variants, i, attr1)
2769 if (attr1)
2771 tree ctx1 = TREE_VALUE (TREE_VALUE (attr1));
2772 FOR_EACH_VEC_ELT_FROM (variants, j, attr2, i + 1)
2773 if (attr2)
2775 tree ctx2 = TREE_VALUE (TREE_VALUE (attr2));
2776 int r = omp_context_selector_compare (ctx1, ctx2);
2777 if (r == -1)
2779 /* ctx1 is a strict subset of ctx2, remove
2780 attr1 from the vector. */
2781 variants[i] = NULL_TREE;
2782 break;
2784 else if (r == 1)
2785 /* ctx2 is a strict subset of ctx1, remove attr2
2786 from the vector. */
2787 variants[j] = NULL_TREE;
2790 score_wide_int max_score1 = 0;
2791 score_wide_int max_score2 = 0;
2792 bool first = true;
2793 FOR_EACH_VEC_ELT (variants, i, attr1)
2794 if (attr1)
2796 if (variant1)
2798 score_wide_int score1;
2799 score_wide_int score2;
2800 bool need_two;
2801 tree ctx;
2802 if (first)
2804 first = false;
2805 ctx = TREE_VALUE (TREE_VALUE (variant1));
2806 need_two = omp_context_compute_score (ctx, &max_score1, false);
2807 if (need_two)
2808 omp_context_compute_score (ctx, &max_score2, true);
2809 else
2810 max_score2 = max_score1;
2812 ctx = TREE_VALUE (TREE_VALUE (attr1));
2813 need_two = omp_context_compute_score (ctx, &score1, false);
2814 if (need_two)
2815 omp_context_compute_score (ctx, &score2, true);
2816 else
2817 score2 = score1;
2818 if (score1 > max_score1)
2820 max_score1 = score1;
2821 variant1 = attr1;
2823 if (score2 > max_score2)
2825 max_score2 = score2;
2826 variant2 = attr1;
2829 else
2831 variant1 = attr1;
2832 variant2 = attr1;
2835 /* If there is a disagreement on which variant has the highest score
2836 depending on whether it will be in a declare simd clone or not,
2837 punt for now and defer until after IPA where we will know that. */
2838 return ((variant1 && variant1 == variant2)
2839 ? TREE_PURPOSE (TREE_VALUE (variant1)) : base);
2842 void
2843 omp_lto_output_declare_variant_alt (lto_simple_output_block *ob,
2844 cgraph_node *node,
2845 lto_symtab_encoder_t encoder)
2847 gcc_assert (node->declare_variant_alt);
2849 omp_declare_variant_base_entry entry;
2850 entry.base = NULL;
2851 entry.node = node;
2852 entry.variants = NULL;
2853 omp_declare_variant_base_entry *entryp
2854 = omp_declare_variant_alt->find_with_hash (&entry, DECL_UID (node->decl));
2855 gcc_assert (entryp);
2857 int nbase = lto_symtab_encoder_lookup (encoder, entryp->base);
2858 gcc_assert (nbase != LCC_NOT_FOUND);
2859 streamer_write_hwi_stream (ob->main_stream, nbase);
2861 streamer_write_hwi_stream (ob->main_stream, entryp->variants->length ());
2863 unsigned int i;
2864 omp_declare_variant_entry *varentry;
2865 FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry)
2867 int nvar = lto_symtab_encoder_lookup (encoder, varentry->variant);
2868 gcc_assert (nvar != LCC_NOT_FOUND);
2869 streamer_write_hwi_stream (ob->main_stream, nvar);
2871 for (score_wide_int *w = &varentry->score; ;
2872 w = &varentry->score_in_declare_simd_clone)
2874 unsigned len = w->get_len ();
2875 streamer_write_hwi_stream (ob->main_stream, len);
2876 const HOST_WIDE_INT *val = w->get_val ();
2877 for (unsigned j = 0; j < len; j++)
2878 streamer_write_hwi_stream (ob->main_stream, val[j]);
2879 if (w == &varentry->score_in_declare_simd_clone)
2880 break;
2883 HOST_WIDE_INT cnt = -1;
2884 HOST_WIDE_INT i = varentry->matches ? 1 : 0;
2885 for (tree attr = DECL_ATTRIBUTES (entryp->base->decl);
2886 attr; attr = TREE_CHAIN (attr), i += 2)
2888 attr = lookup_attribute ("omp declare variant base", attr);
2889 if (attr == NULL_TREE)
2890 break;
2892 if (varentry->ctx == TREE_VALUE (TREE_VALUE (attr)))
2894 cnt = i;
2895 break;
2899 gcc_assert (cnt != -1);
2900 streamer_write_hwi_stream (ob->main_stream, cnt);
2904 void
2905 omp_lto_input_declare_variant_alt (lto_input_block *ib, cgraph_node *node,
2906 vec<symtab_node *> nodes)
2908 gcc_assert (node->declare_variant_alt);
2909 omp_declare_variant_base_entry *entryp
2910 = ggc_cleared_alloc<omp_declare_variant_base_entry> ();
2911 entryp->base = dyn_cast<cgraph_node *> (nodes[streamer_read_hwi (ib)]);
2912 entryp->node = node;
2913 unsigned int len = streamer_read_hwi (ib);
2914 vec_alloc (entryp->variants, len);
2916 for (unsigned int i = 0; i < len; i++)
2918 omp_declare_variant_entry varentry;
2919 varentry.variant
2920 = dyn_cast<cgraph_node *> (nodes[streamer_read_hwi (ib)]);
2921 for (score_wide_int *w = &varentry.score; ;
2922 w = &varentry.score_in_declare_simd_clone)
2924 unsigned len2 = streamer_read_hwi (ib);
2925 HOST_WIDE_INT arr[WIDE_INT_MAX_HWIS (1024)];
2926 gcc_assert (len2 <= WIDE_INT_MAX_HWIS (1024));
2927 for (unsigned int j = 0; j < len2; j++)
2928 arr[j] = streamer_read_hwi (ib);
2929 *w = score_wide_int::from_array (arr, len2, true);
2930 if (w == &varentry.score_in_declare_simd_clone)
2931 break;
2934 HOST_WIDE_INT cnt = streamer_read_hwi (ib);
2935 HOST_WIDE_INT j = 0;
2936 varentry.ctx = NULL_TREE;
2937 varentry.matches = (cnt & 1) ? true : false;
2938 cnt &= ~HOST_WIDE_INT_1;
2939 for (tree attr = DECL_ATTRIBUTES (entryp->base->decl);
2940 attr; attr = TREE_CHAIN (attr), j += 2)
2942 attr = lookup_attribute ("omp declare variant base", attr);
2943 if (attr == NULL_TREE)
2944 break;
2946 if (cnt == j)
2948 varentry.ctx = TREE_VALUE (TREE_VALUE (attr));
2949 break;
2952 gcc_assert (varentry.ctx != NULL_TREE);
2953 entryp->variants->quick_push (varentry);
2955 if (omp_declare_variant_alt == NULL)
2956 omp_declare_variant_alt
2957 = hash_table<omp_declare_variant_alt_hasher>::create_ggc (64);
2958 *omp_declare_variant_alt->find_slot_with_hash (entryp, DECL_UID (node->decl),
2959 INSERT) = entryp;
2962 /* Encode an oacc launch argument. This matches the GOMP_LAUNCH_PACK
2963 macro on gomp-constants.h. We do not check for overflow. */
2965 tree
2966 oacc_launch_pack (unsigned code, tree device, unsigned op)
2968 tree res;
2970 res = build_int_cst (unsigned_type_node, GOMP_LAUNCH_PACK (code, 0, op));
2971 if (device)
2973 device = fold_build2 (LSHIFT_EXPR, unsigned_type_node,
2974 device, build_int_cst (unsigned_type_node,
2975 GOMP_LAUNCH_DEVICE_SHIFT));
2976 res = fold_build2 (BIT_IOR_EXPR, unsigned_type_node, res, device);
2978 return res;
2981 /* Openacc compute grid dimension clauses are converted to an attribute
2982 attached to the function. This permits the target-side code to (a) massage
2983 the dimensions, (b) emit that data and (c) optimize. Non-constant
2984 dimensions are pushed onto ARGS.
2986 The attribute value is a TREE_LIST. A set of dimensions is
2987 represented as a list of INTEGER_CST. Those that are runtime
2988 exprs are represented as an INTEGER_CST of zero.
2990 TODO: Normally the attribute will just contain a single such list. If
2991 however it contains a list of lists, this will represent the use of
2992 device_type. Each member of the outer list is an assoc list of
2993 dimensions, keyed by the device type. The first entry will be the
2994 default. Well, that's the plan. */
2996 /* Replace any existing oacc fn attribute in ATTRIBS with updated
2997 dimensions. */
2999 tree
3000 oacc_replace_fn_attrib_attr (tree attribs, tree dims)
3002 tree ident = get_identifier (OACC_FN_ATTRIB);
3004 /* If we happen to be present as the first attrib, drop it. */
3005 if (attribs && TREE_PURPOSE (attribs) == ident)
3006 attribs = TREE_CHAIN (attribs);
3007 return tree_cons (ident, dims, attribs);
3010 /* Replace any existing oacc fn attribute on FN with updated
3011 dimensions. */
3013 void
3014 oacc_replace_fn_attrib (tree fn, tree dims)
3016 DECL_ATTRIBUTES (fn)
3017 = oacc_replace_fn_attrib_attr (DECL_ATTRIBUTES (fn), dims);
3020 /* Scan CLAUSES for launch dimensions and attach them to the oacc
3021 function attribute. Push any that are non-constant onto the ARGS
3022 list, along with an appropriate GOMP_LAUNCH_DIM tag. */
3024 void
3025 oacc_set_fn_attrib (tree fn, tree clauses, vec<tree> *args)
3027 /* Must match GOMP_DIM ordering. */
3028 static const omp_clause_code ids[]
3029 = { OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS,
3030 OMP_CLAUSE_VECTOR_LENGTH };
3031 unsigned ix;
3032 tree dims[GOMP_DIM_MAX];
3034 tree attr = NULL_TREE;
3035 unsigned non_const = 0;
3037 for (ix = GOMP_DIM_MAX; ix--;)
3039 tree clause = omp_find_clause (clauses, ids[ix]);
3040 tree dim = NULL_TREE;
3042 if (clause)
3043 dim = OMP_CLAUSE_EXPR (clause, ids[ix]);
3044 dims[ix] = dim;
3045 if (dim && TREE_CODE (dim) != INTEGER_CST)
3047 dim = integer_zero_node;
3048 non_const |= GOMP_DIM_MASK (ix);
3050 attr = tree_cons (NULL_TREE, dim, attr);
3053 oacc_replace_fn_attrib (fn, attr);
3055 if (non_const)
3057 /* Push a dynamic argument set. */
3058 args->safe_push (oacc_launch_pack (GOMP_LAUNCH_DIM,
3059 NULL_TREE, non_const));
3060 for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++)
3061 if (non_const & GOMP_DIM_MASK (ix))
3062 args->safe_push (dims[ix]);
3066 /* Verify OpenACC routine clauses.
3068 Returns 0 if FNDECL should be marked with an OpenACC 'routine' directive, 1
3069 if it has already been marked in compatible way, and -1 if incompatible.
3070 Upon returning, the chain of clauses will contain exactly one clause
3071 specifying the level of parallelism. */
3074 oacc_verify_routine_clauses (tree fndecl, tree *clauses, location_t loc,
3075 const char *routine_str)
3077 tree c_level = NULL_TREE;
3078 tree c_nohost = NULL_TREE;
3079 tree c_p = NULL_TREE;
3080 for (tree c = *clauses; c; c_p = c, c = OMP_CLAUSE_CHAIN (c))
3081 switch (OMP_CLAUSE_CODE (c))
3083 case OMP_CLAUSE_GANG:
3084 case OMP_CLAUSE_WORKER:
3085 case OMP_CLAUSE_VECTOR:
3086 case OMP_CLAUSE_SEQ:
3087 if (c_level == NULL_TREE)
3088 c_level = c;
3089 else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_CODE (c_level))
3091 /* This has already been diagnosed in the front ends. */
3092 /* Drop the duplicate clause. */
3093 gcc_checking_assert (c_p != NULL_TREE);
3094 OMP_CLAUSE_CHAIN (c_p) = OMP_CLAUSE_CHAIN (c);
3095 c = c_p;
3097 else
3099 error_at (OMP_CLAUSE_LOCATION (c),
3100 "%qs specifies a conflicting level of parallelism",
3101 omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
3102 inform (OMP_CLAUSE_LOCATION (c_level),
3103 "... to the previous %qs clause here",
3104 omp_clause_code_name[OMP_CLAUSE_CODE (c_level)]);
3105 /* Drop the conflicting clause. */
3106 gcc_checking_assert (c_p != NULL_TREE);
3107 OMP_CLAUSE_CHAIN (c_p) = OMP_CLAUSE_CHAIN (c);
3108 c = c_p;
3110 break;
3111 case OMP_CLAUSE_NOHOST:
3112 /* Don't worry about duplicate clauses here. */
3113 c_nohost = c;
3114 break;
3115 default:
3116 gcc_unreachable ();
3118 if (c_level == NULL_TREE)
3120 /* Default to an implicit 'seq' clause. */
3121 c_level = build_omp_clause (loc, OMP_CLAUSE_SEQ);
3122 OMP_CLAUSE_CHAIN (c_level) = *clauses;
3123 *clauses = c_level;
3125 /* In *clauses, we now have exactly one clause specifying the level of
3126 parallelism. */
3128 tree attr
3129 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl));
3130 if (attr != NULL_TREE)
3132 /* Diagnose if "#pragma omp declare target" has also been applied. */
3133 if (TREE_VALUE (attr) == NULL_TREE)
3135 /* See <https://gcc.gnu.org/PR93465>; the semantics of combining
3136 OpenACC and OpenMP 'target' are not clear. */
3137 error_at (loc,
3138 "cannot apply %<%s%> to %qD, which has also been"
3139 " marked with an OpenMP 'declare target' directive",
3140 routine_str, fndecl);
3141 /* Incompatible. */
3142 return -1;
3145 /* If a "#pragma acc routine" has already been applied, just verify
3146 this one for compatibility. */
3147 /* Collect previous directive's clauses. */
3148 tree c_level_p = NULL_TREE;
3149 tree c_nohost_p = NULL_TREE;
3150 for (tree c = TREE_VALUE (attr); c; c = OMP_CLAUSE_CHAIN (c))
3151 switch (OMP_CLAUSE_CODE (c))
3153 case OMP_CLAUSE_GANG:
3154 case OMP_CLAUSE_WORKER:
3155 case OMP_CLAUSE_VECTOR:
3156 case OMP_CLAUSE_SEQ:
3157 gcc_checking_assert (c_level_p == NULL_TREE);
3158 c_level_p = c;
3159 break;
3160 case OMP_CLAUSE_NOHOST:
3161 gcc_checking_assert (c_nohost_p == NULL_TREE);
3162 c_nohost_p = c;
3163 break;
3164 default:
3165 gcc_unreachable ();
3167 gcc_checking_assert (c_level_p != NULL_TREE);
3168 /* ..., and compare to current directive's, which we've already collected
3169 above. */
3170 tree c_diag;
3171 tree c_diag_p;
3172 /* Matching level of parallelism? */
3173 if (OMP_CLAUSE_CODE (c_level) != OMP_CLAUSE_CODE (c_level_p))
3175 c_diag = c_level;
3176 c_diag_p = c_level_p;
3177 goto incompatible;
3179 /* Matching 'nohost' clauses? */
3180 if ((c_nohost == NULL_TREE) != (c_nohost_p == NULL_TREE))
3182 c_diag = c_nohost;
3183 c_diag_p = c_nohost_p;
3184 goto incompatible;
3186 /* Compatible. */
3187 return 1;
3189 incompatible:
3190 if (c_diag != NULL_TREE)
3191 error_at (OMP_CLAUSE_LOCATION (c_diag),
3192 "incompatible %qs clause when applying"
3193 " %<%s%> to %qD, which has already been"
3194 " marked with an OpenACC 'routine' directive",
3195 omp_clause_code_name[OMP_CLAUSE_CODE (c_diag)],
3196 routine_str, fndecl);
3197 else if (c_diag_p != NULL_TREE)
3198 error_at (loc,
3199 "missing %qs clause when applying"
3200 " %<%s%> to %qD, which has already been"
3201 " marked with an OpenACC 'routine' directive",
3202 omp_clause_code_name[OMP_CLAUSE_CODE (c_diag_p)],
3203 routine_str, fndecl);
3204 else
3205 gcc_unreachable ();
3206 if (c_diag_p != NULL_TREE)
3207 inform (OMP_CLAUSE_LOCATION (c_diag_p),
3208 "... with %qs clause here",
3209 omp_clause_code_name[OMP_CLAUSE_CODE (c_diag_p)]);
3210 else
3212 /* In the front ends, we don't preserve location information for the
3213 OpenACC routine directive itself. However, that of c_level_p
3214 should be close. */
3215 location_t loc_routine = OMP_CLAUSE_LOCATION (c_level_p);
3216 inform (loc_routine, "... without %qs clause near to here",
3217 omp_clause_code_name[OMP_CLAUSE_CODE (c_diag)]);
3219 /* Incompatible. */
3220 return -1;
3223 return 0;
3226 /* Process the OpenACC 'routine' directive clauses to generate an attribute
3227 for the level of parallelism. All dimensions have a size of zero
3228 (dynamic). TREE_PURPOSE is set to indicate whether that dimension
3229 can have a loop partitioned on it. non-zero indicates
3230 yes, zero indicates no. By construction once a non-zero has been
3231 reached, further inner dimensions must also be non-zero. We set
3232 TREE_VALUE to zero for the dimensions that may be partitioned and
3233 1 for the other ones -- if a loop is (erroneously) spawned at
3234 an outer level, we don't want to try and partition it. */
3236 tree
3237 oacc_build_routine_dims (tree clauses)
3239 /* Must match GOMP_DIM ordering. */
3240 static const omp_clause_code ids[]
3241 = {OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ};
3242 int ix;
3243 int level = -1;
3245 for (; clauses; clauses = OMP_CLAUSE_CHAIN (clauses))
3246 for (ix = GOMP_DIM_MAX + 1; ix--;)
3247 if (OMP_CLAUSE_CODE (clauses) == ids[ix])
3249 level = ix;
3250 break;
3252 gcc_checking_assert (level >= 0);
3254 tree dims = NULL_TREE;
3256 for (ix = GOMP_DIM_MAX; ix--;)
3257 dims = tree_cons (build_int_cst (boolean_type_node, ix >= level),
3258 build_int_cst (integer_type_node, ix < level), dims);
3260 return dims;
3263 /* Retrieve the oacc function attrib and return it. Non-oacc
3264 functions will return NULL. */
3266 tree
3267 oacc_get_fn_attrib (tree fn)
3269 return lookup_attribute (OACC_FN_ATTRIB, DECL_ATTRIBUTES (fn));
3272 /* Return true if FN is an OpenMP or OpenACC offloading function. */
3274 bool
3275 offloading_function_p (tree fn)
3277 tree attrs = DECL_ATTRIBUTES (fn);
3278 return (lookup_attribute ("omp declare target", attrs)
3279 || lookup_attribute ("omp target entrypoint", attrs));
3282 /* Extract an oacc execution dimension from FN. FN must be an
3283 offloaded function or routine that has already had its execution
3284 dimensions lowered to the target-specific values. */
3287 oacc_get_fn_dim_size (tree fn, int axis)
3289 tree attrs = oacc_get_fn_attrib (fn);
3291 gcc_assert (axis < GOMP_DIM_MAX);
3293 tree dims = TREE_VALUE (attrs);
3294 while (axis--)
3295 dims = TREE_CHAIN (dims);
3297 int size = TREE_INT_CST_LOW (TREE_VALUE (dims));
3299 return size;
3302 /* Extract the dimension axis from an IFN_GOACC_DIM_POS or
3303 IFN_GOACC_DIM_SIZE call. */
3306 oacc_get_ifn_dim_arg (const gimple *stmt)
3308 gcc_checking_assert (gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_SIZE
3309 || gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_POS);
3310 tree arg = gimple_call_arg (stmt, 0);
3311 HOST_WIDE_INT axis = TREE_INT_CST_LOW (arg);
3313 gcc_checking_assert (axis >= 0 && axis < GOMP_DIM_MAX);
3314 return (int) axis;
3317 /* Build COMPONENT_REF and set TREE_THIS_VOLATILE and TREE_READONLY on it
3318 as appropriate. */
3320 tree
3321 omp_build_component_ref (tree obj, tree field)
3323 tree ret = build3 (COMPONENT_REF, TREE_TYPE (field), obj, field, NULL);
3324 if (TREE_THIS_VOLATILE (field))
3325 TREE_THIS_VOLATILE (ret) |= 1;
3326 if (TREE_READONLY (field))
3327 TREE_READONLY (ret) |= 1;
3328 return ret;
3331 /* Return true if NAME is the name of an omp_* runtime API call. */
3332 bool
3333 omp_runtime_api_procname (const char *name)
3335 if (!startswith (name, "omp_"))
3336 return false;
3338 static const char *omp_runtime_apis[] =
3340 /* This array has 3 sections. First omp_* calls that don't
3341 have any suffixes. */
3342 "aligned_alloc",
3343 "aligned_calloc",
3344 "alloc",
3345 "calloc",
3346 "free",
3347 "get_interop_int",
3348 "get_interop_ptr",
3349 "get_mapped_ptr",
3350 "get_num_interop_properties",
3351 "realloc",
3352 "target_alloc",
3353 "target_associate_ptr",
3354 "target_disassociate_ptr",
3355 "target_free",
3356 "target_is_accessible",
3357 "target_is_present",
3358 "target_memcpy",
3359 "target_memcpy_async",
3360 "target_memcpy_rect",
3361 "target_memcpy_rect_async",
3362 NULL,
3363 /* Now omp_* calls that are available as omp_* and omp_*_; however, the
3364 DECL_NAME is always omp_* without tailing underscore. */
3365 "capture_affinity",
3366 "destroy_allocator",
3367 "destroy_lock",
3368 "destroy_nest_lock",
3369 "display_affinity",
3370 "fulfill_event",
3371 "get_active_level",
3372 "get_affinity_format",
3373 "get_cancellation",
3374 "get_default_allocator",
3375 "get_default_device",
3376 "get_device_from_uid",
3377 "get_device_num",
3378 "get_dynamic",
3379 "get_initial_device",
3380 "get_interop_name",
3381 "get_interop_rc_desc",
3382 "get_interop_str",
3383 "get_interop_type_desc",
3384 "get_level",
3385 "get_max_active_levels",
3386 "get_max_task_priority",
3387 "get_max_teams",
3388 "get_max_threads",
3389 "get_nested",
3390 "get_num_devices",
3391 "get_num_places",
3392 "get_num_procs",
3393 "get_num_teams",
3394 "get_num_threads",
3395 "get_partition_num_places",
3396 "get_place_num",
3397 "get_proc_bind",
3398 "get_supported_active_levels",
3399 "get_team_num",
3400 "get_teams_thread_limit",
3401 "get_thread_limit",
3402 "get_thread_num",
3403 "get_wtick",
3404 "get_wtime",
3405 "in_explicit_task",
3406 "in_final",
3407 "in_parallel",
3408 "init_lock",
3409 "init_nest_lock",
3410 "is_initial_device",
3411 "pause_resource",
3412 "pause_resource_all",
3413 "set_affinity_format",
3414 "set_default_allocator",
3415 "set_lock",
3416 "set_nest_lock",
3417 "test_lock",
3418 "test_nest_lock",
3419 "unset_lock",
3420 "unset_nest_lock",
3421 NULL,
3422 /* And finally calls available as omp_*, omp_*_ and omp_*_8_; however,
3423 as DECL_NAME only omp_* and omp_*_8 appear. */
3424 "display_env",
3425 "get_ancestor_thread_num",
3426 "get_uid_from_device",
3427 "get_partition_place_nums",
3428 "get_place_num_procs",
3429 "get_place_proc_ids",
3430 "get_schedule",
3431 "get_team_size",
3432 "init_allocator",
3433 "set_default_device",
3434 "set_dynamic",
3435 "set_max_active_levels",
3436 "set_nested",
3437 "set_num_teams",
3438 "set_num_threads",
3439 "set_schedule",
3440 "set_teams_thread_limit"
3443 int mode = 0;
3444 for (unsigned i = 0; i < ARRAY_SIZE (omp_runtime_apis); i++)
3446 if (omp_runtime_apis[i] == NULL)
3448 mode++;
3449 continue;
3451 size_t len = strlen (omp_runtime_apis[i]);
3452 if (strncmp (name + 4, omp_runtime_apis[i], len) == 0
3453 && (name[4 + len] == '\0'
3454 || (mode > 1 && strcmp (name + 4 + len, "_8") == 0)))
3455 return true;
3457 return false;
3460 /* Return true if FNDECL is an omp_* runtime API call. */
3462 bool
3463 omp_runtime_api_call (const_tree fndecl)
3465 tree declname = DECL_NAME (fndecl);
3466 if (!declname
3467 || (DECL_CONTEXT (fndecl) != NULL_TREE
3468 && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL)
3469 || !TREE_PUBLIC (fndecl))
3470 return false;
3471 return omp_runtime_api_procname (IDENTIFIER_POINTER (declname));
3474 /* See "Additional Definitions for the OpenMP API Specification" document;
3475 associated IDs are 1, 2, ... */
3476 static const char* omp_interop_fr_str[] = {"cuda", "cuda_driver", "opencl",
3477 "sycl", "hip", "level_zero", "hsa"};
3479 /* Returns the foreign-runtime ID if found or 0 otherwise. */
3482 omp_get_fr_id_from_name (const char *str)
3484 static_assert (GOMP_INTEROP_IFR_LAST == ARRAY_SIZE (omp_interop_fr_str), "");
3486 for (unsigned i = 0; i < ARRAY_SIZE (omp_interop_fr_str); ++i)
3487 if (!strcmp (str, omp_interop_fr_str[i]))
3488 return i + 1;
3489 return 0;
3492 /* Returns the string value to a foreign-runtime integer value or NULL if value
3493 is not known. */
3495 const char *
3496 omp_get_name_from_fr_id (int fr_id)
3498 if (fr_id < 1 || fr_id > (int) ARRAY_SIZE (omp_interop_fr_str))
3499 return NULL;
3500 return omp_interop_fr_str[fr_id-1];
3503 namespace omp_addr_tokenizer {
3505 /* We scan an expression by recursive descent, and build a vector of
3506 "omp_addr_token *" pointers representing a "parsed" version of the
3507 expression. The grammar we use is something like this:
3509 expr0::
3510 expr [section-access]
3512 expr::
3513 structured-expr access-method
3514 | array-base access-method
3516 structured-expr::
3517 structure-base component-selector
3519 arbitrary-expr::
3520 (anything else)
3522 structure-base::
3523 DECL access-method
3524 | structured-expr access-method
3525 | arbitrary-expr access-method
3527 array-base::
3528 DECL
3529 | arbitrary-expr
3531 access-method::
3532 DIRECT
3533 | REF
3534 | POINTER
3535 | REF_TO_POINTER
3536 | POINTER_OFFSET
3537 | REF_TO_POINTER_OFFSET
3538 | INDEXED_ARRAY
3539 | INDEXED_REF_TO_ARRAY
3540 | index-expr
3542 index-expr::
3543 INDEX_EXPR access-method
3545 component-selector::
3546 component-selector COMPONENT_REF
3547 | component-selector ARRAY_REF
3548 | COMPONENT_REF
3550 This tokenized form is then used both in parsing, for OpenMP clause
3551 expansion (for C and C++) and in gimplify.cc for sibling-list handling
3552 (for C, C++ and Fortran). */
3554 omp_addr_token::omp_addr_token (token_type t, tree e)
3555 : type(t), expr(e)
3559 omp_addr_token::omp_addr_token (access_method_kinds k, tree e)
3560 : type(ACCESS_METHOD), expr(e)
3562 u.access_kind = k;
3565 omp_addr_token::omp_addr_token (token_type t, structure_base_kinds k, tree e)
3566 : type(t), expr(e)
3568 u.structure_base_kind = k;
3571 static bool
3572 omp_parse_component_selector (tree *expr0)
3574 tree expr = *expr0;
3575 tree last_component = NULL_TREE;
3577 while (TREE_CODE (expr) == COMPONENT_REF
3578 || TREE_CODE (expr) == ARRAY_REF)
3580 if (TREE_CODE (expr) == COMPONENT_REF)
3581 last_component = expr;
3583 expr = TREE_OPERAND (expr, 0);
3585 if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE)
3586 break;
3589 if (!last_component)
3590 return false;
3592 *expr0 = last_component;
3593 return true;
3596 /* This handles references that have had convert_from_reference called on
3597 them, and also those that haven't. */
3599 static bool
3600 omp_parse_ref (tree *expr0)
3602 tree expr = *expr0;
3604 if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE)
3605 return true;
3606 else if ((TREE_CODE (expr) == INDIRECT_REF
3607 || (TREE_CODE (expr) == MEM_REF
3608 && integer_zerop (TREE_OPERAND (expr, 1))))
3609 && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
3611 *expr0 = TREE_OPERAND (expr, 0);
3612 return true;
3615 return false;
3618 static bool
3619 omp_parse_pointer (tree *expr0, bool *has_offset)
3621 tree expr = *expr0;
3623 *has_offset = false;
3625 if ((TREE_CODE (expr) == INDIRECT_REF
3626 || (TREE_CODE (expr) == MEM_REF
3627 && integer_zerop (TREE_OPERAND (expr, 1))))
3628 && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == POINTER_TYPE)
3630 expr = TREE_OPERAND (expr, 0);
3632 /* The Fortran FE sometimes emits a no-op cast here. */
3633 STRIP_NOPS (expr);
3635 while (1)
3637 if (TREE_CODE (expr) == COMPOUND_EXPR)
3639 expr = TREE_OPERAND (expr, 1);
3640 STRIP_NOPS (expr);
3642 else if (TREE_CODE (expr) == SAVE_EXPR)
3643 expr = TREE_OPERAND (expr, 0);
3644 else if (TREE_CODE (expr) == POINTER_PLUS_EXPR)
3646 *has_offset = true;
3647 expr = TREE_OPERAND (expr, 0);
3649 else
3650 break;
3653 STRIP_NOPS (expr);
3655 *expr0 = expr;
3656 return true;
3659 return false;
3662 static bool
3663 omp_parse_access_method (tree *expr0, enum access_method_kinds *kind)
3665 tree expr = *expr0;
3666 bool has_offset;
3668 if (omp_parse_ref (&expr))
3669 *kind = ACCESS_REF;
3670 else if (omp_parse_pointer (&expr, &has_offset))
3672 if (omp_parse_ref (&expr))
3673 *kind = has_offset ? ACCESS_REF_TO_POINTER_OFFSET
3674 : ACCESS_REF_TO_POINTER;
3675 else
3676 *kind = has_offset ? ACCESS_POINTER_OFFSET : ACCESS_POINTER;
3678 else if (TREE_CODE (expr) == ARRAY_REF)
3680 while (TREE_CODE (expr) == ARRAY_REF)
3681 expr = TREE_OPERAND (expr, 0);
3682 if (omp_parse_ref (&expr))
3683 *kind = ACCESS_INDEXED_REF_TO_ARRAY;
3684 else
3685 *kind = ACCESS_INDEXED_ARRAY;
3687 else
3688 *kind = ACCESS_DIRECT;
3690 STRIP_NOPS (expr);
3692 *expr0 = expr;
3693 return true;
3696 static bool
3697 omp_parse_access_methods (vec<omp_addr_token *> &addr_tokens, tree *expr0)
3699 tree expr = *expr0;
3700 enum access_method_kinds kind;
3701 tree am_expr;
3703 if (omp_parse_access_method (&expr, &kind))
3704 am_expr = expr;
3706 if (TREE_CODE (expr) == INDIRECT_REF
3707 || TREE_CODE (expr) == MEM_REF
3708 || TREE_CODE (expr) == ARRAY_REF)
3709 omp_parse_access_methods (addr_tokens, &expr);
3711 addr_tokens.safe_push (new omp_addr_token (kind, am_expr));
3713 *expr0 = expr;
3714 return true;
3717 static bool omp_parse_structured_expr (vec<omp_addr_token *> &, tree *);
3719 static bool
3720 omp_parse_structure_base (vec<omp_addr_token *> &addr_tokens,
3721 tree *expr0, structure_base_kinds *kind,
3722 vec<omp_addr_token *> &base_access_tokens,
3723 bool allow_structured = true)
3725 tree expr = *expr0;
3727 if (allow_structured)
3728 omp_parse_access_methods (base_access_tokens, &expr);
3730 if (DECL_P (expr))
3732 *kind = BASE_DECL;
3733 return true;
3736 if (allow_structured && omp_parse_structured_expr (addr_tokens, &expr))
3738 *kind = BASE_COMPONENT_EXPR;
3739 *expr0 = expr;
3740 return true;
3743 *kind = BASE_ARBITRARY_EXPR;
3744 *expr0 = expr;
3745 return true;
3748 static bool
3749 omp_parse_structured_expr (vec<omp_addr_token *> &addr_tokens, tree *expr0)
3751 tree expr = *expr0;
3752 tree base_component = NULL_TREE;
3753 structure_base_kinds struct_base_kind;
3754 auto_vec<omp_addr_token *> base_access_tokens;
3756 if (omp_parse_component_selector (&expr))
3757 base_component = expr;
3758 else
3759 return false;
3761 gcc_assert (TREE_CODE (expr) == COMPONENT_REF);
3762 expr = TREE_OPERAND (expr, 0);
3764 tree structure_base = expr;
3766 if (!omp_parse_structure_base (addr_tokens, &expr, &struct_base_kind,
3767 base_access_tokens))
3768 return false;
3770 addr_tokens.safe_push (new omp_addr_token (STRUCTURE_BASE, struct_base_kind,
3771 structure_base));
3772 addr_tokens.safe_splice (base_access_tokens);
3773 addr_tokens.safe_push (new omp_addr_token (COMPONENT_SELECTOR,
3774 base_component));
3776 *expr0 = expr;
3778 return true;
3781 static bool
3782 omp_parse_array_expr (vec<omp_addr_token *> &addr_tokens, tree *expr0)
3784 tree expr = *expr0;
3785 structure_base_kinds s_kind;
3786 auto_vec<omp_addr_token *> base_access_tokens;
3788 if (!omp_parse_structure_base (addr_tokens, &expr, &s_kind,
3789 base_access_tokens, false))
3790 return false;
3792 addr_tokens.safe_push (new omp_addr_token (ARRAY_BASE, s_kind, expr));
3793 addr_tokens.safe_splice (base_access_tokens);
3795 *expr0 = expr;
3796 return true;
3799 /* Return TRUE if the ACCESS_METHOD token at index 'i' has a further
3800 ACCESS_METHOD chained after it (e.g., if we're processing an expression
3801 containing multiple pointer indirections). */
3803 bool
3804 omp_access_chain_p (vec<omp_addr_token *> &addr_tokens, unsigned i)
3806 gcc_assert (addr_tokens[i]->type == ACCESS_METHOD);
3807 return (i + 1 < addr_tokens.length ()
3808 && addr_tokens[i + 1]->type == ACCESS_METHOD);
3811 /* Return the address of the object accessed by the ACCESS_METHOD token
3812 at 'i': either of the next access method's expr, or of EXPR if we're at
3813 the end of the list of tokens. */
3815 tree
3816 omp_accessed_addr (vec<omp_addr_token *> &addr_tokens, unsigned i, tree expr)
3818 if (i + 1 < addr_tokens.length ())
3819 return build_fold_addr_expr (addr_tokens[i + 1]->expr);
3820 else
3821 return build_fold_addr_expr (expr);
3824 } /* namespace omp_addr_tokenizer. */
3826 bool
3827 omp_parse_expr (vec<omp_addr_token *> &addr_tokens, tree expr)
3829 using namespace omp_addr_tokenizer;
3830 auto_vec<omp_addr_token *> expr_access_tokens;
3832 if (!omp_parse_access_methods (expr_access_tokens, &expr))
3833 return false;
3835 if (omp_parse_structured_expr (addr_tokens, &expr))
3837 else if (omp_parse_array_expr (addr_tokens, &expr))
3839 else
3840 return false;
3842 addr_tokens.safe_splice (expr_access_tokens);
3844 return true;
3847 DEBUG_FUNCTION void
3848 debug_omp_tokenized_addr (vec<omp_addr_token *> &addr_tokens,
3849 bool with_exprs)
3851 using namespace omp_addr_tokenizer;
3852 const char *sep = with_exprs ? " " : "";
3854 for (auto e : addr_tokens)
3856 const char *pfx = "";
3858 fputs (sep, stderr);
3860 switch (e->type)
3862 case COMPONENT_SELECTOR:
3863 fputs ("component_selector", stderr);
3864 break;
3865 case ACCESS_METHOD:
3866 switch (e->u.access_kind)
3868 case ACCESS_DIRECT:
3869 fputs ("access_direct", stderr);
3870 break;
3871 case ACCESS_REF:
3872 fputs ("access_ref", stderr);
3873 break;
3874 case ACCESS_POINTER:
3875 fputs ("access_pointer", stderr);
3876 break;
3877 case ACCESS_POINTER_OFFSET:
3878 fputs ("access_pointer_offset", stderr);
3879 break;
3880 case ACCESS_REF_TO_POINTER:
3881 fputs ("access_ref_to_pointer", stderr);
3882 break;
3883 case ACCESS_REF_TO_POINTER_OFFSET:
3884 fputs ("access_ref_to_pointer_offset", stderr);
3885 break;
3886 case ACCESS_INDEXED_ARRAY:
3887 fputs ("access_indexed_array", stderr);
3888 break;
3889 case ACCESS_INDEXED_REF_TO_ARRAY:
3890 fputs ("access_indexed_ref_to_array", stderr);
3891 break;
3893 break;
3894 case ARRAY_BASE:
3895 case STRUCTURE_BASE:
3896 pfx = e->type == ARRAY_BASE ? "array_" : "struct_";
3897 switch (e->u.structure_base_kind)
3899 case BASE_DECL:
3900 fprintf (stderr, "%sbase_decl", pfx);
3901 break;
3902 case BASE_COMPONENT_EXPR:
3903 fputs ("base_component_expr", stderr);
3904 break;
3905 case BASE_ARBITRARY_EXPR:
3906 fprintf (stderr, "%sbase_arbitrary_expr", pfx);
3907 break;
3909 break;
3911 if (with_exprs)
3913 fputs (" [", stderr);
3914 print_generic_expr (stderr, e->expr);
3915 fputc (']', stderr);
3916 sep = ",\n ";
3918 else
3919 sep = " ";
3922 fputs ("\n", stderr);
3925 /* Return number of iterations of loop I in FOR_STMT. If PSTEP is non-NULL,
3926 *PSTEP will be the loop step. */
3928 tree
3929 omp_loop_number_of_iterations (tree for_stmt, int i, tree *pstep)
3931 tree t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
3932 gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
3933 tree decl = TREE_OPERAND (t, 0);
3934 tree n1 = TREE_OPERAND (t, 1);
3935 tree type = TREE_TYPE (decl);
3936 tree cond = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
3937 gcc_assert (COMPARISON_CLASS_P (cond));
3938 gcc_assert (TREE_OPERAND (cond, 0) == decl);
3939 tree_code cond_code = TREE_CODE (cond);
3940 tree n2 = TREE_OPERAND (cond, 1);
3941 t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
3942 tree step = NULL_TREE;
3943 switch (TREE_CODE (t))
3945 case PREINCREMENT_EXPR:
3946 case POSTINCREMENT_EXPR:
3947 gcc_assert (!POINTER_TYPE_P (type));
3948 gcc_assert (TREE_OPERAND (t, 0) == decl);
3949 step = build_int_cst (type, 1);
3950 break;
3951 case PREDECREMENT_EXPR:
3952 case POSTDECREMENT_EXPR:
3953 gcc_assert (!POINTER_TYPE_P (type));
3954 gcc_assert (TREE_OPERAND (t, 0) == decl);
3955 step = build_int_cst (type, -1);
3956 break;
3957 case MODIFY_EXPR:
3958 gcc_assert (TREE_OPERAND (t, 0) == decl);
3959 t = TREE_OPERAND (t, 1);
3960 switch (TREE_CODE (t))
3962 case PLUS_EXPR:
3963 if (TREE_OPERAND (t, 1) == decl)
3965 TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
3966 TREE_OPERAND (t, 0) = decl;
3968 /* FALLTHRU */
3969 case POINTER_PLUS_EXPR:
3970 case MINUS_EXPR:
3971 step = omp_get_for_step_from_incr (EXPR_LOCATION (t), t);
3972 break;
3973 default:
3974 gcc_unreachable ();
3976 break;
3977 default:
3978 gcc_unreachable ();
3980 omp_adjust_for_condition (EXPR_LOCATION (for_stmt), &cond_code, &n2,
3981 decl, step);
3982 if (pstep)
3983 *pstep = step;
3984 if (INTEGRAL_TYPE_P (type)
3985 && TYPE_PRECISION (type) < TYPE_PRECISION (long_long_integer_type_node))
3987 n1 = fold_convert (long_long_integer_type_node, n1);
3988 n2 = fold_convert (long_long_integer_type_node, n2);
3989 step = fold_convert (long_long_integer_type_node, step);
3991 if (cond_code == LT_EXPR
3992 || POINTER_TYPE_P (type)
3993 || !TYPE_UNSIGNED (TREE_TYPE (n1)))
3995 if (POINTER_TYPE_P (type))
3996 t = fold_build2 (POINTER_DIFF_EXPR, ssizetype, n2, n1);
3997 else
3998 t = fold_build2 (MINUS_EXPR, TREE_TYPE (n1), n2, n1);
3999 t = fold_build2 (CEIL_DIV_EXPR, TREE_TYPE (t), t, step);
4001 else
4003 t = fold_build2 (MINUS_EXPR, type, n1, n2);
4004 t = fold_build2 (CEIL_DIV_EXPR, type, t,
4005 fold_build1 (NEGATE_EXPR, type, step));
4007 return t;
4010 /* Tile transformation:
4011 Original loop:
4013 #pragma omp tile sizes(16, 32)
4014 for (i = 0; i < k; ++i)
4015 for (j = 0; j < 128; j += 2)
4017 baz (i, j);
4020 Transformed loop:
4021 #pragma omp tile sizes(16, 32)
4022 for (i.0 = 0; i.0 < k; i.0 += 16)
4023 for (j.0 = 0; j.0 < 128; j.0 += 64)
4025 i = i.0;
4026 i.1 = MIN_EXPR <i.0 + 16, k>;
4027 goto <D.2783>;
4028 <D.2782>:;
4029 j = j.0;
4030 j.1 = j.0 + 32;
4031 goto <D.2786>;
4032 <D.2785>:;
4034 baz (i, j);
4036 j += 2;
4037 <D.2786>:;
4038 if (j < j.1) goto <D.2785>; else goto <D.2787>;
4039 <D.2787>:;
4040 ++i;
4041 <D.2783>:;
4042 if (i < i.1) goto <D.2782>; else goto <D.2784>;
4043 <D.2784>:;
4046 where the grid loops have canonical form, but the inner
4047 loops don't and so are immediately lowered. */
4049 static void
4050 omp_apply_tile (tree for_stmt, tree sizes, int size)
4052 tree pre_body = NULL_TREE, post_body = NULL_TREE;
4053 tree orig_sizes = sizes;
4054 if (OMP_FOR_NON_RECTANGULAR (for_stmt))
4056 error_at (EXPR_LOCATION (for_stmt), "non-rectangular %<tile%>");
4057 return;
4059 for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
4061 if (orig_sizes)
4063 size = tree_to_uhwi (TREE_VALUE (sizes));
4064 sizes = TREE_CHAIN (sizes);
4066 if (size == 1)
4067 continue;
4068 if (OMP_FOR_ORIG_DECLS (for_stmt) == NULL_TREE)
4070 OMP_FOR_ORIG_DECLS (for_stmt)
4071 = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)));
4072 for (int j = 0; j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); j++)
4074 gcc_assert (TREE_CODE (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j))
4075 == MODIFY_EXPR);
4076 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), j)
4077 = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j), 0);
4080 tree step;
4081 tree iters = omp_loop_number_of_iterations (for_stmt, i, &step);
4082 tree t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
4083 tree decl = TREE_OPERAND (t, 0);
4084 tree type = TREE_TYPE (decl);
4085 tree griddecl = create_tmp_var_raw (type);
4086 DECL_CONTEXT (griddecl) = current_function_decl;
4087 t = build1 (DECL_EXPR, void_type_node, griddecl);
4088 append_to_statement_list (t, &OMP_FOR_PRE_BODY (for_stmt));
4089 TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i), 0) = griddecl;
4090 TREE_PRIVATE (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i)) = 1;
4091 tree cond = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
4092 TREE_OPERAND (cond, 0) = griddecl;
4093 tree ub = save_expr (TREE_OPERAND (cond, 1));
4094 TREE_OPERAND (cond, 1) = ub;
4095 t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
4096 if (TREE_CODE (cond) == NE_EXPR)
4098 tree_code cond_code = TREE_CODE (cond);
4099 omp_adjust_for_condition (EXPR_LOCATION (for_stmt), &cond_code,
4100 &ub, griddecl, step);
4101 TREE_SET_CODE (cond, cond_code);
4103 step = save_expr (step);
4104 tree gridstep = fold_build2 (MULT_EXPR, TREE_TYPE (step),
4105 step, build_int_cst (TREE_TYPE (step),
4106 size));
4107 if (POINTER_TYPE_P (type))
4108 t = build2 (POINTER_PLUS_EXPR, type, griddecl,
4109 fold_convert (sizetype, gridstep));
4110 else
4111 t = build2 (PLUS_EXPR, type, griddecl, gridstep);
4112 t = build2 (MODIFY_EXPR, type, griddecl, t);
4113 TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t;
4114 t = build2 (MODIFY_EXPR, type, decl, griddecl);
4115 append_to_statement_list (t, &pre_body);
4116 if (POINTER_TYPE_P (type))
4117 t = build2 (POINTER_PLUS_EXPR, type, griddecl,
4118 fold_convert (sizetype, gridstep));
4119 else
4120 t = build2 (PLUS_EXPR, type, griddecl, gridstep);
4121 bool minmax_needed = true;
4122 if (TREE_CODE (iters) == INTEGER_CST)
4124 wide_int witers = wi::to_wide (iters);
4125 wide_int wsize = wide_int::from (size, witers.get_precision (),
4126 TYPE_SIGN (TREE_TYPE (iters)));
4127 if (wi::multiple_of_p (witers, wsize, TYPE_SIGN (TREE_TYPE (iters))))
4128 minmax_needed = false;
4130 if (minmax_needed)
4131 switch (TREE_CODE (cond))
4133 case LE_EXPR:
4134 if (POINTER_TYPE_P (type))
4135 t = build2 (MIN_EXPR, type, t,
4136 build2 (POINTER_PLUS_EXPR, type, ub, size_int (1)));
4137 else
4138 t = build2 (MIN_EXPR, type, t,
4139 build2 (PLUS_EXPR, type, ub, build_one_cst (type)));
4140 break;
4141 case LT_EXPR:
4142 t = build2 (MIN_EXPR, type, t, ub);
4143 break;
4144 case GE_EXPR:
4145 if (POINTER_TYPE_P (type))
4146 t = build2 (MAX_EXPR, type, t,
4147 build2 (POINTER_PLUS_EXPR, type, ub, size_int (-1)));
4148 else
4149 t = build2 (MAX_EXPR, type, t,
4150 build2 (PLUS_EXPR, type, ub,
4151 build_minus_one_cst (type)));
4152 break;
4153 case GT_EXPR:
4154 t = build2 (MAX_EXPR, type, t, ub);
4155 break;
4156 default:
4157 gcc_unreachable ();
4159 tree end = create_tmp_var_raw (type);
4160 DECL_CONTEXT (end) = current_function_decl;
4161 end = build4 (TARGET_EXPR, type, end, t, NULL_TREE, NULL_TREE);
4162 TREE_SIDE_EFFECTS (end) = 1;
4163 append_to_statement_list (end, &pre_body);
4164 tree lab1 = create_artificial_label (UNKNOWN_LOCATION);
4165 tree lab2 = create_artificial_label (UNKNOWN_LOCATION);
4166 t = build1 (GOTO_EXPR, void_type_node, lab2);
4167 append_to_statement_list (t, &pre_body);
4168 t = build1 (LABEL_EXPR, void_type_node, lab1);
4169 append_to_statement_list (t, &pre_body);
4170 tree this_post_body = NULL_TREE;
4171 if (POINTER_TYPE_P (type))
4172 t = build2 (POINTER_PLUS_EXPR, type, decl,
4173 fold_convert (sizetype, step));
4174 else
4175 t = build2 (PLUS_EXPR, type, decl, step);
4176 t = build2 (MODIFY_EXPR, type, decl, t);
4177 append_to_statement_list (t, &this_post_body);
4178 t = build1 (LABEL_EXPR, void_type_node, lab2);
4179 append_to_statement_list (t, &this_post_body);
4180 t = build2 ((TREE_CODE (cond) == LT_EXPR || TREE_CODE (cond) == LE_EXPR)
4181 ? LT_EXPR : GT_EXPR, boolean_type_node, decl, end);
4182 if (orig_sizes == NULL_TREE)
4184 gcc_assert (i == 0);
4185 t = build3 (ANNOTATE_EXPR, TREE_TYPE (t), t,
4186 build_int_cst (integer_type_node,
4187 annot_expr_unroll_kind),
4188 build_int_cst (integer_type_node, size));
4190 t = build3 (COND_EXPR, void_type_node, t,
4191 build1 (GOTO_EXPR, void_type_node, lab1), NULL_TREE);
4192 append_to_statement_list (t, &this_post_body);
4193 append_to_statement_list (post_body, &this_post_body);
4194 post_body = this_post_body;
4196 if (pre_body || post_body)
4198 append_to_statement_list (OMP_FOR_BODY (for_stmt), &pre_body);
4199 append_to_statement_list (post_body, &pre_body);
4200 OMP_FOR_BODY (for_stmt) = pre_body;
4204 /* Callback for walk_tree to find nested loop transforming construct. */
4206 static tree
4207 find_nested_loop_xform (tree *tp, int *walk_subtrees, void *data)
4209 tree **pdata = (tree **) data;
4210 *walk_subtrees = 0;
4211 switch (TREE_CODE (*tp))
4213 case OMP_TILE:
4214 case OMP_UNROLL:
4215 pdata[1] = tp;
4216 return *tp;
4217 case BIND_EXPR:
4218 if (BIND_EXPR_VARS (*tp)
4219 || (BIND_EXPR_BLOCK (*tp)
4220 && BLOCK_VARS (BIND_EXPR_BLOCK (*tp))))
4221 pdata[0] = tp;
4222 *walk_subtrees = 1;
4223 break;
4224 case STATEMENT_LIST:
4225 if (!tsi_one_before_end_p (tsi_start (*tp)))
4226 pdata[0] = tp;
4227 *walk_subtrees = 1;
4228 break;
4229 case TRY_FINALLY_EXPR:
4230 case CLEANUP_POINT_EXPR:
4231 pdata[0] = tp;
4232 *walk_subtrees = 1;
4233 break;
4234 default:
4235 break;
4237 return NULL;
4240 /* Main entry point for performing OpenMP loop transformations. */
4242 void
4243 omp_maybe_apply_loop_xforms (tree *expr_p, tree for_clauses)
4245 tree for_stmt = *expr_p;
4247 switch (TREE_CODE (for_stmt))
4249 case OMP_TILE:
4250 case OMP_UNROLL:
4251 if (OMP_LOOPXFORM_LOWERED (for_stmt))
4252 return;
4253 break;
4254 default:
4255 break;
4258 tree *inner_expr_p = expr_p;
4259 tree inner_for_stmt = for_stmt;
4260 for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
4262 /* If some loop nest needs one or more loops in canonical form
4263 from nested loop transforming constructs, first perform the
4264 loop transformation on the nested construct and then move over
4265 the corresponding loops in canonical form from the inner construct
4266 to the outer one. */
4267 if (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i) == NULL_TREE)
4269 if (inner_for_stmt == for_stmt
4270 && omp_find_clause (for_clauses ? for_clauses
4271 : OMP_FOR_CLAUSES (for_stmt),
4272 OMP_CLAUSE_ORDERED))
4274 error_at (EXPR_LOCATION (for_stmt),
4275 "%<ordered%> clause used with generated loops");
4276 *expr_p = void_node;
4277 return;
4279 tree *data[2] = { NULL, NULL };
4280 walk_tree (&OMP_FOR_BODY (inner_for_stmt),
4281 find_nested_loop_xform, &data, NULL);
4282 gcc_assert (data[1]);
4283 if (data[0])
4285 /* If there is a BIND_EXPR declaring some vars, or statement
4286 list with more than one stmt etc., move the intervening
4287 code around the outermost loop. */
4288 tree t = *inner_expr_p;
4289 *inner_expr_p = OMP_FOR_BODY (inner_for_stmt);
4290 OMP_FOR_BODY (inner_for_stmt) = *data[1];
4291 *data[1] = t;
4292 inner_expr_p = data[1];
4293 data[1] = &OMP_FOR_BODY (inner_for_stmt);
4295 inner_for_stmt = *data[1];
4297 omp_maybe_apply_loop_xforms (data[1], NULL_TREE);
4298 if (*data[1] != inner_for_stmt)
4300 tree *data2[2] = { NULL, NULL };
4301 walk_tree (data[1], find_nested_loop_xform, &data2, NULL);
4302 gcc_assert (data2[1]
4303 && *data2[1] == inner_for_stmt
4304 && data2[0]);
4305 tree t = *inner_expr_p;
4306 *inner_expr_p = *data[1];
4307 *data[1] = *data2[1];
4308 *data2[1] = t;
4309 inner_expr_p = data2[1];
4311 tree clauses = OMP_FOR_CLAUSES (inner_for_stmt);
4312 gcc_checking_assert (TREE_CODE (inner_for_stmt) != OMP_UNROLL
4313 || omp_find_clause (clauses,
4314 OMP_CLAUSE_PARTIAL));
4315 append_to_statement_list (OMP_FOR_PRE_BODY (inner_for_stmt),
4316 &OMP_FOR_PRE_BODY (for_stmt));
4317 OMP_FOR_PRE_BODY (inner_for_stmt) = NULL_TREE;
4318 if (OMP_FOR_ORIG_DECLS (for_stmt) == NULL_TREE
4319 && OMP_FOR_ORIG_DECLS (inner_for_stmt) != NULL_TREE)
4321 OMP_FOR_ORIG_DECLS (for_stmt)
4322 = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)));
4323 for (int j = 0; j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt));
4324 j++)
4326 if (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j) == NULL_TREE)
4327 continue;
4328 gcc_assert (TREE_CODE (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt),
4329 j)) == MODIFY_EXPR);
4330 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), j)
4331 = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j),
4335 for (int j = 0; j < TREE_VEC_LENGTH (OMP_FOR_INIT (inner_for_stmt));
4336 ++j)
4338 if (i + j == TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)))
4339 break;
4340 if (OMP_FOR_ORIG_DECLS (for_stmt))
4342 if (OMP_FOR_ORIG_DECLS (inner_for_stmt))
4344 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i + j)
4345 = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt),
4347 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), j)
4348 = NULL_TREE;
4350 else
4352 tree t = TREE_VEC_ELT (OMP_FOR_INIT (inner_for_stmt), j);
4353 gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
4354 TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i + j)
4355 = TREE_OPERAND (t, 0);
4358 TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i + j)
4359 = TREE_VEC_ELT (OMP_FOR_INIT (inner_for_stmt), j);
4360 TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i + j)
4361 = TREE_VEC_ELT (OMP_FOR_COND (inner_for_stmt), j);
4362 TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i + j)
4363 = TREE_VEC_ELT (OMP_FOR_INCR (inner_for_stmt), j);
4364 TREE_VEC_ELT (OMP_FOR_INIT (inner_for_stmt), j) = NULL_TREE;
4365 TREE_VEC_ELT (OMP_FOR_COND (inner_for_stmt), j) = NULL_TREE;
4366 TREE_VEC_ELT (OMP_FOR_INCR (inner_for_stmt), j) = NULL_TREE;
4371 switch (TREE_CODE (for_stmt))
4373 case OMP_TILE:
4374 tree sizes;
4375 sizes = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_SIZES);
4376 omp_apply_tile (for_stmt, OMP_CLAUSE_SIZES_LIST (sizes), 0);
4377 OMP_LOOPXFORM_LOWERED (for_stmt) = 1;
4378 break;
4379 case OMP_UNROLL:
4380 tree partial;
4381 partial = omp_find_clause (OMP_FOR_CLAUSES (for_stmt),
4382 OMP_CLAUSE_PARTIAL);
4383 if (partial)
4384 omp_apply_tile (for_stmt, NULL_TREE,
4385 OMP_CLAUSE_PARTIAL_EXPR (partial)
4386 ? tree_to_shwi (OMP_CLAUSE_PARTIAL_EXPR (partial))
4387 : 8);
4388 else if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_FULL))
4390 tree iters = omp_loop_number_of_iterations (for_stmt, 0, NULL);
4391 if (TREE_CODE (iters) != INTEGER_CST)
4392 error_at (EXPR_LOCATION (for_stmt),
4393 "non-constant iteration count of %<unroll full%> loop");
4395 OMP_LOOPXFORM_LOWERED (for_stmt) = 1;
4396 break;
4397 default:
4398 break;
4402 #include "gt-omp-general.h"