Branch data Line data Source code
1 : : /* Bits of OpenMP and OpenACC handling that is specific to device offloading
2 : : and a lowering pass for OpenACC device directives.
3 : :
4 : : Copyright (C) 2005-2024 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 "tree-pass.h"
30 : : #include "ssa.h"
31 : : #include "cgraph.h"
32 : : #include "pretty-print.h"
33 : : #include "diagnostic-core.h"
34 : : #include "fold-const.h"
35 : : #include "internal-fn.h"
36 : : #include "langhooks.h"
37 : : #include "gimplify.h"
38 : : #include "gimple-iterator.h"
39 : : #include "gimplify-me.h"
40 : : #include "gimple-walk.h"
41 : : #include "tree-cfg.h"
42 : : #include "tree-into-ssa.h"
43 : : #include "tree-nested.h"
44 : : #include "stor-layout.h"
45 : : #include "common/common-target.h"
46 : : #include "omp-general.h"
47 : : #include "omp-offload.h"
48 : : #include "lto-section-names.h"
49 : : #include "gomp-constants.h"
50 : : #include "gimple-pretty-print.h"
51 : : #include "intl.h"
52 : : #include "stringpool.h"
53 : : #include "attribs.h"
54 : : #include "cfgloop.h"
55 : : #include "context.h"
56 : : #include "convert.h"
57 : : #include "opts.h"
58 : :
59 : : /* Describe the OpenACC looping structure of a function. The entire
60 : : function is held in a 'NULL' loop. */
61 : :
62 : : struct oacc_loop
63 : : {
64 : : oacc_loop *parent; /* Containing loop. */
65 : :
66 : : oacc_loop *child; /* First inner loop. */
67 : :
68 : : oacc_loop *sibling; /* Next loop within same parent. */
69 : :
70 : : location_t loc; /* Location of the loop start. */
71 : :
72 : : gcall *marker; /* Initial head marker. */
73 : :
74 : : gcall *heads[GOMP_DIM_MAX]; /* Head marker functions. */
75 : : gcall *tails[GOMP_DIM_MAX]; /* Tail marker functions. */
76 : :
77 : : tree routine; /* Pseudo-loop enclosing a routine. */
78 : :
79 : : unsigned mask; /* Partitioning mask. */
80 : : unsigned e_mask; /* Partitioning of element loops (when tiling). */
81 : : unsigned inner; /* Partitioning of inner loops. */
82 : : unsigned flags; /* Partitioning flags. */
83 : : vec<gcall *> ifns; /* Contained loop abstraction functions. */
84 : : tree chunk_size; /* Chunk size. */
85 : : gcall *head_end; /* Final marker of head sequence. */
86 : : };
87 : :
88 : : /* Holds offload tables with decls. */
89 : : vec<tree, va_gc> *offload_funcs, *offload_vars, *offload_ind_funcs;
90 : :
91 : : /* Return level at which oacc routine may spawn a partitioned loop, or
92 : : -1 if it is not a routine (i.e. is an offload fn). */
93 : :
94 : : int
95 : 10584 : oacc_fn_attrib_level (tree attr)
96 : : {
97 : 10584 : tree pos = TREE_VALUE (attr);
98 : :
99 : 10584 : if (!TREE_PURPOSE (pos))
100 : : return -1;
101 : :
102 : : int ix = 0;
103 : 4937 : for (ix = 0; ix != GOMP_DIM_MAX;
104 : 3299 : ix++, pos = TREE_CHAIN (pos))
105 : 4062 : if (!integer_zerop (TREE_PURPOSE (pos)))
106 : : break;
107 : :
108 : : return ix;
109 : : }
110 : :
111 : : /* Helper function for omp_finish_file routine. Takes decls from V_DECLS and
112 : : adds their addresses and sizes to constructor-vector V_CTOR. */
113 : :
114 : : static void
115 : 90 : add_decls_addresses_to_decl_constructor (vec<tree, va_gc> *v_decls,
116 : : vec<constructor_elt, va_gc> *v_ctor)
117 : : {
118 : 90 : unsigned len = vec_safe_length (v_decls);
119 : 169 : for (unsigned i = 0; i < len; i++)
120 : : {
121 : 79 : tree it = (*v_decls)[i];
122 : 79 : bool is_var = VAR_P (it);
123 : 79 : bool is_link_var
124 : : = is_var
125 : : #ifdef ACCEL_COMPILER
126 : : && DECL_HAS_VALUE_EXPR_P (it)
127 : : #endif
128 : 79 : && lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (it));
129 : :
130 : : /* See also omp_finish_file and output_offload_tables in lto-cgraph.cc. */
131 : 79 : if (!in_lto_p && !symtab_node::get (it))
132 : 0 : continue;
133 : :
134 : 79 : tree size = NULL_TREE;
135 : 79 : if (is_var)
136 : 0 : size = fold_convert (const_ptr_type_node, DECL_SIZE_UNIT (it));
137 : :
138 : 79 : tree addr;
139 : 79 : if (!is_link_var)
140 : 79 : addr = build_fold_addr_expr (it);
141 : : else
142 : : {
143 : : #ifdef ACCEL_COMPILER
144 : : /* For "omp declare target link" vars add address of the pointer to
145 : : the target table, instead of address of the var. */
146 : : tree value_expr = DECL_VALUE_EXPR (it);
147 : : tree link_ptr_decl = TREE_OPERAND (value_expr, 0);
148 : : varpool_node::finalize_decl (link_ptr_decl);
149 : : addr = build_fold_addr_expr (link_ptr_decl);
150 : : #else
151 : 0 : addr = build_fold_addr_expr (it);
152 : : #endif
153 : :
154 : : /* Most significant bit of the size marks "omp declare target link"
155 : : vars in host and target tables. */
156 : 0 : unsigned HOST_WIDE_INT isize = tree_to_uhwi (size);
157 : 0 : isize |= 1ULL << (int_size_in_bytes (const_ptr_type_node)
158 : 0 : * BITS_PER_UNIT - 1);
159 : 0 : size = wide_int_to_tree (const_ptr_type_node, isize);
160 : : }
161 : :
162 : 79 : CONSTRUCTOR_APPEND_ELT (v_ctor, NULL_TREE, addr);
163 : 79 : if (is_var)
164 : 0 : CONSTRUCTOR_APPEND_ELT (v_ctor, NULL_TREE, size);
165 : : }
166 : 90 : }
167 : :
168 : : /* Return true if DECL is a function for which its references should be
169 : : analyzed. */
170 : :
171 : : static bool
172 : 72618 : omp_declare_target_fn_p (tree decl)
173 : : {
174 : 72618 : return (TREE_CODE (decl) == FUNCTION_DECL
175 : 72618 : && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))
176 : 10841 : && !lookup_attribute ("omp declare target host",
177 : 10841 : DECL_ATTRIBUTES (decl))
178 : 83404 : && (!flag_openacc
179 : 57 : || oacc_get_fn_attrib (decl) == NULL_TREE));
180 : : }
181 : :
182 : : /* Return true if DECL Is a variable for which its initializer references
183 : : should be analyzed. */
184 : :
185 : : static bool
186 : 10320 : omp_declare_target_var_p (tree decl)
187 : : {
188 : 10320 : return (VAR_P (decl)
189 : 10320 : && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))
190 : 10764 : && !lookup_attribute ("omp declare target link",
191 : 444 : DECL_ATTRIBUTES (decl)));
192 : : }
193 : :
194 : : /* Helper function for omp_discover_implicit_declare_target, called through
195 : : walk_tree. Mark referenced FUNCTION_DECLs implicitly as
196 : : declare target to. */
197 : :
198 : : static tree
199 : 683876 : omp_discover_declare_target_tgt_fn_r (tree *tp, int *walk_subtrees, void *data)
200 : : {
201 : 683876 : if (TREE_CODE (*tp) == CALL_EXPR
202 : 10538 : && CALL_EXPR_FN (*tp)
203 : 10538 : && TREE_CODE (CALL_EXPR_FN (*tp)) == ADDR_EXPR
204 : 10492 : && TREE_CODE (TREE_OPERAND (CALL_EXPR_FN (*tp), 0)) == FUNCTION_DECL
205 : 694368 : && lookup_attribute ("omp declare variant base",
206 : 10492 : DECL_ATTRIBUTES (TREE_OPERAND (CALL_EXPR_FN (*tp),
207 : : 0))))
208 : : {
209 : 38 : tree fn = TREE_OPERAND (CALL_EXPR_FN (*tp), 0);
210 : 88 : for (tree attr = DECL_ATTRIBUTES (fn); attr; attr = TREE_CHAIN (attr))
211 : : {
212 : 51 : attr = lookup_attribute ("omp declare variant base", attr);
213 : 51 : if (attr == NULL_TREE)
214 : : break;
215 : 50 : tree purpose = TREE_PURPOSE (TREE_VALUE (attr));
216 : 50 : if (TREE_CODE (purpose) == FUNCTION_DECL)
217 : 50 : omp_discover_declare_target_tgt_fn_r (&purpose, walk_subtrees, data);
218 : : }
219 : : }
220 : 683838 : else if (TREE_CODE (*tp) == FUNCTION_DECL)
221 : : {
222 : 7099 : tree decl = *tp;
223 : 7099 : tree id = get_identifier ("omp declare target");
224 : 7099 : symtab_node *node = symtab_node::get (*tp);
225 : 7099 : if (node != NULL)
226 : : {
227 : 3678 : while (node->alias_target
228 : 3678 : && TREE_CODE (node->alias_target) == FUNCTION_DECL)
229 : : {
230 : 4 : if (!omp_declare_target_fn_p (node->decl)
231 : 8 : && !lookup_attribute ("omp declare target host",
232 : 4 : DECL_ATTRIBUTES (node->decl)))
233 : : {
234 : 4 : node->offloadable = 1;
235 : 4 : DECL_ATTRIBUTES (node->decl)
236 : 8 : = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (node->decl));
237 : : }
238 : 4 : node = symtab_node::get (node->alias_target);
239 : : }
240 : 3674 : symtab_node *new_node = node->ultimate_alias_target ();
241 : 3674 : decl = new_node->decl;
242 : 3797 : while (node != new_node)
243 : : {
244 : 123 : if (!omp_declare_target_fn_p (node->decl)
245 : 131 : && !lookup_attribute ("omp declare target host",
246 : 8 : DECL_ATTRIBUTES (node->decl)))
247 : : {
248 : 8 : node->offloadable = 1;
249 : 8 : DECL_ATTRIBUTES (node->decl)
250 : 16 : = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (node->decl));
251 : : }
252 : 123 : gcc_assert (node->alias && node->analyzed);
253 : 123 : node = node->get_alias_target ();
254 : : }
255 : 3674 : node->offloadable = 1;
256 : 3674 : if (ENABLE_OFFLOADING)
257 : : g->have_offload = true;
258 : : }
259 : 7099 : if (omp_declare_target_fn_p (decl)
260 : 8491 : || lookup_attribute ("omp declare target host",
261 : 1392 : DECL_ATTRIBUTES (decl)))
262 : 5707 : return NULL_TREE;
263 : :
264 : 1392 : if (!DECL_EXTERNAL (decl) && DECL_SAVED_TREE (decl))
265 : 283 : ((vec<tree> *) data)->safe_push (decl);
266 : 1392 : DECL_ATTRIBUTES (decl) = tree_cons (id, NULL_TREE,
267 : 1392 : DECL_ATTRIBUTES (decl));
268 : : }
269 : 676739 : else if (TYPE_P (*tp))
270 : 31 : *walk_subtrees = 0;
271 : 676708 : else if (TREE_CODE (*tp) == OMP_TARGET)
272 : : {
273 : 1684 : tree c = omp_find_clause (OMP_CLAUSES (*tp), OMP_CLAUSE_DEVICE);
274 : 1684 : if (c && OMP_CLAUSE_DEVICE_ANCESTOR (c))
275 : 48 : *walk_subtrees = 0;
276 : : }
277 : : return NULL_TREE;
278 : : }
279 : :
280 : : /* Similarly, but ignore references outside of OMP_TARGET regions. */
281 : :
282 : : static tree
283 : 529605 : omp_discover_declare_target_fn_r (tree *tp, int *walk_subtrees, void *data)
284 : : {
285 : 529605 : if (TREE_CODE (*tp) == OMP_TARGET)
286 : : {
287 : 11004 : tree c = omp_find_clause (OMP_CLAUSES (*tp), OMP_CLAUSE_DEVICE);
288 : 11004 : if (!c || !OMP_CLAUSE_DEVICE_ANCESTOR (c))
289 : 10936 : walk_tree_without_duplicates (&OMP_TARGET_BODY (*tp),
290 : : omp_discover_declare_target_tgt_fn_r,
291 : : data);
292 : 11004 : *walk_subtrees = 0;
293 : : }
294 : 518601 : else if (TYPE_P (*tp))
295 : 237 : *walk_subtrees = 0;
296 : 529605 : return NULL_TREE;
297 : : }
298 : :
299 : : /* Helper function for omp_discover_implicit_declare_target, called through
300 : : walk_tree. Mark referenced FUNCTION_DECLs implicitly as
301 : : declare target to. */
302 : :
303 : : static tree
304 : 290 : omp_discover_declare_target_var_r (tree *tp, int *walk_subtrees, void *data)
305 : : {
306 : 290 : if (TREE_CODE (*tp) == FUNCTION_DECL)
307 : 12 : return omp_discover_declare_target_tgt_fn_r (tp, walk_subtrees, data);
308 : 278 : else if (VAR_P (*tp)
309 : 34 : && is_global_var (*tp)
310 : 312 : && !omp_declare_target_var_p (*tp))
311 : : {
312 : 18 : tree id = get_identifier ("omp declare target");
313 : 18 : if (lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (*tp)))
314 : : {
315 : 0 : error_at (DECL_SOURCE_LOCATION (*tp),
316 : : "%qD specified both in declare target %<link%> and "
317 : : "implicitly in %<to%> clauses", *tp);
318 : 0 : DECL_ATTRIBUTES (*tp)
319 : 0 : = remove_attribute ("omp declare target link", DECL_ATTRIBUTES (*tp));
320 : : }
321 : 18 : if (TREE_STATIC (*tp) && lang_hooks.decls.omp_get_decl_init (*tp))
322 : 18 : ((vec<tree> *) data)->safe_push (*tp);
323 : 18 : DECL_ATTRIBUTES (*tp) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (*tp));
324 : 18 : symtab_node *node = symtab_node::get (*tp);
325 : 18 : if (node != NULL && !node->offloadable)
326 : : {
327 : 18 : node->offloadable = 1;
328 : 18 : if (ENABLE_OFFLOADING)
329 : : {
330 : : g->have_offload = true;
331 : : if (is_a <varpool_node *> (node))
332 : : vec_safe_push (offload_vars, node->decl);
333 : : }
334 : : }
335 : : }
336 : 260 : else if (TYPE_P (*tp))
337 : 0 : *walk_subtrees = 0;
338 : : return NULL_TREE;
339 : : }
340 : :
341 : : /* Perform the OpenMP implicit declare target to discovery. */
342 : :
343 : : void
344 : 8352 : omp_discover_implicit_declare_target (void)
345 : : {
346 : 8352 : cgraph_node *node;
347 : 8352 : varpool_node *vnode;
348 : 8352 : auto_vec<tree> worklist;
349 : :
350 : 66133 : FOR_EACH_DEFINED_FUNCTION (node)
351 : 57781 : if (DECL_SAVED_TREE (node->decl))
352 : : {
353 : 54670 : struct cgraph_node *cgn;
354 : 54670 : if (lookup_attribute ("omp declare target indirect",
355 : 54670 : DECL_ATTRIBUTES (node->decl)))
356 : 141 : vec_safe_push (offload_ind_funcs, node->decl);
357 : 54670 : if (omp_declare_target_fn_p (node->decl))
358 : 2307 : worklist.safe_push (node->decl);
359 : 52363 : else if (DECL_STRUCT_FUNCTION (node->decl)
360 : 52363 : && DECL_STRUCT_FUNCTION (node->decl)->has_omp_target)
361 : 5934 : worklist.safe_push (node->decl);
362 : 56527 : for (cgn = first_nested_function (node);
363 : 56527 : cgn; cgn = next_nested_function (cgn))
364 : 1857 : if (omp_declare_target_fn_p (cgn->decl))
365 : 21 : worklist.safe_push (cgn->decl);
366 : 1836 : else if (DECL_STRUCT_FUNCTION (cgn->decl)
367 : 1836 : && DECL_STRUCT_FUNCTION (cgn->decl)->has_omp_target)
368 : 320 : worklist.safe_push (cgn->decl);
369 : : }
370 : 47798 : FOR_EACH_VARIABLE (vnode)
371 : 15547 : if (lang_hooks.decls.omp_get_decl_init (vnode->decl)
372 : 15547 : && omp_declare_target_var_p (vnode->decl))
373 : 428 : worklist.safe_push (vnode->decl);
374 : 17663 : while (!worklist.is_empty ())
375 : : {
376 : 9311 : tree decl = worklist.pop ();
377 : 9311 : if (VAR_P (decl))
378 : 446 : walk_tree_without_duplicates (lang_hooks.decls.omp_get_decl_init (decl),
379 : : omp_discover_declare_target_var_r,
380 : : &worklist);
381 : 8865 : else if (omp_declare_target_fn_p (decl))
382 : 2611 : walk_tree_without_duplicates (&DECL_SAVED_TREE (decl),
383 : : omp_discover_declare_target_tgt_fn_r,
384 : : &worklist);
385 : : else
386 : 6254 : walk_tree_without_duplicates (&DECL_SAVED_TREE (decl),
387 : : omp_discover_declare_target_fn_r,
388 : : &worklist);
389 : : }
390 : :
391 : 8352 : lang_hooks.decls.omp_finish_decl_inits ();
392 : 8352 : }
393 : :
394 : :
395 : : /* Create new symbols containing (address, size) pairs for global variables,
396 : : marked with "omp declare target" attribute, as well as addresses for the
397 : : functions, which are outlined offloading regions. */
398 : : void
399 : 229350 : omp_finish_file (void)
400 : : {
401 : 229350 : unsigned num_funcs = vec_safe_length (offload_funcs);
402 : 229350 : unsigned num_vars = vec_safe_length (offload_vars);
403 : 229350 : unsigned num_ind_funcs = vec_safe_length (offload_ind_funcs);
404 : :
405 : 229350 : if (num_funcs == 0 && num_vars == 0 && num_ind_funcs == 0)
406 : 229350 : return;
407 : :
408 : 30 : if (targetm_common.have_named_sections)
409 : : {
410 : 30 : vec<constructor_elt, va_gc> *v_f, *v_v, *v_if;
411 : 30 : vec_alloc (v_f, num_funcs);
412 : 30 : vec_alloc (v_v, num_vars * 2);
413 : 30 : vec_alloc (v_if, num_ind_funcs);
414 : :
415 : 30 : add_decls_addresses_to_decl_constructor (offload_funcs, v_f);
416 : 30 : add_decls_addresses_to_decl_constructor (offload_vars, v_v);
417 : 30 : add_decls_addresses_to_decl_constructor (offload_ind_funcs, v_if);
418 : :
419 : 30 : tree vars_decl_type = build_array_type_nelts (pointer_sized_int_node,
420 : 30 : vec_safe_length (v_v));
421 : 30 : tree funcs_decl_type = build_array_type_nelts (pointer_sized_int_node,
422 : : num_funcs);
423 : 30 : tree ind_funcs_decl_type = build_array_type_nelts (pointer_sized_int_node,
424 : : num_ind_funcs);
425 : :
426 : 30 : SET_TYPE_ALIGN (vars_decl_type, TYPE_ALIGN (pointer_sized_int_node));
427 : 30 : SET_TYPE_ALIGN (funcs_decl_type, TYPE_ALIGN (pointer_sized_int_node));
428 : 30 : SET_TYPE_ALIGN (ind_funcs_decl_type, TYPE_ALIGN (pointer_sized_int_node));
429 : 30 : tree ctor_v = build_constructor (vars_decl_type, v_v);
430 : 30 : tree ctor_f = build_constructor (funcs_decl_type, v_f);
431 : 30 : tree ctor_if = build_constructor (ind_funcs_decl_type, v_if);
432 : 30 : TREE_CONSTANT (ctor_v) = TREE_CONSTANT (ctor_f) = TREE_CONSTANT (ctor_if) = 1;
433 : 30 : TREE_STATIC (ctor_v) = TREE_STATIC (ctor_f) = TREE_STATIC (ctor_if) = 1;
434 : 30 : tree funcs_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
435 : : get_identifier (".offload_func_table"),
436 : : funcs_decl_type);
437 : 30 : tree vars_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
438 : : get_identifier (".offload_var_table"),
439 : : vars_decl_type);
440 : 30 : tree ind_funcs_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
441 : : get_identifier (".offload_ind_func_table"),
442 : : ind_funcs_decl_type);
443 : 30 : TREE_STATIC (funcs_decl) = TREE_STATIC (ind_funcs_decl) = 1;
444 : 30 : TREE_STATIC (vars_decl) = 1;
445 : : /* Do not align tables more than TYPE_ALIGN (pointer_sized_int_node),
446 : : otherwise a joint table in a binary will contain padding between
447 : : tables from multiple object files. */
448 : 30 : DECL_USER_ALIGN (funcs_decl) = DECL_USER_ALIGN (ind_funcs_decl) = 1;
449 : 30 : DECL_USER_ALIGN (vars_decl) = 1;
450 : 30 : SET_DECL_ALIGN (funcs_decl, TYPE_ALIGN (funcs_decl_type));
451 : 30 : SET_DECL_ALIGN (vars_decl, TYPE_ALIGN (vars_decl_type));
452 : 30 : SET_DECL_ALIGN (ind_funcs_decl, TYPE_ALIGN (ind_funcs_decl_type));
453 : 30 : DECL_INITIAL (funcs_decl) = ctor_f;
454 : 30 : DECL_INITIAL (vars_decl) = ctor_v;
455 : 30 : DECL_INITIAL (ind_funcs_decl) = ctor_if;
456 : 30 : set_decl_section_name (funcs_decl, OFFLOAD_FUNC_TABLE_SECTION_NAME);
457 : 30 : set_decl_section_name (vars_decl, OFFLOAD_VAR_TABLE_SECTION_NAME);
458 : 30 : set_decl_section_name (ind_funcs_decl,
459 : : OFFLOAD_IND_FUNC_TABLE_SECTION_NAME);
460 : 30 : varpool_node::finalize_decl (vars_decl);
461 : 30 : varpool_node::finalize_decl (funcs_decl);
462 : 30 : varpool_node::finalize_decl (ind_funcs_decl);
463 : : }
464 : : else
465 : : {
466 : 0 : for (unsigned i = 0; i < num_funcs; i++)
467 : : {
468 : 0 : tree it = (*offload_funcs)[i];
469 : : /* See also add_decls_addresses_to_decl_constructor
470 : : and output_offload_tables in lto-cgraph.cc. */
471 : 0 : if (!in_lto_p && !symtab_node::get (it))
472 : 0 : continue;
473 : 0 : targetm.record_offload_symbol (it);
474 : : }
475 : 0 : for (unsigned i = 0; i < num_vars; i++)
476 : : {
477 : 0 : tree it = (*offload_vars)[i];
478 : 0 : if (!in_lto_p && !symtab_node::get (it))
479 : 0 : continue;
480 : : #ifdef ACCEL_COMPILER
481 : : if (DECL_HAS_VALUE_EXPR_P (it)
482 : : && lookup_attribute ("omp declare target link",
483 : : DECL_ATTRIBUTES (it)))
484 : : {
485 : : tree value_expr = DECL_VALUE_EXPR (it);
486 : : tree link_ptr_decl = TREE_OPERAND (value_expr, 0);
487 : : targetm.record_offload_symbol (link_ptr_decl);
488 : : varpool_node::finalize_decl (link_ptr_decl);
489 : : }
490 : : else
491 : : #endif
492 : 0 : targetm.record_offload_symbol (it);
493 : : }
494 : 0 : for (unsigned i = 0; i < num_ind_funcs; i++)
495 : : {
496 : 0 : tree it = (*offload_ind_funcs)[i];
497 : : /* See also add_decls_addresses_to_decl_constructor
498 : : and output_offload_tables in lto-cgraph.cc. */
499 : 0 : if (!in_lto_p && !symtab_node::get (it))
500 : 0 : continue;
501 : 0 : targetm.record_offload_symbol (it);
502 : : }
503 : : }
504 : : }
505 : :
506 : : /* Call dim_pos (POS == true) or dim_size (POS == false) builtins for
507 : : axis DIM. Return a tmp var holding the result. */
508 : :
509 : : static tree
510 : 28271 : oacc_dim_call (bool pos, int dim, gimple_seq *seq)
511 : : {
512 : 28271 : tree arg = build_int_cst (unsigned_type_node, dim);
513 : 28271 : tree size = create_tmp_var (integer_type_node);
514 : 28271 : enum internal_fn fn = pos ? IFN_GOACC_DIM_POS : IFN_GOACC_DIM_SIZE;
515 : 28271 : gimple *call = gimple_build_call_internal (fn, 1, arg);
516 : :
517 : 28271 : gimple_call_set_lhs (call, size);
518 : 28271 : gimple_seq_add_stmt (seq, call);
519 : :
520 : 28271 : return size;
521 : : }
522 : :
523 : : /* Find the number of threads (POS = false), or thread number (POS =
524 : : true) for an OpenACC region partitioned as MASK. Setup code
525 : : required for the calculation is added to SEQ. */
526 : :
527 : : static tree
528 : 21881 : oacc_thread_numbers (bool pos, int mask, gimple_seq *seq)
529 : : {
530 : 21881 : tree res = pos ? NULL_TREE : build_int_cst (unsigned_type_node, 1);
531 : 21881 : unsigned ix;
532 : :
533 : : /* Start at gang level, and examine relevant dimension indices. */
534 : 87524 : for (ix = GOMP_DIM_GANG; ix != GOMP_DIM_MAX; ix++)
535 : 65643 : if (GOMP_DIM_MASK (ix) & mask)
536 : : {
537 : 24375 : if (res)
538 : : {
539 : : /* We had an outer index, so scale that by the size of
540 : : this dimension. */
541 : 16027 : tree n = oacc_dim_call (false, ix, seq);
542 : 16027 : res = fold_build2 (MULT_EXPR, integer_type_node, res, n);
543 : : }
544 : 24375 : if (pos)
545 : : {
546 : : /* Determine index in this dimension. */
547 : 12244 : tree id = oacc_dim_call (true, ix, seq);
548 : 12244 : if (res)
549 : 3896 : res = fold_build2 (PLUS_EXPR, integer_type_node, res, id);
550 : : else
551 : : res = id;
552 : : }
553 : : }
554 : :
555 : 21881 : if (res == NULL_TREE)
556 : 2645 : res = integer_zero_node;
557 : :
558 : 21881 : return res;
559 : : }
560 : :
561 : : /* Transform IFN_GOACC_LOOP calls to actual code. See
562 : : expand_oacc_for for where these are generated. At the vector
563 : : level, we stride loops, such that each member of a warp will
564 : : operate on adjacent iterations. At the worker and gang level,
565 : : each gang/warp executes a set of contiguous iterations. Chunking
566 : : can override this such that each iteration engine executes a
567 : : contiguous chunk, and then moves on to stride to the next chunk. */
568 : :
569 : : static void
570 : 43199 : oacc_xform_loop (gcall *call)
571 : : {
572 : 43199 : gimple_stmt_iterator gsi = gsi_for_stmt (call);
573 : 43199 : enum ifn_goacc_loop_kind code
574 : 43199 : = (enum ifn_goacc_loop_kind) TREE_INT_CST_LOW (gimple_call_arg (call, 0));
575 : 43199 : tree dir = gimple_call_arg (call, 1);
576 : 43199 : tree range = gimple_call_arg (call, 2);
577 : 43199 : tree step = gimple_call_arg (call, 3);
578 : 43199 : tree chunk_size = NULL_TREE;
579 : 43199 : unsigned mask = (unsigned) TREE_INT_CST_LOW (gimple_call_arg (call, 5));
580 : 43199 : tree lhs = gimple_call_lhs (call);
581 : 43199 : tree type = NULL_TREE;
582 : 43199 : tree diff_type = TREE_TYPE (range);
583 : 43199 : tree r = NULL_TREE;
584 : 43199 : gimple_seq seq = NULL;
585 : 43199 : bool chunking = false, striding = true;
586 : 43199 : unsigned outer_mask = mask & (~mask + 1); // Outermost partitioning
587 : 43199 : unsigned inner_mask = mask & ~outer_mask; // Inner partitioning (if any)
588 : :
589 : : /* Skip lowering if return value of IFN_GOACC_LOOP call is not used. */
590 : 43199 : if (!lhs)
591 : : {
592 : 10 : gsi_replace_with_seq (&gsi, seq, true);
593 : 10 : return;
594 : : }
595 : :
596 : 43189 : type = TREE_TYPE (lhs);
597 : :
598 : : #ifdef ACCEL_COMPILER
599 : : chunk_size = gimple_call_arg (call, 4);
600 : : if (integer_minus_onep (chunk_size) /* Force static allocation. */
601 : : || integer_zerop (chunk_size)) /* Default (also static). */
602 : : {
603 : : /* If we're at the gang level, we want each to execute a
604 : : contiguous run of iterations. Otherwise we want each element
605 : : to stride. */
606 : : striding = !(outer_mask & GOMP_DIM_MASK (GOMP_DIM_GANG));
607 : : chunking = false;
608 : : }
609 : : else
610 : : {
611 : : /* Chunk of size 1 is striding. */
612 : : striding = integer_onep (chunk_size);
613 : : chunking = !striding;
614 : : }
615 : : #endif
616 : :
617 : : /* striding=true, chunking=true
618 : : -> invalid.
619 : : striding=true, chunking=false
620 : : -> chunks=1
621 : : striding=false,chunking=true
622 : : -> chunks=ceil (range/(chunksize*threads*step))
623 : : striding=false,chunking=false
624 : : -> chunk_size=ceil(range/(threads*step)),chunks=1 */
625 : 43189 : push_gimplify_context (true);
626 : :
627 : 43189 : switch (code)
628 : : {
629 : 0 : default: gcc_unreachable ();
630 : :
631 : 10320 : case IFN_GOACC_LOOP_CHUNKS:
632 : 10320 : if (!chunking)
633 : 10320 : r = build_int_cst (type, 1);
634 : : else
635 : : {
636 : : /* chunk_max
637 : : = (range - dir) / (chunks * step * num_threads) + dir */
638 : : tree per = oacc_thread_numbers (false, mask, &seq);
639 : : per = fold_convert (type, per);
640 : : chunk_size = fold_convert (type, chunk_size);
641 : : per = fold_build2 (MULT_EXPR, type, per, chunk_size);
642 : : per = fold_build2 (MULT_EXPR, type, per, step);
643 : : r = build2 (MINUS_EXPR, type, range, dir);
644 : : r = build2 (PLUS_EXPR, type, r, per);
645 : : r = build2 (TRUNC_DIV_EXPR, type, r, per);
646 : : }
647 : : break;
648 : :
649 : 10888 : case IFN_GOACC_LOOP_STEP:
650 : 10888 : {
651 : : /* If striding, step by the entire compute volume, otherwise
652 : : step by the inner volume. */
653 : 10888 : unsigned volume = striding ? mask : inner_mask;
654 : :
655 : 10888 : r = oacc_thread_numbers (false, volume, &seq);
656 : 10888 : r = build2 (MULT_EXPR, type, fold_convert (type, r), step);
657 : : }
658 : 10888 : break;
659 : :
660 : 10993 : case IFN_GOACC_LOOP_OFFSET:
661 : : /* Enable vectorization on non-SIMT targets. */
662 : 10993 : if (!targetm.simt.vf
663 : 10993 : && outer_mask == GOMP_DIM_MASK (GOMP_DIM_VECTOR)
664 : : /* If not -fno-tree-loop-vectorize, hint that we want to vectorize
665 : : the loop. */
666 : 1693 : && (flag_tree_loop_vectorize
667 : 1205 : || !OPTION_SET_P (flag_tree_loop_vectorize)))
668 : : {
669 : 1693 : basic_block bb = gsi_bb (gsi);
670 : 1693 : class loop *parent = bb->loop_father;
671 : 1693 : class loop *body = parent->inner;
672 : :
673 : 1693 : parent->force_vectorize = true;
674 : 1693 : parent->safelen = INT_MAX;
675 : :
676 : : /* "Chunking loops" may have inner loops. */
677 : 1693 : if (parent->inner)
678 : : {
679 : 1681 : body->force_vectorize = true;
680 : 1681 : body->safelen = INT_MAX;
681 : : }
682 : :
683 : 1693 : cfun->has_force_vectorize_loops = true;
684 : : }
685 : 10993 : if (striding)
686 : : {
687 : 10993 : r = oacc_thread_numbers (true, mask, &seq);
688 : 10993 : r = fold_convert (diff_type, r);
689 : : }
690 : : else
691 : : {
692 : : tree inner_size = oacc_thread_numbers (false, inner_mask, &seq);
693 : : tree outer_size = oacc_thread_numbers (false, outer_mask, &seq);
694 : : tree volume = fold_build2 (MULT_EXPR, TREE_TYPE (inner_size),
695 : : inner_size, outer_size);
696 : :
697 : : volume = fold_convert (diff_type, volume);
698 : : if (chunking)
699 : : chunk_size = fold_convert (diff_type, chunk_size);
700 : : else
701 : : {
702 : : tree per = fold_build2 (MULT_EXPR, diff_type, volume, step);
703 : :
704 : : chunk_size = build2 (MINUS_EXPR, diff_type, range, dir);
705 : : chunk_size = build2 (PLUS_EXPR, diff_type, chunk_size, per);
706 : : chunk_size = build2 (TRUNC_DIV_EXPR, diff_type, chunk_size, per);
707 : : }
708 : :
709 : : tree span = build2 (MULT_EXPR, diff_type, chunk_size,
710 : : fold_convert (diff_type, inner_size));
711 : : r = oacc_thread_numbers (true, outer_mask, &seq);
712 : : r = fold_convert (diff_type, r);
713 : : r = build2 (MULT_EXPR, diff_type, r, span);
714 : :
715 : : tree inner = oacc_thread_numbers (true, inner_mask, &seq);
716 : : inner = fold_convert (diff_type, inner);
717 : : r = fold_build2 (PLUS_EXPR, diff_type, r, inner);
718 : :
719 : : if (chunking)
720 : : {
721 : : tree chunk = fold_convert (diff_type, gimple_call_arg (call, 6));
722 : : tree per
723 : : = fold_build2 (MULT_EXPR, diff_type, volume, chunk_size);
724 : : per = build2 (MULT_EXPR, diff_type, per, chunk);
725 : :
726 : : r = build2 (PLUS_EXPR, diff_type, r, per);
727 : : }
728 : : }
729 : 10993 : r = fold_build2 (MULT_EXPR, diff_type, r, step);
730 : 10993 : if (type != diff_type)
731 : 209 : r = fold_convert (type, r);
732 : : break;
733 : :
734 : 10988 : case IFN_GOACC_LOOP_BOUND:
735 : 10988 : if (striding)
736 : 10988 : r = range;
737 : : else
738 : : {
739 : : tree inner_size = oacc_thread_numbers (false, inner_mask, &seq);
740 : : tree outer_size = oacc_thread_numbers (false, outer_mask, &seq);
741 : : tree volume = fold_build2 (MULT_EXPR, TREE_TYPE (inner_size),
742 : : inner_size, outer_size);
743 : :
744 : : volume = fold_convert (diff_type, volume);
745 : : if (chunking)
746 : : chunk_size = fold_convert (diff_type, chunk_size);
747 : : else
748 : : {
749 : : tree per = fold_build2 (MULT_EXPR, diff_type, volume, step);
750 : :
751 : : chunk_size = build2 (MINUS_EXPR, diff_type, range, dir);
752 : : chunk_size = build2 (PLUS_EXPR, diff_type, chunk_size, per);
753 : : chunk_size = build2 (TRUNC_DIV_EXPR, diff_type, chunk_size, per);
754 : : }
755 : :
756 : : tree span = build2 (MULT_EXPR, diff_type, chunk_size,
757 : : fold_convert (diff_type, inner_size));
758 : :
759 : : r = fold_build2 (MULT_EXPR, diff_type, span, step);
760 : :
761 : : tree offset = gimple_call_arg (call, 6);
762 : : r = build2 (PLUS_EXPR, diff_type, r,
763 : : fold_convert (diff_type, offset));
764 : : r = build2 (integer_onep (dir) ? MIN_EXPR : MAX_EXPR,
765 : : diff_type, r, range);
766 : : }
767 : 10988 : if (diff_type != type)
768 : 209 : r = fold_convert (type, r);
769 : : break;
770 : : }
771 : :
772 : 43189 : gimplify_assign (lhs, r, &seq);
773 : :
774 : 43189 : pop_gimplify_context (NULL);
775 : :
776 : 43189 : gsi_replace_with_seq (&gsi, seq, true);
777 : : }
778 : :
779 : : /* Transform a GOACC_TILE call. Determines the element loop span for
780 : : the specified loop of the nest. This is 1 if we're not tiling.
781 : :
782 : : GOACC_TILE (collapse_count, loop_no, tile_arg, gwv_tile, gwv_element); */
783 : :
784 : : static void
785 : 293 : oacc_xform_tile (gcall *call)
786 : : {
787 : 293 : gimple_stmt_iterator gsi = gsi_for_stmt (call);
788 : 293 : unsigned collapse = tree_to_uhwi (gimple_call_arg (call, 0));
789 : : /* Inner loops have higher loop_nos. */
790 : 293 : unsigned loop_no = tree_to_uhwi (gimple_call_arg (call, 1));
791 : 293 : tree tile_size = gimple_call_arg (call, 2);
792 : 293 : unsigned e_mask = tree_to_uhwi (gimple_call_arg (call, 4));
793 : 293 : tree lhs = gimple_call_lhs (call);
794 : 293 : tree type = TREE_TYPE (lhs);
795 : 293 : gimple_seq seq = NULL;
796 : 293 : tree span = build_int_cst (type, 1);
797 : :
798 : 293 : gcc_assert (!(e_mask
799 : : & ~(GOMP_DIM_MASK (GOMP_DIM_VECTOR)
800 : : | GOMP_DIM_MASK (GOMP_DIM_WORKER))));
801 : 293 : push_gimplify_context (!seen_error ());
802 : :
803 : : #ifndef ACCEL_COMPILER
804 : : /* Partitioning disabled on host compilers. */
805 : 293 : e_mask = 0;
806 : : #endif
807 : 293 : if (!e_mask)
808 : : /* Not paritioning. */
809 : 293 : span = integer_one_node;
810 : : else if (!integer_zerop (tile_size))
811 : : /* User explicitly specified size. */
812 : : span = tile_size;
813 : : else
814 : : {
815 : : /* Pick a size based on the paritioning of the element loop and
816 : : the number of loop nests. */
817 : : tree first_size = NULL_TREE;
818 : : tree second_size = NULL_TREE;
819 : :
820 : : if (e_mask & GOMP_DIM_MASK (GOMP_DIM_VECTOR))
821 : : first_size = oacc_dim_call (false, GOMP_DIM_VECTOR, &seq);
822 : : if (e_mask & GOMP_DIM_MASK (GOMP_DIM_WORKER))
823 : : second_size = oacc_dim_call (false, GOMP_DIM_WORKER, &seq);
824 : :
825 : : if (!first_size)
826 : : {
827 : : first_size = second_size;
828 : : second_size = NULL_TREE;
829 : : }
830 : :
831 : : if (loop_no + 1 == collapse)
832 : : {
833 : : span = first_size;
834 : : if (!loop_no && second_size)
835 : : span = fold_build2 (MULT_EXPR, TREE_TYPE (span),
836 : : span, second_size);
837 : : }
838 : : else if (loop_no + 2 == collapse)
839 : : span = second_size;
840 : : else
841 : : span = NULL_TREE;
842 : :
843 : : if (!span)
844 : : /* There's no obvious element size for this loop. Options
845 : : are 1, first_size or some non-unity constant (32 is my
846 : : favourite). We should gather some statistics. */
847 : : span = first_size;
848 : : }
849 : :
850 : 293 : span = fold_convert (type, span);
851 : 293 : gimplify_assign (lhs, span, &seq);
852 : :
853 : 293 : pop_gimplify_context (NULL);
854 : :
855 : 293 : gsi_replace_with_seq (&gsi, seq, true);
856 : 293 : }
857 : :
858 : : /* Default partitioned and minimum partitioned dimensions. */
859 : :
860 : : static int oacc_default_dims[GOMP_DIM_MAX];
861 : : static int oacc_min_dims[GOMP_DIM_MAX];
862 : :
863 : : int
864 : 0 : oacc_get_default_dim (int dim)
865 : : {
866 : 0 : gcc_assert (0 <= dim && dim < GOMP_DIM_MAX);
867 : 0 : return oacc_default_dims[dim];
868 : : }
869 : :
870 : : int
871 : 0 : oacc_get_min_dim (int dim)
872 : : {
873 : 0 : gcc_assert (0 <= dim && dim < GOMP_DIM_MAX);
874 : 0 : return oacc_min_dims[dim];
875 : : }
876 : :
877 : : /* Parse the default dimension parameter. This is a set of
878 : : :-separated optional compute dimensions. Each specified dimension
879 : : is a positive integer. When device type support is added, it is
880 : : planned to be a comma separated list of such compute dimensions,
881 : : with all but the first prefixed by the colon-terminated device
882 : : type. */
883 : :
884 : : static void
885 : 2365 : oacc_parse_default_dims (const char *dims)
886 : : {
887 : 2365 : int ix;
888 : :
889 : 9460 : for (ix = GOMP_DIM_MAX; ix--;)
890 : : {
891 : 7095 : oacc_default_dims[ix] = -1;
892 : 7095 : oacc_min_dims[ix] = 1;
893 : : }
894 : :
895 : : #ifndef ACCEL_COMPILER
896 : : /* Cannot be overridden on the host. */
897 : 2365 : dims = NULL;
898 : : #endif
899 : 2365 : if (dims)
900 : : {
901 : : const char *pos = dims;
902 : :
903 : : for (ix = 0; *pos && ix != GOMP_DIM_MAX; ix++)
904 : : {
905 : : if (ix)
906 : : {
907 : : if (*pos != ':')
908 : : goto malformed;
909 : : pos++;
910 : : }
911 : :
912 : : if (*pos != ':')
913 : : {
914 : : long val;
915 : : const char *eptr;
916 : :
917 : : errno = 0;
918 : : val = strtol (pos, CONST_CAST (char **, &eptr), 10);
919 : : if (errno || val <= 0 || (int) val != val)
920 : : goto malformed;
921 : : pos = eptr;
922 : : oacc_default_dims[ix] = (int) val;
923 : : }
924 : : }
925 : : if (*pos)
926 : : {
927 : : malformed:
928 : : error_at (UNKNOWN_LOCATION,
929 : : "%<-fopenacc-dim%> operand is malformed at %qs", pos);
930 : : }
931 : : }
932 : :
933 : : /* Allow the backend to validate the dimensions. */
934 : 2365 : targetm.goacc.validate_dims (NULL_TREE, oacc_default_dims, -1, 0);
935 : 2365 : targetm.goacc.validate_dims (NULL_TREE, oacc_min_dims, -2, 0);
936 : 2365 : }
937 : :
938 : : /* Validate and update the dimensions for offloaded FN. ATTRS is the
939 : : raw attribute. DIMS is an array of dimensions, which is filled in.
940 : : LEVEL is the partitioning level of a routine, or -1 for an offload
941 : : region itself. USED is the mask of partitioned execution in the
942 : : function. */
943 : :
944 : : static void
945 : 9453 : oacc_validate_dims (tree fn, tree attrs, int *dims, int level, unsigned used)
946 : : {
947 : 9453 : tree purpose[GOMP_DIM_MAX];
948 : 9453 : unsigned ix;
949 : 9453 : tree pos = TREE_VALUE (attrs);
950 : :
951 : : /* Make sure the attribute creator attached the dimension
952 : : information. */
953 : 9453 : gcc_assert (pos);
954 : :
955 : 37812 : for (ix = 0; ix != GOMP_DIM_MAX; ix++)
956 : : {
957 : 28359 : purpose[ix] = TREE_PURPOSE (pos);
958 : 28359 : tree val = TREE_VALUE (pos);
959 : 28359 : dims[ix] = val ? TREE_INT_CST_LOW (val) : -1;
960 : 28359 : pos = TREE_CHAIN (pos);
961 : : }
962 : :
963 : 9453 : bool check = true;
964 : : #ifdef ACCEL_COMPILER
965 : : check = false;
966 : : #endif
967 : 9453 : if (check
968 : 9453 : && warn_openacc_parallelism
969 : 1463 : && !lookup_attribute ("oacc kernels", DECL_ATTRIBUTES (fn)))
970 : : {
971 : 1331 : static char const *const axes[] =
972 : : /* Must be kept in sync with GOMP_DIM enumeration. */
973 : : { "gang", "worker", "vector" };
974 : 5014 : for (ix = level >= 0 ? level : 0; ix != GOMP_DIM_MAX; ix++)
975 : 3683 : if (dims[ix] < 0)
976 : : ; /* Defaulting axis. */
977 : 2021 : else if ((used & GOMP_DIM_MASK (ix)) && dims[ix] == 1)
978 : : /* There is partitioned execution, but the user requested a
979 : : dimension size of 1. They're probably confused. */
980 : 80 : warning_at (DECL_SOURCE_LOCATION (fn), OPT_Wopenacc_parallelism,
981 : : "region contains %s partitioned code but"
982 : 80 : " is not %s partitioned", axes[ix], axes[ix]);
983 : 1941 : else if (!(used & GOMP_DIM_MASK (ix)) && dims[ix] != 1)
984 : : /* The dimension is explicitly partitioned to non-unity, but
985 : : no use is made within the region. */
986 : 531 : warning_at (DECL_SOURCE_LOCATION (fn), OPT_Wopenacc_parallelism,
987 : : "region is %s partitioned but"
988 : : " does not contain %s partitioned code",
989 : 531 : axes[ix], axes[ix]);
990 : : }
991 : :
992 : 9453 : bool changed = targetm.goacc.validate_dims (fn, dims, level, used);
993 : :
994 : : /* Default anything left to 1 or a partitioned default. */
995 : 47265 : for (ix = 0; ix != GOMP_DIM_MAX; ix++)
996 : 28359 : if (dims[ix] < 0)
997 : : {
998 : : /* The OpenACC spec says 'If the [num_gangs] clause is not
999 : : specified, an implementation-defined default will be used;
1000 : : the default may depend on the code within the construct.'
1001 : : (2.5.6). Thus an implementation is free to choose
1002 : : non-unity default for a parallel region that doesn't have
1003 : : any gang-partitioned loops. However, it appears that there
1004 : : is a sufficient body of user code that expects non-gang
1005 : : partitioned regions to not execute in gang-redundant mode.
1006 : : So we (a) don't warn about the non-portability and (b) pick
1007 : : the minimum permissible dimension size when there is no
1008 : : partitioned execution. Otherwise we pick the global
1009 : : default for the dimension, which the user can control. The
1010 : : same wording and logic applies to num_workers and
1011 : : vector_length, however the worker- or vector- single
1012 : : execution doesn't have the same impact as gang-redundant
1013 : : execution. (If the minimum gang-level partioning is not 1,
1014 : : the target is probably too confusing.) */
1015 : 0 : dims[ix] = (used & GOMP_DIM_MASK (ix)
1016 : 0 : ? oacc_default_dims[ix] : oacc_min_dims[ix]);
1017 : 0 : changed = true;
1018 : : }
1019 : :
1020 : 9453 : if (changed)
1021 : : {
1022 : : /* Replace the attribute with new values. */
1023 : : pos = NULL_TREE;
1024 : 36368 : for (ix = GOMP_DIM_MAX; ix--;)
1025 : 27276 : pos = tree_cons (purpose[ix],
1026 : 27276 : build_int_cst (integer_type_node, dims[ix]), pos);
1027 : 9092 : oacc_replace_fn_attrib (fn, pos);
1028 : : }
1029 : 9453 : }
1030 : :
1031 : : /* Create an empty OpenACC loop structure at LOC. */
1032 : :
1033 : : static oacc_loop *
1034 : 19727 : new_oacc_loop_raw (oacc_loop *parent, location_t loc)
1035 : : {
1036 : 9580 : oacc_loop *loop = XCNEW (oacc_loop);
1037 : :
1038 : 19727 : loop->parent = parent;
1039 : :
1040 : 9580 : if (parent)
1041 : : {
1042 : 9580 : loop->sibling = parent->child;
1043 : 9580 : parent->child = loop;
1044 : : }
1045 : :
1046 : 19727 : loop->loc = loc;
1047 : 19727 : return loop;
1048 : : }
1049 : :
1050 : : /* Create an outermost, dummy OpenACC loop for offloaded function
1051 : : DECL. */
1052 : :
1053 : : static oacc_loop *
1054 : 9453 : new_oacc_loop_outer (tree decl)
1055 : : {
1056 : 9453 : return new_oacc_loop_raw (NULL, DECL_SOURCE_LOCATION (decl));
1057 : : }
1058 : :
1059 : : /* Start a new OpenACC loop structure beginning at head marker HEAD.
1060 : : Link into PARENT loop. Return the new loop. */
1061 : :
1062 : : static oacc_loop *
1063 : 8519 : new_oacc_loop (oacc_loop *parent, gcall *marker)
1064 : : {
1065 : 8519 : oacc_loop *loop = new_oacc_loop_raw (parent, gimple_location (marker));
1066 : :
1067 : 8519 : loop->marker = marker;
1068 : :
1069 : : /* TODO: This is where device_type flattening would occur for the loop
1070 : : flags. */
1071 : :
1072 : 8519 : loop->flags = TREE_INT_CST_LOW (gimple_call_arg (marker, 3));
1073 : :
1074 : 8519 : tree chunk_size = integer_zero_node;
1075 : 8519 : if (loop->flags & OLF_GANG_STATIC)
1076 : 131 : chunk_size = gimple_call_arg (marker, 4);
1077 : 8519 : loop->chunk_size = chunk_size;
1078 : :
1079 : 8519 : return loop;
1080 : : }
1081 : :
1082 : : /* Create a dummy loop encompassing a call to a openACC routine.
1083 : : Extract the routine's partitioning requirements. */
1084 : :
1085 : : static void
1086 : 1061 : new_oacc_loop_routine (oacc_loop *parent, gcall *call, tree decl, tree attrs)
1087 : : {
1088 : 1061 : oacc_loop *loop = new_oacc_loop_raw (parent, gimple_location (call));
1089 : 1061 : int level = oacc_fn_attrib_level (attrs);
1090 : :
1091 : 1061 : gcc_assert (level >= 0);
1092 : :
1093 : 1061 : loop->marker = call;
1094 : 1061 : loop->routine = decl;
1095 : 1061 : loop->mask = ((GOMP_DIM_MASK (GOMP_DIM_MAX) - 1)
1096 : 1061 : ^ (GOMP_DIM_MASK (level) - 1));
1097 : 1061 : }
1098 : :
1099 : : /* Finish off the current OpenACC loop ending at tail marker TAIL.
1100 : : Return the parent loop. */
1101 : :
1102 : : static oacc_loop *
1103 : 8519 : finish_oacc_loop (oacc_loop *loop)
1104 : : {
1105 : : /* If the loop has been collapsed, don't partition it. */
1106 : 0 : if (loop->ifns.is_empty ())
1107 : 0 : loop->mask = loop->flags = 0;
1108 : 8519 : return loop->parent;
1109 : : }
1110 : :
1111 : : /* Free all OpenACC loop structures within LOOP (inclusive). */
1112 : :
1113 : : static void
1114 : 19727 : free_oacc_loop (oacc_loop *loop)
1115 : : {
1116 : 19727 : if (loop->sibling)
1117 : 1839 : free_oacc_loop (loop->sibling);
1118 : 19727 : if (loop->child)
1119 : 7741 : free_oacc_loop (loop->child);
1120 : :
1121 : 19727 : loop->ifns.release ();
1122 : 19727 : free (loop);
1123 : 19727 : }
1124 : :
1125 : : /* Dump out the OpenACC loop head or tail beginning at FROM. */
1126 : :
1127 : : static void
1128 : 202 : dump_oacc_loop_part (FILE *file, gcall *from, int depth,
1129 : : const char *title, int level)
1130 : : {
1131 : 202 : enum ifn_unique_kind kind
1132 : 202 : = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (from, 0));
1133 : :
1134 : 202 : fprintf (file, "%*s%s-%d:\n", depth * 2, "", title, level);
1135 : 202 : for (gimple_stmt_iterator gsi = gsi_for_stmt (from);;)
1136 : : {
1137 : 611 : gimple *stmt = gsi_stmt (gsi);
1138 : :
1139 : 611 : if (gimple_call_internal_p (stmt, IFN_UNIQUE))
1140 : : {
1141 : 611 : enum ifn_unique_kind k
1142 : 611 : = ((enum ifn_unique_kind) TREE_INT_CST_LOW
1143 : 611 : (gimple_call_arg (stmt, 0)));
1144 : :
1145 : 611 : if (k == kind && stmt != from)
1146 : : break;
1147 : : }
1148 : 409 : print_gimple_stmt (file, stmt, depth * 2 + 2);
1149 : :
1150 : 409 : gsi_next (&gsi);
1151 : 818 : while (gsi_end_p (gsi))
1152 : 818 : gsi = gsi_start_bb (single_succ (gsi_bb (gsi)));
1153 : : }
1154 : 202 : }
1155 : :
1156 : : /* Dump OpenACC loop LOOP, its children, and its siblings. */
1157 : :
1158 : : static void
1159 : 176 : dump_oacc_loop (FILE *file, oacc_loop *loop, int depth)
1160 : : {
1161 : 208 : int ix;
1162 : :
1163 : 208 : fprintf (file, "%*sLoop %x(%x) %s:%u\n", depth * 2, "",
1164 : : loop->flags, loop->mask,
1165 : 208 : LOCATION_FILE (loop->loc), LOCATION_LINE (loop->loc));
1166 : :
1167 : 208 : if (loop->marker)
1168 : 95 : print_gimple_stmt (file, loop->marker, depth * 2);
1169 : :
1170 : 208 : if (loop->routine)
1171 : 44 : fprintf (file, "%*sRoutine %s:%u:%s\n",
1172 : 44 : depth * 2, "", DECL_SOURCE_FILE (loop->routine),
1173 : 88 : DECL_SOURCE_LINE (loop->routine),
1174 : 44 : IDENTIFIER_POINTER (DECL_NAME (loop->routine)));
1175 : :
1176 : 832 : for (ix = GOMP_DIM_GANG; ix != GOMP_DIM_MAX; ix++)
1177 : 624 : if (loop->heads[ix])
1178 : 101 : dump_oacc_loop_part (file, loop->heads[ix], depth, "Head", ix);
1179 : 832 : for (ix = GOMP_DIM_MAX; ix--;)
1180 : 624 : if (loop->tails[ix])
1181 : 101 : dump_oacc_loop_part (file, loop->tails[ix], depth, "Tail", ix);
1182 : :
1183 : 208 : if (loop->child)
1184 : 63 : dump_oacc_loop (file, loop->child, depth + 1);
1185 : 208 : if (loop->sibling)
1186 : : dump_oacc_loop (file, loop->sibling, depth);
1187 : 176 : }
1188 : :
1189 : : void debug_oacc_loop (oacc_loop *);
1190 : :
1191 : : /* Dump loops to stderr. */
1192 : :
1193 : : DEBUG_FUNCTION void
1194 : 0 : debug_oacc_loop (oacc_loop *loop)
1195 : : {
1196 : 0 : dump_oacc_loop (stderr, loop, 0);
1197 : 0 : }
1198 : :
1199 : : /* Provide diagnostics on OpenACC loop LOOP, its children, and its
1200 : : siblings. */
1201 : :
1202 : : static void
1203 : 2587 : inform_oacc_loop (const oacc_loop *loop)
1204 : : {
1205 : 5174 : const char *gang
1206 : 2587 : = loop->mask & GOMP_DIM_MASK (GOMP_DIM_GANG) ? " gang" : "";
1207 : 5174 : const char *worker
1208 : 2587 : = loop->mask & GOMP_DIM_MASK (GOMP_DIM_WORKER) ? " worker" : "";
1209 : 5174 : const char *vector
1210 : 2587 : = loop->mask & GOMP_DIM_MASK (GOMP_DIM_VECTOR) ? " vector" : "";
1211 : 2587 : const char *seq = loop->mask == 0 ? " seq" : "";
1212 : 2587 : const dump_user_location_t loc
1213 : 2587 : = dump_user_location_t::from_location_t (loop->loc);
1214 : 2587 : dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
1215 : : "assigned OpenACC%s%s%s%s loop parallelism\n", gang, worker,
1216 : : vector, seq);
1217 : :
1218 : 2587 : if (loop->child)
1219 : 622 : inform_oacc_loop (loop->child);
1220 : 2587 : if (loop->sibling)
1221 : 210 : inform_oacc_loop (loop->sibling);
1222 : 2587 : }
1223 : :
1224 : : /* DFS walk of basic blocks BB onwards, creating OpenACC loop
1225 : : structures as we go. By construction these loops are properly
1226 : : nested. */
1227 : :
1228 : : static void
1229 : 162952 : oacc_loop_discover_walk (oacc_loop *loop, basic_block bb)
1230 : : {
1231 : 162952 : int marker = 0;
1232 : 162952 : int remaining = 0;
1233 : :
1234 : 162952 : if (bb->flags & BB_VISITED)
1235 : 37117 : return;
1236 : :
1237 : 125835 : follow:
1238 : 183915 : bb->flags |= BB_VISITED;
1239 : :
1240 : : /* Scan for loop markers. */
1241 : 724892 : for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
1242 : 357062 : gsi_next (&gsi))
1243 : : {
1244 : 357062 : gimple *stmt = gsi_stmt (gsi);
1245 : :
1246 : 357062 : if (!is_gimple_call (stmt))
1247 : 212418 : continue;
1248 : :
1249 : 148989 : gcall *call = as_a <gcall *> (stmt);
1250 : :
1251 : : /* If this is a routine, make a dummy loop for it. */
1252 : 148989 : if (tree decl = gimple_call_fndecl (call))
1253 : 4344 : if (tree attrs = oacc_get_fn_attrib (decl))
1254 : : {
1255 : 1061 : gcc_assert (!marker);
1256 : 1061 : new_oacc_loop_routine (loop, call, decl, attrs);
1257 : : }
1258 : :
1259 : 148989 : if (!gimple_call_internal_p (call))
1260 : 4345 : continue;
1261 : :
1262 : 144644 : switch (gimple_call_internal_fn (call))
1263 : : {
1264 : : default:
1265 : : break;
1266 : :
1267 : 43492 : case IFN_GOACC_LOOP:
1268 : 43492 : case IFN_GOACC_TILE:
1269 : : /* Record the abstraction function, so we can manipulate it
1270 : : later. */
1271 : 43492 : loop->ifns.safe_push (call);
1272 : 43492 : break;
1273 : :
1274 : 75138 : case IFN_UNIQUE:
1275 : 75138 : enum ifn_unique_kind kind
1276 : 75138 : = (enum ifn_unique_kind) (TREE_INT_CST_LOW
1277 : 75138 : (gimple_call_arg (call, 0)));
1278 : 75138 : if (kind == IFN_UNIQUE_OACC_HEAD_MARK
1279 : 75138 : || kind == IFN_UNIQUE_OACC_TAIL_MARK)
1280 : : {
1281 : 45964 : if (gimple_call_num_args (call) == 2)
1282 : : {
1283 : 17038 : gcc_assert (marker && !remaining);
1284 : 17038 : marker = 0;
1285 : 17038 : if (kind == IFN_UNIQUE_OACC_TAIL_MARK)
1286 : 17038 : loop = finish_oacc_loop (loop);
1287 : : else
1288 : 8519 : loop->head_end = call;
1289 : : }
1290 : : else
1291 : : {
1292 : 28926 : int count = TREE_INT_CST_LOW (gimple_call_arg (call, 2));
1293 : :
1294 : 28926 : if (!marker)
1295 : : {
1296 : 17038 : if (kind == IFN_UNIQUE_OACC_HEAD_MARK)
1297 : 8519 : loop = new_oacc_loop (loop, call);
1298 : : remaining = count;
1299 : : }
1300 : 28926 : gcc_assert (count == remaining);
1301 : 28926 : if (remaining)
1302 : : {
1303 : 28926 : remaining--;
1304 : 28926 : if (kind == IFN_UNIQUE_OACC_HEAD_MARK)
1305 : 14463 : loop->heads[marker] = call;
1306 : : else
1307 : 14463 : loop->tails[remaining] = call;
1308 : : }
1309 : 28926 : marker++;
1310 : : }
1311 : : }
1312 : : }
1313 : : }
1314 : 183915 : if (remaining || marker)
1315 : : {
1316 : 58080 : bb = single_succ (bb);
1317 : 116160 : gcc_assert (single_pred_p (bb) && !(bb->flags & BB_VISITED));
1318 : 58080 : goto follow;
1319 : : }
1320 : :
1321 : : /* Walk successor blocks. */
1322 : 125835 : edge e;
1323 : 125835 : edge_iterator ei;
1324 : :
1325 : 279334 : FOR_EACH_EDGE (e, ei, bb->succs)
1326 : 153499 : oacc_loop_discover_walk (loop, e->dest);
1327 : : }
1328 : :
1329 : : /* LOOP is the first sibling. Reverse the order in place and return
1330 : : the new first sibling. Recurse to child loops. */
1331 : :
1332 : : static oacc_loop *
1333 : 17194 : oacc_loop_sibling_nreverse (oacc_loop *loop)
1334 : : {
1335 : 17194 : oacc_loop *last = NULL;
1336 : 19033 : do
1337 : : {
1338 : 19033 : if (loop->child)
1339 : 7741 : loop->child = oacc_loop_sibling_nreverse (loop->child);
1340 : :
1341 : 19033 : oacc_loop *next = loop->sibling;
1342 : 19033 : loop->sibling = last;
1343 : 19033 : last = loop;
1344 : 19033 : loop = next;
1345 : : }
1346 : 19033 : while (loop);
1347 : :
1348 : 17194 : return last;
1349 : : }
1350 : :
1351 : : /* Discover the OpenACC loops marked up by HEAD and TAIL markers for
1352 : : the current function. */
1353 : :
1354 : : static oacc_loop *
1355 : 9453 : oacc_loop_discovery ()
1356 : : {
1357 : : /* Clear basic block flags, in particular BB_VISITED which we're going to use
1358 : : in the following. */
1359 : 9453 : clear_bb_flags ();
1360 : :
1361 : 9453 : oacc_loop *top = new_oacc_loop_outer (current_function_decl);
1362 : 9453 : oacc_loop_discover_walk (top, ENTRY_BLOCK_PTR_FOR_FN (cfun));
1363 : :
1364 : : /* The siblings were constructed in reverse order, reverse them so
1365 : : that diagnostics come out in an unsurprising order. */
1366 : 9453 : top = oacc_loop_sibling_nreverse (top);
1367 : :
1368 : 9453 : return top;
1369 : : }
1370 : :
1371 : : /* Transform the abstract internal function markers starting at FROM
1372 : : to be for partitioning level LEVEL. Stop when we meet another HEAD
1373 : : or TAIL marker. */
1374 : :
1375 : : static void
1376 : 23332 : oacc_loop_xform_head_tail (gcall *from, int level)
1377 : : {
1378 : 23332 : enum ifn_unique_kind kind
1379 : 23332 : = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (from, 0));
1380 : 23332 : tree replacement = build_int_cst (unsigned_type_node, level);
1381 : :
1382 : 23332 : for (gimple_stmt_iterator gsi = gsi_for_stmt (from);;)
1383 : : {
1384 : 99471 : gimple *stmt = gsi_stmt (gsi);
1385 : :
1386 : 99471 : if (gimple_call_internal_p (stmt, IFN_UNIQUE))
1387 : : {
1388 : 70219 : enum ifn_unique_kind k
1389 : : = ((enum ifn_unique_kind)
1390 : 70219 : TREE_INT_CST_LOW (gimple_call_arg (stmt, 0)));
1391 : :
1392 : 70219 : if (k == IFN_UNIQUE_OACC_FORK
1393 : 70219 : || k == IFN_UNIQUE_OACC_JOIN
1394 : 70219 : || k == IFN_UNIQUE_OACC_PRIVATE)
1395 : 23555 : *gimple_call_arg_ptr (stmt, 2) = replacement;
1396 : 46664 : else if (k == kind && stmt != from)
1397 : : break;
1398 : : }
1399 : 29252 : else if (gimple_call_internal_p (stmt, IFN_GOACC_REDUCTION))
1400 : 17424 : *gimple_call_arg_ptr (stmt, 3) = replacement;
1401 : 76139 : update_stmt (stmt);
1402 : :
1403 : 76139 : gsi_next (&gsi);
1404 : 123026 : while (gsi_end_p (gsi))
1405 : 93774 : gsi = gsi_start_bb (single_succ (gsi_bb (gsi)));
1406 : : }
1407 : 23332 : }
1408 : :
1409 : : /* Process the discovered OpenACC loops, setting the correct
1410 : : partitioning level etc. */
1411 : :
1412 : : static void
1413 : 19033 : oacc_loop_process (oacc_loop *loop, int fn_level)
1414 : : {
1415 : 19033 : if (loop->child)
1416 : 7741 : oacc_loop_process (loop->child, fn_level);
1417 : :
1418 : 19033 : if (loop->mask && !loop->routine)
1419 : : {
1420 : 7748 : int ix;
1421 : 7748 : tree mask_arg = build_int_cst (unsigned_type_node, loop->mask);
1422 : 7748 : tree e_mask_arg = build_int_cst (unsigned_type_node, loop->e_mask);
1423 : 7748 : tree chunk_arg = loop->chunk_size;
1424 : 7748 : gcall *call;
1425 : :
1426 : 39252 : for (ix = 0; loop->ifns.iterate (ix, &call); ix++)
1427 : : {
1428 : 31504 : switch (gimple_call_internal_fn (call))
1429 : : {
1430 : 31293 : case IFN_GOACC_LOOP:
1431 : 31293 : {
1432 : 31293 : bool is_e = gimple_call_arg (call, 5) == integer_minus_one_node;
1433 : 62183 : gimple_call_set_arg (call, 5, is_e ? e_mask_arg : mask_arg);
1434 : 31293 : if (!is_e)
1435 : 30890 : gimple_call_set_arg (call, 4, chunk_arg);
1436 : : }
1437 : : break;
1438 : :
1439 : 211 : case IFN_GOACC_TILE:
1440 : 211 : gimple_call_set_arg (call, 3, mask_arg);
1441 : 211 : gimple_call_set_arg (call, 4, e_mask_arg);
1442 : 211 : break;
1443 : :
1444 : 0 : default:
1445 : 0 : gcc_unreachable ();
1446 : : }
1447 : 31504 : update_stmt (call);
1448 : : }
1449 : :
1450 : 7748 : unsigned dim = GOMP_DIM_GANG;
1451 : 7748 : unsigned mask = loop->mask | loop->e_mask;
1452 : 19414 : for (ix = 0; ix != GOMP_DIM_MAX && mask; ix++)
1453 : : {
1454 : 22710 : while (!(GOMP_DIM_MASK (dim) & mask))
1455 : 11044 : dim++;
1456 : :
1457 : 11666 : oacc_loop_xform_head_tail (loop->heads[ix], dim);
1458 : 11666 : oacc_loop_xform_head_tail (loop->tails[ix], dim);
1459 : :
1460 : 11666 : mask ^= GOMP_DIM_MASK (dim);
1461 : : }
1462 : : }
1463 : :
1464 : 19033 : if (loop->sibling)
1465 : 1839 : oacc_loop_process (loop->sibling, fn_level);
1466 : :
1467 : :
1468 : : /* OpenACC 2.6, 2.9.11. "reduction clause" places a restriction such that
1469 : : "The 'reduction' clause may not be specified on an orphaned 'loop'
1470 : : construct with the 'gang' clause, or on an orphaned 'loop' construct that
1471 : : will generate gang parallelism in a procedure that is compiled with the
1472 : : 'routine gang' clause." */
1473 : 19033 : if (fn_level == GOMP_DIM_GANG
1474 : 733 : && (loop->mask & GOMP_DIM_MASK (GOMP_DIM_GANG))
1475 : 241 : && (loop->flags & OLF_REDUCTION))
1476 : 126 : error_at (loop->loc,
1477 : : "gang reduction on an orphan loop");
1478 : 19033 : }
1479 : :
1480 : : /* Walk the OpenACC loop heirarchy checking and assigning the
1481 : : programmer-specified partitionings. OUTER_MASK is the partitioning
1482 : : this loop is contained within. Return mask of partitioning
1483 : : encountered. If any auto loops are discovered, set GOMP_DIM_MAX
1484 : : bit. */
1485 : :
1486 : : static unsigned
1487 : 19033 : oacc_loop_fixed_partitions (oacc_loop *loop, unsigned outer_mask)
1488 : : {
1489 : 19033 : unsigned this_mask = loop->mask;
1490 : 19033 : unsigned mask_all = 0;
1491 : 19033 : bool noisy = true;
1492 : :
1493 : : #ifdef ACCEL_COMPILER
1494 : : /* When device_type is supported, we want the device compiler to be
1495 : : noisy, if the loop parameters are device_type-specific. */
1496 : : noisy = false;
1497 : : #endif
1498 : :
1499 : 19033 : if (!loop->routine)
1500 : : {
1501 : 17972 : bool auto_par = (loop->flags & OLF_AUTO) != 0;
1502 : 17972 : bool seq_par = (loop->flags & OLF_SEQ) != 0;
1503 : 17972 : bool tiling = (loop->flags & OLF_TILE) != 0;
1504 : :
1505 : 17972 : this_mask = ((loop->flags >> OLF_DIM_BASE)
1506 : : & (GOMP_DIM_MASK (GOMP_DIM_MAX) - 1));
1507 : :
1508 : : /* Apply auto partitioning if this is a non-partitioned regular
1509 : : loop, or (no more than) single axis tiled loop. */
1510 : 35944 : bool maybe_auto
1511 : 17972 : = !seq_par && this_mask == (tiling ? this_mask & -this_mask : 0);
1512 : :
1513 : 17972 : if ((this_mask != 0) + auto_par + seq_par > 1)
1514 : : {
1515 : 102 : if (noisy)
1516 : 150 : error_at (loop->loc,
1517 : : seq_par
1518 : : ? G_("%<seq%> overrides other OpenACC loop specifiers")
1519 : : : G_("%<auto%> conflicts with other OpenACC loop "
1520 : : "specifiers"));
1521 : 102 : maybe_auto = false;
1522 : 102 : loop->flags &= ~OLF_AUTO;
1523 : 102 : if (seq_par)
1524 : : {
1525 : 54 : loop->flags
1526 : 54 : &= ~((GOMP_DIM_MASK (GOMP_DIM_MAX) - 1) << OLF_DIM_BASE);
1527 : 54 : this_mask = 0;
1528 : : }
1529 : : }
1530 : :
1531 : 17924 : if (maybe_auto && (loop->flags & OLF_INDEPENDENT))
1532 : : {
1533 : 4747 : loop->flags |= OLF_AUTO;
1534 : 4747 : mask_all |= GOMP_DIM_MASK (GOMP_DIM_MAX);
1535 : : }
1536 : : }
1537 : :
1538 : 19033 : if (this_mask & outer_mask)
1539 : : {
1540 : 244 : const oacc_loop *outer;
1541 : 370 : for (outer = loop->parent; outer; outer = outer->parent)
1542 : 244 : if ((outer->mask | outer->e_mask) & this_mask)
1543 : : break;
1544 : :
1545 : 244 : if (noisy)
1546 : : {
1547 : 244 : if (outer)
1548 : : {
1549 : 118 : error_at (loop->loc,
1550 : 118 : loop->routine
1551 : : ? G_("routine call uses same OpenACC parallelism"
1552 : : " as containing loop")
1553 : : : G_("inner loop uses same OpenACC parallelism"
1554 : : " as containing loop"));
1555 : 118 : inform (outer->loc, "containing loop here");
1556 : : }
1557 : : else
1558 : 126 : error_at (loop->loc,
1559 : 126 : loop->routine
1560 : : ? G_("routine call uses OpenACC parallelism disallowed"
1561 : : " by containing routine")
1562 : : : G_("loop uses OpenACC parallelism disallowed"
1563 : : " by containing routine"));
1564 : :
1565 : 244 : if (loop->routine)
1566 : 152 : inform (DECL_SOURCE_LOCATION (loop->routine),
1567 : : "routine %qD declared here", loop->routine);
1568 : : }
1569 : 244 : this_mask &= ~outer_mask;
1570 : : }
1571 : : else
1572 : : {
1573 : 18789 : unsigned outermost = least_bit_hwi (this_mask);
1574 : :
1575 : 18789 : if (outermost && outermost <= outer_mask)
1576 : : {
1577 : 26 : if (noisy)
1578 : : {
1579 : 26 : error_at (loop->loc,
1580 : : "incorrectly nested OpenACC loop parallelism");
1581 : :
1582 : 26 : const oacc_loop *outer;
1583 : 26 : for (outer = loop->parent;
1584 : 26 : outer->flags && outer->flags < outermost;
1585 : 0 : outer = outer->parent)
1586 : 0 : continue;
1587 : 26 : inform (outer->loc, "containing loop here");
1588 : 0 : }
1589 : :
1590 : 26 : this_mask &= ~outermost;
1591 : : }
1592 : : }
1593 : :
1594 : 19033 : mask_all |= this_mask;
1595 : :
1596 : 19033 : if (loop->flags & OLF_TILE)
1597 : : {
1598 : : /* When tiling, vector goes to the element loop, and failing
1599 : : that we put worker there. The std doesn't contemplate
1600 : : specifying all three. We choose to put worker and vector on
1601 : : the element loops in that case. */
1602 : 146 : unsigned this_e_mask = this_mask & GOMP_DIM_MASK (GOMP_DIM_VECTOR);
1603 : 146 : if (!this_e_mask || this_mask & GOMP_DIM_MASK (GOMP_DIM_GANG))
1604 : 127 : this_e_mask |= this_mask & GOMP_DIM_MASK (GOMP_DIM_WORKER);
1605 : :
1606 : 146 : loop->e_mask = this_e_mask;
1607 : 146 : this_mask ^= this_e_mask;
1608 : : }
1609 : :
1610 : 19033 : loop->mask = this_mask;
1611 : :
1612 : 19033 : if (dump_file)
1613 : 208 : fprintf (dump_file, "Loop %s:%d user specified %d & %d\n",
1614 : 416 : LOCATION_FILE (loop->loc), LOCATION_LINE (loop->loc),
1615 : : loop->mask, loop->e_mask);
1616 : :
1617 : 19033 : if (loop->child)
1618 : : {
1619 : 7741 : unsigned tmp_mask = outer_mask | this_mask | loop->e_mask;
1620 : 7741 : loop->inner = oacc_loop_fixed_partitions (loop->child, tmp_mask);
1621 : 7741 : mask_all |= loop->inner;
1622 : : }
1623 : :
1624 : 19033 : if (loop->sibling)
1625 : 1839 : mask_all |= oacc_loop_fixed_partitions (loop->sibling, outer_mask);
1626 : :
1627 : 19033 : return mask_all;
1628 : : }
1629 : :
1630 : : /* Walk the OpenACC loop heirarchy to assign auto-partitioned loops.
1631 : : OUTER_MASK is the partitioning this loop is contained within.
1632 : : OUTER_ASSIGN is true if an outer loop is being auto-partitioned.
1633 : : Return the cumulative partitioning used by this loop, siblings and
1634 : : children. */
1635 : :
1636 : : static unsigned
1637 : 8907 : oacc_loop_auto_partitions (oacc_loop *loop, unsigned outer_mask,
1638 : : bool outer_assign)
1639 : : {
1640 : 8907 : bool assign = (loop->flags & OLF_AUTO) && (loop->flags & OLF_INDEPENDENT);
1641 : 8907 : bool noisy = true;
1642 : 8907 : bool tiling = loop->flags & OLF_TILE;
1643 : :
1644 : : #ifdef ACCEL_COMPILER
1645 : : /* When device_type is supported, we want the device compiler to be
1646 : : noisy, if the loop parameters are device_type-specific. */
1647 : : noisy = false;
1648 : : #endif
1649 : :
1650 : 8907 : if (assign && (!outer_assign || loop->inner))
1651 : : {
1652 : : /* Allocate outermost and non-innermost loops at the outermost
1653 : : non-innermost available level. */
1654 : : unsigned this_mask = GOMP_DIM_MASK (GOMP_DIM_GANG);
1655 : :
1656 : : /* Find the first outermost available partition. */
1657 : 5524 : while (this_mask <= outer_mask)
1658 : 1488 : this_mask <<= 1;
1659 : :
1660 : : /* Grab two axes if tiling, and we've not assigned anything */
1661 : 4036 : if (tiling && !(loop->mask | loop->e_mask))
1662 : 96 : this_mask |= this_mask << 1;
1663 : :
1664 : : /* Prohibit the innermost partitioning at the moment. */
1665 : 4036 : this_mask &= GOMP_DIM_MASK (GOMP_DIM_MAX - 1) - 1;
1666 : :
1667 : : /* Don't use any dimension explicitly claimed by an inner loop. */
1668 : 4036 : this_mask &= ~loop->inner;
1669 : :
1670 : 4036 : if (tiling && !loop->e_mask)
1671 : : {
1672 : : /* If we got two axes, allocate the inner one to the element
1673 : : loop. */
1674 : 101 : loop->e_mask = this_mask & (this_mask << 1);
1675 : 101 : this_mask ^= loop->e_mask;
1676 : : }
1677 : :
1678 : 4036 : loop->mask |= this_mask;
1679 : : }
1680 : :
1681 : 8907 : if (loop->child)
1682 : : {
1683 : 4643 : unsigned tmp_mask = outer_mask | loop->mask | loop->e_mask;
1684 : 4643 : loop->inner = oacc_loop_auto_partitions (loop->child, tmp_mask,
1685 : 4643 : outer_assign | assign);
1686 : : }
1687 : :
1688 : 8907 : if (assign && (!loop->mask || (tiling && !loop->e_mask) || !outer_assign))
1689 : : {
1690 : : /* Allocate the loop at the innermost available level. Note
1691 : : that we do this even if we already assigned this loop the
1692 : : outermost available level above. That way we'll partition
1693 : : this along 2 axes, if they are available. */
1694 : 4292 : unsigned this_mask = 0;
1695 : :
1696 : : /* Determine the outermost partitioning used within this loop. */
1697 : 4292 : this_mask = loop->inner | GOMP_DIM_MASK (GOMP_DIM_MAX);
1698 : 4292 : this_mask = least_bit_hwi (this_mask);
1699 : :
1700 : : /* Pick the partitioning just inside that one. */
1701 : 4292 : this_mask >>= 1;
1702 : :
1703 : : /* And avoid picking one use by an outer loop. */
1704 : 4292 : this_mask &= ~outer_mask;
1705 : :
1706 : : /* If tiling and we failed completely above, grab the next one
1707 : : too. Making sure it doesn't hit an outer loop. */
1708 : 4292 : if (tiling)
1709 : : {
1710 : 116 : this_mask &= ~(loop->e_mask | loop->mask);
1711 : 116 : unsigned tile_mask = ((this_mask >> 1)
1712 : 116 : & ~(outer_mask | loop->e_mask | loop->mask));
1713 : :
1714 : 116 : if (tile_mask || loop->mask)
1715 : : {
1716 : 106 : loop->e_mask |= this_mask;
1717 : 106 : this_mask = tile_mask;
1718 : : }
1719 : 116 : if (!loop->e_mask && noisy)
1720 : 10 : warning_at (loop->loc, 0,
1721 : : "insufficient partitioning available"
1722 : : " to parallelize element loop");
1723 : : }
1724 : :
1725 : 4292 : loop->mask |= this_mask;
1726 : 4292 : if (!loop->mask && noisy)
1727 : 773 : warning_at (loop->loc, 0,
1728 : : tiling
1729 : : ? G_("insufficient partitioning available"
1730 : : " to parallelize tile loop")
1731 : : : G_("insufficient partitioning available"
1732 : : " to parallelize loop"));
1733 : : }
1734 : :
1735 : 4747 : if (assign && dump_file)
1736 : 38 : fprintf (dump_file, "Auto loop %s:%d assigned %d & %d\n",
1737 : 76 : LOCATION_FILE (loop->loc), LOCATION_LINE (loop->loc),
1738 : : loop->mask, loop->e_mask);
1739 : :
1740 : 8907 : unsigned inner_mask = 0;
1741 : :
1742 : 8907 : if (loop->sibling)
1743 : 1421 : inner_mask |= oacc_loop_auto_partitions (loop->sibling,
1744 : : outer_mask, outer_assign);
1745 : :
1746 : 8907 : inner_mask |= loop->inner | loop->mask | loop->e_mask;
1747 : :
1748 : 8907 : return inner_mask;
1749 : : }
1750 : :
1751 : : /* Walk the OpenACC loop heirarchy to check and assign partitioning
1752 : : axes. Return mask of partitioning. */
1753 : :
1754 : : static unsigned
1755 : 9453 : oacc_loop_partition (oacc_loop *loop, unsigned outer_mask)
1756 : : {
1757 : 9453 : unsigned mask_all = oacc_loop_fixed_partitions (loop, outer_mask);
1758 : :
1759 : 9453 : if (mask_all & GOMP_DIM_MASK (GOMP_DIM_MAX))
1760 : : {
1761 : 2843 : mask_all ^= GOMP_DIM_MASK (GOMP_DIM_MAX);
1762 : 2843 : mask_all |= oacc_loop_auto_partitions (loop, outer_mask, false);
1763 : : }
1764 : 9453 : return mask_all;
1765 : : }
1766 : :
1767 : : /* Default fork/join early expander. Delete the function calls if
1768 : : there is no RTL expander. */
1769 : :
1770 : : bool
1771 : 23332 : default_goacc_fork_join (gcall *ARG_UNUSED (call),
1772 : : const int *ARG_UNUSED (dims), bool is_fork)
1773 : : {
1774 : 23332 : if (is_fork)
1775 : 11666 : return targetm.have_oacc_fork ();
1776 : : else
1777 : 11666 : return targetm.have_oacc_join ();
1778 : : }
1779 : :
1780 : : /* Default goacc.reduction early expander.
1781 : :
1782 : : LHS-opt = IFN_REDUCTION (KIND, RES_PTR, VAR, LEVEL, OP, OFFSET)
1783 : : If RES_PTR is not integer-zerop:
1784 : : SETUP - emit 'LHS = *RES_PTR', LHS = NULL
1785 : : TEARDOWN - emit '*RES_PTR = VAR'
1786 : : If LHS is not NULL
1787 : : emit 'LHS = VAR' */
1788 : :
1789 : : void
1790 : 25376 : default_goacc_reduction (gcall *call)
1791 : : {
1792 : 25376 : unsigned code = (unsigned)TREE_INT_CST_LOW (gimple_call_arg (call, 0));
1793 : 25376 : gimple_stmt_iterator gsi = gsi_for_stmt (call);
1794 : 25376 : tree lhs = gimple_call_lhs (call);
1795 : 25376 : tree var = gimple_call_arg (call, 2);
1796 : 25376 : gimple_seq seq = NULL;
1797 : :
1798 : 25376 : if (code == IFN_GOACC_REDUCTION_SETUP
1799 : 25376 : || code == IFN_GOACC_REDUCTION_TEARDOWN)
1800 : : {
1801 : : /* Setup and Teardown need to copy from/to the receiver object,
1802 : : if there is one. */
1803 : 12688 : tree ref_to_res = gimple_call_arg (call, 1);
1804 : :
1805 : 12688 : if (!integer_zerop (ref_to_res))
1806 : : {
1807 : 4802 : tree dst = build_simple_mem_ref (ref_to_res);
1808 : 4802 : tree src = var;
1809 : :
1810 : 4802 : if (code == IFN_GOACC_REDUCTION_SETUP)
1811 : : {
1812 : 2401 : src = dst;
1813 : 2401 : dst = lhs;
1814 : 2401 : lhs = NULL;
1815 : : }
1816 : 4802 : gimple_seq_add_stmt (&seq, gimple_build_assign (dst, src));
1817 : : }
1818 : : }
1819 : :
1820 : : /* Copy VAR to LHS, if there is an LHS. */
1821 : 25376 : if (lhs)
1822 : 21433 : gimple_seq_add_stmt (&seq, gimple_build_assign (lhs, var));
1823 : :
1824 : 25376 : gsi_replace_with_seq (&gsi, seq, true);
1825 : 25376 : }
1826 : :
1827 : : struct var_decl_rewrite_info
1828 : : {
1829 : : gimple *stmt;
1830 : : hash_map<tree, tree> *adjusted_vars;
1831 : : bool avoid_pointer_conversion;
1832 : : bool modified;
1833 : : };
1834 : :
1835 : : /* Helper function for execute_oacc_device_lower. Rewrite VAR_DECLs (by
1836 : : themselves or wrapped in various other nodes) according to ADJUSTED_VARS in
1837 : : the var_decl_rewrite_info pointed to via DATA. Used as part of coercing
1838 : : gang-private variables in OpenACC offload regions to reside in GPU shared
1839 : : memory. */
1840 : :
1841 : : static tree
1842 : 0 : oacc_rewrite_var_decl (tree *tp, int *walk_subtrees, void *data)
1843 : : {
1844 : 0 : walk_stmt_info *wi = (walk_stmt_info *) data;
1845 : 0 : var_decl_rewrite_info *info = (var_decl_rewrite_info *) wi->info;
1846 : :
1847 : 0 : if (TREE_CODE (*tp) == ADDR_EXPR)
1848 : : {
1849 : 0 : tree arg = TREE_OPERAND (*tp, 0);
1850 : 0 : tree *new_arg = info->adjusted_vars->get (arg);
1851 : :
1852 : 0 : if (new_arg)
1853 : : {
1854 : 0 : if (info->avoid_pointer_conversion)
1855 : : {
1856 : 0 : *tp = build_fold_addr_expr (*new_arg);
1857 : 0 : info->modified = true;
1858 : 0 : *walk_subtrees = 0;
1859 : : }
1860 : : else
1861 : : {
1862 : 0 : gimple_stmt_iterator gsi = gsi_for_stmt (info->stmt);
1863 : 0 : tree repl = build_fold_addr_expr (*new_arg);
1864 : 0 : gimple *stmt1
1865 : 0 : = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
1866 : 0 : tree conv = convert_to_pointer (TREE_TYPE (*tp),
1867 : : gimple_assign_lhs (stmt1));
1868 : 0 : gimple *stmt2
1869 : 0 : = gimple_build_assign (make_ssa_name (TREE_TYPE (*tp)), conv);
1870 : 0 : gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
1871 : 0 : gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
1872 : 0 : *tp = gimple_assign_lhs (stmt2);
1873 : 0 : info->modified = true;
1874 : 0 : *walk_subtrees = 0;
1875 : : }
1876 : : }
1877 : : }
1878 : 0 : else if (TREE_CODE (*tp) == COMPONENT_REF || TREE_CODE (*tp) == ARRAY_REF)
1879 : : {
1880 : 0 : tree *base = &TREE_OPERAND (*tp, 0);
1881 : :
1882 : 0 : while (TREE_CODE (*base) == COMPONENT_REF
1883 : 0 : || TREE_CODE (*base) == ARRAY_REF)
1884 : 0 : base = &TREE_OPERAND (*base, 0);
1885 : :
1886 : 0 : if (TREE_CODE (*base) != VAR_DECL)
1887 : : return NULL;
1888 : :
1889 : 0 : tree *new_decl = info->adjusted_vars->get (*base);
1890 : 0 : if (!new_decl)
1891 : : return NULL;
1892 : :
1893 : 0 : int base_quals = TYPE_QUALS (TREE_TYPE (*new_decl));
1894 : 0 : tree field = TREE_OPERAND (*tp, 1);
1895 : :
1896 : : /* Adjust the type of the field. */
1897 : 0 : int field_quals = TYPE_QUALS (TREE_TYPE (field));
1898 : 0 : if (TREE_CODE (field) == FIELD_DECL && field_quals != base_quals)
1899 : : {
1900 : 0 : tree *field_type = &TREE_TYPE (field);
1901 : 0 : while (TREE_CODE (*field_type) == ARRAY_TYPE)
1902 : 0 : field_type = &TREE_TYPE (*field_type);
1903 : 0 : field_quals |= base_quals;
1904 : 0 : *field_type = build_qualified_type (*field_type, field_quals);
1905 : : }
1906 : :
1907 : : /* Adjust the type of the component ref itself. */
1908 : 0 : tree comp_type = TREE_TYPE (*tp);
1909 : 0 : int comp_quals = TYPE_QUALS (comp_type);
1910 : 0 : if (TREE_CODE (*tp) == COMPONENT_REF && comp_quals != base_quals)
1911 : : {
1912 : 0 : comp_quals |= base_quals;
1913 : 0 : TREE_TYPE (*tp)
1914 : 0 : = build_qualified_type (comp_type, comp_quals);
1915 : : }
1916 : :
1917 : 0 : *base = *new_decl;
1918 : 0 : info->modified = true;
1919 : 0 : }
1920 : 0 : else if (VAR_P (*tp))
1921 : : {
1922 : 0 : tree *new_decl = info->adjusted_vars->get (*tp);
1923 : 0 : if (new_decl)
1924 : : {
1925 : 0 : *tp = *new_decl;
1926 : 0 : info->modified = true;
1927 : : }
1928 : : }
1929 : :
1930 : : return NULL_TREE;
1931 : : }
1932 : :
1933 : : /* Return TRUE if CALL is a call to a builtin atomic/sync operation. */
1934 : :
1935 : : static bool
1936 : 0 : is_sync_builtin_call (gcall *call)
1937 : : {
1938 : 0 : tree callee = gimple_call_fndecl (call);
1939 : :
1940 : 0 : if (callee != NULL_TREE
1941 : 0 : && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1942 : 0 : switch (DECL_FUNCTION_CODE (callee))
1943 : : {
1944 : : #undef DEF_SYNC_BUILTIN
1945 : : #define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
1946 : : #include "sync-builtins.def"
1947 : : #undef DEF_SYNC_BUILTIN
1948 : : return true;
1949 : :
1950 : : default:
1951 : : ;
1952 : : }
1953 : :
1954 : : return false;
1955 : : }
1956 : :
1957 : : /* Main entry point for oacc transformations which run on the device
1958 : : compiler after LTO, so we know what the target device is at this
1959 : : point (including the host fallback). */
1960 : :
1961 : : static unsigned int
1962 : 14894 : execute_oacc_loop_designation ()
1963 : : {
1964 : 14894 : tree attrs = oacc_get_fn_attrib (current_function_decl);
1965 : :
1966 : 14894 : if (!attrs)
1967 : : /* Not an offloaded function. */
1968 : : return 0;
1969 : :
1970 : : /* Parse the default dim argument exactly once. */
1971 : 9523 : if ((const void *)flag_openacc_dims != &flag_openacc_dims)
1972 : : {
1973 : 2365 : oacc_parse_default_dims (flag_openacc_dims);
1974 : 2365 : flag_openacc_dims = (char *)&flag_openacc_dims;
1975 : : }
1976 : :
1977 : 9523 : bool is_oacc_parallel
1978 : 9523 : = (lookup_attribute ("oacc parallel",
1979 : 9523 : DECL_ATTRIBUTES (current_function_decl)) != NULL);
1980 : 9523 : bool is_oacc_kernels
1981 : 9523 : = (lookup_attribute ("oacc kernels",
1982 : 9523 : DECL_ATTRIBUTES (current_function_decl)) != NULL);
1983 : 9523 : bool is_oacc_serial
1984 : 9523 : = (lookup_attribute ("oacc serial",
1985 : 9523 : DECL_ATTRIBUTES (current_function_decl)) != NULL);
1986 : 9523 : bool is_oacc_parallel_kernels_parallelized
1987 : 9523 : = (lookup_attribute ("oacc parallel_kernels_parallelized",
1988 : 9523 : DECL_ATTRIBUTES (current_function_decl)) != NULL);
1989 : 9523 : bool is_oacc_parallel_kernels_gang_single
1990 : 9523 : = (lookup_attribute ("oacc parallel_kernels_gang_single",
1991 : 9523 : DECL_ATTRIBUTES (current_function_decl)) != NULL);
1992 : 9523 : int fn_level = oacc_fn_attrib_level (attrs);
1993 : 9523 : bool is_oacc_routine = (fn_level >= 0);
1994 : 9523 : gcc_checking_assert (is_oacc_parallel
1995 : : + is_oacc_kernels
1996 : : + is_oacc_serial
1997 : : + is_oacc_parallel_kernels_parallelized
1998 : : + is_oacc_parallel_kernels_gang_single
1999 : : + is_oacc_routine
2000 : : == 1);
2001 : :
2002 : 9523 : bool is_oacc_kernels_parallelized
2003 : 9523 : = (lookup_attribute ("oacc kernels parallelized",
2004 : 9523 : DECL_ATTRIBUTES (current_function_decl)) != NULL);
2005 : 9523 : if (is_oacc_kernels_parallelized)
2006 : 422 : gcc_checking_assert (is_oacc_kernels);
2007 : :
2008 : 9523 : if (dump_file)
2009 : : {
2010 : 161 : if (is_oacc_parallel)
2011 : 42 : fprintf (dump_file, "Function is OpenACC parallel offload\n");
2012 : 119 : else if (is_oacc_kernels)
2013 : 84 : fprintf (dump_file, "Function is %s OpenACC kernels offload\n",
2014 : : (is_oacc_kernels_parallelized
2015 : : ? "parallelized" : "unparallelized"));
2016 : 71 : else if (is_oacc_serial)
2017 : 6 : fprintf (dump_file, "Function is OpenACC serial offload\n");
2018 : 65 : else if (is_oacc_parallel_kernels_parallelized)
2019 : 0 : fprintf (dump_file, "Function is %s OpenACC kernels offload\n",
2020 : : "parallel_kernels_parallelized");
2021 : 65 : else if (is_oacc_parallel_kernels_gang_single)
2022 : 0 : fprintf (dump_file, "Function is %s OpenACC kernels offload\n",
2023 : : "parallel_kernels_gang_single");
2024 : 65 : else if (is_oacc_routine)
2025 : 65 : fprintf (dump_file, "Function is OpenACC routine level %d\n",
2026 : : fn_level);
2027 : : else
2028 : 0 : gcc_unreachable ();
2029 : : }
2030 : :
2031 : : /* This doesn't belong into 'pass_oacc_loop_designation' conceptually, but
2032 : : it's a convenient place, so... */
2033 : 9523 : if (is_oacc_routine)
2034 : : {
2035 : 577 : tree attr = lookup_attribute ("omp declare target",
2036 : 577 : DECL_ATTRIBUTES (current_function_decl));
2037 : 577 : gcc_checking_assert (attr);
2038 : 577 : tree clauses = TREE_VALUE (attr);
2039 : 577 : gcc_checking_assert (clauses);
2040 : :
2041 : : /* Should this OpenACC routine be discarded? */
2042 : 577 : bool discard = false;
2043 : :
2044 : 577 : tree clause_nohost = omp_find_clause (clauses, OMP_CLAUSE_NOHOST);
2045 : 577 : if (dump_file)
2046 : 65 : fprintf (dump_file,
2047 : : "OpenACC routine '%s' %s '%s' clause.\n",
2048 : 65 : lang_hooks.decl_printable_name (current_function_decl, 2),
2049 : : clause_nohost ? "has" : "doesn't have",
2050 : 65 : omp_clause_code_name[OMP_CLAUSE_NOHOST]);
2051 : : /* Host compiler, 'nohost' clause? */
2052 : : #ifndef ACCEL_COMPILER
2053 : 577 : if (clause_nohost)
2054 : 70 : discard = true;
2055 : : #endif
2056 : :
2057 : 577 : if (dump_file)
2058 : 130 : fprintf (dump_file,
2059 : : "OpenACC routine '%s' %sdiscarded.\n",
2060 : 65 : lang_hooks.decl_printable_name (current_function_decl, 2),
2061 : : discard ? "" : "not ");
2062 : 577 : if (discard)
2063 : : {
2064 : 70 : TREE_ASM_WRITTEN (current_function_decl) = 1;
2065 : 70 : return TODO_discard_function;
2066 : : }
2067 : : }
2068 : :
2069 : : /* Unparallelized OpenACC kernels constructs must get launched as 1 x 1 x 1
2070 : : kernels, so remove the parallelism dimensions function attributes
2071 : : potentially set earlier on. */
2072 : 9453 : if (is_oacc_kernels && !is_oacc_kernels_parallelized)
2073 : : {
2074 : 1376 : oacc_set_fn_attrib (current_function_decl, NULL, NULL);
2075 : 1376 : attrs = oacc_get_fn_attrib (current_function_decl);
2076 : : }
2077 : :
2078 : : /* Discover, partition and process the loops. */
2079 : 9453 : oacc_loop *loops = oacc_loop_discovery ();
2080 : :
2081 : 9453 : unsigned outer_mask = 0;
2082 : 9453 : if (is_oacc_routine)
2083 : 507 : outer_mask = GOMP_DIM_MASK (fn_level) - 1;
2084 : 9453 : unsigned used_mask = oacc_loop_partition (loops, outer_mask);
2085 : : /* OpenACC kernels constructs are special: they currently don't use the
2086 : : generic oacc_loop infrastructure and attribute/dimension processing. */
2087 : 9453 : if (is_oacc_kernels && is_oacc_kernels_parallelized)
2088 : : {
2089 : : /* Parallelized OpenACC kernels constructs use gang parallelism. See
2090 : : also tree-parloops.cc:create_parallel_loop. */
2091 : 422 : used_mask |= GOMP_DIM_MASK (GOMP_DIM_GANG);
2092 : : }
2093 : :
2094 : 9453 : int dims[GOMP_DIM_MAX];
2095 : 9453 : oacc_validate_dims (current_function_decl, attrs, dims, fn_level, used_mask);
2096 : :
2097 : 9453 : if (dump_file)
2098 : : {
2099 : : const char *comma = "Compute dimensions [";
2100 : 452 : for (int ix = 0; ix != GOMP_DIM_MAX; ix++, comma = ", ")
2101 : 339 : fprintf (dump_file, "%s%d", comma, dims[ix]);
2102 : 113 : fprintf (dump_file, "]\n");
2103 : : }
2104 : :
2105 : : /* Verify that for OpenACC 'kernels' decomposed "gang-single" parts we launch
2106 : : a single gang only. */
2107 : 9453 : if (is_oacc_parallel_kernels_gang_single)
2108 : 145 : gcc_checking_assert (dims[GOMP_DIM_GANG] == 1);
2109 : :
2110 : 9453 : oacc_loop_process (loops, fn_level);
2111 : 9453 : if (dump_file)
2112 : : {
2113 : 113 : fprintf (dump_file, "OpenACC loops\n");
2114 : 113 : dump_oacc_loop (dump_file, loops, 0);
2115 : 113 : fprintf (dump_file, "\n");
2116 : : }
2117 : 9453 : if (dump_enabled_p ())
2118 : : {
2119 : 2287 : oacc_loop *l = loops;
2120 : : /* OpenACC kernels constructs are special: they currently don't use the
2121 : : generic oacc_loop infrastructure. */
2122 : 2287 : if (is_oacc_kernels)
2123 : : {
2124 : : /* Create a fake oacc_loop for diagnostic purposes. */
2125 : 694 : l = new_oacc_loop_raw (NULL,
2126 : 694 : DECL_SOURCE_LOCATION (current_function_decl));
2127 : 694 : l->mask = used_mask;
2128 : : }
2129 : : else
2130 : : {
2131 : : /* Skip the outermost, dummy OpenACC loop */
2132 : 1593 : l = l->child;
2133 : : }
2134 : 2287 : if (l)
2135 : 1755 : inform_oacc_loop (l);
2136 : 2287 : if (is_oacc_kernels)
2137 : 694 : free_oacc_loop (l);
2138 : : }
2139 : :
2140 : 9453 : free_oacc_loop (loops);
2141 : :
2142 : 9453 : return 0;
2143 : : }
2144 : :
2145 : : static unsigned int
2146 : 14824 : execute_oacc_device_lower ()
2147 : : {
2148 : 14824 : tree attrs = oacc_get_fn_attrib (current_function_decl);
2149 : :
2150 : 14824 : if (!attrs)
2151 : : /* Not an offloaded function. */
2152 : : return 0;
2153 : :
2154 : : int dims[GOMP_DIM_MAX];
2155 : 37812 : for (unsigned i = 0; i < GOMP_DIM_MAX; i++)
2156 : 28359 : dims[i] = oacc_get_fn_dim_size (current_function_decl, i);
2157 : :
2158 : 9453 : hash_map<tree, tree> adjusted_vars;
2159 : :
2160 : : /* Now lower internal loop functions to target-specific code
2161 : : sequences. */
2162 : 9453 : basic_block bb;
2163 : 168569 : FOR_ALL_BB_FN (bb, cfun)
2164 : 852065 : for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
2165 : : {
2166 : 533833 : gimple *stmt = gsi_stmt (gsi);
2167 : 533833 : if (!is_gimple_call (stmt))
2168 : : {
2169 : 356573 : gsi_next (&gsi);
2170 : 356573 : continue;
2171 : : }
2172 : :
2173 : 177260 : gcall *call = as_a <gcall *> (stmt);
2174 : 177260 : if (!gimple_call_internal_p (call))
2175 : : {
2176 : 4345 : gsi_next (&gsi);
2177 : 4345 : continue;
2178 : : }
2179 : :
2180 : : /* Rewind to allow rescan. */
2181 : 172915 : gsi_prev (&gsi);
2182 : 172915 : bool rescan = false, remove = false;
2183 : 172915 : enum internal_fn ifn_code = gimple_call_internal_fn (call);
2184 : :
2185 : 172915 : switch (ifn_code)
2186 : : {
2187 : : default: break;
2188 : :
2189 : 293 : case IFN_GOACC_TILE:
2190 : 293 : oacc_xform_tile (call);
2191 : 293 : rescan = true;
2192 : 293 : break;
2193 : :
2194 : 43199 : case IFN_GOACC_LOOP:
2195 : 43199 : oacc_xform_loop (call);
2196 : 43199 : rescan = true;
2197 : 43199 : break;
2198 : :
2199 : 25376 : case IFN_GOACC_REDUCTION:
2200 : : /* Mark the function for SSA renaming. */
2201 : 25376 : mark_virtual_operands_for_renaming (cfun);
2202 : :
2203 : : /* If the level is -1, this ended up being an unused
2204 : : axis. Handle as a default. */
2205 : 25376 : if (integer_minus_onep (gimple_call_arg (call, 3)))
2206 : 5828 : default_goacc_reduction (call);
2207 : : else
2208 : 19548 : targetm.goacc.reduction (call);
2209 : : rescan = true;
2210 : : break;
2211 : :
2212 : 75138 : case IFN_UNIQUE:
2213 : 75138 : {
2214 : 75138 : enum ifn_unique_kind kind
2215 : : = ((enum ifn_unique_kind)
2216 : 75138 : TREE_INT_CST_LOW (gimple_call_arg (call, 0)));
2217 : :
2218 : 75138 : switch (kind)
2219 : : {
2220 : : default:
2221 : : break;
2222 : :
2223 : 28926 : case IFN_UNIQUE_OACC_FORK:
2224 : 28926 : case IFN_UNIQUE_OACC_JOIN:
2225 : 28926 : if (integer_minus_onep (gimple_call_arg (call, 2)))
2226 : : remove = true;
2227 : 23332 : else if (!targetm.goacc.fork_join
2228 : 23332 : (call, dims, kind == IFN_UNIQUE_OACC_FORK))
2229 : 75138 : remove = true;
2230 : : break;
2231 : :
2232 : : case IFN_UNIQUE_OACC_HEAD_MARK:
2233 : : case IFN_UNIQUE_OACC_TAIL_MARK:
2234 : 75138 : remove = true;
2235 : : break;
2236 : :
2237 : 248 : case IFN_UNIQUE_OACC_PRIVATE:
2238 : 248 : {
2239 : 248 : dump_flags_t l_dump_flags
2240 : 248 : = get_openacc_privatization_dump_flags ();
2241 : :
2242 : 248 : location_t loc = gimple_location (stmt);
2243 : 248 : if (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION)
2244 : 20 : loc = DECL_SOURCE_LOCATION (current_function_decl);
2245 : 248 : const dump_user_location_t d_u_loc
2246 : 248 : = dump_user_location_t::from_location_t (loc);
2247 : :
2248 : 248 : HOST_WIDE_INT level
2249 : 248 : = TREE_INT_CST_LOW (gimple_call_arg (call, 2));
2250 : 248 : gcc_checking_assert (level == -1
2251 : : || (level >= 0
2252 : : && level < GOMP_DIM_MAX));
2253 : 340 : for (unsigned i = 3;
2254 : 588 : i < gimple_call_num_args (call);
2255 : : i++)
2256 : : {
2257 : 340 : static char const *const axes[] =
2258 : : /* Must be kept in sync with GOMP_DIM enumeration. */
2259 : : { "gang", "worker", "vector" };
2260 : :
2261 : 340 : tree arg = gimple_call_arg (call, i);
2262 : 340 : gcc_checking_assert (TREE_CODE (arg) == ADDR_EXPR);
2263 : 340 : tree decl = TREE_OPERAND (arg, 0);
2264 : 340 : if (dump_enabled_p ())
2265 : : /* PR100695 "Format decoder, quoting in 'dump_printf' etc." */
2266 : : #if __GNUC__ >= 10
2267 : 335 : # pragma GCC diagnostic push
2268 : 335 : # pragma GCC diagnostic ignored "-Wformat"
2269 : : #endif
2270 : 335 : dump_printf_loc (l_dump_flags, d_u_loc,
2271 : : "variable %<%T%> ought to be"
2272 : : " adjusted for OpenACC"
2273 : : " privatization level: %qs\n",
2274 : : decl,
2275 : : (level == -1
2276 : : ? "UNKNOWN" : axes[level]));
2277 : : #if __GNUC__ >= 10
2278 : 340 : # pragma GCC diagnostic pop
2279 : : #endif
2280 : 340 : bool adjusted;
2281 : 340 : if (level == -1)
2282 : : adjusted = false;
2283 : 335 : else if (!targetm.goacc.adjust_private_decl)
2284 : : adjusted = false;
2285 : 0 : else if (level == GOMP_DIM_VECTOR)
2286 : : {
2287 : : /* That's the default behavior. */
2288 : : adjusted = true;
2289 : : }
2290 : : else
2291 : : {
2292 : 0 : tree oldtype = TREE_TYPE (decl);
2293 : 0 : tree newdecl
2294 : 0 : = targetm.goacc.adjust_private_decl (loc, decl,
2295 : 0 : level);
2296 : 0 : adjusted = (TREE_TYPE (newdecl) != oldtype
2297 : 0 : || newdecl != decl);
2298 : 0 : if (adjusted)
2299 : 0 : adjusted_vars.put (decl, newdecl);
2300 : : }
2301 : 0 : if (adjusted
2302 : 0 : && dump_enabled_p ())
2303 : : /* PR100695 "Format decoder, quoting in 'dump_printf' etc." */
2304 : : #if __GNUC__ >= 10
2305 : 0 : # pragma GCC diagnostic push
2306 : 0 : # pragma GCC diagnostic ignored "-Wformat"
2307 : : #endif
2308 : 0 : dump_printf_loc (l_dump_flags, d_u_loc,
2309 : : "variable %<%T%> adjusted for"
2310 : : " OpenACC privatization level:"
2311 : : " %qs\n",
2312 : 0 : decl, axes[level]);
2313 : : #if __GNUC__ >= 10
2314 : 340 : # pragma GCC diagnostic pop
2315 : : #endif
2316 : : }
2317 : 248 : remove = true;
2318 : : }
2319 : 248 : break;
2320 : : }
2321 : : break;
2322 : : }
2323 : : }
2324 : :
2325 : 172915 : if (gsi_end_p (gsi))
2326 : : /* We rewound past the beginning of the BB. */
2327 : 164644 : gsi = gsi_start_bb (bb);
2328 : : else
2329 : : /* Undo the rewind. */
2330 : 90593 : gsi_next (&gsi);
2331 : :
2332 : 172915 : if (remove)
2333 : : {
2334 : 150276 : if (gimple_vdef (call))
2335 : 75138 : replace_uses_by (gimple_vdef (call), gimple_vuse (call));
2336 : 75138 : if (gimple_call_lhs (call))
2337 : : {
2338 : : /* Propagate the data dependency var. */
2339 : 70118 : gimple *ass = gimple_build_assign (gimple_call_lhs (call),
2340 : : gimple_call_arg (call, 1));
2341 : 70118 : gsi_replace (&gsi, ass, false);
2342 : : }
2343 : : else
2344 : 5020 : gsi_remove (&gsi, true);
2345 : : }
2346 : 97777 : else if (!rescan)
2347 : : /* If not rescanning, advance over the call. */
2348 : 28909 : gsi_next (&gsi);
2349 : : }
2350 : :
2351 : : /* Regarding the OpenACC privatization level, we're currently only looking at
2352 : : making the gang-private level work. Regarding that, we have the following
2353 : : configurations:
2354 : :
2355 : : - GCN offloading: 'targetm.goacc.adjust_private_decl' does the work (in
2356 : : particular, change 'TREE_TYPE', etc.) and there is no
2357 : : 'targetm.goacc.expand_var_decl'.
2358 : :
2359 : : - nvptx offloading: 'targetm.goacc.adjust_private_decl' only sets a
2360 : : marker and then 'targetm.goacc.expand_var_decl' does the work.
2361 : :
2362 : : Eventually (in particular, for worker-private level?), both
2363 : : 'targetm.goacc.adjust_private_decl' and 'targetm.goacc.expand_var_decl'
2364 : : may need to do things, but that's currently not meant to be addressed, and
2365 : : thus not fully worked out and implemented, and thus untested. Hence,
2366 : : 'assert' what currently is implemented/tested, only. */
2367 : :
2368 : 9453 : if (targetm.goacc.expand_var_decl)
2369 : 0 : gcc_assert (adjusted_vars.is_empty ());
2370 : :
2371 : : /* Make adjustments to gang-private local variables if required by the
2372 : : target, e.g. forcing them into a particular address space. Afterwards,
2373 : : ADDR_EXPR nodes which have adjusted variables as their argument need to
2374 : : be modified in one of two ways:
2375 : :
2376 : : 1. They can be recreated, making a pointer to the variable in the new
2377 : : address space, or
2378 : :
2379 : : 2. The address of the variable in the new address space can be taken,
2380 : : converted to the default (original) address space, and the result of
2381 : : that conversion subsituted in place of the original ADDR_EXPR node.
2382 : :
2383 : : Which of these is done depends on the gimple statement being processed.
2384 : : At present atomic operations and inline asms use (1), and everything else
2385 : : uses (2). At least on AMD GCN, there are atomic operations that work
2386 : : directly in the LDS address space.
2387 : :
2388 : : COMPONENT_REFS, ARRAY_REFS and plain VAR_DECLs are also rewritten to use
2389 : : the new decl, adjusting types of appropriate tree nodes as necessary. */
2390 : :
2391 : 9453 : if (targetm.goacc.adjust_private_decl
2392 : 9453 : && !adjusted_vars.is_empty ())
2393 : : {
2394 : 0 : FOR_ALL_BB_FN (bb, cfun)
2395 : 0 : for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
2396 : 0 : !gsi_end_p (gsi);
2397 : 0 : gsi_next (&gsi))
2398 : : {
2399 : 0 : gimple *stmt = gsi_stmt (gsi);
2400 : 0 : walk_stmt_info wi;
2401 : 0 : var_decl_rewrite_info info;
2402 : :
2403 : 0 : info.avoid_pointer_conversion
2404 : 0 : = (is_gimple_call (stmt)
2405 : 0 : && is_sync_builtin_call (as_a <gcall *> (stmt)))
2406 : 0 : || gimple_code (stmt) == GIMPLE_ASM;
2407 : 0 : info.stmt = stmt;
2408 : 0 : info.modified = false;
2409 : 0 : info.adjusted_vars = &adjusted_vars;
2410 : :
2411 : 0 : memset (&wi, 0, sizeof (wi));
2412 : 0 : wi.info = &info;
2413 : :
2414 : 0 : walk_gimple_op (stmt, oacc_rewrite_var_decl, &wi);
2415 : :
2416 : 0 : if (info.modified)
2417 : 0 : update_stmt (stmt);
2418 : : }
2419 : : }
2420 : :
2421 : 9453 : return 0;
2422 : 9453 : }
2423 : :
2424 : : /* Default launch dimension validator. Force everything to 1. A
2425 : : backend that wants to provide larger dimensions must override this
2426 : : hook. */
2427 : :
2428 : : bool
2429 : 14183 : default_goacc_validate_dims (tree ARG_UNUSED (decl), int *dims,
2430 : : int ARG_UNUSED (fn_level),
2431 : : unsigned ARG_UNUSED (used))
2432 : : {
2433 : 14183 : bool changed = false;
2434 : :
2435 : 56732 : for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++)
2436 : : {
2437 : 42549 : if (dims[ix] != 1)
2438 : : {
2439 : 33947 : dims[ix] = 1;
2440 : 33947 : changed = true;
2441 : : }
2442 : : }
2443 : :
2444 : 14183 : return changed;
2445 : : }
2446 : :
2447 : : /* Default dimension bound is unknown on accelerator and 1 on host. */
2448 : :
2449 : : int
2450 : 0 : default_goacc_dim_limit (int ARG_UNUSED (axis))
2451 : : {
2452 : : #ifdef ACCEL_COMPILER
2453 : : return 0;
2454 : : #else
2455 : 0 : return 1;
2456 : : #endif
2457 : : }
2458 : :
2459 : : namespace {
2460 : :
2461 : : const pass_data pass_data_oacc_loop_designation =
2462 : : {
2463 : : GIMPLE_PASS, /* type */
2464 : : "oaccloops", /* name */
2465 : : OPTGROUP_OMP, /* optinfo_flags */
2466 : : TV_NONE, /* tv_id */
2467 : : PROP_cfg, /* properties_required */
2468 : : 0 /* Possibly PROP_gimple_eomp. */, /* properties_provided */
2469 : : 0, /* properties_destroyed */
2470 : : 0, /* todo_flags_start */
2471 : : TODO_update_ssa | TODO_cleanup_cfg, /* todo_flags_finish */
2472 : : };
2473 : :
2474 : : class pass_oacc_loop_designation : public gimple_opt_pass
2475 : : {
2476 : : public:
2477 : 285617 : pass_oacc_loop_designation (gcc::context *ctxt)
2478 : 571234 : : gimple_opt_pass (pass_data_oacc_loop_designation, ctxt)
2479 : : {}
2480 : :
2481 : : /* opt_pass methods: */
2482 : 1420522 : bool gate (function *) final override { return flag_openacc; };
2483 : :
2484 : 14894 : unsigned int execute (function *) final override
2485 : : {
2486 : 14894 : return execute_oacc_loop_designation ();
2487 : : }
2488 : :
2489 : : }; // class pass_oacc_loop_designation
2490 : :
2491 : : const pass_data pass_data_oacc_device_lower =
2492 : : {
2493 : : GIMPLE_PASS, /* type */
2494 : : "oaccdevlow", /* name */
2495 : : OPTGROUP_OMP, /* optinfo_flags */
2496 : : TV_NONE, /* tv_id */
2497 : : PROP_cfg, /* properties_required */
2498 : : 0 /* Possibly PROP_gimple_eomp. */, /* properties_provided */
2499 : : 0, /* properties_destroyed */
2500 : : 0, /* todo_flags_start */
2501 : : TODO_update_ssa | TODO_cleanup_cfg, /* todo_flags_finish */
2502 : : };
2503 : :
2504 : : class pass_oacc_device_lower : public gimple_opt_pass
2505 : : {
2506 : : public:
2507 : 285617 : pass_oacc_device_lower (gcc::context *ctxt)
2508 : 571234 : : gimple_opt_pass (pass_data_oacc_device_lower, ctxt)
2509 : : {}
2510 : :
2511 : : /* opt_pass methods: */
2512 : 1420452 : bool gate (function *) final override { return flag_openacc; };
2513 : :
2514 : 14824 : unsigned int execute (function *) final override
2515 : : {
2516 : 14824 : return execute_oacc_device_lower ();
2517 : : }
2518 : :
2519 : : }; // class pass_oacc_device_lower
2520 : :
2521 : : } // anon namespace
2522 : :
2523 : : gimple_opt_pass *
2524 : 285617 : make_pass_oacc_loop_designation (gcc::context *ctxt)
2525 : : {
2526 : 285617 : return new pass_oacc_loop_designation (ctxt);
2527 : : }
2528 : :
2529 : : gimple_opt_pass *
2530 : 285617 : make_pass_oacc_device_lower (gcc::context *ctxt)
2531 : : {
2532 : 285617 : return new pass_oacc_device_lower (ctxt);
2533 : : }
2534 : :
2535 : :
2536 : : /* Rewrite GOMP_SIMT_ENTER_ALLOC call given by GSI and remove the preceding
2537 : : GOMP_SIMT_ENTER call identifying the privatized variables, which are
2538 : : turned to structure fields and receive a DECL_VALUE_EXPR accordingly.
2539 : : Set *REGIMPLIFY to true, except if no privatized variables were seen. */
2540 : :
2541 : : static void
2542 : 0 : ompdevlow_adjust_simt_enter (gimple_stmt_iterator *gsi, bool *regimplify)
2543 : : {
2544 : 0 : gimple *alloc_stmt = gsi_stmt (*gsi);
2545 : 0 : tree simtrec = gimple_call_lhs (alloc_stmt);
2546 : 0 : tree simduid = gimple_call_arg (alloc_stmt, 0);
2547 : 0 : gimple *enter_stmt = SSA_NAME_DEF_STMT (simduid);
2548 : 0 : gcc_assert (gimple_call_internal_p (enter_stmt, IFN_GOMP_SIMT_ENTER));
2549 : 0 : tree rectype = lang_hooks.types.make_type (RECORD_TYPE);
2550 : 0 : TYPE_ARTIFICIAL (rectype) = TYPE_NAMELESS (rectype) = 1;
2551 : 0 : TREE_ADDRESSABLE (rectype) = 1;
2552 : 0 : TREE_TYPE (simtrec) = build_pointer_type (rectype);
2553 : 0 : for (unsigned i = 1; i < gimple_call_num_args (enter_stmt); i++)
2554 : : {
2555 : 0 : tree *argp = gimple_call_arg_ptr (enter_stmt, i);
2556 : 0 : if (*argp == null_pointer_node)
2557 : 0 : continue;
2558 : 0 : gcc_assert (TREE_CODE (*argp) == ADDR_EXPR
2559 : : && VAR_P (TREE_OPERAND (*argp, 0)));
2560 : 0 : tree var = TREE_OPERAND (*argp, 0);
2561 : :
2562 : 0 : tree field = build_decl (DECL_SOURCE_LOCATION (var), FIELD_DECL,
2563 : 0 : DECL_NAME (var), TREE_TYPE (var));
2564 : 0 : SET_DECL_ALIGN (field, DECL_ALIGN (var));
2565 : 0 : DECL_USER_ALIGN (field) = DECL_USER_ALIGN (var);
2566 : 0 : TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (var);
2567 : :
2568 : 0 : insert_field_into_struct (rectype, field);
2569 : :
2570 : 0 : tree t = build_simple_mem_ref (simtrec);
2571 : 0 : t = build3 (COMPONENT_REF, TREE_TYPE (var), t, field, NULL);
2572 : 0 : TREE_THIS_VOLATILE (t) = TREE_THIS_VOLATILE (var);
2573 : 0 : SET_DECL_VALUE_EXPR (var, t);
2574 : 0 : DECL_HAS_VALUE_EXPR_P (var) = 1;
2575 : 0 : *regimplify = true;
2576 : : }
2577 : 0 : layout_type (rectype);
2578 : 0 : tree size = TYPE_SIZE_UNIT (rectype);
2579 : 0 : tree align = build_int_cst (TREE_TYPE (size), TYPE_ALIGN_UNIT (rectype));
2580 : :
2581 : 0 : alloc_stmt
2582 : 0 : = gimple_build_call_internal (IFN_GOMP_SIMT_ENTER_ALLOC, 2, size, align);
2583 : 0 : gimple_call_set_lhs (alloc_stmt, simtrec);
2584 : 0 : gsi_replace (gsi, alloc_stmt, false);
2585 : 0 : gimple_stmt_iterator enter_gsi = gsi_for_stmt (enter_stmt);
2586 : 0 : enter_stmt = gimple_build_assign (simduid, gimple_call_arg (enter_stmt, 0));
2587 : 0 : gsi_replace (&enter_gsi, enter_stmt, false);
2588 : :
2589 : 0 : use_operand_p use;
2590 : 0 : gimple *exit_stmt;
2591 : 0 : if (single_imm_use (simtrec, &use, &exit_stmt))
2592 : : {
2593 : 0 : gcc_assert (gimple_call_internal_p (exit_stmt, IFN_GOMP_SIMT_EXIT));
2594 : 0 : gimple_stmt_iterator exit_gsi = gsi_for_stmt (exit_stmt);
2595 : 0 : tree clobber = build_clobber (rectype);
2596 : 0 : exit_stmt = gimple_build_assign (build_simple_mem_ref (simtrec), clobber);
2597 : 0 : gsi_insert_before (&exit_gsi, exit_stmt, GSI_SAME_STMT);
2598 : : }
2599 : : else
2600 : 0 : gcc_checking_assert (has_zero_uses (simtrec));
2601 : 0 : }
2602 : :
2603 : : /* Callback for walk_gimple_stmt used to scan for SIMT-privatized variables. */
2604 : :
2605 : : static tree
2606 : 0 : find_simtpriv_var_op (tree *tp, int *walk_subtrees, void *)
2607 : : {
2608 : 0 : tree t = *tp;
2609 : :
2610 : 0 : if (VAR_P (t)
2611 : 0 : && DECL_HAS_VALUE_EXPR_P (t)
2612 : 0 : && lookup_attribute ("omp simt private", DECL_ATTRIBUTES (t)))
2613 : : {
2614 : 0 : *walk_subtrees = 0;
2615 : 0 : return t;
2616 : : }
2617 : : return NULL_TREE;
2618 : : }
2619 : :
2620 : : /* Cleanup uses of SIMT placeholder internal functions: on non-SIMT targets,
2621 : : VF is 1 and LANE is 0; on SIMT targets, VF is folded to a constant, and
2622 : : LANE is kept to be expanded to RTL later on. Also cleanup all other SIMT
2623 : : internal functions on non-SIMT targets, and likewise some SIMD internal
2624 : : functions on SIMT targets. */
2625 : :
2626 : : static unsigned int
2627 : 19255 : execute_omp_device_lower ()
2628 : : {
2629 : 19255 : int vf = targetm.simt.vf ? targetm.simt.vf () : 1;
2630 : 19255 : bool regimplify = false;
2631 : 19255 : basic_block bb;
2632 : 19255 : gimple_stmt_iterator gsi;
2633 : 19255 : bool calls_declare_variant_alt
2634 : 19255 : = cgraph_node::get (cfun->decl)->calls_declare_variant_alt;
2635 : : #ifdef ACCEL_COMPILER
2636 : : bool omp_redirect_indirect_calls = vec_safe_length (offload_ind_funcs) > 0;
2637 : : tree map_ptr_fn
2638 : : = builtin_decl_explicit (BUILT_IN_GOMP_TARGET_MAP_INDIRECT_PTR);
2639 : : #endif
2640 : 49175 : FOR_EACH_BB_FN (bb, cfun)
2641 : 208016 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2642 : : {
2643 : 148176 : gimple *stmt = gsi_stmt (gsi);
2644 : 148176 : if (!is_gimple_call (stmt))
2645 : 131507 : continue;
2646 : 16669 : if (!gimple_call_internal_p (stmt))
2647 : : {
2648 : 16530 : if (calls_declare_variant_alt)
2649 : 163 : if (tree fndecl = gimple_call_fndecl (stmt))
2650 : : {
2651 : 163 : tree new_fndecl = omp_resolve_declare_variant (fndecl);
2652 : 163 : if (new_fndecl != fndecl)
2653 : : {
2654 : 126 : gimple_call_set_fndecl (stmt, new_fndecl);
2655 : 126 : update_stmt (stmt);
2656 : : }
2657 : : }
2658 : : #ifdef ACCEL_COMPILER
2659 : : if (omp_redirect_indirect_calls
2660 : : && gimple_call_fndecl (stmt) == NULL_TREE)
2661 : : {
2662 : : gcall *orig_call = dyn_cast <gcall *> (stmt);
2663 : : tree call_fn = gimple_call_fn (stmt);
2664 : : tree fn_ty = TREE_TYPE (call_fn);
2665 : :
2666 : : if (TREE_CODE (call_fn) == OBJ_TYPE_REF)
2667 : : {
2668 : : tree obj_ref = create_tmp_reg (TREE_TYPE (call_fn),
2669 : : ".ind_fn_objref");
2670 : : gimple *gassign = gimple_build_assign (obj_ref, call_fn);
2671 : : gsi_insert_before (&gsi, gassign, GSI_SAME_STMT);
2672 : : call_fn = obj_ref;
2673 : : }
2674 : : tree mapped_fn = create_tmp_reg (fn_ty, ".ind_fn");
2675 : : gimple *gcall =
2676 : : gimple_build_call (map_ptr_fn, 1, call_fn);
2677 : : gimple_set_location (gcall, gimple_location (stmt));
2678 : : gimple_call_set_lhs (gcall, mapped_fn);
2679 : : gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
2680 : :
2681 : : gimple_call_set_fn (orig_call, mapped_fn);
2682 : : update_stmt (orig_call);
2683 : : }
2684 : : #endif
2685 : 16530 : continue;
2686 : 16530 : }
2687 : 139 : tree lhs = gimple_call_lhs (stmt), rhs = NULL_TREE;
2688 : 139 : tree type = lhs ? TREE_TYPE (lhs) : integer_type_node;
2689 : 139 : switch (gimple_call_internal_fn (stmt))
2690 : : {
2691 : 0 : case IFN_GOMP_TARGET_REV:
2692 : 0 : {
2693 : : #ifndef ACCEL_COMPILER
2694 : 0 : gimple_stmt_iterator gsi2 = gsi;
2695 : 0 : gsi_next (&gsi2);
2696 : 0 : gcc_assert (!gsi_end_p (gsi2));
2697 : 0 : gcc_assert (gimple_call_builtin_p (gsi_stmt (gsi2),
2698 : : BUILT_IN_GOMP_TARGET));
2699 : 0 : tree old_decl
2700 : 0 : = TREE_OPERAND (gimple_call_arg (gsi_stmt (gsi2), 1), 0);
2701 : 0 : tree new_decl = gimple_call_arg (gsi_stmt (gsi), 0);
2702 : 0 : gimple_call_set_arg (gsi_stmt (gsi2), 1, new_decl);
2703 : 0 : update_stmt (gsi_stmt (gsi2));
2704 : 0 : new_decl = TREE_OPERAND (new_decl, 0);
2705 : 0 : unsigned i;
2706 : 0 : unsigned num_funcs = vec_safe_length (offload_funcs);
2707 : 0 : for (i = 0; i < num_funcs; i++)
2708 : : {
2709 : 0 : if ((*offload_funcs)[i] == old_decl)
2710 : : {
2711 : 0 : (*offload_funcs)[i] = new_decl;
2712 : 0 : break;
2713 : : }
2714 : 0 : else if ((*offload_funcs)[i] == new_decl)
2715 : : break; /* This can happen due to inlining. */
2716 : : }
2717 : 0 : gcc_assert (i < num_funcs);
2718 : : #else
2719 : : tree old_decl = TREE_OPERAND (gimple_call_arg (gsi_stmt (gsi), 0),
2720 : : 0);
2721 : : #endif
2722 : : /* FIXME: Find a way to actually prevent outputting the empty-body
2723 : : old_decl as debug symbol + function in the assembly file. */
2724 : 0 : cgraph_node *node = cgraph_node::get (old_decl);
2725 : 0 : node->address_taken = false;
2726 : 0 : node->need_lto_streaming = false;
2727 : 0 : node->offloadable = false;
2728 : :
2729 : 0 : unlink_stmt_vdef (stmt);
2730 : : }
2731 : 0 : break;
2732 : 0 : case IFN_GOMP_USE_SIMT:
2733 : 0 : rhs = vf == 1 ? integer_zero_node : integer_one_node;
2734 : : break;
2735 : 0 : case IFN_GOMP_SIMT_ENTER:
2736 : 0 : rhs = vf == 1 ? gimple_call_arg (stmt, 0) : NULL_TREE;
2737 : 0 : goto simtreg_enter_exit;
2738 : 0 : case IFN_GOMP_SIMT_ENTER_ALLOC:
2739 : 0 : if (vf != 1)
2740 : 0 : ompdevlow_adjust_simt_enter (&gsi, ®implify);
2741 : 0 : rhs = vf == 1 ? null_pointer_node : NULL_TREE;
2742 : 0 : goto simtreg_enter_exit;
2743 : 0 : case IFN_GOMP_SIMT_EXIT:
2744 : 0 : simtreg_enter_exit:
2745 : 0 : if (vf != 1)
2746 : 0 : continue;
2747 : 0 : unlink_stmt_vdef (stmt);
2748 : 0 : break;
2749 : 0 : case IFN_GOMP_SIMT_LANE:
2750 : 0 : case IFN_GOMP_SIMT_LAST_LANE:
2751 : 0 : rhs = vf == 1 ? build_zero_cst (type) : NULL_TREE;
2752 : : break;
2753 : 0 : case IFN_GOMP_SIMT_VF:
2754 : 0 : rhs = build_int_cst (type, vf);
2755 : 0 : break;
2756 : 0 : case IFN_GOMP_SIMT_ORDERED_PRED:
2757 : 0 : rhs = vf == 1 ? integer_zero_node : NULL_TREE;
2758 : 0 : if (rhs || !lhs)
2759 : 0 : unlink_stmt_vdef (stmt);
2760 : : break;
2761 : 0 : case IFN_GOMP_SIMT_VOTE_ANY:
2762 : 0 : case IFN_GOMP_SIMT_XCHG_BFLY:
2763 : 0 : case IFN_GOMP_SIMT_XCHG_IDX:
2764 : 0 : rhs = vf == 1 ? gimple_call_arg (stmt, 0) : NULL_TREE;
2765 : : break;
2766 : 7 : case IFN_GOMP_SIMD_LANE:
2767 : 7 : case IFN_GOMP_SIMD_LAST_LANE:
2768 : 7 : rhs = vf != 1 ? build_zero_cst (type) : NULL_TREE;
2769 : : break;
2770 : 0 : case IFN_GOMP_SIMD_VF:
2771 : 0 : rhs = vf != 1 ? build_one_cst (type) : NULL_TREE;
2772 : : break;
2773 : 132 : default:
2774 : 132 : continue;
2775 : 132 : }
2776 : 7 : if (lhs && !rhs)
2777 : 7 : continue;
2778 : 0 : stmt = lhs ? gimple_build_assign (lhs, rhs) : gimple_build_nop ();
2779 : 0 : gsi_replace (&gsi, stmt, false);
2780 : : }
2781 : 19255 : if (regimplify)
2782 : 0 : FOR_EACH_BB_REVERSE_FN (bb, cfun)
2783 : 0 : for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
2784 : 0 : if (walk_gimple_stmt (&gsi, NULL, find_simtpriv_var_op, NULL))
2785 : : {
2786 : 0 : if (gimple_clobber_p (gsi_stmt (gsi)))
2787 : 0 : gsi_remove (&gsi, true);
2788 : : else
2789 : 0 : gimple_regimplify_operands (gsi_stmt (gsi), &gsi);
2790 : : }
2791 : 19255 : if (vf != 1)
2792 : 0 : cfun->has_force_vectorize_loops = false;
2793 : 19255 : return 0;
2794 : : }
2795 : :
2796 : : namespace {
2797 : :
2798 : : const pass_data pass_data_omp_device_lower =
2799 : : {
2800 : : GIMPLE_PASS, /* type */
2801 : : "ompdevlow", /* name */
2802 : : OPTGROUP_OMP, /* optinfo_flags */
2803 : : TV_NONE, /* tv_id */
2804 : : PROP_cfg, /* properties_required */
2805 : : PROP_gimple_lomp_dev, /* properties_provided */
2806 : : 0, /* properties_destroyed */
2807 : : 0, /* todo_flags_start */
2808 : : TODO_update_ssa, /* todo_flags_finish */
2809 : : };
2810 : :
2811 : : class pass_omp_device_lower : public gimple_opt_pass
2812 : : {
2813 : : public:
2814 : 285617 : pass_omp_device_lower (gcc::context *ctxt)
2815 : 571234 : : gimple_opt_pass (pass_data_omp_device_lower, ctxt)
2816 : : {}
2817 : :
2818 : : /* opt_pass methods: */
2819 : 1420452 : bool gate (function *fun) final override
2820 : : {
2821 : : #ifdef ACCEL_COMPILER
2822 : : bool offload_ind_funcs_p = vec_safe_length (offload_ind_funcs) > 0;
2823 : : #else
2824 : 1420452 : bool offload_ind_funcs_p = false;
2825 : : #endif
2826 : 1420452 : return (!(fun->curr_properties & PROP_gimple_lomp_dev)
2827 : 1420452 : || (flag_openmp
2828 : 59601 : && (cgraph_node::get (fun->decl)->calls_declare_variant_alt
2829 : 1420452 : || offload_ind_funcs_p)));
2830 : : }
2831 : 19255 : unsigned int execute (function *) final override
2832 : : {
2833 : 19255 : return execute_omp_device_lower ();
2834 : : }
2835 : :
2836 : : }; // class pass_expand_omp_ssa
2837 : :
2838 : : } // anon namespace
2839 : :
2840 : : gimple_opt_pass *
2841 : 285617 : make_pass_omp_device_lower (gcc::context *ctxt)
2842 : : {
2843 : 285617 : return new pass_omp_device_lower (ctxt);
2844 : : }
2845 : :
2846 : : /* "omp declare target link" handling pass. */
2847 : :
2848 : : namespace {
2849 : :
2850 : : const pass_data pass_data_omp_target_link =
2851 : : {
2852 : : GIMPLE_PASS, /* type */
2853 : : "omptargetlink", /* name */
2854 : : OPTGROUP_OMP, /* optinfo_flags */
2855 : : TV_NONE, /* tv_id */
2856 : : PROP_ssa, /* properties_required */
2857 : : 0, /* properties_provided */
2858 : : 0, /* properties_destroyed */
2859 : : 0, /* todo_flags_start */
2860 : : TODO_update_ssa, /* todo_flags_finish */
2861 : : };
2862 : :
2863 : : class pass_omp_target_link : public gimple_opt_pass
2864 : : {
2865 : : public:
2866 : 285617 : pass_omp_target_link (gcc::context *ctxt)
2867 : 571234 : : gimple_opt_pass (pass_data_omp_target_link, ctxt)
2868 : : {}
2869 : :
2870 : : /* opt_pass methods: */
2871 : 1420452 : bool gate (function *fun) final override
2872 : : {
2873 : : #ifdef ACCEL_COMPILER
2874 : : return offloading_function_p (fun->decl);
2875 : : #else
2876 : 1420452 : (void) fun;
2877 : 1420452 : return false;
2878 : : #endif
2879 : : }
2880 : :
2881 : : unsigned execute (function *) final override;
2882 : : };
2883 : :
2884 : : /* Callback for walk_gimple_stmt used to scan for link var operands. */
2885 : :
2886 : : static tree
2887 : 0 : find_link_var_op (tree *tp, int *walk_subtrees, void *)
2888 : : {
2889 : 0 : tree t = *tp;
2890 : :
2891 : 0 : if (VAR_P (t)
2892 : 0 : && DECL_HAS_VALUE_EXPR_P (t)
2893 : 0 : && is_global_var (t)
2894 : 0 : && lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (t)))
2895 : : {
2896 : 0 : *walk_subtrees = 0;
2897 : 0 : return t;
2898 : : }
2899 : :
2900 : : return NULL_TREE;
2901 : : }
2902 : :
2903 : : unsigned
2904 : 0 : pass_omp_target_link::execute (function *fun)
2905 : : {
2906 : 0 : basic_block bb;
2907 : 0 : FOR_EACH_BB_FN (bb, fun)
2908 : : {
2909 : 0 : gimple_stmt_iterator gsi;
2910 : 0 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2911 : : {
2912 : 0 : if (gimple_call_builtin_p (gsi_stmt (gsi), BUILT_IN_GOMP_TARGET))
2913 : : {
2914 : 0 : tree dev = gimple_call_arg (gsi_stmt (gsi), 0);
2915 : 0 : tree fn = gimple_call_arg (gsi_stmt (gsi), 1);
2916 : 0 : if (POINTER_TYPE_P (TREE_TYPE (fn)))
2917 : 0 : fn = TREE_OPERAND (fn, 0);
2918 : 0 : if (TREE_CODE (dev) == INTEGER_CST
2919 : 0 : && wi::to_wide (dev) == GOMP_DEVICE_HOST_FALLBACK
2920 : 0 : && lookup_attribute ("omp target device_ancestor_nohost",
2921 : 0 : DECL_ATTRIBUTES (fn)) != NULL_TREE)
2922 : 0 : continue; /* ancestor:1 */
2923 : : /* Nullify the second argument of __builtin_GOMP_target_ext. */
2924 : 0 : gimple_call_set_arg (gsi_stmt (gsi), 1, null_pointer_node);
2925 : 0 : update_stmt (gsi_stmt (gsi));
2926 : : }
2927 : 0 : if (walk_gimple_stmt (&gsi, NULL, find_link_var_op, NULL))
2928 : 0 : gimple_regimplify_operands (gsi_stmt (gsi), &gsi);
2929 : : }
2930 : : }
2931 : :
2932 : 0 : return 0;
2933 : : }
2934 : :
2935 : : } // anon namespace
2936 : :
2937 : : gimple_opt_pass *
2938 : 285617 : make_pass_omp_target_link (gcc::context *ctxt)
2939 : : {
2940 : 285617 : return new pass_omp_target_link (ctxt);
2941 : : }
|