1 /* Copyright (C) 2017-2019 Free Software Foundation, Inc.
2 
3    This file is part of GCC.
4 
5    GCC is free software; you can redistribute it and/or modify it under
6    the terms of the GNU General Public License as published by the Free
7    Software Foundation; either version 3, or (at your option) any later
8    version.
9 
10    GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11    WARRANTY; without even the implied warranty of MERCHANTABILITY or
12    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13    for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with GCC; see the file COPYING3.  If not see
17    <http://www.gnu.org/licenses/>.  */
18 
19 /* {{{ Includes.  */
20 
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "tree-pass.h"
29 #include "gimple-iterator.h"
30 #include "cfghooks.h"
31 #include "cfgloop.h"
32 #include "tm_p.h"
33 #include "stringpool.h"
34 #include "fold-const.h"
35 #include "varasm.h"
36 #include "omp-low.h"
37 #include "omp-general.h"
38 #include "internal-fn.h"
39 #include "tree-vrp.h"
40 #include "tree-ssanames.h"
41 #include "tree-ssa-operands.h"
42 #include "gimplify.h"
43 #include "tree-phinodes.h"
44 #include "cgraph.h"
45 #include "targhooks.h"
46 #include "langhooks-def.h"
47 
48 /* }}}  */
49 /* {{{ OMP GCN pass.
50 
51    This pass is intended to make any GCN-specfic transformations to OpenMP
52    target regions.
53 
54    At present, its only purpose is to convert some "omp" built-in functions
55    to use closer-to-the-metal "gcn" built-in functions.  */
56 
57 unsigned int
execute_omp_gcn(void)58 execute_omp_gcn (void)
59 {
60   tree thr_num_tree = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
61   tree thr_num_id = DECL_NAME (thr_num_tree);
62   tree team_num_tree = builtin_decl_explicit (BUILT_IN_OMP_GET_TEAM_NUM);
63   tree team_num_id = DECL_NAME (team_num_tree);
64   basic_block bb;
65   gimple_stmt_iterator gsi;
66   unsigned int todo = 0;
67 
68   FOR_EACH_BB_FN (bb, cfun)
69     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
70     {
71       gimple *call = gsi_stmt (gsi);
72       tree decl;
73 
74       if (is_gimple_call (call) && (decl = gimple_call_fndecl (call)))
75 	{
76 	  tree decl_id = DECL_NAME (decl);
77 	  tree lhs = gimple_get_lhs (call);
78 
79 	  if (decl_id == thr_num_id)
80 	    {
81 	      if (dump_file && (dump_flags & TDF_DETAILS))
82 		fprintf (dump_file,
83 			 "Replace '%s' with __builtin_gcn_dim_pos.\n",
84 			 IDENTIFIER_POINTER (decl_id));
85 
86 	      /* Transform this:
87 	         lhs = __builtin_omp_get_thread_num ()
88 	         to this:
89 	         lhs = __builtin_gcn_dim_pos (1)  */
90 	      tree fn = targetm.builtin_decl (GCN_BUILTIN_OMP_DIM_POS, 0);
91 	      tree fnarg = build_int_cst (unsigned_type_node, 1);
92 	      gimple *stmt = gimple_build_call (fn, 1, fnarg);
93 	      gimple_call_set_lhs (stmt, lhs);
94 	      gsi_replace (&gsi, stmt, true);
95 
96 	      todo |= TODO_update_ssa;
97 	    }
98 	  else if (decl_id == team_num_id)
99 	    {
100 	      if (dump_file && (dump_flags & TDF_DETAILS))
101 		fprintf (dump_file,
102 			 "Replace '%s' with __builtin_gcn_dim_pos.\n",
103 			 IDENTIFIER_POINTER (decl_id));
104 
105 	      /* Transform this:
106 	         lhs = __builtin_omp_get_team_num ()
107 	         to this:
108 	         lhs = __builtin_gcn_dim_pos (0)  */
109 	      tree fn = targetm.builtin_decl (GCN_BUILTIN_OMP_DIM_POS, 0);
110 	      tree fnarg = build_zero_cst (unsigned_type_node);
111 	      gimple *stmt = gimple_build_call (fn, 1, fnarg);
112 	      gimple_call_set_lhs (stmt, lhs);
113 	      gsi_replace (&gsi, stmt, true);
114 
115 	      todo |= TODO_update_ssa;
116 	    }
117 	}
118     }
119 
120   return todo;
121 }
122 
123 namespace
124 {
125 
126   const pass_data pass_data_omp_gcn = {
127     GIMPLE_PASS,
128     "omp_gcn",			/* name */
129     OPTGROUP_NONE,		/* optinfo_flags */
130     TV_NONE,			/* tv_id */
131     0,				/* properties_required */
132     0,				/* properties_provided */
133     0,				/* properties_destroyed */
134     0,				/* todo_flags_start */
135     TODO_df_finish,		/* todo_flags_finish */
136   };
137 
138   class pass_omp_gcn : public gimple_opt_pass
139   {
140   public:
pass_omp_gcn(gcc::context * ctxt)141     pass_omp_gcn (gcc::context *ctxt)
142       : gimple_opt_pass (pass_data_omp_gcn, ctxt)
143     {
144     }
145 
146     /* opt_pass methods: */
gate(function *)147     virtual bool gate (function *)
148     {
149       return flag_openmp;
150     }
151 
execute(function *)152     virtual unsigned int execute (function *)
153     {
154       return execute_omp_gcn ();
155     }
156 
157   }; /* class pass_omp_gcn.  */
158 
159 } /* anon namespace.  */
160 
161 gimple_opt_pass *
make_pass_omp_gcn(gcc::context * ctxt)162 make_pass_omp_gcn (gcc::context *ctxt)
163 {
164   return new pass_omp_gcn (ctxt);
165 }
166 
167 /* }}}  */
168 /* {{{ OpenACC reductions.  */
169 
170 /* Global lock variable, needed for 128bit worker & gang reductions.  */
171 
172 static GTY(()) tree global_lock_var;
173 
174 /* Lazily generate the global_lock_var decl and return its address.  */
175 
176 static tree
gcn_global_lock_addr()177 gcn_global_lock_addr ()
178 {
179   tree v = global_lock_var;
180 
181   if (!v)
182     {
183       tree name = get_identifier ("__reduction_lock");
184       tree type = build_qualified_type (unsigned_type_node,
185 					TYPE_QUAL_VOLATILE);
186       v = build_decl (BUILTINS_LOCATION, VAR_DECL, name, type);
187       global_lock_var = v;
188       DECL_ARTIFICIAL (v) = 1;
189       DECL_EXTERNAL (v) = 1;
190       TREE_STATIC (v) = 1;
191       TREE_PUBLIC (v) = 1;
192       TREE_USED (v) = 1;
193       mark_addressable (v);
194       mark_decl_referenced (v);
195     }
196 
197   return build_fold_addr_expr (v);
198 }
199 
200 /* Helper function for gcn_reduction_update.
201 
202    Insert code to locklessly update *PTR with *PTR OP VAR just before
203    GSI.  We use a lockless scheme for nearly all case, which looks
204    like:
205      actual = initval (OP);
206      do {
207        guess = actual;
208        write = guess OP myval;
209        actual = cmp&swap (ptr, guess, write)
210      } while (actual bit-different-to guess);
211    return write;
212 
213    This relies on a cmp&swap instruction, which is available for 32- and
214    64-bit types.  Larger types must use a locking scheme.  */
215 
216 static tree
gcn_lockless_update(location_t loc,gimple_stmt_iterator * gsi,tree ptr,tree var,tree_code op)217 gcn_lockless_update (location_t loc, gimple_stmt_iterator *gsi,
218 		     tree ptr, tree var, tree_code op)
219 {
220   unsigned fn = GCN_BUILTIN_CMP_SWAP;
221   tree_code code = NOP_EXPR;
222   tree arg_type = unsigned_type_node;
223   tree var_type = TREE_TYPE (var);
224 
225   if (TREE_CODE (var_type) == COMPLEX_TYPE
226       || TREE_CODE (var_type) == REAL_TYPE)
227     code = VIEW_CONVERT_EXPR;
228 
229   if (TYPE_SIZE (var_type) == TYPE_SIZE (long_long_unsigned_type_node))
230     {
231       arg_type = long_long_unsigned_type_node;
232       fn = GCN_BUILTIN_CMP_SWAPLL;
233     }
234 
235   tree swap_fn = gcn_builtin_decl (fn, true);
236 
237   gimple_seq init_seq = NULL;
238   tree init_var = make_ssa_name (arg_type);
239   tree init_expr = omp_reduction_init_op (loc, op, var_type);
240   init_expr = fold_build1 (code, arg_type, init_expr);
241   gimplify_assign (init_var, init_expr, &init_seq);
242   gimple *init_end = gimple_seq_last (init_seq);
243 
244   gsi_insert_seq_before (gsi, init_seq, GSI_SAME_STMT);
245 
246   /* Split the block just after the init stmts.  */
247   basic_block pre_bb = gsi_bb (*gsi);
248   edge pre_edge = split_block (pre_bb, init_end);
249   basic_block loop_bb = pre_edge->dest;
250   pre_bb = pre_edge->src;
251   /* Reset the iterator.  */
252   *gsi = gsi_for_stmt (gsi_stmt (*gsi));
253 
254   tree expect_var = make_ssa_name (arg_type);
255   tree actual_var = make_ssa_name (arg_type);
256   tree write_var = make_ssa_name (arg_type);
257 
258   /* Build and insert the reduction calculation.  */
259   gimple_seq red_seq = NULL;
260   tree write_expr = fold_build1 (code, var_type, expect_var);
261   write_expr = fold_build2 (op, var_type, write_expr, var);
262   write_expr = fold_build1 (code, arg_type, write_expr);
263   gimplify_assign (write_var, write_expr, &red_seq);
264 
265   gsi_insert_seq_before (gsi, red_seq, GSI_SAME_STMT);
266 
267   /* Build & insert the cmp&swap sequence.  */
268   gimple_seq latch_seq = NULL;
269   tree swap_expr = build_call_expr_loc (loc, swap_fn, 3,
270 					ptr, expect_var, write_var);
271   gimplify_assign (actual_var, swap_expr, &latch_seq);
272 
273   gcond *cond = gimple_build_cond (EQ_EXPR, actual_var, expect_var,
274 				   NULL_TREE, NULL_TREE);
275   gimple_seq_add_stmt (&latch_seq, cond);
276 
277   gimple *latch_end = gimple_seq_last (latch_seq);
278   gsi_insert_seq_before (gsi, latch_seq, GSI_SAME_STMT);
279 
280   /* Split the block just after the latch stmts.  */
281   edge post_edge = split_block (loop_bb, latch_end);
282   basic_block post_bb = post_edge->dest;
283   loop_bb = post_edge->src;
284   *gsi = gsi_for_stmt (gsi_stmt (*gsi));
285 
286   post_edge->flags ^= EDGE_TRUE_VALUE | EDGE_FALLTHRU;
287   /* post_edge->probability = profile_probability::even ();  */
288   edge loop_edge = make_edge (loop_bb, loop_bb, EDGE_FALSE_VALUE);
289   /* loop_edge->probability = profile_probability::even ();  */
290   set_immediate_dominator (CDI_DOMINATORS, loop_bb, pre_bb);
291   set_immediate_dominator (CDI_DOMINATORS, post_bb, loop_bb);
292 
293   gphi *phi = create_phi_node (expect_var, loop_bb);
294   add_phi_arg (phi, init_var, pre_edge, loc);
295   add_phi_arg (phi, actual_var, loop_edge, loc);
296 
297   loop *loop = alloc_loop ();
298   loop->header = loop_bb;
299   loop->latch = loop_bb;
300   add_loop (loop, loop_bb->loop_father);
301 
302   return fold_build1 (code, var_type, write_var);
303 }
304 
305 /* Helper function for gcn_reduction_update.
306 
307    Insert code to lockfully update *PTR with *PTR OP VAR just before
308    GSI.  This is necessary for types larger than 64 bits, where there
309    is no cmp&swap instruction to implement a lockless scheme.  We use
310    a lock variable in global memory.
311 
312    while (cmp&swap (&lock_var, 0, 1))
313      continue;
314    T accum = *ptr;
315    accum = accum OP var;
316    *ptr = accum;
317    cmp&swap (&lock_var, 1, 0);
318    return accum;
319 
320    A lock in global memory is necessary to force execution engine
321    descheduling and avoid resource starvation that can occur if the
322    lock is in shared memory.  */
323 
324 static tree
gcn_lockfull_update(location_t loc,gimple_stmt_iterator * gsi,tree ptr,tree var,tree_code op)325 gcn_lockfull_update (location_t loc, gimple_stmt_iterator *gsi,
326 		     tree ptr, tree var, tree_code op)
327 {
328   tree var_type = TREE_TYPE (var);
329   tree swap_fn = gcn_builtin_decl (GCN_BUILTIN_CMP_SWAP, true);
330   tree uns_unlocked = build_int_cst (unsigned_type_node, 0);
331   tree uns_locked = build_int_cst (unsigned_type_node, 1);
332 
333   /* Split the block just before the gsi.  Insert a gimple nop to make
334      this easier.  */
335   gimple *nop = gimple_build_nop ();
336   gsi_insert_before (gsi, nop, GSI_SAME_STMT);
337   basic_block entry_bb = gsi_bb (*gsi);
338   edge entry_edge = split_block (entry_bb, nop);
339   basic_block lock_bb = entry_edge->dest;
340   /* Reset the iterator.  */
341   *gsi = gsi_for_stmt (gsi_stmt (*gsi));
342 
343   /* Build and insert the locking sequence.  */
344   gimple_seq lock_seq = NULL;
345   tree lock_var = make_ssa_name (unsigned_type_node);
346   tree lock_expr = gcn_global_lock_addr ();
347   lock_expr = build_call_expr_loc (loc, swap_fn, 3, lock_expr,
348 				   uns_unlocked, uns_locked);
349   gimplify_assign (lock_var, lock_expr, &lock_seq);
350   gcond *cond = gimple_build_cond (EQ_EXPR, lock_var, uns_unlocked,
351 				   NULL_TREE, NULL_TREE);
352   gimple_seq_add_stmt (&lock_seq, cond);
353   gimple *lock_end = gimple_seq_last (lock_seq);
354   gsi_insert_seq_before (gsi, lock_seq, GSI_SAME_STMT);
355 
356   /* Split the block just after the lock sequence.  */
357   edge locked_edge = split_block (lock_bb, lock_end);
358   basic_block update_bb = locked_edge->dest;
359   lock_bb = locked_edge->src;
360   *gsi = gsi_for_stmt (gsi_stmt (*gsi));
361 
362   /* Create the lock loop.  */
363   locked_edge->flags ^= EDGE_TRUE_VALUE | EDGE_FALLTHRU;
364   locked_edge->probability = profile_probability::even ();
365   edge loop_edge = make_edge (lock_bb, lock_bb, EDGE_FALSE_VALUE);
366   loop_edge->probability = profile_probability::even ();
367   set_immediate_dominator (CDI_DOMINATORS, lock_bb, entry_bb);
368   set_immediate_dominator (CDI_DOMINATORS, update_bb, lock_bb);
369 
370   /* Create the loop structure.  */
371   loop *lock_loop = alloc_loop ();
372   lock_loop->header = lock_bb;
373   lock_loop->latch = lock_bb;
374   lock_loop->nb_iterations_estimate = 1;
375   lock_loop->any_estimate = true;
376   add_loop (lock_loop, entry_bb->loop_father);
377 
378   /* Build and insert the reduction calculation.  */
379   gimple_seq red_seq = NULL;
380   tree acc_in = make_ssa_name (var_type);
381   tree ref_in = build_simple_mem_ref (ptr);
382   TREE_THIS_VOLATILE (ref_in) = 1;
383   gimplify_assign (acc_in, ref_in, &red_seq);
384 
385   tree acc_out = make_ssa_name (var_type);
386   tree update_expr = fold_build2 (op, var_type, ref_in, var);
387   gimplify_assign (acc_out, update_expr, &red_seq);
388 
389   tree ref_out = build_simple_mem_ref (ptr);
390   TREE_THIS_VOLATILE (ref_out) = 1;
391   gimplify_assign (ref_out, acc_out, &red_seq);
392 
393   gsi_insert_seq_before (gsi, red_seq, GSI_SAME_STMT);
394 
395   /* Build & insert the unlock sequence.  */
396   gimple_seq unlock_seq = NULL;
397   tree unlock_expr = gcn_global_lock_addr ();
398   unlock_expr = build_call_expr_loc (loc, swap_fn, 3, unlock_expr,
399 				     uns_locked, uns_unlocked);
400   gimplify_and_add (unlock_expr, &unlock_seq);
401   gsi_insert_seq_before (gsi, unlock_seq, GSI_SAME_STMT);
402 
403   return acc_out;
404 }
405 
406 /* Emit a sequence to update a reduction accumulator at *PTR with the
407    value held in VAR using operator OP.  Return the updated value.
408 
409    TODO: optimize for atomic ops and independent complex ops.  */
410 
411 static tree
gcn_reduction_update(location_t loc,gimple_stmt_iterator * gsi,tree ptr,tree var,tree_code op)412 gcn_reduction_update (location_t loc, gimple_stmt_iterator *gsi,
413 		      tree ptr, tree var, tree_code op)
414 {
415   tree type = TREE_TYPE (var);
416   tree size = TYPE_SIZE (type);
417 
418   if (size == TYPE_SIZE (unsigned_type_node)
419       || size == TYPE_SIZE (long_long_unsigned_type_node))
420     return gcn_lockless_update (loc, gsi, ptr, var, op);
421   else
422     return gcn_lockfull_update (loc, gsi, ptr, var, op);
423 }
424 
425 /* Return a temporary variable decl to use for an OpenACC worker reduction.  */
426 
427 static tree
gcn_goacc_get_worker_red_decl(tree type,unsigned offset)428 gcn_goacc_get_worker_red_decl (tree type, unsigned offset)
429 {
430   machine_function *machfun = cfun->machine;
431   tree existing_decl;
432 
433   if (TREE_CODE (type) == REFERENCE_TYPE)
434     type = TREE_TYPE (type);
435 
436   tree var_type
437     = build_qualified_type (type,
438 			    (TYPE_QUALS (type)
439 			     | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_LDS)));
440 
441   if (machfun->reduc_decls
442       && offset < machfun->reduc_decls->length ()
443       && (existing_decl = (*machfun->reduc_decls)[offset]))
444     {
445       gcc_assert (TREE_TYPE (existing_decl) == var_type);
446       return existing_decl;
447     }
448   else
449     {
450       char name[50];
451       sprintf (name, ".oacc_reduction_%u", offset);
452       tree decl = create_tmp_var_raw (var_type, name);
453 
454       DECL_CONTEXT (decl) = NULL_TREE;
455       TREE_STATIC (decl) = 1;
456 
457       varpool_node::finalize_decl (decl);
458 
459       vec_safe_grow_cleared (machfun->reduc_decls, offset + 1);
460       (*machfun->reduc_decls)[offset] = decl;
461 
462       return decl;
463     }
464 
465   return NULL_TREE;
466 }
467 
468 /* Expand IFN_GOACC_REDUCTION_SETUP.  */
469 
470 static void
gcn_goacc_reduction_setup(gcall * call)471 gcn_goacc_reduction_setup (gcall *call)
472 {
473   gimple_stmt_iterator gsi = gsi_for_stmt (call);
474   tree lhs = gimple_call_lhs (call);
475   tree var = gimple_call_arg (call, 2);
476   int level = TREE_INT_CST_LOW (gimple_call_arg (call, 3));
477   gimple_seq seq = NULL;
478 
479   push_gimplify_context (true);
480 
481   if (level != GOMP_DIM_GANG)
482     {
483       /* Copy the receiver object.  */
484       tree ref_to_res = gimple_call_arg (call, 1);
485 
486       if (!integer_zerop (ref_to_res))
487 	var = build_simple_mem_ref (ref_to_res);
488     }
489 
490   if (level == GOMP_DIM_WORKER)
491     {
492       tree var_type = TREE_TYPE (var);
493       /* Store incoming value to worker reduction buffer.  */
494       tree offset = gimple_call_arg (call, 5);
495       tree decl
496 	= gcn_goacc_get_worker_red_decl (var_type, TREE_INT_CST_LOW (offset));
497 
498       gimplify_assign (decl, var, &seq);
499     }
500 
501   if (lhs)
502     gimplify_assign (lhs, var, &seq);
503 
504   pop_gimplify_context (NULL);
505   gsi_replace_with_seq (&gsi, seq, true);
506 }
507 
508 /* Expand IFN_GOACC_REDUCTION_INIT.  */
509 
510 static void
gcn_goacc_reduction_init(gcall * call)511 gcn_goacc_reduction_init (gcall *call)
512 {
513   gimple_stmt_iterator gsi = gsi_for_stmt (call);
514   tree lhs = gimple_call_lhs (call);
515   tree var = gimple_call_arg (call, 2);
516   int level = TREE_INT_CST_LOW (gimple_call_arg (call, 3));
517   enum tree_code rcode
518     = (enum tree_code) TREE_INT_CST_LOW (gimple_call_arg (call, 4));
519   tree init = omp_reduction_init_op (gimple_location (call), rcode,
520 				     TREE_TYPE (var));
521   gimple_seq seq = NULL;
522 
523   push_gimplify_context (true);
524 
525   if (level == GOMP_DIM_GANG)
526     {
527       /* If there's no receiver object, propagate the incoming VAR.  */
528       tree ref_to_res = gimple_call_arg (call, 1);
529       if (integer_zerop (ref_to_res))
530 	init = var;
531     }
532 
533   if (lhs)
534     gimplify_assign (lhs, init, &seq);
535 
536   pop_gimplify_context (NULL);
537   gsi_replace_with_seq (&gsi, seq, true);
538 }
539 
540 /* Expand IFN_GOACC_REDUCTION_FINI.  */
541 
542 static void
gcn_goacc_reduction_fini(gcall * call)543 gcn_goacc_reduction_fini (gcall *call)
544 {
545   gimple_stmt_iterator gsi = gsi_for_stmt (call);
546   tree lhs = gimple_call_lhs (call);
547   tree ref_to_res = gimple_call_arg (call, 1);
548   tree var = gimple_call_arg (call, 2);
549   int level = TREE_INT_CST_LOW (gimple_call_arg (call, 3));
550   enum tree_code op
551     = (enum tree_code) TREE_INT_CST_LOW (gimple_call_arg (call, 4));
552   gimple_seq seq = NULL;
553   tree r = NULL_TREE;;
554 
555   push_gimplify_context (true);
556 
557   tree accum = NULL_TREE;
558 
559   if (level == GOMP_DIM_WORKER)
560     {
561       tree var_type = TREE_TYPE (var);
562       tree offset = gimple_call_arg (call, 5);
563       tree decl
564 	= gcn_goacc_get_worker_red_decl (var_type, TREE_INT_CST_LOW (offset));
565 
566       accum = build_fold_addr_expr (decl);
567     }
568   else if (integer_zerop (ref_to_res))
569     r = var;
570   else
571     accum = ref_to_res;
572 
573   if (accum)
574     {
575       /* UPDATE the accumulator.  */
576       gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
577       seq = NULL;
578       r = gcn_reduction_update (gimple_location (call), &gsi, accum, var, op);
579     }
580 
581   if (lhs)
582     gimplify_assign (lhs, r, &seq);
583   pop_gimplify_context (NULL);
584 
585   gsi_replace_with_seq (&gsi, seq, true);
586 }
587 
588 /* Expand IFN_GOACC_REDUCTION_TEARDOWN.  */
589 
590 static void
gcn_goacc_reduction_teardown(gcall * call)591 gcn_goacc_reduction_teardown (gcall *call)
592 {
593   gimple_stmt_iterator gsi = gsi_for_stmt (call);
594   tree lhs = gimple_call_lhs (call);
595   tree var = gimple_call_arg (call, 2);
596   int level = TREE_INT_CST_LOW (gimple_call_arg (call, 3));
597   gimple_seq seq = NULL;
598 
599   push_gimplify_context (true);
600 
601   if (level == GOMP_DIM_WORKER)
602     {
603       tree var_type = TREE_TYPE (var);
604 
605       /* Read the worker reduction buffer.  */
606       tree offset = gimple_call_arg (call, 5);
607       tree decl
608 	= gcn_goacc_get_worker_red_decl (var_type, TREE_INT_CST_LOW (offset));
609       var = decl;
610     }
611 
612   if (level != GOMP_DIM_GANG)
613     {
614       /* Write to the receiver object.  */
615       tree ref_to_res = gimple_call_arg (call, 1);
616 
617       if (!integer_zerop (ref_to_res))
618 	gimplify_assign (build_simple_mem_ref (ref_to_res), var, &seq);
619     }
620 
621   if (lhs)
622     gimplify_assign (lhs, var, &seq);
623 
624   pop_gimplify_context (NULL);
625 
626   gsi_replace_with_seq (&gsi, seq, true);
627 }
628 
629 /* Implement TARGET_GOACC_REDUCTION.
630 
631    Expand calls to the GOACC REDUCTION internal function, into a sequence of
632    gimple instructions.  */
633 
634 void
gcn_goacc_reduction(gcall * call)635 gcn_goacc_reduction (gcall *call)
636 {
637   int level = TREE_INT_CST_LOW (gimple_call_arg (call, 3));
638 
639   if (level == GOMP_DIM_VECTOR)
640     {
641       default_goacc_reduction (call);
642       return;
643     }
644 
645   unsigned code = (unsigned) TREE_INT_CST_LOW (gimple_call_arg (call, 0));
646 
647   switch (code)
648     {
649     case IFN_GOACC_REDUCTION_SETUP:
650       gcn_goacc_reduction_setup (call);
651       break;
652 
653     case IFN_GOACC_REDUCTION_INIT:
654       gcn_goacc_reduction_init (call);
655       break;
656 
657     case IFN_GOACC_REDUCTION_FINI:
658       gcn_goacc_reduction_fini (call);
659       break;
660 
661     case IFN_GOACC_REDUCTION_TEARDOWN:
662       gcn_goacc_reduction_teardown (call);
663       break;
664 
665     default:
666       gcc_unreachable ();
667     }
668 }
669 
670 /* Implement TARGET_GOACC_ADJUST_PROPAGATION_RECORD.
671 
672    Tweak (worker) propagation record, e.g. to put it in shared memory.  */
673 
674 tree
gcn_goacc_adjust_propagation_record(tree record_type,bool sender,const char * name)675 gcn_goacc_adjust_propagation_record (tree record_type, bool sender,
676 				     const char *name)
677 {
678   tree type = record_type;
679 
680   TYPE_ADDR_SPACE (type) = ADDR_SPACE_LDS;
681 
682   if (!sender)
683     type = build_pointer_type (type);
684 
685   tree decl = create_tmp_var_raw (type, name);
686 
687   if (sender)
688     {
689       DECL_CONTEXT (decl) = NULL_TREE;
690       TREE_STATIC (decl) = 1;
691     }
692 
693   if (sender)
694     varpool_node::finalize_decl (decl);
695 
696   return decl;
697 }
698 
699 void
gcn_goacc_adjust_gangprivate_decl(tree var)700 gcn_goacc_adjust_gangprivate_decl (tree var)
701 {
702   tree type = TREE_TYPE (var);
703   tree lds_type = build_qualified_type (type,
704 		    TYPE_QUALS_NO_ADDR_SPACE (type)
705 		    | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_LDS));
706   machine_function *machfun = cfun->machine;
707 
708   TREE_TYPE (var) = lds_type;
709   TREE_STATIC (var) = 1;
710 
711   /* We're making VAR static.  We have to mangle the name to avoid collisions
712      between different local variables that share the same names.  */
713   lhd_set_decl_assembler_name (var);
714 
715   varpool_node::finalize_decl (var);
716 
717   if (machfun)
718     machfun->use_flat_addressing = true;
719 }
720 
721 /* }}}  */
722