1 /* OMP constructs' SIMD clone supporting code. 2 3 Copyright (C) 2005-2017 Free Software Foundation, Inc. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it under 8 the terms of the GNU General Public License as published by the Free 9 Software Foundation; either version 3, or (at your option) any later 10 version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 #include "config.h" 22 #include "system.h" 23 #include "coretypes.h" 24 #include "backend.h" 25 #include "target.h" 26 #include "tree.h" 27 #include "gimple.h" 28 #include "cfghooks.h" 29 #include "alloc-pool.h" 30 #include "tree-pass.h" 31 #include "ssa.h" 32 #include "cgraph.h" 33 #include "pretty-print.h" 34 #include "diagnostic-core.h" 35 #include "fold-const.h" 36 #include "stor-layout.h" 37 #include "cfganal.h" 38 #include "gimplify.h" 39 #include "gimple-iterator.h" 40 #include "gimplify-me.h" 41 #include "gimple-walk.h" 42 #include "langhooks.h" 43 #include "tree-cfg.h" 44 #include "tree-into-ssa.h" 45 #include "tree-dfa.h" 46 #include "cfgloop.h" 47 #include "symbol-summary.h" 48 #include "ipa-prop.h" 49 #include "tree-eh.h" 50 #include "varasm.h" 51 52 53 /* Allocate a fresh `simd_clone' and return it. NARGS is the number 54 of arguments to reserve space for. */ 55 56 static struct cgraph_simd_clone * 57 simd_clone_struct_alloc (int nargs) 58 { 59 struct cgraph_simd_clone *clone_info; 60 size_t len = (sizeof (struct cgraph_simd_clone) 61 + nargs * sizeof (struct cgraph_simd_clone_arg)); 62 clone_info = (struct cgraph_simd_clone *) 63 ggc_internal_cleared_alloc (len); 64 return clone_info; 65 } 66 67 /* Make a copy of the `struct cgraph_simd_clone' in FROM to TO. */ 68 69 static inline void 70 simd_clone_struct_copy (struct cgraph_simd_clone *to, 71 struct cgraph_simd_clone *from) 72 { 73 memcpy (to, from, (sizeof (struct cgraph_simd_clone) 74 + ((from->nargs - from->inbranch) 75 * sizeof (struct cgraph_simd_clone_arg)))); 76 } 77 78 /* Return vector of parameter types of function FNDECL. This uses 79 TYPE_ARG_TYPES if available, otherwise falls back to types of 80 DECL_ARGUMENTS types. */ 81 82 static vec<tree> 83 simd_clone_vector_of_formal_parm_types (tree fndecl) 84 { 85 if (TYPE_ARG_TYPES (TREE_TYPE (fndecl))) 86 return ipa_get_vector_of_formal_parm_types (TREE_TYPE (fndecl)); 87 vec<tree> args = ipa_get_vector_of_formal_parms (fndecl); 88 unsigned int i; 89 tree arg; 90 FOR_EACH_VEC_ELT (args, i, arg) 91 args[i] = TREE_TYPE (args[i]); 92 return args; 93 } 94 95 /* Given a simd function in NODE, extract the simd specific 96 information from the OMP clauses passed in CLAUSES, and return 97 the struct cgraph_simd_clone * if it should be cloned. *INBRANCH_SPECIFIED 98 is set to TRUE if the `inbranch' or `notinbranch' clause specified, 99 otherwise set to FALSE. */ 100 101 static struct cgraph_simd_clone * 102 simd_clone_clauses_extract (struct cgraph_node *node, tree clauses, 103 bool *inbranch_specified) 104 { 105 vec<tree> args = simd_clone_vector_of_formal_parm_types (node->decl); 106 tree t; 107 int n; 108 *inbranch_specified = false; 109 110 n = args.length (); 111 if (n > 0 && args.last () == void_type_node) 112 n--; 113 114 /* To distinguish from an OpenMP simd clone, Cilk Plus functions to 115 be cloned have a distinctive artificial label in addition to "omp 116 declare simd". */ 117 bool cilk_clone 118 = (flag_cilkplus 119 && lookup_attribute ("cilk simd function", 120 DECL_ATTRIBUTES (node->decl))); 121 122 /* Allocate one more than needed just in case this is an in-branch 123 clone which will require a mask argument. */ 124 struct cgraph_simd_clone *clone_info = simd_clone_struct_alloc (n + 1); 125 clone_info->nargs = n; 126 clone_info->cilk_elemental = cilk_clone; 127 128 if (!clauses) 129 goto out; 130 131 clauses = TREE_VALUE (clauses); 132 if (!clauses || TREE_CODE (clauses) != OMP_CLAUSE) 133 goto out; 134 135 for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t)) 136 { 137 switch (OMP_CLAUSE_CODE (t)) 138 { 139 case OMP_CLAUSE_INBRANCH: 140 clone_info->inbranch = 1; 141 *inbranch_specified = true; 142 break; 143 case OMP_CLAUSE_NOTINBRANCH: 144 clone_info->inbranch = 0; 145 *inbranch_specified = true; 146 break; 147 case OMP_CLAUSE_SIMDLEN: 148 clone_info->simdlen 149 = TREE_INT_CST_LOW (OMP_CLAUSE_SIMDLEN_EXPR (t)); 150 break; 151 case OMP_CLAUSE_LINEAR: 152 { 153 tree decl = OMP_CLAUSE_DECL (t); 154 tree step = OMP_CLAUSE_LINEAR_STEP (t); 155 int argno = TREE_INT_CST_LOW (decl); 156 if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (t)) 157 { 158 enum cgraph_simd_clone_arg_type arg_type; 159 if (TREE_CODE (args[argno]) == REFERENCE_TYPE) 160 switch (OMP_CLAUSE_LINEAR_KIND (t)) 161 { 162 case OMP_CLAUSE_LINEAR_REF: 163 arg_type 164 = SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP; 165 break; 166 case OMP_CLAUSE_LINEAR_UVAL: 167 arg_type 168 = SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP; 169 break; 170 case OMP_CLAUSE_LINEAR_VAL: 171 case OMP_CLAUSE_LINEAR_DEFAULT: 172 arg_type 173 = SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP; 174 break; 175 default: 176 gcc_unreachable (); 177 } 178 else 179 arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP; 180 clone_info->args[argno].arg_type = arg_type; 181 clone_info->args[argno].linear_step = tree_to_shwi (step); 182 gcc_assert (clone_info->args[argno].linear_step >= 0 183 && clone_info->args[argno].linear_step < n); 184 } 185 else 186 { 187 if (POINTER_TYPE_P (args[argno])) 188 step = fold_convert (ssizetype, step); 189 if (!tree_fits_shwi_p (step)) 190 { 191 warning_at (OMP_CLAUSE_LOCATION (t), 0, 192 "ignoring large linear step"); 193 args.release (); 194 return NULL; 195 } 196 else if (integer_zerop (step)) 197 { 198 warning_at (OMP_CLAUSE_LOCATION (t), 0, 199 "ignoring zero linear step"); 200 args.release (); 201 return NULL; 202 } 203 else 204 { 205 enum cgraph_simd_clone_arg_type arg_type; 206 if (TREE_CODE (args[argno]) == REFERENCE_TYPE) 207 switch (OMP_CLAUSE_LINEAR_KIND (t)) 208 { 209 case OMP_CLAUSE_LINEAR_REF: 210 arg_type 211 = SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP; 212 break; 213 case OMP_CLAUSE_LINEAR_UVAL: 214 arg_type 215 = SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP; 216 break; 217 case OMP_CLAUSE_LINEAR_VAL: 218 case OMP_CLAUSE_LINEAR_DEFAULT: 219 arg_type 220 = SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP; 221 break; 222 default: 223 gcc_unreachable (); 224 } 225 else 226 arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP; 227 clone_info->args[argno].arg_type = arg_type; 228 clone_info->args[argno].linear_step = tree_to_shwi (step); 229 } 230 } 231 break; 232 } 233 case OMP_CLAUSE_UNIFORM: 234 { 235 tree decl = OMP_CLAUSE_DECL (t); 236 int argno = tree_to_uhwi (decl); 237 clone_info->args[argno].arg_type 238 = SIMD_CLONE_ARG_TYPE_UNIFORM; 239 break; 240 } 241 case OMP_CLAUSE_ALIGNED: 242 { 243 /* Ignore aligned (x) for declare simd, for the ABI we really 244 need an alignment specified. */ 245 if (OMP_CLAUSE_ALIGNED_ALIGNMENT (t) == NULL_TREE) 246 break; 247 tree decl = OMP_CLAUSE_DECL (t); 248 int argno = tree_to_uhwi (decl); 249 clone_info->args[argno].alignment 250 = TREE_INT_CST_LOW (OMP_CLAUSE_ALIGNED_ALIGNMENT (t)); 251 break; 252 } 253 default: 254 break; 255 } 256 } 257 258 out: 259 if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (node->decl)))) 260 { 261 warning_at (DECL_SOURCE_LOCATION (node->decl), 0, 262 "ignoring %<#pragma omp declare simd%> on function " 263 "with %<_Atomic%> qualified return type"); 264 args.release (); 265 return NULL; 266 } 267 268 for (unsigned int argno = 0; argno < clone_info->nargs; argno++) 269 if (TYPE_ATOMIC (args[argno]) 270 && clone_info->args[argno].arg_type != SIMD_CLONE_ARG_TYPE_UNIFORM) 271 { 272 warning_at (DECL_SOURCE_LOCATION (node->decl), 0, 273 "ignoring %<#pragma omp declare simd%> on function " 274 "with %<_Atomic%> qualified non-%<uniform%> argument"); 275 args.release (); 276 return NULL; 277 } 278 279 args.release (); 280 return clone_info; 281 } 282 283 /* Given a SIMD clone in NODE, calculate the characteristic data 284 type and return the coresponding type. The characteristic data 285 type is computed as described in the Intel Vector ABI. */ 286 287 static tree 288 simd_clone_compute_base_data_type (struct cgraph_node *node, 289 struct cgraph_simd_clone *clone_info) 290 { 291 tree type = integer_type_node; 292 tree fndecl = node->decl; 293 294 /* a) For non-void function, the characteristic data type is the 295 return type. */ 296 if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE) 297 type = TREE_TYPE (TREE_TYPE (fndecl)); 298 299 /* b) If the function has any non-uniform, non-linear parameters, 300 then the characteristic data type is the type of the first 301 such parameter. */ 302 else 303 { 304 vec<tree> map = simd_clone_vector_of_formal_parm_types (fndecl); 305 for (unsigned int i = 0; i < clone_info->nargs; ++i) 306 if (clone_info->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR) 307 { 308 type = map[i]; 309 break; 310 } 311 map.release (); 312 } 313 314 /* c) If the characteristic data type determined by a) or b) above 315 is struct, union, or class type which is pass-by-value (except 316 for the type that maps to the built-in complex data type), the 317 characteristic data type is int. */ 318 if (RECORD_OR_UNION_TYPE_P (type) 319 && !aggregate_value_p (type, NULL) 320 && TREE_CODE (type) != COMPLEX_TYPE) 321 return integer_type_node; 322 323 /* d) If none of the above three classes is applicable, the 324 characteristic data type is int. */ 325 326 return type; 327 328 /* e) For Intel Xeon Phi native and offload compilation, if the 329 resulting characteristic data type is 8-bit or 16-bit integer 330 data type, the characteristic data type is int. */ 331 /* Well, we don't handle Xeon Phi yet. */ 332 } 333 334 static tree 335 simd_clone_mangle (struct cgraph_node *node, 336 struct cgraph_simd_clone *clone_info) 337 { 338 char vecsize_mangle = clone_info->vecsize_mangle; 339 char mask = clone_info->inbranch ? 'M' : 'N'; 340 unsigned int simdlen = clone_info->simdlen; 341 unsigned int n; 342 pretty_printer pp; 343 344 gcc_assert (vecsize_mangle && simdlen); 345 346 pp_string (&pp, "_ZGV"); 347 pp_character (&pp, vecsize_mangle); 348 pp_character (&pp, mask); 349 pp_decimal_int (&pp, simdlen); 350 351 for (n = 0; n < clone_info->nargs; ++n) 352 { 353 struct cgraph_simd_clone_arg arg = clone_info->args[n]; 354 355 switch (arg.arg_type) 356 { 357 case SIMD_CLONE_ARG_TYPE_UNIFORM: 358 pp_character (&pp, 'u'); 359 break; 360 case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP: 361 pp_character (&pp, 'l'); 362 goto mangle_linear; 363 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP: 364 pp_character (&pp, 'R'); 365 goto mangle_linear; 366 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP: 367 pp_character (&pp, 'L'); 368 goto mangle_linear; 369 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP: 370 pp_character (&pp, 'U'); 371 goto mangle_linear; 372 mangle_linear: 373 gcc_assert (arg.linear_step != 0); 374 if (arg.linear_step > 1) 375 pp_unsigned_wide_integer (&pp, arg.linear_step); 376 else if (arg.linear_step < 0) 377 { 378 pp_character (&pp, 'n'); 379 pp_unsigned_wide_integer (&pp, (-(unsigned HOST_WIDE_INT) 380 arg.linear_step)); 381 } 382 break; 383 case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP: 384 pp_string (&pp, "ls"); 385 pp_unsigned_wide_integer (&pp, arg.linear_step); 386 break; 387 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP: 388 pp_string (&pp, "Rs"); 389 pp_unsigned_wide_integer (&pp, arg.linear_step); 390 break; 391 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP: 392 pp_string (&pp, "Ls"); 393 pp_unsigned_wide_integer (&pp, arg.linear_step); 394 break; 395 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP: 396 pp_string (&pp, "Us"); 397 pp_unsigned_wide_integer (&pp, arg.linear_step); 398 break; 399 default: 400 pp_character (&pp, 'v'); 401 } 402 if (arg.alignment) 403 { 404 pp_character (&pp, 'a'); 405 pp_decimal_int (&pp, arg.alignment); 406 } 407 } 408 409 pp_underscore (&pp); 410 const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)); 411 if (*str == '*') 412 ++str; 413 pp_string (&pp, str); 414 str = pp_formatted_text (&pp); 415 416 /* If there already is a SIMD clone with the same mangled name, don't 417 add another one. This can happen e.g. for 418 #pragma omp declare simd 419 #pragma omp declare simd simdlen(8) 420 int foo (int, int); 421 if the simdlen is assumed to be 8 for the first one, etc. */ 422 for (struct cgraph_node *clone = node->simd_clones; clone; 423 clone = clone->simdclone->next_clone) 424 if (strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (clone->decl)), 425 str) == 0) 426 return NULL_TREE; 427 428 return get_identifier (str); 429 } 430 431 /* Create a simd clone of OLD_NODE and return it. */ 432 433 static struct cgraph_node * 434 simd_clone_create (struct cgraph_node *old_node) 435 { 436 struct cgraph_node *new_node; 437 if (old_node->definition) 438 { 439 if (!old_node->has_gimple_body_p ()) 440 return NULL; 441 old_node->get_body (); 442 new_node = old_node->create_version_clone_with_body (vNULL, NULL, NULL, 443 false, NULL, NULL, 444 "simdclone"); 445 } 446 else 447 { 448 tree old_decl = old_node->decl; 449 tree new_decl = copy_node (old_node->decl); 450 DECL_NAME (new_decl) = clone_function_name (old_decl, "simdclone"); 451 SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl)); 452 SET_DECL_RTL (new_decl, NULL); 453 DECL_STATIC_CONSTRUCTOR (new_decl) = 0; 454 DECL_STATIC_DESTRUCTOR (new_decl) = 0; 455 new_node = old_node->create_version_clone (new_decl, vNULL, NULL); 456 if (old_node->in_other_partition) 457 new_node->in_other_partition = 1; 458 } 459 if (new_node == NULL) 460 return new_node; 461 462 TREE_PUBLIC (new_node->decl) = TREE_PUBLIC (old_node->decl); 463 DECL_COMDAT (new_node->decl) = DECL_COMDAT (old_node->decl); 464 DECL_WEAK (new_node->decl) = DECL_WEAK (old_node->decl); 465 DECL_EXTERNAL (new_node->decl) = DECL_EXTERNAL (old_node->decl); 466 DECL_VISIBILITY_SPECIFIED (new_node->decl) 467 = DECL_VISIBILITY_SPECIFIED (old_node->decl); 468 DECL_VISIBILITY (new_node->decl) = DECL_VISIBILITY (old_node->decl); 469 DECL_DLLIMPORT_P (new_node->decl) = DECL_DLLIMPORT_P (old_node->decl); 470 if (DECL_ONE_ONLY (old_node->decl)) 471 make_decl_one_only (new_node->decl, DECL_ASSEMBLER_NAME (new_node->decl)); 472 473 /* The method cgraph_version_clone_with_body () will force the new 474 symbol local. Undo this, and inherit external visibility from 475 the old node. */ 476 new_node->local.local = old_node->local.local; 477 new_node->externally_visible = old_node->externally_visible; 478 479 return new_node; 480 } 481 482 /* Adjust the return type of the given function to its appropriate 483 vector counterpart. Returns a simd array to be used throughout the 484 function as a return value. */ 485 486 static tree 487 simd_clone_adjust_return_type (struct cgraph_node *node) 488 { 489 tree fndecl = node->decl; 490 tree orig_rettype = TREE_TYPE (TREE_TYPE (fndecl)); 491 unsigned int veclen; 492 tree t; 493 494 /* Adjust the function return type. */ 495 if (orig_rettype == void_type_node) 496 return NULL_TREE; 497 TREE_TYPE (fndecl) = build_distinct_type_copy (TREE_TYPE (fndecl)); 498 t = TREE_TYPE (TREE_TYPE (fndecl)); 499 if (INTEGRAL_TYPE_P (t) || POINTER_TYPE_P (t)) 500 veclen = node->simdclone->vecsize_int; 501 else 502 veclen = node->simdclone->vecsize_float; 503 veclen /= GET_MODE_BITSIZE (TYPE_MODE (t)); 504 if (veclen > node->simdclone->simdlen) 505 veclen = node->simdclone->simdlen; 506 if (POINTER_TYPE_P (t)) 507 t = pointer_sized_int_node; 508 if (veclen == node->simdclone->simdlen) 509 t = build_vector_type (t, node->simdclone->simdlen); 510 else 511 { 512 t = build_vector_type (t, veclen); 513 t = build_array_type_nelts (t, node->simdclone->simdlen / veclen); 514 } 515 TREE_TYPE (TREE_TYPE (fndecl)) = t; 516 if (!node->definition) 517 return NULL_TREE; 518 519 t = DECL_RESULT (fndecl); 520 /* Adjust the DECL_RESULT. */ 521 gcc_assert (TREE_TYPE (t) != void_type_node); 522 TREE_TYPE (t) = TREE_TYPE (TREE_TYPE (fndecl)); 523 relayout_decl (t); 524 525 tree atype = build_array_type_nelts (orig_rettype, 526 node->simdclone->simdlen); 527 if (veclen != node->simdclone->simdlen) 528 return build1 (VIEW_CONVERT_EXPR, atype, t); 529 530 /* Set up a SIMD array to use as the return value. */ 531 tree retval = create_tmp_var_raw (atype, "retval"); 532 gimple_add_tmp_var (retval); 533 return retval; 534 } 535 536 /* Each vector argument has a corresponding array to be used locally 537 as part of the eventual loop. Create such temporary array and 538 return it. 539 540 PREFIX is the prefix to be used for the temporary. 541 542 TYPE is the inner element type. 543 544 SIMDLEN is the number of elements. */ 545 546 static tree 547 create_tmp_simd_array (const char *prefix, tree type, int simdlen) 548 { 549 tree atype = build_array_type_nelts (type, simdlen); 550 tree avar = create_tmp_var_raw (atype, prefix); 551 gimple_add_tmp_var (avar); 552 return avar; 553 } 554 555 /* Modify the function argument types to their corresponding vector 556 counterparts if appropriate. Also, create one array for each simd 557 argument to be used locally when using the function arguments as 558 part of the loop. 559 560 NODE is the function whose arguments are to be adjusted. 561 562 Returns an adjustment vector that will be filled describing how the 563 argument types will be adjusted. */ 564 565 static ipa_parm_adjustment_vec 566 simd_clone_adjust_argument_types (struct cgraph_node *node) 567 { 568 vec<tree> args; 569 ipa_parm_adjustment_vec adjustments; 570 571 if (node->definition) 572 args = ipa_get_vector_of_formal_parms (node->decl); 573 else 574 args = simd_clone_vector_of_formal_parm_types (node->decl); 575 adjustments.create (args.length ()); 576 unsigned i, j, veclen; 577 struct ipa_parm_adjustment adj; 578 struct cgraph_simd_clone *sc = node->simdclone; 579 580 for (i = 0; i < sc->nargs; ++i) 581 { 582 memset (&adj, 0, sizeof (adj)); 583 tree parm = args[i]; 584 tree parm_type = node->definition ? TREE_TYPE (parm) : parm; 585 adj.base_index = i; 586 adj.base = parm; 587 588 sc->args[i].orig_arg = node->definition ? parm : NULL_TREE; 589 sc->args[i].orig_type = parm_type; 590 591 switch (sc->args[i].arg_type) 592 { 593 default: 594 /* No adjustment necessary for scalar arguments. */ 595 adj.op = IPA_PARM_OP_COPY; 596 break; 597 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP: 598 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP: 599 if (node->definition) 600 sc->args[i].simd_array 601 = create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)), 602 TREE_TYPE (parm_type), 603 sc->simdlen); 604 adj.op = IPA_PARM_OP_COPY; 605 break; 606 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP: 607 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP: 608 case SIMD_CLONE_ARG_TYPE_VECTOR: 609 if (INTEGRAL_TYPE_P (parm_type) || POINTER_TYPE_P (parm_type)) 610 veclen = sc->vecsize_int; 611 else 612 veclen = sc->vecsize_float; 613 veclen /= GET_MODE_BITSIZE (TYPE_MODE (parm_type)); 614 if (veclen > sc->simdlen) 615 veclen = sc->simdlen; 616 adj.arg_prefix = "simd"; 617 if (POINTER_TYPE_P (parm_type)) 618 adj.type = build_vector_type (pointer_sized_int_node, veclen); 619 else 620 adj.type = build_vector_type (parm_type, veclen); 621 sc->args[i].vector_type = adj.type; 622 for (j = veclen; j < sc->simdlen; j += veclen) 623 { 624 adjustments.safe_push (adj); 625 if (j == veclen) 626 { 627 memset (&adj, 0, sizeof (adj)); 628 adj.op = IPA_PARM_OP_NEW; 629 adj.arg_prefix = "simd"; 630 adj.base_index = i; 631 adj.type = sc->args[i].vector_type; 632 } 633 } 634 635 if (node->definition) 636 sc->args[i].simd_array 637 = create_tmp_simd_array (DECL_NAME (parm) 638 ? IDENTIFIER_POINTER (DECL_NAME (parm)) 639 : NULL, parm_type, sc->simdlen); 640 } 641 adjustments.safe_push (adj); 642 } 643 644 if (sc->inbranch) 645 { 646 tree base_type = simd_clone_compute_base_data_type (sc->origin, sc); 647 648 memset (&adj, 0, sizeof (adj)); 649 adj.op = IPA_PARM_OP_NEW; 650 adj.arg_prefix = "mask"; 651 652 adj.base_index = i; 653 if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type)) 654 veclen = sc->vecsize_int; 655 else 656 veclen = sc->vecsize_float; 657 veclen /= GET_MODE_BITSIZE (TYPE_MODE (base_type)); 658 if (veclen > sc->simdlen) 659 veclen = sc->simdlen; 660 if (sc->mask_mode != VOIDmode) 661 adj.type 662 = lang_hooks.types.type_for_mode (sc->mask_mode, 1); 663 else if (POINTER_TYPE_P (base_type)) 664 adj.type = build_vector_type (pointer_sized_int_node, veclen); 665 else 666 adj.type = build_vector_type (base_type, veclen); 667 adjustments.safe_push (adj); 668 669 for (j = veclen; j < sc->simdlen; j += veclen) 670 adjustments.safe_push (adj); 671 672 /* We have previously allocated one extra entry for the mask. Use 673 it and fill it. */ 674 sc->nargs++; 675 if (sc->mask_mode != VOIDmode) 676 base_type = boolean_type_node; 677 if (node->definition) 678 { 679 sc->args[i].orig_arg 680 = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL, base_type); 681 if (sc->mask_mode == VOIDmode) 682 sc->args[i].simd_array 683 = create_tmp_simd_array ("mask", base_type, sc->simdlen); 684 else if (veclen < sc->simdlen) 685 sc->args[i].simd_array 686 = create_tmp_simd_array ("mask", adj.type, sc->simdlen / veclen); 687 else 688 sc->args[i].simd_array = NULL_TREE; 689 } 690 sc->args[i].orig_type = base_type; 691 sc->args[i].arg_type = SIMD_CLONE_ARG_TYPE_MASK; 692 } 693 694 if (node->definition) 695 ipa_modify_formal_parameters (node->decl, adjustments); 696 else 697 { 698 tree new_arg_types = NULL_TREE, new_reversed; 699 bool last_parm_void = false; 700 if (args.length () > 0 && args.last () == void_type_node) 701 last_parm_void = true; 702 703 gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl))); 704 j = adjustments.length (); 705 for (i = 0; i < j; i++) 706 { 707 struct ipa_parm_adjustment *adj = &adjustments[i]; 708 tree ptype; 709 if (adj->op == IPA_PARM_OP_COPY) 710 ptype = args[adj->base_index]; 711 else 712 ptype = adj->type; 713 new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types); 714 } 715 new_reversed = nreverse (new_arg_types); 716 if (last_parm_void) 717 { 718 if (new_reversed) 719 TREE_CHAIN (new_arg_types) = void_list_node; 720 else 721 new_reversed = void_list_node; 722 } 723 724 tree new_type = build_distinct_type_copy (TREE_TYPE (node->decl)); 725 TYPE_ARG_TYPES (new_type) = new_reversed; 726 TREE_TYPE (node->decl) = new_type; 727 728 adjustments.release (); 729 } 730 args.release (); 731 return adjustments; 732 } 733 734 /* Initialize and copy the function arguments in NODE to their 735 corresponding local simd arrays. Returns a fresh gimple_seq with 736 the instruction sequence generated. */ 737 738 static gimple_seq 739 simd_clone_init_simd_arrays (struct cgraph_node *node, 740 ipa_parm_adjustment_vec adjustments) 741 { 742 gimple_seq seq = NULL; 743 unsigned i = 0, j = 0, k; 744 745 for (tree arg = DECL_ARGUMENTS (node->decl); 746 arg; 747 arg = DECL_CHAIN (arg), i++, j++) 748 { 749 if (adjustments[j].op == IPA_PARM_OP_COPY 750 || POINTER_TYPE_P (TREE_TYPE (arg))) 751 continue; 752 753 node->simdclone->args[i].vector_arg = arg; 754 755 tree array = node->simdclone->args[i].simd_array; 756 if (node->simdclone->mask_mode != VOIDmode 757 && node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK) 758 { 759 if (array == NULL_TREE) 760 continue; 761 unsigned int l 762 = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array)))); 763 for (k = 0; k <= l; k++) 764 { 765 if (k) 766 { 767 arg = DECL_CHAIN (arg); 768 j++; 769 } 770 tree t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)), 771 array, size_int (k), NULL, NULL); 772 t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg); 773 gimplify_and_add (t, &seq); 774 } 775 continue; 776 } 777 if (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg)) == node->simdclone->simdlen) 778 { 779 tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array))); 780 tree ptr = build_fold_addr_expr (array); 781 tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr, 782 build_int_cst (ptype, 0)); 783 t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg); 784 gimplify_and_add (t, &seq); 785 } 786 else 787 { 788 unsigned int simdlen = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg)); 789 tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array))); 790 for (k = 0; k < node->simdclone->simdlen; k += simdlen) 791 { 792 tree ptr = build_fold_addr_expr (array); 793 int elemsize; 794 if (k) 795 { 796 arg = DECL_CHAIN (arg); 797 j++; 798 } 799 elemsize 800 = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (arg)))); 801 tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr, 802 build_int_cst (ptype, k * elemsize)); 803 t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg); 804 gimplify_and_add (t, &seq); 805 } 806 } 807 } 808 return seq; 809 } 810 811 /* Callback info for ipa_simd_modify_stmt_ops below. */ 812 813 struct modify_stmt_info { 814 ipa_parm_adjustment_vec adjustments; 815 gimple *stmt; 816 /* True if the parent statement was modified by 817 ipa_simd_modify_stmt_ops. */ 818 bool modified; 819 }; 820 821 /* Callback for walk_gimple_op. 822 823 Adjust operands from a given statement as specified in the 824 adjustments vector in the callback data. */ 825 826 static tree 827 ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data) 828 { 829 struct walk_stmt_info *wi = (struct walk_stmt_info *) data; 830 struct modify_stmt_info *info = (struct modify_stmt_info *) wi->info; 831 tree *orig_tp = tp; 832 if (TREE_CODE (*tp) == ADDR_EXPR) 833 tp = &TREE_OPERAND (*tp, 0); 834 struct ipa_parm_adjustment *cand = NULL; 835 if (TREE_CODE (*tp) == PARM_DECL) 836 cand = ipa_get_adjustment_candidate (&tp, NULL, info->adjustments, true); 837 else 838 { 839 if (TYPE_P (*tp)) 840 *walk_subtrees = 0; 841 } 842 843 tree repl = NULL_TREE; 844 if (cand) 845 repl = unshare_expr (cand->new_decl); 846 else 847 { 848 if (tp != orig_tp) 849 { 850 *walk_subtrees = 0; 851 bool modified = info->modified; 852 info->modified = false; 853 walk_tree (tp, ipa_simd_modify_stmt_ops, wi, wi->pset); 854 if (!info->modified) 855 { 856 info->modified = modified; 857 return NULL_TREE; 858 } 859 info->modified = modified; 860 repl = *tp; 861 } 862 else 863 return NULL_TREE; 864 } 865 866 if (tp != orig_tp) 867 { 868 if (gimple_code (info->stmt) == GIMPLE_PHI 869 && cand 870 && TREE_CODE (*orig_tp) == ADDR_EXPR 871 && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL 872 && cand->alias_ptr_type) 873 { 874 gcc_assert (TREE_CODE (cand->alias_ptr_type) == SSA_NAME); 875 *orig_tp = cand->alias_ptr_type; 876 info->modified = true; 877 return NULL_TREE; 878 } 879 880 repl = build_fold_addr_expr (repl); 881 gimple *stmt; 882 if (is_gimple_debug (info->stmt)) 883 { 884 tree vexpr = make_node (DEBUG_EXPR_DECL); 885 stmt = gimple_build_debug_source_bind (vexpr, repl, NULL); 886 DECL_ARTIFICIAL (vexpr) = 1; 887 TREE_TYPE (vexpr) = TREE_TYPE (repl); 888 SET_DECL_MODE (vexpr, TYPE_MODE (TREE_TYPE (repl))); 889 repl = vexpr; 890 } 891 else 892 { 893 stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl); 894 repl = gimple_assign_lhs (stmt); 895 } 896 gimple_stmt_iterator gsi; 897 if (gimple_code (info->stmt) == GIMPLE_PHI) 898 { 899 gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); 900 /* Cache SSA_NAME for next time. */ 901 if (cand 902 && TREE_CODE (*orig_tp) == ADDR_EXPR 903 && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL) 904 cand->alias_ptr_type = repl; 905 } 906 else 907 gsi = gsi_for_stmt (info->stmt); 908 gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); 909 *orig_tp = repl; 910 } 911 else if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl))) 912 { 913 tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl); 914 *tp = vce; 915 } 916 else 917 *tp = repl; 918 919 info->modified = true; 920 return NULL_TREE; 921 } 922 923 /* Traverse the function body and perform all modifications as 924 described in ADJUSTMENTS. At function return, ADJUSTMENTS will be 925 modified such that the replacement/reduction value will now be an 926 offset into the corresponding simd_array. 927 928 This function will replace all function argument uses with their 929 corresponding simd array elements, and ajust the return values 930 accordingly. */ 931 932 static void 933 ipa_simd_modify_function_body (struct cgraph_node *node, 934 ipa_parm_adjustment_vec adjustments, 935 tree retval_array, tree iter) 936 { 937 basic_block bb; 938 unsigned int i, j, l; 939 940 /* Re-use the adjustments array, but this time use it to replace 941 every function argument use to an offset into the corresponding 942 simd_array. */ 943 for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j) 944 { 945 if (!node->simdclone->args[i].vector_arg) 946 continue; 947 948 tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg); 949 tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg); 950 adjustments[j].new_decl 951 = build4 (ARRAY_REF, 952 basetype, 953 node->simdclone->args[i].simd_array, 954 iter, 955 NULL_TREE, NULL_TREE); 956 if (adjustments[j].op == IPA_PARM_OP_NONE 957 && TYPE_VECTOR_SUBPARTS (vectype) < node->simdclone->simdlen) 958 j += node->simdclone->simdlen / TYPE_VECTOR_SUBPARTS (vectype) - 1; 959 } 960 961 l = adjustments.length (); 962 tree name; 963 964 FOR_EACH_SSA_NAME (i, name, cfun) 965 { 966 if (SSA_NAME_VAR (name) 967 && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL) 968 { 969 for (j = 0; j < l; j++) 970 if (SSA_NAME_VAR (name) == adjustments[j].base 971 && adjustments[j].new_decl) 972 { 973 tree base_var; 974 if (adjustments[j].new_ssa_base == NULL_TREE) 975 { 976 base_var 977 = copy_var_decl (adjustments[j].base, 978 DECL_NAME (adjustments[j].base), 979 TREE_TYPE (adjustments[j].base)); 980 adjustments[j].new_ssa_base = base_var; 981 } 982 else 983 base_var = adjustments[j].new_ssa_base; 984 if (SSA_NAME_IS_DEFAULT_DEF (name)) 985 { 986 bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); 987 gimple_stmt_iterator gsi = gsi_after_labels (bb); 988 tree new_decl = unshare_expr (adjustments[j].new_decl); 989 set_ssa_default_def (cfun, adjustments[j].base, NULL_TREE); 990 SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var); 991 SSA_NAME_IS_DEFAULT_DEF (name) = 0; 992 gimple *stmt = gimple_build_assign (name, new_decl); 993 gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); 994 } 995 else 996 SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var); 997 } 998 } 999 } 1000 1001 struct modify_stmt_info info; 1002 info.adjustments = adjustments; 1003 1004 FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl)) 1005 { 1006 gimple_stmt_iterator gsi; 1007 1008 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) 1009 { 1010 gphi *phi = as_a <gphi *> (gsi_stmt (gsi)); 1011 int i, n = gimple_phi_num_args (phi); 1012 info.stmt = phi; 1013 struct walk_stmt_info wi; 1014 memset (&wi, 0, sizeof (wi)); 1015 info.modified = false; 1016 wi.info = &info; 1017 for (i = 0; i < n; ++i) 1018 { 1019 int walk_subtrees = 1; 1020 tree arg = gimple_phi_arg_def (phi, i); 1021 tree op = arg; 1022 ipa_simd_modify_stmt_ops (&op, &walk_subtrees, &wi); 1023 if (op != arg) 1024 { 1025 SET_PHI_ARG_DEF (phi, i, op); 1026 gcc_assert (TREE_CODE (op) == SSA_NAME); 1027 if (gimple_phi_arg_edge (phi, i)->flags & EDGE_ABNORMAL) 1028 SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1; 1029 } 1030 } 1031 } 1032 1033 gsi = gsi_start_bb (bb); 1034 while (!gsi_end_p (gsi)) 1035 { 1036 gimple *stmt = gsi_stmt (gsi); 1037 info.stmt = stmt; 1038 struct walk_stmt_info wi; 1039 1040 memset (&wi, 0, sizeof (wi)); 1041 info.modified = false; 1042 wi.info = &info; 1043 walk_gimple_op (stmt, ipa_simd_modify_stmt_ops, &wi); 1044 1045 if (greturn *return_stmt = dyn_cast <greturn *> (stmt)) 1046 { 1047 tree retval = gimple_return_retval (return_stmt); 1048 edge e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun)); 1049 e->flags |= EDGE_FALLTHRU; 1050 if (!retval) 1051 { 1052 gsi_remove (&gsi, true); 1053 continue; 1054 } 1055 1056 /* Replace `return foo' with `retval_array[iter] = foo'. */ 1057 tree ref = build4 (ARRAY_REF, TREE_TYPE (retval), 1058 retval_array, iter, NULL, NULL); 1059 stmt = gimple_build_assign (ref, retval); 1060 gsi_replace (&gsi, stmt, true); 1061 info.modified = true; 1062 } 1063 1064 if (info.modified) 1065 { 1066 update_stmt (stmt); 1067 if (maybe_clean_eh_stmt (stmt)) 1068 gimple_purge_dead_eh_edges (gimple_bb (stmt)); 1069 } 1070 gsi_next (&gsi); 1071 } 1072 } 1073 } 1074 1075 /* Helper function of simd_clone_adjust, return linear step addend 1076 of Ith argument. */ 1077 1078 static tree 1079 simd_clone_linear_addend (struct cgraph_node *node, unsigned int i, 1080 tree addtype, basic_block entry_bb) 1081 { 1082 tree ptype = NULL_TREE; 1083 switch (node->simdclone->args[i].arg_type) 1084 { 1085 case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP: 1086 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP: 1087 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP: 1088 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP: 1089 return build_int_cst (addtype, node->simdclone->args[i].linear_step); 1090 case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP: 1091 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP: 1092 ptype = TREE_TYPE (node->simdclone->args[i].orig_arg); 1093 break; 1094 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP: 1095 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP: 1096 ptype = TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg)); 1097 break; 1098 default: 1099 gcc_unreachable (); 1100 } 1101 1102 unsigned int idx = node->simdclone->args[i].linear_step; 1103 tree arg = node->simdclone->args[idx].orig_arg; 1104 gcc_assert (is_gimple_reg_type (TREE_TYPE (arg))); 1105 gimple_stmt_iterator gsi = gsi_after_labels (entry_bb); 1106 gimple *g; 1107 tree ret; 1108 if (is_gimple_reg (arg)) 1109 ret = get_or_create_ssa_default_def (cfun, arg); 1110 else 1111 { 1112 g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg); 1113 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1114 ret = gimple_assign_lhs (g); 1115 } 1116 if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE) 1117 { 1118 g = gimple_build_assign (make_ssa_name (TREE_TYPE (TREE_TYPE (arg))), 1119 build_simple_mem_ref (ret)); 1120 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1121 ret = gimple_assign_lhs (g); 1122 } 1123 if (!useless_type_conversion_p (addtype, TREE_TYPE (ret))) 1124 { 1125 g = gimple_build_assign (make_ssa_name (addtype), NOP_EXPR, ret); 1126 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1127 ret = gimple_assign_lhs (g); 1128 } 1129 if (POINTER_TYPE_P (ptype)) 1130 { 1131 tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptype)); 1132 if (size && TREE_CODE (size) == INTEGER_CST) 1133 { 1134 g = gimple_build_assign (make_ssa_name (addtype), MULT_EXPR, 1135 ret, fold_convert (addtype, size)); 1136 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1137 ret = gimple_assign_lhs (g); 1138 } 1139 } 1140 return ret; 1141 } 1142 1143 /* Adjust the argument types in NODE to their appropriate vector 1144 counterparts. */ 1145 1146 static void 1147 simd_clone_adjust (struct cgraph_node *node) 1148 { 1149 push_cfun (DECL_STRUCT_FUNCTION (node->decl)); 1150 1151 targetm.simd_clone.adjust (node); 1152 1153 tree retval = simd_clone_adjust_return_type (node); 1154 ipa_parm_adjustment_vec adjustments 1155 = simd_clone_adjust_argument_types (node); 1156 1157 push_gimplify_context (); 1158 1159 gimple_seq seq = simd_clone_init_simd_arrays (node, adjustments); 1160 1161 /* Adjust all uses of vector arguments accordingly. Adjust all 1162 return values accordingly. */ 1163 tree iter = create_tmp_var (unsigned_type_node, "iter"); 1164 tree iter1 = make_ssa_name (iter); 1165 tree iter2 = NULL_TREE; 1166 ipa_simd_modify_function_body (node, adjustments, retval, iter1); 1167 adjustments.release (); 1168 1169 /* Initialize the iteration variable. */ 1170 basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); 1171 basic_block body_bb = split_block_after_labels (entry_bb)->dest; 1172 gimple_stmt_iterator gsi = gsi_after_labels (entry_bb); 1173 /* Insert the SIMD array and iv initialization at function 1174 entry. */ 1175 gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT); 1176 1177 pop_gimplify_context (NULL); 1178 1179 gimple *g; 1180 basic_block incr_bb = NULL; 1181 struct loop *loop = NULL; 1182 1183 /* Create a new BB right before the original exit BB, to hold the 1184 iteration increment and the condition/branch. */ 1185 if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)) 1186 { 1187 basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src; 1188 incr_bb = create_empty_bb (orig_exit); 1189 add_bb_to_loop (incr_bb, body_bb->loop_father); 1190 while (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)) 1191 { 1192 edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0); 1193 redirect_edge_succ (e, incr_bb); 1194 } 1195 } 1196 else if (node->simdclone->inbranch) 1197 { 1198 incr_bb = create_empty_bb (entry_bb); 1199 add_bb_to_loop (incr_bb, body_bb->loop_father); 1200 } 1201 1202 if (incr_bb) 1203 { 1204 edge e = make_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0); 1205 e->probability = REG_BR_PROB_BASE; 1206 gsi = gsi_last_bb (incr_bb); 1207 iter2 = make_ssa_name (iter); 1208 g = gimple_build_assign (iter2, PLUS_EXPR, iter1, 1209 build_int_cst (unsigned_type_node, 1)); 1210 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1211 1212 /* Mostly annotate the loop for the vectorizer (the rest is done 1213 below). */ 1214 loop = alloc_loop (); 1215 cfun->has_force_vectorize_loops = true; 1216 loop->safelen = node->simdclone->simdlen; 1217 loop->force_vectorize = true; 1218 loop->header = body_bb; 1219 } 1220 1221 /* Branch around the body if the mask applies. */ 1222 if (node->simdclone->inbranch) 1223 { 1224 gsi = gsi_last_bb (loop->header); 1225 tree mask_array 1226 = node->simdclone->args[node->simdclone->nargs - 1].simd_array; 1227 tree mask; 1228 if (node->simdclone->mask_mode != VOIDmode) 1229 { 1230 tree shift_cnt; 1231 if (mask_array == NULL_TREE) 1232 { 1233 tree arg = node->simdclone->args[node->simdclone->nargs 1234 - 1].vector_arg; 1235 mask = get_or_create_ssa_default_def (cfun, arg); 1236 shift_cnt = iter1; 1237 } 1238 else 1239 { 1240 tree maskt = TREE_TYPE (mask_array); 1241 int c = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (maskt))); 1242 c = node->simdclone->simdlen / (c + 1); 1243 int s = exact_log2 (c); 1244 gcc_assert (s > 0); 1245 c--; 1246 tree idx = make_ssa_name (TREE_TYPE (iter1)); 1247 g = gimple_build_assign (idx, RSHIFT_EXPR, iter1, 1248 build_int_cst (NULL_TREE, s)); 1249 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1250 mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array))); 1251 tree aref = build4 (ARRAY_REF, 1252 TREE_TYPE (TREE_TYPE (mask_array)), 1253 mask_array, idx, NULL, NULL); 1254 g = gimple_build_assign (mask, aref); 1255 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1256 shift_cnt = make_ssa_name (TREE_TYPE (iter1)); 1257 g = gimple_build_assign (shift_cnt, BIT_AND_EXPR, iter1, 1258 build_int_cst (TREE_TYPE (iter1), c)); 1259 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1260 } 1261 g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)), 1262 RSHIFT_EXPR, mask, shift_cnt); 1263 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1264 mask = gimple_assign_lhs (g); 1265 g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)), 1266 BIT_AND_EXPR, mask, 1267 build_int_cst (TREE_TYPE (mask), 1)); 1268 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1269 mask = gimple_assign_lhs (g); 1270 } 1271 else 1272 { 1273 mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array))); 1274 tree aref = build4 (ARRAY_REF, 1275 TREE_TYPE (TREE_TYPE (mask_array)), 1276 mask_array, iter1, NULL, NULL); 1277 g = gimple_build_assign (mask, aref); 1278 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1279 int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (aref))); 1280 if (!INTEGRAL_TYPE_P (TREE_TYPE (aref))) 1281 { 1282 aref = build1 (VIEW_CONVERT_EXPR, 1283 build_nonstandard_integer_type (bitsize, 0), 1284 mask); 1285 mask = make_ssa_name (TREE_TYPE (aref)); 1286 g = gimple_build_assign (mask, aref); 1287 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1288 } 1289 } 1290 1291 g = gimple_build_cond (EQ_EXPR, mask, build_zero_cst (TREE_TYPE (mask)), 1292 NULL, NULL); 1293 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1294 make_edge (loop->header, incr_bb, EDGE_TRUE_VALUE); 1295 FALLTHRU_EDGE (loop->header)->flags = EDGE_FALSE_VALUE; 1296 } 1297 1298 basic_block latch_bb = NULL; 1299 basic_block new_exit_bb = NULL; 1300 1301 /* Generate the condition. */ 1302 if (incr_bb) 1303 { 1304 gsi = gsi_last_bb (incr_bb); 1305 g = gimple_build_cond (LT_EXPR, iter2, 1306 build_int_cst (unsigned_type_node, 1307 node->simdclone->simdlen), 1308 NULL, NULL); 1309 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1310 edge e = split_block (incr_bb, gsi_stmt (gsi)); 1311 latch_bb = e->dest; 1312 new_exit_bb = split_block_after_labels (latch_bb)->dest; 1313 loop->latch = latch_bb; 1314 1315 redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb); 1316 1317 make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE); 1318 /* The successor of incr_bb is already pointing to latch_bb; just 1319 change the flags. 1320 make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE); */ 1321 FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE; 1322 } 1323 1324 gphi *phi = create_phi_node (iter1, body_bb); 1325 edge preheader_edge = find_edge (entry_bb, body_bb); 1326 edge latch_edge = NULL; 1327 add_phi_arg (phi, build_zero_cst (unsigned_type_node), preheader_edge, 1328 UNKNOWN_LOCATION); 1329 if (incr_bb) 1330 { 1331 latch_edge = single_succ_edge (latch_bb); 1332 add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION); 1333 1334 /* Generate the new return. */ 1335 gsi = gsi_last_bb (new_exit_bb); 1336 if (retval 1337 && TREE_CODE (retval) == VIEW_CONVERT_EXPR 1338 && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL) 1339 retval = TREE_OPERAND (retval, 0); 1340 else if (retval) 1341 { 1342 retval = build1 (VIEW_CONVERT_EXPR, 1343 TREE_TYPE (TREE_TYPE (node->decl)), 1344 retval); 1345 retval = force_gimple_operand_gsi (&gsi, retval, true, NULL, 1346 false, GSI_CONTINUE_LINKING); 1347 } 1348 g = gimple_build_return (retval); 1349 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); 1350 } 1351 1352 /* Handle aligned clauses by replacing default defs of the aligned 1353 uniform args with __builtin_assume_aligned (arg_N(D), alignment) 1354 lhs. Handle linear by adding PHIs. */ 1355 for (unsigned i = 0; i < node->simdclone->nargs; i++) 1356 if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM 1357 && (TREE_ADDRESSABLE (node->simdclone->args[i].orig_arg) 1358 || !is_gimple_reg_type 1359 (TREE_TYPE (node->simdclone->args[i].orig_arg)))) 1360 { 1361 tree orig_arg = node->simdclone->args[i].orig_arg; 1362 if (is_gimple_reg_type (TREE_TYPE (orig_arg))) 1363 iter1 = make_ssa_name (TREE_TYPE (orig_arg)); 1364 else 1365 { 1366 iter1 = create_tmp_var_raw (TREE_TYPE (orig_arg)); 1367 gimple_add_tmp_var (iter1); 1368 } 1369 gsi = gsi_after_labels (entry_bb); 1370 g = gimple_build_assign (iter1, orig_arg); 1371 gsi_insert_before (&gsi, g, GSI_NEW_STMT); 1372 gsi = gsi_after_labels (body_bb); 1373 g = gimple_build_assign (orig_arg, iter1); 1374 gsi_insert_before (&gsi, g, GSI_NEW_STMT); 1375 } 1376 else if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM 1377 && DECL_BY_REFERENCE (node->simdclone->args[i].orig_arg) 1378 && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg)) 1379 == REFERENCE_TYPE 1380 && TREE_ADDRESSABLE 1381 (TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg)))) 1382 { 1383 tree orig_arg = node->simdclone->args[i].orig_arg; 1384 tree def = ssa_default_def (cfun, orig_arg); 1385 if (def && !has_zero_uses (def)) 1386 { 1387 iter1 = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (orig_arg))); 1388 gimple_add_tmp_var (iter1); 1389 gsi = gsi_after_labels (entry_bb); 1390 g = gimple_build_assign (iter1, build_simple_mem_ref (def)); 1391 gsi_insert_before (&gsi, g, GSI_NEW_STMT); 1392 gsi = gsi_after_labels (body_bb); 1393 g = gimple_build_assign (build_simple_mem_ref (def), iter1); 1394 gsi_insert_before (&gsi, g, GSI_NEW_STMT); 1395 } 1396 } 1397 else if (node->simdclone->args[i].alignment 1398 && node->simdclone->args[i].arg_type 1399 == SIMD_CLONE_ARG_TYPE_UNIFORM 1400 && (node->simdclone->args[i].alignment 1401 & (node->simdclone->args[i].alignment - 1)) == 0 1402 && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg)) 1403 == POINTER_TYPE) 1404 { 1405 unsigned int alignment = node->simdclone->args[i].alignment; 1406 tree orig_arg = node->simdclone->args[i].orig_arg; 1407 tree def = ssa_default_def (cfun, orig_arg); 1408 if (def && !has_zero_uses (def)) 1409 { 1410 tree fn = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED); 1411 gimple_seq seq = NULL; 1412 bool need_cvt = false; 1413 gcall *call 1414 = gimple_build_call (fn, 2, def, size_int (alignment)); 1415 g = call; 1416 if (!useless_type_conversion_p (TREE_TYPE (orig_arg), 1417 ptr_type_node)) 1418 need_cvt = true; 1419 tree t = make_ssa_name (need_cvt ? ptr_type_node : orig_arg); 1420 gimple_call_set_lhs (g, t); 1421 gimple_seq_add_stmt_without_update (&seq, g); 1422 if (need_cvt) 1423 { 1424 t = make_ssa_name (orig_arg); 1425 g = gimple_build_assign (t, NOP_EXPR, gimple_call_lhs (g)); 1426 gimple_seq_add_stmt_without_update (&seq, g); 1427 } 1428 gsi_insert_seq_on_edge_immediate 1429 (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq); 1430 1431 entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); 1432 int freq = compute_call_stmt_bb_frequency (current_function_decl, 1433 entry_bb); 1434 node->create_edge (cgraph_node::get_create (fn), 1435 call, entry_bb->count, freq); 1436 1437 imm_use_iterator iter; 1438 use_operand_p use_p; 1439 gimple *use_stmt; 1440 tree repl = gimple_get_lhs (g); 1441 FOR_EACH_IMM_USE_STMT (use_stmt, iter, def) 1442 if (is_gimple_debug (use_stmt) || use_stmt == call) 1443 continue; 1444 else 1445 FOR_EACH_IMM_USE_ON_STMT (use_p, iter) 1446 SET_USE (use_p, repl); 1447 } 1448 } 1449 else if ((node->simdclone->args[i].arg_type 1450 == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP) 1451 || (node->simdclone->args[i].arg_type 1452 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP) 1453 || (node->simdclone->args[i].arg_type 1454 == SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP) 1455 || (node->simdclone->args[i].arg_type 1456 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP)) 1457 { 1458 tree orig_arg = node->simdclone->args[i].orig_arg; 1459 gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (orig_arg)) 1460 || POINTER_TYPE_P (TREE_TYPE (orig_arg))); 1461 tree def = NULL_TREE; 1462 if (TREE_ADDRESSABLE (orig_arg)) 1463 { 1464 def = make_ssa_name (TREE_TYPE (orig_arg)); 1465 iter1 = make_ssa_name (TREE_TYPE (orig_arg)); 1466 if (incr_bb) 1467 iter2 = make_ssa_name (TREE_TYPE (orig_arg)); 1468 gsi = gsi_after_labels (entry_bb); 1469 g = gimple_build_assign (def, orig_arg); 1470 gsi_insert_before (&gsi, g, GSI_NEW_STMT); 1471 } 1472 else 1473 { 1474 def = ssa_default_def (cfun, orig_arg); 1475 if (!def || has_zero_uses (def)) 1476 def = NULL_TREE; 1477 else 1478 { 1479 iter1 = make_ssa_name (orig_arg); 1480 if (incr_bb) 1481 iter2 = make_ssa_name (orig_arg); 1482 } 1483 } 1484 if (def) 1485 { 1486 phi = create_phi_node (iter1, body_bb); 1487 add_phi_arg (phi, def, preheader_edge, UNKNOWN_LOCATION); 1488 if (incr_bb) 1489 { 1490 add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION); 1491 enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg)) 1492 ? PLUS_EXPR : POINTER_PLUS_EXPR; 1493 tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg)) 1494 ? TREE_TYPE (orig_arg) : sizetype; 1495 tree addcst = simd_clone_linear_addend (node, i, addtype, 1496 entry_bb); 1497 gsi = gsi_last_bb (incr_bb); 1498 g = gimple_build_assign (iter2, code, iter1, addcst); 1499 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1500 } 1501 1502 imm_use_iterator iter; 1503 use_operand_p use_p; 1504 gimple *use_stmt; 1505 if (TREE_ADDRESSABLE (orig_arg)) 1506 { 1507 gsi = gsi_after_labels (body_bb); 1508 g = gimple_build_assign (orig_arg, iter1); 1509 gsi_insert_before (&gsi, g, GSI_NEW_STMT); 1510 } 1511 else 1512 FOR_EACH_IMM_USE_STMT (use_stmt, iter, def) 1513 if (use_stmt == phi) 1514 continue; 1515 else 1516 FOR_EACH_IMM_USE_ON_STMT (use_p, iter) 1517 SET_USE (use_p, iter1); 1518 } 1519 } 1520 else if (node->simdclone->args[i].arg_type 1521 == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP 1522 || (node->simdclone->args[i].arg_type 1523 == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP)) 1524 { 1525 tree orig_arg = node->simdclone->args[i].orig_arg; 1526 tree def = ssa_default_def (cfun, orig_arg); 1527 gcc_assert (!TREE_ADDRESSABLE (orig_arg) 1528 && TREE_CODE (TREE_TYPE (orig_arg)) == REFERENCE_TYPE); 1529 if (def && !has_zero_uses (def)) 1530 { 1531 tree rtype = TREE_TYPE (TREE_TYPE (orig_arg)); 1532 iter1 = make_ssa_name (orig_arg); 1533 if (incr_bb) 1534 iter2 = make_ssa_name (orig_arg); 1535 tree iter3 = make_ssa_name (rtype); 1536 tree iter4 = make_ssa_name (rtype); 1537 tree iter5 = incr_bb ? make_ssa_name (rtype) : NULL_TREE; 1538 gsi = gsi_after_labels (entry_bb); 1539 gimple *load 1540 = gimple_build_assign (iter3, build_simple_mem_ref (def)); 1541 gsi_insert_before (&gsi, load, GSI_NEW_STMT); 1542 1543 tree array = node->simdclone->args[i].simd_array; 1544 TREE_ADDRESSABLE (array) = 1; 1545 tree ptr = build_fold_addr_expr (array); 1546 phi = create_phi_node (iter1, body_bb); 1547 add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION); 1548 if (incr_bb) 1549 { 1550 add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION); 1551 g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1, 1552 TYPE_SIZE_UNIT (TREE_TYPE (iter3))); 1553 gsi = gsi_last_bb (incr_bb); 1554 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1555 } 1556 1557 phi = create_phi_node (iter4, body_bb); 1558 add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION); 1559 if (incr_bb) 1560 { 1561 add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION); 1562 enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3)) 1563 ? PLUS_EXPR : POINTER_PLUS_EXPR; 1564 tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3)) 1565 ? TREE_TYPE (iter3) : sizetype; 1566 tree addcst = simd_clone_linear_addend (node, i, addtype, 1567 entry_bb); 1568 g = gimple_build_assign (iter5, code, iter4, addcst); 1569 gsi = gsi_last_bb (incr_bb); 1570 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1571 } 1572 1573 g = gimple_build_assign (build_simple_mem_ref (iter1), iter4); 1574 gsi = gsi_after_labels (body_bb); 1575 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1576 1577 imm_use_iterator iter; 1578 use_operand_p use_p; 1579 gimple *use_stmt; 1580 FOR_EACH_IMM_USE_STMT (use_stmt, iter, def) 1581 if (use_stmt == load) 1582 continue; 1583 else 1584 FOR_EACH_IMM_USE_ON_STMT (use_p, iter) 1585 SET_USE (use_p, iter1); 1586 1587 if (!TYPE_READONLY (rtype) && incr_bb) 1588 { 1589 tree v = make_ssa_name (rtype); 1590 tree aref = build4 (ARRAY_REF, rtype, array, 1591 size_zero_node, NULL_TREE, 1592 NULL_TREE); 1593 gsi = gsi_after_labels (new_exit_bb); 1594 g = gimple_build_assign (v, aref); 1595 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1596 g = gimple_build_assign (build_simple_mem_ref (def), v); 1597 gsi_insert_before (&gsi, g, GSI_SAME_STMT); 1598 } 1599 } 1600 } 1601 1602 calculate_dominance_info (CDI_DOMINATORS); 1603 if (loop) 1604 add_loop (loop, loop->header->loop_father); 1605 update_ssa (TODO_update_ssa); 1606 1607 pop_cfun (); 1608 } 1609 1610 /* If the function in NODE is tagged as an elemental SIMD function, 1611 create the appropriate SIMD clones. */ 1612 1613 static void 1614 expand_simd_clones (struct cgraph_node *node) 1615 { 1616 tree attr = lookup_attribute ("omp declare simd", 1617 DECL_ATTRIBUTES (node->decl)); 1618 if (attr == NULL_TREE 1619 || node->global.inlined_to 1620 || lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl))) 1621 return; 1622 1623 /* Ignore 1624 #pragma omp declare simd 1625 extern int foo (); 1626 in C, there we don't know the argument types at all. */ 1627 if (!node->definition 1628 && TYPE_ARG_TYPES (TREE_TYPE (node->decl)) == NULL_TREE) 1629 return; 1630 1631 /* Call this before creating clone_info, as it might ggc_collect. */ 1632 if (node->definition && node->has_gimple_body_p ()) 1633 node->get_body (); 1634 1635 do 1636 { 1637 /* Start with parsing the "omp declare simd" attribute(s). */ 1638 bool inbranch_clause_specified; 1639 struct cgraph_simd_clone *clone_info 1640 = simd_clone_clauses_extract (node, TREE_VALUE (attr), 1641 &inbranch_clause_specified); 1642 if (clone_info == NULL) 1643 continue; 1644 1645 int orig_simdlen = clone_info->simdlen; 1646 tree base_type = simd_clone_compute_base_data_type (node, clone_info); 1647 /* The target can return 0 (no simd clones should be created), 1648 1 (just one ISA of simd clones should be created) or higher 1649 count of ISA variants. In that case, clone_info is initialized 1650 for the first ISA variant. */ 1651 int count 1652 = targetm.simd_clone.compute_vecsize_and_simdlen (node, clone_info, 1653 base_type, 0); 1654 if (count == 0) 1655 continue; 1656 1657 /* Loop over all COUNT ISA variants, and if !INBRANCH_CLAUSE_SPECIFIED, 1658 also create one inbranch and one !inbranch clone of it. */ 1659 for (int i = 0; i < count * 2; i++) 1660 { 1661 struct cgraph_simd_clone *clone = clone_info; 1662 if (inbranch_clause_specified && (i & 1) != 0) 1663 continue; 1664 1665 if (i != 0) 1666 { 1667 clone = simd_clone_struct_alloc (clone_info->nargs 1668 + ((i & 1) != 0)); 1669 simd_clone_struct_copy (clone, clone_info); 1670 /* Undo changes targetm.simd_clone.compute_vecsize_and_simdlen 1671 and simd_clone_adjust_argument_types did to the first 1672 clone's info. */ 1673 clone->nargs -= clone_info->inbranch; 1674 clone->simdlen = orig_simdlen; 1675 /* And call the target hook again to get the right ISA. */ 1676 targetm.simd_clone.compute_vecsize_and_simdlen (node, clone, 1677 base_type, 1678 i / 2); 1679 if ((i & 1) != 0) 1680 clone->inbranch = 1; 1681 } 1682 1683 /* simd_clone_mangle might fail if such a clone has been created 1684 already. */ 1685 tree id = simd_clone_mangle (node, clone); 1686 if (id == NULL_TREE) 1687 continue; 1688 1689 /* Only when we are sure we want to create the clone actually 1690 clone the function (or definitions) or create another 1691 extern FUNCTION_DECL (for prototypes without definitions). */ 1692 struct cgraph_node *n = simd_clone_create (node); 1693 if (n == NULL) 1694 continue; 1695 1696 n->simdclone = clone; 1697 clone->origin = node; 1698 clone->next_clone = NULL; 1699 if (node->simd_clones == NULL) 1700 { 1701 clone->prev_clone = n; 1702 node->simd_clones = n; 1703 } 1704 else 1705 { 1706 clone->prev_clone = node->simd_clones->simdclone->prev_clone; 1707 clone->prev_clone->simdclone->next_clone = n; 1708 node->simd_clones->simdclone->prev_clone = n; 1709 } 1710 symtab->change_decl_assembler_name (n->decl, id); 1711 /* And finally adjust the return type, parameters and for 1712 definitions also function body. */ 1713 if (node->definition) 1714 simd_clone_adjust (n); 1715 else 1716 { 1717 simd_clone_adjust_return_type (n); 1718 simd_clone_adjust_argument_types (n); 1719 } 1720 } 1721 } 1722 while ((attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr)))); 1723 } 1724 1725 /* Entry point for IPA simd clone creation pass. */ 1726 1727 static unsigned int 1728 ipa_omp_simd_clone (void) 1729 { 1730 struct cgraph_node *node; 1731 FOR_EACH_FUNCTION (node) 1732 expand_simd_clones (node); 1733 return 0; 1734 } 1735 1736 namespace { 1737 1738 const pass_data pass_data_omp_simd_clone = 1739 { 1740 SIMPLE_IPA_PASS, /* type */ 1741 "simdclone", /* name */ 1742 OPTGROUP_OMP, /* optinfo_flags */ 1743 TV_NONE, /* tv_id */ 1744 ( PROP_ssa | PROP_cfg ), /* properties_required */ 1745 0, /* properties_provided */ 1746 0, /* properties_destroyed */ 1747 0, /* todo_flags_start */ 1748 0, /* todo_flags_finish */ 1749 }; 1750 1751 class pass_omp_simd_clone : public simple_ipa_opt_pass 1752 { 1753 public: 1754 pass_omp_simd_clone(gcc::context *ctxt) 1755 : simple_ipa_opt_pass(pass_data_omp_simd_clone, ctxt) 1756 {} 1757 1758 /* opt_pass methods: */ 1759 virtual bool gate (function *); 1760 virtual unsigned int execute (function *) { return ipa_omp_simd_clone (); } 1761 }; 1762 1763 bool 1764 pass_omp_simd_clone::gate (function *) 1765 { 1766 return targetm.simd_clone.compute_vecsize_and_simdlen != NULL; 1767 } 1768 1769 } // anon namespace 1770 1771 simple_ipa_opt_pass * 1772 make_pass_omp_simd_clone (gcc::context *ctxt) 1773 { 1774 return new pass_omp_simd_clone (ctxt); 1775 } 1776