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