Branch data Line data Source code
1 : : /* Statement Analysis and Transformation for Vectorization
2 : : Copyright (C) 2003-2025 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 : : #include "tree-dfa.h"
61 : :
62 : : /* For lang_hooks.types.type_for_mode. */
63 : : #include "langhooks.h"
64 : :
65 : : /* Return the vectorized type for the given statement. */
66 : :
67 : : tree
68 : 0 : stmt_vectype (class _stmt_vec_info *stmt_info)
69 : : {
70 : 0 : return STMT_VINFO_VECTYPE (stmt_info);
71 : : }
72 : :
73 : : /* Return TRUE iff the given statement is in an inner loop relative to
74 : : the loop being vectorized. */
75 : : bool
76 : 3735696 : stmt_in_inner_loop_p (vec_info *vinfo, class _stmt_vec_info *stmt_info)
77 : : {
78 : 3735696 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
79 : 3735696 : basic_block bb = gimple_bb (stmt);
80 : 3735696 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
81 : 735231 : class loop* loop;
82 : :
83 : 735231 : if (!loop_vinfo)
84 : : return false;
85 : :
86 : 735231 : loop = LOOP_VINFO_LOOP (loop_vinfo);
87 : :
88 : 735231 : return (bb->loop_father == loop->inner);
89 : : }
90 : :
91 : : /* Record the cost of a statement, either by directly informing the
92 : : target model or by saving it in a vector for later processing.
93 : : Return a preliminary estimate of the statement's cost. */
94 : :
95 : : unsigned
96 : 9141500 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
97 : : enum vect_cost_for_stmt kind,
98 : : stmt_vec_info stmt_info, slp_tree node,
99 : : tree vectype, int misalign,
100 : : enum vect_cost_model_location where)
101 : : {
102 : 9141500 : if ((kind == vector_load || kind == unaligned_load)
103 : 1339941 : && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info)))
104 : : kind = vector_gather_load;
105 : 9141500 : if ((kind == vector_store || kind == unaligned_store)
106 : 924699 : && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info)))
107 : 9141500 : kind = vector_scatter_store;
108 : :
109 : 9141500 : stmt_info_for_cost si
110 : 9141500 : = { count, kind, where, stmt_info, node, vectype, misalign };
111 : 9141500 : body_cost_vec->safe_push (si);
112 : :
113 : 9141500 : return (unsigned)
114 : 9141500 : (builtin_vectorization_cost (kind, vectype, misalign) * count);
115 : : }
116 : :
117 : : unsigned
118 : 5937278 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
119 : : enum vect_cost_for_stmt kind, stmt_vec_info stmt_info,
120 : : tree vectype, int misalign,
121 : : enum vect_cost_model_location where)
122 : : {
123 : 5937278 : return record_stmt_cost (body_cost_vec, count, kind, stmt_info, NULL,
124 : 5937278 : vectype, misalign, where);
125 : : }
126 : :
127 : : unsigned
128 : 1208855 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
129 : : enum vect_cost_for_stmt kind, slp_tree node,
130 : : tree vectype, int misalign,
131 : : enum vect_cost_model_location where)
132 : : {
133 : 1208855 : return record_stmt_cost (body_cost_vec, count, kind, NULL, node,
134 : 1208855 : vectype, misalign, where);
135 : : }
136 : :
137 : : unsigned
138 : 142495 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
139 : : enum vect_cost_for_stmt kind,
140 : : enum vect_cost_model_location where)
141 : : {
142 : 142495 : gcc_assert (kind == cond_branch_taken || kind == cond_branch_not_taken
143 : : || kind == scalar_stmt);
144 : 142495 : return record_stmt_cost (body_cost_vec, count, kind, NULL, NULL,
145 : 142495 : NULL_TREE, 0, where);
146 : : }
147 : :
148 : : /* Return a variable of type ELEM_TYPE[NELEMS]. */
149 : :
150 : : static tree
151 : 0 : create_vector_array (tree elem_type, unsigned HOST_WIDE_INT nelems)
152 : : {
153 : 0 : return create_tmp_var (build_array_type_nelts (elem_type, nelems),
154 : 0 : "vect_array");
155 : : }
156 : :
157 : : /* ARRAY is an array of vectors created by create_vector_array.
158 : : Return an SSA_NAME for the vector in index N. The reference
159 : : is part of the vectorization of STMT_INFO and the vector is associated
160 : : with scalar destination SCALAR_DEST.
161 : : If we need to ensure that inactive elements are set to zero,
162 : : NEED_ZEROING is true, MASK contains the loop mask to be used. */
163 : :
164 : : static tree
165 : 0 : read_vector_array (vec_info *vinfo,
166 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
167 : : tree scalar_dest, tree array, unsigned HOST_WIDE_INT n,
168 : : bool need_zeroing, tree mask)
169 : : {
170 : 0 : tree vect_type, vect, vect_name, tmp, tmp_name, array_ref;
171 : 0 : gimple *new_stmt;
172 : :
173 : 0 : gcc_assert (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE);
174 : 0 : vect_type = TREE_TYPE (TREE_TYPE (array));
175 : 0 : tmp = vect_create_destination_var (scalar_dest, vect_type);
176 : 0 : vect = vect_create_destination_var (scalar_dest, vect_type);
177 : 0 : array_ref = build4 (ARRAY_REF, vect_type, array,
178 : 0 : build_int_cst (size_type_node, n),
179 : : NULL_TREE, NULL_TREE);
180 : :
181 : 0 : new_stmt = gimple_build_assign (tmp, array_ref);
182 : 0 : tmp_name = make_ssa_name (vect, new_stmt);
183 : 0 : gimple_assign_set_lhs (new_stmt, tmp_name);
184 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
185 : :
186 : 0 : if (need_zeroing)
187 : : {
188 : 0 : tree vec_els = vect_get_mask_load_else (MASK_LOAD_ELSE_ZERO,
189 : : vect_type);
190 : 0 : vect_name = make_ssa_name (vect, new_stmt);
191 : 0 : new_stmt
192 : 0 : = gimple_build_assign (vect_name, VEC_COND_EXPR,
193 : : mask, tmp_name, vec_els);
194 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
195 : : }
196 : : else
197 : : vect_name = tmp_name;
198 : :
199 : 0 : return vect_name;
200 : : }
201 : :
202 : : /* ARRAY is an array of vectors created by create_vector_array.
203 : : Emit code to store SSA_NAME VECT in index N of the array.
204 : : The store is part of the vectorization of STMT_INFO. */
205 : :
206 : : static void
207 : 0 : write_vector_array (vec_info *vinfo,
208 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
209 : : tree vect, tree array, unsigned HOST_WIDE_INT n)
210 : : {
211 : 0 : tree array_ref;
212 : 0 : gimple *new_stmt;
213 : :
214 : 0 : array_ref = build4 (ARRAY_REF, TREE_TYPE (vect), array,
215 : 0 : build_int_cst (size_type_node, n),
216 : : NULL_TREE, NULL_TREE);
217 : :
218 : 0 : new_stmt = gimple_build_assign (array_ref, vect);
219 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
220 : 0 : }
221 : :
222 : : /* PTR is a pointer to an array of type TYPE. Return a representation
223 : : of *PTR. The memory reference replaces those in FIRST_DR
224 : : (and its group). */
225 : :
226 : : static tree
227 : 0 : create_array_ref (tree type, tree ptr, tree alias_ptr_type)
228 : : {
229 : 0 : tree mem_ref;
230 : :
231 : 0 : mem_ref = build2 (MEM_REF, type, ptr, build_int_cst (alias_ptr_type, 0));
232 : : /* Arrays have the same alignment as their type. */
233 : 0 : set_ptr_info_alignment (get_ptr_info (ptr), TYPE_ALIGN_UNIT (type), 0);
234 : 0 : return mem_ref;
235 : : }
236 : :
237 : : /* Add a clobber of variable VAR to the vectorization of STMT_INFO.
238 : : Emit the clobber before *GSI. */
239 : :
240 : : static void
241 : 15 : vect_clobber_variable (vec_info *vinfo, stmt_vec_info stmt_info,
242 : : gimple_stmt_iterator *gsi, tree var)
243 : : {
244 : 15 : tree clobber = build_clobber (TREE_TYPE (var));
245 : 15 : gimple *new_stmt = gimple_build_assign (var, clobber);
246 : 15 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
247 : 15 : }
248 : :
249 : : /* Utility functions used by vect_mark_stmts_to_be_vectorized. */
250 : :
251 : : /* Function vect_mark_relevant.
252 : :
253 : : Mark STMT_INFO as "relevant for vectorization" and add it to WORKLIST. */
254 : :
255 : : static void
256 : 2816836 : vect_mark_relevant (vec<stmt_vec_info> *worklist, stmt_vec_info stmt_info,
257 : : enum vect_relevant relevant, bool live_p)
258 : : {
259 : 2816836 : enum vect_relevant save_relevant = STMT_VINFO_RELEVANT (stmt_info);
260 : 2816836 : bool save_live_p = STMT_VINFO_LIVE_P (stmt_info);
261 : :
262 : 2816836 : if (dump_enabled_p ())
263 : 170924 : dump_printf_loc (MSG_NOTE, vect_location,
264 : : "mark relevant %d, live %d: %G", relevant, live_p,
265 : : stmt_info->stmt);
266 : :
267 : : /* If this stmt is an original stmt in a pattern, we might need to mark its
268 : : related pattern stmt instead of the original stmt. However, such stmts
269 : : may have their own uses that are not in any pattern, in such cases the
270 : : stmt itself should be marked. */
271 : 2816836 : if (STMT_VINFO_IN_PATTERN_P (stmt_info))
272 : : {
273 : : /* This is the last stmt in a sequence that was detected as a
274 : : pattern that can potentially be vectorized. Don't mark the stmt
275 : : as relevant/live because it's not going to be vectorized.
276 : : Instead mark the pattern-stmt that replaces it. */
277 : :
278 : 152497 : if (dump_enabled_p ())
279 : 2388 : dump_printf_loc (MSG_NOTE, vect_location,
280 : : "last stmt in pattern. don't mark"
281 : : " relevant/live.\n");
282 : :
283 : 152497 : stmt_vec_info old_stmt_info = stmt_info;
284 : 152497 : stmt_info = STMT_VINFO_RELATED_STMT (stmt_info);
285 : 152497 : gcc_assert (STMT_VINFO_RELATED_STMT (stmt_info) == old_stmt_info);
286 : 152497 : save_relevant = STMT_VINFO_RELEVANT (stmt_info);
287 : 152497 : save_live_p = STMT_VINFO_LIVE_P (stmt_info);
288 : :
289 : 152497 : if (live_p && relevant == vect_unused_in_scope)
290 : : {
291 : 108 : if (dump_enabled_p ())
292 : 6 : dump_printf_loc (MSG_NOTE, vect_location,
293 : : "vec_stmt_relevant_p: forcing live pattern stmt "
294 : : "relevant.\n");
295 : : relevant = vect_used_only_live;
296 : : }
297 : :
298 : 152497 : if (dump_enabled_p ())
299 : 2388 : dump_printf_loc (MSG_NOTE, vect_location,
300 : : "mark relevant %d, live %d: %G", relevant, live_p,
301 : : stmt_info->stmt);
302 : : }
303 : :
304 : 2816836 : STMT_VINFO_LIVE_P (stmt_info) |= live_p;
305 : 2816836 : if (relevant > STMT_VINFO_RELEVANT (stmt_info))
306 : 2343033 : STMT_VINFO_RELEVANT (stmt_info) = relevant;
307 : :
308 : 2816836 : if (STMT_VINFO_RELEVANT (stmt_info) == save_relevant
309 : 473803 : && STMT_VINFO_LIVE_P (stmt_info) == save_live_p)
310 : : {
311 : 473199 : if (dump_enabled_p ())
312 : 22105 : dump_printf_loc (MSG_NOTE, vect_location,
313 : : "already marked relevant/live.\n");
314 : 473199 : return;
315 : : }
316 : :
317 : 2343637 : worklist->safe_push (stmt_info);
318 : : }
319 : :
320 : :
321 : : /* Function is_simple_and_all_uses_invariant
322 : :
323 : : Return true if STMT_INFO is simple and all uses of it are invariant. */
324 : :
325 : : bool
326 : 327759 : is_simple_and_all_uses_invariant (stmt_vec_info stmt_info,
327 : : loop_vec_info loop_vinfo)
328 : : {
329 : 327759 : tree op;
330 : 327759 : ssa_op_iter iter;
331 : :
332 : 445006 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
333 : 117959 : if (!stmt)
334 : : return false;
335 : :
336 : 123091 : FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
337 : : {
338 : 122379 : enum vect_def_type dt = vect_uninitialized_def;
339 : :
340 : 122379 : if (!vect_is_simple_use (op, loop_vinfo, &dt))
341 : : {
342 : 1189 : if (dump_enabled_p ())
343 : 23 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
344 : : "use not simple.\n");
345 : 117247 : return false;
346 : : }
347 : :
348 : 121190 : if (dt != vect_external_def && dt != vect_constant_def)
349 : : return false;
350 : : }
351 : : return true;
352 : : }
353 : :
354 : : /* Function vect_stmt_relevant_p.
355 : :
356 : : Return true if STMT_INFO, in the loop that is represented by LOOP_VINFO,
357 : : is "relevant for vectorization".
358 : :
359 : : A stmt is considered "relevant for vectorization" if:
360 : : - it has uses outside the loop.
361 : : - it has vdefs (it alters memory).
362 : : - control stmts in the loop (except for the exit condition).
363 : : - it is an induction and we have multiple exits.
364 : :
365 : : CHECKME: what other side effects would the vectorizer allow? */
366 : :
367 : : static bool
368 : 3847960 : vect_stmt_relevant_p (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
369 : : enum vect_relevant *relevant, bool *live_p)
370 : : {
371 : 3847960 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
372 : 3847960 : ssa_op_iter op_iter;
373 : 3847960 : imm_use_iterator imm_iter;
374 : 3847960 : use_operand_p use_p;
375 : 3847960 : def_operand_p def_p;
376 : :
377 : 3847960 : *relevant = vect_unused_in_scope;
378 : 3847960 : *live_p = false;
379 : :
380 : : /* cond stmt other than loop exit cond. */
381 : 3847960 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
382 : 3847960 : if (is_ctrl_stmt (stmt)
383 : 443727 : && LOOP_VINFO_LOOP_IV_COND (loop_vinfo) != stmt
384 : 3996101 : && (!loop->inner || gimple_bb (stmt)->loop_father == loop))
385 : 146614 : *relevant = vect_used_in_scope;
386 : :
387 : : /* changing memory. */
388 : 3847960 : if (gimple_code (stmt_info->stmt) != GIMPLE_PHI)
389 : 3079744 : if (gimple_vdef (stmt_info->stmt)
390 : 2633584 : && !gimple_clobber_p (stmt_info->stmt))
391 : : {
392 : 262121 : if (dump_enabled_p ())
393 : 28477 : dump_printf_loc (MSG_NOTE, vect_location,
394 : : "vec_stmt_relevant_p: stmt has vdefs.\n");
395 : 262121 : *relevant = vect_used_in_scope;
396 : : }
397 : :
398 : : /* uses outside the loop. */
399 : 10662929 : FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt_info->stmt, op_iter, SSA_OP_DEF)
400 : : {
401 : 7834213 : FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
402 : : {
403 : 4867204 : basic_block bb = gimple_bb (USE_STMT (use_p));
404 : 4867204 : if (!flow_bb_inside_loop_p (loop, bb))
405 : : {
406 : 163346 : if (is_gimple_debug (USE_STMT (use_p)))
407 : 991 : continue;
408 : :
409 : 162355 : if (dump_enabled_p ())
410 : 5773 : dump_printf_loc (MSG_NOTE, vect_location,
411 : : "vec_stmt_relevant_p: used out of loop.\n");
412 : :
413 : : /* We expect all such uses to be in the loop exit phis
414 : : (because of loop closed form) */
415 : 162355 : gcc_assert (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI);
416 : :
417 : 162355 : *live_p = true;
418 : : }
419 : : }
420 : : }
421 : :
422 : : /* Check if it's an induction and multiple exits. In this case there will be
423 : : a usage later on after peeling which is needed for the alternate exit. */
424 : 3847960 : if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
425 : 1228044 : && STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def)
426 : : {
427 : 198997 : if (dump_enabled_p ())
428 : 2748 : dump_printf_loc (MSG_NOTE, vect_location,
429 : : "vec_stmt_relevant_p: induction forced for "
430 : : "early break.\n");
431 : 198997 : LOOP_VINFO_EARLY_BREAKS_LIVE_IVS (loop_vinfo).safe_push (stmt_info);
432 : 198997 : *live_p = true;
433 : :
434 : : }
435 : :
436 : 327767 : if (*live_p && *relevant == vect_unused_in_scope
437 : 4175719 : && !is_simple_and_all_uses_invariant (stmt_info, loop_vinfo))
438 : : {
439 : 327047 : if (dump_enabled_p ())
440 : 8172 : dump_printf_loc (MSG_NOTE, vect_location,
441 : : "vec_stmt_relevant_p: stmt live but not relevant.\n");
442 : 327047 : *relevant = vect_used_only_live;
443 : : }
444 : :
445 : 3847960 : return (*live_p || *relevant);
446 : : }
447 : :
448 : :
449 : : /* Function exist_non_indexing_operands_for_use_p
450 : :
451 : : USE is one of the uses attached to STMT_INFO. Check if USE is
452 : : used in STMT_INFO for anything other than indexing an array. */
453 : :
454 : : static bool
455 : 3594106 : exist_non_indexing_operands_for_use_p (tree use, stmt_vec_info stmt_info)
456 : : {
457 : 3594106 : tree operand;
458 : :
459 : : /* USE corresponds to some operand in STMT. If there is no data
460 : : reference in STMT, then any operand that corresponds to USE
461 : : is not indexing an array. */
462 : 3594106 : if (!STMT_VINFO_DATA_REF (stmt_info))
463 : : return true;
464 : :
465 : : /* STMT has a data_ref. FORNOW this means that its of one of
466 : : the following forms:
467 : : -1- ARRAY_REF = var
468 : : -2- var = ARRAY_REF
469 : : (This should have been verified in analyze_data_refs).
470 : :
471 : : 'var' in the second case corresponds to a def, not a use,
472 : : so USE cannot correspond to any operands that are not used
473 : : for array indexing.
474 : :
475 : : Therefore, all we need to check is if STMT falls into the
476 : : first case, and whether var corresponds to USE. */
477 : :
478 : 1118010 : gassign *assign = dyn_cast <gassign *> (stmt_info->stmt);
479 : 1105003 : if (!assign || !gimple_assign_copy_p (assign))
480 : : {
481 : 604707 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
482 : 13007 : if (call && gimple_call_internal_p (call))
483 : : {
484 : 13007 : internal_fn ifn = gimple_call_internal_fn (call);
485 : 13007 : int mask_index = internal_fn_mask_index (ifn);
486 : 13007 : if (mask_index >= 0
487 : 13007 : && use == gimple_call_arg (call, mask_index))
488 : : return true;
489 : 8548 : int els_index = internal_fn_else_index (ifn);
490 : 8548 : if (els_index >= 0
491 : 8548 : && use == gimple_call_arg (call, els_index))
492 : : return true;
493 : 7423 : int stored_value_index = internal_fn_stored_value_index (ifn);
494 : 7423 : if (stored_value_index >= 0
495 : 7423 : && use == gimple_call_arg (call, stored_value_index))
496 : : return true;
497 : 5890 : if (internal_gather_scatter_fn_p (ifn)
498 : 5890 : && use == gimple_call_arg (call, 1))
499 : : return true;
500 : : }
501 : 597590 : return false;
502 : : }
503 : :
504 : 513303 : if (TREE_CODE (gimple_assign_lhs (assign)) == SSA_NAME)
505 : : return false;
506 : 513303 : operand = gimple_assign_rhs1 (assign);
507 : 513303 : if (TREE_CODE (operand) != SSA_NAME)
508 : : return false;
509 : :
510 : 455289 : if (operand == use)
511 : : return true;
512 : :
513 : : return false;
514 : : }
515 : :
516 : :
517 : : /*
518 : : Function process_use.
519 : :
520 : : Inputs:
521 : : - a USE in STMT_VINFO in a loop represented by LOOP_VINFO
522 : : - RELEVANT - enum value to be set in the STMT_VINFO of the stmt
523 : : that defined USE. This is done by calling mark_relevant and passing it
524 : : the WORKLIST (to add DEF_STMT to the WORKLIST in case it is relevant).
525 : : - FORCE is true if exist_non_indexing_operands_for_use_p check shouldn't
526 : : be performed.
527 : :
528 : : Outputs:
529 : : Generally, LIVE_P and RELEVANT are used to define the liveness and
530 : : relevance info of the DEF_STMT of this USE:
531 : : STMT_VINFO_LIVE_P (DEF_stmt_vinfo) <-- live_p
532 : : STMT_VINFO_RELEVANT (DEF_stmt_vinfo) <-- relevant
533 : : Exceptions:
534 : : - case 1: If USE is used only for address computations (e.g. array indexing),
535 : : which does not need to be directly vectorized, then the liveness/relevance
536 : : of the respective DEF_STMT is left unchanged.
537 : : - case 2: If STMT_VINFO is a reduction phi and DEF_STMT is a reduction stmt,
538 : : we skip DEF_STMT cause it had already been processed.
539 : : - case 3: If DEF_STMT and STMT_VINFO are in different nests, then
540 : : "relevant" will be modified accordingly.
541 : :
542 : : Return true if everything is as expected. Return false otherwise. */
543 : :
544 : : static opt_result
545 : 3623103 : process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
546 : : enum vect_relevant relevant, vec<stmt_vec_info> *worklist,
547 : : bool force)
548 : : {
549 : 3623103 : stmt_vec_info dstmt_vinfo;
550 : 3623103 : enum vect_def_type dt;
551 : :
552 : : /* case 1: we are only interested in uses that need to be vectorized. Uses
553 : : that are used for address computation are not considered relevant. */
554 : 3623103 : if (!force && !exist_non_indexing_operands_for_use_p (use, stmt_vinfo))
555 : 899363 : return opt_result::success ();
556 : :
557 : 2723740 : if (!vect_is_simple_use (use, loop_vinfo, &dt, &dstmt_vinfo))
558 : 11943 : return opt_result::failure_at (stmt_vinfo->stmt,
559 : : "not vectorized:"
560 : : " unsupported use in stmt.\n");
561 : :
562 : 2711797 : if (!dstmt_vinfo)
563 : 578043 : return opt_result::success ();
564 : :
565 : 2133754 : basic_block def_bb = gimple_bb (dstmt_vinfo->stmt);
566 : 2133754 : basic_block bb = gimple_bb (stmt_vinfo->stmt);
567 : :
568 : : /* case 2: A reduction phi (STMT) defined by a reduction stmt (DSTMT_VINFO).
569 : : We have to force the stmt live since the epilogue loop needs it to
570 : : continue computing the reduction. */
571 : 2133754 : if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI
572 : 349398 : && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
573 : 62208 : && gimple_code (dstmt_vinfo->stmt) != GIMPLE_PHI
574 : 62208 : && STMT_VINFO_DEF_TYPE (dstmt_vinfo) == vect_reduction_def
575 : 2195962 : && bb->loop_father == def_bb->loop_father)
576 : : {
577 : 62208 : if (dump_enabled_p ())
578 : 3780 : dump_printf_loc (MSG_NOTE, vect_location,
579 : : "reduc-stmt defining reduc-phi in the same nest.\n");
580 : 62208 : vect_mark_relevant (worklist, dstmt_vinfo, relevant, true);
581 : 62208 : return opt_result::success ();
582 : : }
583 : :
584 : : /* case 3a: outer-loop stmt defining an inner-loop stmt:
585 : : outer-loop-header-bb:
586 : : d = dstmt_vinfo
587 : : inner-loop:
588 : : stmt # use (d)
589 : : outer-loop-tail-bb:
590 : : ... */
591 : 2071546 : if (flow_loop_nested_p (def_bb->loop_father, bb->loop_father))
592 : : {
593 : 1737 : if (dump_enabled_p ())
594 : 256 : dump_printf_loc (MSG_NOTE, vect_location,
595 : : "outer-loop def-stmt defining inner-loop stmt.\n");
596 : :
597 : 1737 : switch (relevant)
598 : : {
599 : 0 : case vect_unused_in_scope:
600 : 0 : relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_nested_cycle) ?
601 : : vect_used_in_scope : vect_unused_in_scope;
602 : : break;
603 : :
604 : 522 : case vect_used_in_outer_by_reduction:
605 : 522 : gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def);
606 : : relevant = vect_used_by_reduction;
607 : : break;
608 : :
609 : 1008 : case vect_used_in_outer:
610 : 1008 : gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def);
611 : : relevant = vect_used_in_scope;
612 : : break;
613 : :
614 : : case vect_used_in_scope:
615 : : break;
616 : :
617 : 0 : default:
618 : 0 : gcc_unreachable ();
619 : : }
620 : : }
621 : :
622 : : /* case 3b: inner-loop stmt defining an outer-loop stmt:
623 : : outer-loop-header-bb:
624 : : ...
625 : : inner-loop:
626 : : d = dstmt_vinfo
627 : : outer-loop-tail-bb (or outer-loop-exit-bb in double reduction):
628 : : stmt # use (d) */
629 : 2069809 : else if (flow_loop_nested_p (bb->loop_father, def_bb->loop_father))
630 : : {
631 : 1552 : if (dump_enabled_p ())
632 : 506 : dump_printf_loc (MSG_NOTE, vect_location,
633 : : "inner-loop def-stmt defining outer-loop stmt.\n");
634 : :
635 : 1552 : switch (relevant)
636 : : {
637 : 0 : case vect_unused_in_scope:
638 : 0 : relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
639 : 0 : || STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_double_reduction_def) ?
640 : : vect_used_in_outer_by_reduction : vect_unused_in_scope;
641 : : break;
642 : :
643 : : case vect_used_by_reduction:
644 : : case vect_used_only_live:
645 : : relevant = vect_used_in_outer_by_reduction;
646 : : break;
647 : :
648 : : case vect_used_in_scope:
649 : 2018134 : relevant = vect_used_in_outer;
650 : : break;
651 : :
652 : 0 : default:
653 : 0 : gcc_unreachable ();
654 : : }
655 : : }
656 : : /* We are also not interested in uses on loop PHI backedges that are
657 : : inductions. Otherwise we'll needlessly vectorize the IV increment
658 : : and cause hybrid SLP for SLP inductions. Unless the PHI is live
659 : : of course. */
660 : 2068257 : else if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI
661 : 284670 : && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_induction_def
662 : 281388 : && ! STMT_VINFO_LIVE_P (stmt_vinfo)
663 : 2121669 : && (PHI_ARG_DEF_FROM_EDGE (stmt_vinfo->stmt,
664 : : loop_latch_edge (bb->loop_father))
665 : : == use))
666 : : {
667 : 53412 : if (dump_enabled_p ())
668 : 3759 : dump_printf_loc (MSG_NOTE, vect_location,
669 : : "induction value on backedge.\n");
670 : 53412 : return opt_result::success ();
671 : : }
672 : :
673 : :
674 : 2018134 : vect_mark_relevant (worklist, dstmt_vinfo, relevant, false);
675 : 2018134 : return opt_result::success ();
676 : : }
677 : :
678 : :
679 : : /* Function vect_mark_stmts_to_be_vectorized.
680 : :
681 : : Not all stmts in the loop need to be vectorized. For example:
682 : :
683 : : for i...
684 : : for j...
685 : : 1. T0 = i + j
686 : : 2. T1 = a[T0]
687 : :
688 : : 3. j = j + 1
689 : :
690 : : Stmt 1 and 3 do not need to be vectorized, because loop control and
691 : : addressing of vectorized data-refs are handled differently.
692 : :
693 : : This pass detects such stmts. */
694 : :
695 : : opt_result
696 : 295586 : vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo, bool *fatal)
697 : : {
698 : 295586 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
699 : 295586 : basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
700 : 295586 : unsigned int nbbs = loop->num_nodes;
701 : 295586 : gimple_stmt_iterator si;
702 : 295586 : unsigned int i;
703 : 295586 : basic_block bb;
704 : 295586 : bool live_p;
705 : 295586 : enum vect_relevant relevant;
706 : :
707 : 295586 : DUMP_VECT_SCOPE ("vect_mark_stmts_to_be_vectorized");
708 : :
709 : 295586 : auto_vec<stmt_vec_info, 64> worklist;
710 : :
711 : : /* 1. Init worklist. */
712 : 1037969 : for (i = 0; i < nbbs; i++)
713 : : {
714 : 742383 : bb = bbs[i];
715 : 1510599 : for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
716 : : {
717 : 768216 : stmt_vec_info phi_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
718 : 768216 : if (dump_enabled_p ())
719 : 55303 : dump_printf_loc (MSG_NOTE, vect_location, "init: phi relevant? %G",
720 : : phi_info->stmt);
721 : :
722 : 768216 : if (vect_stmt_relevant_p (phi_info, loop_vinfo, &relevant, &live_p))
723 : 204012 : vect_mark_relevant (&worklist, phi_info, relevant, live_p);
724 : : }
725 : 5989113 : for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
726 : : {
727 : 4504347 : if (is_gimple_debug (gsi_stmt (si)))
728 : 1424603 : continue;
729 : 3079744 : stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
730 : 3079744 : if (dump_enabled_p ())
731 : 222784 : dump_printf_loc (MSG_NOTE, vect_location,
732 : : "init: stmt relevant? %G", stmt_info->stmt);
733 : :
734 : 3079744 : if (vect_stmt_relevant_p (stmt_info, loop_vinfo, &relevant, &live_p))
735 : 532482 : vect_mark_relevant (&worklist, stmt_info, relevant, live_p);
736 : : }
737 : : }
738 : :
739 : : /* 2. Process_worklist */
740 : 2593548 : while (worklist.length () > 0)
741 : : {
742 : 2309905 : use_operand_p use_p;
743 : 2309905 : ssa_op_iter iter;
744 : :
745 : 2309905 : stmt_vec_info stmt_vinfo = worklist.pop ();
746 : 2309905 : if (dump_enabled_p ())
747 : 148163 : dump_printf_loc (MSG_NOTE, vect_location,
748 : : "worklist: examine stmt: %G", stmt_vinfo->stmt);
749 : :
750 : : /* Examine the USEs of STMT. For each USE, mark the stmt that defines it
751 : : (DEF_STMT) as relevant/irrelevant according to the relevance property
752 : : of STMT. */
753 : 2309905 : relevant = STMT_VINFO_RELEVANT (stmt_vinfo);
754 : :
755 : : /* Generally, the relevance property of STMT (in STMT_VINFO_RELEVANT) is
756 : : propagated as is to the DEF_STMTs of its USEs.
757 : :
758 : : One exception is when STMT has been identified as defining a reduction
759 : : variable; in this case we set the relevance to vect_used_by_reduction.
760 : : This is because we distinguish between two kinds of relevant stmts -
761 : : those that are used by a reduction computation, and those that are
762 : : (also) used by a regular computation. This allows us later on to
763 : : identify stmts that are used solely by a reduction, and therefore the
764 : : order of the results that they produce does not have to be kept. */
765 : :
766 : 2309905 : switch (STMT_VINFO_DEF_TYPE (stmt_vinfo))
767 : : {
768 : 124989 : case vect_reduction_def:
769 : 124989 : gcc_assert (relevant != vect_unused_in_scope);
770 : 124989 : if (relevant != vect_unused_in_scope
771 : 124989 : && relevant != vect_used_in_scope
772 : 124989 : && relevant != vect_used_by_reduction
773 : 124989 : && relevant != vect_used_only_live)
774 : 0 : return opt_result::failure_at
775 : 0 : (stmt_vinfo->stmt, "unsupported use of reduction.\n");
776 : : break;
777 : :
778 : 1801 : case vect_nested_cycle:
779 : 1801 : if (relevant != vect_unused_in_scope
780 : 1801 : && relevant != vect_used_in_outer_by_reduction
781 : 1441 : && relevant != vect_used_in_outer)
782 : 0 : return opt_result::failure_at
783 : 0 : (stmt_vinfo->stmt, "unsupported use of nested cycle.\n");
784 : : break;
785 : :
786 : 712 : case vect_double_reduction_def:
787 : 712 : if (relevant != vect_unused_in_scope
788 : 712 : && relevant != vect_used_by_reduction
789 : 256 : && relevant != vect_used_only_live)
790 : 0 : return opt_result::failure_at
791 : 0 : (stmt_vinfo->stmt, "unsupported use of double reduction.\n");
792 : : break;
793 : :
794 : : default:
795 : : break;
796 : : }
797 : :
798 : 2309905 : if (is_pattern_stmt_p (stmt_vinfo))
799 : : {
800 : : /* Pattern statements are not inserted into the code, so
801 : : FOR_EACH_PHI_OR_STMT_USE optimizes their operands out, and we
802 : : have to scan the RHS or function arguments instead. */
803 : 401724 : if (gassign *assign = dyn_cast <gassign *> (stmt_vinfo->stmt))
804 : : {
805 : 256427 : enum tree_code rhs_code = gimple_assign_rhs_code (assign);
806 : 256427 : tree op = gimple_assign_rhs1 (assign);
807 : :
808 : 256427 : i = 1;
809 : 256427 : if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op))
810 : : {
811 : 0 : opt_result res
812 : 0 : = process_use (stmt_vinfo, TREE_OPERAND (op, 0),
813 : : loop_vinfo, relevant, &worklist, false);
814 : 0 : if (!res)
815 : 0 : return res;
816 : 0 : res = process_use (stmt_vinfo, TREE_OPERAND (op, 1),
817 : : loop_vinfo, relevant, &worklist, false);
818 : 0 : if (!res)
819 : 0 : return res;
820 : : i = 2;
821 : : }
822 : 747761 : for (; i < gimple_num_ops (assign); i++)
823 : : {
824 : 492697 : op = gimple_op (assign, i);
825 : 492697 : if (TREE_CODE (op) == SSA_NAME)
826 : : {
827 : 370521 : opt_result res
828 : 370521 : = process_use (stmt_vinfo, op, loop_vinfo, relevant,
829 : : &worklist, false);
830 : 370521 : if (!res)
831 : 1363 : return res;
832 : : }
833 : : }
834 : : }
835 : 145297 : else if (gcond *cond = dyn_cast <gcond *> (stmt_vinfo->stmt))
836 : : {
837 : 141282 : tree_code rhs_code = gimple_cond_code (cond);
838 : 141282 : gcc_assert (TREE_CODE_CLASS (rhs_code) == tcc_comparison);
839 : 141282 : opt_result res
840 : 141282 : = process_use (stmt_vinfo, gimple_cond_lhs (cond),
841 : : loop_vinfo, relevant, &worklist, false);
842 : 141282 : if (!res)
843 : 11943 : return res;
844 : 141282 : res = process_use (stmt_vinfo, gimple_cond_rhs (cond),
845 : : loop_vinfo, relevant, &worklist, false);
846 : 141282 : if (!res)
847 : 0 : return res;
848 : : }
849 : 4015 : else if (gcall *call = dyn_cast <gcall *> (stmt_vinfo->stmt))
850 : : {
851 : 19306 : for (i = 0; i < gimple_call_num_args (call); i++)
852 : : {
853 : 15291 : tree arg = gimple_call_arg (call, i);
854 : 15291 : opt_result res
855 : 15291 : = process_use (stmt_vinfo, arg, loop_vinfo, relevant,
856 : : &worklist, false);
857 : 15291 : if (!res)
858 : 0 : return res;
859 : : }
860 : : }
861 : : else
862 : 0 : gcc_unreachable ();
863 : : }
864 : : else
865 : 6732917 : FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE)
866 : : {
867 : 2925730 : tree op = USE_FROM_PTR (use_p);
868 : 2925730 : opt_result res
869 : 2925730 : = process_use (stmt_vinfo, op, loop_vinfo, relevant,
870 : : &worklist, false);
871 : 2925730 : if (!res)
872 : 9175 : return res;
873 : : }
874 : :
875 : 2299367 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo))
876 : : {
877 : 28997 : gather_scatter_info gs_info;
878 : 28997 : if (!vect_check_gather_scatter (stmt_vinfo, loop_vinfo, &gs_info))
879 : 0 : gcc_unreachable ();
880 : 28997 : opt_result res
881 : 28997 : = process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
882 : : &worklist, true);
883 : 28997 : if (!res)
884 : : {
885 : 1405 : if (fatal)
886 : 1405 : *fatal = false;
887 : 1405 : return res;
888 : : }
889 : : }
890 : : } /* while worklist */
891 : :
892 : 283643 : return opt_result::success ();
893 : 295586 : }
894 : :
895 : : /* Function vect_model_simple_cost.
896 : :
897 : : Models cost for simple operations, i.e. those that only emit ncopies of a
898 : : single op. Right now, this does not account for multiple insns that could
899 : : be generated for the single vector op. We will handle that shortly. */
900 : :
901 : : static void
902 : 592882 : vect_model_simple_cost (vec_info *,
903 : : stmt_vec_info stmt_info, int ncopies,
904 : : enum vect_def_type *dt,
905 : : int ndts,
906 : : slp_tree node,
907 : : stmt_vector_for_cost *cost_vec,
908 : : vect_cost_for_stmt kind = vector_stmt)
909 : : {
910 : 592882 : int inside_cost = 0, prologue_cost = 0;
911 : :
912 : 592882 : gcc_assert (cost_vec != NULL);
913 : :
914 : : /* ??? Somehow we need to fix this at the callers. */
915 : 592882 : if (node)
916 : 592882 : ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (node);
917 : :
918 : 592882 : if (!node)
919 : : /* Cost the "broadcast" of a scalar operand in to a vector operand.
920 : : Use scalar_to_vec to cost the broadcast, as elsewhere in the vector
921 : : cost model. */
922 : 0 : for (int i = 0; i < ndts; i++)
923 : 0 : if (dt[i] == vect_constant_def || dt[i] == vect_external_def)
924 : 0 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
925 : : stmt_info, 0, vect_prologue);
926 : :
927 : : /* Pass the inside-of-loop statements to the target-specific cost model. */
928 : 592882 : inside_cost += record_stmt_cost (cost_vec, ncopies, kind,
929 : : stmt_info, 0, vect_body);
930 : :
931 : 592882 : if (dump_enabled_p ())
932 : 35719 : dump_printf_loc (MSG_NOTE, vect_location,
933 : : "vect_model_simple_cost: inside_cost = %d, "
934 : : "prologue_cost = %d .\n", inside_cost, prologue_cost);
935 : 592882 : }
936 : :
937 : :
938 : : /* Model cost for type demotion and promotion operations. PWR is
939 : : normally zero for single-step promotions and demotions. It will be
940 : : one if two-step promotion/demotion is required, and so on. NCOPIES
941 : : is the number of vector results (and thus number of instructions)
942 : : for the narrowest end of the operation chain. Each additional
943 : : step doubles the number of instructions required. If WIDEN_ARITH
944 : : is true the stmt is doing widening arithmetic. */
945 : :
946 : : static void
947 : 46908 : vect_model_promotion_demotion_cost (stmt_vec_info stmt_info,
948 : : enum vect_def_type *dt,
949 : : unsigned int ncopies, int pwr,
950 : : stmt_vector_for_cost *cost_vec,
951 : : bool widen_arith)
952 : : {
953 : 46908 : int i;
954 : 46908 : int inside_cost = 0, prologue_cost = 0;
955 : :
956 : 110365 : for (i = 0; i < pwr + 1; i++)
957 : : {
958 : 125228 : inside_cost += record_stmt_cost (cost_vec, ncopies,
959 : : widen_arith
960 : : ? vector_stmt : vec_promote_demote,
961 : : stmt_info, 0, vect_body);
962 : 63457 : ncopies *= 2;
963 : : }
964 : :
965 : : /* FORNOW: Assuming maximum 2 args per stmts. */
966 : 140724 : for (i = 0; i < 2; i++)
967 : 93816 : if (dt[i] == vect_constant_def || dt[i] == vect_external_def)
968 : 2281 : prologue_cost += record_stmt_cost (cost_vec, 1, vector_stmt,
969 : : stmt_info, 0, vect_prologue);
970 : :
971 : 46908 : if (dump_enabled_p ())
972 : 7430 : dump_printf_loc (MSG_NOTE, vect_location,
973 : : "vect_model_promotion_demotion_cost: inside_cost = %d, "
974 : : "prologue_cost = %d .\n", inside_cost, prologue_cost);
975 : 46908 : }
976 : :
977 : : /* Returns true if the current function returns DECL. */
978 : :
979 : : static bool
980 : 543586 : cfun_returns (tree decl)
981 : : {
982 : 543586 : edge_iterator ei;
983 : 543586 : edge e;
984 : 1058750 : FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
985 : : {
986 : 1075816 : greturn *ret = safe_dyn_cast <greturn *> (*gsi_last_bb (e->src));
987 : 537908 : if (!ret)
988 : 0 : continue;
989 : 537908 : if (gimple_return_retval (ret) == decl)
990 : : return true;
991 : : /* We often end up with an aggregate copy to the result decl,
992 : : handle that case as well. First skip intermediate clobbers
993 : : though. */
994 : : gimple *def = ret;
995 : 1457665 : do
996 : : {
997 : 2915330 : def = SSA_NAME_DEF_STMT (gimple_vuse (def));
998 : : }
999 : 1457665 : while (gimple_clobber_p (def));
1000 : 515570 : if (is_a <gassign *> (def)
1001 : 65832 : && gimple_assign_lhs (def) == gimple_return_retval (ret)
1002 : 518294 : && gimple_assign_rhs1 (def) == decl)
1003 : : return true;
1004 : : }
1005 : : return false;
1006 : : }
1007 : :
1008 : : /* Calculate cost of DR's memory access. */
1009 : : void
1010 : 903683 : vect_get_store_cost (vec_info *, stmt_vec_info stmt_info, slp_tree slp_node,
1011 : : int ncopies, dr_alignment_support alignment_support_scheme,
1012 : : int misalignment,
1013 : : unsigned int *inside_cost,
1014 : : stmt_vector_for_cost *body_cost_vec)
1015 : : {
1016 : 903683 : switch (alignment_support_scheme)
1017 : : {
1018 : 505748 : case dr_aligned:
1019 : 505748 : {
1020 : 505748 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1021 : : vector_store, stmt_info, slp_node, 0,
1022 : : vect_body);
1023 : :
1024 : 505748 : if (dump_enabled_p ())
1025 : 13944 : dump_printf_loc (MSG_NOTE, vect_location,
1026 : : "vect_model_store_cost: aligned.\n");
1027 : : break;
1028 : : }
1029 : :
1030 : 397935 : case dr_unaligned_supported:
1031 : 397935 : {
1032 : : /* Here, we assign an additional cost for the unaligned store. */
1033 : 397935 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1034 : : unaligned_store, stmt_info, slp_node,
1035 : : misalignment, vect_body);
1036 : 397935 : if (dump_enabled_p ())
1037 : 13179 : dump_printf_loc (MSG_NOTE, vect_location,
1038 : : "vect_model_store_cost: unaligned supported by "
1039 : : "hardware.\n");
1040 : : break;
1041 : : }
1042 : :
1043 : 0 : case dr_unaligned_unsupported:
1044 : 0 : {
1045 : 0 : *inside_cost = VECT_MAX_COST;
1046 : :
1047 : 0 : if (dump_enabled_p ())
1048 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1049 : : "vect_model_store_cost: unsupported access.\n");
1050 : : break;
1051 : : }
1052 : :
1053 : 0 : default:
1054 : 0 : gcc_unreachable ();
1055 : : }
1056 : 903683 : }
1057 : :
1058 : : /* Calculate cost of DR's memory access. */
1059 : : void
1060 : 743975 : vect_get_load_cost (vec_info *, stmt_vec_info stmt_info, slp_tree slp_node,
1061 : : int ncopies, dr_alignment_support alignment_support_scheme,
1062 : : int misalignment,
1063 : : bool add_realign_cost, unsigned int *inside_cost,
1064 : : unsigned int *prologue_cost,
1065 : : stmt_vector_for_cost *prologue_cost_vec,
1066 : : stmt_vector_for_cost *body_cost_vec,
1067 : : bool record_prologue_costs)
1068 : : {
1069 : 743975 : switch (alignment_support_scheme)
1070 : : {
1071 : 450674 : case dr_aligned:
1072 : 450674 : {
1073 : 450674 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load,
1074 : : stmt_info, slp_node, 0, vect_body);
1075 : :
1076 : 450674 : if (dump_enabled_p ())
1077 : 17944 : dump_printf_loc (MSG_NOTE, vect_location,
1078 : : "vect_model_load_cost: aligned.\n");
1079 : :
1080 : : break;
1081 : : }
1082 : 257151 : case dr_unaligned_supported:
1083 : 257151 : {
1084 : : /* Here, we assign an additional cost for the unaligned load. */
1085 : 257151 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1086 : : unaligned_load, stmt_info, slp_node,
1087 : : misalignment, vect_body);
1088 : :
1089 : 257151 : if (dump_enabled_p ())
1090 : 22618 : dump_printf_loc (MSG_NOTE, vect_location,
1091 : : "vect_model_load_cost: unaligned supported by "
1092 : : "hardware.\n");
1093 : :
1094 : : break;
1095 : : }
1096 : 0 : case dr_explicit_realign:
1097 : 0 : {
1098 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies * 2,
1099 : : vector_load, stmt_info, slp_node, 0,
1100 : : vect_body);
1101 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1102 : : vec_perm, stmt_info, slp_node, 0,
1103 : : vect_body);
1104 : :
1105 : : /* FIXME: If the misalignment remains fixed across the iterations of
1106 : : the containing loop, the following cost should be added to the
1107 : : prologue costs. */
1108 : 0 : if (targetm.vectorize.builtin_mask_for_load)
1109 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, 1, vector_stmt,
1110 : : stmt_info, slp_node, 0, vect_body);
1111 : :
1112 : 0 : if (dump_enabled_p ())
1113 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1114 : : "vect_model_load_cost: explicit realign\n");
1115 : :
1116 : : break;
1117 : : }
1118 : 0 : case dr_explicit_realign_optimized:
1119 : 0 : {
1120 : 0 : if (dump_enabled_p ())
1121 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1122 : : "vect_model_load_cost: unaligned software "
1123 : : "pipelined.\n");
1124 : :
1125 : : /* Unaligned software pipeline has a load of an address, an initial
1126 : : load, and possibly a mask operation to "prime" the loop. However,
1127 : : if this is an access in a group of loads, which provide grouped
1128 : : access, then the above cost should only be considered for one
1129 : : access in the group. Inside the loop, there is a load op
1130 : : and a realignment op. */
1131 : :
1132 : 0 : if (add_realign_cost && record_prologue_costs)
1133 : : {
1134 : 0 : *prologue_cost += record_stmt_cost (prologue_cost_vec, 2,
1135 : : vector_stmt, stmt_info,
1136 : : slp_node, 0, vect_prologue);
1137 : 0 : if (targetm.vectorize.builtin_mask_for_load)
1138 : 0 : *prologue_cost += record_stmt_cost (prologue_cost_vec, 1,
1139 : : vector_stmt, stmt_info,
1140 : : slp_node, 0, vect_prologue);
1141 : : }
1142 : :
1143 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load,
1144 : : stmt_info, slp_node, 0, vect_body);
1145 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vec_perm,
1146 : : stmt_info, slp_node, 0, vect_body);
1147 : :
1148 : 0 : if (dump_enabled_p ())
1149 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1150 : : "vect_model_load_cost: explicit realign optimized"
1151 : : "\n");
1152 : :
1153 : : break;
1154 : : }
1155 : :
1156 : 36150 : case dr_unaligned_unsupported:
1157 : 36150 : {
1158 : 36150 : *inside_cost = VECT_MAX_COST;
1159 : :
1160 : 36150 : if (dump_enabled_p ())
1161 : 91 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1162 : : "vect_model_load_cost: unsupported access.\n");
1163 : : break;
1164 : : }
1165 : :
1166 : 0 : default:
1167 : 0 : gcc_unreachable ();
1168 : : }
1169 : 743975 : }
1170 : :
1171 : : /* Insert the new stmt NEW_STMT at *GSI or at the appropriate place in
1172 : : the loop preheader for the vectorized stmt STMT_VINFO. */
1173 : :
1174 : : static void
1175 : 5539 : vect_init_vector_1 (vec_info *vinfo, stmt_vec_info stmt_vinfo, gimple *new_stmt,
1176 : : gimple_stmt_iterator *gsi)
1177 : : {
1178 : 5539 : if (gsi)
1179 : 2288 : vect_finish_stmt_generation (vinfo, stmt_vinfo, new_stmt, gsi);
1180 : : else
1181 : 3251 : vinfo->insert_on_entry (stmt_vinfo, new_stmt);
1182 : :
1183 : 5539 : if (dump_enabled_p ())
1184 : 1675 : dump_printf_loc (MSG_NOTE, vect_location,
1185 : : "created new init_stmt: %G", new_stmt);
1186 : 5539 : }
1187 : :
1188 : : /* Function vect_init_vector.
1189 : :
1190 : : Insert a new stmt (INIT_STMT) that initializes a new variable of type
1191 : : TYPE with the value VAL. If TYPE is a vector type and VAL does not have
1192 : : vector type a vector with all elements equal to VAL is created first.
1193 : : Place the initialization at GSI if it is not NULL. Otherwise, place the
1194 : : initialization at the loop preheader.
1195 : : Return the DEF of INIT_STMT.
1196 : : It will be used in the vectorization of STMT_INFO. */
1197 : :
1198 : : tree
1199 : 3826 : vect_init_vector (vec_info *vinfo, stmt_vec_info stmt_info, tree val, tree type,
1200 : : gimple_stmt_iterator *gsi)
1201 : : {
1202 : 3826 : gimple *init_stmt;
1203 : 3826 : tree new_temp;
1204 : :
1205 : : /* We abuse this function to push sth to a SSA name with initial 'val'. */
1206 : 3826 : if (! useless_type_conversion_p (type, TREE_TYPE (val)))
1207 : : {
1208 : 1322 : gcc_assert (VECTOR_TYPE_P (type));
1209 : 1322 : if (! types_compatible_p (TREE_TYPE (type), TREE_TYPE (val)))
1210 : : {
1211 : : /* Scalar boolean value should be transformed into
1212 : : all zeros or all ones value before building a vector. */
1213 : 14 : if (VECTOR_BOOLEAN_TYPE_P (type))
1214 : : {
1215 : 0 : tree true_val = build_all_ones_cst (TREE_TYPE (type));
1216 : 0 : tree false_val = build_zero_cst (TREE_TYPE (type));
1217 : :
1218 : 0 : if (CONSTANT_CLASS_P (val))
1219 : 0 : val = integer_zerop (val) ? false_val : true_val;
1220 : : else
1221 : : {
1222 : 0 : new_temp = make_ssa_name (TREE_TYPE (type));
1223 : 0 : init_stmt = gimple_build_assign (new_temp, COND_EXPR,
1224 : : val, true_val, false_val);
1225 : 0 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1226 : 0 : val = new_temp;
1227 : : }
1228 : : }
1229 : : else
1230 : : {
1231 : 14 : gimple_seq stmts = NULL;
1232 : 14 : if (! INTEGRAL_TYPE_P (TREE_TYPE (val)))
1233 : 12 : val = gimple_build (&stmts, VIEW_CONVERT_EXPR,
1234 : 12 : TREE_TYPE (type), val);
1235 : : else
1236 : : /* ??? Condition vectorization expects us to do
1237 : : promotion of invariant/external defs. */
1238 : 2 : val = gimple_convert (&stmts, TREE_TYPE (type), val);
1239 : 28 : for (gimple_stmt_iterator gsi2 = gsi_start (stmts);
1240 : 28 : !gsi_end_p (gsi2); )
1241 : : {
1242 : 14 : init_stmt = gsi_stmt (gsi2);
1243 : 14 : gsi_remove (&gsi2, false);
1244 : 14 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1245 : : }
1246 : : }
1247 : : }
1248 : 1322 : val = build_vector_from_val (type, val);
1249 : : }
1250 : :
1251 : 3826 : new_temp = vect_get_new_ssa_name (type, vect_simple_var, "cst_");
1252 : 3826 : init_stmt = gimple_build_assign (new_temp, val);
1253 : 3826 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1254 : 3826 : return new_temp;
1255 : : }
1256 : :
1257 : :
1258 : : /* Function vect_get_vec_defs_for_operand.
1259 : :
1260 : : OP is an operand in STMT_VINFO. This function returns a vector of
1261 : : NCOPIES defs that will be used in the vectorized stmts for STMT_VINFO.
1262 : :
1263 : : In the case that OP is an SSA_NAME which is defined in the loop, then
1264 : : STMT_VINFO_VEC_STMTS of the defining stmt holds the relevant defs.
1265 : :
1266 : : In case OP is an invariant or constant, a new stmt that creates a vector def
1267 : : needs to be introduced. VECTYPE may be used to specify a required type for
1268 : : vector invariant. */
1269 : :
1270 : : void
1271 : 0 : vect_get_vec_defs_for_operand (vec_info *vinfo, stmt_vec_info stmt_vinfo,
1272 : : unsigned ncopies,
1273 : : tree op, vec<tree> *vec_oprnds, tree vectype)
1274 : : {
1275 : 0 : gimple *def_stmt;
1276 : 0 : enum vect_def_type dt;
1277 : 0 : bool is_simple_use;
1278 : 0 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
1279 : :
1280 : 0 : if (dump_enabled_p ())
1281 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1282 : : "vect_get_vec_defs_for_operand: %T\n", op);
1283 : :
1284 : 0 : stmt_vec_info def_stmt_info;
1285 : 0 : is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt,
1286 : : &def_stmt_info, &def_stmt);
1287 : 0 : gcc_assert (is_simple_use);
1288 : 0 : if (def_stmt && dump_enabled_p ())
1289 : 0 : dump_printf_loc (MSG_NOTE, vect_location, " def_stmt = %G", def_stmt);
1290 : :
1291 : 0 : vec_oprnds->create (ncopies);
1292 : 0 : if (dt == vect_constant_def || dt == vect_external_def)
1293 : : {
1294 : 0 : tree stmt_vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
1295 : 0 : tree vector_type;
1296 : :
1297 : 0 : if (vectype)
1298 : : vector_type = vectype;
1299 : 0 : else if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op))
1300 : 0 : && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
1301 : 0 : vector_type = truth_type_for (stmt_vectype);
1302 : : else
1303 : 0 : vector_type = get_vectype_for_scalar_type (loop_vinfo, TREE_TYPE (op));
1304 : :
1305 : 0 : gcc_assert (vector_type);
1306 : : /* A masked load can have a default SSA definition as else operand.
1307 : : We should "vectorize" this instead of creating a duplicate from the
1308 : : scalar default. */
1309 : 0 : tree vop;
1310 : 0 : if (TREE_CODE (op) == SSA_NAME
1311 : 0 : && SSA_NAME_IS_DEFAULT_DEF (op)
1312 : 0 : && VAR_P (SSA_NAME_VAR (op)))
1313 : 0 : vop = get_or_create_ssa_default_def (cfun,
1314 : : create_tmp_var (vector_type));
1315 : : else
1316 : 0 : vop = vect_init_vector (vinfo, stmt_vinfo, op, vector_type, NULL);
1317 : 0 : while (ncopies--)
1318 : 0 : vec_oprnds->quick_push (vop);
1319 : : }
1320 : : else
1321 : : {
1322 : 0 : def_stmt_info = vect_stmt_to_vectorize (def_stmt_info);
1323 : 0 : gcc_assert (STMT_VINFO_VEC_STMTS (def_stmt_info).length () == ncopies);
1324 : 0 : for (unsigned i = 0; i < ncopies; ++i)
1325 : 0 : vec_oprnds->quick_push (gimple_get_lhs
1326 : 0 : (STMT_VINFO_VEC_STMTS (def_stmt_info)[i]));
1327 : : }
1328 : 0 : }
1329 : :
1330 : :
1331 : : /* Get vectorized definitions for OP0 and OP1. */
1332 : :
1333 : : void
1334 : 698911 : vect_get_vec_defs (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node,
1335 : : unsigned ncopies,
1336 : : tree op0, tree vectype0, vec<tree> *vec_oprnds0,
1337 : : tree op1, tree vectype1, vec<tree> *vec_oprnds1,
1338 : : tree op2, tree vectype2, vec<tree> *vec_oprnds2,
1339 : : tree op3, tree vectype3, vec<tree> *vec_oprnds3)
1340 : : {
1341 : 698911 : if (slp_node)
1342 : : {
1343 : 698911 : if (op0)
1344 : 697587 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_oprnds0);
1345 : 698911 : if (op1)
1346 : 124243 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[1], vec_oprnds1);
1347 : 698911 : if (op2)
1348 : 6720 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[2], vec_oprnds2);
1349 : 698911 : if (op3)
1350 : 0 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[3], vec_oprnds3);
1351 : : }
1352 : : else
1353 : : {
1354 : 0 : if (op0)
1355 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
1356 : : op0, vec_oprnds0, vectype0);
1357 : 0 : if (op1)
1358 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
1359 : : op1, vec_oprnds1, vectype1);
1360 : 0 : if (op2)
1361 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
1362 : : op2, vec_oprnds2, vectype2);
1363 : 0 : if (op3)
1364 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
1365 : : op3, vec_oprnds3, vectype3);
1366 : : }
1367 : 698911 : }
1368 : :
1369 : : void
1370 : 664088 : vect_get_vec_defs (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node,
1371 : : unsigned ncopies,
1372 : : tree op0, vec<tree> *vec_oprnds0,
1373 : : tree op1, vec<tree> *vec_oprnds1,
1374 : : tree op2, vec<tree> *vec_oprnds2,
1375 : : tree op3, vec<tree> *vec_oprnds3)
1376 : : {
1377 : 664088 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
1378 : : op0, NULL_TREE, vec_oprnds0,
1379 : : op1, NULL_TREE, vec_oprnds1,
1380 : : op2, NULL_TREE, vec_oprnds2,
1381 : : op3, NULL_TREE, vec_oprnds3);
1382 : 664088 : }
1383 : :
1384 : : /* Helper function called by vect_finish_replace_stmt and
1385 : : vect_finish_stmt_generation. Set the location of the new
1386 : : statement and create and return a stmt_vec_info for it. */
1387 : :
1388 : : static void
1389 : 1290749 : vect_finish_stmt_generation_1 (vec_info *,
1390 : : stmt_vec_info stmt_info, gimple *vec_stmt)
1391 : : {
1392 : 1290749 : if (dump_enabled_p ())
1393 : 127395 : dump_printf_loc (MSG_NOTE, vect_location, "add new stmt: %G", vec_stmt);
1394 : :
1395 : 1290749 : if (stmt_info)
1396 : : {
1397 : 1261650 : gimple_set_location (vec_stmt, gimple_location (stmt_info->stmt));
1398 : :
1399 : : /* While EH edges will generally prevent vectorization, stmt might
1400 : : e.g. be in a must-not-throw region. Ensure newly created stmts
1401 : : that could throw are part of the same region. */
1402 : 1261650 : int lp_nr = lookup_stmt_eh_lp (stmt_info->stmt);
1403 : 1261650 : if (lp_nr != 0 && stmt_could_throw_p (cfun, vec_stmt))
1404 : 66 : add_stmt_to_eh_lp (vec_stmt, lp_nr);
1405 : : }
1406 : : else
1407 : 29099 : gcc_assert (!stmt_could_throw_p (cfun, vec_stmt));
1408 : 1290749 : }
1409 : :
1410 : : /* Replace the scalar statement STMT_INFO with a new vector statement VEC_STMT,
1411 : : which sets the same scalar result as STMT_INFO did. Create and return a
1412 : : stmt_vec_info for VEC_STMT. */
1413 : :
1414 : : void
1415 : 797 : vect_finish_replace_stmt (vec_info *vinfo,
1416 : : stmt_vec_info stmt_info, gimple *vec_stmt)
1417 : : {
1418 : 797 : gimple *scalar_stmt = vect_orig_stmt (stmt_info)->stmt;
1419 : 797 : gcc_assert (gimple_get_lhs (scalar_stmt) == gimple_get_lhs (vec_stmt));
1420 : :
1421 : 797 : gimple_stmt_iterator gsi = gsi_for_stmt (scalar_stmt);
1422 : 797 : gsi_replace (&gsi, vec_stmt, true);
1423 : :
1424 : 797 : vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt);
1425 : 797 : }
1426 : :
1427 : : /* Add VEC_STMT to the vectorized implementation of STMT_INFO and insert it
1428 : : before *GSI. Create and return a stmt_vec_info for VEC_STMT. */
1429 : :
1430 : : void
1431 : 1289952 : vect_finish_stmt_generation (vec_info *vinfo,
1432 : : stmt_vec_info stmt_info, gimple *vec_stmt,
1433 : : gimple_stmt_iterator *gsi)
1434 : : {
1435 : 1289952 : gcc_assert (!stmt_info || gimple_code (stmt_info->stmt) != GIMPLE_LABEL);
1436 : :
1437 : 1289952 : if (!gsi_end_p (*gsi)
1438 : 2578621 : && gimple_has_mem_ops (vec_stmt))
1439 : : {
1440 : 1288669 : gimple *at_stmt = gsi_stmt (*gsi);
1441 : 1288669 : tree vuse = gimple_vuse (at_stmt);
1442 : 1282518 : if (vuse && TREE_CODE (vuse) == SSA_NAME)
1443 : : {
1444 : 1172501 : tree vdef = gimple_vdef (at_stmt);
1445 : 1172501 : gimple_set_vuse (vec_stmt, gimple_vuse (at_stmt));
1446 : 1172501 : gimple_set_modified (vec_stmt, true);
1447 : : /* If we have an SSA vuse and insert a store, update virtual
1448 : : SSA form to avoid triggering the renamer. Do so only
1449 : : if we can easily see all uses - which is what almost always
1450 : : happens with the way vectorized stmts are inserted. */
1451 : 732532 : if ((vdef && TREE_CODE (vdef) == SSA_NAME)
1452 : 1904997 : && ((is_gimple_assign (vec_stmt)
1453 : 731810 : && !is_gimple_reg (gimple_assign_lhs (vec_stmt)))
1454 : 61512 : || (is_gimple_call (vec_stmt)
1455 : 686 : && (!(gimple_call_flags (vec_stmt)
1456 : 686 : & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
1457 : 9 : || (gimple_call_lhs (vec_stmt)
1458 : 9 : && !is_gimple_reg (gimple_call_lhs (vec_stmt)))))))
1459 : : {
1460 : 671661 : tree new_vdef = copy_ssa_name (vuse, vec_stmt);
1461 : 671661 : gimple_set_vdef (vec_stmt, new_vdef);
1462 : 671661 : SET_USE (gimple_vuse_op (at_stmt), new_vdef);
1463 : : }
1464 : : }
1465 : : }
1466 : 1289952 : gsi_insert_before (gsi, vec_stmt, GSI_SAME_STMT);
1467 : 1289952 : vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt);
1468 : 1289952 : }
1469 : :
1470 : : /* We want to vectorize a call to combined function CFN with function
1471 : : decl FNDECL, using VECTYPE_OUT as the type of the output and VECTYPE_IN
1472 : : as the types of all inputs. Check whether this is possible using
1473 : : an internal function, returning its code if so or IFN_LAST if not. */
1474 : :
1475 : : static internal_fn
1476 : 11064 : vectorizable_internal_function (combined_fn cfn, tree fndecl,
1477 : : tree vectype_out, tree vectype_in)
1478 : : {
1479 : 11064 : internal_fn ifn;
1480 : 11064 : if (internal_fn_p (cfn))
1481 : 8728 : ifn = as_internal_fn (cfn);
1482 : : else
1483 : 2336 : ifn = associated_internal_fn (fndecl);
1484 : 11064 : if (ifn != IFN_LAST && direct_internal_fn_p (ifn))
1485 : : {
1486 : 7284 : const direct_internal_fn_info &info = direct_internal_fn (ifn);
1487 : 7284 : if (info.vectorizable)
1488 : : {
1489 : 7284 : bool same_size_p = TYPE_SIZE (vectype_in) == TYPE_SIZE (vectype_out);
1490 : 7284 : tree type0 = (info.type0 < 0 ? vectype_out : vectype_in);
1491 : 7284 : tree type1 = (info.type1 < 0 ? vectype_out : vectype_in);
1492 : :
1493 : : /* The type size of both the vectype_in and vectype_out should be
1494 : : exactly the same when vectype_out isn't participating the optab.
1495 : : While there is no restriction for type size when vectype_out
1496 : : is part of the optab query. */
1497 : 7284 : if (type0 != vectype_out && type1 != vectype_out && !same_size_p)
1498 : : return IFN_LAST;
1499 : :
1500 : 7266 : if (direct_internal_fn_supported_p (ifn, tree_pair (type0, type1),
1501 : : OPTIMIZE_FOR_SPEED))
1502 : : return ifn;
1503 : : }
1504 : : }
1505 : : return IFN_LAST;
1506 : : }
1507 : :
1508 : :
1509 : : static tree permute_vec_elements (vec_info *, tree, tree, tree, stmt_vec_info,
1510 : : gimple_stmt_iterator *);
1511 : :
1512 : : /* Check whether a load or store statement in the loop described by
1513 : : LOOP_VINFO is possible in a loop using partial vectors. This is
1514 : : testing whether the vectorizer pass has the appropriate support,
1515 : : as well as whether the target does.
1516 : :
1517 : : VLS_TYPE says whether the statement is a load or store and VECTYPE
1518 : : is the type of the vector being loaded or stored. SLP_NODE is the SLP
1519 : : node that contains the statement, or null if none. MEMORY_ACCESS_TYPE
1520 : : says how the load or store is going to be implemented and GROUP_SIZE
1521 : : is the number of load or store statements in the containing group.
1522 : : If the access is a gather load or scatter store, GS_INFO describes
1523 : : its arguments. If the load or store is conditional, SCALAR_MASK is the
1524 : : condition under which it occurs.
1525 : :
1526 : : Clear LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P if a loop using partial
1527 : : vectors is not supported, otherwise record the required rgroup control
1528 : : types.
1529 : :
1530 : : If partial vectors can be used and ELSVALS is nonzero the supported
1531 : : else values will be added to the vector ELSVALS points to. */
1532 : :
1533 : : static void
1534 : 109 : check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype,
1535 : : slp_tree slp_node,
1536 : : vec_load_store_type vls_type,
1537 : : int group_size,
1538 : : vect_memory_access_type
1539 : : memory_access_type,
1540 : : gather_scatter_info *gs_info,
1541 : : tree scalar_mask,
1542 : : vec<int> *elsvals = nullptr)
1543 : : {
1544 : : /* Invariant loads need no special support. */
1545 : 109 : if (memory_access_type == VMAT_INVARIANT)
1546 : 0 : return;
1547 : :
1548 : 109 : unsigned int nvectors = vect_get_num_copies (loop_vinfo, slp_node, vectype);
1549 : 109 : vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
1550 : 109 : vec_loop_lens *lens = &LOOP_VINFO_LENS (loop_vinfo);
1551 : 109 : machine_mode vecmode = TYPE_MODE (vectype);
1552 : 109 : bool is_load = (vls_type == VLS_LOAD);
1553 : 109 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
1554 : : {
1555 : 0 : if (slp_node)
1556 : 0 : nvectors /= group_size;
1557 : 0 : internal_fn ifn
1558 : 0 : = (is_load ? vect_load_lanes_supported (vectype, group_size, true,
1559 : : elsvals)
1560 : 0 : : vect_store_lanes_supported (vectype, group_size, true));
1561 : 0 : if (ifn == IFN_MASK_LEN_LOAD_LANES || ifn == IFN_MASK_LEN_STORE_LANES)
1562 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1);
1563 : 0 : else if (ifn == IFN_MASK_LOAD_LANES || ifn == IFN_MASK_STORE_LANES)
1564 : 0 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
1565 : : scalar_mask);
1566 : : else
1567 : : {
1568 : 0 : if (dump_enabled_p ())
1569 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1570 : : "can't operate on partial vectors because"
1571 : : " the target doesn't have an appropriate"
1572 : : " load/store-lanes instruction.\n");
1573 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1574 : : }
1575 : 0 : return;
1576 : : }
1577 : :
1578 : 109 : if (memory_access_type == VMAT_GATHER_SCATTER)
1579 : : {
1580 : 0 : internal_fn ifn = (is_load
1581 : 0 : ? IFN_MASK_GATHER_LOAD
1582 : : : IFN_MASK_SCATTER_STORE);
1583 : 0 : internal_fn len_ifn = (is_load
1584 : : ? IFN_MASK_LEN_GATHER_LOAD
1585 : : : IFN_MASK_LEN_SCATTER_STORE);
1586 : 0 : if (internal_gather_scatter_fn_supported_p (len_ifn, vectype,
1587 : : gs_info->memory_type,
1588 : : gs_info->offset_vectype,
1589 : : gs_info->scale,
1590 : : elsvals))
1591 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1);
1592 : 0 : else if (internal_gather_scatter_fn_supported_p (ifn, vectype,
1593 : : gs_info->memory_type,
1594 : : gs_info->offset_vectype,
1595 : : gs_info->scale,
1596 : : elsvals))
1597 : 0 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
1598 : : scalar_mask);
1599 : : else
1600 : : {
1601 : 0 : if (dump_enabled_p ())
1602 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1603 : : "can't operate on partial vectors because"
1604 : : " the target doesn't have an appropriate"
1605 : : " gather load or scatter store instruction.\n");
1606 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1607 : : }
1608 : 0 : return;
1609 : : }
1610 : :
1611 : 109 : if (memory_access_type != VMAT_CONTIGUOUS
1612 : 109 : && memory_access_type != VMAT_CONTIGUOUS_PERMUTE)
1613 : : {
1614 : : /* Element X of the data must come from iteration i * VF + X of the
1615 : : scalar loop. We need more work to support other mappings. */
1616 : 0 : if (dump_enabled_p ())
1617 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1618 : : "can't operate on partial vectors because an"
1619 : : " access isn't contiguous.\n");
1620 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1621 : 0 : return;
1622 : : }
1623 : :
1624 : 109 : if (!VECTOR_MODE_P (vecmode))
1625 : : {
1626 : 0 : if (dump_enabled_p ())
1627 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1628 : : "can't operate on partial vectors when emulating"
1629 : : " vector operations.\n");
1630 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1631 : 0 : return;
1632 : : }
1633 : :
1634 : : /* We might load more scalars than we need for permuting SLP loads.
1635 : : We checked in get_group_load_store_type that the extra elements
1636 : : don't leak into a new vector. */
1637 : 190 : auto group_memory_nvectors = [](poly_uint64 size, poly_uint64 nunits)
1638 : : {
1639 : 81 : unsigned int nvectors;
1640 : 162 : if (can_div_away_from_zero_p (size, nunits, &nvectors))
1641 : 81 : return nvectors;
1642 : : gcc_unreachable ();
1643 : : };
1644 : :
1645 : 109 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
1646 : 109 : poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
1647 : 109 : machine_mode mask_mode;
1648 : 109 : machine_mode vmode;
1649 : 109 : bool using_partial_vectors_p = false;
1650 : 109 : if (get_len_load_store_mode
1651 : 109 : (vecmode, is_load, nullptr, elsvals).exists (&vmode))
1652 : : {
1653 : 0 : nvectors = group_memory_nvectors (group_size * vf, nunits);
1654 : 0 : unsigned factor = (vecmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vecmode);
1655 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, factor);
1656 : 0 : using_partial_vectors_p = true;
1657 : : }
1658 : 190 : else if (targetm.vectorize.get_mask_mode (vecmode).exists (&mask_mode)
1659 : 109 : && can_vec_mask_load_store_p (vecmode, mask_mode, is_load, NULL,
1660 : : elsvals))
1661 : : {
1662 : 81 : nvectors = group_memory_nvectors (group_size * vf, nunits);
1663 : 81 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, scalar_mask);
1664 : 81 : using_partial_vectors_p = true;
1665 : : }
1666 : :
1667 : 81 : if (!using_partial_vectors_p)
1668 : : {
1669 : 28 : if (dump_enabled_p ())
1670 : 3 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1671 : : "can't operate on partial vectors because the"
1672 : : " target doesn't have the appropriate partial"
1673 : : " vectorization load or store.\n");
1674 : 28 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1675 : : }
1676 : : }
1677 : :
1678 : : /* Return the mask input to a masked load or store. VEC_MASK is the vectorized
1679 : : form of the scalar mask condition and LOOP_MASK, if nonnull, is the mask
1680 : : that needs to be applied to all loads and stores in a vectorized loop.
1681 : : Return VEC_MASK if LOOP_MASK is null or if VEC_MASK is already masked,
1682 : : otherwise return VEC_MASK & LOOP_MASK.
1683 : :
1684 : : MASK_TYPE is the type of both masks. If new statements are needed,
1685 : : insert them before GSI. */
1686 : :
1687 : : tree
1688 : 1307 : prepare_vec_mask (loop_vec_info loop_vinfo, tree mask_type, tree loop_mask,
1689 : : tree vec_mask, gimple_stmt_iterator *gsi)
1690 : : {
1691 : 1307 : gcc_assert (useless_type_conversion_p (mask_type, TREE_TYPE (vec_mask)));
1692 : 1307 : if (!loop_mask)
1693 : : return vec_mask;
1694 : :
1695 : 36 : gcc_assert (TREE_TYPE (loop_mask) == mask_type);
1696 : :
1697 : 36 : if (loop_vinfo->vec_cond_masked_set.contains ({ vec_mask, loop_mask }))
1698 : : return vec_mask;
1699 : :
1700 : 36 : tree and_res = make_temp_ssa_name (mask_type, NULL, "vec_mask_and");
1701 : 36 : gimple *and_stmt = gimple_build_assign (and_res, BIT_AND_EXPR,
1702 : : vec_mask, loop_mask);
1703 : :
1704 : 36 : gsi_insert_before (gsi, and_stmt, GSI_SAME_STMT);
1705 : 36 : return and_res;
1706 : : }
1707 : :
1708 : : /* Determine whether we can use a gather load or scatter store to vectorize
1709 : : strided load or store STMT_INFO by truncating the current offset to a
1710 : : smaller width. We need to be able to construct an offset vector:
1711 : :
1712 : : { 0, X, X*2, X*3, ... }
1713 : :
1714 : : without loss of precision, where X is STMT_INFO's DR_STEP.
1715 : :
1716 : : Return true if this is possible, describing the gather load or scatter
1717 : : store in GS_INFO. MASKED_P is true if the load or store is conditional.
1718 : :
1719 : : If we can use gather/scatter and ELSVALS is nonzero the supported
1720 : : else values will be stored in the vector ELSVALS points to. */
1721 : :
1722 : : static bool
1723 : 55061 : vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info,
1724 : : loop_vec_info loop_vinfo, bool masked_p,
1725 : : gather_scatter_info *gs_info,
1726 : : vec<int> *elsvals)
1727 : : {
1728 : 55061 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1729 : 55061 : data_reference *dr = dr_info->dr;
1730 : 55061 : tree step = DR_STEP (dr);
1731 : 55061 : if (TREE_CODE (step) != INTEGER_CST)
1732 : : {
1733 : : /* ??? Perhaps we could use range information here? */
1734 : 31083 : if (dump_enabled_p ())
1735 : 443 : dump_printf_loc (MSG_NOTE, vect_location,
1736 : : "cannot truncate variable step.\n");
1737 : 31083 : return false;
1738 : : }
1739 : :
1740 : : /* Get the number of bits in an element. */
1741 : 23978 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
1742 : 23978 : scalar_mode element_mode = SCALAR_TYPE_MODE (TREE_TYPE (vectype));
1743 : 23978 : unsigned int element_bits = GET_MODE_BITSIZE (element_mode);
1744 : :
1745 : : /* Set COUNT to the upper limit on the number of elements - 1.
1746 : : Start with the maximum vectorization factor. */
1747 : 23978 : unsigned HOST_WIDE_INT count = vect_max_vf (loop_vinfo) - 1;
1748 : :
1749 : : /* Try lowering COUNT to the number of scalar latch iterations. */
1750 : 23978 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
1751 : 23978 : widest_int max_iters;
1752 : 23978 : if (max_loop_iterations (loop, &max_iters)
1753 : 47956 : && max_iters < count)
1754 : 3641 : count = max_iters.to_shwi ();
1755 : :
1756 : : /* Try scales of 1 and the element size. */
1757 : 23978 : unsigned int scales[] = { 1, vect_get_scalar_dr_size (dr_info) };
1758 : 23978 : wi::overflow_type overflow = wi::OVF_NONE;
1759 : 71934 : for (int i = 0; i < 2; ++i)
1760 : : {
1761 : 47956 : unsigned int scale = scales[i];
1762 : 47956 : widest_int factor;
1763 : 47956 : if (!wi::multiple_of_p (wi::to_widest (step), scale, SIGNED, &factor))
1764 : 0 : continue;
1765 : :
1766 : : /* Determine the minimum precision of (COUNT - 1) * STEP / SCALE. */
1767 : 47956 : widest_int range = wi::mul (count, factor, SIGNED, &overflow);
1768 : 47956 : if (overflow)
1769 : 0 : continue;
1770 : 47956 : signop sign = range >= 0 ? UNSIGNED : SIGNED;
1771 : 47956 : unsigned int min_offset_bits = wi::min_precision (range, sign);
1772 : :
1773 : : /* Find the narrowest viable offset type. */
1774 : 47956 : unsigned int offset_bits = 1U << ceil_log2 (min_offset_bits);
1775 : 47956 : tree offset_type = build_nonstandard_integer_type (offset_bits,
1776 : : sign == UNSIGNED);
1777 : :
1778 : : /* See whether the target supports the operation with an offset
1779 : : no narrower than OFFSET_TYPE. */
1780 : 47956 : tree memory_type = TREE_TYPE (DR_REF (dr));
1781 : 47956 : if (!vect_gather_scatter_fn_p (loop_vinfo, DR_IS_READ (dr), masked_p,
1782 : : vectype, memory_type, offset_type, scale,
1783 : : &gs_info->ifn, &gs_info->offset_vectype,
1784 : : elsvals)
1785 : 47956 : || gs_info->ifn == IFN_LAST)
1786 : 47956 : continue;
1787 : :
1788 : 0 : gs_info->decl = NULL_TREE;
1789 : : /* Logically the sum of DR_BASE_ADDRESS, DR_INIT and DR_OFFSET,
1790 : : but we don't need to store that here. */
1791 : 0 : gs_info->base = NULL_TREE;
1792 : 0 : gs_info->element_type = TREE_TYPE (vectype);
1793 : 0 : gs_info->offset = fold_convert (offset_type, step);
1794 : 0 : gs_info->offset_dt = vect_constant_def;
1795 : 0 : gs_info->scale = scale;
1796 : 0 : gs_info->memory_type = memory_type;
1797 : 0 : return true;
1798 : 95912 : }
1799 : :
1800 : 23978 : if (overflow && dump_enabled_p ())
1801 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1802 : : "truncating gather/scatter offset to %d bits"
1803 : : " might change its value.\n", element_bits);
1804 : :
1805 : : return false;
1806 : 23978 : }
1807 : :
1808 : : /* Return true if we can use gather/scatter internal functions to
1809 : : vectorize STMT_INFO, which is a grouped or strided load or store.
1810 : : MASKED_P is true if load or store is conditional. When returning
1811 : : true, fill in GS_INFO with the information required to perform the
1812 : : operation.
1813 : :
1814 : : If we can use gather/scatter and ELSVALS is nonzero the supported
1815 : : else values will be stored in the vector ELSVALS points to. */
1816 : :
1817 : : static bool
1818 : 55061 : vect_use_strided_gather_scatters_p (stmt_vec_info stmt_info,
1819 : : loop_vec_info loop_vinfo, bool masked_p,
1820 : : gather_scatter_info *gs_info,
1821 : : vec<int> *elsvals)
1822 : : {
1823 : 55061 : if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info, elsvals)
1824 : 55061 : || gs_info->ifn == IFN_LAST)
1825 : 55061 : return vect_truncate_gather_scatter_offset (stmt_info, loop_vinfo,
1826 : 55061 : masked_p, gs_info, elsvals);
1827 : :
1828 : 0 : tree old_offset_type = TREE_TYPE (gs_info->offset);
1829 : 0 : tree new_offset_type = TREE_TYPE (gs_info->offset_vectype);
1830 : :
1831 : 0 : gcc_assert (TYPE_PRECISION (new_offset_type)
1832 : : >= TYPE_PRECISION (old_offset_type));
1833 : 0 : gs_info->offset = fold_convert (new_offset_type, gs_info->offset);
1834 : :
1835 : 0 : if (dump_enabled_p ())
1836 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1837 : : "using gather/scatter for strided/grouped access,"
1838 : : " scale = %d\n", gs_info->scale);
1839 : :
1840 : : return true;
1841 : : }
1842 : :
1843 : : /* STMT_INFO is a non-strided load or store, meaning that it accesses
1844 : : elements with a known constant step. Return -1 if that step
1845 : : is negative, 0 if it is zero, and 1 if it is greater than zero. */
1846 : :
1847 : : int
1848 : 2019393 : compare_step_with_zero (vec_info *vinfo, stmt_vec_info stmt_info)
1849 : : {
1850 : 2019393 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1851 : 2019393 : return tree_int_cst_compare (vect_dr_behavior (vinfo, dr_info)->step,
1852 : 2019393 : size_zero_node);
1853 : : }
1854 : :
1855 : : /* If the target supports a permute mask that reverses the elements in
1856 : : a vector of type VECTYPE, return that mask, otherwise return null. */
1857 : :
1858 : : tree
1859 : 12121 : perm_mask_for_reverse (tree vectype)
1860 : : {
1861 : 12121 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
1862 : :
1863 : : /* The encoding has a single stepped pattern. */
1864 : 12121 : vec_perm_builder sel (nunits, 1, 3);
1865 : 48484 : for (int i = 0; i < 3; ++i)
1866 : 36363 : sel.quick_push (nunits - 1 - i);
1867 : :
1868 : 12121 : vec_perm_indices indices (sel, 1, nunits);
1869 : 12121 : if (!can_vec_perm_const_p (TYPE_MODE (vectype), TYPE_MODE (vectype),
1870 : : indices))
1871 : : return NULL_TREE;
1872 : 11055 : return vect_gen_perm_mask_checked (vectype, indices);
1873 : 12121 : }
1874 : :
1875 : : /* A subroutine of get_load_store_type, with a subset of the same
1876 : : arguments. Handle the case where STMT_INFO is a load or store that
1877 : : accesses consecutive elements with a negative step. Sets *POFFSET
1878 : : to the offset to be applied to the DR for the first access. */
1879 : :
1880 : : static vect_memory_access_type
1881 : 13415 : get_negative_load_store_type (vec_info *vinfo,
1882 : : stmt_vec_info stmt_info, tree vectype,
1883 : : vec_load_store_type vls_type,
1884 : : unsigned int ncopies, poly_int64 *poffset)
1885 : : {
1886 : 13415 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1887 : 13415 : dr_alignment_support alignment_support_scheme;
1888 : :
1889 : 13415 : if (ncopies > 1)
1890 : : {
1891 : 0 : if (dump_enabled_p ())
1892 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1893 : : "multiple types with negative step.\n");
1894 : 0 : return VMAT_ELEMENTWISE;
1895 : : }
1896 : :
1897 : : /* For backward running DRs the first access in vectype actually is
1898 : : N-1 elements before the address of the DR. */
1899 : 13415 : *poffset = ((-TYPE_VECTOR_SUBPARTS (vectype) + 1)
1900 : 13415 : * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype))));
1901 : :
1902 : 13415 : int misalignment = dr_misalignment (dr_info, vectype, *poffset);
1903 : 13415 : alignment_support_scheme
1904 : 13415 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype, misalignment);
1905 : 13415 : if (alignment_support_scheme != dr_aligned
1906 : 13415 : && alignment_support_scheme != dr_unaligned_supported)
1907 : : {
1908 : 2736 : if (dump_enabled_p ())
1909 : 4 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1910 : : "negative step but alignment required.\n");
1911 : 2736 : *poffset = 0;
1912 : 2736 : return VMAT_ELEMENTWISE;
1913 : : }
1914 : :
1915 : 10679 : if (vls_type == VLS_STORE_INVARIANT)
1916 : : {
1917 : 1096 : if (dump_enabled_p ())
1918 : 52 : dump_printf_loc (MSG_NOTE, vect_location,
1919 : : "negative step with invariant source;"
1920 : : " no permute needed.\n");
1921 : 1096 : return VMAT_CONTIGUOUS_DOWN;
1922 : : }
1923 : :
1924 : 9583 : if (!perm_mask_for_reverse (vectype))
1925 : : {
1926 : 1066 : if (dump_enabled_p ())
1927 : 50 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1928 : : "negative step and reversing not supported.\n");
1929 : 1066 : *poffset = 0;
1930 : 1066 : return VMAT_ELEMENTWISE;
1931 : : }
1932 : :
1933 : : return VMAT_CONTIGUOUS_REVERSE;
1934 : : }
1935 : :
1936 : : /* STMT_INFO is either a masked or unconditional store. Return the value
1937 : : being stored. */
1938 : :
1939 : : tree
1940 : 5097937 : vect_get_store_rhs (stmt_vec_info stmt_info)
1941 : : {
1942 : 5097937 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
1943 : : {
1944 : 5095812 : gcc_assert (gimple_assign_single_p (assign));
1945 : 5095812 : return gimple_assign_rhs1 (assign);
1946 : : }
1947 : 2125 : if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt))
1948 : : {
1949 : 2125 : internal_fn ifn = gimple_call_internal_fn (call);
1950 : 2125 : int index = internal_fn_stored_value_index (ifn);
1951 : 2125 : gcc_assert (index >= 0);
1952 : 2125 : return gimple_call_arg (call, index);
1953 : : }
1954 : 0 : gcc_unreachable ();
1955 : : }
1956 : :
1957 : : /* Function VECTOR_VECTOR_COMPOSITION_TYPE
1958 : :
1959 : : This function returns a vector type which can be composed with NETLS pieces,
1960 : : whose type is recorded in PTYPE. VTYPE should be a vector type, and has the
1961 : : same vector size as the return vector. It checks target whether supports
1962 : : pieces-size vector mode for construction firstly, if target fails to, check
1963 : : pieces-size scalar mode for construction further. It returns NULL_TREE if
1964 : : fails to find the available composition.
1965 : :
1966 : : For example, for (vtype=V16QI, nelts=4), we can probably get:
1967 : : - V16QI with PTYPE V4QI.
1968 : : - V4SI with PTYPE SI.
1969 : : - NULL_TREE. */
1970 : :
1971 : : static tree
1972 : 11191 : vector_vector_composition_type (tree vtype, poly_uint64 nelts, tree *ptype)
1973 : : {
1974 : 11191 : gcc_assert (VECTOR_TYPE_P (vtype));
1975 : 11191 : gcc_assert (known_gt (nelts, 0U));
1976 : :
1977 : 11191 : machine_mode vmode = TYPE_MODE (vtype);
1978 : 11191 : if (!VECTOR_MODE_P (vmode))
1979 : : return NULL_TREE;
1980 : :
1981 : : /* When we are asked to compose the vector from its components let
1982 : : that happen directly. */
1983 : 11191 : if (known_eq (TYPE_VECTOR_SUBPARTS (vtype), nelts))
1984 : : {
1985 : 5437 : *ptype = TREE_TYPE (vtype);
1986 : 5437 : return vtype;
1987 : : }
1988 : :
1989 : 11508 : poly_uint64 vbsize = GET_MODE_BITSIZE (vmode);
1990 : 5754 : unsigned int pbsize;
1991 : 5754 : if (constant_multiple_p (vbsize, nelts, &pbsize))
1992 : : {
1993 : : /* First check if vec_init optab supports construction from
1994 : : vector pieces directly. */
1995 : 5754 : scalar_mode elmode = SCALAR_TYPE_MODE (TREE_TYPE (vtype));
1996 : 11508 : poly_uint64 inelts = pbsize / GET_MODE_BITSIZE (elmode);
1997 : 5754 : machine_mode rmode;
1998 : 5754 : if (related_vector_mode (vmode, elmode, inelts).exists (&rmode)
1999 : 5182 : && (convert_optab_handler (vec_init_optab, vmode, rmode)
2000 : : != CODE_FOR_nothing))
2001 : : {
2002 : 4211 : *ptype = build_vector_type (TREE_TYPE (vtype), inelts);
2003 : 4211 : return vtype;
2004 : : }
2005 : :
2006 : : /* Otherwise check if exists an integer type of the same piece size and
2007 : : if vec_init optab supports construction from it directly. */
2008 : 1543 : if (int_mode_for_size (pbsize, 0).exists (&elmode)
2009 : 1543 : && related_vector_mode (vmode, elmode, nelts).exists (&rmode)
2010 : 1465 : && (convert_optab_handler (vec_init_optab, rmode, elmode)
2011 : : != CODE_FOR_nothing))
2012 : : {
2013 : 1465 : *ptype = build_nonstandard_integer_type (pbsize, 1);
2014 : 1465 : return build_vector_type (*ptype, nelts);
2015 : : }
2016 : : }
2017 : :
2018 : : return NULL_TREE;
2019 : : }
2020 : :
2021 : : /* A subroutine of get_load_store_type, with a subset of the same
2022 : : arguments. Handle the case where STMT_INFO is part of a grouped load
2023 : : or store.
2024 : :
2025 : : For stores, the statements in the group are all consecutive
2026 : : and there is no gap at the end. For loads, the statements in the
2027 : : group might not be consecutive; there can be gaps between statements
2028 : : as well as at the end.
2029 : :
2030 : : If we can use gather/scatter and ELSVALS is nonzero the supported
2031 : : else values will be stored in the vector ELSVALS points to.
2032 : : */
2033 : :
2034 : : static bool
2035 : 1944708 : get_group_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
2036 : : tree vectype, slp_tree slp_node,
2037 : : bool masked_p, vec_load_store_type vls_type,
2038 : : vect_memory_access_type *memory_access_type,
2039 : : poly_int64 *poffset,
2040 : : dr_alignment_support *alignment_support_scheme,
2041 : : int *misalignment,
2042 : : gather_scatter_info *gs_info,
2043 : : internal_fn *lanes_ifn,
2044 : : vec<int> *elsvals)
2045 : : {
2046 : 1944708 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
2047 : 587642 : class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
2048 : 1944708 : stmt_vec_info first_stmt_info;
2049 : 1944708 : unsigned int group_size;
2050 : 1944708 : unsigned HOST_WIDE_INT gap;
2051 : 1944708 : bool single_element_p;
2052 : 1944708 : poly_int64 neg_ldst_offset = 0;
2053 : 1944708 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
2054 : : {
2055 : 1463808 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
2056 : 1463808 : group_size = DR_GROUP_SIZE (first_stmt_info);
2057 : 1463808 : gap = DR_GROUP_GAP (first_stmt_info);
2058 : 1463808 : single_element_p = (stmt_info == first_stmt_info
2059 : 1463808 : && !DR_GROUP_NEXT_ELEMENT (stmt_info));
2060 : : }
2061 : : else
2062 : : {
2063 : : first_stmt_info = stmt_info;
2064 : : group_size = 1;
2065 : : gap = 0;
2066 : : single_element_p = true;
2067 : : }
2068 : 1944708 : dr_vec_info *first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
2069 : 1944708 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
2070 : :
2071 : : /* True if the vectorized statements would access beyond the last
2072 : : statement in the group. */
2073 : 1944708 : bool overrun_p = false;
2074 : :
2075 : : /* True if we can cope with such overrun by peeling for gaps, so that
2076 : : there is at least one final scalar iteration after the vector loop. */
2077 : 3889416 : bool can_overrun_p = (!masked_p
2078 : 1944708 : && vls_type == VLS_LOAD
2079 : 633425 : && loop_vinfo
2080 : 2348850 : && !loop->inner);
2081 : :
2082 : : /* There can only be a gap at the end of the group if the stride is
2083 : : known at compile time. */
2084 : 1944708 : gcc_assert (!STMT_VINFO_STRIDED_P (first_stmt_info) || gap == 0);
2085 : :
2086 : : /* Stores can't yet have gaps. */
2087 : 1944708 : gcc_assert (slp_node || vls_type == VLS_LOAD || gap == 0);
2088 : :
2089 : 1944708 : if (slp_node)
2090 : : {
2091 : : /* For SLP vectorization we directly vectorize a subchain
2092 : : without permutation. */
2093 : 1944708 : if (! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
2094 : 1885589 : first_dr_info
2095 : 1885589 : = STMT_VINFO_DR_INFO (SLP_TREE_SCALAR_STMTS (slp_node)[0]);
2096 : 1944708 : if (STMT_VINFO_STRIDED_P (first_stmt_info))
2097 : : /* Try to use consecutive accesses of as many elements as possible,
2098 : : separated by the stride, until we have a complete vector.
2099 : : Fall back to scalar accesses if that isn't possible. */
2100 : 55149 : *memory_access_type = VMAT_STRIDED_SLP;
2101 : : else
2102 : : {
2103 : 1889559 : int cmp = compare_step_with_zero (vinfo, stmt_info);
2104 : 1889559 : if (cmp < 0)
2105 : : {
2106 : 13667 : if (single_element_p)
2107 : : /* ??? The VMAT_CONTIGUOUS_REVERSE code generation is
2108 : : only correct for single element "interleaving" SLP. */
2109 : 13415 : *memory_access_type = get_negative_load_store_type
2110 : 13415 : (vinfo, stmt_info, vectype, vls_type, 1,
2111 : : &neg_ldst_offset);
2112 : : else
2113 : : {
2114 : : /* Try to use consecutive accesses of DR_GROUP_SIZE elements,
2115 : : separated by the stride, until we have a complete vector.
2116 : : Fall back to scalar accesses if that isn't possible. */
2117 : 252 : if (multiple_p (nunits, group_size))
2118 : 222 : *memory_access_type = VMAT_STRIDED_SLP;
2119 : : else
2120 : 30 : *memory_access_type = VMAT_ELEMENTWISE;
2121 : : }
2122 : : }
2123 : 1875892 : else if (cmp == 0 && loop_vinfo)
2124 : : {
2125 : 4451 : gcc_assert (vls_type == VLS_LOAD);
2126 : 4451 : *memory_access_type = VMAT_INVARIANT;
2127 : : }
2128 : : /* Try using LOAD/STORE_LANES. */
2129 : 1871441 : else if (slp_node->ldst_lanes
2130 : 1871441 : && (*lanes_ifn
2131 : 0 : = (vls_type == VLS_LOAD
2132 : 0 : ? vect_load_lanes_supported (vectype, group_size,
2133 : : masked_p, elsvals)
2134 : 0 : : vect_store_lanes_supported (vectype, group_size,
2135 : : masked_p))) != IFN_LAST)
2136 : 0 : *memory_access_type = VMAT_LOAD_STORE_LANES;
2137 : : else
2138 : 1871441 : *memory_access_type = VMAT_CONTIGUOUS;
2139 : :
2140 : : /* If this is single-element interleaving with an element
2141 : : distance that leaves unused vector loads around fall back
2142 : : to elementwise access if possible - we otherwise least
2143 : : create very sub-optimal code in that case (and
2144 : : blow up memory, see PR65518). */
2145 : 1889559 : if (loop_vinfo
2146 : 1889559 : && single_element_p
2147 : 462551 : && (*memory_access_type == VMAT_CONTIGUOUS
2148 : 17866 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2149 : 2352110 : && maybe_gt (group_size, TYPE_VECTOR_SUBPARTS (vectype)))
2150 : : {
2151 : 12922 : if (SLP_TREE_LANES (slp_node) == 1)
2152 : : {
2153 : 4944 : *memory_access_type = VMAT_ELEMENTWISE;
2154 : 4944 : if (dump_enabled_p ())
2155 : 250 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2156 : : "single-element interleaving not supported "
2157 : : "for not adjacent vector loads, using "
2158 : : "elementwise access\n");
2159 : : }
2160 : : else
2161 : : {
2162 : 7978 : if (dump_enabled_p ())
2163 : 68 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2164 : : "single-element interleaving not supported "
2165 : : "for not adjacent vector loads\n");
2166 : 7990 : return false;
2167 : : }
2168 : : }
2169 : :
2170 : : /* For single-element interleaving also fall back to elementwise
2171 : : access in case we did not lower a permutation and cannot
2172 : : code generate it. */
2173 : 1881581 : auto_vec<tree> temv;
2174 : 1881581 : unsigned n_perms;
2175 : 1881581 : if (loop_vinfo
2176 : : && single_element_p
2177 : 454573 : && SLP_TREE_LANES (slp_node) == 1
2178 : 448379 : && (*memory_access_type == VMAT_CONTIGUOUS
2179 : 21803 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2180 : 434857 : && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2181 : 1889844 : && !vect_transform_slp_perm_load
2182 : 8263 : (loop_vinfo, slp_node, temv, NULL,
2183 : : LOOP_VINFO_VECT_FACTOR (loop_vinfo), true, &n_perms))
2184 : : {
2185 : 1343 : *memory_access_type = VMAT_ELEMENTWISE;
2186 : 1343 : if (dump_enabled_p ())
2187 : 100 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2188 : : "single-element interleaving permutation not "
2189 : : "supported, using elementwise access\n");
2190 : : }
2191 : :
2192 : 524515 : overrun_p = (loop_vinfo && gap != 0
2193 : 1919254 : && *memory_access_type != VMAT_ELEMENTWISE);
2194 : 1881581 : if (overrun_p && vls_type != VLS_LOAD)
2195 : : {
2196 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2197 : : "Grouped store with gaps requires"
2198 : : " non-consecutive accesses\n");
2199 : 0 : return false;
2200 : : }
2201 : :
2202 : 1881581 : unsigned HOST_WIDE_INT dr_size
2203 : 1881581 : = vect_get_scalar_dr_size (first_dr_info);
2204 : 1881581 : poly_int64 off = 0;
2205 : 1881581 : if (*memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2206 : 8313 : off = (TYPE_VECTOR_SUBPARTS (vectype) - 1) * -dr_size;
2207 : :
2208 : : /* An overrun is fine if the trailing elements are smaller
2209 : : than the alignment boundary B. Every vector access will
2210 : : be a multiple of B and so we are guaranteed to access a
2211 : : non-gap element in the same B-sized block. */
2212 : 1881581 : if (overrun_p
2213 : 1881581 : && gap < (vect_known_alignment_in_bytes (first_dr_info,
2214 : 30991 : vectype, off) / dr_size))
2215 : : overrun_p = false;
2216 : :
2217 : : /* When we have a contiguous access across loop iterations
2218 : : but the access in the loop doesn't cover the full vector
2219 : : we can end up with no gap recorded but still excess
2220 : : elements accessed, see PR103116. Make sure we peel for
2221 : : gaps if necessary and sufficient and give up if not.
2222 : :
2223 : : If there is a combination of the access not covering the full
2224 : : vector and a gap recorded then we may need to peel twice. */
2225 : 1881581 : bool large_vector_overrun_p = false;
2226 : 1881581 : if (loop_vinfo
2227 : 524515 : && (*memory_access_type == VMAT_CONTIGUOUS
2228 : 24201 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2229 : 508627 : && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2230 : 1910082 : && !multiple_p (group_size * LOOP_VINFO_VECT_FACTOR (loop_vinfo),
2231 : : nunits))
2232 : : large_vector_overrun_p = overrun_p = true;
2233 : :
2234 : : /* If the gap splits the vector in half and the target
2235 : : can do half-vector operations avoid the epilogue peeling
2236 : : by simply loading half of the vector only. Usually
2237 : : the construction with an upper zero half will be elided. */
2238 : 1881581 : dr_alignment_support alss;
2239 : 1881581 : int misalign = dr_misalignment (first_dr_info, vectype, off);
2240 : 1881581 : tree half_vtype;
2241 : 1881581 : poly_uint64 remain;
2242 : 1881581 : unsigned HOST_WIDE_INT tem, num;
2243 : 1881581 : if (overrun_p
2244 : 1881581 : && !masked_p
2245 : 25353 : && *memory_access_type != VMAT_LOAD_STORE_LANES
2246 : 25353 : && (((alss = vect_supportable_dr_alignment (vinfo, first_dr_info,
2247 : : vectype, misalign)))
2248 : : == dr_aligned
2249 : 18783 : || alss == dr_unaligned_supported)
2250 : 15439 : && can_div_trunc_p (group_size
2251 : 15439 : * LOOP_VINFO_VECT_FACTOR (loop_vinfo) - gap,
2252 : : nunits, &tem, &remain)
2253 : 1897020 : && (known_eq (remain, 0u)
2254 : 8809 : || (known_ne (remain, 0u)
2255 : 6516 : && constant_multiple_p (nunits, remain, &num)
2256 : 1874951 : && (vector_vector_composition_type (vectype, num,
2257 : : &half_vtype)
2258 : : != NULL_TREE))))
2259 : 13146 : overrun_p = false;
2260 : :
2261 : 1881581 : if (overrun_p && !can_overrun_p)
2262 : : {
2263 : 6 : if (dump_enabled_p ())
2264 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2265 : : "Peeling for outer loop is not supported\n");
2266 : 6 : return false;
2267 : : }
2268 : :
2269 : : /* Peeling for gaps assumes that a single scalar iteration
2270 : : is enough to make sure the last vector iteration doesn't
2271 : : access excess elements. */
2272 : 1881575 : if (overrun_p
2273 : 1881575 : && (!can_div_trunc_p (group_size
2274 : 12201 : * LOOP_VINFO_VECT_FACTOR (loop_vinfo) - gap,
2275 : : nunits, &tem, &remain)
2276 : 12201 : || maybe_lt (remain + group_size, nunits)))
2277 : : {
2278 : : /* But peeling a single scalar iteration is enough if
2279 : : we can use the next power-of-two sized partial
2280 : : access and that is sufficiently small to be covered
2281 : : by the single scalar iteration. */
2282 : 37 : unsigned HOST_WIDE_INT cnunits, cvf, cremain, cpart_size;
2283 : 37 : if (masked_p
2284 : 37 : || !nunits.is_constant (&cnunits)
2285 : 37 : || !LOOP_VINFO_VECT_FACTOR (loop_vinfo).is_constant (&cvf)
2286 : 37 : || (((cremain = (group_size * cvf - gap) % cnunits), true)
2287 : 37 : && ((cpart_size = (1 << ceil_log2 (cremain))), true)
2288 : 37 : && (cremain + group_size < cpart_size
2289 : 31 : || vector_vector_composition_type
2290 : 31 : (vectype, cnunits / cpart_size,
2291 : : &half_vtype) == NULL_TREE)))
2292 : : {
2293 : : /* If all fails we can still resort to niter masking unless
2294 : : the vectors used are too big, so enforce the use of
2295 : : partial vectors. */
2296 : 6 : if (LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
2297 : 0 : && !large_vector_overrun_p)
2298 : : {
2299 : 0 : if (dump_enabled_p ())
2300 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2301 : : "peeling for gaps insufficient for "
2302 : : "access unless using partial "
2303 : : "vectors\n");
2304 : 0 : LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
2305 : : }
2306 : : else
2307 : : {
2308 : 6 : if (dump_enabled_p ())
2309 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2310 : : "peeling for gaps insufficient for "
2311 : : "access\n");
2312 : 6 : return false;
2313 : : }
2314 : : }
2315 : 31 : else if (large_vector_overrun_p)
2316 : : {
2317 : 31 : if (dump_enabled_p ())
2318 : 28 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2319 : : "can't operate on partial vectors because "
2320 : : "only unmasked loads handle access "
2321 : : "shortening required because of gaps at "
2322 : : "the end of the access\n");
2323 : 31 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
2324 : : }
2325 : : }
2326 : 1881581 : }
2327 : : }
2328 : : else
2329 : : {
2330 : : /* We can always handle this case using elementwise accesses,
2331 : : but see if something more efficient is available. */
2332 : 0 : *memory_access_type = VMAT_ELEMENTWISE;
2333 : :
2334 : : /* If there is a gap at the end of the group then these optimizations
2335 : : would access excess elements in the last iteration. */
2336 : 0 : bool would_overrun_p = (gap != 0);
2337 : : /* An overrun is fine if the trailing elements are smaller than the
2338 : : alignment boundary B. Every vector access will be a multiple of B
2339 : : and so we are guaranteed to access a non-gap element in the
2340 : : same B-sized block. */
2341 : 0 : if (would_overrun_p
2342 : 0 : && !masked_p
2343 : 0 : && gap < (vect_known_alignment_in_bytes (first_dr_info, vectype)
2344 : 0 : / vect_get_scalar_dr_size (first_dr_info)))
2345 : 0 : would_overrun_p = false;
2346 : :
2347 : 0 : if (!STMT_VINFO_STRIDED_P (first_stmt_info)
2348 : 0 : && (can_overrun_p || !would_overrun_p)
2349 : 0 : && compare_step_with_zero (vinfo, stmt_info) > 0)
2350 : : {
2351 : : /* First cope with the degenerate case of a single-element
2352 : : vector. */
2353 : 0 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U))
2354 : : ;
2355 : :
2356 : : else
2357 : : {
2358 : : /* Otherwise try using LOAD/STORE_LANES. */
2359 : 0 : *lanes_ifn
2360 : 0 : = vls_type == VLS_LOAD
2361 : 0 : ? vect_load_lanes_supported (vectype, group_size, masked_p,
2362 : : elsvals)
2363 : 0 : : vect_store_lanes_supported (vectype, group_size,
2364 : : masked_p);
2365 : 0 : if (*lanes_ifn != IFN_LAST)
2366 : : {
2367 : 0 : *memory_access_type = VMAT_LOAD_STORE_LANES;
2368 : 0 : overrun_p = would_overrun_p;
2369 : : }
2370 : :
2371 : : /* If that fails, try using permuting loads. */
2372 : 0 : else if (vls_type == VLS_LOAD
2373 : 0 : ? vect_grouped_load_supported (vectype,
2374 : : single_element_p,
2375 : : group_size)
2376 : 0 : : vect_grouped_store_supported (vectype, group_size))
2377 : : {
2378 : 0 : *memory_access_type = VMAT_CONTIGUOUS_PERMUTE;
2379 : 0 : overrun_p = would_overrun_p;
2380 : : }
2381 : : }
2382 : : }
2383 : : }
2384 : :
2385 : : /* As a last resort, trying using a gather load or scatter store.
2386 : :
2387 : : ??? Although the code can handle all group sizes correctly,
2388 : : it probably isn't a win to use separate strided accesses based
2389 : : on nearby locations. Or, even if it's a win over scalar code,
2390 : : it might not be a win over vectorizing at a lower VF, if that
2391 : : allows us to use contiguous accesses. */
2392 : 1936718 : if ((*memory_access_type == VMAT_ELEMENTWISE
2393 : 1936718 : || *memory_access_type == VMAT_STRIDED_SLP)
2394 : 65490 : && single_element_p
2395 : 55338 : && (!slp_node || SLP_TREE_LANES (slp_node) == 1)
2396 : 55061 : && loop_vinfo
2397 : 1991779 : && vect_use_strided_gather_scatters_p (stmt_info, loop_vinfo,
2398 : : masked_p, gs_info, elsvals))
2399 : 0 : *memory_access_type = VMAT_GATHER_SCATTER;
2400 : :
2401 : 1936718 : if (*memory_access_type == VMAT_CONTIGUOUS_DOWN
2402 : 1935622 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2403 : 9405 : *poffset = neg_ldst_offset;
2404 : :
2405 : 1936718 : if (*memory_access_type == VMAT_GATHER_SCATTER
2406 : 1936718 : || *memory_access_type == VMAT_ELEMENTWISE
2407 : 1926599 : || *memory_access_type == VMAT_STRIDED_SLP
2408 : 1871228 : || *memory_access_type == VMAT_INVARIANT)
2409 : : {
2410 : 69941 : *alignment_support_scheme = dr_unaligned_supported;
2411 : 69941 : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2412 : : }
2413 : : else
2414 : : {
2415 : 1866777 : *misalignment = dr_misalignment (first_dr_info, vectype, *poffset);
2416 : 1866777 : *alignment_support_scheme
2417 : 1866777 : = vect_supportable_dr_alignment (vinfo, first_dr_info, vectype,
2418 : : *misalignment);
2419 : : }
2420 : :
2421 : 1936718 : if (vls_type != VLS_LOAD && first_stmt_info == stmt_info)
2422 : : {
2423 : : /* STMT is the leader of the group. Check the operands of all the
2424 : : stmts of the group. */
2425 : 1309730 : stmt_vec_info next_stmt_info = DR_GROUP_NEXT_ELEMENT (stmt_info);
2426 : 3267407 : while (next_stmt_info)
2427 : : {
2428 : 1957677 : tree op = vect_get_store_rhs (next_stmt_info);
2429 : 1957677 : enum vect_def_type dt;
2430 : 1957677 : if (!vect_is_simple_use (op, vinfo, &dt))
2431 : : {
2432 : 0 : if (dump_enabled_p ())
2433 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2434 : : "use not simple.\n");
2435 : 0 : return false;
2436 : : }
2437 : 1957677 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
2438 : : }
2439 : : }
2440 : :
2441 : 1936718 : if (overrun_p)
2442 : : {
2443 : 12195 : gcc_assert (can_overrun_p);
2444 : 12195 : if (dump_enabled_p ())
2445 : 913 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2446 : : "Data access with gaps requires scalar "
2447 : : "epilogue loop\n");
2448 : 12195 : LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo) = true;
2449 : : }
2450 : :
2451 : : return true;
2452 : : }
2453 : :
2454 : : /* Analyze load or store statement STMT_INFO of type VLS_TYPE. Return true
2455 : : if there is a memory access type that the vectorized form can use,
2456 : : storing it in *MEMORY_ACCESS_TYPE if so. If we decide to use gathers
2457 : : or scatters, fill in GS_INFO accordingly. In addition
2458 : : *ALIGNMENT_SUPPORT_SCHEME is filled out and false is returned if
2459 : : the target does not support the alignment scheme. *MISALIGNMENT
2460 : : is set according to the alignment of the access (including
2461 : : DR_MISALIGNMENT_UNKNOWN when it is unknown).
2462 : :
2463 : : SLP says whether we're performing SLP rather than loop vectorization.
2464 : : MASKED_P is true if the statement is conditional on a vectorized mask.
2465 : : VECTYPE is the vector type that the vectorized statements will use.
2466 : : NCOPIES is the number of vector statements that will be needed.
2467 : :
2468 : : If ELSVALS is nonzero the supported else values will be stored in the
2469 : : vector ELSVALS points to. */
2470 : :
2471 : : static bool
2472 : 1953276 : get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
2473 : : tree vectype, slp_tree slp_node,
2474 : : bool masked_p, vec_load_store_type vls_type,
2475 : : unsigned int ncopies,
2476 : : vect_memory_access_type *memory_access_type,
2477 : : poly_int64 *poffset,
2478 : : dr_alignment_support *alignment_support_scheme,
2479 : : int *misalignment,
2480 : : gather_scatter_info *gs_info,
2481 : : internal_fn *lanes_ifn,
2482 : : vec<int> *elsvals = nullptr)
2483 : : {
2484 : 1953276 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
2485 : 1953276 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
2486 : 1953276 : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2487 : 1953276 : *poffset = 0;
2488 : 1953276 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
2489 : : {
2490 : 8568 : *memory_access_type = VMAT_GATHER_SCATTER;
2491 : 8568 : if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info,
2492 : : elsvals))
2493 : 0 : gcc_unreachable ();
2494 : : /* When using internal functions, we rely on pattern recognition
2495 : : to convert the type of the offset to the type that the target
2496 : : requires, with the result being a call to an internal function.
2497 : : If that failed for some reason (e.g. because another pattern
2498 : : took priority), just handle cases in which the offset already
2499 : : has the right type. */
2500 : 8568 : else if (gs_info->ifn != IFN_LAST
2501 : 0 : && !is_gimple_call (stmt_info->stmt)
2502 : 8568 : && !tree_nop_conversion_p (TREE_TYPE (gs_info->offset),
2503 : 0 : TREE_TYPE (gs_info->offset_vectype)))
2504 : : {
2505 : 0 : if (dump_enabled_p ())
2506 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2507 : : "%s offset requires a conversion\n",
2508 : : vls_type == VLS_LOAD ? "gather" : "scatter");
2509 : 0 : return false;
2510 : : }
2511 : 8568 : else if (!vect_is_simple_use (gs_info->offset, vinfo,
2512 : : &gs_info->offset_dt,
2513 : : &gs_info->offset_vectype))
2514 : : {
2515 : 0 : if (dump_enabled_p ())
2516 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2517 : : "%s index use not simple.\n",
2518 : : vls_type == VLS_LOAD ? "gather" : "scatter");
2519 : 0 : return false;
2520 : : }
2521 : 8568 : else if (gs_info->ifn == IFN_LAST && !gs_info->decl)
2522 : : {
2523 : 7775 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant ()
2524 : 7775 : || !TYPE_VECTOR_SUBPARTS (gs_info->offset_vectype).is_constant ()
2525 : 7775 : || !constant_multiple_p (TYPE_VECTOR_SUBPARTS
2526 : 7775 : (gs_info->offset_vectype),
2527 : 13352 : TYPE_VECTOR_SUBPARTS (vectype)))
2528 : : {
2529 : 2198 : if (dump_enabled_p ())
2530 : 440 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2531 : : "unsupported vector types for emulated "
2532 : : "gather.\n");
2533 : 2198 : return false;
2534 : : }
2535 : : }
2536 : : /* Gather-scatter accesses perform only component accesses, alignment
2537 : : is irrelevant for them. */
2538 : 6370 : *alignment_support_scheme = dr_unaligned_supported;
2539 : : }
2540 : 1944708 : else if (STMT_VINFO_GROUPED_ACCESS (stmt_info) || slp_node)
2541 : : {
2542 : 1944708 : if (!get_group_load_store_type (vinfo, stmt_info, vectype, slp_node,
2543 : : masked_p,
2544 : : vls_type, memory_access_type, poffset,
2545 : : alignment_support_scheme,
2546 : : misalignment, gs_info, lanes_ifn,
2547 : : elsvals))
2548 : : return false;
2549 : : }
2550 : 0 : else if (STMT_VINFO_STRIDED_P (stmt_info))
2551 : : {
2552 : 0 : gcc_assert (!slp_node);
2553 : 0 : if (loop_vinfo
2554 : 0 : && vect_use_strided_gather_scatters_p (stmt_info, loop_vinfo,
2555 : : masked_p, gs_info, elsvals))
2556 : 0 : *memory_access_type = VMAT_GATHER_SCATTER;
2557 : : else
2558 : 0 : *memory_access_type = VMAT_ELEMENTWISE;
2559 : : /* Alignment is irrelevant here. */
2560 : 0 : *alignment_support_scheme = dr_unaligned_supported;
2561 : : }
2562 : : else
2563 : : {
2564 : 0 : int cmp = compare_step_with_zero (vinfo, stmt_info);
2565 : 0 : if (cmp == 0)
2566 : : {
2567 : 0 : gcc_assert (vls_type == VLS_LOAD);
2568 : 0 : *memory_access_type = VMAT_INVARIANT;
2569 : : /* Invariant accesses perform only component accesses, alignment
2570 : : is irrelevant for them. */
2571 : 0 : *alignment_support_scheme = dr_unaligned_supported;
2572 : : }
2573 : : else
2574 : : {
2575 : 0 : if (cmp < 0)
2576 : 0 : *memory_access_type = get_negative_load_store_type
2577 : 0 : (vinfo, stmt_info, vectype, vls_type, ncopies, poffset);
2578 : : else
2579 : 0 : *memory_access_type = VMAT_CONTIGUOUS;
2580 : 0 : *misalignment = dr_misalignment (STMT_VINFO_DR_INFO (stmt_info),
2581 : : vectype, *poffset);
2582 : 0 : *alignment_support_scheme
2583 : 0 : = vect_supportable_dr_alignment (vinfo,
2584 : 0 : STMT_VINFO_DR_INFO (stmt_info),
2585 : : vectype, *misalignment);
2586 : : }
2587 : : }
2588 : :
2589 : 1943088 : if ((*memory_access_type == VMAT_ELEMENTWISE
2590 : 1943088 : || *memory_access_type == VMAT_STRIDED_SLP)
2591 : : && !nunits.is_constant ())
2592 : : {
2593 : : if (dump_enabled_p ())
2594 : : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2595 : : "Not using elementwise accesses due to variable "
2596 : : "vectorization factor.\n");
2597 : : return false;
2598 : : }
2599 : :
2600 : :
2601 : : /* Checks if all scalar iterations are known to be inbounds. */
2602 : 1943088 : bool inbounds = DR_SCALAR_KNOWN_BOUNDS (STMT_VINFO_DR_INFO (stmt_info));
2603 : :
2604 : : /* Check if we support the operation if early breaks are needed. Here we
2605 : : must ensure that we don't access any more than the scalar code would
2606 : : have. A masked operation would ensure this, so for these load types
2607 : : force masking. */
2608 : 1943088 : if (loop_vinfo
2609 : 586022 : && dr_safe_speculative_read_required (stmt_info)
2610 : 152814 : && LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
2611 : 1943088 : && (*memory_access_type == VMAT_GATHER_SCATTER
2612 : 152814 : || *memory_access_type == VMAT_STRIDED_SLP))
2613 : : {
2614 : 5816 : if (dump_enabled_p ())
2615 : 8 : dump_printf_loc (MSG_NOTE, vect_location,
2616 : : "early break not supported: cannot peel for "
2617 : : "alignment. With non-contiguous memory vectorization"
2618 : : " could read out of bounds at %G ",
2619 : : STMT_VINFO_STMT (stmt_info));
2620 : 5816 : if (inbounds)
2621 : 0 : LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
2622 : : else
2623 : : return false;
2624 : : }
2625 : :
2626 : : /* If this DR needs alignment for correctness, we must ensure the target
2627 : : alignment is a constant power-of-two multiple of the amount read per
2628 : : vector iteration or force masking. */
2629 : 1937272 : if (dr_safe_speculative_read_required (stmt_info)
2630 : 1937272 : && *alignment_support_scheme == dr_aligned)
2631 : : {
2632 : : /* We can only peel for loops, of course. */
2633 : 89433 : gcc_checking_assert (loop_vinfo);
2634 : :
2635 : 89433 : auto target_alignment
2636 : 89433 : = DR_TARGET_ALIGNMENT (STMT_VINFO_DR_INFO (stmt_info));
2637 : 89433 : unsigned HOST_WIDE_INT target_align;
2638 : :
2639 : 89433 : bool group_aligned = false;
2640 : 89433 : if (target_alignment.is_constant (&target_align)
2641 : : && nunits.is_constant ())
2642 : : {
2643 : 89433 : poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
2644 : 89433 : auto vectype_size
2645 : 89433 : = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
2646 : 89433 : poly_uint64 required_alignment = vf * vectype_size;
2647 : : /* If we have a grouped access we require that the alignment be N * elem. */
2648 : 89433 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
2649 : 6998 : required_alignment *=
2650 : 6998 : DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info));
2651 : 89433 : if (!multiple_p (target_alignment, required_alignment))
2652 : : {
2653 : 5352 : if (dump_enabled_p ())
2654 : 14 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2655 : : "desired alignment %wu not met. Instead got %wu "
2656 : : "for DR alignment at %G",
2657 : : required_alignment.to_constant (),
2658 : : target_align, STMT_VINFO_STMT (stmt_info));
2659 : 5352 : return false;
2660 : : }
2661 : :
2662 : 84081 : if (!pow2p_hwi (target_align))
2663 : : {
2664 : 0 : if (dump_enabled_p ())
2665 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2666 : : "non-power-of-two vector alignment %wd "
2667 : : "for DR alignment at %G",
2668 : : target_align, STMT_VINFO_STMT (stmt_info));
2669 : 0 : return false;
2670 : : }
2671 : :
2672 : : /* For VLA we have to insert a runtime check that the vector loads
2673 : : per iterations don't exceed a page size. For now we can use
2674 : : POLY_VALUE_MAX as a proxy as we can't peel for VLA. */
2675 : 84081 : if (known_gt (required_alignment, (unsigned)param_min_pagesize))
2676 : : {
2677 : 0 : if (dump_enabled_p ())
2678 : : {
2679 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2680 : : "alignment required for correctness (");
2681 : 0 : dump_dec (MSG_MISSED_OPTIMIZATION, required_alignment);
2682 : 0 : dump_printf (MSG_NOTE, ") may exceed page size\n");
2683 : : }
2684 : 0 : return false;
2685 : : }
2686 : :
2687 : 84081 : group_aligned = true;
2688 : : }
2689 : :
2690 : : /* There are multiple loads that have a misalignment that we couldn't
2691 : : align. We would need LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P to
2692 : : vectorize. */
2693 : 84081 : if (!group_aligned)
2694 : : {
2695 : : if (inbounds)
2696 : : LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
2697 : : else
2698 : : return false;
2699 : : }
2700 : :
2701 : : /* When using a group access the first element may be aligned but the
2702 : : subsequent loads may not be. For LOAD_LANES since the loads are based
2703 : : on the first DR then all loads in the group are aligned. For
2704 : : non-LOAD_LANES this is not the case. In particular a load + blend when
2705 : : there are gaps can have the non first loads issued unaligned, even
2706 : : partially overlapping the memory of the first load in order to simplify
2707 : : the blend. This is what the x86_64 backend does for instance. As
2708 : : such only the first load in the group is aligned, the rest are not.
2709 : : Because of this the permutes may break the alignment requirements that
2710 : : have been set, and as such we should for now, reject them. */
2711 : 84081 : if (slp_node && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
2712 : : {
2713 : 1314 : if (dump_enabled_p ())
2714 : 72 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2715 : : "loads with load permutations not supported for "
2716 : : "speculative early break loads for %G",
2717 : : STMT_VINFO_STMT (stmt_info));
2718 : 1314 : return false;
2719 : : }
2720 : : }
2721 : :
2722 : 1930606 : if (*alignment_support_scheme == dr_unaligned_unsupported)
2723 : : {
2724 : 49551 : if (dump_enabled_p ())
2725 : 278 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2726 : : "unsupported unaligned access\n");
2727 : 49551 : return false;
2728 : : }
2729 : :
2730 : : /* FIXME: At the moment the cost model seems to underestimate the
2731 : : cost of using elementwise accesses. This check preserves the
2732 : : traditional behavior until that can be fixed. */
2733 : 1881055 : stmt_vec_info first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
2734 : 1881055 : if (!first_stmt_info)
2735 : 444236 : first_stmt_info = stmt_info;
2736 : 1881055 : if (*memory_access_type == VMAT_ELEMENTWISE
2737 : 10119 : && !STMT_VINFO_STRIDED_P (first_stmt_info)
2738 : 1891174 : && !(stmt_info == DR_GROUP_FIRST_ELEMENT (stmt_info)
2739 : 6698 : && !DR_GROUP_NEXT_ELEMENT (stmt_info)
2740 : 6671 : && !pow2p_hwi (DR_GROUP_SIZE (stmt_info))))
2741 : : {
2742 : 6434 : if (dump_enabled_p ())
2743 : 226 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2744 : : "not falling back to elementwise accesses\n");
2745 : 6434 : return false;
2746 : : }
2747 : : return true;
2748 : : }
2749 : :
2750 : : /* Return true if boolean argument at MASK_INDEX is suitable for vectorizing
2751 : : conditional operation STMT_INFO. When returning true, store the mask
2752 : : in *MASK, the type of its definition in *MASK_DT_OUT, the type of the
2753 : : vectorized mask in *MASK_VECTYPE_OUT and the SLP node corresponding
2754 : : to the mask in *MASK_NODE if MASK_NODE is not NULL. */
2755 : :
2756 : : static bool
2757 : 7850 : vect_check_scalar_mask (vec_info *vinfo, stmt_vec_info stmt_info,
2758 : : slp_tree slp_node, unsigned mask_index,
2759 : : tree *mask, slp_tree *mask_node,
2760 : : vect_def_type *mask_dt_out, tree *mask_vectype_out)
2761 : : {
2762 : 7850 : enum vect_def_type mask_dt;
2763 : 7850 : tree mask_vectype;
2764 : 7850 : slp_tree mask_node_1;
2765 : 7850 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, mask_index,
2766 : : mask, &mask_node_1, &mask_dt, &mask_vectype))
2767 : : {
2768 : 0 : if (dump_enabled_p ())
2769 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2770 : : "mask use not simple.\n");
2771 : 0 : return false;
2772 : : }
2773 : :
2774 : 7850 : if ((mask_dt == vect_constant_def || mask_dt == vect_external_def)
2775 : 7850 : && !VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (*mask)))
2776 : : {
2777 : 0 : if (dump_enabled_p ())
2778 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2779 : : "mask argument is not a boolean.\n");
2780 : 0 : return false;
2781 : : }
2782 : :
2783 : : /* If the caller is not prepared for adjusting an external/constant
2784 : : SLP mask vector type fail. */
2785 : 7850 : if (slp_node
2786 : 7850 : && !mask_node
2787 : 0 : && SLP_TREE_DEF_TYPE (mask_node_1) != vect_internal_def)
2788 : : {
2789 : 0 : if (dump_enabled_p ())
2790 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2791 : : "SLP mask argument is not vectorized.\n");
2792 : 0 : return false;
2793 : : }
2794 : :
2795 : 7850 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
2796 : 7850 : if (!mask_vectype)
2797 : 21 : mask_vectype = get_mask_type_for_scalar_type (vinfo, TREE_TYPE (vectype),
2798 : : mask_node_1);
2799 : :
2800 : 7850 : if (!mask_vectype || !VECTOR_BOOLEAN_TYPE_P (mask_vectype))
2801 : : {
2802 : 0 : if (dump_enabled_p ())
2803 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2804 : : "could not find an appropriate vector mask type.\n");
2805 : 0 : return false;
2806 : : }
2807 : :
2808 : 7850 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (mask_vectype),
2809 : 15700 : TYPE_VECTOR_SUBPARTS (vectype)))
2810 : : {
2811 : 0 : if (dump_enabled_p ())
2812 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2813 : : "vector mask type %T"
2814 : : " does not match vector data type %T.\n",
2815 : : mask_vectype, vectype);
2816 : :
2817 : 0 : return false;
2818 : : }
2819 : :
2820 : 7850 : *mask_dt_out = mask_dt;
2821 : 7850 : *mask_vectype_out = mask_vectype;
2822 : 7850 : if (mask_node)
2823 : 7850 : *mask_node = mask_node_1;
2824 : : return true;
2825 : : }
2826 : :
2827 : : /* Return true if stored value is suitable for vectorizing store
2828 : : statement STMT_INFO. When returning true, store the scalar stored
2829 : : in *RHS and *RHS_NODE, the type of the definition in *RHS_DT_OUT,
2830 : : the type of the vectorized store value in
2831 : : *RHS_VECTYPE_OUT and the type of the store in *VLS_TYPE_OUT. */
2832 : :
2833 : : static bool
2834 : 1312832 : vect_check_store_rhs (vec_info *vinfo, stmt_vec_info stmt_info,
2835 : : slp_tree slp_node, tree *rhs, slp_tree *rhs_node,
2836 : : vect_def_type *rhs_dt_out, tree *rhs_vectype_out,
2837 : : vec_load_store_type *vls_type_out)
2838 : : {
2839 : 1312832 : int op_no = 0;
2840 : 1312832 : if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt))
2841 : : {
2842 : 1590 : if (gimple_call_internal_p (call)
2843 : 1590 : && internal_store_fn_p (gimple_call_internal_fn (call)))
2844 : 1590 : op_no = internal_fn_stored_value_index (gimple_call_internal_fn (call));
2845 : : }
2846 : 1312832 : if (slp_node)
2847 : 1312832 : op_no = vect_slp_child_index_for_operand
2848 : 1312832 : (stmt_info->stmt, op_no, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
2849 : :
2850 : 1312832 : enum vect_def_type rhs_dt;
2851 : 1312832 : tree rhs_vectype;
2852 : 1312832 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, op_no,
2853 : : rhs, rhs_node, &rhs_dt, &rhs_vectype))
2854 : : {
2855 : 0 : if (dump_enabled_p ())
2856 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2857 : : "use not simple.\n");
2858 : 0 : return false;
2859 : : }
2860 : :
2861 : : /* In the case this is a store from a constant make sure
2862 : : native_encode_expr can handle it. */
2863 : 1312832 : if (rhs_dt == vect_constant_def
2864 : 1312832 : && CONSTANT_CLASS_P (*rhs) && native_encode_expr (*rhs, NULL, 64) == 0)
2865 : : {
2866 : 0 : if (dump_enabled_p ())
2867 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2868 : : "cannot encode constant as a byte sequence.\n");
2869 : 0 : return false;
2870 : : }
2871 : :
2872 : 1312832 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
2873 : 1312832 : if (rhs_vectype && !useless_type_conversion_p (vectype, rhs_vectype))
2874 : : {
2875 : 24 : if (dump_enabled_p ())
2876 : 24 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2877 : : "incompatible vector types.\n");
2878 : 24 : return false;
2879 : : }
2880 : :
2881 : 1312808 : *rhs_dt_out = rhs_dt;
2882 : 1312808 : *rhs_vectype_out = rhs_vectype;
2883 : 1312808 : if (rhs_dt == vect_constant_def || rhs_dt == vect_external_def)
2884 : 978954 : *vls_type_out = VLS_STORE_INVARIANT;
2885 : : else
2886 : 333854 : *vls_type_out = VLS_STORE;
2887 : : return true;
2888 : : }
2889 : :
2890 : : /* Build an all-ones vector mask of type MASKTYPE while vectorizing STMT_INFO.
2891 : : Note that we support masks with floating-point type, in which case the
2892 : : floats are interpreted as a bitmask. */
2893 : :
2894 : : static tree
2895 : 163 : vect_build_all_ones_mask (vec_info *vinfo,
2896 : : stmt_vec_info stmt_info, tree masktype)
2897 : : {
2898 : 163 : if (TREE_CODE (masktype) == INTEGER_TYPE)
2899 : 98 : return build_int_cst (masktype, -1);
2900 : 65 : else if (VECTOR_BOOLEAN_TYPE_P (masktype)
2901 : 130 : || TREE_CODE (TREE_TYPE (masktype)) == INTEGER_TYPE)
2902 : : {
2903 : 14 : tree mask = build_int_cst (TREE_TYPE (masktype), -1);
2904 : 14 : mask = build_vector_from_val (masktype, mask);
2905 : 14 : return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL);
2906 : : }
2907 : 51 : else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (masktype)))
2908 : : {
2909 : : REAL_VALUE_TYPE r;
2910 : : long tmp[6];
2911 : 357 : for (int j = 0; j < 6; ++j)
2912 : 306 : tmp[j] = -1;
2913 : 51 : real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (masktype)));
2914 : 51 : tree mask = build_real (TREE_TYPE (masktype), r);
2915 : 51 : mask = build_vector_from_val (masktype, mask);
2916 : 51 : return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL);
2917 : : }
2918 : 0 : gcc_unreachable ();
2919 : : }
2920 : :
2921 : : /* Build an all-zero merge value of type VECTYPE while vectorizing
2922 : : STMT_INFO as a gather load. */
2923 : :
2924 : : static tree
2925 : 156 : vect_build_zero_merge_argument (vec_info *vinfo,
2926 : : stmt_vec_info stmt_info, tree vectype)
2927 : : {
2928 : 156 : tree merge;
2929 : 156 : if (TREE_CODE (TREE_TYPE (vectype)) == INTEGER_TYPE)
2930 : 49 : merge = build_int_cst (TREE_TYPE (vectype), 0);
2931 : 107 : else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (vectype)))
2932 : : {
2933 : : REAL_VALUE_TYPE r;
2934 : : long tmp[6];
2935 : 749 : for (int j = 0; j < 6; ++j)
2936 : 642 : tmp[j] = 0;
2937 : 107 : real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (vectype)));
2938 : 107 : merge = build_real (TREE_TYPE (vectype), r);
2939 : : }
2940 : : else
2941 : 0 : gcc_unreachable ();
2942 : 156 : merge = build_vector_from_val (vectype, merge);
2943 : 156 : return vect_init_vector (vinfo, stmt_info, merge, vectype, NULL);
2944 : : }
2945 : :
2946 : : /* Return the corresponding else value for an else value constant
2947 : : ELSVAL with type TYPE. */
2948 : :
2949 : : tree
2950 : 1627 : vect_get_mask_load_else (int elsval, tree type)
2951 : : {
2952 : 1627 : tree els;
2953 : 1627 : if (elsval == MASK_LOAD_ELSE_UNDEFINED)
2954 : : {
2955 : 0 : tree tmp = create_tmp_var (type);
2956 : : /* No need to warn about anything. */
2957 : 0 : TREE_NO_WARNING (tmp) = 1;
2958 : 0 : els = get_or_create_ssa_default_def (cfun, tmp);
2959 : : }
2960 : 1627 : else if (elsval == MASK_LOAD_ELSE_M1)
2961 : 0 : els = build_minus_one_cst (type);
2962 : 1627 : else if (elsval == MASK_LOAD_ELSE_ZERO)
2963 : 1627 : els = build_zero_cst (type);
2964 : : else
2965 : 0 : gcc_unreachable ();
2966 : :
2967 : 1627 : return els;
2968 : : }
2969 : :
2970 : : /* Build a gather load call while vectorizing STMT_INFO. Insert new
2971 : : instructions before GSI and add them to VEC_STMT. GS_INFO describes
2972 : : the gather load operation. If the load is conditional, MASK is the
2973 : : vectorized condition, otherwise MASK is null. PTR is the base
2974 : : pointer and OFFSET is the vectorized offset. */
2975 : :
2976 : : static gimple *
2977 : 344 : vect_build_one_gather_load_call (vec_info *vinfo, stmt_vec_info stmt_info,
2978 : : gimple_stmt_iterator *gsi,
2979 : : gather_scatter_info *gs_info,
2980 : : tree ptr, tree offset, tree mask)
2981 : : {
2982 : 344 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
2983 : 344 : tree arglist = TYPE_ARG_TYPES (TREE_TYPE (gs_info->decl));
2984 : 344 : tree rettype = TREE_TYPE (TREE_TYPE (gs_info->decl));
2985 : 344 : tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2986 : 344 : /* ptrtype */ arglist = TREE_CHAIN (arglist);
2987 : 344 : tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2988 : 344 : tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2989 : 344 : tree scaletype = TREE_VALUE (arglist);
2990 : 344 : tree var;
2991 : 344 : gcc_checking_assert (types_compatible_p (srctype, rettype)
2992 : : && (!mask
2993 : : || TREE_CODE (masktype) == INTEGER_TYPE
2994 : : || types_compatible_p (srctype, masktype)));
2995 : :
2996 : 344 : tree op = offset;
2997 : 344 : if (!useless_type_conversion_p (idxtype, TREE_TYPE (op)))
2998 : : {
2999 : 100 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)),
3000 : : TYPE_VECTOR_SUBPARTS (idxtype)));
3001 : 100 : var = vect_get_new_ssa_name (idxtype, vect_simple_var);
3002 : 100 : op = build1 (VIEW_CONVERT_EXPR, idxtype, op);
3003 : 100 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op);
3004 : 100 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3005 : 100 : op = var;
3006 : : }
3007 : :
3008 : 344 : tree src_op = NULL_TREE;
3009 : 344 : tree mask_op = NULL_TREE;
3010 : 344 : if (mask)
3011 : : {
3012 : 188 : if (!useless_type_conversion_p (masktype, TREE_TYPE (mask)))
3013 : : {
3014 : 188 : tree utype, optype = TREE_TYPE (mask);
3015 : 188 : if (VECTOR_TYPE_P (masktype)
3016 : 188 : || TYPE_MODE (masktype) == TYPE_MODE (optype))
3017 : : utype = masktype;
3018 : : else
3019 : 7 : utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1);
3020 : 188 : var = vect_get_new_ssa_name (utype, vect_scalar_var);
3021 : 188 : tree mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask);
3022 : 188 : gassign *new_stmt
3023 : 188 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg);
3024 : 188 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3025 : 188 : mask_arg = var;
3026 : 188 : if (!useless_type_conversion_p (masktype, utype))
3027 : : {
3028 : 7 : gcc_assert (TYPE_PRECISION (utype)
3029 : : <= TYPE_PRECISION (masktype));
3030 : 7 : var = vect_get_new_ssa_name (masktype, vect_scalar_var);
3031 : 7 : new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg);
3032 : 7 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3033 : 7 : mask_arg = var;
3034 : : }
3035 : 188 : src_op = build_zero_cst (srctype);
3036 : 188 : mask_op = mask_arg;
3037 : : }
3038 : : else
3039 : : {
3040 : : src_op = mask;
3041 : : mask_op = mask;
3042 : : }
3043 : : }
3044 : : else
3045 : : {
3046 : 156 : src_op = vect_build_zero_merge_argument (vinfo, stmt_info, rettype);
3047 : 156 : mask_op = vect_build_all_ones_mask (vinfo, stmt_info, masktype);
3048 : : }
3049 : :
3050 : 344 : tree scale = build_int_cst (scaletype, gs_info->scale);
3051 : 344 : gimple *new_stmt = gimple_build_call (gs_info->decl, 5, src_op, ptr, op,
3052 : : mask_op, scale);
3053 : :
3054 : 344 : if (!useless_type_conversion_p (vectype, rettype))
3055 : : {
3056 : 49 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (vectype),
3057 : : TYPE_VECTOR_SUBPARTS (rettype)));
3058 : 49 : op = vect_get_new_ssa_name (rettype, vect_simple_var);
3059 : 49 : gimple_call_set_lhs (new_stmt, op);
3060 : 49 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3061 : 49 : op = build1 (VIEW_CONVERT_EXPR, vectype, op);
3062 : 49 : new_stmt = gimple_build_assign (NULL_TREE, VIEW_CONVERT_EXPR, op);
3063 : : }
3064 : :
3065 : 344 : return new_stmt;
3066 : : }
3067 : :
3068 : : /* Build a scatter store call while vectorizing STMT_INFO. Insert new
3069 : : instructions before GSI. GS_INFO describes the scatter store operation.
3070 : : PTR is the base pointer, OFFSET the vectorized offsets and OPRND the
3071 : : vectorized data to store.
3072 : : If the store is conditional, MASK is the vectorized condition, otherwise
3073 : : MASK is null. */
3074 : :
3075 : : static gimple *
3076 : 173 : vect_build_one_scatter_store_call (vec_info *vinfo, stmt_vec_info stmt_info,
3077 : : gimple_stmt_iterator *gsi,
3078 : : gather_scatter_info *gs_info,
3079 : : tree ptr, tree offset, tree oprnd, tree mask)
3080 : : {
3081 : 173 : tree rettype = TREE_TYPE (TREE_TYPE (gs_info->decl));
3082 : 173 : tree arglist = TYPE_ARG_TYPES (TREE_TYPE (gs_info->decl));
3083 : 173 : /* tree ptrtype = TREE_VALUE (arglist); */ arglist = TREE_CHAIN (arglist);
3084 : 173 : tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
3085 : 173 : tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
3086 : 173 : tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
3087 : 173 : tree scaletype = TREE_VALUE (arglist);
3088 : 173 : gcc_checking_assert (TREE_CODE (masktype) == INTEGER_TYPE
3089 : : && TREE_CODE (rettype) == VOID_TYPE);
3090 : :
3091 : 173 : tree mask_arg = NULL_TREE;
3092 : 173 : if (mask)
3093 : : {
3094 : 110 : mask_arg = mask;
3095 : 110 : tree optype = TREE_TYPE (mask_arg);
3096 : 110 : tree utype;
3097 : 110 : if (TYPE_MODE (masktype) == TYPE_MODE (optype))
3098 : : utype = masktype;
3099 : : else
3100 : 8 : utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1);
3101 : 110 : tree var = vect_get_new_ssa_name (utype, vect_scalar_var);
3102 : 110 : mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask_arg);
3103 : 110 : gassign *new_stmt
3104 : 110 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg);
3105 : 110 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3106 : 110 : mask_arg = var;
3107 : 110 : if (!useless_type_conversion_p (masktype, utype))
3108 : : {
3109 : 8 : gcc_assert (TYPE_PRECISION (utype) <= TYPE_PRECISION (masktype));
3110 : 8 : tree var = vect_get_new_ssa_name (masktype, vect_scalar_var);
3111 : 8 : new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg);
3112 : 8 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3113 : 8 : mask_arg = var;
3114 : : }
3115 : : }
3116 : : else
3117 : : {
3118 : 63 : mask_arg = build_int_cst (masktype, -1);
3119 : 63 : mask_arg = vect_init_vector (vinfo, stmt_info, mask_arg, masktype, NULL);
3120 : : }
3121 : :
3122 : 173 : tree src = oprnd;
3123 : 173 : if (!useless_type_conversion_p (srctype, TREE_TYPE (src)))
3124 : : {
3125 : 0 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (src)),
3126 : : TYPE_VECTOR_SUBPARTS (srctype)));
3127 : 0 : tree var = vect_get_new_ssa_name (srctype, vect_simple_var);
3128 : 0 : src = build1 (VIEW_CONVERT_EXPR, srctype, src);
3129 : 0 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, src);
3130 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3131 : 0 : src = var;
3132 : : }
3133 : :
3134 : 173 : tree op = offset;
3135 : 173 : if (!useless_type_conversion_p (idxtype, TREE_TYPE (op)))
3136 : : {
3137 : 24 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)),
3138 : : TYPE_VECTOR_SUBPARTS (idxtype)));
3139 : 24 : tree var = vect_get_new_ssa_name (idxtype, vect_simple_var);
3140 : 24 : op = build1 (VIEW_CONVERT_EXPR, idxtype, op);
3141 : 24 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op);
3142 : 24 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3143 : 24 : op = var;
3144 : : }
3145 : :
3146 : 173 : tree scale = build_int_cst (scaletype, gs_info->scale);
3147 : 173 : gcall *new_stmt
3148 : 173 : = gimple_build_call (gs_info->decl, 5, ptr, mask_arg, op, src, scale);
3149 : 173 : return new_stmt;
3150 : : }
3151 : :
3152 : : /* Prepare the base and offset in GS_INFO for vectorization.
3153 : : Set *DATAREF_PTR to the loop-invariant base address and *VEC_OFFSET
3154 : : to the vectorized offset argument for the first copy of STMT_INFO.
3155 : : STMT_INFO is the statement described by GS_INFO and LOOP is the
3156 : : containing loop. */
3157 : :
3158 : : static void
3159 : 1202 : vect_get_gather_scatter_ops (loop_vec_info loop_vinfo,
3160 : : class loop *loop, stmt_vec_info stmt_info,
3161 : : slp_tree slp_node, gather_scatter_info *gs_info,
3162 : : tree *dataref_ptr, vec<tree> *vec_offset)
3163 : : {
3164 : 1202 : gimple_seq stmts = NULL;
3165 : 1202 : *dataref_ptr = force_gimple_operand (gs_info->base, &stmts, true, NULL_TREE);
3166 : 1202 : if (stmts != NULL)
3167 : : {
3168 : 967 : basic_block new_bb;
3169 : 967 : edge pe = loop_preheader_edge (loop);
3170 : 967 : new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
3171 : 967 : gcc_assert (!new_bb);
3172 : : }
3173 : 1202 : if (slp_node)
3174 : 1202 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_offset);
3175 : : else
3176 : : {
3177 : 0 : unsigned ncopies
3178 : 0 : = vect_get_num_copies (loop_vinfo, gs_info->offset_vectype);
3179 : 0 : vect_get_vec_defs_for_operand (loop_vinfo, stmt_info, ncopies,
3180 : : gs_info->offset, vec_offset,
3181 : : gs_info->offset_vectype);
3182 : : }
3183 : 1202 : }
3184 : :
3185 : : /* Prepare to implement a grouped or strided load or store using
3186 : : the gather load or scatter store operation described by GS_INFO.
3187 : : STMT_INFO is the load or store statement.
3188 : :
3189 : : Set *DATAREF_BUMP to the amount that should be added to the base
3190 : : address after each copy of the vectorized statement. Set *VEC_OFFSET
3191 : : to an invariant offset vector in which element I has the value
3192 : : I * DR_STEP / SCALE. */
3193 : :
3194 : : static void
3195 : 0 : vect_get_strided_load_store_ops (stmt_vec_info stmt_info,
3196 : : loop_vec_info loop_vinfo,
3197 : : gimple_stmt_iterator *gsi,
3198 : : gather_scatter_info *gs_info,
3199 : : tree *dataref_bump, tree *vec_offset,
3200 : : vec_loop_lens *loop_lens)
3201 : : {
3202 : 0 : struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
3203 : 0 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
3204 : :
3205 : 0 : if (LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo))
3206 : : {
3207 : : /* _31 = .SELECT_VL (ivtmp_29, POLY_INT_CST [4, 4]);
3208 : : ivtmp_8 = _31 * 16 (step in bytes);
3209 : : .MASK_LEN_SCATTER_STORE (vectp_a.9_7, ... );
3210 : : vectp_a.9_26 = vectp_a.9_7 + ivtmp_8; */
3211 : 0 : tree loop_len
3212 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens, 1, vectype, 0, 0);
3213 : 0 : tree tmp
3214 : 0 : = fold_build2 (MULT_EXPR, sizetype,
3215 : : fold_convert (sizetype, unshare_expr (DR_STEP (dr))),
3216 : : loop_len);
3217 : 0 : *dataref_bump = force_gimple_operand_gsi (gsi, tmp, true, NULL_TREE, true,
3218 : : GSI_SAME_STMT);
3219 : : }
3220 : : else
3221 : : {
3222 : 0 : tree bump
3223 : 0 : = size_binop (MULT_EXPR,
3224 : : fold_convert (sizetype, unshare_expr (DR_STEP (dr))),
3225 : : size_int (TYPE_VECTOR_SUBPARTS (vectype)));
3226 : 0 : *dataref_bump = cse_and_gimplify_to_preheader (loop_vinfo, bump);
3227 : : }
3228 : :
3229 : 0 : internal_fn ifn
3230 : 0 : = DR_IS_READ (dr) ? IFN_MASK_LEN_STRIDED_LOAD : IFN_MASK_LEN_STRIDED_STORE;
3231 : 0 : if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
3232 : : {
3233 : 0 : *vec_offset = cse_and_gimplify_to_preheader (loop_vinfo,
3234 : : unshare_expr (DR_STEP (dr)));
3235 : 0 : return;
3236 : : }
3237 : :
3238 : : /* The offset given in GS_INFO can have pointer type, so use the element
3239 : : type of the vector instead. */
3240 : 0 : tree offset_type = TREE_TYPE (gs_info->offset_vectype);
3241 : :
3242 : : /* Calculate X = DR_STEP / SCALE and convert it to the appropriate type. */
3243 : 0 : tree step = size_binop (EXACT_DIV_EXPR, unshare_expr (DR_STEP (dr)),
3244 : : ssize_int (gs_info->scale));
3245 : 0 : step = fold_convert (offset_type, step);
3246 : :
3247 : : /* Create {0, X, X*2, X*3, ...}. */
3248 : 0 : tree offset = fold_build2 (VEC_SERIES_EXPR, gs_info->offset_vectype,
3249 : : build_zero_cst (offset_type), step);
3250 : 0 : *vec_offset = cse_and_gimplify_to_preheader (loop_vinfo, offset);
3251 : : }
3252 : :
3253 : : /* Prepare the pointer IVs which needs to be updated by a variable amount.
3254 : : Such variable amount is the outcome of .SELECT_VL. In this case, we can
3255 : : allow each iteration process the flexible number of elements as long as
3256 : : the number <= vf elments.
3257 : :
3258 : : Return data reference according to SELECT_VL.
3259 : : If new statements are needed, insert them before GSI. */
3260 : :
3261 : : static tree
3262 : 0 : vect_get_loop_variant_data_ptr_increment (
3263 : : vec_info *vinfo, tree aggr_type, gimple_stmt_iterator *gsi,
3264 : : vec_loop_lens *loop_lens, dr_vec_info *dr_info,
3265 : : vect_memory_access_type memory_access_type)
3266 : : {
3267 : 0 : loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (vinfo);
3268 : 0 : tree step = vect_dr_behavior (vinfo, dr_info)->step;
3269 : :
3270 : : /* gather/scatter never reach here. */
3271 : 0 : gcc_assert (memory_access_type != VMAT_GATHER_SCATTER);
3272 : :
3273 : : /* When we support SELECT_VL pattern, we dynamic adjust
3274 : : the memory address by .SELECT_VL result.
3275 : :
3276 : : The result of .SELECT_VL is the number of elements to
3277 : : be processed of each iteration. So the memory address
3278 : : adjustment operation should be:
3279 : :
3280 : : addr = addr + .SELECT_VL (ARG..) * step;
3281 : : */
3282 : 0 : tree loop_len
3283 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens, 1, aggr_type, 0, 0);
3284 : 0 : tree len_type = TREE_TYPE (loop_len);
3285 : : /* Since the outcome of .SELECT_VL is element size, we should adjust
3286 : : it into bytesize so that it can be used in address pointer variable
3287 : : amount IVs adjustment. */
3288 : 0 : tree tmp = fold_build2 (MULT_EXPR, len_type, loop_len,
3289 : : wide_int_to_tree (len_type, wi::to_widest (step)));
3290 : 0 : tree bump = make_temp_ssa_name (len_type, NULL, "ivtmp");
3291 : 0 : gassign *assign = gimple_build_assign (bump, tmp);
3292 : 0 : gsi_insert_before (gsi, assign, GSI_SAME_STMT);
3293 : 0 : return bump;
3294 : : }
3295 : :
3296 : : /* Return the amount that should be added to a vector pointer to move
3297 : : to the next or previous copy of AGGR_TYPE. DR_INFO is the data reference
3298 : : being vectorized and MEMORY_ACCESS_TYPE describes the type of
3299 : : vectorization. */
3300 : :
3301 : : static tree
3302 : 681294 : vect_get_data_ptr_increment (vec_info *vinfo, gimple_stmt_iterator *gsi,
3303 : : dr_vec_info *dr_info, tree aggr_type,
3304 : : vect_memory_access_type memory_access_type,
3305 : : vec_loop_lens *loop_lens = nullptr)
3306 : : {
3307 : 681294 : if (memory_access_type == VMAT_INVARIANT)
3308 : 0 : return size_zero_node;
3309 : :
3310 : 681294 : loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (vinfo);
3311 : 122744 : if (loop_vinfo && LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo))
3312 : 0 : return vect_get_loop_variant_data_ptr_increment (vinfo, aggr_type, gsi,
3313 : : loop_lens, dr_info,
3314 : 0 : memory_access_type);
3315 : :
3316 : 681294 : tree iv_step = TYPE_SIZE_UNIT (aggr_type);
3317 : 681294 : tree step = vect_dr_behavior (vinfo, dr_info)->step;
3318 : 681294 : if (tree_int_cst_sgn (step) == -1)
3319 : 2805 : iv_step = fold_build1 (NEGATE_EXPR, TREE_TYPE (iv_step), iv_step);
3320 : : return iv_step;
3321 : : }
3322 : :
3323 : : /* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64,128}. */
3324 : :
3325 : : static bool
3326 : 120 : vectorizable_bswap (vec_info *vinfo,
3327 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
3328 : : gimple **vec_stmt, slp_tree slp_node,
3329 : : slp_tree *slp_op,
3330 : : tree vectype_in, stmt_vector_for_cost *cost_vec)
3331 : : {
3332 : 120 : tree op, vectype;
3333 : 120 : gcall *stmt = as_a <gcall *> (stmt_info->stmt);
3334 : 120 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
3335 : 120 : unsigned ncopies;
3336 : :
3337 : 120 : op = gimple_call_arg (stmt, 0);
3338 : 120 : vectype = STMT_VINFO_VECTYPE (stmt_info);
3339 : 120 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
3340 : :
3341 : : /* Multiple types in SLP are handled by creating the appropriate number of
3342 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
3343 : : case of SLP. */
3344 : 120 : if (slp_node)
3345 : : ncopies = 1;
3346 : : else
3347 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
3348 : :
3349 : 0 : gcc_assert (ncopies >= 1);
3350 : :
3351 : 120 : if (TYPE_SIZE (vectype_in) != TYPE_SIZE (vectype))
3352 : : {
3353 : 2 : if (dump_enabled_p ())
3354 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3355 : : "mismatched vector sizes %T and %T\n",
3356 : : vectype_in, vectype);
3357 : 2 : return false;
3358 : : }
3359 : :
3360 : 118 : tree char_vectype = get_same_sized_vectype (char_type_node, vectype_in);
3361 : 118 : if (! char_vectype)
3362 : : return false;
3363 : :
3364 : 118 : poly_uint64 num_bytes = TYPE_VECTOR_SUBPARTS (char_vectype);
3365 : 118 : unsigned word_bytes;
3366 : 120 : if (!constant_multiple_p (num_bytes, nunits, &word_bytes))
3367 : : return false;
3368 : :
3369 : : /* The encoding uses one stepped pattern for each byte in the word. */
3370 : 118 : vec_perm_builder elts (num_bytes, word_bytes, 3);
3371 : 472 : for (unsigned i = 0; i < 3; ++i)
3372 : 2070 : for (unsigned j = 0; j < word_bytes; ++j)
3373 : 1716 : elts.quick_push ((i + 1) * word_bytes - j - 1);
3374 : :
3375 : 118 : vec_perm_indices indices (elts, 1, num_bytes);
3376 : 118 : machine_mode vmode = TYPE_MODE (char_vectype);
3377 : 118 : if (!can_vec_perm_const_p (vmode, vmode, indices))
3378 : : return false;
3379 : :
3380 : 76 : if (! vec_stmt)
3381 : : {
3382 : 64 : if (slp_node
3383 : 64 : && !vect_maybe_update_slp_op_vectype (slp_op[0], vectype_in))
3384 : : {
3385 : 0 : if (dump_enabled_p ())
3386 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3387 : : "incompatible vector types for invariants\n");
3388 : 0 : return false;
3389 : : }
3390 : :
3391 : 64 : STMT_VINFO_TYPE (stmt_info) = call_vec_info_type;
3392 : 64 : DUMP_VECT_SCOPE ("vectorizable_bswap");
3393 : 64 : record_stmt_cost (cost_vec,
3394 : : 1, vector_stmt, stmt_info, 0, vect_prologue);
3395 : 64 : record_stmt_cost (cost_vec,
3396 : : slp_node
3397 : 64 : ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies,
3398 : : vec_perm, stmt_info, 0, vect_body);
3399 : 64 : return true;
3400 : : }
3401 : :
3402 : 12 : tree bswap_vconst = vec_perm_indices_to_tree (char_vectype, indices);
3403 : :
3404 : : /* Transform. */
3405 : 12 : vec<tree> vec_oprnds = vNULL;
3406 : 12 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
3407 : : op, &vec_oprnds);
3408 : : /* Arguments are ready. create the new vector stmt. */
3409 : 12 : unsigned i;
3410 : 12 : tree vop;
3411 : 24 : FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
3412 : : {
3413 : 12 : gimple *new_stmt;
3414 : 12 : tree tem = make_ssa_name (char_vectype);
3415 : 12 : new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
3416 : : char_vectype, vop));
3417 : 12 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3418 : 12 : tree tem2 = make_ssa_name (char_vectype);
3419 : 12 : new_stmt = gimple_build_assign (tem2, VEC_PERM_EXPR,
3420 : : tem, tem, bswap_vconst);
3421 : 12 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3422 : 12 : tem = make_ssa_name (vectype);
3423 : 12 : new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
3424 : : vectype, tem2));
3425 : 12 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3426 : 12 : if (slp_node)
3427 : 12 : slp_node->push_vec_def (new_stmt);
3428 : : else
3429 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
3430 : : }
3431 : :
3432 : 12 : if (!slp_node)
3433 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
3434 : :
3435 : 12 : vec_oprnds.release ();
3436 : 12 : return true;
3437 : 118 : }
3438 : :
3439 : : /* Return true if vector types VECTYPE_IN and VECTYPE_OUT have
3440 : : integer elements and if we can narrow VECTYPE_IN to VECTYPE_OUT
3441 : : in a single step. On success, store the binary pack code in
3442 : : *CONVERT_CODE. */
3443 : :
3444 : : static bool
3445 : 168 : simple_integer_narrowing (tree vectype_out, tree vectype_in,
3446 : : code_helper *convert_code)
3447 : : {
3448 : 336 : if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype_out))
3449 : 336 : || !INTEGRAL_TYPE_P (TREE_TYPE (vectype_in)))
3450 : : return false;
3451 : :
3452 : 70 : code_helper code;
3453 : 70 : int multi_step_cvt = 0;
3454 : 70 : auto_vec <tree, 8> interm_types;
3455 : 107 : if (!supportable_narrowing_operation (NOP_EXPR, vectype_out, vectype_in,
3456 : : &code, &multi_step_cvt, &interm_types)
3457 : 70 : || multi_step_cvt)
3458 : 37 : return false;
3459 : :
3460 : 33 : *convert_code = code;
3461 : 33 : return true;
3462 : 70 : }
3463 : :
3464 : : /* Function vectorizable_call.
3465 : :
3466 : : Check if STMT_INFO performs a function call that can be vectorized.
3467 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
3468 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
3469 : : Return true if STMT_INFO is vectorizable in this way. */
3470 : :
3471 : : static bool
3472 : 2308851 : vectorizable_call (vec_info *vinfo,
3473 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
3474 : : gimple **vec_stmt, slp_tree slp_node,
3475 : : stmt_vector_for_cost *cost_vec)
3476 : : {
3477 : 2308851 : gcall *stmt;
3478 : 2308851 : tree vec_dest;
3479 : 2308851 : tree scalar_dest;
3480 : 2308851 : tree op;
3481 : 2308851 : tree vec_oprnd0 = NULL_TREE, vec_oprnd1 = NULL_TREE;
3482 : 2308851 : tree vectype_out, vectype_in;
3483 : 2308851 : poly_uint64 nunits_in;
3484 : 2308851 : poly_uint64 nunits_out;
3485 : 2308851 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
3486 : 2308851 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
3487 : 2308851 : tree fndecl, new_temp, rhs_type;
3488 : 2308851 : enum vect_def_type dt[4]
3489 : : = { vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type,
3490 : : vect_unknown_def_type };
3491 : 2308851 : tree vectypes[ARRAY_SIZE (dt)] = {};
3492 : 2308851 : slp_tree slp_op[ARRAY_SIZE (dt)] = {};
3493 : 2308851 : int ndts = ARRAY_SIZE (dt);
3494 : 2308851 : int ncopies, j;
3495 : 2308851 : auto_vec<tree, 8> vargs;
3496 : 2308851 : enum { NARROW, NONE, WIDEN } modifier;
3497 : 2308851 : size_t i, nargs;
3498 : 2308851 : tree lhs;
3499 : 2308851 : tree clz_ctz_arg1 = NULL_TREE;
3500 : :
3501 : 2308851 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
3502 : : return false;
3503 : :
3504 : 2308851 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
3505 : 186872 : && ! vec_stmt)
3506 : : return false;
3507 : :
3508 : : /* Is STMT_INFO a vectorizable call? */
3509 : 2317957 : stmt = dyn_cast <gcall *> (stmt_info->stmt);
3510 : 17823 : if (!stmt)
3511 : : return false;
3512 : :
3513 : 17823 : if (gimple_call_internal_p (stmt)
3514 : 17823 : && (internal_load_fn_p (gimple_call_internal_fn (stmt))
3515 : 10832 : || internal_store_fn_p (gimple_call_internal_fn (stmt))))
3516 : : /* Handled by vectorizable_load and vectorizable_store. */
3517 : 2933 : return false;
3518 : :
3519 : 14890 : if (gimple_call_lhs (stmt) == NULL_TREE
3520 : 14890 : || TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME)
3521 : : return false;
3522 : :
3523 : 14890 : gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
3524 : :
3525 : 14890 : vectype_out = STMT_VINFO_VECTYPE (stmt_info);
3526 : :
3527 : : /* Process function arguments. */
3528 : 14890 : rhs_type = NULL_TREE;
3529 : 14890 : vectype_in = NULL_TREE;
3530 : 14890 : nargs = gimple_call_num_args (stmt);
3531 : :
3532 : : /* Bail out if the function has more than four arguments, we do not have
3533 : : interesting builtin functions to vectorize with more than two arguments
3534 : : except for fma. No arguments is also not good. */
3535 : 14890 : if (nargs == 0 || nargs > 4)
3536 : : return false;
3537 : :
3538 : : /* Ignore the arguments of IFN_GOMP_SIMD_LANE, they are magic. */
3539 : 14874 : combined_fn cfn = gimple_call_combined_fn (stmt);
3540 : 14874 : if (cfn == CFN_GOMP_SIMD_LANE)
3541 : : {
3542 : 3629 : nargs = 0;
3543 : 3629 : rhs_type = unsigned_type_node;
3544 : : }
3545 : : /* Similarly pretend IFN_CLZ and IFN_CTZ only has one argument, the second
3546 : : argument just says whether it is well-defined at zero or not and what
3547 : : value should be returned for it. */
3548 : 14874 : if ((cfn == CFN_CLZ || cfn == CFN_CTZ) && nargs == 2)
3549 : : {
3550 : 118 : nargs = 1;
3551 : 118 : clz_ctz_arg1 = gimple_call_arg (stmt, 1);
3552 : : }
3553 : :
3554 : 14874 : int mask_opno = -1;
3555 : 14874 : if (internal_fn_p (cfn))
3556 : 11968 : mask_opno = internal_fn_mask_index (as_internal_fn (cfn));
3557 : :
3558 : 40420 : for (i = 0; i < nargs; i++)
3559 : : {
3560 : 26701 : if ((int) i == mask_opno)
3561 : : {
3562 : 3824 : if (!vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_opno,
3563 : : &op, &slp_op[i], &dt[i], &vectypes[i]))
3564 : : return false;
3565 : 3824 : continue;
3566 : : }
3567 : :
3568 : 22877 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
3569 : : i, &op, &slp_op[i], &dt[i], &vectypes[i]))
3570 : : {
3571 : 0 : if (dump_enabled_p ())
3572 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3573 : : "use not simple.\n");
3574 : 0 : return false;
3575 : : }
3576 : :
3577 : : /* We can only handle calls with arguments of the same type. */
3578 : 22877 : if (rhs_type
3579 : 22877 : && !types_compatible_p (rhs_type, TREE_TYPE (op)))
3580 : : {
3581 : 1155 : if (dump_enabled_p ())
3582 : 367 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3583 : : "argument types differ.\n");
3584 : 1155 : return false;
3585 : : }
3586 : 21722 : if (!rhs_type)
3587 : 11245 : rhs_type = TREE_TYPE (op);
3588 : :
3589 : 21722 : if (!vectype_in)
3590 : 11756 : vectype_in = vectypes[i];
3591 : 9966 : else if (vectypes[i]
3592 : 9966 : && !types_compatible_p (vectypes[i], vectype_in))
3593 : : {
3594 : 0 : if (dump_enabled_p ())
3595 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3596 : : "argument vector types differ.\n");
3597 : 0 : return false;
3598 : : }
3599 : : }
3600 : : /* If all arguments are external or constant defs, infer the vector type
3601 : : from the scalar type. */
3602 : 13719 : if (!vectype_in)
3603 : 5593 : vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
3604 : 13719 : if (vec_stmt)
3605 : 3445 : gcc_assert (vectype_in);
3606 : 10274 : if (!vectype_in)
3607 : : {
3608 : 874 : if (dump_enabled_p ())
3609 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3610 : : "no vectype for scalar type %T\n", rhs_type);
3611 : :
3612 : 874 : return false;
3613 : : }
3614 : :
3615 : 25690 : if (VECTOR_BOOLEAN_TYPE_P (vectype_out)
3616 : 12845 : != VECTOR_BOOLEAN_TYPE_P (vectype_in))
3617 : : {
3618 : 0 : if (dump_enabled_p ())
3619 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3620 : : "mixed mask and nonmask vector types\n");
3621 : 0 : return false;
3622 : : }
3623 : :
3624 : 12845 : if (vect_emulated_vector_p (vectype_in) || vect_emulated_vector_p (vectype_out))
3625 : : {
3626 : 0 : if (dump_enabled_p ())
3627 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3628 : : "use emulated vector type for call\n");
3629 : 0 : return false;
3630 : : }
3631 : :
3632 : : /* FORNOW */
3633 : 12845 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
3634 : 12845 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
3635 : 12845 : if (known_eq (nunits_in * 2, nunits_out))
3636 : : modifier = NARROW;
3637 : 12521 : else if (known_eq (nunits_out, nunits_in))
3638 : : modifier = NONE;
3639 : 31 : else if (known_eq (nunits_out * 2, nunits_in))
3640 : : modifier = WIDEN;
3641 : : else
3642 : : return false;
3643 : :
3644 : : /* We only handle functions that do not read or clobber memory. */
3645 : 25674 : if (gimple_vuse (stmt))
3646 : : {
3647 : 1027 : if (dump_enabled_p ())
3648 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3649 : : "function reads from or writes to memory.\n");
3650 : 1027 : return false;
3651 : : }
3652 : :
3653 : : /* For now, we only vectorize functions if a target specific builtin
3654 : : is available. TODO -- in some cases, it might be profitable to
3655 : : insert the calls for pieces of the vector, in order to be able
3656 : : to vectorize other operations in the loop. */
3657 : 11810 : fndecl = NULL_TREE;
3658 : 11810 : internal_fn ifn = IFN_LAST;
3659 : 11810 : tree callee = gimple_call_fndecl (stmt);
3660 : :
3661 : : /* First try using an internal function. */
3662 : 11810 : code_helper convert_code = MAX_TREE_CODES;
3663 : 11810 : if (cfn != CFN_LAST
3664 : 11810 : && (modifier == NONE
3665 : 188 : || (modifier == NARROW
3666 : 168 : && simple_integer_narrowing (vectype_out, vectype_in,
3667 : : &convert_code))))
3668 : 11064 : ifn = vectorizable_internal_function (cfn, callee, vectype_out,
3669 : : vectype_in);
3670 : :
3671 : : /* If that fails, try asking for a target-specific built-in function. */
3672 : 11064 : if (ifn == IFN_LAST)
3673 : : {
3674 : 7136 : if (cfn != CFN_LAST)
3675 : 6545 : fndecl = targetm.vectorize.builtin_vectorized_function
3676 : 6545 : (cfn, vectype_out, vectype_in);
3677 : 591 : else if (callee && fndecl_built_in_p (callee, BUILT_IN_MD))
3678 : 36 : fndecl = targetm.vectorize.builtin_md_vectorized_function
3679 : 36 : (callee, vectype_out, vectype_in);
3680 : : }
3681 : :
3682 : 11810 : if (ifn == IFN_LAST && !fndecl)
3683 : : {
3684 : 6842 : if (cfn == CFN_GOMP_SIMD_LANE
3685 : 3629 : && (!slp_node || SLP_TREE_LANES (slp_node) == 1)
3686 : 3629 : && loop_vinfo
3687 : 3629 : && LOOP_VINFO_LOOP (loop_vinfo)->simduid
3688 : 3629 : && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME
3689 : 14100 : && LOOP_VINFO_LOOP (loop_vinfo)->simduid
3690 : 3629 : == SSA_NAME_VAR (gimple_call_arg (stmt, 0)))
3691 : : {
3692 : : /* We can handle IFN_GOMP_SIMD_LANE by returning a
3693 : : { 0, 1, 2, ... vf - 1 } vector. */
3694 : 3629 : gcc_assert (nargs == 0);
3695 : : }
3696 : 3213 : else if (modifier == NONE
3697 : 3213 : && (gimple_call_builtin_p (stmt, BUILT_IN_BSWAP16)
3698 : 3047 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP32)
3699 : 2975 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64)
3700 : 2943 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP128)))
3701 : 120 : return vectorizable_bswap (vinfo, stmt_info, gsi, vec_stmt, slp_node,
3702 : 120 : slp_op, vectype_in, cost_vec);
3703 : : else
3704 : : {
3705 : 3093 : if (dump_enabled_p ())
3706 : 234 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3707 : : "function is not vectorizable.\n");
3708 : 3093 : return false;
3709 : : }
3710 : : }
3711 : :
3712 : 8597 : if (slp_node)
3713 : : ncopies = 1;
3714 : 0 : else if (modifier == NARROW && ifn == IFN_LAST)
3715 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype_out);
3716 : : else
3717 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype_in);
3718 : :
3719 : : /* Sanity check: make sure that at least one copy of the vectorized stmt
3720 : : needs to be generated. */
3721 : 0 : gcc_assert (ncopies >= 1);
3722 : :
3723 : 8597 : int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info);
3724 : 8597 : internal_fn cond_fn = get_conditional_internal_fn (ifn);
3725 : 8597 : internal_fn cond_len_fn = get_len_internal_fn (ifn);
3726 : 8597 : int len_opno = internal_fn_len_index (cond_len_fn);
3727 : 8597 : vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL);
3728 : 7947 : vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL);
3729 : 8597 : if (!vec_stmt) /* transformation not required. */
3730 : : {
3731 : 5164 : if (slp_node)
3732 : 14299 : for (i = 0; i < nargs; ++i)
3733 : 9135 : if (!vect_maybe_update_slp_op_vectype (slp_op[i],
3734 : 9135 : vectypes[i]
3735 : : ? vectypes[i] : vectype_in))
3736 : : {
3737 : 0 : if (dump_enabled_p ())
3738 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3739 : : "incompatible vector types for invariants\n");
3740 : 0 : return false;
3741 : : }
3742 : 5164 : STMT_VINFO_TYPE (stmt_info) = call_vec_info_type;
3743 : 5164 : DUMP_VECT_SCOPE ("vectorizable_call");
3744 : 5164 : vect_model_simple_cost (vinfo, stmt_info,
3745 : : ncopies, dt, ndts, slp_node, cost_vec);
3746 : 5164 : if (ifn != IFN_LAST && modifier == NARROW && !slp_node)
3747 : 0 : record_stmt_cost (cost_vec, ncopies / 2,
3748 : : vec_promote_demote, stmt_info, 0, vect_body);
3749 : :
3750 : 5164 : if (loop_vinfo
3751 : 4798 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
3752 : 19 : && (reduc_idx >= 0 || mask_opno >= 0))
3753 : : {
3754 : 18 : if (reduc_idx >= 0
3755 : 0 : && (cond_fn == IFN_LAST
3756 : 0 : || !direct_internal_fn_supported_p (cond_fn, vectype_out,
3757 : : OPTIMIZE_FOR_SPEED))
3758 : 18 : && (cond_len_fn == IFN_LAST
3759 : 0 : || !direct_internal_fn_supported_p (cond_len_fn, vectype_out,
3760 : : OPTIMIZE_FOR_SPEED)))
3761 : : {
3762 : 0 : if (dump_enabled_p ())
3763 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3764 : : "can't use a fully-masked loop because no"
3765 : : " conditional operation is available.\n");
3766 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
3767 : : }
3768 : : else
3769 : : {
3770 : 36 : unsigned int nvectors
3771 : : = (slp_node
3772 : 18 : ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node)
3773 : : : ncopies);
3774 : 18 : tree scalar_mask = NULL_TREE;
3775 : 18 : if (mask_opno >= 0)
3776 : 18 : scalar_mask = gimple_call_arg (stmt_info->stmt, mask_opno);
3777 : 18 : if (cond_len_fn != IFN_LAST
3778 : 18 : && direct_internal_fn_supported_p (cond_len_fn, vectype_out,
3779 : : OPTIMIZE_FOR_SPEED))
3780 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype_out,
3781 : : 1);
3782 : : else
3783 : 18 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype_out,
3784 : : scalar_mask);
3785 : : }
3786 : : }
3787 : 5164 : return true;
3788 : : }
3789 : :
3790 : : /* Transform. */
3791 : :
3792 : 3433 : if (dump_enabled_p ())
3793 : 398 : dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n");
3794 : :
3795 : : /* Handle def. */
3796 : 3433 : scalar_dest = gimple_call_lhs (stmt);
3797 : 3433 : vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
3798 : :
3799 : 3433 : bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
3800 : 3149 : bool len_loop_p = loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
3801 : 3433 : unsigned int vect_nargs = nargs;
3802 : 3433 : if (len_loop_p)
3803 : : {
3804 : 0 : if (len_opno >= 0)
3805 : : {
3806 : 0 : ifn = cond_len_fn;
3807 : : /* COND_* -> COND_LEN_* takes 2 extra arguments:LEN,BIAS. */
3808 : 0 : vect_nargs += 2;
3809 : : }
3810 : 0 : else if (reduc_idx >= 0)
3811 : 0 : gcc_unreachable ();
3812 : : }
3813 : 3433 : else if (masked_loop_p && reduc_idx >= 0)
3814 : : {
3815 : 0 : ifn = cond_fn;
3816 : 0 : vect_nargs += 2;
3817 : : }
3818 : 3433 : if (clz_ctz_arg1)
3819 : 59 : ++vect_nargs;
3820 : :
3821 : 3433 : if (modifier == NONE || ifn != IFN_LAST)
3822 : : {
3823 : 3401 : tree prev_res = NULL_TREE;
3824 : 3401 : vargs.safe_grow (vect_nargs, true);
3825 : 3401 : auto_vec<vec<tree> > vec_defs (nargs);
3826 : 6802 : for (j = 0; j < ncopies; ++j)
3827 : : {
3828 : : /* Build argument list for the vectorized call. */
3829 : 3401 : if (slp_node)
3830 : : {
3831 : 3401 : if (cfn == CFN_GOMP_SIMD_LANE)
3832 : : {
3833 : 3290 : for (i = 0; i < SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); ++i)
3834 : : {
3835 : : /* ??? For multi-lane SLP we'd need to build
3836 : : { 0, 0, .., 1, 1, ... }. */
3837 : 3398 : tree cst = build_index_vector (vectype_out,
3838 : 1699 : i * nunits_out, 1);
3839 : 1699 : tree new_var
3840 : 1699 : = vect_get_new_ssa_name (vectype_out, vect_simple_var,
3841 : : "cst_");
3842 : 1699 : gimple *init_stmt = gimple_build_assign (new_var, cst);
3843 : 1699 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, NULL);
3844 : 1699 : new_temp = make_ssa_name (vec_dest);
3845 : 1699 : gimple *new_stmt
3846 : 1699 : = gimple_build_assign (new_temp, new_var);
3847 : 1699 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
3848 : : gsi);
3849 : 1699 : slp_node->push_vec_def (new_stmt);
3850 : : }
3851 : 1591 : continue;
3852 : 1591 : }
3853 : :
3854 : 1810 : vec<tree> vec_oprnds0;
3855 : 1810 : vect_get_slp_defs (vinfo, slp_node, &vec_defs);
3856 : 1810 : vec_oprnds0 = vec_defs[0];
3857 : :
3858 : : /* Arguments are ready. Create the new vector stmt. */
3859 : 3741 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_oprnd0)
3860 : : {
3861 : 1931 : int varg = 0;
3862 : 1931 : if (masked_loop_p && reduc_idx >= 0)
3863 : : {
3864 : 0 : unsigned int vec_num = vec_oprnds0.length ();
3865 : : /* Always true for SLP. */
3866 : 0 : gcc_assert (ncopies == 1);
3867 : 0 : vargs[varg++] = vect_get_loop_mask (loop_vinfo,
3868 : : gsi, masks, vec_num,
3869 : : vectype_out, i);
3870 : : }
3871 : : size_t k;
3872 : 7169 : for (k = 0; k < nargs; k++)
3873 : : {
3874 : 5238 : vec<tree> vec_oprndsk = vec_defs[k];
3875 : 5238 : vargs[varg++] = vec_oprndsk[i];
3876 : : }
3877 : 1931 : if (masked_loop_p && reduc_idx >= 0)
3878 : 0 : vargs[varg++] = vargs[reduc_idx + 1];
3879 : 1931 : if (clz_ctz_arg1)
3880 : 59 : vargs[varg++] = clz_ctz_arg1;
3881 : :
3882 : 1931 : gimple *new_stmt;
3883 : 1931 : if (modifier == NARROW)
3884 : : {
3885 : : /* We don't define any narrowing conditional functions
3886 : : at present. */
3887 : 0 : gcc_assert (mask_opno < 0);
3888 : 0 : tree half_res = make_ssa_name (vectype_in);
3889 : 0 : gcall *call
3890 : 0 : = gimple_build_call_internal_vec (ifn, vargs);
3891 : 0 : gimple_call_set_lhs (call, half_res);
3892 : 0 : gimple_call_set_nothrow (call, true);
3893 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3894 : 0 : if ((i & 1) == 0)
3895 : : {
3896 : 0 : prev_res = half_res;
3897 : 0 : continue;
3898 : : }
3899 : 0 : new_temp = make_ssa_name (vec_dest);
3900 : 0 : new_stmt = vect_gimple_build (new_temp, convert_code,
3901 : : prev_res, half_res);
3902 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
3903 : : new_stmt, gsi);
3904 : : }
3905 : : else
3906 : : {
3907 : 1931 : if (len_opno >= 0 && len_loop_p)
3908 : : {
3909 : 0 : unsigned int vec_num = vec_oprnds0.length ();
3910 : : /* Always true for SLP. */
3911 : 0 : gcc_assert (ncopies == 1);
3912 : 0 : tree len
3913 : 0 : = vect_get_loop_len (loop_vinfo, gsi, lens, vec_num,
3914 : : vectype_out, i, 1);
3915 : 0 : signed char biasval
3916 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
3917 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
3918 : 0 : vargs[len_opno] = len;
3919 : 0 : vargs[len_opno + 1] = bias;
3920 : : }
3921 : 1931 : else if (mask_opno >= 0 && masked_loop_p)
3922 : : {
3923 : 36 : unsigned int vec_num = vec_oprnds0.length ();
3924 : : /* Always true for SLP. */
3925 : 36 : gcc_assert (ncopies == 1);
3926 : 36 : tree mask = vect_get_loop_mask (loop_vinfo,
3927 : : gsi, masks, vec_num,
3928 : : vectype_out, i);
3929 : 36 : vargs[mask_opno] = prepare_vec_mask
3930 : 36 : (loop_vinfo, TREE_TYPE (mask), mask,
3931 : 36 : vargs[mask_opno], gsi);
3932 : : }
3933 : :
3934 : 1931 : gcall *call;
3935 : 1931 : if (ifn != IFN_LAST)
3936 : 1850 : call = gimple_build_call_internal_vec (ifn, vargs);
3937 : : else
3938 : 81 : call = gimple_build_call_vec (fndecl, vargs);
3939 : 1931 : new_temp = make_ssa_name (vec_dest, call);
3940 : 1931 : gimple_call_set_lhs (call, new_temp);
3941 : 1931 : gimple_call_set_nothrow (call, true);
3942 : 1931 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3943 : 1931 : new_stmt = call;
3944 : : }
3945 : 1931 : slp_node->push_vec_def (new_stmt);
3946 : : }
3947 : 1810 : continue;
3948 : 1810 : }
3949 : :
3950 : 0 : int varg = 0;
3951 : 0 : if (masked_loop_p && reduc_idx >= 0)
3952 : 0 : vargs[varg++] = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies,
3953 : : vectype_out, j);
3954 : 0 : for (i = 0; i < nargs; i++)
3955 : : {
3956 : 0 : op = gimple_call_arg (stmt, i);
3957 : 0 : if (j == 0)
3958 : : {
3959 : 0 : vec_defs.quick_push (vNULL);
3960 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
3961 : 0 : op, &vec_defs[i],
3962 : : vectypes[i]);
3963 : : }
3964 : 0 : vargs[varg++] = vec_defs[i][j];
3965 : : }
3966 : 0 : if (masked_loop_p && reduc_idx >= 0)
3967 : 0 : vargs[varg++] = vargs[reduc_idx + 1];
3968 : 0 : if (clz_ctz_arg1)
3969 : 0 : vargs[varg++] = clz_ctz_arg1;
3970 : :
3971 : 0 : if (len_opno >= 0 && len_loop_p)
3972 : : {
3973 : 0 : tree len = vect_get_loop_len (loop_vinfo, gsi, lens, ncopies,
3974 : : vectype_out, j, 1);
3975 : 0 : signed char biasval
3976 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
3977 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
3978 : 0 : vargs[len_opno] = len;
3979 : 0 : vargs[len_opno + 1] = bias;
3980 : : }
3981 : 0 : else if (mask_opno >= 0 && masked_loop_p)
3982 : : {
3983 : 0 : tree mask = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies,
3984 : : vectype_out, j);
3985 : 0 : vargs[mask_opno]
3986 : 0 : = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
3987 : 0 : vargs[mask_opno], gsi);
3988 : : }
3989 : :
3990 : 0 : gimple *new_stmt;
3991 : 0 : if (cfn == CFN_GOMP_SIMD_LANE)
3992 : : {
3993 : 0 : tree cst = build_index_vector (vectype_out, j * nunits_out, 1);
3994 : 0 : tree new_var
3995 : 0 : = vect_get_new_ssa_name (vectype_out, vect_simple_var, "cst_");
3996 : 0 : gimple *init_stmt = gimple_build_assign (new_var, cst);
3997 : 0 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, NULL);
3998 : 0 : new_temp = make_ssa_name (vec_dest);
3999 : 0 : new_stmt = gimple_build_assign (new_temp, new_var);
4000 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4001 : : }
4002 : 0 : else if (modifier == NARROW)
4003 : : {
4004 : : /* We don't define any narrowing conditional functions at
4005 : : present. */
4006 : 0 : gcc_assert (mask_opno < 0);
4007 : 0 : tree half_res = make_ssa_name (vectype_in);
4008 : 0 : gcall *call = gimple_build_call_internal_vec (ifn, vargs);
4009 : 0 : gimple_call_set_lhs (call, half_res);
4010 : 0 : gimple_call_set_nothrow (call, true);
4011 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
4012 : 0 : if ((j & 1) == 0)
4013 : : {
4014 : 0 : prev_res = half_res;
4015 : 0 : continue;
4016 : : }
4017 : 0 : new_temp = make_ssa_name (vec_dest);
4018 : 0 : new_stmt = vect_gimple_build (new_temp, convert_code, prev_res,
4019 : : half_res);
4020 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4021 : : }
4022 : : else
4023 : : {
4024 : 0 : gcall *call;
4025 : 0 : if (ifn != IFN_LAST)
4026 : 0 : call = gimple_build_call_internal_vec (ifn, vargs);
4027 : : else
4028 : 0 : call = gimple_build_call_vec (fndecl, vargs);
4029 : 0 : new_temp = make_ssa_name (vec_dest, call);
4030 : 0 : gimple_call_set_lhs (call, new_temp);
4031 : 0 : gimple_call_set_nothrow (call, true);
4032 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
4033 : 0 : new_stmt = call;
4034 : : }
4035 : :
4036 : 0 : if (j == (modifier == NARROW ? 1 : 0))
4037 : 0 : *vec_stmt = new_stmt;
4038 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
4039 : : }
4040 : 8353 : for (i = 0; i < nargs; i++)
4041 : : {
4042 : 4952 : vec<tree> vec_oprndsi = vec_defs[i];
4043 : 4952 : vec_oprndsi.release ();
4044 : : }
4045 : 3401 : }
4046 : 32 : else if (modifier == NARROW)
4047 : : {
4048 : 32 : auto_vec<vec<tree> > vec_defs (nargs);
4049 : : /* We don't define any narrowing conditional functions at present. */
4050 : 32 : gcc_assert (mask_opno < 0);
4051 : 64 : for (j = 0; j < ncopies; ++j)
4052 : : {
4053 : : /* Build argument list for the vectorized call. */
4054 : 32 : if (j == 0)
4055 : 32 : vargs.create (nargs * 2);
4056 : : else
4057 : 0 : vargs.truncate (0);
4058 : :
4059 : 32 : if (slp_node)
4060 : : {
4061 : 32 : vec<tree> vec_oprnds0;
4062 : :
4063 : 32 : vect_get_slp_defs (vinfo, slp_node, &vec_defs);
4064 : 32 : vec_oprnds0 = vec_defs[0];
4065 : :
4066 : : /* Arguments are ready. Create the new vector stmt. */
4067 : 64 : for (i = 0; vec_oprnds0.iterate (i, &vec_oprnd0); i += 2)
4068 : : {
4069 : 32 : size_t k;
4070 : 32 : vargs.truncate (0);
4071 : 64 : for (k = 0; k < nargs; k++)
4072 : : {
4073 : 32 : vec<tree> vec_oprndsk = vec_defs[k];
4074 : 32 : vargs.quick_push (vec_oprndsk[i]);
4075 : 32 : vargs.quick_push (vec_oprndsk[i + 1]);
4076 : : }
4077 : 32 : gcall *call;
4078 : 32 : if (ifn != IFN_LAST)
4079 : : call = gimple_build_call_internal_vec (ifn, vargs);
4080 : : else
4081 : 32 : call = gimple_build_call_vec (fndecl, vargs);
4082 : 32 : new_temp = make_ssa_name (vec_dest, call);
4083 : 32 : gimple_call_set_lhs (call, new_temp);
4084 : 32 : gimple_call_set_nothrow (call, true);
4085 : 32 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
4086 : 32 : slp_node->push_vec_def (call);
4087 : : }
4088 : 32 : continue;
4089 : 32 : }
4090 : :
4091 : 0 : for (i = 0; i < nargs; i++)
4092 : : {
4093 : 0 : op = gimple_call_arg (stmt, i);
4094 : 0 : if (j == 0)
4095 : : {
4096 : 0 : vec_defs.quick_push (vNULL);
4097 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, 2 * ncopies,
4098 : 0 : op, &vec_defs[i], vectypes[i]);
4099 : : }
4100 : 0 : vec_oprnd0 = vec_defs[i][2*j];
4101 : 0 : vec_oprnd1 = vec_defs[i][2*j+1];
4102 : :
4103 : 0 : vargs.quick_push (vec_oprnd0);
4104 : 0 : vargs.quick_push (vec_oprnd1);
4105 : : }
4106 : :
4107 : 0 : gcall *new_stmt = gimple_build_call_vec (fndecl, vargs);
4108 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
4109 : 0 : gimple_call_set_lhs (new_stmt, new_temp);
4110 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4111 : :
4112 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
4113 : : }
4114 : :
4115 : 32 : if (!slp_node)
4116 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
4117 : :
4118 : 64 : for (i = 0; i < nargs; i++)
4119 : : {
4120 : 32 : vec<tree> vec_oprndsi = vec_defs[i];
4121 : 32 : vec_oprndsi.release ();
4122 : : }
4123 : 32 : }
4124 : : else
4125 : : /* No current target implements this case. */
4126 : : return false;
4127 : :
4128 : 3433 : vargs.release ();
4129 : :
4130 : : /* The call in STMT might prevent it from being removed in dce.
4131 : : We however cannot remove it here, due to the way the ssa name
4132 : : it defines is mapped to the new definition. So just replace
4133 : : rhs of the statement with something harmless. */
4134 : :
4135 : 3433 : if (slp_node)
4136 : : return true;
4137 : :
4138 : 0 : stmt_info = vect_orig_stmt (stmt_info);
4139 : 0 : lhs = gimple_get_lhs (stmt_info->stmt);
4140 : :
4141 : 0 : gassign *new_stmt
4142 : 0 : = gimple_build_assign (lhs, build_zero_cst (TREE_TYPE (lhs)));
4143 : 0 : vinfo->replace_stmt (gsi, stmt_info, new_stmt);
4144 : :
4145 : 0 : return true;
4146 : 2308851 : }
4147 : :
4148 : :
4149 : : struct simd_call_arg_info
4150 : : {
4151 : : tree vectype;
4152 : : tree op;
4153 : : HOST_WIDE_INT linear_step;
4154 : : enum vect_def_type dt;
4155 : : unsigned int align;
4156 : : bool simd_lane_linear;
4157 : : };
4158 : :
4159 : : /* Helper function of vectorizable_simd_clone_call. If OP, an SSA_NAME,
4160 : : is linear within simd lane (but not within whole loop), note it in
4161 : : *ARGINFO. */
4162 : :
4163 : : static void
4164 : 3 : vect_simd_lane_linear (tree op, class loop *loop,
4165 : : struct simd_call_arg_info *arginfo)
4166 : : {
4167 : 3 : gimple *def_stmt = SSA_NAME_DEF_STMT (op);
4168 : :
4169 : 3 : if (!is_gimple_assign (def_stmt)
4170 : 3 : || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR
4171 : 3 : || !is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt)))
4172 : 3 : return;
4173 : :
4174 : 0 : tree base = gimple_assign_rhs1 (def_stmt);
4175 : 0 : HOST_WIDE_INT linear_step = 0;
4176 : 0 : tree v = gimple_assign_rhs2 (def_stmt);
4177 : 0 : while (TREE_CODE (v) == SSA_NAME)
4178 : : {
4179 : 0 : tree t;
4180 : 0 : def_stmt = SSA_NAME_DEF_STMT (v);
4181 : 0 : if (is_gimple_assign (def_stmt))
4182 : 0 : switch (gimple_assign_rhs_code (def_stmt))
4183 : : {
4184 : 0 : case PLUS_EXPR:
4185 : 0 : t = gimple_assign_rhs2 (def_stmt);
4186 : 0 : if (linear_step || TREE_CODE (t) != INTEGER_CST)
4187 : : return;
4188 : 0 : base = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, t);
4189 : 0 : v = gimple_assign_rhs1 (def_stmt);
4190 : 0 : continue;
4191 : 0 : case MULT_EXPR:
4192 : 0 : t = gimple_assign_rhs2 (def_stmt);
4193 : 0 : if (linear_step || !tree_fits_shwi_p (t) || integer_zerop (t))
4194 : 0 : return;
4195 : 0 : linear_step = tree_to_shwi (t);
4196 : 0 : v = gimple_assign_rhs1 (def_stmt);
4197 : 0 : continue;
4198 : 0 : CASE_CONVERT:
4199 : 0 : t = gimple_assign_rhs1 (def_stmt);
4200 : 0 : if (TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE
4201 : 0 : || (TYPE_PRECISION (TREE_TYPE (v))
4202 : 0 : < TYPE_PRECISION (TREE_TYPE (t))))
4203 : : return;
4204 : 0 : if (!linear_step)
4205 : 0 : linear_step = 1;
4206 : 0 : v = t;
4207 : 0 : continue;
4208 : : default:
4209 : : return;
4210 : : }
4211 : 0 : else if (gimple_call_internal_p (def_stmt, IFN_GOMP_SIMD_LANE)
4212 : 0 : && loop->simduid
4213 : 0 : && TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME
4214 : 0 : && (SSA_NAME_VAR (gimple_call_arg (def_stmt, 0))
4215 : : == loop->simduid))
4216 : : {
4217 : 0 : if (!linear_step)
4218 : 0 : linear_step = 1;
4219 : 0 : arginfo->linear_step = linear_step;
4220 : 0 : arginfo->op = base;
4221 : 0 : arginfo->simd_lane_linear = true;
4222 : 0 : return;
4223 : : }
4224 : : }
4225 : : }
4226 : :
4227 : : /* Function vectorizable_simd_clone_call.
4228 : :
4229 : : Check if STMT_INFO performs a function call that can be vectorized
4230 : : by calling a simd clone of the function.
4231 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
4232 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
4233 : : Return true if STMT_INFO is vectorizable in this way. */
4234 : :
4235 : : static bool
4236 : 2300492 : vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
4237 : : gimple_stmt_iterator *gsi,
4238 : : gimple **vec_stmt, slp_tree slp_node,
4239 : : stmt_vector_for_cost *)
4240 : : {
4241 : 2300492 : tree vec_dest;
4242 : 2300492 : tree scalar_dest;
4243 : 2300492 : tree op, type;
4244 : 2300492 : tree vec_oprnd0 = NULL_TREE;
4245 : 2300492 : tree vectype;
4246 : 2300492 : poly_uint64 nunits;
4247 : 2300492 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
4248 : 2300492 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
4249 : 2300492 : class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
4250 : 2300492 : tree fndecl, new_temp;
4251 : 2300492 : int ncopies, j;
4252 : 2300492 : auto_vec<simd_call_arg_info> arginfo;
4253 : 2300492 : vec<tree> vargs = vNULL;
4254 : 2300492 : size_t i, nargs;
4255 : 2300492 : tree lhs, rtype, ratype;
4256 : 2300492 : vec<constructor_elt, va_gc> *ret_ctor_elts = NULL;
4257 : 2300492 : int masked_call_offset = 0;
4258 : :
4259 : : /* Is STMT a vectorizable call? */
4260 : 2300492 : gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt);
4261 : 10026 : if (!stmt)
4262 : : return false;
4263 : :
4264 : 10026 : fndecl = gimple_call_fndecl (stmt);
4265 : 10026 : if (fndecl == NULL_TREE
4266 : 10026 : && gimple_call_internal_p (stmt, IFN_MASK_CALL))
4267 : : {
4268 : 173 : fndecl = gimple_call_arg (stmt, 0);
4269 : 173 : gcc_checking_assert (TREE_CODE (fndecl) == ADDR_EXPR);
4270 : 173 : fndecl = TREE_OPERAND (fndecl, 0);
4271 : 173 : gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
4272 : : masked_call_offset = 1;
4273 : : }
4274 : 9853 : if (fndecl == NULL_TREE)
4275 : : return false;
4276 : :
4277 : 4156 : struct cgraph_node *node = cgraph_node::get (fndecl);
4278 : 4156 : if (node == NULL || node->simd_clones == NULL)
4279 : : return false;
4280 : :
4281 : 1196 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
4282 : : return false;
4283 : :
4284 : 1196 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
4285 : 0 : && ! vec_stmt)
4286 : : return false;
4287 : :
4288 : 1196 : if (gimple_call_lhs (stmt)
4289 : 1196 : && TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME)
4290 : : return false;
4291 : :
4292 : 1196 : gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
4293 : :
4294 : 1196 : vectype = STMT_VINFO_VECTYPE (stmt_info);
4295 : :
4296 : 2300492 : if (loop_vinfo && nested_in_vect_loop_p (loop, stmt_info))
4297 : : return false;
4298 : :
4299 : : /* Process function arguments. */
4300 : 1196 : nargs = gimple_call_num_args (stmt) - masked_call_offset;
4301 : :
4302 : : /* Bail out if the function has zero arguments. */
4303 : 1196 : if (nargs == 0)
4304 : : return false;
4305 : :
4306 : 1196 : vec<tree>& simd_clone_info = (slp_node ? SLP_TREE_SIMD_CLONE_INFO (slp_node)
4307 : : : STMT_VINFO_SIMD_CLONE_INFO (stmt_info));
4308 : 1196 : if (!vec_stmt)
4309 : 882 : simd_clone_info.truncate (0);
4310 : 1196 : arginfo.reserve (nargs, true);
4311 : 1196 : auto_vec<slp_tree> slp_op;
4312 : 1196 : slp_op.safe_grow_cleared (nargs);
4313 : :
4314 : 3649 : for (i = 0; i < nargs; i++)
4315 : : {
4316 : 2453 : simd_call_arg_info thisarginfo;
4317 : 2453 : affine_iv iv;
4318 : :
4319 : 2453 : thisarginfo.linear_step = 0;
4320 : 2453 : thisarginfo.align = 0;
4321 : 2453 : thisarginfo.op = NULL_TREE;
4322 : 2453 : thisarginfo.simd_lane_linear = false;
4323 : :
4324 : 2453 : int op_no = i + masked_call_offset;
4325 : 2453 : if (slp_node)
4326 : 2453 : op_no = vect_slp_child_index_for_operand (stmt, op_no, false);
4327 : 4906 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
4328 : 2453 : op_no, &op, &slp_op[i],
4329 : : &thisarginfo.dt, &thisarginfo.vectype)
4330 : 2453 : || thisarginfo.dt == vect_uninitialized_def)
4331 : : {
4332 : 0 : if (dump_enabled_p ())
4333 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4334 : : "use not simple.\n");
4335 : 0 : return false;
4336 : : }
4337 : :
4338 : 2453 : if (thisarginfo.dt == vect_constant_def
4339 : 2453 : || thisarginfo.dt == vect_external_def)
4340 : : {
4341 : : /* With SLP we determine the vector type of constants/externals
4342 : : at analysis time, handling conflicts via
4343 : : vect_maybe_update_slp_op_vectype. At transform time
4344 : : we have a vector type recorded for SLP. */
4345 : 515 : gcc_assert (!vec_stmt
4346 : : || !slp_node
4347 : : || thisarginfo.vectype != NULL_TREE);
4348 : 515 : if (!vec_stmt)
4349 : 393 : thisarginfo.vectype = get_vectype_for_scalar_type (vinfo,
4350 : 393 : TREE_TYPE (op),
4351 : : slp_node);
4352 : : }
4353 : : else
4354 : 1938 : gcc_assert (thisarginfo.vectype != NULL_TREE);
4355 : :
4356 : : /* For linear arguments, the analyze phase should have saved
4357 : : the base and step in {STMT_VINFO,SLP_TREE}_SIMD_CLONE_INFO. */
4358 : 2331 : if (vec_stmt
4359 : 1398 : && i * 3 + 4 <= simd_clone_info.length ()
4360 : 2532 : && simd_clone_info[i * 3 + 2])
4361 : : {
4362 : 112 : thisarginfo.linear_step = tree_to_shwi (simd_clone_info[i * 3 + 2]);
4363 : 112 : thisarginfo.op = simd_clone_info[i * 3 + 1];
4364 : 112 : thisarginfo.simd_lane_linear
4365 : 112 : = (simd_clone_info[i * 3 + 3] == boolean_true_node);
4366 : : /* If loop has been peeled for alignment, we need to adjust it. */
4367 : 112 : tree n1 = LOOP_VINFO_NITERS_UNCHANGED (loop_vinfo);
4368 : 112 : tree n2 = LOOP_VINFO_NITERS (loop_vinfo);
4369 : 112 : if (n1 != n2 && !thisarginfo.simd_lane_linear)
4370 : : {
4371 : 0 : tree bias = fold_build2 (MINUS_EXPR, TREE_TYPE (n1), n1, n2);
4372 : 0 : tree step = simd_clone_info[i * 3 + 2];
4373 : 0 : tree opt = TREE_TYPE (thisarginfo.op);
4374 : 0 : bias = fold_convert (TREE_TYPE (step), bias);
4375 : 0 : bias = fold_build2 (MULT_EXPR, TREE_TYPE (step), bias, step);
4376 : 0 : thisarginfo.op
4377 : 0 : = fold_build2 (POINTER_TYPE_P (opt)
4378 : : ? POINTER_PLUS_EXPR : PLUS_EXPR, opt,
4379 : : thisarginfo.op, bias);
4380 : : }
4381 : : }
4382 : 2341 : else if (!vec_stmt
4383 : 1754 : && thisarginfo.dt != vect_constant_def
4384 : 1614 : && thisarginfo.dt != vect_external_def
4385 : 1361 : && loop_vinfo
4386 : 1358 : && TREE_CODE (op) == SSA_NAME
4387 : 2716 : && simple_iv (loop, loop_containing_stmt (stmt), op,
4388 : : &iv, false)
4389 : 2545 : && tree_fits_shwi_p (iv.step))
4390 : : {
4391 : 204 : thisarginfo.linear_step = tree_to_shwi (iv.step);
4392 : 204 : thisarginfo.op = iv.base;
4393 : : }
4394 : 2137 : else if ((thisarginfo.dt == vect_constant_def
4395 : 2137 : || thisarginfo.dt == vect_external_def)
4396 : 2137 : && POINTER_TYPE_P (TREE_TYPE (op)))
4397 : 287 : thisarginfo.align = get_pointer_alignment (op) / BITS_PER_UNIT;
4398 : : /* Addresses of array elements indexed by GOMP_SIMD_LANE are
4399 : : linear too. */
4400 : 4533 : if (POINTER_TYPE_P (TREE_TYPE (op))
4401 : 373 : && !thisarginfo.linear_step
4402 : 295 : && !vec_stmt
4403 : 247 : && thisarginfo.dt != vect_constant_def
4404 : 247 : && thisarginfo.dt != vect_external_def
4405 : 3 : && loop_vinfo
4406 : 2456 : && TREE_CODE (op) == SSA_NAME)
4407 : 3 : vect_simd_lane_linear (op, loop, &thisarginfo);
4408 : :
4409 : 2453 : arginfo.quick_push (thisarginfo);
4410 : : }
4411 : :
4412 : 1196 : poly_uint64 vf = loop_vinfo ? LOOP_VINFO_VECT_FACTOR (loop_vinfo) : 1;
4413 : 1196 : unsigned group_size = slp_node ? SLP_TREE_LANES (slp_node) : 1;
4414 : 1196 : unsigned int badness = 0;
4415 : 1196 : struct cgraph_node *bestn = NULL;
4416 : 1196 : if (vec_stmt)
4417 : 314 : bestn = cgraph_node::get (simd_clone_info[0]);
4418 : : else
4419 : 5216 : for (struct cgraph_node *n = node->simd_clones; n != NULL;
4420 : 4334 : n = n->simdclone->next_clone)
4421 : : {
4422 : 4334 : unsigned int this_badness = 0;
4423 : 4334 : unsigned int num_calls;
4424 : : /* The number of arguments in the call and the number of parameters in
4425 : : the simdclone should match. However, when the simdclone is
4426 : : 'inbranch', it could have one more paramater than nargs when using
4427 : : an inbranch simdclone to call a non-inbranch call, either in a
4428 : : non-masked loop using a all true constant mask, or inside a masked
4429 : : loop using it's mask. */
4430 : 4334 : size_t simd_nargs = n->simdclone->nargs;
4431 : 4334 : if (!masked_call_offset && n->simdclone->inbranch)
4432 : 1651 : simd_nargs--;
4433 : 4334 : if (!constant_multiple_p (vf * group_size, n->simdclone->simdlen,
4434 : : &num_calls)
4435 : 1958 : || (!n->simdclone->inbranch && (masked_call_offset > 0))
4436 : 1840 : || (nargs != simd_nargs))
4437 : 2494 : continue;
4438 : 1840 : if (num_calls != 1)
4439 : 1178 : this_badness += floor_log2 (num_calls) * 4096;
4440 : 1840 : if (n->simdclone->inbranch)
4441 : 737 : this_badness += 8192;
4442 : :
4443 : : /* If STMT_VINFO_VECTYPE has not been set yet pass the general vector
4444 : : mode, which for targets that use it will determine what ISA we can
4445 : : vectorize this code with. */
4446 : 1840 : machine_mode vector_mode = vinfo->vector_mode;
4447 : 1840 : if (vectype)
4448 : 1840 : vector_mode = TYPE_MODE (vectype);
4449 : 1840 : int target_badness = targetm.simd_clone.usable (n, vector_mode);
4450 : 1840 : if (target_badness < 0)
4451 : 387 : continue;
4452 : 1453 : this_badness += target_badness * 512;
4453 : 4381 : for (i = 0; i < nargs; i++)
4454 : : {
4455 : 3121 : switch (n->simdclone->args[i].arg_type)
4456 : : {
4457 : 2264 : case SIMD_CLONE_ARG_TYPE_VECTOR:
4458 : 2264 : if (!useless_type_conversion_p
4459 : 2264 : (n->simdclone->args[i].orig_type,
4460 : 2264 : TREE_TYPE (gimple_call_arg (stmt,
4461 : : i + masked_call_offset))))
4462 : : i = -1;
4463 : 2148 : else if (arginfo[i].dt == vect_constant_def
4464 : 2040 : || arginfo[i].dt == vect_external_def
4465 : 4124 : || arginfo[i].linear_step)
4466 : 359 : this_badness += 64;
4467 : : break;
4468 : 342 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
4469 : 342 : if (arginfo[i].dt != vect_constant_def
4470 : 342 : && arginfo[i].dt != vect_external_def)
4471 : : i = -1;
4472 : : break;
4473 : 312 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4474 : 312 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4475 : 312 : if (arginfo[i].dt == vect_constant_def
4476 : 312 : || arginfo[i].dt == vect_external_def
4477 : 312 : || (arginfo[i].linear_step
4478 : 312 : != n->simdclone->args[i].linear_step))
4479 : : i = -1;
4480 : : break;
4481 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
4482 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
4483 : : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
4484 : : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
4485 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
4486 : : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
4487 : : /* FORNOW */
4488 : : i = -1;
4489 : : break;
4490 : 203 : case SIMD_CLONE_ARG_TYPE_MASK:
4491 : : /* While we can create a traditional data vector from
4492 : : an incoming integer mode mask we have no good way to
4493 : : force generate an integer mode mask from a traditional
4494 : : boolean vector input. */
4495 : 203 : if (SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4496 : 203 : && !SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype)))
4497 : : i = -1;
4498 : 197 : else if (!SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4499 : 197 : && SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype)))
4500 : 45 : this_badness += 2048;
4501 : : break;
4502 : : }
4503 : 2928 : if (i == (size_t) -1)
4504 : : break;
4505 : 2928 : if (n->simdclone->args[i].alignment > arginfo[i].align)
4506 : : {
4507 : : i = -1;
4508 : : break;
4509 : : }
4510 : 2928 : if (arginfo[i].align)
4511 : 110 : this_badness += (exact_log2 (arginfo[i].align)
4512 : 160 : - exact_log2 (n->simdclone->args[i].alignment));
4513 : : }
4514 : 1453 : if (i == (size_t) -1)
4515 : 193 : continue;
4516 : 1260 : if (masked_call_offset == 0
4517 : 1063 : && n->simdclone->inbranch
4518 : 319 : && n->simdclone->nargs > nargs)
4519 : : {
4520 : 319 : gcc_assert (n->simdclone->args[n->simdclone->nargs - 1].arg_type ==
4521 : : SIMD_CLONE_ARG_TYPE_MASK);
4522 : : /* Penalize using a masked SIMD clone in a non-masked loop, that is
4523 : : not in a branch, as we'd have to construct an all-true mask. */
4524 : 319 : if (!loop_vinfo || !LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4525 : 319 : this_badness += 64;
4526 : : }
4527 : 1260 : if (bestn == NULL || this_badness < badness)
4528 : : {
4529 : 4334 : bestn = n;
4530 : 4334 : badness = this_badness;
4531 : : }
4532 : : }
4533 : :
4534 : 1196 : if (bestn == NULL)
4535 : : return false;
4536 : :
4537 : 813 : unsigned int num_mask_args = 0;
4538 : 813 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4539 : 111 : for (i = 0; i < nargs; i++)
4540 : 72 : if (bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
4541 : 18 : num_mask_args++;
4542 : :
4543 : 2621 : for (i = 0; i < nargs; i++)
4544 : : {
4545 : 1838 : if ((arginfo[i].dt == vect_constant_def
4546 : 1678 : || arginfo[i].dt == vect_external_def)
4547 : 1940 : && bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
4548 : : {
4549 : 69 : tree arg_type = TREE_TYPE (gimple_call_arg (stmt,
4550 : : i + masked_call_offset));
4551 : 69 : arginfo[i].vectype = get_vectype_for_scalar_type (vinfo, arg_type,
4552 : : slp_node);
4553 : 69 : if (arginfo[i].vectype == NULL
4554 : 138 : || !constant_multiple_p (bestn->simdclone->simdlen,
4555 : 138 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4556 : 0 : return false;
4557 : : }
4558 : :
4559 : 1838 : if (bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR
4560 : 1838 : && VECTOR_BOOLEAN_TYPE_P (bestn->simdclone->args[i].vector_type))
4561 : : {
4562 : 0 : if (dump_enabled_p ())
4563 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4564 : : "vector mask arguments are not supported.\n");
4565 : 0 : return false;
4566 : : }
4567 : :
4568 : 1838 : if (bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
4569 : : {
4570 : 123 : tree clone_arg_vectype = bestn->simdclone->args[i].vector_type;
4571 : 123 : if (bestn->simdclone->mask_mode == VOIDmode)
4572 : : {
4573 : 105 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (clone_arg_vectype),
4574 : 210 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4575 : : {
4576 : : /* FORNOW we only have partial support for vector-type masks
4577 : : that can't hold all of simdlen. */
4578 : 12 : if (dump_enabled_p ())
4579 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4580 : : vect_location,
4581 : : "in-branch vector clones are not yet"
4582 : : " supported for mismatched vector sizes.\n");
4583 : 12 : return false;
4584 : : }
4585 : 93 : if (!expand_vec_cond_expr_p (clone_arg_vectype,
4586 : 93 : arginfo[i].vectype))
4587 : : {
4588 : 6 : if (dump_enabled_p ())
4589 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4590 : : vect_location,
4591 : : "cannot compute mask argument for"
4592 : : " in-branch vector clones.\n");
4593 : 6 : return false;
4594 : : }
4595 : : }
4596 : 18 : else if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4597 : : {
4598 : 18 : if (!SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype))
4599 : 36 : || maybe_ne (exact_div (bestn->simdclone->simdlen,
4600 : : num_mask_args),
4601 : 24 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4602 : : {
4603 : : /* FORNOW we only have partial support for integer-type masks
4604 : : that represent the same number of lanes as the
4605 : : vectorized mask inputs. */
4606 : 12 : if (dump_enabled_p ())
4607 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4608 : : vect_location,
4609 : : "in-branch vector clones are not yet "
4610 : : "supported for mismatched vector sizes.\n");
4611 : 12 : return false;
4612 : : }
4613 : : }
4614 : : else
4615 : : {
4616 : 0 : if (dump_enabled_p ())
4617 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4618 : : vect_location,
4619 : : "in-branch vector clones not supported"
4620 : : " on this target.\n");
4621 : 0 : return false;
4622 : : }
4623 : : }
4624 : : }
4625 : :
4626 : 783 : fndecl = bestn->decl;
4627 : 783 : nunits = bestn->simdclone->simdlen;
4628 : 783 : if (slp_node)
4629 : 783 : ncopies = vector_unroll_factor (vf * group_size, nunits);
4630 : : else
4631 : 0 : ncopies = vector_unroll_factor (vf, nunits);
4632 : :
4633 : : /* If the function isn't const, only allow it in simd loops where user
4634 : : has asserted that at least nunits consecutive iterations can be
4635 : : performed using SIMD instructions. */
4636 : 781 : if ((loop == NULL || maybe_lt ((unsigned) loop->safelen, nunits))
4637 : 957 : && gimple_vuse (stmt))
4638 : : return false;
4639 : :
4640 : : /* Sanity check: make sure that at least one copy of the vectorized stmt
4641 : : needs to be generated. */
4642 : 783 : gcc_assert (ncopies >= 1);
4643 : :
4644 : 783 : if (!vec_stmt) /* transformation not required. */
4645 : : {
4646 : 469 : if (slp_node)
4647 : 1536 : for (unsigned i = 0; i < nargs; ++i)
4648 : 1067 : if (!vect_maybe_update_slp_op_vectype (slp_op[i], arginfo[i].vectype))
4649 : : {
4650 : 0 : if (dump_enabled_p ())
4651 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4652 : : "incompatible vector types for invariants\n");
4653 : 0 : return false;
4654 : : }
4655 : : /* When the original call is pure or const but the SIMD ABI dictates
4656 : : an aggregate return we will have to use a virtual definition and
4657 : : in a loop eventually even need to add a virtual PHI. That's
4658 : : not straight-forward so allow to fix this up via renaming. */
4659 : 469 : if (gimple_call_lhs (stmt)
4660 : 469 : && !gimple_vdef (stmt)
4661 : 836 : && TREE_CODE (TREE_TYPE (TREE_TYPE (bestn->decl))) == ARRAY_TYPE)
4662 : 33 : vinfo->any_known_not_updated_vssa = true;
4663 : : /* ??? For SLP code-gen we end up inserting after the last
4664 : : vector argument def rather than at the original call position
4665 : : so automagic virtual operand updating doesn't work. */
4666 : 938 : if (gimple_vuse (stmt) && slp_node)
4667 : 139 : vinfo->any_known_not_updated_vssa = true;
4668 : 469 : simd_clone_info.safe_push (bestn->decl);
4669 : 1547 : for (i = 0; i < bestn->simdclone->nargs; i++)
4670 : : {
4671 : 1078 : switch (bestn->simdclone->args[i].arg_type)
4672 : : {
4673 : 905 : default:
4674 : 905 : continue;
4675 : 112 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4676 : 112 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4677 : 112 : {
4678 : 112 : simd_clone_info.safe_grow_cleared (i * 3 + 1, true);
4679 : 112 : simd_clone_info.safe_push (arginfo[i].op);
4680 : 196 : tree lst = POINTER_TYPE_P (TREE_TYPE (arginfo[i].op))
4681 : 196 : ? size_type_node : TREE_TYPE (arginfo[i].op);
4682 : 112 : tree ls = build_int_cst (lst, arginfo[i].linear_step);
4683 : 112 : simd_clone_info.safe_push (ls);
4684 : 112 : tree sll = arginfo[i].simd_lane_linear
4685 : 112 : ? boolean_true_node : boolean_false_node;
4686 : 112 : simd_clone_info.safe_push (sll);
4687 : : }
4688 : 112 : break;
4689 : 61 : case SIMD_CLONE_ARG_TYPE_MASK:
4690 : 61 : if (loop_vinfo
4691 : 61 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
4692 : 0 : vect_record_loop_mask (loop_vinfo,
4693 : : &LOOP_VINFO_MASKS (loop_vinfo),
4694 : : ncopies, vectype, op);
4695 : :
4696 : : break;
4697 : 905 : }
4698 : : }
4699 : :
4700 : 469 : if (!bestn->simdclone->inbranch && loop_vinfo)
4701 : : {
4702 : 407 : if (dump_enabled_p ()
4703 : 407 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
4704 : 3 : dump_printf_loc (MSG_NOTE, vect_location,
4705 : : "can't use a fully-masked loop because a"
4706 : : " non-masked simd clone was selected.\n");
4707 : 407 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
4708 : : }
4709 : :
4710 : 469 : STMT_VINFO_TYPE (stmt_info) = call_simd_clone_vec_info_type;
4711 : 469 : DUMP_VECT_SCOPE ("vectorizable_simd_clone_call");
4712 : : /* vect_model_simple_cost (vinfo, stmt_info, ncopies,
4713 : : dt, slp_node, cost_vec); */
4714 : 469 : return true;
4715 : : }
4716 : :
4717 : : /* Transform. */
4718 : :
4719 : 314 : if (dump_enabled_p ())
4720 : 210 : dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n");
4721 : :
4722 : : /* Handle def. */
4723 : 314 : scalar_dest = gimple_call_lhs (stmt);
4724 : 314 : vec_dest = NULL_TREE;
4725 : 314 : rtype = NULL_TREE;
4726 : 314 : ratype = NULL_TREE;
4727 : 314 : if (scalar_dest)
4728 : : {
4729 : 314 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
4730 : 314 : rtype = TREE_TYPE (TREE_TYPE (fndecl));
4731 : 314 : if (TREE_CODE (rtype) == ARRAY_TYPE)
4732 : : {
4733 : 9 : ratype = rtype;
4734 : 9 : rtype = TREE_TYPE (ratype);
4735 : : }
4736 : : }
4737 : :
4738 : 628 : auto_vec<vec<tree> > vec_oprnds;
4739 : 314 : auto_vec<unsigned> vec_oprnds_i;
4740 : 314 : vec_oprnds_i.safe_grow_cleared (nargs, true);
4741 : 314 : if (slp_node)
4742 : : {
4743 : 314 : vec_oprnds.reserve_exact (nargs);
4744 : 314 : vect_get_slp_defs (vinfo, slp_node, &vec_oprnds);
4745 : : }
4746 : : else
4747 : 0 : vec_oprnds.safe_grow_cleared (nargs, true);
4748 : 732 : for (j = 0; j < ncopies; ++j)
4749 : : {
4750 : 418 : poly_uint64 callee_nelements;
4751 : 418 : poly_uint64 caller_nelements;
4752 : : /* Build argument list for the vectorized call. */
4753 : 418 : if (j == 0)
4754 : 314 : vargs.create (nargs);
4755 : : else
4756 : 104 : vargs.truncate (0);
4757 : :
4758 : 1412 : for (i = 0; i < nargs; i++)
4759 : : {
4760 : 994 : unsigned int k, l, m, o;
4761 : 994 : tree atype;
4762 : 994 : op = gimple_call_arg (stmt, i + masked_call_offset);
4763 : 994 : switch (bestn->simdclone->args[i].arg_type)
4764 : : {
4765 : 742 : case SIMD_CLONE_ARG_TYPE_VECTOR:
4766 : 742 : atype = bestn->simdclone->args[i].vector_type;
4767 : 742 : caller_nelements = TYPE_VECTOR_SUBPARTS (arginfo[i].vectype);
4768 : 742 : callee_nelements = TYPE_VECTOR_SUBPARTS (atype);
4769 : 742 : o = vector_unroll_factor (nunits, callee_nelements);
4770 : 1660 : for (m = j * o; m < (j + 1) * o; m++)
4771 : : {
4772 : 918 : if (known_lt (callee_nelements, caller_nelements))
4773 : : {
4774 : 348 : poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (atype));
4775 : 174 : if (!constant_multiple_p (caller_nelements,
4776 : : callee_nelements, &k))
4777 : 0 : gcc_unreachable ();
4778 : :
4779 : 174 : gcc_assert ((k & (k - 1)) == 0);
4780 : 174 : if (m == 0)
4781 : : {
4782 : 39 : if (!slp_node)
4783 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
4784 : 0 : ncopies * o / k, op,
4785 : 0 : &vec_oprnds[i]);
4786 : 39 : vec_oprnds_i[i] = 0;
4787 : 39 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4788 : : }
4789 : : else
4790 : : {
4791 : 135 : vec_oprnd0 = arginfo[i].op;
4792 : 135 : if ((m & (k - 1)) == 0)
4793 : 48 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4794 : : }
4795 : 174 : arginfo[i].op = vec_oprnd0;
4796 : 174 : vec_oprnd0
4797 : 174 : = build3 (BIT_FIELD_REF, atype, vec_oprnd0,
4798 : 174 : bitsize_int (prec),
4799 : 174 : bitsize_int ((m & (k - 1)) * prec));
4800 : 174 : gassign *new_stmt
4801 : 174 : = gimple_build_assign (make_ssa_name (atype),
4802 : : vec_oprnd0);
4803 : 174 : vect_finish_stmt_generation (vinfo, stmt_info,
4804 : : new_stmt, gsi);
4805 : 174 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4806 : : }
4807 : : else
4808 : : {
4809 : 744 : if (!constant_multiple_p (callee_nelements,
4810 : : caller_nelements, &k))
4811 : 0 : gcc_unreachable ();
4812 : 744 : gcc_assert ((k & (k - 1)) == 0);
4813 : 744 : vec<constructor_elt, va_gc> *ctor_elts;
4814 : 744 : if (k != 1)
4815 : 14 : vec_alloc (ctor_elts, k);
4816 : : else
4817 : 730 : ctor_elts = NULL;
4818 : 772 : for (l = 0; l < k; l++)
4819 : : {
4820 : 758 : if (m == 0 && l == 0)
4821 : : {
4822 : 411 : if (!slp_node)
4823 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
4824 : 0 : k * o * ncopies,
4825 : : op,
4826 : 0 : &vec_oprnds[i]);
4827 : 411 : vec_oprnds_i[i] = 0;
4828 : 411 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4829 : : }
4830 : : else
4831 : 347 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4832 : 758 : arginfo[i].op = vec_oprnd0;
4833 : 758 : if (k == 1)
4834 : : break;
4835 : 28 : CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE,
4836 : : vec_oprnd0);
4837 : : }
4838 : 744 : if (k == 1)
4839 : 730 : if (!useless_type_conversion_p (TREE_TYPE (vec_oprnd0),
4840 : : atype))
4841 : : {
4842 : 0 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, atype,
4843 : : vec_oprnd0);
4844 : 0 : gassign *new_stmt
4845 : 0 : = gimple_build_assign (make_ssa_name (atype),
4846 : : vec_oprnd0);
4847 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
4848 : : new_stmt, gsi);
4849 : 0 : vargs.safe_push (gimple_get_lhs (new_stmt));
4850 : : }
4851 : : else
4852 : 730 : vargs.safe_push (vec_oprnd0);
4853 : : else
4854 : : {
4855 : 14 : vec_oprnd0 = build_constructor (atype, ctor_elts);
4856 : 14 : gassign *new_stmt
4857 : 14 : = gimple_build_assign (make_ssa_name (atype),
4858 : : vec_oprnd0);
4859 : 14 : vect_finish_stmt_generation (vinfo, stmt_info,
4860 : : new_stmt, gsi);
4861 : 14 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4862 : : }
4863 : : }
4864 : : }
4865 : : break;
4866 : 43 : case SIMD_CLONE_ARG_TYPE_MASK:
4867 : 43 : if (bestn->simdclone->mask_mode == VOIDmode)
4868 : : {
4869 : 40 : atype = bestn->simdclone->args[i].vector_type;
4870 : 40 : tree elt_type = TREE_TYPE (atype);
4871 : 40 : tree one = fold_convert (elt_type, integer_one_node);
4872 : 40 : tree zero = fold_convert (elt_type, integer_zero_node);
4873 : 40 : callee_nelements = TYPE_VECTOR_SUBPARTS (atype);
4874 : 40 : caller_nelements = TYPE_VECTOR_SUBPARTS (arginfo[i].vectype);
4875 : 40 : o = vector_unroll_factor (nunits, callee_nelements);
4876 : 80 : for (m = j * o; m < (j + 1) * o; m++)
4877 : : {
4878 : 40 : if (maybe_lt (callee_nelements, caller_nelements))
4879 : : {
4880 : : /* The mask type has fewer elements than simdlen. */
4881 : :
4882 : : /* FORNOW */
4883 : 0 : gcc_unreachable ();
4884 : : }
4885 : 40 : else if (known_eq (callee_nelements, caller_nelements))
4886 : : {
4887 : : /* The SIMD clone function has the same number of
4888 : : elements as the current function. */
4889 : 40 : if (m == 0)
4890 : : {
4891 : 40 : if (!slp_node)
4892 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
4893 : 0 : o * ncopies,
4894 : : op,
4895 : 0 : &vec_oprnds[i]);
4896 : 40 : vec_oprnds_i[i] = 0;
4897 : : }
4898 : 40 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4899 : 40 : if (loop_vinfo
4900 : 40 : && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4901 : : {
4902 : 0 : vec_loop_masks *loop_masks
4903 : : = &LOOP_VINFO_MASKS (loop_vinfo);
4904 : 0 : tree loop_mask
4905 : 0 : = vect_get_loop_mask (loop_vinfo, gsi,
4906 : : loop_masks, ncopies,
4907 : 0 : vectype, j);
4908 : 0 : vec_oprnd0
4909 : 0 : = prepare_vec_mask (loop_vinfo,
4910 : 0 : TREE_TYPE (loop_mask),
4911 : : loop_mask, vec_oprnd0,
4912 : : gsi);
4913 : 0 : loop_vinfo->vec_cond_masked_set.add ({ vec_oprnd0,
4914 : : loop_mask });
4915 : :
4916 : : }
4917 : 40 : vec_oprnd0
4918 : 40 : = build3 (VEC_COND_EXPR, atype, vec_oprnd0,
4919 : : build_vector_from_val (atype, one),
4920 : : build_vector_from_val (atype, zero));
4921 : 40 : gassign *new_stmt
4922 : 40 : = gimple_build_assign (make_ssa_name (atype),
4923 : : vec_oprnd0);
4924 : 40 : vect_finish_stmt_generation (vinfo, stmt_info,
4925 : : new_stmt, gsi);
4926 : 40 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4927 : : }
4928 : : else
4929 : : {
4930 : : /* The mask type has more elements than simdlen. */
4931 : :
4932 : : /* FORNOW */
4933 : 0 : gcc_unreachable ();
4934 : : }
4935 : : }
4936 : : }
4937 : 3 : else if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4938 : : {
4939 : 3 : atype = bestn->simdclone->args[i].vector_type;
4940 : : /* Guess the number of lanes represented by atype. */
4941 : 3 : poly_uint64 atype_subparts
4942 : 3 : = exact_div (bestn->simdclone->simdlen,
4943 : : num_mask_args);
4944 : 3 : o = vector_unroll_factor (nunits, atype_subparts);
4945 : 6 : for (m = j * o; m < (j + 1) * o; m++)
4946 : : {
4947 : 3 : if (m == 0)
4948 : : {
4949 : 3 : if (!slp_node)
4950 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
4951 : 0 : o * ncopies,
4952 : : op,
4953 : 0 : &vec_oprnds[i]);
4954 : 3 : vec_oprnds_i[i] = 0;
4955 : : }
4956 : 3 : if (maybe_lt (atype_subparts,
4957 : 3 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4958 : : {
4959 : : /* The mask argument has fewer elements than the
4960 : : input vector. */
4961 : : /* FORNOW */
4962 : 0 : gcc_unreachable ();
4963 : : }
4964 : 3 : else if (known_eq (atype_subparts,
4965 : : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4966 : : {
4967 : : /* The vector mask argument matches the input
4968 : : in the number of lanes, but not necessarily
4969 : : in the mode. */
4970 : 3 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4971 : 3 : tree st = lang_hooks.types.type_for_mode
4972 : 3 : (TYPE_MODE (TREE_TYPE (vec_oprnd0)), 1);
4973 : 3 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, st,
4974 : : vec_oprnd0);
4975 : 3 : gassign *new_stmt
4976 : 3 : = gimple_build_assign (make_ssa_name (st),
4977 : : vec_oprnd0);
4978 : 3 : vect_finish_stmt_generation (vinfo, stmt_info,
4979 : : new_stmt, gsi);
4980 : 3 : if (!types_compatible_p (atype, st))
4981 : : {
4982 : 3 : new_stmt
4983 : 3 : = gimple_build_assign (make_ssa_name (atype),
4984 : : NOP_EXPR,
4985 : : gimple_assign_lhs
4986 : : (new_stmt));
4987 : 3 : vect_finish_stmt_generation (vinfo, stmt_info,
4988 : : new_stmt, gsi);
4989 : : }
4990 : 3 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4991 : : }
4992 : : else
4993 : : {
4994 : : /* The mask argument has more elements than the
4995 : : input vector. */
4996 : : /* FORNOW */
4997 : 0 : gcc_unreachable ();
4998 : : }
4999 : : }
5000 : : }
5001 : : else
5002 : 0 : gcc_unreachable ();
5003 : : break;
5004 : 94 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
5005 : 94 : vargs.safe_push (op);
5006 : 94 : break;
5007 : 115 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
5008 : 115 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
5009 : 115 : if (j == 0)
5010 : : {
5011 : 112 : gimple_seq stmts;
5012 : 112 : arginfo[i].op
5013 : 112 : = force_gimple_operand (unshare_expr (arginfo[i].op),
5014 : : &stmts, true, NULL_TREE);
5015 : 112 : if (stmts != NULL)
5016 : : {
5017 : 0 : basic_block new_bb;
5018 : 0 : edge pe = loop_preheader_edge (loop);
5019 : 0 : new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
5020 : 0 : gcc_assert (!new_bb);
5021 : : }
5022 : 112 : if (arginfo[i].simd_lane_linear)
5023 : : {
5024 : 0 : vargs.safe_push (arginfo[i].op);
5025 : 0 : break;
5026 : : }
5027 : 112 : tree phi_res = copy_ssa_name (op);
5028 : 112 : gphi *new_phi = create_phi_node (phi_res, loop->header);
5029 : 112 : add_phi_arg (new_phi, arginfo[i].op,
5030 : : loop_preheader_edge (loop), UNKNOWN_LOCATION);
5031 : 112 : enum tree_code code
5032 : 196 : = POINTER_TYPE_P (TREE_TYPE (op))
5033 : 112 : ? POINTER_PLUS_EXPR : PLUS_EXPR;
5034 : 196 : tree type = POINTER_TYPE_P (TREE_TYPE (op))
5035 : 196 : ? sizetype : TREE_TYPE (op);
5036 : 112 : poly_widest_int cst
5037 : 112 : = wi::mul (bestn->simdclone->args[i].linear_step,
5038 : 112 : ncopies * nunits);
5039 : 112 : tree tcst = wide_int_to_tree (type, cst);
5040 : 112 : tree phi_arg = copy_ssa_name (op);
5041 : 112 : gassign *new_stmt
5042 : 112 : = gimple_build_assign (phi_arg, code, phi_res, tcst);
5043 : 112 : gimple_stmt_iterator si = gsi_after_labels (loop->header);
5044 : 112 : gsi_insert_after (&si, new_stmt, GSI_NEW_STMT);
5045 : 112 : add_phi_arg (new_phi, phi_arg, loop_latch_edge (loop),
5046 : : UNKNOWN_LOCATION);
5047 : 112 : arginfo[i].op = phi_res;
5048 : 112 : vargs.safe_push (phi_res);
5049 : 112 : }
5050 : : else
5051 : : {
5052 : 3 : enum tree_code code
5053 : 6 : = POINTER_TYPE_P (TREE_TYPE (op))
5054 : 3 : ? POINTER_PLUS_EXPR : PLUS_EXPR;
5055 : 6 : tree type = POINTER_TYPE_P (TREE_TYPE (op))
5056 : 6 : ? sizetype : TREE_TYPE (op);
5057 : 3 : poly_widest_int cst
5058 : 3 : = wi::mul (bestn->simdclone->args[i].linear_step,
5059 : 3 : j * nunits);
5060 : 3 : tree tcst = wide_int_to_tree (type, cst);
5061 : 3 : new_temp = make_ssa_name (TREE_TYPE (op));
5062 : 3 : gassign *new_stmt
5063 : 6 : = gimple_build_assign (new_temp, code,
5064 : 3 : arginfo[i].op, tcst);
5065 : 3 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5066 : 3 : vargs.safe_push (new_temp);
5067 : 3 : }
5068 : : break;
5069 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
5070 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
5071 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
5072 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
5073 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
5074 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
5075 : 0 : default:
5076 : 0 : gcc_unreachable ();
5077 : : }
5078 : : }
5079 : :
5080 : 418 : if (masked_call_offset == 0
5081 : 375 : && bestn->simdclone->inbranch
5082 : 7 : && bestn->simdclone->nargs > nargs)
5083 : : {
5084 : 7 : unsigned long m, o;
5085 : 7 : size_t mask_i = bestn->simdclone->nargs - 1;
5086 : 7 : tree mask;
5087 : 7 : gcc_assert (bestn->simdclone->args[mask_i].arg_type ==
5088 : : SIMD_CLONE_ARG_TYPE_MASK);
5089 : :
5090 : 7 : tree masktype = bestn->simdclone->args[mask_i].vector_type;
5091 : 7 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
5092 : : /* Guess the number of lanes represented by masktype. */
5093 : 1 : callee_nelements = exact_div (bestn->simdclone->simdlen,
5094 : 1 : bestn->simdclone->nargs - nargs);
5095 : : else
5096 : 6 : callee_nelements = TYPE_VECTOR_SUBPARTS (masktype);
5097 : 7 : o = vector_unroll_factor (nunits, callee_nelements);
5098 : 14 : for (m = j * o; m < (j + 1) * o; m++)
5099 : : {
5100 : 7 : if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
5101 : : {
5102 : 0 : vec_loop_masks *loop_masks = &LOOP_VINFO_MASKS (loop_vinfo);
5103 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
5104 : : ncopies, masktype, j);
5105 : : }
5106 : : else
5107 : 7 : mask = vect_build_all_ones_mask (vinfo, stmt_info, masktype);
5108 : :
5109 : 7 : gassign *new_stmt;
5110 : 7 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
5111 : : {
5112 : : /* This means we are dealing with integer mask modes.
5113 : : First convert to an integer type with the same size as
5114 : : the current vector type. */
5115 : 1 : unsigned HOST_WIDE_INT intermediate_size
5116 : 1 : = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (mask)));
5117 : 1 : tree mid_int_type =
5118 : 1 : build_nonstandard_integer_type (intermediate_size, 1);
5119 : 1 : mask = build1 (VIEW_CONVERT_EXPR, mid_int_type, mask);
5120 : 1 : new_stmt
5121 : 1 : = gimple_build_assign (make_ssa_name (mid_int_type),
5122 : : mask);
5123 : 1 : gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
5124 : : /* Then zero-extend to the mask mode. */
5125 : 1 : mask = fold_build1 (NOP_EXPR, masktype,
5126 : : gimple_get_lhs (new_stmt));
5127 : : }
5128 : 6 : else if (bestn->simdclone->mask_mode == VOIDmode)
5129 : : {
5130 : 6 : tree one = fold_convert (TREE_TYPE (masktype),
5131 : : integer_one_node);
5132 : 6 : tree zero = fold_convert (TREE_TYPE (masktype),
5133 : : integer_zero_node);
5134 : 6 : mask = build3 (VEC_COND_EXPR, masktype, mask,
5135 : : build_vector_from_val (masktype, one),
5136 : : build_vector_from_val (masktype, zero));
5137 : : }
5138 : : else
5139 : 0 : gcc_unreachable ();
5140 : :
5141 : 7 : new_stmt = gimple_build_assign (make_ssa_name (masktype), mask);
5142 : 7 : vect_finish_stmt_generation (vinfo, stmt_info,
5143 : : new_stmt, gsi);
5144 : 7 : mask = gimple_assign_lhs (new_stmt);
5145 : 7 : vargs.safe_push (mask);
5146 : : }
5147 : : }
5148 : :
5149 : 418 : gcall *new_call = gimple_build_call_vec (fndecl, vargs);
5150 : 418 : if (vec_dest)
5151 : : {
5152 : 418 : gcc_assert (ratype
5153 : : || known_eq (TYPE_VECTOR_SUBPARTS (rtype), nunits));
5154 : 418 : if (ratype)
5155 : 15 : new_temp = create_tmp_var (ratype);
5156 : 403 : else if (useless_type_conversion_p (vectype, rtype))
5157 : 393 : new_temp = make_ssa_name (vec_dest, new_call);
5158 : : else
5159 : 10 : new_temp = make_ssa_name (rtype, new_call);
5160 : 418 : gimple_call_set_lhs (new_call, new_temp);
5161 : : }
5162 : 418 : vect_finish_stmt_generation (vinfo, stmt_info, new_call, gsi);
5163 : 418 : gimple *new_stmt = new_call;
5164 : :
5165 : 418 : if (vec_dest)
5166 : : {
5167 : 418 : if (!multiple_p (TYPE_VECTOR_SUBPARTS (vectype), nunits))
5168 : : {
5169 : 21 : unsigned int k, l;
5170 : 42 : poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (vectype));
5171 : 42 : poly_uint64 bytes = GET_MODE_SIZE (TYPE_MODE (vectype));
5172 : 21 : k = vector_unroll_factor (nunits,
5173 : : TYPE_VECTOR_SUBPARTS (vectype));
5174 : 21 : gcc_assert ((k & (k - 1)) == 0);
5175 : 75 : for (l = 0; l < k; l++)
5176 : : {
5177 : 54 : tree t;
5178 : 54 : if (ratype)
5179 : : {
5180 : 42 : t = build_fold_addr_expr (new_temp);
5181 : 42 : t = build2 (MEM_REF, vectype, t,
5182 : 42 : build_int_cst (TREE_TYPE (t), l * bytes));
5183 : : }
5184 : : else
5185 : 12 : t = build3 (BIT_FIELD_REF, vectype, new_temp,
5186 : 12 : bitsize_int (prec), bitsize_int (l * prec));
5187 : 54 : new_stmt = gimple_build_assign (make_ssa_name (vectype), t);
5188 : 54 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5189 : :
5190 : 54 : if (j == 0 && l == 0)
5191 : 15 : *vec_stmt = new_stmt;
5192 : 54 : if (slp_node)
5193 : 54 : SLP_TREE_VEC_DEFS (slp_node)
5194 : 54 : .quick_push (gimple_assign_lhs (new_stmt));
5195 : : else
5196 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
5197 : : }
5198 : :
5199 : 21 : if (ratype)
5200 : 15 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
5201 : 21 : continue;
5202 : 21 : }
5203 : 397 : else if (!multiple_p (nunits, TYPE_VECTOR_SUBPARTS (vectype)))
5204 : : {
5205 : 4 : unsigned int k;
5206 : 4 : if (!constant_multiple_p (TYPE_VECTOR_SUBPARTS (vectype),
5207 : 4 : TYPE_VECTOR_SUBPARTS (rtype), &k))
5208 : 0 : gcc_unreachable ();
5209 : 4 : gcc_assert ((k & (k - 1)) == 0);
5210 : 4 : if ((j & (k - 1)) == 0)
5211 : 2 : vec_alloc (ret_ctor_elts, k);
5212 : 4 : if (ratype)
5213 : : {
5214 : 0 : unsigned int m, o;
5215 : 0 : o = vector_unroll_factor (nunits,
5216 : : TYPE_VECTOR_SUBPARTS (rtype));
5217 : 0 : for (m = 0; m < o; m++)
5218 : : {
5219 : 0 : tree tem = build4 (ARRAY_REF, rtype, new_temp,
5220 : 0 : size_int (m), NULL_TREE, NULL_TREE);
5221 : 0 : new_stmt = gimple_build_assign (make_ssa_name (rtype),
5222 : : tem);
5223 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
5224 : : new_stmt, gsi);
5225 : 0 : CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE,
5226 : : gimple_assign_lhs (new_stmt));
5227 : : }
5228 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
5229 : : }
5230 : : else
5231 : 4 : CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE, new_temp);
5232 : 4 : if ((j & (k - 1)) != k - 1)
5233 : 2 : continue;
5234 : 2 : vec_oprnd0 = build_constructor (vectype, ret_ctor_elts);
5235 : 2 : new_stmt
5236 : 2 : = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0);
5237 : 2 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5238 : :
5239 : 2 : if ((unsigned) j == k - 1)
5240 : 2 : *vec_stmt = new_stmt;
5241 : 2 : if (slp_node)
5242 : 2 : SLP_TREE_VEC_DEFS (slp_node)
5243 : 2 : .quick_push (gimple_assign_lhs (new_stmt));
5244 : : else
5245 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
5246 : 2 : continue;
5247 : 2 : }
5248 : 393 : else if (ratype)
5249 : : {
5250 : 0 : tree t = build_fold_addr_expr (new_temp);
5251 : 0 : t = build2 (MEM_REF, vectype, t,
5252 : 0 : build_int_cst (TREE_TYPE (t), 0));
5253 : 0 : new_stmt = gimple_build_assign (make_ssa_name (vec_dest), t);
5254 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5255 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
5256 : : }
5257 : 393 : else if (!useless_type_conversion_p (vectype, rtype))
5258 : : {
5259 : 0 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, vectype, new_temp);
5260 : 0 : new_stmt
5261 : 0 : = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0);
5262 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5263 : : }
5264 : : }
5265 : :
5266 : 393 : if (j == 0)
5267 : 297 : *vec_stmt = new_stmt;
5268 : 393 : if (slp_node)
5269 : 393 : SLP_TREE_VEC_DEFS (slp_node).quick_push (gimple_get_lhs (new_stmt));
5270 : : else
5271 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
5272 : : }
5273 : :
5274 : 1013 : for (i = 0; i < nargs; ++i)
5275 : : {
5276 : 699 : vec<tree> oprndsi = vec_oprnds[i];
5277 : 699 : oprndsi.release ();
5278 : : }
5279 : 314 : vargs.release ();
5280 : :
5281 : : /* Mark the clone as no longer being a candidate for GC. */
5282 : 314 : bestn->gc_candidate = false;
5283 : :
5284 : : /* The call in STMT might prevent it from being removed in dce.
5285 : : We however cannot remove it here, due to the way the ssa name
5286 : : it defines is mapped to the new definition. So just replace
5287 : : rhs of the statement with something harmless. */
5288 : :
5289 : 314 : if (slp_node)
5290 : : return true;
5291 : :
5292 : 0 : gimple *new_stmt;
5293 : 0 : if (scalar_dest)
5294 : : {
5295 : 0 : type = TREE_TYPE (scalar_dest);
5296 : 0 : lhs = gimple_call_lhs (vect_orig_stmt (stmt_info)->stmt);
5297 : 0 : new_stmt = gimple_build_assign (lhs, build_zero_cst (type));
5298 : : }
5299 : : else
5300 : 0 : new_stmt = gimple_build_nop ();
5301 : 0 : vinfo->replace_stmt (gsi, vect_orig_stmt (stmt_info), new_stmt);
5302 : 0 : unlink_stmt_vdef (stmt);
5303 : :
5304 : 0 : return true;
5305 : 1196 : }
5306 : :
5307 : :
5308 : : /* Function vect_gen_widened_results_half
5309 : :
5310 : : Create a vector stmt whose code, type, number of arguments, and result
5311 : : variable are CODE, OP_TYPE, and VEC_DEST, and its arguments are
5312 : : VEC_OPRND0 and VEC_OPRND1. The new vector stmt is to be inserted at GSI.
5313 : : In the case that CODE is a CALL_EXPR, this means that a call to DECL
5314 : : needs to be created (DECL is a function-decl of a target-builtin).
5315 : : STMT_INFO is the original scalar stmt that we are vectorizing. */
5316 : :
5317 : : static gimple *
5318 : 21516 : vect_gen_widened_results_half (vec_info *vinfo, code_helper ch,
5319 : : tree vec_oprnd0, tree vec_oprnd1, int op_type,
5320 : : tree vec_dest, gimple_stmt_iterator *gsi,
5321 : : stmt_vec_info stmt_info)
5322 : : {
5323 : 21516 : gimple *new_stmt;
5324 : 21516 : tree new_temp;
5325 : :
5326 : : /* Generate half of the widened result: */
5327 : 21516 : if (op_type != binary_op)
5328 : 20522 : vec_oprnd1 = NULL;
5329 : 21516 : new_stmt = vect_gimple_build (vec_dest, ch, vec_oprnd0, vec_oprnd1);
5330 : 21516 : new_temp = make_ssa_name (vec_dest, new_stmt);
5331 : 21516 : gimple_set_lhs (new_stmt, new_temp);
5332 : 21516 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5333 : :
5334 : 21516 : return new_stmt;
5335 : : }
5336 : :
5337 : :
5338 : : /* Create vectorized demotion statements for vector operands from VEC_OPRNDS.
5339 : : For multi-step conversions store the resulting vectors and call the function
5340 : : recursively. When NARROW_SRC_P is true, there's still a conversion after
5341 : : narrowing, don't store the vectors in the SLP_NODE or in vector info of
5342 : : the scalar statement(or in STMT_VINFO_RELATED_STMT chain). */
5343 : :
5344 : : static void
5345 : 9416 : vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
5346 : : int multi_step_cvt,
5347 : : stmt_vec_info stmt_info,
5348 : : vec<tree> &vec_dsts,
5349 : : gimple_stmt_iterator *gsi,
5350 : : slp_tree slp_node, code_helper code,
5351 : : bool narrow_src_p)
5352 : : {
5353 : 9416 : unsigned int i;
5354 : 9416 : tree vop0, vop1, new_tmp, vec_dest;
5355 : :
5356 : 9416 : vec_dest = vec_dsts.pop ();
5357 : :
5358 : 21849 : for (i = 0; i < vec_oprnds->length (); i += 2)
5359 : : {
5360 : : /* Create demotion operation. */
5361 : 12433 : vop0 = (*vec_oprnds)[i];
5362 : 12433 : vop1 = (*vec_oprnds)[i + 1];
5363 : 12433 : gimple *new_stmt = vect_gimple_build (vec_dest, code, vop0, vop1);
5364 : 12433 : new_tmp = make_ssa_name (vec_dest, new_stmt);
5365 : 12433 : gimple_set_lhs (new_stmt, new_tmp);
5366 : 12433 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5367 : 12433 : if (multi_step_cvt || narrow_src_p)
5368 : : /* Store the resulting vector for next recursive call,
5369 : : or return the resulting vector_tmp for NARROW FLOAT_EXPR. */
5370 : 4563 : (*vec_oprnds)[i/2] = new_tmp;
5371 : : else
5372 : : {
5373 : : /* This is the last step of the conversion sequence. Store the
5374 : : vectors in SLP_NODE or in vector info of the scalar statement
5375 : : (or in STMT_VINFO_RELATED_STMT chain). */
5376 : 7870 : if (slp_node)
5377 : 7870 : slp_node->push_vec_def (new_stmt);
5378 : : else
5379 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
5380 : : }
5381 : : }
5382 : :
5383 : : /* For multi-step demotion operations we first generate demotion operations
5384 : : from the source type to the intermediate types, and then combine the
5385 : : results (stored in VEC_OPRNDS) in demotion operation to the destination
5386 : : type. */
5387 : 9416 : if (multi_step_cvt)
5388 : : {
5389 : : /* At each level of recursion we have half of the operands we had at the
5390 : : previous level. */
5391 : 2084 : vec_oprnds->truncate ((i+1)/2);
5392 : 2084 : vect_create_vectorized_demotion_stmts (vinfo, vec_oprnds,
5393 : : multi_step_cvt - 1,
5394 : : stmt_info, vec_dsts, gsi,
5395 : : slp_node, VEC_PACK_TRUNC_EXPR,
5396 : : narrow_src_p);
5397 : : }
5398 : :
5399 : 9416 : vec_dsts.quick_push (vec_dest);
5400 : 9416 : }
5401 : :
5402 : :
5403 : : /* Create vectorized promotion statements for vector operands from VEC_OPRNDS0
5404 : : and VEC_OPRNDS1, for a binary operation associated with scalar statement
5405 : : STMT_INFO. For multi-step conversions store the resulting vectors and
5406 : : call the function recursively. */
5407 : :
5408 : : static void
5409 : 8420 : vect_create_vectorized_promotion_stmts (vec_info *vinfo,
5410 : : vec<tree> *vec_oprnds0,
5411 : : vec<tree> *vec_oprnds1,
5412 : : stmt_vec_info stmt_info, tree vec_dest,
5413 : : gimple_stmt_iterator *gsi,
5414 : : code_helper ch1,
5415 : : code_helper ch2, int op_type)
5416 : : {
5417 : 8420 : int i;
5418 : 8420 : tree vop0, vop1, new_tmp1, new_tmp2;
5419 : 8420 : gimple *new_stmt1, *new_stmt2;
5420 : 8420 : vec<tree> vec_tmp = vNULL;
5421 : :
5422 : 8420 : vec_tmp.create (vec_oprnds0->length () * 2);
5423 : 27598 : FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0)
5424 : : {
5425 : 10758 : if (op_type == binary_op)
5426 : 497 : vop1 = (*vec_oprnds1)[i];
5427 : : else
5428 : : vop1 = NULL_TREE;
5429 : :
5430 : : /* Generate the two halves of promotion operation. */
5431 : 10758 : new_stmt1 = vect_gen_widened_results_half (vinfo, ch1, vop0, vop1,
5432 : : op_type, vec_dest, gsi,
5433 : : stmt_info);
5434 : 10758 : new_stmt2 = vect_gen_widened_results_half (vinfo, ch2, vop0, vop1,
5435 : : op_type, vec_dest, gsi,
5436 : : stmt_info);
5437 : 10758 : if (is_gimple_call (new_stmt1))
5438 : : {
5439 : 0 : new_tmp1 = gimple_call_lhs (new_stmt1);
5440 : 0 : new_tmp2 = gimple_call_lhs (new_stmt2);
5441 : : }
5442 : : else
5443 : : {
5444 : 10758 : new_tmp1 = gimple_assign_lhs (new_stmt1);
5445 : 10758 : new_tmp2 = gimple_assign_lhs (new_stmt2);
5446 : : }
5447 : :
5448 : : /* Store the results for the next step. */
5449 : 10758 : vec_tmp.quick_push (new_tmp1);
5450 : 10758 : vec_tmp.quick_push (new_tmp2);
5451 : : }
5452 : :
5453 : 8420 : vec_oprnds0->release ();
5454 : 8420 : *vec_oprnds0 = vec_tmp;
5455 : 8420 : }
5456 : :
5457 : : /* Create vectorized promotion stmts for widening stmts using only half the
5458 : : potential vector size for input. */
5459 : : static void
5460 : 14 : vect_create_half_widening_stmts (vec_info *vinfo,
5461 : : vec<tree> *vec_oprnds0,
5462 : : vec<tree> *vec_oprnds1,
5463 : : stmt_vec_info stmt_info, tree vec_dest,
5464 : : gimple_stmt_iterator *gsi,
5465 : : code_helper code1,
5466 : : int op_type)
5467 : : {
5468 : 14 : int i;
5469 : 14 : tree vop0, vop1;
5470 : 14 : gimple *new_stmt1;
5471 : 14 : gimple *new_stmt2;
5472 : 14 : gimple *new_stmt3;
5473 : 14 : vec<tree> vec_tmp = vNULL;
5474 : :
5475 : 14 : vec_tmp.create (vec_oprnds0->length ());
5476 : 28 : FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0)
5477 : : {
5478 : 14 : tree new_tmp1, new_tmp2, new_tmp3, out_type;
5479 : :
5480 : 14 : gcc_assert (op_type == binary_op);
5481 : 14 : vop1 = (*vec_oprnds1)[i];
5482 : :
5483 : : /* Widen the first vector input. */
5484 : 14 : out_type = TREE_TYPE (vec_dest);
5485 : 14 : new_tmp1 = make_ssa_name (out_type);
5486 : 14 : new_stmt1 = gimple_build_assign (new_tmp1, NOP_EXPR, vop0);
5487 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt1, gsi);
5488 : 14 : if (VECTOR_TYPE_P (TREE_TYPE (vop1)))
5489 : : {
5490 : : /* Widen the second vector input. */
5491 : 14 : new_tmp2 = make_ssa_name (out_type);
5492 : 14 : new_stmt2 = gimple_build_assign (new_tmp2, NOP_EXPR, vop1);
5493 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt2, gsi);
5494 : : /* Perform the operation. With both vector inputs widened. */
5495 : 14 : new_stmt3 = vect_gimple_build (vec_dest, code1, new_tmp1, new_tmp2);
5496 : : }
5497 : : else
5498 : : {
5499 : : /* Perform the operation. With the single vector input widened. */
5500 : 0 : new_stmt3 = vect_gimple_build (vec_dest, code1, new_tmp1, vop1);
5501 : : }
5502 : :
5503 : 14 : new_tmp3 = make_ssa_name (vec_dest, new_stmt3);
5504 : 14 : gimple_assign_set_lhs (new_stmt3, new_tmp3);
5505 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt3, gsi);
5506 : :
5507 : : /* Store the results for the next step. */
5508 : 14 : vec_tmp.quick_push (new_tmp3);
5509 : : }
5510 : :
5511 : 14 : vec_oprnds0->release ();
5512 : 14 : *vec_oprnds0 = vec_tmp;
5513 : 14 : }
5514 : :
5515 : :
5516 : : /* Check if STMT_INFO performs a conversion operation that can be vectorized.
5517 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
5518 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
5519 : : Return true if STMT_INFO is vectorizable in this way. */
5520 : :
5521 : : static bool
5522 : 2318825 : vectorizable_conversion (vec_info *vinfo,
5523 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
5524 : : gimple **vec_stmt, slp_tree slp_node,
5525 : : stmt_vector_for_cost *cost_vec)
5526 : : {
5527 : 2318825 : tree vec_dest, cvt_op = NULL_TREE;
5528 : 2318825 : tree scalar_dest;
5529 : 2318825 : tree op0, op1 = NULL_TREE;
5530 : 2318825 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
5531 : 2318825 : tree_code tc1;
5532 : 2318825 : code_helper code, code1, code2;
5533 : 2318825 : code_helper codecvt1 = ERROR_MARK, codecvt2 = ERROR_MARK;
5534 : 2318825 : tree new_temp;
5535 : 2318825 : enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
5536 : 2318825 : int ndts = 2;
5537 : 2318825 : poly_uint64 nunits_in;
5538 : 2318825 : poly_uint64 nunits_out;
5539 : 2318825 : tree vectype_out, vectype_in;
5540 : 2318825 : int ncopies, i;
5541 : 2318825 : tree lhs_type, rhs_type;
5542 : : /* For conversions between floating point and integer, there're 2 NARROW
5543 : : cases. NARROW_SRC is for FLOAT_EXPR, means
5544 : : integer --DEMOTION--> integer --FLOAT_EXPR--> floating point.
5545 : : This is safe when the range of the source integer can fit into the lower
5546 : : precision. NARROW_DST is for FIX_TRUNC_EXPR, means
5547 : : floating point --FIX_TRUNC_EXPR--> integer --DEMOTION--> INTEGER.
5548 : : For other conversions, when there's narrowing, NARROW_DST is used as
5549 : : default. */
5550 : 2318825 : enum { NARROW_SRC, NARROW_DST, NONE, WIDEN } modifier;
5551 : 2318825 : vec<tree> vec_oprnds0 = vNULL;
5552 : 2318825 : vec<tree> vec_oprnds1 = vNULL;
5553 : 2318825 : tree vop0;
5554 : 2318825 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
5555 : 2318825 : int multi_step_cvt = 0;
5556 : 2318825 : vec<tree> interm_types = vNULL;
5557 : 2318825 : tree intermediate_type, cvt_type = NULL_TREE;
5558 : 2318825 : int op_type;
5559 : 2318825 : unsigned short fltsz;
5560 : :
5561 : : /* Is STMT a vectorizable conversion? */
5562 : :
5563 : 2318825 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
5564 : : return false;
5565 : :
5566 : 2318825 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
5567 : 186872 : && ! vec_stmt)
5568 : : return false;
5569 : :
5570 : 2131953 : gimple* stmt = stmt_info->stmt;
5571 : 2131953 : if (!(is_gimple_assign (stmt) || is_gimple_call (stmt)))
5572 : : return false;
5573 : :
5574 : 2080861 : if (gimple_get_lhs (stmt) == NULL_TREE
5575 : 2080861 : || TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME)
5576 : 779558 : return false;
5577 : :
5578 : 1301303 : if (TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME)
5579 : : return false;
5580 : :
5581 : 1301303 : if (is_gimple_assign (stmt))
5582 : : {
5583 : 1293701 : code = gimple_assign_rhs_code (stmt);
5584 : 1293701 : op_type = TREE_CODE_LENGTH ((tree_code) code);
5585 : : }
5586 : 7602 : else if (gimple_call_internal_p (stmt))
5587 : : {
5588 : 4225 : code = gimple_call_internal_fn (stmt);
5589 : 4225 : op_type = gimple_call_num_args (stmt);
5590 : : }
5591 : : else
5592 : : return false;
5593 : :
5594 : 1297926 : bool widen_arith = (code == WIDEN_MULT_EXPR
5595 : 1295712 : || code == WIDEN_LSHIFT_EXPR
5596 : 2593638 : || widening_fn_p (code));
5597 : :
5598 : 1295712 : if (!widen_arith
5599 : 1295712 : && !CONVERT_EXPR_CODE_P (code)
5600 : : && code != FIX_TRUNC_EXPR
5601 : : && code != FLOAT_EXPR)
5602 : : return false;
5603 : :
5604 : : /* Check types of lhs and rhs. */
5605 : 142658 : scalar_dest = gimple_get_lhs (stmt);
5606 : 142658 : lhs_type = TREE_TYPE (scalar_dest);
5607 : 142658 : vectype_out = STMT_VINFO_VECTYPE (stmt_info);
5608 : :
5609 : : /* Check the operands of the operation. */
5610 : 142658 : slp_tree slp_op0, slp_op1 = NULL;
5611 : 142658 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
5612 : : 0, &op0, &slp_op0, &dt[0], &vectype_in))
5613 : : {
5614 : 0 : if (dump_enabled_p ())
5615 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5616 : : "use not simple.\n");
5617 : 0 : return false;
5618 : : }
5619 : :
5620 : 142658 : rhs_type = TREE_TYPE (op0);
5621 : 142658 : if ((code != FIX_TRUNC_EXPR && code != FLOAT_EXPR)
5622 : 271615 : && !((INTEGRAL_TYPE_P (lhs_type)
5623 : 117719 : && INTEGRAL_TYPE_P (rhs_type))
5624 : : || (SCALAR_FLOAT_TYPE_P (lhs_type)
5625 : 6829 : && SCALAR_FLOAT_TYPE_P (rhs_type))))
5626 : : return false;
5627 : :
5628 : 138249 : if (!VECTOR_BOOLEAN_TYPE_P (vectype_out)
5629 : 265813 : && ((INTEGRAL_TYPE_P (lhs_type)
5630 : 106009 : && !type_has_mode_precision_p (lhs_type))
5631 : 127123 : || (INTEGRAL_TYPE_P (rhs_type)
5632 : 118023 : && !type_has_mode_precision_p (rhs_type))))
5633 : : {
5634 : 966 : if (dump_enabled_p ())
5635 : 10 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5636 : : "type conversion to/from bit-precision unsupported."
5637 : : "\n");
5638 : 966 : return false;
5639 : : }
5640 : :
5641 : 137283 : if (op_type == binary_op)
5642 : : {
5643 : 2214 : gcc_assert (code == WIDEN_MULT_EXPR
5644 : : || code == WIDEN_LSHIFT_EXPR
5645 : : || widening_fn_p (code));
5646 : :
5647 : 2214 : op1 = is_gimple_assign (stmt) ? gimple_assign_rhs2 (stmt) :
5648 : 0 : gimple_call_arg (stmt, 0);
5649 : 2214 : tree vectype1_in;
5650 : 2214 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1,
5651 : : &op1, &slp_op1, &dt[1], &vectype1_in))
5652 : : {
5653 : 0 : if (dump_enabled_p ())
5654 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5655 : : "use not simple.\n");
5656 : 0 : return false;
5657 : : }
5658 : : /* For WIDEN_MULT_EXPR, if OP0 is a constant, use the type of
5659 : : OP1. */
5660 : 2214 : if (!vectype_in)
5661 : 117 : vectype_in = vectype1_in;
5662 : : }
5663 : :
5664 : : /* If op0 is an external or constant def, infer the vector type
5665 : : from the scalar type. */
5666 : 137283 : if (!vectype_in)
5667 : 12512 : vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
5668 : 137283 : if (vec_stmt)
5669 : 19116 : gcc_assert (vectype_in);
5670 : 137283 : if (!vectype_in)
5671 : : {
5672 : 1210 : if (dump_enabled_p ())
5673 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5674 : : "no vectype for scalar type %T\n", rhs_type);
5675 : :
5676 : 1210 : return false;
5677 : : }
5678 : :
5679 : 136073 : if (VECTOR_BOOLEAN_TYPE_P (vectype_out)
5680 : 146758 : && !VECTOR_BOOLEAN_TYPE_P (vectype_in))
5681 : : {
5682 : 193 : if (dump_enabled_p ())
5683 : 30 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5684 : : "can't convert between boolean and non "
5685 : : "boolean vectors %T\n", rhs_type);
5686 : :
5687 : 193 : return false;
5688 : : }
5689 : :
5690 : 135880 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
5691 : 135880 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
5692 : 135880 : if (known_eq (nunits_out, nunits_in))
5693 : 62492 : if (widen_arith)
5694 : : modifier = WIDEN;
5695 : : else
5696 : 135880 : modifier = NONE;
5697 : 73388 : else if (multiple_p (nunits_out, nunits_in))
5698 : : modifier = NARROW_DST;
5699 : : else
5700 : : {
5701 : 42541 : gcc_checking_assert (multiple_p (nunits_in, nunits_out));
5702 : : modifier = WIDEN;
5703 : : }
5704 : :
5705 : : /* Multiple types in SLP are handled by creating the appropriate number of
5706 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
5707 : : case of SLP. */
5708 : 135880 : if (slp_node)
5709 : : ncopies = 1;
5710 : 0 : else if (modifier == NARROW_DST)
5711 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype_out);
5712 : : else
5713 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype_in);
5714 : :
5715 : : /* Sanity check: make sure that at least one copy of the vectorized stmt
5716 : : needs to be generated. */
5717 : 0 : gcc_assert (ncopies >= 1);
5718 : :
5719 : 135880 : bool found_mode = false;
5720 : 135880 : scalar_mode lhs_mode = SCALAR_TYPE_MODE (lhs_type);
5721 : 135880 : scalar_mode rhs_mode = SCALAR_TYPE_MODE (rhs_type);
5722 : 135880 : opt_scalar_mode rhs_mode_iter;
5723 : 135880 : auto_vec<std::pair<tree, tree_code> > converts;
5724 : :
5725 : : /* Supportable by target? */
5726 : 135880 : switch (modifier)
5727 : : {
5728 : 62267 : case NONE:
5729 : 62267 : if (code != FIX_TRUNC_EXPR
5730 : : && code != FLOAT_EXPR
5731 : : && !CONVERT_EXPR_CODE_P (code))
5732 : : return false;
5733 : 62267 : gcc_assert (code.is_tree_code ());
5734 : 62267 : if (supportable_indirect_convert_operation (code,
5735 : : vectype_out, vectype_in,
5736 : : converts, op0, slp_op0))
5737 : : {
5738 : 16145 : gcc_assert (converts.length () <= 2);
5739 : 16145 : if (converts.length () == 1)
5740 : 16071 : code1 = converts[0].second;
5741 : : else
5742 : : {
5743 : 74 : cvt_type = NULL_TREE;
5744 : 74 : multi_step_cvt = converts.length () - 1;
5745 : 74 : codecvt1 = converts[0].second;
5746 : 74 : code1 = converts[1].second;
5747 : 74 : interm_types.safe_push (converts[0].first);
5748 : : }
5749 : : break;
5750 : : }
5751 : :
5752 : : /* FALLTHRU */
5753 : 46122 : unsupported:
5754 : 58121 : if (dump_enabled_p ())
5755 : 7024 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5756 : : "conversion not supported by target.\n");
5757 : : return false;
5758 : :
5759 : 42766 : case WIDEN:
5760 : 42766 : if (known_eq (nunits_in, nunits_out))
5761 : : {
5762 : 450 : if (!(code.is_tree_code ()
5763 : 225 : && supportable_half_widening_operation ((tree_code) code,
5764 : : vectype_out, vectype_in,
5765 : : &tc1)))
5766 : 71 : goto unsupported;
5767 : 154 : code1 = tc1;
5768 : 154 : gcc_assert (!(multi_step_cvt && op_type == binary_op));
5769 : : break;
5770 : : }
5771 : 42541 : if (supportable_widening_operation (vinfo, code, stmt_info,
5772 : : vectype_out, vectype_in, &code1,
5773 : : &code2, &multi_step_cvt,
5774 : : &interm_types))
5775 : : {
5776 : : /* Binary widening operation can only be supported directly by the
5777 : : architecture. */
5778 : 34448 : gcc_assert (!(multi_step_cvt && op_type == binary_op));
5779 : : break;
5780 : : }
5781 : :
5782 : 8093 : if (code != FLOAT_EXPR
5783 : 8447 : || GET_MODE_SIZE (lhs_mode) <= GET_MODE_SIZE (rhs_mode))
5784 : 7916 : goto unsupported;
5785 : :
5786 : 177 : fltsz = GET_MODE_SIZE (lhs_mode);
5787 : 252 : FOR_EACH_2XWIDER_MODE (rhs_mode_iter, rhs_mode)
5788 : : {
5789 : 252 : rhs_mode = rhs_mode_iter.require ();
5790 : 504 : if (GET_MODE_SIZE (rhs_mode) > fltsz)
5791 : : break;
5792 : :
5793 : 252 : cvt_type
5794 : 252 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0);
5795 : 252 : cvt_type = get_same_sized_vectype (cvt_type, vectype_in);
5796 : 252 : if (cvt_type == NULL_TREE)
5797 : 0 : goto unsupported;
5798 : :
5799 : 504 : if (GET_MODE_SIZE (rhs_mode) == fltsz)
5800 : : {
5801 : 62 : tc1 = ERROR_MARK;
5802 : 62 : gcc_assert (code.is_tree_code ());
5803 : 62 : if (!supportable_convert_operation ((tree_code) code, vectype_out,
5804 : : cvt_type, &tc1))
5805 : 22 : goto unsupported;
5806 : 40 : codecvt1 = tc1;
5807 : : }
5808 : 190 : else if (!supportable_widening_operation (vinfo, code,
5809 : : stmt_info, vectype_out,
5810 : : cvt_type, &codecvt1,
5811 : : &codecvt2, &multi_step_cvt,
5812 : : &interm_types))
5813 : 75 : continue;
5814 : : else
5815 : 115 : gcc_assert (multi_step_cvt == 0);
5816 : :
5817 : 155 : if (supportable_widening_operation (vinfo, NOP_EXPR, stmt_info,
5818 : : cvt_type,
5819 : : vectype_in, &code1,
5820 : : &code2, &multi_step_cvt,
5821 : : &interm_types))
5822 : : {
5823 : : found_mode = true;
5824 : : break;
5825 : : }
5826 : : }
5827 : :
5828 : 155 : if (!found_mode)
5829 : 0 : goto unsupported;
5830 : :
5831 : 310 : if (GET_MODE_SIZE (rhs_mode) == fltsz)
5832 : 40 : codecvt2 = ERROR_MARK;
5833 : : else
5834 : : {
5835 : 115 : multi_step_cvt++;
5836 : 115 : interm_types.safe_push (cvt_type);
5837 : 115 : cvt_type = NULL_TREE;
5838 : : }
5839 : : break;
5840 : :
5841 : 30847 : case NARROW_DST:
5842 : 30847 : gcc_assert (op_type == unary_op);
5843 : 30847 : if (supportable_narrowing_operation (code, vectype_out, vectype_in,
5844 : : &code1, &multi_step_cvt,
5845 : : &interm_types))
5846 : : break;
5847 : :
5848 : 13026 : if (GET_MODE_SIZE (lhs_mode) >= GET_MODE_SIZE (rhs_mode))
5849 : 611 : goto unsupported;
5850 : :
5851 : 3731 : if (code == FIX_TRUNC_EXPR)
5852 : : {
5853 : 352 : cvt_type
5854 : 352 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0);
5855 : 352 : cvt_type = get_same_sized_vectype (cvt_type, vectype_in);
5856 : 352 : if (cvt_type == NULL_TREE)
5857 : 0 : goto unsupported;
5858 : 352 : if (supportable_convert_operation ((tree_code) code, cvt_type, vectype_in,
5859 : : &tc1))
5860 : 350 : codecvt1 = tc1;
5861 : : else
5862 : 2 : goto unsupported;
5863 : 350 : if (supportable_narrowing_operation (NOP_EXPR, vectype_out, cvt_type,
5864 : : &code1, &multi_step_cvt,
5865 : : &interm_types))
5866 : : break;
5867 : : }
5868 : : /* If op0 can be represented with low precision integer,
5869 : : truncate it to cvt_type and the do FLOAT_EXPR. */
5870 : 3379 : else if (code == FLOAT_EXPR)
5871 : : {
5872 : 86 : wide_int op_min_value, op_max_value;
5873 : 86 : if (slp_node)
5874 : : {
5875 : 86 : tree def;
5876 : : /* ??? Merge ranges in case of more than one lane. */
5877 : 86 : if (SLP_TREE_LANES (slp_op0) != 1
5878 : 82 : || !(def = vect_get_slp_scalar_def (slp_op0, 0))
5879 : 168 : || !vect_get_range_info (def, &op_min_value, &op_max_value))
5880 : 84 : goto unsupported;
5881 : : }
5882 : 0 : else if (!vect_get_range_info (op0, &op_min_value, &op_max_value))
5883 : 0 : goto unsupported;
5884 : :
5885 : 2 : cvt_type
5886 : 2 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (lhs_mode), 0);
5887 : 2 : if (cvt_type == NULL_TREE
5888 : 2 : || (wi::min_precision (op_max_value, SIGNED)
5889 : 2 : > TYPE_PRECISION (cvt_type))
5890 : 4 : || (wi::min_precision (op_min_value, SIGNED)
5891 : 2 : > TYPE_PRECISION (cvt_type)))
5892 : 0 : goto unsupported;
5893 : :
5894 : 2 : cvt_type = get_same_sized_vectype (cvt_type, vectype_out);
5895 : 2 : if (cvt_type == NULL_TREE)
5896 : 0 : goto unsupported;
5897 : 2 : if (!supportable_narrowing_operation (NOP_EXPR, cvt_type, vectype_in,
5898 : : &code1, &multi_step_cvt,
5899 : : &interm_types))
5900 : 0 : goto unsupported;
5901 : 2 : if (supportable_convert_operation ((tree_code) code, vectype_out,
5902 : : cvt_type, &tc1))
5903 : : {
5904 : 2 : codecvt1 = tc1;
5905 : 2 : modifier = NARROW_SRC;
5906 : 2 : break;
5907 : : }
5908 : 86 : }
5909 : :
5910 : 3293 : goto unsupported;
5911 : :
5912 : : default:
5913 : : gcc_unreachable ();
5914 : : }
5915 : :
5916 : 77759 : if (!vec_stmt) /* transformation not required. */
5917 : : {
5918 : 58643 : if (slp_node
5919 : 58643 : && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype_in)
5920 : 58643 : || !vect_maybe_update_slp_op_vectype (slp_op1, vectype_in)))
5921 : : {
5922 : 0 : if (dump_enabled_p ())
5923 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5924 : : "incompatible vector types for invariants\n");
5925 : 0 : return false;
5926 : : }
5927 : 58643 : DUMP_VECT_SCOPE ("vectorizable_conversion");
5928 : 58643 : if (modifier == NONE)
5929 : : {
5930 : 11735 : STMT_VINFO_TYPE (stmt_info) = type_conversion_vec_info_type;
5931 : 11735 : vect_model_simple_cost (vinfo, stmt_info,
5932 : 11735 : ncopies * (1 + multi_step_cvt),
5933 : : dt, ndts, slp_node, cost_vec);
5934 : : }
5935 : 46908 : else if (modifier == NARROW_SRC || modifier == NARROW_DST)
5936 : : {
5937 : 19525 : STMT_VINFO_TYPE (stmt_info) = type_demotion_vec_info_type;
5938 : : /* The final packing step produces one vector result per copy. */
5939 : 39050 : unsigned int nvectors
5940 : 19525 : = (slp_node ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies);
5941 : 19525 : vect_model_promotion_demotion_cost (stmt_info, dt, nvectors,
5942 : : multi_step_cvt, cost_vec,
5943 : : widen_arith);
5944 : : }
5945 : : else
5946 : : {
5947 : 27383 : STMT_VINFO_TYPE (stmt_info) = type_promotion_vec_info_type;
5948 : : /* The initial unpacking step produces two vector results
5949 : : per copy. MULTI_STEP_CVT is 0 for a single conversion,
5950 : : so >> MULTI_STEP_CVT divides by 2^(number of steps - 1). */
5951 : 54766 : unsigned int nvectors
5952 : : = (slp_node
5953 : 27383 : ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) >> multi_step_cvt
5954 : 0 : : ncopies * 2);
5955 : 27383 : vect_model_promotion_demotion_cost (stmt_info, dt, nvectors,
5956 : : multi_step_cvt, cost_vec,
5957 : : widen_arith);
5958 : : }
5959 : 58643 : interm_types.release ();
5960 : 58643 : return true;
5961 : : }
5962 : :
5963 : : /* Transform. */
5964 : 19116 : if (dump_enabled_p ())
5965 : 3964 : dump_printf_loc (MSG_NOTE, vect_location,
5966 : : "transform conversion. ncopies = %d.\n", ncopies);
5967 : :
5968 : 19116 : if (op_type == binary_op)
5969 : : {
5970 : 457 : if (CONSTANT_CLASS_P (op0))
5971 : 0 : op0 = fold_convert (TREE_TYPE (op1), op0);
5972 : 457 : else if (CONSTANT_CLASS_P (op1))
5973 : 204 : op1 = fold_convert (TREE_TYPE (op0), op1);
5974 : : }
5975 : :
5976 : : /* In case of multi-step conversion, we first generate conversion operations
5977 : : to the intermediate types, and then from that types to the final one.
5978 : : We create vector destinations for the intermediate type (TYPES) received
5979 : : from supportable_*_operation, and store them in the correct order
5980 : : for future use in vect_create_vectorized_*_stmts (). */
5981 : 38232 : auto_vec<tree> vec_dsts (multi_step_cvt + 1);
5982 : 19116 : bool widen_or_narrow_float_p
5983 : 19116 : = cvt_type && (modifier == WIDEN || modifier == NARROW_SRC);
5984 : 19116 : vec_dest = vect_create_destination_var (scalar_dest,
5985 : : widen_or_narrow_float_p
5986 : : ? cvt_type : vectype_out);
5987 : 19116 : vec_dsts.quick_push (vec_dest);
5988 : :
5989 : 19116 : if (multi_step_cvt)
5990 : : {
5991 : 5842 : for (i = interm_types.length () - 1;
5992 : 6086 : interm_types.iterate (i, &intermediate_type); i--)
5993 : : {
5994 : 3165 : vec_dest = vect_create_destination_var (scalar_dest,
5995 : : intermediate_type);
5996 : 3165 : vec_dsts.quick_push (vec_dest);
5997 : : }
5998 : : }
5999 : :
6000 : 19116 : if (cvt_type)
6001 : 106 : vec_dest = vect_create_destination_var (scalar_dest,
6002 : : widen_or_narrow_float_p
6003 : : ? vectype_out : cvt_type);
6004 : :
6005 : 19116 : int ninputs = 1;
6006 : 19116 : if (!slp_node)
6007 : : {
6008 : 0 : if (modifier == WIDEN)
6009 : : ;
6010 : 0 : else if (modifier == NARROW_SRC || modifier == NARROW_DST)
6011 : : {
6012 : 0 : if (multi_step_cvt)
6013 : 0 : ninputs = vect_pow2 (multi_step_cvt);
6014 : 0 : ninputs *= 2;
6015 : : }
6016 : : }
6017 : :
6018 : 19116 : switch (modifier)
6019 : : {
6020 : 4410 : case NONE:
6021 : 4410 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
6022 : : op0, vectype_in, &vec_oprnds0);
6023 : : /* vec_dest is intermediate type operand when multi_step_cvt. */
6024 : 4410 : if (multi_step_cvt)
6025 : : {
6026 : 21 : cvt_op = vec_dest;
6027 : 21 : vec_dest = vec_dsts[0];
6028 : : }
6029 : :
6030 : 9123 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6031 : : {
6032 : : /* Arguments are ready, create the new vector stmt. */
6033 : 4713 : gimple* new_stmt;
6034 : 4713 : if (multi_step_cvt)
6035 : : {
6036 : 21 : gcc_assert (multi_step_cvt == 1);
6037 : 21 : new_stmt = vect_gimple_build (cvt_op, codecvt1, vop0);
6038 : 21 : new_temp = make_ssa_name (cvt_op, new_stmt);
6039 : 21 : gimple_assign_set_lhs (new_stmt, new_temp);
6040 : 21 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6041 : 21 : vop0 = new_temp;
6042 : : }
6043 : 4713 : new_stmt = vect_gimple_build (vec_dest, code1, vop0);
6044 : 4713 : new_temp = make_ssa_name (vec_dest, new_stmt);
6045 : 4713 : gimple_set_lhs (new_stmt, new_temp);
6046 : 4713 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6047 : :
6048 : 4713 : if (slp_node)
6049 : 4713 : slp_node->push_vec_def (new_stmt);
6050 : : else
6051 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
6052 : : }
6053 : : break;
6054 : :
6055 : 7374 : case WIDEN:
6056 : : /* In case the vectorization factor (VF) is bigger than the number
6057 : : of elements that we can fit in a vectype (nunits), we have to
6058 : : generate more than one vector stmt - i.e - we need to "unroll"
6059 : : the vector stmt by a factor VF/nunits. */
6060 : 7374 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies * ninputs,
6061 : : op0, vectype_in, &vec_oprnds0,
6062 : 7374 : code == WIDEN_LSHIFT_EXPR ? NULL_TREE : op1,
6063 : : vectype_in, &vec_oprnds1);
6064 : 7374 : if (code == WIDEN_LSHIFT_EXPR)
6065 : : {
6066 : 0 : int oprnds_size = vec_oprnds0.length ();
6067 : 0 : vec_oprnds1.create (oprnds_size);
6068 : 0 : for (i = 0; i < oprnds_size; ++i)
6069 : 0 : vec_oprnds1.quick_push (op1);
6070 : : }
6071 : : /* Arguments are ready. Create the new vector stmts. */
6072 : 15808 : for (i = multi_step_cvt; i >= 0; i--)
6073 : : {
6074 : 8434 : tree this_dest = vec_dsts[i];
6075 : 8434 : code_helper c1 = code1, c2 = code2;
6076 : 8434 : if (i == 0 && codecvt2 != ERROR_MARK)
6077 : : {
6078 : 48 : c1 = codecvt1;
6079 : 48 : c2 = codecvt2;
6080 : : }
6081 : 8434 : if (known_eq (nunits_out, nunits_in))
6082 : 14 : vect_create_half_widening_stmts (vinfo, &vec_oprnds0, &vec_oprnds1,
6083 : : stmt_info, this_dest, gsi, c1,
6084 : : op_type);
6085 : : else
6086 : 8420 : vect_create_vectorized_promotion_stmts (vinfo, &vec_oprnds0,
6087 : : &vec_oprnds1, stmt_info,
6088 : : this_dest, gsi,
6089 : : c1, c2, op_type);
6090 : : }
6091 : :
6092 : 26434 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6093 : : {
6094 : 19060 : gimple *new_stmt;
6095 : 19060 : if (cvt_type)
6096 : : {
6097 : 142 : new_temp = make_ssa_name (vec_dest);
6098 : 142 : new_stmt = vect_gimple_build (new_temp, codecvt1, vop0);
6099 : 142 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6100 : : }
6101 : : else
6102 : 18918 : new_stmt = SSA_NAME_DEF_STMT (vop0);
6103 : :
6104 : 19060 : if (slp_node)
6105 : 19060 : slp_node->push_vec_def (new_stmt);
6106 : : else
6107 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
6108 : : }
6109 : : break;
6110 : :
6111 : 7332 : case NARROW_SRC:
6112 : 7332 : case NARROW_DST:
6113 : : /* In case the vectorization factor (VF) is bigger than the number
6114 : : of elements that we can fit in a vectype (nunits), we have to
6115 : : generate more than one vector stmt - i.e - we need to "unroll"
6116 : : the vector stmt by a factor VF/nunits. */
6117 : 7332 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies * ninputs,
6118 : : op0, vectype_in, &vec_oprnds0);
6119 : : /* Arguments are ready. Create the new vector stmts. */
6120 : 7332 : if (cvt_type && modifier == NARROW_DST)
6121 : 201 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6122 : : {
6123 : 156 : new_temp = make_ssa_name (vec_dest);
6124 : 156 : gimple *new_stmt = vect_gimple_build (new_temp, codecvt1, vop0);
6125 : 156 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6126 : 156 : vec_oprnds0[i] = new_temp;
6127 : : }
6128 : :
6129 : 7332 : vect_create_vectorized_demotion_stmts (vinfo, &vec_oprnds0,
6130 : : multi_step_cvt,
6131 : : stmt_info, vec_dsts, gsi,
6132 : : slp_node, code1,
6133 : : modifier == NARROW_SRC);
6134 : : /* After demoting op0 to cvt_type, convert it to dest. */
6135 : 7332 : if (cvt_type && code == FLOAT_EXPR)
6136 : : {
6137 : 4 : for (unsigned int i = 0; i != vec_oprnds0.length() / 2; i++)
6138 : : {
6139 : : /* Arguments are ready, create the new vector stmt. */
6140 : 1 : gcc_assert (TREE_CODE_LENGTH ((tree_code) codecvt1) == unary_op);
6141 : 1 : gimple *new_stmt
6142 : 1 : = vect_gimple_build (vec_dest, codecvt1, vec_oprnds0[i]);
6143 : 1 : new_temp = make_ssa_name (vec_dest, new_stmt);
6144 : 1 : gimple_set_lhs (new_stmt, new_temp);
6145 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6146 : :
6147 : : /* This is the last step of the conversion sequence. Store the
6148 : : vectors in SLP_NODE or in vector info of the scalar statement
6149 : : (or in STMT_VINFO_RELATED_STMT chain). */
6150 : 1 : if (slp_node)
6151 : 1 : slp_node->push_vec_def (new_stmt);
6152 : : else
6153 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
6154 : : }
6155 : : }
6156 : : break;
6157 : : }
6158 : 19116 : if (!slp_node)
6159 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
6160 : :
6161 : 19116 : vec_oprnds0.release ();
6162 : 19116 : vec_oprnds1.release ();
6163 : 19116 : interm_types.release ();
6164 : :
6165 : 19116 : return true;
6166 : 135880 : }
6167 : :
6168 : : /* Return true if we can assume from the scalar form of STMT_INFO that
6169 : : neither the scalar nor the vector forms will generate code. STMT_INFO
6170 : : is known not to involve a data reference. */
6171 : :
6172 : : bool
6173 : 949285 : vect_nop_conversion_p (stmt_vec_info stmt_info)
6174 : : {
6175 : 949285 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
6176 : 748535 : if (!stmt)
6177 : : return false;
6178 : :
6179 : 748535 : tree lhs = gimple_assign_lhs (stmt);
6180 : 748535 : tree_code code = gimple_assign_rhs_code (stmt);
6181 : 748535 : tree rhs = gimple_assign_rhs1 (stmt);
6182 : :
6183 : 748535 : if (code == SSA_NAME || code == VIEW_CONVERT_EXPR)
6184 : : return true;
6185 : :
6186 : 747304 : if (CONVERT_EXPR_CODE_P (code))
6187 : 157288 : return tree_nop_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs));
6188 : :
6189 : : return false;
6190 : : }
6191 : :
6192 : : /* Function vectorizable_assignment.
6193 : :
6194 : : Check if STMT_INFO performs an assignment (copy) that can be vectorized.
6195 : : If VEC_STMT is also passed, vectorize the STMT_INFO: create a vectorized
6196 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
6197 : : Return true if STMT_INFO is vectorizable in this way. */
6198 : :
6199 : : static bool
6200 : 1829976 : vectorizable_assignment (vec_info *vinfo,
6201 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
6202 : : gimple **vec_stmt, slp_tree slp_node,
6203 : : stmt_vector_for_cost *cost_vec)
6204 : : {
6205 : 1829976 : tree vec_dest;
6206 : 1829976 : tree scalar_dest;
6207 : 1829976 : tree op;
6208 : 1829976 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
6209 : 1829976 : tree new_temp;
6210 : 1829976 : enum vect_def_type dt[1] = {vect_unknown_def_type};
6211 : 1829976 : int ndts = 1;
6212 : 1829976 : int ncopies;
6213 : 1829976 : int i;
6214 : 1829976 : vec<tree> vec_oprnds = vNULL;
6215 : 1829976 : tree vop;
6216 : 1829976 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
6217 : 1829976 : enum tree_code code;
6218 : 1829976 : tree vectype_in;
6219 : :
6220 : 1829976 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
6221 : : return false;
6222 : :
6223 : 1829976 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
6224 : 186872 : && ! vec_stmt)
6225 : : return false;
6226 : :
6227 : : /* Is vectorizable assignment? */
6228 : 3349921 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
6229 : 1583331 : if (!stmt)
6230 : : return false;
6231 : :
6232 : 1583331 : scalar_dest = gimple_assign_lhs (stmt);
6233 : 1583331 : if (TREE_CODE (scalar_dest) != SSA_NAME)
6234 : : return false;
6235 : :
6236 : 804852 : if (STMT_VINFO_DATA_REF (stmt_info))
6237 : : return false;
6238 : :
6239 : 320621 : code = gimple_assign_rhs_code (stmt);
6240 : 320621 : if (!(gimple_assign_single_p (stmt)
6241 : 319647 : || code == PAREN_EXPR
6242 : 317897 : || CONVERT_EXPR_CODE_P (code)))
6243 : : return false;
6244 : :
6245 : 80243 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
6246 : 80243 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
6247 : :
6248 : : /* Multiple types in SLP are handled by creating the appropriate number of
6249 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
6250 : : case of SLP. */
6251 : 80243 : if (slp_node)
6252 : : ncopies = 1;
6253 : : else
6254 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
6255 : :
6256 : 0 : gcc_assert (ncopies >= 1);
6257 : :
6258 : 80243 : slp_tree slp_op;
6259 : 80243 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &op, &slp_op,
6260 : : &dt[0], &vectype_in))
6261 : : {
6262 : 0 : if (dump_enabled_p ())
6263 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6264 : : "use not simple.\n");
6265 : 0 : return false;
6266 : : }
6267 : 80243 : if (!vectype_in)
6268 : 11416 : vectype_in = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op), slp_node);
6269 : :
6270 : : /* We can handle VIEW_CONVERT conversions that do not change the number
6271 : : of elements or the vector size or other conversions when the component
6272 : : types are nop-convertible. */
6273 : 80243 : if (!vectype_in
6274 : 78932 : || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype_in), nunits)
6275 : 66650 : || (code == VIEW_CONVERT_EXPR
6276 : 1410 : && maybe_ne (GET_MODE_SIZE (TYPE_MODE (vectype)),
6277 : 1410 : GET_MODE_SIZE (TYPE_MODE (vectype_in))))
6278 : 146893 : || (CONVERT_EXPR_CODE_P (code)
6279 : 64092 : && !tree_nop_conversion_p (TREE_TYPE (vectype),
6280 : 64092 : TREE_TYPE (vectype_in))))
6281 : 16631 : return false;
6282 : :
6283 : 190724 : if (VECTOR_BOOLEAN_TYPE_P (vectype) != VECTOR_BOOLEAN_TYPE_P (vectype_in))
6284 : : {
6285 : 0 : if (dump_enabled_p ())
6286 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6287 : : "can't convert between boolean and non "
6288 : 0 : "boolean vectors %T\n", TREE_TYPE (op));
6289 : :
6290 : 0 : return false;
6291 : : }
6292 : :
6293 : : /* We do not handle bit-precision changes. */
6294 : 63612 : if ((CONVERT_EXPR_CODE_P (code)
6295 : 2558 : || code == VIEW_CONVERT_EXPR)
6296 : 61759 : && ((INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
6297 : 60308 : && !type_has_mode_precision_p (TREE_TYPE (scalar_dest)))
6298 : 61495 : || (INTEGRAL_TYPE_P (TREE_TYPE (op))
6299 : 57460 : && !type_has_mode_precision_p (TREE_TYPE (op))))
6300 : : /* But a conversion that does not change the bit-pattern is ok. */
6301 : 64268 : && !(INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
6302 : 656 : && INTEGRAL_TYPE_P (TREE_TYPE (op))
6303 : 656 : && (((TYPE_PRECISION (TREE_TYPE (scalar_dest))
6304 : 656 : > TYPE_PRECISION (TREE_TYPE (op)))
6305 : 392 : && TYPE_UNSIGNED (TREE_TYPE (op)))
6306 : 288 : || (TYPE_PRECISION (TREE_TYPE (scalar_dest))
6307 : 288 : == TYPE_PRECISION (TREE_TYPE (op))))))
6308 : : {
6309 : 226 : if (dump_enabled_p ())
6310 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6311 : : "type conversion to/from bit-precision "
6312 : : "unsupported.\n");
6313 : 226 : return false;
6314 : : }
6315 : :
6316 : 63386 : if (!vec_stmt) /* transformation not required. */
6317 : : {
6318 : 49338 : if (slp_node
6319 : 49338 : && !vect_maybe_update_slp_op_vectype (slp_op, vectype_in))
6320 : : {
6321 : 0 : if (dump_enabled_p ())
6322 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6323 : : "incompatible vector types for invariants\n");
6324 : 0 : return false;
6325 : : }
6326 : 49338 : STMT_VINFO_TYPE (stmt_info) = assignment_vec_info_type;
6327 : 49338 : DUMP_VECT_SCOPE ("vectorizable_assignment");
6328 : 49338 : if (!vect_nop_conversion_p (stmt_info))
6329 : 1544 : vect_model_simple_cost (vinfo, stmt_info, ncopies, dt, ndts, slp_node,
6330 : : cost_vec);
6331 : 49338 : return true;
6332 : : }
6333 : :
6334 : : /* Transform. */
6335 : 14048 : if (dump_enabled_p ())
6336 : 3295 : dump_printf_loc (MSG_NOTE, vect_location, "transform assignment.\n");
6337 : :
6338 : : /* Handle def. */
6339 : 14048 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6340 : :
6341 : : /* Handle use. */
6342 : 14048 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, op, &vec_oprnds);
6343 : :
6344 : : /* Arguments are ready. create the new vector stmt. */
6345 : 30681 : FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
6346 : : {
6347 : 16633 : if (CONVERT_EXPR_CODE_P (code)
6348 : 615 : || code == VIEW_CONVERT_EXPR)
6349 : 16055 : vop = build1 (VIEW_CONVERT_EXPR, vectype, vop);
6350 : 16633 : gassign *new_stmt = gimple_build_assign (vec_dest, vop);
6351 : 16633 : new_temp = make_ssa_name (vec_dest, new_stmt);
6352 : 16633 : gimple_assign_set_lhs (new_stmt, new_temp);
6353 : 16633 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6354 : 16633 : if (slp_node)
6355 : 16633 : slp_node->push_vec_def (new_stmt);
6356 : : else
6357 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
6358 : : }
6359 : 14048 : if (!slp_node)
6360 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
6361 : :
6362 : 14048 : vec_oprnds.release ();
6363 : 14048 : return true;
6364 : : }
6365 : :
6366 : :
6367 : : /* Return TRUE if CODE (a shift operation) is supported for SCALAR_TYPE
6368 : : either as shift by a scalar or by a vector. */
6369 : :
6370 : : bool
6371 : 236970 : vect_supportable_shift (vec_info *vinfo, enum tree_code code, tree scalar_type)
6372 : : {
6373 : 236970 : optab optab;
6374 : 236970 : tree vectype;
6375 : :
6376 : 236970 : vectype = get_vectype_for_scalar_type (vinfo, scalar_type);
6377 : 236970 : if (!vectype)
6378 : : return false;
6379 : :
6380 : 236970 : optab = optab_for_tree_code (code, vectype, optab_scalar);
6381 : 236970 : if (optab && can_implement_p (optab, TYPE_MODE (vectype)))
6382 : : return true;
6383 : :
6384 : 208152 : optab = optab_for_tree_code (code, vectype, optab_vector);
6385 : 208152 : if (optab && can_implement_p (optab, TYPE_MODE (vectype)))
6386 : : return true;
6387 : :
6388 : : return false;
6389 : : }
6390 : :
6391 : :
6392 : : /* Function vectorizable_shift.
6393 : :
6394 : : Check if STMT_INFO performs a shift operation that can be vectorized.
6395 : : If VEC_STMT is also passed, vectorize the STMT_INFO: create a vectorized
6396 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
6397 : : Return true if STMT_INFO is vectorizable in this way. */
6398 : :
6399 : : static bool
6400 : 1408143 : vectorizable_shift (vec_info *vinfo,
6401 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
6402 : : gimple **vec_stmt, slp_tree slp_node,
6403 : : stmt_vector_for_cost *cost_vec)
6404 : : {
6405 : 1408143 : tree vec_dest;
6406 : 1408143 : tree scalar_dest;
6407 : 1408143 : tree op0, op1 = NULL;
6408 : 1408143 : tree vec_oprnd1 = NULL_TREE;
6409 : 1408143 : tree vectype;
6410 : 1408143 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
6411 : 1408143 : enum tree_code code;
6412 : 1408143 : machine_mode vec_mode;
6413 : 1408143 : tree new_temp;
6414 : 1408143 : optab optab;
6415 : 1408143 : int icode;
6416 : 1408143 : machine_mode optab_op2_mode;
6417 : 1408143 : enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
6418 : 1408143 : int ndts = 2;
6419 : 1408143 : poly_uint64 nunits_in;
6420 : 1408143 : poly_uint64 nunits_out;
6421 : 1408143 : tree vectype_out;
6422 : 1408143 : tree op1_vectype;
6423 : 1408143 : int ncopies;
6424 : 1408143 : int i;
6425 : 1408143 : vec<tree> vec_oprnds0 = vNULL;
6426 : 1408143 : vec<tree> vec_oprnds1 = vNULL;
6427 : 1408143 : tree vop0, vop1;
6428 : 1408143 : unsigned int k;
6429 : 1408143 : bool scalar_shift_arg = true;
6430 : 1408143 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
6431 : 1408143 : bool incompatible_op1_vectype_p = false;
6432 : :
6433 : 1408143 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
6434 : : return false;
6435 : :
6436 : 1408143 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
6437 : 28411 : && STMT_VINFO_DEF_TYPE (stmt_info) != vect_nested_cycle
6438 : 28411 : && ! vec_stmt)
6439 : : return false;
6440 : :
6441 : : /* Is STMT a vectorizable binary/unary operation? */
6442 : 2689737 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
6443 : 1321989 : if (!stmt)
6444 : : return false;
6445 : :
6446 : 1321989 : if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
6447 : : return false;
6448 : :
6449 : 669995 : code = gimple_assign_rhs_code (stmt);
6450 : :
6451 : 669995 : if (!(code == LSHIFT_EXPR || code == RSHIFT_EXPR || code == LROTATE_EXPR
6452 : : || code == RROTATE_EXPR))
6453 : : return false;
6454 : :
6455 : 54035 : scalar_dest = gimple_assign_lhs (stmt);
6456 : 54035 : vectype_out = STMT_VINFO_VECTYPE (stmt_info);
6457 : 54035 : if (!type_has_mode_precision_p (TREE_TYPE (scalar_dest)))
6458 : : {
6459 : 0 : if (dump_enabled_p ())
6460 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6461 : : "bit-precision shifts not supported.\n");
6462 : 0 : return false;
6463 : : }
6464 : :
6465 : 54035 : slp_tree slp_op0;
6466 : 54035 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
6467 : : 0, &op0, &slp_op0, &dt[0], &vectype))
6468 : : {
6469 : 0 : if (dump_enabled_p ())
6470 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6471 : : "use not simple.\n");
6472 : 0 : return false;
6473 : : }
6474 : : /* If op0 is an external or constant def, infer the vector type
6475 : : from the scalar type. */
6476 : 54035 : if (!vectype)
6477 : 16270 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0), slp_node);
6478 : 54035 : if (vec_stmt)
6479 : 5731 : gcc_assert (vectype);
6480 : 54035 : if (!vectype)
6481 : : {
6482 : 0 : if (dump_enabled_p ())
6483 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6484 : : "no vectype for scalar type\n");
6485 : 0 : return false;
6486 : : }
6487 : :
6488 : 54035 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
6489 : 54035 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
6490 : 54035 : if (maybe_ne (nunits_out, nunits_in))
6491 : : return false;
6492 : :
6493 : 54035 : stmt_vec_info op1_def_stmt_info;
6494 : 54035 : slp_tree slp_op1;
6495 : 54035 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1, &op1, &slp_op1,
6496 : : &dt[1], &op1_vectype, &op1_def_stmt_info))
6497 : : {
6498 : 0 : if (dump_enabled_p ())
6499 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6500 : : "use not simple.\n");
6501 : 0 : return false;
6502 : : }
6503 : :
6504 : : /* Multiple types in SLP are handled by creating the appropriate number of
6505 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
6506 : : case of SLP. */
6507 : 54035 : if (slp_node)
6508 : : ncopies = 1;
6509 : : else
6510 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
6511 : :
6512 : 0 : gcc_assert (ncopies >= 1);
6513 : :
6514 : : /* Determine whether the shift amount is a vector, or scalar. If the
6515 : : shift/rotate amount is a vector, use the vector/vector shift optabs. */
6516 : :
6517 : 54035 : if ((dt[1] == vect_internal_def
6518 : 54035 : || dt[1] == vect_induction_def
6519 : 37995 : || dt[1] == vect_nested_cycle)
6520 : 16058 : && (!slp_node || SLP_TREE_LANES (slp_node) == 1))
6521 : : scalar_shift_arg = false;
6522 : 38025 : else if (dt[1] == vect_constant_def
6523 : : || dt[1] == vect_external_def
6524 : 38025 : || dt[1] == vect_internal_def)
6525 : : {
6526 : : /* In SLP, need to check whether the shift count is the same,
6527 : : in loops if it is a constant or invariant, it is always
6528 : : a scalar shift. */
6529 : 38017 : if (slp_node)
6530 : : {
6531 : 38017 : vec<stmt_vec_info> stmts = SLP_TREE_SCALAR_STMTS (slp_node);
6532 : 38017 : stmt_vec_info slpstmt_info;
6533 : :
6534 : 103634 : FOR_EACH_VEC_ELT (stmts, k, slpstmt_info)
6535 : 65617 : if (slpstmt_info)
6536 : : {
6537 : 65617 : gassign *slpstmt = as_a <gassign *> (slpstmt_info->stmt);
6538 : 131234 : if (!operand_equal_p (gimple_assign_rhs2 (slpstmt), op1, 0))
6539 : 65617 : scalar_shift_arg = false;
6540 : : }
6541 : :
6542 : : /* For internal SLP defs we have to make sure we see scalar stmts
6543 : : for all vector elements.
6544 : : ??? For different vectors we could resort to a different
6545 : : scalar shift operand but code-generation below simply always
6546 : : takes the first. */
6547 : 38017 : if (dt[1] == vect_internal_def
6548 : 38017 : && maybe_ne (nunits_out * SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node),
6549 : 40 : stmts.length ()))
6550 : : scalar_shift_arg = false;
6551 : : }
6552 : :
6553 : : /* If the shift amount is computed by a pattern stmt we cannot
6554 : : use the scalar amount directly thus give up and use a vector
6555 : : shift. */
6556 : 38017 : if (op1_def_stmt_info && is_pattern_stmt_p (op1_def_stmt_info))
6557 : : scalar_shift_arg = false;
6558 : : }
6559 : : else
6560 : : {
6561 : 8 : if (dump_enabled_p ())
6562 : 8 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6563 : : "operand mode requires invariant argument.\n");
6564 : 8 : return false;
6565 : : }
6566 : :
6567 : : /* Vector shifted by vector. */
6568 : 54055 : bool was_scalar_shift_arg = scalar_shift_arg;
6569 : 38017 : if (!scalar_shift_arg)
6570 : : {
6571 : 16038 : optab = optab_for_tree_code (code, vectype, optab_vector);
6572 : 16038 : if (dump_enabled_p ())
6573 : 1121 : dump_printf_loc (MSG_NOTE, vect_location,
6574 : : "vector/vector shift/rotate found.\n");
6575 : :
6576 : 16038 : if (!op1_vectype)
6577 : 7 : op1_vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op1),
6578 : : slp_op1);
6579 : 16038 : incompatible_op1_vectype_p
6580 : 32076 : = (op1_vectype == NULL_TREE
6581 : 16038 : || maybe_ne (TYPE_VECTOR_SUBPARTS (op1_vectype),
6582 : 16038 : TYPE_VECTOR_SUBPARTS (vectype))
6583 : 22124 : || TYPE_MODE (op1_vectype) != TYPE_MODE (vectype));
6584 : 6081 : if (incompatible_op1_vectype_p
6585 : 9957 : && (!slp_node
6586 : 9957 : || SLP_TREE_DEF_TYPE (slp_op1) != vect_constant_def
6587 : 1 : || slp_op1->refcnt != 1))
6588 : : {
6589 : 9956 : if (dump_enabled_p ())
6590 : 72 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6591 : : "unusable type for last operand in"
6592 : : " vector/vector shift/rotate.\n");
6593 : 9956 : return false;
6594 : : }
6595 : : }
6596 : : /* See if the machine has a vector shifted by scalar insn and if not
6597 : : then see if it has a vector shifted by vector insn. */
6598 : : else
6599 : : {
6600 : 37989 : optab = optab_for_tree_code (code, vectype, optab_scalar);
6601 : 37989 : if (optab
6602 : 37989 : && can_implement_p (optab, TYPE_MODE (vectype)))
6603 : : {
6604 : 37989 : if (dump_enabled_p ())
6605 : 5272 : dump_printf_loc (MSG_NOTE, vect_location,
6606 : : "vector/scalar shift/rotate found.\n");
6607 : : }
6608 : : else
6609 : : {
6610 : 0 : optab = optab_for_tree_code (code, vectype, optab_vector);
6611 : 0 : if (optab
6612 : 0 : && can_implement_p (optab, TYPE_MODE (vectype)))
6613 : : {
6614 : 0 : scalar_shift_arg = false;
6615 : :
6616 : 0 : if (dump_enabled_p ())
6617 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
6618 : : "vector/vector shift/rotate found.\n");
6619 : :
6620 : 0 : if (!op1_vectype)
6621 : 0 : op1_vectype = get_vectype_for_scalar_type (vinfo,
6622 : 0 : TREE_TYPE (op1),
6623 : : slp_op1);
6624 : :
6625 : : /* Unlike the other binary operators, shifts/rotates have
6626 : : the rhs being int, instead of the same type as the lhs,
6627 : : so make sure the scalar is the right type if we are
6628 : : dealing with vectors of long long/long/short/char. */
6629 : 0 : incompatible_op1_vectype_p
6630 : 0 : = (!op1_vectype
6631 : 0 : || !tree_nop_conversion_p (TREE_TYPE (vectype),
6632 : 0 : TREE_TYPE (op1)));
6633 : 0 : if (incompatible_op1_vectype_p
6634 : 0 : && dt[1] == vect_internal_def)
6635 : : {
6636 : 0 : if (dump_enabled_p ())
6637 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6638 : : "unusable type for last operand in"
6639 : : " vector/vector shift/rotate.\n");
6640 : 0 : return false;
6641 : : }
6642 : : }
6643 : : }
6644 : : }
6645 : :
6646 : : /* Supportable by target? */
6647 : 44071 : if (!optab)
6648 : : {
6649 : 0 : if (dump_enabled_p ())
6650 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6651 : : "no optab.\n");
6652 : 0 : return false;
6653 : : }
6654 : 44071 : vec_mode = TYPE_MODE (vectype);
6655 : 44071 : icode = (int) optab_handler (optab, vec_mode);
6656 : 44071 : if (icode == CODE_FOR_nothing)
6657 : : {
6658 : 3676 : if (dump_enabled_p ())
6659 : 776 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6660 : : "op not supported by target.\n");
6661 : 3676 : return false;
6662 : : }
6663 : : /* vector lowering cannot optimize vector shifts using word arithmetic. */
6664 : 40395 : if (vect_emulated_vector_p (vectype))
6665 : : return false;
6666 : :
6667 : 40395 : if (!vec_stmt) /* transformation not required. */
6668 : : {
6669 : 34664 : if (slp_node
6670 : 34664 : && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
6671 : 34664 : || ((!scalar_shift_arg || dt[1] == vect_internal_def)
6672 : 1699 : && (!incompatible_op1_vectype_p
6673 : 1 : || dt[1] == vect_constant_def)
6674 : 1699 : && !vect_maybe_update_slp_op_vectype
6675 : 1699 : (slp_op1,
6676 : : incompatible_op1_vectype_p ? vectype : op1_vectype))))
6677 : : {
6678 : 0 : if (dump_enabled_p ())
6679 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6680 : : "incompatible vector types for invariants\n");
6681 : 0 : return false;
6682 : : }
6683 : : /* Now adjust the constant shift amount in place. */
6684 : 34664 : if (slp_node
6685 : 34664 : && incompatible_op1_vectype_p
6686 : 1 : && dt[1] == vect_constant_def)
6687 : : {
6688 : 4 : for (unsigned i = 0;
6689 : 5 : i < SLP_TREE_SCALAR_OPS (slp_op1).length (); ++i)
6690 : : {
6691 : 4 : SLP_TREE_SCALAR_OPS (slp_op1)[i]
6692 : 4 : = fold_convert (TREE_TYPE (vectype),
6693 : : SLP_TREE_SCALAR_OPS (slp_op1)[i]);
6694 : 4 : gcc_assert ((TREE_CODE (SLP_TREE_SCALAR_OPS (slp_op1)[i])
6695 : : == INTEGER_CST));
6696 : : }
6697 : : }
6698 : 34664 : STMT_VINFO_TYPE (stmt_info) = shift_vec_info_type;
6699 : 34664 : DUMP_VECT_SCOPE ("vectorizable_shift");
6700 : 36353 : vect_model_simple_cost (vinfo, stmt_info, ncopies, dt,
6701 : : scalar_shift_arg ? 1 : ndts, slp_node, cost_vec);
6702 : 34664 : return true;
6703 : : }
6704 : :
6705 : : /* Transform. */
6706 : :
6707 : 5731 : if (dump_enabled_p ())
6708 : 1829 : dump_printf_loc (MSG_NOTE, vect_location,
6709 : : "transform binary/unary operation.\n");
6710 : :
6711 : 5731 : if (incompatible_op1_vectype_p && !slp_node)
6712 : : {
6713 : 0 : gcc_assert (!scalar_shift_arg && was_scalar_shift_arg);
6714 : 0 : op1 = fold_convert (TREE_TYPE (vectype), op1);
6715 : 0 : if (dt[1] != vect_constant_def)
6716 : 0 : op1 = vect_init_vector (vinfo, stmt_info, op1,
6717 : 0 : TREE_TYPE (vectype), NULL);
6718 : : }
6719 : :
6720 : : /* Handle def. */
6721 : 5731 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6722 : :
6723 : 5731 : if (scalar_shift_arg && dt[1] != vect_internal_def)
6724 : : {
6725 : : /* Vector shl and shr insn patterns can be defined with scalar
6726 : : operand 2 (shift operand). In this case, use constant or loop
6727 : : invariant op1 directly, without extending it to vector mode
6728 : : first. */
6729 : 5004 : optab_op2_mode = insn_data[icode].operand[2].mode;
6730 : 5004 : if (!VECTOR_MODE_P (optab_op2_mode))
6731 : : {
6732 : 5004 : if (dump_enabled_p ())
6733 : 1723 : dump_printf_loc (MSG_NOTE, vect_location,
6734 : : "operand 1 using scalar mode.\n");
6735 : 5004 : vec_oprnd1 = op1;
6736 : 5004 : vec_oprnds1.create (slp_node ? slp_node->vec_stmts_size : ncopies);
6737 : 5004 : vec_oprnds1.quick_push (vec_oprnd1);
6738 : : /* Store vec_oprnd1 for every vector stmt to be created.
6739 : : We check during the analysis that all the shift arguments
6740 : : are the same.
6741 : : TODO: Allow different constants for different vector
6742 : : stmts generated for an SLP instance. */
6743 : 5004 : for (k = 0;
6744 : 7201 : k < (slp_node ? slp_node->vec_stmts_size - 1 : ncopies - 1); k++)
6745 : 2197 : vec_oprnds1.quick_push (vec_oprnd1);
6746 : : }
6747 : : }
6748 : 727 : else if (!scalar_shift_arg && slp_node && incompatible_op1_vectype_p)
6749 : : {
6750 : 0 : if (was_scalar_shift_arg)
6751 : : {
6752 : : /* If the argument was the same in all lanes create
6753 : : the correctly typed vector shift amount directly. */
6754 : 0 : op1 = fold_convert (TREE_TYPE (vectype), op1);
6755 : 0 : op1 = vect_init_vector (vinfo, stmt_info, op1, TREE_TYPE (vectype),
6756 : : !loop_vinfo ? gsi : NULL);
6757 : 0 : vec_oprnd1 = vect_init_vector (vinfo, stmt_info, op1, vectype,
6758 : : !loop_vinfo ? gsi : NULL);
6759 : 0 : vec_oprnds1.create (slp_node->vec_stmts_size);
6760 : 0 : for (k = 0; k < slp_node->vec_stmts_size; k++)
6761 : 0 : vec_oprnds1.quick_push (vec_oprnd1);
6762 : : }
6763 : 0 : else if (dt[1] == vect_constant_def)
6764 : : /* The constant shift amount has been adjusted in place. */
6765 : : ;
6766 : : else
6767 : 0 : gcc_assert (TYPE_MODE (op1_vectype) == TYPE_MODE (vectype));
6768 : : }
6769 : :
6770 : : /* vec_oprnd1 is available if operand 1 should be of a scalar-type
6771 : : (a special case for certain kind of vector shifts); otherwise,
6772 : : operand 1 should be of a vector type (the usual case). */
6773 : 727 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
6774 : : op0, &vec_oprnds0,
6775 : 5731 : vec_oprnd1 ? NULL_TREE : op1, &vec_oprnds1);
6776 : :
6777 : : /* Arguments are ready. Create the new vector stmt. */
6778 : 14038 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6779 : : {
6780 : : /* For internal defs where we need to use a scalar shift arg
6781 : : extract the first lane. */
6782 : 8307 : if (scalar_shift_arg && dt[1] == vect_internal_def)
6783 : : {
6784 : 10 : vop1 = vec_oprnds1[0];
6785 : 10 : new_temp = make_ssa_name (TREE_TYPE (TREE_TYPE (vop1)));
6786 : 10 : gassign *new_stmt
6787 : 10 : = gimple_build_assign (new_temp,
6788 : 10 : build3 (BIT_FIELD_REF, TREE_TYPE (new_temp),
6789 : : vop1,
6790 : 10 : TYPE_SIZE (TREE_TYPE (new_temp)),
6791 : : bitsize_zero_node));
6792 : 10 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6793 : 10 : vop1 = new_temp;
6794 : 10 : }
6795 : : else
6796 : 8297 : vop1 = vec_oprnds1[i];
6797 : 8307 : gassign *new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1);
6798 : 8307 : new_temp = make_ssa_name (vec_dest, new_stmt);
6799 : 8307 : gimple_assign_set_lhs (new_stmt, new_temp);
6800 : 8307 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6801 : 8307 : if (slp_node)
6802 : 8307 : slp_node->push_vec_def (new_stmt);
6803 : : else
6804 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
6805 : : }
6806 : :
6807 : 5731 : if (!slp_node)
6808 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
6809 : :
6810 : 5731 : vec_oprnds0.release ();
6811 : 5731 : vec_oprnds1.release ();
6812 : :
6813 : 5731 : return true;
6814 : : }
6815 : :
6816 : : /* Function vectorizable_operation.
6817 : :
6818 : : Check if STMT_INFO performs a binary, unary or ternary operation that can
6819 : : be vectorized.
6820 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
6821 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
6822 : : Return true if STMT_INFO is vectorizable in this way. */
6823 : :
6824 : : static bool
6825 : 2328577 : vectorizable_operation (vec_info *vinfo,
6826 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
6827 : : gimple **vec_stmt, slp_tree slp_node,
6828 : : stmt_vector_for_cost *cost_vec)
6829 : : {
6830 : 2328577 : tree vec_dest;
6831 : 2328577 : tree scalar_dest;
6832 : 2328577 : tree op0, op1 = NULL_TREE, op2 = NULL_TREE;
6833 : 2328577 : tree vectype;
6834 : 2328577 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
6835 : 2328577 : enum tree_code code, orig_code;
6836 : 2328577 : machine_mode vec_mode;
6837 : 2328577 : tree new_temp;
6838 : 2328577 : int op_type;
6839 : 2328577 : optab optab;
6840 : 2328577 : bool target_support_p;
6841 : 2328577 : enum vect_def_type dt[3]
6842 : : = {vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type};
6843 : 2328577 : int ndts = 3;
6844 : 2328577 : poly_uint64 nunits_in;
6845 : 2328577 : poly_uint64 nunits_out;
6846 : 2328577 : tree vectype_out;
6847 : 2328577 : unsigned int ncopies;
6848 : 2328577 : int vec_num;
6849 : 2328577 : int i;
6850 : 2328577 : vec<tree> vec_oprnds0 = vNULL;
6851 : 2328577 : vec<tree> vec_oprnds1 = vNULL;
6852 : 2328577 : vec<tree> vec_oprnds2 = vNULL;
6853 : 2328577 : tree vop0, vop1, vop2;
6854 : 2328577 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
6855 : :
6856 : 2328577 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
6857 : : return false;
6858 : :
6859 : 2328577 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
6860 : 186872 : && ! vec_stmt)
6861 : : return false;
6862 : :
6863 : : /* Is STMT a vectorizable binary/unary operation? */
6864 : 3897860 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
6865 : 2081932 : if (!stmt)
6866 : : return false;
6867 : :
6868 : : /* Loads and stores are handled in vectorizable_{load,store}. */
6869 : 2081932 : if (STMT_VINFO_DATA_REF (stmt_info))
6870 : : return false;
6871 : :
6872 : 819222 : orig_code = code = gimple_assign_rhs_code (stmt);
6873 : :
6874 : : /* Shifts are handled in vectorizable_shift. */
6875 : 819222 : if (code == LSHIFT_EXPR
6876 : : || code == RSHIFT_EXPR
6877 : : || code == LROTATE_EXPR
6878 : 819222 : || code == RROTATE_EXPR)
6879 : : return false;
6880 : :
6881 : : /* Comparisons are handled in vectorizable_comparison. */
6882 : 790884 : if (TREE_CODE_CLASS (code) == tcc_comparison)
6883 : : return false;
6884 : :
6885 : : /* Conditions are handled in vectorizable_condition. */
6886 : 628856 : if (code == COND_EXPR)
6887 : : return false;
6888 : :
6889 : : /* For pointer addition and subtraction, we should use the normal
6890 : : plus and minus for the vector operation. */
6891 : 609757 : if (code == POINTER_PLUS_EXPR)
6892 : : code = PLUS_EXPR;
6893 : 596071 : if (code == POINTER_DIFF_EXPR)
6894 : 1981 : code = MINUS_EXPR;
6895 : :
6896 : : /* Support only unary or binary operations. */
6897 : 609757 : op_type = TREE_CODE_LENGTH (code);
6898 : 609757 : if (op_type != unary_op && op_type != binary_op && op_type != ternary_op)
6899 : : {
6900 : 10 : if (dump_enabled_p ())
6901 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6902 : : "num. args = %d (not unary/binary/ternary op).\n",
6903 : : op_type);
6904 : 10 : return false;
6905 : : }
6906 : :
6907 : 609747 : scalar_dest = gimple_assign_lhs (stmt);
6908 : 609747 : vectype_out = STMT_VINFO_VECTYPE (stmt_info);
6909 : :
6910 : : /* Most operations cannot handle bit-precision types without extra
6911 : : truncations. */
6912 : 609747 : bool mask_op_p = VECTOR_BOOLEAN_TYPE_P (vectype_out);
6913 : 601349 : if (!mask_op_p
6914 : 601349 : && !type_has_mode_precision_p (TREE_TYPE (scalar_dest))
6915 : : /* Exception are bitwise binary operations. */
6916 : : && code != BIT_IOR_EXPR
6917 : 1298 : && code != BIT_XOR_EXPR
6918 : 1163 : && code != BIT_AND_EXPR)
6919 : : {
6920 : 924 : if (dump_enabled_p ())
6921 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6922 : : "bit-precision arithmetic not supported.\n");
6923 : 924 : return false;
6924 : : }
6925 : :
6926 : 608823 : slp_tree slp_op0;
6927 : 608823 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
6928 : : 0, &op0, &slp_op0, &dt[0], &vectype))
6929 : : {
6930 : 0 : if (dump_enabled_p ())
6931 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6932 : : "use not simple.\n");
6933 : 0 : return false;
6934 : : }
6935 : 608823 : bool is_invariant = (dt[0] == vect_external_def
6936 : 608823 : || dt[0] == vect_constant_def);
6937 : : /* If op0 is an external or constant def, infer the vector type
6938 : : from the scalar type. */
6939 : 608823 : if (!vectype)
6940 : : {
6941 : : /* For boolean type we cannot determine vectype by
6942 : : invariant value (don't know whether it is a vector
6943 : : of booleans or vector of integers). We use output
6944 : : vectype because operations on boolean don't change
6945 : : type. */
6946 : 59257 : if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op0)))
6947 : : {
6948 : 959 : if (!VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (scalar_dest)))
6949 : : {
6950 : 164 : if (dump_enabled_p ())
6951 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6952 : : "not supported operation on bool value.\n");
6953 : 164 : return false;
6954 : : }
6955 : 795 : vectype = vectype_out;
6956 : : }
6957 : : else
6958 : 58298 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0),
6959 : : slp_node);
6960 : : }
6961 : 608659 : if (vec_stmt)
6962 : 107477 : gcc_assert (vectype);
6963 : 608659 : if (!vectype)
6964 : : {
6965 : 1376 : if (dump_enabled_p ())
6966 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6967 : : "no vectype for scalar type %T\n",
6968 : 0 : TREE_TYPE (op0));
6969 : :
6970 : 1376 : return false;
6971 : : }
6972 : :
6973 : 607283 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
6974 : 607283 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
6975 : 607283 : if (maybe_ne (nunits_out, nunits_in)
6976 : 607283 : || !tree_nop_conversion_p (TREE_TYPE (vectype_out), TREE_TYPE (vectype)))
6977 : 16225 : return false;
6978 : :
6979 : 591058 : tree vectype2 = NULL_TREE, vectype3 = NULL_TREE;
6980 : 591058 : slp_tree slp_op1 = NULL, slp_op2 = NULL;
6981 : 591058 : if (op_type == binary_op || op_type == ternary_op)
6982 : : {
6983 : 529847 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
6984 : : 1, &op1, &slp_op1, &dt[1], &vectype2))
6985 : : {
6986 : 0 : if (dump_enabled_p ())
6987 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6988 : : "use not simple.\n");
6989 : 0 : return false;
6990 : : }
6991 : 529847 : is_invariant &= (dt[1] == vect_external_def
6992 : 529847 : || dt[1] == vect_constant_def);
6993 : 529847 : if (vectype2
6994 : 887699 : && (maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype2))
6995 : 357852 : || !tree_nop_conversion_p (TREE_TYPE (vectype_out),
6996 : 357852 : TREE_TYPE (vectype2))))
6997 : 326 : return false;
6998 : : }
6999 : 590732 : if (op_type == ternary_op)
7000 : : {
7001 : 0 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
7002 : : 2, &op2, &slp_op2, &dt[2], &vectype3))
7003 : : {
7004 : 0 : if (dump_enabled_p ())
7005 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7006 : : "use not simple.\n");
7007 : 0 : return false;
7008 : : }
7009 : 0 : is_invariant &= (dt[2] == vect_external_def
7010 : 0 : || dt[2] == vect_constant_def);
7011 : 0 : if (vectype3
7012 : 0 : && (maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype3))
7013 : 0 : || !tree_nop_conversion_p (TREE_TYPE (vectype_out),
7014 : 0 : TREE_TYPE (vectype3))))
7015 : 0 : return false;
7016 : : }
7017 : :
7018 : : /* Multiple types in SLP are handled by creating the appropriate number of
7019 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
7020 : : case of SLP. */
7021 : 590732 : if (slp_node)
7022 : : {
7023 : 590732 : ncopies = 1;
7024 : 590732 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
7025 : : }
7026 : : else
7027 : : {
7028 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
7029 : 0 : vec_num = 1;
7030 : : }
7031 : :
7032 : 590732 : gcc_assert (ncopies >= 1);
7033 : :
7034 : : /* Reject attempts to combine mask types with nonmask types, e.g. if
7035 : : we have an AND between a (nonmask) boolean loaded from memory and
7036 : : a (mask) boolean result of a comparison.
7037 : :
7038 : : TODO: We could easily fix these cases up using pattern statements. */
7039 : 590732 : if (VECTOR_BOOLEAN_TYPE_P (vectype) != mask_op_p
7040 : 944267 : || (vectype2 && VECTOR_BOOLEAN_TYPE_P (vectype2) != mask_op_p)
7041 : 1181452 : || (vectype3 && VECTOR_BOOLEAN_TYPE_P (vectype3) != mask_op_p))
7042 : : {
7043 : 12 : if (dump_enabled_p ())
7044 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7045 : : "mixed mask and nonmask vector types\n");
7046 : 12 : return false;
7047 : : }
7048 : :
7049 : : /* Supportable by target? */
7050 : :
7051 : 590720 : vec_mode = TYPE_MODE (vectype);
7052 : 590720 : optab = optab_for_tree_code (code, vectype, optab_default);
7053 : 590720 : if (!optab)
7054 : : {
7055 : 49249 : if (dump_enabled_p ())
7056 : 6763 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7057 : : "no optab.\n");
7058 : 49249 : return false;
7059 : : }
7060 : 541471 : target_support_p = can_implement_p (optab, vec_mode);
7061 : :
7062 : 541471 : bool using_emulated_vectors_p = vect_emulated_vector_p (vectype);
7063 : 541471 : if (!target_support_p || using_emulated_vectors_p)
7064 : : {
7065 : 34741 : if (dump_enabled_p ())
7066 : 1415 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7067 : : "op not supported by target.\n");
7068 : : /* When vec_mode is not a vector mode and we verified ops we
7069 : : do not have to lower like AND are natively supported let
7070 : : those through even when the mode isn't word_mode. For
7071 : : ops we have to lower the lowering code assumes we are
7072 : : dealing with word_mode. */
7073 : 69482 : if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype))
7074 : 34647 : || (((code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR)
7075 : 24449 : || !target_support_p)
7076 : 72271 : && maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD))
7077 : : /* Check only during analysis. */
7078 : 51430 : || (!vec_stmt && !vect_can_vectorize_without_simd_p (code)))
7079 : : {
7080 : 28652 : if (dump_enabled_p ())
7081 : 1383 : dump_printf (MSG_NOTE, "using word mode not possible.\n");
7082 : 28652 : return false;
7083 : : }
7084 : 6089 : if (dump_enabled_p ())
7085 : 32 : dump_printf_loc (MSG_NOTE, vect_location,
7086 : : "proceeding using word mode.\n");
7087 : : using_emulated_vectors_p = true;
7088 : : }
7089 : :
7090 : 512819 : int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info);
7091 : 512819 : vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL);
7092 : 358918 : vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL);
7093 : 512819 : internal_fn cond_fn = get_conditional_internal_fn (code);
7094 : 512819 : internal_fn cond_len_fn = get_conditional_len_internal_fn (code);
7095 : :
7096 : : /* If operating on inactive elements could generate spurious traps,
7097 : : we need to restrict the operation to active lanes. Note that this
7098 : : specifically doesn't apply to unhoisted invariants, since they
7099 : : operate on the same value for every lane.
7100 : :
7101 : : Similarly, if this operation is part of a reduction, a fully-masked
7102 : : loop should only change the active lanes of the reduction chain,
7103 : : keeping the inactive lanes as-is. */
7104 : 489771 : bool mask_out_inactive = ((!is_invariant && gimple_could_trap_p (stmt))
7105 : 945280 : || reduc_idx >= 0);
7106 : :
7107 : 512819 : if (!vec_stmt) /* transformation not required. */
7108 : : {
7109 : 405342 : if (loop_vinfo
7110 : 259284 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
7111 : 31 : && mask_out_inactive)
7112 : : {
7113 : 10 : if (cond_len_fn != IFN_LAST
7114 : 10 : && direct_internal_fn_supported_p (cond_len_fn, vectype,
7115 : : OPTIMIZE_FOR_SPEED))
7116 : 0 : vect_record_loop_len (loop_vinfo, lens, ncopies * vec_num, vectype,
7117 : : 1);
7118 : 10 : else if (cond_fn != IFN_LAST
7119 : 10 : && direct_internal_fn_supported_p (cond_fn, vectype,
7120 : : OPTIMIZE_FOR_SPEED))
7121 : 10 : vect_record_loop_mask (loop_vinfo, masks, ncopies * vec_num,
7122 : : vectype, NULL);
7123 : : else
7124 : : {
7125 : 0 : if (dump_enabled_p ())
7126 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7127 : : "can't use a fully-masked loop because no"
7128 : : " conditional operation is available.\n");
7129 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
7130 : : }
7131 : : }
7132 : :
7133 : : /* Put types on constant and invariant SLP children. */
7134 : 405342 : if (slp_node
7135 : 405342 : && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
7136 : 405188 : || !vect_maybe_update_slp_op_vectype (slp_op1, vectype)
7137 : 405172 : || !vect_maybe_update_slp_op_vectype (slp_op2, vectype)))
7138 : : {
7139 : 170 : if (dump_enabled_p ())
7140 : 3 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7141 : : "incompatible vector types for invariants\n");
7142 : 170 : return false;
7143 : : }
7144 : :
7145 : 405172 : STMT_VINFO_TYPE (stmt_info) = op_vec_info_type;
7146 : 405172 : DUMP_VECT_SCOPE ("vectorizable_operation");
7147 : 405172 : vect_model_simple_cost (vinfo, stmt_info,
7148 : : ncopies, dt, ndts, slp_node, cost_vec);
7149 : 405172 : if (using_emulated_vectors_p)
7150 : : {
7151 : : /* The above vect_model_simple_cost call handles constants
7152 : : in the prologue and (mis-)costs one of the stmts as
7153 : : vector stmt. See below for the actual lowering that will
7154 : : be applied. */
7155 : 12174 : unsigned n
7156 : 6087 : = slp_node ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies;
7157 : 6087 : switch (code)
7158 : : {
7159 : 2812 : case PLUS_EXPR:
7160 : 2812 : n *= 5;
7161 : 2812 : break;
7162 : 2578 : case MINUS_EXPR:
7163 : 2578 : n *= 6;
7164 : 2578 : break;
7165 : 6 : case NEGATE_EXPR:
7166 : 6 : n *= 4;
7167 : 6 : break;
7168 : : default:
7169 : : /* Bit operations do not have extra cost and are accounted
7170 : : as vector stmt by vect_model_simple_cost. */
7171 : : n = 0;
7172 : : break;
7173 : : }
7174 : 5396 : if (n != 0)
7175 : : {
7176 : : /* We also need to materialize two large constants. */
7177 : 5396 : record_stmt_cost (cost_vec, 2, scalar_stmt, stmt_info,
7178 : : 0, vect_prologue);
7179 : 5396 : record_stmt_cost (cost_vec, n, scalar_stmt, stmt_info,
7180 : : 0, vect_body);
7181 : : }
7182 : : }
7183 : 405172 : return true;
7184 : : }
7185 : :
7186 : : /* Transform. */
7187 : :
7188 : 107477 : if (dump_enabled_p ())
7189 : 15390 : dump_printf_loc (MSG_NOTE, vect_location,
7190 : : "transform binary/unary operation.\n");
7191 : :
7192 : 107477 : bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
7193 : 99634 : bool len_loop_p = loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
7194 : :
7195 : : /* POINTER_DIFF_EXPR has pointer arguments which are vectorized as
7196 : : vectors with unsigned elements, but the result is signed. So, we
7197 : : need to compute the MINUS_EXPR into vectype temporary and
7198 : : VIEW_CONVERT_EXPR it into the final vectype_out result. */
7199 : 107477 : tree vec_cvt_dest = NULL_TREE;
7200 : 107477 : if (orig_code == POINTER_DIFF_EXPR)
7201 : : {
7202 : 13 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
7203 : 13 : vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out);
7204 : : }
7205 : : /* Handle def. */
7206 : : else
7207 : 107464 : vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
7208 : :
7209 : : /* In case the vectorization factor (VF) is bigger than the number
7210 : : of elements that we can fit in a vectype (nunits), we have to generate
7211 : : more than one vector stmt - i.e - we need to "unroll" the
7212 : : vector stmt by a factor VF/nunits. In doing so, we record a pointer
7213 : : from one copy of the vector stmt to the next, in the field
7214 : : STMT_VINFO_RELATED_STMT. This is necessary in order to allow following
7215 : : stages to find the correct vector defs to be used when vectorizing
7216 : : stmts that use the defs of the current stmt. The example below
7217 : : illustrates the vectorization process when VF=16 and nunits=4 (i.e.,
7218 : : we need to create 4 vectorized stmts):
7219 : :
7220 : : before vectorization:
7221 : : RELATED_STMT VEC_STMT
7222 : : S1: x = memref - -
7223 : : S2: z = x + 1 - -
7224 : :
7225 : : step 1: vectorize stmt S1 (done in vectorizable_load. See more details
7226 : : there):
7227 : : RELATED_STMT VEC_STMT
7228 : : VS1_0: vx0 = memref0 VS1_1 -
7229 : : VS1_1: vx1 = memref1 VS1_2 -
7230 : : VS1_2: vx2 = memref2 VS1_3 -
7231 : : VS1_3: vx3 = memref3 - -
7232 : : S1: x = load - VS1_0
7233 : : S2: z = x + 1 - -
7234 : :
7235 : : step2: vectorize stmt S2 (done here):
7236 : : To vectorize stmt S2 we first need to find the relevant vector
7237 : : def for the first operand 'x'. This is, as usual, obtained from
7238 : : the vector stmt recorded in the STMT_VINFO_VEC_STMT of the stmt
7239 : : that defines 'x' (S1). This way we find the stmt VS1_0, and the
7240 : : relevant vector def 'vx0'. Having found 'vx0' we can generate
7241 : : the vector stmt VS2_0, and as usual, record it in the
7242 : : STMT_VINFO_VEC_STMT of stmt S2.
7243 : : When creating the second copy (VS2_1), we obtain the relevant vector
7244 : : def from the vector stmt recorded in the STMT_VINFO_RELATED_STMT of
7245 : : stmt VS1_0. This way we find the stmt VS1_1 and the relevant
7246 : : vector def 'vx1'. Using 'vx1' we create stmt VS2_1 and record a
7247 : : pointer to it in the STMT_VINFO_RELATED_STMT of the vector stmt VS2_0.
7248 : : Similarly when creating stmts VS2_2 and VS2_3. This is the resulting
7249 : : chain of stmts and pointers:
7250 : : RELATED_STMT VEC_STMT
7251 : : VS1_0: vx0 = memref0 VS1_1 -
7252 : : VS1_1: vx1 = memref1 VS1_2 -
7253 : : VS1_2: vx2 = memref2 VS1_3 -
7254 : : VS1_3: vx3 = memref3 - -
7255 : : S1: x = load - VS1_0
7256 : : VS2_0: vz0 = vx0 + v1 VS2_1 -
7257 : : VS2_1: vz1 = vx1 + v1 VS2_2 -
7258 : : VS2_2: vz2 = vx2 + v1 VS2_3 -
7259 : : VS2_3: vz3 = vx3 + v1 - -
7260 : : S2: z = x + 1 - VS2_0 */
7261 : :
7262 : 107477 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
7263 : : op0, &vec_oprnds0, op1, &vec_oprnds1, op2, &vec_oprnds2);
7264 : : /* Arguments are ready. Create the new vector stmt. */
7265 : 233602 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
7266 : : {
7267 : 126125 : gimple *new_stmt = NULL;
7268 : 252250 : vop1 = ((op_type == binary_op || op_type == ternary_op)
7269 : 126125 : ? vec_oprnds1[i] : NULL_TREE);
7270 : 126125 : vop2 = ((op_type == ternary_op) ? vec_oprnds2[i] : NULL_TREE);
7271 : 126125 : if (using_emulated_vectors_p
7272 : 2 : && (code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR))
7273 : : {
7274 : : /* Lower the operation. This follows vector lowering. */
7275 : 1 : unsigned int width = vector_element_bits (vectype);
7276 : 1 : tree inner_type = TREE_TYPE (vectype);
7277 : 1 : tree word_type
7278 : 1 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (word_mode), 1);
7279 : 1 : HOST_WIDE_INT max = GET_MODE_MASK (TYPE_MODE (inner_type));
7280 : 1 : tree low_bits = build_replicated_int_cst (word_type, width, max >> 1);
7281 : 1 : tree high_bits
7282 : 1 : = build_replicated_int_cst (word_type, width, max & ~(max >> 1));
7283 : 1 : tree wvop0 = make_ssa_name (word_type);
7284 : 1 : new_stmt = gimple_build_assign (wvop0, VIEW_CONVERT_EXPR,
7285 : : build1 (VIEW_CONVERT_EXPR,
7286 : : word_type, vop0));
7287 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7288 : 1 : tree result_low, signs;
7289 : 1 : if (code == PLUS_EXPR || code == MINUS_EXPR)
7290 : : {
7291 : 1 : tree wvop1 = make_ssa_name (word_type);
7292 : 1 : new_stmt = gimple_build_assign (wvop1, VIEW_CONVERT_EXPR,
7293 : : build1 (VIEW_CONVERT_EXPR,
7294 : : word_type, vop1));
7295 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7296 : 1 : signs = make_ssa_name (word_type);
7297 : 1 : new_stmt = gimple_build_assign (signs,
7298 : : BIT_XOR_EXPR, wvop0, wvop1);
7299 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7300 : 1 : tree b_low = make_ssa_name (word_type);
7301 : 1 : new_stmt = gimple_build_assign (b_low,
7302 : : BIT_AND_EXPR, wvop1, low_bits);
7303 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7304 : 1 : tree a_low = make_ssa_name (word_type);
7305 : 1 : if (code == PLUS_EXPR)
7306 : 1 : new_stmt = gimple_build_assign (a_low,
7307 : : BIT_AND_EXPR, wvop0, low_bits);
7308 : : else
7309 : 0 : new_stmt = gimple_build_assign (a_low,
7310 : : BIT_IOR_EXPR, wvop0, high_bits);
7311 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7312 : 1 : if (code == MINUS_EXPR)
7313 : : {
7314 : 0 : new_stmt = gimple_build_assign (NULL_TREE,
7315 : : BIT_NOT_EXPR, signs);
7316 : 0 : signs = make_ssa_name (word_type);
7317 : 0 : gimple_assign_set_lhs (new_stmt, signs);
7318 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7319 : : }
7320 : 1 : new_stmt = gimple_build_assign (NULL_TREE,
7321 : : BIT_AND_EXPR, signs, high_bits);
7322 : 1 : signs = make_ssa_name (word_type);
7323 : 1 : gimple_assign_set_lhs (new_stmt, signs);
7324 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7325 : 1 : result_low = make_ssa_name (word_type);
7326 : 1 : new_stmt = gimple_build_assign (result_low, code, a_low, b_low);
7327 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7328 : : }
7329 : : else
7330 : : {
7331 : 0 : tree a_low = make_ssa_name (word_type);
7332 : 0 : new_stmt = gimple_build_assign (a_low,
7333 : : BIT_AND_EXPR, wvop0, low_bits);
7334 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7335 : 0 : signs = make_ssa_name (word_type);
7336 : 0 : new_stmt = gimple_build_assign (signs, BIT_NOT_EXPR, wvop0);
7337 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7338 : 0 : new_stmt = gimple_build_assign (NULL_TREE,
7339 : : BIT_AND_EXPR, signs, high_bits);
7340 : 0 : signs = make_ssa_name (word_type);
7341 : 0 : gimple_assign_set_lhs (new_stmt, signs);
7342 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7343 : 0 : result_low = make_ssa_name (word_type);
7344 : 0 : new_stmt = gimple_build_assign (result_low,
7345 : : MINUS_EXPR, high_bits, a_low);
7346 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7347 : : }
7348 : 1 : new_stmt = gimple_build_assign (NULL_TREE, BIT_XOR_EXPR, result_low,
7349 : : signs);
7350 : 1 : result_low = make_ssa_name (word_type);
7351 : 1 : gimple_assign_set_lhs (new_stmt, result_low);
7352 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7353 : 1 : new_stmt = gimple_build_assign (NULL_TREE, VIEW_CONVERT_EXPR,
7354 : : build1 (VIEW_CONVERT_EXPR,
7355 : : vectype, result_low));
7356 : 1 : new_temp = make_ssa_name (vectype);
7357 : 1 : gimple_assign_set_lhs (new_stmt, new_temp);
7358 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7359 : 1 : }
7360 : 126124 : else if ((masked_loop_p || len_loop_p) && mask_out_inactive)
7361 : : {
7362 : 15 : tree mask;
7363 : 15 : if (masked_loop_p)
7364 : 15 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
7365 : 15 : vec_num * ncopies, vectype, i);
7366 : : else
7367 : : /* Dummy mask. */
7368 : 0 : mask = build_minus_one_cst (truth_type_for (vectype));
7369 : 15 : auto_vec<tree> vops (6);
7370 : 15 : vops.quick_push (mask);
7371 : 15 : vops.quick_push (vop0);
7372 : 15 : if (vop1)
7373 : 15 : vops.quick_push (vop1);
7374 : 15 : if (vop2)
7375 : 0 : vops.quick_push (vop2);
7376 : 15 : if (reduc_idx >= 0)
7377 : : {
7378 : : /* Perform the operation on active elements only and take
7379 : : inactive elements from the reduction chain input. */
7380 : 8 : gcc_assert (!vop2);
7381 : 8 : vops.quick_push (reduc_idx == 1 ? vop1 : vop0);
7382 : : }
7383 : : else
7384 : : {
7385 : 7 : auto else_value = targetm.preferred_else_value
7386 : 7 : (cond_fn, vectype, vops.length () - 1, &vops[1]);
7387 : 7 : vops.quick_push (else_value);
7388 : : }
7389 : 15 : if (len_loop_p)
7390 : : {
7391 : 0 : tree len = vect_get_loop_len (loop_vinfo, gsi, lens,
7392 : 0 : vec_num * ncopies, vectype, i, 1);
7393 : 0 : signed char biasval
7394 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
7395 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
7396 : 0 : vops.quick_push (len);
7397 : 0 : vops.quick_push (bias);
7398 : : }
7399 : 15 : gcall *call
7400 : 15 : = gimple_build_call_internal_vec (masked_loop_p ? cond_fn
7401 : : : cond_len_fn,
7402 : : vops);
7403 : 15 : new_temp = make_ssa_name (vec_dest, call);
7404 : 15 : gimple_call_set_lhs (call, new_temp);
7405 : 15 : gimple_call_set_nothrow (call, true);
7406 : 15 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
7407 : 15 : new_stmt = call;
7408 : 15 : }
7409 : : else
7410 : : {
7411 : 126109 : tree mask = NULL_TREE;
7412 : : /* When combining two masks check if either of them is elsewhere
7413 : : combined with a loop mask, if that's the case we can mark that the
7414 : : new combined mask doesn't need to be combined with a loop mask. */
7415 : 126109 : if (masked_loop_p
7416 : 126109 : && code == BIT_AND_EXPR
7417 : 126109 : && VECTOR_BOOLEAN_TYPE_P (vectype))
7418 : : {
7419 : 0 : if (loop_vinfo->scalar_cond_masked_set.contains ({ op0,
7420 : : ncopies}))
7421 : : {
7422 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
7423 : 0 : vec_num * ncopies, vectype, i);
7424 : :
7425 : 0 : vop0 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
7426 : : vop0, gsi);
7427 : : }
7428 : :
7429 : 0 : if (loop_vinfo->scalar_cond_masked_set.contains ({ op1,
7430 : : ncopies }))
7431 : : {
7432 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
7433 : 0 : vec_num * ncopies, vectype, i);
7434 : :
7435 : 0 : vop1 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
7436 : : vop1, gsi);
7437 : : }
7438 : : }
7439 : :
7440 : 126109 : new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1, vop2);
7441 : 126109 : new_temp = make_ssa_name (vec_dest, new_stmt);
7442 : 126109 : gimple_assign_set_lhs (new_stmt, new_temp);
7443 : 126109 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7444 : 126109 : if (using_emulated_vectors_p)
7445 : 1 : suppress_warning (new_stmt, OPT_Wvector_operation_performance);
7446 : :
7447 : : /* Enter the combined value into the vector cond hash so we don't
7448 : : AND it with a loop mask again. */
7449 : 126109 : if (mask)
7450 : 0 : loop_vinfo->vec_cond_masked_set.add ({ new_temp, mask });
7451 : : }
7452 : :
7453 : 126125 : if (vec_cvt_dest)
7454 : : {
7455 : 28 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype_out, new_temp);
7456 : 28 : new_stmt = gimple_build_assign (vec_cvt_dest, VIEW_CONVERT_EXPR,
7457 : : new_temp);
7458 : 28 : new_temp = make_ssa_name (vec_cvt_dest, new_stmt);
7459 : 28 : gimple_assign_set_lhs (new_stmt, new_temp);
7460 : 28 : vect_finish_stmt_generation (vinfo, stmt_info,
7461 : : new_stmt, gsi);
7462 : : }
7463 : :
7464 : 126125 : if (slp_node)
7465 : 126125 : slp_node->push_vec_def (new_stmt);
7466 : : else
7467 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
7468 : : }
7469 : :
7470 : 107477 : if (!slp_node)
7471 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
7472 : :
7473 : 107477 : vec_oprnds0.release ();
7474 : 107477 : vec_oprnds1.release ();
7475 : 107477 : vec_oprnds2.release ();
7476 : :
7477 : 107477 : return true;
7478 : : }
7479 : :
7480 : : /* A helper function to ensure data reference DR_INFO's base alignment. */
7481 : :
7482 : : static void
7483 : 1867084 : ensure_base_align (dr_vec_info *dr_info)
7484 : : {
7485 : : /* Alignment is only analyzed for the first element of a DR group,
7486 : : use that to look at base alignment we need to enforce. */
7487 : 1867084 : if (STMT_VINFO_GROUPED_ACCESS (dr_info->stmt))
7488 : 1426961 : dr_info = STMT_VINFO_DR_INFO (DR_GROUP_FIRST_ELEMENT (dr_info->stmt));
7489 : :
7490 : 1867084 : gcc_assert (dr_info->misalignment != DR_MISALIGNMENT_UNINITIALIZED);
7491 : :
7492 : 1867084 : if (dr_info->base_misaligned)
7493 : : {
7494 : 170856 : tree base_decl = dr_info->base_decl;
7495 : :
7496 : : // We should only be able to increase the alignment of a base object if
7497 : : // we know what its new alignment should be at compile time.
7498 : 170856 : unsigned HOST_WIDE_INT align_base_to =
7499 : 170856 : DR_TARGET_ALIGNMENT (dr_info).to_constant () * BITS_PER_UNIT;
7500 : :
7501 : 170856 : if (decl_in_symtab_p (base_decl))
7502 : 5515 : symtab_node::get (base_decl)->increase_alignment (align_base_to);
7503 : 165341 : else if (DECL_ALIGN (base_decl) < align_base_to)
7504 : : {
7505 : 133691 : SET_DECL_ALIGN (base_decl, align_base_to);
7506 : 133691 : DECL_USER_ALIGN (base_decl) = 1;
7507 : : }
7508 : 170856 : dr_info->base_misaligned = false;
7509 : : }
7510 : 1867084 : }
7511 : :
7512 : :
7513 : : /* Function get_group_alias_ptr_type.
7514 : :
7515 : : Return the alias type for the group starting at FIRST_STMT_INFO. */
7516 : :
7517 : : static tree
7518 : 1587607 : get_group_alias_ptr_type (stmt_vec_info first_stmt_info)
7519 : : {
7520 : 1587607 : struct data_reference *first_dr, *next_dr;
7521 : :
7522 : 1587607 : first_dr = STMT_VINFO_DATA_REF (first_stmt_info);
7523 : 1587607 : stmt_vec_info next_stmt_info = DR_GROUP_NEXT_ELEMENT (first_stmt_info);
7524 : 3812158 : while (next_stmt_info)
7525 : : {
7526 : 2353622 : next_dr = STMT_VINFO_DATA_REF (next_stmt_info);
7527 : 4707244 : if (get_alias_set (DR_REF (first_dr))
7528 : 2353622 : != get_alias_set (DR_REF (next_dr)))
7529 : : {
7530 : 129071 : if (dump_enabled_p ())
7531 : 4 : dump_printf_loc (MSG_NOTE, vect_location,
7532 : : "conflicting alias set types.\n");
7533 : 129071 : return ptr_type_node;
7534 : : }
7535 : 2224551 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
7536 : : }
7537 : 1458536 : return reference_alias_ptr_type (DR_REF (first_dr));
7538 : : }
7539 : :
7540 : :
7541 : : /* Function scan_operand_equal_p.
7542 : :
7543 : : Helper function for check_scan_store. Compare two references
7544 : : with .GOMP_SIMD_LANE bases. */
7545 : :
7546 : : static bool
7547 : 1284 : scan_operand_equal_p (tree ref1, tree ref2)
7548 : : {
7549 : 1284 : tree ref[2] = { ref1, ref2 };
7550 : 1284 : poly_int64 bitsize[2], bitpos[2];
7551 : : tree offset[2], base[2];
7552 : 3852 : for (int i = 0; i < 2; ++i)
7553 : : {
7554 : 2568 : machine_mode mode;
7555 : 2568 : int unsignedp, reversep, volatilep = 0;
7556 : 2568 : base[i] = get_inner_reference (ref[i], &bitsize[i], &bitpos[i],
7557 : : &offset[i], &mode, &unsignedp,
7558 : : &reversep, &volatilep);
7559 : 2568 : if (reversep || volatilep || maybe_ne (bitpos[i], 0))
7560 : 0 : return false;
7561 : 2568 : if (TREE_CODE (base[i]) == MEM_REF
7562 : 42 : && offset[i] == NULL_TREE
7563 : 2610 : && TREE_CODE (TREE_OPERAND (base[i], 0)) == SSA_NAME)
7564 : : {
7565 : 42 : gimple *def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (base[i], 0));
7566 : 42 : if (is_gimple_assign (def_stmt)
7567 : 42 : && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR
7568 : 42 : && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == ADDR_EXPR
7569 : 84 : && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME)
7570 : : {
7571 : 42 : if (maybe_ne (mem_ref_offset (base[i]), 0))
7572 : : return false;
7573 : 42 : base[i] = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0);
7574 : 42 : offset[i] = gimple_assign_rhs2 (def_stmt);
7575 : : }
7576 : : }
7577 : : }
7578 : :
7579 : 1284 : if (!operand_equal_p (base[0], base[1], 0))
7580 : : return false;
7581 : 934 : if (maybe_ne (bitsize[0], bitsize[1]))
7582 : : return false;
7583 : 934 : if (offset[0] != offset[1])
7584 : : {
7585 : 916 : if (!offset[0] || !offset[1])
7586 : : return false;
7587 : 916 : if (!operand_equal_p (offset[0], offset[1], 0))
7588 : : {
7589 : : tree step[2];
7590 : 0 : for (int i = 0; i < 2; ++i)
7591 : : {
7592 : 0 : step[i] = integer_one_node;
7593 : 0 : if (TREE_CODE (offset[i]) == SSA_NAME)
7594 : : {
7595 : 0 : gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]);
7596 : 0 : if (is_gimple_assign (def_stmt)
7597 : 0 : && gimple_assign_rhs_code (def_stmt) == MULT_EXPR
7598 : 0 : && (TREE_CODE (gimple_assign_rhs2 (def_stmt))
7599 : : == INTEGER_CST))
7600 : : {
7601 : 0 : step[i] = gimple_assign_rhs2 (def_stmt);
7602 : 0 : offset[i] = gimple_assign_rhs1 (def_stmt);
7603 : : }
7604 : : }
7605 : 0 : else if (TREE_CODE (offset[i]) == MULT_EXPR)
7606 : : {
7607 : 0 : step[i] = TREE_OPERAND (offset[i], 1);
7608 : 0 : offset[i] = TREE_OPERAND (offset[i], 0);
7609 : : }
7610 : 0 : tree rhs1 = NULL_TREE;
7611 : 0 : if (TREE_CODE (offset[i]) == SSA_NAME)
7612 : : {
7613 : 0 : gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]);
7614 : 0 : if (gimple_assign_cast_p (def_stmt))
7615 : 0 : rhs1 = gimple_assign_rhs1 (def_stmt);
7616 : : }
7617 : 0 : else if (CONVERT_EXPR_P (offset[i]))
7618 : 0 : rhs1 = TREE_OPERAND (offset[i], 0);
7619 : 0 : if (rhs1
7620 : 0 : && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
7621 : 0 : && INTEGRAL_TYPE_P (TREE_TYPE (offset[i]))
7622 : 0 : && (TYPE_PRECISION (TREE_TYPE (offset[i]))
7623 : 0 : >= TYPE_PRECISION (TREE_TYPE (rhs1))))
7624 : 0 : offset[i] = rhs1;
7625 : : }
7626 : 0 : if (!operand_equal_p (offset[0], offset[1], 0)
7627 : 0 : || !operand_equal_p (step[0], step[1], 0))
7628 : 0 : return false;
7629 : : }
7630 : : }
7631 : : return true;
7632 : : }
7633 : :
7634 : :
7635 : : enum scan_store_kind {
7636 : : /* Normal permutation. */
7637 : : scan_store_kind_perm,
7638 : :
7639 : : /* Whole vector left shift permutation with zero init. */
7640 : : scan_store_kind_lshift_zero,
7641 : :
7642 : : /* Whole vector left shift permutation and VEC_COND_EXPR. */
7643 : : scan_store_kind_lshift_cond
7644 : : };
7645 : :
7646 : : /* Function check_scan_store.
7647 : :
7648 : : Verify if we can perform the needed permutations or whole vector shifts.
7649 : : Return -1 on failure, otherwise exact log2 of vectype's nunits.
7650 : : USE_WHOLE_VECTOR is a vector of enum scan_store_kind which operation
7651 : : to do at each step. */
7652 : :
7653 : : static int
7654 : 1024 : scan_store_can_perm_p (tree vectype, tree init,
7655 : : vec<enum scan_store_kind> *use_whole_vector = NULL)
7656 : : {
7657 : 1024 : enum machine_mode vec_mode = TYPE_MODE (vectype);
7658 : 1024 : unsigned HOST_WIDE_INT nunits;
7659 : 1024 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits))
7660 : : return -1;
7661 : 1024 : int units_log2 = exact_log2 (nunits);
7662 : 1024 : if (units_log2 <= 0)
7663 : : return -1;
7664 : :
7665 : : int i;
7666 : : enum scan_store_kind whole_vector_shift_kind = scan_store_kind_perm;
7667 : 4784 : for (i = 0; i <= units_log2; ++i)
7668 : : {
7669 : 3760 : unsigned HOST_WIDE_INT j, k;
7670 : 3760 : enum scan_store_kind kind = scan_store_kind_perm;
7671 : 3760 : vec_perm_builder sel (nunits, nunits, 1);
7672 : 3760 : sel.quick_grow (nunits);
7673 : 3760 : if (i == units_log2)
7674 : : {
7675 : 9728 : for (j = 0; j < nunits; ++j)
7676 : 8704 : sel[j] = nunits - 1;
7677 : : }
7678 : : else
7679 : : {
7680 : 10416 : for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j)
7681 : 7680 : sel[j] = j;
7682 : 26416 : for (k = 0; j < nunits; ++j, ++k)
7683 : 23680 : sel[j] = nunits + k;
7684 : : }
7685 : 6496 : vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits);
7686 : 3760 : if (!can_vec_perm_const_p (vec_mode, vec_mode, indices))
7687 : : {
7688 : 0 : if (i == units_log2)
7689 : : return -1;
7690 : :
7691 : 0 : if (whole_vector_shift_kind == scan_store_kind_perm)
7692 : : {
7693 : 0 : if (!can_implement_p (vec_shl_optab, vec_mode))
7694 : : return -1;
7695 : 0 : whole_vector_shift_kind = scan_store_kind_lshift_zero;
7696 : : /* Whole vector shifts shift in zeros, so if init is all zero
7697 : : constant, there is no need to do anything further. */
7698 : 0 : if ((TREE_CODE (init) != INTEGER_CST
7699 : 0 : && TREE_CODE (init) != REAL_CST)
7700 : 0 : || !initializer_zerop (init))
7701 : : {
7702 : 0 : tree masktype = truth_type_for (vectype);
7703 : 0 : if (!expand_vec_cond_expr_p (vectype, masktype))
7704 : : return -1;
7705 : : whole_vector_shift_kind = scan_store_kind_lshift_cond;
7706 : : }
7707 : : }
7708 : 0 : kind = whole_vector_shift_kind;
7709 : : }
7710 : 3760 : if (use_whole_vector)
7711 : : {
7712 : 1880 : if (kind != scan_store_kind_perm && use_whole_vector->is_empty ())
7713 : 0 : use_whole_vector->safe_grow_cleared (i, true);
7714 : 5640 : if (kind != scan_store_kind_perm || !use_whole_vector->is_empty ())
7715 : 0 : use_whole_vector->safe_push (kind);
7716 : : }
7717 : 3760 : }
7718 : :
7719 : : return units_log2;
7720 : : }
7721 : :
7722 : :
7723 : : /* Function check_scan_store.
7724 : :
7725 : : Check magic stores for #pragma omp scan {in,ex}clusive reductions. */
7726 : :
7727 : : static bool
7728 : 1076 : check_scan_store (vec_info *vinfo, stmt_vec_info stmt_info, tree vectype,
7729 : : enum vect_def_type rhs_dt, slp_tree slp_node, tree mask,
7730 : : vect_memory_access_type memory_access_type)
7731 : : {
7732 : 1076 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
7733 : 1076 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
7734 : 1076 : tree ref_type;
7735 : :
7736 : 1076 : gcc_assert (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1);
7737 : 1076 : if ((slp_node && SLP_TREE_LANES (slp_node) > 1)
7738 : 1076 : || mask
7739 : 1076 : || memory_access_type != VMAT_CONTIGUOUS
7740 : 1076 : || TREE_CODE (DR_BASE_ADDRESS (dr_info->dr)) != ADDR_EXPR
7741 : 1076 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0))
7742 : 1076 : || loop_vinfo == NULL
7743 : 1076 : || LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
7744 : 1076 : || STMT_VINFO_GROUPED_ACCESS (stmt_info)
7745 : 1076 : || !integer_zerop (get_dr_vinfo_offset (vinfo, dr_info))
7746 : 1076 : || !integer_zerop (DR_INIT (dr_info->dr))
7747 : 1076 : || !(ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr)))
7748 : 2152 : || !alias_sets_conflict_p (get_alias_set (vectype),
7749 : 1076 : get_alias_set (TREE_TYPE (ref_type))))
7750 : : {
7751 : 0 : if (dump_enabled_p ())
7752 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7753 : : "unsupported OpenMP scan store.\n");
7754 : 0 : return false;
7755 : : }
7756 : :
7757 : : /* We need to pattern match code built by OpenMP lowering and simplified
7758 : : by following optimizations into something we can handle.
7759 : : #pragma omp simd reduction(inscan,+:r)
7760 : : for (...)
7761 : : {
7762 : : r += something ();
7763 : : #pragma omp scan inclusive (r)
7764 : : use (r);
7765 : : }
7766 : : shall have body with:
7767 : : // Initialization for input phase, store the reduction initializer:
7768 : : _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0);
7769 : : _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1);
7770 : : D.2042[_21] = 0;
7771 : : // Actual input phase:
7772 : : ...
7773 : : r.0_5 = D.2042[_20];
7774 : : _6 = _4 + r.0_5;
7775 : : D.2042[_20] = _6;
7776 : : // Initialization for scan phase:
7777 : : _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 2);
7778 : : _26 = D.2043[_25];
7779 : : _27 = D.2042[_25];
7780 : : _28 = _26 + _27;
7781 : : D.2043[_25] = _28;
7782 : : D.2042[_25] = _28;
7783 : : // Actual scan phase:
7784 : : ...
7785 : : r.1_8 = D.2042[_20];
7786 : : ...
7787 : : The "omp simd array" variable D.2042 holds the privatized copy used
7788 : : inside of the loop and D.2043 is another one that holds copies of
7789 : : the current original list item. The separate GOMP_SIMD_LANE ifn
7790 : : kinds are there in order to allow optimizing the initializer store
7791 : : and combiner sequence, e.g. if it is originally some C++ish user
7792 : : defined reduction, but allow the vectorizer to pattern recognize it
7793 : : and turn into the appropriate vectorized scan.
7794 : :
7795 : : For exclusive scan, this is slightly different:
7796 : : #pragma omp simd reduction(inscan,+:r)
7797 : : for (...)
7798 : : {
7799 : : use (r);
7800 : : #pragma omp scan exclusive (r)
7801 : : r += something ();
7802 : : }
7803 : : shall have body with:
7804 : : // Initialization for input phase, store the reduction initializer:
7805 : : _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0);
7806 : : _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1);
7807 : : D.2042[_21] = 0;
7808 : : // Actual input phase:
7809 : : ...
7810 : : r.0_5 = D.2042[_20];
7811 : : _6 = _4 + r.0_5;
7812 : : D.2042[_20] = _6;
7813 : : // Initialization for scan phase:
7814 : : _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 3);
7815 : : _26 = D.2043[_25];
7816 : : D.2044[_25] = _26;
7817 : : _27 = D.2042[_25];
7818 : : _28 = _26 + _27;
7819 : : D.2043[_25] = _28;
7820 : : // Actual scan phase:
7821 : : ...
7822 : : r.1_8 = D.2044[_20];
7823 : : ... */
7824 : :
7825 : 1076 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 2)
7826 : : {
7827 : : /* Match the D.2042[_21] = 0; store above. Just require that
7828 : : it is a constant or external definition store. */
7829 : 564 : if (rhs_dt != vect_constant_def && rhs_dt != vect_external_def)
7830 : : {
7831 : 0 : fail_init:
7832 : 0 : if (dump_enabled_p ())
7833 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7834 : : "unsupported OpenMP scan initializer store.\n");
7835 : 0 : return false;
7836 : : }
7837 : :
7838 : 564 : if (! loop_vinfo->scan_map)
7839 : 322 : loop_vinfo->scan_map = new hash_map<tree, tree>;
7840 : 564 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7841 : 564 : tree &cached = loop_vinfo->scan_map->get_or_insert (var);
7842 : 564 : if (cached)
7843 : 0 : goto fail_init;
7844 : 564 : cached = gimple_assign_rhs1 (STMT_VINFO_STMT (stmt_info));
7845 : :
7846 : : /* These stores can be vectorized normally. */
7847 : 564 : return true;
7848 : : }
7849 : :
7850 : 512 : if (rhs_dt != vect_internal_def)
7851 : : {
7852 : 0 : fail:
7853 : 0 : if (dump_enabled_p ())
7854 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7855 : : "unsupported OpenMP scan combiner pattern.\n");
7856 : 0 : return false;
7857 : : }
7858 : :
7859 : 512 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
7860 : 512 : tree rhs = gimple_assign_rhs1 (stmt);
7861 : 512 : if (TREE_CODE (rhs) != SSA_NAME)
7862 : 0 : goto fail;
7863 : :
7864 : 512 : gimple *other_store_stmt = NULL;
7865 : 512 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7866 : 512 : bool inscan_var_store
7867 : 512 : = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL;
7868 : :
7869 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7870 : : {
7871 : 252 : if (!inscan_var_store)
7872 : : {
7873 : 126 : use_operand_p use_p;
7874 : 126 : imm_use_iterator iter;
7875 : 378 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7876 : : {
7877 : 252 : gimple *use_stmt = USE_STMT (use_p);
7878 : 252 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7879 : 126 : continue;
7880 : 126 : if (gimple_bb (use_stmt) != gimple_bb (stmt)
7881 : 126 : || !is_gimple_assign (use_stmt)
7882 : 126 : || gimple_assign_rhs_class (use_stmt) != GIMPLE_BINARY_RHS
7883 : 126 : || other_store_stmt
7884 : 252 : || TREE_CODE (gimple_assign_lhs (use_stmt)) != SSA_NAME)
7885 : 0 : goto fail;
7886 : 126 : other_store_stmt = use_stmt;
7887 : : }
7888 : 126 : if (other_store_stmt == NULL)
7889 : 0 : goto fail;
7890 : 126 : rhs = gimple_assign_lhs (other_store_stmt);
7891 : 126 : if (!single_imm_use (rhs, &use_p, &other_store_stmt))
7892 : 0 : goto fail;
7893 : : }
7894 : : }
7895 : 260 : else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3)
7896 : : {
7897 : 260 : use_operand_p use_p;
7898 : 260 : imm_use_iterator iter;
7899 : 780 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7900 : : {
7901 : 520 : gimple *use_stmt = USE_STMT (use_p);
7902 : 520 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7903 : 260 : continue;
7904 : 260 : if (other_store_stmt)
7905 : 0 : goto fail;
7906 : 260 : other_store_stmt = use_stmt;
7907 : : }
7908 : : }
7909 : : else
7910 : 0 : goto fail;
7911 : :
7912 : 512 : gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
7913 : 512 : if (gimple_bb (def_stmt) != gimple_bb (stmt)
7914 : 512 : || !is_gimple_assign (def_stmt)
7915 : 1024 : || gimple_assign_rhs_class (def_stmt) != GIMPLE_BINARY_RHS)
7916 : 0 : goto fail;
7917 : :
7918 : 512 : enum tree_code code = gimple_assign_rhs_code (def_stmt);
7919 : : /* For pointer addition, we should use the normal plus for the vector
7920 : : operation. */
7921 : 512 : switch (code)
7922 : : {
7923 : 0 : case POINTER_PLUS_EXPR:
7924 : 0 : code = PLUS_EXPR;
7925 : 0 : break;
7926 : 0 : case MULT_HIGHPART_EXPR:
7927 : 0 : goto fail;
7928 : : default:
7929 : : break;
7930 : : }
7931 : 512 : if (TREE_CODE_LENGTH (code) != binary_op || !commutative_tree_code (code))
7932 : 0 : goto fail;
7933 : :
7934 : 512 : tree rhs1 = gimple_assign_rhs1 (def_stmt);
7935 : 512 : tree rhs2 = gimple_assign_rhs2 (def_stmt);
7936 : 512 : if (TREE_CODE (rhs1) != SSA_NAME || TREE_CODE (rhs2) != SSA_NAME)
7937 : 0 : goto fail;
7938 : :
7939 : 512 : gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1);
7940 : 512 : gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2);
7941 : 512 : if (gimple_bb (load1_stmt) != gimple_bb (stmt)
7942 : 512 : || !gimple_assign_load_p (load1_stmt)
7943 : 512 : || gimple_bb (load2_stmt) != gimple_bb (stmt)
7944 : 1024 : || !gimple_assign_load_p (load2_stmt))
7945 : 0 : goto fail;
7946 : :
7947 : 512 : stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt);
7948 : 512 : stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt);
7949 : 512 : if (load1_stmt_info == NULL
7950 : 512 : || load2_stmt_info == NULL
7951 : 512 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (load1_stmt_info)
7952 : 512 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info))
7953 : 512 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (load2_stmt_info)
7954 : 512 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)))
7955 : 0 : goto fail;
7956 : :
7957 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && inscan_var_store)
7958 : : {
7959 : 126 : dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info);
7960 : 126 : if (TREE_CODE (DR_BASE_ADDRESS (load1_dr_info->dr)) != ADDR_EXPR
7961 : 126 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0)))
7962 : 0 : goto fail;
7963 : 126 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0);
7964 : 126 : tree lrhs;
7965 : 126 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7966 : : lrhs = rhs1;
7967 : : else
7968 : 16 : lrhs = rhs2;
7969 : 126 : use_operand_p use_p;
7970 : 126 : imm_use_iterator iter;
7971 : 378 : FOR_EACH_IMM_USE_FAST (use_p, iter, lrhs)
7972 : : {
7973 : 252 : gimple *use_stmt = USE_STMT (use_p);
7974 : 252 : if (use_stmt == def_stmt || is_gimple_debug (use_stmt))
7975 : 126 : continue;
7976 : 126 : if (other_store_stmt)
7977 : 0 : goto fail;
7978 : 126 : other_store_stmt = use_stmt;
7979 : : }
7980 : : }
7981 : :
7982 : 512 : if (other_store_stmt == NULL)
7983 : 0 : goto fail;
7984 : 512 : if (gimple_bb (other_store_stmt) != gimple_bb (stmt)
7985 : 512 : || !gimple_store_p (other_store_stmt))
7986 : 0 : goto fail;
7987 : :
7988 : 512 : stmt_vec_info other_store_stmt_info
7989 : 512 : = loop_vinfo->lookup_stmt (other_store_stmt);
7990 : 512 : if (other_store_stmt_info == NULL
7991 : 512 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (other_store_stmt_info)
7992 : 512 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)))
7993 : 0 : goto fail;
7994 : :
7995 : 512 : gimple *stmt1 = stmt;
7996 : 512 : gimple *stmt2 = other_store_stmt;
7997 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7998 : : std::swap (stmt1, stmt2);
7999 : 512 : if (scan_operand_equal_p (gimple_assign_lhs (stmt1),
8000 : : gimple_assign_rhs1 (load2_stmt)))
8001 : : {
8002 : 162 : std::swap (rhs1, rhs2);
8003 : 162 : std::swap (load1_stmt, load2_stmt);
8004 : 162 : std::swap (load1_stmt_info, load2_stmt_info);
8005 : : }
8006 : 512 : if (!scan_operand_equal_p (gimple_assign_lhs (stmt1),
8007 : : gimple_assign_rhs1 (load1_stmt)))
8008 : 0 : goto fail;
8009 : :
8010 : 512 : tree var3 = NULL_TREE;
8011 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3
8012 : 512 : && !scan_operand_equal_p (gimple_assign_lhs (stmt2),
8013 : : gimple_assign_rhs1 (load2_stmt)))
8014 : 0 : goto fail;
8015 : 512 : else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
8016 : : {
8017 : 252 : dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info);
8018 : 252 : if (TREE_CODE (DR_BASE_ADDRESS (load2_dr_info->dr)) != ADDR_EXPR
8019 : 252 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0)))
8020 : 0 : goto fail;
8021 : 252 : var3 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0);
8022 : 252 : if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var3))
8023 : 252 : || lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var3))
8024 : 504 : || lookup_attribute ("omp simd inscan exclusive",
8025 : 252 : DECL_ATTRIBUTES (var3)))
8026 : 0 : goto fail;
8027 : : }
8028 : :
8029 : 512 : dr_vec_info *other_dr_info = STMT_VINFO_DR_INFO (other_store_stmt_info);
8030 : 512 : if (TREE_CODE (DR_BASE_ADDRESS (other_dr_info->dr)) != ADDR_EXPR
8031 : 512 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0)))
8032 : 0 : goto fail;
8033 : :
8034 : 512 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
8035 : 512 : tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0);
8036 : 512 : if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var1))
8037 : 512 : || !lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var2))
8038 : 1024 : || (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
8039 : 512 : == (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var2))))
8040 : 0 : goto fail;
8041 : :
8042 : 512 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
8043 : 256 : std::swap (var1, var2);
8044 : :
8045 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
8046 : : {
8047 : 252 : if (!lookup_attribute ("omp simd inscan exclusive",
8048 : 252 : DECL_ATTRIBUTES (var1)))
8049 : 0 : goto fail;
8050 : 252 : var1 = var3;
8051 : : }
8052 : :
8053 : 512 : if (loop_vinfo->scan_map == NULL)
8054 : 0 : goto fail;
8055 : 512 : tree *init = loop_vinfo->scan_map->get (var1);
8056 : 512 : if (init == NULL)
8057 : 0 : goto fail;
8058 : :
8059 : : /* The IL is as expected, now check if we can actually vectorize it.
8060 : : Inclusive scan:
8061 : : _26 = D.2043[_25];
8062 : : _27 = D.2042[_25];
8063 : : _28 = _26 + _27;
8064 : : D.2043[_25] = _28;
8065 : : D.2042[_25] = _28;
8066 : : should be vectorized as (where _40 is the vectorized rhs
8067 : : from the D.2042[_21] = 0; store):
8068 : : _30 = MEM <vector(8) int> [(int *)&D.2043];
8069 : : _31 = MEM <vector(8) int> [(int *)&D.2042];
8070 : : _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
8071 : : _33 = _31 + _32;
8072 : : // _33 = { _31[0], _31[0]+_31[1], _31[1]+_31[2], ..., _31[6]+_31[7] };
8073 : : _34 = VEC_PERM_EXPR <_40, _33, { 0, 1, 8, 9, 10, 11, 12, 13 }>;
8074 : : _35 = _33 + _34;
8075 : : // _35 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
8076 : : // _31[1]+.._31[4], ... _31[4]+.._31[7] };
8077 : : _36 = VEC_PERM_EXPR <_40, _35, { 0, 1, 2, 3, 8, 9, 10, 11 }>;
8078 : : _37 = _35 + _36;
8079 : : // _37 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
8080 : : // _31[0]+.._31[4], ... _31[0]+.._31[7] };
8081 : : _38 = _30 + _37;
8082 : : _39 = VEC_PERM_EXPR <_38, _38, { 7, 7, 7, 7, 7, 7, 7, 7 }>;
8083 : : MEM <vector(8) int> [(int *)&D.2043] = _39;
8084 : : MEM <vector(8) int> [(int *)&D.2042] = _38;
8085 : : Exclusive scan:
8086 : : _26 = D.2043[_25];
8087 : : D.2044[_25] = _26;
8088 : : _27 = D.2042[_25];
8089 : : _28 = _26 + _27;
8090 : : D.2043[_25] = _28;
8091 : : should be vectorized as (where _40 is the vectorized rhs
8092 : : from the D.2042[_21] = 0; store):
8093 : : _30 = MEM <vector(8) int> [(int *)&D.2043];
8094 : : _31 = MEM <vector(8) int> [(int *)&D.2042];
8095 : : _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
8096 : : _33 = VEC_PERM_EXPR <_40, _32, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
8097 : : _34 = _32 + _33;
8098 : : // _34 = { 0, _31[0], _31[0]+_31[1], _31[1]+_31[2], _31[2]+_31[3],
8099 : : // _31[3]+_31[4], ... _31[5]+.._31[6] };
8100 : : _35 = VEC_PERM_EXPR <_40, _34, { 0, 1, 8, 9, 10, 11, 12, 13 }>;
8101 : : _36 = _34 + _35;
8102 : : // _36 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
8103 : : // _31[1]+.._31[4], ... _31[3]+.._31[6] };
8104 : : _37 = VEC_PERM_EXPR <_40, _36, { 0, 1, 2, 3, 8, 9, 10, 11 }>;
8105 : : _38 = _36 + _37;
8106 : : // _38 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
8107 : : // _31[0]+.._31[4], ... _31[0]+.._31[6] };
8108 : : _39 = _30 + _38;
8109 : : _50 = _31 + _39;
8110 : : _51 = VEC_PERM_EXPR <_50, _50, { 7, 7, 7, 7, 7, 7, 7, 7 }>;
8111 : : MEM <vector(8) int> [(int *)&D.2044] = _39;
8112 : : MEM <vector(8) int> [(int *)&D.2042] = _51; */
8113 : 512 : enum machine_mode vec_mode = TYPE_MODE (vectype);
8114 : 512 : optab optab = optab_for_tree_code (code, vectype, optab_default);
8115 : 512 : if (!optab || !can_implement_p (optab, vec_mode))
8116 : 0 : goto fail;
8117 : :
8118 : 512 : int units_log2 = scan_store_can_perm_p (vectype, *init);
8119 : 512 : if (units_log2 == -1)
8120 : 0 : goto fail;
8121 : :
8122 : : return true;
8123 : : }
8124 : :
8125 : :
8126 : : /* Function vectorizable_scan_store.
8127 : :
8128 : : Helper of vectorizable_score, arguments like on vectorizable_store.
8129 : : Handle only the transformation, checking is done in check_scan_store. */
8130 : :
8131 : : static bool
8132 : 512 : vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
8133 : : slp_tree slp_node, gimple_stmt_iterator *gsi,
8134 : : gimple **vec_stmt, int ncopies)
8135 : : {
8136 : 512 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
8137 : 512 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
8138 : 512 : tree ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr));
8139 : 512 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
8140 : :
8141 : 512 : if (dump_enabled_p ())
8142 : 492 : dump_printf_loc (MSG_NOTE, vect_location,
8143 : : "transform scan store. ncopies = %d\n", ncopies);
8144 : :
8145 : 512 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
8146 : 512 : tree rhs = gimple_assign_rhs1 (stmt);
8147 : 512 : gcc_assert (TREE_CODE (rhs) == SSA_NAME);
8148 : :
8149 : 512 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
8150 : 512 : bool inscan_var_store
8151 : 512 : = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL;
8152 : :
8153 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
8154 : : {
8155 : 126 : use_operand_p use_p;
8156 : 126 : imm_use_iterator iter;
8157 : 126 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
8158 : : {
8159 : 126 : gimple *use_stmt = USE_STMT (use_p);
8160 : 126 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
8161 : 0 : continue;
8162 : 126 : rhs = gimple_assign_lhs (use_stmt);
8163 : 126 : break;
8164 : : }
8165 : : }
8166 : :
8167 : 512 : gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
8168 : 512 : enum tree_code code = gimple_assign_rhs_code (def_stmt);
8169 : 512 : if (code == POINTER_PLUS_EXPR)
8170 : 0 : code = PLUS_EXPR;
8171 : 512 : gcc_assert (TREE_CODE_LENGTH (code) == binary_op
8172 : : && commutative_tree_code (code));
8173 : 512 : tree rhs1 = gimple_assign_rhs1 (def_stmt);
8174 : 512 : tree rhs2 = gimple_assign_rhs2 (def_stmt);
8175 : 512 : gcc_assert (TREE_CODE (rhs1) == SSA_NAME && TREE_CODE (rhs2) == SSA_NAME);
8176 : 512 : gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1);
8177 : 512 : gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2);
8178 : 512 : stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt);
8179 : 512 : stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt);
8180 : 512 : dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info);
8181 : 512 : dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info);
8182 : 512 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0);
8183 : 512 : tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0);
8184 : :
8185 : 512 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
8186 : : {
8187 : 436 : std::swap (rhs1, rhs2);
8188 : 436 : std::swap (var1, var2);
8189 : 436 : std::swap (load1_dr_info, load2_dr_info);
8190 : : }
8191 : :
8192 : 512 : tree *init = loop_vinfo->scan_map->get (var1);
8193 : 512 : gcc_assert (init);
8194 : :
8195 : 512 : unsigned HOST_WIDE_INT nunits;
8196 : 512 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits))
8197 : : gcc_unreachable ();
8198 : 512 : auto_vec<enum scan_store_kind, 16> use_whole_vector;
8199 : 512 : int units_log2 = scan_store_can_perm_p (vectype, *init, &use_whole_vector);
8200 : 512 : gcc_assert (units_log2 > 0);
8201 : 512 : auto_vec<tree, 16> perms;
8202 : 512 : perms.quick_grow (units_log2 + 1);
8203 : 512 : tree zero_vec = NULL_TREE, masktype = NULL_TREE;
8204 : 2392 : for (int i = 0; i <= units_log2; ++i)
8205 : : {
8206 : 1880 : unsigned HOST_WIDE_INT j, k;
8207 : 1880 : vec_perm_builder sel (nunits, nunits, 1);
8208 : 1880 : sel.quick_grow (nunits);
8209 : 1880 : if (i == units_log2)
8210 : 4864 : for (j = 0; j < nunits; ++j)
8211 : 4352 : sel[j] = nunits - 1;
8212 : : else
8213 : : {
8214 : 5208 : for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j)
8215 : 3840 : sel[j] = j;
8216 : 13208 : for (k = 0; j < nunits; ++j, ++k)
8217 : 11840 : sel[j] = nunits + k;
8218 : : }
8219 : 3248 : vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits);
8220 : 1880 : if (!use_whole_vector.is_empty ()
8221 : 0 : && use_whole_vector[i] != scan_store_kind_perm)
8222 : : {
8223 : 0 : if (zero_vec == NULL_TREE)
8224 : 0 : zero_vec = build_zero_cst (vectype);
8225 : 0 : if (masktype == NULL_TREE
8226 : 0 : && use_whole_vector[i] == scan_store_kind_lshift_cond)
8227 : 0 : masktype = truth_type_for (vectype);
8228 : 0 : perms[i] = vect_gen_perm_mask_any (vectype, indices);
8229 : : }
8230 : : else
8231 : 1880 : perms[i] = vect_gen_perm_mask_checked (vectype, indices);
8232 : 1880 : }
8233 : :
8234 : 512 : tree vec_oprnd1 = NULL_TREE;
8235 : 512 : tree vec_oprnd2 = NULL_TREE;
8236 : 512 : tree vec_oprnd3 = NULL_TREE;
8237 : 512 : tree dataref_ptr = DR_BASE_ADDRESS (dr_info->dr);
8238 : 512 : tree dataref_offset = build_int_cst (ref_type, 0);
8239 : 512 : tree bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info,
8240 : : vectype, VMAT_CONTIGUOUS);
8241 : 512 : tree ldataref_ptr = NULL_TREE;
8242 : 512 : tree orig = NULL_TREE;
8243 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
8244 : 126 : ldataref_ptr = DR_BASE_ADDRESS (load1_dr_info->dr);
8245 : : /* The initialization is invariant. */
8246 : 512 : vec_oprnd1 = vect_init_vector (vinfo, stmt_info, *init, vectype, NULL);
8247 : 512 : auto_vec<tree> vec_oprnds2;
8248 : 512 : auto_vec<tree> vec_oprnds3;
8249 : 512 : if (ldataref_ptr == NULL)
8250 : : {
8251 : : /* We want to lookup the vector operands of the reduction, not those
8252 : : of the store - for SLP we have to use the proper SLP node for the
8253 : : lookup, which should be the single child of the scan store. */
8254 : 386 : vect_get_vec_defs (vinfo, stmt_info, SLP_TREE_CHILDREN (slp_node)[0],
8255 : : ncopies, rhs1, &vec_oprnds2, rhs2, &vec_oprnds3);
8256 : : /* ??? For SLP we do not key the def on 'rhs1' or 'rhs2' but get
8257 : : them in SLP child order. So we have to swap here with logic
8258 : : similar to above. */
8259 : 386 : stmt_vec_info load
8260 : 386 : = SLP_TREE_SCALAR_STMTS (SLP_TREE_CHILDREN
8261 : 386 : (SLP_TREE_CHILDREN (slp_node)[0])[0])[0];
8262 : 386 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (load);
8263 : 386 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
8264 : 386 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)))
8265 : 820 : for (unsigned i = 0; i < vec_oprnds2.length (); ++i)
8266 : 494 : std::swap (vec_oprnds2[i], vec_oprnds3[i]);;
8267 : : }
8268 : : else
8269 : 126 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
8270 : : rhs2, &vec_oprnds3);
8271 : 1248 : for (unsigned j = 0; j < vec_oprnds3.length (); j++)
8272 : : {
8273 : 736 : if (ldataref_ptr == NULL)
8274 : 554 : vec_oprnd2 = vec_oprnds2[j];
8275 : 736 : vec_oprnd3 = vec_oprnds3[j];
8276 : 736 : if (j == 0)
8277 : : orig = vec_oprnd3;
8278 : 224 : else if (!inscan_var_store)
8279 : 112 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
8280 : :
8281 : 736 : if (ldataref_ptr)
8282 : : {
8283 : 182 : vec_oprnd2 = make_ssa_name (vectype);
8284 : 182 : tree data_ref = fold_build2 (MEM_REF, vectype,
8285 : : unshare_expr (ldataref_ptr),
8286 : : dataref_offset);
8287 : 182 : vect_copy_ref_info (data_ref, DR_REF (load1_dr_info->dr));
8288 : 182 : gimple *g = gimple_build_assign (vec_oprnd2, data_ref);
8289 : 182 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8290 : 182 : if (! slp_node)
8291 : : {
8292 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8293 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
8294 : : }
8295 : : }
8296 : :
8297 : 736 : tree v = vec_oprnd2;
8298 : 3068 : for (int i = 0; i < units_log2; ++i)
8299 : : {
8300 : 2332 : tree new_temp = make_ssa_name (vectype);
8301 : 2332 : gimple *g = gimple_build_assign (new_temp, VEC_PERM_EXPR,
8302 : : (zero_vec
8303 : 0 : && (use_whole_vector[i]
8304 : 0 : != scan_store_kind_perm))
8305 : : ? zero_vec : vec_oprnd1, v,
8306 : 2332 : perms[i]);
8307 : 2332 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8308 : 2332 : if (! slp_node)
8309 : : {
8310 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8311 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
8312 : : }
8313 : :
8314 : 2332 : if (zero_vec && use_whole_vector[i] == scan_store_kind_lshift_cond)
8315 : : {
8316 : : /* Whole vector shift shifted in zero bits, but if *init
8317 : : is not initializer_zerop, we need to replace those elements
8318 : : with elements from vec_oprnd1. */
8319 : 0 : tree_vector_builder vb (masktype, nunits, 1);
8320 : 0 : for (unsigned HOST_WIDE_INT k = 0; k < nunits; ++k)
8321 : 0 : vb.quick_push (k < (HOST_WIDE_INT_1U << i)
8322 : : ? boolean_false_node : boolean_true_node);
8323 : :
8324 : 0 : tree new_temp2 = make_ssa_name (vectype);
8325 : 0 : g = gimple_build_assign (new_temp2, VEC_COND_EXPR, vb.build (),
8326 : : new_temp, vec_oprnd1);
8327 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
8328 : : g, gsi);
8329 : 0 : if (! slp_node)
8330 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8331 : 0 : new_temp = new_temp2;
8332 : 0 : }
8333 : :
8334 : : /* For exclusive scan, perform the perms[i] permutation once
8335 : : more. */
8336 : 2332 : if (i == 0
8337 : 1100 : && STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4
8338 : 728 : && v == vec_oprnd2)
8339 : : {
8340 : 364 : v = new_temp;
8341 : 364 : --i;
8342 : 364 : continue;
8343 : : }
8344 : :
8345 : 1968 : tree new_temp2 = make_ssa_name (vectype);
8346 : 1968 : g = gimple_build_assign (new_temp2, code, v, new_temp);
8347 : 1968 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8348 : 1968 : if (! slp_node)
8349 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8350 : :
8351 : 1968 : v = new_temp2;
8352 : : }
8353 : :
8354 : 736 : tree new_temp = make_ssa_name (vectype);
8355 : 736 : gimple *g = gimple_build_assign (new_temp, code, orig, v);
8356 : 736 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8357 : 736 : if (! slp_node)
8358 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8359 : :
8360 : 736 : tree last_perm_arg = new_temp;
8361 : : /* For exclusive scan, new_temp computed above is the exclusive scan
8362 : : prefix sum. Turn it into inclusive prefix sum for the broadcast
8363 : : of the last element into orig. */
8364 : 736 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
8365 : : {
8366 : 364 : last_perm_arg = make_ssa_name (vectype);
8367 : 364 : g = gimple_build_assign (last_perm_arg, code, new_temp, vec_oprnd2);
8368 : 364 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8369 : 364 : if (! slp_node)
8370 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8371 : : }
8372 : :
8373 : 736 : orig = make_ssa_name (vectype);
8374 : 2208 : g = gimple_build_assign (orig, VEC_PERM_EXPR, last_perm_arg,
8375 : 736 : last_perm_arg, perms[units_log2]);
8376 : 736 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8377 : 736 : if (! slp_node)
8378 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8379 : :
8380 : 736 : if (!inscan_var_store)
8381 : : {
8382 : 368 : tree data_ref = fold_build2 (MEM_REF, vectype,
8383 : : unshare_expr (dataref_ptr),
8384 : : dataref_offset);
8385 : 368 : vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
8386 : 368 : g = gimple_build_assign (data_ref, new_temp);
8387 : 368 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8388 : 368 : if (! slp_node)
8389 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8390 : : }
8391 : : }
8392 : :
8393 : 512 : if (inscan_var_store)
8394 : 624 : for (unsigned j = 0; j < vec_oprnds3.length (); j++)
8395 : : {
8396 : 368 : if (j != 0)
8397 : 112 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
8398 : :
8399 : 368 : tree data_ref = fold_build2 (MEM_REF, vectype,
8400 : : unshare_expr (dataref_ptr),
8401 : : dataref_offset);
8402 : 368 : vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
8403 : 368 : gimple *g = gimple_build_assign (data_ref, orig);
8404 : 368 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8405 : 368 : if (! slp_node)
8406 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
8407 : : }
8408 : 512 : return true;
8409 : 512 : }
8410 : :
8411 : :
8412 : : /* Function vectorizable_store.
8413 : :
8414 : : Check if STMT_INFO defines a non scalar data-ref (array/pointer/structure)
8415 : : that can be vectorized.
8416 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
8417 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
8418 : : Return true if STMT_INFO is vectorizable in this way. */
8419 : :
8420 : : static bool
8421 : 1900893 : vectorizable_store (vec_info *vinfo,
8422 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
8423 : : gimple **vec_stmt, slp_tree slp_node,
8424 : : stmt_vector_for_cost *cost_vec)
8425 : : {
8426 : 1900893 : tree data_ref;
8427 : 1900893 : tree vec_oprnd = NULL_TREE;
8428 : 1900893 : tree elem_type;
8429 : 1900893 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
8430 : 1900893 : class loop *loop = NULL;
8431 : 1900893 : machine_mode vec_mode;
8432 : 1900893 : tree dummy;
8433 : 1900893 : enum vect_def_type rhs_dt = vect_unknown_def_type;
8434 : 1900893 : enum vect_def_type mask_dt = vect_unknown_def_type;
8435 : 1900893 : tree dataref_ptr = NULL_TREE;
8436 : 1900893 : tree dataref_offset = NULL_TREE;
8437 : 1900893 : gimple *ptr_incr = NULL;
8438 : 1900893 : int ncopies;
8439 : 1900893 : int j;
8440 : 1900893 : stmt_vec_info first_stmt_info;
8441 : 1900893 : bool grouped_store;
8442 : 1900893 : unsigned int group_size, i;
8443 : 1900893 : bool slp = (slp_node != NULL);
8444 : 1900893 : unsigned int vec_num;
8445 : 1900893 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
8446 : 1900893 : tree aggr_type;
8447 : 1900893 : gather_scatter_info gs_info;
8448 : 1900893 : poly_uint64 vf;
8449 : 1900893 : vec_load_store_type vls_type;
8450 : 1900893 : tree ref_type;
8451 : :
8452 : 1900893 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
8453 : : return false;
8454 : :
8455 : 1900893 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
8456 : 186872 : && ! vec_stmt)
8457 : : return false;
8458 : :
8459 : : /* Is vectorizable store? */
8460 : :
8461 : 1714021 : tree mask = NULL_TREE, mask_vectype = NULL_TREE;
8462 : 1714021 : slp_tree mask_node = NULL;
8463 : 1714021 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
8464 : : {
8465 : 1654908 : tree scalar_dest = gimple_assign_lhs (assign);
8466 : 1654908 : if (TREE_CODE (scalar_dest) == VIEW_CONVERT_EXPR
8467 : 1654908 : && is_pattern_stmt_p (stmt_info))
8468 : 1062 : scalar_dest = TREE_OPERAND (scalar_dest, 0);
8469 : 1654908 : if (TREE_CODE (scalar_dest) != ARRAY_REF
8470 : 1654908 : && TREE_CODE (scalar_dest) != BIT_FIELD_REF
8471 : : && TREE_CODE (scalar_dest) != INDIRECT_REF
8472 : : && TREE_CODE (scalar_dest) != COMPONENT_REF
8473 : : && TREE_CODE (scalar_dest) != IMAGPART_EXPR
8474 : : && TREE_CODE (scalar_dest) != REALPART_EXPR
8475 : : && TREE_CODE (scalar_dest) != MEM_REF)
8476 : : return false;
8477 : : }
8478 : : else
8479 : : {
8480 : 596717 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
8481 : 8021 : if (!call || !gimple_call_internal_p (call))
8482 : : return false;
8483 : :
8484 : 4644 : internal_fn ifn = gimple_call_internal_fn (call);
8485 : 4644 : if (!internal_store_fn_p (ifn))
8486 : : return false;
8487 : :
8488 : 1590 : int mask_index = internal_fn_mask_index (ifn);
8489 : 1590 : if (mask_index >= 0 && slp_node)
8490 : 1590 : mask_index = vect_slp_child_index_for_operand
8491 : 1590 : (call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
8492 : 1590 : if (mask_index >= 0
8493 : 1590 : && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index,
8494 : : &mask, &mask_node, &mask_dt,
8495 : : &mask_vectype))
8496 : : return false;
8497 : : }
8498 : :
8499 : : /* Cannot have hybrid store SLP -- that would mean storing to the
8500 : : same location twice. */
8501 : 1312840 : gcc_assert (slp == PURE_SLP_STMT (stmt_info));
8502 : :
8503 : 1312840 : tree vectype = STMT_VINFO_VECTYPE (stmt_info), rhs_vectype = NULL_TREE;
8504 : 1312840 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
8505 : :
8506 : 1312840 : if (loop_vinfo)
8507 : : {
8508 : 185060 : loop = LOOP_VINFO_LOOP (loop_vinfo);
8509 : 185060 : vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
8510 : : }
8511 : : else
8512 : : vf = 1;
8513 : :
8514 : : /* Multiple types in SLP are handled by creating the appropriate number of
8515 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
8516 : : case of SLP. */
8517 : 1312840 : if (slp)
8518 : : ncopies = 1;
8519 : : else
8520 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
8521 : :
8522 : 0 : gcc_assert (ncopies >= 1);
8523 : :
8524 : : /* FORNOW. This restriction should be relaxed. */
8525 : 1312840 : if (loop
8526 : 185060 : && nested_in_vect_loop_p (loop, stmt_info)
8527 : 1313079 : && (ncopies > 1 || (slp && SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) > 1)))
8528 : : {
8529 : 8 : if (dump_enabled_p ())
8530 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8531 : : "multiple types in nested loop.\n");
8532 : 8 : return false;
8533 : : }
8534 : :
8535 : 1312832 : tree op;
8536 : 1312832 : slp_tree op_node;
8537 : 1312832 : if (!vect_check_store_rhs (vinfo, stmt_info, slp_node,
8538 : : &op, &op_node, &rhs_dt, &rhs_vectype, &vls_type))
8539 : : return false;
8540 : :
8541 : 1312808 : elem_type = TREE_TYPE (vectype);
8542 : 1312808 : vec_mode = TYPE_MODE (vectype);
8543 : :
8544 : 1312808 : if (!STMT_VINFO_DATA_REF (stmt_info))
8545 : : return false;
8546 : :
8547 : 1312808 : vect_memory_access_type memory_access_type;
8548 : 1312808 : enum dr_alignment_support alignment_support_scheme;
8549 : 1312808 : int misalignment;
8550 : 1312808 : poly_int64 poffset;
8551 : 1312808 : internal_fn lanes_ifn;
8552 : 1312808 : if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, vls_type,
8553 : : ncopies, &memory_access_type, &poffset,
8554 : : &alignment_support_scheme, &misalignment, &gs_info,
8555 : : &lanes_ifn))
8556 : : return false;
8557 : :
8558 : 1312327 : if (slp_node
8559 : 1312327 : && slp_node->ldst_lanes
8560 : 0 : && memory_access_type != VMAT_LOAD_STORE_LANES)
8561 : : {
8562 : 0 : if (dump_enabled_p ())
8563 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8564 : : "discovered store-lane but cannot use it.\n");
8565 : 0 : return false;
8566 : : }
8567 : :
8568 : 1312327 : if (mask)
8569 : : {
8570 : 1500 : if (memory_access_type == VMAT_CONTIGUOUS)
8571 : : {
8572 : 486 : if (!VECTOR_MODE_P (vec_mode)
8573 : 2396 : || !can_vec_mask_load_store_p (vec_mode,
8574 : 1198 : TYPE_MODE (mask_vectype), false))
8575 : 32 : return false;
8576 : : }
8577 : 302 : else if (memory_access_type != VMAT_LOAD_STORE_LANES
8578 : 302 : && (memory_access_type != VMAT_GATHER_SCATTER
8579 : 272 : || (gs_info.decl && !VECTOR_BOOLEAN_TYPE_P (mask_vectype))))
8580 : : {
8581 : 30 : if (dump_enabled_p ())
8582 : 28 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8583 : : "unsupported access type for masked store.\n");
8584 : 30 : return false;
8585 : : }
8586 : 272 : else if (memory_access_type == VMAT_GATHER_SCATTER
8587 : 272 : && gs_info.ifn == IFN_LAST
8588 : 272 : && !gs_info.decl)
8589 : : {
8590 : 68 : if (dump_enabled_p ())
8591 : 24 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8592 : : "unsupported masked emulated scatter.\n");
8593 : 68 : return false;
8594 : : }
8595 : : }
8596 : : else
8597 : : {
8598 : : /* FORNOW. In some cases can vectorize even if data-type not supported
8599 : : (e.g. - array initialization with 0). */
8600 : 1310827 : if (!can_implement_p (mov_optab, vec_mode))
8601 : : return false;
8602 : : }
8603 : :
8604 : 1312197 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL;
8605 : 1312197 : grouped_store = (STMT_VINFO_GROUPED_ACCESS (stmt_info)
8606 : 1147066 : && memory_access_type != VMAT_GATHER_SCATTER
8607 : 2459263 : && (slp || memory_access_type != VMAT_CONTIGUOUS));
8608 : 1312197 : if (grouped_store)
8609 : : {
8610 : 1147066 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
8611 : 1147066 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
8612 : 1147066 : group_size = DR_GROUP_SIZE (first_stmt_info);
8613 : : }
8614 : : else
8615 : : {
8616 : : first_stmt_info = stmt_info;
8617 : : first_dr_info = dr_info;
8618 : : group_size = vec_num = 1;
8619 : : }
8620 : :
8621 : 1312197 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1 && !vec_stmt)
8622 : : {
8623 : 1076 : if (!check_scan_store (vinfo, stmt_info, vectype, rhs_dt, slp_node, mask,
8624 : : memory_access_type))
8625 : : return false;
8626 : : }
8627 : :
8628 : 1312197 : bool costing_p = !vec_stmt;
8629 : 1312197 : if (costing_p) /* transformation not required. */
8630 : : {
8631 : 777706 : STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info) = memory_access_type;
8632 : 777706 : if (slp_node)
8633 : 777706 : SLP_TREE_MEMORY_ACCESS_TYPE (slp_node) = memory_access_type;
8634 : :
8635 : 777706 : if (loop_vinfo
8636 : 127344 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
8637 : 27 : check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
8638 : : vls_type, group_size,
8639 : : memory_access_type, &gs_info,
8640 : : mask);
8641 : :
8642 : 777706 : if (slp_node
8643 : 777706 : && (!vect_maybe_update_slp_op_vectype (op_node, vectype)
8644 : 777706 : || (mask
8645 : 859 : && !vect_maybe_update_slp_op_vectype (mask_node,
8646 : : mask_vectype))))
8647 : : {
8648 : 0 : if (dump_enabled_p ())
8649 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8650 : : "incompatible vector types for invariants\n");
8651 : 0 : return false;
8652 : : }
8653 : :
8654 : 777706 : if (dump_enabled_p ()
8655 : : && memory_access_type != VMAT_ELEMENTWISE
8656 : : && memory_access_type != VMAT_GATHER_SCATTER
8657 : : && memory_access_type != VMAT_STRIDED_SLP
8658 : 15098 : && memory_access_type != VMAT_INVARIANT
8659 : 792804 : && alignment_support_scheme != dr_aligned)
8660 : 5423 : dump_printf_loc (MSG_NOTE, vect_location,
8661 : : "Vectorizing an unaligned access.\n");
8662 : :
8663 : 777706 : STMT_VINFO_TYPE (stmt_info) = store_vec_info_type;
8664 : :
8665 : : /* As function vect_transform_stmt shows, for interleaving stores
8666 : : the whole chain is vectorized when the last store in the chain
8667 : : is reached, the other stores in the group are skipped. So we
8668 : : want to only cost the last one here, but it's not trivial to
8669 : : get the last, as it's equivalent to use the first one for
8670 : : costing, use the first one instead. */
8671 : 777706 : if (grouped_store
8672 : 663003 : && !slp
8673 : 0 : && first_stmt_info != stmt_info)
8674 : : return true;
8675 : : }
8676 : 1312197 : if (slp_node)
8677 : 1312197 : gcc_assert (memory_access_type == SLP_TREE_MEMORY_ACCESS_TYPE (stmt_info));
8678 : : else
8679 : 0 : gcc_assert (memory_access_type == STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info));
8680 : :
8681 : : /* Transform. */
8682 : :
8683 : 1312197 : ensure_base_align (dr_info);
8684 : :
8685 : 1312197 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) >= 3)
8686 : : {
8687 : 1024 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS);
8688 : 1024 : gcc_assert (!slp || SLP_TREE_LANES (slp_node) == 1);
8689 : 1024 : if (costing_p)
8690 : : {
8691 : 512 : unsigned int inside_cost = 0, prologue_cost = 0;
8692 : 512 : if (vls_type == VLS_STORE_INVARIANT)
8693 : 0 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
8694 : : stmt_info, 0, vect_prologue);
8695 : 512 : vect_get_store_cost (vinfo, stmt_info, slp_node, ncopies,
8696 : : alignment_support_scheme, misalignment,
8697 : : &inside_cost, cost_vec);
8698 : :
8699 : 512 : if (dump_enabled_p ())
8700 : 492 : dump_printf_loc (MSG_NOTE, vect_location,
8701 : : "vect_model_store_cost: inside_cost = %d, "
8702 : : "prologue_cost = %d .\n",
8703 : : inside_cost, prologue_cost);
8704 : :
8705 : 512 : return true;
8706 : : }
8707 : 512 : return vectorizable_scan_store (vinfo, stmt_info, slp_node,
8708 : 512 : gsi, vec_stmt, ncopies);
8709 : : }
8710 : :
8711 : 1311173 : if (grouped_store || slp)
8712 : : {
8713 : : /* FORNOW */
8714 : 1311173 : gcc_assert (!grouped_store
8715 : : || !loop
8716 : : || !nested_in_vect_loop_p (loop, stmt_info));
8717 : :
8718 : 1311173 : if (slp)
8719 : : {
8720 : 1311173 : grouped_store = false;
8721 : : /* VEC_NUM is the number of vect stmts to be created for this
8722 : : group. */
8723 : 1311173 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
8724 : 1311173 : first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
8725 : 1311173 : gcc_assert (!STMT_VINFO_GROUPED_ACCESS (first_stmt_info)
8726 : : || (DR_GROUP_FIRST_ELEMENT (first_stmt_info)
8727 : : == first_stmt_info));
8728 : 1311173 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
8729 : 1311173 : op = vect_get_store_rhs (first_stmt_info);
8730 : : }
8731 : : else
8732 : : /* VEC_NUM is the number of vect stmts to be created for this
8733 : : group. */
8734 : : vec_num = group_size;
8735 : :
8736 : 1311173 : ref_type = get_group_alias_ptr_type (first_stmt_info);
8737 : : }
8738 : : else
8739 : 0 : ref_type = reference_alias_ptr_type (DR_REF (first_dr_info->dr));
8740 : :
8741 : 1311173 : if (!costing_p && dump_enabled_p ())
8742 : 11519 : dump_printf_loc (MSG_NOTE, vect_location, "transform store. ncopies = %d\n",
8743 : : ncopies);
8744 : :
8745 : : /* Check if we need to update prologue cost for invariant,
8746 : : and update it accordingly if so. If it's not for
8747 : : interleaving store, we can just check vls_type; but if
8748 : : it's for interleaving store, need to check the def_type
8749 : : of the stored value since the current vls_type is just
8750 : : for first_stmt_info. */
8751 : 3168630 : auto update_prologue_cost = [&](unsigned *prologue_cost, tree store_rhs)
8752 : : {
8753 : 1857457 : gcc_assert (costing_p);
8754 : 1857457 : if (slp)
8755 : : return;
8756 : 0 : if (grouped_store)
8757 : : {
8758 : 0 : gcc_assert (store_rhs);
8759 : 0 : enum vect_def_type cdt;
8760 : 0 : gcc_assert (vect_is_simple_use (store_rhs, vinfo, &cdt));
8761 : 0 : if (cdt != vect_constant_def && cdt != vect_external_def)
8762 : 0 : return;
8763 : : }
8764 : 0 : else if (vls_type != VLS_STORE_INVARIANT)
8765 : : return;
8766 : 0 : *prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec, stmt_info,
8767 : : slp_node, 0, vect_prologue);
8768 : 1311173 : };
8769 : :
8770 : 1311173 : if (memory_access_type == VMAT_ELEMENTWISE
8771 : 1311173 : || memory_access_type == VMAT_STRIDED_SLP)
8772 : : {
8773 : 32799 : unsigned inside_cost = 0, prologue_cost = 0;
8774 : 32799 : gimple_stmt_iterator incr_gsi;
8775 : 32799 : bool insert_after;
8776 : 32799 : gimple *incr;
8777 : 32799 : tree offvar = NULL_TREE;
8778 : 32799 : tree ivstep;
8779 : 32799 : tree running_off;
8780 : 32799 : tree stride_base, stride_step, alias_off;
8781 : 32799 : tree vec_oprnd = NULL_TREE;
8782 : 32799 : tree dr_offset;
8783 : 32799 : unsigned int g;
8784 : : /* Checked by get_load_store_type. */
8785 : 32799 : unsigned int const_nunits = nunits.to_constant ();
8786 : :
8787 : 32799 : gcc_assert (!LOOP_VINFO_FULLY_MASKED_P (loop_vinfo));
8788 : 32799 : gcc_assert (!nested_in_vect_loop_p (loop, stmt_info));
8789 : :
8790 : 32799 : dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info);
8791 : 32799 : stride_base
8792 : 32799 : = fold_build_pointer_plus
8793 : : (DR_BASE_ADDRESS (first_dr_info->dr),
8794 : : size_binop (PLUS_EXPR,
8795 : : convert_to_ptrofftype (dr_offset),
8796 : : convert_to_ptrofftype (DR_INIT (first_dr_info->dr))));
8797 : 32799 : stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr));
8798 : :
8799 : : /* For a store with loop-invariant (but other than power-of-2)
8800 : : stride (i.e. not a grouped access) like so:
8801 : :
8802 : : for (i = 0; i < n; i += stride)
8803 : : array[i] = ...;
8804 : :
8805 : : we generate a new induction variable and new stores from
8806 : : the components of the (vectorized) rhs:
8807 : :
8808 : : for (j = 0; ; j += VF*stride)
8809 : : vectemp = ...;
8810 : : tmp1 = vectemp[0];
8811 : : array[j] = tmp1;
8812 : : tmp2 = vectemp[1];
8813 : : array[j + stride] = tmp2;
8814 : : ...
8815 : : */
8816 : :
8817 : 32799 : unsigned nstores = const_nunits;
8818 : 32799 : unsigned lnel = 1;
8819 : 32799 : tree ltype = elem_type;
8820 : 32799 : tree lvectype = vectype;
8821 : 32799 : if (slp)
8822 : : {
8823 : 32799 : HOST_WIDE_INT n = gcd (group_size, const_nunits);
8824 : 32799 : if (n == const_nunits)
8825 : : {
8826 : 3939 : int mis_align = dr_misalignment (first_dr_info, vectype);
8827 : 3939 : dr_alignment_support dr_align
8828 : 3939 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype,
8829 : : mis_align);
8830 : 3939 : if (dr_align == dr_aligned
8831 : 3939 : || dr_align == dr_unaligned_supported)
8832 : : {
8833 : 3939 : nstores = 1;
8834 : 3939 : lnel = const_nunits;
8835 : 3939 : ltype = vectype;
8836 : 3939 : lvectype = vectype;
8837 : 3939 : alignment_support_scheme = dr_align;
8838 : 3939 : misalignment = mis_align;
8839 : : }
8840 : : }
8841 : 28860 : else if (n > 1)
8842 : : {
8843 : 2733 : nstores = const_nunits / n;
8844 : 2733 : lnel = n;
8845 : 2733 : ltype = build_vector_type (elem_type, n);
8846 : 2733 : lvectype = vectype;
8847 : 2733 : int mis_align = dr_misalignment (first_dr_info, ltype);
8848 : 2733 : dr_alignment_support dr_align
8849 : 2733 : = vect_supportable_dr_alignment (vinfo, dr_info, ltype,
8850 : : mis_align);
8851 : 2733 : alignment_support_scheme = dr_align;
8852 : 2733 : misalignment = mis_align;
8853 : :
8854 : : /* First check if vec_extract optab doesn't support extraction
8855 : : of vector elts directly. */
8856 : 2733 : scalar_mode elmode = SCALAR_TYPE_MODE (elem_type);
8857 : 2733 : machine_mode vmode;
8858 : 5466 : if (!VECTOR_MODE_P (TYPE_MODE (vectype))
8859 : 3026 : || !related_vector_mode (TYPE_MODE (vectype), elmode,
8860 : 4937 : n).exists (&vmode)
8861 : 2497 : || (convert_optab_handler (vec_extract_optab,
8862 : 2497 : TYPE_MODE (vectype), vmode)
8863 : : == CODE_FOR_nothing)
8864 : 2733 : || !(dr_align == dr_aligned
8865 : 293 : || dr_align == dr_unaligned_supported))
8866 : : {
8867 : : /* Try to avoid emitting an extract of vector elements
8868 : : by performing the extracts using an integer type of the
8869 : : same size, extracting from a vector of those and then
8870 : : re-interpreting it as the original vector type if
8871 : : supported. */
8872 : 2440 : unsigned lsize
8873 : 2440 : = n * GET_MODE_BITSIZE (elmode);
8874 : 2440 : unsigned int lnunits = const_nunits / n;
8875 : : /* If we can't construct such a vector fall back to
8876 : : element extracts from the original vector type and
8877 : : element size stores. */
8878 : 2440 : if (int_mode_for_size (lsize, 0).exists (&elmode)
8879 : 2440 : && VECTOR_MODE_P (TYPE_MODE (vectype))
8880 : 2440 : && related_vector_mode (TYPE_MODE (vectype), elmode,
8881 : 2440 : lnunits).exists (&vmode)
8882 : 2390 : && (convert_optab_handler (vec_extract_optab,
8883 : : vmode, elmode)
8884 : : != CODE_FOR_nothing))
8885 : : {
8886 : 2390 : nstores = lnunits;
8887 : 2390 : lnel = n;
8888 : 2390 : ltype = build_nonstandard_integer_type (lsize, 1);
8889 : 2390 : lvectype = build_vector_type (ltype, nstores);
8890 : : }
8891 : : /* Else fall back to vector extraction anyway.
8892 : : Fewer stores are more important than avoiding spilling
8893 : : of the vector we extract from. Compared to the
8894 : : construction case in vectorizable_load no store-forwarding
8895 : : issue exists here for reasonable archs. But only
8896 : : if the store is supported. */
8897 : 50 : else if (!(dr_align == dr_aligned
8898 : 50 : || dr_align == dr_unaligned_supported))
8899 : : {
8900 : 26127 : nstores = const_nunits;
8901 : 26127 : lnel = 1;
8902 : 26127 : ltype = elem_type;
8903 : 26127 : lvectype = vectype;
8904 : : }
8905 : : }
8906 : : }
8907 : 32799 : unsigned align;
8908 : 32799 : if (alignment_support_scheme == dr_aligned)
8909 : 2286 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
8910 : : else
8911 : 30513 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
8912 : : /* Alignment is at most the access size if we do multiple stores. */
8913 : 32799 : if (nstores > 1)
8914 : 28860 : align = MIN (tree_to_uhwi (TYPE_SIZE_UNIT (ltype)), align);
8915 : 32799 : ltype = build_aligned_type (ltype, align * BITS_PER_UNIT);
8916 : 32799 : ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
8917 : : }
8918 : :
8919 : 32799 : if (!costing_p)
8920 : : {
8921 : 3300 : ivstep = stride_step;
8922 : 3300 : ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (ivstep), ivstep,
8923 : : build_int_cst (TREE_TYPE (ivstep), vf));
8924 : :
8925 : 3300 : standard_iv_increment_position (loop, &incr_gsi, &insert_after);
8926 : :
8927 : 3300 : stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base);
8928 : 3300 : ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep);
8929 : 3300 : create_iv (stride_base, PLUS_EXPR, ivstep, NULL, loop, &incr_gsi,
8930 : : insert_after, &offvar, NULL);
8931 : 3300 : incr = gsi_stmt (incr_gsi);
8932 : :
8933 : 3300 : stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step);
8934 : : }
8935 : :
8936 : 32799 : alias_off = build_int_cst (ref_type, 0);
8937 : 32799 : stmt_vec_info next_stmt_info = first_stmt_info;
8938 : 32799 : auto_vec<tree> vec_oprnds;
8939 : : /* For costing some adjacent vector stores, we'd like to cost with
8940 : : the total number of them once instead of cost each one by one. */
8941 : 32799 : unsigned int n_adjacent_stores = 0;
8942 : 32799 : for (g = 0; g < group_size; g++)
8943 : : {
8944 : 32799 : running_off = offvar;
8945 : 32799 : if (!costing_p)
8946 : : {
8947 : 3300 : if (g)
8948 : : {
8949 : 0 : tree size = TYPE_SIZE_UNIT (ltype);
8950 : 0 : tree pos
8951 : 0 : = fold_build2 (MULT_EXPR, sizetype, size_int (g), size);
8952 : 0 : tree newoff = copy_ssa_name (running_off, NULL);
8953 : 0 : incr = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
8954 : : running_off, pos);
8955 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
8956 : 0 : running_off = newoff;
8957 : : }
8958 : : }
8959 : 32799 : if (!slp)
8960 : 0 : op = vect_get_store_rhs (next_stmt_info);
8961 : 32799 : if (!costing_p)
8962 : 3300 : vect_get_vec_defs (vinfo, next_stmt_info, slp_node, ncopies, op,
8963 : : &vec_oprnds);
8964 : : else
8965 : 29499 : update_prologue_cost (&prologue_cost, op);
8966 : 32799 : unsigned int group_el = 0;
8967 : 32799 : unsigned HOST_WIDE_INT
8968 : 32799 : elsz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
8969 : 100330 : for (j = 0; j < ncopies; j++)
8970 : : {
8971 : 67531 : if (!costing_p)
8972 : : {
8973 : 5558 : vec_oprnd = vec_oprnds[j];
8974 : : /* Pun the vector to extract from if necessary. */
8975 : 5558 : if (lvectype != vectype)
8976 : : {
8977 : 1205 : tree tem = make_ssa_name (lvectype);
8978 : 1205 : tree cvt
8979 : 1205 : = build1 (VIEW_CONVERT_EXPR, lvectype, vec_oprnd);
8980 : 1205 : gimple *pun = gimple_build_assign (tem, cvt);
8981 : 1205 : vect_finish_stmt_generation (vinfo, stmt_info, pun, gsi);
8982 : 1205 : vec_oprnd = tem;
8983 : : }
8984 : : }
8985 : 250074 : for (i = 0; i < nstores; i++)
8986 : : {
8987 : 182543 : if (costing_p)
8988 : : {
8989 : 165737 : n_adjacent_stores++;
8990 : 165737 : continue;
8991 : : }
8992 : 16806 : tree newref, newoff;
8993 : 16806 : gimple *incr, *assign;
8994 : 16806 : tree size = TYPE_SIZE (ltype);
8995 : : /* Extract the i'th component. */
8996 : 16806 : tree pos = fold_build2 (MULT_EXPR, bitsizetype,
8997 : : bitsize_int (i), size);
8998 : 16806 : tree elem = fold_build3 (BIT_FIELD_REF, ltype, vec_oprnd,
8999 : : size, pos);
9000 : :
9001 : 16806 : elem = force_gimple_operand_gsi (gsi, elem, true,
9002 : : NULL_TREE, true,
9003 : : GSI_SAME_STMT);
9004 : :
9005 : 16806 : tree this_off = build_int_cst (TREE_TYPE (alias_off),
9006 : 16806 : group_el * elsz);
9007 : 16806 : newref = build2 (MEM_REF, ltype,
9008 : : running_off, this_off);
9009 : 16806 : vect_copy_ref_info (newref, DR_REF (first_dr_info->dr));
9010 : :
9011 : : /* And store it to *running_off. */
9012 : 16806 : assign = gimple_build_assign (newref, elem);
9013 : 16806 : vect_finish_stmt_generation (vinfo, stmt_info, assign, gsi);
9014 : :
9015 : 16806 : group_el += lnel;
9016 : 16806 : if (! slp
9017 : 16806 : || group_el == group_size)
9018 : : {
9019 : 15503 : newoff = copy_ssa_name (running_off, NULL);
9020 : 15503 : incr = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
9021 : : running_off, stride_step);
9022 : 15503 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
9023 : :
9024 : 15503 : running_off = newoff;
9025 : 15503 : group_el = 0;
9026 : : }
9027 : 16806 : if (g == group_size - 1
9028 : 9036 : && !slp)
9029 : : {
9030 : 0 : if (j == 0 && i == 0)
9031 : 0 : *vec_stmt = assign;
9032 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (assign);
9033 : : }
9034 : : }
9035 : : }
9036 : 32799 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
9037 : 32799 : vec_oprnds.truncate(0);
9038 : 32799 : if (slp)
9039 : : break;
9040 : : }
9041 : :
9042 : 32799 : if (costing_p)
9043 : : {
9044 : 29499 : if (n_adjacent_stores > 0)
9045 : : {
9046 : : /* Take a single lane vector type store as scalar
9047 : : store to avoid ICE like 110776. */
9048 : 29499 : if (VECTOR_TYPE_P (ltype)
9049 : 29499 : && maybe_ne (TYPE_VECTOR_SUBPARTS (ltype), 1U))
9050 : 1608 : vect_get_store_cost (vinfo, stmt_info, slp_node,
9051 : : n_adjacent_stores, alignment_support_scheme,
9052 : : misalignment, &inside_cost, cost_vec);
9053 : : else
9054 : 27891 : inside_cost
9055 : 27891 : += record_stmt_cost (cost_vec, n_adjacent_stores,
9056 : : scalar_store, stmt_info, 0, vect_body);
9057 : : /* Only need vector extracting when there are more
9058 : : than one stores. */
9059 : 29499 : if (nstores > 1)
9060 : 26299 : inside_cost
9061 : 26299 : += record_stmt_cost (cost_vec, n_adjacent_stores,
9062 : : vec_to_scalar, stmt_info, slp_node,
9063 : : 0, vect_body);
9064 : : }
9065 : 29499 : if (dump_enabled_p ())
9066 : 788 : dump_printf_loc (MSG_NOTE, vect_location,
9067 : : "vect_model_store_cost: inside_cost = %d, "
9068 : : "prologue_cost = %d .\n",
9069 : : inside_cost, prologue_cost);
9070 : : }
9071 : :
9072 : 32799 : return true;
9073 : 32799 : }
9074 : :
9075 : 1278374 : gcc_assert (alignment_support_scheme);
9076 : 1278374 : vec_loop_masks *loop_masks
9077 : 150594 : = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
9078 : 1278374 : ? &LOOP_VINFO_MASKS (loop_vinfo)
9079 : 1428973 : : NULL);
9080 : 5 : vec_loop_lens *loop_lens
9081 : 150594 : = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)
9082 : 0 : ? &LOOP_VINFO_LENS (loop_vinfo)
9083 : 1278374 : : NULL);
9084 : :
9085 : : /* The vect_transform_stmt and vect_analyze_stmt will go here but there
9086 : : are some difference here. We cannot enable both the lens and masks
9087 : : during transform but it is allowed during analysis.
9088 : : Shouldn't go with length-based approach if fully masked. */
9089 : 1278374 : if (cost_vec == NULL)
9090 : : /* The cost_vec is NULL during transfrom. */
9091 : 530679 : gcc_assert ((!loop_lens || !loop_masks));
9092 : :
9093 : : /* Targets with store-lane instructions must not require explicit
9094 : : realignment. vect_supportable_dr_alignment always returns either
9095 : : dr_aligned or dr_unaligned_supported for masked operations. */
9096 : 1278374 : gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES
9097 : : && !mask
9098 : : && !loop_masks)
9099 : : || alignment_support_scheme == dr_aligned
9100 : : || alignment_support_scheme == dr_unaligned_supported);
9101 : :
9102 : 1278374 : tree offset = NULL_TREE;
9103 : 1278374 : if (!known_eq (poffset, 0))
9104 : 4533 : offset = size_int (poffset);
9105 : :
9106 : 1278374 : tree bump;
9107 : 1278374 : tree vec_offset = NULL_TREE;
9108 : 1278374 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
9109 : : {
9110 : 2626 : aggr_type = NULL_TREE;
9111 : 2626 : bump = NULL_TREE;
9112 : : }
9113 : 1275748 : else if (memory_access_type == VMAT_GATHER_SCATTER)
9114 : : {
9115 : 0 : aggr_type = elem_type;
9116 : 0 : if (!costing_p)
9117 : 0 : vect_get_strided_load_store_ops (stmt_info, loop_vinfo, gsi, &gs_info,
9118 : : &bump, &vec_offset, loop_lens);
9119 : : }
9120 : : else
9121 : : {
9122 : 1275748 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
9123 : 0 : aggr_type = build_array_type_nelts (elem_type, group_size * nunits);
9124 : : else
9125 : : aggr_type = vectype;
9126 : 1275748 : if (!costing_p)
9127 : 530210 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
9128 : : memory_access_type, loop_lens);
9129 : : }
9130 : :
9131 : 1278374 : if (mask && !costing_p)
9132 : 511 : LOOP_VINFO_HAS_MASK_STORE (loop_vinfo) = true;
9133 : :
9134 : : /* In case the vectorization factor (VF) is bigger than the number
9135 : : of elements that we can fit in a vectype (nunits), we have to generate
9136 : : more than one vector stmt - i.e - we need to "unroll" the
9137 : : vector stmt by a factor VF/nunits. */
9138 : :
9139 : : /* In case of interleaving (non-unit grouped access):
9140 : :
9141 : : S1: &base + 2 = x2
9142 : : S2: &base = x0
9143 : : S3: &base + 1 = x1
9144 : : S4: &base + 3 = x3
9145 : :
9146 : : We create vectorized stores starting from base address (the access of the
9147 : : first stmt in the chain (S2 in the above example), when the last store stmt
9148 : : of the chain (S4) is reached:
9149 : :
9150 : : VS1: &base = vx2
9151 : : VS2: &base + vec_size*1 = vx0
9152 : : VS3: &base + vec_size*2 = vx1
9153 : : VS4: &base + vec_size*3 = vx3
9154 : :
9155 : : Then permutation statements are generated:
9156 : :
9157 : : VS5: vx5 = VEC_PERM_EXPR < vx0, vx3, {0, 8, 1, 9, 2, 10, 3, 11} >
9158 : : VS6: vx6 = VEC_PERM_EXPR < vx0, vx3, {4, 12, 5, 13, 6, 14, 7, 15} >
9159 : : ...
9160 : :
9161 : : And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts
9162 : : (the order of the data-refs in the output of vect_permute_store_chain
9163 : : corresponds to the order of scalar stmts in the interleaving chain - see
9164 : : the documentation of vect_permute_store_chain()).
9165 : :
9166 : : In case of both multiple types and interleaving, above vector stores and
9167 : : permutation stmts are created for every copy. The result vector stmts are
9168 : : put in STMT_VINFO_VEC_STMT for the first copy and in the corresponding
9169 : : STMT_VINFO_RELATED_STMT for the next copies.
9170 : : */
9171 : :
9172 : 1278374 : auto_vec<tree> dr_chain (group_size);
9173 : 1278374 : auto_vec<tree> vec_masks;
9174 : 1278374 : tree vec_mask = NULL;
9175 : 1278374 : auto_delete_vec<auto_vec<tree>> gvec_oprnds (group_size);
9176 : 5779471 : for (i = 0; i < group_size; i++)
9177 : 3222723 : gvec_oprnds.quick_push (new auto_vec<tree> ());
9178 : :
9179 : 1278374 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
9180 : : {
9181 : 0 : if (costing_p && slp_node)
9182 : : /* Update all incoming store operand nodes, the general handling
9183 : : above only handles the mask and the first store operand node. */
9184 : 0 : for (slp_tree child : SLP_TREE_CHILDREN (slp_node))
9185 : 0 : if (child != mask_node
9186 : 0 : && !vect_maybe_update_slp_op_vectype (child, vectype))
9187 : : {
9188 : 0 : if (dump_enabled_p ())
9189 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9190 : : "incompatible vector types for invariants\n");
9191 : 0 : return false;
9192 : : }
9193 : 0 : unsigned inside_cost = 0, prologue_cost = 0;
9194 : : /* For costing some adjacent vector stores, we'd like to cost with
9195 : : the total number of them once instead of cost each one by one. */
9196 : 0 : unsigned int n_adjacent_stores = 0;
9197 : 0 : if (slp)
9198 : 0 : ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) / group_size;
9199 : 0 : for (j = 0; j < ncopies; j++)
9200 : : {
9201 : 0 : gimple *new_stmt;
9202 : 0 : if (j == 0)
9203 : : {
9204 : : /* For interleaved stores we collect vectorized defs for all
9205 : : the stores in the group in DR_CHAIN. DR_CHAIN is then used
9206 : : as an input to vect_permute_store_chain(). */
9207 : : stmt_vec_info next_stmt_info = first_stmt_info;
9208 : 0 : for (i = 0; i < group_size; i++)
9209 : : {
9210 : : /* Since gaps are not supported for interleaved stores,
9211 : : DR_GROUP_SIZE is the exact number of stmts in the
9212 : : chain. Therefore, NEXT_STMT_INFO can't be NULL_TREE. */
9213 : 0 : op = vect_get_store_rhs (next_stmt_info);
9214 : 0 : if (costing_p)
9215 : 0 : update_prologue_cost (&prologue_cost, op);
9216 : 0 : else if (!slp)
9217 : : {
9218 : 0 : vect_get_vec_defs_for_operand (vinfo, next_stmt_info,
9219 : : ncopies, op,
9220 : 0 : gvec_oprnds[i]);
9221 : 0 : vec_oprnd = (*gvec_oprnds[i])[0];
9222 : 0 : dr_chain.quick_push (vec_oprnd);
9223 : : }
9224 : 0 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
9225 : : }
9226 : :
9227 : 0 : if (!costing_p)
9228 : : {
9229 : 0 : if (mask)
9230 : : {
9231 : 0 : if (slp_node)
9232 : 0 : vect_get_slp_defs (mask_node, &vec_masks);
9233 : : else
9234 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
9235 : : mask, &vec_masks,
9236 : : mask_vectype);
9237 : 0 : vec_mask = vec_masks[0];
9238 : : }
9239 : :
9240 : 0 : dataref_ptr
9241 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info,
9242 : : aggr_type, NULL, offset, &dummy,
9243 : : gsi, &ptr_incr, false, bump);
9244 : : }
9245 : : }
9246 : 0 : else if (!costing_p)
9247 : : {
9248 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
9249 : : /* DR_CHAIN is then used as an input to
9250 : : vect_permute_store_chain(). */
9251 : 0 : if (!slp)
9252 : : {
9253 : : /* We should have caught mismatched types earlier. */
9254 : 0 : gcc_assert (
9255 : : useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd)));
9256 : 0 : for (i = 0; i < group_size; i++)
9257 : : {
9258 : 0 : vec_oprnd = (*gvec_oprnds[i])[j];
9259 : 0 : dr_chain[i] = vec_oprnd;
9260 : : }
9261 : : }
9262 : 0 : if (mask)
9263 : 0 : vec_mask = vec_masks[j];
9264 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
9265 : : stmt_info, bump);
9266 : : }
9267 : :
9268 : 0 : if (costing_p)
9269 : : {
9270 : 0 : n_adjacent_stores += group_size;
9271 : 0 : continue;
9272 : : }
9273 : :
9274 : : /* Get an array into which we can store the individual vectors. */
9275 : 0 : tree vec_array = create_vector_array (vectype, group_size);
9276 : :
9277 : : /* Invalidate the current contents of VEC_ARRAY. This should
9278 : : become an RTL clobber too, which prevents the vector registers
9279 : : from being upward-exposed. */
9280 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
9281 : :
9282 : : /* Store the individual vectors into the array. */
9283 : 0 : for (i = 0; i < group_size; i++)
9284 : : {
9285 : 0 : if (slp)
9286 : : {
9287 : 0 : slp_tree child;
9288 : 0 : if (i == 0 || !mask_node)
9289 : 0 : child = SLP_TREE_CHILDREN (slp_node)[i];
9290 : : else
9291 : 0 : child = SLP_TREE_CHILDREN (slp_node)[i + 1];
9292 : 0 : vec_oprnd = SLP_TREE_VEC_DEFS (child)[j];
9293 : : }
9294 : : else
9295 : 0 : vec_oprnd = dr_chain[i];
9296 : 0 : write_vector_array (vinfo, stmt_info, gsi, vec_oprnd, vec_array,
9297 : : i);
9298 : : }
9299 : :
9300 : 0 : tree final_mask = NULL;
9301 : 0 : tree final_len = NULL;
9302 : 0 : tree bias = NULL;
9303 : 0 : if (loop_masks)
9304 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
9305 : : ncopies, vectype, j);
9306 : 0 : if (vec_mask)
9307 : 0 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
9308 : : vec_mask, gsi);
9309 : :
9310 : 0 : if (lanes_ifn == IFN_MASK_LEN_STORE_LANES)
9311 : : {
9312 : 0 : if (loop_lens)
9313 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
9314 : : ncopies, vectype, j, 1);
9315 : : else
9316 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
9317 : 0 : signed char biasval
9318 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
9319 : 0 : bias = build_int_cst (intQI_type_node, biasval);
9320 : 0 : if (!final_mask)
9321 : : {
9322 : 0 : mask_vectype = truth_type_for (vectype);
9323 : 0 : final_mask = build_minus_one_cst (mask_vectype);
9324 : : }
9325 : : }
9326 : :
9327 : 0 : gcall *call;
9328 : 0 : if (final_len && final_mask)
9329 : : {
9330 : : /* Emit:
9331 : : MASK_LEN_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
9332 : : LEN, BIAS, VEC_ARRAY). */
9333 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
9334 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
9335 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_STORE_LANES, 6,
9336 : : dataref_ptr, alias_ptr,
9337 : : final_mask, final_len, bias,
9338 : : vec_array);
9339 : : }
9340 : 0 : else if (final_mask)
9341 : : {
9342 : : /* Emit:
9343 : : MASK_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
9344 : : VEC_ARRAY). */
9345 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
9346 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
9347 : 0 : call = gimple_build_call_internal (IFN_MASK_STORE_LANES, 4,
9348 : : dataref_ptr, alias_ptr,
9349 : : final_mask, vec_array);
9350 : : }
9351 : : else
9352 : : {
9353 : : /* Emit:
9354 : : MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY). */
9355 : 0 : data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
9356 : 0 : call = gimple_build_call_internal (IFN_STORE_LANES, 1, vec_array);
9357 : 0 : gimple_call_set_lhs (call, data_ref);
9358 : : }
9359 : 0 : gimple_call_set_nothrow (call, true);
9360 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9361 : 0 : new_stmt = call;
9362 : :
9363 : : /* Record that VEC_ARRAY is now dead. */
9364 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
9365 : 0 : if (j == 0 && !slp)
9366 : 0 : *vec_stmt = new_stmt;
9367 : 0 : if (!slp)
9368 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
9369 : : }
9370 : :
9371 : 0 : if (costing_p)
9372 : : {
9373 : 0 : if (n_adjacent_stores > 0)
9374 : 0 : vect_get_store_cost (vinfo, stmt_info, slp_node, n_adjacent_stores,
9375 : : alignment_support_scheme, misalignment,
9376 : : &inside_cost, cost_vec);
9377 : 0 : if (dump_enabled_p ())
9378 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
9379 : : "vect_model_store_cost: inside_cost = %d, "
9380 : : "prologue_cost = %d .\n",
9381 : : inside_cost, prologue_cost);
9382 : : }
9383 : :
9384 : 0 : return true;
9385 : : }
9386 : :
9387 : 1278374 : if (memory_access_type == VMAT_GATHER_SCATTER)
9388 : : {
9389 : 2626 : gcc_assert (!grouped_store);
9390 : 2626 : auto_vec<tree> vec_offsets;
9391 : 2626 : unsigned int inside_cost = 0, prologue_cost = 0;
9392 : 2626 : int num_stmts = ncopies * vec_num;
9393 : 5728 : for (j = 0; j < num_stmts; j++)
9394 : : {
9395 : 3102 : gimple *new_stmt;
9396 : 3102 : if (j == 0)
9397 : : {
9398 : 2626 : if (costing_p && vls_type == VLS_STORE_INVARIANT)
9399 : 239 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
9400 : : stmt_info, slp_node, 0,
9401 : : vect_prologue);
9402 : 2387 : else if (!costing_p)
9403 : : {
9404 : : /* Since the store is not grouped, DR_GROUP_SIZE is 1, and
9405 : : DR_CHAIN is of size 1. */
9406 : 469 : gcc_assert (group_size == 1);
9407 : 469 : if (slp_node)
9408 : 469 : vect_get_slp_defs (op_node, gvec_oprnds[0]);
9409 : : else
9410 : 0 : vect_get_vec_defs_for_operand (vinfo, first_stmt_info,
9411 : 0 : num_stmts, op, gvec_oprnds[0]);
9412 : 469 : if (mask)
9413 : : {
9414 : 70 : if (slp_node)
9415 : 70 : vect_get_slp_defs (mask_node, &vec_masks);
9416 : : else
9417 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info,
9418 : : num_stmts,
9419 : : mask, &vec_masks,
9420 : : mask_vectype);
9421 : : }
9422 : :
9423 : 469 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
9424 : 469 : vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info,
9425 : : slp_node, &gs_info,
9426 : : &dataref_ptr, &vec_offsets);
9427 : : else
9428 : 0 : dataref_ptr
9429 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info,
9430 : : aggr_type, NULL, offset,
9431 : : &dummy, gsi, &ptr_incr, false,
9432 : : bump);
9433 : : }
9434 : : }
9435 : 476 : else if (!costing_p)
9436 : : {
9437 : 42 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
9438 : 42 : if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info))
9439 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
9440 : : gsi, stmt_info, bump);
9441 : : }
9442 : :
9443 : 3102 : new_stmt = NULL;
9444 : 3102 : if (!costing_p)
9445 : : {
9446 : 511 : vec_oprnd = (*gvec_oprnds[0])[j];
9447 : 511 : if (mask)
9448 : 90 : vec_mask = vec_masks[j];
9449 : : /* We should have catched mismatched types earlier. */
9450 : 511 : gcc_assert (useless_type_conversion_p (vectype,
9451 : : TREE_TYPE (vec_oprnd)));
9452 : : }
9453 : 3102 : unsigned HOST_WIDE_INT align;
9454 : 3102 : tree final_mask = NULL_TREE;
9455 : 3102 : tree final_len = NULL_TREE;
9456 : 3102 : tree bias = NULL_TREE;
9457 : 3102 : if (!costing_p)
9458 : : {
9459 : 511 : if (loop_masks)
9460 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi,
9461 : : loop_masks, num_stmts,
9462 : : vectype, j);
9463 : 511 : if (vec_mask)
9464 : 90 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
9465 : : final_mask, vec_mask, gsi);
9466 : : }
9467 : :
9468 : 3102 : if (gs_info.ifn != IFN_LAST)
9469 : : {
9470 : 0 : if (costing_p)
9471 : : {
9472 : 0 : unsigned int cnunits = vect_nunits_for_cost (vectype);
9473 : 0 : inside_cost
9474 : 0 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
9475 : : stmt_info, slp_node, 0,
9476 : : vect_body);
9477 : 2591 : continue;
9478 : 0 : }
9479 : :
9480 : 0 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
9481 : 0 : vec_offset = vec_offsets[j];
9482 : :
9483 : 0 : tree scale = size_int (gs_info.scale);
9484 : :
9485 : 0 : if (gs_info.ifn == IFN_MASK_LEN_SCATTER_STORE)
9486 : : {
9487 : 0 : if (loop_lens)
9488 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi,
9489 : : loop_lens, num_stmts,
9490 : : vectype, j, 1);
9491 : : else
9492 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
9493 : :
9494 : 0 : signed char biasval
9495 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
9496 : 0 : bias = build_int_cst (intQI_type_node, biasval);
9497 : 0 : if (!final_mask)
9498 : : {
9499 : 0 : mask_vectype = truth_type_for (vectype);
9500 : 0 : final_mask = build_minus_one_cst (mask_vectype);
9501 : : }
9502 : : }
9503 : :
9504 : 0 : gcall *call;
9505 : 0 : if (final_len && final_mask)
9506 : : {
9507 : 0 : if (VECTOR_TYPE_P (TREE_TYPE (vec_offset)))
9508 : 0 : call = gimple_build_call_internal (
9509 : : IFN_MASK_LEN_SCATTER_STORE, 7, dataref_ptr,
9510 : : vec_offset, scale, vec_oprnd, final_mask, final_len,
9511 : : bias);
9512 : : else
9513 : : /* Non-vector offset indicates that prefer to take
9514 : : MASK_LEN_STRIDED_STORE instead of the
9515 : : IFN_MASK_SCATTER_STORE with direct stride arg. */
9516 : 0 : call = gimple_build_call_internal (
9517 : : IFN_MASK_LEN_STRIDED_STORE, 6, dataref_ptr,
9518 : : vec_offset, vec_oprnd, final_mask, final_len, bias);
9519 : : }
9520 : 0 : else if (final_mask)
9521 : 0 : call = gimple_build_call_internal
9522 : 0 : (IFN_MASK_SCATTER_STORE, 5, dataref_ptr,
9523 : : vec_offset, scale, vec_oprnd, final_mask);
9524 : : else
9525 : 0 : call = gimple_build_call_internal (IFN_SCATTER_STORE, 4,
9526 : : dataref_ptr, vec_offset,
9527 : : scale, vec_oprnd);
9528 : 0 : gimple_call_set_nothrow (call, true);
9529 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9530 : 0 : new_stmt = call;
9531 : : }
9532 : 3102 : else if (gs_info.decl)
9533 : : {
9534 : : /* The builtin decls path for scatter is legacy, x86 only. */
9535 : 398 : gcc_assert (nunits.is_constant ()
9536 : : && (!final_mask
9537 : : || SCALAR_INT_MODE_P
9538 : : (TYPE_MODE (TREE_TYPE (final_mask)))));
9539 : 398 : if (costing_p)
9540 : : {
9541 : 255 : unsigned int cnunits = vect_nunits_for_cost (vectype);
9542 : 255 : inside_cost
9543 : 255 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
9544 : : stmt_info, slp_node, 0, vect_body);
9545 : 255 : continue;
9546 : 255 : }
9547 : :
9548 : 143 : poly_uint64 offset_nunits
9549 : 143 : = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype);
9550 : 143 : if (known_eq (nunits, offset_nunits))
9551 : : {
9552 : 134 : new_stmt = vect_build_one_scatter_store_call
9553 : 134 : (vinfo, stmt_info, gsi, &gs_info,
9554 : 67 : dataref_ptr, vec_offsets[j],
9555 : : vec_oprnd, final_mask);
9556 : 67 : vect_finish_stmt_generation (vinfo, stmt_info,
9557 : : new_stmt, gsi);
9558 : : }
9559 : 76 : else if (known_eq (nunits, offset_nunits * 2))
9560 : : {
9561 : : /* We have a offset vector with half the number of
9562 : : lanes but the builtins will store full vectype
9563 : : data from the lower lanes. */
9564 : 30 : new_stmt = vect_build_one_scatter_store_call
9565 : 60 : (vinfo, stmt_info, gsi, &gs_info,
9566 : 30 : dataref_ptr, vec_offsets[2 * j],
9567 : : vec_oprnd, final_mask);
9568 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
9569 : : new_stmt, gsi);
9570 : 30 : int count = nunits.to_constant ();
9571 : 30 : vec_perm_builder sel (count, count, 1);
9572 : 30 : sel.quick_grow (count);
9573 : 382 : for (int i = 0; i < count; ++i)
9574 : 352 : sel[i] = i | (count / 2);
9575 : 30 : vec_perm_indices indices (sel, 2, count);
9576 : 30 : tree perm_mask
9577 : 30 : = vect_gen_perm_mask_checked (vectype, indices);
9578 : 30 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
9579 : : vec_oprnd, vec_oprnd,
9580 : : perm_mask);
9581 : 30 : vec_oprnd = make_ssa_name (vectype);
9582 : 30 : gimple_set_lhs (new_stmt, vec_oprnd);
9583 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
9584 : : new_stmt, gsi);
9585 : 30 : if (final_mask)
9586 : : {
9587 : 20 : new_stmt = gimple_build_assign (NULL_TREE,
9588 : : VEC_UNPACK_HI_EXPR,
9589 : : final_mask);
9590 : 20 : final_mask = make_ssa_name
9591 : 20 : (truth_type_for (gs_info.offset_vectype));
9592 : 20 : gimple_set_lhs (new_stmt, final_mask);
9593 : 20 : vect_finish_stmt_generation (vinfo, stmt_info,
9594 : : new_stmt, gsi);
9595 : : }
9596 : :
9597 : 60 : new_stmt = vect_build_one_scatter_store_call
9598 : 30 : (vinfo, stmt_info, gsi, &gs_info,
9599 : 30 : dataref_ptr, vec_offsets[2 * j + 1],
9600 : : vec_oprnd, final_mask);
9601 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
9602 : : new_stmt, gsi);
9603 : 30 : }
9604 : 46 : else if (known_eq (nunits * 2, offset_nunits))
9605 : : {
9606 : : /* We have a offset vector with double the number of
9607 : : lanes. Select the low/high part accordingly. */
9608 : 46 : vec_offset = vec_offsets[j / 2];
9609 : 46 : if (j & 1)
9610 : : {
9611 : 23 : int count = offset_nunits.to_constant ();
9612 : 23 : vec_perm_builder sel (count, count, 1);
9613 : 23 : sel.quick_grow (count);
9614 : 263 : for (int i = 0; i < count; ++i)
9615 : 240 : sel[i] = i | (count / 2);
9616 : 23 : vec_perm_indices indices (sel, 2, count);
9617 : 23 : tree perm_mask = vect_gen_perm_mask_checked
9618 : 23 : (TREE_TYPE (vec_offset), indices);
9619 : 23 : new_stmt = gimple_build_assign (NULL_TREE,
9620 : : VEC_PERM_EXPR,
9621 : : vec_offset,
9622 : : vec_offset,
9623 : : perm_mask);
9624 : 23 : vec_offset = make_ssa_name (TREE_TYPE (vec_offset));
9625 : 23 : gimple_set_lhs (new_stmt, vec_offset);
9626 : 23 : vect_finish_stmt_generation (vinfo, stmt_info,
9627 : : new_stmt, gsi);
9628 : 23 : }
9629 : :
9630 : 92 : new_stmt = vect_build_one_scatter_store_call
9631 : 46 : (vinfo, stmt_info, gsi, &gs_info,
9632 : : dataref_ptr, vec_offset,
9633 : : vec_oprnd, final_mask);
9634 : 46 : vect_finish_stmt_generation (vinfo, stmt_info,
9635 : : new_stmt, gsi);
9636 : : }
9637 : : else
9638 : 0 : gcc_unreachable ();
9639 : : }
9640 : : else
9641 : : {
9642 : : /* Emulated scatter. */
9643 : 2704 : gcc_assert (!final_mask);
9644 : 2704 : if (costing_p)
9645 : : {
9646 : 2336 : unsigned int cnunits = vect_nunits_for_cost (vectype);
9647 : : /* For emulated scatter N offset vector element extracts
9648 : : (we assume the scalar scaling and ptr + offset add is
9649 : : consumed by the load). */
9650 : 2336 : inside_cost
9651 : 2336 : += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
9652 : : stmt_info, slp_node, 0, vect_body);
9653 : : /* N scalar stores plus extracting the elements. */
9654 : 2336 : inside_cost
9655 : 2336 : += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
9656 : : stmt_info, slp_node, 0, vect_body);
9657 : 2336 : inside_cost
9658 : 2336 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
9659 : : stmt_info, slp_node, 0, vect_body);
9660 : 2336 : continue;
9661 : 2336 : }
9662 : :
9663 : 368 : unsigned HOST_WIDE_INT const_nunits = nunits.to_constant ();
9664 : 368 : unsigned HOST_WIDE_INT const_offset_nunits
9665 : 368 : = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype).to_constant ();
9666 : 368 : vec<constructor_elt, va_gc> *ctor_elts;
9667 : 368 : vec_alloc (ctor_elts, const_nunits);
9668 : 368 : gimple_seq stmts = NULL;
9669 : 368 : tree elt_type = TREE_TYPE (vectype);
9670 : 368 : unsigned HOST_WIDE_INT elt_size
9671 : 368 : = tree_to_uhwi (TYPE_SIZE (elt_type));
9672 : : /* We support offset vectors with more elements
9673 : : than the data vector for now. */
9674 : 368 : unsigned HOST_WIDE_INT factor
9675 : : = const_offset_nunits / const_nunits;
9676 : 368 : vec_offset = vec_offsets[j / factor];
9677 : 368 : unsigned elt_offset
9678 : 368 : = (j % factor) * const_nunits;
9679 : 368 : tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset));
9680 : 368 : tree scale = size_int (gs_info.scale);
9681 : 368 : align = get_object_alignment (DR_REF (first_dr_info->dr));
9682 : 368 : tree ltype = build_aligned_type (TREE_TYPE (vectype), align);
9683 : 1500 : for (unsigned k = 0; k < const_nunits; ++k)
9684 : : {
9685 : : /* Compute the offsetted pointer. */
9686 : 1132 : tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type),
9687 : : bitsize_int (k + elt_offset));
9688 : 1132 : tree idx
9689 : 1132 : = gimple_build (&stmts, BIT_FIELD_REF, idx_type,
9690 : 1132 : vec_offset, TYPE_SIZE (idx_type), boff);
9691 : 1132 : idx = gimple_convert (&stmts, sizetype, idx);
9692 : 1132 : idx = gimple_build (&stmts, MULT_EXPR, sizetype,
9693 : : idx, scale);
9694 : 1132 : tree ptr
9695 : 1132 : = gimple_build (&stmts, PLUS_EXPR,
9696 : 1132 : TREE_TYPE (dataref_ptr),
9697 : : dataref_ptr, idx);
9698 : 1132 : ptr = gimple_convert (&stmts, ptr_type_node, ptr);
9699 : : /* Extract the element to be stored. */
9700 : 1132 : tree elt
9701 : 2264 : = gimple_build (&stmts, BIT_FIELD_REF,
9702 : 1132 : TREE_TYPE (vectype),
9703 : 1132 : vec_oprnd, TYPE_SIZE (elt_type),
9704 : 1132 : bitsize_int (k * elt_size));
9705 : 1132 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
9706 : 1132 : stmts = NULL;
9707 : 1132 : tree ref
9708 : 1132 : = build2 (MEM_REF, ltype, ptr,
9709 : 1132 : build_int_cst (ref_type, 0));
9710 : 1132 : new_stmt = gimple_build_assign (ref, elt);
9711 : 1132 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
9712 : : }
9713 : :
9714 : 368 : if (slp)
9715 : 368 : slp_node->push_vec_def (new_stmt);
9716 : : }
9717 : :
9718 : 511 : if (!slp && !costing_p)
9719 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
9720 : : }
9721 : :
9722 : 2626 : if (!slp && !costing_p)
9723 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
9724 : :
9725 : 2626 : if (costing_p && dump_enabled_p ())
9726 : 96 : dump_printf_loc (MSG_NOTE, vect_location,
9727 : : "vect_model_store_cost: inside_cost = %d, "
9728 : : "prologue_cost = %d .\n",
9729 : : inside_cost, prologue_cost);
9730 : :
9731 : 2626 : return true;
9732 : 2626 : }
9733 : :
9734 : 1275748 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS
9735 : : || memory_access_type == VMAT_CONTIGUOUS_DOWN
9736 : : || memory_access_type == VMAT_CONTIGUOUS_PERMUTE
9737 : : || memory_access_type == VMAT_CONTIGUOUS_REVERSE);
9738 : :
9739 : 1275748 : unsigned inside_cost = 0, prologue_cost = 0;
9740 : : /* For costing some adjacent vector stores, we'd like to cost with
9741 : : the total number of them once instead of cost each one by one. */
9742 : 1275748 : unsigned int n_adjacent_stores = 0;
9743 : 1275748 : auto_vec<tree> result_chain (group_size);
9744 : 1275748 : auto_vec<tree, 1> vec_oprnds;
9745 : 2551496 : for (j = 0; j < ncopies; j++)
9746 : : {
9747 : 1275748 : gimple *new_stmt;
9748 : 1275748 : if (j == 0)
9749 : : {
9750 : 1275748 : if (slp && !costing_p)
9751 : : {
9752 : : /* Get vectorized arguments for SLP_NODE. */
9753 : 530210 : vect_get_vec_defs (vinfo, stmt_info, slp_node, 1, op,
9754 : : &vec_oprnds, mask, &vec_masks);
9755 : 530210 : vec_oprnd = vec_oprnds[0];
9756 : 530210 : if (mask)
9757 : 441 : vec_mask = vec_masks[0];
9758 : : }
9759 : : else
9760 : : {
9761 : : /* For interleaved stores we collect vectorized defs for all the
9762 : : stores in the group in DR_CHAIN. DR_CHAIN is then used as an
9763 : : input to vect_permute_store_chain().
9764 : :
9765 : : If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN
9766 : : is of size 1. */
9767 : : stmt_vec_info next_stmt_info = first_stmt_info;
9768 : 2573496 : for (i = 0; i < group_size; i++)
9769 : : {
9770 : : /* Since gaps are not supported for interleaved stores,
9771 : : DR_GROUP_SIZE is the exact number of stmts in the chain.
9772 : : Therefore, NEXT_STMT_INFO can't be NULL_TREE. In case
9773 : : that there is no interleaving, DR_GROUP_SIZE is 1,
9774 : : and only one iteration of the loop will be executed. */
9775 : 1827958 : op = vect_get_store_rhs (next_stmt_info);
9776 : 1827958 : if (costing_p)
9777 : 1827958 : update_prologue_cost (&prologue_cost, op);
9778 : : else
9779 : : {
9780 : 0 : vect_get_vec_defs_for_operand (vinfo, next_stmt_info,
9781 : : ncopies, op,
9782 : 0 : gvec_oprnds[i]);
9783 : 0 : vec_oprnd = (*gvec_oprnds[i])[0];
9784 : 0 : dr_chain.quick_push (vec_oprnd);
9785 : : }
9786 : 1827958 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
9787 : : }
9788 : 745538 : if (mask && !costing_p)
9789 : : {
9790 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
9791 : : mask, &vec_masks,
9792 : : mask_vectype);
9793 : 0 : vec_mask = vec_masks[0];
9794 : : }
9795 : : }
9796 : :
9797 : : /* We should have catched mismatched types earlier. */
9798 : 1275748 : gcc_assert (costing_p
9799 : : || useless_type_conversion_p (vectype,
9800 : : TREE_TYPE (vec_oprnd)));
9801 : 1275748 : bool simd_lane_access_p
9802 : 1275748 : = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0;
9803 : 1275748 : if (!costing_p
9804 : : && simd_lane_access_p
9805 : 530210 : && !loop_masks
9806 : 4353 : && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR
9807 : 4353 : && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0))
9808 : 4353 : && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info))
9809 : 4353 : && integer_zerop (DR_INIT (first_dr_info->dr))
9810 : 1280101 : && alias_sets_conflict_p (get_alias_set (aggr_type),
9811 : 4353 : get_alias_set (TREE_TYPE (ref_type))))
9812 : : {
9813 : 4345 : dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr));
9814 : 4345 : dataref_offset = build_int_cst (ref_type, 0);
9815 : : }
9816 : 1271403 : else if (!costing_p)
9817 : 525865 : dataref_ptr
9818 : 1051722 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
9819 : : simd_lane_access_p ? loop : NULL,
9820 : : offset, &dummy, gsi, &ptr_incr,
9821 : : simd_lane_access_p, bump);
9822 : : }
9823 : 0 : else if (!costing_p)
9824 : : {
9825 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
9826 : : /* DR_CHAIN is then used as an input to vect_permute_store_chain().
9827 : : If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN is
9828 : : of size 1. */
9829 : 0 : for (i = 0; i < group_size; i++)
9830 : : {
9831 : 0 : vec_oprnd = (*gvec_oprnds[i])[j];
9832 : 0 : dr_chain[i] = vec_oprnd;
9833 : : }
9834 : 0 : if (mask)
9835 : 0 : vec_mask = vec_masks[j];
9836 : 0 : if (dataref_offset)
9837 : 0 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
9838 : : else
9839 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
9840 : : stmt_info, bump);
9841 : : }
9842 : :
9843 : 1275748 : new_stmt = NULL;
9844 : 1275748 : if (grouped_store)
9845 : : {
9846 : : /* Permute. */
9847 : 0 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS_PERMUTE);
9848 : 0 : if (costing_p)
9849 : : {
9850 : 0 : int group_size = DR_GROUP_SIZE (first_stmt_info);
9851 : 0 : int nstmts = ceil_log2 (group_size) * group_size;
9852 : 0 : inside_cost += record_stmt_cost (cost_vec, nstmts, vec_perm,
9853 : : stmt_info, slp_node, 0,
9854 : : vect_body);
9855 : 0 : if (dump_enabled_p ())
9856 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
9857 : : "vect_model_store_cost: "
9858 : : "strided group_size = %d .\n",
9859 : : group_size);
9860 : : }
9861 : : else
9862 : 0 : vect_permute_store_chain (vinfo, dr_chain, group_size, stmt_info,
9863 : : gsi, &result_chain);
9864 : : }
9865 : :
9866 : : stmt_vec_info next_stmt_info = first_stmt_info;
9867 : 2884943 : for (i = 0; i < vec_num; i++)
9868 : : {
9869 : 1609195 : if (!costing_p)
9870 : : {
9871 : 652814 : if (slp)
9872 : 652814 : vec_oprnd = vec_oprnds[i];
9873 : 0 : else if (grouped_store)
9874 : : /* For grouped stores vectorized defs are interleaved in
9875 : : vect_permute_store_chain(). */
9876 : 0 : vec_oprnd = result_chain[i];
9877 : : }
9878 : :
9879 : 1609195 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
9880 : : {
9881 : 3447 : if (costing_p)
9882 : 2318 : inside_cost += record_stmt_cost (cost_vec, 1, vec_perm,
9883 : : stmt_info, slp_node, 0,
9884 : : vect_body);
9885 : : else
9886 : : {
9887 : 1129 : tree perm_mask = perm_mask_for_reverse (vectype);
9888 : 1129 : tree perm_dest = vect_create_destination_var (
9889 : : vect_get_store_rhs (stmt_info), vectype);
9890 : 1129 : tree new_temp = make_ssa_name (perm_dest);
9891 : :
9892 : : /* Generate the permute statement. */
9893 : 1129 : gimple *perm_stmt
9894 : 1129 : = gimple_build_assign (new_temp, VEC_PERM_EXPR, vec_oprnd,
9895 : : vec_oprnd, perm_mask);
9896 : 1129 : vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt,
9897 : : gsi);
9898 : :
9899 : 1129 : perm_stmt = SSA_NAME_DEF_STMT (new_temp);
9900 : 1129 : vec_oprnd = new_temp;
9901 : : }
9902 : : }
9903 : :
9904 : 1609195 : if (costing_p)
9905 : : {
9906 : 956381 : n_adjacent_stores++;
9907 : :
9908 : 956381 : if (!slp)
9909 : : {
9910 : 0 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
9911 : 0 : if (!next_stmt_info)
9912 : : break;
9913 : : }
9914 : :
9915 : 1609195 : continue;
9916 : : }
9917 : :
9918 : 652814 : tree final_mask = NULL_TREE;
9919 : 652814 : tree final_len = NULL_TREE;
9920 : 652814 : tree bias = NULL_TREE;
9921 : 652814 : if (loop_masks)
9922 : 6 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
9923 : : vec_num * ncopies, vectype,
9924 : 6 : vec_num * j + i);
9925 : 652814 : if (slp && vec_mask)
9926 : 498 : vec_mask = vec_masks[i];
9927 : 498 : if (vec_mask)
9928 : 498 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
9929 : : vec_mask, gsi);
9930 : :
9931 : 652814 : if (i > 0)
9932 : : /* Bump the vector pointer. */
9933 : 122604 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
9934 : : stmt_info, bump);
9935 : :
9936 : 652814 : unsigned misalign;
9937 : 652814 : unsigned HOST_WIDE_INT align;
9938 : 652814 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
9939 : 652814 : if (alignment_support_scheme == dr_aligned)
9940 : : misalign = 0;
9941 : 308862 : else if (misalignment == DR_MISALIGNMENT_UNKNOWN)
9942 : : {
9943 : 152833 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
9944 : 152833 : misalign = 0;
9945 : : }
9946 : : else
9947 : 156029 : misalign = misalignment;
9948 : 652814 : if (dataref_offset == NULL_TREE
9949 : 647465 : && TREE_CODE (dataref_ptr) == SSA_NAME)
9950 : 163117 : set_ptr_info_alignment (get_ptr_info (dataref_ptr), align,
9951 : : misalign);
9952 : 652814 : align = least_bit_hwi (misalign | align);
9953 : :
9954 : : /* Compute IFN when LOOP_LENS or final_mask valid. */
9955 : 652814 : machine_mode vmode = TYPE_MODE (vectype);
9956 : 652814 : machine_mode new_vmode = vmode;
9957 : 652814 : internal_fn partial_ifn = IFN_LAST;
9958 : 652814 : if (loop_lens)
9959 : : {
9960 : 0 : opt_machine_mode new_ovmode
9961 : 0 : = get_len_load_store_mode (vmode, false, &partial_ifn);
9962 : 0 : new_vmode = new_ovmode.require ();
9963 : 0 : unsigned factor
9964 : 0 : = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode);
9965 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
9966 : : vec_num * ncopies, vectype,
9967 : 0 : vec_num * j + i, factor);
9968 : : }
9969 : 652814 : else if (final_mask)
9970 : : {
9971 : 504 : if (!can_vec_mask_load_store_p (
9972 : 504 : vmode, TYPE_MODE (TREE_TYPE (final_mask)), false,
9973 : : &partial_ifn))
9974 : 0 : gcc_unreachable ();
9975 : : }
9976 : :
9977 : 652814 : if (partial_ifn == IFN_MASK_LEN_STORE)
9978 : : {
9979 : 0 : if (!final_len)
9980 : : {
9981 : : /* Pass VF value to 'len' argument of
9982 : : MASK_LEN_STORE if LOOP_LENS is invalid. */
9983 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
9984 : : }
9985 : 0 : if (!final_mask)
9986 : : {
9987 : : /* Pass all ones value to 'mask' argument of
9988 : : MASK_LEN_STORE if final_mask is invalid. */
9989 : 0 : mask_vectype = truth_type_for (vectype);
9990 : 0 : final_mask = build_minus_one_cst (mask_vectype);
9991 : : }
9992 : : }
9993 : 652814 : if (final_len)
9994 : : {
9995 : 0 : signed char biasval
9996 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
9997 : :
9998 : 0 : bias = build_int_cst (intQI_type_node, biasval);
9999 : : }
10000 : :
10001 : : /* Arguments are ready. Create the new vector stmt. */
10002 : 652814 : if (final_len)
10003 : : {
10004 : 0 : gcall *call;
10005 : 0 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
10006 : : /* Need conversion if it's wrapped with VnQI. */
10007 : 0 : if (vmode != new_vmode)
10008 : : {
10009 : 0 : tree new_vtype
10010 : 0 : = build_vector_type_for_mode (unsigned_intQI_type_node,
10011 : : new_vmode);
10012 : 0 : tree var = vect_get_new_ssa_name (new_vtype, vect_simple_var);
10013 : 0 : vec_oprnd = build1 (VIEW_CONVERT_EXPR, new_vtype, vec_oprnd);
10014 : 0 : gassign *new_stmt
10015 : 0 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, vec_oprnd);
10016 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10017 : 0 : vec_oprnd = var;
10018 : : }
10019 : :
10020 : 0 : if (partial_ifn == IFN_MASK_LEN_STORE)
10021 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_STORE, 6,
10022 : : dataref_ptr, ptr, final_mask,
10023 : : final_len, bias, vec_oprnd);
10024 : : else
10025 : 0 : call = gimple_build_call_internal (IFN_LEN_STORE, 5,
10026 : : dataref_ptr, ptr, final_len,
10027 : : bias, vec_oprnd);
10028 : 0 : gimple_call_set_nothrow (call, true);
10029 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
10030 : 0 : new_stmt = call;
10031 : : }
10032 : 652814 : else if (final_mask)
10033 : : {
10034 : 504 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
10035 : 504 : gcall *call
10036 : 504 : = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr,
10037 : : ptr, final_mask, vec_oprnd);
10038 : 504 : gimple_call_set_nothrow (call, true);
10039 : 504 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
10040 : 504 : new_stmt = call;
10041 : : }
10042 : : else
10043 : : {
10044 : 652310 : data_ref
10045 : 652310 : = fold_build2 (MEM_REF, vectype, dataref_ptr,
10046 : : dataref_offset ? dataref_offset
10047 : : : build_int_cst (ref_type, 0));
10048 : 652310 : if (alignment_support_scheme == dr_aligned)
10049 : : ;
10050 : : else
10051 : 308506 : TREE_TYPE (data_ref)
10052 : 617012 : = build_aligned_type (TREE_TYPE (data_ref),
10053 : : align * BITS_PER_UNIT);
10054 : 652310 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
10055 : 652310 : new_stmt = gimple_build_assign (data_ref, vec_oprnd);
10056 : 652310 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10057 : : }
10058 : :
10059 : 652814 : if (slp)
10060 : 652814 : continue;
10061 : :
10062 : 0 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
10063 : 0 : if (!next_stmt_info)
10064 : : break;
10065 : : }
10066 : 1275748 : if (!slp && !costing_p)
10067 : : {
10068 : 0 : if (j == 0)
10069 : 0 : *vec_stmt = new_stmt;
10070 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
10071 : : }
10072 : : }
10073 : :
10074 : 1275748 : if (costing_p)
10075 : : {
10076 : 745538 : if (n_adjacent_stores > 0)
10077 : 745538 : vect_get_store_cost (vinfo, stmt_info, slp_node, n_adjacent_stores,
10078 : : alignment_support_scheme, misalignment,
10079 : : &inside_cost, cost_vec);
10080 : :
10081 : : /* When vectorizing a store into the function result assign
10082 : : a penalty if the function returns in a multi-register location.
10083 : : In this case we assume we'll end up with having to spill the
10084 : : vector result and do piecewise loads as a conservative estimate. */
10085 : 745538 : tree base = get_base_address (STMT_VINFO_DATA_REF (stmt_info)->ref);
10086 : 745538 : if (base
10087 : 745538 : && (TREE_CODE (base) == RESULT_DECL
10088 : 681033 : || (DECL_P (base) && cfun_returns (base)))
10089 : 832787 : && !aggregate_value_p (base, cfun->decl))
10090 : : {
10091 : 22396 : rtx reg = hard_function_value (TREE_TYPE (base), cfun->decl, 0, 1);
10092 : : /* ??? Handle PARALLEL in some way. */
10093 : 22396 : if (REG_P (reg))
10094 : : {
10095 : 22173 : int nregs = hard_regno_nregs (REGNO (reg), GET_MODE (reg));
10096 : : /* Assume that a single reg-reg move is possible and cheap,
10097 : : do not account for vector to gp register move cost. */
10098 : 22173 : if (nregs > 1)
10099 : : {
10100 : : /* Spill. */
10101 : 21016 : prologue_cost
10102 : 21016 : += record_stmt_cost (cost_vec, ncopies, vector_store,
10103 : : stmt_info, slp_node, 0, vect_epilogue);
10104 : : /* Loads. */
10105 : 21016 : prologue_cost
10106 : 21016 : += record_stmt_cost (cost_vec, ncopies * nregs, scalar_load,
10107 : : stmt_info, slp_node, 0, vect_epilogue);
10108 : : }
10109 : : }
10110 : : }
10111 : 745538 : if (dump_enabled_p ())
10112 : 14606 : dump_printf_loc (MSG_NOTE, vect_location,
10113 : : "vect_model_store_cost: inside_cost = %d, "
10114 : : "prologue_cost = %d .\n",
10115 : : inside_cost, prologue_cost);
10116 : : }
10117 : :
10118 : 1275748 : return true;
10119 : 2554122 : }
10120 : :
10121 : : /* Given a vector type VECTYPE, turns permutation SEL into the equivalent
10122 : : VECTOR_CST mask. No checks are made that the target platform supports the
10123 : : mask, so callers may wish to test can_vec_perm_const_p separately, or use
10124 : : vect_gen_perm_mask_checked. */
10125 : :
10126 : : tree
10127 : 53239 : vect_gen_perm_mask_any (tree vectype, const vec_perm_indices &sel)
10128 : : {
10129 : 53239 : tree mask_type;
10130 : :
10131 : 53239 : poly_uint64 nunits = sel.length ();
10132 : 53239 : gcc_assert (known_eq (nunits, TYPE_VECTOR_SUBPARTS (vectype)));
10133 : :
10134 : 53239 : mask_type = build_vector_type (ssizetype, nunits);
10135 : 53239 : return vec_perm_indices_to_tree (mask_type, sel);
10136 : : }
10137 : :
10138 : : /* Checked version of vect_gen_perm_mask_any. Asserts can_vec_perm_const_p,
10139 : : i.e. that the target supports the pattern _for arbitrary input vectors_. */
10140 : :
10141 : : tree
10142 : 50756 : vect_gen_perm_mask_checked (tree vectype, const vec_perm_indices &sel)
10143 : : {
10144 : 50756 : machine_mode vmode = TYPE_MODE (vectype);
10145 : 50756 : gcc_assert (can_vec_perm_const_p (vmode, vmode, sel));
10146 : 50756 : return vect_gen_perm_mask_any (vectype, sel);
10147 : : }
10148 : :
10149 : : /* Given a vector variable X and Y, that was generated for the scalar
10150 : : STMT_INFO, generate instructions to permute the vector elements of X and Y
10151 : : using permutation mask MASK_VEC, insert them at *GSI and return the
10152 : : permuted vector variable. */
10153 : :
10154 : : static tree
10155 : 1409 : permute_vec_elements (vec_info *vinfo,
10156 : : tree x, tree y, tree mask_vec, stmt_vec_info stmt_info,
10157 : : gimple_stmt_iterator *gsi)
10158 : : {
10159 : 1409 : tree vectype = TREE_TYPE (x);
10160 : 1409 : tree perm_dest, data_ref;
10161 : 1409 : gimple *perm_stmt;
10162 : :
10163 : 1409 : tree scalar_dest = gimple_get_lhs (stmt_info->stmt);
10164 : 1409 : if (scalar_dest && TREE_CODE (scalar_dest) == SSA_NAME)
10165 : 1409 : perm_dest = vect_create_destination_var (scalar_dest, vectype);
10166 : : else
10167 : 0 : perm_dest = vect_get_new_vect_var (vectype, vect_simple_var, NULL);
10168 : 1409 : data_ref = make_ssa_name (perm_dest);
10169 : :
10170 : : /* Generate the permute statement. */
10171 : 1409 : perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, x, y, mask_vec);
10172 : 1409 : vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
10173 : :
10174 : 1409 : return data_ref;
10175 : : }
10176 : :
10177 : : /* Hoist the definitions of all SSA uses on STMT_INFO out of the loop LOOP,
10178 : : inserting them on the loops preheader edge. Returns true if we
10179 : : were successful in doing so (and thus STMT_INFO can be moved then),
10180 : : otherwise returns false. HOIST_P indicates if we want to hoist the
10181 : : definitions of all SSA uses, it would be false when we are costing. */
10182 : :
10183 : : static bool
10184 : 4401 : hoist_defs_of_uses (gimple *stmt, class loop *loop, bool hoist_p)
10185 : : {
10186 : 4401 : ssa_op_iter i;
10187 : 4401 : use_operand_p use_p;
10188 : 4401 : auto_vec<use_operand_p, 8> to_hoist;
10189 : :
10190 : 8331 : FOR_EACH_SSA_USE_OPERAND (use_p, stmt, i, SSA_OP_USE)
10191 : : {
10192 : 3954 : gimple *def_stmt = SSA_NAME_DEF_STMT (USE_FROM_PTR (use_p));
10193 : 3954 : if (!gimple_nop_p (def_stmt)
10194 : 3954 : && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)))
10195 : : {
10196 : : /* Make sure we don't need to recurse. While we could do
10197 : : so in simple cases when there are more complex use webs
10198 : : we don't have an easy way to preserve stmt order to fulfil
10199 : : dependencies within them. */
10200 : 93 : tree op2;
10201 : 93 : ssa_op_iter i2;
10202 : 93 : if (gimple_code (def_stmt) == GIMPLE_PHI
10203 : 93 : || (single_ssa_def_operand (def_stmt, SSA_OP_DEF)
10204 : : == NULL_DEF_OPERAND_P))
10205 : 24 : return false;
10206 : 182 : FOR_EACH_SSA_TREE_OPERAND (op2, def_stmt, i2, SSA_OP_USE)
10207 : : {
10208 : 113 : gimple *def_stmt2 = SSA_NAME_DEF_STMT (op2);
10209 : 113 : if (!gimple_nop_p (def_stmt2)
10210 : 113 : && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt2)))
10211 : : return false;
10212 : : }
10213 : 69 : to_hoist.safe_push (use_p);
10214 : : }
10215 : : }
10216 : :
10217 : 8754 : if (to_hoist.is_empty ())
10218 : : return true;
10219 : :
10220 : 69 : if (!hoist_p)
10221 : : return true;
10222 : :
10223 : : /* Instead of moving defs we copy them so we can zero their UID to not
10224 : : confuse dominance queries in the preheader. */
10225 : 13 : gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
10226 : 52 : for (use_operand_p use_p : to_hoist)
10227 : : {
10228 : 13 : gimple *def_stmt = SSA_NAME_DEF_STMT (USE_FROM_PTR (use_p));
10229 : 13 : gimple *copy = gimple_copy (def_stmt);
10230 : 13 : gimple_set_uid (copy, 0);
10231 : 13 : def_operand_p def_p = single_ssa_def_operand (def_stmt, SSA_OP_DEF);
10232 : 13 : tree new_def = duplicate_ssa_name (DEF_FROM_PTR (def_p), copy);
10233 : 13 : update_stmt (copy);
10234 : 13 : def_p = single_ssa_def_operand (copy, SSA_OP_DEF);
10235 : 13 : SET_DEF (def_p, new_def);
10236 : 13 : SET_USE (use_p, new_def);
10237 : 13 : gsi_insert_before (&gsi, copy, GSI_SAME_STMT);
10238 : : }
10239 : :
10240 : : return true;
10241 : 4401 : }
10242 : :
10243 : : /* vectorizable_load.
10244 : :
10245 : : Check if STMT_INFO reads a non scalar data-ref (array/pointer/structure)
10246 : : that can be vectorized.
10247 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
10248 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
10249 : : Return true if STMT_INFO is vectorizable in this way. */
10250 : :
10251 : : static bool
10252 : 1921289 : vectorizable_load (vec_info *vinfo,
10253 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
10254 : : gimple **vec_stmt, slp_tree slp_node,
10255 : : stmt_vector_for_cost *cost_vec)
10256 : : {
10257 : 1921289 : tree scalar_dest;
10258 : 1921289 : tree vec_dest = NULL;
10259 : 1921289 : tree data_ref = NULL;
10260 : 1921289 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
10261 : 1921289 : class loop *loop = NULL;
10262 : 1921289 : class loop *containing_loop = gimple_bb (stmt_info->stmt)->loop_father;
10263 : 1921289 : bool nested_in_vect_loop = false;
10264 : 1921289 : tree elem_type;
10265 : : /* Avoid false positive uninitialized warning, see PR110652. */
10266 : 1921289 : tree new_temp = NULL_TREE;
10267 : 1921289 : machine_mode mode;
10268 : 1921289 : tree dummy;
10269 : 1921289 : tree dataref_ptr = NULL_TREE;
10270 : 1921289 : tree dataref_offset = NULL_TREE;
10271 : 1921289 : gimple *ptr_incr = NULL;
10272 : 1921289 : int ncopies;
10273 : 1921289 : int i, j;
10274 : 1921289 : unsigned int group_size;
10275 : 1921289 : poly_uint64 group_gap_adj;
10276 : 1921289 : tree msq = NULL_TREE, lsq;
10277 : 1921289 : tree realignment_token = NULL_TREE;
10278 : 1921289 : gphi *phi = NULL;
10279 : 1921289 : vec<tree> dr_chain = vNULL;
10280 : 1921289 : bool grouped_load = false;
10281 : 1921289 : stmt_vec_info first_stmt_info;
10282 : 1921289 : stmt_vec_info first_stmt_info_for_drptr = NULL;
10283 : 1921289 : bool compute_in_loop = false;
10284 : 1921289 : class loop *at_loop;
10285 : 1921289 : int vec_num;
10286 : 1921289 : bool slp = (slp_node != NULL);
10287 : 1921289 : bool slp_perm = false;
10288 : 1921289 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
10289 : 1921289 : poly_uint64 vf;
10290 : 1921289 : tree aggr_type;
10291 : 1921289 : gather_scatter_info gs_info;
10292 : 1921289 : tree ref_type;
10293 : 1921289 : enum vect_def_type mask_dt = vect_unknown_def_type;
10294 : 1921289 : enum vect_def_type els_dt = vect_unknown_def_type;
10295 : :
10296 : 1921289 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
10297 : : return false;
10298 : :
10299 : 1921289 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
10300 : 186872 : && ! vec_stmt)
10301 : : return false;
10302 : :
10303 : 1734417 : if (!STMT_VINFO_DATA_REF (stmt_info))
10304 : : return false;
10305 : :
10306 : 1420342 : tree mask = NULL_TREE, mask_vectype = NULL_TREE;
10307 : 1420342 : tree els = NULL_TREE; tree els_vectype = NULL_TREE;
10308 : :
10309 : 1420342 : int mask_index = -1;
10310 : 1420342 : int els_index = -1;
10311 : 1420342 : slp_tree slp_op = NULL;
10312 : 1420342 : slp_tree els_op = NULL;
10313 : 1420342 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
10314 : : {
10315 : 1416827 : scalar_dest = gimple_assign_lhs (assign);
10316 : 1416827 : if (TREE_CODE (scalar_dest) != SSA_NAME)
10317 : : return false;
10318 : :
10319 : 638348 : tree_code code = gimple_assign_rhs_code (assign);
10320 : 638348 : if (code != ARRAY_REF
10321 : 638348 : && code != BIT_FIELD_REF
10322 : 638348 : && code != INDIRECT_REF
10323 : 430047 : && code != COMPONENT_REF
10324 : 430047 : && code != IMAGPART_EXPR
10325 : 215066 : && code != REALPART_EXPR
10326 : 215066 : && code != MEM_REF
10327 : 213 : && TREE_CODE_CLASS (code) != tcc_declaration)
10328 : : return false;
10329 : : }
10330 : : else
10331 : : {
10332 : 1284336 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
10333 : 3515 : if (!call || !gimple_call_internal_p (call))
10334 : : return false;
10335 : :
10336 : 3515 : internal_fn ifn = gimple_call_internal_fn (call);
10337 : 3515 : if (!internal_load_fn_p (ifn))
10338 : : return false;
10339 : :
10340 : 2436 : scalar_dest = gimple_call_lhs (call);
10341 : 2436 : if (!scalar_dest)
10342 : : return false;
10343 : :
10344 : 2436 : mask_index = internal_fn_mask_index (ifn);
10345 : 2436 : if (mask_index >= 0 && slp_node)
10346 : 2436 : mask_index = vect_slp_child_index_for_operand
10347 : 2436 : (call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
10348 : 2436 : if (mask_index >= 0
10349 : 2436 : && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index,
10350 : : &mask, &slp_op, &mask_dt, &mask_vectype))
10351 : : return false;
10352 : :
10353 : 2436 : els_index = internal_fn_else_index (ifn);
10354 : 2436 : if (els_index >= 0 && slp_node)
10355 : 2436 : els_index = vect_slp_child_index_for_operand
10356 : 2436 : (call, els_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
10357 : 2436 : if (els_index >= 0
10358 : 2436 : && !vect_is_simple_use (vinfo, stmt_info, slp_node, els_index,
10359 : : &els, &els_op, &els_dt, &els_vectype))
10360 : : return false;
10361 : : }
10362 : :
10363 : 640784 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
10364 : 640784 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
10365 : :
10366 : 640784 : if (loop_vinfo)
10367 : : {
10368 : 411498 : loop = LOOP_VINFO_LOOP (loop_vinfo);
10369 : 411498 : nested_in_vect_loop = nested_in_vect_loop_p (loop, stmt_info);
10370 : 411498 : vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
10371 : : }
10372 : : else
10373 : : vf = 1;
10374 : :
10375 : : /* Multiple types in SLP are handled by creating the appropriate number of
10376 : : vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
10377 : : case of SLP. */
10378 : 640784 : if (slp)
10379 : : ncopies = 1;
10380 : : else
10381 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
10382 : :
10383 : 0 : gcc_assert (ncopies >= 1);
10384 : :
10385 : : /* FORNOW. This restriction should be relaxed. */
10386 : 640784 : if (nested_in_vect_loop
10387 : 1440 : && (ncopies > 1 || (slp && SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) > 1)))
10388 : : {
10389 : 304 : if (dump_enabled_p ())
10390 : 72 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10391 : : "multiple types in nested loop.\n");
10392 : 304 : return false;
10393 : : }
10394 : :
10395 : : /* Invalidate assumptions made by dependence analysis when vectorization
10396 : : on the unrolled body effectively re-orders stmts. */
10397 : 640480 : if (ncopies > 1
10398 : 0 : && STMT_VINFO_MIN_NEG_DIST (stmt_info) != 0
10399 : 640480 : && maybe_gt (LOOP_VINFO_VECT_FACTOR (loop_vinfo),
10400 : : STMT_VINFO_MIN_NEG_DIST (stmt_info)))
10401 : : {
10402 : 0 : if (dump_enabled_p ())
10403 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10404 : : "cannot perform implicit CSE when unrolling "
10405 : : "with negative dependence distance\n");
10406 : 0 : return false;
10407 : : }
10408 : :
10409 : 640480 : elem_type = TREE_TYPE (vectype);
10410 : 640480 : mode = TYPE_MODE (vectype);
10411 : :
10412 : : /* FORNOW. In some cases can vectorize even if data-type not supported
10413 : : (e.g. - data copies). */
10414 : 640480 : if (!can_implement_p (mov_optab, mode))
10415 : : {
10416 : 0 : if (dump_enabled_p ())
10417 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10418 : : "Aligned load, but unsupported type.\n");
10419 : 0 : return false;
10420 : : }
10421 : :
10422 : : /* Check if the load is a part of an interleaving chain. */
10423 : 640480 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
10424 : : {
10425 : 316733 : grouped_load = true;
10426 : : /* FORNOW */
10427 : 316733 : gcc_assert (!nested_in_vect_loop);
10428 : 316733 : gcc_assert (!STMT_VINFO_GATHER_SCATTER_P (stmt_info));
10429 : :
10430 : 316733 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
10431 : 316733 : group_size = DR_GROUP_SIZE (first_stmt_info);
10432 : :
10433 : : /* Refuse non-SLP vectorization of SLP-only groups. */
10434 : 316733 : if (!slp && STMT_VINFO_SLP_VECT_ONLY (first_stmt_info))
10435 : : {
10436 : 0 : if (dump_enabled_p ())
10437 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10438 : : "cannot vectorize load in non-SLP mode.\n");
10439 : 0 : return false;
10440 : : }
10441 : :
10442 : : /* Invalidate assumptions made by dependence analysis when vectorization
10443 : : on the unrolled body effectively re-orders stmts. */
10444 : 316733 : if (STMT_VINFO_MIN_NEG_DIST (stmt_info) != 0
10445 : 316733 : && maybe_gt (LOOP_VINFO_VECT_FACTOR (loop_vinfo),
10446 : : STMT_VINFO_MIN_NEG_DIST (stmt_info)))
10447 : : {
10448 : 12 : if (dump_enabled_p ())
10449 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10450 : : "cannot perform implicit CSE when performing "
10451 : : "group loads with negative dependence distance\n");
10452 : 12 : return false;
10453 : : }
10454 : : }
10455 : : else
10456 : : group_size = 1;
10457 : :
10458 : 640468 : vect_memory_access_type memory_access_type;
10459 : 640468 : enum dr_alignment_support alignment_support_scheme;
10460 : 640468 : int misalignment;
10461 : 640468 : poly_int64 poffset;
10462 : 640468 : internal_fn lanes_ifn;
10463 : 640468 : auto_vec<int> elsvals;
10464 : 640468 : int maskload_elsval = 0;
10465 : 640468 : bool need_zeroing = false;
10466 : 640468 : if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, VLS_LOAD,
10467 : : ncopies, &memory_access_type, &poffset,
10468 : : &alignment_support_scheme, &misalignment, &gs_info,
10469 : : &lanes_ifn, &elsvals))
10470 : : return false;
10471 : :
10472 : :
10473 : : /* We might need to explicitly zero inactive elements if there are
10474 : : padding bits in the type that might leak otherwise.
10475 : : Refer to PR115336. */
10476 : 562294 : tree scalar_type = TREE_TYPE (scalar_dest);
10477 : 562294 : bool type_mode_padding_p
10478 : 1124588 : = TYPE_PRECISION (scalar_type) < GET_MODE_PRECISION (GET_MODE_INNER (mode));
10479 : :
10480 : : /* ??? The following checks should really be part of
10481 : : get_group_load_store_type. */
10482 : 562294 : if (slp
10483 : 562294 : && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
10484 : 612676 : && !((memory_access_type == VMAT_ELEMENTWISE
10485 : 46855 : || memory_access_type == VMAT_GATHER_SCATTER)
10486 : 3527 : && SLP_TREE_LANES (slp_node) == 1))
10487 : : {
10488 : 46855 : slp_perm = true;
10489 : :
10490 : 46855 : if (!loop_vinfo)
10491 : : {
10492 : : /* In BB vectorization we may not actually use a loaded vector
10493 : : accessing elements in excess of DR_GROUP_SIZE. */
10494 : 20590 : stmt_vec_info group_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
10495 : 20590 : group_info = DR_GROUP_FIRST_ELEMENT (group_info);
10496 : 20590 : unsigned HOST_WIDE_INT nunits;
10497 : 20590 : unsigned j, k, maxk = 0;
10498 : 81260 : FOR_EACH_VEC_ELT (SLP_TREE_LOAD_PERMUTATION (slp_node), j, k)
10499 : 60670 : if (k > maxk)
10500 : : maxk = k;
10501 : 20590 : tree vectype = SLP_TREE_VECTYPE (slp_node);
10502 : 36842 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits)
10503 : 20590 : || maxk >= (DR_GROUP_SIZE (group_info) & ~(nunits - 1)))
10504 : : {
10505 : 4338 : if (dump_enabled_p ())
10506 : 33 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10507 : : "BB vectorization with gaps at the end of "
10508 : : "a load is not supported\n");
10509 : 4338 : return false;
10510 : : }
10511 : : }
10512 : :
10513 : 42517 : auto_vec<tree> tem;
10514 : 42517 : unsigned n_perms;
10515 : 42517 : if (!vect_transform_slp_perm_load (vinfo, slp_node, tem, NULL, vf,
10516 : : true, &n_perms))
10517 : : {
10518 : 2498 : if (dump_enabled_p ())
10519 : 144 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
10520 : : vect_location,
10521 : : "unsupported load permutation\n");
10522 : 2498 : return false;
10523 : : }
10524 : 42517 : }
10525 : :
10526 : 555458 : if (slp_node
10527 : 555458 : && slp_node->ldst_lanes
10528 : 0 : && memory_access_type != VMAT_LOAD_STORE_LANES)
10529 : : {
10530 : 0 : if (dump_enabled_p ())
10531 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10532 : : "discovered load-lane but cannot use it.\n");
10533 : 0 : return false;
10534 : : }
10535 : :
10536 : 555458 : if (mask)
10537 : : {
10538 : 2324 : if (memory_access_type == VMAT_CONTIGUOUS)
10539 : : {
10540 : 1499 : machine_mode vec_mode = TYPE_MODE (vectype);
10541 : 376 : if (!VECTOR_MODE_P (vec_mode)
10542 : 2998 : || !can_vec_mask_load_store_p (vec_mode,
10543 : 1499 : TYPE_MODE (mask_vectype),
10544 : : true, NULL, &elsvals))
10545 : 51 : return false;
10546 : : }
10547 : 825 : else if (memory_access_type != VMAT_LOAD_STORE_LANES
10548 : 825 : && memory_access_type != VMAT_GATHER_SCATTER)
10549 : : {
10550 : 54 : if (dump_enabled_p ())
10551 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10552 : : "unsupported access type for masked load.\n");
10553 : 54 : return false;
10554 : : }
10555 : 771 : else if (memory_access_type == VMAT_GATHER_SCATTER
10556 : 771 : && gs_info.ifn == IFN_LAST
10557 : 771 : && !gs_info.decl)
10558 : : {
10559 : 466 : if (dump_enabled_p ())
10560 : 26 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10561 : : "unsupported masked emulated gather.\n");
10562 : 466 : return false;
10563 : : }
10564 : : else if (memory_access_type == VMAT_ELEMENTWISE
10565 : : || memory_access_type == VMAT_STRIDED_SLP)
10566 : : {
10567 : : if (dump_enabled_p ())
10568 : : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10569 : : "unsupported masked strided access.\n");
10570 : : return false;
10571 : : }
10572 : : }
10573 : :
10574 : 554887 : bool costing_p = !vec_stmt;
10575 : :
10576 : 554887 : if (costing_p) /* transformation not required. */
10577 : : {
10578 : 400188 : if (slp_node
10579 : 400188 : && mask
10580 : 401359 : && !vect_maybe_update_slp_op_vectype (slp_op,
10581 : : mask_vectype))
10582 : : {
10583 : 0 : if (dump_enabled_p ())
10584 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10585 : : "incompatible vector types for invariants\n");
10586 : 0 : return false;
10587 : : }
10588 : :
10589 : 400188 : if (!slp)
10590 : 0 : STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info) = memory_access_type;
10591 : : else
10592 : 400188 : SLP_TREE_MEMORY_ACCESS_TYPE (slp_node) = memory_access_type;
10593 : :
10594 : 400188 : if (loop_vinfo
10595 : 258318 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
10596 : 56 : check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
10597 : : VLS_LOAD, group_size,
10598 : : memory_access_type, &gs_info,
10599 : : mask, &elsvals);
10600 : :
10601 : 400188 : if (dump_enabled_p ()
10602 : 27041 : && memory_access_type != VMAT_ELEMENTWISE
10603 : : && memory_access_type != VMAT_GATHER_SCATTER
10604 : : && memory_access_type != VMAT_STRIDED_SLP
10605 : 26141 : && memory_access_type != VMAT_INVARIANT
10606 : 425764 : && alignment_support_scheme != dr_aligned)
10607 : 11345 : dump_printf_loc (MSG_NOTE, vect_location,
10608 : : "Vectorizing an unaligned access.\n");
10609 : :
10610 : 400188 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
10611 : 0 : vinfo->any_known_not_updated_vssa = true;
10612 : :
10613 : 400188 : STMT_VINFO_TYPE (stmt_info) = load_vec_info_type;
10614 : : }
10615 : : else
10616 : : {
10617 : : /* Here just get the else values. */
10618 : 154699 : if (loop_vinfo
10619 : 73567 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
10620 : 26 : check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
10621 : : VLS_LOAD, group_size,
10622 : : memory_access_type, &gs_info,
10623 : : mask, &elsvals);
10624 : : }
10625 : :
10626 : : /* If the type needs padding we must zero inactive elements.
10627 : : Check if we can do that with a VEC_COND_EXPR and store the
10628 : : elsval we choose in MASKLOAD_ELSVAL. */
10629 : 554887 : if (elsvals.length ()
10630 : 1508 : && type_mode_padding_p
10631 : 0 : && !elsvals.contains (MASK_LOAD_ELSE_ZERO)
10632 : 1508 : && !expand_vec_cond_expr_p (vectype, truth_type_for (vectype)))
10633 : : {
10634 : 0 : if (dump_enabled_p ())
10635 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
10636 : : "cannot zero inactive elements.\n");
10637 : 0 : return false;
10638 : : }
10639 : :
10640 : : /* For now just use the first available else value.
10641 : : get_supported_else_vals tries MASK_LOAD_ELSE_ZERO first so we will
10642 : : select it here if it is supported. */
10643 : 554887 : if (elsvals.length ())
10644 : 1508 : maskload_elsval = *elsvals.begin ();
10645 : :
10646 : 554887 : if (!slp)
10647 : 0 : gcc_assert (memory_access_type
10648 : : == STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info));
10649 : : else
10650 : 554887 : gcc_assert (memory_access_type
10651 : : == SLP_TREE_MEMORY_ACCESS_TYPE (slp_node));
10652 : :
10653 : 554887 : if (dump_enabled_p () && !costing_p)
10654 : 15417 : dump_printf_loc (MSG_NOTE, vect_location,
10655 : : "transform load. ncopies = %d\n", ncopies);
10656 : :
10657 : : /* Transform. */
10658 : :
10659 : 554887 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL;
10660 : 554887 : ensure_base_align (dr_info);
10661 : :
10662 : 554887 : if (memory_access_type == VMAT_INVARIANT)
10663 : : {
10664 : 4397 : gcc_assert (!grouped_load && !mask && !bb_vinfo);
10665 : : /* If we have versioned for aliasing or the loop doesn't
10666 : : have any data dependencies that would preclude this,
10667 : : then we are sure this is a loop invariant load and
10668 : : thus we can insert it on the preheader edge.
10669 : : TODO: hoist_defs_of_uses should ideally be computed
10670 : : once at analysis time, remembered and used in the
10671 : : transform time. */
10672 : 4397 : bool hoist_p = (LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo)
10673 : 4193 : && !nested_in_vect_loop
10674 : 8178 : && hoist_defs_of_uses (stmt_info->stmt, loop, false));
10675 : 4397 : if (costing_p)
10676 : : {
10677 : 7174 : enum vect_cost_model_location cost_loc
10678 : 3587 : = hoist_p ? vect_prologue : vect_body;
10679 : 3587 : unsigned int cost = record_stmt_cost (cost_vec, 1, scalar_load,
10680 : : stmt_info, slp_node, 0,
10681 : : cost_loc);
10682 : 3587 : cost += record_stmt_cost (cost_vec, 1, scalar_to_vec, stmt_info,
10683 : : slp_node, 0, cost_loc);
10684 : 3587 : unsigned int prologue_cost = hoist_p ? cost : 0;
10685 : 450 : unsigned int inside_cost = hoist_p ? 0 : cost;
10686 : 3587 : if (dump_enabled_p ())
10687 : 565 : dump_printf_loc (MSG_NOTE, vect_location,
10688 : : "vect_model_load_cost: inside_cost = %d, "
10689 : : "prologue_cost = %d .\n",
10690 : : inside_cost, prologue_cost);
10691 : 3587 : return true;
10692 : : }
10693 : 810 : if (hoist_p)
10694 : : {
10695 : 620 : gassign *stmt = as_a <gassign *> (stmt_info->stmt);
10696 : 620 : if (dump_enabled_p ())
10697 : 208 : dump_printf_loc (MSG_NOTE, vect_location,
10698 : : "hoisting out of the vectorized loop: %G",
10699 : : (gimple *) stmt);
10700 : 620 : scalar_dest = copy_ssa_name (scalar_dest);
10701 : 620 : tree rhs = unshare_expr (gimple_assign_rhs1 (stmt));
10702 : 620 : edge pe = loop_preheader_edge (loop);
10703 : 620 : gphi *vphi = get_virtual_phi (loop->header);
10704 : 620 : tree vuse;
10705 : 620 : if (vphi)
10706 : 614 : vuse = PHI_ARG_DEF_FROM_EDGE (vphi, pe);
10707 : : else
10708 : 6 : vuse = gimple_vuse (gsi_stmt (*gsi));
10709 : 620 : gimple *new_stmt = gimple_build_assign (scalar_dest, rhs);
10710 : 620 : gimple_set_vuse (new_stmt, vuse);
10711 : 620 : gsi_insert_on_edge_immediate (pe, new_stmt);
10712 : 620 : hoist_defs_of_uses (new_stmt, loop, true);
10713 : : }
10714 : : /* These copies are all equivalent. */
10715 : 810 : if (hoist_p)
10716 : 620 : new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest,
10717 : : vectype, NULL);
10718 : : else
10719 : : {
10720 : 190 : gimple_stmt_iterator gsi2 = *gsi;
10721 : 190 : gsi_next (&gsi2);
10722 : 190 : new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest,
10723 : : vectype, &gsi2);
10724 : : }
10725 : 810 : gimple *new_stmt = SSA_NAME_DEF_STMT (new_temp);
10726 : 810 : if (slp)
10727 : 1682 : for (j = 0; j < (int) SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); ++j)
10728 : 872 : slp_node->push_vec_def (new_stmt);
10729 : : else
10730 : : {
10731 : 0 : for (j = 0; j < ncopies; ++j)
10732 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
10733 : 0 : *vec_stmt = new_stmt;
10734 : : }
10735 : 810 : return true;
10736 : : }
10737 : :
10738 : 550490 : if (memory_access_type == VMAT_ELEMENTWISE
10739 : 550490 : || memory_access_type == VMAT_STRIDED_SLP)
10740 : : {
10741 : 20682 : gimple_stmt_iterator incr_gsi;
10742 : 20682 : bool insert_after;
10743 : 20682 : tree offvar = NULL_TREE;
10744 : 20682 : tree ivstep;
10745 : 20682 : tree running_off;
10746 : 20682 : vec<constructor_elt, va_gc> *v = NULL;
10747 : 20682 : tree stride_base, stride_step, alias_off;
10748 : : /* Checked by get_load_store_type. */
10749 : 20682 : unsigned int const_nunits = nunits.to_constant ();
10750 : 20682 : unsigned HOST_WIDE_INT cst_offset = 0;
10751 : 20682 : tree dr_offset;
10752 : 20682 : unsigned int inside_cost = 0;
10753 : :
10754 : 20682 : gcc_assert (!LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo));
10755 : 20682 : gcc_assert (!nested_in_vect_loop);
10756 : :
10757 : 20682 : if (grouped_load)
10758 : : {
10759 : 8065 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
10760 : 8065 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
10761 : : }
10762 : : else
10763 : : {
10764 : : first_stmt_info = stmt_info;
10765 : : first_dr_info = dr_info;
10766 : : }
10767 : :
10768 : 8065 : if (slp && grouped_load
10769 : 8065 : && memory_access_type == VMAT_STRIDED_SLP)
10770 : : {
10771 : 4380 : group_size = DR_GROUP_SIZE (first_stmt_info);
10772 : 4380 : ref_type = get_group_alias_ptr_type (first_stmt_info);
10773 : : }
10774 : : else
10775 : : {
10776 : 16302 : if (grouped_load)
10777 : 3685 : cst_offset
10778 : 3685 : = (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)))
10779 : 3685 : * vect_get_place_in_interleaving_chain (stmt_info,
10780 : : first_stmt_info));
10781 : 16302 : group_size = 1;
10782 : 16302 : ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr));
10783 : : }
10784 : :
10785 : 20682 : if (!costing_p)
10786 : : {
10787 : 2584 : dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info);
10788 : 2584 : stride_base = fold_build_pointer_plus (
10789 : : DR_BASE_ADDRESS (first_dr_info->dr),
10790 : : size_binop (PLUS_EXPR, convert_to_ptrofftype (dr_offset),
10791 : : convert_to_ptrofftype (DR_INIT (first_dr_info->dr))));
10792 : 2584 : stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr));
10793 : :
10794 : : /* For a load with loop-invariant (but other than power-of-2)
10795 : : stride (i.e. not a grouped access) like so:
10796 : :
10797 : : for (i = 0; i < n; i += stride)
10798 : : ... = array[i];
10799 : :
10800 : : we generate a new induction variable and new accesses to
10801 : : form a new vector (or vectors, depending on ncopies):
10802 : :
10803 : : for (j = 0; ; j += VF*stride)
10804 : : tmp1 = array[j];
10805 : : tmp2 = array[j + stride];
10806 : : ...
10807 : : vectemp = {tmp1, tmp2, ...}
10808 : : */
10809 : :
10810 : 2584 : ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (stride_step), stride_step,
10811 : : build_int_cst (TREE_TYPE (stride_step), vf));
10812 : :
10813 : 2584 : standard_iv_increment_position (loop, &incr_gsi, &insert_after);
10814 : :
10815 : 2584 : stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base);
10816 : 2584 : ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep);
10817 : 2584 : create_iv (stride_base, PLUS_EXPR, ivstep, NULL,
10818 : : loop, &incr_gsi, insert_after,
10819 : : &offvar, NULL);
10820 : :
10821 : 2584 : stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step);
10822 : : }
10823 : :
10824 : 20682 : running_off = offvar;
10825 : 20682 : alias_off = build_int_cst (ref_type, 0);
10826 : 20682 : int nloads = const_nunits;
10827 : 20682 : int lnel = 1;
10828 : 20682 : tree ltype = TREE_TYPE (vectype);
10829 : 20682 : tree lvectype = vectype;
10830 : 20682 : auto_vec<tree> dr_chain;
10831 : 20682 : if (memory_access_type == VMAT_STRIDED_SLP)
10832 : : {
10833 : 16997 : HOST_WIDE_INT n = gcd (group_size, const_nunits);
10834 : : /* Use the target vector type if the group size is a multiple
10835 : : of it. */
10836 : 16997 : if (n == const_nunits)
10837 : : {
10838 : 1783 : int mis_align = dr_misalignment (first_dr_info, vectype);
10839 : 1783 : dr_alignment_support dr_align
10840 : 1783 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype,
10841 : : mis_align);
10842 : 1783 : if (dr_align == dr_aligned
10843 : 1783 : || dr_align == dr_unaligned_supported)
10844 : : {
10845 : 1783 : nloads = 1;
10846 : 1783 : lnel = const_nunits;
10847 : 1783 : ltype = vectype;
10848 : 1783 : alignment_support_scheme = dr_align;
10849 : 1783 : misalignment = mis_align;
10850 : : }
10851 : : }
10852 : : /* Else use the biggest vector we can load the group without
10853 : : accessing excess elements. */
10854 : 15214 : else if (n > 1)
10855 : : {
10856 : 2662 : tree ptype;
10857 : 2662 : tree vtype
10858 : 2662 : = vector_vector_composition_type (vectype, const_nunits / n,
10859 : : &ptype);
10860 : 2662 : if (vtype != NULL_TREE)
10861 : : {
10862 : 2584 : dr_alignment_support dr_align;
10863 : 2584 : int mis_align = 0;
10864 : 2584 : if (VECTOR_TYPE_P (ptype))
10865 : : {
10866 : 1289 : mis_align = dr_misalignment (first_dr_info, ptype);
10867 : 1289 : dr_align
10868 : 1289 : = vect_supportable_dr_alignment (vinfo, dr_info, ptype,
10869 : : mis_align);
10870 : : }
10871 : : else
10872 : : dr_align = dr_unaligned_supported;
10873 : 2584 : if (dr_align == dr_aligned
10874 : 2584 : || dr_align == dr_unaligned_supported)
10875 : : {
10876 : 2584 : nloads = const_nunits / n;
10877 : 2584 : lnel = n;
10878 : 2584 : lvectype = vtype;
10879 : 2584 : ltype = ptype;
10880 : 2584 : alignment_support_scheme = dr_align;
10881 : 2584 : misalignment = mis_align;
10882 : : }
10883 : : }
10884 : : }
10885 : 16997 : unsigned align;
10886 : 16997 : if (alignment_support_scheme == dr_aligned)
10887 : 32 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
10888 : : else
10889 : 16965 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
10890 : : /* Alignment is at most the access size if we do multiple loads. */
10891 : 16997 : if (nloads > 1)
10892 : 15214 : align = MIN (tree_to_uhwi (TYPE_SIZE_UNIT (ltype)), align);
10893 : 16997 : ltype = build_aligned_type (ltype, align * BITS_PER_UNIT);
10894 : : }
10895 : :
10896 : 20682 : if (slp)
10897 : : {
10898 : : /* For SLP permutation support we need to load the whole group,
10899 : : not only the number of vector stmts the permutation result
10900 : : fits in. */
10901 : 20682 : if (slp_perm)
10902 : : {
10903 : : /* We don't yet generate SLP_TREE_LOAD_PERMUTATIONs for
10904 : : variable VF. */
10905 : 2971 : unsigned int const_vf = vf.to_constant ();
10906 : 2971 : ncopies = CEIL (group_size * const_vf, const_nunits);
10907 : 2971 : dr_chain.create (ncopies);
10908 : : }
10909 : : else
10910 : 17711 : ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
10911 : : }
10912 : 20682 : unsigned int group_el = 0;
10913 : 20682 : unsigned HOST_WIDE_INT
10914 : 20682 : elsz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
10915 : 20682 : unsigned int n_groups = 0;
10916 : : /* For costing some adjacent vector loads, we'd like to cost with
10917 : : the total number of them once instead of cost each one by one. */
10918 : 20682 : unsigned int n_adjacent_loads = 0;
10919 : 47949 : for (j = 0; j < ncopies; j++)
10920 : : {
10921 : 27267 : if (nloads > 1 && !costing_p)
10922 : 2094 : vec_alloc (v, nloads);
10923 : 27267 : gimple *new_stmt = NULL;
10924 : 133851 : for (i = 0; i < nloads; i++)
10925 : : {
10926 : 106584 : if (costing_p)
10927 : : {
10928 : : /* For VMAT_ELEMENTWISE, just cost it as scalar_load to
10929 : : avoid ICE, see PR110776. */
10930 : 98490 : if (VECTOR_TYPE_P (ltype)
10931 : 6090 : && memory_access_type != VMAT_ELEMENTWISE)
10932 : 6090 : n_adjacent_loads++;
10933 : : else
10934 : 92400 : inside_cost += record_stmt_cost (cost_vec, 1, scalar_load,
10935 : : stmt_info, slp_node, 0,
10936 : : vect_body);
10937 : 98490 : continue;
10938 : : }
10939 : 8094 : tree this_off = build_int_cst (TREE_TYPE (alias_off),
10940 : 8094 : group_el * elsz + cst_offset);
10941 : 8094 : tree data_ref = build2 (MEM_REF, ltype, running_off, this_off);
10942 : 8094 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
10943 : 8094 : new_temp = make_ssa_name (ltype);
10944 : 8094 : new_stmt = gimple_build_assign (new_temp, data_ref);
10945 : 8094 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10946 : 8094 : if (nloads > 1)
10947 : 6746 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, new_temp);
10948 : :
10949 : 8094 : group_el += lnel;
10950 : 8094 : if (! slp
10951 : 8094 : || group_el == group_size)
10952 : : {
10953 : 7788 : n_groups++;
10954 : : /* When doing SLP make sure to not load elements from
10955 : : the next vector iteration, those will not be accessed
10956 : : so just use the last element again. See PR107451. */
10957 : 7788 : if (!slp || known_lt (n_groups, vf))
10958 : : {
10959 : 5182 : tree newoff = copy_ssa_name (running_off);
10960 : 5182 : gimple *incr
10961 : 5182 : = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
10962 : : running_off, stride_step);
10963 : 5182 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
10964 : 5182 : running_off = newoff;
10965 : : }
10966 : : group_el = 0;
10967 : : }
10968 : : }
10969 : :
10970 : 27267 : if (nloads > 1)
10971 : : {
10972 : 22837 : if (costing_p)
10973 : 20743 : inside_cost += record_stmt_cost (cost_vec, 1, vec_construct,
10974 : : stmt_info, slp_node, 0,
10975 : : vect_body);
10976 : : else
10977 : : {
10978 : 2094 : tree vec_inv = build_constructor (lvectype, v);
10979 : 2094 : new_temp = vect_init_vector (vinfo, stmt_info, vec_inv,
10980 : : lvectype, gsi);
10981 : 2094 : new_stmt = SSA_NAME_DEF_STMT (new_temp);
10982 : 2094 : if (lvectype != vectype)
10983 : : {
10984 : 221 : new_stmt
10985 : 221 : = gimple_build_assign (make_ssa_name (vectype),
10986 : : VIEW_CONVERT_EXPR,
10987 : : build1 (VIEW_CONVERT_EXPR,
10988 : : vectype, new_temp));
10989 : 221 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
10990 : : gsi);
10991 : : }
10992 : : }
10993 : : }
10994 : 4430 : else if (!costing_p && ltype != vectype)
10995 : : {
10996 : 1331 : new_stmt = gimple_build_assign (make_ssa_name (vectype),
10997 : : VIEW_CONVERT_EXPR,
10998 : : build1 (VIEW_CONVERT_EXPR,
10999 : : vectype, new_temp));
11000 : 1331 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
11001 : : gsi);
11002 : : }
11003 : :
11004 : 27267 : if (!costing_p)
11005 : : {
11006 : 3442 : if (slp)
11007 : : {
11008 : 3442 : if (slp_perm)
11009 : 1038 : dr_chain.quick_push (gimple_assign_lhs (new_stmt));
11010 : : else
11011 : 2404 : slp_node->push_vec_def (new_stmt);
11012 : : }
11013 : : else
11014 : : {
11015 : 0 : if (j == 0)
11016 : 0 : *vec_stmt = new_stmt;
11017 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
11018 : : }
11019 : : }
11020 : : }
11021 : 20682 : if (slp_perm)
11022 : : {
11023 : 2971 : unsigned n_perms;
11024 : 2971 : if (costing_p)
11025 : : {
11026 : 2374 : unsigned n_loads;
11027 : 2374 : vect_transform_slp_perm_load (vinfo, slp_node, vNULL, NULL, vf,
11028 : : true, &n_perms, &n_loads);
11029 : 2374 : inside_cost += record_stmt_cost (cost_vec, n_perms, vec_perm,
11030 : : first_stmt_info, slp_node, 0,
11031 : : vect_body);
11032 : : }
11033 : : else
11034 : 597 : vect_transform_slp_perm_load (vinfo, slp_node, dr_chain, gsi, vf,
11035 : : false, &n_perms);
11036 : : }
11037 : :
11038 : 20682 : if (costing_p)
11039 : : {
11040 : 18098 : if (n_adjacent_loads > 0)
11041 : 2108 : vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
11042 : : alignment_support_scheme, misalignment, false,
11043 : : &inside_cost, nullptr, cost_vec, cost_vec,
11044 : : true);
11045 : 18098 : if (dump_enabled_p ())
11046 : 606 : dump_printf_loc (MSG_NOTE, vect_location,
11047 : : "vect_model_load_cost: inside_cost = %u, "
11048 : : "prologue_cost = 0 .\n",
11049 : : inside_cost);
11050 : : }
11051 : :
11052 : 20682 : return true;
11053 : 20682 : }
11054 : :
11055 : 529808 : if (memory_access_type == VMAT_GATHER_SCATTER
11056 : 526884 : || (!slp && memory_access_type == VMAT_CONTIGUOUS))
11057 : : grouped_load = false;
11058 : :
11059 : 526884 : if (grouped_load
11060 : 529808 : || (slp && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()))
11061 : : {
11062 : 272054 : if (grouped_load)
11063 : : {
11064 : 271830 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
11065 : 271830 : group_size = DR_GROUP_SIZE (first_stmt_info);
11066 : : }
11067 : : else
11068 : : {
11069 : : first_stmt_info = stmt_info;
11070 : : group_size = 1;
11071 : : }
11072 : : /* For SLP vectorization we directly vectorize a subchain
11073 : : without permutation. */
11074 : 272054 : if (slp && ! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
11075 : 235530 : first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
11076 : : /* For BB vectorization always use the first stmt to base
11077 : : the data ref pointer on. */
11078 : 272054 : if (bb_vinfo)
11079 : 223002 : first_stmt_info_for_drptr
11080 : 223002 : = vect_find_first_scalar_stmt_in_slp (slp_node);
11081 : :
11082 : : /* Check if the chain of loads is already vectorized. */
11083 : 272054 : if (STMT_VINFO_VEC_STMTS (first_stmt_info).exists ()
11084 : : /* For SLP we would need to copy over SLP_TREE_VEC_DEFS.
11085 : : ??? But we can only do so if there is exactly one
11086 : : as we have no way to get at the rest. Leave the CSE
11087 : : opportunity alone.
11088 : : ??? With the group load eventually participating
11089 : : in multiple different permutations (having multiple
11090 : : slp nodes which refer to the same group) the CSE
11091 : : is even wrong code. See PR56270. */
11092 : 272054 : && !slp)
11093 : : {
11094 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
11095 : 0 : return true;
11096 : : }
11097 : 272054 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
11098 : 272054 : group_gap_adj = 0;
11099 : :
11100 : : /* VEC_NUM is the number of vect stmts to be created for this group. */
11101 : 272054 : if (slp)
11102 : : {
11103 : 272054 : grouped_load = false;
11104 : : /* If an SLP permutation is from N elements to N elements,
11105 : : and if one vector holds a whole number of N, we can load
11106 : : the inputs to the permutation in the same way as an
11107 : : unpermuted sequence. In other cases we need to load the
11108 : : whole group, not only the number of vector stmts the
11109 : : permutation result fits in. */
11110 : 272054 : unsigned scalar_lanes = SLP_TREE_LANES (slp_node);
11111 : 272054 : if (nested_in_vect_loop)
11112 : : /* We do not support grouped accesses in a nested loop,
11113 : : instead the access is contiguous but it might be
11114 : : permuted. No gap adjustment is needed though. */
11115 : 2 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
11116 : 272052 : else if (slp_perm
11117 : 272052 : && (group_size != scalar_lanes
11118 : 6416 : || !multiple_p (nunits, group_size)))
11119 : : {
11120 : : /* We don't yet generate such SLP_TREE_LOAD_PERMUTATIONs for
11121 : : variable VF; see vect_transform_slp_perm_load. */
11122 : 31964 : unsigned int const_vf = vf.to_constant ();
11123 : 31964 : unsigned int const_nunits = nunits.to_constant ();
11124 : 31964 : vec_num = CEIL (group_size * const_vf, const_nunits);
11125 : 31964 : group_gap_adj = vf * group_size - nunits * vec_num;
11126 : : }
11127 : : else
11128 : : {
11129 : 240088 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
11130 : 240088 : group_gap_adj
11131 : 240088 : = group_size - scalar_lanes;
11132 : : }
11133 : : }
11134 : : else
11135 : 0 : vec_num = group_size;
11136 : :
11137 : 272054 : ref_type = get_group_alias_ptr_type (first_stmt_info);
11138 : : }
11139 : : else
11140 : : {
11141 : 257754 : first_stmt_info = stmt_info;
11142 : 257754 : first_dr_info = dr_info;
11143 : 257754 : group_size = vec_num = 1;
11144 : 257754 : group_gap_adj = 0;
11145 : 257754 : ref_type = reference_alias_ptr_type (DR_REF (first_dr_info->dr));
11146 : 257754 : if (slp)
11147 : 257754 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
11148 : : }
11149 : :
11150 : 529808 : gcc_assert (alignment_support_scheme);
11151 : 529808 : vec_loop_masks *loop_masks
11152 : 306806 : = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
11153 : 529808 : ? &LOOP_VINFO_MASKS (loop_vinfo)
11154 : 836628 : : NULL);
11155 : 14 : vec_loop_lens *loop_lens
11156 : 306806 : = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)
11157 : 0 : ? &LOOP_VINFO_LENS (loop_vinfo)
11158 : 529808 : : NULL);
11159 : :
11160 : : /* The vect_transform_stmt and vect_analyze_stmt will go here but there
11161 : : are some difference here. We cannot enable both the lens and masks
11162 : : during transform but it is allowed during analysis.
11163 : : Shouldn't go with length-based approach if fully masked. */
11164 : 529808 : if (cost_vec == NULL)
11165 : : /* The cost_vec is NULL during transfrom. */
11166 : 151305 : gcc_assert ((!loop_lens || !loop_masks));
11167 : :
11168 : : /* Targets with store-lane instructions must not require explicit
11169 : : realignment. vect_supportable_dr_alignment always returns either
11170 : : dr_aligned or dr_unaligned_supported for masked operations. */
11171 : 529808 : gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES
11172 : : && !mask
11173 : : && !loop_masks)
11174 : : || alignment_support_scheme == dr_aligned
11175 : : || alignment_support_scheme == dr_unaligned_supported);
11176 : :
11177 : : /* In case the vectorization factor (VF) is bigger than the number
11178 : : of elements that we can fit in a vectype (nunits), we have to generate
11179 : : more than one vector stmt - i.e - we need to "unroll" the
11180 : : vector stmt by a factor VF/nunits. In doing so, we record a pointer
11181 : : from one copy of the vector stmt to the next, in the field
11182 : : STMT_VINFO_RELATED_STMT. This is necessary in order to allow following
11183 : : stages to find the correct vector defs to be used when vectorizing
11184 : : stmts that use the defs of the current stmt. The example below
11185 : : illustrates the vectorization process when VF=16 and nunits=4 (i.e., we
11186 : : need to create 4 vectorized stmts):
11187 : :
11188 : : before vectorization:
11189 : : RELATED_STMT VEC_STMT
11190 : : S1: x = memref - -
11191 : : S2: z = x + 1 - -
11192 : :
11193 : : step 1: vectorize stmt S1:
11194 : : We first create the vector stmt VS1_0, and, as usual, record a
11195 : : pointer to it in the STMT_VINFO_VEC_STMT of the scalar stmt S1.
11196 : : Next, we create the vector stmt VS1_1, and record a pointer to
11197 : : it in the STMT_VINFO_RELATED_STMT of the vector stmt VS1_0.
11198 : : Similarly, for VS1_2 and VS1_3. This is the resulting chain of
11199 : : stmts and pointers:
11200 : : RELATED_STMT VEC_STMT
11201 : : VS1_0: vx0 = memref0 VS1_1 -
11202 : : VS1_1: vx1 = memref1 VS1_2 -
11203 : : VS1_2: vx2 = memref2 VS1_3 -
11204 : : VS1_3: vx3 = memref3 - -
11205 : : S1: x = load - VS1_0
11206 : : S2: z = x + 1 - -
11207 : : */
11208 : :
11209 : : /* In case of interleaving (non-unit grouped access):
11210 : :
11211 : : S1: x2 = &base + 2
11212 : : S2: x0 = &base
11213 : : S3: x1 = &base + 1
11214 : : S4: x3 = &base + 3
11215 : :
11216 : : Vectorized loads are created in the order of memory accesses
11217 : : starting from the access of the first stmt of the chain:
11218 : :
11219 : : VS1: vx0 = &base
11220 : : VS2: vx1 = &base + vec_size*1
11221 : : VS3: vx3 = &base + vec_size*2
11222 : : VS4: vx4 = &base + vec_size*3
11223 : :
11224 : : Then permutation statements are generated:
11225 : :
11226 : : VS5: vx5 = VEC_PERM_EXPR < vx0, vx1, { 0, 2, ..., i*2 } >
11227 : : VS6: vx6 = VEC_PERM_EXPR < vx0, vx1, { 1, 3, ..., i*2+1 } >
11228 : : ...
11229 : :
11230 : : And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts
11231 : : (the order of the data-refs in the output of vect_permute_load_chain
11232 : : corresponds to the order of scalar stmts in the interleaving chain - see
11233 : : the documentation of vect_permute_load_chain()).
11234 : : The generation of permutation stmts and recording them in
11235 : : STMT_VINFO_VEC_STMT is done in vect_transform_grouped_load().
11236 : :
11237 : : In case of both multiple types and interleaving, the vector loads and
11238 : : permutation stmts above are created for every copy. The result vector
11239 : : stmts are put in STMT_VINFO_VEC_STMT for the first copy and in the
11240 : : corresponding STMT_VINFO_RELATED_STMT for the next copies. */
11241 : :
11242 : : /* If the data reference is aligned (dr_aligned) or potentially unaligned
11243 : : on a target that supports unaligned accesses (dr_unaligned_supported)
11244 : : we generate the following code:
11245 : : p = initial_addr;
11246 : : indx = 0;
11247 : : loop {
11248 : : p = p + indx * vectype_size;
11249 : : vec_dest = *(p);
11250 : : indx = indx + 1;
11251 : : }
11252 : :
11253 : : Otherwise, the data reference is potentially unaligned on a target that
11254 : : does not support unaligned accesses (dr_explicit_realign_optimized) -
11255 : : then generate the following code, in which the data in each iteration is
11256 : : obtained by two vector loads, one from the previous iteration, and one
11257 : : from the current iteration:
11258 : : p1 = initial_addr;
11259 : : msq_init = *(floor(p1))
11260 : : p2 = initial_addr + VS - 1;
11261 : : realignment_token = call target_builtin;
11262 : : indx = 0;
11263 : : loop {
11264 : : p2 = p2 + indx * vectype_size
11265 : : lsq = *(floor(p2))
11266 : : vec_dest = realign_load (msq, lsq, realignment_token)
11267 : : indx = indx + 1;
11268 : : msq = lsq;
11269 : : } */
11270 : :
11271 : : /* If the misalignment remains the same throughout the execution of the
11272 : : loop, we can create the init_addr and permutation mask at the loop
11273 : : preheader. Otherwise, it needs to be created inside the loop.
11274 : : This can only occur when vectorizing memory accesses in the inner-loop
11275 : : nested within an outer-loop that is being vectorized. */
11276 : :
11277 : 529808 : if (nested_in_vect_loop
11278 : 529808 : && !multiple_p (DR_STEP_ALIGNMENT (dr_info->dr),
11279 : 1292 : GET_MODE_SIZE (TYPE_MODE (vectype))))
11280 : : {
11281 : 211 : gcc_assert (alignment_support_scheme != dr_explicit_realign_optimized);
11282 : : compute_in_loop = true;
11283 : : }
11284 : :
11285 : 529808 : bool diff_first_stmt_info
11286 : 529808 : = first_stmt_info_for_drptr && first_stmt_info != first_stmt_info_for_drptr;
11287 : :
11288 : 529808 : tree offset = NULL_TREE;
11289 : 529808 : if ((alignment_support_scheme == dr_explicit_realign_optimized
11290 : 529808 : || alignment_support_scheme == dr_explicit_realign)
11291 : 0 : && !compute_in_loop)
11292 : : {
11293 : : /* If we have different first_stmt_info, we can't set up realignment
11294 : : here, since we can't guarantee first_stmt_info DR has been
11295 : : initialized yet, use first_stmt_info_for_drptr DR by bumping the
11296 : : distance from first_stmt_info DR instead as below. */
11297 : 0 : if (!costing_p)
11298 : : {
11299 : 0 : if (!diff_first_stmt_info)
11300 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info, gsi,
11301 : : &realignment_token,
11302 : : alignment_support_scheme, NULL_TREE,
11303 : : &at_loop);
11304 : 0 : if (alignment_support_scheme == dr_explicit_realign_optimized)
11305 : : {
11306 : 0 : phi = as_a<gphi *> (SSA_NAME_DEF_STMT (msq));
11307 : 0 : offset = size_binop (MINUS_EXPR, TYPE_SIZE_UNIT (vectype),
11308 : : size_one_node);
11309 : 0 : gcc_assert (!first_stmt_info_for_drptr);
11310 : : }
11311 : : }
11312 : : }
11313 : : else
11314 : 529808 : at_loop = loop;
11315 : :
11316 : 529808 : if (!known_eq (poffset, 0))
11317 : 4856 : offset = (offset
11318 : 4856 : ? size_binop (PLUS_EXPR, offset, size_int (poffset))
11319 : 4856 : : size_int (poffset));
11320 : :
11321 : 529808 : tree bump;
11322 : 529808 : tree vec_offset = NULL_TREE;
11323 : 529808 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
11324 : : {
11325 : 2924 : aggr_type = NULL_TREE;
11326 : 2924 : bump = NULL_TREE;
11327 : : }
11328 : 526884 : else if (memory_access_type == VMAT_GATHER_SCATTER)
11329 : : {
11330 : 0 : aggr_type = elem_type;
11331 : 0 : if (!costing_p)
11332 : 0 : vect_get_strided_load_store_ops (stmt_info, loop_vinfo, gsi, &gs_info,
11333 : : &bump, &vec_offset, loop_lens);
11334 : : }
11335 : : else
11336 : : {
11337 : 526884 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
11338 : 0 : aggr_type = build_array_type_nelts (elem_type, group_size * nunits);
11339 : : else
11340 : : aggr_type = vectype;
11341 : 526884 : if (!costing_p)
11342 : 150572 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
11343 : : memory_access_type, loop_lens);
11344 : : }
11345 : :
11346 : 529808 : auto_vec<tree> vec_offsets;
11347 : 529808 : auto_vec<tree> vec_masks;
11348 : 529808 : if (mask && !costing_p)
11349 : : {
11350 : 582 : if (slp_node)
11351 : 582 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[mask_index],
11352 : : &vec_masks);
11353 : : else
11354 : 0 : vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, mask,
11355 : : &vec_masks, mask_vectype);
11356 : : }
11357 : :
11358 : 529808 : tree vec_mask = NULL_TREE;
11359 : 529808 : tree vec_els = NULL_TREE;
11360 : 529808 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
11361 : : {
11362 : 0 : gcc_assert (alignment_support_scheme == dr_aligned
11363 : : || alignment_support_scheme == dr_unaligned_supported);
11364 : :
11365 : 0 : unsigned int inside_cost = 0, prologue_cost = 0;
11366 : : /* For costing some adjacent vector loads, we'd like to cost with
11367 : : the total number of them once instead of cost each one by one. */
11368 : 0 : unsigned int n_adjacent_loads = 0;
11369 : 0 : if (slp_node)
11370 : 0 : ncopies = slp_node->vec_stmts_size / group_size;
11371 : 0 : for (j = 0; j < ncopies; j++)
11372 : : {
11373 : 0 : if (costing_p)
11374 : : {
11375 : : /* An IFN_LOAD_LANES will load all its vector results,
11376 : : regardless of which ones we actually need. Account
11377 : : for the cost of unused results. */
11378 : 0 : if (first_stmt_info == stmt_info)
11379 : : {
11380 : 0 : unsigned int gaps = DR_GROUP_SIZE (first_stmt_info);
11381 : 0 : stmt_vec_info next_stmt_info = first_stmt_info;
11382 : 0 : do
11383 : : {
11384 : 0 : gaps -= 1;
11385 : 0 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
11386 : : }
11387 : 0 : while (next_stmt_info);
11388 : 0 : if (gaps)
11389 : : {
11390 : 0 : if (dump_enabled_p ())
11391 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
11392 : : "vect_model_load_cost: %d "
11393 : : "unused vectors.\n",
11394 : : gaps);
11395 : 0 : vect_get_load_cost (vinfo, stmt_info, slp_node, gaps,
11396 : : alignment_support_scheme,
11397 : : misalignment, false, &inside_cost,
11398 : : &prologue_cost, cost_vec, cost_vec,
11399 : : true);
11400 : : }
11401 : : }
11402 : 0 : n_adjacent_loads++;
11403 : 0 : continue;
11404 : 0 : }
11405 : :
11406 : : /* 1. Create the vector or array pointer update chain. */
11407 : 0 : if (j == 0)
11408 : 0 : dataref_ptr
11409 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
11410 : : at_loop, offset, &dummy, gsi,
11411 : : &ptr_incr, false, bump);
11412 : : else
11413 : : {
11414 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
11415 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11416 : : stmt_info, bump);
11417 : : }
11418 : 0 : if (mask)
11419 : 0 : vec_mask = vec_masks[j];
11420 : :
11421 : 0 : tree vec_array = create_vector_array (vectype, group_size);
11422 : :
11423 : 0 : tree final_mask = NULL_TREE;
11424 : 0 : tree final_len = NULL_TREE;
11425 : 0 : tree bias = NULL_TREE;
11426 : 0 : if (loop_masks)
11427 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
11428 : : ncopies, vectype, j);
11429 : 0 : if (vec_mask)
11430 : 0 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
11431 : : vec_mask, gsi);
11432 : :
11433 : 0 : if (lanes_ifn == IFN_MASK_LEN_LOAD_LANES)
11434 : : {
11435 : 0 : if (loop_lens)
11436 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
11437 : : ncopies, vectype, j, 1);
11438 : : else
11439 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
11440 : 0 : signed char biasval
11441 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
11442 : 0 : bias = build_int_cst (intQI_type_node, biasval);
11443 : 0 : if (!final_mask)
11444 : : {
11445 : 0 : mask_vectype = truth_type_for (vectype);
11446 : 0 : final_mask = build_minus_one_cst (mask_vectype);
11447 : : }
11448 : : }
11449 : :
11450 : 0 : if (final_mask)
11451 : : {
11452 : 0 : vec_els = vect_get_mask_load_else (maskload_elsval, vectype);
11453 : 0 : if (type_mode_padding_p
11454 : 0 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
11455 : 0 : need_zeroing = true;
11456 : : }
11457 : :
11458 : 0 : gcall *call;
11459 : 0 : if (final_len && final_mask)
11460 : : {
11461 : : /* Emit:
11462 : : VEC_ARRAY = MASK_LEN_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,
11463 : : VEC_MASK, LEN, BIAS). */
11464 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
11465 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
11466 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_LOAD_LANES, 6,
11467 : : dataref_ptr, alias_ptr,
11468 : : final_mask, vec_els,
11469 : : final_len, bias);
11470 : : }
11471 : 0 : else if (final_mask)
11472 : : {
11473 : : /* Emit:
11474 : : VEC_ARRAY = MASK_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,
11475 : : VEC_MASK). */
11476 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
11477 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
11478 : 0 : call = gimple_build_call_internal (IFN_MASK_LOAD_LANES, 4,
11479 : : dataref_ptr, alias_ptr,
11480 : : final_mask, vec_els);
11481 : : }
11482 : : else
11483 : : {
11484 : : /* Emit:
11485 : : VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]). */
11486 : 0 : data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
11487 : 0 : call = gimple_build_call_internal (IFN_LOAD_LANES, 1, data_ref);
11488 : : }
11489 : 0 : gimple_call_set_lhs (call, vec_array);
11490 : 0 : gimple_call_set_nothrow (call, true);
11491 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
11492 : :
11493 : 0 : if (!slp)
11494 : 0 : dr_chain.create (group_size);
11495 : : /* Extract each vector into an SSA_NAME. */
11496 : 0 : for (unsigned i = 0; i < group_size; i++)
11497 : : {
11498 : 0 : new_temp = read_vector_array (vinfo, stmt_info, gsi, scalar_dest,
11499 : : vec_array, i, need_zeroing,
11500 : : final_mask);
11501 : 0 : if (slp)
11502 : 0 : slp_node->push_vec_def (new_temp);
11503 : : else
11504 : 0 : dr_chain.quick_push (new_temp);
11505 : : }
11506 : :
11507 : 0 : if (!slp)
11508 : : /* Record the mapping between SSA_NAMEs and statements. */
11509 : 0 : vect_record_grouped_load_vectors (vinfo, stmt_info, dr_chain);
11510 : :
11511 : : /* Record that VEC_ARRAY is now dead. */
11512 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
11513 : :
11514 : 0 : if (!slp)
11515 : 0 : dr_chain.release ();
11516 : :
11517 : 0 : if (!slp_node)
11518 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
11519 : : }
11520 : :
11521 : 0 : if (costing_p)
11522 : : {
11523 : 0 : if (n_adjacent_loads > 0)
11524 : 0 : vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
11525 : : alignment_support_scheme, misalignment, false,
11526 : : &inside_cost, &prologue_cost, cost_vec,
11527 : : cost_vec, true);
11528 : 0 : if (dump_enabled_p ())
11529 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
11530 : : "vect_model_load_cost: inside_cost = %u, "
11531 : : "prologue_cost = %u .\n",
11532 : : inside_cost, prologue_cost);
11533 : : }
11534 : :
11535 : 0 : return true;
11536 : : }
11537 : :
11538 : 529808 : if (memory_access_type == VMAT_GATHER_SCATTER)
11539 : : {
11540 : 2924 : gcc_assert (alignment_support_scheme == dr_aligned
11541 : : || alignment_support_scheme == dr_unaligned_supported);
11542 : 2924 : gcc_assert (!grouped_load && !slp_perm);
11543 : :
11544 : : unsigned int inside_cost = 0, prologue_cost = 0;
11545 : 5848 : for (j = 0; j < ncopies; j++)
11546 : : {
11547 : : /* 1. Create the vector or array pointer update chain. */
11548 : 2924 : if (j == 0 && !costing_p)
11549 : : {
11550 : 733 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
11551 : 733 : vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info,
11552 : : slp_node, &gs_info, &dataref_ptr,
11553 : : &vec_offsets);
11554 : : else
11555 : 0 : dataref_ptr
11556 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
11557 : : at_loop, offset, &dummy, gsi,
11558 : : &ptr_incr, false, bump);
11559 : : }
11560 : 2191 : else if (!costing_p)
11561 : : {
11562 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
11563 : 0 : if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info))
11564 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
11565 : : gsi, stmt_info, bump);
11566 : : }
11567 : :
11568 : 2924 : gimple *new_stmt = NULL;
11569 : 6779 : for (i = 0; i < vec_num; i++)
11570 : : {
11571 : 3855 : tree final_mask = NULL_TREE;
11572 : 3855 : tree final_len = NULL_TREE;
11573 : 3855 : tree bias = NULL_TREE;
11574 : 3855 : if (!costing_p)
11575 : : {
11576 : 939 : if (mask)
11577 : 153 : vec_mask = vec_masks[vec_num * j + i];
11578 : 939 : if (loop_masks)
11579 : 0 : final_mask
11580 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
11581 : 0 : vec_num * ncopies, vectype,
11582 : 0 : vec_num * j + i);
11583 : 939 : if (vec_mask)
11584 : 153 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
11585 : : final_mask, vec_mask, gsi);
11586 : :
11587 : 939 : if (i > 0 && !STMT_VINFO_GATHER_SCATTER_P (stmt_info))
11588 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
11589 : : gsi, stmt_info, bump);
11590 : : }
11591 : :
11592 : : /* 2. Create the vector-load in the loop. */
11593 : 3855 : unsigned HOST_WIDE_INT align;
11594 : 3855 : if (gs_info.ifn != IFN_LAST)
11595 : : {
11596 : 0 : if (costing_p)
11597 : : {
11598 : 0 : unsigned int cnunits = vect_nunits_for_cost (vectype);
11599 : 0 : inside_cost
11600 : 0 : = record_stmt_cost (cost_vec, cnunits, scalar_load,
11601 : : stmt_info, slp_node, 0, vect_body);
11602 : 0 : continue;
11603 : 0 : }
11604 : 0 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
11605 : 0 : vec_offset = vec_offsets[vec_num * j + i];
11606 : 0 : tree zero = build_zero_cst (vectype);
11607 : 0 : tree scale = size_int (gs_info.scale);
11608 : :
11609 : 0 : if (gs_info.ifn == IFN_MASK_LEN_GATHER_LOAD)
11610 : : {
11611 : 0 : if (loop_lens)
11612 : 0 : final_len
11613 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
11614 : 0 : vec_num * ncopies, vectype,
11615 : 0 : vec_num * j + i, 1);
11616 : : else
11617 : 0 : final_len
11618 : 0 : = build_int_cst (sizetype,
11619 : 0 : TYPE_VECTOR_SUBPARTS (vectype));
11620 : 0 : signed char biasval
11621 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
11622 : 0 : bias = build_int_cst (intQI_type_node, biasval);
11623 : 0 : if (!final_mask)
11624 : : {
11625 : 0 : mask_vectype = truth_type_for (vectype);
11626 : 0 : final_mask = build_minus_one_cst (mask_vectype);
11627 : : }
11628 : : }
11629 : :
11630 : 0 : if (final_mask)
11631 : : {
11632 : 0 : vec_els = vect_get_mask_load_else
11633 : 0 : (maskload_elsval, vectype);
11634 : 0 : if (type_mode_padding_p
11635 : 0 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
11636 : 0 : need_zeroing = true;
11637 : : }
11638 : :
11639 : 0 : gcall *call;
11640 : 0 : if (final_len && final_mask)
11641 : : {
11642 : 0 : if (VECTOR_TYPE_P (TREE_TYPE (vec_offset)))
11643 : 0 : call = gimple_build_call_internal (
11644 : : IFN_MASK_LEN_GATHER_LOAD, 8, dataref_ptr, vec_offset,
11645 : : scale, zero, final_mask, vec_els, final_len, bias);
11646 : : else
11647 : : /* Non-vector offset indicates that prefer to take
11648 : : MASK_LEN_STRIDED_LOAD instead of the
11649 : : MASK_LEN_GATHER_LOAD with direct stride arg. */
11650 : 0 : call = gimple_build_call_internal (
11651 : : IFN_MASK_LEN_STRIDED_LOAD, 7, dataref_ptr, vec_offset,
11652 : : zero, final_mask, vec_els, final_len, bias);
11653 : : }
11654 : 0 : else if (final_mask)
11655 : 0 : call = gimple_build_call_internal (IFN_MASK_GATHER_LOAD,
11656 : : 6, dataref_ptr,
11657 : : vec_offset, scale,
11658 : : zero, final_mask,
11659 : : vec_els);
11660 : : else
11661 : 0 : call = gimple_build_call_internal (IFN_GATHER_LOAD, 4,
11662 : : dataref_ptr, vec_offset,
11663 : : scale, zero);
11664 : 0 : gimple_call_set_nothrow (call, true);
11665 : 0 : new_stmt = call;
11666 : 0 : data_ref = NULL_TREE;
11667 : : }
11668 : 3855 : else if (gs_info.decl)
11669 : : {
11670 : : /* The builtin decls path for gather is legacy, x86 only. */
11671 : 657 : gcc_assert (!final_len && nunits.is_constant ());
11672 : 657 : if (costing_p)
11673 : : {
11674 : 376 : unsigned int cnunits = vect_nunits_for_cost (vectype);
11675 : 376 : inside_cost
11676 : 376 : = record_stmt_cost (cost_vec, cnunits, scalar_load,
11677 : : stmt_info, slp_node, 0, vect_body);
11678 : 376 : continue;
11679 : 376 : }
11680 : 281 : poly_uint64 offset_nunits
11681 : 281 : = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype);
11682 : 281 : if (known_eq (nunits, offset_nunits))
11683 : : {
11684 : 264 : new_stmt = vect_build_one_gather_load_call
11685 : 132 : (vinfo, stmt_info, gsi, &gs_info,
11686 : 132 : dataref_ptr, vec_offsets[vec_num * j + i],
11687 : : final_mask);
11688 : 132 : data_ref = NULL_TREE;
11689 : : }
11690 : 149 : else if (known_eq (nunits, offset_nunits * 2))
11691 : : {
11692 : : /* We have a offset vector with half the number of
11693 : : lanes but the builtins will produce full vectype
11694 : : data with just the lower lanes filled. */
11695 : 126 : new_stmt = vect_build_one_gather_load_call
11696 : 63 : (vinfo, stmt_info, gsi, &gs_info,
11697 : 63 : dataref_ptr, vec_offsets[2 * vec_num * j + 2 * i],
11698 : : final_mask);
11699 : 63 : tree low = make_ssa_name (vectype);
11700 : 63 : gimple_set_lhs (new_stmt, low);
11701 : 63 : vect_finish_stmt_generation (vinfo, stmt_info,
11702 : : new_stmt, gsi);
11703 : :
11704 : : /* now put upper half of final_mask in final_mask low. */
11705 : 63 : if (final_mask
11706 : 63 : && !SCALAR_INT_MODE_P
11707 : : (TYPE_MODE (TREE_TYPE (final_mask))))
11708 : : {
11709 : 10 : int count = nunits.to_constant ();
11710 : 10 : vec_perm_builder sel (count, count, 1);
11711 : 10 : sel.quick_grow (count);
11712 : 78 : for (int i = 0; i < count; ++i)
11713 : 68 : sel[i] = i | (count / 2);
11714 : 10 : vec_perm_indices indices (sel, 2, count);
11715 : 10 : tree perm_mask = vect_gen_perm_mask_checked
11716 : 10 : (TREE_TYPE (final_mask), indices);
11717 : 10 : new_stmt = gimple_build_assign (NULL_TREE,
11718 : : VEC_PERM_EXPR,
11719 : : final_mask,
11720 : : final_mask,
11721 : : perm_mask);
11722 : 10 : final_mask = make_ssa_name (TREE_TYPE (final_mask));
11723 : 10 : gimple_set_lhs (new_stmt, final_mask);
11724 : 10 : vect_finish_stmt_generation (vinfo, stmt_info,
11725 : : new_stmt, gsi);
11726 : 10 : }
11727 : 53 : else if (final_mask)
11728 : : {
11729 : 25 : new_stmt = gimple_build_assign (NULL_TREE,
11730 : : VEC_UNPACK_HI_EXPR,
11731 : : final_mask);
11732 : 25 : final_mask = make_ssa_name
11733 : 25 : (truth_type_for (gs_info.offset_vectype));
11734 : 25 : gimple_set_lhs (new_stmt, final_mask);
11735 : 25 : vect_finish_stmt_generation (vinfo, stmt_info,
11736 : : new_stmt, gsi);
11737 : : }
11738 : :
11739 : 63 : new_stmt = vect_build_one_gather_load_call
11740 : 63 : (vinfo, stmt_info, gsi, &gs_info,
11741 : : dataref_ptr,
11742 : 63 : vec_offsets[2 * vec_num * j + 2 * i + 1],
11743 : : final_mask);
11744 : 63 : tree high = make_ssa_name (vectype);
11745 : 63 : gimple_set_lhs (new_stmt, high);
11746 : 63 : vect_finish_stmt_generation (vinfo, stmt_info,
11747 : : new_stmt, gsi);
11748 : :
11749 : : /* compose low + high. */
11750 : 63 : int count = nunits.to_constant ();
11751 : 63 : vec_perm_builder sel (count, count, 1);
11752 : 63 : sel.quick_grow (count);
11753 : 655 : for (int i = 0; i < count; ++i)
11754 : 592 : sel[i] = i < count / 2 ? i : i + count / 2;
11755 : 63 : vec_perm_indices indices (sel, 2, count);
11756 : 63 : tree perm_mask
11757 : 63 : = vect_gen_perm_mask_checked (vectype, indices);
11758 : 63 : new_stmt = gimple_build_assign (NULL_TREE,
11759 : : VEC_PERM_EXPR,
11760 : : low, high, perm_mask);
11761 : 63 : data_ref = NULL_TREE;
11762 : 63 : }
11763 : 86 : else if (known_eq (nunits * 2, offset_nunits))
11764 : : {
11765 : : /* We have a offset vector with double the number of
11766 : : lanes. Select the low/high part accordingly. */
11767 : 86 : vec_offset = vec_offsets[(vec_num * j + i) / 2];
11768 : 86 : if ((vec_num * j + i) & 1)
11769 : : {
11770 : 43 : int count = offset_nunits.to_constant ();
11771 : 43 : vec_perm_builder sel (count, count, 1);
11772 : 43 : sel.quick_grow (count);
11773 : 463 : for (int i = 0; i < count; ++i)
11774 : 420 : sel[i] = i | (count / 2);
11775 : 43 : vec_perm_indices indices (sel, 2, count);
11776 : 43 : tree perm_mask = vect_gen_perm_mask_checked
11777 : 43 : (TREE_TYPE (vec_offset), indices);
11778 : 43 : new_stmt = gimple_build_assign (NULL_TREE,
11779 : : VEC_PERM_EXPR,
11780 : : vec_offset,
11781 : : vec_offset,
11782 : : perm_mask);
11783 : 43 : vec_offset = make_ssa_name (TREE_TYPE (vec_offset));
11784 : 43 : gimple_set_lhs (new_stmt, vec_offset);
11785 : 43 : vect_finish_stmt_generation (vinfo, stmt_info,
11786 : : new_stmt, gsi);
11787 : 43 : }
11788 : 172 : new_stmt = vect_build_one_gather_load_call
11789 : 86 : (vinfo, stmt_info, gsi, &gs_info,
11790 : : dataref_ptr, vec_offset, final_mask);
11791 : 86 : data_ref = NULL_TREE;
11792 : : }
11793 : : else
11794 : 0 : gcc_unreachable ();
11795 : : }
11796 : : else
11797 : : {
11798 : : /* Emulated gather-scatter. */
11799 : 3198 : gcc_assert (!final_mask);
11800 : 3198 : unsigned HOST_WIDE_INT const_nunits = nunits.to_constant ();
11801 : 3198 : if (costing_p)
11802 : : {
11803 : : /* For emulated gathers N offset vector element
11804 : : offset add is consumed by the load). */
11805 : 2540 : inside_cost = record_stmt_cost (cost_vec, const_nunits,
11806 : : vec_to_scalar, stmt_info,
11807 : : slp_node, 0, vect_body);
11808 : : /* N scalar loads plus gathering them into a
11809 : : vector. */
11810 : 2540 : inside_cost
11811 : 2540 : = record_stmt_cost (cost_vec, const_nunits, scalar_load,
11812 : : stmt_info, slp_node, 0, vect_body);
11813 : 2540 : inside_cost
11814 : 2540 : = record_stmt_cost (cost_vec, 1, vec_construct,
11815 : : stmt_info, slp_node, 0, vect_body);
11816 : 2540 : continue;
11817 : : }
11818 : 658 : unsigned HOST_WIDE_INT const_offset_nunits
11819 : 658 : = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype)
11820 : 658 : .to_constant ();
11821 : 658 : vec<constructor_elt, va_gc> *ctor_elts;
11822 : 658 : vec_alloc (ctor_elts, const_nunits);
11823 : 658 : gimple_seq stmts = NULL;
11824 : : /* We support offset vectors with more elements
11825 : : than the data vector for now. */
11826 : 658 : unsigned HOST_WIDE_INT factor
11827 : : = const_offset_nunits / const_nunits;
11828 : 658 : vec_offset = vec_offsets[(vec_num * j + i) / factor];
11829 : 658 : unsigned elt_offset
11830 : 658 : = ((vec_num * j + i) % factor) * const_nunits;
11831 : 658 : tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset));
11832 : 658 : tree scale = size_int (gs_info.scale);
11833 : 658 : align = get_object_alignment (DR_REF (first_dr_info->dr));
11834 : 658 : tree ltype = build_aligned_type (TREE_TYPE (vectype), align);
11835 : 2692 : for (unsigned k = 0; k < const_nunits; ++k)
11836 : : {
11837 : 2034 : tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type),
11838 : : bitsize_int (k + elt_offset));
11839 : 2034 : tree idx
11840 : 2034 : = gimple_build (&stmts, BIT_FIELD_REF, idx_type,
11841 : 2034 : vec_offset, TYPE_SIZE (idx_type), boff);
11842 : 2034 : idx = gimple_convert (&stmts, sizetype, idx);
11843 : 2034 : idx = gimple_build (&stmts, MULT_EXPR, sizetype, idx,
11844 : : scale);
11845 : 2034 : tree ptr = gimple_build (&stmts, PLUS_EXPR,
11846 : 2034 : TREE_TYPE (dataref_ptr),
11847 : : dataref_ptr, idx);
11848 : 2034 : ptr = gimple_convert (&stmts, ptr_type_node, ptr);
11849 : 2034 : tree elt = make_ssa_name (TREE_TYPE (vectype));
11850 : 2034 : tree ref = build2 (MEM_REF, ltype, ptr,
11851 : 2034 : build_int_cst (ref_type, 0));
11852 : 2034 : new_stmt = gimple_build_assign (elt, ref);
11853 : 4068 : gimple_set_vuse (new_stmt, gimple_vuse (gsi_stmt (*gsi)));
11854 : 2034 : gimple_seq_add_stmt (&stmts, new_stmt);
11855 : 2034 : CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE, elt);
11856 : : }
11857 : 658 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
11858 : 658 : new_stmt = gimple_build_assign (
11859 : : NULL_TREE, build_constructor (vectype, ctor_elts));
11860 : 658 : data_ref = NULL_TREE;
11861 : : }
11862 : :
11863 : 939 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11864 : : /* DATA_REF is null if we've already built the statement. */
11865 : 939 : if (data_ref)
11866 : : {
11867 : : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
11868 : : new_stmt = gimple_build_assign (vec_dest, data_ref);
11869 : : }
11870 : 1878 : new_temp = need_zeroing
11871 : 939 : ? make_ssa_name (vectype)
11872 : 939 : : make_ssa_name (vec_dest, new_stmt);
11873 : 939 : gimple_set_lhs (new_stmt, new_temp);
11874 : 939 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11875 : :
11876 : : /* If we need to explicitly zero inactive elements emit a
11877 : : VEC_COND_EXPR that does so. */
11878 : 939 : if (need_zeroing)
11879 : : {
11880 : 0 : vec_els = vect_get_mask_load_else (MASK_LOAD_ELSE_ZERO,
11881 : : vectype);
11882 : :
11883 : 0 : tree new_temp2 = make_ssa_name (vec_dest, new_stmt);
11884 : 0 : new_stmt
11885 : 0 : = gimple_build_assign (new_temp2, VEC_COND_EXPR,
11886 : : final_mask, new_temp, vec_els);
11887 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
11888 : : gsi);
11889 : 0 : new_temp = new_temp2;
11890 : : }
11891 : :
11892 : : /* Store vector loads in the corresponding SLP_NODE. */
11893 : 939 : if (slp)
11894 : 939 : slp_node->push_vec_def (new_stmt);
11895 : : }
11896 : :
11897 : 2924 : if (!slp && !costing_p)
11898 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
11899 : : }
11900 : :
11901 : 2924 : if (!slp && !costing_p)
11902 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
11903 : :
11904 : 2924 : if (costing_p && dump_enabled_p ())
11905 : 294 : dump_printf_loc (MSG_NOTE, vect_location,
11906 : : "vect_model_load_cost: inside_cost = %u, "
11907 : : "prologue_cost = %u .\n",
11908 : : inside_cost, prologue_cost);
11909 : 2924 : return true;
11910 : : }
11911 : :
11912 : 526884 : poly_uint64 group_elt = 0;
11913 : 526884 : unsigned int inside_cost = 0, prologue_cost = 0;
11914 : : /* For costing some adjacent vector loads, we'd like to cost with
11915 : : the total number of them once instead of cost each one by one. */
11916 : 526884 : unsigned int n_adjacent_loads = 0;
11917 : 1053768 : for (j = 0; j < ncopies; j++)
11918 : : {
11919 : : /* 1. Create the vector or array pointer update chain. */
11920 : 526884 : if (j == 0 && !costing_p)
11921 : : {
11922 : 150572 : bool simd_lane_access_p
11923 : 150572 : = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0;
11924 : 150572 : if (simd_lane_access_p
11925 : 1607 : && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR
11926 : 1607 : && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0))
11927 : 1607 : && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info))
11928 : 1607 : && integer_zerop (DR_INIT (first_dr_info->dr))
11929 : 1607 : && alias_sets_conflict_p (get_alias_set (aggr_type),
11930 : 1607 : get_alias_set (TREE_TYPE (ref_type)))
11931 : 152179 : && (alignment_support_scheme == dr_aligned
11932 : 0 : || alignment_support_scheme == dr_unaligned_supported))
11933 : : {
11934 : 1607 : dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr));
11935 : 1607 : dataref_offset = build_int_cst (ref_type, 0);
11936 : : }
11937 : 148965 : else if (diff_first_stmt_info)
11938 : : {
11939 : 2801 : dataref_ptr
11940 : 2801 : = vect_create_data_ref_ptr (vinfo, first_stmt_info_for_drptr,
11941 : : aggr_type, at_loop, offset, &dummy,
11942 : : gsi, &ptr_incr, simd_lane_access_p,
11943 : : bump);
11944 : : /* Adjust the pointer by the difference to first_stmt. */
11945 : 2801 : data_reference_p ptrdr
11946 : : = STMT_VINFO_DATA_REF (first_stmt_info_for_drptr);
11947 : 2801 : tree diff
11948 : 2801 : = fold_convert (sizetype,
11949 : : size_binop (MINUS_EXPR,
11950 : : DR_INIT (first_dr_info->dr),
11951 : : DR_INIT (ptrdr)));
11952 : 2801 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11953 : : stmt_info, diff);
11954 : 2801 : if (alignment_support_scheme == dr_explicit_realign)
11955 : : {
11956 : 0 : msq = vect_setup_realignment (vinfo,
11957 : : first_stmt_info_for_drptr, gsi,
11958 : : &realignment_token,
11959 : : alignment_support_scheme,
11960 : : dataref_ptr, &at_loop);
11961 : 0 : gcc_assert (!compute_in_loop);
11962 : : }
11963 : : }
11964 : : else
11965 : 146164 : dataref_ptr
11966 : 146164 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
11967 : : at_loop,
11968 : : offset, &dummy, gsi, &ptr_incr,
11969 : : simd_lane_access_p, bump);
11970 : : }
11971 : 376312 : else if (!costing_p)
11972 : : {
11973 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
11974 : 0 : if (dataref_offset)
11975 : 0 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset,
11976 : : bump);
11977 : : else
11978 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11979 : : stmt_info, bump);
11980 : : }
11981 : :
11982 : 526884 : if (grouped_load || slp_perm)
11983 : 36524 : dr_chain.create (vec_num);
11984 : :
11985 : 526884 : gimple *new_stmt = NULL;
11986 : 1596807 : for (i = 0; i < vec_num; i++)
11987 : : {
11988 : 1069923 : tree final_mask = NULL_TREE;
11989 : 1069923 : tree final_len = NULL_TREE;
11990 : 1069923 : tree bias = NULL_TREE;
11991 : :
11992 : 1069923 : if (!costing_p)
11993 : : {
11994 : 216153 : if (mask)
11995 : 530 : vec_mask = vec_masks[vec_num * j + i];
11996 : 216153 : if (loop_masks)
11997 : 17 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
11998 : 17 : vec_num * ncopies, vectype,
11999 : 17 : vec_num * j + i);
12000 : 216153 : if (vec_mask)
12001 : 530 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
12002 : : final_mask, vec_mask, gsi);
12003 : :
12004 : 216153 : if (i > 0)
12005 : 65581 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
12006 : : gsi, stmt_info, bump);
12007 : : }
12008 : :
12009 : : /* 2. Create the vector-load in the loop. */
12010 : 1069923 : switch (alignment_support_scheme)
12011 : : {
12012 : 1069923 : case dr_aligned:
12013 : 1069923 : case dr_unaligned_supported:
12014 : 1069923 : {
12015 : 1069923 : if (costing_p)
12016 : : break;
12017 : :
12018 : 216153 : unsigned int misalign;
12019 : 216153 : unsigned HOST_WIDE_INT align;
12020 : 216153 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
12021 : 216153 : if (alignment_support_scheme == dr_aligned)
12022 : : misalign = 0;
12023 : 118277 : else if (misalignment == DR_MISALIGNMENT_UNKNOWN)
12024 : : {
12025 : 90444 : align
12026 : 90444 : = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
12027 : 90444 : misalign = 0;
12028 : : }
12029 : : else
12030 : 27833 : misalign = misalignment;
12031 : 216153 : if (dataref_offset == NULL_TREE
12032 : 214058 : && TREE_CODE (dataref_ptr) == SSA_NAME)
12033 : 144187 : set_ptr_info_alignment (get_ptr_info (dataref_ptr), align,
12034 : : misalign);
12035 : 216153 : align = least_bit_hwi (misalign | align);
12036 : :
12037 : : /* Compute IFN when LOOP_LENS or final_mask valid. */
12038 : 216153 : machine_mode vmode = TYPE_MODE (vectype);
12039 : 216153 : machine_mode new_vmode = vmode;
12040 : 216153 : internal_fn partial_ifn = IFN_LAST;
12041 : 216153 : if (loop_lens)
12042 : : {
12043 : 0 : opt_machine_mode new_ovmode
12044 : 0 : = get_len_load_store_mode (vmode, true, &partial_ifn);
12045 : 0 : new_vmode = new_ovmode.require ();
12046 : 0 : unsigned factor
12047 : 0 : = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode);
12048 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
12049 : 0 : vec_num * ncopies, vectype,
12050 : 0 : vec_num * j + i, factor);
12051 : : }
12052 : 216153 : else if (final_mask)
12053 : : {
12054 : 547 : if (!can_vec_mask_load_store_p (
12055 : 547 : vmode, TYPE_MODE (TREE_TYPE (final_mask)), true,
12056 : : &partial_ifn))
12057 : 0 : gcc_unreachable ();
12058 : : }
12059 : :
12060 : 216153 : if (partial_ifn == IFN_MASK_LEN_LOAD)
12061 : : {
12062 : 0 : if (!final_len)
12063 : : {
12064 : : /* Pass VF value to 'len' argument of
12065 : : MASK_LEN_LOAD if LOOP_LENS is invalid. */
12066 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
12067 : : }
12068 : 0 : if (!final_mask)
12069 : : {
12070 : : /* Pass all ones value to 'mask' argument of
12071 : : MASK_LEN_LOAD if final_mask is invalid. */
12072 : 0 : mask_vectype = truth_type_for (vectype);
12073 : 0 : final_mask = build_minus_one_cst (mask_vectype);
12074 : : }
12075 : : }
12076 : 216153 : if (final_len)
12077 : : {
12078 : 0 : signed char biasval
12079 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
12080 : :
12081 : 0 : bias = build_int_cst (intQI_type_node, biasval);
12082 : : }
12083 : :
12084 : 216153 : tree vec_els;
12085 : :
12086 : 216153 : if (final_len)
12087 : : {
12088 : 0 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
12089 : 0 : gcall *call;
12090 : 0 : if (partial_ifn == IFN_MASK_LEN_LOAD)
12091 : : {
12092 : 0 : vec_els = vect_get_mask_load_else
12093 : 0 : (maskload_elsval, vectype);
12094 : 0 : if (type_mode_padding_p
12095 : 0 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
12096 : 0 : need_zeroing = true;
12097 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_LOAD,
12098 : : 6, dataref_ptr, ptr,
12099 : : final_mask, vec_els,
12100 : : final_len, bias);
12101 : : }
12102 : : else
12103 : 0 : call = gimple_build_call_internal (IFN_LEN_LOAD, 4,
12104 : : dataref_ptr, ptr,
12105 : : final_len, bias);
12106 : 0 : gimple_call_set_nothrow (call, true);
12107 : 0 : new_stmt = call;
12108 : 0 : data_ref = NULL_TREE;
12109 : :
12110 : : /* Need conversion if it's wrapped with VnQI. */
12111 : 0 : if (vmode != new_vmode)
12112 : : {
12113 : 0 : tree new_vtype = build_vector_type_for_mode (
12114 : : unsigned_intQI_type_node, new_vmode);
12115 : 0 : tree var
12116 : 0 : = vect_get_new_ssa_name (new_vtype, vect_simple_var);
12117 : 0 : gimple_set_lhs (call, var);
12118 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call,
12119 : : gsi);
12120 : 0 : tree op = build1 (VIEW_CONVERT_EXPR, vectype, var);
12121 : 0 : new_stmt = gimple_build_assign (vec_dest,
12122 : : VIEW_CONVERT_EXPR, op);
12123 : : }
12124 : : }
12125 : 216153 : else if (final_mask)
12126 : : {
12127 : 547 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
12128 : 547 : vec_els = vect_get_mask_load_else
12129 : 547 : (maskload_elsval, vectype);
12130 : 547 : if (type_mode_padding_p
12131 : 547 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
12132 : 0 : need_zeroing = true;
12133 : 547 : gcall *call = gimple_build_call_internal (IFN_MASK_LOAD, 4,
12134 : : dataref_ptr, ptr,
12135 : : final_mask,
12136 : : vec_els);
12137 : 547 : gimple_call_set_nothrow (call, true);
12138 : 547 : new_stmt = call;
12139 : 547 : data_ref = NULL_TREE;
12140 : : }
12141 : : else
12142 : : {
12143 : 215606 : tree ltype = vectype;
12144 : 215606 : tree new_vtype = NULL_TREE;
12145 : 215606 : unsigned HOST_WIDE_INT gap = DR_GROUP_GAP (first_stmt_info);
12146 : 215606 : unsigned HOST_WIDE_INT dr_size
12147 : 215606 : = vect_get_scalar_dr_size (first_dr_info);
12148 : 215606 : poly_int64 off = 0;
12149 : 215606 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
12150 : 1409 : off = (TYPE_VECTOR_SUBPARTS (vectype) - 1) * -dr_size;
12151 : 215606 : unsigned int vect_align
12152 : 215606 : = vect_known_alignment_in_bytes (first_dr_info, vectype,
12153 : 215606 : off);
12154 : : /* Try to use a single smaller load when we are about
12155 : : to load excess elements compared to the unrolled
12156 : : scalar loop. */
12157 : 215606 : if (known_gt ((vec_num * j + i + 1) * nunits,
12158 : : (group_size * vf - gap)))
12159 : : {
12160 : 2107 : poly_uint64 remain = ((group_size * vf - gap)
12161 : 2107 : - (vec_num * j + i) * nunits);
12162 : 2107 : if (known_ge ((vec_num * j + i + 1) * nunits
12163 : : - (group_size * vf - gap), nunits))
12164 : : /* DR will be unused. */
12165 : : ltype = NULL_TREE;
12166 : 1582 : else if (known_ge (vect_align,
12167 : : tree_to_poly_uint64
12168 : : (TYPE_SIZE_UNIT (vectype))))
12169 : : /* Aligned access to excess elements is OK if
12170 : : at least one element is accessed in the
12171 : : scalar loop. */
12172 : : ;
12173 : 1351 : else if (known_gt (vect_align,
12174 : : ((nunits - remain) * dr_size)))
12175 : : /* Aligned access to the gap area when there's
12176 : : at least one element in it is OK. */
12177 : : ;
12178 : : else
12179 : : {
12180 : : /* remain should now be > 0 and < nunits. */
12181 : 1348 : unsigned num;
12182 : 1348 : if (known_ne (remain, 0u)
12183 : 1348 : && constant_multiple_p (nunits, remain, &num))
12184 : : {
12185 : 985 : tree ptype;
12186 : 985 : new_vtype
12187 : 985 : = vector_vector_composition_type (vectype,
12188 : : num,
12189 : : &ptype);
12190 : 985 : if (new_vtype)
12191 : 985 : ltype = ptype;
12192 : : }
12193 : : /* Else use multiple loads or a masked load? */
12194 : : /* For loop vectorization we now should have
12195 : : an alternate type or LOOP_VINFO_PEELING_FOR_GAPS
12196 : : set. */
12197 : 1348 : if (loop_vinfo)
12198 : 1295 : gcc_assert (new_vtype
12199 : : || LOOP_VINFO_PEELING_FOR_GAPS
12200 : : (loop_vinfo));
12201 : : /* But still reduce the access size to the next
12202 : : required power-of-two so peeling a single
12203 : : scalar iteration is sufficient. */
12204 : 1348 : unsigned HOST_WIDE_INT cremain;
12205 : 1348 : if (remain.is_constant (&cremain))
12206 : : {
12207 : 1348 : unsigned HOST_WIDE_INT cpart_size
12208 : 1348 : = 1 << ceil_log2 (cremain);
12209 : 1348 : if (known_gt (nunits, cpart_size)
12210 : 1348 : && constant_multiple_p (nunits, cpart_size,
12211 : : &num))
12212 : : {
12213 : 997 : tree ptype;
12214 : 997 : new_vtype
12215 : 997 : = vector_vector_composition_type (vectype,
12216 : : num,
12217 : : &ptype);
12218 : 997 : if (new_vtype)
12219 : 997 : ltype = ptype;
12220 : : }
12221 : : }
12222 : : }
12223 : : }
12224 : 215606 : tree offset
12225 : 215606 : = (dataref_offset ? dataref_offset
12226 : 213511 : : build_int_cst (ref_type, 0));
12227 : 215606 : if (!ltype)
12228 : : ;
12229 : 215081 : else if (ltype != vectype
12230 : 997 : && memory_access_type == VMAT_CONTIGUOUS_REVERSE)
12231 : : {
12232 : 21 : poly_uint64 gap_offset
12233 : 21 : = (tree_to_poly_uint64 (TYPE_SIZE_UNIT (vectype))
12234 : 21 : - tree_to_poly_uint64 (TYPE_SIZE_UNIT (ltype)));
12235 : 21 : tree gapcst = build_int_cstu (ref_type, gap_offset);
12236 : 21 : offset = size_binop (PLUS_EXPR, offset, gapcst);
12237 : : }
12238 : 215606 : if (ltype)
12239 : : {
12240 : 215081 : data_ref
12241 : 215081 : = fold_build2 (MEM_REF, ltype, dataref_ptr, offset);
12242 : 215081 : if (alignment_support_scheme == dr_aligned)
12243 : : ;
12244 : : else
12245 : 117608 : TREE_TYPE (data_ref)
12246 : 235216 : = build_aligned_type (TREE_TYPE (data_ref),
12247 : : align * BITS_PER_UNIT);
12248 : : }
12249 : 215606 : if (!ltype)
12250 : 525 : data_ref = build_constructor (vectype, NULL);
12251 : 215081 : else if (ltype != vectype)
12252 : : {
12253 : 997 : vect_copy_ref_info (data_ref,
12254 : 997 : DR_REF (first_dr_info->dr));
12255 : 997 : tree tem = make_ssa_name (ltype);
12256 : 997 : new_stmt = gimple_build_assign (tem, data_ref);
12257 : 997 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
12258 : : gsi);
12259 : 997 : data_ref = NULL;
12260 : 997 : vec<constructor_elt, va_gc> *v;
12261 : : /* We've computed 'num' above to statically two
12262 : : or via constant_multiple_p. */
12263 : 997 : unsigned num
12264 : 997 : = (exact_div (tree_to_poly_uint64
12265 : 997 : (TYPE_SIZE_UNIT (vectype)),
12266 : : tree_to_poly_uint64
12267 : 997 : (TYPE_SIZE_UNIT (ltype)))
12268 : 997 : .to_constant ());
12269 : 997 : vec_alloc (v, num);
12270 : 997 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
12271 : : {
12272 : 54 : while (--num)
12273 : 54 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
12274 : : build_zero_cst (ltype));
12275 : 21 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem);
12276 : : }
12277 : : else
12278 : : {
12279 : 976 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem);
12280 : 976 : while (--num)
12281 : 2296 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
12282 : : build_zero_cst (ltype));
12283 : : }
12284 : 997 : gcc_assert (new_vtype != NULL_TREE);
12285 : 997 : if (new_vtype == vectype)
12286 : 967 : new_stmt = gimple_build_assign (
12287 : : vec_dest, build_constructor (vectype, v));
12288 : : else
12289 : : {
12290 : 30 : tree new_vname = make_ssa_name (new_vtype);
12291 : 30 : new_stmt = gimple_build_assign (
12292 : : new_vname, build_constructor (new_vtype, v));
12293 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
12294 : : new_stmt, gsi);
12295 : 30 : new_stmt = gimple_build_assign (
12296 : : vec_dest,
12297 : : build1 (VIEW_CONVERT_EXPR, vectype, new_vname));
12298 : : }
12299 : : }
12300 : : }
12301 : : break;
12302 : : }
12303 : 0 : case dr_explicit_realign:
12304 : 0 : {
12305 : 0 : if (costing_p)
12306 : : break;
12307 : 0 : tree ptr, bump;
12308 : :
12309 : 0 : tree vs = size_int (TYPE_VECTOR_SUBPARTS (vectype));
12310 : :
12311 : 0 : if (compute_in_loop)
12312 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info, gsi,
12313 : : &realignment_token,
12314 : : dr_explicit_realign,
12315 : : dataref_ptr, NULL);
12316 : :
12317 : 0 : if (TREE_CODE (dataref_ptr) == SSA_NAME)
12318 : 0 : ptr = copy_ssa_name (dataref_ptr);
12319 : : else
12320 : 0 : ptr = make_ssa_name (TREE_TYPE (dataref_ptr));
12321 : : // For explicit realign the target alignment should be
12322 : : // known at compile time.
12323 : 0 : unsigned HOST_WIDE_INT align
12324 : 0 : = DR_TARGET_ALIGNMENT (first_dr_info).to_constant ();
12325 : 0 : new_stmt = gimple_build_assign (
12326 : : ptr, BIT_AND_EXPR, dataref_ptr,
12327 : 0 : build_int_cst (TREE_TYPE (dataref_ptr),
12328 : 0 : -(HOST_WIDE_INT) align));
12329 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12330 : 0 : data_ref
12331 : 0 : = build2 (MEM_REF, vectype, ptr, build_int_cst (ref_type, 0));
12332 : 0 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
12333 : 0 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
12334 : 0 : new_stmt = gimple_build_assign (vec_dest, data_ref);
12335 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
12336 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
12337 : 0 : gimple_move_vops (new_stmt, stmt_info->stmt);
12338 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12339 : 0 : msq = new_temp;
12340 : :
12341 : 0 : bump = size_binop (MULT_EXPR, vs, TYPE_SIZE_UNIT (elem_type));
12342 : 0 : bump = size_binop (MINUS_EXPR, bump, size_one_node);
12343 : 0 : ptr = bump_vector_ptr (vinfo, dataref_ptr, NULL, gsi, stmt_info,
12344 : : bump);
12345 : 0 : new_stmt = gimple_build_assign (
12346 : : NULL_TREE, BIT_AND_EXPR, ptr,
12347 : 0 : build_int_cst (TREE_TYPE (ptr), -(HOST_WIDE_INT) align));
12348 : 0 : if (TREE_CODE (ptr) == SSA_NAME)
12349 : 0 : ptr = copy_ssa_name (ptr, new_stmt);
12350 : : else
12351 : 0 : ptr = make_ssa_name (TREE_TYPE (ptr), new_stmt);
12352 : 0 : gimple_assign_set_lhs (new_stmt, ptr);
12353 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12354 : 0 : data_ref
12355 : 0 : = build2 (MEM_REF, vectype, ptr, build_int_cst (ref_type, 0));
12356 : 0 : break;
12357 : : }
12358 : 0 : case dr_explicit_realign_optimized:
12359 : 0 : {
12360 : 0 : if (costing_p)
12361 : : break;
12362 : 0 : if (TREE_CODE (dataref_ptr) == SSA_NAME)
12363 : 0 : new_temp = copy_ssa_name (dataref_ptr);
12364 : : else
12365 : 0 : new_temp = make_ssa_name (TREE_TYPE (dataref_ptr));
12366 : : // We should only be doing this if we know the target
12367 : : // alignment at compile time.
12368 : 0 : unsigned HOST_WIDE_INT align
12369 : 0 : = DR_TARGET_ALIGNMENT (first_dr_info).to_constant ();
12370 : 0 : new_stmt = gimple_build_assign (
12371 : : new_temp, BIT_AND_EXPR, dataref_ptr,
12372 : 0 : build_int_cst (TREE_TYPE (dataref_ptr),
12373 : 0 : -(HOST_WIDE_INT) align));
12374 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12375 : 0 : data_ref = build2 (MEM_REF, vectype, new_temp,
12376 : 0 : build_int_cst (ref_type, 0));
12377 : 0 : break;
12378 : : }
12379 : 0 : default:
12380 : 0 : gcc_unreachable ();
12381 : : }
12382 : :
12383 : : /* One common place to cost the above vect load for different
12384 : : alignment support schemes. */
12385 : 1069923 : if (costing_p)
12386 : : {
12387 : : /* For VMAT_CONTIGUOUS_PERMUTE if it's grouped load, we
12388 : : only need to take care of the first stmt, whose
12389 : : stmt_info is first_stmt_info, vec_num iterating on it
12390 : : will cover the cost for the remaining, it's consistent
12391 : : with transforming. For the prologue cost for realign,
12392 : : we only need to count it once for the whole group. */
12393 : 853770 : bool first_stmt_info_p = first_stmt_info == stmt_info;
12394 : 853770 : bool add_realign_cost = first_stmt_info_p && i == 0;
12395 : 853770 : if (memory_access_type == VMAT_CONTIGUOUS
12396 : 5081 : || memory_access_type == VMAT_CONTIGUOUS_REVERSE
12397 : 0 : || (memory_access_type == VMAT_CONTIGUOUS_PERMUTE
12398 : 0 : && (!grouped_load || first_stmt_info_p)))
12399 : : {
12400 : : /* Leave realign cases alone to keep them simple. */
12401 : 853770 : if (alignment_support_scheme == dr_explicit_realign_optimized
12402 : 853770 : || alignment_support_scheme == dr_explicit_realign)
12403 : 0 : vect_get_load_cost (vinfo, stmt_info, slp_node, 1,
12404 : : alignment_support_scheme, misalignment,
12405 : : add_realign_cost, &inside_cost,
12406 : : &prologue_cost, cost_vec, cost_vec,
12407 : : true);
12408 : : else
12409 : 853770 : n_adjacent_loads++;
12410 : : }
12411 : : }
12412 : : else
12413 : : {
12414 : 216153 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
12415 : : /* DATA_REF is null if we've already built the statement. */
12416 : 216153 : if (data_ref)
12417 : : {
12418 : 214609 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
12419 : 214609 : new_stmt = gimple_build_assign (vec_dest, data_ref);
12420 : : }
12421 : :
12422 : 432306 : new_temp = need_zeroing
12423 : 216153 : ? make_ssa_name (vectype)
12424 : 216153 : : make_ssa_name (vec_dest, new_stmt);
12425 : 216153 : gimple_set_lhs (new_stmt, new_temp);
12426 : 216153 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12427 : :
12428 : : /* If we need to explicitly zero inactive elements emit a
12429 : : VEC_COND_EXPR that does so. */
12430 : 216153 : if (need_zeroing)
12431 : : {
12432 : 0 : vec_els = vect_get_mask_load_else (MASK_LOAD_ELSE_ZERO,
12433 : : vectype);
12434 : :
12435 : 0 : tree new_temp2 = make_ssa_name (vec_dest, new_stmt);
12436 : 0 : new_stmt
12437 : 0 : = gimple_build_assign (new_temp2, VEC_COND_EXPR,
12438 : : final_mask, new_temp, vec_els);
12439 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
12440 : : gsi);
12441 : 0 : new_temp = new_temp2;
12442 : : }
12443 : : }
12444 : :
12445 : : /* 3. Handle explicit realignment if necessary/supported.
12446 : : Create in loop:
12447 : : vec_dest = realign_load (msq, lsq, realignment_token) */
12448 : 1069923 : if (!costing_p
12449 : 216153 : && (alignment_support_scheme == dr_explicit_realign_optimized
12450 : 216153 : || alignment_support_scheme == dr_explicit_realign))
12451 : : {
12452 : 0 : lsq = gimple_assign_lhs (new_stmt);
12453 : 0 : if (!realignment_token)
12454 : 0 : realignment_token = dataref_ptr;
12455 : 0 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
12456 : 0 : new_stmt = gimple_build_assign (vec_dest, REALIGN_LOAD_EXPR, msq,
12457 : : lsq, realignment_token);
12458 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
12459 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
12460 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12461 : :
12462 : 0 : if (alignment_support_scheme == dr_explicit_realign_optimized)
12463 : : {
12464 : 0 : gcc_assert (phi);
12465 : 0 : if (i == vec_num - 1 && j == ncopies - 1)
12466 : 0 : add_phi_arg (phi, lsq, loop_latch_edge (containing_loop),
12467 : : UNKNOWN_LOCATION);
12468 : : msq = lsq;
12469 : : }
12470 : : }
12471 : :
12472 : 1069923 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
12473 : : {
12474 : 6490 : if (costing_p)
12475 : 5081 : inside_cost = record_stmt_cost (cost_vec, 1, vec_perm,
12476 : : stmt_info, slp_node, 0,
12477 : : vect_body);
12478 : : else
12479 : : {
12480 : 1409 : tree perm_mask = perm_mask_for_reverse (vectype);
12481 : 1409 : new_temp = permute_vec_elements (vinfo, new_temp, new_temp,
12482 : : perm_mask, stmt_info, gsi);
12483 : 1409 : new_stmt = SSA_NAME_DEF_STMT (new_temp);
12484 : : }
12485 : : }
12486 : :
12487 : : /* Collect vector loads and later create their permutation in
12488 : : vect_transform_grouped_load (). */
12489 : 1069923 : if (!costing_p && (grouped_load || slp_perm))
12490 : 44202 : dr_chain.quick_push (new_temp);
12491 : :
12492 : : /* Store vector loads in the corresponding SLP_NODE. */
12493 : 1069923 : if (!costing_p && slp && !slp_perm)
12494 : 171951 : slp_node->push_vec_def (new_stmt);
12495 : :
12496 : : /* With SLP permutation we load the gaps as well, without
12497 : : we need to skip the gaps after we manage to fully load
12498 : : all elements. group_gap_adj is DR_GROUP_SIZE here. */
12499 : 1069923 : group_elt += nunits;
12500 : 1069923 : if (!costing_p
12501 : 216153 : && maybe_ne (group_gap_adj, 0U)
12502 : 21940 : && !slp_perm
12503 : 1090214 : && known_eq (group_elt, group_size - group_gap_adj))
12504 : : {
12505 : 16827 : poly_wide_int bump_val
12506 : 16827 : = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj);
12507 : 16827 : if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step)
12508 : : == -1)
12509 : 0 : bump_val = -bump_val;
12510 : 16827 : tree bump = wide_int_to_tree (sizetype, bump_val);
12511 : 16827 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
12512 : : stmt_info, bump);
12513 : 16827 : group_elt = 0;
12514 : 16827 : }
12515 : : }
12516 : : /* Bump the vector pointer to account for a gap or for excess
12517 : : elements loaded for a permuted SLP load. */
12518 : 526884 : if (!costing_p
12519 : 150572 : && maybe_ne (group_gap_adj, 0U)
12520 : 543892 : && slp_perm)
12521 : : {
12522 : 181 : poly_wide_int bump_val
12523 : 181 : = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj);
12524 : 181 : if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step) == -1)
12525 : 9 : bump_val = -bump_val;
12526 : 181 : tree bump = wide_int_to_tree (sizetype, bump_val);
12527 : 181 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
12528 : : stmt_info, bump);
12529 : 181 : }
12530 : :
12531 : 526884 : if (slp && !slp_perm)
12532 : 490360 : continue;
12533 : :
12534 : 36524 : if (slp_perm)
12535 : : {
12536 : 36524 : unsigned n_perms;
12537 : : /* For SLP we know we've seen all possible uses of dr_chain so
12538 : : direct vect_transform_slp_perm_load to DCE the unused parts.
12539 : : ??? This is a hack to prevent compile-time issues as seen
12540 : : in PR101120 and friends. */
12541 : 36524 : if (costing_p)
12542 : : {
12543 : 27445 : vect_transform_slp_perm_load (vinfo, slp_node, vNULL, nullptr, vf,
12544 : : true, &n_perms, nullptr);
12545 : 27445 : inside_cost = record_stmt_cost (cost_vec, n_perms, vec_perm,
12546 : : stmt_info, slp_node, 0,
12547 : : vect_body);
12548 : : }
12549 : : else
12550 : : {
12551 : 9079 : bool ok = vect_transform_slp_perm_load (vinfo, slp_node, dr_chain,
12552 : : gsi, vf, false, &n_perms,
12553 : : nullptr, true);
12554 : 9079 : gcc_assert (ok);
12555 : : }
12556 : : }
12557 : : else
12558 : : {
12559 : 0 : if (grouped_load)
12560 : : {
12561 : 0 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS_PERMUTE);
12562 : : /* We assume that the cost of a single load-lanes instruction
12563 : : is equivalent to the cost of DR_GROUP_SIZE separate loads.
12564 : : If a grouped access is instead being provided by a
12565 : : load-and-permute operation, include the cost of the
12566 : : permutes. */
12567 : 0 : if (costing_p && first_stmt_info == stmt_info)
12568 : : {
12569 : : /* Uses an even and odd extract operations or shuffle
12570 : : operations for each needed permute. */
12571 : 0 : int group_size = DR_GROUP_SIZE (first_stmt_info);
12572 : 0 : int nstmts = ceil_log2 (group_size) * group_size;
12573 : 0 : inside_cost += record_stmt_cost (cost_vec, nstmts, vec_perm,
12574 : : stmt_info, slp_node, 0,
12575 : : vect_body);
12576 : :
12577 : 0 : if (dump_enabled_p ())
12578 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
12579 : : "vect_model_load_cost: "
12580 : : "strided group_size = %d .\n",
12581 : : group_size);
12582 : : }
12583 : 0 : else if (!costing_p)
12584 : : {
12585 : 0 : vect_transform_grouped_load (vinfo, stmt_info, dr_chain,
12586 : : group_size, gsi);
12587 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
12588 : : }
12589 : : }
12590 : 0 : else if (!costing_p)
12591 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
12592 : : }
12593 : 36524 : dr_chain.release ();
12594 : : }
12595 : 526884 : if (!slp && !costing_p)
12596 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
12597 : :
12598 : 526884 : if (costing_p)
12599 : : {
12600 : 376312 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS
12601 : : || memory_access_type == VMAT_CONTIGUOUS_REVERSE
12602 : : || memory_access_type == VMAT_CONTIGUOUS_PERMUTE);
12603 : 376312 : if (n_adjacent_loads > 0)
12604 : 376312 : vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
12605 : : alignment_support_scheme, misalignment, false,
12606 : : &inside_cost, &prologue_cost, cost_vec, cost_vec,
12607 : : true);
12608 : 376312 : if (dump_enabled_p ())
12609 : 25576 : dump_printf_loc (MSG_NOTE, vect_location,
12610 : : "vect_model_load_cost: inside_cost = %u, "
12611 : : "prologue_cost = %u .\n",
12612 : : inside_cost, prologue_cost);
12613 : : }
12614 : :
12615 : : return true;
12616 : 1170276 : }
12617 : :
12618 : : /* Function vect_is_simple_cond.
12619 : :
12620 : : Input:
12621 : : LOOP - the loop that is being vectorized.
12622 : : COND - Condition that is checked for simple use.
12623 : :
12624 : : Output:
12625 : : *COMP_VECTYPE - the vector type for the comparison.
12626 : : *DTS - The def types for the arguments of the comparison
12627 : :
12628 : : Returns whether a COND can be vectorized. Checks whether
12629 : : condition operands are supportable using vec_is_simple_use. */
12630 : :
12631 : : static bool
12632 : 25342 : vect_is_simple_cond (tree cond, vec_info *vinfo, stmt_vec_info stmt_info,
12633 : : slp_tree slp_node, tree *comp_vectype,
12634 : : enum vect_def_type *dts, tree vectype)
12635 : : {
12636 : 25342 : tree lhs, rhs;
12637 : 25342 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
12638 : 25342 : slp_tree slp_op;
12639 : :
12640 : : /* Mask case. */
12641 : 25342 : if (TREE_CODE (cond) == SSA_NAME
12642 : 25342 : && VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (cond)))
12643 : : {
12644 : 25330 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &cond,
12645 : : &slp_op, &dts[0], comp_vectype)
12646 : 25330 : || !*comp_vectype
12647 : 50634 : || !VECTOR_BOOLEAN_TYPE_P (*comp_vectype))
12648 : : return false;
12649 : : return true;
12650 : : }
12651 : :
12652 : 12 : if (!COMPARISON_CLASS_P (cond))
12653 : : return false;
12654 : :
12655 : 0 : lhs = TREE_OPERAND (cond, 0);
12656 : 0 : rhs = TREE_OPERAND (cond, 1);
12657 : :
12658 : 0 : if (TREE_CODE (lhs) == SSA_NAME)
12659 : : {
12660 : 0 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0,
12661 : : &lhs, &slp_op, &dts[0], &vectype1))
12662 : : return false;
12663 : : }
12664 : 0 : else if (TREE_CODE (lhs) == INTEGER_CST || TREE_CODE (lhs) == REAL_CST
12665 : 0 : || TREE_CODE (lhs) == FIXED_CST)
12666 : 0 : dts[0] = vect_constant_def;
12667 : : else
12668 : : return false;
12669 : :
12670 : 0 : if (TREE_CODE (rhs) == SSA_NAME)
12671 : : {
12672 : 0 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1,
12673 : : &rhs, &slp_op, &dts[1], &vectype2))
12674 : : return false;
12675 : : }
12676 : 0 : else if (TREE_CODE (rhs) == INTEGER_CST || TREE_CODE (rhs) == REAL_CST
12677 : 0 : || TREE_CODE (rhs) == FIXED_CST)
12678 : 0 : dts[1] = vect_constant_def;
12679 : : else
12680 : : return false;
12681 : :
12682 : 0 : if (vectype1 && vectype2
12683 : 0 : && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1),
12684 : 0 : TYPE_VECTOR_SUBPARTS (vectype2)))
12685 : 0 : return false;
12686 : :
12687 : 0 : *comp_vectype = vectype1 ? vectype1 : vectype2;
12688 : : /* Invariant comparison. */
12689 : 0 : if (! *comp_vectype)
12690 : : {
12691 : 0 : tree scalar_type = TREE_TYPE (lhs);
12692 : 0 : if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type))
12693 : 0 : *comp_vectype = truth_type_for (vectype);
12694 : : else
12695 : : {
12696 : : /* If we can widen the comparison to match vectype do so. */
12697 : 0 : if (INTEGRAL_TYPE_P (scalar_type)
12698 : 0 : && !slp_node
12699 : 0 : && tree_int_cst_lt (TYPE_SIZE (scalar_type),
12700 : 0 : TYPE_SIZE (TREE_TYPE (vectype))))
12701 : 0 : scalar_type = build_nonstandard_integer_type
12702 : 0 : (vector_element_bits (vectype), TYPE_UNSIGNED (scalar_type));
12703 : 0 : *comp_vectype = get_vectype_for_scalar_type (vinfo, scalar_type,
12704 : : slp_node);
12705 : : }
12706 : : }
12707 : :
12708 : : return true;
12709 : : }
12710 : :
12711 : : /* vectorizable_condition.
12712 : :
12713 : : Check if STMT_INFO is conditional modify expression that can be vectorized.
12714 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
12715 : : stmt using VEC_COND_EXPR to replace it, put it in VEC_STMT, and insert it
12716 : : at GSI.
12717 : :
12718 : : When STMT_INFO is vectorized as a nested cycle, for_reduction is true.
12719 : :
12720 : : Return true if STMT_INFO is vectorizable in this way. */
12721 : :
12722 : : static bool
12723 : 421366 : vectorizable_condition (vec_info *vinfo,
12724 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
12725 : : gimple **vec_stmt,
12726 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12727 : : {
12728 : 421366 : tree scalar_dest = NULL_TREE;
12729 : 421366 : tree vec_dest = NULL_TREE;
12730 : 421366 : tree cond_expr, cond_expr0 = NULL_TREE, cond_expr1 = NULL_TREE;
12731 : 421366 : tree then_clause, else_clause;
12732 : 421366 : tree comp_vectype = NULL_TREE;
12733 : 421366 : tree vec_cond_lhs = NULL_TREE, vec_cond_rhs = NULL_TREE;
12734 : 421366 : tree vec_then_clause = NULL_TREE, vec_else_clause = NULL_TREE;
12735 : 421366 : tree vec_compare;
12736 : 421366 : tree new_temp;
12737 : 421366 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
12738 : 421366 : enum vect_def_type dts[4]
12739 : : = {vect_unknown_def_type, vect_unknown_def_type,
12740 : : vect_unknown_def_type, vect_unknown_def_type};
12741 : 421366 : int ndts = 4;
12742 : 421366 : int ncopies;
12743 : 421366 : int vec_num;
12744 : 421366 : enum tree_code code, cond_code, bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
12745 : 421366 : int i;
12746 : 421366 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
12747 : 421366 : vec<tree> vec_oprnds0 = vNULL;
12748 : 421366 : vec<tree> vec_oprnds1 = vNULL;
12749 : 421366 : vec<tree> vec_oprnds2 = vNULL;
12750 : 421366 : vec<tree> vec_oprnds3 = vNULL;
12751 : 421366 : tree vec_cmp_type;
12752 : 421366 : bool masked = false;
12753 : :
12754 : 421366 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
12755 : : return false;
12756 : :
12757 : : /* Is vectorizable conditional operation? */
12758 : 732526 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
12759 : 335212 : if (!stmt)
12760 : : return false;
12761 : :
12762 : 335212 : code = gimple_assign_rhs_code (stmt);
12763 : 335212 : if (code != COND_EXPR)
12764 : : return false;
12765 : :
12766 : 25342 : stmt_vec_info reduc_info = NULL;
12767 : 25342 : int reduc_index = -1;
12768 : 25342 : vect_reduction_type reduction_type = TREE_CODE_REDUCTION;
12769 : 25342 : bool for_reduction
12770 : 25342 : = STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)) != NULL;
12771 : 25342 : if (for_reduction)
12772 : : {
12773 : 843 : if (slp_node && SLP_TREE_LANES (slp_node) > 1)
12774 : : return false;
12775 : 843 : reduc_info = info_for_reduction (vinfo, stmt_info);
12776 : 843 : reduction_type = STMT_VINFO_REDUC_TYPE (reduc_info);
12777 : 843 : reduc_index = STMT_VINFO_REDUC_IDX (stmt_info);
12778 : 843 : gcc_assert (reduction_type != EXTRACT_LAST_REDUCTION
12779 : : || reduc_index != -1);
12780 : : }
12781 : : else
12782 : : {
12783 : 24499 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
12784 : : return false;
12785 : : }
12786 : :
12787 : 25342 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
12788 : 25342 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
12789 : :
12790 : 25342 : if (slp_node)
12791 : : {
12792 : 25342 : ncopies = 1;
12793 : 25342 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
12794 : : }
12795 : : else
12796 : : {
12797 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
12798 : 0 : vec_num = 1;
12799 : : }
12800 : :
12801 : 25342 : gcc_assert (ncopies >= 1);
12802 : 25342 : if (for_reduction && ncopies > 1)
12803 : : return false; /* FORNOW */
12804 : :
12805 : 25342 : cond_expr = gimple_assign_rhs1 (stmt);
12806 : 25342 : gcc_assert (! COMPARISON_CLASS_P (cond_expr));
12807 : :
12808 : 25342 : if (!vect_is_simple_cond (cond_expr, vinfo, stmt_info, slp_node,
12809 : : &comp_vectype, &dts[0], vectype)
12810 : 25342 : || !comp_vectype)
12811 : : return false;
12812 : :
12813 : 25248 : unsigned op_adjust = COMPARISON_CLASS_P (cond_expr) ? 1 : 0;
12814 : 25248 : slp_tree then_slp_node, else_slp_node;
12815 : 25248 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1 + op_adjust,
12816 : : &then_clause, &then_slp_node, &dts[2], &vectype1))
12817 : : return false;
12818 : 25248 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 2 + op_adjust,
12819 : : &else_clause, &else_slp_node, &dts[3], &vectype2))
12820 : : return false;
12821 : :
12822 : 25248 : if (vectype1 && !useless_type_conversion_p (vectype, vectype1))
12823 : : return false;
12824 : :
12825 : 25248 : if (vectype2 && !useless_type_conversion_p (vectype, vectype2))
12826 : : return false;
12827 : :
12828 : 25248 : masked = !COMPARISON_CLASS_P (cond_expr);
12829 : 25248 : vec_cmp_type = truth_type_for (comp_vectype);
12830 : 25248 : if (vec_cmp_type == NULL_TREE
12831 : 50496 : || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype),
12832 : 25248 : TYPE_VECTOR_SUBPARTS (vec_cmp_type)))
12833 : 1128 : return false;
12834 : :
12835 : 24120 : cond_code = TREE_CODE (cond_expr);
12836 : 24120 : if (!masked)
12837 : : {
12838 : 0 : cond_expr0 = TREE_OPERAND (cond_expr, 0);
12839 : 0 : cond_expr1 = TREE_OPERAND (cond_expr, 1);
12840 : : }
12841 : :
12842 : : /* For conditional reductions, the "then" value needs to be the candidate
12843 : : value calculated by this iteration while the "else" value needs to be
12844 : : the result carried over from previous iterations. If the COND_EXPR
12845 : : is the other way around, we need to swap it. */
12846 : 24120 : bool must_invert_cmp_result = false;
12847 : 24120 : if (reduction_type == EXTRACT_LAST_REDUCTION && reduc_index == 1)
12848 : : {
12849 : 0 : if (masked)
12850 : : must_invert_cmp_result = true;
12851 : : else
12852 : : {
12853 : 0 : bool honor_nans = HONOR_NANS (TREE_TYPE (cond_expr0));
12854 : 0 : tree_code new_code = invert_tree_comparison (cond_code, honor_nans);
12855 : 0 : if (new_code == ERROR_MARK)
12856 : : must_invert_cmp_result = true;
12857 : : else
12858 : : {
12859 : 0 : cond_code = new_code;
12860 : : /* Make sure we don't accidentally use the old condition. */
12861 : 0 : cond_expr = NULL_TREE;
12862 : : }
12863 : : }
12864 : : /* ??? The vectorized operand query below doesn't allow swapping
12865 : : this way for SLP. */
12866 : 0 : if (slp_node)
12867 : : return false;
12868 : 0 : std::swap (then_clause, else_clause);
12869 : : }
12870 : :
12871 : 24120 : if (!masked && VECTOR_BOOLEAN_TYPE_P (comp_vectype))
12872 : : {
12873 : : /* Boolean values may have another representation in vectors
12874 : : and therefore we prefer bit operations over comparison for
12875 : : them (which also works for scalar masks). We store opcodes
12876 : : to use in bitop1 and bitop2. Statement is vectorized as
12877 : : BITOP2 (rhs1 BITOP1 rhs2) or rhs1 BITOP2 (BITOP1 rhs2)
12878 : : depending on bitop1 and bitop2 arity. */
12879 : 0 : switch (cond_code)
12880 : : {
12881 : : case GT_EXPR:
12882 : : bitop1 = BIT_NOT_EXPR;
12883 : : bitop2 = BIT_AND_EXPR;
12884 : : break;
12885 : 0 : case GE_EXPR:
12886 : 0 : bitop1 = BIT_NOT_EXPR;
12887 : 0 : bitop2 = BIT_IOR_EXPR;
12888 : 0 : break;
12889 : 0 : case LT_EXPR:
12890 : 0 : bitop1 = BIT_NOT_EXPR;
12891 : 0 : bitop2 = BIT_AND_EXPR;
12892 : 0 : std::swap (cond_expr0, cond_expr1);
12893 : 0 : break;
12894 : 0 : case LE_EXPR:
12895 : 0 : bitop1 = BIT_NOT_EXPR;
12896 : 0 : bitop2 = BIT_IOR_EXPR;
12897 : 0 : std::swap (cond_expr0, cond_expr1);
12898 : 0 : break;
12899 : 0 : case NE_EXPR:
12900 : 0 : bitop1 = BIT_XOR_EXPR;
12901 : 0 : break;
12902 : 0 : case EQ_EXPR:
12903 : 0 : bitop1 = BIT_XOR_EXPR;
12904 : 0 : bitop2 = BIT_NOT_EXPR;
12905 : 0 : break;
12906 : : default:
12907 : : return false;
12908 : : }
12909 : : cond_code = SSA_NAME;
12910 : : }
12911 : :
12912 : 24120 : if (TREE_CODE_CLASS (cond_code) == tcc_comparison
12913 : 0 : && reduction_type == EXTRACT_LAST_REDUCTION
12914 : 24120 : && !expand_vec_cmp_expr_p (comp_vectype, vec_cmp_type, cond_code))
12915 : : {
12916 : 0 : if (dump_enabled_p ())
12917 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12918 : : "reduction comparison operation not supported.\n");
12919 : 0 : return false;
12920 : : }
12921 : :
12922 : 24120 : if (!vec_stmt)
12923 : : {
12924 : 17877 : if (bitop1 != NOP_EXPR)
12925 : : {
12926 : 0 : machine_mode mode = TYPE_MODE (comp_vectype);
12927 : 0 : optab optab;
12928 : :
12929 : 0 : optab = optab_for_tree_code (bitop1, comp_vectype, optab_default);
12930 : 0 : if (!optab || !can_implement_p (optab, mode))
12931 : 0 : return false;
12932 : :
12933 : 0 : if (bitop2 != NOP_EXPR)
12934 : : {
12935 : 0 : optab = optab_for_tree_code (bitop2, comp_vectype,
12936 : : optab_default);
12937 : 0 : if (!optab || !can_implement_p (optab, mode))
12938 : 0 : return false;
12939 : : }
12940 : : }
12941 : :
12942 : 17877 : vect_cost_for_stmt kind = vector_stmt;
12943 : 17877 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12944 : : /* Count one reduction-like operation per vector. */
12945 : : kind = vec_to_scalar;
12946 : 17877 : else if ((masked && !expand_vec_cond_expr_p (vectype, comp_vectype))
12947 : 17877 : || (!masked
12948 : 0 : && (!expand_vec_cmp_expr_p (comp_vectype, vec_cmp_type,
12949 : : cond_code)
12950 : 0 : || !expand_vec_cond_expr_p (vectype, vec_cmp_type))))
12951 : 68 : return false;
12952 : :
12953 : 17809 : if (slp_node
12954 : 35618 : && (!vect_maybe_update_slp_op_vectype
12955 : 17809 : (SLP_TREE_CHILDREN (slp_node)[0], comp_vectype)
12956 : 17809 : || (op_adjust == 1
12957 : 0 : && !vect_maybe_update_slp_op_vectype
12958 : 0 : (SLP_TREE_CHILDREN (slp_node)[1], comp_vectype))
12959 : 17809 : || !vect_maybe_update_slp_op_vectype (then_slp_node, vectype)
12960 : 17809 : || !vect_maybe_update_slp_op_vectype (else_slp_node, vectype)))
12961 : : {
12962 : 0 : if (dump_enabled_p ())
12963 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12964 : : "incompatible vector types for invariants\n");
12965 : 0 : return false;
12966 : : }
12967 : :
12968 : 17809 : if (loop_vinfo && for_reduction
12969 : 664 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
12970 : : {
12971 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12972 : : {
12973 : 0 : if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST,
12974 : : vectype, OPTIMIZE_FOR_SPEED))
12975 : 0 : vect_record_loop_len (loop_vinfo,
12976 : : &LOOP_VINFO_LENS (loop_vinfo),
12977 : 0 : ncopies * vec_num, vectype, 1);
12978 : : else
12979 : 0 : vect_record_loop_mask (loop_vinfo,
12980 : : &LOOP_VINFO_MASKS (loop_vinfo),
12981 : 0 : ncopies * vec_num, vectype, NULL);
12982 : : }
12983 : : /* Extra inactive lanes should be safe for vect_nested_cycle. */
12984 : 0 : else if (STMT_VINFO_DEF_TYPE (reduc_info) != vect_nested_cycle)
12985 : : {
12986 : 0 : if (dump_enabled_p ())
12987 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12988 : : "conditional reduction prevents the use"
12989 : : " of partial vectors.\n");
12990 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
12991 : : }
12992 : : }
12993 : :
12994 : 17809 : STMT_VINFO_TYPE (stmt_info) = condition_vec_info_type;
12995 : 17809 : vect_model_simple_cost (vinfo, stmt_info, ncopies, dts, ndts, slp_node,
12996 : : cost_vec, kind);
12997 : 17809 : return true;
12998 : : }
12999 : :
13000 : : /* Transform. */
13001 : :
13002 : : /* Handle def. */
13003 : 6243 : scalar_dest = gimple_assign_lhs (stmt);
13004 : 6243 : if (reduction_type != EXTRACT_LAST_REDUCTION)
13005 : 6243 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
13006 : :
13007 : 6243 : bool swap_cond_operands = false;
13008 : :
13009 : : /* See whether another part of the vectorized code applies a loop
13010 : : mask to the condition, or to its inverse. */
13011 : :
13012 : 6243 : vec_loop_masks *masks = NULL;
13013 : 6243 : vec_loop_lens *lens = NULL;
13014 : 6243 : if (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo))
13015 : : {
13016 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
13017 : 0 : lens = &LOOP_VINFO_LENS (loop_vinfo);
13018 : : }
13019 : 6243 : else if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
13020 : : {
13021 : 2 : if (reduction_type == EXTRACT_LAST_REDUCTION)
13022 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
13023 : : else
13024 : : {
13025 : 2 : scalar_cond_masked_key cond (cond_expr, ncopies);
13026 : 2 : if (loop_vinfo->scalar_cond_masked_set.contains (cond))
13027 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
13028 : : else
13029 : : {
13030 : 2 : bool honor_nans = HONOR_NANS (TREE_TYPE (cond.op0));
13031 : 2 : tree_code orig_code = cond.code;
13032 : 2 : cond.code = invert_tree_comparison (cond.code, honor_nans);
13033 : 2 : if (!masked && loop_vinfo->scalar_cond_masked_set.contains (cond))
13034 : : {
13035 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
13036 : 0 : cond_code = cond.code;
13037 : 0 : swap_cond_operands = true;
13038 : : }
13039 : : else
13040 : : {
13041 : : /* Try the inverse of the current mask. We check if the
13042 : : inverse mask is live and if so we generate a negate of
13043 : : the current mask such that we still honor NaNs. */
13044 : 2 : cond.inverted_p = true;
13045 : 2 : cond.code = orig_code;
13046 : 2 : if (loop_vinfo->scalar_cond_masked_set.contains (cond))
13047 : : {
13048 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
13049 : 0 : cond_code = cond.code;
13050 : 0 : swap_cond_operands = true;
13051 : 0 : must_invert_cmp_result = true;
13052 : : }
13053 : : }
13054 : : }
13055 : : }
13056 : : }
13057 : :
13058 : : /* Handle cond expr. */
13059 : 6243 : if (masked)
13060 : 6243 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
13061 : : cond_expr, comp_vectype, &vec_oprnds0,
13062 : : then_clause, vectype, &vec_oprnds2,
13063 : : reduction_type != EXTRACT_LAST_REDUCTION
13064 : : ? else_clause : NULL, vectype, &vec_oprnds3);
13065 : : else
13066 : 0 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
13067 : : cond_expr0, comp_vectype, &vec_oprnds0,
13068 : : cond_expr1, comp_vectype, &vec_oprnds1,
13069 : : then_clause, vectype, &vec_oprnds2,
13070 : : reduction_type != EXTRACT_LAST_REDUCTION
13071 : : ? else_clause : NULL, vectype, &vec_oprnds3);
13072 : :
13073 : 6243 : if (reduction_type == EXTRACT_LAST_REDUCTION)
13074 : 0 : vec_else_clause = else_clause;
13075 : :
13076 : : /* Arguments are ready. Create the new vector stmt. */
13077 : 15026 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_cond_lhs)
13078 : : {
13079 : 8783 : vec_then_clause = vec_oprnds2[i];
13080 : 8783 : if (reduction_type != EXTRACT_LAST_REDUCTION)
13081 : 8783 : vec_else_clause = vec_oprnds3[i];
13082 : :
13083 : 8783 : if (swap_cond_operands)
13084 : 0 : std::swap (vec_then_clause, vec_else_clause);
13085 : :
13086 : 8783 : if (masked)
13087 : : vec_compare = vec_cond_lhs;
13088 : : else
13089 : : {
13090 : 0 : vec_cond_rhs = vec_oprnds1[i];
13091 : 0 : if (bitop1 == NOP_EXPR)
13092 : : {
13093 : 0 : gimple_seq stmts = NULL;
13094 : 0 : vec_compare = gimple_build (&stmts, cond_code, vec_cmp_type,
13095 : : vec_cond_lhs, vec_cond_rhs);
13096 : 0 : gsi_insert_before (gsi, stmts, GSI_SAME_STMT);
13097 : : }
13098 : : else
13099 : : {
13100 : 0 : new_temp = make_ssa_name (vec_cmp_type);
13101 : 0 : gassign *new_stmt;
13102 : 0 : if (bitop1 == BIT_NOT_EXPR)
13103 : 0 : new_stmt = gimple_build_assign (new_temp, bitop1,
13104 : : vec_cond_rhs);
13105 : : else
13106 : 0 : new_stmt
13107 : 0 : = gimple_build_assign (new_temp, bitop1, vec_cond_lhs,
13108 : : vec_cond_rhs);
13109 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
13110 : 0 : if (bitop2 == NOP_EXPR)
13111 : : vec_compare = new_temp;
13112 : 0 : else if (bitop2 == BIT_NOT_EXPR
13113 : 0 : && reduction_type != EXTRACT_LAST_REDUCTION)
13114 : : {
13115 : : /* Instead of doing ~x ? y : z do x ? z : y. */
13116 : : vec_compare = new_temp;
13117 : : std::swap (vec_then_clause, vec_else_clause);
13118 : : }
13119 : : else
13120 : : {
13121 : 0 : vec_compare = make_ssa_name (vec_cmp_type);
13122 : 0 : if (bitop2 == BIT_NOT_EXPR)
13123 : 0 : new_stmt
13124 : 0 : = gimple_build_assign (vec_compare, bitop2, new_temp);
13125 : : else
13126 : 0 : new_stmt
13127 : 0 : = gimple_build_assign (vec_compare, bitop2,
13128 : : vec_cond_lhs, new_temp);
13129 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
13130 : : new_stmt, gsi);
13131 : : }
13132 : : }
13133 : : }
13134 : :
13135 : : /* If we decided to apply a loop mask to the result of the vector
13136 : : comparison, AND the comparison with the mask now. Later passes
13137 : : should then be able to reuse the AND results between mulitple
13138 : : vector statements.
13139 : :
13140 : : For example:
13141 : : for (int i = 0; i < 100; ++i)
13142 : : x[i] = y[i] ? z[i] : 10;
13143 : :
13144 : : results in following optimized GIMPLE:
13145 : :
13146 : : mask__35.8_43 = vect__4.7_41 != { 0, ... };
13147 : : vec_mask_and_46 = loop_mask_40 & mask__35.8_43;
13148 : : _19 = &MEM[base: z_12(D), index: ivtmp_56, step: 4, offset: 0B];
13149 : : vect_iftmp.11_47 = .MASK_LOAD (_19, 4B, vec_mask_and_46);
13150 : : vect_iftmp.12_52 = VEC_COND_EXPR <vec_mask_and_46,
13151 : : vect_iftmp.11_47, { 10, ... }>;
13152 : :
13153 : : instead of using a masked and unmasked forms of
13154 : : vec != { 0, ... } (masked in the MASK_LOAD,
13155 : : unmasked in the VEC_COND_EXPR). */
13156 : :
13157 : : /* Force vec_compare to be an SSA_NAME rather than a comparison,
13158 : : in cases where that's necessary. */
13159 : :
13160 : 8783 : tree len = NULL_TREE, bias = NULL_TREE;
13161 : 8783 : if (masks || lens || reduction_type == EXTRACT_LAST_REDUCTION)
13162 : : {
13163 : 0 : if (!is_gimple_val (vec_compare))
13164 : : {
13165 : 0 : tree vec_compare_name = make_ssa_name (vec_cmp_type);
13166 : 0 : gassign *new_stmt = gimple_build_assign (vec_compare_name,
13167 : : vec_compare);
13168 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
13169 : 0 : vec_compare = vec_compare_name;
13170 : : }
13171 : :
13172 : 0 : if (must_invert_cmp_result)
13173 : : {
13174 : 0 : tree vec_compare_name = make_ssa_name (vec_cmp_type);
13175 : 0 : gassign *new_stmt = gimple_build_assign (vec_compare_name,
13176 : : BIT_NOT_EXPR,
13177 : : vec_compare);
13178 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
13179 : 0 : vec_compare = vec_compare_name;
13180 : : }
13181 : :
13182 : 0 : if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST,
13183 : : vectype, OPTIMIZE_FOR_SPEED))
13184 : : {
13185 : 0 : if (lens)
13186 : : {
13187 : 0 : len = vect_get_loop_len (loop_vinfo, gsi, lens,
13188 : 0 : vec_num * ncopies, vectype, i, 1);
13189 : 0 : signed char biasval
13190 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
13191 : 0 : bias = build_int_cst (intQI_type_node, biasval);
13192 : : }
13193 : : else
13194 : : {
13195 : 0 : len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
13196 : 0 : bias = build_int_cst (intQI_type_node, 0);
13197 : : }
13198 : : }
13199 : 0 : if (masks)
13200 : : {
13201 : 0 : tree loop_mask
13202 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, vec_num * ncopies,
13203 : : vectype, i);
13204 : 0 : tree tmp2 = make_ssa_name (vec_cmp_type);
13205 : 0 : gassign *g
13206 : 0 : = gimple_build_assign (tmp2, BIT_AND_EXPR, vec_compare,
13207 : : loop_mask);
13208 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
13209 : 0 : vec_compare = tmp2;
13210 : : }
13211 : : }
13212 : :
13213 : 0 : gimple *new_stmt;
13214 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
13215 : : {
13216 : 0 : gimple *old_stmt = vect_orig_stmt (stmt_info)->stmt;
13217 : 0 : tree lhs = gimple_get_lhs (old_stmt);
13218 : 0 : if ((unsigned)i != vec_oprnds0.length () - 1)
13219 : 0 : lhs = copy_ssa_name (lhs);
13220 : 0 : if (len)
13221 : 0 : new_stmt = gimple_build_call_internal
13222 : 0 : (IFN_LEN_FOLD_EXTRACT_LAST, 5, vec_else_clause, vec_compare,
13223 : : vec_then_clause, len, bias);
13224 : : else
13225 : 0 : new_stmt = gimple_build_call_internal
13226 : 0 : (IFN_FOLD_EXTRACT_LAST, 3, vec_else_clause, vec_compare,
13227 : : vec_then_clause);
13228 : 0 : gimple_call_set_lhs (new_stmt, lhs);
13229 : 0 : SSA_NAME_DEF_STMT (lhs) = new_stmt;
13230 : 0 : if ((unsigned)i != vec_oprnds0.length () - 1)
13231 : : {
13232 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
13233 : 0 : vec_else_clause = lhs;
13234 : : }
13235 : 0 : else if (old_stmt == gsi_stmt (*gsi))
13236 : 0 : vect_finish_replace_stmt (vinfo, stmt_info, new_stmt);
13237 : : else
13238 : : {
13239 : : /* In this case we're moving the definition to later in the
13240 : : block. That doesn't matter because the only uses of the
13241 : : lhs are in phi statements. */
13242 : 0 : gimple_stmt_iterator old_gsi = gsi_for_stmt (old_stmt);
13243 : 0 : gsi_remove (&old_gsi, true);
13244 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
13245 : : }
13246 : : }
13247 : : else
13248 : : {
13249 : 8783 : new_temp = make_ssa_name (vec_dest);
13250 : 8783 : new_stmt = gimple_build_assign (new_temp, VEC_COND_EXPR, vec_compare,
13251 : : vec_then_clause, vec_else_clause);
13252 : 8783 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
13253 : : }
13254 : 8783 : if (slp_node)
13255 : 8783 : slp_node->push_vec_def (new_stmt);
13256 : : else
13257 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
13258 : : }
13259 : :
13260 : 6243 : if (!slp_node)
13261 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
13262 : :
13263 : 6243 : vec_oprnds0.release ();
13264 : 6243 : vec_oprnds1.release ();
13265 : 6243 : vec_oprnds2.release ();
13266 : 6243 : vec_oprnds3.release ();
13267 : :
13268 : 6243 : return true;
13269 : : }
13270 : :
13271 : : /* Helper of vectorizable_comparison.
13272 : :
13273 : : Check if STMT_INFO is comparison expression CODE that can be vectorized.
13274 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
13275 : : comparison, put it in VEC_STMT, and insert it at GSI.
13276 : :
13277 : : Return true if STMT_INFO is vectorizable in this way. */
13278 : :
13279 : : static bool
13280 : 322409 : vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
13281 : : stmt_vec_info stmt_info, tree_code code,
13282 : : gimple_stmt_iterator *gsi, gimple **vec_stmt,
13283 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
13284 : : {
13285 : 322409 : tree lhs, rhs1, rhs2;
13286 : 322409 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
13287 : 322409 : tree vec_rhs1 = NULL_TREE, vec_rhs2 = NULL_TREE;
13288 : 322409 : tree new_temp;
13289 : 322409 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
13290 : 322409 : enum vect_def_type dts[2] = {vect_unknown_def_type, vect_unknown_def_type};
13291 : 322409 : int ndts = 2;
13292 : 322409 : poly_uint64 nunits;
13293 : 322409 : int ncopies;
13294 : 322409 : enum tree_code bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
13295 : 322409 : int i;
13296 : 322409 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
13297 : 322409 : vec<tree> vec_oprnds0 = vNULL;
13298 : 322409 : vec<tree> vec_oprnds1 = vNULL;
13299 : 322409 : tree mask_type;
13300 : 322409 : tree mask = NULL_TREE;
13301 : :
13302 : 322409 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
13303 : : return false;
13304 : :
13305 : 322409 : if (!vectype || !VECTOR_BOOLEAN_TYPE_P (vectype))
13306 : : return false;
13307 : :
13308 : 134165 : mask_type = vectype;
13309 : 134165 : nunits = TYPE_VECTOR_SUBPARTS (vectype);
13310 : :
13311 : 134165 : if (slp_node)
13312 : : ncopies = 1;
13313 : : else
13314 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
13315 : :
13316 : 0 : gcc_assert (ncopies >= 1);
13317 : :
13318 : 134165 : if (TREE_CODE_CLASS (code) != tcc_comparison)
13319 : : return false;
13320 : :
13321 : 131223 : slp_tree slp_rhs1, slp_rhs2;
13322 : 131223 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
13323 : : 0, &rhs1, &slp_rhs1, &dts[0], &vectype1))
13324 : : return false;
13325 : :
13326 : 131223 : if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
13327 : : 1, &rhs2, &slp_rhs2, &dts[1], &vectype2))
13328 : : return false;
13329 : :
13330 : 73206 : if (vectype1 && vectype2
13331 : 191677 : && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1),
13332 : 60454 : TYPE_VECTOR_SUBPARTS (vectype2)))
13333 : 16 : return false;
13334 : :
13335 : 131207 : vectype = vectype1 ? vectype1 : vectype2;
13336 : :
13337 : : /* Invariant comparison. */
13338 : 131207 : if (!vectype)
13339 : : {
13340 : 27666 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (rhs1), slp_node);
13341 : 27666 : if (!vectype || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype), nunits))
13342 : 11 : return false;
13343 : : }
13344 : 103541 : else if (maybe_ne (nunits, TYPE_VECTOR_SUBPARTS (vectype)))
13345 : : return false;
13346 : :
13347 : : /* Can't compare mask and non-mask types. */
13348 : 73190 : if (vectype1 && vectype2
13349 : 311982 : && (VECTOR_BOOLEAN_TYPE_P (vectype1) ^ VECTOR_BOOLEAN_TYPE_P (vectype2)))
13350 : : return false;
13351 : :
13352 : : /* Boolean values may have another representation in vectors
13353 : : and therefore we prefer bit operations over comparison for
13354 : : them (which also works for scalar masks). We store opcodes
13355 : : to use in bitop1 and bitop2. Statement is vectorized as
13356 : : BITOP2 (rhs1 BITOP1 rhs2) or
13357 : : rhs1 BITOP2 (BITOP1 rhs2)
13358 : : depending on bitop1 and bitop2 arity. */
13359 : 131188 : bool swap_p = false;
13360 : 131188 : if (VECTOR_BOOLEAN_TYPE_P (vectype))
13361 : : {
13362 : 707 : if (code == GT_EXPR)
13363 : : {
13364 : : bitop1 = BIT_NOT_EXPR;
13365 : : bitop2 = BIT_AND_EXPR;
13366 : : }
13367 : : else if (code == GE_EXPR)
13368 : : {
13369 : : bitop1 = BIT_NOT_EXPR;
13370 : : bitop2 = BIT_IOR_EXPR;
13371 : : }
13372 : : else if (code == LT_EXPR)
13373 : : {
13374 : : bitop1 = BIT_NOT_EXPR;
13375 : : bitop2 = BIT_AND_EXPR;
13376 : : swap_p = true;
13377 : : }
13378 : : else if (code == LE_EXPR)
13379 : : {
13380 : : bitop1 = BIT_NOT_EXPR;
13381 : : bitop2 = BIT_IOR_EXPR;
13382 : : swap_p = true;
13383 : : }
13384 : : else
13385 : : {
13386 : : bitop1 = BIT_XOR_EXPR;
13387 : : if (code == EQ_EXPR)
13388 : : bitop2 = BIT_NOT_EXPR;
13389 : : }
13390 : : }
13391 : :
13392 : 131188 : if (!vec_stmt)
13393 : : {
13394 : 121962 : if (bitop1 == NOP_EXPR)
13395 : : {
13396 : 121374 : if (!expand_vec_cmp_expr_p (vectype, mask_type, code))
13397 : : return false;
13398 : : }
13399 : : else
13400 : : {
13401 : 588 : machine_mode mode = TYPE_MODE (vectype);
13402 : 588 : optab optab;
13403 : :
13404 : 588 : optab = optab_for_tree_code (bitop1, vectype, optab_default);
13405 : 588 : if (!optab || !can_implement_p (optab, mode))
13406 : 0 : return false;
13407 : :
13408 : 588 : if (bitop2 != NOP_EXPR)
13409 : : {
13410 : 77 : optab = optab_for_tree_code (bitop2, vectype, optab_default);
13411 : 77 : if (!optab || !can_implement_p (optab, mode))
13412 : 0 : return false;
13413 : : }
13414 : : }
13415 : :
13416 : : /* Put types on constant and invariant SLP children. */
13417 : 116794 : if (slp_node
13418 : 116794 : && (!vect_maybe_update_slp_op_vectype (slp_rhs1, vectype)
13419 : 116794 : || !vect_maybe_update_slp_op_vectype (slp_rhs2, vectype)))
13420 : : {
13421 : 0 : if (dump_enabled_p ())
13422 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
13423 : : "incompatible vector types for invariants\n");
13424 : 0 : return false;
13425 : : }
13426 : :
13427 : 233588 : vect_model_simple_cost (vinfo, stmt_info,
13428 : 116794 : ncopies * (1 + (bitop2 != NOP_EXPR)),
13429 : : dts, ndts, slp_node, cost_vec);
13430 : 116794 : return true;
13431 : : }
13432 : :
13433 : : /* Transform. */
13434 : :
13435 : : /* Handle def. */
13436 : 9226 : lhs = gimple_get_lhs (STMT_VINFO_STMT (stmt_info));
13437 : 9226 : if (lhs)
13438 : 9226 : mask = vect_create_destination_var (lhs, mask_type);
13439 : :
13440 : 9226 : vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
13441 : : rhs1, vectype, &vec_oprnds0,
13442 : : rhs2, vectype, &vec_oprnds1);
13443 : 9226 : if (swap_p)
13444 : 26 : std::swap (vec_oprnds0, vec_oprnds1);
13445 : :
13446 : : /* Arguments are ready. Create the new vector stmt. */
13447 : 21618 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_rhs1)
13448 : : {
13449 : 12392 : gimple *new_stmt;
13450 : 12392 : vec_rhs2 = vec_oprnds1[i];
13451 : :
13452 : 12392 : if (lhs)
13453 : 12392 : new_temp = make_ssa_name (mask);
13454 : : else
13455 : 0 : new_temp = make_temp_ssa_name (mask_type, NULL, "cmp");
13456 : 12392 : if (bitop1 == NOP_EXPR)
13457 : : {
13458 : 12267 : new_stmt = gimple_build_assign (new_temp, code,
13459 : : vec_rhs1, vec_rhs2);
13460 : 12267 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
13461 : : }
13462 : : else
13463 : : {
13464 : 125 : if (bitop1 == BIT_NOT_EXPR)
13465 : 54 : new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs2);
13466 : : else
13467 : 71 : new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs1,
13468 : : vec_rhs2);
13469 : 125 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
13470 : 125 : if (bitop2 != NOP_EXPR)
13471 : : {
13472 : 54 : tree res = make_ssa_name (mask);
13473 : 54 : if (bitop2 == BIT_NOT_EXPR)
13474 : 0 : new_stmt = gimple_build_assign (res, bitop2, new_temp);
13475 : : else
13476 : 54 : new_stmt = gimple_build_assign (res, bitop2, vec_rhs1,
13477 : : new_temp);
13478 : 54 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
13479 : : }
13480 : : }
13481 : 12392 : if (slp_node)
13482 : 12392 : slp_node->push_vec_def (new_stmt);
13483 : : else
13484 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
13485 : : }
13486 : :
13487 : 9226 : if (!slp_node)
13488 : 0 : *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
13489 : :
13490 : 9226 : vec_oprnds0.release ();
13491 : 9226 : vec_oprnds1.release ();
13492 : :
13493 : 9226 : return true;
13494 : : }
13495 : :
13496 : : /* vectorizable_comparison.
13497 : :
13498 : : Check if STMT_INFO is comparison expression that can be vectorized.
13499 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
13500 : : comparison, put it in VEC_STMT, and insert it at GSI.
13501 : :
13502 : : Return true if STMT_INFO is vectorizable in this way. */
13503 : :
13504 : : static bool
13505 : 406540 : vectorizable_comparison (vec_info *vinfo,
13506 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
13507 : : gimple **vec_stmt,
13508 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
13509 : : {
13510 : 406540 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
13511 : :
13512 : 406540 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
13513 : : return false;
13514 : :
13515 : 406540 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
13516 : : return false;
13517 : :
13518 : 602929 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
13519 : 320386 : if (!stmt)
13520 : : return false;
13521 : :
13522 : 320386 : enum tree_code code = gimple_assign_rhs_code (stmt);
13523 : 320386 : tree vectype = STMT_VINFO_VECTYPE (stmt_info);
13524 : 320386 : if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
13525 : : vec_stmt, slp_node, cost_vec))
13526 : : return false;
13527 : :
13528 : 123997 : if (!vec_stmt)
13529 : 114771 : STMT_VINFO_TYPE (stmt_info) = comparison_vec_info_type;
13530 : :
13531 : : return true;
13532 : : }
13533 : :
13534 : : /* Check to see if the current early break given in STMT_INFO is valid for
13535 : : vectorization. */
13536 : :
13537 : : bool
13538 : 285246 : vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
13539 : : gimple_stmt_iterator *gsi, gimple **vec_stmt,
13540 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
13541 : : {
13542 : 285246 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
13543 : 214210 : if (!loop_vinfo
13544 : 214210 : || !is_a <gcond *> (STMT_VINFO_STMT (stmt_info)))
13545 : : return false;
13546 : :
13547 : 54057 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_condition_def)
13548 : : return false;
13549 : :
13550 : 54057 : if (!STMT_VINFO_RELEVANT_P (stmt_info))
13551 : : return false;
13552 : :
13553 : 54057 : DUMP_VECT_SCOPE ("vectorizable_early_exit");
13554 : :
13555 : 54057 : auto code = gimple_cond_code (STMT_VINFO_STMT (stmt_info));
13556 : :
13557 : 54057 : tree vectype = NULL_TREE;
13558 : 54057 : slp_tree slp_op0;
13559 : 54057 : tree op0;
13560 : 54057 : enum vect_def_type dt0;
13561 : :
13562 : : /* Early break gcond kind SLP trees can be root only and have no children,
13563 : : for instance in the case where the argument is an external. If that's
13564 : : the case there is no operand to analyse use of. */
13565 : 54057 : if ((!slp_node || !SLP_TREE_CHILDREN (slp_node).is_empty ())
13566 : 108114 : && !vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &op0, &slp_op0, &dt0,
13567 : : &vectype))
13568 : : {
13569 : 0 : if (dump_enabled_p ())
13570 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
13571 : : "use not simple.\n");
13572 : 0 : return false;
13573 : : }
13574 : :
13575 : : /* For SLP we don't want to use the type of the operands of the SLP node, when
13576 : : vectorizing using SLP slp_node will be the children of the gcond and we
13577 : : want to use the type of the direct children which since the gcond is root
13578 : : will be the current node, rather than a child node as vect_is_simple_use
13579 : : assumes. */
13580 : 54057 : if (slp_node)
13581 : 54057 : vectype = SLP_TREE_VECTYPE (slp_node);
13582 : :
13583 : 54057 : if (!vectype)
13584 : : return false;
13585 : :
13586 : 54057 : machine_mode mode = TYPE_MODE (vectype);
13587 : 54057 : int ncopies, vec_num;
13588 : :
13589 : 54057 : if (slp_node)
13590 : : {
13591 : 54057 : ncopies = 1;
13592 : 54057 : vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
13593 : : }
13594 : : else
13595 : : {
13596 : 0 : ncopies = vect_get_num_copies (loop_vinfo, vectype);
13597 : 0 : vec_num = 1;
13598 : : }
13599 : :
13600 : 54057 : vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
13601 : 54057 : vec_loop_lens *lens = &LOOP_VINFO_LENS (loop_vinfo);
13602 : 54057 : bool masked_loop_p = LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
13603 : 54057 : bool len_loop_p = LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
13604 : :
13605 : : /* Now build the new conditional. Pattern gimple_conds get dropped during
13606 : : codegen so we must replace the original insn. */
13607 : 54057 : gimple *orig_stmt = STMT_VINFO_STMT (vect_orig_stmt (stmt_info));
13608 : 54057 : gcond *cond_stmt = as_a <gcond *>(orig_stmt);
13609 : : /* When vectorizing we assume that if the branch edge is taken that we're
13610 : : exiting the loop. This is not however always the case as the compiler will
13611 : : rewrite conditions to always be a comparison against 0. To do this it
13612 : : sometimes flips the edges. This is fine for scalar, but for vector we
13613 : : then have to flip the test, as we're still assuming that if you take the
13614 : : branch edge that we found the exit condition. i.e. we need to know whether
13615 : : we are generating a `forall` or an `exist` condition. */
13616 : 54057 : auto new_code = NE_EXPR;
13617 : 54057 : auto reduc_optab = ior_optab;
13618 : 54057 : auto reduc_op = BIT_IOR_EXPR;
13619 : 54057 : tree cst = build_zero_cst (vectype);
13620 : 54057 : edge exit_true_edge = EDGE_SUCC (gimple_bb (cond_stmt), 0);
13621 : 54057 : if (exit_true_edge->flags & EDGE_FALSE_VALUE)
13622 : 586 : exit_true_edge = EDGE_SUCC (gimple_bb (cond_stmt), 1);
13623 : 54057 : gcc_assert (exit_true_edge->flags & EDGE_TRUE_VALUE);
13624 : 54057 : if (flow_bb_inside_loop_p (LOOP_VINFO_LOOP (loop_vinfo),
13625 : 54057 : exit_true_edge->dest))
13626 : : {
13627 : 2981 : new_code = EQ_EXPR;
13628 : 2981 : reduc_optab = and_optab;
13629 : 2981 : reduc_op = BIT_AND_EXPR;
13630 : 2981 : cst = build_minus_one_cst (vectype);
13631 : : }
13632 : :
13633 : : /* Analyze only. */
13634 : 54057 : if (!vec_stmt)
13635 : : {
13636 : 52529 : if (direct_optab_handler (cbranch_optab, mode) == CODE_FOR_nothing)
13637 : : {
13638 : 50506 : if (dump_enabled_p ())
13639 : 570 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
13640 : : "can't vectorize early exit because the "
13641 : : "target doesn't support flag setting vector "
13642 : : "comparisons.\n");
13643 : 50506 : return false;
13644 : : }
13645 : :
13646 : 2023 : if (ncopies > 1
13647 : 2023 : && direct_optab_handler (reduc_optab, mode) == CODE_FOR_nothing)
13648 : : {
13649 : 0 : if (dump_enabled_p ())
13650 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
13651 : : "can't vectorize early exit because the "
13652 : : "target does not support boolean vector %s "
13653 : : "for type %T.\n",
13654 : : reduc_optab == ior_optab ? "OR" : "AND",
13655 : : vectype);
13656 : 0 : return false;
13657 : : }
13658 : :
13659 : 2023 : if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
13660 : : vec_stmt, slp_node, cost_vec))
13661 : : return false;
13662 : :
13663 : 2023 : if (LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
13664 : : {
13665 : 1 : if (direct_internal_fn_supported_p (IFN_VCOND_MASK_LEN, vectype,
13666 : : OPTIMIZE_FOR_SPEED))
13667 : 0 : vect_record_loop_len (loop_vinfo, lens, ncopies * vec_num,
13668 : : vectype, 1);
13669 : : else
13670 : 1 : vect_record_loop_mask (loop_vinfo, masks, ncopies * vec_num,
13671 : : vectype, NULL);
13672 : : }
13673 : :
13674 : 2023 : return true;
13675 : : }
13676 : :
13677 : : /* Tranform. */
13678 : :
13679 : 1528 : tree new_temp = NULL_TREE;
13680 : 1528 : gimple *new_stmt = NULL;
13681 : :
13682 : 1528 : if (dump_enabled_p ())
13683 : 339 : dump_printf_loc (MSG_NOTE, vect_location, "transform early-exit.\n");
13684 : :
13685 : : /* For SLP we don't do codegen of the body starting from the gcond, the gconds are
13686 : : roots and so by the time we get to them we have already codegened the SLP tree
13687 : : and so we shouldn't try to do so again. The arguments have already been
13688 : : vectorized. It's not very clean to do this here, But the masking code below is
13689 : : complex and this keeps it all in one place to ease fixes and backports. Once we
13690 : : drop the non-SLP loop vect or split vectorizable_* this can be simplified. */
13691 : 1528 : if (!slp_node)
13692 : : {
13693 : 0 : if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
13694 : : vec_stmt, slp_node, cost_vec))
13695 : 0 : gcc_unreachable ();
13696 : : }
13697 : :
13698 : 1528 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
13699 : 1528 : basic_block cond_bb = gimple_bb (stmt);
13700 : 1528 : gimple_stmt_iterator cond_gsi = gsi_last_bb (cond_bb);
13701 : :
13702 : 1528 : auto_vec<tree> stmts;
13703 : :
13704 : 1528 : if (slp_node)
13705 : 1528 : stmts.safe_splice (SLP_TREE_VEC_DEFS (slp_node));
13706 : : else
13707 : : {
13708 : 0 : auto vec_stmts = STMT_VINFO_VEC_STMTS (stmt_info);
13709 : 0 : stmts.reserve_exact (vec_stmts.length ());
13710 : 0 : for (auto stmt : vec_stmts)
13711 : 0 : stmts.quick_push (gimple_assign_lhs (stmt));
13712 : : }
13713 : :
13714 : : /* Determine if we need to reduce the final value. */
13715 : 1528 : if (stmts.length () > 1)
13716 : : {
13717 : : /* We build the reductions in a way to maintain as much parallelism as
13718 : : possible. */
13719 : 365 : auto_vec<tree> workset (stmts.length ());
13720 : :
13721 : : /* Mask the statements as we queue them up. Normally we loop over
13722 : : vec_num, but since we inspect the exact results of vectorization
13723 : : we don't need to and instead can just use the stmts themselves. */
13724 : 365 : if (masked_loop_p)
13725 : 0 : for (unsigned i = 0; i < stmts.length (); i++)
13726 : : {
13727 : 0 : tree stmt_mask
13728 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies * vec_num,
13729 : : vectype, i);
13730 : 0 : stmt_mask
13731 : 0 : = prepare_vec_mask (loop_vinfo, TREE_TYPE (stmt_mask), stmt_mask,
13732 : 0 : stmts[i], &cond_gsi);
13733 : 0 : workset.quick_push (stmt_mask);
13734 : : }
13735 : 365 : else if (len_loop_p)
13736 : 0 : for (unsigned i = 0; i < stmts.length (); i++)
13737 : : {
13738 : 0 : tree len_mask = vect_gen_loop_len_mask (loop_vinfo, gsi, &cond_gsi,
13739 : 0 : lens, ncopies * vec_num,
13740 : 0 : vectype, stmts[i], i, 1);
13741 : :
13742 : 0 : workset.quick_push (len_mask);
13743 : : }
13744 : : else
13745 : 365 : workset.splice (stmts);
13746 : :
13747 : 860 : while (workset.length () > 1)
13748 : : {
13749 : 495 : new_temp = make_temp_ssa_name (vectype, NULL, "vexit_reduc");
13750 : 495 : tree arg0 = workset.pop ();
13751 : 495 : tree arg1 = workset.pop ();
13752 : 495 : new_stmt = gimple_build_assign (new_temp, reduc_op, arg0, arg1);
13753 : 495 : vect_finish_stmt_generation (loop_vinfo, stmt_info, new_stmt,
13754 : : &cond_gsi);
13755 : 495 : workset.quick_insert (0, new_temp);
13756 : : }
13757 : 365 : }
13758 : : else
13759 : : {
13760 : 1163 : new_temp = stmts[0];
13761 : 1163 : if (masked_loop_p)
13762 : : {
13763 : 0 : tree mask
13764 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies, vectype, 0);
13765 : 0 : new_temp = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
13766 : : new_temp, &cond_gsi);
13767 : : }
13768 : 1163 : else if (len_loop_p)
13769 : 0 : new_temp = vect_gen_loop_len_mask (loop_vinfo, gsi, &cond_gsi, lens,
13770 : : ncopies, vectype, new_temp, 0, 1);
13771 : : }
13772 : :
13773 : 1528 : gcc_assert (new_temp);
13774 : :
13775 : 1528 : gimple_cond_set_condition (cond_stmt, new_code, new_temp, cst);
13776 : 1528 : update_stmt (orig_stmt);
13777 : :
13778 : 1528 : if (slp_node)
13779 : 1528 : SLP_TREE_VEC_DEFS (slp_node).truncate (0);
13780 : : else
13781 : 0 : STMT_VINFO_VEC_STMTS (stmt_info).truncate (0);
13782 : :
13783 : 1528 : if (!slp_node)
13784 : 0 : *vec_stmt = orig_stmt;
13785 : :
13786 : 1528 : return true;
13787 : 1528 : }
13788 : :
13789 : : /* If SLP_NODE is nonnull, return true if vectorizable_live_operation
13790 : : can handle all live statements in the node. Otherwise return true
13791 : : if STMT_INFO is not live or if vectorizable_live_operation can handle it.
13792 : : VEC_STMT_P is as for vectorizable_live_operation. */
13793 : :
13794 : : static bool
13795 : 1376095 : can_vectorize_live_stmts (vec_info *vinfo, stmt_vec_info stmt_info,
13796 : : slp_tree slp_node, slp_instance slp_node_instance,
13797 : : bool vec_stmt_p,
13798 : : stmt_vector_for_cost *cost_vec)
13799 : : {
13800 : 1376095 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
13801 : 1376095 : if (slp_node)
13802 : : {
13803 : : stmt_vec_info slp_stmt_info;
13804 : : unsigned int i;
13805 : 3097837 : FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (slp_node), i, slp_stmt_info)
13806 : : {
13807 : 1721742 : if (slp_stmt_info
13808 : 1701514 : && (STMT_VINFO_LIVE_P (slp_stmt_info)
13809 : 1513405 : || (loop_vinfo
13810 : 1257579 : && LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
13811 : 222282 : && STMT_VINFO_DEF_TYPE (slp_stmt_info)
13812 : : == vect_induction_def))
13813 : 1909851 : && !vectorizable_live_operation (vinfo, slp_stmt_info, slp_node,
13814 : : slp_node_instance, i,
13815 : : vec_stmt_p, cost_vec))
13816 : 0 : return false;
13817 : : }
13818 : : }
13819 : 0 : else if ((STMT_VINFO_LIVE_P (stmt_info)
13820 : 0 : || (LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
13821 : 0 : && STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def))
13822 : 0 : && !vectorizable_live_operation (vinfo, stmt_info,
13823 : : slp_node, slp_node_instance, -1,
13824 : : vec_stmt_p, cost_vec))
13825 : : return false;
13826 : :
13827 : : return true;
13828 : : }
13829 : :
13830 : : /* Make sure the statement is vectorizable. */
13831 : :
13832 : : opt_result
13833 : 3577000 : vect_analyze_stmt (vec_info *vinfo,
13834 : : stmt_vec_info stmt_info, bool *need_to_vectorize,
13835 : : slp_tree node, slp_instance node_instance,
13836 : : stmt_vector_for_cost *cost_vec)
13837 : : {
13838 : 3577000 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
13839 : 3577000 : enum vect_relevant relevance = STMT_VINFO_RELEVANT (stmt_info);
13840 : 3577000 : bool ok;
13841 : 3577000 : gimple_seq pattern_def_seq;
13842 : :
13843 : 3577000 : if (dump_enabled_p ())
13844 : 282339 : dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: %G",
13845 : : stmt_info->stmt);
13846 : :
13847 : 6806478 : if (gimple_has_volatile_ops (stmt_info->stmt))
13848 : 0 : return opt_result::failure_at (stmt_info->stmt,
13849 : : "not vectorized:"
13850 : : " stmt has volatile operands: %G\n",
13851 : : stmt_info->stmt);
13852 : :
13853 : 3577000 : if (STMT_VINFO_IN_PATTERN_P (stmt_info)
13854 : 41342 : && node == NULL
13855 : 3618342 : && (pattern_def_seq = STMT_VINFO_PATTERN_DEF_SEQ (stmt_info)))
13856 : : {
13857 : : gimple_stmt_iterator si;
13858 : :
13859 : 83186 : for (si = gsi_start (pattern_def_seq); !gsi_end_p (si); gsi_next (&si))
13860 : : {
13861 : 48596 : stmt_vec_info pattern_def_stmt_info
13862 : 48596 : = vinfo->lookup_stmt (gsi_stmt (si));
13863 : 48596 : if (STMT_VINFO_RELEVANT_P (pattern_def_stmt_info)
13864 : 19819 : || STMT_VINFO_LIVE_P (pattern_def_stmt_info))
13865 : : {
13866 : : /* Analyze def stmt of STMT if it's a pattern stmt. */
13867 : 28777 : if (dump_enabled_p ())
13868 : 10250 : dump_printf_loc (MSG_NOTE, vect_location,
13869 : : "==> examining pattern def statement: %G",
13870 : : pattern_def_stmt_info->stmt);
13871 : :
13872 : 28777 : opt_result res
13873 : 28777 : = vect_analyze_stmt (vinfo, pattern_def_stmt_info,
13874 : : need_to_vectorize, node, node_instance,
13875 : : cost_vec);
13876 : 28777 : if (!res)
13877 : 4 : return res;
13878 : : }
13879 : : }
13880 : : }
13881 : :
13882 : : /* Skip stmts that do not need to be vectorized. In loops this is expected
13883 : : to include:
13884 : : - the COND_EXPR which is the loop exit condition
13885 : : - any LABEL_EXPRs in the loop
13886 : : - computations that are used only for array indexing or loop control.
13887 : : In basic blocks we only analyze statements that are a part of some SLP
13888 : : instance, therefore, all the statements are relevant.
13889 : :
13890 : : Pattern statement needs to be analyzed instead of the original statement
13891 : : if the original statement is not relevant. Otherwise, we analyze both
13892 : : statements. In basic blocks we are called from some SLP instance
13893 : : traversal, don't analyze pattern stmts instead, the pattern stmts
13894 : : already will be part of SLP instance. */
13895 : :
13896 : 3576996 : stmt_vec_info pattern_stmt_info = STMT_VINFO_RELATED_STMT (stmt_info);
13897 : 3576996 : if (!STMT_VINFO_RELEVANT_P (stmt_info)
13898 : 690433 : && !STMT_VINFO_LIVE_P (stmt_info))
13899 : : {
13900 : 690409 : if (STMT_VINFO_IN_PATTERN_P (stmt_info)
13901 : 41338 : && pattern_stmt_info
13902 : 41338 : && (STMT_VINFO_RELEVANT_P (pattern_stmt_info)
13903 : 24828 : || STMT_VINFO_LIVE_P (pattern_stmt_info)))
13904 : : {
13905 : : /* Analyze PATTERN_STMT instead of the original stmt. */
13906 : 16510 : stmt_info = pattern_stmt_info;
13907 : 16510 : if (dump_enabled_p ())
13908 : 4344 : dump_printf_loc (MSG_NOTE, vect_location,
13909 : : "==> examining pattern statement: %G",
13910 : : stmt_info->stmt);
13911 : : }
13912 : : else
13913 : : {
13914 : 673899 : if (dump_enabled_p ())
13915 : 77314 : dump_printf_loc (MSG_NOTE, vect_location, "irrelevant.\n");
13916 : :
13917 : 673899 : if (node)
13918 : 0 : return opt_result::failure_at (stmt_info->stmt,
13919 : : "not vectorized:"
13920 : : " irrelevant stmt as SLP node %p "
13921 : : "representative.\n",
13922 : : (void *)node);
13923 : 673899 : return opt_result::success ();
13924 : : }
13925 : : }
13926 : 2886587 : else if (STMT_VINFO_IN_PATTERN_P (stmt_info)
13927 : 0 : && node == NULL
13928 : 0 : && pattern_stmt_info
13929 : 0 : && (STMT_VINFO_RELEVANT_P (pattern_stmt_info)
13930 : 0 : || STMT_VINFO_LIVE_P (pattern_stmt_info)))
13931 : : {
13932 : : /* Analyze PATTERN_STMT too. */
13933 : 0 : if (dump_enabled_p ())
13934 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
13935 : : "==> examining pattern statement: %G",
13936 : : pattern_stmt_info->stmt);
13937 : :
13938 : 0 : opt_result res
13939 : 0 : = vect_analyze_stmt (vinfo, pattern_stmt_info, need_to_vectorize, node,
13940 : : node_instance, cost_vec);
13941 : 0 : if (!res)
13942 : 0 : return res;
13943 : : }
13944 : :
13945 : 2903097 : switch (STMT_VINFO_DEF_TYPE (stmt_info))
13946 : : {
13947 : : case vect_internal_def:
13948 : : case vect_condition_def:
13949 : : break;
13950 : :
13951 : 66909 : case vect_reduction_def:
13952 : 66909 : case vect_nested_cycle:
13953 : 66909 : gcc_assert (!bb_vinfo
13954 : : && (relevance == vect_used_in_outer
13955 : : || relevance == vect_used_in_outer_by_reduction
13956 : : || relevance == vect_used_by_reduction
13957 : : || relevance == vect_unused_in_scope
13958 : : || relevance == vect_used_only_live));
13959 : : break;
13960 : :
13961 : 382 : case vect_double_reduction_def:
13962 : 382 : gcc_assert (!bb_vinfo && node);
13963 : : break;
13964 : :
13965 : 126561 : case vect_induction_def:
13966 : 126561 : case vect_first_order_recurrence:
13967 : 126561 : gcc_assert (!bb_vinfo);
13968 : : break;
13969 : :
13970 : 0 : case vect_constant_def:
13971 : 0 : case vect_external_def:
13972 : 0 : case vect_unknown_def_type:
13973 : 0 : default:
13974 : 0 : gcc_unreachable ();
13975 : : }
13976 : :
13977 : 2903097 : tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info);
13978 : 2903097 : if (node)
13979 : 2305406 : STMT_VINFO_VECTYPE (stmt_info) = SLP_TREE_VECTYPE (node);
13980 : :
13981 : 2903097 : if (STMT_VINFO_RELEVANT_P (stmt_info))
13982 : : {
13983 : 2903073 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
13984 : 2903073 : gcc_assert (STMT_VINFO_VECTYPE (stmt_info)
13985 : : || gimple_code (stmt_info->stmt) == GIMPLE_COND
13986 : : || (call && gimple_call_lhs (call) == NULL_TREE));
13987 : 2903073 : *need_to_vectorize = true;
13988 : : }
13989 : :
13990 : 2903097 : if (PURE_SLP_STMT (stmt_info) && !node)
13991 : : {
13992 : 597073 : if (dump_enabled_p ())
13993 : 96453 : dump_printf_loc (MSG_NOTE, vect_location,
13994 : : "handled only by SLP analysis\n");
13995 : 597073 : return opt_result::success ();
13996 : : }
13997 : :
13998 : : /* When we arrive here with a non-SLP statement and we are supposed
13999 : : to use SLP for everything fail vectorization. */
14000 : 7348 : if (!node && param_vect_force_slp)
14001 : 618 : return opt_result::failure_at (stmt_info->stmt,
14002 : : "needs non-SLP handling\n");
14003 : :
14004 : 2305406 : ok = true;
14005 : 2305406 : if (!bb_vinfo
14006 : 1169693 : && (STMT_VINFO_RELEVANT_P (stmt_info)
14007 : 0 : || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def))
14008 : : /* Prefer vectorizable_call over vectorizable_simd_clone_call so
14009 : : -mveclibabi= takes preference over library functions with
14010 : : the simd attribute. */
14011 : 1169693 : ok = (vectorizable_call (vinfo, stmt_info, NULL, NULL, node, cost_vec)
14012 : 1164881 : || vectorizable_simd_clone_call (vinfo, stmt_info, NULL, NULL, node,
14013 : : cost_vec)
14014 : 1164413 : || vectorizable_conversion (vinfo, stmt_info,
14015 : : NULL, NULL, node, cost_vec)
14016 : 1114279 : || vectorizable_operation (vinfo, stmt_info,
14017 : : NULL, NULL, node, cost_vec)
14018 : 855003 : || vectorizable_assignment (vinfo, stmt_info,
14019 : : NULL, NULL, node, cost_vec)
14020 : 820162 : || vectorizable_load (vinfo, stmt_info, NULL, NULL, node, cost_vec)
14021 : 561844 : || vectorizable_store (vinfo, stmt_info, NULL, NULL, node, cost_vec)
14022 : 434500 : || vectorizable_lane_reducing (as_a <loop_vec_info> (vinfo),
14023 : : stmt_info, node, cost_vec)
14024 : 434086 : || vectorizable_reduction (as_a <loop_vec_info> (vinfo), stmt_info,
14025 : : node, node_instance, cost_vec)
14026 : 376398 : || vectorizable_induction (as_a <loop_vec_info> (vinfo), stmt_info,
14027 : : NULL, node, cost_vec)
14028 : 275625 : || vectorizable_shift (vinfo, stmt_info, NULL, NULL, node, cost_vec)
14029 : 260927 : || vectorizable_condition (vinfo, stmt_info,
14030 : : NULL, NULL, node, cost_vec)
14031 : 243738 : || vectorizable_comparison (vinfo, stmt_info, NULL, NULL, node,
14032 : : cost_vec)
14033 : 161160 : || vectorizable_lc_phi (as_a <loop_vec_info> (vinfo),
14034 : : stmt_info, NULL, node)
14035 : 160351 : || vectorizable_recurr (as_a <loop_vec_info> (vinfo),
14036 : : stmt_info, NULL, node, cost_vec)
14037 : 1329846 : || vectorizable_early_exit (vinfo, stmt_info, NULL, NULL, node,
14038 : : cost_vec));
14039 : : else
14040 : : {
14041 : : if (bb_vinfo)
14042 : 1135713 : ok = (vectorizable_call (vinfo, stmt_info, NULL, NULL, node, cost_vec)
14043 : 1135297 : || vectorizable_simd_clone_call (vinfo, stmt_info,
14044 : : NULL, NULL, node, cost_vec)
14045 : 1135296 : || vectorizable_conversion (vinfo, stmt_info, NULL, NULL, node,
14046 : : cost_vec)
14047 : 1126787 : || vectorizable_shift (vinfo, stmt_info,
14048 : : NULL, NULL, node, cost_vec)
14049 : 1106821 : || vectorizable_operation (vinfo, stmt_info,
14050 : : NULL, NULL, node, cost_vec)
14051 : 960925 : || vectorizable_assignment (vinfo, stmt_info, NULL, NULL, node,
14052 : : cost_vec)
14053 : 946428 : || vectorizable_load (vinfo, stmt_info,
14054 : : NULL, NULL, node, cost_vec)
14055 : 804558 : || vectorizable_store (vinfo, stmt_info,
14056 : : NULL, NULL, node, cost_vec)
14057 : 154196 : || vectorizable_condition (vinfo, stmt_info,
14058 : : NULL, NULL, node, cost_vec)
14059 : 153576 : || vectorizable_comparison (vinfo, stmt_info, NULL, NULL, node,
14060 : : cost_vec)
14061 : 121383 : || vectorizable_phi (vinfo, stmt_info, NULL, node, cost_vec)
14062 : 1206749 : || vectorizable_early_exit (vinfo, stmt_info, NULL, NULL, node,
14063 : : cost_vec));
14064 : :
14065 : : }
14066 : :
14067 : 2305406 : if (node)
14068 : 2305406 : STMT_VINFO_VECTYPE (stmt_info) = saved_vectype;
14069 : :
14070 : 2305406 : if (!ok)
14071 : 231189 : return opt_result::failure_at (stmt_info->stmt,
14072 : : "not vectorized:"
14073 : : " relevant stmt not supported: %G",
14074 : : stmt_info->stmt);
14075 : :
14076 : : /* Stmts that are (also) "live" (i.e. - that are used out of the loop)
14077 : : need extra handling, except for vectorizable reductions. */
14078 : 2074217 : if (!bb_vinfo
14079 : 1009540 : && STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type
14080 : 1002665 : && STMT_VINFO_TYPE (stmt_info) != lc_phi_info_type
14081 : 1001856 : && (!node || !node->ldst_lanes || SLP_TREE_CODE (node) == VEC_PERM_EXPR)
14082 : 3076073 : && !can_vectorize_live_stmts (as_a <loop_vec_info> (vinfo),
14083 : : stmt_info, node, node_instance,
14084 : : false, cost_vec))
14085 : 0 : return opt_result::failure_at (stmt_info->stmt,
14086 : : "not vectorized:"
14087 : : " live stmt not supported: %G",
14088 : : stmt_info->stmt);
14089 : :
14090 : 2074217 : return opt_result::success ();
14091 : : }
14092 : :
14093 : :
14094 : : /* Function vect_transform_stmt.
14095 : :
14096 : : Create a vectorized stmt to replace STMT_INFO, and insert it at GSI. */
14097 : :
14098 : : bool
14099 : 908730 : vect_transform_stmt (vec_info *vinfo,
14100 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
14101 : : slp_tree slp_node, slp_instance slp_node_instance)
14102 : : {
14103 : 908730 : bool is_store = false;
14104 : 908730 : gimple *vec_stmt = NULL;
14105 : 908730 : bool done;
14106 : :
14107 : 908730 : gcc_assert (slp_node || !PURE_SLP_STMT (stmt_info));
14108 : :
14109 : 908730 : tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info);
14110 : 0 : if (slp_node)
14111 : 908730 : STMT_VINFO_VECTYPE (stmt_info) = SLP_TREE_VECTYPE (slp_node);
14112 : :
14113 : 908730 : switch (STMT_VINFO_TYPE (stmt_info))
14114 : : {
14115 : 19116 : case type_demotion_vec_info_type:
14116 : 19116 : case type_promotion_vec_info_type:
14117 : 19116 : case type_conversion_vec_info_type:
14118 : 19116 : done = vectorizable_conversion (vinfo, stmt_info,
14119 : : gsi, &vec_stmt, slp_node, NULL);
14120 : 19116 : gcc_assert (done);
14121 : : break;
14122 : :
14123 : 15626 : case induc_vec_info_type:
14124 : 15626 : done = vectorizable_induction (as_a <loop_vec_info> (vinfo),
14125 : : stmt_info, &vec_stmt, slp_node,
14126 : : NULL);
14127 : 15626 : gcc_assert (done);
14128 : : break;
14129 : :
14130 : 5731 : case shift_vec_info_type:
14131 : 5731 : done = vectorizable_shift (vinfo, stmt_info,
14132 : : gsi, &vec_stmt, slp_node, NULL);
14133 : 5731 : gcc_assert (done);
14134 : : break;
14135 : :
14136 : 107477 : case op_vec_info_type:
14137 : 107477 : done = vectorizable_operation (vinfo, stmt_info, gsi, &vec_stmt, slp_node,
14138 : : NULL);
14139 : 107477 : gcc_assert (done);
14140 : : break;
14141 : :
14142 : 14048 : case assignment_vec_info_type:
14143 : 14048 : done = vectorizable_assignment (vinfo, stmt_info,
14144 : : gsi, &vec_stmt, slp_node, NULL);
14145 : 14048 : gcc_assert (done);
14146 : : break;
14147 : :
14148 : 154699 : case load_vec_info_type:
14149 : 154699 : done = vectorizable_load (vinfo, stmt_info, gsi, &vec_stmt, slp_node,
14150 : : NULL);
14151 : 154699 : gcc_assert (done);
14152 : : break;
14153 : :
14154 : 534491 : case store_vec_info_type:
14155 : 534491 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info)
14156 : 484063 : && !slp_node
14157 : 534491 : && (++DR_GROUP_STORE_COUNT (DR_GROUP_FIRST_ELEMENT (stmt_info))
14158 : 0 : < DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info))))
14159 : : /* In case of interleaving, the whole chain is vectorized when the
14160 : : last store in the chain is reached. Store stmts before the last
14161 : : one are skipped, and there vec_stmt_info shouldn't be freed
14162 : : meanwhile. */
14163 : : ;
14164 : : else
14165 : : {
14166 : 534491 : done = vectorizable_store (vinfo, stmt_info,
14167 : : gsi, &vec_stmt, slp_node, NULL);
14168 : 534491 : gcc_assert (done);
14169 : : is_store = true;
14170 : : }
14171 : : break;
14172 : :
14173 : 6243 : case condition_vec_info_type:
14174 : 6243 : done = vectorizable_condition (vinfo, stmt_info,
14175 : : gsi, &vec_stmt, slp_node, NULL);
14176 : 6243 : gcc_assert (done);
14177 : : break;
14178 : :
14179 : 9226 : case comparison_vec_info_type:
14180 : 9226 : done = vectorizable_comparison (vinfo, stmt_info, gsi, &vec_stmt,
14181 : : slp_node, NULL);
14182 : 9226 : gcc_assert (done);
14183 : : break;
14184 : :
14185 : 3445 : case call_vec_info_type:
14186 : 3445 : done = vectorizable_call (vinfo, stmt_info,
14187 : : gsi, &vec_stmt, slp_node, NULL);
14188 : 3445 : break;
14189 : :
14190 : 314 : case call_simd_clone_vec_info_type:
14191 : 314 : done = vectorizable_simd_clone_call (vinfo, stmt_info, gsi, &vec_stmt,
14192 : : slp_node, NULL);
14193 : 314 : break;
14194 : :
14195 : 2169 : case reduc_vec_info_type:
14196 : 2169 : done = vect_transform_reduction (as_a <loop_vec_info> (vinfo), stmt_info,
14197 : : gsi, &vec_stmt, slp_node);
14198 : 2169 : gcc_assert (done);
14199 : : break;
14200 : :
14201 : 22098 : case cycle_phi_info_type:
14202 : 22098 : done = vect_transform_cycle_phi (as_a <loop_vec_info> (vinfo), stmt_info,
14203 : : &vec_stmt, slp_node, slp_node_instance);
14204 : 22098 : gcc_assert (done);
14205 : : break;
14206 : :
14207 : 340 : case lc_phi_info_type:
14208 : 340 : done = vectorizable_lc_phi (as_a <loop_vec_info> (vinfo),
14209 : : stmt_info, &vec_stmt, slp_node);
14210 : 340 : gcc_assert (done);
14211 : : break;
14212 : :
14213 : 32 : case recurr_info_type:
14214 : 32 : done = vectorizable_recurr (as_a <loop_vec_info> (vinfo),
14215 : : stmt_info, &vec_stmt, slp_node, NULL);
14216 : 32 : gcc_assert (done);
14217 : : break;
14218 : :
14219 : 13675 : case phi_info_type:
14220 : 13675 : done = vectorizable_phi (vinfo, stmt_info, &vec_stmt, slp_node, NULL);
14221 : 13675 : gcc_assert (done);
14222 : : break;
14223 : :
14224 : 0 : case loop_exit_ctrl_vec_info_type:
14225 : 0 : done = vectorizable_early_exit (vinfo, stmt_info, gsi, &vec_stmt,
14226 : : slp_node, NULL);
14227 : 0 : gcc_assert (done);
14228 : : break;
14229 : :
14230 : 0 : default:
14231 : 0 : if (!STMT_VINFO_LIVE_P (stmt_info))
14232 : : {
14233 : 0 : if (dump_enabled_p ())
14234 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
14235 : : "stmt not supported.\n");
14236 : 0 : gcc_unreachable ();
14237 : : }
14238 : 908730 : done = true;
14239 : : }
14240 : :
14241 : 908730 : if (!slp_node && vec_stmt)
14242 : 0 : gcc_assert (STMT_VINFO_VEC_STMTS (stmt_info).exists ());
14243 : :
14244 : 908730 : if (STMT_VINFO_TYPE (stmt_info) != store_vec_info_type
14245 : 374239 : && (!slp_node
14246 : 374239 : || !slp_node->ldst_lanes
14247 : 0 : || SLP_TREE_CODE (slp_node) == VEC_PERM_EXPR))
14248 : : {
14249 : : /* Handle stmts whose DEF is used outside the loop-nest that is
14250 : : being vectorized. */
14251 : 374239 : done = can_vectorize_live_stmts (vinfo, stmt_info, slp_node,
14252 : : slp_node_instance, true, NULL);
14253 : 374239 : gcc_assert (done);
14254 : : }
14255 : :
14256 : 908730 : if (slp_node)
14257 : 908730 : STMT_VINFO_VECTYPE (stmt_info) = saved_vectype;
14258 : :
14259 : 908730 : return is_store;
14260 : : }
14261 : :
14262 : :
14263 : : /* Remove a group of stores (for SLP or interleaving), free their
14264 : : stmt_vec_info. */
14265 : :
14266 : : void
14267 : 0 : vect_remove_stores (vec_info *vinfo, stmt_vec_info first_stmt_info)
14268 : : {
14269 : 0 : stmt_vec_info next_stmt_info = first_stmt_info;
14270 : :
14271 : 0 : while (next_stmt_info)
14272 : : {
14273 : 0 : stmt_vec_info tmp = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
14274 : 0 : next_stmt_info = vect_orig_stmt (next_stmt_info);
14275 : : /* Free the attached stmt_vec_info and remove the stmt. */
14276 : 0 : vinfo->remove_stmt (next_stmt_info);
14277 : 0 : next_stmt_info = tmp;
14278 : : }
14279 : 0 : }
14280 : :
14281 : : /* If NUNITS is nonzero, return a vector type that contains NUNITS
14282 : : elements of type SCALAR_TYPE, or null if the target doesn't support
14283 : : such a type.
14284 : :
14285 : : If NUNITS is zero, return a vector type that contains elements of
14286 : : type SCALAR_TYPE, choosing whichever vector size the target prefers.
14287 : :
14288 : : If PREVAILING_MODE is VOIDmode, we have not yet chosen a vector mode
14289 : : for this vectorization region and want to "autodetect" the best choice.
14290 : : Otherwise, PREVAILING_MODE is a previously-chosen vector TYPE_MODE
14291 : : and we want the new type to be interoperable with it. PREVAILING_MODE
14292 : : in this case can be a scalar integer mode or a vector mode; when it
14293 : : is a vector mode, the function acts like a tree-level version of
14294 : : related_vector_mode. */
14295 : :
14296 : : tree
14297 : 28632195 : get_related_vectype_for_scalar_type (machine_mode prevailing_mode,
14298 : : tree scalar_type, poly_uint64 nunits)
14299 : : {
14300 : 28632195 : tree orig_scalar_type = scalar_type;
14301 : 28632195 : scalar_mode inner_mode;
14302 : 28632195 : machine_mode simd_mode;
14303 : 28632195 : tree vectype;
14304 : :
14305 : 28632195 : if ((!INTEGRAL_TYPE_P (scalar_type)
14306 : 9904097 : && !POINTER_TYPE_P (scalar_type)
14307 : 1647776 : && !SCALAR_FLOAT_TYPE_P (scalar_type))
14308 : 38081917 : || (!is_int_mode (TYPE_MODE (scalar_type), &inner_mode)
14309 : 1193480 : && !is_float_mode (TYPE_MODE (scalar_type), &inner_mode)))
14310 : 458927 : return NULL_TREE;
14311 : :
14312 : 28173268 : unsigned int nbytes = GET_MODE_SIZE (inner_mode);
14313 : :
14314 : : /* Interoperability between modes requires one to be a constant multiple
14315 : : of the other, so that the number of vectors required for each operation
14316 : : is a compile-time constant. */
14317 : 28173268 : if (prevailing_mode != VOIDmode
14318 : 27122210 : && !constant_multiple_p (nunits * nbytes,
14319 : 27122210 : GET_MODE_SIZE (prevailing_mode))
14320 : 29635508 : && !constant_multiple_p (GET_MODE_SIZE (prevailing_mode),
14321 : 1462240 : nunits * nbytes))
14322 : : return NULL_TREE;
14323 : :
14324 : : /* For vector types of elements whose mode precision doesn't
14325 : : match their types precision we use a element type of mode
14326 : : precision. The vectorization routines will have to make sure
14327 : : they support the proper result truncation/extension.
14328 : : We also make sure to build vector types with INTEGER_TYPE
14329 : : component type only. */
14330 : 28173268 : if (INTEGRAL_TYPE_P (scalar_type)
14331 : 46901287 : && (GET_MODE_BITSIZE (inner_mode) != TYPE_PRECISION (scalar_type)
14332 : 16933497 : || TREE_CODE (scalar_type) != INTEGER_TYPE))
14333 : 2014661 : scalar_type = build_nonstandard_integer_type (GET_MODE_BITSIZE (inner_mode),
14334 : 2014661 : TYPE_UNSIGNED (scalar_type));
14335 : :
14336 : : /* We shouldn't end up building VECTOR_TYPEs of non-scalar components.
14337 : : When the component mode passes the above test simply use a type
14338 : : corresponding to that mode. The theory is that any use that
14339 : : would cause problems with this will disable vectorization anyway. */
14340 : 26158607 : else if (!SCALAR_FLOAT_TYPE_P (scalar_type)
14341 : : && !INTEGRAL_TYPE_P (scalar_type))
14342 : 8256321 : scalar_type = lang_hooks.types.type_for_mode (inner_mode, 1);
14343 : :
14344 : : /* We can't build a vector type of elements with alignment bigger than
14345 : : their size. */
14346 : 17902286 : else if (nbytes < TYPE_ALIGN_UNIT (scalar_type))
14347 : 249970 : scalar_type = lang_hooks.types.type_for_mode (inner_mode,
14348 : 124985 : TYPE_UNSIGNED (scalar_type));
14349 : :
14350 : : /* If we felt back to using the mode fail if there was
14351 : : no scalar type for it. */
14352 : 28173268 : if (scalar_type == NULL_TREE)
14353 : : return NULL_TREE;
14354 : :
14355 : : /* If no prevailing mode was supplied, use the mode the target prefers.
14356 : : Otherwise lookup a vector mode based on the prevailing mode. */
14357 : 28173268 : if (prevailing_mode == VOIDmode)
14358 : : {
14359 : 1051058 : gcc_assert (known_eq (nunits, 0U));
14360 : 1051058 : simd_mode = targetm.vectorize.preferred_simd_mode (inner_mode);
14361 : 1051058 : if (SCALAR_INT_MODE_P (simd_mode))
14362 : : {
14363 : : /* Traditional behavior is not to take the integer mode
14364 : : literally, but simply to use it as a way of determining
14365 : : the vector size. It is up to mode_for_vector to decide
14366 : : what the TYPE_MODE should be.
14367 : :
14368 : : Note that nunits == 1 is allowed in order to support single
14369 : : element vector types. */
14370 : 32674 : if (!multiple_p (GET_MODE_SIZE (simd_mode), nbytes, &nunits)
14371 : 340 : || !mode_for_vector (inner_mode, nunits).exists (&simd_mode))
14372 : 15997 : return NULL_TREE;
14373 : : }
14374 : : }
14375 : 27122210 : else if (SCALAR_INT_MODE_P (prevailing_mode)
14376 : 27122210 : || !related_vector_mode (prevailing_mode,
14377 : 25308932 : inner_mode, nunits).exists (&simd_mode))
14378 : : {
14379 : : /* Fall back to using mode_for_vector, mostly in the hope of being
14380 : : able to use an integer mode. */
14381 : 1813278 : if (known_eq (nunits, 0U)
14382 : 4242803 : && !multiple_p (GET_MODE_SIZE (prevailing_mode), nbytes, &nunits))
14383 : : return NULL_TREE;
14384 : :
14385 : 148230 : if (!mode_for_vector (inner_mode, nunits).exists (&simd_mode))
14386 : 138468 : return NULL_TREE;
14387 : : }
14388 : :
14389 : 26353755 : vectype = build_vector_type_for_mode (scalar_type, simd_mode);
14390 : :
14391 : : /* In cases where the mode was chosen by mode_for_vector, check that
14392 : : the target actually supports the chosen mode, or that it at least
14393 : : allows the vector mode to be replaced by a like-sized integer. */
14394 : 52707510 : if (!VECTOR_MODE_P (TYPE_MODE (vectype))
14395 : 26363765 : && !INTEGRAL_MODE_P (TYPE_MODE (vectype)))
14396 : : return NULL_TREE;
14397 : :
14398 : : /* Re-attach the address-space qualifier if we canonicalized the scalar
14399 : : type. */
14400 : 26345799 : if (TYPE_ADDR_SPACE (orig_scalar_type) != TYPE_ADDR_SPACE (vectype))
14401 : 9 : return build_qualified_type
14402 : 9 : (vectype, KEEP_QUAL_ADDR_SPACE (TYPE_QUALS (orig_scalar_type)));
14403 : :
14404 : : return vectype;
14405 : : }
14406 : :
14407 : : /* Function get_vectype_for_scalar_type.
14408 : :
14409 : : Returns the vector type corresponding to SCALAR_TYPE as supported
14410 : : by the target. If GROUP_SIZE is nonzero and we're performing BB
14411 : : vectorization, make sure that the number of elements in the vector
14412 : : is no bigger than GROUP_SIZE. */
14413 : :
14414 : : tree
14415 : 25578985 : get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type,
14416 : : unsigned int group_size)
14417 : : {
14418 : : /* For BB vectorization, we should always have a group size once we've
14419 : : constructed the SLP tree; the only valid uses of zero GROUP_SIZEs
14420 : : are tentative requests during things like early data reference
14421 : : analysis and pattern recognition. */
14422 : 25578985 : if (is_a <bb_vec_info> (vinfo))
14423 : 23838550 : gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0);
14424 : : else
14425 : : group_size = 0;
14426 : :
14427 : 25578985 : tree vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode,
14428 : : scalar_type);
14429 : 25578985 : if (vectype && vinfo->vector_mode == VOIDmode)
14430 : 1035059 : vinfo->vector_mode = TYPE_MODE (vectype);
14431 : :
14432 : : /* Register the natural choice of vector type, before the group size
14433 : : has been applied. */
14434 : 0 : if (vectype)
14435 : 23296374 : vinfo->used_vector_modes.add (TYPE_MODE (vectype));
14436 : :
14437 : : /* If the natural choice of vector type doesn't satisfy GROUP_SIZE,
14438 : : try again with an explicit number of elements. */
14439 : 23296374 : if (vectype
14440 : 23296374 : && group_size
14441 : 25578985 : && maybe_ge (TYPE_VECTOR_SUBPARTS (vectype), group_size))
14442 : : {
14443 : : /* Start with the biggest number of units that fits within
14444 : : GROUP_SIZE and halve it until we find a valid vector type.
14445 : : Usually either the first attempt will succeed or all will
14446 : : fail (in the latter case because GROUP_SIZE is too small
14447 : : for the target), but it's possible that a target could have
14448 : : a hole between supported vector types.
14449 : :
14450 : : If GROUP_SIZE is not a power of 2, this has the effect of
14451 : : trying the largest power of 2 that fits within the group,
14452 : : even though the group is not a multiple of that vector size.
14453 : : The BB vectorizer will then try to carve up the group into
14454 : : smaller pieces. */
14455 : 2906564 : unsigned int nunits = 1 << floor_log2 (group_size);
14456 : 2906564 : do
14457 : : {
14458 : 2906564 : vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode,
14459 : : scalar_type, nunits);
14460 : 2906564 : nunits /= 2;
14461 : : }
14462 : 2906564 : while (nunits > 1 && !vectype);
14463 : : }
14464 : :
14465 : 25578985 : return vectype;
14466 : : }
14467 : :
14468 : : /* Return the vector type corresponding to SCALAR_TYPE as supported
14469 : : by the target. NODE, if nonnull, is the SLP tree node that will
14470 : : use the returned vector type. */
14471 : :
14472 : : tree
14473 : 136006 : get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type, slp_tree node)
14474 : : {
14475 : 136006 : unsigned int group_size = 0;
14476 : 136006 : if (node)
14477 : 136006 : group_size = SLP_TREE_LANES (node);
14478 : 136006 : return get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
14479 : : }
14480 : :
14481 : : /* Function get_mask_type_for_scalar_type.
14482 : :
14483 : : Returns the mask type corresponding to a result of comparison
14484 : : of vectors of specified SCALAR_TYPE as supported by target.
14485 : : If GROUP_SIZE is nonzero and we're performing BB vectorization,
14486 : : make sure that the number of elements in the vector is no bigger
14487 : : than GROUP_SIZE. */
14488 : :
14489 : : tree
14490 : 1595375 : get_mask_type_for_scalar_type (vec_info *vinfo, tree scalar_type,
14491 : : unsigned int group_size)
14492 : : {
14493 : 1595375 : tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
14494 : :
14495 : 1595375 : if (!vectype)
14496 : : return NULL;
14497 : :
14498 : 1579835 : return truth_type_for (vectype);
14499 : : }
14500 : :
14501 : : /* Function get_mask_type_for_scalar_type.
14502 : :
14503 : : Returns the mask type corresponding to a result of comparison
14504 : : of vectors of specified SCALAR_TYPE as supported by target.
14505 : : NODE, if nonnull, is the SLP tree node that will use the returned
14506 : : vector type. */
14507 : :
14508 : : tree
14509 : 21 : get_mask_type_for_scalar_type (vec_info *vinfo, tree scalar_type,
14510 : : slp_tree node)
14511 : : {
14512 : 21 : tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type, node);
14513 : :
14514 : 21 : if (!vectype)
14515 : : return NULL;
14516 : :
14517 : 21 : return truth_type_for (vectype);
14518 : : }
14519 : :
14520 : : /* Function get_same_sized_vectype
14521 : :
14522 : : Returns a vector type corresponding to SCALAR_TYPE of size
14523 : : VECTOR_TYPE if supported by the target. */
14524 : :
14525 : : tree
14526 : 136015 : get_same_sized_vectype (tree scalar_type, tree vector_type)
14527 : : {
14528 : 136015 : if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type))
14529 : 0 : return truth_type_for (vector_type);
14530 : :
14531 : 136015 : poly_uint64 nunits;
14532 : 272030 : if (!multiple_p (GET_MODE_SIZE (TYPE_MODE (vector_type)),
14533 : 272030 : GET_MODE_SIZE (TYPE_MODE (scalar_type)), &nunits))
14534 : : return NULL_TREE;
14535 : :
14536 : 136015 : return get_related_vectype_for_scalar_type (TYPE_MODE (vector_type),
14537 : 136015 : scalar_type, nunits);
14538 : : }
14539 : :
14540 : : /* Return true if replacing LOOP_VINFO->vector_mode with VECTOR_MODE
14541 : : would not change the chosen vector modes. */
14542 : :
14543 : : bool
14544 : 1368024 : vect_chooses_same_modes_p (vec_info *vinfo, machine_mode vector_mode)
14545 : : {
14546 : 1368024 : for (vec_info::mode_set::iterator i = vinfo->used_vector_modes.begin ();
14547 : 3217452 : i != vinfo->used_vector_modes.end (); ++i)
14548 : 1656955 : if (!VECTOR_MODE_P (*i)
14549 : 4970865 : || related_vector_mode (vector_mode, GET_MODE_INNER (*i), 0) != *i)
14550 : 732241 : return false;
14551 : 635783 : return true;
14552 : : }
14553 : :
14554 : : /* Function vect_is_simple_use.
14555 : :
14556 : : Input:
14557 : : VINFO - the vect info of the loop or basic block that is being vectorized.
14558 : : OPERAND - operand in the loop or bb.
14559 : : Output:
14560 : : DEF_STMT_INFO_OUT (optional) - information about the defining stmt in
14561 : : case OPERAND is an SSA_NAME that is defined in the vectorizable region
14562 : : DEF_STMT_OUT (optional) - the defining stmt in case OPERAND is an SSA_NAME;
14563 : : the definition could be anywhere in the function
14564 : : DT - the type of definition
14565 : :
14566 : : Returns whether a stmt with OPERAND can be vectorized.
14567 : : For loops, supportable operands are constants, loop invariants, and operands
14568 : : that are defined by the current iteration of the loop. Unsupportable
14569 : : operands are those that are defined by a previous iteration of the loop (as
14570 : : is the case in reduction/induction computations).
14571 : : For basic blocks, supportable operands are constants and bb invariants.
14572 : : For now, operands defined outside the basic block are not supported. */
14573 : :
14574 : : bool
14575 : 40893599 : vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
14576 : : stmt_vec_info *def_stmt_info_out, gimple **def_stmt_out)
14577 : : {
14578 : 40893599 : if (def_stmt_info_out)
14579 : 37146608 : *def_stmt_info_out = NULL;
14580 : 40893599 : if (def_stmt_out)
14581 : 8279594 : *def_stmt_out = NULL;
14582 : 40893599 : *dt = vect_unknown_def_type;
14583 : :
14584 : 40893599 : if (dump_enabled_p ())
14585 : : {
14586 : 798742 : dump_printf_loc (MSG_NOTE, vect_location,
14587 : : "vect_is_simple_use: operand ");
14588 : 798742 : if (TREE_CODE (operand) == SSA_NAME
14589 : 798742 : && !SSA_NAME_IS_DEFAULT_DEF (operand))
14590 : 726072 : dump_gimple_expr (MSG_NOTE, TDF_SLIM, SSA_NAME_DEF_STMT (operand), 0);
14591 : : else
14592 : 72670 : dump_generic_expr (MSG_NOTE, TDF_SLIM, operand);
14593 : : }
14594 : :
14595 : 40893599 : if (CONSTANT_CLASS_P (operand))
14596 : 4208243 : *dt = vect_constant_def;
14597 : 36685356 : else if (is_gimple_min_invariant (operand))
14598 : 550623 : *dt = vect_external_def;
14599 : 36134733 : else if (TREE_CODE (operand) != SSA_NAME)
14600 : 1186 : *dt = vect_unknown_def_type;
14601 : 36133547 : else if (SSA_NAME_IS_DEFAULT_DEF (operand))
14602 : 522993 : *dt = vect_external_def;
14603 : : else
14604 : : {
14605 : 35610554 : gimple *def_stmt = SSA_NAME_DEF_STMT (operand);
14606 : 35610554 : stmt_vec_info stmt_vinfo = vinfo->lookup_def (operand);
14607 : 35610554 : if (!stmt_vinfo)
14608 : 826259 : *dt = vect_external_def;
14609 : : else
14610 : : {
14611 : 34784295 : stmt_vinfo = vect_stmt_to_vectorize (stmt_vinfo);
14612 : 34784295 : def_stmt = stmt_vinfo->stmt;
14613 : 34784295 : *dt = STMT_VINFO_DEF_TYPE (stmt_vinfo);
14614 : 34784295 : if (def_stmt_info_out)
14615 : 32529032 : *def_stmt_info_out = stmt_vinfo;
14616 : : }
14617 : 35610554 : if (def_stmt_out)
14618 : 8102196 : *def_stmt_out = def_stmt;
14619 : : }
14620 : :
14621 : 40893599 : if (dump_enabled_p ())
14622 : : {
14623 : 798742 : dump_printf (MSG_NOTE, ", type of def: ");
14624 : 798742 : switch (*dt)
14625 : : {
14626 : 0 : case vect_uninitialized_def:
14627 : 0 : dump_printf (MSG_NOTE, "uninitialized\n");
14628 : 0 : break;
14629 : 60739 : case vect_constant_def:
14630 : 60739 : dump_printf (MSG_NOTE, "constant\n");
14631 : 60739 : break;
14632 : 28181 : case vect_external_def:
14633 : 28181 : dump_printf (MSG_NOTE, "external\n");
14634 : 28181 : break;
14635 : 583793 : case vect_internal_def:
14636 : 583793 : dump_printf (MSG_NOTE, "internal\n");
14637 : 583793 : break;
14638 : 98452 : case vect_induction_def:
14639 : 98452 : dump_printf (MSG_NOTE, "induction\n");
14640 : 98452 : break;
14641 : 24697 : case vect_reduction_def:
14642 : 24697 : dump_printf (MSG_NOTE, "reduction\n");
14643 : 24697 : break;
14644 : 340 : case vect_double_reduction_def:
14645 : 340 : dump_printf (MSG_NOTE, "double reduction\n");
14646 : 340 : break;
14647 : 1843 : case vect_nested_cycle:
14648 : 1843 : dump_printf (MSG_NOTE, "nested cycle\n");
14649 : 1843 : break;
14650 : 195 : case vect_first_order_recurrence:
14651 : 195 : dump_printf (MSG_NOTE, "first order recurrence\n");
14652 : 195 : break;
14653 : 0 : case vect_condition_def:
14654 : 0 : dump_printf (MSG_NOTE, "control flow\n");
14655 : 0 : break;
14656 : 502 : case vect_unknown_def_type:
14657 : 502 : dump_printf (MSG_NOTE, "unknown\n");
14658 : 502 : break;
14659 : : }
14660 : : }
14661 : :
14662 : 40893599 : if (*dt == vect_unknown_def_type)
14663 : : {
14664 : 19369 : if (dump_enabled_p ())
14665 : 502 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
14666 : : "Unsupported pattern.\n");
14667 : 19369 : return false;
14668 : : }
14669 : :
14670 : : return true;
14671 : : }
14672 : :
14673 : : /* Function vect_is_simple_use.
14674 : :
14675 : : Same as vect_is_simple_use but also determines the vector operand
14676 : : type of OPERAND and stores it to *VECTYPE. If the definition of
14677 : : OPERAND is vect_uninitialized_def, vect_constant_def or
14678 : : vect_external_def *VECTYPE will be set to NULL_TREE and the caller
14679 : : is responsible to compute the best suited vector type for the
14680 : : scalar operand. */
14681 : :
14682 : : bool
14683 : 9302 : vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
14684 : : tree *vectype, stmt_vec_info *def_stmt_info_out,
14685 : : gimple **def_stmt_out)
14686 : : {
14687 : 9302 : stmt_vec_info def_stmt_info;
14688 : 9302 : gimple *def_stmt;
14689 : 9302 : if (!vect_is_simple_use (operand, vinfo, dt, &def_stmt_info, &def_stmt))
14690 : : return false;
14691 : :
14692 : 9302 : if (def_stmt_out)
14693 : 0 : *def_stmt_out = def_stmt;
14694 : 9302 : if (def_stmt_info_out)
14695 : 108 : *def_stmt_info_out = def_stmt_info;
14696 : :
14697 : : /* Now get a vector type if the def is internal, otherwise supply
14698 : : NULL_TREE and leave it up to the caller to figure out a proper
14699 : : type for the use stmt. */
14700 : 9302 : if (*dt == vect_internal_def
14701 : : || *dt == vect_induction_def
14702 : : || *dt == vect_reduction_def
14703 : : || *dt == vect_double_reduction_def
14704 : : || *dt == vect_nested_cycle
14705 : 9302 : || *dt == vect_first_order_recurrence)
14706 : : {
14707 : 9291 : *vectype = STMT_VINFO_VECTYPE (def_stmt_info);
14708 : 9291 : gcc_assert (*vectype != NULL_TREE);
14709 : 9291 : if (dump_enabled_p ())
14710 : 1597 : dump_printf_loc (MSG_NOTE, vect_location,
14711 : : "vect_is_simple_use: vectype %T\n", *vectype);
14712 : : }
14713 : 11 : else if (*dt == vect_uninitialized_def
14714 : : || *dt == vect_constant_def
14715 : : || *dt == vect_external_def)
14716 : 11 : *vectype = NULL_TREE;
14717 : : else
14718 : 0 : gcc_unreachable ();
14719 : :
14720 : : return true;
14721 : : }
14722 : :
14723 : : /* Function vect_is_simple_use.
14724 : :
14725 : : Same as vect_is_simple_use but determines the operand by operand
14726 : : position OPERAND from either STMT or SLP_NODE, filling in *OP
14727 : : and *SLP_DEF (when SLP_NODE is not NULL). */
14728 : :
14729 : : bool
14730 : 3322195 : vect_is_simple_use (vec_info *vinfo, stmt_vec_info stmt, slp_tree slp_node,
14731 : : unsigned operand, tree *op, slp_tree *slp_def,
14732 : : enum vect_def_type *dt,
14733 : : tree *vectype, stmt_vec_info *def_stmt_info_out)
14734 : : {
14735 : 3322195 : if (slp_node)
14736 : : {
14737 : 3322087 : slp_tree child = SLP_TREE_CHILDREN (slp_node)[operand];
14738 : 3322087 : *slp_def = child;
14739 : 3322087 : *vectype = SLP_TREE_VECTYPE (child);
14740 : 3322087 : if (SLP_TREE_DEF_TYPE (child) == vect_internal_def)
14741 : : {
14742 : : /* ??? VEC_PERM nodes might be intermediate and their lane value
14743 : : have no representative (nor do we build a VEC_PERM stmt for
14744 : : the actual operation). Note for two-operator nodes we set
14745 : : a representative but leave scalar stmts empty as we'd only
14746 : : have one for a subset of lanes. Ideally no caller would
14747 : : require *op for internal defs. */
14748 : 1763017 : if (SLP_TREE_REPRESENTATIVE (child))
14749 : : {
14750 : 1762230 : *op = gimple_get_lhs (SLP_TREE_REPRESENTATIVE (child)->stmt);
14751 : 1762230 : return vect_is_simple_use (*op, vinfo, dt, def_stmt_info_out);
14752 : : }
14753 : : else
14754 : : {
14755 : 787 : gcc_assert (SLP_TREE_CODE (child) == VEC_PERM_EXPR);
14756 : 787 : *op = error_mark_node;
14757 : 787 : *dt = vect_internal_def;
14758 : 787 : if (def_stmt_info_out)
14759 : 0 : *def_stmt_info_out = NULL;
14760 : 787 : return true;
14761 : : }
14762 : : }
14763 : : else
14764 : : {
14765 : 1559070 : if (def_stmt_info_out)
14766 : 41738 : *def_stmt_info_out = NULL;
14767 : 1559070 : *op = SLP_TREE_SCALAR_OPS (child)[0];
14768 : 1559070 : *dt = SLP_TREE_DEF_TYPE (child);
14769 : 1559070 : return true;
14770 : : }
14771 : : }
14772 : : else
14773 : : {
14774 : 108 : *slp_def = NULL;
14775 : 108 : if (gassign *ass = dyn_cast <gassign *> (stmt->stmt))
14776 : : {
14777 : 108 : if (gimple_assign_rhs_code (ass) == COND_EXPR
14778 : 108 : && COMPARISON_CLASS_P (gimple_assign_rhs1 (ass)))
14779 : 0 : gcc_unreachable ();
14780 : 108 : else if (gimple_assign_rhs_code (ass) == VIEW_CONVERT_EXPR)
14781 : 0 : *op = TREE_OPERAND (gimple_assign_rhs1 (ass), 0);
14782 : : else
14783 : 108 : *op = gimple_op (ass, operand + 1);
14784 : : }
14785 : 0 : else if (gcond *cond = dyn_cast <gcond *> (stmt->stmt))
14786 : 0 : *op = gimple_op (cond, operand);
14787 : 0 : else if (gcall *call = dyn_cast <gcall *> (stmt->stmt))
14788 : 0 : *op = gimple_call_arg (call, operand);
14789 : : else
14790 : 0 : gcc_unreachable ();
14791 : 108 : return vect_is_simple_use (*op, vinfo, dt, vectype, def_stmt_info_out);
14792 : : }
14793 : : }
14794 : :
14795 : : /* If OP is not NULL and is external or constant update its vector
14796 : : type with VECTYPE. Returns true if successful or false if not,
14797 : : for example when conflicting vector types are present. */
14798 : :
14799 : : bool
14800 : 2839836 : vect_maybe_update_slp_op_vectype (slp_tree op, tree vectype)
14801 : : {
14802 : 2839836 : if (!op || SLP_TREE_DEF_TYPE (op) == vect_internal_def)
14803 : : return true;
14804 : 1010031 : if (SLP_TREE_VECTYPE (op))
14805 : 64139 : return types_compatible_p (SLP_TREE_VECTYPE (op), vectype);
14806 : : /* For external defs refuse to produce VECTOR_BOOLEAN_TYPE_P, those
14807 : : should be handled by patters. Allow vect_constant_def for now
14808 : : as well as the trivial single-lane uniform vect_external_def case
14809 : : both of which we code-generate reasonably. */
14810 : 945892 : if (VECTOR_BOOLEAN_TYPE_P (vectype)
14811 : 1186 : && SLP_TREE_DEF_TYPE (op) == vect_external_def
14812 : 946630 : && SLP_TREE_LANES (op) > 1)
14813 : : return false;
14814 : 945703 : SLP_TREE_VECTYPE (op) = vectype;
14815 : 945703 : return true;
14816 : : }
14817 : :
14818 : : /* Function supportable_widening_operation
14819 : :
14820 : : Check whether an operation represented by the code CODE is a
14821 : : widening operation that is supported by the target platform in
14822 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
14823 : : producing a result of type VECTYPE_OUT).
14824 : :
14825 : : Widening operations we currently support are NOP (CONVERT), FLOAT,
14826 : : FIX_TRUNC and WIDEN_MULT. This function checks if these operations
14827 : : are supported by the target platform either directly (via vector
14828 : : tree-codes), or via target builtins.
14829 : :
14830 : : Output:
14831 : : - CODE1 and CODE2 are codes of vector operations to be used when
14832 : : vectorizing the operation, if available.
14833 : : - MULTI_STEP_CVT determines the number of required intermediate steps in
14834 : : case of multi-step conversion (like char->short->int - in that case
14835 : : MULTI_STEP_CVT will be 1).
14836 : : - INTERM_TYPES contains the intermediate type required to perform the
14837 : : widening operation (short in the above example). */
14838 : :
14839 : : bool
14840 : 309275 : supportable_widening_operation (vec_info *vinfo,
14841 : : code_helper code,
14842 : : stmt_vec_info stmt_info,
14843 : : tree vectype_out, tree vectype_in,
14844 : : code_helper *code1,
14845 : : code_helper *code2,
14846 : : int *multi_step_cvt,
14847 : : vec<tree> *interm_types)
14848 : : {
14849 : 309275 : loop_vec_info loop_info = dyn_cast <loop_vec_info> (vinfo);
14850 : 309275 : class loop *vect_loop = NULL;
14851 : 309275 : machine_mode vec_mode;
14852 : 309275 : enum insn_code icode1, icode2;
14853 : 309275 : optab optab1 = unknown_optab, optab2 = unknown_optab;
14854 : 309275 : tree vectype = vectype_in;
14855 : 309275 : tree wide_vectype = vectype_out;
14856 : 309275 : tree_code c1 = MAX_TREE_CODES, c2 = MAX_TREE_CODES;
14857 : 309275 : int i;
14858 : 309275 : tree prev_type, intermediate_type;
14859 : 309275 : machine_mode intermediate_mode, prev_mode;
14860 : 309275 : optab optab3, optab4;
14861 : :
14862 : 309275 : *multi_step_cvt = 0;
14863 : 172720 : if (loop_info)
14864 : 136555 : vect_loop = LOOP_VINFO_LOOP (loop_info);
14865 : :
14866 : 309275 : switch (code.safe_as_tree_code ())
14867 : : {
14868 : : case MAX_TREE_CODES:
14869 : : /* Don't set c1 and c2 if code is not a tree_code. */
14870 : : break;
14871 : :
14872 : 159903 : case WIDEN_MULT_EXPR:
14873 : : /* The result of a vectorized widening operation usually requires
14874 : : two vectors (because the widened results do not fit into one vector).
14875 : : The generated vector results would normally be expected to be
14876 : : generated in the same order as in the original scalar computation,
14877 : : i.e. if 8 results are generated in each vector iteration, they are
14878 : : to be organized as follows:
14879 : : vect1: [res1,res2,res3,res4],
14880 : : vect2: [res5,res6,res7,res8].
14881 : :
14882 : : However, in the special case that the result of the widening
14883 : : operation is used in a reduction computation only, the order doesn't
14884 : : matter (because when vectorizing a reduction we change the order of
14885 : : the computation). Some targets can take advantage of this and
14886 : : generate more efficient code. For example, targets like Altivec,
14887 : : that support widen_mult using a sequence of {mult_even,mult_odd}
14888 : : generate the following vectors:
14889 : : vect1: [res1,res3,res5,res7],
14890 : : vect2: [res2,res4,res6,res8].
14891 : :
14892 : : When vectorizing outer-loops, we execute the inner-loop sequentially
14893 : : (each vectorized inner-loop iteration contributes to VF outer-loop
14894 : : iterations in parallel). We therefore don't allow to change the
14895 : : order of the computation in the inner-loop during outer-loop
14896 : : vectorization. */
14897 : : /* TODO: Another case in which order doesn't *really* matter is when we
14898 : : widen and then contract again, e.g. (short)((int)x * y >> 8).
14899 : : Normally, pack_trunc performs an even/odd permute, whereas the
14900 : : repack from an even/odd expansion would be an interleave, which
14901 : : would be significantly simpler for e.g. AVX2. */
14902 : : /* In any case, in order to avoid duplicating the code below, recurse
14903 : : on VEC_WIDEN_MULT_EVEN_EXPR. If it succeeds, all the return values
14904 : : are properly set up for the caller. If we fail, we'll continue with
14905 : : a VEC_WIDEN_MULT_LO/HI_EXPR check. */
14906 : 159903 : if (vect_loop
14907 : 43833 : && !nested_in_vect_loop_p (vect_loop, stmt_info)
14908 : 204205 : && supportable_widening_operation (vinfo, VEC_WIDEN_MULT_EVEN_EXPR,
14909 : : stmt_info, vectype_out,
14910 : : vectype_in, code1,
14911 : : code2, multi_step_cvt,
14912 : : interm_types))
14913 : : {
14914 : : /* Elements in a vector with vect_used_by_reduction property cannot
14915 : : be reordered if the use chain with this property does not have the
14916 : : same operation. One such an example is s += a * b, where elements
14917 : : in a and b cannot be reordered. Here we check if the vector defined
14918 : : by STMT is only directly used in the reduction statement. */
14919 : 30134 : tree lhs = gimple_assign_lhs (vect_orig_stmt (stmt_info)->stmt);
14920 : 28860 : stmt_vec_info use_stmt_info = loop_info->lookup_single_use (lhs);
14921 : 28860 : if (use_stmt_info && STMT_VINFO_REDUC_DEF (use_stmt_info))
14922 : : return true;
14923 : : }
14924 : : c1 = VEC_WIDEN_MULT_LO_EXPR;
14925 : : c2 = VEC_WIDEN_MULT_HI_EXPR;
14926 : : break;
14927 : :
14928 : : case DOT_PROD_EXPR:
14929 : 309165 : c1 = DOT_PROD_EXPR;
14930 : 309165 : c2 = DOT_PROD_EXPR;
14931 : : break;
14932 : :
14933 : 0 : case SAD_EXPR:
14934 : 0 : c1 = SAD_EXPR;
14935 : 0 : c2 = SAD_EXPR;
14936 : 0 : break;
14937 : :
14938 : 43833 : case VEC_WIDEN_MULT_EVEN_EXPR:
14939 : : /* Support the recursion induced just above. */
14940 : 43833 : c1 = VEC_WIDEN_MULT_EVEN_EXPR;
14941 : 43833 : c2 = VEC_WIDEN_MULT_ODD_EXPR;
14942 : 43833 : break;
14943 : :
14944 : 9537 : case WIDEN_LSHIFT_EXPR:
14945 : 9537 : c1 = VEC_WIDEN_LSHIFT_LO_EXPR;
14946 : 9537 : c2 = VEC_WIDEN_LSHIFT_HI_EXPR;
14947 : 9537 : break;
14948 : :
14949 : 33354 : CASE_CONVERT:
14950 : 33354 : c1 = VEC_UNPACK_LO_EXPR;
14951 : 33354 : c2 = VEC_UNPACK_HI_EXPR;
14952 : 33354 : break;
14953 : :
14954 : 7241 : case FLOAT_EXPR:
14955 : 7241 : c1 = VEC_UNPACK_FLOAT_LO_EXPR;
14956 : 7241 : c2 = VEC_UNPACK_FLOAT_HI_EXPR;
14957 : 7241 : break;
14958 : :
14959 : 302 : case FIX_TRUNC_EXPR:
14960 : 302 : c1 = VEC_UNPACK_FIX_TRUNC_LO_EXPR;
14961 : 302 : c2 = VEC_UNPACK_FIX_TRUNC_HI_EXPR;
14962 : 302 : break;
14963 : :
14964 : 0 : default:
14965 : 0 : gcc_unreachable ();
14966 : : }
14967 : :
14968 : 309165 : if (BYTES_BIG_ENDIAN && c1 != VEC_WIDEN_MULT_EVEN_EXPR)
14969 : : std::swap (c1, c2);
14970 : :
14971 : 309165 : if (code == FIX_TRUNC_EXPR)
14972 : : {
14973 : : /* The signedness is determined from output operand. */
14974 : 302 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
14975 : 302 : optab2 = optab_for_tree_code (c2, vectype_out, optab_default);
14976 : : }
14977 : 535466 : else if (CONVERT_EXPR_CODE_P (code.safe_as_tree_code ())
14978 : 33354 : && VECTOR_BOOLEAN_TYPE_P (wide_vectype)
14979 : 5859 : && VECTOR_BOOLEAN_TYPE_P (vectype)
14980 : 5859 : && TYPE_MODE (wide_vectype) == TYPE_MODE (vectype)
14981 : 254032 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype)))
14982 : : {
14983 : : /* If the input and result modes are the same, a different optab
14984 : : is needed where we pass in the number of units in vectype. */
14985 : : optab1 = vec_unpacks_sbool_lo_optab;
14986 : : optab2 = vec_unpacks_sbool_hi_optab;
14987 : : }
14988 : :
14989 : 309165 : vec_mode = TYPE_MODE (vectype);
14990 : 309165 : if (widening_fn_p (code))
14991 : : {
14992 : : /* If this is an internal fn then we must check whether the target
14993 : : supports either a low-high split or an even-odd split. */
14994 : 55105 : internal_fn ifn = as_internal_fn ((combined_fn) code);
14995 : :
14996 : 55105 : internal_fn lo, hi, even, odd;
14997 : 55105 : lookup_hilo_internal_fn (ifn, &lo, &hi);
14998 : 55105 : *code1 = as_combined_fn (lo);
14999 : 55105 : *code2 = as_combined_fn (hi);
15000 : 55105 : optab1 = direct_internal_fn_optab (lo, {vectype, vectype});
15001 : 55105 : optab2 = direct_internal_fn_optab (hi, {vectype, vectype});
15002 : :
15003 : : /* If we don't support low-high, then check for even-odd. */
15004 : 55105 : if (!optab1
15005 : 55105 : || (icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing
15006 : 0 : || !optab2
15007 : 55105 : || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing)
15008 : : {
15009 : 55105 : lookup_evenodd_internal_fn (ifn, &even, &odd);
15010 : 55105 : *code1 = as_combined_fn (even);
15011 : 55105 : *code2 = as_combined_fn (odd);
15012 : 55105 : optab1 = direct_internal_fn_optab (even, {vectype, vectype});
15013 : 55105 : optab2 = direct_internal_fn_optab (odd, {vectype, vectype});
15014 : : }
15015 : : }
15016 : 254060 : else if (code.is_tree_code ())
15017 : : {
15018 : 254060 : if (code == FIX_TRUNC_EXPR)
15019 : : {
15020 : : /* The signedness is determined from output operand. */
15021 : 302 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
15022 : 302 : optab2 = optab_for_tree_code (c2, vectype_out, optab_default);
15023 : : }
15024 : 253758 : else if (CONVERT_EXPR_CODE_P ((tree_code) code.safe_as_tree_code ())
15025 : 33354 : && VECTOR_BOOLEAN_TYPE_P (wide_vectype)
15026 : 5859 : && VECTOR_BOOLEAN_TYPE_P (vectype)
15027 : 5859 : && TYPE_MODE (wide_vectype) == TYPE_MODE (vectype)
15028 : 254032 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype)))
15029 : : {
15030 : : /* If the input and result modes are the same, a different optab
15031 : : is needed where we pass in the number of units in vectype. */
15032 : : optab1 = vec_unpacks_sbool_lo_optab;
15033 : : optab2 = vec_unpacks_sbool_hi_optab;
15034 : : }
15035 : : else
15036 : : {
15037 : 253484 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
15038 : 253484 : optab2 = optab_for_tree_code (c2, vectype, optab_default);
15039 : : }
15040 : 254060 : *code1 = c1;
15041 : 254060 : *code2 = c2;
15042 : : }
15043 : :
15044 : 309165 : if (!optab1 || !optab2)
15045 : : return false;
15046 : :
15047 : 309165 : if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing
15048 : 309165 : || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing)
15049 : 154605 : return false;
15050 : :
15051 : :
15052 : 154560 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype)
15053 : 154560 : && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype))
15054 : : {
15055 : 144909 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
15056 : : return true;
15057 : : /* For scalar masks we may have different boolean
15058 : : vector types having the same QImode. Thus we
15059 : : add additional check for elements number. */
15060 : 2655 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype),
15061 : : TYPE_VECTOR_SUBPARTS (wide_vectype) * 2))
15062 : : return true;
15063 : : }
15064 : :
15065 : : /* Check if it's a multi-step conversion that can be done using intermediate
15066 : : types. */
15067 : :
15068 : 9751 : prev_type = vectype;
15069 : 9751 : prev_mode = vec_mode;
15070 : :
15071 : 165892 : if (!CONVERT_EXPR_CODE_P (code.safe_as_tree_code ()))
15072 : : return false;
15073 : :
15074 : : /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS
15075 : : intermediate steps in promotion sequence. We try
15076 : : MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do
15077 : : not. */
15078 : 9699 : interm_types->create (MAX_INTERM_CVT_STEPS);
15079 : 11587 : for (i = 0; i < MAX_INTERM_CVT_STEPS; i++)
15080 : : {
15081 : 11587 : intermediate_mode = insn_data[icode1].operand[0].mode;
15082 : 11587 : if (VECTOR_BOOLEAN_TYPE_P (prev_type))
15083 : 3963 : intermediate_type
15084 : 3963 : = vect_halve_mask_nunits (prev_type, intermediate_mode);
15085 : 7624 : else if (VECTOR_MODE_P (intermediate_mode))
15086 : : {
15087 : 7624 : tree intermediate_element_type
15088 : 7624 : = lang_hooks.types.type_for_mode (GET_MODE_INNER (intermediate_mode),
15089 : 7624 : TYPE_UNSIGNED (prev_type));
15090 : 7624 : intermediate_type
15091 : 7624 : = build_vector_type_for_mode (intermediate_element_type,
15092 : : intermediate_mode);
15093 : 7624 : }
15094 : : else
15095 : 0 : intermediate_type
15096 : 0 : = lang_hooks.types.type_for_mode (intermediate_mode,
15097 : 0 : TYPE_UNSIGNED (prev_type));
15098 : :
15099 : 11587 : if (VECTOR_BOOLEAN_TYPE_P (intermediate_type)
15100 : 3963 : && VECTOR_BOOLEAN_TYPE_P (prev_type)
15101 : 3963 : && intermediate_mode == prev_mode
15102 : 11587 : && SCALAR_INT_MODE_P (prev_mode))
15103 : : {
15104 : : /* If the input and result modes are the same, a different optab
15105 : : is needed where we pass in the number of units in vectype. */
15106 : : optab3 = vec_unpacks_sbool_lo_optab;
15107 : : optab4 = vec_unpacks_sbool_hi_optab;
15108 : : }
15109 : : else
15110 : : {
15111 : 11587 : optab3 = optab_for_tree_code (c1, intermediate_type, optab_default);
15112 : 11587 : optab4 = optab_for_tree_code (c2, intermediate_type, optab_default);
15113 : : }
15114 : :
15115 : 11587 : if (!optab3 || !optab4
15116 : 11587 : || (icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing
15117 : 11587 : || insn_data[icode1].operand[0].mode != intermediate_mode
15118 : 11587 : || (icode2 = optab_handler (optab2, prev_mode)) == CODE_FOR_nothing
15119 : 11587 : || insn_data[icode2].operand[0].mode != intermediate_mode
15120 : 11587 : || ((icode1 = optab_handler (optab3, intermediate_mode))
15121 : : == CODE_FOR_nothing)
15122 : 21638 : || ((icode2 = optab_handler (optab4, intermediate_mode))
15123 : : == CODE_FOR_nothing))
15124 : : break;
15125 : :
15126 : 10051 : interm_types->quick_push (intermediate_type);
15127 : 10051 : (*multi_step_cvt)++;
15128 : :
15129 : 10051 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype)
15130 : 10051 : && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype))
15131 : : {
15132 : 8183 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
15133 : : return true;
15134 : 1708 : if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type),
15135 : : TYPE_VECTOR_SUBPARTS (wide_vectype) * 2))
15136 : : return true;
15137 : : }
15138 : :
15139 : 1888 : prev_type = intermediate_type;
15140 : 1888 : prev_mode = intermediate_mode;
15141 : : }
15142 : :
15143 : 1536 : interm_types->release ();
15144 : 1536 : return false;
15145 : : }
15146 : :
15147 : :
15148 : : /* Function supportable_narrowing_operation
15149 : :
15150 : : Check whether an operation represented by the code CODE is a
15151 : : narrowing operation that is supported by the target platform in
15152 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
15153 : : and producing a result of type VECTYPE_OUT).
15154 : :
15155 : : Narrowing operations we currently support are NOP (CONVERT), FIX_TRUNC
15156 : : and FLOAT. This function checks if these operations are supported by
15157 : : the target platform directly via vector tree-codes.
15158 : :
15159 : : Output:
15160 : : - CODE1 is the code of a vector operation to be used when
15161 : : vectorizing the operation, if available.
15162 : : - MULTI_STEP_CVT determines the number of required intermediate steps in
15163 : : case of multi-step conversion (like int->short->char - in that case
15164 : : MULTI_STEP_CVT will be 1).
15165 : : - INTERM_TYPES contains the intermediate type required to perform the
15166 : : narrowing operation (short in the above example). */
15167 : :
15168 : : bool
15169 : 31269 : supportable_narrowing_operation (code_helper code,
15170 : : tree vectype_out, tree vectype_in,
15171 : : code_helper *code1, int *multi_step_cvt,
15172 : : vec<tree> *interm_types)
15173 : : {
15174 : 31269 : machine_mode vec_mode;
15175 : 31269 : enum insn_code icode1;
15176 : 31269 : optab optab1, interm_optab;
15177 : 31269 : tree vectype = vectype_in;
15178 : 31269 : tree narrow_vectype = vectype_out;
15179 : 31269 : enum tree_code c1;
15180 : 31269 : tree intermediate_type, prev_type;
15181 : 31269 : machine_mode intermediate_mode, prev_mode;
15182 : 31269 : int i;
15183 : 31269 : unsigned HOST_WIDE_INT n_elts;
15184 : 31269 : bool uns;
15185 : :
15186 : 31269 : if (!code.is_tree_code ())
15187 : : return false;
15188 : :
15189 : 31269 : *multi_step_cvt = 0;
15190 : 31269 : switch ((tree_code) code)
15191 : : {
15192 : 30225 : CASE_CONVERT:
15193 : 30225 : c1 = VEC_PACK_TRUNC_EXPR;
15194 : 30225 : if (VECTOR_BOOLEAN_TYPE_P (narrow_vectype)
15195 : 4569 : && VECTOR_BOOLEAN_TYPE_P (vectype)
15196 : 4569 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype))
15197 : 1748 : && TYPE_VECTOR_SUBPARTS (vectype).is_constant (&n_elts)
15198 : 31973 : && n_elts < BITS_PER_UNIT)
15199 : : optab1 = vec_pack_sbool_trunc_optab;
15200 : : else
15201 : 29514 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
15202 : : break;
15203 : :
15204 : 880 : case FIX_TRUNC_EXPR:
15205 : 880 : c1 = VEC_PACK_FIX_TRUNC_EXPR;
15206 : : /* The signedness is determined from output operand. */
15207 : 880 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
15208 : 880 : break;
15209 : :
15210 : 164 : case FLOAT_EXPR:
15211 : 164 : c1 = VEC_PACK_FLOAT_EXPR;
15212 : 164 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
15213 : 164 : break;
15214 : :
15215 : 0 : default:
15216 : 0 : gcc_unreachable ();
15217 : : }
15218 : :
15219 : 31269 : if (!optab1)
15220 : : return false;
15221 : :
15222 : 31269 : vec_mode = TYPE_MODE (vectype);
15223 : 31269 : if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing)
15224 : : return false;
15225 : :
15226 : 27394 : *code1 = c1;
15227 : :
15228 : 27394 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype))
15229 : : {
15230 : 17413 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
15231 : : return true;
15232 : : /* For scalar masks we may have different boolean
15233 : : vector types having the same QImode. Thus we
15234 : : add additional check for elements number. */
15235 : 3031 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype) * 2,
15236 : : TYPE_VECTOR_SUBPARTS (narrow_vectype)))
15237 : : return true;
15238 : : }
15239 : :
15240 : 9982 : if (code == FLOAT_EXPR)
15241 : : return false;
15242 : :
15243 : : /* Check if it's a multi-step conversion that can be done using intermediate
15244 : : types. */
15245 : 9982 : prev_mode = vec_mode;
15246 : 9982 : prev_type = vectype;
15247 : 9982 : if (code == FIX_TRUNC_EXPR)
15248 : 172 : uns = TYPE_UNSIGNED (vectype_out);
15249 : : else
15250 : 9810 : uns = TYPE_UNSIGNED (vectype);
15251 : :
15252 : : /* For multi-step FIX_TRUNC_EXPR prefer signed floating to integer
15253 : : conversion over unsigned, as unsigned FIX_TRUNC_EXPR is often more
15254 : : costly than signed. */
15255 : 9982 : if (code == FIX_TRUNC_EXPR && uns)
15256 : : {
15257 : 76 : enum insn_code icode2;
15258 : :
15259 : 76 : intermediate_type
15260 : 76 : = lang_hooks.types.type_for_mode (TYPE_MODE (vectype_out), 0);
15261 : 76 : interm_optab
15262 : 76 : = optab_for_tree_code (c1, intermediate_type, optab_default);
15263 : 76 : if (interm_optab != unknown_optab
15264 : 76 : && (icode2 = optab_handler (optab1, vec_mode)) != CODE_FOR_nothing
15265 : 76 : && insn_data[icode1].operand[0].mode
15266 : 76 : == insn_data[icode2].operand[0].mode)
15267 : : {
15268 : : uns = false;
15269 : : optab1 = interm_optab;
15270 : : icode1 = icode2;
15271 : : }
15272 : : }
15273 : :
15274 : : /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS
15275 : : intermediate steps in promotion sequence. We try
15276 : : MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do not. */
15277 : 9982 : interm_types->create (MAX_INTERM_CVT_STEPS);
15278 : 21152 : for (i = 0; i < MAX_INTERM_CVT_STEPS; i++)
15279 : : {
15280 : 11170 : intermediate_mode = insn_data[icode1].operand[0].mode;
15281 : 11170 : if (VECTOR_BOOLEAN_TYPE_P (prev_type))
15282 : 1846 : intermediate_type
15283 : 1846 : = vect_double_mask_nunits (prev_type, intermediate_mode);
15284 : : else
15285 : 9324 : intermediate_type
15286 : 9324 : = lang_hooks.types.type_for_mode (intermediate_mode, uns);
15287 : 11170 : if (VECTOR_BOOLEAN_TYPE_P (intermediate_type)
15288 : 1846 : && VECTOR_BOOLEAN_TYPE_P (prev_type)
15289 : 1846 : && SCALAR_INT_MODE_P (prev_mode)
15290 : 679 : && TYPE_VECTOR_SUBPARTS (intermediate_type).is_constant (&n_elts)
15291 : 11849 : && n_elts < BITS_PER_UNIT)
15292 : : interm_optab = vec_pack_sbool_trunc_optab;
15293 : : else
15294 : 11135 : interm_optab
15295 : 11135 : = optab_for_tree_code (VEC_PACK_TRUNC_EXPR, intermediate_type,
15296 : : optab_default);
15297 : 35 : if (!interm_optab
15298 : 11170 : || ((icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing)
15299 : 11170 : || insn_data[icode1].operand[0].mode != intermediate_mode
15300 : 22305 : || ((icode1 = optab_handler (interm_optab, intermediate_mode))
15301 : : == CODE_FOR_nothing))
15302 : : break;
15303 : :
15304 : 10666 : interm_types->quick_push (intermediate_type);
15305 : 10666 : (*multi_step_cvt)++;
15306 : :
15307 : 10666 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype))
15308 : : {
15309 : 9478 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
15310 : : return true;
15311 : 928 : if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type) * 2,
15312 : : TYPE_VECTOR_SUBPARTS (narrow_vectype)))
15313 : : return true;
15314 : : }
15315 : :
15316 : 1188 : prev_mode = intermediate_mode;
15317 : 1188 : prev_type = intermediate_type;
15318 : 1188 : optab1 = interm_optab;
15319 : : }
15320 : :
15321 : 504 : interm_types->release ();
15322 : 504 : return false;
15323 : : }
15324 : :
15325 : : /* Function supportable_indirect_convert_operation
15326 : :
15327 : : Check whether an operation represented by the code CODE is single or multi
15328 : : operations that are supported by the target platform in
15329 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
15330 : : producing a result of type VECTYPE_OUT).
15331 : :
15332 : : Convert operations we currently support directly are FIX_TRUNC and FLOAT.
15333 : : This function checks if these operations are supported
15334 : : by the target platform directly (via vector tree-codes).
15335 : :
15336 : : Output:
15337 : : - converts contains some pairs to perform the convert operation,
15338 : : the pair's first is the intermediate type, and its second is the code of
15339 : : a vector operation to be used when converting the operation from the
15340 : : previous type to the intermediate type. */
15341 : : bool
15342 : 62715 : supportable_indirect_convert_operation (code_helper code,
15343 : : tree vectype_out,
15344 : : tree vectype_in,
15345 : : vec<std::pair<tree, tree_code> > &converts,
15346 : : tree op0, slp_tree slp_op0)
15347 : : {
15348 : 62715 : bool found_mode = false;
15349 : 62715 : scalar_mode lhs_mode = GET_MODE_INNER (TYPE_MODE (vectype_out));
15350 : 62715 : scalar_mode rhs_mode = GET_MODE_INNER (TYPE_MODE (vectype_in));
15351 : 62715 : opt_scalar_mode mode_iter;
15352 : 62715 : tree_code tc1, tc2, code1, code2;
15353 : :
15354 : 62715 : tree cvt_type = NULL_TREE;
15355 : 62715 : poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (vectype_in);
15356 : :
15357 : 62715 : if (supportable_convert_operation ((tree_code) code,
15358 : : vectype_out,
15359 : : vectype_in,
15360 : : &tc1))
15361 : : {
15362 : 16305 : converts.safe_push (std::make_pair (vectype_out, tc1));
15363 : 16305 : return true;
15364 : : }
15365 : :
15366 : : /* For conversions between float and integer types try whether
15367 : : we can use intermediate signed integer types to support the
15368 : : conversion. */
15369 : 92820 : if (GET_MODE_SIZE (lhs_mode) != GET_MODE_SIZE (rhs_mode)
15370 : 46410 : && (code == FLOAT_EXPR
15371 : 2996 : || (code == FIX_TRUNC_EXPR && !flag_trapping_math)))
15372 : : {
15373 : 380 : bool demotion = GET_MODE_SIZE (rhs_mode) > GET_MODE_SIZE (lhs_mode);
15374 : 190 : bool float_expr_p = code == FLOAT_EXPR;
15375 : 190 : unsigned short target_size;
15376 : 190 : scalar_mode intermediate_mode;
15377 : 190 : if (demotion)
15378 : : {
15379 : 86 : intermediate_mode = lhs_mode;
15380 : 86 : target_size = GET_MODE_SIZE (rhs_mode);
15381 : : }
15382 : : else
15383 : : {
15384 : 104 : target_size = GET_MODE_SIZE (lhs_mode);
15385 : 104 : if (!int_mode_for_size
15386 : 104 : (GET_MODE_BITSIZE (rhs_mode), 0).exists (&intermediate_mode))
15387 : 122 : return false;
15388 : : }
15389 : 190 : code1 = float_expr_p ? (tree_code) code : NOP_EXPR;
15390 : 190 : code2 = float_expr_p ? NOP_EXPR : (tree_code) code;
15391 : 190 : opt_scalar_mode mode_iter;
15392 : 294 : FOR_EACH_2XWIDER_MODE (mode_iter, intermediate_mode)
15393 : : {
15394 : 294 : intermediate_mode = mode_iter.require ();
15395 : :
15396 : 588 : if (GET_MODE_SIZE (intermediate_mode) > target_size)
15397 : : break;
15398 : :
15399 : 266 : scalar_mode cvt_mode;
15400 : 266 : if (!int_mode_for_size
15401 : 266 : (GET_MODE_BITSIZE (intermediate_mode), 0).exists (&cvt_mode))
15402 : : break;
15403 : :
15404 : 236 : cvt_type = build_nonstandard_integer_type
15405 : 236 : (GET_MODE_BITSIZE (cvt_mode), 0);
15406 : :
15407 : : /* Check if the intermediate type can hold OP0's range.
15408 : : When converting from float to integer this is not necessary
15409 : : because values that do not fit the (smaller) target type are
15410 : : unspecified anyway. */
15411 : 236 : if (demotion && float_expr_p)
15412 : : {
15413 : 10 : wide_int op_min_value, op_max_value;
15414 : : /* For vector form, it looks like op0 doesn't have RANGE_INFO.
15415 : : In the future, if it is supported, changes may need to be made
15416 : : to this part, such as checking the RANGE of each element
15417 : : in the vector. */
15418 : 10 : if (slp_op0)
15419 : : {
15420 : 6 : tree def;
15421 : : /* ??? Merge ranges in case of more than one lane. */
15422 : 6 : if (SLP_TREE_LANES (slp_op0) != 1
15423 : 0 : || !(def = vect_get_slp_scalar_def (slp_op0, 0))
15424 : 6 : || !vect_get_range_info (def,
15425 : : &op_min_value, &op_max_value))
15426 : : break;
15427 : : }
15428 : 4 : else if (!op0
15429 : 0 : || TREE_CODE (op0) != SSA_NAME
15430 : 0 : || !SSA_NAME_RANGE_INFO (op0)
15431 : 4 : || !vect_get_range_info (op0, &op_min_value,
15432 : : &op_max_value))
15433 : : break;
15434 : :
15435 : 0 : if (cvt_type == NULL_TREE
15436 : 0 : || (wi::min_precision (op_max_value, SIGNED)
15437 : 0 : > TYPE_PRECISION (cvt_type))
15438 : 0 : || (wi::min_precision (op_min_value, SIGNED)
15439 : 0 : > TYPE_PRECISION (cvt_type)))
15440 : 0 : continue;
15441 : 10 : }
15442 : :
15443 : 226 : cvt_type = get_related_vectype_for_scalar_type (TYPE_MODE (vectype_in),
15444 : : cvt_type,
15445 : : nelts);
15446 : : /* This should only happened for SLP as long as loop vectorizer
15447 : : only supports same-sized vector. */
15448 : 330 : if (cvt_type == NULL_TREE
15449 : 348 : || maybe_ne (TYPE_VECTOR_SUBPARTS (cvt_type), nelts)
15450 : 226 : || !supportable_convert_operation ((tree_code) code1,
15451 : : vectype_out,
15452 : : cvt_type, &tc1)
15453 : 396 : || !supportable_convert_operation ((tree_code) code2,
15454 : : cvt_type,
15455 : : vectype_in, &tc2))
15456 : 104 : continue;
15457 : :
15458 : : found_mode = true;
15459 : : break;
15460 : : }
15461 : :
15462 : 190 : if (found_mode)
15463 : : {
15464 : 122 : converts.safe_push (std::make_pair (cvt_type, tc2));
15465 : 122 : if (TYPE_MODE (cvt_type) != TYPE_MODE (vectype_out))
15466 : 122 : converts.safe_push (std::make_pair (vectype_out, tc1));
15467 : 122 : return true;
15468 : : }
15469 : : }
15470 : : return false;
15471 : : }
15472 : :
15473 : : /* Generate and return a vector mask of MASK_TYPE such that
15474 : : mask[I] is true iff J + START_INDEX < END_INDEX for all J <= I.
15475 : : Add the statements to SEQ. */
15476 : :
15477 : : tree
15478 : 0 : vect_gen_while (gimple_seq *seq, tree mask_type, tree start_index,
15479 : : tree end_index, const char *name)
15480 : : {
15481 : 0 : tree cmp_type = TREE_TYPE (start_index);
15482 : 0 : gcc_checking_assert (direct_internal_fn_supported_p (IFN_WHILE_ULT,
15483 : : cmp_type, mask_type,
15484 : : OPTIMIZE_FOR_SPEED));
15485 : 0 : gcall *call = gimple_build_call_internal (IFN_WHILE_ULT, 3,
15486 : : start_index, end_index,
15487 : : build_zero_cst (mask_type));
15488 : 0 : tree tmp;
15489 : 0 : if (name)
15490 : 0 : tmp = make_temp_ssa_name (mask_type, NULL, name);
15491 : : else
15492 : 0 : tmp = make_ssa_name (mask_type);
15493 : 0 : gimple_call_set_lhs (call, tmp);
15494 : 0 : gimple_seq_add_stmt (seq, call);
15495 : 0 : return tmp;
15496 : : }
15497 : :
15498 : : /* Generate a vector mask of type MASK_TYPE for which index I is false iff
15499 : : J + START_INDEX < END_INDEX for all J <= I. Add the statements to SEQ. */
15500 : :
15501 : : tree
15502 : 0 : vect_gen_while_not (gimple_seq *seq, tree mask_type, tree start_index,
15503 : : tree end_index)
15504 : : {
15505 : 0 : tree tmp = vect_gen_while (seq, mask_type, start_index, end_index);
15506 : 0 : return gimple_build (seq, BIT_NOT_EXPR, mask_type, tmp);
15507 : : }
15508 : :
15509 : : /* Try to compute the vector types required to vectorize STMT_INFO,
15510 : : returning true on success and false if vectorization isn't possible.
15511 : : If GROUP_SIZE is nonzero and we're performing BB vectorization,
15512 : : take sure that the number of elements in the vectors is no bigger
15513 : : than GROUP_SIZE.
15514 : :
15515 : : On success:
15516 : :
15517 : : - Set *STMT_VECTYPE_OUT to:
15518 : : - NULL_TREE if the statement doesn't need to be vectorized;
15519 : : - the equivalent of STMT_VINFO_VECTYPE otherwise.
15520 : :
15521 : : - Set *NUNITS_VECTYPE_OUT to the vector type that contains the maximum
15522 : : number of units needed to vectorize STMT_INFO, or NULL_TREE if the
15523 : : statement does not help to determine the overall number of units. */
15524 : :
15525 : : opt_result
15526 : 7004143 : vect_get_vector_types_for_stmt (vec_info *vinfo, stmt_vec_info stmt_info,
15527 : : tree *stmt_vectype_out,
15528 : : tree *nunits_vectype_out,
15529 : : unsigned int group_size)
15530 : : {
15531 : 7004143 : gimple *stmt = stmt_info->stmt;
15532 : :
15533 : : /* For BB vectorization, we should always have a group size once we've
15534 : : constructed the SLP tree; the only valid uses of zero GROUP_SIZEs
15535 : : are tentative requests during things like early data reference
15536 : : analysis and pattern recognition. */
15537 : 7004143 : if (is_a <bb_vec_info> (vinfo))
15538 : 4330099 : gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0);
15539 : : else
15540 : : group_size = 0;
15541 : :
15542 : 7004143 : *stmt_vectype_out = NULL_TREE;
15543 : 7004143 : *nunits_vectype_out = NULL_TREE;
15544 : :
15545 : 7004143 : if (gimple_get_lhs (stmt) == NULL_TREE
15546 : : /* Allow vector conditionals through here. */
15547 : 121174 : && !is_a <gcond *> (stmt)
15548 : : /* MASK_STORE and friends have no lhs, but are ok. */
15549 : 7010900 : && !(is_gimple_call (stmt)
15550 : 3309 : && gimple_call_internal_p (stmt)
15551 : 3283 : && internal_store_fn_p (gimple_call_internal_fn (stmt))))
15552 : : {
15553 : 191 : if (is_a <gcall *> (stmt))
15554 : : {
15555 : : /* Ignore calls with no lhs. These must be calls to
15556 : : #pragma omp simd functions, and what vectorization factor
15557 : : it really needs can't be determined until
15558 : : vectorizable_simd_clone_call. */
15559 : 26 : if (dump_enabled_p ())
15560 : 24 : dump_printf_loc (MSG_NOTE, vect_location,
15561 : : "defer to SIMD clone analysis.\n");
15562 : 26 : return opt_result::success ();
15563 : : }
15564 : :
15565 : 165 : return opt_result::failure_at (stmt,
15566 : : "not vectorized: irregular stmt: %G", stmt);
15567 : : }
15568 : :
15569 : 7003952 : tree vectype;
15570 : 7003952 : tree scalar_type = NULL_TREE;
15571 : 7003952 : if (group_size == 0 && STMT_VINFO_VECTYPE (stmt_info))
15572 : : {
15573 : 3435192 : vectype = STMT_VINFO_VECTYPE (stmt_info);
15574 : 3435192 : if (dump_enabled_p ())
15575 : 229507 : dump_printf_loc (MSG_NOTE, vect_location,
15576 : : "precomputed vectype: %T\n", vectype);
15577 : : }
15578 : 3568760 : else if (vect_use_mask_type_p (stmt_info))
15579 : : {
15580 : 171968 : unsigned int precision = stmt_info->mask_precision;
15581 : 171968 : scalar_type = build_nonstandard_integer_type (precision, 1);
15582 : 171968 : vectype = get_mask_type_for_scalar_type (vinfo, scalar_type, group_size);
15583 : 171968 : if (!vectype)
15584 : 0 : return opt_result::failure_at (stmt, "not vectorized: unsupported"
15585 : : " data-type %T\n", scalar_type);
15586 : 171968 : if (dump_enabled_p ())
15587 : 3732 : dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype);
15588 : : }
15589 : : else
15590 : : {
15591 : : /* If we got here with a gcond it means that the target had no available vector
15592 : : mode for the scalar type. We can't vectorize so abort. */
15593 : 3396792 : if (is_a <gcond *> (stmt))
15594 : 23 : return opt_result::failure_at (stmt,
15595 : : "not vectorized:"
15596 : : " unsupported data-type for gcond %T\n",
15597 : : scalar_type);
15598 : :
15599 : 3396769 : if (data_reference *dr = STMT_VINFO_DATA_REF (stmt_info))
15600 : 1418541 : scalar_type = TREE_TYPE (DR_REF (dr));
15601 : : else
15602 : 1978228 : scalar_type = TREE_TYPE (gimple_get_lhs (stmt));
15603 : :
15604 : 3396769 : if (dump_enabled_p ())
15605 : : {
15606 : 53742 : if (group_size)
15607 : 7515 : dump_printf_loc (MSG_NOTE, vect_location,
15608 : : "get vectype for scalar type (group size %d):"
15609 : : " %T\n", group_size, scalar_type);
15610 : : else
15611 : 46227 : dump_printf_loc (MSG_NOTE, vect_location,
15612 : : "get vectype for scalar type: %T\n", scalar_type);
15613 : : }
15614 : 3396769 : vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
15615 : 3396769 : if (!vectype)
15616 : 179029 : return opt_result::failure_at (stmt,
15617 : : "not vectorized:"
15618 : : " unsupported data-type %T\n",
15619 : : scalar_type);
15620 : :
15621 : 3217740 : if (dump_enabled_p ())
15622 : 53574 : dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype);
15623 : : }
15624 : :
15625 : 3619215 : if (scalar_type && VECTOR_MODE_P (TYPE_MODE (scalar_type)))
15626 : 0 : return opt_result::failure_at (stmt,
15627 : : "not vectorized: vector stmt in loop:%G",
15628 : : stmt);
15629 : :
15630 : 6824900 : *stmt_vectype_out = vectype;
15631 : :
15632 : : /* Don't try to compute scalar types if the stmt produces a boolean
15633 : : vector; use the existing vector type instead. */
15634 : 6824900 : tree nunits_vectype = vectype;
15635 : 6824900 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
15636 : : {
15637 : : /* The number of units is set according to the smallest scalar
15638 : : type (or the largest vector size, but we only support one
15639 : : vector size per vectorization). */
15640 : 6106411 : scalar_type = vect_get_smallest_scalar_type (stmt_info,
15641 : 6106411 : TREE_TYPE (vectype));
15642 : 6106411 : if (!types_compatible_p (scalar_type, TREE_TYPE (vectype)))
15643 : : {
15644 : 1074930 : if (dump_enabled_p ())
15645 : 19623 : dump_printf_loc (MSG_NOTE, vect_location,
15646 : : "get vectype for smallest scalar type: %T\n",
15647 : : scalar_type);
15648 : 1074930 : nunits_vectype = get_vectype_for_scalar_type (vinfo, scalar_type,
15649 : : group_size);
15650 : 1074930 : if (!nunits_vectype)
15651 : 7 : return opt_result::failure_at
15652 : 7 : (stmt, "not vectorized: unsupported data-type %T\n",
15653 : : scalar_type);
15654 : 1074923 : if (dump_enabled_p ())
15655 : 19623 : dump_printf_loc (MSG_NOTE, vect_location, "nunits vectype: %T\n",
15656 : : nunits_vectype);
15657 : : }
15658 : : }
15659 : :
15660 : 6824893 : if (!multiple_p (TYPE_VECTOR_SUBPARTS (nunits_vectype),
15661 : 6824893 : TYPE_VECTOR_SUBPARTS (*stmt_vectype_out)))
15662 : 0 : return opt_result::failure_at (stmt,
15663 : : "Not vectorized: Incompatible number "
15664 : : "of vector subparts between %T and %T\n",
15665 : : nunits_vectype, *stmt_vectype_out);
15666 : :
15667 : 6824893 : if (dump_enabled_p ())
15668 : : {
15669 : 286813 : dump_printf_loc (MSG_NOTE, vect_location, "nunits = ");
15670 : 286813 : dump_dec (MSG_NOTE, TYPE_VECTOR_SUBPARTS (nunits_vectype));
15671 : 286813 : dump_printf (MSG_NOTE, "\n");
15672 : : }
15673 : :
15674 : 6824893 : *nunits_vectype_out = nunits_vectype;
15675 : 6824893 : return opt_result::success ();
15676 : : }
15677 : :
15678 : : /* Generate and return statement sequence that sets vector length LEN that is:
15679 : :
15680 : : min_of_start_and_end = min (START_INDEX, END_INDEX);
15681 : : left_len = END_INDEX - min_of_start_and_end;
15682 : : rhs = min (left_len, LEN_LIMIT);
15683 : : LEN = rhs;
15684 : :
15685 : : Note: the cost of the code generated by this function is modeled
15686 : : by vect_estimate_min_profitable_iters, so changes here may need
15687 : : corresponding changes there. */
15688 : :
15689 : : gimple_seq
15690 : 0 : vect_gen_len (tree len, tree start_index, tree end_index, tree len_limit)
15691 : : {
15692 : 0 : gimple_seq stmts = NULL;
15693 : 0 : tree len_type = TREE_TYPE (len);
15694 : 0 : gcc_assert (TREE_TYPE (start_index) == len_type);
15695 : :
15696 : 0 : tree min = gimple_build (&stmts, MIN_EXPR, len_type, start_index, end_index);
15697 : 0 : tree left_len = gimple_build (&stmts, MINUS_EXPR, len_type, end_index, min);
15698 : 0 : tree rhs = gimple_build (&stmts, MIN_EXPR, len_type, left_len, len_limit);
15699 : 0 : gimple* stmt = gimple_build_assign (len, rhs);
15700 : 0 : gimple_seq_add_stmt (&stmts, stmt);
15701 : :
15702 : 0 : return stmts;
15703 : : }
15704 : :
|