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