1 /* General types and functions that are uselful for processing of OpenMP,
2    OpenACC and similar directivers at various stages of compilation.
3 
4    Copyright (C) 2005-2021 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 /* Find an OMP clause of type KIND within CLAUSES.  */
23 
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "backend.h"
28 #include "target.h"
29 #include "tree.h"
30 #include "gimple.h"
31 #include "ssa.h"
32 #include "diagnostic-core.h"
33 #include "fold-const.h"
34 #include "langhooks.h"
35 #include "omp-general.h"
36 #include "stringpool.h"
37 #include "attribs.h"
38 #include "gimplify.h"
39 #include "cgraph.h"
40 #include "alloc-pool.h"
41 #include "symbol-summary.h"
42 #include "tree-pass.h"
43 #include "omp-device-properties.h"
44 #include "tree-iterator.h"
45 #include "data-streamer.h"
46 #include "streamer-hooks.h"
47 #include "opts.h"
48 
49 enum omp_requires omp_requires_mask;
50 
51 tree
omp_find_clause(tree clauses,enum omp_clause_code kind)52 omp_find_clause (tree clauses, enum omp_clause_code kind)
53 {
54   for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
55     if (OMP_CLAUSE_CODE (clauses) == kind)
56       return clauses;
57 
58   return NULL_TREE;
59 }
60 
61 /* True if OpenMP should regard this DECL as being a scalar which has Fortran's
62    allocatable or pointer attribute.  */
63 bool
omp_is_allocatable_or_ptr(tree decl)64 omp_is_allocatable_or_ptr (tree decl)
65 {
66   return lang_hooks.decls.omp_is_allocatable_or_ptr (decl);
67 }
68 
69 /* Check whether this DECL belongs to a Fortran optional argument.
70    With 'for_present_check' set to false, decls which are optional parameters
71    themselve are returned as tree - or a NULL_TREE otherwise. Those decls are
72    always pointers.  With 'for_present_check' set to true, the decl for checking
73    whether an argument is present is returned; for arguments with value
74    attribute this is the hidden argument and of BOOLEAN_TYPE.  If the decl is
75    unrelated to optional arguments, NULL_TREE is returned.  */
76 
77 tree
omp_check_optional_argument(tree decl,bool for_present_check)78 omp_check_optional_argument (tree decl, bool for_present_check)
79 {
80   return lang_hooks.decls.omp_check_optional_argument (decl, for_present_check);
81 }
82 
83 /* True if OpenMP should privatize what this DECL points to rather
84    than the DECL itself.  */
85 
86 bool
omp_privatize_by_reference(tree decl)87 omp_privatize_by_reference (tree decl)
88 {
89   return lang_hooks.decls.omp_privatize_by_reference (decl);
90 }
91 
92 /* Adjust *COND_CODE and *N2 so that the former is either LT_EXPR or GT_EXPR,
93    given that V is the loop index variable and STEP is loop step. */
94 
95 void
omp_adjust_for_condition(location_t loc,enum tree_code * cond_code,tree * n2,tree v,tree step)96 omp_adjust_for_condition (location_t loc, enum tree_code *cond_code, tree *n2,
97 			  tree v, tree step)
98 {
99   switch (*cond_code)
100     {
101     case LT_EXPR:
102     case GT_EXPR:
103       break;
104 
105     case NE_EXPR:
106       gcc_assert (TREE_CODE (step) == INTEGER_CST);
107       if (TREE_CODE (TREE_TYPE (v)) == INTEGER_TYPE)
108 	{
109 	  if (integer_onep (step))
110 	    *cond_code = LT_EXPR;
111 	  else
112 	    {
113 	      gcc_assert (integer_minus_onep (step));
114 	      *cond_code = GT_EXPR;
115 	    }
116 	}
117       else
118 	{
119 	  tree unit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (v)));
120 	  gcc_assert (TREE_CODE (unit) == INTEGER_CST);
121 	  if (tree_int_cst_equal (unit, step))
122 	    *cond_code = LT_EXPR;
123 	  else
124 	    {
125 	      gcc_assert (wi::neg (wi::to_widest (unit))
126 			  == wi::to_widest (step));
127 	      *cond_code = GT_EXPR;
128 	    }
129 	}
130 
131       break;
132 
133     case LE_EXPR:
134       if (POINTER_TYPE_P (TREE_TYPE (*n2)))
135 	*n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, 1);
136       else
137 	*n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (*n2), *n2,
138 			       build_int_cst (TREE_TYPE (*n2), 1));
139       *cond_code = LT_EXPR;
140       break;
141     case GE_EXPR:
142       if (POINTER_TYPE_P (TREE_TYPE (*n2)))
143 	*n2 = fold_build_pointer_plus_hwi_loc (loc, *n2, -1);
144       else
145 	*n2 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (*n2), *n2,
146 			       build_int_cst (TREE_TYPE (*n2), 1));
147       *cond_code = GT_EXPR;
148       break;
149     default:
150       gcc_unreachable ();
151     }
152 }
153 
154 /* Return the looping step from INCR, extracted from the step of a gimple omp
155    for statement.  */
156 
157 tree
omp_get_for_step_from_incr(location_t loc,tree incr)158 omp_get_for_step_from_incr (location_t loc, tree incr)
159 {
160   tree step;
161   switch (TREE_CODE (incr))
162     {
163     case PLUS_EXPR:
164       step = TREE_OPERAND (incr, 1);
165       break;
166     case POINTER_PLUS_EXPR:
167       step = fold_convert (ssizetype, TREE_OPERAND (incr, 1));
168       break;
169     case MINUS_EXPR:
170       step = TREE_OPERAND (incr, 1);
171       step = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (step), step);
172       break;
173     default:
174       gcc_unreachable ();
175     }
176   return step;
177 }
178 
179 /* Extract the header elements of parallel loop FOR_STMT and store
180    them into *FD.  */
181 
182 void
omp_extract_for_data(gomp_for * for_stmt,struct omp_for_data * fd,struct omp_for_data_loop * loops)183 omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd,
184 		      struct omp_for_data_loop *loops)
185 {
186   tree t, var, *collapse_iter, *collapse_count;
187   tree count = NULL_TREE, iter_type = long_integer_type_node;
188   struct omp_for_data_loop *loop;
189   int i;
190   struct omp_for_data_loop dummy_loop;
191   location_t loc = gimple_location (for_stmt);
192   bool simd = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD;
193   bool distribute = gimple_omp_for_kind (for_stmt)
194 		    == GF_OMP_FOR_KIND_DISTRIBUTE;
195   bool taskloop = gimple_omp_for_kind (for_stmt)
196 		  == GF_OMP_FOR_KIND_TASKLOOP;
197   bool order_reproducible = false;
198   tree iterv, countv;
199 
200   fd->for_stmt = for_stmt;
201   fd->pre = NULL;
202   fd->have_nowait = distribute || simd;
203   fd->have_ordered = false;
204   fd->have_reductemp = false;
205   fd->have_pointer_condtemp = false;
206   fd->have_scantemp = false;
207   fd->have_nonctrl_scantemp = false;
208   fd->non_rect = false;
209   fd->lastprivate_conditional = 0;
210   fd->tiling = NULL_TREE;
211   fd->collapse = 1;
212   fd->ordered = 0;
213   fd->first_nonrect = -1;
214   fd->last_nonrect = -1;
215   fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
216   fd->sched_modifiers = 0;
217   fd->chunk_size = NULL_TREE;
218   fd->simd_schedule = false;
219   fd->first_inner_iterations = NULL_TREE;
220   fd->factor = NULL_TREE;
221   fd->adjn1 = NULL_TREE;
222   collapse_iter = NULL;
223   collapse_count = NULL;
224 
225   for (t = gimple_omp_for_clauses (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t))
226     switch (OMP_CLAUSE_CODE (t))
227       {
228       case OMP_CLAUSE_NOWAIT:
229 	fd->have_nowait = true;
230 	break;
231       case OMP_CLAUSE_ORDERED:
232 	fd->have_ordered = true;
233 	if (OMP_CLAUSE_ORDERED_EXPR (t))
234 	  fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t));
235 	break;
236       case OMP_CLAUSE_SCHEDULE:
237 	gcc_assert (!distribute && !taskloop);
238 	fd->sched_kind
239 	  = (enum omp_clause_schedule_kind)
240 	    (OMP_CLAUSE_SCHEDULE_KIND (t) & OMP_CLAUSE_SCHEDULE_MASK);
241 	fd->sched_modifiers = (OMP_CLAUSE_SCHEDULE_KIND (t)
242 			       & ~OMP_CLAUSE_SCHEDULE_MASK);
243 	fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
244 	fd->simd_schedule = OMP_CLAUSE_SCHEDULE_SIMD (t);
245 	break;
246       case OMP_CLAUSE_DIST_SCHEDULE:
247 	gcc_assert (distribute);
248 	fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t);
249 	break;
250       case OMP_CLAUSE_COLLAPSE:
251 	fd->collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (t));
252 	if (fd->collapse > 1)
253 	  {
254 	    collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t);
255 	    collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t);
256 	  }
257 	break;
258       case OMP_CLAUSE_TILE:
259 	fd->tiling = OMP_CLAUSE_TILE_LIST (t);
260 	fd->collapse = list_length (fd->tiling);
261 	gcc_assert (fd->collapse);
262 	collapse_iter = &OMP_CLAUSE_TILE_ITERVAR (t);
263 	collapse_count = &OMP_CLAUSE_TILE_COUNT (t);
264 	break;
265       case OMP_CLAUSE__REDUCTEMP_:
266 	fd->have_reductemp = true;
267 	break;
268       case OMP_CLAUSE_LASTPRIVATE:
269 	if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (t))
270 	  fd->lastprivate_conditional++;
271 	break;
272       case OMP_CLAUSE__CONDTEMP_:
273 	if (POINTER_TYPE_P (TREE_TYPE (OMP_CLAUSE_DECL (t))))
274 	  fd->have_pointer_condtemp = true;
275 	break;
276       case OMP_CLAUSE__SCANTEMP_:
277 	fd->have_scantemp = true;
278 	if (!OMP_CLAUSE__SCANTEMP__ALLOC (t)
279 	    && !OMP_CLAUSE__SCANTEMP__CONTROL (t))
280 	  fd->have_nonctrl_scantemp = true;
281 	break;
282       case OMP_CLAUSE_ORDER:
283 	/* FIXME: For OpenMP 5.2 this should change to
284 	   if (OMP_CLAUSE_ORDER_REPRODUCIBLE (t))
285 	   (with the exception of loop construct but that lowers to
286 	   no schedule/dist_schedule clauses currently).  */
287 	if (!OMP_CLAUSE_ORDER_UNCONSTRAINED (t))
288 	  order_reproducible = true;
289       default:
290 	break;
291       }
292 
293   /* For order(reproducible:concurrent) schedule ({dynamic,guided,runtime})
294      we have either the option to expensively remember at runtime how we've
295      distributed work from first loop and reuse that in following loops with
296      the same number of iterations and schedule, or just force static schedule.
297      OpenMP API calls etc. aren't allowed in order(concurrent) bodies so
298      users can't observe it easily anyway.  */
299   if (order_reproducible)
300     fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
301   if (fd->collapse > 1 || fd->tiling)
302     fd->loops = loops;
303   else
304     fd->loops = &fd->loop;
305 
306   if (fd->ordered && fd->collapse == 1 && loops != NULL)
307     {
308       fd->loops = loops;
309       iterv = NULL_TREE;
310       countv = NULL_TREE;
311       collapse_iter = &iterv;
312       collapse_count = &countv;
313     }
314 
315   /* FIXME: for now map schedule(auto) to schedule(static).
316      There should be analysis to determine whether all iterations
317      are approximately the same amount of work (then schedule(static)
318      is best) or if it varies (then schedule(dynamic,N) is better).  */
319   if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO)
320     {
321       fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
322       gcc_assert (fd->chunk_size == NULL);
323     }
324   gcc_assert ((fd->collapse == 1 && !fd->tiling) || collapse_iter != NULL);
325   if (taskloop)
326     fd->sched_kind = OMP_CLAUSE_SCHEDULE_RUNTIME;
327   if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
328     gcc_assert (fd->chunk_size == NULL);
329   else if (fd->chunk_size == NULL)
330     {
331       /* We only need to compute a default chunk size for ordered
332 	 static loops and dynamic loops.  */
333       if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
334 	  || fd->have_ordered)
335 	fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
336 			 ? integer_zero_node : integer_one_node;
337     }
338 
339   int cnt = fd->ordered ? fd->ordered : fd->collapse;
340   int single_nonrect = -1;
341   tree single_nonrect_count = NULL_TREE;
342   enum tree_code single_nonrect_cond_code = ERROR_MARK;
343   for (i = 1; i < cnt; i++)
344     {
345       tree n1 = gimple_omp_for_initial (for_stmt, i);
346       tree n2 = gimple_omp_for_final (for_stmt, i);
347       if (TREE_CODE (n1) == TREE_VEC)
348 	{
349 	  if (fd->non_rect)
350 	    {
351 	      single_nonrect = -1;
352 	      break;
353 	    }
354 	  for (int j = i - 1; j >= 0; j--)
355 	    if (TREE_VEC_ELT (n1, 0) == gimple_omp_for_index (for_stmt, j))
356 	      {
357 		single_nonrect = j;
358 		break;
359 	      }
360 	  fd->non_rect = true;
361 	}
362       else if (TREE_CODE (n2) == TREE_VEC)
363 	{
364 	  if (fd->non_rect)
365 	    {
366 	      single_nonrect = -1;
367 	      break;
368 	    }
369 	  for (int j = i - 1; j >= 0; j--)
370 	    if (TREE_VEC_ELT (n2, 0) == gimple_omp_for_index (for_stmt, j))
371 	      {
372 		single_nonrect = j;
373 		break;
374 	      }
375 	  fd->non_rect = true;
376 	}
377     }
378   for (i = 0; i < cnt; i++)
379     {
380       if (i == 0
381 	  && fd->collapse == 1
382 	  && !fd->tiling
383 	  && (fd->ordered == 0 || loops == NULL))
384 	loop = &fd->loop;
385       else if (loops != NULL)
386 	loop = loops + i;
387       else
388 	loop = &dummy_loop;
389 
390       loop->v = gimple_omp_for_index (for_stmt, i);
391       gcc_assert (SSA_VAR_P (loop->v));
392       gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
393 		  || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
394       var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
395       loop->n1 = gimple_omp_for_initial (for_stmt, i);
396       loop->m1 = NULL_TREE;
397       loop->m2 = NULL_TREE;
398       loop->outer = 0;
399       loop->non_rect_referenced = false;
400       if (TREE_CODE (loop->n1) == TREE_VEC)
401 	{
402 	  for (int j = i - 1; j >= 0; j--)
403 	    if (TREE_VEC_ELT (loop->n1, 0) == gimple_omp_for_index (for_stmt, j))
404 	      {
405 		loop->outer = i - j;
406 		if (loops != NULL)
407 		  loops[j].non_rect_referenced = true;
408 		if (fd->first_nonrect == -1 || fd->first_nonrect > j)
409 		  fd->first_nonrect = j;
410 		break;
411 	      }
412 	  gcc_assert (loop->outer);
413 	  loop->m1 = TREE_VEC_ELT (loop->n1, 1);
414 	  loop->n1 = TREE_VEC_ELT (loop->n1, 2);
415 	  fd->non_rect = true;
416 	  fd->last_nonrect = i;
417 	}
418 
419       loop->cond_code = gimple_omp_for_cond (for_stmt, i);
420       loop->n2 = gimple_omp_for_final (for_stmt, i);
421       gcc_assert (loop->cond_code != NE_EXPR
422 		  || (gimple_omp_for_kind (for_stmt)
423 		      != GF_OMP_FOR_KIND_OACC_LOOP));
424       if (TREE_CODE (loop->n2) == TREE_VEC)
425 	{
426 	  if (loop->outer)
427 	    gcc_assert (TREE_VEC_ELT (loop->n2, 0)
428 			== gimple_omp_for_index (for_stmt, i - loop->outer));
429 	  else
430 	    for (int j = i - 1; j >= 0; j--)
431 	      if (TREE_VEC_ELT (loop->n2, 0) == gimple_omp_for_index (for_stmt, j))
432 		{
433 		  loop->outer = i - j;
434 		  if (loops != NULL)
435 		    loops[j].non_rect_referenced = true;
436 		  if (fd->first_nonrect == -1 || fd->first_nonrect > j)
437 		    fd->first_nonrect = j;
438 		  break;
439 		}
440 	  gcc_assert (loop->outer);
441 	  loop->m2 = TREE_VEC_ELT (loop->n2, 1);
442 	  loop->n2 = TREE_VEC_ELT (loop->n2, 2);
443 	  fd->non_rect = true;
444 	  fd->last_nonrect = i;
445 	}
446 
447       t = gimple_omp_for_incr (for_stmt, i);
448       gcc_assert (TREE_OPERAND (t, 0) == var);
449       loop->step = omp_get_for_step_from_incr (loc, t);
450 
451       omp_adjust_for_condition (loc, &loop->cond_code, &loop->n2, loop->v,
452 				loop->step);
453 
454       if (simd
455 	  || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
456 	      && !fd->have_ordered))
457 	{
458 	  if (fd->collapse == 1 && !fd->tiling)
459 	    iter_type = TREE_TYPE (loop->v);
460 	  else if (i == 0
461 		   || TYPE_PRECISION (iter_type)
462 		      < TYPE_PRECISION (TREE_TYPE (loop->v)))
463 	    iter_type
464 	      = build_nonstandard_integer_type
465 		  (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
466 	}
467       else if (iter_type != long_long_unsigned_type_node)
468 	{
469 	  if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
470 	    iter_type = long_long_unsigned_type_node;
471 	  else if (TYPE_UNSIGNED (TREE_TYPE (loop->v))
472 		   && TYPE_PRECISION (TREE_TYPE (loop->v))
473 		      >= TYPE_PRECISION (iter_type))
474 	    {
475 	      tree n;
476 
477 	      if (loop->cond_code == LT_EXPR)
478 		n = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v),
479 				     loop->n2, loop->step);
480 	      else
481 		n = loop->n1;
482 	      if (loop->m1
483 		  || loop->m2
484 		  || TREE_CODE (n) != INTEGER_CST
485 		  || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n))
486 		iter_type = long_long_unsigned_type_node;
487 	    }
488 	  else if (TYPE_PRECISION (TREE_TYPE (loop->v))
489 		   > TYPE_PRECISION (iter_type))
490 	    {
491 	      tree n1, n2;
492 
493 	      if (loop->cond_code == LT_EXPR)
494 		{
495 		  n1 = loop->n1;
496 		  n2 = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (loop->v),
497 					loop->n2, loop->step);
498 		}
499 	      else
500 		{
501 		  n1 = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (loop->v),
502 					loop->n2, loop->step);
503 		  n2 = loop->n1;
504 		}
505 	      if (loop->m1
506 		  || loop->m2
507 		  || TREE_CODE (n1) != INTEGER_CST
508 		  || TREE_CODE (n2) != INTEGER_CST
509 		  || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1)
510 		  || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type)))
511 		iter_type = long_long_unsigned_type_node;
512 	    }
513 	}
514 
515       if (i >= fd->collapse)
516 	continue;
517 
518       if (collapse_count && *collapse_count == NULL)
519 	{
520 	  if (count && integer_zerop (count))
521 	    continue;
522 	  tree n1first = NULL_TREE, n2first = NULL_TREE;
523 	  tree n1last = NULL_TREE, n2last = NULL_TREE;
524 	  tree ostep = NULL_TREE;
525 	  if (loop->m1 || loop->m2)
526 	    {
527 	      if (count == NULL_TREE)
528 		continue;
529 	      if (single_nonrect == -1
530 		  || (loop->m1 && TREE_CODE (loop->m1) != INTEGER_CST)
531 		  || (loop->m2 && TREE_CODE (loop->m2) != INTEGER_CST)
532 		  || TREE_CODE (loop->n1) != INTEGER_CST
533 		  || TREE_CODE (loop->n2) != INTEGER_CST
534 		  || TREE_CODE (loop->step) != INTEGER_CST)
535 		{
536 		  count = NULL_TREE;
537 		  continue;
538 		}
539 	      tree var = gimple_omp_for_initial (for_stmt, single_nonrect);
540 	      tree itype = TREE_TYPE (var);
541 	      tree first = gimple_omp_for_initial (for_stmt, single_nonrect);
542 	      t = gimple_omp_for_incr (for_stmt, single_nonrect);
543 	      ostep = omp_get_for_step_from_incr (loc, t);
544 	      t = fold_binary (MINUS_EXPR, long_long_unsigned_type_node,
545 			       single_nonrect_count,
546 			       build_one_cst (long_long_unsigned_type_node));
547 	      t = fold_convert (itype, t);
548 	      first = fold_convert (itype, first);
549 	      ostep = fold_convert (itype, ostep);
550 	      tree last = fold_binary (PLUS_EXPR, itype, first,
551 				       fold_binary (MULT_EXPR, itype, t,
552 						    ostep));
553 	      if (TREE_CODE (first) != INTEGER_CST
554 		  || TREE_CODE (last) != INTEGER_CST)
555 		{
556 		  count = NULL_TREE;
557 		  continue;
558 		}
559 	      if (loop->m1)
560 		{
561 		  tree m1 = fold_convert (itype, loop->m1);
562 		  tree n1 = fold_convert (itype, loop->n1);
563 		  n1first = fold_binary (PLUS_EXPR, itype,
564 					 fold_binary (MULT_EXPR, itype,
565 						      first, m1), n1);
566 		  n1last = fold_binary (PLUS_EXPR, itype,
567 					fold_binary (MULT_EXPR, itype,
568 						     last, m1), n1);
569 		}
570 	      else
571 		n1first = n1last = loop->n1;
572 	      if (loop->m2)
573 		{
574 		  tree n2 = fold_convert (itype, loop->n2);
575 		  tree m2 = fold_convert (itype, loop->m2);
576 		  n2first = fold_binary (PLUS_EXPR, itype,
577 					 fold_binary (MULT_EXPR, itype,
578 						      first, m2), n2);
579 		  n2last = fold_binary (PLUS_EXPR, itype,
580 					fold_binary (MULT_EXPR, itype,
581 						     last, m2), n2);
582 		}
583 	      else
584 		n2first = n2last = loop->n2;
585 	      n1first = fold_convert (TREE_TYPE (loop->v), n1first);
586 	      n2first = fold_convert (TREE_TYPE (loop->v), n2first);
587 	      n1last = fold_convert (TREE_TYPE (loop->v), n1last);
588 	      n2last = fold_convert (TREE_TYPE (loop->v), n2last);
589 	      t = fold_binary (loop->cond_code, boolean_type_node,
590 			       n1first, n2first);
591 	      tree t2 = fold_binary (loop->cond_code, boolean_type_node,
592 				     n1last, n2last);
593 	      if (t && t2 && integer_nonzerop (t) && integer_nonzerop (t2))
594 		/* All outer loop iterators have at least one inner loop
595 		   iteration.  Try to compute the count at compile time.  */
596 		t = NULL_TREE;
597 	      else if (t && t2 && integer_zerop (t) && integer_zerop (t2))
598 		/* No iterations of the inner loop.  count will be set to
599 		   zero cst below.  */;
600 	      else if (TYPE_UNSIGNED (itype)
601 		       || t == NULL_TREE
602 		       || t2 == NULL_TREE
603 		       || TREE_CODE (t) != INTEGER_CST
604 		       || TREE_CODE (t2) != INTEGER_CST)
605 		{
606 		  /* Punt (for now).  */
607 		  count = NULL_TREE;
608 		  continue;
609 		}
610 	      else
611 		{
612 		  /* Some iterations of the outer loop have zero iterations
613 		     of the inner loop, while others have at least one.
614 		     In this case, we need to adjust one of those outer
615 		     loop bounds.  If ADJ_FIRST, we need to adjust outer n1
616 		     (first), otherwise outer n2 (last).  */
617 		  bool adj_first = integer_zerop (t);
618 		  tree n1 = fold_convert (itype, loop->n1);
619 		  tree n2 = fold_convert (itype, loop->n2);
620 		  tree m1 = loop->m1 ? fold_convert (itype, loop->m1)
621 				     : build_zero_cst (itype);
622 		  tree m2 = loop->m2 ? fold_convert (itype, loop->m2)
623 				     : build_zero_cst (itype);
624 		  t = fold_binary (MINUS_EXPR, itype, n1, n2);
625 		  t2 = fold_binary (MINUS_EXPR, itype, m2, m1);
626 		  t = fold_binary (TRUNC_DIV_EXPR, itype, t, t2);
627 		  t2 = fold_binary (MINUS_EXPR, itype, t, first);
628 		  t2 = fold_binary (TRUNC_MOD_EXPR, itype, t2, ostep);
629 		  t = fold_binary (MINUS_EXPR, itype, t, t2);
630 		  tree n1cur
631 		    = fold_binary (PLUS_EXPR, itype, n1,
632 				   fold_binary (MULT_EXPR, itype, m1, t));
633 		  tree n2cur
634 		    = fold_binary (PLUS_EXPR, itype, n2,
635 				   fold_binary (MULT_EXPR, itype, m2, t));
636 		  t2 = fold_binary (loop->cond_code, boolean_type_node,
637 				    n1cur, n2cur);
638 		  tree t3 = fold_binary (MULT_EXPR, itype, m1, ostep);
639 		  tree t4 = fold_binary (MULT_EXPR, itype, m2, ostep);
640 		  tree diff;
641 		  if (adj_first)
642 		    {
643 		      tree new_first;
644 		      if (integer_nonzerop (t2))
645 			{
646 			  new_first = t;
647 			  n1first = n1cur;
648 			  n2first = n2cur;
649 			  if (flag_checking)
650 			    {
651 			      t3 = fold_binary (MINUS_EXPR, itype, n1cur, t3);
652 			      t4 = fold_binary (MINUS_EXPR, itype, n2cur, t4);
653 			      t3 = fold_binary (loop->cond_code,
654 						boolean_type_node, t3, t4);
655 			      gcc_assert (integer_zerop (t3));
656 			    }
657 			}
658 		      else
659 			{
660 			  t3 = fold_binary (PLUS_EXPR, itype, n1cur, t3);
661 			  t4 = fold_binary (PLUS_EXPR, itype, n2cur, t4);
662 			  new_first = fold_binary (PLUS_EXPR, itype, t, ostep);
663 			  n1first = t3;
664 			  n2first = t4;
665 			  if (flag_checking)
666 			    {
667 			      t3 = fold_binary (loop->cond_code,
668 						boolean_type_node, t3, t4);
669 			      gcc_assert (integer_nonzerop (t3));
670 			    }
671 			}
672 		      diff = fold_binary (MINUS_EXPR, itype, new_first, first);
673 		      first = new_first;
674 		      fd->adjn1 = first;
675 		    }
676 		  else
677 		    {
678 		      tree new_last;
679 		      if (integer_zerop (t2))
680 			{
681 			  t3 = fold_binary (MINUS_EXPR, itype, n1cur, t3);
682 			  t4 = fold_binary (MINUS_EXPR, itype, n2cur, t4);
683 			  new_last = fold_binary (MINUS_EXPR, itype, t, ostep);
684 			  n1last = t3;
685 			  n2last = t4;
686 			  if (flag_checking)
687 			    {
688 			      t3 = fold_binary (loop->cond_code,
689 						boolean_type_node, t3, t4);
690 			      gcc_assert (integer_nonzerop (t3));
691 			    }
692 			}
693 		      else
694 			{
695 			  new_last = t;
696 			  n1last = n1cur;
697 			  n2last = n2cur;
698 			  if (flag_checking)
699 			    {
700 			      t3 = fold_binary (PLUS_EXPR, itype, n1cur, t3);
701 			      t4 = fold_binary (PLUS_EXPR, itype, n2cur, t4);
702 			      t3 = fold_binary (loop->cond_code,
703 						boolean_type_node, t3, t4);
704 			      gcc_assert (integer_zerop (t3));
705 			    }
706 			}
707 		      diff = fold_binary (MINUS_EXPR, itype, last, new_last);
708 		    }
709 		  if (TYPE_UNSIGNED (itype)
710 		      && single_nonrect_cond_code == GT_EXPR)
711 		    diff = fold_binary (TRUNC_DIV_EXPR, itype,
712 					fold_unary (NEGATE_EXPR, itype, diff),
713 					fold_unary (NEGATE_EXPR, itype,
714 						    ostep));
715 		  else
716 		    diff = fold_binary (TRUNC_DIV_EXPR, itype, diff, ostep);
717 		  diff = fold_convert (long_long_unsigned_type_node, diff);
718 		  single_nonrect_count
719 		    = fold_binary (MINUS_EXPR, long_long_unsigned_type_node,
720 				   single_nonrect_count, diff);
721 		  t = NULL_TREE;
722 		}
723 	    }
724 	  else
725 	    t = fold_binary (loop->cond_code, boolean_type_node,
726 			     fold_convert (TREE_TYPE (loop->v), loop->n1),
727 			     fold_convert (TREE_TYPE (loop->v), loop->n2));
728 	  if (t && integer_zerop (t))
729 	    count = build_zero_cst (long_long_unsigned_type_node);
730 	  else if ((i == 0 || count != NULL_TREE)
731 		   && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
732 		   && TREE_CONSTANT (loop->n1)
733 		   && TREE_CONSTANT (loop->n2)
734 		   && TREE_CODE (loop->step) == INTEGER_CST)
735 	    {
736 	      tree itype = TREE_TYPE (loop->v);
737 
738 	      if (POINTER_TYPE_P (itype))
739 		itype = signed_type_for (itype);
740 	      t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1));
741 	      t = fold_build2 (PLUS_EXPR, itype,
742 			       fold_convert (itype, loop->step), t);
743 	      tree n1 = loop->n1;
744 	      tree n2 = loop->n2;
745 	      if (loop->m1 || loop->m2)
746 		{
747 		  gcc_assert (single_nonrect != -1);
748 		  n1 = n1first;
749 		  n2 = n2first;
750 		}
751 	      t = fold_build2 (PLUS_EXPR, itype, t, fold_convert (itype, n2));
752 	      t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1));
753 	      tree step = fold_convert_loc (loc, itype, loop->step);
754 	      if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
755 		t = fold_build2 (TRUNC_DIV_EXPR, itype,
756 				 fold_build1 (NEGATE_EXPR, itype, t),
757 				 fold_build1 (NEGATE_EXPR, itype, step));
758 	      else
759 		t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step);
760 	      tree llutype = long_long_unsigned_type_node;
761 	      t = fold_convert (llutype, t);
762 	      if (loop->m1 || loop->m2)
763 		{
764 		  /* t is number of iterations of inner loop at either first
765 		     or last value of the outer iterator (the one with fewer
766 		     iterations).
767 		     Compute t2 = ((m2 - m1) * ostep) / step
768 		     and niters = outer_count * t
769 				  + t2 * ((outer_count - 1) * outer_count / 2)
770 		   */
771 		  tree m1 = loop->m1 ? loop->m1 : integer_zero_node;
772 		  tree m2 = loop->m2 ? loop->m2 : integer_zero_node;
773 		  m1 = fold_convert (itype, m1);
774 		  m2 = fold_convert (itype, m2);
775 		  tree t2 = fold_build2 (MINUS_EXPR, itype, m2, m1);
776 		  t2 = fold_build2 (MULT_EXPR, itype, t2, ostep);
777 		  if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
778 		    t2 = fold_build2 (TRUNC_DIV_EXPR, itype,
779 				      fold_build1 (NEGATE_EXPR, itype, t2),
780 				      fold_build1 (NEGATE_EXPR, itype, step));
781 		  else
782 		    t2 = fold_build2 (TRUNC_DIV_EXPR, itype, t2, step);
783 		  t2 = fold_convert (llutype, t2);
784 		  fd->first_inner_iterations = t;
785 		  fd->factor = t2;
786 		  t = fold_build2 (MULT_EXPR, llutype, t,
787 				   single_nonrect_count);
788 		  tree t3 = fold_build2 (MINUS_EXPR, llutype,
789 					 single_nonrect_count,
790 					 build_one_cst (llutype));
791 		  t3 = fold_build2 (MULT_EXPR, llutype, t3,
792 				    single_nonrect_count);
793 		  t3 = fold_build2 (TRUNC_DIV_EXPR, llutype, t3,
794 				    build_int_cst (llutype, 2));
795 		  t2 = fold_build2 (MULT_EXPR, llutype, t2, t3);
796 		  t = fold_build2 (PLUS_EXPR, llutype, t, t2);
797 		}
798 	      if (i == single_nonrect)
799 		{
800 		  if (integer_zerop (t) || TREE_CODE (t) != INTEGER_CST)
801 		    count = t;
802 		  else
803 		    {
804 		      single_nonrect_count = t;
805 		      single_nonrect_cond_code = loop->cond_code;
806 		      if (count == NULL_TREE)
807 			count = build_one_cst (llutype);
808 		    }
809 		}
810 	      else if (count != NULL_TREE)
811 		count = fold_build2 (MULT_EXPR, llutype, count, t);
812 	      else
813 		count = t;
814 	      if (TREE_CODE (count) != INTEGER_CST)
815 		count = NULL_TREE;
816 	    }
817 	  else if (count && !integer_zerop (count))
818 	    count = NULL_TREE;
819 	}
820     }
821 
822   if (count
823       && !simd
824       && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
825 	  || fd->have_ordered))
826     {
827       if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
828 	iter_type = long_long_unsigned_type_node;
829       else
830 	iter_type = long_integer_type_node;
831     }
832   else if (collapse_iter && *collapse_iter != NULL)
833     iter_type = TREE_TYPE (*collapse_iter);
834   fd->iter_type = iter_type;
835   if (collapse_iter && *collapse_iter == NULL)
836     *collapse_iter = create_tmp_var (iter_type, ".iter");
837   if (collapse_count && *collapse_count == NULL)
838     {
839       if (count)
840 	{
841 	  *collapse_count = fold_convert_loc (loc, iter_type, count);
842 	  if (fd->first_inner_iterations && fd->factor)
843 	    {
844 	      t = make_tree_vec (4);
845 	      TREE_VEC_ELT (t, 0) = *collapse_count;
846 	      TREE_VEC_ELT (t, 1) = fd->first_inner_iterations;
847 	      TREE_VEC_ELT (t, 2) = fd->factor;
848 	      TREE_VEC_ELT (t, 3) = fd->adjn1;
849 	      *collapse_count = t;
850 	    }
851 	}
852       else
853 	*collapse_count = create_tmp_var (iter_type, ".count");
854     }
855 
856   if (fd->collapse > 1 || fd->tiling || (fd->ordered && loops))
857     {
858       fd->loop.v = *collapse_iter;
859       fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
860       fd->loop.n2 = *collapse_count;
861       if (TREE_CODE (fd->loop.n2) == TREE_VEC)
862 	{
863 	  gcc_assert (fd->non_rect);
864 	  fd->first_inner_iterations = TREE_VEC_ELT (fd->loop.n2, 1);
865 	  fd->factor = TREE_VEC_ELT (fd->loop.n2, 2);
866 	  fd->adjn1 = TREE_VEC_ELT (fd->loop.n2, 3);
867 	  fd->loop.n2 = TREE_VEC_ELT (fd->loop.n2, 0);
868 	}
869       fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
870       fd->loop.m1 = NULL_TREE;
871       fd->loop.m2 = NULL_TREE;
872       fd->loop.outer = 0;
873       fd->loop.cond_code = LT_EXPR;
874     }
875   else if (loops)
876     loops[0] = fd->loop;
877 }
878 
879 /* Build a call to GOMP_barrier.  */
880 
881 gimple *
omp_build_barrier(tree lhs)882 omp_build_barrier (tree lhs)
883 {
884   tree fndecl = builtin_decl_explicit (lhs ? BUILT_IN_GOMP_BARRIER_CANCEL
885 					   : BUILT_IN_GOMP_BARRIER);
886   gcall *g = gimple_build_call (fndecl, 0);
887   if (lhs)
888     gimple_call_set_lhs (g, lhs);
889   return g;
890 }
891 
892 /* Find OMP_FOR resp. OMP_SIMD with non-NULL OMP_FOR_INIT.  Also, fill in pdata
893    array, pdata[0] non-NULL if there is anything non-trivial in between,
894    pdata[1] is address of OMP_PARALLEL in between if any, pdata[2] is address
895    of OMP_FOR in between if any and pdata[3] is address of the inner
896    OMP_FOR/OMP_SIMD.  */
897 
898 tree
find_combined_omp_for(tree * tp,int * walk_subtrees,void * data)899 find_combined_omp_for (tree *tp, int *walk_subtrees, void *data)
900 {
901   tree **pdata = (tree **) data;
902   *walk_subtrees = 0;
903   switch (TREE_CODE (*tp))
904     {
905     case OMP_FOR:
906       if (OMP_FOR_INIT (*tp) != NULL_TREE)
907 	{
908 	  pdata[3] = tp;
909 	  return *tp;
910 	}
911       pdata[2] = tp;
912       *walk_subtrees = 1;
913       break;
914     case OMP_SIMD:
915       if (OMP_FOR_INIT (*tp) != NULL_TREE)
916 	{
917 	  pdata[3] = tp;
918 	  return *tp;
919 	}
920       break;
921     case BIND_EXPR:
922       if (BIND_EXPR_VARS (*tp)
923 	  || (BIND_EXPR_BLOCK (*tp)
924 	      && BLOCK_VARS (BIND_EXPR_BLOCK (*tp))))
925 	pdata[0] = tp;
926       *walk_subtrees = 1;
927       break;
928     case STATEMENT_LIST:
929       if (!tsi_one_before_end_p (tsi_start (*tp)))
930 	pdata[0] = tp;
931       *walk_subtrees = 1;
932       break;
933     case TRY_FINALLY_EXPR:
934       pdata[0] = tp;
935       *walk_subtrees = 1;
936       break;
937     case OMP_PARALLEL:
938       pdata[1] = tp;
939       *walk_subtrees = 1;
940       break;
941     default:
942       break;
943     }
944   return NULL_TREE;
945 }
946 
947 /* Return maximum possible vectorization factor for the target.  */
948 
949 poly_uint64
omp_max_vf(void)950 omp_max_vf (void)
951 {
952   if (!optimize
953       || optimize_debug
954       || !flag_tree_loop_optimize
955       || (!flag_tree_loop_vectorize
956 	  && OPTION_SET_P (flag_tree_loop_vectorize)))
957     return 1;
958 
959   auto_vector_modes modes;
960   targetm.vectorize.autovectorize_vector_modes (&modes, true);
961   if (!modes.is_empty ())
962     {
963       poly_uint64 vf = 0;
964       for (unsigned int i = 0; i < modes.length (); ++i)
965 	/* The returned modes use the smallest element size (and thus
966 	   the largest nunits) for the vectorization approach that they
967 	   represent.  */
968 	vf = ordered_max (vf, GET_MODE_NUNITS (modes[i]));
969       return vf;
970     }
971 
972   machine_mode vqimode = targetm.vectorize.preferred_simd_mode (QImode);
973   if (GET_MODE_CLASS (vqimode) == MODE_VECTOR_INT)
974     return GET_MODE_NUNITS (vqimode);
975 
976   return 1;
977 }
978 
979 /* Return maximum SIMT width if offloading may target SIMT hardware.  */
980 
981 int
omp_max_simt_vf(void)982 omp_max_simt_vf (void)
983 {
984   if (!optimize)
985     return 0;
986   if (ENABLE_OFFLOADING)
987     for (const char *c = getenv ("OFFLOAD_TARGET_NAMES"); c;)
988       {
989 	if (startswith (c, "nvptx"))
990 	  return 32;
991 	else if ((c = strchr (c, ':')))
992 	  c++;
993       }
994   return 0;
995 }
996 
997 /* Store the construct selectors as tree codes from last to first,
998    return their number.  */
999 
1000 int
omp_constructor_traits_to_codes(tree ctx,enum tree_code * constructs)1001 omp_constructor_traits_to_codes (tree ctx, enum tree_code *constructs)
1002 {
1003   int nconstructs = list_length (ctx);
1004   int i = nconstructs - 1;
1005   for (tree t2 = ctx; t2; t2 = TREE_CHAIN (t2), i--)
1006     {
1007       const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t2));
1008       if (!strcmp (sel, "target"))
1009 	constructs[i] = OMP_TARGET;
1010       else if (!strcmp (sel, "teams"))
1011 	constructs[i] = OMP_TEAMS;
1012       else if (!strcmp (sel, "parallel"))
1013 	constructs[i] = OMP_PARALLEL;
1014       else if (!strcmp (sel, "for") || !strcmp (sel, "do"))
1015 	constructs[i] = OMP_FOR;
1016       else if (!strcmp (sel, "simd"))
1017 	constructs[i] = OMP_SIMD;
1018       else
1019 	gcc_unreachable ();
1020     }
1021   gcc_assert (i == -1);
1022   return nconstructs;
1023 }
1024 
1025 /* Return true if PROP is possibly present in one of the offloading target's
1026    OpenMP contexts.  The format of PROPS string is always offloading target's
1027    name terminated by '\0', followed by properties for that offloading
1028    target separated by '\0' and terminated by another '\0'.  The strings
1029    are created from omp-device-properties installed files of all configured
1030    offloading targets.  */
1031 
1032 static bool
omp_offload_device_kind_arch_isa(const char * props,const char * prop)1033 omp_offload_device_kind_arch_isa (const char *props, const char *prop)
1034 {
1035   const char *names = getenv ("OFFLOAD_TARGET_NAMES");
1036   if (names == NULL || *names == '\0')
1037     return false;
1038   while (*props != '\0')
1039     {
1040       size_t name_len = strlen (props);
1041       bool matches = false;
1042       for (const char *c = names; c; )
1043 	{
1044 	  if (strncmp (props, c, name_len) == 0
1045 	      && (c[name_len] == '\0'
1046 		  || c[name_len] == ':'
1047 		  || c[name_len] == '='))
1048 	    {
1049 	      matches = true;
1050 	      break;
1051 	    }
1052 	  else if ((c = strchr (c, ':')))
1053 	    c++;
1054 	}
1055       props = props + name_len + 1;
1056       while (*props != '\0')
1057 	{
1058 	  if (matches && strcmp (props, prop) == 0)
1059 	    return true;
1060 	  props = strchr (props, '\0') + 1;
1061 	}
1062       props++;
1063     }
1064   return false;
1065 }
1066 
1067 /* Return true if the current code location is or might be offloaded.
1068    Return true in declare target functions, or when nested in a target
1069    region or when unsure, return false otherwise.  */
1070 
1071 static bool
omp_maybe_offloaded(void)1072 omp_maybe_offloaded (void)
1073 {
1074   if (!ENABLE_OFFLOADING)
1075     return false;
1076   const char *names = getenv ("OFFLOAD_TARGET_NAMES");
1077   if (names == NULL || *names == '\0')
1078     return false;
1079 
1080   if (symtab->state == PARSING)
1081     /* Maybe.  */
1082     return true;
1083   if (cfun && cfun->after_inlining)
1084     return false;
1085   if (current_function_decl
1086       && lookup_attribute ("omp declare target",
1087 			   DECL_ATTRIBUTES (current_function_decl)))
1088     return true;
1089   if (cfun && (cfun->curr_properties & PROP_gimple_any) == 0)
1090     {
1091       enum tree_code construct = OMP_TARGET;
1092       if (omp_construct_selector_matches (&construct, 1, NULL))
1093 	return true;
1094     }
1095   return false;
1096 }
1097 
1098 
1099 /* Diagnose errors in an OpenMP context selector, return CTX if
1100    it is correct or error_mark_node otherwise.  */
1101 
1102 tree
omp_check_context_selector(location_t loc,tree ctx)1103 omp_check_context_selector (location_t loc, tree ctx)
1104 {
1105   /* Each trait-set-selector-name can only be specified once.
1106      There are just 4 set names.  */
1107   for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
1108     for (tree t2 = TREE_CHAIN (t1); t2; t2 = TREE_CHAIN (t2))
1109       if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
1110 	{
1111 	  error_at (loc, "selector set %qs specified more than once",
1112 		    IDENTIFIER_POINTER (TREE_PURPOSE (t1)));
1113 	  return error_mark_node;
1114 	}
1115   for (tree t = ctx; t; t = TREE_CHAIN (t))
1116     {
1117       /* Each trait-selector-name can only be specified once.  */
1118       if (list_length (TREE_VALUE (t)) < 5)
1119 	{
1120 	  for (tree t1 = TREE_VALUE (t); t1; t1 = TREE_CHAIN (t1))
1121 	    for (tree t2 = TREE_CHAIN (t1); t2; t2 = TREE_CHAIN (t2))
1122 	      if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
1123 		{
1124 		  error_at (loc,
1125 			    "selector %qs specified more than once in set %qs",
1126 			    IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
1127 			    IDENTIFIER_POINTER (TREE_PURPOSE (t)));
1128 		  return error_mark_node;
1129 		}
1130 	}
1131       else
1132 	{
1133 	  hash_set<tree> pset;
1134 	  for (tree t1 = TREE_VALUE (t); t1; t1 = TREE_CHAIN (t1))
1135 	    if (pset.add (TREE_PURPOSE (t1)))
1136 	      {
1137 		error_at (loc,
1138 			  "selector %qs specified more than once in set %qs",
1139 			  IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
1140 			  IDENTIFIER_POINTER (TREE_PURPOSE (t)));
1141 		return error_mark_node;
1142 	      }
1143 	}
1144 
1145       static const char *const kind[] = {
1146 	"host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
1147       static const char *const vendor[] = {
1148 	"amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
1149 	"llvm", "nvidia", "pgi", "ti", "unknown", NULL };
1150       static const char *const extension[] = { NULL };
1151       static const char *const atomic_default_mem_order[] = {
1152 	"seq_cst", "relaxed", "acq_rel", NULL };
1153       struct known_properties { const char *set; const char *selector;
1154 				const char *const *props; };
1155       known_properties props[] = {
1156 	{ "device", "kind", kind },
1157 	{ "implementation", "vendor", vendor },
1158 	{ "implementation", "extension", extension },
1159 	{ "implementation", "atomic_default_mem_order",
1160 	  atomic_default_mem_order } };
1161       for (tree t1 = TREE_VALUE (t); t1; t1 = TREE_CHAIN (t1))
1162 	for (unsigned i = 0; i < ARRAY_SIZE (props); i++)
1163 	  if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
1164 					   props[i].selector)
1165 	      && !strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t)),
1166 					      props[i].set))
1167 	    for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
1168 	      for (unsigned j = 0; ; j++)
1169 		{
1170 		  if (props[i].props[j] == NULL)
1171 		    {
1172 		      if (TREE_PURPOSE (t2)
1173 			  && !strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
1174 				      " score"))
1175 			break;
1176 		      if (props[i].props == atomic_default_mem_order)
1177 			{
1178 			  error_at (loc,
1179 				    "incorrect property %qs of %qs selector",
1180 				    IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
1181 				    "atomic_default_mem_order");
1182 			  return error_mark_node;
1183 			}
1184 		      else if (TREE_PURPOSE (t2))
1185 			warning_at (loc, 0,
1186 				    "unknown property %qs of %qs selector",
1187 				    IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
1188 				    props[i].selector);
1189 		      else
1190 			warning_at (loc, 0,
1191 				    "unknown property %qE of %qs selector",
1192 				    TREE_VALUE (t2), props[i].selector);
1193 		      break;
1194 		    }
1195 		  else if (TREE_PURPOSE (t2) == NULL_TREE)
1196 		    {
1197 		      const char *str = TREE_STRING_POINTER (TREE_VALUE (t2));
1198 		      if (!strcmp (str, props[i].props[j])
1199 			  && ((size_t) TREE_STRING_LENGTH (TREE_VALUE (t2))
1200 			      == strlen (str) + (lang_GNU_Fortran () ? 0 : 1)))
1201 			break;
1202 		    }
1203 		  else if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
1204 				    props[i].props[j]))
1205 		    break;
1206 		}
1207     }
1208   return ctx;
1209 }
1210 
1211 
1212 /* Register VARIANT as variant of some base function marked with
1213    #pragma omp declare variant.  CONSTRUCT is corresponding construct
1214    selector set.  */
1215 
1216 void
omp_mark_declare_variant(location_t loc,tree variant,tree construct)1217 omp_mark_declare_variant (location_t loc, tree variant, tree construct)
1218 {
1219   tree attr = lookup_attribute ("omp declare variant variant",
1220 				DECL_ATTRIBUTES (variant));
1221   if (attr == NULL_TREE)
1222     {
1223       attr = tree_cons (get_identifier ("omp declare variant variant"),
1224 			unshare_expr (construct),
1225 			DECL_ATTRIBUTES (variant));
1226       DECL_ATTRIBUTES (variant) = attr;
1227       return;
1228     }
1229   if ((TREE_VALUE (attr) != NULL_TREE) != (construct != NULL_TREE)
1230       || (construct != NULL_TREE
1231 	  && omp_context_selector_set_compare ("construct", TREE_VALUE (attr),
1232 					       construct)))
1233     error_at (loc, "%qD used as a variant with incompatible %<construct%> "
1234 		   "selector sets", variant);
1235 }
1236 
1237 
1238 /* Return a name from PROP, a property in selectors accepting
1239    name lists.  */
1240 
1241 static const char *
omp_context_name_list_prop(tree prop)1242 omp_context_name_list_prop (tree prop)
1243 {
1244   if (TREE_PURPOSE (prop))
1245     return IDENTIFIER_POINTER (TREE_PURPOSE (prop));
1246   else
1247     {
1248       const char *ret = TREE_STRING_POINTER (TREE_VALUE (prop));
1249       if ((size_t) TREE_STRING_LENGTH (TREE_VALUE (prop))
1250 	  == strlen (ret) + (lang_GNU_Fortran () ? 0 : 1))
1251 	return ret;
1252       return NULL;
1253     }
1254 }
1255 
1256 /* Return 1 if context selector matches the current OpenMP context, 0
1257    if it does not and -1 if it is unknown and need to be determined later.
1258    Some properties can be checked right away during parsing (this routine),
1259    others need to wait until the whole TU is parsed, others need to wait until
1260    IPA, others until vectorization.  */
1261 
1262 int
omp_context_selector_matches(tree ctx)1263 omp_context_selector_matches (tree ctx)
1264 {
1265   int ret = 1;
1266   for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
1267     {
1268       char set = IDENTIFIER_POINTER (TREE_PURPOSE (t1))[0];
1269       if (set == 'c')
1270 	{
1271 	  /* For now, ignore the construct set.  While something can be
1272 	     determined already during parsing, we don't know until end of TU
1273 	     whether additional constructs aren't added through declare variant
1274 	     unless "omp declare variant variant" attribute exists already
1275 	     (so in most of the cases), and we'd need to maintain set of
1276 	     surrounding OpenMP constructs, which is better handled during
1277 	     gimplification.  */
1278 	  if (symtab->state == PARSING)
1279 	    {
1280 	      ret = -1;
1281 	      continue;
1282 	    }
1283 
1284 	  enum tree_code constructs[5];
1285 	  int nconstructs
1286 	    = omp_constructor_traits_to_codes (TREE_VALUE (t1), constructs);
1287 
1288 	  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1289 	    {
1290 	      if (!cfun->after_inlining)
1291 		{
1292 		  ret = -1;
1293 		  continue;
1294 		}
1295 	      int i;
1296 	      for (i = 0; i < nconstructs; ++i)
1297 		if (constructs[i] == OMP_SIMD)
1298 		  break;
1299 	      if (i < nconstructs)
1300 		{
1301 		  ret = -1;
1302 		  continue;
1303 		}
1304 	      /* If there is no simd, assume it is ok after IPA,
1305 		 constructs should have been checked before.  */
1306 	      continue;
1307 	    }
1308 
1309 	  int r = omp_construct_selector_matches (constructs, nconstructs,
1310 						  NULL);
1311 	  if (r == 0)
1312 	    return 0;
1313 	  if (r == -1)
1314 	    ret = -1;
1315 	  continue;
1316 	}
1317       for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
1318 	{
1319 	  const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t2));
1320 	  switch (*sel)
1321 	    {
1322 	    case 'v':
1323 	      if (set == 'i' && !strcmp (sel, "vendor"))
1324 		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
1325 		  {
1326 		    const char *prop = omp_context_name_list_prop (t3);
1327 		    if (prop == NULL)
1328 		      return 0;
1329 		    if ((!strcmp (prop, " score") && TREE_PURPOSE (t3))
1330 			|| !strcmp (prop, "gnu"))
1331 		      continue;
1332 		    return 0;
1333 		  }
1334 	      break;
1335 	    case 'e':
1336 	      if (set == 'i' && !strcmp (sel, "extension"))
1337 		/* We don't support any extensions right now.  */
1338 		return 0;
1339 	      break;
1340 	    case 'a':
1341 	      if (set == 'i' && !strcmp (sel, "atomic_default_mem_order"))
1342 		{
1343 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1344 		    break;
1345 
1346 		  enum omp_memory_order omo
1347 		    = ((enum omp_memory_order)
1348 		       (omp_requires_mask
1349 			& OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER));
1350 		  if (omo == OMP_MEMORY_ORDER_UNSPECIFIED)
1351 		    {
1352 		      /* We don't know yet, until end of TU.  */
1353 		      if (symtab->state == PARSING)
1354 			{
1355 			  ret = -1;
1356 			  break;
1357 			}
1358 		      else
1359 			omo = OMP_MEMORY_ORDER_RELAXED;
1360 		    }
1361 		  tree t3 = TREE_VALUE (t2);
1362 		  const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
1363 		  if (!strcmp (prop, " score"))
1364 		    {
1365 		      t3 = TREE_CHAIN (t3);
1366 		      prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
1367 		    }
1368 		  if (!strcmp (prop, "relaxed")
1369 		      && omo != OMP_MEMORY_ORDER_RELAXED)
1370 		    return 0;
1371 		  else if (!strcmp (prop, "seq_cst")
1372 			   && omo != OMP_MEMORY_ORDER_SEQ_CST)
1373 		    return 0;
1374 		  else if (!strcmp (prop, "acq_rel")
1375 			   && omo != OMP_MEMORY_ORDER_ACQ_REL)
1376 		    return 0;
1377 		}
1378 	      if (set == 'd' && !strcmp (sel, "arch"))
1379 		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
1380 		  {
1381 		    const char *arch = omp_context_name_list_prop (t3);
1382 		    if (arch == NULL)
1383 		      return 0;
1384 		    int r = 0;
1385 		    if (targetm.omp.device_kind_arch_isa != NULL)
1386 		      r = targetm.omp.device_kind_arch_isa (omp_device_arch,
1387 							    arch);
1388 		    if (r == 0 || (r == -1 && symtab->state != PARSING))
1389 		      {
1390 			/* If we are or might be in a target region or
1391 			   declare target function, need to take into account
1392 			   also offloading values.  */
1393 			if (!omp_maybe_offloaded ())
1394 			  return 0;
1395 			if (ENABLE_OFFLOADING)
1396 			  {
1397 			    const char *arches = omp_offload_device_arch;
1398 			    if (omp_offload_device_kind_arch_isa (arches,
1399 								  arch))
1400 			      {
1401 				ret = -1;
1402 				continue;
1403 			      }
1404 			  }
1405 			return 0;
1406 		      }
1407 		    else if (r == -1)
1408 		      ret = -1;
1409 		    /* If arch matches on the host, it still might not match
1410 		       in the offloading region.  */
1411 		    else if (omp_maybe_offloaded ())
1412 		      ret = -1;
1413 		  }
1414 	      break;
1415 	    case 'u':
1416 	      if (set == 'i' && !strcmp (sel, "unified_address"))
1417 		{
1418 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1419 		    break;
1420 
1421 		  if ((omp_requires_mask & OMP_REQUIRES_UNIFIED_ADDRESS) == 0)
1422 		    {
1423 		      if (symtab->state == PARSING)
1424 			ret = -1;
1425 		      else
1426 			return 0;
1427 		    }
1428 		  break;
1429 		}
1430 	      if (set == 'i' && !strcmp (sel, "unified_shared_memory"))
1431 		{
1432 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1433 		    break;
1434 
1435 		  if ((omp_requires_mask
1436 		       & OMP_REQUIRES_UNIFIED_SHARED_MEMORY) == 0)
1437 		    {
1438 		      if (symtab->state == PARSING)
1439 			ret = -1;
1440 		      else
1441 			return 0;
1442 		    }
1443 		  break;
1444 		}
1445 	      break;
1446 	    case 'd':
1447 	      if (set == 'i' && !strcmp (sel, "dynamic_allocators"))
1448 		{
1449 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1450 		    break;
1451 
1452 		  if ((omp_requires_mask
1453 		       & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0)
1454 		    {
1455 		      if (symtab->state == PARSING)
1456 			ret = -1;
1457 		      else
1458 			return 0;
1459 		    }
1460 		  break;
1461 		}
1462 	      break;
1463 	    case 'r':
1464 	      if (set == 'i' && !strcmp (sel, "reverse_offload"))
1465 		{
1466 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
1467 		    break;
1468 
1469 		  if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0)
1470 		    {
1471 		      if (symtab->state == PARSING)
1472 			ret = -1;
1473 		      else
1474 			return 0;
1475 		    }
1476 		  break;
1477 		}
1478 	      break;
1479 	    case 'k':
1480 	      if (set == 'd' && !strcmp (sel, "kind"))
1481 		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
1482 		  {
1483 		    const char *prop = omp_context_name_list_prop (t3);
1484 		    if (prop == NULL)
1485 		      return 0;
1486 		    if (!strcmp (prop, "any"))
1487 		      continue;
1488 		    if (!strcmp (prop, "host"))
1489 		      {
1490 #ifdef ACCEL_COMPILER
1491 			return 0;
1492 #else
1493 			if (omp_maybe_offloaded ())
1494 			  ret = -1;
1495 			continue;
1496 #endif
1497 		      }
1498 		    if (!strcmp (prop, "nohost"))
1499 		      {
1500 #ifndef ACCEL_COMPILER
1501 			if (omp_maybe_offloaded ())
1502 			  ret = -1;
1503 			else
1504 			  return 0;
1505 #endif
1506 			continue;
1507 		      }
1508 		    int r = 0;
1509 		    if (targetm.omp.device_kind_arch_isa != NULL)
1510 		      r = targetm.omp.device_kind_arch_isa (omp_device_kind,
1511 							    prop);
1512 		    else
1513 		      r = strcmp (prop, "cpu") == 0;
1514 		    if (r == 0 || (r == -1 && symtab->state != PARSING))
1515 		      {
1516 			/* If we are or might be in a target region or
1517 			   declare target function, need to take into account
1518 			   also offloading values.  */
1519 			if (!omp_maybe_offloaded ())
1520 			  return 0;
1521 			if (ENABLE_OFFLOADING)
1522 			  {
1523 			    const char *kinds = omp_offload_device_kind;
1524 			    if (omp_offload_device_kind_arch_isa (kinds, prop))
1525 			      {
1526 				ret = -1;
1527 				continue;
1528 			      }
1529 			  }
1530 			return 0;
1531 		      }
1532 		    else if (r == -1)
1533 		      ret = -1;
1534 		    /* If kind matches on the host, it still might not match
1535 		       in the offloading region.  */
1536 		    else if (omp_maybe_offloaded ())
1537 		      ret = -1;
1538 		  }
1539 	      break;
1540 	    case 'i':
1541 	      if (set == 'd' && !strcmp (sel, "isa"))
1542 		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
1543 		  {
1544 		    const char *isa = omp_context_name_list_prop (t3);
1545 		    if (isa == NULL)
1546 		      return 0;
1547 		    int r = 0;
1548 		    if (targetm.omp.device_kind_arch_isa != NULL)
1549 		      r = targetm.omp.device_kind_arch_isa (omp_device_isa,
1550 							    isa);
1551 		    if (r == 0 || (r == -1 && symtab->state != PARSING))
1552 		      {
1553 			/* If isa is valid on the target, but not in the
1554 			   current function and current function has
1555 			   #pragma omp declare simd on it, some simd clones
1556 			   might have the isa added later on.  */
1557 			if (r == -1
1558 			    && targetm.simd_clone.compute_vecsize_and_simdlen
1559 			    && (cfun == NULL || !cfun->after_inlining))
1560 			  {
1561 			    tree attrs
1562 			      = DECL_ATTRIBUTES (current_function_decl);
1563 			    if (lookup_attribute ("omp declare simd", attrs))
1564 			      {
1565 				ret = -1;
1566 				continue;
1567 			      }
1568 			  }
1569 			/* If we are or might be in a target region or
1570 			   declare target function, need to take into account
1571 			   also offloading values.  */
1572 			if (!omp_maybe_offloaded ())
1573 			  return 0;
1574 			if (ENABLE_OFFLOADING)
1575 			  {
1576 			    const char *isas = omp_offload_device_isa;
1577 			    if (omp_offload_device_kind_arch_isa (isas, isa))
1578 			      {
1579 				ret = -1;
1580 				continue;
1581 			      }
1582 			  }
1583 			return 0;
1584 		      }
1585 		    else if (r == -1)
1586 		      ret = -1;
1587 		    /* If isa matches on the host, it still might not match
1588 		       in the offloading region.  */
1589 		    else if (omp_maybe_offloaded ())
1590 		      ret = -1;
1591 		  }
1592 	      break;
1593 	    case 'c':
1594 	      if (set == 'u' && !strcmp (sel, "condition"))
1595 		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
1596 		  if (TREE_PURPOSE (t3) == NULL_TREE)
1597 		    {
1598 		      if (integer_zerop (TREE_VALUE (t3)))
1599 			return 0;
1600 		      if (integer_nonzerop (TREE_VALUE (t3)))
1601 			break;
1602 		      ret = -1;
1603 		    }
1604 	      break;
1605 	    default:
1606 	      break;
1607 	    }
1608 	}
1609     }
1610   return ret;
1611 }
1612 
1613 /* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as
1614    in omp_context_selector_set_compare.  */
1615 
1616 static int
omp_construct_simd_compare(tree clauses1,tree clauses2)1617 omp_construct_simd_compare (tree clauses1, tree clauses2)
1618 {
1619   if (clauses1 == NULL_TREE)
1620     return clauses2 == NULL_TREE ? 0 : -1;
1621   if (clauses2 == NULL_TREE)
1622     return 1;
1623 
1624   int r = 0;
1625   struct declare_variant_simd_data {
1626     bool inbranch, notinbranch;
1627     tree simdlen;
1628     auto_vec<tree,16> data_sharing;
1629     auto_vec<tree,16> aligned;
1630     declare_variant_simd_data ()
1631       : inbranch(false), notinbranch(false), simdlen(NULL_TREE) {}
1632   } data[2];
1633   unsigned int i;
1634   for (i = 0; i < 2; i++)
1635     for (tree c = i ? clauses2 : clauses1; c; c = OMP_CLAUSE_CHAIN (c))
1636       {
1637 	vec<tree> *v;
1638 	switch (OMP_CLAUSE_CODE (c))
1639 	  {
1640 	  case OMP_CLAUSE_INBRANCH:
1641 	    data[i].inbranch = true;
1642 	    continue;
1643 	  case OMP_CLAUSE_NOTINBRANCH:
1644 	    data[i].notinbranch = true;
1645 	    continue;
1646 	  case OMP_CLAUSE_SIMDLEN:
1647 	    data[i].simdlen = OMP_CLAUSE_SIMDLEN_EXPR (c);
1648 	    continue;
1649 	  case OMP_CLAUSE_UNIFORM:
1650 	  case OMP_CLAUSE_LINEAR:
1651 	    v = &data[i].data_sharing;
1652 	    break;
1653 	  case OMP_CLAUSE_ALIGNED:
1654 	    v = &data[i].aligned;
1655 	    break;
1656 	  default:
1657 	    gcc_unreachable ();
1658 	  }
1659 	unsigned HOST_WIDE_INT argno = tree_to_uhwi (OMP_CLAUSE_DECL (c));
1660 	if (argno >= v->length ())
1661 	  v->safe_grow_cleared (argno + 1, true);
1662 	(*v)[argno] = c;
1663       }
1664   /* Here, r is used as a bitmask, 2 is set if CLAUSES1 has something
1665      CLAUSES2 doesn't, 1 is set if CLAUSES2 has something CLAUSES1
1666      doesn't.  Thus, r == 3 implies return value 2, r == 1 implies
1667      -1, r == 2 implies 1 and r == 0 implies 0.  */
1668   if (data[0].inbranch != data[1].inbranch)
1669     r |= data[0].inbranch ? 2 : 1;
1670   if (data[0].notinbranch != data[1].notinbranch)
1671     r |= data[0].notinbranch ? 2 : 1;
1672   if (!simple_cst_equal (data[0].simdlen, data[1].simdlen))
1673     {
1674       if (data[0].simdlen && data[1].simdlen)
1675 	return 2;
1676       r |= data[0].simdlen ? 2 : 1;
1677     }
1678   if (data[0].data_sharing.length () < data[1].data_sharing.length ()
1679       || data[0].aligned.length () < data[1].aligned.length ())
1680     r |= 1;
1681   tree c1, c2;
1682   FOR_EACH_VEC_ELT (data[0].data_sharing, i, c1)
1683     {
1684       c2 = (i < data[1].data_sharing.length ()
1685 	    ? data[1].data_sharing[i] : NULL_TREE);
1686       if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
1687 	{
1688 	  r |= c1 != NULL_TREE ? 2 : 1;
1689 	  continue;
1690 	}
1691       if (c1 == NULL_TREE)
1692 	continue;
1693       if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_CODE (c2))
1694 	return 2;
1695       if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_LINEAR)
1696 	continue;
1697       if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1)
1698 	  != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2))
1699 	return 2;
1700       if (OMP_CLAUSE_LINEAR_KIND (c1) != OMP_CLAUSE_LINEAR_KIND (c2))
1701 	return 2;
1702       if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1),
1703 			     OMP_CLAUSE_LINEAR_STEP (c2)))
1704 	return 2;
1705     }
1706   FOR_EACH_VEC_ELT (data[0].aligned, i, c1)
1707     {
1708       c2 = i < data[1].aligned.length () ? data[1].aligned[i] : NULL_TREE;
1709       if ((c1 == NULL_TREE) != (c2 == NULL_TREE))
1710 	{
1711 	  r |= c1 != NULL_TREE ? 2 : 1;
1712 	  continue;
1713 	}
1714       if (c1 == NULL_TREE)
1715 	continue;
1716       if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1),
1717 			     OMP_CLAUSE_ALIGNED_ALIGNMENT (c2)))
1718 	return 2;
1719     }
1720   switch (r)
1721     {
1722     case 0: return 0;
1723     case 1: return -1;
1724     case 2: return 1;
1725     case 3: return 2;
1726     default: gcc_unreachable ();
1727     }
1728 }
1729 
1730 /* Compare properties of selectors SEL from SET other than construct.
1731    Return 0/-1/1/2 as in omp_context_selector_set_compare.
1732    Unlike set names or selector names, properties can have duplicates.  */
1733 
1734 static int
omp_context_selector_props_compare(const char * set,const char * sel,tree ctx1,tree ctx2)1735 omp_context_selector_props_compare (const char *set, const char *sel,
1736 				    tree ctx1, tree ctx2)
1737 {
1738   int ret = 0;
1739   for (int pass = 0; pass < 2; pass++)
1740     for (tree t1 = pass ? ctx2 : ctx1; t1; t1 = TREE_CHAIN (t1))
1741       {
1742 	tree t2;
1743 	for (t2 = pass ? ctx1 : ctx2; t2; t2 = TREE_CHAIN (t2))
1744 	  if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
1745 	    {
1746 	      if (TREE_PURPOSE (t1) == NULL_TREE)
1747 		{
1748 		  if (set[0] == 'u' && strcmp (sel, "condition") == 0)
1749 		    {
1750 		      if (integer_zerop (TREE_VALUE (t1))
1751 			  != integer_zerop (TREE_VALUE (t2)))
1752 			return 2;
1753 		      break;
1754 		    }
1755 		  if (simple_cst_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
1756 		    break;
1757 		}
1758 	      else if (strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
1759 			       " score") == 0)
1760 		{
1761 		  if (!simple_cst_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
1762 		    return 2;
1763 		  break;
1764 		}
1765 	      else
1766 		break;
1767 	    }
1768 	  else if (TREE_PURPOSE (t1)
1769 		   && TREE_PURPOSE (t2) == NULL_TREE
1770 		   && TREE_CODE (TREE_VALUE (t2)) == STRING_CST)
1771 	    {
1772 	      const char *p1 = omp_context_name_list_prop (t1);
1773 	      const char *p2 = omp_context_name_list_prop (t2);
1774 	      if (p2
1775 		  && strcmp (p1, p2) == 0
1776 		  && strcmp (p1, " score"))
1777 		break;
1778 	    }
1779 	  else if (TREE_PURPOSE (t1) == NULL_TREE
1780 		   && TREE_PURPOSE (t2)
1781 		   && TREE_CODE (TREE_VALUE (t1)) == STRING_CST)
1782 	    {
1783 	      const char *p1 = omp_context_name_list_prop (t1);
1784 	      const char *p2 = omp_context_name_list_prop (t2);
1785 	      if (p1
1786 		  && strcmp (p1, p2) == 0
1787 		  && strcmp (p1, " score"))
1788 		break;
1789 	    }
1790 	if (t2 == NULL_TREE)
1791 	  {
1792 	    int r = pass ? -1 : 1;
1793 	    if (ret && ret != r)
1794 	      return 2;
1795 	    else if (pass)
1796 	      return r;
1797 	    else
1798 	      {
1799 		ret = r;
1800 		break;
1801 	      }
1802 	  }
1803       }
1804   return ret;
1805 }
1806 
1807 /* Compare single context selector sets CTX1 and CTX2 with SET name.
1808    Return 0 if CTX1 is equal to CTX2,
1809    -1 if CTX1 is a strict subset of CTX2,
1810    1 if CTX2 is a strict subset of CTX1, or
1811    2 if neither context is a subset of another one.  */
1812 
1813 int
omp_context_selector_set_compare(const char * set,tree ctx1,tree ctx2)1814 omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
1815 {
1816   bool swapped = false;
1817   int ret = 0;
1818   int len1 = list_length (ctx1);
1819   int len2 = list_length (ctx2);
1820   int cnt = 0;
1821   if (len1 < len2)
1822     {
1823       swapped = true;
1824       std::swap (ctx1, ctx2);
1825       std::swap (len1, len2);
1826     }
1827   if (set[0] == 'c')
1828     {
1829       tree t1;
1830       tree t2 = ctx2;
1831       tree simd = get_identifier ("simd");
1832       /* Handle construct set specially.  In this case the order
1833 	 of the selector matters too.  */
1834       for (t1 = ctx1; t1; t1 = TREE_CHAIN (t1))
1835 	if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
1836 	  {
1837 	    int r = 0;
1838 	    if (TREE_PURPOSE (t1) == simd)
1839 	      r = omp_construct_simd_compare (TREE_VALUE (t1),
1840 					      TREE_VALUE (t2));
1841 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
1842 	      return 2;
1843 	    if (ret == 0)
1844 	      ret = r;
1845 	    t2 = TREE_CHAIN (t2);
1846 	    if (t2 == NULL_TREE)
1847 	      {
1848 		t1 = TREE_CHAIN (t1);
1849 		break;
1850 	      }
1851 	  }
1852 	else if (ret < 0)
1853 	  return 2;
1854 	else
1855 	  ret = 1;
1856       if (t2 != NULL_TREE)
1857 	return 2;
1858       if (t1 != NULL_TREE)
1859 	{
1860 	  if (ret < 0)
1861 	    return 2;
1862 	  ret = 1;
1863 	}
1864       if (ret == 0)
1865 	return 0;
1866       return swapped ? -ret : ret;
1867     }
1868   for (tree t1 = ctx1; t1; t1 = TREE_CHAIN (t1))
1869     {
1870       tree t2;
1871       for (t2 = ctx2; t2; t2 = TREE_CHAIN (t2))
1872 	if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
1873 	  {
1874 	    const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t1));
1875 	    int r = omp_context_selector_props_compare (set, sel,
1876 							TREE_VALUE (t1),
1877 							TREE_VALUE (t2));
1878 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
1879 	      return 2;
1880 	    if (ret == 0)
1881 	      ret = r;
1882 	    cnt++;
1883 	    break;
1884 	  }
1885       if (t2 == NULL_TREE)
1886 	{
1887 	  if (ret == -1)
1888 	    return 2;
1889 	  ret = 1;
1890 	}
1891     }
1892   if (cnt < len2)
1893     return 2;
1894   if (ret == 0)
1895     return 0;
1896   return swapped ? -ret : ret;
1897 }
1898 
1899 /* Compare whole context selector specification CTX1 and CTX2.
1900    Return 0 if CTX1 is equal to CTX2,
1901    -1 if CTX1 is a strict subset of CTX2,
1902    1 if CTX2 is a strict subset of CTX1, or
1903    2 if neither context is a subset of another one.  */
1904 
1905 static int
omp_context_selector_compare(tree ctx1,tree ctx2)1906 omp_context_selector_compare (tree ctx1, tree ctx2)
1907 {
1908   bool swapped = false;
1909   int ret = 0;
1910   int len1 = list_length (ctx1);
1911   int len2 = list_length (ctx2);
1912   int cnt = 0;
1913   if (len1 < len2)
1914     {
1915       swapped = true;
1916       std::swap (ctx1, ctx2);
1917       std::swap (len1, len2);
1918     }
1919   for (tree t1 = ctx1; t1; t1 = TREE_CHAIN (t1))
1920     {
1921       tree t2;
1922       for (t2 = ctx2; t2; t2 = TREE_CHAIN (t2))
1923 	if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
1924 	  {
1925 	    const char *set = IDENTIFIER_POINTER (TREE_PURPOSE (t1));
1926 	    int r = omp_context_selector_set_compare (set, TREE_VALUE (t1),
1927 						      TREE_VALUE (t2));
1928 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
1929 	      return 2;
1930 	    if (ret == 0)
1931 	      ret = r;
1932 	    cnt++;
1933 	    break;
1934 	  }
1935       if (t2 == NULL_TREE)
1936 	{
1937 	  if (ret == -1)
1938 	    return 2;
1939 	  ret = 1;
1940 	}
1941     }
1942   if (cnt < len2)
1943     return 2;
1944   if (ret == 0)
1945     return 0;
1946   return swapped ? -ret : ret;
1947 }
1948 
1949 /* From context selector CTX, return trait-selector with name SEL in
1950    trait-selector-set with name SET if any, or NULL_TREE if not found.
1951    If SEL is NULL, return the list of trait-selectors in SET.  */
1952 
1953 tree
omp_get_context_selector(tree ctx,const char * set,const char * sel)1954 omp_get_context_selector (tree ctx, const char *set, const char *sel)
1955 {
1956   tree setid = get_identifier (set);
1957   tree selid = sel ? get_identifier (sel) : NULL_TREE;
1958   for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
1959     if (TREE_PURPOSE (t1) == setid)
1960       {
1961 	if (sel == NULL)
1962 	  return TREE_VALUE (t1);
1963 	for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
1964 	  if (TREE_PURPOSE (t2) == selid)
1965 	    return t2;
1966       }
1967   return NULL_TREE;
1968 }
1969 
1970 /* Compute *SCORE for context selector CTX.  Return true if the score
1971    would be different depending on whether it is a declare simd clone or
1972    not.  DECLARE_SIMD should be true for the case when it would be
1973    a declare simd clone.  */
1974 
1975 static bool
omp_context_compute_score(tree ctx,widest_int * score,bool declare_simd)1976 omp_context_compute_score (tree ctx, widest_int *score, bool declare_simd)
1977 {
1978   tree construct = omp_get_context_selector (ctx, "construct", NULL);
1979   bool has_kind = omp_get_context_selector (ctx, "device", "kind");
1980   bool has_arch = omp_get_context_selector (ctx, "device", "arch");
1981   bool has_isa = omp_get_context_selector (ctx, "device", "isa");
1982   bool ret = false;
1983   *score = 1;
1984   for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
1985     if (TREE_VALUE (t1) != construct)
1986       for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
1987 	if (tree t3 = TREE_VALUE (t2))
1988 	  if (TREE_PURPOSE (t3)
1989 	      && strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t3)), " score") == 0
1990 	      && TREE_CODE (TREE_VALUE (t3)) == INTEGER_CST)
1991 	    *score += wi::to_widest (TREE_VALUE (t3));
1992   if (construct || has_kind || has_arch || has_isa)
1993     {
1994       int scores[12];
1995       enum tree_code constructs[5];
1996       int nconstructs = 0;
1997       if (construct)
1998 	nconstructs = omp_constructor_traits_to_codes (construct, constructs);
1999       if (omp_construct_selector_matches (constructs, nconstructs, scores)
2000 	  == 2)
2001 	ret = true;
2002       int b = declare_simd ? nconstructs + 1 : 0;
2003       if (scores[b + nconstructs] + 4U < score->get_precision ())
2004 	{
2005 	  for (int n = 0; n < nconstructs; ++n)
2006 	    {
2007 	      if (scores[b + n] < 0)
2008 		{
2009 		  *score = -1;
2010 		  return ret;
2011 		}
2012 	      *score += wi::shifted_mask <widest_int> (scores[b + n], 1, false);
2013 	    }
2014 	  if (has_kind)
2015 	    *score += wi::shifted_mask <widest_int> (scores[b + nconstructs],
2016 						     1, false);
2017 	  if (has_arch)
2018 	    *score += wi::shifted_mask <widest_int> (scores[b + nconstructs] + 1,
2019 						     1, false);
2020 	  if (has_isa)
2021 	    *score += wi::shifted_mask <widest_int> (scores[b + nconstructs] + 2,
2022 						     1, false);
2023 	}
2024       else /* FIXME: Implement this.  */
2025 	gcc_unreachable ();
2026     }
2027   return ret;
2028 }
2029 
2030 /* Class describing a single variant.  */
2031 struct GTY(()) omp_declare_variant_entry {
2032   /* NODE of the variant.  */
2033   cgraph_node *variant;
2034   /* Score if not in declare simd clone.  */
2035   widest_int score;
2036   /* Score if in declare simd clone.  */
2037   widest_int score_in_declare_simd_clone;
2038   /* Context selector for the variant.  */
2039   tree ctx;
2040   /* True if the context selector is known to match already.  */
2041   bool matches;
2042 };
2043 
2044 /* Class describing a function with variants.  */
2045 struct GTY((for_user)) omp_declare_variant_base_entry {
2046   /* NODE of the base function.  */
2047   cgraph_node *base;
2048   /* NODE of the artificial function created for the deferred variant
2049      resolution.  */
2050   cgraph_node *node;
2051   /* Vector of the variants.  */
2052   vec<omp_declare_variant_entry, va_gc> *variants;
2053 };
2054 
2055 struct omp_declare_variant_hasher
2056   : ggc_ptr_hash<omp_declare_variant_base_entry> {
2057   static hashval_t hash (omp_declare_variant_base_entry *);
2058   static bool equal (omp_declare_variant_base_entry *,
2059 		     omp_declare_variant_base_entry *);
2060 };
2061 
2062 hashval_t
hash(omp_declare_variant_base_entry * x)2063 omp_declare_variant_hasher::hash (omp_declare_variant_base_entry *x)
2064 {
2065   inchash::hash hstate;
2066   hstate.add_int (DECL_UID (x->base->decl));
2067   hstate.add_int (x->variants->length ());
2068   omp_declare_variant_entry *variant;
2069   unsigned int i;
2070   FOR_EACH_VEC_SAFE_ELT (x->variants, i, variant)
2071     {
2072       hstate.add_int (DECL_UID (variant->variant->decl));
2073       hstate.add_wide_int (variant->score);
2074       hstate.add_wide_int (variant->score_in_declare_simd_clone);
2075       hstate.add_ptr (variant->ctx);
2076       hstate.add_int (variant->matches);
2077     }
2078   return hstate.end ();
2079 }
2080 
2081 bool
equal(omp_declare_variant_base_entry * x,omp_declare_variant_base_entry * y)2082 omp_declare_variant_hasher::equal (omp_declare_variant_base_entry *x,
2083 				   omp_declare_variant_base_entry *y)
2084 {
2085   if (x->base != y->base
2086       || x->variants->length () != y->variants->length ())
2087     return false;
2088   omp_declare_variant_entry *variant;
2089   unsigned int i;
2090   FOR_EACH_VEC_SAFE_ELT (x->variants, i, variant)
2091     if (variant->variant != (*y->variants)[i].variant
2092 	|| variant->score != (*y->variants)[i].score
2093 	|| (variant->score_in_declare_simd_clone
2094 	    != (*y->variants)[i].score_in_declare_simd_clone)
2095 	|| variant->ctx != (*y->variants)[i].ctx
2096 	|| variant->matches != (*y->variants)[i].matches)
2097       return false;
2098   return true;
2099 }
2100 
2101 static GTY(()) hash_table<omp_declare_variant_hasher> *omp_declare_variants;
2102 
2103 struct omp_declare_variant_alt_hasher
2104   : ggc_ptr_hash<omp_declare_variant_base_entry> {
2105   static hashval_t hash (omp_declare_variant_base_entry *);
2106   static bool equal (omp_declare_variant_base_entry *,
2107 		     omp_declare_variant_base_entry *);
2108 };
2109 
2110 hashval_t
hash(omp_declare_variant_base_entry * x)2111 omp_declare_variant_alt_hasher::hash (omp_declare_variant_base_entry *x)
2112 {
2113   return DECL_UID (x->node->decl);
2114 }
2115 
2116 bool
equal(omp_declare_variant_base_entry * x,omp_declare_variant_base_entry * y)2117 omp_declare_variant_alt_hasher::equal (omp_declare_variant_base_entry *x,
2118 				       omp_declare_variant_base_entry *y)
2119 {
2120   return x->node == y->node;
2121 }
2122 
2123 static GTY(()) hash_table<omp_declare_variant_alt_hasher>
2124   *omp_declare_variant_alt;
2125 
2126 /* Try to resolve declare variant after gimplification.  */
2127 
2128 static tree
omp_resolve_late_declare_variant(tree alt)2129 omp_resolve_late_declare_variant (tree alt)
2130 {
2131   cgraph_node *node = cgraph_node::get (alt);
2132   cgraph_node *cur_node = cgraph_node::get (cfun->decl);
2133   if (node == NULL
2134       || !node->declare_variant_alt
2135       || !cfun->after_inlining)
2136     return alt;
2137 
2138   omp_declare_variant_base_entry entry;
2139   entry.base = NULL;
2140   entry.node = node;
2141   entry.variants = NULL;
2142   omp_declare_variant_base_entry *entryp
2143     = omp_declare_variant_alt->find_with_hash (&entry, DECL_UID (alt));
2144 
2145   unsigned int i, j;
2146   omp_declare_variant_entry *varentry1, *varentry2;
2147   auto_vec <bool, 16> matches;
2148   unsigned int nmatches = 0;
2149   FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
2150     {
2151       if (varentry1->matches)
2152 	{
2153 	  /* This has been checked to be ok already.  */
2154 	  matches.safe_push (true);
2155 	  nmatches++;
2156 	  continue;
2157 	}
2158       switch (omp_context_selector_matches (varentry1->ctx))
2159 	{
2160 	case 0:
2161           matches.safe_push (false);
2162 	  break;
2163 	case -1:
2164 	  return alt;
2165 	default:
2166 	  matches.safe_push (true);
2167 	  nmatches++;
2168 	  break;
2169 	}
2170     }
2171 
2172   if (nmatches == 0)
2173     return entryp->base->decl;
2174 
2175   /* A context selector that is a strict subset of another context selector
2176      has a score of zero.  */
2177   FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
2178     if (matches[i])
2179       {
2180         for (j = i + 1;
2181 	     vec_safe_iterate (entryp->variants, j, &varentry2); ++j)
2182 	  if (matches[j])
2183 	    {
2184 	      int r = omp_context_selector_compare (varentry1->ctx,
2185 						    varentry2->ctx);
2186 	      if (r == -1)
2187 		{
2188 		  /* ctx1 is a strict subset of ctx2, ignore ctx1.  */
2189 		  matches[i] = false;
2190 		  break;
2191 		}
2192 	      else if (r == 1)
2193 		/* ctx2 is a strict subset of ctx1, remove ctx2.  */
2194 		matches[j] = false;
2195 	    }
2196       }
2197 
2198   widest_int max_score = -1;
2199   varentry2 = NULL;
2200   FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry1)
2201     if (matches[i])
2202       {
2203 	widest_int score
2204 	  = (cur_node->simdclone ? varentry1->score_in_declare_simd_clone
2205 	     : varentry1->score);
2206 	if (score > max_score)
2207 	  {
2208 	    max_score = score;
2209 	    varentry2 = varentry1;
2210 	  }
2211       }
2212   return varentry2->variant->decl;
2213 }
2214 
2215 /* Hook to adjust hash tables on cgraph_node removal.  */
2216 
2217 static void
omp_declare_variant_remove_hook(struct cgraph_node * node,void *)2218 omp_declare_variant_remove_hook (struct cgraph_node *node, void *)
2219 {
2220   if (!node->declare_variant_alt)
2221     return;
2222 
2223   /* Drop this hash table completely.  */
2224   omp_declare_variants = NULL;
2225   /* And remove node from the other hash table.  */
2226   if (omp_declare_variant_alt)
2227     {
2228       omp_declare_variant_base_entry entry;
2229       entry.base = NULL;
2230       entry.node = node;
2231       entry.variants = NULL;
2232       omp_declare_variant_alt->remove_elt_with_hash (&entry,
2233 						     DECL_UID (node->decl));
2234     }
2235 }
2236 
2237 /* Try to resolve declare variant, return the variant decl if it should
2238    be used instead of base, or base otherwise.  */
2239 
2240 tree
omp_resolve_declare_variant(tree base)2241 omp_resolve_declare_variant (tree base)
2242 {
2243   tree variant1 = NULL_TREE, variant2 = NULL_TREE;
2244   if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
2245     return omp_resolve_late_declare_variant (base);
2246 
2247   auto_vec <tree, 16> variants;
2248   auto_vec <bool, 16> defer;
2249   bool any_deferred = false;
2250   for (tree attr = DECL_ATTRIBUTES (base); attr; attr = TREE_CHAIN (attr))
2251     {
2252       attr = lookup_attribute ("omp declare variant base", attr);
2253       if (attr == NULL_TREE)
2254 	break;
2255       if (TREE_CODE (TREE_PURPOSE (TREE_VALUE (attr))) != FUNCTION_DECL)
2256 	continue;
2257       cgraph_node *node = cgraph_node::get (base);
2258       /* If this is already a magic decl created by this function,
2259 	 don't process it again.  */
2260       if (node && node->declare_variant_alt)
2261 	return base;
2262       switch (omp_context_selector_matches (TREE_VALUE (TREE_VALUE (attr))))
2263 	{
2264 	case 0:
2265 	  /* No match, ignore.  */
2266 	  break;
2267 	case -1:
2268 	  /* Needs to be deferred.  */
2269 	  any_deferred = true;
2270 	  variants.safe_push (attr);
2271 	  defer.safe_push (true);
2272 	  break;
2273 	default:
2274 	  variants.safe_push (attr);
2275 	  defer.safe_push (false);
2276 	  break;
2277 	}
2278     }
2279   if (variants.length () == 0)
2280     return base;
2281 
2282   if (any_deferred)
2283     {
2284       widest_int max_score1 = 0;
2285       widest_int max_score2 = 0;
2286       bool first = true;
2287       unsigned int i;
2288       tree attr1, attr2;
2289       omp_declare_variant_base_entry entry;
2290       entry.base = cgraph_node::get_create (base);
2291       entry.node = NULL;
2292       vec_alloc (entry.variants, variants.length ());
2293       FOR_EACH_VEC_ELT (variants, i, attr1)
2294 	{
2295 	  widest_int score1;
2296 	  widest_int score2;
2297 	  bool need_two;
2298 	  tree ctx = TREE_VALUE (TREE_VALUE (attr1));
2299 	  need_two = omp_context_compute_score (ctx, &score1, false);
2300 	  if (need_two)
2301 	    omp_context_compute_score (ctx, &score2, true);
2302 	  else
2303 	    score2 = score1;
2304 	  if (first)
2305 	    {
2306 	      first = false;
2307 	      max_score1 = score1;
2308 	      max_score2 = score2;
2309 	      if (!defer[i])
2310 		{
2311 		  variant1 = attr1;
2312 		  variant2 = attr1;
2313 		}
2314 	    }
2315 	  else
2316 	    {
2317 	      if (max_score1 == score1)
2318 		variant1 = NULL_TREE;
2319 	      else if (score1 > max_score1)
2320 		{
2321 		  max_score1 = score1;
2322 		  variant1 = defer[i] ? NULL_TREE : attr1;
2323 		}
2324 	      if (max_score2 == score2)
2325 		variant2 = NULL_TREE;
2326 	      else if (score2 > max_score2)
2327 		{
2328 		  max_score2 = score2;
2329 		  variant2 = defer[i] ? NULL_TREE : attr1;
2330 		}
2331 	    }
2332 	  omp_declare_variant_entry varentry;
2333 	  varentry.variant
2334 	    = cgraph_node::get_create (TREE_PURPOSE (TREE_VALUE (attr1)));
2335 	  varentry.score = score1;
2336 	  varentry.score_in_declare_simd_clone = score2;
2337 	  varentry.ctx = ctx;
2338 	  varentry.matches = !defer[i];
2339 	  entry.variants->quick_push (varentry);
2340 	}
2341 
2342       /* If there is a clear winner variant with the score which is not
2343 	 deferred, verify it is not a strict subset of any other context
2344 	 selector and if it is not, it is the best alternative no matter
2345 	 whether the others do or don't match.  */
2346       if (variant1 && variant1 == variant2)
2347 	{
2348 	  tree ctx1 = TREE_VALUE (TREE_VALUE (variant1));
2349 	  FOR_EACH_VEC_ELT (variants, i, attr2)
2350 	    {
2351 	      if (attr2 == variant1)
2352 		continue;
2353 	      tree ctx2 = TREE_VALUE (TREE_VALUE (attr2));
2354 	      int r = omp_context_selector_compare (ctx1, ctx2);
2355 	      if (r == -1)
2356 		{
2357 		  /* The winner is a strict subset of ctx2, can't
2358 		     decide now.  */
2359 		  variant1 = NULL_TREE;
2360 		  break;
2361 		}
2362 	    }
2363 	  if (variant1)
2364 	    {
2365 	      vec_free (entry.variants);
2366 	      return TREE_PURPOSE (TREE_VALUE (variant1));
2367 	    }
2368 	}
2369 
2370       static struct cgraph_node_hook_list *node_removal_hook_holder;
2371       if (!node_removal_hook_holder)
2372 	node_removal_hook_holder
2373 	  = symtab->add_cgraph_removal_hook (omp_declare_variant_remove_hook,
2374 					     NULL);
2375 
2376       if (omp_declare_variants == NULL)
2377 	omp_declare_variants
2378 	  = hash_table<omp_declare_variant_hasher>::create_ggc (64);
2379       omp_declare_variant_base_entry **slot
2380 	= omp_declare_variants->find_slot (&entry, INSERT);
2381       if (*slot != NULL)
2382 	{
2383 	  vec_free (entry.variants);
2384 	  return (*slot)->node->decl;
2385 	}
2386 
2387       *slot = ggc_cleared_alloc<omp_declare_variant_base_entry> ();
2388       (*slot)->base = entry.base;
2389       (*slot)->node = entry.base;
2390       (*slot)->variants = entry.variants;
2391       tree alt = build_decl (DECL_SOURCE_LOCATION (base), FUNCTION_DECL,
2392 			     DECL_NAME (base), TREE_TYPE (base));
2393       DECL_ARTIFICIAL (alt) = 1;
2394       DECL_IGNORED_P (alt) = 1;
2395       TREE_STATIC (alt) = 1;
2396       tree attributes = DECL_ATTRIBUTES (base);
2397       if (lookup_attribute ("noipa", attributes) == NULL)
2398 	{
2399 	  attributes = tree_cons (get_identifier ("noipa"), NULL, attributes);
2400 	  if (lookup_attribute ("noinline", attributes) == NULL)
2401 	    attributes = tree_cons (get_identifier ("noinline"), NULL,
2402 				    attributes);
2403 	  if (lookup_attribute ("noclone", attributes) == NULL)
2404 	    attributes = tree_cons (get_identifier ("noclone"), NULL,
2405 				    attributes);
2406 	  if (lookup_attribute ("no_icf", attributes) == NULL)
2407 	    attributes = tree_cons (get_identifier ("no_icf"), NULL,
2408 				    attributes);
2409 	}
2410       DECL_ATTRIBUTES (alt) = attributes;
2411       DECL_INITIAL (alt) = error_mark_node;
2412       (*slot)->node = cgraph_node::create (alt);
2413       (*slot)->node->declare_variant_alt = 1;
2414       (*slot)->node->create_reference (entry.base, IPA_REF_ADDR);
2415       omp_declare_variant_entry *varentry;
2416       FOR_EACH_VEC_SAFE_ELT (entry.variants, i, varentry)
2417 	(*slot)->node->create_reference (varentry->variant, IPA_REF_ADDR);
2418       if (omp_declare_variant_alt == NULL)
2419 	omp_declare_variant_alt
2420 	  = hash_table<omp_declare_variant_alt_hasher>::create_ggc (64);
2421       *omp_declare_variant_alt->find_slot_with_hash (*slot, DECL_UID (alt),
2422 						     INSERT) = *slot;
2423       return alt;
2424     }
2425 
2426   if (variants.length () == 1)
2427     return TREE_PURPOSE (TREE_VALUE (variants[0]));
2428 
2429   /* A context selector that is a strict subset of another context selector
2430      has a score of zero.  */
2431   tree attr1, attr2;
2432   unsigned int i, j;
2433   FOR_EACH_VEC_ELT (variants, i, attr1)
2434     if (attr1)
2435       {
2436 	tree ctx1 = TREE_VALUE (TREE_VALUE (attr1));
2437 	FOR_EACH_VEC_ELT_FROM (variants, j, attr2, i + 1)
2438 	  if (attr2)
2439 	    {
2440 	      tree ctx2 = TREE_VALUE (TREE_VALUE (attr2));
2441 	      int r = omp_context_selector_compare (ctx1, ctx2);
2442 	      if (r == -1)
2443 		{
2444 		  /* ctx1 is a strict subset of ctx2, remove
2445 		     attr1 from the vector.  */
2446 		  variants[i] = NULL_TREE;
2447 		  break;
2448 		}
2449 	      else if (r == 1)
2450 		/* ctx2 is a strict subset of ctx1, remove attr2
2451 		   from the vector.  */
2452 		variants[j] = NULL_TREE;
2453 	    }
2454       }
2455   widest_int max_score1 = 0;
2456   widest_int max_score2 = 0;
2457   bool first = true;
2458   FOR_EACH_VEC_ELT (variants, i, attr1)
2459     if (attr1)
2460       {
2461 	if (variant1)
2462 	  {
2463 	    widest_int score1;
2464 	    widest_int score2;
2465 	    bool need_two;
2466 	    tree ctx;
2467 	    if (first)
2468 	      {
2469 		first = false;
2470 		ctx = TREE_VALUE (TREE_VALUE (variant1));
2471 		need_two = omp_context_compute_score (ctx, &max_score1, false);
2472 		if (need_two)
2473 		  omp_context_compute_score (ctx, &max_score2, true);
2474 		else
2475 		  max_score2 = max_score1;
2476 	      }
2477 	    ctx = TREE_VALUE (TREE_VALUE (attr1));
2478 	    need_two = omp_context_compute_score (ctx, &score1, false);
2479 	    if (need_two)
2480 	      omp_context_compute_score (ctx, &score2, true);
2481 	    else
2482 	      score2 = score1;
2483 	    if (score1 > max_score1)
2484 	      {
2485 		max_score1 = score1;
2486 		variant1 = attr1;
2487 	      }
2488 	    if (score2 > max_score2)
2489 	      {
2490 		max_score2 = score2;
2491 		variant2 = attr1;
2492 	      }
2493 	  }
2494 	else
2495 	  {
2496 	    variant1 = attr1;
2497 	    variant2 = attr1;
2498 	  }
2499       }
2500   /* If there is a disagreement on which variant has the highest score
2501      depending on whether it will be in a declare simd clone or not,
2502      punt for now and defer until after IPA where we will know that.  */
2503   return ((variant1 && variant1 == variant2)
2504 	  ? TREE_PURPOSE (TREE_VALUE (variant1)) : base);
2505 }
2506 
2507 void
omp_lto_output_declare_variant_alt(lto_simple_output_block * ob,cgraph_node * node,lto_symtab_encoder_t encoder)2508 omp_lto_output_declare_variant_alt (lto_simple_output_block *ob,
2509 				    cgraph_node *node,
2510 				    lto_symtab_encoder_t encoder)
2511 {
2512   gcc_assert (node->declare_variant_alt);
2513 
2514   omp_declare_variant_base_entry entry;
2515   entry.base = NULL;
2516   entry.node = node;
2517   entry.variants = NULL;
2518   omp_declare_variant_base_entry *entryp
2519     = omp_declare_variant_alt->find_with_hash (&entry, DECL_UID (node->decl));
2520   gcc_assert (entryp);
2521 
2522   int nbase = lto_symtab_encoder_lookup (encoder, entryp->base);
2523   gcc_assert (nbase != LCC_NOT_FOUND);
2524   streamer_write_hwi_stream (ob->main_stream, nbase);
2525 
2526   streamer_write_hwi_stream (ob->main_stream, entryp->variants->length ());
2527 
2528   unsigned int i;
2529   omp_declare_variant_entry *varentry;
2530   FOR_EACH_VEC_SAFE_ELT (entryp->variants, i, varentry)
2531     {
2532       int nvar = lto_symtab_encoder_lookup (encoder, varentry->variant);
2533       gcc_assert (nvar != LCC_NOT_FOUND);
2534       streamer_write_hwi_stream (ob->main_stream, nvar);
2535 
2536       for (widest_int *w = &varentry->score; ;
2537 	   w = &varentry->score_in_declare_simd_clone)
2538 	{
2539 	  unsigned len = w->get_len ();
2540 	  streamer_write_hwi_stream (ob->main_stream, len);
2541 	  const HOST_WIDE_INT *val = w->get_val ();
2542 	  for (unsigned j = 0; j < len; j++)
2543 	    streamer_write_hwi_stream (ob->main_stream, val[j]);
2544 	  if (w == &varentry->score_in_declare_simd_clone)
2545 	    break;
2546 	}
2547 
2548       HOST_WIDE_INT cnt = -1;
2549       HOST_WIDE_INT i = varentry->matches ? 1 : 0;
2550       for (tree attr = DECL_ATTRIBUTES (entryp->base->decl);
2551 	   attr; attr = TREE_CHAIN (attr), i += 2)
2552 	{
2553 	  attr = lookup_attribute ("omp declare variant base", attr);
2554 	  if (attr == NULL_TREE)
2555 	    break;
2556 
2557 	  if (varentry->ctx == TREE_VALUE (TREE_VALUE (attr)))
2558 	    {
2559 	      cnt = i;
2560 	      break;
2561 	    }
2562 	}
2563 
2564       gcc_assert (cnt != -1);
2565       streamer_write_hwi_stream (ob->main_stream, cnt);
2566     }
2567 }
2568 
2569 void
omp_lto_input_declare_variant_alt(lto_input_block * ib,cgraph_node * node,vec<symtab_node * > nodes)2570 omp_lto_input_declare_variant_alt (lto_input_block *ib, cgraph_node *node,
2571 				   vec<symtab_node *> nodes)
2572 {
2573   gcc_assert (node->declare_variant_alt);
2574   omp_declare_variant_base_entry *entryp
2575     = ggc_cleared_alloc<omp_declare_variant_base_entry> ();
2576   entryp->base = dyn_cast<cgraph_node *> (nodes[streamer_read_hwi (ib)]);
2577   entryp->node = node;
2578   unsigned int len = streamer_read_hwi (ib);
2579   vec_alloc (entryp->variants, len);
2580 
2581   for (unsigned int i = 0; i < len; i++)
2582     {
2583       omp_declare_variant_entry varentry;
2584       varentry.variant
2585 	= dyn_cast<cgraph_node *> (nodes[streamer_read_hwi (ib)]);
2586       for (widest_int *w = &varentry.score; ;
2587 	   w = &varentry.score_in_declare_simd_clone)
2588 	{
2589 	  unsigned len2 = streamer_read_hwi (ib);
2590 	  HOST_WIDE_INT arr[WIDE_INT_MAX_ELTS];
2591 	  gcc_assert (len2 <= WIDE_INT_MAX_ELTS);
2592 	  for (unsigned int j = 0; j < len2; j++)
2593 	    arr[j] = streamer_read_hwi (ib);
2594 	  *w = widest_int::from_array (arr, len2, true);
2595 	  if (w == &varentry.score_in_declare_simd_clone)
2596 	    break;
2597 	}
2598 
2599       HOST_WIDE_INT cnt = streamer_read_hwi (ib);
2600       HOST_WIDE_INT j = 0;
2601       varentry.ctx = NULL_TREE;
2602       varentry.matches = (cnt & 1) ? true : false;
2603       cnt &= ~HOST_WIDE_INT_1;
2604       for (tree attr = DECL_ATTRIBUTES (entryp->base->decl);
2605 	   attr; attr = TREE_CHAIN (attr), j += 2)
2606 	{
2607 	  attr = lookup_attribute ("omp declare variant base", attr);
2608 	  if (attr == NULL_TREE)
2609 	    break;
2610 
2611 	  if (cnt == j)
2612 	    {
2613 	      varentry.ctx = TREE_VALUE (TREE_VALUE (attr));
2614 	      break;
2615 	    }
2616 	}
2617       gcc_assert (varentry.ctx != NULL_TREE);
2618       entryp->variants->quick_push (varentry);
2619     }
2620   if (omp_declare_variant_alt == NULL)
2621     omp_declare_variant_alt
2622       = hash_table<omp_declare_variant_alt_hasher>::create_ggc (64);
2623   *omp_declare_variant_alt->find_slot_with_hash (entryp, DECL_UID (node->decl),
2624 						 INSERT) = entryp;
2625 }
2626 
2627 /* Encode an oacc launch argument.  This matches the GOMP_LAUNCH_PACK
2628    macro on gomp-constants.h.  We do not check for overflow.  */
2629 
2630 tree
oacc_launch_pack(unsigned code,tree device,unsigned op)2631 oacc_launch_pack (unsigned code, tree device, unsigned op)
2632 {
2633   tree res;
2634 
2635   res = build_int_cst (unsigned_type_node, GOMP_LAUNCH_PACK (code, 0, op));
2636   if (device)
2637     {
2638       device = fold_build2 (LSHIFT_EXPR, unsigned_type_node,
2639 			    device, build_int_cst (unsigned_type_node,
2640 						   GOMP_LAUNCH_DEVICE_SHIFT));
2641       res = fold_build2 (BIT_IOR_EXPR, unsigned_type_node, res, device);
2642     }
2643   return res;
2644 }
2645 
2646 /* FIXME: What is the following comment for? */
2647 /* Look for compute grid dimension clauses and convert to an attribute
2648    attached to FN.  This permits the target-side code to (a) massage
2649    the dimensions, (b) emit that data and (c) optimize.  Non-constant
2650    dimensions are pushed onto ARGS.
2651 
2652    The attribute value is a TREE_LIST.  A set of dimensions is
2653    represented as a list of INTEGER_CST.  Those that are runtime
2654    exprs are represented as an INTEGER_CST of zero.
2655 
2656    TODO: Normally the attribute will just contain a single such list.  If
2657    however it contains a list of lists, this will represent the use of
2658    device_type.  Each member of the outer list is an assoc list of
2659    dimensions, keyed by the device type.  The first entry will be the
2660    default.  Well, that's the plan.  */
2661 
2662 /* Replace any existing oacc fn attribute with updated dimensions.  */
2663 
2664 /* Variant working on a list of attributes.  */
2665 
2666 tree
oacc_replace_fn_attrib_attr(tree attribs,tree dims)2667 oacc_replace_fn_attrib_attr (tree attribs, tree dims)
2668 {
2669   tree ident = get_identifier (OACC_FN_ATTRIB);
2670 
2671   /* If we happen to be present as the first attrib, drop it.  */
2672   if (attribs && TREE_PURPOSE (attribs) == ident)
2673     attribs = TREE_CHAIN (attribs);
2674   return tree_cons (ident, dims, attribs);
2675 }
2676 
2677 /* Variant working on a function decl.  */
2678 
2679 void
oacc_replace_fn_attrib(tree fn,tree dims)2680 oacc_replace_fn_attrib (tree fn, tree dims)
2681 {
2682   DECL_ATTRIBUTES (fn)
2683     = oacc_replace_fn_attrib_attr (DECL_ATTRIBUTES (fn), dims);
2684 }
2685 
2686 /* Scan CLAUSES for launch dimensions and attach them to the oacc
2687    function attribute.  Push any that are non-constant onto the ARGS
2688    list, along with an appropriate GOMP_LAUNCH_DIM tag.  */
2689 
2690 void
oacc_set_fn_attrib(tree fn,tree clauses,vec<tree> * args)2691 oacc_set_fn_attrib (tree fn, tree clauses, vec<tree> *args)
2692 {
2693   /* Must match GOMP_DIM ordering.  */
2694   static const omp_clause_code ids[]
2695     = { OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS,
2696 	OMP_CLAUSE_VECTOR_LENGTH };
2697   unsigned ix;
2698   tree dims[GOMP_DIM_MAX];
2699 
2700   tree attr = NULL_TREE;
2701   unsigned non_const = 0;
2702 
2703   for (ix = GOMP_DIM_MAX; ix--;)
2704     {
2705       tree clause = omp_find_clause (clauses, ids[ix]);
2706       tree dim = NULL_TREE;
2707 
2708       if (clause)
2709 	dim = OMP_CLAUSE_EXPR (clause, ids[ix]);
2710       dims[ix] = dim;
2711       if (dim && TREE_CODE (dim) != INTEGER_CST)
2712 	{
2713 	  dim = integer_zero_node;
2714 	  non_const |= GOMP_DIM_MASK (ix);
2715 	}
2716       attr = tree_cons (NULL_TREE, dim, attr);
2717     }
2718 
2719   oacc_replace_fn_attrib (fn, attr);
2720 
2721   if (non_const)
2722     {
2723       /* Push a dynamic argument set.  */
2724       args->safe_push (oacc_launch_pack (GOMP_LAUNCH_DIM,
2725 					 NULL_TREE, non_const));
2726       for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++)
2727 	if (non_const & GOMP_DIM_MASK (ix))
2728 	  args->safe_push (dims[ix]);
2729     }
2730 }
2731 
2732 /* Verify OpenACC routine clauses.
2733 
2734    Returns 0 if FNDECL should be marked with an OpenACC 'routine' directive, 1
2735    if it has already been marked in compatible way, and -1 if incompatible.
2736    Upon returning, the chain of clauses will contain exactly one clause
2737    specifying the level of parallelism.  */
2738 
2739 int
oacc_verify_routine_clauses(tree fndecl,tree * clauses,location_t loc,const char * routine_str)2740 oacc_verify_routine_clauses (tree fndecl, tree *clauses, location_t loc,
2741 			     const char *routine_str)
2742 {
2743   tree c_level = NULL_TREE;
2744   tree c_nohost = NULL_TREE;
2745   tree c_p = NULL_TREE;
2746   for (tree c = *clauses; c; c_p = c, c = OMP_CLAUSE_CHAIN (c))
2747     switch (OMP_CLAUSE_CODE (c))
2748       {
2749       case OMP_CLAUSE_GANG:
2750       case OMP_CLAUSE_WORKER:
2751       case OMP_CLAUSE_VECTOR:
2752       case OMP_CLAUSE_SEQ:
2753 	if (c_level == NULL_TREE)
2754 	  c_level = c;
2755 	else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_CODE (c_level))
2756 	  {
2757 	    /* This has already been diagnosed in the front ends.  */
2758 	    /* Drop the duplicate clause.  */
2759 	    gcc_checking_assert (c_p != NULL_TREE);
2760 	    OMP_CLAUSE_CHAIN (c_p) = OMP_CLAUSE_CHAIN (c);
2761 	    c = c_p;
2762 	  }
2763 	else
2764 	  {
2765 	    error_at (OMP_CLAUSE_LOCATION (c),
2766 		      "%qs specifies a conflicting level of parallelism",
2767 		      omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
2768 	    inform (OMP_CLAUSE_LOCATION (c_level),
2769 		    "... to the previous %qs clause here",
2770 		    omp_clause_code_name[OMP_CLAUSE_CODE (c_level)]);
2771 	    /* Drop the conflicting clause.  */
2772 	    gcc_checking_assert (c_p != NULL_TREE);
2773 	    OMP_CLAUSE_CHAIN (c_p) = OMP_CLAUSE_CHAIN (c);
2774 	    c = c_p;
2775 	  }
2776 	break;
2777       case OMP_CLAUSE_NOHOST:
2778 	/* Don't worry about duplicate clauses here.  */
2779 	c_nohost = c;
2780 	break;
2781       default:
2782 	gcc_unreachable ();
2783       }
2784   if (c_level == NULL_TREE)
2785     {
2786       /* Default to an implicit 'seq' clause.  */
2787       c_level = build_omp_clause (loc, OMP_CLAUSE_SEQ);
2788       OMP_CLAUSE_CHAIN (c_level) = *clauses;
2789       *clauses = c_level;
2790     }
2791   /* In *clauses, we now have exactly one clause specifying the level of
2792      parallelism.  */
2793 
2794   tree attr
2795     = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl));
2796   if (attr != NULL_TREE)
2797     {
2798       /* Diagnose if "#pragma omp declare target" has also been applied.  */
2799       if (TREE_VALUE (attr) == NULL_TREE)
2800 	{
2801 	  /* See <https://gcc.gnu.org/PR93465>; the semantics of combining
2802 	     OpenACC and OpenMP 'target' are not clear.  */
2803 	  error_at (loc,
2804 		    "cannot apply %<%s%> to %qD, which has also been"
2805 		    " marked with an OpenMP 'declare target' directive",
2806 		    routine_str, fndecl);
2807 	  /* Incompatible.  */
2808 	  return -1;
2809 	}
2810 
2811       /* If a "#pragma acc routine" has already been applied, just verify
2812 	 this one for compatibility.  */
2813       /* Collect previous directive's clauses.  */
2814       tree c_level_p = NULL_TREE;
2815       tree c_nohost_p = NULL_TREE;
2816       for (tree c = TREE_VALUE (attr); c; c = OMP_CLAUSE_CHAIN (c))
2817 	switch (OMP_CLAUSE_CODE (c))
2818 	  {
2819 	  case OMP_CLAUSE_GANG:
2820 	  case OMP_CLAUSE_WORKER:
2821 	  case OMP_CLAUSE_VECTOR:
2822 	  case OMP_CLAUSE_SEQ:
2823 	    gcc_checking_assert (c_level_p == NULL_TREE);
2824 	    c_level_p = c;
2825 	    break;
2826 	  case OMP_CLAUSE_NOHOST:
2827 	    gcc_checking_assert (c_nohost_p == NULL_TREE);
2828 	    c_nohost_p = c;
2829 	    break;
2830 	  default:
2831 	    gcc_unreachable ();
2832 	  }
2833       gcc_checking_assert (c_level_p != NULL_TREE);
2834       /* ..., and compare to current directive's, which we've already collected
2835 	 above.  */
2836       tree c_diag;
2837       tree c_diag_p;
2838       /* Matching level of parallelism?  */
2839       if (OMP_CLAUSE_CODE (c_level) != OMP_CLAUSE_CODE (c_level_p))
2840 	{
2841 	  c_diag = c_level;
2842 	  c_diag_p = c_level_p;
2843 	  goto incompatible;
2844 	}
2845       /* Matching 'nohost' clauses?  */
2846       if ((c_nohost == NULL_TREE) != (c_nohost_p == NULL_TREE))
2847 	{
2848 	  c_diag = c_nohost;
2849 	  c_diag_p = c_nohost_p;
2850 	  goto incompatible;
2851 	}
2852       /* Compatible.  */
2853       return 1;
2854 
2855     incompatible:
2856       if (c_diag != NULL_TREE)
2857 	error_at (OMP_CLAUSE_LOCATION (c_diag),
2858 		  "incompatible %qs clause when applying"
2859 		  " %<%s%> to %qD, which has already been"
2860 		  " marked with an OpenACC 'routine' directive",
2861 		  omp_clause_code_name[OMP_CLAUSE_CODE (c_diag)],
2862 		  routine_str, fndecl);
2863       else if (c_diag_p != NULL_TREE)
2864 	error_at (loc,
2865 		  "missing %qs clause when applying"
2866 		  " %<%s%> to %qD, which has already been"
2867 		  " marked with an OpenACC 'routine' directive",
2868 		  omp_clause_code_name[OMP_CLAUSE_CODE (c_diag_p)],
2869 		  routine_str, fndecl);
2870       else
2871 	gcc_unreachable ();
2872       if (c_diag_p != NULL_TREE)
2873 	inform (OMP_CLAUSE_LOCATION (c_diag_p),
2874 		"... with %qs clause here",
2875 		omp_clause_code_name[OMP_CLAUSE_CODE (c_diag_p)]);
2876       else
2877 	{
2878 	  /* In the front ends, we don't preserve location information for the
2879 	     OpenACC routine directive itself.  However, that of c_level_p
2880 	     should be close.  */
2881 	  location_t loc_routine = OMP_CLAUSE_LOCATION (c_level_p);
2882 	  inform (loc_routine, "... without %qs clause near to here",
2883 		  omp_clause_code_name[OMP_CLAUSE_CODE (c_diag)]);
2884 	}
2885       /* Incompatible.  */
2886       return -1;
2887     }
2888 
2889   return 0;
2890 }
2891 
2892 /*  Process the OpenACC 'routine' directive clauses to generate an attribute
2893     for the level of parallelism.  All dimensions have a size of zero
2894     (dynamic).  TREE_PURPOSE is set to indicate whether that dimension
2895     can have a loop partitioned on it.  non-zero indicates
2896     yes, zero indicates no.  By construction once a non-zero has been
2897     reached, further inner dimensions must also be non-zero.  We set
2898     TREE_VALUE to zero for the dimensions that may be partitioned and
2899     1 for the other ones -- if a loop is (erroneously) spawned at
2900     an outer level, we don't want to try and partition it.  */
2901 
2902 tree
oacc_build_routine_dims(tree clauses)2903 oacc_build_routine_dims (tree clauses)
2904 {
2905   /* Must match GOMP_DIM ordering.  */
2906   static const omp_clause_code ids[]
2907     = {OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ};
2908   int ix;
2909   int level = -1;
2910 
2911   for (; clauses; clauses = OMP_CLAUSE_CHAIN (clauses))
2912     for (ix = GOMP_DIM_MAX + 1; ix--;)
2913       if (OMP_CLAUSE_CODE (clauses) == ids[ix])
2914 	{
2915 	  level = ix;
2916 	  break;
2917 	}
2918   gcc_checking_assert (level >= 0);
2919 
2920   tree dims = NULL_TREE;
2921 
2922   for (ix = GOMP_DIM_MAX; ix--;)
2923     dims = tree_cons (build_int_cst (boolean_type_node, ix >= level),
2924 		      build_int_cst (integer_type_node, ix < level), dims);
2925 
2926   return dims;
2927 }
2928 
2929 /* Retrieve the oacc function attrib and return it.  Non-oacc
2930    functions will return NULL.  */
2931 
2932 tree
oacc_get_fn_attrib(tree fn)2933 oacc_get_fn_attrib (tree fn)
2934 {
2935   return lookup_attribute (OACC_FN_ATTRIB, DECL_ATTRIBUTES (fn));
2936 }
2937 
2938 /* Return true if FN is an OpenMP or OpenACC offloading function.  */
2939 
2940 bool
offloading_function_p(tree fn)2941 offloading_function_p (tree fn)
2942 {
2943   tree attrs = DECL_ATTRIBUTES (fn);
2944   return (lookup_attribute ("omp declare target", attrs)
2945 	  || lookup_attribute ("omp target entrypoint", attrs));
2946 }
2947 
2948 /* Extract an oacc execution dimension from FN.  FN must be an
2949    offloaded function or routine that has already had its execution
2950    dimensions lowered to the target-specific values.  */
2951 
2952 int
oacc_get_fn_dim_size(tree fn,int axis)2953 oacc_get_fn_dim_size (tree fn, int axis)
2954 {
2955   tree attrs = oacc_get_fn_attrib (fn);
2956 
2957   gcc_assert (axis < GOMP_DIM_MAX);
2958 
2959   tree dims = TREE_VALUE (attrs);
2960   while (axis--)
2961     dims = TREE_CHAIN (dims);
2962 
2963   int size = TREE_INT_CST_LOW (TREE_VALUE (dims));
2964 
2965   return size;
2966 }
2967 
2968 /* Extract the dimension axis from an IFN_GOACC_DIM_POS or
2969    IFN_GOACC_DIM_SIZE call.  */
2970 
2971 int
oacc_get_ifn_dim_arg(const gimple * stmt)2972 oacc_get_ifn_dim_arg (const gimple *stmt)
2973 {
2974   gcc_checking_assert (gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_SIZE
2975 		       || gimple_call_internal_fn (stmt) == IFN_GOACC_DIM_POS);
2976   tree arg = gimple_call_arg (stmt, 0);
2977   HOST_WIDE_INT axis = TREE_INT_CST_LOW (arg);
2978 
2979   gcc_checking_assert (axis >= 0 && axis < GOMP_DIM_MAX);
2980   return (int) axis;
2981 }
2982 
2983 #include "gt-omp-general.h"
2984