Branch data Line data Source code
1 : : /* General types and functions that are useful for processing of OpenMP,
2 : : OpenACC and similar directives at various stages of compilation.
3 : :
4 : : Copyright (C) 2005-2025 Free Software Foundation, Inc.
5 : :
6 : : This file is part of GCC.
7 : :
8 : : GCC is free software; you can redistribute it and/or modify it under
9 : : the terms of the GNU General Public License as published by the Free
10 : : Software Foundation; either version 3, or (at your option) any later
11 : : version.
12 : :
13 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 : : for more details.
17 : :
18 : : You should have received a copy of the GNU General Public License
19 : : along with GCC; see the file COPYING3. If not see
20 : : <http://www.gnu.org/licenses/>. */
21 : :
22 : : #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"
47 : :
48 : : enum omp_requires omp_requires_mask;
49 : :
50 : : /* Find an OMP clause of type KIND within CLAUSES. */
51 : : tree
52 : 1201688 : omp_find_clause (tree clauses, enum omp_clause_code kind)
53 : : {
54 : 4406387 : for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
55 : 3458227 : if (OMP_CLAUSE_CODE (clauses) == kind)
56 : : return clauses;
57 : :
58 : : return NULL_TREE;
59 : : }
60 : :
61 : : /* True if OpenMP should regard this DECL as being a scalar which has Fortran's
62 : : allocatable or pointer attribute. */
63 : : bool
64 : 15379 : omp_is_allocatable_or_ptr (tree decl)
65 : : {
66 : 15379 : return lang_hooks.decls.omp_is_allocatable_or_ptr (decl);
67 : : }
68 : :
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. */
76 : :
77 : : tree
78 : 13225 : omp_check_optional_argument (tree decl, bool for_present_check)
79 : : {
80 : 13225 : return lang_hooks.decls.omp_check_optional_argument (decl, for_present_check);
81 : : }
82 : :
83 : : /* Return true if TYPE is an OpenMP mappable type. */
84 : :
85 : : bool
86 : 45547 : omp_mappable_type (tree type)
87 : : {
88 : : /* Mappable type has to be complete. */
89 : 45547 : if (type == error_mark_node || !COMPLETE_TYPE_P (type))
90 : 188 : return false;
91 : : return true;
92 : : }
93 : :
94 : : /* True if OpenMP should privatize what this DECL points to rather
95 : : than the DECL itself. */
96 : :
97 : : bool
98 : 4930810 : omp_privatize_by_reference (tree decl)
99 : : {
100 : 4930810 : return lang_hooks.decls.omp_privatize_by_reference (decl);
101 : : }
102 : :
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. */
105 : :
106 : : void
107 : 196328 : omp_adjust_for_condition (location_t loc, enum tree_code *cond_code, tree *n2,
108 : : tree v, tree step)
109 : : {
110 : 196328 : switch (*cond_code)
111 : : {
112 : : case LT_EXPR:
113 : : case GT_EXPR:
114 : : break;
115 : :
116 : 29865 : case NE_EXPR:
117 : 29865 : gcc_assert (TREE_CODE (step) == INTEGER_CST);
118 : 29865 : if (TREE_CODE (TREE_TYPE (v)) == INTEGER_TYPE
119 : 29865 : || TREE_CODE (TREE_TYPE (v)) == BITINT_TYPE)
120 : : {
121 : 25021 : if (integer_onep (step))
122 : 17737 : *cond_code = LT_EXPR;
123 : : else
124 : : {
125 : 7284 : gcc_assert (integer_minus_onep (step));
126 : 7284 : *cond_code = GT_EXPR;
127 : : }
128 : : }
129 : : else
130 : : {
131 : 4844 : tree unit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v)));
132 : 4844 : gcc_assert (TREE_CODE (unit) == INTEGER_CST);
133 : 4844 : if (tree_int_cst_equal (unit, step))
134 : 3358 : *cond_code = LT_EXPR;
135 : : else
136 : : {
137 : 1486 : gcc_assert (wi::neg (wi::to_widest (unit))
138 : : == wi::to_widest (step));
139 : 1486 : *cond_code = GT_EXPR;
140 : : }
141 : : }
142 : :
143 : : break;
144 : :
145 : 28460 : case LE_EXPR:
146 : 28460 : if (POINTER_TYPE_P (TREE_TYPE (*n2)))
147 : : {
148 : 123 : tree unit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v)));
149 : 123 : gcc_assert (TREE_CODE (unit) == INTEGER_CST);
150 : 123 : *n2 = fold_build_pointer_plus_loc (loc, *n2, unit);
151 : : }
152 : : else
153 : 28337 : *n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (*n2), *n2,
154 : 28337 : build_int_cst (TREE_TYPE (*n2), 1));
155 : 28460 : *cond_code = LT_EXPR;
156 : 28460 : break;
157 : 1808 : case GE_EXPR:
158 : 1808 : if (POINTER_TYPE_P (TREE_TYPE (*n2)))
159 : : {
160 : 137 : tree unit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v)));
161 : 137 : gcc_assert (TREE_CODE (unit) == INTEGER_CST);
162 : 137 : unit = convert_to_ptrofftype_loc (loc, unit);
163 : 137 : unit = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (unit),
164 : : unit);
165 : 137 : *n2 = fold_build_pointer_plus_loc (loc, *n2, unit);
166 : : }
167 : : else
168 : 1671 : *n2 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (*n2), *n2,
169 : 1671 : build_int_cst (TREE_TYPE (*n2), 1));
170 : 1808 : *cond_code = GT_EXPR;
171 : 1808 : break;
172 : 0 : default:
173 : 0 : gcc_unreachable ();
174 : : }
175 : 196328 : }
176 : :
177 : : /* Return the looping step from INCR, extracted from the step of a gimple omp
178 : : for statement. */
179 : :
180 : : tree
181 : 195164 : omp_get_for_step_from_incr (location_t loc, tree incr)
182 : : {
183 : 195164 : tree step;
184 : 195164 : switch (TREE_CODE (incr))
185 : : {
186 : 172933 : case PLUS_EXPR:
187 : 172933 : step = TREE_OPERAND (incr, 1);
188 : 172933 : break;
189 : 16136 : case POINTER_PLUS_EXPR:
190 : 16136 : step = fold_convert (ssizetype, TREE_OPERAND (incr, 1));
191 : 16136 : break;
192 : 6095 : case MINUS_EXPR:
193 : 6095 : step = TREE_OPERAND (incr, 1);
194 : 6095 : step = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (step), step);
195 : 6095 : break;
196 : 0 : default:
197 : 0 : gcc_unreachable ();
198 : : }
199 : 195164 : return step;
200 : : }
201 : :
202 : : /* Extract the header elements of parallel loop FOR_STMT and store
203 : : them into *FD. */
204 : :
205 : : void
206 : 129249 : omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
207 : : struct omp_for_data_loop *loops)
208 : : {
209 : 129249 : tree t, var, *collapse_iter, *collapse_count;
210 : 129249 : tree count = NULL_TREE, iter_type = long_integer_type_node;
211 : 129249 : struct omp_for_data_loop *loop;
212 : 129249 : int i;
213 : 129249 : struct omp_for_data_loop dummy_loop;
214 : 129249 : location_t loc = gimple_location (for_stmt);
215 : 129249 : bool simd = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD;
216 : 129249 : bool distribute = gimple_omp_for_kind (for_stmt)
217 : 129249 : == GF_OMP_FOR_KIND_DISTRIBUTE;
218 : 129249 : bool taskloop = gimple_omp_for_kind (for_stmt)
219 : 129249 : == GF_OMP_FOR_KIND_TASKLOOP;
220 : 129249 : bool order_reproducible = false;
221 : 129249 : tree iterv, countv;
222 : :
223 : 129249 : fd->for_stmt = for_stmt;
224 : 129249 : fd->pre = NULL;
225 : 129249 : fd->have_nowait = distribute || simd;
226 : 129249 : fd->have_ordered = false;
227 : 129249 : fd->have_reductemp = false;
228 : 129249 : fd->have_pointer_condtemp = false;
229 : 129249 : fd->have_scantemp = false;
230 : 129249 : fd->have_nonctrl_scantemp = false;
231 : 129249 : fd->non_rect = false;
232 : 129249 : fd->lastprivate_conditional = 0;
233 : 129249 : fd->tiling = NULL_TREE;
234 : 129249 : fd->collapse = 1;
235 : 129249 : fd->ordered = 0;
236 : 129249 : fd->first_nonrect = -1;
237 : 129249 : fd->last_nonrect = -1;
238 : 129249 : fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
239 : 129249 : fd->sched_modifiers = 0;
240 : 129249 : fd->chunk_size = NULL_TREE;
241 : 129249 : fd->simd_schedule = false;
242 : 129249 : fd->first_inner_iterations = NULL_TREE;
243 : 129249 : fd->factor = NULL_TREE;
244 : 129249 : fd->adjn1 = NULL_TREE;
245 : 129249 : collapse_iter = NULL;
246 : 129249 : collapse_count = NULL;
247 : :
248 : 647648 : for (t = gimple_omp_for_clauses (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t))
249 : 518399 : switch (OMP_CLAUSE_CODE (t))
250 : : {
251 : 45029 : case OMP_CLAUSE_NOWAIT:
252 : 45029 : fd->have_nowait = true;
253 : 45029 : break;
254 : 1389 : case OMP_CLAUSE_ORDERED:
255 : 1389 : fd->have_ordered = true;
256 : 1389 : if (OMP_CLAUSE_ORDERED_DOACROSS (t))
257 : : {
258 : 692 : if (OMP_CLAUSE_ORDERED_EXPR (t))
259 : 672 : fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t));
260 : : else
261 : 20 : fd->ordered = -1;
262 : : }
263 : : break;
264 : 30436 : case OMP_CLAUSE_SCHEDULE:
265 : 30436 : gcc_assert (!distribute && !taskloop);
266 : 30436 : fd->sched_kind
267 : 30436 : = (enum omp_clause_schedule_kind)
268 : 30436 : (OMP_CLAUSE_SCHEDULE_KIND (t) & OMP_CLAUSE_SCHEDULE_MASK);
269 : 30436 : fd->sched_modifiers = (OMP_CLAUSE_SCHEDULE_KIND (t)
270 : 30436 : & ~OMP_CLAUSE_SCHEDULE_MASK);
271 : 30436 : fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
272 : 30436 : fd->simd_schedule = OMP_CLAUSE_SCHEDULE_SIMD (t);
273 : 30436 : break;
274 : 7004 : case OMP_CLAUSE_DIST_SCHEDULE:
275 : 7004 : gcc_assert (distribute);
276 : 7004 : fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t);
277 : 7004 : break;
278 : 41345 : case OMP_CLAUSE_COLLAPSE:
279 : 41345 : fd->collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t));
280 : 41345 : if (fd->collapse > 1)
281 : : {
282 : 33780 : collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t);
283 : 33780 : collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t);
284 : : }
285 : : break;
286 : 354 : case OMP_CLAUSE_TILE:
287 : 354 : fd->tiling = OMP_CLAUSE_TILE_LIST (t);
288 : 354 : fd->collapse = list_length (fd->tiling);
289 : 354 : gcc_assert (fd->collapse);
290 : 354 : collapse_iter = &OMP_CLAUSE_TILE_ITERVAR (t);
291 : 354 : collapse_count = &OMP_CLAUSE_TILE_COUNT (t);
292 : 354 : break;
293 : 482 : case OMP_CLAUSE__REDUCTEMP_:
294 : 482 : fd->have_reductemp = true;
295 : 482 : break;
296 : 40594 : case OMP_CLAUSE_LASTPRIVATE:
297 : 40594 : if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (t))
298 : 1504 : fd->lastprivate_conditional++;
299 : : break;
300 : 1556 : case OMP_CLAUSE__CONDTEMP_:
301 : 1556 : if (POINTER_TYPE_P (TREE_TYPE (OMP_CLAUSE_DECL (t))))
302 : 185 : fd->have_pointer_condtemp = true;
303 : : break;
304 : 1102 : case OMP_CLAUSE__SCANTEMP_:
305 : 1102 : fd->have_scantemp = true;
306 : 1102 : if (!OMP_CLAUSE__SCANTEMP__ALLOC (t)
307 : 1102 : && !OMP_CLAUSE__SCANTEMP__CONTROL (t))
308 : 205 : fd->have_nonctrl_scantemp = true;
309 : : break;
310 : 7688 : 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 : 7688 : if (!OMP_CLAUSE_ORDER_UNCONSTRAINED (t))
316 : 518399 : order_reproducible = true;
317 : : default:
318 : : break;
319 : : }
320 : :
321 : 129249 : if (fd->ordered == -1)
322 : 20 : fd->ordered = fd->collapse;
323 : :
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 : 129249 : if (order_reproducible)
331 : 7393 : fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
332 : 129249 : if (fd->collapse > 1 || fd->tiling)
333 : 34130 : fd->loops = loops;
334 : : else
335 : 95119 : fd->loops = &fd->loop;
336 : :
337 : 129249 : if (fd->ordered && fd->collapse == 1 && loops != NULL)
338 : : {
339 : 184 : fd->loops = loops;
340 : 184 : iterv = NULL_TREE;
341 : 184 : countv = NULL_TREE;
342 : 184 : collapse_iter = &iterv;
343 : 184 : collapse_count = &countv;
344 : : }
345 : :
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 : 129249 : if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO)
351 : : {
352 : 5747 : fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
353 : 5747 : gcc_assert (fd->chunk_size == NULL);
354 : : }
355 : 129249 : gcc_assert ((fd->collapse == 1 && !fd->tiling) || collapse_iter != NULL);
356 : 129249 : if (taskloop)
357 : 9638 : fd->sched_kind = OMP_CLAUSE_SCHEDULE_RUNTIME;
358 : 129249 : if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
359 : 16639 : gcc_assert (fd->chunk_size == NULL);
360 : 112610 : else if (fd->chunk_size == NULL)
361 : : {
362 : : /* We only need to compute a default chunk size for ordered
363 : : static loops and dynamic loops. */
364 : 89541 : if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
365 : 88947 : || fd->have_ordered)
366 : 1305 : fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
367 : 1305 : ? integer_zero_node : integer_one_node;
368 : : }
369 : :
370 : 129249 : int cnt = fd->ordered ? fd->ordered : fd->collapse;
371 : 129249 : int single_nonrect = -1;
372 : 129249 : tree single_nonrect_count = NULL_TREE;
373 : 129249 : enum tree_code single_nonrect_cond_code = ERROR_MARK;
374 : 193306 : for (i = 1; i < cnt; i++)
375 : : {
376 : 64185 : tree n1 = gimple_omp_for_initial (for_stmt, i);
377 : 64185 : tree n2 = gimple_omp_for_final (for_stmt, i);
378 : 64185 : if (TREE_CODE (n1) == TREE_VEC)
379 : : {
380 : 1786 : if (fd->non_rect)
381 : : {
382 : : single_nonrect = -1;
383 : : break;
384 : : }
385 : 2152 : for (int j = i - 1; j >= 0; j--)
386 : 2152 : if (TREE_VEC_ELT (n1, 0) == gimple_omp_for_index (for_stmt, j))
387 : : {
388 : : single_nonrect = j;
389 : : break;
390 : : }
391 : 1664 : fd->non_rect = true;
392 : : }
393 : 62399 : else if (TREE_CODE (n2) == TREE_VEC)
394 : : {
395 : 531 : if (fd->non_rect)
396 : : {
397 : : single_nonrect = -1;
398 : : break;
399 : : }
400 : 681 : for (int j = i - 1; j >= 0; j--)
401 : 681 : if (TREE_VEC_ELT (n2, 0) == gimple_omp_for_index (for_stmt, j))
402 : : {
403 : : single_nonrect = j;
404 : : break;
405 : : }
406 : 525 : fd->non_rect = true;
407 : : }
408 : : }
409 : 322767 : for (i = 0; i < cnt; i++)
410 : : {
411 : 193518 : if (i == 0
412 : 129249 : && fd->collapse == 1
413 : 95291 : && !fd->tiling
414 : 95119 : && (fd->ordered == 0 || loops == NULL))
415 : 94935 : loop = &fd->loop;
416 : 98399 : else if (loops != NULL)
417 : 32686 : loop = loops + i;
418 : : else
419 : : loop = &dummy_loop;
420 : :
421 : 193518 : loop->v = gimple_omp_for_index (for_stmt, i);
422 : 193518 : gcc_assert (SSA_VAR_P (loop->v));
423 : 193518 : 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 : 193518 : var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
427 : 193518 : loop->n1 = gimple_omp_for_initial (for_stmt, i);
428 : 193518 : loop->m1 = NULL_TREE;
429 : 193518 : loop->m2 = NULL_TREE;
430 : 193518 : loop->outer = 0;
431 : 193518 : loop->non_rect_referenced = false;
432 : 193518 : if (TREE_CODE (loop->n1) == TREE_VEC)
433 : : {
434 : 2313 : for (int j = i - 1; j >= 0; j--)
435 : 2313 : if (TREE_VEC_ELT (loop->n1, 0) == gimple_omp_for_index (for_stmt, j))
436 : : {
437 : 1786 : loop->outer = i - j;
438 : 1786 : if (loops != NULL)
439 : 639 : loops[j].non_rect_referenced = true;
440 : 1786 : if (fd->first_nonrect == -1 || fd->first_nonrect > j)
441 : 1664 : fd->first_nonrect = j;
442 : : break;
443 : : }
444 : 1786 : gcc_assert (loop->outer);
445 : 1786 : loop->m1 = TREE_VEC_ELT (loop->n1, 1);
446 : 1786 : loop->n1 = TREE_VEC_ELT (loop->n1, 2);
447 : 1786 : fd->non_rect = true;
448 : 1786 : fd->last_nonrect = i;
449 : : }
450 : :
451 : 193518 : loop->cond_code = gimple_omp_for_cond (for_stmt, i);
452 : 193518 : loop->n2 = gimple_omp_for_final (for_stmt, i);
453 : 193518 : gcc_assert (loop->cond_code != NE_EXPR
454 : : || (gimple_omp_for_kind (for_stmt)
455 : : != GF_OMP_FOR_KIND_OACC_LOOP));
456 : 193518 : if (TREE_CODE (loop->n2) == TREE_VEC)
457 : : {
458 : 1273 : if (loop->outer)
459 : 742 : gcc_assert (TREE_VEC_ELT (loop->n2, 0)
460 : : == gimple_omp_for_index (for_stmt, i - loop->outer));
461 : : else
462 : 690 : for (int j = i - 1; j >= 0; j--)
463 : 690 : if (TREE_VEC_ELT (loop->n2, 0) == gimple_omp_for_index (for_stmt, j))
464 : : {
465 : 531 : loop->outer = i - j;
466 : 531 : if (loops != NULL)
467 : 241 : loops[j].non_rect_referenced = true;
468 : 531 : if (fd->first_nonrect == -1 || fd->first_nonrect > j)
469 : 525 : fd->first_nonrect = j;
470 : : break;
471 : : }
472 : 1273 : gcc_assert (loop->outer);
473 : 1273 : loop->m2 = TREE_VEC_ELT (loop->n2, 1);
474 : 1273 : loop->n2 = TREE_VEC_ELT (loop->n2, 2);
475 : 1273 : fd->non_rect = true;
476 : 1273 : fd->last_nonrect = i;
477 : : }
478 : :
479 : 193518 : t = gimple_omp_for_incr (for_stmt, i);
480 : 193518 : gcc_assert (TREE_OPERAND (t, 0) == var);
481 : 193518 : loop->step = omp_get_for_step_from_incr (loc, t);
482 : :
483 : 193518 : omp_adjust_for_condition (loc, &loop->cond_code, &loop->n2, loop->v,
484 : : loop->step);
485 : :
486 : 193518 : if (simd
487 : 153689 : || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
488 : 114189 : && !fd->have_ordered))
489 : : {
490 : 152307 : if (fd->collapse == 1 && !fd->tiling)
491 : 77273 : iter_type = TREE_TYPE (loop->v);
492 : 75034 : else if (i == 0
493 : 75034 : || TYPE_PRECISION (iter_type)
494 : 48425 : < TYPE_PRECISION (TREE_TYPE (loop->v)))
495 : : {
496 : 37486 : if (TREE_CODE (iter_type) == BITINT_TYPE
497 : 37486 : || TREE_CODE (TREE_TYPE (loop->v)) == BITINT_TYPE)
498 : 2 : iter_type
499 : 2 : = build_bitint_type (TYPE_PRECISION (TREE_TYPE (loop->v)),
500 : : 1);
501 : : else
502 : 37484 : iter_type
503 : : = build_nonstandard_integer_type
504 : 37484 : (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
505 : : }
506 : : }
507 : 41211 : else if (iter_type != long_long_unsigned_type_node)
508 : : {
509 : 37751 : if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
510 : : iter_type = long_long_unsigned_type_node;
511 : 35789 : else if (TYPE_UNSIGNED (TREE_TYPE (loop->v))
512 : 35789 : && TYPE_PRECISION (TREE_TYPE (loop->v))
513 : 6285 : >= TYPE_PRECISION (iter_type))
514 : : {
515 : 2319 : tree n;
516 : :
517 : 2319 : if (loop->cond_code == LT_EXPR)
518 : 451 : n = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v),
519 : : loop->n2, loop->step);
520 : : else
521 : 1868 : n = loop->n1;
522 : 2319 : if (loop->m1
523 : 2319 : || loop->m2
524 : 2319 : || TREE_CODE (n) != INTEGER_CST
525 : 4284 : || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n))
526 : 2242 : iter_type = long_long_unsigned_type_node;
527 : : }
528 : 33470 : else if (TYPE_PRECISION (TREE_TYPE (loop->v))
529 : 33470 : > TYPE_PRECISION (iter_type))
530 : : {
531 : 0 : tree n1, n2;
532 : :
533 : 0 : if (loop->cond_code == LT_EXPR)
534 : : {
535 : 0 : n1 = loop->n1;
536 : 0 : n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v),
537 : : loop->n2, loop->step);
538 : : }
539 : : else
540 : : {
541 : 0 : n1 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (loop->v),
542 : : loop->n2, loop->step);
543 : 0 : n2 = loop->n1;
544 : : }
545 : 0 : if (loop->m1
546 : 0 : || loop->m2
547 : 0 : || TREE_CODE (n1) != INTEGER_CST
548 : 0 : || TREE_CODE (n2) != INTEGER_CST
549 : 0 : || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1)
550 : 0 : || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type)))
551 : 0 : iter_type = long_long_unsigned_type_node;
552 : : }
553 : : }
554 : :
555 : 193518 : if (i >= fd->collapse)
556 : 1802 : continue;
557 : :
558 : 191716 : if (collapse_count && *collapse_count == NULL)
559 : : {
560 : 31861 : if (count && integer_zerop (count))
561 : 2240 : continue;
562 : 29621 : tree n1first = NULL_TREE, n2first = NULL_TREE;
563 : 29621 : tree n1last = NULL_TREE, n2last = NULL_TREE;
564 : 29621 : tree ostep = NULL_TREE;
565 : 29621 : if (loop->m1 || loop->m2)
566 : : {
567 : 911 : if (count == NULL_TREE)
568 : 645 : continue;
569 : 266 : if (single_nonrect == -1
570 : 247 : || (loop->m1 && TREE_CODE (loop->m1) != INTEGER_CST)
571 : 206 : || (loop->m2 && TREE_CODE (loop->m2) != INTEGER_CST)
572 : 190 : || TREE_CODE (loop->n1) != INTEGER_CST
573 : 186 : || TREE_CODE (loop->n2) != INTEGER_CST
574 : 182 : || TREE_CODE (loop->step) != INTEGER_CST)
575 : : {
576 : 84 : count = NULL_TREE;
577 : 84 : continue;
578 : : }
579 : 182 : tree var = gimple_omp_for_initial (for_stmt, single_nonrect);
580 : 182 : tree itype = TREE_TYPE (var);
581 : 182 : tree first = gimple_omp_for_initial (for_stmt, single_nonrect);
582 : 182 : t = gimple_omp_for_incr (for_stmt, single_nonrect);
583 : 182 : ostep = omp_get_for_step_from_incr (loc, t);
584 : 182 : t = fold_binary (MINUS_EXPR, long_long_unsigned_type_node,
585 : : single_nonrect_count,
586 : : build_one_cst (long_long_unsigned_type_node));
587 : 182 : t = fold_convert (itype, t);
588 : 182 : first = fold_convert (itype, first);
589 : 182 : ostep = fold_convert (itype, ostep);
590 : 182 : tree last = fold_binary (PLUS_EXPR, itype, first,
591 : : fold_binary (MULT_EXPR, itype, t,
592 : : ostep));
593 : 182 : if (TREE_CODE (first) != INTEGER_CST
594 : 182 : || TREE_CODE (last) != INTEGER_CST)
595 : : {
596 : 0 : count = NULL_TREE;
597 : 0 : continue;
598 : : }
599 : 182 : if (loop->m1)
600 : : {
601 : 115 : tree m1 = fold_convert (itype, loop->m1);
602 : 115 : tree n1 = fold_convert (itype, loop->n1);
603 : 115 : n1first = fold_binary (PLUS_EXPR, itype,
604 : : fold_binary (MULT_EXPR, itype,
605 : : first, m1), n1);
606 : 115 : n1last = fold_binary (PLUS_EXPR, itype,
607 : : fold_binary (MULT_EXPR, itype,
608 : : last, m1), n1);
609 : : }
610 : : else
611 : 67 : n1first = n1last = loop->n1;
612 : 182 : if (loop->m2)
613 : : {
614 : 136 : tree n2 = fold_convert (itype, loop->n2);
615 : 136 : tree m2 = fold_convert (itype, loop->m2);
616 : 136 : n2first = fold_binary (PLUS_EXPR, itype,
617 : : fold_binary (MULT_EXPR, itype,
618 : : first, m2), n2);
619 : 136 : n2last = fold_binary (PLUS_EXPR, itype,
620 : : fold_binary (MULT_EXPR, itype,
621 : : last, m2), n2);
622 : : }
623 : : else
624 : 46 : n2first = n2last = loop->n2;
625 : 182 : n1first = fold_convert (TREE_TYPE (loop->v), n1first);
626 : 182 : n2first = fold_convert (TREE_TYPE (loop->v), n2first);
627 : 182 : n1last = fold_convert (TREE_TYPE (loop->v), n1last);
628 : 182 : n2last = fold_convert (TREE_TYPE (loop->v), n2last);
629 : 182 : t = fold_binary (loop->cond_code, boolean_type_node,
630 : : n1first, n2first);
631 : 182 : tree t2 = fold_binary (loop->cond_code, boolean_type_node,
632 : : n1last, n2last);
633 : 182 : 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 : 103 : 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 : 95 : else if (TYPE_UNSIGNED (itype)
641 : 95 : || t == NULL_TREE
642 : 95 : || t2 == NULL_TREE
643 : 95 : || TREE_CODE (t) != INTEGER_CST
644 : 190 : || TREE_CODE (t2) != INTEGER_CST)
645 : : {
646 : : /* Punt (for now). */
647 : 0 : count = NULL_TREE;
648 : 0 : continue;
649 : : }
650 : : else
651 : : {
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 : 95 : bool adj_first = integer_zerop (t);
658 : 95 : tree n1 = fold_convert (itype, loop->n1);
659 : 95 : tree n2 = fold_convert (itype, loop->n2);
660 : 95 : tree m1 = loop->m1 ? fold_convert (itype, loop->m1)
661 : 25 : : build_zero_cst (itype);
662 : 95 : tree m2 = loop->m2 ? fold_convert (itype, loop->m2)
663 : 11 : : build_zero_cst (itype);
664 : 95 : t = fold_binary (MINUS_EXPR, itype, n1, n2);
665 : 95 : t2 = fold_binary (MINUS_EXPR, itype, m2, m1);
666 : 95 : t = fold_binary (TRUNC_DIV_EXPR, itype, t, t2);
667 : 95 : t2 = fold_binary (MINUS_EXPR, itype, t, first);
668 : 95 : t2 = fold_binary (TRUNC_MOD_EXPR, itype, t2, ostep);
669 : 95 : t = fold_binary (MINUS_EXPR, itype, t, t2);
670 : 95 : tree n1cur
671 : 95 : = fold_binary (PLUS_EXPR, itype, n1,
672 : : fold_binary (MULT_EXPR, itype, m1, t));
673 : 95 : tree n2cur
674 : 95 : = fold_binary (PLUS_EXPR, itype, n2,
675 : : fold_binary (MULT_EXPR, itype, m2, t));
676 : 95 : t2 = fold_binary (loop->cond_code, boolean_type_node,
677 : : n1cur, n2cur);
678 : 95 : tree t3 = fold_binary (MULT_EXPR, itype, m1, ostep);
679 : 95 : tree t4 = fold_binary (MULT_EXPR, itype, m2, ostep);
680 : 95 : tree diff;
681 : 95 : if (adj_first)
682 : : {
683 : 67 : tree new_first;
684 : 67 : if (integer_nonzerop (t2))
685 : : {
686 : 6 : new_first = t;
687 : 6 : n1first = n1cur;
688 : 6 : n2first = n2cur;
689 : 6 : if (flag_checking)
690 : : {
691 : 6 : t3 = fold_binary (MINUS_EXPR, itype, n1cur, t3);
692 : 6 : t4 = fold_binary (MINUS_EXPR, itype, n2cur, t4);
693 : 6 : t3 = fold_binary (loop->cond_code,
694 : : boolean_type_node, t3, t4);
695 : 6 : gcc_assert (integer_zerop (t3));
696 : : }
697 : : }
698 : : else
699 : : {
700 : 61 : t3 = fold_binary (PLUS_EXPR, itype, n1cur, t3);
701 : 61 : t4 = fold_binary (PLUS_EXPR, itype, n2cur, t4);
702 : 61 : new_first = fold_binary (PLUS_EXPR, itype, t, ostep);
703 : 61 : n1first = t3;
704 : 61 : n2first = t4;
705 : 61 : if (flag_checking)
706 : : {
707 : 61 : t3 = fold_binary (loop->cond_code,
708 : : boolean_type_node, t3, t4);
709 : 61 : gcc_assert (integer_nonzerop (t3));
710 : : }
711 : : }
712 : 67 : diff = fold_binary (MINUS_EXPR, itype, new_first, first);
713 : 67 : first = new_first;
714 : 67 : fd->adjn1 = first;
715 : : }
716 : : else
717 : : {
718 : 28 : tree new_last;
719 : 28 : if (integer_zerop (t2))
720 : : {
721 : 11 : t3 = fold_binary (MINUS_EXPR, itype, n1cur, t3);
722 : 11 : t4 = fold_binary (MINUS_EXPR, itype, n2cur, t4);
723 : 11 : new_last = fold_binary (MINUS_EXPR, itype, t, ostep);
724 : 11 : n1last = t3;
725 : 11 : n2last = t4;
726 : 11 : if (flag_checking)
727 : : {
728 : 11 : t3 = fold_binary (loop->cond_code,
729 : : boolean_type_node, t3, t4);
730 : 11 : gcc_assert (integer_nonzerop (t3));
731 : : }
732 : : }
733 : : else
734 : : {
735 : 17 : new_last = t;
736 : 17 : n1last = n1cur;
737 : 17 : n2last = n2cur;
738 : 17 : if (flag_checking)
739 : : {
740 : 17 : t3 = fold_binary (PLUS_EXPR, itype, n1cur, t3);
741 : 17 : t4 = fold_binary (PLUS_EXPR, itype, n2cur, t4);
742 : 17 : t3 = fold_binary (loop->cond_code,
743 : : boolean_type_node, t3, t4);
744 : 17 : gcc_assert (integer_zerop (t3));
745 : : }
746 : : }
747 : 28 : diff = fold_binary (MINUS_EXPR, itype, last, new_last);
748 : : }
749 : 95 : if (TYPE_UNSIGNED (itype)
750 : 95 : && single_nonrect_cond_code == GT_EXPR)
751 : 0 : 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 : 95 : diff = fold_binary (TRUNC_DIV_EXPR, itype, diff, ostep);
757 : 95 : diff = fold_convert (long_long_unsigned_type_node, diff);
758 : 95 : single_nonrect_count
759 : 95 : = fold_binary (MINUS_EXPR, long_long_unsigned_type_node,
760 : : single_nonrect_count, diff);
761 : 95 : t = NULL_TREE;
762 : : }
763 : : }
764 : : else
765 : 28710 : 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 : 28813 : if (t && integer_zerop (t))
769 : 2248 : count = build_zero_cst (long_long_unsigned_type_node);
770 : 26644 : else if ((i == 0 || count != NULL_TREE)
771 : 16949 : && (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
772 : 1202 : || TREE_CODE (TREE_TYPE (loop->v)) == BITINT_TYPE)
773 : 15748 : && TREE_CONSTANT (loop->n1)
774 : 11747 : && TREE_CONSTANT (loop->n2)
775 : 37400 : && TREE_CODE (loop->step) == INTEGER_CST)
776 : : {
777 : 10734 : tree itype = TREE_TYPE (loop->v);
778 : :
779 : 10734 : if (POINTER_TYPE_P (itype))
780 : 0 : itype = signed_type_for (itype);
781 : 13102 : t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1));
782 : 10734 : t = fold_build2 (PLUS_EXPR, itype,
783 : : fold_convert (itype, loop->step), t);
784 : 10734 : tree n1 = loop->n1;
785 : 10734 : tree n2 = loop->n2;
786 : 10734 : if (loop->m1 || loop->m2)
787 : : {
788 : 174 : gcc_assert (single_nonrect != -1);
789 : : n1 = n1first;
790 : : n2 = n2first;
791 : : }
792 : 10734 : t = fold_build2 (PLUS_EXPR, itype, t, fold_convert (itype, n2));
793 : 10734 : t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1));
794 : 10734 : tree step = fold_convert_loc (loc, itype, loop->step);
795 : 10734 : if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
796 : 2254 : t = fold_build2 (TRUNC_DIV_EXPR, itype,
797 : : fold_build1 (NEGATE_EXPR, itype, t),
798 : : fold_build1 (NEGATE_EXPR, itype, step));
799 : : else
800 : 8480 : t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step);
801 : 10734 : tree llutype = long_long_unsigned_type_node;
802 : 10734 : t = fold_convert (llutype, t);
803 : 10734 : if (loop->m1 || loop->m2)
804 : : {
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)
811 : : */
812 : 174 : tree m1 = loop->m1 ? loop->m1 : integer_zero_node;
813 : 174 : tree m2 = loop->m2 ? loop->m2 : integer_zero_node;
814 : 174 : m1 = fold_convert (itype, m1);
815 : 174 : m2 = fold_convert (itype, m2);
816 : 174 : tree t2 = fold_build2 (MINUS_EXPR, itype, m2, m1);
817 : 174 : t2 = fold_build2 (MULT_EXPR, itype, t2, ostep);
818 : 174 : if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
819 : 0 : t2 = fold_build2 (TRUNC_DIV_EXPR, itype,
820 : : fold_build1 (NEGATE_EXPR, itype, t2),
821 : : fold_build1 (NEGATE_EXPR, itype, step));
822 : : else
823 : 174 : t2 = fold_build2 (TRUNC_DIV_EXPR, itype, t2, step);
824 : 174 : t2 = fold_convert (llutype, t2);
825 : 174 : fd->first_inner_iterations = t;
826 : 174 : fd->factor = t2;
827 : 174 : t = fold_build2 (MULT_EXPR, llutype, t,
828 : : single_nonrect_count);
829 : 174 : tree t3 = fold_build2 (MINUS_EXPR, llutype,
830 : : single_nonrect_count,
831 : : build_one_cst (llutype));
832 : 174 : t3 = fold_build2 (MULT_EXPR, llutype, t3,
833 : : single_nonrect_count);
834 : 174 : t3 = fold_build2 (TRUNC_DIV_EXPR, llutype, t3,
835 : : build_int_cst (llutype, 2));
836 : 174 : t2 = fold_build2 (MULT_EXPR, llutype, t2, t3);
837 : 174 : t = fold_build2 (PLUS_EXPR, llutype, t, t2);
838 : : }
839 : 10734 : if (i == single_nonrect)
840 : : {
841 : 247 : if (integer_zerop (t) || TREE_CODE (t) != INTEGER_CST)
842 : : count = t;
843 : : else
844 : : {
845 : 247 : single_nonrect_count = t;
846 : 247 : single_nonrect_cond_code = loop->cond_code;
847 : 247 : if (count == NULL_TREE)
848 : 246 : count = build_one_cst (llutype);
849 : : }
850 : : }
851 : 10487 : else if (count != NULL_TREE)
852 : 4194 : count = fold_build2 (MULT_EXPR, llutype, count, t);
853 : : else
854 : : count = t;
855 : 10734 : if (TREE_CODE (count) != INTEGER_CST)
856 : 0 : count = NULL_TREE;
857 : : }
858 : 15910 : else if (count && !integer_zerop (count))
859 : : count = NULL_TREE;
860 : : }
861 : : }
862 : :
863 : 129249 : if (count
864 : 129249 : && !simd
865 : 4039 : && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
866 : 3280 : || fd->have_ordered))
867 : : {
868 : 855 : if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
869 : 0 : iter_type = long_long_unsigned_type_node;
870 : : else
871 : 855 : iter_type = long_integer_type_node;
872 : : }
873 : 128394 : else if (collapse_iter && *collapse_iter != NULL)
874 : 22809 : iter_type = TREE_TYPE (*collapse_iter);
875 : 129249 : fd->iter_type = iter_type;
876 : 129249 : if (collapse_iter && *collapse_iter == NULL)
877 : 11509 : *collapse_iter = create_tmp_var (iter_type, ".iter");
878 : 129249 : if (collapse_count && *collapse_count == NULL)
879 : : {
880 : 11509 : if (count)
881 : : {
882 : 5210 : *collapse_count = fold_convert_loc (loc, iter_type, count);
883 : 5210 : if (fd->first_inner_iterations && fd->factor)
884 : : {
885 : 174 : t = make_tree_vec (4);
886 : 174 : TREE_VEC_ELT (t, 0) = *collapse_count;
887 : 174 : TREE_VEC_ELT (t, 1) = fd->first_inner_iterations;
888 : 174 : TREE_VEC_ELT (t, 2) = fd->factor;
889 : 174 : TREE_VEC_ELT (t, 3) = fd->adjn1;
890 : 174 : *collapse_count = t;
891 : : }
892 : : }
893 : : else
894 : 6299 : *collapse_count = create_tmp_var (iter_type, ".count");
895 : : }
896 : :
897 : 129249 : if (fd->collapse > 1 || fd->tiling || (fd->ordered && loops))
898 : : {
899 : 34314 : fd->loop.v = *collapse_iter;
900 : 34314 : fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
901 : 34314 : fd->loop.n2 = *collapse_count;
902 : 34314 : if (TREE_CODE (fd->loop.n2) == TREE_VEC)
903 : : {
904 : 377 : gcc_assert (fd->non_rect);
905 : 377 : fd->first_inner_iterations = TREE_VEC_ELT (fd->loop.n2, 1);
906 : 377 : fd->factor = TREE_VEC_ELT (fd->loop.n2, 2);
907 : 377 : fd->adjn1 = TREE_VEC_ELT (fd->loop.n2, 3);
908 : 377 : fd->loop.n2 = TREE_VEC_ELT (fd->loop.n2, 0);
909 : : }
910 : 34314 : fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
911 : 34314 : fd->loop.m1 = NULL_TREE;
912 : 34314 : fd->loop.m2 = NULL_TREE;
913 : 34314 : fd->loop.outer = 0;
914 : 34314 : fd->loop.cond_code = LT_EXPR;
915 : : }
916 : 94723 : else if (loops)
917 : 36002 : loops[0] = fd->loop;
918 : 129249 : }
919 : :
920 : : /* Build a call to GOMP_barrier. */
921 : :
922 : : gimple *
923 : 4740 : omp_build_barrier (tree lhs)
924 : : {
925 : 9422 : tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL
926 : : : BUILT_IN_GOMP_BARRIER);
927 : 4740 : gcall *g = gimple_build_call (fndecl, 0);
928 : 4740 : if (lhs)
929 : 58 : gimple_call_set_lhs (g, lhs);
930 : 4740 : return g;
931 : : }
932 : :
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. */
938 : :
939 : : tree
940 : 109517 : find_combined_omp_for (tree *tp, int *walk_subtrees, void *data)
941 : : {
942 : 109517 : tree **pdata = (tree **) data;
943 : 109517 : *walk_subtrees = 0;
944 : 109517 : switch (TREE_CODE (*tp))
945 : : {
946 : 11855 : case OMP_FOR:
947 : 11855 : if (OMP_FOR_INIT (*tp) != NULL_TREE)
948 : : {
949 : 6045 : pdata[3] = tp;
950 : 6045 : return *tp;
951 : : }
952 : 5810 : pdata[2] = tp;
953 : 5810 : *walk_subtrees = 1;
954 : 5810 : break;
955 : 15303 : case OMP_SIMD:
956 : 15303 : if (OMP_FOR_INIT (*tp) != NULL_TREE)
957 : : {
958 : 15303 : pdata[3] = tp;
959 : 15303 : return *tp;
960 : : }
961 : : break;
962 : 46391 : case BIND_EXPR:
963 : 46391 : if (BIND_EXPR_VARS (*tp)
964 : 46391 : || (BIND_EXPR_BLOCK (*tp)
965 : 40840 : && BLOCK_VARS (BIND_EXPR_BLOCK (*tp))))
966 : 5098 : pdata[0] = tp;
967 : 46391 : *walk_subtrees = 1;
968 : 46391 : break;
969 : 8516 : case STATEMENT_LIST:
970 : 8516 : if (!tsi_one_before_end_p (tsi_start (*tp)))
971 : 242 : pdata[0] = tp;
972 : 8516 : *walk_subtrees = 1;
973 : 8516 : break;
974 : 216 : case TRY_FINALLY_EXPR:
975 : 216 : case CLEANUP_POINT_EXPR:
976 : 216 : pdata[0] = tp;
977 : 216 : *walk_subtrees = 1;
978 : 216 : break;
979 : 11883 : case OMP_PARALLEL:
980 : 11883 : pdata[1] = tp;
981 : 11883 : *walk_subtrees = 1;
982 : 11883 : break;
983 : : default:
984 : : break;
985 : : }
986 : : return NULL_TREE;
987 : : }
988 : :
989 : : /* Return maximum possible vectorization factor for the target, or for
990 : : the OpenMP offload target if one exists. */
991 : :
992 : : poly_uint64
993 : 30385 : omp_max_vf (bool offload)
994 : : {
995 : 30385 : if (!optimize
996 : 29058 : || optimize_debug
997 : 29058 : || !flag_tree_loop_optimize
998 : 29057 : || (!flag_tree_loop_vectorize
999 : 581 : && OPTION_SET_P (flag_tree_loop_vectorize)))
1000 : 1332 : return 1;
1001 : :
1002 : 29053 : if (ENABLE_OFFLOADING && offload)
1003 : : {
1004 : : for (const char *c = getenv ("OFFLOAD_TARGET_NAMES"); c;)
1005 : : {
1006 : : if (startswith (c, "amdgcn"))
1007 : : return ordered_max (poly_uint64 (64), omp_max_vf (false));
1008 : : else if ((c = strchr (c, ':')))
1009 : : c++;
1010 : : }
1011 : : /* Otherwise, fall through to host VF. */
1012 : : }
1013 : :
1014 : 29053 : auto_vector_modes modes;
1015 : 29053 : targetm.vectorize.autovectorize_vector_modes (&modes, true);
1016 : 29053 : if (!modes.is_empty ())
1017 : : {
1018 : : poly_uint64 vf = 0;
1019 : 121082 : for (unsigned int i = 0; i < modes.length (); ++i)
1020 : : /* The returned modes use the smallest element size (and thus
1021 : : the largest nunits) for the vectorization approach that they
1022 : : represent. */
1023 : 184066 : vf = ordered_max (vf, GET_MODE_NUNITS (modes[i]));
1024 : 29049 : return vf;
1025 : : }
1026 : :
1027 : 4 : machine_mode vqimode = targetm.vectorize.preferred_simd_mode (QImode);
1028 : 4 : if (GET_MODE_CLASS (vqimode) == MODE_VECTOR_INT)
1029 : 0 : return GET_MODE_NUNITS (vqimode);
1030 : :
1031 : 4 : return 1;
1032 : 29053 : }
1033 : :
1034 : : /* Return maximum SIMT width if offloading may target SIMT hardware. */
1035 : :
1036 : : int
1037 : 3650 : omp_max_simt_vf (void)
1038 : : {
1039 : 3650 : if (!optimize)
1040 : : return 0;
1041 : : if (ENABLE_OFFLOADING)
1042 : : for (const char *c = getenv ("OFFLOAD_TARGET_NAMES"); c;)
1043 : : {
1044 : : if (startswith (c, "nvptx"))
1045 : : return 32;
1046 : : else if ((c = strchr (c, ':')))
1047 : : c++;
1048 : : }
1049 : : return 0;
1050 : : }
1051 : :
1052 : : /* Return true if PROP is possibly present in one of the offloading target's
1053 : : OpenMP contexts. The format of PROPS string is always offloading target's
1054 : : name terminated by '\0', followed by properties for that offloading
1055 : : target separated by '\0' and terminated by another '\0'. The strings
1056 : : are created from omp-device-properties installed files of all configured
1057 : : offloading targets. */
1058 : :
1059 : : static bool
1060 : 0 : omp_offload_device_kind_arch_isa (const char *props, const char *prop)
1061 : : {
1062 : 0 : const char *names = getenv ("OFFLOAD_TARGET_NAMES");
1063 : 0 : if (names == NULL || *names == '\0')
1064 : : return false;
1065 : 0 : while (*props != '\0')
1066 : : {
1067 : 0 : size_t name_len = strlen (props);
1068 : 0 : bool matches = false;
1069 : 0 : for (const char *c = names; c; )
1070 : : {
1071 : 0 : if (strncmp (props, c, name_len) == 0
1072 : 0 : && (c[name_len] == '\0'
1073 : : || c[name_len] == ':'
1074 : : || c[name_len] == '='))
1075 : : {
1076 : : matches = true;
1077 : : break;
1078 : : }
1079 : 0 : else if ((c = strchr (c, ':')))
1080 : 0 : c++;
1081 : : }
1082 : 0 : props = props + name_len + 1;
1083 : 0 : while (*props != '\0')
1084 : : {
1085 : 0 : if (matches && strcmp (props, prop) == 0)
1086 : : return true;
1087 : 0 : props = strchr (props, '\0') + 1;
1088 : : }
1089 : 0 : props++;
1090 : : }
1091 : : return false;
1092 : : }
1093 : :
1094 : : /* Return true if the current code location is or might be offloaded.
1095 : : Return true in declare target functions, or when nested in a target
1096 : : region or when unsure, return false otherwise. */
1097 : :
1098 : : static bool
1099 : 0 : omp_maybe_offloaded (tree construct_context)
1100 : : {
1101 : : /* No offload targets available? */
1102 : 0 : if (!ENABLE_OFFLOADING)
1103 : 0 : return false;
1104 : : const char *names = getenv ("OFFLOAD_TARGET_NAMES");
1105 : : if (names == NULL || *names == '\0')
1106 : : return false;
1107 : :
1108 : : /* Parsing is too early to tell. */
1109 : : if (symtab->state == PARSING)
1110 : : /* Maybe. */
1111 : : return true;
1112 : :
1113 : : /* Late resolution of offloaded code happens in the offload compiler,
1114 : : where it's treated as native code instead. So return false here. */
1115 : : if (cfun && cfun->after_inlining)
1116 : : return false;
1117 : :
1118 : : /* Check if the function is marked for offloading (either explicitly
1119 : : or via omp_discover_implicit_declare_target). */
1120 : : if (current_function_decl
1121 : : && lookup_attribute ("omp declare target",
1122 : : DECL_ATTRIBUTES (current_function_decl)))
1123 : : return true;
1124 : :
1125 : : /* Check for nesting inside a target directive. */
1126 : : for (tree ts = construct_context; ts; ts = TREE_CHAIN (ts))
1127 : : if (OMP_TS_CODE (ts) == OMP_TRAIT_CONSTRUCT_TARGET)
1128 : : return true;
1129 : :
1130 : : return false;
1131 : : }
1132 : :
1133 : : /* Lookup tables for context selectors. */
1134 : : const char *omp_tss_map[] =
1135 : : {
1136 : : "construct",
1137 : : "device",
1138 : : "target_device",
1139 : : "implementation",
1140 : : "user",
1141 : : NULL
1142 : : };
1143 : :
1144 : : /* Arrays of property candidates must be null-terminated. */
1145 : : static const char *const kind_properties[] =
1146 : : { "host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
1147 : : static const char *const vendor_properties[] =
1148 : : { "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "hpe", "ibm", "intel",
1149 : : "llvm", "nec", "nvidia", "pgi", "ti", "unknown", NULL };
1150 : : static const char *const extension_properties[] =
1151 : : { NULL };
1152 : : static const char *const atomic_default_mem_order_properties[] =
1153 : : { "seq_cst", "relaxed", "acq_rel", "acquire", "release", NULL };
1154 : :
1155 : : struct omp_ts_info omp_ts_map[] =
1156 : : {
1157 : : { "kind",
1158 : : (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1159 : : OMP_TRAIT_PROPERTY_NAME_LIST, false,
1160 : : kind_properties
1161 : : },
1162 : : { "isa",
1163 : : (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1164 : : OMP_TRAIT_PROPERTY_NAME_LIST, false,
1165 : : NULL
1166 : : },
1167 : : { "arch",
1168 : : (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1169 : : OMP_TRAIT_PROPERTY_NAME_LIST, false,
1170 : : NULL
1171 : : },
1172 : : { "device_num",
1173 : : (1 << OMP_TRAIT_SET_TARGET_DEVICE),
1174 : : OMP_TRAIT_PROPERTY_DEV_NUM_EXPR, false,
1175 : : NULL
1176 : : },
1177 : : { "vendor",
1178 : : (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1179 : : OMP_TRAIT_PROPERTY_NAME_LIST, true,
1180 : : vendor_properties,
1181 : : },
1182 : : { "extension",
1183 : : (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1184 : : OMP_TRAIT_PROPERTY_NAME_LIST, true,
1185 : : extension_properties,
1186 : : },
1187 : : { "atomic_default_mem_order",
1188 : : (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1189 : : OMP_TRAIT_PROPERTY_ID, true,
1190 : : atomic_default_mem_order_properties,
1191 : : },
1192 : : { "requires",
1193 : : (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1194 : : OMP_TRAIT_PROPERTY_CLAUSE_LIST, true,
1195 : : NULL
1196 : : },
1197 : : { "unified_address",
1198 : : (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1199 : : OMP_TRAIT_PROPERTY_NONE, true,
1200 : : NULL
1201 : : },
1202 : : { "unified_shared_memory",
1203 : : (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1204 : : OMP_TRAIT_PROPERTY_NONE, true,
1205 : : NULL
1206 : : },
1207 : : { "self_maps",
1208 : : (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1209 : : OMP_TRAIT_PROPERTY_NONE, true,
1210 : : NULL
1211 : : },
1212 : : { "dynamic_allocators",
1213 : : (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1214 : : OMP_TRAIT_PROPERTY_NONE, true,
1215 : : NULL
1216 : : },
1217 : : { "reverse_offload",
1218 : : (1 << OMP_TRAIT_SET_IMPLEMENTATION),
1219 : : OMP_TRAIT_PROPERTY_NONE, true,
1220 : : NULL
1221 : : },
1222 : : { "condition",
1223 : : (1 << OMP_TRAIT_SET_USER),
1224 : : OMP_TRAIT_PROPERTY_BOOL_EXPR, true,
1225 : : NULL
1226 : : },
1227 : : { "target",
1228 : : (1 << OMP_TRAIT_SET_CONSTRUCT),
1229 : : OMP_TRAIT_PROPERTY_NONE, false,
1230 : : NULL
1231 : : },
1232 : : { "teams",
1233 : : (1 << OMP_TRAIT_SET_CONSTRUCT),
1234 : : OMP_TRAIT_PROPERTY_NONE, false,
1235 : : NULL
1236 : : },
1237 : : { "parallel",
1238 : : (1 << OMP_TRAIT_SET_CONSTRUCT),
1239 : : OMP_TRAIT_PROPERTY_NONE, false,
1240 : : NULL
1241 : : },
1242 : : { "for",
1243 : : (1 << OMP_TRAIT_SET_CONSTRUCT),
1244 : : OMP_TRAIT_PROPERTY_NONE, false,
1245 : : NULL
1246 : : },
1247 : : { "simd",
1248 : : (1 << OMP_TRAIT_SET_CONSTRUCT),
1249 : : OMP_TRAIT_PROPERTY_CLAUSE_LIST, false,
1250 : : NULL
1251 : : },
1252 : : { "dispatch",
1253 : : (1 << OMP_TRAIT_SET_CONSTRUCT),
1254 : : OMP_TRAIT_PROPERTY_NONE, false,
1255 : : NULL
1256 : : },
1257 : : { NULL, 0, OMP_TRAIT_PROPERTY_NONE, false, NULL } /* OMP_TRAIT_LAST */
1258 : : };
1259 : :
1260 : : /* Return a name from PROP, a property in selectors accepting
1261 : : name lists. */
1262 : :
1263 : : const char *
1264 : 9782 : omp_context_name_list_prop (tree prop)
1265 : : {
1266 : 9782 : gcc_assert (OMP_TP_NAME (prop) == OMP_TP_NAMELIST_NODE);
1267 : 9782 : tree val = OMP_TP_VALUE (prop);
1268 : 9782 : switch (TREE_CODE (val))
1269 : : {
1270 : 7214 : case IDENTIFIER_NODE:
1271 : 7214 : return IDENTIFIER_POINTER (val);
1272 : 2568 : case STRING_CST:
1273 : : #ifdef ACCEL_COMPILER
1274 : : return TREE_STRING_POINTER (val);
1275 : : #else
1276 : 2568 : {
1277 : 2568 : const char *ret = TREE_STRING_POINTER (val);
1278 : 5136 : if ((size_t) TREE_STRING_LENGTH (val)
1279 : 4660 : == strlen (ret) + (lang_GNU_Fortran () ? 0 : 1))
1280 : : return ret;
1281 : : return NULL;
1282 : : }
1283 : : #endif
1284 : : default:
1285 : : return NULL;
1286 : : }
1287 : : }
1288 : :
1289 : :
1290 : : /* Helper function called via walk_tree, to determine if *TP is a
1291 : : PARM_DECL. */
1292 : : static tree
1293 : 1264 : expr_uses_parm_decl (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
1294 : : void *data ATTRIBUTE_UNUSED)
1295 : : {
1296 : 1264 : if (TREE_CODE (*tp) == PARM_DECL)
1297 : 26 : return *tp;
1298 : : return NULL_TREE;
1299 : : }
1300 : :
1301 : : /* Diagnose errors in an OpenMP context selector, return CTX if
1302 : : it is correct or error_mark_node otherwise. */
1303 : :
1304 : : tree
1305 : 2786 : omp_check_context_selector (location_t loc, tree ctx,
1306 : : enum omp_ctx_directive directive)
1307 : : {
1308 : 2786 : bool tss_seen[OMP_TRAIT_SET_LAST], ts_seen[OMP_TRAIT_LAST];
1309 : :
1310 : 2786 : memset (tss_seen, 0, sizeof (tss_seen));
1311 : 5707 : for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
1312 : : {
1313 : 3047 : enum omp_tss_code tss_code = OMP_TSS_CODE (tss);
1314 : 3047 : bool saw_any_prop = false;
1315 : 3047 : bool saw_other_prop = false;
1316 : :
1317 : : /* Each trait-set-selector-name can only be specified once. */
1318 : 3047 : if (tss_seen[tss_code])
1319 : : {
1320 : 60 : error_at (loc, "selector set %qs specified more than once",
1321 : 30 : OMP_TSS_NAME (tss));
1322 : 30 : return error_mark_node;
1323 : : }
1324 : : else
1325 : 3017 : tss_seen[tss_code] = true;
1326 : :
1327 : 3017 : memset (ts_seen, 0, sizeof (ts_seen));
1328 : 6773 : for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
1329 : : {
1330 : 3832 : enum omp_ts_code ts_code = OMP_TS_CODE (ts);
1331 : :
1332 : : /* Ignore unknown traits. */
1333 : 3832 : if (ts_code == OMP_TRAIT_INVALID)
1334 : 73 : continue;
1335 : :
1336 : : /* Each trait-selector-name can only be specified once. */
1337 : 3759 : if (ts_seen[ts_code])
1338 : : {
1339 : 15 : error_at (loc,
1340 : : "selector %qs specified more than once in set %qs",
1341 : 15 : OMP_TS_NAME (ts),
1342 : 15 : OMP_TSS_NAME (tss));
1343 : 15 : return error_mark_node;
1344 : : }
1345 : : else
1346 : 3744 : ts_seen[ts_code] = true;
1347 : :
1348 : : /* If trait-property "any" is specified in the "kind"
1349 : : trait-selector of the "device" selector set or the
1350 : : "target_device" selector sets, no other trait-property
1351 : : may be specified in the same selector set. */
1352 : 3744 : if (ts_code == OMP_TRAIT_DEVICE_KIND)
1353 : 1186 : for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1354 : : {
1355 : 438 : const char *prop = omp_context_name_list_prop (p);
1356 : 438 : if (!prop)
1357 : 4 : continue;
1358 : 434 : else if (strcmp (prop, "any") == 0)
1359 : : saw_any_prop = true;
1360 : : else
1361 : 367 : saw_other_prop = true;
1362 : : }
1363 : : /* It seems slightly suspicious that the spec's language covers
1364 : : the device_num selector too, but
1365 : : target_device={device_num(whatever),kind(any)}
1366 : : is probably not terribly useful anyway. */
1367 : 3370 : else if (ts_code == OMP_TRAIT_DEVICE_ARCH
1368 : : || ts_code == OMP_TRAIT_DEVICE_ISA
1369 : 3370 : || ts_code == OMP_TRAIT_DEVICE_NUM)
1370 : 685 : saw_other_prop = true;
1371 : :
1372 : : /* Each trait-property can only be specified once in a trait-selector
1373 : : other than the construct selector set. FIXME: only handles
1374 : : name-list properties, not clause-list properties, since the
1375 : : "requires" selector is not implemented yet (PR 113067). */
1376 : 3744 : if (tss_code != OMP_TRAIT_SET_CONSTRUCT)
1377 : 5980 : for (tree p1 = OMP_TS_PROPERTIES (ts); p1; p1 = TREE_CHAIN (p1))
1378 : : {
1379 : 2397 : if (OMP_TP_NAME (p1) != OMP_TP_NAMELIST_NODE)
1380 : : break;
1381 : 1558 : const char *n1 = omp_context_name_list_prop (p1);
1382 : 1558 : if (!n1)
1383 : 8 : continue;
1384 : 1908 : for (tree p2 = TREE_CHAIN (p1); p2; p2 = TREE_CHAIN (p2))
1385 : : {
1386 : 388 : const char *n2 = omp_context_name_list_prop (p2);
1387 : 388 : if (!n2)
1388 : 0 : continue;
1389 : 388 : if (!strcmp (n1, n2))
1390 : : {
1391 : 30 : error_at (loc,
1392 : : "trait-property %qs specified more "
1393 : : "than once in %qs selector",
1394 : 30 : n1, OMP_TS_NAME (ts));
1395 : 30 : return error_mark_node;
1396 : : }
1397 : : }
1398 : : }
1399 : :
1400 : : /* This restriction is documented in the spec in the section
1401 : : for the metadirective "when" clause (7.4.1 in the 5.2 spec). */
1402 : 3714 : if (directive == OMP_CTX_METADIRECTIVE
1403 : 3714 : && ts_code == OMP_TRAIT_CONSTRUCT_SIMD
1404 : 3718 : && OMP_TS_PROPERTIES (ts))
1405 : : {
1406 : 0 : error_at (loc,
1407 : : "properties must not be specified for the %<simd%> "
1408 : : "selector in a %<metadirective%> context-selector");
1409 : 0 : return error_mark_node;
1410 : : }
1411 : :
1412 : : /* "simd" is not allowed at all in "begin declare variant"
1413 : : selectors. */
1414 : 3714 : if (directive == OMP_CTX_BEGIN_DECLARE_VARIANT
1415 : 3714 : && ts_code == OMP_TRAIT_CONSTRUCT_SIMD)
1416 : : {
1417 : 0 : error_at (loc,
1418 : : "the %<simd%> selector is not permitted in a "
1419 : : "%<begin declare variant%> context selector");
1420 : 0 : return error_mark_node;
1421 : : }
1422 : :
1423 : : /* Reject expressions that reference parameter variables in
1424 : : "declare variant", as this is not yet implemented. FIXME;
1425 : : see PR middle-end/113904. */
1426 : 3714 : if (directive != OMP_CTX_METADIRECTIVE
1427 : 2913 : && (ts_code == OMP_TRAIT_DEVICE_NUM
1428 : 2913 : || ts_code == OMP_TRAIT_USER_CONDITION))
1429 : : {
1430 : 528 : tree exp = OMP_TS_PROPERTIES (ts);
1431 : 528 : if (walk_tree (&exp, expr_uses_parm_decl, NULL, NULL))
1432 : : {
1433 : 26 : sorry_at (loc,
1434 : : "reference to function parameter in "
1435 : : "%<declare variant%> dynamic selector expression");
1436 : 26 : return error_mark_node;
1437 : : }
1438 : : }
1439 : :
1440 : : /* Check for unknown properties. */
1441 : 3688 : if (omp_ts_map[ts_code].valid_properties == NULL)
1442 : 2852 : continue;
1443 : 2592 : for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1444 : 3311 : for (unsigned j = 0; ; j++)
1445 : : {
1446 : 4236 : const char *candidate
1447 : 4236 : = omp_ts_map[ts_code].valid_properties[j];
1448 : 4236 : if (candidate == NULL)
1449 : : {
1450 : : /* We've reached the end of the candidate array. */
1451 : 75 : if (ts_code == OMP_TRAIT_IMPLEMENTATION_ADMO)
1452 : : /* FIXME: not sure why this is an error vs warnings
1453 : : for the others, + incorrect/unknown wording? */
1454 : : {
1455 : 5 : error_at (loc,
1456 : : "incorrect property %qs of %qs selector",
1457 : 5 : IDENTIFIER_POINTER (OMP_TP_NAME (p)),
1458 : : "atomic_default_mem_order");
1459 : 5 : return error_mark_node;
1460 : : }
1461 : 70 : if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
1462 : 70 : && (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
1463 : 30 : warning_at (loc, OPT_Wopenmp,
1464 : : "unknown property %qE of %qs selector",
1465 : 15 : OMP_TP_VALUE (p),
1466 : 15 : OMP_TS_NAME (ts));
1467 : 55 : else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
1468 : 110 : warning_at (loc, OPT_Wopenmp,
1469 : : "unknown property %qs of %qs selector",
1470 : : omp_context_name_list_prop (p),
1471 : 55 : OMP_TS_NAME (ts));
1472 : 0 : else if (OMP_TP_NAME (p))
1473 : 0 : warning_at (loc, OPT_Wopenmp,
1474 : : "unknown property %qs of %qs selector",
1475 : 0 : IDENTIFIER_POINTER (OMP_TP_NAME (p)),
1476 : 0 : OMP_TS_NAME (ts));
1477 : : break;
1478 : : }
1479 : 4161 : else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
1480 : : /* Property-list traits. */
1481 : : {
1482 : 3913 : const char *str = omp_context_name_list_prop (p);
1483 : 3913 : if (str && !strcmp (str, candidate))
1484 : : break;
1485 : : }
1486 : 248 : else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
1487 : : candidate))
1488 : : /* Identifier traits. */
1489 : : break;
1490 : 3311 : }
1491 : : }
1492 : :
1493 : 2941 : if (saw_any_prop && saw_other_prop)
1494 : : {
1495 : 20 : error_at (loc,
1496 : : "no other trait-property may be specified "
1497 : : "in the same selector set with %<kind(\"any\")%>");
1498 : 20 : return error_mark_node;
1499 : : }
1500 : : }
1501 : : return ctx;
1502 : : }
1503 : :
1504 : : /* Forward declarations. */
1505 : : static int omp_context_selector_set_compare (enum omp_tss_code, tree, tree);
1506 : : static int omp_construct_simd_compare (tree, tree, bool);
1507 : :
1508 : : /* Register VARIANT as variant of some base function marked with
1509 : : #pragma omp declare variant. CONSTRUCT is corresponding list of
1510 : : trait-selectors for the construct selector set. This is stashed as the
1511 : : value of the "omp declare variant variant" attribute on VARIANT. */
1512 : : void
1513 : 1852 : omp_mark_declare_variant (location_t loc, tree variant, tree construct)
1514 : : {
1515 : : /* Ignore this variant if it contains unknown construct selectors.
1516 : : It will never match, and the front ends have already issued a warning
1517 : : about it. */
1518 : 2972 : for (tree c = construct; c; c = TREE_CHAIN (c))
1519 : 1176 : if (OMP_TS_CODE (c) == OMP_TRAIT_INVALID)
1520 : : return;
1521 : :
1522 : 1796 : tree attr = lookup_attribute ("omp declare variant variant",
1523 : 1796 : DECL_ATTRIBUTES (variant));
1524 : 1796 : if (attr == NULL_TREE)
1525 : : {
1526 : 1267 : attr = tree_cons (get_identifier ("omp declare variant variant"),
1527 : : unshare_expr (construct),
1528 : 1267 : DECL_ATTRIBUTES (variant));
1529 : 1267 : DECL_ATTRIBUTES (variant) = attr;
1530 : 1267 : return;
1531 : : }
1532 : 529 : if ((TREE_VALUE (attr) != NULL_TREE) != (construct != NULL_TREE)
1533 : 529 : || (construct != NULL_TREE
1534 : 115 : && omp_context_selector_set_compare (OMP_TRAIT_SET_CONSTRUCT,
1535 : 115 : TREE_VALUE (attr),
1536 : : construct)))
1537 : 53 : error_at (loc, "%qD used as a variant with incompatible %<construct%> "
1538 : : "selector sets", variant);
1539 : : }
1540 : :
1541 : :
1542 : : /* Constructors for context selectors. */
1543 : :
1544 : : tree
1545 : 3094 : make_trait_set_selector (enum omp_tss_code code, tree selectors, tree chain)
1546 : : {
1547 : 3094 : return tree_cons (build_int_cst (integer_type_node, code),
1548 : 3094 : selectors, chain);
1549 : : }
1550 : :
1551 : : tree
1552 : 6185 : make_trait_selector (enum omp_ts_code code, tree score, tree properties,
1553 : : tree chain)
1554 : : {
1555 : 6185 : if (score == NULL_TREE)
1556 : 5772 : return tree_cons (build_int_cst (integer_type_node, code),
1557 : : properties, chain);
1558 : : else
1559 : 413 : return tree_cons (build_int_cst (integer_type_node, code),
1560 : : tree_cons (OMP_TS_SCORE_NODE, score, properties),
1561 : : chain);
1562 : : }
1563 : :
1564 : : tree
1565 : 2529 : make_trait_property (tree name, tree value, tree chain)
1566 : : {
1567 : 2529 : return tree_cons (name, value, chain);
1568 : : }
1569 : :
1570 : : /* Constructor for metadirective variants. */
1571 : : tree
1572 : 853 : make_omp_metadirective_variant (tree selector, tree directive, tree body)
1573 : : {
1574 : 853 : return build_tree_list (selector, build_tree_list (directive, body));
1575 : : }
1576 : :
1577 : : /* If the construct selector traits SELECTOR_TRAITS match the corresponding
1578 : : OpenMP context traits CONTEXT_TRAITS, return true and set *SCORE to the
1579 : : corresponding score if it is non-null. */
1580 : : static bool
1581 : 4330 : omp_construct_traits_match (tree selector_traits, tree context_traits,
1582 : : score_wide_int *score)
1583 : : {
1584 : 4330 : int slength = list_length (selector_traits);
1585 : 4330 : int clength = list_length (context_traits);
1586 : :
1587 : : /* Trivial failure: the selector has more traits than the OpenMP context. */
1588 : 4330 : if (slength > clength)
1589 : : return false;
1590 : :
1591 : : /* There's only one trait in the selector and it doesn't have any properties
1592 : : to match. */
1593 : 7518 : if (slength == 1 && !OMP_TS_PROPERTIES (selector_traits))
1594 : : {
1595 : 3509 : int p = 0, i = 1;
1596 : 3509 : enum omp_ts_code code = OMP_TS_CODE (selector_traits);
1597 : 7314 : for (tree t = context_traits; t; t = TREE_CHAIN (t), i++)
1598 : 3805 : if (OMP_TS_CODE (t) == code)
1599 : 3546 : p = i;
1600 : 3509 : if (p != 0)
1601 : : {
1602 : 3486 : if (score)
1603 : 1226 : *score = wi::shifted_mask <score_wide_int> (p - 1, 1, false);
1604 : 3486 : return true;
1605 : : }
1606 : : else
1607 : : return false;
1608 : : }
1609 : :
1610 : : /* Now handle the more general cases.
1611 : : Both lists of traits are ordered from outside in, corresponding to
1612 : : the c1, ..., cN numbering for the OpenMP context specified in
1613 : : in section 7.1 of the OpenMP 5.2 spec. Section 7.3 of the spec says
1614 : : "if the traits that correspond to the construct selector set appear
1615 : : multiple times in the OpenMP context, the highest valued subset of
1616 : : context traits that contains all trait selectors in the same order
1617 : : are used". This means that we want to start the search for a match
1618 : : from the end of the list, rather than the beginning. To facilitate
1619 : : that, transfer the lists to temporary arrays to allow random access
1620 : : to the elements (their order remains outside in). */
1621 : 492 : int i, j;
1622 : 492 : tree s, c;
1623 : :
1624 : 492 : tree *sarray = (tree *) alloca (slength * sizeof (tree));
1625 : 1574 : for (s = selector_traits, i = 0; s; s = TREE_CHAIN (s), i++)
1626 : 1082 : sarray[i] = s;
1627 : :
1628 : 492 : tree *carray = (tree *) alloca (clength * sizeof (tree));
1629 : 1785 : for (c = context_traits, j = 0; c; c = TREE_CHAIN (c), j++)
1630 : 1293 : carray[j] = c;
1631 : :
1632 : : /* The variable "i" indexes the selector, "j" indexes the OpenMP context.
1633 : : Find the "j" corresponding to each sarray[i]. Note that the spec uses
1634 : : "p" as the 1-based position, but "j" is zero-based, e.g. equal to
1635 : : p - 1. */
1636 : 492 : score_wide_int result = 0;
1637 : 492 : j = clength - 1;
1638 : 1452 : for (i = slength - 1; i >= 0; i--)
1639 : : {
1640 : 1029 : enum omp_ts_code code = OMP_TS_CODE (sarray[i]);
1641 : 1029 : tree props = OMP_TS_PROPERTIES (sarray[i]);
1642 : 1287 : for (; j >= 0; j--)
1643 : : {
1644 : 1218 : if (OMP_TS_CODE (carray[j]) != code)
1645 : 218 : continue;
1646 : 1040 : if (code == OMP_TRAIT_CONSTRUCT_SIMD
1647 : 1000 : && props
1648 : 1040 : && omp_construct_simd_compare (props,
1649 : 40 : OMP_TS_PROPERTIES (carray[j]),
1650 : : true) > 0)
1651 : 40 : continue;
1652 : : break;
1653 : : }
1654 : : /* If j >= 0, we have a match for this trait at position j. */
1655 : 960 : if (j < 0)
1656 : : return false;
1657 : 960 : result += wi::shifted_mask <score_wide_int> (j, 1, false);
1658 : 960 : j--;
1659 : : }
1660 : 423 : if (score)
1661 : 141 : *score = result;
1662 : : return true;
1663 : : }
1664 : :
1665 : : /* Return 1 if context selector CTX matches the current OpenMP context, 0
1666 : : if it does not and -1 if it is unknown and need to be determined later.
1667 : : Some properties can be checked right away during parsing, others need
1668 : : to wait until the whole TU is parsed, others need to wait until
1669 : : IPA, others until vectorization.
1670 : :
1671 : : CONSTRUCT_CONTEXT is a list of construct traits from the OpenMP context,
1672 : : which must be collected by omp_get_construct_context during
1673 : : gimplification. It is ignored (and may be null) if this function is
1674 : : called during parsing. Otherwise COMPLETE_P should indicate whether
1675 : : CONSTRUCT_CONTEXT is known to be complete and not missing constructs
1676 : : filled in later during compilation.
1677 : :
1678 : : Dynamic properties (which are evaluated at run-time) should always
1679 : : return 1. */
1680 : :
1681 : : int
1682 : 8998 : omp_context_selector_matches (tree ctx,
1683 : : tree construct_context,
1684 : : bool complete_p)
1685 : : {
1686 : 8998 : int ret = 1;
1687 : 8998 : bool maybe_offloaded = omp_maybe_offloaded (construct_context);
1688 : :
1689 : 17140 : for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
1690 : : {
1691 : 9390 : enum omp_tss_code set = OMP_TSS_CODE (tss);
1692 : 9390 : tree selectors = OMP_TSS_TRAIT_SELECTORS (tss);
1693 : :
1694 : : /* Immediately reject the match if there are any ignored
1695 : : selectors present. */
1696 : 20575 : for (tree ts = selectors; ts; ts = TREE_CHAIN (ts))
1697 : 11253 : if (OMP_TS_CODE (ts) == OMP_TRAIT_INVALID)
1698 : : return 0;
1699 : :
1700 : 9322 : if (set == OMP_TRAIT_SET_CONSTRUCT)
1701 : : {
1702 : : /* We cannot resolve the construct selector during parsing because
1703 : : the OpenMP context (and CONSTRUCT_CONTEXT) isn't available
1704 : : until gimplification. */
1705 : 4056 : if (symtab->state == PARSING)
1706 : : {
1707 : 1097 : ret = -1;
1708 : 1097 : continue;
1709 : : }
1710 : :
1711 : 2959 : gcc_assert (selectors);
1712 : :
1713 : : /* During gimplification, CONSTRUCT_CONTEXT is partial, and doesn't
1714 : : include a construct for "declare simd" that may be added
1715 : : when there is not an enclosing "target" construct. We might
1716 : : be able to find a positive match against the partial context
1717 : : (although we cannot yet score it accurately), but if we can't,
1718 : : treat it as unknown instead of no match. */
1719 : 2959 : if (!omp_construct_traits_match (selectors, construct_context, NULL))
1720 : : {
1721 : : /* If we've got a complete context, it's definitely a failed
1722 : : match. */
1723 : 417 : if (complete_p)
1724 : : return 0;
1725 : :
1726 : : /* If the selector doesn't include simd, then we don't have
1727 : : to worry about whether "declare simd" would cause it to
1728 : : match; so this is also a definite failure. */
1729 : 8 : bool have_simd = false;
1730 : 8 : for (tree ts = selectors; ts; ts = TREE_CHAIN (ts))
1731 : 8 : if (OMP_TS_CODE (ts) == OMP_TRAIT_CONSTRUCT_SIMD)
1732 : : {
1733 : : have_simd = true;
1734 : : break;
1735 : : }
1736 : 8 : if (!have_simd)
1737 : : return 0;
1738 : : else
1739 : : ret = -1;
1740 : : }
1741 : 2550 : continue;
1742 : 2550 : }
1743 : 5266 : else if (set == OMP_TRAIT_SET_TARGET_DEVICE)
1744 : : /* The target_device set is dynamic, so treat it as always
1745 : : resolvable. However, the current implementation doesn't
1746 : : support it in a target region, so diagnose that as an error.
1747 : : FIXME: maybe make this a warning and return 0 instead? */
1748 : : {
1749 : 426 : for (tree ts = construct_context; ts; ts = TREE_CHAIN (ts))
1750 : 0 : if (OMP_TS_CODE (ts) == OMP_TRAIT_CONSTRUCT_TARGET)
1751 : 0 : sorry ("%<target_device%> selector set inside of %<target%> "
1752 : : "directive");
1753 : 426 : continue;
1754 : 426 : }
1755 : :
1756 : 9184 : for (tree ts = selectors; ts; ts = TREE_CHAIN (ts))
1757 : : {
1758 : 5115 : enum omp_ts_code sel = OMP_TS_CODE (ts);
1759 : 5115 : switch (sel)
1760 : : {
1761 : 921 : case OMP_TRAIT_IMPLEMENTATION_VENDOR:
1762 : 921 : gcc_assert (set == OMP_TRAIT_SET_IMPLEMENTATION);
1763 : 2625 : for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1764 : : {
1765 : 936 : const char *prop = omp_context_name_list_prop (p);
1766 : 936 : if (prop == NULL)
1767 : : return 0;
1768 : 932 : if (!strcmp (prop, "gnu"))
1769 : 783 : continue;
1770 : : return 0;
1771 : : }
1772 : : break;
1773 : 30 : case OMP_TRAIT_IMPLEMENTATION_EXTENSION:
1774 : 30 : gcc_assert (set == OMP_TRAIT_SET_IMPLEMENTATION);
1775 : : /* We don't support any extensions right now. */
1776 : : return 0;
1777 : 163 : break;
1778 : 163 : case OMP_TRAIT_IMPLEMENTATION_ADMO:
1779 : 163 : gcc_assert (set == OMP_TRAIT_SET_IMPLEMENTATION);
1780 : 163 : if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1781 : : break;
1782 : :
1783 : 163 : {
1784 : 163 : enum omp_memory_order omo
1785 : : = ((enum omp_memory_order)
1786 : 163 : (omp_requires_mask
1787 : : & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER));
1788 : 163 : if (omo == OMP_MEMORY_ORDER_UNSPECIFIED)
1789 : : {
1790 : : /* We don't know yet, until end of TU. */
1791 : 72 : if (symtab->state == PARSING)
1792 : : {
1793 : : ret = -1;
1794 : : break;
1795 : : }
1796 : : else
1797 : : omo = OMP_MEMORY_ORDER_RELAXED;
1798 : : }
1799 : 91 : tree p = OMP_TS_PROPERTIES (ts);
1800 : 91 : const char *prop = IDENTIFIER_POINTER (OMP_TP_NAME (p));
1801 : 91 : if (!strcmp (prop, "relaxed")
1802 : 5 : && omo != OMP_MEMORY_ORDER_RELAXED)
1803 : : return 0;
1804 : 86 : else if (!strcmp (prop, "seq_cst")
1805 : 86 : && omo != OMP_MEMORY_ORDER_SEQ_CST)
1806 : : return 0;
1807 : 86 : else if (!strcmp (prop, "acq_rel")
1808 : 0 : && omo != OMP_MEMORY_ORDER_ACQ_REL)
1809 : : return 0;
1810 : 86 : else if (!strcmp (prop, "acquire")
1811 : 0 : && omo != OMP_MEMORY_ORDER_ACQUIRE)
1812 : : return 0;
1813 : 86 : else if (!strcmp (prop, "release")
1814 : 0 : && omo != OMP_MEMORY_ORDER_RELEASE)
1815 : : return 0;
1816 : : }
1817 : : break;
1818 : 388 : case OMP_TRAIT_DEVICE_ARCH:
1819 : 388 : gcc_assert (set == OMP_TRAIT_SET_DEVICE);
1820 : 951 : for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1821 : : {
1822 : 393 : const char *arch = omp_context_name_list_prop (p);
1823 : 393 : if (arch == NULL)
1824 : : return 0;
1825 : 393 : int r = 0;
1826 : 393 : if (targetm.omp.device_kind_arch_isa != NULL)
1827 : 393 : r = targetm.omp.device_kind_arch_isa (omp_device_arch,
1828 : : arch);
1829 : 393 : if (r == 0 || (r == -1 && symtab->state != PARSING))
1830 : : {
1831 : : /* If we are or might be in a target region or
1832 : : declare target function, need to take into account
1833 : : also offloading values.
1834 : : Note that maybe_offloaded is always false in late
1835 : : resolution; that's handled as native code (the
1836 : : above case) in the offload compiler instead. */
1837 : 218 : if (!maybe_offloaded)
1838 : 218 : return 0;
1839 : : if (ENABLE_OFFLOADING)
1840 : : {
1841 : : const char *arches = omp_offload_device_arch;
1842 : : if (omp_offload_device_kind_arch_isa (arches, arch))
1843 : : {
1844 : : ret = -1;
1845 : : continue;
1846 : : }
1847 : : }
1848 : : return 0;
1849 : : }
1850 : : else if (r == -1)
1851 : : ret = -1;
1852 : : /* If arch matches on the host, it still might not match
1853 : : in the offloading region. */
1854 : : else if (maybe_offloaded)
1855 : : ret = -1;
1856 : : }
1857 : : break;
1858 : 20 : case OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS:
1859 : 20 : gcc_assert (set == OMP_TRAIT_SET_IMPLEMENTATION);
1860 : 20 : if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1861 : : break;
1862 : :
1863 : 20 : if ((omp_requires_mask & OMP_REQUIRES_UNIFIED_ADDRESS) == 0)
1864 : : {
1865 : 20 : if (symtab->state == PARSING)
1866 : : ret = -1;
1867 : : else
1868 : : return 0;
1869 : : }
1870 : : break;
1871 : 15 : case OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY:
1872 : 15 : gcc_assert (set == OMP_TRAIT_SET_IMPLEMENTATION);
1873 : 15 : if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1874 : : break;
1875 : :
1876 : 15 : if ((omp_requires_mask
1877 : : & OMP_REQUIRES_UNIFIED_SHARED_MEMORY) == 0)
1878 : : {
1879 : 15 : if (symtab->state == PARSING)
1880 : : ret = -1;
1881 : : else
1882 : : return 0;
1883 : : }
1884 : : break;
1885 : 5 : case OMP_TRAIT_IMPLEMENTATION_SELF_MAPS:
1886 : 5 : gcc_assert (set == OMP_TRAIT_SET_IMPLEMENTATION);
1887 : 5 : if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1888 : : break;
1889 : :
1890 : 5 : if ((omp_requires_mask & OMP_REQUIRES_SELF_MAPS) == 0)
1891 : : {
1892 : 5 : if (symtab->state == PARSING)
1893 : : ret = -1;
1894 : : else
1895 : : return 0;
1896 : : }
1897 : : break;
1898 : 10 : case OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS:
1899 : 10 : gcc_assert (set == OMP_TRAIT_SET_IMPLEMENTATION);
1900 : 10 : if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1901 : : break;
1902 : :
1903 : 10 : if ((omp_requires_mask
1904 : : & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0)
1905 : : {
1906 : 10 : if (symtab->state == PARSING)
1907 : : ret = -1;
1908 : : else
1909 : : return 0;
1910 : : }
1911 : : break;
1912 : 10 : case OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD:
1913 : 10 : gcc_assert (set == OMP_TRAIT_SET_IMPLEMENTATION);
1914 : 10 : if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1915 : : break;
1916 : :
1917 : 10 : if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0)
1918 : : {
1919 : 10 : if (symtab->state == PARSING)
1920 : : ret = -1;
1921 : : else
1922 : : return 0;
1923 : : }
1924 : : break;
1925 : 643 : case OMP_TRAIT_DEVICE_KIND:
1926 : 643 : gcc_assert (set == OMP_TRAIT_SET_DEVICE);
1927 : 1875 : for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1928 : : {
1929 : 667 : const char *prop = omp_context_name_list_prop (p);
1930 : 667 : if (prop == NULL)
1931 : : return 0;
1932 : 663 : if (!strcmp (prop, "any"))
1933 : 35 : continue;
1934 : 628 : if (!strcmp (prop, "host"))
1935 : : {
1936 : : #ifdef ACCEL_COMPILER
1937 : : return 0;
1938 : : #else
1939 : 285 : if (maybe_offloaded)
1940 : : ret = -1;
1941 : 285 : continue;
1942 : : #endif
1943 : : }
1944 : 343 : if (!strcmp (prop, "nohost"))
1945 : : {
1946 : : #ifndef ACCEL_COMPILER
1947 : : if (maybe_offloaded)
1948 : : ret = -1;
1949 : : else
1950 : : return 0;
1951 : : #endif
1952 : : continue;
1953 : : }
1954 : :
1955 : 315 : int r = 0;
1956 : 315 : if (targetm.omp.device_kind_arch_isa != NULL)
1957 : 315 : r = targetm.omp.device_kind_arch_isa (omp_device_kind,
1958 : : prop);
1959 : : else
1960 : : #ifndef ACCEL_COMPILER
1961 : 0 : r = strcmp (prop, "cpu") == 0;
1962 : : #else
1963 : : gcc_unreachable ();
1964 : : #endif
1965 : 315 : if (r == 0 || (r == -1 && symtab->state != PARSING))
1966 : : {
1967 : : /* If we are or might be in a target region or
1968 : : declare target function, need to take into account
1969 : : also offloading values.
1970 : : Note that maybe_offloaded is always false in late
1971 : : resolution; that's handled as native code (the
1972 : : above case) in the offload compiler instead. */
1973 : : if (!maybe_offloaded)
1974 : : return 0;
1975 : : if (ENABLE_OFFLOADING)
1976 : : {
1977 : : const char *kinds = omp_offload_device_kind;
1978 : : if (omp_offload_device_kind_arch_isa (kinds, prop))
1979 : : {
1980 : : ret = -1;
1981 : : continue;
1982 : : }
1983 : : }
1984 : : return 0;
1985 : : }
1986 : : else if (r == -1)
1987 : : ret = -1;
1988 : : /* If kind matches on the host, it still might not match
1989 : : in the offloading region. */
1990 : : else if (maybe_offloaded)
1991 : : ret = -1;
1992 : : }
1993 : : break;
1994 : 513 : case OMP_TRAIT_DEVICE_ISA:
1995 : 513 : gcc_assert (set == OMP_TRAIT_SET_DEVICE);
1996 : 1664 : for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
1997 : : {
1998 : 771 : const char *isa = omp_context_name_list_prop (p);
1999 : 771 : if (isa == NULL)
2000 : : return 0;
2001 : 771 : int r = 0;
2002 : 771 : if (targetm.omp.device_kind_arch_isa != NULL)
2003 : 771 : r = targetm.omp.device_kind_arch_isa (omp_device_isa,
2004 : : isa);
2005 : 771 : if (r == 0 || (r == -1 && symtab->state != PARSING))
2006 : : {
2007 : : /* If isa is valid on the target, but not in the
2008 : : current function and current function has
2009 : : #pragma omp declare simd on it, some simd clones
2010 : : might have the isa added later on. */
2011 : 139 : if (r == -1
2012 : 139 : && targetm.simd_clone.compute_vecsize_and_simdlen
2013 : 139 : && (cfun == NULL || !cfun->after_inlining))
2014 : : {
2015 : 55 : tree attrs
2016 : 55 : = DECL_ATTRIBUTES (current_function_decl);
2017 : 55 : if (lookup_attribute ("omp declare simd", attrs))
2018 : : {
2019 : 34 : ret = -1;
2020 : 34 : continue;
2021 : : }
2022 : : }
2023 : : /* If we are or might be in a target region or
2024 : : declare target function, need to take into account
2025 : : also offloading values.
2026 : : Note that maybe_offloaded is always false in late
2027 : : resolution; that's handled as native code (the
2028 : : above case) in the offload compiler instead. */
2029 : 133 : if (!maybe_offloaded)
2030 : 133 : return 0;
2031 : : if (ENABLE_OFFLOADING)
2032 : : {
2033 : : const char *isas = omp_offload_device_isa;
2034 : : if (omp_offload_device_kind_arch_isa (isas, isa))
2035 : : {
2036 : : ret = -1;
2037 : : continue;
2038 : : }
2039 : : }
2040 : : return 0;
2041 : : }
2042 : : else if (r == -1)
2043 : : ret = -1;
2044 : : /* If isa matches on the host, it still might not match
2045 : : in the offloading region. */
2046 : : else if (maybe_offloaded)
2047 : : ret = -1;
2048 : : }
2049 : : break;
2050 : 2397 : case OMP_TRAIT_USER_CONDITION:
2051 : 2397 : gcc_assert (set == OMP_TRAIT_SET_USER);
2052 : 4794 : for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
2053 : 2396 : if (OMP_TP_NAME (p) == NULL_TREE)
2054 : : {
2055 : : /* If the expression is not a constant, the selector
2056 : : is dynamic. */
2057 : 2396 : if (!tree_fits_shwi_p (OMP_TP_VALUE (p)))
2058 : : break;
2059 : :
2060 : 951 : if (integer_zerop (OMP_TP_VALUE (p)))
2061 : : return 0;
2062 : 797 : if (integer_nonzerop (OMP_TP_VALUE (p)))
2063 : : break;
2064 : : ret = -1;
2065 : : }
2066 : : break;
2067 : : default:
2068 : : break;
2069 : : }
2070 : : }
2071 : : }
2072 : : return ret;
2073 : : }
2074 : :
2075 : : /* Helper function for resolve_omp_target_device_matches, also used
2076 : : directly when we know in advance that the device is the host to avoid
2077 : : the overhead of late resolution. SEL is the selector code and
2078 : : PROPERTIES are the properties to match. The return value is a
2079 : : boolean. */
2080 : : static bool
2081 : 153 : omp_target_device_matches_on_host (enum omp_ts_code selector,
2082 : : tree properties)
2083 : : {
2084 : 153 : bool result = 1;
2085 : :
2086 : 153 : if (dump_file)
2087 : 0 : fprintf (dump_file, "omp_target_device_matches_on_host:\n");
2088 : :
2089 : 153 : switch (selector)
2090 : : {
2091 : : case OMP_TRAIT_DEVICE_KIND:
2092 : 216 : for (tree p = properties; p && result; p = TREE_CHAIN (p))
2093 : : {
2094 : 108 : const char *prop = omp_context_name_list_prop (p);
2095 : :
2096 : 108 : if (prop == NULL)
2097 : : result = 0;
2098 : 108 : else if (!strcmp (prop, "any"))
2099 : : ;
2100 : 108 : else if (!strcmp (prop, "host"))
2101 : : {
2102 : : #ifdef ACCEL_COMPILER
2103 : : result = 0;
2104 : : #else
2105 : : ;
2106 : : #endif
2107 : : }
2108 : 52 : else if (!strcmp (prop, "nohost"))
2109 : : {
2110 : : #ifdef ACCEL_COMPILER
2111 : : ;
2112 : : #else
2113 : : result = 0;
2114 : : #endif
2115 : : }
2116 : 44 : else if (targetm.omp.device_kind_arch_isa != NULL)
2117 : 44 : result = targetm.omp.device_kind_arch_isa (omp_device_kind, prop);
2118 : : else
2119 : : #ifndef ACCEL_COMPILER
2120 : 0 : result = strcmp (prop, "cpu") == 0;
2121 : : #else
2122 : : gcc_unreachable ();
2123 : : #endif
2124 : 108 : if (dump_file)
2125 : 0 : fprintf (dump_file, "Matching device kind %s = %s\n",
2126 : : prop, (result ? "true" : "false"));
2127 : : }
2128 : : break;
2129 : 29 : case OMP_TRAIT_DEVICE_ARCH:
2130 : 29 : if (targetm.omp.device_kind_arch_isa != NULL)
2131 : 58 : for (tree p = properties; p && result; p = TREE_CHAIN (p))
2132 : : {
2133 : 29 : const char *prop = omp_context_name_list_prop (p);
2134 : 29 : if (prop == NULL)
2135 : : result = 0;
2136 : : else
2137 : 29 : result = targetm.omp.device_kind_arch_isa (omp_device_arch,
2138 : : prop);
2139 : 29 : if (dump_file)
2140 : 0 : fprintf (dump_file, "Matching device arch %s = %s\n",
2141 : : prop, (result ? "true" : "false"));
2142 : : }
2143 : : else
2144 : : {
2145 : 0 : result = 0;
2146 : 0 : if (dump_file)
2147 : 0 : fprintf (dump_file, "Cannot match device arch on target\n");
2148 : : }
2149 : : break;
2150 : 16 : case OMP_TRAIT_DEVICE_ISA:
2151 : 16 : if (targetm.omp.device_kind_arch_isa != NULL)
2152 : 32 : for (tree p = properties; p && result; p = TREE_CHAIN (p))
2153 : : {
2154 : 16 : const char *prop = omp_context_name_list_prop (p);
2155 : 16 : if (prop == NULL)
2156 : : result = 0;
2157 : : else
2158 : 16 : result = targetm.omp.device_kind_arch_isa (omp_device_isa,
2159 : : prop);
2160 : 16 : if (dump_file)
2161 : 0 : fprintf (dump_file, "Matching device isa %s = %s\n",
2162 : : prop, (result ? "true" : "false"));
2163 : : }
2164 : : else
2165 : : {
2166 : 0 : result = 0;
2167 : 0 : if (dump_file)
2168 : 0 : fprintf (dump_file, "Cannot match device isa on target\n");
2169 : : }
2170 : : break;
2171 : 0 : default:
2172 : 0 : gcc_unreachable ();
2173 : : }
2174 : 153 : return result;
2175 : : }
2176 : :
2177 : : /* Called for late resolution of the OMP_TARGET_DEVICE_MATCHES tree node to
2178 : : a constant in omp-offload.cc. This is used in code that is wrapped in a
2179 : : #pragma omp target construct to execute on the specified device, and
2180 : : can be reduced to a compile-time constant in the offload compiler.
2181 : : NODE is an OMP_TARGET_DEVICE_MATCHES tree node and the result is an
2182 : : INTEGER_CST. */
2183 : : tree
2184 : 0 : resolve_omp_target_device_matches (tree node)
2185 : : {
2186 : 0 : tree sel = OMP_TARGET_DEVICE_MATCHES_SELECTOR (node);
2187 : 0 : enum omp_ts_code selector = (enum omp_ts_code) tree_to_shwi (sel);
2188 : 0 : tree properties = OMP_TARGET_DEVICE_MATCHES_PROPERTIES (node);
2189 : 0 : if (omp_target_device_matches_on_host (selector, properties))
2190 : 0 : return integer_one_node;
2191 : : else
2192 : 0 : return integer_zero_node;
2193 : : }
2194 : :
2195 : : /* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as
2196 : : in omp_context_selector_set_compare. If MATCH_P is true, additionally
2197 : : apply the special matching rules for the "simdlen" and "aligned" clauses
2198 : : used to determine whether the selector CLAUSES1 is part of matches
2199 : : the OpenMP context containing CLAUSES2. */
2200 : :
2201 : : static int
2202 : 58 : omp_construct_simd_compare (tree clauses1, tree clauses2, bool match_p)
2203 : : {
2204 : 58 : if (clauses1 == NULL_TREE)
2205 : 0 : return clauses2 == NULL_TREE ? 0 : -1;
2206 : 58 : if (clauses2 == NULL_TREE)
2207 : : return 1;
2208 : :
2209 : 102 : int r = 0;
2210 : 68 : struct declare_variant_simd_data {
2211 : : bool inbranch, notinbranch;
2212 : : tree simdlen;
2213 : : auto_vec<tree,16> data_sharing;
2214 : : auto_vec<tree,16> aligned;
2215 : 68 : declare_variant_simd_data ()
2216 : 68 : : inbranch(false), notinbranch(false), simdlen(NULL_TREE) {}
2217 : 238 : } data[2];
2218 : : unsigned int i;
2219 : : tree e0, e1;
2220 : 102 : for (i = 0; i < 2; i++)
2221 : 332 : for (tree c = i ? clauses2 : clauses1; c; c = OMP_CLAUSE_CHAIN (c))
2222 : : {
2223 : 196 : vec<tree> *v;
2224 : 196 : switch (OMP_CLAUSE_CODE (c))
2225 : : {
2226 : 12 : case OMP_CLAUSE_INBRANCH:
2227 : 12 : data[i].inbranch = true;
2228 : 12 : continue;
2229 : 40 : case OMP_CLAUSE_NOTINBRANCH:
2230 : 40 : data[i].notinbranch = true;
2231 : 40 : continue;
2232 : 68 : case OMP_CLAUSE_SIMDLEN:
2233 : 68 : data[i].simdlen = OMP_CLAUSE_SIMDLEN_EXPR (c);
2234 : 68 : continue;
2235 : 52 : case OMP_CLAUSE_UNIFORM:
2236 : 52 : case OMP_CLAUSE_LINEAR:
2237 : 52 : v = &data[i].data_sharing;
2238 : 52 : break;
2239 : 24 : case OMP_CLAUSE_ALIGNED:
2240 : 24 : v = &data[i].aligned;
2241 : 24 : break;
2242 : 0 : default:
2243 : 0 : gcc_unreachable ();
2244 : : }
2245 : 76 : unsigned HOST_WIDE_INT argno = tree_to_uhwi (OMP_CLAUSE_DECL (c));
2246 : 76 : if (argno >= v->length ())
2247 : 76 : v->safe_grow_cleared (argno + 1, true);
2248 : 76 : (*v)[argno] = c;
2249 : : }
2250 : : /* Here, r is used as a bitmask, 2 is set if CLAUSES1 has something
2251 : : CLAUSES2 doesn't, 1 is set if CLAUSES2 has something CLAUSES1
2252 : : doesn't. Thus, r == 3 implies return value 2, r == 1 implies
2253 : : -1, r == 2 implies 1 and r == 0 implies 0. */
2254 : 34 : if (data[0].inbranch != data[1].inbranch)
2255 : 0 : r |= data[0].inbranch ? 2 : 1;
2256 : 34 : if (data[0].notinbranch != data[1].notinbranch)
2257 : 16 : r |= data[0].notinbranch ? 2 : 1;
2258 : 34 : e0 = data[0].simdlen;
2259 : 34 : e1 = data[1].simdlen;
2260 : 34 : if (!simple_cst_equal (e0, e1))
2261 : : {
2262 : 8 : if (e0 && e1)
2263 : : {
2264 : 8 : if (match_p && tree_fits_uhwi_p (e0) && tree_fits_uhwi_p (e1))
2265 : : {
2266 : : /* The two simdlen clauses match if m is a multiple of n. */
2267 : 8 : unsigned HOST_WIDE_INT n = tree_to_uhwi (e0);
2268 : 8 : unsigned HOST_WIDE_INT m = tree_to_uhwi (e1);
2269 : 8 : if (m % n != 0)
2270 : : return 2;
2271 : : }
2272 : : else
2273 : : return 2;
2274 : : }
2275 : 0 : r |= data[0].simdlen ? 2 : 1;
2276 : : }
2277 : 78 : if (data[0].data_sharing.length () < data[1].data_sharing.length ()
2278 : 52 : || data[0].aligned.length () < data[1].aligned.length ())
2279 : 0 : r |= 1;
2280 : : tree c1, c2;
2281 : 90 : FOR_EACH_VEC_ELT (data[0].data_sharing, i, c1)
2282 : : {
2283 : 72 : c2 = (i < data[1].data_sharing.length ()
2284 : 120 : ? data[1].data_sharing[i] : NULL_TREE);
2285 : 72 : if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
2286 : : {
2287 : 8 : r |= c1 != NULL_TREE ? 2 : 1;
2288 : 8 : continue;
2289 : : }
2290 : 64 : if (c1 == NULL_TREE)
2291 : 46 : continue;
2292 : 18 : if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_CODE (c2))
2293 : : return 2;
2294 : 13 : if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_LINEAR)
2295 : 7 : continue;
2296 : 6 : if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1)
2297 : 6 : != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2))
2298 : : return 2;
2299 : 6 : if (OMP_CLAUSE_LINEAR_KIND (c1) != OMP_CLAUSE_LINEAR_KIND (c2))
2300 : : return 2;
2301 : 6 : if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1),
2302 : 6 : OMP_CLAUSE_LINEAR_STEP (c2)))
2303 : : return 2;
2304 : : }
2305 : 55 : FOR_EACH_VEC_ELT (data[0].aligned, i, c1)
2306 : : {
2307 : 60 : c2 = i < data[1].aligned.length () ? data[1].aligned[i] : NULL_TREE;
2308 : 42 : if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
2309 : : {
2310 : 8 : r |= c1 != NULL_TREE ? 2 : 1;
2311 : 8 : continue;
2312 : : }
2313 : 34 : if (c1 == NULL_TREE)
2314 : 28 : continue;
2315 : 6 : e0 = OMP_CLAUSE_ALIGNED_ALIGNMENT (c1);
2316 : 6 : e1 = OMP_CLAUSE_ALIGNED_ALIGNMENT (c2);
2317 : 6 : if (!simple_cst_equal (e0, e1))
2318 : : {
2319 : 5 : if (e0 && e1
2320 : 1 : && match_p && tree_fits_uhwi_p (e0) && tree_fits_uhwi_p (e1))
2321 : : {
2322 : : /* The two aligned clauses match if n is a multiple of m. */
2323 : 0 : unsigned HOST_WIDE_INT n = tree_to_uhwi (e0);
2324 : 0 : unsigned HOST_WIDE_INT m = tree_to_uhwi (e1);
2325 : 0 : if (n % m != 0)
2326 : : return 2;
2327 : : }
2328 : : else
2329 : : return 2;
2330 : : }
2331 : : }
2332 : 13 : switch (r)
2333 : : {
2334 : : case 0: return 0;
2335 : 0 : case 1: return -1;
2336 : 8 : case 2: return 1;
2337 : : case 3: return 2;
2338 : 0 : default: gcc_unreachable ();
2339 : : }
2340 : 102 : }
2341 : :
2342 : : /* Compare properties of selectors SEL from SET other than construct.
2343 : : CTX1 and CTX2 are the lists of properties to compare.
2344 : : Return 0/-1/1/2 as in omp_context_selector_set_compare.
2345 : : Unlike set names or selector names, properties can have duplicates. */
2346 : :
2347 : : static int
2348 : 155 : omp_context_selector_props_compare (enum omp_tss_code set,
2349 : : enum omp_ts_code sel,
2350 : : tree ctx1, tree ctx2)
2351 : : {
2352 : 155 : int ret = 0;
2353 : 326 : for (int pass = 0; pass < 2; pass++)
2354 : 662 : for (tree p1 = pass ? ctx2 : ctx1; p1; p1 = TREE_CHAIN (p1))
2355 : : {
2356 : 253 : tree p2;
2357 : 576 : for (p2 = pass ? ctx1 : ctx2; p2; p2 = TREE_CHAIN (p2))
2358 : 313 : if (OMP_TP_NAME (p1) == OMP_TP_NAME (p2))
2359 : : {
2360 : 313 : if (OMP_TP_NAME (p1) == NULL_TREE)
2361 : : {
2362 : 173 : if (set == OMP_TRAIT_SET_USER
2363 : 173 : && sel == OMP_TRAIT_USER_CONDITION)
2364 : : {
2365 : : /* Recognize constants that have equal truth values,
2366 : : otherwise assume all expressions are unique. */
2367 : 122 : tree v1 = OMP_TP_VALUE (p1);
2368 : 122 : tree v2 = OMP_TP_VALUE (p2);
2369 : 122 : if (TREE_CODE (v1) != INTEGER_CST
2370 : 106 : || TREE_CODE (v2) != INTEGER_CST
2371 : 228 : || integer_zerop (v1) != integer_zerop (v2))
2372 : 16 : return 2;
2373 : : break;
2374 : : }
2375 : 51 : if (set == OMP_TRAIT_SET_TARGET_DEVICE
2376 : 51 : && sel == OMP_TRAIT_DEVICE_NUM)
2377 : : {
2378 : : /* Recognize constants that have equal values,
2379 : : otherwise assume all expressions are unique. */
2380 : 51 : tree v1 = OMP_TP_VALUE (p1);
2381 : 51 : tree v2 = OMP_TP_VALUE (p2);
2382 : 51 : if (TREE_CODE (v1) != INTEGER_CST
2383 : 0 : || TREE_CODE (v2) != INTEGER_CST
2384 : 51 : || tree_int_cst_compare (v1, v2) != 0)
2385 : 51 : return 2;
2386 : : break;
2387 : : }
2388 : 0 : if (simple_cst_equal (OMP_TP_VALUE (p1), OMP_TP_VALUE (p2)))
2389 : : break;
2390 : : }
2391 : 140 : else if (OMP_TP_NAME (p1) == OMP_TP_NAMELIST_NODE)
2392 : : {
2393 : : /* Handle string constant vs identifier comparison for
2394 : : name-list properties. */
2395 : 140 : const char *n1 = omp_context_name_list_prop (p1);
2396 : 140 : const char *n2 = omp_context_name_list_prop (p2);
2397 : 140 : if (n1 && n2 && !strcmp (n1, n2))
2398 : : break;
2399 : : }
2400 : : else
2401 : : break;
2402 : : }
2403 : 176 : if (p2 == NULL_TREE)
2404 : : {
2405 : 10 : int r = pass ? -1 : 1;
2406 : 10 : if (ret && ret != r)
2407 : : return 2;
2408 : 10 : else if (pass)
2409 : : return r;
2410 : : else
2411 : : {
2412 : : ret = r;
2413 : : break;
2414 : : }
2415 : : }
2416 : : }
2417 : : return ret;
2418 : : }
2419 : :
2420 : : /* Compare single context selector sets CTX1 and CTX2 with SET name.
2421 : : CTX1 and CTX2 are lists of trait-selectors.
2422 : : Return 0 if CTX1 is equal to CTX2,
2423 : : -1 if CTX1 is a strict subset of CTX2,
2424 : : 1 if CTX2 is a strict subset of CTX1, or
2425 : : 2 if neither context is a subset of another one. */
2426 : :
2427 : : static int
2428 : 2617 : omp_context_selector_set_compare (enum omp_tss_code set, tree ctx1, tree ctx2)
2429 : : {
2430 : :
2431 : : /* If either list includes an ignored selector trait, neither can
2432 : : be a subset of the other. */
2433 : 5486 : for (tree ts = ctx1; ts; ts = TREE_CHAIN (ts))
2434 : 2869 : if (OMP_TS_CODE (ts) == OMP_TRAIT_INVALID)
2435 : : return 2;
2436 : 5513 : for (tree ts = ctx2; ts; ts = TREE_CHAIN (ts))
2437 : 2896 : if (OMP_TS_CODE (ts) == OMP_TRAIT_INVALID)
2438 : : return 2;
2439 : :
2440 : 2617 : bool swapped = false;
2441 : 2617 : int ret = 0;
2442 : 2617 : int len1 = list_length (ctx1);
2443 : 2617 : int len2 = list_length (ctx2);
2444 : 2617 : int cnt = 0;
2445 : 2617 : if (len1 < len2)
2446 : : {
2447 : 76 : swapped = true;
2448 : 76 : std::swap (ctx1, ctx2);
2449 : 76 : std::swap (len1, len2);
2450 : : }
2451 : :
2452 : 2617 : if (set == OMP_TRAIT_SET_CONSTRUCT)
2453 : : {
2454 : : tree ts1;
2455 : : tree ts2 = ctx2;
2456 : : /* Handle construct set specially. In this case the order
2457 : : of the selector matters too. */
2458 : 376 : for (ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
2459 : 368 : if (OMP_TS_CODE (ts1) == OMP_TS_CODE (ts2))
2460 : : {
2461 : 286 : int r = 0;
2462 : 286 : if (OMP_TS_CODE (ts1) == OMP_TRAIT_CONSTRUCT_SIMD)
2463 : 18 : r = omp_construct_simd_compare (OMP_TS_PROPERTIES (ts1),
2464 : 18 : OMP_TS_PROPERTIES (ts2),
2465 : : false);
2466 : 286 : if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
2467 : 13 : return 2;
2468 : 273 : if (ret == 0)
2469 : 192 : ret = r;
2470 : 273 : ts2 = TREE_CHAIN (ts2);
2471 : 273 : if (ts2 == NULL_TREE)
2472 : : {
2473 : 194 : ts1 = TREE_CHAIN (ts1);
2474 : 194 : break;
2475 : : }
2476 : : }
2477 : 82 : else if (ret < 0)
2478 : : return 2;
2479 : : else
2480 : : ret = 1;
2481 : 202 : if (ts2 != NULL_TREE)
2482 : : return 2;
2483 : 194 : if (ts1 != NULL_TREE)
2484 : : {
2485 : 36 : if (ret < 0)
2486 : : return 2;
2487 : : ret = 1;
2488 : : }
2489 : 158 : if (ret == 0)
2490 : : return 0;
2491 : 89 : return swapped ? -ret : ret;
2492 : : }
2493 : 2597 : for (tree ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
2494 : : {
2495 : 2422 : enum omp_ts_code sel = OMP_TS_CODE (ts1);
2496 : 2422 : tree ts2;
2497 : 2539 : for (ts2 = ctx2; ts2; ts2 = TREE_CHAIN (ts2))
2498 : 2432 : if (sel == OMP_TS_CODE (ts2))
2499 : : {
2500 : 2315 : tree score1 = OMP_TS_SCORE (ts1);
2501 : 2315 : tree score2 = OMP_TS_SCORE (ts2);
2502 : 2144 : if ((score1 && score2 && !simple_cst_equal (score1, score2))
2503 : 171 : || (score1 && !score2)
2504 : 2479 : || (!score1 && score2))
2505 : 2160 : return 2;
2506 : :
2507 : 310 : int r = omp_context_selector_props_compare (set, OMP_TS_CODE (ts1),
2508 : 155 : OMP_TS_PROPERTIES (ts1),
2509 : 155 : OMP_TS_PROPERTIES (ts2));
2510 : 155 : if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
2511 : : return 2;
2512 : 88 : if (ret == 0)
2513 : 83 : ret = r;
2514 : 88 : cnt++;
2515 : 88 : break;
2516 : : }
2517 : 195 : if (ts2 == NULL_TREE)
2518 : : {
2519 : 107 : if (ret == -1)
2520 : : return 2;
2521 : : ret = 1;
2522 : : }
2523 : : }
2524 : 175 : if (cnt < len2)
2525 : : return 2;
2526 : 83 : if (ret == 0)
2527 : : return 0;
2528 : 20 : return swapped ? -ret : ret;
2529 : : }
2530 : :
2531 : : /* Compare whole context selector specification CTX1 and CTX2.
2532 : : Return 0 if CTX1 is equal to CTX2,
2533 : : -1 if CTX1 is a strict subset of CTX2,
2534 : : 1 if CTX2 is a strict subset of CTX1, or
2535 : : 2 if neither context is a subset of another one. */
2536 : :
2537 : : static int
2538 : 3669 : omp_context_selector_compare (tree ctx1, tree ctx2)
2539 : : {
2540 : 3669 : bool swapped = false;
2541 : 3669 : int ret = 0;
2542 : 3669 : int len1 = list_length (ctx1);
2543 : 3669 : int len2 = list_length (ctx2);
2544 : 3669 : int cnt = 0;
2545 : 3669 : if (len1 < len2)
2546 : : {
2547 : 89 : swapped = true;
2548 : 89 : std::swap (ctx1, ctx2);
2549 : 89 : std::swap (len1, len2);
2550 : : }
2551 : 5249 : for (tree tss1 = ctx1; tss1; tss1 = TREE_CHAIN (tss1))
2552 : : {
2553 : 3914 : enum omp_tss_code set = OMP_TSS_CODE (tss1);
2554 : 3914 : tree tss2;
2555 : 5352 : for (tss2 = ctx2; tss2; tss2 = TREE_CHAIN (tss2))
2556 : 3940 : if (set == OMP_TSS_CODE (tss2))
2557 : : {
2558 : 2502 : int r
2559 : : = omp_context_selector_set_compare
2560 : 5004 : (set, OMP_TSS_TRAIT_SELECTORS (tss1),
2561 : 2502 : OMP_TSS_TRAIT_SELECTORS (tss2));
2562 : 2502 : if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
2563 : : return 2;
2564 : 183 : if (ret == 0)
2565 : 130 : ret = r;
2566 : 183 : cnt++;
2567 : 183 : break;
2568 : : }
2569 : 1595 : if (tss2 == NULL_TREE)
2570 : : {
2571 : 1412 : if (ret == -1)
2572 : : return 2;
2573 : : ret = 1;
2574 : : }
2575 : : }
2576 : 1335 : if (cnt < len2)
2577 : : return 2;
2578 : 147 : if (ret == 0)
2579 : : return 0;
2580 : 147 : return swapped ? -ret : ret;
2581 : : }
2582 : :
2583 : : /* From context selector CTX, return trait-selector with name SEL in
2584 : : trait-selector-set with name SET if any, or NULL_TREE if not found. */
2585 : : tree
2586 : 6741 : omp_get_context_selector (tree ctx, enum omp_tss_code set,
2587 : : enum omp_ts_code sel)
2588 : : {
2589 : 11889 : for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
2590 : 7375 : if (OMP_TSS_CODE (tss) == set)
2591 : 5021 : for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
2592 : 3955 : if (OMP_TS_CODE (ts) == sel)
2593 : : return ts;
2594 : : return NULL_TREE;
2595 : : }
2596 : :
2597 : : /* Similar, but returns the whole trait-selector list for SET in CTX. */
2598 : : tree
2599 : 4545 : omp_get_context_selector_list (tree ctx, enum omp_tss_code set)
2600 : : {
2601 : 8403 : for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
2602 : 4983 : if (OMP_TSS_CODE (tss) == set)
2603 : 1125 : return OMP_TSS_TRAIT_SELECTORS (tss);
2604 : : return NULL_TREE;
2605 : : }
2606 : :
2607 : : /* Map string S onto a trait selector set code. */
2608 : : enum omp_tss_code
2609 : 3322 : omp_lookup_tss_code (const char * s)
2610 : : {
2611 : 8949 : for (int i = 0; i < OMP_TRAIT_SET_LAST; i++)
2612 : 8926 : if (strcmp (s, omp_tss_map[i]) == 0)
2613 : : return (enum omp_tss_code) i;
2614 : : return OMP_TRAIT_SET_INVALID;
2615 : : }
2616 : :
2617 : : /* Map string S onto a trait selector code for set SET. */
2618 : : enum omp_ts_code
2619 : 4065 : omp_lookup_ts_code (enum omp_tss_code set, const char *s)
2620 : : {
2621 : 4065 : unsigned int mask = 1 << set;
2622 : 45056 : for (int i = 0; i < OMP_TRAIT_LAST; i++)
2623 : 44967 : if ((mask & omp_ts_map[i].tss_mask) != 0
2624 : 10974 : && strcmp (s, omp_ts_map[i].name) == 0)
2625 : : return (enum omp_ts_code) i;
2626 : : return OMP_TRAIT_INVALID;
2627 : : }
2628 : :
2629 : :
2630 : : /* Return true if the selector CTX is dynamic. */
2631 : : static bool
2632 : 3353 : omp_selector_is_dynamic (tree ctx)
2633 : : {
2634 : 3353 : tree user_sel = omp_get_context_selector (ctx, OMP_TRAIT_SET_USER,
2635 : : OMP_TRAIT_USER_CONDITION);
2636 : 3353 : if (user_sel)
2637 : : {
2638 : 1394 : tree expr = OMP_TP_VALUE (OMP_TS_PROPERTIES (user_sel));
2639 : :
2640 : : /* The user condition is not dynamic if it is constant. */
2641 : 1394 : if (!tree_fits_shwi_p (expr))
2642 : : return true;
2643 : : }
2644 : :
2645 : 2240 : tree target_device_ss
2646 : 2240 : = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_TARGET_DEVICE);
2647 : 2240 : if (target_device_ss)
2648 : : return true;
2649 : :
2650 : : return false;
2651 : : }
2652 : :
2653 : : /* Helper function for omp_dynamic_cond: return a boolean tree expression
2654 : : that tests whether *DEVICE_NUM is a "conforming device number other
2655 : : than omp_invalid_device". This may modify *DEVICE_NUM (i.e, to be
2656 : : a save_expr). *IS_HOST is set to true if the device can be statically
2657 : : determined to be the host. */
2658 : :
2659 : : static tree
2660 : 91 : omp_device_num_check (tree *device_num, bool *is_host)
2661 : : {
2662 : : /* First check for some constant values we can treat specially. */
2663 : 91 : if (tree_fits_shwi_p (*device_num))
2664 : : {
2665 : 32 : HOST_WIDE_INT num = tree_to_shwi (*device_num);
2666 : 32 : if (num < -1)
2667 : 4 : return integer_zero_node;
2668 : : /* Initial device? */
2669 : 28 : if (num == -1)
2670 : : {
2671 : 20 : *is_host = true;
2672 : 20 : return integer_one_node;
2673 : : }
2674 : : /* There is always at least one device (the host + offload devices). */
2675 : 8 : if (num == 0)
2676 : 4 : return integer_one_node;
2677 : : /* If there is no offloading, there is exactly one device. */
2678 : 4 : if (!ENABLE_OFFLOADING && num > 0)
2679 : 4 : return integer_zero_node;
2680 : : }
2681 : :
2682 : : /* Also test for direct calls to OpenMP routines that return valid
2683 : : device numbers. */
2684 : 59 : if (TREE_CODE (*device_num) == CALL_EXPR)
2685 : : {
2686 : 20 : tree fndecl = get_callee_fndecl (*device_num);
2687 : 20 : if (fndecl && omp_runtime_api_call (fndecl))
2688 : : {
2689 : 20 : const char *fnname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
2690 : 20 : if (strcmp (fnname, "omp_get_default_device") == 0
2691 : 12 : || strcmp (fnname, "omp_get_device_num") == 0)
2692 : 12 : return integer_one_node;
2693 : 8 : if (strcmp (fnname, "omp_get_num_devices") == 0
2694 : 4 : || strcmp (fnname, "omp_get_initial_device") == 0)
2695 : : {
2696 : 8 : *is_host = true;
2697 : 8 : return integer_one_node;
2698 : : }
2699 : : }
2700 : : }
2701 : :
2702 : : /* Otherwise, test that -1 <= *device_num <= omp_get_num_devices (). */
2703 : 39 : *device_num = save_expr (*device_num);
2704 : 39 : tree lotest = build2 (GE_EXPR, integer_type_node, *device_num,
2705 : : integer_minus_one_node);
2706 : 39 : tree fndecl = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_DEVICES);
2707 : 39 : tree hitest = build2 (LE_EXPR, integer_type_node, *device_num,
2708 : : build_call_expr (fndecl, 0));
2709 : 39 : return build2 (TRUTH_ANDIF_EXPR, integer_type_node, lotest, hitest);
2710 : : }
2711 : :
2712 : : /* Return a tree expression representing the dynamic part of the context
2713 : : selector CTX. SUPERCONTEXT is the surrounding BLOCK, in case we need
2714 : : to introduce a new BLOCK in the result. */
2715 : : tree
2716 : 453 : omp_dynamic_cond (tree ctx, tree supercontext)
2717 : : {
2718 : 453 : tree user_cond = NULL_TREE, target_device_cond = NULL_TREE;
2719 : :
2720 : : /* Build the "user" part of the dynamic selector. This is a test
2721 : : predicate taken directly for the "condition" trait in this set. */
2722 : 453 : tree user_sel = omp_get_context_selector (ctx, OMP_TRAIT_SET_USER,
2723 : : OMP_TRAIT_USER_CONDITION);
2724 : 453 : if (user_sel)
2725 : : {
2726 : 113 : tree expr = OMP_TP_VALUE (OMP_TS_PROPERTIES (user_sel));
2727 : :
2728 : : /* The user condition is not dynamic if it is constant. */
2729 : 113 : if (!tree_fits_shwi_p (expr))
2730 : 453 : user_cond = expr;
2731 : : }
2732 : :
2733 : : /* Build the "target_device" part of the dynamic selector. In the
2734 : : most general case this requires building a bit of code that runs
2735 : : on the specified device_num using the same mechanism as
2736 : : "#pragma omp target" that uses the OMP_TARGET_DEVICE_MATCHES magic
2737 : : cookie to represent the kind/arch/isa tests which are and'ed together.
2738 : : These cookies can be resolved into a constant truth value by the
2739 : : offload compiler; see resolve_omp_target_device_matches, above.
2740 : :
2741 : : In some cases, we can (in)validate the device number in advance.
2742 : : If it is not valid, the whole selector fails to match. If it is
2743 : : valid and refers to the host (e.g., constant -1), then we can
2744 : : resolve the match to a constant truth value now instead of having
2745 : : to create a OMP_TARGET_DEVICE_MATCHES. */
2746 : :
2747 : 453 : tree target_device_ss
2748 : 453 : = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_TARGET_DEVICE);
2749 : 453 : if (target_device_ss)
2750 : : {
2751 : 126 : tree device_num = NULL_TREE;
2752 : 126 : tree kind = NULL_TREE;
2753 : 126 : tree arch = NULL_TREE;
2754 : 126 : tree isa = NULL_TREE;
2755 : 126 : tree device_ok = NULL_TREE;
2756 : 126 : bool is_host = !ENABLE_OFFLOADING;
2757 : :
2758 : 126 : tree device_num_sel
2759 : 126 : = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
2760 : : OMP_TRAIT_DEVICE_NUM);
2761 : 126 : if (device_num_sel)
2762 : : {
2763 : 91 : device_num = OMP_TP_VALUE (OMP_TS_PROPERTIES (device_num_sel));
2764 : 91 : device_ok = omp_device_num_check (&device_num, &is_host);
2765 : : /* If an invalid constant device number was specified, the
2766 : : whole selector fails to match, and there's no point in
2767 : : continuing to generate code that would never be executed. */
2768 : 91 : if (device_ok == integer_zero_node)
2769 : : {
2770 : 8 : target_device_cond = integer_zero_node;
2771 : 51 : goto wrapup;
2772 : : }
2773 : : }
2774 : :
2775 : 118 : tree kind_sel
2776 : 118 : = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
2777 : : OMP_TRAIT_DEVICE_KIND);
2778 : : /* "any" is equivalent to omitting this trait selector. */
2779 : 118 : if (kind_sel
2780 : 228 : && strcmp (omp_context_name_list_prop (OMP_TS_PROPERTIES (kind_sel)),
2781 : : "any"))
2782 : : {
2783 : 108 : tree props = OMP_TS_PROPERTIES (kind_sel);
2784 : 108 : if (!is_host)
2785 : 0 : kind = build2 (OMP_TARGET_DEVICE_MATCHES, integer_type_node,
2786 : 0 : build_int_cst (integer_type_node,
2787 : 0 : (int) OMP_TRAIT_DEVICE_KIND),
2788 : : props);
2789 : 108 : else if (!omp_target_device_matches_on_host (OMP_TRAIT_DEVICE_KIND,
2790 : : props))
2791 : : {
2792 : : /* The whole selector fails to match. */
2793 : 43 : target_device_cond = integer_zero_node;
2794 : 43 : goto wrapup;
2795 : : }
2796 : : /* else it is statically resolved to true and is a no-op. */
2797 : : }
2798 : 75 : tree arch_sel
2799 : 75 : = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
2800 : : OMP_TRAIT_DEVICE_ARCH);
2801 : 75 : if (arch_sel)
2802 : : {
2803 : 29 : tree props = OMP_TS_PROPERTIES (arch_sel);
2804 : 29 : if (!is_host)
2805 : 0 : arch = build2 (OMP_TARGET_DEVICE_MATCHES, integer_type_node,
2806 : 0 : build_int_cst (integer_type_node,
2807 : 0 : (int) OMP_TRAIT_DEVICE_ARCH),
2808 : : props);
2809 : 29 : else if (!omp_target_device_matches_on_host (OMP_TRAIT_DEVICE_ARCH,
2810 : : props))
2811 : : {
2812 : : /* The whole selector fails to match. */
2813 : 0 : target_device_cond = integer_zero_node;
2814 : 0 : goto wrapup;
2815 : : }
2816 : : /* else it is statically resolved to true and is a no-op. */
2817 : : }
2818 : :
2819 : 75 : tree isa_sel
2820 : 75 : = omp_get_context_selector (ctx, OMP_TRAIT_SET_TARGET_DEVICE,
2821 : : OMP_TRAIT_DEVICE_ISA);
2822 : 75 : if (isa_sel)
2823 : : {
2824 : 16 : tree props = OMP_TS_PROPERTIES (isa_sel);
2825 : 16 : if (!is_host)
2826 : 0 : isa = build2 (OMP_TARGET_DEVICE_MATCHES, integer_type_node,
2827 : 0 : build_int_cst (integer_type_node,
2828 : 0 : (int) OMP_TRAIT_DEVICE_ISA),
2829 : : props);
2830 : 16 : else if (!omp_target_device_matches_on_host (OMP_TRAIT_DEVICE_ISA,
2831 : : props))
2832 : : {
2833 : : /* The whole selector fails to match. */
2834 : 0 : target_device_cond = integer_zero_node;
2835 : 0 : goto wrapup;
2836 : : }
2837 : : /* else it is statically resolved to true and is a no-op. */
2838 : : }
2839 : :
2840 : : /* AND the three possible tests together. */
2841 : 75 : tree test_expr = kind ? kind : NULL_TREE;
2842 : 75 : if (arch && test_expr)
2843 : 0 : test_expr = build2 (TRUTH_ANDIF_EXPR, integer_type_node,
2844 : : arch, test_expr);
2845 : 75 : else if (arch)
2846 : 0 : test_expr = arch;
2847 : 75 : if (isa && test_expr)
2848 : 0 : test_expr = build2 (TRUTH_ANDIF_EXPR, integer_type_node,
2849 : : isa, test_expr);
2850 : 75 : else if (isa)
2851 : : test_expr = isa;
2852 : :
2853 : 75 : if (!test_expr)
2854 : : /* This could happen if the selector includes only kind="any",
2855 : : or is_host is true and it could be statically determined to
2856 : : be true. The selector always matches, but we still have to
2857 : : evaluate the device_num expression. */
2858 : : {
2859 : 75 : if (device_num)
2860 : 55 : target_device_cond = build2 (COMPOUND_EXPR, integer_type_node,
2861 : : device_num, integer_one_node);
2862 : : else
2863 : 20 : target_device_cond = integer_one_node;
2864 : : }
2865 : : else
2866 : : {
2867 : : /* Arrange to evaluate test_expr in the offload compiler for
2868 : : device device_num. */
2869 : 0 : tree stmt = make_node (OMP_TARGET);
2870 : 0 : TREE_TYPE (stmt) = void_type_node;
2871 : 0 : tree result_var = create_tmp_var (integer_type_node, "td_match");
2872 : 0 : tree map = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_MAP);
2873 : 0 : OMP_CLAUSE_DECL (map) = result_var;
2874 : 0 : OMP_CLAUSE_SET_MAP_KIND (map, GOMP_MAP_FROM);
2875 : 0 : OMP_TARGET_CLAUSES (stmt) = map;
2876 : 0 : if (device_num)
2877 : : {
2878 : 0 : tree clause = build_omp_clause (UNKNOWN_LOCATION,
2879 : : OMP_CLAUSE_DEVICE);
2880 : 0 : OMP_CLAUSE_CHAIN (clause) = NULL_TREE;
2881 : 0 : OMP_CLAUSE_DEVICE_ID (clause) = device_num;
2882 : 0 : OMP_CLAUSE_DEVICE_ANCESTOR (clause) = false;
2883 : 0 : OMP_CLAUSE_CHAIN (map) = clause;
2884 : : }
2885 : :
2886 : 0 : tree block = make_node (BLOCK);
2887 : 0 : BLOCK_SUPERCONTEXT (block) = supercontext;
2888 : :
2889 : 0 : tree bind = build3 (BIND_EXPR, void_type_node, NULL_TREE,
2890 : : build2 (MODIFY_EXPR, integer_type_node,
2891 : : result_var, test_expr),
2892 : : block);
2893 : 0 : TREE_SIDE_EFFECTS (bind) = 1;
2894 : 0 : OMP_TARGET_BODY (stmt) = bind;
2895 : 0 : target_device_cond = build2 (COMPOUND_EXPR, integer_type_node,
2896 : : stmt, result_var);
2897 : :
2898 : : /* If necessary, "and" target_device_cond with the test to
2899 : : make sure the device number is valid. */
2900 : 0 : if (device_ok && device_ok != integer_one_node)
2901 : 0 : target_device_cond = build2 (TRUTH_ANDIF_EXPR, integer_type_node,
2902 : : device_ok, target_device_cond);
2903 : :
2904 : : /* Set the bit to trigger resolution of OMP_TARGET_DEVICE_MATCHES
2905 : : in the ompdevlow pass. */
2906 : 0 : if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
2907 : 0 : cgraph_node::get (cfun->decl)->has_omp_variant_constructs = 1;
2908 : : }
2909 : : }
2910 : :
2911 : 327 : wrapup:
2912 : 453 : if (user_cond && target_device_cond)
2913 : 0 : return build2 (TRUTH_ANDIF_EXPR, integer_type_node,
2914 : 0 : user_cond, target_device_cond);
2915 : 453 : else if (user_cond)
2916 : 113 : return user_cond;
2917 : : else if (target_device_cond)
2918 : : return target_device_cond;
2919 : : else
2920 : : return NULL_TREE;
2921 : : }
2922 : :
2923 : :
2924 : : /* Given an omp_variant VARIANT, compute VARIANT->score and
2925 : : VARIANT->scorable.
2926 : : CONSTRUCT_CONTEXT is the OpenMP construct context; if this is null or
2927 : : COMPLETE_P is false (e.g., during parsing or gimplification) then it
2928 : : may not be possible to compute the score accurately and the scorable
2929 : : flag is set to false.
2930 : :
2931 : : Cited text in the comments is from section 7.2 of the OpenMP 5.2
2932 : : specification. */
2933 : :
2934 : : static void
2935 : 3353 : omp_context_compute_score (struct omp_variant *variant,
2936 : : tree construct_context, bool complete_p)
2937 : : {
2938 : 3353 : int l = list_length (construct_context);
2939 : 3353 : tree ctx = variant->selector;
2940 : 3353 : variant->scorable = true;
2941 : :
2942 : : /* "the final score is the sum of the values of all specified selectors
2943 : : plus 1". */
2944 : 3353 : variant->score = 1;
2945 : 7141 : for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
2946 : : {
2947 : 3788 : if (OMP_TSS_CODE (tss) == OMP_TRAIT_SET_CONSTRUCT)
2948 : : {
2949 : : /* "Each trait selector for which the corresponding trait appears
2950 : : in the context trait set in the OpenMP context..." */
2951 : 1371 : score_wide_int tss_score = 0;
2952 : 1371 : omp_construct_traits_match (OMP_TSS_TRAIT_SELECTORS (tss),
2953 : : construct_context, &tss_score);
2954 : 1371 : variant->score += tss_score;
2955 : 1371 : if (!complete_p)
2956 : 4 : variant->scorable = false;
2957 : : }
2958 : 2417 : else if (OMP_TSS_CODE (tss) == OMP_TRAIT_SET_DEVICE
2959 : 2417 : || OMP_TSS_CODE (tss) == OMP_TRAIT_SET_TARGET_DEVICE)
2960 : : {
2961 : : /* "The kind, arch, and isa selectors, if specified, are given
2962 : : the values 2**l, 2**(l+1), and 2**(l+2), respectively..."
2963 : : FIXME: the spec isn't clear what should happen if there are
2964 : : both "device" and "target_device" selector sets specified.
2965 : : This implementation adds up the bits rather than ORs them. */
2966 : 1412 : for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
2967 : 834 : ts = TREE_CHAIN (ts))
2968 : : {
2969 : 834 : enum omp_ts_code code = OMP_TS_CODE (ts);
2970 : 834 : if (code == OMP_TRAIT_DEVICE_KIND)
2971 : 449 : variant->score
2972 : 449 : += wi::shifted_mask <score_wide_int> (l, 1, false);
2973 : 385 : else if (code == OMP_TRAIT_DEVICE_ARCH)
2974 : 119 : variant->score
2975 : 119 : += wi::shifted_mask <score_wide_int> (l + 1, 1, false);
2976 : 266 : else if (code == OMP_TRAIT_DEVICE_ISA)
2977 : 151 : variant->score
2978 : 151 : += wi::shifted_mask <score_wide_int> (l + 2, 1, false);
2979 : : }
2980 : 578 : if (!complete_p)
2981 : 183 : variant->scorable = false;
2982 : : }
2983 : : else
2984 : : {
2985 : : /* "Trait selectors for which a trait-score is specified..."
2986 : : Note that there are no implementation-defined selectors, and
2987 : : "other selectors are given a value of zero". */
2988 : 3678 : for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
2989 : 1839 : ts = TREE_CHAIN (ts))
2990 : : {
2991 : 3229 : tree s = OMP_TS_SCORE (ts);
2992 : 1390 : if (s && TREE_CODE (s) == INTEGER_CST)
2993 : 1390 : variant->score
2994 : 2780 : += score_wide_int::from (wi::to_wide (s),
2995 : 2780 : TYPE_SIGN (TREE_TYPE (s)));
2996 : : }
2997 : : }
2998 : : }
2999 : 3353 : }
3000 : :
3001 : : /* CONSTRUCT_CONTEXT contains "the directive names, each being a trait,
3002 : : of all enclosing constructs at that point in the program up to a target
3003 : : construct", per section 7.1 of the 5.2 specification. The traits are
3004 : : collected during gimplification and are listed outermost first.
3005 : :
3006 : : This function attempts to apply the "if the point in the program is not
3007 : : enclosed by a target construct, the following rules are applied in order"
3008 : : requirements that follow in the same paragraph. This may not be possible,
3009 : : depending on the compilation phase; in particular, "declare simd" clones
3010 : : are not known until late resolution.
3011 : :
3012 : : The augmented context is returned, and *COMPLETEP is set to true if
3013 : : the context is known to be complete, false otherwise. */
3014 : : static tree
3015 : 4874 : omp_complete_construct_context (tree construct_context, bool *completep)
3016 : : {
3017 : : /* The point in the program is enclosed by a target construct. */
3018 : 4874 : if (construct_context
3019 : 7868 : && OMP_TS_CODE (construct_context) == OMP_TRAIT_CONSTRUCT_TARGET)
3020 : 162 : *completep = true;
3021 : :
3022 : : /* At parse time we have none of the information we need to collect
3023 : : the missing pieces. */
3024 : 4712 : else if (symtab->state == PARSING)
3025 : 696 : *completep = false;
3026 : :
3027 : : else
3028 : : {
3029 : 4016 : tree attributes = DECL_ATTRIBUTES (current_function_decl);
3030 : :
3031 : : /* Add simd trait when in a simd clone. This information is only
3032 : : available during late resolution in the omp_device_lower pass,
3033 : : however we can also rule out cases where we know earlier that
3034 : : cfun is not a candidate for cloning. */
3035 : 4016 : if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
3036 : : {
3037 : 304 : cgraph_node *node = cgraph_node::get (cfun->decl);
3038 : 304 : if (node->simdclone)
3039 : 288 : construct_context = make_trait_selector (OMP_TRAIT_CONSTRUCT_SIMD,
3040 : : NULL_TREE, NULL_TREE,
3041 : : construct_context);
3042 : 304 : *completep = true;
3043 : 304 : }
3044 : 3712 : else if (lookup_attribute ("omp declare simd", attributes))
3045 : 42 : *completep = false;
3046 : : else
3047 : 3670 : *completep = true;
3048 : :
3049 : : /* Add construct selector set within a "declare variant" function. */
3050 : 4016 : tree variant_attr
3051 : 4016 : = lookup_attribute ("omp declare variant variant", attributes);
3052 : 4016 : if (variant_attr)
3053 : : {
3054 : 20 : tree temp = NULL_TREE;
3055 : 40 : for (tree t = TREE_VALUE (variant_attr); t; t = TREE_CHAIN (t))
3056 : 20 : temp = chainon (temp, copy_node (t));
3057 : 20 : construct_context = chainon (temp, construct_context);
3058 : : }
3059 : :
3060 : : /* Add target trait when in a target variant. */
3061 : 4016 : if (lookup_attribute ("omp declare target", attributes))
3062 : 74 : construct_context = make_trait_selector (OMP_TRAIT_CONSTRUCT_TARGET,
3063 : : NULL_TREE, NULL_TREE,
3064 : : construct_context);
3065 : : }
3066 : 4874 : return construct_context;
3067 : : }
3068 : :
3069 : : /* Comparison function for sorting routines, to sort OpenMP metadirective
3070 : : variants by decreasing score. */
3071 : :
3072 : : static int
3073 : 11899 : sort_variant (const void * a, const void *b, void *)
3074 : : {
3075 : 11899 : score_wide_int score1
3076 : : = ((const struct omp_variant *) a)->score;
3077 : 11899 : score_wide_int score2
3078 : : = ((const struct omp_variant *) b)->score;
3079 : :
3080 : 11899 : if (score1 > score2)
3081 : : return -1;
3082 : 5191 : else if (score1 < score2)
3083 : : return 1;
3084 : : else
3085 : 267 : return 0;
3086 : : }
3087 : :
3088 : : /* Return a vector of dynamic replacement candidates for the directive
3089 : : candidates in ALL_VARIANTS. Return an empty vector if the candidates
3090 : : cannot be resolved. */
3091 : :
3092 : : vec<struct omp_variant>
3093 : 2589 : omp_get_dynamic_candidates (vec <struct omp_variant> &all_variants,
3094 : : tree construct_context)
3095 : : {
3096 : 2589 : auto_vec <struct omp_variant> variants;
3097 : 2589 : struct omp_variant default_variant;
3098 : 2589 : bool default_found = false;
3099 : 2589 : bool complete_p;
3100 : :
3101 : 2589 : construct_context
3102 : 2589 : = omp_complete_construct_context (construct_context, &complete_p);
3103 : :
3104 : 2589 : if (dump_file)
3105 : : {
3106 : 40 : fprintf (dump_file, "\nIn omp_get_dynamic_candidates:\n");
3107 : 40 : if (symtab->state == PARSING)
3108 : 40 : fprintf (dump_file, "invoked during parsing\n");
3109 : 0 : else if (cfun && (cfun->curr_properties & PROP_gimple_any) == 0)
3110 : 0 : fprintf (dump_file, "invoked during gimplification\n");
3111 : 0 : else if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
3112 : 0 : fprintf (dump_file, "invoked during late resolution\n");
3113 : : else
3114 : 0 : fprintf (dump_file, "confused about invocation context?!?\n");
3115 : 80 : fprintf (dump_file, "construct_context has %d traits (%s)\n",
3116 : 0 : (construct_context ? list_length (construct_context) : 0),
3117 : : (complete_p ? "complete" : "incomplete"));
3118 : : }
3119 : :
3120 : 8541 : for (unsigned int i = 0; i < all_variants.length (); i++)
3121 : : {
3122 : 6030 : struct omp_variant variant = all_variants[i];
3123 : :
3124 : 6030 : if (variant.selector == NULL_TREE)
3125 : : {
3126 : 2511 : gcc_assert (!default_found);
3127 : 2511 : default_found = true;
3128 : 2511 : default_variant = variant;
3129 : 2511 : default_variant.score = 0;
3130 : 2511 : default_variant.scorable = true;
3131 : 2511 : default_variant.matchable = true;
3132 : 2511 : default_variant.dynamic_selector = false;
3133 : 2511 : if (dump_file)
3134 : 16 : fprintf (dump_file,
3135 : : "Considering default selector as candidate\n");
3136 : 2511 : continue;
3137 : : }
3138 : :
3139 : 3519 : variant.matchable = true;
3140 : 3519 : variant.scorable = true;
3141 : :
3142 : 3519 : if (dump_file)
3143 : : {
3144 : 40 : fprintf (dump_file, "Considering selector ");
3145 : 40 : print_omp_context_selector (dump_file, variant.selector, TDF_NONE);
3146 : 40 : fprintf (dump_file, " as candidate - ");
3147 : : }
3148 : :
3149 : 3519 : switch (omp_context_selector_matches (variant.selector,
3150 : : construct_context, complete_p))
3151 : : {
3152 : 99 : case -1:
3153 : 99 : if (dump_file)
3154 : 24 : fprintf (dump_file, "unmatchable\n");
3155 : : /* At parse time, just give up if we can't determine whether
3156 : : things match. */
3157 : 99 : if (symtab->state == PARSING)
3158 : : {
3159 : 78 : variants.truncate (0);
3160 : 78 : return variants.copy ();
3161 : : }
3162 : : /* Otherwise we must be invoked from the gimplifier. */
3163 : 21 : gcc_assert (cfun && (cfun->curr_properties & PROP_gimple_any) == 0);
3164 : 21 : variant.matchable = false;
3165 : : /* FALLTHRU */
3166 : 3353 : case 1:
3167 : 3353 : omp_context_compute_score (&variant, construct_context, complete_p);
3168 : 3353 : variant.dynamic_selector
3169 : 3353 : = omp_selector_is_dynamic (variant.selector);
3170 : 3353 : variants.safe_push (variant);
3171 : 3353 : if (dump_file && variant.matchable)
3172 : : {
3173 : 16 : if (variant.dynamic_selector)
3174 : 16 : fprintf (dump_file, "matched, dynamic");
3175 : : else
3176 : 0 : fprintf (dump_file, "matched, non-dynamic");
3177 : : }
3178 : : break;
3179 : 88 : case 0:
3180 : 88 : if (dump_file)
3181 : 0 : fprintf (dump_file, "no match");
3182 : : break;
3183 : : }
3184 : :
3185 : 3441 : if (dump_file)
3186 : 16 : fprintf (dump_file, "\n");
3187 : : }
3188 : :
3189 : : /* There must be one default variant. */
3190 : 2511 : gcc_assert (default_found);
3191 : :
3192 : : /* If there are no matching selectors, return the default. */
3193 : 2511 : if (variants.length () == 0)
3194 : : {
3195 : 691 : variants.safe_push (default_variant);
3196 : 691 : return variants.copy ();
3197 : : }
3198 : :
3199 : : /* If there is only one matching selector, use it. */
3200 : 1820 : if (variants.length () == 1)
3201 : : {
3202 : 1230 : if (variants[0].matchable)
3203 : : {
3204 : 1230 : if (variants[0].dynamic_selector)
3205 : 150 : variants.safe_push (default_variant);
3206 : 1230 : return variants.copy ();
3207 : : }
3208 : : else
3209 : : {
3210 : : /* We don't know whether the one non-default selector will
3211 : : actually match. */
3212 : 0 : variants.truncate (0);
3213 : 0 : return variants.copy ();
3214 : : }
3215 : : }
3216 : :
3217 : : /* A context selector that is a strict subset of another context selector
3218 : : has a score of zero. This only applies if the selector that is a
3219 : : superset definitely matches, though. */
3220 : 2713 : for (unsigned int i = 0; i < variants.length (); i++)
3221 : 5739 : for (unsigned int j = i + 1; j < variants.length (); j++)
3222 : : {
3223 : 7338 : int r = omp_context_selector_compare (variants[i].selector,
3224 : 3669 : variants[j].selector);
3225 : 3722 : if (r == -1 && variants[j].matchable)
3226 : : {
3227 : : /* variant i is a strict subset of variant j. */
3228 : 53 : variants[i].score = 0;
3229 : 53 : variants[i].scorable = true;
3230 : 53 : break;
3231 : : }
3232 : 3710 : else if (r == 1 && variants[i].matchable)
3233 : : /* variant j is a strict subset of variant i. */
3234 : : {
3235 : 94 : variants[j].score = 0;
3236 : 94 : variants[j].scorable = true;
3237 : : }
3238 : : }
3239 : :
3240 : : /* Sort the variants by decreasing score, preserving the original order
3241 : : in case of a tie. */
3242 : 590 : variants.stablesort (sort_variant, NULL);
3243 : :
3244 : : /* Add the default as a final choice. */
3245 : 590 : variants.safe_push (default_variant);
3246 : :
3247 : 590 : if (dump_file)
3248 : : {
3249 : 0 : fprintf (dump_file, "Sorted variants are:\n");
3250 : 0 : for (unsigned i = 0; i < variants.length (); i++)
3251 : : {
3252 : 0 : HOST_WIDE_INT score = variants[i].score.to_shwi ();
3253 : 0 : fprintf (dump_file, "score %d matchable %d scorable %d ",
3254 : 0 : (int)score, (int)(variants[i].matchable),
3255 : 0 : (int)(variants[i].scorable));
3256 : 0 : if (variants[i].selector)
3257 : : {
3258 : 0 : fprintf (dump_file, "selector ");
3259 : 0 : print_omp_context_selector (dump_file, variants[i].selector,
3260 : : TDF_NONE);
3261 : 0 : fprintf (dump_file, "\n");
3262 : : }
3263 : : else
3264 : 0 : fprintf (dump_file, "default selector\n");
3265 : : }
3266 : : }
3267 : :
3268 : : /* Build the dynamic candidate list. */
3269 : 1687 : for (unsigned i = 0; i < variants.length (); i++)
3270 : : {
3271 : : /* If we encounter a candidate that wasn't definitely matched,
3272 : : give up now. */
3273 : 1687 : if (!variants[i].matchable)
3274 : : {
3275 : 4 : variants.truncate (0);
3276 : 4 : break;
3277 : : }
3278 : :
3279 : : /* In general, we can't proceed if we can't accurately score any
3280 : : of the selectors, since the sorting may be incorrect. But, since
3281 : : the actual score will never be lower than the guessed value, we
3282 : : can use the first variant if it is not scorable but either the next
3283 : : one is a subset of the first, is scorable, or we can make a
3284 : : direct comparison of the high-order isa/arch/kind bits. */
3285 : 1683 : if (!variants[i].scorable)
3286 : : {
3287 : 28 : bool ok = true;
3288 : 28 : if (i != 0)
3289 : : ok = false;
3290 : 20 : else if (variants[i+1].scorable)
3291 : : /* ok */
3292 : : ;
3293 : 20 : else if (variants[i+1].score > 0)
3294 : : {
3295 : : /* To keep comparisons simple, reject selectors that contain
3296 : : sets other than device, target_device, or construct. */
3297 : 20 : for (tree tss = variants[i].selector;
3298 : 40 : tss && ok; tss = TREE_CHAIN (tss))
3299 : : {
3300 : 20 : enum omp_tss_code code = OMP_TSS_CODE (tss);
3301 : 20 : if (code != OMP_TRAIT_SET_DEVICE
3302 : : && code != OMP_TRAIT_SET_TARGET_DEVICE
3303 : 20 : && code != OMP_TRAIT_SET_CONSTRUCT)
3304 : 12 : ok = false;
3305 : : }
3306 : 20 : for (tree tss = variants[i+1].selector;
3307 : 28 : tss && ok; tss = TREE_CHAIN (tss))
3308 : : {
3309 : 8 : enum omp_tss_code code = OMP_TSS_CODE (tss);
3310 : 8 : if (code != OMP_TRAIT_SET_DEVICE
3311 : : && code != OMP_TRAIT_SET_TARGET_DEVICE
3312 : 8 : && code != OMP_TRAIT_SET_CONSTRUCT)
3313 : 0 : ok = false;
3314 : : }
3315 : : /* Ignore the construct bits of the score. If the isa/arch/kind
3316 : : bits are strictly ordered, we're good to go. Since
3317 : : "the final score is the sum of the values of all specified
3318 : : selectors plus 1", subtract that 1 from both scores before
3319 : : getting rid of the low bits. */
3320 : 20 : if (ok)
3321 : : {
3322 : 8 : size_t l = list_length (construct_context);
3323 : 8 : gcc_assert (variants[i].score > 0
3324 : : && variants[i+1].score > 0);
3325 : 8 : if ((variants[i].score - 1) >> l
3326 : 16 : <= (variants[i+1].score - 1) >> l)
3327 : 0 : ok = false;
3328 : : }
3329 : : }
3330 : :
3331 : 8 : if (!ok)
3332 : : {
3333 : 20 : variants.truncate (0);
3334 : 20 : break;
3335 : : }
3336 : : }
3337 : :
3338 : 1663 : if (dump_file)
3339 : : {
3340 : 0 : fprintf (dump_file, "Adding directive variant with ");
3341 : :
3342 : 0 : if (variants[i].selector)
3343 : : {
3344 : 0 : fprintf (dump_file, "selector ");
3345 : 0 : print_omp_context_selector (dump_file, variants[i].selector,
3346 : : TDF_NONE);
3347 : : }
3348 : : else
3349 : 0 : fprintf (dump_file, "default selector");
3350 : :
3351 : 0 : fprintf (dump_file, " as candidate.\n");
3352 : : }
3353 : :
3354 : : /* The last of the candidates is ended by a static selector. */
3355 : 1663 : if (!variants[i].dynamic_selector)
3356 : : {
3357 : 566 : variants.truncate (i + 1);
3358 : 566 : break;
3359 : : }
3360 : : }
3361 : :
3362 : 590 : return variants.copy ();
3363 : 2589 : }
3364 : :
3365 : : /* Two attempts are made to resolve calls to "declare variant" functions:
3366 : : early resolution in the gimplifier, and late resolution in the
3367 : : omp_device_lower pass. If early resolution is not possible, the
3368 : : original function call is gimplified into the same form as metadirective
3369 : : and goes through the same late resolution code as metadirective. */
3370 : :
3371 : : /* Collect "declare variant" candidates for BASE. CONSTRUCT_CONTEXT
3372 : : is the un-augmented context, or NULL_TREE if that information is not
3373 : : available yet. */
3374 : : vec<struct omp_variant>
3375 : 1775 : omp_declare_variant_candidates (tree base, tree construct_context)
3376 : : {
3377 : 1775 : auto_vec <struct omp_variant> candidates;
3378 : 1775 : bool complete_p;
3379 : 1775 : tree augmented_context
3380 : 1775 : = omp_complete_construct_context (construct_context, &complete_p);
3381 : :
3382 : : /* The variants are stored on (possible multiple) "omp declare variant base"
3383 : : attributes on the base function. */
3384 : 3737 : for (tree attr = DECL_ATTRIBUTES (base); attr; attr = TREE_CHAIN (attr))
3385 : : {
3386 : 2023 : attr = lookup_attribute ("omp declare variant base", attr);
3387 : 2023 : if (attr == NULL_TREE)
3388 : : break;
3389 : :
3390 : 1962 : tree fndecl = TREE_PURPOSE (TREE_VALUE (attr));
3391 : 1962 : tree selector = TREE_VALUE (TREE_VALUE (attr));
3392 : :
3393 : 1962 : if (TREE_CODE (fndecl) != FUNCTION_DECL)
3394 : 371 : continue;
3395 : :
3396 : : /* Ignore this variant if its selector is known not to match. */
3397 : 1962 : if (!omp_context_selector_matches (selector, augmented_context,
3398 : : complete_p))
3399 : 371 : continue;
3400 : :
3401 : 1591 : struct omp_variant candidate;
3402 : 1591 : candidate.selector = selector;
3403 : 1591 : candidate.dynamic_selector = false;
3404 : 1591 : candidate.alternative = fndecl;
3405 : 1591 : candidate.body = NULL_TREE;
3406 : 1591 : candidates.safe_push (candidate);
3407 : : }
3408 : :
3409 : : /* Add a default that is the base function. */
3410 : 1775 : struct omp_variant v;
3411 : 1775 : v.selector = NULL_TREE;
3412 : 1775 : v.dynamic_selector = false;
3413 : 1775 : v.alternative = base;
3414 : 1775 : v.body = NULL_TREE;
3415 : 1775 : candidates.safe_push (v);
3416 : 1775 : return candidates.copy ();
3417 : 1775 : }
3418 : :
3419 : : /* Collect metadirective candidates for METADIRECTIVE. CONSTRUCT_CONTEXT
3420 : : is the un-augmented context, or NULL_TREE if that information is not
3421 : : available yet. */
3422 : : vec<struct omp_variant>
3423 : 510 : omp_metadirective_candidates (tree metadirective, tree construct_context)
3424 : : {
3425 : 510 : auto_vec <struct omp_variant> candidates;
3426 : 510 : tree variant = OMP_METADIRECTIVE_VARIANTS (metadirective);
3427 : 510 : bool complete_p;
3428 : 510 : tree augmented_context
3429 : 510 : = omp_complete_construct_context (construct_context, &complete_p);
3430 : :
3431 : 510 : gcc_assert (variant);
3432 : 1555 : for (; variant; variant = TREE_CHAIN (variant))
3433 : : {
3434 : 1045 : tree selector = OMP_METADIRECTIVE_VARIANT_SELECTOR (variant);
3435 : :
3436 : : /* Ignore this variant if its selector is known not to match. */
3437 : 1045 : if (!omp_context_selector_matches (selector, augmented_context,
3438 : : complete_p))
3439 : 59 : continue;
3440 : :
3441 : 986 : struct omp_variant candidate;
3442 : 986 : candidate.selector = selector;
3443 : 986 : candidate.dynamic_selector = false;
3444 : 986 : candidate.alternative = OMP_METADIRECTIVE_VARIANT_DIRECTIVE (variant);
3445 : 986 : candidate.body = OMP_METADIRECTIVE_VARIANT_BODY (variant);
3446 : 986 : candidates.safe_push (candidate);
3447 : : }
3448 : 510 : return candidates.copy ();
3449 : 510 : }
3450 : :
3451 : : /* Return a vector of dynamic replacement candidates for the metadirective
3452 : : statement in METADIRECTIVE. Return an empty vector if the metadirective
3453 : : cannot be resolved. This function is intended to be called from the
3454 : : front ends, prior to gimplification. */
3455 : :
3456 : : vec<struct omp_variant>
3457 : 348 : omp_early_resolve_metadirective (tree metadirective)
3458 : : {
3459 : 348 : vec <struct omp_variant> candidates
3460 : 348 : = omp_metadirective_candidates (metadirective, NULL_TREE);
3461 : 348 : return omp_get_dynamic_candidates (candidates, NULL_TREE);
3462 : : }
3463 : :
3464 : : /* Return a vector of dynamic replacement candidates for the variant construct
3465 : : with SELECTORS and CONSTRUCT_CONTEXT. This version is called during late
3466 : : resolution in the ompdevlow pass. */
3467 : :
3468 : : vec<struct omp_variant>
3469 : 304 : omp_resolve_variant_construct (tree construct_context, tree selectors)
3470 : : {
3471 : 304 : auto_vec <struct omp_variant> variants;
3472 : :
3473 : 2108 : for (int i = 0; i < TREE_VEC_LENGTH (selectors); i++)
3474 : : {
3475 : 1804 : struct omp_variant variant;
3476 : :
3477 : 1804 : variant.selector = TREE_VEC_ELT (selectors, i);
3478 : 1804 : variant.dynamic_selector = false;
3479 : 1804 : variant.alternative = build_int_cst (integer_type_node, i + 1);
3480 : 1804 : variant.body = NULL_TREE;
3481 : :
3482 : 1804 : variants.safe_push (variant);
3483 : : }
3484 : :
3485 : 304 : return omp_get_dynamic_candidates (variants, construct_context);
3486 : 304 : }
3487 : :
3488 : : /* Encode an oacc launch argument. This matches the GOMP_LAUNCH_PACK
3489 : : macro on gomp-constants.h. We do not check for overflow. */
3490 : :
3491 : : tree
3492 : 10919 : oacc_launch_pack (unsigned code, tree device, unsigned op)
3493 : : {
3494 : 10919 : tree res;
3495 : :
3496 : 10919 : res = build_int_cst (unsigned_type_node, GOMP_LAUNCH_PACK (code, 0, op));
3497 : 10919 : if (device)
3498 : : {
3499 : 0 : device = fold_build2 (LSHIFT_EXPR, unsigned_type_node,
3500 : : device, build_int_cst (unsigned_type_node,
3501 : : GOMP_LAUNCH_DEVICE_SHIFT));
3502 : 0 : res = fold_build2 (BIT_IOR_EXPR, unsigned_type_node, res, device);
3503 : : }
3504 : 10919 : return res;
3505 : : }
3506 : :
3507 : : /* Openacc compute grid dimension clauses are converted to an attribute
3508 : : attached to the function. This permits the target-side code to (a) massage
3509 : : the dimensions, (b) emit that data and (c) optimize. Non-constant
3510 : : dimensions are pushed onto ARGS.
3511 : :
3512 : : The attribute value is a TREE_LIST. A set of dimensions is
3513 : : represented as a list of INTEGER_CST. Those that are runtime
3514 : : exprs are represented as an INTEGER_CST of zero.
3515 : :
3516 : : TODO: Normally the attribute will just contain a single such list. If
3517 : : however it contains a list of lists, this will represent the use of
3518 : : device_type. Each member of the outer list is an assoc list of
3519 : : dimensions, keyed by the device type. The first entry will be the
3520 : : default. Well, that's the plan. */
3521 : :
3522 : : /* Replace any existing oacc fn attribute in ATTRIBS with updated
3523 : : dimensions. */
3524 : :
3525 : : tree
3526 : 20315 : oacc_replace_fn_attrib_attr (tree attribs, tree dims)
3527 : : {
3528 : 20315 : tree ident = get_identifier (OACC_FN_ATTRIB);
3529 : :
3530 : : /* If we happen to be present as the first attrib, drop it. */
3531 : 39560 : if (attribs && TREE_PURPOSE (attribs) == ident)
3532 : 9446 : attribs = TREE_CHAIN (attribs);
3533 : 20315 : return tree_cons (ident, dims, attribs);
3534 : : }
3535 : :
3536 : : /* Replace any existing oacc fn attribute on FN with updated
3537 : : dimensions. */
3538 : :
3539 : : void
3540 : 19961 : oacc_replace_fn_attrib (tree fn, tree dims)
3541 : : {
3542 : 39922 : DECL_ATTRIBUTES (fn)
3543 : 19961 : = oacc_replace_fn_attrib_attr (DECL_ATTRIBUTES (fn), dims);
3544 : 19961 : }
3545 : :
3546 : : /* Scan CLAUSES for launch dimensions and attach them to the oacc
3547 : : function attribute. Push any that are non-constant onto the ARGS
3548 : : list, along with an appropriate GOMP_LAUNCH_DIM tag. */
3549 : :
3550 : : void
3551 : 9769 : oacc_set_fn_attrib (tree fn, tree clauses, vec<tree> *args)
3552 : : {
3553 : : /* Must match GOMP_DIM ordering. */
3554 : 9769 : static const omp_clause_code ids[]
3555 : : = { OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS,
3556 : : OMP_CLAUSE_VECTOR_LENGTH };
3557 : 9769 : unsigned ix;
3558 : 9769 : tree dims[GOMP_DIM_MAX];
3559 : :
3560 : 9769 : tree attr = NULL_TREE;
3561 : 9769 : unsigned non_const = 0;
3562 : :
3563 : 39076 : for (ix = GOMP_DIM_MAX; ix--;)
3564 : : {
3565 : 29307 : tree clause = omp_find_clause (clauses, ids[ix]);
3566 : 29307 : tree dim = NULL_TREE;
3567 : :
3568 : 29307 : if (clause)
3569 : 3287 : dim = OMP_CLAUSE_EXPR (clause, ids[ix]);
3570 : 29307 : dims[ix] = dim;
3571 : 29307 : if (dim && TREE_CODE (dim) != INTEGER_CST)
3572 : : {
3573 : 157 : dim = integer_zero_node;
3574 : 157 : non_const |= GOMP_DIM_MASK (ix);
3575 : : }
3576 : 29307 : attr = tree_cons (NULL_TREE, dim, attr);
3577 : : }
3578 : :
3579 : 9769 : oacc_replace_fn_attrib (fn, attr);
3580 : :
3581 : 9769 : if (non_const)
3582 : : {
3583 : : /* Push a dynamic argument set. */
3584 : 101 : args->safe_push (oacc_launch_pack (GOMP_LAUNCH_DIM,
3585 : : NULL_TREE, non_const));
3586 : 404 : for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++)
3587 : 303 : if (non_const & GOMP_DIM_MASK (ix))
3588 : 157 : args->safe_push (dims[ix]);
3589 : : }
3590 : 9769 : }
3591 : :
3592 : : /* Verify OpenACC routine clauses.
3593 : :
3594 : : Returns 0 if FNDECL should be marked with an OpenACC 'routine' directive, 1
3595 : : if it has already been marked in compatible way, and -1 if incompatible.
3596 : : Upon returning, the chain of clauses will contain exactly one clause
3597 : : specifying the level of parallelism. */
3598 : :
3599 : : int
3600 : 1197 : oacc_verify_routine_clauses (tree fndecl, tree *clauses, location_t loc,
3601 : : const char *routine_str)
3602 : : {
3603 : 1197 : tree c_level = NULL_TREE;
3604 : 1197 : tree c_nohost = NULL_TREE;
3605 : 1197 : tree c_p = NULL_TREE;
3606 : 3608 : for (tree c = *clauses; c; c_p = c, c = OMP_CLAUSE_CHAIN (c))
3607 : 2411 : switch (OMP_CLAUSE_CODE (c))
3608 : : {
3609 : 2312 : case OMP_CLAUSE_GANG:
3610 : 2312 : case OMP_CLAUSE_WORKER:
3611 : 2312 : case OMP_CLAUSE_VECTOR:
3612 : 2312 : case OMP_CLAUSE_SEQ:
3613 : 2312 : if (c_level == NULL_TREE)
3614 : : c_level = c;
3615 : 1496 : else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_CODE (c_level))
3616 : : {
3617 : : /* This has already been diagnosed in the front ends. */
3618 : : /* Drop the duplicate clause. */
3619 : 352 : gcc_checking_assert (c_p != NULL_TREE);
3620 : 352 : OMP_CLAUSE_CHAIN (c_p) = OMP_CLAUSE_CHAIN (c);
3621 : 352 : c = c_p;
3622 : : }
3623 : : else
3624 : : {
3625 : 1144 : error_at (OMP_CLAUSE_LOCATION (c),
3626 : : "%qs specifies a conflicting level of parallelism",
3627 : 1144 : omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
3628 : 1144 : inform (OMP_CLAUSE_LOCATION (c_level),
3629 : : "... to the previous %qs clause here",
3630 : 1144 : omp_clause_code_name[OMP_CLAUSE_CODE (c_level)]);
3631 : : /* Drop the conflicting clause. */
3632 : 1144 : gcc_checking_assert (c_p != NULL_TREE);
3633 : 1144 : OMP_CLAUSE_CHAIN (c_p) = OMP_CLAUSE_CHAIN (c);
3634 : 1144 : c = c_p;
3635 : : }
3636 : : break;
3637 : : case OMP_CLAUSE_NOHOST:
3638 : : /* Don't worry about duplicate clauses here. */
3639 : : c_nohost = c;
3640 : : break;
3641 : 0 : default:
3642 : 0 : gcc_unreachable ();
3643 : : }
3644 : 1197 : if (c_level == NULL_TREE)
3645 : : {
3646 : : /* Default to an implicit 'seq' clause. */
3647 : 381 : c_level = build_omp_clause (loc, OMP_CLAUSE_SEQ);
3648 : 381 : OMP_CLAUSE_CHAIN (c_level) = *clauses;
3649 : 381 : *clauses = c_level;
3650 : : }
3651 : : /* In *clauses, we now have exactly one clause specifying the level of
3652 : : parallelism. */
3653 : :
3654 : 1197 : tree attr
3655 : 1197 : = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl));
3656 : 1197 : if (attr != NULL_TREE)
3657 : : {
3658 : : /* Diagnose if "#pragma omp declare target" has also been applied. */
3659 : 429 : if (TREE_VALUE (attr) == NULL_TREE)
3660 : : {
3661 : : /* See <https://gcc.gnu.org/PR93465>; the semantics of combining
3662 : : OpenACC and OpenMP 'target' are not clear. */
3663 : 32 : error_at (loc,
3664 : : "cannot apply %qs to %qD, which has also been"
3665 : : " marked with an OpenMP 'declare target' directive",
3666 : : routine_str, fndecl);
3667 : : /* Incompatible. */
3668 : 32 : return -1;
3669 : : }
3670 : :
3671 : : /* If a "#pragma acc routine" has already been applied, just verify
3672 : : this one for compatibility. */
3673 : : /* Collect previous directive's clauses. */
3674 : : tree c_level_p = NULL_TREE;
3675 : : tree c_nohost_p = NULL_TREE;
3676 : 850 : for (tree c = TREE_VALUE (attr); c; c = OMP_CLAUSE_CHAIN (c))
3677 : 453 : switch (OMP_CLAUSE_CODE (c))
3678 : : {
3679 : 397 : case OMP_CLAUSE_GANG:
3680 : 397 : case OMP_CLAUSE_WORKER:
3681 : 397 : case OMP_CLAUSE_VECTOR:
3682 : 397 : case OMP_CLAUSE_SEQ:
3683 : 397 : gcc_checking_assert (c_level_p == NULL_TREE);
3684 : : c_level_p = c;
3685 : : break;
3686 : 56 : case OMP_CLAUSE_NOHOST:
3687 : 56 : gcc_checking_assert (c_nohost_p == NULL_TREE);
3688 : : c_nohost_p = c;
3689 : : break;
3690 : 0 : default:
3691 : 0 : gcc_unreachable ();
3692 : : }
3693 : 397 : gcc_checking_assert (c_level_p != NULL_TREE);
3694 : : /* ..., and compare to current directive's, which we've already collected
3695 : : above. */
3696 : 397 : tree c_diag;
3697 : 397 : tree c_diag_p;
3698 : : /* Matching level of parallelism? */
3699 : 397 : if (OMP_CLAUSE_CODE (c_level) != OMP_CLAUSE_CODE (c_level_p))
3700 : : {
3701 : 97 : c_diag = c_level;
3702 : 97 : c_diag_p = c_level_p;
3703 : 97 : goto incompatible;
3704 : : }
3705 : : /* Matching 'nohost' clauses? */
3706 : 300 : if ((c_nohost == NULL_TREE) != (c_nohost_p == NULL_TREE))
3707 : : {
3708 : 56 : c_diag = c_nohost;
3709 : 56 : c_diag_p = c_nohost_p;
3710 : 56 : goto incompatible;
3711 : : }
3712 : : /* Compatible. */
3713 : : return 1;
3714 : :
3715 : 153 : incompatible:
3716 : 153 : if (c_diag != NULL_TREE)
3717 : 125 : error_at (OMP_CLAUSE_LOCATION (c_diag),
3718 : : "incompatible %qs clause when applying"
3719 : : " %qs to %qD, which has already been"
3720 : : " marked with an OpenACC 'routine' directive",
3721 : 125 : omp_clause_code_name[OMP_CLAUSE_CODE (c_diag)],
3722 : : routine_str, fndecl);
3723 : 28 : else if (c_diag_p != NULL_TREE)
3724 : 28 : error_at (loc,
3725 : : "missing %qs clause when applying"
3726 : : " %qs to %qD, which has already been"
3727 : : " marked with an OpenACC 'routine' directive",
3728 : 28 : omp_clause_code_name[OMP_CLAUSE_CODE (c_diag_p)],
3729 : : routine_str, fndecl);
3730 : : else
3731 : 0 : gcc_unreachable ();
3732 : 153 : if (c_diag_p != NULL_TREE)
3733 : 125 : inform (OMP_CLAUSE_LOCATION (c_diag_p),
3734 : : "... with %qs clause here",
3735 : 125 : omp_clause_code_name[OMP_CLAUSE_CODE (c_diag_p)]);
3736 : : else
3737 : : {
3738 : : /* In the front ends, we don't preserve location information for the
3739 : : OpenACC routine directive itself. However, that of c_level_p
3740 : : should be close. */
3741 : 28 : location_t loc_routine = OMP_CLAUSE_LOCATION (c_level_p);
3742 : 28 : inform (loc_routine, "... without %qs clause near to here",
3743 : 28 : omp_clause_code_name[OMP_CLAUSE_CODE (c_diag)]);
3744 : : }
3745 : : /* Incompatible. */
3746 : 153 : return -1;
3747 : : }
3748 : :
3749 : : return 0;
3750 : : }
3751 : :
3752 : : /* Process the OpenACC 'routine' directive clauses to generate an attribute
3753 : : for the level of parallelism. All dimensions have a size of zero
3754 : : (dynamic). TREE_PURPOSE is set to indicate whether that dimension
3755 : : can have a loop partitioned on it. non-zero indicates
3756 : : yes, zero indicates no. By construction once a non-zero has been
3757 : : reached, further inner dimensions must also be non-zero. We set
3758 : : TREE_VALUE to zero for the dimensions that may be partitioned and
3759 : : 1 for the other ones -- if a loop is (erroneously) spawned at
3760 : : an outer level, we don't want to try and partition it. */
3761 : :
3762 : : tree
3763 : 1114 : oacc_build_routine_dims (tree clauses)
3764 : : {
3765 : : /* Must match GOMP_DIM ordering. */
3766 : 1114 : static const omp_clause_code ids[]
3767 : : = {OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ};
3768 : 1114 : int ix;
3769 : 1114 : int level = -1;
3770 : :
3771 : 2271 : for (; clauses; clauses = OMP_CLAUSE_CHAIN (clauses))
3772 : 2285 : for (ix = GOMP_DIM_MAX + 1; ix--;)
3773 : 2242 : if (OMP_CLAUSE_CODE (clauses) == ids[ix])
3774 : : {
3775 : : level = ix;
3776 : : break;
3777 : : }
3778 : 1114 : gcc_checking_assert (level >= 0);
3779 : :
3780 : : tree dims = NULL_TREE;
3781 : :
3782 : 4456 : for (ix = GOMP_DIM_MAX; ix--;)
3783 : 3342 : dims = tree_cons (build_int_cst (boolean_type_node, ix >= level),
3784 : 3342 : build_int_cst (integer_type_node, ix < level), dims);
3785 : :
3786 : 1114 : return dims;
3787 : : }
3788 : :
3789 : : /* Retrieve the oacc function attrib and return it. Non-oacc
3790 : : functions will return NULL. */
3791 : :
3792 : : tree
3793 : 311104 : oacc_get_fn_attrib (tree fn)
3794 : : {
3795 : 311104 : return lookup_attribute (OACC_FN_ATTRIB, DECL_ATTRIBUTES (fn));
3796 : : }
3797 : :
3798 : : /* Return true if FN is an OpenMP or OpenACC offloading function. */
3799 : :
3800 : : bool
3801 : 534 : offloading_function_p (tree fn)
3802 : : {
3803 : 534 : tree attrs = DECL_ATTRIBUTES (fn);
3804 : 534 : return (lookup_attribute ("omp declare target", attrs)
3805 : 534 : || lookup_attribute ("omp target entrypoint", attrs));
3806 : : }
3807 : :
3808 : : /* Extract an oacc execution dimension from FN. FN must be an
3809 : : offloaded function or routine that has already had its execution
3810 : : dimensions lowered to the target-specific values. */
3811 : :
3812 : : int
3813 : 60265 : oacc_get_fn_dim_size (tree fn, int axis)
3814 : : {
3815 : 60265 : tree attrs = oacc_get_fn_attrib (fn);
3816 : :
3817 : 60265 : gcc_assert (axis < GOMP_DIM_MAX);
3818 : :
3819 : 60265 : tree dims = TREE_VALUE (attrs);
3820 : 122159 : while (axis--)
3821 : 61894 : dims = TREE_CHAIN (dims);
3822 : :
3823 : 60265 : int size = TREE_INT_CST_LOW (TREE_VALUE (dims));
3824 : :
3825 : 60265 : return size;
3826 : : }
3827 : :
3828 : : /* Extract the dimension axis from an IFN_GOACC_DIM_POS or
3829 : : IFN_GOACC_DIM_SIZE call. */
3830 : :
3831 : : int
3832 : 89529 : oacc_get_ifn_dim_arg (const gimple *stmt)
3833 : : {
3834 : 89529 : gcc_checking_assert (gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_SIZE
3835 : : || gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_POS);
3836 : 89529 : tree arg = gimple_call_arg (stmt, 0);
3837 : 89529 : HOST_WIDE_INT axis = TREE_INT_CST_LOW (arg);
3838 : :
3839 : 89529 : gcc_checking_assert (axis >= 0 && axis < GOMP_DIM_MAX);
3840 : 89529 : return (int) axis;
3841 : : }
3842 : :
3843 : : /* Build COMPONENT_REF and set TREE_THIS_VOLATILE and TREE_READONLY on it
3844 : : as appropriate. */
3845 : :
3846 : : tree
3847 : 287947 : omp_build_component_ref (tree obj, tree field)
3848 : : {
3849 : 287947 : tree ret = build3 (COMPONENT_REF, TREE_TYPE (field), obj, field, NULL);
3850 : 287947 : if (TREE_THIS_VOLATILE (field))
3851 : 62 : TREE_THIS_VOLATILE (ret) |= 1;
3852 : 287947 : if (TREE_READONLY (field))
3853 : 0 : TREE_READONLY (ret) |= 1;
3854 : 287947 : return ret;
3855 : : }
3856 : :
3857 : : /* Return true if NAME is the name of an omp_* runtime API call. */
3858 : : bool
3859 : 7253 : omp_runtime_api_procname (const char *name)
3860 : : {
3861 : 7253 : if (!startswith (name, "omp_"))
3862 : : return false;
3863 : :
3864 : : static const char *omp_runtime_apis[] =
3865 : : {
3866 : : /* This array has 3 sections. First omp_* calls that don't
3867 : : have any suffixes. */
3868 : : "aligned_alloc",
3869 : : "aligned_calloc",
3870 : : "alloc",
3871 : : "calloc",
3872 : : "free",
3873 : : "get_interop_int",
3874 : : "get_interop_ptr",
3875 : : "get_mapped_ptr",
3876 : : "get_num_interop_properties",
3877 : : "realloc",
3878 : : "target_alloc",
3879 : : "target_associate_ptr",
3880 : : "target_disassociate_ptr",
3881 : : "target_free",
3882 : : "target_is_accessible",
3883 : : "target_is_present",
3884 : : "target_memcpy",
3885 : : "target_memcpy_async",
3886 : : "target_memcpy_rect",
3887 : : "target_memcpy_rect_async",
3888 : : NULL,
3889 : : /* Now omp_* calls that are available as omp_* and omp_*_; however, the
3890 : : DECL_NAME is always omp_* without tailing underscore. */
3891 : : "capture_affinity",
3892 : : "destroy_allocator",
3893 : : "destroy_lock",
3894 : : "destroy_nest_lock",
3895 : : "display_affinity",
3896 : : "fulfill_event",
3897 : : "get_active_level",
3898 : : "get_affinity_format",
3899 : : "get_cancellation",
3900 : : "get_default_allocator",
3901 : : "get_default_device",
3902 : : "get_device_from_uid",
3903 : : "get_device_num",
3904 : : "get_dynamic",
3905 : : "get_initial_device",
3906 : : "get_interop_name",
3907 : : "get_interop_rc_desc",
3908 : : "get_interop_str",
3909 : : "get_interop_type_desc",
3910 : : "get_level",
3911 : : "get_max_active_levels",
3912 : : "get_max_task_priority",
3913 : : "get_max_teams",
3914 : : "get_max_threads",
3915 : : "get_nested",
3916 : : "get_num_devices",
3917 : : "get_num_places",
3918 : : "get_num_procs",
3919 : : "get_num_teams",
3920 : : "get_num_threads",
3921 : : "get_partition_num_places",
3922 : : "get_place_num",
3923 : : "get_proc_bind",
3924 : : "get_supported_active_levels",
3925 : : "get_team_num",
3926 : : "get_teams_thread_limit",
3927 : : "get_thread_limit",
3928 : : "get_thread_num",
3929 : : "get_wtick",
3930 : : "get_wtime",
3931 : : "in_explicit_task",
3932 : : "in_final",
3933 : : "in_parallel",
3934 : : "init_lock",
3935 : : "init_nest_lock",
3936 : : "is_initial_device",
3937 : : "pause_resource",
3938 : : "pause_resource_all",
3939 : : "set_affinity_format",
3940 : : "set_default_allocator",
3941 : : "set_lock",
3942 : : "set_nest_lock",
3943 : : "test_lock",
3944 : : "test_nest_lock",
3945 : : "unset_lock",
3946 : : "unset_nest_lock",
3947 : : NULL,
3948 : : /* And finally calls available as omp_*, omp_*_ and omp_*_8_; however,
3949 : : as DECL_NAME only omp_* and omp_*_8 appear. */
3950 : : "display_env",
3951 : : "get_ancestor_thread_num",
3952 : : "get_uid_from_device",
3953 : : "get_partition_place_nums",
3954 : : "get_place_num_procs",
3955 : : "get_place_proc_ids",
3956 : : "get_schedule",
3957 : : "get_team_size",
3958 : : "init_allocator",
3959 : : "set_default_device",
3960 : : "set_dynamic",
3961 : : "set_max_active_levels",
3962 : : "set_nested",
3963 : : "set_num_teams",
3964 : : "set_num_threads",
3965 : : "set_schedule",
3966 : : "set_teams_thread_limit"
3967 : : };
3968 : :
3969 : : int mode = 0;
3970 : 41891 : for (unsigned i = 0; i < ARRAY_SIZE (omp_runtime_apis); i++)
3971 : : {
3972 : 41890 : if (omp_runtime_apis[i] == NULL)
3973 : : {
3974 : 825 : mode++;
3975 : 825 : continue;
3976 : : }
3977 : 41065 : size_t len = strlen (omp_runtime_apis[i]);
3978 : 41065 : if (strncmp (name + 4, omp_runtime_apis[i], len) == 0
3979 : 937 : && (name[4 + len] == '\0'
3980 : 3 : || (mode > 1 && strcmp (name + 4 + len, "_8") == 0)))
3981 : : return true;
3982 : : }
3983 : : return false;
3984 : : }
3985 : :
3986 : : /* Return true if FNDECL is an omp_* runtime API call. */
3987 : :
3988 : : bool
3989 : 7418 : omp_runtime_api_call (const_tree fndecl)
3990 : : {
3991 : 7418 : tree declname = DECL_NAME (fndecl);
3992 : 7418 : if (!declname
3993 : 7418 : || (DECL_CONTEXT (fndecl) != NULL_TREE
3994 : 5402 : && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL)
3995 : 14252 : || !TREE_PUBLIC (fndecl))
3996 : : return false;
3997 : 6775 : return omp_runtime_api_procname (IDENTIFIER_POINTER (declname));
3998 : : }
3999 : :
4000 : : /* See "Additional Definitions for the OpenMP API Specification" document;
4001 : : associated IDs are 1, 2, ... */
4002 : : static const char* omp_interop_fr_str[] = {"cuda", "cuda_driver", "opencl",
4003 : : "sycl", "hip", "level_zero", "hsa"};
4004 : :
4005 : : /* Returns the foreign-runtime ID if found or 0 otherwise. */
4006 : :
4007 : : char
4008 : 362 : omp_get_fr_id_from_name (const char *str)
4009 : : {
4010 : 362 : static_assert (GOMP_INTEROP_IFR_LAST == ARRAY_SIZE (omp_interop_fr_str), "");
4011 : :
4012 : 1349 : for (unsigned i = 0; i < ARRAY_SIZE (omp_interop_fr_str); ++i)
4013 : 1313 : if (!strcmp (str, omp_interop_fr_str[i]))
4014 : 326 : return i + 1;
4015 : : return GOMP_INTEROP_IFR_UNKNOWN;
4016 : : }
4017 : :
4018 : : /* Returns the string value to a foreign-runtime integer value or NULL if value
4019 : : is not known. */
4020 : :
4021 : : const char *
4022 : 386 : omp_get_name_from_fr_id (int fr_id)
4023 : : {
4024 : 386 : if (fr_id < 1 || fr_id > (int) ARRAY_SIZE (omp_interop_fr_str))
4025 : : return "<unknown>";
4026 : 272 : return omp_interop_fr_str[fr_id-1];
4027 : : }
4028 : :
4029 : : namespace omp_addr_tokenizer {
4030 : :
4031 : : /* We scan an expression by recursive descent, and build a vector of
4032 : : "omp_addr_token *" pointers representing a "parsed" version of the
4033 : : expression. The grammar we use is something like this:
4034 : :
4035 : : expr0::
4036 : : expr [section-access]
4037 : :
4038 : : expr::
4039 : : structured-expr access-method
4040 : : | array-base access-method
4041 : :
4042 : : structured-expr::
4043 : : structure-base component-selector
4044 : :
4045 : : arbitrary-expr::
4046 : : (anything else)
4047 : :
4048 : : structure-base::
4049 : : DECL access-method
4050 : : | structured-expr access-method
4051 : : | arbitrary-expr access-method
4052 : :
4053 : : array-base::
4054 : : DECL
4055 : : | arbitrary-expr
4056 : :
4057 : : access-method::
4058 : : DIRECT
4059 : : | REF
4060 : : | POINTER
4061 : : | REF_TO_POINTER
4062 : : | POINTER_OFFSET
4063 : : | REF_TO_POINTER_OFFSET
4064 : : | INDEXED_ARRAY
4065 : : | INDEXED_REF_TO_ARRAY
4066 : : | index-expr
4067 : :
4068 : : index-expr::
4069 : : INDEX_EXPR access-method
4070 : :
4071 : : component-selector::
4072 : : component-selector COMPONENT_REF
4073 : : | component-selector ARRAY_REF
4074 : : | COMPONENT_REF
4075 : :
4076 : : This tokenized form is then used both in parsing, for OpenMP clause
4077 : : expansion (for C and C++) and in gimplify.cc for sibling-list handling
4078 : : (for C, C++ and Fortran). */
4079 : :
4080 : 28018 : omp_addr_token::omp_addr_token (token_type t, tree e)
4081 : 28018 : : type(t), expr(e)
4082 : : {
4083 : 28018 : }
4084 : :
4085 : 112943 : omp_addr_token::omp_addr_token (access_method_kinds k, tree e)
4086 : 112943 : : type(ACCESS_METHOD), expr(e)
4087 : : {
4088 : 112943 : u.access_kind = k;
4089 : 112943 : }
4090 : :
4091 : 87229 : omp_addr_token::omp_addr_token (token_type t, structure_base_kinds k, tree e)
4092 : 87229 : : type(t), expr(e)
4093 : : {
4094 : 87229 : u.structure_base_kind = k;
4095 : 87229 : }
4096 : :
4097 : : static bool
4098 : 87232 : omp_parse_component_selector (tree *expr0)
4099 : : {
4100 : 87232 : tree expr = *expr0;
4101 : 87232 : tree last_component = NULL_TREE;
4102 : :
4103 : 87232 : while (TREE_CODE (expr) == COMPONENT_REF
4104 : 122192 : || TREE_CODE (expr) == ARRAY_REF)
4105 : : {
4106 : 34960 : if (TREE_CODE (expr) == COMPONENT_REF)
4107 : 33195 : last_component = expr;
4108 : :
4109 : 34960 : expr = TREE_OPERAND (expr, 0);
4110 : :
4111 : 34960 : if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE)
4112 : : break;
4113 : : }
4114 : :
4115 : 87232 : if (!last_component)
4116 : : return false;
4117 : :
4118 : 28018 : *expr0 = last_component;
4119 : 28018 : return true;
4120 : : }
4121 : :
4122 : : /* This handles references that have had convert_from_reference called on
4123 : : them, and also those that haven't. */
4124 : :
4125 : : static bool
4126 : 146677 : omp_parse_ref (tree *expr0)
4127 : : {
4128 : 146677 : tree expr = *expr0;
4129 : :
4130 : 146677 : if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE)
4131 : : return true;
4132 : 142702 : else if ((TREE_CODE (expr) == INDIRECT_REF
4133 : 104779 : || (TREE_CODE (expr) == MEM_REF
4134 : 0 : && integer_zerop (TREE_OPERAND (expr, 1))))
4135 : 142702 : && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
4136 : : {
4137 : 9331 : *expr0 = TREE_OPERAND (expr, 0);
4138 : 9331 : return true;
4139 : : }
4140 : :
4141 : : return false;
4142 : : }
4143 : :
4144 : : static bool
4145 : 103448 : omp_parse_pointer (tree *expr0, bool *has_offset)
4146 : : {
4147 : 103448 : tree expr = *expr0;
4148 : :
4149 : 103448 : *has_offset = false;
4150 : :
4151 : 103448 : if ((TREE_CODE (expr) == INDIRECT_REF
4152 : 75953 : || (TREE_CODE (expr) == MEM_REF
4153 : 0 : && integer_zerop (TREE_OPERAND (expr, 1))))
4154 : 103448 : && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == POINTER_TYPE)
4155 : : {
4156 : 27495 : expr = TREE_OPERAND (expr, 0);
4157 : :
4158 : : /* The Fortran FE sometimes emits a no-op cast here. */
4159 : 27495 : STRIP_NOPS (expr);
4160 : :
4161 : 30416 : while (1)
4162 : : {
4163 : 30416 : if (TREE_CODE (expr) == COMPOUND_EXPR)
4164 : : {
4165 : 101 : expr = TREE_OPERAND (expr, 1);
4166 : 101 : STRIP_NOPS (expr);
4167 : : }
4168 : 30315 : else if (TREE_CODE (expr) == SAVE_EXPR)
4169 : 89 : expr = TREE_OPERAND (expr, 0);
4170 : 30226 : else if (TREE_CODE (expr) == POINTER_PLUS_EXPR)
4171 : : {
4172 : 2731 : *has_offset = true;
4173 : 2731 : expr = TREE_OPERAND (expr, 0);
4174 : : }
4175 : : else
4176 : : break;
4177 : : }
4178 : :
4179 : 27495 : STRIP_NOPS (expr);
4180 : :
4181 : 27495 : *expr0 = expr;
4182 : 27495 : return true;
4183 : : }
4184 : :
4185 : : return false;
4186 : : }
4187 : :
4188 : : static bool
4189 : 112943 : omp_parse_access_method (tree *expr0, enum access_method_kinds *kind)
4190 : : {
4191 : 112943 : tree expr = *expr0;
4192 : 112943 : bool has_offset;
4193 : :
4194 : 112943 : if (omp_parse_ref (&expr))
4195 : 9495 : *kind = ACCESS_REF;
4196 : 103448 : else if (omp_parse_pointer (&expr, &has_offset))
4197 : : {
4198 : 27495 : if (omp_parse_ref (&expr))
4199 : 5574 : *kind = has_offset ? ACCESS_REF_TO_POINTER_OFFSET
4200 : : : ACCESS_REF_TO_POINTER;
4201 : : else
4202 : 46685 : *kind = has_offset ? ACCESS_POINTER_OFFSET : ACCESS_POINTER;
4203 : : }
4204 : 75953 : else if (TREE_CODE (expr) == ARRAY_REF)
4205 : : {
4206 : 12770 : while (TREE_CODE (expr) == ARRAY_REF)
4207 : 6531 : expr = TREE_OPERAND (expr, 0);
4208 : 6239 : if (omp_parse_ref (&expr))
4209 : 640 : *kind = ACCESS_INDEXED_REF_TO_ARRAY;
4210 : : else
4211 : 5599 : *kind = ACCESS_INDEXED_ARRAY;
4212 : : }
4213 : : else
4214 : 69714 : *kind = ACCESS_DIRECT;
4215 : :
4216 : 112943 : STRIP_NOPS (expr);
4217 : :
4218 : 112943 : *expr0 = expr;
4219 : 112943 : return true;
4220 : : }
4221 : :
4222 : : static bool
4223 : 112943 : omp_parse_access_methods (vec<omp_addr_token *> &addr_tokens, tree *expr0)
4224 : : {
4225 : 112943 : tree expr = *expr0;
4226 : 112943 : enum access_method_kinds kind;
4227 : 112943 : tree am_expr;
4228 : :
4229 : 112943 : if (omp_parse_access_method (&expr, &kind))
4230 : 112943 : am_expr = expr;
4231 : :
4232 : 112943 : if (TREE_CODE (expr) == INDIRECT_REF
4233 : 112943 : || TREE_CODE (expr) == MEM_REF
4234 : 111846 : || TREE_CODE (expr) == ARRAY_REF)
4235 : 1488 : omp_parse_access_methods (addr_tokens, &expr);
4236 : :
4237 : 112943 : addr_tokens.safe_push (new omp_addr_token (kind, am_expr));
4238 : :
4239 : 112943 : *expr0 = expr;
4240 : 112943 : return true;
4241 : : }
4242 : :
4243 : : static bool omp_parse_structured_expr (vec<omp_addr_token *> &, tree *);
4244 : :
4245 : : static bool
4246 : 87229 : omp_parse_structure_base (vec<omp_addr_token *> &addr_tokens,
4247 : : tree *expr0, structure_base_kinds *kind,
4248 : : vec<omp_addr_token *> &base_access_tokens,
4249 : : bool allow_structured = true)
4250 : : {
4251 : 87229 : tree expr = *expr0;
4252 : :
4253 : 87229 : if (allow_structured)
4254 : 28018 : omp_parse_access_methods (base_access_tokens, &expr);
4255 : :
4256 : 87229 : if (DECL_P (expr))
4257 : : {
4258 : 82914 : *kind = BASE_DECL;
4259 : 82914 : return true;
4260 : : }
4261 : :
4262 : 4315 : if (allow_structured && omp_parse_structured_expr (addr_tokens, &expr))
4263 : : {
4264 : 3792 : *kind = BASE_COMPONENT_EXPR;
4265 : 3792 : *expr0 = expr;
4266 : 3792 : return true;
4267 : : }
4268 : :
4269 : 523 : *kind = BASE_ARBITRARY_EXPR;
4270 : 523 : *expr0 = expr;
4271 : 523 : return true;
4272 : : }
4273 : :
4274 : : static bool
4275 : 87232 : omp_parse_structured_expr (vec<omp_addr_token *> &addr_tokens, tree *expr0)
4276 : : {
4277 : 87232 : tree expr = *expr0;
4278 : 87232 : tree base_component = NULL_TREE;
4279 : 87232 : structure_base_kinds struct_base_kind;
4280 : 87232 : auto_vec<omp_addr_token *> base_access_tokens;
4281 : :
4282 : 87232 : if (omp_parse_component_selector (&expr))
4283 : 28018 : base_component = expr;
4284 : : else
4285 : : return false;
4286 : :
4287 : 28018 : gcc_assert (TREE_CODE (expr) == COMPONENT_REF);
4288 : 28018 : expr = TREE_OPERAND (expr, 0);
4289 : :
4290 : 28018 : tree structure_base = expr;
4291 : :
4292 : 28018 : if (!omp_parse_structure_base (addr_tokens, &expr, &struct_base_kind,
4293 : : base_access_tokens))
4294 : : return false;
4295 : :
4296 : 28018 : addr_tokens.safe_push (new omp_addr_token (STRUCTURE_BASE, struct_base_kind,
4297 : 28018 : structure_base));
4298 : 28018 : addr_tokens.safe_splice (base_access_tokens);
4299 : 28018 : addr_tokens.safe_push (new omp_addr_token (COMPONENT_SELECTOR,
4300 : 28018 : base_component));
4301 : :
4302 : 28018 : *expr0 = expr;
4303 : :
4304 : 28018 : return true;
4305 : 87232 : }
4306 : :
4307 : : static bool
4308 : 59211 : omp_parse_array_expr (vec<omp_addr_token *> &addr_tokens, tree *expr0)
4309 : : {
4310 : 59211 : tree expr = *expr0;
4311 : 59211 : structure_base_kinds s_kind;
4312 : 59211 : auto_vec<omp_addr_token *> base_access_tokens;
4313 : :
4314 : 59211 : if (!omp_parse_structure_base (addr_tokens, &expr, &s_kind,
4315 : : base_access_tokens, false))
4316 : : return false;
4317 : :
4318 : 59211 : addr_tokens.safe_push (new omp_addr_token (ARRAY_BASE, s_kind, expr));
4319 : 59211 : addr_tokens.safe_splice (base_access_tokens);
4320 : :
4321 : 59211 : *expr0 = expr;
4322 : 59211 : return true;
4323 : 59211 : }
4324 : :
4325 : : /* Return TRUE if the ACCESS_METHOD token at index 'i' has a further
4326 : : ACCESS_METHOD chained after it (e.g., if we're processing an expression
4327 : : containing multiple pointer indirections). */
4328 : :
4329 : : bool
4330 : 44785 : omp_access_chain_p (vec<omp_addr_token *> &addr_tokens, unsigned i)
4331 : : {
4332 : 44785 : gcc_assert (addr_tokens[i]->type == ACCESS_METHOD);
4333 : 44785 : return (i + 1 < addr_tokens.length ()
4334 : 44785 : && addr_tokens[i + 1]->type == ACCESS_METHOD);
4335 : : }
4336 : :
4337 : : /* Return the address of the object accessed by the ACCESS_METHOD token
4338 : : at 'i': either of the next access method's expr, or of EXPR if we're at
4339 : : the end of the list of tokens. */
4340 : :
4341 : : tree
4342 : 4251 : omp_accessed_addr (vec<omp_addr_token *> &addr_tokens, unsigned i, tree expr)
4343 : : {
4344 : 4251 : if (i + 1 < addr_tokens.length ())
4345 : 26 : return build_fold_addr_expr (addr_tokens[i + 1]->expr);
4346 : : else
4347 : 4225 : return build_fold_addr_expr (expr);
4348 : : }
4349 : :
4350 : : } /* namespace omp_addr_tokenizer. */
4351 : :
4352 : : bool
4353 : 83437 : omp_parse_expr (vec<omp_addr_token *> &addr_tokens, tree expr)
4354 : : {
4355 : 83437 : using namespace omp_addr_tokenizer;
4356 : 83437 : auto_vec<omp_addr_token *> expr_access_tokens;
4357 : :
4358 : 83437 : if (!omp_parse_access_methods (expr_access_tokens, &expr))
4359 : : return false;
4360 : :
4361 : 83437 : if (omp_parse_structured_expr (addr_tokens, &expr))
4362 : : ;
4363 : 59211 : else if (omp_parse_array_expr (addr_tokens, &expr))
4364 : : ;
4365 : : else
4366 : : return false;
4367 : :
4368 : 83437 : addr_tokens.safe_splice (expr_access_tokens);
4369 : :
4370 : 83437 : return true;
4371 : 83437 : }
4372 : :
4373 : : DEBUG_FUNCTION void
4374 : 0 : debug_omp_tokenized_addr (vec<omp_addr_token *> &addr_tokens,
4375 : : bool with_exprs)
4376 : : {
4377 : 0 : using namespace omp_addr_tokenizer;
4378 : 0 : const char *sep = with_exprs ? " " : "";
4379 : :
4380 : 0 : for (auto e : addr_tokens)
4381 : : {
4382 : 0 : const char *pfx = "";
4383 : :
4384 : 0 : fputs (sep, stderr);
4385 : :
4386 : 0 : switch (e->type)
4387 : : {
4388 : 0 : case COMPONENT_SELECTOR:
4389 : 0 : fputs ("component_selector", stderr);
4390 : 0 : break;
4391 : 0 : case ACCESS_METHOD:
4392 : 0 : switch (e->u.access_kind)
4393 : : {
4394 : 0 : case ACCESS_DIRECT:
4395 : 0 : fputs ("access_direct", stderr);
4396 : 0 : break;
4397 : 0 : case ACCESS_REF:
4398 : 0 : fputs ("access_ref", stderr);
4399 : 0 : break;
4400 : 0 : case ACCESS_POINTER:
4401 : 0 : fputs ("access_pointer", stderr);
4402 : 0 : break;
4403 : 0 : case ACCESS_POINTER_OFFSET:
4404 : 0 : fputs ("access_pointer_offset", stderr);
4405 : 0 : break;
4406 : 0 : case ACCESS_REF_TO_POINTER:
4407 : 0 : fputs ("access_ref_to_pointer", stderr);
4408 : 0 : break;
4409 : 0 : case ACCESS_REF_TO_POINTER_OFFSET:
4410 : 0 : fputs ("access_ref_to_pointer_offset", stderr);
4411 : 0 : break;
4412 : 0 : case ACCESS_INDEXED_ARRAY:
4413 : 0 : fputs ("access_indexed_array", stderr);
4414 : 0 : break;
4415 : 0 : case ACCESS_INDEXED_REF_TO_ARRAY:
4416 : 0 : fputs ("access_indexed_ref_to_array", stderr);
4417 : 0 : break;
4418 : : }
4419 : : break;
4420 : 0 : case ARRAY_BASE:
4421 : 0 : case STRUCTURE_BASE:
4422 : 0 : pfx = e->type == ARRAY_BASE ? "array_" : "struct_";
4423 : 0 : switch (e->u.structure_base_kind)
4424 : : {
4425 : 0 : case BASE_DECL:
4426 : 0 : fprintf (stderr, "%sbase_decl", pfx);
4427 : 0 : break;
4428 : 0 : case BASE_COMPONENT_EXPR:
4429 : 0 : fputs ("base_component_expr", stderr);
4430 : 0 : break;
4431 : 0 : case BASE_ARBITRARY_EXPR:
4432 : 0 : fprintf (stderr, "%sbase_arbitrary_expr", pfx);
4433 : 0 : break;
4434 : : }
4435 : : break;
4436 : : }
4437 : 0 : if (with_exprs)
4438 : : {
4439 : 0 : fputs (" [", stderr);
4440 : 0 : print_generic_expr (stderr, e->expr);
4441 : 0 : fputc (']', stderr);
4442 : 0 : sep = ",\n ";
4443 : : }
4444 : : else
4445 : : sep = " ";
4446 : : }
4447 : :
4448 : 0 : fputs ("\n", stderr);
4449 : 0 : }
4450 : :
4451 : : /* Return number of iterations of loop I in FOR_STMT. If PSTEP is non-NULL,
4452 : : *PSTEP will be the loop step. */
4453 : :
4454 : : tree
4455 : 2647 : omp_loop_number_of_iterations (tree for_stmt, int i, tree *pstep)
4456 : : {
4457 : 2647 : tree t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
4458 : 2647 : gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
4459 : 2647 : tree decl = TREE_OPERAND (t, 0);
4460 : 2647 : tree n1 = TREE_OPERAND (t, 1);
4461 : 2647 : tree type = TREE_TYPE (decl);
4462 : 2647 : tree cond = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
4463 : 2647 : gcc_assert (COMPARISON_CLASS_P (cond));
4464 : 2647 : gcc_assert (TREE_OPERAND (cond, 0) == decl);
4465 : 2647 : tree_code cond_code = TREE_CODE (cond);
4466 : 2647 : tree n2 = TREE_OPERAND (cond, 1);
4467 : 2647 : t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
4468 : 2647 : tree step = NULL_TREE;
4469 : 2647 : switch (TREE_CODE (t))
4470 : : {
4471 : 1141 : case PREINCREMENT_EXPR:
4472 : 1141 : case POSTINCREMENT_EXPR:
4473 : 1141 : gcc_assert (!POINTER_TYPE_P (type));
4474 : 1141 : gcc_assert (TREE_OPERAND (t, 0) == decl);
4475 : 1141 : step = build_int_cst (type, 1);
4476 : 1141 : break;
4477 : 42 : case PREDECREMENT_EXPR:
4478 : 42 : case POSTDECREMENT_EXPR:
4479 : 42 : gcc_assert (!POINTER_TYPE_P (type));
4480 : 42 : gcc_assert (TREE_OPERAND (t, 0) == decl);
4481 : 42 : step = build_int_cst (type, -1);
4482 : 42 : break;
4483 : 1464 : case MODIFY_EXPR:
4484 : 1464 : gcc_assert (TREE_OPERAND (t, 0) == decl);
4485 : 1464 : t = TREE_OPERAND (t, 1);
4486 : 1464 : switch (TREE_CODE (t))
4487 : : {
4488 : 1389 : case PLUS_EXPR:
4489 : 1389 : if (TREE_OPERAND (t, 1) == decl)
4490 : : {
4491 : 3 : TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
4492 : 3 : TREE_OPERAND (t, 0) = decl;
4493 : : }
4494 : : /* FALLTHRU */
4495 : : case POINTER_PLUS_EXPR:
4496 : : case MINUS_EXPR:
4497 : 1464 : step = omp_get_for_step_from_incr (EXPR_LOCATION (t), t);
4498 : 1464 : break;
4499 : 0 : default:
4500 : 0 : gcc_unreachable ();
4501 : : }
4502 : 1464 : break;
4503 : 0 : default:
4504 : 0 : gcc_unreachable ();
4505 : : }
4506 : 2647 : omp_adjust_for_condition (EXPR_LOCATION (for_stmt), &cond_code, &n2,
4507 : : decl, step);
4508 : 2647 : if (pstep)
4509 : 2099 : *pstep = step;
4510 : 2647 : if (INTEGRAL_TYPE_P (type)
4511 : 2647 : && TYPE_PRECISION (type) < TYPE_PRECISION (long_long_integer_type_node))
4512 : : {
4513 : 2538 : n1 = fold_convert (long_long_integer_type_node, n1);
4514 : 2538 : n2 = fold_convert (long_long_integer_type_node, n2);
4515 : 2538 : step = fold_convert (long_long_integer_type_node, step);
4516 : : }
4517 : 2647 : if (cond_code == LT_EXPR
4518 : 156 : || POINTER_TYPE_P (type)
4519 : 2783 : || !TYPE_UNSIGNED (TREE_TYPE (n1)))
4520 : : {
4521 : 2647 : if (POINTER_TYPE_P (type))
4522 : 60 : t = fold_build2 (POINTER_DIFF_EXPR, ssizetype, n2, n1);
4523 : : else
4524 : 2587 : t = fold_build2 (MINUS_EXPR, TREE_TYPE (n1), n2, n1);
4525 : 2647 : t = fold_build2 (CEIL_DIV_EXPR, TREE_TYPE (t), t, step);
4526 : : }
4527 : : else
4528 : : {
4529 : 0 : t = fold_build2 (MINUS_EXPR, type, n1, n2);
4530 : 0 : t = fold_build2 (CEIL_DIV_EXPR, type, t,
4531 : : fold_build1 (NEGATE_EXPR, type, step));
4532 : : }
4533 : 2647 : return t;
4534 : : }
4535 : :
4536 : : /* Tile transformation:
4537 : : Original loop:
4538 : :
4539 : : #pragma omp tile sizes(16, 32)
4540 : : for (i = 0; i < k; ++i)
4541 : : for (j = 0; j < 128; j += 2)
4542 : : {
4543 : : baz (i, j);
4544 : : }
4545 : :
4546 : : Transformed loop:
4547 : : #pragma omp tile sizes(16, 32)
4548 : : for (i.0 = 0; i.0 < k; i.0 += 16)
4549 : : for (j.0 = 0; j.0 < 128; j.0 += 64)
4550 : : {
4551 : : i = i.0;
4552 : : i.1 = MIN_EXPR <i.0 + 16, k>;
4553 : : goto <D.2783>;
4554 : : <D.2782>:;
4555 : : j = j.0;
4556 : : j.1 = j.0 + 32;
4557 : : goto <D.2786>;
4558 : : <D.2785>:;
4559 : : {
4560 : : baz (i, j);
4561 : : }
4562 : : j += 2;
4563 : : <D.2786>:;
4564 : : if (j < j.1) goto <D.2785>; else goto <D.2787>;
4565 : : <D.2787>:;
4566 : : ++i;
4567 : : <D.2783>:;
4568 : : if (i < i.1) goto <D.2782>; else goto <D.2784>;
4569 : : <D.2784>:;
4570 : : }
4571 : :
4572 : : where the grid loops have canonical form, but the inner
4573 : : loops don't and so are immediately lowered. */
4574 : :
4575 : : static void
4576 : 1958 : omp_apply_tile (tree for_stmt, tree sizes, int size)
4577 : : {
4578 : 1958 : tree pre_body = NULL_TREE, post_body = NULL_TREE;
4579 : 1958 : tree orig_sizes = sizes;
4580 : 1958 : if (OMP_FOR_NON_RECTANGULAR (for_stmt))
4581 : : {
4582 : 51 : error_at (EXPR_LOCATION (for_stmt), "non-rectangular %<tile%>");
4583 : 51 : return;
4584 : : }
4585 : 4434 : for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
4586 : : {
4587 : 2527 : if (orig_sizes)
4588 : : {
4589 : 1734 : size = tree_to_uhwi (TREE_VALUE (sizes));
4590 : 1734 : sizes = TREE_CHAIN (sizes);
4591 : : }
4592 : 2527 : if (size == 1)
4593 : 428 : continue;
4594 : 2099 : if (OMP_FOR_ORIG_DECLS (for_stmt) == NULL_TREE)
4595 : : {
4596 : 522 : OMP_FOR_ORIG_DECLS (for_stmt)
4597 : 1044 : = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)));
4598 : 1188 : for (int j = 0; j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); j++)
4599 : : {
4600 : 666 : gcc_assert (TREE_CODE (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j))
4601 : : == MODIFY_EXPR);
4602 : 666 : TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), j)
4603 : 1332 : = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j), 0);
4604 : : }
4605 : : }
4606 : 2099 : tree step;
4607 : 2099 : tree iters = omp_loop_number_of_iterations (for_stmt, i, &step);
4608 : 2099 : tree t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
4609 : 2099 : tree decl = TREE_OPERAND (t, 0);
4610 : 2099 : tree type = TREE_TYPE (decl);
4611 : 2099 : tree griddecl = create_tmp_var_raw (type);
4612 : 2099 : DECL_CONTEXT (griddecl) = current_function_decl;
4613 : 2099 : t = build1 (DECL_EXPR, void_type_node, griddecl);
4614 : 2099 : append_to_statement_list (t, &OMP_FOR_PRE_BODY (for_stmt));
4615 : 2099 : TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i), 0) = griddecl;
4616 : 2099 : TREE_PRIVATE (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i)) = 1;
4617 : 2099 : tree cond = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i);
4618 : 2099 : TREE_OPERAND (cond, 0) = griddecl;
4619 : 2099 : tree ub = save_expr (TREE_OPERAND (cond, 1));
4620 : 2099 : TREE_OPERAND (cond, 1) = ub;
4621 : 2099 : t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
4622 : 2099 : if (TREE_CODE (cond) == NE_EXPR)
4623 : : {
4624 : 163 : tree_code cond_code = TREE_CODE (cond);
4625 : 163 : omp_adjust_for_condition (EXPR_LOCATION (for_stmt), &cond_code,
4626 : : &ub, griddecl, step);
4627 : 163 : TREE_SET_CODE (cond, cond_code);
4628 : : }
4629 : 2099 : step = save_expr (step);
4630 : 2099 : tree gridstep = fold_build2 (MULT_EXPR, TREE_TYPE (step),
4631 : : step, build_int_cst (TREE_TYPE (step),
4632 : : size));
4633 : 2099 : if (POINTER_TYPE_P (type))
4634 : 52 : t = build2 (POINTER_PLUS_EXPR, type, griddecl,
4635 : : fold_convert (sizetype, gridstep));
4636 : : else
4637 : 2047 : t = build2 (PLUS_EXPR, type, griddecl, gridstep);
4638 : 2099 : t = build2 (MODIFY_EXPR, type, griddecl, t);
4639 : 2099 : TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t;
4640 : 2099 : t = build2 (MODIFY_EXPR, type, decl, griddecl);
4641 : 2099 : append_to_statement_list (t, &pre_body);
4642 : 2099 : if (POINTER_TYPE_P (type))
4643 : 52 : t = build2 (POINTER_PLUS_EXPR, type, griddecl,
4644 : : fold_convert (sizetype, gridstep));
4645 : : else
4646 : 2047 : t = build2 (PLUS_EXPR, type, griddecl, gridstep);
4647 : 2099 : bool minmax_needed = true;
4648 : 2099 : if (TREE_CODE (iters) == INTEGER_CST)
4649 : : {
4650 : 1135 : wide_int witers = wi::to_wide (iters);
4651 : 1135 : wide_int wsize = wide_int::from (size, witers.get_precision (),
4652 : 1135 : TYPE_SIGN (TREE_TYPE (iters)));
4653 : 1135 : if (wi::multiple_of_p (witers, wsize, TYPE_SIGN (TREE_TYPE (iters))))
4654 : 417 : minmax_needed = false;
4655 : 1135 : }
4656 : 1135 : if (minmax_needed)
4657 : 1682 : switch (TREE_CODE (cond))
4658 : : {
4659 : 251 : case LE_EXPR:
4660 : 251 : if (POINTER_TYPE_P (type))
4661 : 4 : t = build2 (MIN_EXPR, type, t,
4662 : 4 : build2 (POINTER_PLUS_EXPR, type, ub, size_int (1)));
4663 : : else
4664 : 247 : t = build2 (MIN_EXPR, type, t,
4665 : : build2 (PLUS_EXPR, type, ub, build_one_cst (type)));
4666 : : break;
4667 : 1375 : case LT_EXPR:
4668 : 1375 : t = build2 (MIN_EXPR, type, t, ub);
4669 : 1375 : break;
4670 : 28 : case GE_EXPR:
4671 : 28 : if (POINTER_TYPE_P (type))
4672 : 8 : t = build2 (MAX_EXPR, type, t,
4673 : 8 : build2 (POINTER_PLUS_EXPR, type, ub, size_int (-1)));
4674 : : else
4675 : 20 : t = build2 (MAX_EXPR, type, t,
4676 : : build2 (PLUS_EXPR, type, ub,
4677 : : build_minus_one_cst (type)));
4678 : : break;
4679 : 28 : case GT_EXPR:
4680 : 28 : t = build2 (MAX_EXPR, type, t, ub);
4681 : 28 : break;
4682 : 0 : default:
4683 : 0 : gcc_unreachable ();
4684 : : }
4685 : 2099 : tree end = create_tmp_var_raw (type);
4686 : 2099 : DECL_CONTEXT (end) = current_function_decl;
4687 : 2099 : end = build4 (TARGET_EXPR, type, end, t, NULL_TREE, NULL_TREE);
4688 : 2099 : TREE_SIDE_EFFECTS (end) = 1;
4689 : 2099 : append_to_statement_list (end, &pre_body);
4690 : 2099 : tree lab1 = create_artificial_label (UNKNOWN_LOCATION);
4691 : 2099 : tree lab2 = create_artificial_label (UNKNOWN_LOCATION);
4692 : 2099 : t = build1 (GOTO_EXPR, void_type_node, lab2);
4693 : 2099 : append_to_statement_list (t, &pre_body);
4694 : 2099 : t = build1 (LABEL_EXPR, void_type_node, lab1);
4695 : 2099 : append_to_statement_list (t, &pre_body);
4696 : 2099 : tree this_post_body = NULL_TREE;
4697 : 2099 : if (POINTER_TYPE_P (type))
4698 : 52 : t = build2 (POINTER_PLUS_EXPR, type, decl,
4699 : : fold_convert (sizetype, step));
4700 : : else
4701 : 2047 : t = build2 (PLUS_EXPR, type, decl, step);
4702 : 2099 : t = build2 (MODIFY_EXPR, type, decl, t);
4703 : 2099 : append_to_statement_list (t, &this_post_body);
4704 : 2099 : t = build1 (LABEL_EXPR, void_type_node, lab2);
4705 : 2099 : append_to_statement_list (t, &this_post_body);
4706 : 2165 : t = build2 ((TREE_CODE (cond) == LT_EXPR || TREE_CODE (cond) == LE_EXPR)
4707 : : ? LT_EXPR : GT_EXPR, boolean_type_node, decl, end);
4708 : 2099 : if (orig_sizes == NULL_TREE)
4709 : : {
4710 : 745 : gcc_assert (i == 0);
4711 : 1490 : t = build3 (ANNOTATE_EXPR, TREE_TYPE (t), t,
4712 : 745 : build_int_cst (integer_type_node,
4713 : 745 : annot_expr_unroll_kind),
4714 : 745 : build_int_cst (integer_type_node, size));
4715 : : }
4716 : 2099 : t = build3 (COND_EXPR, void_type_node, t,
4717 : : build1 (GOTO_EXPR, void_type_node, lab1), NULL_TREE);
4718 : 2099 : append_to_statement_list (t, &this_post_body);
4719 : 2099 : append_to_statement_list (post_body, &this_post_body);
4720 : 2099 : post_body = this_post_body;
4721 : : }
4722 : 1907 : if (pre_body || post_body)
4723 : : {
4724 : 1614 : append_to_statement_list (OMP_FOR_BODY (for_stmt), &pre_body);
4725 : 1614 : append_to_statement_list (post_body, &pre_body);
4726 : 1614 : OMP_FOR_BODY (for_stmt) = pre_body;
4727 : : }
4728 : : }
4729 : :
4730 : : /* Callback for walk_tree to find nested loop transforming construct. */
4731 : :
4732 : : static tree
4733 : 9257 : find_nested_loop_xform (tree *tp, int *walk_subtrees, void *data)
4734 : : {
4735 : 9257 : tree **pdata = (tree **) data;
4736 : 9257 : *walk_subtrees = 0;
4737 : 9257 : switch (TREE_CODE (*tp))
4738 : : {
4739 : 1987 : case OMP_TILE:
4740 : 1987 : case OMP_UNROLL:
4741 : 1987 : pdata[1] = tp;
4742 : 1987 : return *tp;
4743 : 2581 : case BIND_EXPR:
4744 : 2581 : if (BIND_EXPR_VARS (*tp)
4745 : 2581 : || (BIND_EXPR_BLOCK (*tp)
4746 : 1270 : && BLOCK_VARS (BIND_EXPR_BLOCK (*tp))))
4747 : 1311 : pdata[0] = tp;
4748 : 2581 : *walk_subtrees = 1;
4749 : 2581 : break;
4750 : 425 : case STATEMENT_LIST:
4751 : 425 : if (!tsi_one_before_end_p (tsi_start (*tp)))
4752 : 425 : pdata[0] = tp;
4753 : 425 : *walk_subtrees = 1;
4754 : 425 : break;
4755 : 32 : case TRY_FINALLY_EXPR:
4756 : 32 : case CLEANUP_POINT_EXPR:
4757 : 32 : pdata[0] = tp;
4758 : 32 : *walk_subtrees = 1;
4759 : 32 : break;
4760 : : default:
4761 : : break;
4762 : : }
4763 : : return NULL;
4764 : : }
4765 : :
4766 : : /* Main entry point for performing OpenMP loop transformations. */
4767 : :
4768 : : void
4769 : 60599 : omp_maybe_apply_loop_xforms (tree *expr_p, tree for_clauses)
4770 : : {
4771 : 60599 : tree for_stmt = *expr_p;
4772 : :
4773 : 60599 : switch (TREE_CODE (for_stmt))
4774 : : {
4775 : 3923 : case OMP_TILE:
4776 : 3923 : case OMP_UNROLL:
4777 : 3923 : if (OMP_LOOPXFORM_LOWERED (for_stmt))
4778 : : return;
4779 : : break;
4780 : : default:
4781 : : break;
4782 : : }
4783 : :
4784 : : tree *inner_expr_p = expr_p;
4785 : : tree inner_for_stmt = for_stmt;
4786 : 143004 : for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
4787 : : {
4788 : : /* If some loop nest needs one or more loops in canonical form
4789 : : from nested loop transforming constructs, first perform the
4790 : : loop transformation on the nested construct and then move over
4791 : : the corresponding loops in canonical form from the inner construct
4792 : : to the outer one. */
4793 : 84127 : if (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i) == NULL_TREE)
4794 : : {
4795 : 1516 : if (inner_for_stmt == for_stmt
4796 : 3008 : && omp_find_clause (for_clauses ? for_clauses
4797 : 1492 : : OMP_FOR_CLAUSES (for_stmt),
4798 : : OMP_CLAUSE_ORDERED))
4799 : : {
4800 : 73 : error_at (EXPR_LOCATION (for_stmt),
4801 : : "%<ordered%> clause used with generated loops");
4802 : 73 : *expr_p = void_node;
4803 : 73 : return;
4804 : : }
4805 : 1443 : tree *data[2] = { NULL, NULL };
4806 : 1443 : walk_tree (&OMP_FOR_BODY (inner_for_stmt),
4807 : : find_nested_loop_xform, &data, NULL);
4808 : 1443 : gcc_assert (data[1]);
4809 : 1443 : if (data[0])
4810 : : {
4811 : : /* If there is a BIND_EXPR declaring some vars, or statement
4812 : : list with more than one stmt etc., move the intervening
4813 : : code around the outermost loop. */
4814 : 1008 : tree t = *inner_expr_p;
4815 : 1008 : *inner_expr_p = OMP_FOR_BODY (inner_for_stmt);
4816 : 1008 : OMP_FOR_BODY (inner_for_stmt) = *data[1];
4817 : 1008 : *data[1] = t;
4818 : 1008 : inner_expr_p = data[1];
4819 : 1008 : data[1] = &OMP_FOR_BODY (inner_for_stmt);
4820 : : }
4821 : 1443 : inner_for_stmt = *data[1];
4822 : :
4823 : 1443 : omp_maybe_apply_loop_xforms (data[1], NULL_TREE);
4824 : 1443 : if (*data[1] != inner_for_stmt)
4825 : : {
4826 : 544 : tree *data2[2] = { NULL, NULL };
4827 : 544 : walk_tree (data[1], find_nested_loop_xform, &data2, NULL);
4828 : 544 : gcc_assert (data2[1]
4829 : : && *data2[1] == inner_for_stmt
4830 : : && data2[0]);
4831 : 544 : tree t = *inner_expr_p;
4832 : 544 : *inner_expr_p = *data[1];
4833 : 544 : *data[1] = *data2[1];
4834 : 544 : *data2[1] = t;
4835 : 544 : inner_expr_p = data2[1];
4836 : : }
4837 : 1443 : tree clauses = OMP_FOR_CLAUSES (inner_for_stmt);
4838 : 1443 : gcc_checking_assert (TREE_CODE (inner_for_stmt) != OMP_UNROLL
4839 : : || omp_find_clause (clauses,
4840 : : OMP_CLAUSE_PARTIAL));
4841 : 1443 : append_to_statement_list (OMP_FOR_PRE_BODY (inner_for_stmt),
4842 : : &OMP_FOR_PRE_BODY (for_stmt));
4843 : 1443 : OMP_FOR_PRE_BODY (inner_for_stmt) = NULL_TREE;
4844 : 1443 : if (OMP_FOR_ORIG_DECLS (for_stmt) == NULL_TREE
4845 : 1443 : && OMP_FOR_ORIG_DECLS (inner_for_stmt) != NULL_TREE)
4846 : : {
4847 : 624 : OMP_FOR_ORIG_DECLS (for_stmt)
4848 : 1248 : = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)));
4849 : 1466 : for (int j = 0; j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt));
4850 : : j++)
4851 : : {
4852 : 842 : if (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j) == NULL_TREE)
4853 : 717 : continue;
4854 : 125 : gcc_assert (TREE_CODE (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt),
4855 : : j)) == MODIFY_EXPR);
4856 : 125 : TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), j)
4857 : 250 : = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j),
4858 : : 0);
4859 : : }
4860 : : }
4861 : 3104 : for (int j = 0; j < TREE_VEC_LENGTH (OMP_FOR_INIT (inner_for_stmt));
4862 : : ++j)
4863 : : {
4864 : 1924 : if (i + j == TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)))
4865 : : break;
4866 : 1661 : if (OMP_FOR_ORIG_DECLS (for_stmt))
4867 : : {
4868 : 1576 : if (OMP_FOR_ORIG_DECLS (inner_for_stmt))
4869 : : {
4870 : 1576 : TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i + j)
4871 : 1576 : = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt),
4872 : : j);
4873 : 1576 : TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), j)
4874 : 1576 : = NULL_TREE;
4875 : : }
4876 : : else
4877 : : {
4878 : 0 : tree t = TREE_VEC_ELT (OMP_FOR_INIT (inner_for_stmt), j);
4879 : 0 : gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
4880 : 0 : TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i + j)
4881 : 0 : = TREE_OPERAND (t, 0);
4882 : : }
4883 : : }
4884 : 1661 : TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i + j)
4885 : 1661 : = TREE_VEC_ELT (OMP_FOR_INIT (inner_for_stmt), j);
4886 : 1661 : TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i + j)
4887 : 1661 : = TREE_VEC_ELT (OMP_FOR_COND (inner_for_stmt), j);
4888 : 1661 : TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i + j)
4889 : 1661 : = TREE_VEC_ELT (OMP_FOR_INCR (inner_for_stmt), j);
4890 : 1661 : TREE_VEC_ELT (OMP_FOR_INIT (inner_for_stmt), j) = NULL_TREE;
4891 : 1661 : TREE_VEC_ELT (OMP_FOR_COND (inner_for_stmt), j) = NULL_TREE;
4892 : 1661 : TREE_VEC_ELT (OMP_FOR_INCR (inner_for_stmt), j) = NULL_TREE;
4893 : : }
4894 : : }
4895 : : }
4896 : :
4897 : 58877 : switch (TREE_CODE (for_stmt))
4898 : : {
4899 : 1165 : case OMP_TILE:
4900 : 1165 : tree sizes;
4901 : 1165 : sizes = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_SIZES);
4902 : 1165 : omp_apply_tile (for_stmt, OMP_CLAUSE_SIZES_LIST (sizes), 0);
4903 : 1165 : OMP_LOOPXFORM_LOWERED (for_stmt) = 1;
4904 : 1165 : break;
4905 : 1109 : case OMP_UNROLL:
4906 : 1109 : tree partial;
4907 : 1109 : partial = omp_find_clause (OMP_FOR_CLAUSES (for_stmt),
4908 : : OMP_CLAUSE_PARTIAL);
4909 : 1109 : if (partial)
4910 : 793 : omp_apply_tile (for_stmt, NULL_TREE,
4911 : 793 : OMP_CLAUSE_PARTIAL_EXPR (partial)
4912 : 609 : ? tree_to_shwi (OMP_CLAUSE_PARTIAL_EXPR (partial))
4913 : : : 8);
4914 : 316 : else if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_FULL))
4915 : : {
4916 : 274 : tree iters = omp_loop_number_of_iterations (for_stmt, 0, NULL);
4917 : 274 : if (TREE_CODE (iters) != INTEGER_CST)
4918 : 12 : error_at (EXPR_LOCATION (for_stmt),
4919 : : "non-constant iteration count of %<unroll full%> loop");
4920 : : }
4921 : 1109 : OMP_LOOPXFORM_LOWERED (for_stmt) = 1;
4922 : 1109 : break;
4923 : : default:
4924 : : break;
4925 : : }
4926 : : }
4927 : :
|