1 /* Statement Analysis and Transformation for Vectorization 2 Copyright (C) 2003-2022 Free Software Foundation, Inc. 3 Contributed by Dorit Naishlos <dorit (at) il.ibm.com> 4 and Ira Rosen <irar (at) il.ibm.com> 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 #include "config.h" 23 #include "system.h" 24 #include "coretypes.h" 25 #include "backend.h" 26 #include "target.h" 27 #include "rtl.h" 28 #include "tree.h" 29 #include "gimple.h" 30 #include "ssa.h" 31 #include "optabs-tree.h" 32 #include "insn-config.h" 33 #include "recog.h" /* FIXME: for insn_data */ 34 #include "cgraph.h" 35 #include "dumpfile.h" 36 #include "alias.h" 37 #include "fold-const.h" 38 #include "stor-layout.h" 39 #include "tree-eh.h" 40 #include "gimplify.h" 41 #include "gimple-iterator.h" 42 #include "gimplify-me.h" 43 #include "tree-cfg.h" 44 #include "tree-ssa-loop-manip.h" 45 #include "cfgloop.h" 46 #include "explow.h" 47 #include "tree-ssa-loop.h" 48 #include "tree-scalar-evolution.h" 49 #include "tree-vectorizer.h" 50 #include "builtins.h" 51 #include "internal-fn.h" 52 #include "tree-vector-builder.h" 53 #include "vec-perm-indices.h" 54 #include "tree-ssa-loop-niter.h" 55 #include "gimple-fold.h" 56 #include "regs.h" 57 #include "attribs.h" 58 59 /* For lang_hooks.types.type_for_mode. */ 60 #include "langhooks.h" 61 62 /* Return the vectorized type for the given statement. */ 63 64 tree 65 stmt_vectype (class _stmt_vec_info *stmt_info) 66 { 67 return STMT_VINFO_VECTYPE (stmt_info); 68 } 69 70 /* Return TRUE iff the given statement is in an inner loop relative to 71 the loop being vectorized. */ 72 bool 73 stmt_in_inner_loop_p (vec_info *vinfo, class _stmt_vec_info *stmt_info) 74 { 75 gimple *stmt = STMT_VINFO_STMT (stmt_info); 76 basic_block bb = gimple_bb (stmt); 77 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 78 class loop* loop; 79 80 if (!loop_vinfo) 81 return false; 82 83 loop = LOOP_VINFO_LOOP (loop_vinfo); 84 85 return (bb->loop_father == loop->inner); 86 } 87 88 /* Record the cost of a statement, either by directly informing the 89 target model or by saving it in a vector for later processing. 90 Return a preliminary estimate of the statement's cost. */ 91 92 static unsigned 93 record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count, 94 enum vect_cost_for_stmt kind, 95 stmt_vec_info stmt_info, slp_tree node, 96 tree vectype, int misalign, 97 enum vect_cost_model_location where) 98 { 99 if ((kind == vector_load || kind == unaligned_load) 100 && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info))) 101 kind = vector_gather_load; 102 if ((kind == vector_store || kind == unaligned_store) 103 && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info))) 104 kind = vector_scatter_store; 105 106 stmt_info_for_cost si 107 = { count, kind, where, stmt_info, node, vectype, misalign }; 108 body_cost_vec->safe_push (si); 109 110 return (unsigned) 111 (builtin_vectorization_cost (kind, vectype, misalign) * count); 112 } 113 114 unsigned 115 record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count, 116 enum vect_cost_for_stmt kind, stmt_vec_info stmt_info, 117 tree vectype, int misalign, 118 enum vect_cost_model_location where) 119 { 120 return record_stmt_cost (body_cost_vec, count, kind, stmt_info, NULL, 121 vectype, misalign, where); 122 } 123 124 unsigned 125 record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count, 126 enum vect_cost_for_stmt kind, slp_tree node, 127 tree vectype, int misalign, 128 enum vect_cost_model_location where) 129 { 130 return record_stmt_cost (body_cost_vec, count, kind, NULL, node, 131 vectype, misalign, where); 132 } 133 134 unsigned 135 record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count, 136 enum vect_cost_for_stmt kind, 137 enum vect_cost_model_location where) 138 { 139 gcc_assert (kind == cond_branch_taken || kind == cond_branch_not_taken 140 || kind == scalar_stmt); 141 return record_stmt_cost (body_cost_vec, count, kind, NULL, NULL, 142 NULL_TREE, 0, where); 143 } 144 145 /* Return a variable of type ELEM_TYPE[NELEMS]. */ 146 147 static tree 148 create_vector_array (tree elem_type, unsigned HOST_WIDE_INT nelems) 149 { 150 return create_tmp_var (build_array_type_nelts (elem_type, nelems), 151 "vect_array"); 152 } 153 154 /* ARRAY is an array of vectors created by create_vector_array. 155 Return an SSA_NAME for the vector in index N. The reference 156 is part of the vectorization of STMT_INFO and the vector is associated 157 with scalar destination SCALAR_DEST. */ 158 159 static tree 160 read_vector_array (vec_info *vinfo, 161 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 162 tree scalar_dest, tree array, unsigned HOST_WIDE_INT n) 163 { 164 tree vect_type, vect, vect_name, array_ref; 165 gimple *new_stmt; 166 167 gcc_assert (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE); 168 vect_type = TREE_TYPE (TREE_TYPE (array)); 169 vect = vect_create_destination_var (scalar_dest, vect_type); 170 array_ref = build4 (ARRAY_REF, vect_type, array, 171 build_int_cst (size_type_node, n), 172 NULL_TREE, NULL_TREE); 173 174 new_stmt = gimple_build_assign (vect, array_ref); 175 vect_name = make_ssa_name (vect, new_stmt); 176 gimple_assign_set_lhs (new_stmt, vect_name); 177 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 178 179 return vect_name; 180 } 181 182 /* ARRAY is an array of vectors created by create_vector_array. 183 Emit code to store SSA_NAME VECT in index N of the array. 184 The store is part of the vectorization of STMT_INFO. */ 185 186 static void 187 write_vector_array (vec_info *vinfo, 188 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 189 tree vect, tree array, unsigned HOST_WIDE_INT n) 190 { 191 tree array_ref; 192 gimple *new_stmt; 193 194 array_ref = build4 (ARRAY_REF, TREE_TYPE (vect), array, 195 build_int_cst (size_type_node, n), 196 NULL_TREE, NULL_TREE); 197 198 new_stmt = gimple_build_assign (array_ref, vect); 199 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 200 } 201 202 /* PTR is a pointer to an array of type TYPE. Return a representation 203 of *PTR. The memory reference replaces those in FIRST_DR 204 (and its group). */ 205 206 static tree 207 create_array_ref (tree type, tree ptr, tree alias_ptr_type) 208 { 209 tree mem_ref; 210 211 mem_ref = build2 (MEM_REF, type, ptr, build_int_cst (alias_ptr_type, 0)); 212 /* Arrays have the same alignment as their type. */ 213 set_ptr_info_alignment (get_ptr_info (ptr), TYPE_ALIGN_UNIT (type), 0); 214 return mem_ref; 215 } 216 217 /* Add a clobber of variable VAR to the vectorization of STMT_INFO. 218 Emit the clobber before *GSI. */ 219 220 static void 221 vect_clobber_variable (vec_info *vinfo, stmt_vec_info stmt_info, 222 gimple_stmt_iterator *gsi, tree var) 223 { 224 tree clobber = build_clobber (TREE_TYPE (var)); 225 gimple *new_stmt = gimple_build_assign (var, clobber); 226 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 227 } 228 229 /* Utility functions used by vect_mark_stmts_to_be_vectorized. */ 230 231 /* Function vect_mark_relevant. 232 233 Mark STMT_INFO as "relevant for vectorization" and add it to WORKLIST. */ 234 235 static void 236 vect_mark_relevant (vec<stmt_vec_info> *worklist, stmt_vec_info stmt_info, 237 enum vect_relevant relevant, bool live_p) 238 { 239 enum vect_relevant save_relevant = STMT_VINFO_RELEVANT (stmt_info); 240 bool save_live_p = STMT_VINFO_LIVE_P (stmt_info); 241 242 if (dump_enabled_p ()) 243 dump_printf_loc (MSG_NOTE, vect_location, 244 "mark relevant %d, live %d: %G", relevant, live_p, 245 stmt_info->stmt); 246 247 /* If this stmt is an original stmt in a pattern, we might need to mark its 248 related pattern stmt instead of the original stmt. However, such stmts 249 may have their own uses that are not in any pattern, in such cases the 250 stmt itself should be marked. */ 251 if (STMT_VINFO_IN_PATTERN_P (stmt_info)) 252 { 253 /* This is the last stmt in a sequence that was detected as a 254 pattern that can potentially be vectorized. Don't mark the stmt 255 as relevant/live because it's not going to be vectorized. 256 Instead mark the pattern-stmt that replaces it. */ 257 258 if (dump_enabled_p ()) 259 dump_printf_loc (MSG_NOTE, vect_location, 260 "last stmt in pattern. don't mark" 261 " relevant/live.\n"); 262 stmt_vec_info old_stmt_info = stmt_info; 263 stmt_info = STMT_VINFO_RELATED_STMT (stmt_info); 264 gcc_assert (STMT_VINFO_RELATED_STMT (stmt_info) == old_stmt_info); 265 save_relevant = STMT_VINFO_RELEVANT (stmt_info); 266 save_live_p = STMT_VINFO_LIVE_P (stmt_info); 267 } 268 269 STMT_VINFO_LIVE_P (stmt_info) |= live_p; 270 if (relevant > STMT_VINFO_RELEVANT (stmt_info)) 271 STMT_VINFO_RELEVANT (stmt_info) = relevant; 272 273 if (STMT_VINFO_RELEVANT (stmt_info) == save_relevant 274 && STMT_VINFO_LIVE_P (stmt_info) == save_live_p) 275 { 276 if (dump_enabled_p ()) 277 dump_printf_loc (MSG_NOTE, vect_location, 278 "already marked relevant/live.\n"); 279 return; 280 } 281 282 worklist->safe_push (stmt_info); 283 } 284 285 286 /* Function is_simple_and_all_uses_invariant 287 288 Return true if STMT_INFO is simple and all uses of it are invariant. */ 289 290 bool 291 is_simple_and_all_uses_invariant (stmt_vec_info stmt_info, 292 loop_vec_info loop_vinfo) 293 { 294 tree op; 295 ssa_op_iter iter; 296 297 gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt); 298 if (!stmt) 299 return false; 300 301 FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE) 302 { 303 enum vect_def_type dt = vect_uninitialized_def; 304 305 if (!vect_is_simple_use (op, loop_vinfo, &dt)) 306 { 307 if (dump_enabled_p ()) 308 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 309 "use not simple.\n"); 310 return false; 311 } 312 313 if (dt != vect_external_def && dt != vect_constant_def) 314 return false; 315 } 316 return true; 317 } 318 319 /* Function vect_stmt_relevant_p. 320 321 Return true if STMT_INFO, in the loop that is represented by LOOP_VINFO, 322 is "relevant for vectorization". 323 324 A stmt is considered "relevant for vectorization" if: 325 - it has uses outside the loop. 326 - it has vdefs (it alters memory). 327 - control stmts in the loop (except for the exit condition). 328 329 CHECKME: what other side effects would the vectorizer allow? */ 330 331 static bool 332 vect_stmt_relevant_p (stmt_vec_info stmt_info, loop_vec_info loop_vinfo, 333 enum vect_relevant *relevant, bool *live_p) 334 { 335 class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); 336 ssa_op_iter op_iter; 337 imm_use_iterator imm_iter; 338 use_operand_p use_p; 339 def_operand_p def_p; 340 341 *relevant = vect_unused_in_scope; 342 *live_p = false; 343 344 /* cond stmt other than loop exit cond. */ 345 if (is_ctrl_stmt (stmt_info->stmt) 346 && STMT_VINFO_TYPE (stmt_info) != loop_exit_ctrl_vec_info_type) 347 *relevant = vect_used_in_scope; 348 349 /* changing memory. */ 350 if (gimple_code (stmt_info->stmt) != GIMPLE_PHI) 351 if (gimple_vdef (stmt_info->stmt) 352 && !gimple_clobber_p (stmt_info->stmt)) 353 { 354 if (dump_enabled_p ()) 355 dump_printf_loc (MSG_NOTE, vect_location, 356 "vec_stmt_relevant_p: stmt has vdefs.\n"); 357 *relevant = vect_used_in_scope; 358 } 359 360 /* uses outside the loop. */ 361 FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt_info->stmt, op_iter, SSA_OP_DEF) 362 { 363 FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p)) 364 { 365 basic_block bb = gimple_bb (USE_STMT (use_p)); 366 if (!flow_bb_inside_loop_p (loop, bb)) 367 { 368 if (is_gimple_debug (USE_STMT (use_p))) 369 continue; 370 371 if (dump_enabled_p ()) 372 dump_printf_loc (MSG_NOTE, vect_location, 373 "vec_stmt_relevant_p: used out of loop.\n"); 374 375 /* We expect all such uses to be in the loop exit phis 376 (because of loop closed form) */ 377 gcc_assert (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI); 378 gcc_assert (bb == single_exit (loop)->dest); 379 380 *live_p = true; 381 } 382 } 383 } 384 385 if (*live_p && *relevant == vect_unused_in_scope 386 && !is_simple_and_all_uses_invariant (stmt_info, loop_vinfo)) 387 { 388 if (dump_enabled_p ()) 389 dump_printf_loc (MSG_NOTE, vect_location, 390 "vec_stmt_relevant_p: stmt live but not relevant.\n"); 391 *relevant = vect_used_only_live; 392 } 393 394 return (*live_p || *relevant); 395 } 396 397 398 /* Function exist_non_indexing_operands_for_use_p 399 400 USE is one of the uses attached to STMT_INFO. Check if USE is 401 used in STMT_INFO for anything other than indexing an array. */ 402 403 static bool 404 exist_non_indexing_operands_for_use_p (tree use, stmt_vec_info stmt_info) 405 { 406 tree operand; 407 408 /* USE corresponds to some operand in STMT. If there is no data 409 reference in STMT, then any operand that corresponds to USE 410 is not indexing an array. */ 411 if (!STMT_VINFO_DATA_REF (stmt_info)) 412 return true; 413 414 /* STMT has a data_ref. FORNOW this means that its of one of 415 the following forms: 416 -1- ARRAY_REF = var 417 -2- var = ARRAY_REF 418 (This should have been verified in analyze_data_refs). 419 420 'var' in the second case corresponds to a def, not a use, 421 so USE cannot correspond to any operands that are not used 422 for array indexing. 423 424 Therefore, all we need to check is if STMT falls into the 425 first case, and whether var corresponds to USE. */ 426 427 gassign *assign = dyn_cast <gassign *> (stmt_info->stmt); 428 if (!assign || !gimple_assign_copy_p (assign)) 429 { 430 gcall *call = dyn_cast <gcall *> (stmt_info->stmt); 431 if (call && gimple_call_internal_p (call)) 432 { 433 internal_fn ifn = gimple_call_internal_fn (call); 434 int mask_index = internal_fn_mask_index (ifn); 435 if (mask_index >= 0 436 && use == gimple_call_arg (call, mask_index)) 437 return true; 438 int stored_value_index = internal_fn_stored_value_index (ifn); 439 if (stored_value_index >= 0 440 && use == gimple_call_arg (call, stored_value_index)) 441 return true; 442 if (internal_gather_scatter_fn_p (ifn) 443 && use == gimple_call_arg (call, 1)) 444 return true; 445 } 446 return false; 447 } 448 449 if (TREE_CODE (gimple_assign_lhs (assign)) == SSA_NAME) 450 return false; 451 operand = gimple_assign_rhs1 (assign); 452 if (TREE_CODE (operand) != SSA_NAME) 453 return false; 454 455 if (operand == use) 456 return true; 457 458 return false; 459 } 460 461 462 /* 463 Function process_use. 464 465 Inputs: 466 - a USE in STMT_VINFO in a loop represented by LOOP_VINFO 467 - RELEVANT - enum value to be set in the STMT_VINFO of the stmt 468 that defined USE. This is done by calling mark_relevant and passing it 469 the WORKLIST (to add DEF_STMT to the WORKLIST in case it is relevant). 470 - FORCE is true if exist_non_indexing_operands_for_use_p check shouldn't 471 be performed. 472 473 Outputs: 474 Generally, LIVE_P and RELEVANT are used to define the liveness and 475 relevance info of the DEF_STMT of this USE: 476 STMT_VINFO_LIVE_P (DEF_stmt_vinfo) <-- live_p 477 STMT_VINFO_RELEVANT (DEF_stmt_vinfo) <-- relevant 478 Exceptions: 479 - case 1: If USE is used only for address computations (e.g. array indexing), 480 which does not need to be directly vectorized, then the liveness/relevance 481 of the respective DEF_STMT is left unchanged. 482 - case 2: If STMT_VINFO is a reduction phi and DEF_STMT is a reduction stmt, 483 we skip DEF_STMT cause it had already been processed. 484 - case 3: If DEF_STMT and STMT_VINFO are in different nests, then 485 "relevant" will be modified accordingly. 486 487 Return true if everything is as expected. Return false otherwise. */ 488 489 static opt_result 490 process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo, 491 enum vect_relevant relevant, vec<stmt_vec_info> *worklist, 492 bool force) 493 { 494 stmt_vec_info dstmt_vinfo; 495 enum vect_def_type dt; 496 497 /* case 1: we are only interested in uses that need to be vectorized. Uses 498 that are used for address computation are not considered relevant. */ 499 if (!force && !exist_non_indexing_operands_for_use_p (use, stmt_vinfo)) 500 return opt_result::success (); 501 502 if (!vect_is_simple_use (use, loop_vinfo, &dt, &dstmt_vinfo)) 503 return opt_result::failure_at (stmt_vinfo->stmt, 504 "not vectorized:" 505 " unsupported use in stmt.\n"); 506 507 if (!dstmt_vinfo) 508 return opt_result::success (); 509 510 basic_block def_bb = gimple_bb (dstmt_vinfo->stmt); 511 basic_block bb = gimple_bb (stmt_vinfo->stmt); 512 513 /* case 2: A reduction phi (STMT) defined by a reduction stmt (DSTMT_VINFO). 514 We have to force the stmt live since the epilogue loop needs it to 515 continue computing the reduction. */ 516 if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI 517 && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def 518 && gimple_code (dstmt_vinfo->stmt) != GIMPLE_PHI 519 && STMT_VINFO_DEF_TYPE (dstmt_vinfo) == vect_reduction_def 520 && bb->loop_father == def_bb->loop_father) 521 { 522 if (dump_enabled_p ()) 523 dump_printf_loc (MSG_NOTE, vect_location, 524 "reduc-stmt defining reduc-phi in the same nest.\n"); 525 vect_mark_relevant (worklist, dstmt_vinfo, relevant, true); 526 return opt_result::success (); 527 } 528 529 /* case 3a: outer-loop stmt defining an inner-loop stmt: 530 outer-loop-header-bb: 531 d = dstmt_vinfo 532 inner-loop: 533 stmt # use (d) 534 outer-loop-tail-bb: 535 ... */ 536 if (flow_loop_nested_p (def_bb->loop_father, bb->loop_father)) 537 { 538 if (dump_enabled_p ()) 539 dump_printf_loc (MSG_NOTE, vect_location, 540 "outer-loop def-stmt defining inner-loop stmt.\n"); 541 542 switch (relevant) 543 { 544 case vect_unused_in_scope: 545 relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_nested_cycle) ? 546 vect_used_in_scope : vect_unused_in_scope; 547 break; 548 549 case vect_used_in_outer_by_reduction: 550 gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def); 551 relevant = vect_used_by_reduction; 552 break; 553 554 case vect_used_in_outer: 555 gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def); 556 relevant = vect_used_in_scope; 557 break; 558 559 case vect_used_in_scope: 560 break; 561 562 default: 563 gcc_unreachable (); 564 } 565 } 566 567 /* case 3b: inner-loop stmt defining an outer-loop stmt: 568 outer-loop-header-bb: 569 ... 570 inner-loop: 571 d = dstmt_vinfo 572 outer-loop-tail-bb (or outer-loop-exit-bb in double reduction): 573 stmt # use (d) */ 574 else if (flow_loop_nested_p (bb->loop_father, def_bb->loop_father)) 575 { 576 if (dump_enabled_p ()) 577 dump_printf_loc (MSG_NOTE, vect_location, 578 "inner-loop def-stmt defining outer-loop stmt.\n"); 579 580 switch (relevant) 581 { 582 case vect_unused_in_scope: 583 relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def 584 || STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_double_reduction_def) ? 585 vect_used_in_outer_by_reduction : vect_unused_in_scope; 586 break; 587 588 case vect_used_by_reduction: 589 case vect_used_only_live: 590 relevant = vect_used_in_outer_by_reduction; 591 break; 592 593 case vect_used_in_scope: 594 relevant = vect_used_in_outer; 595 break; 596 597 default: 598 gcc_unreachable (); 599 } 600 } 601 /* We are also not interested in uses on loop PHI backedges that are 602 inductions. Otherwise we'll needlessly vectorize the IV increment 603 and cause hybrid SLP for SLP inductions. Unless the PHI is live 604 of course. */ 605 else if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI 606 && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_induction_def 607 && ! STMT_VINFO_LIVE_P (stmt_vinfo) 608 && (PHI_ARG_DEF_FROM_EDGE (stmt_vinfo->stmt, 609 loop_latch_edge (bb->loop_father)) 610 == use)) 611 { 612 if (dump_enabled_p ()) 613 dump_printf_loc (MSG_NOTE, vect_location, 614 "induction value on backedge.\n"); 615 return opt_result::success (); 616 } 617 618 619 vect_mark_relevant (worklist, dstmt_vinfo, relevant, false); 620 return opt_result::success (); 621 } 622 623 624 /* Function vect_mark_stmts_to_be_vectorized. 625 626 Not all stmts in the loop need to be vectorized. For example: 627 628 for i... 629 for j... 630 1. T0 = i + j 631 2. T1 = a[T0] 632 633 3. j = j + 1 634 635 Stmt 1 and 3 do not need to be vectorized, because loop control and 636 addressing of vectorized data-refs are handled differently. 637 638 This pass detects such stmts. */ 639 640 opt_result 641 vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo, bool *fatal) 642 { 643 class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); 644 basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo); 645 unsigned int nbbs = loop->num_nodes; 646 gimple_stmt_iterator si; 647 unsigned int i; 648 basic_block bb; 649 bool live_p; 650 enum vect_relevant relevant; 651 652 DUMP_VECT_SCOPE ("vect_mark_stmts_to_be_vectorized"); 653 654 auto_vec<stmt_vec_info, 64> worklist; 655 656 /* 1. Init worklist. */ 657 for (i = 0; i < nbbs; i++) 658 { 659 bb = bbs[i]; 660 for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) 661 { 662 stmt_vec_info phi_info = loop_vinfo->lookup_stmt (gsi_stmt (si)); 663 if (dump_enabled_p ()) 664 dump_printf_loc (MSG_NOTE, vect_location, "init: phi relevant? %G", 665 phi_info->stmt); 666 667 if (vect_stmt_relevant_p (phi_info, loop_vinfo, &relevant, &live_p)) 668 vect_mark_relevant (&worklist, phi_info, relevant, live_p); 669 } 670 for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si)) 671 { 672 if (is_gimple_debug (gsi_stmt (si))) 673 continue; 674 stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si)); 675 if (dump_enabled_p ()) 676 dump_printf_loc (MSG_NOTE, vect_location, 677 "init: stmt relevant? %G", stmt_info->stmt); 678 679 if (vect_stmt_relevant_p (stmt_info, loop_vinfo, &relevant, &live_p)) 680 vect_mark_relevant (&worklist, stmt_info, relevant, live_p); 681 } 682 } 683 684 /* 2. Process_worklist */ 685 while (worklist.length () > 0) 686 { 687 use_operand_p use_p; 688 ssa_op_iter iter; 689 690 stmt_vec_info stmt_vinfo = worklist.pop (); 691 if (dump_enabled_p ()) 692 dump_printf_loc (MSG_NOTE, vect_location, 693 "worklist: examine stmt: %G", stmt_vinfo->stmt); 694 695 /* Examine the USEs of STMT. For each USE, mark the stmt that defines it 696 (DEF_STMT) as relevant/irrelevant according to the relevance property 697 of STMT. */ 698 relevant = STMT_VINFO_RELEVANT (stmt_vinfo); 699 700 /* Generally, the relevance property of STMT (in STMT_VINFO_RELEVANT) is 701 propagated as is to the DEF_STMTs of its USEs. 702 703 One exception is when STMT has been identified as defining a reduction 704 variable; in this case we set the relevance to vect_used_by_reduction. 705 This is because we distinguish between two kinds of relevant stmts - 706 those that are used by a reduction computation, and those that are 707 (also) used by a regular computation. This allows us later on to 708 identify stmts that are used solely by a reduction, and therefore the 709 order of the results that they produce does not have to be kept. */ 710 711 switch (STMT_VINFO_DEF_TYPE (stmt_vinfo)) 712 { 713 case vect_reduction_def: 714 gcc_assert (relevant != vect_unused_in_scope); 715 if (relevant != vect_unused_in_scope 716 && relevant != vect_used_in_scope 717 && relevant != vect_used_by_reduction 718 && relevant != vect_used_only_live) 719 return opt_result::failure_at 720 (stmt_vinfo->stmt, "unsupported use of reduction.\n"); 721 break; 722 723 case vect_nested_cycle: 724 if (relevant != vect_unused_in_scope 725 && relevant != vect_used_in_outer_by_reduction 726 && relevant != vect_used_in_outer) 727 return opt_result::failure_at 728 (stmt_vinfo->stmt, "unsupported use of nested cycle.\n"); 729 break; 730 731 case vect_double_reduction_def: 732 if (relevant != vect_unused_in_scope 733 && relevant != vect_used_by_reduction 734 && relevant != vect_used_only_live) 735 return opt_result::failure_at 736 (stmt_vinfo->stmt, "unsupported use of double reduction.\n"); 737 break; 738 739 default: 740 break; 741 } 742 743 if (is_pattern_stmt_p (stmt_vinfo)) 744 { 745 /* Pattern statements are not inserted into the code, so 746 FOR_EACH_PHI_OR_STMT_USE optimizes their operands out, and we 747 have to scan the RHS or function arguments instead. */ 748 if (gassign *assign = dyn_cast <gassign *> (stmt_vinfo->stmt)) 749 { 750 enum tree_code rhs_code = gimple_assign_rhs_code (assign); 751 tree op = gimple_assign_rhs1 (assign); 752 753 i = 1; 754 if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op)) 755 { 756 opt_result res 757 = process_use (stmt_vinfo, TREE_OPERAND (op, 0), 758 loop_vinfo, relevant, &worklist, false); 759 if (!res) 760 return res; 761 res = process_use (stmt_vinfo, TREE_OPERAND (op, 1), 762 loop_vinfo, relevant, &worklist, false); 763 if (!res) 764 return res; 765 i = 2; 766 } 767 for (; i < gimple_num_ops (assign); i++) 768 { 769 op = gimple_op (assign, i); 770 if (TREE_CODE (op) == SSA_NAME) 771 { 772 opt_result res 773 = process_use (stmt_vinfo, op, loop_vinfo, relevant, 774 &worklist, false); 775 if (!res) 776 return res; 777 } 778 } 779 } 780 else if (gcall *call = dyn_cast <gcall *> (stmt_vinfo->stmt)) 781 { 782 for (i = 0; i < gimple_call_num_args (call); i++) 783 { 784 tree arg = gimple_call_arg (call, i); 785 opt_result res 786 = process_use (stmt_vinfo, arg, loop_vinfo, relevant, 787 &worklist, false); 788 if (!res) 789 return res; 790 } 791 } 792 } 793 else 794 FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE) 795 { 796 tree op = USE_FROM_PTR (use_p); 797 opt_result res 798 = process_use (stmt_vinfo, op, loop_vinfo, relevant, 799 &worklist, false); 800 if (!res) 801 return res; 802 } 803 804 if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo)) 805 { 806 gather_scatter_info gs_info; 807 if (!vect_check_gather_scatter (stmt_vinfo, loop_vinfo, &gs_info)) 808 gcc_unreachable (); 809 opt_result res 810 = process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant, 811 &worklist, true); 812 if (!res) 813 { 814 if (fatal) 815 *fatal = false; 816 return res; 817 } 818 } 819 } /* while worklist */ 820 821 return opt_result::success (); 822 } 823 824 /* Function vect_model_simple_cost. 825 826 Models cost for simple operations, i.e. those that only emit ncopies of a 827 single op. Right now, this does not account for multiple insns that could 828 be generated for the single vector op. We will handle that shortly. */ 829 830 static void 831 vect_model_simple_cost (vec_info *, 832 stmt_vec_info stmt_info, int ncopies, 833 enum vect_def_type *dt, 834 int ndts, 835 slp_tree node, 836 stmt_vector_for_cost *cost_vec, 837 vect_cost_for_stmt kind = vector_stmt) 838 { 839 int inside_cost = 0, prologue_cost = 0; 840 841 gcc_assert (cost_vec != NULL); 842 843 /* ??? Somehow we need to fix this at the callers. */ 844 if (node) 845 ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (node); 846 847 if (!node) 848 /* Cost the "broadcast" of a scalar operand in to a vector operand. 849 Use scalar_to_vec to cost the broadcast, as elsewhere in the vector 850 cost model. */ 851 for (int i = 0; i < ndts; i++) 852 if (dt[i] == vect_constant_def || dt[i] == vect_external_def) 853 prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec, 854 stmt_info, 0, vect_prologue); 855 856 /* Pass the inside-of-loop statements to the target-specific cost model. */ 857 inside_cost += record_stmt_cost (cost_vec, ncopies, kind, 858 stmt_info, 0, vect_body); 859 860 if (dump_enabled_p ()) 861 dump_printf_loc (MSG_NOTE, vect_location, 862 "vect_model_simple_cost: inside_cost = %d, " 863 "prologue_cost = %d .\n", inside_cost, prologue_cost); 864 } 865 866 867 /* Model cost for type demotion and promotion operations. PWR is 868 normally zero for single-step promotions and demotions. It will be 869 one if two-step promotion/demotion is required, and so on. NCOPIES 870 is the number of vector results (and thus number of instructions) 871 for the narrowest end of the operation chain. Each additional 872 step doubles the number of instructions required. If WIDEN_ARITH 873 is true the stmt is doing widening arithmetic. */ 874 875 static void 876 vect_model_promotion_demotion_cost (stmt_vec_info stmt_info, 877 enum vect_def_type *dt, 878 unsigned int ncopies, int pwr, 879 stmt_vector_for_cost *cost_vec, 880 bool widen_arith) 881 { 882 int i; 883 int inside_cost = 0, prologue_cost = 0; 884 885 for (i = 0; i < pwr + 1; i++) 886 { 887 inside_cost += record_stmt_cost (cost_vec, ncopies, 888 widen_arith 889 ? vector_stmt : vec_promote_demote, 890 stmt_info, 0, vect_body); 891 ncopies *= 2; 892 } 893 894 /* FORNOW: Assuming maximum 2 args per stmts. */ 895 for (i = 0; i < 2; i++) 896 if (dt[i] == vect_constant_def || dt[i] == vect_external_def) 897 prologue_cost += record_stmt_cost (cost_vec, 1, vector_stmt, 898 stmt_info, 0, vect_prologue); 899 900 if (dump_enabled_p ()) 901 dump_printf_loc (MSG_NOTE, vect_location, 902 "vect_model_promotion_demotion_cost: inside_cost = %d, " 903 "prologue_cost = %d .\n", inside_cost, prologue_cost); 904 } 905 906 /* Returns true if the current function returns DECL. */ 907 908 static bool 909 cfun_returns (tree decl) 910 { 911 edge_iterator ei; 912 edge e; 913 FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) 914 { 915 greturn *ret = safe_dyn_cast <greturn *> (last_stmt (e->src)); 916 if (!ret) 917 continue; 918 if (gimple_return_retval (ret) == decl) 919 return true; 920 /* We often end up with an aggregate copy to the result decl, 921 handle that case as well. First skip intermediate clobbers 922 though. */ 923 gimple *def = ret; 924 do 925 { 926 def = SSA_NAME_DEF_STMT (gimple_vuse (def)); 927 } 928 while (gimple_clobber_p (def)); 929 if (is_a <gassign *> (def) 930 && gimple_assign_lhs (def) == gimple_return_retval (ret) 931 && gimple_assign_rhs1 (def) == decl) 932 return true; 933 } 934 return false; 935 } 936 937 /* Function vect_model_store_cost 938 939 Models cost for stores. In the case of grouped accesses, one access 940 has the overhead of the grouped access attributed to it. */ 941 942 static void 943 vect_model_store_cost (vec_info *vinfo, stmt_vec_info stmt_info, int ncopies, 944 vect_memory_access_type memory_access_type, 945 dr_alignment_support alignment_support_scheme, 946 int misalignment, 947 vec_load_store_type vls_type, slp_tree slp_node, 948 stmt_vector_for_cost *cost_vec) 949 { 950 unsigned int inside_cost = 0, prologue_cost = 0; 951 stmt_vec_info first_stmt_info = stmt_info; 952 bool grouped_access_p = STMT_VINFO_GROUPED_ACCESS (stmt_info); 953 954 /* ??? Somehow we need to fix this at the callers. */ 955 if (slp_node) 956 ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 957 958 if (vls_type == VLS_STORE_INVARIANT) 959 { 960 if (!slp_node) 961 prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec, 962 stmt_info, 0, vect_prologue); 963 } 964 965 /* Grouped stores update all elements in the group at once, 966 so we want the DR for the first statement. */ 967 if (!slp_node && grouped_access_p) 968 first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 969 970 /* True if we should include any once-per-group costs as well as 971 the cost of the statement itself. For SLP we only get called 972 once per group anyhow. */ 973 bool first_stmt_p = (first_stmt_info == stmt_info); 974 975 /* We assume that the cost of a single store-lanes instruction is 976 equivalent to the cost of DR_GROUP_SIZE separate stores. If a grouped 977 access is instead being provided by a permute-and-store operation, 978 include the cost of the permutes. */ 979 if (first_stmt_p 980 && memory_access_type == VMAT_CONTIGUOUS_PERMUTE) 981 { 982 /* Uses a high and low interleave or shuffle operations for each 983 needed permute. */ 984 int group_size = DR_GROUP_SIZE (first_stmt_info); 985 int nstmts = ncopies * ceil_log2 (group_size) * group_size; 986 inside_cost = record_stmt_cost (cost_vec, nstmts, vec_perm, 987 stmt_info, 0, vect_body); 988 989 if (dump_enabled_p ()) 990 dump_printf_loc (MSG_NOTE, vect_location, 991 "vect_model_store_cost: strided group_size = %d .\n", 992 group_size); 993 } 994 995 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 996 /* Costs of the stores. */ 997 if (memory_access_type == VMAT_ELEMENTWISE 998 || memory_access_type == VMAT_GATHER_SCATTER) 999 { 1000 /* N scalar stores plus extracting the elements. */ 1001 unsigned int assumed_nunits = vect_nunits_for_cost (vectype); 1002 inside_cost += record_stmt_cost (cost_vec, 1003 ncopies * assumed_nunits, 1004 scalar_store, stmt_info, 0, vect_body); 1005 } 1006 else 1007 vect_get_store_cost (vinfo, stmt_info, ncopies, alignment_support_scheme, 1008 misalignment, &inside_cost, cost_vec); 1009 1010 if (memory_access_type == VMAT_ELEMENTWISE 1011 || memory_access_type == VMAT_STRIDED_SLP) 1012 { 1013 /* N scalar stores plus extracting the elements. */ 1014 unsigned int assumed_nunits = vect_nunits_for_cost (vectype); 1015 inside_cost += record_stmt_cost (cost_vec, 1016 ncopies * assumed_nunits, 1017 vec_to_scalar, stmt_info, 0, vect_body); 1018 } 1019 1020 /* When vectorizing a store into the function result assign 1021 a penalty if the function returns in a multi-register location. 1022 In this case we assume we'll end up with having to spill the 1023 vector result and do piecewise loads as a conservative estimate. */ 1024 tree base = get_base_address (STMT_VINFO_DATA_REF (stmt_info)->ref); 1025 if (base 1026 && (TREE_CODE (base) == RESULT_DECL 1027 || (DECL_P (base) && cfun_returns (base))) 1028 && !aggregate_value_p (base, cfun->decl)) 1029 { 1030 rtx reg = hard_function_value (TREE_TYPE (base), cfun->decl, 0, 1); 1031 /* ??? Handle PARALLEL in some way. */ 1032 if (REG_P (reg)) 1033 { 1034 int nregs = hard_regno_nregs (REGNO (reg), GET_MODE (reg)); 1035 /* Assume that a single reg-reg move is possible and cheap, 1036 do not account for vector to gp register move cost. */ 1037 if (nregs > 1) 1038 { 1039 /* Spill. */ 1040 prologue_cost += record_stmt_cost (cost_vec, ncopies, 1041 vector_store, 1042 stmt_info, 0, vect_epilogue); 1043 /* Loads. */ 1044 prologue_cost += record_stmt_cost (cost_vec, ncopies * nregs, 1045 scalar_load, 1046 stmt_info, 0, vect_epilogue); 1047 } 1048 } 1049 } 1050 1051 if (dump_enabled_p ()) 1052 dump_printf_loc (MSG_NOTE, vect_location, 1053 "vect_model_store_cost: inside_cost = %d, " 1054 "prologue_cost = %d .\n", inside_cost, prologue_cost); 1055 } 1056 1057 1058 /* Calculate cost of DR's memory access. */ 1059 void 1060 vect_get_store_cost (vec_info *, stmt_vec_info stmt_info, int ncopies, 1061 dr_alignment_support alignment_support_scheme, 1062 int misalignment, 1063 unsigned int *inside_cost, 1064 stmt_vector_for_cost *body_cost_vec) 1065 { 1066 switch (alignment_support_scheme) 1067 { 1068 case dr_aligned: 1069 { 1070 *inside_cost += record_stmt_cost (body_cost_vec, ncopies, 1071 vector_store, stmt_info, 0, 1072 vect_body); 1073 1074 if (dump_enabled_p ()) 1075 dump_printf_loc (MSG_NOTE, vect_location, 1076 "vect_model_store_cost: aligned.\n"); 1077 break; 1078 } 1079 1080 case dr_unaligned_supported: 1081 { 1082 /* Here, we assign an additional cost for the unaligned store. */ 1083 *inside_cost += record_stmt_cost (body_cost_vec, ncopies, 1084 unaligned_store, stmt_info, 1085 misalignment, vect_body); 1086 if (dump_enabled_p ()) 1087 dump_printf_loc (MSG_NOTE, vect_location, 1088 "vect_model_store_cost: unaligned supported by " 1089 "hardware.\n"); 1090 break; 1091 } 1092 1093 case dr_unaligned_unsupported: 1094 { 1095 *inside_cost = VECT_MAX_COST; 1096 1097 if (dump_enabled_p ()) 1098 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 1099 "vect_model_store_cost: unsupported access.\n"); 1100 break; 1101 } 1102 1103 default: 1104 gcc_unreachable (); 1105 } 1106 } 1107 1108 1109 /* Function vect_model_load_cost 1110 1111 Models cost for loads. In the case of grouped accesses, one access has 1112 the overhead of the grouped access attributed to it. Since unaligned 1113 accesses are supported for loads, we also account for the costs of the 1114 access scheme chosen. */ 1115 1116 static void 1117 vect_model_load_cost (vec_info *vinfo, 1118 stmt_vec_info stmt_info, unsigned ncopies, poly_uint64 vf, 1119 vect_memory_access_type memory_access_type, 1120 dr_alignment_support alignment_support_scheme, 1121 int misalignment, 1122 gather_scatter_info *gs_info, 1123 slp_tree slp_node, 1124 stmt_vector_for_cost *cost_vec) 1125 { 1126 unsigned int inside_cost = 0, prologue_cost = 0; 1127 bool grouped_access_p = STMT_VINFO_GROUPED_ACCESS (stmt_info); 1128 1129 gcc_assert (cost_vec); 1130 1131 /* ??? Somehow we need to fix this at the callers. */ 1132 if (slp_node) 1133 ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 1134 1135 if (slp_node && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()) 1136 { 1137 /* If the load is permuted then the alignment is determined by 1138 the first group element not by the first scalar stmt DR. */ 1139 stmt_vec_info first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 1140 /* Record the cost for the permutation. */ 1141 unsigned n_perms, n_loads; 1142 vect_transform_slp_perm_load (vinfo, slp_node, vNULL, NULL, 1143 vf, true, &n_perms, &n_loads); 1144 inside_cost += record_stmt_cost (cost_vec, n_perms, vec_perm, 1145 first_stmt_info, 0, vect_body); 1146 1147 /* And adjust the number of loads performed. This handles 1148 redundancies as well as loads that are later dead. */ 1149 ncopies = n_loads; 1150 } 1151 1152 /* Grouped loads read all elements in the group at once, 1153 so we want the DR for the first statement. */ 1154 stmt_vec_info first_stmt_info = stmt_info; 1155 if (!slp_node && grouped_access_p) 1156 first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 1157 1158 /* True if we should include any once-per-group costs as well as 1159 the cost of the statement itself. For SLP we only get called 1160 once per group anyhow. */ 1161 bool first_stmt_p = (first_stmt_info == stmt_info); 1162 1163 /* An IFN_LOAD_LANES will load all its vector results, regardless of which 1164 ones we actually need. Account for the cost of unused results. */ 1165 if (first_stmt_p && !slp_node && memory_access_type == VMAT_LOAD_STORE_LANES) 1166 { 1167 unsigned int gaps = DR_GROUP_SIZE (first_stmt_info); 1168 stmt_vec_info next_stmt_info = first_stmt_info; 1169 do 1170 { 1171 gaps -= 1; 1172 next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); 1173 } 1174 while (next_stmt_info); 1175 if (gaps) 1176 { 1177 if (dump_enabled_p ()) 1178 dump_printf_loc (MSG_NOTE, vect_location, 1179 "vect_model_load_cost: %d unused vectors.\n", 1180 gaps); 1181 vect_get_load_cost (vinfo, stmt_info, ncopies * gaps, 1182 alignment_support_scheme, misalignment, false, 1183 &inside_cost, &prologue_cost, 1184 cost_vec, cost_vec, true); 1185 } 1186 } 1187 1188 /* We assume that the cost of a single load-lanes instruction is 1189 equivalent to the cost of DR_GROUP_SIZE separate loads. If a grouped 1190 access is instead being provided by a load-and-permute operation, 1191 include the cost of the permutes. */ 1192 if (first_stmt_p 1193 && memory_access_type == VMAT_CONTIGUOUS_PERMUTE) 1194 { 1195 /* Uses an even and odd extract operations or shuffle operations 1196 for each needed permute. */ 1197 int group_size = DR_GROUP_SIZE (first_stmt_info); 1198 int nstmts = ncopies * ceil_log2 (group_size) * group_size; 1199 inside_cost += record_stmt_cost (cost_vec, nstmts, vec_perm, 1200 stmt_info, 0, vect_body); 1201 1202 if (dump_enabled_p ()) 1203 dump_printf_loc (MSG_NOTE, vect_location, 1204 "vect_model_load_cost: strided group_size = %d .\n", 1205 group_size); 1206 } 1207 1208 /* The loads themselves. */ 1209 if (memory_access_type == VMAT_ELEMENTWISE 1210 || memory_access_type == VMAT_GATHER_SCATTER) 1211 { 1212 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 1213 unsigned int assumed_nunits = vect_nunits_for_cost (vectype); 1214 if (memory_access_type == VMAT_GATHER_SCATTER 1215 && gs_info->ifn == IFN_LAST && !gs_info->decl) 1216 /* For emulated gathers N offset vector element extracts 1217 (we assume the scalar scaling and ptr + offset add is consumed by 1218 the load). */ 1219 inside_cost += record_stmt_cost (cost_vec, ncopies * assumed_nunits, 1220 vec_to_scalar, stmt_info, 0, 1221 vect_body); 1222 /* N scalar loads plus gathering them into a vector. */ 1223 inside_cost += record_stmt_cost (cost_vec, 1224 ncopies * assumed_nunits, 1225 scalar_load, stmt_info, 0, vect_body); 1226 } 1227 else if (memory_access_type == VMAT_INVARIANT) 1228 { 1229 /* Invariant loads will ideally be hoisted and splat to a vector. */ 1230 prologue_cost += record_stmt_cost (cost_vec, 1, 1231 scalar_load, stmt_info, 0, 1232 vect_prologue); 1233 prologue_cost += record_stmt_cost (cost_vec, 1, 1234 scalar_to_vec, stmt_info, 0, 1235 vect_prologue); 1236 } 1237 else 1238 vect_get_load_cost (vinfo, stmt_info, ncopies, 1239 alignment_support_scheme, misalignment, first_stmt_p, 1240 &inside_cost, &prologue_cost, 1241 cost_vec, cost_vec, true); 1242 if (memory_access_type == VMAT_ELEMENTWISE 1243 || memory_access_type == VMAT_STRIDED_SLP 1244 || (memory_access_type == VMAT_GATHER_SCATTER 1245 && gs_info->ifn == IFN_LAST && !gs_info->decl)) 1246 inside_cost += record_stmt_cost (cost_vec, ncopies, vec_construct, 1247 stmt_info, 0, vect_body); 1248 1249 if (dump_enabled_p ()) 1250 dump_printf_loc (MSG_NOTE, vect_location, 1251 "vect_model_load_cost: inside_cost = %d, " 1252 "prologue_cost = %d .\n", inside_cost, prologue_cost); 1253 } 1254 1255 1256 /* Calculate cost of DR's memory access. */ 1257 void 1258 vect_get_load_cost (vec_info *, stmt_vec_info stmt_info, int ncopies, 1259 dr_alignment_support alignment_support_scheme, 1260 int misalignment, 1261 bool add_realign_cost, unsigned int *inside_cost, 1262 unsigned int *prologue_cost, 1263 stmt_vector_for_cost *prologue_cost_vec, 1264 stmt_vector_for_cost *body_cost_vec, 1265 bool record_prologue_costs) 1266 { 1267 switch (alignment_support_scheme) 1268 { 1269 case dr_aligned: 1270 { 1271 *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load, 1272 stmt_info, 0, vect_body); 1273 1274 if (dump_enabled_p ()) 1275 dump_printf_loc (MSG_NOTE, vect_location, 1276 "vect_model_load_cost: aligned.\n"); 1277 1278 break; 1279 } 1280 case dr_unaligned_supported: 1281 { 1282 /* Here, we assign an additional cost for the unaligned load. */ 1283 *inside_cost += record_stmt_cost (body_cost_vec, ncopies, 1284 unaligned_load, stmt_info, 1285 misalignment, vect_body); 1286 1287 if (dump_enabled_p ()) 1288 dump_printf_loc (MSG_NOTE, vect_location, 1289 "vect_model_load_cost: unaligned supported by " 1290 "hardware.\n"); 1291 1292 break; 1293 } 1294 case dr_explicit_realign: 1295 { 1296 *inside_cost += record_stmt_cost (body_cost_vec, ncopies * 2, 1297 vector_load, stmt_info, 0, vect_body); 1298 *inside_cost += record_stmt_cost (body_cost_vec, ncopies, 1299 vec_perm, stmt_info, 0, vect_body); 1300 1301 /* FIXME: If the misalignment remains fixed across the iterations of 1302 the containing loop, the following cost should be added to the 1303 prologue costs. */ 1304 if (targetm.vectorize.builtin_mask_for_load) 1305 *inside_cost += record_stmt_cost (body_cost_vec, 1, vector_stmt, 1306 stmt_info, 0, vect_body); 1307 1308 if (dump_enabled_p ()) 1309 dump_printf_loc (MSG_NOTE, vect_location, 1310 "vect_model_load_cost: explicit realign\n"); 1311 1312 break; 1313 } 1314 case dr_explicit_realign_optimized: 1315 { 1316 if (dump_enabled_p ()) 1317 dump_printf_loc (MSG_NOTE, vect_location, 1318 "vect_model_load_cost: unaligned software " 1319 "pipelined.\n"); 1320 1321 /* Unaligned software pipeline has a load of an address, an initial 1322 load, and possibly a mask operation to "prime" the loop. However, 1323 if this is an access in a group of loads, which provide grouped 1324 access, then the above cost should only be considered for one 1325 access in the group. Inside the loop, there is a load op 1326 and a realignment op. */ 1327 1328 if (add_realign_cost && record_prologue_costs) 1329 { 1330 *prologue_cost += record_stmt_cost (prologue_cost_vec, 2, 1331 vector_stmt, stmt_info, 1332 0, vect_prologue); 1333 if (targetm.vectorize.builtin_mask_for_load) 1334 *prologue_cost += record_stmt_cost (prologue_cost_vec, 1, 1335 vector_stmt, stmt_info, 1336 0, vect_prologue); 1337 } 1338 1339 *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load, 1340 stmt_info, 0, vect_body); 1341 *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vec_perm, 1342 stmt_info, 0, vect_body); 1343 1344 if (dump_enabled_p ()) 1345 dump_printf_loc (MSG_NOTE, vect_location, 1346 "vect_model_load_cost: explicit realign optimized" 1347 "\n"); 1348 1349 break; 1350 } 1351 1352 case dr_unaligned_unsupported: 1353 { 1354 *inside_cost = VECT_MAX_COST; 1355 1356 if (dump_enabled_p ()) 1357 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 1358 "vect_model_load_cost: unsupported access.\n"); 1359 break; 1360 } 1361 1362 default: 1363 gcc_unreachable (); 1364 } 1365 } 1366 1367 /* Insert the new stmt NEW_STMT at *GSI or at the appropriate place in 1368 the loop preheader for the vectorized stmt STMT_VINFO. */ 1369 1370 static void 1371 vect_init_vector_1 (vec_info *vinfo, stmt_vec_info stmt_vinfo, gimple *new_stmt, 1372 gimple_stmt_iterator *gsi) 1373 { 1374 if (gsi) 1375 vect_finish_stmt_generation (vinfo, stmt_vinfo, new_stmt, gsi); 1376 else 1377 vinfo->insert_on_entry (stmt_vinfo, new_stmt); 1378 1379 if (dump_enabled_p ()) 1380 dump_printf_loc (MSG_NOTE, vect_location, 1381 "created new init_stmt: %G", new_stmt); 1382 } 1383 1384 /* Function vect_init_vector. 1385 1386 Insert a new stmt (INIT_STMT) that initializes a new variable of type 1387 TYPE with the value VAL. If TYPE is a vector type and VAL does not have 1388 vector type a vector with all elements equal to VAL is created first. 1389 Place the initialization at GSI if it is not NULL. Otherwise, place the 1390 initialization at the loop preheader. 1391 Return the DEF of INIT_STMT. 1392 It will be used in the vectorization of STMT_INFO. */ 1393 1394 tree 1395 vect_init_vector (vec_info *vinfo, stmt_vec_info stmt_info, tree val, tree type, 1396 gimple_stmt_iterator *gsi) 1397 { 1398 gimple *init_stmt; 1399 tree new_temp; 1400 1401 /* We abuse this function to push sth to a SSA name with initial 'val'. */ 1402 if (! useless_type_conversion_p (type, TREE_TYPE (val))) 1403 { 1404 gcc_assert (TREE_CODE (type) == VECTOR_TYPE); 1405 if (! types_compatible_p (TREE_TYPE (type), TREE_TYPE (val))) 1406 { 1407 /* Scalar boolean value should be transformed into 1408 all zeros or all ones value before building a vector. */ 1409 if (VECTOR_BOOLEAN_TYPE_P (type)) 1410 { 1411 tree true_val = build_all_ones_cst (TREE_TYPE (type)); 1412 tree false_val = build_zero_cst (TREE_TYPE (type)); 1413 1414 if (CONSTANT_CLASS_P (val)) 1415 val = integer_zerop (val) ? false_val : true_val; 1416 else 1417 { 1418 new_temp = make_ssa_name (TREE_TYPE (type)); 1419 init_stmt = gimple_build_assign (new_temp, COND_EXPR, 1420 val, true_val, false_val); 1421 vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi); 1422 val = new_temp; 1423 } 1424 } 1425 else 1426 { 1427 gimple_seq stmts = NULL; 1428 if (! INTEGRAL_TYPE_P (TREE_TYPE (val))) 1429 val = gimple_build (&stmts, VIEW_CONVERT_EXPR, 1430 TREE_TYPE (type), val); 1431 else 1432 /* ??? Condition vectorization expects us to do 1433 promotion of invariant/external defs. */ 1434 val = gimple_convert (&stmts, TREE_TYPE (type), val); 1435 for (gimple_stmt_iterator gsi2 = gsi_start (stmts); 1436 !gsi_end_p (gsi2); ) 1437 { 1438 init_stmt = gsi_stmt (gsi2); 1439 gsi_remove (&gsi2, false); 1440 vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi); 1441 } 1442 } 1443 } 1444 val = build_vector_from_val (type, val); 1445 } 1446 1447 new_temp = vect_get_new_ssa_name (type, vect_simple_var, "cst_"); 1448 init_stmt = gimple_build_assign (new_temp, val); 1449 vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi); 1450 return new_temp; 1451 } 1452 1453 1454 /* Function vect_get_vec_defs_for_operand. 1455 1456 OP is an operand in STMT_VINFO. This function returns a vector of 1457 NCOPIES defs that will be used in the vectorized stmts for STMT_VINFO. 1458 1459 In the case that OP is an SSA_NAME which is defined in the loop, then 1460 STMT_VINFO_VEC_STMTS of the defining stmt holds the relevant defs. 1461 1462 In case OP is an invariant or constant, a new stmt that creates a vector def 1463 needs to be introduced. VECTYPE may be used to specify a required type for 1464 vector invariant. */ 1465 1466 void 1467 vect_get_vec_defs_for_operand (vec_info *vinfo, stmt_vec_info stmt_vinfo, 1468 unsigned ncopies, 1469 tree op, vec<tree> *vec_oprnds, tree vectype) 1470 { 1471 gimple *def_stmt; 1472 enum vect_def_type dt; 1473 bool is_simple_use; 1474 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 1475 1476 if (dump_enabled_p ()) 1477 dump_printf_loc (MSG_NOTE, vect_location, 1478 "vect_get_vec_defs_for_operand: %T\n", op); 1479 1480 stmt_vec_info def_stmt_info; 1481 is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt, 1482 &def_stmt_info, &def_stmt); 1483 gcc_assert (is_simple_use); 1484 if (def_stmt && dump_enabled_p ()) 1485 dump_printf_loc (MSG_NOTE, vect_location, " def_stmt = %G", def_stmt); 1486 1487 vec_oprnds->create (ncopies); 1488 if (dt == vect_constant_def || dt == vect_external_def) 1489 { 1490 tree stmt_vectype = STMT_VINFO_VECTYPE (stmt_vinfo); 1491 tree vector_type; 1492 1493 if (vectype) 1494 vector_type = vectype; 1495 else if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op)) 1496 && VECTOR_BOOLEAN_TYPE_P (stmt_vectype)) 1497 vector_type = truth_type_for (stmt_vectype); 1498 else 1499 vector_type = get_vectype_for_scalar_type (loop_vinfo, TREE_TYPE (op)); 1500 1501 gcc_assert (vector_type); 1502 tree vop = vect_init_vector (vinfo, stmt_vinfo, op, vector_type, NULL); 1503 while (ncopies--) 1504 vec_oprnds->quick_push (vop); 1505 } 1506 else 1507 { 1508 def_stmt_info = vect_stmt_to_vectorize (def_stmt_info); 1509 gcc_assert (STMT_VINFO_VEC_STMTS (def_stmt_info).length () == ncopies); 1510 for (unsigned i = 0; i < ncopies; ++i) 1511 vec_oprnds->quick_push (gimple_get_lhs 1512 (STMT_VINFO_VEC_STMTS (def_stmt_info)[i])); 1513 } 1514 } 1515 1516 1517 /* Get vectorized definitions for OP0 and OP1. */ 1518 1519 void 1520 vect_get_vec_defs (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node, 1521 unsigned ncopies, 1522 tree op0, vec<tree> *vec_oprnds0, tree vectype0, 1523 tree op1, vec<tree> *vec_oprnds1, tree vectype1, 1524 tree op2, vec<tree> *vec_oprnds2, tree vectype2, 1525 tree op3, vec<tree> *vec_oprnds3, tree vectype3) 1526 { 1527 if (slp_node) 1528 { 1529 if (op0) 1530 vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_oprnds0); 1531 if (op1) 1532 vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[1], vec_oprnds1); 1533 if (op2) 1534 vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[2], vec_oprnds2); 1535 if (op3) 1536 vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[3], vec_oprnds3); 1537 } 1538 else 1539 { 1540 if (op0) 1541 vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, 1542 op0, vec_oprnds0, vectype0); 1543 if (op1) 1544 vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, 1545 op1, vec_oprnds1, vectype1); 1546 if (op2) 1547 vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, 1548 op2, vec_oprnds2, vectype2); 1549 if (op3) 1550 vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, 1551 op3, vec_oprnds3, vectype3); 1552 } 1553 } 1554 1555 void 1556 vect_get_vec_defs (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node, 1557 unsigned ncopies, 1558 tree op0, vec<tree> *vec_oprnds0, 1559 tree op1, vec<tree> *vec_oprnds1, 1560 tree op2, vec<tree> *vec_oprnds2, 1561 tree op3, vec<tree> *vec_oprnds3) 1562 { 1563 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, 1564 op0, vec_oprnds0, NULL_TREE, 1565 op1, vec_oprnds1, NULL_TREE, 1566 op2, vec_oprnds2, NULL_TREE, 1567 op3, vec_oprnds3, NULL_TREE); 1568 } 1569 1570 /* Helper function called by vect_finish_replace_stmt and 1571 vect_finish_stmt_generation. Set the location of the new 1572 statement and create and return a stmt_vec_info for it. */ 1573 1574 static void 1575 vect_finish_stmt_generation_1 (vec_info *, 1576 stmt_vec_info stmt_info, gimple *vec_stmt) 1577 { 1578 if (dump_enabled_p ()) 1579 dump_printf_loc (MSG_NOTE, vect_location, "add new stmt: %G", vec_stmt); 1580 1581 if (stmt_info) 1582 { 1583 gimple_set_location (vec_stmt, gimple_location (stmt_info->stmt)); 1584 1585 /* While EH edges will generally prevent vectorization, stmt might 1586 e.g. be in a must-not-throw region. Ensure newly created stmts 1587 that could throw are part of the same region. */ 1588 int lp_nr = lookup_stmt_eh_lp (stmt_info->stmt); 1589 if (lp_nr != 0 && stmt_could_throw_p (cfun, vec_stmt)) 1590 add_stmt_to_eh_lp (vec_stmt, lp_nr); 1591 } 1592 else 1593 gcc_assert (!stmt_could_throw_p (cfun, vec_stmt)); 1594 } 1595 1596 /* Replace the scalar statement STMT_INFO with a new vector statement VEC_STMT, 1597 which sets the same scalar result as STMT_INFO did. Create and return a 1598 stmt_vec_info for VEC_STMT. */ 1599 1600 void 1601 vect_finish_replace_stmt (vec_info *vinfo, 1602 stmt_vec_info stmt_info, gimple *vec_stmt) 1603 { 1604 gimple *scalar_stmt = vect_orig_stmt (stmt_info)->stmt; 1605 gcc_assert (gimple_get_lhs (scalar_stmt) == gimple_get_lhs (vec_stmt)); 1606 1607 gimple_stmt_iterator gsi = gsi_for_stmt (scalar_stmt); 1608 gsi_replace (&gsi, vec_stmt, true); 1609 1610 vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt); 1611 } 1612 1613 /* Add VEC_STMT to the vectorized implementation of STMT_INFO and insert it 1614 before *GSI. Create and return a stmt_vec_info for VEC_STMT. */ 1615 1616 void 1617 vect_finish_stmt_generation (vec_info *vinfo, 1618 stmt_vec_info stmt_info, gimple *vec_stmt, 1619 gimple_stmt_iterator *gsi) 1620 { 1621 gcc_assert (!stmt_info || gimple_code (stmt_info->stmt) != GIMPLE_LABEL); 1622 1623 if (!gsi_end_p (*gsi) 1624 && gimple_has_mem_ops (vec_stmt)) 1625 { 1626 gimple *at_stmt = gsi_stmt (*gsi); 1627 tree vuse = gimple_vuse (at_stmt); 1628 if (vuse && TREE_CODE (vuse) == SSA_NAME) 1629 { 1630 tree vdef = gimple_vdef (at_stmt); 1631 gimple_set_vuse (vec_stmt, gimple_vuse (at_stmt)); 1632 gimple_set_modified (vec_stmt, true); 1633 /* If we have an SSA vuse and insert a store, update virtual 1634 SSA form to avoid triggering the renamer. Do so only 1635 if we can easily see all uses - which is what almost always 1636 happens with the way vectorized stmts are inserted. */ 1637 if ((vdef && TREE_CODE (vdef) == SSA_NAME) 1638 && ((is_gimple_assign (vec_stmt) 1639 && !is_gimple_reg (gimple_assign_lhs (vec_stmt))) 1640 || (is_gimple_call (vec_stmt) 1641 && !(gimple_call_flags (vec_stmt) 1642 & (ECF_CONST|ECF_PURE|ECF_NOVOPS))))) 1643 { 1644 tree new_vdef = copy_ssa_name (vuse, vec_stmt); 1645 gimple_set_vdef (vec_stmt, new_vdef); 1646 SET_USE (gimple_vuse_op (at_stmt), new_vdef); 1647 } 1648 } 1649 } 1650 gsi_insert_before (gsi, vec_stmt, GSI_SAME_STMT); 1651 vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt); 1652 } 1653 1654 /* We want to vectorize a call to combined function CFN with function 1655 decl FNDECL, using VECTYPE_OUT as the type of the output and VECTYPE_IN 1656 as the types of all inputs. Check whether this is possible using 1657 an internal function, returning its code if so or IFN_LAST if not. */ 1658 1659 static internal_fn 1660 vectorizable_internal_function (combined_fn cfn, tree fndecl, 1661 tree vectype_out, tree vectype_in) 1662 { 1663 internal_fn ifn; 1664 if (internal_fn_p (cfn)) 1665 ifn = as_internal_fn (cfn); 1666 else 1667 ifn = associated_internal_fn (fndecl); 1668 if (ifn != IFN_LAST && direct_internal_fn_p (ifn)) 1669 { 1670 const direct_internal_fn_info &info = direct_internal_fn (ifn); 1671 if (info.vectorizable) 1672 { 1673 tree type0 = (info.type0 < 0 ? vectype_out : vectype_in); 1674 tree type1 = (info.type1 < 0 ? vectype_out : vectype_in); 1675 if (direct_internal_fn_supported_p (ifn, tree_pair (type0, type1), 1676 OPTIMIZE_FOR_SPEED)) 1677 return ifn; 1678 } 1679 } 1680 return IFN_LAST; 1681 } 1682 1683 1684 static tree permute_vec_elements (vec_info *, tree, tree, tree, stmt_vec_info, 1685 gimple_stmt_iterator *); 1686 1687 /* Check whether a load or store statement in the loop described by 1688 LOOP_VINFO is possible in a loop using partial vectors. This is 1689 testing whether the vectorizer pass has the appropriate support, 1690 as well as whether the target does. 1691 1692 VLS_TYPE says whether the statement is a load or store and VECTYPE 1693 is the type of the vector being loaded or stored. SLP_NODE is the SLP 1694 node that contains the statement, or null if none. MEMORY_ACCESS_TYPE 1695 says how the load or store is going to be implemented and GROUP_SIZE 1696 is the number of load or store statements in the containing group. 1697 If the access is a gather load or scatter store, GS_INFO describes 1698 its arguments. If the load or store is conditional, SCALAR_MASK is the 1699 condition under which it occurs. 1700 1701 Clear LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P if a loop using partial 1702 vectors is not supported, otherwise record the required rgroup control 1703 types. */ 1704 1705 static void 1706 check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype, 1707 slp_tree slp_node, 1708 vec_load_store_type vls_type, 1709 int group_size, 1710 vect_memory_access_type 1711 memory_access_type, 1712 gather_scatter_info *gs_info, 1713 tree scalar_mask) 1714 { 1715 /* Invariant loads need no special support. */ 1716 if (memory_access_type == VMAT_INVARIANT) 1717 return; 1718 1719 unsigned int nvectors; 1720 if (slp_node) 1721 nvectors = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 1722 else 1723 nvectors = vect_get_num_copies (loop_vinfo, vectype); 1724 1725 vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo); 1726 machine_mode vecmode = TYPE_MODE (vectype); 1727 bool is_load = (vls_type == VLS_LOAD); 1728 if (memory_access_type == VMAT_LOAD_STORE_LANES) 1729 { 1730 if (is_load 1731 ? !vect_load_lanes_supported (vectype, group_size, true) 1732 : !vect_store_lanes_supported (vectype, group_size, true)) 1733 { 1734 if (dump_enabled_p ()) 1735 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 1736 "can't operate on partial vectors because" 1737 " the target doesn't have an appropriate" 1738 " load/store-lanes instruction.\n"); 1739 LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; 1740 return; 1741 } 1742 vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, 1743 scalar_mask); 1744 return; 1745 } 1746 1747 if (memory_access_type == VMAT_GATHER_SCATTER) 1748 { 1749 internal_fn ifn = (is_load 1750 ? IFN_MASK_GATHER_LOAD 1751 : IFN_MASK_SCATTER_STORE); 1752 if (!internal_gather_scatter_fn_supported_p (ifn, vectype, 1753 gs_info->memory_type, 1754 gs_info->offset_vectype, 1755 gs_info->scale)) 1756 { 1757 if (dump_enabled_p ()) 1758 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 1759 "can't operate on partial vectors because" 1760 " the target doesn't have an appropriate" 1761 " gather load or scatter store instruction.\n"); 1762 LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; 1763 return; 1764 } 1765 vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, 1766 scalar_mask); 1767 return; 1768 } 1769 1770 if (memory_access_type != VMAT_CONTIGUOUS 1771 && memory_access_type != VMAT_CONTIGUOUS_PERMUTE) 1772 { 1773 /* Element X of the data must come from iteration i * VF + X of the 1774 scalar loop. We need more work to support other mappings. */ 1775 if (dump_enabled_p ()) 1776 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 1777 "can't operate on partial vectors because an" 1778 " access isn't contiguous.\n"); 1779 LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; 1780 return; 1781 } 1782 1783 if (!VECTOR_MODE_P (vecmode)) 1784 { 1785 if (dump_enabled_p ()) 1786 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 1787 "can't operate on partial vectors when emulating" 1788 " vector operations.\n"); 1789 LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; 1790 return; 1791 } 1792 1793 /* We might load more scalars than we need for permuting SLP loads. 1794 We checked in get_group_load_store_type that the extra elements 1795 don't leak into a new vector. */ 1796 auto group_memory_nvectors = [](poly_uint64 size, poly_uint64 nunits) 1797 { 1798 unsigned int nvectors; 1799 if (can_div_away_from_zero_p (size, nunits, &nvectors)) 1800 return nvectors; 1801 gcc_unreachable (); 1802 }; 1803 1804 poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); 1805 poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); 1806 machine_mode mask_mode; 1807 bool using_partial_vectors_p = false; 1808 if (targetm.vectorize.get_mask_mode (vecmode).exists (&mask_mode) 1809 && can_vec_mask_load_store_p (vecmode, mask_mode, is_load)) 1810 { 1811 nvectors = group_memory_nvectors (group_size * vf, nunits); 1812 vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, scalar_mask); 1813 using_partial_vectors_p = true; 1814 } 1815 1816 machine_mode vmode; 1817 if (get_len_load_store_mode (vecmode, is_load).exists (&vmode)) 1818 { 1819 nvectors = group_memory_nvectors (group_size * vf, nunits); 1820 vec_loop_lens *lens = &LOOP_VINFO_LENS (loop_vinfo); 1821 unsigned factor = (vecmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vecmode); 1822 vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, factor); 1823 using_partial_vectors_p = true; 1824 } 1825 1826 if (!using_partial_vectors_p) 1827 { 1828 if (dump_enabled_p ()) 1829 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 1830 "can't operate on partial vectors because the" 1831 " target doesn't have the appropriate partial" 1832 " vectorization load or store.\n"); 1833 LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; 1834 } 1835 } 1836 1837 /* Return the mask input to a masked load or store. VEC_MASK is the vectorized 1838 form of the scalar mask condition and LOOP_MASK, if nonnull, is the mask 1839 that needs to be applied to all loads and stores in a vectorized loop. 1840 Return VEC_MASK if LOOP_MASK is null or if VEC_MASK is already masked, 1841 otherwise return VEC_MASK & LOOP_MASK. 1842 1843 MASK_TYPE is the type of both masks. If new statements are needed, 1844 insert them before GSI. */ 1845 1846 static tree 1847 prepare_vec_mask (loop_vec_info loop_vinfo, tree mask_type, tree loop_mask, 1848 tree vec_mask, gimple_stmt_iterator *gsi) 1849 { 1850 gcc_assert (useless_type_conversion_p (mask_type, TREE_TYPE (vec_mask))); 1851 if (!loop_mask) 1852 return vec_mask; 1853 1854 gcc_assert (TREE_TYPE (loop_mask) == mask_type); 1855 1856 if (loop_vinfo->vec_cond_masked_set.contains ({ vec_mask, loop_mask })) 1857 return vec_mask; 1858 1859 tree and_res = make_temp_ssa_name (mask_type, NULL, "vec_mask_and"); 1860 gimple *and_stmt = gimple_build_assign (and_res, BIT_AND_EXPR, 1861 vec_mask, loop_mask); 1862 1863 gsi_insert_before (gsi, and_stmt, GSI_SAME_STMT); 1864 return and_res; 1865 } 1866 1867 /* Determine whether we can use a gather load or scatter store to vectorize 1868 strided load or store STMT_INFO by truncating the current offset to a 1869 smaller width. We need to be able to construct an offset vector: 1870 1871 { 0, X, X*2, X*3, ... } 1872 1873 without loss of precision, where X is STMT_INFO's DR_STEP. 1874 1875 Return true if this is possible, describing the gather load or scatter 1876 store in GS_INFO. MASKED_P is true if the load or store is conditional. */ 1877 1878 static bool 1879 vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info, 1880 loop_vec_info loop_vinfo, bool masked_p, 1881 gather_scatter_info *gs_info) 1882 { 1883 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info); 1884 data_reference *dr = dr_info->dr; 1885 tree step = DR_STEP (dr); 1886 if (TREE_CODE (step) != INTEGER_CST) 1887 { 1888 /* ??? Perhaps we could use range information here? */ 1889 if (dump_enabled_p ()) 1890 dump_printf_loc (MSG_NOTE, vect_location, 1891 "cannot truncate variable step.\n"); 1892 return false; 1893 } 1894 1895 /* Get the number of bits in an element. */ 1896 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 1897 scalar_mode element_mode = SCALAR_TYPE_MODE (TREE_TYPE (vectype)); 1898 unsigned int element_bits = GET_MODE_BITSIZE (element_mode); 1899 1900 /* Set COUNT to the upper limit on the number of elements - 1. 1901 Start with the maximum vectorization factor. */ 1902 unsigned HOST_WIDE_INT count = vect_max_vf (loop_vinfo) - 1; 1903 1904 /* Try lowering COUNT to the number of scalar latch iterations. */ 1905 class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); 1906 widest_int max_iters; 1907 if (max_loop_iterations (loop, &max_iters) 1908 && max_iters < count) 1909 count = max_iters.to_shwi (); 1910 1911 /* Try scales of 1 and the element size. */ 1912 int scales[] = { 1, vect_get_scalar_dr_size (dr_info) }; 1913 wi::overflow_type overflow = wi::OVF_NONE; 1914 for (int i = 0; i < 2; ++i) 1915 { 1916 int scale = scales[i]; 1917 widest_int factor; 1918 if (!wi::multiple_of_p (wi::to_widest (step), scale, SIGNED, &factor)) 1919 continue; 1920 1921 /* Determine the minimum precision of (COUNT - 1) * STEP / SCALE. */ 1922 widest_int range = wi::mul (count, factor, SIGNED, &overflow); 1923 if (overflow) 1924 continue; 1925 signop sign = range >= 0 ? UNSIGNED : SIGNED; 1926 unsigned int min_offset_bits = wi::min_precision (range, sign); 1927 1928 /* Find the narrowest viable offset type. */ 1929 unsigned int offset_bits = 1U << ceil_log2 (min_offset_bits); 1930 tree offset_type = build_nonstandard_integer_type (offset_bits, 1931 sign == UNSIGNED); 1932 1933 /* See whether the target supports the operation with an offset 1934 no narrower than OFFSET_TYPE. */ 1935 tree memory_type = TREE_TYPE (DR_REF (dr)); 1936 if (!vect_gather_scatter_fn_p (loop_vinfo, DR_IS_READ (dr), masked_p, 1937 vectype, memory_type, offset_type, scale, 1938 &gs_info->ifn, &gs_info->offset_vectype) 1939 || gs_info->ifn == IFN_LAST) 1940 continue; 1941 1942 gs_info->decl = NULL_TREE; 1943 /* Logically the sum of DR_BASE_ADDRESS, DR_INIT and DR_OFFSET, 1944 but we don't need to store that here. */ 1945 gs_info->base = NULL_TREE; 1946 gs_info->element_type = TREE_TYPE (vectype); 1947 gs_info->offset = fold_convert (offset_type, step); 1948 gs_info->offset_dt = vect_constant_def; 1949 gs_info->scale = scale; 1950 gs_info->memory_type = memory_type; 1951 return true; 1952 } 1953 1954 if (overflow && dump_enabled_p ()) 1955 dump_printf_loc (MSG_NOTE, vect_location, 1956 "truncating gather/scatter offset to %d bits" 1957 " might change its value.\n", element_bits); 1958 1959 return false; 1960 } 1961 1962 /* Return true if we can use gather/scatter internal functions to 1963 vectorize STMT_INFO, which is a grouped or strided load or store. 1964 MASKED_P is true if load or store is conditional. When returning 1965 true, fill in GS_INFO with the information required to perform the 1966 operation. */ 1967 1968 static bool 1969 vect_use_strided_gather_scatters_p (stmt_vec_info stmt_info, 1970 loop_vec_info loop_vinfo, bool masked_p, 1971 gather_scatter_info *gs_info) 1972 { 1973 if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info) 1974 || gs_info->ifn == IFN_LAST) 1975 return vect_truncate_gather_scatter_offset (stmt_info, loop_vinfo, 1976 masked_p, gs_info); 1977 1978 tree old_offset_type = TREE_TYPE (gs_info->offset); 1979 tree new_offset_type = TREE_TYPE (gs_info->offset_vectype); 1980 1981 gcc_assert (TYPE_PRECISION (new_offset_type) 1982 >= TYPE_PRECISION (old_offset_type)); 1983 gs_info->offset = fold_convert (new_offset_type, gs_info->offset); 1984 1985 if (dump_enabled_p ()) 1986 dump_printf_loc (MSG_NOTE, vect_location, 1987 "using gather/scatter for strided/grouped access," 1988 " scale = %d\n", gs_info->scale); 1989 1990 return true; 1991 } 1992 1993 /* STMT_INFO is a non-strided load or store, meaning that it accesses 1994 elements with a known constant step. Return -1 if that step 1995 is negative, 0 if it is zero, and 1 if it is greater than zero. */ 1996 1997 static int 1998 compare_step_with_zero (vec_info *vinfo, stmt_vec_info stmt_info) 1999 { 2000 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info); 2001 return tree_int_cst_compare (vect_dr_behavior (vinfo, dr_info)->step, 2002 size_zero_node); 2003 } 2004 2005 /* If the target supports a permute mask that reverses the elements in 2006 a vector of type VECTYPE, return that mask, otherwise return null. */ 2007 2008 static tree 2009 perm_mask_for_reverse (tree vectype) 2010 { 2011 poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); 2012 2013 /* The encoding has a single stepped pattern. */ 2014 vec_perm_builder sel (nunits, 1, 3); 2015 for (int i = 0; i < 3; ++i) 2016 sel.quick_push (nunits - 1 - i); 2017 2018 vec_perm_indices indices (sel, 1, nunits); 2019 if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) 2020 return NULL_TREE; 2021 return vect_gen_perm_mask_checked (vectype, indices); 2022 } 2023 2024 /* A subroutine of get_load_store_type, with a subset of the same 2025 arguments. Handle the case where STMT_INFO is a load or store that 2026 accesses consecutive elements with a negative step. Sets *POFFSET 2027 to the offset to be applied to the DR for the first access. */ 2028 2029 static vect_memory_access_type 2030 get_negative_load_store_type (vec_info *vinfo, 2031 stmt_vec_info stmt_info, tree vectype, 2032 vec_load_store_type vls_type, 2033 unsigned int ncopies, poly_int64 *poffset) 2034 { 2035 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info); 2036 dr_alignment_support alignment_support_scheme; 2037 2038 if (ncopies > 1) 2039 { 2040 if (dump_enabled_p ()) 2041 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2042 "multiple types with negative step.\n"); 2043 return VMAT_ELEMENTWISE; 2044 } 2045 2046 /* For backward running DRs the first access in vectype actually is 2047 N-1 elements before the address of the DR. */ 2048 *poffset = ((-TYPE_VECTOR_SUBPARTS (vectype) + 1) 2049 * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype)))); 2050 2051 int misalignment = dr_misalignment (dr_info, vectype, *poffset); 2052 alignment_support_scheme 2053 = vect_supportable_dr_alignment (vinfo, dr_info, vectype, misalignment); 2054 if (alignment_support_scheme != dr_aligned 2055 && alignment_support_scheme != dr_unaligned_supported) 2056 { 2057 if (dump_enabled_p ()) 2058 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2059 "negative step but alignment required.\n"); 2060 *poffset = 0; 2061 return VMAT_ELEMENTWISE; 2062 } 2063 2064 if (vls_type == VLS_STORE_INVARIANT) 2065 { 2066 if (dump_enabled_p ()) 2067 dump_printf_loc (MSG_NOTE, vect_location, 2068 "negative step with invariant source;" 2069 " no permute needed.\n"); 2070 return VMAT_CONTIGUOUS_DOWN; 2071 } 2072 2073 if (!perm_mask_for_reverse (vectype)) 2074 { 2075 if (dump_enabled_p ()) 2076 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2077 "negative step and reversing not supported.\n"); 2078 *poffset = 0; 2079 return VMAT_ELEMENTWISE; 2080 } 2081 2082 return VMAT_CONTIGUOUS_REVERSE; 2083 } 2084 2085 /* STMT_INFO is either a masked or unconditional store. Return the value 2086 being stored. */ 2087 2088 tree 2089 vect_get_store_rhs (stmt_vec_info stmt_info) 2090 { 2091 if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt)) 2092 { 2093 gcc_assert (gimple_assign_single_p (assign)); 2094 return gimple_assign_rhs1 (assign); 2095 } 2096 if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt)) 2097 { 2098 internal_fn ifn = gimple_call_internal_fn (call); 2099 int index = internal_fn_stored_value_index (ifn); 2100 gcc_assert (index >= 0); 2101 return gimple_call_arg (call, index); 2102 } 2103 gcc_unreachable (); 2104 } 2105 2106 /* Function VECTOR_VECTOR_COMPOSITION_TYPE 2107 2108 This function returns a vector type which can be composed with NETLS pieces, 2109 whose type is recorded in PTYPE. VTYPE should be a vector type, and has the 2110 same vector size as the return vector. It checks target whether supports 2111 pieces-size vector mode for construction firstly, if target fails to, check 2112 pieces-size scalar mode for construction further. It returns NULL_TREE if 2113 fails to find the available composition. 2114 2115 For example, for (vtype=V16QI, nelts=4), we can probably get: 2116 - V16QI with PTYPE V4QI. 2117 - V4SI with PTYPE SI. 2118 - NULL_TREE. */ 2119 2120 static tree 2121 vector_vector_composition_type (tree vtype, poly_uint64 nelts, tree *ptype) 2122 { 2123 gcc_assert (VECTOR_TYPE_P (vtype)); 2124 gcc_assert (known_gt (nelts, 0U)); 2125 2126 machine_mode vmode = TYPE_MODE (vtype); 2127 if (!VECTOR_MODE_P (vmode)) 2128 return NULL_TREE; 2129 2130 poly_uint64 vbsize = GET_MODE_BITSIZE (vmode); 2131 unsigned int pbsize; 2132 if (constant_multiple_p (vbsize, nelts, &pbsize)) 2133 { 2134 /* First check if vec_init optab supports construction from 2135 vector pieces directly. */ 2136 scalar_mode elmode = SCALAR_TYPE_MODE (TREE_TYPE (vtype)); 2137 poly_uint64 inelts = pbsize / GET_MODE_BITSIZE (elmode); 2138 machine_mode rmode; 2139 if (related_vector_mode (vmode, elmode, inelts).exists (&rmode) 2140 && (convert_optab_handler (vec_init_optab, vmode, rmode) 2141 != CODE_FOR_nothing)) 2142 { 2143 *ptype = build_vector_type (TREE_TYPE (vtype), inelts); 2144 return vtype; 2145 } 2146 2147 /* Otherwise check if exists an integer type of the same piece size and 2148 if vec_init optab supports construction from it directly. */ 2149 if (int_mode_for_size (pbsize, 0).exists (&elmode) 2150 && related_vector_mode (vmode, elmode, nelts).exists (&rmode) 2151 && (convert_optab_handler (vec_init_optab, rmode, elmode) 2152 != CODE_FOR_nothing)) 2153 { 2154 *ptype = build_nonstandard_integer_type (pbsize, 1); 2155 return build_vector_type (*ptype, nelts); 2156 } 2157 } 2158 2159 return NULL_TREE; 2160 } 2161 2162 /* A subroutine of get_load_store_type, with a subset of the same 2163 arguments. Handle the case where STMT_INFO is part of a grouped load 2164 or store. 2165 2166 For stores, the statements in the group are all consecutive 2167 and there is no gap at the end. For loads, the statements in the 2168 group might not be consecutive; there can be gaps between statements 2169 as well as at the end. */ 2170 2171 static bool 2172 get_group_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, 2173 tree vectype, slp_tree slp_node, 2174 bool masked_p, vec_load_store_type vls_type, 2175 vect_memory_access_type *memory_access_type, 2176 poly_int64 *poffset, 2177 dr_alignment_support *alignment_support_scheme, 2178 int *misalignment, 2179 gather_scatter_info *gs_info) 2180 { 2181 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 2182 class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL; 2183 stmt_vec_info first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 2184 dr_vec_info *first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info); 2185 unsigned int group_size = DR_GROUP_SIZE (first_stmt_info); 2186 bool single_element_p = (stmt_info == first_stmt_info 2187 && !DR_GROUP_NEXT_ELEMENT (stmt_info)); 2188 unsigned HOST_WIDE_INT gap = DR_GROUP_GAP (first_stmt_info); 2189 poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); 2190 2191 /* True if the vectorized statements would access beyond the last 2192 statement in the group. */ 2193 bool overrun_p = false; 2194 2195 /* True if we can cope with such overrun by peeling for gaps, so that 2196 there is at least one final scalar iteration after the vector loop. */ 2197 bool can_overrun_p = (!masked_p 2198 && vls_type == VLS_LOAD 2199 && loop_vinfo 2200 && !loop->inner); 2201 2202 /* There can only be a gap at the end of the group if the stride is 2203 known at compile time. */ 2204 gcc_assert (!STMT_VINFO_STRIDED_P (first_stmt_info) || gap == 0); 2205 2206 /* Stores can't yet have gaps. */ 2207 gcc_assert (slp_node || vls_type == VLS_LOAD || gap == 0); 2208 2209 if (slp_node) 2210 { 2211 /* For SLP vectorization we directly vectorize a subchain 2212 without permutation. */ 2213 if (! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()) 2214 first_dr_info 2215 = STMT_VINFO_DR_INFO (SLP_TREE_SCALAR_STMTS (slp_node)[0]); 2216 if (STMT_VINFO_STRIDED_P (first_stmt_info)) 2217 { 2218 /* Try to use consecutive accesses of DR_GROUP_SIZE elements, 2219 separated by the stride, until we have a complete vector. 2220 Fall back to scalar accesses if that isn't possible. */ 2221 if (multiple_p (nunits, group_size)) 2222 *memory_access_type = VMAT_STRIDED_SLP; 2223 else 2224 *memory_access_type = VMAT_ELEMENTWISE; 2225 } 2226 else 2227 { 2228 overrun_p = loop_vinfo && gap != 0; 2229 if (overrun_p && vls_type != VLS_LOAD) 2230 { 2231 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2232 "Grouped store with gaps requires" 2233 " non-consecutive accesses\n"); 2234 return false; 2235 } 2236 /* An overrun is fine if the trailing elements are smaller 2237 than the alignment boundary B. Every vector access will 2238 be a multiple of B and so we are guaranteed to access a 2239 non-gap element in the same B-sized block. */ 2240 if (overrun_p 2241 && gap < (vect_known_alignment_in_bytes (first_dr_info, 2242 vectype) 2243 / vect_get_scalar_dr_size (first_dr_info))) 2244 overrun_p = false; 2245 2246 /* If the gap splits the vector in half and the target 2247 can do half-vector operations avoid the epilogue peeling 2248 by simply loading half of the vector only. Usually 2249 the construction with an upper zero half will be elided. */ 2250 dr_alignment_support alss; 2251 int misalign = dr_misalignment (first_dr_info, vectype); 2252 tree half_vtype; 2253 if (overrun_p 2254 && !masked_p 2255 && (((alss = vect_supportable_dr_alignment (vinfo, first_dr_info, 2256 vectype, misalign))) 2257 == dr_aligned 2258 || alss == dr_unaligned_supported) 2259 && known_eq (nunits, (group_size - gap) * 2) 2260 && known_eq (nunits, group_size) 2261 && (vector_vector_composition_type (vectype, 2, &half_vtype) 2262 != NULL_TREE)) 2263 overrun_p = false; 2264 2265 if (overrun_p && !can_overrun_p) 2266 { 2267 if (dump_enabled_p ()) 2268 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2269 "Peeling for outer loop is not supported\n"); 2270 return false; 2271 } 2272 int cmp = compare_step_with_zero (vinfo, stmt_info); 2273 if (cmp < 0) 2274 { 2275 if (single_element_p) 2276 /* ??? The VMAT_CONTIGUOUS_REVERSE code generation is 2277 only correct for single element "interleaving" SLP. */ 2278 *memory_access_type = get_negative_load_store_type 2279 (vinfo, stmt_info, vectype, vls_type, 1, poffset); 2280 else 2281 { 2282 /* Try to use consecutive accesses of DR_GROUP_SIZE elements, 2283 separated by the stride, until we have a complete vector. 2284 Fall back to scalar accesses if that isn't possible. */ 2285 if (multiple_p (nunits, group_size)) 2286 *memory_access_type = VMAT_STRIDED_SLP; 2287 else 2288 *memory_access_type = VMAT_ELEMENTWISE; 2289 } 2290 } 2291 else 2292 { 2293 gcc_assert (!loop_vinfo || cmp > 0); 2294 *memory_access_type = VMAT_CONTIGUOUS; 2295 } 2296 2297 /* When we have a contiguous access across loop iterations 2298 but the access in the loop doesn't cover the full vector 2299 we can end up with no gap recorded but still excess 2300 elements accessed, see PR103116. Make sure we peel for 2301 gaps if necessary and sufficient and give up if not. */ 2302 if (loop_vinfo 2303 && *memory_access_type == VMAT_CONTIGUOUS 2304 && SLP_TREE_LOAD_PERMUTATION (slp_node).exists () 2305 && !multiple_p (group_size * LOOP_VINFO_VECT_FACTOR (loop_vinfo), 2306 nunits)) 2307 { 2308 unsigned HOST_WIDE_INT cnunits, cvf; 2309 if (!can_overrun_p 2310 || !nunits.is_constant (&cnunits) 2311 || !LOOP_VINFO_VECT_FACTOR (loop_vinfo).is_constant (&cvf) 2312 /* Peeling for gaps assumes that a single scalar iteration 2313 is enough to make sure the last vector iteration doesn't 2314 access excess elements. 2315 ??? Enhancements include peeling multiple iterations 2316 or using masked loads with a static mask. */ 2317 || (group_size * cvf) % cnunits + group_size < cnunits) 2318 { 2319 if (dump_enabled_p ()) 2320 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2321 "peeling for gaps insufficient for " 2322 "access\n"); 2323 return false; 2324 } 2325 overrun_p = true; 2326 } 2327 } 2328 } 2329 else 2330 { 2331 /* We can always handle this case using elementwise accesses, 2332 but see if something more efficient is available. */ 2333 *memory_access_type = VMAT_ELEMENTWISE; 2334 2335 /* If there is a gap at the end of the group then these optimizations 2336 would access excess elements in the last iteration. */ 2337 bool would_overrun_p = (gap != 0); 2338 /* An overrun is fine if the trailing elements are smaller than the 2339 alignment boundary B. Every vector access will be a multiple of B 2340 and so we are guaranteed to access a non-gap element in the 2341 same B-sized block. */ 2342 if (would_overrun_p 2343 && !masked_p 2344 && gap < (vect_known_alignment_in_bytes (first_dr_info, vectype) 2345 / vect_get_scalar_dr_size (first_dr_info))) 2346 would_overrun_p = false; 2347 2348 if (!STMT_VINFO_STRIDED_P (first_stmt_info) 2349 && (can_overrun_p || !would_overrun_p) 2350 && compare_step_with_zero (vinfo, stmt_info) > 0) 2351 { 2352 /* First cope with the degenerate case of a single-element 2353 vector. */ 2354 if (known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U)) 2355 ; 2356 2357 /* Otherwise try using LOAD/STORE_LANES. */ 2358 else if (vls_type == VLS_LOAD 2359 ? vect_load_lanes_supported (vectype, group_size, masked_p) 2360 : vect_store_lanes_supported (vectype, group_size, 2361 masked_p)) 2362 { 2363 *memory_access_type = VMAT_LOAD_STORE_LANES; 2364 overrun_p = would_overrun_p; 2365 } 2366 2367 /* If that fails, try using permuting loads. */ 2368 else if (vls_type == VLS_LOAD 2369 ? vect_grouped_load_supported (vectype, single_element_p, 2370 group_size) 2371 : vect_grouped_store_supported (vectype, group_size)) 2372 { 2373 *memory_access_type = VMAT_CONTIGUOUS_PERMUTE; 2374 overrun_p = would_overrun_p; 2375 } 2376 } 2377 2378 /* As a last resort, trying using a gather load or scatter store. 2379 2380 ??? Although the code can handle all group sizes correctly, 2381 it probably isn't a win to use separate strided accesses based 2382 on nearby locations. Or, even if it's a win over scalar code, 2383 it might not be a win over vectorizing at a lower VF, if that 2384 allows us to use contiguous accesses. */ 2385 if (*memory_access_type == VMAT_ELEMENTWISE 2386 && single_element_p 2387 && loop_vinfo 2388 && vect_use_strided_gather_scatters_p (stmt_info, loop_vinfo, 2389 masked_p, gs_info)) 2390 *memory_access_type = VMAT_GATHER_SCATTER; 2391 } 2392 2393 if (*memory_access_type == VMAT_GATHER_SCATTER 2394 || *memory_access_type == VMAT_ELEMENTWISE) 2395 { 2396 *alignment_support_scheme = dr_unaligned_supported; 2397 *misalignment = DR_MISALIGNMENT_UNKNOWN; 2398 } 2399 else 2400 { 2401 *misalignment = dr_misalignment (first_dr_info, vectype, *poffset); 2402 *alignment_support_scheme 2403 = vect_supportable_dr_alignment (vinfo, first_dr_info, vectype, 2404 *misalignment); 2405 } 2406 2407 if (vls_type != VLS_LOAD && first_stmt_info == stmt_info) 2408 { 2409 /* STMT is the leader of the group. Check the operands of all the 2410 stmts of the group. */ 2411 stmt_vec_info next_stmt_info = DR_GROUP_NEXT_ELEMENT (stmt_info); 2412 while (next_stmt_info) 2413 { 2414 tree op = vect_get_store_rhs (next_stmt_info); 2415 enum vect_def_type dt; 2416 if (!vect_is_simple_use (op, vinfo, &dt)) 2417 { 2418 if (dump_enabled_p ()) 2419 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2420 "use not simple.\n"); 2421 return false; 2422 } 2423 next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); 2424 } 2425 } 2426 2427 if (overrun_p) 2428 { 2429 gcc_assert (can_overrun_p); 2430 if (dump_enabled_p ()) 2431 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2432 "Data access with gaps requires scalar " 2433 "epilogue loop\n"); 2434 LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo) = true; 2435 } 2436 2437 return true; 2438 } 2439 2440 /* Analyze load or store statement STMT_INFO of type VLS_TYPE. Return true 2441 if there is a memory access type that the vectorized form can use, 2442 storing it in *MEMORY_ACCESS_TYPE if so. If we decide to use gathers 2443 or scatters, fill in GS_INFO accordingly. In addition 2444 *ALIGNMENT_SUPPORT_SCHEME is filled out and false is returned if 2445 the target does not support the alignment scheme. *MISALIGNMENT 2446 is set according to the alignment of the access (including 2447 DR_MISALIGNMENT_UNKNOWN when it is unknown). 2448 2449 SLP says whether we're performing SLP rather than loop vectorization. 2450 MASKED_P is true if the statement is conditional on a vectorized mask. 2451 VECTYPE is the vector type that the vectorized statements will use. 2452 NCOPIES is the number of vector statements that will be needed. */ 2453 2454 static bool 2455 get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, 2456 tree vectype, slp_tree slp_node, 2457 bool masked_p, vec_load_store_type vls_type, 2458 unsigned int ncopies, 2459 vect_memory_access_type *memory_access_type, 2460 poly_int64 *poffset, 2461 dr_alignment_support *alignment_support_scheme, 2462 int *misalignment, 2463 gather_scatter_info *gs_info) 2464 { 2465 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 2466 poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); 2467 *misalignment = DR_MISALIGNMENT_UNKNOWN; 2468 *poffset = 0; 2469 if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) 2470 { 2471 *memory_access_type = VMAT_GATHER_SCATTER; 2472 if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info)) 2473 gcc_unreachable (); 2474 else if (!vect_is_simple_use (gs_info->offset, vinfo, 2475 &gs_info->offset_dt, 2476 &gs_info->offset_vectype)) 2477 { 2478 if (dump_enabled_p ()) 2479 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2480 "%s index use not simple.\n", 2481 vls_type == VLS_LOAD ? "gather" : "scatter"); 2482 return false; 2483 } 2484 else if (gs_info->ifn == IFN_LAST && !gs_info->decl) 2485 { 2486 if (vls_type != VLS_LOAD) 2487 { 2488 if (dump_enabled_p ()) 2489 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2490 "unsupported emulated scatter.\n"); 2491 return false; 2492 } 2493 else if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant () 2494 || !TYPE_VECTOR_SUBPARTS 2495 (gs_info->offset_vectype).is_constant () 2496 || VECTOR_BOOLEAN_TYPE_P (gs_info->offset_vectype) 2497 || !constant_multiple_p (TYPE_VECTOR_SUBPARTS 2498 (gs_info->offset_vectype), 2499 TYPE_VECTOR_SUBPARTS (vectype))) 2500 { 2501 if (dump_enabled_p ()) 2502 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2503 "unsupported vector types for emulated " 2504 "gather.\n"); 2505 return false; 2506 } 2507 } 2508 /* Gather-scatter accesses perform only component accesses, alignment 2509 is irrelevant for them. */ 2510 *alignment_support_scheme = dr_unaligned_supported; 2511 } 2512 else if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) 2513 { 2514 if (!get_group_load_store_type (vinfo, stmt_info, vectype, slp_node, 2515 masked_p, 2516 vls_type, memory_access_type, poffset, 2517 alignment_support_scheme, 2518 misalignment, gs_info)) 2519 return false; 2520 } 2521 else if (STMT_VINFO_STRIDED_P (stmt_info)) 2522 { 2523 gcc_assert (!slp_node); 2524 if (loop_vinfo 2525 && vect_use_strided_gather_scatters_p (stmt_info, loop_vinfo, 2526 masked_p, gs_info)) 2527 *memory_access_type = VMAT_GATHER_SCATTER; 2528 else 2529 *memory_access_type = VMAT_ELEMENTWISE; 2530 /* Alignment is irrelevant here. */ 2531 *alignment_support_scheme = dr_unaligned_supported; 2532 } 2533 else 2534 { 2535 int cmp = compare_step_with_zero (vinfo, stmt_info); 2536 if (cmp == 0) 2537 { 2538 gcc_assert (vls_type == VLS_LOAD); 2539 *memory_access_type = VMAT_INVARIANT; 2540 /* Invariant accesses perform only component accesses, alignment 2541 is irrelevant for them. */ 2542 *alignment_support_scheme = dr_unaligned_supported; 2543 } 2544 else 2545 { 2546 if (cmp < 0) 2547 *memory_access_type = get_negative_load_store_type 2548 (vinfo, stmt_info, vectype, vls_type, ncopies, poffset); 2549 else 2550 *memory_access_type = VMAT_CONTIGUOUS; 2551 *misalignment = dr_misalignment (STMT_VINFO_DR_INFO (stmt_info), 2552 vectype, *poffset); 2553 *alignment_support_scheme 2554 = vect_supportable_dr_alignment (vinfo, 2555 STMT_VINFO_DR_INFO (stmt_info), 2556 vectype, *misalignment); 2557 } 2558 } 2559 2560 if ((*memory_access_type == VMAT_ELEMENTWISE 2561 || *memory_access_type == VMAT_STRIDED_SLP) 2562 && !nunits.is_constant ()) 2563 { 2564 if (dump_enabled_p ()) 2565 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2566 "Not using elementwise accesses due to variable " 2567 "vectorization factor.\n"); 2568 return false; 2569 } 2570 2571 if (*alignment_support_scheme == dr_unaligned_unsupported) 2572 { 2573 if (dump_enabled_p ()) 2574 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2575 "unsupported unaligned access\n"); 2576 return false; 2577 } 2578 2579 /* FIXME: At the moment the cost model seems to underestimate the 2580 cost of using elementwise accesses. This check preserves the 2581 traditional behavior until that can be fixed. */ 2582 stmt_vec_info first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 2583 if (!first_stmt_info) 2584 first_stmt_info = stmt_info; 2585 if (*memory_access_type == VMAT_ELEMENTWISE 2586 && !STMT_VINFO_STRIDED_P (first_stmt_info) 2587 && !(stmt_info == DR_GROUP_FIRST_ELEMENT (stmt_info) 2588 && !DR_GROUP_NEXT_ELEMENT (stmt_info) 2589 && !pow2p_hwi (DR_GROUP_SIZE (stmt_info)))) 2590 { 2591 if (dump_enabled_p ()) 2592 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2593 "not falling back to elementwise accesses\n"); 2594 return false; 2595 } 2596 return true; 2597 } 2598 2599 /* Return true if boolean argument at MASK_INDEX is suitable for vectorizing 2600 conditional operation STMT_INFO. When returning true, store the mask 2601 in *MASK, the type of its definition in *MASK_DT_OUT, the type of the 2602 vectorized mask in *MASK_VECTYPE_OUT and the SLP node corresponding 2603 to the mask in *MASK_NODE if MASK_NODE is not NULL. */ 2604 2605 static bool 2606 vect_check_scalar_mask (vec_info *vinfo, stmt_vec_info stmt_info, 2607 slp_tree slp_node, unsigned mask_index, 2608 tree *mask, slp_tree *mask_node, 2609 vect_def_type *mask_dt_out, tree *mask_vectype_out) 2610 { 2611 enum vect_def_type mask_dt; 2612 tree mask_vectype; 2613 slp_tree mask_node_1; 2614 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, mask_index, 2615 mask, &mask_node_1, &mask_dt, &mask_vectype)) 2616 { 2617 if (dump_enabled_p ()) 2618 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2619 "mask use not simple.\n"); 2620 return false; 2621 } 2622 2623 if (!VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (*mask))) 2624 { 2625 if (dump_enabled_p ()) 2626 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2627 "mask argument is not a boolean.\n"); 2628 return false; 2629 } 2630 2631 /* If the caller is not prepared for adjusting an external/constant 2632 SLP mask vector type fail. */ 2633 if (slp_node 2634 && !mask_node 2635 && SLP_TREE_DEF_TYPE (mask_node_1) != vect_internal_def) 2636 { 2637 if (dump_enabled_p ()) 2638 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2639 "SLP mask argument is not vectorized.\n"); 2640 return false; 2641 } 2642 2643 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 2644 if (!mask_vectype) 2645 mask_vectype = get_mask_type_for_scalar_type (vinfo, TREE_TYPE (vectype)); 2646 2647 if (!mask_vectype || !VECTOR_BOOLEAN_TYPE_P (mask_vectype)) 2648 { 2649 if (dump_enabled_p ()) 2650 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2651 "could not find an appropriate vector mask type.\n"); 2652 return false; 2653 } 2654 2655 if (maybe_ne (TYPE_VECTOR_SUBPARTS (mask_vectype), 2656 TYPE_VECTOR_SUBPARTS (vectype))) 2657 { 2658 if (dump_enabled_p ()) 2659 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2660 "vector mask type %T" 2661 " does not match vector data type %T.\n", 2662 mask_vectype, vectype); 2663 2664 return false; 2665 } 2666 2667 *mask_dt_out = mask_dt; 2668 *mask_vectype_out = mask_vectype; 2669 if (mask_node) 2670 *mask_node = mask_node_1; 2671 return true; 2672 } 2673 2674 /* Return true if stored value RHS is suitable for vectorizing store 2675 statement STMT_INFO. When returning true, store the type of the 2676 definition in *RHS_DT_OUT, the type of the vectorized store value in 2677 *RHS_VECTYPE_OUT and the type of the store in *VLS_TYPE_OUT. */ 2678 2679 static bool 2680 vect_check_store_rhs (vec_info *vinfo, stmt_vec_info stmt_info, 2681 slp_tree slp_node, tree rhs, 2682 vect_def_type *rhs_dt_out, tree *rhs_vectype_out, 2683 vec_load_store_type *vls_type_out) 2684 { 2685 /* In the case this is a store from a constant make sure 2686 native_encode_expr can handle it. */ 2687 if (CONSTANT_CLASS_P (rhs) && native_encode_expr (rhs, NULL, 64) == 0) 2688 { 2689 if (dump_enabled_p ()) 2690 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2691 "cannot encode constant as a byte sequence.\n"); 2692 return false; 2693 } 2694 2695 unsigned op_no = 0; 2696 if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt)) 2697 { 2698 if (gimple_call_internal_p (call) 2699 && internal_store_fn_p (gimple_call_internal_fn (call))) 2700 op_no = internal_fn_stored_value_index (gimple_call_internal_fn (call)); 2701 } 2702 2703 enum vect_def_type rhs_dt; 2704 tree rhs_vectype; 2705 slp_tree slp_op; 2706 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, op_no, 2707 &rhs, &slp_op, &rhs_dt, &rhs_vectype)) 2708 { 2709 if (dump_enabled_p ()) 2710 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2711 "use not simple.\n"); 2712 return false; 2713 } 2714 2715 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 2716 if (rhs_vectype && !useless_type_conversion_p (vectype, rhs_vectype)) 2717 { 2718 if (dump_enabled_p ()) 2719 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 2720 "incompatible vector types.\n"); 2721 return false; 2722 } 2723 2724 *rhs_dt_out = rhs_dt; 2725 *rhs_vectype_out = rhs_vectype; 2726 if (rhs_dt == vect_constant_def || rhs_dt == vect_external_def) 2727 *vls_type_out = VLS_STORE_INVARIANT; 2728 else 2729 *vls_type_out = VLS_STORE; 2730 return true; 2731 } 2732 2733 /* Build an all-ones vector mask of type MASKTYPE while vectorizing STMT_INFO. 2734 Note that we support masks with floating-point type, in which case the 2735 floats are interpreted as a bitmask. */ 2736 2737 static tree 2738 vect_build_all_ones_mask (vec_info *vinfo, 2739 stmt_vec_info stmt_info, tree masktype) 2740 { 2741 if (TREE_CODE (masktype) == INTEGER_TYPE) 2742 return build_int_cst (masktype, -1); 2743 else if (TREE_CODE (TREE_TYPE (masktype)) == INTEGER_TYPE) 2744 { 2745 tree mask = build_int_cst (TREE_TYPE (masktype), -1); 2746 mask = build_vector_from_val (masktype, mask); 2747 return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL); 2748 } 2749 else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (masktype))) 2750 { 2751 REAL_VALUE_TYPE r; 2752 long tmp[6]; 2753 for (int j = 0; j < 6; ++j) 2754 tmp[j] = -1; 2755 real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (masktype))); 2756 tree mask = build_real (TREE_TYPE (masktype), r); 2757 mask = build_vector_from_val (masktype, mask); 2758 return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL); 2759 } 2760 gcc_unreachable (); 2761 } 2762 2763 /* Build an all-zero merge value of type VECTYPE while vectorizing 2764 STMT_INFO as a gather load. */ 2765 2766 static tree 2767 vect_build_zero_merge_argument (vec_info *vinfo, 2768 stmt_vec_info stmt_info, tree vectype) 2769 { 2770 tree merge; 2771 if (TREE_CODE (TREE_TYPE (vectype)) == INTEGER_TYPE) 2772 merge = build_int_cst (TREE_TYPE (vectype), 0); 2773 else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (vectype))) 2774 { 2775 REAL_VALUE_TYPE r; 2776 long tmp[6]; 2777 for (int j = 0; j < 6; ++j) 2778 tmp[j] = 0; 2779 real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (vectype))); 2780 merge = build_real (TREE_TYPE (vectype), r); 2781 } 2782 else 2783 gcc_unreachable (); 2784 merge = build_vector_from_val (vectype, merge); 2785 return vect_init_vector (vinfo, stmt_info, merge, vectype, NULL); 2786 } 2787 2788 /* Build a gather load call while vectorizing STMT_INFO. Insert new 2789 instructions before GSI and add them to VEC_STMT. GS_INFO describes 2790 the gather load operation. If the load is conditional, MASK is the 2791 unvectorized condition and MASK_DT is its definition type, otherwise 2792 MASK is null. */ 2793 2794 static void 2795 vect_build_gather_load_calls (vec_info *vinfo, stmt_vec_info stmt_info, 2796 gimple_stmt_iterator *gsi, 2797 gimple **vec_stmt, 2798 gather_scatter_info *gs_info, 2799 tree mask) 2800 { 2801 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 2802 class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); 2803 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 2804 poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); 2805 int ncopies = vect_get_num_copies (loop_vinfo, vectype); 2806 edge pe = loop_preheader_edge (loop); 2807 enum { NARROW, NONE, WIDEN } modifier; 2808 poly_uint64 gather_off_nunits 2809 = TYPE_VECTOR_SUBPARTS (gs_info->offset_vectype); 2810 2811 tree arglist = TYPE_ARG_TYPES (TREE_TYPE (gs_info->decl)); 2812 tree rettype = TREE_TYPE (TREE_TYPE (gs_info->decl)); 2813 tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); 2814 tree ptrtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); 2815 tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); 2816 tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); 2817 tree scaletype = TREE_VALUE (arglist); 2818 tree real_masktype = masktype; 2819 gcc_checking_assert (types_compatible_p (srctype, rettype) 2820 && (!mask 2821 || TREE_CODE (masktype) == INTEGER_TYPE 2822 || types_compatible_p (srctype, masktype))); 2823 if (mask) 2824 masktype = truth_type_for (srctype); 2825 2826 tree mask_halftype = masktype; 2827 tree perm_mask = NULL_TREE; 2828 tree mask_perm_mask = NULL_TREE; 2829 if (known_eq (nunits, gather_off_nunits)) 2830 modifier = NONE; 2831 else if (known_eq (nunits * 2, gather_off_nunits)) 2832 { 2833 modifier = WIDEN; 2834 2835 /* Currently widening gathers and scatters are only supported for 2836 fixed-length vectors. */ 2837 int count = gather_off_nunits.to_constant (); 2838 vec_perm_builder sel (count, count, 1); 2839 for (int i = 0; i < count; ++i) 2840 sel.quick_push (i | (count / 2)); 2841 2842 vec_perm_indices indices (sel, 1, count); 2843 perm_mask = vect_gen_perm_mask_checked (gs_info->offset_vectype, 2844 indices); 2845 } 2846 else if (known_eq (nunits, gather_off_nunits * 2)) 2847 { 2848 modifier = NARROW; 2849 2850 /* Currently narrowing gathers and scatters are only supported for 2851 fixed-length vectors. */ 2852 int count = nunits.to_constant (); 2853 vec_perm_builder sel (count, count, 1); 2854 sel.quick_grow (count); 2855 for (int i = 0; i < count; ++i) 2856 sel[i] = i < count / 2 ? i : i + count / 2; 2857 vec_perm_indices indices (sel, 2, count); 2858 perm_mask = vect_gen_perm_mask_checked (vectype, indices); 2859 2860 ncopies *= 2; 2861 2862 if (mask && VECTOR_TYPE_P (real_masktype)) 2863 { 2864 for (int i = 0; i < count; ++i) 2865 sel[i] = i | (count / 2); 2866 indices.new_vector (sel, 2, count); 2867 mask_perm_mask = vect_gen_perm_mask_checked (masktype, indices); 2868 } 2869 else if (mask) 2870 mask_halftype = truth_type_for (gs_info->offset_vectype); 2871 } 2872 else 2873 gcc_unreachable (); 2874 2875 tree scalar_dest = gimple_get_lhs (stmt_info->stmt); 2876 tree vec_dest = vect_create_destination_var (scalar_dest, vectype); 2877 2878 tree ptr = fold_convert (ptrtype, gs_info->base); 2879 if (!is_gimple_min_invariant (ptr)) 2880 { 2881 gimple_seq seq; 2882 ptr = force_gimple_operand (ptr, &seq, true, NULL_TREE); 2883 basic_block new_bb = gsi_insert_seq_on_edge_immediate (pe, seq); 2884 gcc_assert (!new_bb); 2885 } 2886 2887 tree scale = build_int_cst (scaletype, gs_info->scale); 2888 2889 tree vec_oprnd0 = NULL_TREE; 2890 tree vec_mask = NULL_TREE; 2891 tree src_op = NULL_TREE; 2892 tree mask_op = NULL_TREE; 2893 tree prev_res = NULL_TREE; 2894 2895 if (!mask) 2896 { 2897 src_op = vect_build_zero_merge_argument (vinfo, stmt_info, rettype); 2898 mask_op = vect_build_all_ones_mask (vinfo, stmt_info, masktype); 2899 } 2900 2901 auto_vec<tree> vec_oprnds0; 2902 auto_vec<tree> vec_masks; 2903 vect_get_vec_defs_for_operand (vinfo, stmt_info, 2904 modifier == WIDEN ? ncopies / 2 : ncopies, 2905 gs_info->offset, &vec_oprnds0); 2906 if (mask) 2907 vect_get_vec_defs_for_operand (vinfo, stmt_info, 2908 modifier == NARROW ? ncopies / 2 : ncopies, 2909 mask, &vec_masks, masktype); 2910 for (int j = 0; j < ncopies; ++j) 2911 { 2912 tree op, var; 2913 if (modifier == WIDEN && (j & 1)) 2914 op = permute_vec_elements (vinfo, vec_oprnd0, vec_oprnd0, 2915 perm_mask, stmt_info, gsi); 2916 else 2917 op = vec_oprnd0 = vec_oprnds0[modifier == WIDEN ? j / 2 : j]; 2918 2919 if (!useless_type_conversion_p (idxtype, TREE_TYPE (op))) 2920 { 2921 gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)), 2922 TYPE_VECTOR_SUBPARTS (idxtype))); 2923 var = vect_get_new_ssa_name (idxtype, vect_simple_var); 2924 op = build1 (VIEW_CONVERT_EXPR, idxtype, op); 2925 gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op); 2926 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 2927 op = var; 2928 } 2929 2930 if (mask) 2931 { 2932 if (mask_perm_mask && (j & 1)) 2933 mask_op = permute_vec_elements (vinfo, mask_op, mask_op, 2934 mask_perm_mask, stmt_info, gsi); 2935 else 2936 { 2937 if (modifier == NARROW) 2938 { 2939 if ((j & 1) == 0) 2940 vec_mask = vec_masks[j / 2]; 2941 } 2942 else 2943 vec_mask = vec_masks[j]; 2944 2945 mask_op = vec_mask; 2946 if (!useless_type_conversion_p (masktype, TREE_TYPE (vec_mask))) 2947 { 2948 poly_uint64 sub1 = TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask_op)); 2949 poly_uint64 sub2 = TYPE_VECTOR_SUBPARTS (masktype); 2950 gcc_assert (known_eq (sub1, sub2)); 2951 var = vect_get_new_ssa_name (masktype, vect_simple_var); 2952 mask_op = build1 (VIEW_CONVERT_EXPR, masktype, mask_op); 2953 gassign *new_stmt 2954 = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_op); 2955 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 2956 mask_op = var; 2957 } 2958 } 2959 if (modifier == NARROW && !VECTOR_TYPE_P (real_masktype)) 2960 { 2961 var = vect_get_new_ssa_name (mask_halftype, vect_simple_var); 2962 gassign *new_stmt 2963 = gimple_build_assign (var, (j & 1) ? VEC_UNPACK_HI_EXPR 2964 : VEC_UNPACK_LO_EXPR, 2965 mask_op); 2966 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 2967 mask_op = var; 2968 } 2969 src_op = mask_op; 2970 } 2971 2972 tree mask_arg = mask_op; 2973 if (masktype != real_masktype) 2974 { 2975 tree utype, optype = TREE_TYPE (mask_op); 2976 if (VECTOR_TYPE_P (real_masktype) 2977 || TYPE_MODE (real_masktype) == TYPE_MODE (optype)) 2978 utype = real_masktype; 2979 else 2980 utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1); 2981 var = vect_get_new_ssa_name (utype, vect_scalar_var); 2982 mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask_op); 2983 gassign *new_stmt 2984 = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg); 2985 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 2986 mask_arg = var; 2987 if (!useless_type_conversion_p (real_masktype, utype)) 2988 { 2989 gcc_assert (TYPE_PRECISION (utype) 2990 <= TYPE_PRECISION (real_masktype)); 2991 var = vect_get_new_ssa_name (real_masktype, vect_scalar_var); 2992 new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg); 2993 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 2994 mask_arg = var; 2995 } 2996 src_op = build_zero_cst (srctype); 2997 } 2998 gimple *new_stmt = gimple_build_call (gs_info->decl, 5, src_op, ptr, op, 2999 mask_arg, scale); 3000 3001 if (!useless_type_conversion_p (vectype, rettype)) 3002 { 3003 gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (vectype), 3004 TYPE_VECTOR_SUBPARTS (rettype))); 3005 op = vect_get_new_ssa_name (rettype, vect_simple_var); 3006 gimple_call_set_lhs (new_stmt, op); 3007 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 3008 var = make_ssa_name (vec_dest); 3009 op = build1 (VIEW_CONVERT_EXPR, vectype, op); 3010 new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op); 3011 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 3012 } 3013 else 3014 { 3015 var = make_ssa_name (vec_dest, new_stmt); 3016 gimple_call_set_lhs (new_stmt, var); 3017 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 3018 } 3019 3020 if (modifier == NARROW) 3021 { 3022 if ((j & 1) == 0) 3023 { 3024 prev_res = var; 3025 continue; 3026 } 3027 var = permute_vec_elements (vinfo, prev_res, var, perm_mask, 3028 stmt_info, gsi); 3029 new_stmt = SSA_NAME_DEF_STMT (var); 3030 } 3031 3032 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 3033 } 3034 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 3035 } 3036 3037 /* Prepare the base and offset in GS_INFO for vectorization. 3038 Set *DATAREF_PTR to the loop-invariant base address and *VEC_OFFSET 3039 to the vectorized offset argument for the first copy of STMT_INFO. 3040 STMT_INFO is the statement described by GS_INFO and LOOP is the 3041 containing loop. */ 3042 3043 static void 3044 vect_get_gather_scatter_ops (loop_vec_info loop_vinfo, 3045 class loop *loop, stmt_vec_info stmt_info, 3046 slp_tree slp_node, gather_scatter_info *gs_info, 3047 tree *dataref_ptr, vec<tree> *vec_offset) 3048 { 3049 gimple_seq stmts = NULL; 3050 *dataref_ptr = force_gimple_operand (gs_info->base, &stmts, true, NULL_TREE); 3051 if (stmts != NULL) 3052 { 3053 basic_block new_bb; 3054 edge pe = loop_preheader_edge (loop); 3055 new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts); 3056 gcc_assert (!new_bb); 3057 } 3058 if (slp_node) 3059 vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_offset); 3060 else 3061 { 3062 unsigned ncopies 3063 = vect_get_num_copies (loop_vinfo, gs_info->offset_vectype); 3064 vect_get_vec_defs_for_operand (loop_vinfo, stmt_info, ncopies, 3065 gs_info->offset, vec_offset, 3066 gs_info->offset_vectype); 3067 } 3068 } 3069 3070 /* Prepare to implement a grouped or strided load or store using 3071 the gather load or scatter store operation described by GS_INFO. 3072 STMT_INFO is the load or store statement. 3073 3074 Set *DATAREF_BUMP to the amount that should be added to the base 3075 address after each copy of the vectorized statement. Set *VEC_OFFSET 3076 to an invariant offset vector in which element I has the value 3077 I * DR_STEP / SCALE. */ 3078 3079 static void 3080 vect_get_strided_load_store_ops (stmt_vec_info stmt_info, 3081 loop_vec_info loop_vinfo, 3082 gather_scatter_info *gs_info, 3083 tree *dataref_bump, tree *vec_offset) 3084 { 3085 struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info); 3086 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 3087 3088 tree bump = size_binop (MULT_EXPR, 3089 fold_convert (sizetype, unshare_expr (DR_STEP (dr))), 3090 size_int (TYPE_VECTOR_SUBPARTS (vectype))); 3091 *dataref_bump = cse_and_gimplify_to_preheader (loop_vinfo, bump); 3092 3093 /* The offset given in GS_INFO can have pointer type, so use the element 3094 type of the vector instead. */ 3095 tree offset_type = TREE_TYPE (gs_info->offset_vectype); 3096 3097 /* Calculate X = DR_STEP / SCALE and convert it to the appropriate type. */ 3098 tree step = size_binop (EXACT_DIV_EXPR, unshare_expr (DR_STEP (dr)), 3099 ssize_int (gs_info->scale)); 3100 step = fold_convert (offset_type, step); 3101 3102 /* Create {0, X, X*2, X*3, ...}. */ 3103 tree offset = fold_build2 (VEC_SERIES_EXPR, gs_info->offset_vectype, 3104 build_zero_cst (offset_type), step); 3105 *vec_offset = cse_and_gimplify_to_preheader (loop_vinfo, offset); 3106 } 3107 3108 /* Return the amount that should be added to a vector pointer to move 3109 to the next or previous copy of AGGR_TYPE. DR_INFO is the data reference 3110 being vectorized and MEMORY_ACCESS_TYPE describes the type of 3111 vectorization. */ 3112 3113 static tree 3114 vect_get_data_ptr_increment (vec_info *vinfo, 3115 dr_vec_info *dr_info, tree aggr_type, 3116 vect_memory_access_type memory_access_type) 3117 { 3118 if (memory_access_type == VMAT_INVARIANT) 3119 return size_zero_node; 3120 3121 tree iv_step = TYPE_SIZE_UNIT (aggr_type); 3122 tree step = vect_dr_behavior (vinfo, dr_info)->step; 3123 if (tree_int_cst_sgn (step) == -1) 3124 iv_step = fold_build1 (NEGATE_EXPR, TREE_TYPE (iv_step), iv_step); 3125 return iv_step; 3126 } 3127 3128 /* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64,128}. */ 3129 3130 static bool 3131 vectorizable_bswap (vec_info *vinfo, 3132 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 3133 gimple **vec_stmt, slp_tree slp_node, 3134 slp_tree *slp_op, 3135 tree vectype_in, stmt_vector_for_cost *cost_vec) 3136 { 3137 tree op, vectype; 3138 gcall *stmt = as_a <gcall *> (stmt_info->stmt); 3139 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 3140 unsigned ncopies; 3141 3142 op = gimple_call_arg (stmt, 0); 3143 vectype = STMT_VINFO_VECTYPE (stmt_info); 3144 poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); 3145 3146 /* Multiple types in SLP are handled by creating the appropriate number of 3147 vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in 3148 case of SLP. */ 3149 if (slp_node) 3150 ncopies = 1; 3151 else 3152 ncopies = vect_get_num_copies (loop_vinfo, vectype); 3153 3154 gcc_assert (ncopies >= 1); 3155 3156 tree char_vectype = get_same_sized_vectype (char_type_node, vectype_in); 3157 if (! char_vectype) 3158 return false; 3159 3160 poly_uint64 num_bytes = TYPE_VECTOR_SUBPARTS (char_vectype); 3161 unsigned word_bytes; 3162 if (!constant_multiple_p (num_bytes, nunits, &word_bytes)) 3163 return false; 3164 3165 /* The encoding uses one stepped pattern for each byte in the word. */ 3166 vec_perm_builder elts (num_bytes, word_bytes, 3); 3167 for (unsigned i = 0; i < 3; ++i) 3168 for (unsigned j = 0; j < word_bytes; ++j) 3169 elts.quick_push ((i + 1) * word_bytes - j - 1); 3170 3171 vec_perm_indices indices (elts, 1, num_bytes); 3172 if (!can_vec_perm_const_p (TYPE_MODE (char_vectype), indices)) 3173 return false; 3174 3175 if (! vec_stmt) 3176 { 3177 if (slp_node 3178 && !vect_maybe_update_slp_op_vectype (slp_op[0], vectype_in)) 3179 { 3180 if (dump_enabled_p ()) 3181 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3182 "incompatible vector types for invariants\n"); 3183 return false; 3184 } 3185 3186 STMT_VINFO_TYPE (stmt_info) = call_vec_info_type; 3187 DUMP_VECT_SCOPE ("vectorizable_bswap"); 3188 record_stmt_cost (cost_vec, 3189 1, vector_stmt, stmt_info, 0, vect_prologue); 3190 record_stmt_cost (cost_vec, 3191 slp_node 3192 ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies, 3193 vec_perm, stmt_info, 0, vect_body); 3194 return true; 3195 } 3196 3197 tree bswap_vconst = vec_perm_indices_to_tree (char_vectype, indices); 3198 3199 /* Transform. */ 3200 vec<tree> vec_oprnds = vNULL; 3201 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, 3202 op, &vec_oprnds); 3203 /* Arguments are ready. create the new vector stmt. */ 3204 unsigned i; 3205 tree vop; 3206 FOR_EACH_VEC_ELT (vec_oprnds, i, vop) 3207 { 3208 gimple *new_stmt; 3209 tree tem = make_ssa_name (char_vectype); 3210 new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR, 3211 char_vectype, vop)); 3212 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 3213 tree tem2 = make_ssa_name (char_vectype); 3214 new_stmt = gimple_build_assign (tem2, VEC_PERM_EXPR, 3215 tem, tem, bswap_vconst); 3216 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 3217 tem = make_ssa_name (vectype); 3218 new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR, 3219 vectype, tem2)); 3220 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 3221 if (slp_node) 3222 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 3223 else 3224 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 3225 } 3226 3227 if (!slp_node) 3228 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 3229 3230 vec_oprnds.release (); 3231 return true; 3232 } 3233 3234 /* Return true if vector types VECTYPE_IN and VECTYPE_OUT have 3235 integer elements and if we can narrow VECTYPE_IN to VECTYPE_OUT 3236 in a single step. On success, store the binary pack code in 3237 *CONVERT_CODE. */ 3238 3239 static bool 3240 simple_integer_narrowing (tree vectype_out, tree vectype_in, 3241 tree_code *convert_code) 3242 { 3243 if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype_out)) 3244 || !INTEGRAL_TYPE_P (TREE_TYPE (vectype_in))) 3245 return false; 3246 3247 tree_code code; 3248 int multi_step_cvt = 0; 3249 auto_vec <tree, 8> interm_types; 3250 if (!supportable_narrowing_operation (NOP_EXPR, vectype_out, vectype_in, 3251 &code, &multi_step_cvt, &interm_types) 3252 || multi_step_cvt) 3253 return false; 3254 3255 *convert_code = code; 3256 return true; 3257 } 3258 3259 /* Function vectorizable_call. 3260 3261 Check if STMT_INFO performs a function call that can be vectorized. 3262 If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized 3263 stmt to replace it, put it in VEC_STMT, and insert it at GSI. 3264 Return true if STMT_INFO is vectorizable in this way. */ 3265 3266 static bool 3267 vectorizable_call (vec_info *vinfo, 3268 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 3269 gimple **vec_stmt, slp_tree slp_node, 3270 stmt_vector_for_cost *cost_vec) 3271 { 3272 gcall *stmt; 3273 tree vec_dest; 3274 tree scalar_dest; 3275 tree op; 3276 tree vec_oprnd0 = NULL_TREE, vec_oprnd1 = NULL_TREE; 3277 tree vectype_out, vectype_in; 3278 poly_uint64 nunits_in; 3279 poly_uint64 nunits_out; 3280 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 3281 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 3282 tree fndecl, new_temp, rhs_type; 3283 enum vect_def_type dt[4] 3284 = { vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type, 3285 vect_unknown_def_type }; 3286 tree vectypes[ARRAY_SIZE (dt)] = {}; 3287 slp_tree slp_op[ARRAY_SIZE (dt)] = {}; 3288 int ndts = ARRAY_SIZE (dt); 3289 int ncopies, j; 3290 auto_vec<tree, 8> vargs; 3291 enum { NARROW, NONE, WIDEN } modifier; 3292 size_t i, nargs; 3293 tree lhs; 3294 3295 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 3296 return false; 3297 3298 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def 3299 && ! vec_stmt) 3300 return false; 3301 3302 /* Is STMT_INFO a vectorizable call? */ 3303 stmt = dyn_cast <gcall *> (stmt_info->stmt); 3304 if (!stmt) 3305 return false; 3306 3307 if (gimple_call_internal_p (stmt) 3308 && (internal_load_fn_p (gimple_call_internal_fn (stmt)) 3309 || internal_store_fn_p (gimple_call_internal_fn (stmt)))) 3310 /* Handled by vectorizable_load and vectorizable_store. */ 3311 return false; 3312 3313 if (gimple_call_lhs (stmt) == NULL_TREE 3314 || TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME) 3315 return false; 3316 3317 gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt)); 3318 3319 vectype_out = STMT_VINFO_VECTYPE (stmt_info); 3320 3321 /* Process function arguments. */ 3322 rhs_type = NULL_TREE; 3323 vectype_in = NULL_TREE; 3324 nargs = gimple_call_num_args (stmt); 3325 3326 /* Bail out if the function has more than four arguments, we do not have 3327 interesting builtin functions to vectorize with more than two arguments 3328 except for fma. No arguments is also not good. */ 3329 if (nargs == 0 || nargs > 4) 3330 return false; 3331 3332 /* Ignore the arguments of IFN_GOMP_SIMD_LANE, they are magic. */ 3333 combined_fn cfn = gimple_call_combined_fn (stmt); 3334 if (cfn == CFN_GOMP_SIMD_LANE) 3335 { 3336 nargs = 0; 3337 rhs_type = unsigned_type_node; 3338 } 3339 3340 int mask_opno = -1; 3341 if (internal_fn_p (cfn)) 3342 mask_opno = internal_fn_mask_index (as_internal_fn (cfn)); 3343 3344 for (i = 0; i < nargs; i++) 3345 { 3346 if ((int) i == mask_opno) 3347 { 3348 if (!vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_opno, 3349 &op, &slp_op[i], &dt[i], &vectypes[i])) 3350 return false; 3351 continue; 3352 } 3353 3354 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 3355 i, &op, &slp_op[i], &dt[i], &vectypes[i])) 3356 { 3357 if (dump_enabled_p ()) 3358 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3359 "use not simple.\n"); 3360 return false; 3361 } 3362 3363 /* We can only handle calls with arguments of the same type. */ 3364 if (rhs_type 3365 && !types_compatible_p (rhs_type, TREE_TYPE (op))) 3366 { 3367 if (dump_enabled_p ()) 3368 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3369 "argument types differ.\n"); 3370 return false; 3371 } 3372 if (!rhs_type) 3373 rhs_type = TREE_TYPE (op); 3374 3375 if (!vectype_in) 3376 vectype_in = vectypes[i]; 3377 else if (vectypes[i] 3378 && !types_compatible_p (vectypes[i], vectype_in)) 3379 { 3380 if (dump_enabled_p ()) 3381 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3382 "argument vector types differ.\n"); 3383 return false; 3384 } 3385 } 3386 /* If all arguments are external or constant defs, infer the vector type 3387 from the scalar type. */ 3388 if (!vectype_in) 3389 vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node); 3390 if (vec_stmt) 3391 gcc_assert (vectype_in); 3392 if (!vectype_in) 3393 { 3394 if (dump_enabled_p ()) 3395 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3396 "no vectype for scalar type %T\n", rhs_type); 3397 3398 return false; 3399 } 3400 /* FORNOW: we don't yet support mixtures of vector sizes for calls, 3401 just mixtures of nunits. E.g. DI->SI versions of __builtin_ctz* 3402 are traditionally vectorized as two VnDI->VnDI IFN_CTZs followed 3403 by a pack of the two vectors into an SI vector. We would need 3404 separate code to handle direct VnDI->VnSI IFN_CTZs. */ 3405 if (TYPE_SIZE (vectype_in) != TYPE_SIZE (vectype_out)) 3406 { 3407 if (dump_enabled_p ()) 3408 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3409 "mismatched vector sizes %T and %T\n", 3410 vectype_in, vectype_out); 3411 return false; 3412 } 3413 3414 if (VECTOR_BOOLEAN_TYPE_P (vectype_out) 3415 != VECTOR_BOOLEAN_TYPE_P (vectype_in)) 3416 { 3417 if (dump_enabled_p ()) 3418 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3419 "mixed mask and nonmask vector types\n"); 3420 return false; 3421 } 3422 3423 if (vect_emulated_vector_p (vectype_in) || vect_emulated_vector_p (vectype_out)) 3424 { 3425 if (dump_enabled_p ()) 3426 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3427 "use emulated vector type for call\n"); 3428 return false; 3429 } 3430 3431 /* FORNOW */ 3432 nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in); 3433 nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out); 3434 if (known_eq (nunits_in * 2, nunits_out)) 3435 modifier = NARROW; 3436 else if (known_eq (nunits_out, nunits_in)) 3437 modifier = NONE; 3438 else if (known_eq (nunits_out * 2, nunits_in)) 3439 modifier = WIDEN; 3440 else 3441 return false; 3442 3443 /* We only handle functions that do not read or clobber memory. */ 3444 if (gimple_vuse (stmt)) 3445 { 3446 if (dump_enabled_p ()) 3447 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3448 "function reads from or writes to memory.\n"); 3449 return false; 3450 } 3451 3452 /* For now, we only vectorize functions if a target specific builtin 3453 is available. TODO -- in some cases, it might be profitable to 3454 insert the calls for pieces of the vector, in order to be able 3455 to vectorize other operations in the loop. */ 3456 fndecl = NULL_TREE; 3457 internal_fn ifn = IFN_LAST; 3458 tree callee = gimple_call_fndecl (stmt); 3459 3460 /* First try using an internal function. */ 3461 tree_code convert_code = ERROR_MARK; 3462 if (cfn != CFN_LAST 3463 && (modifier == NONE 3464 || (modifier == NARROW 3465 && simple_integer_narrowing (vectype_out, vectype_in, 3466 &convert_code)))) 3467 ifn = vectorizable_internal_function (cfn, callee, vectype_out, 3468 vectype_in); 3469 3470 /* If that fails, try asking for a target-specific built-in function. */ 3471 if (ifn == IFN_LAST) 3472 { 3473 if (cfn != CFN_LAST) 3474 fndecl = targetm.vectorize.builtin_vectorized_function 3475 (cfn, vectype_out, vectype_in); 3476 else if (callee && fndecl_built_in_p (callee, BUILT_IN_MD)) 3477 fndecl = targetm.vectorize.builtin_md_vectorized_function 3478 (callee, vectype_out, vectype_in); 3479 } 3480 3481 if (ifn == IFN_LAST && !fndecl) 3482 { 3483 if (cfn == CFN_GOMP_SIMD_LANE 3484 && !slp_node 3485 && loop_vinfo 3486 && LOOP_VINFO_LOOP (loop_vinfo)->simduid 3487 && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME 3488 && LOOP_VINFO_LOOP (loop_vinfo)->simduid 3489 == SSA_NAME_VAR (gimple_call_arg (stmt, 0))) 3490 { 3491 /* We can handle IFN_GOMP_SIMD_LANE by returning a 3492 { 0, 1, 2, ... vf - 1 } vector. */ 3493 gcc_assert (nargs == 0); 3494 } 3495 else if (modifier == NONE 3496 && (gimple_call_builtin_p (stmt, BUILT_IN_BSWAP16) 3497 || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP32) 3498 || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64) 3499 || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP128))) 3500 return vectorizable_bswap (vinfo, stmt_info, gsi, vec_stmt, slp_node, 3501 slp_op, vectype_in, cost_vec); 3502 else 3503 { 3504 if (dump_enabled_p ()) 3505 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3506 "function is not vectorizable.\n"); 3507 return false; 3508 } 3509 } 3510 3511 if (slp_node) 3512 ncopies = 1; 3513 else if (modifier == NARROW && ifn == IFN_LAST) 3514 ncopies = vect_get_num_copies (loop_vinfo, vectype_out); 3515 else 3516 ncopies = vect_get_num_copies (loop_vinfo, vectype_in); 3517 3518 /* Sanity check: make sure that at least one copy of the vectorized stmt 3519 needs to be generated. */ 3520 gcc_assert (ncopies >= 1); 3521 3522 int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info); 3523 internal_fn cond_fn = get_conditional_internal_fn (ifn); 3524 vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL); 3525 if (!vec_stmt) /* transformation not required. */ 3526 { 3527 if (slp_node) 3528 for (i = 0; i < nargs; ++i) 3529 if (!vect_maybe_update_slp_op_vectype (slp_op[i], 3530 vectypes[i] 3531 ? vectypes[i] : vectype_in)) 3532 { 3533 if (dump_enabled_p ()) 3534 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3535 "incompatible vector types for invariants\n"); 3536 return false; 3537 } 3538 STMT_VINFO_TYPE (stmt_info) = call_vec_info_type; 3539 DUMP_VECT_SCOPE ("vectorizable_call"); 3540 vect_model_simple_cost (vinfo, stmt_info, 3541 ncopies, dt, ndts, slp_node, cost_vec); 3542 if (ifn != IFN_LAST && modifier == NARROW && !slp_node) 3543 record_stmt_cost (cost_vec, ncopies / 2, 3544 vec_promote_demote, stmt_info, 0, vect_body); 3545 3546 if (loop_vinfo 3547 && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) 3548 && (reduc_idx >= 0 || mask_opno >= 0)) 3549 { 3550 if (reduc_idx >= 0 3551 && (cond_fn == IFN_LAST 3552 || !direct_internal_fn_supported_p (cond_fn, vectype_out, 3553 OPTIMIZE_FOR_SPEED))) 3554 { 3555 if (dump_enabled_p ()) 3556 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 3557 "can't use a fully-masked loop because no" 3558 " conditional operation is available.\n"); 3559 LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; 3560 } 3561 else 3562 { 3563 unsigned int nvectors 3564 = (slp_node 3565 ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) 3566 : ncopies); 3567 tree scalar_mask = NULL_TREE; 3568 if (mask_opno >= 0) 3569 scalar_mask = gimple_call_arg (stmt_info->stmt, mask_opno); 3570 vect_record_loop_mask (loop_vinfo, masks, nvectors, 3571 vectype_out, scalar_mask); 3572 } 3573 } 3574 return true; 3575 } 3576 3577 /* Transform. */ 3578 3579 if (dump_enabled_p ()) 3580 dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n"); 3581 3582 /* Handle def. */ 3583 scalar_dest = gimple_call_lhs (stmt); 3584 vec_dest = vect_create_destination_var (scalar_dest, vectype_out); 3585 3586 bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo); 3587 unsigned int vect_nargs = nargs; 3588 if (masked_loop_p && reduc_idx >= 0) 3589 { 3590 ifn = cond_fn; 3591 vect_nargs += 2; 3592 } 3593 3594 if (modifier == NONE || ifn != IFN_LAST) 3595 { 3596 tree prev_res = NULL_TREE; 3597 vargs.safe_grow (vect_nargs, true); 3598 auto_vec<vec<tree> > vec_defs (nargs); 3599 for (j = 0; j < ncopies; ++j) 3600 { 3601 /* Build argument list for the vectorized call. */ 3602 if (slp_node) 3603 { 3604 vec<tree> vec_oprnds0; 3605 3606 vect_get_slp_defs (vinfo, slp_node, &vec_defs); 3607 vec_oprnds0 = vec_defs[0]; 3608 3609 /* Arguments are ready. Create the new vector stmt. */ 3610 FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_oprnd0) 3611 { 3612 int varg = 0; 3613 if (masked_loop_p && reduc_idx >= 0) 3614 { 3615 unsigned int vec_num = vec_oprnds0.length (); 3616 /* Always true for SLP. */ 3617 gcc_assert (ncopies == 1); 3618 vargs[varg++] = vect_get_loop_mask (gsi, masks, vec_num, 3619 vectype_out, i); 3620 } 3621 size_t k; 3622 for (k = 0; k < nargs; k++) 3623 { 3624 vec<tree> vec_oprndsk = vec_defs[k]; 3625 vargs[varg++] = vec_oprndsk[i]; 3626 } 3627 if (masked_loop_p && reduc_idx >= 0) 3628 vargs[varg++] = vargs[reduc_idx + 1]; 3629 gimple *new_stmt; 3630 if (modifier == NARROW) 3631 { 3632 /* We don't define any narrowing conditional functions 3633 at present. */ 3634 gcc_assert (mask_opno < 0); 3635 tree half_res = make_ssa_name (vectype_in); 3636 gcall *call 3637 = gimple_build_call_internal_vec (ifn, vargs); 3638 gimple_call_set_lhs (call, half_res); 3639 gimple_call_set_nothrow (call, true); 3640 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 3641 if ((i & 1) == 0) 3642 { 3643 prev_res = half_res; 3644 continue; 3645 } 3646 new_temp = make_ssa_name (vec_dest); 3647 new_stmt = gimple_build_assign (new_temp, convert_code, 3648 prev_res, half_res); 3649 vect_finish_stmt_generation (vinfo, stmt_info, 3650 new_stmt, gsi); 3651 } 3652 else 3653 { 3654 if (mask_opno >= 0 && masked_loop_p) 3655 { 3656 unsigned int vec_num = vec_oprnds0.length (); 3657 /* Always true for SLP. */ 3658 gcc_assert (ncopies == 1); 3659 tree mask = vect_get_loop_mask (gsi, masks, vec_num, 3660 vectype_out, i); 3661 vargs[mask_opno] = prepare_vec_mask 3662 (loop_vinfo, TREE_TYPE (mask), mask, 3663 vargs[mask_opno], gsi); 3664 } 3665 3666 gcall *call; 3667 if (ifn != IFN_LAST) 3668 call = gimple_build_call_internal_vec (ifn, vargs); 3669 else 3670 call = gimple_build_call_vec (fndecl, vargs); 3671 new_temp = make_ssa_name (vec_dest, call); 3672 gimple_call_set_lhs (call, new_temp); 3673 gimple_call_set_nothrow (call, true); 3674 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 3675 new_stmt = call; 3676 } 3677 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 3678 } 3679 continue; 3680 } 3681 3682 int varg = 0; 3683 if (masked_loop_p && reduc_idx >= 0) 3684 vargs[varg++] = vect_get_loop_mask (gsi, masks, ncopies, 3685 vectype_out, j); 3686 for (i = 0; i < nargs; i++) 3687 { 3688 op = gimple_call_arg (stmt, i); 3689 if (j == 0) 3690 { 3691 vec_defs.quick_push (vNULL); 3692 vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, 3693 op, &vec_defs[i], 3694 vectypes[i]); 3695 } 3696 vargs[varg++] = vec_defs[i][j]; 3697 } 3698 if (masked_loop_p && reduc_idx >= 0) 3699 vargs[varg++] = vargs[reduc_idx + 1]; 3700 3701 if (mask_opno >= 0 && masked_loop_p) 3702 { 3703 tree mask = vect_get_loop_mask (gsi, masks, ncopies, 3704 vectype_out, j); 3705 vargs[mask_opno] 3706 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask, 3707 vargs[mask_opno], gsi); 3708 } 3709 3710 gimple *new_stmt; 3711 if (cfn == CFN_GOMP_SIMD_LANE) 3712 { 3713 tree cst = build_index_vector (vectype_out, j * nunits_out, 1); 3714 tree new_var 3715 = vect_get_new_ssa_name (vectype_out, vect_simple_var, "cst_"); 3716 gimple *init_stmt = gimple_build_assign (new_var, cst); 3717 vect_init_vector_1 (vinfo, stmt_info, init_stmt, NULL); 3718 new_temp = make_ssa_name (vec_dest); 3719 new_stmt = gimple_build_assign (new_temp, new_var); 3720 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 3721 } 3722 else if (modifier == NARROW) 3723 { 3724 /* We don't define any narrowing conditional functions at 3725 present. */ 3726 gcc_assert (mask_opno < 0); 3727 tree half_res = make_ssa_name (vectype_in); 3728 gcall *call = gimple_build_call_internal_vec (ifn, vargs); 3729 gimple_call_set_lhs (call, half_res); 3730 gimple_call_set_nothrow (call, true); 3731 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 3732 if ((j & 1) == 0) 3733 { 3734 prev_res = half_res; 3735 continue; 3736 } 3737 new_temp = make_ssa_name (vec_dest); 3738 new_stmt = gimple_build_assign (new_temp, convert_code, 3739 prev_res, half_res); 3740 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 3741 } 3742 else 3743 { 3744 gcall *call; 3745 if (ifn != IFN_LAST) 3746 call = gimple_build_call_internal_vec (ifn, vargs); 3747 else 3748 call = gimple_build_call_vec (fndecl, vargs); 3749 new_temp = make_ssa_name (vec_dest, call); 3750 gimple_call_set_lhs (call, new_temp); 3751 gimple_call_set_nothrow (call, true); 3752 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 3753 new_stmt = call; 3754 } 3755 3756 if (j == (modifier == NARROW ? 1 : 0)) 3757 *vec_stmt = new_stmt; 3758 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 3759 } 3760 for (i = 0; i < nargs; i++) 3761 { 3762 vec<tree> vec_oprndsi = vec_defs[i]; 3763 vec_oprndsi.release (); 3764 } 3765 } 3766 else if (modifier == NARROW) 3767 { 3768 auto_vec<vec<tree> > vec_defs (nargs); 3769 /* We don't define any narrowing conditional functions at present. */ 3770 gcc_assert (mask_opno < 0); 3771 for (j = 0; j < ncopies; ++j) 3772 { 3773 /* Build argument list for the vectorized call. */ 3774 if (j == 0) 3775 vargs.create (nargs * 2); 3776 else 3777 vargs.truncate (0); 3778 3779 if (slp_node) 3780 { 3781 vec<tree> vec_oprnds0; 3782 3783 vect_get_slp_defs (vinfo, slp_node, &vec_defs); 3784 vec_oprnds0 = vec_defs[0]; 3785 3786 /* Arguments are ready. Create the new vector stmt. */ 3787 for (i = 0; vec_oprnds0.iterate (i, &vec_oprnd0); i += 2) 3788 { 3789 size_t k; 3790 vargs.truncate (0); 3791 for (k = 0; k < nargs; k++) 3792 { 3793 vec<tree> vec_oprndsk = vec_defs[k]; 3794 vargs.quick_push (vec_oprndsk[i]); 3795 vargs.quick_push (vec_oprndsk[i + 1]); 3796 } 3797 gcall *call; 3798 if (ifn != IFN_LAST) 3799 call = gimple_build_call_internal_vec (ifn, vargs); 3800 else 3801 call = gimple_build_call_vec (fndecl, vargs); 3802 new_temp = make_ssa_name (vec_dest, call); 3803 gimple_call_set_lhs (call, new_temp); 3804 gimple_call_set_nothrow (call, true); 3805 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 3806 SLP_TREE_VEC_STMTS (slp_node).quick_push (call); 3807 } 3808 continue; 3809 } 3810 3811 for (i = 0; i < nargs; i++) 3812 { 3813 op = gimple_call_arg (stmt, i); 3814 if (j == 0) 3815 { 3816 vec_defs.quick_push (vNULL); 3817 vect_get_vec_defs_for_operand (vinfo, stmt_info, 2 * ncopies, 3818 op, &vec_defs[i], vectypes[i]); 3819 } 3820 vec_oprnd0 = vec_defs[i][2*j]; 3821 vec_oprnd1 = vec_defs[i][2*j+1]; 3822 3823 vargs.quick_push (vec_oprnd0); 3824 vargs.quick_push (vec_oprnd1); 3825 } 3826 3827 gcall *new_stmt = gimple_build_call_vec (fndecl, vargs); 3828 new_temp = make_ssa_name (vec_dest, new_stmt); 3829 gimple_call_set_lhs (new_stmt, new_temp); 3830 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 3831 3832 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 3833 } 3834 3835 if (!slp_node) 3836 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 3837 3838 for (i = 0; i < nargs; i++) 3839 { 3840 vec<tree> vec_oprndsi = vec_defs[i]; 3841 vec_oprndsi.release (); 3842 } 3843 } 3844 else 3845 /* No current target implements this case. */ 3846 return false; 3847 3848 vargs.release (); 3849 3850 /* The call in STMT might prevent it from being removed in dce. 3851 We however cannot remove it here, due to the way the ssa name 3852 it defines is mapped to the new definition. So just replace 3853 rhs of the statement with something harmless. */ 3854 3855 if (slp_node) 3856 return true; 3857 3858 stmt_info = vect_orig_stmt (stmt_info); 3859 lhs = gimple_get_lhs (stmt_info->stmt); 3860 3861 gassign *new_stmt 3862 = gimple_build_assign (lhs, build_zero_cst (TREE_TYPE (lhs))); 3863 vinfo->replace_stmt (gsi, stmt_info, new_stmt); 3864 3865 return true; 3866 } 3867 3868 3869 struct simd_call_arg_info 3870 { 3871 tree vectype; 3872 tree op; 3873 HOST_WIDE_INT linear_step; 3874 enum vect_def_type dt; 3875 unsigned int align; 3876 bool simd_lane_linear; 3877 }; 3878 3879 /* Helper function of vectorizable_simd_clone_call. If OP, an SSA_NAME, 3880 is linear within simd lane (but not within whole loop), note it in 3881 *ARGINFO. */ 3882 3883 static void 3884 vect_simd_lane_linear (tree op, class loop *loop, 3885 struct simd_call_arg_info *arginfo) 3886 { 3887 gimple *def_stmt = SSA_NAME_DEF_STMT (op); 3888 3889 if (!is_gimple_assign (def_stmt) 3890 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR 3891 || !is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt))) 3892 return; 3893 3894 tree base = gimple_assign_rhs1 (def_stmt); 3895 HOST_WIDE_INT linear_step = 0; 3896 tree v = gimple_assign_rhs2 (def_stmt); 3897 while (TREE_CODE (v) == SSA_NAME) 3898 { 3899 tree t; 3900 def_stmt = SSA_NAME_DEF_STMT (v); 3901 if (is_gimple_assign (def_stmt)) 3902 switch (gimple_assign_rhs_code (def_stmt)) 3903 { 3904 case PLUS_EXPR: 3905 t = gimple_assign_rhs2 (def_stmt); 3906 if (linear_step || TREE_CODE (t) != INTEGER_CST) 3907 return; 3908 base = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, t); 3909 v = gimple_assign_rhs1 (def_stmt); 3910 continue; 3911 case MULT_EXPR: 3912 t = gimple_assign_rhs2 (def_stmt); 3913 if (linear_step || !tree_fits_shwi_p (t) || integer_zerop (t)) 3914 return; 3915 linear_step = tree_to_shwi (t); 3916 v = gimple_assign_rhs1 (def_stmt); 3917 continue; 3918 CASE_CONVERT: 3919 t = gimple_assign_rhs1 (def_stmt); 3920 if (TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE 3921 || (TYPE_PRECISION (TREE_TYPE (v)) 3922 < TYPE_PRECISION (TREE_TYPE (t)))) 3923 return; 3924 if (!linear_step) 3925 linear_step = 1; 3926 v = t; 3927 continue; 3928 default: 3929 return; 3930 } 3931 else if (gimple_call_internal_p (def_stmt, IFN_GOMP_SIMD_LANE) 3932 && loop->simduid 3933 && TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME 3934 && (SSA_NAME_VAR (gimple_call_arg (def_stmt, 0)) 3935 == loop->simduid)) 3936 { 3937 if (!linear_step) 3938 linear_step = 1; 3939 arginfo->linear_step = linear_step; 3940 arginfo->op = base; 3941 arginfo->simd_lane_linear = true; 3942 return; 3943 } 3944 } 3945 } 3946 3947 /* Return the number of elements in vector type VECTYPE, which is associated 3948 with a SIMD clone. At present these vectors always have a constant 3949 length. */ 3950 3951 static unsigned HOST_WIDE_INT 3952 simd_clone_subparts (tree vectype) 3953 { 3954 return TYPE_VECTOR_SUBPARTS (vectype).to_constant (); 3955 } 3956 3957 /* Function vectorizable_simd_clone_call. 3958 3959 Check if STMT_INFO performs a function call that can be vectorized 3960 by calling a simd clone of the function. 3961 If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized 3962 stmt to replace it, put it in VEC_STMT, and insert it at GSI. 3963 Return true if STMT_INFO is vectorizable in this way. */ 3964 3965 static bool 3966 vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info, 3967 gimple_stmt_iterator *gsi, 3968 gimple **vec_stmt, slp_tree slp_node, 3969 stmt_vector_for_cost *) 3970 { 3971 tree vec_dest; 3972 tree scalar_dest; 3973 tree op, type; 3974 tree vec_oprnd0 = NULL_TREE; 3975 tree vectype; 3976 poly_uint64 nunits; 3977 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 3978 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 3979 class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL; 3980 tree fndecl, new_temp; 3981 int ncopies, j; 3982 auto_vec<simd_call_arg_info> arginfo; 3983 vec<tree> vargs = vNULL; 3984 size_t i, nargs; 3985 tree lhs, rtype, ratype; 3986 vec<constructor_elt, va_gc> *ret_ctor_elts = NULL; 3987 3988 /* Is STMT a vectorizable call? */ 3989 gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt); 3990 if (!stmt) 3991 return false; 3992 3993 fndecl = gimple_call_fndecl (stmt); 3994 if (fndecl == NULL_TREE) 3995 return false; 3996 3997 struct cgraph_node *node = cgraph_node::get (fndecl); 3998 if (node == NULL || node->simd_clones == NULL) 3999 return false; 4000 4001 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 4002 return false; 4003 4004 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def 4005 && ! vec_stmt) 4006 return false; 4007 4008 if (gimple_call_lhs (stmt) 4009 && TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME) 4010 return false; 4011 4012 gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt)); 4013 4014 vectype = STMT_VINFO_VECTYPE (stmt_info); 4015 4016 if (loop_vinfo && nested_in_vect_loop_p (loop, stmt_info)) 4017 return false; 4018 4019 /* FORNOW */ 4020 if (slp_node) 4021 return false; 4022 4023 /* Process function arguments. */ 4024 nargs = gimple_call_num_args (stmt); 4025 4026 /* Bail out if the function has zero arguments. */ 4027 if (nargs == 0) 4028 return false; 4029 4030 arginfo.reserve (nargs, true); 4031 4032 for (i = 0; i < nargs; i++) 4033 { 4034 simd_call_arg_info thisarginfo; 4035 affine_iv iv; 4036 4037 thisarginfo.linear_step = 0; 4038 thisarginfo.align = 0; 4039 thisarginfo.op = NULL_TREE; 4040 thisarginfo.simd_lane_linear = false; 4041 4042 op = gimple_call_arg (stmt, i); 4043 if (!vect_is_simple_use (op, vinfo, &thisarginfo.dt, 4044 &thisarginfo.vectype) 4045 || thisarginfo.dt == vect_uninitialized_def) 4046 { 4047 if (dump_enabled_p ()) 4048 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 4049 "use not simple.\n"); 4050 return false; 4051 } 4052 4053 if (thisarginfo.dt == vect_constant_def 4054 || thisarginfo.dt == vect_external_def) 4055 gcc_assert (thisarginfo.vectype == NULL_TREE); 4056 else 4057 { 4058 gcc_assert (thisarginfo.vectype != NULL_TREE); 4059 if (VECTOR_BOOLEAN_TYPE_P (thisarginfo.vectype)) 4060 { 4061 if (dump_enabled_p ()) 4062 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 4063 "vector mask arguments are not supported\n"); 4064 return false; 4065 } 4066 } 4067 4068 /* For linear arguments, the analyze phase should have saved 4069 the base and step in STMT_VINFO_SIMD_CLONE_INFO. */ 4070 if (i * 3 + 4 <= STMT_VINFO_SIMD_CLONE_INFO (stmt_info).length () 4071 && STMT_VINFO_SIMD_CLONE_INFO (stmt_info)[i * 3 + 2]) 4072 { 4073 gcc_assert (vec_stmt); 4074 thisarginfo.linear_step 4075 = tree_to_shwi (STMT_VINFO_SIMD_CLONE_INFO (stmt_info)[i * 3 + 2]); 4076 thisarginfo.op 4077 = STMT_VINFO_SIMD_CLONE_INFO (stmt_info)[i * 3 + 1]; 4078 thisarginfo.simd_lane_linear 4079 = (STMT_VINFO_SIMD_CLONE_INFO (stmt_info)[i * 3 + 3] 4080 == boolean_true_node); 4081 /* If loop has been peeled for alignment, we need to adjust it. */ 4082 tree n1 = LOOP_VINFO_NITERS_UNCHANGED (loop_vinfo); 4083 tree n2 = LOOP_VINFO_NITERS (loop_vinfo); 4084 if (n1 != n2 && !thisarginfo.simd_lane_linear) 4085 { 4086 tree bias = fold_build2 (MINUS_EXPR, TREE_TYPE (n1), n1, n2); 4087 tree step = STMT_VINFO_SIMD_CLONE_INFO (stmt_info)[i * 3 + 2]; 4088 tree opt = TREE_TYPE (thisarginfo.op); 4089 bias = fold_convert (TREE_TYPE (step), bias); 4090 bias = fold_build2 (MULT_EXPR, TREE_TYPE (step), bias, step); 4091 thisarginfo.op 4092 = fold_build2 (POINTER_TYPE_P (opt) 4093 ? POINTER_PLUS_EXPR : PLUS_EXPR, opt, 4094 thisarginfo.op, bias); 4095 } 4096 } 4097 else if (!vec_stmt 4098 && thisarginfo.dt != vect_constant_def 4099 && thisarginfo.dt != vect_external_def 4100 && loop_vinfo 4101 && TREE_CODE (op) == SSA_NAME 4102 && simple_iv (loop, loop_containing_stmt (stmt), op, 4103 &iv, false) 4104 && tree_fits_shwi_p (iv.step)) 4105 { 4106 thisarginfo.linear_step = tree_to_shwi (iv.step); 4107 thisarginfo.op = iv.base; 4108 } 4109 else if ((thisarginfo.dt == vect_constant_def 4110 || thisarginfo.dt == vect_external_def) 4111 && POINTER_TYPE_P (TREE_TYPE (op))) 4112 thisarginfo.align = get_pointer_alignment (op) / BITS_PER_UNIT; 4113 /* Addresses of array elements indexed by GOMP_SIMD_LANE are 4114 linear too. */ 4115 if (POINTER_TYPE_P (TREE_TYPE (op)) 4116 && !thisarginfo.linear_step 4117 && !vec_stmt 4118 && thisarginfo.dt != vect_constant_def 4119 && thisarginfo.dt != vect_external_def 4120 && loop_vinfo 4121 && !slp_node 4122 && TREE_CODE (op) == SSA_NAME) 4123 vect_simd_lane_linear (op, loop, &thisarginfo); 4124 4125 arginfo.quick_push (thisarginfo); 4126 } 4127 4128 poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); 4129 if (!vf.is_constant ()) 4130 { 4131 if (dump_enabled_p ()) 4132 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 4133 "not considering SIMD clones; not yet supported" 4134 " for variable-width vectors.\n"); 4135 return false; 4136 } 4137 4138 unsigned int badness = 0; 4139 struct cgraph_node *bestn = NULL; 4140 if (STMT_VINFO_SIMD_CLONE_INFO (stmt_info).exists ()) 4141 bestn = cgraph_node::get (STMT_VINFO_SIMD_CLONE_INFO (stmt_info)[0]); 4142 else 4143 for (struct cgraph_node *n = node->simd_clones; n != NULL; 4144 n = n->simdclone->next_clone) 4145 { 4146 unsigned int this_badness = 0; 4147 unsigned int num_calls; 4148 if (!constant_multiple_p (vf, n->simdclone->simdlen, &num_calls) 4149 || n->simdclone->nargs != nargs) 4150 continue; 4151 if (num_calls != 1) 4152 this_badness += exact_log2 (num_calls) * 4096; 4153 if (n->simdclone->inbranch) 4154 this_badness += 8192; 4155 int target_badness = targetm.simd_clone.usable (n); 4156 if (target_badness < 0) 4157 continue; 4158 this_badness += target_badness * 512; 4159 /* FORNOW: Have to add code to add the mask argument. */ 4160 if (n->simdclone->inbranch) 4161 continue; 4162 for (i = 0; i < nargs; i++) 4163 { 4164 switch (n->simdclone->args[i].arg_type) 4165 { 4166 case SIMD_CLONE_ARG_TYPE_VECTOR: 4167 if (!useless_type_conversion_p 4168 (n->simdclone->args[i].orig_type, 4169 TREE_TYPE (gimple_call_arg (stmt, i)))) 4170 i = -1; 4171 else if (arginfo[i].dt == vect_constant_def 4172 || arginfo[i].dt == vect_external_def 4173 || arginfo[i].linear_step) 4174 this_badness += 64; 4175 break; 4176 case SIMD_CLONE_ARG_TYPE_UNIFORM: 4177 if (arginfo[i].dt != vect_constant_def 4178 && arginfo[i].dt != vect_external_def) 4179 i = -1; 4180 break; 4181 case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP: 4182 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP: 4183 if (arginfo[i].dt == vect_constant_def 4184 || arginfo[i].dt == vect_external_def 4185 || (arginfo[i].linear_step 4186 != n->simdclone->args[i].linear_step)) 4187 i = -1; 4188 break; 4189 case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP: 4190 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP: 4191 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP: 4192 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP: 4193 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP: 4194 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP: 4195 /* FORNOW */ 4196 i = -1; 4197 break; 4198 case SIMD_CLONE_ARG_TYPE_MASK: 4199 gcc_unreachable (); 4200 } 4201 if (i == (size_t) -1) 4202 break; 4203 if (n->simdclone->args[i].alignment > arginfo[i].align) 4204 { 4205 i = -1; 4206 break; 4207 } 4208 if (arginfo[i].align) 4209 this_badness += (exact_log2 (arginfo[i].align) 4210 - exact_log2 (n->simdclone->args[i].alignment)); 4211 } 4212 if (i == (size_t) -1) 4213 continue; 4214 if (bestn == NULL || this_badness < badness) 4215 { 4216 bestn = n; 4217 badness = this_badness; 4218 } 4219 } 4220 4221 if (bestn == NULL) 4222 return false; 4223 4224 for (i = 0; i < nargs; i++) 4225 if ((arginfo[i].dt == vect_constant_def 4226 || arginfo[i].dt == vect_external_def) 4227 && bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR) 4228 { 4229 tree arg_type = TREE_TYPE (gimple_call_arg (stmt, i)); 4230 arginfo[i].vectype = get_vectype_for_scalar_type (vinfo, arg_type, 4231 slp_node); 4232 if (arginfo[i].vectype == NULL 4233 || !constant_multiple_p (bestn->simdclone->simdlen, 4234 simd_clone_subparts (arginfo[i].vectype))) 4235 return false; 4236 } 4237 4238 fndecl = bestn->decl; 4239 nunits = bestn->simdclone->simdlen; 4240 ncopies = vector_unroll_factor (vf, nunits); 4241 4242 /* If the function isn't const, only allow it in simd loops where user 4243 has asserted that at least nunits consecutive iterations can be 4244 performed using SIMD instructions. */ 4245 if ((loop == NULL || maybe_lt ((unsigned) loop->safelen, nunits)) 4246 && gimple_vuse (stmt)) 4247 return false; 4248 4249 /* Sanity check: make sure that at least one copy of the vectorized stmt 4250 needs to be generated. */ 4251 gcc_assert (ncopies >= 1); 4252 4253 if (!vec_stmt) /* transformation not required. */ 4254 { 4255 STMT_VINFO_SIMD_CLONE_INFO (stmt_info).safe_push (bestn->decl); 4256 for (i = 0; i < nargs; i++) 4257 if ((bestn->simdclone->args[i].arg_type 4258 == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP) 4259 || (bestn->simdclone->args[i].arg_type 4260 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)) 4261 { 4262 STMT_VINFO_SIMD_CLONE_INFO (stmt_info).safe_grow_cleared (i * 3 4263 + 1, 4264 true); 4265 STMT_VINFO_SIMD_CLONE_INFO (stmt_info).safe_push (arginfo[i].op); 4266 tree lst = POINTER_TYPE_P (TREE_TYPE (arginfo[i].op)) 4267 ? size_type_node : TREE_TYPE (arginfo[i].op); 4268 tree ls = build_int_cst (lst, arginfo[i].linear_step); 4269 STMT_VINFO_SIMD_CLONE_INFO (stmt_info).safe_push (ls); 4270 tree sll = arginfo[i].simd_lane_linear 4271 ? boolean_true_node : boolean_false_node; 4272 STMT_VINFO_SIMD_CLONE_INFO (stmt_info).safe_push (sll); 4273 } 4274 STMT_VINFO_TYPE (stmt_info) = call_simd_clone_vec_info_type; 4275 DUMP_VECT_SCOPE ("vectorizable_simd_clone_call"); 4276 /* vect_model_simple_cost (vinfo, stmt_info, ncopies, 4277 dt, slp_node, cost_vec); */ 4278 return true; 4279 } 4280 4281 /* Transform. */ 4282 4283 if (dump_enabled_p ()) 4284 dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n"); 4285 4286 /* Handle def. */ 4287 scalar_dest = gimple_call_lhs (stmt); 4288 vec_dest = NULL_TREE; 4289 rtype = NULL_TREE; 4290 ratype = NULL_TREE; 4291 if (scalar_dest) 4292 { 4293 vec_dest = vect_create_destination_var (scalar_dest, vectype); 4294 rtype = TREE_TYPE (TREE_TYPE (fndecl)); 4295 if (TREE_CODE (rtype) == ARRAY_TYPE) 4296 { 4297 ratype = rtype; 4298 rtype = TREE_TYPE (ratype); 4299 } 4300 } 4301 4302 auto_vec<vec<tree> > vec_oprnds; 4303 auto_vec<unsigned> vec_oprnds_i; 4304 vec_oprnds.safe_grow_cleared (nargs, true); 4305 vec_oprnds_i.safe_grow_cleared (nargs, true); 4306 for (j = 0; j < ncopies; ++j) 4307 { 4308 /* Build argument list for the vectorized call. */ 4309 if (j == 0) 4310 vargs.create (nargs); 4311 else 4312 vargs.truncate (0); 4313 4314 for (i = 0; i < nargs; i++) 4315 { 4316 unsigned int k, l, m, o; 4317 tree atype; 4318 op = gimple_call_arg (stmt, i); 4319 switch (bestn->simdclone->args[i].arg_type) 4320 { 4321 case SIMD_CLONE_ARG_TYPE_VECTOR: 4322 atype = bestn->simdclone->args[i].vector_type; 4323 o = vector_unroll_factor (nunits, 4324 simd_clone_subparts (atype)); 4325 for (m = j * o; m < (j + 1) * o; m++) 4326 { 4327 if (simd_clone_subparts (atype) 4328 < simd_clone_subparts (arginfo[i].vectype)) 4329 { 4330 poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (atype)); 4331 k = (simd_clone_subparts (arginfo[i].vectype) 4332 / simd_clone_subparts (atype)); 4333 gcc_assert ((k & (k - 1)) == 0); 4334 if (m == 0) 4335 { 4336 vect_get_vec_defs_for_operand (vinfo, stmt_info, 4337 ncopies * o / k, op, 4338 &vec_oprnds[i]); 4339 vec_oprnds_i[i] = 0; 4340 vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++]; 4341 } 4342 else 4343 { 4344 vec_oprnd0 = arginfo[i].op; 4345 if ((m & (k - 1)) == 0) 4346 vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++]; 4347 } 4348 arginfo[i].op = vec_oprnd0; 4349 vec_oprnd0 4350 = build3 (BIT_FIELD_REF, atype, vec_oprnd0, 4351 bitsize_int (prec), 4352 bitsize_int ((m & (k - 1)) * prec)); 4353 gassign *new_stmt 4354 = gimple_build_assign (make_ssa_name (atype), 4355 vec_oprnd0); 4356 vect_finish_stmt_generation (vinfo, stmt_info, 4357 new_stmt, gsi); 4358 vargs.safe_push (gimple_assign_lhs (new_stmt)); 4359 } 4360 else 4361 { 4362 k = (simd_clone_subparts (atype) 4363 / simd_clone_subparts (arginfo[i].vectype)); 4364 gcc_assert ((k & (k - 1)) == 0); 4365 vec<constructor_elt, va_gc> *ctor_elts; 4366 if (k != 1) 4367 vec_alloc (ctor_elts, k); 4368 else 4369 ctor_elts = NULL; 4370 for (l = 0; l < k; l++) 4371 { 4372 if (m == 0 && l == 0) 4373 { 4374 vect_get_vec_defs_for_operand (vinfo, stmt_info, 4375 k * o * ncopies, 4376 op, 4377 &vec_oprnds[i]); 4378 vec_oprnds_i[i] = 0; 4379 vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++]; 4380 } 4381 else 4382 vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++]; 4383 arginfo[i].op = vec_oprnd0; 4384 if (k == 1) 4385 break; 4386 CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE, 4387 vec_oprnd0); 4388 } 4389 if (k == 1) 4390 if (!useless_type_conversion_p (TREE_TYPE (vec_oprnd0), 4391 atype)) 4392 { 4393 vec_oprnd0 4394 = build1 (VIEW_CONVERT_EXPR, atype, vec_oprnd0); 4395 gassign *new_stmt 4396 = gimple_build_assign (make_ssa_name (atype), 4397 vec_oprnd0); 4398 vect_finish_stmt_generation (vinfo, stmt_info, 4399 new_stmt, gsi); 4400 vargs.safe_push (gimple_assign_lhs (new_stmt)); 4401 } 4402 else 4403 vargs.safe_push (vec_oprnd0); 4404 else 4405 { 4406 vec_oprnd0 = build_constructor (atype, ctor_elts); 4407 gassign *new_stmt 4408 = gimple_build_assign (make_ssa_name (atype), 4409 vec_oprnd0); 4410 vect_finish_stmt_generation (vinfo, stmt_info, 4411 new_stmt, gsi); 4412 vargs.safe_push (gimple_assign_lhs (new_stmt)); 4413 } 4414 } 4415 } 4416 break; 4417 case SIMD_CLONE_ARG_TYPE_UNIFORM: 4418 vargs.safe_push (op); 4419 break; 4420 case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP: 4421 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP: 4422 if (j == 0) 4423 { 4424 gimple_seq stmts; 4425 arginfo[i].op 4426 = force_gimple_operand (unshare_expr (arginfo[i].op), 4427 &stmts, true, NULL_TREE); 4428 if (stmts != NULL) 4429 { 4430 basic_block new_bb; 4431 edge pe = loop_preheader_edge (loop); 4432 new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts); 4433 gcc_assert (!new_bb); 4434 } 4435 if (arginfo[i].simd_lane_linear) 4436 { 4437 vargs.safe_push (arginfo[i].op); 4438 break; 4439 } 4440 tree phi_res = copy_ssa_name (op); 4441 gphi *new_phi = create_phi_node (phi_res, loop->header); 4442 add_phi_arg (new_phi, arginfo[i].op, 4443 loop_preheader_edge (loop), UNKNOWN_LOCATION); 4444 enum tree_code code 4445 = POINTER_TYPE_P (TREE_TYPE (op)) 4446 ? POINTER_PLUS_EXPR : PLUS_EXPR; 4447 tree type = POINTER_TYPE_P (TREE_TYPE (op)) 4448 ? sizetype : TREE_TYPE (op); 4449 poly_widest_int cst 4450 = wi::mul (bestn->simdclone->args[i].linear_step, 4451 ncopies * nunits); 4452 tree tcst = wide_int_to_tree (type, cst); 4453 tree phi_arg = copy_ssa_name (op); 4454 gassign *new_stmt 4455 = gimple_build_assign (phi_arg, code, phi_res, tcst); 4456 gimple_stmt_iterator si = gsi_after_labels (loop->header); 4457 gsi_insert_after (&si, new_stmt, GSI_NEW_STMT); 4458 add_phi_arg (new_phi, phi_arg, loop_latch_edge (loop), 4459 UNKNOWN_LOCATION); 4460 arginfo[i].op = phi_res; 4461 vargs.safe_push (phi_res); 4462 } 4463 else 4464 { 4465 enum tree_code code 4466 = POINTER_TYPE_P (TREE_TYPE (op)) 4467 ? POINTER_PLUS_EXPR : PLUS_EXPR; 4468 tree type = POINTER_TYPE_P (TREE_TYPE (op)) 4469 ? sizetype : TREE_TYPE (op); 4470 poly_widest_int cst 4471 = wi::mul (bestn->simdclone->args[i].linear_step, 4472 j * nunits); 4473 tree tcst = wide_int_to_tree (type, cst); 4474 new_temp = make_ssa_name (TREE_TYPE (op)); 4475 gassign *new_stmt 4476 = gimple_build_assign (new_temp, code, 4477 arginfo[i].op, tcst); 4478 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 4479 vargs.safe_push (new_temp); 4480 } 4481 break; 4482 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP: 4483 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP: 4484 case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP: 4485 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP: 4486 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP: 4487 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP: 4488 default: 4489 gcc_unreachable (); 4490 } 4491 } 4492 4493 gcall *new_call = gimple_build_call_vec (fndecl, vargs); 4494 if (vec_dest) 4495 { 4496 gcc_assert (ratype 4497 || known_eq (simd_clone_subparts (rtype), nunits)); 4498 if (ratype) 4499 new_temp = create_tmp_var (ratype); 4500 else if (useless_type_conversion_p (vectype, rtype)) 4501 new_temp = make_ssa_name (vec_dest, new_call); 4502 else 4503 new_temp = make_ssa_name (rtype, new_call); 4504 gimple_call_set_lhs (new_call, new_temp); 4505 } 4506 vect_finish_stmt_generation (vinfo, stmt_info, new_call, gsi); 4507 gimple *new_stmt = new_call; 4508 4509 if (vec_dest) 4510 { 4511 if (!multiple_p (simd_clone_subparts (vectype), nunits)) 4512 { 4513 unsigned int k, l; 4514 poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (vectype)); 4515 poly_uint64 bytes = GET_MODE_SIZE (TYPE_MODE (vectype)); 4516 k = vector_unroll_factor (nunits, 4517 simd_clone_subparts (vectype)); 4518 gcc_assert ((k & (k - 1)) == 0); 4519 for (l = 0; l < k; l++) 4520 { 4521 tree t; 4522 if (ratype) 4523 { 4524 t = build_fold_addr_expr (new_temp); 4525 t = build2 (MEM_REF, vectype, t, 4526 build_int_cst (TREE_TYPE (t), l * bytes)); 4527 } 4528 else 4529 t = build3 (BIT_FIELD_REF, vectype, new_temp, 4530 bitsize_int (prec), bitsize_int (l * prec)); 4531 new_stmt = gimple_build_assign (make_ssa_name (vectype), t); 4532 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 4533 4534 if (j == 0 && l == 0) 4535 *vec_stmt = new_stmt; 4536 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 4537 } 4538 4539 if (ratype) 4540 vect_clobber_variable (vinfo, stmt_info, gsi, new_temp); 4541 continue; 4542 } 4543 else if (!multiple_p (nunits, simd_clone_subparts (vectype))) 4544 { 4545 unsigned int k = (simd_clone_subparts (vectype) 4546 / simd_clone_subparts (rtype)); 4547 gcc_assert ((k & (k - 1)) == 0); 4548 if ((j & (k - 1)) == 0) 4549 vec_alloc (ret_ctor_elts, k); 4550 if (ratype) 4551 { 4552 unsigned int m, o; 4553 o = vector_unroll_factor (nunits, 4554 simd_clone_subparts (rtype)); 4555 for (m = 0; m < o; m++) 4556 { 4557 tree tem = build4 (ARRAY_REF, rtype, new_temp, 4558 size_int (m), NULL_TREE, NULL_TREE); 4559 new_stmt = gimple_build_assign (make_ssa_name (rtype), 4560 tem); 4561 vect_finish_stmt_generation (vinfo, stmt_info, 4562 new_stmt, gsi); 4563 CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE, 4564 gimple_assign_lhs (new_stmt)); 4565 } 4566 vect_clobber_variable (vinfo, stmt_info, gsi, new_temp); 4567 } 4568 else 4569 CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE, new_temp); 4570 if ((j & (k - 1)) != k - 1) 4571 continue; 4572 vec_oprnd0 = build_constructor (vectype, ret_ctor_elts); 4573 new_stmt 4574 = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0); 4575 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 4576 4577 if ((unsigned) j == k - 1) 4578 *vec_stmt = new_stmt; 4579 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 4580 continue; 4581 } 4582 else if (ratype) 4583 { 4584 tree t = build_fold_addr_expr (new_temp); 4585 t = build2 (MEM_REF, vectype, t, 4586 build_int_cst (TREE_TYPE (t), 0)); 4587 new_stmt = gimple_build_assign (make_ssa_name (vec_dest), t); 4588 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 4589 vect_clobber_variable (vinfo, stmt_info, gsi, new_temp); 4590 } 4591 else if (!useless_type_conversion_p (vectype, rtype)) 4592 { 4593 vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, vectype, new_temp); 4594 new_stmt 4595 = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0); 4596 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 4597 } 4598 } 4599 4600 if (j == 0) 4601 *vec_stmt = new_stmt; 4602 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 4603 } 4604 4605 for (i = 0; i < nargs; ++i) 4606 { 4607 vec<tree> oprndsi = vec_oprnds[i]; 4608 oprndsi.release (); 4609 } 4610 vargs.release (); 4611 4612 /* The call in STMT might prevent it from being removed in dce. 4613 We however cannot remove it here, due to the way the ssa name 4614 it defines is mapped to the new definition. So just replace 4615 rhs of the statement with something harmless. */ 4616 4617 if (slp_node) 4618 return true; 4619 4620 gimple *new_stmt; 4621 if (scalar_dest) 4622 { 4623 type = TREE_TYPE (scalar_dest); 4624 lhs = gimple_call_lhs (vect_orig_stmt (stmt_info)->stmt); 4625 new_stmt = gimple_build_assign (lhs, build_zero_cst (type)); 4626 } 4627 else 4628 new_stmt = gimple_build_nop (); 4629 vinfo->replace_stmt (gsi, vect_orig_stmt (stmt_info), new_stmt); 4630 unlink_stmt_vdef (stmt); 4631 4632 return true; 4633 } 4634 4635 4636 /* Function vect_gen_widened_results_half 4637 4638 Create a vector stmt whose code, type, number of arguments, and result 4639 variable are CODE, OP_TYPE, and VEC_DEST, and its arguments are 4640 VEC_OPRND0 and VEC_OPRND1. The new vector stmt is to be inserted at GSI. 4641 In the case that CODE is a CALL_EXPR, this means that a call to DECL 4642 needs to be created (DECL is a function-decl of a target-builtin). 4643 STMT_INFO is the original scalar stmt that we are vectorizing. */ 4644 4645 static gimple * 4646 vect_gen_widened_results_half (vec_info *vinfo, enum tree_code code, 4647 tree vec_oprnd0, tree vec_oprnd1, int op_type, 4648 tree vec_dest, gimple_stmt_iterator *gsi, 4649 stmt_vec_info stmt_info) 4650 { 4651 gimple *new_stmt; 4652 tree new_temp; 4653 4654 /* Generate half of the widened result: */ 4655 gcc_assert (op_type == TREE_CODE_LENGTH (code)); 4656 if (op_type != binary_op) 4657 vec_oprnd1 = NULL; 4658 new_stmt = gimple_build_assign (vec_dest, code, vec_oprnd0, vec_oprnd1); 4659 new_temp = make_ssa_name (vec_dest, new_stmt); 4660 gimple_assign_set_lhs (new_stmt, new_temp); 4661 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 4662 4663 return new_stmt; 4664 } 4665 4666 4667 /* Create vectorized demotion statements for vector operands from VEC_OPRNDS. 4668 For multi-step conversions store the resulting vectors and call the function 4669 recursively. */ 4670 4671 static void 4672 vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds, 4673 int multi_step_cvt, 4674 stmt_vec_info stmt_info, 4675 vec<tree> &vec_dsts, 4676 gimple_stmt_iterator *gsi, 4677 slp_tree slp_node, enum tree_code code) 4678 { 4679 unsigned int i; 4680 tree vop0, vop1, new_tmp, vec_dest; 4681 4682 vec_dest = vec_dsts.pop (); 4683 4684 for (i = 0; i < vec_oprnds->length (); i += 2) 4685 { 4686 /* Create demotion operation. */ 4687 vop0 = (*vec_oprnds)[i]; 4688 vop1 = (*vec_oprnds)[i + 1]; 4689 gassign *new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1); 4690 new_tmp = make_ssa_name (vec_dest, new_stmt); 4691 gimple_assign_set_lhs (new_stmt, new_tmp); 4692 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 4693 4694 if (multi_step_cvt) 4695 /* Store the resulting vector for next recursive call. */ 4696 (*vec_oprnds)[i/2] = new_tmp; 4697 else 4698 { 4699 /* This is the last step of the conversion sequence. Store the 4700 vectors in SLP_NODE or in vector info of the scalar statement 4701 (or in STMT_VINFO_RELATED_STMT chain). */ 4702 if (slp_node) 4703 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 4704 else 4705 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 4706 } 4707 } 4708 4709 /* For multi-step demotion operations we first generate demotion operations 4710 from the source type to the intermediate types, and then combine the 4711 results (stored in VEC_OPRNDS) in demotion operation to the destination 4712 type. */ 4713 if (multi_step_cvt) 4714 { 4715 /* At each level of recursion we have half of the operands we had at the 4716 previous level. */ 4717 vec_oprnds->truncate ((i+1)/2); 4718 vect_create_vectorized_demotion_stmts (vinfo, vec_oprnds, 4719 multi_step_cvt - 1, 4720 stmt_info, vec_dsts, gsi, 4721 slp_node, VEC_PACK_TRUNC_EXPR); 4722 } 4723 4724 vec_dsts.quick_push (vec_dest); 4725 } 4726 4727 4728 /* Create vectorized promotion statements for vector operands from VEC_OPRNDS0 4729 and VEC_OPRNDS1, for a binary operation associated with scalar statement 4730 STMT_INFO. For multi-step conversions store the resulting vectors and 4731 call the function recursively. */ 4732 4733 static void 4734 vect_create_vectorized_promotion_stmts (vec_info *vinfo, 4735 vec<tree> *vec_oprnds0, 4736 vec<tree> *vec_oprnds1, 4737 stmt_vec_info stmt_info, tree vec_dest, 4738 gimple_stmt_iterator *gsi, 4739 enum tree_code code1, 4740 enum tree_code code2, int op_type) 4741 { 4742 int i; 4743 tree vop0, vop1, new_tmp1, new_tmp2; 4744 gimple *new_stmt1, *new_stmt2; 4745 vec<tree> vec_tmp = vNULL; 4746 4747 vec_tmp.create (vec_oprnds0->length () * 2); 4748 FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0) 4749 { 4750 if (op_type == binary_op) 4751 vop1 = (*vec_oprnds1)[i]; 4752 else 4753 vop1 = NULL_TREE; 4754 4755 /* Generate the two halves of promotion operation. */ 4756 new_stmt1 = vect_gen_widened_results_half (vinfo, code1, vop0, vop1, 4757 op_type, vec_dest, gsi, 4758 stmt_info); 4759 new_stmt2 = vect_gen_widened_results_half (vinfo, code2, vop0, vop1, 4760 op_type, vec_dest, gsi, 4761 stmt_info); 4762 if (is_gimple_call (new_stmt1)) 4763 { 4764 new_tmp1 = gimple_call_lhs (new_stmt1); 4765 new_tmp2 = gimple_call_lhs (new_stmt2); 4766 } 4767 else 4768 { 4769 new_tmp1 = gimple_assign_lhs (new_stmt1); 4770 new_tmp2 = gimple_assign_lhs (new_stmt2); 4771 } 4772 4773 /* Store the results for the next step. */ 4774 vec_tmp.quick_push (new_tmp1); 4775 vec_tmp.quick_push (new_tmp2); 4776 } 4777 4778 vec_oprnds0->release (); 4779 *vec_oprnds0 = vec_tmp; 4780 } 4781 4782 /* Create vectorized promotion stmts for widening stmts using only half the 4783 potential vector size for input. */ 4784 static void 4785 vect_create_half_widening_stmts (vec_info *vinfo, 4786 vec<tree> *vec_oprnds0, 4787 vec<tree> *vec_oprnds1, 4788 stmt_vec_info stmt_info, tree vec_dest, 4789 gimple_stmt_iterator *gsi, 4790 enum tree_code code1, 4791 int op_type) 4792 { 4793 int i; 4794 tree vop0, vop1; 4795 gimple *new_stmt1; 4796 gimple *new_stmt2; 4797 gimple *new_stmt3; 4798 vec<tree> vec_tmp = vNULL; 4799 4800 vec_tmp.create (vec_oprnds0->length ()); 4801 FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0) 4802 { 4803 tree new_tmp1, new_tmp2, new_tmp3, out_type; 4804 4805 gcc_assert (op_type == binary_op); 4806 vop1 = (*vec_oprnds1)[i]; 4807 4808 /* Widen the first vector input. */ 4809 out_type = TREE_TYPE (vec_dest); 4810 new_tmp1 = make_ssa_name (out_type); 4811 new_stmt1 = gimple_build_assign (new_tmp1, NOP_EXPR, vop0); 4812 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt1, gsi); 4813 if (VECTOR_TYPE_P (TREE_TYPE (vop1))) 4814 { 4815 /* Widen the second vector input. */ 4816 new_tmp2 = make_ssa_name (out_type); 4817 new_stmt2 = gimple_build_assign (new_tmp2, NOP_EXPR, vop1); 4818 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt2, gsi); 4819 /* Perform the operation. With both vector inputs widened. */ 4820 new_stmt3 = gimple_build_assign (vec_dest, code1, new_tmp1, new_tmp2); 4821 } 4822 else 4823 { 4824 /* Perform the operation. With the single vector input widened. */ 4825 new_stmt3 = gimple_build_assign (vec_dest, code1, new_tmp1, vop1); 4826 } 4827 4828 new_tmp3 = make_ssa_name (vec_dest, new_stmt3); 4829 gimple_assign_set_lhs (new_stmt3, new_tmp3); 4830 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt3, gsi); 4831 4832 /* Store the results for the next step. */ 4833 vec_tmp.quick_push (new_tmp3); 4834 } 4835 4836 vec_oprnds0->release (); 4837 *vec_oprnds0 = vec_tmp; 4838 } 4839 4840 4841 /* Check if STMT_INFO performs a conversion operation that can be vectorized. 4842 If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized 4843 stmt to replace it, put it in VEC_STMT, and insert it at GSI. 4844 Return true if STMT_INFO is vectorizable in this way. */ 4845 4846 static bool 4847 vectorizable_conversion (vec_info *vinfo, 4848 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 4849 gimple **vec_stmt, slp_tree slp_node, 4850 stmt_vector_for_cost *cost_vec) 4851 { 4852 tree vec_dest; 4853 tree scalar_dest; 4854 tree op0, op1 = NULL_TREE; 4855 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 4856 enum tree_code code, code1 = ERROR_MARK, code2 = ERROR_MARK; 4857 enum tree_code codecvt1 = ERROR_MARK, codecvt2 = ERROR_MARK; 4858 tree new_temp; 4859 enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type}; 4860 int ndts = 2; 4861 poly_uint64 nunits_in; 4862 poly_uint64 nunits_out; 4863 tree vectype_out, vectype_in; 4864 int ncopies, i; 4865 tree lhs_type, rhs_type; 4866 enum { NARROW, NONE, WIDEN } modifier; 4867 vec<tree> vec_oprnds0 = vNULL; 4868 vec<tree> vec_oprnds1 = vNULL; 4869 tree vop0; 4870 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 4871 int multi_step_cvt = 0; 4872 vec<tree> interm_types = vNULL; 4873 tree intermediate_type, cvt_type = NULL_TREE; 4874 int op_type; 4875 unsigned short fltsz; 4876 4877 /* Is STMT a vectorizable conversion? */ 4878 4879 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 4880 return false; 4881 4882 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def 4883 && ! vec_stmt) 4884 return false; 4885 4886 gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt); 4887 if (!stmt) 4888 return false; 4889 4890 if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME) 4891 return false; 4892 4893 code = gimple_assign_rhs_code (stmt); 4894 if (!CONVERT_EXPR_CODE_P (code) 4895 && code != FIX_TRUNC_EXPR 4896 && code != FLOAT_EXPR 4897 && code != WIDEN_PLUS_EXPR 4898 && code != WIDEN_MINUS_EXPR 4899 && code != WIDEN_MULT_EXPR 4900 && code != WIDEN_LSHIFT_EXPR) 4901 return false; 4902 4903 bool widen_arith = (code == WIDEN_PLUS_EXPR 4904 || code == WIDEN_MINUS_EXPR 4905 || code == WIDEN_MULT_EXPR 4906 || code == WIDEN_LSHIFT_EXPR); 4907 op_type = TREE_CODE_LENGTH (code); 4908 4909 /* Check types of lhs and rhs. */ 4910 scalar_dest = gimple_assign_lhs (stmt); 4911 lhs_type = TREE_TYPE (scalar_dest); 4912 vectype_out = STMT_VINFO_VECTYPE (stmt_info); 4913 4914 /* Check the operands of the operation. */ 4915 slp_tree slp_op0, slp_op1 = NULL; 4916 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 4917 0, &op0, &slp_op0, &dt[0], &vectype_in)) 4918 { 4919 if (dump_enabled_p ()) 4920 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 4921 "use not simple.\n"); 4922 return false; 4923 } 4924 4925 rhs_type = TREE_TYPE (op0); 4926 if ((code != FIX_TRUNC_EXPR && code != FLOAT_EXPR) 4927 && !((INTEGRAL_TYPE_P (lhs_type) 4928 && INTEGRAL_TYPE_P (rhs_type)) 4929 || (SCALAR_FLOAT_TYPE_P (lhs_type) 4930 && SCALAR_FLOAT_TYPE_P (rhs_type)))) 4931 return false; 4932 4933 if (!VECTOR_BOOLEAN_TYPE_P (vectype_out) 4934 && ((INTEGRAL_TYPE_P (lhs_type) 4935 && !type_has_mode_precision_p (lhs_type)) 4936 || (INTEGRAL_TYPE_P (rhs_type) 4937 && !type_has_mode_precision_p (rhs_type)))) 4938 { 4939 if (dump_enabled_p ()) 4940 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 4941 "type conversion to/from bit-precision unsupported." 4942 "\n"); 4943 return false; 4944 } 4945 4946 if (op_type == binary_op) 4947 { 4948 gcc_assert (code == WIDEN_MULT_EXPR || code == WIDEN_LSHIFT_EXPR 4949 || code == WIDEN_PLUS_EXPR || code == WIDEN_MINUS_EXPR); 4950 4951 op1 = gimple_assign_rhs2 (stmt); 4952 tree vectype1_in; 4953 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1, 4954 &op1, &slp_op1, &dt[1], &vectype1_in)) 4955 { 4956 if (dump_enabled_p ()) 4957 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 4958 "use not simple.\n"); 4959 return false; 4960 } 4961 /* For WIDEN_MULT_EXPR, if OP0 is a constant, use the type of 4962 OP1. */ 4963 if (!vectype_in) 4964 vectype_in = vectype1_in; 4965 } 4966 4967 /* If op0 is an external or constant def, infer the vector type 4968 from the scalar type. */ 4969 if (!vectype_in) 4970 vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node); 4971 if (vec_stmt) 4972 gcc_assert (vectype_in); 4973 if (!vectype_in) 4974 { 4975 if (dump_enabled_p ()) 4976 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 4977 "no vectype for scalar type %T\n", rhs_type); 4978 4979 return false; 4980 } 4981 4982 if (VECTOR_BOOLEAN_TYPE_P (vectype_out) 4983 && !VECTOR_BOOLEAN_TYPE_P (vectype_in)) 4984 { 4985 if (dump_enabled_p ()) 4986 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 4987 "can't convert between boolean and non " 4988 "boolean vectors %T\n", rhs_type); 4989 4990 return false; 4991 } 4992 4993 nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in); 4994 nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out); 4995 if (known_eq (nunits_out, nunits_in)) 4996 if (widen_arith) 4997 modifier = WIDEN; 4998 else 4999 modifier = NONE; 5000 else if (multiple_p (nunits_out, nunits_in)) 5001 modifier = NARROW; 5002 else 5003 { 5004 gcc_checking_assert (multiple_p (nunits_in, nunits_out)); 5005 modifier = WIDEN; 5006 } 5007 5008 /* Multiple types in SLP are handled by creating the appropriate number of 5009 vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in 5010 case of SLP. */ 5011 if (slp_node) 5012 ncopies = 1; 5013 else if (modifier == NARROW) 5014 ncopies = vect_get_num_copies (loop_vinfo, vectype_out); 5015 else 5016 ncopies = vect_get_num_copies (loop_vinfo, vectype_in); 5017 5018 /* Sanity check: make sure that at least one copy of the vectorized stmt 5019 needs to be generated. */ 5020 gcc_assert (ncopies >= 1); 5021 5022 bool found_mode = false; 5023 scalar_mode lhs_mode = SCALAR_TYPE_MODE (lhs_type); 5024 scalar_mode rhs_mode = SCALAR_TYPE_MODE (rhs_type); 5025 opt_scalar_mode rhs_mode_iter; 5026 5027 /* Supportable by target? */ 5028 switch (modifier) 5029 { 5030 case NONE: 5031 if (code != FIX_TRUNC_EXPR 5032 && code != FLOAT_EXPR 5033 && !CONVERT_EXPR_CODE_P (code)) 5034 return false; 5035 if (supportable_convert_operation (code, vectype_out, vectype_in, &code1)) 5036 break; 5037 /* FALLTHRU */ 5038 unsupported: 5039 if (dump_enabled_p ()) 5040 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5041 "conversion not supported by target.\n"); 5042 return false; 5043 5044 case WIDEN: 5045 if (known_eq (nunits_in, nunits_out)) 5046 { 5047 if (!supportable_half_widening_operation (code, vectype_out, 5048 vectype_in, &code1)) 5049 goto unsupported; 5050 gcc_assert (!(multi_step_cvt && op_type == binary_op)); 5051 break; 5052 } 5053 if (supportable_widening_operation (vinfo, code, stmt_info, 5054 vectype_out, vectype_in, &code1, 5055 &code2, &multi_step_cvt, 5056 &interm_types)) 5057 { 5058 /* Binary widening operation can only be supported directly by the 5059 architecture. */ 5060 gcc_assert (!(multi_step_cvt && op_type == binary_op)); 5061 break; 5062 } 5063 5064 if (code != FLOAT_EXPR 5065 || GET_MODE_SIZE (lhs_mode) <= GET_MODE_SIZE (rhs_mode)) 5066 goto unsupported; 5067 5068 fltsz = GET_MODE_SIZE (lhs_mode); 5069 FOR_EACH_2XWIDER_MODE (rhs_mode_iter, rhs_mode) 5070 { 5071 rhs_mode = rhs_mode_iter.require (); 5072 if (GET_MODE_SIZE (rhs_mode) > fltsz) 5073 break; 5074 5075 cvt_type 5076 = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0); 5077 cvt_type = get_same_sized_vectype (cvt_type, vectype_in); 5078 if (cvt_type == NULL_TREE) 5079 goto unsupported; 5080 5081 if (GET_MODE_SIZE (rhs_mode) == fltsz) 5082 { 5083 if (!supportable_convert_operation (code, vectype_out, 5084 cvt_type, &codecvt1)) 5085 goto unsupported; 5086 } 5087 else if (!supportable_widening_operation (vinfo, code, stmt_info, 5088 vectype_out, cvt_type, 5089 &codecvt1, &codecvt2, 5090 &multi_step_cvt, 5091 &interm_types)) 5092 continue; 5093 else 5094 gcc_assert (multi_step_cvt == 0); 5095 5096 if (supportable_widening_operation (vinfo, NOP_EXPR, stmt_info, 5097 cvt_type, 5098 vectype_in, &code1, &code2, 5099 &multi_step_cvt, &interm_types)) 5100 { 5101 found_mode = true; 5102 break; 5103 } 5104 } 5105 5106 if (!found_mode) 5107 goto unsupported; 5108 5109 if (GET_MODE_SIZE (rhs_mode) == fltsz) 5110 codecvt2 = ERROR_MARK; 5111 else 5112 { 5113 multi_step_cvt++; 5114 interm_types.safe_push (cvt_type); 5115 cvt_type = NULL_TREE; 5116 } 5117 break; 5118 5119 case NARROW: 5120 gcc_assert (op_type == unary_op); 5121 if (supportable_narrowing_operation (code, vectype_out, vectype_in, 5122 &code1, &multi_step_cvt, 5123 &interm_types)) 5124 break; 5125 5126 if (code != FIX_TRUNC_EXPR 5127 || GET_MODE_SIZE (lhs_mode) >= GET_MODE_SIZE (rhs_mode)) 5128 goto unsupported; 5129 5130 cvt_type 5131 = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0); 5132 cvt_type = get_same_sized_vectype (cvt_type, vectype_in); 5133 if (cvt_type == NULL_TREE) 5134 goto unsupported; 5135 if (!supportable_convert_operation (code, cvt_type, vectype_in, 5136 &codecvt1)) 5137 goto unsupported; 5138 if (supportable_narrowing_operation (NOP_EXPR, vectype_out, cvt_type, 5139 &code1, &multi_step_cvt, 5140 &interm_types)) 5141 break; 5142 goto unsupported; 5143 5144 default: 5145 gcc_unreachable (); 5146 } 5147 5148 if (!vec_stmt) /* transformation not required. */ 5149 { 5150 if (slp_node 5151 && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype_in) 5152 || !vect_maybe_update_slp_op_vectype (slp_op1, vectype_in))) 5153 { 5154 if (dump_enabled_p ()) 5155 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5156 "incompatible vector types for invariants\n"); 5157 return false; 5158 } 5159 DUMP_VECT_SCOPE ("vectorizable_conversion"); 5160 if (modifier == NONE) 5161 { 5162 STMT_VINFO_TYPE (stmt_info) = type_conversion_vec_info_type; 5163 vect_model_simple_cost (vinfo, stmt_info, ncopies, dt, ndts, slp_node, 5164 cost_vec); 5165 } 5166 else if (modifier == NARROW) 5167 { 5168 STMT_VINFO_TYPE (stmt_info) = type_demotion_vec_info_type; 5169 /* The final packing step produces one vector result per copy. */ 5170 unsigned int nvectors 5171 = (slp_node ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies); 5172 vect_model_promotion_demotion_cost (stmt_info, dt, nvectors, 5173 multi_step_cvt, cost_vec, 5174 widen_arith); 5175 } 5176 else 5177 { 5178 STMT_VINFO_TYPE (stmt_info) = type_promotion_vec_info_type; 5179 /* The initial unpacking step produces two vector results 5180 per copy. MULTI_STEP_CVT is 0 for a single conversion, 5181 so >> MULTI_STEP_CVT divides by 2^(number of steps - 1). */ 5182 unsigned int nvectors 5183 = (slp_node 5184 ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) >> multi_step_cvt 5185 : ncopies * 2); 5186 vect_model_promotion_demotion_cost (stmt_info, dt, nvectors, 5187 multi_step_cvt, cost_vec, 5188 widen_arith); 5189 } 5190 interm_types.release (); 5191 return true; 5192 } 5193 5194 /* Transform. */ 5195 if (dump_enabled_p ()) 5196 dump_printf_loc (MSG_NOTE, vect_location, 5197 "transform conversion. ncopies = %d.\n", ncopies); 5198 5199 if (op_type == binary_op) 5200 { 5201 if (CONSTANT_CLASS_P (op0)) 5202 op0 = fold_convert (TREE_TYPE (op1), op0); 5203 else if (CONSTANT_CLASS_P (op1)) 5204 op1 = fold_convert (TREE_TYPE (op0), op1); 5205 } 5206 5207 /* In case of multi-step conversion, we first generate conversion operations 5208 to the intermediate types, and then from that types to the final one. 5209 We create vector destinations for the intermediate type (TYPES) received 5210 from supportable_*_operation, and store them in the correct order 5211 for future use in vect_create_vectorized_*_stmts (). */ 5212 auto_vec<tree> vec_dsts (multi_step_cvt + 1); 5213 vec_dest = vect_create_destination_var (scalar_dest, 5214 (cvt_type && modifier == WIDEN) 5215 ? cvt_type : vectype_out); 5216 vec_dsts.quick_push (vec_dest); 5217 5218 if (multi_step_cvt) 5219 { 5220 for (i = interm_types.length () - 1; 5221 interm_types.iterate (i, &intermediate_type); i--) 5222 { 5223 vec_dest = vect_create_destination_var (scalar_dest, 5224 intermediate_type); 5225 vec_dsts.quick_push (vec_dest); 5226 } 5227 } 5228 5229 if (cvt_type) 5230 vec_dest = vect_create_destination_var (scalar_dest, 5231 modifier == WIDEN 5232 ? vectype_out : cvt_type); 5233 5234 int ninputs = 1; 5235 if (!slp_node) 5236 { 5237 if (modifier == WIDEN) 5238 ; 5239 else if (modifier == NARROW) 5240 { 5241 if (multi_step_cvt) 5242 ninputs = vect_pow2 (multi_step_cvt); 5243 ninputs *= 2; 5244 } 5245 } 5246 5247 switch (modifier) 5248 { 5249 case NONE: 5250 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, 5251 op0, &vec_oprnds0); 5252 FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0) 5253 { 5254 /* Arguments are ready, create the new vector stmt. */ 5255 gcc_assert (TREE_CODE_LENGTH (code1) == unary_op); 5256 gassign *new_stmt = gimple_build_assign (vec_dest, code1, vop0); 5257 new_temp = make_ssa_name (vec_dest, new_stmt); 5258 gimple_assign_set_lhs (new_stmt, new_temp); 5259 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 5260 5261 if (slp_node) 5262 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 5263 else 5264 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 5265 } 5266 break; 5267 5268 case WIDEN: 5269 /* In case the vectorization factor (VF) is bigger than the number 5270 of elements that we can fit in a vectype (nunits), we have to 5271 generate more than one vector stmt - i.e - we need to "unroll" 5272 the vector stmt by a factor VF/nunits. */ 5273 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies * ninputs, 5274 op0, &vec_oprnds0, 5275 code == WIDEN_LSHIFT_EXPR ? NULL_TREE : op1, 5276 &vec_oprnds1); 5277 if (code == WIDEN_LSHIFT_EXPR) 5278 { 5279 int oprnds_size = vec_oprnds0.length (); 5280 vec_oprnds1.create (oprnds_size); 5281 for (i = 0; i < oprnds_size; ++i) 5282 vec_oprnds1.quick_push (op1); 5283 } 5284 /* Arguments are ready. Create the new vector stmts. */ 5285 for (i = multi_step_cvt; i >= 0; i--) 5286 { 5287 tree this_dest = vec_dsts[i]; 5288 enum tree_code c1 = code1, c2 = code2; 5289 if (i == 0 && codecvt2 != ERROR_MARK) 5290 { 5291 c1 = codecvt1; 5292 c2 = codecvt2; 5293 } 5294 if (known_eq (nunits_out, nunits_in)) 5295 vect_create_half_widening_stmts (vinfo, &vec_oprnds0, 5296 &vec_oprnds1, stmt_info, 5297 this_dest, gsi, 5298 c1, op_type); 5299 else 5300 vect_create_vectorized_promotion_stmts (vinfo, &vec_oprnds0, 5301 &vec_oprnds1, stmt_info, 5302 this_dest, gsi, 5303 c1, c2, op_type); 5304 } 5305 5306 FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0) 5307 { 5308 gimple *new_stmt; 5309 if (cvt_type) 5310 { 5311 gcc_assert (TREE_CODE_LENGTH (codecvt1) == unary_op); 5312 new_temp = make_ssa_name (vec_dest); 5313 new_stmt = gimple_build_assign (new_temp, codecvt1, vop0); 5314 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 5315 } 5316 else 5317 new_stmt = SSA_NAME_DEF_STMT (vop0); 5318 5319 if (slp_node) 5320 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 5321 else 5322 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 5323 } 5324 break; 5325 5326 case NARROW: 5327 /* In case the vectorization factor (VF) is bigger than the number 5328 of elements that we can fit in a vectype (nunits), we have to 5329 generate more than one vector stmt - i.e - we need to "unroll" 5330 the vector stmt by a factor VF/nunits. */ 5331 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies * ninputs, 5332 op0, &vec_oprnds0); 5333 /* Arguments are ready. Create the new vector stmts. */ 5334 if (cvt_type) 5335 FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0) 5336 { 5337 gcc_assert (TREE_CODE_LENGTH (codecvt1) == unary_op); 5338 new_temp = make_ssa_name (vec_dest); 5339 gassign *new_stmt 5340 = gimple_build_assign (new_temp, codecvt1, vop0); 5341 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 5342 vec_oprnds0[i] = new_temp; 5343 } 5344 5345 vect_create_vectorized_demotion_stmts (vinfo, &vec_oprnds0, 5346 multi_step_cvt, 5347 stmt_info, vec_dsts, gsi, 5348 slp_node, code1); 5349 break; 5350 } 5351 if (!slp_node) 5352 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 5353 5354 vec_oprnds0.release (); 5355 vec_oprnds1.release (); 5356 interm_types.release (); 5357 5358 return true; 5359 } 5360 5361 /* Return true if we can assume from the scalar form of STMT_INFO that 5362 neither the scalar nor the vector forms will generate code. STMT_INFO 5363 is known not to involve a data reference. */ 5364 5365 bool 5366 vect_nop_conversion_p (stmt_vec_info stmt_info) 5367 { 5368 gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt); 5369 if (!stmt) 5370 return false; 5371 5372 tree lhs = gimple_assign_lhs (stmt); 5373 tree_code code = gimple_assign_rhs_code (stmt); 5374 tree rhs = gimple_assign_rhs1 (stmt); 5375 5376 if (code == SSA_NAME || code == VIEW_CONVERT_EXPR) 5377 return true; 5378 5379 if (CONVERT_EXPR_CODE_P (code)) 5380 return tree_nop_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)); 5381 5382 return false; 5383 } 5384 5385 /* Function vectorizable_assignment. 5386 5387 Check if STMT_INFO performs an assignment (copy) that can be vectorized. 5388 If VEC_STMT is also passed, vectorize the STMT_INFO: create a vectorized 5389 stmt to replace it, put it in VEC_STMT, and insert it at GSI. 5390 Return true if STMT_INFO is vectorizable in this way. */ 5391 5392 static bool 5393 vectorizable_assignment (vec_info *vinfo, 5394 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 5395 gimple **vec_stmt, slp_tree slp_node, 5396 stmt_vector_for_cost *cost_vec) 5397 { 5398 tree vec_dest; 5399 tree scalar_dest; 5400 tree op; 5401 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 5402 tree new_temp; 5403 enum vect_def_type dt[1] = {vect_unknown_def_type}; 5404 int ndts = 1; 5405 int ncopies; 5406 int i; 5407 vec<tree> vec_oprnds = vNULL; 5408 tree vop; 5409 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 5410 enum tree_code code; 5411 tree vectype_in; 5412 5413 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 5414 return false; 5415 5416 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def 5417 && ! vec_stmt) 5418 return false; 5419 5420 /* Is vectorizable assignment? */ 5421 gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt); 5422 if (!stmt) 5423 return false; 5424 5425 scalar_dest = gimple_assign_lhs (stmt); 5426 if (TREE_CODE (scalar_dest) != SSA_NAME) 5427 return false; 5428 5429 if (STMT_VINFO_DATA_REF (stmt_info)) 5430 return false; 5431 5432 code = gimple_assign_rhs_code (stmt); 5433 if (!(gimple_assign_single_p (stmt) 5434 || code == PAREN_EXPR 5435 || CONVERT_EXPR_CODE_P (code))) 5436 return false; 5437 5438 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 5439 poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); 5440 5441 /* Multiple types in SLP are handled by creating the appropriate number of 5442 vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in 5443 case of SLP. */ 5444 if (slp_node) 5445 ncopies = 1; 5446 else 5447 ncopies = vect_get_num_copies (loop_vinfo, vectype); 5448 5449 gcc_assert (ncopies >= 1); 5450 5451 slp_tree slp_op; 5452 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &op, &slp_op, 5453 &dt[0], &vectype_in)) 5454 { 5455 if (dump_enabled_p ()) 5456 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5457 "use not simple.\n"); 5458 return false; 5459 } 5460 if (!vectype_in) 5461 vectype_in = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op), slp_node); 5462 5463 /* We can handle NOP_EXPR conversions that do not change the number 5464 of elements or the vector size. */ 5465 if ((CONVERT_EXPR_CODE_P (code) 5466 || code == VIEW_CONVERT_EXPR) 5467 && (!vectype_in 5468 || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype_in), nunits) 5469 || maybe_ne (GET_MODE_SIZE (TYPE_MODE (vectype)), 5470 GET_MODE_SIZE (TYPE_MODE (vectype_in))))) 5471 return false; 5472 5473 if (VECTOR_BOOLEAN_TYPE_P (vectype) != VECTOR_BOOLEAN_TYPE_P (vectype_in)) 5474 { 5475 if (dump_enabled_p ()) 5476 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5477 "can't convert between boolean and non " 5478 "boolean vectors %T\n", TREE_TYPE (op)); 5479 5480 return false; 5481 } 5482 5483 /* We do not handle bit-precision changes. */ 5484 if ((CONVERT_EXPR_CODE_P (code) 5485 || code == VIEW_CONVERT_EXPR) 5486 && INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest)) 5487 && (!type_has_mode_precision_p (TREE_TYPE (scalar_dest)) 5488 || !type_has_mode_precision_p (TREE_TYPE (op))) 5489 /* But a conversion that does not change the bit-pattern is ok. */ 5490 && !((TYPE_PRECISION (TREE_TYPE (scalar_dest)) 5491 > TYPE_PRECISION (TREE_TYPE (op))) 5492 && TYPE_UNSIGNED (TREE_TYPE (op)))) 5493 { 5494 if (dump_enabled_p ()) 5495 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5496 "type conversion to/from bit-precision " 5497 "unsupported.\n"); 5498 return false; 5499 } 5500 5501 if (!vec_stmt) /* transformation not required. */ 5502 { 5503 if (slp_node 5504 && !vect_maybe_update_slp_op_vectype (slp_op, vectype_in)) 5505 { 5506 if (dump_enabled_p ()) 5507 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5508 "incompatible vector types for invariants\n"); 5509 return false; 5510 } 5511 STMT_VINFO_TYPE (stmt_info) = assignment_vec_info_type; 5512 DUMP_VECT_SCOPE ("vectorizable_assignment"); 5513 if (!vect_nop_conversion_p (stmt_info)) 5514 vect_model_simple_cost (vinfo, stmt_info, ncopies, dt, ndts, slp_node, 5515 cost_vec); 5516 return true; 5517 } 5518 5519 /* Transform. */ 5520 if (dump_enabled_p ()) 5521 dump_printf_loc (MSG_NOTE, vect_location, "transform assignment.\n"); 5522 5523 /* Handle def. */ 5524 vec_dest = vect_create_destination_var (scalar_dest, vectype); 5525 5526 /* Handle use. */ 5527 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, op, &vec_oprnds); 5528 5529 /* Arguments are ready. create the new vector stmt. */ 5530 FOR_EACH_VEC_ELT (vec_oprnds, i, vop) 5531 { 5532 if (CONVERT_EXPR_CODE_P (code) 5533 || code == VIEW_CONVERT_EXPR) 5534 vop = build1 (VIEW_CONVERT_EXPR, vectype, vop); 5535 gassign *new_stmt = gimple_build_assign (vec_dest, vop); 5536 new_temp = make_ssa_name (vec_dest, new_stmt); 5537 gimple_assign_set_lhs (new_stmt, new_temp); 5538 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 5539 if (slp_node) 5540 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 5541 else 5542 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 5543 } 5544 if (!slp_node) 5545 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 5546 5547 vec_oprnds.release (); 5548 return true; 5549 } 5550 5551 5552 /* Return TRUE if CODE (a shift operation) is supported for SCALAR_TYPE 5553 either as shift by a scalar or by a vector. */ 5554 5555 bool 5556 vect_supportable_shift (vec_info *vinfo, enum tree_code code, tree scalar_type) 5557 { 5558 5559 machine_mode vec_mode; 5560 optab optab; 5561 int icode; 5562 tree vectype; 5563 5564 vectype = get_vectype_for_scalar_type (vinfo, scalar_type); 5565 if (!vectype) 5566 return false; 5567 5568 optab = optab_for_tree_code (code, vectype, optab_scalar); 5569 if (!optab 5570 || optab_handler (optab, TYPE_MODE (vectype)) == CODE_FOR_nothing) 5571 { 5572 optab = optab_for_tree_code (code, vectype, optab_vector); 5573 if (!optab 5574 || (optab_handler (optab, TYPE_MODE (vectype)) 5575 == CODE_FOR_nothing)) 5576 return false; 5577 } 5578 5579 vec_mode = TYPE_MODE (vectype); 5580 icode = (int) optab_handler (optab, vec_mode); 5581 if (icode == CODE_FOR_nothing) 5582 return false; 5583 5584 return true; 5585 } 5586 5587 5588 /* Function vectorizable_shift. 5589 5590 Check if STMT_INFO performs a shift operation that can be vectorized. 5591 If VEC_STMT is also passed, vectorize the STMT_INFO: create a vectorized 5592 stmt to replace it, put it in VEC_STMT, and insert it at GSI. 5593 Return true if STMT_INFO is vectorizable in this way. */ 5594 5595 static bool 5596 vectorizable_shift (vec_info *vinfo, 5597 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 5598 gimple **vec_stmt, slp_tree slp_node, 5599 stmt_vector_for_cost *cost_vec) 5600 { 5601 tree vec_dest; 5602 tree scalar_dest; 5603 tree op0, op1 = NULL; 5604 tree vec_oprnd1 = NULL_TREE; 5605 tree vectype; 5606 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 5607 enum tree_code code; 5608 machine_mode vec_mode; 5609 tree new_temp; 5610 optab optab; 5611 int icode; 5612 machine_mode optab_op2_mode; 5613 enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type}; 5614 int ndts = 2; 5615 poly_uint64 nunits_in; 5616 poly_uint64 nunits_out; 5617 tree vectype_out; 5618 tree op1_vectype; 5619 int ncopies; 5620 int i; 5621 vec<tree> vec_oprnds0 = vNULL; 5622 vec<tree> vec_oprnds1 = vNULL; 5623 tree vop0, vop1; 5624 unsigned int k; 5625 bool scalar_shift_arg = true; 5626 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 5627 bool incompatible_op1_vectype_p = false; 5628 5629 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 5630 return false; 5631 5632 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def 5633 && STMT_VINFO_DEF_TYPE (stmt_info) != vect_nested_cycle 5634 && ! vec_stmt) 5635 return false; 5636 5637 /* Is STMT a vectorizable binary/unary operation? */ 5638 gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt); 5639 if (!stmt) 5640 return false; 5641 5642 if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME) 5643 return false; 5644 5645 code = gimple_assign_rhs_code (stmt); 5646 5647 if (!(code == LSHIFT_EXPR || code == RSHIFT_EXPR || code == LROTATE_EXPR 5648 || code == RROTATE_EXPR)) 5649 return false; 5650 5651 scalar_dest = gimple_assign_lhs (stmt); 5652 vectype_out = STMT_VINFO_VECTYPE (stmt_info); 5653 if (!type_has_mode_precision_p (TREE_TYPE (scalar_dest))) 5654 { 5655 if (dump_enabled_p ()) 5656 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5657 "bit-precision shifts not supported.\n"); 5658 return false; 5659 } 5660 5661 slp_tree slp_op0; 5662 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 5663 0, &op0, &slp_op0, &dt[0], &vectype)) 5664 { 5665 if (dump_enabled_p ()) 5666 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5667 "use not simple.\n"); 5668 return false; 5669 } 5670 /* If op0 is an external or constant def, infer the vector type 5671 from the scalar type. */ 5672 if (!vectype) 5673 vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0), slp_node); 5674 if (vec_stmt) 5675 gcc_assert (vectype); 5676 if (!vectype) 5677 { 5678 if (dump_enabled_p ()) 5679 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5680 "no vectype for scalar type\n"); 5681 return false; 5682 } 5683 5684 nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out); 5685 nunits_in = TYPE_VECTOR_SUBPARTS (vectype); 5686 if (maybe_ne (nunits_out, nunits_in)) 5687 return false; 5688 5689 stmt_vec_info op1_def_stmt_info; 5690 slp_tree slp_op1; 5691 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1, &op1, &slp_op1, 5692 &dt[1], &op1_vectype, &op1_def_stmt_info)) 5693 { 5694 if (dump_enabled_p ()) 5695 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5696 "use not simple.\n"); 5697 return false; 5698 } 5699 5700 /* Multiple types in SLP are handled by creating the appropriate number of 5701 vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in 5702 case of SLP. */ 5703 if (slp_node) 5704 ncopies = 1; 5705 else 5706 ncopies = vect_get_num_copies (loop_vinfo, vectype); 5707 5708 gcc_assert (ncopies >= 1); 5709 5710 /* Determine whether the shift amount is a vector, or scalar. If the 5711 shift/rotate amount is a vector, use the vector/vector shift optabs. */ 5712 5713 if ((dt[1] == vect_internal_def 5714 || dt[1] == vect_induction_def 5715 || dt[1] == vect_nested_cycle) 5716 && !slp_node) 5717 scalar_shift_arg = false; 5718 else if (dt[1] == vect_constant_def 5719 || dt[1] == vect_external_def 5720 || dt[1] == vect_internal_def) 5721 { 5722 /* In SLP, need to check whether the shift count is the same, 5723 in loops if it is a constant or invariant, it is always 5724 a scalar shift. */ 5725 if (slp_node) 5726 { 5727 vec<stmt_vec_info> stmts = SLP_TREE_SCALAR_STMTS (slp_node); 5728 stmt_vec_info slpstmt_info; 5729 5730 FOR_EACH_VEC_ELT (stmts, k, slpstmt_info) 5731 { 5732 gassign *slpstmt = as_a <gassign *> (slpstmt_info->stmt); 5733 if (!operand_equal_p (gimple_assign_rhs2 (slpstmt), op1, 0)) 5734 scalar_shift_arg = false; 5735 } 5736 5737 /* For internal SLP defs we have to make sure we see scalar stmts 5738 for all vector elements. 5739 ??? For different vectors we could resort to a different 5740 scalar shift operand but code-generation below simply always 5741 takes the first. */ 5742 if (dt[1] == vect_internal_def 5743 && maybe_ne (nunits_out * SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node), 5744 stmts.length ())) 5745 scalar_shift_arg = false; 5746 } 5747 5748 /* If the shift amount is computed by a pattern stmt we cannot 5749 use the scalar amount directly thus give up and use a vector 5750 shift. */ 5751 if (op1_def_stmt_info && is_pattern_stmt_p (op1_def_stmt_info)) 5752 scalar_shift_arg = false; 5753 } 5754 else 5755 { 5756 if (dump_enabled_p ()) 5757 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5758 "operand mode requires invariant argument.\n"); 5759 return false; 5760 } 5761 5762 /* Vector shifted by vector. */ 5763 bool was_scalar_shift_arg = scalar_shift_arg; 5764 if (!scalar_shift_arg) 5765 { 5766 optab = optab_for_tree_code (code, vectype, optab_vector); 5767 if (dump_enabled_p ()) 5768 dump_printf_loc (MSG_NOTE, vect_location, 5769 "vector/vector shift/rotate found.\n"); 5770 5771 if (!op1_vectype) 5772 op1_vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op1), 5773 slp_op1); 5774 incompatible_op1_vectype_p 5775 = (op1_vectype == NULL_TREE 5776 || maybe_ne (TYPE_VECTOR_SUBPARTS (op1_vectype), 5777 TYPE_VECTOR_SUBPARTS (vectype)) 5778 || TYPE_MODE (op1_vectype) != TYPE_MODE (vectype)); 5779 if (incompatible_op1_vectype_p 5780 && (!slp_node 5781 || SLP_TREE_DEF_TYPE (slp_op1) != vect_constant_def 5782 || slp_op1->refcnt != 1)) 5783 { 5784 if (dump_enabled_p ()) 5785 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5786 "unusable type for last operand in" 5787 " vector/vector shift/rotate.\n"); 5788 return false; 5789 } 5790 } 5791 /* See if the machine has a vector shifted by scalar insn and if not 5792 then see if it has a vector shifted by vector insn. */ 5793 else 5794 { 5795 optab = optab_for_tree_code (code, vectype, optab_scalar); 5796 if (optab 5797 && optab_handler (optab, TYPE_MODE (vectype)) != CODE_FOR_nothing) 5798 { 5799 if (dump_enabled_p ()) 5800 dump_printf_loc (MSG_NOTE, vect_location, 5801 "vector/scalar shift/rotate found.\n"); 5802 } 5803 else 5804 { 5805 optab = optab_for_tree_code (code, vectype, optab_vector); 5806 if (optab 5807 && (optab_handler (optab, TYPE_MODE (vectype)) 5808 != CODE_FOR_nothing)) 5809 { 5810 scalar_shift_arg = false; 5811 5812 if (dump_enabled_p ()) 5813 dump_printf_loc (MSG_NOTE, vect_location, 5814 "vector/vector shift/rotate found.\n"); 5815 5816 if (!op1_vectype) 5817 op1_vectype = get_vectype_for_scalar_type (vinfo, 5818 TREE_TYPE (op1), 5819 slp_op1); 5820 5821 /* Unlike the other binary operators, shifts/rotates have 5822 the rhs being int, instead of the same type as the lhs, 5823 so make sure the scalar is the right type if we are 5824 dealing with vectors of long long/long/short/char. */ 5825 incompatible_op1_vectype_p 5826 = (!op1_vectype 5827 || !tree_nop_conversion_p (TREE_TYPE (vectype), 5828 TREE_TYPE (op1))); 5829 if (incompatible_op1_vectype_p 5830 && dt[1] == vect_internal_def) 5831 { 5832 if (dump_enabled_p ()) 5833 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5834 "unusable type for last operand in" 5835 " vector/vector shift/rotate.\n"); 5836 return false; 5837 } 5838 } 5839 } 5840 } 5841 5842 /* Supportable by target? */ 5843 if (!optab) 5844 { 5845 if (dump_enabled_p ()) 5846 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5847 "no optab.\n"); 5848 return false; 5849 } 5850 vec_mode = TYPE_MODE (vectype); 5851 icode = (int) optab_handler (optab, vec_mode); 5852 if (icode == CODE_FOR_nothing) 5853 { 5854 if (dump_enabled_p ()) 5855 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5856 "op not supported by target.\n"); 5857 return false; 5858 } 5859 /* vector lowering cannot optimize vector shifts using word arithmetic. */ 5860 if (vect_emulated_vector_p (vectype)) 5861 return false; 5862 5863 if (!vec_stmt) /* transformation not required. */ 5864 { 5865 if (slp_node 5866 && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype) 5867 || ((!scalar_shift_arg || dt[1] == vect_internal_def) 5868 && (!incompatible_op1_vectype_p 5869 || dt[1] == vect_constant_def) 5870 && !vect_maybe_update_slp_op_vectype 5871 (slp_op1, 5872 incompatible_op1_vectype_p ? vectype : op1_vectype)))) 5873 { 5874 if (dump_enabled_p ()) 5875 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 5876 "incompatible vector types for invariants\n"); 5877 return false; 5878 } 5879 /* Now adjust the constant shift amount in place. */ 5880 if (slp_node 5881 && incompatible_op1_vectype_p 5882 && dt[1] == vect_constant_def) 5883 { 5884 for (unsigned i = 0; 5885 i < SLP_TREE_SCALAR_OPS (slp_op1).length (); ++i) 5886 { 5887 SLP_TREE_SCALAR_OPS (slp_op1)[i] 5888 = fold_convert (TREE_TYPE (vectype), 5889 SLP_TREE_SCALAR_OPS (slp_op1)[i]); 5890 gcc_assert ((TREE_CODE (SLP_TREE_SCALAR_OPS (slp_op1)[i]) 5891 == INTEGER_CST)); 5892 } 5893 } 5894 STMT_VINFO_TYPE (stmt_info) = shift_vec_info_type; 5895 DUMP_VECT_SCOPE ("vectorizable_shift"); 5896 vect_model_simple_cost (vinfo, stmt_info, ncopies, dt, 5897 scalar_shift_arg ? 1 : ndts, slp_node, cost_vec); 5898 return true; 5899 } 5900 5901 /* Transform. */ 5902 5903 if (dump_enabled_p ()) 5904 dump_printf_loc (MSG_NOTE, vect_location, 5905 "transform binary/unary operation.\n"); 5906 5907 if (incompatible_op1_vectype_p && !slp_node) 5908 { 5909 gcc_assert (!scalar_shift_arg && was_scalar_shift_arg); 5910 op1 = fold_convert (TREE_TYPE (vectype), op1); 5911 if (dt[1] != vect_constant_def) 5912 op1 = vect_init_vector (vinfo, stmt_info, op1, 5913 TREE_TYPE (vectype), NULL); 5914 } 5915 5916 /* Handle def. */ 5917 vec_dest = vect_create_destination_var (scalar_dest, vectype); 5918 5919 if (scalar_shift_arg && dt[1] != vect_internal_def) 5920 { 5921 /* Vector shl and shr insn patterns can be defined with scalar 5922 operand 2 (shift operand). In this case, use constant or loop 5923 invariant op1 directly, without extending it to vector mode 5924 first. */ 5925 optab_op2_mode = insn_data[icode].operand[2].mode; 5926 if (!VECTOR_MODE_P (optab_op2_mode)) 5927 { 5928 if (dump_enabled_p ()) 5929 dump_printf_loc (MSG_NOTE, vect_location, 5930 "operand 1 using scalar mode.\n"); 5931 vec_oprnd1 = op1; 5932 vec_oprnds1.create (slp_node ? slp_node->vec_stmts_size : ncopies); 5933 vec_oprnds1.quick_push (vec_oprnd1); 5934 /* Store vec_oprnd1 for every vector stmt to be created. 5935 We check during the analysis that all the shift arguments 5936 are the same. 5937 TODO: Allow different constants for different vector 5938 stmts generated for an SLP instance. */ 5939 for (k = 0; 5940 k < (slp_node ? slp_node->vec_stmts_size - 1 : ncopies - 1); k++) 5941 vec_oprnds1.quick_push (vec_oprnd1); 5942 } 5943 } 5944 else if (!scalar_shift_arg && slp_node && incompatible_op1_vectype_p) 5945 { 5946 if (was_scalar_shift_arg) 5947 { 5948 /* If the argument was the same in all lanes create 5949 the correctly typed vector shift amount directly. */ 5950 op1 = fold_convert (TREE_TYPE (vectype), op1); 5951 op1 = vect_init_vector (vinfo, stmt_info, op1, TREE_TYPE (vectype), 5952 !loop_vinfo ? gsi : NULL); 5953 vec_oprnd1 = vect_init_vector (vinfo, stmt_info, op1, vectype, 5954 !loop_vinfo ? gsi : NULL); 5955 vec_oprnds1.create (slp_node->vec_stmts_size); 5956 for (k = 0; k < slp_node->vec_stmts_size; k++) 5957 vec_oprnds1.quick_push (vec_oprnd1); 5958 } 5959 else if (dt[1] == vect_constant_def) 5960 /* The constant shift amount has been adjusted in place. */ 5961 ; 5962 else 5963 gcc_assert (TYPE_MODE (op1_vectype) == TYPE_MODE (vectype)); 5964 } 5965 5966 /* vec_oprnd1 is available if operand 1 should be of a scalar-type 5967 (a special case for certain kind of vector shifts); otherwise, 5968 operand 1 should be of a vector type (the usual case). */ 5969 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, 5970 op0, &vec_oprnds0, 5971 vec_oprnd1 ? NULL_TREE : op1, &vec_oprnds1); 5972 5973 /* Arguments are ready. Create the new vector stmt. */ 5974 FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0) 5975 { 5976 /* For internal defs where we need to use a scalar shift arg 5977 extract the first lane. */ 5978 if (scalar_shift_arg && dt[1] == vect_internal_def) 5979 { 5980 vop1 = vec_oprnds1[0]; 5981 new_temp = make_ssa_name (TREE_TYPE (TREE_TYPE (vop1))); 5982 gassign *new_stmt 5983 = gimple_build_assign (new_temp, 5984 build3 (BIT_FIELD_REF, TREE_TYPE (new_temp), 5985 vop1, 5986 TYPE_SIZE (TREE_TYPE (new_temp)), 5987 bitsize_zero_node)); 5988 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 5989 vop1 = new_temp; 5990 } 5991 else 5992 vop1 = vec_oprnds1[i]; 5993 gassign *new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1); 5994 new_temp = make_ssa_name (vec_dest, new_stmt); 5995 gimple_assign_set_lhs (new_stmt, new_temp); 5996 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 5997 if (slp_node) 5998 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 5999 else 6000 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 6001 } 6002 6003 if (!slp_node) 6004 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 6005 6006 vec_oprnds0.release (); 6007 vec_oprnds1.release (); 6008 6009 return true; 6010 } 6011 6012 6013 /* Function vectorizable_operation. 6014 6015 Check if STMT_INFO performs a binary, unary or ternary operation that can 6016 be vectorized. 6017 If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized 6018 stmt to replace it, put it in VEC_STMT, and insert it at GSI. 6019 Return true if STMT_INFO is vectorizable in this way. */ 6020 6021 static bool 6022 vectorizable_operation (vec_info *vinfo, 6023 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 6024 gimple **vec_stmt, slp_tree slp_node, 6025 stmt_vector_for_cost *cost_vec) 6026 { 6027 tree vec_dest; 6028 tree scalar_dest; 6029 tree op0, op1 = NULL_TREE, op2 = NULL_TREE; 6030 tree vectype; 6031 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 6032 enum tree_code code, orig_code; 6033 machine_mode vec_mode; 6034 tree new_temp; 6035 int op_type; 6036 optab optab; 6037 bool target_support_p; 6038 enum vect_def_type dt[3] 6039 = {vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type}; 6040 int ndts = 3; 6041 poly_uint64 nunits_in; 6042 poly_uint64 nunits_out; 6043 tree vectype_out; 6044 int ncopies, vec_num; 6045 int i; 6046 vec<tree> vec_oprnds0 = vNULL; 6047 vec<tree> vec_oprnds1 = vNULL; 6048 vec<tree> vec_oprnds2 = vNULL; 6049 tree vop0, vop1, vop2; 6050 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 6051 6052 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 6053 return false; 6054 6055 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def 6056 && ! vec_stmt) 6057 return false; 6058 6059 /* Is STMT a vectorizable binary/unary operation? */ 6060 gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt); 6061 if (!stmt) 6062 return false; 6063 6064 /* Loads and stores are handled in vectorizable_{load,store}. */ 6065 if (STMT_VINFO_DATA_REF (stmt_info)) 6066 return false; 6067 6068 orig_code = code = gimple_assign_rhs_code (stmt); 6069 6070 /* Shifts are handled in vectorizable_shift. */ 6071 if (code == LSHIFT_EXPR 6072 || code == RSHIFT_EXPR 6073 || code == LROTATE_EXPR 6074 || code == RROTATE_EXPR) 6075 return false; 6076 6077 /* Comparisons are handled in vectorizable_comparison. */ 6078 if (TREE_CODE_CLASS (code) == tcc_comparison) 6079 return false; 6080 6081 /* Conditions are handled in vectorizable_condition. */ 6082 if (code == COND_EXPR) 6083 return false; 6084 6085 /* For pointer addition and subtraction, we should use the normal 6086 plus and minus for the vector operation. */ 6087 if (code == POINTER_PLUS_EXPR) 6088 code = PLUS_EXPR; 6089 if (code == POINTER_DIFF_EXPR) 6090 code = MINUS_EXPR; 6091 6092 /* Support only unary or binary operations. */ 6093 op_type = TREE_CODE_LENGTH (code); 6094 if (op_type != unary_op && op_type != binary_op && op_type != ternary_op) 6095 { 6096 if (dump_enabled_p ()) 6097 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6098 "num. args = %d (not unary/binary/ternary op).\n", 6099 op_type); 6100 return false; 6101 } 6102 6103 scalar_dest = gimple_assign_lhs (stmt); 6104 vectype_out = STMT_VINFO_VECTYPE (stmt_info); 6105 6106 /* Most operations cannot handle bit-precision types without extra 6107 truncations. */ 6108 bool mask_op_p = VECTOR_BOOLEAN_TYPE_P (vectype_out); 6109 if (!mask_op_p 6110 && !type_has_mode_precision_p (TREE_TYPE (scalar_dest)) 6111 /* Exception are bitwise binary operations. */ 6112 && code != BIT_IOR_EXPR 6113 && code != BIT_XOR_EXPR 6114 && code != BIT_AND_EXPR) 6115 { 6116 if (dump_enabled_p ()) 6117 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6118 "bit-precision arithmetic not supported.\n"); 6119 return false; 6120 } 6121 6122 slp_tree slp_op0; 6123 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 6124 0, &op0, &slp_op0, &dt[0], &vectype)) 6125 { 6126 if (dump_enabled_p ()) 6127 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6128 "use not simple.\n"); 6129 return false; 6130 } 6131 bool is_invariant = (dt[0] == vect_external_def 6132 || dt[0] == vect_constant_def); 6133 /* If op0 is an external or constant def, infer the vector type 6134 from the scalar type. */ 6135 if (!vectype) 6136 { 6137 /* For boolean type we cannot determine vectype by 6138 invariant value (don't know whether it is a vector 6139 of booleans or vector of integers). We use output 6140 vectype because operations on boolean don't change 6141 type. */ 6142 if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op0))) 6143 { 6144 if (!VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (scalar_dest))) 6145 { 6146 if (dump_enabled_p ()) 6147 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6148 "not supported operation on bool value.\n"); 6149 return false; 6150 } 6151 vectype = vectype_out; 6152 } 6153 else 6154 vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0), 6155 slp_node); 6156 } 6157 if (vec_stmt) 6158 gcc_assert (vectype); 6159 if (!vectype) 6160 { 6161 if (dump_enabled_p ()) 6162 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6163 "no vectype for scalar type %T\n", 6164 TREE_TYPE (op0)); 6165 6166 return false; 6167 } 6168 6169 nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out); 6170 nunits_in = TYPE_VECTOR_SUBPARTS (vectype); 6171 if (maybe_ne (nunits_out, nunits_in)) 6172 return false; 6173 6174 tree vectype2 = NULL_TREE, vectype3 = NULL_TREE; 6175 slp_tree slp_op1 = NULL, slp_op2 = NULL; 6176 if (op_type == binary_op || op_type == ternary_op) 6177 { 6178 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 6179 1, &op1, &slp_op1, &dt[1], &vectype2)) 6180 { 6181 if (dump_enabled_p ()) 6182 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6183 "use not simple.\n"); 6184 return false; 6185 } 6186 is_invariant &= (dt[1] == vect_external_def 6187 || dt[1] == vect_constant_def); 6188 if (vectype2 6189 && maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype2))) 6190 return false; 6191 } 6192 if (op_type == ternary_op) 6193 { 6194 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 6195 2, &op2, &slp_op2, &dt[2], &vectype3)) 6196 { 6197 if (dump_enabled_p ()) 6198 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6199 "use not simple.\n"); 6200 return false; 6201 } 6202 is_invariant &= (dt[2] == vect_external_def 6203 || dt[2] == vect_constant_def); 6204 if (vectype3 6205 && maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype3))) 6206 return false; 6207 } 6208 6209 /* Multiple types in SLP are handled by creating the appropriate number of 6210 vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in 6211 case of SLP. */ 6212 if (slp_node) 6213 { 6214 ncopies = 1; 6215 vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 6216 } 6217 else 6218 { 6219 ncopies = vect_get_num_copies (loop_vinfo, vectype); 6220 vec_num = 1; 6221 } 6222 6223 gcc_assert (ncopies >= 1); 6224 6225 /* Reject attempts to combine mask types with nonmask types, e.g. if 6226 we have an AND between a (nonmask) boolean loaded from memory and 6227 a (mask) boolean result of a comparison. 6228 6229 TODO: We could easily fix these cases up using pattern statements. */ 6230 if (VECTOR_BOOLEAN_TYPE_P (vectype) != mask_op_p 6231 || (vectype2 && VECTOR_BOOLEAN_TYPE_P (vectype2) != mask_op_p) 6232 || (vectype3 && VECTOR_BOOLEAN_TYPE_P (vectype3) != mask_op_p)) 6233 { 6234 if (dump_enabled_p ()) 6235 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6236 "mixed mask and nonmask vector types\n"); 6237 return false; 6238 } 6239 6240 /* Supportable by target? */ 6241 6242 vec_mode = TYPE_MODE (vectype); 6243 if (code == MULT_HIGHPART_EXPR) 6244 target_support_p = can_mult_highpart_p (vec_mode, TYPE_UNSIGNED (vectype)); 6245 else 6246 { 6247 optab = optab_for_tree_code (code, vectype, optab_default); 6248 if (!optab) 6249 { 6250 if (dump_enabled_p ()) 6251 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6252 "no optab.\n"); 6253 return false; 6254 } 6255 target_support_p = (optab_handler (optab, vec_mode) 6256 != CODE_FOR_nothing); 6257 } 6258 6259 bool using_emulated_vectors_p = vect_emulated_vector_p (vectype); 6260 if (!target_support_p) 6261 { 6262 if (dump_enabled_p ()) 6263 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6264 "op not supported by target.\n"); 6265 /* Check only during analysis. */ 6266 if (maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD) 6267 || (!vec_stmt && !vect_can_vectorize_without_simd_p (code))) 6268 return false; 6269 if (dump_enabled_p ()) 6270 dump_printf_loc (MSG_NOTE, vect_location, 6271 "proceeding using word mode.\n"); 6272 using_emulated_vectors_p = true; 6273 } 6274 6275 if (using_emulated_vectors_p 6276 && !vect_can_vectorize_without_simd_p (code)) 6277 { 6278 if (dump_enabled_p ()) 6279 dump_printf (MSG_NOTE, "using word mode not possible.\n"); 6280 return false; 6281 } 6282 6283 /* ??? We should instead expand the operations here, instead of 6284 relying on vector lowering which has this hard cap on the number 6285 of vector elements below it performs elementwise operations. */ 6286 if (using_emulated_vectors_p 6287 && (code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR) 6288 && ((BITS_PER_WORD / vector_element_bits (vectype)) < 4 6289 || maybe_lt (nunits_out, 4U))) 6290 { 6291 if (dump_enabled_p ()) 6292 dump_printf (MSG_NOTE, "not using word mode for +- and less than " 6293 "four vector elements\n"); 6294 return false; 6295 } 6296 6297 int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info); 6298 vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL); 6299 internal_fn cond_fn = get_conditional_internal_fn (code); 6300 6301 /* If operating on inactive elements could generate spurious traps, 6302 we need to restrict the operation to active lanes. Note that this 6303 specifically doesn't apply to unhoisted invariants, since they 6304 operate on the same value for every lane. 6305 6306 Similarly, if this operation is part of a reduction, a fully-masked 6307 loop should only change the active lanes of the reduction chain, 6308 keeping the inactive lanes as-is. */ 6309 bool mask_out_inactive = ((!is_invariant && gimple_could_trap_p (stmt)) 6310 || reduc_idx >= 0); 6311 6312 if (!vec_stmt) /* transformation not required. */ 6313 { 6314 if (loop_vinfo 6315 && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) 6316 && mask_out_inactive) 6317 { 6318 if (cond_fn == IFN_LAST 6319 || !direct_internal_fn_supported_p (cond_fn, vectype, 6320 OPTIMIZE_FOR_SPEED)) 6321 { 6322 if (dump_enabled_p ()) 6323 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6324 "can't use a fully-masked loop because no" 6325 " conditional operation is available.\n"); 6326 LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; 6327 } 6328 else 6329 vect_record_loop_mask (loop_vinfo, masks, ncopies * vec_num, 6330 vectype, NULL); 6331 } 6332 6333 /* Put types on constant and invariant SLP children. */ 6334 if (slp_node 6335 && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype) 6336 || !vect_maybe_update_slp_op_vectype (slp_op1, vectype) 6337 || !vect_maybe_update_slp_op_vectype (slp_op2, vectype))) 6338 { 6339 if (dump_enabled_p ()) 6340 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6341 "incompatible vector types for invariants\n"); 6342 return false; 6343 } 6344 6345 STMT_VINFO_TYPE (stmt_info) = op_vec_info_type; 6346 DUMP_VECT_SCOPE ("vectorizable_operation"); 6347 vect_model_simple_cost (vinfo, stmt_info, 6348 ncopies, dt, ndts, slp_node, cost_vec); 6349 if (using_emulated_vectors_p) 6350 { 6351 /* The above vect_model_simple_cost call handles constants 6352 in the prologue and (mis-)costs one of the stmts as 6353 vector stmt. See tree-vect-generic.cc:do_plus_minus/do_negate 6354 for the actual lowering that will be applied. */ 6355 unsigned n 6356 = slp_node ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies; 6357 switch (code) 6358 { 6359 case PLUS_EXPR: 6360 n *= 5; 6361 break; 6362 case MINUS_EXPR: 6363 n *= 6; 6364 break; 6365 case NEGATE_EXPR: 6366 n *= 4; 6367 break; 6368 default:; 6369 } 6370 record_stmt_cost (cost_vec, n, scalar_stmt, stmt_info, 0, vect_body); 6371 } 6372 return true; 6373 } 6374 6375 /* Transform. */ 6376 6377 if (dump_enabled_p ()) 6378 dump_printf_loc (MSG_NOTE, vect_location, 6379 "transform binary/unary operation.\n"); 6380 6381 bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo); 6382 6383 /* POINTER_DIFF_EXPR has pointer arguments which are vectorized as 6384 vectors with unsigned elements, but the result is signed. So, we 6385 need to compute the MINUS_EXPR into vectype temporary and 6386 VIEW_CONVERT_EXPR it into the final vectype_out result. */ 6387 tree vec_cvt_dest = NULL_TREE; 6388 if (orig_code == POINTER_DIFF_EXPR) 6389 { 6390 vec_dest = vect_create_destination_var (scalar_dest, vectype); 6391 vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out); 6392 } 6393 /* Handle def. */ 6394 else 6395 vec_dest = vect_create_destination_var (scalar_dest, vectype_out); 6396 6397 /* In case the vectorization factor (VF) is bigger than the number 6398 of elements that we can fit in a vectype (nunits), we have to generate 6399 more than one vector stmt - i.e - we need to "unroll" the 6400 vector stmt by a factor VF/nunits. In doing so, we record a pointer 6401 from one copy of the vector stmt to the next, in the field 6402 STMT_VINFO_RELATED_STMT. This is necessary in order to allow following 6403 stages to find the correct vector defs to be used when vectorizing 6404 stmts that use the defs of the current stmt. The example below 6405 illustrates the vectorization process when VF=16 and nunits=4 (i.e., 6406 we need to create 4 vectorized stmts): 6407 6408 before vectorization: 6409 RELATED_STMT VEC_STMT 6410 S1: x = memref - - 6411 S2: z = x + 1 - - 6412 6413 step 1: vectorize stmt S1 (done in vectorizable_load. See more details 6414 there): 6415 RELATED_STMT VEC_STMT 6416 VS1_0: vx0 = memref0 VS1_1 - 6417 VS1_1: vx1 = memref1 VS1_2 - 6418 VS1_2: vx2 = memref2 VS1_3 - 6419 VS1_3: vx3 = memref3 - - 6420 S1: x = load - VS1_0 6421 S2: z = x + 1 - - 6422 6423 step2: vectorize stmt S2 (done here): 6424 To vectorize stmt S2 we first need to find the relevant vector 6425 def for the first operand 'x'. This is, as usual, obtained from 6426 the vector stmt recorded in the STMT_VINFO_VEC_STMT of the stmt 6427 that defines 'x' (S1). This way we find the stmt VS1_0, and the 6428 relevant vector def 'vx0'. Having found 'vx0' we can generate 6429 the vector stmt VS2_0, and as usual, record it in the 6430 STMT_VINFO_VEC_STMT of stmt S2. 6431 When creating the second copy (VS2_1), we obtain the relevant vector 6432 def from the vector stmt recorded in the STMT_VINFO_RELATED_STMT of 6433 stmt VS1_0. This way we find the stmt VS1_1 and the relevant 6434 vector def 'vx1'. Using 'vx1' we create stmt VS2_1 and record a 6435 pointer to it in the STMT_VINFO_RELATED_STMT of the vector stmt VS2_0. 6436 Similarly when creating stmts VS2_2 and VS2_3. This is the resulting 6437 chain of stmts and pointers: 6438 RELATED_STMT VEC_STMT 6439 VS1_0: vx0 = memref0 VS1_1 - 6440 VS1_1: vx1 = memref1 VS1_2 - 6441 VS1_2: vx2 = memref2 VS1_3 - 6442 VS1_3: vx3 = memref3 - - 6443 S1: x = load - VS1_0 6444 VS2_0: vz0 = vx0 + v1 VS2_1 - 6445 VS2_1: vz1 = vx1 + v1 VS2_2 - 6446 VS2_2: vz2 = vx2 + v1 VS2_3 - 6447 VS2_3: vz3 = vx3 + v1 - - 6448 S2: z = x + 1 - VS2_0 */ 6449 6450 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, 6451 op0, &vec_oprnds0, op1, &vec_oprnds1, op2, &vec_oprnds2); 6452 /* Arguments are ready. Create the new vector stmt. */ 6453 FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0) 6454 { 6455 gimple *new_stmt = NULL; 6456 vop1 = ((op_type == binary_op || op_type == ternary_op) 6457 ? vec_oprnds1[i] : NULL_TREE); 6458 vop2 = ((op_type == ternary_op) ? vec_oprnds2[i] : NULL_TREE); 6459 if (masked_loop_p && mask_out_inactive) 6460 { 6461 tree mask = vect_get_loop_mask (gsi, masks, vec_num * ncopies, 6462 vectype, i); 6463 auto_vec<tree> vops (5); 6464 vops.quick_push (mask); 6465 vops.quick_push (vop0); 6466 if (vop1) 6467 vops.quick_push (vop1); 6468 if (vop2) 6469 vops.quick_push (vop2); 6470 if (reduc_idx >= 0) 6471 { 6472 /* Perform the operation on active elements only and take 6473 inactive elements from the reduction chain input. */ 6474 gcc_assert (!vop2); 6475 vops.quick_push (reduc_idx == 1 ? vop1 : vop0); 6476 } 6477 else 6478 { 6479 auto else_value = targetm.preferred_else_value 6480 (cond_fn, vectype, vops.length () - 1, &vops[1]); 6481 vops.quick_push (else_value); 6482 } 6483 gcall *call = gimple_build_call_internal_vec (cond_fn, vops); 6484 new_temp = make_ssa_name (vec_dest, call); 6485 gimple_call_set_lhs (call, new_temp); 6486 gimple_call_set_nothrow (call, true); 6487 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 6488 new_stmt = call; 6489 } 6490 else 6491 { 6492 tree mask = NULL_TREE; 6493 /* When combining two masks check if either of them is elsewhere 6494 combined with a loop mask, if that's the case we can mark that the 6495 new combined mask doesn't need to be combined with a loop mask. */ 6496 if (masked_loop_p 6497 && code == BIT_AND_EXPR 6498 && VECTOR_BOOLEAN_TYPE_P (vectype)) 6499 { 6500 if (loop_vinfo->scalar_cond_masked_set.contains ({ op0, 6501 ncopies})) 6502 { 6503 mask = vect_get_loop_mask (gsi, masks, vec_num * ncopies, 6504 vectype, i); 6505 6506 vop0 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask, 6507 vop0, gsi); 6508 } 6509 6510 if (loop_vinfo->scalar_cond_masked_set.contains ({ op1, 6511 ncopies })) 6512 { 6513 mask = vect_get_loop_mask (gsi, masks, vec_num * ncopies, 6514 vectype, i); 6515 6516 vop1 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask, 6517 vop1, gsi); 6518 } 6519 } 6520 6521 new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1, vop2); 6522 new_temp = make_ssa_name (vec_dest, new_stmt); 6523 gimple_assign_set_lhs (new_stmt, new_temp); 6524 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 6525 if (using_emulated_vectors_p) 6526 suppress_warning (new_stmt, OPT_Wvector_operation_performance); 6527 6528 /* Enter the combined value into the vector cond hash so we don't 6529 AND it with a loop mask again. */ 6530 if (mask) 6531 loop_vinfo->vec_cond_masked_set.add ({ new_temp, mask }); 6532 6533 if (vec_cvt_dest) 6534 { 6535 new_temp = build1 (VIEW_CONVERT_EXPR, vectype_out, new_temp); 6536 new_stmt = gimple_build_assign (vec_cvt_dest, VIEW_CONVERT_EXPR, 6537 new_temp); 6538 new_temp = make_ssa_name (vec_cvt_dest, new_stmt); 6539 gimple_assign_set_lhs (new_stmt, new_temp); 6540 vect_finish_stmt_generation (vinfo, stmt_info, 6541 new_stmt, gsi); 6542 } 6543 } 6544 if (slp_node) 6545 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 6546 else 6547 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 6548 } 6549 6550 if (!slp_node) 6551 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 6552 6553 vec_oprnds0.release (); 6554 vec_oprnds1.release (); 6555 vec_oprnds2.release (); 6556 6557 return true; 6558 } 6559 6560 /* A helper function to ensure data reference DR_INFO's base alignment. */ 6561 6562 static void 6563 ensure_base_align (dr_vec_info *dr_info) 6564 { 6565 /* Alignment is only analyzed for the first element of a DR group, 6566 use that to look at base alignment we need to enforce. */ 6567 if (STMT_VINFO_GROUPED_ACCESS (dr_info->stmt)) 6568 dr_info = STMT_VINFO_DR_INFO (DR_GROUP_FIRST_ELEMENT (dr_info->stmt)); 6569 6570 gcc_assert (dr_info->misalignment != DR_MISALIGNMENT_UNINITIALIZED); 6571 6572 if (dr_info->base_misaligned) 6573 { 6574 tree base_decl = dr_info->base_decl; 6575 6576 // We should only be able to increase the alignment of a base object if 6577 // we know what its new alignment should be at compile time. 6578 unsigned HOST_WIDE_INT align_base_to = 6579 DR_TARGET_ALIGNMENT (dr_info).to_constant () * BITS_PER_UNIT; 6580 6581 if (decl_in_symtab_p (base_decl)) 6582 symtab_node::get (base_decl)->increase_alignment (align_base_to); 6583 else if (DECL_ALIGN (base_decl) < align_base_to) 6584 { 6585 SET_DECL_ALIGN (base_decl, align_base_to); 6586 DECL_USER_ALIGN (base_decl) = 1; 6587 } 6588 dr_info->base_misaligned = false; 6589 } 6590 } 6591 6592 6593 /* Function get_group_alias_ptr_type. 6594 6595 Return the alias type for the group starting at FIRST_STMT_INFO. */ 6596 6597 static tree 6598 get_group_alias_ptr_type (stmt_vec_info first_stmt_info) 6599 { 6600 struct data_reference *first_dr, *next_dr; 6601 6602 first_dr = STMT_VINFO_DATA_REF (first_stmt_info); 6603 stmt_vec_info next_stmt_info = DR_GROUP_NEXT_ELEMENT (first_stmt_info); 6604 while (next_stmt_info) 6605 { 6606 next_dr = STMT_VINFO_DATA_REF (next_stmt_info); 6607 if (get_alias_set (DR_REF (first_dr)) 6608 != get_alias_set (DR_REF (next_dr))) 6609 { 6610 if (dump_enabled_p ()) 6611 dump_printf_loc (MSG_NOTE, vect_location, 6612 "conflicting alias set types.\n"); 6613 return ptr_type_node; 6614 } 6615 next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); 6616 } 6617 return reference_alias_ptr_type (DR_REF (first_dr)); 6618 } 6619 6620 6621 /* Function scan_operand_equal_p. 6622 6623 Helper function for check_scan_store. Compare two references 6624 with .GOMP_SIMD_LANE bases. */ 6625 6626 static bool 6627 scan_operand_equal_p (tree ref1, tree ref2) 6628 { 6629 tree ref[2] = { ref1, ref2 }; 6630 poly_int64 bitsize[2], bitpos[2]; 6631 tree offset[2], base[2]; 6632 for (int i = 0; i < 2; ++i) 6633 { 6634 machine_mode mode; 6635 int unsignedp, reversep, volatilep = 0; 6636 base[i] = get_inner_reference (ref[i], &bitsize[i], &bitpos[i], 6637 &offset[i], &mode, &unsignedp, 6638 &reversep, &volatilep); 6639 if (reversep || volatilep || maybe_ne (bitpos[i], 0)) 6640 return false; 6641 if (TREE_CODE (base[i]) == MEM_REF 6642 && offset[i] == NULL_TREE 6643 && TREE_CODE (TREE_OPERAND (base[i], 0)) == SSA_NAME) 6644 { 6645 gimple *def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (base[i], 0)); 6646 if (is_gimple_assign (def_stmt) 6647 && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR 6648 && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == ADDR_EXPR 6649 && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME) 6650 { 6651 if (maybe_ne (mem_ref_offset (base[i]), 0)) 6652 return false; 6653 base[i] = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0); 6654 offset[i] = gimple_assign_rhs2 (def_stmt); 6655 } 6656 } 6657 } 6658 6659 if (!operand_equal_p (base[0], base[1], 0)) 6660 return false; 6661 if (maybe_ne (bitsize[0], bitsize[1])) 6662 return false; 6663 if (offset[0] != offset[1]) 6664 { 6665 if (!offset[0] || !offset[1]) 6666 return false; 6667 if (!operand_equal_p (offset[0], offset[1], 0)) 6668 { 6669 tree step[2]; 6670 for (int i = 0; i < 2; ++i) 6671 { 6672 step[i] = integer_one_node; 6673 if (TREE_CODE (offset[i]) == SSA_NAME) 6674 { 6675 gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]); 6676 if (is_gimple_assign (def_stmt) 6677 && gimple_assign_rhs_code (def_stmt) == MULT_EXPR 6678 && (TREE_CODE (gimple_assign_rhs2 (def_stmt)) 6679 == INTEGER_CST)) 6680 { 6681 step[i] = gimple_assign_rhs2 (def_stmt); 6682 offset[i] = gimple_assign_rhs1 (def_stmt); 6683 } 6684 } 6685 else if (TREE_CODE (offset[i]) == MULT_EXPR) 6686 { 6687 step[i] = TREE_OPERAND (offset[i], 1); 6688 offset[i] = TREE_OPERAND (offset[i], 0); 6689 } 6690 tree rhs1 = NULL_TREE; 6691 if (TREE_CODE (offset[i]) == SSA_NAME) 6692 { 6693 gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]); 6694 if (gimple_assign_cast_p (def_stmt)) 6695 rhs1 = gimple_assign_rhs1 (def_stmt); 6696 } 6697 else if (CONVERT_EXPR_P (offset[i])) 6698 rhs1 = TREE_OPERAND (offset[i], 0); 6699 if (rhs1 6700 && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)) 6701 && INTEGRAL_TYPE_P (TREE_TYPE (offset[i])) 6702 && (TYPE_PRECISION (TREE_TYPE (offset[i])) 6703 >= TYPE_PRECISION (TREE_TYPE (rhs1)))) 6704 offset[i] = rhs1; 6705 } 6706 if (!operand_equal_p (offset[0], offset[1], 0) 6707 || !operand_equal_p (step[0], step[1], 0)) 6708 return false; 6709 } 6710 } 6711 return true; 6712 } 6713 6714 6715 enum scan_store_kind { 6716 /* Normal permutation. */ 6717 scan_store_kind_perm, 6718 6719 /* Whole vector left shift permutation with zero init. */ 6720 scan_store_kind_lshift_zero, 6721 6722 /* Whole vector left shift permutation and VEC_COND_EXPR. */ 6723 scan_store_kind_lshift_cond 6724 }; 6725 6726 /* Function check_scan_store. 6727 6728 Verify if we can perform the needed permutations or whole vector shifts. 6729 Return -1 on failure, otherwise exact log2 of vectype's nunits. 6730 USE_WHOLE_VECTOR is a vector of enum scan_store_kind which operation 6731 to do at each step. */ 6732 6733 static int 6734 scan_store_can_perm_p (tree vectype, tree init, 6735 vec<enum scan_store_kind> *use_whole_vector = NULL) 6736 { 6737 enum machine_mode vec_mode = TYPE_MODE (vectype); 6738 unsigned HOST_WIDE_INT nunits; 6739 if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits)) 6740 return -1; 6741 int units_log2 = exact_log2 (nunits); 6742 if (units_log2 <= 0) 6743 return -1; 6744 6745 int i; 6746 enum scan_store_kind whole_vector_shift_kind = scan_store_kind_perm; 6747 for (i = 0; i <= units_log2; ++i) 6748 { 6749 unsigned HOST_WIDE_INT j, k; 6750 enum scan_store_kind kind = scan_store_kind_perm; 6751 vec_perm_builder sel (nunits, nunits, 1); 6752 sel.quick_grow (nunits); 6753 if (i == units_log2) 6754 { 6755 for (j = 0; j < nunits; ++j) 6756 sel[j] = nunits - 1; 6757 } 6758 else 6759 { 6760 for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j) 6761 sel[j] = j; 6762 for (k = 0; j < nunits; ++j, ++k) 6763 sel[j] = nunits + k; 6764 } 6765 vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits); 6766 if (!can_vec_perm_const_p (vec_mode, indices)) 6767 { 6768 if (i == units_log2) 6769 return -1; 6770 6771 if (whole_vector_shift_kind == scan_store_kind_perm) 6772 { 6773 if (optab_handler (vec_shl_optab, vec_mode) == CODE_FOR_nothing) 6774 return -1; 6775 whole_vector_shift_kind = scan_store_kind_lshift_zero; 6776 /* Whole vector shifts shift in zeros, so if init is all zero 6777 constant, there is no need to do anything further. */ 6778 if ((TREE_CODE (init) != INTEGER_CST 6779 && TREE_CODE (init) != REAL_CST) 6780 || !initializer_zerop (init)) 6781 { 6782 tree masktype = truth_type_for (vectype); 6783 if (!expand_vec_cond_expr_p (vectype, masktype, VECTOR_CST)) 6784 return -1; 6785 whole_vector_shift_kind = scan_store_kind_lshift_cond; 6786 } 6787 } 6788 kind = whole_vector_shift_kind; 6789 } 6790 if (use_whole_vector) 6791 { 6792 if (kind != scan_store_kind_perm && use_whole_vector->is_empty ()) 6793 use_whole_vector->safe_grow_cleared (i, true); 6794 if (kind != scan_store_kind_perm || !use_whole_vector->is_empty ()) 6795 use_whole_vector->safe_push (kind); 6796 } 6797 } 6798 6799 return units_log2; 6800 } 6801 6802 6803 /* Function check_scan_store. 6804 6805 Check magic stores for #pragma omp scan {in,ex}clusive reductions. */ 6806 6807 static bool 6808 check_scan_store (vec_info *vinfo, stmt_vec_info stmt_info, tree vectype, 6809 enum vect_def_type rhs_dt, bool slp, tree mask, 6810 vect_memory_access_type memory_access_type) 6811 { 6812 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 6813 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info); 6814 tree ref_type; 6815 6816 gcc_assert (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1); 6817 if (slp 6818 || mask 6819 || memory_access_type != VMAT_CONTIGUOUS 6820 || TREE_CODE (DR_BASE_ADDRESS (dr_info->dr)) != ADDR_EXPR 6821 || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0)) 6822 || loop_vinfo == NULL 6823 || LOOP_VINFO_FULLY_MASKED_P (loop_vinfo) 6824 || STMT_VINFO_GROUPED_ACCESS (stmt_info) 6825 || !integer_zerop (get_dr_vinfo_offset (vinfo, dr_info)) 6826 || !integer_zerop (DR_INIT (dr_info->dr)) 6827 || !(ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr))) 6828 || !alias_sets_conflict_p (get_alias_set (vectype), 6829 get_alias_set (TREE_TYPE (ref_type)))) 6830 { 6831 if (dump_enabled_p ()) 6832 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6833 "unsupported OpenMP scan store.\n"); 6834 return false; 6835 } 6836 6837 /* We need to pattern match code built by OpenMP lowering and simplified 6838 by following optimizations into something we can handle. 6839 #pragma omp simd reduction(inscan,+:r) 6840 for (...) 6841 { 6842 r += something (); 6843 #pragma omp scan inclusive (r) 6844 use (r); 6845 } 6846 shall have body with: 6847 // Initialization for input phase, store the reduction initializer: 6848 _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0); 6849 _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1); 6850 D.2042[_21] = 0; 6851 // Actual input phase: 6852 ... 6853 r.0_5 = D.2042[_20]; 6854 _6 = _4 + r.0_5; 6855 D.2042[_20] = _6; 6856 // Initialization for scan phase: 6857 _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 2); 6858 _26 = D.2043[_25]; 6859 _27 = D.2042[_25]; 6860 _28 = _26 + _27; 6861 D.2043[_25] = _28; 6862 D.2042[_25] = _28; 6863 // Actual scan phase: 6864 ... 6865 r.1_8 = D.2042[_20]; 6866 ... 6867 The "omp simd array" variable D.2042 holds the privatized copy used 6868 inside of the loop and D.2043 is another one that holds copies of 6869 the current original list item. The separate GOMP_SIMD_LANE ifn 6870 kinds are there in order to allow optimizing the initializer store 6871 and combiner sequence, e.g. if it is originally some C++ish user 6872 defined reduction, but allow the vectorizer to pattern recognize it 6873 and turn into the appropriate vectorized scan. 6874 6875 For exclusive scan, this is slightly different: 6876 #pragma omp simd reduction(inscan,+:r) 6877 for (...) 6878 { 6879 use (r); 6880 #pragma omp scan exclusive (r) 6881 r += something (); 6882 } 6883 shall have body with: 6884 // Initialization for input phase, store the reduction initializer: 6885 _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0); 6886 _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1); 6887 D.2042[_21] = 0; 6888 // Actual input phase: 6889 ... 6890 r.0_5 = D.2042[_20]; 6891 _6 = _4 + r.0_5; 6892 D.2042[_20] = _6; 6893 // Initialization for scan phase: 6894 _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 3); 6895 _26 = D.2043[_25]; 6896 D.2044[_25] = _26; 6897 _27 = D.2042[_25]; 6898 _28 = _26 + _27; 6899 D.2043[_25] = _28; 6900 // Actual scan phase: 6901 ... 6902 r.1_8 = D.2044[_20]; 6903 ... */ 6904 6905 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 2) 6906 { 6907 /* Match the D.2042[_21] = 0; store above. Just require that 6908 it is a constant or external definition store. */ 6909 if (rhs_dt != vect_constant_def && rhs_dt != vect_external_def) 6910 { 6911 fail_init: 6912 if (dump_enabled_p ()) 6913 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6914 "unsupported OpenMP scan initializer store.\n"); 6915 return false; 6916 } 6917 6918 if (! loop_vinfo->scan_map) 6919 loop_vinfo->scan_map = new hash_map<tree, tree>; 6920 tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0); 6921 tree &cached = loop_vinfo->scan_map->get_or_insert (var); 6922 if (cached) 6923 goto fail_init; 6924 cached = gimple_assign_rhs1 (STMT_VINFO_STMT (stmt_info)); 6925 6926 /* These stores can be vectorized normally. */ 6927 return true; 6928 } 6929 6930 if (rhs_dt != vect_internal_def) 6931 { 6932 fail: 6933 if (dump_enabled_p ()) 6934 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 6935 "unsupported OpenMP scan combiner pattern.\n"); 6936 return false; 6937 } 6938 6939 gimple *stmt = STMT_VINFO_STMT (stmt_info); 6940 tree rhs = gimple_assign_rhs1 (stmt); 6941 if (TREE_CODE (rhs) != SSA_NAME) 6942 goto fail; 6943 6944 gimple *other_store_stmt = NULL; 6945 tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0); 6946 bool inscan_var_store 6947 = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL; 6948 6949 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4) 6950 { 6951 if (!inscan_var_store) 6952 { 6953 use_operand_p use_p; 6954 imm_use_iterator iter; 6955 FOR_EACH_IMM_USE_FAST (use_p, iter, rhs) 6956 { 6957 gimple *use_stmt = USE_STMT (use_p); 6958 if (use_stmt == stmt || is_gimple_debug (use_stmt)) 6959 continue; 6960 if (gimple_bb (use_stmt) != gimple_bb (stmt) 6961 || !is_gimple_assign (use_stmt) 6962 || gimple_assign_rhs_class (use_stmt) != GIMPLE_BINARY_RHS 6963 || other_store_stmt 6964 || TREE_CODE (gimple_assign_lhs (use_stmt)) != SSA_NAME) 6965 goto fail; 6966 other_store_stmt = use_stmt; 6967 } 6968 if (other_store_stmt == NULL) 6969 goto fail; 6970 rhs = gimple_assign_lhs (other_store_stmt); 6971 if (!single_imm_use (rhs, &use_p, &other_store_stmt)) 6972 goto fail; 6973 } 6974 } 6975 else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3) 6976 { 6977 use_operand_p use_p; 6978 imm_use_iterator iter; 6979 FOR_EACH_IMM_USE_FAST (use_p, iter, rhs) 6980 { 6981 gimple *use_stmt = USE_STMT (use_p); 6982 if (use_stmt == stmt || is_gimple_debug (use_stmt)) 6983 continue; 6984 if (other_store_stmt) 6985 goto fail; 6986 other_store_stmt = use_stmt; 6987 } 6988 } 6989 else 6990 goto fail; 6991 6992 gimple *def_stmt = SSA_NAME_DEF_STMT (rhs); 6993 if (gimple_bb (def_stmt) != gimple_bb (stmt) 6994 || !is_gimple_assign (def_stmt) 6995 || gimple_assign_rhs_class (def_stmt) != GIMPLE_BINARY_RHS) 6996 goto fail; 6997 6998 enum tree_code code = gimple_assign_rhs_code (def_stmt); 6999 /* For pointer addition, we should use the normal plus for the vector 7000 operation. */ 7001 switch (code) 7002 { 7003 case POINTER_PLUS_EXPR: 7004 code = PLUS_EXPR; 7005 break; 7006 case MULT_HIGHPART_EXPR: 7007 goto fail; 7008 default: 7009 break; 7010 } 7011 if (TREE_CODE_LENGTH (code) != binary_op || !commutative_tree_code (code)) 7012 goto fail; 7013 7014 tree rhs1 = gimple_assign_rhs1 (def_stmt); 7015 tree rhs2 = gimple_assign_rhs2 (def_stmt); 7016 if (TREE_CODE (rhs1) != SSA_NAME || TREE_CODE (rhs2) != SSA_NAME) 7017 goto fail; 7018 7019 gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1); 7020 gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2); 7021 if (gimple_bb (load1_stmt) != gimple_bb (stmt) 7022 || !gimple_assign_load_p (load1_stmt) 7023 || gimple_bb (load2_stmt) != gimple_bb (stmt) 7024 || !gimple_assign_load_p (load2_stmt)) 7025 goto fail; 7026 7027 stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt); 7028 stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt); 7029 if (load1_stmt_info == NULL 7030 || load2_stmt_info == NULL 7031 || (STMT_VINFO_SIMD_LANE_ACCESS_P (load1_stmt_info) 7032 != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)) 7033 || (STMT_VINFO_SIMD_LANE_ACCESS_P (load2_stmt_info) 7034 != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info))) 7035 goto fail; 7036 7037 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && inscan_var_store) 7038 { 7039 dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info); 7040 if (TREE_CODE (DR_BASE_ADDRESS (load1_dr_info->dr)) != ADDR_EXPR 7041 || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0))) 7042 goto fail; 7043 tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0); 7044 tree lrhs; 7045 if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1))) 7046 lrhs = rhs1; 7047 else 7048 lrhs = rhs2; 7049 use_operand_p use_p; 7050 imm_use_iterator iter; 7051 FOR_EACH_IMM_USE_FAST (use_p, iter, lrhs) 7052 { 7053 gimple *use_stmt = USE_STMT (use_p); 7054 if (use_stmt == def_stmt || is_gimple_debug (use_stmt)) 7055 continue; 7056 if (other_store_stmt) 7057 goto fail; 7058 other_store_stmt = use_stmt; 7059 } 7060 } 7061 7062 if (other_store_stmt == NULL) 7063 goto fail; 7064 if (gimple_bb (other_store_stmt) != gimple_bb (stmt) 7065 || !gimple_store_p (other_store_stmt)) 7066 goto fail; 7067 7068 stmt_vec_info other_store_stmt_info 7069 = loop_vinfo->lookup_stmt (other_store_stmt); 7070 if (other_store_stmt_info == NULL 7071 || (STMT_VINFO_SIMD_LANE_ACCESS_P (other_store_stmt_info) 7072 != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info))) 7073 goto fail; 7074 7075 gimple *stmt1 = stmt; 7076 gimple *stmt2 = other_store_stmt; 7077 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store) 7078 std::swap (stmt1, stmt2); 7079 if (scan_operand_equal_p (gimple_assign_lhs (stmt1), 7080 gimple_assign_rhs1 (load2_stmt))) 7081 { 7082 std::swap (rhs1, rhs2); 7083 std::swap (load1_stmt, load2_stmt); 7084 std::swap (load1_stmt_info, load2_stmt_info); 7085 } 7086 if (!scan_operand_equal_p (gimple_assign_lhs (stmt1), 7087 gimple_assign_rhs1 (load1_stmt))) 7088 goto fail; 7089 7090 tree var3 = NULL_TREE; 7091 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3 7092 && !scan_operand_equal_p (gimple_assign_lhs (stmt2), 7093 gimple_assign_rhs1 (load2_stmt))) 7094 goto fail; 7095 else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4) 7096 { 7097 dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info); 7098 if (TREE_CODE (DR_BASE_ADDRESS (load2_dr_info->dr)) != ADDR_EXPR 7099 || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0))) 7100 goto fail; 7101 var3 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0); 7102 if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var3)) 7103 || lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var3)) 7104 || lookup_attribute ("omp simd inscan exclusive", 7105 DECL_ATTRIBUTES (var3))) 7106 goto fail; 7107 } 7108 7109 dr_vec_info *other_dr_info = STMT_VINFO_DR_INFO (other_store_stmt_info); 7110 if (TREE_CODE (DR_BASE_ADDRESS (other_dr_info->dr)) != ADDR_EXPR 7111 || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0))) 7112 goto fail; 7113 7114 tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0); 7115 tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0); 7116 if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var1)) 7117 || !lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var2)) 7118 || (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1))) 7119 == (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var2)))) 7120 goto fail; 7121 7122 if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1))) 7123 std::swap (var1, var2); 7124 7125 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4) 7126 { 7127 if (!lookup_attribute ("omp simd inscan exclusive", 7128 DECL_ATTRIBUTES (var1))) 7129 goto fail; 7130 var1 = var3; 7131 } 7132 7133 if (loop_vinfo->scan_map == NULL) 7134 goto fail; 7135 tree *init = loop_vinfo->scan_map->get (var1); 7136 if (init == NULL) 7137 goto fail; 7138 7139 /* The IL is as expected, now check if we can actually vectorize it. 7140 Inclusive scan: 7141 _26 = D.2043[_25]; 7142 _27 = D.2042[_25]; 7143 _28 = _26 + _27; 7144 D.2043[_25] = _28; 7145 D.2042[_25] = _28; 7146 should be vectorized as (where _40 is the vectorized rhs 7147 from the D.2042[_21] = 0; store): 7148 _30 = MEM <vector(8) int> [(int *)&D.2043]; 7149 _31 = MEM <vector(8) int> [(int *)&D.2042]; 7150 _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>; 7151 _33 = _31 + _32; 7152 // _33 = { _31[0], _31[0]+_31[1], _31[1]+_31[2], ..., _31[6]+_31[7] }; 7153 _34 = VEC_PERM_EXPR <_40, _33, { 0, 1, 8, 9, 10, 11, 12, 13 }>; 7154 _35 = _33 + _34; 7155 // _35 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3], 7156 // _31[1]+.._31[4], ... _31[4]+.._31[7] }; 7157 _36 = VEC_PERM_EXPR <_40, _35, { 0, 1, 2, 3, 8, 9, 10, 11 }>; 7158 _37 = _35 + _36; 7159 // _37 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3], 7160 // _31[0]+.._31[4], ... _31[0]+.._31[7] }; 7161 _38 = _30 + _37; 7162 _39 = VEC_PERM_EXPR <_38, _38, { 7, 7, 7, 7, 7, 7, 7, 7 }>; 7163 MEM <vector(8) int> [(int *)&D.2043] = _39; 7164 MEM <vector(8) int> [(int *)&D.2042] = _38; 7165 Exclusive scan: 7166 _26 = D.2043[_25]; 7167 D.2044[_25] = _26; 7168 _27 = D.2042[_25]; 7169 _28 = _26 + _27; 7170 D.2043[_25] = _28; 7171 should be vectorized as (where _40 is the vectorized rhs 7172 from the D.2042[_21] = 0; store): 7173 _30 = MEM <vector(8) int> [(int *)&D.2043]; 7174 _31 = MEM <vector(8) int> [(int *)&D.2042]; 7175 _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>; 7176 _33 = VEC_PERM_EXPR <_40, _32, { 0, 8, 9, 10, 11, 12, 13, 14 }>; 7177 _34 = _32 + _33; 7178 // _34 = { 0, _31[0], _31[0]+_31[1], _31[1]+_31[2], _31[2]+_31[3], 7179 // _31[3]+_31[4], ... _31[5]+.._31[6] }; 7180 _35 = VEC_PERM_EXPR <_40, _34, { 0, 1, 8, 9, 10, 11, 12, 13 }>; 7181 _36 = _34 + _35; 7182 // _36 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3], 7183 // _31[1]+.._31[4], ... _31[3]+.._31[6] }; 7184 _37 = VEC_PERM_EXPR <_40, _36, { 0, 1, 2, 3, 8, 9, 10, 11 }>; 7185 _38 = _36 + _37; 7186 // _38 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3], 7187 // _31[0]+.._31[4], ... _31[0]+.._31[6] }; 7188 _39 = _30 + _38; 7189 _50 = _31 + _39; 7190 _51 = VEC_PERM_EXPR <_50, _50, { 7, 7, 7, 7, 7, 7, 7, 7 }>; 7191 MEM <vector(8) int> [(int *)&D.2044] = _39; 7192 MEM <vector(8) int> [(int *)&D.2042] = _51; */ 7193 enum machine_mode vec_mode = TYPE_MODE (vectype); 7194 optab optab = optab_for_tree_code (code, vectype, optab_default); 7195 if (!optab || optab_handler (optab, vec_mode) == CODE_FOR_nothing) 7196 goto fail; 7197 7198 int units_log2 = scan_store_can_perm_p (vectype, *init); 7199 if (units_log2 == -1) 7200 goto fail; 7201 7202 return true; 7203 } 7204 7205 7206 /* Function vectorizable_scan_store. 7207 7208 Helper of vectorizable_score, arguments like on vectorizable_store. 7209 Handle only the transformation, checking is done in check_scan_store. */ 7210 7211 static bool 7212 vectorizable_scan_store (vec_info *vinfo, 7213 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 7214 gimple **vec_stmt, int ncopies) 7215 { 7216 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 7217 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info); 7218 tree ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr)); 7219 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 7220 7221 if (dump_enabled_p ()) 7222 dump_printf_loc (MSG_NOTE, vect_location, 7223 "transform scan store. ncopies = %d\n", ncopies); 7224 7225 gimple *stmt = STMT_VINFO_STMT (stmt_info); 7226 tree rhs = gimple_assign_rhs1 (stmt); 7227 gcc_assert (TREE_CODE (rhs) == SSA_NAME); 7228 7229 tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0); 7230 bool inscan_var_store 7231 = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL; 7232 7233 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store) 7234 { 7235 use_operand_p use_p; 7236 imm_use_iterator iter; 7237 FOR_EACH_IMM_USE_FAST (use_p, iter, rhs) 7238 { 7239 gimple *use_stmt = USE_STMT (use_p); 7240 if (use_stmt == stmt || is_gimple_debug (use_stmt)) 7241 continue; 7242 rhs = gimple_assign_lhs (use_stmt); 7243 break; 7244 } 7245 } 7246 7247 gimple *def_stmt = SSA_NAME_DEF_STMT (rhs); 7248 enum tree_code code = gimple_assign_rhs_code (def_stmt); 7249 if (code == POINTER_PLUS_EXPR) 7250 code = PLUS_EXPR; 7251 gcc_assert (TREE_CODE_LENGTH (code) == binary_op 7252 && commutative_tree_code (code)); 7253 tree rhs1 = gimple_assign_rhs1 (def_stmt); 7254 tree rhs2 = gimple_assign_rhs2 (def_stmt); 7255 gcc_assert (TREE_CODE (rhs1) == SSA_NAME && TREE_CODE (rhs2) == SSA_NAME); 7256 gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1); 7257 gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2); 7258 stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt); 7259 stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt); 7260 dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info); 7261 dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info); 7262 tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0); 7263 tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0); 7264 7265 if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1))) 7266 { 7267 std::swap (rhs1, rhs2); 7268 std::swap (var1, var2); 7269 std::swap (load1_dr_info, load2_dr_info); 7270 } 7271 7272 tree *init = loop_vinfo->scan_map->get (var1); 7273 gcc_assert (init); 7274 7275 unsigned HOST_WIDE_INT nunits; 7276 if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits)) 7277 gcc_unreachable (); 7278 auto_vec<enum scan_store_kind, 16> use_whole_vector; 7279 int units_log2 = scan_store_can_perm_p (vectype, *init, &use_whole_vector); 7280 gcc_assert (units_log2 > 0); 7281 auto_vec<tree, 16> perms; 7282 perms.quick_grow (units_log2 + 1); 7283 tree zero_vec = NULL_TREE, masktype = NULL_TREE; 7284 for (int i = 0; i <= units_log2; ++i) 7285 { 7286 unsigned HOST_WIDE_INT j, k; 7287 vec_perm_builder sel (nunits, nunits, 1); 7288 sel.quick_grow (nunits); 7289 if (i == units_log2) 7290 for (j = 0; j < nunits; ++j) 7291 sel[j] = nunits - 1; 7292 else 7293 { 7294 for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j) 7295 sel[j] = j; 7296 for (k = 0; j < nunits; ++j, ++k) 7297 sel[j] = nunits + k; 7298 } 7299 vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits); 7300 if (!use_whole_vector.is_empty () 7301 && use_whole_vector[i] != scan_store_kind_perm) 7302 { 7303 if (zero_vec == NULL_TREE) 7304 zero_vec = build_zero_cst (vectype); 7305 if (masktype == NULL_TREE 7306 && use_whole_vector[i] == scan_store_kind_lshift_cond) 7307 masktype = truth_type_for (vectype); 7308 perms[i] = vect_gen_perm_mask_any (vectype, indices); 7309 } 7310 else 7311 perms[i] = vect_gen_perm_mask_checked (vectype, indices); 7312 } 7313 7314 tree vec_oprnd1 = NULL_TREE; 7315 tree vec_oprnd2 = NULL_TREE; 7316 tree vec_oprnd3 = NULL_TREE; 7317 tree dataref_ptr = DR_BASE_ADDRESS (dr_info->dr); 7318 tree dataref_offset = build_int_cst (ref_type, 0); 7319 tree bump = vect_get_data_ptr_increment (vinfo, dr_info, 7320 vectype, VMAT_CONTIGUOUS); 7321 tree ldataref_ptr = NULL_TREE; 7322 tree orig = NULL_TREE; 7323 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store) 7324 ldataref_ptr = DR_BASE_ADDRESS (load1_dr_info->dr); 7325 auto_vec<tree> vec_oprnds1; 7326 auto_vec<tree> vec_oprnds2; 7327 auto_vec<tree> vec_oprnds3; 7328 vect_get_vec_defs (vinfo, stmt_info, NULL, ncopies, 7329 *init, &vec_oprnds1, 7330 ldataref_ptr == NULL ? rhs1 : NULL, &vec_oprnds2, 7331 rhs2, &vec_oprnds3); 7332 for (int j = 0; j < ncopies; j++) 7333 { 7334 vec_oprnd1 = vec_oprnds1[j]; 7335 if (ldataref_ptr == NULL) 7336 vec_oprnd2 = vec_oprnds2[j]; 7337 vec_oprnd3 = vec_oprnds3[j]; 7338 if (j == 0) 7339 orig = vec_oprnd3; 7340 else if (!inscan_var_store) 7341 dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump); 7342 7343 if (ldataref_ptr) 7344 { 7345 vec_oprnd2 = make_ssa_name (vectype); 7346 tree data_ref = fold_build2 (MEM_REF, vectype, 7347 unshare_expr (ldataref_ptr), 7348 dataref_offset); 7349 vect_copy_ref_info (data_ref, DR_REF (load1_dr_info->dr)); 7350 gimple *g = gimple_build_assign (vec_oprnd2, data_ref); 7351 vect_finish_stmt_generation (vinfo, stmt_info, g, gsi); 7352 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g); 7353 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 7354 } 7355 7356 tree v = vec_oprnd2; 7357 for (int i = 0; i < units_log2; ++i) 7358 { 7359 tree new_temp = make_ssa_name (vectype); 7360 gimple *g = gimple_build_assign (new_temp, VEC_PERM_EXPR, 7361 (zero_vec 7362 && (use_whole_vector[i] 7363 != scan_store_kind_perm)) 7364 ? zero_vec : vec_oprnd1, v, 7365 perms[i]); 7366 vect_finish_stmt_generation (vinfo, stmt_info, g, gsi); 7367 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g); 7368 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 7369 7370 if (zero_vec && use_whole_vector[i] == scan_store_kind_lshift_cond) 7371 { 7372 /* Whole vector shift shifted in zero bits, but if *init 7373 is not initializer_zerop, we need to replace those elements 7374 with elements from vec_oprnd1. */ 7375 tree_vector_builder vb (masktype, nunits, 1); 7376 for (unsigned HOST_WIDE_INT k = 0; k < nunits; ++k) 7377 vb.quick_push (k < (HOST_WIDE_INT_1U << i) 7378 ? boolean_false_node : boolean_true_node); 7379 7380 tree new_temp2 = make_ssa_name (vectype); 7381 g = gimple_build_assign (new_temp2, VEC_COND_EXPR, vb.build (), 7382 new_temp, vec_oprnd1); 7383 vect_finish_stmt_generation (vinfo, stmt_info, 7384 g, gsi); 7385 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g); 7386 new_temp = new_temp2; 7387 } 7388 7389 /* For exclusive scan, perform the perms[i] permutation once 7390 more. */ 7391 if (i == 0 7392 && STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 7393 && v == vec_oprnd2) 7394 { 7395 v = new_temp; 7396 --i; 7397 continue; 7398 } 7399 7400 tree new_temp2 = make_ssa_name (vectype); 7401 g = gimple_build_assign (new_temp2, code, v, new_temp); 7402 vect_finish_stmt_generation (vinfo, stmt_info, g, gsi); 7403 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g); 7404 7405 v = new_temp2; 7406 } 7407 7408 tree new_temp = make_ssa_name (vectype); 7409 gimple *g = gimple_build_assign (new_temp, code, orig, v); 7410 vect_finish_stmt_generation (vinfo, stmt_info, g, gsi); 7411 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g); 7412 7413 tree last_perm_arg = new_temp; 7414 /* For exclusive scan, new_temp computed above is the exclusive scan 7415 prefix sum. Turn it into inclusive prefix sum for the broadcast 7416 of the last element into orig. */ 7417 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4) 7418 { 7419 last_perm_arg = make_ssa_name (vectype); 7420 g = gimple_build_assign (last_perm_arg, code, new_temp, vec_oprnd2); 7421 vect_finish_stmt_generation (vinfo, stmt_info, g, gsi); 7422 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g); 7423 } 7424 7425 orig = make_ssa_name (vectype); 7426 g = gimple_build_assign (orig, VEC_PERM_EXPR, last_perm_arg, 7427 last_perm_arg, perms[units_log2]); 7428 vect_finish_stmt_generation (vinfo, stmt_info, g, gsi); 7429 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g); 7430 7431 if (!inscan_var_store) 7432 { 7433 tree data_ref = fold_build2 (MEM_REF, vectype, 7434 unshare_expr (dataref_ptr), 7435 dataref_offset); 7436 vect_copy_ref_info (data_ref, DR_REF (dr_info->dr)); 7437 g = gimple_build_assign (data_ref, new_temp); 7438 vect_finish_stmt_generation (vinfo, stmt_info, g, gsi); 7439 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g); 7440 } 7441 } 7442 7443 if (inscan_var_store) 7444 for (int j = 0; j < ncopies; j++) 7445 { 7446 if (j != 0) 7447 dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump); 7448 7449 tree data_ref = fold_build2 (MEM_REF, vectype, 7450 unshare_expr (dataref_ptr), 7451 dataref_offset); 7452 vect_copy_ref_info (data_ref, DR_REF (dr_info->dr)); 7453 gimple *g = gimple_build_assign (data_ref, orig); 7454 vect_finish_stmt_generation (vinfo, stmt_info, g, gsi); 7455 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g); 7456 } 7457 return true; 7458 } 7459 7460 7461 /* Function vectorizable_store. 7462 7463 Check if STMT_INFO defines a non scalar data-ref (array/pointer/structure) 7464 that can be vectorized. 7465 If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized 7466 stmt to replace it, put it in VEC_STMT, and insert it at GSI. 7467 Return true if STMT_INFO is vectorizable in this way. */ 7468 7469 static bool 7470 vectorizable_store (vec_info *vinfo, 7471 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 7472 gimple **vec_stmt, slp_tree slp_node, 7473 stmt_vector_for_cost *cost_vec) 7474 { 7475 tree data_ref; 7476 tree op; 7477 tree vec_oprnd = NULL_TREE; 7478 tree elem_type; 7479 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 7480 class loop *loop = NULL; 7481 machine_mode vec_mode; 7482 tree dummy; 7483 enum vect_def_type rhs_dt = vect_unknown_def_type; 7484 enum vect_def_type mask_dt = vect_unknown_def_type; 7485 tree dataref_ptr = NULL_TREE; 7486 tree dataref_offset = NULL_TREE; 7487 gimple *ptr_incr = NULL; 7488 int ncopies; 7489 int j; 7490 stmt_vec_info first_stmt_info; 7491 bool grouped_store; 7492 unsigned int group_size, i; 7493 vec<tree> oprnds = vNULL; 7494 vec<tree> result_chain = vNULL; 7495 vec<tree> vec_oprnds = vNULL; 7496 bool slp = (slp_node != NULL); 7497 unsigned int vec_num; 7498 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 7499 tree aggr_type; 7500 gather_scatter_info gs_info; 7501 poly_uint64 vf; 7502 vec_load_store_type vls_type; 7503 tree ref_type; 7504 7505 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 7506 return false; 7507 7508 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def 7509 && ! vec_stmt) 7510 return false; 7511 7512 /* Is vectorizable store? */ 7513 7514 tree mask = NULL_TREE, mask_vectype = NULL_TREE; 7515 if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt)) 7516 { 7517 tree scalar_dest = gimple_assign_lhs (assign); 7518 if (TREE_CODE (scalar_dest) == VIEW_CONVERT_EXPR 7519 && is_pattern_stmt_p (stmt_info)) 7520 scalar_dest = TREE_OPERAND (scalar_dest, 0); 7521 if (TREE_CODE (scalar_dest) != ARRAY_REF 7522 && TREE_CODE (scalar_dest) != BIT_FIELD_REF 7523 && TREE_CODE (scalar_dest) != INDIRECT_REF 7524 && TREE_CODE (scalar_dest) != COMPONENT_REF 7525 && TREE_CODE (scalar_dest) != IMAGPART_EXPR 7526 && TREE_CODE (scalar_dest) != REALPART_EXPR 7527 && TREE_CODE (scalar_dest) != MEM_REF) 7528 return false; 7529 } 7530 else 7531 { 7532 gcall *call = dyn_cast <gcall *> (stmt_info->stmt); 7533 if (!call || !gimple_call_internal_p (call)) 7534 return false; 7535 7536 internal_fn ifn = gimple_call_internal_fn (call); 7537 if (!internal_store_fn_p (ifn)) 7538 return false; 7539 7540 if (slp_node != NULL) 7541 { 7542 if (dump_enabled_p ()) 7543 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 7544 "SLP of masked stores not supported.\n"); 7545 return false; 7546 } 7547 7548 int mask_index = internal_fn_mask_index (ifn); 7549 if (mask_index >= 0 7550 && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index, 7551 &mask, NULL, &mask_dt, &mask_vectype)) 7552 return false; 7553 } 7554 7555 op = vect_get_store_rhs (stmt_info); 7556 7557 /* Cannot have hybrid store SLP -- that would mean storing to the 7558 same location twice. */ 7559 gcc_assert (slp == PURE_SLP_STMT (stmt_info)); 7560 7561 tree vectype = STMT_VINFO_VECTYPE (stmt_info), rhs_vectype = NULL_TREE; 7562 poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); 7563 7564 if (loop_vinfo) 7565 { 7566 loop = LOOP_VINFO_LOOP (loop_vinfo); 7567 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); 7568 } 7569 else 7570 vf = 1; 7571 7572 /* Multiple types in SLP are handled by creating the appropriate number of 7573 vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in 7574 case of SLP. */ 7575 if (slp) 7576 ncopies = 1; 7577 else 7578 ncopies = vect_get_num_copies (loop_vinfo, vectype); 7579 7580 gcc_assert (ncopies >= 1); 7581 7582 /* FORNOW. This restriction should be relaxed. */ 7583 if (loop && nested_in_vect_loop_p (loop, stmt_info) && ncopies > 1) 7584 { 7585 if (dump_enabled_p ()) 7586 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 7587 "multiple types in nested loop.\n"); 7588 return false; 7589 } 7590 7591 if (!vect_check_store_rhs (vinfo, stmt_info, slp_node, 7592 op, &rhs_dt, &rhs_vectype, &vls_type)) 7593 return false; 7594 7595 elem_type = TREE_TYPE (vectype); 7596 vec_mode = TYPE_MODE (vectype); 7597 7598 if (!STMT_VINFO_DATA_REF (stmt_info)) 7599 return false; 7600 7601 vect_memory_access_type memory_access_type; 7602 enum dr_alignment_support alignment_support_scheme; 7603 int misalignment; 7604 poly_int64 poffset; 7605 if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, vls_type, 7606 ncopies, &memory_access_type, &poffset, 7607 &alignment_support_scheme, &misalignment, &gs_info)) 7608 return false; 7609 7610 if (mask) 7611 { 7612 if (memory_access_type == VMAT_CONTIGUOUS) 7613 { 7614 if (!VECTOR_MODE_P (vec_mode) 7615 || !can_vec_mask_load_store_p (vec_mode, 7616 TYPE_MODE (mask_vectype), false)) 7617 return false; 7618 } 7619 else if (memory_access_type != VMAT_LOAD_STORE_LANES 7620 && (memory_access_type != VMAT_GATHER_SCATTER 7621 || (gs_info.decl && !VECTOR_BOOLEAN_TYPE_P (mask_vectype)))) 7622 { 7623 if (dump_enabled_p ()) 7624 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 7625 "unsupported access type for masked store.\n"); 7626 return false; 7627 } 7628 } 7629 else 7630 { 7631 /* FORNOW. In some cases can vectorize even if data-type not supported 7632 (e.g. - array initialization with 0). */ 7633 if (optab_handler (mov_optab, vec_mode) == CODE_FOR_nothing) 7634 return false; 7635 } 7636 7637 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL; 7638 grouped_store = (STMT_VINFO_GROUPED_ACCESS (stmt_info) 7639 && memory_access_type != VMAT_GATHER_SCATTER 7640 && (slp || memory_access_type != VMAT_CONTIGUOUS)); 7641 if (grouped_store) 7642 { 7643 first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 7644 first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info); 7645 group_size = DR_GROUP_SIZE (first_stmt_info); 7646 } 7647 else 7648 { 7649 first_stmt_info = stmt_info; 7650 first_dr_info = dr_info; 7651 group_size = vec_num = 1; 7652 } 7653 7654 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1 && !vec_stmt) 7655 { 7656 if (!check_scan_store (vinfo, stmt_info, vectype, rhs_dt, slp, mask, 7657 memory_access_type)) 7658 return false; 7659 } 7660 7661 if (!vec_stmt) /* transformation not required. */ 7662 { 7663 STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info) = memory_access_type; 7664 7665 if (loop_vinfo 7666 && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)) 7667 check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node, 7668 vls_type, group_size, 7669 memory_access_type, &gs_info, 7670 mask); 7671 7672 if (slp_node 7673 && !vect_maybe_update_slp_op_vectype (SLP_TREE_CHILDREN (slp_node)[0], 7674 vectype)) 7675 { 7676 if (dump_enabled_p ()) 7677 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 7678 "incompatible vector types for invariants\n"); 7679 return false; 7680 } 7681 7682 if (dump_enabled_p () 7683 && memory_access_type != VMAT_ELEMENTWISE 7684 && memory_access_type != VMAT_GATHER_SCATTER 7685 && alignment_support_scheme != dr_aligned) 7686 dump_printf_loc (MSG_NOTE, vect_location, 7687 "Vectorizing an unaligned access.\n"); 7688 7689 STMT_VINFO_TYPE (stmt_info) = store_vec_info_type; 7690 vect_model_store_cost (vinfo, stmt_info, ncopies, 7691 memory_access_type, alignment_support_scheme, 7692 misalignment, vls_type, slp_node, cost_vec); 7693 return true; 7694 } 7695 gcc_assert (memory_access_type == STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info)); 7696 7697 /* Transform. */ 7698 7699 ensure_base_align (dr_info); 7700 7701 if (memory_access_type == VMAT_GATHER_SCATTER && gs_info.decl) 7702 { 7703 tree vec_oprnd0 = NULL_TREE, vec_oprnd1 = NULL_TREE, src; 7704 tree arglist = TYPE_ARG_TYPES (TREE_TYPE (gs_info.decl)); 7705 tree rettype, srctype, ptrtype, idxtype, masktype, scaletype; 7706 tree ptr, var, scale, vec_mask; 7707 tree mask_arg = NULL_TREE, mask_op = NULL_TREE, perm_mask = NULL_TREE; 7708 tree mask_halfvectype = mask_vectype; 7709 edge pe = loop_preheader_edge (loop); 7710 gimple_seq seq; 7711 basic_block new_bb; 7712 enum { NARROW, NONE, WIDEN } modifier; 7713 poly_uint64 scatter_off_nunits 7714 = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype); 7715 7716 if (known_eq (nunits, scatter_off_nunits)) 7717 modifier = NONE; 7718 else if (known_eq (nunits * 2, scatter_off_nunits)) 7719 { 7720 modifier = WIDEN; 7721 7722 /* Currently gathers and scatters are only supported for 7723 fixed-length vectors. */ 7724 unsigned int count = scatter_off_nunits.to_constant (); 7725 vec_perm_builder sel (count, count, 1); 7726 for (i = 0; i < (unsigned int) count; ++i) 7727 sel.quick_push (i | (count / 2)); 7728 7729 vec_perm_indices indices (sel, 1, count); 7730 perm_mask = vect_gen_perm_mask_checked (gs_info.offset_vectype, 7731 indices); 7732 gcc_assert (perm_mask != NULL_TREE); 7733 } 7734 else if (known_eq (nunits, scatter_off_nunits * 2)) 7735 { 7736 modifier = NARROW; 7737 7738 /* Currently gathers and scatters are only supported for 7739 fixed-length vectors. */ 7740 unsigned int count = nunits.to_constant (); 7741 vec_perm_builder sel (count, count, 1); 7742 for (i = 0; i < (unsigned int) count; ++i) 7743 sel.quick_push (i | (count / 2)); 7744 7745 vec_perm_indices indices (sel, 2, count); 7746 perm_mask = vect_gen_perm_mask_checked (vectype, indices); 7747 gcc_assert (perm_mask != NULL_TREE); 7748 ncopies *= 2; 7749 7750 if (mask) 7751 mask_halfvectype = truth_type_for (gs_info.offset_vectype); 7752 } 7753 else 7754 gcc_unreachable (); 7755 7756 rettype = TREE_TYPE (TREE_TYPE (gs_info.decl)); 7757 ptrtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); 7758 masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); 7759 idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); 7760 srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist); 7761 scaletype = TREE_VALUE (arglist); 7762 7763 gcc_checking_assert (TREE_CODE (masktype) == INTEGER_TYPE 7764 && TREE_CODE (rettype) == VOID_TYPE); 7765 7766 ptr = fold_convert (ptrtype, gs_info.base); 7767 if (!is_gimple_min_invariant (ptr)) 7768 { 7769 ptr = force_gimple_operand (ptr, &seq, true, NULL_TREE); 7770 new_bb = gsi_insert_seq_on_edge_immediate (pe, seq); 7771 gcc_assert (!new_bb); 7772 } 7773 7774 if (mask == NULL_TREE) 7775 { 7776 mask_arg = build_int_cst (masktype, -1); 7777 mask_arg = vect_init_vector (vinfo, stmt_info, 7778 mask_arg, masktype, NULL); 7779 } 7780 7781 scale = build_int_cst (scaletype, gs_info.scale); 7782 7783 auto_vec<tree> vec_oprnds0; 7784 auto_vec<tree> vec_oprnds1; 7785 auto_vec<tree> vec_masks; 7786 if (mask) 7787 { 7788 tree mask_vectype = truth_type_for (vectype); 7789 vect_get_vec_defs_for_operand (vinfo, stmt_info, 7790 modifier == NARROW 7791 ? ncopies / 2 : ncopies, 7792 mask, &vec_masks, mask_vectype); 7793 } 7794 vect_get_vec_defs_for_operand (vinfo, stmt_info, 7795 modifier == WIDEN 7796 ? ncopies / 2 : ncopies, 7797 gs_info.offset, &vec_oprnds0); 7798 vect_get_vec_defs_for_operand (vinfo, stmt_info, 7799 modifier == NARROW 7800 ? ncopies / 2 : ncopies, 7801 op, &vec_oprnds1); 7802 for (j = 0; j < ncopies; ++j) 7803 { 7804 if (modifier == WIDEN) 7805 { 7806 if (j & 1) 7807 op = permute_vec_elements (vinfo, vec_oprnd0, vec_oprnd0, 7808 perm_mask, stmt_info, gsi); 7809 else 7810 op = vec_oprnd0 = vec_oprnds0[j / 2]; 7811 src = vec_oprnd1 = vec_oprnds1[j]; 7812 if (mask) 7813 mask_op = vec_mask = vec_masks[j]; 7814 } 7815 else if (modifier == NARROW) 7816 { 7817 if (j & 1) 7818 src = permute_vec_elements (vinfo, vec_oprnd1, vec_oprnd1, 7819 perm_mask, stmt_info, gsi); 7820 else 7821 src = vec_oprnd1 = vec_oprnds1[j / 2]; 7822 op = vec_oprnd0 = vec_oprnds0[j]; 7823 if (mask) 7824 mask_op = vec_mask = vec_masks[j / 2]; 7825 } 7826 else 7827 { 7828 op = vec_oprnd0 = vec_oprnds0[j]; 7829 src = vec_oprnd1 = vec_oprnds1[j]; 7830 if (mask) 7831 mask_op = vec_mask = vec_masks[j]; 7832 } 7833 7834 if (!useless_type_conversion_p (srctype, TREE_TYPE (src))) 7835 { 7836 gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (src)), 7837 TYPE_VECTOR_SUBPARTS (srctype))); 7838 var = vect_get_new_ssa_name (srctype, vect_simple_var); 7839 src = build1 (VIEW_CONVERT_EXPR, srctype, src); 7840 gassign *new_stmt 7841 = gimple_build_assign (var, VIEW_CONVERT_EXPR, src); 7842 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 7843 src = var; 7844 } 7845 7846 if (!useless_type_conversion_p (idxtype, TREE_TYPE (op))) 7847 { 7848 gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)), 7849 TYPE_VECTOR_SUBPARTS (idxtype))); 7850 var = vect_get_new_ssa_name (idxtype, vect_simple_var); 7851 op = build1 (VIEW_CONVERT_EXPR, idxtype, op); 7852 gassign *new_stmt 7853 = gimple_build_assign (var, VIEW_CONVERT_EXPR, op); 7854 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 7855 op = var; 7856 } 7857 7858 if (mask) 7859 { 7860 tree utype; 7861 mask_arg = mask_op; 7862 if (modifier == NARROW) 7863 { 7864 var = vect_get_new_ssa_name (mask_halfvectype, 7865 vect_simple_var); 7866 gassign *new_stmt 7867 = gimple_build_assign (var, (j & 1) ? VEC_UNPACK_HI_EXPR 7868 : VEC_UNPACK_LO_EXPR, 7869 mask_op); 7870 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 7871 mask_arg = var; 7872 } 7873 tree optype = TREE_TYPE (mask_arg); 7874 if (TYPE_MODE (masktype) == TYPE_MODE (optype)) 7875 utype = masktype; 7876 else 7877 utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1); 7878 var = vect_get_new_ssa_name (utype, vect_scalar_var); 7879 mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask_arg); 7880 gassign *new_stmt 7881 = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg); 7882 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 7883 mask_arg = var; 7884 if (!useless_type_conversion_p (masktype, utype)) 7885 { 7886 gcc_assert (TYPE_PRECISION (utype) 7887 <= TYPE_PRECISION (masktype)); 7888 var = vect_get_new_ssa_name (masktype, vect_scalar_var); 7889 new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg); 7890 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 7891 mask_arg = var; 7892 } 7893 } 7894 7895 gcall *new_stmt 7896 = gimple_build_call (gs_info.decl, 5, ptr, mask_arg, op, src, scale); 7897 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 7898 7899 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 7900 } 7901 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 7902 return true; 7903 } 7904 else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) >= 3) 7905 return vectorizable_scan_store (vinfo, stmt_info, gsi, vec_stmt, ncopies); 7906 7907 if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) 7908 DR_GROUP_STORE_COUNT (DR_GROUP_FIRST_ELEMENT (stmt_info))++; 7909 7910 if (grouped_store) 7911 { 7912 /* FORNOW */ 7913 gcc_assert (!loop || !nested_in_vect_loop_p (loop, stmt_info)); 7914 7915 /* We vectorize all the stmts of the interleaving group when we 7916 reach the last stmt in the group. */ 7917 if (DR_GROUP_STORE_COUNT (first_stmt_info) 7918 < DR_GROUP_SIZE (first_stmt_info) 7919 && !slp) 7920 { 7921 *vec_stmt = NULL; 7922 return true; 7923 } 7924 7925 if (slp) 7926 { 7927 grouped_store = false; 7928 /* VEC_NUM is the number of vect stmts to be created for this 7929 group. */ 7930 vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 7931 first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0]; 7932 gcc_assert (DR_GROUP_FIRST_ELEMENT (first_stmt_info) 7933 == first_stmt_info); 7934 first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info); 7935 op = vect_get_store_rhs (first_stmt_info); 7936 } 7937 else 7938 /* VEC_NUM is the number of vect stmts to be created for this 7939 group. */ 7940 vec_num = group_size; 7941 7942 ref_type = get_group_alias_ptr_type (first_stmt_info); 7943 } 7944 else 7945 ref_type = reference_alias_ptr_type (DR_REF (first_dr_info->dr)); 7946 7947 if (dump_enabled_p ()) 7948 dump_printf_loc (MSG_NOTE, vect_location, 7949 "transform store. ncopies = %d\n", ncopies); 7950 7951 if (memory_access_type == VMAT_ELEMENTWISE 7952 || memory_access_type == VMAT_STRIDED_SLP) 7953 { 7954 gimple_stmt_iterator incr_gsi; 7955 bool insert_after; 7956 gimple *incr; 7957 tree offvar; 7958 tree ivstep; 7959 tree running_off; 7960 tree stride_base, stride_step, alias_off; 7961 tree vec_oprnd; 7962 tree dr_offset; 7963 unsigned int g; 7964 /* Checked by get_load_store_type. */ 7965 unsigned int const_nunits = nunits.to_constant (); 7966 7967 gcc_assert (!LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)); 7968 gcc_assert (!nested_in_vect_loop_p (loop, stmt_info)); 7969 7970 dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info); 7971 stride_base 7972 = fold_build_pointer_plus 7973 (DR_BASE_ADDRESS (first_dr_info->dr), 7974 size_binop (PLUS_EXPR, 7975 convert_to_ptrofftype (dr_offset), 7976 convert_to_ptrofftype (DR_INIT (first_dr_info->dr)))); 7977 stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr)); 7978 7979 /* For a store with loop-invariant (but other than power-of-2) 7980 stride (i.e. not a grouped access) like so: 7981 7982 for (i = 0; i < n; i += stride) 7983 array[i] = ...; 7984 7985 we generate a new induction variable and new stores from 7986 the components of the (vectorized) rhs: 7987 7988 for (j = 0; ; j += VF*stride) 7989 vectemp = ...; 7990 tmp1 = vectemp[0]; 7991 array[j] = tmp1; 7992 tmp2 = vectemp[1]; 7993 array[j + stride] = tmp2; 7994 ... 7995 */ 7996 7997 unsigned nstores = const_nunits; 7998 unsigned lnel = 1; 7999 tree ltype = elem_type; 8000 tree lvectype = vectype; 8001 if (slp) 8002 { 8003 if (group_size < const_nunits 8004 && const_nunits % group_size == 0) 8005 { 8006 nstores = const_nunits / group_size; 8007 lnel = group_size; 8008 ltype = build_vector_type (elem_type, group_size); 8009 lvectype = vectype; 8010 8011 /* First check if vec_extract optab doesn't support extraction 8012 of vector elts directly. */ 8013 scalar_mode elmode = SCALAR_TYPE_MODE (elem_type); 8014 machine_mode vmode; 8015 if (!VECTOR_MODE_P (TYPE_MODE (vectype)) 8016 || !related_vector_mode (TYPE_MODE (vectype), elmode, 8017 group_size).exists (&vmode) 8018 || (convert_optab_handler (vec_extract_optab, 8019 TYPE_MODE (vectype), vmode) 8020 == CODE_FOR_nothing)) 8021 { 8022 /* Try to avoid emitting an extract of vector elements 8023 by performing the extracts using an integer type of the 8024 same size, extracting from a vector of those and then 8025 re-interpreting it as the original vector type if 8026 supported. */ 8027 unsigned lsize 8028 = group_size * GET_MODE_BITSIZE (elmode); 8029 unsigned int lnunits = const_nunits / group_size; 8030 /* If we can't construct such a vector fall back to 8031 element extracts from the original vector type and 8032 element size stores. */ 8033 if (int_mode_for_size (lsize, 0).exists (&elmode) 8034 && VECTOR_MODE_P (TYPE_MODE (vectype)) 8035 && related_vector_mode (TYPE_MODE (vectype), elmode, 8036 lnunits).exists (&vmode) 8037 && (convert_optab_handler (vec_extract_optab, 8038 vmode, elmode) 8039 != CODE_FOR_nothing)) 8040 { 8041 nstores = lnunits; 8042 lnel = group_size; 8043 ltype = build_nonstandard_integer_type (lsize, 1); 8044 lvectype = build_vector_type (ltype, nstores); 8045 } 8046 /* Else fall back to vector extraction anyway. 8047 Fewer stores are more important than avoiding spilling 8048 of the vector we extract from. Compared to the 8049 construction case in vectorizable_load no store-forwarding 8050 issue exists here for reasonable archs. */ 8051 } 8052 } 8053 else if (group_size >= const_nunits 8054 && group_size % const_nunits == 0) 8055 { 8056 nstores = 1; 8057 lnel = const_nunits; 8058 ltype = vectype; 8059 lvectype = vectype; 8060 } 8061 ltype = build_aligned_type (ltype, TYPE_ALIGN (elem_type)); 8062 ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 8063 } 8064 8065 ivstep = stride_step; 8066 ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (ivstep), ivstep, 8067 build_int_cst (TREE_TYPE (ivstep), vf)); 8068 8069 standard_iv_increment_position (loop, &incr_gsi, &insert_after); 8070 8071 stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base); 8072 ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep); 8073 create_iv (stride_base, ivstep, NULL, 8074 loop, &incr_gsi, insert_after, 8075 &offvar, NULL); 8076 incr = gsi_stmt (incr_gsi); 8077 8078 stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step); 8079 8080 alias_off = build_int_cst (ref_type, 0); 8081 stmt_vec_info next_stmt_info = first_stmt_info; 8082 for (g = 0; g < group_size; g++) 8083 { 8084 running_off = offvar; 8085 if (g) 8086 { 8087 tree size = TYPE_SIZE_UNIT (ltype); 8088 tree pos = fold_build2 (MULT_EXPR, sizetype, size_int (g), 8089 size); 8090 tree newoff = copy_ssa_name (running_off, NULL); 8091 incr = gimple_build_assign (newoff, POINTER_PLUS_EXPR, 8092 running_off, pos); 8093 vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi); 8094 running_off = newoff; 8095 } 8096 if (!slp) 8097 op = vect_get_store_rhs (next_stmt_info); 8098 vect_get_vec_defs (vinfo, next_stmt_info, slp_node, ncopies, 8099 op, &vec_oprnds); 8100 unsigned int group_el = 0; 8101 unsigned HOST_WIDE_INT 8102 elsz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype))); 8103 for (j = 0; j < ncopies; j++) 8104 { 8105 vec_oprnd = vec_oprnds[j]; 8106 /* Pun the vector to extract from if necessary. */ 8107 if (lvectype != vectype) 8108 { 8109 tree tem = make_ssa_name (lvectype); 8110 gimple *pun 8111 = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR, 8112 lvectype, vec_oprnd)); 8113 vect_finish_stmt_generation (vinfo, stmt_info, pun, gsi); 8114 vec_oprnd = tem; 8115 } 8116 for (i = 0; i < nstores; i++) 8117 { 8118 tree newref, newoff; 8119 gimple *incr, *assign; 8120 tree size = TYPE_SIZE (ltype); 8121 /* Extract the i'th component. */ 8122 tree pos = fold_build2 (MULT_EXPR, bitsizetype, 8123 bitsize_int (i), size); 8124 tree elem = fold_build3 (BIT_FIELD_REF, ltype, vec_oprnd, 8125 size, pos); 8126 8127 elem = force_gimple_operand_gsi (gsi, elem, true, 8128 NULL_TREE, true, 8129 GSI_SAME_STMT); 8130 8131 tree this_off = build_int_cst (TREE_TYPE (alias_off), 8132 group_el * elsz); 8133 newref = build2 (MEM_REF, ltype, 8134 running_off, this_off); 8135 vect_copy_ref_info (newref, DR_REF (first_dr_info->dr)); 8136 8137 /* And store it to *running_off. */ 8138 assign = gimple_build_assign (newref, elem); 8139 vect_finish_stmt_generation (vinfo, stmt_info, assign, gsi); 8140 8141 group_el += lnel; 8142 if (! slp 8143 || group_el == group_size) 8144 { 8145 newoff = copy_ssa_name (running_off, NULL); 8146 incr = gimple_build_assign (newoff, POINTER_PLUS_EXPR, 8147 running_off, stride_step); 8148 vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi); 8149 8150 running_off = newoff; 8151 group_el = 0; 8152 } 8153 if (g == group_size - 1 8154 && !slp) 8155 { 8156 if (j == 0 && i == 0) 8157 *vec_stmt = assign; 8158 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (assign); 8159 } 8160 } 8161 } 8162 next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); 8163 vec_oprnds.release (); 8164 if (slp) 8165 break; 8166 } 8167 8168 return true; 8169 } 8170 8171 auto_vec<tree> dr_chain (group_size); 8172 oprnds.create (group_size); 8173 8174 gcc_assert (alignment_support_scheme); 8175 vec_loop_masks *loop_masks 8176 = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo) 8177 ? &LOOP_VINFO_MASKS (loop_vinfo) 8178 : NULL); 8179 vec_loop_lens *loop_lens 8180 = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo) 8181 ? &LOOP_VINFO_LENS (loop_vinfo) 8182 : NULL); 8183 8184 /* Shouldn't go with length-based approach if fully masked. */ 8185 gcc_assert (!loop_lens || !loop_masks); 8186 8187 /* Targets with store-lane instructions must not require explicit 8188 realignment. vect_supportable_dr_alignment always returns either 8189 dr_aligned or dr_unaligned_supported for masked operations. */ 8190 gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES 8191 && !mask 8192 && !loop_masks) 8193 || alignment_support_scheme == dr_aligned 8194 || alignment_support_scheme == dr_unaligned_supported); 8195 8196 tree offset = NULL_TREE; 8197 if (!known_eq (poffset, 0)) 8198 offset = size_int (poffset); 8199 8200 tree bump; 8201 tree vec_offset = NULL_TREE; 8202 if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) 8203 { 8204 aggr_type = NULL_TREE; 8205 bump = NULL_TREE; 8206 } 8207 else if (memory_access_type == VMAT_GATHER_SCATTER) 8208 { 8209 aggr_type = elem_type; 8210 vect_get_strided_load_store_ops (stmt_info, loop_vinfo, &gs_info, 8211 &bump, &vec_offset); 8212 } 8213 else 8214 { 8215 if (memory_access_type == VMAT_LOAD_STORE_LANES) 8216 aggr_type = build_array_type_nelts (elem_type, vec_num * nunits); 8217 else 8218 aggr_type = vectype; 8219 bump = vect_get_data_ptr_increment (vinfo, dr_info, aggr_type, 8220 memory_access_type); 8221 } 8222 8223 if (mask) 8224 LOOP_VINFO_HAS_MASK_STORE (loop_vinfo) = true; 8225 8226 /* In case the vectorization factor (VF) is bigger than the number 8227 of elements that we can fit in a vectype (nunits), we have to generate 8228 more than one vector stmt - i.e - we need to "unroll" the 8229 vector stmt by a factor VF/nunits. */ 8230 8231 /* In case of interleaving (non-unit grouped access): 8232 8233 S1: &base + 2 = x2 8234 S2: &base = x0 8235 S3: &base + 1 = x1 8236 S4: &base + 3 = x3 8237 8238 We create vectorized stores starting from base address (the access of the 8239 first stmt in the chain (S2 in the above example), when the last store stmt 8240 of the chain (S4) is reached: 8241 8242 VS1: &base = vx2 8243 VS2: &base + vec_size*1 = vx0 8244 VS3: &base + vec_size*2 = vx1 8245 VS4: &base + vec_size*3 = vx3 8246 8247 Then permutation statements are generated: 8248 8249 VS5: vx5 = VEC_PERM_EXPR < vx0, vx3, {0, 8, 1, 9, 2, 10, 3, 11} > 8250 VS6: vx6 = VEC_PERM_EXPR < vx0, vx3, {4, 12, 5, 13, 6, 14, 7, 15} > 8251 ... 8252 8253 And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts 8254 (the order of the data-refs in the output of vect_permute_store_chain 8255 corresponds to the order of scalar stmts in the interleaving chain - see 8256 the documentation of vect_permute_store_chain()). 8257 8258 In case of both multiple types and interleaving, above vector stores and 8259 permutation stmts are created for every copy. The result vector stmts are 8260 put in STMT_VINFO_VEC_STMT for the first copy and in the corresponding 8261 STMT_VINFO_RELATED_STMT for the next copies. 8262 */ 8263 8264 auto_vec<tree> vec_masks; 8265 tree vec_mask = NULL; 8266 auto_vec<tree> vec_offsets; 8267 auto_vec<vec<tree> > gvec_oprnds; 8268 gvec_oprnds.safe_grow_cleared (group_size, true); 8269 for (j = 0; j < ncopies; j++) 8270 { 8271 gimple *new_stmt; 8272 if (j == 0) 8273 { 8274 if (slp) 8275 { 8276 /* Get vectorized arguments for SLP_NODE. */ 8277 vect_get_vec_defs (vinfo, stmt_info, slp_node, 1, 8278 op, &vec_oprnds); 8279 vec_oprnd = vec_oprnds[0]; 8280 } 8281 else 8282 { 8283 /* For interleaved stores we collect vectorized defs for all the 8284 stores in the group in DR_CHAIN and OPRNDS. DR_CHAIN is then 8285 used as an input to vect_permute_store_chain(). 8286 8287 If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN 8288 and OPRNDS are of size 1. */ 8289 stmt_vec_info next_stmt_info = first_stmt_info; 8290 for (i = 0; i < group_size; i++) 8291 { 8292 /* Since gaps are not supported for interleaved stores, 8293 DR_GROUP_SIZE is the exact number of stmts in the chain. 8294 Therefore, NEXT_STMT_INFO can't be NULL_TREE. In case 8295 that there is no interleaving, DR_GROUP_SIZE is 1, 8296 and only one iteration of the loop will be executed. */ 8297 op = vect_get_store_rhs (next_stmt_info); 8298 vect_get_vec_defs_for_operand (vinfo, next_stmt_info, 8299 ncopies, op, &gvec_oprnds[i]); 8300 vec_oprnd = gvec_oprnds[i][0]; 8301 dr_chain.quick_push (gvec_oprnds[i][0]); 8302 oprnds.quick_push (gvec_oprnds[i][0]); 8303 next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); 8304 } 8305 if (mask) 8306 { 8307 vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, 8308 mask, &vec_masks, mask_vectype); 8309 vec_mask = vec_masks[0]; 8310 } 8311 } 8312 8313 /* We should have catched mismatched types earlier. */ 8314 gcc_assert (useless_type_conversion_p (vectype, 8315 TREE_TYPE (vec_oprnd))); 8316 bool simd_lane_access_p 8317 = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0; 8318 if (simd_lane_access_p 8319 && !loop_masks 8320 && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR 8321 && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0)) 8322 && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info)) 8323 && integer_zerop (DR_INIT (first_dr_info->dr)) 8324 && alias_sets_conflict_p (get_alias_set (aggr_type), 8325 get_alias_set (TREE_TYPE (ref_type)))) 8326 { 8327 dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr)); 8328 dataref_offset = build_int_cst (ref_type, 0); 8329 } 8330 else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) 8331 { 8332 vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, 8333 slp_node, &gs_info, &dataref_ptr, 8334 &vec_offsets); 8335 vec_offset = vec_offsets[0]; 8336 } 8337 else 8338 dataref_ptr 8339 = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type, 8340 simd_lane_access_p ? loop : NULL, 8341 offset, &dummy, gsi, &ptr_incr, 8342 simd_lane_access_p, bump); 8343 } 8344 else 8345 { 8346 /* For interleaved stores we created vectorized defs for all the 8347 defs stored in OPRNDS in the previous iteration (previous copy). 8348 DR_CHAIN is then used as an input to vect_permute_store_chain(). 8349 If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN and 8350 OPRNDS are of size 1. */ 8351 for (i = 0; i < group_size; i++) 8352 { 8353 vec_oprnd = gvec_oprnds[i][j]; 8354 dr_chain[i] = gvec_oprnds[i][j]; 8355 oprnds[i] = gvec_oprnds[i][j]; 8356 } 8357 if (mask) 8358 vec_mask = vec_masks[j]; 8359 if (dataref_offset) 8360 dataref_offset 8361 = int_const_binop (PLUS_EXPR, dataref_offset, bump); 8362 else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) 8363 vec_offset = vec_offsets[j]; 8364 else 8365 dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, 8366 stmt_info, bump); 8367 } 8368 8369 if (memory_access_type == VMAT_LOAD_STORE_LANES) 8370 { 8371 tree vec_array; 8372 8373 /* Get an array into which we can store the individual vectors. */ 8374 vec_array = create_vector_array (vectype, vec_num); 8375 8376 /* Invalidate the current contents of VEC_ARRAY. This should 8377 become an RTL clobber too, which prevents the vector registers 8378 from being upward-exposed. */ 8379 vect_clobber_variable (vinfo, stmt_info, gsi, vec_array); 8380 8381 /* Store the individual vectors into the array. */ 8382 for (i = 0; i < vec_num; i++) 8383 { 8384 vec_oprnd = dr_chain[i]; 8385 write_vector_array (vinfo, stmt_info, 8386 gsi, vec_oprnd, vec_array, i); 8387 } 8388 8389 tree final_mask = NULL; 8390 if (loop_masks) 8391 final_mask = vect_get_loop_mask (gsi, loop_masks, ncopies, 8392 vectype, j); 8393 if (vec_mask) 8394 final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, 8395 final_mask, vec_mask, gsi); 8396 8397 gcall *call; 8398 if (final_mask) 8399 { 8400 /* Emit: 8401 MASK_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK, 8402 VEC_ARRAY). */ 8403 unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype)); 8404 tree alias_ptr = build_int_cst (ref_type, align); 8405 call = gimple_build_call_internal (IFN_MASK_STORE_LANES, 4, 8406 dataref_ptr, alias_ptr, 8407 final_mask, vec_array); 8408 } 8409 else 8410 { 8411 /* Emit: 8412 MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY). */ 8413 data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type); 8414 call = gimple_build_call_internal (IFN_STORE_LANES, 1, 8415 vec_array); 8416 gimple_call_set_lhs (call, data_ref); 8417 } 8418 gimple_call_set_nothrow (call, true); 8419 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 8420 new_stmt = call; 8421 8422 /* Record that VEC_ARRAY is now dead. */ 8423 vect_clobber_variable (vinfo, stmt_info, gsi, vec_array); 8424 } 8425 else 8426 { 8427 new_stmt = NULL; 8428 if (grouped_store) 8429 { 8430 if (j == 0) 8431 result_chain.create (group_size); 8432 /* Permute. */ 8433 vect_permute_store_chain (vinfo, dr_chain, group_size, stmt_info, 8434 gsi, &result_chain); 8435 } 8436 8437 stmt_vec_info next_stmt_info = first_stmt_info; 8438 for (i = 0; i < vec_num; i++) 8439 { 8440 unsigned misalign; 8441 unsigned HOST_WIDE_INT align; 8442 8443 tree final_mask = NULL_TREE; 8444 if (loop_masks) 8445 final_mask = vect_get_loop_mask (gsi, loop_masks, 8446 vec_num * ncopies, 8447 vectype, vec_num * j + i); 8448 if (vec_mask) 8449 final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, 8450 final_mask, vec_mask, gsi); 8451 8452 if (memory_access_type == VMAT_GATHER_SCATTER) 8453 { 8454 tree scale = size_int (gs_info.scale); 8455 gcall *call; 8456 if (final_mask) 8457 call = gimple_build_call_internal 8458 (IFN_MASK_SCATTER_STORE, 5, dataref_ptr, vec_offset, 8459 scale, vec_oprnd, final_mask); 8460 else 8461 call = gimple_build_call_internal 8462 (IFN_SCATTER_STORE, 4, dataref_ptr, vec_offset, 8463 scale, vec_oprnd); 8464 gimple_call_set_nothrow (call, true); 8465 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 8466 new_stmt = call; 8467 break; 8468 } 8469 8470 if (i > 0) 8471 /* Bump the vector pointer. */ 8472 dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, 8473 gsi, stmt_info, bump); 8474 8475 if (slp) 8476 vec_oprnd = vec_oprnds[i]; 8477 else if (grouped_store) 8478 /* For grouped stores vectorized defs are interleaved in 8479 vect_permute_store_chain(). */ 8480 vec_oprnd = result_chain[i]; 8481 8482 align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info)); 8483 if (alignment_support_scheme == dr_aligned) 8484 misalign = 0; 8485 else if (misalignment == DR_MISALIGNMENT_UNKNOWN) 8486 { 8487 align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info)); 8488 misalign = 0; 8489 } 8490 else 8491 misalign = misalignment; 8492 if (dataref_offset == NULL_TREE 8493 && TREE_CODE (dataref_ptr) == SSA_NAME) 8494 set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, 8495 misalign); 8496 align = least_bit_hwi (misalign | align); 8497 8498 if (memory_access_type == VMAT_CONTIGUOUS_REVERSE) 8499 { 8500 tree perm_mask = perm_mask_for_reverse (vectype); 8501 tree perm_dest = vect_create_destination_var 8502 (vect_get_store_rhs (stmt_info), vectype); 8503 tree new_temp = make_ssa_name (perm_dest); 8504 8505 /* Generate the permute statement. */ 8506 gimple *perm_stmt 8507 = gimple_build_assign (new_temp, VEC_PERM_EXPR, vec_oprnd, 8508 vec_oprnd, perm_mask); 8509 vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi); 8510 8511 perm_stmt = SSA_NAME_DEF_STMT (new_temp); 8512 vec_oprnd = new_temp; 8513 } 8514 8515 /* Arguments are ready. Create the new vector stmt. */ 8516 if (final_mask) 8517 { 8518 tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT); 8519 gcall *call 8520 = gimple_build_call_internal (IFN_MASK_STORE, 4, 8521 dataref_ptr, ptr, 8522 final_mask, vec_oprnd); 8523 gimple_call_set_nothrow (call, true); 8524 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 8525 new_stmt = call; 8526 } 8527 else if (loop_lens) 8528 { 8529 tree final_len 8530 = vect_get_loop_len (loop_vinfo, loop_lens, 8531 vec_num * ncopies, vec_num * j + i); 8532 tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT); 8533 machine_mode vmode = TYPE_MODE (vectype); 8534 opt_machine_mode new_ovmode 8535 = get_len_load_store_mode (vmode, false); 8536 machine_mode new_vmode = new_ovmode.require (); 8537 /* Need conversion if it's wrapped with VnQI. */ 8538 if (vmode != new_vmode) 8539 { 8540 tree new_vtype 8541 = build_vector_type_for_mode (unsigned_intQI_type_node, 8542 new_vmode); 8543 tree var 8544 = vect_get_new_ssa_name (new_vtype, vect_simple_var); 8545 vec_oprnd 8546 = build1 (VIEW_CONVERT_EXPR, new_vtype, vec_oprnd); 8547 gassign *new_stmt 8548 = gimple_build_assign (var, VIEW_CONVERT_EXPR, 8549 vec_oprnd); 8550 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, 8551 gsi); 8552 vec_oprnd = var; 8553 } 8554 8555 signed char biasval = 8556 LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); 8557 8558 tree bias = build_int_cst (intQI_type_node, biasval); 8559 gcall *call 8560 = gimple_build_call_internal (IFN_LEN_STORE, 5, dataref_ptr, 8561 ptr, final_len, vec_oprnd, 8562 bias); 8563 gimple_call_set_nothrow (call, true); 8564 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 8565 new_stmt = call; 8566 } 8567 else 8568 { 8569 data_ref = fold_build2 (MEM_REF, vectype, 8570 dataref_ptr, 8571 dataref_offset 8572 ? dataref_offset 8573 : build_int_cst (ref_type, 0)); 8574 if (alignment_support_scheme == dr_aligned) 8575 ; 8576 else 8577 TREE_TYPE (data_ref) 8578 = build_aligned_type (TREE_TYPE (data_ref), 8579 align * BITS_PER_UNIT); 8580 vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); 8581 new_stmt = gimple_build_assign (data_ref, vec_oprnd); 8582 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 8583 } 8584 8585 if (slp) 8586 continue; 8587 8588 next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info); 8589 if (!next_stmt_info) 8590 break; 8591 } 8592 } 8593 if (!slp) 8594 { 8595 if (j == 0) 8596 *vec_stmt = new_stmt; 8597 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 8598 } 8599 } 8600 8601 for (i = 0; i < group_size; ++i) 8602 { 8603 vec<tree> oprndsi = gvec_oprnds[i]; 8604 oprndsi.release (); 8605 } 8606 oprnds.release (); 8607 result_chain.release (); 8608 vec_oprnds.release (); 8609 8610 return true; 8611 } 8612 8613 /* Given a vector type VECTYPE, turns permutation SEL into the equivalent 8614 VECTOR_CST mask. No checks are made that the target platform supports the 8615 mask, so callers may wish to test can_vec_perm_const_p separately, or use 8616 vect_gen_perm_mask_checked. */ 8617 8618 tree 8619 vect_gen_perm_mask_any (tree vectype, const vec_perm_indices &sel) 8620 { 8621 tree mask_type; 8622 8623 poly_uint64 nunits = sel.length (); 8624 gcc_assert (known_eq (nunits, TYPE_VECTOR_SUBPARTS (vectype))); 8625 8626 mask_type = build_vector_type (ssizetype, nunits); 8627 return vec_perm_indices_to_tree (mask_type, sel); 8628 } 8629 8630 /* Checked version of vect_gen_perm_mask_any. Asserts can_vec_perm_const_p, 8631 i.e. that the target supports the pattern _for arbitrary input vectors_. */ 8632 8633 tree 8634 vect_gen_perm_mask_checked (tree vectype, const vec_perm_indices &sel) 8635 { 8636 gcc_assert (can_vec_perm_const_p (TYPE_MODE (vectype), sel)); 8637 return vect_gen_perm_mask_any (vectype, sel); 8638 } 8639 8640 /* Given a vector variable X and Y, that was generated for the scalar 8641 STMT_INFO, generate instructions to permute the vector elements of X and Y 8642 using permutation mask MASK_VEC, insert them at *GSI and return the 8643 permuted vector variable. */ 8644 8645 static tree 8646 permute_vec_elements (vec_info *vinfo, 8647 tree x, tree y, tree mask_vec, stmt_vec_info stmt_info, 8648 gimple_stmt_iterator *gsi) 8649 { 8650 tree vectype = TREE_TYPE (x); 8651 tree perm_dest, data_ref; 8652 gimple *perm_stmt; 8653 8654 tree scalar_dest = gimple_get_lhs (stmt_info->stmt); 8655 if (scalar_dest && TREE_CODE (scalar_dest) == SSA_NAME) 8656 perm_dest = vect_create_destination_var (scalar_dest, vectype); 8657 else 8658 perm_dest = vect_get_new_vect_var (vectype, vect_simple_var, NULL); 8659 data_ref = make_ssa_name (perm_dest); 8660 8661 /* Generate the permute statement. */ 8662 perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, x, y, mask_vec); 8663 vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi); 8664 8665 return data_ref; 8666 } 8667 8668 /* Hoist the definitions of all SSA uses on STMT_INFO out of the loop LOOP, 8669 inserting them on the loops preheader edge. Returns true if we 8670 were successful in doing so (and thus STMT_INFO can be moved then), 8671 otherwise returns false. */ 8672 8673 static bool 8674 hoist_defs_of_uses (stmt_vec_info stmt_info, class loop *loop) 8675 { 8676 ssa_op_iter i; 8677 tree op; 8678 bool any = false; 8679 8680 FOR_EACH_SSA_TREE_OPERAND (op, stmt_info->stmt, i, SSA_OP_USE) 8681 { 8682 gimple *def_stmt = SSA_NAME_DEF_STMT (op); 8683 if (!gimple_nop_p (def_stmt) 8684 && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt))) 8685 { 8686 /* Make sure we don't need to recurse. While we could do 8687 so in simple cases when there are more complex use webs 8688 we don't have an easy way to preserve stmt order to fulfil 8689 dependencies within them. */ 8690 tree op2; 8691 ssa_op_iter i2; 8692 if (gimple_code (def_stmt) == GIMPLE_PHI) 8693 return false; 8694 FOR_EACH_SSA_TREE_OPERAND (op2, def_stmt, i2, SSA_OP_USE) 8695 { 8696 gimple *def_stmt2 = SSA_NAME_DEF_STMT (op2); 8697 if (!gimple_nop_p (def_stmt2) 8698 && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt2))) 8699 return false; 8700 } 8701 any = true; 8702 } 8703 } 8704 8705 if (!any) 8706 return true; 8707 8708 FOR_EACH_SSA_TREE_OPERAND (op, stmt_info->stmt, i, SSA_OP_USE) 8709 { 8710 gimple *def_stmt = SSA_NAME_DEF_STMT (op); 8711 if (!gimple_nop_p (def_stmt) 8712 && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt))) 8713 { 8714 gimple_stmt_iterator gsi = gsi_for_stmt (def_stmt); 8715 gsi_remove (&gsi, false); 8716 gsi_insert_on_edge_immediate (loop_preheader_edge (loop), def_stmt); 8717 } 8718 } 8719 8720 return true; 8721 } 8722 8723 /* vectorizable_load. 8724 8725 Check if STMT_INFO reads a non scalar data-ref (array/pointer/structure) 8726 that can be vectorized. 8727 If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized 8728 stmt to replace it, put it in VEC_STMT, and insert it at GSI. 8729 Return true if STMT_INFO is vectorizable in this way. */ 8730 8731 static bool 8732 vectorizable_load (vec_info *vinfo, 8733 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 8734 gimple **vec_stmt, slp_tree slp_node, 8735 stmt_vector_for_cost *cost_vec) 8736 { 8737 tree scalar_dest; 8738 tree vec_dest = NULL; 8739 tree data_ref = NULL; 8740 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 8741 class loop *loop = NULL; 8742 class loop *containing_loop = gimple_bb (stmt_info->stmt)->loop_father; 8743 bool nested_in_vect_loop = false; 8744 tree elem_type; 8745 tree new_temp; 8746 machine_mode mode; 8747 tree dummy; 8748 tree dataref_ptr = NULL_TREE; 8749 tree dataref_offset = NULL_TREE; 8750 gimple *ptr_incr = NULL; 8751 int ncopies; 8752 int i, j; 8753 unsigned int group_size; 8754 poly_uint64 group_gap_adj; 8755 tree msq = NULL_TREE, lsq; 8756 tree realignment_token = NULL_TREE; 8757 gphi *phi = NULL; 8758 vec<tree> dr_chain = vNULL; 8759 bool grouped_load = false; 8760 stmt_vec_info first_stmt_info; 8761 stmt_vec_info first_stmt_info_for_drptr = NULL; 8762 bool compute_in_loop = false; 8763 class loop *at_loop; 8764 int vec_num; 8765 bool slp = (slp_node != NULL); 8766 bool slp_perm = false; 8767 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 8768 poly_uint64 vf; 8769 tree aggr_type; 8770 gather_scatter_info gs_info; 8771 tree ref_type; 8772 enum vect_def_type mask_dt = vect_unknown_def_type; 8773 8774 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 8775 return false; 8776 8777 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def 8778 && ! vec_stmt) 8779 return false; 8780 8781 if (!STMT_VINFO_DATA_REF (stmt_info)) 8782 return false; 8783 8784 tree mask = NULL_TREE, mask_vectype = NULL_TREE; 8785 int mask_index = -1; 8786 if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt)) 8787 { 8788 scalar_dest = gimple_assign_lhs (assign); 8789 if (TREE_CODE (scalar_dest) != SSA_NAME) 8790 return false; 8791 8792 tree_code code = gimple_assign_rhs_code (assign); 8793 if (code != ARRAY_REF 8794 && code != BIT_FIELD_REF 8795 && code != INDIRECT_REF 8796 && code != COMPONENT_REF 8797 && code != IMAGPART_EXPR 8798 && code != REALPART_EXPR 8799 && code != MEM_REF 8800 && TREE_CODE_CLASS (code) != tcc_declaration) 8801 return false; 8802 } 8803 else 8804 { 8805 gcall *call = dyn_cast <gcall *> (stmt_info->stmt); 8806 if (!call || !gimple_call_internal_p (call)) 8807 return false; 8808 8809 internal_fn ifn = gimple_call_internal_fn (call); 8810 if (!internal_load_fn_p (ifn)) 8811 return false; 8812 8813 scalar_dest = gimple_call_lhs (call); 8814 if (!scalar_dest) 8815 return false; 8816 8817 mask_index = internal_fn_mask_index (ifn); 8818 /* ??? For SLP the mask operand is always last. */ 8819 if (mask_index >= 0 && slp_node) 8820 mask_index = SLP_TREE_CHILDREN (slp_node).length () - 1; 8821 if (mask_index >= 0 8822 && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index, 8823 &mask, NULL, &mask_dt, &mask_vectype)) 8824 return false; 8825 } 8826 8827 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 8828 poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); 8829 8830 if (loop_vinfo) 8831 { 8832 loop = LOOP_VINFO_LOOP (loop_vinfo); 8833 nested_in_vect_loop = nested_in_vect_loop_p (loop, stmt_info); 8834 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); 8835 } 8836 else 8837 vf = 1; 8838 8839 /* Multiple types in SLP are handled by creating the appropriate number of 8840 vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in 8841 case of SLP. */ 8842 if (slp) 8843 ncopies = 1; 8844 else 8845 ncopies = vect_get_num_copies (loop_vinfo, vectype); 8846 8847 gcc_assert (ncopies >= 1); 8848 8849 /* FORNOW. This restriction should be relaxed. */ 8850 if (nested_in_vect_loop && ncopies > 1) 8851 { 8852 if (dump_enabled_p ()) 8853 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 8854 "multiple types in nested loop.\n"); 8855 return false; 8856 } 8857 8858 /* Invalidate assumptions made by dependence analysis when vectorization 8859 on the unrolled body effectively re-orders stmts. */ 8860 if (ncopies > 1 8861 && STMT_VINFO_MIN_NEG_DIST (stmt_info) != 0 8862 && maybe_gt (LOOP_VINFO_VECT_FACTOR (loop_vinfo), 8863 STMT_VINFO_MIN_NEG_DIST (stmt_info))) 8864 { 8865 if (dump_enabled_p ()) 8866 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 8867 "cannot perform implicit CSE when unrolling " 8868 "with negative dependence distance\n"); 8869 return false; 8870 } 8871 8872 elem_type = TREE_TYPE (vectype); 8873 mode = TYPE_MODE (vectype); 8874 8875 /* FORNOW. In some cases can vectorize even if data-type not supported 8876 (e.g. - data copies). */ 8877 if (optab_handler (mov_optab, mode) == CODE_FOR_nothing) 8878 { 8879 if (dump_enabled_p ()) 8880 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 8881 "Aligned load, but unsupported type.\n"); 8882 return false; 8883 } 8884 8885 /* Check if the load is a part of an interleaving chain. */ 8886 if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) 8887 { 8888 grouped_load = true; 8889 /* FORNOW */ 8890 gcc_assert (!nested_in_vect_loop); 8891 gcc_assert (!STMT_VINFO_GATHER_SCATTER_P (stmt_info)); 8892 8893 first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 8894 group_size = DR_GROUP_SIZE (first_stmt_info); 8895 8896 /* Refuse non-SLP vectorization of SLP-only groups. */ 8897 if (!slp && STMT_VINFO_SLP_VECT_ONLY (first_stmt_info)) 8898 { 8899 if (dump_enabled_p ()) 8900 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 8901 "cannot vectorize load in non-SLP mode.\n"); 8902 return false; 8903 } 8904 8905 if (slp && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()) 8906 { 8907 slp_perm = true; 8908 8909 if (!loop_vinfo) 8910 { 8911 /* In BB vectorization we may not actually use a loaded vector 8912 accessing elements in excess of DR_GROUP_SIZE. */ 8913 stmt_vec_info group_info = SLP_TREE_SCALAR_STMTS (slp_node)[0]; 8914 group_info = DR_GROUP_FIRST_ELEMENT (group_info); 8915 unsigned HOST_WIDE_INT nunits; 8916 unsigned j, k, maxk = 0; 8917 FOR_EACH_VEC_ELT (SLP_TREE_LOAD_PERMUTATION (slp_node), j, k) 8918 if (k > maxk) 8919 maxk = k; 8920 tree vectype = SLP_TREE_VECTYPE (slp_node); 8921 if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits) 8922 || maxk >= (DR_GROUP_SIZE (group_info) & ~(nunits - 1))) 8923 { 8924 if (dump_enabled_p ()) 8925 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 8926 "BB vectorization with gaps at the end of " 8927 "a load is not supported\n"); 8928 return false; 8929 } 8930 } 8931 8932 auto_vec<tree> tem; 8933 unsigned n_perms; 8934 if (!vect_transform_slp_perm_load (vinfo, slp_node, tem, NULL, vf, 8935 true, &n_perms)) 8936 { 8937 if (dump_enabled_p ()) 8938 dump_printf_loc (MSG_MISSED_OPTIMIZATION, 8939 vect_location, 8940 "unsupported load permutation\n"); 8941 return false; 8942 } 8943 } 8944 8945 /* Invalidate assumptions made by dependence analysis when vectorization 8946 on the unrolled body effectively re-orders stmts. */ 8947 if (!PURE_SLP_STMT (stmt_info) 8948 && STMT_VINFO_MIN_NEG_DIST (stmt_info) != 0 8949 && maybe_gt (LOOP_VINFO_VECT_FACTOR (loop_vinfo), 8950 STMT_VINFO_MIN_NEG_DIST (stmt_info))) 8951 { 8952 if (dump_enabled_p ()) 8953 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 8954 "cannot perform implicit CSE when performing " 8955 "group loads with negative dependence distance\n"); 8956 return false; 8957 } 8958 } 8959 else 8960 group_size = 1; 8961 8962 vect_memory_access_type memory_access_type; 8963 enum dr_alignment_support alignment_support_scheme; 8964 int misalignment; 8965 poly_int64 poffset; 8966 if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, VLS_LOAD, 8967 ncopies, &memory_access_type, &poffset, 8968 &alignment_support_scheme, &misalignment, &gs_info)) 8969 return false; 8970 8971 if (mask) 8972 { 8973 if (memory_access_type == VMAT_CONTIGUOUS) 8974 { 8975 machine_mode vec_mode = TYPE_MODE (vectype); 8976 if (!VECTOR_MODE_P (vec_mode) 8977 || !can_vec_mask_load_store_p (vec_mode, 8978 TYPE_MODE (mask_vectype), true)) 8979 return false; 8980 } 8981 else if (memory_access_type != VMAT_LOAD_STORE_LANES 8982 && memory_access_type != VMAT_GATHER_SCATTER) 8983 { 8984 if (dump_enabled_p ()) 8985 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 8986 "unsupported access type for masked load.\n"); 8987 return false; 8988 } 8989 else if (memory_access_type == VMAT_GATHER_SCATTER 8990 && gs_info.ifn == IFN_LAST 8991 && !gs_info.decl) 8992 { 8993 if (dump_enabled_p ()) 8994 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 8995 "unsupported masked emulated gather.\n"); 8996 return false; 8997 } 8998 else if (memory_access_type == VMAT_ELEMENTWISE 8999 || memory_access_type == VMAT_STRIDED_SLP) 9000 { 9001 if (dump_enabled_p ()) 9002 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 9003 "unsupported masked strided access.\n"); 9004 return false; 9005 } 9006 } 9007 9008 if (!vec_stmt) /* transformation not required. */ 9009 { 9010 if (slp_node 9011 && mask 9012 && !vect_maybe_update_slp_op_vectype (SLP_TREE_CHILDREN (slp_node)[0], 9013 mask_vectype)) 9014 { 9015 if (dump_enabled_p ()) 9016 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 9017 "incompatible vector types for invariants\n"); 9018 return false; 9019 } 9020 9021 if (!slp) 9022 STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info) = memory_access_type; 9023 9024 if (loop_vinfo 9025 && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)) 9026 check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node, 9027 VLS_LOAD, group_size, 9028 memory_access_type, &gs_info, 9029 mask); 9030 9031 if (dump_enabled_p () 9032 && memory_access_type != VMAT_ELEMENTWISE 9033 && memory_access_type != VMAT_GATHER_SCATTER 9034 && alignment_support_scheme != dr_aligned) 9035 dump_printf_loc (MSG_NOTE, vect_location, 9036 "Vectorizing an unaligned access.\n"); 9037 9038 STMT_VINFO_TYPE (stmt_info) = load_vec_info_type; 9039 vect_model_load_cost (vinfo, stmt_info, ncopies, vf, memory_access_type, 9040 alignment_support_scheme, misalignment, 9041 &gs_info, slp_node, cost_vec); 9042 return true; 9043 } 9044 9045 if (!slp) 9046 gcc_assert (memory_access_type 9047 == STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info)); 9048 9049 if (dump_enabled_p ()) 9050 dump_printf_loc (MSG_NOTE, vect_location, 9051 "transform load. ncopies = %d\n", ncopies); 9052 9053 /* Transform. */ 9054 9055 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL; 9056 ensure_base_align (dr_info); 9057 9058 if (memory_access_type == VMAT_GATHER_SCATTER && gs_info.decl) 9059 { 9060 vect_build_gather_load_calls (vinfo, 9061 stmt_info, gsi, vec_stmt, &gs_info, mask); 9062 return true; 9063 } 9064 9065 if (memory_access_type == VMAT_INVARIANT) 9066 { 9067 gcc_assert (!grouped_load && !mask && !bb_vinfo); 9068 /* If we have versioned for aliasing or the loop doesn't 9069 have any data dependencies that would preclude this, 9070 then we are sure this is a loop invariant load and 9071 thus we can insert it on the preheader edge. */ 9072 bool hoist_p = (LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) 9073 && !nested_in_vect_loop 9074 && hoist_defs_of_uses (stmt_info, loop)); 9075 if (hoist_p) 9076 { 9077 gassign *stmt = as_a <gassign *> (stmt_info->stmt); 9078 if (dump_enabled_p ()) 9079 dump_printf_loc (MSG_NOTE, vect_location, 9080 "hoisting out of the vectorized loop: %G", stmt); 9081 scalar_dest = copy_ssa_name (scalar_dest); 9082 tree rhs = unshare_expr (gimple_assign_rhs1 (stmt)); 9083 gsi_insert_on_edge_immediate 9084 (loop_preheader_edge (loop), 9085 gimple_build_assign (scalar_dest, rhs)); 9086 } 9087 /* These copies are all equivalent, but currently the representation 9088 requires a separate STMT_VINFO_VEC_STMT for each one. */ 9089 gimple_stmt_iterator gsi2 = *gsi; 9090 gsi_next (&gsi2); 9091 for (j = 0; j < ncopies; j++) 9092 { 9093 if (hoist_p) 9094 new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest, 9095 vectype, NULL); 9096 else 9097 new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest, 9098 vectype, &gsi2); 9099 gimple *new_stmt = SSA_NAME_DEF_STMT (new_temp); 9100 if (slp) 9101 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 9102 else 9103 { 9104 if (j == 0) 9105 *vec_stmt = new_stmt; 9106 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 9107 } 9108 } 9109 return true; 9110 } 9111 9112 if (memory_access_type == VMAT_ELEMENTWISE 9113 || memory_access_type == VMAT_STRIDED_SLP) 9114 { 9115 gimple_stmt_iterator incr_gsi; 9116 bool insert_after; 9117 tree offvar; 9118 tree ivstep; 9119 tree running_off; 9120 vec<constructor_elt, va_gc> *v = NULL; 9121 tree stride_base, stride_step, alias_off; 9122 /* Checked by get_load_store_type. */ 9123 unsigned int const_nunits = nunits.to_constant (); 9124 unsigned HOST_WIDE_INT cst_offset = 0; 9125 tree dr_offset; 9126 9127 gcc_assert (!LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo)); 9128 gcc_assert (!nested_in_vect_loop); 9129 9130 if (grouped_load) 9131 { 9132 first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 9133 first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info); 9134 } 9135 else 9136 { 9137 first_stmt_info = stmt_info; 9138 first_dr_info = dr_info; 9139 } 9140 if (slp && grouped_load) 9141 { 9142 group_size = DR_GROUP_SIZE (first_stmt_info); 9143 ref_type = get_group_alias_ptr_type (first_stmt_info); 9144 } 9145 else 9146 { 9147 if (grouped_load) 9148 cst_offset 9149 = (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype))) 9150 * vect_get_place_in_interleaving_chain (stmt_info, 9151 first_stmt_info)); 9152 group_size = 1; 9153 ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr)); 9154 } 9155 9156 dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info); 9157 stride_base 9158 = fold_build_pointer_plus 9159 (DR_BASE_ADDRESS (first_dr_info->dr), 9160 size_binop (PLUS_EXPR, 9161 convert_to_ptrofftype (dr_offset), 9162 convert_to_ptrofftype (DR_INIT (first_dr_info->dr)))); 9163 stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr)); 9164 9165 /* For a load with loop-invariant (but other than power-of-2) 9166 stride (i.e. not a grouped access) like so: 9167 9168 for (i = 0; i < n; i += stride) 9169 ... = array[i]; 9170 9171 we generate a new induction variable and new accesses to 9172 form a new vector (or vectors, depending on ncopies): 9173 9174 for (j = 0; ; j += VF*stride) 9175 tmp1 = array[j]; 9176 tmp2 = array[j + stride]; 9177 ... 9178 vectemp = {tmp1, tmp2, ...} 9179 */ 9180 9181 ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (stride_step), stride_step, 9182 build_int_cst (TREE_TYPE (stride_step), vf)); 9183 9184 standard_iv_increment_position (loop, &incr_gsi, &insert_after); 9185 9186 stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base); 9187 ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep); 9188 create_iv (stride_base, ivstep, NULL, 9189 loop, &incr_gsi, insert_after, 9190 &offvar, NULL); 9191 9192 stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step); 9193 9194 running_off = offvar; 9195 alias_off = build_int_cst (ref_type, 0); 9196 int nloads = const_nunits; 9197 int lnel = 1; 9198 tree ltype = TREE_TYPE (vectype); 9199 tree lvectype = vectype; 9200 auto_vec<tree> dr_chain; 9201 if (memory_access_type == VMAT_STRIDED_SLP) 9202 { 9203 if (group_size < const_nunits) 9204 { 9205 /* First check if vec_init optab supports construction from vector 9206 elts directly. Otherwise avoid emitting a constructor of 9207 vector elements by performing the loads using an integer type 9208 of the same size, constructing a vector of those and then 9209 re-interpreting it as the original vector type. This avoids a 9210 huge runtime penalty due to the general inability to perform 9211 store forwarding from smaller stores to a larger load. */ 9212 tree ptype; 9213 tree vtype 9214 = vector_vector_composition_type (vectype, 9215 const_nunits / group_size, 9216 &ptype); 9217 if (vtype != NULL_TREE) 9218 { 9219 nloads = const_nunits / group_size; 9220 lnel = group_size; 9221 lvectype = vtype; 9222 ltype = ptype; 9223 } 9224 } 9225 else 9226 { 9227 nloads = 1; 9228 lnel = const_nunits; 9229 ltype = vectype; 9230 } 9231 ltype = build_aligned_type (ltype, TYPE_ALIGN (TREE_TYPE (vectype))); 9232 } 9233 /* Load vector(1) scalar_type if it's 1 element-wise vectype. */ 9234 else if (nloads == 1) 9235 ltype = vectype; 9236 9237 if (slp) 9238 { 9239 /* For SLP permutation support we need to load the whole group, 9240 not only the number of vector stmts the permutation result 9241 fits in. */ 9242 if (slp_perm) 9243 { 9244 /* We don't yet generate SLP_TREE_LOAD_PERMUTATIONs for 9245 variable VF. */ 9246 unsigned int const_vf = vf.to_constant (); 9247 ncopies = CEIL (group_size * const_vf, const_nunits); 9248 dr_chain.create (ncopies); 9249 } 9250 else 9251 ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 9252 } 9253 unsigned int group_el = 0; 9254 unsigned HOST_WIDE_INT 9255 elsz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype))); 9256 unsigned int n_groups = 0; 9257 for (j = 0; j < ncopies; j++) 9258 { 9259 if (nloads > 1) 9260 vec_alloc (v, nloads); 9261 gimple *new_stmt = NULL; 9262 for (i = 0; i < nloads; i++) 9263 { 9264 tree this_off = build_int_cst (TREE_TYPE (alias_off), 9265 group_el * elsz + cst_offset); 9266 tree data_ref = build2 (MEM_REF, ltype, running_off, this_off); 9267 vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); 9268 new_stmt = gimple_build_assign (make_ssa_name (ltype), data_ref); 9269 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 9270 if (nloads > 1) 9271 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, 9272 gimple_assign_lhs (new_stmt)); 9273 9274 group_el += lnel; 9275 if (! slp 9276 || group_el == group_size) 9277 { 9278 n_groups++; 9279 /* When doing SLP make sure to not load elements from 9280 the next vector iteration, those will not be accessed 9281 so just use the last element again. See PR107451. */ 9282 if (!slp || known_lt (n_groups, vf)) 9283 { 9284 tree newoff = copy_ssa_name (running_off); 9285 gimple *incr 9286 = gimple_build_assign (newoff, POINTER_PLUS_EXPR, 9287 running_off, stride_step); 9288 vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi); 9289 running_off = newoff; 9290 } 9291 group_el = 0; 9292 } 9293 } 9294 if (nloads > 1) 9295 { 9296 tree vec_inv = build_constructor (lvectype, v); 9297 new_temp = vect_init_vector (vinfo, stmt_info, 9298 vec_inv, lvectype, gsi); 9299 new_stmt = SSA_NAME_DEF_STMT (new_temp); 9300 if (lvectype != vectype) 9301 { 9302 new_stmt = gimple_build_assign (make_ssa_name (vectype), 9303 VIEW_CONVERT_EXPR, 9304 build1 (VIEW_CONVERT_EXPR, 9305 vectype, new_temp)); 9306 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 9307 } 9308 } 9309 9310 if (slp) 9311 { 9312 if (slp_perm) 9313 dr_chain.quick_push (gimple_assign_lhs (new_stmt)); 9314 else 9315 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 9316 } 9317 else 9318 { 9319 if (j == 0) 9320 *vec_stmt = new_stmt; 9321 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 9322 } 9323 } 9324 if (slp_perm) 9325 { 9326 unsigned n_perms; 9327 vect_transform_slp_perm_load (vinfo, slp_node, dr_chain, gsi, vf, 9328 false, &n_perms); 9329 } 9330 return true; 9331 } 9332 9333 if (memory_access_type == VMAT_GATHER_SCATTER 9334 || (!slp && memory_access_type == VMAT_CONTIGUOUS)) 9335 grouped_load = false; 9336 9337 if (grouped_load) 9338 { 9339 first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 9340 group_size = DR_GROUP_SIZE (first_stmt_info); 9341 /* For SLP vectorization we directly vectorize a subchain 9342 without permutation. */ 9343 if (slp && ! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()) 9344 first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0]; 9345 /* For BB vectorization always use the first stmt to base 9346 the data ref pointer on. */ 9347 if (bb_vinfo) 9348 first_stmt_info_for_drptr 9349 = vect_find_first_scalar_stmt_in_slp (slp_node); 9350 9351 /* Check if the chain of loads is already vectorized. */ 9352 if (STMT_VINFO_VEC_STMTS (first_stmt_info).exists () 9353 /* For SLP we would need to copy over SLP_TREE_VEC_STMTS. 9354 ??? But we can only do so if there is exactly one 9355 as we have no way to get at the rest. Leave the CSE 9356 opportunity alone. 9357 ??? With the group load eventually participating 9358 in multiple different permutations (having multiple 9359 slp nodes which refer to the same group) the CSE 9360 is even wrong code. See PR56270. */ 9361 && !slp) 9362 { 9363 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 9364 return true; 9365 } 9366 first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info); 9367 group_gap_adj = 0; 9368 9369 /* VEC_NUM is the number of vect stmts to be created for this group. */ 9370 if (slp) 9371 { 9372 grouped_load = false; 9373 /* If an SLP permutation is from N elements to N elements, 9374 and if one vector holds a whole number of N, we can load 9375 the inputs to the permutation in the same way as an 9376 unpermuted sequence. In other cases we need to load the 9377 whole group, not only the number of vector stmts the 9378 permutation result fits in. */ 9379 unsigned scalar_lanes = SLP_TREE_LANES (slp_node); 9380 if (slp_perm 9381 && (group_size != scalar_lanes 9382 || !multiple_p (nunits, group_size))) 9383 { 9384 /* We don't yet generate such SLP_TREE_LOAD_PERMUTATIONs for 9385 variable VF; see vect_transform_slp_perm_load. */ 9386 unsigned int const_vf = vf.to_constant (); 9387 unsigned int const_nunits = nunits.to_constant (); 9388 vec_num = CEIL (group_size * const_vf, const_nunits); 9389 group_gap_adj = vf * group_size - nunits * vec_num; 9390 } 9391 else 9392 { 9393 vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 9394 group_gap_adj 9395 = group_size - scalar_lanes; 9396 } 9397 } 9398 else 9399 vec_num = group_size; 9400 9401 ref_type = get_group_alias_ptr_type (first_stmt_info); 9402 } 9403 else 9404 { 9405 first_stmt_info = stmt_info; 9406 first_dr_info = dr_info; 9407 group_size = vec_num = 1; 9408 group_gap_adj = 0; 9409 ref_type = reference_alias_ptr_type (DR_REF (first_dr_info->dr)); 9410 if (slp) 9411 vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 9412 } 9413 9414 gcc_assert (alignment_support_scheme); 9415 vec_loop_masks *loop_masks 9416 = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo) 9417 ? &LOOP_VINFO_MASKS (loop_vinfo) 9418 : NULL); 9419 vec_loop_lens *loop_lens 9420 = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo) 9421 ? &LOOP_VINFO_LENS (loop_vinfo) 9422 : NULL); 9423 9424 /* Shouldn't go with length-based approach if fully masked. */ 9425 gcc_assert (!loop_lens || !loop_masks); 9426 9427 /* Targets with store-lane instructions must not require explicit 9428 realignment. vect_supportable_dr_alignment always returns either 9429 dr_aligned or dr_unaligned_supported for masked operations. */ 9430 gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES 9431 && !mask 9432 && !loop_masks) 9433 || alignment_support_scheme == dr_aligned 9434 || alignment_support_scheme == dr_unaligned_supported); 9435 9436 /* In case the vectorization factor (VF) is bigger than the number 9437 of elements that we can fit in a vectype (nunits), we have to generate 9438 more than one vector stmt - i.e - we need to "unroll" the 9439 vector stmt by a factor VF/nunits. In doing so, we record a pointer 9440 from one copy of the vector stmt to the next, in the field 9441 STMT_VINFO_RELATED_STMT. This is necessary in order to allow following 9442 stages to find the correct vector defs to be used when vectorizing 9443 stmts that use the defs of the current stmt. The example below 9444 illustrates the vectorization process when VF=16 and nunits=4 (i.e., we 9445 need to create 4 vectorized stmts): 9446 9447 before vectorization: 9448 RELATED_STMT VEC_STMT 9449 S1: x = memref - - 9450 S2: z = x + 1 - - 9451 9452 step 1: vectorize stmt S1: 9453 We first create the vector stmt VS1_0, and, as usual, record a 9454 pointer to it in the STMT_VINFO_VEC_STMT of the scalar stmt S1. 9455 Next, we create the vector stmt VS1_1, and record a pointer to 9456 it in the STMT_VINFO_RELATED_STMT of the vector stmt VS1_0. 9457 Similarly, for VS1_2 and VS1_3. This is the resulting chain of 9458 stmts and pointers: 9459 RELATED_STMT VEC_STMT 9460 VS1_0: vx0 = memref0 VS1_1 - 9461 VS1_1: vx1 = memref1 VS1_2 - 9462 VS1_2: vx2 = memref2 VS1_3 - 9463 VS1_3: vx3 = memref3 - - 9464 S1: x = load - VS1_0 9465 S2: z = x + 1 - - 9466 */ 9467 9468 /* In case of interleaving (non-unit grouped access): 9469 9470 S1: x2 = &base + 2 9471 S2: x0 = &base 9472 S3: x1 = &base + 1 9473 S4: x3 = &base + 3 9474 9475 Vectorized loads are created in the order of memory accesses 9476 starting from the access of the first stmt of the chain: 9477 9478 VS1: vx0 = &base 9479 VS2: vx1 = &base + vec_size*1 9480 VS3: vx3 = &base + vec_size*2 9481 VS4: vx4 = &base + vec_size*3 9482 9483 Then permutation statements are generated: 9484 9485 VS5: vx5 = VEC_PERM_EXPR < vx0, vx1, { 0, 2, ..., i*2 } > 9486 VS6: vx6 = VEC_PERM_EXPR < vx0, vx1, { 1, 3, ..., i*2+1 } > 9487 ... 9488 9489 And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts 9490 (the order of the data-refs in the output of vect_permute_load_chain 9491 corresponds to the order of scalar stmts in the interleaving chain - see 9492 the documentation of vect_permute_load_chain()). 9493 The generation of permutation stmts and recording them in 9494 STMT_VINFO_VEC_STMT is done in vect_transform_grouped_load(). 9495 9496 In case of both multiple types and interleaving, the vector loads and 9497 permutation stmts above are created for every copy. The result vector 9498 stmts are put in STMT_VINFO_VEC_STMT for the first copy and in the 9499 corresponding STMT_VINFO_RELATED_STMT for the next copies. */ 9500 9501 /* If the data reference is aligned (dr_aligned) or potentially unaligned 9502 on a target that supports unaligned accesses (dr_unaligned_supported) 9503 we generate the following code: 9504 p = initial_addr; 9505 indx = 0; 9506 loop { 9507 p = p + indx * vectype_size; 9508 vec_dest = *(p); 9509 indx = indx + 1; 9510 } 9511 9512 Otherwise, the data reference is potentially unaligned on a target that 9513 does not support unaligned accesses (dr_explicit_realign_optimized) - 9514 then generate the following code, in which the data in each iteration is 9515 obtained by two vector loads, one from the previous iteration, and one 9516 from the current iteration: 9517 p1 = initial_addr; 9518 msq_init = *(floor(p1)) 9519 p2 = initial_addr + VS - 1; 9520 realignment_token = call target_builtin; 9521 indx = 0; 9522 loop { 9523 p2 = p2 + indx * vectype_size 9524 lsq = *(floor(p2)) 9525 vec_dest = realign_load (msq, lsq, realignment_token) 9526 indx = indx + 1; 9527 msq = lsq; 9528 } */ 9529 9530 /* If the misalignment remains the same throughout the execution of the 9531 loop, we can create the init_addr and permutation mask at the loop 9532 preheader. Otherwise, it needs to be created inside the loop. 9533 This can only occur when vectorizing memory accesses in the inner-loop 9534 nested within an outer-loop that is being vectorized. */ 9535 9536 if (nested_in_vect_loop 9537 && !multiple_p (DR_STEP_ALIGNMENT (dr_info->dr), 9538 GET_MODE_SIZE (TYPE_MODE (vectype)))) 9539 { 9540 gcc_assert (alignment_support_scheme != dr_explicit_realign_optimized); 9541 compute_in_loop = true; 9542 } 9543 9544 bool diff_first_stmt_info 9545 = first_stmt_info_for_drptr && first_stmt_info != first_stmt_info_for_drptr; 9546 9547 tree offset = NULL_TREE; 9548 if ((alignment_support_scheme == dr_explicit_realign_optimized 9549 || alignment_support_scheme == dr_explicit_realign) 9550 && !compute_in_loop) 9551 { 9552 /* If we have different first_stmt_info, we can't set up realignment 9553 here, since we can't guarantee first_stmt_info DR has been 9554 initialized yet, use first_stmt_info_for_drptr DR by bumping the 9555 distance from first_stmt_info DR instead as below. */ 9556 if (!diff_first_stmt_info) 9557 msq = vect_setup_realignment (vinfo, 9558 first_stmt_info, gsi, &realignment_token, 9559 alignment_support_scheme, NULL_TREE, 9560 &at_loop); 9561 if (alignment_support_scheme == dr_explicit_realign_optimized) 9562 { 9563 phi = as_a <gphi *> (SSA_NAME_DEF_STMT (msq)); 9564 offset = size_binop (MINUS_EXPR, TYPE_SIZE_UNIT (vectype), 9565 size_one_node); 9566 gcc_assert (!first_stmt_info_for_drptr); 9567 } 9568 } 9569 else 9570 at_loop = loop; 9571 9572 if (!known_eq (poffset, 0)) 9573 offset = (offset 9574 ? size_binop (PLUS_EXPR, offset, size_int (poffset)) 9575 : size_int (poffset)); 9576 9577 tree bump; 9578 tree vec_offset = NULL_TREE; 9579 if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) 9580 { 9581 aggr_type = NULL_TREE; 9582 bump = NULL_TREE; 9583 } 9584 else if (memory_access_type == VMAT_GATHER_SCATTER) 9585 { 9586 aggr_type = elem_type; 9587 vect_get_strided_load_store_ops (stmt_info, loop_vinfo, &gs_info, 9588 &bump, &vec_offset); 9589 } 9590 else 9591 { 9592 if (memory_access_type == VMAT_LOAD_STORE_LANES) 9593 aggr_type = build_array_type_nelts (elem_type, vec_num * nunits); 9594 else 9595 aggr_type = vectype; 9596 bump = vect_get_data_ptr_increment (vinfo, dr_info, aggr_type, 9597 memory_access_type); 9598 } 9599 9600 auto_vec<tree> vec_offsets; 9601 auto_vec<tree> vec_masks; 9602 if (mask) 9603 { 9604 if (slp_node) 9605 vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[mask_index], 9606 &vec_masks); 9607 else 9608 vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, mask, 9609 &vec_masks, mask_vectype); 9610 } 9611 tree vec_mask = NULL_TREE; 9612 poly_uint64 group_elt = 0; 9613 for (j = 0; j < ncopies; j++) 9614 { 9615 /* 1. Create the vector or array pointer update chain. */ 9616 if (j == 0) 9617 { 9618 bool simd_lane_access_p 9619 = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0; 9620 if (simd_lane_access_p 9621 && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR 9622 && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0)) 9623 && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info)) 9624 && integer_zerop (DR_INIT (first_dr_info->dr)) 9625 && alias_sets_conflict_p (get_alias_set (aggr_type), 9626 get_alias_set (TREE_TYPE (ref_type))) 9627 && (alignment_support_scheme == dr_aligned 9628 || alignment_support_scheme == dr_unaligned_supported)) 9629 { 9630 dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr)); 9631 dataref_offset = build_int_cst (ref_type, 0); 9632 } 9633 else if (diff_first_stmt_info) 9634 { 9635 dataref_ptr 9636 = vect_create_data_ref_ptr (vinfo, first_stmt_info_for_drptr, 9637 aggr_type, at_loop, offset, &dummy, 9638 gsi, &ptr_incr, simd_lane_access_p, 9639 bump); 9640 /* Adjust the pointer by the difference to first_stmt. */ 9641 data_reference_p ptrdr 9642 = STMT_VINFO_DATA_REF (first_stmt_info_for_drptr); 9643 tree diff 9644 = fold_convert (sizetype, 9645 size_binop (MINUS_EXPR, 9646 DR_INIT (first_dr_info->dr), 9647 DR_INIT (ptrdr))); 9648 dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, 9649 stmt_info, diff); 9650 if (alignment_support_scheme == dr_explicit_realign) 9651 { 9652 msq = vect_setup_realignment (vinfo, 9653 first_stmt_info_for_drptr, gsi, 9654 &realignment_token, 9655 alignment_support_scheme, 9656 dataref_ptr, &at_loop); 9657 gcc_assert (!compute_in_loop); 9658 } 9659 } 9660 else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) 9661 { 9662 vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, 9663 slp_node, &gs_info, &dataref_ptr, 9664 &vec_offsets); 9665 } 9666 else 9667 dataref_ptr 9668 = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type, 9669 at_loop, 9670 offset, &dummy, gsi, &ptr_incr, 9671 simd_lane_access_p, bump); 9672 if (mask) 9673 vec_mask = vec_masks[0]; 9674 } 9675 else 9676 { 9677 if (dataref_offset) 9678 dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, 9679 bump); 9680 else if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info)) 9681 dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, 9682 stmt_info, bump); 9683 if (mask) 9684 vec_mask = vec_masks[j]; 9685 } 9686 9687 if (grouped_load || slp_perm) 9688 dr_chain.create (vec_num); 9689 9690 gimple *new_stmt = NULL; 9691 if (memory_access_type == VMAT_LOAD_STORE_LANES) 9692 { 9693 tree vec_array; 9694 9695 vec_array = create_vector_array (vectype, vec_num); 9696 9697 tree final_mask = NULL_TREE; 9698 if (loop_masks) 9699 final_mask = vect_get_loop_mask (gsi, loop_masks, ncopies, 9700 vectype, j); 9701 if (vec_mask) 9702 final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, 9703 final_mask, vec_mask, gsi); 9704 9705 gcall *call; 9706 if (final_mask) 9707 { 9708 /* Emit: 9709 VEC_ARRAY = MASK_LOAD_LANES (DATAREF_PTR, ALIAS_PTR, 9710 VEC_MASK). */ 9711 unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype)); 9712 tree alias_ptr = build_int_cst (ref_type, align); 9713 call = gimple_build_call_internal (IFN_MASK_LOAD_LANES, 3, 9714 dataref_ptr, alias_ptr, 9715 final_mask); 9716 } 9717 else 9718 { 9719 /* Emit: 9720 VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]). */ 9721 data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type); 9722 call = gimple_build_call_internal (IFN_LOAD_LANES, 1, data_ref); 9723 } 9724 gimple_call_set_lhs (call, vec_array); 9725 gimple_call_set_nothrow (call, true); 9726 vect_finish_stmt_generation (vinfo, stmt_info, call, gsi); 9727 new_stmt = call; 9728 9729 /* Extract each vector into an SSA_NAME. */ 9730 for (i = 0; i < vec_num; i++) 9731 { 9732 new_temp = read_vector_array (vinfo, stmt_info, gsi, scalar_dest, 9733 vec_array, i); 9734 dr_chain.quick_push (new_temp); 9735 } 9736 9737 /* Record the mapping between SSA_NAMEs and statements. */ 9738 vect_record_grouped_load_vectors (vinfo, stmt_info, dr_chain); 9739 9740 /* Record that VEC_ARRAY is now dead. */ 9741 vect_clobber_variable (vinfo, stmt_info, gsi, vec_array); 9742 } 9743 else 9744 { 9745 for (i = 0; i < vec_num; i++) 9746 { 9747 tree final_mask = NULL_TREE; 9748 if (loop_masks 9749 && memory_access_type != VMAT_INVARIANT) 9750 final_mask = vect_get_loop_mask (gsi, loop_masks, 9751 vec_num * ncopies, 9752 vectype, vec_num * j + i); 9753 if (vec_mask) 9754 final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, 9755 final_mask, vec_mask, gsi); 9756 9757 if (i > 0 && !STMT_VINFO_GATHER_SCATTER_P (stmt_info)) 9758 dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, 9759 gsi, stmt_info, bump); 9760 9761 /* 2. Create the vector-load in the loop. */ 9762 switch (alignment_support_scheme) 9763 { 9764 case dr_aligned: 9765 case dr_unaligned_supported: 9766 { 9767 unsigned int misalign; 9768 unsigned HOST_WIDE_INT align; 9769 9770 if (memory_access_type == VMAT_GATHER_SCATTER 9771 && gs_info.ifn != IFN_LAST) 9772 { 9773 if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) 9774 vec_offset = vec_offsets[vec_num * j + i]; 9775 tree zero = build_zero_cst (vectype); 9776 tree scale = size_int (gs_info.scale); 9777 gcall *call; 9778 if (final_mask) 9779 call = gimple_build_call_internal 9780 (IFN_MASK_GATHER_LOAD, 5, dataref_ptr, 9781 vec_offset, scale, zero, final_mask); 9782 else 9783 call = gimple_build_call_internal 9784 (IFN_GATHER_LOAD, 4, dataref_ptr, 9785 vec_offset, scale, zero); 9786 gimple_call_set_nothrow (call, true); 9787 new_stmt = call; 9788 data_ref = NULL_TREE; 9789 break; 9790 } 9791 else if (memory_access_type == VMAT_GATHER_SCATTER) 9792 { 9793 /* Emulated gather-scatter. */ 9794 gcc_assert (!final_mask); 9795 unsigned HOST_WIDE_INT const_nunits 9796 = nunits.to_constant (); 9797 unsigned HOST_WIDE_INT const_offset_nunits 9798 = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype) 9799 .to_constant (); 9800 vec<constructor_elt, va_gc> *ctor_elts; 9801 vec_alloc (ctor_elts, const_nunits); 9802 gimple_seq stmts = NULL; 9803 /* We support offset vectors with more elements 9804 than the data vector for now. */ 9805 unsigned HOST_WIDE_INT factor 9806 = const_offset_nunits / const_nunits; 9807 vec_offset = vec_offsets[j / factor]; 9808 unsigned elt_offset = (j % factor) * const_nunits; 9809 tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset)); 9810 tree scale = size_int (gs_info.scale); 9811 align 9812 = get_object_alignment (DR_REF (first_dr_info->dr)); 9813 tree ltype = build_aligned_type (TREE_TYPE (vectype), 9814 align); 9815 for (unsigned k = 0; k < const_nunits; ++k) 9816 { 9817 tree boff = size_binop (MULT_EXPR, 9818 TYPE_SIZE (idx_type), 9819 bitsize_int 9820 (k + elt_offset)); 9821 tree idx = gimple_build (&stmts, BIT_FIELD_REF, 9822 idx_type, vec_offset, 9823 TYPE_SIZE (idx_type), 9824 boff); 9825 idx = gimple_convert (&stmts, sizetype, idx); 9826 idx = gimple_build (&stmts, MULT_EXPR, 9827 sizetype, idx, scale); 9828 tree ptr = gimple_build (&stmts, PLUS_EXPR, 9829 TREE_TYPE (dataref_ptr), 9830 dataref_ptr, idx); 9831 ptr = gimple_convert (&stmts, ptr_type_node, ptr); 9832 tree elt = make_ssa_name (TREE_TYPE (vectype)); 9833 tree ref = build2 (MEM_REF, ltype, ptr, 9834 build_int_cst (ref_type, 0)); 9835 new_stmt = gimple_build_assign (elt, ref); 9836 gimple_seq_add_stmt (&stmts, new_stmt); 9837 CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE, elt); 9838 } 9839 gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); 9840 new_stmt = gimple_build_assign (NULL_TREE, 9841 build_constructor 9842 (vectype, ctor_elts)); 9843 data_ref = NULL_TREE; 9844 break; 9845 } 9846 9847 align = 9848 known_alignment (DR_TARGET_ALIGNMENT (first_dr_info)); 9849 if (alignment_support_scheme == dr_aligned) 9850 misalign = 0; 9851 else if (misalignment == DR_MISALIGNMENT_UNKNOWN) 9852 { 9853 align = dr_alignment 9854 (vect_dr_behavior (vinfo, first_dr_info)); 9855 misalign = 0; 9856 } 9857 else 9858 misalign = misalignment; 9859 if (dataref_offset == NULL_TREE 9860 && TREE_CODE (dataref_ptr) == SSA_NAME) 9861 set_ptr_info_alignment (get_ptr_info (dataref_ptr), 9862 align, misalign); 9863 align = least_bit_hwi (misalign | align); 9864 9865 if (final_mask) 9866 { 9867 tree ptr = build_int_cst (ref_type, 9868 align * BITS_PER_UNIT); 9869 gcall *call 9870 = gimple_build_call_internal (IFN_MASK_LOAD, 3, 9871 dataref_ptr, ptr, 9872 final_mask); 9873 gimple_call_set_nothrow (call, true); 9874 new_stmt = call; 9875 data_ref = NULL_TREE; 9876 } 9877 else if (loop_lens && memory_access_type != VMAT_INVARIANT) 9878 { 9879 tree final_len 9880 = vect_get_loop_len (loop_vinfo, loop_lens, 9881 vec_num * ncopies, 9882 vec_num * j + i); 9883 tree ptr = build_int_cst (ref_type, 9884 align * BITS_PER_UNIT); 9885 9886 machine_mode vmode = TYPE_MODE (vectype); 9887 opt_machine_mode new_ovmode 9888 = get_len_load_store_mode (vmode, true); 9889 machine_mode new_vmode = new_ovmode.require (); 9890 tree qi_type = unsigned_intQI_type_node; 9891 9892 signed char biasval = 9893 LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo); 9894 9895 tree bias = build_int_cst (intQI_type_node, biasval); 9896 9897 gcall *call 9898 = gimple_build_call_internal (IFN_LEN_LOAD, 4, 9899 dataref_ptr, ptr, 9900 final_len, bias); 9901 gimple_call_set_nothrow (call, true); 9902 new_stmt = call; 9903 data_ref = NULL_TREE; 9904 9905 /* Need conversion if it's wrapped with VnQI. */ 9906 if (vmode != new_vmode) 9907 { 9908 tree new_vtype 9909 = build_vector_type_for_mode (qi_type, new_vmode); 9910 tree var = vect_get_new_ssa_name (new_vtype, 9911 vect_simple_var); 9912 gimple_set_lhs (call, var); 9913 vect_finish_stmt_generation (vinfo, stmt_info, call, 9914 gsi); 9915 tree op = build1 (VIEW_CONVERT_EXPR, vectype, var); 9916 new_stmt 9917 = gimple_build_assign (vec_dest, 9918 VIEW_CONVERT_EXPR, op); 9919 } 9920 } 9921 else 9922 { 9923 tree ltype = vectype; 9924 tree new_vtype = NULL_TREE; 9925 unsigned HOST_WIDE_INT gap 9926 = DR_GROUP_GAP (first_stmt_info); 9927 unsigned int vect_align 9928 = vect_known_alignment_in_bytes (first_dr_info, 9929 vectype); 9930 unsigned int scalar_dr_size 9931 = vect_get_scalar_dr_size (first_dr_info); 9932 /* If there's no peeling for gaps but we have a gap 9933 with slp loads then load the lower half of the 9934 vector only. See get_group_load_store_type for 9935 when we apply this optimization. */ 9936 if (slp 9937 && loop_vinfo 9938 && !LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo) 9939 && gap != 0 9940 && known_eq (nunits, (group_size - gap) * 2) 9941 && known_eq (nunits, group_size) 9942 && gap >= (vect_align / scalar_dr_size)) 9943 { 9944 tree half_vtype; 9945 new_vtype 9946 = vector_vector_composition_type (vectype, 2, 9947 &half_vtype); 9948 if (new_vtype != NULL_TREE) 9949 ltype = half_vtype; 9950 } 9951 tree offset 9952 = (dataref_offset ? dataref_offset 9953 : build_int_cst (ref_type, 0)); 9954 if (ltype != vectype 9955 && memory_access_type == VMAT_CONTIGUOUS_REVERSE) 9956 { 9957 unsigned HOST_WIDE_INT gap_offset 9958 = gap * tree_to_uhwi (TYPE_SIZE_UNIT (elem_type)); 9959 tree gapcst = build_int_cst (ref_type, gap_offset); 9960 offset = size_binop (PLUS_EXPR, offset, gapcst); 9961 } 9962 data_ref 9963 = fold_build2 (MEM_REF, ltype, dataref_ptr, offset); 9964 if (alignment_support_scheme == dr_aligned) 9965 ; 9966 else 9967 TREE_TYPE (data_ref) 9968 = build_aligned_type (TREE_TYPE (data_ref), 9969 align * BITS_PER_UNIT); 9970 if (ltype != vectype) 9971 { 9972 vect_copy_ref_info (data_ref, 9973 DR_REF (first_dr_info->dr)); 9974 tree tem = make_ssa_name (ltype); 9975 new_stmt = gimple_build_assign (tem, data_ref); 9976 vect_finish_stmt_generation (vinfo, stmt_info, 9977 new_stmt, gsi); 9978 data_ref = NULL; 9979 vec<constructor_elt, va_gc> *v; 9980 vec_alloc (v, 2); 9981 if (memory_access_type == VMAT_CONTIGUOUS_REVERSE) 9982 { 9983 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, 9984 build_zero_cst (ltype)); 9985 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem); 9986 } 9987 else 9988 { 9989 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem); 9990 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, 9991 build_zero_cst (ltype)); 9992 } 9993 gcc_assert (new_vtype != NULL_TREE); 9994 if (new_vtype == vectype) 9995 new_stmt = gimple_build_assign ( 9996 vec_dest, build_constructor (vectype, v)); 9997 else 9998 { 9999 tree new_vname = make_ssa_name (new_vtype); 10000 new_stmt = gimple_build_assign ( 10001 new_vname, build_constructor (new_vtype, v)); 10002 vect_finish_stmt_generation (vinfo, stmt_info, 10003 new_stmt, gsi); 10004 new_stmt = gimple_build_assign ( 10005 vec_dest, build1 (VIEW_CONVERT_EXPR, vectype, 10006 new_vname)); 10007 } 10008 } 10009 } 10010 break; 10011 } 10012 case dr_explicit_realign: 10013 { 10014 tree ptr, bump; 10015 10016 tree vs = size_int (TYPE_VECTOR_SUBPARTS (vectype)); 10017 10018 if (compute_in_loop) 10019 msq = vect_setup_realignment (vinfo, first_stmt_info, gsi, 10020 &realignment_token, 10021 dr_explicit_realign, 10022 dataref_ptr, NULL); 10023 10024 if (TREE_CODE (dataref_ptr) == SSA_NAME) 10025 ptr = copy_ssa_name (dataref_ptr); 10026 else 10027 ptr = make_ssa_name (TREE_TYPE (dataref_ptr)); 10028 // For explicit realign the target alignment should be 10029 // known at compile time. 10030 unsigned HOST_WIDE_INT align = 10031 DR_TARGET_ALIGNMENT (first_dr_info).to_constant (); 10032 new_stmt = gimple_build_assign 10033 (ptr, BIT_AND_EXPR, dataref_ptr, 10034 build_int_cst 10035 (TREE_TYPE (dataref_ptr), 10036 -(HOST_WIDE_INT) align)); 10037 vect_finish_stmt_generation (vinfo, stmt_info, 10038 new_stmt, gsi); 10039 data_ref 10040 = build2 (MEM_REF, vectype, ptr, 10041 build_int_cst (ref_type, 0)); 10042 vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); 10043 vec_dest = vect_create_destination_var (scalar_dest, 10044 vectype); 10045 new_stmt = gimple_build_assign (vec_dest, data_ref); 10046 new_temp = make_ssa_name (vec_dest, new_stmt); 10047 gimple_assign_set_lhs (new_stmt, new_temp); 10048 gimple_move_vops (new_stmt, stmt_info->stmt); 10049 vect_finish_stmt_generation (vinfo, stmt_info, 10050 new_stmt, gsi); 10051 msq = new_temp; 10052 10053 bump = size_binop (MULT_EXPR, vs, 10054 TYPE_SIZE_UNIT (elem_type)); 10055 bump = size_binop (MINUS_EXPR, bump, size_one_node); 10056 ptr = bump_vector_ptr (vinfo, dataref_ptr, NULL, gsi, 10057 stmt_info, bump); 10058 new_stmt = gimple_build_assign 10059 (NULL_TREE, BIT_AND_EXPR, ptr, 10060 build_int_cst 10061 (TREE_TYPE (ptr), -(HOST_WIDE_INT) align)); 10062 ptr = copy_ssa_name (ptr, new_stmt); 10063 gimple_assign_set_lhs (new_stmt, ptr); 10064 vect_finish_stmt_generation (vinfo, stmt_info, 10065 new_stmt, gsi); 10066 data_ref 10067 = build2 (MEM_REF, vectype, ptr, 10068 build_int_cst (ref_type, 0)); 10069 break; 10070 } 10071 case dr_explicit_realign_optimized: 10072 { 10073 if (TREE_CODE (dataref_ptr) == SSA_NAME) 10074 new_temp = copy_ssa_name (dataref_ptr); 10075 else 10076 new_temp = make_ssa_name (TREE_TYPE (dataref_ptr)); 10077 // We should only be doing this if we know the target 10078 // alignment at compile time. 10079 unsigned HOST_WIDE_INT align = 10080 DR_TARGET_ALIGNMENT (first_dr_info).to_constant (); 10081 new_stmt = gimple_build_assign 10082 (new_temp, BIT_AND_EXPR, dataref_ptr, 10083 build_int_cst (TREE_TYPE (dataref_ptr), 10084 -(HOST_WIDE_INT) align)); 10085 vect_finish_stmt_generation (vinfo, stmt_info, 10086 new_stmt, gsi); 10087 data_ref 10088 = build2 (MEM_REF, vectype, new_temp, 10089 build_int_cst (ref_type, 0)); 10090 break; 10091 } 10092 default: 10093 gcc_unreachable (); 10094 } 10095 vec_dest = vect_create_destination_var (scalar_dest, vectype); 10096 /* DATA_REF is null if we've already built the statement. */ 10097 if (data_ref) 10098 { 10099 vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr)); 10100 new_stmt = gimple_build_assign (vec_dest, data_ref); 10101 } 10102 new_temp = make_ssa_name (vec_dest, new_stmt); 10103 gimple_set_lhs (new_stmt, new_temp); 10104 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 10105 10106 /* 3. Handle explicit realignment if necessary/supported. 10107 Create in loop: 10108 vec_dest = realign_load (msq, lsq, realignment_token) */ 10109 if (alignment_support_scheme == dr_explicit_realign_optimized 10110 || alignment_support_scheme == dr_explicit_realign) 10111 { 10112 lsq = gimple_assign_lhs (new_stmt); 10113 if (!realignment_token) 10114 realignment_token = dataref_ptr; 10115 vec_dest = vect_create_destination_var (scalar_dest, vectype); 10116 new_stmt = gimple_build_assign (vec_dest, REALIGN_LOAD_EXPR, 10117 msq, lsq, realignment_token); 10118 new_temp = make_ssa_name (vec_dest, new_stmt); 10119 gimple_assign_set_lhs (new_stmt, new_temp); 10120 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 10121 10122 if (alignment_support_scheme == dr_explicit_realign_optimized) 10123 { 10124 gcc_assert (phi); 10125 if (i == vec_num - 1 && j == ncopies - 1) 10126 add_phi_arg (phi, lsq, 10127 loop_latch_edge (containing_loop), 10128 UNKNOWN_LOCATION); 10129 msq = lsq; 10130 } 10131 } 10132 10133 if (memory_access_type == VMAT_CONTIGUOUS_REVERSE) 10134 { 10135 tree perm_mask = perm_mask_for_reverse (vectype); 10136 new_temp = permute_vec_elements (vinfo, new_temp, new_temp, 10137 perm_mask, stmt_info, gsi); 10138 new_stmt = SSA_NAME_DEF_STMT (new_temp); 10139 } 10140 10141 /* Collect vector loads and later create their permutation in 10142 vect_transform_grouped_load (). */ 10143 if (grouped_load || slp_perm) 10144 dr_chain.quick_push (new_temp); 10145 10146 /* Store vector loads in the corresponding SLP_NODE. */ 10147 if (slp && !slp_perm) 10148 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 10149 10150 /* With SLP permutation we load the gaps as well, without 10151 we need to skip the gaps after we manage to fully load 10152 all elements. group_gap_adj is DR_GROUP_SIZE here. */ 10153 group_elt += nunits; 10154 if (maybe_ne (group_gap_adj, 0U) 10155 && !slp_perm 10156 && known_eq (group_elt, group_size - group_gap_adj)) 10157 { 10158 poly_wide_int bump_val 10159 = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) 10160 * group_gap_adj); 10161 if (tree_int_cst_sgn 10162 (vect_dr_behavior (vinfo, dr_info)->step) == -1) 10163 bump_val = -bump_val; 10164 tree bump = wide_int_to_tree (sizetype, bump_val); 10165 dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, 10166 gsi, stmt_info, bump); 10167 group_elt = 0; 10168 } 10169 } 10170 /* Bump the vector pointer to account for a gap or for excess 10171 elements loaded for a permuted SLP load. */ 10172 if (maybe_ne (group_gap_adj, 0U) && slp_perm) 10173 { 10174 poly_wide_int bump_val 10175 = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) 10176 * group_gap_adj); 10177 if (tree_int_cst_sgn 10178 (vect_dr_behavior (vinfo, dr_info)->step) == -1) 10179 bump_val = -bump_val; 10180 tree bump = wide_int_to_tree (sizetype, bump_val); 10181 dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, 10182 stmt_info, bump); 10183 } 10184 } 10185 10186 if (slp && !slp_perm) 10187 continue; 10188 10189 if (slp_perm) 10190 { 10191 unsigned n_perms; 10192 /* For SLP we know we've seen all possible uses of dr_chain so 10193 direct vect_transform_slp_perm_load to DCE the unused parts. 10194 ??? This is a hack to prevent compile-time issues as seen 10195 in PR101120 and friends. */ 10196 bool ok = vect_transform_slp_perm_load (vinfo, slp_node, dr_chain, 10197 gsi, vf, false, &n_perms, 10198 nullptr, true); 10199 gcc_assert (ok); 10200 } 10201 else 10202 { 10203 if (grouped_load) 10204 { 10205 if (memory_access_type != VMAT_LOAD_STORE_LANES) 10206 vect_transform_grouped_load (vinfo, stmt_info, dr_chain, 10207 group_size, gsi); 10208 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 10209 } 10210 else 10211 { 10212 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 10213 } 10214 } 10215 dr_chain.release (); 10216 } 10217 if (!slp) 10218 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 10219 10220 return true; 10221 } 10222 10223 /* Function vect_is_simple_cond. 10224 10225 Input: 10226 LOOP - the loop that is being vectorized. 10227 COND - Condition that is checked for simple use. 10228 10229 Output: 10230 *COMP_VECTYPE - the vector type for the comparison. 10231 *DTS - The def types for the arguments of the comparison 10232 10233 Returns whether a COND can be vectorized. Checks whether 10234 condition operands are supportable using vec_is_simple_use. */ 10235 10236 static bool 10237 vect_is_simple_cond (tree cond, vec_info *vinfo, stmt_vec_info stmt_info, 10238 slp_tree slp_node, tree *comp_vectype, 10239 enum vect_def_type *dts, tree vectype) 10240 { 10241 tree lhs, rhs; 10242 tree vectype1 = NULL_TREE, vectype2 = NULL_TREE; 10243 slp_tree slp_op; 10244 10245 /* Mask case. */ 10246 if (TREE_CODE (cond) == SSA_NAME 10247 && VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (cond))) 10248 { 10249 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &cond, 10250 &slp_op, &dts[0], comp_vectype) 10251 || !*comp_vectype 10252 || !VECTOR_BOOLEAN_TYPE_P (*comp_vectype)) 10253 return false; 10254 return true; 10255 } 10256 10257 if (!COMPARISON_CLASS_P (cond)) 10258 return false; 10259 10260 lhs = TREE_OPERAND (cond, 0); 10261 rhs = TREE_OPERAND (cond, 1); 10262 10263 if (TREE_CODE (lhs) == SSA_NAME) 10264 { 10265 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, 10266 &lhs, &slp_op, &dts[0], &vectype1)) 10267 return false; 10268 } 10269 else if (TREE_CODE (lhs) == INTEGER_CST || TREE_CODE (lhs) == REAL_CST 10270 || TREE_CODE (lhs) == FIXED_CST) 10271 dts[0] = vect_constant_def; 10272 else 10273 return false; 10274 10275 if (TREE_CODE (rhs) == SSA_NAME) 10276 { 10277 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1, 10278 &rhs, &slp_op, &dts[1], &vectype2)) 10279 return false; 10280 } 10281 else if (TREE_CODE (rhs) == INTEGER_CST || TREE_CODE (rhs) == REAL_CST 10282 || TREE_CODE (rhs) == FIXED_CST) 10283 dts[1] = vect_constant_def; 10284 else 10285 return false; 10286 10287 if (vectype1 && vectype2 10288 && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1), 10289 TYPE_VECTOR_SUBPARTS (vectype2))) 10290 return false; 10291 10292 *comp_vectype = vectype1 ? vectype1 : vectype2; 10293 /* Invariant comparison. */ 10294 if (! *comp_vectype) 10295 { 10296 tree scalar_type = TREE_TYPE (lhs); 10297 if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type)) 10298 *comp_vectype = truth_type_for (vectype); 10299 else 10300 { 10301 /* If we can widen the comparison to match vectype do so. */ 10302 if (INTEGRAL_TYPE_P (scalar_type) 10303 && !slp_node 10304 && tree_int_cst_lt (TYPE_SIZE (scalar_type), 10305 TYPE_SIZE (TREE_TYPE (vectype)))) 10306 scalar_type = build_nonstandard_integer_type 10307 (vector_element_bits (vectype), TYPE_UNSIGNED (scalar_type)); 10308 *comp_vectype = get_vectype_for_scalar_type (vinfo, scalar_type, 10309 slp_node); 10310 } 10311 } 10312 10313 return true; 10314 } 10315 10316 /* vectorizable_condition. 10317 10318 Check if STMT_INFO is conditional modify expression that can be vectorized. 10319 If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized 10320 stmt using VEC_COND_EXPR to replace it, put it in VEC_STMT, and insert it 10321 at GSI. 10322 10323 When STMT_INFO is vectorized as a nested cycle, for_reduction is true. 10324 10325 Return true if STMT_INFO is vectorizable in this way. */ 10326 10327 static bool 10328 vectorizable_condition (vec_info *vinfo, 10329 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 10330 gimple **vec_stmt, 10331 slp_tree slp_node, stmt_vector_for_cost *cost_vec) 10332 { 10333 tree scalar_dest = NULL_TREE; 10334 tree vec_dest = NULL_TREE; 10335 tree cond_expr, cond_expr0 = NULL_TREE, cond_expr1 = NULL_TREE; 10336 tree then_clause, else_clause; 10337 tree comp_vectype = NULL_TREE; 10338 tree vec_cond_lhs = NULL_TREE, vec_cond_rhs = NULL_TREE; 10339 tree vec_then_clause = NULL_TREE, vec_else_clause = NULL_TREE; 10340 tree vec_compare; 10341 tree new_temp; 10342 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 10343 enum vect_def_type dts[4] 10344 = {vect_unknown_def_type, vect_unknown_def_type, 10345 vect_unknown_def_type, vect_unknown_def_type}; 10346 int ndts = 4; 10347 int ncopies; 10348 int vec_num; 10349 enum tree_code code, cond_code, bitop1 = NOP_EXPR, bitop2 = NOP_EXPR; 10350 int i; 10351 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 10352 vec<tree> vec_oprnds0 = vNULL; 10353 vec<tree> vec_oprnds1 = vNULL; 10354 vec<tree> vec_oprnds2 = vNULL; 10355 vec<tree> vec_oprnds3 = vNULL; 10356 tree vec_cmp_type; 10357 bool masked = false; 10358 10359 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 10360 return false; 10361 10362 /* Is vectorizable conditional operation? */ 10363 gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt); 10364 if (!stmt) 10365 return false; 10366 10367 code = gimple_assign_rhs_code (stmt); 10368 if (code != COND_EXPR) 10369 return false; 10370 10371 stmt_vec_info reduc_info = NULL; 10372 int reduc_index = -1; 10373 vect_reduction_type reduction_type = TREE_CODE_REDUCTION; 10374 bool for_reduction 10375 = STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)) != NULL; 10376 if (for_reduction) 10377 { 10378 if (slp_node) 10379 return false; 10380 reduc_info = info_for_reduction (vinfo, stmt_info); 10381 reduction_type = STMT_VINFO_REDUC_TYPE (reduc_info); 10382 reduc_index = STMT_VINFO_REDUC_IDX (stmt_info); 10383 gcc_assert (reduction_type != EXTRACT_LAST_REDUCTION 10384 || reduc_index != -1); 10385 } 10386 else 10387 { 10388 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def) 10389 return false; 10390 } 10391 10392 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 10393 tree vectype1 = NULL_TREE, vectype2 = NULL_TREE; 10394 10395 if (slp_node) 10396 { 10397 ncopies = 1; 10398 vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); 10399 } 10400 else 10401 { 10402 ncopies = vect_get_num_copies (loop_vinfo, vectype); 10403 vec_num = 1; 10404 } 10405 10406 gcc_assert (ncopies >= 1); 10407 if (for_reduction && ncopies > 1) 10408 return false; /* FORNOW */ 10409 10410 cond_expr = gimple_assign_rhs1 (stmt); 10411 10412 if (!vect_is_simple_cond (cond_expr, vinfo, stmt_info, slp_node, 10413 &comp_vectype, &dts[0], vectype) 10414 || !comp_vectype) 10415 return false; 10416 10417 unsigned op_adjust = COMPARISON_CLASS_P (cond_expr) ? 1 : 0; 10418 slp_tree then_slp_node, else_slp_node; 10419 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1 + op_adjust, 10420 &then_clause, &then_slp_node, &dts[2], &vectype1)) 10421 return false; 10422 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 2 + op_adjust, 10423 &else_clause, &else_slp_node, &dts[3], &vectype2)) 10424 return false; 10425 10426 if (vectype1 && !useless_type_conversion_p (vectype, vectype1)) 10427 return false; 10428 10429 if (vectype2 && !useless_type_conversion_p (vectype, vectype2)) 10430 return false; 10431 10432 masked = !COMPARISON_CLASS_P (cond_expr); 10433 vec_cmp_type = truth_type_for (comp_vectype); 10434 10435 if (vec_cmp_type == NULL_TREE) 10436 return false; 10437 10438 cond_code = TREE_CODE (cond_expr); 10439 if (!masked) 10440 { 10441 cond_expr0 = TREE_OPERAND (cond_expr, 0); 10442 cond_expr1 = TREE_OPERAND (cond_expr, 1); 10443 } 10444 10445 /* For conditional reductions, the "then" value needs to be the candidate 10446 value calculated by this iteration while the "else" value needs to be 10447 the result carried over from previous iterations. If the COND_EXPR 10448 is the other way around, we need to swap it. */ 10449 bool must_invert_cmp_result = false; 10450 if (reduction_type == EXTRACT_LAST_REDUCTION && reduc_index == 1) 10451 { 10452 if (masked) 10453 must_invert_cmp_result = true; 10454 else 10455 { 10456 bool honor_nans = HONOR_NANS (TREE_TYPE (cond_expr0)); 10457 tree_code new_code = invert_tree_comparison (cond_code, honor_nans); 10458 if (new_code == ERROR_MARK) 10459 must_invert_cmp_result = true; 10460 else 10461 { 10462 cond_code = new_code; 10463 /* Make sure we don't accidentally use the old condition. */ 10464 cond_expr = NULL_TREE; 10465 } 10466 } 10467 std::swap (then_clause, else_clause); 10468 } 10469 10470 if (!masked && VECTOR_BOOLEAN_TYPE_P (comp_vectype)) 10471 { 10472 /* Boolean values may have another representation in vectors 10473 and therefore we prefer bit operations over comparison for 10474 them (which also works for scalar masks). We store opcodes 10475 to use in bitop1 and bitop2. Statement is vectorized as 10476 BITOP2 (rhs1 BITOP1 rhs2) or rhs1 BITOP2 (BITOP1 rhs2) 10477 depending on bitop1 and bitop2 arity. */ 10478 switch (cond_code) 10479 { 10480 case GT_EXPR: 10481 bitop1 = BIT_NOT_EXPR; 10482 bitop2 = BIT_AND_EXPR; 10483 break; 10484 case GE_EXPR: 10485 bitop1 = BIT_NOT_EXPR; 10486 bitop2 = BIT_IOR_EXPR; 10487 break; 10488 case LT_EXPR: 10489 bitop1 = BIT_NOT_EXPR; 10490 bitop2 = BIT_AND_EXPR; 10491 std::swap (cond_expr0, cond_expr1); 10492 break; 10493 case LE_EXPR: 10494 bitop1 = BIT_NOT_EXPR; 10495 bitop2 = BIT_IOR_EXPR; 10496 std::swap (cond_expr0, cond_expr1); 10497 break; 10498 case NE_EXPR: 10499 bitop1 = BIT_XOR_EXPR; 10500 break; 10501 case EQ_EXPR: 10502 bitop1 = BIT_XOR_EXPR; 10503 bitop2 = BIT_NOT_EXPR; 10504 break; 10505 default: 10506 return false; 10507 } 10508 cond_code = SSA_NAME; 10509 } 10510 10511 if (TREE_CODE_CLASS (cond_code) == tcc_comparison 10512 && reduction_type == EXTRACT_LAST_REDUCTION 10513 && !expand_vec_cmp_expr_p (comp_vectype, vec_cmp_type, cond_code)) 10514 { 10515 if (dump_enabled_p ()) 10516 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 10517 "reduction comparison operation not supported.\n"); 10518 return false; 10519 } 10520 10521 if (!vec_stmt) 10522 { 10523 if (bitop1 != NOP_EXPR) 10524 { 10525 machine_mode mode = TYPE_MODE (comp_vectype); 10526 optab optab; 10527 10528 optab = optab_for_tree_code (bitop1, comp_vectype, optab_default); 10529 if (!optab || optab_handler (optab, mode) == CODE_FOR_nothing) 10530 return false; 10531 10532 if (bitop2 != NOP_EXPR) 10533 { 10534 optab = optab_for_tree_code (bitop2, comp_vectype, 10535 optab_default); 10536 if (!optab || optab_handler (optab, mode) == CODE_FOR_nothing) 10537 return false; 10538 } 10539 } 10540 10541 vect_cost_for_stmt kind = vector_stmt; 10542 if (reduction_type == EXTRACT_LAST_REDUCTION) 10543 /* Count one reduction-like operation per vector. */ 10544 kind = vec_to_scalar; 10545 else if (!expand_vec_cond_expr_p (vectype, comp_vectype, cond_code)) 10546 return false; 10547 10548 if (slp_node 10549 && (!vect_maybe_update_slp_op_vectype 10550 (SLP_TREE_CHILDREN (slp_node)[0], comp_vectype) 10551 || (op_adjust == 1 10552 && !vect_maybe_update_slp_op_vectype 10553 (SLP_TREE_CHILDREN (slp_node)[1], comp_vectype)) 10554 || !vect_maybe_update_slp_op_vectype (then_slp_node, vectype) 10555 || !vect_maybe_update_slp_op_vectype (else_slp_node, vectype))) 10556 { 10557 if (dump_enabled_p ()) 10558 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 10559 "incompatible vector types for invariants\n"); 10560 return false; 10561 } 10562 10563 if (loop_vinfo && for_reduction 10564 && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)) 10565 { 10566 if (reduction_type == EXTRACT_LAST_REDUCTION) 10567 vect_record_loop_mask (loop_vinfo, &LOOP_VINFO_MASKS (loop_vinfo), 10568 ncopies * vec_num, vectype, NULL); 10569 /* Extra inactive lanes should be safe for vect_nested_cycle. */ 10570 else if (STMT_VINFO_DEF_TYPE (reduc_info) != vect_nested_cycle) 10571 { 10572 if (dump_enabled_p ()) 10573 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 10574 "conditional reduction prevents the use" 10575 " of partial vectors.\n"); 10576 LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; 10577 } 10578 } 10579 10580 STMT_VINFO_TYPE (stmt_info) = condition_vec_info_type; 10581 vect_model_simple_cost (vinfo, stmt_info, ncopies, dts, ndts, slp_node, 10582 cost_vec, kind); 10583 return true; 10584 } 10585 10586 /* Transform. */ 10587 10588 /* Handle def. */ 10589 scalar_dest = gimple_assign_lhs (stmt); 10590 if (reduction_type != EXTRACT_LAST_REDUCTION) 10591 vec_dest = vect_create_destination_var (scalar_dest, vectype); 10592 10593 bool swap_cond_operands = false; 10594 10595 /* See whether another part of the vectorized code applies a loop 10596 mask to the condition, or to its inverse. */ 10597 10598 vec_loop_masks *masks = NULL; 10599 if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)) 10600 { 10601 if (reduction_type == EXTRACT_LAST_REDUCTION) 10602 masks = &LOOP_VINFO_MASKS (loop_vinfo); 10603 else 10604 { 10605 scalar_cond_masked_key cond (cond_expr, ncopies); 10606 if (loop_vinfo->scalar_cond_masked_set.contains (cond)) 10607 masks = &LOOP_VINFO_MASKS (loop_vinfo); 10608 else 10609 { 10610 bool honor_nans = HONOR_NANS (TREE_TYPE (cond.op0)); 10611 tree_code orig_code = cond.code; 10612 cond.code = invert_tree_comparison (cond.code, honor_nans); 10613 if (!masked && loop_vinfo->scalar_cond_masked_set.contains (cond)) 10614 { 10615 masks = &LOOP_VINFO_MASKS (loop_vinfo); 10616 cond_code = cond.code; 10617 swap_cond_operands = true; 10618 } 10619 else 10620 { 10621 /* Try the inverse of the current mask. We check if the 10622 inverse mask is live and if so we generate a negate of 10623 the current mask such that we still honor NaNs. */ 10624 cond.inverted_p = true; 10625 cond.code = orig_code; 10626 if (loop_vinfo->scalar_cond_masked_set.contains (cond)) 10627 { 10628 masks = &LOOP_VINFO_MASKS (loop_vinfo); 10629 cond_code = cond.code; 10630 swap_cond_operands = true; 10631 must_invert_cmp_result = true; 10632 } 10633 } 10634 } 10635 } 10636 } 10637 10638 /* Handle cond expr. */ 10639 if (masked) 10640 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, 10641 cond_expr, &vec_oprnds0, comp_vectype, 10642 then_clause, &vec_oprnds2, vectype, 10643 reduction_type != EXTRACT_LAST_REDUCTION 10644 ? else_clause : NULL, &vec_oprnds3, vectype); 10645 else 10646 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, 10647 cond_expr0, &vec_oprnds0, comp_vectype, 10648 cond_expr1, &vec_oprnds1, comp_vectype, 10649 then_clause, &vec_oprnds2, vectype, 10650 reduction_type != EXTRACT_LAST_REDUCTION 10651 ? else_clause : NULL, &vec_oprnds3, vectype); 10652 10653 /* Arguments are ready. Create the new vector stmt. */ 10654 FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_cond_lhs) 10655 { 10656 vec_then_clause = vec_oprnds2[i]; 10657 if (reduction_type != EXTRACT_LAST_REDUCTION) 10658 vec_else_clause = vec_oprnds3[i]; 10659 10660 if (swap_cond_operands) 10661 std::swap (vec_then_clause, vec_else_clause); 10662 10663 if (masked) 10664 vec_compare = vec_cond_lhs; 10665 else 10666 { 10667 vec_cond_rhs = vec_oprnds1[i]; 10668 if (bitop1 == NOP_EXPR) 10669 { 10670 gimple_seq stmts = NULL; 10671 vec_compare = gimple_build (&stmts, cond_code, vec_cmp_type, 10672 vec_cond_lhs, vec_cond_rhs); 10673 gsi_insert_before (gsi, stmts, GSI_SAME_STMT); 10674 } 10675 else 10676 { 10677 new_temp = make_ssa_name (vec_cmp_type); 10678 gassign *new_stmt; 10679 if (bitop1 == BIT_NOT_EXPR) 10680 new_stmt = gimple_build_assign (new_temp, bitop1, 10681 vec_cond_rhs); 10682 else 10683 new_stmt 10684 = gimple_build_assign (new_temp, bitop1, vec_cond_lhs, 10685 vec_cond_rhs); 10686 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 10687 if (bitop2 == NOP_EXPR) 10688 vec_compare = new_temp; 10689 else if (bitop2 == BIT_NOT_EXPR) 10690 { 10691 /* Instead of doing ~x ? y : z do x ? z : y. */ 10692 vec_compare = new_temp; 10693 std::swap (vec_then_clause, vec_else_clause); 10694 } 10695 else 10696 { 10697 vec_compare = make_ssa_name (vec_cmp_type); 10698 new_stmt 10699 = gimple_build_assign (vec_compare, bitop2, 10700 vec_cond_lhs, new_temp); 10701 vect_finish_stmt_generation (vinfo, stmt_info, 10702 new_stmt, gsi); 10703 } 10704 } 10705 } 10706 10707 /* If we decided to apply a loop mask to the result of the vector 10708 comparison, AND the comparison with the mask now. Later passes 10709 should then be able to reuse the AND results between mulitple 10710 vector statements. 10711 10712 For example: 10713 for (int i = 0; i < 100; ++i) 10714 x[i] = y[i] ? z[i] : 10; 10715 10716 results in following optimized GIMPLE: 10717 10718 mask__35.8_43 = vect__4.7_41 != { 0, ... }; 10719 vec_mask_and_46 = loop_mask_40 & mask__35.8_43; 10720 _19 = &MEM[base: z_12(D), index: ivtmp_56, step: 4, offset: 0B]; 10721 vect_iftmp.11_47 = .MASK_LOAD (_19, 4B, vec_mask_and_46); 10722 vect_iftmp.12_52 = VEC_COND_EXPR <vec_mask_and_46, 10723 vect_iftmp.11_47, { 10, ... }>; 10724 10725 instead of using a masked and unmasked forms of 10726 vec != { 0, ... } (masked in the MASK_LOAD, 10727 unmasked in the VEC_COND_EXPR). */ 10728 10729 /* Force vec_compare to be an SSA_NAME rather than a comparison, 10730 in cases where that's necessary. */ 10731 10732 if (masks || reduction_type == EXTRACT_LAST_REDUCTION) 10733 { 10734 if (!is_gimple_val (vec_compare)) 10735 { 10736 tree vec_compare_name = make_ssa_name (vec_cmp_type); 10737 gassign *new_stmt = gimple_build_assign (vec_compare_name, 10738 vec_compare); 10739 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 10740 vec_compare = vec_compare_name; 10741 } 10742 10743 if (must_invert_cmp_result) 10744 { 10745 tree vec_compare_name = make_ssa_name (vec_cmp_type); 10746 gassign *new_stmt = gimple_build_assign (vec_compare_name, 10747 BIT_NOT_EXPR, 10748 vec_compare); 10749 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 10750 vec_compare = vec_compare_name; 10751 } 10752 10753 if (masks) 10754 { 10755 tree loop_mask 10756 = vect_get_loop_mask (gsi, masks, vec_num * ncopies, 10757 vectype, i); 10758 tree tmp2 = make_ssa_name (vec_cmp_type); 10759 gassign *g 10760 = gimple_build_assign (tmp2, BIT_AND_EXPR, vec_compare, 10761 loop_mask); 10762 vect_finish_stmt_generation (vinfo, stmt_info, g, gsi); 10763 vec_compare = tmp2; 10764 } 10765 } 10766 10767 gimple *new_stmt; 10768 if (reduction_type == EXTRACT_LAST_REDUCTION) 10769 { 10770 gimple *old_stmt = vect_orig_stmt (stmt_info)->stmt; 10771 tree lhs = gimple_get_lhs (old_stmt); 10772 new_stmt = gimple_build_call_internal 10773 (IFN_FOLD_EXTRACT_LAST, 3, else_clause, vec_compare, 10774 vec_then_clause); 10775 gimple_call_set_lhs (new_stmt, lhs); 10776 SSA_NAME_DEF_STMT (lhs) = new_stmt; 10777 if (old_stmt == gsi_stmt (*gsi)) 10778 vect_finish_replace_stmt (vinfo, stmt_info, new_stmt); 10779 else 10780 { 10781 /* In this case we're moving the definition to later in the 10782 block. That doesn't matter because the only uses of the 10783 lhs are in phi statements. */ 10784 gimple_stmt_iterator old_gsi = gsi_for_stmt (old_stmt); 10785 gsi_remove (&old_gsi, true); 10786 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 10787 } 10788 } 10789 else 10790 { 10791 new_temp = make_ssa_name (vec_dest); 10792 new_stmt = gimple_build_assign (new_temp, VEC_COND_EXPR, vec_compare, 10793 vec_then_clause, vec_else_clause); 10794 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 10795 } 10796 if (slp_node) 10797 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 10798 else 10799 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 10800 } 10801 10802 if (!slp_node) 10803 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 10804 10805 vec_oprnds0.release (); 10806 vec_oprnds1.release (); 10807 vec_oprnds2.release (); 10808 vec_oprnds3.release (); 10809 10810 return true; 10811 } 10812 10813 /* vectorizable_comparison. 10814 10815 Check if STMT_INFO is comparison expression that can be vectorized. 10816 If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized 10817 comparison, put it in VEC_STMT, and insert it at GSI. 10818 10819 Return true if STMT_INFO is vectorizable in this way. */ 10820 10821 static bool 10822 vectorizable_comparison (vec_info *vinfo, 10823 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 10824 gimple **vec_stmt, 10825 slp_tree slp_node, stmt_vector_for_cost *cost_vec) 10826 { 10827 tree lhs, rhs1, rhs2; 10828 tree vectype1 = NULL_TREE, vectype2 = NULL_TREE; 10829 tree vectype = STMT_VINFO_VECTYPE (stmt_info); 10830 tree vec_rhs1 = NULL_TREE, vec_rhs2 = NULL_TREE; 10831 tree new_temp; 10832 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); 10833 enum vect_def_type dts[2] = {vect_unknown_def_type, vect_unknown_def_type}; 10834 int ndts = 2; 10835 poly_uint64 nunits; 10836 int ncopies; 10837 enum tree_code code, bitop1 = NOP_EXPR, bitop2 = NOP_EXPR; 10838 int i; 10839 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 10840 vec<tree> vec_oprnds0 = vNULL; 10841 vec<tree> vec_oprnds1 = vNULL; 10842 tree mask_type; 10843 tree mask; 10844 10845 if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) 10846 return false; 10847 10848 if (!vectype || !VECTOR_BOOLEAN_TYPE_P (vectype)) 10849 return false; 10850 10851 mask_type = vectype; 10852 nunits = TYPE_VECTOR_SUBPARTS (vectype); 10853 10854 if (slp_node) 10855 ncopies = 1; 10856 else 10857 ncopies = vect_get_num_copies (loop_vinfo, vectype); 10858 10859 gcc_assert (ncopies >= 1); 10860 if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def) 10861 return false; 10862 10863 gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt); 10864 if (!stmt) 10865 return false; 10866 10867 code = gimple_assign_rhs_code (stmt); 10868 10869 if (TREE_CODE_CLASS (code) != tcc_comparison) 10870 return false; 10871 10872 slp_tree slp_rhs1, slp_rhs2; 10873 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 10874 0, &rhs1, &slp_rhs1, &dts[0], &vectype1)) 10875 return false; 10876 10877 if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 10878 1, &rhs2, &slp_rhs2, &dts[1], &vectype2)) 10879 return false; 10880 10881 if (vectype1 && vectype2 10882 && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1), 10883 TYPE_VECTOR_SUBPARTS (vectype2))) 10884 return false; 10885 10886 vectype = vectype1 ? vectype1 : vectype2; 10887 10888 /* Invariant comparison. */ 10889 if (!vectype) 10890 { 10891 if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (rhs1))) 10892 vectype = mask_type; 10893 else 10894 vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (rhs1), 10895 slp_node); 10896 if (!vectype || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype), nunits)) 10897 return false; 10898 } 10899 else if (maybe_ne (nunits, TYPE_VECTOR_SUBPARTS (vectype))) 10900 return false; 10901 10902 /* Can't compare mask and non-mask types. */ 10903 if (vectype1 && vectype2 10904 && (VECTOR_BOOLEAN_TYPE_P (vectype1) ^ VECTOR_BOOLEAN_TYPE_P (vectype2))) 10905 return false; 10906 10907 /* Boolean values may have another representation in vectors 10908 and therefore we prefer bit operations over comparison for 10909 them (which also works for scalar masks). We store opcodes 10910 to use in bitop1 and bitop2. Statement is vectorized as 10911 BITOP2 (rhs1 BITOP1 rhs2) or 10912 rhs1 BITOP2 (BITOP1 rhs2) 10913 depending on bitop1 and bitop2 arity. */ 10914 bool swap_p = false; 10915 if (VECTOR_BOOLEAN_TYPE_P (vectype)) 10916 { 10917 if (code == GT_EXPR) 10918 { 10919 bitop1 = BIT_NOT_EXPR; 10920 bitop2 = BIT_AND_EXPR; 10921 } 10922 else if (code == GE_EXPR) 10923 { 10924 bitop1 = BIT_NOT_EXPR; 10925 bitop2 = BIT_IOR_EXPR; 10926 } 10927 else if (code == LT_EXPR) 10928 { 10929 bitop1 = BIT_NOT_EXPR; 10930 bitop2 = BIT_AND_EXPR; 10931 swap_p = true; 10932 } 10933 else if (code == LE_EXPR) 10934 { 10935 bitop1 = BIT_NOT_EXPR; 10936 bitop2 = BIT_IOR_EXPR; 10937 swap_p = true; 10938 } 10939 else 10940 { 10941 bitop1 = BIT_XOR_EXPR; 10942 if (code == EQ_EXPR) 10943 bitop2 = BIT_NOT_EXPR; 10944 } 10945 } 10946 10947 if (!vec_stmt) 10948 { 10949 if (bitop1 == NOP_EXPR) 10950 { 10951 if (!expand_vec_cmp_expr_p (vectype, mask_type, code)) 10952 return false; 10953 } 10954 else 10955 { 10956 machine_mode mode = TYPE_MODE (vectype); 10957 optab optab; 10958 10959 optab = optab_for_tree_code (bitop1, vectype, optab_default); 10960 if (!optab || optab_handler (optab, mode) == CODE_FOR_nothing) 10961 return false; 10962 10963 if (bitop2 != NOP_EXPR) 10964 { 10965 optab = optab_for_tree_code (bitop2, vectype, optab_default); 10966 if (!optab || optab_handler (optab, mode) == CODE_FOR_nothing) 10967 return false; 10968 } 10969 } 10970 10971 /* Put types on constant and invariant SLP children. */ 10972 if (slp_node 10973 && (!vect_maybe_update_slp_op_vectype (slp_rhs1, vectype) 10974 || !vect_maybe_update_slp_op_vectype (slp_rhs2, vectype))) 10975 { 10976 if (dump_enabled_p ()) 10977 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 10978 "incompatible vector types for invariants\n"); 10979 return false; 10980 } 10981 10982 STMT_VINFO_TYPE (stmt_info) = comparison_vec_info_type; 10983 vect_model_simple_cost (vinfo, stmt_info, 10984 ncopies * (1 + (bitop2 != NOP_EXPR)), 10985 dts, ndts, slp_node, cost_vec); 10986 return true; 10987 } 10988 10989 /* Transform. */ 10990 10991 /* Handle def. */ 10992 lhs = gimple_assign_lhs (stmt); 10993 mask = vect_create_destination_var (lhs, mask_type); 10994 10995 vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, 10996 rhs1, &vec_oprnds0, vectype, 10997 rhs2, &vec_oprnds1, vectype); 10998 if (swap_p) 10999 std::swap (vec_oprnds0, vec_oprnds1); 11000 11001 /* Arguments are ready. Create the new vector stmt. */ 11002 FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_rhs1) 11003 { 11004 gimple *new_stmt; 11005 vec_rhs2 = vec_oprnds1[i]; 11006 11007 new_temp = make_ssa_name (mask); 11008 if (bitop1 == NOP_EXPR) 11009 { 11010 new_stmt = gimple_build_assign (new_temp, code, 11011 vec_rhs1, vec_rhs2); 11012 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 11013 } 11014 else 11015 { 11016 if (bitop1 == BIT_NOT_EXPR) 11017 new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs2); 11018 else 11019 new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs1, 11020 vec_rhs2); 11021 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 11022 if (bitop2 != NOP_EXPR) 11023 { 11024 tree res = make_ssa_name (mask); 11025 if (bitop2 == BIT_NOT_EXPR) 11026 new_stmt = gimple_build_assign (res, bitop2, new_temp); 11027 else 11028 new_stmt = gimple_build_assign (res, bitop2, vec_rhs1, 11029 new_temp); 11030 vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi); 11031 } 11032 } 11033 if (slp_node) 11034 SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt); 11035 else 11036 STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt); 11037 } 11038 11039 if (!slp_node) 11040 *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; 11041 11042 vec_oprnds0.release (); 11043 vec_oprnds1.release (); 11044 11045 return true; 11046 } 11047 11048 /* If SLP_NODE is nonnull, return true if vectorizable_live_operation 11049 can handle all live statements in the node. Otherwise return true 11050 if STMT_INFO is not live or if vectorizable_live_operation can handle it. 11051 GSI and VEC_STMT_P are as for vectorizable_live_operation. */ 11052 11053 static bool 11054 can_vectorize_live_stmts (vec_info *vinfo, 11055 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 11056 slp_tree slp_node, slp_instance slp_node_instance, 11057 bool vec_stmt_p, 11058 stmt_vector_for_cost *cost_vec) 11059 { 11060 if (slp_node) 11061 { 11062 stmt_vec_info slp_stmt_info; 11063 unsigned int i; 11064 FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (slp_node), i, slp_stmt_info) 11065 { 11066 if (STMT_VINFO_LIVE_P (slp_stmt_info) 11067 && !vectorizable_live_operation (vinfo, 11068 slp_stmt_info, gsi, slp_node, 11069 slp_node_instance, i, 11070 vec_stmt_p, cost_vec)) 11071 return false; 11072 } 11073 } 11074 else if (STMT_VINFO_LIVE_P (stmt_info) 11075 && !vectorizable_live_operation (vinfo, stmt_info, gsi, 11076 slp_node, slp_node_instance, -1, 11077 vec_stmt_p, cost_vec)) 11078 return false; 11079 11080 return true; 11081 } 11082 11083 /* Make sure the statement is vectorizable. */ 11084 11085 opt_result 11086 vect_analyze_stmt (vec_info *vinfo, 11087 stmt_vec_info stmt_info, bool *need_to_vectorize, 11088 slp_tree node, slp_instance node_instance, 11089 stmt_vector_for_cost *cost_vec) 11090 { 11091 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); 11092 enum vect_relevant relevance = STMT_VINFO_RELEVANT (stmt_info); 11093 bool ok; 11094 gimple_seq pattern_def_seq; 11095 11096 if (dump_enabled_p ()) 11097 dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: %G", 11098 stmt_info->stmt); 11099 11100 if (gimple_has_volatile_ops (stmt_info->stmt)) 11101 return opt_result::failure_at (stmt_info->stmt, 11102 "not vectorized:" 11103 " stmt has volatile operands: %G\n", 11104 stmt_info->stmt); 11105 11106 if (STMT_VINFO_IN_PATTERN_P (stmt_info) 11107 && node == NULL 11108 && (pattern_def_seq = STMT_VINFO_PATTERN_DEF_SEQ (stmt_info))) 11109 { 11110 gimple_stmt_iterator si; 11111 11112 for (si = gsi_start (pattern_def_seq); !gsi_end_p (si); gsi_next (&si)) 11113 { 11114 stmt_vec_info pattern_def_stmt_info 11115 = vinfo->lookup_stmt (gsi_stmt (si)); 11116 if (STMT_VINFO_RELEVANT_P (pattern_def_stmt_info) 11117 || STMT_VINFO_LIVE_P (pattern_def_stmt_info)) 11118 { 11119 /* Analyze def stmt of STMT if it's a pattern stmt. */ 11120 if (dump_enabled_p ()) 11121 dump_printf_loc (MSG_NOTE, vect_location, 11122 "==> examining pattern def statement: %G", 11123 pattern_def_stmt_info->stmt); 11124 11125 opt_result res 11126 = vect_analyze_stmt (vinfo, pattern_def_stmt_info, 11127 need_to_vectorize, node, node_instance, 11128 cost_vec); 11129 if (!res) 11130 return res; 11131 } 11132 } 11133 } 11134 11135 /* Skip stmts that do not need to be vectorized. In loops this is expected 11136 to include: 11137 - the COND_EXPR which is the loop exit condition 11138 - any LABEL_EXPRs in the loop 11139 - computations that are used only for array indexing or loop control. 11140 In basic blocks we only analyze statements that are a part of some SLP 11141 instance, therefore, all the statements are relevant. 11142 11143 Pattern statement needs to be analyzed instead of the original statement 11144 if the original statement is not relevant. Otherwise, we analyze both 11145 statements. In basic blocks we are called from some SLP instance 11146 traversal, don't analyze pattern stmts instead, the pattern stmts 11147 already will be part of SLP instance. */ 11148 11149 stmt_vec_info pattern_stmt_info = STMT_VINFO_RELATED_STMT (stmt_info); 11150 if (!STMT_VINFO_RELEVANT_P (stmt_info) 11151 && !STMT_VINFO_LIVE_P (stmt_info)) 11152 { 11153 if (STMT_VINFO_IN_PATTERN_P (stmt_info) 11154 && pattern_stmt_info 11155 && (STMT_VINFO_RELEVANT_P (pattern_stmt_info) 11156 || STMT_VINFO_LIVE_P (pattern_stmt_info))) 11157 { 11158 /* Analyze PATTERN_STMT instead of the original stmt. */ 11159 stmt_info = pattern_stmt_info; 11160 if (dump_enabled_p ()) 11161 dump_printf_loc (MSG_NOTE, vect_location, 11162 "==> examining pattern statement: %G", 11163 stmt_info->stmt); 11164 } 11165 else 11166 { 11167 if (dump_enabled_p ()) 11168 dump_printf_loc (MSG_NOTE, vect_location, "irrelevant.\n"); 11169 11170 return opt_result::success (); 11171 } 11172 } 11173 else if (STMT_VINFO_IN_PATTERN_P (stmt_info) 11174 && node == NULL 11175 && pattern_stmt_info 11176 && (STMT_VINFO_RELEVANT_P (pattern_stmt_info) 11177 || STMT_VINFO_LIVE_P (pattern_stmt_info))) 11178 { 11179 /* Analyze PATTERN_STMT too. */ 11180 if (dump_enabled_p ()) 11181 dump_printf_loc (MSG_NOTE, vect_location, 11182 "==> examining pattern statement: %G", 11183 pattern_stmt_info->stmt); 11184 11185 opt_result res 11186 = vect_analyze_stmt (vinfo, pattern_stmt_info, need_to_vectorize, node, 11187 node_instance, cost_vec); 11188 if (!res) 11189 return res; 11190 } 11191 11192 switch (STMT_VINFO_DEF_TYPE (stmt_info)) 11193 { 11194 case vect_internal_def: 11195 break; 11196 11197 case vect_reduction_def: 11198 case vect_nested_cycle: 11199 gcc_assert (!bb_vinfo 11200 && (relevance == vect_used_in_outer 11201 || relevance == vect_used_in_outer_by_reduction 11202 || relevance == vect_used_by_reduction 11203 || relevance == vect_unused_in_scope 11204 || relevance == vect_used_only_live)); 11205 break; 11206 11207 case vect_induction_def: 11208 gcc_assert (!bb_vinfo); 11209 break; 11210 11211 case vect_constant_def: 11212 case vect_external_def: 11213 case vect_unknown_def_type: 11214 default: 11215 gcc_unreachable (); 11216 } 11217 11218 tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info); 11219 if (node) 11220 STMT_VINFO_VECTYPE (stmt_info) = SLP_TREE_VECTYPE (node); 11221 11222 if (STMT_VINFO_RELEVANT_P (stmt_info)) 11223 { 11224 gcall *call = dyn_cast <gcall *> (stmt_info->stmt); 11225 gcc_assert (STMT_VINFO_VECTYPE (stmt_info) 11226 || (call && gimple_call_lhs (call) == NULL_TREE)); 11227 *need_to_vectorize = true; 11228 } 11229 11230 if (PURE_SLP_STMT (stmt_info) && !node) 11231 { 11232 if (dump_enabled_p ()) 11233 dump_printf_loc (MSG_NOTE, vect_location, 11234 "handled only by SLP analysis\n"); 11235 return opt_result::success (); 11236 } 11237 11238 ok = true; 11239 if (!bb_vinfo 11240 && (STMT_VINFO_RELEVANT_P (stmt_info) 11241 || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def)) 11242 /* Prefer vectorizable_call over vectorizable_simd_clone_call so 11243 -mveclibabi= takes preference over library functions with 11244 the simd attribute. */ 11245 ok = (vectorizable_call (vinfo, stmt_info, NULL, NULL, node, cost_vec) 11246 || vectorizable_simd_clone_call (vinfo, stmt_info, NULL, NULL, node, 11247 cost_vec) 11248 || vectorizable_conversion (vinfo, stmt_info, 11249 NULL, NULL, node, cost_vec) 11250 || vectorizable_operation (vinfo, stmt_info, 11251 NULL, NULL, node, cost_vec) 11252 || vectorizable_assignment (vinfo, stmt_info, 11253 NULL, NULL, node, cost_vec) 11254 || vectorizable_load (vinfo, stmt_info, NULL, NULL, node, cost_vec) 11255 || vectorizable_store (vinfo, stmt_info, NULL, NULL, node, cost_vec) 11256 || vectorizable_reduction (as_a <loop_vec_info> (vinfo), stmt_info, 11257 node, node_instance, cost_vec) 11258 || vectorizable_induction (as_a <loop_vec_info> (vinfo), stmt_info, 11259 NULL, node, cost_vec) 11260 || vectorizable_shift (vinfo, stmt_info, NULL, NULL, node, cost_vec) 11261 || vectorizable_condition (vinfo, stmt_info, 11262 NULL, NULL, node, cost_vec) 11263 || vectorizable_comparison (vinfo, stmt_info, NULL, NULL, node, 11264 cost_vec) 11265 || vectorizable_lc_phi (as_a <loop_vec_info> (vinfo), 11266 stmt_info, NULL, node)); 11267 else 11268 { 11269 if (bb_vinfo) 11270 ok = (vectorizable_call (vinfo, stmt_info, NULL, NULL, node, cost_vec) 11271 || vectorizable_simd_clone_call (vinfo, stmt_info, 11272 NULL, NULL, node, cost_vec) 11273 || vectorizable_conversion (vinfo, stmt_info, NULL, NULL, node, 11274 cost_vec) 11275 || vectorizable_shift (vinfo, stmt_info, 11276 NULL, NULL, node, cost_vec) 11277 || vectorizable_operation (vinfo, stmt_info, 11278 NULL, NULL, node, cost_vec) 11279 || vectorizable_assignment (vinfo, stmt_info, NULL, NULL, node, 11280 cost_vec) 11281 || vectorizable_load (vinfo, stmt_info, 11282 NULL, NULL, node, cost_vec) 11283 || vectorizable_store (vinfo, stmt_info, 11284 NULL, NULL, node, cost_vec) 11285 || vectorizable_condition (vinfo, stmt_info, 11286 NULL, NULL, node, cost_vec) 11287 || vectorizable_comparison (vinfo, stmt_info, NULL, NULL, node, 11288 cost_vec) 11289 || vectorizable_phi (vinfo, stmt_info, NULL, node, cost_vec)); 11290 } 11291 11292 if (node) 11293 STMT_VINFO_VECTYPE (stmt_info) = saved_vectype; 11294 11295 if (!ok) 11296 return opt_result::failure_at (stmt_info->stmt, 11297 "not vectorized:" 11298 " relevant stmt not supported: %G", 11299 stmt_info->stmt); 11300 11301 /* Stmts that are (also) "live" (i.e. - that are used out of the loop) 11302 need extra handling, except for vectorizable reductions. */ 11303 if (!bb_vinfo 11304 && STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type 11305 && STMT_VINFO_TYPE (stmt_info) != lc_phi_info_type 11306 && !can_vectorize_live_stmts (as_a <loop_vec_info> (vinfo), 11307 stmt_info, NULL, node, node_instance, 11308 false, cost_vec)) 11309 return opt_result::failure_at (stmt_info->stmt, 11310 "not vectorized:" 11311 " live stmt not supported: %G", 11312 stmt_info->stmt); 11313 11314 return opt_result::success (); 11315 } 11316 11317 11318 /* Function vect_transform_stmt. 11319 11320 Create a vectorized stmt to replace STMT_INFO, and insert it at GSI. */ 11321 11322 bool 11323 vect_transform_stmt (vec_info *vinfo, 11324 stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, 11325 slp_tree slp_node, slp_instance slp_node_instance) 11326 { 11327 bool is_store = false; 11328 gimple *vec_stmt = NULL; 11329 bool done; 11330 11331 gcc_assert (slp_node || !PURE_SLP_STMT (stmt_info)); 11332 11333 tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info); 11334 if (slp_node) 11335 STMT_VINFO_VECTYPE (stmt_info) = SLP_TREE_VECTYPE (slp_node); 11336 11337 switch (STMT_VINFO_TYPE (stmt_info)) 11338 { 11339 case type_demotion_vec_info_type: 11340 case type_promotion_vec_info_type: 11341 case type_conversion_vec_info_type: 11342 done = vectorizable_conversion (vinfo, stmt_info, 11343 gsi, &vec_stmt, slp_node, NULL); 11344 gcc_assert (done); 11345 break; 11346 11347 case induc_vec_info_type: 11348 done = vectorizable_induction (as_a <loop_vec_info> (vinfo), 11349 stmt_info, &vec_stmt, slp_node, 11350 NULL); 11351 gcc_assert (done); 11352 break; 11353 11354 case shift_vec_info_type: 11355 done = vectorizable_shift (vinfo, stmt_info, 11356 gsi, &vec_stmt, slp_node, NULL); 11357 gcc_assert (done); 11358 break; 11359 11360 case op_vec_info_type: 11361 done = vectorizable_operation (vinfo, stmt_info, gsi, &vec_stmt, slp_node, 11362 NULL); 11363 gcc_assert (done); 11364 break; 11365 11366 case assignment_vec_info_type: 11367 done = vectorizable_assignment (vinfo, stmt_info, 11368 gsi, &vec_stmt, slp_node, NULL); 11369 gcc_assert (done); 11370 break; 11371 11372 case load_vec_info_type: 11373 done = vectorizable_load (vinfo, stmt_info, gsi, &vec_stmt, slp_node, 11374 NULL); 11375 gcc_assert (done); 11376 break; 11377 11378 case store_vec_info_type: 11379 done = vectorizable_store (vinfo, stmt_info, 11380 gsi, &vec_stmt, slp_node, NULL); 11381 gcc_assert (done); 11382 if (STMT_VINFO_GROUPED_ACCESS (stmt_info) && !slp_node) 11383 { 11384 /* In case of interleaving, the whole chain is vectorized when the 11385 last store in the chain is reached. Store stmts before the last 11386 one are skipped, and there vec_stmt_info shouldn't be freed 11387 meanwhile. */ 11388 stmt_vec_info group_info = DR_GROUP_FIRST_ELEMENT (stmt_info); 11389 if (DR_GROUP_STORE_COUNT (group_info) == DR_GROUP_SIZE (group_info)) 11390 is_store = true; 11391 } 11392 else 11393 is_store = true; 11394 break; 11395 11396 case condition_vec_info_type: 11397 done = vectorizable_condition (vinfo, stmt_info, 11398 gsi, &vec_stmt, slp_node, NULL); 11399 gcc_assert (done); 11400 break; 11401 11402 case comparison_vec_info_type: 11403 done = vectorizable_comparison (vinfo, stmt_info, gsi, &vec_stmt, 11404 slp_node, NULL); 11405 gcc_assert (done); 11406 break; 11407 11408 case call_vec_info_type: 11409 done = vectorizable_call (vinfo, stmt_info, 11410 gsi, &vec_stmt, slp_node, NULL); 11411 break; 11412 11413 case call_simd_clone_vec_info_type: 11414 done = vectorizable_simd_clone_call (vinfo, stmt_info, gsi, &vec_stmt, 11415 slp_node, NULL); 11416 break; 11417 11418 case reduc_vec_info_type: 11419 done = vect_transform_reduction (as_a <loop_vec_info> (vinfo), stmt_info, 11420 gsi, &vec_stmt, slp_node); 11421 gcc_assert (done); 11422 break; 11423 11424 case cycle_phi_info_type: 11425 done = vect_transform_cycle_phi (as_a <loop_vec_info> (vinfo), stmt_info, 11426 &vec_stmt, slp_node, slp_node_instance); 11427 gcc_assert (done); 11428 break; 11429 11430 case lc_phi_info_type: 11431 done = vectorizable_lc_phi (as_a <loop_vec_info> (vinfo), 11432 stmt_info, &vec_stmt, slp_node); 11433 gcc_assert (done); 11434 break; 11435 11436 case phi_info_type: 11437 done = vectorizable_phi (vinfo, stmt_info, &vec_stmt, slp_node, NULL); 11438 gcc_assert (done); 11439 break; 11440 11441 default: 11442 if (!STMT_VINFO_LIVE_P (stmt_info)) 11443 { 11444 if (dump_enabled_p ()) 11445 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 11446 "stmt not supported.\n"); 11447 gcc_unreachable (); 11448 } 11449 done = true; 11450 } 11451 11452 if (!slp_node && vec_stmt) 11453 gcc_assert (STMT_VINFO_VEC_STMTS (stmt_info).exists ()); 11454 11455 if (STMT_VINFO_TYPE (stmt_info) != store_vec_info_type) 11456 { 11457 /* Handle stmts whose DEF is used outside the loop-nest that is 11458 being vectorized. */ 11459 done = can_vectorize_live_stmts (vinfo, stmt_info, gsi, slp_node, 11460 slp_node_instance, true, NULL); 11461 gcc_assert (done); 11462 } 11463 11464 if (slp_node) 11465 STMT_VINFO_VECTYPE (stmt_info) = saved_vectype; 11466 11467 return is_store; 11468 } 11469 11470 11471 /* Remove a group of stores (for SLP or interleaving), free their 11472 stmt_vec_info. */ 11473 11474 void 11475 vect_remove_stores (vec_info *vinfo, stmt_vec_info first_stmt_info) 11476 { 11477 stmt_vec_info next_stmt_info = first_stmt_info; 11478 11479 while (next_stmt_info) 11480 { 11481 stmt_vec_info tmp = DR_GROUP_NEXT_ELEMENT (next_stmt_info); 11482 next_stmt_info = vect_orig_stmt (next_stmt_info); 11483 /* Free the attached stmt_vec_info and remove the stmt. */ 11484 vinfo->remove_stmt (next_stmt_info); 11485 next_stmt_info = tmp; 11486 } 11487 } 11488 11489 /* If NUNITS is nonzero, return a vector type that contains NUNITS 11490 elements of type SCALAR_TYPE, or null if the target doesn't support 11491 such a type. 11492 11493 If NUNITS is zero, return a vector type that contains elements of 11494 type SCALAR_TYPE, choosing whichever vector size the target prefers. 11495 11496 If PREVAILING_MODE is VOIDmode, we have not yet chosen a vector mode 11497 for this vectorization region and want to "autodetect" the best choice. 11498 Otherwise, PREVAILING_MODE is a previously-chosen vector TYPE_MODE 11499 and we want the new type to be interoperable with it. PREVAILING_MODE 11500 in this case can be a scalar integer mode or a vector mode; when it 11501 is a vector mode, the function acts like a tree-level version of 11502 related_vector_mode. */ 11503 11504 tree 11505 get_related_vectype_for_scalar_type (machine_mode prevailing_mode, 11506 tree scalar_type, poly_uint64 nunits) 11507 { 11508 tree orig_scalar_type = scalar_type; 11509 scalar_mode inner_mode; 11510 machine_mode simd_mode; 11511 tree vectype; 11512 11513 if (!is_int_mode (TYPE_MODE (scalar_type), &inner_mode) 11514 && !is_float_mode (TYPE_MODE (scalar_type), &inner_mode)) 11515 return NULL_TREE; 11516 11517 unsigned int nbytes = GET_MODE_SIZE (inner_mode); 11518 11519 /* For vector types of elements whose mode precision doesn't 11520 match their types precision we use a element type of mode 11521 precision. The vectorization routines will have to make sure 11522 they support the proper result truncation/extension. 11523 We also make sure to build vector types with INTEGER_TYPE 11524 component type only. */ 11525 if (INTEGRAL_TYPE_P (scalar_type) 11526 && (GET_MODE_BITSIZE (inner_mode) != TYPE_PRECISION (scalar_type) 11527 || TREE_CODE (scalar_type) != INTEGER_TYPE)) 11528 scalar_type = build_nonstandard_integer_type (GET_MODE_BITSIZE (inner_mode), 11529 TYPE_UNSIGNED (scalar_type)); 11530 11531 /* We shouldn't end up building VECTOR_TYPEs of non-scalar components. 11532 When the component mode passes the above test simply use a type 11533 corresponding to that mode. The theory is that any use that 11534 would cause problems with this will disable vectorization anyway. */ 11535 else if (!SCALAR_FLOAT_TYPE_P (scalar_type) 11536 && !INTEGRAL_TYPE_P (scalar_type)) 11537 scalar_type = lang_hooks.types.type_for_mode (inner_mode, 1); 11538 11539 /* We can't build a vector type of elements with alignment bigger than 11540 their size. */ 11541 else if (nbytes < TYPE_ALIGN_UNIT (scalar_type)) 11542 scalar_type = lang_hooks.types.type_for_mode (inner_mode, 11543 TYPE_UNSIGNED (scalar_type)); 11544 11545 /* If we felt back to using the mode fail if there was 11546 no scalar type for it. */ 11547 if (scalar_type == NULL_TREE) 11548 return NULL_TREE; 11549 11550 /* If no prevailing mode was supplied, use the mode the target prefers. 11551 Otherwise lookup a vector mode based on the prevailing mode. */ 11552 if (prevailing_mode == VOIDmode) 11553 { 11554 gcc_assert (known_eq (nunits, 0U)); 11555 simd_mode = targetm.vectorize.preferred_simd_mode (inner_mode); 11556 if (SCALAR_INT_MODE_P (simd_mode)) 11557 { 11558 /* Traditional behavior is not to take the integer mode 11559 literally, but simply to use it as a way of determining 11560 the vector size. It is up to mode_for_vector to decide 11561 what the TYPE_MODE should be. 11562 11563 Note that nunits == 1 is allowed in order to support single 11564 element vector types. */ 11565 if (!multiple_p (GET_MODE_SIZE (simd_mode), nbytes, &nunits) 11566 || !mode_for_vector (inner_mode, nunits).exists (&simd_mode)) 11567 return NULL_TREE; 11568 } 11569 } 11570 else if (SCALAR_INT_MODE_P (prevailing_mode) 11571 || !related_vector_mode (prevailing_mode, 11572 inner_mode, nunits).exists (&simd_mode)) 11573 { 11574 /* Fall back to using mode_for_vector, mostly in the hope of being 11575 able to use an integer mode. */ 11576 if (known_eq (nunits, 0U) 11577 && !multiple_p (GET_MODE_SIZE (prevailing_mode), nbytes, &nunits)) 11578 return NULL_TREE; 11579 11580 if (!mode_for_vector (inner_mode, nunits).exists (&simd_mode)) 11581 return NULL_TREE; 11582 } 11583 11584 vectype = build_vector_type_for_mode (scalar_type, simd_mode); 11585 11586 /* In cases where the mode was chosen by mode_for_vector, check that 11587 the target actually supports the chosen mode, or that it at least 11588 allows the vector mode to be replaced by a like-sized integer. */ 11589 if (!VECTOR_MODE_P (TYPE_MODE (vectype)) 11590 && !INTEGRAL_MODE_P (TYPE_MODE (vectype))) 11591 return NULL_TREE; 11592 11593 /* Re-attach the address-space qualifier if we canonicalized the scalar 11594 type. */ 11595 if (TYPE_ADDR_SPACE (orig_scalar_type) != TYPE_ADDR_SPACE (vectype)) 11596 return build_qualified_type 11597 (vectype, KEEP_QUAL_ADDR_SPACE (TYPE_QUALS (orig_scalar_type))); 11598 11599 return vectype; 11600 } 11601 11602 /* Function get_vectype_for_scalar_type. 11603 11604 Returns the vector type corresponding to SCALAR_TYPE as supported 11605 by the target. If GROUP_SIZE is nonzero and we're performing BB 11606 vectorization, make sure that the number of elements in the vector 11607 is no bigger than GROUP_SIZE. */ 11608 11609 tree 11610 get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type, 11611 unsigned int group_size) 11612 { 11613 /* For BB vectorization, we should always have a group size once we've 11614 constructed the SLP tree; the only valid uses of zero GROUP_SIZEs 11615 are tentative requests during things like early data reference 11616 analysis and pattern recognition. */ 11617 if (is_a <bb_vec_info> (vinfo)) 11618 gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0); 11619 else 11620 group_size = 0; 11621 11622 tree vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode, 11623 scalar_type); 11624 if (vectype && vinfo->vector_mode == VOIDmode) 11625 vinfo->vector_mode = TYPE_MODE (vectype); 11626 11627 /* Register the natural choice of vector type, before the group size 11628 has been applied. */ 11629 if (vectype) 11630 vinfo->used_vector_modes.add (TYPE_MODE (vectype)); 11631 11632 /* If the natural choice of vector type doesn't satisfy GROUP_SIZE, 11633 try again with an explicit number of elements. */ 11634 if (vectype 11635 && group_size 11636 && maybe_ge (TYPE_VECTOR_SUBPARTS (vectype), group_size)) 11637 { 11638 /* Start with the biggest number of units that fits within 11639 GROUP_SIZE and halve it until we find a valid vector type. 11640 Usually either the first attempt will succeed or all will 11641 fail (in the latter case because GROUP_SIZE is too small 11642 for the target), but it's possible that a target could have 11643 a hole between supported vector types. 11644 11645 If GROUP_SIZE is not a power of 2, this has the effect of 11646 trying the largest power of 2 that fits within the group, 11647 even though the group is not a multiple of that vector size. 11648 The BB vectorizer will then try to carve up the group into 11649 smaller pieces. */ 11650 unsigned int nunits = 1 << floor_log2 (group_size); 11651 do 11652 { 11653 vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode, 11654 scalar_type, nunits); 11655 nunits /= 2; 11656 } 11657 while (nunits > 1 && !vectype); 11658 } 11659 11660 return vectype; 11661 } 11662 11663 /* Return the vector type corresponding to SCALAR_TYPE as supported 11664 by the target. NODE, if nonnull, is the SLP tree node that will 11665 use the returned vector type. */ 11666 11667 tree 11668 get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type, slp_tree node) 11669 { 11670 unsigned int group_size = 0; 11671 if (node) 11672 group_size = SLP_TREE_LANES (node); 11673 return get_vectype_for_scalar_type (vinfo, scalar_type, group_size); 11674 } 11675 11676 /* Function get_mask_type_for_scalar_type. 11677 11678 Returns the mask type corresponding to a result of comparison 11679 of vectors of specified SCALAR_TYPE as supported by target. 11680 If GROUP_SIZE is nonzero and we're performing BB vectorization, 11681 make sure that the number of elements in the vector is no bigger 11682 than GROUP_SIZE. */ 11683 11684 tree 11685 get_mask_type_for_scalar_type (vec_info *vinfo, tree scalar_type, 11686 unsigned int group_size) 11687 { 11688 tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size); 11689 11690 if (!vectype) 11691 return NULL; 11692 11693 return truth_type_for (vectype); 11694 } 11695 11696 /* Function get_same_sized_vectype 11697 11698 Returns a vector type corresponding to SCALAR_TYPE of size 11699 VECTOR_TYPE if supported by the target. */ 11700 11701 tree 11702 get_same_sized_vectype (tree scalar_type, tree vector_type) 11703 { 11704 if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type)) 11705 return truth_type_for (vector_type); 11706 11707 poly_uint64 nunits; 11708 if (!multiple_p (GET_MODE_SIZE (TYPE_MODE (vector_type)), 11709 GET_MODE_SIZE (TYPE_MODE (scalar_type)), &nunits)) 11710 return NULL_TREE; 11711 11712 return get_related_vectype_for_scalar_type (TYPE_MODE (vector_type), 11713 scalar_type, nunits); 11714 } 11715 11716 /* Return true if replacing LOOP_VINFO->vector_mode with VECTOR_MODE 11717 would not change the chosen vector modes. */ 11718 11719 bool 11720 vect_chooses_same_modes_p (vec_info *vinfo, machine_mode vector_mode) 11721 { 11722 for (vec_info::mode_set::iterator i = vinfo->used_vector_modes.begin (); 11723 i != vinfo->used_vector_modes.end (); ++i) 11724 if (!VECTOR_MODE_P (*i) 11725 || related_vector_mode (vector_mode, GET_MODE_INNER (*i), 0) != *i) 11726 return false; 11727 return true; 11728 } 11729 11730 /* Function vect_is_simple_use. 11731 11732 Input: 11733 VINFO - the vect info of the loop or basic block that is being vectorized. 11734 OPERAND - operand in the loop or bb. 11735 Output: 11736 DEF_STMT_INFO_OUT (optional) - information about the defining stmt in 11737 case OPERAND is an SSA_NAME that is defined in the vectorizable region 11738 DEF_STMT_OUT (optional) - the defining stmt in case OPERAND is an SSA_NAME; 11739 the definition could be anywhere in the function 11740 DT - the type of definition 11741 11742 Returns whether a stmt with OPERAND can be vectorized. 11743 For loops, supportable operands are constants, loop invariants, and operands 11744 that are defined by the current iteration of the loop. Unsupportable 11745 operands are those that are defined by a previous iteration of the loop (as 11746 is the case in reduction/induction computations). 11747 For basic blocks, supportable operands are constants and bb invariants. 11748 For now, operands defined outside the basic block are not supported. */ 11749 11750 bool 11751 vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt, 11752 stmt_vec_info *def_stmt_info_out, gimple **def_stmt_out) 11753 { 11754 if (def_stmt_info_out) 11755 *def_stmt_info_out = NULL; 11756 if (def_stmt_out) 11757 *def_stmt_out = NULL; 11758 *dt = vect_unknown_def_type; 11759 11760 if (dump_enabled_p ()) 11761 { 11762 dump_printf_loc (MSG_NOTE, vect_location, 11763 "vect_is_simple_use: operand "); 11764 if (TREE_CODE (operand) == SSA_NAME 11765 && !SSA_NAME_IS_DEFAULT_DEF (operand)) 11766 dump_gimple_expr (MSG_NOTE, TDF_SLIM, SSA_NAME_DEF_STMT (operand), 0); 11767 else 11768 dump_generic_expr (MSG_NOTE, TDF_SLIM, operand); 11769 } 11770 11771 if (CONSTANT_CLASS_P (operand)) 11772 *dt = vect_constant_def; 11773 else if (is_gimple_min_invariant (operand)) 11774 *dt = vect_external_def; 11775 else if (TREE_CODE (operand) != SSA_NAME) 11776 *dt = vect_unknown_def_type; 11777 else if (SSA_NAME_IS_DEFAULT_DEF (operand)) 11778 *dt = vect_external_def; 11779 else 11780 { 11781 gimple *def_stmt = SSA_NAME_DEF_STMT (operand); 11782 stmt_vec_info stmt_vinfo = vinfo->lookup_def (operand); 11783 if (!stmt_vinfo) 11784 *dt = vect_external_def; 11785 else 11786 { 11787 stmt_vinfo = vect_stmt_to_vectorize (stmt_vinfo); 11788 def_stmt = stmt_vinfo->stmt; 11789 *dt = STMT_VINFO_DEF_TYPE (stmt_vinfo); 11790 if (def_stmt_info_out) 11791 *def_stmt_info_out = stmt_vinfo; 11792 } 11793 if (def_stmt_out) 11794 *def_stmt_out = def_stmt; 11795 } 11796 11797 if (dump_enabled_p ()) 11798 { 11799 dump_printf (MSG_NOTE, ", type of def: "); 11800 switch (*dt) 11801 { 11802 case vect_uninitialized_def: 11803 dump_printf (MSG_NOTE, "uninitialized\n"); 11804 break; 11805 case vect_constant_def: 11806 dump_printf (MSG_NOTE, "constant\n"); 11807 break; 11808 case vect_external_def: 11809 dump_printf (MSG_NOTE, "external\n"); 11810 break; 11811 case vect_internal_def: 11812 dump_printf (MSG_NOTE, "internal\n"); 11813 break; 11814 case vect_induction_def: 11815 dump_printf (MSG_NOTE, "induction\n"); 11816 break; 11817 case vect_reduction_def: 11818 dump_printf (MSG_NOTE, "reduction\n"); 11819 break; 11820 case vect_double_reduction_def: 11821 dump_printf (MSG_NOTE, "double reduction\n"); 11822 break; 11823 case vect_nested_cycle: 11824 dump_printf (MSG_NOTE, "nested cycle\n"); 11825 break; 11826 case vect_unknown_def_type: 11827 dump_printf (MSG_NOTE, "unknown\n"); 11828 break; 11829 } 11830 } 11831 11832 if (*dt == vect_unknown_def_type) 11833 { 11834 if (dump_enabled_p ()) 11835 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 11836 "Unsupported pattern.\n"); 11837 return false; 11838 } 11839 11840 return true; 11841 } 11842 11843 /* Function vect_is_simple_use. 11844 11845 Same as vect_is_simple_use but also determines the vector operand 11846 type of OPERAND and stores it to *VECTYPE. If the definition of 11847 OPERAND is vect_uninitialized_def, vect_constant_def or 11848 vect_external_def *VECTYPE will be set to NULL_TREE and the caller 11849 is responsible to compute the best suited vector type for the 11850 scalar operand. */ 11851 11852 bool 11853 vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt, 11854 tree *vectype, stmt_vec_info *def_stmt_info_out, 11855 gimple **def_stmt_out) 11856 { 11857 stmt_vec_info def_stmt_info; 11858 gimple *def_stmt; 11859 if (!vect_is_simple_use (operand, vinfo, dt, &def_stmt_info, &def_stmt)) 11860 return false; 11861 11862 if (def_stmt_out) 11863 *def_stmt_out = def_stmt; 11864 if (def_stmt_info_out) 11865 *def_stmt_info_out = def_stmt_info; 11866 11867 /* Now get a vector type if the def is internal, otherwise supply 11868 NULL_TREE and leave it up to the caller to figure out a proper 11869 type for the use stmt. */ 11870 if (*dt == vect_internal_def 11871 || *dt == vect_induction_def 11872 || *dt == vect_reduction_def 11873 || *dt == vect_double_reduction_def 11874 || *dt == vect_nested_cycle) 11875 { 11876 *vectype = STMT_VINFO_VECTYPE (def_stmt_info); 11877 gcc_assert (*vectype != NULL_TREE); 11878 if (dump_enabled_p ()) 11879 dump_printf_loc (MSG_NOTE, vect_location, 11880 "vect_is_simple_use: vectype %T\n", *vectype); 11881 } 11882 else if (*dt == vect_uninitialized_def 11883 || *dt == vect_constant_def 11884 || *dt == vect_external_def) 11885 *vectype = NULL_TREE; 11886 else 11887 gcc_unreachable (); 11888 11889 return true; 11890 } 11891 11892 /* Function vect_is_simple_use. 11893 11894 Same as vect_is_simple_use but determines the operand by operand 11895 position OPERAND from either STMT or SLP_NODE, filling in *OP 11896 and *SLP_DEF (when SLP_NODE is not NULL). */ 11897 11898 bool 11899 vect_is_simple_use (vec_info *vinfo, stmt_vec_info stmt, slp_tree slp_node, 11900 unsigned operand, tree *op, slp_tree *slp_def, 11901 enum vect_def_type *dt, 11902 tree *vectype, stmt_vec_info *def_stmt_info_out) 11903 { 11904 if (slp_node) 11905 { 11906 slp_tree child = SLP_TREE_CHILDREN (slp_node)[operand]; 11907 *slp_def = child; 11908 *vectype = SLP_TREE_VECTYPE (child); 11909 if (SLP_TREE_DEF_TYPE (child) == vect_internal_def) 11910 { 11911 *op = gimple_get_lhs (SLP_TREE_REPRESENTATIVE (child)->stmt); 11912 return vect_is_simple_use (*op, vinfo, dt, def_stmt_info_out); 11913 } 11914 else 11915 { 11916 if (def_stmt_info_out) 11917 *def_stmt_info_out = NULL; 11918 *op = SLP_TREE_SCALAR_OPS (child)[0]; 11919 *dt = SLP_TREE_DEF_TYPE (child); 11920 return true; 11921 } 11922 } 11923 else 11924 { 11925 *slp_def = NULL; 11926 if (gassign *ass = dyn_cast <gassign *> (stmt->stmt)) 11927 { 11928 if (gimple_assign_rhs_code (ass) == COND_EXPR 11929 && COMPARISON_CLASS_P (gimple_assign_rhs1 (ass))) 11930 { 11931 if (operand < 2) 11932 *op = TREE_OPERAND (gimple_assign_rhs1 (ass), operand); 11933 else 11934 *op = gimple_op (ass, operand); 11935 } 11936 else if (gimple_assign_rhs_code (ass) == VIEW_CONVERT_EXPR) 11937 *op = TREE_OPERAND (gimple_assign_rhs1 (ass), 0); 11938 else 11939 *op = gimple_op (ass, operand + 1); 11940 } 11941 else if (gcall *call = dyn_cast <gcall *> (stmt->stmt)) 11942 *op = gimple_call_arg (call, operand); 11943 else 11944 gcc_unreachable (); 11945 return vect_is_simple_use (*op, vinfo, dt, vectype, def_stmt_info_out); 11946 } 11947 } 11948 11949 /* If OP is not NULL and is external or constant update its vector 11950 type with VECTYPE. Returns true if successful or false if not, 11951 for example when conflicting vector types are present. */ 11952 11953 bool 11954 vect_maybe_update_slp_op_vectype (slp_tree op, tree vectype) 11955 { 11956 if (!op || SLP_TREE_DEF_TYPE (op) == vect_internal_def) 11957 return true; 11958 if (SLP_TREE_VECTYPE (op)) 11959 return types_compatible_p (SLP_TREE_VECTYPE (op), vectype); 11960 SLP_TREE_VECTYPE (op) = vectype; 11961 return true; 11962 } 11963 11964 /* Function supportable_widening_operation 11965 11966 Check whether an operation represented by the code CODE is a 11967 widening operation that is supported by the target platform in 11968 vector form (i.e., when operating on arguments of type VECTYPE_IN 11969 producing a result of type VECTYPE_OUT). 11970 11971 Widening operations we currently support are NOP (CONVERT), FLOAT, 11972 FIX_TRUNC and WIDEN_MULT. This function checks if these operations 11973 are supported by the target platform either directly (via vector 11974 tree-codes), or via target builtins. 11975 11976 Output: 11977 - CODE1 and CODE2 are codes of vector operations to be used when 11978 vectorizing the operation, if available. 11979 - MULTI_STEP_CVT determines the number of required intermediate steps in 11980 case of multi-step conversion (like char->short->int - in that case 11981 MULTI_STEP_CVT will be 1). 11982 - INTERM_TYPES contains the intermediate type required to perform the 11983 widening operation (short in the above example). */ 11984 11985 bool 11986 supportable_widening_operation (vec_info *vinfo, 11987 enum tree_code code, stmt_vec_info stmt_info, 11988 tree vectype_out, tree vectype_in, 11989 enum tree_code *code1, enum tree_code *code2, 11990 int *multi_step_cvt, 11991 vec<tree> *interm_types) 11992 { 11993 loop_vec_info loop_info = dyn_cast <loop_vec_info> (vinfo); 11994 class loop *vect_loop = NULL; 11995 machine_mode vec_mode; 11996 enum insn_code icode1, icode2; 11997 optab optab1, optab2; 11998 tree vectype = vectype_in; 11999 tree wide_vectype = vectype_out; 12000 enum tree_code c1, c2; 12001 int i; 12002 tree prev_type, intermediate_type; 12003 machine_mode intermediate_mode, prev_mode; 12004 optab optab3, optab4; 12005 12006 *multi_step_cvt = 0; 12007 if (loop_info) 12008 vect_loop = LOOP_VINFO_LOOP (loop_info); 12009 12010 switch (code) 12011 { 12012 case WIDEN_MULT_EXPR: 12013 /* The result of a vectorized widening operation usually requires 12014 two vectors (because the widened results do not fit into one vector). 12015 The generated vector results would normally be expected to be 12016 generated in the same order as in the original scalar computation, 12017 i.e. if 8 results are generated in each vector iteration, they are 12018 to be organized as follows: 12019 vect1: [res1,res2,res3,res4], 12020 vect2: [res5,res6,res7,res8]. 12021 12022 However, in the special case that the result of the widening 12023 operation is used in a reduction computation only, the order doesn't 12024 matter (because when vectorizing a reduction we change the order of 12025 the computation). Some targets can take advantage of this and 12026 generate more efficient code. For example, targets like Altivec, 12027 that support widen_mult using a sequence of {mult_even,mult_odd} 12028 generate the following vectors: 12029 vect1: [res1,res3,res5,res7], 12030 vect2: [res2,res4,res6,res8]. 12031 12032 When vectorizing outer-loops, we execute the inner-loop sequentially 12033 (each vectorized inner-loop iteration contributes to VF outer-loop 12034 iterations in parallel). We therefore don't allow to change the 12035 order of the computation in the inner-loop during outer-loop 12036 vectorization. */ 12037 /* TODO: Another case in which order doesn't *really* matter is when we 12038 widen and then contract again, e.g. (short)((int)x * y >> 8). 12039 Normally, pack_trunc performs an even/odd permute, whereas the 12040 repack from an even/odd expansion would be an interleave, which 12041 would be significantly simpler for e.g. AVX2. */ 12042 /* In any case, in order to avoid duplicating the code below, recurse 12043 on VEC_WIDEN_MULT_EVEN_EXPR. If it succeeds, all the return values 12044 are properly set up for the caller. If we fail, we'll continue with 12045 a VEC_WIDEN_MULT_LO/HI_EXPR check. */ 12046 if (vect_loop 12047 && STMT_VINFO_RELEVANT (stmt_info) == vect_used_by_reduction 12048 && !nested_in_vect_loop_p (vect_loop, stmt_info) 12049 && supportable_widening_operation (vinfo, VEC_WIDEN_MULT_EVEN_EXPR, 12050 stmt_info, vectype_out, 12051 vectype_in, code1, code2, 12052 multi_step_cvt, interm_types)) 12053 { 12054 /* Elements in a vector with vect_used_by_reduction property cannot 12055 be reordered if the use chain with this property does not have the 12056 same operation. One such an example is s += a * b, where elements 12057 in a and b cannot be reordered. Here we check if the vector defined 12058 by STMT is only directly used in the reduction statement. */ 12059 tree lhs = gimple_assign_lhs (stmt_info->stmt); 12060 stmt_vec_info use_stmt_info = loop_info->lookup_single_use (lhs); 12061 if (use_stmt_info 12062 && STMT_VINFO_DEF_TYPE (use_stmt_info) == vect_reduction_def) 12063 return true; 12064 } 12065 c1 = VEC_WIDEN_MULT_LO_EXPR; 12066 c2 = VEC_WIDEN_MULT_HI_EXPR; 12067 break; 12068 12069 case DOT_PROD_EXPR: 12070 c1 = DOT_PROD_EXPR; 12071 c2 = DOT_PROD_EXPR; 12072 break; 12073 12074 case SAD_EXPR: 12075 c1 = SAD_EXPR; 12076 c2 = SAD_EXPR; 12077 break; 12078 12079 case VEC_WIDEN_MULT_EVEN_EXPR: 12080 /* Support the recursion induced just above. */ 12081 c1 = VEC_WIDEN_MULT_EVEN_EXPR; 12082 c2 = VEC_WIDEN_MULT_ODD_EXPR; 12083 break; 12084 12085 case WIDEN_LSHIFT_EXPR: 12086 c1 = VEC_WIDEN_LSHIFT_LO_EXPR; 12087 c2 = VEC_WIDEN_LSHIFT_HI_EXPR; 12088 break; 12089 12090 case WIDEN_PLUS_EXPR: 12091 c1 = VEC_WIDEN_PLUS_LO_EXPR; 12092 c2 = VEC_WIDEN_PLUS_HI_EXPR; 12093 break; 12094 12095 case WIDEN_MINUS_EXPR: 12096 c1 = VEC_WIDEN_MINUS_LO_EXPR; 12097 c2 = VEC_WIDEN_MINUS_HI_EXPR; 12098 break; 12099 12100 CASE_CONVERT: 12101 c1 = VEC_UNPACK_LO_EXPR; 12102 c2 = VEC_UNPACK_HI_EXPR; 12103 break; 12104 12105 case FLOAT_EXPR: 12106 c1 = VEC_UNPACK_FLOAT_LO_EXPR; 12107 c2 = VEC_UNPACK_FLOAT_HI_EXPR; 12108 break; 12109 12110 case FIX_TRUNC_EXPR: 12111 c1 = VEC_UNPACK_FIX_TRUNC_LO_EXPR; 12112 c2 = VEC_UNPACK_FIX_TRUNC_HI_EXPR; 12113 break; 12114 12115 default: 12116 gcc_unreachable (); 12117 } 12118 12119 if (BYTES_BIG_ENDIAN && c1 != VEC_WIDEN_MULT_EVEN_EXPR) 12120 std::swap (c1, c2); 12121 12122 if (code == FIX_TRUNC_EXPR) 12123 { 12124 /* The signedness is determined from output operand. */ 12125 optab1 = optab_for_tree_code (c1, vectype_out, optab_default); 12126 optab2 = optab_for_tree_code (c2, vectype_out, optab_default); 12127 } 12128 else if (CONVERT_EXPR_CODE_P (code) 12129 && VECTOR_BOOLEAN_TYPE_P (wide_vectype) 12130 && VECTOR_BOOLEAN_TYPE_P (vectype) 12131 && TYPE_MODE (wide_vectype) == TYPE_MODE (vectype) 12132 && SCALAR_INT_MODE_P (TYPE_MODE (vectype))) 12133 { 12134 /* If the input and result modes are the same, a different optab 12135 is needed where we pass in the number of units in vectype. */ 12136 optab1 = vec_unpacks_sbool_lo_optab; 12137 optab2 = vec_unpacks_sbool_hi_optab; 12138 } 12139 else 12140 { 12141 optab1 = optab_for_tree_code (c1, vectype, optab_default); 12142 optab2 = optab_for_tree_code (c2, vectype, optab_default); 12143 } 12144 12145 if (!optab1 || !optab2) 12146 return false; 12147 12148 vec_mode = TYPE_MODE (vectype); 12149 if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing 12150 || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing) 12151 return false; 12152 12153 *code1 = c1; 12154 *code2 = c2; 12155 12156 if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype) 12157 && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype)) 12158 { 12159 if (!VECTOR_BOOLEAN_TYPE_P (vectype)) 12160 return true; 12161 /* For scalar masks we may have different boolean 12162 vector types having the same QImode. Thus we 12163 add additional check for elements number. */ 12164 if (known_eq (TYPE_VECTOR_SUBPARTS (vectype), 12165 TYPE_VECTOR_SUBPARTS (wide_vectype) * 2)) 12166 return true; 12167 } 12168 12169 /* Check if it's a multi-step conversion that can be done using intermediate 12170 types. */ 12171 12172 prev_type = vectype; 12173 prev_mode = vec_mode; 12174 12175 if (!CONVERT_EXPR_CODE_P (code)) 12176 return false; 12177 12178 /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS 12179 intermediate steps in promotion sequence. We try 12180 MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do 12181 not. */ 12182 interm_types->create (MAX_INTERM_CVT_STEPS); 12183 for (i = 0; i < MAX_INTERM_CVT_STEPS; i++) 12184 { 12185 intermediate_mode = insn_data[icode1].operand[0].mode; 12186 if (VECTOR_BOOLEAN_TYPE_P (prev_type)) 12187 intermediate_type 12188 = vect_halve_mask_nunits (prev_type, intermediate_mode); 12189 else 12190 intermediate_type 12191 = lang_hooks.types.type_for_mode (intermediate_mode, 12192 TYPE_UNSIGNED (prev_type)); 12193 12194 if (VECTOR_BOOLEAN_TYPE_P (intermediate_type) 12195 && VECTOR_BOOLEAN_TYPE_P (prev_type) 12196 && intermediate_mode == prev_mode 12197 && SCALAR_INT_MODE_P (prev_mode)) 12198 { 12199 /* If the input and result modes are the same, a different optab 12200 is needed where we pass in the number of units in vectype. */ 12201 optab3 = vec_unpacks_sbool_lo_optab; 12202 optab4 = vec_unpacks_sbool_hi_optab; 12203 } 12204 else 12205 { 12206 optab3 = optab_for_tree_code (c1, intermediate_type, optab_default); 12207 optab4 = optab_for_tree_code (c2, intermediate_type, optab_default); 12208 } 12209 12210 if (!optab3 || !optab4 12211 || (icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing 12212 || insn_data[icode1].operand[0].mode != intermediate_mode 12213 || (icode2 = optab_handler (optab2, prev_mode)) == CODE_FOR_nothing 12214 || insn_data[icode2].operand[0].mode != intermediate_mode 12215 || ((icode1 = optab_handler (optab3, intermediate_mode)) 12216 == CODE_FOR_nothing) 12217 || ((icode2 = optab_handler (optab4, intermediate_mode)) 12218 == CODE_FOR_nothing)) 12219 break; 12220 12221 interm_types->quick_push (intermediate_type); 12222 (*multi_step_cvt)++; 12223 12224 if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype) 12225 && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype)) 12226 { 12227 if (!VECTOR_BOOLEAN_TYPE_P (vectype)) 12228 return true; 12229 if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type), 12230 TYPE_VECTOR_SUBPARTS (wide_vectype) * 2)) 12231 return true; 12232 } 12233 12234 prev_type = intermediate_type; 12235 prev_mode = intermediate_mode; 12236 } 12237 12238 interm_types->release (); 12239 return false; 12240 } 12241 12242 12243 /* Function supportable_narrowing_operation 12244 12245 Check whether an operation represented by the code CODE is a 12246 narrowing operation that is supported by the target platform in 12247 vector form (i.e., when operating on arguments of type VECTYPE_IN 12248 and producing a result of type VECTYPE_OUT). 12249 12250 Narrowing operations we currently support are NOP (CONVERT), FIX_TRUNC 12251 and FLOAT. This function checks if these operations are supported by 12252 the target platform directly via vector tree-codes. 12253 12254 Output: 12255 - CODE1 is the code of a vector operation to be used when 12256 vectorizing the operation, if available. 12257 - MULTI_STEP_CVT determines the number of required intermediate steps in 12258 case of multi-step conversion (like int->short->char - in that case 12259 MULTI_STEP_CVT will be 1). 12260 - INTERM_TYPES contains the intermediate type required to perform the 12261 narrowing operation (short in the above example). */ 12262 12263 bool 12264 supportable_narrowing_operation (enum tree_code code, 12265 tree vectype_out, tree vectype_in, 12266 enum tree_code *code1, int *multi_step_cvt, 12267 vec<tree> *interm_types) 12268 { 12269 machine_mode vec_mode; 12270 enum insn_code icode1; 12271 optab optab1, interm_optab; 12272 tree vectype = vectype_in; 12273 tree narrow_vectype = vectype_out; 12274 enum tree_code c1; 12275 tree intermediate_type, prev_type; 12276 machine_mode intermediate_mode, prev_mode; 12277 int i; 12278 unsigned HOST_WIDE_INT n_elts; 12279 bool uns; 12280 12281 *multi_step_cvt = 0; 12282 switch (code) 12283 { 12284 CASE_CONVERT: 12285 c1 = VEC_PACK_TRUNC_EXPR; 12286 if (VECTOR_BOOLEAN_TYPE_P (narrow_vectype) 12287 && VECTOR_BOOLEAN_TYPE_P (vectype) 12288 && SCALAR_INT_MODE_P (TYPE_MODE (vectype)) 12289 && TYPE_VECTOR_SUBPARTS (vectype).is_constant (&n_elts) 12290 && n_elts < BITS_PER_UNIT) 12291 optab1 = vec_pack_sbool_trunc_optab; 12292 else 12293 optab1 = optab_for_tree_code (c1, vectype, optab_default); 12294 break; 12295 12296 case FIX_TRUNC_EXPR: 12297 c1 = VEC_PACK_FIX_TRUNC_EXPR; 12298 /* The signedness is determined from output operand. */ 12299 optab1 = optab_for_tree_code (c1, vectype_out, optab_default); 12300 break; 12301 12302 case FLOAT_EXPR: 12303 c1 = VEC_PACK_FLOAT_EXPR; 12304 optab1 = optab_for_tree_code (c1, vectype, optab_default); 12305 break; 12306 12307 default: 12308 gcc_unreachable (); 12309 } 12310 12311 if (!optab1) 12312 return false; 12313 12314 vec_mode = TYPE_MODE (vectype); 12315 if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing) 12316 return false; 12317 12318 *code1 = c1; 12319 12320 if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype)) 12321 { 12322 if (!VECTOR_BOOLEAN_TYPE_P (vectype)) 12323 return true; 12324 /* For scalar masks we may have different boolean 12325 vector types having the same QImode. Thus we 12326 add additional check for elements number. */ 12327 if (known_eq (TYPE_VECTOR_SUBPARTS (vectype) * 2, 12328 TYPE_VECTOR_SUBPARTS (narrow_vectype))) 12329 return true; 12330 } 12331 12332 if (code == FLOAT_EXPR) 12333 return false; 12334 12335 /* Check if it's a multi-step conversion that can be done using intermediate 12336 types. */ 12337 prev_mode = vec_mode; 12338 prev_type = vectype; 12339 if (code == FIX_TRUNC_EXPR) 12340 uns = TYPE_UNSIGNED (vectype_out); 12341 else 12342 uns = TYPE_UNSIGNED (vectype); 12343 12344 /* For multi-step FIX_TRUNC_EXPR prefer signed floating to integer 12345 conversion over unsigned, as unsigned FIX_TRUNC_EXPR is often more 12346 costly than signed. */ 12347 if (code == FIX_TRUNC_EXPR && uns) 12348 { 12349 enum insn_code icode2; 12350 12351 intermediate_type 12352 = lang_hooks.types.type_for_mode (TYPE_MODE (vectype_out), 0); 12353 interm_optab 12354 = optab_for_tree_code (c1, intermediate_type, optab_default); 12355 if (interm_optab != unknown_optab 12356 && (icode2 = optab_handler (optab1, vec_mode)) != CODE_FOR_nothing 12357 && insn_data[icode1].operand[0].mode 12358 == insn_data[icode2].operand[0].mode) 12359 { 12360 uns = false; 12361 optab1 = interm_optab; 12362 icode1 = icode2; 12363 } 12364 } 12365 12366 /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS 12367 intermediate steps in promotion sequence. We try 12368 MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do not. */ 12369 interm_types->create (MAX_INTERM_CVT_STEPS); 12370 for (i = 0; i < MAX_INTERM_CVT_STEPS; i++) 12371 { 12372 intermediate_mode = insn_data[icode1].operand[0].mode; 12373 if (VECTOR_BOOLEAN_TYPE_P (prev_type)) 12374 intermediate_type 12375 = vect_double_mask_nunits (prev_type, intermediate_mode); 12376 else 12377 intermediate_type 12378 = lang_hooks.types.type_for_mode (intermediate_mode, uns); 12379 if (VECTOR_BOOLEAN_TYPE_P (intermediate_type) 12380 && VECTOR_BOOLEAN_TYPE_P (prev_type) 12381 && SCALAR_INT_MODE_P (prev_mode) 12382 && TYPE_VECTOR_SUBPARTS (intermediate_type).is_constant (&n_elts) 12383 && n_elts < BITS_PER_UNIT) 12384 interm_optab = vec_pack_sbool_trunc_optab; 12385 else 12386 interm_optab 12387 = optab_for_tree_code (VEC_PACK_TRUNC_EXPR, intermediate_type, 12388 optab_default); 12389 if (!interm_optab 12390 || ((icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing) 12391 || insn_data[icode1].operand[0].mode != intermediate_mode 12392 || ((icode1 = optab_handler (interm_optab, intermediate_mode)) 12393 == CODE_FOR_nothing)) 12394 break; 12395 12396 interm_types->quick_push (intermediate_type); 12397 (*multi_step_cvt)++; 12398 12399 if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype)) 12400 { 12401 if (!VECTOR_BOOLEAN_TYPE_P (vectype)) 12402 return true; 12403 if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type) * 2, 12404 TYPE_VECTOR_SUBPARTS (narrow_vectype))) 12405 return true; 12406 } 12407 12408 prev_mode = intermediate_mode; 12409 prev_type = intermediate_type; 12410 optab1 = interm_optab; 12411 } 12412 12413 interm_types->release (); 12414 return false; 12415 } 12416 12417 /* Generate and return a vector mask of MASK_TYPE such that 12418 mask[I] is true iff J + START_INDEX < END_INDEX for all J <= I. 12419 Add the statements to SEQ. */ 12420 12421 tree 12422 vect_gen_while (gimple_seq *seq, tree mask_type, tree start_index, 12423 tree end_index, const char *name) 12424 { 12425 tree cmp_type = TREE_TYPE (start_index); 12426 gcc_checking_assert (direct_internal_fn_supported_p (IFN_WHILE_ULT, 12427 cmp_type, mask_type, 12428 OPTIMIZE_FOR_SPEED)); 12429 gcall *call = gimple_build_call_internal (IFN_WHILE_ULT, 3, 12430 start_index, end_index, 12431 build_zero_cst (mask_type)); 12432 tree tmp; 12433 if (name) 12434 tmp = make_temp_ssa_name (mask_type, NULL, name); 12435 else 12436 tmp = make_ssa_name (mask_type); 12437 gimple_call_set_lhs (call, tmp); 12438 gimple_seq_add_stmt (seq, call); 12439 return tmp; 12440 } 12441 12442 /* Generate a vector mask of type MASK_TYPE for which index I is false iff 12443 J + START_INDEX < END_INDEX for all J <= I. Add the statements to SEQ. */ 12444 12445 tree 12446 vect_gen_while_not (gimple_seq *seq, tree mask_type, tree start_index, 12447 tree end_index) 12448 { 12449 tree tmp = vect_gen_while (seq, mask_type, start_index, end_index); 12450 return gimple_build (seq, BIT_NOT_EXPR, mask_type, tmp); 12451 } 12452 12453 /* Try to compute the vector types required to vectorize STMT_INFO, 12454 returning true on success and false if vectorization isn't possible. 12455 If GROUP_SIZE is nonzero and we're performing BB vectorization, 12456 take sure that the number of elements in the vectors is no bigger 12457 than GROUP_SIZE. 12458 12459 On success: 12460 12461 - Set *STMT_VECTYPE_OUT to: 12462 - NULL_TREE if the statement doesn't need to be vectorized; 12463 - the equivalent of STMT_VINFO_VECTYPE otherwise. 12464 12465 - Set *NUNITS_VECTYPE_OUT to the vector type that contains the maximum 12466 number of units needed to vectorize STMT_INFO, or NULL_TREE if the 12467 statement does not help to determine the overall number of units. */ 12468 12469 opt_result 12470 vect_get_vector_types_for_stmt (vec_info *vinfo, stmt_vec_info stmt_info, 12471 tree *stmt_vectype_out, 12472 tree *nunits_vectype_out, 12473 unsigned int group_size) 12474 { 12475 gimple *stmt = stmt_info->stmt; 12476 12477 /* For BB vectorization, we should always have a group size once we've 12478 constructed the SLP tree; the only valid uses of zero GROUP_SIZEs 12479 are tentative requests during things like early data reference 12480 analysis and pattern recognition. */ 12481 if (is_a <bb_vec_info> (vinfo)) 12482 gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0); 12483 else 12484 group_size = 0; 12485 12486 *stmt_vectype_out = NULL_TREE; 12487 *nunits_vectype_out = NULL_TREE; 12488 12489 if (gimple_get_lhs (stmt) == NULL_TREE 12490 /* MASK_STORE has no lhs, but is ok. */ 12491 && !gimple_call_internal_p (stmt, IFN_MASK_STORE)) 12492 { 12493 if (is_a <gcall *> (stmt)) 12494 { 12495 /* Ignore calls with no lhs. These must be calls to 12496 #pragma omp simd functions, and what vectorization factor 12497 it really needs can't be determined until 12498 vectorizable_simd_clone_call. */ 12499 if (dump_enabled_p ()) 12500 dump_printf_loc (MSG_NOTE, vect_location, 12501 "defer to SIMD clone analysis.\n"); 12502 return opt_result::success (); 12503 } 12504 12505 return opt_result::failure_at (stmt, 12506 "not vectorized: irregular stmt.%G", stmt); 12507 } 12508 12509 tree vectype; 12510 tree scalar_type = NULL_TREE; 12511 if (group_size == 0 && STMT_VINFO_VECTYPE (stmt_info)) 12512 { 12513 vectype = STMT_VINFO_VECTYPE (stmt_info); 12514 if (dump_enabled_p ()) 12515 dump_printf_loc (MSG_NOTE, vect_location, 12516 "precomputed vectype: %T\n", vectype); 12517 } 12518 else if (vect_use_mask_type_p (stmt_info)) 12519 { 12520 unsigned int precision = stmt_info->mask_precision; 12521 scalar_type = build_nonstandard_integer_type (precision, 1); 12522 vectype = get_mask_type_for_scalar_type (vinfo, scalar_type, group_size); 12523 if (!vectype) 12524 return opt_result::failure_at (stmt, "not vectorized: unsupported" 12525 " data-type %T\n", scalar_type); 12526 if (dump_enabled_p ()) 12527 dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype); 12528 } 12529 else 12530 { 12531 if (data_reference *dr = STMT_VINFO_DATA_REF (stmt_info)) 12532 scalar_type = TREE_TYPE (DR_REF (dr)); 12533 else if (gimple_call_internal_p (stmt, IFN_MASK_STORE)) 12534 scalar_type = TREE_TYPE (gimple_call_arg (stmt, 3)); 12535 else 12536 scalar_type = TREE_TYPE (gimple_get_lhs (stmt)); 12537 12538 if (dump_enabled_p ()) 12539 { 12540 if (group_size) 12541 dump_printf_loc (MSG_NOTE, vect_location, 12542 "get vectype for scalar type (group size %d):" 12543 " %T\n", group_size, scalar_type); 12544 else 12545 dump_printf_loc (MSG_NOTE, vect_location, 12546 "get vectype for scalar type: %T\n", scalar_type); 12547 } 12548 vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size); 12549 if (!vectype) 12550 return opt_result::failure_at (stmt, 12551 "not vectorized:" 12552 " unsupported data-type %T\n", 12553 scalar_type); 12554 12555 if (dump_enabled_p ()) 12556 dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype); 12557 } 12558 12559 if (scalar_type && VECTOR_MODE_P (TYPE_MODE (scalar_type))) 12560 return opt_result::failure_at (stmt, 12561 "not vectorized: vector stmt in loop:%G", 12562 stmt); 12563 12564 *stmt_vectype_out = vectype; 12565 12566 /* Don't try to compute scalar types if the stmt produces a boolean 12567 vector; use the existing vector type instead. */ 12568 tree nunits_vectype = vectype; 12569 if (!VECTOR_BOOLEAN_TYPE_P (vectype)) 12570 { 12571 /* The number of units is set according to the smallest scalar 12572 type (or the largest vector size, but we only support one 12573 vector size per vectorization). */ 12574 scalar_type = vect_get_smallest_scalar_type (stmt_info, 12575 TREE_TYPE (vectype)); 12576 if (scalar_type != TREE_TYPE (vectype)) 12577 { 12578 if (dump_enabled_p ()) 12579 dump_printf_loc (MSG_NOTE, vect_location, 12580 "get vectype for smallest scalar type: %T\n", 12581 scalar_type); 12582 nunits_vectype = get_vectype_for_scalar_type (vinfo, scalar_type, 12583 group_size); 12584 if (!nunits_vectype) 12585 return opt_result::failure_at 12586 (stmt, "not vectorized: unsupported data-type %T\n", 12587 scalar_type); 12588 if (dump_enabled_p ()) 12589 dump_printf_loc (MSG_NOTE, vect_location, "nunits vectype: %T\n", 12590 nunits_vectype); 12591 } 12592 } 12593 12594 if (!multiple_p (TYPE_VECTOR_SUBPARTS (nunits_vectype), 12595 TYPE_VECTOR_SUBPARTS (*stmt_vectype_out))) 12596 return opt_result::failure_at (stmt, 12597 "Not vectorized: Incompatible number " 12598 "of vector subparts between %T and %T\n", 12599 nunits_vectype, *stmt_vectype_out); 12600 12601 if (dump_enabled_p ()) 12602 { 12603 dump_printf_loc (MSG_NOTE, vect_location, "nunits = "); 12604 dump_dec (MSG_NOTE, TYPE_VECTOR_SUBPARTS (nunits_vectype)); 12605 dump_printf (MSG_NOTE, "\n"); 12606 } 12607 12608 *nunits_vectype_out = nunits_vectype; 12609 return opt_result::success (); 12610 } 12611 12612 /* Generate and return statement sequence that sets vector length LEN that is: 12613 12614 min_of_start_and_end = min (START_INDEX, END_INDEX); 12615 left_len = END_INDEX - min_of_start_and_end; 12616 rhs = min (left_len, LEN_LIMIT); 12617 LEN = rhs; 12618 12619 Note: the cost of the code generated by this function is modeled 12620 by vect_estimate_min_profitable_iters, so changes here may need 12621 corresponding changes there. */ 12622 12623 gimple_seq 12624 vect_gen_len (tree len, tree start_index, tree end_index, tree len_limit) 12625 { 12626 gimple_seq stmts = NULL; 12627 tree len_type = TREE_TYPE (len); 12628 gcc_assert (TREE_TYPE (start_index) == len_type); 12629 12630 tree min = gimple_build (&stmts, MIN_EXPR, len_type, start_index, end_index); 12631 tree left_len = gimple_build (&stmts, MINUS_EXPR, len_type, end_index, min); 12632 tree rhs = gimple_build (&stmts, MIN_EXPR, len_type, left_len, len_limit); 12633 gimple* stmt = gimple_build_assign (len, rhs); 12634 gimple_seq_add_stmt (&stmts, stmt); 12635 12636 return stmts; 12637 } 12638 12639