Branch data Line data Source code
1 : : /* Statement Analysis and Transformation for Vectorization
2 : : Copyright (C) 2003-2024 Free Software Foundation, Inc.
3 : : Contributed by Dorit Naishlos <dorit@il.ibm.com>
4 : : and Ira Rosen <irar@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 "gimple-range.h"
55 : : #include "tree-ssa-loop-niter.h"
56 : : #include "gimple-fold.h"
57 : : #include "regs.h"
58 : : #include "attribs.h"
59 : : #include "optabs-libfuncs.h"
60 : :
61 : : /* For lang_hooks.types.type_for_mode. */
62 : : #include "langhooks.h"
63 : :
64 : : /* Return the vectorized type for the given statement. */
65 : :
66 : : tree
67 : 0 : stmt_vectype (class _stmt_vec_info *stmt_info)
68 : : {
69 : 0 : return STMT_VINFO_VECTYPE (stmt_info);
70 : : }
71 : :
72 : : /* Return TRUE iff the given statement is in an inner loop relative to
73 : : the loop being vectorized. */
74 : : bool
75 : 3732865 : stmt_in_inner_loop_p (vec_info *vinfo, class _stmt_vec_info *stmt_info)
76 : : {
77 : 3732865 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
78 : 3732865 : basic_block bb = gimple_bb (stmt);
79 : 3732865 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
80 : 828879 : class loop* loop;
81 : :
82 : 828879 : if (!loop_vinfo)
83 : : return false;
84 : :
85 : 828879 : loop = LOOP_VINFO_LOOP (loop_vinfo);
86 : :
87 : 828879 : return (bb->loop_father == loop->inner);
88 : : }
89 : :
90 : : /* Record the cost of a statement, either by directly informing the
91 : : target model or by saving it in a vector for later processing.
92 : : Return a preliminary estimate of the statement's cost. */
93 : :
94 : : static unsigned
95 : 7360391 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
96 : : enum vect_cost_for_stmt kind,
97 : : stmt_vec_info stmt_info, slp_tree node,
98 : : tree vectype, int misalign,
99 : : enum vect_cost_model_location where)
100 : : {
101 : 7360391 : if ((kind == vector_load || kind == unaligned_load)
102 : 901440 : && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info)))
103 : 7360391 : kind = vector_gather_load;
104 : 7360391 : if ((kind == vector_store || kind == unaligned_store)
105 : 845677 : && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info)))
106 : 7360391 : kind = vector_scatter_store;
107 : :
108 : 7360391 : stmt_info_for_cost si
109 : 7360391 : = { count, kind, where, stmt_info, node, vectype, misalign };
110 : 7360391 : body_cost_vec->safe_push (si);
111 : :
112 : 7360391 : return (unsigned)
113 : 7360391 : (builtin_vectorization_cost (kind, vectype, misalign) * count);
114 : : }
115 : :
116 : : unsigned
117 : 6402140 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
118 : : enum vect_cost_for_stmt kind, stmt_vec_info stmt_info,
119 : : tree vectype, int misalign,
120 : : enum vect_cost_model_location where)
121 : : {
122 : 6402140 : return record_stmt_cost (body_cost_vec, count, kind, stmt_info, NULL,
123 : 6402140 : vectype, misalign, where);
124 : : }
125 : :
126 : : unsigned
127 : 869444 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
128 : : enum vect_cost_for_stmt kind, slp_tree node,
129 : : tree vectype, int misalign,
130 : : enum vect_cost_model_location where)
131 : : {
132 : 869444 : return record_stmt_cost (body_cost_vec, count, kind, NULL, node,
133 : 869444 : vectype, misalign, where);
134 : : }
135 : :
136 : : unsigned
137 : 88807 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
138 : : enum vect_cost_for_stmt kind,
139 : : enum vect_cost_model_location where)
140 : : {
141 : 88807 : gcc_assert (kind == cond_branch_taken || kind == cond_branch_not_taken
142 : : || kind == scalar_stmt);
143 : 88807 : return record_stmt_cost (body_cost_vec, count, kind, NULL, NULL,
144 : 88807 : NULL_TREE, 0, where);
145 : : }
146 : :
147 : : /* Return a variable of type ELEM_TYPE[NELEMS]. */
148 : :
149 : : static tree
150 : 0 : create_vector_array (tree elem_type, unsigned HOST_WIDE_INT nelems)
151 : : {
152 : 0 : return create_tmp_var (build_array_type_nelts (elem_type, nelems),
153 : 0 : "vect_array");
154 : : }
155 : :
156 : : /* ARRAY is an array of vectors created by create_vector_array.
157 : : Return an SSA_NAME for the vector in index N. The reference
158 : : is part of the vectorization of STMT_INFO and the vector is associated
159 : : with scalar destination SCALAR_DEST. */
160 : :
161 : : static tree
162 : 0 : read_vector_array (vec_info *vinfo,
163 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
164 : : tree scalar_dest, tree array, unsigned HOST_WIDE_INT n)
165 : : {
166 : 0 : tree vect_type, vect, vect_name, array_ref;
167 : 0 : gimple *new_stmt;
168 : :
169 : 0 : gcc_assert (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE);
170 : 0 : vect_type = TREE_TYPE (TREE_TYPE (array));
171 : 0 : vect = vect_create_destination_var (scalar_dest, vect_type);
172 : 0 : array_ref = build4 (ARRAY_REF, vect_type, array,
173 : : build_int_cst (size_type_node, n),
174 : : NULL_TREE, NULL_TREE);
175 : :
176 : 0 : new_stmt = gimple_build_assign (vect, array_ref);
177 : 0 : vect_name = make_ssa_name (vect, new_stmt);
178 : 0 : gimple_assign_set_lhs (new_stmt, vect_name);
179 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
180 : :
181 : 0 : return vect_name;
182 : : }
183 : :
184 : : /* ARRAY is an array of vectors created by create_vector_array.
185 : : Emit code to store SSA_NAME VECT in index N of the array.
186 : : The store is part of the vectorization of STMT_INFO. */
187 : :
188 : : static void
189 : 0 : write_vector_array (vec_info *vinfo,
190 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
191 : : tree vect, tree array, unsigned HOST_WIDE_INT n)
192 : : {
193 : 0 : tree array_ref;
194 : 0 : gimple *new_stmt;
195 : :
196 : 0 : array_ref = build4 (ARRAY_REF, TREE_TYPE (vect), array,
197 : : build_int_cst (size_type_node, n),
198 : : NULL_TREE, NULL_TREE);
199 : :
200 : 0 : new_stmt = gimple_build_assign (array_ref, vect);
201 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
202 : 0 : }
203 : :
204 : : /* PTR is a pointer to an array of type TYPE. Return a representation
205 : : of *PTR. The memory reference replaces those in FIRST_DR
206 : : (and its group). */
207 : :
208 : : static tree
209 : 0 : create_array_ref (tree type, tree ptr, tree alias_ptr_type)
210 : : {
211 : 0 : tree mem_ref;
212 : :
213 : 0 : mem_ref = build2 (MEM_REF, type, ptr, build_int_cst (alias_ptr_type, 0));
214 : : /* Arrays have the same alignment as their type. */
215 : 0 : set_ptr_info_alignment (get_ptr_info (ptr), TYPE_ALIGN_UNIT (type), 0);
216 : 0 : return mem_ref;
217 : : }
218 : :
219 : : /* Add a clobber of variable VAR to the vectorization of STMT_INFO.
220 : : Emit the clobber before *GSI. */
221 : :
222 : : static void
223 : 15 : vect_clobber_variable (vec_info *vinfo, stmt_vec_info stmt_info,
224 : : gimple_stmt_iterator *gsi, tree var)
225 : : {
226 : 15 : tree clobber = build_clobber (TREE_TYPE (var));
227 : 15 : gimple *new_stmt = gimple_build_assign (var, clobber);
228 : 15 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
229 : 15 : }
230 : :
231 : : /* Utility functions used by vect_mark_stmts_to_be_vectorized. */
232 : :
233 : : /* Function vect_mark_relevant.
234 : :
235 : : Mark STMT_INFO as "relevant for vectorization" and add it to WORKLIST. */
236 : :
237 : : static void
238 : 2526296 : vect_mark_relevant (vec<stmt_vec_info> *worklist, stmt_vec_info stmt_info,
239 : : enum vect_relevant relevant, bool live_p)
240 : : {
241 : 2526296 : enum vect_relevant save_relevant = STMT_VINFO_RELEVANT (stmt_info);
242 : 2526296 : bool save_live_p = STMT_VINFO_LIVE_P (stmt_info);
243 : :
244 : 2526296 : if (dump_enabled_p ())
245 : 161794 : dump_printf_loc (MSG_NOTE, vect_location,
246 : : "mark relevant %d, live %d: %G", relevant, live_p,
247 : : stmt_info->stmt);
248 : :
249 : : /* If this stmt is an original stmt in a pattern, we might need to mark its
250 : : related pattern stmt instead of the original stmt. However, such stmts
251 : : may have their own uses that are not in any pattern, in such cases the
252 : : stmt itself should be marked. */
253 : 2526296 : if (STMT_VINFO_IN_PATTERN_P (stmt_info))
254 : : {
255 : : /* This is the last stmt in a sequence that was detected as a
256 : : pattern that can potentially be vectorized. Don't mark the stmt
257 : : as relevant/live because it's not going to be vectorized.
258 : : Instead mark the pattern-stmt that replaces it. */
259 : :
260 : 120501 : if (dump_enabled_p ())
261 : 2228 : dump_printf_loc (MSG_NOTE, vect_location,
262 : : "last stmt in pattern. don't mark"
263 : : " relevant/live.\n");
264 : :
265 : 120501 : stmt_vec_info old_stmt_info = stmt_info;
266 : 120501 : stmt_info = STMT_VINFO_RELATED_STMT (stmt_info);
267 : 120501 : gcc_assert (STMT_VINFO_RELATED_STMT (stmt_info) == old_stmt_info);
268 : 120501 : save_relevant = STMT_VINFO_RELEVANT (stmt_info);
269 : 120501 : save_live_p = STMT_VINFO_LIVE_P (stmt_info);
270 : :
271 : 120501 : if (live_p && relevant == vect_unused_in_scope)
272 : : {
273 : 114 : if (dump_enabled_p ())
274 : 6 : dump_printf_loc (MSG_NOTE, vect_location,
275 : : "vec_stmt_relevant_p: forcing live pattern stmt "
276 : : "relevant.\n");
277 : : relevant = vect_used_only_live;
278 : : }
279 : :
280 : 120501 : if (dump_enabled_p ())
281 : 2228 : dump_printf_loc (MSG_NOTE, vect_location,
282 : : "mark relevant %d, live %d: %G", relevant, live_p,
283 : : stmt_info->stmt);
284 : : }
285 : :
286 : 2526296 : STMT_VINFO_LIVE_P (stmt_info) |= live_p;
287 : 2526296 : if (relevant > STMT_VINFO_RELEVANT (stmt_info))
288 : 2099155 : STMT_VINFO_RELEVANT (stmt_info) = relevant;
289 : :
290 : 2526296 : if (STMT_VINFO_RELEVANT (stmt_info) == save_relevant
291 : 427141 : && STMT_VINFO_LIVE_P (stmt_info) == save_live_p)
292 : : {
293 : 426868 : if (dump_enabled_p ())
294 : 19797 : dump_printf_loc (MSG_NOTE, vect_location,
295 : : "already marked relevant/live.\n");
296 : 426868 : return;
297 : : }
298 : :
299 : 2099428 : worklist->safe_push (stmt_info);
300 : : }
301 : :
302 : :
303 : : /* Function is_simple_and_all_uses_invariant
304 : :
305 : : Return true if STMT_INFO is simple and all uses of it are invariant. */
306 : :
307 : : bool
308 : 288732 : is_simple_and_all_uses_invariant (stmt_vec_info stmt_info,
309 : : loop_vec_info loop_vinfo)
310 : : {
311 : 288732 : tree op;
312 : 288732 : ssa_op_iter iter;
313 : :
314 : 400835 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
315 : 112558 : if (!stmt)
316 : : return false;
317 : :
318 : 114958 : FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
319 : : {
320 : 114503 : enum vect_def_type dt = vect_uninitialized_def;
321 : :
322 : 114503 : if (!vect_is_simple_use (op, loop_vinfo, &dt))
323 : : {
324 : 1021 : if (dump_enabled_p ())
325 : 25 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
326 : : "use not simple.\n");
327 : 112103 : return false;
328 : : }
329 : :
330 : 113482 : if (dt != vect_external_def && dt != vect_constant_def)
331 : : return false;
332 : : }
333 : : return true;
334 : : }
335 : :
336 : : /* Function vect_stmt_relevant_p.
337 : :
338 : : Return true if STMT_INFO, in the loop that is represented by LOOP_VINFO,
339 : : is "relevant for vectorization".
340 : :
341 : : A stmt is considered "relevant for vectorization" if:
342 : : - it has uses outside the loop.
343 : : - it has vdefs (it alters memory).
344 : : - control stmts in the loop (except for the exit condition).
345 : : - it is an induction and we have multiple exits.
346 : :
347 : : CHECKME: what other side effects would the vectorizer allow? */
348 : :
349 : : static bool
350 : 3546337 : vect_stmt_relevant_p (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
351 : : enum vect_relevant *relevant, bool *live_p)
352 : : {
353 : 3546337 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
354 : 3546337 : ssa_op_iter op_iter;
355 : 3546337 : imm_use_iterator imm_iter;
356 : 3546337 : use_operand_p use_p;
357 : 3546337 : def_operand_p def_p;
358 : :
359 : 3546337 : *relevant = vect_unused_in_scope;
360 : 3546337 : *live_p = false;
361 : :
362 : : /* cond stmt other than loop exit cond. */
363 : 3546337 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
364 : 3546337 : if (is_ctrl_stmt (stmt)
365 : 401257 : && LOOP_VINFO_LOOP_IV_COND (loop_vinfo) != stmt
366 : 3667730 : && (!loop->inner || gimple_bb (stmt)->loop_father == loop))
367 : 119887 : *relevant = vect_used_in_scope;
368 : :
369 : : /* changing memory. */
370 : 3546337 : if (gimple_code (stmt_info->stmt) != GIMPLE_PHI)
371 : 2815531 : if (gimple_vdef (stmt_info->stmt)
372 : 2411850 : && !gimple_clobber_p (stmt_info->stmt))
373 : : {
374 : 250444 : if (dump_enabled_p ())
375 : 27303 : dump_printf_loc (MSG_NOTE, vect_location,
376 : : "vec_stmt_relevant_p: stmt has vdefs.\n");
377 : 250444 : *relevant = vect_used_in_scope;
378 : : }
379 : :
380 : : /* uses outside the loop. */
381 : 9816664 : FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt_info->stmt, op_iter, SSA_OP_DEF)
382 : : {
383 : 7071303 : FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
384 : : {
385 : 4347313 : basic_block bb = gimple_bb (USE_STMT (use_p));
386 : 4347313 : if (!flow_bb_inside_loop_p (loop, bb))
387 : : {
388 : 150851 : if (is_gimple_debug (USE_STMT (use_p)))
389 : 1373 : continue;
390 : :
391 : 149478 : if (dump_enabled_p ())
392 : 5497 : dump_printf_loc (MSG_NOTE, vect_location,
393 : : "vec_stmt_relevant_p: used out of loop.\n");
394 : :
395 : : /* We expect all such uses to be in the loop exit phis
396 : : (because of loop closed form) */
397 : 149478 : gcc_assert (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI);
398 : :
399 : 149478 : *live_p = true;
400 : : }
401 : : }
402 : : }
403 : :
404 : : /* Check if it's an induction and multiple exits. In this case there will be
405 : : a usage later on after peeling which is needed for the alternate exit. */
406 : 3546337 : if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
407 : 991987 : && STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def)
408 : : {
409 : 165035 : if (dump_enabled_p ())
410 : 2713 : dump_printf_loc (MSG_NOTE, vect_location,
411 : : "vec_stmt_relevant_p: induction forced for "
412 : : "early break.\n");
413 : 165035 : *live_p = true;
414 : :
415 : : }
416 : :
417 : 288674 : if (*live_p && *relevant == vect_unused_in_scope
418 : 3835001 : && !is_simple_and_all_uses_invariant (stmt_info, loop_vinfo))
419 : : {
420 : 288277 : if (dump_enabled_p ())
421 : 7914 : dump_printf_loc (MSG_NOTE, vect_location,
422 : : "vec_stmt_relevant_p: stmt live but not relevant.\n");
423 : 288277 : *relevant = vect_used_only_live;
424 : : }
425 : :
426 : 3546337 : return (*live_p || *relevant);
427 : : }
428 : :
429 : :
430 : : /* Function exist_non_indexing_operands_for_use_p
431 : :
432 : : USE is one of the uses attached to STMT_INFO. Check if USE is
433 : : used in STMT_INFO for anything other than indexing an array. */
434 : :
435 : : static bool
436 : 3215290 : exist_non_indexing_operands_for_use_p (tree use, stmt_vec_info stmt_info)
437 : : {
438 : 3215290 : tree operand;
439 : :
440 : : /* USE corresponds to some operand in STMT. If there is no data
441 : : reference in STMT, then any operand that corresponds to USE
442 : : is not indexing an array. */
443 : 3215290 : if (!STMT_VINFO_DATA_REF (stmt_info))
444 : : return true;
445 : :
446 : : /* STMT has a data_ref. FORNOW this means that its of one of
447 : : the following forms:
448 : : -1- ARRAY_REF = var
449 : : -2- var = ARRAY_REF
450 : : (This should have been verified in analyze_data_refs).
451 : :
452 : : 'var' in the second case corresponds to a def, not a use,
453 : : so USE cannot correspond to any operands that are not used
454 : : for array indexing.
455 : :
456 : : Therefore, all we need to check is if STMT falls into the
457 : : first case, and whether var corresponds to USE. */
458 : :
459 : 1006972 : gassign *assign = dyn_cast <gassign *> (stmt_info->stmt);
460 : 992671 : if (!assign || !gimple_assign_copy_p (assign))
461 : : {
462 : 518438 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
463 : 14301 : if (call && gimple_call_internal_p (call))
464 : : {
465 : 14301 : internal_fn ifn = gimple_call_internal_fn (call);
466 : 14301 : int mask_index = internal_fn_mask_index (ifn);
467 : 14301 : if (mask_index >= 0
468 : 14301 : && use == gimple_call_arg (call, mask_index))
469 : : return true;
470 : 8986 : int stored_value_index = internal_fn_stored_value_index (ifn);
471 : 8986 : if (stored_value_index >= 0
472 : 8986 : && use == gimple_call_arg (call, stored_value_index))
473 : : return true;
474 : 6884 : if (internal_gather_scatter_fn_p (ifn)
475 : 6884 : && use == gimple_call_arg (call, 1))
476 : : return true;
477 : : }
478 : 511021 : return false;
479 : : }
480 : :
481 : 488534 : if (TREE_CODE (gimple_assign_lhs (assign)) == SSA_NAME)
482 : : return false;
483 : 488534 : operand = gimple_assign_rhs1 (assign);
484 : 488534 : if (TREE_CODE (operand) != SSA_NAME)
485 : : return false;
486 : :
487 : 435551 : if (operand == use)
488 : : return true;
489 : :
490 : : return false;
491 : : }
492 : :
493 : :
494 : : /*
495 : : Function process_use.
496 : :
497 : : Inputs:
498 : : - a USE in STMT_VINFO in a loop represented by LOOP_VINFO
499 : : - RELEVANT - enum value to be set in the STMT_VINFO of the stmt
500 : : that defined USE. This is done by calling mark_relevant and passing it
501 : : the WORKLIST (to add DEF_STMT to the WORKLIST in case it is relevant).
502 : : - FORCE is true if exist_non_indexing_operands_for_use_p check shouldn't
503 : : be performed.
504 : :
505 : : Outputs:
506 : : Generally, LIVE_P and RELEVANT are used to define the liveness and
507 : : relevance info of the DEF_STMT of this USE:
508 : : STMT_VINFO_LIVE_P (DEF_stmt_vinfo) <-- live_p
509 : : STMT_VINFO_RELEVANT (DEF_stmt_vinfo) <-- relevant
510 : : Exceptions:
511 : : - case 1: If USE is used only for address computations (e.g. array indexing),
512 : : which does not need to be directly vectorized, then the liveness/relevance
513 : : of the respective DEF_STMT is left unchanged.
514 : : - case 2: If STMT_VINFO is a reduction phi and DEF_STMT is a reduction stmt,
515 : : we skip DEF_STMT cause it had already been processed.
516 : : - case 3: If DEF_STMT and STMT_VINFO are in different nests, then
517 : : "relevant" will be modified accordingly.
518 : :
519 : : Return true if everything is as expected. Return false otherwise. */
520 : :
521 : : static opt_result
522 : 3241614 : process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
523 : : enum vect_relevant relevant, vec<stmt_vec_info> *worklist,
524 : : bool force)
525 : : {
526 : 3241614 : stmt_vec_info dstmt_vinfo;
527 : 3241614 : enum vect_def_type dt;
528 : :
529 : : /* case 1: we are only interested in uses that need to be vectorized. Uses
530 : : that are used for address computation are not considered relevant. */
531 : 3241614 : if (!force && !exist_non_indexing_operands_for_use_p (use, stmt_vinfo))
532 : 797479 : return opt_result::success ();
533 : :
534 : 2444135 : if (!vect_is_simple_use (use, loop_vinfo, &dt, &dstmt_vinfo))
535 : 10473 : return opt_result::failure_at (stmt_vinfo->stmt,
536 : : "not vectorized:"
537 : : " unsupported use in stmt.\n");
538 : :
539 : 2433662 : if (!dstmt_vinfo)
540 : 514494 : return opt_result::success ();
541 : :
542 : 1919168 : basic_block def_bb = gimple_bb (dstmt_vinfo->stmt);
543 : 1919168 : basic_block bb = gimple_bb (stmt_vinfo->stmt);
544 : :
545 : : /* case 2: A reduction phi (STMT) defined by a reduction stmt (DSTMT_VINFO).
546 : : We have to force the stmt live since the epilogue loop needs it to
547 : : continue computing the reduction. */
548 : 1919168 : if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI
549 : 315469 : && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
550 : 65850 : && gimple_code (dstmt_vinfo->stmt) != GIMPLE_PHI
551 : 65850 : && STMT_VINFO_DEF_TYPE (dstmt_vinfo) == vect_reduction_def
552 : 1985018 : && bb->loop_father == def_bb->loop_father)
553 : : {
554 : 65850 : if (dump_enabled_p ())
555 : 3546 : dump_printf_loc (MSG_NOTE, vect_location,
556 : : "reduc-stmt defining reduc-phi in the same nest.\n");
557 : 65850 : vect_mark_relevant (worklist, dstmt_vinfo, relevant, true);
558 : 65850 : return opt_result::success ();
559 : : }
560 : :
561 : : /* case 3a: outer-loop stmt defining an inner-loop stmt:
562 : : outer-loop-header-bb:
563 : : d = dstmt_vinfo
564 : : inner-loop:
565 : : stmt # use (d)
566 : : outer-loop-tail-bb:
567 : : ... */
568 : 1853318 : if (flow_loop_nested_p (def_bb->loop_father, bb->loop_father))
569 : : {
570 : 1961 : if (dump_enabled_p ())
571 : 253 : dump_printf_loc (MSG_NOTE, vect_location,
572 : : "outer-loop def-stmt defining inner-loop stmt.\n");
573 : :
574 : 1961 : switch (relevant)
575 : : {
576 : 0 : case vect_unused_in_scope:
577 : 0 : relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_nested_cycle) ?
578 : : vect_used_in_scope : vect_unused_in_scope;
579 : : break;
580 : :
581 : 521 : case vect_used_in_outer_by_reduction:
582 : 521 : gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def);
583 : : relevant = vect_used_by_reduction;
584 : : break;
585 : :
586 : 1224 : case vect_used_in_outer:
587 : 1224 : gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def);
588 : : relevant = vect_used_in_scope;
589 : : break;
590 : :
591 : : case vect_used_in_scope:
592 : : break;
593 : :
594 : 0 : default:
595 : 0 : gcc_unreachable ();
596 : : }
597 : : }
598 : :
599 : : /* case 3b: inner-loop stmt defining an outer-loop stmt:
600 : : outer-loop-header-bb:
601 : : ...
602 : : inner-loop:
603 : : d = dstmt_vinfo
604 : : outer-loop-tail-bb (or outer-loop-exit-bb in double reduction):
605 : : stmt # use (d) */
606 : 1851357 : else if (flow_loop_nested_p (bb->loop_father, def_bb->loop_father))
607 : : {
608 : 1590 : if (dump_enabled_p ())
609 : 492 : dump_printf_loc (MSG_NOTE, vect_location,
610 : : "inner-loop def-stmt defining outer-loop stmt.\n");
611 : :
612 : 1590 : switch (relevant)
613 : : {
614 : 0 : case vect_unused_in_scope:
615 : 0 : relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
616 : 0 : || STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_double_reduction_def) ?
617 : : vect_used_in_outer_by_reduction : vect_unused_in_scope;
618 : : break;
619 : :
620 : : case vect_used_by_reduction:
621 : : case vect_used_only_live:
622 : : relevant = vect_used_in_outer_by_reduction;
623 : : break;
624 : :
625 : : case vect_used_in_scope:
626 : 1801451 : relevant = vect_used_in_outer;
627 : : break;
628 : :
629 : 0 : default:
630 : 0 : gcc_unreachable ();
631 : : }
632 : : }
633 : : /* We are also not interested in uses on loop PHI backedges that are
634 : : inductions. Otherwise we'll needlessly vectorize the IV increment
635 : : and cause hybrid SLP for SLP inductions. Unless the PHI is live
636 : : of course. */
637 : 1849767 : else if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI
638 : 246864 : && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_induction_def
639 : 243508 : && ! STMT_VINFO_LIVE_P (stmt_vinfo)
640 : 1901634 : && (PHI_ARG_DEF_FROM_EDGE (stmt_vinfo->stmt,
641 : : loop_latch_edge (bb->loop_father))
642 : : == use))
643 : : {
644 : 51867 : if (dump_enabled_p ())
645 : 3597 : dump_printf_loc (MSG_NOTE, vect_location,
646 : : "induction value on backedge.\n");
647 : 51867 : return opt_result::success ();
648 : : }
649 : :
650 : :
651 : 1801451 : vect_mark_relevant (worklist, dstmt_vinfo, relevant, false);
652 : 1801451 : return opt_result::success ();
653 : : }
654 : :
655 : :
656 : : /* Function vect_mark_stmts_to_be_vectorized.
657 : :
658 : : Not all stmts in the loop need to be vectorized. For example:
659 : :
660 : : for i...
661 : : for j...
662 : : 1. T0 = i + j
663 : : 2. T1 = a[T0]
664 : :
665 : : 3. j = j + 1
666 : :
667 : : Stmt 1 and 3 do not need to be vectorized, because loop control and
668 : : addressing of vectorized data-refs are handled differently.
669 : :
670 : : This pass detects such stmts. */
671 : :
672 : : opt_result
673 : 279864 : vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo, bool *fatal)
674 : : {
675 : 279864 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
676 : 279864 : basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
677 : 279864 : unsigned int nbbs = loop->num_nodes;
678 : 279864 : gimple_stmt_iterator si;
679 : 279864 : unsigned int i;
680 : 279864 : basic_block bb;
681 : 279864 : bool live_p;
682 : 279864 : enum vect_relevant relevant;
683 : :
684 : 279864 : DUMP_VECT_SCOPE ("vect_mark_stmts_to_be_vectorized");
685 : :
686 : 279864 : auto_vec<stmt_vec_info, 64> worklist;
687 : :
688 : : /* 1. Init worklist. */
689 : 963997 : for (i = 0; i < nbbs; i++)
690 : : {
691 : 684133 : bb = bbs[i];
692 : 1414939 : for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
693 : : {
694 : 730806 : stmt_vec_info phi_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
695 : 730806 : if (dump_enabled_p ())
696 : 54224 : dump_printf_loc (MSG_NOTE, vect_location, "init: phi relevant? %G",
697 : : phi_info->stmt);
698 : :
699 : 730806 : if (vect_stmt_relevant_p (phi_info, loop_vinfo, &relevant, &live_p))
700 : 170378 : vect_mark_relevant (&worklist, phi_info, relevant, live_p);
701 : : }
702 : 5232345 : for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
703 : : {
704 : 3864079 : if (is_gimple_debug (gsi_stmt (si)))
705 : 1048548 : continue;
706 : 2815531 : stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
707 : 2815531 : if (dump_enabled_p ())
708 : 213138 : dump_printf_loc (MSG_NOTE, vect_location,
709 : : "init: stmt relevant? %G", stmt_info->stmt);
710 : :
711 : 2815531 : if (vect_stmt_relevant_p (stmt_info, loop_vinfo, &relevant, &live_p))
712 : 488617 : vect_mark_relevant (&worklist, stmt_info, relevant, live_p);
713 : : }
714 : : }
715 : :
716 : : /* 2. Process_worklist */
717 : 2339017 : while (worklist.length () > 0)
718 : : {
719 : 2069626 : use_operand_p use_p;
720 : 2069626 : ssa_op_iter iter;
721 : :
722 : 2069626 : stmt_vec_info stmt_vinfo = worklist.pop ();
723 : 2069626 : if (dump_enabled_p ())
724 : 141320 : dump_printf_loc (MSG_NOTE, vect_location,
725 : : "worklist: examine stmt: %G", stmt_vinfo->stmt);
726 : :
727 : : /* Examine the USEs of STMT. For each USE, mark the stmt that defines it
728 : : (DEF_STMT) as relevant/irrelevant according to the relevance property
729 : : of STMT. */
730 : 2069626 : relevant = STMT_VINFO_RELEVANT (stmt_vinfo);
731 : :
732 : : /* Generally, the relevance property of STMT (in STMT_VINFO_RELEVANT) is
733 : : propagated as is to the DEF_STMTs of its USEs.
734 : :
735 : : One exception is when STMT has been identified as defining a reduction
736 : : variable; in this case we set the relevance to vect_used_by_reduction.
737 : : This is because we distinguish between two kinds of relevant stmts -
738 : : those that are used by a reduction computation, and those that are
739 : : (also) used by a regular computation. This allows us later on to
740 : : identify stmts that are used solely by a reduction, and therefore the
741 : : order of the results that they produce does not have to be kept. */
742 : :
743 : 2069626 : switch (STMT_VINFO_DEF_TYPE (stmt_vinfo))
744 : : {
745 : 132264 : case vect_reduction_def:
746 : 132264 : gcc_assert (relevant != vect_unused_in_scope);
747 : 132264 : if (relevant != vect_unused_in_scope
748 : 132264 : && relevant != vect_used_in_scope
749 : 132264 : && relevant != vect_used_by_reduction
750 : 132264 : && relevant != vect_used_only_live)
751 : 0 : return opt_result::failure_at
752 : 0 : (stmt_vinfo->stmt, "unsupported use of reduction.\n");
753 : : break;
754 : :
755 : 1835 : case vect_nested_cycle:
756 : 1835 : if (relevant != vect_unused_in_scope
757 : 1835 : && relevant != vect_used_in_outer_by_reduction
758 : 1455 : && relevant != vect_used_in_outer)
759 : 0 : return opt_result::failure_at
760 : 0 : (stmt_vinfo->stmt, "unsupported use of nested cycle.\n");
761 : : break;
762 : :
763 : 787 : case vect_double_reduction_def:
764 : 787 : if (relevant != vect_unused_in_scope
765 : 787 : && relevant != vect_used_by_reduction
766 : 279 : && relevant != vect_used_only_live)
767 : 0 : return opt_result::failure_at
768 : 0 : (stmt_vinfo->stmt, "unsupported use of double reduction.\n");
769 : : break;
770 : :
771 : : default:
772 : : break;
773 : : }
774 : :
775 : 2069626 : if (is_pattern_stmt_p (stmt_vinfo))
776 : : {
777 : : /* Pattern statements are not inserted into the code, so
778 : : FOR_EACH_PHI_OR_STMT_USE optimizes their operands out, and we
779 : : have to scan the RHS or function arguments instead. */
780 : 328615 : if (gassign *assign = dyn_cast <gassign *> (stmt_vinfo->stmt))
781 : : {
782 : 214154 : enum tree_code rhs_code = gimple_assign_rhs_code (assign);
783 : 214154 : tree op = gimple_assign_rhs1 (assign);
784 : :
785 : 214154 : i = 1;
786 : 214154 : if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op))
787 : : {
788 : 6773 : opt_result res
789 : 6773 : = process_use (stmt_vinfo, TREE_OPERAND (op, 0),
790 : : loop_vinfo, relevant, &worklist, false);
791 : 6773 : if (!res)
792 : 4 : return res;
793 : 6769 : res = process_use (stmt_vinfo, TREE_OPERAND (op, 1),
794 : : loop_vinfo, relevant, &worklist, false);
795 : 6769 : if (!res)
796 : 0 : return res;
797 : : i = 2;
798 : : }
799 : 609867 : for (; i < gimple_num_ops (assign); i++)
800 : : {
801 : 397135 : op = gimple_op (assign, i);
802 : 397135 : if (TREE_CODE (op) == SSA_NAME)
803 : : {
804 : 302593 : opt_result res
805 : 302593 : = process_use (stmt_vinfo, op, loop_vinfo, relevant,
806 : : &worklist, false);
807 : 302593 : if (!res)
808 : 1418 : return res;
809 : : }
810 : : }
811 : : }
812 : 114461 : else if (gcond *cond = dyn_cast <gcond *> (stmt_vinfo->stmt))
813 : : {
814 : 110414 : tree_code rhs_code = gimple_cond_code (cond);
815 : 110414 : gcc_assert (TREE_CODE_CLASS (rhs_code) == tcc_comparison);
816 : 110414 : opt_result res
817 : 110414 : = process_use (stmt_vinfo, gimple_cond_lhs (cond),
818 : : loop_vinfo, relevant, &worklist, false);
819 : 110414 : if (!res)
820 : 10473 : return res;
821 : 110414 : res = process_use (stmt_vinfo, gimple_cond_rhs (cond),
822 : : loop_vinfo, relevant, &worklist, false);
823 : 110414 : if (!res)
824 : 0 : return res;
825 : : }
826 : 4047 : else if (gcall *call = dyn_cast <gcall *> (stmt_vinfo->stmt))
827 : : {
828 : 18410 : for (i = 0; i < gimple_call_num_args (call); i++)
829 : : {
830 : 14363 : tree arg = gimple_call_arg (call, i);
831 : 14363 : opt_result res
832 : 14363 : = process_use (stmt_vinfo, arg, loop_vinfo, relevant,
833 : : &worklist, false);
834 : 14363 : if (!res)
835 : 0 : return res;
836 : : }
837 : : }
838 : : else
839 : 0 : gcc_unreachable ();
840 : : }
841 : : else
842 : 6137919 : FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE)
843 : : {
844 : 2663964 : tree op = USE_FROM_PTR (use_p);
845 : 2663964 : opt_result res
846 : 2663964 : = process_use (stmt_vinfo, op, loop_vinfo, relevant,
847 : : &worklist, false);
848 : 2663964 : if (!res)
849 : 8067 : return res;
850 : : }
851 : :
852 : 2060137 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo))
853 : : {
854 : 26324 : gather_scatter_info gs_info;
855 : 26324 : if (!vect_check_gather_scatter (stmt_vinfo, loop_vinfo, &gs_info))
856 : 0 : gcc_unreachable ();
857 : 26324 : opt_result res
858 : 26324 : = process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
859 : : &worklist, true);
860 : 26324 : if (!res)
861 : : {
862 : 984 : if (fatal)
863 : 984 : *fatal = false;
864 : 984 : return res;
865 : : }
866 : : }
867 : : } /* while worklist */
868 : :
869 : 269391 : return opt_result::success ();
870 : 279864 : }
871 : :
872 : : /* Function vect_model_simple_cost.
873 : :
874 : : Models cost for simple operations, i.e. those that only emit ncopies of a
875 : : single op. Right now, this does not account for multiple insns that could
876 : : be generated for the single vector op. We will handle that shortly. */
877 : :
878 : : static void
879 : 474370 : vect_model_simple_cost (vec_info *,
880 : : stmt_vec_info stmt_info, int ncopies,
881 : : enum vect_def_type *dt,
882 : : int ndts,
883 : : slp_tree node,
884 : : stmt_vector_for_cost *cost_vec,
885 : : vect_cost_for_stmt kind = vector_stmt)
886 : : {
887 : 474370 : int inside_cost = 0, prologue_cost = 0;
888 : :
889 : 474370 : gcc_assert (cost_vec != NULL);
890 : :
891 : : /* ??? Somehow we need to fix this at the callers. */
892 : 474370 : if (node)
893 : 227707 : ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (node);
894 : :
895 : 227707 : if (!node)
896 : : /* Cost the "broadcast" of a scalar operand in to a vector operand.
897 : : Use scalar_to_vec to cost the broadcast, as elsewhere in the vector
898 : : cost model. */
899 : 940464 : for (int i = 0; i < ndts; i++)
900 : 693801 : if (dt[i] == vect_constant_def || dt[i] == vect_external_def)
901 : 106837 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
902 : : stmt_info, 0, vect_prologue);
903 : :
904 : : /* Pass the inside-of-loop statements to the target-specific cost model. */
905 : 474370 : inside_cost += record_stmt_cost (cost_vec, ncopies, kind,
906 : : stmt_info, 0, vect_body);
907 : :
908 : 474370 : if (dump_enabled_p ())
909 : 30410 : dump_printf_loc (MSG_NOTE, vect_location,
910 : : "vect_model_simple_cost: inside_cost = %d, "
911 : : "prologue_cost = %d .\n", inside_cost, prologue_cost);
912 : 474370 : }
913 : :
914 : :
915 : : /* Model cost for type demotion and promotion operations. PWR is
916 : : normally zero for single-step promotions and demotions. It will be
917 : : one if two-step promotion/demotion is required, and so on. NCOPIES
918 : : is the number of vector results (and thus number of instructions)
919 : : for the narrowest end of the operation chain. Each additional
920 : : step doubles the number of instructions required. If WIDEN_ARITH
921 : : is true the stmt is doing widening arithmetic. */
922 : :
923 : : static void
924 : 34807 : vect_model_promotion_demotion_cost (stmt_vec_info stmt_info,
925 : : enum vect_def_type *dt,
926 : : unsigned int ncopies, int pwr,
927 : : stmt_vector_for_cost *cost_vec,
928 : : bool widen_arith)
929 : : {
930 : 34807 : int i;
931 : 34807 : int inside_cost = 0, prologue_cost = 0;
932 : :
933 : 80255 : for (i = 0; i < pwr + 1; i++)
934 : : {
935 : 89669 : inside_cost += record_stmt_cost (cost_vec, ncopies,
936 : : widen_arith
937 : : ? vector_stmt : vec_promote_demote,
938 : : stmt_info, 0, vect_body);
939 : 45448 : ncopies *= 2;
940 : : }
941 : :
942 : : /* FORNOW: Assuming maximum 2 args per stmts. */
943 : 104421 : for (i = 0; i < 2; i++)
944 : 69614 : if (dt[i] == vect_constant_def || dt[i] == vect_external_def)
945 : 1805 : prologue_cost += record_stmt_cost (cost_vec, 1, vector_stmt,
946 : : stmt_info, 0, vect_prologue);
947 : :
948 : 34807 : if (dump_enabled_p ())
949 : 6196 : dump_printf_loc (MSG_NOTE, vect_location,
950 : : "vect_model_promotion_demotion_cost: inside_cost = %d, "
951 : : "prologue_cost = %d .\n", inside_cost, prologue_cost);
952 : 34807 : }
953 : :
954 : : /* Returns true if the current function returns DECL. */
955 : :
956 : : static bool
957 : 495207 : cfun_returns (tree decl)
958 : : {
959 : 495207 : edge_iterator ei;
960 : 495207 : edge e;
961 : 961537 : FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
962 : : {
963 : 980242 : greturn *ret = safe_dyn_cast <greturn *> (*gsi_last_bb (e->src));
964 : 490121 : if (!ret)
965 : 0 : continue;
966 : 490121 : if (gimple_return_retval (ret) == decl)
967 : : return true;
968 : : /* We often end up with an aggregate copy to the result decl,
969 : : handle that case as well. First skip intermediate clobbers
970 : : though. */
971 : : gimple *def = ret;
972 : 1380832 : do
973 : : {
974 : 2761664 : def = SSA_NAME_DEF_STMT (gimple_vuse (def));
975 : : }
976 : 1380832 : while (gimple_clobber_p (def));
977 : 466733 : if (is_a <gassign *> (def)
978 : 61127 : && gimple_assign_lhs (def) == gimple_return_retval (ret)
979 : 469547 : && gimple_assign_rhs1 (def) == decl)
980 : : return true;
981 : : }
982 : : return false;
983 : : }
984 : :
985 : : /* Calculate cost of DR's memory access. */
986 : : void
987 : 823294 : vect_get_store_cost (vec_info *, stmt_vec_info stmt_info, int ncopies,
988 : : dr_alignment_support alignment_support_scheme,
989 : : int misalignment,
990 : : unsigned int *inside_cost,
991 : : stmt_vector_for_cost *body_cost_vec)
992 : : {
993 : 823294 : switch (alignment_support_scheme)
994 : : {
995 : 437028 : case dr_aligned:
996 : 437028 : {
997 : 437028 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
998 : : vector_store, stmt_info, 0,
999 : : vect_body);
1000 : :
1001 : 437028 : if (dump_enabled_p ())
1002 : 13057 : dump_printf_loc (MSG_NOTE, vect_location,
1003 : : "vect_model_store_cost: aligned.\n");
1004 : : break;
1005 : : }
1006 : :
1007 : 386266 : case dr_unaligned_supported:
1008 : 386266 : {
1009 : : /* Here, we assign an additional cost for the unaligned store. */
1010 : 386266 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1011 : : unaligned_store, stmt_info,
1012 : : misalignment, vect_body);
1013 : 386266 : if (dump_enabled_p ())
1014 : 11446 : dump_printf_loc (MSG_NOTE, vect_location,
1015 : : "vect_model_store_cost: unaligned supported by "
1016 : : "hardware.\n");
1017 : : break;
1018 : : }
1019 : :
1020 : 0 : case dr_unaligned_unsupported:
1021 : 0 : {
1022 : 0 : *inside_cost = VECT_MAX_COST;
1023 : :
1024 : 0 : if (dump_enabled_p ())
1025 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1026 : : "vect_model_store_cost: unsupported access.\n");
1027 : : break;
1028 : : }
1029 : :
1030 : 0 : default:
1031 : 0 : gcc_unreachable ();
1032 : : }
1033 : 823294 : }
1034 : :
1035 : : /* Calculate cost of DR's memory access. */
1036 : : void
1037 : 475421 : vect_get_load_cost (vec_info *, stmt_vec_info stmt_info, int ncopies,
1038 : : dr_alignment_support alignment_support_scheme,
1039 : : int misalignment,
1040 : : bool add_realign_cost, unsigned int *inside_cost,
1041 : : unsigned int *prologue_cost,
1042 : : stmt_vector_for_cost *prologue_cost_vec,
1043 : : stmt_vector_for_cost *body_cost_vec,
1044 : : bool record_prologue_costs)
1045 : : {
1046 : 475421 : switch (alignment_support_scheme)
1047 : : {
1048 : 235637 : case dr_aligned:
1049 : 235637 : {
1050 : 235637 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load,
1051 : : stmt_info, 0, vect_body);
1052 : :
1053 : 235637 : if (dump_enabled_p ())
1054 : 14463 : dump_printf_loc (MSG_NOTE, vect_location,
1055 : : "vect_model_load_cost: aligned.\n");
1056 : :
1057 : : break;
1058 : : }
1059 : 239784 : case dr_unaligned_supported:
1060 : 239784 : {
1061 : : /* Here, we assign an additional cost for the unaligned load. */
1062 : 239784 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1063 : : unaligned_load, stmt_info,
1064 : : misalignment, vect_body);
1065 : :
1066 : 239784 : if (dump_enabled_p ())
1067 : 18971 : dump_printf_loc (MSG_NOTE, vect_location,
1068 : : "vect_model_load_cost: unaligned supported by "
1069 : : "hardware.\n");
1070 : :
1071 : : break;
1072 : : }
1073 : 0 : case dr_explicit_realign:
1074 : 0 : {
1075 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies * 2,
1076 : : vector_load, stmt_info, 0, vect_body);
1077 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1078 : : vec_perm, stmt_info, 0, vect_body);
1079 : :
1080 : : /* FIXME: If the misalignment remains fixed across the iterations of
1081 : : the containing loop, the following cost should be added to the
1082 : : prologue costs. */
1083 : 0 : if (targetm.vectorize.builtin_mask_for_load)
1084 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, 1, vector_stmt,
1085 : : stmt_info, 0, vect_body);
1086 : :
1087 : 0 : if (dump_enabled_p ())
1088 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1089 : : "vect_model_load_cost: explicit realign\n");
1090 : :
1091 : : break;
1092 : : }
1093 : 0 : case dr_explicit_realign_optimized:
1094 : 0 : {
1095 : 0 : if (dump_enabled_p ())
1096 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1097 : : "vect_model_load_cost: unaligned software "
1098 : : "pipelined.\n");
1099 : :
1100 : : /* Unaligned software pipeline has a load of an address, an initial
1101 : : load, and possibly a mask operation to "prime" the loop. However,
1102 : : if this is an access in a group of loads, which provide grouped
1103 : : access, then the above cost should only be considered for one
1104 : : access in the group. Inside the loop, there is a load op
1105 : : and a realignment op. */
1106 : :
1107 : 0 : if (add_realign_cost && record_prologue_costs)
1108 : : {
1109 : 0 : *prologue_cost += record_stmt_cost (prologue_cost_vec, 2,
1110 : : vector_stmt, stmt_info,
1111 : : 0, vect_prologue);
1112 : 0 : if (targetm.vectorize.builtin_mask_for_load)
1113 : 0 : *prologue_cost += record_stmt_cost (prologue_cost_vec, 1,
1114 : : vector_stmt, stmt_info,
1115 : : 0, vect_prologue);
1116 : : }
1117 : :
1118 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load,
1119 : : stmt_info, 0, vect_body);
1120 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vec_perm,
1121 : : stmt_info, 0, vect_body);
1122 : :
1123 : 0 : if (dump_enabled_p ())
1124 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1125 : : "vect_model_load_cost: explicit realign optimized"
1126 : : "\n");
1127 : :
1128 : : break;
1129 : : }
1130 : :
1131 : 0 : case dr_unaligned_unsupported:
1132 : 0 : {
1133 : 0 : *inside_cost = VECT_MAX_COST;
1134 : :
1135 : 0 : if (dump_enabled_p ())
1136 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1137 : : "vect_model_load_cost: unsupported access.\n");
1138 : : break;
1139 : : }
1140 : :
1141 : 0 : default:
1142 : 0 : gcc_unreachable ();
1143 : : }
1144 : 475421 : }
1145 : :
1146 : : /* Insert the new stmt NEW_STMT at *GSI or at the appropriate place in
1147 : : the loop preheader for the vectorized stmt STMT_VINFO. */
1148 : :
1149 : : static void
1150 : 70568 : vect_init_vector_1 (vec_info *vinfo, stmt_vec_info stmt_vinfo, gimple *new_stmt,
1151 : : gimple_stmt_iterator *gsi)
1152 : : {
1153 : 70568 : if (gsi)
1154 : 3339 : vect_finish_stmt_generation (vinfo, stmt_vinfo, new_stmt, gsi);
1155 : : else
1156 : 67229 : vinfo->insert_on_entry (stmt_vinfo, new_stmt);
1157 : :
1158 : 70568 : if (dump_enabled_p ())
1159 : 15647 : dump_printf_loc (MSG_NOTE, vect_location,
1160 : : "created new init_stmt: %G", new_stmt);
1161 : 70568 : }
1162 : :
1163 : : /* Function vect_init_vector.
1164 : :
1165 : : Insert a new stmt (INIT_STMT) that initializes a new variable of type
1166 : : TYPE with the value VAL. If TYPE is a vector type and VAL does not have
1167 : : vector type a vector with all elements equal to VAL is created first.
1168 : : Place the initialization at GSI if it is not NULL. Otherwise, place the
1169 : : initialization at the loop preheader.
1170 : : Return the DEF of INIT_STMT.
1171 : : It will be used in the vectorization of STMT_INFO. */
1172 : :
1173 : : tree
1174 : 68102 : vect_init_vector (vec_info *vinfo, stmt_vec_info stmt_info, tree val, tree type,
1175 : : gimple_stmt_iterator *gsi)
1176 : : {
1177 : 68102 : gimple *init_stmt;
1178 : 68102 : tree new_temp;
1179 : :
1180 : : /* We abuse this function to push sth to a SSA name with initial 'val'. */
1181 : 68102 : if (! useless_type_conversion_p (type, TREE_TYPE (val)))
1182 : : {
1183 : 49450 : gcc_assert (VECTOR_TYPE_P (type));
1184 : 49450 : if (! types_compatible_p (TREE_TYPE (type), TREE_TYPE (val)))
1185 : : {
1186 : : /* Scalar boolean value should be transformed into
1187 : : all zeros or all ones value before building a vector. */
1188 : 2226 : if (VECTOR_BOOLEAN_TYPE_P (type))
1189 : : {
1190 : 1845 : tree true_val = build_all_ones_cst (TREE_TYPE (type));
1191 : 1845 : tree false_val = build_zero_cst (TREE_TYPE (type));
1192 : :
1193 : 1845 : if (CONSTANT_CLASS_P (val))
1194 : 1401 : val = integer_zerop (val) ? false_val : true_val;
1195 : : else
1196 : : {
1197 : 444 : new_temp = make_ssa_name (TREE_TYPE (type));
1198 : 444 : init_stmt = gimple_build_assign (new_temp, COND_EXPR,
1199 : : val, true_val, false_val);
1200 : 444 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1201 : 444 : val = new_temp;
1202 : : }
1203 : : }
1204 : : else
1205 : : {
1206 : 381 : gimple_seq stmts = NULL;
1207 : 381 : if (! INTEGRAL_TYPE_P (TREE_TYPE (val)))
1208 : 323 : val = gimple_build (&stmts, VIEW_CONVERT_EXPR,
1209 : 323 : TREE_TYPE (type), val);
1210 : : else
1211 : : /* ??? Condition vectorization expects us to do
1212 : : promotion of invariant/external defs. */
1213 : 58 : val = gimple_convert (&stmts, TREE_TYPE (type), val);
1214 : 677 : for (gimple_stmt_iterator gsi2 = gsi_start (stmts);
1215 : 677 : !gsi_end_p (gsi2); )
1216 : : {
1217 : 296 : init_stmt = gsi_stmt (gsi2);
1218 : 296 : gsi_remove (&gsi2, false);
1219 : 296 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1220 : : }
1221 : : }
1222 : : }
1223 : 49450 : val = build_vector_from_val (type, val);
1224 : : }
1225 : :
1226 : 68102 : new_temp = vect_get_new_ssa_name (type, vect_simple_var, "cst_");
1227 : 68102 : init_stmt = gimple_build_assign (new_temp, val);
1228 : 68102 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1229 : 68102 : return new_temp;
1230 : : }
1231 : :
1232 : :
1233 : : /* Function vect_get_vec_defs_for_operand.
1234 : :
1235 : : OP is an operand in STMT_VINFO. This function returns a vector of
1236 : : NCOPIES defs that will be used in the vectorized stmts for STMT_VINFO.
1237 : :
1238 : : In the case that OP is an SSA_NAME which is defined in the loop, then
1239 : : STMT_VINFO_VEC_STMTS of the defining stmt holds the relevant defs.
1240 : :
1241 : : In case OP is an invariant or constant, a new stmt that creates a vector def
1242 : : needs to be introduced. VECTYPE may be used to specify a required type for
1243 : : vector invariant. */
1244 : :
1245 : : void
1246 : 283737 : vect_get_vec_defs_for_operand (vec_info *vinfo, stmt_vec_info stmt_vinfo,
1247 : : unsigned ncopies,
1248 : : tree op, vec<tree> *vec_oprnds, tree vectype)
1249 : : {
1250 : 283737 : gimple *def_stmt;
1251 : 283737 : enum vect_def_type dt;
1252 : 283737 : bool is_simple_use;
1253 : 283737 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
1254 : :
1255 : 283737 : if (dump_enabled_p ())
1256 : 54526 : dump_printf_loc (MSG_NOTE, vect_location,
1257 : : "vect_get_vec_defs_for_operand: %T\n", op);
1258 : :
1259 : 283737 : stmt_vec_info def_stmt_info;
1260 : 283737 : is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt,
1261 : : &def_stmt_info, &def_stmt);
1262 : 283737 : gcc_assert (is_simple_use);
1263 : 283737 : if (def_stmt && dump_enabled_p ())
1264 : 44890 : dump_printf_loc (MSG_NOTE, vect_location, " def_stmt = %G", def_stmt);
1265 : :
1266 : 283737 : vec_oprnds->create (ncopies);
1267 : 283737 : if (dt == vect_constant_def || dt == vect_external_def)
1268 : : {
1269 : 48701 : tree stmt_vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
1270 : 48701 : tree vector_type;
1271 : :
1272 : 48701 : if (vectype)
1273 : : vector_type = vectype;
1274 : 72266 : else if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op))
1275 : 36315 : && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
1276 : 330 : vector_type = truth_type_for (stmt_vectype);
1277 : : else
1278 : 35985 : vector_type = get_vectype_for_scalar_type (loop_vinfo, TREE_TYPE (op));
1279 : :
1280 : 36315 : gcc_assert (vector_type);
1281 : 48701 : tree vop = vect_init_vector (vinfo, stmt_vinfo, op, vector_type, NULL);
1282 : 109556 : while (ncopies--)
1283 : 60855 : vec_oprnds->quick_push (vop);
1284 : : }
1285 : : else
1286 : : {
1287 : 235036 : def_stmt_info = vect_stmt_to_vectorize (def_stmt_info);
1288 : 470072 : gcc_assert (STMT_VINFO_VEC_STMTS (def_stmt_info).length () == ncopies);
1289 : 509008 : for (unsigned i = 0; i < ncopies; ++i)
1290 : 547944 : vec_oprnds->quick_push (gimple_get_lhs
1291 : 273972 : (STMT_VINFO_VEC_STMTS (def_stmt_info)[i]));
1292 : : }
1293 : 283737 : }
1294 : :
1295 : :
1296 : : /* Get vectorized definitions for OP0 and OP1. */
1297 : :
1298 : : void
1299 : 659213 : vect_get_vec_defs (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node,
1300 : : unsigned ncopies,
1301 : : tree op0, tree vectype0, vec<tree> *vec_oprnds0,
1302 : : tree op1, tree vectype1, vec<tree> *vec_oprnds1,
1303 : : tree op2, tree vectype2, vec<tree> *vec_oprnds2,
1304 : : tree op3, tree vectype3, vec<tree> *vec_oprnds3)
1305 : : {
1306 : 659213 : if (slp_node)
1307 : : {
1308 : 527831 : if (op0)
1309 : 527831 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_oprnds0);
1310 : 527831 : if (op1)
1311 : 15142 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[1], vec_oprnds1);
1312 : 527831 : if (op2)
1313 : 203 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[2], vec_oprnds2);
1314 : 527831 : if (op3)
1315 : 38 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[3], vec_oprnds3);
1316 : : }
1317 : : else
1318 : : {
1319 : 131382 : if (op0)
1320 : 131126 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
1321 : : op0, vec_oprnds0, vectype0);
1322 : 131382 : if (op1)
1323 : 94155 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
1324 : : op1, vec_oprnds1, vectype1);
1325 : 131382 : if (op2)
1326 : 5690 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
1327 : : op2, vec_oprnds2, vectype2);
1328 : 131382 : if (op3)
1329 : 341 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
1330 : : op3, vec_oprnds3, vectype3);
1331 : : }
1332 : 659213 : }
1333 : :
1334 : : void
1335 : 629472 : vect_get_vec_defs (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node,
1336 : : unsigned ncopies,
1337 : : tree op0, vec<tree> *vec_oprnds0,
1338 : : tree op1, vec<tree> *vec_oprnds1,
1339 : : tree op2, vec<tree> *vec_oprnds2,
1340 : : tree op3, vec<tree> *vec_oprnds3)
1341 : : {
1342 : 629472 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
1343 : : op0, NULL_TREE, vec_oprnds0,
1344 : : op1, NULL_TREE, vec_oprnds1,
1345 : : op2, NULL_TREE, vec_oprnds2,
1346 : : op3, NULL_TREE, vec_oprnds3);
1347 : 629472 : }
1348 : :
1349 : : /* Helper function called by vect_finish_replace_stmt and
1350 : : vect_finish_stmt_generation. Set the location of the new
1351 : : statement and create and return a stmt_vec_info for it. */
1352 : :
1353 : : static void
1354 : 1260277 : vect_finish_stmt_generation_1 (vec_info *,
1355 : : stmt_vec_info stmt_info, gimple *vec_stmt)
1356 : : {
1357 : 1260277 : if (dump_enabled_p ())
1358 : 128120 : dump_printf_loc (MSG_NOTE, vect_location, "add new stmt: %G", vec_stmt);
1359 : :
1360 : 1260277 : if (stmt_info)
1361 : : {
1362 : 1258212 : gimple_set_location (vec_stmt, gimple_location (stmt_info->stmt));
1363 : :
1364 : : /* While EH edges will generally prevent vectorization, stmt might
1365 : : e.g. be in a must-not-throw region. Ensure newly created stmts
1366 : : that could throw are part of the same region. */
1367 : 1258212 : int lp_nr = lookup_stmt_eh_lp (stmt_info->stmt);
1368 : 1258212 : if (lp_nr != 0 && stmt_could_throw_p (cfun, vec_stmt))
1369 : 80 : add_stmt_to_eh_lp (vec_stmt, lp_nr);
1370 : : }
1371 : : else
1372 : 2065 : gcc_assert (!stmt_could_throw_p (cfun, vec_stmt));
1373 : 1260277 : }
1374 : :
1375 : : /* Replace the scalar statement STMT_INFO with a new vector statement VEC_STMT,
1376 : : which sets the same scalar result as STMT_INFO did. Create and return a
1377 : : stmt_vec_info for VEC_STMT. */
1378 : :
1379 : : void
1380 : 641 : vect_finish_replace_stmt (vec_info *vinfo,
1381 : : stmt_vec_info stmt_info, gimple *vec_stmt)
1382 : : {
1383 : 641 : gimple *scalar_stmt = vect_orig_stmt (stmt_info)->stmt;
1384 : 641 : gcc_assert (gimple_get_lhs (scalar_stmt) == gimple_get_lhs (vec_stmt));
1385 : :
1386 : 641 : gimple_stmt_iterator gsi = gsi_for_stmt (scalar_stmt);
1387 : 641 : gsi_replace (&gsi, vec_stmt, true);
1388 : :
1389 : 641 : vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt);
1390 : 641 : }
1391 : :
1392 : : /* Add VEC_STMT to the vectorized implementation of STMT_INFO and insert it
1393 : : before *GSI. Create and return a stmt_vec_info for VEC_STMT. */
1394 : :
1395 : : void
1396 : 1259636 : vect_finish_stmt_generation (vec_info *vinfo,
1397 : : stmt_vec_info stmt_info, gimple *vec_stmt,
1398 : : gimple_stmt_iterator *gsi)
1399 : : {
1400 : 1259636 : gcc_assert (!stmt_info || gimple_code (stmt_info->stmt) != GIMPLE_LABEL);
1401 : :
1402 : 1259636 : if (!gsi_end_p (*gsi)
1403 : 2518993 : && gimple_has_mem_ops (vec_stmt))
1404 : : {
1405 : 1259357 : gimple *at_stmt = gsi_stmt (*gsi);
1406 : 1259357 : tree vuse = gimple_vuse (at_stmt);
1407 : 1253779 : if (vuse && TREE_CODE (vuse) == SSA_NAME)
1408 : : {
1409 : 1079486 : tree vdef = gimple_vdef (at_stmt);
1410 : 1079486 : gimple_set_vuse (vec_stmt, gimple_vuse (at_stmt));
1411 : 1079486 : gimple_set_modified (vec_stmt, true);
1412 : : /* If we have an SSA vuse and insert a store, update virtual
1413 : : SSA form to avoid triggering the renamer. Do so only
1414 : : if we can easily see all uses - which is what almost always
1415 : : happens with the way vectorized stmts are inserted. */
1416 : 746145 : if ((vdef && TREE_CODE (vdef) == SSA_NAME)
1417 : 1825631 : && ((is_gimple_assign (vec_stmt)
1418 : 744679 : && !is_gimple_reg (gimple_assign_lhs (vec_stmt)))
1419 : 66940 : || (is_gimple_call (vec_stmt)
1420 : 1466 : && (!(gimple_call_flags (vec_stmt)
1421 : 1466 : & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
1422 : 1 : || (gimple_call_lhs (vec_stmt)
1423 : 1 : && !is_gimple_reg (gimple_call_lhs (vec_stmt)))))))
1424 : : {
1425 : 680670 : tree new_vdef = copy_ssa_name (vuse, vec_stmt);
1426 : 680670 : gimple_set_vdef (vec_stmt, new_vdef);
1427 : 680670 : SET_USE (gimple_vuse_op (at_stmt), new_vdef);
1428 : : }
1429 : : }
1430 : : }
1431 : 1259636 : gsi_insert_before (gsi, vec_stmt, GSI_SAME_STMT);
1432 : 1259636 : vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt);
1433 : 1259636 : }
1434 : :
1435 : : /* We want to vectorize a call to combined function CFN with function
1436 : : decl FNDECL, using VECTYPE_OUT as the type of the output and VECTYPE_IN
1437 : : as the types of all inputs. Check whether this is possible using
1438 : : an internal function, returning its code if so or IFN_LAST if not. */
1439 : :
1440 : : static internal_fn
1441 : 10738 : vectorizable_internal_function (combined_fn cfn, tree fndecl,
1442 : : tree vectype_out, tree vectype_in)
1443 : : {
1444 : 10738 : internal_fn ifn;
1445 : 10738 : if (internal_fn_p (cfn))
1446 : 9107 : ifn = as_internal_fn (cfn);
1447 : : else
1448 : 1631 : ifn = associated_internal_fn (fndecl);
1449 : 10738 : if (ifn != IFN_LAST && direct_internal_fn_p (ifn))
1450 : : {
1451 : 6998 : const direct_internal_fn_info &info = direct_internal_fn (ifn);
1452 : 6998 : if (info.vectorizable)
1453 : : {
1454 : 6998 : bool same_size_p = TYPE_SIZE (vectype_in) == TYPE_SIZE (vectype_out);
1455 : 6998 : tree type0 = (info.type0 < 0 ? vectype_out : vectype_in);
1456 : 6998 : tree type1 = (info.type1 < 0 ? vectype_out : vectype_in);
1457 : :
1458 : : /* The type size of both the vectype_in and vectype_out should be
1459 : : exactly the same when vectype_out isn't participating the optab.
1460 : : While there is no restriction for type size when vectype_out
1461 : : is part of the optab query. */
1462 : 6998 : if (type0 != vectype_out && type1 != vectype_out && !same_size_p)
1463 : : return IFN_LAST;
1464 : :
1465 : 6983 : if (direct_internal_fn_supported_p (ifn, tree_pair (type0, type1),
1466 : : OPTIMIZE_FOR_SPEED))
1467 : : return ifn;
1468 : : }
1469 : : }
1470 : : return IFN_LAST;
1471 : : }
1472 : :
1473 : :
1474 : : static tree permute_vec_elements (vec_info *, tree, tree, tree, stmt_vec_info,
1475 : : gimple_stmt_iterator *);
1476 : :
1477 : : /* Check whether a load or store statement in the loop described by
1478 : : LOOP_VINFO is possible in a loop using partial vectors. This is
1479 : : testing whether the vectorizer pass has the appropriate support,
1480 : : as well as whether the target does.
1481 : :
1482 : : VLS_TYPE says whether the statement is a load or store and VECTYPE
1483 : : is the type of the vector being loaded or stored. SLP_NODE is the SLP
1484 : : node that contains the statement, or null if none. MEMORY_ACCESS_TYPE
1485 : : says how the load or store is going to be implemented and GROUP_SIZE
1486 : : is the number of load or store statements in the containing group.
1487 : : If the access is a gather load or scatter store, GS_INFO describes
1488 : : its arguments. If the load or store is conditional, SCALAR_MASK is the
1489 : : condition under which it occurs.
1490 : :
1491 : : Clear LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P if a loop using partial
1492 : : vectors is not supported, otherwise record the required rgroup control
1493 : : types. */
1494 : :
1495 : : static void
1496 : 49 : check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype,
1497 : : slp_tree slp_node,
1498 : : vec_load_store_type vls_type,
1499 : : int group_size,
1500 : : vect_memory_access_type
1501 : : memory_access_type,
1502 : : gather_scatter_info *gs_info,
1503 : : tree scalar_mask)
1504 : : {
1505 : : /* Invariant loads need no special support. */
1506 : 49 : if (memory_access_type == VMAT_INVARIANT)
1507 : 0 : return;
1508 : :
1509 : 49 : unsigned int nvectors;
1510 : 49 : if (slp_node)
1511 : 7 : nvectors = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
1512 : : else
1513 : 42 : nvectors = vect_get_num_copies (loop_vinfo, vectype);
1514 : :
1515 : 49 : vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
1516 : 49 : vec_loop_lens *lens = &LOOP_VINFO_LENS (loop_vinfo);
1517 : 49 : machine_mode vecmode = TYPE_MODE (vectype);
1518 : 49 : bool is_load = (vls_type == VLS_LOAD);
1519 : 49 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
1520 : : {
1521 : 0 : internal_fn ifn
1522 : 0 : = (is_load ? vect_load_lanes_supported (vectype, group_size, true)
1523 : 0 : : vect_store_lanes_supported (vectype, group_size, true));
1524 : 0 : if (ifn == IFN_MASK_LEN_LOAD_LANES || ifn == IFN_MASK_LEN_STORE_LANES)
1525 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1);
1526 : 0 : else if (ifn == IFN_MASK_LOAD_LANES || ifn == IFN_MASK_STORE_LANES)
1527 : 0 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
1528 : : scalar_mask);
1529 : : else
1530 : : {
1531 : 0 : if (dump_enabled_p ())
1532 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1533 : : "can't operate on partial vectors because"
1534 : : " the target doesn't have an appropriate"
1535 : : " load/store-lanes instruction.\n");
1536 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1537 : : }
1538 : 0 : return;
1539 : : }
1540 : :
1541 : 49 : if (memory_access_type == VMAT_GATHER_SCATTER)
1542 : : {
1543 : 0 : internal_fn ifn = (is_load
1544 : 0 : ? IFN_MASK_GATHER_LOAD
1545 : : : IFN_MASK_SCATTER_STORE);
1546 : 0 : internal_fn len_ifn = (is_load
1547 : : ? IFN_MASK_LEN_GATHER_LOAD
1548 : : : IFN_MASK_LEN_SCATTER_STORE);
1549 : 0 : if (internal_gather_scatter_fn_supported_p (len_ifn, vectype,
1550 : : gs_info->memory_type,
1551 : : gs_info->offset_vectype,
1552 : : gs_info->scale))
1553 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1);
1554 : 0 : else if (internal_gather_scatter_fn_supported_p (ifn, vectype,
1555 : : gs_info->memory_type,
1556 : : gs_info->offset_vectype,
1557 : : gs_info->scale))
1558 : 0 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
1559 : : scalar_mask);
1560 : : else
1561 : : {
1562 : 0 : if (dump_enabled_p ())
1563 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1564 : : "can't operate on partial vectors because"
1565 : : " the target doesn't have an appropriate"
1566 : : " gather load or scatter store instruction.\n");
1567 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1568 : : }
1569 : 0 : return;
1570 : : }
1571 : :
1572 : 49 : if (memory_access_type != VMAT_CONTIGUOUS
1573 : 49 : && memory_access_type != VMAT_CONTIGUOUS_PERMUTE)
1574 : : {
1575 : : /* Element X of the data must come from iteration i * VF + X of the
1576 : : scalar loop. We need more work to support other mappings. */
1577 : 0 : if (dump_enabled_p ())
1578 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1579 : : "can't operate on partial vectors because an"
1580 : : " access isn't contiguous.\n");
1581 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1582 : 0 : return;
1583 : : }
1584 : :
1585 : 49 : if (!VECTOR_MODE_P (vecmode))
1586 : : {
1587 : 0 : if (dump_enabled_p ())
1588 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1589 : : "can't operate on partial vectors when emulating"
1590 : : " vector operations.\n");
1591 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1592 : 0 : return;
1593 : : }
1594 : :
1595 : : /* We might load more scalars than we need for permuting SLP loads.
1596 : : We checked in get_group_load_store_type that the extra elements
1597 : : don't leak into a new vector. */
1598 : 74 : auto group_memory_nvectors = [](poly_uint64 size, poly_uint64 nunits)
1599 : : {
1600 : 25 : unsigned int nvectors;
1601 : 50 : if (can_div_away_from_zero_p (size, nunits, &nvectors))
1602 : 25 : return nvectors;
1603 : : gcc_unreachable ();
1604 : : };
1605 : :
1606 : 49 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
1607 : 49 : poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
1608 : 49 : machine_mode mask_mode;
1609 : 49 : machine_mode vmode;
1610 : 49 : bool using_partial_vectors_p = false;
1611 : 49 : if (get_len_load_store_mode (vecmode, is_load).exists (&vmode))
1612 : : {
1613 : 0 : nvectors = group_memory_nvectors (group_size * vf, nunits);
1614 : 0 : unsigned factor = (vecmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vecmode);
1615 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, factor);
1616 : 0 : using_partial_vectors_p = true;
1617 : : }
1618 : 74 : else if (targetm.vectorize.get_mask_mode (vecmode).exists (&mask_mode)
1619 : 49 : && can_vec_mask_load_store_p (vecmode, mask_mode, is_load))
1620 : : {
1621 : 25 : nvectors = group_memory_nvectors (group_size * vf, nunits);
1622 : 25 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, scalar_mask);
1623 : 25 : using_partial_vectors_p = true;
1624 : : }
1625 : :
1626 : 25 : if (!using_partial_vectors_p)
1627 : : {
1628 : 24 : if (dump_enabled_p ())
1629 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1630 : : "can't operate on partial vectors because the"
1631 : : " target doesn't have the appropriate partial"
1632 : : " vectorization load or store.\n");
1633 : 24 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1634 : : }
1635 : : }
1636 : :
1637 : : /* Return the mask input to a masked load or store. VEC_MASK is the vectorized
1638 : : form of the scalar mask condition and LOOP_MASK, if nonnull, is the mask
1639 : : that needs to be applied to all loads and stores in a vectorized loop.
1640 : : Return VEC_MASK if LOOP_MASK is null or if VEC_MASK is already masked,
1641 : : otherwise return VEC_MASK & LOOP_MASK.
1642 : :
1643 : : MASK_TYPE is the type of both masks. If new statements are needed,
1644 : : insert them before GSI. */
1645 : :
1646 : : static tree
1647 : 1962 : prepare_vec_mask (loop_vec_info loop_vinfo, tree mask_type, tree loop_mask,
1648 : : tree vec_mask, gimple_stmt_iterator *gsi)
1649 : : {
1650 : 1962 : gcc_assert (useless_type_conversion_p (mask_type, TREE_TYPE (vec_mask)));
1651 : 1962 : if (!loop_mask)
1652 : : return vec_mask;
1653 : :
1654 : 36 : gcc_assert (TREE_TYPE (loop_mask) == mask_type);
1655 : :
1656 : 36 : if (loop_vinfo->vec_cond_masked_set.contains ({ vec_mask, loop_mask }))
1657 : : return vec_mask;
1658 : :
1659 : 36 : tree and_res = make_temp_ssa_name (mask_type, NULL, "vec_mask_and");
1660 : 36 : gimple *and_stmt = gimple_build_assign (and_res, BIT_AND_EXPR,
1661 : : vec_mask, loop_mask);
1662 : :
1663 : 36 : gsi_insert_before (gsi, and_stmt, GSI_SAME_STMT);
1664 : 36 : return and_res;
1665 : : }
1666 : :
1667 : : /* Determine whether we can use a gather load or scatter store to vectorize
1668 : : strided load or store STMT_INFO by truncating the current offset to a
1669 : : smaller width. We need to be able to construct an offset vector:
1670 : :
1671 : : { 0, X, X*2, X*3, ... }
1672 : :
1673 : : without loss of precision, where X is STMT_INFO's DR_STEP.
1674 : :
1675 : : Return true if this is possible, describing the gather load or scatter
1676 : : store in GS_INFO. MASKED_P is true if the load or store is conditional. */
1677 : :
1678 : : static bool
1679 : 27387 : vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info,
1680 : : loop_vec_info loop_vinfo, bool masked_p,
1681 : : gather_scatter_info *gs_info)
1682 : : {
1683 : 27387 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1684 : 27387 : data_reference *dr = dr_info->dr;
1685 : 27387 : tree step = DR_STEP (dr);
1686 : 27387 : if (TREE_CODE (step) != INTEGER_CST)
1687 : : {
1688 : : /* ??? Perhaps we could use range information here? */
1689 : 14050 : if (dump_enabled_p ())
1690 : 247 : dump_printf_loc (MSG_NOTE, vect_location,
1691 : : "cannot truncate variable step.\n");
1692 : 14050 : return false;
1693 : : }
1694 : :
1695 : : /* Get the number of bits in an element. */
1696 : 13337 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
1697 : 13337 : scalar_mode element_mode = SCALAR_TYPE_MODE (TREE_TYPE (vectype));
1698 : 13337 : unsigned int element_bits = GET_MODE_BITSIZE (element_mode);
1699 : :
1700 : : /* Set COUNT to the upper limit on the number of elements - 1.
1701 : : Start with the maximum vectorization factor. */
1702 : 13337 : unsigned HOST_WIDE_INT count = vect_max_vf (loop_vinfo) - 1;
1703 : :
1704 : : /* Try lowering COUNT to the number of scalar latch iterations. */
1705 : 13337 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
1706 : 13337 : widest_int max_iters;
1707 : 13337 : if (max_loop_iterations (loop, &max_iters)
1708 : 26674 : && max_iters < count)
1709 : 2448 : count = max_iters.to_shwi ();
1710 : :
1711 : : /* Try scales of 1 and the element size. */
1712 : 13337 : int scales[] = { 1, vect_get_scalar_dr_size (dr_info) };
1713 : 13337 : wi::overflow_type overflow = wi::OVF_NONE;
1714 : 40011 : for (int i = 0; i < 2; ++i)
1715 : : {
1716 : 26674 : int scale = scales[i];
1717 : 26674 : widest_int factor;
1718 : 26674 : if (!wi::multiple_of_p (wi::to_widest (step), scale, SIGNED, &factor))
1719 : 0 : continue;
1720 : :
1721 : : /* Determine the minimum precision of (COUNT - 1) * STEP / SCALE. */
1722 : 26674 : widest_int range = wi::mul (count, factor, SIGNED, &overflow);
1723 : 26674 : if (overflow)
1724 : 0 : continue;
1725 : 26674 : signop sign = range >= 0 ? UNSIGNED : SIGNED;
1726 : 26674 : unsigned int min_offset_bits = wi::min_precision (range, sign);
1727 : :
1728 : : /* Find the narrowest viable offset type. */
1729 : 26674 : unsigned int offset_bits = 1U << ceil_log2 (min_offset_bits);
1730 : 26674 : tree offset_type = build_nonstandard_integer_type (offset_bits,
1731 : : sign == UNSIGNED);
1732 : :
1733 : : /* See whether the target supports the operation with an offset
1734 : : no narrower than OFFSET_TYPE. */
1735 : 26674 : tree memory_type = TREE_TYPE (DR_REF (dr));
1736 : 26674 : if (!vect_gather_scatter_fn_p (loop_vinfo, DR_IS_READ (dr), masked_p,
1737 : : vectype, memory_type, offset_type, scale,
1738 : : &gs_info->ifn, &gs_info->offset_vectype)
1739 : 26674 : || gs_info->ifn == IFN_LAST)
1740 : 26674 : continue;
1741 : :
1742 : 0 : gs_info->decl = NULL_TREE;
1743 : : /* Logically the sum of DR_BASE_ADDRESS, DR_INIT and DR_OFFSET,
1744 : : but we don't need to store that here. */
1745 : 0 : gs_info->base = NULL_TREE;
1746 : 0 : gs_info->element_type = TREE_TYPE (vectype);
1747 : 0 : gs_info->offset = fold_convert (offset_type, step);
1748 : 0 : gs_info->offset_dt = vect_constant_def;
1749 : 0 : gs_info->scale = scale;
1750 : 0 : gs_info->memory_type = memory_type;
1751 : 0 : return true;
1752 : 53348 : }
1753 : :
1754 : 13337 : if (overflow && dump_enabled_p ())
1755 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1756 : : "truncating gather/scatter offset to %d bits"
1757 : : " might change its value.\n", element_bits);
1758 : :
1759 : : return false;
1760 : 13337 : }
1761 : :
1762 : : /* Return true if we can use gather/scatter internal functions to
1763 : : vectorize STMT_INFO, which is a grouped or strided load or store.
1764 : : MASKED_P is true if load or store is conditional. When returning
1765 : : true, fill in GS_INFO with the information required to perform the
1766 : : operation. */
1767 : :
1768 : : static bool
1769 : 27387 : vect_use_strided_gather_scatters_p (stmt_vec_info stmt_info,
1770 : : loop_vec_info loop_vinfo, bool masked_p,
1771 : : gather_scatter_info *gs_info)
1772 : : {
1773 : 27387 : if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info)
1774 : 27387 : || gs_info->ifn == IFN_LAST)
1775 : 27387 : return vect_truncate_gather_scatter_offset (stmt_info, loop_vinfo,
1776 : 27387 : masked_p, gs_info);
1777 : :
1778 : 0 : tree old_offset_type = TREE_TYPE (gs_info->offset);
1779 : 0 : tree new_offset_type = TREE_TYPE (gs_info->offset_vectype);
1780 : :
1781 : 0 : gcc_assert (TYPE_PRECISION (new_offset_type)
1782 : : >= TYPE_PRECISION (old_offset_type));
1783 : 0 : gs_info->offset = fold_convert (new_offset_type, gs_info->offset);
1784 : :
1785 : 0 : if (dump_enabled_p ())
1786 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1787 : : "using gather/scatter for strided/grouped access,"
1788 : : " scale = %d\n", gs_info->scale);
1789 : :
1790 : : return true;
1791 : : }
1792 : :
1793 : : /* STMT_INFO is a non-strided load or store, meaning that it accesses
1794 : : elements with a known constant step. Return -1 if that step
1795 : : is negative, 0 if it is zero, and 1 if it is greater than zero. */
1796 : :
1797 : : static int
1798 : 1717144 : compare_step_with_zero (vec_info *vinfo, stmt_vec_info stmt_info)
1799 : : {
1800 : 1717144 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1801 : 1717144 : return tree_int_cst_compare (vect_dr_behavior (vinfo, dr_info)->step,
1802 : 1717144 : size_zero_node);
1803 : : }
1804 : :
1805 : : /* If the target supports a permute mask that reverses the elements in
1806 : : a vector of type VECTYPE, return that mask, otherwise return null. */
1807 : :
1808 : : tree
1809 : 9674 : perm_mask_for_reverse (tree vectype)
1810 : : {
1811 : 9674 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
1812 : :
1813 : : /* The encoding has a single stepped pattern. */
1814 : 9674 : vec_perm_builder sel (nunits, 1, 3);
1815 : 38696 : for (int i = 0; i < 3; ++i)
1816 : 29022 : sel.quick_push (nunits - 1 - i);
1817 : :
1818 : 9674 : vec_perm_indices indices (sel, 1, nunits);
1819 : 9674 : if (!can_vec_perm_const_p (TYPE_MODE (vectype), TYPE_MODE (vectype),
1820 : : indices))
1821 : : return NULL_TREE;
1822 : 9379 : return vect_gen_perm_mask_checked (vectype, indices);
1823 : 9674 : }
1824 : :
1825 : : /* A subroutine of get_load_store_type, with a subset of the same
1826 : : arguments. Handle the case where STMT_INFO is a load or store that
1827 : : accesses consecutive elements with a negative step. Sets *POFFSET
1828 : : to the offset to be applied to the DR for the first access. */
1829 : :
1830 : : static vect_memory_access_type
1831 : 8264 : get_negative_load_store_type (vec_info *vinfo,
1832 : : stmt_vec_info stmt_info, tree vectype,
1833 : : vec_load_store_type vls_type,
1834 : : unsigned int ncopies, poly_int64 *poffset)
1835 : : {
1836 : 8264 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1837 : 8264 : dr_alignment_support alignment_support_scheme;
1838 : :
1839 : 8264 : if (ncopies > 1)
1840 : : {
1841 : 49 : if (dump_enabled_p ())
1842 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1843 : : "multiple types with negative step.\n");
1844 : 49 : return VMAT_ELEMENTWISE;
1845 : : }
1846 : :
1847 : : /* For backward running DRs the first access in vectype actually is
1848 : : N-1 elements before the address of the DR. */
1849 : 8215 : *poffset = ((-TYPE_VECTOR_SUBPARTS (vectype) + 1)
1850 : 8215 : * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype))));
1851 : :
1852 : 8215 : int misalignment = dr_misalignment (dr_info, vectype, *poffset);
1853 : 8215 : alignment_support_scheme
1854 : 8215 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype, misalignment);
1855 : 8215 : if (alignment_support_scheme != dr_aligned
1856 : 8215 : && alignment_support_scheme != dr_unaligned_supported)
1857 : : {
1858 : 0 : if (dump_enabled_p ())
1859 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1860 : : "negative step but alignment required.\n");
1861 : 0 : *poffset = 0;
1862 : 0 : return VMAT_ELEMENTWISE;
1863 : : }
1864 : :
1865 : 8215 : if (vls_type == VLS_STORE_INVARIANT)
1866 : : {
1867 : 890 : if (dump_enabled_p ())
1868 : 32 : dump_printf_loc (MSG_NOTE, vect_location,
1869 : : "negative step with invariant source;"
1870 : : " no permute needed.\n");
1871 : 890 : return VMAT_CONTIGUOUS_DOWN;
1872 : : }
1873 : :
1874 : 7325 : if (!perm_mask_for_reverse (vectype))
1875 : : {
1876 : 295 : if (dump_enabled_p ())
1877 : 24 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1878 : : "negative step and reversing not supported.\n");
1879 : 295 : *poffset = 0;
1880 : 295 : return VMAT_ELEMENTWISE;
1881 : : }
1882 : :
1883 : : return VMAT_CONTIGUOUS_REVERSE;
1884 : : }
1885 : :
1886 : : /* STMT_INFO is either a masked or unconditional store. Return the value
1887 : : being stored. */
1888 : :
1889 : : tree
1890 : 4775012 : vect_get_store_rhs (stmt_vec_info stmt_info)
1891 : : {
1892 : 4775012 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
1893 : : {
1894 : 4772483 : gcc_assert (gimple_assign_single_p (assign));
1895 : 4772483 : return gimple_assign_rhs1 (assign);
1896 : : }
1897 : 2529 : if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt))
1898 : : {
1899 : 2529 : internal_fn ifn = gimple_call_internal_fn (call);
1900 : 2529 : int index = internal_fn_stored_value_index (ifn);
1901 : 2529 : gcc_assert (index >= 0);
1902 : 2529 : return gimple_call_arg (call, index);
1903 : : }
1904 : 0 : gcc_unreachable ();
1905 : : }
1906 : :
1907 : : /* Function VECTOR_VECTOR_COMPOSITION_TYPE
1908 : :
1909 : : This function returns a vector type which can be composed with NETLS pieces,
1910 : : whose type is recorded in PTYPE. VTYPE should be a vector type, and has the
1911 : : same vector size as the return vector. It checks target whether supports
1912 : : pieces-size vector mode for construction firstly, if target fails to, check
1913 : : pieces-size scalar mode for construction further. It returns NULL_TREE if
1914 : : fails to find the available composition.
1915 : :
1916 : : For example, for (vtype=V16QI, nelts=4), we can probably get:
1917 : : - V16QI with PTYPE V4QI.
1918 : : - V4SI with PTYPE SI.
1919 : : - NULL_TREE. */
1920 : :
1921 : : static tree
1922 : 2580 : vector_vector_composition_type (tree vtype, poly_uint64 nelts, tree *ptype)
1923 : : {
1924 : 2580 : gcc_assert (VECTOR_TYPE_P (vtype));
1925 : 2580 : gcc_assert (known_gt (nelts, 0U));
1926 : :
1927 : 2580 : machine_mode vmode = TYPE_MODE (vtype);
1928 : 2580 : if (!VECTOR_MODE_P (vmode))
1929 : : return NULL_TREE;
1930 : :
1931 : : /* When we are asked to compose the vector from its components let
1932 : : that happen directly. */
1933 : 2580 : if (known_eq (TYPE_VECTOR_SUBPARTS (vtype), nelts))
1934 : : {
1935 : 291 : *ptype = TREE_TYPE (vtype);
1936 : 291 : return vtype;
1937 : : }
1938 : :
1939 : 4578 : poly_uint64 vbsize = GET_MODE_BITSIZE (vmode);
1940 : 2289 : unsigned int pbsize;
1941 : 2289 : if (constant_multiple_p (vbsize, nelts, &pbsize))
1942 : : {
1943 : : /* First check if vec_init optab supports construction from
1944 : : vector pieces directly. */
1945 : 2289 : scalar_mode elmode = SCALAR_TYPE_MODE (TREE_TYPE (vtype));
1946 : 4578 : poly_uint64 inelts = pbsize / GET_MODE_BITSIZE (elmode);
1947 : 2289 : machine_mode rmode;
1948 : 2289 : if (related_vector_mode (vmode, elmode, inelts).exists (&rmode)
1949 : 1665 : && (convert_optab_handler (vec_init_optab, vmode, rmode)
1950 : : != CODE_FOR_nothing))
1951 : : {
1952 : 1072 : *ptype = build_vector_type (TREE_TYPE (vtype), inelts);
1953 : 1072 : return vtype;
1954 : : }
1955 : :
1956 : : /* Otherwise check if exists an integer type of the same piece size and
1957 : : if vec_init optab supports construction from it directly. */
1958 : 1217 : if (int_mode_for_size (pbsize, 0).exists (&elmode)
1959 : 1217 : && related_vector_mode (vmode, elmode, nelts).exists (&rmode)
1960 : 1139 : && (convert_optab_handler (vec_init_optab, rmode, elmode)
1961 : : != CODE_FOR_nothing))
1962 : : {
1963 : 1139 : *ptype = build_nonstandard_integer_type (pbsize, 1);
1964 : 1139 : return build_vector_type (*ptype, nelts);
1965 : : }
1966 : : }
1967 : :
1968 : : return NULL_TREE;
1969 : : }
1970 : :
1971 : : /* A subroutine of get_load_store_type, with a subset of the same
1972 : : arguments. Handle the case where STMT_INFO is part of a grouped load
1973 : : or store.
1974 : :
1975 : : For stores, the statements in the group are all consecutive
1976 : : and there is no gap at the end. For loads, the statements in the
1977 : : group might not be consecutive; there can be gaps between statements
1978 : : as well as at the end. */
1979 : :
1980 : : static bool
1981 : 1439755 : get_group_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
1982 : : tree vectype, slp_tree slp_node,
1983 : : bool masked_p, vec_load_store_type vls_type,
1984 : : vect_memory_access_type *memory_access_type,
1985 : : poly_int64 *poffset,
1986 : : dr_alignment_support *alignment_support_scheme,
1987 : : int *misalignment,
1988 : : gather_scatter_info *gs_info,
1989 : : internal_fn *lanes_ifn)
1990 : : {
1991 : 1439755 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
1992 : 83347 : class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
1993 : 1439755 : stmt_vec_info first_stmt_info;
1994 : 1439755 : unsigned int group_size;
1995 : 1439755 : unsigned HOST_WIDE_INT gap;
1996 : 1439755 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
1997 : : {
1998 : 1439091 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
1999 : 1439091 : group_size = DR_GROUP_SIZE (first_stmt_info);
2000 : 1439091 : gap = DR_GROUP_GAP (first_stmt_info);
2001 : : }
2002 : : else
2003 : : {
2004 : : first_stmt_info = stmt_info;
2005 : : group_size = 1;
2006 : : gap = 0;
2007 : : }
2008 : 1439755 : dr_vec_info *first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
2009 : 1439755 : bool single_element_p = (stmt_info == first_stmt_info
2010 : 1439755 : && !DR_GROUP_NEXT_ELEMENT (stmt_info));
2011 : 1439755 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
2012 : :
2013 : : /* True if the vectorized statements would access beyond the last
2014 : : statement in the group. */
2015 : 1439755 : bool overrun_p = false;
2016 : :
2017 : : /* True if we can cope with such overrun by peeling for gaps, so that
2018 : : there is at least one final scalar iteration after the vector loop. */
2019 : 2879510 : bool can_overrun_p = (!masked_p
2020 : 1439755 : && vls_type == VLS_LOAD
2021 : 298914 : && loop_vinfo
2022 : 1497515 : && !loop->inner);
2023 : :
2024 : : /* There can only be a gap at the end of the group if the stride is
2025 : : known at compile time. */
2026 : 1439755 : gcc_assert (!STMT_VINFO_STRIDED_P (first_stmt_info) || gap == 0);
2027 : :
2028 : : /* Stores can't yet have gaps. */
2029 : 1439755 : gcc_assert (slp_node || vls_type == VLS_LOAD || gap == 0);
2030 : :
2031 : 1439755 : if (slp_node)
2032 : : {
2033 : : /* For SLP vectorization we directly vectorize a subchain
2034 : : without permutation. */
2035 : 1388281 : if (! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
2036 : 1359036 : first_dr_info
2037 : 1359036 : = STMT_VINFO_DR_INFO (SLP_TREE_SCALAR_STMTS (slp_node)[0]);
2038 : 1388281 : if (STMT_VINFO_STRIDED_P (first_stmt_info))
2039 : : {
2040 : : /* Try to use consecutive accesses of DR_GROUP_SIZE elements,
2041 : : separated by the stride, until we have a complete vector.
2042 : : Fall back to scalar accesses if that isn't possible. */
2043 : 7575 : if (multiple_p (nunits, group_size))
2044 : 6425 : *memory_access_type = VMAT_STRIDED_SLP;
2045 : : else
2046 : 1150 : *memory_access_type = VMAT_ELEMENTWISE;
2047 : : }
2048 : : else
2049 : : {
2050 : 1380706 : overrun_p = loop_vinfo && gap != 0;
2051 : 1380706 : if (overrun_p && vls_type != VLS_LOAD)
2052 : : {
2053 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2054 : : "Grouped store with gaps requires"
2055 : : " non-consecutive accesses\n");
2056 : 62 : return false;
2057 : : }
2058 : : /* An overrun is fine if the trailing elements are smaller
2059 : : than the alignment boundary B. Every vector access will
2060 : : be a multiple of B and so we are guaranteed to access a
2061 : : non-gap element in the same B-sized block. */
2062 : 1380706 : if (overrun_p
2063 : 1380706 : && gap < (vect_known_alignment_in_bytes (first_dr_info,
2064 : : vectype)
2065 : 778 : / vect_get_scalar_dr_size (first_dr_info)))
2066 : : overrun_p = false;
2067 : :
2068 : : /* If the gap splits the vector in half and the target
2069 : : can do half-vector operations avoid the epilogue peeling
2070 : : by simply loading half of the vector only. Usually
2071 : : the construction with an upper zero half will be elided. */
2072 : 1380706 : dr_alignment_support alss;
2073 : 1380706 : int misalign = dr_misalignment (first_dr_info, vectype);
2074 : 1380706 : tree half_vtype;
2075 : 1380706 : if (overrun_p
2076 : 1380706 : && !masked_p
2077 : 692 : && (((alss = vect_supportable_dr_alignment (vinfo, first_dr_info,
2078 : : vectype, misalign)))
2079 : : == dr_aligned
2080 : 581 : || alss == dr_unaligned_supported)
2081 : 692 : && known_eq (nunits, (group_size - gap) * 2)
2082 : 74 : && known_eq (nunits, group_size)
2083 : 1381398 : && (vector_vector_composition_type (vectype, 2, &half_vtype)
2084 : : != NULL_TREE))
2085 : 49 : overrun_p = false;
2086 : :
2087 : 1380706 : if (overrun_p && !can_overrun_p)
2088 : : {
2089 : 4 : if (dump_enabled_p ())
2090 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2091 : : "Peeling for outer loop is not supported\n");
2092 : 4 : return false;
2093 : : }
2094 : 1380702 : int cmp = compare_step_with_zero (vinfo, stmt_info);
2095 : 1380702 : if (cmp < 0)
2096 : : {
2097 : 240 : if (single_element_p)
2098 : : /* ??? The VMAT_CONTIGUOUS_REVERSE code generation is
2099 : : only correct for single element "interleaving" SLP. */
2100 : 34 : *memory_access_type = get_negative_load_store_type
2101 : 34 : (vinfo, stmt_info, vectype, vls_type, 1, poffset);
2102 : : else
2103 : : {
2104 : : /* Try to use consecutive accesses of DR_GROUP_SIZE elements,
2105 : : separated by the stride, until we have a complete vector.
2106 : : Fall back to scalar accesses if that isn't possible. */
2107 : 206 : if (multiple_p (nunits, group_size))
2108 : 189 : *memory_access_type = VMAT_STRIDED_SLP;
2109 : : else
2110 : 17 : *memory_access_type = VMAT_ELEMENTWISE;
2111 : : }
2112 : : }
2113 : 1380462 : else if (cmp == 0 && loop_vinfo)
2114 : : {
2115 : 452 : gcc_assert (vls_type == VLS_LOAD);
2116 : 452 : *memory_access_type = VMAT_INVARIANT;
2117 : : /* Invariant accesses perform only component accesses, alignment
2118 : : is irrelevant for them. */
2119 : 452 : *alignment_support_scheme = dr_unaligned_supported;
2120 : : }
2121 : : else
2122 : 1380010 : *memory_access_type = VMAT_CONTIGUOUS;
2123 : :
2124 : : /* When we have a contiguous access across loop iterations
2125 : : but the access in the loop doesn't cover the full vector
2126 : : we can end up with no gap recorded but still excess
2127 : : elements accessed, see PR103116. Make sure we peel for
2128 : : gaps if necessary and sufficient and give up if not.
2129 : :
2130 : : If there is a combination of the access not covering the full
2131 : : vector and a gap recorded then we may need to peel twice. */
2132 : 1380702 : if (loop_vinfo
2133 : 24294 : && *memory_access_type == VMAT_CONTIGUOUS
2134 : 23602 : && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2135 : 1405106 : && !multiple_p (group_size * LOOP_VINFO_VECT_FACTOR (loop_vinfo),
2136 : : nunits))
2137 : : {
2138 : 168 : unsigned HOST_WIDE_INT cnunits, cvf;
2139 : 168 : if (!can_overrun_p
2140 : 166 : || !nunits.is_constant (&cnunits)
2141 : 166 : || !LOOP_VINFO_VECT_FACTOR (loop_vinfo).is_constant (&cvf)
2142 : : /* Peeling for gaps assumes that a single scalar iteration
2143 : : is enough to make sure the last vector iteration doesn't
2144 : : access excess elements.
2145 : : ??? Enhancements include peeling multiple iterations
2146 : : or using masked loads with a static mask. */
2147 : 168 : || (group_size * cvf) % cnunits + group_size - gap < cnunits)
2148 : : {
2149 : 58 : if (dump_enabled_p ())
2150 : 17 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2151 : : "peeling for gaps insufficient for "
2152 : : "access\n");
2153 : 58 : return false;
2154 : : }
2155 : : overrun_p = true;
2156 : : }
2157 : : }
2158 : : }
2159 : : else
2160 : : {
2161 : : /* We can always handle this case using elementwise accesses,
2162 : : but see if something more efficient is available. */
2163 : 51474 : *memory_access_type = VMAT_ELEMENTWISE;
2164 : :
2165 : : /* If there is a gap at the end of the group then these optimizations
2166 : : would access excess elements in the last iteration. */
2167 : 51474 : bool would_overrun_p = (gap != 0);
2168 : : /* An overrun is fine if the trailing elements are smaller than the
2169 : : alignment boundary B. Every vector access will be a multiple of B
2170 : : and so we are guaranteed to access a non-gap element in the
2171 : : same B-sized block. */
2172 : 51474 : if (would_overrun_p
2173 : 51474 : && !masked_p
2174 : 51474 : && gap < (vect_known_alignment_in_bytes (first_dr_info, vectype)
2175 : 15942 : / vect_get_scalar_dr_size (first_dr_info)))
2176 : : would_overrun_p = false;
2177 : :
2178 : 51474 : if (!STMT_VINFO_STRIDED_P (first_stmt_info)
2179 : 46409 : && (can_overrun_p || !would_overrun_p)
2180 : 97825 : && compare_step_with_zero (vinfo, stmt_info) > 0)
2181 : : {
2182 : : /* First cope with the degenerate case of a single-element
2183 : : vector. */
2184 : 46272 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U))
2185 : : ;
2186 : :
2187 : : else
2188 : : {
2189 : : /* Otherwise try using LOAD/STORE_LANES. */
2190 : 45767 : *lanes_ifn
2191 : 45767 : = vls_type == VLS_LOAD
2192 : 45767 : ? vect_load_lanes_supported (vectype, group_size, masked_p)
2193 : 6927 : : vect_store_lanes_supported (vectype, group_size,
2194 : : masked_p);
2195 : 45767 : if (*lanes_ifn != IFN_LAST)
2196 : : {
2197 : 0 : *memory_access_type = VMAT_LOAD_STORE_LANES;
2198 : 0 : overrun_p = would_overrun_p;
2199 : : }
2200 : :
2201 : : /* If that fails, try using permuting loads. */
2202 : 45767 : else if (vls_type == VLS_LOAD
2203 : 45767 : ? vect_grouped_load_supported (vectype,
2204 : : single_element_p,
2205 : : group_size)
2206 : 6927 : : vect_grouped_store_supported (vectype, group_size))
2207 : : {
2208 : 40279 : *memory_access_type = VMAT_CONTIGUOUS_PERMUTE;
2209 : 40279 : overrun_p = would_overrun_p;
2210 : : }
2211 : : }
2212 : : }
2213 : :
2214 : : /* As a last resort, trying using a gather load or scatter store.
2215 : :
2216 : : ??? Although the code can handle all group sizes correctly,
2217 : : it probably isn't a win to use separate strided accesses based
2218 : : on nearby locations. Or, even if it's a win over scalar code,
2219 : : it might not be a win over vectorizing at a lower VF, if that
2220 : : allows us to use contiguous accesses. */
2221 : 51474 : if (*memory_access_type == VMAT_ELEMENTWISE
2222 : : && single_element_p
2223 : 11195 : && loop_vinfo
2224 : 56684 : && vect_use_strided_gather_scatters_p (stmt_info, loop_vinfo,
2225 : : masked_p, gs_info))
2226 : 0 : *memory_access_type = VMAT_GATHER_SCATTER;
2227 : : }
2228 : :
2229 : 1439693 : if (*memory_access_type == VMAT_GATHER_SCATTER
2230 : 1439693 : || *memory_access_type == VMAT_ELEMENTWISE)
2231 : : {
2232 : 12362 : *alignment_support_scheme = dr_unaligned_supported;
2233 : 12362 : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2234 : : }
2235 : : else
2236 : : {
2237 : 1427331 : *misalignment = dr_misalignment (first_dr_info, vectype, *poffset);
2238 : 1427331 : *alignment_support_scheme
2239 : 1427331 : = vect_supportable_dr_alignment (vinfo, first_dr_info, vectype,
2240 : : *misalignment);
2241 : : }
2242 : :
2243 : 1439693 : if (vls_type != VLS_LOAD && first_stmt_info == stmt_info)
2244 : : {
2245 : : /* STMT is the leader of the group. Check the operands of all the
2246 : : stmts of the group. */
2247 : 1133337 : stmt_vec_info next_stmt_info = DR_GROUP_NEXT_ELEMENT (stmt_info);
2248 : 3010203 : while (next_stmt_info)
2249 : : {
2250 : 1876866 : tree op = vect_get_store_rhs (next_stmt_info);
2251 : 1876866 : enum vect_def_type dt;
2252 : 1876866 : if (!vect_is_simple_use (op, vinfo, &dt))
2253 : : {
2254 : 0 : if (dump_enabled_p ())
2255 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2256 : : "use not simple.\n");
2257 : 0 : return false;
2258 : : }
2259 : 1876866 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
2260 : : }
2261 : : }
2262 : :
2263 : 1439693 : if (overrun_p)
2264 : : {
2265 : 7409 : gcc_assert (can_overrun_p);
2266 : 7409 : if (dump_enabled_p ())
2267 : 1338 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2268 : : "Data access with gaps requires scalar "
2269 : : "epilogue loop\n");
2270 : 7409 : LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo) = true;
2271 : : }
2272 : :
2273 : : return true;
2274 : : }
2275 : :
2276 : : /* Analyze load or store statement STMT_INFO of type VLS_TYPE. Return true
2277 : : if there is a memory access type that the vectorized form can use,
2278 : : storing it in *MEMORY_ACCESS_TYPE if so. If we decide to use gathers
2279 : : or scatters, fill in GS_INFO accordingly. In addition
2280 : : *ALIGNMENT_SUPPORT_SCHEME is filled out and false is returned if
2281 : : the target does not support the alignment scheme. *MISALIGNMENT
2282 : : is set according to the alignment of the access (including
2283 : : DR_MISALIGNMENT_UNKNOWN when it is unknown).
2284 : :
2285 : : SLP says whether we're performing SLP rather than loop vectorization.
2286 : : MASKED_P is true if the statement is conditional on a vectorized mask.
2287 : : VECTYPE is the vector type that the vectorized statements will use.
2288 : : NCOPIES is the number of vector statements that will be needed. */
2289 : :
2290 : : static bool
2291 : 1756820 : get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
2292 : : tree vectype, slp_tree slp_node,
2293 : : bool masked_p, vec_load_store_type vls_type,
2294 : : unsigned int ncopies,
2295 : : vect_memory_access_type *memory_access_type,
2296 : : poly_int64 *poffset,
2297 : : dr_alignment_support *alignment_support_scheme,
2298 : : int *misalignment,
2299 : : gather_scatter_info *gs_info,
2300 : : internal_fn *lanes_ifn)
2301 : : {
2302 : 1756820 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
2303 : 1756820 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
2304 : 1756820 : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2305 : 1756820 : *poffset = 0;
2306 : 1756820 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
2307 : : {
2308 : 4797 : *memory_access_type = VMAT_GATHER_SCATTER;
2309 : 4797 : if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info))
2310 : 0 : gcc_unreachable ();
2311 : : /* When using internal functions, we rely on pattern recognition
2312 : : to convert the type of the offset to the type that the target
2313 : : requires, with the result being a call to an internal function.
2314 : : If that failed for some reason (e.g. because another pattern
2315 : : took priority), just handle cases in which the offset already
2316 : : has the right type. */
2317 : 4797 : else if (gs_info->ifn != IFN_LAST
2318 : 0 : && !is_gimple_call (stmt_info->stmt)
2319 : 4797 : && !tree_nop_conversion_p (TREE_TYPE (gs_info->offset),
2320 : 0 : TREE_TYPE (gs_info->offset_vectype)))
2321 : : {
2322 : 0 : if (dump_enabled_p ())
2323 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2324 : : "%s offset requires a conversion\n",
2325 : : vls_type == VLS_LOAD ? "gather" : "scatter");
2326 : 0 : return false;
2327 : : }
2328 : 4797 : else if (!vect_is_simple_use (gs_info->offset, vinfo,
2329 : : &gs_info->offset_dt,
2330 : : &gs_info->offset_vectype))
2331 : : {
2332 : 0 : if (dump_enabled_p ())
2333 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2334 : : "%s index use not simple.\n",
2335 : : vls_type == VLS_LOAD ? "gather" : "scatter");
2336 : 0 : return false;
2337 : : }
2338 : 4797 : else if (gs_info->ifn == IFN_LAST && !gs_info->decl)
2339 : : {
2340 : 3995 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant ()
2341 : 3995 : || !TYPE_VECTOR_SUBPARTS (gs_info->offset_vectype).is_constant ()
2342 : 3995 : || !constant_multiple_p (TYPE_VECTOR_SUBPARTS
2343 : 3995 : (gs_info->offset_vectype),
2344 : 7135 : TYPE_VECTOR_SUBPARTS (vectype)))
2345 : : {
2346 : 855 : if (dump_enabled_p ())
2347 : 274 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2348 : : "unsupported vector types for emulated "
2349 : : "gather.\n");
2350 : 855 : return false;
2351 : : }
2352 : : }
2353 : : /* Gather-scatter accesses perform only component accesses, alignment
2354 : : is irrelevant for them. */
2355 : 3942 : *alignment_support_scheme = dr_unaligned_supported;
2356 : : }
2357 : 1752023 : else if (STMT_VINFO_GROUPED_ACCESS (stmt_info) || slp_node)
2358 : : {
2359 : 1439755 : if (!get_group_load_store_type (vinfo, stmt_info, vectype, slp_node,
2360 : : masked_p,
2361 : : vls_type, memory_access_type, poffset,
2362 : : alignment_support_scheme,
2363 : : misalignment, gs_info, lanes_ifn))
2364 : : return false;
2365 : : }
2366 : 312268 : else if (STMT_VINFO_STRIDED_P (stmt_info))
2367 : : {
2368 : 22177 : gcc_assert (!slp_node);
2369 : 22177 : if (loop_vinfo
2370 : 22177 : && vect_use_strided_gather_scatters_p (stmt_info, loop_vinfo,
2371 : : masked_p, gs_info))
2372 : 0 : *memory_access_type = VMAT_GATHER_SCATTER;
2373 : : else
2374 : 22177 : *memory_access_type = VMAT_ELEMENTWISE;
2375 : : /* Alignment is irrelevant here. */
2376 : 22177 : *alignment_support_scheme = dr_unaligned_supported;
2377 : : }
2378 : : else
2379 : : {
2380 : 290091 : int cmp = compare_step_with_zero (vinfo, stmt_info);
2381 : 290091 : if (cmp == 0)
2382 : : {
2383 : 1904 : gcc_assert (vls_type == VLS_LOAD);
2384 : 1904 : *memory_access_type = VMAT_INVARIANT;
2385 : : /* Invariant accesses perform only component accesses, alignment
2386 : : is irrelevant for them. */
2387 : 1904 : *alignment_support_scheme = dr_unaligned_supported;
2388 : : }
2389 : : else
2390 : : {
2391 : 288187 : if (cmp < 0)
2392 : 8230 : *memory_access_type = get_negative_load_store_type
2393 : 8230 : (vinfo, stmt_info, vectype, vls_type, ncopies, poffset);
2394 : : else
2395 : 279957 : *memory_access_type = VMAT_CONTIGUOUS;
2396 : 288187 : *misalignment = dr_misalignment (STMT_VINFO_DR_INFO (stmt_info),
2397 : : vectype, *poffset);
2398 : 288187 : *alignment_support_scheme
2399 : 288187 : = vect_supportable_dr_alignment (vinfo,
2400 : 288187 : STMT_VINFO_DR_INFO (stmt_info),
2401 : : vectype, *misalignment);
2402 : : }
2403 : : }
2404 : :
2405 : 1755903 : if ((*memory_access_type == VMAT_ELEMENTWISE
2406 : 1755903 : || *memory_access_type == VMAT_STRIDED_SLP)
2407 : : && !nunits.is_constant ())
2408 : : {
2409 : : if (dump_enabled_p ())
2410 : : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2411 : : "Not using elementwise accesses due to variable "
2412 : : "vectorization factor.\n");
2413 : : return false;
2414 : : }
2415 : :
2416 : 1755903 : if (*alignment_support_scheme == dr_unaligned_unsupported)
2417 : : {
2418 : 1 : if (dump_enabled_p ())
2419 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2420 : : "unsupported unaligned access\n");
2421 : 1 : return false;
2422 : : }
2423 : :
2424 : : /* FIXME: At the moment the cost model seems to underestimate the
2425 : : cost of using elementwise accesses. This check preserves the
2426 : : traditional behavior until that can be fixed. */
2427 : 1755902 : stmt_vec_info first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
2428 : 1755902 : if (!first_stmt_info)
2429 : 316829 : first_stmt_info = stmt_info;
2430 : 1755902 : if (*memory_access_type == VMAT_ELEMENTWISE
2431 : 34883 : && !STMT_VINFO_STRIDED_P (first_stmt_info)
2432 : 1762393 : && !(stmt_info == DR_GROUP_FIRST_ELEMENT (stmt_info)
2433 : 5776 : && !DR_GROUP_NEXT_ELEMENT (stmt_info)
2434 : 4897 : && !pow2p_hwi (DR_GROUP_SIZE (stmt_info))))
2435 : : {
2436 : 2590 : if (dump_enabled_p ())
2437 : 306 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2438 : : "not falling back to elementwise accesses\n");
2439 : 2590 : return false;
2440 : : }
2441 : : return true;
2442 : : }
2443 : :
2444 : : /* Return true if boolean argument at MASK_INDEX is suitable for vectorizing
2445 : : conditional operation STMT_INFO. When returning true, store the mask
2446 : : in *MASK, the type of its definition in *MASK_DT_OUT, the type of the
2447 : : vectorized mask in *MASK_VECTYPE_OUT and the SLP node corresponding
2448 : : to the mask in *MASK_NODE if MASK_NODE is not NULL. */
2449 : :
2450 : : static bool
2451 : 7985 : vect_check_scalar_mask (vec_info *vinfo, stmt_vec_info stmt_info,
2452 : : slp_tree slp_node, unsigned mask_index,
2453 : : tree *mask, slp_tree *mask_node,
2454 : : vect_def_type *mask_dt_out, tree *mask_vectype_out)
2455 : : {
2456 : 7985 : enum vect_def_type mask_dt;
2457 : 7985 : tree mask_vectype;
2458 : 7985 : slp_tree mask_node_1;
2459 : 7985 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, mask_index,
2460 : : mask, &mask_node_1, &mask_dt, &mask_vectype))
2461 : : {
2462 : 0 : if (dump_enabled_p ())
2463 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2464 : : "mask use not simple.\n");
2465 : 0 : return false;
2466 : : }
2467 : :
2468 : 7985 : if (!VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (*mask)))
2469 : : {
2470 : 0 : if (dump_enabled_p ())
2471 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2472 : : "mask argument is not a boolean.\n");
2473 : 0 : return false;
2474 : : }
2475 : :
2476 : : /* If the caller is not prepared for adjusting an external/constant
2477 : : SLP mask vector type fail. */
2478 : 7985 : if (slp_node
2479 : 7985 : && !mask_node
2480 : 0 : && SLP_TREE_DEF_TYPE (mask_node_1) != vect_internal_def)
2481 : : {
2482 : 0 : if (dump_enabled_p ())
2483 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2484 : : "SLP mask argument is not vectorized.\n");
2485 : 0 : return false;
2486 : : }
2487 : :
2488 : 7985 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
2489 : 7985 : if (!mask_vectype)
2490 : 26 : mask_vectype = get_mask_type_for_scalar_type (vinfo, TREE_TYPE (vectype),
2491 : : mask_node_1);
2492 : :
2493 : 7985 : if (!mask_vectype || !VECTOR_BOOLEAN_TYPE_P (mask_vectype))
2494 : : {
2495 : 0 : if (dump_enabled_p ())
2496 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2497 : : "could not find an appropriate vector mask type.\n");
2498 : 0 : return false;
2499 : : }
2500 : :
2501 : 7985 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (mask_vectype),
2502 : 15970 : TYPE_VECTOR_SUBPARTS (vectype)))
2503 : : {
2504 : 0 : if (dump_enabled_p ())
2505 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2506 : : "vector mask type %T"
2507 : : " does not match vector data type %T.\n",
2508 : : mask_vectype, vectype);
2509 : :
2510 : 0 : return false;
2511 : : }
2512 : :
2513 : 7985 : *mask_dt_out = mask_dt;
2514 : 7985 : *mask_vectype_out = mask_vectype;
2515 : 7985 : if (mask_node)
2516 : 7985 : *mask_node = mask_node_1;
2517 : : return true;
2518 : : }
2519 : :
2520 : : /* Return true if stored value is suitable for vectorizing store
2521 : : statement STMT_INFO. When returning true, store the scalar stored
2522 : : in *RHS and *RHS_NODE, the type of the definition in *RHS_DT_OUT,
2523 : : the type of the vectorized store value in
2524 : : *RHS_VECTYPE_OUT and the type of the store in *VLS_TYPE_OUT. */
2525 : :
2526 : : static bool
2527 : 1274903 : vect_check_store_rhs (vec_info *vinfo, stmt_vec_info stmt_info,
2528 : : slp_tree slp_node, tree *rhs, slp_tree *rhs_node,
2529 : : vect_def_type *rhs_dt_out, tree *rhs_vectype_out,
2530 : : vec_load_store_type *vls_type_out)
2531 : : {
2532 : 1274903 : int op_no = 0;
2533 : 1274903 : if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt))
2534 : : {
2535 : 2814 : if (gimple_call_internal_p (call)
2536 : 2814 : && internal_store_fn_p (gimple_call_internal_fn (call)))
2537 : 2814 : op_no = internal_fn_stored_value_index (gimple_call_internal_fn (call));
2538 : : }
2539 : 1274903 : if (slp_node)
2540 : 1129307 : op_no = vect_slp_child_index_for_operand
2541 : 1129307 : (stmt_info->stmt, op_no, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
2542 : :
2543 : 1274903 : enum vect_def_type rhs_dt;
2544 : 1274903 : tree rhs_vectype;
2545 : 1274903 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, op_no,
2546 : : rhs, rhs_node, &rhs_dt, &rhs_vectype))
2547 : : {
2548 : 0 : if (dump_enabled_p ())
2549 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2550 : : "use not simple.\n");
2551 : 0 : return false;
2552 : : }
2553 : :
2554 : : /* In the case this is a store from a constant make sure
2555 : : native_encode_expr can handle it. */
2556 : 1274903 : if (CONSTANT_CLASS_P (*rhs) && native_encode_expr (*rhs, NULL, 64) == 0)
2557 : : {
2558 : 0 : if (dump_enabled_p ())
2559 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2560 : : "cannot encode constant as a byte sequence.\n");
2561 : 0 : return false;
2562 : : }
2563 : :
2564 : 1274903 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
2565 : 1274903 : if (rhs_vectype && !useless_type_conversion_p (vectype, rhs_vectype))
2566 : : {
2567 : 16 : if (dump_enabled_p ())
2568 : 16 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2569 : : "incompatible vector types.\n");
2570 : 16 : return false;
2571 : : }
2572 : :
2573 : 1274887 : *rhs_dt_out = rhs_dt;
2574 : 1274887 : *rhs_vectype_out = rhs_vectype;
2575 : 1274887 : if (rhs_dt == vect_constant_def || rhs_dt == vect_external_def)
2576 : 948682 : *vls_type_out = VLS_STORE_INVARIANT;
2577 : : else
2578 : 326205 : *vls_type_out = VLS_STORE;
2579 : : return true;
2580 : : }
2581 : :
2582 : : /* Build an all-ones vector mask of type MASKTYPE while vectorizing STMT_INFO.
2583 : : Note that we support masks with floating-point type, in which case the
2584 : : floats are interpreted as a bitmask. */
2585 : :
2586 : : static tree
2587 : 164 : vect_build_all_ones_mask (vec_info *vinfo,
2588 : : stmt_vec_info stmt_info, tree masktype)
2589 : : {
2590 : 164 : if (TREE_CODE (masktype) == INTEGER_TYPE)
2591 : 97 : return build_int_cst (masktype, -1);
2592 : 67 : else if (VECTOR_BOOLEAN_TYPE_P (masktype)
2593 : 134 : || TREE_CODE (TREE_TYPE (masktype)) == INTEGER_TYPE)
2594 : : {
2595 : 15 : tree mask = build_int_cst (TREE_TYPE (masktype), -1);
2596 : 15 : mask = build_vector_from_val (masktype, mask);
2597 : 15 : return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL);
2598 : : }
2599 : 52 : else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (masktype)))
2600 : : {
2601 : : REAL_VALUE_TYPE r;
2602 : : long tmp[6];
2603 : 364 : for (int j = 0; j < 6; ++j)
2604 : 312 : tmp[j] = -1;
2605 : 52 : real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (masktype)));
2606 : 52 : tree mask = build_real (TREE_TYPE (masktype), r);
2607 : 52 : mask = build_vector_from_val (masktype, mask);
2608 : 52 : return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL);
2609 : : }
2610 : 0 : gcc_unreachable ();
2611 : : }
2612 : :
2613 : : /* Build an all-zero merge value of type VECTYPE while vectorizing
2614 : : STMT_INFO as a gather load. */
2615 : :
2616 : : static tree
2617 : 158 : vect_build_zero_merge_argument (vec_info *vinfo,
2618 : : stmt_vec_info stmt_info, tree vectype)
2619 : : {
2620 : 158 : tree merge;
2621 : 158 : if (TREE_CODE (TREE_TYPE (vectype)) == INTEGER_TYPE)
2622 : 50 : merge = build_int_cst (TREE_TYPE (vectype), 0);
2623 : 108 : else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (vectype)))
2624 : : {
2625 : : REAL_VALUE_TYPE r;
2626 : : long tmp[6];
2627 : 756 : for (int j = 0; j < 6; ++j)
2628 : 648 : tmp[j] = 0;
2629 : 108 : real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (vectype)));
2630 : 108 : merge = build_real (TREE_TYPE (vectype), r);
2631 : : }
2632 : : else
2633 : 0 : gcc_unreachable ();
2634 : 158 : merge = build_vector_from_val (vectype, merge);
2635 : 158 : return vect_init_vector (vinfo, stmt_info, merge, vectype, NULL);
2636 : : }
2637 : :
2638 : : /* Build a gather load call while vectorizing STMT_INFO. Insert new
2639 : : instructions before GSI and add them to VEC_STMT. GS_INFO describes
2640 : : the gather load operation. If the load is conditional, MASK is the
2641 : : vectorized condition, otherwise MASK is null. PTR is the base
2642 : : pointer and OFFSET is the vectorized offset. */
2643 : :
2644 : : static gimple *
2645 : 347 : vect_build_one_gather_load_call (vec_info *vinfo, stmt_vec_info stmt_info,
2646 : : gimple_stmt_iterator *gsi,
2647 : : gather_scatter_info *gs_info,
2648 : : tree ptr, tree offset, tree mask)
2649 : : {
2650 : 347 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
2651 : 347 : tree arglist = TYPE_ARG_TYPES (TREE_TYPE (gs_info->decl));
2652 : 347 : tree rettype = TREE_TYPE (TREE_TYPE (gs_info->decl));
2653 : 347 : tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2654 : 347 : /* ptrtype */ arglist = TREE_CHAIN (arglist);
2655 : 347 : tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2656 : 347 : tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2657 : 347 : tree scaletype = TREE_VALUE (arglist);
2658 : 347 : tree var;
2659 : 347 : gcc_checking_assert (types_compatible_p (srctype, rettype)
2660 : : && (!mask
2661 : : || TREE_CODE (masktype) == INTEGER_TYPE
2662 : : || types_compatible_p (srctype, masktype)));
2663 : :
2664 : 347 : tree op = offset;
2665 : 347 : if (!useless_type_conversion_p (idxtype, TREE_TYPE (op)))
2666 : : {
2667 : 100 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)),
2668 : : TYPE_VECTOR_SUBPARTS (idxtype)));
2669 : 100 : var = vect_get_new_ssa_name (idxtype, vect_simple_var);
2670 : 100 : op = build1 (VIEW_CONVERT_EXPR, idxtype, op);
2671 : 100 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op);
2672 : 100 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2673 : 100 : op = var;
2674 : : }
2675 : :
2676 : 347 : tree src_op = NULL_TREE;
2677 : 347 : tree mask_op = NULL_TREE;
2678 : 347 : if (mask)
2679 : : {
2680 : 189 : if (!useless_type_conversion_p (masktype, TREE_TYPE (mask)))
2681 : : {
2682 : 189 : tree utype, optype = TREE_TYPE (mask);
2683 : 189 : if (VECTOR_TYPE_P (masktype)
2684 : 189 : || TYPE_MODE (masktype) == TYPE_MODE (optype))
2685 : : utype = masktype;
2686 : : else
2687 : 7 : utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1);
2688 : 189 : var = vect_get_new_ssa_name (utype, vect_scalar_var);
2689 : 189 : tree mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask);
2690 : 189 : gassign *new_stmt
2691 : 189 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg);
2692 : 189 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2693 : 189 : mask_arg = var;
2694 : 189 : if (!useless_type_conversion_p (masktype, utype))
2695 : : {
2696 : 7 : gcc_assert (TYPE_PRECISION (utype)
2697 : : <= TYPE_PRECISION (masktype));
2698 : 7 : var = vect_get_new_ssa_name (masktype, vect_scalar_var);
2699 : 7 : new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg);
2700 : 7 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2701 : 7 : mask_arg = var;
2702 : : }
2703 : 189 : src_op = build_zero_cst (srctype);
2704 : 189 : mask_op = mask_arg;
2705 : : }
2706 : : else
2707 : : {
2708 : : src_op = mask;
2709 : : mask_op = mask;
2710 : : }
2711 : : }
2712 : : else
2713 : : {
2714 : 158 : src_op = vect_build_zero_merge_argument (vinfo, stmt_info, rettype);
2715 : 158 : mask_op = vect_build_all_ones_mask (vinfo, stmt_info, masktype);
2716 : : }
2717 : :
2718 : 347 : tree scale = build_int_cst (scaletype, gs_info->scale);
2719 : 347 : gimple *new_stmt = gimple_build_call (gs_info->decl, 5, src_op, ptr, op,
2720 : : mask_op, scale);
2721 : :
2722 : 347 : if (!useless_type_conversion_p (vectype, rettype))
2723 : : {
2724 : 49 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (vectype),
2725 : : TYPE_VECTOR_SUBPARTS (rettype)));
2726 : 49 : op = vect_get_new_ssa_name (rettype, vect_simple_var);
2727 : 49 : gimple_call_set_lhs (new_stmt, op);
2728 : 49 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2729 : 49 : op = build1 (VIEW_CONVERT_EXPR, vectype, op);
2730 : 49 : new_stmt = gimple_build_assign (NULL_TREE, VIEW_CONVERT_EXPR, op);
2731 : : }
2732 : :
2733 : 347 : return new_stmt;
2734 : : }
2735 : :
2736 : : /* Build a scatter store call while vectorizing STMT_INFO. Insert new
2737 : : instructions before GSI. GS_INFO describes the scatter store operation.
2738 : : PTR is the base pointer, OFFSET the vectorized offsets and OPRND the
2739 : : vectorized data to store.
2740 : : If the store is conditional, MASK is the vectorized condition, otherwise
2741 : : MASK is null. */
2742 : :
2743 : : static gimple *
2744 : 187 : vect_build_one_scatter_store_call (vec_info *vinfo, stmt_vec_info stmt_info,
2745 : : gimple_stmt_iterator *gsi,
2746 : : gather_scatter_info *gs_info,
2747 : : tree ptr, tree offset, tree oprnd, tree mask)
2748 : : {
2749 : 187 : tree rettype = TREE_TYPE (TREE_TYPE (gs_info->decl));
2750 : 187 : tree arglist = TYPE_ARG_TYPES (TREE_TYPE (gs_info->decl));
2751 : 187 : /* tree ptrtype = TREE_VALUE (arglist); */ arglist = TREE_CHAIN (arglist);
2752 : 187 : tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2753 : 187 : tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2754 : 187 : tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2755 : 187 : tree scaletype = TREE_VALUE (arglist);
2756 : 187 : gcc_checking_assert (TREE_CODE (masktype) == INTEGER_TYPE
2757 : : && TREE_CODE (rettype) == VOID_TYPE);
2758 : :
2759 : 187 : tree mask_arg = NULL_TREE;
2760 : 187 : if (mask)
2761 : : {
2762 : 116 : mask_arg = mask;
2763 : 116 : tree optype = TREE_TYPE (mask_arg);
2764 : 116 : tree utype;
2765 : 116 : if (TYPE_MODE (masktype) == TYPE_MODE (optype))
2766 : : utype = masktype;
2767 : : else
2768 : 8 : utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1);
2769 : 116 : tree var = vect_get_new_ssa_name (utype, vect_scalar_var);
2770 : 116 : mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask_arg);
2771 : 116 : gassign *new_stmt
2772 : 116 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg);
2773 : 116 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2774 : 116 : mask_arg = var;
2775 : 116 : if (!useless_type_conversion_p (masktype, utype))
2776 : : {
2777 : 8 : gcc_assert (TYPE_PRECISION (utype) <= TYPE_PRECISION (masktype));
2778 : 8 : tree var = vect_get_new_ssa_name (masktype, vect_scalar_var);
2779 : 8 : new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg);
2780 : 8 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2781 : 8 : mask_arg = var;
2782 : : }
2783 : : }
2784 : : else
2785 : : {
2786 : 71 : mask_arg = build_int_cst (masktype, -1);
2787 : 71 : mask_arg = vect_init_vector (vinfo, stmt_info, mask_arg, masktype, NULL);
2788 : : }
2789 : :
2790 : 187 : tree src = oprnd;
2791 : 187 : if (!useless_type_conversion_p (srctype, TREE_TYPE (src)))
2792 : : {
2793 : 0 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (src)),
2794 : : TYPE_VECTOR_SUBPARTS (srctype)));
2795 : 0 : tree var = vect_get_new_ssa_name (srctype, vect_simple_var);
2796 : 0 : src = build1 (VIEW_CONVERT_EXPR, srctype, src);
2797 : 0 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, src);
2798 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2799 : 0 : src = var;
2800 : : }
2801 : :
2802 : 187 : tree op = offset;
2803 : 187 : if (!useless_type_conversion_p (idxtype, TREE_TYPE (op)))
2804 : : {
2805 : 20 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)),
2806 : : TYPE_VECTOR_SUBPARTS (idxtype)));
2807 : 20 : tree var = vect_get_new_ssa_name (idxtype, vect_simple_var);
2808 : 20 : op = build1 (VIEW_CONVERT_EXPR, idxtype, op);
2809 : 20 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op);
2810 : 20 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2811 : 20 : op = var;
2812 : : }
2813 : :
2814 : 187 : tree scale = build_int_cst (scaletype, gs_info->scale);
2815 : 187 : gcall *new_stmt
2816 : 187 : = gimple_build_call (gs_info->decl, 5, ptr, mask_arg, op, src, scale);
2817 : 187 : return new_stmt;
2818 : : }
2819 : :
2820 : : /* Prepare the base and offset in GS_INFO for vectorization.
2821 : : Set *DATAREF_PTR to the loop-invariant base address and *VEC_OFFSET
2822 : : to the vectorized offset argument for the first copy of STMT_INFO.
2823 : : STMT_INFO is the statement described by GS_INFO and LOOP is the
2824 : : containing loop. */
2825 : :
2826 : : static void
2827 : 1206 : vect_get_gather_scatter_ops (loop_vec_info loop_vinfo,
2828 : : class loop *loop, stmt_vec_info stmt_info,
2829 : : slp_tree slp_node, gather_scatter_info *gs_info,
2830 : : tree *dataref_ptr, vec<tree> *vec_offset)
2831 : : {
2832 : 1206 : gimple_seq stmts = NULL;
2833 : 1206 : *dataref_ptr = force_gimple_operand (gs_info->base, &stmts, true, NULL_TREE);
2834 : 1206 : if (stmts != NULL)
2835 : : {
2836 : 970 : basic_block new_bb;
2837 : 970 : edge pe = loop_preheader_edge (loop);
2838 : 970 : new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
2839 : 970 : gcc_assert (!new_bb);
2840 : : }
2841 : 1206 : if (slp_node)
2842 : 26 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_offset);
2843 : : else
2844 : : {
2845 : 1180 : unsigned ncopies
2846 : 1180 : = vect_get_num_copies (loop_vinfo, gs_info->offset_vectype);
2847 : 1180 : vect_get_vec_defs_for_operand (loop_vinfo, stmt_info, ncopies,
2848 : : gs_info->offset, vec_offset,
2849 : : gs_info->offset_vectype);
2850 : : }
2851 : 1206 : }
2852 : :
2853 : : /* Prepare to implement a grouped or strided load or store using
2854 : : the gather load or scatter store operation described by GS_INFO.
2855 : : STMT_INFO is the load or store statement.
2856 : :
2857 : : Set *DATAREF_BUMP to the amount that should be added to the base
2858 : : address after each copy of the vectorized statement. Set *VEC_OFFSET
2859 : : to an invariant offset vector in which element I has the value
2860 : : I * DR_STEP / SCALE. */
2861 : :
2862 : : static void
2863 : 0 : vect_get_strided_load_store_ops (stmt_vec_info stmt_info,
2864 : : loop_vec_info loop_vinfo,
2865 : : gimple_stmt_iterator *gsi,
2866 : : gather_scatter_info *gs_info,
2867 : : tree *dataref_bump, tree *vec_offset,
2868 : : vec_loop_lens *loop_lens)
2869 : : {
2870 : 0 : struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
2871 : 0 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
2872 : :
2873 : 0 : if (LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo))
2874 : : {
2875 : : /* _31 = .SELECT_VL (ivtmp_29, POLY_INT_CST [4, 4]);
2876 : : ivtmp_8 = _31 * 16 (step in bytes);
2877 : : .MASK_LEN_SCATTER_STORE (vectp_a.9_7, ... );
2878 : : vectp_a.9_26 = vectp_a.9_7 + ivtmp_8; */
2879 : 0 : tree loop_len
2880 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens, 1, vectype, 0, 0);
2881 : 0 : tree tmp
2882 : 0 : = fold_build2 (MULT_EXPR, sizetype,
2883 : : fold_convert (sizetype, unshare_expr (DR_STEP (dr))),
2884 : : loop_len);
2885 : 0 : *dataref_bump = force_gimple_operand_gsi (gsi, tmp, true, NULL_TREE, true,
2886 : : GSI_SAME_STMT);
2887 : : }
2888 : : else
2889 : : {
2890 : 0 : tree bump
2891 : 0 : = size_binop (MULT_EXPR,
2892 : : fold_convert (sizetype, unshare_expr (DR_STEP (dr))),
2893 : : size_int (TYPE_VECTOR_SUBPARTS (vectype)));
2894 : 0 : *dataref_bump = cse_and_gimplify_to_preheader (loop_vinfo, bump);
2895 : : }
2896 : :
2897 : : /* The offset given in GS_INFO can have pointer type, so use the element
2898 : : type of the vector instead. */
2899 : 0 : tree offset_type = TREE_TYPE (gs_info->offset_vectype);
2900 : :
2901 : : /* Calculate X = DR_STEP / SCALE and convert it to the appropriate type. */
2902 : 0 : tree step = size_binop (EXACT_DIV_EXPR, unshare_expr (DR_STEP (dr)),
2903 : : ssize_int (gs_info->scale));
2904 : 0 : step = fold_convert (offset_type, step);
2905 : :
2906 : : /* Create {0, X, X*2, X*3, ...}. */
2907 : 0 : tree offset = fold_build2 (VEC_SERIES_EXPR, gs_info->offset_vectype,
2908 : : build_zero_cst (offset_type), step);
2909 : 0 : *vec_offset = cse_and_gimplify_to_preheader (loop_vinfo, offset);
2910 : 0 : }
2911 : :
2912 : : /* Prepare the pointer IVs which needs to be updated by a variable amount.
2913 : : Such variable amount is the outcome of .SELECT_VL. In this case, we can
2914 : : allow each iteration process the flexible number of elements as long as
2915 : : the number <= vf elments.
2916 : :
2917 : : Return data reference according to SELECT_VL.
2918 : : If new statements are needed, insert them before GSI. */
2919 : :
2920 : : static tree
2921 : 0 : vect_get_loop_variant_data_ptr_increment (
2922 : : vec_info *vinfo, tree aggr_type, gimple_stmt_iterator *gsi,
2923 : : vec_loop_lens *loop_lens, dr_vec_info *dr_info,
2924 : : vect_memory_access_type memory_access_type)
2925 : : {
2926 : 0 : loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (vinfo);
2927 : 0 : tree step = vect_dr_behavior (vinfo, dr_info)->step;
2928 : :
2929 : : /* gather/scatter never reach here. */
2930 : 0 : gcc_assert (memory_access_type != VMAT_GATHER_SCATTER);
2931 : :
2932 : : /* When we support SELECT_VL pattern, we dynamic adjust
2933 : : the memory address by .SELECT_VL result.
2934 : :
2935 : : The result of .SELECT_VL is the number of elements to
2936 : : be processed of each iteration. So the memory address
2937 : : adjustment operation should be:
2938 : :
2939 : : addr = addr + .SELECT_VL (ARG..) * step;
2940 : : */
2941 : 0 : tree loop_len
2942 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens, 1, aggr_type, 0, 0);
2943 : 0 : tree len_type = TREE_TYPE (loop_len);
2944 : : /* Since the outcome of .SELECT_VL is element size, we should adjust
2945 : : it into bytesize so that it can be used in address pointer variable
2946 : : amount IVs adjustment. */
2947 : 0 : tree tmp = fold_build2 (MULT_EXPR, len_type, loop_len,
2948 : : wide_int_to_tree (len_type, wi::to_widest (step)));
2949 : 0 : tree bump = make_temp_ssa_name (len_type, NULL, "ivtmp");
2950 : 0 : gassign *assign = gimple_build_assign (bump, tmp);
2951 : 0 : gsi_insert_before (gsi, assign, GSI_SAME_STMT);
2952 : 0 : return bump;
2953 : : }
2954 : :
2955 : : /* Return the amount that should be added to a vector pointer to move
2956 : : to the next or previous copy of AGGR_TYPE. DR_INFO is the data reference
2957 : : being vectorized and MEMORY_ACCESS_TYPE describes the type of
2958 : : vectorization. */
2959 : :
2960 : : static tree
2961 : 1700522 : vect_get_data_ptr_increment (vec_info *vinfo, gimple_stmt_iterator *gsi,
2962 : : dr_vec_info *dr_info, tree aggr_type,
2963 : : vect_memory_access_type memory_access_type,
2964 : : vec_loop_lens *loop_lens = nullptr)
2965 : : {
2966 : 1700522 : if (memory_access_type == VMAT_INVARIANT)
2967 : 0 : return size_zero_node;
2968 : :
2969 : 1700522 : loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (vinfo);
2970 : 344118 : if (loop_vinfo && LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo))
2971 : 0 : return vect_get_loop_variant_data_ptr_increment (vinfo, aggr_type, gsi,
2972 : : loop_lens, dr_info,
2973 : 0 : memory_access_type);
2974 : :
2975 : 1700522 : tree iv_step = TYPE_SIZE_UNIT (aggr_type);
2976 : 1700522 : tree step = vect_dr_behavior (vinfo, dr_info)->step;
2977 : 1700522 : if (tree_int_cst_sgn (step) == -1)
2978 : 7920 : iv_step = fold_build1 (NEGATE_EXPR, TREE_TYPE (iv_step), iv_step);
2979 : : return iv_step;
2980 : : }
2981 : :
2982 : : /* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64,128}. */
2983 : :
2984 : : static bool
2985 : 106 : vectorizable_bswap (vec_info *vinfo,
2986 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
2987 : : gimple **vec_stmt, slp_tree slp_node,
2988 : : slp_tree *slp_op,
2989 : : tree vectype_in, stmt_vector_for_cost *cost_vec)
2990 : : {
2991 : 106 : tree op, vectype;
2992 : 106 : gcall *stmt = as_a <gcall *> (stmt_info->stmt);
2993 : 106 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
2994 : 106 : unsigned ncopies;
2995 : :
2996 : 106 : op = gimple_call_arg (stmt, 0);
2997 : 106 : vectype = STMT_VINFO_VECTYPE (stmt_info);
2998 : 106 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
2999 : :
3000 : : /* Multiple types in SLP are handled by creating the appropriate number of
3001 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
3002 : : case of SLP. */
3003 : 106 : if (slp_node)
3004 : : ncopies = 1;
3005 : : else
3006 : 32 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
3007 : :
3008 : 32 : gcc_assert (ncopies >= 1);
3009 : :
3010 : 106 : if (TYPE_SIZE (vectype_in) != TYPE_SIZE (vectype))
3011 : : {
3012 : 2 : if (dump_enabled_p ())
3013 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3014 : : "mismatched vector sizes %T and %T\n",
3015 : : vectype_in, vectype);
3016 : 2 : return false;
3017 : : }
3018 : :
3019 : 104 : tree char_vectype = get_same_sized_vectype (char_type_node, vectype_in);
3020 : 104 : if (! char_vectype)
3021 : : return false;
3022 : :
3023 : 104 : poly_uint64 num_bytes = TYPE_VECTOR_SUBPARTS (char_vectype);
3024 : 104 : unsigned word_bytes;
3025 : 208 : if (!constant_multiple_p (num_bytes, nunits, &word_bytes))
3026 : : return false;
3027 : :
3028 : : /* The encoding uses one stepped pattern for each byte in the word. */
3029 : 104 : vec_perm_builder elts (num_bytes, word_bytes, 3);
3030 : 416 : for (unsigned i = 0; i < 3; ++i)
3031 : 1848 : for (unsigned j = 0; j < word_bytes; ++j)
3032 : 1536 : elts.quick_push ((i + 1) * word_bytes - j - 1);
3033 : :
3034 : 104 : vec_perm_indices indices (elts, 1, num_bytes);
3035 : 104 : machine_mode vmode = TYPE_MODE (char_vectype);
3036 : 104 : if (!can_vec_perm_const_p (vmode, vmode, indices))
3037 : : return false;
3038 : :
3039 : 74 : if (! vec_stmt)
3040 : : {
3041 : 65 : if (slp_node
3042 : 65 : && !vect_maybe_update_slp_op_vectype (slp_op[0], vectype_in))
3043 : : {
3044 : 0 : if (dump_enabled_p ())
3045 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3046 : : "incompatible vector types for invariants\n");
3047 : 0 : return false;
3048 : : }
3049 : :
3050 : 65 : STMT_VINFO_TYPE (stmt_info) = call_vec_info_type;
3051 : 65 : DUMP_VECT_SCOPE ("vectorizable_bswap");
3052 : 65 : record_stmt_cost (cost_vec,
3053 : : 1, vector_stmt, stmt_info, 0, vect_prologue);
3054 : 65 : record_stmt_cost (cost_vec,
3055 : : slp_node
3056 : 56 : ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies,
3057 : : vec_perm, stmt_info, 0, vect_body);
3058 : 65 : return true;
3059 : : }
3060 : :
3061 : 9 : tree bswap_vconst = vec_perm_indices_to_tree (char_vectype, indices);
3062 : :
3063 : : /* Transform. */
3064 : 9 : vec<tree> vec_oprnds = vNULL;
3065 : 9 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
3066 : : op, &vec_oprnds);
3067 : : /* Arguments are ready. create the new vector stmt. */
3068 : 9 : unsigned i;
3069 : 9 : tree vop;
3070 : 18 : FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
3071 : : {
3072 : 9 : gimple *new_stmt;
3073 : 9 : tree tem = make_ssa_name (char_vectype);
3074 : 9 : new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
3075 : : char_vectype, vop));
3076 : 9 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3077 : 9 : tree tem2 = make_ssa_name (char_vectype);
3078 : 9 : new_stmt = gimple_build_assign (tem2, VEC_PERM_EXPR,
3079 : : tem, tem, bswap_vconst);
3080 : 9 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3081 : 9 : tem = make_ssa_name (vectype);
3082 : 9 : new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
3083 : : vectype, tem2));
3084 : 9 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3085 : 9 : if (slp_node)
3086 : 0 : slp_node->push_vec_def (new_stmt);
3087 : : else
3088 : 9 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
3089 : : }
3090 : :
3091 : 9 : if (!slp_node)
3092 : 9 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
3093 : :
3094 : 9 : vec_oprnds.release ();
3095 : 9 : return true;
3096 : 104 : }
3097 : :
3098 : : /* Return true if vector types VECTYPE_IN and VECTYPE_OUT have
3099 : : integer elements and if we can narrow VECTYPE_IN to VECTYPE_OUT
3100 : : in a single step. On success, store the binary pack code in
3101 : : *CONVERT_CODE. */
3102 : :
3103 : : static bool
3104 : 126 : simple_integer_narrowing (tree vectype_out, tree vectype_in,
3105 : : code_helper *convert_code)
3106 : : {
3107 : 252 : if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype_out))
3108 : 252 : || !INTEGRAL_TYPE_P (TREE_TYPE (vectype_in)))
3109 : : return false;
3110 : :
3111 : 51 : code_helper code;
3112 : 51 : int multi_step_cvt = 0;
3113 : 51 : auto_vec <tree, 8> interm_types;
3114 : 76 : if (!supportable_narrowing_operation (NOP_EXPR, vectype_out, vectype_in,
3115 : : &code, &multi_step_cvt, &interm_types)
3116 : 51 : || multi_step_cvt)
3117 : 25 : return false;
3118 : :
3119 : 26 : *convert_code = code;
3120 : 26 : return true;
3121 : 51 : }
3122 : :
3123 : : /* Function vectorizable_call.
3124 : :
3125 : : Check if STMT_INFO performs a function call that can be vectorized.
3126 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
3127 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
3128 : : Return true if STMT_INFO is vectorizable in this way. */
3129 : :
3130 : : static bool
3131 : 1798331 : vectorizable_call (vec_info *vinfo,
3132 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
3133 : : gimple **vec_stmt, slp_tree slp_node,
3134 : : stmt_vector_for_cost *cost_vec)
3135 : : {
3136 : 1798331 : gcall *stmt;
3137 : 1798331 : tree vec_dest;
3138 : 1798331 : tree scalar_dest;
3139 : 1798331 : tree op;
3140 : 1798331 : tree vec_oprnd0 = NULL_TREE, vec_oprnd1 = NULL_TREE;
3141 : 1798331 : tree vectype_out, vectype_in;
3142 : 1798331 : poly_uint64 nunits_in;
3143 : 1798331 : poly_uint64 nunits_out;
3144 : 1798331 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
3145 : 1798331 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
3146 : 1798331 : tree fndecl, new_temp, rhs_type;
3147 : 1798331 : enum vect_def_type dt[4]
3148 : : = { vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type,
3149 : : vect_unknown_def_type };
3150 : 1798331 : tree vectypes[ARRAY_SIZE (dt)] = {};
3151 : 1798331 : slp_tree slp_op[ARRAY_SIZE (dt)] = {};
3152 : 1798331 : int ndts = ARRAY_SIZE (dt);
3153 : 1798331 : int ncopies, j;
3154 : 1798331 : auto_vec<tree, 8> vargs;
3155 : 1798331 : enum { NARROW, NONE, WIDEN } modifier;
3156 : 1798331 : size_t i, nargs;
3157 : 1798331 : tree lhs;
3158 : 1798331 : tree clz_ctz_arg1 = NULL_TREE;
3159 : :
3160 : 1798331 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
3161 : : return false;
3162 : :
3163 : 1798331 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
3164 : 24817 : && ! vec_stmt)
3165 : : return false;
3166 : :
3167 : : /* Is STMT_INFO a vectorizable call? */
3168 : 1806566 : stmt = dyn_cast <gcall *> (stmt_info->stmt);
3169 : 17742 : if (!stmt)
3170 : : return false;
3171 : :
3172 : 17742 : if (gimple_call_internal_p (stmt)
3173 : 17742 : && (internal_load_fn_p (gimple_call_internal_fn (stmt))
3174 : 11747 : || internal_store_fn_p (gimple_call_internal_fn (stmt))))
3175 : : /* Handled by vectorizable_load and vectorizable_store. */
3176 : 3154 : return false;
3177 : :
3178 : 14588 : if (gimple_call_lhs (stmt) == NULL_TREE
3179 : 14588 : || TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME)
3180 : : return false;
3181 : :
3182 : 14578 : gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
3183 : :
3184 : 14578 : vectype_out = STMT_VINFO_VECTYPE (stmt_info);
3185 : :
3186 : : /* Process function arguments. */
3187 : 14578 : rhs_type = NULL_TREE;
3188 : 14578 : vectype_in = NULL_TREE;
3189 : 14578 : nargs = gimple_call_num_args (stmt);
3190 : :
3191 : : /* Bail out if the function has more than four arguments, we do not have
3192 : : interesting builtin functions to vectorize with more than two arguments
3193 : : except for fma. No arguments is also not good. */
3194 : 14578 : if (nargs == 0 || nargs > 4)
3195 : : return false;
3196 : :
3197 : : /* Ignore the arguments of IFN_GOMP_SIMD_LANE, they are magic. */
3198 : 14571 : combined_fn cfn = gimple_call_combined_fn (stmt);
3199 : 14571 : if (cfn == CFN_GOMP_SIMD_LANE)
3200 : : {
3201 : 3625 : nargs = 0;
3202 : 3625 : rhs_type = unsigned_type_node;
3203 : : }
3204 : : /* Similarly pretend IFN_CLZ and IFN_CTZ only has one argument, the second
3205 : : argument just says whether it is well-defined at zero or not and what
3206 : : value should be returned for it. */
3207 : 14571 : if ((cfn == CFN_CLZ || cfn == CFN_CTZ) && nargs == 2)
3208 : : {
3209 : 118 : nargs = 1;
3210 : 118 : clz_ctz_arg1 = gimple_call_arg (stmt, 1);
3211 : : }
3212 : :
3213 : 14571 : int mask_opno = -1;
3214 : 14571 : if (internal_fn_p (cfn))
3215 : 12399 : mask_opno = internal_fn_mask_index (as_internal_fn (cfn));
3216 : :
3217 : 39563 : for (i = 0; i < nargs; i++)
3218 : : {
3219 : 25935 : if ((int) i == mask_opno)
3220 : : {
3221 : 3093 : if (!vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_opno,
3222 : : &op, &slp_op[i], &dt[i], &vectypes[i]))
3223 : : return false;
3224 : 3093 : continue;
3225 : : }
3226 : :
3227 : 22842 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
3228 : : i, &op, &slp_op[i], &dt[i], &vectypes[i]))
3229 : : {
3230 : 0 : if (dump_enabled_p ())
3231 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3232 : : "use not simple.\n");
3233 : 0 : return false;
3234 : : }
3235 : :
3236 : : /* We can only handle calls with arguments of the same type. */
3237 : 22842 : if (rhs_type
3238 : 22842 : && !types_compatible_p (rhs_type, TREE_TYPE (op)))
3239 : : {
3240 : 943 : if (dump_enabled_p ())
3241 : 289 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3242 : : "argument types differ.\n");
3243 : 943 : return false;
3244 : : }
3245 : 21899 : if (!rhs_type)
3246 : 10946 : rhs_type = TREE_TYPE (op);
3247 : :
3248 : 21899 : if (!vectype_in)
3249 : 11498 : vectype_in = vectypes[i];
3250 : 10401 : else if (vectypes[i]
3251 : 10401 : && !types_compatible_p (vectypes[i], vectype_in))
3252 : : {
3253 : 0 : if (dump_enabled_p ())
3254 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3255 : : "argument vector types differ.\n");
3256 : 0 : return false;
3257 : : }
3258 : : }
3259 : : /* If all arguments are external or constant defs, infer the vector type
3260 : : from the scalar type. */
3261 : 13628 : if (!vectype_in)
3262 : 6065 : vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
3263 : 13628 : if (vec_stmt)
3264 : 3890 : gcc_assert (vectype_in);
3265 : 9738 : if (!vectype_in)
3266 : : {
3267 : 994 : if (dump_enabled_p ())
3268 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3269 : : "no vectype for scalar type %T\n", rhs_type);
3270 : :
3271 : 994 : return false;
3272 : : }
3273 : :
3274 : 25268 : if (VECTOR_BOOLEAN_TYPE_P (vectype_out)
3275 : 12634 : != VECTOR_BOOLEAN_TYPE_P (vectype_in))
3276 : : {
3277 : 0 : if (dump_enabled_p ())
3278 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3279 : : "mixed mask and nonmask vector types\n");
3280 : 0 : return false;
3281 : : }
3282 : :
3283 : 12634 : if (vect_emulated_vector_p (vectype_in) || vect_emulated_vector_p (vectype_out))
3284 : : {
3285 : 0 : if (dump_enabled_p ())
3286 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3287 : : "use emulated vector type for call\n");
3288 : 0 : return false;
3289 : : }
3290 : :
3291 : : /* FORNOW */
3292 : 12634 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
3293 : 12634 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
3294 : 12634 : if (known_eq (nunits_in * 2, nunits_out))
3295 : : modifier = NARROW;
3296 : 12272 : else if (known_eq (nunits_out, nunits_in))
3297 : : modifier = NONE;
3298 : 18 : else if (known_eq (nunits_out * 2, nunits_in))
3299 : : modifier = WIDEN;
3300 : : else
3301 : : return false;
3302 : :
3303 : : /* We only handle functions that do not read or clobber memory. */
3304 : 25260 : if (gimple_vuse (stmt))
3305 : : {
3306 : 1366 : if (dump_enabled_p ())
3307 : 16 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3308 : : "function reads from or writes to memory.\n");
3309 : 1366 : return false;
3310 : : }
3311 : :
3312 : : /* For now, we only vectorize functions if a target specific builtin
3313 : : is available. TODO -- in some cases, it might be profitable to
3314 : : insert the calls for pieces of the vector, in order to be able
3315 : : to vectorize other operations in the loop. */
3316 : 11264 : fndecl = NULL_TREE;
3317 : 11264 : internal_fn ifn = IFN_LAST;
3318 : 11264 : tree callee = gimple_call_fndecl (stmt);
3319 : :
3320 : : /* First try using an internal function. */
3321 : 11264 : code_helper convert_code = MAX_TREE_CODES;
3322 : 11264 : if (cfn != CFN_LAST
3323 : 11264 : && (modifier == NONE
3324 : 135 : || (modifier == NARROW
3325 : 126 : && simple_integer_narrowing (vectype_out, vectype_in,
3326 : : &convert_code))))
3327 : 10738 : ifn = vectorizable_internal_function (cfn, callee, vectype_out,
3328 : : vectype_in);
3329 : :
3330 : : /* If that fails, try asking for a target-specific built-in function. */
3331 : 10738 : if (ifn == IFN_LAST)
3332 : : {
3333 : 5565 : if (cfn != CFN_LAST)
3334 : 5148 : fndecl = targetm.vectorize.builtin_vectorized_function
3335 : 5148 : (cfn, vectype_out, vectype_in);
3336 : 417 : else if (callee && fndecl_built_in_p (callee, BUILT_IN_MD))
3337 : 24 : fndecl = targetm.vectorize.builtin_md_vectorized_function
3338 : 24 : (callee, vectype_out, vectype_in);
3339 : : }
3340 : :
3341 : 11264 : if (ifn == IFN_LAST && !fndecl)
3342 : : {
3343 : 5488 : if (cfn == CFN_GOMP_SIMD_LANE
3344 : 5488 : && !slp_node
3345 : 3625 : && loop_vinfo
3346 : 3625 : && LOOP_VINFO_LOOP (loop_vinfo)->simduid
3347 : 3625 : && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME
3348 : 12738 : && LOOP_VINFO_LOOP (loop_vinfo)->simduid
3349 : : == SSA_NAME_VAR (gimple_call_arg (stmt, 0)))
3350 : : {
3351 : : /* We can handle IFN_GOMP_SIMD_LANE by returning a
3352 : : { 0, 1, 2, ... vf - 1 } vector. */
3353 : 3625 : gcc_assert (nargs == 0);
3354 : : }
3355 : 1863 : else if (modifier == NONE
3356 : 1863 : && (gimple_call_builtin_p (stmt, BUILT_IN_BSWAP16)
3357 : 1750 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP32)
3358 : 1682 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64)
3359 : 1654 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP128)))
3360 : 106 : return vectorizable_bswap (vinfo, stmt_info, gsi, vec_stmt, slp_node,
3361 : 106 : slp_op, vectype_in, cost_vec);
3362 : : else
3363 : : {
3364 : 1757 : if (dump_enabled_p ())
3365 : 125 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3366 : : "function is not vectorizable.\n");
3367 : 1757 : return false;
3368 : : }
3369 : : }
3370 : :
3371 : 9401 : if (slp_node)
3372 : : ncopies = 1;
3373 : 7305 : else if (modifier == NARROW && ifn == IFN_LAST)
3374 : 68 : ncopies = vect_get_num_copies (loop_vinfo, vectype_out);
3375 : : else
3376 : 7237 : ncopies = vect_get_num_copies (loop_vinfo, vectype_in);
3377 : :
3378 : : /* Sanity check: make sure that at least one copy of the vectorized stmt
3379 : : needs to be generated. */
3380 : 7305 : gcc_assert (ncopies >= 1);
3381 : :
3382 : 9401 : int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info);
3383 : 9401 : internal_fn cond_fn = get_conditional_internal_fn (ifn);
3384 : 9401 : internal_fn cond_len_fn = get_len_internal_fn (ifn);
3385 : 9401 : int len_opno = internal_fn_len_index (cond_len_fn);
3386 : 9401 : vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL);
3387 : 8122 : vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL);
3388 : 9401 : if (!vec_stmt) /* transformation not required. */
3389 : : {
3390 : 5520 : if (slp_node)
3391 : 4003 : for (i = 0; i < nargs; ++i)
3392 : 2869 : if (!vect_maybe_update_slp_op_vectype (slp_op[i],
3393 : 2869 : vectypes[i]
3394 : : ? vectypes[i] : vectype_in))
3395 : : {
3396 : 0 : if (dump_enabled_p ())
3397 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3398 : : "incompatible vector types for invariants\n");
3399 : 0 : return false;
3400 : : }
3401 : 5520 : STMT_VINFO_TYPE (stmt_info) = call_vec_info_type;
3402 : 5520 : DUMP_VECT_SCOPE ("vectorizable_call");
3403 : 5520 : vect_model_simple_cost (vinfo, stmt_info,
3404 : : ncopies, dt, ndts, slp_node, cost_vec);
3405 : 5520 : if (ifn != IFN_LAST && modifier == NARROW && !slp_node)
3406 : 0 : record_stmt_cost (cost_vec, ncopies / 2,
3407 : : vec_promote_demote, stmt_info, 0, vect_body);
3408 : :
3409 : 5520 : if (loop_vinfo
3410 : 4877 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
3411 : 19 : && (reduc_idx >= 0 || mask_opno >= 0))
3412 : : {
3413 : 18 : if (reduc_idx >= 0
3414 : 0 : && (cond_fn == IFN_LAST
3415 : 0 : || !direct_internal_fn_supported_p (cond_fn, vectype_out,
3416 : : OPTIMIZE_FOR_SPEED))
3417 : 18 : && (cond_len_fn == IFN_LAST
3418 : 0 : || !direct_internal_fn_supported_p (cond_len_fn, vectype_out,
3419 : : OPTIMIZE_FOR_SPEED)))
3420 : : {
3421 : 0 : if (dump_enabled_p ())
3422 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3423 : : "can't use a fully-masked loop because no"
3424 : : " conditional operation is available.\n");
3425 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
3426 : : }
3427 : : else
3428 : : {
3429 : 36 : unsigned int nvectors
3430 : : = (slp_node
3431 : 18 : ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node)
3432 : : : ncopies);
3433 : 18 : tree scalar_mask = NULL_TREE;
3434 : 18 : if (mask_opno >= 0)
3435 : 18 : scalar_mask = gimple_call_arg (stmt_info->stmt, mask_opno);
3436 : 18 : if (cond_len_fn != IFN_LAST
3437 : 18 : && direct_internal_fn_supported_p (cond_len_fn, vectype_out,
3438 : : OPTIMIZE_FOR_SPEED))
3439 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype_out,
3440 : : 1);
3441 : : else
3442 : 18 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype_out,
3443 : : scalar_mask);
3444 : : }
3445 : : }
3446 : 5520 : return true;
3447 : : }
3448 : :
3449 : : /* Transform. */
3450 : :
3451 : 3881 : if (dump_enabled_p ())
3452 : 361 : dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n");
3453 : :
3454 : : /* Handle def. */
3455 : 3881 : scalar_dest = gimple_call_lhs (stmt);
3456 : 3881 : vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
3457 : :
3458 : 3881 : bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
3459 : 3245 : bool len_loop_p = loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
3460 : 3881 : unsigned int vect_nargs = nargs;
3461 : 3881 : if (len_loop_p)
3462 : : {
3463 : 0 : if (len_opno >= 0)
3464 : : {
3465 : 0 : ifn = cond_len_fn;
3466 : : /* COND_* -> COND_LEN_* takes 2 extra arguments:LEN,BIAS. */
3467 : 0 : vect_nargs += 2;
3468 : : }
3469 : 0 : else if (reduc_idx >= 0)
3470 : 0 : gcc_unreachable ();
3471 : : }
3472 : 3881 : else if (masked_loop_p && reduc_idx >= 0)
3473 : : {
3474 : 0 : ifn = cond_fn;
3475 : 0 : vect_nargs += 2;
3476 : : }
3477 : 3881 : if (clz_ctz_arg1)
3478 : 59 : ++vect_nargs;
3479 : :
3480 : 3881 : if (modifier == NONE || ifn != IFN_LAST)
3481 : : {
3482 : 3849 : tree prev_res = NULL_TREE;
3483 : 3849 : vargs.safe_grow (vect_nargs, true);
3484 : 3849 : auto_vec<vec<tree> > vec_defs (nargs);
3485 : 7867 : for (j = 0; j < ncopies; ++j)
3486 : : {
3487 : : /* Build argument list for the vectorized call. */
3488 : 4018 : if (slp_node)
3489 : : {
3490 : 962 : vec<tree> vec_oprnds0;
3491 : :
3492 : 962 : vect_get_slp_defs (vinfo, slp_node, &vec_defs);
3493 : 962 : vec_oprnds0 = vec_defs[0];
3494 : :
3495 : : /* Arguments are ready. Create the new vector stmt. */
3496 : 2006 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_oprnd0)
3497 : : {
3498 : 1044 : int varg = 0;
3499 : 1044 : if (masked_loop_p && reduc_idx >= 0)
3500 : : {
3501 : 0 : unsigned int vec_num = vec_oprnds0.length ();
3502 : : /* Always true for SLP. */
3503 : 0 : gcc_assert (ncopies == 1);
3504 : 0 : vargs[varg++] = vect_get_loop_mask (loop_vinfo,
3505 : : gsi, masks, vec_num,
3506 : : vectype_out, i);
3507 : : }
3508 : : size_t k;
3509 : 3638 : for (k = 0; k < nargs; k++)
3510 : : {
3511 : 2594 : vec<tree> vec_oprndsk = vec_defs[k];
3512 : 2594 : vargs[varg++] = vec_oprndsk[i];
3513 : : }
3514 : 1044 : if (masked_loop_p && reduc_idx >= 0)
3515 : 0 : vargs[varg++] = vargs[reduc_idx + 1];
3516 : 1044 : if (clz_ctz_arg1)
3517 : 3 : vargs[varg++] = clz_ctz_arg1;
3518 : :
3519 : 1044 : gimple *new_stmt;
3520 : 1044 : if (modifier == NARROW)
3521 : : {
3522 : : /* We don't define any narrowing conditional functions
3523 : : at present. */
3524 : 0 : gcc_assert (mask_opno < 0);
3525 : 0 : tree half_res = make_ssa_name (vectype_in);
3526 : 0 : gcall *call
3527 : 0 : = gimple_build_call_internal_vec (ifn, vargs);
3528 : 0 : gimple_call_set_lhs (call, half_res);
3529 : 0 : gimple_call_set_nothrow (call, true);
3530 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3531 : 0 : if ((i & 1) == 0)
3532 : : {
3533 : 0 : prev_res = half_res;
3534 : 0 : continue;
3535 : : }
3536 : 0 : new_temp = make_ssa_name (vec_dest);
3537 : 0 : new_stmt = vect_gimple_build (new_temp, convert_code,
3538 : : prev_res, half_res);
3539 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
3540 : : new_stmt, gsi);
3541 : : }
3542 : : else
3543 : : {
3544 : 1044 : if (len_opno >= 0 && len_loop_p)
3545 : : {
3546 : 0 : unsigned int vec_num = vec_oprnds0.length ();
3547 : : /* Always true for SLP. */
3548 : 0 : gcc_assert (ncopies == 1);
3549 : 0 : tree len
3550 : 0 : = vect_get_loop_len (loop_vinfo, gsi, lens, vec_num,
3551 : : vectype_out, i, 1);
3552 : 0 : signed char biasval
3553 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
3554 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
3555 : 0 : vargs[len_opno] = len;
3556 : 0 : vargs[len_opno + 1] = bias;
3557 : : }
3558 : 1044 : else if (mask_opno >= 0 && masked_loop_p)
3559 : : {
3560 : 36 : unsigned int vec_num = vec_oprnds0.length ();
3561 : : /* Always true for SLP. */
3562 : 36 : gcc_assert (ncopies == 1);
3563 : 36 : tree mask = vect_get_loop_mask (loop_vinfo,
3564 : : gsi, masks, vec_num,
3565 : : vectype_out, i);
3566 : 36 : vargs[mask_opno] = prepare_vec_mask
3567 : 36 : (loop_vinfo, TREE_TYPE (mask), mask,
3568 : 36 : vargs[mask_opno], gsi);
3569 : : }
3570 : :
3571 : 1044 : gcall *call;
3572 : 1044 : if (ifn != IFN_LAST)
3573 : 1044 : call = gimple_build_call_internal_vec (ifn, vargs);
3574 : : else
3575 : 0 : call = gimple_build_call_vec (fndecl, vargs);
3576 : 1044 : new_temp = make_ssa_name (vec_dest, call);
3577 : 1044 : gimple_call_set_lhs (call, new_temp);
3578 : 1044 : gimple_call_set_nothrow (call, true);
3579 : 1044 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3580 : 1044 : new_stmt = call;
3581 : : }
3582 : 1044 : slp_node->push_vec_def (new_stmt);
3583 : : }
3584 : 962 : continue;
3585 : 962 : }
3586 : :
3587 : 3056 : int varg = 0;
3588 : 3056 : if (masked_loop_p && reduc_idx >= 0)
3589 : 0 : vargs[varg++] = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies,
3590 : : vectype_out, j);
3591 : 7091 : for (i = 0; i < nargs; i++)
3592 : : {
3593 : 4035 : op = gimple_call_arg (stmt, i);
3594 : 4035 : if (j == 0)
3595 : : {
3596 : 3893 : vec_defs.quick_push (vNULL);
3597 : 7786 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
3598 : 3893 : op, &vec_defs[i],
3599 : : vectypes[i]);
3600 : : }
3601 : 4035 : vargs[varg++] = vec_defs[i][j];
3602 : : }
3603 : 3056 : if (masked_loop_p && reduc_idx >= 0)
3604 : 0 : vargs[varg++] = vargs[reduc_idx + 1];
3605 : 3056 : if (clz_ctz_arg1)
3606 : 56 : vargs[varg++] = clz_ctz_arg1;
3607 : :
3608 : 3056 : if (len_opno >= 0 && len_loop_p)
3609 : : {
3610 : 0 : tree len = vect_get_loop_len (loop_vinfo, gsi, lens, ncopies,
3611 : : vectype_out, j, 1);
3612 : 0 : signed char biasval
3613 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
3614 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
3615 : 0 : vargs[len_opno] = len;
3616 : 0 : vargs[len_opno + 1] = bias;
3617 : : }
3618 : 3056 : else if (mask_opno >= 0 && masked_loop_p)
3619 : : {
3620 : 0 : tree mask = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies,
3621 : : vectype_out, j);
3622 : 0 : vargs[mask_opno]
3623 : 0 : = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
3624 : 0 : vargs[mask_opno], gsi);
3625 : : }
3626 : :
3627 : 3056 : gimple *new_stmt;
3628 : 3056 : if (cfn == CFN_GOMP_SIMD_LANE)
3629 : : {
3630 : 1726 : tree cst = build_index_vector (vectype_out, j * nunits_out, 1);
3631 : 1726 : tree new_var
3632 : 1726 : = vect_get_new_ssa_name (vectype_out, vect_simple_var, "cst_");
3633 : 1726 : gimple *init_stmt = gimple_build_assign (new_var, cst);
3634 : 1726 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, NULL);
3635 : 1726 : new_temp = make_ssa_name (vec_dest);
3636 : 1726 : new_stmt = gimple_build_assign (new_temp, new_var);
3637 : 1726 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3638 : : }
3639 : 1330 : else if (modifier == NARROW)
3640 : : {
3641 : : /* We don't define any narrowing conditional functions at
3642 : : present. */
3643 : 0 : gcc_assert (mask_opno < 0);
3644 : 0 : tree half_res = make_ssa_name (vectype_in);
3645 : 0 : gcall *call = gimple_build_call_internal_vec (ifn, vargs);
3646 : 0 : gimple_call_set_lhs (call, half_res);
3647 : 0 : gimple_call_set_nothrow (call, true);
3648 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3649 : 0 : if ((j & 1) == 0)
3650 : : {
3651 : 0 : prev_res = half_res;
3652 : 0 : continue;
3653 : : }
3654 : 0 : new_temp = make_ssa_name (vec_dest);
3655 : 0 : new_stmt = vect_gimple_build (new_temp, convert_code, prev_res,
3656 : : half_res);
3657 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3658 : : }
3659 : : else
3660 : : {
3661 : 1330 : gcall *call;
3662 : 1330 : if (ifn != IFN_LAST)
3663 : 1326 : call = gimple_build_call_internal_vec (ifn, vargs);
3664 : : else
3665 : 4 : call = gimple_build_call_vec (fndecl, vargs);
3666 : 1330 : new_temp = make_ssa_name (vec_dest, call);
3667 : 1330 : gimple_call_set_lhs (call, new_temp);
3668 : 1330 : gimple_call_set_nothrow (call, true);
3669 : 1330 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3670 : 1330 : new_stmt = call;
3671 : : }
3672 : :
3673 : 6112 : if (j == (modifier == NARROW ? 1 : 0))
3674 : 2887 : *vec_stmt = new_stmt;
3675 : 3056 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
3676 : : }
3677 : 10138 : for (i = 0; i < nargs; i++)
3678 : : {
3679 : 6289 : vec<tree> vec_oprndsi = vec_defs[i];
3680 : 6289 : vec_oprndsi.release ();
3681 : : }
3682 : 3849 : }
3683 : 32 : else if (modifier == NARROW)
3684 : : {
3685 : 32 : auto_vec<vec<tree> > vec_defs (nargs);
3686 : : /* We don't define any narrowing conditional functions at present. */
3687 : 32 : gcc_assert (mask_opno < 0);
3688 : 64 : for (j = 0; j < ncopies; ++j)
3689 : : {
3690 : : /* Build argument list for the vectorized call. */
3691 : 32 : if (j == 0)
3692 : 32 : vargs.create (nargs * 2);
3693 : : else
3694 : 0 : vargs.truncate (0);
3695 : :
3696 : 32 : if (slp_node)
3697 : : {
3698 : 0 : vec<tree> vec_oprnds0;
3699 : :
3700 : 0 : vect_get_slp_defs (vinfo, slp_node, &vec_defs);
3701 : 0 : vec_oprnds0 = vec_defs[0];
3702 : :
3703 : : /* Arguments are ready. Create the new vector stmt. */
3704 : 0 : for (i = 0; vec_oprnds0.iterate (i, &vec_oprnd0); i += 2)
3705 : : {
3706 : 0 : size_t k;
3707 : 0 : vargs.truncate (0);
3708 : 0 : for (k = 0; k < nargs; k++)
3709 : : {
3710 : 0 : vec<tree> vec_oprndsk = vec_defs[k];
3711 : 0 : vargs.quick_push (vec_oprndsk[i]);
3712 : 0 : vargs.quick_push (vec_oprndsk[i + 1]);
3713 : : }
3714 : 0 : gcall *call;
3715 : 0 : if (ifn != IFN_LAST)
3716 : : call = gimple_build_call_internal_vec (ifn, vargs);
3717 : : else
3718 : 0 : call = gimple_build_call_vec (fndecl, vargs);
3719 : 0 : new_temp = make_ssa_name (vec_dest, call);
3720 : 0 : gimple_call_set_lhs (call, new_temp);
3721 : 0 : gimple_call_set_nothrow (call, true);
3722 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3723 : 0 : slp_node->push_vec_def (call);
3724 : : }
3725 : 0 : continue;
3726 : 0 : }
3727 : :
3728 : 64 : for (i = 0; i < nargs; i++)
3729 : : {
3730 : 32 : op = gimple_call_arg (stmt, i);
3731 : 32 : if (j == 0)
3732 : : {
3733 : 32 : vec_defs.quick_push (vNULL);
3734 : 64 : vect_get_vec_defs_for_operand (vinfo, stmt_info, 2 * ncopies,
3735 : 32 : op, &vec_defs[i], vectypes[i]);
3736 : : }
3737 : 32 : vec_oprnd0 = vec_defs[i][2*j];
3738 : 32 : vec_oprnd1 = vec_defs[i][2*j+1];
3739 : :
3740 : 32 : vargs.quick_push (vec_oprnd0);
3741 : 32 : vargs.quick_push (vec_oprnd1);
3742 : : }
3743 : :
3744 : 32 : gcall *new_stmt = gimple_build_call_vec (fndecl, vargs);
3745 : 32 : new_temp = make_ssa_name (vec_dest, new_stmt);
3746 : 32 : gimple_call_set_lhs (new_stmt, new_temp);
3747 : 32 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3748 : :
3749 : 32 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
3750 : : }
3751 : :
3752 : 32 : if (!slp_node)
3753 : 32 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
3754 : :
3755 : 64 : for (i = 0; i < nargs; i++)
3756 : : {
3757 : 32 : vec<tree> vec_oprndsi = vec_defs[i];
3758 : 32 : vec_oprndsi.release ();
3759 : : }
3760 : 32 : }
3761 : : else
3762 : : /* No current target implements this case. */
3763 : : return false;
3764 : :
3765 : 3881 : vargs.release ();
3766 : :
3767 : : /* The call in STMT might prevent it from being removed in dce.
3768 : : We however cannot remove it here, due to the way the ssa name
3769 : : it defines is mapped to the new definition. So just replace
3770 : : rhs of the statement with something harmless. */
3771 : :
3772 : 3881 : if (slp_node)
3773 : : return true;
3774 : :
3775 : 2919 : stmt_info = vect_orig_stmt (stmt_info);
3776 : 2919 : lhs = gimple_get_lhs (stmt_info->stmt);
3777 : :
3778 : 2919 : gassign *new_stmt
3779 : 2919 : = gimple_build_assign (lhs, build_zero_cst (TREE_TYPE (lhs)));
3780 : 2919 : vinfo->replace_stmt (gsi, stmt_info, new_stmt);
3781 : :
3782 : 2919 : return true;
3783 : 1798331 : }
3784 : :
3785 : :
3786 : : struct simd_call_arg_info
3787 : : {
3788 : : tree vectype;
3789 : : tree op;
3790 : : HOST_WIDE_INT linear_step;
3791 : : enum vect_def_type dt;
3792 : : unsigned int align;
3793 : : bool simd_lane_linear;
3794 : : };
3795 : :
3796 : : /* Helper function of vectorizable_simd_clone_call. If OP, an SSA_NAME,
3797 : : is linear within simd lane (but not within whole loop), note it in
3798 : : *ARGINFO. */
3799 : :
3800 : : static void
3801 : 17 : vect_simd_lane_linear (tree op, class loop *loop,
3802 : : struct simd_call_arg_info *arginfo)
3803 : : {
3804 : 17 : gimple *def_stmt = SSA_NAME_DEF_STMT (op);
3805 : :
3806 : 17 : if (!is_gimple_assign (def_stmt)
3807 : 17 : || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR
3808 : 31 : || !is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt)))
3809 : 5 : return;
3810 : :
3811 : 12 : tree base = gimple_assign_rhs1 (def_stmt);
3812 : 12 : HOST_WIDE_INT linear_step = 0;
3813 : 12 : tree v = gimple_assign_rhs2 (def_stmt);
3814 : 48 : while (TREE_CODE (v) == SSA_NAME)
3815 : : {
3816 : 36 : tree t;
3817 : 36 : def_stmt = SSA_NAME_DEF_STMT (v);
3818 : 36 : if (is_gimple_assign (def_stmt))
3819 : 24 : switch (gimple_assign_rhs_code (def_stmt))
3820 : : {
3821 : 0 : case PLUS_EXPR:
3822 : 0 : t = gimple_assign_rhs2 (def_stmt);
3823 : 0 : if (linear_step || TREE_CODE (t) != INTEGER_CST)
3824 : : return;
3825 : 0 : base = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, t);
3826 : 0 : v = gimple_assign_rhs1 (def_stmt);
3827 : 0 : continue;
3828 : 12 : case MULT_EXPR:
3829 : 12 : t = gimple_assign_rhs2 (def_stmt);
3830 : 12 : if (linear_step || !tree_fits_shwi_p (t) || integer_zerop (t))
3831 : 0 : return;
3832 : 12 : linear_step = tree_to_shwi (t);
3833 : 12 : v = gimple_assign_rhs1 (def_stmt);
3834 : 12 : continue;
3835 : 12 : CASE_CONVERT:
3836 : 12 : t = gimple_assign_rhs1 (def_stmt);
3837 : 12 : if (TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE
3838 : 12 : || (TYPE_PRECISION (TREE_TYPE (v))
3839 : 12 : < TYPE_PRECISION (TREE_TYPE (t))))
3840 : : return;
3841 : 12 : if (!linear_step)
3842 : 0 : linear_step = 1;
3843 : 12 : v = t;
3844 : 12 : continue;
3845 : : default:
3846 : : return;
3847 : : }
3848 : 12 : else if (gimple_call_internal_p (def_stmt, IFN_GOMP_SIMD_LANE)
3849 : 12 : && loop->simduid
3850 : 12 : && TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME
3851 : 24 : && (SSA_NAME_VAR (gimple_call_arg (def_stmt, 0))
3852 : : == loop->simduid))
3853 : : {
3854 : 12 : if (!linear_step)
3855 : 0 : linear_step = 1;
3856 : 12 : arginfo->linear_step = linear_step;
3857 : 12 : arginfo->op = base;
3858 : 12 : arginfo->simd_lane_linear = true;
3859 : 12 : return;
3860 : : }
3861 : : }
3862 : : }
3863 : :
3864 : : /* Function vectorizable_simd_clone_call.
3865 : :
3866 : : Check if STMT_INFO performs a function call that can be vectorized
3867 : : by calling a simd clone of the function.
3868 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
3869 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
3870 : : Return true if STMT_INFO is vectorizable in this way. */
3871 : :
3872 : : static bool
3873 : 1789198 : vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
3874 : : gimple_stmt_iterator *gsi,
3875 : : gimple **vec_stmt, slp_tree slp_node,
3876 : : stmt_vector_for_cost *)
3877 : : {
3878 : 1789198 : tree vec_dest;
3879 : 1789198 : tree scalar_dest;
3880 : 1789198 : tree op, type;
3881 : 1789198 : tree vec_oprnd0 = NULL_TREE;
3882 : 1789198 : tree vectype;
3883 : 1789198 : poly_uint64 nunits;
3884 : 1789198 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
3885 : 1789198 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
3886 : 1789198 : class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
3887 : 1789198 : tree fndecl, new_temp;
3888 : 1789198 : int ncopies, j;
3889 : 1789198 : auto_vec<simd_call_arg_info> arginfo;
3890 : 1789198 : vec<tree> vargs = vNULL;
3891 : 1789198 : size_t i, nargs;
3892 : 1789198 : tree lhs, rtype, ratype;
3893 : 1789198 : vec<constructor_elt, va_gc> *ret_ctor_elts = NULL;
3894 : 1789198 : int masked_call_offset = 0;
3895 : :
3896 : : /* Is STMT a vectorizable call? */
3897 : 1789198 : gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt);
3898 : 9146 : if (!stmt)
3899 : : return false;
3900 : :
3901 : 9146 : fndecl = gimple_call_fndecl (stmt);
3902 : 9146 : if (fndecl == NULL_TREE
3903 : 9146 : && gimple_call_internal_p (stmt, IFN_MASK_CALL))
3904 : : {
3905 : 143 : fndecl = gimple_call_arg (stmt, 0);
3906 : 143 : gcc_checking_assert (TREE_CODE (fndecl) == ADDR_EXPR);
3907 : 143 : fndecl = TREE_OPERAND (fndecl, 0);
3908 : 143 : gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
3909 : : masked_call_offset = 1;
3910 : : }
3911 : 9003 : if (fndecl == NULL_TREE)
3912 : : return false;
3913 : :
3914 : 3787 : struct cgraph_node *node = cgraph_node::get (fndecl);
3915 : 3787 : if (node == NULL || node->simd_clones == NULL)
3916 : : return false;
3917 : :
3918 : 1425 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
3919 : : return false;
3920 : :
3921 : 1425 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
3922 : 0 : && ! vec_stmt)
3923 : : return false;
3924 : :
3925 : 1425 : if (gimple_call_lhs (stmt)
3926 : 1425 : && TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME)
3927 : : return false;
3928 : :
3929 : 1425 : gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
3930 : :
3931 : 1425 : vectype = STMT_VINFO_VECTYPE (stmt_info);
3932 : :
3933 : 1789198 : if (loop_vinfo && nested_in_vect_loop_p (loop, stmt_info))
3934 : : return false;
3935 : :
3936 : : /* Process function arguments. */
3937 : 1425 : nargs = gimple_call_num_args (stmt) - masked_call_offset;
3938 : :
3939 : : /* Bail out if the function has zero arguments. */
3940 : 1425 : if (nargs == 0)
3941 : : return false;
3942 : :
3943 : 1425 : vec<tree>& simd_clone_info = (slp_node ? SLP_TREE_SIMD_CLONE_INFO (slp_node)
3944 : : : STMT_VINFO_SIMD_CLONE_INFO (stmt_info));
3945 : 1425 : arginfo.reserve (nargs, true);
3946 : 1425 : auto_vec<slp_tree> slp_op;
3947 : 1425 : slp_op.safe_grow_cleared (nargs);
3948 : :
3949 : 4044 : for (i = 0; i < nargs; i++)
3950 : : {
3951 : 2619 : simd_call_arg_info thisarginfo;
3952 : 2619 : affine_iv iv;
3953 : :
3954 : 2619 : thisarginfo.linear_step = 0;
3955 : 2619 : thisarginfo.align = 0;
3956 : 2619 : thisarginfo.op = NULL_TREE;
3957 : 2619 : thisarginfo.simd_lane_linear = false;
3958 : :
3959 : 2619 : int op_no = i + masked_call_offset;
3960 : 2619 : if (slp_node)
3961 : 621 : op_no = vect_slp_child_index_for_operand (stmt, op_no, false);
3962 : 5238 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
3963 : 2619 : op_no, &op, &slp_op[i],
3964 : : &thisarginfo.dt, &thisarginfo.vectype)
3965 : 2619 : || thisarginfo.dt == vect_uninitialized_def)
3966 : : {
3967 : 0 : if (dump_enabled_p ())
3968 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3969 : : "use not simple.\n");
3970 : 0 : return false;
3971 : : }
3972 : :
3973 : 2619 : if (thisarginfo.dt == vect_constant_def
3974 : 2619 : || thisarginfo.dt == vect_external_def)
3975 : : {
3976 : : /* With SLP we determine the vector type of constants/externals
3977 : : at analysis time, handling conflicts via
3978 : : vect_maybe_update_slp_op_vectype. At transform time
3979 : : we have a vector type recorded for SLP. */
3980 : 851 : gcc_assert (!vec_stmt
3981 : : || !slp_node
3982 : : || thisarginfo.vectype != NULL_TREE);
3983 : 851 : if (!vec_stmt)
3984 : 713 : thisarginfo.vectype = get_vectype_for_scalar_type (vinfo,
3985 : 713 : TREE_TYPE (op),
3986 : : slp_node);
3987 : : }
3988 : : else
3989 : 1768 : gcc_assert (thisarginfo.vectype != NULL_TREE);
3990 : :
3991 : : /* For linear arguments, the analyze phase should have saved
3992 : : the base and step in {STMT_VINFO,SLP_TREE}_SIMD_CLONE_INFO. */
3993 : 2619 : if (i * 3 + 4 <= simd_clone_info.length ()
3994 : 2619 : && simd_clone_info[i * 3 + 2])
3995 : : {
3996 : 133 : gcc_assert (vec_stmt);
3997 : 133 : thisarginfo.linear_step = tree_to_shwi (simd_clone_info[i * 3 + 2]);
3998 : 133 : thisarginfo.op = simd_clone_info[i * 3 + 1];
3999 : 133 : thisarginfo.simd_lane_linear
4000 : 133 : = (simd_clone_info[i * 3 + 3] == boolean_true_node);
4001 : : /* If loop has been peeled for alignment, we need to adjust it. */
4002 : 133 : tree n1 = LOOP_VINFO_NITERS_UNCHANGED (loop_vinfo);
4003 : 133 : tree n2 = LOOP_VINFO_NITERS (loop_vinfo);
4004 : 133 : if (n1 != n2 && !thisarginfo.simd_lane_linear)
4005 : : {
4006 : 0 : tree bias = fold_build2 (MINUS_EXPR, TREE_TYPE (n1), n1, n2);
4007 : 0 : tree step = simd_clone_info[i * 3 + 2];
4008 : 0 : tree opt = TREE_TYPE (thisarginfo.op);
4009 : 0 : bias = fold_convert (TREE_TYPE (step), bias);
4010 : 0 : bias = fold_build2 (MULT_EXPR, TREE_TYPE (step), bias, step);
4011 : 0 : thisarginfo.op
4012 : 0 : = fold_build2 (POINTER_TYPE_P (opt)
4013 : : ? POINTER_PLUS_EXPR : PLUS_EXPR, opt,
4014 : : thisarginfo.op, bias);
4015 : : }
4016 : : }
4017 : 2486 : else if (!vec_stmt
4018 : 1853 : && thisarginfo.dt != vect_constant_def
4019 : 1677 : && thisarginfo.dt != vect_external_def
4020 : 1140 : && loop_vinfo
4021 : 1095 : && TREE_CODE (op) == SSA_NAME
4022 : 2190 : && simple_iv (loop, loop_containing_stmt (stmt), op,
4023 : : &iv, false)
4024 : 2709 : && tree_fits_shwi_p (iv.step))
4025 : : {
4026 : 223 : thisarginfo.linear_step = tree_to_shwi (iv.step);
4027 : 223 : thisarginfo.op = iv.base;
4028 : : }
4029 : 2263 : else if ((thisarginfo.dt == vect_constant_def
4030 : 2263 : || thisarginfo.dt == vect_external_def)
4031 : 2263 : && POINTER_TYPE_P (TREE_TYPE (op)))
4032 : 572 : thisarginfo.align = get_pointer_alignment (op) / BITS_PER_UNIT;
4033 : : /* Addresses of array elements indexed by GOMP_SIMD_LANE are
4034 : : linear too. */
4035 : 4552 : if (POINTER_TYPE_P (TREE_TYPE (op))
4036 : 686 : && !thisarginfo.linear_step
4037 : 600 : && !vec_stmt
4038 : 529 : && thisarginfo.dt != vect_constant_def
4039 : 529 : && thisarginfo.dt != vect_external_def
4040 : 17 : && loop_vinfo
4041 : 2636 : && TREE_CODE (op) == SSA_NAME)
4042 : 17 : vect_simd_lane_linear (op, loop, &thisarginfo);
4043 : :
4044 : 2619 : arginfo.quick_push (thisarginfo);
4045 : : }
4046 : :
4047 : 1425 : poly_uint64 vf = loop_vinfo ? LOOP_VINFO_VECT_FACTOR (loop_vinfo) : 1;
4048 : 1425 : unsigned group_size = slp_node ? SLP_TREE_LANES (slp_node) : 1;
4049 : 1425 : unsigned int badness = 0;
4050 : 1425 : struct cgraph_node *bestn = NULL;
4051 : 1425 : if (simd_clone_info.exists ())
4052 : 343 : bestn = cgraph_node::get (simd_clone_info[0]);
4053 : : else
4054 : 6416 : for (struct cgraph_node *n = node->simd_clones; n != NULL;
4055 : 5334 : n = n->simdclone->next_clone)
4056 : : {
4057 : 5334 : unsigned int this_badness = 0;
4058 : 5334 : unsigned int num_calls;
4059 : : /* The number of arguments in the call and the number of parameters in
4060 : : the simdclone should match. However, when the simdclone is
4061 : : 'inbranch', it could have one more paramater than nargs when using
4062 : : an inbranch simdclone to call a non-inbranch call, either in a
4063 : : non-masked loop using a all true constant mask, or inside a masked
4064 : : loop using it's mask. */
4065 : 5334 : size_t simd_nargs = n->simdclone->nargs;
4066 : 5334 : if (!masked_call_offset && n->simdclone->inbranch)
4067 : 2791 : simd_nargs--;
4068 : 5334 : if (!constant_multiple_p (vf * group_size, n->simdclone->simdlen,
4069 : : &num_calls)
4070 : 1971 : || (!n->simdclone->inbranch && (masked_call_offset > 0))
4071 : 7217 : || (nargs != simd_nargs))
4072 : 3451 : continue;
4073 : 1883 : if (num_calls != 1)
4074 : 944 : this_badness += floor_log2 (num_calls) * 4096;
4075 : 1883 : if (n->simdclone->inbranch)
4076 : 759 : this_badness += 8192;
4077 : 1883 : int target_badness = targetm.simd_clone.usable (n);
4078 : 1883 : if (target_badness < 0)
4079 : 346 : continue;
4080 : 1537 : this_badness += target_badness * 512;
4081 : 4714 : for (i = 0; i < nargs; i++)
4082 : : {
4083 : 3304 : switch (n->simdclone->args[i].arg_type)
4084 : : {
4085 : 2409 : case SIMD_CLONE_ARG_TYPE_VECTOR:
4086 : 2409 : if (!useless_type_conversion_p
4087 : 2409 : (n->simdclone->args[i].orig_type,
4088 : 2409 : TREE_TYPE (gimple_call_arg (stmt,
4089 : : i + masked_call_offset))))
4090 : : i = -1;
4091 : 2341 : else if (arginfo[i].dt == vect_constant_def
4092 : 1993 : || arginfo[i].dt == vect_external_def
4093 : 4178 : || arginfo[i].linear_step)
4094 : 740 : this_badness += 64;
4095 : : break;
4096 : 348 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
4097 : 348 : if (arginfo[i].dt != vect_constant_def
4098 : 348 : && arginfo[i].dt != vect_external_def)
4099 : : i = -1;
4100 : : break;
4101 : 374 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4102 : 374 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4103 : 374 : if (arginfo[i].dt == vect_constant_def
4104 : 374 : || arginfo[i].dt == vect_external_def
4105 : 374 : || (arginfo[i].linear_step
4106 : 374 : != n->simdclone->args[i].linear_step))
4107 : : i = -1;
4108 : : break;
4109 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
4110 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
4111 : : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
4112 : : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
4113 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
4114 : : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
4115 : : /* FORNOW */
4116 : : i = -1;
4117 : : break;
4118 : 173 : case SIMD_CLONE_ARG_TYPE_MASK:
4119 : : /* While we can create a traditional data vector from
4120 : : an incoming integer mode mask we have no good way to
4121 : : force generate an integer mode mask from a traditional
4122 : : boolean vector input. */
4123 : 173 : if (SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4124 : 173 : && !SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype)))
4125 : : i = -1;
4126 : 169 : else if (!SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4127 : 169 : && SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype)))
4128 : 30 : this_badness += 2048;
4129 : : break;
4130 : : }
4131 : 3177 : if (i == (size_t) -1)
4132 : : break;
4133 : 3177 : if (n->simdclone->args[i].alignment > arginfo[i].align)
4134 : : {
4135 : : i = -1;
4136 : : break;
4137 : : }
4138 : 3177 : if (arginfo[i].align)
4139 : 156 : this_badness += (exact_log2 (arginfo[i].align)
4140 : 232 : - exact_log2 (n->simdclone->args[i].alignment));
4141 : : }
4142 : 1537 : if (i == (size_t) -1)
4143 : 127 : continue;
4144 : 1410 : if (masked_call_offset == 0
4145 : 1241 : && n->simdclone->inbranch
4146 : 423 : && n->simdclone->nargs > nargs)
4147 : : {
4148 : 423 : gcc_assert (n->simdclone->args[n->simdclone->nargs - 1].arg_type ==
4149 : : SIMD_CLONE_ARG_TYPE_MASK);
4150 : : /* Penalize using a masked SIMD clone in a non-masked loop, that is
4151 : : not in a branch, as we'd have to construct an all-true mask. */
4152 : 423 : if (!loop_vinfo || !LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4153 : 423 : this_badness += 64;
4154 : : }
4155 : 1410 : if (bestn == NULL || this_badness < badness)
4156 : : {
4157 : 5334 : bestn = n;
4158 : 5334 : badness = this_badness;
4159 : : }
4160 : : }
4161 : :
4162 : 1425 : if (bestn == NULL)
4163 : : return false;
4164 : :
4165 : 872 : unsigned int num_mask_args = 0;
4166 : 872 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4167 : 99 : for (i = 0; i < nargs; i++)
4168 : 62 : if (bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
4169 : 13 : num_mask_args++;
4170 : :
4171 : 2793 : for (i = 0; i < nargs; i++)
4172 : : {
4173 : 1942 : if ((arginfo[i].dt == vect_constant_def
4174 : 1722 : || arginfo[i].dt == vect_external_def)
4175 : 2094 : && bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
4176 : : {
4177 : 157 : tree arg_type = TREE_TYPE (gimple_call_arg (stmt,
4178 : : i + masked_call_offset));
4179 : 157 : arginfo[i].vectype = get_vectype_for_scalar_type (vinfo, arg_type,
4180 : : slp_node);
4181 : 157 : if (arginfo[i].vectype == NULL
4182 : 314 : || !constant_multiple_p (bestn->simdclone->simdlen,
4183 : 314 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4184 : 0 : return false;
4185 : : }
4186 : :
4187 : 1942 : if (bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR
4188 : 1942 : && VECTOR_BOOLEAN_TYPE_P (bestn->simdclone->args[i].vector_type))
4189 : : {
4190 : 0 : if (dump_enabled_p ())
4191 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4192 : : "vector mask arguments are not supported.\n");
4193 : 0 : return false;
4194 : : }
4195 : :
4196 : 1942 : if (bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
4197 : : {
4198 : 118 : tree clone_arg_vectype = bestn->simdclone->args[i].vector_type;
4199 : 118 : if (bestn->simdclone->mask_mode == VOIDmode)
4200 : : {
4201 : 105 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (clone_arg_vectype),
4202 : 210 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4203 : : {
4204 : : /* FORNOW we only have partial support for vector-type masks
4205 : : that can't hold all of simdlen. */
4206 : 10 : if (dump_enabled_p ())
4207 : 10 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4208 : : vect_location,
4209 : : "in-branch vector clones are not yet"
4210 : : " supported for mismatched vector sizes.\n");
4211 : 10 : return false;
4212 : : }
4213 : 95 : if (!expand_vec_cond_expr_p (clone_arg_vectype,
4214 : 95 : arginfo[i].vectype, ERROR_MARK))
4215 : : {
4216 : 4 : if (dump_enabled_p ())
4217 : 4 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4218 : : vect_location,
4219 : : "cannot compute mask argument for"
4220 : : " in-branch vector clones.\n");
4221 : 4 : return false;
4222 : : }
4223 : : }
4224 : 13 : else if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4225 : : {
4226 : 13 : if (!SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype))
4227 : 26 : || maybe_ne (exact_div (bestn->simdclone->simdlen,
4228 : : num_mask_args),
4229 : 19 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4230 : : {
4231 : : /* FORNOW we only have partial support for integer-type masks
4232 : : that represent the same number of lanes as the
4233 : : vectorized mask inputs. */
4234 : 7 : if (dump_enabled_p ())
4235 : 4 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4236 : : vect_location,
4237 : : "in-branch vector clones are not yet "
4238 : : "supported for mismatched vector sizes.\n");
4239 : 7 : return false;
4240 : : }
4241 : : }
4242 : : else
4243 : : {
4244 : 0 : if (dump_enabled_p ())
4245 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4246 : : vect_location,
4247 : : "in-branch vector clones not supported"
4248 : : " on this target.\n");
4249 : 0 : return false;
4250 : : }
4251 : : }
4252 : : }
4253 : :
4254 : 851 : fndecl = bestn->decl;
4255 : 851 : nunits = bestn->simdclone->simdlen;
4256 : 851 : if (slp_node)
4257 : 76 : ncopies = vector_unroll_factor (vf * group_size, nunits);
4258 : : else
4259 : 775 : ncopies = vector_unroll_factor (vf, nunits);
4260 : :
4261 : : /* If the function isn't const, only allow it in simd loops where user
4262 : : has asserted that at least nunits consecutive iterations can be
4263 : : performed using SIMD instructions. */
4264 : 789 : if ((loop == NULL || maybe_lt ((unsigned) loop->safelen, nunits))
4265 : 1050 : && gimple_vuse (stmt))
4266 : : return false;
4267 : :
4268 : : /* Sanity check: make sure that at least one copy of the vectorized stmt
4269 : : needs to be generated. */
4270 : 851 : gcc_assert (ncopies >= 1);
4271 : :
4272 : 851 : if (!vec_stmt) /* transformation not required. */
4273 : : {
4274 : 509 : if (slp_node)
4275 : 209 : for (unsigned i = 0; i < nargs; ++i)
4276 : 140 : if (!vect_maybe_update_slp_op_vectype (slp_op[i], arginfo[i].vectype))
4277 : : {
4278 : 0 : if (dump_enabled_p ())
4279 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4280 : : "incompatible vector types for invariants\n");
4281 : 0 : return false;
4282 : : }
4283 : : /* When the original call is pure or const but the SIMD ABI dictates
4284 : : an aggregate return we will have to use a virtual definition and
4285 : : in a loop eventually even need to add a virtual PHI. That's
4286 : : not straight-forward so allow to fix this up via renaming. */
4287 : 509 : if (gimple_call_lhs (stmt)
4288 : 500 : && !gimple_vdef (stmt)
4289 : 908 : && TREE_CODE (TREE_TYPE (TREE_TYPE (bestn->decl))) == ARRAY_TYPE)
4290 : 21 : vinfo->any_known_not_updated_vssa = true;
4291 : : /* ??? For SLP code-gen we end up inserting after the last
4292 : : vector argument def rather than at the original call position
4293 : : so automagic virtual operand updating doesn't work. */
4294 : 1018 : if (gimple_vuse (stmt) && slp_node)
4295 : 0 : vinfo->any_known_not_updated_vssa = true;
4296 : 509 : simd_clone_info.safe_push (bestn->decl);
4297 : 1647 : for (i = 0; i < bestn->simdclone->nargs; i++)
4298 : : {
4299 : 1138 : switch (bestn->simdclone->args[i].arg_type)
4300 : : {
4301 : 940 : default:
4302 : 940 : continue;
4303 : 133 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4304 : 133 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4305 : 133 : {
4306 : 133 : simd_clone_info.safe_grow_cleared (i * 3 + 1, true);
4307 : 133 : simd_clone_info.safe_push (arginfo[i].op);
4308 : 226 : tree lst = POINTER_TYPE_P (TREE_TYPE (arginfo[i].op))
4309 : 226 : ? size_type_node : TREE_TYPE (arginfo[i].op);
4310 : 133 : tree ls = build_int_cst (lst, arginfo[i].linear_step);
4311 : 133 : simd_clone_info.safe_push (ls);
4312 : 133 : tree sll = arginfo[i].simd_lane_linear
4313 : 133 : ? boolean_true_node : boolean_false_node;
4314 : 133 : simd_clone_info.safe_push (sll);
4315 : : }
4316 : 133 : break;
4317 : 65 : case SIMD_CLONE_ARG_TYPE_MASK:
4318 : 65 : if (loop_vinfo
4319 : 65 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
4320 : 0 : vect_record_loop_mask (loop_vinfo,
4321 : : &LOOP_VINFO_MASKS (loop_vinfo),
4322 : : ncopies, vectype, op);
4323 : :
4324 : : break;
4325 : 940 : }
4326 : : }
4327 : :
4328 : 509 : if (!bestn->simdclone->inbranch && loop_vinfo)
4329 : : {
4330 : 383 : if (dump_enabled_p ()
4331 : 383 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
4332 : 3 : dump_printf_loc (MSG_NOTE, vect_location,
4333 : : "can't use a fully-masked loop because a"
4334 : : " non-masked simd clone was selected.\n");
4335 : 383 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
4336 : : }
4337 : :
4338 : 509 : STMT_VINFO_TYPE (stmt_info) = call_simd_clone_vec_info_type;
4339 : 509 : DUMP_VECT_SCOPE ("vectorizable_simd_clone_call");
4340 : : /* vect_model_simple_cost (vinfo, stmt_info, ncopies,
4341 : : dt, slp_node, cost_vec); */
4342 : 509 : return true;
4343 : : }
4344 : :
4345 : : /* Transform. */
4346 : :
4347 : 342 : if (dump_enabled_p ())
4348 : 241 : dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n");
4349 : :
4350 : : /* Handle def. */
4351 : 342 : scalar_dest = gimple_call_lhs (stmt);
4352 : 342 : vec_dest = NULL_TREE;
4353 : 342 : rtype = NULL_TREE;
4354 : 342 : ratype = NULL_TREE;
4355 : 342 : if (scalar_dest)
4356 : : {
4357 : 333 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
4358 : 333 : rtype = TREE_TYPE (TREE_TYPE (fndecl));
4359 : 333 : if (TREE_CODE (rtype) == ARRAY_TYPE)
4360 : : {
4361 : 9 : ratype = rtype;
4362 : 9 : rtype = TREE_TYPE (ratype);
4363 : : }
4364 : : }
4365 : :
4366 : 684 : auto_vec<vec<tree> > vec_oprnds;
4367 : 342 : auto_vec<unsigned> vec_oprnds_i;
4368 : 342 : vec_oprnds_i.safe_grow_cleared (nargs, true);
4369 : 342 : if (slp_node)
4370 : : {
4371 : 7 : vec_oprnds.reserve_exact (nargs);
4372 : 7 : vect_get_slp_defs (vinfo, slp_node, &vec_oprnds);
4373 : : }
4374 : : else
4375 : 335 : vec_oprnds.safe_grow_cleared (nargs, true);
4376 : 785 : for (j = 0; j < ncopies; ++j)
4377 : : {
4378 : 443 : poly_uint64 callee_nelements;
4379 : 443 : poly_uint64 caller_nelements;
4380 : : /* Build argument list for the vectorized call. */
4381 : 443 : if (j == 0)
4382 : 342 : vargs.create (nargs);
4383 : : else
4384 : 101 : vargs.truncate (0);
4385 : :
4386 : 1501 : for (i = 0; i < nargs; i++)
4387 : : {
4388 : 1058 : unsigned int k, l, m, o;
4389 : 1058 : tree atype;
4390 : 1058 : op = gimple_call_arg (stmt, i + masked_call_offset);
4391 : 1058 : switch (bestn->simdclone->args[i].arg_type)
4392 : : {
4393 : 772 : case SIMD_CLONE_ARG_TYPE_VECTOR:
4394 : 772 : atype = bestn->simdclone->args[i].vector_type;
4395 : 772 : caller_nelements = TYPE_VECTOR_SUBPARTS (arginfo[i].vectype);
4396 : 772 : callee_nelements = TYPE_VECTOR_SUBPARTS (atype);
4397 : 772 : o = vector_unroll_factor (nunits, callee_nelements);
4398 : 1738 : for (m = j * o; m < (j + 1) * o; m++)
4399 : : {
4400 : 966 : if (known_lt (callee_nelements, caller_nelements))
4401 : : {
4402 : 348 : poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (atype));
4403 : 348 : if (!constant_multiple_p (caller_nelements,
4404 : : callee_nelements, &k))
4405 : 0 : gcc_unreachable ();
4406 : :
4407 : 174 : gcc_assert ((k & (k - 1)) == 0);
4408 : 174 : if (m == 0)
4409 : : {
4410 : 39 : if (!slp_node)
4411 : 78 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
4412 : 39 : ncopies * o / k, op,
4413 : 39 : &vec_oprnds[i]);
4414 : 39 : vec_oprnds_i[i] = 0;
4415 : 39 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4416 : : }
4417 : : else
4418 : : {
4419 : 135 : vec_oprnd0 = arginfo[i].op;
4420 : 135 : if ((m & (k - 1)) == 0)
4421 : 48 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4422 : : }
4423 : 174 : arginfo[i].op = vec_oprnd0;
4424 : 174 : vec_oprnd0
4425 : 174 : = build3 (BIT_FIELD_REF, atype, vec_oprnd0,
4426 : : bitsize_int (prec),
4427 : 174 : bitsize_int ((m & (k - 1)) * prec));
4428 : 174 : gassign *new_stmt
4429 : 174 : = gimple_build_assign (make_ssa_name (atype),
4430 : : vec_oprnd0);
4431 : 174 : vect_finish_stmt_generation (vinfo, stmt_info,
4432 : : new_stmt, gsi);
4433 : 174 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4434 : : }
4435 : : else
4436 : : {
4437 : 1584 : if (!constant_multiple_p (callee_nelements,
4438 : : caller_nelements, &k))
4439 : 0 : gcc_unreachable ();
4440 : 792 : gcc_assert ((k & (k - 1)) == 0);
4441 : 792 : vec<constructor_elt, va_gc> *ctor_elts;
4442 : 792 : if (k != 1)
4443 : 11 : vec_alloc (ctor_elts, k);
4444 : : else
4445 : 781 : ctor_elts = NULL;
4446 : 814 : for (l = 0; l < k; l++)
4447 : : {
4448 : 803 : if (m == 0 && l == 0)
4449 : : {
4450 : 444 : if (!slp_node)
4451 : 862 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
4452 : 431 : k * o * ncopies,
4453 : : op,
4454 : 431 : &vec_oprnds[i]);
4455 : 444 : vec_oprnds_i[i] = 0;
4456 : 444 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4457 : : }
4458 : : else
4459 : 359 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4460 : 803 : arginfo[i].op = vec_oprnd0;
4461 : 803 : if (k == 1)
4462 : : break;
4463 : 22 : CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE,
4464 : : vec_oprnd0);
4465 : : }
4466 : 792 : if (k == 1)
4467 : 781 : if (!useless_type_conversion_p (TREE_TYPE (vec_oprnd0),
4468 : : atype))
4469 : : {
4470 : 0 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, atype,
4471 : : vec_oprnd0);
4472 : 0 : gassign *new_stmt
4473 : 0 : = gimple_build_assign (make_ssa_name (atype),
4474 : : vec_oprnd0);
4475 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
4476 : : new_stmt, gsi);
4477 : 0 : vargs.safe_push (gimple_get_lhs (new_stmt));
4478 : : }
4479 : : else
4480 : 781 : vargs.safe_push (vec_oprnd0);
4481 : : else
4482 : : {
4483 : 11 : vec_oprnd0 = build_constructor (atype, ctor_elts);
4484 : 11 : gassign *new_stmt
4485 : 11 : = gimple_build_assign (make_ssa_name (atype),
4486 : : vec_oprnd0);
4487 : 11 : vect_finish_stmt_generation (vinfo, stmt_info,
4488 : : new_stmt, gsi);
4489 : 11 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4490 : : }
4491 : : }
4492 : : }
4493 : : break;
4494 : 45 : case SIMD_CLONE_ARG_TYPE_MASK:
4495 : 45 : if (bestn->simdclone->mask_mode == VOIDmode)
4496 : : {
4497 : 42 : atype = bestn->simdclone->args[i].vector_type;
4498 : 42 : tree elt_type = TREE_TYPE (atype);
4499 : 42 : tree one = fold_convert (elt_type, integer_one_node);
4500 : 42 : tree zero = fold_convert (elt_type, integer_zero_node);
4501 : 42 : callee_nelements = TYPE_VECTOR_SUBPARTS (atype);
4502 : 42 : caller_nelements = TYPE_VECTOR_SUBPARTS (arginfo[i].vectype);
4503 : 42 : o = vector_unroll_factor (nunits, callee_nelements);
4504 : 84 : for (m = j * o; m < (j + 1) * o; m++)
4505 : : {
4506 : 42 : if (maybe_lt (callee_nelements, caller_nelements))
4507 : : {
4508 : : /* The mask type has fewer elements than simdlen. */
4509 : :
4510 : : /* FORNOW */
4511 : 0 : gcc_unreachable ();
4512 : : }
4513 : 42 : else if (known_eq (callee_nelements, caller_nelements))
4514 : : {
4515 : : /* The SIMD clone function has the same number of
4516 : : elements as the current function. */
4517 : 42 : if (m == 0)
4518 : : {
4519 : 42 : if (!slp_node)
4520 : 78 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
4521 : 39 : o * ncopies,
4522 : : op,
4523 : 39 : &vec_oprnds[i]);
4524 : 42 : vec_oprnds_i[i] = 0;
4525 : : }
4526 : 42 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4527 : 42 : if (loop_vinfo
4528 : 42 : && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4529 : : {
4530 : 0 : vec_loop_masks *loop_masks
4531 : : = &LOOP_VINFO_MASKS (loop_vinfo);
4532 : 0 : tree loop_mask
4533 : 0 : = vect_get_loop_mask (loop_vinfo, gsi,
4534 : : loop_masks, ncopies,
4535 : 0 : vectype, j);
4536 : 0 : vec_oprnd0
4537 : 0 : = prepare_vec_mask (loop_vinfo,
4538 : 0 : TREE_TYPE (loop_mask),
4539 : : loop_mask, vec_oprnd0,
4540 : : gsi);
4541 : 0 : loop_vinfo->vec_cond_masked_set.add ({ vec_oprnd0,
4542 : : loop_mask });
4543 : :
4544 : : }
4545 : 42 : vec_oprnd0
4546 : 42 : = build3 (VEC_COND_EXPR, atype, vec_oprnd0,
4547 : : build_vector_from_val (atype, one),
4548 : : build_vector_from_val (atype, zero));
4549 : 42 : gassign *new_stmt
4550 : 42 : = gimple_build_assign (make_ssa_name (atype),
4551 : : vec_oprnd0);
4552 : 42 : vect_finish_stmt_generation (vinfo, stmt_info,
4553 : : new_stmt, gsi);
4554 : 42 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4555 : : }
4556 : : else
4557 : : {
4558 : : /* The mask type has more elements than simdlen. */
4559 : :
4560 : : /* FORNOW */
4561 : 0 : gcc_unreachable ();
4562 : : }
4563 : : }
4564 : : }
4565 : 3 : else if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4566 : : {
4567 : 3 : atype = bestn->simdclone->args[i].vector_type;
4568 : : /* Guess the number of lanes represented by atype. */
4569 : 3 : poly_uint64 atype_subparts
4570 : 3 : = exact_div (bestn->simdclone->simdlen,
4571 : : num_mask_args);
4572 : 3 : o = vector_unroll_factor (nunits, atype_subparts);
4573 : 6 : for (m = j * o; m < (j + 1) * o; m++)
4574 : : {
4575 : 3 : if (m == 0)
4576 : : {
4577 : 3 : if (!slp_node)
4578 : 6 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
4579 : 3 : o * ncopies,
4580 : : op,
4581 : 3 : &vec_oprnds[i]);
4582 : 3 : vec_oprnds_i[i] = 0;
4583 : : }
4584 : 3 : if (maybe_lt (atype_subparts,
4585 : 3 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4586 : : {
4587 : : /* The mask argument has fewer elements than the
4588 : : input vector. */
4589 : : /* FORNOW */
4590 : 0 : gcc_unreachable ();
4591 : : }
4592 : 3 : else if (known_eq (atype_subparts,
4593 : : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4594 : : {
4595 : : /* The vector mask argument matches the input
4596 : : in the number of lanes, but not necessarily
4597 : : in the mode. */
4598 : 3 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4599 : 3 : tree st = lang_hooks.types.type_for_mode
4600 : 3 : (TYPE_MODE (TREE_TYPE (vec_oprnd0)), 1);
4601 : 3 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, st,
4602 : : vec_oprnd0);
4603 : 3 : gassign *new_stmt
4604 : 3 : = gimple_build_assign (make_ssa_name (st),
4605 : : vec_oprnd0);
4606 : 3 : vect_finish_stmt_generation (vinfo, stmt_info,
4607 : : new_stmt, gsi);
4608 : 3 : if (!types_compatible_p (atype, st))
4609 : : {
4610 : 3 : new_stmt
4611 : 3 : = gimple_build_assign (make_ssa_name (atype),
4612 : : NOP_EXPR,
4613 : : gimple_assign_lhs
4614 : : (new_stmt));
4615 : 3 : vect_finish_stmt_generation (vinfo, stmt_info,
4616 : : new_stmt, gsi);
4617 : : }
4618 : 3 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4619 : : }
4620 : : else
4621 : : {
4622 : : /* The mask argument has more elements than the
4623 : : input vector. */
4624 : : /* FORNOW */
4625 : 0 : gcc_unreachable ();
4626 : : }
4627 : : }
4628 : : }
4629 : : else
4630 : 0 : gcc_unreachable ();
4631 : : break;
4632 : 105 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
4633 : 105 : vargs.safe_push (op);
4634 : 105 : break;
4635 : 136 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4636 : 136 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4637 : 136 : if (j == 0)
4638 : : {
4639 : 133 : gimple_seq stmts;
4640 : 133 : arginfo[i].op
4641 : 133 : = force_gimple_operand (unshare_expr (arginfo[i].op),
4642 : : &stmts, true, NULL_TREE);
4643 : 133 : if (stmts != NULL)
4644 : : {
4645 : 0 : basic_block new_bb;
4646 : 0 : edge pe = loop_preheader_edge (loop);
4647 : 0 : new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
4648 : 0 : gcc_assert (!new_bb);
4649 : : }
4650 : 133 : if (arginfo[i].simd_lane_linear)
4651 : : {
4652 : 6 : vargs.safe_push (arginfo[i].op);
4653 : 6 : break;
4654 : : }
4655 : 127 : tree phi_res = copy_ssa_name (op);
4656 : 127 : gphi *new_phi = create_phi_node (phi_res, loop->header);
4657 : 127 : add_phi_arg (new_phi, arginfo[i].op,
4658 : : loop_preheader_edge (loop), UNKNOWN_LOCATION);
4659 : 127 : enum tree_code code
4660 : 220 : = POINTER_TYPE_P (TREE_TYPE (op))
4661 : 127 : ? POINTER_PLUS_EXPR : PLUS_EXPR;
4662 : 220 : tree type = POINTER_TYPE_P (TREE_TYPE (op))
4663 : 220 : ? sizetype : TREE_TYPE (op);
4664 : 127 : poly_widest_int cst
4665 : 127 : = wi::mul (bestn->simdclone->args[i].linear_step,
4666 : 127 : ncopies * nunits);
4667 : 127 : tree tcst = wide_int_to_tree (type, cst);
4668 : 127 : tree phi_arg = copy_ssa_name (op);
4669 : 127 : gassign *new_stmt
4670 : 127 : = gimple_build_assign (phi_arg, code, phi_res, tcst);
4671 : 127 : gimple_stmt_iterator si = gsi_after_labels (loop->header);
4672 : 127 : gsi_insert_after (&si, new_stmt, GSI_NEW_STMT);
4673 : 127 : add_phi_arg (new_phi, phi_arg, loop_latch_edge (loop),
4674 : : UNKNOWN_LOCATION);
4675 : 127 : arginfo[i].op = phi_res;
4676 : 127 : vargs.safe_push (phi_res);
4677 : 127 : }
4678 : : else
4679 : : {
4680 : 3 : enum tree_code code
4681 : 6 : = POINTER_TYPE_P (TREE_TYPE (op))
4682 : 3 : ? POINTER_PLUS_EXPR : PLUS_EXPR;
4683 : 6 : tree type = POINTER_TYPE_P (TREE_TYPE (op))
4684 : 6 : ? sizetype : TREE_TYPE (op);
4685 : 3 : poly_widest_int cst
4686 : 3 : = wi::mul (bestn->simdclone->args[i].linear_step,
4687 : 3 : j * nunits);
4688 : 3 : tree tcst = wide_int_to_tree (type, cst);
4689 : 3 : new_temp = make_ssa_name (TREE_TYPE (op));
4690 : 3 : gassign *new_stmt
4691 : 6 : = gimple_build_assign (new_temp, code,
4692 : 3 : arginfo[i].op, tcst);
4693 : 3 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4694 : 3 : vargs.safe_push (new_temp);
4695 : 3 : }
4696 : : break;
4697 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
4698 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
4699 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
4700 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
4701 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
4702 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
4703 : 0 : default:
4704 : 0 : gcc_unreachable ();
4705 : : }
4706 : : }
4707 : :
4708 : 443 : if (masked_call_offset == 0
4709 : 398 : && bestn->simdclone->inbranch
4710 : 6 : && bestn->simdclone->nargs > nargs)
4711 : : {
4712 : 6 : unsigned long m, o;
4713 : 6 : size_t mask_i = bestn->simdclone->nargs - 1;
4714 : 6 : tree mask;
4715 : 6 : gcc_assert (bestn->simdclone->args[mask_i].arg_type ==
4716 : : SIMD_CLONE_ARG_TYPE_MASK);
4717 : :
4718 : 6 : tree masktype = bestn->simdclone->args[mask_i].vector_type;
4719 : 6 : callee_nelements = TYPE_VECTOR_SUBPARTS (masktype);
4720 : 6 : o = vector_unroll_factor (nunits, callee_nelements);
4721 : 12 : for (m = j * o; m < (j + 1) * o; m++)
4722 : : {
4723 : 6 : if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4724 : : {
4725 : 0 : vec_loop_masks *loop_masks = &LOOP_VINFO_MASKS (loop_vinfo);
4726 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
4727 : : ncopies, vectype, j);
4728 : : }
4729 : : else
4730 : 6 : mask = vect_build_all_ones_mask (vinfo, stmt_info, masktype);
4731 : :
4732 : 6 : gassign *new_stmt;
4733 : 6 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4734 : : {
4735 : : /* This means we are dealing with integer mask modes.
4736 : : First convert to an integer type with the same size as
4737 : : the current vector type. */
4738 : 0 : unsigned HOST_WIDE_INT intermediate_size
4739 : 0 : = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (mask)));
4740 : 0 : tree mid_int_type =
4741 : 0 : build_nonstandard_integer_type (intermediate_size, 1);
4742 : 0 : mask = build1 (VIEW_CONVERT_EXPR, mid_int_type, mask);
4743 : 0 : new_stmt
4744 : 0 : = gimple_build_assign (make_ssa_name (mid_int_type),
4745 : : mask);
4746 : 0 : gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
4747 : : /* Then zero-extend to the mask mode. */
4748 : 0 : mask = fold_build1 (NOP_EXPR, masktype,
4749 : : gimple_get_lhs (new_stmt));
4750 : : }
4751 : 6 : else if (bestn->simdclone->mask_mode == VOIDmode)
4752 : : {
4753 : 6 : tree one = fold_convert (TREE_TYPE (masktype),
4754 : : integer_one_node);
4755 : 6 : tree zero = fold_convert (TREE_TYPE (masktype),
4756 : : integer_zero_node);
4757 : 6 : mask = build3 (VEC_COND_EXPR, masktype, mask,
4758 : : build_vector_from_val (masktype, one),
4759 : : build_vector_from_val (masktype, zero));
4760 : : }
4761 : : else
4762 : 0 : gcc_unreachable ();
4763 : :
4764 : 6 : new_stmt = gimple_build_assign (make_ssa_name (masktype), mask);
4765 : 6 : vect_finish_stmt_generation (vinfo, stmt_info,
4766 : : new_stmt, gsi);
4767 : 6 : mask = gimple_assign_lhs (new_stmt);
4768 : 6 : vargs.safe_push (mask);
4769 : : }
4770 : : }
4771 : :
4772 : 443 : gcall *new_call = gimple_build_call_vec (fndecl, vargs);
4773 : 443 : if (vec_dest)
4774 : : {
4775 : 434 : gcc_assert (ratype
4776 : : || known_eq (TYPE_VECTOR_SUBPARTS (rtype), nunits));
4777 : 434 : if (ratype)
4778 : 15 : new_temp = create_tmp_var (ratype);
4779 : 419 : else if (useless_type_conversion_p (vectype, rtype))
4780 : 412 : new_temp = make_ssa_name (vec_dest, new_call);
4781 : : else
4782 : 7 : new_temp = make_ssa_name (rtype, new_call);
4783 : 434 : gimple_call_set_lhs (new_call, new_temp);
4784 : : }
4785 : 443 : vect_finish_stmt_generation (vinfo, stmt_info, new_call, gsi);
4786 : 443 : gimple *new_stmt = new_call;
4787 : :
4788 : 443 : if (vec_dest)
4789 : : {
4790 : 434 : if (!multiple_p (TYPE_VECTOR_SUBPARTS (vectype), nunits))
4791 : : {
4792 : 18 : unsigned int k, l;
4793 : 36 : poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (vectype));
4794 : 36 : poly_uint64 bytes = GET_MODE_SIZE (TYPE_MODE (vectype));
4795 : 18 : k = vector_unroll_factor (nunits,
4796 : : TYPE_VECTOR_SUBPARTS (vectype));
4797 : 18 : gcc_assert ((k & (k - 1)) == 0);
4798 : 66 : for (l = 0; l < k; l++)
4799 : : {
4800 : 48 : tree t;
4801 : 48 : if (ratype)
4802 : : {
4803 : 42 : t = build_fold_addr_expr (new_temp);
4804 : 42 : t = build2 (MEM_REF, vectype, t,
4805 : 42 : build_int_cst (TREE_TYPE (t), l * bytes));
4806 : : }
4807 : : else
4808 : 6 : t = build3 (BIT_FIELD_REF, vectype, new_temp,
4809 : 6 : bitsize_int (prec), bitsize_int (l * prec));
4810 : 48 : new_stmt = gimple_build_assign (make_ssa_name (vectype), t);
4811 : 48 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4812 : :
4813 : 48 : if (j == 0 && l == 0)
4814 : 12 : *vec_stmt = new_stmt;
4815 : 48 : if (slp_node)
4816 : 0 : SLP_TREE_VEC_DEFS (slp_node)
4817 : 0 : .quick_push (gimple_assign_lhs (new_stmt));
4818 : : else
4819 : 48 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
4820 : : }
4821 : :
4822 : 18 : if (ratype)
4823 : 15 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
4824 : 18 : continue;
4825 : 18 : }
4826 : 416 : else if (!multiple_p (nunits, TYPE_VECTOR_SUBPARTS (vectype)))
4827 : : {
4828 : 4 : unsigned int k;
4829 : 4 : if (!constant_multiple_p (TYPE_VECTOR_SUBPARTS (vectype),
4830 : 8 : TYPE_VECTOR_SUBPARTS (rtype), &k))
4831 : 0 : gcc_unreachable ();
4832 : 4 : gcc_assert ((k & (k - 1)) == 0);
4833 : 4 : if ((j & (k - 1)) == 0)
4834 : 2 : vec_alloc (ret_ctor_elts, k);
4835 : 4 : if (ratype)
4836 : : {
4837 : 0 : unsigned int m, o;
4838 : 0 : o = vector_unroll_factor (nunits,
4839 : : TYPE_VECTOR_SUBPARTS (rtype));
4840 : 0 : for (m = 0; m < o; m++)
4841 : : {
4842 : 0 : tree tem = build4 (ARRAY_REF, rtype, new_temp,
4843 : : size_int (m), NULL_TREE, NULL_TREE);
4844 : 0 : new_stmt = gimple_build_assign (make_ssa_name (rtype),
4845 : : tem);
4846 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
4847 : : new_stmt, gsi);
4848 : 0 : CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE,
4849 : : gimple_assign_lhs (new_stmt));
4850 : : }
4851 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
4852 : : }
4853 : : else
4854 : 4 : CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE, new_temp);
4855 : 4 : if ((j & (k - 1)) != k - 1)
4856 : 2 : continue;
4857 : 2 : vec_oprnd0 = build_constructor (vectype, ret_ctor_elts);
4858 : 2 : new_stmt
4859 : 2 : = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0);
4860 : 2 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4861 : :
4862 : 2 : if ((unsigned) j == k - 1)
4863 : 2 : *vec_stmt = new_stmt;
4864 : 2 : if (slp_node)
4865 : 0 : SLP_TREE_VEC_DEFS (slp_node)
4866 : 0 : .quick_push (gimple_assign_lhs (new_stmt));
4867 : : else
4868 : 2 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
4869 : 2 : continue;
4870 : 2 : }
4871 : 412 : else if (ratype)
4872 : : {
4873 : 0 : tree t = build_fold_addr_expr (new_temp);
4874 : 0 : t = build2 (MEM_REF, vectype, t,
4875 : 0 : build_int_cst (TREE_TYPE (t), 0));
4876 : 0 : new_stmt = gimple_build_assign (make_ssa_name (vec_dest), t);
4877 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4878 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
4879 : : }
4880 : 412 : else if (!useless_type_conversion_p (vectype, rtype))
4881 : : {
4882 : 0 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, vectype, new_temp);
4883 : 0 : new_stmt
4884 : 0 : = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0);
4885 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4886 : : }
4887 : : }
4888 : :
4889 : 421 : if (j == 0)
4890 : 328 : *vec_stmt = new_stmt;
4891 : 421 : if (slp_node)
4892 : 7 : SLP_TREE_VEC_DEFS (slp_node).quick_push (gimple_get_lhs (new_stmt));
4893 : : else
4894 : 414 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
4895 : : }
4896 : :
4897 : 1108 : for (i = 0; i < nargs; ++i)
4898 : : {
4899 : 766 : vec<tree> oprndsi = vec_oprnds[i];
4900 : 766 : oprndsi.release ();
4901 : : }
4902 : 342 : vargs.release ();
4903 : :
4904 : : /* Mark the clone as no longer being a candidate for GC. */
4905 : 342 : bestn->gc_candidate = false;
4906 : :
4907 : : /* The call in STMT might prevent it from being removed in dce.
4908 : : We however cannot remove it here, due to the way the ssa name
4909 : : it defines is mapped to the new definition. So just replace
4910 : : rhs of the statement with something harmless. */
4911 : :
4912 : 342 : if (slp_node)
4913 : : return true;
4914 : :
4915 : 335 : gimple *new_stmt;
4916 : 335 : if (scalar_dest)
4917 : : {
4918 : 326 : type = TREE_TYPE (scalar_dest);
4919 : 328 : lhs = gimple_call_lhs (vect_orig_stmt (stmt_info)->stmt);
4920 : 326 : new_stmt = gimple_build_assign (lhs, build_zero_cst (type));
4921 : : }
4922 : : else
4923 : 9 : new_stmt = gimple_build_nop ();
4924 : 337 : vinfo->replace_stmt (gsi, vect_orig_stmt (stmt_info), new_stmt);
4925 : 335 : unlink_stmt_vdef (stmt);
4926 : :
4927 : 335 : return true;
4928 : 1425 : }
4929 : :
4930 : :
4931 : : /* Function vect_gen_widened_results_half
4932 : :
4933 : : Create a vector stmt whose code, type, number of arguments, and result
4934 : : variable are CODE, OP_TYPE, and VEC_DEST, and its arguments are
4935 : : VEC_OPRND0 and VEC_OPRND1. The new vector stmt is to be inserted at GSI.
4936 : : In the case that CODE is a CALL_EXPR, this means that a call to DECL
4937 : : needs to be created (DECL is a function-decl of a target-builtin).
4938 : : STMT_INFO is the original scalar stmt that we are vectorizing. */
4939 : :
4940 : : static gimple *
4941 : 17712 : vect_gen_widened_results_half (vec_info *vinfo, code_helper ch,
4942 : : tree vec_oprnd0, tree vec_oprnd1, int op_type,
4943 : : tree vec_dest, gimple_stmt_iterator *gsi,
4944 : : stmt_vec_info stmt_info)
4945 : : {
4946 : 17712 : gimple *new_stmt;
4947 : 17712 : tree new_temp;
4948 : :
4949 : : /* Generate half of the widened result: */
4950 : 17712 : if (op_type != binary_op)
4951 : 16656 : vec_oprnd1 = NULL;
4952 : 17712 : new_stmt = vect_gimple_build (vec_dest, ch, vec_oprnd0, vec_oprnd1);
4953 : 17712 : new_temp = make_ssa_name (vec_dest, new_stmt);
4954 : 17712 : gimple_set_lhs (new_stmt, new_temp);
4955 : 17712 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4956 : :
4957 : 17712 : return new_stmt;
4958 : : }
4959 : :
4960 : :
4961 : : /* Create vectorized demotion statements for vector operands from VEC_OPRNDS.
4962 : : For multi-step conversions store the resulting vectors and call the function
4963 : : recursively. When NARROW_SRC_P is true, there's still a conversion after
4964 : : narrowing, don't store the vectors in the SLP_NODE or in vector info of
4965 : : the scalar statement(or in STMT_VINFO_RELATED_STMT chain). */
4966 : :
4967 : : static void
4968 : 7793 : vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
4969 : : int multi_step_cvt,
4970 : : stmt_vec_info stmt_info,
4971 : : vec<tree> &vec_dsts,
4972 : : gimple_stmt_iterator *gsi,
4973 : : slp_tree slp_node, code_helper code,
4974 : : bool narrow_src_p)
4975 : : {
4976 : 7793 : unsigned int i;
4977 : 7793 : tree vop0, vop1, new_tmp, vec_dest;
4978 : :
4979 : 7793 : vec_dest = vec_dsts.pop ();
4980 : :
4981 : 36146 : for (i = 0; i < vec_oprnds->length (); i += 2)
4982 : : {
4983 : : /* Create demotion operation. */
4984 : 10280 : vop0 = (*vec_oprnds)[i];
4985 : 10280 : vop1 = (*vec_oprnds)[i + 1];
4986 : 10280 : gimple *new_stmt = vect_gimple_build (vec_dest, code, vop0, vop1);
4987 : 10280 : new_tmp = make_ssa_name (vec_dest, new_stmt);
4988 : 10280 : gimple_set_lhs (new_stmt, new_tmp);
4989 : 10280 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4990 : 10280 : if (multi_step_cvt || narrow_src_p)
4991 : : /* Store the resulting vector for next recursive call,
4992 : : or return the resulting vector_tmp for NARROW FLOAT_EXPR. */
4993 : 3509 : (*vec_oprnds)[i/2] = new_tmp;
4994 : : else
4995 : : {
4996 : : /* This is the last step of the conversion sequence. Store the
4997 : : vectors in SLP_NODE or in vector info of the scalar statement
4998 : : (or in STMT_VINFO_RELATED_STMT chain). */
4999 : 6771 : if (slp_node)
5000 : 638 : slp_node->push_vec_def (new_stmt);
5001 : : else
5002 : 6133 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
5003 : : }
5004 : : }
5005 : :
5006 : : /* For multi-step demotion operations we first generate demotion operations
5007 : : from the source type to the intermediate types, and then combine the
5008 : : results (stored in VEC_OPRNDS) in demotion operation to the destination
5009 : : type. */
5010 : 7793 : if (multi_step_cvt)
5011 : : {
5012 : : /* At each level of recursion we have half of the operands we had at the
5013 : : previous level. */
5014 : 1598 : vec_oprnds->truncate ((i+1)/2);
5015 : 1598 : vect_create_vectorized_demotion_stmts (vinfo, vec_oprnds,
5016 : : multi_step_cvt - 1,
5017 : : stmt_info, vec_dsts, gsi,
5018 : : slp_node, VEC_PACK_TRUNC_EXPR,
5019 : : narrow_src_p);
5020 : : }
5021 : :
5022 : 7793 : vec_dsts.quick_push (vec_dest);
5023 : 7793 : }
5024 : :
5025 : :
5026 : : /* Create vectorized promotion statements for vector operands from VEC_OPRNDS0
5027 : : and VEC_OPRNDS1, for a binary operation associated with scalar statement
5028 : : STMT_INFO. For multi-step conversions store the resulting vectors and
5029 : : call the function recursively. */
5030 : :
5031 : : static void
5032 : 6936 : vect_create_vectorized_promotion_stmts (vec_info *vinfo,
5033 : : vec<tree> *vec_oprnds0,
5034 : : vec<tree> *vec_oprnds1,
5035 : : stmt_vec_info stmt_info, tree vec_dest,
5036 : : gimple_stmt_iterator *gsi,
5037 : : code_helper ch1,
5038 : : code_helper ch2, int op_type)
5039 : : {
5040 : 6936 : int i;
5041 : 6936 : tree vop0, vop1, new_tmp1, new_tmp2;
5042 : 6936 : gimple *new_stmt1, *new_stmt2;
5043 : 6936 : vec<tree> vec_tmp = vNULL;
5044 : :
5045 : 6936 : vec_tmp.create (vec_oprnds0->length () * 2);
5046 : 22728 : FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0)
5047 : : {
5048 : 8856 : if (op_type == binary_op)
5049 : 528 : vop1 = (*vec_oprnds1)[i];
5050 : : else
5051 : : vop1 = NULL_TREE;
5052 : :
5053 : : /* Generate the two halves of promotion operation. */
5054 : 8856 : new_stmt1 = vect_gen_widened_results_half (vinfo, ch1, vop0, vop1,
5055 : : op_type, vec_dest, gsi,
5056 : : stmt_info);
5057 : 8856 : new_stmt2 = vect_gen_widened_results_half (vinfo, ch2, vop0, vop1,
5058 : : op_type, vec_dest, gsi,
5059 : : stmt_info);
5060 : 8856 : if (is_gimple_call (new_stmt1))
5061 : : {
5062 : 0 : new_tmp1 = gimple_call_lhs (new_stmt1);
5063 : 0 : new_tmp2 = gimple_call_lhs (new_stmt2);
5064 : : }
5065 : : else
5066 : : {
5067 : 8856 : new_tmp1 = gimple_assign_lhs (new_stmt1);
5068 : 8856 : new_tmp2 = gimple_assign_lhs (new_stmt2);
5069 : : }
5070 : :
5071 : : /* Store the results for the next step. */
5072 : 8856 : vec_tmp.quick_push (new_tmp1);
5073 : 8856 : vec_tmp.quick_push (new_tmp2);
5074 : : }
5075 : :
5076 : 6936 : vec_oprnds0->release ();
5077 : 6936 : *vec_oprnds0 = vec_tmp;
5078 : 6936 : }
5079 : :
5080 : : /* Create vectorized promotion stmts for widening stmts using only half the
5081 : : potential vector size for input. */
5082 : : static void
5083 : 14 : vect_create_half_widening_stmts (vec_info *vinfo,
5084 : : vec<tree> *vec_oprnds0,
5085 : : vec<tree> *vec_oprnds1,
5086 : : stmt_vec_info stmt_info, tree vec_dest,
5087 : : gimple_stmt_iterator *gsi,
5088 : : code_helper code1,
5089 : : int op_type)
5090 : : {
5091 : 14 : int i;
5092 : 14 : tree vop0, vop1;
5093 : 14 : gimple *new_stmt1;
5094 : 14 : gimple *new_stmt2;
5095 : 14 : gimple *new_stmt3;
5096 : 14 : vec<tree> vec_tmp = vNULL;
5097 : :
5098 : 14 : vec_tmp.create (vec_oprnds0->length ());
5099 : 28 : FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0)
5100 : : {
5101 : 14 : tree new_tmp1, new_tmp2, new_tmp3, out_type;
5102 : :
5103 : 14 : gcc_assert (op_type == binary_op);
5104 : 14 : vop1 = (*vec_oprnds1)[i];
5105 : :
5106 : : /* Widen the first vector input. */
5107 : 14 : out_type = TREE_TYPE (vec_dest);
5108 : 14 : new_tmp1 = make_ssa_name (out_type);
5109 : 14 : new_stmt1 = gimple_build_assign (new_tmp1, NOP_EXPR, vop0);
5110 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt1, gsi);
5111 : 14 : if (VECTOR_TYPE_P (TREE_TYPE (vop1)))
5112 : : {
5113 : : /* Widen the second vector input. */
5114 : 14 : new_tmp2 = make_ssa_name (out_type);
5115 : 14 : new_stmt2 = gimple_build_assign (new_tmp2, NOP_EXPR, vop1);
5116 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt2, gsi);
5117 : : /* Perform the operation. With both vector inputs widened. */
5118 : 14 : new_stmt3 = vect_gimple_build (vec_dest, code1, new_tmp1, new_tmp2);
5119 : : }
5120 : : else
5121 : : {
5122 : : /* Perform the operation. With the single vector input widened. */
5123 : 0 : new_stmt3 = vect_gimple_build (vec_dest, code1, new_tmp1, vop1);
5124 : : }
5125 : :
5126 : 14 : new_tmp3 = make_ssa_name (vec_dest, new_stmt3);
5127 : 14 : gimple_assign_set_lhs (new_stmt3, new_tmp3);
5128 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt3, gsi);
5129 : :
5130 : : /* Store the results for the next step. */
5131 : 14 : vec_tmp.quick_push (new_tmp3);
5132 : : }
5133 : :
5134 : 14 : vec_oprnds0->release ();
5135 : 14 : *vec_oprnds0 = vec_tmp;
5136 : 14 : }
5137 : :
5138 : :
5139 : : /* Check if STMT_INFO performs a conversion operation that can be vectorized.
5140 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
5141 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
5142 : : Return true if STMT_INFO is vectorizable in this way. */
5143 : :
5144 : : static bool
5145 : 1803682 : vectorizable_conversion (vec_info *vinfo,
5146 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
5147 : : gimple **vec_stmt, slp_tree slp_node,
5148 : : stmt_vector_for_cost *cost_vec)
5149 : : {
5150 : 1803682 : tree vec_dest, cvt_op = NULL_TREE;
5151 : 1803682 : tree scalar_dest;
5152 : 1803682 : tree op0, op1 = NULL_TREE;
5153 : 1803682 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
5154 : 1803682 : tree_code tc1, tc2;
5155 : 1803682 : code_helper code, code1, code2;
5156 : 1803682 : code_helper codecvt1 = ERROR_MARK, codecvt2 = ERROR_MARK;
5157 : 1803682 : tree new_temp;
5158 : 1803682 : enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
5159 : 1803682 : int ndts = 2;
5160 : 1803682 : poly_uint64 nunits_in;
5161 : 1803682 : poly_uint64 nunits_out;
5162 : 1803682 : tree vectype_out, vectype_in;
5163 : 1803682 : int ncopies, i;
5164 : 1803682 : tree lhs_type, rhs_type;
5165 : : /* For conversions between floating point and integer, there're 2 NARROW
5166 : : cases. NARROW_SRC is for FLOAT_EXPR, means
5167 : : integer --DEMOTION--> integer --FLOAT_EXPR--> floating point.
5168 : : This is safe when the range of the source integer can fit into the lower
5169 : : precision. NARROW_DST is for FIX_TRUNC_EXPR, means
5170 : : floating point --FIX_TRUNC_EXPR--> integer --DEMOTION--> INTEGER.
5171 : : For other conversions, when there's narrowing, NARROW_DST is used as
5172 : : default. */
5173 : 1803682 : enum { NARROW_SRC, NARROW_DST, NONE, WIDEN } modifier;
5174 : 1803682 : vec<tree> vec_oprnds0 = vNULL;
5175 : 1803682 : vec<tree> vec_oprnds1 = vNULL;
5176 : 1803682 : tree vop0;
5177 : 1803682 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
5178 : 1803682 : int multi_step_cvt = 0;
5179 : 1803682 : vec<tree> interm_types = vNULL;
5180 : 1803682 : tree intermediate_type, cvt_type = NULL_TREE;
5181 : 1803682 : int op_type;
5182 : 1803682 : unsigned short fltsz;
5183 : :
5184 : : /* Is STMT a vectorizable conversion? */
5185 : :
5186 : 1803682 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
5187 : : return false;
5188 : :
5189 : 1803682 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
5190 : 24817 : && ! vec_stmt)
5191 : : return false;
5192 : :
5193 : 1778865 : gimple* stmt = stmt_info->stmt;
5194 : 1778865 : if (!(is_gimple_assign (stmt) || is_gimple_call (stmt)))
5195 : : return false;
5196 : :
5197 : 1718518 : if (gimple_get_lhs (stmt) == NULL_TREE
5198 : 1718518 : || TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME)
5199 : 724247 : return false;
5200 : :
5201 : 994271 : if (TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME)
5202 : : return false;
5203 : :
5204 : 994271 : if (is_gimple_assign (stmt))
5205 : : {
5206 : 988190 : code = gimple_assign_rhs_code (stmt);
5207 : 988190 : op_type = TREE_CODE_LENGTH ((tree_code) code);
5208 : : }
5209 : 6081 : else if (gimple_call_internal_p (stmt))
5210 : : {
5211 : 3084 : code = gimple_call_internal_fn (stmt);
5212 : 3084 : op_type = gimple_call_num_args (stmt);
5213 : : }
5214 : : else
5215 : : return false;
5216 : :
5217 : 991274 : bool widen_arith = (code == WIDEN_MULT_EXPR
5218 : 989489 : || code == WIDEN_LSHIFT_EXPR
5219 : 1980763 : || widening_fn_p (code));
5220 : :
5221 : 989489 : if (!widen_arith
5222 : 989489 : && !CONVERT_EXPR_CODE_P (code)
5223 : 874953 : && code != FIX_TRUNC_EXPR
5224 : 873205 : && code != FLOAT_EXPR)
5225 : : return false;
5226 : :
5227 : : /* Check types of lhs and rhs. */
5228 : 128751 : scalar_dest = gimple_get_lhs (stmt);
5229 : 128751 : lhs_type = TREE_TYPE (scalar_dest);
5230 : 128751 : vectype_out = STMT_VINFO_VECTYPE (stmt_info);
5231 : :
5232 : : /* Check the operands of the operation. */
5233 : 128751 : slp_tree slp_op0, slp_op1 = NULL;
5234 : 128751 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
5235 : : 0, &op0, &slp_op0, &dt[0], &vectype_in))
5236 : : {
5237 : 0 : if (dump_enabled_p ())
5238 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5239 : : "use not simple.\n");
5240 : 0 : return false;
5241 : : }
5242 : :
5243 : 128751 : rhs_type = TREE_TYPE (op0);
5244 : 127003 : if ((code != FIX_TRUNC_EXPR && code != FLOAT_EXPR)
5245 : 247986 : && !((INTEGRAL_TYPE_P (lhs_type)
5246 : 110139 : && INTEGRAL_TYPE_P (rhs_type))
5247 : : || (SCALAR_FLOAT_TYPE_P (lhs_type)
5248 : 4989 : && SCALAR_FLOAT_TYPE_P (rhs_type))))
5249 : : return false;
5250 : :
5251 : 124644 : if (!VECTOR_BOOLEAN_TYPE_P (vectype_out)
5252 : 242562 : && ((INTEGRAL_TYPE_P (lhs_type)
5253 : 102247 : && !type_has_mode_precision_p (lhs_type))
5254 : 117612 : || (INTEGRAL_TYPE_P (rhs_type)
5255 : 110875 : && !type_has_mode_precision_p (rhs_type))))
5256 : : {
5257 : 708 : if (dump_enabled_p ())
5258 : 2 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5259 : : "type conversion to/from bit-precision unsupported."
5260 : : "\n");
5261 : 708 : return false;
5262 : : }
5263 : :
5264 : 123936 : if (op_type == binary_op)
5265 : : {
5266 : 1785 : gcc_assert (code == WIDEN_MULT_EXPR
5267 : : || code == WIDEN_LSHIFT_EXPR
5268 : : || widening_fn_p (code));
5269 : :
5270 : 1785 : op1 = is_gimple_assign (stmt) ? gimple_assign_rhs2 (stmt) :
5271 : 0 : gimple_call_arg (stmt, 0);
5272 : 1785 : tree vectype1_in;
5273 : 1785 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1,
5274 : : &op1, &slp_op1, &dt[1], &vectype1_in))
5275 : : {
5276 : 0 : if (dump_enabled_p ())
5277 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5278 : : "use not simple.\n");
5279 : 0 : return false;
5280 : : }
5281 : : /* For WIDEN_MULT_EXPR, if OP0 is a constant, use the type of
5282 : : OP1. */
5283 : 1785 : if (!vectype_in)
5284 : 114 : vectype_in = vectype1_in;
5285 : : }
5286 : :
5287 : : /* If op0 is an external or constant def, infer the vector type
5288 : : from the scalar type. */
5289 : 123936 : if (!vectype_in)
5290 : 21800 : vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
5291 : 123936 : if (vec_stmt)
5292 : 15335 : gcc_assert (vectype_in);
5293 : 123936 : if (!vectype_in)
5294 : : {
5295 : 1320 : if (dump_enabled_p ())
5296 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5297 : : "no vectype for scalar type %T\n", rhs_type);
5298 : :
5299 : 1320 : return false;
5300 : : }
5301 : :
5302 : 122616 : if (VECTOR_BOOLEAN_TYPE_P (vectype_out)
5303 : 129342 : && !VECTOR_BOOLEAN_TYPE_P (vectype_in))
5304 : : {
5305 : 168 : if (dump_enabled_p ())
5306 : 9 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5307 : : "can't convert between boolean and non "
5308 : : "boolean vectors %T\n", rhs_type);
5309 : :
5310 : 168 : return false;
5311 : : }
5312 : :
5313 : 122448 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
5314 : 122448 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
5315 : 122448 : if (known_eq (nunits_out, nunits_in))
5316 : 67789 : if (widen_arith)
5317 : : modifier = WIDEN;
5318 : : else
5319 : 122448 : modifier = NONE;
5320 : 54659 : else if (multiple_p (nunits_out, nunits_in))
5321 : : modifier = NARROW_DST;
5322 : : else
5323 : : {
5324 : 29039 : gcc_checking_assert (multiple_p (nunits_in, nunits_out));
5325 : : modifier = WIDEN;
5326 : : }
5327 : :
5328 : : /* Multiple types in SLP are handled by creating the appropriate number of
5329 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
5330 : : case of SLP. */
5331 : 122448 : if (slp_node)
5332 : : ncopies = 1;
5333 : 84199 : else if (modifier == NARROW_DST)
5334 : 22423 : ncopies = vect_get_num_copies (loop_vinfo, vectype_out);
5335 : : else
5336 : 61776 : ncopies = vect_get_num_copies (loop_vinfo, vectype_in);
5337 : :
5338 : : /* Sanity check: make sure that at least one copy of the vectorized stmt
5339 : : needs to be generated. */
5340 : 84199 : gcc_assert (ncopies >= 1);
5341 : :
5342 : 122448 : bool found_mode = false;
5343 : 122448 : scalar_mode lhs_mode = SCALAR_TYPE_MODE (lhs_type);
5344 : 122448 : scalar_mode rhs_mode = SCALAR_TYPE_MODE (rhs_type);
5345 : 122448 : opt_scalar_mode rhs_mode_iter;
5346 : :
5347 : : /* Supportable by target? */
5348 : 122448 : switch (modifier)
5349 : : {
5350 : 67552 : case NONE:
5351 : 67552 : if (code != FIX_TRUNC_EXPR
5352 : 66738 : && code != FLOAT_EXPR
5353 : 129274 : && !CONVERT_EXPR_CODE_P (code))
5354 : : return false;
5355 : 67552 : gcc_assert (code.is_tree_code ());
5356 : 67552 : if (supportable_convert_operation ((tree_code) code, vectype_out,
5357 : : vectype_in, &tc1))
5358 : : {
5359 : 12805 : code1 = tc1;
5360 : 12805 : break;
5361 : : }
5362 : :
5363 : : /* For conversions between float and integer types try whether
5364 : : we can use intermediate signed integer types to support the
5365 : : conversion. */
5366 : 109494 : if (GET_MODE_SIZE (lhs_mode) != GET_MODE_SIZE (rhs_mode)
5367 : 54747 : && (code == FLOAT_EXPR ||
5368 : 4963 : (code == FIX_TRUNC_EXPR && !flag_trapping_math)))
5369 : : {
5370 : 212 : bool demotion = GET_MODE_SIZE (rhs_mode) > GET_MODE_SIZE (lhs_mode);
5371 : 106 : bool float_expr_p = code == FLOAT_EXPR;
5372 : 106 : unsigned short target_size;
5373 : 106 : scalar_mode intermediate_mode;
5374 : 106 : if (demotion)
5375 : : {
5376 : 22 : intermediate_mode = lhs_mode;
5377 : 22 : target_size = GET_MODE_SIZE (rhs_mode);
5378 : : }
5379 : : else
5380 : : {
5381 : 84 : target_size = GET_MODE_SIZE (lhs_mode);
5382 : 84 : if (!int_mode_for_size
5383 : 84 : (GET_MODE_BITSIZE (rhs_mode), 0).exists (&intermediate_mode))
5384 : 0 : goto unsupported;
5385 : : }
5386 : 106 : code1 = float_expr_p ? code : NOP_EXPR;
5387 : 106 : codecvt1 = float_expr_p ? NOP_EXPR : code;
5388 : 106 : opt_scalar_mode mode_iter;
5389 : 166 : FOR_EACH_2XWIDER_MODE (mode_iter, intermediate_mode)
5390 : : {
5391 : 166 : intermediate_mode = mode_iter.require ();
5392 : :
5393 : 332 : if (GET_MODE_SIZE (intermediate_mode) > target_size)
5394 : : break;
5395 : :
5396 : 148 : scalar_mode cvt_mode;
5397 : 148 : if (!int_mode_for_size
5398 : 148 : (GET_MODE_BITSIZE (intermediate_mode), 0).exists (&cvt_mode))
5399 : : break;
5400 : :
5401 : 148 : cvt_type = build_nonstandard_integer_type
5402 : 148 : (GET_MODE_BITSIZE (cvt_mode), 0);
5403 : :
5404 : : /* Check if the intermediate type can hold OP0's range.
5405 : : When converting from float to integer this is not necessary
5406 : : because values that do not fit the (smaller) target type are
5407 : : unspecified anyway. */
5408 : 148 : if (demotion && float_expr_p)
5409 : : {
5410 : 0 : wide_int op_min_value, op_max_value;
5411 : 0 : if (!vect_get_range_info (op0, &op_min_value, &op_max_value))
5412 : : break;
5413 : :
5414 : 0 : if (cvt_type == NULL_TREE
5415 : 0 : || (wi::min_precision (op_max_value, SIGNED)
5416 : 0 : > TYPE_PRECISION (cvt_type))
5417 : 0 : || (wi::min_precision (op_min_value, SIGNED)
5418 : 0 : > TYPE_PRECISION (cvt_type)))
5419 : 0 : continue;
5420 : 0 : }
5421 : :
5422 : 148 : cvt_type = get_vectype_for_scalar_type (vinfo, cvt_type, slp_node);
5423 : : /* This should only happened for SLP as long as loop vectorizer
5424 : : only supports same-sized vector. */
5425 : 208 : if (cvt_type == NULL_TREE
5426 : 236 : || maybe_ne (TYPE_VECTOR_SUBPARTS (cvt_type), nunits_in)
5427 : 148 : || !supportable_convert_operation ((tree_code) code1,
5428 : : vectype_out,
5429 : : cvt_type, &tc1)
5430 : 256 : || !supportable_convert_operation ((tree_code) codecvt1,
5431 : : cvt_type,
5432 : : vectype_in, &tc2))
5433 : 60 : continue;
5434 : :
5435 : : found_mode = true;
5436 : : break;
5437 : : }
5438 : :
5439 : 106 : if (found_mode)
5440 : : {
5441 : 88 : multi_step_cvt++;
5442 : 88 : interm_types.safe_push (cvt_type);
5443 : 88 : cvt_type = NULL_TREE;
5444 : 88 : code1 = tc1;
5445 : 88 : codecvt1 = tc2;
5446 : 88 : break;
5447 : : }
5448 : : }
5449 : : /* FALLTHRU */
5450 : 62360 : unsupported:
5451 : 62360 : if (dump_enabled_p ())
5452 : 6320 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5453 : : "conversion not supported by target.\n");
5454 : : return false;
5455 : :
5456 : 29276 : case WIDEN:
5457 : 29276 : if (known_eq (nunits_in, nunits_out))
5458 : : {
5459 : 474 : if (!(code.is_tree_code ()
5460 : 237 : && supportable_half_widening_operation ((tree_code) code,
5461 : : vectype_out, vectype_in,
5462 : : &tc1)))
5463 : 70 : goto unsupported;
5464 : 167 : code1 = tc1;
5465 : 167 : gcc_assert (!(multi_step_cvt && op_type == binary_op));
5466 : : break;
5467 : : }
5468 : 29039 : if (supportable_widening_operation (vinfo, code, stmt_info,
5469 : : vectype_out, vectype_in, &code1,
5470 : : &code2, &multi_step_cvt,
5471 : : &interm_types))
5472 : : {
5473 : : /* Binary widening operation can only be supported directly by the
5474 : : architecture. */
5475 : 24214 : gcc_assert (!(multi_step_cvt && op_type == binary_op));
5476 : : break;
5477 : : }
5478 : :
5479 : 4825 : if (code != FLOAT_EXPR
5480 : 5121 : || GET_MODE_SIZE (lhs_mode) <= GET_MODE_SIZE (rhs_mode))
5481 : 4677 : goto unsupported;
5482 : :
5483 : 148 : fltsz = GET_MODE_SIZE (lhs_mode);
5484 : 214 : FOR_EACH_2XWIDER_MODE (rhs_mode_iter, rhs_mode)
5485 : : {
5486 : 214 : rhs_mode = rhs_mode_iter.require ();
5487 : 428 : if (GET_MODE_SIZE (rhs_mode) > fltsz)
5488 : : break;
5489 : :
5490 : 214 : cvt_type
5491 : 214 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0);
5492 : 214 : cvt_type = get_same_sized_vectype (cvt_type, vectype_in);
5493 : 214 : if (cvt_type == NULL_TREE)
5494 : 0 : goto unsupported;
5495 : :
5496 : 428 : if (GET_MODE_SIZE (rhs_mode) == fltsz)
5497 : : {
5498 : 42 : tc1 = ERROR_MARK;
5499 : 42 : gcc_assert (code.is_tree_code ());
5500 : 42 : if (!supportable_convert_operation ((tree_code) code, vectype_out,
5501 : : cvt_type, &tc1))
5502 : 22 : goto unsupported;
5503 : 20 : codecvt1 = tc1;
5504 : : }
5505 : 172 : else if (!supportable_widening_operation (vinfo, code,
5506 : : stmt_info, vectype_out,
5507 : : cvt_type, &codecvt1,
5508 : : &codecvt2, &multi_step_cvt,
5509 : : &interm_types))
5510 : 66 : continue;
5511 : : else
5512 : 106 : gcc_assert (multi_step_cvt == 0);
5513 : :
5514 : 126 : if (supportable_widening_operation (vinfo, NOP_EXPR, stmt_info,
5515 : : cvt_type,
5516 : : vectype_in, &code1,
5517 : : &code2, &multi_step_cvt,
5518 : : &interm_types))
5519 : : {
5520 : : found_mode = true;
5521 : : break;
5522 : : }
5523 : : }
5524 : :
5525 : 126 : if (!found_mode)
5526 : 0 : goto unsupported;
5527 : :
5528 : 252 : if (GET_MODE_SIZE (rhs_mode) == fltsz)
5529 : 20 : codecvt2 = ERROR_MARK;
5530 : : else
5531 : : {
5532 : 106 : multi_step_cvt++;
5533 : 106 : interm_types.safe_push (cvt_type);
5534 : 106 : cvt_type = NULL_TREE;
5535 : : }
5536 : : break;
5537 : :
5538 : 25620 : case NARROW_DST:
5539 : 25620 : gcc_assert (op_type == unary_op);
5540 : 25620 : if (supportable_narrowing_operation (code, vectype_out, vectype_in,
5541 : : &code1, &multi_step_cvt,
5542 : : &interm_types))
5543 : : break;
5544 : :
5545 : 9471 : if (GET_MODE_SIZE (lhs_mode) >= GET_MODE_SIZE (rhs_mode))
5546 : 192 : goto unsupported;
5547 : :
5548 : 2965 : if (code == FIX_TRUNC_EXPR)
5549 : : {
5550 : 221 : cvt_type
5551 : 221 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0);
5552 : 221 : cvt_type = get_same_sized_vectype (cvt_type, vectype_in);
5553 : 221 : if (cvt_type == NULL_TREE)
5554 : 0 : goto unsupported;
5555 : 221 : if (supportable_convert_operation ((tree_code) code, cvt_type, vectype_in,
5556 : : &tc1))
5557 : 220 : codecvt1 = tc1;
5558 : : else
5559 : 1 : goto unsupported;
5560 : 220 : if (supportable_narrowing_operation (NOP_EXPR, vectype_out, cvt_type,
5561 : : &code1, &multi_step_cvt,
5562 : : &interm_types))
5563 : : break;
5564 : : }
5565 : : /* If op0 can be represented with low precision integer,
5566 : : truncate it to cvt_type and the do FLOAT_EXPR. */
5567 : 2744 : else if (code == FLOAT_EXPR)
5568 : : {
5569 : 42 : wide_int op_min_value, op_max_value;
5570 : 42 : if (!vect_get_range_info (op0, &op_min_value, &op_max_value))
5571 : 36 : goto unsupported;
5572 : :
5573 : 6 : cvt_type
5574 : 6 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (lhs_mode), 0);
5575 : 6 : if (cvt_type == NULL_TREE
5576 : 6 : || (wi::min_precision (op_max_value, SIGNED)
5577 : 6 : > TYPE_PRECISION (cvt_type))
5578 : 11 : || (wi::min_precision (op_min_value, SIGNED)
5579 : 5 : > TYPE_PRECISION (cvt_type)))
5580 : 1 : goto unsupported;
5581 : :
5582 : 5 : cvt_type = get_same_sized_vectype (cvt_type, vectype_out);
5583 : 5 : if (cvt_type == NULL_TREE)
5584 : 0 : goto unsupported;
5585 : 5 : if (!supportable_narrowing_operation (NOP_EXPR, cvt_type, vectype_in,
5586 : : &code1, &multi_step_cvt,
5587 : : &interm_types))
5588 : 0 : goto unsupported;
5589 : 5 : if (supportable_convert_operation ((tree_code) code, vectype_out,
5590 : : cvt_type, &tc1))
5591 : : {
5592 : 5 : codecvt1 = tc1;
5593 : 5 : modifier = NARROW_SRC;
5594 : 5 : break;
5595 : : }
5596 : 42 : }
5597 : :
5598 : 2702 : goto unsupported;
5599 : :
5600 : : default:
5601 : : gcc_unreachable ();
5602 : : }
5603 : :
5604 : 60088 : if (!vec_stmt) /* transformation not required. */
5605 : : {
5606 : 44753 : if (slp_node
5607 : 44753 : && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype_in)
5608 : 9663 : || !vect_maybe_update_slp_op_vectype (slp_op1, vectype_in)))
5609 : : {
5610 : 0 : if (dump_enabled_p ())
5611 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5612 : : "incompatible vector types for invariants\n");
5613 : 0 : return false;
5614 : : }
5615 : 44753 : DUMP_VECT_SCOPE ("vectorizable_conversion");
5616 : 44753 : if (modifier == NONE)
5617 : : {
5618 : 9946 : STMT_VINFO_TYPE (stmt_info) = type_conversion_vec_info_type;
5619 : 9946 : vect_model_simple_cost (vinfo, stmt_info,
5620 : 9946 : ncopies * (1 + multi_step_cvt),
5621 : : dt, ndts, slp_node, cost_vec);
5622 : : }
5623 : 34807 : else if (modifier == NARROW_SRC || modifier == NARROW_DST)
5624 : : {
5625 : 16493 : STMT_VINFO_TYPE (stmt_info) = type_demotion_vec_info_type;
5626 : : /* The final packing step produces one vector result per copy. */
5627 : 32986 : unsigned int nvectors
5628 : 16493 : = (slp_node ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies);
5629 : 16493 : vect_model_promotion_demotion_cost (stmt_info, dt, nvectors,
5630 : : multi_step_cvt, cost_vec,
5631 : : widen_arith);
5632 : : }
5633 : : else
5634 : : {
5635 : 18314 : STMT_VINFO_TYPE (stmt_info) = type_promotion_vec_info_type;
5636 : : /* The initial unpacking step produces two vector results
5637 : : per copy. MULTI_STEP_CVT is 0 for a single conversion,
5638 : : so >> MULTI_STEP_CVT divides by 2^(number of steps - 1). */
5639 : 36628 : unsigned int nvectors
5640 : : = (slp_node
5641 : 18314 : ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) >> multi_step_cvt
5642 : 16713 : : ncopies * 2);
5643 : 18314 : vect_model_promotion_demotion_cost (stmt_info, dt, nvectors,
5644 : : multi_step_cvt, cost_vec,
5645 : : widen_arith);
5646 : : }
5647 : 44753 : interm_types.release ();
5648 : 44753 : return true;
5649 : 44753 : }
5650 : :
5651 : : /* Transform. */
5652 : 15335 : if (dump_enabled_p ())
5653 : 3845 : dump_printf_loc (MSG_NOTE, vect_location,
5654 : : "transform conversion. ncopies = %d.\n", ncopies);
5655 : :
5656 : 15335 : if (op_type == binary_op)
5657 : : {
5658 : 488 : if (CONSTANT_CLASS_P (op0))
5659 : 0 : op0 = fold_convert (TREE_TYPE (op1), op0);
5660 : 488 : else if (CONSTANT_CLASS_P (op1))
5661 : 242 : op1 = fold_convert (TREE_TYPE (op0), op1);
5662 : : }
5663 : :
5664 : : /* In case of multi-step conversion, we first generate conversion operations
5665 : : to the intermediate types, and then from that types to the final one.
5666 : : We create vector destinations for the intermediate type (TYPES) received
5667 : : from supportable_*_operation, and store them in the correct order
5668 : : for future use in vect_create_vectorized_*_stmts (). */
5669 : 15335 : auto_vec<tree> vec_dsts (multi_step_cvt + 1);
5670 : 15335 : bool widen_or_narrow_float_p
5671 : 15335 : = cvt_type && (modifier == WIDEN || modifier == NARROW_SRC);
5672 : 15335 : vec_dest = vect_create_destination_var (scalar_dest,
5673 : : widen_or_narrow_float_p
5674 : : ? cvt_type : vectype_out);
5675 : 15335 : vec_dsts.quick_push (vec_dest);
5676 : :
5677 : 15335 : if (multi_step_cvt)
5678 : : {
5679 : 4602 : for (i = interm_types.length () - 1;
5680 : 4602 : interm_types.iterate (i, &intermediate_type); i--)
5681 : : {
5682 : 2383 : vec_dest = vect_create_destination_var (scalar_dest,
5683 : : intermediate_type);
5684 : 2383 : vec_dsts.quick_push (vec_dest);
5685 : : }
5686 : : }
5687 : :
5688 : 15335 : if (cvt_type)
5689 : 101 : vec_dest = vect_create_destination_var (scalar_dest,
5690 : : widen_or_narrow_float_p
5691 : : ? vectype_out : cvt_type);
5692 : :
5693 : 15335 : int ninputs = 1;
5694 : 15335 : if (!slp_node)
5695 : : {
5696 : 13517 : if (modifier == WIDEN)
5697 : : ;
5698 : 7688 : else if (modifier == NARROW_SRC || modifier == NARROW_DST)
5699 : : {
5700 : 5828 : if (multi_step_cvt)
5701 : 1407 : ninputs = vect_pow2 (multi_step_cvt);
5702 : 5828 : ninputs *= 2;
5703 : : }
5704 : : }
5705 : :
5706 : 9506 : switch (modifier)
5707 : : {
5708 : 2947 : case NONE:
5709 : 2947 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
5710 : : op0, vectype_in, &vec_oprnds0);
5711 : : /* vec_dest is intermediate type operand when multi_step_cvt. */
5712 : 2947 : if (multi_step_cvt)
5713 : : {
5714 : 28 : cvt_op = vec_dest;
5715 : 28 : vec_dest = vec_dsts[0];
5716 : : }
5717 : :
5718 : 6180 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
5719 : : {
5720 : : /* Arguments are ready, create the new vector stmt. */
5721 : 3233 : gimple* new_stmt;
5722 : 3233 : if (multi_step_cvt)
5723 : : {
5724 : 28 : gcc_assert (multi_step_cvt == 1);
5725 : 28 : new_stmt = vect_gimple_build (cvt_op, codecvt1, vop0);
5726 : 28 : new_temp = make_ssa_name (cvt_op, new_stmt);
5727 : 28 : gimple_assign_set_lhs (new_stmt, new_temp);
5728 : 28 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5729 : 28 : vop0 = new_temp;
5730 : : }
5731 : 3233 : new_stmt = vect_gimple_build (vec_dest, code1, vop0);
5732 : 3233 : new_temp = make_ssa_name (vec_dest, new_stmt);
5733 : 3233 : gimple_set_lhs (new_stmt, new_temp);
5734 : 3233 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5735 : :
5736 : 3233 : if (slp_node)
5737 : 1323 : slp_node->push_vec_def (new_stmt);
5738 : : else
5739 : 1910 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
5740 : : }
5741 : : break;
5742 : :
5743 : 6193 : case WIDEN:
5744 : : /* In case the vectorization factor (VF) is bigger than the number
5745 : : of elements that we can fit in a vectype (nunits), we have to
5746 : : generate more than one vector stmt - i.e - we need to "unroll"
5747 : : the vector stmt by a factor VF/nunits. */
5748 : 6193 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies * ninputs,
5749 : : op0, vectype_in, &vec_oprnds0,
5750 : 6193 : code == WIDEN_LSHIFT_EXPR ? NULL_TREE : op1,
5751 : : vectype_in, &vec_oprnds1);
5752 : 6193 : if (code == WIDEN_LSHIFT_EXPR)
5753 : : {
5754 : 0 : int oprnds_size = vec_oprnds0.length ();
5755 : 0 : vec_oprnds1.create (oprnds_size);
5756 : 0 : for (i = 0; i < oprnds_size; ++i)
5757 : 0 : vec_oprnds1.quick_push (op1);
5758 : : }
5759 : : /* Arguments are ready. Create the new vector stmts. */
5760 : 13143 : for (i = multi_step_cvt; i >= 0; i--)
5761 : : {
5762 : 6950 : tree this_dest = vec_dsts[i];
5763 : 6950 : code_helper c1 = code1, c2 = code2;
5764 : 6950 : if (i == 0 && codecvt2 != ERROR_MARK)
5765 : : {
5766 : 48 : c1 = codecvt1;
5767 : 48 : c2 = codecvt2;
5768 : : }
5769 : 6950 : if (known_eq (nunits_out, nunits_in))
5770 : 14 : vect_create_half_widening_stmts (vinfo, &vec_oprnds0, &vec_oprnds1,
5771 : : stmt_info, this_dest, gsi, c1,
5772 : : op_type);
5773 : : else
5774 : 6936 : vect_create_vectorized_promotion_stmts (vinfo, &vec_oprnds0,
5775 : : &vec_oprnds1, stmt_info,
5776 : : this_dest, gsi,
5777 : : c1, c2, op_type);
5778 : : }
5779 : :
5780 : 22125 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
5781 : : {
5782 : 15932 : gimple *new_stmt;
5783 : 15932 : if (cvt_type)
5784 : : {
5785 : 120 : new_temp = make_ssa_name (vec_dest);
5786 : 120 : new_stmt = vect_gimple_build (new_temp, codecvt1, vop0);
5787 : 120 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5788 : : }
5789 : : else
5790 : 15812 : new_stmt = SSA_NAME_DEF_STMT (vop0);
5791 : :
5792 : 15932 : if (slp_node)
5793 : 1562 : slp_node->push_vec_def (new_stmt);
5794 : : else
5795 : 14370 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
5796 : : }
5797 : : break;
5798 : :
5799 : 6195 : case NARROW_SRC:
5800 : 6195 : case NARROW_DST:
5801 : : /* In case the vectorization factor (VF) is bigger than the number
5802 : : of elements that we can fit in a vectype (nunits), we have to
5803 : : generate more than one vector stmt - i.e - we need to "unroll"
5804 : : the vector stmt by a factor VF/nunits. */
5805 : 6195 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies * ninputs,
5806 : : op0, vectype_in, &vec_oprnds0);
5807 : : /* Arguments are ready. Create the new vector stmts. */
5808 : 6195 : if (cvt_type && modifier == NARROW_DST)
5809 : 201 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
5810 : : {
5811 : 156 : new_temp = make_ssa_name (vec_dest);
5812 : 156 : gimple *new_stmt = vect_gimple_build (new_temp, codecvt1, vop0);
5813 : 156 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5814 : 156 : vec_oprnds0[i] = new_temp;
5815 : : }
5816 : :
5817 : 6195 : vect_create_vectorized_demotion_stmts (vinfo, &vec_oprnds0,
5818 : : multi_step_cvt,
5819 : : stmt_info, vec_dsts, gsi,
5820 : : slp_node, code1,
5821 : : modifier == NARROW_SRC);
5822 : : /* After demoting op0 to cvt_type, convert it to dest. */
5823 : 6195 : if (cvt_type && code == FLOAT_EXPR)
5824 : : {
5825 : 2 : for (unsigned int i = 0; i != vec_oprnds0.length() / 2; i++)
5826 : : {
5827 : : /* Arguments are ready, create the new vector stmt. */
5828 : 1 : gcc_assert (TREE_CODE_LENGTH ((tree_code) codecvt1) == unary_op);
5829 : 1 : gimple *new_stmt
5830 : 1 : = vect_gimple_build (vec_dest, codecvt1, vec_oprnds0[i]);
5831 : 1 : new_temp = make_ssa_name (vec_dest, new_stmt);
5832 : 1 : gimple_set_lhs (new_stmt, new_temp);
5833 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5834 : :
5835 : : /* This is the last step of the conversion sequence. Store the
5836 : : vectors in SLP_NODE or in vector info of the scalar statement
5837 : : (or in STMT_VINFO_RELATED_STMT chain). */
5838 : 1 : if (slp_node)
5839 : 0 : slp_node->push_vec_def (new_stmt);
5840 : : else
5841 : 1 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
5842 : : }
5843 : : }
5844 : : break;
5845 : : }
5846 : 15335 : if (!slp_node)
5847 : 13517 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
5848 : :
5849 : 15335 : vec_oprnds0.release ();
5850 : 15335 : vec_oprnds1.release ();
5851 : 15335 : interm_types.release ();
5852 : :
5853 : 15335 : return true;
5854 : : }
5855 : :
5856 : : /* Return true if we can assume from the scalar form of STMT_INFO that
5857 : : neither the scalar nor the vector forms will generate code. STMT_INFO
5858 : : is known not to involve a data reference. */
5859 : :
5860 : : bool
5861 : 720228 : vect_nop_conversion_p (stmt_vec_info stmt_info)
5862 : : {
5863 : 720228 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
5864 : 619486 : if (!stmt)
5865 : : return false;
5866 : :
5867 : 619486 : tree lhs = gimple_assign_lhs (stmt);
5868 : 619486 : tree_code code = gimple_assign_rhs_code (stmt);
5869 : 619486 : tree rhs = gimple_assign_rhs1 (stmt);
5870 : :
5871 : 619486 : if (code == SSA_NAME || code == VIEW_CONVERT_EXPR)
5872 : : return true;
5873 : :
5874 : 617838 : if (CONVERT_EXPR_CODE_P (code))
5875 : 165679 : return tree_nop_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs));
5876 : :
5877 : : return false;
5878 : : }
5879 : :
5880 : : /* Function vectorizable_assignment.
5881 : :
5882 : : Check if STMT_INFO performs an assignment (copy) that can be vectorized.
5883 : : If VEC_STMT is also passed, vectorize the STMT_INFO: create a vectorized
5884 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
5885 : : Return true if STMT_INFO is vectorizable in this way. */
5886 : :
5887 : : static bool
5888 : 1395822 : vectorizable_assignment (vec_info *vinfo,
5889 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
5890 : : gimple **vec_stmt, slp_tree slp_node,
5891 : : stmt_vector_for_cost *cost_vec)
5892 : : {
5893 : 1395822 : tree vec_dest;
5894 : 1395822 : tree scalar_dest;
5895 : 1395822 : tree op;
5896 : 1395822 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
5897 : 1395822 : tree new_temp;
5898 : 1395822 : enum vect_def_type dt[1] = {vect_unknown_def_type};
5899 : 1395822 : int ndts = 1;
5900 : 1395822 : int ncopies;
5901 : 1395822 : int i;
5902 : 1395822 : vec<tree> vec_oprnds = vNULL;
5903 : 1395822 : tree vop;
5904 : 1395822 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
5905 : 1395822 : enum tree_code code;
5906 : 1395822 : tree vectype_in;
5907 : :
5908 : 1395822 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
5909 : : return false;
5910 : :
5911 : 1395822 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
5912 : 24817 : && ! vec_stmt)
5913 : : return false;
5914 : :
5915 : : /* Is vectorizable assignment? */
5916 : 2626491 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
5917 : 1302900 : if (!stmt)
5918 : : return false;
5919 : :
5920 : 1302900 : scalar_dest = gimple_assign_lhs (stmt);
5921 : 1302900 : if (TREE_CODE (scalar_dest) != SSA_NAME)
5922 : : return false;
5923 : :
5924 : 580330 : if (STMT_VINFO_DATA_REF (stmt_info))
5925 : : return false;
5926 : :
5927 : 255125 : code = gimple_assign_rhs_code (stmt);
5928 : 255125 : if (!(gimple_assign_single_p (stmt)
5929 : 253915 : || code == PAREN_EXPR
5930 : 252745 : || CONVERT_EXPR_CODE_P (code)))
5931 : : return false;
5932 : :
5933 : 86907 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
5934 : 86907 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
5935 : :
5936 : : /* Multiple types in SLP are handled by creating the appropriate number of
5937 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
5938 : : case of SLP. */
5939 : 86907 : if (slp_node)
5940 : : ncopies = 1;
5941 : : else
5942 : 50961 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
5943 : :
5944 : 50961 : gcc_assert (ncopies >= 1);
5945 : :
5946 : 86907 : slp_tree slp_op;
5947 : 86907 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &op, &slp_op,
5948 : : &dt[0], &vectype_in))
5949 : : {
5950 : 64 : if (dump_enabled_p ())
5951 : 2 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5952 : : "use not simple.\n");
5953 : 64 : return false;
5954 : : }
5955 : 86843 : if (!vectype_in)
5956 : 19857 : vectype_in = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op), slp_node);
5957 : :
5958 : : /* We can handle NOP_EXPR conversions that do not change the number
5959 : : of elements or the vector size. */
5960 : 86843 : if ((CONVERT_EXPR_CODE_P (code)
5961 : 2316 : || code == VIEW_CONVERT_EXPR)
5962 : 87883 : && (!vectype_in
5963 : 84157 : || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype_in), nunits)
5964 : 152560 : || maybe_ne (GET_MODE_SIZE (TYPE_MODE (vectype)),
5965 : 152560 : GET_MODE_SIZE (TYPE_MODE (vectype_in)))))
5966 : 14406 : return false;
5967 : :
5968 : 217310 : if (VECTOR_BOOLEAN_TYPE_P (vectype) != VECTOR_BOOLEAN_TYPE_P (vectype_in))
5969 : : {
5970 : 1 : if (dump_enabled_p ())
5971 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5972 : : "can't convert between boolean and non "
5973 : 0 : "boolean vectors %T\n", TREE_TYPE (op));
5974 : :
5975 : 1 : return false;
5976 : : }
5977 : :
5978 : : /* We do not handle bit-precision changes. */
5979 : 72436 : if ((CONVERT_EXPR_CODE_P (code)
5980 : 2142 : || code == VIEW_CONVERT_EXPR)
5981 : 71160 : && ((INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
5982 : 69623 : && !type_has_mode_precision_p (TREE_TYPE (scalar_dest)))
5983 : 70969 : || (INTEGRAL_TYPE_P (TREE_TYPE (op))
5984 : 67172 : && !type_has_mode_precision_p (TREE_TYPE (op))))
5985 : : /* But a conversion that does not change the bit-pattern is ok. */
5986 : 73022 : && !(INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
5987 : 586 : && INTEGRAL_TYPE_P (TREE_TYPE (op))
5988 : 586 : && (((TYPE_PRECISION (TREE_TYPE (scalar_dest))
5989 : 586 : > TYPE_PRECISION (TREE_TYPE (op)))
5990 : 395 : && TYPE_UNSIGNED (TREE_TYPE (op)))
5991 : 211 : || (TYPE_PRECISION (TREE_TYPE (scalar_dest))
5992 : 211 : == TYPE_PRECISION (TREE_TYPE (op))))))
5993 : : {
5994 : 205 : if (dump_enabled_p ())
5995 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5996 : : "type conversion to/from bit-precision "
5997 : : "unsupported.\n");
5998 : 205 : return false;
5999 : : }
6000 : :
6001 : 72231 : if (!vec_stmt) /* transformation not required. */
6002 : : {
6003 : 55247 : if (slp_node
6004 : 55247 : && !vect_maybe_update_slp_op_vectype (slp_op, vectype_in))
6005 : : {
6006 : 0 : if (dump_enabled_p ())
6007 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6008 : : "incompatible vector types for invariants\n");
6009 : 0 : return false;
6010 : : }
6011 : 55247 : STMT_VINFO_TYPE (stmt_info) = assignment_vec_info_type;
6012 : 55247 : DUMP_VECT_SCOPE ("vectorizable_assignment");
6013 : 55247 : if (!vect_nop_conversion_p (stmt_info))
6014 : 978 : vect_model_simple_cost (vinfo, stmt_info, ncopies, dt, ndts, slp_node,
6015 : : cost_vec);
6016 : 55247 : return true;
6017 : : }
6018 : :
6019 : : /* Transform. */
6020 : 16984 : if (dump_enabled_p ())
6021 : 3280 : dump_printf_loc (MSG_NOTE, vect_location, "transform assignment.\n");
6022 : :
6023 : : /* Handle def. */
6024 : 16984 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6025 : :
6026 : : /* Handle use. */
6027 : 16984 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, op, &vec_oprnds);
6028 : :
6029 : : /* Arguments are ready. create the new vector stmt. */
6030 : 36214 : FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
6031 : : {
6032 : 19230 : if (CONVERT_EXPR_CODE_P (code)
6033 : 542 : || code == VIEW_CONVERT_EXPR)
6034 : 18725 : vop = build1 (VIEW_CONVERT_EXPR, vectype, vop);
6035 : 19230 : gassign *new_stmt = gimple_build_assign (vec_dest, vop);
6036 : 19230 : new_temp = make_ssa_name (vec_dest, new_stmt);
6037 : 19230 : gimple_assign_set_lhs (new_stmt, new_temp);
6038 : 19230 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6039 : 19230 : if (slp_node)
6040 : 3787 : slp_node->push_vec_def (new_stmt);
6041 : : else
6042 : 15443 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
6043 : : }
6044 : 16984 : if (!slp_node)
6045 : 14242 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
6046 : :
6047 : 16984 : vec_oprnds.release ();
6048 : 16984 : return true;
6049 : : }
6050 : :
6051 : :
6052 : : /* Return TRUE if CODE (a shift operation) is supported for SCALAR_TYPE
6053 : : either as shift by a scalar or by a vector. */
6054 : :
6055 : : bool
6056 : 197327 : vect_supportable_shift (vec_info *vinfo, enum tree_code code, tree scalar_type)
6057 : : {
6058 : :
6059 : 197327 : machine_mode vec_mode;
6060 : 197327 : optab optab;
6061 : 197327 : int icode;
6062 : 197327 : tree vectype;
6063 : :
6064 : 197327 : vectype = get_vectype_for_scalar_type (vinfo, scalar_type);
6065 : 197327 : if (!vectype)
6066 : : return false;
6067 : :
6068 : 197327 : optab = optab_for_tree_code (code, vectype, optab_scalar);
6069 : 197327 : if (!optab
6070 : 197327 : || optab_handler (optab, TYPE_MODE (vectype)) == CODE_FOR_nothing)
6071 : : {
6072 : 173921 : optab = optab_for_tree_code (code, vectype, optab_vector);
6073 : 173921 : if (!optab
6074 : 173921 : || (optab_handler (optab, TYPE_MODE (vectype))
6075 : : == CODE_FOR_nothing))
6076 : 173921 : return false;
6077 : : }
6078 : :
6079 : 23406 : vec_mode = TYPE_MODE (vectype);
6080 : 23406 : icode = (int) optab_handler (optab, vec_mode);
6081 : 23406 : if (icode == CODE_FOR_nothing)
6082 : : return false;
6083 : :
6084 : : return true;
6085 : : }
6086 : :
6087 : :
6088 : : /* Function vectorizable_shift.
6089 : :
6090 : : Check if STMT_INFO performs a shift operation that can be vectorized.
6091 : : If VEC_STMT is also passed, vectorize the STMT_INFO: create a vectorized
6092 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
6093 : : Return true if STMT_INFO is vectorizable in this way. */
6094 : :
6095 : : static bool
6096 : 1237704 : vectorizable_shift (vec_info *vinfo,
6097 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
6098 : : gimple **vec_stmt, slp_tree slp_node,
6099 : : stmt_vector_for_cost *cost_vec)
6100 : : {
6101 : 1237704 : tree vec_dest;
6102 : 1237704 : tree scalar_dest;
6103 : 1237704 : tree op0, op1 = NULL;
6104 : 1237704 : tree vec_oprnd1 = NULL_TREE;
6105 : 1237704 : tree vectype;
6106 : 1237704 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
6107 : 1237704 : enum tree_code code;
6108 : 1237704 : machine_mode vec_mode;
6109 : 1237704 : tree new_temp;
6110 : 1237704 : optab optab;
6111 : 1237704 : int icode;
6112 : 1237704 : machine_mode optab_op2_mode;
6113 : 1237704 : enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
6114 : 1237704 : int ndts = 2;
6115 : 1237704 : poly_uint64 nunits_in;
6116 : 1237704 : poly_uint64 nunits_out;
6117 : 1237704 : tree vectype_out;
6118 : 1237704 : tree op1_vectype;
6119 : 1237704 : int ncopies;
6120 : 1237704 : int i;
6121 : 1237704 : vec<tree> vec_oprnds0 = vNULL;
6122 : 1237704 : vec<tree> vec_oprnds1 = vNULL;
6123 : 1237704 : tree vop0, vop1;
6124 : 1237704 : unsigned int k;
6125 : 1237704 : bool scalar_shift_arg = true;
6126 : 1237704 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
6127 : 1237704 : bool incompatible_op1_vectype_p = false;
6128 : :
6129 : 1237704 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
6130 : : return false;
6131 : :
6132 : 1237704 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
6133 : 18547 : && STMT_VINFO_DEF_TYPE (stmt_info) != vect_nested_cycle
6134 : 18547 : && ! vec_stmt)
6135 : : return false;
6136 : :
6137 : : /* Is STMT a vectorizable binary/unary operation? */
6138 : 2353057 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
6139 : 1153714 : if (!stmt)
6140 : : return false;
6141 : :
6142 : 1153714 : if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
6143 : : return false;
6144 : :
6145 : 539013 : code = gimple_assign_rhs_code (stmt);
6146 : :
6147 : 539013 : if (!(code == LSHIFT_EXPR || code == RSHIFT_EXPR || code == LROTATE_EXPR
6148 : : || code == RROTATE_EXPR))
6149 : : return false;
6150 : :
6151 : 46242 : scalar_dest = gimple_assign_lhs (stmt);
6152 : 46242 : vectype_out = STMT_VINFO_VECTYPE (stmt_info);
6153 : 46242 : if (!type_has_mode_precision_p (TREE_TYPE (scalar_dest)))
6154 : : {
6155 : 0 : if (dump_enabled_p ())
6156 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6157 : : "bit-precision shifts not supported.\n");
6158 : 0 : return false;
6159 : : }
6160 : :
6161 : 46242 : slp_tree slp_op0;
6162 : 46242 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
6163 : : 0, &op0, &slp_op0, &dt[0], &vectype))
6164 : : {
6165 : 0 : if (dump_enabled_p ())
6166 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6167 : : "use not simple.\n");
6168 : 0 : return false;
6169 : : }
6170 : : /* If op0 is an external or constant def, infer the vector type
6171 : : from the scalar type. */
6172 : 46242 : if (!vectype)
6173 : 11819 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0), slp_node);
6174 : 46242 : if (vec_stmt)
6175 : 5522 : gcc_assert (vectype);
6176 : 46242 : if (!vectype)
6177 : : {
6178 : 0 : if (dump_enabled_p ())
6179 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6180 : : "no vectype for scalar type\n");
6181 : 0 : return false;
6182 : : }
6183 : :
6184 : 46242 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
6185 : 46242 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
6186 : 46242 : if (maybe_ne (nunits_out, nunits_in))
6187 : : return false;
6188 : :
6189 : 46242 : stmt_vec_info op1_def_stmt_info;
6190 : 46242 : slp_tree slp_op1;
6191 : 46242 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1, &op1, &slp_op1,
6192 : : &dt[1], &op1_vectype, &op1_def_stmt_info))
6193 : : {
6194 : 0 : if (dump_enabled_p ())
6195 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6196 : : "use not simple.\n");
6197 : 0 : return false;
6198 : : }
6199 : :
6200 : : /* Multiple types in SLP are handled by creating the appropriate number of
6201 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
6202 : : case of SLP. */
6203 : 46242 : if (slp_node)
6204 : : ncopies = 1;
6205 : : else
6206 : 23722 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
6207 : :
6208 : 23722 : gcc_assert (ncopies >= 1);
6209 : :
6210 : : /* Determine whether the shift amount is a vector, or scalar. If the
6211 : : shift/rotate amount is a vector, use the vector/vector shift optabs. */
6212 : :
6213 : 46242 : if ((dt[1] == vect_internal_def
6214 : 46242 : || dt[1] == vect_induction_def
6215 : 36165 : || dt[1] == vect_nested_cycle)
6216 : 10101 : && !slp_node)
6217 : : scalar_shift_arg = false;
6218 : 36189 : else if (dt[1] == vect_constant_def
6219 : : || dt[1] == vect_external_def
6220 : 36189 : || dt[1] == vect_internal_def)
6221 : : {
6222 : : /* In SLP, need to check whether the shift count is the same,
6223 : : in loops if it is a constant or invariant, it is always
6224 : : a scalar shift. */
6225 : 36187 : if (slp_node)
6226 : : {
6227 : 22518 : vec<stmt_vec_info> stmts = SLP_TREE_SCALAR_STMTS (slp_node);
6228 : 22518 : stmt_vec_info slpstmt_info;
6229 : :
6230 : 75546 : FOR_EACH_VEC_ELT (stmts, k, slpstmt_info)
6231 : : {
6232 : 53028 : gassign *slpstmt = as_a <gassign *> (slpstmt_info->stmt);
6233 : 106056 : if (!operand_equal_p (gimple_assign_rhs2 (slpstmt), op1, 0))
6234 : 354 : scalar_shift_arg = false;
6235 : : }
6236 : :
6237 : : /* For internal SLP defs we have to make sure we see scalar stmts
6238 : : for all vector elements.
6239 : : ??? For different vectors we could resort to a different
6240 : : scalar shift operand but code-generation below simply always
6241 : : takes the first. */
6242 : 22518 : if (dt[1] == vect_internal_def
6243 : 22518 : && maybe_ne (nunits_out * SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node),
6244 : 46 : stmts.length ()))
6245 : : scalar_shift_arg = false;
6246 : : }
6247 : :
6248 : : /* If the shift amount is computed by a pattern stmt we cannot
6249 : : use the scalar amount directly thus give up and use a vector
6250 : : shift. */
6251 : 36187 : if (op1_def_stmt_info && is_pattern_stmt_p (op1_def_stmt_info))
6252 : : scalar_shift_arg = false;
6253 : : }
6254 : : else
6255 : : {
6256 : 2 : if (dump_enabled_p ())
6257 : 2 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6258 : : "operand mode requires invariant argument.\n");
6259 : 2 : return false;
6260 : : }
6261 : :
6262 : : /* Vector shifted by vector. */
6263 : 46266 : bool was_scalar_shift_arg = scalar_shift_arg;
6264 : 36179 : if (!scalar_shift_arg)
6265 : : {
6266 : 10087 : optab = optab_for_tree_code (code, vectype, optab_vector);
6267 : 10087 : if (dump_enabled_p ())
6268 : 639 : dump_printf_loc (MSG_NOTE, vect_location,
6269 : : "vector/vector shift/rotate found.\n");
6270 : :
6271 : 10087 : if (!op1_vectype)
6272 : 7 : op1_vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op1),
6273 : : slp_op1);
6274 : 10087 : incompatible_op1_vectype_p
6275 : 20174 : = (op1_vectype == NULL_TREE
6276 : 10087 : || maybe_ne (TYPE_VECTOR_SUBPARTS (op1_vectype),
6277 : 10087 : TYPE_VECTOR_SUBPARTS (vectype))
6278 : 14169 : || TYPE_MODE (op1_vectype) != TYPE_MODE (vectype));
6279 : 4077 : if (incompatible_op1_vectype_p
6280 : 6010 : && (!slp_node
6281 : 7 : || SLP_TREE_DEF_TYPE (slp_op1) != vect_constant_def
6282 : 1 : || slp_op1->refcnt != 1))
6283 : : {
6284 : 6009 : if (dump_enabled_p ())
6285 : 74 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6286 : : "unusable type for last operand in"
6287 : : " vector/vector shift/rotate.\n");
6288 : 6009 : return false;
6289 : : }
6290 : : }
6291 : : /* See if the machine has a vector shifted by scalar insn and if not
6292 : : then see if it has a vector shifted by vector insn. */
6293 : : else
6294 : : {
6295 : 36153 : optab = optab_for_tree_code (code, vectype, optab_scalar);
6296 : 36153 : if (optab
6297 : 36153 : && optab_handler (optab, TYPE_MODE (vectype)) != CODE_FOR_nothing)
6298 : : {
6299 : 36092 : if (dump_enabled_p ())
6300 : 4824 : dump_printf_loc (MSG_NOTE, vect_location,
6301 : : "vector/scalar shift/rotate found.\n");
6302 : : }
6303 : : else
6304 : : {
6305 : 61 : optab = optab_for_tree_code (code, vectype, optab_vector);
6306 : 61 : if (optab
6307 : 61 : && (optab_handler (optab, TYPE_MODE (vectype))
6308 : : != CODE_FOR_nothing))
6309 : : {
6310 : 0 : scalar_shift_arg = false;
6311 : :
6312 : 0 : if (dump_enabled_p ())
6313 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
6314 : : "vector/vector shift/rotate found.\n");
6315 : :
6316 : 0 : if (!op1_vectype)
6317 : 0 : op1_vectype = get_vectype_for_scalar_type (vinfo,
6318 : 0 : TREE_TYPE (op1),
6319 : : slp_op1);
6320 : :
6321 : : /* Unlike the other binary operators, shifts/rotates have
6322 : : the rhs being int, instead of the same type as the lhs,
6323 : : so make sure the scalar is the right type if we are
6324 : : dealing with vectors of long long/long/short/char. */
6325 : 0 : incompatible_op1_vectype_p
6326 : 0 : = (!op1_vectype
6327 : 0 : || !tree_nop_conversion_p (TREE_TYPE (vectype),
6328 : 0 : TREE_TYPE (op1)));
6329 : 0 : if (incompatible_op1_vectype_p
6330 : 0 : && dt[1] == vect_internal_def)
6331 : : {
6332 : 0 : if (dump_enabled_p ())
6333 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6334 : : "unusable type for last operand in"
6335 : : " vector/vector shift/rotate.\n");
6336 : 0 : return false;
6337 : : }
6338 : : }
6339 : : }
6340 : : }
6341 : :
6342 : : /* Supportable by target? */
6343 : 40231 : if (!optab)
6344 : : {
6345 : 0 : if (dump_enabled_p ())
6346 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6347 : : "no optab.\n");
6348 : 0 : return false;
6349 : : }
6350 : 40231 : vec_mode = TYPE_MODE (vectype);
6351 : 40231 : icode = (int) optab_handler (optab, vec_mode);
6352 : 40231 : if (icode == CODE_FOR_nothing)
6353 : : {
6354 : 1870 : if (dump_enabled_p ())
6355 : 389 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6356 : : "op not supported by target.\n");
6357 : 1870 : return false;
6358 : : }
6359 : : /* vector lowering cannot optimize vector shifts using word arithmetic. */
6360 : 38361 : if (vect_emulated_vector_p (vectype))
6361 : : return false;
6362 : :
6363 : 38361 : if (!vec_stmt) /* transformation not required. */
6364 : : {
6365 : 32839 : if (slp_node
6366 : 32839 : && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
6367 : 22000 : || ((!scalar_shift_arg || dt[1] == vect_internal_def)
6368 : 27 : && (!incompatible_op1_vectype_p
6369 : 1 : || dt[1] == vect_constant_def)
6370 : 27 : && !vect_maybe_update_slp_op_vectype
6371 : 27 : (slp_op1,
6372 : : incompatible_op1_vectype_p ? vectype : op1_vectype))))
6373 : : {
6374 : 0 : if (dump_enabled_p ())
6375 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6376 : : "incompatible vector types for invariants\n");
6377 : 0 : return false;
6378 : : }
6379 : : /* Now adjust the constant shift amount in place. */
6380 : 32839 : if (slp_node
6381 : 32839 : && incompatible_op1_vectype_p
6382 : 1 : && dt[1] == vect_constant_def)
6383 : : {
6384 : 4 : for (unsigned i = 0;
6385 : 10 : i < SLP_TREE_SCALAR_OPS (slp_op1).length (); ++i)
6386 : : {
6387 : 4 : SLP_TREE_SCALAR_OPS (slp_op1)[i]
6388 : 4 : = fold_convert (TREE_TYPE (vectype),
6389 : : SLP_TREE_SCALAR_OPS (slp_op1)[i]);
6390 : 4 : gcc_assert ((TREE_CODE (SLP_TREE_SCALAR_OPS (slp_op1)[i])
6391 : : == INTEGER_CST));
6392 : : }
6393 : : }
6394 : 32839 : STMT_VINFO_TYPE (stmt_info) = shift_vec_info_type;
6395 : 32839 : DUMP_VECT_SCOPE ("vectorizable_shift");
6396 : 34428 : vect_model_simple_cost (vinfo, stmt_info, ncopies, dt,
6397 : : scalar_shift_arg ? 1 : ndts, slp_node, cost_vec);
6398 : 32839 : return true;
6399 : : }
6400 : :
6401 : : /* Transform. */
6402 : :
6403 : 5522 : if (dump_enabled_p ())
6404 : 1844 : dump_printf_loc (MSG_NOTE, vect_location,
6405 : : "transform binary/unary operation.\n");
6406 : :
6407 : 5522 : if (incompatible_op1_vectype_p && !slp_node)
6408 : : {
6409 : 0 : gcc_assert (!scalar_shift_arg && was_scalar_shift_arg);
6410 : 0 : op1 = fold_convert (TREE_TYPE (vectype), op1);
6411 : 0 : if (dt[1] != vect_constant_def)
6412 : 0 : op1 = vect_init_vector (vinfo, stmt_info, op1,
6413 : 0 : TREE_TYPE (vectype), NULL);
6414 : : }
6415 : :
6416 : : /* Handle def. */
6417 : 5522 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6418 : :
6419 : 5522 : if (scalar_shift_arg && dt[1] != vect_internal_def)
6420 : : {
6421 : : /* Vector shl and shr insn patterns can be defined with scalar
6422 : : operand 2 (shift operand). In this case, use constant or loop
6423 : : invariant op1 directly, without extending it to vector mode
6424 : : first. */
6425 : 4832 : optab_op2_mode = insn_data[icode].operand[2].mode;
6426 : 4832 : if (!VECTOR_MODE_P (optab_op2_mode))
6427 : : {
6428 : 4832 : if (dump_enabled_p ())
6429 : 1755 : dump_printf_loc (MSG_NOTE, vect_location,
6430 : : "operand 1 using scalar mode.\n");
6431 : 4832 : vec_oprnd1 = op1;
6432 : 4832 : vec_oprnds1.create (slp_node ? slp_node->vec_stmts_size : ncopies);
6433 : 4832 : vec_oprnds1.quick_push (vec_oprnd1);
6434 : : /* Store vec_oprnd1 for every vector stmt to be created.
6435 : : We check during the analysis that all the shift arguments
6436 : : are the same.
6437 : : TODO: Allow different constants for different vector
6438 : : stmts generated for an SLP instance. */
6439 : 4832 : for (k = 0;
6440 : 6798 : k < (slp_node ? slp_node->vec_stmts_size - 1 : ncopies - 1); k++)
6441 : 1966 : vec_oprnds1.quick_push (vec_oprnd1);
6442 : : }
6443 : : }
6444 : 690 : else if (!scalar_shift_arg && slp_node && incompatible_op1_vectype_p)
6445 : : {
6446 : 0 : if (was_scalar_shift_arg)
6447 : : {
6448 : : /* If the argument was the same in all lanes create
6449 : : the correctly typed vector shift amount directly. */
6450 : 0 : op1 = fold_convert (TREE_TYPE (vectype), op1);
6451 : 0 : op1 = vect_init_vector (vinfo, stmt_info, op1, TREE_TYPE (vectype),
6452 : : !loop_vinfo ? gsi : NULL);
6453 : 0 : vec_oprnd1 = vect_init_vector (vinfo, stmt_info, op1, vectype,
6454 : : !loop_vinfo ? gsi : NULL);
6455 : 0 : vec_oprnds1.create (slp_node->vec_stmts_size);
6456 : 0 : for (k = 0; k < slp_node->vec_stmts_size; k++)
6457 : 0 : vec_oprnds1.quick_push (vec_oprnd1);
6458 : : }
6459 : 0 : else if (dt[1] == vect_constant_def)
6460 : : /* The constant shift amount has been adjusted in place. */
6461 : : ;
6462 : : else
6463 : 0 : gcc_assert (TYPE_MODE (op1_vectype) == TYPE_MODE (vectype));
6464 : : }
6465 : :
6466 : : /* vec_oprnd1 is available if operand 1 should be of a scalar-type
6467 : : (a special case for certain kind of vector shifts); otherwise,
6468 : : operand 1 should be of a vector type (the usual case). */
6469 : 690 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
6470 : : op0, &vec_oprnds0,
6471 : 5522 : vec_oprnd1 ? NULL_TREE : op1, &vec_oprnds1);
6472 : :
6473 : : /* Arguments are ready. Create the new vector stmt. */
6474 : 13407 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6475 : : {
6476 : : /* For internal defs where we need to use a scalar shift arg
6477 : : extract the first lane. */
6478 : 7885 : if (scalar_shift_arg && dt[1] == vect_internal_def)
6479 : : {
6480 : 10 : vop1 = vec_oprnds1[0];
6481 : 10 : new_temp = make_ssa_name (TREE_TYPE (TREE_TYPE (vop1)));
6482 : 10 : gassign *new_stmt
6483 : 10 : = gimple_build_assign (new_temp,
6484 : 10 : build3 (BIT_FIELD_REF, TREE_TYPE (new_temp),
6485 : : vop1,
6486 : 10 : TYPE_SIZE (TREE_TYPE (new_temp)),
6487 : : bitsize_zero_node));
6488 : 10 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6489 : 10 : vop1 = new_temp;
6490 : 10 : }
6491 : : else
6492 : 7875 : vop1 = vec_oprnds1[i];
6493 : 7885 : gassign *new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1);
6494 : 7885 : new_temp = make_ssa_name (vec_dest, new_stmt);
6495 : 7885 : gimple_assign_set_lhs (new_stmt, new_temp);
6496 : 7885 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6497 : 7885 : if (slp_node)
6498 : 1147 : slp_node->push_vec_def (new_stmt);
6499 : : else
6500 : 6738 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
6501 : : }
6502 : :
6503 : 5522 : if (!slp_node)
6504 : 5016 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
6505 : :
6506 : 5522 : vec_oprnds0.release ();
6507 : 5522 : vec_oprnds1.release ();
6508 : :
6509 : 5522 : return true;
6510 : : }
6511 : :
6512 : : /* Function vectorizable_operation.
6513 : :
6514 : : Check if STMT_INFO performs a binary, unary or ternary operation that can
6515 : : be vectorized.
6516 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
6517 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
6518 : : Return true if STMT_INFO is vectorizable in this way. */
6519 : :
6520 : : static bool
6521 : 1817164 : vectorizable_operation (vec_info *vinfo,
6522 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
6523 : : gimple **vec_stmt, slp_tree slp_node,
6524 : : stmt_vector_for_cost *cost_vec)
6525 : : {
6526 : 1817164 : tree vec_dest;
6527 : 1817164 : tree scalar_dest;
6528 : 1817164 : tree op0, op1 = NULL_TREE, op2 = NULL_TREE;
6529 : 1817164 : tree vectype;
6530 : 1817164 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
6531 : 1817164 : enum tree_code code, orig_code;
6532 : 1817164 : machine_mode vec_mode;
6533 : 1817164 : tree new_temp;
6534 : 1817164 : int op_type;
6535 : 1817164 : optab optab;
6536 : 1817164 : bool target_support_p;
6537 : 1817164 : enum vect_def_type dt[3]
6538 : : = {vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type};
6539 : 1817164 : int ndts = 3;
6540 : 1817164 : poly_uint64 nunits_in;
6541 : 1817164 : poly_uint64 nunits_out;
6542 : 1817164 : tree vectype_out;
6543 : 1817164 : int ncopies, vec_num;
6544 : 1817164 : int i;
6545 : 1817164 : vec<tree> vec_oprnds0 = vNULL;
6546 : 1817164 : vec<tree> vec_oprnds1 = vNULL;
6547 : 1817164 : vec<tree> vec_oprnds2 = vNULL;
6548 : 1817164 : tree vop0, vop1, vop2;
6549 : 1817164 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
6550 : :
6551 : 1817164 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
6552 : : return false;
6553 : :
6554 : 1817164 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
6555 : 24817 : && ! vec_stmt)
6556 : : return false;
6557 : :
6558 : : /* Is STMT a vectorizable binary/unary operation? */
6559 : 1792347 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
6560 : 1792347 : if (!stmt)
6561 : : return false;
6562 : :
6563 : : /* Loads and stores are handled in vectorizable_{load,store}. */
6564 : 1724242 : if (STMT_VINFO_DATA_REF (stmt_info))
6565 : : return false;
6566 : :
6567 : 676467 : orig_code = code = gimple_assign_rhs_code (stmt);
6568 : :
6569 : : /* Shifts are handled in vectorizable_shift. */
6570 : 676467 : if (code == LSHIFT_EXPR
6571 : : || code == RSHIFT_EXPR
6572 : : || code == LROTATE_EXPR
6573 : 676467 : || code == RROTATE_EXPR)
6574 : : return false;
6575 : :
6576 : : /* Comparisons are handled in vectorizable_comparison. */
6577 : 657389 : if (TREE_CODE_CLASS (code) == tcc_comparison)
6578 : : return false;
6579 : :
6580 : : /* Conditions are handled in vectorizable_condition. */
6581 : 542202 : if (code == COND_EXPR)
6582 : : return false;
6583 : :
6584 : : /* For pointer addition and subtraction, we should use the normal
6585 : : plus and minus for the vector operation. */
6586 : 530029 : if (code == POINTER_PLUS_EXPR)
6587 : : code = PLUS_EXPR;
6588 : 525427 : if (code == POINTER_DIFF_EXPR)
6589 : 2081 : code = MINUS_EXPR;
6590 : :
6591 : : /* Support only unary or binary operations. */
6592 : 530029 : op_type = TREE_CODE_LENGTH (code);
6593 : 530029 : if (op_type != unary_op && op_type != binary_op && op_type != ternary_op)
6594 : : {
6595 : 19 : if (dump_enabled_p ())
6596 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6597 : : "num. args = %d (not unary/binary/ternary op).\n",
6598 : : op_type);
6599 : 19 : return false;
6600 : : }
6601 : :
6602 : 530010 : scalar_dest = gimple_assign_lhs (stmt);
6603 : 530010 : vectype_out = STMT_VINFO_VECTYPE (stmt_info);
6604 : :
6605 : : /* Most operations cannot handle bit-precision types without extra
6606 : : truncations. */
6607 : 530010 : bool mask_op_p = VECTOR_BOOLEAN_TYPE_P (vectype_out);
6608 : 523799 : if (!mask_op_p
6609 : 523799 : && !type_has_mode_precision_p (TREE_TYPE (scalar_dest))
6610 : : /* Exception are bitwise binary operations. */
6611 : : && code != BIT_IOR_EXPR
6612 : 1022 : && code != BIT_XOR_EXPR
6613 : 889 : && code != BIT_AND_EXPR)
6614 : : {
6615 : 669 : if (dump_enabled_p ())
6616 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6617 : : "bit-precision arithmetic not supported.\n");
6618 : 669 : return false;
6619 : : }
6620 : :
6621 : 529341 : slp_tree slp_op0;
6622 : 529341 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
6623 : : 0, &op0, &slp_op0, &dt[0], &vectype))
6624 : : {
6625 : 55 : if (dump_enabled_p ())
6626 : 2 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6627 : : "use not simple.\n");
6628 : 55 : return false;
6629 : : }
6630 : 529286 : bool is_invariant = (dt[0] == vect_external_def
6631 : 529286 : || dt[0] == vect_constant_def);
6632 : : /* If op0 is an external or constant def, infer the vector type
6633 : : from the scalar type. */
6634 : 529286 : if (!vectype)
6635 : : {
6636 : : /* For boolean type we cannot determine vectype by
6637 : : invariant value (don't know whether it is a vector
6638 : : of booleans or vector of integers). We use output
6639 : : vectype because operations on boolean don't change
6640 : : type. */
6641 : 67572 : if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op0)))
6642 : : {
6643 : 1185 : if (!VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (scalar_dest)))
6644 : : {
6645 : 239 : if (dump_enabled_p ())
6646 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6647 : : "not supported operation on bool value.\n");
6648 : 239 : return false;
6649 : : }
6650 : 946 : vectype = vectype_out;
6651 : : }
6652 : : else
6653 : 66387 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0),
6654 : : slp_node);
6655 : : }
6656 : 529047 : if (vec_stmt)
6657 : 95212 : gcc_assert (vectype);
6658 : 529047 : if (!vectype)
6659 : : {
6660 : 1494 : if (dump_enabled_p ())
6661 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6662 : : "no vectype for scalar type %T\n",
6663 : 0 : TREE_TYPE (op0));
6664 : :
6665 : 1494 : return false;
6666 : : }
6667 : :
6668 : 527553 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
6669 : 527553 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
6670 : 527553 : if (maybe_ne (nunits_out, nunits_in))
6671 : : return false;
6672 : :
6673 : 519839 : tree vectype2 = NULL_TREE, vectype3 = NULL_TREE;
6674 : 519839 : slp_tree slp_op1 = NULL, slp_op2 = NULL;
6675 : 519839 : if (op_type == binary_op || op_type == ternary_op)
6676 : : {
6677 : 450673 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
6678 : : 1, &op1, &slp_op1, &dt[1], &vectype2))
6679 : : {
6680 : 0 : if (dump_enabled_p ())
6681 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6682 : : "use not simple.\n");
6683 : 0 : return false;
6684 : : }
6685 : 450673 : is_invariant &= (dt[1] == vect_external_def
6686 : 450673 : || dt[1] == vect_constant_def);
6687 : 450673 : if (vectype2
6688 : 450673 : && maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype2)))
6689 : 164 : return false;
6690 : : }
6691 : 519675 : if (op_type == ternary_op)
6692 : : {
6693 : 0 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
6694 : : 2, &op2, &slp_op2, &dt[2], &vectype3))
6695 : : {
6696 : 0 : if (dump_enabled_p ())
6697 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6698 : : "use not simple.\n");
6699 : 0 : return false;
6700 : : }
6701 : 0 : is_invariant &= (dt[2] == vect_external_def
6702 : 0 : || dt[2] == vect_constant_def);
6703 : 0 : if (vectype3
6704 : 0 : && maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype3)))
6705 : 0 : return false;
6706 : : }
6707 : :
6708 : : /* Multiple types in SLP are handled by creating the appropriate number of
6709 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
6710 : : case of SLP. */
6711 : 519675 : if (slp_node)
6712 : : {
6713 : 219442 : ncopies = 1;
6714 : 219442 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
6715 : : }
6716 : : else
6717 : : {
6718 : 300233 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
6719 : 300233 : vec_num = 1;
6720 : : }
6721 : :
6722 : 519675 : gcc_assert (ncopies >= 1);
6723 : :
6724 : : /* Reject attempts to combine mask types with nonmask types, e.g. if
6725 : : we have an AND between a (nonmask) boolean loaded from memory and
6726 : : a (mask) boolean result of a comparison.
6727 : :
6728 : : TODO: We could easily fix these cases up using pattern statements. */
6729 : 519675 : if (VECTOR_BOOLEAN_TYPE_P (vectype) != mask_op_p
6730 : 817208 : || (vectype2 && VECTOR_BOOLEAN_TYPE_P (vectype2) != mask_op_p)
6731 : 1039338 : || (vectype3 && VECTOR_BOOLEAN_TYPE_P (vectype3) != mask_op_p))
6732 : : {
6733 : 12 : if (dump_enabled_p ())
6734 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6735 : : "mixed mask and nonmask vector types\n");
6736 : 12 : return false;
6737 : : }
6738 : :
6739 : : /* Supportable by target? */
6740 : :
6741 : 519663 : vec_mode = TYPE_MODE (vectype);
6742 : 519663 : if (code == MULT_HIGHPART_EXPR)
6743 : 1571 : target_support_p = can_mult_highpart_p (vec_mode, TYPE_UNSIGNED (vectype));
6744 : : else
6745 : : {
6746 : 518092 : optab = optab_for_tree_code (code, vectype, optab_default);
6747 : 518092 : if (!optab)
6748 : : {
6749 : 60632 : if (dump_enabled_p ())
6750 : 6230 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6751 : : "no optab.\n");
6752 : 60632 : return false;
6753 : : }
6754 : 457460 : target_support_p = (optab_handler (optab, vec_mode) != CODE_FOR_nothing
6755 : 457460 : || optab_libfunc (optab, vec_mode));
6756 : : }
6757 : :
6758 : 459031 : bool using_emulated_vectors_p = vect_emulated_vector_p (vectype);
6759 : 459031 : if (!target_support_p || using_emulated_vectors_p)
6760 : : {
6761 : 23749 : if (dump_enabled_p ())
6762 : 795 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6763 : : "op not supported by target.\n");
6764 : : /* When vec_mode is not a vector mode and we verified ops we
6765 : : do not have to lower like AND are natively supported let
6766 : : those through even when the mode isn't word_mode. For
6767 : : ops we have to lower the lowering code assumes we are
6768 : : dealing with word_mode. */
6769 : 47498 : if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype))
6770 : 23711 : || (((code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR)
6771 : 16251 : || !target_support_p)
6772 : 52139 : && maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD))
6773 : : /* Check only during analysis. */
6774 : 34822 : || (!vec_stmt && !vect_can_vectorize_without_simd_p (code)))
6775 : : {
6776 : 20534 : if (dump_enabled_p ())
6777 : 769 : dump_printf (MSG_NOTE, "using word mode not possible.\n");
6778 : 20534 : return false;
6779 : : }
6780 : 3215 : if (dump_enabled_p ())
6781 : 26 : dump_printf_loc (MSG_NOTE, vect_location,
6782 : : "proceeding using word mode.\n");
6783 : : using_emulated_vectors_p = true;
6784 : : }
6785 : :
6786 : 438497 : int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info);
6787 : 438497 : vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL);
6788 : 272615 : vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL);
6789 : 438497 : internal_fn cond_fn = get_conditional_internal_fn (code);
6790 : 438497 : internal_fn cond_len_fn = get_conditional_len_internal_fn (code);
6791 : :
6792 : : /* If operating on inactive elements could generate spurious traps,
6793 : : we need to restrict the operation to active lanes. Note that this
6794 : : specifically doesn't apply to unhoisted invariants, since they
6795 : : operate on the same value for every lane.
6796 : :
6797 : : Similarly, if this operation is part of a reduction, a fully-masked
6798 : : loop should only change the active lanes of the reduction chain,
6799 : : keeping the inactive lanes as-is. */
6800 : 413391 : bool mask_out_inactive = ((!is_invariant && gimple_could_trap_p (stmt))
6801 : 803823 : || reduc_idx >= 0);
6802 : :
6803 : 438497 : if (!vec_stmt) /* transformation not required. */
6804 : : {
6805 : 343285 : if (loop_vinfo
6806 : 187798 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
6807 : 11 : && mask_out_inactive)
6808 : : {
6809 : 4 : if (cond_len_fn != IFN_LAST
6810 : 4 : && direct_internal_fn_supported_p (cond_len_fn, vectype,
6811 : : OPTIMIZE_FOR_SPEED))
6812 : 0 : vect_record_loop_len (loop_vinfo, lens, ncopies * vec_num, vectype,
6813 : : 1);
6814 : 4 : else if (cond_fn != IFN_LAST
6815 : 4 : && direct_internal_fn_supported_p (cond_fn, vectype,
6816 : : OPTIMIZE_FOR_SPEED))
6817 : 4 : vect_record_loop_mask (loop_vinfo, masks, ncopies * vec_num,
6818 : : vectype, NULL);
6819 : : else
6820 : : {
6821 : 0 : if (dump_enabled_p ())
6822 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6823 : : "can't use a fully-masked loop because no"
6824 : : " conditional operation is available.\n");
6825 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
6826 : : }
6827 : : }
6828 : :
6829 : : /* Put types on constant and invariant SLP children. */
6830 : 343285 : if (slp_node
6831 : 343285 : && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
6832 : 163238 : || !vect_maybe_update_slp_op_vectype (slp_op1, vectype)
6833 : 163209 : || !vect_maybe_update_slp_op_vectype (slp_op2, vectype)))
6834 : : {
6835 : 171 : if (dump_enabled_p ())
6836 : 3 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6837 : : "incompatible vector types for invariants\n");
6838 : 171 : return false;
6839 : : }
6840 : :
6841 : 343114 : STMT_VINFO_TYPE (stmt_info) = op_vec_info_type;
6842 : 343114 : DUMP_VECT_SCOPE ("vectorizable_operation");
6843 : 343114 : vect_model_simple_cost (vinfo, stmt_info,
6844 : : ncopies, dt, ndts, slp_node, cost_vec);
6845 : 343114 : if (using_emulated_vectors_p)
6846 : : {
6847 : : /* The above vect_model_simple_cost call handles constants
6848 : : in the prologue and (mis-)costs one of the stmts as
6849 : : vector stmt. See below for the actual lowering that will
6850 : : be applied. */
6851 : 6426 : unsigned n
6852 : 3213 : = slp_node ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies;
6853 : 3213 : switch (code)
6854 : : {
6855 : 1454 : case PLUS_EXPR:
6856 : 1454 : n *= 5;
6857 : 1454 : break;
6858 : 1209 : case MINUS_EXPR:
6859 : 1209 : n *= 6;
6860 : 1209 : break;
6861 : 6 : case NEGATE_EXPR:
6862 : 6 : n *= 4;
6863 : 6 : break;
6864 : : default:
6865 : : /* Bit operations do not have extra cost and are accounted
6866 : : as vector stmt by vect_model_simple_cost. */
6867 : : n = 0;
6868 : : break;
6869 : : }
6870 : 2669 : if (n != 0)
6871 : : {
6872 : : /* We also need to materialize two large constants. */
6873 : 2669 : record_stmt_cost (cost_vec, 2, scalar_stmt, stmt_info,
6874 : : 0, vect_prologue);
6875 : 2669 : record_stmt_cost (cost_vec, n, scalar_stmt, stmt_info,
6876 : : 0, vect_body);
6877 : : }
6878 : : }
6879 : 343114 : return true;
6880 : 343114 : }
6881 : :
6882 : : /* Transform. */
6883 : :
6884 : 95212 : if (dump_enabled_p ())
6885 : 14427 : dump_printf_loc (MSG_NOTE, vect_location,
6886 : : "transform binary/unary operation.\n");
6887 : :
6888 : 95212 : bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
6889 : 84817 : bool len_loop_p = loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
6890 : :
6891 : : /* POINTER_DIFF_EXPR has pointer arguments which are vectorized as
6892 : : vectors with unsigned elements, but the result is signed. So, we
6893 : : need to compute the MINUS_EXPR into vectype temporary and
6894 : : VIEW_CONVERT_EXPR it into the final vectype_out result. */
6895 : 95212 : tree vec_cvt_dest = NULL_TREE;
6896 : 95212 : if (orig_code == POINTER_DIFF_EXPR)
6897 : : {
6898 : 127 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6899 : 127 : vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out);
6900 : : }
6901 : : /* Handle def. */
6902 : : else
6903 : 95085 : vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
6904 : :
6905 : : /* In case the vectorization factor (VF) is bigger than the number
6906 : : of elements that we can fit in a vectype (nunits), we have to generate
6907 : : more than one vector stmt - i.e - we need to "unroll" the
6908 : : vector stmt by a factor VF/nunits. In doing so, we record a pointer
6909 : : from one copy of the vector stmt to the next, in the field
6910 : : STMT_VINFO_RELATED_STMT. This is necessary in order to allow following
6911 : : stages to find the correct vector defs to be used when vectorizing
6912 : : stmts that use the defs of the current stmt. The example below
6913 : : illustrates the vectorization process when VF=16 and nunits=4 (i.e.,
6914 : : we need to create 4 vectorized stmts):
6915 : :
6916 : : before vectorization:
6917 : : RELATED_STMT VEC_STMT
6918 : : S1: x = memref - -
6919 : : S2: z = x + 1 - -
6920 : :
6921 : : step 1: vectorize stmt S1 (done in vectorizable_load. See more details
6922 : : there):
6923 : : RELATED_STMT VEC_STMT
6924 : : VS1_0: vx0 = memref0 VS1_1 -
6925 : : VS1_1: vx1 = memref1 VS1_2 -
6926 : : VS1_2: vx2 = memref2 VS1_3 -
6927 : : VS1_3: vx3 = memref3 - -
6928 : : S1: x = load - VS1_0
6929 : : S2: z = x + 1 - -
6930 : :
6931 : : step2: vectorize stmt S2 (done here):
6932 : : To vectorize stmt S2 we first need to find the relevant vector
6933 : : def for the first operand 'x'. This is, as usual, obtained from
6934 : : the vector stmt recorded in the STMT_VINFO_VEC_STMT of the stmt
6935 : : that defines 'x' (S1). This way we find the stmt VS1_0, and the
6936 : : relevant vector def 'vx0'. Having found 'vx0' we can generate
6937 : : the vector stmt VS2_0, and as usual, record it in the
6938 : : STMT_VINFO_VEC_STMT of stmt S2.
6939 : : When creating the second copy (VS2_1), we obtain the relevant vector
6940 : : def from the vector stmt recorded in the STMT_VINFO_RELATED_STMT of
6941 : : stmt VS1_0. This way we find the stmt VS1_1 and the relevant
6942 : : vector def 'vx1'. Using 'vx1' we create stmt VS2_1 and record a
6943 : : pointer to it in the STMT_VINFO_RELATED_STMT of the vector stmt VS2_0.
6944 : : Similarly when creating stmts VS2_2 and VS2_3. This is the resulting
6945 : : chain of stmts and pointers:
6946 : : RELATED_STMT VEC_STMT
6947 : : VS1_0: vx0 = memref0 VS1_1 -
6948 : : VS1_1: vx1 = memref1 VS1_2 -
6949 : : VS1_2: vx2 = memref2 VS1_3 -
6950 : : VS1_3: vx3 = memref3 - -
6951 : : S1: x = load - VS1_0
6952 : : VS2_0: vz0 = vx0 + v1 VS2_1 -
6953 : : VS2_1: vz1 = vx1 + v1 VS2_2 -
6954 : : VS2_2: vz2 = vx2 + v1 VS2_3 -
6955 : : VS2_3: vz3 = vx3 + v1 - -
6956 : : S2: z = x + 1 - VS2_0 */
6957 : :
6958 : 95212 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
6959 : : op0, &vec_oprnds0, op1, &vec_oprnds1, op2, &vec_oprnds2);
6960 : : /* Arguments are ready. Create the new vector stmt. */
6961 : 206374 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6962 : : {
6963 : 111162 : gimple *new_stmt = NULL;
6964 : 222324 : vop1 = ((op_type == binary_op || op_type == ternary_op)
6965 : 111162 : ? vec_oprnds1[i] : NULL_TREE);
6966 : 111162 : vop2 = ((op_type == ternary_op) ? vec_oprnds2[i] : NULL_TREE);
6967 : 111162 : if (using_emulated_vectors_p
6968 : 2 : && (code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR))
6969 : : {
6970 : : /* Lower the operation. This follows vector lowering. */
6971 : 1 : unsigned int width = vector_element_bits (vectype);
6972 : 1 : tree inner_type = TREE_TYPE (vectype);
6973 : 1 : tree word_type
6974 : 1 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (word_mode), 1);
6975 : 1 : HOST_WIDE_INT max = GET_MODE_MASK (TYPE_MODE (inner_type));
6976 : 1 : tree low_bits = build_replicated_int_cst (word_type, width, max >> 1);
6977 : 1 : tree high_bits
6978 : 1 : = build_replicated_int_cst (word_type, width, max & ~(max >> 1));
6979 : 1 : tree wvop0 = make_ssa_name (word_type);
6980 : 1 : new_stmt = gimple_build_assign (wvop0, VIEW_CONVERT_EXPR,
6981 : : build1 (VIEW_CONVERT_EXPR,
6982 : : word_type, vop0));
6983 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6984 : 1 : tree result_low, signs;
6985 : 1 : if (code == PLUS_EXPR || code == MINUS_EXPR)
6986 : : {
6987 : 1 : tree wvop1 = make_ssa_name (word_type);
6988 : 1 : new_stmt = gimple_build_assign (wvop1, VIEW_CONVERT_EXPR,
6989 : : build1 (VIEW_CONVERT_EXPR,
6990 : : word_type, vop1));
6991 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6992 : 1 : signs = make_ssa_name (word_type);
6993 : 1 : new_stmt = gimple_build_assign (signs,
6994 : : BIT_XOR_EXPR, wvop0, wvop1);
6995 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6996 : 1 : tree b_low = make_ssa_name (word_type);
6997 : 1 : new_stmt = gimple_build_assign (b_low,
6998 : : BIT_AND_EXPR, wvop1, low_bits);
6999 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7000 : 1 : tree a_low = make_ssa_name (word_type);
7001 : 1 : if (code == PLUS_EXPR)
7002 : 1 : new_stmt = gimple_build_assign (a_low,
7003 : : BIT_AND_EXPR, wvop0, low_bits);
7004 : : else
7005 : 0 : new_stmt = gimple_build_assign (a_low,
7006 : : BIT_IOR_EXPR, wvop0, high_bits);
7007 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7008 : 1 : if (code == MINUS_EXPR)
7009 : : {
7010 : 0 : new_stmt = gimple_build_assign (NULL_TREE,
7011 : : BIT_NOT_EXPR, signs);
7012 : 0 : signs = make_ssa_name (word_type);
7013 : 0 : gimple_assign_set_lhs (new_stmt, signs);
7014 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7015 : : }
7016 : 1 : new_stmt = gimple_build_assign (NULL_TREE,
7017 : : BIT_AND_EXPR, signs, high_bits);
7018 : 1 : signs = make_ssa_name (word_type);
7019 : 1 : gimple_assign_set_lhs (new_stmt, signs);
7020 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7021 : 1 : result_low = make_ssa_name (word_type);
7022 : 1 : new_stmt = gimple_build_assign (result_low, code, a_low, b_low);
7023 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7024 : : }
7025 : : else
7026 : : {
7027 : 0 : tree a_low = make_ssa_name (word_type);
7028 : 0 : new_stmt = gimple_build_assign (a_low,
7029 : : BIT_AND_EXPR, wvop0, low_bits);
7030 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7031 : 0 : signs = make_ssa_name (word_type);
7032 : 0 : new_stmt = gimple_build_assign (signs, BIT_NOT_EXPR, wvop0);
7033 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7034 : 0 : new_stmt = gimple_build_assign (NULL_TREE,
7035 : : BIT_AND_EXPR, signs, high_bits);
7036 : 0 : signs = make_ssa_name (word_type);
7037 : 0 : gimple_assign_set_lhs (new_stmt, signs);
7038 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7039 : 0 : result_low = make_ssa_name (word_type);
7040 : 0 : new_stmt = gimple_build_assign (result_low,
7041 : : MINUS_EXPR, high_bits, a_low);
7042 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7043 : : }
7044 : 1 : new_stmt = gimple_build_assign (NULL_TREE, BIT_XOR_EXPR, result_low,
7045 : : signs);
7046 : 1 : result_low = make_ssa_name (word_type);
7047 : 1 : gimple_assign_set_lhs (new_stmt, result_low);
7048 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7049 : 1 : new_stmt = gimple_build_assign (NULL_TREE, VIEW_CONVERT_EXPR,
7050 : : build1 (VIEW_CONVERT_EXPR,
7051 : : vectype, result_low));
7052 : 1 : new_temp = make_ssa_name (vectype);
7053 : 1 : gimple_assign_set_lhs (new_stmt, new_temp);
7054 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7055 : 1 : }
7056 : 111161 : else if ((masked_loop_p || len_loop_p) && mask_out_inactive)
7057 : : {
7058 : 7 : tree mask;
7059 : 7 : if (masked_loop_p)
7060 : 7 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
7061 : 7 : vec_num * ncopies, vectype, i);
7062 : : else
7063 : : /* Dummy mask. */
7064 : 0 : mask = build_minus_one_cst (truth_type_for (vectype));
7065 : 7 : auto_vec<tree> vops (6);
7066 : 7 : vops.quick_push (mask);
7067 : 7 : vops.quick_push (vop0);
7068 : 7 : if (vop1)
7069 : 7 : vops.quick_push (vop1);
7070 : 7 : if (vop2)
7071 : 0 : vops.quick_push (vop2);
7072 : 7 : if (reduc_idx >= 0)
7073 : : {
7074 : : /* Perform the operation on active elements only and take
7075 : : inactive elements from the reduction chain input. */
7076 : 0 : gcc_assert (!vop2);
7077 : 0 : vops.quick_push (reduc_idx == 1 ? vop1 : vop0);
7078 : : }
7079 : : else
7080 : : {
7081 : 7 : auto else_value = targetm.preferred_else_value
7082 : 7 : (cond_fn, vectype, vops.length () - 1, &vops[1]);
7083 : 7 : vops.quick_push (else_value);
7084 : : }
7085 : 7 : if (len_loop_p)
7086 : : {
7087 : 0 : tree len = vect_get_loop_len (loop_vinfo, gsi, lens,
7088 : 0 : vec_num * ncopies, vectype, i, 1);
7089 : 0 : signed char biasval
7090 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
7091 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
7092 : 0 : vops.quick_push (len);
7093 : 0 : vops.quick_push (bias);
7094 : : }
7095 : 7 : gcall *call
7096 : 7 : = gimple_build_call_internal_vec (masked_loop_p ? cond_fn
7097 : : : cond_len_fn,
7098 : : vops);
7099 : 7 : new_temp = make_ssa_name (vec_dest, call);
7100 : 7 : gimple_call_set_lhs (call, new_temp);
7101 : 7 : gimple_call_set_nothrow (call, true);
7102 : 7 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
7103 : 7 : new_stmt = call;
7104 : 7 : }
7105 : : else
7106 : : {
7107 : 111154 : tree mask = NULL_TREE;
7108 : : /* When combining two masks check if either of them is elsewhere
7109 : : combined with a loop mask, if that's the case we can mark that the
7110 : : new combined mask doesn't need to be combined with a loop mask. */
7111 : 111154 : if (masked_loop_p
7112 : 111154 : && code == BIT_AND_EXPR
7113 : 111154 : && VECTOR_BOOLEAN_TYPE_P (vectype))
7114 : : {
7115 : 0 : if (loop_vinfo->scalar_cond_masked_set.contains ({ op0,
7116 : : ncopies}))
7117 : : {
7118 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
7119 : 0 : vec_num * ncopies, vectype, i);
7120 : :
7121 : 0 : vop0 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
7122 : : vop0, gsi);
7123 : : }
7124 : :
7125 : 0 : if (loop_vinfo->scalar_cond_masked_set.contains ({ op1,
7126 : : ncopies }))
7127 : : {
7128 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
7129 : 0 : vec_num * ncopies, vectype, i);
7130 : :
7131 : 0 : vop1 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
7132 : : vop1, gsi);
7133 : : }
7134 : : }
7135 : :
7136 : 111154 : new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1, vop2);
7137 : 111154 : new_temp = make_ssa_name (vec_dest, new_stmt);
7138 : 111154 : gimple_assign_set_lhs (new_stmt, new_temp);
7139 : 111154 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7140 : 111154 : if (using_emulated_vectors_p)
7141 : 1 : suppress_warning (new_stmt, OPT_Wvector_operation_performance);
7142 : :
7143 : : /* Enter the combined value into the vector cond hash so we don't
7144 : : AND it with a loop mask again. */
7145 : 111154 : if (mask)
7146 : 0 : loop_vinfo->vec_cond_masked_set.add ({ new_temp, mask });
7147 : : }
7148 : :
7149 : 111162 : if (vec_cvt_dest)
7150 : : {
7151 : 147 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype_out, new_temp);
7152 : 147 : new_stmt = gimple_build_assign (vec_cvt_dest, VIEW_CONVERT_EXPR,
7153 : : new_temp);
7154 : 147 : new_temp = make_ssa_name (vec_cvt_dest, new_stmt);
7155 : 147 : gimple_assign_set_lhs (new_stmt, new_temp);
7156 : 147 : vect_finish_stmt_generation (vinfo, stmt_info,
7157 : : new_stmt, gsi);
7158 : : }
7159 : :
7160 : 111162 : if (slp_node)
7161 : 21723 : slp_node->push_vec_def (new_stmt);
7162 : : else
7163 : 89439 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
7164 : : }
7165 : :
7166 : 95212 : if (!slp_node)
7167 : 80310 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
7168 : :
7169 : 95212 : vec_oprnds0.release ();
7170 : 95212 : vec_oprnds1.release ();
7171 : 95212 : vec_oprnds2.release ();
7172 : :
7173 : 95212 : return true;
7174 : : }
7175 : :
7176 : : /* A helper function to ensure data reference DR_INFO's base alignment. */
7177 : :
7178 : : static void
7179 : 1746640 : ensure_base_align (dr_vec_info *dr_info)
7180 : : {
7181 : : /* Alignment is only analyzed for the first element of a DR group,
7182 : : use that to look at base alignment we need to enforce. */
7183 : 1746640 : if (STMT_VINFO_GROUPED_ACCESS (dr_info->stmt))
7184 : 1430491 : dr_info = STMT_VINFO_DR_INFO (DR_GROUP_FIRST_ELEMENT (dr_info->stmt));
7185 : :
7186 : 1746640 : gcc_assert (dr_info->misalignment != DR_MISALIGNMENT_UNINITIALIZED);
7187 : :
7188 : 1746640 : if (dr_info->base_misaligned)
7189 : : {
7190 : 164504 : tree base_decl = dr_info->base_decl;
7191 : :
7192 : : // We should only be able to increase the alignment of a base object if
7193 : : // we know what its new alignment should be at compile time.
7194 : 164504 : unsigned HOST_WIDE_INT align_base_to =
7195 : 164504 : DR_TARGET_ALIGNMENT (dr_info).to_constant () * BITS_PER_UNIT;
7196 : :
7197 : 164504 : if (decl_in_symtab_p (base_decl))
7198 : 4120 : symtab_node::get (base_decl)->increase_alignment (align_base_to);
7199 : 160384 : else if (DECL_ALIGN (base_decl) < align_base_to)
7200 : : {
7201 : 133182 : SET_DECL_ALIGN (base_decl, align_base_to);
7202 : 133182 : DECL_USER_ALIGN (base_decl) = 1;
7203 : : }
7204 : 164504 : dr_info->base_misaligned = false;
7205 : : }
7206 : 1746640 : }
7207 : :
7208 : :
7209 : : /* Function get_group_alias_ptr_type.
7210 : :
7211 : : Return the alias type for the group starting at FIRST_STMT_INFO. */
7212 : :
7213 : : static tree
7214 : 1423170 : get_group_alias_ptr_type (stmt_vec_info first_stmt_info)
7215 : : {
7216 : 1423170 : struct data_reference *first_dr, *next_dr;
7217 : :
7218 : 1423170 : first_dr = STMT_VINFO_DATA_REF (first_stmt_info);
7219 : 1423170 : stmt_vec_info next_stmt_info = DR_GROUP_NEXT_ELEMENT (first_stmt_info);
7220 : 3574177 : while (next_stmt_info)
7221 : : {
7222 : 2279321 : next_dr = STMT_VINFO_DATA_REF (next_stmt_info);
7223 : 4558642 : if (get_alias_set (DR_REF (first_dr))
7224 : 2279321 : != get_alias_set (DR_REF (next_dr)))
7225 : : {
7226 : 128314 : if (dump_enabled_p ())
7227 : 12 : dump_printf_loc (MSG_NOTE, vect_location,
7228 : : "conflicting alias set types.\n");
7229 : 128314 : return ptr_type_node;
7230 : : }
7231 : 2151007 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
7232 : : }
7233 : 1294856 : return reference_alias_ptr_type (DR_REF (first_dr));
7234 : : }
7235 : :
7236 : :
7237 : : /* Function scan_operand_equal_p.
7238 : :
7239 : : Helper function for check_scan_store. Compare two references
7240 : : with .GOMP_SIMD_LANE bases. */
7241 : :
7242 : : static bool
7243 : 1376 : scan_operand_equal_p (tree ref1, tree ref2)
7244 : : {
7245 : 1376 : tree ref[2] = { ref1, ref2 };
7246 : 1376 : poly_int64 bitsize[2], bitpos[2];
7247 : : tree offset[2], base[2];
7248 : 4128 : for (int i = 0; i < 2; ++i)
7249 : : {
7250 : 2752 : machine_mode mode;
7251 : 2752 : int unsignedp, reversep, volatilep = 0;
7252 : 2752 : base[i] = get_inner_reference (ref[i], &bitsize[i], &bitpos[i],
7253 : : &offset[i], &mode, &unsignedp,
7254 : : &reversep, &volatilep);
7255 : 2752 : if (reversep || volatilep || maybe_ne (bitpos[i], 0))
7256 : 0 : return false;
7257 : 2752 : if (TREE_CODE (base[i]) == MEM_REF
7258 : 56 : && offset[i] == NULL_TREE
7259 : 2808 : && TREE_CODE (TREE_OPERAND (base[i], 0)) == SSA_NAME)
7260 : : {
7261 : 56 : gimple *def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (base[i], 0));
7262 : 56 : if (is_gimple_assign (def_stmt)
7263 : 56 : && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR
7264 : 56 : && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == ADDR_EXPR
7265 : 112 : && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME)
7266 : : {
7267 : 56 : if (maybe_ne (mem_ref_offset (base[i]), 0))
7268 : : return false;
7269 : 56 : base[i] = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0);
7270 : 56 : offset[i] = gimple_assign_rhs2 (def_stmt);
7271 : : }
7272 : : }
7273 : : }
7274 : :
7275 : 1376 : if (!operand_equal_p (base[0], base[1], 0))
7276 : : return false;
7277 : 1008 : if (maybe_ne (bitsize[0], bitsize[1]))
7278 : : return false;
7279 : 1008 : if (offset[0] != offset[1])
7280 : : {
7281 : 984 : if (!offset[0] || !offset[1])
7282 : : return false;
7283 : 984 : if (!operand_equal_p (offset[0], offset[1], 0))
7284 : : {
7285 : : tree step[2];
7286 : 0 : for (int i = 0; i < 2; ++i)
7287 : : {
7288 : 0 : step[i] = integer_one_node;
7289 : 0 : if (TREE_CODE (offset[i]) == SSA_NAME)
7290 : : {
7291 : 0 : gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]);
7292 : 0 : if (is_gimple_assign (def_stmt)
7293 : 0 : && gimple_assign_rhs_code (def_stmt) == MULT_EXPR
7294 : 0 : && (TREE_CODE (gimple_assign_rhs2 (def_stmt))
7295 : : == INTEGER_CST))
7296 : : {
7297 : 0 : step[i] = gimple_assign_rhs2 (def_stmt);
7298 : 0 : offset[i] = gimple_assign_rhs1 (def_stmt);
7299 : : }
7300 : : }
7301 : 0 : else if (TREE_CODE (offset[i]) == MULT_EXPR)
7302 : : {
7303 : 0 : step[i] = TREE_OPERAND (offset[i], 1);
7304 : 0 : offset[i] = TREE_OPERAND (offset[i], 0);
7305 : : }
7306 : 0 : tree rhs1 = NULL_TREE;
7307 : 0 : if (TREE_CODE (offset[i]) == SSA_NAME)
7308 : : {
7309 : 0 : gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]);
7310 : 0 : if (gimple_assign_cast_p (def_stmt))
7311 : 0 : rhs1 = gimple_assign_rhs1 (def_stmt);
7312 : : }
7313 : 0 : else if (CONVERT_EXPR_P (offset[i]))
7314 : 0 : rhs1 = TREE_OPERAND (offset[i], 0);
7315 : 0 : if (rhs1
7316 : 0 : && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
7317 : 0 : && INTEGRAL_TYPE_P (TREE_TYPE (offset[i]))
7318 : 0 : && (TYPE_PRECISION (TREE_TYPE (offset[i]))
7319 : 0 : >= TYPE_PRECISION (TREE_TYPE (rhs1))))
7320 : 0 : offset[i] = rhs1;
7321 : : }
7322 : 0 : if (!operand_equal_p (offset[0], offset[1], 0)
7323 : 0 : || !operand_equal_p (step[0], step[1], 0))
7324 : 0 : return false;
7325 : : }
7326 : : }
7327 : : return true;
7328 : : }
7329 : :
7330 : :
7331 : : enum scan_store_kind {
7332 : : /* Normal permutation. */
7333 : : scan_store_kind_perm,
7334 : :
7335 : : /* Whole vector left shift permutation with zero init. */
7336 : : scan_store_kind_lshift_zero,
7337 : :
7338 : : /* Whole vector left shift permutation and VEC_COND_EXPR. */
7339 : : scan_store_kind_lshift_cond
7340 : : };
7341 : :
7342 : : /* Function check_scan_store.
7343 : :
7344 : : Verify if we can perform the needed permutations or whole vector shifts.
7345 : : Return -1 on failure, otherwise exact log2 of vectype's nunits.
7346 : : USE_WHOLE_VECTOR is a vector of enum scan_store_kind which operation
7347 : : to do at each step. */
7348 : :
7349 : : static int
7350 : 1096 : scan_store_can_perm_p (tree vectype, tree init,
7351 : : vec<enum scan_store_kind> *use_whole_vector = NULL)
7352 : : {
7353 : 1096 : enum machine_mode vec_mode = TYPE_MODE (vectype);
7354 : 1096 : unsigned HOST_WIDE_INT nunits;
7355 : 1096 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits))
7356 : : return -1;
7357 : 1096 : int units_log2 = exact_log2 (nunits);
7358 : 1096 : if (units_log2 <= 0)
7359 : : return -1;
7360 : :
7361 : : int i;
7362 : : enum scan_store_kind whole_vector_shift_kind = scan_store_kind_perm;
7363 : 5072 : for (i = 0; i <= units_log2; ++i)
7364 : : {
7365 : 3976 : unsigned HOST_WIDE_INT j, k;
7366 : 3976 : enum scan_store_kind kind = scan_store_kind_perm;
7367 : 3976 : vec_perm_builder sel (nunits, nunits, 1);
7368 : 3976 : sel.quick_grow (nunits);
7369 : 3976 : if (i == units_log2)
7370 : : {
7371 : 10088 : for (j = 0; j < nunits; ++j)
7372 : 8992 : sel[j] = nunits - 1;
7373 : : }
7374 : : else
7375 : : {
7376 : 10776 : for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j)
7377 : 7896 : sel[j] = j;
7378 : 26920 : for (k = 0; j < nunits; ++j, ++k)
7379 : 24040 : sel[j] = nunits + k;
7380 : : }
7381 : 6856 : vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits);
7382 : 3976 : if (!can_vec_perm_const_p (vec_mode, vec_mode, indices))
7383 : : {
7384 : 0 : if (i == units_log2)
7385 : : return -1;
7386 : :
7387 : 0 : if (whole_vector_shift_kind == scan_store_kind_perm)
7388 : : {
7389 : 0 : if (optab_handler (vec_shl_optab, vec_mode) == CODE_FOR_nothing)
7390 : : return -1;
7391 : 0 : whole_vector_shift_kind = scan_store_kind_lshift_zero;
7392 : : /* Whole vector shifts shift in zeros, so if init is all zero
7393 : : constant, there is no need to do anything further. */
7394 : 0 : if ((TREE_CODE (init) != INTEGER_CST
7395 : 0 : && TREE_CODE (init) != REAL_CST)
7396 : 0 : || !initializer_zerop (init))
7397 : : {
7398 : 0 : tree masktype = truth_type_for (vectype);
7399 : 0 : if (!expand_vec_cond_expr_p (vectype, masktype, VECTOR_CST))
7400 : : return -1;
7401 : : whole_vector_shift_kind = scan_store_kind_lshift_cond;
7402 : : }
7403 : : }
7404 : 0 : kind = whole_vector_shift_kind;
7405 : : }
7406 : 3976 : if (use_whole_vector)
7407 : : {
7408 : 1988 : if (kind != scan_store_kind_perm && use_whole_vector->is_empty ())
7409 : 0 : use_whole_vector->safe_grow_cleared (i, true);
7410 : 5964 : if (kind != scan_store_kind_perm || !use_whole_vector->is_empty ())
7411 : 0 : use_whole_vector->safe_push (kind);
7412 : : }
7413 : 3976 : }
7414 : :
7415 : : return units_log2;
7416 : : }
7417 : :
7418 : :
7419 : : /* Function check_scan_store.
7420 : :
7421 : : Check magic stores for #pragma omp scan {in,ex}clusive reductions. */
7422 : :
7423 : : static bool
7424 : 992 : check_scan_store (vec_info *vinfo, stmt_vec_info stmt_info, tree vectype,
7425 : : enum vect_def_type rhs_dt, bool slp, tree mask,
7426 : : vect_memory_access_type memory_access_type)
7427 : : {
7428 : 992 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
7429 : 992 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
7430 : 992 : tree ref_type;
7431 : :
7432 : 992 : gcc_assert (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1);
7433 : 992 : if (slp
7434 : 992 : || mask
7435 : 992 : || memory_access_type != VMAT_CONTIGUOUS
7436 : 992 : || TREE_CODE (DR_BASE_ADDRESS (dr_info->dr)) != ADDR_EXPR
7437 : 992 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0))
7438 : 992 : || loop_vinfo == NULL
7439 : 992 : || LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
7440 : 992 : || STMT_VINFO_GROUPED_ACCESS (stmt_info)
7441 : 992 : || !integer_zerop (get_dr_vinfo_offset (vinfo, dr_info))
7442 : 992 : || !integer_zerop (DR_INIT (dr_info->dr))
7443 : 992 : || !(ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr)))
7444 : 1984 : || !alias_sets_conflict_p (get_alias_set (vectype),
7445 : 992 : get_alias_set (TREE_TYPE (ref_type))))
7446 : : {
7447 : 0 : if (dump_enabled_p ())
7448 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7449 : : "unsupported OpenMP scan store.\n");
7450 : 0 : return false;
7451 : : }
7452 : :
7453 : : /* We need to pattern match code built by OpenMP lowering and simplified
7454 : : by following optimizations into something we can handle.
7455 : : #pragma omp simd reduction(inscan,+:r)
7456 : : for (...)
7457 : : {
7458 : : r += something ();
7459 : : #pragma omp scan inclusive (r)
7460 : : use (r);
7461 : : }
7462 : : shall have body with:
7463 : : // Initialization for input phase, store the reduction initializer:
7464 : : _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0);
7465 : : _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1);
7466 : : D.2042[_21] = 0;
7467 : : // Actual input phase:
7468 : : ...
7469 : : r.0_5 = D.2042[_20];
7470 : : _6 = _4 + r.0_5;
7471 : : D.2042[_20] = _6;
7472 : : // Initialization for scan phase:
7473 : : _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 2);
7474 : : _26 = D.2043[_25];
7475 : : _27 = D.2042[_25];
7476 : : _28 = _26 + _27;
7477 : : D.2043[_25] = _28;
7478 : : D.2042[_25] = _28;
7479 : : // Actual scan phase:
7480 : : ...
7481 : : r.1_8 = D.2042[_20];
7482 : : ...
7483 : : The "omp simd array" variable D.2042 holds the privatized copy used
7484 : : inside of the loop and D.2043 is another one that holds copies of
7485 : : the current original list item. The separate GOMP_SIMD_LANE ifn
7486 : : kinds are there in order to allow optimizing the initializer store
7487 : : and combiner sequence, e.g. if it is originally some C++ish user
7488 : : defined reduction, but allow the vectorizer to pattern recognize it
7489 : : and turn into the appropriate vectorized scan.
7490 : :
7491 : : For exclusive scan, this is slightly different:
7492 : : #pragma omp simd reduction(inscan,+:r)
7493 : : for (...)
7494 : : {
7495 : : use (r);
7496 : : #pragma omp scan exclusive (r)
7497 : : r += something ();
7498 : : }
7499 : : shall have body with:
7500 : : // Initialization for input phase, store the reduction initializer:
7501 : : _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0);
7502 : : _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1);
7503 : : D.2042[_21] = 0;
7504 : : // Actual input phase:
7505 : : ...
7506 : : r.0_5 = D.2042[_20];
7507 : : _6 = _4 + r.0_5;
7508 : : D.2042[_20] = _6;
7509 : : // Initialization for scan phase:
7510 : : _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 3);
7511 : : _26 = D.2043[_25];
7512 : : D.2044[_25] = _26;
7513 : : _27 = D.2042[_25];
7514 : : _28 = _26 + _27;
7515 : : D.2043[_25] = _28;
7516 : : // Actual scan phase:
7517 : : ...
7518 : : r.1_8 = D.2044[_20];
7519 : : ... */
7520 : :
7521 : 992 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 2)
7522 : : {
7523 : : /* Match the D.2042[_21] = 0; store above. Just require that
7524 : : it is a constant or external definition store. */
7525 : 444 : if (rhs_dt != vect_constant_def && rhs_dt != vect_external_def)
7526 : : {
7527 : 0 : fail_init:
7528 : 0 : if (dump_enabled_p ())
7529 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7530 : : "unsupported OpenMP scan initializer store.\n");
7531 : 0 : return false;
7532 : : }
7533 : :
7534 : 444 : if (! loop_vinfo->scan_map)
7535 : 356 : loop_vinfo->scan_map = new hash_map<tree, tree>;
7536 : 444 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7537 : 444 : tree &cached = loop_vinfo->scan_map->get_or_insert (var);
7538 : 444 : if (cached)
7539 : 0 : goto fail_init;
7540 : 444 : cached = gimple_assign_rhs1 (STMT_VINFO_STMT (stmt_info));
7541 : :
7542 : : /* These stores can be vectorized normally. */
7543 : 444 : return true;
7544 : : }
7545 : :
7546 : 548 : if (rhs_dt != vect_internal_def)
7547 : : {
7548 : 0 : fail:
7549 : 0 : if (dump_enabled_p ())
7550 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7551 : : "unsupported OpenMP scan combiner pattern.\n");
7552 : 0 : return false;
7553 : : }
7554 : :
7555 : 548 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
7556 : 548 : tree rhs = gimple_assign_rhs1 (stmt);
7557 : 548 : if (TREE_CODE (rhs) != SSA_NAME)
7558 : 0 : goto fail;
7559 : :
7560 : 548 : gimple *other_store_stmt = NULL;
7561 : 548 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7562 : 548 : bool inscan_var_store
7563 : 548 : = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL;
7564 : :
7565 : 548 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7566 : : {
7567 : 268 : if (!inscan_var_store)
7568 : : {
7569 : 134 : use_operand_p use_p;
7570 : 134 : imm_use_iterator iter;
7571 : 402 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7572 : : {
7573 : 268 : gimple *use_stmt = USE_STMT (use_p);
7574 : 268 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7575 : 134 : continue;
7576 : 134 : if (gimple_bb (use_stmt) != gimple_bb (stmt)
7577 : 134 : || !is_gimple_assign (use_stmt)
7578 : 134 : || gimple_assign_rhs_class (use_stmt) != GIMPLE_BINARY_RHS
7579 : 134 : || other_store_stmt
7580 : 268 : || TREE_CODE (gimple_assign_lhs (use_stmt)) != SSA_NAME)
7581 : 0 : goto fail;
7582 : 134 : other_store_stmt = use_stmt;
7583 : : }
7584 : 134 : if (other_store_stmt == NULL)
7585 : 0 : goto fail;
7586 : 134 : rhs = gimple_assign_lhs (other_store_stmt);
7587 : 134 : if (!single_imm_use (rhs, &use_p, &other_store_stmt))
7588 : 0 : goto fail;
7589 : : }
7590 : : }
7591 : 280 : else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3)
7592 : : {
7593 : 280 : use_operand_p use_p;
7594 : 280 : imm_use_iterator iter;
7595 : 840 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7596 : : {
7597 : 560 : gimple *use_stmt = USE_STMT (use_p);
7598 : 560 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7599 : 280 : continue;
7600 : 280 : if (other_store_stmt)
7601 : 0 : goto fail;
7602 : 280 : other_store_stmt = use_stmt;
7603 : : }
7604 : : }
7605 : : else
7606 : 0 : goto fail;
7607 : :
7608 : 548 : gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
7609 : 548 : if (gimple_bb (def_stmt) != gimple_bb (stmt)
7610 : 548 : || !is_gimple_assign (def_stmt)
7611 : 1096 : || gimple_assign_rhs_class (def_stmt) != GIMPLE_BINARY_RHS)
7612 : 0 : goto fail;
7613 : :
7614 : 548 : enum tree_code code = gimple_assign_rhs_code (def_stmt);
7615 : : /* For pointer addition, we should use the normal plus for the vector
7616 : : operation. */
7617 : 548 : switch (code)
7618 : : {
7619 : 0 : case POINTER_PLUS_EXPR:
7620 : 0 : code = PLUS_EXPR;
7621 : 0 : break;
7622 : 0 : case MULT_HIGHPART_EXPR:
7623 : 0 : goto fail;
7624 : : default:
7625 : : break;
7626 : : }
7627 : 548 : if (TREE_CODE_LENGTH (code) != binary_op || !commutative_tree_code (code))
7628 : 0 : goto fail;
7629 : :
7630 : 548 : tree rhs1 = gimple_assign_rhs1 (def_stmt);
7631 : 548 : tree rhs2 = gimple_assign_rhs2 (def_stmt);
7632 : 548 : if (TREE_CODE (rhs1) != SSA_NAME || TREE_CODE (rhs2) != SSA_NAME)
7633 : 0 : goto fail;
7634 : :
7635 : 548 : gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1);
7636 : 548 : gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2);
7637 : 548 : if (gimple_bb (load1_stmt) != gimple_bb (stmt)
7638 : 548 : || !gimple_assign_load_p (load1_stmt)
7639 : 548 : || gimple_bb (load2_stmt) != gimple_bb (stmt)
7640 : 1096 : || !gimple_assign_load_p (load2_stmt))
7641 : 0 : goto fail;
7642 : :
7643 : 548 : stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt);
7644 : 548 : stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt);
7645 : 548 : if (load1_stmt_info == NULL
7646 : 548 : || load2_stmt_info == NULL
7647 : 548 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (load1_stmt_info)
7648 : 548 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info))
7649 : 548 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (load2_stmt_info)
7650 : 548 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)))
7651 : 0 : goto fail;
7652 : :
7653 : 548 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && inscan_var_store)
7654 : : {
7655 : 134 : dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info);
7656 : 134 : if (TREE_CODE (DR_BASE_ADDRESS (load1_dr_info->dr)) != ADDR_EXPR
7657 : 134 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0)))
7658 : 0 : goto fail;
7659 : 134 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0);
7660 : 134 : tree lrhs;
7661 : 134 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7662 : : lrhs = rhs1;
7663 : : else
7664 : 20 : lrhs = rhs2;
7665 : 134 : use_operand_p use_p;
7666 : 134 : imm_use_iterator iter;
7667 : 402 : FOR_EACH_IMM_USE_FAST (use_p, iter, lrhs)
7668 : : {
7669 : 268 : gimple *use_stmt = USE_STMT (use_p);
7670 : 268 : if (use_stmt == def_stmt || is_gimple_debug (use_stmt))
7671 : 134 : continue;
7672 : 134 : if (other_store_stmt)
7673 : 0 : goto fail;
7674 : 134 : other_store_stmt = use_stmt;
7675 : : }
7676 : : }
7677 : :
7678 : 548 : if (other_store_stmt == NULL)
7679 : 0 : goto fail;
7680 : 548 : if (gimple_bb (other_store_stmt) != gimple_bb (stmt)
7681 : 548 : || !gimple_store_p (other_store_stmt))
7682 : 0 : goto fail;
7683 : :
7684 : 548 : stmt_vec_info other_store_stmt_info
7685 : 548 : = loop_vinfo->lookup_stmt (other_store_stmt);
7686 : 548 : if (other_store_stmt_info == NULL
7687 : 548 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (other_store_stmt_info)
7688 : 548 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)))
7689 : 0 : goto fail;
7690 : :
7691 : 548 : gimple *stmt1 = stmt;
7692 : 548 : gimple *stmt2 = other_store_stmt;
7693 : 548 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7694 : : std::swap (stmt1, stmt2);
7695 : 548 : if (scan_operand_equal_p (gimple_assign_lhs (stmt1),
7696 : : gimple_assign_rhs1 (load2_stmt)))
7697 : : {
7698 : 180 : std::swap (rhs1, rhs2);
7699 : 180 : std::swap (load1_stmt, load2_stmt);
7700 : 180 : std::swap (load1_stmt_info, load2_stmt_info);
7701 : : }
7702 : 548 : if (!scan_operand_equal_p (gimple_assign_lhs (stmt1),
7703 : : gimple_assign_rhs1 (load1_stmt)))
7704 : 0 : goto fail;
7705 : :
7706 : 548 : tree var3 = NULL_TREE;
7707 : 548 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3
7708 : 548 : && !scan_operand_equal_p (gimple_assign_lhs (stmt2),
7709 : : gimple_assign_rhs1 (load2_stmt)))
7710 : 0 : goto fail;
7711 : 548 : else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7712 : : {
7713 : 268 : dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info);
7714 : 268 : if (TREE_CODE (DR_BASE_ADDRESS (load2_dr_info->dr)) != ADDR_EXPR
7715 : 268 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0)))
7716 : 0 : goto fail;
7717 : 268 : var3 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0);
7718 : 268 : if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var3))
7719 : 268 : || lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var3))
7720 : 536 : || lookup_attribute ("omp simd inscan exclusive",
7721 : 268 : DECL_ATTRIBUTES (var3)))
7722 : 0 : goto fail;
7723 : : }
7724 : :
7725 : 548 : dr_vec_info *other_dr_info = STMT_VINFO_DR_INFO (other_store_stmt_info);
7726 : 548 : if (TREE_CODE (DR_BASE_ADDRESS (other_dr_info->dr)) != ADDR_EXPR
7727 : 548 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0)))
7728 : 0 : goto fail;
7729 : :
7730 : 548 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7731 : 548 : tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0);
7732 : 548 : if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var1))
7733 : 548 : || !lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var2))
7734 : 1096 : || (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7735 : 548 : == (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var2))))
7736 : 0 : goto fail;
7737 : :
7738 : 548 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7739 : 274 : std::swap (var1, var2);
7740 : :
7741 : 548 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7742 : : {
7743 : 268 : if (!lookup_attribute ("omp simd inscan exclusive",
7744 : 268 : DECL_ATTRIBUTES (var1)))
7745 : 0 : goto fail;
7746 : 268 : var1 = var3;
7747 : : }
7748 : :
7749 : 548 : if (loop_vinfo->scan_map == NULL)
7750 : 0 : goto fail;
7751 : 548 : tree *init = loop_vinfo->scan_map->get (var1);
7752 : 548 : if (init == NULL)
7753 : 0 : goto fail;
7754 : :
7755 : : /* The IL is as expected, now check if we can actually vectorize it.
7756 : : Inclusive scan:
7757 : : _26 = D.2043[_25];
7758 : : _27 = D.2042[_25];
7759 : : _28 = _26 + _27;
7760 : : D.2043[_25] = _28;
7761 : : D.2042[_25] = _28;
7762 : : should be vectorized as (where _40 is the vectorized rhs
7763 : : from the D.2042[_21] = 0; store):
7764 : : _30 = MEM <vector(8) int> [(int *)&D.2043];
7765 : : _31 = MEM <vector(8) int> [(int *)&D.2042];
7766 : : _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
7767 : : _33 = _31 + _32;
7768 : : // _33 = { _31[0], _31[0]+_31[1], _31[1]+_31[2], ..., _31[6]+_31[7] };
7769 : : _34 = VEC_PERM_EXPR <_40, _33, { 0, 1, 8, 9, 10, 11, 12, 13 }>;
7770 : : _35 = _33 + _34;
7771 : : // _35 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7772 : : // _31[1]+.._31[4], ... _31[4]+.._31[7] };
7773 : : _36 = VEC_PERM_EXPR <_40, _35, { 0, 1, 2, 3, 8, 9, 10, 11 }>;
7774 : : _37 = _35 + _36;
7775 : : // _37 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7776 : : // _31[0]+.._31[4], ... _31[0]+.._31[7] };
7777 : : _38 = _30 + _37;
7778 : : _39 = VEC_PERM_EXPR <_38, _38, { 7, 7, 7, 7, 7, 7, 7, 7 }>;
7779 : : MEM <vector(8) int> [(int *)&D.2043] = _39;
7780 : : MEM <vector(8) int> [(int *)&D.2042] = _38;
7781 : : Exclusive scan:
7782 : : _26 = D.2043[_25];
7783 : : D.2044[_25] = _26;
7784 : : _27 = D.2042[_25];
7785 : : _28 = _26 + _27;
7786 : : D.2043[_25] = _28;
7787 : : should be vectorized as (where _40 is the vectorized rhs
7788 : : from the D.2042[_21] = 0; store):
7789 : : _30 = MEM <vector(8) int> [(int *)&D.2043];
7790 : : _31 = MEM <vector(8) int> [(int *)&D.2042];
7791 : : _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
7792 : : _33 = VEC_PERM_EXPR <_40, _32, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
7793 : : _34 = _32 + _33;
7794 : : // _34 = { 0, _31[0], _31[0]+_31[1], _31[1]+_31[2], _31[2]+_31[3],
7795 : : // _31[3]+_31[4], ... _31[5]+.._31[6] };
7796 : : _35 = VEC_PERM_EXPR <_40, _34, { 0, 1, 8, 9, 10, 11, 12, 13 }>;
7797 : : _36 = _34 + _35;
7798 : : // _36 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7799 : : // _31[1]+.._31[4], ... _31[3]+.._31[6] };
7800 : : _37 = VEC_PERM_EXPR <_40, _36, { 0, 1, 2, 3, 8, 9, 10, 11 }>;
7801 : : _38 = _36 + _37;
7802 : : // _38 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7803 : : // _31[0]+.._31[4], ... _31[0]+.._31[6] };
7804 : : _39 = _30 + _38;
7805 : : _50 = _31 + _39;
7806 : : _51 = VEC_PERM_EXPR <_50, _50, { 7, 7, 7, 7, 7, 7, 7, 7 }>;
7807 : : MEM <vector(8) int> [(int *)&D.2044] = _39;
7808 : : MEM <vector(8) int> [(int *)&D.2042] = _51; */
7809 : 548 : enum machine_mode vec_mode = TYPE_MODE (vectype);
7810 : 548 : optab optab = optab_for_tree_code (code, vectype, optab_default);
7811 : 548 : if (!optab || optab_handler (optab, vec_mode) == CODE_FOR_nothing)
7812 : 0 : goto fail;
7813 : :
7814 : 548 : int units_log2 = scan_store_can_perm_p (vectype, *init);
7815 : 548 : if (units_log2 == -1)
7816 : 0 : goto fail;
7817 : :
7818 : : return true;
7819 : : }
7820 : :
7821 : :
7822 : : /* Function vectorizable_scan_store.
7823 : :
7824 : : Helper of vectorizable_score, arguments like on vectorizable_store.
7825 : : Handle only the transformation, checking is done in check_scan_store. */
7826 : :
7827 : : static bool
7828 : 548 : vectorizable_scan_store (vec_info *vinfo,
7829 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
7830 : : gimple **vec_stmt, int ncopies)
7831 : : {
7832 : 548 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
7833 : 548 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
7834 : 548 : tree ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr));
7835 : 548 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
7836 : :
7837 : 548 : if (dump_enabled_p ())
7838 : 528 : dump_printf_loc (MSG_NOTE, vect_location,
7839 : : "transform scan store. ncopies = %d\n", ncopies);
7840 : :
7841 : 548 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
7842 : 548 : tree rhs = gimple_assign_rhs1 (stmt);
7843 : 548 : gcc_assert (TREE_CODE (rhs) == SSA_NAME);
7844 : :
7845 : 548 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7846 : 548 : bool inscan_var_store
7847 : 548 : = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL;
7848 : :
7849 : 548 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7850 : : {
7851 : 134 : use_operand_p use_p;
7852 : 134 : imm_use_iterator iter;
7853 : 134 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7854 : : {
7855 : 134 : gimple *use_stmt = USE_STMT (use_p);
7856 : 134 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7857 : 0 : continue;
7858 : 134 : rhs = gimple_assign_lhs (use_stmt);
7859 : 134 : break;
7860 : : }
7861 : : }
7862 : :
7863 : 548 : gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
7864 : 548 : enum tree_code code = gimple_assign_rhs_code (def_stmt);
7865 : 548 : if (code == POINTER_PLUS_EXPR)
7866 : 0 : code = PLUS_EXPR;
7867 : 548 : gcc_assert (TREE_CODE_LENGTH (code) == binary_op
7868 : : && commutative_tree_code (code));
7869 : 548 : tree rhs1 = gimple_assign_rhs1 (def_stmt);
7870 : 548 : tree rhs2 = gimple_assign_rhs2 (def_stmt);
7871 : 548 : gcc_assert (TREE_CODE (rhs1) == SSA_NAME && TREE_CODE (rhs2) == SSA_NAME);
7872 : 548 : gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1);
7873 : 548 : gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2);
7874 : 548 : stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt);
7875 : 548 : stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt);
7876 : 548 : dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info);
7877 : 548 : dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info);
7878 : 548 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0);
7879 : 548 : tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0);
7880 : :
7881 : 548 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7882 : : {
7883 : 460 : std::swap (rhs1, rhs2);
7884 : 460 : std::swap (var1, var2);
7885 : 460 : std::swap (load1_dr_info, load2_dr_info);
7886 : : }
7887 : :
7888 : 548 : tree *init = loop_vinfo->scan_map->get (var1);
7889 : 548 : gcc_assert (init);
7890 : :
7891 : 548 : unsigned HOST_WIDE_INT nunits;
7892 : 548 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits))
7893 : : gcc_unreachable ();
7894 : 548 : auto_vec<enum scan_store_kind, 16> use_whole_vector;
7895 : 548 : int units_log2 = scan_store_can_perm_p (vectype, *init, &use_whole_vector);
7896 : 548 : gcc_assert (units_log2 > 0);
7897 : 548 : auto_vec<tree, 16> perms;
7898 : 548 : perms.quick_grow (units_log2 + 1);
7899 : 548 : tree zero_vec = NULL_TREE, masktype = NULL_TREE;
7900 : 2536 : for (int i = 0; i <= units_log2; ++i)
7901 : : {
7902 : 1988 : unsigned HOST_WIDE_INT j, k;
7903 : 1988 : vec_perm_builder sel (nunits, nunits, 1);
7904 : 1988 : sel.quick_grow (nunits);
7905 : 1988 : if (i == units_log2)
7906 : 5044 : for (j = 0; j < nunits; ++j)
7907 : 4496 : sel[j] = nunits - 1;
7908 : : else
7909 : : {
7910 : 5388 : for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j)
7911 : 3948 : sel[j] = j;
7912 : 13460 : for (k = 0; j < nunits; ++j, ++k)
7913 : 12020 : sel[j] = nunits + k;
7914 : : }
7915 : 3428 : vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits);
7916 : 1988 : if (!use_whole_vector.is_empty ()
7917 : 0 : && use_whole_vector[i] != scan_store_kind_perm)
7918 : : {
7919 : 0 : if (zero_vec == NULL_TREE)
7920 : 0 : zero_vec = build_zero_cst (vectype);
7921 : 0 : if (masktype == NULL_TREE
7922 : 0 : && use_whole_vector[i] == scan_store_kind_lshift_cond)
7923 : 0 : masktype = truth_type_for (vectype);
7924 : 0 : perms[i] = vect_gen_perm_mask_any (vectype, indices);
7925 : : }
7926 : : else
7927 : 1988 : perms[i] = vect_gen_perm_mask_checked (vectype, indices);
7928 : 1988 : }
7929 : :
7930 : 548 : tree vec_oprnd1 = NULL_TREE;
7931 : 548 : tree vec_oprnd2 = NULL_TREE;
7932 : 548 : tree vec_oprnd3 = NULL_TREE;
7933 : 548 : tree dataref_ptr = DR_BASE_ADDRESS (dr_info->dr);
7934 : 548 : tree dataref_offset = build_int_cst (ref_type, 0);
7935 : 548 : tree bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info,
7936 : : vectype, VMAT_CONTIGUOUS);
7937 : 548 : tree ldataref_ptr = NULL_TREE;
7938 : 548 : tree orig = NULL_TREE;
7939 : 548 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7940 : 134 : ldataref_ptr = DR_BASE_ADDRESS (load1_dr_info->dr);
7941 : 548 : auto_vec<tree> vec_oprnds1;
7942 : 548 : auto_vec<tree> vec_oprnds2;
7943 : 548 : auto_vec<tree> vec_oprnds3;
7944 : 548 : vect_get_vec_defs (vinfo, stmt_info, NULL, ncopies,
7945 : : *init, &vec_oprnds1,
7946 : : ldataref_ptr == NULL ? rhs1 : NULL, &vec_oprnds2,
7947 : : rhs2, &vec_oprnds3);
7948 : 1320 : for (int j = 0; j < ncopies; j++)
7949 : : {
7950 : 772 : vec_oprnd1 = vec_oprnds1[j];
7951 : 772 : if (ldataref_ptr == NULL)
7952 : 582 : vec_oprnd2 = vec_oprnds2[j];
7953 : 772 : vec_oprnd3 = vec_oprnds3[j];
7954 : 772 : if (j == 0)
7955 : : orig = vec_oprnd3;
7956 : 224 : else if (!inscan_var_store)
7957 : 112 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
7958 : :
7959 : 772 : if (ldataref_ptr)
7960 : : {
7961 : 190 : vec_oprnd2 = make_ssa_name (vectype);
7962 : 190 : tree data_ref = fold_build2 (MEM_REF, vectype,
7963 : : unshare_expr (ldataref_ptr),
7964 : : dataref_offset);
7965 : 190 : vect_copy_ref_info (data_ref, DR_REF (load1_dr_info->dr));
7966 : 190 : gimple *g = gimple_build_assign (vec_oprnd2, data_ref);
7967 : 190 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7968 : 190 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
7969 : 190 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
7970 : : }
7971 : :
7972 : 772 : tree v = vec_oprnd2;
7973 : 3192 : for (int i = 0; i < units_log2; ++i)
7974 : : {
7975 : 2420 : tree new_temp = make_ssa_name (vectype);
7976 : 2420 : gimple *g = gimple_build_assign (new_temp, VEC_PERM_EXPR,
7977 : : (zero_vec
7978 : 0 : && (use_whole_vector[i]
7979 : 0 : != scan_store_kind_perm))
7980 : : ? zero_vec : vec_oprnd1, v,
7981 : 2420 : perms[i]);
7982 : 2420 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7983 : 2420 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
7984 : 2420 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
7985 : :
7986 : 2420 : if (zero_vec && use_whole_vector[i] == scan_store_kind_lshift_cond)
7987 : : {
7988 : : /* Whole vector shift shifted in zero bits, but if *init
7989 : : is not initializer_zerop, we need to replace those elements
7990 : : with elements from vec_oprnd1. */
7991 : 0 : tree_vector_builder vb (masktype, nunits, 1);
7992 : 0 : for (unsigned HOST_WIDE_INT k = 0; k < nunits; ++k)
7993 : 0 : vb.quick_push (k < (HOST_WIDE_INT_1U << i)
7994 : : ? boolean_false_node : boolean_true_node);
7995 : :
7996 : 0 : tree new_temp2 = make_ssa_name (vectype);
7997 : 0 : g = gimple_build_assign (new_temp2, VEC_COND_EXPR, vb.build (),
7998 : : new_temp, vec_oprnd1);
7999 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
8000 : : g, gsi);
8001 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8002 : 0 : new_temp = new_temp2;
8003 : 0 : }
8004 : :
8005 : : /* For exclusive scan, perform the perms[i] permutation once
8006 : : more. */
8007 : 2420 : if (i == 0
8008 : 1152 : && STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4
8009 : 760 : && v == vec_oprnd2)
8010 : : {
8011 : 380 : v = new_temp;
8012 : 380 : --i;
8013 : 380 : continue;
8014 : : }
8015 : :
8016 : 2040 : tree new_temp2 = make_ssa_name (vectype);
8017 : 2040 : g = gimple_build_assign (new_temp2, code, v, new_temp);
8018 : 2040 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8019 : 2040 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8020 : :
8021 : 2040 : v = new_temp2;
8022 : : }
8023 : :
8024 : 772 : tree new_temp = make_ssa_name (vectype);
8025 : 772 : gimple *g = gimple_build_assign (new_temp, code, orig, v);
8026 : 772 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8027 : 772 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8028 : :
8029 : 772 : tree last_perm_arg = new_temp;
8030 : : /* For exclusive scan, new_temp computed above is the exclusive scan
8031 : : prefix sum. Turn it into inclusive prefix sum for the broadcast
8032 : : of the last element into orig. */
8033 : 772 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
8034 : : {
8035 : 380 : last_perm_arg = make_ssa_name (vectype);
8036 : 380 : g = gimple_build_assign (last_perm_arg, code, new_temp, vec_oprnd2);
8037 : 380 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8038 : 380 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8039 : : }
8040 : :
8041 : 772 : orig = make_ssa_name (vectype);
8042 : 2316 : g = gimple_build_assign (orig, VEC_PERM_EXPR, last_perm_arg,
8043 : 772 : last_perm_arg, perms[units_log2]);
8044 : 772 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8045 : 772 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8046 : :
8047 : 772 : if (!inscan_var_store)
8048 : : {
8049 : 386 : tree data_ref = fold_build2 (MEM_REF, vectype,
8050 : : unshare_expr (dataref_ptr),
8051 : : dataref_offset);
8052 : 386 : vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
8053 : 386 : g = gimple_build_assign (data_ref, new_temp);
8054 : 386 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8055 : 386 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8056 : : }
8057 : : }
8058 : :
8059 : 548 : if (inscan_var_store)
8060 : 660 : for (int j = 0; j < ncopies; j++)
8061 : : {
8062 : 386 : if (j != 0)
8063 : 112 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
8064 : :
8065 : 386 : tree data_ref = fold_build2 (MEM_REF, vectype,
8066 : : unshare_expr (dataref_ptr),
8067 : : dataref_offset);
8068 : 386 : vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
8069 : 386 : gimple *g = gimple_build_assign (data_ref, orig);
8070 : 386 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8071 : 386 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8072 : : }
8073 : 548 : return true;
8074 : 548 : }
8075 : :
8076 : :
8077 : : /* Function vectorizable_store.
8078 : :
8079 : : Check if STMT_INFO defines a non scalar data-ref (array/pointer/structure)
8080 : : that can be vectorized.
8081 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
8082 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
8083 : : Return true if STMT_INFO is vectorizable in this way. */
8084 : :
8085 : : static bool
8086 : 1558537 : vectorizable_store (vec_info *vinfo,
8087 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
8088 : : gimple **vec_stmt, slp_tree slp_node,
8089 : : stmt_vector_for_cost *cost_vec)
8090 : : {
8091 : 1558537 : tree data_ref;
8092 : 1558537 : tree vec_oprnd = NULL_TREE;
8093 : 1558537 : tree elem_type;
8094 : 1558537 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
8095 : 1558537 : class loop *loop = NULL;
8096 : 1558537 : machine_mode vec_mode;
8097 : 1558537 : tree dummy;
8098 : 1558537 : enum vect_def_type rhs_dt = vect_unknown_def_type;
8099 : 1558537 : enum vect_def_type mask_dt = vect_unknown_def_type;
8100 : 1558537 : tree dataref_ptr = NULL_TREE;
8101 : 1558537 : tree dataref_offset = NULL_TREE;
8102 : 1558537 : gimple *ptr_incr = NULL;
8103 : 1558537 : int ncopies;
8104 : 1558537 : int j;
8105 : 1558537 : stmt_vec_info first_stmt_info;
8106 : 1558537 : bool grouped_store;
8107 : 1558537 : unsigned int group_size, i;
8108 : 1558537 : bool slp = (slp_node != NULL);
8109 : 1558537 : unsigned int vec_num;
8110 : 1558537 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
8111 : 1558537 : tree aggr_type;
8112 : 1558537 : gather_scatter_info gs_info;
8113 : 1558537 : poly_uint64 vf;
8114 : 1558537 : vec_load_store_type vls_type;
8115 : 1558537 : tree ref_type;
8116 : :
8117 : 1558537 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
8118 : : return false;
8119 : :
8120 : 1558537 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
8121 : 24817 : && ! vec_stmt)
8122 : : return false;
8123 : :
8124 : : /* Is vectorizable store? */
8125 : :
8126 : 1533720 : tree mask = NULL_TREE, mask_vectype = NULL_TREE;
8127 : 1533720 : slp_tree mask_node = NULL;
8128 : 1533720 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
8129 : : {
8130 : 1465567 : tree scalar_dest = gimple_assign_lhs (assign);
8131 : 1465567 : if (TREE_CODE (scalar_dest) == VIEW_CONVERT_EXPR
8132 : 1465567 : && is_pattern_stmt_p (stmt_info))
8133 : 1273 : scalar_dest = TREE_OPERAND (scalar_dest, 0);
8134 : 1465567 : if (TREE_CODE (scalar_dest) != ARRAY_REF
8135 : 1465567 : && TREE_CODE (scalar_dest) != BIT_FIELD_REF
8136 : : && TREE_CODE (scalar_dest) != INDIRECT_REF
8137 : : && TREE_CODE (scalar_dest) != COMPONENT_REF
8138 : : && TREE_CODE (scalar_dest) != IMAGPART_EXPR
8139 : : && TREE_CODE (scalar_dest) != REALPART_EXPR
8140 : : && TREE_CODE (scalar_dest) != MEM_REF)
8141 : : return false;
8142 : : }
8143 : : else
8144 : : {
8145 : 292191 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
8146 : 7806 : if (!call || !gimple_call_internal_p (call))
8147 : : return false;
8148 : :
8149 : 4808 : internal_fn ifn = gimple_call_internal_fn (call);
8150 : 4808 : if (!internal_store_fn_p (ifn))
8151 : : return false;
8152 : :
8153 : 2814 : int mask_index = internal_fn_mask_index (ifn);
8154 : 2814 : if (mask_index >= 0 && slp_node)
8155 : 18 : mask_index = vect_slp_child_index_for_operand
8156 : 18 : (call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
8157 : 2814 : if (mask_index >= 0
8158 : 2814 : && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index,
8159 : : &mask, &mask_node, &mask_dt,
8160 : : &mask_vectype))
8161 : : return false;
8162 : : }
8163 : :
8164 : : /* Cannot have hybrid store SLP -- that would mean storing to the
8165 : : same location twice. */
8166 : 1274906 : gcc_assert (slp == PURE_SLP_STMT (stmt_info));
8167 : :
8168 : 1274906 : tree vectype = STMT_VINFO_VECTYPE (stmt_info), rhs_vectype = NULL_TREE;
8169 : 1274906 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
8170 : :
8171 : 1274906 : if (loop_vinfo)
8172 : : {
8173 : 159655 : loop = LOOP_VINFO_LOOP (loop_vinfo);
8174 : 159655 : vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
8175 : : }
8176 : : else
8177 : : vf = 1;
8178 : :
8179 : : /* Multiple types in SLP are handled by creating the appropriate number of
8180 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
8181 : : case of SLP. */
8182 : 1274906 : if (slp)
8183 : : ncopies = 1;
8184 : : else
8185 : 145599 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
8186 : :
8187 : 145599 : gcc_assert (ncopies >= 1);
8188 : :
8189 : : /* FORNOW. This restriction should be relaxed. */
8190 : 1275135 : if (loop && nested_in_vect_loop_p (loop, stmt_info) && ncopies > 1)
8191 : : {
8192 : 3 : if (dump_enabled_p ())
8193 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8194 : : "multiple types in nested loop.\n");
8195 : 3 : return false;
8196 : : }
8197 : :
8198 : 1274903 : tree op;
8199 : 1274903 : slp_tree op_node;
8200 : 1274903 : if (!vect_check_store_rhs (vinfo, stmt_info, slp_node,
8201 : : &op, &op_node, &rhs_dt, &rhs_vectype, &vls_type))
8202 : : return false;
8203 : :
8204 : 1274887 : elem_type = TREE_TYPE (vectype);
8205 : 1274887 : vec_mode = TYPE_MODE (vectype);
8206 : :
8207 : 1274887 : if (!STMT_VINFO_DATA_REF (stmt_info))
8208 : : return false;
8209 : :
8210 : 1274887 : vect_memory_access_type memory_access_type;
8211 : 1274887 : enum dr_alignment_support alignment_support_scheme;
8212 : 1274887 : int misalignment;
8213 : 1274887 : poly_int64 poffset;
8214 : 1274887 : internal_fn lanes_ifn;
8215 : 1274887 : if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, vls_type,
8216 : : ncopies, &memory_access_type, &poffset,
8217 : : &alignment_support_scheme, &misalignment, &gs_info,
8218 : : &lanes_ifn))
8219 : : return false;
8220 : :
8221 : 1274207 : if (mask)
8222 : : {
8223 : 2765 : if (memory_access_type == VMAT_CONTIGUOUS)
8224 : : {
8225 : 1129 : if (!VECTOR_MODE_P (vec_mode)
8226 : 5038 : || !can_vec_mask_load_store_p (vec_mode,
8227 : 2519 : TYPE_MODE (mask_vectype), false))
8228 : 14 : return false;
8229 : : }
8230 : 246 : else if (memory_access_type != VMAT_LOAD_STORE_LANES
8231 : 246 : && (memory_access_type != VMAT_GATHER_SCATTER
8232 : 239 : || (gs_info.decl && !VECTOR_BOOLEAN_TYPE_P (mask_vectype))))
8233 : : {
8234 : 7 : if (dump_enabled_p ())
8235 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8236 : : "unsupported access type for masked store.\n");
8237 : 7 : return false;
8238 : : }
8239 : 239 : else if (memory_access_type == VMAT_GATHER_SCATTER
8240 : 239 : && gs_info.ifn == IFN_LAST
8241 : 239 : && !gs_info.decl)
8242 : : {
8243 : 34 : if (dump_enabled_p ())
8244 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8245 : : "unsupported masked emulated scatter.\n");
8246 : 34 : return false;
8247 : : }
8248 : : }
8249 : : else
8250 : : {
8251 : : /* FORNOW. In some cases can vectorize even if data-type not supported
8252 : : (e.g. - array initialization with 0). */
8253 : 1271442 : if (optab_handler (mov_optab, vec_mode) == CODE_FOR_nothing)
8254 : : return false;
8255 : : }
8256 : :
8257 : 1274152 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL;
8258 : 1274152 : grouped_store = (STMT_VINFO_GROUPED_ACCESS (stmt_info)
8259 : 1140355 : && memory_access_type != VMAT_GATHER_SCATTER
8260 : 2414507 : && (slp || memory_access_type != VMAT_CONTIGUOUS));
8261 : 1274152 : if (grouped_store)
8262 : : {
8263 : 1140355 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
8264 : 1140355 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
8265 : 1140355 : group_size = DR_GROUP_SIZE (first_stmt_info);
8266 : : }
8267 : : else
8268 : : {
8269 : : first_stmt_info = stmt_info;
8270 : : first_dr_info = dr_info;
8271 : : group_size = vec_num = 1;
8272 : : }
8273 : :
8274 : 1274152 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1 && !vec_stmt)
8275 : : {
8276 : 992 : if (!check_scan_store (vinfo, stmt_info, vectype, rhs_dt, slp, mask,
8277 : : memory_access_type))
8278 : : return false;
8279 : : }
8280 : :
8281 : 1274152 : bool costing_p = !vec_stmt;
8282 : 1274152 : if (costing_p) /* transformation not required. */
8283 : : {
8284 : 722265 : STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info) = memory_access_type;
8285 : :
8286 : 722265 : if (loop_vinfo
8287 : 109441 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
8288 : 18 : check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
8289 : : vls_type, group_size,
8290 : : memory_access_type, &gs_info,
8291 : : mask);
8292 : :
8293 : 722265 : if (slp_node
8294 : 722265 : && (!vect_maybe_update_slp_op_vectype (op_node, vectype)
8295 : 621827 : || (mask
8296 : 6 : && !vect_maybe_update_slp_op_vectype (mask_node,
8297 : : mask_vectype))))
8298 : : {
8299 : 0 : if (dump_enabled_p ())
8300 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8301 : : "incompatible vector types for invariants\n");
8302 : 0 : return false;
8303 : : }
8304 : :
8305 : 722265 : if (dump_enabled_p ()
8306 : 16841 : && memory_access_type != VMAT_ELEMENTWISE
8307 : 16263 : && memory_access_type != VMAT_GATHER_SCATTER
8308 : 738432 : && alignment_support_scheme != dr_aligned)
8309 : 6024 : dump_printf_loc (MSG_NOTE, vect_location,
8310 : : "Vectorizing an unaligned access.\n");
8311 : :
8312 : 722265 : STMT_VINFO_TYPE (stmt_info) = store_vec_info_type;
8313 : :
8314 : : /* As function vect_transform_stmt shows, for interleaving stores
8315 : : the whole chain is vectorized when the last store in the chain
8316 : : is reached, the other stores in the group are skipped. So we
8317 : : want to only cost the last one here, but it's not trivial to
8318 : : get the last, as it's equivalent to use the first one for
8319 : : costing, use the first one instead. */
8320 : 722265 : if (grouped_store
8321 : 631661 : && !slp
8322 : 9834 : && first_stmt_info != stmt_info)
8323 : : return true;
8324 : : }
8325 : 1267826 : gcc_assert (memory_access_type == STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info));
8326 : :
8327 : : /* Transform. */
8328 : :
8329 : 1267826 : ensure_base_align (dr_info);
8330 : :
8331 : 1267826 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) >= 3)
8332 : : {
8333 : 1096 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS);
8334 : 1096 : gcc_assert (!slp);
8335 : 1096 : if (costing_p)
8336 : : {
8337 : 548 : unsigned int inside_cost = 0, prologue_cost = 0;
8338 : 548 : if (vls_type == VLS_STORE_INVARIANT)
8339 : 0 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
8340 : : stmt_info, 0, vect_prologue);
8341 : 548 : vect_get_store_cost (vinfo, stmt_info, ncopies,
8342 : : alignment_support_scheme, misalignment,
8343 : : &inside_cost, cost_vec);
8344 : :
8345 : 548 : if (dump_enabled_p ())
8346 : 528 : dump_printf_loc (MSG_NOTE, vect_location,
8347 : : "vect_model_store_cost: inside_cost = %d, "
8348 : : "prologue_cost = %d .\n",
8349 : : inside_cost, prologue_cost);
8350 : :
8351 : 548 : return true;
8352 : : }
8353 : 548 : return vectorizable_scan_store (vinfo, stmt_info, gsi, vec_stmt, ncopies);
8354 : : }
8355 : :
8356 : 1266730 : if (grouped_store)
8357 : : {
8358 : : /* FORNOW */
8359 : 1134029 : gcc_assert (!loop || !nested_in_vect_loop_p (loop, stmt_info));
8360 : :
8361 : 1134029 : if (slp)
8362 : : {
8363 : 1129297 : grouped_store = false;
8364 : : /* VEC_NUM is the number of vect stmts to be created for this
8365 : : group. */
8366 : 1129297 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
8367 : 1129297 : first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
8368 : 1129297 : gcc_assert (DR_GROUP_FIRST_ELEMENT (first_stmt_info)
8369 : : == first_stmt_info);
8370 : 1129297 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
8371 : 1129297 : op = vect_get_store_rhs (first_stmt_info);
8372 : : }
8373 : : else
8374 : : /* VEC_NUM is the number of vect stmts to be created for this
8375 : : group. */
8376 : : vec_num = group_size;
8377 : :
8378 : 1134029 : ref_type = get_group_alias_ptr_type (first_stmt_info);
8379 : : }
8380 : : else
8381 : 132701 : ref_type = reference_alias_ptr_type (DR_REF (first_dr_info->dr));
8382 : :
8383 : 1266730 : if (!costing_p && dump_enabled_p ())
8384 : 11326 : dump_printf_loc (MSG_NOTE, vect_location, "transform store. ncopies = %d\n",
8385 : : ncopies);
8386 : :
8387 : : /* Check if we need to update prologue cost for invariant,
8388 : : and update it accordingly if so. If it's not for
8389 : : interleaving store, we can just check vls_type; but if
8390 : : it's for interleaving store, need to check the def_type
8391 : : of the stored value since the current vls_type is just
8392 : : for first_stmt_info. */
8393 : 2992243 : auto update_prologue_cost = [&](unsigned *prologue_cost, tree store_rhs)
8394 : : {
8395 : 1725513 : gcc_assert (costing_p);
8396 : 1725513 : if (slp)
8397 : : return;
8398 : 98263 : if (grouped_store)
8399 : : {
8400 : 9112 : gcc_assert (store_rhs);
8401 : 9112 : enum vect_def_type cdt;
8402 : 9112 : gcc_assert (vect_is_simple_use (store_rhs, vinfo, &cdt));
8403 : 9112 : if (cdt != vect_constant_def && cdt != vect_external_def)
8404 : 6598 : return;
8405 : : }
8406 : 89151 : else if (vls_type != VLS_STORE_INVARIANT)
8407 : : return;
8408 : 25732 : *prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec, stmt_info,
8409 : : 0, vect_prologue);
8410 : 1266730 : };
8411 : :
8412 : 1266730 : if (memory_access_type == VMAT_ELEMENTWISE
8413 : 1266730 : || memory_access_type == VMAT_STRIDED_SLP)
8414 : : {
8415 : 21075 : unsigned inside_cost = 0, prologue_cost = 0;
8416 : 21075 : gimple_stmt_iterator incr_gsi;
8417 : 21075 : bool insert_after;
8418 : 21075 : gimple *incr;
8419 : 21075 : tree offvar;
8420 : 21075 : tree ivstep;
8421 : 21075 : tree running_off;
8422 : 21075 : tree stride_base, stride_step, alias_off;
8423 : 21075 : tree vec_oprnd = NULL_TREE;
8424 : 21075 : tree dr_offset;
8425 : 21075 : unsigned int g;
8426 : : /* Checked by get_load_store_type. */
8427 : 21075 : unsigned int const_nunits = nunits.to_constant ();
8428 : :
8429 : 21075 : gcc_assert (!LOOP_VINFO_FULLY_MASKED_P (loop_vinfo));
8430 : 21075 : gcc_assert (!nested_in_vect_loop_p (loop, stmt_info));
8431 : :
8432 : 21075 : dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info);
8433 : 21075 : stride_base
8434 : 21075 : = fold_build_pointer_plus
8435 : : (DR_BASE_ADDRESS (first_dr_info->dr),
8436 : : size_binop (PLUS_EXPR,
8437 : : convert_to_ptrofftype (dr_offset),
8438 : : convert_to_ptrofftype (DR_INIT (first_dr_info->dr))));
8439 : 21075 : stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr));
8440 : :
8441 : : /* For a store with loop-invariant (but other than power-of-2)
8442 : : stride (i.e. not a grouped access) like so:
8443 : :
8444 : : for (i = 0; i < n; i += stride)
8445 : : array[i] = ...;
8446 : :
8447 : : we generate a new induction variable and new stores from
8448 : : the components of the (vectorized) rhs:
8449 : :
8450 : : for (j = 0; ; j += VF*stride)
8451 : : vectemp = ...;
8452 : : tmp1 = vectemp[0];
8453 : : array[j] = tmp1;
8454 : : tmp2 = vectemp[1];
8455 : : array[j + stride] = tmp2;
8456 : : ...
8457 : : */
8458 : :
8459 : 21075 : unsigned nstores = const_nunits;
8460 : 21075 : unsigned lnel = 1;
8461 : 21075 : tree ltype = elem_type;
8462 : 21075 : tree lvectype = vectype;
8463 : 21075 : if (slp)
8464 : : {
8465 : 4178 : if (group_size < const_nunits
8466 : 2030 : && const_nunits % group_size == 0)
8467 : : {
8468 : 1977 : nstores = const_nunits / group_size;
8469 : 1977 : lnel = group_size;
8470 : 1977 : ltype = build_vector_type (elem_type, group_size);
8471 : 1977 : lvectype = vectype;
8472 : :
8473 : : /* First check if vec_extract optab doesn't support extraction
8474 : : of vector elts directly. */
8475 : 1977 : scalar_mode elmode = SCALAR_TYPE_MODE (elem_type);
8476 : 1977 : machine_mode vmode;
8477 : 3954 : if (!VECTOR_MODE_P (TYPE_MODE (vectype))
8478 : 2206 : || !related_vector_mode (TYPE_MODE (vectype), elmode,
8479 : 1977 : group_size).exists (&vmode)
8480 : 3600 : || (convert_optab_handler (vec_extract_optab,
8481 : 1623 : TYPE_MODE (vectype), vmode)
8482 : : == CODE_FOR_nothing))
8483 : : {
8484 : : /* Try to avoid emitting an extract of vector elements
8485 : : by performing the extracts using an integer type of the
8486 : : same size, extracting from a vector of those and then
8487 : : re-interpreting it as the original vector type if
8488 : : supported. */
8489 : 1748 : unsigned lsize
8490 : 1748 : = group_size * GET_MODE_BITSIZE (elmode);
8491 : 1748 : unsigned int lnunits = const_nunits / group_size;
8492 : : /* If we can't construct such a vector fall back to
8493 : : element extracts from the original vector type and
8494 : : element size stores. */
8495 : 1748 : if (int_mode_for_size (lsize, 0).exists (&elmode)
8496 : 1748 : && VECTOR_MODE_P (TYPE_MODE (vectype))
8497 : 1748 : && related_vector_mode (TYPE_MODE (vectype), elmode,
8498 : 30 : lnunits).exists (&vmode)
8499 : 1718 : && (convert_optab_handler (vec_extract_optab,
8500 : : vmode, elmode)
8501 : : != CODE_FOR_nothing))
8502 : : {
8503 : 1718 : nstores = lnunits;
8504 : 1718 : lnel = group_size;
8505 : 1718 : ltype = build_nonstandard_integer_type (lsize, 1);
8506 : 1718 : lvectype = build_vector_type (ltype, nstores);
8507 : : }
8508 : : /* Else fall back to vector extraction anyway.
8509 : : Fewer stores are more important than avoiding spilling
8510 : : of the vector we extract from. Compared to the
8511 : : construction case in vectorizable_load no store-forwarding
8512 : : issue exists here for reasonable archs. */
8513 : : }
8514 : : }
8515 : 2201 : else if (group_size >= const_nunits
8516 : 2148 : && group_size % const_nunits == 0)
8517 : : {
8518 : 1805 : int mis_align = dr_misalignment (first_dr_info, vectype);
8519 : 1805 : dr_alignment_support dr_align
8520 : 1805 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype,
8521 : : mis_align);
8522 : 1805 : if (dr_align == dr_aligned
8523 : 1805 : || dr_align == dr_unaligned_supported)
8524 : : {
8525 : 1805 : nstores = 1;
8526 : 1805 : lnel = const_nunits;
8527 : 1805 : ltype = vectype;
8528 : 1805 : lvectype = vectype;
8529 : 1805 : alignment_support_scheme = dr_align;
8530 : 1805 : misalignment = mis_align;
8531 : : }
8532 : : }
8533 : 4178 : ltype = build_aligned_type (ltype, TYPE_ALIGN (elem_type));
8534 : 4178 : ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
8535 : : }
8536 : :
8537 : 21075 : if (!costing_p)
8538 : : {
8539 : 3292 : ivstep = stride_step;
8540 : 3292 : ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (ivstep), ivstep,
8541 : : build_int_cst (TREE_TYPE (ivstep), vf));
8542 : :
8543 : 3292 : standard_iv_increment_position (loop, &incr_gsi, &insert_after);
8544 : :
8545 : 3292 : stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base);
8546 : 3292 : ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep);
8547 : 3292 : create_iv (stride_base, PLUS_EXPR, ivstep, NULL, loop, &incr_gsi,
8548 : : insert_after, &offvar, NULL);
8549 : 3292 : incr = gsi_stmt (incr_gsi);
8550 : :
8551 : 3292 : stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step);
8552 : : }
8553 : :
8554 : 21075 : alias_off = build_int_cst (ref_type, 0);
8555 : 21075 : stmt_vec_info next_stmt_info = first_stmt_info;
8556 : 21075 : auto_vec<tree> vec_oprnds;
8557 : : /* For costing some adjacent vector stores, we'd like to cost with
8558 : : the total number of them once instead of cost each one by one. */
8559 : 21075 : unsigned int n_adjacent_stores = 0;
8560 : 40854 : for (g = 0; g < group_size; g++)
8561 : : {
8562 : 23957 : running_off = offvar;
8563 : 23957 : if (!costing_p)
8564 : : {
8565 : 3805 : if (g)
8566 : : {
8567 : 513 : tree size = TYPE_SIZE_UNIT (ltype);
8568 : 513 : tree pos
8569 : 513 : = fold_build2 (MULT_EXPR, sizetype, size_int (g), size);
8570 : 513 : tree newoff = copy_ssa_name (running_off, NULL);
8571 : 513 : incr = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
8572 : : running_off, pos);
8573 : 513 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
8574 : 513 : running_off = newoff;
8575 : : }
8576 : : }
8577 : 23957 : if (!slp)
8578 : 19779 : op = vect_get_store_rhs (next_stmt_info);
8579 : 23957 : if (!costing_p)
8580 : 3805 : vect_get_vec_defs (vinfo, next_stmt_info, slp_node, ncopies, op,
8581 : : &vec_oprnds);
8582 : : else
8583 : 20152 : update_prologue_cost (&prologue_cost, op);
8584 : 23957 : unsigned int group_el = 0;
8585 : 23957 : unsigned HOST_WIDE_INT
8586 : 23957 : elsz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
8587 : 98429 : for (j = 0; j < ncopies; j++)
8588 : : {
8589 : 74472 : if (!costing_p)
8590 : : {
8591 : 6030 : vec_oprnd = vec_oprnds[j];
8592 : : /* Pun the vector to extract from if necessary. */
8593 : 6030 : if (lvectype != vectype)
8594 : : {
8595 : 515 : tree tem = make_ssa_name (lvectype);
8596 : 515 : tree cvt
8597 : 515 : = build1 (VIEW_CONVERT_EXPR, lvectype, vec_oprnd);
8598 : 515 : gimple *pun = gimple_build_assign (tem, cvt);
8599 : 515 : vect_finish_stmt_generation (vinfo, stmt_info, pun, gsi);
8600 : 515 : vec_oprnd = tem;
8601 : : }
8602 : : }
8603 : 261518 : for (i = 0; i < nstores; i++)
8604 : : {
8605 : 187046 : if (costing_p)
8606 : : {
8607 : : /* Only need vector extracting when there are more
8608 : : than one stores. */
8609 : 164025 : if (nstores > 1)
8610 : 137104 : inside_cost
8611 : 137104 : += record_stmt_cost (cost_vec, 1, vec_to_scalar,
8612 : : stmt_info, 0, vect_body);
8613 : : /* Take a single lane vector type store as scalar
8614 : : store to avoid ICE like 110776. */
8615 : 164025 : if (VECTOR_TYPE_P (ltype)
8616 : 164025 : && known_ne (TYPE_VECTOR_SUBPARTS (ltype), 1U))
8617 : 4255 : n_adjacent_stores++;
8618 : : else
8619 : 159770 : inside_cost
8620 : 159770 : += record_stmt_cost (cost_vec, 1, scalar_store,
8621 : : stmt_info, 0, vect_body);
8622 : 164025 : continue;
8623 : : }
8624 : 23021 : tree newref, newoff;
8625 : 23021 : gimple *incr, *assign;
8626 : 23021 : tree size = TYPE_SIZE (ltype);
8627 : : /* Extract the i'th component. */
8628 : 23021 : tree pos = fold_build2 (MULT_EXPR, bitsizetype,
8629 : : bitsize_int (i), size);
8630 : 23021 : tree elem = fold_build3 (BIT_FIELD_REF, ltype, vec_oprnd,
8631 : : size, pos);
8632 : :
8633 : 23021 : elem = force_gimple_operand_gsi (gsi, elem, true,
8634 : : NULL_TREE, true,
8635 : : GSI_SAME_STMT);
8636 : :
8637 : 23021 : tree this_off = build_int_cst (TREE_TYPE (alias_off),
8638 : 23021 : group_el * elsz);
8639 : 23021 : newref = build2 (MEM_REF, ltype,
8640 : : running_off, this_off);
8641 : 23021 : vect_copy_ref_info (newref, DR_REF (first_dr_info->dr));
8642 : :
8643 : : /* And store it to *running_off. */
8644 : 23021 : assign = gimple_build_assign (newref, elem);
8645 : 23021 : vect_finish_stmt_generation (vinfo, stmt_info, assign, gsi);
8646 : :
8647 : 23021 : group_el += lnel;
8648 : 23021 : if (! slp
8649 : 5125 : || group_el == group_size)
8650 : : {
8651 : 21372 : newoff = copy_ssa_name (running_off, NULL);
8652 : 21372 : incr = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
8653 : : running_off, stride_step);
8654 : 21372 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
8655 : :
8656 : 21372 : running_off = newoff;
8657 : 21372 : group_el = 0;
8658 : : }
8659 : 23021 : if (g == group_size - 1
8660 : 12952 : && !slp)
8661 : : {
8662 : 12896 : if (j == 0 && i == 0)
8663 : 2102 : *vec_stmt = assign;
8664 : 12896 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (assign);
8665 : : }
8666 : : }
8667 : : }
8668 : 23957 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
8669 : 23957 : vec_oprnds.truncate(0);
8670 : 23957 : if (slp)
8671 : : break;
8672 : : }
8673 : :
8674 : 21075 : if (costing_p)
8675 : : {
8676 : 17783 : if (n_adjacent_stores > 0)
8677 : 1106 : vect_get_store_cost (vinfo, stmt_info, n_adjacent_stores,
8678 : : alignment_support_scheme, misalignment,
8679 : : &inside_cost, cost_vec);
8680 : 17783 : if (dump_enabled_p ())
8681 : 715 : dump_printf_loc (MSG_NOTE, vect_location,
8682 : : "vect_model_store_cost: inside_cost = %d, "
8683 : : "prologue_cost = %d .\n",
8684 : : inside_cost, prologue_cost);
8685 : : }
8686 : :
8687 : 21075 : return true;
8688 : 21075 : }
8689 : :
8690 : 1245655 : gcc_assert (alignment_support_scheme);
8691 : 1245655 : vec_loop_masks *loop_masks
8692 : 130404 : = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
8693 : 1245655 : ? &LOOP_VINFO_MASKS (loop_vinfo)
8694 : 1376064 : : NULL);
8695 : 5 : vec_loop_lens *loop_lens
8696 : 130404 : = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)
8697 : 0 : ? &LOOP_VINFO_LENS (loop_vinfo)
8698 : 1245655 : : NULL);
8699 : :
8700 : : /* The vect_transform_stmt and vect_analyze_stmt will go here but there
8701 : : are some difference here. We cannot enable both the lens and masks
8702 : : during transform but it is allowed during analysis.
8703 : : Shouldn't go with length-based approach if fully masked. */
8704 : 1245655 : if (cost_vec == NULL)
8705 : : /* The cost_vec is NULL during transfrom. */
8706 : 548047 : gcc_assert ((!loop_lens || !loop_masks));
8707 : :
8708 : : /* Targets with store-lane instructions must not require explicit
8709 : : realignment. vect_supportable_dr_alignment always returns either
8710 : : dr_aligned or dr_unaligned_supported for masked operations. */
8711 : 1245655 : gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES
8712 : : && !mask
8713 : : && !loop_masks)
8714 : : || alignment_support_scheme == dr_aligned
8715 : : || alignment_support_scheme == dr_unaligned_supported);
8716 : :
8717 : 1245655 : tree offset = NULL_TREE;
8718 : 1245655 : if (!known_eq (poffset, 0))
8719 : 4081 : offset = size_int (poffset);
8720 : :
8721 : 1245655 : tree bump;
8722 : 1245655 : tree vec_offset = NULL_TREE;
8723 : 1245655 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
8724 : : {
8725 : 1379 : aggr_type = NULL_TREE;
8726 : 1379 : bump = NULL_TREE;
8727 : : }
8728 : 1244276 : else if (memory_access_type == VMAT_GATHER_SCATTER)
8729 : : {
8730 : 0 : aggr_type = elem_type;
8731 : 0 : if (!costing_p)
8732 : 0 : vect_get_strided_load_store_ops (stmt_info, loop_vinfo, gsi, &gs_info,
8733 : : &bump, &vec_offset, loop_lens);
8734 : : }
8735 : : else
8736 : : {
8737 : 1244276 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
8738 : 0 : aggr_type = build_array_type_nelts (elem_type, vec_num * nunits);
8739 : : else
8740 : : aggr_type = vectype;
8741 : 1244276 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
8742 : : memory_access_type, loop_lens);
8743 : : }
8744 : :
8745 : 1245655 : if (mask && !costing_p)
8746 : 1138 : LOOP_VINFO_HAS_MASK_STORE (loop_vinfo) = true;
8747 : :
8748 : : /* In case the vectorization factor (VF) is bigger than the number
8749 : : of elements that we can fit in a vectype (nunits), we have to generate
8750 : : more than one vector stmt - i.e - we need to "unroll" the
8751 : : vector stmt by a factor VF/nunits. */
8752 : :
8753 : : /* In case of interleaving (non-unit grouped access):
8754 : :
8755 : : S1: &base + 2 = x2
8756 : : S2: &base = x0
8757 : : S3: &base + 1 = x1
8758 : : S4: &base + 3 = x3
8759 : :
8760 : : We create vectorized stores starting from base address (the access of the
8761 : : first stmt in the chain (S2 in the above example), when the last store stmt
8762 : : of the chain (S4) is reached:
8763 : :
8764 : : VS1: &base = vx2
8765 : : VS2: &base + vec_size*1 = vx0
8766 : : VS3: &base + vec_size*2 = vx1
8767 : : VS4: &base + vec_size*3 = vx3
8768 : :
8769 : : Then permutation statements are generated:
8770 : :
8771 : : VS5: vx5 = VEC_PERM_EXPR < vx0, vx3, {0, 8, 1, 9, 2, 10, 3, 11} >
8772 : : VS6: vx6 = VEC_PERM_EXPR < vx0, vx3, {4, 12, 5, 13, 6, 14, 7, 15} >
8773 : : ...
8774 : :
8775 : : And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts
8776 : : (the order of the data-refs in the output of vect_permute_store_chain
8777 : : corresponds to the order of scalar stmts in the interleaving chain - see
8778 : : the documentation of vect_permute_store_chain()).
8779 : :
8780 : : In case of both multiple types and interleaving, above vector stores and
8781 : : permutation stmts are created for every copy. The result vector stmts are
8782 : : put in STMT_VINFO_VEC_STMT for the first copy and in the corresponding
8783 : : STMT_VINFO_RELATED_STMT for the next copies.
8784 : : */
8785 : :
8786 : 1245655 : auto_vec<tree> dr_chain (group_size);
8787 : 1245655 : auto_vec<tree> vec_masks;
8788 : 1245655 : tree vec_mask = NULL;
8789 : 1245655 : auto_delete_vec<auto_vec<tree>> gvec_oprnds (group_size);
8790 : 5600086 : for (i = 0; i < group_size; i++)
8791 : 3108776 : gvec_oprnds.quick_push (new auto_vec<tree> ());
8792 : :
8793 : 1245655 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
8794 : : {
8795 : 0 : gcc_assert (!slp && grouped_store);
8796 : 0 : unsigned inside_cost = 0, prologue_cost = 0;
8797 : : /* For costing some adjacent vector stores, we'd like to cost with
8798 : : the total number of them once instead of cost each one by one. */
8799 : 0 : unsigned int n_adjacent_stores = 0;
8800 : 0 : for (j = 0; j < ncopies; j++)
8801 : : {
8802 : 0 : gimple *new_stmt;
8803 : 0 : if (j == 0)
8804 : : {
8805 : : /* For interleaved stores we collect vectorized defs for all
8806 : : the stores in the group in DR_CHAIN. DR_CHAIN is then used
8807 : : as an input to vect_permute_store_chain(). */
8808 : : stmt_vec_info next_stmt_info = first_stmt_info;
8809 : 0 : for (i = 0; i < group_size; i++)
8810 : : {
8811 : : /* Since gaps are not supported for interleaved stores,
8812 : : DR_GROUP_SIZE is the exact number of stmts in the
8813 : : chain. Therefore, NEXT_STMT_INFO can't be NULL_TREE. */
8814 : 0 : op = vect_get_store_rhs (next_stmt_info);
8815 : 0 : if (costing_p)
8816 : 0 : update_prologue_cost (&prologue_cost, op);
8817 : : else
8818 : : {
8819 : 0 : vect_get_vec_defs_for_operand (vinfo, next_stmt_info,
8820 : : ncopies, op,
8821 : 0 : gvec_oprnds[i]);
8822 : 0 : vec_oprnd = (*gvec_oprnds[i])[0];
8823 : 0 : dr_chain.quick_push (vec_oprnd);
8824 : : }
8825 : 0 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
8826 : : }
8827 : :
8828 : 0 : if (!costing_p)
8829 : : {
8830 : 0 : if (mask)
8831 : : {
8832 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
8833 : : mask, &vec_masks,
8834 : : mask_vectype);
8835 : 0 : vec_mask = vec_masks[0];
8836 : : }
8837 : :
8838 : : /* We should have catched mismatched types earlier. */
8839 : 0 : gcc_assert (
8840 : : useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd)));
8841 : 0 : dataref_ptr
8842 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info,
8843 : : aggr_type, NULL, offset, &dummy,
8844 : : gsi, &ptr_incr, false, bump);
8845 : : }
8846 : : }
8847 : 0 : else if (!costing_p)
8848 : : {
8849 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
8850 : : /* DR_CHAIN is then used as an input to
8851 : : vect_permute_store_chain(). */
8852 : 0 : for (i = 0; i < group_size; i++)
8853 : : {
8854 : 0 : vec_oprnd = (*gvec_oprnds[i])[j];
8855 : 0 : dr_chain[i] = vec_oprnd;
8856 : : }
8857 : 0 : if (mask)
8858 : 0 : vec_mask = vec_masks[j];
8859 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
8860 : : stmt_info, bump);
8861 : : }
8862 : :
8863 : 0 : if (costing_p)
8864 : : {
8865 : 0 : n_adjacent_stores += vec_num;
8866 : 0 : continue;
8867 : : }
8868 : :
8869 : : /* Get an array into which we can store the individual vectors. */
8870 : 0 : tree vec_array = create_vector_array (vectype, vec_num);
8871 : :
8872 : : /* Invalidate the current contents of VEC_ARRAY. This should
8873 : : become an RTL clobber too, which prevents the vector registers
8874 : : from being upward-exposed. */
8875 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
8876 : :
8877 : : /* Store the individual vectors into the array. */
8878 : 0 : for (i = 0; i < vec_num; i++)
8879 : : {
8880 : 0 : vec_oprnd = dr_chain[i];
8881 : 0 : write_vector_array (vinfo, stmt_info, gsi, vec_oprnd, vec_array,
8882 : : i);
8883 : : }
8884 : :
8885 : 0 : tree final_mask = NULL;
8886 : 0 : tree final_len = NULL;
8887 : 0 : tree bias = NULL;
8888 : 0 : if (loop_masks)
8889 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
8890 : : ncopies, vectype, j);
8891 : 0 : if (vec_mask)
8892 : 0 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
8893 : : vec_mask, gsi);
8894 : :
8895 : 0 : if (lanes_ifn == IFN_MASK_LEN_STORE_LANES)
8896 : : {
8897 : 0 : if (loop_lens)
8898 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
8899 : : ncopies, vectype, j, 1);
8900 : : else
8901 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
8902 : 0 : signed char biasval
8903 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
8904 : 0 : bias = build_int_cst (intQI_type_node, biasval);
8905 : 0 : if (!final_mask)
8906 : : {
8907 : 0 : mask_vectype = truth_type_for (vectype);
8908 : 0 : final_mask = build_minus_one_cst (mask_vectype);
8909 : : }
8910 : : }
8911 : :
8912 : 0 : gcall *call;
8913 : 0 : if (final_len && final_mask)
8914 : : {
8915 : : /* Emit:
8916 : : MASK_LEN_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
8917 : : LEN, BIAS, VEC_ARRAY). */
8918 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
8919 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
8920 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_STORE_LANES, 6,
8921 : : dataref_ptr, alias_ptr,
8922 : : final_mask, final_len, bias,
8923 : : vec_array);
8924 : : }
8925 : 0 : else if (final_mask)
8926 : : {
8927 : : /* Emit:
8928 : : MASK_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
8929 : : VEC_ARRAY). */
8930 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
8931 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
8932 : 0 : call = gimple_build_call_internal (IFN_MASK_STORE_LANES, 4,
8933 : : dataref_ptr, alias_ptr,
8934 : : final_mask, vec_array);
8935 : : }
8936 : : else
8937 : : {
8938 : : /* Emit:
8939 : : MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY). */
8940 : 0 : data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
8941 : 0 : call = gimple_build_call_internal (IFN_STORE_LANES, 1, vec_array);
8942 : 0 : gimple_call_set_lhs (call, data_ref);
8943 : : }
8944 : 0 : gimple_call_set_nothrow (call, true);
8945 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
8946 : 0 : new_stmt = call;
8947 : :
8948 : : /* Record that VEC_ARRAY is now dead. */
8949 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
8950 : 0 : if (j == 0)
8951 : 0 : *vec_stmt = new_stmt;
8952 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
8953 : : }
8954 : :
8955 : 0 : if (costing_p)
8956 : : {
8957 : 0 : if (n_adjacent_stores > 0)
8958 : 0 : vect_get_store_cost (vinfo, stmt_info, n_adjacent_stores,
8959 : : alignment_support_scheme, misalignment,
8960 : : &inside_cost, cost_vec);
8961 : 0 : if (dump_enabled_p ())
8962 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
8963 : : "vect_model_store_cost: inside_cost = %d, "
8964 : : "prologue_cost = %d .\n",
8965 : : inside_cost, prologue_cost);
8966 : : }
8967 : :
8968 : 0 : return true;
8969 : : }
8970 : :
8971 : 1245655 : if (memory_access_type == VMAT_GATHER_SCATTER)
8972 : : {
8973 : 1379 : gcc_assert (!grouped_store);
8974 : 1379 : auto_vec<tree> vec_offsets;
8975 : 1379 : unsigned int inside_cost = 0, prologue_cost = 0;
8976 : 3059 : for (j = 0; j < ncopies; j++)
8977 : : {
8978 : 1680 : gimple *new_stmt;
8979 : 1680 : if (j == 0)
8980 : : {
8981 : 1379 : if (costing_p && vls_type == VLS_STORE_INVARIANT)
8982 : 138 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
8983 : : stmt_info, 0, vect_prologue);
8984 : 1241 : else if (!costing_p)
8985 : : {
8986 : : /* Since the store is not grouped, DR_GROUP_SIZE is 1, and
8987 : : DR_CHAIN is of size 1. */
8988 : 474 : gcc_assert (group_size == 1);
8989 : 474 : if (slp_node)
8990 : 0 : vect_get_slp_defs (op_node, gvec_oprnds[0]);
8991 : : else
8992 : 474 : vect_get_vec_defs_for_operand (vinfo, first_stmt_info,
8993 : 474 : ncopies, op, gvec_oprnds[0]);
8994 : 474 : if (mask)
8995 : : {
8996 : 74 : if (slp_node)
8997 : 0 : vect_get_slp_defs (mask_node, &vec_masks);
8998 : : else
8999 : 74 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
9000 : : ncopies,
9001 : : mask, &vec_masks,
9002 : : mask_vectype);
9003 : : }
9004 : :
9005 : 474 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
9006 : 474 : vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info,
9007 : : slp_node, &gs_info,
9008 : : &dataref_ptr, &vec_offsets);
9009 : : else
9010 : 0 : dataref_ptr
9011 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info,
9012 : : aggr_type, NULL, offset,
9013 : : &dummy, gsi, &ptr_incr, false,
9014 : : bump);
9015 : : }
9016 : : }
9017 : 301 : else if (!costing_p)
9018 : : {
9019 : 51 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
9020 : 51 : if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info))
9021 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
9022 : : gsi, stmt_info, bump);
9023 : : }
9024 : :
9025 : 1680 : new_stmt = NULL;
9026 : 3360 : for (i = 0; i < vec_num; ++i)
9027 : : {
9028 : 1680 : if (!costing_p)
9029 : : {
9030 : 525 : vec_oprnd = (*gvec_oprnds[0])[vec_num * j + i];
9031 : 525 : if (mask)
9032 : 96 : vec_mask = vec_masks[vec_num * j + i];
9033 : : /* We should have catched mismatched types earlier. */
9034 : 525 : gcc_assert (useless_type_conversion_p (vectype,
9035 : : TREE_TYPE (vec_oprnd)));
9036 : : }
9037 : 1680 : unsigned HOST_WIDE_INT align;
9038 : 1680 : tree final_mask = NULL_TREE;
9039 : 1680 : tree final_len = NULL_TREE;
9040 : 1680 : tree bias = NULL_TREE;
9041 : 1680 : if (!costing_p)
9042 : : {
9043 : 525 : if (loop_masks)
9044 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi,
9045 : : loop_masks, ncopies,
9046 : : vectype, j);
9047 : 525 : if (vec_mask)
9048 : 96 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
9049 : : final_mask, vec_mask, gsi);
9050 : : }
9051 : :
9052 : 1680 : if (gs_info.ifn != IFN_LAST)
9053 : : {
9054 : 0 : if (costing_p)
9055 : : {
9056 : 0 : unsigned int cnunits = vect_nunits_for_cost (vectype);
9057 : 0 : inside_cost
9058 : 0 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
9059 : : stmt_info, 0, vect_body);
9060 : 0 : continue;
9061 : 0 : }
9062 : :
9063 : 0 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
9064 : 0 : vec_offset = vec_offsets[vec_num * j + i];
9065 : 0 : tree scale = size_int (gs_info.scale);
9066 : :
9067 : 0 : if (gs_info.ifn == IFN_MASK_LEN_SCATTER_STORE)
9068 : : {
9069 : 0 : if (loop_lens)
9070 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi,
9071 : : loop_lens, ncopies,
9072 : : vectype, j, 1);
9073 : : else
9074 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
9075 : 0 : signed char biasval
9076 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
9077 : 0 : bias = build_int_cst (intQI_type_node, biasval);
9078 : 0 : if (!final_mask)
9079 : : {
9080 : 0 : mask_vectype = truth_type_for (vectype);
9081 : 0 : final_mask = build_minus_one_cst (mask_vectype);
9082 : : }
9083 : : }
9084 : :
9085 : 0 : gcall *call;
9086 : 0 : if (final_len && final_mask)
9087 : 0 : call = gimple_build_call_internal
9088 : 0 : (IFN_MASK_LEN_SCATTER_STORE, 7, dataref_ptr,
9089 : : vec_offset, scale, vec_oprnd, final_mask,
9090 : : final_len, bias);
9091 : 0 : else if (final_mask)
9092 : 0 : call = gimple_build_call_internal
9093 : 0 : (IFN_MASK_SCATTER_STORE, 5, dataref_ptr,
9094 : : vec_offset, scale, vec_oprnd, final_mask);
9095 : : else
9096 : 0 : call = gimple_build_call_internal (IFN_SCATTER_STORE, 4,
9097 : : dataref_ptr, vec_offset,
9098 : : scale, vec_oprnd);
9099 : 0 : gimple_call_set_nothrow (call, true);
9100 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9101 : 0 : new_stmt = call;
9102 : : }
9103 : 1680 : else if (gs_info.decl)
9104 : : {
9105 : : /* The builtin decls path for scatter is legacy, x86 only. */
9106 : 406 : gcc_assert (nunits.is_constant ()
9107 : : && (!final_mask
9108 : : || SCALAR_INT_MODE_P
9109 : : (TYPE_MODE (TREE_TYPE (final_mask)))));
9110 : 406 : if (costing_p)
9111 : : {
9112 : 249 : unsigned int cnunits = vect_nunits_for_cost (vectype);
9113 : 249 : inside_cost
9114 : 249 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
9115 : : stmt_info, 0, vect_body);
9116 : 249 : continue;
9117 : 249 : }
9118 : 157 : poly_uint64 offset_nunits
9119 : 157 : = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype);
9120 : 157 : if (known_eq (nunits, offset_nunits))
9121 : : {
9122 : 162 : new_stmt = vect_build_one_scatter_store_call
9123 : 162 : (vinfo, stmt_info, gsi, &gs_info,
9124 : 81 : dataref_ptr, vec_offsets[vec_num * j + i],
9125 : : vec_oprnd, final_mask);
9126 : 81 : vect_finish_stmt_generation (vinfo, stmt_info,
9127 : : new_stmt, gsi);
9128 : : }
9129 : 76 : else if (known_eq (nunits, offset_nunits * 2))
9130 : : {
9131 : : /* We have a offset vector with half the number of
9132 : : lanes but the builtins will store full vectype
9133 : : data from the lower lanes. */
9134 : 30 : new_stmt = vect_build_one_scatter_store_call
9135 : 60 : (vinfo, stmt_info, gsi, &gs_info,
9136 : : dataref_ptr,
9137 : 30 : vec_offsets[2 * vec_num * j + 2 * i],
9138 : : vec_oprnd, final_mask);
9139 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
9140 : : new_stmt, gsi);
9141 : 30 : int count = nunits.to_constant ();
9142 : 30 : vec_perm_builder sel (count, count, 1);
9143 : 30 : sel.quick_grow (count);
9144 : 382 : for (int i = 0; i < count; ++i)
9145 : 352 : sel[i] = i | (count / 2);
9146 : 30 : vec_perm_indices indices (sel, 2, count);
9147 : 30 : tree perm_mask
9148 : 30 : = vect_gen_perm_mask_checked (vectype, indices);
9149 : 30 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
9150 : : vec_oprnd, vec_oprnd,
9151 : : perm_mask);
9152 : 30 : vec_oprnd = make_ssa_name (vectype);
9153 : 30 : gimple_set_lhs (new_stmt, vec_oprnd);
9154 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
9155 : : new_stmt, gsi);
9156 : 30 : if (final_mask)
9157 : : {
9158 : 20 : new_stmt = gimple_build_assign (NULL_TREE,
9159 : : VEC_UNPACK_HI_EXPR,
9160 : : final_mask);
9161 : 20 : final_mask = make_ssa_name
9162 : 20 : (truth_type_for (gs_info.offset_vectype));
9163 : 20 : gimple_set_lhs (new_stmt, final_mask);
9164 : 20 : vect_finish_stmt_generation (vinfo, stmt_info,
9165 : : new_stmt, gsi);
9166 : : }
9167 : 60 : new_stmt = vect_build_one_scatter_store_call
9168 : 30 : (vinfo, stmt_info, gsi, &gs_info,
9169 : : dataref_ptr,
9170 : 30 : vec_offsets[2 * vec_num * j + 2 * i + 1],
9171 : : vec_oprnd, final_mask);
9172 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
9173 : : new_stmt, gsi);
9174 : 30 : }
9175 : 46 : else if (known_eq (nunits * 2, offset_nunits))
9176 : : {
9177 : : /* We have a offset vector with double the number of
9178 : : lanes. Select the low/high part accordingly. */
9179 : 46 : vec_offset = vec_offsets[(vec_num * j + i) / 2];
9180 : 46 : if ((vec_num * j + i) & 1)
9181 : : {
9182 : 23 : int count = offset_nunits.to_constant ();
9183 : 23 : vec_perm_builder sel (count, count, 1);
9184 : 23 : sel.quick_grow (count);
9185 : 263 : for (int i = 0; i < count; ++i)
9186 : 240 : sel[i] = i | (count / 2);
9187 : 23 : vec_perm_indices indices (sel, 2, count);
9188 : 23 : tree perm_mask = vect_gen_perm_mask_checked
9189 : 23 : (TREE_TYPE (vec_offset), indices);
9190 : 23 : new_stmt = gimple_build_assign (NULL_TREE,
9191 : : VEC_PERM_EXPR,
9192 : : vec_offset,
9193 : : vec_offset,
9194 : : perm_mask);
9195 : 23 : vec_offset = make_ssa_name (TREE_TYPE (vec_offset));
9196 : 23 : gimple_set_lhs (new_stmt, vec_offset);
9197 : 23 : vect_finish_stmt_generation (vinfo, stmt_info,
9198 : : new_stmt, gsi);
9199 : 23 : }
9200 : 92 : new_stmt = vect_build_one_scatter_store_call
9201 : 46 : (vinfo, stmt_info, gsi, &gs_info,
9202 : : dataref_ptr, vec_offset,
9203 : : vec_oprnd, final_mask);
9204 : 46 : vect_finish_stmt_generation (vinfo, stmt_info,
9205 : : new_stmt, gsi);
9206 : : }
9207 : : else
9208 : 0 : gcc_unreachable ();
9209 : : }
9210 : : else
9211 : : {
9212 : : /* Emulated scatter. */
9213 : 1274 : gcc_assert (!final_mask);
9214 : 1274 : if (costing_p)
9215 : : {
9216 : 906 : unsigned int cnunits = vect_nunits_for_cost (vectype);
9217 : : /* For emulated scatter N offset vector element extracts
9218 : : (we assume the scalar scaling and ptr + offset add is
9219 : : consumed by the load). */
9220 : 906 : inside_cost
9221 : 906 : += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
9222 : : stmt_info, 0, vect_body);
9223 : : /* N scalar stores plus extracting the elements. */
9224 : 906 : inside_cost
9225 : 906 : += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
9226 : : stmt_info, 0, vect_body);
9227 : 906 : inside_cost
9228 : 906 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
9229 : : stmt_info, 0, vect_body);
9230 : 906 : continue;
9231 : 906 : }
9232 : :
9233 : 368 : unsigned HOST_WIDE_INT const_nunits = nunits.to_constant ();
9234 : 368 : unsigned HOST_WIDE_INT const_offset_nunits
9235 : 368 : = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype).to_constant ();
9236 : 368 : vec<constructor_elt, va_gc> *ctor_elts;
9237 : 368 : vec_alloc (ctor_elts, const_nunits);
9238 : 368 : gimple_seq stmts = NULL;
9239 : 368 : tree elt_type = TREE_TYPE (vectype);
9240 : 368 : unsigned HOST_WIDE_INT elt_size
9241 : 368 : = tree_to_uhwi (TYPE_SIZE (elt_type));
9242 : : /* We support offset vectors with more elements
9243 : : than the data vector for now. */
9244 : 368 : unsigned HOST_WIDE_INT factor
9245 : : = const_offset_nunits / const_nunits;
9246 : 368 : vec_offset = vec_offsets[(vec_num * j + i) / factor];
9247 : 368 : unsigned elt_offset
9248 : 368 : = ((vec_num * j + i) % factor) * const_nunits;
9249 : 368 : tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset));
9250 : 368 : tree scale = size_int (gs_info.scale);
9251 : 368 : align = get_object_alignment (DR_REF (first_dr_info->dr));
9252 : 368 : tree ltype = build_aligned_type (TREE_TYPE (vectype), align);
9253 : 1498 : for (unsigned k = 0; k < const_nunits; ++k)
9254 : : {
9255 : : /* Compute the offsetted pointer. */
9256 : 1130 : tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type),
9257 : : bitsize_int (k + elt_offset));
9258 : 1130 : tree idx
9259 : 1130 : = gimple_build (&stmts, BIT_FIELD_REF, idx_type,
9260 : 1130 : vec_offset, TYPE_SIZE (idx_type), boff);
9261 : 1130 : idx = gimple_convert (&stmts, sizetype, idx);
9262 : 1130 : idx = gimple_build (&stmts, MULT_EXPR, sizetype,
9263 : : idx, scale);
9264 : 1130 : tree ptr
9265 : 1130 : = gimple_build (&stmts, PLUS_EXPR,
9266 : 1130 : TREE_TYPE (dataref_ptr),
9267 : : dataref_ptr, idx);
9268 : 1130 : ptr = gimple_convert (&stmts, ptr_type_node, ptr);
9269 : : /* Extract the element to be stored. */
9270 : 1130 : tree elt
9271 : 2260 : = gimple_build (&stmts, BIT_FIELD_REF,
9272 : 1130 : TREE_TYPE (vectype),
9273 : 1130 : vec_oprnd, TYPE_SIZE (elt_type),
9274 : 1130 : bitsize_int (k * elt_size));
9275 : 1130 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
9276 : 1130 : stmts = NULL;
9277 : 1130 : tree ref
9278 : 1130 : = build2 (MEM_REF, ltype, ptr,
9279 : 1130 : build_int_cst (ref_type, 0));
9280 : 1130 : new_stmt = gimple_build_assign (ref, elt);
9281 : 1130 : vect_finish_stmt_generation (vinfo, stmt_info,
9282 : : new_stmt, gsi);
9283 : : }
9284 : 368 : if (slp)
9285 : 0 : slp_node->push_vec_def (new_stmt);
9286 : : }
9287 : : }
9288 : 1680 : if (!slp && !costing_p)
9289 : 525 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
9290 : : }
9291 : :
9292 : 1379 : if (!slp && !costing_p)
9293 : 474 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
9294 : :
9295 : 1379 : if (costing_p && dump_enabled_p ())
9296 : 96 : dump_printf_loc (MSG_NOTE, vect_location,
9297 : : "vect_model_store_cost: inside_cost = %d, "
9298 : : "prologue_cost = %d .\n",
9299 : : inside_cost, prologue_cost);
9300 : :
9301 : 1379 : return true;
9302 : 1379 : }
9303 : :
9304 : 1244276 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS
9305 : : || memory_access_type == VMAT_CONTIGUOUS_DOWN
9306 : : || memory_access_type == VMAT_CONTIGUOUS_PERMUTE
9307 : : || memory_access_type == VMAT_CONTIGUOUS_REVERSE);
9308 : :
9309 : 1244276 : unsigned inside_cost = 0, prologue_cost = 0;
9310 : : /* For costing some adjacent vector stores, we'd like to cost with
9311 : : the total number of them once instead of cost each one by one. */
9312 : 1244276 : unsigned int n_adjacent_stores = 0;
9313 : 1244276 : auto_vec<tree> result_chain (group_size);
9314 : 1244276 : auto_vec<tree, 1> vec_oprnds;
9315 : 2502995 : for (j = 0; j < ncopies; j++)
9316 : : {
9317 : 1258719 : gimple *new_stmt;
9318 : 1258719 : if (j == 0)
9319 : : {
9320 : 1244276 : if (slp && !costing_p)
9321 : : {
9322 : : /* Get vectorized arguments for SLP_NODE. */
9323 : 506280 : vect_get_vec_defs (vinfo, stmt_info, slp_node, 1, op,
9324 : : &vec_oprnds, mask, &vec_masks);
9325 : 506280 : vec_oprnd = vec_oprnds[0];
9326 : 506280 : if (mask)
9327 : 6 : vec_mask = vec_masks[0];
9328 : : }
9329 : : else
9330 : : {
9331 : : /* For interleaved stores we collect vectorized defs for all the
9332 : : stores in the group in DR_CHAIN. DR_CHAIN is then used as an
9333 : : input to vect_permute_store_chain().
9334 : :
9335 : : If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN
9336 : : is of size 1. */
9337 : : stmt_vec_info next_stmt_info = first_stmt_info;
9338 : 2486001 : for (i = 0; i < group_size; i++)
9339 : : {
9340 : : /* Since gaps are not supported for interleaved stores,
9341 : : DR_GROUP_SIZE is the exact number of stmts in the chain.
9342 : : Therefore, NEXT_STMT_INFO can't be NULL_TREE. In case
9343 : : that there is no interleaving, DR_GROUP_SIZE is 1,
9344 : : and only one iteration of the loop will be executed. */
9345 : 1748005 : op = vect_get_store_rhs (next_stmt_info);
9346 : 1748005 : if (costing_p)
9347 : 1705361 : update_prologue_cost (&prologue_cost, op);
9348 : : else
9349 : : {
9350 : 85288 : vect_get_vec_defs_for_operand (vinfo, next_stmt_info,
9351 : : ncopies, op,
9352 : 42644 : gvec_oprnds[i]);
9353 : 42644 : vec_oprnd = (*gvec_oprnds[i])[0];
9354 : 42644 : dr_chain.quick_push (vec_oprnd);
9355 : : }
9356 : 1748005 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
9357 : : }
9358 : 737996 : if (mask && !costing_p)
9359 : : {
9360 : 1058 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
9361 : : mask, &vec_masks,
9362 : : mask_vectype);
9363 : 1058 : vec_mask = vec_masks[0];
9364 : : }
9365 : : }
9366 : :
9367 : : /* We should have catched mismatched types earlier. */
9368 : 1244276 : gcc_assert (costing_p
9369 : : || useless_type_conversion_p (vectype,
9370 : : TREE_TYPE (vec_oprnd)));
9371 : 1244276 : bool simd_lane_access_p
9372 : 1244276 : = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0;
9373 : 1244276 : if (!costing_p
9374 : : && simd_lane_access_p
9375 : 547573 : && !loop_masks
9376 : 4416 : && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR
9377 : 4416 : && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0))
9378 : 4416 : && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info))
9379 : 4416 : && integer_zerop (DR_INIT (first_dr_info->dr))
9380 : 1248692 : && alias_sets_conflict_p (get_alias_set (aggr_type),
9381 : 4416 : get_alias_set (TREE_TYPE (ref_type))))
9382 : : {
9383 : 4408 : dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr));
9384 : 4408 : dataref_offset = build_int_cst (ref_type, 0);
9385 : : }
9386 : 1239868 : else if (!costing_p)
9387 : 543165 : dataref_ptr
9388 : 1086322 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
9389 : : simd_lane_access_p ? loop : NULL,
9390 : : offset, &dummy, gsi, &ptr_incr,
9391 : : simd_lane_access_p, bump);
9392 : : }
9393 : 14443 : else if (!costing_p)
9394 : : {
9395 : 5345 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
9396 : : /* DR_CHAIN is then used as an input to vect_permute_store_chain().
9397 : : If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN is
9398 : : of size 1. */
9399 : 10762 : for (i = 0; i < group_size; i++)
9400 : : {
9401 : 5417 : vec_oprnd = (*gvec_oprnds[i])[j];
9402 : 5417 : dr_chain[i] = vec_oprnd;
9403 : : }
9404 : 5345 : if (mask)
9405 : 70 : vec_mask = vec_masks[j];
9406 : 5345 : if (dataref_offset)
9407 : 1004 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
9408 : : else
9409 : 4341 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
9410 : : stmt_info, bump);
9411 : : }
9412 : :
9413 : 1258719 : new_stmt = NULL;
9414 : 1258719 : if (grouped_store)
9415 : : {
9416 : : /* Permute. */
9417 : 2744 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS_PERMUTE);
9418 : 2744 : if (costing_p)
9419 : : {
9420 : 1957 : int group_size = DR_GROUP_SIZE (first_stmt_info);
9421 : 1957 : int nstmts = ceil_log2 (group_size) * group_size;
9422 : 1957 : inside_cost += record_stmt_cost (cost_vec, nstmts, vec_perm,
9423 : : stmt_info, 0, vect_body);
9424 : 1957 : if (dump_enabled_p ())
9425 : 587 : dump_printf_loc (MSG_NOTE, vect_location,
9426 : : "vect_model_store_cost: "
9427 : : "strided group_size = %d .\n",
9428 : : group_size);
9429 : : }
9430 : : else
9431 : 787 : vect_permute_store_chain (vinfo, dr_chain, group_size, stmt_info,
9432 : : gsi, &result_chain);
9433 : : }
9434 : :
9435 : : stmt_vec_info next_stmt_info = first_stmt_info;
9436 : 2644276 : for (i = 0; i < vec_num; i++)
9437 : : {
9438 : 1519157 : if (!costing_p)
9439 : : {
9440 : 655422 : if (slp)
9441 : 607361 : vec_oprnd = vec_oprnds[i];
9442 : 48061 : else if (grouped_store)
9443 : : /* For grouped stores vectorized defs are interleaved in
9444 : : vect_permute_store_chain(). */
9445 : 2210 : vec_oprnd = result_chain[i];
9446 : : }
9447 : :
9448 : 1519157 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
9449 : : {
9450 : 3191 : if (costing_p)
9451 : 2126 : inside_cost += record_stmt_cost (cost_vec, 1, vec_perm,
9452 : : stmt_info, 0, vect_body);
9453 : : else
9454 : : {
9455 : 1065 : tree perm_mask = perm_mask_for_reverse (vectype);
9456 : 1065 : tree perm_dest = vect_create_destination_var (
9457 : : vect_get_store_rhs (stmt_info), vectype);
9458 : 1065 : tree new_temp = make_ssa_name (perm_dest);
9459 : :
9460 : : /* Generate the permute statement. */
9461 : 1065 : gimple *perm_stmt
9462 : 1065 : = gimple_build_assign (new_temp, VEC_PERM_EXPR, vec_oprnd,
9463 : : vec_oprnd, perm_mask);
9464 : 1065 : vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt,
9465 : : gsi);
9466 : :
9467 : 1065 : perm_stmt = SSA_NAME_DEF_STMT (new_temp);
9468 : 1065 : vec_oprnd = new_temp;
9469 : : }
9470 : : }
9471 : :
9472 : 1519157 : if (costing_p)
9473 : : {
9474 : 863735 : n_adjacent_stores++;
9475 : :
9476 : 863735 : if (!slp)
9477 : : {
9478 : 90357 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
9479 : 90357 : if (!next_stmt_info)
9480 : : break;
9481 : : }
9482 : :
9483 : 1384134 : continue;
9484 : : }
9485 : :
9486 : 655422 : tree final_mask = NULL_TREE;
9487 : 655422 : tree final_len = NULL_TREE;
9488 : 655422 : tree bias = NULL_TREE;
9489 : 655422 : if (loop_masks)
9490 : 6 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
9491 : : vec_num * ncopies, vectype,
9492 : 6 : vec_num * j + i);
9493 : 655422 : if (slp && vec_mask)
9494 : 6 : vec_mask = vec_masks[i];
9495 : 48067 : if (vec_mask)
9496 : 1134 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
9497 : : vec_mask, gsi);
9498 : :
9499 : 655422 : if (i > 0)
9500 : : /* Bump the vector pointer. */
9501 : 102504 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
9502 : : stmt_info, bump);
9503 : :
9504 : 655422 : unsigned misalign;
9505 : 655422 : unsigned HOST_WIDE_INT align;
9506 : 655422 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
9507 : 655422 : if (alignment_support_scheme == dr_aligned)
9508 : : misalign = 0;
9509 : 308558 : else if (misalignment == DR_MISALIGNMENT_UNKNOWN)
9510 : : {
9511 : 157942 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
9512 : 157942 : misalign = 0;
9513 : : }
9514 : : else
9515 : 150616 : misalign = misalignment;
9516 : 655422 : if (dataref_offset == NULL_TREE
9517 : 650010 : && TREE_CODE (dataref_ptr) == SSA_NAME)
9518 : 154259 : set_ptr_info_alignment (get_ptr_info (dataref_ptr), align,
9519 : : misalign);
9520 : 655422 : align = least_bit_hwi (misalign | align);
9521 : :
9522 : : /* Compute IFN when LOOP_LENS or final_mask valid. */
9523 : 655422 : machine_mode vmode = TYPE_MODE (vectype);
9524 : 655422 : machine_mode new_vmode = vmode;
9525 : 655422 : internal_fn partial_ifn = IFN_LAST;
9526 : 655422 : if (loop_lens)
9527 : : {
9528 : 0 : opt_machine_mode new_ovmode
9529 : 0 : = get_len_load_store_mode (vmode, false, &partial_ifn);
9530 : 0 : new_vmode = new_ovmode.require ();
9531 : 0 : unsigned factor
9532 : 0 : = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode);
9533 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
9534 : : vec_num * ncopies, vectype,
9535 : 0 : vec_num * j + i, factor);
9536 : : }
9537 : 655422 : else if (final_mask)
9538 : : {
9539 : 1140 : if (!can_vec_mask_load_store_p (
9540 : 1140 : vmode, TYPE_MODE (TREE_TYPE (final_mask)), false,
9541 : : &partial_ifn))
9542 : 0 : gcc_unreachable ();
9543 : : }
9544 : :
9545 : 655422 : if (partial_ifn == IFN_MASK_LEN_STORE)
9546 : : {
9547 : 0 : if (!final_len)
9548 : : {
9549 : : /* Pass VF value to 'len' argument of
9550 : : MASK_LEN_STORE if LOOP_LENS is invalid. */
9551 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
9552 : : }
9553 : 0 : if (!final_mask)
9554 : : {
9555 : : /* Pass all ones value to 'mask' argument of
9556 : : MASK_LEN_STORE if final_mask is invalid. */
9557 : 0 : mask_vectype = truth_type_for (vectype);
9558 : 0 : final_mask = build_minus_one_cst (mask_vectype);
9559 : : }
9560 : : }
9561 : 655422 : if (final_len)
9562 : : {
9563 : 0 : signed char biasval
9564 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
9565 : :
9566 : 0 : bias = build_int_cst (intQI_type_node, biasval);
9567 : : }
9568 : :
9569 : : /* Arguments are ready. Create the new vector stmt. */
9570 : 655422 : if (final_len)
9571 : : {
9572 : 0 : gcall *call;
9573 : 0 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
9574 : : /* Need conversion if it's wrapped with VnQI. */
9575 : 0 : if (vmode != new_vmode)
9576 : : {
9577 : 0 : tree new_vtype
9578 : 0 : = build_vector_type_for_mode (unsigned_intQI_type_node,
9579 : : new_vmode);
9580 : 0 : tree var = vect_get_new_ssa_name (new_vtype, vect_simple_var);
9581 : 0 : vec_oprnd = build1 (VIEW_CONVERT_EXPR, new_vtype, vec_oprnd);
9582 : 0 : gassign *new_stmt
9583 : 0 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, vec_oprnd);
9584 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
9585 : 0 : vec_oprnd = var;
9586 : : }
9587 : :
9588 : 0 : if (partial_ifn == IFN_MASK_LEN_STORE)
9589 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_STORE, 6,
9590 : : dataref_ptr, ptr, final_mask,
9591 : : final_len, bias, vec_oprnd);
9592 : : else
9593 : 0 : call = gimple_build_call_internal (IFN_LEN_STORE, 5,
9594 : : dataref_ptr, ptr, final_len,
9595 : : bias, vec_oprnd);
9596 : 0 : gimple_call_set_nothrow (call, true);
9597 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9598 : 0 : new_stmt = call;
9599 : : }
9600 : 655422 : else if (final_mask)
9601 : : {
9602 : 1140 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
9603 : 1140 : gcall *call
9604 : 1140 : = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr,
9605 : : ptr, final_mask, vec_oprnd);
9606 : 1140 : gimple_call_set_nothrow (call, true);
9607 : 1140 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9608 : 1140 : new_stmt = call;
9609 : : }
9610 : : else
9611 : : {
9612 : 654282 : data_ref
9613 : 654282 : = fold_build2 (MEM_REF, vectype, dataref_ptr,
9614 : : dataref_offset ? dataref_offset
9615 : : : build_int_cst (ref_type, 0));
9616 : 654282 : if (alignment_support_scheme == dr_aligned)
9617 : : ;
9618 : : else
9619 : 308196 : TREE_TYPE (data_ref)
9620 : 616392 : = build_aligned_type (TREE_TYPE (data_ref),
9621 : : align * BITS_PER_UNIT);
9622 : 654282 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
9623 : 654282 : new_stmt = gimple_build_assign (data_ref, vec_oprnd);
9624 : 654282 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
9625 : : }
9626 : :
9627 : 655422 : if (slp)
9628 : 607361 : continue;
9629 : :
9630 : 48061 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
9631 : 48061 : if (!next_stmt_info)
9632 : : break;
9633 : : }
9634 : 1258719 : if (!slp && !costing_p)
9635 : : {
9636 : 46638 : if (j == 0)
9637 : 41293 : *vec_stmt = new_stmt;
9638 : 46638 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
9639 : : }
9640 : : }
9641 : :
9642 : 1244276 : if (costing_p)
9643 : : {
9644 : 696703 : if (n_adjacent_stores > 0)
9645 : 696703 : vect_get_store_cost (vinfo, stmt_info, n_adjacent_stores,
9646 : : alignment_support_scheme, misalignment,
9647 : : &inside_cost, cost_vec);
9648 : :
9649 : : /* When vectorizing a store into the function result assign
9650 : : a penalty if the function returns in a multi-register location.
9651 : : In this case we assume we'll end up with having to spill the
9652 : : vector result and do piecewise loads as a conservative estimate. */
9653 : 696703 : tree base = get_base_address (STMT_VINFO_DATA_REF (stmt_info)->ref);
9654 : 696703 : if (base
9655 : 696703 : && (TREE_CODE (base) == RESULT_DECL
9656 : 634960 : || (DECL_P (base) && cfun_returns (base)))
9657 : 782237 : && !aggregate_value_p (base, cfun->decl))
9658 : : {
9659 : 23453 : rtx reg = hard_function_value (TREE_TYPE (base), cfun->decl, 0, 1);
9660 : : /* ??? Handle PARALLEL in some way. */
9661 : 23453 : if (REG_P (reg))
9662 : : {
9663 : 23224 : int nregs = hard_regno_nregs (REGNO (reg), GET_MODE (reg));
9664 : : /* Assume that a single reg-reg move is possible and cheap,
9665 : : do not account for vector to gp register move cost. */
9666 : 23224 : if (nregs > 1)
9667 : : {
9668 : : /* Spill. */
9669 : 22383 : prologue_cost
9670 : 22383 : += record_stmt_cost (cost_vec, ncopies, vector_store,
9671 : : stmt_info, 0, vect_epilogue);
9672 : : /* Loads. */
9673 : 22383 : prologue_cost
9674 : 22383 : += record_stmt_cost (cost_vec, ncopies * nregs, scalar_load,
9675 : : stmt_info, 0, vect_epilogue);
9676 : : }
9677 : : }
9678 : : }
9679 : 696703 : if (dump_enabled_p ())
9680 : 13933 : dump_printf_loc (MSG_NOTE, vect_location,
9681 : : "vect_model_store_cost: inside_cost = %d, "
9682 : : "prologue_cost = %d .\n",
9683 : : inside_cost, prologue_cost);
9684 : : }
9685 : :
9686 : 1244276 : return true;
9687 : 1245655 : }
9688 : :
9689 : : /* Given a vector type VECTYPE, turns permutation SEL into the equivalent
9690 : : VECTOR_CST mask. No checks are made that the target platform supports the
9691 : : mask, so callers may wish to test can_vec_perm_const_p separately, or use
9692 : : vect_gen_perm_mask_checked. */
9693 : :
9694 : : tree
9695 : 34500 : vect_gen_perm_mask_any (tree vectype, const vec_perm_indices &sel)
9696 : : {
9697 : 34500 : tree mask_type;
9698 : :
9699 : 34500 : poly_uint64 nunits = sel.length ();
9700 : 34500 : gcc_assert (known_eq (nunits, TYPE_VECTOR_SUBPARTS (vectype)));
9701 : :
9702 : 34500 : mask_type = build_vector_type (ssizetype, nunits);
9703 : 34500 : return vec_perm_indices_to_tree (mask_type, sel);
9704 : : }
9705 : :
9706 : : /* Checked version of vect_gen_perm_mask_any. Asserts can_vec_perm_const_p,
9707 : : i.e. that the target supports the pattern _for arbitrary input vectors_. */
9708 : :
9709 : : tree
9710 : 32181 : vect_gen_perm_mask_checked (tree vectype, const vec_perm_indices &sel)
9711 : : {
9712 : 32181 : machine_mode vmode = TYPE_MODE (vectype);
9713 : 32181 : gcc_assert (can_vec_perm_const_p (vmode, vmode, sel));
9714 : 32181 : return vect_gen_perm_mask_any (vectype, sel);
9715 : : }
9716 : :
9717 : : /* Given a vector variable X and Y, that was generated for the scalar
9718 : : STMT_INFO, generate instructions to permute the vector elements of X and Y
9719 : : using permutation mask MASK_VEC, insert them at *GSI and return the
9720 : : permuted vector variable. */
9721 : :
9722 : : static tree
9723 : 1284 : permute_vec_elements (vec_info *vinfo,
9724 : : tree x, tree y, tree mask_vec, stmt_vec_info stmt_info,
9725 : : gimple_stmt_iterator *gsi)
9726 : : {
9727 : 1284 : tree vectype = TREE_TYPE (x);
9728 : 1284 : tree perm_dest, data_ref;
9729 : 1284 : gimple *perm_stmt;
9730 : :
9731 : 1284 : tree scalar_dest = gimple_get_lhs (stmt_info->stmt);
9732 : 1284 : if (scalar_dest && TREE_CODE (scalar_dest) == SSA_NAME)
9733 : 1284 : perm_dest = vect_create_destination_var (scalar_dest, vectype);
9734 : : else
9735 : 0 : perm_dest = vect_get_new_vect_var (vectype, vect_simple_var, NULL);
9736 : 1284 : data_ref = make_ssa_name (perm_dest);
9737 : :
9738 : : /* Generate the permute statement. */
9739 : 1284 : perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, x, y, mask_vec);
9740 : 1284 : vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
9741 : :
9742 : 1284 : return data_ref;
9743 : : }
9744 : :
9745 : : /* Hoist the definitions of all SSA uses on STMT_INFO out of the loop LOOP,
9746 : : inserting them on the loops preheader edge. Returns true if we
9747 : : were successful in doing so (and thus STMT_INFO can be moved then),
9748 : : otherwise returns false. HOIST_P indicates if we want to hoist the
9749 : : definitions of all SSA uses, it would be false when we are costing. */
9750 : :
9751 : : static bool
9752 : 1886 : hoist_defs_of_uses (stmt_vec_info stmt_info, class loop *loop, bool hoist_p)
9753 : : {
9754 : 1886 : ssa_op_iter i;
9755 : 1886 : tree op;
9756 : 1886 : bool any = false;
9757 : :
9758 : 3412 : FOR_EACH_SSA_TREE_OPERAND (op, stmt_info->stmt, i, SSA_OP_USE)
9759 : : {
9760 : 1551 : gimple *def_stmt = SSA_NAME_DEF_STMT (op);
9761 : 1551 : if (!gimple_nop_p (def_stmt)
9762 : 1551 : && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)))
9763 : : {
9764 : : /* Make sure we don't need to recurse. While we could do
9765 : : so in simple cases when there are more complex use webs
9766 : : we don't have an easy way to preserve stmt order to fulfil
9767 : : dependencies within them. */
9768 : 49 : tree op2;
9769 : 49 : ssa_op_iter i2;
9770 : 49 : if (gimple_code (def_stmt) == GIMPLE_PHI)
9771 : 25 : return false;
9772 : 93 : FOR_EACH_SSA_TREE_OPERAND (op2, def_stmt, i2, SSA_OP_USE)
9773 : : {
9774 : 69 : gimple *def_stmt2 = SSA_NAME_DEF_STMT (op2);
9775 : 69 : if (!gimple_nop_p (def_stmt2)
9776 : 69 : && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt2)))
9777 : : return false;
9778 : : }
9779 : 24 : any = true;
9780 : : }
9781 : : }
9782 : :
9783 : 1861 : if (!any)
9784 : : return true;
9785 : :
9786 : 24 : if (!hoist_p)
9787 : : return true;
9788 : :
9789 : 22 : FOR_EACH_SSA_TREE_OPERAND (op, stmt_info->stmt, i, SSA_OP_USE)
9790 : : {
9791 : 13 : gimple *def_stmt = SSA_NAME_DEF_STMT (op);
9792 : 13 : if (!gimple_nop_p (def_stmt)
9793 : 13 : && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)))
9794 : : {
9795 : 9 : gimple_stmt_iterator gsi = gsi_for_stmt (def_stmt);
9796 : 9 : gsi_remove (&gsi, false);
9797 : 9 : gsi_insert_on_edge_immediate (loop_preheader_edge (loop), def_stmt);
9798 : : }
9799 : : }
9800 : :
9801 : : return true;
9802 : : }
9803 : :
9804 : : /* vectorizable_load.
9805 : :
9806 : : Check if STMT_INFO reads a non scalar data-ref (array/pointer/structure)
9807 : : that can be vectorized.
9808 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
9809 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
9810 : : Return true if STMT_INFO is vectorizable in this way. */
9811 : :
9812 : : static bool
9813 : 1485464 : vectorizable_load (vec_info *vinfo,
9814 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
9815 : : gimple **vec_stmt, slp_tree slp_node,
9816 : : stmt_vector_for_cost *cost_vec)
9817 : : {
9818 : 1485464 : tree scalar_dest;
9819 : 1485464 : tree vec_dest = NULL;
9820 : 1485464 : tree data_ref = NULL;
9821 : 1485464 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
9822 : 1485464 : class loop *loop = NULL;
9823 : 1485464 : class loop *containing_loop = gimple_bb (stmt_info->stmt)->loop_father;
9824 : 1485464 : bool nested_in_vect_loop = false;
9825 : 1485464 : tree elem_type;
9826 : : /* Avoid false positive uninitialized warning, see PR110652. */
9827 : 1485464 : tree new_temp = NULL_TREE;
9828 : 1485464 : machine_mode mode;
9829 : 1485464 : tree dummy;
9830 : 1485464 : tree dataref_ptr = NULL_TREE;
9831 : 1485464 : tree dataref_offset = NULL_TREE;
9832 : 1485464 : gimple *ptr_incr = NULL;
9833 : 1485464 : int ncopies;
9834 : 1485464 : int i, j;
9835 : 1485464 : unsigned int group_size;
9836 : 1485464 : poly_uint64 group_gap_adj;
9837 : 1485464 : tree msq = NULL_TREE, lsq;
9838 : 1485464 : tree realignment_token = NULL_TREE;
9839 : 1485464 : gphi *phi = NULL;
9840 : 1485464 : vec<tree> dr_chain = vNULL;
9841 : 1485464 : bool grouped_load = false;
9842 : 1485464 : stmt_vec_info first_stmt_info;
9843 : 1485464 : stmt_vec_info first_stmt_info_for_drptr = NULL;
9844 : 1485464 : bool compute_in_loop = false;
9845 : 1485464 : class loop *at_loop;
9846 : 1485464 : int vec_num;
9847 : 1485464 : bool slp = (slp_node != NULL);
9848 : 1485464 : bool slp_perm = false;
9849 : 1485464 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
9850 : 1485464 : poly_uint64 vf;
9851 : 1485464 : tree aggr_type;
9852 : 1485464 : gather_scatter_info gs_info;
9853 : 1485464 : tree ref_type;
9854 : 1485464 : enum vect_def_type mask_dt = vect_unknown_def_type;
9855 : :
9856 : 1485464 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
9857 : : return false;
9858 : :
9859 : 1485464 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
9860 : 24817 : && ! vec_stmt)
9861 : : return false;
9862 : :
9863 : 1460647 : if (!STMT_VINFO_DATA_REF (stmt_info))
9864 : : return false;
9865 : :
9866 : 1212802 : tree mask = NULL_TREE, mask_vectype = NULL_TREE;
9867 : 1212802 : int mask_index = -1;
9868 : 1212802 : slp_tree slp_op = NULL;
9869 : 1212802 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
9870 : : {
9871 : 1209048 : scalar_dest = gimple_assign_lhs (assign);
9872 : 1209048 : if (TREE_CODE (scalar_dest) != SSA_NAME)
9873 : : return false;
9874 : :
9875 : 486478 : tree_code code = gimple_assign_rhs_code (assign);
9876 : 486478 : if (code != ARRAY_REF
9877 : 486478 : && code != BIT_FIELD_REF
9878 : 486478 : && code != INDIRECT_REF
9879 : 365962 : && code != COMPONENT_REF
9880 : 365962 : && code != IMAGPART_EXPR
9881 : 165095 : && code != REALPART_EXPR
9882 : 165095 : && code != MEM_REF
9883 : 160 : && TREE_CODE_CLASS (code) != tcc_declaration)
9884 : : return false;
9885 : : }
9886 : : else
9887 : : {
9888 : 1010404 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
9889 : 3754 : if (!call || !gimple_call_internal_p (call))
9890 : : return false;
9891 : :
9892 : 3754 : internal_fn ifn = gimple_call_internal_fn (call);
9893 : 3754 : if (!internal_load_fn_p (ifn))
9894 : : return false;
9895 : :
9896 : 2078 : scalar_dest = gimple_call_lhs (call);
9897 : 2078 : if (!scalar_dest)
9898 : : return false;
9899 : :
9900 : 2078 : mask_index = internal_fn_mask_index (ifn);
9901 : 2078 : if (mask_index >= 0 && slp_node)
9902 : 9 : mask_index = vect_slp_child_index_for_operand
9903 : 9 : (call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
9904 : 2078 : if (mask_index >= 0
9905 : 2078 : && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index,
9906 : : &mask, &slp_op, &mask_dt, &mask_vectype))
9907 : : return false;
9908 : : }
9909 : :
9910 : 488556 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
9911 : 488556 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
9912 : :
9913 : 488556 : if (loop_vinfo)
9914 : : {
9915 : 241250 : loop = LOOP_VINFO_LOOP (loop_vinfo);
9916 : 241250 : nested_in_vect_loop = nested_in_vect_loop_p (loop, stmt_info);
9917 : 241250 : vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
9918 : : }
9919 : : else
9920 : : vf = 1;
9921 : :
9922 : : /* Multiple types in SLP are handled by creating the appropriate number of
9923 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
9924 : : case of SLP. */
9925 : 488556 : if (slp)
9926 : : ncopies = 1;
9927 : : else
9928 : 223051 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
9929 : :
9930 : 223051 : gcc_assert (ncopies >= 1);
9931 : :
9932 : : /* FORNOW. This restriction should be relaxed. */
9933 : 488556 : if (nested_in_vect_loop && ncopies > 1)
9934 : : {
9935 : 144 : if (dump_enabled_p ())
9936 : 30 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9937 : : "multiple types in nested loop.\n");
9938 : 144 : return false;
9939 : : }
9940 : :
9941 : : /* Invalidate assumptions made by dependence analysis when vectorization
9942 : : on the unrolled body effectively re-orders stmts. */
9943 : 488412 : if (ncopies > 1
9944 : 20801 : && STMT_VINFO_MIN_NEG_DIST (stmt_info) != 0
9945 : 488412 : && maybe_gt (LOOP_VINFO_VECT_FACTOR (loop_vinfo),
9946 : : STMT_VINFO_MIN_NEG_DIST (stmt_info)))
9947 : : {
9948 : 0 : if (dump_enabled_p ())
9949 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9950 : : "cannot perform implicit CSE when unrolling "
9951 : : "with negative dependence distance\n");
9952 : 0 : return false;
9953 : : }
9954 : :
9955 : 488412 : elem_type = TREE_TYPE (vectype);
9956 : 488412 : mode = TYPE_MODE (vectype);
9957 : :
9958 : : /* FORNOW. In some cases can vectorize even if data-type not supported
9959 : : (e.g. - data copies). */
9960 : 488412 : if (optab_handler (mov_optab, mode) == CODE_FOR_nothing)
9961 : : {
9962 : 0 : if (dump_enabled_p ())
9963 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9964 : : "Aligned load, but unsupported type.\n");
9965 : 0 : return false;
9966 : : }
9967 : :
9968 : : /* Check if the load is a part of an interleaving chain. */
9969 : 488412 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
9970 : : {
9971 : 304764 : grouped_load = true;
9972 : : /* FORNOW */
9973 : 304764 : gcc_assert (!nested_in_vect_loop);
9974 : 304764 : gcc_assert (!STMT_VINFO_GATHER_SCATTER_P (stmt_info));
9975 : :
9976 : 304764 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
9977 : 304764 : group_size = DR_GROUP_SIZE (first_stmt_info);
9978 : :
9979 : : /* Refuse non-SLP vectorization of SLP-only groups. */
9980 : 304764 : if (!slp && STMT_VINFO_SLP_VECT_ONLY (first_stmt_info))
9981 : : {
9982 : 0 : if (dump_enabled_p ())
9983 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9984 : : "cannot vectorize load in non-SLP mode.\n");
9985 : 0 : return false;
9986 : : }
9987 : :
9988 : : /* Invalidate assumptions made by dependence analysis when vectorization
9989 : : on the unrolled body effectively re-orders stmts. */
9990 : 304764 : if (!PURE_SLP_STMT (stmt_info)
9991 : 40446 : && STMT_VINFO_MIN_NEG_DIST (stmt_info) != 0
9992 : 304770 : && maybe_gt (LOOP_VINFO_VECT_FACTOR (loop_vinfo),
9993 : : STMT_VINFO_MIN_NEG_DIST (stmt_info)))
9994 : : {
9995 : 6 : if (dump_enabled_p ())
9996 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9997 : : "cannot perform implicit CSE when performing "
9998 : : "group loads with negative dependence distance\n");
9999 : 6 : return false;
10000 : : }
10001 : : }
10002 : : else
10003 : : group_size = 1;
10004 : :
10005 : 488406 : if (slp && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
10006 : : {
10007 : 35718 : slp_perm = true;
10008 : :
10009 : 35718 : if (!loop_vinfo)
10010 : : {
10011 : : /* In BB vectorization we may not actually use a loaded vector
10012 : : accessing elements in excess of DR_GROUP_SIZE. */
10013 : 28310 : stmt_vec_info group_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
10014 : 28310 : group_info = DR_GROUP_FIRST_ELEMENT (group_info);
10015 : 28310 : unsigned HOST_WIDE_INT nunits;
10016 : 28310 : unsigned j, k, maxk = 0;
10017 : 102703 : FOR_EACH_VEC_ELT (SLP_TREE_LOAD_PERMUTATION (slp_node), j, k)
10018 : 74393 : if (k > maxk)
10019 : : maxk = k;
10020 : 28310 : tree vectype = SLP_TREE_VECTYPE (slp_node);
10021 : 52081 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits)
10022 : 28310 : || maxk >= (DR_GROUP_SIZE (group_info) & ~(nunits - 1)))
10023 : : {
10024 : 4539 : if (dump_enabled_p ())
10025 : 29 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10026 : : "BB vectorization with gaps at the end of "
10027 : : "a load is not supported\n");
10028 : 4539 : return false;
10029 : : }
10030 : : }
10031 : :
10032 : 31179 : auto_vec<tree> tem;
10033 : 31179 : unsigned n_perms;
10034 : 31179 : if (!vect_transform_slp_perm_load (vinfo, slp_node, tem, NULL, vf,
10035 : : true, &n_perms))
10036 : : {
10037 : 1934 : if (dump_enabled_p ())
10038 : 272 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
10039 : : vect_location,
10040 : : "unsupported load permutation\n");
10041 : 1934 : return false;
10042 : : }
10043 : 31179 : }
10044 : :
10045 : 481933 : vect_memory_access_type memory_access_type;
10046 : 481933 : enum dr_alignment_support alignment_support_scheme;
10047 : 481933 : int misalignment;
10048 : 481933 : poly_int64 poffset;
10049 : 481933 : internal_fn lanes_ifn;
10050 : 481933 : if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, VLS_LOAD,
10051 : : ncopies, &memory_access_type, &poffset,
10052 : : &alignment_support_scheme, &misalignment, &gs_info,
10053 : : &lanes_ifn))
10054 : : return false;
10055 : :
10056 : 479105 : if (mask)
10057 : : {
10058 : 1981 : if (memory_access_type == VMAT_CONTIGUOUS)
10059 : : {
10060 : 1411 : machine_mode vec_mode = TYPE_MODE (vectype);
10061 : 326 : if (!VECTOR_MODE_P (vec_mode)
10062 : 2822 : || !can_vec_mask_load_store_p (vec_mode,
10063 : 1411 : TYPE_MODE (mask_vectype), true))
10064 : 25 : return false;
10065 : : }
10066 : 570 : else if (memory_access_type != VMAT_LOAD_STORE_LANES
10067 : 570 : && memory_access_type != VMAT_GATHER_SCATTER)
10068 : : {
10069 : 33 : if (dump_enabled_p ())
10070 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10071 : : "unsupported access type for masked load.\n");
10072 : 33 : return false;
10073 : : }
10074 : 537 : else if (memory_access_type == VMAT_GATHER_SCATTER
10075 : 537 : && gs_info.ifn == IFN_LAST
10076 : 537 : && !gs_info.decl)
10077 : : {
10078 : 233 : if (dump_enabled_p ())
10079 : 13 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10080 : : "unsupported masked emulated gather.\n");
10081 : 233 : return false;
10082 : : }
10083 : : else if (memory_access_type == VMAT_ELEMENTWISE
10084 : : || memory_access_type == VMAT_STRIDED_SLP)
10085 : : {
10086 : : if (dump_enabled_p ())
10087 : : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10088 : : "unsupported masked strided access.\n");
10089 : : return false;
10090 : : }
10091 : : }
10092 : :
10093 : 478814 : bool costing_p = !vec_stmt;
10094 : :
10095 : 478814 : if (costing_p) /* transformation not required. */
10096 : : {
10097 : 316941 : if (slp_node
10098 : 153943 : && mask
10099 : 316944 : && !vect_maybe_update_slp_op_vectype (slp_op,
10100 : : mask_vectype))
10101 : : {
10102 : 0 : if (dump_enabled_p ())
10103 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10104 : : "incompatible vector types for invariants\n");
10105 : 0 : return false;
10106 : : }
10107 : :
10108 : 316941 : if (!slp)
10109 : 162998 : STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info) = memory_access_type;
10110 : :
10111 : 316941 : if (loop_vinfo
10112 : 173820 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
10113 : 31 : check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
10114 : : VLS_LOAD, group_size,
10115 : : memory_access_type, &gs_info,
10116 : : mask);
10117 : :
10118 : 316941 : if (dump_enabled_p ()
10119 : 24073 : && memory_access_type != VMAT_ELEMENTWISE
10120 : 23627 : && memory_access_type != VMAT_GATHER_SCATTER
10121 : 340299 : && alignment_support_scheme != dr_aligned)
10122 : 11617 : dump_printf_loc (MSG_NOTE, vect_location,
10123 : : "Vectorizing an unaligned access.\n");
10124 : :
10125 : 316941 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
10126 : 0 : vinfo->any_known_not_updated_vssa = true;
10127 : :
10128 : 316941 : STMT_VINFO_TYPE (stmt_info) = load_vec_info_type;
10129 : : }
10130 : :
10131 : 478814 : if (!slp)
10132 : 219861 : gcc_assert (memory_access_type
10133 : : == STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info));
10134 : :
10135 : 478814 : if (dump_enabled_p () && !costing_p)
10136 : 15304 : dump_printf_loc (MSG_NOTE, vect_location,
10137 : : "transform load. ncopies = %d\n", ncopies);
10138 : :
10139 : : /* Transform. */
10140 : :
10141 : 478814 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL;
10142 : 478814 : ensure_base_align (dr_info);
10143 : :
10144 : 478814 : if (memory_access_type == VMAT_INVARIANT)
10145 : : {
10146 : 2329 : gcc_assert (!grouped_load && !mask && !bb_vinfo);
10147 : : /* If we have versioned for aliasing or the loop doesn't
10148 : : have any data dependencies that would preclude this,
10149 : : then we are sure this is a loop invariant load and
10150 : : thus we can insert it on the preheader edge.
10151 : : TODO: hoist_defs_of_uses should ideally be computed
10152 : : once at analysis time, remembered and used in the
10153 : : transform time. */
10154 : 2329 : bool hoist_p = (LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo)
10155 : 2193 : && !nested_in_vect_loop
10156 : 4215 : && hoist_defs_of_uses (stmt_info, loop, !costing_p));
10157 : 2329 : if (costing_p)
10158 : : {
10159 : 3160 : enum vect_cost_model_location cost_loc
10160 : 1580 : = hoist_p ? vect_prologue : vect_body;
10161 : 1580 : unsigned int cost = record_stmt_cost (cost_vec, 1, scalar_load,
10162 : : stmt_info, 0, cost_loc);
10163 : 1580 : cost += record_stmt_cost (cost_vec, 1, scalar_to_vec, stmt_info, 0,
10164 : : cost_loc);
10165 : 1580 : unsigned int prologue_cost = hoist_p ? cost : 0;
10166 : 276 : unsigned int inside_cost = hoist_p ? 0 : cost;
10167 : 1580 : if (dump_enabled_p ())
10168 : 401 : dump_printf_loc (MSG_NOTE, vect_location,
10169 : : "vect_model_load_cost: inside_cost = %d, "
10170 : : "prologue_cost = %d .\n",
10171 : : inside_cost, prologue_cost);
10172 : 1580 : return true;
10173 : : }
10174 : 749 : if (hoist_p)
10175 : : {
10176 : 557 : gassign *stmt = as_a <gassign *> (stmt_info->stmt);
10177 : 557 : if (dump_enabled_p ())
10178 : 158 : dump_printf_loc (MSG_NOTE, vect_location,
10179 : : "hoisting out of the vectorized loop: %G",
10180 : : (gimple *) stmt);
10181 : 557 : scalar_dest = copy_ssa_name (scalar_dest);
10182 : 557 : tree rhs = unshare_expr (gimple_assign_rhs1 (stmt));
10183 : 557 : edge pe = loop_preheader_edge (loop);
10184 : 557 : gphi *vphi = get_virtual_phi (loop->header);
10185 : 557 : tree vuse;
10186 : 557 : if (vphi)
10187 : 552 : vuse = PHI_ARG_DEF_FROM_EDGE (vphi, pe);
10188 : : else
10189 : 5 : vuse = gimple_vuse (gsi_stmt (*gsi));
10190 : 557 : gimple *new_stmt = gimple_build_assign (scalar_dest, rhs);
10191 : 557 : gimple_set_vuse (new_stmt, vuse);
10192 : 557 : gsi_insert_on_edge_immediate (pe, new_stmt);
10193 : : }
10194 : : /* These copies are all equivalent. */
10195 : 749 : if (hoist_p)
10196 : 557 : new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest,
10197 : : vectype, NULL);
10198 : : else
10199 : : {
10200 : 192 : gimple_stmt_iterator gsi2 = *gsi;
10201 : 192 : gsi_next (&gsi2);
10202 : 192 : new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest,
10203 : : vectype, &gsi2);
10204 : : }
10205 : 749 : gimple *new_stmt = SSA_NAME_DEF_STMT (new_temp);
10206 : 749 : if (slp)
10207 : 404 : for (j = 0; j < (int) SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); ++j)
10208 : 224 : slp_node->push_vec_def (new_stmt);
10209 : : else
10210 : : {
10211 : 1203 : for (j = 0; j < ncopies; ++j)
10212 : 634 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
10213 : 569 : *vec_stmt = new_stmt;
10214 : : }
10215 : 749 : return true;
10216 : : }
10217 : :
10218 : 476485 : if (memory_access_type == VMAT_ELEMENTWISE
10219 : 476485 : || memory_access_type == VMAT_STRIDED_SLP)
10220 : : {
10221 : 15458 : gimple_stmt_iterator incr_gsi;
10222 : 15458 : bool insert_after;
10223 : 15458 : tree offvar;
10224 : 15458 : tree ivstep;
10225 : 15458 : tree running_off;
10226 : 15458 : vec<constructor_elt, va_gc> *v = NULL;
10227 : 15458 : tree stride_base, stride_step, alias_off;
10228 : : /* Checked by get_load_store_type. */
10229 : 15458 : unsigned int const_nunits = nunits.to_constant ();
10230 : 15458 : unsigned HOST_WIDE_INT cst_offset = 0;
10231 : 15458 : tree dr_offset;
10232 : 15458 : unsigned int inside_cost = 0;
10233 : :
10234 : 15458 : gcc_assert (!LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo));
10235 : 15458 : gcc_assert (!nested_in_vect_loop);
10236 : :
10237 : 15458 : if (grouped_load)
10238 : : {
10239 : 7971 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
10240 : 7971 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
10241 : : }
10242 : : else
10243 : : {
10244 : : first_stmt_info = stmt_info;
10245 : : first_dr_info = dr_info;
10246 : : }
10247 : :
10248 : 15458 : if (slp && grouped_load)
10249 : : {
10250 : 3548 : group_size = DR_GROUP_SIZE (first_stmt_info);
10251 : 3548 : ref_type = get_group_alias_ptr_type (first_stmt_info);
10252 : : }
10253 : : else
10254 : : {
10255 : 11910 : if (grouped_load)
10256 : 4423 : cst_offset
10257 : 4423 : = (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)))
10258 : 4423 : * vect_get_place_in_interleaving_chain (stmt_info,
10259 : : first_stmt_info));
10260 : 11910 : group_size = 1;
10261 : 11910 : ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr));
10262 : : }
10263 : :
10264 : 15458 : if (!costing_p)
10265 : : {
10266 : 3374 : dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info);
10267 : 3374 : stride_base = fold_build_pointer_plus (
10268 : : DR_BASE_ADDRESS (first_dr_info->dr),
10269 : : size_binop (PLUS_EXPR, convert_to_ptrofftype (dr_offset),
10270 : : convert_to_ptrofftype (DR_INIT (first_dr_info->dr))));
10271 : 3374 : stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr));
10272 : :
10273 : : /* For a load with loop-invariant (but other than power-of-2)
10274 : : stride (i.e. not a grouped access) like so:
10275 : :
10276 : : for (i = 0; i < n; i += stride)
10277 : : ... = array[i];
10278 : :
10279 : : we generate a new induction variable and new accesses to
10280 : : form a new vector (or vectors, depending on ncopies):
10281 : :
10282 : : for (j = 0; ; j += VF*stride)
10283 : : tmp1 = array[j];
10284 : : tmp2 = array[j + stride];
10285 : : ...
10286 : : vectemp = {tmp1, tmp2, ...}
10287 : : */
10288 : :
10289 : 3374 : ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (stride_step), stride_step,
10290 : : build_int_cst (TREE_TYPE (stride_step), vf));
10291 : :
10292 : 3374 : standard_iv_increment_position (loop, &incr_gsi, &insert_after);
10293 : :
10294 : 3374 : stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base);
10295 : 3374 : ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep);
10296 : 3374 : create_iv (stride_base, PLUS_EXPR, ivstep, NULL,
10297 : : loop, &incr_gsi, insert_after,
10298 : : &offvar, NULL);
10299 : :
10300 : 3374 : stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step);
10301 : : }
10302 : :
10303 : 15458 : running_off = offvar;
10304 : 15458 : alias_off = build_int_cst (ref_type, 0);
10305 : 15458 : int nloads = const_nunits;
10306 : 15458 : int lnel = 1;
10307 : 15458 : tree ltype = TREE_TYPE (vectype);
10308 : 15458 : tree lvectype = vectype;
10309 : 15458 : auto_vec<tree> dr_chain;
10310 : 15458 : if (memory_access_type == VMAT_STRIDED_SLP)
10311 : : {
10312 : 3406 : if (group_size < const_nunits)
10313 : : {
10314 : : /* First check if vec_init optab supports construction from vector
10315 : : elts directly. Otherwise avoid emitting a constructor of
10316 : : vector elements by performing the loads using an integer type
10317 : : of the same size, constructing a vector of those and then
10318 : : re-interpreting it as the original vector type. This avoids a
10319 : : huge runtime penalty due to the general inability to perform
10320 : : store forwarding from smaller stores to a larger load. */
10321 : 2265 : tree ptype;
10322 : 2265 : tree vtype
10323 : 2265 : = vector_vector_composition_type (vectype,
10324 : 2265 : const_nunits / group_size,
10325 : : &ptype);
10326 : 2265 : if (vtype != NULL_TREE)
10327 : : {
10328 : 2187 : nloads = const_nunits / group_size;
10329 : 2187 : lnel = group_size;
10330 : 2187 : lvectype = vtype;
10331 : 2187 : ltype = ptype;
10332 : : }
10333 : : }
10334 : : else
10335 : : {
10336 : : nloads = 1;
10337 : : lnel = const_nunits;
10338 : : ltype = vectype;
10339 : : }
10340 : 3406 : ltype = build_aligned_type (ltype, TYPE_ALIGN (TREE_TYPE (vectype)));
10341 : : }
10342 : : /* Load vector(1) scalar_type if it's 1 element-wise vectype. */
10343 : 12052 : else if (nloads == 1)
10344 : 115 : ltype = vectype;
10345 : :
10346 : 15458 : if (slp)
10347 : : {
10348 : : /* For SLP permutation support we need to load the whole group,
10349 : : not only the number of vector stmts the permutation result
10350 : : fits in. */
10351 : 3580 : if (slp_perm)
10352 : : {
10353 : : /* We don't yet generate SLP_TREE_LOAD_PERMUTATIONs for
10354 : : variable VF. */
10355 : 2012 : unsigned int const_vf = vf.to_constant ();
10356 : 2012 : ncopies = CEIL (group_size * const_vf, const_nunits);
10357 : 2012 : dr_chain.create (ncopies);
10358 : : }
10359 : : else
10360 : 1568 : ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
10361 : : }
10362 : 15458 : unsigned int group_el = 0;
10363 : 15458 : unsigned HOST_WIDE_INT
10364 : 15458 : elsz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
10365 : 15458 : unsigned int n_groups = 0;
10366 : : /* For costing some adjacent vector loads, we'd like to cost with
10367 : : the total number of them once instead of cost each one by one. */
10368 : 15458 : unsigned int n_adjacent_loads = 0;
10369 : 33403 : for (j = 0; j < ncopies; j++)
10370 : : {
10371 : 17945 : if (nloads > 1 && !costing_p)
10372 : 3143 : vec_alloc (v, nloads);
10373 : 17945 : gimple *new_stmt = NULL;
10374 : 83585 : for (i = 0; i < nloads; i++)
10375 : : {
10376 : 65640 : if (costing_p)
10377 : : {
10378 : : /* For VMAT_ELEMENTWISE, just cost it as scalar_load to
10379 : : avoid ICE, see PR110776. */
10380 : 54991 : if (VECTOR_TYPE_P (ltype)
10381 : 2997 : && memory_access_type != VMAT_ELEMENTWISE)
10382 : 2425 : n_adjacent_loads++;
10383 : : else
10384 : 52566 : inside_cost += record_stmt_cost (cost_vec, 1, scalar_load,
10385 : : stmt_info, 0, vect_body);
10386 : 54991 : continue;
10387 : : }
10388 : 10649 : tree this_off = build_int_cst (TREE_TYPE (alias_off),
10389 : 10649 : group_el * elsz + cst_offset);
10390 : 10649 : tree data_ref = build2 (MEM_REF, ltype, running_off, this_off);
10391 : 10649 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
10392 : 10649 : new_stmt = gimple_build_assign (make_ssa_name (ltype), data_ref);
10393 : 10649 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10394 : 10649 : if (nloads > 1)
10395 : 10016 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
10396 : : gimple_assign_lhs (new_stmt));
10397 : :
10398 : 10649 : group_el += lnel;
10399 : 10649 : if (! slp
10400 : 4155 : || group_el == group_size)
10401 : : {
10402 : 9910 : n_groups++;
10403 : : /* When doing SLP make sure to not load elements from
10404 : : the next vector iteration, those will not be accessed
10405 : : so just use the last element again. See PR107451. */
10406 : 9910 : if (!slp || known_lt (n_groups, vf))
10407 : : {
10408 : 8533 : tree newoff = copy_ssa_name (running_off);
10409 : 8533 : gimple *incr
10410 : 8533 : = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
10411 : : running_off, stride_step);
10412 : 8533 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
10413 : 8533 : running_off = newoff;
10414 : : }
10415 : : group_el = 0;
10416 : : }
10417 : : }
10418 : :
10419 : 17945 : if (nloads > 1)
10420 : : {
10421 : 15865 : if (costing_p)
10422 : 12722 : inside_cost += record_stmt_cost (cost_vec, 1, vec_construct,
10423 : : stmt_info, 0, vect_body);
10424 : : else
10425 : : {
10426 : 3143 : tree vec_inv = build_constructor (lvectype, v);
10427 : 3143 : new_temp = vect_init_vector (vinfo, stmt_info, vec_inv,
10428 : : lvectype, gsi);
10429 : 3143 : new_stmt = SSA_NAME_DEF_STMT (new_temp);
10430 : 3143 : if (lvectype != vectype)
10431 : : {
10432 : 437 : new_stmt
10433 : 437 : = gimple_build_assign (make_ssa_name (vectype),
10434 : : VIEW_CONVERT_EXPR,
10435 : : build1 (VIEW_CONVERT_EXPR,
10436 : : vectype, new_temp));
10437 : 437 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
10438 : : gsi);
10439 : : }
10440 : : }
10441 : : }
10442 : :
10443 : 17945 : if (!costing_p)
10444 : : {
10445 : 3776 : if (slp)
10446 : : {
10447 : 1732 : if (slp_perm)
10448 : 744 : dr_chain.quick_push (gimple_assign_lhs (new_stmt));
10449 : : else
10450 : 988 : slp_node->push_vec_def (new_stmt);
10451 : : }
10452 : : else
10453 : : {
10454 : 2044 : if (j == 0)
10455 : 2016 : *vec_stmt = new_stmt;
10456 : 2044 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
10457 : : }
10458 : : }
10459 : : }
10460 : 15458 : if (slp_perm)
10461 : : {
10462 : 2012 : unsigned n_perms;
10463 : 2012 : if (costing_p)
10464 : : {
10465 : 1274 : unsigned n_loads;
10466 : 1274 : vect_transform_slp_perm_load (vinfo, slp_node, vNULL, NULL, vf,
10467 : : true, &n_perms, &n_loads);
10468 : 1274 : inside_cost += record_stmt_cost (cost_vec, n_perms, vec_perm,
10469 : : first_stmt_info, 0, vect_body);
10470 : : }
10471 : : else
10472 : 738 : vect_transform_slp_perm_load (vinfo, slp_node, dr_chain, gsi, vf,
10473 : : false, &n_perms);
10474 : : }
10475 : :
10476 : 15458 : if (costing_p)
10477 : : {
10478 : 12084 : if (n_adjacent_loads > 0)
10479 : 1314 : vect_get_load_cost (vinfo, stmt_info, n_adjacent_loads,
10480 : : alignment_support_scheme, misalignment, false,
10481 : : &inside_cost, nullptr, cost_vec, cost_vec,
10482 : : true);
10483 : 12084 : if (dump_enabled_p ())
10484 : 702 : dump_printf_loc (MSG_NOTE, vect_location,
10485 : : "vect_model_load_cost: inside_cost = %u, "
10486 : : "prologue_cost = 0 .\n",
10487 : : inside_cost);
10488 : : }
10489 : :
10490 : 15458 : return true;
10491 : 15458 : }
10492 : :
10493 : 461027 : if (memory_access_type == VMAT_GATHER_SCATTER
10494 : 458731 : || (!slp && memory_access_type == VMAT_CONTIGUOUS))
10495 : : grouped_load = false;
10496 : :
10497 : 292431 : if (grouped_load
10498 : 461027 : || (slp && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()))
10499 : : {
10500 : 288626 : if (grouped_load)
10501 : : {
10502 : 288491 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
10503 : 288491 : group_size = DR_GROUP_SIZE (first_stmt_info);
10504 : : }
10505 : : else
10506 : : {
10507 : : first_stmt_info = stmt_info;
10508 : : group_size = 1;
10509 : : }
10510 : : /* For SLP vectorization we directly vectorize a subchain
10511 : : without permutation. */
10512 : 288626 : if (slp && ! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
10513 : 228120 : first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
10514 : : /* For BB vectorization always use the first stmt to base
10515 : : the data ref pointer on. */
10516 : 288626 : if (bb_vinfo)
10517 : 241153 : first_stmt_info_for_drptr
10518 : 241153 : = vect_find_first_scalar_stmt_in_slp (slp_node);
10519 : :
10520 : : /* Check if the chain of loads is already vectorized. */
10521 : 288626 : if (STMT_VINFO_VEC_STMTS (first_stmt_info).exists ()
10522 : : /* For SLP we would need to copy over SLP_TREE_VEC_DEFS.
10523 : : ??? But we can only do so if there is exactly one
10524 : : as we have no way to get at the rest. Leave the CSE
10525 : : opportunity alone.
10526 : : ??? With the group load eventually participating
10527 : : in multiple different permutations (having multiple
10528 : : slp nodes which refer to the same group) the CSE
10529 : : is even wrong code. See PR56270. */
10530 : 288626 : && !slp)
10531 : : {
10532 : 3033 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
10533 : 3033 : return true;
10534 : : }
10535 : 285593 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
10536 : 285593 : group_gap_adj = 0;
10537 : :
10538 : : /* VEC_NUM is the number of vect stmts to be created for this group. */
10539 : 285593 : if (slp)
10540 : : {
10541 : 254863 : grouped_load = false;
10542 : : /* If an SLP permutation is from N elements to N elements,
10543 : : and if one vector holds a whole number of N, we can load
10544 : : the inputs to the permutation in the same way as an
10545 : : unpermuted sequence. In other cases we need to load the
10546 : : whole group, not only the number of vector stmts the
10547 : : permutation result fits in. */
10548 : 254863 : unsigned scalar_lanes = SLP_TREE_LANES (slp_node);
10549 : 254863 : if (slp_perm
10550 : 254863 : && (group_size != scalar_lanes
10551 : 8867 : || !multiple_p (nunits, group_size)))
10552 : : {
10553 : : /* We don't yet generate such SLP_TREE_LOAD_PERMUTATIONs for
10554 : : variable VF; see vect_transform_slp_perm_load. */
10555 : 19445 : unsigned int const_vf = vf.to_constant ();
10556 : 19445 : unsigned int const_nunits = nunits.to_constant ();
10557 : 19445 : vec_num = CEIL (group_size * const_vf, const_nunits);
10558 : 19445 : group_gap_adj = vf * group_size - nunits * vec_num;
10559 : : }
10560 : : else
10561 : : {
10562 : 235418 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
10563 : 235418 : group_gap_adj
10564 : 235418 : = group_size - scalar_lanes;
10565 : : }
10566 : : }
10567 : : else
10568 : 30730 : vec_num = group_size;
10569 : :
10570 : 285593 : ref_type = get_group_alias_ptr_type (first_stmt_info);
10571 : : }
10572 : : else
10573 : : {
10574 : 172401 : first_stmt_info = stmt_info;
10575 : 172401 : first_dr_info = dr_info;
10576 : 172401 : group_size = vec_num = 1;
10577 : 172401 : group_gap_adj = 0;
10578 : 172401 : ref_type = reference_alias_ptr_type (DR_REF (first_dr_info->dr));
10579 : 172401 : if (slp)
10580 : 58 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
10581 : : }
10582 : :
10583 : 457994 : gcc_assert (alignment_support_scheme);
10584 : 457994 : vec_loop_masks *loop_masks
10585 : 216841 : = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
10586 : 457994 : ? &LOOP_VINFO_MASKS (loop_vinfo)
10587 : 674841 : : NULL);
10588 : 6 : vec_loop_lens *loop_lens
10589 : 216841 : = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)
10590 : 0 : ? &LOOP_VINFO_LENS (loop_vinfo)
10591 : 457994 : : NULL);
10592 : :
10593 : : /* The vect_transform_stmt and vect_analyze_stmt will go here but there
10594 : : are some difference here. We cannot enable both the lens and masks
10595 : : during transform but it is allowed during analysis.
10596 : : Shouldn't go with length-based approach if fully masked. */
10597 : 457994 : if (cost_vec == NULL)
10598 : : /* The cost_vec is NULL during transfrom. */
10599 : 154717 : gcc_assert ((!loop_lens || !loop_masks));
10600 : :
10601 : : /* Targets with store-lane instructions must not require explicit
10602 : : realignment. vect_supportable_dr_alignment always returns either
10603 : : dr_aligned or dr_unaligned_supported for masked operations. */
10604 : 457994 : gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES
10605 : : && !mask
10606 : : && !loop_masks)
10607 : : || alignment_support_scheme == dr_aligned
10608 : : || alignment_support_scheme == dr_unaligned_supported);
10609 : :
10610 : : /* In case the vectorization factor (VF) is bigger than the number
10611 : : of elements that we can fit in a vectype (nunits), we have to generate
10612 : : more than one vector stmt - i.e - we need to "unroll" the
10613 : : vector stmt by a factor VF/nunits. In doing so, we record a pointer
10614 : : from one copy of the vector stmt to the next, in the field
10615 : : STMT_VINFO_RELATED_STMT. This is necessary in order to allow following
10616 : : stages to find the correct vector defs to be used when vectorizing
10617 : : stmts that use the defs of the current stmt. The example below
10618 : : illustrates the vectorization process when VF=16 and nunits=4 (i.e., we
10619 : : need to create 4 vectorized stmts):
10620 : :
10621 : : before vectorization:
10622 : : RELATED_STMT VEC_STMT
10623 : : S1: x = memref - -
10624 : : S2: z = x + 1 - -
10625 : :
10626 : : step 1: vectorize stmt S1:
10627 : : We first create the vector stmt VS1_0, and, as usual, record a
10628 : : pointer to it in the STMT_VINFO_VEC_STMT of the scalar stmt S1.
10629 : : Next, we create the vector stmt VS1_1, and record a pointer to
10630 : : it in the STMT_VINFO_RELATED_STMT of the vector stmt VS1_0.
10631 : : Similarly, for VS1_2 and VS1_3. This is the resulting chain of
10632 : : stmts and pointers:
10633 : : RELATED_STMT VEC_STMT
10634 : : VS1_0: vx0 = memref0 VS1_1 -
10635 : : VS1_1: vx1 = memref1 VS1_2 -
10636 : : VS1_2: vx2 = memref2 VS1_3 -
10637 : : VS1_3: vx3 = memref3 - -
10638 : : S1: x = load - VS1_0
10639 : : S2: z = x + 1 - -
10640 : : */
10641 : :
10642 : : /* In case of interleaving (non-unit grouped access):
10643 : :
10644 : : S1: x2 = &base + 2
10645 : : S2: x0 = &base
10646 : : S3: x1 = &base + 1
10647 : : S4: x3 = &base + 3
10648 : :
10649 : : Vectorized loads are created in the order of memory accesses
10650 : : starting from the access of the first stmt of the chain:
10651 : :
10652 : : VS1: vx0 = &base
10653 : : VS2: vx1 = &base + vec_size*1
10654 : : VS3: vx3 = &base + vec_size*2
10655 : : VS4: vx4 = &base + vec_size*3
10656 : :
10657 : : Then permutation statements are generated:
10658 : :
10659 : : VS5: vx5 = VEC_PERM_EXPR < vx0, vx1, { 0, 2, ..., i*2 } >
10660 : : VS6: vx6 = VEC_PERM_EXPR < vx0, vx1, { 1, 3, ..., i*2+1 } >
10661 : : ...
10662 : :
10663 : : And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts
10664 : : (the order of the data-refs in the output of vect_permute_load_chain
10665 : : corresponds to the order of scalar stmts in the interleaving chain - see
10666 : : the documentation of vect_permute_load_chain()).
10667 : : The generation of permutation stmts and recording them in
10668 : : STMT_VINFO_VEC_STMT is done in vect_transform_grouped_load().
10669 : :
10670 : : In case of both multiple types and interleaving, the vector loads and
10671 : : permutation stmts above are created for every copy. The result vector
10672 : : stmts are put in STMT_VINFO_VEC_STMT for the first copy and in the
10673 : : corresponding STMT_VINFO_RELATED_STMT for the next copies. */
10674 : :
10675 : : /* If the data reference is aligned (dr_aligned) or potentially unaligned
10676 : : on a target that supports unaligned accesses (dr_unaligned_supported)
10677 : : we generate the following code:
10678 : : p = initial_addr;
10679 : : indx = 0;
10680 : : loop {
10681 : : p = p + indx * vectype_size;
10682 : : vec_dest = *(p);
10683 : : indx = indx + 1;
10684 : : }
10685 : :
10686 : : Otherwise, the data reference is potentially unaligned on a target that
10687 : : does not support unaligned accesses (dr_explicit_realign_optimized) -
10688 : : then generate the following code, in which the data in each iteration is
10689 : : obtained by two vector loads, one from the previous iteration, and one
10690 : : from the current iteration:
10691 : : p1 = initial_addr;
10692 : : msq_init = *(floor(p1))
10693 : : p2 = initial_addr + VS - 1;
10694 : : realignment_token = call target_builtin;
10695 : : indx = 0;
10696 : : loop {
10697 : : p2 = p2 + indx * vectype_size
10698 : : lsq = *(floor(p2))
10699 : : vec_dest = realign_load (msq, lsq, realignment_token)
10700 : : indx = indx + 1;
10701 : : msq = lsq;
10702 : : } */
10703 : :
10704 : : /* If the misalignment remains the same throughout the execution of the
10705 : : loop, we can create the init_addr and permutation mask at the loop
10706 : : preheader. Otherwise, it needs to be created inside the loop.
10707 : : This can only occur when vectorizing memory accesses in the inner-loop
10708 : : nested within an outer-loop that is being vectorized. */
10709 : :
10710 : 457994 : if (nested_in_vect_loop
10711 : 457994 : && !multiple_p (DR_STEP_ALIGNMENT (dr_info->dr),
10712 : 852 : GET_MODE_SIZE (TYPE_MODE (vectype))))
10713 : : {
10714 : 106 : gcc_assert (alignment_support_scheme != dr_explicit_realign_optimized);
10715 : : compute_in_loop = true;
10716 : : }
10717 : :
10718 : 457994 : bool diff_first_stmt_info
10719 : 457994 : = first_stmt_info_for_drptr && first_stmt_info != first_stmt_info_for_drptr;
10720 : :
10721 : 457994 : tree offset = NULL_TREE;
10722 : 457994 : if ((alignment_support_scheme == dr_explicit_realign_optimized
10723 : 457994 : || alignment_support_scheme == dr_explicit_realign)
10724 : 0 : && !compute_in_loop)
10725 : : {
10726 : : /* If we have different first_stmt_info, we can't set up realignment
10727 : : here, since we can't guarantee first_stmt_info DR has been
10728 : : initialized yet, use first_stmt_info_for_drptr DR by bumping the
10729 : : distance from first_stmt_info DR instead as below. */
10730 : 0 : if (!costing_p)
10731 : : {
10732 : 0 : if (!diff_first_stmt_info)
10733 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info, gsi,
10734 : : &realignment_token,
10735 : : alignment_support_scheme, NULL_TREE,
10736 : : &at_loop);
10737 : 0 : if (alignment_support_scheme == dr_explicit_realign_optimized)
10738 : : {
10739 : 0 : phi = as_a<gphi *> (SSA_NAME_DEF_STMT (msq));
10740 : 0 : offset = size_binop (MINUS_EXPR, TYPE_SIZE_UNIT (vectype),
10741 : : size_one_node);
10742 : 0 : gcc_assert (!first_stmt_info_for_drptr);
10743 : : }
10744 : : }
10745 : : }
10746 : : else
10747 : 457994 : at_loop = loop;
10748 : :
10749 : 457994 : if (!known_eq (poffset, 0))
10750 : 3839 : offset = (offset
10751 : 3839 : ? size_binop (PLUS_EXPR, offset, size_int (poffset))
10752 : 3839 : : size_int (poffset));
10753 : :
10754 : 457994 : tree bump;
10755 : 457994 : tree vec_offset = NULL_TREE;
10756 : 457994 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
10757 : : {
10758 : 2296 : aggr_type = NULL_TREE;
10759 : 2296 : bump = NULL_TREE;
10760 : : }
10761 : 455698 : else if (memory_access_type == VMAT_GATHER_SCATTER)
10762 : : {
10763 : 0 : aggr_type = elem_type;
10764 : 0 : if (!costing_p)
10765 : 0 : vect_get_strided_load_store_ops (stmt_info, loop_vinfo, gsi, &gs_info,
10766 : : &bump, &vec_offset, loop_lens);
10767 : : }
10768 : : else
10769 : : {
10770 : 455698 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
10771 : 0 : aggr_type = build_array_type_nelts (elem_type, vec_num * nunits);
10772 : : else
10773 : : aggr_type = vectype;
10774 : 455698 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
10775 : : memory_access_type, loop_lens);
10776 : : }
10777 : :
10778 : 457994 : auto_vec<tree> vec_offsets;
10779 : 457994 : auto_vec<tree> vec_masks;
10780 : 457994 : if (mask && !costing_p)
10781 : : {
10782 : 600 : if (slp_node)
10783 : 3 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[mask_index],
10784 : : &vec_masks);
10785 : : else
10786 : 597 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, mask,
10787 : : &vec_masks, mask_vectype);
10788 : : }
10789 : :
10790 : 457994 : tree vec_mask = NULL_TREE;
10791 : 457994 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
10792 : : {
10793 : 0 : gcc_assert (alignment_support_scheme == dr_aligned
10794 : : || alignment_support_scheme == dr_unaligned_supported);
10795 : 0 : gcc_assert (grouped_load && !slp);
10796 : :
10797 : 0 : unsigned int inside_cost = 0, prologue_cost = 0;
10798 : : /* For costing some adjacent vector loads, we'd like to cost with
10799 : : the total number of them once instead of cost each one by one. */
10800 : 0 : unsigned int n_adjacent_loads = 0;
10801 : 0 : for (j = 0; j < ncopies; j++)
10802 : : {
10803 : 0 : if (costing_p)
10804 : : {
10805 : : /* An IFN_LOAD_LANES will load all its vector results,
10806 : : regardless of which ones we actually need. Account
10807 : : for the cost of unused results. */
10808 : 0 : if (first_stmt_info == stmt_info)
10809 : : {
10810 : 0 : unsigned int gaps = DR_GROUP_SIZE (first_stmt_info);
10811 : 0 : stmt_vec_info next_stmt_info = first_stmt_info;
10812 : 0 : do
10813 : : {
10814 : 0 : gaps -= 1;
10815 : 0 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
10816 : : }
10817 : 0 : while (next_stmt_info);
10818 : 0 : if (gaps)
10819 : : {
10820 : 0 : if (dump_enabled_p ())
10821 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
10822 : : "vect_model_load_cost: %d "
10823 : : "unused vectors.\n",
10824 : : gaps);
10825 : 0 : vect_get_load_cost (vinfo, stmt_info, gaps,
10826 : : alignment_support_scheme,
10827 : : misalignment, false, &inside_cost,
10828 : : &prologue_cost, cost_vec, cost_vec,
10829 : : true);
10830 : : }
10831 : : }
10832 : 0 : n_adjacent_loads++;
10833 : 0 : continue;
10834 : 0 : }
10835 : :
10836 : : /* 1. Create the vector or array pointer update chain. */
10837 : 0 : if (j == 0)
10838 : 0 : dataref_ptr
10839 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
10840 : : at_loop, offset, &dummy, gsi,
10841 : : &ptr_incr, false, bump);
10842 : : else
10843 : : {
10844 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
10845 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
10846 : : stmt_info, bump);
10847 : : }
10848 : 0 : if (mask)
10849 : 0 : vec_mask = vec_masks[j];
10850 : :
10851 : 0 : tree vec_array = create_vector_array (vectype, vec_num);
10852 : :
10853 : 0 : tree final_mask = NULL_TREE;
10854 : 0 : tree final_len = NULL_TREE;
10855 : 0 : tree bias = NULL_TREE;
10856 : 0 : if (loop_masks)
10857 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
10858 : : ncopies, vectype, j);
10859 : 0 : if (vec_mask)
10860 : 0 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
10861 : : vec_mask, gsi);
10862 : :
10863 : 0 : if (lanes_ifn == IFN_MASK_LEN_LOAD_LANES)
10864 : : {
10865 : 0 : if (loop_lens)
10866 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
10867 : : ncopies, vectype, j, 1);
10868 : : else
10869 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
10870 : 0 : signed char biasval
10871 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
10872 : 0 : bias = build_int_cst (intQI_type_node, biasval);
10873 : 0 : if (!final_mask)
10874 : : {
10875 : 0 : mask_vectype = truth_type_for (vectype);
10876 : 0 : final_mask = build_minus_one_cst (mask_vectype);
10877 : : }
10878 : : }
10879 : :
10880 : 0 : gcall *call;
10881 : 0 : if (final_len && final_mask)
10882 : : {
10883 : : /* Emit:
10884 : : VEC_ARRAY = MASK_LEN_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,
10885 : : VEC_MASK, LEN, BIAS). */
10886 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
10887 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
10888 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_LOAD_LANES, 5,
10889 : : dataref_ptr, alias_ptr,
10890 : : final_mask, final_len, bias);
10891 : : }
10892 : 0 : else if (final_mask)
10893 : : {
10894 : : /* Emit:
10895 : : VEC_ARRAY = MASK_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,
10896 : : VEC_MASK). */
10897 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
10898 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
10899 : 0 : call = gimple_build_call_internal (IFN_MASK_LOAD_LANES, 3,
10900 : : dataref_ptr, alias_ptr,
10901 : : final_mask);
10902 : : }
10903 : : else
10904 : : {
10905 : : /* Emit:
10906 : : VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]). */
10907 : 0 : data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
10908 : 0 : call = gimple_build_call_internal (IFN_LOAD_LANES, 1, data_ref);
10909 : : }
10910 : 0 : gimple_call_set_lhs (call, vec_array);
10911 : 0 : gimple_call_set_nothrow (call, true);
10912 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
10913 : :
10914 : 0 : dr_chain.create (vec_num);
10915 : : /* Extract each vector into an SSA_NAME. */
10916 : 0 : for (i = 0; i < vec_num; i++)
10917 : : {
10918 : 0 : new_temp = read_vector_array (vinfo, stmt_info, gsi, scalar_dest,
10919 : : vec_array, i);
10920 : 0 : dr_chain.quick_push (new_temp);
10921 : : }
10922 : :
10923 : : /* Record the mapping between SSA_NAMEs and statements. */
10924 : 0 : vect_record_grouped_load_vectors (vinfo, stmt_info, dr_chain);
10925 : :
10926 : : /* Record that VEC_ARRAY is now dead. */
10927 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
10928 : :
10929 : 0 : dr_chain.release ();
10930 : :
10931 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
10932 : : }
10933 : :
10934 : 0 : if (costing_p)
10935 : : {
10936 : 0 : if (n_adjacent_loads > 0)
10937 : 0 : vect_get_load_cost (vinfo, stmt_info, n_adjacent_loads,
10938 : : alignment_support_scheme, misalignment, false,
10939 : : &inside_cost, &prologue_cost, cost_vec,
10940 : : cost_vec, true);
10941 : 0 : if (dump_enabled_p ())
10942 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
10943 : : "vect_model_load_cost: inside_cost = %u, "
10944 : : "prologue_cost = %u .\n",
10945 : : inside_cost, prologue_cost);
10946 : : }
10947 : :
10948 : 0 : return true;
10949 : : }
10950 : :
10951 : 457994 : if (memory_access_type == VMAT_GATHER_SCATTER)
10952 : : {
10953 : 2296 : gcc_assert (alignment_support_scheme == dr_aligned
10954 : : || alignment_support_scheme == dr_unaligned_supported);
10955 : 2296 : gcc_assert (!grouped_load && !slp_perm);
10956 : :
10957 : : unsigned int inside_cost = 0, prologue_cost = 0;
10958 : 5184 : for (j = 0; j < ncopies; j++)
10959 : : {
10960 : : /* 1. Create the vector or array pointer update chain. */
10961 : 2888 : if (j == 0 && !costing_p)
10962 : : {
10963 : 732 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
10964 : 732 : vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info,
10965 : : slp_node, &gs_info, &dataref_ptr,
10966 : : &vec_offsets);
10967 : : else
10968 : 0 : dataref_ptr
10969 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
10970 : : at_loop, offset, &dummy, gsi,
10971 : : &ptr_incr, false, bump);
10972 : : }
10973 : 2156 : else if (!costing_p)
10974 : : {
10975 : 179 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
10976 : 179 : if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info))
10977 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
10978 : : gsi, stmt_info, bump);
10979 : : }
10980 : :
10981 : 2888 : gimple *new_stmt = NULL;
10982 : 5858 : for (i = 0; i < vec_num; i++)
10983 : : {
10984 : 2970 : tree final_mask = NULL_TREE;
10985 : 2970 : tree final_len = NULL_TREE;
10986 : 2970 : tree bias = NULL_TREE;
10987 : 2970 : if (!costing_p)
10988 : : {
10989 : 949 : if (mask)
10990 : 154 : vec_mask = vec_masks[vec_num * j + i];
10991 : 949 : if (loop_masks)
10992 : 0 : final_mask
10993 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
10994 : 0 : vec_num * ncopies, vectype,
10995 : 0 : vec_num * j + i);
10996 : 949 : if (vec_mask)
10997 : 154 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
10998 : : final_mask, vec_mask, gsi);
10999 : :
11000 : 949 : if (i > 0 && !STMT_VINFO_GATHER_SCATTER_P (stmt_info))
11001 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
11002 : : gsi, stmt_info, bump);
11003 : : }
11004 : :
11005 : : /* 2. Create the vector-load in the loop. */
11006 : 2970 : unsigned HOST_WIDE_INT align;
11007 : 2970 : if (gs_info.ifn != IFN_LAST)
11008 : : {
11009 : 0 : if (costing_p)
11010 : : {
11011 : 0 : unsigned int cnunits = vect_nunits_for_cost (vectype);
11012 : 0 : inside_cost
11013 : 0 : = record_stmt_cost (cost_vec, cnunits, scalar_load,
11014 : : stmt_info, 0, vect_body);
11015 : 0 : continue;
11016 : 0 : }
11017 : 0 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
11018 : 0 : vec_offset = vec_offsets[vec_num * j + i];
11019 : 0 : tree zero = build_zero_cst (vectype);
11020 : 0 : tree scale = size_int (gs_info.scale);
11021 : :
11022 : 0 : if (gs_info.ifn == IFN_MASK_LEN_GATHER_LOAD)
11023 : : {
11024 : 0 : if (loop_lens)
11025 : 0 : final_len
11026 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
11027 : 0 : vec_num * ncopies, vectype,
11028 : 0 : vec_num * j + i, 1);
11029 : : else
11030 : 0 : final_len
11031 : 0 : = build_int_cst (sizetype,
11032 : 0 : TYPE_VECTOR_SUBPARTS (vectype));
11033 : 0 : signed char biasval
11034 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
11035 : 0 : bias = build_int_cst (intQI_type_node, biasval);
11036 : 0 : if (!final_mask)
11037 : : {
11038 : 0 : mask_vectype = truth_type_for (vectype);
11039 : 0 : final_mask = build_minus_one_cst (mask_vectype);
11040 : : }
11041 : : }
11042 : :
11043 : 0 : gcall *call;
11044 : 0 : if (final_len && final_mask)
11045 : 0 : call
11046 : 0 : = gimple_build_call_internal (IFN_MASK_LEN_GATHER_LOAD, 7,
11047 : : dataref_ptr, vec_offset,
11048 : : scale, zero, final_mask,
11049 : : final_len, bias);
11050 : 0 : else if (final_mask)
11051 : 0 : call = gimple_build_call_internal (IFN_MASK_GATHER_LOAD, 5,
11052 : : dataref_ptr, vec_offset,
11053 : : scale, zero, final_mask);
11054 : : else
11055 : 0 : call = gimple_build_call_internal (IFN_GATHER_LOAD, 4,
11056 : : dataref_ptr, vec_offset,
11057 : : scale, zero);
11058 : 0 : gimple_call_set_nothrow (call, true);
11059 : 0 : new_stmt = call;
11060 : 0 : data_ref = NULL_TREE;
11061 : : }
11062 : 2970 : else if (gs_info.decl)
11063 : : {
11064 : : /* The builtin decls path for gather is legacy, x86 only. */
11065 : 664 : gcc_assert (!final_len && nunits.is_constant ());
11066 : 664 : if (costing_p)
11067 : : {
11068 : 380 : unsigned int cnunits = vect_nunits_for_cost (vectype);
11069 : 380 : inside_cost
11070 : 380 : = record_stmt_cost (cost_vec, cnunits, scalar_load,
11071 : : stmt_info, 0, vect_body);
11072 : 380 : continue;
11073 : 380 : }
11074 : 284 : poly_uint64 offset_nunits
11075 : 284 : = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype);
11076 : 284 : if (known_eq (nunits, offset_nunits))
11077 : : {
11078 : 270 : new_stmt = vect_build_one_gather_load_call
11079 : 135 : (vinfo, stmt_info, gsi, &gs_info,
11080 : 135 : dataref_ptr, vec_offsets[vec_num * j + i],
11081 : : final_mask);
11082 : 135 : data_ref = NULL_TREE;
11083 : : }
11084 : 149 : else if (known_eq (nunits, offset_nunits * 2))
11085 : : {
11086 : : /* We have a offset vector with half the number of
11087 : : lanes but the builtins will produce full vectype
11088 : : data with just the lower lanes filled. */
11089 : 126 : new_stmt = vect_build_one_gather_load_call
11090 : 63 : (vinfo, stmt_info, gsi, &gs_info,
11091 : 63 : dataref_ptr, vec_offsets[2 * vec_num * j + 2 * i],
11092 : : final_mask);
11093 : 63 : tree low = make_ssa_name (vectype);
11094 : 63 : gimple_set_lhs (new_stmt, low);
11095 : 63 : vect_finish_stmt_generation (vinfo, stmt_info,
11096 : : new_stmt, gsi);
11097 : :
11098 : : /* now put upper half of final_mask in final_mask low. */
11099 : 63 : if (final_mask
11100 : 63 : && !SCALAR_INT_MODE_P
11101 : : (TYPE_MODE (TREE_TYPE (final_mask))))
11102 : : {
11103 : 10 : int count = nunits.to_constant ();
11104 : 10 : vec_perm_builder sel (count, count, 1);
11105 : 10 : sel.quick_grow (count);
11106 : 78 : for (int i = 0; i < count; ++i)
11107 : 68 : sel[i] = i | (count / 2);
11108 : 10 : vec_perm_indices indices (sel, 2, count);
11109 : 10 : tree perm_mask = vect_gen_perm_mask_checked
11110 : 10 : (TREE_TYPE (final_mask), indices);
11111 : 10 : new_stmt = gimple_build_assign (NULL_TREE,
11112 : : VEC_PERM_EXPR,
11113 : : final_mask,
11114 : : final_mask,
11115 : : perm_mask);
11116 : 10 : final_mask = make_ssa_name (TREE_TYPE (final_mask));
11117 : 10 : gimple_set_lhs (new_stmt, final_mask);
11118 : 10 : vect_finish_stmt_generation (vinfo, stmt_info,
11119 : : new_stmt, gsi);
11120 : 10 : }
11121 : 53 : else if (final_mask)
11122 : : {
11123 : 25 : new_stmt = gimple_build_assign (NULL_TREE,
11124 : : VEC_UNPACK_HI_EXPR,
11125 : : final_mask);
11126 : 25 : final_mask = make_ssa_name
11127 : 25 : (truth_type_for (gs_info.offset_vectype));
11128 : 25 : gimple_set_lhs (new_stmt, final_mask);
11129 : 25 : vect_finish_stmt_generation (vinfo, stmt_info,
11130 : : new_stmt, gsi);
11131 : : }
11132 : :
11133 : 63 : new_stmt = vect_build_one_gather_load_call
11134 : 63 : (vinfo, stmt_info, gsi, &gs_info,
11135 : : dataref_ptr,
11136 : 63 : vec_offsets[2 * vec_num * j + 2 * i + 1],
11137 : : final_mask);
11138 : 63 : tree high = make_ssa_name (vectype);
11139 : 63 : gimple_set_lhs (new_stmt, high);
11140 : 63 : vect_finish_stmt_generation (vinfo, stmt_info,
11141 : : new_stmt, gsi);
11142 : :
11143 : : /* compose low + high. */
11144 : 63 : int count = nunits.to_constant ();
11145 : 63 : vec_perm_builder sel (count, count, 1);
11146 : 63 : sel.quick_grow (count);
11147 : 655 : for (int i = 0; i < count; ++i)
11148 : 592 : sel[i] = i < count / 2 ? i : i + count / 2;
11149 : 63 : vec_perm_indices indices (sel, 2, count);
11150 : 63 : tree perm_mask
11151 : 63 : = vect_gen_perm_mask_checked (vectype, indices);
11152 : 63 : new_stmt = gimple_build_assign (NULL_TREE,
11153 : : VEC_PERM_EXPR,
11154 : : low, high, perm_mask);
11155 : 63 : data_ref = NULL_TREE;
11156 : 63 : }
11157 : 86 : else if (known_eq (nunits * 2, offset_nunits))
11158 : : {
11159 : : /* We have a offset vector with double the number of
11160 : : lanes. Select the low/high part accordingly. */
11161 : 86 : vec_offset = vec_offsets[(vec_num * j + i) / 2];
11162 : 86 : if ((vec_num * j + i) & 1)
11163 : : {
11164 : 43 : int count = offset_nunits.to_constant ();
11165 : 43 : vec_perm_builder sel (count, count, 1);
11166 : 43 : sel.quick_grow (count);
11167 : 463 : for (int i = 0; i < count; ++i)
11168 : 420 : sel[i] = i | (count / 2);
11169 : 43 : vec_perm_indices indices (sel, 2, count);
11170 : 43 : tree perm_mask = vect_gen_perm_mask_checked
11171 : 43 : (TREE_TYPE (vec_offset), indices);
11172 : 43 : new_stmt = gimple_build_assign (NULL_TREE,
11173 : : VEC_PERM_EXPR,
11174 : : vec_offset,
11175 : : vec_offset,
11176 : : perm_mask);
11177 : 43 : vec_offset = make_ssa_name (TREE_TYPE (vec_offset));
11178 : 43 : gimple_set_lhs (new_stmt, vec_offset);
11179 : 43 : vect_finish_stmt_generation (vinfo, stmt_info,
11180 : : new_stmt, gsi);
11181 : 43 : }
11182 : 172 : new_stmt = vect_build_one_gather_load_call
11183 : 86 : (vinfo, stmt_info, gsi, &gs_info,
11184 : : dataref_ptr, vec_offset, final_mask);
11185 : 86 : data_ref = NULL_TREE;
11186 : : }
11187 : : else
11188 : 0 : gcc_unreachable ();
11189 : : }
11190 : : else
11191 : : {
11192 : : /* Emulated gather-scatter. */
11193 : 2306 : gcc_assert (!final_mask);
11194 : 2306 : unsigned HOST_WIDE_INT const_nunits = nunits.to_constant ();
11195 : 2306 : if (costing_p)
11196 : : {
11197 : : /* For emulated gathers N offset vector element
11198 : : offset add is consumed by the load). */
11199 : 1641 : inside_cost = record_stmt_cost (cost_vec, const_nunits,
11200 : : vec_to_scalar, stmt_info,
11201 : : 0, vect_body);
11202 : : /* N scalar loads plus gathering them into a
11203 : : vector. */
11204 : 1641 : inside_cost
11205 : 1641 : = record_stmt_cost (cost_vec, const_nunits, scalar_load,
11206 : : stmt_info, 0, vect_body);
11207 : 1641 : inside_cost
11208 : 1641 : = record_stmt_cost (cost_vec, 1, vec_construct,
11209 : : stmt_info, 0, vect_body);
11210 : 1641 : continue;
11211 : : }
11212 : 665 : unsigned HOST_WIDE_INT const_offset_nunits
11213 : 665 : = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype)
11214 : 665 : .to_constant ();
11215 : 665 : vec<constructor_elt, va_gc> *ctor_elts;
11216 : 665 : vec_alloc (ctor_elts, const_nunits);
11217 : 665 : gimple_seq stmts = NULL;
11218 : : /* We support offset vectors with more elements
11219 : : than the data vector for now. */
11220 : 665 : unsigned HOST_WIDE_INT factor
11221 : : = const_offset_nunits / const_nunits;
11222 : 665 : vec_offset = vec_offsets[(vec_num * j + i) / factor];
11223 : 665 : unsigned elt_offset
11224 : 665 : = ((vec_num * j + i) % factor) * const_nunits;
11225 : 665 : tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset));
11226 : 665 : tree scale = size_int (gs_info.scale);
11227 : 665 : align = get_object_alignment (DR_REF (first_dr_info->dr));
11228 : 665 : tree ltype = build_aligned_type (TREE_TYPE (vectype), align);
11229 : 2697 : for (unsigned k = 0; k < const_nunits; ++k)
11230 : : {
11231 : 2032 : tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type),
11232 : : bitsize_int (k + elt_offset));
11233 : 2032 : tree idx
11234 : 2032 : = gimple_build (&stmts, BIT_FIELD_REF, idx_type,
11235 : 2032 : vec_offset, TYPE_SIZE (idx_type), boff);
11236 : 2032 : idx = gimple_convert (&stmts, sizetype, idx);
11237 : 2032 : idx = gimple_build (&stmts, MULT_EXPR, sizetype, idx,
11238 : : scale);
11239 : 2032 : tree ptr = gimple_build (&stmts, PLUS_EXPR,
11240 : 2032 : TREE_TYPE (dataref_ptr),
11241 : : dataref_ptr, idx);
11242 : 2032 : ptr = gimple_convert (&stmts, ptr_type_node, ptr);
11243 : 2032 : tree elt = make_ssa_name (TREE_TYPE (vectype));
11244 : 2032 : tree ref = build2 (MEM_REF, ltype, ptr,
11245 : 2032 : build_int_cst (ref_type, 0));
11246 : 2032 : new_stmt = gimple_build_assign (elt, ref);
11247 : 4064 : gimple_set_vuse (new_stmt, gimple_vuse (gsi_stmt (*gsi)));
11248 : 2032 : gimple_seq_add_stmt (&stmts, new_stmt);
11249 : 2032 : CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE, elt);
11250 : : }
11251 : 665 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
11252 : 665 : new_stmt = gimple_build_assign (
11253 : : NULL_TREE, build_constructor (vectype, ctor_elts));
11254 : 665 : data_ref = NULL_TREE;
11255 : : }
11256 : :
11257 : 949 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11258 : : /* DATA_REF is null if we've already built the statement. */
11259 : 949 : if (data_ref)
11260 : : {
11261 : : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
11262 : : new_stmt = gimple_build_assign (vec_dest, data_ref);
11263 : : }
11264 : 949 : new_temp = make_ssa_name (vec_dest, new_stmt);
11265 : 949 : gimple_set_lhs (new_stmt, new_temp);
11266 : 949 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11267 : :
11268 : : /* Store vector loads in the corresponding SLP_NODE. */
11269 : 949 : if (slp)
11270 : 64 : slp_node->push_vec_def (new_stmt);
11271 : : }
11272 : :
11273 : 2888 : if (!slp && !costing_p)
11274 : 885 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
11275 : : }
11276 : :
11277 : 2296 : if (!slp && !costing_p)
11278 : 706 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
11279 : :
11280 : 2296 : if (costing_p && dump_enabled_p ())
11281 : 269 : dump_printf_loc (MSG_NOTE, vect_location,
11282 : : "vect_model_load_cost: inside_cost = %u, "
11283 : : "prologue_cost = %u .\n",
11284 : : inside_cost, prologue_cost);
11285 : 2296 : return true;
11286 : : }
11287 : :
11288 : 455698 : poly_uint64 group_elt = 0;
11289 : 455698 : unsigned int inside_cost = 0, prologue_cost = 0;
11290 : : /* For costing some adjacent vector loads, we'd like to cost with
11291 : : the total number of them once instead of cost each one by one. */
11292 : 455698 : unsigned int n_adjacent_loads = 0;
11293 : 949969 : for (j = 0; j < ncopies; j++)
11294 : : {
11295 : : /* 1. Create the vector or array pointer update chain. */
11296 : 494271 : if (j == 0 && !costing_p)
11297 : : {
11298 : 153985 : bool simd_lane_access_p
11299 : 153985 : = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0;
11300 : 153985 : if (simd_lane_access_p
11301 : 1709 : && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR
11302 : 1709 : && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0))
11303 : 1709 : && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info))
11304 : 1709 : && integer_zerop (DR_INIT (first_dr_info->dr))
11305 : 1709 : && alias_sets_conflict_p (get_alias_set (aggr_type),
11306 : 1709 : get_alias_set (TREE_TYPE (ref_type)))
11307 : 155694 : && (alignment_support_scheme == dr_aligned
11308 : 0 : || alignment_support_scheme == dr_unaligned_supported))
11309 : : {
11310 : 1709 : dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr));
11311 : 1709 : dataref_offset = build_int_cst (ref_type, 0);
11312 : : }
11313 : 152276 : else if (diff_first_stmt_info)
11314 : : {
11315 : 2602 : dataref_ptr
11316 : 2602 : = vect_create_data_ref_ptr (vinfo, first_stmt_info_for_drptr,
11317 : : aggr_type, at_loop, offset, &dummy,
11318 : : gsi, &ptr_incr, simd_lane_access_p,
11319 : : bump);
11320 : : /* Adjust the pointer by the difference to first_stmt. */
11321 : 2602 : data_reference_p ptrdr
11322 : : = STMT_VINFO_DATA_REF (first_stmt_info_for_drptr);
11323 : 2602 : tree diff
11324 : 2602 : = fold_convert (sizetype,
11325 : : size_binop (MINUS_EXPR,
11326 : : DR_INIT (first_dr_info->dr),
11327 : : DR_INIT (ptrdr)));
11328 : 2602 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11329 : : stmt_info, diff);
11330 : 2602 : if (alignment_support_scheme == dr_explicit_realign)
11331 : : {
11332 : 0 : msq = vect_setup_realignment (vinfo,
11333 : : first_stmt_info_for_drptr, gsi,
11334 : : &realignment_token,
11335 : : alignment_support_scheme,
11336 : : dataref_ptr, &at_loop);
11337 : 0 : gcc_assert (!compute_in_loop);
11338 : : }
11339 : : }
11340 : : else
11341 : 149674 : dataref_ptr
11342 : 149674 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
11343 : : at_loop,
11344 : : offset, &dummy, gsi, &ptr_incr,
11345 : : simd_lane_access_p, bump);
11346 : : }
11347 : 340286 : else if (!costing_p)
11348 : : {
11349 : 5349 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
11350 : 5349 : if (dataref_offset)
11351 : 488 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset,
11352 : : bump);
11353 : : else
11354 : 4861 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11355 : : stmt_info, bump);
11356 : : }
11357 : :
11358 : 494271 : if (grouped_load || slp_perm)
11359 : 62819 : dr_chain.create (vec_num);
11360 : :
11361 : 494271 : gimple *new_stmt = NULL;
11362 : 1371480 : for (i = 0; i < vec_num; i++)
11363 : : {
11364 : 877209 : tree final_mask = NULL_TREE;
11365 : 877209 : tree final_len = NULL_TREE;
11366 : 877209 : tree bias = NULL_TREE;
11367 : 877209 : if (!costing_p)
11368 : : {
11369 : 212462 : if (mask)
11370 : 542 : vec_mask = vec_masks[vec_num * j + i];
11371 : 212462 : if (loop_masks)
11372 : 9 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
11373 : 9 : vec_num * ncopies, vectype,
11374 : 9 : vec_num * j + i);
11375 : 212462 : if (vec_mask)
11376 : 542 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
11377 : : final_mask, vec_mask, gsi);
11378 : :
11379 : 212462 : if (i > 0)
11380 : 53128 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
11381 : : gsi, stmt_info, bump);
11382 : : }
11383 : :
11384 : : /* 2. Create the vector-load in the loop. */
11385 : 877209 : switch (alignment_support_scheme)
11386 : : {
11387 : 877209 : case dr_aligned:
11388 : 877209 : case dr_unaligned_supported:
11389 : 877209 : {
11390 : 877209 : if (costing_p)
11391 : : break;
11392 : :
11393 : 212462 : unsigned int misalign;
11394 : 212462 : unsigned HOST_WIDE_INT align;
11395 : 212462 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
11396 : 212462 : if (alignment_support_scheme == dr_aligned)
11397 : : misalign = 0;
11398 : 110674 : else if (misalignment == DR_MISALIGNMENT_UNKNOWN)
11399 : : {
11400 : 80465 : align
11401 : 80465 : = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
11402 : 80465 : misalign = 0;
11403 : : }
11404 : : else
11405 : 30209 : misalign = misalignment;
11406 : 212462 : if (dataref_offset == NULL_TREE
11407 : 210265 : && TREE_CODE (dataref_ptr) == SSA_NAME)
11408 : 128682 : set_ptr_info_alignment (get_ptr_info (dataref_ptr), align,
11409 : : misalign);
11410 : 212462 : align = least_bit_hwi (misalign | align);
11411 : :
11412 : : /* Compute IFN when LOOP_LENS or final_mask valid. */
11413 : 212462 : machine_mode vmode = TYPE_MODE (vectype);
11414 : 212462 : machine_mode new_vmode = vmode;
11415 : 212462 : internal_fn partial_ifn = IFN_LAST;
11416 : 212462 : if (loop_lens)
11417 : : {
11418 : 0 : opt_machine_mode new_ovmode
11419 : 0 : = get_len_load_store_mode (vmode, true, &partial_ifn);
11420 : 0 : new_vmode = new_ovmode.require ();
11421 : 0 : unsigned factor
11422 : 0 : = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode);
11423 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
11424 : 0 : vec_num * ncopies, vectype,
11425 : 0 : vec_num * j + i, factor);
11426 : : }
11427 : 212462 : else if (final_mask)
11428 : : {
11429 : 551 : if (!can_vec_mask_load_store_p (
11430 : 551 : vmode, TYPE_MODE (TREE_TYPE (final_mask)), true,
11431 : : &partial_ifn))
11432 : 0 : gcc_unreachable ();
11433 : : }
11434 : :
11435 : 212462 : if (partial_ifn == IFN_MASK_LEN_LOAD)
11436 : : {
11437 : 0 : if (!final_len)
11438 : : {
11439 : : /* Pass VF value to 'len' argument of
11440 : : MASK_LEN_LOAD if LOOP_LENS is invalid. */
11441 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
11442 : : }
11443 : 0 : if (!final_mask)
11444 : : {
11445 : : /* Pass all ones value to 'mask' argument of
11446 : : MASK_LEN_LOAD if final_mask is invalid. */
11447 : 0 : mask_vectype = truth_type_for (vectype);
11448 : 0 : final_mask = build_minus_one_cst (mask_vectype);
11449 : : }
11450 : : }
11451 : 212462 : if (final_len)
11452 : : {
11453 : 0 : signed char biasval
11454 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
11455 : :
11456 : 0 : bias = build_int_cst (intQI_type_node, biasval);
11457 : : }
11458 : :
11459 : 212462 : if (final_len)
11460 : : {
11461 : 0 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
11462 : 0 : gcall *call;
11463 : 0 : if (partial_ifn == IFN_MASK_LEN_LOAD)
11464 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_LOAD, 5,
11465 : : dataref_ptr, ptr,
11466 : : final_mask, final_len,
11467 : : bias);
11468 : : else
11469 : 0 : call = gimple_build_call_internal (IFN_LEN_LOAD, 4,
11470 : : dataref_ptr, ptr,
11471 : : final_len, bias);
11472 : 0 : gimple_call_set_nothrow (call, true);
11473 : 0 : new_stmt = call;
11474 : 0 : data_ref = NULL_TREE;
11475 : :
11476 : : /* Need conversion if it's wrapped with VnQI. */
11477 : 0 : if (vmode != new_vmode)
11478 : : {
11479 : 0 : tree new_vtype = build_vector_type_for_mode (
11480 : : unsigned_intQI_type_node, new_vmode);
11481 : 0 : tree var
11482 : 0 : = vect_get_new_ssa_name (new_vtype, vect_simple_var);
11483 : 0 : gimple_set_lhs (call, var);
11484 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call,
11485 : : gsi);
11486 : 0 : tree op = build1 (VIEW_CONVERT_EXPR, vectype, var);
11487 : 0 : new_stmt = gimple_build_assign (vec_dest,
11488 : : VIEW_CONVERT_EXPR, op);
11489 : : }
11490 : : }
11491 : 212462 : else if (final_mask)
11492 : : {
11493 : 551 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
11494 : 551 : gcall *call = gimple_build_call_internal (IFN_MASK_LOAD, 3,
11495 : : dataref_ptr, ptr,
11496 : : final_mask);
11497 : 551 : gimple_call_set_nothrow (call, true);
11498 : 551 : new_stmt = call;
11499 : 551 : data_ref = NULL_TREE;
11500 : : }
11501 : : else
11502 : : {
11503 : 211911 : tree ltype = vectype;
11504 : 211911 : tree new_vtype = NULL_TREE;
11505 : 211911 : unsigned HOST_WIDE_INT gap = DR_GROUP_GAP (first_stmt_info);
11506 : 211911 : unsigned int vect_align
11507 : 211911 : = vect_known_alignment_in_bytes (first_dr_info, vectype);
11508 : 211911 : unsigned int scalar_dr_size
11509 : 211911 : = vect_get_scalar_dr_size (first_dr_info);
11510 : : /* If there's no peeling for gaps but we have a gap
11511 : : with slp loads then load the lower half of the
11512 : : vector only. See get_group_load_store_type for
11513 : : when we apply this optimization. */
11514 : 211911 : if (slp
11515 : 211911 : && loop_vinfo
11516 : 9881 : && !LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo) && gap != 0
11517 : 104 : && known_eq (nunits, (group_size - gap) * 2)
11518 : 32 : && known_eq (nunits, group_size)
11519 : 211943 : && gap >= (vect_align / scalar_dr_size))
11520 : : {
11521 : 21 : tree half_vtype;
11522 : 21 : new_vtype
11523 : 21 : = vector_vector_composition_type (vectype, 2,
11524 : : &half_vtype);
11525 : 21 : if (new_vtype != NULL_TREE)
11526 : 21 : ltype = half_vtype;
11527 : : }
11528 : : /* Try to use a single smaller load when we are about
11529 : : to load excess elements compared to the unrolled
11530 : : scalar loop.
11531 : : ??? This should cover the above case as well. */
11532 : 211890 : else if (known_gt ((vec_num * j + i + 1) * nunits,
11533 : : (group_size * vf - gap)))
11534 : : {
11535 : 1030 : if (known_ge ((vec_num * j + i + 1) * nunits
11536 : : - (group_size * vf - gap), nunits))
11537 : : /* DR will be unused. */
11538 : : ltype = NULL_TREE;
11539 : 861 : else if (known_ge (vect_align,
11540 : : tree_to_poly_uint64
11541 : : (TYPE_SIZE_UNIT (vectype))))
11542 : : /* Aligned access to excess elements is OK if
11543 : : at least one element is accessed in the
11544 : : scalar loop. */
11545 : : ;
11546 : : else
11547 : : {
11548 : 595 : auto remain
11549 : 595 : = ((group_size * vf - gap)
11550 : 595 : - (vec_num * j + i) * nunits);
11551 : : /* remain should now be > 0 and < nunits. */
11552 : 595 : unsigned num;
11553 : 595 : if (constant_multiple_p (nunits, remain, &num))
11554 : : {
11555 : 245 : tree ptype;
11556 : 245 : new_vtype
11557 : 245 : = vector_vector_composition_type (vectype,
11558 : : num,
11559 : : &ptype);
11560 : 245 : if (new_vtype)
11561 : 245 : ltype = ptype;
11562 : : }
11563 : : /* Else use multiple loads or a masked load? */
11564 : : }
11565 : : }
11566 : 211911 : tree offset
11567 : 211911 : = (dataref_offset ? dataref_offset
11568 : 209714 : : build_int_cst (ref_type, 0));
11569 : 211911 : if (!ltype)
11570 : : ;
11571 : 211742 : else if (ltype != vectype
11572 : 266 : && memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11573 : : {
11574 : 12 : poly_uint64 gap_offset
11575 : 12 : = (tree_to_poly_uint64 (TYPE_SIZE_UNIT (vectype))
11576 : 12 : - tree_to_poly_uint64 (TYPE_SIZE_UNIT (ltype)));
11577 : 12 : tree gapcst = build_int_cstu (ref_type, gap_offset);
11578 : 12 : offset = size_binop (PLUS_EXPR, offset, gapcst);
11579 : : }
11580 : 211911 : if (ltype)
11581 : : {
11582 : 211742 : data_ref
11583 : 211742 : = fold_build2 (MEM_REF, ltype, dataref_ptr, offset);
11584 : 211742 : if (alignment_support_scheme == dr_aligned)
11585 : : ;
11586 : : else
11587 : 110115 : TREE_TYPE (data_ref)
11588 : 220230 : = build_aligned_type (TREE_TYPE (data_ref),
11589 : : align * BITS_PER_UNIT);
11590 : : }
11591 : 211911 : if (!ltype)
11592 : 169 : data_ref = build_constructor (vectype, NULL);
11593 : 211742 : else if (ltype != vectype)
11594 : : {
11595 : 266 : vect_copy_ref_info (data_ref,
11596 : 266 : DR_REF (first_dr_info->dr));
11597 : 266 : tree tem = make_ssa_name (ltype);
11598 : 266 : new_stmt = gimple_build_assign (tem, data_ref);
11599 : 266 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
11600 : : gsi);
11601 : 266 : data_ref = NULL;
11602 : 266 : vec<constructor_elt, va_gc> *v;
11603 : : /* We've computed 'num' above to statically two
11604 : : or via constant_multiple_p. */
11605 : 266 : unsigned num
11606 : 266 : = (exact_div (tree_to_poly_uint64
11607 : 266 : (TYPE_SIZE_UNIT (vectype)),
11608 : : tree_to_poly_uint64
11609 : 266 : (TYPE_SIZE_UNIT (ltype)))
11610 : 266 : .to_constant ());
11611 : 266 : vec_alloc (v, num);
11612 : 266 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11613 : : {
11614 : 42 : while (--num)
11615 : 42 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
11616 : : build_zero_cst (ltype));
11617 : 12 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem);
11618 : : }
11619 : : else
11620 : : {
11621 : 254 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem);
11622 : 254 : while (--num)
11623 : 734 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
11624 : : build_zero_cst (ltype));
11625 : : }
11626 : 266 : gcc_assert (new_vtype != NULL_TREE);
11627 : 266 : if (new_vtype == vectype)
11628 : 260 : new_stmt = gimple_build_assign (
11629 : : vec_dest, build_constructor (vectype, v));
11630 : : else
11631 : : {
11632 : 6 : tree new_vname = make_ssa_name (new_vtype);
11633 : 6 : new_stmt = gimple_build_assign (
11634 : : new_vname, build_constructor (new_vtype, v));
11635 : 6 : vect_finish_stmt_generation (vinfo, stmt_info,
11636 : : new_stmt, gsi);
11637 : 6 : new_stmt = gimple_build_assign (
11638 : : vec_dest,
11639 : : build1 (VIEW_CONVERT_EXPR, vectype, new_vname));
11640 : : }
11641 : : }
11642 : : }
11643 : : break;
11644 : : }
11645 : 0 : case dr_explicit_realign:
11646 : 0 : {
11647 : 0 : if (costing_p)
11648 : : break;
11649 : 0 : tree ptr, bump;
11650 : :
11651 : 0 : tree vs = size_int (TYPE_VECTOR_SUBPARTS (vectype));
11652 : :
11653 : 0 : if (compute_in_loop)
11654 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info, gsi,
11655 : : &realignment_token,
11656 : : dr_explicit_realign,
11657 : : dataref_ptr, NULL);
11658 : :
11659 : 0 : if (TREE_CODE (dataref_ptr) == SSA_NAME)
11660 : 0 : ptr = copy_ssa_name (dataref_ptr);
11661 : : else
11662 : 0 : ptr = make_ssa_name (TREE_TYPE (dataref_ptr));
11663 : : // For explicit realign the target alignment should be
11664 : : // known at compile time.
11665 : 0 : unsigned HOST_WIDE_INT align
11666 : 0 : = DR_TARGET_ALIGNMENT (first_dr_info).to_constant ();
11667 : 0 : new_stmt = gimple_build_assign (
11668 : : ptr, BIT_AND_EXPR, dataref_ptr,
11669 : 0 : build_int_cst (TREE_TYPE (dataref_ptr),
11670 : 0 : -(HOST_WIDE_INT) align));
11671 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11672 : 0 : data_ref
11673 : 0 : = build2 (MEM_REF, vectype, ptr, build_int_cst (ref_type, 0));
11674 : 0 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
11675 : 0 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11676 : 0 : new_stmt = gimple_build_assign (vec_dest, data_ref);
11677 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
11678 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
11679 : 0 : gimple_move_vops (new_stmt, stmt_info->stmt);
11680 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11681 : 0 : msq = new_temp;
11682 : :
11683 : 0 : bump = size_binop (MULT_EXPR, vs, TYPE_SIZE_UNIT (elem_type));
11684 : 0 : bump = size_binop (MINUS_EXPR, bump, size_one_node);
11685 : 0 : ptr = bump_vector_ptr (vinfo, dataref_ptr, NULL, gsi, stmt_info,
11686 : : bump);
11687 : 0 : new_stmt = gimple_build_assign (
11688 : : NULL_TREE, BIT_AND_EXPR, ptr,
11689 : 0 : build_int_cst (TREE_TYPE (ptr), -(HOST_WIDE_INT) align));
11690 : 0 : if (TREE_CODE (ptr) == SSA_NAME)
11691 : 0 : ptr = copy_ssa_name (ptr, new_stmt);
11692 : : else
11693 : 0 : ptr = make_ssa_name (TREE_TYPE (ptr), new_stmt);
11694 : 0 : gimple_assign_set_lhs (new_stmt, ptr);
11695 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11696 : 0 : data_ref
11697 : 0 : = build2 (MEM_REF, vectype, ptr, build_int_cst (ref_type, 0));
11698 : 0 : break;
11699 : : }
11700 : 0 : case dr_explicit_realign_optimized:
11701 : 0 : {
11702 : 0 : if (costing_p)
11703 : : break;
11704 : 0 : if (TREE_CODE (dataref_ptr) == SSA_NAME)
11705 : 0 : new_temp = copy_ssa_name (dataref_ptr);
11706 : : else
11707 : 0 : new_temp = make_ssa_name (TREE_TYPE (dataref_ptr));
11708 : : // We should only be doing this if we know the target
11709 : : // alignment at compile time.
11710 : 0 : unsigned HOST_WIDE_INT align
11711 : 0 : = DR_TARGET_ALIGNMENT (first_dr_info).to_constant ();
11712 : 0 : new_stmt = gimple_build_assign (
11713 : : new_temp, BIT_AND_EXPR, dataref_ptr,
11714 : 0 : build_int_cst (TREE_TYPE (dataref_ptr),
11715 : 0 : -(HOST_WIDE_INT) align));
11716 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11717 : 0 : data_ref = build2 (MEM_REF, vectype, new_temp,
11718 : 0 : build_int_cst (ref_type, 0));
11719 : 0 : break;
11720 : : }
11721 : 0 : default:
11722 : 0 : gcc_unreachable ();
11723 : : }
11724 : :
11725 : : /* One common place to cost the above vect load for different
11726 : : alignment support schemes. */
11727 : 877209 : if (costing_p)
11728 : : {
11729 : : /* For VMAT_CONTIGUOUS_PERMUTE if it's grouped load, we
11730 : : only need to take care of the first stmt, whose
11731 : : stmt_info is first_stmt_info, vec_num iterating on it
11732 : : will cover the cost for the remaining, it's consistent
11733 : : with transforming. For the prologue cost for realign,
11734 : : we only need to count it once for the whole group. */
11735 : 664747 : bool first_stmt_info_p = first_stmt_info == stmt_info;
11736 : 664747 : bool add_realign_cost = first_stmt_info_p && i == 0;
11737 : 664747 : if (memory_access_type == VMAT_CONTIGUOUS
11738 : 98271 : || memory_access_type == VMAT_CONTIGUOUS_REVERSE
11739 : 95710 : || (memory_access_type == VMAT_CONTIGUOUS_PERMUTE
11740 : 95710 : && (!grouped_load || first_stmt_info_p)))
11741 : : {
11742 : : /* Leave realign cases alone to keep them simple. */
11743 : 616784 : if (alignment_support_scheme == dr_explicit_realign_optimized
11744 : : || alignment_support_scheme == dr_explicit_realign)
11745 : 0 : vect_get_load_cost (vinfo, stmt_info, 1,
11746 : : alignment_support_scheme, misalignment,
11747 : : add_realign_cost, &inside_cost,
11748 : : &prologue_cost, cost_vec, cost_vec,
11749 : : true);
11750 : : else
11751 : 616784 : n_adjacent_loads++;
11752 : : }
11753 : : }
11754 : : else
11755 : : {
11756 : 212462 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11757 : : /* DATA_REF is null if we've already built the statement. */
11758 : 212462 : if (data_ref)
11759 : : {
11760 : 211645 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
11761 : 211645 : new_stmt = gimple_build_assign (vec_dest, data_ref);
11762 : : }
11763 : 212462 : new_temp = make_ssa_name (vec_dest, new_stmt);
11764 : 212462 : gimple_set_lhs (new_stmt, new_temp);
11765 : 212462 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11766 : : }
11767 : :
11768 : : /* 3. Handle explicit realignment if necessary/supported.
11769 : : Create in loop:
11770 : : vec_dest = realign_load (msq, lsq, realignment_token) */
11771 : 877209 : if (!costing_p
11772 : 212462 : && (alignment_support_scheme == dr_explicit_realign_optimized
11773 : : || alignment_support_scheme == dr_explicit_realign))
11774 : : {
11775 : 0 : lsq = gimple_assign_lhs (new_stmt);
11776 : 0 : if (!realignment_token)
11777 : 0 : realignment_token = dataref_ptr;
11778 : 0 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11779 : 0 : new_stmt = gimple_build_assign (vec_dest, REALIGN_LOAD_EXPR, msq,
11780 : : lsq, realignment_token);
11781 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
11782 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
11783 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11784 : :
11785 : 0 : if (alignment_support_scheme == dr_explicit_realign_optimized)
11786 : : {
11787 : 0 : gcc_assert (phi);
11788 : 0 : if (i == vec_num - 1 && j == ncopies - 1)
11789 : 0 : add_phi_arg (phi, lsq, loop_latch_edge (containing_loop),
11790 : : UNKNOWN_LOCATION);
11791 : : msq = lsq;
11792 : : }
11793 : : }
11794 : :
11795 : 877209 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11796 : : {
11797 : 3845 : if (costing_p)
11798 : 2561 : inside_cost = record_stmt_cost (cost_vec, 1, vec_perm,
11799 : : stmt_info, 0, vect_body);
11800 : : else
11801 : : {
11802 : 1284 : tree perm_mask = perm_mask_for_reverse (vectype);
11803 : 1284 : new_temp = permute_vec_elements (vinfo, new_temp, new_temp,
11804 : : perm_mask, stmt_info, gsi);
11805 : 1284 : new_stmt = SSA_NAME_DEF_STMT (new_temp);
11806 : : }
11807 : : }
11808 : :
11809 : : /* Collect vector loads and later create their permutation in
11810 : : vect_transform_grouped_load (). */
11811 : 877209 : if (!costing_p && (grouped_load || slp_perm))
11812 : 47289 : dr_chain.quick_push (new_temp);
11813 : :
11814 : : /* Store vector loads in the corresponding SLP_NODE. */
11815 : 877209 : if (!costing_p && slp && !slp_perm)
11816 : 112566 : slp_node->push_vec_def (new_stmt);
11817 : :
11818 : : /* With SLP permutation we load the gaps as well, without
11819 : : we need to skip the gaps after we manage to fully load
11820 : : all elements. group_gap_adj is DR_GROUP_SIZE here. */
11821 : 877209 : group_elt += nunits;
11822 : 877209 : if (!costing_p
11823 : 212462 : && maybe_ne (group_gap_adj, 0U)
11824 : 20885 : && !slp_perm
11825 : 896371 : && known_eq (group_elt, group_size - group_gap_adj))
11826 : : {
11827 : 16286 : poly_wide_int bump_val
11828 : 16286 : = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj);
11829 : 16286 : if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step)
11830 : : == -1)
11831 : 0 : bump_val = -bump_val;
11832 : 16286 : tree bump = wide_int_to_tree (sizetype, bump_val);
11833 : 16286 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11834 : : stmt_info, bump);
11835 : 16286 : group_elt = 0;
11836 : 16286 : }
11837 : : }
11838 : : /* Bump the vector pointer to account for a gap or for excess
11839 : : elements loaded for a permuted SLP load. */
11840 : 494271 : if (!costing_p
11841 : 159334 : && maybe_ne (group_gap_adj, 0U)
11842 : 510666 : && slp_perm)
11843 : : {
11844 : 109 : poly_wide_int bump_val
11845 : 109 : = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj);
11846 : 109 : if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step) == -1)
11847 : 12 : bump_val = -bump_val;
11848 : 109 : tree bump = wide_int_to_tree (sizetype, bump_val);
11849 : 109 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11850 : : stmt_info, bump);
11851 : 109 : }
11852 : :
11853 : 494271 : if (slp && !slp_perm)
11854 : 228120 : continue;
11855 : :
11856 : 266151 : if (slp_perm)
11857 : : {
11858 : 26743 : unsigned n_perms;
11859 : : /* For SLP we know we've seen all possible uses of dr_chain so
11860 : : direct vect_transform_slp_perm_load to DCE the unused parts.
11861 : : ??? This is a hack to prevent compile-time issues as seen
11862 : : in PR101120 and friends. */
11863 : 26743 : if (costing_p)
11864 : : {
11865 : 18659 : vect_transform_slp_perm_load (vinfo, slp_node, vNULL, nullptr, vf,
11866 : : true, &n_perms, nullptr);
11867 : 18659 : inside_cost = record_stmt_cost (cost_vec, n_perms, vec_perm,
11868 : : stmt_info, 0, vect_body);
11869 : : }
11870 : : else
11871 : : {
11872 : 8084 : bool ok = vect_transform_slp_perm_load (vinfo, slp_node, dr_chain,
11873 : : gsi, vf, false, &n_perms,
11874 : : nullptr, true);
11875 : 8084 : gcc_assert (ok);
11876 : : }
11877 : : }
11878 : : else
11879 : : {
11880 : 239408 : if (grouped_load)
11881 : : {
11882 : 36076 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS_PERMUTE);
11883 : : /* We assume that the cost of a single load-lanes instruction
11884 : : is equivalent to the cost of DR_GROUP_SIZE separate loads.
11885 : : If a grouped access is instead being provided by a
11886 : : load-and-permute operation, include the cost of the
11887 : : permutes. */
11888 : 36076 : if (costing_p && first_stmt_info == stmt_info)
11889 : : {
11890 : : /* Uses an even and odd extract operations or shuffle
11891 : : operations for each needed permute. */
11892 : 16975 : int group_size = DR_GROUP_SIZE (first_stmt_info);
11893 : 16975 : int nstmts = ceil_log2 (group_size) * group_size;
11894 : 16975 : inside_cost += record_stmt_cost (cost_vec, nstmts, vec_perm,
11895 : : stmt_info, 0, vect_body);
11896 : :
11897 : 16975 : if (dump_enabled_p ())
11898 : 1554 : dump_printf_loc (MSG_NOTE, vect_location,
11899 : : "vect_model_load_cost:"
11900 : : "strided group_size = %d .\n",
11901 : : group_size);
11902 : : }
11903 : 19101 : else if (!costing_p)
11904 : : {
11905 : 3281 : vect_transform_grouped_load (vinfo, stmt_info, dr_chain,
11906 : : group_size, gsi);
11907 : 3281 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
11908 : : }
11909 : : }
11910 : 203332 : else if (!costing_p)
11911 : 52607 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
11912 : : }
11913 : 266151 : dr_chain.release ();
11914 : : }
11915 : 455698 : if (!slp && !costing_p)
11916 : 50539 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
11917 : :
11918 : 455698 : if (costing_p)
11919 : : {
11920 : 301713 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS
11921 : : || memory_access_type == VMAT_CONTIGUOUS_REVERSE
11922 : : || memory_access_type == VMAT_CONTIGUOUS_PERMUTE);
11923 : 301713 : if (n_adjacent_loads > 0)
11924 : 288353 : vect_get_load_cost (vinfo, stmt_info, n_adjacent_loads,
11925 : : alignment_support_scheme, misalignment, false,
11926 : : &inside_cost, &prologue_cost, cost_vec, cost_vec,
11927 : : true);
11928 : 301713 : if (dump_enabled_p ())
11929 : 22701 : dump_printf_loc (MSG_NOTE, vect_location,
11930 : : "vect_model_load_cost: inside_cost = %u, "
11931 : : "prologue_cost = %u .\n",
11932 : : inside_cost, prologue_cost);
11933 : : }
11934 : :
11935 : : return true;
11936 : 457994 : }
11937 : :
11938 : : /* Function vect_is_simple_cond.
11939 : :
11940 : : Input:
11941 : : LOOP - the loop that is being vectorized.
11942 : : COND - Condition that is checked for simple use.
11943 : :
11944 : : Output:
11945 : : *COMP_VECTYPE - the vector type for the comparison.
11946 : : *DTS - The def types for the arguments of the comparison
11947 : :
11948 : : Returns whether a COND can be vectorized. Checks whether
11949 : : condition operands are supportable using vec_is_simple_use. */
11950 : :
11951 : : static bool
11952 : 17128 : vect_is_simple_cond (tree cond, vec_info *vinfo, stmt_vec_info stmt_info,
11953 : : slp_tree slp_node, tree *comp_vectype,
11954 : : enum vect_def_type *dts, tree vectype)
11955 : : {
11956 : 17128 : tree lhs, rhs;
11957 : 17128 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
11958 : 17128 : slp_tree slp_op;
11959 : :
11960 : : /* Mask case. */
11961 : 17128 : if (TREE_CODE (cond) == SSA_NAME
11962 : 17128 : && VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (cond)))
11963 : : {
11964 : 15319 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &cond,
11965 : : &slp_op, &dts[0], comp_vectype)
11966 : 15319 : || !*comp_vectype
11967 : 30612 : || !VECTOR_BOOLEAN_TYPE_P (*comp_vectype))
11968 : : return false;
11969 : : return true;
11970 : : }
11971 : :
11972 : 1809 : if (!COMPARISON_CLASS_P (cond))
11973 : : return false;
11974 : :
11975 : 1802 : lhs = TREE_OPERAND (cond, 0);
11976 : 1802 : rhs = TREE_OPERAND (cond, 1);
11977 : :
11978 : 1802 : if (TREE_CODE (lhs) == SSA_NAME)
11979 : : {
11980 : 1802 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0,
11981 : : &lhs, &slp_op, &dts[0], &vectype1))
11982 : : return false;
11983 : : }
11984 : 0 : else if (TREE_CODE (lhs) == INTEGER_CST || TREE_CODE (lhs) == REAL_CST
11985 : 0 : || TREE_CODE (lhs) == FIXED_CST)
11986 : 0 : dts[0] = vect_constant_def;
11987 : : else
11988 : : return false;
11989 : :
11990 : 1802 : if (TREE_CODE (rhs) == SSA_NAME)
11991 : : {
11992 : 0 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1,
11993 : : &rhs, &slp_op, &dts[1], &vectype2))
11994 : : return false;
11995 : : }
11996 : 1802 : else if (TREE_CODE (rhs) == INTEGER_CST || TREE_CODE (rhs) == REAL_CST
11997 : 0 : || TREE_CODE (rhs) == FIXED_CST)
11998 : 1802 : dts[1] = vect_constant_def;
11999 : : else
12000 : : return false;
12001 : :
12002 : 1237 : if (vectype1 && vectype2
12003 : 1802 : && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1),
12004 : 0 : TYPE_VECTOR_SUBPARTS (vectype2)))
12005 : 0 : return false;
12006 : :
12007 : 1802 : *comp_vectype = vectype1 ? vectype1 : vectype2;
12008 : : /* Invariant comparison. */
12009 : 1802 : if (! *comp_vectype)
12010 : : {
12011 : 565 : tree scalar_type = TREE_TYPE (lhs);
12012 : 565 : if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type))
12013 : 565 : *comp_vectype = truth_type_for (vectype);
12014 : : else
12015 : : {
12016 : : /* If we can widen the comparison to match vectype do so. */
12017 : 0 : if (INTEGRAL_TYPE_P (scalar_type)
12018 : 0 : && !slp_node
12019 : 0 : && tree_int_cst_lt (TYPE_SIZE (scalar_type),
12020 : 0 : TYPE_SIZE (TREE_TYPE (vectype))))
12021 : 0 : scalar_type = build_nonstandard_integer_type
12022 : 0 : (vector_element_bits (vectype), TYPE_UNSIGNED (scalar_type));
12023 : 0 : *comp_vectype = get_vectype_for_scalar_type (vinfo, scalar_type,
12024 : : slp_node);
12025 : : }
12026 : : }
12027 : :
12028 : : return true;
12029 : : }
12030 : :
12031 : : /* vectorizable_condition.
12032 : :
12033 : : Check if STMT_INFO is conditional modify expression that can be vectorized.
12034 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
12035 : : stmt using VEC_COND_EXPR to replace it, put it in VEC_STMT, and insert it
12036 : : at GSI.
12037 : :
12038 : : When STMT_INFO is vectorized as a nested cycle, for_reduction is true.
12039 : :
12040 : : Return true if STMT_INFO is vectorizable in this way. */
12041 : :
12042 : : static bool
12043 : 271901 : vectorizable_condition (vec_info *vinfo,
12044 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
12045 : : gimple **vec_stmt,
12046 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12047 : : {
12048 : 271901 : tree scalar_dest = NULL_TREE;
12049 : 271901 : tree vec_dest = NULL_TREE;
12050 : 271901 : tree cond_expr, cond_expr0 = NULL_TREE, cond_expr1 = NULL_TREE;
12051 : 271901 : tree then_clause, else_clause;
12052 : 271901 : tree comp_vectype = NULL_TREE;
12053 : 271901 : tree vec_cond_lhs = NULL_TREE, vec_cond_rhs = NULL_TREE;
12054 : 271901 : tree vec_then_clause = NULL_TREE, vec_else_clause = NULL_TREE;
12055 : 271901 : tree vec_compare;
12056 : 271901 : tree new_temp;
12057 : 271901 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
12058 : 271901 : enum vect_def_type dts[4]
12059 : : = {vect_unknown_def_type, vect_unknown_def_type,
12060 : : vect_unknown_def_type, vect_unknown_def_type};
12061 : 271901 : int ndts = 4;
12062 : 271901 : int ncopies;
12063 : 271901 : int vec_num;
12064 : 271901 : enum tree_code code, cond_code, bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
12065 : 271901 : int i;
12066 : 271901 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
12067 : 271901 : vec<tree> vec_oprnds0 = vNULL;
12068 : 271901 : vec<tree> vec_oprnds1 = vNULL;
12069 : 271901 : vec<tree> vec_oprnds2 = vNULL;
12070 : 271901 : vec<tree> vec_oprnds3 = vNULL;
12071 : 271901 : tree vec_cmp_type;
12072 : 271901 : bool masked = false;
12073 : :
12074 : 271901 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
12075 : : return false;
12076 : :
12077 : : /* Is vectorizable conditional operation? */
12078 : 443345 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
12079 : 187911 : if (!stmt)
12080 : : return false;
12081 : :
12082 : 187911 : code = gimple_assign_rhs_code (stmt);
12083 : 187911 : if (code != COND_EXPR)
12084 : : return false;
12085 : :
12086 : 17156 : stmt_vec_info reduc_info = NULL;
12087 : 17156 : int reduc_index = -1;
12088 : 17156 : vect_reduction_type reduction_type = TREE_CODE_REDUCTION;
12089 : 17156 : bool for_reduction
12090 : 17156 : = STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)) != NULL;
12091 : 17156 : if (for_reduction)
12092 : : {
12093 : 655 : if (slp_node)
12094 : : return false;
12095 : 655 : reduc_info = info_for_reduction (vinfo, stmt_info);
12096 : 655 : reduction_type = STMT_VINFO_REDUC_TYPE (reduc_info);
12097 : 655 : reduc_index = STMT_VINFO_REDUC_IDX (stmt_info);
12098 : 655 : gcc_assert (reduction_type != EXTRACT_LAST_REDUCTION
12099 : : || reduc_index != -1);
12100 : : }
12101 : : else
12102 : : {
12103 : 16501 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
12104 : : return false;
12105 : : }
12106 : :
12107 : 17156 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
12108 : 17156 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
12109 : :
12110 : 17156 : if (slp_node)
12111 : : {
12112 : 982 : ncopies = 1;
12113 : 982 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
12114 : : }
12115 : : else
12116 : : {
12117 : 16174 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
12118 : 16174 : vec_num = 1;
12119 : : }
12120 : :
12121 : 17156 : gcc_assert (ncopies >= 1);
12122 : 17156 : if (for_reduction && ncopies > 1)
12123 : : return false; /* FORNOW */
12124 : :
12125 : 17128 : cond_expr = gimple_assign_rhs1 (stmt);
12126 : :
12127 : 17128 : if (!vect_is_simple_cond (cond_expr, vinfo, stmt_info, slp_node,
12128 : : &comp_vectype, &dts[0], vectype)
12129 : 17128 : || !comp_vectype)
12130 : : return false;
12131 : :
12132 : 17095 : unsigned op_adjust = COMPARISON_CLASS_P (cond_expr) ? 1 : 0;
12133 : 17095 : slp_tree then_slp_node, else_slp_node;
12134 : 17095 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1 + op_adjust,
12135 : : &then_clause, &then_slp_node, &dts[2], &vectype1))
12136 : : return false;
12137 : 17095 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 2 + op_adjust,
12138 : : &else_clause, &else_slp_node, &dts[3], &vectype2))
12139 : : return false;
12140 : :
12141 : 17095 : if (vectype1 && !useless_type_conversion_p (vectype, vectype1))
12142 : : return false;
12143 : :
12144 : 17095 : if (vectype2 && !useless_type_conversion_p (vectype, vectype2))
12145 : : return false;
12146 : :
12147 : 17095 : masked = !COMPARISON_CLASS_P (cond_expr);
12148 : 17095 : vec_cmp_type = truth_type_for (comp_vectype);
12149 : :
12150 : 17095 : if (vec_cmp_type == NULL_TREE)
12151 : : return false;
12152 : :
12153 : 17095 : cond_code = TREE_CODE (cond_expr);
12154 : 17095 : if (!masked)
12155 : : {
12156 : 1802 : cond_expr0 = TREE_OPERAND (cond_expr, 0);
12157 : 1802 : cond_expr1 = TREE_OPERAND (cond_expr, 1);
12158 : : }
12159 : :
12160 : : /* For conditional reductions, the "then" value needs to be the candidate
12161 : : value calculated by this iteration while the "else" value needs to be
12162 : : the result carried over from previous iterations. If the COND_EXPR
12163 : : is the other way around, we need to swap it. */
12164 : 17095 : bool must_invert_cmp_result = false;
12165 : 17095 : if (reduction_type == EXTRACT_LAST_REDUCTION && reduc_index == 1)
12166 : : {
12167 : 0 : if (masked)
12168 : : must_invert_cmp_result = true;
12169 : : else
12170 : : {
12171 : 0 : bool honor_nans = HONOR_NANS (TREE_TYPE (cond_expr0));
12172 : 0 : tree_code new_code = invert_tree_comparison (cond_code, honor_nans);
12173 : 0 : if (new_code == ERROR_MARK)
12174 : : must_invert_cmp_result = true;
12175 : : else
12176 : : {
12177 : 0 : cond_code = new_code;
12178 : : /* Make sure we don't accidentally use the old condition. */
12179 : 0 : cond_expr = NULL_TREE;
12180 : : }
12181 : : }
12182 : 0 : std::swap (then_clause, else_clause);
12183 : : }
12184 : :
12185 : 17095 : if (!masked && VECTOR_BOOLEAN_TYPE_P (comp_vectype))
12186 : : {
12187 : : /* Boolean values may have another representation in vectors
12188 : : and therefore we prefer bit operations over comparison for
12189 : : them (which also works for scalar masks). We store opcodes
12190 : : to use in bitop1 and bitop2. Statement is vectorized as
12191 : : BITOP2 (rhs1 BITOP1 rhs2) or rhs1 BITOP2 (BITOP1 rhs2)
12192 : : depending on bitop1 and bitop2 arity. */
12193 : 565 : switch (cond_code)
12194 : : {
12195 : : case GT_EXPR:
12196 : : bitop1 = BIT_NOT_EXPR;
12197 : : bitop2 = BIT_AND_EXPR;
12198 : : break;
12199 : 0 : case GE_EXPR:
12200 : 0 : bitop1 = BIT_NOT_EXPR;
12201 : 0 : bitop2 = BIT_IOR_EXPR;
12202 : 0 : break;
12203 : 0 : case LT_EXPR:
12204 : 0 : bitop1 = BIT_NOT_EXPR;
12205 : 0 : bitop2 = BIT_AND_EXPR;
12206 : 0 : std::swap (cond_expr0, cond_expr1);
12207 : 0 : break;
12208 : 0 : case LE_EXPR:
12209 : 0 : bitop1 = BIT_NOT_EXPR;
12210 : 0 : bitop2 = BIT_IOR_EXPR;
12211 : 0 : std::swap (cond_expr0, cond_expr1);
12212 : 0 : break;
12213 : 565 : case NE_EXPR:
12214 : 565 : bitop1 = BIT_XOR_EXPR;
12215 : 565 : break;
12216 : 0 : case EQ_EXPR:
12217 : 0 : bitop1 = BIT_XOR_EXPR;
12218 : 0 : bitop2 = BIT_NOT_EXPR;
12219 : 0 : break;
12220 : : default:
12221 : : return false;
12222 : : }
12223 : : cond_code = SSA_NAME;
12224 : : }
12225 : :
12226 : 17095 : if (TREE_CODE_CLASS (cond_code) == tcc_comparison
12227 : 1237 : && reduction_type == EXTRACT_LAST_REDUCTION
12228 : 17095 : && !expand_vec_cmp_expr_p (comp_vectype, vec_cmp_type, cond_code))
12229 : : {
12230 : 0 : if (dump_enabled_p ())
12231 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12232 : : "reduction comparison operation not supported.\n");
12233 : 0 : return false;
12234 : : }
12235 : :
12236 : 17095 : if (!vec_stmt)
12237 : : {
12238 : 12112 : if (bitop1 != NOP_EXPR)
12239 : : {
12240 : 463 : machine_mode mode = TYPE_MODE (comp_vectype);
12241 : 463 : optab optab;
12242 : :
12243 : 463 : optab = optab_for_tree_code (bitop1, comp_vectype, optab_default);
12244 : 463 : if (!optab || optab_handler (optab, mode) == CODE_FOR_nothing)
12245 : 46 : return false;
12246 : :
12247 : 417 : if (bitop2 != NOP_EXPR)
12248 : : {
12249 : 0 : optab = optab_for_tree_code (bitop2, comp_vectype,
12250 : : optab_default);
12251 : 0 : if (!optab || optab_handler (optab, mode) == CODE_FOR_nothing)
12252 : 0 : return false;
12253 : : }
12254 : : }
12255 : :
12256 : 12066 : vect_cost_for_stmt kind = vector_stmt;
12257 : 12066 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12258 : : /* Count one reduction-like operation per vector. */
12259 : : kind = vec_to_scalar;
12260 : 12066 : else if (!expand_vec_cond_expr_p (vectype, comp_vectype, cond_code)
12261 : 12066 : && (masked
12262 : 513 : || (!expand_vec_cmp_expr_p (comp_vectype, vec_cmp_type,
12263 : : cond_code)
12264 : 37 : || !expand_vec_cond_expr_p (vectype, vec_cmp_type,
12265 : : ERROR_MARK))))
12266 : 514 : return false;
12267 : :
12268 : 11552 : if (slp_node
12269 : 12156 : && (!vect_maybe_update_slp_op_vectype
12270 : 604 : (SLP_TREE_CHILDREN (slp_node)[0], comp_vectype)
12271 : 536 : || (op_adjust == 1
12272 : 67 : && !vect_maybe_update_slp_op_vectype
12273 : 67 : (SLP_TREE_CHILDREN (slp_node)[1], comp_vectype))
12274 : 536 : || !vect_maybe_update_slp_op_vectype (then_slp_node, vectype)
12275 : 536 : || !vect_maybe_update_slp_op_vectype (else_slp_node, vectype)))
12276 : : {
12277 : 68 : if (dump_enabled_p ())
12278 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12279 : : "incompatible vector types for invariants\n");
12280 : 68 : return false;
12281 : : }
12282 : :
12283 : 11484 : if (loop_vinfo && for_reduction
12284 : 440 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
12285 : : {
12286 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12287 : : {
12288 : 0 : if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST,
12289 : : vectype, OPTIMIZE_FOR_SPEED))
12290 : 0 : vect_record_loop_len (loop_vinfo,
12291 : : &LOOP_VINFO_LENS (loop_vinfo),
12292 : 0 : ncopies * vec_num, vectype, 1);
12293 : : else
12294 : 0 : vect_record_loop_mask (loop_vinfo,
12295 : : &LOOP_VINFO_MASKS (loop_vinfo),
12296 : 0 : ncopies * vec_num, vectype, NULL);
12297 : : }
12298 : : /* Extra inactive lanes should be safe for vect_nested_cycle. */
12299 : 0 : else if (STMT_VINFO_DEF_TYPE (reduc_info) != vect_nested_cycle)
12300 : : {
12301 : 0 : if (dump_enabled_p ())
12302 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12303 : : "conditional reduction prevents the use"
12304 : : " of partial vectors.\n");
12305 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
12306 : : }
12307 : : }
12308 : :
12309 : 11484 : STMT_VINFO_TYPE (stmt_info) = condition_vec_info_type;
12310 : 11484 : vect_model_simple_cost (vinfo, stmt_info, ncopies, dts, ndts, slp_node,
12311 : : cost_vec, kind);
12312 : 11484 : return true;
12313 : : }
12314 : :
12315 : : /* Transform. */
12316 : :
12317 : : /* Handle def. */
12318 : 4983 : scalar_dest = gimple_assign_lhs (stmt);
12319 : 4983 : if (reduction_type != EXTRACT_LAST_REDUCTION)
12320 : 4983 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
12321 : :
12322 : 4983 : bool swap_cond_operands = false;
12323 : :
12324 : : /* See whether another part of the vectorized code applies a loop
12325 : : mask to the condition, or to its inverse. */
12326 : :
12327 : 4983 : vec_loop_masks *masks = NULL;
12328 : 4983 : vec_loop_lens *lens = NULL;
12329 : 4983 : if (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo))
12330 : : {
12331 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12332 : 0 : lens = &LOOP_VINFO_LENS (loop_vinfo);
12333 : : }
12334 : 4983 : else if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
12335 : : {
12336 : 2 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12337 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
12338 : : else
12339 : : {
12340 : 2 : scalar_cond_masked_key cond (cond_expr, ncopies);
12341 : 2 : if (loop_vinfo->scalar_cond_masked_set.contains (cond))
12342 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
12343 : : else
12344 : : {
12345 : 2 : bool honor_nans = HONOR_NANS (TREE_TYPE (cond.op0));
12346 : 2 : tree_code orig_code = cond.code;
12347 : 2 : cond.code = invert_tree_comparison (cond.code, honor_nans);
12348 : 2 : if (!masked && loop_vinfo->scalar_cond_masked_set.contains (cond))
12349 : : {
12350 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
12351 : 0 : cond_code = cond.code;
12352 : 0 : swap_cond_operands = true;
12353 : : }
12354 : : else
12355 : : {
12356 : : /* Try the inverse of the current mask. We check if the
12357 : : inverse mask is live and if so we generate a negate of
12358 : : the current mask such that we still honor NaNs. */
12359 : 2 : cond.inverted_p = true;
12360 : 2 : cond.code = orig_code;
12361 : 2 : if (loop_vinfo->scalar_cond_masked_set.contains (cond))
12362 : : {
12363 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
12364 : 0 : cond_code = cond.code;
12365 : 0 : swap_cond_operands = true;
12366 : 0 : must_invert_cmp_result = true;
12367 : : }
12368 : : }
12369 : : }
12370 : : }
12371 : : }
12372 : :
12373 : : /* Handle cond expr. */
12374 : 4983 : if (masked)
12375 : 4604 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
12376 : : cond_expr, comp_vectype, &vec_oprnds0,
12377 : : then_clause, vectype, &vec_oprnds2,
12378 : : reduction_type != EXTRACT_LAST_REDUCTION
12379 : : ? else_clause : NULL, vectype, &vec_oprnds3);
12380 : : else
12381 : 379 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
12382 : : cond_expr0, comp_vectype, &vec_oprnds0,
12383 : : cond_expr1, comp_vectype, &vec_oprnds1,
12384 : : then_clause, vectype, &vec_oprnds2,
12385 : : reduction_type != EXTRACT_LAST_REDUCTION
12386 : : ? else_clause : NULL, vectype, &vec_oprnds3);
12387 : :
12388 : : /* Arguments are ready. Create the new vector stmt. */
12389 : 11640 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_cond_lhs)
12390 : : {
12391 : 6657 : vec_then_clause = vec_oprnds2[i];
12392 : 6657 : if (reduction_type != EXTRACT_LAST_REDUCTION)
12393 : 6657 : vec_else_clause = vec_oprnds3[i];
12394 : :
12395 : 6657 : if (swap_cond_operands)
12396 : 0 : std::swap (vec_then_clause, vec_else_clause);
12397 : :
12398 : 6657 : if (masked)
12399 : : vec_compare = vec_cond_lhs;
12400 : : else
12401 : : {
12402 : 458 : vec_cond_rhs = vec_oprnds1[i];
12403 : 458 : if (bitop1 == NOP_EXPR)
12404 : : {
12405 : 341 : gimple_seq stmts = NULL;
12406 : 341 : vec_compare = gimple_build (&stmts, cond_code, vec_cmp_type,
12407 : : vec_cond_lhs, vec_cond_rhs);
12408 : 341 : gsi_insert_before (gsi, stmts, GSI_SAME_STMT);
12409 : : }
12410 : : else
12411 : : {
12412 : 117 : new_temp = make_ssa_name (vec_cmp_type);
12413 : 117 : gassign *new_stmt;
12414 : 117 : if (bitop1 == BIT_NOT_EXPR)
12415 : 0 : new_stmt = gimple_build_assign (new_temp, bitop1,
12416 : : vec_cond_rhs);
12417 : : else
12418 : 117 : new_stmt
12419 : 117 : = gimple_build_assign (new_temp, bitop1, vec_cond_lhs,
12420 : : vec_cond_rhs);
12421 : 117 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12422 : 117 : if (bitop2 == NOP_EXPR)
12423 : : vec_compare = new_temp;
12424 : 0 : else if (bitop2 == BIT_NOT_EXPR
12425 : 0 : && reduction_type != EXTRACT_LAST_REDUCTION)
12426 : : {
12427 : : /* Instead of doing ~x ? y : z do x ? z : y. */
12428 : : vec_compare = new_temp;
12429 : : std::swap (vec_then_clause, vec_else_clause);
12430 : : }
12431 : : else
12432 : : {
12433 : 0 : vec_compare = make_ssa_name (vec_cmp_type);
12434 : 0 : if (bitop2 == BIT_NOT_EXPR)
12435 : 0 : new_stmt
12436 : 0 : = gimple_build_assign (vec_compare, bitop2, new_temp);
12437 : : else
12438 : 0 : new_stmt
12439 : 0 : = gimple_build_assign (vec_compare, bitop2,
12440 : : vec_cond_lhs, new_temp);
12441 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
12442 : : new_stmt, gsi);
12443 : : }
12444 : : }
12445 : : }
12446 : :
12447 : : /* If we decided to apply a loop mask to the result of the vector
12448 : : comparison, AND the comparison with the mask now. Later passes
12449 : : should then be able to reuse the AND results between mulitple
12450 : : vector statements.
12451 : :
12452 : : For example:
12453 : : for (int i = 0; i < 100; ++i)
12454 : : x[i] = y[i] ? z[i] : 10;
12455 : :
12456 : : results in following optimized GIMPLE:
12457 : :
12458 : : mask__35.8_43 = vect__4.7_41 != { 0, ... };
12459 : : vec_mask_and_46 = loop_mask_40 & mask__35.8_43;
12460 : : _19 = &MEM[base: z_12(D), index: ivtmp_56, step: 4, offset: 0B];
12461 : : vect_iftmp.11_47 = .MASK_LOAD (_19, 4B, vec_mask_and_46);
12462 : : vect_iftmp.12_52 = VEC_COND_EXPR <vec_mask_and_46,
12463 : : vect_iftmp.11_47, { 10, ... }>;
12464 : :
12465 : : instead of using a masked and unmasked forms of
12466 : : vec != { 0, ... } (masked in the MASK_LOAD,
12467 : : unmasked in the VEC_COND_EXPR). */
12468 : :
12469 : : /* Force vec_compare to be an SSA_NAME rather than a comparison,
12470 : : in cases where that's necessary. */
12471 : :
12472 : 6657 : tree len = NULL_TREE, bias = NULL_TREE;
12473 : 6657 : if (masks || lens || reduction_type == EXTRACT_LAST_REDUCTION)
12474 : : {
12475 : 0 : if (!is_gimple_val (vec_compare))
12476 : : {
12477 : 0 : tree vec_compare_name = make_ssa_name (vec_cmp_type);
12478 : 0 : gassign *new_stmt = gimple_build_assign (vec_compare_name,
12479 : : vec_compare);
12480 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12481 : 0 : vec_compare = vec_compare_name;
12482 : : }
12483 : :
12484 : 0 : if (must_invert_cmp_result)
12485 : : {
12486 : 0 : tree vec_compare_name = make_ssa_name (vec_cmp_type);
12487 : 0 : gassign *new_stmt = gimple_build_assign (vec_compare_name,
12488 : : BIT_NOT_EXPR,
12489 : : vec_compare);
12490 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12491 : 0 : vec_compare = vec_compare_name;
12492 : : }
12493 : :
12494 : 0 : if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST,
12495 : : vectype, OPTIMIZE_FOR_SPEED))
12496 : : {
12497 : 0 : if (lens)
12498 : : {
12499 : 0 : len = vect_get_loop_len (loop_vinfo, gsi, lens,
12500 : 0 : vec_num * ncopies, vectype, i, 1);
12501 : 0 : signed char biasval
12502 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
12503 : 0 : bias = build_int_cst (intQI_type_node, biasval);
12504 : : }
12505 : : else
12506 : : {
12507 : 0 : len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
12508 : 0 : bias = build_int_cst (intQI_type_node, 0);
12509 : : }
12510 : : }
12511 : 0 : if (masks)
12512 : : {
12513 : 0 : tree loop_mask
12514 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, vec_num * ncopies,
12515 : : vectype, i);
12516 : 0 : tree tmp2 = make_ssa_name (vec_cmp_type);
12517 : 0 : gassign *g
12518 : 0 : = gimple_build_assign (tmp2, BIT_AND_EXPR, vec_compare,
12519 : : loop_mask);
12520 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
12521 : 0 : vec_compare = tmp2;
12522 : : }
12523 : : }
12524 : :
12525 : 6657 : gimple *new_stmt;
12526 : 6657 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12527 : : {
12528 : 0 : gimple *old_stmt = vect_orig_stmt (stmt_info)->stmt;
12529 : 0 : tree lhs = gimple_get_lhs (old_stmt);
12530 : 0 : if (len)
12531 : 0 : new_stmt = gimple_build_call_internal
12532 : 0 : (IFN_LEN_FOLD_EXTRACT_LAST, 5, else_clause, vec_compare,
12533 : : vec_then_clause, len, bias);
12534 : : else
12535 : 0 : new_stmt = gimple_build_call_internal
12536 : 0 : (IFN_FOLD_EXTRACT_LAST, 3, else_clause, vec_compare,
12537 : : vec_then_clause);
12538 : 0 : gimple_call_set_lhs (new_stmt, lhs);
12539 : 0 : SSA_NAME_DEF_STMT (lhs) = new_stmt;
12540 : 0 : if (old_stmt == gsi_stmt (*gsi))
12541 : 0 : vect_finish_replace_stmt (vinfo, stmt_info, new_stmt);
12542 : : else
12543 : : {
12544 : : /* In this case we're moving the definition to later in the
12545 : : block. That doesn't matter because the only uses of the
12546 : : lhs are in phi statements. */
12547 : 0 : gimple_stmt_iterator old_gsi = gsi_for_stmt (old_stmt);
12548 : 0 : gsi_remove (&old_gsi, true);
12549 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12550 : : }
12551 : : }
12552 : : else
12553 : : {
12554 : 6657 : new_temp = make_ssa_name (vec_dest);
12555 : 6657 : new_stmt = gimple_build_assign (new_temp, VEC_COND_EXPR, vec_compare,
12556 : : vec_then_clause, vec_else_clause);
12557 : 6657 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12558 : : }
12559 : 6657 : if (slp_node)
12560 : 545 : slp_node->push_vec_def (new_stmt);
12561 : : else
12562 : 6112 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
12563 : : }
12564 : :
12565 : 4983 : if (!slp_node)
12566 : 4791 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
12567 : :
12568 : 4983 : vec_oprnds0.release ();
12569 : 4983 : vec_oprnds1.release ();
12570 : 4983 : vec_oprnds2.release ();
12571 : 4983 : vec_oprnds3.release ();
12572 : :
12573 : 4983 : return true;
12574 : : }
12575 : :
12576 : : /* Helper of vectorizable_comparison.
12577 : :
12578 : : Check if STMT_INFO is comparison expression CODE that can be vectorized.
12579 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
12580 : : comparison, put it in VEC_STMT, and insert it at GSI.
12581 : :
12582 : : Return true if STMT_INFO is vectorizable in this way. */
12583 : :
12584 : : static bool
12585 : 182223 : vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
12586 : : stmt_vec_info stmt_info, tree_code code,
12587 : : gimple_stmt_iterator *gsi, gimple **vec_stmt,
12588 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12589 : : {
12590 : 182223 : tree lhs, rhs1, rhs2;
12591 : 182223 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
12592 : 182223 : tree vec_rhs1 = NULL_TREE, vec_rhs2 = NULL_TREE;
12593 : 182223 : tree new_temp;
12594 : 182223 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
12595 : 182223 : enum vect_def_type dts[2] = {vect_unknown_def_type, vect_unknown_def_type};
12596 : 182223 : int ndts = 2;
12597 : 182223 : poly_uint64 nunits;
12598 : 182223 : int ncopies;
12599 : 182223 : enum tree_code bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
12600 : 182223 : int i;
12601 : 182223 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
12602 : 182223 : vec<tree> vec_oprnds0 = vNULL;
12603 : 182223 : vec<tree> vec_oprnds1 = vNULL;
12604 : 182223 : tree mask_type;
12605 : 182223 : tree mask = NULL_TREE;
12606 : :
12607 : 182223 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
12608 : : return false;
12609 : :
12610 : 182223 : if (!vectype || !VECTOR_BOOLEAN_TYPE_P (vectype))
12611 : : return false;
12612 : :
12613 : 85056 : mask_type = vectype;
12614 : 85056 : nunits = TYPE_VECTOR_SUBPARTS (vectype);
12615 : :
12616 : 85056 : if (slp_node)
12617 : : ncopies = 1;
12618 : : else
12619 : 47452 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
12620 : :
12621 : 47452 : gcc_assert (ncopies >= 1);
12622 : :
12623 : 85056 : if (TREE_CODE_CLASS (code) != tcc_comparison)
12624 : : return false;
12625 : :
12626 : 83662 : slp_tree slp_rhs1, slp_rhs2;
12627 : 83662 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
12628 : : 0, &rhs1, &slp_rhs1, &dts[0], &vectype1))
12629 : : return false;
12630 : :
12631 : 83662 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
12632 : : 1, &rhs2, &slp_rhs2, &dts[1], &vectype2))
12633 : : return false;
12634 : :
12635 : 49348 : if (vectype1 && vectype2
12636 : 112959 : && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1),
12637 : 29297 : TYPE_VECTOR_SUBPARTS (vectype2)))
12638 : 8 : return false;
12639 : :
12640 : 83654 : vectype = vectype1 ? vectype1 : vectype2;
12641 : :
12642 : : /* Invariant comparison. */
12643 : 83654 : if (!vectype)
12644 : : {
12645 : 29896 : if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (rhs1)))
12646 : : vectype = mask_type;
12647 : : else
12648 : 29794 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (rhs1),
12649 : : slp_node);
12650 : 29896 : if (!vectype || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype), nunits))
12651 : 11 : return false;
12652 : : }
12653 : 53758 : else if (maybe_ne (nunits, TYPE_VECTOR_SUBPARTS (vectype)))
12654 : : return false;
12655 : :
12656 : : /* Can't compare mask and non-mask types. */
12657 : 49340 : if (vectype1 && vectype2
12658 : 171248 : && (VECTOR_BOOLEAN_TYPE_P (vectype1) ^ VECTOR_BOOLEAN_TYPE_P (vectype2)))
12659 : : return false;
12660 : :
12661 : : /* Boolean values may have another representation in vectors
12662 : : and therefore we prefer bit operations over comparison for
12663 : : them (which also works for scalar masks). We store opcodes
12664 : : to use in bitop1 and bitop2. Statement is vectorized as
12665 : : BITOP2 (rhs1 BITOP1 rhs2) or
12666 : : rhs1 BITOP2 (BITOP1 rhs2)
12667 : : depending on bitop1 and bitop2 arity. */
12668 : 83641 : bool swap_p = false;
12669 : 83641 : if (VECTOR_BOOLEAN_TYPE_P (vectype))
12670 : : {
12671 : 3145 : if (code == GT_EXPR)
12672 : : {
12673 : : bitop1 = BIT_NOT_EXPR;
12674 : : bitop2 = BIT_AND_EXPR;
12675 : : }
12676 : : else if (code == GE_EXPR)
12677 : : {
12678 : : bitop1 = BIT_NOT_EXPR;
12679 : : bitop2 = BIT_IOR_EXPR;
12680 : : }
12681 : : else if (code == LT_EXPR)
12682 : : {
12683 : : bitop1 = BIT_NOT_EXPR;
12684 : : bitop2 = BIT_AND_EXPR;
12685 : : swap_p = true;
12686 : : }
12687 : : else if (code == LE_EXPR)
12688 : : {
12689 : : bitop1 = BIT_NOT_EXPR;
12690 : : bitop2 = BIT_IOR_EXPR;
12691 : : swap_p = true;
12692 : : }
12693 : : else
12694 : : {
12695 : : bitop1 = BIT_XOR_EXPR;
12696 : : if (code == EQ_EXPR)
12697 : : bitop2 = BIT_NOT_EXPR;
12698 : : }
12699 : : }
12700 : :
12701 : 83641 : if (!vec_stmt)
12702 : : {
12703 : 74452 : if (bitop1 == NOP_EXPR)
12704 : : {
12705 : 72663 : if (!expand_vec_cmp_expr_p (vectype, mask_type, code))
12706 : : return false;
12707 : : }
12708 : : else
12709 : : {
12710 : 1789 : machine_mode mode = TYPE_MODE (vectype);
12711 : 1789 : optab optab;
12712 : :
12713 : 1789 : optab = optab_for_tree_code (bitop1, vectype, optab_default);
12714 : 1789 : if (!optab || optab_handler (optab, mode) == CODE_FOR_nothing)
12715 : 0 : return false;
12716 : :
12717 : 1789 : if (bitop2 != NOP_EXPR)
12718 : : {
12719 : 81 : optab = optab_for_tree_code (bitop2, vectype, optab_default);
12720 : 81 : if (!optab || optab_handler (optab, mode) == CODE_FOR_nothing)
12721 : 0 : return false;
12722 : : }
12723 : : }
12724 : :
12725 : : /* Put types on constant and invariant SLP children. */
12726 : 70591 : if (slp_node
12727 : 70591 : && (!vect_maybe_update_slp_op_vectype (slp_rhs1, vectype)
12728 : 33721 : || !vect_maybe_update_slp_op_vectype (slp_rhs2, vectype)))
12729 : : {
12730 : 102 : if (dump_enabled_p ())
12731 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12732 : : "incompatible vector types for invariants\n");
12733 : 102 : return false;
12734 : : }
12735 : :
12736 : 140978 : vect_model_simple_cost (vinfo, stmt_info,
12737 : 70489 : ncopies * (1 + (bitop2 != NOP_EXPR)),
12738 : : dts, ndts, slp_node, cost_vec);
12739 : 70489 : return true;
12740 : : }
12741 : :
12742 : : /* Transform. */
12743 : :
12744 : : /* Handle def. */
12745 : 9189 : lhs = gimple_get_lhs (STMT_VINFO_STMT (stmt_info));
12746 : 9189 : if (lhs)
12747 : 7896 : mask = vect_create_destination_var (lhs, mask_type);
12748 : :
12749 : 9189 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
12750 : : rhs1, vectype, &vec_oprnds0,
12751 : : rhs2, vectype, &vec_oprnds1);
12752 : 9189 : if (swap_p)
12753 : 26 : std::swap (vec_oprnds0, vec_oprnds1);
12754 : :
12755 : : /* Arguments are ready. Create the new vector stmt. */
12756 : 21513 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_rhs1)
12757 : : {
12758 : 12324 : gimple *new_stmt;
12759 : 12324 : vec_rhs2 = vec_oprnds1[i];
12760 : :
12761 : 12324 : if (lhs)
12762 : 10571 : new_temp = make_ssa_name (mask);
12763 : : else
12764 : 1753 : new_temp = make_temp_ssa_name (mask_type, NULL, "cmp");
12765 : 12324 : if (bitop1 == NOP_EXPR)
12766 : : {
12767 : 10501 : new_stmt = gimple_build_assign (new_temp, code,
12768 : : vec_rhs1, vec_rhs2);
12769 : 10501 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12770 : : }
12771 : : else
12772 : : {
12773 : 1823 : if (bitop1 == BIT_NOT_EXPR)
12774 : 54 : new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs2);
12775 : : else
12776 : 1769 : new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs1,
12777 : : vec_rhs2);
12778 : 1823 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12779 : 1823 : if (bitop2 != NOP_EXPR)
12780 : : {
12781 : 54 : tree res = make_ssa_name (mask);
12782 : 54 : if (bitop2 == BIT_NOT_EXPR)
12783 : 0 : new_stmt = gimple_build_assign (res, bitop2, new_temp);
12784 : : else
12785 : 54 : new_stmt = gimple_build_assign (res, bitop2, vec_rhs1,
12786 : : new_temp);
12787 : 54 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12788 : : }
12789 : : }
12790 : 12324 : if (slp_node)
12791 : 521 : slp_node->push_vec_def (new_stmt);
12792 : : else
12793 : 11803 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
12794 : : }
12795 : :
12796 : 9189 : if (!slp_node)
12797 : 9019 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
12798 : :
12799 : 9189 : vec_oprnds0.release ();
12800 : 9189 : vec_oprnds1.release ();
12801 : :
12802 : 9189 : return true;
12803 : : }
12804 : :
12805 : : /* vectorizable_comparison.
12806 : :
12807 : : Check if STMT_INFO is comparison expression that can be vectorized.
12808 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
12809 : : comparison, put it in VEC_STMT, and insert it at GSI.
12810 : :
12811 : : Return true if STMT_INFO is vectorizable in this way. */
12812 : :
12813 : : static bool
12814 : 263330 : vectorizable_comparison (vec_info *vinfo,
12815 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
12816 : : gimple **vec_stmt,
12817 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12818 : : {
12819 : 263330 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
12820 : :
12821 : 263330 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
12822 : : return false;
12823 : :
12824 : 263330 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
12825 : : return false;
12826 : :
12827 : 365875 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
12828 : 179340 : if (!stmt)
12829 : : return false;
12830 : :
12831 : 179340 : enum tree_code code = gimple_assign_rhs_code (stmt);
12832 : 179340 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
12833 : 179340 : if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
12834 : : vec_stmt, slp_node, cost_vec))
12835 : : return false;
12836 : :
12837 : 76795 : if (!vec_stmt)
12838 : 68899 : STMT_VINFO_TYPE (stmt_info) = comparison_vec_info_type;
12839 : :
12840 : : return true;
12841 : : }
12842 : :
12843 : : /* Check to see if the current early break given in STMT_INFO is valid for
12844 : : vectorization. */
12845 : :
12846 : : static bool
12847 : 127501 : vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
12848 : : gimple_stmt_iterator *gsi, gimple **vec_stmt,
12849 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12850 : : {
12851 : 127501 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
12852 : 46790 : if (!loop_vinfo
12853 : 46790 : || !is_a <gcond *> (STMT_VINFO_STMT (stmt_info)))
12854 : : return false;
12855 : :
12856 : 19714 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_condition_def)
12857 : : return false;
12858 : :
12859 : 19714 : if (!STMT_VINFO_RELEVANT_P (stmt_info))
12860 : : return false;
12861 : :
12862 : 19714 : DUMP_VECT_SCOPE ("vectorizable_early_exit");
12863 : :
12864 : 19714 : auto code = gimple_cond_code (STMT_VINFO_STMT (stmt_info));
12865 : :
12866 : 19714 : tree vectype = NULL_TREE;
12867 : 19714 : slp_tree slp_op0;
12868 : 19714 : tree op0;
12869 : 19714 : enum vect_def_type dt0;
12870 : 19714 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &op0, &slp_op0, &dt0,
12871 : : &vectype))
12872 : : {
12873 : 0 : if (dump_enabled_p ())
12874 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12875 : : "use not simple.\n");
12876 : 0 : return false;
12877 : : }
12878 : :
12879 : 19714 : if (!vectype)
12880 : : return false;
12881 : :
12882 : 19671 : machine_mode mode = TYPE_MODE (vectype);
12883 : 19671 : int ncopies;
12884 : :
12885 : 19671 : if (slp_node)
12886 : : ncopies = 1;
12887 : : else
12888 : 19671 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
12889 : :
12890 : 19671 : vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
12891 : 19671 : bool masked_loop_p = LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
12892 : :
12893 : : /* Now build the new conditional. Pattern gimple_conds get dropped during
12894 : : codegen so we must replace the original insn. */
12895 : 19671 : gimple *orig_stmt = STMT_VINFO_STMT (vect_orig_stmt (stmt_info));
12896 : 19671 : gcond *cond_stmt = as_a <gcond *>(orig_stmt);
12897 : : /* When vectorizing we assume that if the branch edge is taken that we're
12898 : : exiting the loop. This is not however always the case as the compiler will
12899 : : rewrite conditions to always be a comparison against 0. To do this it
12900 : : sometimes flips the edges. This is fine for scalar, but for vector we
12901 : : then have to flip the test, as we're still assuming that if you take the
12902 : : branch edge that we found the exit condition. i.e. we need to know whether
12903 : : we are generating a `forall` or an `exist` condition. */
12904 : 19671 : auto new_code = NE_EXPR;
12905 : 19671 : auto reduc_optab = ior_optab;
12906 : 19671 : auto reduc_op = BIT_IOR_EXPR;
12907 : 19671 : tree cst = build_zero_cst (vectype);
12908 : 19671 : edge exit_true_edge = EDGE_SUCC (gimple_bb (cond_stmt), 0);
12909 : 19671 : if (exit_true_edge->flags & EDGE_FALSE_VALUE)
12910 : 1577 : exit_true_edge = EDGE_SUCC (gimple_bb (cond_stmt), 1);
12911 : 19671 : gcc_assert (exit_true_edge->flags & EDGE_TRUE_VALUE);
12912 : 19671 : if (flow_bb_inside_loop_p (LOOP_VINFO_LOOP (loop_vinfo),
12913 : 19671 : exit_true_edge->dest))
12914 : : {
12915 : 1058 : new_code = EQ_EXPR;
12916 : 1058 : reduc_optab = and_optab;
12917 : 1058 : reduc_op = BIT_AND_EXPR;
12918 : 1058 : cst = build_minus_one_cst (vectype);
12919 : : }
12920 : :
12921 : : /* Analyze only. */
12922 : 19671 : if (!vec_stmt)
12923 : : {
12924 : 18378 : if (direct_optab_handler (cbranch_optab, mode) == CODE_FOR_nothing)
12925 : : {
12926 : 16788 : if (dump_enabled_p ())
12927 : 239 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12928 : : "can't vectorize early exit because the "
12929 : : "target doesn't support flag setting vector "
12930 : : "comparisons.\n");
12931 : 16788 : return false;
12932 : : }
12933 : :
12934 : 1590 : if (ncopies > 1
12935 : 2039 : && direct_optab_handler (reduc_optab, mode) == CODE_FOR_nothing)
12936 : : {
12937 : 0 : if (dump_enabled_p ())
12938 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12939 : : "can't vectorize early exit because the "
12940 : : "target does not support boolean vector %s "
12941 : : "for type %T.\n",
12942 : : reduc_optab == ior_optab ? "OR" : "AND",
12943 : : vectype);
12944 : 0 : return false;
12945 : : }
12946 : :
12947 : 1590 : if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
12948 : : vec_stmt, slp_node, cost_vec))
12949 : : return false;
12950 : :
12951 : 1590 : if (LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
12952 : : {
12953 : 0 : if (direct_internal_fn_supported_p (IFN_VCOND_MASK_LEN, vectype,
12954 : : OPTIMIZE_FOR_SPEED))
12955 : : return false;
12956 : : else
12957 : 0 : vect_record_loop_mask (loop_vinfo, masks, ncopies, vectype, NULL);
12958 : : }
12959 : :
12960 : :
12961 : 1590 : return true;
12962 : : }
12963 : :
12964 : : /* Tranform. */
12965 : :
12966 : 1293 : tree new_temp = NULL_TREE;
12967 : 1293 : gimple *new_stmt = NULL;
12968 : :
12969 : 1293 : if (dump_enabled_p ())
12970 : 345 : dump_printf_loc (MSG_NOTE, vect_location, "transform early-exit.\n");
12971 : :
12972 : 1293 : if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
12973 : : vec_stmt, slp_node, cost_vec))
12974 : 0 : gcc_unreachable ();
12975 : :
12976 : 1293 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
12977 : 1293 : basic_block cond_bb = gimple_bb (stmt);
12978 : 1293 : gimple_stmt_iterator cond_gsi = gsi_last_bb (cond_bb);
12979 : :
12980 : 1293 : auto_vec<tree> stmts;
12981 : :
12982 : 1293 : if (slp_node)
12983 : 0 : stmts.safe_splice (SLP_TREE_VEC_DEFS (slp_node));
12984 : : else
12985 : : {
12986 : 1293 : auto vec_stmts = STMT_VINFO_VEC_STMTS (stmt_info);
12987 : 2586 : stmts.reserve_exact (vec_stmts.length ());
12988 : 5632 : for (auto stmt : vec_stmts)
12989 : 1753 : stmts.quick_push (gimple_assign_lhs (stmt));
12990 : : }
12991 : :
12992 : : /* Determine if we need to reduce the final value. */
12993 : 1293 : if (stmts.length () > 1)
12994 : : {
12995 : : /* We build the reductions in a way to maintain as much parallelism as
12996 : : possible. */
12997 : 344 : auto_vec<tree> workset (stmts.length ());
12998 : :
12999 : : /* Mask the statements as we queue them up. Normally we loop over
13000 : : vec_num, but since we inspect the exact results of vectorization
13001 : : we don't need to and instead can just use the stmts themselves. */
13002 : 344 : if (masked_loop_p)
13003 : 0 : for (unsigned i = 0; i < stmts.length (); i++)
13004 : : {
13005 : 0 : tree stmt_mask
13006 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies, vectype,
13007 : : i);
13008 : 0 : stmt_mask
13009 : 0 : = prepare_vec_mask (loop_vinfo, TREE_TYPE (stmt_mask), stmt_mask,
13010 : 0 : stmts[i], &cond_gsi);
13011 : 0 : workset.quick_push (stmt_mask);
13012 : : }
13013 : : else
13014 : 344 : workset.splice (stmts);
13015 : :
13016 : 804 : while (workset.length () > 1)
13017 : : {
13018 : 460 : new_temp = make_temp_ssa_name (vectype, NULL, "vexit_reduc");
13019 : 460 : tree arg0 = workset.pop ();
13020 : 460 : tree arg1 = workset.pop ();
13021 : 460 : new_stmt = gimple_build_assign (new_temp, reduc_op, arg0, arg1);
13022 : 460 : vect_finish_stmt_generation (loop_vinfo, stmt_info, new_stmt,
13023 : : &cond_gsi);
13024 : 460 : workset.quick_insert (0, new_temp);
13025 : : }
13026 : 344 : }
13027 : : else
13028 : : {
13029 : 949 : new_temp = stmts[0];
13030 : 949 : if (masked_loop_p)
13031 : : {
13032 : 0 : tree mask
13033 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies, vectype, 0);
13034 : 0 : new_temp = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
13035 : : new_temp, &cond_gsi);
13036 : : }
13037 : : }
13038 : :
13039 : 1293 : gcc_assert (new_temp);
13040 : :
13041 : 1293 : gimple_cond_set_condition (cond_stmt, new_code, new_temp, cst);
13042 : 1293 : update_stmt (orig_stmt);
13043 : :
13044 : 1293 : if (slp_node)
13045 : 0 : SLP_TREE_VEC_DEFS (slp_node).truncate (0);
13046 : : else
13047 : 1293 : STMT_VINFO_VEC_STMTS (stmt_info).truncate (0);
13048 : :
13049 : 1293 : if (!slp_node)
13050 : 1293 : *vec_stmt = orig_stmt;
13051 : :
13052 : 1293 : return true;
13053 : 1293 : }
13054 : :
13055 : : /* If SLP_NODE is nonnull, return true if vectorizable_live_operation
13056 : : can handle all live statements in the node. Otherwise return true
13057 : : if STMT_INFO is not live or if vectorizable_live_operation can handle it.
13058 : : VEC_STMT_P is as for vectorizable_live_operation. */
13059 : :
13060 : : static bool
13061 : 974433 : can_vectorize_live_stmts (vec_info *vinfo, stmt_vec_info stmt_info,
13062 : : slp_tree slp_node, slp_instance slp_node_instance,
13063 : : bool vec_stmt_p,
13064 : : stmt_vector_for_cost *cost_vec)
13065 : : {
13066 : 974433 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
13067 : 974433 : if (slp_node)
13068 : : {
13069 : : stmt_vec_info slp_stmt_info;
13070 : : unsigned int i;
13071 : 679539 : FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (slp_node), i, slp_stmt_info)
13072 : : {
13073 : 499346 : if ((STMT_VINFO_LIVE_P (slp_stmt_info)
13074 : 456240 : || (loop_vinfo
13075 : 154267 : && LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
13076 : 328 : && STMT_VINFO_DEF_TYPE (slp_stmt_info)
13077 : : == vect_induction_def))
13078 : 499346 : && !vectorizable_live_operation (vinfo, slp_stmt_info, slp_node,
13079 : : slp_node_instance, i,
13080 : : vec_stmt_p, cost_vec))
13081 : 0 : return false;
13082 : : }
13083 : : }
13084 : 794240 : else if ((STMT_VINFO_LIVE_P (stmt_info)
13085 : 728038 : || (LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
13086 : 79737 : && STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def))
13087 : 794240 : && !vectorizable_live_operation (vinfo, stmt_info,
13088 : : slp_node, slp_node_instance, -1,
13089 : : vec_stmt_p, cost_vec))
13090 : : return false;
13091 : :
13092 : : return true;
13093 : : }
13094 : :
13095 : : /* Make sure the statement is vectorizable. */
13096 : :
13097 : : opt_result
13098 : 2503435 : vect_analyze_stmt (vec_info *vinfo,
13099 : : stmt_vec_info stmt_info, bool *need_to_vectorize,
13100 : : slp_tree node, slp_instance node_instance,
13101 : : stmt_vector_for_cost *cost_vec)
13102 : : {
13103 : 2503435 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
13104 : 2503435 : enum vect_relevant relevance = STMT_VINFO_RELEVANT (stmt_info);
13105 : 2503435 : bool ok;
13106 : 2503435 : gimple_seq pattern_def_seq;
13107 : :
13108 : 2503435 : if (dump_enabled_p ())
13109 : 192826 : dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: %G",
13110 : : stmt_info->stmt);
13111 : :
13112 : 4819361 : if (gimple_has_volatile_ops (stmt_info->stmt))
13113 : 0 : return opt_result::failure_at (stmt_info->stmt,
13114 : : "not vectorized:"
13115 : : " stmt has volatile operands: %G\n",
13116 : : stmt_info->stmt);
13117 : :
13118 : 2503435 : if (STMT_VINFO_IN_PATTERN_P (stmt_info)
13119 : 63771 : && node == NULL
13120 : 2567206 : && (pattern_def_seq = STMT_VINFO_PATTERN_DEF_SEQ (stmt_info)))
13121 : : {
13122 : : gimple_stmt_iterator si;
13123 : :
13124 : 125459 : for (si = gsi_start (pattern_def_seq); !gsi_end_p (si); gsi_next (&si))
13125 : : {
13126 : 71601 : stmt_vec_info pattern_def_stmt_info
13127 : 71601 : = vinfo->lookup_stmt (gsi_stmt (si));
13128 : 71601 : if (STMT_VINFO_RELEVANT_P (pattern_def_stmt_info)
13129 : 18840 : || STMT_VINFO_LIVE_P (pattern_def_stmt_info))
13130 : : {
13131 : : /* Analyze def stmt of STMT if it's a pattern stmt. */
13132 : 52761 : if (dump_enabled_p ())
13133 : 11079 : dump_printf_loc (MSG_NOTE, vect_location,
13134 : : "==> examining pattern def statement: %G",
13135 : : pattern_def_stmt_info->stmt);
13136 : :
13137 : 52761 : opt_result res
13138 : 52761 : = vect_analyze_stmt (vinfo, pattern_def_stmt_info,
13139 : : need_to_vectorize, node, node_instance,
13140 : : cost_vec);
13141 : 52761 : if (!res)
13142 : 2381 : return res;
13143 : : }
13144 : : }
13145 : : }
13146 : :
13147 : : /* Skip stmts that do not need to be vectorized. In loops this is expected
13148 : : to include:
13149 : : - the COND_EXPR which is the loop exit condition
13150 : : - any LABEL_EXPRs in the loop
13151 : : - computations that are used only for array indexing or loop control.
13152 : : In basic blocks we only analyze statements that are a part of some SLP
13153 : : instance, therefore, all the statements are relevant.
13154 : :
13155 : : Pattern statement needs to be analyzed instead of the original statement
13156 : : if the original statement is not relevant. Otherwise, we analyze both
13157 : : statements. In basic blocks we are called from some SLP instance
13158 : : traversal, don't analyze pattern stmts instead, the pattern stmts
13159 : : already will be part of SLP instance. */
13160 : :
13161 : 2501054 : stmt_vec_info pattern_stmt_info = STMT_VINFO_RELATED_STMT (stmt_info);
13162 : 2501054 : if (!STMT_VINFO_RELEVANT_P (stmt_info)
13163 : 651907 : && !STMT_VINFO_LIVE_P (stmt_info))
13164 : : {
13165 : 651847 : if (STMT_VINFO_IN_PATTERN_P (stmt_info)
13166 : 61390 : && pattern_stmt_info
13167 : 61390 : && (STMT_VINFO_RELEVANT_P (pattern_stmt_info)
13168 : 25356 : || STMT_VINFO_LIVE_P (pattern_stmt_info)))
13169 : : {
13170 : : /* Analyze PATTERN_STMT instead of the original stmt. */
13171 : 36034 : stmt_info = pattern_stmt_info;
13172 : 36034 : if (dump_enabled_p ())
13173 : 4706 : dump_printf_loc (MSG_NOTE, vect_location,
13174 : : "==> examining pattern statement: %G",
13175 : : stmt_info->stmt);
13176 : : }
13177 : : else
13178 : : {
13179 : 615813 : if (dump_enabled_p ())
13180 : 76794 : dump_printf_loc (MSG_NOTE, vect_location, "irrelevant.\n");
13181 : :
13182 : 615813 : return opt_result::success ();
13183 : : }
13184 : : }
13185 : 1849207 : else if (STMT_VINFO_IN_PATTERN_P (stmt_info)
13186 : 0 : && node == NULL
13187 : 0 : && pattern_stmt_info
13188 : 0 : && (STMT_VINFO_RELEVANT_P (pattern_stmt_info)
13189 : 0 : || STMT_VINFO_LIVE_P (pattern_stmt_info)))
13190 : : {
13191 : : /* Analyze PATTERN_STMT too. */
13192 : 0 : if (dump_enabled_p ())
13193 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
13194 : : "==> examining pattern statement: %G",
13195 : : pattern_stmt_info->stmt);
13196 : :
13197 : 0 : opt_result res
13198 : 0 : = vect_analyze_stmt (vinfo, pattern_stmt_info, need_to_vectorize, node,
13199 : : node_instance, cost_vec);
13200 : 0 : if (!res)
13201 : 0 : return res;
13202 : : }
13203 : :
13204 : 1885241 : switch (STMT_VINFO_DEF_TYPE (stmt_info))
13205 : : {
13206 : : case vect_internal_def:
13207 : : case vect_condition_def:
13208 : : break;
13209 : :
13210 : 7206 : case vect_reduction_def:
13211 : 7206 : case vect_nested_cycle:
13212 : 7206 : gcc_assert (!bb_vinfo
13213 : : && (relevance == vect_used_in_outer
13214 : : || relevance == vect_used_in_outer_by_reduction
13215 : : || relevance == vect_used_by_reduction
13216 : : || relevance == vect_unused_in_scope
13217 : : || relevance == vect_used_only_live));
13218 : : break;
13219 : :
13220 : 554 : case vect_induction_def:
13221 : 554 : case vect_first_order_recurrence:
13222 : 554 : gcc_assert (!bb_vinfo);
13223 : : break;
13224 : :
13225 : 0 : case vect_constant_def:
13226 : 0 : case vect_external_def:
13227 : 0 : case vect_unknown_def_type:
13228 : 0 : default:
13229 : 0 : gcc_unreachable ();
13230 : : }
13231 : :
13232 : 1885241 : tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info);
13233 : 1885241 : if (node)
13234 : 1171767 : STMT_VINFO_VECTYPE (stmt_info) = SLP_TREE_VECTYPE (node);
13235 : :
13236 : 1885241 : if (STMT_VINFO_RELEVANT_P (stmt_info))
13237 : : {
13238 : 1885181 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
13239 : 1885181 : gcc_assert (STMT_VINFO_VECTYPE (stmt_info)
13240 : : || gimple_code (stmt_info->stmt) == GIMPLE_COND
13241 : : || (call && gimple_call_lhs (call) == NULL_TREE));
13242 : 1885181 : *need_to_vectorize = true;
13243 : : }
13244 : :
13245 : 1885241 : if (PURE_SLP_STMT (stmt_info) && !node)
13246 : : {
13247 : 90740 : if (dump_enabled_p ())
13248 : 27412 : dump_printf_loc (MSG_NOTE, vect_location,
13249 : : "handled only by SLP analysis\n");
13250 : 90740 : return opt_result::success ();
13251 : : }
13252 : :
13253 : 1794501 : ok = true;
13254 : 1794501 : if (!bb_vinfo
13255 : 656454 : && (STMT_VINFO_RELEVANT_P (stmt_info)
13256 : 60 : || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def))
13257 : : /* Prefer vectorizable_call over vectorizable_simd_clone_call so
13258 : : -mveclibabi= takes preference over library functions with
13259 : : the simd attribute. */
13260 : 656394 : ok = (vectorizable_call (vinfo, stmt_info, NULL, NULL, node, cost_vec)
13261 : 651508 : || vectorizable_simd_clone_call (vinfo, stmt_info, NULL, NULL, node,
13262 : : cost_vec)
13263 : 651060 : || vectorizable_conversion (vinfo, stmt_info,
13264 : : NULL, NULL, node, cost_vec)
13265 : 614836 : || vectorizable_operation (vinfo, stmt_info,
13266 : : NULL, NULL, node, cost_vec)
13267 : 427046 : || vectorizable_assignment (vinfo, stmt_info,
13268 : : NULL, NULL, node, cost_vec)
13269 : 392955 : || vectorizable_load (vinfo, stmt_info, NULL, NULL, node, cost_vec)
13270 : 219135 : || vectorizable_store (vinfo, stmt_info, NULL, NULL, node, cost_vec)
13271 : 109694 : || vectorizable_reduction (as_a <loop_vec_info> (vinfo), stmt_info,
13272 : : node, node_instance, cost_vec)
13273 : 103940 : || vectorizable_induction (as_a <loop_vec_info> (vinfo), stmt_info,
13274 : : NULL, node, cost_vec)
13275 : 103424 : || vectorizable_shift (vinfo, stmt_info, NULL, NULL, node, cost_vec)
13276 : 92227 : || vectorizable_condition (vinfo, stmt_info,
13277 : : NULL, NULL, node, cost_vec)
13278 : 81052 : || vectorizable_comparison (vinfo, stmt_info, NULL, NULL, node,
13279 : : cost_vec)
13280 : 45535 : || vectorizable_lc_phi (as_a <loop_vec_info> (vinfo),
13281 : : stmt_info, NULL, node)
13282 : 45509 : || vectorizable_recurr (as_a <loop_vec_info> (vinfo),
13283 : : stmt_info, NULL, node, cost_vec)
13284 : 701891 : || vectorizable_early_exit (vinfo, stmt_info, NULL, NULL, node,
13285 : : cost_vec));
13286 : : else
13287 : : {
13288 : : if (bb_vinfo)
13289 : 1138047 : ok = (vectorizable_call (vinfo, stmt_info, NULL, NULL, node, cost_vec)
13290 : 1137348 : || vectorizable_simd_clone_call (vinfo, stmt_info,
13291 : : NULL, NULL, node, cost_vec)
13292 : 1137287 : || vectorizable_conversion (vinfo, stmt_info, NULL, NULL, node,
13293 : : cost_vec)
13294 : 1128758 : || vectorizable_shift (vinfo, stmt_info,
13295 : : NULL, NULL, node, cost_vec)
13296 : 1107116 : || vectorizable_operation (vinfo, stmt_info,
13297 : : NULL, NULL, node, cost_vec)
13298 : 951792 : || vectorizable_assignment (vinfo, stmt_info, NULL, NULL, node,
13299 : : cost_vec)
13300 : 930636 : || vectorizable_load (vinfo, stmt_info,
13301 : : NULL, NULL, node, cost_vec)
13302 : 787515 : || vectorizable_store (vinfo, stmt_info,
13303 : : NULL, NULL, node, cost_vec)
13304 : 174691 : || vectorizable_condition (vinfo, stmt_info,
13305 : : NULL, NULL, node, cost_vec)
13306 : 174382 : || vectorizable_comparison (vinfo, stmt_info, NULL, NULL, node,
13307 : : cost_vec)
13308 : 141000 : || vectorizable_phi (vinfo, stmt_info, NULL, node, cost_vec)
13309 : 1218758 : || vectorizable_early_exit (vinfo, stmt_info, NULL, NULL, node,
13310 : : cost_vec));
13311 : :
13312 : : }
13313 : :
13314 : 1794501 : if (node)
13315 : 1171767 : STMT_VINFO_VECTYPE (stmt_info) = saved_vectype;
13316 : :
13317 : 1794501 : if (!ok)
13318 : 124618 : return opt_result::failure_at (stmt_info->stmt,
13319 : : "not vectorized:"
13320 : : " relevant stmt not supported: %G",
13321 : : stmt_info->stmt);
13322 : :
13323 : : /* Stmts that are (also) "live" (i.e. - that are used out of the loop)
13324 : : need extra handling, except for vectorizable reductions. */
13325 : 1669883 : if (!bb_vinfo
13326 : 612547 : && STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type
13327 : 607947 : && STMT_VINFO_TYPE (stmt_info) != lc_phi_info_type
13328 : 2277804 : && !can_vectorize_live_stmts (as_a <loop_vec_info> (vinfo),
13329 : : stmt_info, node, node_instance,
13330 : : false, cost_vec))
13331 : 0 : return opt_result::failure_at (stmt_info->stmt,
13332 : : "not vectorized:"
13333 : : " live stmt not supported: %G",
13334 : : stmt_info->stmt);
13335 : :
13336 : 1669883 : return opt_result::success ();
13337 : : }
13338 : :
13339 : :
13340 : : /* Function vect_transform_stmt.
13341 : :
13342 : : Create a vectorized stmt to replace STMT_INFO, and insert it at GSI. */
13343 : :
13344 : : bool
13345 : 920263 : vect_transform_stmt (vec_info *vinfo,
13346 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
13347 : : slp_tree slp_node, slp_instance slp_node_instance)
13348 : : {
13349 : 920263 : bool is_store = false;
13350 : 920263 : gimple *vec_stmt = NULL;
13351 : 920263 : bool done;
13352 : :
13353 : 920263 : gcc_assert (slp_node || !PURE_SLP_STMT (stmt_info));
13354 : :
13355 : 920263 : tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info);
13356 : 265446 : if (slp_node)
13357 : 654817 : STMT_VINFO_VECTYPE (stmt_info) = SLP_TREE_VECTYPE (slp_node);
13358 : :
13359 : 920263 : switch (STMT_VINFO_TYPE (stmt_info))
13360 : : {
13361 : 15335 : case type_demotion_vec_info_type:
13362 : 15335 : case type_promotion_vec_info_type:
13363 : 15335 : case type_conversion_vec_info_type:
13364 : 15335 : done = vectorizable_conversion (vinfo, stmt_info,
13365 : : gsi, &vec_stmt, slp_node, NULL);
13366 : 15335 : gcc_assert (done);
13367 : : break;
13368 : :
13369 : 13431 : case induc_vec_info_type:
13370 : 13431 : done = vectorizable_induction (as_a <loop_vec_info> (vinfo),
13371 : : stmt_info, &vec_stmt, slp_node,
13372 : : NULL);
13373 : 13431 : gcc_assert (done);
13374 : : break;
13375 : :
13376 : 5522 : case shift_vec_info_type:
13377 : 5522 : done = vectorizable_shift (vinfo, stmt_info,
13378 : : gsi, &vec_stmt, slp_node, NULL);
13379 : 5522 : gcc_assert (done);
13380 : : break;
13381 : :
13382 : 95212 : case op_vec_info_type:
13383 : 95212 : done = vectorizable_operation (vinfo, stmt_info, gsi, &vec_stmt, slp_node,
13384 : : NULL);
13385 : 95212 : gcc_assert (done);
13386 : : break;
13387 : :
13388 : 16984 : case assignment_vec_info_type:
13389 : 16984 : done = vectorizable_assignment (vinfo, stmt_info,
13390 : : gsi, &vec_stmt, slp_node, NULL);
13391 : 16984 : gcc_assert (done);
13392 : : break;
13393 : :
13394 : 161873 : case load_vec_info_type:
13395 : 161873 : done = vectorizable_load (vinfo, stmt_info, gsi, &vec_stmt, slp_node,
13396 : : NULL);
13397 : 161873 : gcc_assert (done);
13398 : : break;
13399 : :
13400 : 553751 : case store_vec_info_type:
13401 : 553751 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info)
13402 : 510558 : && !slp_node
13403 : 556839 : && (++DR_GROUP_STORE_COUNT (DR_GROUP_FIRST_ELEMENT (stmt_info))
13404 : 3088 : < DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info))))
13405 : : /* In case of interleaving, the whole chain is vectorized when the
13406 : : last store in the chain is reached. Store stmts before the last
13407 : : one are skipped, and there vec_stmt_info shouldn't be freed
13408 : : meanwhile. */
13409 : : ;
13410 : : else
13411 : : {
13412 : 551887 : done = vectorizable_store (vinfo, stmt_info,
13413 : : gsi, &vec_stmt, slp_node, NULL);
13414 : 551887 : gcc_assert (done);
13415 : : is_store = true;
13416 : : }
13417 : : break;
13418 : :
13419 : 4983 : case condition_vec_info_type:
13420 : 4983 : done = vectorizable_condition (vinfo, stmt_info,
13421 : : gsi, &vec_stmt, slp_node, NULL);
13422 : 4983 : gcc_assert (done);
13423 : : break;
13424 : :
13425 : 7896 : case comparison_vec_info_type:
13426 : 7896 : done = vectorizable_comparison (vinfo, stmt_info, gsi, &vec_stmt,
13427 : : slp_node, NULL);
13428 : 7896 : gcc_assert (done);
13429 : : break;
13430 : :
13431 : 3890 : case call_vec_info_type:
13432 : 3890 : done = vectorizable_call (vinfo, stmt_info,
13433 : : gsi, &vec_stmt, slp_node, NULL);
13434 : 3890 : break;
13435 : :
13436 : 342 : case call_simd_clone_vec_info_type:
13437 : 342 : done = vectorizable_simd_clone_call (vinfo, stmt_info, gsi, &vec_stmt,
13438 : : slp_node, NULL);
13439 : 342 : break;
13440 : :
13441 : 1650 : case reduc_vec_info_type:
13442 : 1650 : done = vect_transform_reduction (as_a <loop_vec_info> (vinfo), stmt_info,
13443 : : gsi, &vec_stmt, slp_node);
13444 : 1650 : gcc_assert (done);
13445 : : break;
13446 : :
13447 : 17676 : case cycle_phi_info_type:
13448 : 17676 : done = vect_transform_cycle_phi (as_a <loop_vec_info> (vinfo), stmt_info,
13449 : : &vec_stmt, slp_node, slp_node_instance);
13450 : 17676 : gcc_assert (done);
13451 : : break;
13452 : :
13453 : 337 : case lc_phi_info_type:
13454 : 337 : done = vectorizable_lc_phi (as_a <loop_vec_info> (vinfo),
13455 : : stmt_info, &vec_stmt, slp_node);
13456 : 337 : gcc_assert (done);
13457 : : break;
13458 : :
13459 : 34 : case recurr_info_type:
13460 : 34 : done = vectorizable_recurr (as_a <loop_vec_info> (vinfo),
13461 : : stmt_info, &vec_stmt, slp_node, NULL);
13462 : 34 : gcc_assert (done);
13463 : : break;
13464 : :
13465 : 20046 : case phi_info_type:
13466 : 20046 : done = vectorizable_phi (vinfo, stmt_info, &vec_stmt, slp_node, NULL);
13467 : 20046 : gcc_assert (done);
13468 : : break;
13469 : :
13470 : 1293 : case loop_exit_ctrl_vec_info_type:
13471 : 1293 : done = vectorizable_early_exit (vinfo, stmt_info, gsi, &vec_stmt,
13472 : : slp_node, NULL);
13473 : 1293 : gcc_assert (done);
13474 : : break;
13475 : :
13476 : 8 : default:
13477 : 8 : if (!STMT_VINFO_LIVE_P (stmt_info))
13478 : : {
13479 : 0 : if (dump_enabled_p ())
13480 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
13481 : : "stmt not supported.\n");
13482 : 0 : gcc_unreachable ();
13483 : : }
13484 : 920263 : done = true;
13485 : : }
13486 : :
13487 : 920263 : if (!slp_node && vec_stmt)
13488 : 262982 : gcc_assert (STMT_VINFO_VEC_STMTS (stmt_info).exists ());
13489 : :
13490 : 920263 : if (STMT_VINFO_TYPE (stmt_info) != store_vec_info_type)
13491 : : {
13492 : : /* Handle stmts whose DEF is used outside the loop-nest that is
13493 : : being vectorized. */
13494 : 366512 : done = can_vectorize_live_stmts (vinfo, stmt_info, slp_node,
13495 : : slp_node_instance, true, NULL);
13496 : 366512 : gcc_assert (done);
13497 : : }
13498 : :
13499 : 920263 : if (slp_node)
13500 : 654817 : STMT_VINFO_VECTYPE (stmt_info) = saved_vectype;
13501 : :
13502 : 920263 : return is_store;
13503 : : }
13504 : :
13505 : :
13506 : : /* Remove a group of stores (for SLP or interleaving), free their
13507 : : stmt_vec_info. */
13508 : :
13509 : : void
13510 : 1224 : vect_remove_stores (vec_info *vinfo, stmt_vec_info first_stmt_info)
13511 : : {
13512 : 1224 : stmt_vec_info next_stmt_info = first_stmt_info;
13513 : :
13514 : 4312 : while (next_stmt_info)
13515 : : {
13516 : 3088 : stmt_vec_info tmp = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
13517 : 3088 : next_stmt_info = vect_orig_stmt (next_stmt_info);
13518 : : /* Free the attached stmt_vec_info and remove the stmt. */
13519 : 3088 : vinfo->remove_stmt (next_stmt_info);
13520 : 3088 : next_stmt_info = tmp;
13521 : : }
13522 : 1224 : }
13523 : :
13524 : : /* If NUNITS is nonzero, return a vector type that contains NUNITS
13525 : : elements of type SCALAR_TYPE, or null if the target doesn't support
13526 : : such a type.
13527 : :
13528 : : If NUNITS is zero, return a vector type that contains elements of
13529 : : type SCALAR_TYPE, choosing whichever vector size the target prefers.
13530 : :
13531 : : If PREVAILING_MODE is VOIDmode, we have not yet chosen a vector mode
13532 : : for this vectorization region and want to "autodetect" the best choice.
13533 : : Otherwise, PREVAILING_MODE is a previously-chosen vector TYPE_MODE
13534 : : and we want the new type to be interoperable with it. PREVAILING_MODE
13535 : : in this case can be a scalar integer mode or a vector mode; when it
13536 : : is a vector mode, the function acts like a tree-level version of
13537 : : related_vector_mode. */
13538 : :
13539 : : tree
13540 : 40649541 : get_related_vectype_for_scalar_type (machine_mode prevailing_mode,
13541 : : tree scalar_type, poly_uint64 nunits)
13542 : : {
13543 : 40649541 : tree orig_scalar_type = scalar_type;
13544 : 40649541 : scalar_mode inner_mode;
13545 : 40649541 : machine_mode simd_mode;
13546 : 40649541 : tree vectype;
13547 : :
13548 : 40649541 : if ((!INTEGRAL_TYPE_P (scalar_type)
13549 : 11724671 : && !POINTER_TYPE_P (scalar_type)
13550 : 1758478 : && !SCALAR_FLOAT_TYPE_P (scalar_type))
13551 : 51968876 : || (!is_int_mode (TYPE_MODE (scalar_type), &inner_mode)
13552 : 1353211 : && !is_float_mode (TYPE_MODE (scalar_type), &inner_mode)))
13553 : 410196 : return NULL_TREE;
13554 : :
13555 : 40239345 : unsigned int nbytes = GET_MODE_SIZE (inner_mode);
13556 : :
13557 : : /* Interoperability between modes requires one to be a constant multiple
13558 : : of the other, so that the number of vectors required for each operation
13559 : : is a compile-time constant. */
13560 : 40239345 : if (prevailing_mode != VOIDmode
13561 : 79475250 : && !constant_multiple_p (nunits * nbytes,
13562 : 39235905 : GET_MODE_SIZE (prevailing_mode))
13563 : 43109841 : && !constant_multiple_p (GET_MODE_SIZE (prevailing_mode),
13564 : 2870496 : nunits * nbytes))
13565 : 0 : return NULL_TREE;
13566 : :
13567 : : /* For vector types of elements whose mode precision doesn't
13568 : : match their types precision we use a element type of mode
13569 : : precision. The vectorization routines will have to make sure
13570 : : they support the proper result truncation/extension.
13571 : : We also make sure to build vector types with INTEGER_TYPE
13572 : : component type only. */
13573 : 40239345 : if (INTEGRAL_TYPE_P (scalar_type)
13574 : 69164146 : && (GET_MODE_BITSIZE (inner_mode) != TYPE_PRECISION (scalar_type)
13575 : 26731902 : || TREE_CODE (scalar_type) != INTEGER_TYPE))
13576 : 2462231 : scalar_type = build_nonstandard_integer_type (GET_MODE_BITSIZE (inner_mode),
13577 : 2462231 : TYPE_UNSIGNED (scalar_type));
13578 : :
13579 : : /* We shouldn't end up building VECTOR_TYPEs of non-scalar components.
13580 : : When the component mode passes the above test simply use a type
13581 : : corresponding to that mode. The theory is that any use that
13582 : : would cause problems with this will disable vectorization anyway. */
13583 : 37777114 : else if (!SCALAR_FLOAT_TYPE_P (scalar_type)
13584 : : && !INTEGRAL_TYPE_P (scalar_type))
13585 : 9966193 : scalar_type = lang_hooks.types.type_for_mode (inner_mode, 1);
13586 : :
13587 : : /* We can't build a vector type of elements with alignment bigger than
13588 : : their size. */
13589 : 27810921 : else if (nbytes < TYPE_ALIGN_UNIT (scalar_type))
13590 : 289450 : scalar_type = lang_hooks.types.type_for_mode (inner_mode,
13591 : 144725 : TYPE_UNSIGNED (scalar_type));
13592 : :
13593 : : /* If we felt back to using the mode fail if there was
13594 : : no scalar type for it. */
13595 : 40239345 : if (scalar_type == NULL_TREE)
13596 : : return NULL_TREE;
13597 : :
13598 : : /* If no prevailing mode was supplied, use the mode the target prefers.
13599 : : Otherwise lookup a vector mode based on the prevailing mode. */
13600 : 40239345 : if (prevailing_mode == VOIDmode)
13601 : : {
13602 : 1003440 : gcc_assert (known_eq (nunits, 0U));
13603 : 1003440 : simd_mode = targetm.vectorize.preferred_simd_mode (inner_mode);
13604 : 1003440 : if (SCALAR_INT_MODE_P (simd_mode))
13605 : : {
13606 : : /* Traditional behavior is not to take the integer mode
13607 : : literally, but simply to use it as a way of determining
13608 : : the vector size. It is up to mode_for_vector to decide
13609 : : what the TYPE_MODE should be.
13610 : :
13611 : : Note that nunits == 1 is allowed in order to support single
13612 : : element vector types. */
13613 : 32776 : if (!multiple_p (GET_MODE_SIZE (simd_mode), nbytes, &nunits)
13614 : 16388 : || !mode_for_vector (inner_mode, nunits).exists (&simd_mode))
13615 : 15953 : return NULL_TREE;
13616 : : }
13617 : : }
13618 : 39235905 : else if (SCALAR_INT_MODE_P (prevailing_mode)
13619 : 78470848 : || !related_vector_mode (prevailing_mode,
13620 : 39234943 : inner_mode, nunits).exists (&simd_mode))
13621 : : {
13622 : : /* Fall back to using mode_for_vector, mostly in the hope of being
13623 : : able to use an integer mode. */
13624 : 2941274 : if (known_eq (nunits, 0U)
13625 : 2935913 : && !multiple_p (GET_MODE_SIZE (prevailing_mode), nbytes, &nunits))
13626 : 1337377 : return NULL_TREE;
13627 : :
13628 : 133260 : if (!mode_for_vector (inner_mode, nunits).exists (&simd_mode))
13629 : : return NULL_TREE;
13630 : : }
13631 : :
13632 : 38763152 : vectype = build_vector_type_for_mode (scalar_type, simd_mode);
13633 : :
13634 : : /* In cases where the mode was chosen by mode_for_vector, check that
13635 : : the target actually supports the chosen mode, or that it at least
13636 : : allows the vector mode to be replaced by a like-sized integer. */
13637 : 77526304 : if (!VECTOR_MODE_P (TYPE_MODE (vectype))
13638 : 38773800 : && !INTEGRAL_MODE_P (TYPE_MODE (vectype)))
13639 : : return NULL_TREE;
13640 : :
13641 : : /* Re-attach the address-space qualifier if we canonicalized the scalar
13642 : : type. */
13643 : 38754912 : if (TYPE_ADDR_SPACE (orig_scalar_type) != TYPE_ADDR_SPACE (vectype))
13644 : 7 : return build_qualified_type
13645 : 7 : (vectype, KEEP_QUAL_ADDR_SPACE (TYPE_QUALS (orig_scalar_type)));
13646 : :
13647 : : return vectype;
13648 : : }
13649 : :
13650 : : /* Function get_vectype_for_scalar_type.
13651 : :
13652 : : Returns the vector type corresponding to SCALAR_TYPE as supported
13653 : : by the target. If GROUP_SIZE is nonzero and we're performing BB
13654 : : vectorization, make sure that the number of elements in the vector
13655 : : is no bigger than GROUP_SIZE. */
13656 : :
13657 : : tree
13658 : 35011138 : get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type,
13659 : : unsigned int group_size)
13660 : : {
13661 : : /* For BB vectorization, we should always have a group size once we've
13662 : : constructed the SLP tree; the only valid uses of zero GROUP_SIZEs
13663 : : are tentative requests during things like early data reference
13664 : : analysis and pattern recognition. */
13665 : 35011138 : if (is_a <bb_vec_info> (vinfo))
13666 : 44493759 : gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0);
13667 : : else
13668 : : group_size = 0;
13669 : :
13670 : 35011138 : tree vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode,
13671 : : scalar_type);
13672 : 35011138 : if (vectype && vinfo->vector_mode == VOIDmode)
13673 : 987487 : vinfo->vector_mode = TYPE_MODE (vectype);
13674 : :
13675 : : /* Register the natural choice of vector type, before the group size
13676 : : has been applied. */
13677 : 0 : if (vectype)
13678 : 33120454 : vinfo->used_vector_modes.add (TYPE_MODE (vectype));
13679 : :
13680 : : /* If the natural choice of vector type doesn't satisfy GROUP_SIZE,
13681 : : try again with an explicit number of elements. */
13682 : 33120454 : if (vectype
13683 : 33120454 : && group_size
13684 : 35011138 : && maybe_ge (TYPE_VECTOR_SUBPARTS (vectype), group_size))
13685 : : {
13686 : : /* Start with the biggest number of units that fits within
13687 : : GROUP_SIZE and halve it until we find a valid vector type.
13688 : : Usually either the first attempt will succeed or all will
13689 : : fail (in the latter case because GROUP_SIZE is too small
13690 : : for the target), but it's possible that a target could have
13691 : : a hole between supported vector types.
13692 : :
13693 : : If GROUP_SIZE is not a power of 2, this has the effect of
13694 : : trying the largest power of 2 that fits within the group,
13695 : : even though the group is not a multiple of that vector size.
13696 : : The BB vectorizer will then try to carve up the group into
13697 : : smaller pieces. */
13698 : 5534344 : unsigned int nunits = 1 << floor_log2 (group_size);
13699 : 5534344 : do
13700 : : {
13701 : 5534344 : vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode,
13702 : : scalar_type, nunits);
13703 : 5534344 : nunits /= 2;
13704 : : }
13705 : 5534344 : while (nunits > 1 && !vectype);
13706 : : }
13707 : :
13708 : 35011138 : return vectype;
13709 : : }
13710 : :
13711 : : /* Return the vector type corresponding to SCALAR_TYPE as supported
13712 : : by the target. NODE, if nonnull, is the SLP tree node that will
13713 : : use the returned vector type. */
13714 : :
13715 : : tree
13716 : 160122 : get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type, slp_tree node)
13717 : : {
13718 : 160122 : unsigned int group_size = 0;
13719 : 160122 : if (node)
13720 : 135722 : group_size = SLP_TREE_LANES (node);
13721 : 160122 : return get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
13722 : : }
13723 : :
13724 : : /* Function get_mask_type_for_scalar_type.
13725 : :
13726 : : Returns the mask type corresponding to a result of comparison
13727 : : of vectors of specified SCALAR_TYPE as supported by target.
13728 : : If GROUP_SIZE is nonzero and we're performing BB vectorization,
13729 : : make sure that the number of elements in the vector is no bigger
13730 : : than GROUP_SIZE. */
13731 : :
13732 : : tree
13733 : 1372455 : get_mask_type_for_scalar_type (vec_info *vinfo, tree scalar_type,
13734 : : unsigned int group_size)
13735 : : {
13736 : 1372455 : tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
13737 : :
13738 : 1372455 : if (!vectype)
13739 : : return NULL;
13740 : :
13741 : 1372455 : return truth_type_for (vectype);
13742 : : }
13743 : :
13744 : : /* Function get_mask_type_for_scalar_type.
13745 : :
13746 : : Returns the mask type corresponding to a result of comparison
13747 : : of vectors of specified SCALAR_TYPE as supported by target.
13748 : : NODE, if nonnull, is the SLP tree node that will use the returned
13749 : : vector type. */
13750 : :
13751 : : tree
13752 : 26 : get_mask_type_for_scalar_type (vec_info *vinfo, tree scalar_type,
13753 : : slp_tree node)
13754 : : {
13755 : 26 : tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type, node);
13756 : :
13757 : 26 : if (!vectype)
13758 : : return NULL;
13759 : :
13760 : 26 : return truth_type_for (vectype);
13761 : : }
13762 : :
13763 : : /* Function get_same_sized_vectype
13764 : :
13765 : : Returns a vector type corresponding to SCALAR_TYPE of size
13766 : : VECTOR_TYPE if supported by the target. */
13767 : :
13768 : : tree
13769 : 93399 : get_same_sized_vectype (tree scalar_type, tree vector_type)
13770 : : {
13771 : 93399 : if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type))
13772 : 0 : return truth_type_for (vector_type);
13773 : :
13774 : 93399 : poly_uint64 nunits;
13775 : 186798 : if (!multiple_p (GET_MODE_SIZE (TYPE_MODE (vector_type)),
13776 : 186798 : GET_MODE_SIZE (TYPE_MODE (scalar_type)), &nunits))
13777 : : return NULL_TREE;
13778 : :
13779 : 93399 : return get_related_vectype_for_scalar_type (TYPE_MODE (vector_type),
13780 : 93399 : scalar_type, nunits);
13781 : : }
13782 : :
13783 : : /* Return true if replacing LOOP_VINFO->vector_mode with VECTOR_MODE
13784 : : would not change the chosen vector modes. */
13785 : :
13786 : : bool
13787 : 1295499 : vect_chooses_same_modes_p (vec_info *vinfo, machine_mode vector_mode)
13788 : : {
13789 : 1295499 : for (vec_info::mode_set::iterator i = vinfo->used_vector_modes.begin ();
13790 : 3026005 : i != vinfo->used_vector_modes.end (); ++i)
13791 : 1560310 : if (!VECTOR_MODE_P (*i)
13792 : 4680930 : || related_vector_mode (vector_mode, GET_MODE_INNER (*i), 0) != *i)
13793 : 695057 : return false;
13794 : 600442 : return true;
13795 : : }
13796 : :
13797 : : /* Function vect_is_simple_use.
13798 : :
13799 : : Input:
13800 : : VINFO - the vect info of the loop or basic block that is being vectorized.
13801 : : OPERAND - operand in the loop or bb.
13802 : : Output:
13803 : : DEF_STMT_INFO_OUT (optional) - information about the defining stmt in
13804 : : case OPERAND is an SSA_NAME that is defined in the vectorizable region
13805 : : DEF_STMT_OUT (optional) - the defining stmt in case OPERAND is an SSA_NAME;
13806 : : the definition could be anywhere in the function
13807 : : DT - the type of definition
13808 : :
13809 : : Returns whether a stmt with OPERAND can be vectorized.
13810 : : For loops, supportable operands are constants, loop invariants, and operands
13811 : : that are defined by the current iteration of the loop. Unsupportable
13812 : : operands are those that are defined by a previous iteration of the loop (as
13813 : : is the case in reduction/induction computations).
13814 : : For basic blocks, supportable operands are constants and bb invariants.
13815 : : For now, operands defined outside the basic block are not supported. */
13816 : :
13817 : : bool
13818 : 35169978 : vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
13819 : : stmt_vec_info *def_stmt_info_out, gimple **def_stmt_out)
13820 : : {
13821 : 35169978 : if (def_stmt_info_out)
13822 : 32646221 : *def_stmt_info_out = NULL;
13823 : 35169978 : if (def_stmt_out)
13824 : 8617850 : *def_stmt_out = NULL;
13825 : 35169978 : *dt = vect_unknown_def_type;
13826 : :
13827 : 35169978 : if (dump_enabled_p ())
13828 : : {
13829 : 668640 : dump_printf_loc (MSG_NOTE, vect_location,
13830 : : "vect_is_simple_use: operand ");
13831 : 668640 : if (TREE_CODE (operand) == SSA_NAME
13832 : 668640 : && !SSA_NAME_IS_DEFAULT_DEF (operand))
13833 : 602665 : dump_gimple_expr (MSG_NOTE, TDF_SLIM, SSA_NAME_DEF_STMT (operand), 0);
13834 : : else
13835 : 65975 : dump_generic_expr (MSG_NOTE, TDF_SLIM, operand);
13836 : : }
13837 : :
13838 : 35169978 : if (CONSTANT_CLASS_P (operand))
13839 : 3077878 : *dt = vect_constant_def;
13840 : 32092100 : else if (is_gimple_min_invariant (operand))
13841 : 317707 : *dt = vect_external_def;
13842 : 31774393 : else if (TREE_CODE (operand) != SSA_NAME)
13843 : 1088 : *dt = vect_unknown_def_type;
13844 : 31773305 : else if (SSA_NAME_IS_DEFAULT_DEF (operand))
13845 : 463265 : *dt = vect_external_def;
13846 : : else
13847 : : {
13848 : 31310040 : gimple *def_stmt = SSA_NAME_DEF_STMT (operand);
13849 : 31310040 : stmt_vec_info stmt_vinfo = vinfo->lookup_def (operand);
13850 : 31310040 : if (!stmt_vinfo)
13851 : 634530 : *dt = vect_external_def;
13852 : : else
13853 : : {
13854 : 30675510 : stmt_vinfo = vect_stmt_to_vectorize (stmt_vinfo);
13855 : 30675510 : def_stmt = stmt_vinfo->stmt;
13856 : 30675510 : *dt = STMT_VINFO_DEF_TYPE (stmt_vinfo);
13857 : 30675510 : if (def_stmt_info_out)
13858 : 29495093 : *def_stmt_info_out = stmt_vinfo;
13859 : : }
13860 : 31310040 : if (def_stmt_out)
13861 : 8214704 : *def_stmt_out = def_stmt;
13862 : : }
13863 : :
13864 : 35169978 : if (dump_enabled_p ())
13865 : : {
13866 : 668640 : dump_printf (MSG_NOTE, ", type of def: ");
13867 : 668640 : switch (*dt)
13868 : : {
13869 : 0 : case vect_uninitialized_def:
13870 : 0 : dump_printf (MSG_NOTE, "uninitialized\n");
13871 : 0 : break;
13872 : 56666 : case vect_constant_def:
13873 : 56666 : dump_printf (MSG_NOTE, "constant\n");
13874 : 56666 : break;
13875 : 25470 : case vect_external_def:
13876 : 25470 : dump_printf (MSG_NOTE, "external\n");
13877 : 25470 : break;
13878 : 477867 : case vect_internal_def:
13879 : 477867 : dump_printf (MSG_NOTE, "internal\n");
13880 : 477867 : break;
13881 : 89473 : case vect_induction_def:
13882 : 89473 : dump_printf (MSG_NOTE, "induction\n");
13883 : 89473 : break;
13884 : 16729 : case vect_reduction_def:
13885 : 16729 : dump_printf (MSG_NOTE, "reduction\n");
13886 : 16729 : break;
13887 : 205 : case vect_double_reduction_def:
13888 : 205 : dump_printf (MSG_NOTE, "double reduction\n");
13889 : 205 : break;
13890 : 1543 : case vect_nested_cycle:
13891 : 1543 : dump_printf (MSG_NOTE, "nested cycle\n");
13892 : 1543 : break;
13893 : 174 : case vect_first_order_recurrence:
13894 : 174 : dump_printf (MSG_NOTE, "first order recurrence\n");
13895 : 174 : break;
13896 : 0 : case vect_condition_def:
13897 : 0 : dump_printf (MSG_NOTE, "control flow\n");
13898 : 0 : break;
13899 : 513 : case vect_unknown_def_type:
13900 : 513 : dump_printf (MSG_NOTE, "unknown\n");
13901 : 513 : break;
13902 : : }
13903 : : }
13904 : :
13905 : 35169978 : if (*dt == vect_unknown_def_type)
13906 : : {
13907 : 17455 : if (dump_enabled_p ())
13908 : 513 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
13909 : : "Unsupported pattern.\n");
13910 : 17455 : return false;
13911 : : }
13912 : :
13913 : : return true;
13914 : : }
13915 : :
13916 : : /* Function vect_is_simple_use.
13917 : :
13918 : : Same as vect_is_simple_use but also determines the vector operand
13919 : : type of OPERAND and stores it to *VECTYPE. If the definition of
13920 : : OPERAND is vect_uninitialized_def, vect_constant_def or
13921 : : vect_external_def *VECTYPE will be set to NULL_TREE and the caller
13922 : : is responsible to compute the best suited vector type for the
13923 : : scalar operand. */
13924 : :
13925 : : bool
13926 : 1194170 : vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
13927 : : tree *vectype, stmt_vec_info *def_stmt_info_out,
13928 : : gimple **def_stmt_out)
13929 : : {
13930 : 1194170 : stmt_vec_info def_stmt_info;
13931 : 1194170 : gimple *def_stmt;
13932 : 1194170 : if (!vect_is_simple_use (operand, vinfo, dt, &def_stmt_info, &def_stmt))
13933 : : return false;
13934 : :
13935 : 1194051 : if (def_stmt_out)
13936 : 0 : *def_stmt_out = def_stmt;
13937 : 1194051 : if (def_stmt_info_out)
13938 : 134008 : *def_stmt_info_out = def_stmt_info;
13939 : :
13940 : : /* Now get a vector type if the def is internal, otherwise supply
13941 : : NULL_TREE and leave it up to the caller to figure out a proper
13942 : : type for the use stmt. */
13943 : 1194051 : if (*dt == vect_internal_def
13944 : : || *dt == vect_induction_def
13945 : : || *dt == vect_reduction_def
13946 : : || *dt == vect_double_reduction_def
13947 : : || *dt == vect_nested_cycle
13948 : 1194051 : || *dt == vect_first_order_recurrence)
13949 : : {
13950 : 982089 : *vectype = STMT_VINFO_VECTYPE (def_stmt_info);
13951 : 982089 : gcc_assert (*vectype != NULL_TREE);
13952 : 982089 : if (dump_enabled_p ())
13953 : 123577 : dump_printf_loc (MSG_NOTE, vect_location,
13954 : : "vect_is_simple_use: vectype %T\n", *vectype);
13955 : : }
13956 : 211962 : else if (*dt == vect_uninitialized_def
13957 : : || *dt == vect_constant_def
13958 : : || *dt == vect_external_def)
13959 : 211962 : *vectype = NULL_TREE;
13960 : : else
13961 : 0 : gcc_unreachable ();
13962 : :
13963 : : return true;
13964 : : }
13965 : :
13966 : : /* Function vect_is_simple_use.
13967 : :
13968 : : Same as vect_is_simple_use but determines the operand by operand
13969 : : position OPERAND from either STMT or SLP_NODE, filling in *OP
13970 : : and *SLP_DEF (when SLP_NODE is not NULL). */
13971 : :
13972 : : bool
13973 : 2949339 : vect_is_simple_use (vec_info *vinfo, stmt_vec_info stmt, slp_tree slp_node,
13974 : : unsigned operand, tree *op, slp_tree *slp_def,
13975 : : enum vect_def_type *dt,
13976 : : tree *vectype, stmt_vec_info *def_stmt_info_out)
13977 : : {
13978 : 2949339 : if (slp_node)
13979 : : {
13980 : 1759966 : slp_tree child = SLP_TREE_CHILDREN (slp_node)[operand];
13981 : 1759966 : *slp_def = child;
13982 : 1759966 : *vectype = SLP_TREE_VECTYPE (child);
13983 : 1759966 : if (SLP_TREE_DEF_TYPE (child) == vect_internal_def)
13984 : : {
13985 : 525582 : *op = gimple_get_lhs (SLP_TREE_REPRESENTATIVE (child)->stmt);
13986 : 525582 : return vect_is_simple_use (*op, vinfo, dt, def_stmt_info_out);
13987 : : }
13988 : : else
13989 : : {
13990 : 1234384 : if (def_stmt_info_out)
13991 : 22539 : *def_stmt_info_out = NULL;
13992 : 1234384 : *op = SLP_TREE_SCALAR_OPS (child)[0];
13993 : 1234384 : *dt = SLP_TREE_DEF_TYPE (child);
13994 : 1234384 : return true;
13995 : : }
13996 : : }
13997 : : else
13998 : : {
13999 : 1189373 : *slp_def = NULL;
14000 : 1189373 : if (gassign *ass = dyn_cast <gassign *> (stmt->stmt))
14001 : : {
14002 : 1125838 : if (gimple_assign_rhs_code (ass) == COND_EXPR
14003 : 1125838 : && COMPARISON_CLASS_P (gimple_assign_rhs1 (ass)))
14004 : : {
14005 : 4748 : if (operand < 2)
14006 : 1470 : *op = TREE_OPERAND (gimple_assign_rhs1 (ass), operand);
14007 : : else
14008 : 3278 : *op = gimple_op (ass, operand);
14009 : : }
14010 : 1121090 : else if (gimple_assign_rhs_code (ass) == VIEW_CONVERT_EXPR)
14011 : 132 : *op = TREE_OPERAND (gimple_assign_rhs1 (ass), 0);
14012 : : else
14013 : 1120958 : *op = gimple_op (ass, operand + 1);
14014 : : }
14015 : 63535 : else if (gcond *cond = dyn_cast <gcond *> (stmt->stmt))
14016 : 25480 : *op = gimple_op (cond, operand);
14017 : 38055 : else if (gcall *call = dyn_cast <gcall *> (stmt->stmt))
14018 : 38055 : *op = gimple_call_arg (call, operand);
14019 : : else
14020 : 0 : gcc_unreachable ();
14021 : 1189373 : return vect_is_simple_use (*op, vinfo, dt, vectype, def_stmt_info_out);
14022 : : }
14023 : : }
14024 : :
14025 : : /* If OP is not NULL and is external or constant update its vector
14026 : : type with VECTYPE. Returns true if successful or false if not,
14027 : : for example when conflicting vector types are present. */
14028 : :
14029 : : bool
14030 : 1389618 : vect_maybe_update_slp_op_vectype (slp_tree op, tree vectype)
14031 : : {
14032 : 1389618 : if (!op || SLP_TREE_DEF_TYPE (op) == vect_internal_def)
14033 : : return true;
14034 : 768826 : if (SLP_TREE_VECTYPE (op))
14035 : 65301 : return types_compatible_p (SLP_TREE_VECTYPE (op), vectype);
14036 : : /* For external defs refuse to produce VECTOR_BOOLEAN_TYPE_P, those
14037 : : should be handled by patters. Allow vect_constant_def for now. */
14038 : 703525 : if (VECTOR_BOOLEAN_TYPE_P (vectype)
14039 : 703981 : && SLP_TREE_DEF_TYPE (op) == vect_external_def)
14040 : : return false;
14041 : 703167 : SLP_TREE_VECTYPE (op) = vectype;
14042 : 703167 : return true;
14043 : : }
14044 : :
14045 : : /* Function supportable_widening_operation
14046 : :
14047 : : Check whether an operation represented by the code CODE is a
14048 : : widening operation that is supported by the target platform in
14049 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
14050 : : producing a result of type VECTYPE_OUT).
14051 : :
14052 : : Widening operations we currently support are NOP (CONVERT), FLOAT,
14053 : : FIX_TRUNC and WIDEN_MULT. This function checks if these operations
14054 : : are supported by the target platform either directly (via vector
14055 : : tree-codes), or via target builtins.
14056 : :
14057 : : Output:
14058 : : - CODE1 and CODE2 are codes of vector operations to be used when
14059 : : vectorizing the operation, if available.
14060 : : - MULTI_STEP_CVT determines the number of required intermediate steps in
14061 : : case of multi-step conversion (like char->short->int - in that case
14062 : : MULTI_STEP_CVT will be 1).
14063 : : - INTERM_TYPES contains the intermediate type required to perform the
14064 : : widening operation (short in the above example). */
14065 : :
14066 : : bool
14067 : 229787 : supportable_widening_operation (vec_info *vinfo,
14068 : : code_helper code,
14069 : : stmt_vec_info stmt_info,
14070 : : tree vectype_out, tree vectype_in,
14071 : : code_helper *code1,
14072 : : code_helper *code2,
14073 : : int *multi_step_cvt,
14074 : : vec<tree> *interm_types)
14075 : : {
14076 : 229787 : loop_vec_info loop_info = dyn_cast <loop_vec_info> (vinfo);
14077 : 229787 : class loop *vect_loop = NULL;
14078 : 229787 : machine_mode vec_mode;
14079 : 229787 : enum insn_code icode1, icode2;
14080 : 229787 : optab optab1 = unknown_optab, optab2 = unknown_optab;
14081 : 229787 : tree vectype = vectype_in;
14082 : 229787 : tree wide_vectype = vectype_out;
14083 : 229787 : tree_code c1 = MAX_TREE_CODES, c2 = MAX_TREE_CODES;
14084 : 229787 : int i;
14085 : 229787 : tree prev_type, intermediate_type;
14086 : 229787 : machine_mode intermediate_mode, prev_mode;
14087 : 229787 : optab optab3, optab4;
14088 : :
14089 : 229787 : *multi_step_cvt = 0;
14090 : 154203 : if (loop_info)
14091 : 75584 : vect_loop = LOOP_VINFO_LOOP (loop_info);
14092 : :
14093 : 229787 : switch (code.safe_as_tree_code ())
14094 : : {
14095 : : case MAX_TREE_CODES:
14096 : : /* Don't set c1 and c2 if code is not a tree_code. */
14097 : : break;
14098 : :
14099 : 144865 : case WIDEN_MULT_EXPR:
14100 : : /* The result of a vectorized widening operation usually requires
14101 : : two vectors (because the widened results do not fit into one vector).
14102 : : The generated vector results would normally be expected to be
14103 : : generated in the same order as in the original scalar computation,
14104 : : i.e. if 8 results are generated in each vector iteration, they are
14105 : : to be organized as follows:
14106 : : vect1: [res1,res2,res3,res4],
14107 : : vect2: [res5,res6,res7,res8].
14108 : :
14109 : : However, in the special case that the result of the widening
14110 : : operation is used in a reduction computation only, the order doesn't
14111 : : matter (because when vectorizing a reduction we change the order of
14112 : : the computation). Some targets can take advantage of this and
14113 : : generate more efficient code. For example, targets like Altivec,
14114 : : that support widen_mult using a sequence of {mult_even,mult_odd}
14115 : : generate the following vectors:
14116 : : vect1: [res1,res3,res5,res7],
14117 : : vect2: [res2,res4,res6,res8].
14118 : :
14119 : : When vectorizing outer-loops, we execute the inner-loop sequentially
14120 : : (each vectorized inner-loop iteration contributes to VF outer-loop
14121 : : iterations in parallel). We therefore don't allow to change the
14122 : : order of the computation in the inner-loop during outer-loop
14123 : : vectorization. */
14124 : : /* TODO: Another case in which order doesn't *really* matter is when we
14125 : : widen and then contract again, e.g. (short)((int)x * y >> 8).
14126 : : Normally, pack_trunc performs an even/odd permute, whereas the
14127 : : repack from an even/odd expansion would be an interleave, which
14128 : : would be significantly simpler for e.g. AVX2. */
14129 : : /* In any case, in order to avoid duplicating the code below, recurse
14130 : : on VEC_WIDEN_MULT_EVEN_EXPR. If it succeeds, all the return values
14131 : : are properly set up for the caller. If we fail, we'll continue with
14132 : : a VEC_WIDEN_MULT_LO/HI_EXPR check. */
14133 : 144865 : if (vect_loop
14134 : 42035 : && STMT_VINFO_RELEVANT (stmt_info) == vect_used_by_reduction
14135 : 0 : && !nested_in_vect_loop_p (vect_loop, stmt_info)
14136 : 186900 : && supportable_widening_operation (vinfo, VEC_WIDEN_MULT_EVEN_EXPR,
14137 : : stmt_info, vectype_out,
14138 : : vectype_in, code1,
14139 : : code2, multi_step_cvt,
14140 : : interm_types))
14141 : : {
14142 : : /* Elements in a vector with vect_used_by_reduction property cannot
14143 : : be reordered if the use chain with this property does not have the
14144 : : same operation. One such an example is s += a * b, where elements
14145 : : in a and b cannot be reordered. Here we check if the vector defined
14146 : : by STMT is only directly used in the reduction statement. */
14147 : 0 : tree lhs = gimple_assign_lhs (stmt_info->stmt);
14148 : 0 : stmt_vec_info use_stmt_info = loop_info->lookup_single_use (lhs);
14149 : 0 : if (use_stmt_info
14150 : 0 : && STMT_VINFO_DEF_TYPE (use_stmt_info) == vect_reduction_def)
14151 : : return true;
14152 : : }
14153 : : c1 = VEC_WIDEN_MULT_LO_EXPR;
14154 : : c2 = VEC_WIDEN_MULT_HI_EXPR;
14155 : : break;
14156 : :
14157 : : case DOT_PROD_EXPR:
14158 : 229787 : c1 = DOT_PROD_EXPR;
14159 : 229787 : c2 = DOT_PROD_EXPR;
14160 : : break;
14161 : :
14162 : 0 : case SAD_EXPR:
14163 : 0 : c1 = SAD_EXPR;
14164 : 0 : c2 = SAD_EXPR;
14165 : 0 : break;
14166 : :
14167 : 0 : case VEC_WIDEN_MULT_EVEN_EXPR:
14168 : : /* Support the recursion induced just above. */
14169 : 0 : c1 = VEC_WIDEN_MULT_EVEN_EXPR;
14170 : 0 : c2 = VEC_WIDEN_MULT_ODD_EXPR;
14171 : 0 : break;
14172 : :
14173 : 8420 : case WIDEN_LSHIFT_EXPR:
14174 : 8420 : c1 = VEC_WIDEN_LSHIFT_LO_EXPR;
14175 : 8420 : c2 = VEC_WIDEN_LSHIFT_HI_EXPR;
14176 : 8420 : break;
14177 : :
14178 : 21865 : CASE_CONVERT:
14179 : 21865 : c1 = VEC_UNPACK_LO_EXPR;
14180 : 21865 : c2 = VEC_UNPACK_HI_EXPR;
14181 : 21865 : break;
14182 : :
14183 : 5718 : case FLOAT_EXPR:
14184 : 5718 : c1 = VEC_UNPACK_FLOAT_LO_EXPR;
14185 : 5718 : c2 = VEC_UNPACK_FLOAT_HI_EXPR;
14186 : 5718 : break;
14187 : :
14188 : 206 : case FIX_TRUNC_EXPR:
14189 : 206 : c1 = VEC_UNPACK_FIX_TRUNC_LO_EXPR;
14190 : 206 : c2 = VEC_UNPACK_FIX_TRUNC_HI_EXPR;
14191 : 206 : break;
14192 : :
14193 : 0 : default:
14194 : 0 : gcc_unreachable ();
14195 : : }
14196 : :
14197 : 229787 : if (BYTES_BIG_ENDIAN && c1 != VEC_WIDEN_MULT_EVEN_EXPR)
14198 : : std::swap (c1, c2);
14199 : :
14200 : 229787 : if (code == FIX_TRUNC_EXPR)
14201 : : {
14202 : : /* The signedness is determined from output operand. */
14203 : 206 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
14204 : 206 : optab2 = optab_for_tree_code (c2, vectype_out, optab_default);
14205 : : }
14206 : 392014 : else if (CONVERT_EXPR_CODE_P (code.safe_as_tree_code ())
14207 : 21865 : && VECTOR_BOOLEAN_TYPE_P (wide_vectype)
14208 : 3175 : && VECTOR_BOOLEAN_TYPE_P (vectype)
14209 : 3175 : && TYPE_MODE (wide_vectype) == TYPE_MODE (vectype)
14210 : 181139 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype)))
14211 : : {
14212 : : /* If the input and result modes are the same, a different optab
14213 : : is needed where we pass in the number of units in vectype. */
14214 : : optab1 = vec_unpacks_sbool_lo_optab;
14215 : : optab2 = vec_unpacks_sbool_hi_optab;
14216 : : }
14217 : :
14218 : 229787 : vec_mode = TYPE_MODE (vectype);
14219 : 229787 : if (widening_fn_p (code))
14220 : : {
14221 : : /* If this is an internal fn then we must check whether the target
14222 : : supports either a low-high split or an even-odd split. */
14223 : 48713 : internal_fn ifn = as_internal_fn ((combined_fn) code);
14224 : :
14225 : 48713 : internal_fn lo, hi, even, odd;
14226 : 48713 : lookup_hilo_internal_fn (ifn, &lo, &hi);
14227 : 48713 : *code1 = as_combined_fn (lo);
14228 : 48713 : *code2 = as_combined_fn (hi);
14229 : 48713 : optab1 = direct_internal_fn_optab (lo, {vectype, vectype});
14230 : 48713 : optab2 = direct_internal_fn_optab (hi, {vectype, vectype});
14231 : :
14232 : : /* If we don't support low-high, then check for even-odd. */
14233 : 48713 : if (!optab1
14234 : 48713 : || (icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing
14235 : 0 : || !optab2
14236 : 48713 : || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing)
14237 : : {
14238 : 48713 : lookup_evenodd_internal_fn (ifn, &even, &odd);
14239 : 48713 : *code1 = as_combined_fn (even);
14240 : 48713 : *code2 = as_combined_fn (odd);
14241 : 48713 : optab1 = direct_internal_fn_optab (even, {vectype, vectype});
14242 : 48713 : optab2 = direct_internal_fn_optab (odd, {vectype, vectype});
14243 : : }
14244 : : }
14245 : 181074 : else if (code.is_tree_code ())
14246 : : {
14247 : 181074 : if (code == FIX_TRUNC_EXPR)
14248 : : {
14249 : : /* The signedness is determined from output operand. */
14250 : 206 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
14251 : 206 : optab2 = optab_for_tree_code (c2, vectype_out, optab_default);
14252 : : }
14253 : 180868 : else if (CONVERT_EXPR_CODE_P ((tree_code) code.safe_as_tree_code ())
14254 : 21865 : && VECTOR_BOOLEAN_TYPE_P (wide_vectype)
14255 : 3175 : && VECTOR_BOOLEAN_TYPE_P (vectype)
14256 : 3175 : && TYPE_MODE (wide_vectype) == TYPE_MODE (vectype)
14257 : 181139 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype)))
14258 : : {
14259 : : /* If the input and result modes are the same, a different optab
14260 : : is needed where we pass in the number of units in vectype. */
14261 : : optab1 = vec_unpacks_sbool_lo_optab;
14262 : : optab2 = vec_unpacks_sbool_hi_optab;
14263 : : }
14264 : : else
14265 : : {
14266 : 180597 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
14267 : 180597 : optab2 = optab_for_tree_code (c2, vectype, optab_default);
14268 : : }
14269 : 181074 : *code1 = c1;
14270 : 181074 : *code2 = c2;
14271 : : }
14272 : :
14273 : 229787 : if (!optab1 || !optab2)
14274 : : return false;
14275 : :
14276 : 229787 : if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing
14277 : 229787 : || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing)
14278 : 124139 : return false;
14279 : :
14280 : :
14281 : 105648 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype)
14282 : 105648 : && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype))
14283 : : {
14284 : 99848 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14285 : : return true;
14286 : : /* For scalar masks we may have different boolean
14287 : : vector types having the same QImode. Thus we
14288 : : add additional check for elements number. */
14289 : 1580 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype),
14290 : : TYPE_VECTOR_SUBPARTS (wide_vectype) * 2))
14291 : : return true;
14292 : : }
14293 : :
14294 : : /* Check if it's a multi-step conversion that can be done using intermediate
14295 : : types. */
14296 : :
14297 : 5852 : prev_type = vectype;
14298 : 5852 : prev_mode = vec_mode;
14299 : :
14300 : 130774 : if (!CONVERT_EXPR_CODE_P (code.safe_as_tree_code ()))
14301 : : return false;
14302 : :
14303 : : /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS
14304 : : intermediate steps in promotion sequence. We try
14305 : : MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do
14306 : : not. */
14307 : 5800 : interm_types->create (MAX_INTERM_CVT_STEPS);
14308 : 6774 : for (i = 0; i < MAX_INTERM_CVT_STEPS; i++)
14309 : : {
14310 : 6774 : intermediate_mode = insn_data[icode1].operand[0].mode;
14311 : 6774 : if (VECTOR_BOOLEAN_TYPE_P (prev_type))
14312 : 2101 : intermediate_type
14313 : 2101 : = vect_halve_mask_nunits (prev_type, intermediate_mode);
14314 : 4673 : else if (VECTOR_MODE_P (intermediate_mode))
14315 : : {
14316 : 4673 : tree intermediate_element_type
14317 : 4673 : = lang_hooks.types.type_for_mode (GET_MODE_INNER (intermediate_mode),
14318 : 4673 : TYPE_UNSIGNED (prev_type));
14319 : 4673 : intermediate_type
14320 : 4673 : = build_vector_type_for_mode (intermediate_element_type,
14321 : : intermediate_mode);
14322 : 4673 : }
14323 : : else
14324 : 0 : intermediate_type
14325 : 0 : = lang_hooks.types.type_for_mode (intermediate_mode,
14326 : 0 : TYPE_UNSIGNED (prev_type));
14327 : :
14328 : 6774 : if (VECTOR_BOOLEAN_TYPE_P (intermediate_type)
14329 : 2101 : && VECTOR_BOOLEAN_TYPE_P (prev_type)
14330 : 2101 : && intermediate_mode == prev_mode
14331 : 6774 : && SCALAR_INT_MODE_P (prev_mode))
14332 : : {
14333 : : /* If the input and result modes are the same, a different optab
14334 : : is needed where we pass in the number of units in vectype. */
14335 : : optab3 = vec_unpacks_sbool_lo_optab;
14336 : : optab4 = vec_unpacks_sbool_hi_optab;
14337 : : }
14338 : : else
14339 : : {
14340 : 6774 : optab3 = optab_for_tree_code (c1, intermediate_type, optab_default);
14341 : 6774 : optab4 = optab_for_tree_code (c2, intermediate_type, optab_default);
14342 : : }
14343 : :
14344 : 6774 : if (!optab3 || !optab4
14345 : 6774 : || (icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing
14346 : 6774 : || insn_data[icode1].operand[0].mode != intermediate_mode
14347 : 6774 : || (icode2 = optab_handler (optab2, prev_mode)) == CODE_FOR_nothing
14348 : 6774 : || insn_data[icode2].operand[0].mode != intermediate_mode
14349 : 6774 : || ((icode1 = optab_handler (optab3, intermediate_mode))
14350 : : == CODE_FOR_nothing)
14351 : 12765 : || ((icode2 = optab_handler (optab4, intermediate_mode))
14352 : : == CODE_FOR_nothing))
14353 : : break;
14354 : :
14355 : 5991 : interm_types->quick_push (intermediate_type);
14356 : 5991 : (*multi_step_cvt)++;
14357 : :
14358 : 5991 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype)
14359 : 5991 : && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype))
14360 : : {
14361 : 5027 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14362 : : return true;
14363 : 977 : if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type),
14364 : : TYPE_VECTOR_SUBPARTS (wide_vectype) * 2))
14365 : : return true;
14366 : : }
14367 : :
14368 : 974 : prev_type = intermediate_type;
14369 : 974 : prev_mode = intermediate_mode;
14370 : : }
14371 : :
14372 : 783 : interm_types->release ();
14373 : 783 : return false;
14374 : : }
14375 : :
14376 : :
14377 : : /* Function supportable_narrowing_operation
14378 : :
14379 : : Check whether an operation represented by the code CODE is a
14380 : : narrowing operation that is supported by the target platform in
14381 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
14382 : : and producing a result of type VECTYPE_OUT).
14383 : :
14384 : : Narrowing operations we currently support are NOP (CONVERT), FIX_TRUNC
14385 : : and FLOAT. This function checks if these operations are supported by
14386 : : the target platform directly via vector tree-codes.
14387 : :
14388 : : Output:
14389 : : - CODE1 is the code of a vector operation to be used when
14390 : : vectorizing the operation, if available.
14391 : : - MULTI_STEP_CVT determines the number of required intermediate steps in
14392 : : case of multi-step conversion (like int->short->char - in that case
14393 : : MULTI_STEP_CVT will be 1).
14394 : : - INTERM_TYPES contains the intermediate type required to perform the
14395 : : narrowing operation (short in the above example). */
14396 : :
14397 : : bool
14398 : 25896 : supportable_narrowing_operation (code_helper code,
14399 : : tree vectype_out, tree vectype_in,
14400 : : code_helper *code1, int *multi_step_cvt,
14401 : : vec<tree> *interm_types)
14402 : : {
14403 : 25896 : machine_mode vec_mode;
14404 : 25896 : enum insn_code icode1;
14405 : 25896 : optab optab1, interm_optab;
14406 : 25896 : tree vectype = vectype_in;
14407 : 25896 : tree narrow_vectype = vectype_out;
14408 : 25896 : enum tree_code c1;
14409 : 25896 : tree intermediate_type, prev_type;
14410 : 25896 : machine_mode intermediate_mode, prev_mode;
14411 : 25896 : int i;
14412 : 25896 : unsigned HOST_WIDE_INT n_elts;
14413 : 25896 : bool uns;
14414 : :
14415 : 25896 : if (!code.is_tree_code ())
14416 : : return false;
14417 : :
14418 : 25896 : *multi_step_cvt = 0;
14419 : 25896 : switch ((tree_code) code)
14420 : : {
14421 : 25133 : CASE_CONVERT:
14422 : 25133 : c1 = VEC_PACK_TRUNC_EXPR;
14423 : 25133 : if (VECTOR_BOOLEAN_TYPE_P (narrow_vectype)
14424 : 3378 : && VECTOR_BOOLEAN_TYPE_P (vectype)
14425 : 3378 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype))
14426 : 1355 : && TYPE_VECTOR_SUBPARTS (vectype).is_constant (&n_elts)
14427 : 26488 : && n_elts < BITS_PER_UNIT)
14428 : : optab1 = vec_pack_sbool_trunc_optab;
14429 : : else
14430 : 24518 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
14431 : : break;
14432 : :
14433 : 643 : case FIX_TRUNC_EXPR:
14434 : 643 : c1 = VEC_PACK_FIX_TRUNC_EXPR;
14435 : : /* The signedness is determined from output operand. */
14436 : 643 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
14437 : 643 : break;
14438 : :
14439 : 120 : case FLOAT_EXPR:
14440 : 120 : c1 = VEC_PACK_FLOAT_EXPR;
14441 : 120 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
14442 : 120 : break;
14443 : :
14444 : 0 : default:
14445 : 0 : gcc_unreachable ();
14446 : : }
14447 : :
14448 : 25896 : if (!optab1)
14449 : : return false;
14450 : :
14451 : 25896 : vec_mode = TYPE_MODE (vectype);
14452 : 25896 : if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing)
14453 : : return false;
14454 : :
14455 : 23013 : *code1 = c1;
14456 : :
14457 : 23013 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype))
14458 : : {
14459 : 15912 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14460 : : return true;
14461 : : /* For scalar masks we may have different boolean
14462 : : vector types having the same QImode. Thus we
14463 : : add additional check for elements number. */
14464 : 2585 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype) * 2,
14465 : : TYPE_VECTOR_SUBPARTS (narrow_vectype)))
14466 : : return true;
14467 : : }
14468 : :
14469 : 7103 : if (code == FLOAT_EXPR)
14470 : : return false;
14471 : :
14472 : : /* Check if it's a multi-step conversion that can be done using intermediate
14473 : : types. */
14474 : 7103 : prev_mode = vec_mode;
14475 : 7103 : prev_type = vectype;
14476 : 7103 : if (code == FIX_TRUNC_EXPR)
14477 : 121 : uns = TYPE_UNSIGNED (vectype_out);
14478 : : else
14479 : 6982 : uns = TYPE_UNSIGNED (vectype);
14480 : :
14481 : : /* For multi-step FIX_TRUNC_EXPR prefer signed floating to integer
14482 : : conversion over unsigned, as unsigned FIX_TRUNC_EXPR is often more
14483 : : costly than signed. */
14484 : 7103 : if (code == FIX_TRUNC_EXPR && uns)
14485 : : {
14486 : 52 : enum insn_code icode2;
14487 : :
14488 : 52 : intermediate_type
14489 : 52 : = lang_hooks.types.type_for_mode (TYPE_MODE (vectype_out), 0);
14490 : 52 : interm_optab
14491 : 52 : = optab_for_tree_code (c1, intermediate_type, optab_default);
14492 : 52 : if (interm_optab != unknown_optab
14493 : 52 : && (icode2 = optab_handler (optab1, vec_mode)) != CODE_FOR_nothing
14494 : 52 : && insn_data[icode1].operand[0].mode
14495 : 52 : == insn_data[icode2].operand[0].mode)
14496 : : {
14497 : : uns = false;
14498 : : optab1 = interm_optab;
14499 : : icode1 = icode2;
14500 : : }
14501 : : }
14502 : :
14503 : : /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS
14504 : : intermediate steps in promotion sequence. We try
14505 : : MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do not. */
14506 : 7103 : interm_types->create (MAX_INTERM_CVT_STEPS);
14507 : 14965 : for (i = 0; i < MAX_INTERM_CVT_STEPS; i++)
14508 : : {
14509 : 7862 : intermediate_mode = insn_data[icode1].operand[0].mode;
14510 : 7862 : if (VECTOR_BOOLEAN_TYPE_P (prev_type))
14511 : 1029 : intermediate_type
14512 : 1029 : = vect_double_mask_nunits (prev_type, intermediate_mode);
14513 : : else
14514 : 6833 : intermediate_type
14515 : 6833 : = lang_hooks.types.type_for_mode (intermediate_mode, uns);
14516 : 7862 : if (VECTOR_BOOLEAN_TYPE_P (intermediate_type)
14517 : 1029 : && VECTOR_BOOLEAN_TYPE_P (prev_type)
14518 : 1029 : && SCALAR_INT_MODE_P (prev_mode)
14519 : 375 : && TYPE_VECTOR_SUBPARTS (intermediate_type).is_constant (&n_elts)
14520 : 8237 : && n_elts < BITS_PER_UNIT)
14521 : : interm_optab = vec_pack_sbool_trunc_optab;
14522 : : else
14523 : 7839 : interm_optab
14524 : 7839 : = optab_for_tree_code (VEC_PACK_TRUNC_EXPR, intermediate_type,
14525 : : optab_default);
14526 : 23 : if (!interm_optab
14527 : 7862 : || ((icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing)
14528 : 7862 : || insn_data[icode1].operand[0].mode != intermediate_mode
14529 : 15701 : || ((icode1 = optab_handler (interm_optab, intermediate_mode))
14530 : : == CODE_FOR_nothing))
14531 : : break;
14532 : :
14533 : 7563 : interm_types->quick_push (intermediate_type);
14534 : 7563 : (*multi_step_cvt)++;
14535 : :
14536 : 7563 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype))
14537 : : {
14538 : 6804 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14539 : : return true;
14540 : 603 : if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type) * 2,
14541 : : TYPE_VECTOR_SUBPARTS (narrow_vectype)))
14542 : : return true;
14543 : : }
14544 : :
14545 : 759 : prev_mode = intermediate_mode;
14546 : 759 : prev_type = intermediate_type;
14547 : 759 : optab1 = interm_optab;
14548 : : }
14549 : :
14550 : 299 : interm_types->release ();
14551 : 299 : return false;
14552 : : }
14553 : :
14554 : : /* Generate and return a vector mask of MASK_TYPE such that
14555 : : mask[I] is true iff J + START_INDEX < END_INDEX for all J <= I.
14556 : : Add the statements to SEQ. */
14557 : :
14558 : : tree
14559 : 0 : vect_gen_while (gimple_seq *seq, tree mask_type, tree start_index,
14560 : : tree end_index, const char *name)
14561 : : {
14562 : 0 : tree cmp_type = TREE_TYPE (start_index);
14563 : 0 : gcc_checking_assert (direct_internal_fn_supported_p (IFN_WHILE_ULT,
14564 : : cmp_type, mask_type,
14565 : : OPTIMIZE_FOR_SPEED));
14566 : 0 : gcall *call = gimple_build_call_internal (IFN_WHILE_ULT, 3,
14567 : : start_index, end_index,
14568 : : build_zero_cst (mask_type));
14569 : 0 : tree tmp;
14570 : 0 : if (name)
14571 : 0 : tmp = make_temp_ssa_name (mask_type, NULL, name);
14572 : : else
14573 : 0 : tmp = make_ssa_name (mask_type);
14574 : 0 : gimple_call_set_lhs (call, tmp);
14575 : 0 : gimple_seq_add_stmt (seq, call);
14576 : 0 : return tmp;
14577 : : }
14578 : :
14579 : : /* Generate a vector mask of type MASK_TYPE for which index I is false iff
14580 : : J + START_INDEX < END_INDEX for all J <= I. Add the statements to SEQ. */
14581 : :
14582 : : tree
14583 : 0 : vect_gen_while_not (gimple_seq *seq, tree mask_type, tree start_index,
14584 : : tree end_index)
14585 : : {
14586 : 0 : tree tmp = vect_gen_while (seq, mask_type, start_index, end_index);
14587 : 0 : return gimple_build (seq, BIT_NOT_EXPR, mask_type, tmp);
14588 : : }
14589 : :
14590 : : /* Try to compute the vector types required to vectorize STMT_INFO,
14591 : : returning true on success and false if vectorization isn't possible.
14592 : : If GROUP_SIZE is nonzero and we're performing BB vectorization,
14593 : : take sure that the number of elements in the vectors is no bigger
14594 : : than GROUP_SIZE.
14595 : :
14596 : : On success:
14597 : :
14598 : : - Set *STMT_VECTYPE_OUT to:
14599 : : - NULL_TREE if the statement doesn't need to be vectorized;
14600 : : - the equivalent of STMT_VINFO_VECTYPE otherwise.
14601 : :
14602 : : - Set *NUNITS_VECTYPE_OUT to the vector type that contains the maximum
14603 : : number of units needed to vectorize STMT_INFO, or NULL_TREE if the
14604 : : statement does not help to determine the overall number of units. */
14605 : :
14606 : : opt_result
14607 : 15157422 : vect_get_vector_types_for_stmt (vec_info *vinfo, stmt_vec_info stmt_info,
14608 : : tree *stmt_vectype_out,
14609 : : tree *nunits_vectype_out,
14610 : : unsigned int group_size)
14611 : : {
14612 : 15157422 : gimple *stmt = stmt_info->stmt;
14613 : :
14614 : : /* For BB vectorization, we should always have a group size once we've
14615 : : constructed the SLP tree; the only valid uses of zero GROUP_SIZEs
14616 : : are tentative requests during things like early data reference
14617 : : analysis and pattern recognition. */
14618 : 15157422 : if (is_a <bb_vec_info> (vinfo))
14619 : 24708456 : gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0);
14620 : : else
14621 : : group_size = 0;
14622 : :
14623 : 15157422 : *stmt_vectype_out = NULL_TREE;
14624 : 15157422 : *nunits_vectype_out = NULL_TREE;
14625 : :
14626 : 15157422 : if (gimple_get_lhs (stmt) == NULL_TREE
14627 : : /* Allow vector conditionals through here. */
14628 : 40864 : && !is_a <gcond *> (stmt)
14629 : : /* MASK_STORE has no lhs, but is ok. */
14630 : 15159776 : && !gimple_call_internal_p (stmt, IFN_MASK_STORE))
14631 : : {
14632 : 161 : if (is_a <gcall *> (stmt))
14633 : : {
14634 : : /* Ignore calls with no lhs. These must be calls to
14635 : : #pragma omp simd functions, and what vectorization factor
14636 : : it really needs can't be determined until
14637 : : vectorizable_simd_clone_call. */
14638 : 14 : if (dump_enabled_p ())
14639 : 12 : dump_printf_loc (MSG_NOTE, vect_location,
14640 : : "defer to SIMD clone analysis.\n");
14641 : 14 : return opt_result::success ();
14642 : : }
14643 : :
14644 : 147 : return opt_result::failure_at (stmt,
14645 : : "not vectorized: irregular stmt: %G", stmt);
14646 : : }
14647 : :
14648 : 15157261 : tree vectype;
14649 : 15157261 : tree scalar_type = NULL_TREE;
14650 : 15157261 : if (group_size == 0 && STMT_VINFO_VECTYPE (stmt_info))
14651 : : {
14652 : 906106 : vectype = STMT_VINFO_VECTYPE (stmt_info);
14653 : 906106 : if (dump_enabled_p ())
14654 : 121836 : dump_printf_loc (MSG_NOTE, vect_location,
14655 : : "precomputed vectype: %T\n", vectype);
14656 : : }
14657 : 14251155 : else if (vect_use_mask_type_p (stmt_info))
14658 : : {
14659 : 279037 : unsigned int precision = stmt_info->mask_precision;
14660 : 279037 : scalar_type = build_nonstandard_integer_type (precision, 1);
14661 : 279037 : vectype = get_mask_type_for_scalar_type (vinfo, scalar_type, group_size);
14662 : 279037 : if (!vectype)
14663 : 0 : return opt_result::failure_at (stmt, "not vectorized: unsupported"
14664 : : " data-type %T\n", scalar_type);
14665 : 279037 : if (dump_enabled_p ())
14666 : 3926 : dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype);
14667 : : }
14668 : : else
14669 : : {
14670 : : /* If we got here with a gcond it means that the target had no available vector
14671 : : mode for the scalar type. We can't vectorize so abort. */
14672 : 13972118 : if (is_a <gcond *> (stmt))
14673 : 87 : return opt_result::failure_at (stmt,
14674 : : "not vectorized:"
14675 : : " unsupported data-type for gcond %T\n",
14676 : : scalar_type);
14677 : :
14678 : 13972031 : if (data_reference *dr = STMT_VINFO_DATA_REF (stmt_info))
14679 : 3258569 : scalar_type = TREE_TYPE (DR_REF (dr));
14680 : 10713462 : else if (gimple_call_internal_p (stmt, IFN_MASK_STORE))
14681 : 0 : scalar_type = TREE_TYPE (gimple_call_arg (stmt, 3));
14682 : : else
14683 : 10713462 : scalar_type = TREE_TYPE (gimple_get_lhs (stmt));
14684 : :
14685 : 13972031 : if (dump_enabled_p ())
14686 : : {
14687 : 75021 : if (group_size)
14688 : 32640 : dump_printf_loc (MSG_NOTE, vect_location,
14689 : : "get vectype for scalar type (group size %d):"
14690 : : " %T\n", group_size, scalar_type);
14691 : : else
14692 : 42381 : dump_printf_loc (MSG_NOTE, vect_location,
14693 : : "get vectype for scalar type: %T\n", scalar_type);
14694 : : }
14695 : 13972031 : vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
14696 : 13972031 : if (!vectype)
14697 : 144798 : return opt_result::failure_at (stmt,
14698 : : "not vectorized:"
14699 : : " unsupported data-type %T\n",
14700 : : scalar_type);
14701 : :
14702 : 13827233 : if (dump_enabled_p ())
14703 : 74889 : dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype);
14704 : : }
14705 : :
14706 : 14228106 : if (scalar_type && VECTOR_MODE_P (TYPE_MODE (scalar_type)))
14707 : 0 : return opt_result::failure_at (stmt,
14708 : : "not vectorized: vector stmt in loop:%G",
14709 : : stmt);
14710 : :
14711 : 15012376 : *stmt_vectype_out = vectype;
14712 : :
14713 : : /* Don't try to compute scalar types if the stmt produces a boolean
14714 : : vector; use the existing vector type instead. */
14715 : 15012376 : tree nunits_vectype = vectype;
14716 : 15012376 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14717 : : {
14718 : : /* The number of units is set according to the smallest scalar
14719 : : type (or the largest vector size, but we only support one
14720 : : vector size per vectorization). */
14721 : 14644885 : scalar_type = vect_get_smallest_scalar_type (stmt_info,
14722 : 14644885 : TREE_TYPE (vectype));
14723 : 14644885 : if (scalar_type != TREE_TYPE (vectype))
14724 : : {
14725 : 2300355 : if (dump_enabled_p ())
14726 : 20599 : dump_printf_loc (MSG_NOTE, vect_location,
14727 : : "get vectype for smallest scalar type: %T\n",
14728 : : scalar_type);
14729 : 2300355 : nunits_vectype = get_vectype_for_scalar_type (vinfo, scalar_type,
14730 : : group_size);
14731 : 2300355 : if (!nunits_vectype)
14732 : 7 : return opt_result::failure_at
14733 : 7 : (stmt, "not vectorized: unsupported data-type %T\n",
14734 : : scalar_type);
14735 : 2300348 : if (dump_enabled_p ())
14736 : 20599 : dump_printf_loc (MSG_NOTE, vect_location, "nunits vectype: %T\n",
14737 : : nunits_vectype);
14738 : : }
14739 : : }
14740 : :
14741 : 15012369 : if (!multiple_p (TYPE_VECTOR_SUBPARTS (nunits_vectype),
14742 : 15012369 : TYPE_VECTOR_SUBPARTS (*stmt_vectype_out)))
14743 : 0 : return opt_result::failure_at (stmt,
14744 : : "Not vectorized: Incompatible number "
14745 : : "of vector subparts between %T and %T\n",
14746 : : nunits_vectype, *stmt_vectype_out);
14747 : :
14748 : 15012369 : if (dump_enabled_p ())
14749 : : {
14750 : 200651 : dump_printf_loc (MSG_NOTE, vect_location, "nunits = ");
14751 : 200651 : dump_dec (MSG_NOTE, TYPE_VECTOR_SUBPARTS (nunits_vectype));
14752 : 200651 : dump_printf (MSG_NOTE, "\n");
14753 : : }
14754 : :
14755 : 15012369 : *nunits_vectype_out = nunits_vectype;
14756 : 15012369 : return opt_result::success ();
14757 : : }
14758 : :
14759 : : /* Generate and return statement sequence that sets vector length LEN that is:
14760 : :
14761 : : min_of_start_and_end = min (START_INDEX, END_INDEX);
14762 : : left_len = END_INDEX - min_of_start_and_end;
14763 : : rhs = min (left_len, LEN_LIMIT);
14764 : : LEN = rhs;
14765 : :
14766 : : Note: the cost of the code generated by this function is modeled
14767 : : by vect_estimate_min_profitable_iters, so changes here may need
14768 : : corresponding changes there. */
14769 : :
14770 : : gimple_seq
14771 : 0 : vect_gen_len (tree len, tree start_index, tree end_index, tree len_limit)
14772 : : {
14773 : 0 : gimple_seq stmts = NULL;
14774 : 0 : tree len_type = TREE_TYPE (len);
14775 : 0 : gcc_assert (TREE_TYPE (start_index) == len_type);
14776 : :
14777 : 0 : tree min = gimple_build (&stmts, MIN_EXPR, len_type, start_index, end_index);
14778 : 0 : tree left_len = gimple_build (&stmts, MINUS_EXPR, len_type, end_index, min);
14779 : 0 : tree rhs = gimple_build (&stmts, MIN_EXPR, len_type, left_len, len_limit);
14780 : 0 : gimple* stmt = gimple_build_assign (len, rhs);
14781 : 0 : gimple_seq_add_stmt (&stmts, stmt);
14782 : :
14783 : 0 : return stmts;
14784 : : }
14785 : :
|