111
|
1 /* General types and functions that are uselful for processing of OpenMP,
|
|
2 OpenACC and similar directivers at various stages of compilation.
|
|
3
|
131
|
4 Copyright (C) 2005-2018 Free Software Foundation, Inc.
|
111
|
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"
|
|
36 #include "stringpool.h"
|
|
37 #include "attribs.h"
|
|
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;
|
|
137 fd->have_nowait = distribute || simd;
|
|
138 fd->have_ordered = false;
|
|
139 fd->tiling = NULL_TREE;
|
|
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;
|
|
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;
|
|
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;
|
|
189 default:
|
|
190 break;
|
|
191 }
|
|
192
|
|
193 if (fd->collapse > 1 || fd->tiling)
|
|
194 fd->loops = loops;
|
|
195 else
|
|
196 fd->loops = &fd->loop;
|
|
197
|
|
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 }
|
|
216 gcc_assert ((fd->collapse == 1 && !fd->tiling) || collapse_iter != NULL);
|
|
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 {
|
|
234 if (i == 0
|
|
235 && fd->collapse == 1
|
|
236 && !fd->tiling
|
|
237 && (fd->ordered == 0 || loops == NULL))
|
|
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);
|
131
|
253 gcc_assert (loop->cond_code != NE_EXPR);
|
111
|
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 {
|
|
264 if (fd->collapse == 1 && !fd->tiling)
|
|
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
|
|
395 if (fd->collapse > 1 || fd->tiling || (fd->ordered && loops))
|
|
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
|
131
|
422 poly_uint64
|
111
|
423 omp_max_vf (void)
|
|
424 {
|
|
425 if (!optimize
|
|
426 || optimize_debug
|
|
427 || !flag_tree_loop_optimize
|
|
428 || (!flag_tree_loop_vectorize
|
|
429 && global_options_set.x_flag_tree_loop_vectorize))
|
|
430 return 1;
|
|
431
|
131
|
432 auto_vector_sizes sizes;
|
|
433 targetm.vectorize.autovectorize_vector_sizes (&sizes);
|
|
434 if (!sizes.is_empty ())
|
111
|
435 {
|
131
|
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;
|
111
|
440 }
|
131
|
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;
|
111
|
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)
|
|
457 for (const char *c = getenv ("OFFLOAD_TARGET_NAMES"); c;)
|
|
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
|
|
496 TODO: Normally the attribute will just contain a single such list. If
|
|
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
|
|
518 list, along with an appropriate GOMP_LAUNCH_DIM tag. */
|
|
519
|
|
520 void
|
|
521 oacc_set_fn_attrib (tree fn, tree clauses, vec<tree> *args)
|
|
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);
|
|
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. */
|
|
577 static const omp_clause_code ids[]
|
|
578 = {OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ};
|
|
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
|
131
|
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
|
111
|
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 }
|