]>
Commit | Line | Data |
---|---|---|
629b3d75 MJ |
1 | /* General types and functions that are uselful for processing of OpenMP, |
2 | OpenACC and similar directivers at various stages of compilation. | |
3 | ||
85ec4feb | 4 | Copyright (C) 2005-2018 Free Software Foundation, Inc. |
629b3d75 MJ |
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 | /* Find an OMP clause of type KIND within CLAUSES. */ | |
23 | ||
24 | #include "config.h" | |
25 | #include "system.h" | |
26 | #include "coretypes.h" | |
27 | #include "backend.h" | |
28 | #include "target.h" | |
29 | #include "tree.h" | |
30 | #include "gimple.h" | |
31 | #include "ssa.h" | |
32 | #include "diagnostic-core.h" | |
33 | #include "fold-const.h" | |
34 | #include "langhooks.h" | |
35 | #include "omp-general.h" | |
314e6352 ML |
36 | #include "stringpool.h" |
37 | #include "attribs.h" | |
629b3d75 MJ |
38 | |
39 | tree | |
40 | omp_find_clause (tree clauses, enum omp_clause_code kind) | |
41 | { | |
42 | for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses)) | |
43 | if (OMP_CLAUSE_CODE (clauses) == kind) | |
44 | return clauses; | |
45 | ||
46 | return NULL_TREE; | |
47 | } | |
48 | ||
49 | /* Return true if DECL is a reference type. */ | |
50 | ||
51 | bool | |
52 | omp_is_reference (tree decl) | |
53 | { | |
54 | return lang_hooks.decls.omp_privatize_by_reference (decl); | |
55 | } | |
56 | ||
57 | /* Adjust *COND_CODE and *N2 so that the former is either LT_EXPR or | |
58 | GT_EXPR. */ | |
59 | ||
60 | void | |
61 | omp_adjust_for_condition (location_t loc, enum tree_code *cond_code, tree *n2) | |
62 | { | |
63 | switch (*cond_code) | |
64 | { | |
65 | case LT_EXPR: | |
66 | case GT_EXPR: | |
67 | case NE_EXPR: | |
68 | break; | |
69 | case LE_EXPR: | |
70 | if (POINTER_TYPE_P (TREE_TYPE (*n2))) | |
71 | *n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, 1); | |
72 | else | |
73 | *n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (*n2), *n2, | |
74 | build_int_cst (TREE_TYPE (*n2), 1)); | |
75 | *cond_code = LT_EXPR; | |
76 | break; | |
77 | case GE_EXPR: | |
78 | if (POINTER_TYPE_P (TREE_TYPE (*n2))) | |
79 | *n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, -1); | |
80 | else | |
81 | *n2 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (*n2), *n2, | |
82 | build_int_cst (TREE_TYPE (*n2), 1)); | |
83 | *cond_code = GT_EXPR; | |
84 | break; | |
85 | default: | |
86 | gcc_unreachable (); | |
87 | } | |
88 | } | |
89 | ||
90 | /* Return the looping step from INCR, extracted from the step of a gimple omp | |
91 | for statement. */ | |
92 | ||
93 | tree | |
94 | omp_get_for_step_from_incr (location_t loc, tree incr) | |
95 | { | |
96 | tree step; | |
97 | switch (TREE_CODE (incr)) | |
98 | { | |
99 | case PLUS_EXPR: | |
100 | step = TREE_OPERAND (incr, 1); | |
101 | break; | |
102 | case POINTER_PLUS_EXPR: | |
103 | step = fold_convert (ssizetype, TREE_OPERAND (incr, 1)); | |
104 | break; | |
105 | case MINUS_EXPR: | |
106 | step = TREE_OPERAND (incr, 1); | |
107 | step = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (step), step); | |
108 | break; | |
109 | default: | |
110 | gcc_unreachable (); | |
111 | } | |
112 | return step; | |
113 | } | |
114 | ||
115 | /* Extract the header elements of parallel loop FOR_STMT and store | |
116 | them into *FD. */ | |
117 | ||
118 | void | |
119 | omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd, | |
120 | struct omp_for_data_loop *loops) | |
121 | { | |
122 | tree t, var, *collapse_iter, *collapse_count; | |
123 | tree count = NULL_TREE, iter_type = long_integer_type_node; | |
124 | struct omp_for_data_loop *loop; | |
125 | int i; | |
126 | struct omp_for_data_loop dummy_loop; | |
127 | location_t loc = gimple_location (for_stmt); | |
128 | bool simd = gimple_omp_for_kind (for_stmt) & GF_OMP_FOR_SIMD; | |
129 | bool distribute = gimple_omp_for_kind (for_stmt) | |
130 | == GF_OMP_FOR_KIND_DISTRIBUTE; | |
131 | bool taskloop = gimple_omp_for_kind (for_stmt) | |
132 | == GF_OMP_FOR_KIND_TASKLOOP; | |
133 | tree iterv, countv; | |
134 | ||
135 | fd->for_stmt = for_stmt; | |
136 | fd->pre = NULL; | |
629b3d75 MJ |
137 | fd->have_nowait = distribute || simd; |
138 | fd->have_ordered = false; | |
02889d23 | 139 | fd->tiling = NULL_TREE; |
629b3d75 MJ |
140 | fd->collapse = 1; |
141 | fd->ordered = 0; | |
142 | fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC; | |
143 | fd->sched_modifiers = 0; | |
144 | fd->chunk_size = NULL_TREE; | |
145 | fd->simd_schedule = false; | |
629b3d75 MJ |
146 | collapse_iter = NULL; |
147 | collapse_count = NULL; | |
148 | ||
149 | for (t = gimple_omp_for_clauses (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t)) | |
150 | switch (OMP_CLAUSE_CODE (t)) | |
151 | { | |
152 | case OMP_CLAUSE_NOWAIT: | |
153 | fd->have_nowait = true; | |
154 | break; | |
155 | case OMP_CLAUSE_ORDERED: | |
156 | fd->have_ordered = true; | |
157 | if (OMP_CLAUSE_ORDERED_EXPR (t)) | |
158 | fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t)); | |
159 | break; | |
160 | case OMP_CLAUSE_SCHEDULE: | |
161 | gcc_assert (!distribute && !taskloop); | |
162 | fd->sched_kind | |
163 | = (enum omp_clause_schedule_kind) | |
164 | (OMP_CLAUSE_SCHEDULE_KIND (t) & OMP_CLAUSE_SCHEDULE_MASK); | |
165 | fd->sched_modifiers = (OMP_CLAUSE_SCHEDULE_KIND (t) | |
166 | & ~OMP_CLAUSE_SCHEDULE_MASK); | |
167 | fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t); | |
168 | fd->simd_schedule = OMP_CLAUSE_SCHEDULE_SIMD (t); | |
169 | break; | |
170 | case OMP_CLAUSE_DIST_SCHEDULE: | |
171 | gcc_assert (distribute); | |
172 | fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t); | |
173 | break; | |
174 | case OMP_CLAUSE_COLLAPSE: | |
175 | fd->collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t)); | |
176 | if (fd->collapse > 1) | |
177 | { | |
178 | collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t); | |
179 | collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t); | |
180 | } | |
181 | break; | |
02889d23 CLT |
182 | case OMP_CLAUSE_TILE: |
183 | fd->tiling = OMP_CLAUSE_TILE_LIST (t); | |
184 | fd->collapse = list_length (fd->tiling); | |
185 | gcc_assert (fd->collapse); | |
186 | collapse_iter = &OMP_CLAUSE_TILE_ITERVAR (t); | |
187 | collapse_count = &OMP_CLAUSE_TILE_COUNT (t); | |
188 | break; | |
629b3d75 MJ |
189 | default: |
190 | break; | |
191 | } | |
02889d23 CLT |
192 | |
193 | if (fd->collapse > 1 || fd->tiling) | |
194 | fd->loops = loops; | |
195 | else | |
196 | fd->loops = &fd->loop; | |
197 | ||
629b3d75 MJ |
198 | if (fd->ordered && fd->collapse == 1 && loops != NULL) |
199 | { | |
200 | fd->loops = loops; | |
201 | iterv = NULL_TREE; | |
202 | countv = NULL_TREE; | |
203 | collapse_iter = &iterv; | |
204 | collapse_count = &countv; | |
205 | } | |
206 | ||
207 | /* FIXME: for now map schedule(auto) to schedule(static). | |
208 | There should be analysis to determine whether all iterations | |
209 | are approximately the same amount of work (then schedule(static) | |
210 | is best) or if it varies (then schedule(dynamic,N) is better). */ | |
211 | if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO) | |
212 | { | |
213 | fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC; | |
214 | gcc_assert (fd->chunk_size == NULL); | |
215 | } | |
02889d23 | 216 | gcc_assert ((fd->collapse == 1 && !fd->tiling) || collapse_iter != NULL); |
629b3d75 MJ |
217 | if (taskloop) |
218 | fd->sched_kind = OMP_CLAUSE_SCHEDULE_RUNTIME; | |
219 | if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME) | |
220 | gcc_assert (fd->chunk_size == NULL); | |
221 | else if (fd->chunk_size == NULL) | |
222 | { | |
223 | /* We only need to compute a default chunk size for ordered | |
224 | static loops and dynamic loops. */ | |
225 | if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC | |
226 | || fd->have_ordered) | |
227 | fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC) | |
228 | ? integer_zero_node : integer_one_node; | |
229 | } | |
230 | ||
231 | int cnt = fd->ordered ? fd->ordered : fd->collapse; | |
232 | for (i = 0; i < cnt; i++) | |
233 | { | |
02889d23 CLT |
234 | if (i == 0 |
235 | && fd->collapse == 1 | |
236 | && !fd->tiling | |
237 | && (fd->ordered == 0 || loops == NULL)) | |
629b3d75 MJ |
238 | loop = &fd->loop; |
239 | else if (loops != NULL) | |
240 | loop = loops + i; | |
241 | else | |
242 | loop = &dummy_loop; | |
243 | ||
244 | loop->v = gimple_omp_for_index (for_stmt, i); | |
245 | gcc_assert (SSA_VAR_P (loop->v)); | |
246 | gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE | |
247 | || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE); | |
248 | var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v; | |
249 | loop->n1 = gimple_omp_for_initial (for_stmt, i); | |
250 | ||
251 | loop->cond_code = gimple_omp_for_cond (for_stmt, i); | |
252 | loop->n2 = gimple_omp_for_final (for_stmt, i); | |
5e9d6aa4 | 253 | gcc_assert (loop->cond_code != NE_EXPR); |
629b3d75 MJ |
254 | omp_adjust_for_condition (loc, &loop->cond_code, &loop->n2); |
255 | ||
256 | t = gimple_omp_for_incr (for_stmt, i); | |
257 | gcc_assert (TREE_OPERAND (t, 0) == var); | |
258 | loop->step = omp_get_for_step_from_incr (loc, t); | |
259 | ||
260 | if (simd | |
261 | || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC | |
262 | && !fd->have_ordered)) | |
263 | { | |
02889d23 | 264 | if (fd->collapse == 1 && !fd->tiling) |
629b3d75 MJ |
265 | iter_type = TREE_TYPE (loop->v); |
266 | else if (i == 0 | |
267 | || TYPE_PRECISION (iter_type) | |
268 | < TYPE_PRECISION (TREE_TYPE (loop->v))) | |
269 | iter_type | |
270 | = build_nonstandard_integer_type | |
271 | (TYPE_PRECISION (TREE_TYPE (loop->v)), 1); | |
272 | } | |
273 | else if (iter_type != long_long_unsigned_type_node) | |
274 | { | |
275 | if (POINTER_TYPE_P (TREE_TYPE (loop->v))) | |
276 | iter_type = long_long_unsigned_type_node; | |
277 | else if (TYPE_UNSIGNED (TREE_TYPE (loop->v)) | |
278 | && TYPE_PRECISION (TREE_TYPE (loop->v)) | |
279 | >= TYPE_PRECISION (iter_type)) | |
280 | { | |
281 | tree n; | |
282 | ||
283 | if (loop->cond_code == LT_EXPR) | |
284 | n = fold_build2_loc (loc, | |
285 | PLUS_EXPR, TREE_TYPE (loop->v), | |
286 | loop->n2, loop->step); | |
287 | else | |
288 | n = loop->n1; | |
289 | if (TREE_CODE (n) != INTEGER_CST | |
290 | || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n)) | |
291 | iter_type = long_long_unsigned_type_node; | |
292 | } | |
293 | else if (TYPE_PRECISION (TREE_TYPE (loop->v)) | |
294 | > TYPE_PRECISION (iter_type)) | |
295 | { | |
296 | tree n1, n2; | |
297 | ||
298 | if (loop->cond_code == LT_EXPR) | |
299 | { | |
300 | n1 = loop->n1; | |
301 | n2 = fold_build2_loc (loc, | |
302 | PLUS_EXPR, TREE_TYPE (loop->v), | |
303 | loop->n2, loop->step); | |
304 | } | |
305 | else | |
306 | { | |
307 | n1 = fold_build2_loc (loc, | |
308 | MINUS_EXPR, TREE_TYPE (loop->v), | |
309 | loop->n2, loop->step); | |
310 | n2 = loop->n1; | |
311 | } | |
312 | if (TREE_CODE (n1) != INTEGER_CST | |
313 | || TREE_CODE (n2) != INTEGER_CST | |
314 | || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1) | |
315 | || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type))) | |
316 | iter_type = long_long_unsigned_type_node; | |
317 | } | |
318 | } | |
319 | ||
320 | if (i >= fd->collapse) | |
321 | continue; | |
322 | ||
323 | if (collapse_count && *collapse_count == NULL) | |
324 | { | |
325 | t = fold_binary (loop->cond_code, boolean_type_node, | |
326 | fold_convert (TREE_TYPE (loop->v), loop->n1), | |
327 | fold_convert (TREE_TYPE (loop->v), loop->n2)); | |
328 | if (t && integer_zerop (t)) | |
329 | count = build_zero_cst (long_long_unsigned_type_node); | |
330 | else if ((i == 0 || count != NULL_TREE) | |
331 | && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE | |
332 | && TREE_CONSTANT (loop->n1) | |
333 | && TREE_CONSTANT (loop->n2) | |
334 | && TREE_CODE (loop->step) == INTEGER_CST) | |
335 | { | |
336 | tree itype = TREE_TYPE (loop->v); | |
337 | ||
338 | if (POINTER_TYPE_P (itype)) | |
339 | itype = signed_type_for (itype); | |
340 | t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1)); | |
341 | t = fold_build2_loc (loc, | |
342 | PLUS_EXPR, itype, | |
343 | fold_convert_loc (loc, itype, loop->step), t); | |
344 | t = fold_build2_loc (loc, PLUS_EXPR, itype, t, | |
345 | fold_convert_loc (loc, itype, loop->n2)); | |
346 | t = fold_build2_loc (loc, MINUS_EXPR, itype, t, | |
347 | fold_convert_loc (loc, itype, loop->n1)); | |
348 | if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR) | |
349 | t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, | |
350 | fold_build1_loc (loc, NEGATE_EXPR, itype, t), | |
351 | fold_build1_loc (loc, NEGATE_EXPR, itype, | |
352 | fold_convert_loc (loc, itype, | |
353 | loop->step))); | |
354 | else | |
355 | t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, t, | |
356 | fold_convert_loc (loc, itype, loop->step)); | |
357 | t = fold_convert_loc (loc, long_long_unsigned_type_node, t); | |
358 | if (count != NULL_TREE) | |
359 | count = fold_build2_loc (loc, | |
360 | MULT_EXPR, long_long_unsigned_type_node, | |
361 | count, t); | |
362 | else | |
363 | count = t; | |
364 | if (TREE_CODE (count) != INTEGER_CST) | |
365 | count = NULL_TREE; | |
366 | } | |
367 | else if (count && !integer_zerop (count)) | |
368 | count = NULL_TREE; | |
369 | } | |
370 | } | |
371 | ||
372 | if (count | |
373 | && !simd | |
374 | && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC | |
375 | || fd->have_ordered)) | |
376 | { | |
377 | if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node))) | |
378 | iter_type = long_long_unsigned_type_node; | |
379 | else | |
380 | iter_type = long_integer_type_node; | |
381 | } | |
382 | else if (collapse_iter && *collapse_iter != NULL) | |
383 | iter_type = TREE_TYPE (*collapse_iter); | |
384 | fd->iter_type = iter_type; | |
385 | if (collapse_iter && *collapse_iter == NULL) | |
386 | *collapse_iter = create_tmp_var (iter_type, ".iter"); | |
387 | if (collapse_count && *collapse_count == NULL) | |
388 | { | |
389 | if (count) | |
390 | *collapse_count = fold_convert_loc (loc, iter_type, count); | |
391 | else | |
392 | *collapse_count = create_tmp_var (iter_type, ".count"); | |
393 | } | |
394 | ||
02889d23 | 395 | if (fd->collapse > 1 || fd->tiling || (fd->ordered && loops)) |
629b3d75 MJ |
396 | { |
397 | fd->loop.v = *collapse_iter; | |
398 | fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0); | |
399 | fd->loop.n2 = *collapse_count; | |
400 | fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1); | |
401 | fd->loop.cond_code = LT_EXPR; | |
402 | } | |
403 | else if (loops) | |
404 | loops[0] = fd->loop; | |
405 | } | |
406 | ||
407 | /* Build a call to GOMP_barrier. */ | |
408 | ||
409 | gimple * | |
410 | omp_build_barrier (tree lhs) | |
411 | { | |
412 | tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL | |
413 | : BUILT_IN_GOMP_BARRIER); | |
414 | gcall *g = gimple_build_call (fndecl, 0); | |
415 | if (lhs) | |
416 | gimple_call_set_lhs (g, lhs); | |
417 | return g; | |
418 | } | |
419 | ||
420 | /* Return maximum possible vectorization factor for the target. */ | |
421 | ||
9d2f08ab | 422 | poly_uint64 |
629b3d75 MJ |
423 | omp_max_vf (void) |
424 | { | |
425 | if (!optimize | |
426 | || optimize_debug | |
427 | || !flag_tree_loop_optimize | |
428 | || (!flag_tree_loop_vectorize | |
26d476cd | 429 | && global_options_set.x_flag_tree_loop_vectorize)) |
629b3d75 MJ |
430 | return 1; |
431 | ||
86e36728 RS |
432 | auto_vector_sizes sizes; |
433 | targetm.vectorize.autovectorize_vector_sizes (&sizes); | |
434 | if (!sizes.is_empty ()) | |
629b3d75 | 435 | { |
86e36728 RS |
436 | poly_uint64 vf = 0; |
437 | for (unsigned int i = 0; i < sizes.length (); ++i) | |
438 | vf = ordered_max (vf, sizes[i]); | |
439 | return vf; | |
629b3d75 | 440 | } |
86e36728 RS |
441 | |
442 | machine_mode vqimode = targetm.vectorize.preferred_simd_mode (QImode); | |
443 | if (GET_MODE_CLASS (vqimode) == MODE_VECTOR_INT) | |
444 | return GET_MODE_NUNITS (vqimode); | |
445 | ||
446 | return 1; | |
629b3d75 MJ |
447 | } |
448 | ||
449 | /* Return maximum SIMT width if offloading may target SIMT hardware. */ | |
450 | ||
451 | int | |
452 | omp_max_simt_vf (void) | |
453 | { | |
454 | if (!optimize) | |
455 | return 0; | |
456 | if (ENABLE_OFFLOADING) | |
01914336 | 457 | for (const char *c = getenv ("OFFLOAD_TARGET_NAMES"); c;) |
629b3d75 MJ |
458 | { |
459 | if (!strncmp (c, "nvptx", strlen ("nvptx"))) | |
460 | return 32; | |
461 | else if ((c = strchr (c, ','))) | |
462 | c++; | |
463 | } | |
464 | return 0; | |
465 | } | |
466 | ||
467 | /* Encode an oacc launch argument. This matches the GOMP_LAUNCH_PACK | |
468 | macro on gomp-constants.h. We do not check for overflow. */ | |
469 | ||
470 | tree | |
471 | oacc_launch_pack (unsigned code, tree device, unsigned op) | |
472 | { | |
473 | tree res; | |
474 | ||
475 | res = build_int_cst (unsigned_type_node, GOMP_LAUNCH_PACK (code, 0, op)); | |
476 | if (device) | |
477 | { | |
478 | device = fold_build2 (LSHIFT_EXPR, unsigned_type_node, | |
479 | device, build_int_cst (unsigned_type_node, | |
480 | GOMP_LAUNCH_DEVICE_SHIFT)); | |
481 | res = fold_build2 (BIT_IOR_EXPR, unsigned_type_node, res, device); | |
482 | } | |
483 | return res; | |
484 | } | |
485 | ||
486 | /* FIXME: What is the following comment for? */ | |
487 | /* Look for compute grid dimension clauses and convert to an attribute | |
488 | attached to FN. This permits the target-side code to (a) massage | |
489 | the dimensions, (b) emit that data and (c) optimize. Non-constant | |
490 | dimensions are pushed onto ARGS. | |
491 | ||
492 | The attribute value is a TREE_LIST. A set of dimensions is | |
493 | represented as a list of INTEGER_CST. Those that are runtime | |
494 | exprs are represented as an INTEGER_CST of zero. | |
495 | ||
01914336 | 496 | TODO: Normally the attribute will just contain a single such list. If |
629b3d75 MJ |
497 | however it contains a list of lists, this will represent the use of |
498 | device_type. Each member of the outer list is an assoc list of | |
499 | dimensions, keyed by the device type. The first entry will be the | |
500 | default. Well, that's the plan. */ | |
501 | ||
502 | /* Replace any existing oacc fn attribute with updated dimensions. */ | |
503 | ||
504 | void | |
505 | oacc_replace_fn_attrib (tree fn, tree dims) | |
506 | { | |
507 | tree ident = get_identifier (OACC_FN_ATTRIB); | |
508 | tree attribs = DECL_ATTRIBUTES (fn); | |
509 | ||
510 | /* If we happen to be present as the first attrib, drop it. */ | |
511 | if (attribs && TREE_PURPOSE (attribs) == ident) | |
512 | attribs = TREE_CHAIN (attribs); | |
513 | DECL_ATTRIBUTES (fn) = tree_cons (ident, dims, attribs); | |
514 | } | |
515 | ||
516 | /* Scan CLAUSES for launch dimensions and attach them to the oacc | |
517 | function attribute. Push any that are non-constant onto the ARGS | |
25651634 | 518 | list, along with an appropriate GOMP_LAUNCH_DIM tag. */ |
629b3d75 MJ |
519 | |
520 | void | |
25651634 | 521 | oacc_set_fn_attrib (tree fn, tree clauses, vec<tree> *args) |
629b3d75 MJ |
522 | { |
523 | /* Must match GOMP_DIM ordering. */ | |
524 | static const omp_clause_code ids[] | |
525 | = { OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS, | |
526 | OMP_CLAUSE_VECTOR_LENGTH }; | |
527 | unsigned ix; | |
528 | tree dims[GOMP_DIM_MAX]; | |
529 | ||
530 | tree attr = NULL_TREE; | |
531 | unsigned non_const = 0; | |
532 | ||
533 | for (ix = GOMP_DIM_MAX; ix--;) | |
534 | { | |
535 | tree clause = omp_find_clause (clauses, ids[ix]); | |
536 | tree dim = NULL_TREE; | |
537 | ||
538 | if (clause) | |
539 | dim = OMP_CLAUSE_EXPR (clause, ids[ix]); | |
540 | dims[ix] = dim; | |
541 | if (dim && TREE_CODE (dim) != INTEGER_CST) | |
542 | { | |
543 | dim = integer_zero_node; | |
544 | non_const |= GOMP_DIM_MASK (ix); | |
545 | } | |
546 | attr = tree_cons (NULL_TREE, dim, attr); | |
629b3d75 MJ |
547 | } |
548 | ||
549 | oacc_replace_fn_attrib (fn, attr); | |
550 | ||
551 | if (non_const) | |
552 | { | |
553 | /* Push a dynamic argument set. */ | |
554 | args->safe_push (oacc_launch_pack (GOMP_LAUNCH_DIM, | |
555 | NULL_TREE, non_const)); | |
556 | for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++) | |
557 | if (non_const & GOMP_DIM_MASK (ix)) | |
558 | args->safe_push (dims[ix]); | |
559 | } | |
560 | } | |
561 | ||
562 | /* Process the routine's dimension clauess to generate an attribute | |
563 | value. Issue diagnostics as appropriate. We default to SEQ | |
564 | (OpenACC 2.5 clarifies this). All dimensions have a size of zero | |
565 | (dynamic). TREE_PURPOSE is set to indicate whether that dimension | |
566 | can have a loop partitioned on it. non-zero indicates | |
567 | yes, zero indicates no. By construction once a non-zero has been | |
568 | reached, further inner dimensions must also be non-zero. We set | |
569 | TREE_VALUE to zero for the dimensions that may be partitioned and | |
570 | 1 for the other ones -- if a loop is (erroneously) spawned at | |
571 | an outer level, we don't want to try and partition it. */ | |
572 | ||
573 | tree | |
574 | oacc_build_routine_dims (tree clauses) | |
575 | { | |
576 | /* Must match GOMP_DIM ordering. */ | |
01914336 MJ |
577 | static const omp_clause_code ids[] |
578 | = {OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ}; | |
629b3d75 MJ |
579 | int ix; |
580 | int level = -1; | |
581 | ||
582 | for (; clauses; clauses = OMP_CLAUSE_CHAIN (clauses)) | |
583 | for (ix = GOMP_DIM_MAX + 1; ix--;) | |
584 | if (OMP_CLAUSE_CODE (clauses) == ids[ix]) | |
585 | { | |
586 | if (level >= 0) | |
587 | error_at (OMP_CLAUSE_LOCATION (clauses), | |
588 | "multiple loop axes specified for routine"); | |
589 | level = ix; | |
590 | break; | |
591 | } | |
592 | ||
593 | /* Default to SEQ. */ | |
594 | if (level < 0) | |
595 | level = GOMP_DIM_MAX; | |
596 | ||
597 | tree dims = NULL_TREE; | |
598 | ||
599 | for (ix = GOMP_DIM_MAX; ix--;) | |
600 | dims = tree_cons (build_int_cst (boolean_type_node, ix >= level), | |
601 | build_int_cst (integer_type_node, ix < level), dims); | |
602 | ||
603 | return dims; | |
604 | } | |
605 | ||
606 | /* Retrieve the oacc function attrib and return it. Non-oacc | |
607 | functions will return NULL. */ | |
608 | ||
609 | tree | |
610 | oacc_get_fn_attrib (tree fn) | |
611 | { | |
612 | return lookup_attribute (OACC_FN_ATTRIB, DECL_ATTRIBUTES (fn)); | |
613 | } | |
614 | ||
46dbeb40 TV |
615 | /* Return true if FN is an OpenMP or OpenACC offloading function. */ |
616 | ||
617 | bool | |
618 | offloading_function_p (tree fn) | |
619 | { | |
620 | tree attrs = DECL_ATTRIBUTES (fn); | |
621 | return (lookup_attribute ("omp declare target", attrs) | |
622 | || lookup_attribute ("omp target entrypoint", attrs)); | |
623 | } | |
624 | ||
629b3d75 MJ |
625 | /* Extract an oacc execution dimension from FN. FN must be an |
626 | offloaded function or routine that has already had its execution | |
627 | dimensions lowered to the target-specific values. */ | |
628 | ||
629 | int | |
630 | oacc_get_fn_dim_size (tree fn, int axis) | |
631 | { | |
632 | tree attrs = oacc_get_fn_attrib (fn); | |
633 | ||
634 | gcc_assert (axis < GOMP_DIM_MAX); | |
635 | ||
636 | tree dims = TREE_VALUE (attrs); | |
637 | while (axis--) | |
638 | dims = TREE_CHAIN (dims); | |
639 | ||
640 | int size = TREE_INT_CST_LOW (TREE_VALUE (dims)); | |
641 | ||
642 | return size; | |
643 | } | |
644 | ||
645 | /* Extract the dimension axis from an IFN_GOACC_DIM_POS or | |
646 | IFN_GOACC_DIM_SIZE call. */ | |
647 | ||
648 | int | |
649 | oacc_get_ifn_dim_arg (const gimple *stmt) | |
650 | { | |
651 | gcc_checking_assert (gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_SIZE | |
652 | || gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_POS); | |
653 | tree arg = gimple_call_arg (stmt, 0); | |
654 | HOST_WIDE_INT axis = TREE_INT_CST_LOW (arg); | |
655 | ||
656 | gcc_checking_assert (axis >= 0 && axis < GOMP_DIM_MAX); | |
657 | return (int) axis; | |
658 | } |