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 TRUE iff the given statement is in an inner loop relative to
66 : : the loop being vectorized. */
67 : : bool
68 : 3795634 : stmt_in_inner_loop_p (vec_info *vinfo, class _stmt_vec_info *stmt_info)
69 : : {
70 : 3795634 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
71 : 3795634 : basic_block bb = gimple_bb (stmt);
72 : 3795634 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
73 : 721012 : class loop* loop;
74 : :
75 : 721012 : if (!loop_vinfo)
76 : : return false;
77 : :
78 : 721012 : loop = LOOP_VINFO_LOOP (loop_vinfo);
79 : :
80 : 721012 : return (bb->loop_father == loop->inner);
81 : : }
82 : :
83 : : /* Record the cost of a statement, either by directly informing the
84 : : target model or by saving it in a vector for later processing.
85 : : Return a preliminary estimate of the statement's cost. */
86 : :
87 : : unsigned
88 : 9569260 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
89 : : enum vect_cost_for_stmt kind,
90 : : stmt_vec_info stmt_info, slp_tree node,
91 : : tree vectype, int misalign,
92 : : enum vect_cost_model_location where)
93 : : {
94 : 9569260 : if ((kind == vector_load || kind == unaligned_load)
95 : 1327716 : && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info)))
96 : : kind = vector_gather_load;
97 : 9569260 : if ((kind == vector_store || kind == unaligned_store)
98 : 916161 : && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info)))
99 : 9569260 : kind = vector_scatter_store;
100 : :
101 : 9569260 : stmt_info_for_cost si
102 : 9569260 : = { count, kind, where, stmt_info, node, vectype, misalign };
103 : 9569260 : body_cost_vec->safe_push (si);
104 : :
105 : 9569260 : return (unsigned)
106 : 9569260 : (builtin_vectorization_cost (kind, vectype, misalign) * count);
107 : : }
108 : :
109 : : unsigned
110 : 5251601 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
111 : : enum vect_cost_for_stmt kind, stmt_vec_info stmt_info,
112 : : tree vectype, int misalign,
113 : : enum vect_cost_model_location where)
114 : : {
115 : 5251601 : return record_stmt_cost (body_cost_vec, count, kind, stmt_info, NULL,
116 : 5251601 : vectype, misalign, where);
117 : : }
118 : :
119 : : unsigned
120 : 1477044 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
121 : : enum vect_cost_for_stmt kind, slp_tree node,
122 : : tree vectype, int misalign,
123 : : enum vect_cost_model_location where)
124 : : {
125 : 1477044 : return record_stmt_cost (body_cost_vec, count, kind,
126 : : SLP_TREE_REPRESENTATIVE (node), node,
127 : 1477044 : vectype, misalign, where);
128 : : }
129 : :
130 : : unsigned
131 : 146010 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
132 : : enum vect_cost_for_stmt kind,
133 : : enum vect_cost_model_location where)
134 : : {
135 : 146010 : gcc_assert (kind == cond_branch_taken || kind == cond_branch_not_taken
136 : : || kind == scalar_stmt);
137 : 146010 : return record_stmt_cost (body_cost_vec, count, kind, NULL, NULL,
138 : 146010 : NULL_TREE, 0, where);
139 : : }
140 : :
141 : : /* Return a variable of type ELEM_TYPE[NELEMS]. */
142 : :
143 : : static tree
144 : 0 : create_vector_array (tree elem_type, unsigned HOST_WIDE_INT nelems)
145 : : {
146 : 0 : return create_tmp_var (build_array_type_nelts (elem_type, nelems),
147 : 0 : "vect_array");
148 : : }
149 : :
150 : : /* ARRAY is an array of vectors created by create_vector_array.
151 : : Return an SSA_NAME for the vector in index N. The reference
152 : : is part of the vectorization of STMT_INFO and the vector is associated
153 : : with scalar destination SCALAR_DEST.
154 : : If we need to ensure that inactive elements are set to zero,
155 : : NEED_ZEROING is true, MASK contains the loop mask to be used. */
156 : :
157 : : static tree
158 : 0 : read_vector_array (vec_info *vinfo,
159 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
160 : : tree scalar_dest, tree array, unsigned HOST_WIDE_INT n,
161 : : bool need_zeroing, tree mask)
162 : : {
163 : 0 : tree vect_type, vect, vect_name, tmp, tmp_name, array_ref;
164 : 0 : gimple *new_stmt;
165 : :
166 : 0 : gcc_assert (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE);
167 : 0 : vect_type = TREE_TYPE (TREE_TYPE (array));
168 : 0 : tmp = vect_create_destination_var (scalar_dest, vect_type);
169 : 0 : vect = vect_create_destination_var (scalar_dest, vect_type);
170 : 0 : array_ref = build4 (ARRAY_REF, vect_type, array,
171 : 0 : build_int_cst (size_type_node, n),
172 : : NULL_TREE, NULL_TREE);
173 : :
174 : 0 : new_stmt = gimple_build_assign (tmp, array_ref);
175 : 0 : tmp_name = make_ssa_name (vect, new_stmt);
176 : 0 : gimple_assign_set_lhs (new_stmt, tmp_name);
177 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
178 : :
179 : 0 : if (need_zeroing)
180 : : {
181 : 0 : tree vec_els = vect_get_mask_load_else (MASK_LOAD_ELSE_ZERO,
182 : : vect_type);
183 : 0 : vect_name = make_ssa_name (vect, new_stmt);
184 : 0 : new_stmt
185 : 0 : = gimple_build_assign (vect_name, VEC_COND_EXPR,
186 : : mask, tmp_name, vec_els);
187 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
188 : : }
189 : : else
190 : : vect_name = tmp_name;
191 : :
192 : 0 : return vect_name;
193 : : }
194 : :
195 : : /* ARRAY is an array of vectors created by create_vector_array.
196 : : Emit code to store SSA_NAME VECT in index N of the array.
197 : : The store is part of the vectorization of STMT_INFO. */
198 : :
199 : : static void
200 : 0 : write_vector_array (vec_info *vinfo,
201 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
202 : : tree vect, tree array, unsigned HOST_WIDE_INT n)
203 : : {
204 : 0 : tree array_ref;
205 : 0 : gimple *new_stmt;
206 : :
207 : 0 : array_ref = build4 (ARRAY_REF, TREE_TYPE (vect), array,
208 : 0 : build_int_cst (size_type_node, n),
209 : : NULL_TREE, NULL_TREE);
210 : :
211 : 0 : new_stmt = gimple_build_assign (array_ref, vect);
212 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
213 : 0 : }
214 : :
215 : : /* PTR is a pointer to an array of type TYPE. Return a representation
216 : : of *PTR. The memory reference replaces those in FIRST_DR
217 : : (and its group). */
218 : :
219 : : static tree
220 : 0 : create_array_ref (tree type, tree ptr, tree alias_ptr_type)
221 : : {
222 : 0 : tree mem_ref;
223 : :
224 : 0 : mem_ref = build2 (MEM_REF, type, ptr, build_int_cst (alias_ptr_type, 0));
225 : : /* Arrays have the same alignment as their type. */
226 : 0 : set_ptr_info_alignment (get_ptr_info (ptr), TYPE_ALIGN_UNIT (type), 0);
227 : 0 : return mem_ref;
228 : : }
229 : :
230 : : /* Add a clobber of variable VAR to the vectorization of STMT_INFO.
231 : : Emit the clobber before *GSI. */
232 : :
233 : : static void
234 : 15 : vect_clobber_variable (vec_info *vinfo, stmt_vec_info stmt_info,
235 : : gimple_stmt_iterator *gsi, tree var)
236 : : {
237 : 15 : tree clobber = build_clobber (TREE_TYPE (var));
238 : 15 : gimple *new_stmt = gimple_build_assign (var, clobber);
239 : 15 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
240 : 15 : }
241 : :
242 : : /* Utility functions used by vect_mark_stmts_to_be_vectorized. */
243 : :
244 : : /* Function vect_mark_relevant.
245 : :
246 : : Mark STMT_INFO as "relevant for vectorization" and add it to WORKLIST. */
247 : :
248 : : static void
249 : 2932013 : vect_mark_relevant (vec<stmt_vec_info> *worklist, stmt_vec_info stmt_info,
250 : : enum vect_relevant relevant, bool live_p)
251 : : {
252 : 2932013 : enum vect_relevant save_relevant = STMT_VINFO_RELEVANT (stmt_info);
253 : 2932013 : bool save_live_p = STMT_VINFO_LIVE_P (stmt_info);
254 : :
255 : 2932013 : if (dump_enabled_p ())
256 : 154805 : dump_printf_loc (MSG_NOTE, vect_location,
257 : : "mark relevant %d, live %d: %G", relevant, live_p,
258 : : stmt_info->stmt);
259 : :
260 : : /* If this stmt is an original stmt in a pattern, we might need to mark its
261 : : related pattern stmt instead of the original stmt. However, such stmts
262 : : may have their own uses that are not in any pattern, in such cases the
263 : : stmt itself should be marked. */
264 : 2932013 : if (STMT_VINFO_IN_PATTERN_P (stmt_info))
265 : : {
266 : : /* This is the last stmt in a sequence that was detected as a
267 : : pattern that can potentially be vectorized. Don't mark the stmt
268 : : as relevant/live because it's not going to be vectorized.
269 : : Instead mark the pattern-stmt that replaces it. */
270 : :
271 : 164752 : if (dump_enabled_p ())
272 : 2185 : dump_printf_loc (MSG_NOTE, vect_location,
273 : : "last stmt in pattern. don't mark"
274 : : " relevant/live.\n");
275 : :
276 : 164752 : stmt_vec_info old_stmt_info = stmt_info;
277 : 164752 : stmt_info = STMT_VINFO_RELATED_STMT (stmt_info);
278 : 164752 : gcc_assert (STMT_VINFO_RELATED_STMT (stmt_info) == old_stmt_info);
279 : 164752 : save_relevant = STMT_VINFO_RELEVANT (stmt_info);
280 : 164752 : save_live_p = STMT_VINFO_LIVE_P (stmt_info);
281 : :
282 : 164752 : if (live_p && relevant == vect_unused_in_scope)
283 : : {
284 : 92 : if (dump_enabled_p ())
285 : 4 : dump_printf_loc (MSG_NOTE, vect_location,
286 : : "vec_stmt_relevant_p: forcing live pattern stmt "
287 : : "relevant.\n");
288 : : relevant = vect_used_only_live;
289 : : }
290 : :
291 : 164752 : if (dump_enabled_p ())
292 : 2185 : dump_printf_loc (MSG_NOTE, vect_location,
293 : : "mark relevant %d, live %d: %G", relevant, live_p,
294 : : stmt_info->stmt);
295 : : }
296 : :
297 : 2932013 : STMT_VINFO_LIVE_P (stmt_info) |= live_p;
298 : 2932013 : if (relevant > STMT_VINFO_RELEVANT (stmt_info))
299 : 2435017 : STMT_VINFO_RELEVANT (stmt_info) = relevant;
300 : :
301 : 2932013 : if (STMT_VINFO_RELEVANT (stmt_info) == save_relevant
302 : 496996 : && STMT_VINFO_LIVE_P (stmt_info) == save_live_p)
303 : : {
304 : 496344 : if (dump_enabled_p ())
305 : 19937 : dump_printf_loc (MSG_NOTE, vect_location,
306 : : "already marked relevant/live.\n");
307 : 496344 : return;
308 : : }
309 : :
310 : 2435669 : worklist->safe_push (stmt_info);
311 : : }
312 : :
313 : :
314 : : /* Function is_simple_and_all_uses_invariant
315 : :
316 : : Return true if STMT_INFO is simple and all uses of it are invariant. */
317 : :
318 : : bool
319 : 354732 : is_simple_and_all_uses_invariant (stmt_vec_info stmt_info,
320 : : loop_vec_info loop_vinfo)
321 : : {
322 : 354732 : tree op;
323 : 354732 : ssa_op_iter iter;
324 : :
325 : 466169 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
326 : 112181 : if (!stmt)
327 : : return false;
328 : :
329 : 117269 : FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
330 : : {
331 : 116525 : enum vect_def_type dt = vect_uninitialized_def;
332 : :
333 : 116525 : if (!vect_is_simple_use (op, loop_vinfo, &dt))
334 : : {
335 : 684 : if (dump_enabled_p ())
336 : 15 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
337 : : "use not simple.\n");
338 : 111437 : return false;
339 : : }
340 : :
341 : 115841 : if (dt != vect_external_def && dt != vect_constant_def)
342 : : return false;
343 : : }
344 : : return true;
345 : : }
346 : :
347 : : /* Function vect_stmt_relevant_p.
348 : :
349 : : Return true if STMT_INFO, in the loop that is represented by LOOP_VINFO,
350 : : is "relevant for vectorization".
351 : :
352 : : A stmt is considered "relevant for vectorization" if:
353 : : - it has uses outside the loop.
354 : : - it has vdefs (it alters memory).
355 : : - control stmts in the loop (except for the exit condition).
356 : : - it is an induction and we have multiple exits.
357 : :
358 : : CHECKME: what other side effects would the vectorizer allow? */
359 : :
360 : : static bool
361 : 3752150 : vect_stmt_relevant_p (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
362 : : enum vect_relevant *relevant, bool *live_p)
363 : : {
364 : 3752150 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
365 : 3752150 : ssa_op_iter op_iter;
366 : 3752150 : imm_use_iterator imm_iter;
367 : 3752150 : use_operand_p use_p;
368 : 3752150 : def_operand_p def_p;
369 : :
370 : 3752150 : *relevant = vect_unused_in_scope;
371 : 3752150 : *live_p = false;
372 : :
373 : : /* cond stmt other than loop exit cond. */
374 : 3752150 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
375 : 3752150 : if (is_ctrl_stmt (stmt)
376 : 468167 : && LOOP_VINFO_LOOP_IV_COND (loop_vinfo) != stmt
377 : 3912903 : && (!loop->inner || gimple_bb (stmt)->loop_father == loop))
378 : 159108 : *relevant = vect_used_in_scope;
379 : :
380 : : /* changing memory. */
381 : 3752150 : if (gimple_code (stmt_info->stmt) != GIMPLE_PHI)
382 : 3116613 : if (gimple_vdef (stmt_info->stmt)
383 : 2648446 : && !gimple_clobber_p (stmt_info->stmt))
384 : : {
385 : 266010 : if (dump_enabled_p ())
386 : 25690 : dump_printf_loc (MSG_NOTE, vect_location,
387 : : "vec_stmt_relevant_p: stmt has vdefs.\n");
388 : 266010 : *relevant = vect_used_in_scope;
389 : 266010 : if (! STMT_VINFO_DATA_REF (stmt_info)
390 : 266010 : && zero_ssa_operands (stmt_info->stmt, SSA_OP_DEF))
391 : 20 : LOOP_VINFO_ALTERNATE_DEFS (loop_vinfo).safe_push (stmt_info);
392 : : }
393 : :
394 : : /* uses outside the loop. */
395 : 10511208 : FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt_info->stmt, op_iter, SSA_OP_DEF)
396 : : {
397 : 7981583 : FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
398 : : {
399 : 4974675 : basic_block bb = gimple_bb (USE_STMT (use_p));
400 : 4974675 : if (!flow_bb_inside_loop_p (loop, bb))
401 : : {
402 : 156926 : if (is_gimple_debug (USE_STMT (use_p)))
403 : 591 : continue;
404 : :
405 : 156335 : if (dump_enabled_p ())
406 : 5267 : dump_printf_loc (MSG_NOTE, vect_location,
407 : : "vec_stmt_relevant_p: used out of loop.\n");
408 : :
409 : : /* We expect all such uses to be in the loop exit phis
410 : : (because of loop closed form) */
411 : 156335 : gcc_assert (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI);
412 : :
413 : 156335 : *live_p = true;
414 : : }
415 : : }
416 : : }
417 : :
418 : : /* Check if it's a not live PHI and multiple exits. In this case
419 : : there will be a usage later on after peeling which is needed for the
420 : : alternate exit.
421 : : ??? Unless the PHI was marked live because of early
422 : : break, which also needs the latch def live and vectorized. */
423 : 3752150 : if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
424 : 1320654 : && is_a <gphi *> (stmt)
425 : 238770 : && gimple_bb (stmt) == LOOP_VINFO_LOOP (loop_vinfo)->header
426 : 3990914 : && ((! VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (stmt_info))
427 : 235305 : && ! *live_p)
428 : 30062 : || STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def))
429 : : {
430 : 233006 : if (dump_enabled_p ())
431 : 2696 : dump_printf_loc (MSG_NOTE, vect_location,
432 : : "vec_stmt_relevant_p: PHI forced live for "
433 : : "early break.\n");
434 : 233006 : LOOP_VINFO_EARLY_BREAKS_LIVE_IVS (loop_vinfo).safe_push (stmt_info);
435 : 233006 : *live_p = true;
436 : : }
437 : :
438 : 354734 : if (*live_p && *relevant == vect_unused_in_scope
439 : 4106882 : && !is_simple_and_all_uses_invariant (stmt_info, loop_vinfo))
440 : : {
441 : 353988 : if (dump_enabled_p ())
442 : 7624 : dump_printf_loc (MSG_NOTE, vect_location,
443 : : "vec_stmt_relevant_p: stmt live but not relevant.\n");
444 : 353988 : *relevant = vect_used_only_live;
445 : : }
446 : :
447 : 3752150 : return (*live_p || *relevant);
448 : : }
449 : :
450 : :
451 : : /* Function exist_non_indexing_operands_for_use_p
452 : :
453 : : USE is one of the uses attached to STMT_INFO. Check if USE is
454 : : used in STMT_INFO for anything other than indexing an array. */
455 : :
456 : : static bool
457 : 3719544 : exist_non_indexing_operands_for_use_p (tree use, stmt_vec_info stmt_info)
458 : : {
459 : 3719544 : tree operand;
460 : :
461 : : /* USE corresponds to some operand in STMT. If there is no data
462 : : reference in STMT, then any operand that corresponds to USE
463 : : is not indexing an array. */
464 : 3719544 : if (!STMT_VINFO_DATA_REF (stmt_info))
465 : : return true;
466 : :
467 : : /* STMT has a data_ref. FORNOW this means that its of one of
468 : : the following forms:
469 : : -1- ARRAY_REF = var
470 : : -2- var = ARRAY_REF
471 : : (This should have been verified in analyze_data_refs).
472 : :
473 : : 'var' in the second case corresponds to a def, not a use,
474 : : so USE cannot correspond to any operands that are not used
475 : : for array indexing.
476 : :
477 : : Therefore, all we need to check is if STMT falls into the
478 : : first case, and whether var corresponds to USE. */
479 : :
480 : 1115971 : gassign *assign = dyn_cast <gassign *> (stmt_info->stmt);
481 : 1103938 : if (!assign || !gimple_assign_copy_p (assign))
482 : : {
483 : 612671 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
484 : 12033 : if (call && gimple_call_internal_p (call))
485 : : {
486 : 12033 : internal_fn ifn = gimple_call_internal_fn (call);
487 : 12033 : int mask_index = internal_fn_mask_index (ifn);
488 : 12033 : if (mask_index >= 0
489 : 12033 : && use == gimple_call_arg (call, mask_index))
490 : : return true;
491 : 7875 : int els_index = internal_fn_else_index (ifn);
492 : 7875 : if (els_index >= 0
493 : 7875 : && use == gimple_call_arg (call, els_index))
494 : : return true;
495 : 6770 : int stored_value_index = internal_fn_stored_value_index (ifn);
496 : 6770 : if (stored_value_index >= 0
497 : 6770 : && use == gimple_call_arg (call, stored_value_index))
498 : : return true;
499 : 5449 : if (internal_gather_scatter_fn_p (ifn)
500 : 5449 : && use == gimple_call_arg (call, 1))
501 : : return true;
502 : : }
503 : 606087 : return false;
504 : : }
505 : :
506 : 503300 : if (TREE_CODE (gimple_assign_lhs (assign)) == SSA_NAME)
507 : : return false;
508 : 503300 : operand = gimple_assign_rhs1 (assign);
509 : 503300 : if (TREE_CODE (operand) != SSA_NAME)
510 : : return false;
511 : :
512 : 438411 : if (operand == use)
513 : : return true;
514 : :
515 : : return false;
516 : : }
517 : :
518 : :
519 : : /*
520 : : Function process_use.
521 : :
522 : : Inputs:
523 : : - a USE in STMT_VINFO in a loop represented by LOOP_VINFO
524 : : - RELEVANT - enum value to be set in the STMT_VINFO of the stmt
525 : : that defined USE. This is done by calling mark_relevant and passing it
526 : : the WORKLIST (to add DEF_STMT to the WORKLIST in case it is relevant).
527 : : - FORCE is true if exist_non_indexing_operands_for_use_p check shouldn't
528 : : be performed.
529 : :
530 : : Outputs:
531 : : Generally, LIVE_P and RELEVANT are used to define the liveness and
532 : : relevance info of the DEF_STMT of this USE:
533 : : STMT_VINFO_LIVE_P (DEF_stmt_vinfo) <-- live_p
534 : : STMT_VINFO_RELEVANT (DEF_stmt_vinfo) <-- relevant
535 : : Exceptions:
536 : : - case 1: If USE is used only for address computations (e.g. array indexing),
537 : : which does not need to be directly vectorized, then the liveness/relevance
538 : : of the respective DEF_STMT is left unchanged.
539 : : - case 2: If STMT_VINFO is a reduction phi and DEF_STMT is a reduction stmt,
540 : : we skip DEF_STMT cause it had already been processed.
541 : : - case 3: If DEF_STMT and STMT_VINFO are in different nests, then
542 : : "relevant" will be modified accordingly.
543 : :
544 : : Return true if everything is as expected. Return false otherwise. */
545 : :
546 : : static opt_result
547 : 3748467 : process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
548 : : enum vect_relevant relevant, vec<stmt_vec_info> *worklist,
549 : : bool force)
550 : : {
551 : 3748467 : stmt_vec_info dstmt_vinfo;
552 : 3748467 : enum vect_def_type dt;
553 : :
554 : : /* case 1: we are only interested in uses that need to be vectorized. Uses
555 : : that are used for address computation are not considered relevant. */
556 : 3748467 : if (!force && !exist_non_indexing_operands_for_use_p (use, stmt_vinfo))
557 : 902679 : return opt_result::success ();
558 : :
559 : 2845788 : if (!vect_is_simple_use (use, loop_vinfo, &dt, &dstmt_vinfo))
560 : 8520 : return opt_result::failure_at (stmt_vinfo->stmt,
561 : : "not vectorized:"
562 : : " unsupported use in stmt.\n");
563 : :
564 : 2837268 : if (!dstmt_vinfo)
565 : 624825 : return opt_result::success ();
566 : :
567 : 2212443 : basic_block def_bb = gimple_bb (dstmt_vinfo->stmt);
568 : 2212443 : basic_block bb = gimple_bb (stmt_vinfo->stmt);
569 : :
570 : : /* case 2: A reduction phi (STMT) defined by a reduction stmt (DSTMT_VINFO).
571 : : We have to force the stmt live since the epilogue loop needs it to
572 : : continue computing the reduction. */
573 : 2212443 : if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI
574 : 385898 : && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
575 : 57241 : && gimple_code (dstmt_vinfo->stmt) != GIMPLE_PHI
576 : 57241 : && STMT_VINFO_DEF_TYPE (dstmt_vinfo) == vect_reduction_def
577 : 2269684 : && bb->loop_father == def_bb->loop_father)
578 : : {
579 : 57241 : if (dump_enabled_p ())
580 : 3411 : dump_printf_loc (MSG_NOTE, vect_location,
581 : : "reduc-stmt defining reduc-phi in the same nest.\n");
582 : 57241 : vect_mark_relevant (worklist, dstmt_vinfo, relevant, true);
583 : 57241 : return opt_result::success ();
584 : : }
585 : :
586 : : /* case 3a: outer-loop stmt defining an inner-loop stmt:
587 : : outer-loop-header-bb:
588 : : d = dstmt_vinfo
589 : : inner-loop:
590 : : stmt # use (d)
591 : : outer-loop-tail-bb:
592 : : ... */
593 : 2155202 : if (flow_loop_nested_p (def_bb->loop_father, bb->loop_father))
594 : : {
595 : 1869 : if (dump_enabled_p ())
596 : 283 : dump_printf_loc (MSG_NOTE, vect_location,
597 : : "outer-loop def-stmt defining inner-loop stmt.\n");
598 : :
599 : 1869 : switch (relevant)
600 : : {
601 : 0 : case vect_unused_in_scope:
602 : 0 : relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_nested_cycle) ?
603 : : vect_used_in_scope : vect_unused_in_scope;
604 : : break;
605 : :
606 : 635 : case vect_used_in_outer_by_reduction:
607 : 635 : gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def);
608 : : relevant = vect_used_by_reduction;
609 : : break;
610 : :
611 : 1022 : case vect_used_in_outer:
612 : 1022 : gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def);
613 : : relevant = vect_used_in_scope;
614 : : break;
615 : :
616 : : case vect_used_in_scope:
617 : : break;
618 : :
619 : 0 : default:
620 : 0 : gcc_unreachable ();
621 : : }
622 : : }
623 : :
624 : : /* case 3b: inner-loop stmt defining an outer-loop stmt:
625 : : outer-loop-header-bb:
626 : : ...
627 : : inner-loop:
628 : : d = dstmt_vinfo
629 : : outer-loop-tail-bb (or outer-loop-exit-bb in double reduction):
630 : : stmt # use (d) */
631 : 2153333 : else if (flow_loop_nested_p (bb->loop_father, def_bb->loop_father))
632 : : {
633 : 1760 : if (dump_enabled_p ())
634 : 542 : dump_printf_loc (MSG_NOTE, vect_location,
635 : : "inner-loop def-stmt defining outer-loop stmt.\n");
636 : :
637 : 1760 : switch (relevant)
638 : : {
639 : 0 : case vect_unused_in_scope:
640 : 0 : relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
641 : 0 : || STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_double_reduction_def) ?
642 : : vect_used_in_outer_by_reduction : vect_unused_in_scope;
643 : : break;
644 : :
645 : : case vect_used_by_reduction:
646 : : case vect_used_only_live:
647 : : relevant = vect_used_in_outer_by_reduction;
648 : : break;
649 : :
650 : : case vect_used_in_scope:
651 : 2099824 : relevant = vect_used_in_outer;
652 : : break;
653 : :
654 : 0 : default:
655 : 0 : gcc_unreachable ();
656 : : }
657 : : }
658 : : /* We are also not interested in uses on loop PHI backedges that are
659 : : inductions. Otherwise we'll needlessly vectorize the IV increment
660 : : and cause hybrid SLP for SLP inductions. */
661 : 2151573 : else if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI
662 : 325815 : && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_induction_def
663 : 323047 : && (PHI_ARG_DEF_FROM_EDGE (stmt_vinfo->stmt,
664 : : loop_latch_edge (bb->loop_father))
665 : : == use)
666 : 2474620 : && (!LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
667 : 267669 : || (gimple_bb (stmt_vinfo->stmt)
668 : 267669 : != LOOP_VINFO_LOOP (loop_vinfo)->header)))
669 : : {
670 : 55378 : if (dump_enabled_p ())
671 : 3428 : dump_printf_loc (MSG_NOTE, vect_location,
672 : : "induction value on backedge.\n");
673 : 55378 : return opt_result::success ();
674 : : }
675 : :
676 : 2099824 : vect_mark_relevant (worklist, dstmt_vinfo, relevant, false);
677 : 2099824 : return opt_result::success ();
678 : : }
679 : :
680 : :
681 : : /* Function vect_mark_stmts_to_be_vectorized.
682 : :
683 : : Not all stmts in the loop need to be vectorized. For example:
684 : :
685 : : for i...
686 : : for j...
687 : : 1. T0 = i + j
688 : : 2. T1 = a[T0]
689 : :
690 : : 3. j = j + 1
691 : :
692 : : Stmt 1 and 3 do not need to be vectorized, because loop control and
693 : : addressing of vectorized data-refs are handled differently.
694 : :
695 : : This pass detects such stmts. */
696 : :
697 : : opt_result
698 : 312431 : vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo, bool *fatal)
699 : : {
700 : 312431 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
701 : 312431 : basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
702 : 312431 : unsigned int nbbs = loop->num_nodes;
703 : 312431 : gimple_stmt_iterator si;
704 : 312431 : unsigned int i;
705 : 312431 : basic_block bb;
706 : 312431 : bool live_p;
707 : 312431 : enum vect_relevant relevant;
708 : :
709 : 312431 : DUMP_VECT_SCOPE ("vect_mark_stmts_to_be_vectorized");
710 : :
711 : 312431 : auto_vec<stmt_vec_info, 64> worklist;
712 : :
713 : : /* 1. Init worklist. */
714 : 1091314 : for (i = 0; i < nbbs; i++)
715 : : {
716 : 783900 : bb = bbs[i];
717 : 1581319 : for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
718 : : {
719 : 1604642 : if (virtual_operand_p (gimple_phi_result (gsi_stmt (si))))
720 : 166784 : continue;
721 : 635537 : stmt_vec_info phi_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
722 : 635537 : if (dump_enabled_p ())
723 : 37346 : dump_printf_loc (MSG_NOTE, vect_location, "init: phi relevant? %G",
724 : : phi_info->stmt);
725 : :
726 : 635537 : if (vect_stmt_relevant_p (phi_info, loop_vinfo, &relevant, &live_p))
727 : : {
728 : 236627 : if (STMT_VINFO_DEF_TYPE (phi_info) == vect_unknown_def_type)
729 : 4902 : return opt_result::failure_at
730 : 4902 : (*si, "not vectorized: unhandled relevant PHI: %G", *si);
731 : 231725 : vect_mark_relevant (&worklist, phi_info, relevant, live_p);
732 : : }
733 : : }
734 : 5616544 : for (si = gsi_after_labels (bb); !gsi_end_p (si); gsi_next (&si))
735 : : {
736 : 4837661 : gimple *stmt = gsi_stmt (si);
737 : 4837661 : if (is_gimple_debug (stmt))
738 : 1720933 : continue;
739 : 3116728 : stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (stmt);
740 : 3116728 : if (dump_enabled_p ())
741 : 200636 : dump_printf_loc (MSG_NOTE, vect_location,
742 : : "init: stmt relevant? %G", stmt);
743 : :
744 : 3116728 : if (gimple_get_lhs (stmt) == NULL_TREE
745 : 474403 : && !is_a <gcond *> (stmt)
746 : 3122964 : && !is_a <gcall *> (stmt))
747 : 115 : return opt_result::failure_at
748 : 115 : (stmt, "not vectorized: irregular stmt: %G", stmt);
749 : :
750 : 3116613 : if (vect_stmt_relevant_p (stmt_info, loop_vinfo, &relevant, &live_p))
751 : 543223 : vect_mark_relevant (&worklist, stmt_info, relevant, live_p);
752 : : }
753 : : }
754 : :
755 : : /* 2. Process_worklist */
756 : 2713276 : while (worklist.length () > 0)
757 : : {
758 : 2414384 : use_operand_p use_p;
759 : 2414384 : ssa_op_iter iter;
760 : :
761 : 2414384 : stmt_vec_info stmt_vinfo = worklist.pop ();
762 : 2414384 : if (dump_enabled_p ())
763 : 134526 : dump_printf_loc (MSG_NOTE, vect_location,
764 : : "worklist: examine stmt: %G", stmt_vinfo->stmt);
765 : :
766 : : /* Examine the USEs of STMT. For each USE, mark the stmt that defines it
767 : : (DEF_STMT) as relevant/irrelevant according to the relevance property
768 : : of STMT. */
769 : 2414384 : relevant = STMT_VINFO_RELEVANT (stmt_vinfo);
770 : :
771 : : /* Generally, the relevance property of STMT (in STMT_VINFO_RELEVANT) is
772 : : propagated as is to the DEF_STMTs of its USEs.
773 : :
774 : : One exception is when STMT has been identified as defining a reduction
775 : : variable; in this case we set the relevance to vect_used_by_reduction.
776 : : This is because we distinguish between two kinds of relevant stmts -
777 : : those that are used by a reduction computation, and those that are
778 : : (also) used by a regular computation. This allows us later on to
779 : : identify stmts that are used solely by a reduction, and therefore the
780 : : order of the results that they produce does not have to be kept. */
781 : :
782 : 2414384 : switch (STMT_VINFO_DEF_TYPE (stmt_vinfo))
783 : : {
784 : 114800 : case vect_reduction_def:
785 : 114800 : gcc_assert (relevant != vect_unused_in_scope);
786 : 114800 : if (relevant != vect_unused_in_scope
787 : 114800 : && relevant != vect_used_in_scope
788 : 114800 : && relevant != vect_used_by_reduction
789 : 114800 : && relevant != vect_used_only_live)
790 : 0 : return opt_result::failure_at
791 : 0 : (stmt_vinfo->stmt, "unsupported use of reduction.\n");
792 : : break;
793 : :
794 : 1931 : case vect_nested_cycle:
795 : 1931 : if (relevant != vect_unused_in_scope
796 : 1931 : && relevant != vect_used_in_outer_by_reduction
797 : 1429 : && relevant != vect_used_in_outer)
798 : 2 : return opt_result::failure_at
799 : 2 : (stmt_vinfo->stmt, "unsupported use of nested cycle.\n");
800 : : break;
801 : :
802 : 1025 : case vect_double_reduction_def:
803 : 1025 : if (relevant != vect_unused_in_scope
804 : 1025 : && relevant != vect_used_by_reduction
805 : 345 : && relevant != vect_used_only_live)
806 : 0 : return opt_result::failure_at
807 : 0 : (stmt_vinfo->stmt, "unsupported use of double reduction.\n");
808 : : break;
809 : :
810 : : default:
811 : : break;
812 : : }
813 : :
814 : 2414382 : if (is_pattern_stmt_p (stmt_vinfo))
815 : : {
816 : : /* Pattern statements are not inserted into the code, so
817 : : FOR_EACH_PHI_OR_STMT_USE optimizes their operands out, and we
818 : : have to scan the RHS or function arguments instead. */
819 : 431386 : if (gassign *assign = dyn_cast <gassign *> (stmt_vinfo->stmt))
820 : : {
821 : 272810 : enum tree_code rhs_code = gimple_assign_rhs_code (assign);
822 : 272810 : tree op = gimple_assign_rhs1 (assign);
823 : :
824 : 272810 : i = 1;
825 : 272810 : if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op))
826 : : {
827 : 0 : opt_result res
828 : 0 : = process_use (stmt_vinfo, TREE_OPERAND (op, 0),
829 : : loop_vinfo, relevant, &worklist, false);
830 : 0 : if (!res)
831 : 0 : return res;
832 : 0 : res = process_use (stmt_vinfo, TREE_OPERAND (op, 1),
833 : : loop_vinfo, relevant, &worklist, false);
834 : 0 : if (!res)
835 : 0 : return res;
836 : : i = 2;
837 : : }
838 : 796330 : for (; i < gimple_num_ops (assign); i++)
839 : : {
840 : 523878 : op = gimple_op (assign, i);
841 : 523878 : if (TREE_CODE (op) == SSA_NAME)
842 : : {
843 : 399593 : opt_result res
844 : 399593 : = process_use (stmt_vinfo, op, loop_vinfo, relevant,
845 : : &worklist, false);
846 : 399593 : if (!res)
847 : 358 : return res;
848 : : }
849 : : }
850 : : }
851 : 158576 : else if (gcond *cond = dyn_cast <gcond *> (stmt_vinfo->stmt))
852 : : {
853 : 154600 : tree_code rhs_code = gimple_cond_code (cond);
854 : 154600 : gcc_assert (TREE_CODE_CLASS (rhs_code) == tcc_comparison);
855 : 154600 : opt_result res
856 : 154600 : = process_use (stmt_vinfo, gimple_cond_lhs (cond),
857 : : loop_vinfo, relevant, &worklist, false);
858 : 154600 : if (!res)
859 : 8522 : return res;
860 : 154600 : res = process_use (stmt_vinfo, gimple_cond_rhs (cond),
861 : : loop_vinfo, relevant, &worklist, false);
862 : 154600 : if (!res)
863 : 0 : return res;
864 : : }
865 : 3976 : else if (gcall *call = dyn_cast <gcall *> (stmt_vinfo->stmt))
866 : : {
867 : 19128 : for (i = 0; i < gimple_call_num_args (call); i++)
868 : : {
869 : 15152 : tree arg = gimple_call_arg (call, i);
870 : 15152 : opt_result res
871 : 15152 : = process_use (stmt_vinfo, arg, loop_vinfo, relevant,
872 : : &worklist, false);
873 : 15152 : if (!res)
874 : 0 : return res;
875 : : }
876 : : }
877 : : else
878 : 0 : gcc_unreachable ();
879 : : }
880 : : else
881 : 6954294 : FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE)
882 : : {
883 : 2995599 : tree op = USE_FROM_PTR (use_p);
884 : 2995599 : opt_result res
885 : 2995599 : = process_use (stmt_vinfo, op, loop_vinfo, relevant,
886 : : &worklist, false);
887 : 2995599 : if (!res)
888 : 7297 : return res;
889 : : }
890 : :
891 : 2406727 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo))
892 : : {
893 : 28923 : gather_scatter_info gs_info;
894 : 28923 : if (!vect_check_gather_scatter (stmt_vinfo,
895 : : STMT_VINFO_VECTYPE (stmt_vinfo),
896 : : loop_vinfo, &gs_info))
897 : 0 : gcc_unreachable ();
898 : 28923 : opt_result res
899 : 28923 : = process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
900 : : &worklist, true);
901 : 28923 : if (!res)
902 : : {
903 : 865 : if (fatal)
904 : 865 : *fatal = false;
905 : 865 : return res;
906 : : }
907 : : }
908 : : } /* while worklist */
909 : :
910 : 298892 : return opt_result::success ();
911 : 312431 : }
912 : :
913 : : /* Function vect_model_simple_cost.
914 : :
915 : : Models cost for simple operations, i.e. those that only emit N operations
916 : : of the same KIND. */
917 : :
918 : : static void
919 : 585687 : vect_model_simple_cost (vec_info *vinfo, int n, slp_tree node,
920 : : stmt_vector_for_cost *cost_vec,
921 : : vect_cost_for_stmt kind = vector_stmt)
922 : : {
923 : 585687 : int inside_cost = 0, prologue_cost = 0;
924 : :
925 : 585687 : gcc_assert (cost_vec != NULL);
926 : :
927 : 585687 : n *= vect_get_num_copies (vinfo, node);
928 : :
929 : : /* Pass the inside-of-loop statements to the target-specific cost model. */
930 : 585687 : inside_cost += record_stmt_cost (cost_vec, n, kind, node, 0, vect_body);
931 : :
932 : 585687 : if (dump_enabled_p ())
933 : 30535 : dump_printf_loc (MSG_NOTE, vect_location,
934 : : "vect_model_simple_cost: inside_cost = %d, "
935 : : "prologue_cost = %d .\n", inside_cost, prologue_cost);
936 : 585687 : }
937 : :
938 : :
939 : : /* Model cost for type demotion and promotion operations. PWR is
940 : : normally zero for single-step promotions and demotions. It will be
941 : : one if two-step promotion/demotion is required, and so on. NCOPIES
942 : : is the number of vector results (and thus number of instructions)
943 : : for the narrowest end of the operation chain. Each additional
944 : : step doubles the number of instructions required. If WIDEN_ARITH
945 : : is true the stmt is doing widening arithmetic. */
946 : :
947 : : static void
948 : 46478 : vect_model_promotion_demotion_cost (slp_tree slp_node,
949 : : unsigned int ncopies, int pwr,
950 : : stmt_vector_for_cost *cost_vec,
951 : : bool widen_arith)
952 : : {
953 : 46478 : int i;
954 : 46478 : int inside_cost = 0, prologue_cost = 0;
955 : :
956 : 110632 : for (i = 0; i < pwr + 1; i++)
957 : : {
958 : 126406 : inside_cost += record_stmt_cost (cost_vec, ncopies,
959 : : widen_arith
960 : : ? vector_stmt : vec_promote_demote,
961 : : slp_node, 0, vect_body);
962 : 64154 : ncopies *= 2;
963 : : }
964 : :
965 : 46478 : if (dump_enabled_p ())
966 : 6038 : dump_printf_loc (MSG_NOTE, vect_location,
967 : : "vect_model_promotion_demotion_cost: inside_cost = %d, "
968 : : "prologue_cost = %d .\n", inside_cost, prologue_cost);
969 : 46478 : }
970 : :
971 : : /* Returns true if the current function returns DECL. */
972 : :
973 : : static bool
974 : 545648 : cfun_returns (tree decl)
975 : : {
976 : 545648 : edge_iterator ei;
977 : 545648 : edge e;
978 : 1073903 : FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
979 : : {
980 : 1080490 : greturn *ret = safe_dyn_cast <greturn *> (*gsi_last_bb (e->src));
981 : 540245 : if (!ret)
982 : 0 : continue;
983 : 540245 : if (gimple_return_retval (ret) == decl)
984 : : return true;
985 : : /* We often end up with an aggregate copy to the result decl,
986 : : handle that case as well. First skip intermediate clobbers
987 : : though. */
988 : : gimple *def = ret;
989 : 1578665 : do
990 : : {
991 : 3157330 : def = SSA_NAME_DEF_STMT (gimple_vuse (def));
992 : : }
993 : 1578665 : while (gimple_clobber_p (def));
994 : 529017 : if (is_a <gassign *> (def)
995 : 62218 : && gimple_assign_lhs (def) == gimple_return_retval (ret)
996 : 537133 : && gimple_assign_rhs1 (def) == decl)
997 : : return true;
998 : : }
999 : : return false;
1000 : : }
1001 : :
1002 : : /* Calculate cost of DR's memory access. */
1003 : : void
1004 : 905906 : vect_get_store_cost (vec_info *, stmt_vec_info stmt_info, slp_tree slp_node,
1005 : : int ncopies, dr_alignment_support alignment_support_scheme,
1006 : : int misalignment,
1007 : : unsigned int *inside_cost,
1008 : : stmt_vector_for_cost *body_cost_vec)
1009 : : {
1010 : 905906 : tree vectype
1011 : 905906 : = slp_node ? SLP_TREE_VECTYPE (slp_node) : STMT_VINFO_VECTYPE (stmt_info);
1012 : 905906 : switch (alignment_support_scheme)
1013 : : {
1014 : 484253 : case dr_aligned:
1015 : 484253 : {
1016 : 484253 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1017 : : vector_store, stmt_info, slp_node,
1018 : : vectype, 0, vect_body);
1019 : :
1020 : 484253 : if (dump_enabled_p ())
1021 : 13162 : dump_printf_loc (MSG_NOTE, vect_location,
1022 : : "vect_model_store_cost: aligned.\n");
1023 : : break;
1024 : : }
1025 : :
1026 : 421653 : case dr_unaligned_supported:
1027 : 421653 : {
1028 : : /* Here, we assign an additional cost for the unaligned store. */
1029 : 421653 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1030 : : unaligned_store, stmt_info, slp_node,
1031 : : vectype, misalignment, vect_body);
1032 : 421653 : if (dump_enabled_p ())
1033 : 12104 : dump_printf_loc (MSG_NOTE, vect_location,
1034 : : "vect_model_store_cost: unaligned supported by "
1035 : : "hardware.\n");
1036 : : break;
1037 : : }
1038 : :
1039 : 0 : case dr_unaligned_unsupported:
1040 : 0 : {
1041 : 0 : *inside_cost = VECT_MAX_COST;
1042 : :
1043 : 0 : if (dump_enabled_p ())
1044 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1045 : : "vect_model_store_cost: unsupported access.\n");
1046 : : break;
1047 : : }
1048 : :
1049 : 0 : default:
1050 : 0 : gcc_unreachable ();
1051 : : }
1052 : 905906 : }
1053 : :
1054 : : /* Calculate cost of DR's memory access. */
1055 : : void
1056 : 738623 : vect_get_load_cost (vec_info *, stmt_vec_info stmt_info, slp_tree slp_node,
1057 : : int ncopies, dr_alignment_support alignment_support_scheme,
1058 : : int misalignment,
1059 : : bool add_realign_cost, unsigned int *inside_cost,
1060 : : unsigned int *prologue_cost,
1061 : : stmt_vector_for_cost *prologue_cost_vec,
1062 : : stmt_vector_for_cost *body_cost_vec,
1063 : : bool record_prologue_costs)
1064 : : {
1065 : 738623 : tree vectype
1066 : 738623 : = slp_node ? SLP_TREE_VECTYPE (slp_node) : STMT_VINFO_VECTYPE (stmt_info);
1067 : 738623 : switch (alignment_support_scheme)
1068 : : {
1069 : 433774 : case dr_aligned:
1070 : 433774 : {
1071 : 433774 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load,
1072 : : stmt_info, slp_node, vectype,
1073 : : 0, vect_body);
1074 : :
1075 : 433774 : if (dump_enabled_p ())
1076 : 17160 : dump_printf_loc (MSG_NOTE, vect_location,
1077 : : "vect_model_load_cost: aligned.\n");
1078 : :
1079 : : break;
1080 : : }
1081 : 254511 : case dr_unaligned_supported:
1082 : 254511 : {
1083 : : /* Here, we assign an additional cost for the unaligned load. */
1084 : 254511 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1085 : : unaligned_load, stmt_info, slp_node,
1086 : : vectype, misalignment, vect_body);
1087 : :
1088 : 254511 : if (dump_enabled_p ())
1089 : 20034 : dump_printf_loc (MSG_NOTE, vect_location,
1090 : : "vect_model_load_cost: unaligned supported by "
1091 : : "hardware.\n");
1092 : :
1093 : : break;
1094 : : }
1095 : 0 : case dr_explicit_realign:
1096 : 0 : {
1097 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies * 2,
1098 : : vector_load, stmt_info, slp_node,
1099 : : vectype, 0, vect_body);
1100 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1101 : : vec_perm, stmt_info, slp_node,
1102 : : vectype, 0, vect_body);
1103 : :
1104 : : /* FIXME: If the misalignment remains fixed across the iterations of
1105 : : the containing loop, the following cost should be added to the
1106 : : prologue costs. */
1107 : 0 : if (targetm.vectorize.builtin_mask_for_load)
1108 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, 1, vector_stmt,
1109 : : stmt_info, slp_node, vectype,
1110 : : 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, vectype,
1137 : : 0, vect_prologue);
1138 : 0 : if (targetm.vectorize.builtin_mask_for_load)
1139 : 0 : *prologue_cost += record_stmt_cost (prologue_cost_vec, 1,
1140 : : vector_stmt, stmt_info,
1141 : : slp_node, vectype,
1142 : : 0, vect_prologue);
1143 : : }
1144 : :
1145 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load,
1146 : : stmt_info, slp_node, vectype,
1147 : : 0, vect_body);
1148 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vec_perm,
1149 : : stmt_info, slp_node, vectype,
1150 : : 0, vect_body);
1151 : :
1152 : 0 : if (dump_enabled_p ())
1153 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1154 : : "vect_model_load_cost: explicit realign optimized"
1155 : : "\n");
1156 : :
1157 : : break;
1158 : : }
1159 : :
1160 : 50338 : case dr_unaligned_unsupported:
1161 : 50338 : {
1162 : 50338 : *inside_cost = VECT_MAX_COST;
1163 : :
1164 : 50338 : if (dump_enabled_p ())
1165 : 93 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1166 : : "vect_model_load_cost: unsupported access.\n");
1167 : : break;
1168 : : }
1169 : :
1170 : 0 : default:
1171 : 0 : gcc_unreachable ();
1172 : : }
1173 : 738623 : }
1174 : :
1175 : : /* Insert the new stmt NEW_STMT at *GSI or at the appropriate place in
1176 : : the loop preheader for the vectorized stmt STMT_VINFO. */
1177 : :
1178 : : static void
1179 : 6235 : vect_init_vector_1 (vec_info *vinfo, stmt_vec_info stmt_vinfo, gimple *new_stmt,
1180 : : gimple_stmt_iterator *gsi)
1181 : : {
1182 : 6235 : if (gsi)
1183 : 2953 : vect_finish_stmt_generation (vinfo, stmt_vinfo, new_stmt, gsi);
1184 : : else
1185 : 3282 : vinfo->insert_on_entry (stmt_vinfo, new_stmt);
1186 : :
1187 : 6235 : if (dump_enabled_p ())
1188 : 1723 : dump_printf_loc (MSG_NOTE, vect_location,
1189 : : "created new init_stmt: %G", new_stmt);
1190 : 6235 : }
1191 : :
1192 : : /* Function vect_init_vector.
1193 : :
1194 : : Insert a new stmt (INIT_STMT) that initializes a new variable of type
1195 : : TYPE with the value VAL. If TYPE is a vector type and VAL does not have
1196 : : vector type a vector with all elements equal to VAL is created first.
1197 : : Place the initialization at GSI if it is not NULL. Otherwise, place the
1198 : : initialization at the loop preheader.
1199 : : Return the DEF of INIT_STMT.
1200 : : It will be used in the vectorization of STMT_INFO. */
1201 : :
1202 : : tree
1203 : 4511 : vect_init_vector (vec_info *vinfo, stmt_vec_info stmt_info, tree val, tree type,
1204 : : gimple_stmt_iterator *gsi)
1205 : : {
1206 : 4511 : gimple *init_stmt;
1207 : 4511 : tree new_temp;
1208 : :
1209 : : /* We abuse this function to push sth to a SSA name with initial 'val'. */
1210 : 4511 : if (! useless_type_conversion_p (type, TREE_TYPE (val)))
1211 : : {
1212 : 1372 : gcc_assert (VECTOR_TYPE_P (type));
1213 : 1372 : if (! types_compatible_p (TREE_TYPE (type), TREE_TYPE (val)))
1214 : : {
1215 : : /* Scalar boolean value should be transformed into
1216 : : all zeros or all ones value before building a vector. */
1217 : 18 : if (VECTOR_BOOLEAN_TYPE_P (type))
1218 : : {
1219 : 0 : tree true_val = build_all_ones_cst (TREE_TYPE (type));
1220 : 0 : tree false_val = build_zero_cst (TREE_TYPE (type));
1221 : :
1222 : 0 : if (CONSTANT_CLASS_P (val))
1223 : 0 : val = integer_zerop (val) ? false_val : true_val;
1224 : : else
1225 : : {
1226 : 0 : new_temp = make_ssa_name (TREE_TYPE (type));
1227 : 0 : init_stmt = gimple_build_assign (new_temp, COND_EXPR,
1228 : : val, true_val, false_val);
1229 : 0 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1230 : 0 : val = new_temp;
1231 : : }
1232 : : }
1233 : : else
1234 : : {
1235 : 18 : gimple_seq stmts = NULL;
1236 : 18 : if (! INTEGRAL_TYPE_P (TREE_TYPE (val)))
1237 : 16 : val = gimple_build (&stmts, VIEW_CONVERT_EXPR,
1238 : 16 : TREE_TYPE (type), val);
1239 : : else
1240 : : /* ??? Condition vectorization expects us to do
1241 : : promotion of invariant/external defs. */
1242 : 2 : val = gimple_convert (&stmts, TREE_TYPE (type), val);
1243 : 36 : for (gimple_stmt_iterator gsi2 = gsi_start (stmts);
1244 : 36 : !gsi_end_p (gsi2); )
1245 : : {
1246 : 18 : init_stmt = gsi_stmt (gsi2);
1247 : 18 : gsi_remove (&gsi2, false);
1248 : 18 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1249 : : }
1250 : : }
1251 : : }
1252 : 1372 : val = build_vector_from_val (type, val);
1253 : : }
1254 : :
1255 : 4511 : new_temp = vect_get_new_ssa_name (type, vect_simple_var, "cst_");
1256 : 4511 : init_stmt = gimple_build_assign (new_temp, val);
1257 : 4511 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1258 : 4511 : return new_temp;
1259 : : }
1260 : :
1261 : :
1262 : : /* Get vectorized definitions for OP0 and OP1. */
1263 : :
1264 : : void
1265 : 168662 : vect_get_vec_defs (vec_info *, slp_tree slp_node,
1266 : : tree op0, vec<tree> *vec_oprnds0,
1267 : : tree op1, vec<tree> *vec_oprnds1,
1268 : : tree op2, vec<tree> *vec_oprnds2,
1269 : : tree op3, vec<tree> *vec_oprnds3)
1270 : : {
1271 : 168662 : if (op0)
1272 : 167254 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_oprnds0);
1273 : 168662 : if (op1)
1274 : 126027 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[1], vec_oprnds1);
1275 : 168662 : if (op2)
1276 : 7050 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[2], vec_oprnds2);
1277 : 168662 : if (op3)
1278 : 0 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[3], vec_oprnds3);
1279 : 168662 : }
1280 : :
1281 : : /* Helper function called by vect_finish_replace_stmt and
1282 : : vect_finish_stmt_generation. Set the location of the new
1283 : : statement and create and return a stmt_vec_info for it. */
1284 : :
1285 : : static void
1286 : 1325196 : vect_finish_stmt_generation_1 (vec_info *,
1287 : : stmt_vec_info stmt_info, gimple *vec_stmt)
1288 : : {
1289 : 1325196 : if (dump_enabled_p ())
1290 : 137895 : dump_printf_loc (MSG_NOTE, vect_location, "add new stmt: %G", vec_stmt);
1291 : :
1292 : 1325196 : if (stmt_info)
1293 : : {
1294 : 1294791 : gimple_set_location (vec_stmt, gimple_location (stmt_info->stmt));
1295 : :
1296 : : /* While EH edges will generally prevent vectorization, stmt might
1297 : : e.g. be in a must-not-throw region. Ensure newly created stmts
1298 : : that could throw are part of the same region. */
1299 : 1294791 : int lp_nr = lookup_stmt_eh_lp (stmt_info->stmt);
1300 : 1294791 : if (lp_nr != 0 && stmt_could_throw_p (cfun, vec_stmt))
1301 : 48 : add_stmt_to_eh_lp (vec_stmt, lp_nr);
1302 : : }
1303 : : else
1304 : 30405 : gcc_assert (!stmt_could_throw_p (cfun, vec_stmt));
1305 : 1325196 : }
1306 : :
1307 : : /* Replace the scalar statement STMT_INFO with a new vector statement VEC_STMT,
1308 : : which sets the same scalar result as STMT_INFO did. Create and return a
1309 : : stmt_vec_info for VEC_STMT. */
1310 : :
1311 : : void
1312 : 838 : vect_finish_replace_stmt (vec_info *vinfo,
1313 : : stmt_vec_info stmt_info, gimple *vec_stmt)
1314 : : {
1315 : 838 : gimple *scalar_stmt = vect_orig_stmt (stmt_info)->stmt;
1316 : 838 : gcc_assert (gimple_get_lhs (scalar_stmt) == gimple_get_lhs (vec_stmt));
1317 : :
1318 : 838 : gimple_stmt_iterator gsi = gsi_for_stmt (scalar_stmt);
1319 : 838 : gsi_replace (&gsi, vec_stmt, true);
1320 : :
1321 : 838 : vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt);
1322 : 838 : }
1323 : :
1324 : : /* Add VEC_STMT to the vectorized implementation of STMT_INFO and insert it
1325 : : before *GSI. Create and return a stmt_vec_info for VEC_STMT. */
1326 : :
1327 : : void
1328 : 1324358 : vect_finish_stmt_generation (vec_info *vinfo,
1329 : : stmt_vec_info stmt_info, gimple *vec_stmt,
1330 : : gimple_stmt_iterator *gsi)
1331 : : {
1332 : 1324358 : gcc_assert (!stmt_info || gimple_code (stmt_info->stmt) != GIMPLE_LABEL);
1333 : :
1334 : 1324358 : if (!gsi_end_p (*gsi)
1335 : 2647679 : && gimple_has_mem_ops (vec_stmt))
1336 : : {
1337 : 1323321 : gimple *at_stmt = gsi_stmt (*gsi);
1338 : 1323321 : tree vuse = gimple_vuse (at_stmt);
1339 : 1316713 : if (vuse && TREE_CODE (vuse) == SSA_NAME)
1340 : : {
1341 : 1206680 : tree vdef = gimple_vdef (at_stmt);
1342 : 1206680 : gimple_set_vuse (vec_stmt, gimple_vuse (at_stmt));
1343 : 1206680 : gimple_set_modified (vec_stmt, true);
1344 : : /* If we have an SSA vuse and insert a store, update virtual
1345 : : SSA form to avoid triggering the renamer. Do so only
1346 : : if we can easily see all uses - which is what almost always
1347 : : happens with the way vectorized stmts are inserted. */
1348 : 751441 : if ((vdef && TREE_CODE (vdef) == SSA_NAME)
1349 : 1958085 : && ((is_gimple_assign (vec_stmt)
1350 : 750589 : && !is_gimple_reg (gimple_assign_lhs (vec_stmt)))
1351 : 62991 : || (is_gimple_call (vec_stmt)
1352 : 816 : && (!(gimple_call_flags (vec_stmt)
1353 : 816 : & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
1354 : 1 : || (gimple_call_lhs (vec_stmt)
1355 : 1 : && !is_gimple_reg (gimple_call_lhs (vec_stmt)))))))
1356 : : {
1357 : 689229 : tree new_vdef = copy_ssa_name (vuse, vec_stmt);
1358 : 689229 : gimple_set_vdef (vec_stmt, new_vdef);
1359 : 689229 : SET_USE (gimple_vuse_op (at_stmt), new_vdef);
1360 : : }
1361 : : }
1362 : : }
1363 : 1324358 : gsi_insert_before (gsi, vec_stmt, GSI_SAME_STMT);
1364 : 1324358 : vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt);
1365 : 1324358 : }
1366 : :
1367 : : /* We want to vectorize a call to combined function CFN with function
1368 : : decl FNDECL, using VECTYPE_OUT as the type of the output and VECTYPE_IN
1369 : : as the types of all inputs. Check whether this is possible using
1370 : : an internal function, returning its code if so or IFN_LAST if not. */
1371 : :
1372 : : static internal_fn
1373 : 12009 : vectorizable_internal_function (combined_fn cfn, tree fndecl,
1374 : : tree vectype_out, tree vectype_in)
1375 : : {
1376 : 12009 : internal_fn ifn;
1377 : 12009 : if (internal_fn_p (cfn))
1378 : 9669 : ifn = as_internal_fn (cfn);
1379 : : else
1380 : 2340 : ifn = associated_internal_fn (fndecl);
1381 : 12009 : if (ifn != IFN_LAST && direct_internal_fn_p (ifn))
1382 : : {
1383 : 8579 : const direct_internal_fn_info &info = direct_internal_fn (ifn);
1384 : 8579 : if (info.vectorizable)
1385 : : {
1386 : 8579 : bool same_size_p = TYPE_SIZE (vectype_in) == TYPE_SIZE (vectype_out);
1387 : 8579 : tree type0 = (info.type0 < 0 ? vectype_out : vectype_in);
1388 : 8579 : tree type1 = (info.type1 < 0 ? vectype_out : vectype_in);
1389 : :
1390 : : /* The type size of both the vectype_in and vectype_out should be
1391 : : exactly the same when vectype_out isn't participating the optab.
1392 : : While there is no restriction for type size when vectype_out
1393 : : is part of the optab query. */
1394 : 8579 : if (type0 != vectype_out && type1 != vectype_out && !same_size_p)
1395 : : return IFN_LAST;
1396 : :
1397 : 8559 : if (direct_internal_fn_supported_p (ifn, tree_pair (type0, type1),
1398 : : OPTIMIZE_FOR_SPEED))
1399 : : return ifn;
1400 : : }
1401 : : }
1402 : : return IFN_LAST;
1403 : : }
1404 : :
1405 : :
1406 : : static tree permute_vec_elements (vec_info *, tree, tree, tree, stmt_vec_info,
1407 : : gimple_stmt_iterator *);
1408 : :
1409 : : /* Check whether a load or store statement in the loop described by
1410 : : LOOP_VINFO is possible in a loop using partial vectors. This is
1411 : : testing whether the vectorizer pass has the appropriate support,
1412 : : as well as whether the target does.
1413 : :
1414 : : VLS_TYPE says whether the statement is a load or store and VECTYPE
1415 : : is the type of the vector being loaded or stored. SLP_NODE is the SLP
1416 : : node that contains the statement, or null if none. MEMORY_ACCESS_TYPE
1417 : : says how the load or store is going to be implemented and GROUP_SIZE
1418 : : is the number of load or store statements in the containing group.
1419 : : If the access is a gather load or scatter store, GS_INFO describes
1420 : : its arguments. If the load or store is conditional, SCALAR_MASK is the
1421 : : condition under which it occurs.
1422 : :
1423 : : Clear LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P if a loop using partial
1424 : : vectors is not supported, otherwise record the required rgroup control
1425 : : types.
1426 : :
1427 : : If partial vectors can be used and ELSVALS is nonzero the supported
1428 : : else values will be added to the vector ELSVALS points to. */
1429 : :
1430 : : static void
1431 : 127 : check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype,
1432 : : slp_tree slp_node,
1433 : : vec_load_store_type vls_type,
1434 : : int group_size,
1435 : : vect_load_store_data *ls,
1436 : : slp_tree mask_node,
1437 : : vec<int> *elsvals = nullptr)
1438 : : {
1439 : 127 : vect_memory_access_type memory_access_type = ls->memory_access_type;
1440 : :
1441 : : /* Invariant loads need no special support. */
1442 : 127 : if (memory_access_type == VMAT_INVARIANT)
1443 : 2 : return;
1444 : :
1445 : : /* Figure whether the mask is uniform. scalar_mask is used to
1446 : : populate the scalar_cond_masked_set. */
1447 : 125 : tree scalar_mask = NULL_TREE;
1448 : 125 : if (mask_node)
1449 : 20 : for (unsigned i = 0; i < SLP_TREE_LANES (mask_node); ++i)
1450 : : {
1451 : 14 : tree def = vect_get_slp_scalar_def (mask_node, i);
1452 : 14 : if (!def
1453 : 14 : || (scalar_mask && def != scalar_mask))
1454 : : {
1455 : : scalar_mask = NULL;
1456 : : break;
1457 : : }
1458 : : else
1459 : 10 : scalar_mask = def;
1460 : : }
1461 : :
1462 : 125 : unsigned int nvectors = vect_get_num_copies (loop_vinfo, slp_node);
1463 : 125 : vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
1464 : 125 : vec_loop_lens *lens = &LOOP_VINFO_LENS (loop_vinfo);
1465 : 125 : machine_mode vecmode = TYPE_MODE (vectype);
1466 : 125 : bool is_load = (vls_type == VLS_LOAD);
1467 : 125 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
1468 : : {
1469 : 0 : nvectors /= group_size;
1470 : 0 : internal_fn ifn
1471 : 0 : = (is_load ? vect_load_lanes_supported (vectype, group_size, true,
1472 : : elsvals)
1473 : 0 : : vect_store_lanes_supported (vectype, group_size, true));
1474 : 0 : if (ifn == IFN_MASK_LEN_LOAD_LANES || ifn == IFN_MASK_LEN_STORE_LANES)
1475 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1);
1476 : 0 : else if (ifn == IFN_MASK_LOAD_LANES || ifn == IFN_MASK_STORE_LANES)
1477 : 0 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
1478 : : scalar_mask);
1479 : : else
1480 : : {
1481 : 0 : if (dump_enabled_p ())
1482 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1483 : : "can't operate on partial vectors because"
1484 : : " the target doesn't have an appropriate"
1485 : : " load/store-lanes instruction.\n");
1486 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1487 : : }
1488 : 0 : return;
1489 : : }
1490 : :
1491 : 125 : if (mat_gather_scatter_p (memory_access_type))
1492 : : {
1493 : 0 : internal_fn ifn = (is_load
1494 : 0 : ? IFN_MASK_GATHER_LOAD
1495 : : : IFN_MASK_SCATTER_STORE);
1496 : 0 : internal_fn len_ifn = (is_load
1497 : : ? IFN_MASK_LEN_GATHER_LOAD
1498 : : : IFN_MASK_LEN_SCATTER_STORE);
1499 : 0 : stmt_vec_info repr = SLP_TREE_REPRESENTATIVE (slp_node);
1500 : 0 : tree off_vectype = (STMT_VINFO_GATHER_SCATTER_P (repr)
1501 : 0 : ? SLP_TREE_VECTYPE (SLP_TREE_CHILDREN (slp_node)[0])
1502 : 0 : : ls->strided_offset_vectype);
1503 : 0 : tree memory_type = TREE_TYPE (DR_REF (STMT_VINFO_DR_INFO (repr)->dr));
1504 : 0 : int scale = SLP_TREE_GS_SCALE (slp_node);
1505 : 0 : if (internal_gather_scatter_fn_supported_p (len_ifn, vectype,
1506 : : memory_type,
1507 : : off_vectype, scale,
1508 : : elsvals))
1509 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1);
1510 : 0 : else if (internal_gather_scatter_fn_supported_p (ifn, vectype,
1511 : : memory_type,
1512 : : off_vectype, scale,
1513 : : elsvals)
1514 : 0 : || memory_access_type == VMAT_GATHER_SCATTER_LEGACY)
1515 : 0 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
1516 : : scalar_mask);
1517 : : else
1518 : : {
1519 : 0 : if (dump_enabled_p ())
1520 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1521 : : "can't operate on partial vectors because"
1522 : : " the target doesn't have an appropriate"
1523 : : " gather load or scatter store instruction.\n");
1524 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1525 : : }
1526 : 0 : return;
1527 : : }
1528 : :
1529 : 125 : if (memory_access_type != VMAT_CONTIGUOUS)
1530 : : {
1531 : : /* Element X of the data must come from iteration i * VF + X of the
1532 : : scalar loop. We need more work to support other mappings. */
1533 : 0 : if (dump_enabled_p ())
1534 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1535 : : "can't operate on partial vectors because an"
1536 : : " access isn't contiguous.\n");
1537 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1538 : 0 : return;
1539 : : }
1540 : :
1541 : 125 : if (!VECTOR_MODE_P (vecmode))
1542 : : {
1543 : 0 : if (dump_enabled_p ())
1544 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1545 : : "can't operate on partial vectors when emulating"
1546 : : " vector operations.\n");
1547 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1548 : 0 : return;
1549 : : }
1550 : :
1551 : : /* We might load more scalars than we need for permuting SLP loads.
1552 : : We checked in get_load_store_type that the extra elements
1553 : : don't leak into a new vector. */
1554 : 211 : auto group_memory_nvectors = [](poly_uint64 size, poly_uint64 nunits)
1555 : : {
1556 : 86 : unsigned int nvectors;
1557 : 172 : if (can_div_away_from_zero_p (size, nunits, &nvectors))
1558 : 86 : return nvectors;
1559 : : gcc_unreachable ();
1560 : : };
1561 : :
1562 : 125 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
1563 : 125 : poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
1564 : 125 : machine_mode mask_mode;
1565 : 125 : machine_mode vmode;
1566 : 125 : bool using_partial_vectors_p = false;
1567 : 125 : if (get_len_load_store_mode
1568 : 125 : (vecmode, is_load, nullptr, elsvals).exists (&vmode))
1569 : : {
1570 : 0 : nvectors = group_memory_nvectors (group_size * vf, nunits);
1571 : 0 : unsigned factor = (vecmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vecmode);
1572 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, factor);
1573 : 0 : using_partial_vectors_p = true;
1574 : : }
1575 : 211 : else if (targetm.vectorize.get_mask_mode (vecmode).exists (&mask_mode)
1576 : 125 : && can_vec_mask_load_store_p (vecmode, mask_mode, is_load, NULL,
1577 : : elsvals))
1578 : : {
1579 : 86 : nvectors = group_memory_nvectors (group_size * vf, nunits);
1580 : 86 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, scalar_mask);
1581 : 86 : using_partial_vectors_p = true;
1582 : : }
1583 : :
1584 : 86 : if (!using_partial_vectors_p)
1585 : : {
1586 : 39 : if (dump_enabled_p ())
1587 : 18 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1588 : : "can't operate on partial vectors because the"
1589 : : " target doesn't have the appropriate partial"
1590 : : " vectorization load or store.\n");
1591 : 39 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1592 : : }
1593 : : }
1594 : :
1595 : : /* Return the mask input to a masked load or store. VEC_MASK is the vectorized
1596 : : form of the scalar mask condition and LOOP_MASK, if nonnull, is the mask
1597 : : that needs to be applied to all loads and stores in a vectorized loop.
1598 : : Return VEC_MASK if LOOP_MASK is null or if VEC_MASK is already masked,
1599 : : otherwise return VEC_MASK & LOOP_MASK.
1600 : :
1601 : : MASK_TYPE is the type of both masks. If new statements are needed,
1602 : : insert them before GSI. */
1603 : :
1604 : : tree
1605 : 1443 : prepare_vec_mask (loop_vec_info loop_vinfo, tree mask_type, tree loop_mask,
1606 : : tree vec_mask, gimple_stmt_iterator *gsi)
1607 : : {
1608 : 1443 : gcc_assert (useless_type_conversion_p (mask_type, TREE_TYPE (vec_mask)));
1609 : 1443 : if (!loop_mask)
1610 : : return vec_mask;
1611 : :
1612 : 102 : gcc_assert (TREE_TYPE (loop_mask) == mask_type);
1613 : :
1614 : 102 : if (loop_vinfo->vec_cond_masked_set.contains ({ vec_mask, loop_mask }))
1615 : : return vec_mask;
1616 : :
1617 : 102 : tree and_res = make_temp_ssa_name (mask_type, NULL, "vec_mask_and");
1618 : 102 : gimple *and_stmt = gimple_build_assign (and_res, BIT_AND_EXPR,
1619 : : vec_mask, loop_mask);
1620 : :
1621 : 102 : gsi_insert_before (gsi, and_stmt, GSI_SAME_STMT);
1622 : 102 : return and_res;
1623 : : }
1624 : :
1625 : : /* Determine whether we can use a gather load or scatter store to vectorize
1626 : : strided load or store STMT_INFO by truncating the current offset to a
1627 : : smaller width. We need to be able to construct an offset vector:
1628 : :
1629 : : { 0, X, X*2, X*3, ... }
1630 : :
1631 : : without loss of precision, where X is STMT_INFO's DR_STEP.
1632 : :
1633 : : Return true if this is possible, describing the gather load or scatter
1634 : : store in GS_INFO. MASKED_P is true if the load or store is conditional.
1635 : :
1636 : : If we can use gather/scatter and ELSVALS is nonzero the supported
1637 : : else values will be stored in the vector ELSVALS points to. */
1638 : :
1639 : : static bool
1640 : 58938 : vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info, tree vectype,
1641 : : loop_vec_info loop_vinfo, bool masked_p,
1642 : : gather_scatter_info *gs_info,
1643 : : vec<int> *elsvals)
1644 : : {
1645 : 58938 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1646 : 58938 : data_reference *dr = dr_info->dr;
1647 : 58938 : tree step = DR_STEP (dr);
1648 : 58938 : if (TREE_CODE (step) != INTEGER_CST)
1649 : : {
1650 : : /* ??? Perhaps we could use range information here? */
1651 : 29119 : if (dump_enabled_p ())
1652 : 233 : dump_printf_loc (MSG_NOTE, vect_location,
1653 : : "cannot truncate variable step.\n");
1654 : 29119 : return false;
1655 : : }
1656 : :
1657 : : /* Get the number of bits in an element. */
1658 : 29819 : scalar_mode element_mode = SCALAR_TYPE_MODE (TREE_TYPE (vectype));
1659 : 29819 : unsigned int element_bits = GET_MODE_BITSIZE (element_mode);
1660 : :
1661 : : /* Set COUNT to the upper limit on the number of elements - 1.
1662 : : Start with the maximum vectorization factor. */
1663 : 29819 : unsigned HOST_WIDE_INT count = vect_max_vf (loop_vinfo) - 1;
1664 : :
1665 : : /* Try lowering COUNT to the number of scalar latch iterations. */
1666 : 29819 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
1667 : 29819 : widest_int max_iters;
1668 : 29819 : if (max_loop_iterations (loop, &max_iters)
1669 : 59638 : && max_iters < count)
1670 : 2280 : count = max_iters.to_shwi ();
1671 : :
1672 : : /* Try scales of 1 and the element size. */
1673 : 29819 : unsigned int scales[] = { 1, vect_get_scalar_dr_size (dr_info) };
1674 : 29819 : wi::overflow_type overflow = wi::OVF_NONE;
1675 : 89457 : for (int i = 0; i < 2; ++i)
1676 : : {
1677 : 59638 : unsigned int scale = scales[i];
1678 : 59638 : widest_int factor;
1679 : 59638 : if (!wi::multiple_of_p (wi::to_widest (step), scale, SIGNED, &factor))
1680 : 0 : continue;
1681 : :
1682 : : /* Determine the minimum precision of (COUNT - 1) * STEP / SCALE. */
1683 : 59638 : widest_int range = wi::mul (count, factor, SIGNED, &overflow);
1684 : 59638 : if (overflow)
1685 : 0 : continue;
1686 : 59638 : signop sign = range >= 0 ? UNSIGNED : SIGNED;
1687 : 59638 : unsigned int min_offset_bits = wi::min_precision (range, sign);
1688 : :
1689 : : /* Find the narrowest viable offset type. */
1690 : 59638 : unsigned int offset_bits = 1U << ceil_log2 (min_offset_bits);
1691 : 59638 : tree offset_type = build_nonstandard_integer_type (offset_bits,
1692 : : sign == UNSIGNED);
1693 : :
1694 : : /* See whether the target supports the operation with an offset
1695 : : no narrower than OFFSET_TYPE. */
1696 : 59638 : tree memory_type = TREE_TYPE (DR_REF (dr));
1697 : 59638 : if (!vect_gather_scatter_fn_p (loop_vinfo, DR_IS_READ (dr), masked_p,
1698 : : vectype, memory_type, offset_type, scale,
1699 : : &gs_info->ifn, &gs_info->offset_vectype,
1700 : : elsvals)
1701 : 59638 : || gs_info->ifn == IFN_LAST)
1702 : 59638 : continue;
1703 : :
1704 : 0 : gs_info->decl = NULL_TREE;
1705 : : /* Logically the sum of DR_BASE_ADDRESS, DR_INIT and DR_OFFSET,
1706 : : but we don't need to store that here. */
1707 : 0 : gs_info->base = NULL_TREE;
1708 : 0 : gs_info->alias_ptr = build_int_cst
1709 : 0 : (reference_alias_ptr_type (DR_REF (dr)),
1710 : 0 : get_object_alignment (DR_REF (dr)));
1711 : 0 : gs_info->element_type = TREE_TYPE (vectype);
1712 : 0 : gs_info->offset = fold_convert (offset_type, step);
1713 : 0 : gs_info->scale = scale;
1714 : 0 : gs_info->memory_type = memory_type;
1715 : 0 : return true;
1716 : 119276 : }
1717 : :
1718 : 29819 : if (overflow && dump_enabled_p ())
1719 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1720 : : "truncating gather/scatter offset to %d bits"
1721 : : " might change its value.\n", element_bits);
1722 : :
1723 : : return false;
1724 : 29819 : }
1725 : :
1726 : : /* Return true if we can use gather/scatter internal functions to
1727 : : vectorize STMT_INFO, which is a grouped or strided load or store.
1728 : : MASKED_P is true if load or store is conditional. When returning
1729 : : true, fill in GS_INFO with the information required to perform the
1730 : : operation.
1731 : :
1732 : : If we can use gather/scatter and ELSVALS is nonzero the supported
1733 : : else values will be stored in the vector ELSVALS points to. */
1734 : :
1735 : : static bool
1736 : 58938 : vect_use_strided_gather_scatters_p (stmt_vec_info stmt_info, tree vectype,
1737 : : loop_vec_info loop_vinfo, bool masked_p,
1738 : : gather_scatter_info *gs_info,
1739 : : vec<int> *elsvals,
1740 : : unsigned int group_size,
1741 : : bool single_element_p)
1742 : : {
1743 : 58938 : if (!vect_check_gather_scatter (stmt_info, vectype,
1744 : : loop_vinfo, gs_info, elsvals)
1745 : 58938 : || gs_info->ifn == IFN_LAST)
1746 : : {
1747 : 58938 : if (!vect_truncate_gather_scatter_offset (stmt_info, vectype, loop_vinfo,
1748 : : masked_p, gs_info, elsvals))
1749 : : return false;
1750 : : }
1751 : : else
1752 : : {
1753 : 0 : tree old_offset_type = TREE_TYPE (gs_info->offset);
1754 : 0 : tree new_offset_type = TREE_TYPE (gs_info->offset_vectype);
1755 : :
1756 : 0 : gcc_assert (TYPE_PRECISION (new_offset_type)
1757 : : >= TYPE_PRECISION (old_offset_type));
1758 : 0 : gs_info->offset = fold_convert (new_offset_type, gs_info->offset);
1759 : : }
1760 : :
1761 : 0 : if (!single_element_p
1762 : 0 : && !targetm.vectorize.prefer_gather_scatter (TYPE_MODE (vectype),
1763 : : gs_info->scale,
1764 : : group_size))
1765 : : return false;
1766 : :
1767 : 0 : if (dump_enabled_p ())
1768 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1769 : : "using gather/scatter for strided/grouped access,"
1770 : : " scale = %d\n", gs_info->scale);
1771 : :
1772 : : return true;
1773 : : }
1774 : :
1775 : : /* STMT_INFO is a non-strided load or store, meaning that it accesses
1776 : : elements with a known constant step. Return -1 if that step
1777 : : is negative, 0 if it is zero, and 1 if it is greater than zero. */
1778 : :
1779 : : int
1780 : 1332412 : compare_step_with_zero (vec_info *vinfo, stmt_vec_info stmt_info)
1781 : : {
1782 : 1332412 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1783 : 1332412 : return tree_int_cst_compare (vect_dr_behavior (vinfo, dr_info)->step,
1784 : 1332412 : size_zero_node);
1785 : : }
1786 : :
1787 : : /* If the target supports a permute mask that reverses the elements in
1788 : : a vector of type VECTYPE, return that mask, otherwise return null. */
1789 : :
1790 : : tree
1791 : 8808 : perm_mask_for_reverse (tree vectype)
1792 : : {
1793 : 8808 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
1794 : :
1795 : : /* The encoding has a single stepped pattern. */
1796 : 8808 : vec_perm_builder sel (nunits, 1, 3);
1797 : 35232 : for (int i = 0; i < 3; ++i)
1798 : 26424 : sel.quick_push (nunits - 1 - i);
1799 : :
1800 : 8808 : vec_perm_indices indices (sel, 1, nunits);
1801 : 8808 : if (!can_vec_perm_const_p (TYPE_MODE (vectype), TYPE_MODE (vectype),
1802 : : indices))
1803 : : return NULL_TREE;
1804 : 7764 : return vect_gen_perm_mask_checked (vectype, indices);
1805 : 8808 : }
1806 : :
1807 : : /* A subroutine of get_load_store_type, with a subset of the same
1808 : : arguments. Handle the case where STMT_INFO is a load or store that
1809 : : accesses consecutive elements with a negative step. Sets *POFFSET
1810 : : to the offset to be applied to the DR for the first access. */
1811 : :
1812 : : static vect_memory_access_type
1813 : 10056 : get_negative_load_store_type (vec_info *vinfo,
1814 : : stmt_vec_info stmt_info, tree vectype,
1815 : : vec_load_store_type vls_type,
1816 : : unsigned int ncopies, poly_int64 *poffset)
1817 : : {
1818 : 10056 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1819 : 10056 : dr_alignment_support alignment_support_scheme;
1820 : :
1821 : 10056 : if (ncopies > 1)
1822 : : {
1823 : 0 : if (dump_enabled_p ())
1824 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1825 : : "multiple types with negative step.\n");
1826 : 0 : return VMAT_ELEMENTWISE;
1827 : : }
1828 : :
1829 : : /* For backward running DRs the first access in vectype actually is
1830 : : N-1 elements before the address of the DR. */
1831 : 10056 : *poffset = ((-TYPE_VECTOR_SUBPARTS (vectype) + 1)
1832 : 10056 : * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype))));
1833 : :
1834 : 10056 : int misalignment = dr_misalignment (dr_info, vectype, *poffset);
1835 : 10056 : alignment_support_scheme
1836 : 10056 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype, misalignment);
1837 : 10056 : if (alignment_support_scheme != dr_aligned
1838 : 10056 : && alignment_support_scheme != dr_unaligned_supported)
1839 : : {
1840 : 3092 : if (dump_enabled_p ())
1841 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1842 : : "negative step but alignment required.\n");
1843 : 3092 : *poffset = 0;
1844 : 3092 : return VMAT_ELEMENTWISE;
1845 : : }
1846 : :
1847 : 6964 : if (vls_type == VLS_STORE_INVARIANT)
1848 : : {
1849 : 711 : if (dump_enabled_p ())
1850 : 21 : dump_printf_loc (MSG_NOTE, vect_location,
1851 : : "negative step with invariant source;"
1852 : : " no permute needed.\n");
1853 : 711 : return VMAT_CONTIGUOUS_DOWN;
1854 : : }
1855 : :
1856 : 6253 : if (!perm_mask_for_reverse (vectype))
1857 : : {
1858 : 1044 : if (dump_enabled_p ())
1859 : 50 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1860 : : "negative step and reversing not supported.\n");
1861 : 1044 : *poffset = 0;
1862 : 1044 : return VMAT_ELEMENTWISE;
1863 : : }
1864 : :
1865 : : return VMAT_CONTIGUOUS_REVERSE;
1866 : : }
1867 : :
1868 : : /* STMT_INFO is either a masked or unconditional store. Return the value
1869 : : being stored. */
1870 : :
1871 : : tree
1872 : 0 : vect_get_store_rhs (stmt_vec_info stmt_info)
1873 : : {
1874 : 0 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
1875 : : {
1876 : 0 : gcc_assert (gimple_assign_single_p (assign));
1877 : 0 : return gimple_assign_rhs1 (assign);
1878 : : }
1879 : 0 : if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt))
1880 : : {
1881 : 0 : internal_fn ifn = gimple_call_internal_fn (call);
1882 : 0 : int index = internal_fn_stored_value_index (ifn);
1883 : 0 : gcc_assert (index >= 0);
1884 : 0 : return gimple_call_arg (call, index);
1885 : : }
1886 : 0 : gcc_unreachable ();
1887 : : }
1888 : :
1889 : : /* Function VECTOR_VECTOR_COMPOSITION_TYPE
1890 : :
1891 : : This function returns a vector type which can be composed with NETLS pieces,
1892 : : whose type is recorded in PTYPE. VTYPE should be a vector type, and has the
1893 : : same vector size as the return vector. It checks target whether supports
1894 : : pieces-size vector mode for construction firstly, if target fails to, check
1895 : : pieces-size scalar mode for construction further. It returns NULL_TREE if
1896 : : fails to find the available composition.
1897 : :
1898 : : For example, for (vtype=V16QI, nelts=4), we can probably get:
1899 : : - V16QI with PTYPE V4QI.
1900 : : - V4SI with PTYPE SI.
1901 : : - NULL_TREE. */
1902 : :
1903 : : static tree
1904 : 9525 : vector_vector_composition_type (tree vtype, poly_uint64 nelts, tree *ptype)
1905 : : {
1906 : 9525 : gcc_assert (VECTOR_TYPE_P (vtype));
1907 : 9525 : gcc_assert (known_gt (nelts, 0U));
1908 : :
1909 : 9525 : machine_mode vmode = TYPE_MODE (vtype);
1910 : 9525 : if (!VECTOR_MODE_P (vmode))
1911 : : return NULL_TREE;
1912 : :
1913 : : /* When we are asked to compose the vector from its components let
1914 : : that happen directly. */
1915 : 9525 : if (known_eq (TYPE_VECTOR_SUBPARTS (vtype), nelts))
1916 : : {
1917 : 5142 : *ptype = TREE_TYPE (vtype);
1918 : 5142 : return vtype;
1919 : : }
1920 : :
1921 : 8766 : poly_uint64 vbsize = GET_MODE_BITSIZE (vmode);
1922 : 4383 : unsigned int pbsize;
1923 : 4383 : if (constant_multiple_p (vbsize, nelts, &pbsize))
1924 : : {
1925 : : /* First check if vec_init optab supports construction from
1926 : : vector pieces directly. */
1927 : 4383 : scalar_mode elmode = SCALAR_TYPE_MODE (TREE_TYPE (vtype));
1928 : 8766 : poly_uint64 inelts = pbsize / GET_MODE_BITSIZE (elmode);
1929 : 4383 : machine_mode rmode;
1930 : 4383 : if (related_vector_mode (vmode, elmode, inelts).exists (&rmode)
1931 : 3935 : && (convert_optab_handler (vec_init_optab, vmode, rmode)
1932 : : != CODE_FOR_nothing))
1933 : : {
1934 : 3309 : *ptype = build_vector_type (TREE_TYPE (vtype), inelts);
1935 : 3309 : return vtype;
1936 : : }
1937 : :
1938 : : /* Otherwise check if exists an integer type of the same piece size and
1939 : : if vec_init optab supports construction from it directly. */
1940 : 1074 : if (int_mode_for_size (pbsize, 0).exists (&elmode)
1941 : 1074 : && related_vector_mode (vmode, elmode, nelts).exists (&rmode)
1942 : 1032 : && (convert_optab_handler (vec_init_optab, rmode, elmode)
1943 : : != CODE_FOR_nothing))
1944 : : {
1945 : 1032 : *ptype = build_nonstandard_integer_type (pbsize, 1);
1946 : 1032 : return build_vector_type (*ptype, nelts);
1947 : : }
1948 : : }
1949 : :
1950 : : return NULL_TREE;
1951 : : }
1952 : :
1953 : : /* Analyze load or store SLP_NODE of type VLS_TYPE. Return true
1954 : : if there is a memory access type that the vectorized form can use,
1955 : : storing it in *MEMORY_ACCESS_TYPE if so. If we decide to use gathers
1956 : : or scatters, fill in GS_INFO accordingly. In addition
1957 : : *ALIGNMENT_SUPPORT_SCHEME is filled out and false is returned if
1958 : : the target does not support the alignment scheme. *MISALIGNMENT
1959 : : is set according to the alignment of the access (including
1960 : : DR_MISALIGNMENT_UNKNOWN when it is unknown).
1961 : :
1962 : : MASKED_P is true if the statement is conditional on a vectorized mask.
1963 : : VECTYPE is the vector type that the vectorized statements will use.
1964 : :
1965 : : If ELSVALS is nonzero the supported else values will be stored in the
1966 : : vector ELSVALS points to.
1967 : :
1968 : : For loads PERM_OK indicates whether we can code generate a
1969 : : SLP_TREE_LOAD_PERMUTATION on the node. */
1970 : :
1971 : : static bool
1972 : 1242192 : get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
1973 : : tree vectype, slp_tree slp_node,
1974 : : bool masked_p, vec_load_store_type vls_type,
1975 : : bool perm_ok, vect_load_store_data *ls)
1976 : : {
1977 : 1242192 : vect_memory_access_type *memory_access_type = &ls->memory_access_type;
1978 : 1242192 : poly_int64 *poffset = &ls->poffset;
1979 : 1242192 : dr_alignment_support *alignment_support_scheme
1980 : : = &ls->alignment_support_scheme;
1981 : 1242192 : int *misalignment = &ls->misalignment;
1982 : 1242192 : internal_fn *lanes_ifn = &ls->lanes_ifn;
1983 : 1242192 : vec<int> *elsvals = &ls->elsvals;
1984 : 1242192 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
1985 : 1242192 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
1986 : 1242192 : class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
1987 : 1242192 : stmt_vec_info first_stmt_info;
1988 : 1242192 : unsigned int group_size;
1989 : 1242192 : unsigned HOST_WIDE_INT gap;
1990 : 1242192 : bool single_element_p;
1991 : 1242192 : poly_int64 neg_ldst_offset = 0;
1992 : :
1993 : 1242192 : *misalignment = DR_MISALIGNMENT_UNKNOWN;
1994 : 1242192 : *poffset = 0;
1995 : :
1996 : 1242192 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
1997 : : {
1998 : 870091 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
1999 : 870091 : group_size = DR_GROUP_SIZE (first_stmt_info);
2000 : 870091 : gap = DR_GROUP_GAP (first_stmt_info);
2001 : 870091 : single_element_p = (stmt_info == first_stmt_info
2002 : 870091 : && !DR_GROUP_NEXT_ELEMENT (stmt_info));
2003 : : }
2004 : : else
2005 : : {
2006 : : first_stmt_info = stmt_info;
2007 : : group_size = 1;
2008 : : gap = 0;
2009 : : single_element_p = true;
2010 : : }
2011 : 1242192 : dr_vec_info *first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
2012 : :
2013 : : /* True if the vectorized statements would access beyond the last
2014 : : statement in the group. */
2015 : 1242192 : bool overrun_p = false;
2016 : :
2017 : : /* True if we can cope with such overrun by peeling for gaps, so that
2018 : : there is at least one final scalar iteration after the vector loop. */
2019 : 2484384 : bool can_overrun_p = (!masked_p
2020 : 1242192 : && vls_type == VLS_LOAD
2021 : 462721 : && loop_vinfo
2022 : 1572268 : && !loop->inner);
2023 : :
2024 : : /* There can only be a gap at the end of the group if the stride is
2025 : : known at compile time. */
2026 : 1242192 : gcc_assert (!STMT_VINFO_STRIDED_P (first_stmt_info) || gap == 0);
2027 : :
2028 : : /* For SLP vectorization we directly vectorize a subchain
2029 : : without permutation. */
2030 : 1242192 : if (! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
2031 : 1181677 : first_dr_info = STMT_VINFO_DR_INFO (SLP_TREE_SCALAR_STMTS (slp_node)[0]);
2032 : :
2033 : 1242192 : if (STMT_VINFO_STRIDED_P (first_stmt_info))
2034 : : /* Try to use consecutive accesses of as many elements as possible,
2035 : : separated by the stride, until we have a complete vector.
2036 : : Fall back to scalar accesses if that isn't possible. */
2037 : 45190 : *memory_access_type = VMAT_STRIDED_SLP;
2038 : 1197002 : else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
2039 : : {
2040 : 7355 : slp_tree offset_node = SLP_TREE_CHILDREN (slp_node)[0];
2041 : 7355 : tree offset_vectype = SLP_TREE_VECTYPE (offset_node);
2042 : 7355 : int scale = SLP_TREE_GS_SCALE (slp_node);
2043 : 7355 : tree memory_type = TREE_TYPE (DR_REF (first_dr_info->dr));
2044 : 7355 : tree tem;
2045 : 7355 : if (vect_gather_scatter_fn_p (loop_vinfo, vls_type == VLS_LOAD,
2046 : : masked_p, vectype,
2047 : : memory_type,
2048 : : offset_vectype, scale,
2049 : : &ls->gs.ifn, &tem,
2050 : : elsvals))
2051 : 0 : *memory_access_type = VMAT_GATHER_SCATTER_IFN;
2052 : 7355 : else if (vls_type == VLS_LOAD
2053 : 7355 : ? (targetm.vectorize.builtin_gather
2054 : 4906 : && (ls->gs.decl
2055 : 4906 : = targetm.vectorize.builtin_gather (vectype,
2056 : 4906 : TREE_TYPE
2057 : : (offset_vectype),
2058 : : scale)))
2059 : 2449 : : (targetm.vectorize.builtin_scatter
2060 : 2449 : && (ls->gs.decl
2061 : 2449 : = targetm.vectorize.builtin_scatter (vectype,
2062 : 2449 : TREE_TYPE
2063 : : (offset_vectype),
2064 : : scale))))
2065 : 349 : *memory_access_type = VMAT_GATHER_SCATTER_LEGACY;
2066 : : else
2067 : : {
2068 : : /* GATHER_SCATTER_EMULATED_P. */
2069 : 7006 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant ()
2070 : 7006 : || !TYPE_VECTOR_SUBPARTS (offset_vectype).is_constant ()
2071 : 7006 : || VECTOR_BOOLEAN_TYPE_P (offset_vectype)
2072 : 7006 : || !constant_multiple_p (TYPE_VECTOR_SUBPARTS (offset_vectype),
2073 : 7006 : TYPE_VECTOR_SUBPARTS (vectype)))
2074 : : {
2075 : 2536 : if (dump_enabled_p ())
2076 : 442 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2077 : : "unsupported vector types for emulated "
2078 : : "gather.\n");
2079 : 2536 : return false;
2080 : : }
2081 : 4470 : *memory_access_type = VMAT_GATHER_SCATTER_EMULATED;
2082 : : }
2083 : : }
2084 : : else
2085 : : {
2086 : 1189647 : int cmp = compare_step_with_zero (vinfo, stmt_info);
2087 : 1189647 : if (cmp < 0)
2088 : : {
2089 : 10212 : if (single_element_p)
2090 : : /* ??? The VMAT_CONTIGUOUS_REVERSE code generation is
2091 : : only correct for single element "interleaving" SLP. */
2092 : 10056 : *memory_access_type = get_negative_load_store_type
2093 : 10056 : (vinfo, stmt_info, vectype, vls_type, 1,
2094 : : &neg_ldst_offset);
2095 : : else
2096 : : /* We can fall back to VMAT_STRIDED_SLP since that does
2097 : : not care whether the stride between the group instances
2098 : : is positive or negative. */
2099 : 156 : *memory_access_type = VMAT_STRIDED_SLP;
2100 : : }
2101 : 1179435 : else if (cmp == 0 && loop_vinfo)
2102 : : {
2103 : 3051 : gcc_assert (vls_type == VLS_LOAD);
2104 : 3051 : *memory_access_type = VMAT_INVARIANT;
2105 : : }
2106 : : /* Try using LOAD/STORE_LANES. */
2107 : 1176384 : else if (slp_node->ldst_lanes
2108 : 1176384 : && (*lanes_ifn
2109 : 0 : = (vls_type == VLS_LOAD
2110 : 0 : ? vect_load_lanes_supported (vectype, group_size,
2111 : : masked_p, elsvals)
2112 : 0 : : vect_store_lanes_supported (vectype, group_size,
2113 : : masked_p))) != IFN_LAST)
2114 : 0 : *memory_access_type = VMAT_LOAD_STORE_LANES;
2115 : 1176384 : else if (!loop_vinfo && slp_node->avoid_stlf_fail)
2116 : : {
2117 : 72 : *memory_access_type = VMAT_ELEMENTWISE;
2118 : 72 : if (dump_enabled_p ())
2119 : 2 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2120 : : "using element-wise load to avoid disrupting "
2121 : : "cross iteration store-to-load forwarding\n");
2122 : : }
2123 : : else
2124 : 1176312 : *memory_access_type = VMAT_CONTIGUOUS;
2125 : :
2126 : : /* If this is single-element interleaving with an element
2127 : : distance that leaves unused vector loads around fall back
2128 : : to elementwise access if possible - we otherwise least
2129 : : create very sub-optimal code in that case (and
2130 : : blow up memory, see PR65518). */
2131 : 1189647 : if (loop_vinfo
2132 : 1189647 : && single_element_p
2133 : 350690 : && (*memory_access_type == VMAT_CONTIGUOUS
2134 : 13107 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2135 : 1540337 : && maybe_gt (group_size, TYPE_VECTOR_SUBPARTS (vectype)))
2136 : : {
2137 : 13342 : if (SLP_TREE_LANES (slp_node) == 1)
2138 : : {
2139 : 13325 : *memory_access_type = VMAT_ELEMENTWISE;
2140 : 13325 : if (dump_enabled_p ())
2141 : 190 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2142 : : "single-element interleaving not supported "
2143 : : "for not adjacent vector loads, using "
2144 : : "elementwise access\n");
2145 : : }
2146 : : else
2147 : : {
2148 : 17 : if (dump_enabled_p ())
2149 : 10 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2150 : : "single-element interleaving not supported "
2151 : : "for not adjacent vector loads\n");
2152 : 26 : return false;
2153 : : }
2154 : : }
2155 : :
2156 : : /* For single-element interleaving also fall back to elementwise
2157 : : access in case we did not lower a permutation and cannot
2158 : : code generate it. */
2159 : 1189630 : if (loop_vinfo
2160 : : && single_element_p
2161 : 350673 : && SLP_TREE_LANES (slp_node) == 1
2162 : 345673 : && (*memory_access_type == VMAT_CONTIGUOUS
2163 : 25899 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2164 : 324806 : && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2165 : 1197459 : && !perm_ok)
2166 : : {
2167 : 1479 : *memory_access_type = VMAT_ELEMENTWISE;
2168 : 1479 : if (dump_enabled_p ())
2169 : 81 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2170 : : "single-element interleaving permutation not "
2171 : : "supported, using elementwise access\n");
2172 : : }
2173 : :
2174 : 400444 : overrun_p = (loop_vinfo && gap != 0
2175 : 1232723 : && *memory_access_type != VMAT_ELEMENTWISE);
2176 : 1189630 : if (overrun_p && vls_type != VLS_LOAD)
2177 : : {
2178 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2179 : : "Grouped store with gaps requires"
2180 : : " non-consecutive accesses\n");
2181 : 0 : return false;
2182 : : }
2183 : :
2184 : 1189630 : unsigned HOST_WIDE_INT dr_size = vect_get_scalar_dr_size (first_dr_info);
2185 : 1189630 : poly_int64 off = 0;
2186 : 1189630 : if (*memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2187 : 5054 : off = (TYPE_VECTOR_SUBPARTS (vectype) - 1) * -dr_size;
2188 : :
2189 : : /* An overrun is fine if the trailing elements are smaller
2190 : : than the alignment boundary B. Every vector access will
2191 : : be a multiple of B and so we are guaranteed to access a
2192 : : non-gap element in the same B-sized block. */
2193 : 1189630 : if (overrun_p
2194 : 1189630 : && gap < (vect_known_alignment_in_bytes (first_dr_info,
2195 : 27939 : vectype, off) / dr_size))
2196 : : overrun_p = false;
2197 : :
2198 : : /* When we have a contiguous access across loop iterations
2199 : : but the access in the loop doesn't cover the full vector
2200 : : we can end up with no gap recorded but still excess
2201 : : elements accessed, see PR103116. Make sure we peel for
2202 : : gaps if necessary and sufficient and give up if not.
2203 : :
2204 : : If there is a combination of the access not covering the full
2205 : : vector and a gap recorded then we may need to peel twice. */
2206 : 1189630 : bool large_vector_overrun_p = false;
2207 : 1189630 : if (loop_vinfo
2208 : 400444 : && (*memory_access_type == VMAT_CONTIGUOUS
2209 : 27912 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2210 : 377586 : && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2211 : 1209258 : && !multiple_p (group_size * LOOP_VINFO_VECT_FACTOR (loop_vinfo),
2212 : : nunits))
2213 : : large_vector_overrun_p = overrun_p = true;
2214 : :
2215 : : /* If the gap splits the vector in half and the target
2216 : : can do half-vector operations avoid the epilogue peeling
2217 : : by simply loading half of the vector only. Usually
2218 : : the construction with an upper zero half will be elided. */
2219 : 1189630 : dr_alignment_support alss;
2220 : 1189630 : int misalign = dr_misalignment (first_dr_info, vectype, off);
2221 : 1189630 : tree half_vtype;
2222 : 1189630 : poly_uint64 remain;
2223 : 1189630 : unsigned HOST_WIDE_INT tem, num;
2224 : 1189630 : if (overrun_p
2225 : 1189630 : && !masked_p
2226 : 22428 : && *memory_access_type != VMAT_LOAD_STORE_LANES
2227 : 22428 : && (((alss = vect_supportable_dr_alignment (vinfo, first_dr_info,
2228 : : vectype, misalign)))
2229 : : == dr_aligned
2230 : 17500 : || alss == dr_unaligned_supported)
2231 : 12090 : && can_div_trunc_p (group_size
2232 : 12090 : * LOOP_VINFO_VECT_FACTOR (loop_vinfo) - gap,
2233 : : nunits, &tem, &remain)
2234 : 1201720 : && (known_eq (remain, 0u)
2235 : 7162 : || (known_ne (remain, 0u)
2236 : 5502 : && constant_multiple_p (nunits, remain, &num)
2237 : 1184702 : && (vector_vector_composition_type (vectype, num, &half_vtype)
2238 : : != NULL_TREE))))
2239 : 10430 : overrun_p = false;
2240 : :
2241 : 1189630 : if (overrun_p && !can_overrun_p)
2242 : : {
2243 : 6 : if (dump_enabled_p ())
2244 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2245 : : "Peeling for outer loop is not supported\n");
2246 : 6 : return false;
2247 : : }
2248 : :
2249 : : /* Peeling for gaps assumes that a single scalar iteration
2250 : : is enough to make sure the last vector iteration doesn't
2251 : : access excess elements. */
2252 : 1189624 : if (overrun_p
2253 : 1189624 : && (!can_div_trunc_p (group_size
2254 : 11992 : * LOOP_VINFO_VECT_FACTOR (loop_vinfo) - gap,
2255 : : nunits, &tem, &remain)
2256 : 11992 : || maybe_lt (remain + group_size, nunits)))
2257 : : {
2258 : : /* But peeling a single scalar iteration is enough if
2259 : : we can use the next power-of-two sized partial
2260 : : access and that is sufficiently small to be covered
2261 : : by the single scalar iteration. */
2262 : 17 : unsigned HOST_WIDE_INT cnunits, cvf, cremain, cpart_size;
2263 : 17 : if (masked_p
2264 : 17 : || !nunits.is_constant (&cnunits)
2265 : 17 : || !LOOP_VINFO_VECT_FACTOR (loop_vinfo).is_constant (&cvf)
2266 : 17 : || (((cremain = (group_size * cvf - gap) % cnunits), true)
2267 : 17 : && ((cpart_size = (1 << ceil_log2 (cremain))), true)
2268 : 17 : && (cremain + group_size < cpart_size
2269 : 14 : || (vector_vector_composition_type (vectype,
2270 : 14 : cnunits / cpart_size,
2271 : : &half_vtype)
2272 : : == NULL_TREE))))
2273 : : {
2274 : : /* If all fails we can still resort to niter masking unless
2275 : : the vectors used are too big, so enforce the use of
2276 : : partial vectors. */
2277 : 3 : if (LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
2278 : 0 : && !large_vector_overrun_p)
2279 : : {
2280 : 0 : if (dump_enabled_p ())
2281 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2282 : : "peeling for gaps insufficient for "
2283 : : "access unless using partial "
2284 : : "vectors\n");
2285 : 0 : LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
2286 : : }
2287 : : else
2288 : : {
2289 : 3 : if (dump_enabled_p ())
2290 : 3 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2291 : : "peeling for gaps insufficient for "
2292 : : "access\n");
2293 : 3 : return false;
2294 : : }
2295 : : }
2296 : 14 : else if (large_vector_overrun_p)
2297 : : {
2298 : 14 : if (dump_enabled_p ())
2299 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2300 : : "can't operate on partial vectors because "
2301 : : "only unmasked loads handle access "
2302 : : "shortening required because of gaps at "
2303 : : "the end of the access\n");
2304 : 14 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
2305 : : }
2306 : : }
2307 : : }
2308 : :
2309 : : /* As a last resort, trying using a gather load or scatter store.
2310 : :
2311 : : ??? Although the code can handle all group sizes correctly,
2312 : : it probably isn't a win to use separate strided accesses based
2313 : : on nearby locations. Or, even if it's a win over scalar code,
2314 : : it might not be a win over vectorizing at a lower VF, if that
2315 : : allows us to use contiguous accesses. */
2316 : 14 : if (loop_vinfo
2317 : 450444 : && (*memory_access_type == VMAT_ELEMENTWISE
2318 : 450444 : || *memory_access_type == VMAT_STRIDED_SLP)
2319 : 64286 : && !STMT_VINFO_GATHER_SCATTER_P (stmt_info)
2320 : 64286 : && SLP_TREE_LANES (slp_node) == 1
2321 : 1300016 : && (!SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2322 : 16483 : || single_element_p))
2323 : : {
2324 : 58938 : gather_scatter_info gs_info;
2325 : 58938 : if (vect_use_strided_gather_scatters_p (stmt_info, vectype, loop_vinfo,
2326 : : masked_p, &gs_info, elsvals,
2327 : : group_size, single_element_p))
2328 : : {
2329 : 0 : SLP_TREE_GS_SCALE (slp_node) = gs_info.scale;
2330 : 0 : SLP_TREE_GS_BASE (slp_node) = error_mark_node;
2331 : 0 : ls->gs.ifn = gs_info.ifn;
2332 : 0 : ls->strided_offset_vectype = gs_info.offset_vectype;
2333 : 0 : *memory_access_type = VMAT_GATHER_SCATTER_IFN;
2334 : : }
2335 : : }
2336 : :
2337 : 1239630 : if (*memory_access_type == VMAT_CONTIGUOUS_DOWN
2338 : 1239630 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2339 : 5761 : *poffset = neg_ldst_offset;
2340 : :
2341 : 1239630 : if (*memory_access_type == VMAT_ELEMENTWISE
2342 : 1220618 : || *memory_access_type == VMAT_GATHER_SCATTER_LEGACY
2343 : 1220269 : || *memory_access_type == VMAT_STRIDED_SLP
2344 : 1174923 : || *memory_access_type == VMAT_INVARIANT)
2345 : : {
2346 : 67758 : *alignment_support_scheme = dr_unaligned_supported;
2347 : 67758 : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2348 : : }
2349 : : else
2350 : : {
2351 : 1171872 : if (mat_gather_scatter_p (*memory_access_type)
2352 : : && !first_dr_info)
2353 : : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2354 : : else
2355 : 1171872 : *misalignment = dr_misalignment (first_dr_info, vectype, *poffset);
2356 : 1171872 : *alignment_support_scheme
2357 : 1171872 : = vect_supportable_dr_alignment
2358 : 1171872 : (vinfo, first_dr_info, vectype, *misalignment,
2359 : 1171872 : mat_gather_scatter_p (*memory_access_type));
2360 : : }
2361 : :
2362 : 1239630 : if (overrun_p)
2363 : : {
2364 : 11989 : gcc_assert (can_overrun_p);
2365 : 11989 : if (dump_enabled_p ())
2366 : 527 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2367 : : "Data access with gaps requires scalar "
2368 : : "epilogue loop\n");
2369 : 11989 : LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo) = true;
2370 : : }
2371 : :
2372 : 1239630 : if ((*memory_access_type == VMAT_ELEMENTWISE
2373 : 1239630 : || *memory_access_type == VMAT_STRIDED_SLP)
2374 : : && !nunits.is_constant ())
2375 : : {
2376 : : if (dump_enabled_p ())
2377 : : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2378 : : "Not using elementwise accesses due to variable "
2379 : : "vectorization factor.\n");
2380 : : return false;
2381 : : }
2382 : :
2383 : : /* Checks if all scalar iterations are known to be inbounds. */
2384 : 1239630 : bool inbounds = DR_SCALAR_KNOWN_BOUNDS (STMT_VINFO_DR_INFO (stmt_info));
2385 : :
2386 : : /* Check if we support the operation if early breaks are needed. Here we
2387 : : must ensure that we don't access any more than the scalar code would
2388 : : have. A masked operation would ensure this, so for these load types
2389 : : force masking. */
2390 : 1239630 : if (loop_vinfo
2391 : 450444 : && dr_safe_speculative_read_required (stmt_info)
2392 : 163626 : && LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
2393 : 1403256 : && (mat_gather_scatter_p (*memory_access_type)
2394 : 163218 : || *memory_access_type == VMAT_STRIDED_SLP))
2395 : : {
2396 : 6228 : if (dump_enabled_p ())
2397 : 8 : dump_printf_loc (MSG_NOTE, vect_location,
2398 : : "early break not supported: cannot peel for "
2399 : : "alignment. With non-contiguous memory vectorization"
2400 : : " could read out of bounds at %G ",
2401 : : STMT_VINFO_STMT (stmt_info));
2402 : 6228 : if (inbounds)
2403 : 0 : LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
2404 : : else
2405 : : return false;
2406 : : }
2407 : :
2408 : : /* If this DR needs alignment for correctness, we must ensure the target
2409 : : alignment is a constant power-of-two multiple of the amount read per
2410 : : vector iteration or force masking. */
2411 : 1233402 : if (dr_safe_speculative_read_required (stmt_info)
2412 : 1233402 : && (*alignment_support_scheme == dr_aligned
2413 : 86044 : && !mat_gather_scatter_p (*memory_access_type)))
2414 : : {
2415 : : /* We can only peel for loops, of course. */
2416 : 86044 : gcc_checking_assert (loop_vinfo);
2417 : :
2418 : 86044 : poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
2419 : 86044 : poly_uint64 read_amount
2420 : 86044 : = vf * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
2421 : 86044 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
2422 : 6957 : read_amount *= DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info));
2423 : :
2424 : 86044 : auto target_alignment
2425 : 86044 : = DR_TARGET_ALIGNMENT (STMT_VINFO_DR_INFO (stmt_info));
2426 : 86044 : if (!multiple_p (target_alignment, read_amount))
2427 : : {
2428 : 5354 : if (dump_enabled_p ())
2429 : : {
2430 : 14 : dump_printf_loc (MSG_NOTE, vect_location,
2431 : : "desired alignment not met, target was ");
2432 : 14 : dump_dec (MSG_NOTE, target_alignment);
2433 : 14 : dump_printf (MSG_NOTE, " previously, but read amount is ");
2434 : 14 : dump_dec (MSG_NOTE, read_amount);
2435 : 14 : dump_printf (MSG_NOTE, " at %G.\n", STMT_VINFO_STMT (stmt_info));
2436 : : }
2437 : 6546 : return false;
2438 : : }
2439 : :
2440 : : /* When using a group access the first element may be aligned but the
2441 : : subsequent loads may not be. For LOAD_LANES since the loads are based
2442 : : on the first DR then all loads in the group are aligned. For
2443 : : non-LOAD_LANES this is not the case. In particular a load + blend when
2444 : : there are gaps can have the non first loads issued unaligned, even
2445 : : partially overlapping the memory of the first load in order to simplify
2446 : : the blend. This is what the x86_64 backend does for instance. As
2447 : : such only the first load in the group is aligned, the rest are not.
2448 : : Because of this the permutes may break the alignment requirements that
2449 : : have been set, and as such we should for now, reject them. */
2450 : 80690 : if (SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
2451 : : {
2452 : 1192 : if (dump_enabled_p ())
2453 : 72 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2454 : : "loads with load permutations not supported for "
2455 : : "speculative early break loads for %G",
2456 : : STMT_VINFO_STMT (stmt_info));
2457 : 1192 : return false;
2458 : : }
2459 : :
2460 : : /* Reject vectorization if we know the read mount per vector iteration
2461 : : exceeds the min page size. */
2462 : 79498 : if (known_gt (read_amount, (unsigned) param_min_pagesize))
2463 : : {
2464 : 0 : if (dump_enabled_p ())
2465 : : {
2466 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2467 : : "alignment required for correctness (");
2468 : 0 : dump_dec (MSG_MISSED_OPTIMIZATION, read_amount);
2469 : 0 : dump_printf (MSG_NOTE, ") may exceed page size.\n");
2470 : : }
2471 : 0 : return false;
2472 : : }
2473 : :
2474 : 79498 : if (!vf.is_constant ())
2475 : : {
2476 : : /* For VLA modes, we need a runtime check to ensure any speculative
2477 : : read amount does not exceed the page size. Here we record the max
2478 : : possible read amount for the check. */
2479 : : if (maybe_gt (read_amount,
2480 : : LOOP_VINFO_MAX_SPEC_READ_AMOUNT (loop_vinfo)))
2481 : : LOOP_VINFO_MAX_SPEC_READ_AMOUNT (loop_vinfo) = read_amount;
2482 : :
2483 : : /* For VLA modes, we must use partial vectors. */
2484 : : LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
2485 : : }
2486 : : }
2487 : :
2488 : 1226856 : if (*alignment_support_scheme == dr_unaligned_unsupported)
2489 : : {
2490 : 58885 : if (dump_enabled_p ())
2491 : 270 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2492 : : "unsupported unaligned access\n");
2493 : 58885 : return false;
2494 : : }
2495 : :
2496 : : /* FIXME: At the moment the cost model seems to underestimate the
2497 : : cost of using elementwise accesses. This check preserves the
2498 : : traditional behavior until that can be fixed. */
2499 : 1167971 : if (*memory_access_type == VMAT_ELEMENTWISE
2500 : 19012 : && !STMT_VINFO_STRIDED_P (first_stmt_info)
2501 : 1186983 : && !(stmt_info == DR_GROUP_FIRST_ELEMENT (stmt_info)
2502 : 15212 : && !DR_GROUP_NEXT_ELEMENT (stmt_info)
2503 : 15154 : && !pow2p_hwi (DR_GROUP_SIZE (stmt_info))))
2504 : : {
2505 : 8560 : if (dump_enabled_p ())
2506 : 218 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2507 : : "not falling back to elementwise accesses\n");
2508 : 8560 : return false;
2509 : : }
2510 : : return true;
2511 : : }
2512 : :
2513 : : /* Return true if boolean argument at MASK_INDEX is suitable for vectorizing
2514 : : conditional operation STMT_INFO. When returning true, store the mask
2515 : : in *MASK_NODE, the type of its definition in *MASK_DT_OUT and the type of
2516 : : the vectorized mask in *MASK_VECTYPE_OUT. */
2517 : :
2518 : : static bool
2519 : 7508 : vect_check_scalar_mask (vec_info *vinfo,
2520 : : slp_tree slp_node, unsigned mask_index,
2521 : : slp_tree *mask_node,
2522 : : vect_def_type *mask_dt_out, tree *mask_vectype_out)
2523 : : {
2524 : 7508 : enum vect_def_type mask_dt;
2525 : 7508 : tree mask_vectype;
2526 : 7508 : slp_tree mask_node_1;
2527 : 7508 : tree mask_;
2528 : 7508 : if (!vect_is_simple_use (vinfo, slp_node, mask_index,
2529 : : &mask_, &mask_node_1, &mask_dt, &mask_vectype))
2530 : : {
2531 : 0 : if (dump_enabled_p ())
2532 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2533 : : "mask use not simple.\n");
2534 : 0 : return false;
2535 : : }
2536 : :
2537 : 7508 : if ((mask_dt == vect_constant_def || mask_dt == vect_external_def)
2538 : 7508 : && !VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (mask_)))
2539 : : {
2540 : 0 : if (dump_enabled_p ())
2541 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2542 : : "mask argument is not a boolean.\n");
2543 : 0 : return false;
2544 : : }
2545 : :
2546 : 7508 : tree vectype = SLP_TREE_VECTYPE (slp_node);
2547 : 7508 : if (!mask_vectype)
2548 : 17 : mask_vectype = get_mask_type_for_scalar_type (vinfo, TREE_TYPE (vectype),
2549 : : mask_node_1);
2550 : :
2551 : 7508 : if (!mask_vectype || !VECTOR_BOOLEAN_TYPE_P (mask_vectype))
2552 : : {
2553 : 0 : if (dump_enabled_p ())
2554 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2555 : : "could not find an appropriate vector mask type.\n");
2556 : 0 : return false;
2557 : : }
2558 : :
2559 : 7508 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (mask_vectype),
2560 : 15016 : TYPE_VECTOR_SUBPARTS (vectype)))
2561 : : {
2562 : 0 : if (dump_enabled_p ())
2563 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2564 : : "vector mask type %T"
2565 : : " does not match vector data type %T.\n",
2566 : : mask_vectype, vectype);
2567 : :
2568 : 0 : return false;
2569 : : }
2570 : :
2571 : 7508 : *mask_dt_out = mask_dt;
2572 : 7508 : *mask_vectype_out = mask_vectype;
2573 : 7508 : *mask_node = mask_node_1;
2574 : 7508 : return true;
2575 : : }
2576 : :
2577 : :
2578 : : /* Return true if stored value is suitable for vectorizing store
2579 : : statement STMT_INFO. When returning true, store the scalar stored
2580 : : in *RHS and *RHS_NODE, the type of the definition in *RHS_DT_OUT,
2581 : : the type of the vectorized store value in
2582 : : *RHS_VECTYPE_OUT and the type of the store in *VLS_TYPE_OUT. */
2583 : :
2584 : : static bool
2585 : 1323474 : vect_check_store_rhs (vec_info *vinfo, stmt_vec_info stmt_info,
2586 : : slp_tree slp_node, slp_tree *rhs_node,
2587 : : vect_def_type *rhs_dt_out, tree *rhs_vectype_out,
2588 : : vec_load_store_type *vls_type_out)
2589 : : {
2590 : 1323474 : int op_no = 0;
2591 : 1323474 : if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt))
2592 : : {
2593 : 1417 : if (gimple_call_internal_p (call)
2594 : 1417 : && internal_store_fn_p (gimple_call_internal_fn (call)))
2595 : 1417 : op_no = internal_fn_stored_value_index (gimple_call_internal_fn (call));
2596 : : }
2597 : 1323474 : op_no = vect_slp_child_index_for_operand
2598 : 1323474 : (stmt_info->stmt, op_no, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
2599 : :
2600 : 1323474 : enum vect_def_type rhs_dt;
2601 : 1323474 : tree rhs_vectype;
2602 : 1323474 : tree rhs;
2603 : 1323474 : if (!vect_is_simple_use (vinfo, slp_node, op_no,
2604 : : &rhs, rhs_node, &rhs_dt, &rhs_vectype))
2605 : : {
2606 : 0 : if (dump_enabled_p ())
2607 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2608 : : "use not simple.\n");
2609 : 0 : return false;
2610 : : }
2611 : :
2612 : : /* In the case this is a store from a constant make sure
2613 : : native_encode_expr can handle it. */
2614 : 1323474 : if (rhs_dt == vect_constant_def
2615 : 1323474 : && CONSTANT_CLASS_P (rhs) && native_encode_expr (rhs, NULL, 64) == 0)
2616 : : {
2617 : 0 : if (dump_enabled_p ())
2618 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2619 : : "cannot encode constant as a byte sequence.\n");
2620 : 0 : return false;
2621 : : }
2622 : :
2623 : 1323474 : tree vectype = SLP_TREE_VECTYPE (slp_node);
2624 : 1323474 : if (rhs_vectype && !useless_type_conversion_p (vectype, rhs_vectype))
2625 : : {
2626 : 24 : if (dump_enabled_p ())
2627 : 24 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2628 : : "incompatible vector types.\n");
2629 : 24 : return false;
2630 : : }
2631 : :
2632 : 1323450 : *rhs_dt_out = rhs_dt;
2633 : 1323450 : *rhs_vectype_out = rhs_vectype;
2634 : 1323450 : if (rhs_dt == vect_constant_def || rhs_dt == vect_external_def)
2635 : 1002936 : *vls_type_out = VLS_STORE_INVARIANT;
2636 : : else
2637 : 320514 : *vls_type_out = VLS_STORE;
2638 : : return true;
2639 : : }
2640 : :
2641 : : /* Build an all-ones vector mask of type MASKTYPE while vectorizing STMT_INFO.
2642 : : Note that we support masks with floating-point type, in which case the
2643 : : floats are interpreted as a bitmask. */
2644 : :
2645 : : static tree
2646 : 165 : vect_build_all_ones_mask (vec_info *vinfo,
2647 : : stmt_vec_info stmt_info, tree masktype)
2648 : : {
2649 : 165 : if (TREE_CODE (masktype) == INTEGER_TYPE)
2650 : 98 : return build_int_cst (masktype, -1);
2651 : 67 : else if (VECTOR_BOOLEAN_TYPE_P (masktype)
2652 : 134 : || TREE_CODE (TREE_TYPE (masktype)) == INTEGER_TYPE)
2653 : : {
2654 : 14 : tree mask = build_int_cst (TREE_TYPE (masktype), -1);
2655 : 14 : mask = build_vector_from_val (masktype, mask);
2656 : 14 : return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL);
2657 : : }
2658 : 53 : else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (masktype)))
2659 : : {
2660 : : REAL_VALUE_TYPE r;
2661 : : long tmp[6];
2662 : 371 : for (int j = 0; j < 6; ++j)
2663 : 318 : tmp[j] = -1;
2664 : 53 : real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (masktype)));
2665 : 53 : tree mask = build_real (TREE_TYPE (masktype), r);
2666 : 53 : mask = build_vector_from_val (masktype, mask);
2667 : 53 : return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL);
2668 : : }
2669 : 0 : gcc_unreachable ();
2670 : : }
2671 : :
2672 : : /* Build an all-zero merge value of type VECTYPE while vectorizing
2673 : : STMT_INFO as a gather load. */
2674 : :
2675 : : static tree
2676 : 158 : vect_build_zero_merge_argument (vec_info *vinfo,
2677 : : stmt_vec_info stmt_info, tree vectype)
2678 : : {
2679 : 158 : tree merge;
2680 : 158 : if (TREE_CODE (TREE_TYPE (vectype)) == INTEGER_TYPE)
2681 : 49 : merge = build_int_cst (TREE_TYPE (vectype), 0);
2682 : 109 : else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (vectype)))
2683 : : {
2684 : : REAL_VALUE_TYPE r;
2685 : : long tmp[6];
2686 : 763 : for (int j = 0; j < 6; ++j)
2687 : 654 : tmp[j] = 0;
2688 : 109 : real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (vectype)));
2689 : 109 : merge = build_real (TREE_TYPE (vectype), r);
2690 : : }
2691 : : else
2692 : 0 : gcc_unreachable ();
2693 : 158 : merge = build_vector_from_val (vectype, merge);
2694 : 158 : return vect_init_vector (vinfo, stmt_info, merge, vectype, NULL);
2695 : : }
2696 : :
2697 : : /* Return the corresponding else value for an else value constant
2698 : : ELSVAL with type TYPE. */
2699 : :
2700 : : tree
2701 : 1641 : vect_get_mask_load_else (int elsval, tree type)
2702 : : {
2703 : 1641 : tree els;
2704 : 1641 : if (elsval == MASK_LOAD_ELSE_UNDEFINED)
2705 : : {
2706 : 0 : tree tmp = create_tmp_var (type);
2707 : : /* No need to warn about anything. */
2708 : 0 : TREE_NO_WARNING (tmp) = 1;
2709 : 0 : els = get_or_create_ssa_default_def (cfun, tmp);
2710 : : }
2711 : 1641 : else if (elsval == MASK_LOAD_ELSE_M1)
2712 : 0 : els = build_minus_one_cst (type);
2713 : 1641 : else if (elsval == MASK_LOAD_ELSE_ZERO)
2714 : 1641 : els = build_zero_cst (type);
2715 : : else
2716 : 0 : gcc_unreachable ();
2717 : :
2718 : 1641 : return els;
2719 : : }
2720 : :
2721 : : /* Build a gather load call while vectorizing STMT_INFO. Insert new
2722 : : instructions before GSI and add them to VEC_STMT. GS_INFO describes
2723 : : the gather load operation. If the load is conditional, MASK is the
2724 : : vectorized condition, otherwise MASK is null. PTR is the base
2725 : : pointer and OFFSET is the vectorized offset. */
2726 : :
2727 : : static gimple *
2728 : 346 : vect_build_one_gather_load_call (vec_info *vinfo, stmt_vec_info stmt_info,
2729 : : slp_tree slp_node, tree vectype,
2730 : : gimple_stmt_iterator *gsi, tree decl,
2731 : : tree ptr, tree offset, tree mask)
2732 : : {
2733 : 346 : tree arglist = TYPE_ARG_TYPES (TREE_TYPE (decl));
2734 : 346 : tree rettype = TREE_TYPE (TREE_TYPE (decl));
2735 : 346 : tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2736 : 346 : /* ptrtype */ arglist = TREE_CHAIN (arglist);
2737 : 346 : tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2738 : 346 : tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2739 : 346 : tree scaletype = TREE_VALUE (arglist);
2740 : 346 : tree var;
2741 : 346 : gcc_checking_assert (types_compatible_p (srctype, rettype)
2742 : : && (!mask
2743 : : || TREE_CODE (masktype) == INTEGER_TYPE
2744 : : || types_compatible_p (srctype, masktype)));
2745 : :
2746 : 346 : tree op = offset;
2747 : 346 : if (!useless_type_conversion_p (idxtype, TREE_TYPE (op)))
2748 : : {
2749 : 100 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)),
2750 : : TYPE_VECTOR_SUBPARTS (idxtype)));
2751 : 100 : var = vect_get_new_ssa_name (idxtype, vect_simple_var);
2752 : 100 : op = build1 (VIEW_CONVERT_EXPR, idxtype, op);
2753 : 100 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op);
2754 : 100 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2755 : 100 : op = var;
2756 : : }
2757 : :
2758 : 346 : tree src_op = NULL_TREE;
2759 : 346 : tree mask_op = NULL_TREE;
2760 : 346 : if (mask)
2761 : : {
2762 : 188 : if (!useless_type_conversion_p (masktype, TREE_TYPE (mask)))
2763 : : {
2764 : 188 : tree utype, optype = TREE_TYPE (mask);
2765 : 188 : if (VECTOR_TYPE_P (masktype)
2766 : 188 : || TYPE_MODE (masktype) == TYPE_MODE (optype))
2767 : : utype = masktype;
2768 : : else
2769 : 7 : utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1);
2770 : 188 : var = vect_get_new_ssa_name (utype, vect_scalar_var);
2771 : 188 : tree mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask);
2772 : 188 : gassign *new_stmt
2773 : 188 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg);
2774 : 188 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2775 : 188 : mask_arg = var;
2776 : 188 : if (!useless_type_conversion_p (masktype, utype))
2777 : : {
2778 : 7 : gcc_assert (TYPE_PRECISION (utype)
2779 : : <= TYPE_PRECISION (masktype));
2780 : 7 : var = vect_get_new_ssa_name (masktype, vect_scalar_var);
2781 : 7 : new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg);
2782 : 7 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2783 : 7 : mask_arg = var;
2784 : : }
2785 : 188 : src_op = build_zero_cst (srctype);
2786 : 188 : mask_op = mask_arg;
2787 : : }
2788 : : else
2789 : : {
2790 : : src_op = mask;
2791 : : mask_op = mask;
2792 : : }
2793 : : }
2794 : : else
2795 : : {
2796 : 158 : src_op = vect_build_zero_merge_argument (vinfo, stmt_info, rettype);
2797 : 158 : mask_op = vect_build_all_ones_mask (vinfo, stmt_info, masktype);
2798 : : }
2799 : :
2800 : 346 : tree scale = build_int_cst (scaletype, SLP_TREE_GS_SCALE (slp_node));
2801 : 346 : gimple *new_stmt = gimple_build_call (decl, 5, src_op, ptr, op,
2802 : : mask_op, scale);
2803 : :
2804 : 346 : if (!useless_type_conversion_p (vectype, rettype))
2805 : : {
2806 : 49 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (vectype),
2807 : : TYPE_VECTOR_SUBPARTS (rettype)));
2808 : 49 : op = vect_get_new_ssa_name (rettype, vect_simple_var);
2809 : 49 : gimple_call_set_lhs (new_stmt, op);
2810 : 49 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2811 : 49 : op = build1 (VIEW_CONVERT_EXPR, vectype, op);
2812 : 49 : new_stmt = gimple_build_assign (NULL_TREE, VIEW_CONVERT_EXPR, op);
2813 : : }
2814 : :
2815 : 346 : return new_stmt;
2816 : : }
2817 : :
2818 : : /* Build a scatter store call while vectorizing STMT_INFO. Insert new
2819 : : instructions before GSI. GS_INFO describes the scatter store operation.
2820 : : PTR is the base pointer, OFFSET the vectorized offsets and OPRND the
2821 : : vectorized data to store.
2822 : : If the store is conditional, MASK is the vectorized condition, otherwise
2823 : : MASK is null. */
2824 : :
2825 : : static gimple *
2826 : 169 : vect_build_one_scatter_store_call (vec_info *vinfo, stmt_vec_info stmt_info,
2827 : : slp_tree slp_node,
2828 : : gimple_stmt_iterator *gsi,
2829 : : tree decl,
2830 : : tree ptr, tree offset, tree oprnd, tree mask)
2831 : : {
2832 : 169 : tree rettype = TREE_TYPE (TREE_TYPE (decl));
2833 : 169 : tree arglist = TYPE_ARG_TYPES (TREE_TYPE (decl));
2834 : 169 : /* tree ptrtype = TREE_VALUE (arglist); */ arglist = TREE_CHAIN (arglist);
2835 : 169 : tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2836 : 169 : tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2837 : 169 : tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2838 : 169 : tree scaletype = TREE_VALUE (arglist);
2839 : 169 : gcc_checking_assert (TREE_CODE (masktype) == INTEGER_TYPE
2840 : : && TREE_CODE (rettype) == VOID_TYPE);
2841 : :
2842 : 169 : tree mask_arg = NULL_TREE;
2843 : 169 : if (mask)
2844 : : {
2845 : 110 : mask_arg = mask;
2846 : 110 : tree optype = TREE_TYPE (mask_arg);
2847 : 110 : tree utype;
2848 : 110 : if (TYPE_MODE (masktype) == TYPE_MODE (optype))
2849 : : utype = masktype;
2850 : : else
2851 : 8 : utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1);
2852 : 110 : tree var = vect_get_new_ssa_name (utype, vect_scalar_var);
2853 : 110 : mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask_arg);
2854 : 110 : gassign *new_stmt
2855 : 110 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg);
2856 : 110 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2857 : 110 : mask_arg = var;
2858 : 110 : if (!useless_type_conversion_p (masktype, utype))
2859 : : {
2860 : 8 : gcc_assert (TYPE_PRECISION (utype) <= TYPE_PRECISION (masktype));
2861 : 8 : tree var = vect_get_new_ssa_name (masktype, vect_scalar_var);
2862 : 8 : new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg);
2863 : 8 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2864 : 8 : mask_arg = var;
2865 : : }
2866 : : }
2867 : : else
2868 : : {
2869 : 59 : mask_arg = build_int_cst (masktype, -1);
2870 : 59 : mask_arg = vect_init_vector (vinfo, stmt_info, mask_arg, masktype, NULL);
2871 : : }
2872 : :
2873 : 169 : tree src = oprnd;
2874 : 169 : if (!useless_type_conversion_p (srctype, TREE_TYPE (src)))
2875 : : {
2876 : 0 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (src)),
2877 : : TYPE_VECTOR_SUBPARTS (srctype)));
2878 : 0 : tree var = vect_get_new_ssa_name (srctype, vect_simple_var);
2879 : 0 : src = build1 (VIEW_CONVERT_EXPR, srctype, src);
2880 : 0 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, src);
2881 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2882 : 0 : src = var;
2883 : : }
2884 : :
2885 : 169 : tree op = offset;
2886 : 169 : if (!useless_type_conversion_p (idxtype, TREE_TYPE (op)))
2887 : : {
2888 : 24 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)),
2889 : : TYPE_VECTOR_SUBPARTS (idxtype)));
2890 : 24 : tree var = vect_get_new_ssa_name (idxtype, vect_simple_var);
2891 : 24 : op = build1 (VIEW_CONVERT_EXPR, idxtype, op);
2892 : 24 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op);
2893 : 24 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2894 : 24 : op = var;
2895 : : }
2896 : :
2897 : 169 : tree scale = build_int_cst (scaletype, SLP_TREE_GS_SCALE (slp_node));
2898 : 169 : gcall *new_stmt
2899 : 169 : = gimple_build_call (decl, 5, ptr, mask_arg, op, src, scale);
2900 : 169 : return new_stmt;
2901 : : }
2902 : :
2903 : : /* Prepare the base and offset in GS_INFO for vectorization.
2904 : : Set *DATAREF_PTR to the loop-invariant base address and *VEC_OFFSET
2905 : : to the vectorized offset argument for the first copy of STMT_INFO.
2906 : : STMT_INFO is the statement described by GS_INFO and LOOP is the
2907 : : containing loop. */
2908 : :
2909 : : static void
2910 : 1221 : vect_get_gather_scatter_ops (class loop *loop, slp_tree slp_node,
2911 : : tree *dataref_ptr, vec<tree> *vec_offset)
2912 : : {
2913 : 1221 : gimple_seq stmts = NULL;
2914 : 1221 : *dataref_ptr = force_gimple_operand (SLP_TREE_GS_BASE (slp_node),
2915 : : &stmts, true, NULL_TREE);
2916 : 1221 : if (stmts != NULL)
2917 : : {
2918 : 986 : basic_block new_bb;
2919 : 986 : edge pe = loop_preheader_edge (loop);
2920 : 986 : new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
2921 : 986 : gcc_assert (!new_bb);
2922 : : }
2923 : 1221 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_offset);
2924 : 1221 : }
2925 : :
2926 : : /* Prepare to implement a grouped or strided load or store using
2927 : : the gather load or scatter store operation described by GS_INFO.
2928 : : STMT_INFO is the load or store statement.
2929 : :
2930 : : Set *DATAREF_BUMP to the amount that should be added to the base
2931 : : address after each copy of the vectorized statement. Set *VEC_OFFSET
2932 : : to an invariant offset vector in which element I has the value
2933 : : I * DR_STEP / SCALE. */
2934 : :
2935 : : static void
2936 : 0 : vect_get_strided_load_store_ops (stmt_vec_info stmt_info, slp_tree node,
2937 : : tree vectype, tree offset_vectype,
2938 : : loop_vec_info loop_vinfo,
2939 : : gimple_stmt_iterator *gsi,
2940 : : tree *dataref_bump, tree *vec_offset,
2941 : : vec_loop_lens *loop_lens)
2942 : : {
2943 : 0 : struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
2944 : :
2945 : 0 : if (LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo))
2946 : : {
2947 : : /* _31 = .SELECT_VL (ivtmp_29, POLY_INT_CST [4, 4]);
2948 : : ivtmp_8 = _31 * 16 (step in bytes);
2949 : : .MASK_LEN_SCATTER_STORE (vectp_a.9_7, ... );
2950 : : vectp_a.9_26 = vectp_a.9_7 + ivtmp_8; */
2951 : 0 : tree loop_len
2952 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens, 1, vectype, 0, 0);
2953 : 0 : tree tmp
2954 : 0 : = fold_build2 (MULT_EXPR, sizetype,
2955 : : fold_convert (sizetype, unshare_expr (DR_STEP (dr))),
2956 : : loop_len);
2957 : 0 : *dataref_bump = force_gimple_operand_gsi (gsi, tmp, true, NULL_TREE, true,
2958 : : GSI_SAME_STMT);
2959 : : }
2960 : : else
2961 : : {
2962 : 0 : tree bump
2963 : 0 : = size_binop (MULT_EXPR,
2964 : : fold_convert (sizetype, unshare_expr (DR_STEP (dr))),
2965 : : size_int (TYPE_VECTOR_SUBPARTS (vectype)));
2966 : 0 : *dataref_bump = cse_and_gimplify_to_preheader (loop_vinfo, bump);
2967 : : }
2968 : :
2969 : 0 : internal_fn ifn
2970 : 0 : = DR_IS_READ (dr) ? IFN_MASK_LEN_STRIDED_LOAD : IFN_MASK_LEN_STRIDED_STORE;
2971 : 0 : if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
2972 : : {
2973 : 0 : *vec_offset = cse_and_gimplify_to_preheader (loop_vinfo,
2974 : : unshare_expr (DR_STEP (dr)));
2975 : 0 : return;
2976 : : }
2977 : :
2978 : : /* The offset given in GS_INFO can have pointer type, so use the element
2979 : : type of the vector instead. */
2980 : 0 : tree offset_type = TREE_TYPE (offset_vectype);
2981 : :
2982 : : /* Calculate X = DR_STEP / SCALE and convert it to the appropriate type. */
2983 : 0 : tree step = size_binop (EXACT_DIV_EXPR, unshare_expr (DR_STEP (dr)),
2984 : : ssize_int (SLP_TREE_GS_SCALE (node)));
2985 : 0 : step = fold_convert (offset_type, step);
2986 : :
2987 : : /* Create {0, X, X*2, X*3, ...}. */
2988 : 0 : tree offset = fold_build2 (VEC_SERIES_EXPR, offset_vectype,
2989 : : build_zero_cst (offset_type), step);
2990 : 0 : *vec_offset = cse_and_gimplify_to_preheader (loop_vinfo, offset);
2991 : : }
2992 : :
2993 : : /* Prepare the pointer IVs which needs to be updated by a variable amount.
2994 : : Such variable amount is the outcome of .SELECT_VL. In this case, we can
2995 : : allow each iteration process the flexible number of elements as long as
2996 : : the number <= vf elments.
2997 : :
2998 : : Return data reference according to SELECT_VL.
2999 : : If new statements are needed, insert them before GSI. */
3000 : :
3001 : : static tree
3002 : 0 : vect_get_loop_variant_data_ptr_increment (
3003 : : vec_info *vinfo, tree aggr_type, gimple_stmt_iterator *gsi,
3004 : : vec_loop_lens *loop_lens, dr_vec_info *dr_info,
3005 : : vect_memory_access_type memory_access_type)
3006 : : {
3007 : 0 : loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (vinfo);
3008 : 0 : tree step = vect_dr_behavior (vinfo, dr_info)->step;
3009 : :
3010 : : /* gather/scatter never reach here. */
3011 : 0 : gcc_assert (!mat_gather_scatter_p (memory_access_type));
3012 : :
3013 : : /* When we support SELECT_VL pattern, we dynamic adjust
3014 : : the memory address by .SELECT_VL result.
3015 : :
3016 : : The result of .SELECT_VL is the number of elements to
3017 : : be processed of each iteration. So the memory address
3018 : : adjustment operation should be:
3019 : :
3020 : : addr = addr + .SELECT_VL (ARG..) * step;
3021 : : */
3022 : 0 : tree loop_len
3023 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens, 1, aggr_type, 0, 0);
3024 : 0 : tree len_type = TREE_TYPE (loop_len);
3025 : : /* Since the outcome of .SELECT_VL is element size, we should adjust
3026 : : it into bytesize so that it can be used in address pointer variable
3027 : : amount IVs adjustment. */
3028 : 0 : tree tmp = fold_build2 (MULT_EXPR, len_type, loop_len,
3029 : : wide_int_to_tree (len_type, wi::to_widest (step)));
3030 : 0 : tree bump = make_temp_ssa_name (len_type, NULL, "ivtmp");
3031 : 0 : gassign *assign = gimple_build_assign (bump, tmp);
3032 : 0 : gsi_insert_before (gsi, assign, GSI_SAME_STMT);
3033 : 0 : return bump;
3034 : : }
3035 : :
3036 : : /* Return the amount that should be added to a vector pointer to move
3037 : : to the next or previous copy of AGGR_TYPE. DR_INFO is the data reference
3038 : : being vectorized and MEMORY_ACCESS_TYPE describes the type of
3039 : : vectorization. */
3040 : :
3041 : : static tree
3042 : 701096 : vect_get_data_ptr_increment (vec_info *vinfo, gimple_stmt_iterator *gsi,
3043 : : dr_vec_info *dr_info, tree aggr_type,
3044 : : vect_memory_access_type memory_access_type,
3045 : : vec_loop_lens *loop_lens = nullptr)
3046 : : {
3047 : 701096 : if (memory_access_type == VMAT_INVARIANT)
3048 : 0 : return size_zero_node;
3049 : :
3050 : 701096 : loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (vinfo);
3051 : 129163 : if (loop_vinfo && LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo))
3052 : 0 : return vect_get_loop_variant_data_ptr_increment (vinfo, aggr_type, gsi,
3053 : : loop_lens, dr_info,
3054 : 0 : memory_access_type);
3055 : :
3056 : 701096 : tree iv_step = TYPE_SIZE_UNIT (aggr_type);
3057 : 701096 : tree step = vect_dr_behavior (vinfo, dr_info)->step;
3058 : 701096 : if (tree_int_cst_sgn (step) == -1)
3059 : 2816 : iv_step = fold_build1 (NEGATE_EXPR, TREE_TYPE (iv_step), iv_step);
3060 : : return iv_step;
3061 : : }
3062 : :
3063 : : /* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64,128}. */
3064 : :
3065 : : static bool
3066 : 196 : vectorizable_bswap (vec_info *vinfo,
3067 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
3068 : : slp_tree slp_node,
3069 : : slp_tree *slp_op,
3070 : : tree vectype_in, stmt_vector_for_cost *cost_vec)
3071 : : {
3072 : 196 : tree op, vectype;
3073 : 196 : gcall *stmt = as_a <gcall *> (stmt_info->stmt);
3074 : :
3075 : 196 : op = gimple_call_arg (stmt, 0);
3076 : 196 : vectype = SLP_TREE_VECTYPE (slp_node);
3077 : 196 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
3078 : :
3079 : 196 : if (TYPE_SIZE (vectype_in) != TYPE_SIZE (vectype))
3080 : : {
3081 : 0 : if (dump_enabled_p ())
3082 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3083 : : "mismatched vector sizes %T and %T\n",
3084 : : vectype_in, vectype);
3085 : 0 : return false;
3086 : : }
3087 : :
3088 : 196 : tree char_vectype = get_same_sized_vectype (char_type_node, vectype_in);
3089 : 196 : if (! char_vectype)
3090 : : return false;
3091 : :
3092 : 196 : poly_uint64 num_bytes = TYPE_VECTOR_SUBPARTS (char_vectype);
3093 : 196 : unsigned word_bytes;
3094 : 196 : if (!constant_multiple_p (num_bytes, nunits, &word_bytes))
3095 : : return false;
3096 : :
3097 : : /* The encoding uses one stepped pattern for each byte in the word. */
3098 : 196 : vec_perm_builder elts (num_bytes, word_bytes, 3);
3099 : 784 : for (unsigned i = 0; i < 3; ++i)
3100 : 3228 : for (unsigned j = 0; j < word_bytes; ++j)
3101 : 2640 : elts.quick_push ((i + 1) * word_bytes - j - 1);
3102 : :
3103 : 196 : vec_perm_indices indices (elts, 1, num_bytes);
3104 : 196 : machine_mode vmode = TYPE_MODE (char_vectype);
3105 : 196 : if (!can_vec_perm_const_p (vmode, vmode, indices))
3106 : : return false;
3107 : :
3108 : 152 : if (cost_vec)
3109 : : {
3110 : 140 : if (!vect_maybe_update_slp_op_vectype (slp_op[0], vectype_in))
3111 : : {
3112 : 0 : if (dump_enabled_p ())
3113 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3114 : : "incompatible vector types for invariants\n");
3115 : 0 : return false;
3116 : : }
3117 : :
3118 : 140 : SLP_TREE_TYPE (slp_node) = call_vec_info_type;
3119 : 140 : DUMP_VECT_SCOPE ("vectorizable_bswap");
3120 : 140 : record_stmt_cost (cost_vec,
3121 : : 1, vector_stmt, slp_node, 0, vect_prologue);
3122 : 140 : record_stmt_cost (cost_vec,
3123 : 140 : vect_get_num_copies (vinfo, slp_node),
3124 : : vec_perm, slp_node, 0, vect_body);
3125 : 140 : return true;
3126 : : }
3127 : :
3128 : 12 : tree bswap_vconst = vec_perm_indices_to_tree (char_vectype, indices);
3129 : :
3130 : : /* Transform. */
3131 : 12 : vec<tree> vec_oprnds = vNULL;
3132 : 12 : vect_get_vec_defs (vinfo, slp_node, op, &vec_oprnds);
3133 : : /* Arguments are ready. create the new vector stmt. */
3134 : 12 : unsigned i;
3135 : 12 : tree vop;
3136 : 24 : FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
3137 : : {
3138 : 12 : gimple *new_stmt;
3139 : 12 : tree tem = make_ssa_name (char_vectype);
3140 : 12 : new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
3141 : : char_vectype, vop));
3142 : 12 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3143 : 12 : tree tem2 = make_ssa_name (char_vectype);
3144 : 12 : new_stmt = gimple_build_assign (tem2, VEC_PERM_EXPR,
3145 : : tem, tem, bswap_vconst);
3146 : 12 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3147 : 12 : tem = make_ssa_name (vectype);
3148 : 12 : new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
3149 : : vectype, tem2));
3150 : 12 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3151 : 12 : slp_node->push_vec_def (new_stmt);
3152 : : }
3153 : :
3154 : 12 : vec_oprnds.release ();
3155 : 12 : return true;
3156 : 196 : }
3157 : :
3158 : : /* Return true if vector types VECTYPE_IN and VECTYPE_OUT have
3159 : : integer elements and if we can narrow VECTYPE_IN to VECTYPE_OUT
3160 : : in a single step. On success, store the binary pack code in
3161 : : *CONVERT_CODE. */
3162 : :
3163 : : static bool
3164 : 150 : simple_integer_narrowing (tree vectype_out, tree vectype_in,
3165 : : code_helper *convert_code)
3166 : : {
3167 : 300 : if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype_out))
3168 : 300 : || !INTEGRAL_TYPE_P (TREE_TYPE (vectype_in)))
3169 : : return false;
3170 : :
3171 : 60 : code_helper code;
3172 : 60 : int multi_step_cvt = 0;
3173 : 60 : auto_vec <tree, 8> interm_types;
3174 : 88 : if (!supportable_narrowing_operation (NOP_EXPR, vectype_out, vectype_in,
3175 : : &code, &multi_step_cvt, &interm_types)
3176 : 60 : || multi_step_cvt)
3177 : 28 : return false;
3178 : :
3179 : 32 : *convert_code = code;
3180 : 32 : return true;
3181 : 60 : }
3182 : :
3183 : : /* Function vectorizable_call.
3184 : :
3185 : : Check if STMT_INFO performs a function call that can be vectorized.
3186 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
3187 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
3188 : : Return true if STMT_INFO is vectorizable in this way. */
3189 : :
3190 : : static bool
3191 : 2290285 : vectorizable_call (vec_info *vinfo,
3192 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
3193 : : slp_tree slp_node,
3194 : : stmt_vector_for_cost *cost_vec)
3195 : : {
3196 : 2290285 : gcall *stmt;
3197 : 2290285 : tree vec_dest;
3198 : 2290285 : tree scalar_dest;
3199 : 2290285 : tree op;
3200 : 2290285 : tree vec_oprnd0 = NULL_TREE;
3201 : 2290285 : tree vectype_out, vectype_in;
3202 : 2290285 : poly_uint64 nunits_in;
3203 : 2290285 : poly_uint64 nunits_out;
3204 : 2290285 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
3205 : 2290285 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
3206 : 2290285 : tree fndecl, new_temp, rhs_type;
3207 : 2290285 : enum vect_def_type dt[4]
3208 : : = { vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type,
3209 : : vect_unknown_def_type };
3210 : 2290285 : tree vectypes[ARRAY_SIZE (dt)] = {};
3211 : 2290285 : slp_tree slp_op[ARRAY_SIZE (dt)] = {};
3212 : 2290285 : auto_vec<tree, 8> vargs;
3213 : 2290285 : enum { NARROW, NONE, WIDEN } modifier;
3214 : 2290285 : size_t i, nargs;
3215 : 2290285 : tree clz_ctz_arg1 = NULL_TREE;
3216 : :
3217 : 2290285 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
3218 : : return false;
3219 : :
3220 : 2290285 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
3221 : 180307 : && cost_vec)
3222 : : return false;
3223 : :
3224 : : /* Is STMT_INFO a vectorizable call? */
3225 : 2299454 : stmt = dyn_cast <gcall *> (stmt_info->stmt);
3226 : 18878 : if (!stmt)
3227 : : return false;
3228 : :
3229 : 18878 : if (gimple_call_internal_p (stmt)
3230 : 18878 : && (internal_load_fn_p (gimple_call_internal_fn (stmt))
3231 : 11833 : || internal_store_fn_p (gimple_call_internal_fn (stmt))))
3232 : : /* Handled by vectorizable_load and vectorizable_store. */
3233 : 2576 : return false;
3234 : :
3235 : 16302 : if (gimple_call_lhs (stmt) == NULL_TREE
3236 : 16302 : || TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME)
3237 : : return false;
3238 : :
3239 : 16296 : gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
3240 : :
3241 : 16296 : vectype_out = SLP_TREE_VECTYPE (slp_node);
3242 : :
3243 : : /* Process function arguments. */
3244 : 16296 : rhs_type = NULL_TREE;
3245 : 16296 : vectype_in = NULL_TREE;
3246 : 16296 : nargs = gimple_call_num_args (stmt);
3247 : :
3248 : : /* Bail out if the function has more than four arguments, we do not have
3249 : : interesting builtin functions to vectorize with more than two arguments
3250 : : except for fma. No arguments is also not good. */
3251 : 16296 : if (nargs == 0 || nargs > 4)
3252 : : return false;
3253 : :
3254 : : /* Ignore the arguments of IFN_GOMP_SIMD_LANE, they are magic. */
3255 : 16216 : combined_fn cfn = gimple_call_combined_fn (stmt);
3256 : 16216 : if (cfn == CFN_GOMP_SIMD_LANE)
3257 : : {
3258 : 3203 : nargs = 0;
3259 : 3203 : rhs_type = unsigned_type_node;
3260 : : }
3261 : : /* Similarly pretend IFN_CLZ and IFN_CTZ only has one argument, the second
3262 : : argument just says whether it is well-defined at zero or not and what
3263 : : value should be returned for it. */
3264 : 16216 : if ((cfn == CFN_CLZ || cfn == CFN_CTZ) && nargs == 2)
3265 : : {
3266 : 118 : nargs = 1;
3267 : 118 : clz_ctz_arg1 = gimple_call_arg (stmt, 1);
3268 : : }
3269 : :
3270 : 16216 : int mask_opno = -1;
3271 : 16216 : if (internal_fn_p (cfn))
3272 : : {
3273 : : /* We can only handle direct internal masked calls here,
3274 : : vectorizable_simd_clone_call is for the rest. */
3275 : 13404 : if (cfn == CFN_MASK_CALL)
3276 : : return false;
3277 : 13279 : mask_opno = internal_fn_mask_index (as_internal_fn (cfn));
3278 : : }
3279 : :
3280 : 44511 : for (i = 0; i < nargs; i++)
3281 : : {
3282 : 29472 : if ((int) i == mask_opno)
3283 : : {
3284 : 3825 : if (!vect_check_scalar_mask (vinfo, slp_node, mask_opno,
3285 : : &slp_op[i], &dt[i], &vectypes[i]))
3286 : : return false;
3287 : 3825 : continue;
3288 : : }
3289 : :
3290 : 25647 : if (!vect_is_simple_use (vinfo, slp_node,
3291 : : i, &op, &slp_op[i], &dt[i], &vectypes[i]))
3292 : : {
3293 : 0 : if (dump_enabled_p ())
3294 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3295 : : "use not simple.\n");
3296 : 0 : return false;
3297 : : }
3298 : :
3299 : : /* We can only handle calls with arguments of the same type. */
3300 : 25647 : if (rhs_type
3301 : 25647 : && !types_compatible_p (rhs_type, TREE_TYPE (op)))
3302 : : {
3303 : 1052 : if (dump_enabled_p ())
3304 : 200 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3305 : : "argument types differ.\n");
3306 : 1052 : return false;
3307 : : }
3308 : 24595 : if (!rhs_type)
3309 : 12888 : rhs_type = TREE_TYPE (op);
3310 : :
3311 : 24595 : if (!vectype_in)
3312 : 13361 : vectype_in = vectypes[i];
3313 : 11234 : else if (vectypes[i]
3314 : 11234 : && !types_compatible_p (vectypes[i], vectype_in))
3315 : : {
3316 : 0 : if (dump_enabled_p ())
3317 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3318 : : "argument vector types differ.\n");
3319 : 0 : return false;
3320 : : }
3321 : : }
3322 : : /* If all arguments are external or constant defs, infer the vector type
3323 : : from the scalar type. */
3324 : 15039 : if (!vectype_in)
3325 : 5493 : vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
3326 : 15039 : if (!cost_vec)
3327 : 4195 : gcc_assert (vectype_in);
3328 : 10844 : if (!vectype_in)
3329 : : {
3330 : 1019 : if (dump_enabled_p ())
3331 : 4 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3332 : : "no vectype for scalar type %T\n", rhs_type);
3333 : :
3334 : 1019 : return false;
3335 : : }
3336 : :
3337 : 28040 : if (VECTOR_BOOLEAN_TYPE_P (vectype_out)
3338 : 14020 : != VECTOR_BOOLEAN_TYPE_P (vectype_in))
3339 : : {
3340 : 12 : if (dump_enabled_p ())
3341 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3342 : : "mixed mask and nonmask vector types\n");
3343 : 12 : return false;
3344 : : }
3345 : :
3346 : 14008 : if (vect_emulated_vector_p (vectype_in)
3347 : 14008 : || vect_emulated_vector_p (vectype_out))
3348 : : {
3349 : 0 : if (dump_enabled_p ())
3350 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3351 : : "use emulated vector type for call\n");
3352 : 0 : return false;
3353 : : }
3354 : :
3355 : : /* FORNOW */
3356 : 14008 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
3357 : 14008 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
3358 : 14008 : if (known_eq (nunits_in * 2, nunits_out))
3359 : : modifier = NARROW;
3360 : 13616 : else if (known_eq (nunits_out, nunits_in))
3361 : : modifier = NONE;
3362 : 19 : else if (known_eq (nunits_out * 2, nunits_in))
3363 : : modifier = WIDEN;
3364 : : else
3365 : : return false;
3366 : :
3367 : : /* We only handle functions that do not read or clobber memory. */
3368 : 28016 : if (gimple_vuse (stmt))
3369 : : {
3370 : 1228 : if (dump_enabled_p ())
3371 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3372 : : "function reads from or writes to memory.\n");
3373 : 1228 : return false;
3374 : : }
3375 : :
3376 : : /* For now, we only vectorize functions if a target specific builtin
3377 : : is available. TODO -- in some cases, it might be profitable to
3378 : : insert the calls for pieces of the vector, in order to be able
3379 : : to vectorize other operations in the loop. */
3380 : 12780 : fndecl = NULL_TREE;
3381 : 12780 : internal_fn ifn = IFN_LAST;
3382 : 12780 : tree callee = gimple_call_fndecl (stmt);
3383 : :
3384 : : /* First try using an internal function. */
3385 : 12780 : code_helper convert_code = MAX_TREE_CODES;
3386 : 12780 : if (cfn != CFN_LAST
3387 : 12780 : && (modifier == NONE
3388 : 166 : || (modifier == NARROW
3389 : 150 : && simple_integer_narrowing (vectype_out, vectype_in,
3390 : : &convert_code))))
3391 : 12009 : ifn = vectorizable_internal_function (cfn, callee, vectype_out,
3392 : : vectype_in);
3393 : :
3394 : : /* If that fails, try asking for a target-specific built-in function. */
3395 : 12009 : if (ifn == IFN_LAST)
3396 : : {
3397 : 6764 : if (cfn != CFN_LAST)
3398 : 6127 : fndecl = targetm.vectorize.builtin_vectorized_function
3399 : 6127 : (cfn, vectype_out, vectype_in);
3400 : 637 : else if (callee && fndecl_built_in_p (callee, BUILT_IN_MD))
3401 : 24 : fndecl = targetm.vectorize.builtin_md_vectorized_function
3402 : 24 : (callee, vectype_out, vectype_in);
3403 : : }
3404 : :
3405 : 12780 : if (ifn == IFN_LAST && !fndecl)
3406 : : {
3407 : 6470 : if (cfn == CFN_GOMP_SIMD_LANE
3408 : 3203 : && SLP_TREE_LANES (slp_node) == 1
3409 : 3203 : && loop_vinfo
3410 : 3203 : && LOOP_VINFO_LOOP (loop_vinfo)->simduid
3411 : 3203 : && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME
3412 : 12876 : && LOOP_VINFO_LOOP (loop_vinfo)->simduid
3413 : 3203 : == SSA_NAME_VAR (gimple_call_arg (stmt, 0)))
3414 : : {
3415 : : /* We can handle IFN_GOMP_SIMD_LANE by returning a
3416 : : { 0, 1, 2, ... vf - 1 } vector. */
3417 : 3203 : gcc_assert (nargs == 0);
3418 : : }
3419 : 3267 : else if (modifier == NONE
3420 : 3267 : && (gimple_call_builtin_p (stmt, BUILT_IN_BSWAP16)
3421 : 3123 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP32)
3422 : 2975 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64)
3423 : 2943 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP128)))
3424 : 196 : return vectorizable_bswap (vinfo, stmt_info, gsi, slp_node,
3425 : 196 : slp_op, vectype_in, cost_vec);
3426 : : else
3427 : : {
3428 : 3071 : if (dump_enabled_p ())
3429 : 243 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3430 : : "function is not vectorizable.\n");
3431 : 3071 : return false;
3432 : : }
3433 : : }
3434 : :
3435 : 9513 : int reduc_idx = SLP_TREE_REDUC_IDX (slp_node);
3436 : 9513 : internal_fn cond_fn = get_conditional_internal_fn (ifn);
3437 : 9513 : internal_fn cond_len_fn = get_len_internal_fn (ifn);
3438 : 9513 : int len_opno = internal_fn_len_index (cond_len_fn);
3439 : 9513 : vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL);
3440 : 7503 : vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL);
3441 : 9513 : unsigned int nvectors = vect_get_num_copies (vinfo, slp_node);
3442 : 9513 : if (cost_vec) /* transformation not required. */
3443 : : {
3444 : 15670 : for (i = 0; i < nargs; ++i)
3445 : 10340 : if (!vect_maybe_update_slp_op_vectype (slp_op[i],
3446 : 10340 : vectypes[i]
3447 : : ? vectypes[i] : vectype_in))
3448 : : {
3449 : 0 : if (dump_enabled_p ())
3450 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3451 : : "incompatible vector types for invariants\n");
3452 : 0 : return false;
3453 : : }
3454 : 5330 : SLP_TREE_TYPE (slp_node) = call_vec_info_type;
3455 : 5330 : DUMP_VECT_SCOPE ("vectorizable_call");
3456 : 5330 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
3457 : :
3458 : 5330 : if (loop_vinfo
3459 : 4318 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
3460 : 19 : && (reduc_idx >= 0 || mask_opno >= 0))
3461 : : {
3462 : 18 : if (reduc_idx >= 0
3463 : 0 : && (cond_fn == IFN_LAST
3464 : 0 : || !direct_internal_fn_supported_p (cond_fn, vectype_out,
3465 : : OPTIMIZE_FOR_SPEED))
3466 : 18 : && (cond_len_fn == IFN_LAST
3467 : 0 : || !direct_internal_fn_supported_p (cond_len_fn, vectype_out,
3468 : : OPTIMIZE_FOR_SPEED)))
3469 : : {
3470 : 0 : if (dump_enabled_p ())
3471 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3472 : : "can't use a fully-masked loop because no"
3473 : : " conditional operation is available.\n");
3474 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
3475 : : }
3476 : : else
3477 : : {
3478 : 18 : tree scalar_mask = NULL_TREE;
3479 : 18 : if (mask_opno >= 0)
3480 : 18 : scalar_mask = gimple_call_arg (stmt_info->stmt, mask_opno);
3481 : 18 : if (cond_len_fn != IFN_LAST
3482 : 18 : && direct_internal_fn_supported_p (cond_len_fn, vectype_out,
3483 : : OPTIMIZE_FOR_SPEED))
3484 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype_out,
3485 : : 1);
3486 : : else
3487 : 18 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype_out,
3488 : : scalar_mask);
3489 : : }
3490 : : }
3491 : 5330 : return true;
3492 : : }
3493 : :
3494 : : /* Transform. */
3495 : :
3496 : 4183 : if (dump_enabled_p ())
3497 : 414 : dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n");
3498 : :
3499 : : /* Handle def. */
3500 : 4183 : scalar_dest = gimple_call_lhs (stmt);
3501 : 4183 : vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
3502 : :
3503 : 4183 : bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
3504 : 3185 : bool len_loop_p = loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
3505 : 4183 : unsigned int vect_nargs = nargs;
3506 : 4183 : if (len_loop_p)
3507 : : {
3508 : 0 : if (len_opno >= 0)
3509 : : {
3510 : 0 : ifn = cond_len_fn;
3511 : : /* COND_* -> COND_LEN_* takes 2 extra arguments:LEN,BIAS. */
3512 : 0 : vect_nargs += 2;
3513 : : }
3514 : 0 : else if (reduc_idx >= 0)
3515 : 0 : gcc_unreachable ();
3516 : : }
3517 : 4183 : else if (masked_loop_p && reduc_idx >= 0)
3518 : : {
3519 : 0 : ifn = cond_fn;
3520 : 0 : vect_nargs += 2;
3521 : : }
3522 : 4183 : if (clz_ctz_arg1)
3523 : 59 : ++vect_nargs;
3524 : :
3525 : 4183 : if (modifier == NONE || ifn != IFN_LAST)
3526 : : {
3527 : 4151 : tree prev_res = NULL_TREE;
3528 : 4151 : vargs.safe_grow (vect_nargs, true);
3529 : 4151 : auto_vec<vec<tree> > vec_defs (nargs);
3530 : :
3531 : : /* Build argument list for the vectorized call. */
3532 : 4151 : if (cfn == CFN_GOMP_SIMD_LANE)
3533 : : {
3534 : 3304 : for (i = 0; i < nvectors; ++i)
3535 : : {
3536 : : /* ??? For multi-lane SLP we'd need to build
3537 : : { 0, 0, .., 1, 1, ... }. */
3538 : 1706 : tree cst = build_index_vector (vectype_out,
3539 : : i * nunits_out, 1);
3540 : 1706 : tree new_var
3541 : 1706 : = vect_get_new_ssa_name (vectype_out, vect_simple_var, "cst_");
3542 : 1706 : gimple *init_stmt = gimple_build_assign (new_var, cst);
3543 : 1706 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, NULL);
3544 : 1706 : new_temp = make_ssa_name (vec_dest);
3545 : 1706 : gimple *new_stmt = gimple_build_assign (new_temp, new_var);
3546 : 1706 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3547 : 1706 : slp_node->push_vec_def (new_stmt);
3548 : : }
3549 : : }
3550 : : else
3551 : : {
3552 : 2553 : vec<tree> vec_oprnds0;
3553 : 2553 : vect_get_slp_defs (vinfo, slp_node, &vec_defs);
3554 : 2553 : vec_oprnds0 = vec_defs[0];
3555 : :
3556 : : /* Arguments are ready. Create the new vector stmt. */
3557 : 5274 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_oprnd0)
3558 : : {
3559 : 2721 : int varg = 0;
3560 : 2721 : if (masked_loop_p && reduc_idx >= 0)
3561 : : {
3562 : 0 : unsigned int vec_num = vec_oprnds0.length ();
3563 : 0 : vargs[varg++] = vect_get_loop_mask (loop_vinfo, gsi, masks,
3564 : : vec_num, vectype_out, i);
3565 : : }
3566 : : size_t k;
3567 : 9564 : for (k = 0; k < nargs; k++)
3568 : : {
3569 : 6843 : vec<tree> vec_oprndsk = vec_defs[k];
3570 : 6843 : vargs[varg++] = vec_oprndsk[i];
3571 : : }
3572 : 2721 : if (masked_loop_p && reduc_idx >= 0)
3573 : 0 : vargs[varg++] = vargs[reduc_idx + 1];
3574 : 2721 : if (clz_ctz_arg1)
3575 : 59 : vargs[varg++] = clz_ctz_arg1;
3576 : :
3577 : 2721 : gimple *new_stmt;
3578 : 2721 : if (modifier == NARROW)
3579 : : {
3580 : : /* We don't define any narrowing conditional functions
3581 : : at present. */
3582 : 0 : gcc_assert (mask_opno < 0);
3583 : 0 : tree half_res = make_ssa_name (vectype_in);
3584 : 0 : gcall *call = gimple_build_call_internal_vec (ifn, vargs);
3585 : 0 : gimple_call_set_lhs (call, half_res);
3586 : 0 : gimple_call_set_nothrow (call, true);
3587 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3588 : 0 : if ((i & 1) == 0)
3589 : : {
3590 : 0 : prev_res = half_res;
3591 : 0 : continue;
3592 : : }
3593 : 0 : new_temp = make_ssa_name (vec_dest);
3594 : 0 : new_stmt = vect_gimple_build (new_temp, convert_code,
3595 : : prev_res, half_res);
3596 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3597 : : }
3598 : : else
3599 : : {
3600 : 2721 : if (len_opno >= 0 && len_loop_p)
3601 : : {
3602 : 0 : unsigned int vec_num = vec_oprnds0.length ();
3603 : 0 : tree len = vect_get_loop_len (loop_vinfo, gsi, lens,
3604 : : vec_num, vectype_out, i, 1);
3605 : 0 : signed char biasval
3606 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
3607 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
3608 : 0 : vargs[len_opno] = len;
3609 : 0 : vargs[len_opno + 1] = bias;
3610 : : }
3611 : 2721 : else if (mask_opno >= 0 && masked_loop_p)
3612 : : {
3613 : 36 : unsigned int vec_num = vec_oprnds0.length ();
3614 : 36 : tree mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
3615 : : vec_num, vectype_out, i);
3616 : 36 : vargs[mask_opno]
3617 : 72 : = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
3618 : 36 : vargs[mask_opno], gsi);
3619 : : }
3620 : :
3621 : 2721 : gcall *call;
3622 : 2721 : if (ifn != IFN_LAST)
3623 : 2640 : call = gimple_build_call_internal_vec (ifn, vargs);
3624 : : else
3625 : 81 : call = gimple_build_call_vec (fndecl, vargs);
3626 : 2721 : new_temp = make_ssa_name (vec_dest, call);
3627 : 2721 : gimple_call_set_lhs (call, new_temp);
3628 : 2721 : gimple_call_set_nothrow (call, true);
3629 : 2721 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3630 : 2721 : new_stmt = call;
3631 : : }
3632 : 2721 : slp_node->push_vec_def (new_stmt);
3633 : : }
3634 : : }
3635 : :
3636 : 10611 : for (i = 0; i < nargs; i++)
3637 : : {
3638 : 6460 : vec<tree> vec_oprndsi = vec_defs[i];
3639 : 6460 : vec_oprndsi.release ();
3640 : : }
3641 : 4151 : }
3642 : 32 : else if (modifier == NARROW)
3643 : : {
3644 : 32 : auto_vec<vec<tree> > vec_defs (nargs);
3645 : : /* We don't define any narrowing conditional functions at present. */
3646 : 32 : gcc_assert (mask_opno < 0);
3647 : :
3648 : : /* Build argument list for the vectorized call. */
3649 : 32 : vargs.create (nargs * 2);
3650 : :
3651 : 32 : vect_get_slp_defs (vinfo, slp_node, &vec_defs);
3652 : 32 : vec<tree> vec_oprnds0 = vec_defs[0];
3653 : :
3654 : : /* Arguments are ready. Create the new vector stmt. */
3655 : 64 : for (i = 0; vec_oprnds0.iterate (i, &vec_oprnd0); i += 2)
3656 : : {
3657 : 32 : size_t k;
3658 : 32 : vargs.truncate (0);
3659 : 64 : for (k = 0; k < nargs; k++)
3660 : : {
3661 : 32 : vec<tree> vec_oprndsk = vec_defs[k];
3662 : 32 : vargs.quick_push (vec_oprndsk[i]);
3663 : 32 : vargs.quick_push (vec_oprndsk[i + 1]);
3664 : : }
3665 : 32 : gcall *call;
3666 : 32 : if (ifn != IFN_LAST)
3667 : : call = gimple_build_call_internal_vec (ifn, vargs);
3668 : : else
3669 : 32 : call = gimple_build_call_vec (fndecl, vargs);
3670 : 32 : new_temp = make_ssa_name (vec_dest, call);
3671 : 32 : gimple_call_set_lhs (call, new_temp);
3672 : 32 : gimple_call_set_nothrow (call, true);
3673 : 32 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3674 : 32 : slp_node->push_vec_def (call);
3675 : : }
3676 : :
3677 : 64 : for (i = 0; i < nargs; i++)
3678 : : {
3679 : 32 : vec<tree> vec_oprndsi = vec_defs[i];
3680 : 32 : vec_oprndsi.release ();
3681 : : }
3682 : 32 : }
3683 : : else
3684 : : /* No current target implements this case. */
3685 : : return false;
3686 : :
3687 : 4183 : vargs.release ();
3688 : :
3689 : 4183 : return true;
3690 : 2290285 : }
3691 : :
3692 : :
3693 : : struct simd_call_arg_info
3694 : : {
3695 : : tree vectype;
3696 : : tree op;
3697 : : HOST_WIDE_INT linear_step;
3698 : : enum vect_def_type dt;
3699 : : unsigned int align;
3700 : : bool simd_lane_linear;
3701 : : };
3702 : :
3703 : : /* Helper function of vectorizable_simd_clone_call. If OP, an SSA_NAME,
3704 : : is linear within simd lane (but not within whole loop), note it in
3705 : : *ARGINFO. */
3706 : :
3707 : : static void
3708 : 15 : vect_simd_lane_linear (tree op, class loop *loop,
3709 : : struct simd_call_arg_info *arginfo)
3710 : : {
3711 : 15 : gimple *def_stmt = SSA_NAME_DEF_STMT (op);
3712 : :
3713 : 15 : if (!is_gimple_assign (def_stmt)
3714 : 15 : || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR
3715 : 27 : || !is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt)))
3716 : 3 : return;
3717 : :
3718 : 12 : tree base = gimple_assign_rhs1 (def_stmt);
3719 : 12 : HOST_WIDE_INT linear_step = 0;
3720 : 12 : tree v = gimple_assign_rhs2 (def_stmt);
3721 : 48 : while (TREE_CODE (v) == SSA_NAME)
3722 : : {
3723 : 36 : tree t;
3724 : 36 : def_stmt = SSA_NAME_DEF_STMT (v);
3725 : 36 : if (is_gimple_assign (def_stmt))
3726 : 24 : switch (gimple_assign_rhs_code (def_stmt))
3727 : : {
3728 : 0 : case PLUS_EXPR:
3729 : 0 : t = gimple_assign_rhs2 (def_stmt);
3730 : 0 : if (linear_step || TREE_CODE (t) != INTEGER_CST)
3731 : : return;
3732 : 0 : base = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, t);
3733 : 0 : v = gimple_assign_rhs1 (def_stmt);
3734 : 0 : continue;
3735 : 12 : case MULT_EXPR:
3736 : 12 : t = gimple_assign_rhs2 (def_stmt);
3737 : 12 : if (linear_step || !tree_fits_shwi_p (t) || integer_zerop (t))
3738 : 0 : return;
3739 : 12 : linear_step = tree_to_shwi (t);
3740 : 12 : v = gimple_assign_rhs1 (def_stmt);
3741 : 12 : continue;
3742 : 12 : CASE_CONVERT:
3743 : 12 : t = gimple_assign_rhs1 (def_stmt);
3744 : 12 : if (TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE
3745 : 12 : || (TYPE_PRECISION (TREE_TYPE (v))
3746 : 12 : < TYPE_PRECISION (TREE_TYPE (t))))
3747 : : return;
3748 : 12 : if (!linear_step)
3749 : 0 : linear_step = 1;
3750 : 12 : v = t;
3751 : 12 : continue;
3752 : : default:
3753 : : return;
3754 : : }
3755 : 12 : else if (gimple_call_internal_p (def_stmt, IFN_GOMP_SIMD_LANE)
3756 : 12 : && loop->simduid
3757 : 12 : && TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME
3758 : 24 : && (SSA_NAME_VAR (gimple_call_arg (def_stmt, 0))
3759 : : == loop->simduid))
3760 : : {
3761 : 12 : if (!linear_step)
3762 : 0 : linear_step = 1;
3763 : 12 : arginfo->linear_step = linear_step;
3764 : 12 : arginfo->op = base;
3765 : 12 : arginfo->simd_lane_linear = true;
3766 : 12 : return;
3767 : : }
3768 : : }
3769 : : }
3770 : :
3771 : : /* Function vectorizable_simd_clone_call.
3772 : :
3773 : : Check if STMT_INFO performs a function call that can be vectorized
3774 : : by calling a simd clone of the function.
3775 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
3776 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
3777 : : Return true if STMT_INFO is vectorizable in this way. */
3778 : :
3779 : : static bool
3780 : 2280964 : vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
3781 : : gimple_stmt_iterator *gsi,
3782 : : slp_tree slp_node,
3783 : : stmt_vector_for_cost *cost_vec)
3784 : : {
3785 : 2280964 : tree vec_dest;
3786 : 2280964 : tree scalar_dest;
3787 : 2280964 : tree op;
3788 : 2280964 : tree vec_oprnd0 = NULL_TREE;
3789 : 2280964 : tree vectype;
3790 : 2280964 : poly_uint64 nunits;
3791 : 2280964 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
3792 : 2280964 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
3793 : 2280964 : class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
3794 : 2280964 : tree fndecl, new_temp;
3795 : 2280964 : int ncopies, j;
3796 : 2280964 : auto_vec<simd_call_arg_info> arginfo;
3797 : 2280964 : vec<tree> vargs = vNULL;
3798 : 2280964 : size_t i, nargs;
3799 : 2280964 : tree rtype, ratype;
3800 : 2280964 : vec<constructor_elt, va_gc> *ret_ctor_elts = NULL;
3801 : 2280964 : int masked_call_offset = 0;
3802 : :
3803 : : /* Is STMT a vectorizable call? */
3804 : 2280964 : gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt);
3805 : 10153 : if (!stmt)
3806 : : return false;
3807 : :
3808 : 10153 : fndecl = gimple_call_fndecl (stmt);
3809 : 10153 : if (fndecl == NULL_TREE
3810 : 10153 : && gimple_call_internal_p (stmt, IFN_MASK_CALL))
3811 : : {
3812 : 186 : fndecl = gimple_call_arg (stmt, 0);
3813 : 186 : gcc_checking_assert (TREE_CODE (fndecl) == ADDR_EXPR);
3814 : 186 : fndecl = TREE_OPERAND (fndecl, 0);
3815 : 186 : gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
3816 : : masked_call_offset = 1;
3817 : : }
3818 : 9967 : if (fndecl == NULL_TREE)
3819 : : return false;
3820 : :
3821 : 4335 : struct cgraph_node *node = cgraph_node::get (fndecl);
3822 : 4335 : if (node == NULL || node->simd_clones == NULL)
3823 : : return false;
3824 : :
3825 : 1404 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
3826 : : return false;
3827 : :
3828 : 1404 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
3829 : 0 : && cost_vec)
3830 : : return false;
3831 : :
3832 : 1404 : if (gimple_call_lhs (stmt)
3833 : 1404 : && TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME)
3834 : : return false;
3835 : :
3836 : 1404 : gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
3837 : :
3838 : 1404 : vectype = SLP_TREE_VECTYPE (slp_node);
3839 : :
3840 : 2281028 : if (loop_vinfo && nested_in_vect_loop_p (loop, stmt_info))
3841 : : return false;
3842 : :
3843 : : /* Process function arguments. */
3844 : 1404 : nargs = gimple_call_num_args (stmt) - masked_call_offset;
3845 : :
3846 : : /* Bail out if the function has zero arguments. */
3847 : 1404 : if (nargs == 0)
3848 : : return false;
3849 : :
3850 : 1340 : vect_simd_clone_data _data;
3851 : 1340 : vect_simd_clone_data &data = slp_node->get_data (_data);
3852 : 1340 : vec<tree>& simd_clone_info = data.simd_clone_info;
3853 : 1340 : arginfo.reserve (nargs, true);
3854 : 1340 : auto_vec<slp_tree> slp_op;
3855 : 1340 : slp_op.safe_grow_cleared (nargs);
3856 : :
3857 : 3852 : for (i = 0; i < nargs; i++)
3858 : : {
3859 : 2512 : simd_call_arg_info thisarginfo;
3860 : 2512 : affine_iv iv;
3861 : :
3862 : 2512 : thisarginfo.linear_step = 0;
3863 : 2512 : thisarginfo.align = 0;
3864 : 2512 : thisarginfo.op = NULL_TREE;
3865 : 2512 : thisarginfo.simd_lane_linear = false;
3866 : :
3867 : 5024 : int op_no = vect_slp_child_index_for_operand (stmt,
3868 : 2512 : i + masked_call_offset,
3869 : : false);
3870 : 5024 : if (!vect_is_simple_use (vinfo, slp_node,
3871 : 2512 : op_no, &op, &slp_op[i],
3872 : : &thisarginfo.dt, &thisarginfo.vectype)
3873 : 2512 : || thisarginfo.dt == vect_uninitialized_def)
3874 : : {
3875 : 0 : if (dump_enabled_p ())
3876 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3877 : : "use not simple.\n");
3878 : 0 : return false;
3879 : : }
3880 : :
3881 : 2512 : if (thisarginfo.dt == vect_constant_def
3882 : 2512 : || thisarginfo.dt == vect_external_def)
3883 : : {
3884 : : /* With SLP we determine the vector type of constants/externals
3885 : : at analysis time, handling conflicts via
3886 : : vect_maybe_update_slp_op_vectype. At transform time
3887 : : we have a vector type recorded for SLP. */
3888 : 697 : gcc_assert (cost_vec
3889 : : || thisarginfo.vectype != NULL_TREE);
3890 : : if (cost_vec)
3891 : 567 : thisarginfo.vectype = get_vectype_for_scalar_type (vinfo,
3892 : 567 : TREE_TYPE (op),
3893 : : slp_node);
3894 : : }
3895 : : else
3896 : 1815 : gcc_assert (thisarginfo.vectype != NULL_TREE);
3897 : :
3898 : : /* For linear arguments, the analyze phase should have saved
3899 : : the base and step in {STMT_VINFO,SLP_TREE}_SIMD_CLONE_INFO. */
3900 : 2382 : if (!cost_vec
3901 : 1546 : && i * 3 + 4 <= simd_clone_info.length ()
3902 : 2592 : && simd_clone_info[i * 3 + 2])
3903 : : {
3904 : 118 : thisarginfo.linear_step = tree_to_shwi (simd_clone_info[i * 3 + 2]);
3905 : 118 : thisarginfo.op = simd_clone_info[i * 3 + 1];
3906 : 118 : thisarginfo.simd_lane_linear
3907 : 118 : = (simd_clone_info[i * 3 + 3] == boolean_true_node);
3908 : : /* If loop has been peeled for alignment, we need to adjust it. */
3909 : 118 : tree n1 = LOOP_VINFO_NITERS_UNCHANGED (loop_vinfo);
3910 : 118 : tree n2 = LOOP_VINFO_NITERS (loop_vinfo);
3911 : 118 : if (n1 != n2 && !thisarginfo.simd_lane_linear)
3912 : : {
3913 : 0 : tree bias = fold_build2 (MINUS_EXPR, TREE_TYPE (n1), n1, n2);
3914 : 0 : tree step = simd_clone_info[i * 3 + 2];
3915 : 0 : tree opt = TREE_TYPE (thisarginfo.op);
3916 : 0 : bias = fold_convert (TREE_TYPE (step), bias);
3917 : 0 : bias = fold_build2 (MULT_EXPR, TREE_TYPE (step), bias, step);
3918 : 0 : thisarginfo.op
3919 : 0 : = fold_build2 (POINTER_TYPE_P (opt)
3920 : : ? POINTER_PLUS_EXPR : PLUS_EXPR, opt,
3921 : : thisarginfo.op, bias);
3922 : : }
3923 : : }
3924 : 2394 : else if (cost_vec
3925 : 1739 : && thisarginfo.dt != vect_constant_def
3926 : 1616 : && thisarginfo.dt != vect_external_def
3927 : 1172 : && loop_vinfo
3928 : 1169 : && TREE_CODE (op) == SSA_NAME
3929 : 2338 : && simple_iv (loop, loop_containing_stmt (stmt), op,
3930 : : &iv, false)
3931 : 2598 : && tree_fits_shwi_p (iv.step))
3932 : : {
3933 : 204 : thisarginfo.linear_step = tree_to_shwi (iv.step);
3934 : 204 : thisarginfo.op = iv.base;
3935 : : }
3936 : 2190 : else if ((thisarginfo.dt == vect_constant_def
3937 : 2190 : || thisarginfo.dt == vect_external_def)
3938 : 2190 : && POINTER_TYPE_P (TREE_TYPE (op)))
3939 : 479 : thisarginfo.align = get_pointer_alignment (op) / BITS_PER_UNIT;
3940 : : /* Addresses of array elements indexed by GOMP_SIMD_LANE are
3941 : : linear too. */
3942 : 4435 : if (POINTER_TYPE_P (TREE_TYPE (op))
3943 : 589 : && !thisarginfo.linear_step
3944 : 505 : && cost_vec
3945 : 451 : && thisarginfo.dt != vect_constant_def
3946 : 451 : && thisarginfo.dt != vect_external_def
3947 : 15 : && loop_vinfo
3948 : 2527 : && TREE_CODE (op) == SSA_NAME)
3949 : 15 : vect_simd_lane_linear (op, loop, &thisarginfo);
3950 : :
3951 : 2512 : arginfo.quick_push (thisarginfo);
3952 : : }
3953 : :
3954 : 1340 : poly_uint64 vf = loop_vinfo ? LOOP_VINFO_VECT_FACTOR (loop_vinfo) : 1;
3955 : 1340 : unsigned group_size = SLP_TREE_LANES (slp_node);
3956 : 1340 : unsigned int badness = 0;
3957 : 1340 : struct cgraph_node *bestn = NULL;
3958 : 1340 : if (!cost_vec)
3959 : 344 : bestn = cgraph_node::get (simd_clone_info[0]);
3960 : : else
3961 : 5746 : for (struct cgraph_node *n = node->simd_clones; n != NULL;
3962 : 4750 : n = n->simdclone->next_clone)
3963 : : {
3964 : 4750 : unsigned int this_badness = 0;
3965 : 4750 : unsigned int num_calls;
3966 : : /* The number of arguments in the call and the number of parameters in
3967 : : the simdclone should match. However, when the simdclone is
3968 : : 'inbranch', it could have one more paramater than nargs when using
3969 : : an inbranch simdclone to call a non-inbranch call, either in a
3970 : : non-masked loop using a all true constant mask, or inside a masked
3971 : : loop using it's mask. */
3972 : 4750 : size_t simd_nargs = n->simdclone->nargs;
3973 : 4750 : if (!masked_call_offset && n->simdclone->inbranch)
3974 : 2321 : simd_nargs--;
3975 : 4750 : if (!constant_multiple_p (vf * group_size, n->simdclone->simdlen,
3976 : : &num_calls)
3977 : 1850 : || (!n->simdclone->inbranch && (masked_call_offset > 0))
3978 : 1700 : || (nargs != simd_nargs))
3979 : 3050 : continue;
3980 : 1700 : if (num_calls != 1)
3981 : 1108 : this_badness += floor_log2 (num_calls) * 4096;
3982 : 1700 : if (n->simdclone->inbranch)
3983 : 705 : this_badness += 8192;
3984 : :
3985 : : /* If SLP_TREE_VECTYPE has not been set yet pass the general vector
3986 : : mode, which for targets that use it will determine what ISA we can
3987 : : vectorize this code with. */
3988 : 1700 : machine_mode vector_mode = vinfo->vector_mode;
3989 : 1700 : if (vectype)
3990 : 1680 : vector_mode = TYPE_MODE (vectype);
3991 : 1700 : int target_badness = targetm.simd_clone.usable (n, vector_mode);
3992 : 1700 : if (target_badness < 0)
3993 : 370 : continue;
3994 : 1330 : this_badness += target_badness * 512;
3995 : 4149 : for (i = 0; i < nargs; i++)
3996 : : {
3997 : 2876 : switch (n->simdclone->args[i].arg_type)
3998 : : {
3999 : 1992 : case SIMD_CLONE_ARG_TYPE_VECTOR:
4000 : 1992 : if (!useless_type_conversion_p
4001 : 1992 : (n->simdclone->args[i].orig_type,
4002 : 1992 : TREE_TYPE (gimple_call_arg (stmt,
4003 : : i + masked_call_offset))))
4004 : : i = -1;
4005 : 1992 : else if (arginfo[i].dt == vect_constant_def
4006 : 1887 : || arginfo[i].dt == vect_external_def
4007 : 3817 : || arginfo[i].linear_step)
4008 : 386 : this_badness += 64;
4009 : : break;
4010 : 314 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
4011 : 314 : if (arginfo[i].dt != vect_constant_def
4012 : 314 : && arginfo[i].dt != vect_external_def)
4013 : : i = -1;
4014 : : break;
4015 : 324 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4016 : 324 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4017 : 324 : if (arginfo[i].dt == vect_constant_def
4018 : 324 : || arginfo[i].dt == vect_external_def
4019 : 324 : || (arginfo[i].linear_step
4020 : 324 : != n->simdclone->args[i].linear_step))
4021 : : i = -1;
4022 : : break;
4023 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
4024 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
4025 : : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
4026 : : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
4027 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
4028 : : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
4029 : : /* FORNOW */
4030 : : i = -1;
4031 : : break;
4032 : 246 : case SIMD_CLONE_ARG_TYPE_MASK:
4033 : : /* While we can create a traditional data vector from
4034 : : an incoming integer mode mask we have no good way to
4035 : : force generate an integer mode mask from a traditional
4036 : : boolean vector input. */
4037 : 246 : if (SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4038 : 246 : && !SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype)))
4039 : : i = -1;
4040 : 240 : else if (!SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4041 : 240 : && SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype)))
4042 : 45 : this_badness += 2048;
4043 : : break;
4044 : : }
4045 : 2819 : if (i == (size_t) -1)
4046 : : break;
4047 : 2819 : if (n->simdclone->args[i].alignment > arginfo[i].align)
4048 : : {
4049 : : i = -1;
4050 : : break;
4051 : : }
4052 : 2819 : if (arginfo[i].align)
4053 : 110 : this_badness += (exact_log2 (arginfo[i].align)
4054 : 160 : - exact_log2 (n->simdclone->args[i].alignment));
4055 : : }
4056 : 1330 : if (i == (size_t) -1)
4057 : 57 : continue;
4058 : 1273 : if (masked_call_offset == 0
4059 : 1033 : && n->simdclone->inbranch
4060 : 334 : && n->simdclone->nargs > nargs)
4061 : : {
4062 : 334 : gcc_assert (n->simdclone->args[n->simdclone->nargs - 1].arg_type ==
4063 : : SIMD_CLONE_ARG_TYPE_MASK);
4064 : : /* Penalize using a masked SIMD clone in a non-masked loop, that is
4065 : : not in a branch, as we'd have to construct an all-true mask. */
4066 : 334 : if (!loop_vinfo || !LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4067 : 334 : this_badness += 64;
4068 : : }
4069 : 1273 : if (bestn == NULL || this_badness < badness)
4070 : : {
4071 : 4750 : bestn = n;
4072 : 4750 : badness = this_badness;
4073 : : }
4074 : : }
4075 : :
4076 : 1340 : if (bestn == NULL)
4077 : : return false;
4078 : :
4079 : 825 : unsigned int num_mask_args = 0;
4080 : 825 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4081 : 111 : for (i = 0; i < nargs; i++)
4082 : 72 : if (bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
4083 : 18 : num_mask_args++;
4084 : :
4085 : 2650 : for (i = 0; i < nargs; i++)
4086 : : {
4087 : 1867 : if ((arginfo[i].dt == vect_constant_def
4088 : 1698 : || arginfo[i].dt == vect_external_def)
4089 : 1968 : && bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
4090 : : {
4091 : 65 : tree arg_type = TREE_TYPE (gimple_call_arg (stmt,
4092 : : i + masked_call_offset));
4093 : 65 : arginfo[i].vectype = get_vectype_for_scalar_type (vinfo, arg_type,
4094 : : slp_node);
4095 : 65 : if (arginfo[i].vectype == NULL
4096 : 130 : || !constant_multiple_p (bestn->simdclone->simdlen,
4097 : 130 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4098 : 0 : return false;
4099 : : }
4100 : :
4101 : 1867 : if (bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR
4102 : 1867 : && VECTOR_BOOLEAN_TYPE_P (bestn->simdclone->args[i].vector_type))
4103 : : {
4104 : 4 : if (dump_enabled_p ())
4105 : 4 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4106 : : "vector mask arguments are not supported.\n");
4107 : 4 : return false;
4108 : : }
4109 : :
4110 : 1863 : if (bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
4111 : : {
4112 : 160 : tree clone_arg_vectype = bestn->simdclone->args[i].vector_type;
4113 : 160 : if (bestn->simdclone->mask_mode == VOIDmode)
4114 : : {
4115 : 142 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (clone_arg_vectype),
4116 : 284 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4117 : : {
4118 : : /* FORNOW we only have partial support for vector-type masks
4119 : : that can't hold all of simdlen. */
4120 : 20 : if (dump_enabled_p ())
4121 : 20 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4122 : : vect_location,
4123 : : "in-branch vector clones are not yet"
4124 : : " supported for mismatched vector sizes.\n");
4125 : 20 : return false;
4126 : : }
4127 : 122 : if (!expand_vec_cond_expr_p (clone_arg_vectype,
4128 : 122 : arginfo[i].vectype))
4129 : : {
4130 : 6 : if (dump_enabled_p ())
4131 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4132 : : vect_location,
4133 : : "cannot compute mask argument for"
4134 : : " in-branch vector clones.\n");
4135 : 6 : return false;
4136 : : }
4137 : : }
4138 : 18 : else if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4139 : : {
4140 : 18 : if (!SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype))
4141 : 36 : || maybe_ne (exact_div (bestn->simdclone->simdlen,
4142 : : num_mask_args),
4143 : 24 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4144 : : {
4145 : : /* FORNOW we only have partial support for integer-type masks
4146 : : that represent the same number of lanes as the
4147 : : vectorized mask inputs. */
4148 : 12 : if (dump_enabled_p ())
4149 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4150 : : vect_location,
4151 : : "in-branch vector clones are not yet "
4152 : : "supported for mismatched vector sizes.\n");
4153 : 12 : return false;
4154 : : }
4155 : : }
4156 : : else
4157 : : {
4158 : 0 : if (dump_enabled_p ())
4159 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
4160 : : vect_location,
4161 : : "in-branch vector clones not supported"
4162 : : " on this target.\n");
4163 : 0 : return false;
4164 : : }
4165 : : }
4166 : : }
4167 : :
4168 : 783 : fndecl = bestn->decl;
4169 : 783 : nunits = bestn->simdclone->simdlen;
4170 : 783 : ncopies = vector_unroll_factor (vf * group_size, nunits);
4171 : :
4172 : : /* If the function isn't const, only allow it in simd loops where user
4173 : : has asserted that at least nunits consecutive iterations can be
4174 : : performed using SIMD instructions. */
4175 : 781 : if ((loop == NULL || maybe_lt ((unsigned) loop->safelen, nunits))
4176 : 929 : && gimple_vuse (stmt))
4177 : : return false;
4178 : :
4179 : : /* Sanity check: make sure that at least one copy of the vectorized stmt
4180 : : needs to be generated. */
4181 : 783 : gcc_assert (ncopies >= 1);
4182 : :
4183 : 783 : if (cost_vec) /* transformation not required. */
4184 : : {
4185 : 1449 : for (unsigned i = 0; i < nargs; ++i)
4186 : 1010 : if (!vect_maybe_update_slp_op_vectype (slp_op[i], arginfo[i].vectype))
4187 : : {
4188 : 0 : if (dump_enabled_p ())
4189 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4190 : : "incompatible vector types for invariants\n");
4191 : 0 : return false;
4192 : : }
4193 : : /* When the original call is pure or const but the SIMD ABI dictates
4194 : : an aggregate return we will have to use a virtual definition and
4195 : : in a loop eventually even need to add a virtual PHI. That's
4196 : : not straight-forward so allow to fix this up via renaming. */
4197 : 439 : if (gimple_call_lhs (stmt)
4198 : 433 : && !gimple_vdef (stmt)
4199 : 778 : && TREE_CODE (TREE_TYPE (TREE_TYPE (bestn->decl))) == ARRAY_TYPE)
4200 : 27 : vinfo->any_known_not_updated_vssa = true;
4201 : : /* ??? For SLP code-gen we end up inserting after the last
4202 : : vector argument def rather than at the original call position
4203 : : so automagic virtual operand updating doesn't work. */
4204 : 878 : if (gimple_vuse (stmt))
4205 : 137 : vinfo->any_known_not_updated_vssa = true;
4206 : 439 : simd_clone_info.safe_push (bestn->decl);
4207 : 1460 : for (i = 0; i < bestn->simdclone->nargs; i++)
4208 : : {
4209 : 1021 : switch (bestn->simdclone->args[i].arg_type)
4210 : : {
4211 : 831 : default:
4212 : 831 : continue;
4213 : 118 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4214 : 118 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4215 : 118 : {
4216 : 118 : simd_clone_info.safe_grow_cleared (i * 3 + 1, true);
4217 : 118 : simd_clone_info.safe_push (arginfo[i].op);
4218 : 202 : tree lst = POINTER_TYPE_P (TREE_TYPE (arginfo[i].op))
4219 : 202 : ? size_type_node : TREE_TYPE (arginfo[i].op);
4220 : 118 : tree ls = build_int_cst (lst, arginfo[i].linear_step);
4221 : 118 : simd_clone_info.safe_push (ls);
4222 : 118 : tree sll = arginfo[i].simd_lane_linear
4223 : 118 : ? boolean_true_node : boolean_false_node;
4224 : 118 : simd_clone_info.safe_push (sll);
4225 : : }
4226 : 118 : break;
4227 : 72 : case SIMD_CLONE_ARG_TYPE_MASK:
4228 : 72 : if (loop_vinfo
4229 : 72 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
4230 : 0 : vect_record_loop_mask (loop_vinfo,
4231 : : &LOOP_VINFO_MASKS (loop_vinfo),
4232 : : ncopies, vectype, op);
4233 : :
4234 : : break;
4235 : 831 : }
4236 : : }
4237 : :
4238 : 439 : if (!bestn->simdclone->inbranch && loop_vinfo)
4239 : : {
4240 : 366 : if (dump_enabled_p ()
4241 : 366 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
4242 : 3 : dump_printf_loc (MSG_NOTE, vect_location,
4243 : : "can't use a fully-masked loop because a"
4244 : : " non-masked simd clone was selected.\n");
4245 : 366 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
4246 : : }
4247 : :
4248 : 439 : SLP_TREE_TYPE (slp_node) = call_simd_clone_vec_info_type;
4249 : 439 : slp_node->data = new vect_simd_clone_data (std::move (_data));
4250 : 439 : DUMP_VECT_SCOPE ("vectorizable_simd_clone_call");
4251 : : /* vect_model_simple_cost (vinfo, 1, slp_node, cost_vec); */
4252 : 439 : return true;
4253 : : }
4254 : :
4255 : : /* Transform. */
4256 : :
4257 : 344 : if (dump_enabled_p ())
4258 : 240 : dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n");
4259 : :
4260 : : /* Handle def. */
4261 : 344 : scalar_dest = gimple_call_lhs (stmt);
4262 : 344 : vec_dest = NULL_TREE;
4263 : 344 : rtype = NULL_TREE;
4264 : 344 : ratype = NULL_TREE;
4265 : 344 : if (scalar_dest)
4266 : : {
4267 : 338 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
4268 : 338 : rtype = TREE_TYPE (TREE_TYPE (fndecl));
4269 : 338 : if (TREE_CODE (rtype) == ARRAY_TYPE)
4270 : : {
4271 : 9 : ratype = rtype;
4272 : 9 : rtype = TREE_TYPE (ratype);
4273 : : }
4274 : : }
4275 : :
4276 : 688 : auto_vec<vec<tree> > vec_oprnds;
4277 : 344 : auto_vec<unsigned> vec_oprnds_i;
4278 : 344 : vec_oprnds_i.safe_grow_cleared (nargs, true);
4279 : 344 : vec_oprnds.reserve_exact (nargs);
4280 : 344 : vect_get_slp_defs (vinfo, slp_node, &vec_oprnds);
4281 : 798 : for (j = 0; j < ncopies; ++j)
4282 : : {
4283 : 454 : poly_uint64 callee_nelements;
4284 : 454 : poly_uint64 caller_nelements;
4285 : : /* Build argument list for the vectorized call. */
4286 : 454 : if (j == 0)
4287 : 344 : vargs.create (nargs);
4288 : : else
4289 : 110 : vargs.truncate (0);
4290 : :
4291 : 1540 : for (i = 0; i < nargs; i++)
4292 : : {
4293 : 1086 : unsigned int k, l, m, o;
4294 : 1086 : tree atype;
4295 : 1086 : op = gimple_call_arg (stmt, i + masked_call_offset);
4296 : 1086 : switch (bestn->simdclone->args[i].arg_type)
4297 : : {
4298 : 802 : case SIMD_CLONE_ARG_TYPE_VECTOR:
4299 : 802 : atype = bestn->simdclone->args[i].vector_type;
4300 : 802 : caller_nelements = TYPE_VECTOR_SUBPARTS (arginfo[i].vectype);
4301 : 802 : callee_nelements = TYPE_VECTOR_SUBPARTS (atype);
4302 : 802 : o = vector_unroll_factor (nunits, callee_nelements);
4303 : 1834 : for (m = j * o; m < (j + 1) * o; m++)
4304 : : {
4305 : 1032 : if (known_lt (callee_nelements, caller_nelements))
4306 : : {
4307 : 516 : poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (atype));
4308 : 258 : if (!constant_multiple_p (caller_nelements,
4309 : : callee_nelements, &k))
4310 : 0 : gcc_unreachable ();
4311 : :
4312 : 258 : gcc_assert ((k & (k - 1)) == 0);
4313 : 258 : if (m == 0)
4314 : : {
4315 : 57 : vec_oprnds_i[i] = 0;
4316 : 57 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4317 : : }
4318 : : else
4319 : : {
4320 : 201 : vec_oprnd0 = arginfo[i].op;
4321 : 201 : if ((m & (k - 1)) == 0)
4322 : 72 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4323 : : }
4324 : 258 : arginfo[i].op = vec_oprnd0;
4325 : 258 : vec_oprnd0
4326 : 258 : = build3 (BIT_FIELD_REF, atype, vec_oprnd0,
4327 : 258 : bitsize_int (prec),
4328 : 258 : bitsize_int ((m & (k - 1)) * prec));
4329 : 258 : gassign *new_stmt
4330 : 258 : = gimple_build_assign (make_ssa_name (atype),
4331 : : vec_oprnd0);
4332 : 258 : vect_finish_stmt_generation (vinfo, stmt_info,
4333 : : new_stmt, gsi);
4334 : 258 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4335 : : }
4336 : : else
4337 : : {
4338 : 774 : if (!constant_multiple_p (callee_nelements,
4339 : : caller_nelements, &k))
4340 : 0 : gcc_unreachable ();
4341 : 774 : gcc_assert ((k & (k - 1)) == 0);
4342 : 774 : vec<constructor_elt, va_gc> *ctor_elts;
4343 : 774 : if (k != 1)
4344 : 14 : vec_alloc (ctor_elts, k);
4345 : : else
4346 : 760 : ctor_elts = NULL;
4347 : 802 : for (l = 0; l < k; l++)
4348 : : {
4349 : 788 : if (m == 0 && l == 0)
4350 : : {
4351 : 435 : vec_oprnds_i[i] = 0;
4352 : 435 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4353 : : }
4354 : : else
4355 : 353 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4356 : 788 : arginfo[i].op = vec_oprnd0;
4357 : 788 : if (k == 1)
4358 : : break;
4359 : 28 : CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE,
4360 : : vec_oprnd0);
4361 : : }
4362 : 774 : if (k == 1)
4363 : 760 : if (!useless_type_conversion_p (TREE_TYPE (vec_oprnd0),
4364 : : atype))
4365 : : {
4366 : 0 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, atype,
4367 : : vec_oprnd0);
4368 : 0 : gassign *new_stmt
4369 : 0 : = gimple_build_assign (make_ssa_name (atype),
4370 : : vec_oprnd0);
4371 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
4372 : : new_stmt, gsi);
4373 : 0 : vargs.safe_push (gimple_get_lhs (new_stmt));
4374 : : }
4375 : : else
4376 : 760 : vargs.safe_push (vec_oprnd0);
4377 : : else
4378 : : {
4379 : 14 : vec_oprnd0 = build_constructor (atype, ctor_elts);
4380 : 14 : gassign *new_stmt
4381 : 14 : = gimple_build_assign (make_ssa_name (atype),
4382 : : vec_oprnd0);
4383 : 14 : vect_finish_stmt_generation (vinfo, stmt_info,
4384 : : new_stmt, gsi);
4385 : 14 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4386 : : }
4387 : : }
4388 : : }
4389 : : break;
4390 : 61 : case SIMD_CLONE_ARG_TYPE_MASK:
4391 : 61 : if (bestn->simdclone->mask_mode == VOIDmode)
4392 : : {
4393 : 58 : atype = bestn->simdclone->args[i].vector_type;
4394 : 58 : tree elt_type = TREE_TYPE (atype);
4395 : 58 : tree one = fold_convert (elt_type, integer_one_node);
4396 : 58 : tree zero = fold_convert (elt_type, integer_zero_node);
4397 : 58 : callee_nelements = TYPE_VECTOR_SUBPARTS (atype);
4398 : 58 : caller_nelements = TYPE_VECTOR_SUBPARTS (arginfo[i].vectype);
4399 : 58 : o = vector_unroll_factor (nunits, callee_nelements);
4400 : 116 : for (m = j * o; m < (j + 1) * o; m++)
4401 : : {
4402 : 58 : if (maybe_lt (callee_nelements, caller_nelements))
4403 : : {
4404 : : /* The mask type has fewer elements than simdlen. */
4405 : :
4406 : : /* FORNOW */
4407 : 0 : gcc_unreachable ();
4408 : : }
4409 : 58 : else if (known_eq (callee_nelements, caller_nelements))
4410 : : {
4411 : : /* The SIMD clone function has the same number of
4412 : : elements as the current function. */
4413 : 58 : if (m == 0)
4414 : 58 : vec_oprnds_i[i] = 0;
4415 : 58 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4416 : 58 : if (loop_vinfo
4417 : 58 : && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4418 : : {
4419 : 0 : vec_loop_masks *loop_masks
4420 : : = &LOOP_VINFO_MASKS (loop_vinfo);
4421 : 0 : tree loop_mask
4422 : 0 : = vect_get_loop_mask (loop_vinfo, gsi,
4423 : : loop_masks, ncopies,
4424 : 0 : vectype, j);
4425 : 0 : vec_oprnd0
4426 : 0 : = prepare_vec_mask (loop_vinfo,
4427 : 0 : TREE_TYPE (loop_mask),
4428 : : loop_mask, vec_oprnd0,
4429 : : gsi);
4430 : 0 : loop_vinfo->vec_cond_masked_set.add ({ vec_oprnd0,
4431 : : loop_mask });
4432 : :
4433 : : }
4434 : 58 : vec_oprnd0
4435 : 58 : = build3 (VEC_COND_EXPR, atype, vec_oprnd0,
4436 : : build_vector_from_val (atype, one),
4437 : : build_vector_from_val (atype, zero));
4438 : 58 : gassign *new_stmt
4439 : 58 : = gimple_build_assign (make_ssa_name (atype),
4440 : : vec_oprnd0);
4441 : 58 : vect_finish_stmt_generation (vinfo, stmt_info,
4442 : : new_stmt, gsi);
4443 : 58 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4444 : : }
4445 : : else
4446 : : {
4447 : : /* The mask type has more elements than simdlen. */
4448 : :
4449 : : /* FORNOW */
4450 : 0 : gcc_unreachable ();
4451 : : }
4452 : : }
4453 : : }
4454 : 3 : else if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4455 : : {
4456 : 3 : atype = bestn->simdclone->args[i].vector_type;
4457 : : /* Guess the number of lanes represented by atype. */
4458 : 3 : poly_uint64 atype_subparts
4459 : 3 : = exact_div (bestn->simdclone->simdlen,
4460 : : num_mask_args);
4461 : 3 : o = vector_unroll_factor (nunits, atype_subparts);
4462 : 6 : for (m = j * o; m < (j + 1) * o; m++)
4463 : : {
4464 : 3 : if (m == 0)
4465 : 3 : vec_oprnds_i[i] = 0;
4466 : 3 : if (maybe_lt (atype_subparts,
4467 : 3 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4468 : : {
4469 : : /* The mask argument has fewer elements than the
4470 : : input vector. */
4471 : : /* FORNOW */
4472 : 0 : gcc_unreachable ();
4473 : : }
4474 : 3 : else if (known_eq (atype_subparts,
4475 : : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4476 : : {
4477 : : /* The vector mask argument matches the input
4478 : : in the number of lanes, but not necessarily
4479 : : in the mode. */
4480 : 3 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4481 : 3 : tree st = lang_hooks.types.type_for_mode
4482 : 3 : (TYPE_MODE (TREE_TYPE (vec_oprnd0)), 1);
4483 : 3 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, st,
4484 : : vec_oprnd0);
4485 : 3 : gassign *new_stmt
4486 : 3 : = gimple_build_assign (make_ssa_name (st),
4487 : : vec_oprnd0);
4488 : 3 : vect_finish_stmt_generation (vinfo, stmt_info,
4489 : : new_stmt, gsi);
4490 : 3 : if (!types_compatible_p (atype, st))
4491 : : {
4492 : 3 : new_stmt
4493 : 3 : = gimple_build_assign (make_ssa_name (atype),
4494 : : NOP_EXPR,
4495 : : gimple_assign_lhs
4496 : : (new_stmt));
4497 : 3 : vect_finish_stmt_generation (vinfo, stmt_info,
4498 : : new_stmt, gsi);
4499 : : }
4500 : 3 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4501 : : }
4502 : : else
4503 : : {
4504 : : /* The mask argument has more elements than the
4505 : : input vector. */
4506 : : /* FORNOW */
4507 : 0 : gcc_unreachable ();
4508 : : }
4509 : : }
4510 : : }
4511 : : else
4512 : 0 : gcc_unreachable ();
4513 : : break;
4514 : 102 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
4515 : 102 : vargs.safe_push (op);
4516 : 102 : break;
4517 : 121 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4518 : 121 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4519 : 121 : if (j == 0)
4520 : : {
4521 : 118 : gimple_seq stmts;
4522 : 118 : arginfo[i].op
4523 : 118 : = force_gimple_operand (unshare_expr (arginfo[i].op),
4524 : : &stmts, true, NULL_TREE);
4525 : 118 : if (stmts != NULL)
4526 : : {
4527 : 0 : basic_block new_bb;
4528 : 0 : edge pe = loop_preheader_edge (loop);
4529 : 0 : new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
4530 : 0 : gcc_assert (!new_bb);
4531 : : }
4532 : 118 : if (arginfo[i].simd_lane_linear)
4533 : : {
4534 : 6 : vargs.safe_push (arginfo[i].op);
4535 : 6 : break;
4536 : : }
4537 : 112 : tree phi_res = copy_ssa_name (op);
4538 : 112 : gphi *new_phi = create_phi_node (phi_res, loop->header);
4539 : 112 : add_phi_arg (new_phi, arginfo[i].op,
4540 : : loop_preheader_edge (loop), UNKNOWN_LOCATION);
4541 : 112 : enum tree_code code
4542 : 196 : = POINTER_TYPE_P (TREE_TYPE (op))
4543 : 112 : ? POINTER_PLUS_EXPR : PLUS_EXPR;
4544 : 196 : tree type = POINTER_TYPE_P (TREE_TYPE (op))
4545 : 196 : ? sizetype : TREE_TYPE (op);
4546 : 112 : poly_widest_int cst
4547 : 112 : = wi::mul (bestn->simdclone->args[i].linear_step,
4548 : 112 : ncopies * nunits);
4549 : 112 : tree tcst = wide_int_to_tree (type, cst);
4550 : 112 : tree phi_arg = copy_ssa_name (op);
4551 : 112 : gassign *new_stmt
4552 : 112 : = gimple_build_assign (phi_arg, code, phi_res, tcst);
4553 : 112 : gimple_stmt_iterator si = gsi_after_labels (loop->header);
4554 : 112 : gsi_insert_after (&si, new_stmt, GSI_NEW_STMT);
4555 : 112 : add_phi_arg (new_phi, phi_arg, loop_latch_edge (loop),
4556 : : UNKNOWN_LOCATION);
4557 : 112 : arginfo[i].op = phi_res;
4558 : 112 : vargs.safe_push (phi_res);
4559 : 112 : }
4560 : : else
4561 : : {
4562 : 3 : enum tree_code code
4563 : 6 : = POINTER_TYPE_P (TREE_TYPE (op))
4564 : 3 : ? POINTER_PLUS_EXPR : PLUS_EXPR;
4565 : 6 : tree type = POINTER_TYPE_P (TREE_TYPE (op))
4566 : 6 : ? sizetype : TREE_TYPE (op);
4567 : 3 : poly_widest_int cst
4568 : 3 : = wi::mul (bestn->simdclone->args[i].linear_step,
4569 : 3 : j * nunits);
4570 : 3 : tree tcst = wide_int_to_tree (type, cst);
4571 : 3 : new_temp = make_ssa_name (TREE_TYPE (op));
4572 : 3 : gassign *new_stmt
4573 : 6 : = gimple_build_assign (new_temp, code,
4574 : 3 : arginfo[i].op, tcst);
4575 : 3 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4576 : 3 : vargs.safe_push (new_temp);
4577 : 3 : }
4578 : : break;
4579 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
4580 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
4581 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
4582 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
4583 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
4584 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
4585 : 0 : default:
4586 : 0 : gcc_unreachable ();
4587 : : }
4588 : : }
4589 : :
4590 : 454 : if (masked_call_offset == 0
4591 : 393 : && bestn->simdclone->inbranch
4592 : 7 : && bestn->simdclone->nargs > nargs)
4593 : : {
4594 : 7 : unsigned long m, o;
4595 : 7 : size_t mask_i = bestn->simdclone->nargs - 1;
4596 : 7 : tree mask;
4597 : 7 : gcc_assert (bestn->simdclone->args[mask_i].arg_type ==
4598 : : SIMD_CLONE_ARG_TYPE_MASK);
4599 : :
4600 : 7 : tree masktype = bestn->simdclone->args[mask_i].vector_type;
4601 : 7 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4602 : : /* Guess the number of lanes represented by masktype. */
4603 : 1 : callee_nelements = exact_div (bestn->simdclone->simdlen,
4604 : 1 : bestn->simdclone->nargs - nargs);
4605 : : else
4606 : 6 : callee_nelements = TYPE_VECTOR_SUBPARTS (masktype);
4607 : 7 : o = vector_unroll_factor (nunits, callee_nelements);
4608 : 14 : for (m = j * o; m < (j + 1) * o; m++)
4609 : : {
4610 : 7 : if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4611 : : {
4612 : 0 : vec_loop_masks *loop_masks = &LOOP_VINFO_MASKS (loop_vinfo);
4613 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
4614 : : ncopies, masktype, j);
4615 : : }
4616 : : else
4617 : 7 : mask = vect_build_all_ones_mask (vinfo, stmt_info, masktype);
4618 : :
4619 : 7 : gassign *new_stmt;
4620 : 7 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4621 : : {
4622 : : /* This means we are dealing with integer mask modes.
4623 : : First convert to an integer type with the same size as
4624 : : the current vector type. */
4625 : 1 : unsigned HOST_WIDE_INT intermediate_size
4626 : 1 : = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (mask)));
4627 : 1 : tree mid_int_type =
4628 : 1 : build_nonstandard_integer_type (intermediate_size, 1);
4629 : 1 : mask = build1 (VIEW_CONVERT_EXPR, mid_int_type, mask);
4630 : 1 : new_stmt
4631 : 1 : = gimple_build_assign (make_ssa_name (mid_int_type),
4632 : : mask);
4633 : 1 : gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
4634 : : /* Then zero-extend to the mask mode. */
4635 : 1 : mask = fold_build1 (NOP_EXPR, masktype,
4636 : : gimple_get_lhs (new_stmt));
4637 : : }
4638 : 6 : else if (bestn->simdclone->mask_mode == VOIDmode)
4639 : : {
4640 : 6 : tree one = fold_convert (TREE_TYPE (masktype),
4641 : : integer_one_node);
4642 : 6 : tree zero = fold_convert (TREE_TYPE (masktype),
4643 : : integer_zero_node);
4644 : 6 : mask = build3 (VEC_COND_EXPR, masktype, mask,
4645 : : build_vector_from_val (masktype, one),
4646 : : build_vector_from_val (masktype, zero));
4647 : : }
4648 : : else
4649 : 0 : gcc_unreachable ();
4650 : :
4651 : 7 : new_stmt = gimple_build_assign (make_ssa_name (masktype), mask);
4652 : 7 : vect_finish_stmt_generation (vinfo, stmt_info,
4653 : : new_stmt, gsi);
4654 : 7 : mask = gimple_assign_lhs (new_stmt);
4655 : 7 : vargs.safe_push (mask);
4656 : : }
4657 : : }
4658 : :
4659 : 454 : gcall *new_call = gimple_build_call_vec (fndecl, vargs);
4660 : 454 : if (vec_dest)
4661 : : {
4662 : 448 : gcc_assert (ratype
4663 : : || known_eq (TYPE_VECTOR_SUBPARTS (rtype), nunits));
4664 : 448 : if (ratype)
4665 : 15 : new_temp = create_tmp_var (ratype);
4666 : 433 : else if (useless_type_conversion_p (vectype, rtype))
4667 : 411 : new_temp = make_ssa_name (vec_dest, new_call);
4668 : : else
4669 : 22 : new_temp = make_ssa_name (rtype, new_call);
4670 : 448 : gimple_call_set_lhs (new_call, new_temp);
4671 : : }
4672 : 454 : vect_finish_stmt_generation (vinfo, stmt_info, new_call, gsi);
4673 : 454 : gimple *new_stmt = new_call;
4674 : :
4675 : 454 : if (vec_dest)
4676 : : {
4677 : 448 : if (!multiple_p (TYPE_VECTOR_SUBPARTS (vectype), nunits))
4678 : : {
4679 : 21 : unsigned int k, l;
4680 : 42 : poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (vectype));
4681 : 42 : poly_uint64 bytes = GET_MODE_SIZE (TYPE_MODE (vectype));
4682 : 21 : k = vector_unroll_factor (nunits,
4683 : : TYPE_VECTOR_SUBPARTS (vectype));
4684 : 21 : gcc_assert ((k & (k - 1)) == 0);
4685 : 75 : for (l = 0; l < k; l++)
4686 : : {
4687 : 54 : tree t;
4688 : 54 : if (ratype)
4689 : : {
4690 : 42 : t = build_fold_addr_expr (new_temp);
4691 : 42 : t = build2 (MEM_REF, vectype, t,
4692 : 42 : build_int_cst (TREE_TYPE (t), l * bytes));
4693 : : }
4694 : : else
4695 : 12 : t = build3 (BIT_FIELD_REF, vectype, new_temp,
4696 : 12 : bitsize_int (prec), bitsize_int (l * prec));
4697 : 54 : new_stmt = gimple_build_assign (make_ssa_name (vectype), t);
4698 : 54 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4699 : :
4700 : 54 : SLP_TREE_VEC_DEFS (slp_node)
4701 : 54 : .quick_push (gimple_assign_lhs (new_stmt));
4702 : : }
4703 : :
4704 : 21 : if (ratype)
4705 : 15 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
4706 : 21 : continue;
4707 : 21 : }
4708 : 427 : else if (!multiple_p (nunits, TYPE_VECTOR_SUBPARTS (vectype)))
4709 : : {
4710 : 16 : unsigned int k;
4711 : 16 : if (!constant_multiple_p (TYPE_VECTOR_SUBPARTS (vectype),
4712 : 16 : TYPE_VECTOR_SUBPARTS (rtype), &k))
4713 : 0 : gcc_unreachable ();
4714 : 16 : gcc_assert ((k & (k - 1)) == 0);
4715 : 16 : if ((j & (k - 1)) == 0)
4716 : 8 : vec_alloc (ret_ctor_elts, k);
4717 : 16 : if (ratype)
4718 : : {
4719 : 0 : unsigned int m, o;
4720 : 0 : o = vector_unroll_factor (nunits,
4721 : : TYPE_VECTOR_SUBPARTS (rtype));
4722 : 0 : for (m = 0; m < o; m++)
4723 : : {
4724 : 0 : tree tem = build4 (ARRAY_REF, rtype, new_temp,
4725 : 0 : size_int (m), NULL_TREE, NULL_TREE);
4726 : 0 : new_stmt = gimple_build_assign (make_ssa_name (rtype),
4727 : : tem);
4728 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
4729 : : new_stmt, gsi);
4730 : 0 : CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE,
4731 : : gimple_assign_lhs (new_stmt));
4732 : : }
4733 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
4734 : : }
4735 : : else
4736 : 16 : CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE, new_temp);
4737 : 16 : if ((j & (k - 1)) != k - 1)
4738 : 8 : continue;
4739 : 8 : vec_oprnd0 = build_constructor (vectype, ret_ctor_elts);
4740 : 8 : new_stmt
4741 : 8 : = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0);
4742 : 8 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4743 : :
4744 : 8 : SLP_TREE_VEC_DEFS (slp_node)
4745 : 8 : .quick_push (gimple_assign_lhs (new_stmt));
4746 : 8 : continue;
4747 : 8 : }
4748 : 411 : else if (ratype)
4749 : : {
4750 : 0 : tree t = build_fold_addr_expr (new_temp);
4751 : 0 : t = build2 (MEM_REF, vectype, t,
4752 : 0 : build_int_cst (TREE_TYPE (t), 0));
4753 : 0 : new_stmt = gimple_build_assign (make_ssa_name (vec_dest), t);
4754 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4755 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
4756 : : }
4757 : 411 : else if (!useless_type_conversion_p (vectype, rtype))
4758 : : {
4759 : 0 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, vectype, new_temp);
4760 : 0 : new_stmt
4761 : 0 : = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0);
4762 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4763 : : }
4764 : : }
4765 : :
4766 : 417 : if (gimple_get_lhs (new_stmt))
4767 : 411 : SLP_TREE_VEC_DEFS (slp_node).quick_push (gimple_get_lhs (new_stmt));
4768 : : }
4769 : :
4770 : 1117 : for (i = 0; i < nargs; ++i)
4771 : : {
4772 : 773 : vec<tree> oprndsi = vec_oprnds[i];
4773 : 773 : oprndsi.release ();
4774 : : }
4775 : 344 : vargs.release ();
4776 : :
4777 : : /* Mark the clone as no longer being a candidate for GC. */
4778 : 344 : bestn->gc_candidate = false;
4779 : :
4780 : 344 : return true;
4781 : 1340 : }
4782 : :
4783 : :
4784 : : /* Function vect_gen_widened_results_half
4785 : :
4786 : : Create a vector stmt whose code, type, number of arguments, and result
4787 : : variable are CODE, OP_TYPE, and VEC_DEST, and its arguments are
4788 : : VEC_OPRND0 and VEC_OPRND1. The new vector stmt is to be inserted at GSI.
4789 : : In the case that CODE is a CALL_EXPR, this means that a call to DECL
4790 : : needs to be created (DECL is a function-decl of a target-builtin).
4791 : : STMT_INFO is the original scalar stmt that we are vectorizing. */
4792 : :
4793 : : static gimple *
4794 : 23330 : vect_gen_widened_results_half (vec_info *vinfo, code_helper ch,
4795 : : tree vec_oprnd0, tree vec_oprnd1, int op_type,
4796 : : tree vec_dest, gimple_stmt_iterator *gsi,
4797 : : stmt_vec_info stmt_info)
4798 : : {
4799 : 23330 : gimple *new_stmt;
4800 : 23330 : tree new_temp;
4801 : :
4802 : : /* Generate half of the widened result: */
4803 : 23330 : if (op_type != binary_op)
4804 : 22278 : vec_oprnd1 = NULL;
4805 : 23330 : new_stmt = vect_gimple_build (vec_dest, ch, vec_oprnd0, vec_oprnd1);
4806 : 23330 : new_temp = make_ssa_name (vec_dest, new_stmt);
4807 : 23330 : gimple_set_lhs (new_stmt, new_temp);
4808 : 23330 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4809 : :
4810 : 23330 : return new_stmt;
4811 : : }
4812 : :
4813 : :
4814 : : /* Create vectorized demotion statements for vector operands from VEC_OPRNDS.
4815 : : For multi-step conversions store the resulting vectors and call the function
4816 : : recursively. When NARROW_SRC_P is true, there's still a conversion after
4817 : : narrowing, don't store the vectors in the SLP_NODE or in vector info of
4818 : : the scalar statement(or in STMT_VINFO_RELATED_STMT chain). */
4819 : :
4820 : : static void
4821 : 9729 : vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
4822 : : int multi_step_cvt,
4823 : : stmt_vec_info stmt_info,
4824 : : vec<tree> &vec_dsts,
4825 : : gimple_stmt_iterator *gsi,
4826 : : slp_tree slp_node, code_helper code,
4827 : : bool narrow_src_p)
4828 : : {
4829 : 9729 : unsigned int i;
4830 : 9729 : tree vop0, vop1, new_tmp, vec_dest;
4831 : :
4832 : 9729 : vec_dest = vec_dsts.pop ();
4833 : :
4834 : 22452 : for (i = 0; i < vec_oprnds->length (); i += 2)
4835 : : {
4836 : : /* Create demotion operation. */
4837 : 12723 : vop0 = (*vec_oprnds)[i];
4838 : 12723 : vop1 = (*vec_oprnds)[i + 1];
4839 : 12723 : gimple *new_stmt = vect_gimple_build (vec_dest, code, vop0, vop1);
4840 : 12723 : new_tmp = make_ssa_name (vec_dest, new_stmt);
4841 : 12723 : gimple_set_lhs (new_stmt, new_tmp);
4842 : 12723 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4843 : 12723 : if (multi_step_cvt || narrow_src_p)
4844 : : /* Store the resulting vector for next recursive call,
4845 : : or return the resulting vector_tmp for NARROW FLOAT_EXPR. */
4846 : 4557 : (*vec_oprnds)[i/2] = new_tmp;
4847 : : else
4848 : : {
4849 : : /* This is the last step of the conversion sequence. Store the
4850 : : vectors in SLP_NODE. */
4851 : 8166 : slp_node->push_vec_def (new_stmt);
4852 : : }
4853 : : }
4854 : :
4855 : : /* For multi-step demotion operations we first generate demotion operations
4856 : : from the source type to the intermediate types, and then combine the
4857 : : results (stored in VEC_OPRNDS) in demotion operation to the destination
4858 : : type. */
4859 : 9729 : if (multi_step_cvt)
4860 : : {
4861 : : /* At each level of recursion we have half of the operands we had at the
4862 : : previous level. */
4863 : 2111 : vec_oprnds->truncate ((i+1)/2);
4864 : 2111 : vect_create_vectorized_demotion_stmts (vinfo, vec_oprnds,
4865 : : multi_step_cvt - 1,
4866 : : stmt_info, vec_dsts, gsi,
4867 : 2111 : slp_node, VEC_PACK_TRUNC_EXPR,
4868 : : narrow_src_p);
4869 : : }
4870 : :
4871 : 9729 : vec_dsts.quick_push (vec_dest);
4872 : 9729 : }
4873 : :
4874 : :
4875 : : /* Create vectorized promotion statements for vector operands from VEC_OPRNDS0
4876 : : and VEC_OPRNDS1, for a binary operation associated with scalar statement
4877 : : STMT_INFO. For multi-step conversions store the resulting vectors and
4878 : : call the function recursively. */
4879 : :
4880 : : static void
4881 : 9035 : vect_create_vectorized_promotion_stmts (vec_info *vinfo,
4882 : : vec<tree> *vec_oprnds0,
4883 : : vec<tree> *vec_oprnds1,
4884 : : stmt_vec_info stmt_info, tree vec_dest,
4885 : : gimple_stmt_iterator *gsi,
4886 : : code_helper ch1,
4887 : : code_helper ch2, int op_type)
4888 : : {
4889 : 9035 : int i;
4890 : 9035 : tree vop0, vop1, new_tmp1, new_tmp2;
4891 : 9035 : gimple *new_stmt1, *new_stmt2;
4892 : 9035 : vec<tree> vec_tmp = vNULL;
4893 : :
4894 : 9035 : vec_tmp.create (vec_oprnds0->length () * 2);
4895 : 29735 : FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0)
4896 : : {
4897 : 11665 : if (op_type == binary_op)
4898 : 526 : vop1 = (*vec_oprnds1)[i];
4899 : : else
4900 : : vop1 = NULL_TREE;
4901 : :
4902 : : /* Generate the two halves of promotion operation. */
4903 : 11665 : new_stmt1 = vect_gen_widened_results_half (vinfo, ch1, vop0, vop1,
4904 : : op_type, vec_dest, gsi,
4905 : : stmt_info);
4906 : 11665 : new_stmt2 = vect_gen_widened_results_half (vinfo, ch2, vop0, vop1,
4907 : : op_type, vec_dest, gsi,
4908 : : stmt_info);
4909 : 11665 : if (is_gimple_call (new_stmt1))
4910 : : {
4911 : 0 : new_tmp1 = gimple_call_lhs (new_stmt1);
4912 : 0 : new_tmp2 = gimple_call_lhs (new_stmt2);
4913 : : }
4914 : : else
4915 : : {
4916 : 11665 : new_tmp1 = gimple_assign_lhs (new_stmt1);
4917 : 11665 : new_tmp2 = gimple_assign_lhs (new_stmt2);
4918 : : }
4919 : :
4920 : : /* Store the results for the next step. */
4921 : 11665 : vec_tmp.quick_push (new_tmp1);
4922 : 11665 : vec_tmp.quick_push (new_tmp2);
4923 : : }
4924 : :
4925 : 9035 : vec_oprnds0->release ();
4926 : 9035 : *vec_oprnds0 = vec_tmp;
4927 : 9035 : }
4928 : :
4929 : : /* Create vectorized promotion stmts for widening stmts using only half the
4930 : : potential vector size for input. */
4931 : : static void
4932 : 14 : vect_create_half_widening_stmts (vec_info *vinfo,
4933 : : vec<tree> *vec_oprnds0,
4934 : : vec<tree> *vec_oprnds1,
4935 : : stmt_vec_info stmt_info, tree vec_dest,
4936 : : gimple_stmt_iterator *gsi,
4937 : : code_helper code1,
4938 : : int op_type)
4939 : : {
4940 : 14 : int i;
4941 : 14 : tree vop0, vop1;
4942 : 14 : gimple *new_stmt1;
4943 : 14 : gimple *new_stmt2;
4944 : 14 : gimple *new_stmt3;
4945 : 14 : vec<tree> vec_tmp = vNULL;
4946 : :
4947 : 14 : vec_tmp.create (vec_oprnds0->length ());
4948 : 28 : FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0)
4949 : : {
4950 : 14 : tree new_tmp1, new_tmp2, new_tmp3, out_type;
4951 : :
4952 : 14 : gcc_assert (op_type == binary_op);
4953 : 14 : vop1 = (*vec_oprnds1)[i];
4954 : :
4955 : : /* Widen the first vector input. */
4956 : 14 : out_type = TREE_TYPE (vec_dest);
4957 : 14 : new_tmp1 = make_ssa_name (out_type);
4958 : 14 : new_stmt1 = gimple_build_assign (new_tmp1, NOP_EXPR, vop0);
4959 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt1, gsi);
4960 : 14 : if (VECTOR_TYPE_P (TREE_TYPE (vop1)))
4961 : : {
4962 : : /* Widen the second vector input. */
4963 : 14 : new_tmp2 = make_ssa_name (out_type);
4964 : 14 : new_stmt2 = gimple_build_assign (new_tmp2, NOP_EXPR, vop1);
4965 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt2, gsi);
4966 : : /* Perform the operation. With both vector inputs widened. */
4967 : 14 : new_stmt3 = vect_gimple_build (vec_dest, code1, new_tmp1, new_tmp2);
4968 : : }
4969 : : else
4970 : : {
4971 : : /* Perform the operation. With the single vector input widened. */
4972 : 0 : new_stmt3 = vect_gimple_build (vec_dest, code1, new_tmp1, vop1);
4973 : : }
4974 : :
4975 : 14 : new_tmp3 = make_ssa_name (vec_dest, new_stmt3);
4976 : 14 : gimple_assign_set_lhs (new_stmt3, new_tmp3);
4977 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt3, gsi);
4978 : :
4979 : : /* Store the results for the next step. */
4980 : 14 : vec_tmp.quick_push (new_tmp3);
4981 : : }
4982 : :
4983 : 14 : vec_oprnds0->release ();
4984 : 14 : *vec_oprnds0 = vec_tmp;
4985 : 14 : }
4986 : :
4987 : :
4988 : : /* Check if STMT_INFO performs a conversion operation that can be vectorized.
4989 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
4990 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
4991 : : Return true if STMT_INFO is vectorizable in this way. */
4992 : :
4993 : : static bool
4994 : 2299762 : vectorizable_conversion (vec_info *vinfo,
4995 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
4996 : : slp_tree slp_node,
4997 : : stmt_vector_for_cost *cost_vec)
4998 : : {
4999 : 2299762 : tree vec_dest, cvt_op = NULL_TREE;
5000 : 2299762 : tree scalar_dest;
5001 : 2299762 : tree op0, op1 = NULL_TREE;
5002 : 2299762 : tree_code tc1;
5003 : 2299762 : code_helper code, code1, code2;
5004 : 2299762 : code_helper codecvt1 = ERROR_MARK, codecvt2 = ERROR_MARK;
5005 : 2299762 : tree new_temp;
5006 : 2299762 : enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
5007 : 2299762 : poly_uint64 nunits_in;
5008 : 2299762 : poly_uint64 nunits_out;
5009 : 2299762 : tree vectype_out, vectype_in;
5010 : 2299762 : int i;
5011 : 2299762 : tree lhs_type, rhs_type;
5012 : : /* For conversions between floating point and integer, there're 2 NARROW
5013 : : cases. NARROW_SRC is for FLOAT_EXPR, means
5014 : : integer --DEMOTION--> integer --FLOAT_EXPR--> floating point.
5015 : : This is safe when the range of the source integer can fit into the lower
5016 : : precision. NARROW_DST is for FIX_TRUNC_EXPR, means
5017 : : floating point --FIX_TRUNC_EXPR--> integer --DEMOTION--> INTEGER.
5018 : : For other conversions, when there's narrowing, NARROW_DST is used as
5019 : : default. */
5020 : 2299762 : enum { NARROW_SRC, NARROW_DST, NONE, WIDEN } modifier;
5021 : 2299762 : vec<tree> vec_oprnds0 = vNULL;
5022 : 2299762 : vec<tree> vec_oprnds1 = vNULL;
5023 : 2299762 : tree vop0;
5024 : 2299762 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
5025 : 2299762 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
5026 : 2299762 : int multi_step_cvt = 0;
5027 : 2299762 : vec<tree> interm_types = vNULL;
5028 : 2299762 : tree intermediate_type, cvt_type = NULL_TREE;
5029 : 2299762 : int op_type;
5030 : 2299762 : unsigned short fltsz;
5031 : :
5032 : : /* Is STMT a vectorizable conversion? */
5033 : :
5034 : 2299762 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
5035 : : return false;
5036 : :
5037 : 2299762 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
5038 : 180307 : && cost_vec)
5039 : : return false;
5040 : :
5041 : 2119455 : gimple* stmt = stmt_info->stmt;
5042 : 2119455 : if (!(is_gimple_assign (stmt) || is_gimple_call (stmt)))
5043 : : return false;
5044 : :
5045 : 2056097 : if (gimple_get_lhs (stmt) == NULL_TREE
5046 : 2056097 : || TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME)
5047 : 777821 : return false;
5048 : :
5049 : 1278276 : if (TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME)
5050 : : return false;
5051 : :
5052 : 1278276 : if (is_gimple_assign (stmt))
5053 : : {
5054 : 1270396 : code = gimple_assign_rhs_code (stmt);
5055 : 1270396 : op_type = TREE_CODE_LENGTH ((tree_code) code);
5056 : : }
5057 : 7880 : else if (gimple_call_internal_p (stmt))
5058 : : {
5059 : 4287 : code = gimple_call_internal_fn (stmt);
5060 : 4287 : op_type = gimple_call_num_args (stmt);
5061 : : }
5062 : : else
5063 : : return false;
5064 : :
5065 : 1274683 : bool widen_arith = (code == WIDEN_MULT_EXPR
5066 : 1272225 : || code == WIDEN_LSHIFT_EXPR
5067 : 2546908 : || widening_fn_p (code));
5068 : :
5069 : 1272225 : if (!widen_arith
5070 : 1272225 : && !CONVERT_EXPR_CODE_P (code)
5071 : : && code != FIX_TRUNC_EXPR
5072 : : && code != FLOAT_EXPR)
5073 : : return false;
5074 : :
5075 : : /* Check types of lhs and rhs. */
5076 : 143153 : scalar_dest = gimple_get_lhs (stmt);
5077 : 143153 : lhs_type = TREE_TYPE (scalar_dest);
5078 : 143153 : vectype_out = SLP_TREE_VECTYPE (slp_node);
5079 : :
5080 : : /* Check the operands of the operation. */
5081 : 143153 : slp_tree slp_op0, slp_op1 = NULL;
5082 : 143153 : if (!vect_is_simple_use (vinfo, slp_node,
5083 : : 0, &op0, &slp_op0, &dt[0], &vectype_in))
5084 : : {
5085 : 0 : if (dump_enabled_p ())
5086 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5087 : : "use not simple.\n");
5088 : 0 : return false;
5089 : : }
5090 : :
5091 : 143153 : rhs_type = TREE_TYPE (op0);
5092 : 143153 : if ((code != FIX_TRUNC_EXPR && code != FLOAT_EXPR)
5093 : 273372 : && !((INTEGRAL_TYPE_P (lhs_type)
5094 : 119014 : && INTEGRAL_TYPE_P (rhs_type))
5095 : : || (SCALAR_FLOAT_TYPE_P (lhs_type)
5096 : 6804 : && SCALAR_FLOAT_TYPE_P (rhs_type))))
5097 : : return false;
5098 : :
5099 : 138752 : if (!VECTOR_BOOLEAN_TYPE_P (vectype_out)
5100 : 267698 : && ((INTEGRAL_TYPE_P (lhs_type)
5101 : 107955 : && !type_has_mode_precision_p (lhs_type))
5102 : 128405 : || (INTEGRAL_TYPE_P (rhs_type)
5103 : 119548 : && !type_has_mode_precision_p (rhs_type))))
5104 : : {
5105 : 920 : if (dump_enabled_p ())
5106 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5107 : : "type conversion to/from bit-precision unsupported."
5108 : : "\n");
5109 : 920 : return false;
5110 : : }
5111 : :
5112 : 137832 : if (op_type == binary_op)
5113 : : {
5114 : 2458 : gcc_assert (code == WIDEN_MULT_EXPR
5115 : : || code == WIDEN_LSHIFT_EXPR
5116 : : || widening_fn_p (code));
5117 : :
5118 : 2458 : op1 = is_gimple_assign (stmt) ? gimple_assign_rhs2 (stmt) :
5119 : 0 : gimple_call_arg (stmt, 0);
5120 : 2458 : tree vectype1_in;
5121 : 2458 : if (!vect_is_simple_use (vinfo, slp_node, 1,
5122 : : &op1, &slp_op1, &dt[1], &vectype1_in))
5123 : : {
5124 : 0 : if (dump_enabled_p ())
5125 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5126 : : "use not simple.\n");
5127 : 0 : return false;
5128 : : }
5129 : : /* For WIDEN_MULT_EXPR, if OP0 is a constant, use the type of
5130 : : OP1. */
5131 : 2458 : if (!vectype_in)
5132 : 104 : vectype_in = vectype1_in;
5133 : : }
5134 : :
5135 : : /* If op0 is an external or constant def, infer the vector type
5136 : : from the scalar type. */
5137 : 137832 : if (!vectype_in)
5138 : 19324 : vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
5139 : 137832 : if (!cost_vec)
5140 : 19581 : gcc_assert (vectype_in);
5141 : 137832 : if (!vectype_in)
5142 : : {
5143 : 272 : if (dump_enabled_p ())
5144 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5145 : : "no vectype for scalar type %T\n", rhs_type);
5146 : :
5147 : 272 : return false;
5148 : : }
5149 : :
5150 : 137560 : if (VECTOR_BOOLEAN_TYPE_P (vectype_out)
5151 : 147366 : && !VECTOR_BOOLEAN_TYPE_P (vectype_in))
5152 : : {
5153 : 201 : if (dump_enabled_p ())
5154 : 30 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5155 : : "can't convert between boolean and non "
5156 : : "boolean vectors %T\n", rhs_type);
5157 : :
5158 : 201 : return false;
5159 : : }
5160 : :
5161 : 137359 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
5162 : 137359 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
5163 : 137359 : if (known_eq (nunits_out, nunits_in))
5164 : 69597 : if (widen_arith)
5165 : : modifier = WIDEN;
5166 : : else
5167 : 137359 : modifier = NONE;
5168 : 67762 : else if (multiple_p (nunits_out, nunits_in))
5169 : : modifier = NARROW_DST;
5170 : : else
5171 : : {
5172 : 35885 : gcc_checking_assert (multiple_p (nunits_in, nunits_out));
5173 : : modifier = WIDEN;
5174 : : }
5175 : :
5176 : 137359 : bool found_mode = false;
5177 : 137359 : scalar_mode lhs_mode = SCALAR_TYPE_MODE (lhs_type);
5178 : 137359 : scalar_mode rhs_mode = SCALAR_TYPE_MODE (rhs_type);
5179 : 137359 : opt_scalar_mode rhs_mode_iter;
5180 : 137359 : auto_vec<std::pair<tree, tree_code>, 2> converts;
5181 : :
5182 : : /* Supportable by target? */
5183 : 137359 : switch (modifier)
5184 : : {
5185 : 69364 : case NONE:
5186 : 69364 : if (code != FIX_TRUNC_EXPR
5187 : : && code != FLOAT_EXPR
5188 : : && !CONVERT_EXPR_CODE_P (code))
5189 : : return false;
5190 : 69364 : gcc_assert (code.is_tree_code ());
5191 : 69364 : if (supportable_indirect_convert_operation (code,
5192 : : vectype_out, vectype_in,
5193 : : converts, op0, slp_op0))
5194 : : {
5195 : 17332 : gcc_assert (converts.length () <= 2);
5196 : 17332 : if (converts.length () == 1)
5197 : 17258 : code1 = converts[0].second;
5198 : : else
5199 : : {
5200 : 74 : cvt_type = NULL_TREE;
5201 : 74 : multi_step_cvt = converts.length () - 1;
5202 : 74 : codecvt1 = converts[0].second;
5203 : 74 : code1 = converts[1].second;
5204 : 74 : interm_types.safe_push (converts[0].first);
5205 : : }
5206 : : break;
5207 : : }
5208 : :
5209 : : /* FALLTHRU */
5210 : 52032 : unsupported:
5211 : 58172 : if (dump_enabled_p ())
5212 : 5784 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5213 : : "conversion not supported by target.\n");
5214 : : return false;
5215 : :
5216 : 36118 : case WIDEN:
5217 : 36118 : if (known_eq (nunits_in, nunits_out))
5218 : : {
5219 : 466 : if (!(code.is_tree_code ()
5220 : 233 : && supportable_half_widening_operation ((tree_code) code,
5221 : : vectype_out, vectype_in,
5222 : : &tc1)))
5223 : 70 : goto unsupported;
5224 : 163 : code1 = tc1;
5225 : 163 : gcc_assert (!(multi_step_cvt && op_type == binary_op));
5226 : : break;
5227 : : }
5228 : 35885 : if (supportable_widening_operation (vinfo, code, stmt_info,
5229 : : vectype_out, vectype_in, &code1,
5230 : : &code2, &multi_step_cvt,
5231 : : &interm_types))
5232 : : {
5233 : : /* Binary widening operation can only be supported directly by the
5234 : : architecture. */
5235 : 33834 : gcc_assert (!(multi_step_cvt && op_type == binary_op));
5236 : : break;
5237 : : }
5238 : :
5239 : 2051 : if (code != FLOAT_EXPR
5240 : 2375 : || GET_MODE_SIZE (lhs_mode) <= GET_MODE_SIZE (rhs_mode))
5241 : 1889 : goto unsupported;
5242 : :
5243 : 162 : fltsz = GET_MODE_SIZE (lhs_mode);
5244 : 237 : FOR_EACH_2XWIDER_MODE (rhs_mode_iter, rhs_mode)
5245 : : {
5246 : 237 : rhs_mode = rhs_mode_iter.require ();
5247 : 474 : if (GET_MODE_SIZE (rhs_mode) > fltsz)
5248 : : break;
5249 : :
5250 : 237 : cvt_type
5251 : 237 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0);
5252 : 237 : cvt_type = get_same_sized_vectype (cvt_type, vectype_in);
5253 : 237 : if (cvt_type == NULL_TREE)
5254 : 0 : goto unsupported;
5255 : :
5256 : 474 : if (GET_MODE_SIZE (rhs_mode) == fltsz)
5257 : : {
5258 : 57 : tc1 = ERROR_MARK;
5259 : 57 : gcc_assert (code.is_tree_code ());
5260 : 57 : if (!supportable_convert_operation ((tree_code) code, vectype_out,
5261 : : cvt_type, &tc1))
5262 : 22 : goto unsupported;
5263 : 35 : codecvt1 = tc1;
5264 : : }
5265 : 180 : else if (!supportable_widening_operation (vinfo, code,
5266 : : stmt_info, vectype_out,
5267 : : cvt_type, &codecvt1,
5268 : : &codecvt2, &multi_step_cvt,
5269 : : &interm_types))
5270 : 75 : continue;
5271 : : else
5272 : 105 : gcc_assert (multi_step_cvt == 0);
5273 : :
5274 : 140 : if (supportable_widening_operation (vinfo, NOP_EXPR, stmt_info,
5275 : : cvt_type,
5276 : : vectype_in, &code1,
5277 : : &code2, &multi_step_cvt,
5278 : : &interm_types))
5279 : : {
5280 : : found_mode = true;
5281 : : break;
5282 : : }
5283 : : }
5284 : :
5285 : 140 : if (!found_mode)
5286 : 0 : goto unsupported;
5287 : :
5288 : 280 : if (GET_MODE_SIZE (rhs_mode) == fltsz)
5289 : 35 : codecvt2 = ERROR_MARK;
5290 : : else
5291 : : {
5292 : 105 : multi_step_cvt++;
5293 : 105 : interm_types.safe_push (cvt_type);
5294 : 105 : cvt_type = NULL_TREE;
5295 : : }
5296 : : break;
5297 : :
5298 : 31877 : case NARROW_DST:
5299 : 31877 : gcc_assert (op_type == unary_op);
5300 : 31877 : if (supportable_narrowing_operation (code, vectype_out, vectype_in,
5301 : : &code1, &multi_step_cvt,
5302 : : &interm_types))
5303 : : break;
5304 : :
5305 : 13287 : if (GET_MODE_SIZE (lhs_mode) >= GET_MODE_SIZE (rhs_mode))
5306 : 586 : goto unsupported;
5307 : :
5308 : 3843 : if (code == FIX_TRUNC_EXPR)
5309 : : {
5310 : 274 : cvt_type
5311 : 274 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0);
5312 : 274 : cvt_type = get_same_sized_vectype (cvt_type, vectype_in);
5313 : 274 : if (cvt_type == NULL_TREE)
5314 : 0 : goto unsupported;
5315 : 274 : if (supportable_convert_operation ((tree_code) code, cvt_type, vectype_in,
5316 : : &tc1))
5317 : 272 : codecvt1 = tc1;
5318 : : else
5319 : 2 : goto unsupported;
5320 : 272 : if (supportable_narrowing_operation (NOP_EXPR, vectype_out, cvt_type,
5321 : : &code1, &multi_step_cvt,
5322 : : &interm_types))
5323 : : break;
5324 : : }
5325 : : /* If op0 can be represented with low precision integer,
5326 : : truncate it to cvt_type and the do FLOAT_EXPR. */
5327 : 3569 : else if (code == FLOAT_EXPR)
5328 : : {
5329 : 96 : wide_int op_min_value, op_max_value;
5330 : 96 : tree def;
5331 : : /* ??? Merge ranges in case of more than one lane. */
5332 : 96 : if (SLP_TREE_LANES (slp_op0) != 1
5333 : 94 : || !(def = vect_get_slp_scalar_def (slp_op0, 0))
5334 : 190 : || !vect_get_range_info (def, &op_min_value, &op_max_value))
5335 : 94 : goto unsupported;
5336 : :
5337 : 2 : cvt_type
5338 : 2 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (lhs_mode), 0);
5339 : 2 : if (cvt_type == NULL_TREE
5340 : 2 : || (wi::min_precision (op_max_value, SIGNED)
5341 : 2 : > TYPE_PRECISION (cvt_type))
5342 : 4 : || (wi::min_precision (op_min_value, SIGNED)
5343 : 2 : > TYPE_PRECISION (cvt_type)))
5344 : 0 : goto unsupported;
5345 : :
5346 : 2 : cvt_type = get_same_sized_vectype (cvt_type, vectype_out);
5347 : 2 : if (cvt_type == NULL_TREE)
5348 : 0 : goto unsupported;
5349 : 2 : if (!supportable_narrowing_operation (NOP_EXPR, cvt_type, vectype_in,
5350 : : &code1, &multi_step_cvt,
5351 : : &interm_types))
5352 : 0 : goto unsupported;
5353 : 2 : if (supportable_convert_operation ((tree_code) code, vectype_out,
5354 : : cvt_type, &tc1))
5355 : : {
5356 : 2 : codecvt1 = tc1;
5357 : 2 : modifier = NARROW_SRC;
5358 : 2 : break;
5359 : : }
5360 : 96 : }
5361 : :
5362 : 3477 : goto unsupported;
5363 : :
5364 : : default:
5365 : : gcc_unreachable ();
5366 : : }
5367 : :
5368 : 79187 : if (modifier == WIDEN
5369 : 79187 : && loop_vinfo
5370 : 33046 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
5371 : 79219 : && (code1 == VEC_WIDEN_MULT_EVEN_EXPR
5372 : 30 : || widening_evenodd_fn_p (code1)))
5373 : : {
5374 : 2 : if (dump_enabled_p ())
5375 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5376 : : "can't use a fully-masked loop because"
5377 : : " widening operation on even/odd elements"
5378 : : " mixes up lanes.\n");
5379 : 2 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
5380 : : }
5381 : :
5382 : 79187 : if (cost_vec) /* transformation not required. */
5383 : : {
5384 : 59606 : if (!vect_maybe_update_slp_op_vectype (slp_op0, vectype_in)
5385 : 59606 : || !vect_maybe_update_slp_op_vectype (slp_op1, vectype_in))
5386 : : {
5387 : 0 : if (dump_enabled_p ())
5388 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5389 : : "incompatible vector types for invariants\n");
5390 : 0 : return false;
5391 : : }
5392 : 59606 : DUMP_VECT_SCOPE ("vectorizable_conversion");
5393 : 59606 : unsigned int nvectors = vect_get_num_copies (vinfo, slp_node);
5394 : 59606 : if (modifier == NONE)
5395 : : {
5396 : 13128 : SLP_TREE_TYPE (slp_node) = type_conversion_vec_info_type;
5397 : 13128 : vect_model_simple_cost (vinfo, (1 + multi_step_cvt),
5398 : : slp_node, cost_vec);
5399 : : }
5400 : 46478 : else if (modifier == NARROW_SRC || modifier == NARROW_DST)
5401 : : {
5402 : 20100 : SLP_TREE_TYPE (slp_node) = type_demotion_vec_info_type;
5403 : : /* The final packing step produces one vector result per copy. */
5404 : 20100 : vect_model_promotion_demotion_cost (slp_node, nvectors,
5405 : : multi_step_cvt, cost_vec,
5406 : : widen_arith);
5407 : : }
5408 : : else
5409 : : {
5410 : 26378 : SLP_TREE_TYPE (slp_node) = type_promotion_vec_info_type;
5411 : : /* The initial unpacking step produces two vector results
5412 : : per copy. MULTI_STEP_CVT is 0 for a single conversion,
5413 : : so >> MULTI_STEP_CVT divides by 2^(number of steps - 1). */
5414 : 26378 : vect_model_promotion_demotion_cost (slp_node,
5415 : : nvectors >> multi_step_cvt,
5416 : : multi_step_cvt, cost_vec,
5417 : : widen_arith);
5418 : : }
5419 : 59606 : interm_types.release ();
5420 : 59606 : return true;
5421 : : }
5422 : :
5423 : : /* Transform. */
5424 : 19581 : if (dump_enabled_p ())
5425 : 4164 : dump_printf_loc (MSG_NOTE, vect_location, "transform conversion.\n");
5426 : :
5427 : 19581 : if (op_type == binary_op)
5428 : : {
5429 : 486 : if (CONSTANT_CLASS_P (op0))
5430 : 0 : op0 = fold_convert (TREE_TYPE (op1), op0);
5431 : 486 : else if (CONSTANT_CLASS_P (op1))
5432 : 232 : op1 = fold_convert (TREE_TYPE (op0), op1);
5433 : : }
5434 : :
5435 : : /* In case of multi-step conversion, we first generate conversion operations
5436 : : to the intermediate types, and then from that types to the final one.
5437 : : We create vector destinations for the intermediate type (TYPES) received
5438 : : from supportable_*_operation, and store them in the correct order
5439 : : for future use in vect_create_vectorized_*_stmts (). */
5440 : 39162 : auto_vec<tree> vec_dsts (multi_step_cvt + 1);
5441 : 19581 : bool widen_or_narrow_float_p
5442 : 19581 : = cvt_type && (modifier == WIDEN || modifier == NARROW_SRC);
5443 : 19581 : vec_dest = vect_create_destination_var (scalar_dest,
5444 : : widen_or_narrow_float_p
5445 : : ? cvt_type : vectype_out);
5446 : 19581 : vec_dsts.quick_push (vec_dest);
5447 : :
5448 : 19581 : if (multi_step_cvt)
5449 : : {
5450 : 6324 : for (i = interm_types.length () - 1;
5451 : 6584 : interm_types.iterate (i, &intermediate_type); i--)
5452 : : {
5453 : 3422 : vec_dest = vect_create_destination_var (scalar_dest,
5454 : : intermediate_type);
5455 : 3422 : vec_dsts.quick_push (vec_dest);
5456 : : }
5457 : : }
5458 : :
5459 : 19581 : if (cvt_type)
5460 : 69 : vec_dest = vect_create_destination_var (scalar_dest,
5461 : : widen_or_narrow_float_p
5462 : : ? vectype_out : cvt_type);
5463 : :
5464 : 19581 : switch (modifier)
5465 : : {
5466 : 4204 : case NONE:
5467 : 4204 : vect_get_vec_defs (vinfo, slp_node, op0, &vec_oprnds0);
5468 : : /* vec_dest is intermediate type operand when multi_step_cvt. */
5469 : 4204 : if (multi_step_cvt)
5470 : : {
5471 : 21 : cvt_op = vec_dest;
5472 : 21 : vec_dest = vec_dsts[0];
5473 : : }
5474 : :
5475 : 8733 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
5476 : : {
5477 : : /* Arguments are ready, create the new vector stmt. */
5478 : 4529 : gimple* new_stmt;
5479 : 4529 : if (multi_step_cvt)
5480 : : {
5481 : 21 : gcc_assert (multi_step_cvt == 1);
5482 : 21 : new_stmt = vect_gimple_build (cvt_op, codecvt1, vop0);
5483 : 21 : new_temp = make_ssa_name (cvt_op, new_stmt);
5484 : 21 : gimple_assign_set_lhs (new_stmt, new_temp);
5485 : 21 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5486 : 21 : vop0 = new_temp;
5487 : : }
5488 : 4529 : new_stmt = vect_gimple_build (vec_dest, code1, vop0);
5489 : 4529 : new_temp = make_ssa_name (vec_dest, new_stmt);
5490 : 4529 : gimple_set_lhs (new_stmt, new_temp);
5491 : 4529 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5492 : :
5493 : 4529 : slp_node->push_vec_def (new_stmt);
5494 : : }
5495 : : break;
5496 : :
5497 : 7759 : case WIDEN:
5498 : : /* In case the vectorization factor (VF) is bigger than the number
5499 : : of elements that we can fit in a vectype (nunits), we have to
5500 : : generate more than one vector stmt - i.e - we need to "unroll"
5501 : : the vector stmt by a factor VF/nunits. */
5502 : 7759 : vect_get_vec_defs (vinfo, slp_node, op0, &vec_oprnds0,
5503 : 7759 : code == WIDEN_LSHIFT_EXPR ? NULL_TREE : op1,
5504 : : &vec_oprnds1);
5505 : 7759 : if (code == WIDEN_LSHIFT_EXPR)
5506 : : {
5507 : 0 : int oprnds_size = vec_oprnds0.length ();
5508 : 0 : vec_oprnds1.create (oprnds_size);
5509 : 0 : for (i = 0; i < oprnds_size; ++i)
5510 : 0 : vec_oprnds1.quick_push (op1);
5511 : : }
5512 : : /* Arguments are ready. Create the new vector stmts. */
5513 : 16808 : for (i = multi_step_cvt; i >= 0; i--)
5514 : : {
5515 : 9049 : tree this_dest = vec_dsts[i];
5516 : 9049 : code_helper c1 = code1, c2 = code2;
5517 : 9049 : if (i == 0 && codecvt2 != ERROR_MARK)
5518 : : {
5519 : 48 : c1 = codecvt1;
5520 : 48 : c2 = codecvt2;
5521 : : }
5522 : 9049 : if (known_eq (nunits_out, nunits_in))
5523 : 14 : vect_create_half_widening_stmts (vinfo, &vec_oprnds0, &vec_oprnds1,
5524 : : stmt_info, this_dest, gsi, c1,
5525 : : op_type);
5526 : : else
5527 : 9035 : vect_create_vectorized_promotion_stmts (vinfo, &vec_oprnds0,
5528 : : &vec_oprnds1, stmt_info,
5529 : : this_dest, gsi,
5530 : : c1, c2, op_type);
5531 : : }
5532 : :
5533 : 28077 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
5534 : : {
5535 : 20318 : gimple *new_stmt;
5536 : 20318 : if (cvt_type)
5537 : : {
5538 : 120 : new_temp = make_ssa_name (vec_dest);
5539 : 120 : new_stmt = vect_gimple_build (new_temp, codecvt1, vop0);
5540 : 120 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5541 : : }
5542 : : else
5543 : 20198 : new_stmt = SSA_NAME_DEF_STMT (vop0);
5544 : :
5545 : 20318 : slp_node->push_vec_def (new_stmt);
5546 : : }
5547 : : break;
5548 : :
5549 : 7618 : case NARROW_SRC:
5550 : 7618 : case NARROW_DST:
5551 : : /* In case the vectorization factor (VF) is bigger than the number
5552 : : of elements that we can fit in a vectype (nunits), we have to
5553 : : generate more than one vector stmt - i.e - we need to "unroll"
5554 : : the vector stmt by a factor VF/nunits. */
5555 : 7618 : vect_get_vec_defs (vinfo, slp_node, op0, &vec_oprnds0);
5556 : : /* Arguments are ready. Create the new vector stmts. */
5557 : 7618 : if (cvt_type && modifier == NARROW_DST)
5558 : 153 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
5559 : : {
5560 : 124 : new_temp = make_ssa_name (vec_dest);
5561 : 124 : gimple *new_stmt = vect_gimple_build (new_temp, codecvt1, vop0);
5562 : 124 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5563 : 124 : vec_oprnds0[i] = new_temp;
5564 : : }
5565 : :
5566 : 7618 : vect_create_vectorized_demotion_stmts (vinfo, &vec_oprnds0,
5567 : : multi_step_cvt,
5568 : : stmt_info, vec_dsts, gsi,
5569 : : slp_node, code1,
5570 : : modifier == NARROW_SRC);
5571 : : /* After demoting op0 to cvt_type, convert it to dest. */
5572 : 7618 : if (cvt_type && code == FLOAT_EXPR)
5573 : : {
5574 : 4 : for (unsigned int i = 0; i != vec_oprnds0.length() / 2; i++)
5575 : : {
5576 : : /* Arguments are ready, create the new vector stmt. */
5577 : 1 : gcc_assert (TREE_CODE_LENGTH ((tree_code) codecvt1) == unary_op);
5578 : 1 : gimple *new_stmt
5579 : 1 : = vect_gimple_build (vec_dest, codecvt1, vec_oprnds0[i]);
5580 : 1 : new_temp = make_ssa_name (vec_dest, new_stmt);
5581 : 1 : gimple_set_lhs (new_stmt, new_temp);
5582 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5583 : :
5584 : : /* This is the last step of the conversion sequence. Store the
5585 : : vectors in SLP_NODE or in vector info of the scalar statement
5586 : : (or in STMT_VINFO_RELATED_STMT chain). */
5587 : 1 : slp_node->push_vec_def (new_stmt);
5588 : : }
5589 : : }
5590 : : break;
5591 : : }
5592 : :
5593 : 19581 : vec_oprnds0.release ();
5594 : 19581 : vec_oprnds1.release ();
5595 : 19581 : interm_types.release ();
5596 : :
5597 : 19581 : return true;
5598 : 137359 : }
5599 : :
5600 : : /* Return true if we can assume from the scalar form of STMT_INFO that
5601 : : neither the scalar nor the vector forms will generate code. STMT_INFO
5602 : : is known not to involve a data reference. */
5603 : :
5604 : : bool
5605 : 1179718 : vect_nop_conversion_p (stmt_vec_info stmt_info)
5606 : : {
5607 : 1179718 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
5608 : 925845 : if (!stmt)
5609 : : return false;
5610 : :
5611 : 925845 : tree lhs = gimple_assign_lhs (stmt);
5612 : 925845 : tree_code code = gimple_assign_rhs_code (stmt);
5613 : 925845 : tree rhs = gimple_assign_rhs1 (stmt);
5614 : :
5615 : 925845 : if (code == SSA_NAME || code == VIEW_CONVERT_EXPR)
5616 : : return true;
5617 : :
5618 : 923876 : if (CONVERT_EXPR_CODE_P (code))
5619 : 195244 : return tree_nop_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs));
5620 : :
5621 : : return false;
5622 : : }
5623 : :
5624 : : /* Function vectorizable_assignment.
5625 : :
5626 : : Check if STMT_INFO performs an assignment (copy) that can be vectorized.
5627 : : If VEC_STMT is also passed, vectorize the STMT_INFO: create a vectorized
5628 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
5629 : : Return true if STMT_INFO is vectorizable in this way. */
5630 : :
5631 : : static bool
5632 : 1842846 : vectorizable_assignment (vec_info *vinfo,
5633 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
5634 : : slp_tree slp_node,
5635 : : stmt_vector_for_cost *cost_vec)
5636 : : {
5637 : 1842846 : tree vec_dest;
5638 : 1842846 : tree scalar_dest;
5639 : 1842846 : tree op;
5640 : 1842846 : tree new_temp;
5641 : 1842846 : enum vect_def_type dt[1] = {vect_unknown_def_type};
5642 : 1842846 : int i;
5643 : 1842846 : vec<tree> vec_oprnds = vNULL;
5644 : 1842846 : tree vop;
5645 : 1842846 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
5646 : 1842846 : enum tree_code code;
5647 : 1842846 : tree vectype_in;
5648 : :
5649 : 1842846 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
5650 : : return false;
5651 : :
5652 : 1842846 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
5653 : 180307 : && cost_vec)
5654 : : return false;
5655 : :
5656 : : /* Is vectorizable assignment? */
5657 : 3363948 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
5658 : 1590407 : if (!stmt)
5659 : : return false;
5660 : :
5661 : 1590407 : scalar_dest = gimple_assign_lhs (stmt);
5662 : 1590407 : if (TREE_CODE (scalar_dest) != SSA_NAME)
5663 : : return false;
5664 : :
5665 : 813480 : if (STMT_VINFO_DATA_REF (stmt_info))
5666 : : return false;
5667 : :
5668 : 350382 : code = gimple_assign_rhs_code (stmt);
5669 : 350382 : if (!(gimple_assign_single_p (stmt)
5670 : 349180 : || code == PAREN_EXPR
5671 : 347605 : || CONVERT_EXPR_CODE_P (code)))
5672 : : return false;
5673 : :
5674 : 79350 : tree vectype = SLP_TREE_VECTYPE (slp_node);
5675 : 79350 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
5676 : :
5677 : 79350 : slp_tree slp_op;
5678 : 79350 : if (!vect_is_simple_use (vinfo, slp_node, 0, &op, &slp_op,
5679 : : &dt[0], &vectype_in))
5680 : : {
5681 : 0 : if (dump_enabled_p ())
5682 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5683 : : "use not simple.\n");
5684 : 0 : return false;
5685 : : }
5686 : 79350 : if (!vectype_in)
5687 : 17447 : vectype_in = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op), slp_node);
5688 : :
5689 : : /* We can handle VIEW_CONVERT conversions that do not change the number
5690 : : of elements or the vector size or other conversions when the component
5691 : : types are nop-convertible. */
5692 : 79350 : if (!vectype_in
5693 : 79062 : || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype_in), nunits)
5694 : 72609 : || (code == VIEW_CONVERT_EXPR
5695 : 2152 : && maybe_ne (GET_MODE_SIZE (TYPE_MODE (vectype)),
5696 : 2152 : GET_MODE_SIZE (TYPE_MODE (vectype_in))))
5697 : 151959 : || (CONVERT_EXPR_CODE_P (code)
5698 : 69864 : && !tree_nop_conversion_p (TREE_TYPE (vectype),
5699 : 69864 : TREE_TYPE (vectype_in))))
5700 : 9785 : return false;
5701 : :
5702 : 208583 : if (VECTOR_BOOLEAN_TYPE_P (vectype) != VECTOR_BOOLEAN_TYPE_P (vectype_in))
5703 : : {
5704 : 0 : if (dump_enabled_p ())
5705 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5706 : : "can't convert between boolean and non "
5707 : 0 : "boolean vectors %T\n", TREE_TYPE (op));
5708 : :
5709 : 0 : return false;
5710 : : }
5711 : :
5712 : : /* We do not handle bit-precision changes. */
5713 : 69565 : if ((CONVERT_EXPR_CODE_P (code)
5714 : 2745 : || code == VIEW_CONVERT_EXPR)
5715 : 67896 : && ((INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
5716 : 66632 : && !type_has_mode_precision_p (TREE_TYPE (scalar_dest)))
5717 : 67596 : || (INTEGRAL_TYPE_P (TREE_TYPE (op))
5718 : 63295 : && !type_has_mode_precision_p (TREE_TYPE (op))))
5719 : : /* But a conversion that does not change the bit-pattern is ok. */
5720 : 70231 : && !(INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
5721 : 666 : && INTEGRAL_TYPE_P (TREE_TYPE (op))
5722 : 666 : && (((TYPE_PRECISION (TREE_TYPE (scalar_dest))
5723 : 666 : > TYPE_PRECISION (TREE_TYPE (op)))
5724 : 366 : && TYPE_UNSIGNED (TREE_TYPE (op)))
5725 : 316 : || (TYPE_PRECISION (TREE_TYPE (scalar_dest))
5726 : 316 : == TYPE_PRECISION (TREE_TYPE (op))))))
5727 : : {
5728 : 260 : if (dump_enabled_p ())
5729 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5730 : : "type conversion to/from bit-precision "
5731 : : "unsupported.\n");
5732 : 260 : return false;
5733 : : }
5734 : :
5735 : 69305 : if (cost_vec) /* transformation not required. */
5736 : : {
5737 : 55341 : if (!vect_maybe_update_slp_op_vectype (slp_op, vectype_in))
5738 : : {
5739 : 0 : if (dump_enabled_p ())
5740 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5741 : : "incompatible vector types for invariants\n");
5742 : 0 : return false;
5743 : : }
5744 : 55341 : SLP_TREE_TYPE (slp_node) = assignment_vec_info_type;
5745 : 55341 : DUMP_VECT_SCOPE ("vectorizable_assignment");
5746 : 55341 : if (!vect_nop_conversion_p (stmt_info))
5747 : 1318 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
5748 : 55341 : return true;
5749 : : }
5750 : :
5751 : : /* Transform. */
5752 : 13964 : if (dump_enabled_p ())
5753 : 3460 : dump_printf_loc (MSG_NOTE, vect_location, "transform assignment.\n");
5754 : :
5755 : : /* Handle def. */
5756 : 13964 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
5757 : :
5758 : : /* Handle use. */
5759 : 13964 : vect_get_vec_defs (vinfo, slp_node, op, &vec_oprnds);
5760 : :
5761 : : /* Arguments are ready. create the new vector stmt. */
5762 : 30613 : FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
5763 : : {
5764 : 16649 : if (CONVERT_EXPR_CODE_P (code)
5765 : 639 : || code == VIEW_CONVERT_EXPR)
5766 : 16102 : vop = build1 (VIEW_CONVERT_EXPR, vectype, vop);
5767 : 16649 : gassign *new_stmt = gimple_build_assign (vec_dest, vop);
5768 : 16649 : new_temp = make_ssa_name (vec_dest, new_stmt);
5769 : 16649 : gimple_assign_set_lhs (new_stmt, new_temp);
5770 : 16649 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5771 : 16649 : slp_node->push_vec_def (new_stmt);
5772 : : }
5773 : :
5774 : 13964 : vec_oprnds.release ();
5775 : 13964 : return true;
5776 : : }
5777 : :
5778 : :
5779 : : /* Return TRUE if CODE (a shift operation) is supported for SCALAR_TYPE
5780 : : either as shift by a scalar or by a vector. */
5781 : :
5782 : : bool
5783 : 270055 : vect_supportable_shift (vec_info *vinfo, enum tree_code code, tree scalar_type)
5784 : : {
5785 : 270055 : optab optab;
5786 : 270055 : tree vectype;
5787 : :
5788 : 270055 : vectype = get_vectype_for_scalar_type (vinfo, scalar_type);
5789 : 270055 : if (!vectype)
5790 : : return false;
5791 : :
5792 : 270055 : optab = optab_for_tree_code (code, vectype, optab_scalar);
5793 : 270055 : if (optab && can_implement_p (optab, TYPE_MODE (vectype)))
5794 : : return true;
5795 : :
5796 : 237067 : optab = optab_for_tree_code (code, vectype, optab_vector);
5797 : 237067 : if (optab && can_implement_p (optab, TYPE_MODE (vectype)))
5798 : : return true;
5799 : :
5800 : : return false;
5801 : : }
5802 : :
5803 : :
5804 : : /* Function vectorizable_shift.
5805 : :
5806 : : Check if STMT_INFO performs a shift operation that can be vectorized.
5807 : : If VEC_STMT is also passed, vectorize the STMT_INFO: create a vectorized
5808 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
5809 : : Return true if STMT_INFO is vectorizable in this way. */
5810 : :
5811 : : static bool
5812 : 628089 : vectorizable_shift (vec_info *vinfo,
5813 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
5814 : : slp_tree slp_node,
5815 : : stmt_vector_for_cost *cost_vec)
5816 : : {
5817 : 628089 : tree vec_dest;
5818 : 628089 : tree scalar_dest;
5819 : 628089 : tree op0, op1 = NULL;
5820 : 628089 : tree vec_oprnd1 = NULL_TREE;
5821 : 628089 : tree vectype;
5822 : 628089 : enum tree_code code;
5823 : 628089 : machine_mode vec_mode;
5824 : 628089 : tree new_temp;
5825 : 628089 : optab optab;
5826 : 628089 : int icode;
5827 : 628089 : machine_mode optab_op2_mode;
5828 : 628089 : enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
5829 : 628089 : poly_uint64 nunits_in;
5830 : 628089 : poly_uint64 nunits_out;
5831 : 628089 : tree vectype_out;
5832 : 628089 : tree op1_vectype;
5833 : 628089 : int i;
5834 : 628089 : vec<tree> vec_oprnds0 = vNULL;
5835 : 628089 : vec<tree> vec_oprnds1 = vNULL;
5836 : 628089 : tree vop0, vop1;
5837 : 628089 : unsigned int k;
5838 : 628089 : bool scalar_shift_arg = true;
5839 : 628089 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
5840 : 628089 : bool incompatible_op1_vectype_p = false;
5841 : :
5842 : 628089 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
5843 : : return false;
5844 : :
5845 : 628089 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
5846 : 180307 : && STMT_VINFO_DEF_TYPE (stmt_info) != vect_nested_cycle
5847 : 179017 : && cost_vec)
5848 : : return false;
5849 : :
5850 : : /* Is STMT a vectorizable binary/unary operation? */
5851 : 961497 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
5852 : 377305 : if (!stmt)
5853 : : return false;
5854 : :
5855 : 377305 : if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
5856 : : return false;
5857 : :
5858 : 376815 : code = gimple_assign_rhs_code (stmt);
5859 : :
5860 : 376815 : if (!(code == LSHIFT_EXPR || code == RSHIFT_EXPR || code == LROTATE_EXPR
5861 : : || code == RROTATE_EXPR))
5862 : : return false;
5863 : :
5864 : 58359 : scalar_dest = gimple_assign_lhs (stmt);
5865 : 58359 : vectype_out = SLP_TREE_VECTYPE (slp_node);
5866 : 58359 : if (!type_has_mode_precision_p (TREE_TYPE (scalar_dest)))
5867 : : {
5868 : 0 : if (dump_enabled_p ())
5869 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5870 : : "bit-precision shifts not supported.\n");
5871 : 0 : return false;
5872 : : }
5873 : :
5874 : 58359 : slp_tree slp_op0;
5875 : 58359 : if (!vect_is_simple_use (vinfo, slp_node,
5876 : : 0, &op0, &slp_op0, &dt[0], &vectype))
5877 : : {
5878 : 0 : if (dump_enabled_p ())
5879 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5880 : : "use not simple.\n");
5881 : 0 : return false;
5882 : : }
5883 : : /* If op0 is an external or constant def, infer the vector type
5884 : : from the scalar type. */
5885 : 58359 : if (!vectype)
5886 : 17499 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0), slp_node);
5887 : 58359 : if (!cost_vec)
5888 : 6195 : gcc_assert (vectype);
5889 : 58359 : if (!vectype)
5890 : : {
5891 : 0 : if (dump_enabled_p ())
5892 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5893 : : "no vectype for scalar type\n");
5894 : 0 : return false;
5895 : : }
5896 : :
5897 : 58359 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
5898 : 58359 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
5899 : 58359 : if (maybe_ne (nunits_out, nunits_in))
5900 : : return false;
5901 : :
5902 : 58359 : stmt_vec_info op1_def_stmt_info;
5903 : 58359 : slp_tree slp_op1;
5904 : 58359 : if (!vect_is_simple_use (vinfo, slp_node, 1, &op1, &slp_op1,
5905 : : &dt[1], &op1_vectype, &op1_def_stmt_info))
5906 : : {
5907 : 0 : if (dump_enabled_p ())
5908 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5909 : : "use not simple.\n");
5910 : 0 : return false;
5911 : : }
5912 : :
5913 : : /* Determine whether the shift amount is a vector, or scalar. If the
5914 : : shift/rotate amount is a vector, use the vector/vector shift optabs. */
5915 : :
5916 : 58359 : if ((dt[1] == vect_internal_def
5917 : 58359 : || dt[1] == vect_induction_def
5918 : 41359 : || dt[1] == vect_nested_cycle)
5919 : 17018 : && SLP_TREE_LANES (slp_node) == 1)
5920 : : scalar_shift_arg = false;
5921 : 41396 : else if (dt[1] == vect_constant_def
5922 : : || dt[1] == vect_external_def
5923 : 41396 : || dt[1] == vect_internal_def)
5924 : : {
5925 : : /* In SLP, need to check whether the shift count is the same,
5926 : : in loops if it is a constant or invariant, it is always
5927 : : a scalar shift. */
5928 : 41388 : vec<stmt_vec_info> stmts = SLP_TREE_SCALAR_STMTS (slp_node);
5929 : 41388 : stmt_vec_info slpstmt_info;
5930 : :
5931 : 113673 : FOR_EACH_VEC_ELT (stmts, k, slpstmt_info)
5932 : 72285 : if (slpstmt_info)
5933 : : {
5934 : 72285 : gassign *slpstmt = as_a <gassign *> (slpstmt_info->stmt);
5935 : 144570 : if (!operand_equal_p (gimple_assign_rhs2 (slpstmt), op1, 0))
5936 : 72285 : scalar_shift_arg = false;
5937 : : }
5938 : :
5939 : : /* For internal SLP defs we have to make sure we see scalar stmts
5940 : : for all vector elements.
5941 : : ??? For different vectors we could resort to a different
5942 : : scalar shift operand but code-generation below simply always
5943 : : takes the first. */
5944 : 41388 : if (dt[1] == vect_internal_def
5945 : 41435 : && maybe_ne (nunits_out * vect_get_num_copies (vinfo, slp_node),
5946 : 47 : stmts.length ()))
5947 : : scalar_shift_arg = false;
5948 : :
5949 : : /* If the shift amount is computed by a pattern stmt we cannot
5950 : : use the scalar amount directly thus give up and use a vector
5951 : : shift. */
5952 : 41388 : if (op1_def_stmt_info && is_pattern_stmt_p (op1_def_stmt_info))
5953 : : scalar_shift_arg = false;
5954 : : }
5955 : : else
5956 : : {
5957 : 8 : if (dump_enabled_p ())
5958 : 8 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5959 : : "operand mode requires invariant argument.\n");
5960 : 8 : return false;
5961 : : }
5962 : :
5963 : : /* Vector shifted by vector. */
5964 : 58379 : bool was_scalar_shift_arg = scalar_shift_arg;
5965 : 41381 : if (!scalar_shift_arg)
5966 : : {
5967 : 16998 : optab = optab_for_tree_code (code, vectype, optab_vector);
5968 : 16998 : if (dump_enabled_p ())
5969 : 1137 : dump_printf_loc (MSG_NOTE, vect_location,
5970 : : "vector/vector shift/rotate found.\n");
5971 : :
5972 : 16998 : if (!op1_vectype)
5973 : 7 : op1_vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op1),
5974 : : slp_op1);
5975 : 16998 : incompatible_op1_vectype_p
5976 : 33996 : = (op1_vectype == NULL_TREE
5977 : 16998 : || maybe_ne (TYPE_VECTOR_SUBPARTS (op1_vectype),
5978 : 16998 : TYPE_VECTOR_SUBPARTS (vectype))
5979 : 23884 : || TYPE_MODE (op1_vectype) != TYPE_MODE (vectype));
5980 : 6881 : if (incompatible_op1_vectype_p
5981 : 10117 : && (SLP_TREE_DEF_TYPE (slp_op1) != vect_constant_def
5982 : 1 : || slp_op1->refcnt != 1))
5983 : : {
5984 : 10116 : if (dump_enabled_p ())
5985 : 30 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5986 : : "unusable type for last operand in"
5987 : : " vector/vector shift/rotate.\n");
5988 : 10116 : return false;
5989 : : }
5990 : : }
5991 : : /* See if the machine has a vector shifted by scalar insn and if not
5992 : : then see if it has a vector shifted by vector insn. */
5993 : : else
5994 : : {
5995 : 41353 : optab = optab_for_tree_code (code, vectype, optab_scalar);
5996 : 41353 : if (optab
5997 : 41353 : && can_implement_p (optab, TYPE_MODE (vectype)))
5998 : : {
5999 : 41353 : if (dump_enabled_p ())
6000 : 4652 : dump_printf_loc (MSG_NOTE, vect_location,
6001 : : "vector/scalar shift/rotate found.\n");
6002 : : }
6003 : : else
6004 : : {
6005 : 0 : optab = optab_for_tree_code (code, vectype, optab_vector);
6006 : 0 : if (optab
6007 : 0 : && can_implement_p (optab, TYPE_MODE (vectype)))
6008 : : {
6009 : 0 : scalar_shift_arg = false;
6010 : :
6011 : 0 : if (dump_enabled_p ())
6012 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
6013 : : "vector/vector shift/rotate found.\n");
6014 : :
6015 : 0 : if (!op1_vectype)
6016 : 0 : op1_vectype = get_vectype_for_scalar_type (vinfo,
6017 : 0 : TREE_TYPE (op1),
6018 : : slp_op1);
6019 : :
6020 : : /* Unlike the other binary operators, shifts/rotates have
6021 : : the rhs being int, instead of the same type as the lhs,
6022 : : so make sure the scalar is the right type if we are
6023 : : dealing with vectors of long long/long/short/char. */
6024 : 0 : incompatible_op1_vectype_p
6025 : 0 : = (!op1_vectype
6026 : 0 : || !tree_nop_conversion_p (TREE_TYPE (vectype),
6027 : 0 : TREE_TYPE (op1)));
6028 : 0 : if (incompatible_op1_vectype_p
6029 : 0 : && dt[1] == vect_internal_def)
6030 : : {
6031 : 0 : if (dump_enabled_p ())
6032 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6033 : : "unusable type for last operand in"
6034 : : " vector/vector shift/rotate.\n");
6035 : 0 : return false;
6036 : : }
6037 : : }
6038 : : }
6039 : : }
6040 : :
6041 : : /* Supportable by target? */
6042 : 48235 : if (!optab)
6043 : : {
6044 : 0 : if (dump_enabled_p ())
6045 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6046 : : "no optab.\n");
6047 : 0 : return false;
6048 : : }
6049 : 48235 : vec_mode = TYPE_MODE (vectype);
6050 : 48235 : icode = (int) optab_handler (optab, vec_mode);
6051 : 48235 : if (icode == CODE_FOR_nothing)
6052 : : {
6053 : 4338 : if (dump_enabled_p ())
6054 : 818 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6055 : : "op not supported by target.\n");
6056 : 4338 : return false;
6057 : : }
6058 : : /* vector lowering cannot optimize vector shifts using word arithmetic. */
6059 : 43897 : if (vect_emulated_vector_p (vectype))
6060 : : return false;
6061 : :
6062 : 43897 : if (cost_vec) /* transformation not required. */
6063 : : {
6064 : 37702 : if (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
6065 : 37702 : || ((!scalar_shift_arg || dt[1] == vect_internal_def)
6066 : 1804 : && (!incompatible_op1_vectype_p
6067 : 1 : || dt[1] == vect_constant_def)
6068 : 1804 : && !vect_maybe_update_slp_op_vectype
6069 : 1804 : (slp_op1,
6070 : : incompatible_op1_vectype_p ? vectype : op1_vectype)))
6071 : : {
6072 : 0 : if (dump_enabled_p ())
6073 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6074 : : "incompatible vector types for invariants\n");
6075 : 0 : return false;
6076 : : }
6077 : : /* Now adjust the constant shift amount in place. */
6078 : 37702 : if (incompatible_op1_vectype_p
6079 : 1 : && dt[1] == vect_constant_def)
6080 : 4 : for (unsigned i = 0;
6081 : 5 : i < SLP_TREE_SCALAR_OPS (slp_op1).length (); ++i)
6082 : : {
6083 : 4 : SLP_TREE_SCALAR_OPS (slp_op1)[i]
6084 : 4 : = fold_convert (TREE_TYPE (vectype),
6085 : : SLP_TREE_SCALAR_OPS (slp_op1)[i]);
6086 : 4 : gcc_assert ((TREE_CODE (SLP_TREE_SCALAR_OPS (slp_op1)[i])
6087 : : == INTEGER_CST));
6088 : : }
6089 : 37702 : SLP_TREE_TYPE (slp_node) = shift_vec_info_type;
6090 : 37702 : DUMP_VECT_SCOPE ("vectorizable_shift");
6091 : 37702 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
6092 : 37702 : return true;
6093 : : }
6094 : :
6095 : : /* Transform. */
6096 : :
6097 : 6195 : if (dump_enabled_p ())
6098 : 1871 : dump_printf_loc (MSG_NOTE, vect_location,
6099 : : "transform binary/unary operation.\n");
6100 : :
6101 : : /* Handle def. */
6102 : 6195 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6103 : :
6104 : 6195 : unsigned nvectors = vect_get_num_copies (vinfo, slp_node);
6105 : 6195 : if (scalar_shift_arg && dt[1] != vect_internal_def)
6106 : : {
6107 : : /* Vector shl and shr insn patterns can be defined with scalar
6108 : : operand 2 (shift operand). In this case, use constant or loop
6109 : : invariant op1 directly, without extending it to vector mode
6110 : : first. */
6111 : 5435 : optab_op2_mode = insn_data[icode].operand[2].mode;
6112 : 5435 : if (!VECTOR_MODE_P (optab_op2_mode))
6113 : : {
6114 : 5435 : if (dump_enabled_p ())
6115 : 1763 : dump_printf_loc (MSG_NOTE, vect_location,
6116 : : "operand 1 using scalar mode.\n");
6117 : 5435 : vec_oprnd1 = op1;
6118 : 5435 : vec_oprnds1.create (nvectors);
6119 : 5435 : vec_oprnds1.quick_push (vec_oprnd1);
6120 : : /* Store vec_oprnd1 for every vector stmt to be created.
6121 : : We check during the analysis that all the shift arguments
6122 : : are the same.
6123 : : TODO: Allow different constants for different vector
6124 : : stmts generated for an SLP instance. */
6125 : 12972 : for (k = 0; k < nvectors - 1; k++)
6126 : 2102 : vec_oprnds1.quick_push (vec_oprnd1);
6127 : : }
6128 : : }
6129 : 760 : else if (!scalar_shift_arg && incompatible_op1_vectype_p)
6130 : : {
6131 : 0 : if (was_scalar_shift_arg)
6132 : : {
6133 : : /* If the argument was the same in all lanes create the
6134 : : correctly typed vector shift amount directly. Note
6135 : : we made SLP scheduling think we use the original scalars,
6136 : : so place the compensation code next to the shift which
6137 : : is conservative. See PR119640 where it otherwise breaks. */
6138 : 0 : op1 = fold_convert (TREE_TYPE (vectype), op1);
6139 : 0 : op1 = vect_init_vector (vinfo, stmt_info, op1, TREE_TYPE (vectype),
6140 : : gsi);
6141 : 0 : vec_oprnd1 = vect_init_vector (vinfo, stmt_info, op1, vectype,
6142 : : gsi);
6143 : 0 : vec_oprnds1.create (nvectors);
6144 : 0 : for (k = 0; k < nvectors; k++)
6145 : 0 : vec_oprnds1.quick_push (vec_oprnd1);
6146 : : }
6147 : 0 : else if (dt[1] == vect_constant_def)
6148 : : /* The constant shift amount has been adjusted in place. */
6149 : : ;
6150 : : else
6151 : 0 : gcc_assert (TYPE_MODE (op1_vectype) == TYPE_MODE (vectype));
6152 : : }
6153 : :
6154 : : /* vec_oprnd1 is available if operand 1 should be of a scalar-type
6155 : : (a special case for certain kind of vector shifts); otherwise,
6156 : : operand 1 should be of a vector type (the usual case). */
6157 : 760 : vect_get_vec_defs (vinfo, slp_node,
6158 : : op0, &vec_oprnds0,
6159 : 6195 : vec_oprnd1 ? NULL_TREE : op1, &vec_oprnds1);
6160 : :
6161 : : /* Arguments are ready. Create the new vector stmt. */
6162 : 14902 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6163 : : {
6164 : : /* For internal defs where we need to use a scalar shift arg
6165 : : extract the first lane. */
6166 : 8707 : if (scalar_shift_arg && dt[1] == vect_internal_def)
6167 : : {
6168 : 10 : vop1 = vec_oprnds1[0];
6169 : 10 : new_temp = make_ssa_name (TREE_TYPE (TREE_TYPE (vop1)));
6170 : 10 : gassign *new_stmt
6171 : 10 : = gimple_build_assign (new_temp,
6172 : 10 : build3 (BIT_FIELD_REF, TREE_TYPE (new_temp),
6173 : : vop1,
6174 : 10 : TYPE_SIZE (TREE_TYPE (new_temp)),
6175 : : bitsize_zero_node));
6176 : 10 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6177 : 10 : vop1 = new_temp;
6178 : 10 : }
6179 : : else
6180 : 8697 : vop1 = vec_oprnds1[i];
6181 : 8707 : gassign *new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1);
6182 : 8707 : new_temp = make_ssa_name (vec_dest, new_stmt);
6183 : 8707 : gimple_assign_set_lhs (new_stmt, new_temp);
6184 : 8707 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6185 : 8707 : slp_node->push_vec_def (new_stmt);
6186 : : }
6187 : :
6188 : 6195 : vec_oprnds0.release ();
6189 : 6195 : vec_oprnds1.release ();
6190 : :
6191 : 6195 : return true;
6192 : : }
6193 : :
6194 : : /* Function vectorizable_operation.
6195 : :
6196 : : Check if STMT_INFO performs a binary, unary or ternary operation that can
6197 : : be vectorized.
6198 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
6199 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
6200 : : Return true if STMT_INFO is vectorizable in this way. */
6201 : :
6202 : : static bool
6203 : 2329283 : vectorizable_operation (vec_info *vinfo,
6204 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
6205 : : slp_tree slp_node,
6206 : : stmt_vector_for_cost *cost_vec)
6207 : : {
6208 : 2329283 : tree vec_dest;
6209 : 2329283 : tree scalar_dest;
6210 : 2329283 : tree op0, op1 = NULL_TREE, op2 = NULL_TREE;
6211 : 2329283 : tree vectype;
6212 : 2329283 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
6213 : 2329283 : enum tree_code code, orig_code;
6214 : 2329283 : machine_mode vec_mode;
6215 : 2329283 : tree new_temp;
6216 : 2329283 : int op_type;
6217 : 2329283 : optab optab;
6218 : 2329283 : bool target_support_p;
6219 : 2329283 : enum vect_def_type dt[3]
6220 : : = {vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type};
6221 : 2329283 : poly_uint64 nunits_in;
6222 : 2329283 : poly_uint64 nunits_out;
6223 : 2329283 : tree vectype_out;
6224 : 2329283 : int i;
6225 : 2329283 : vec<tree> vec_oprnds0 = vNULL;
6226 : 2329283 : vec<tree> vec_oprnds1 = vNULL;
6227 : 2329283 : vec<tree> vec_oprnds2 = vNULL;
6228 : 2329283 : tree vop0, vop1, vop2;
6229 : 2329283 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
6230 : :
6231 : 2329283 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
6232 : : return false;
6233 : :
6234 : 2329283 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
6235 : 180307 : && cost_vec)
6236 : : return false;
6237 : :
6238 : : /* Is STMT a vectorizable binary/unary operation? */
6239 : 3905726 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
6240 : 2076844 : if (!stmt)
6241 : : return false;
6242 : :
6243 : : /* Loads and stores are handled in vectorizable_{load,store}. */
6244 : 2076844 : if (STMT_VINFO_DATA_REF (stmt_info))
6245 : : return false;
6246 : :
6247 : 836819 : orig_code = code = gimple_assign_rhs_code (stmt);
6248 : :
6249 : : /* Shifts are handled in vectorizable_shift. */
6250 : 836819 : if (code == LSHIFT_EXPR
6251 : : || code == RSHIFT_EXPR
6252 : : || code == LROTATE_EXPR
6253 : 836819 : || code == RROTATE_EXPR)
6254 : : return false;
6255 : :
6256 : : /* Comparisons are handled in vectorizable_comparison. */
6257 : 784655 : if (TREE_CODE_CLASS (code) == tcc_comparison)
6258 : : return false;
6259 : :
6260 : : /* Conditions are handled in vectorizable_condition. */
6261 : 613491 : if (code == COND_EXPR)
6262 : : return false;
6263 : :
6264 : : /* For pointer addition and subtraction, we should use the normal
6265 : : plus and minus for the vector operation. */
6266 : 596034 : if (code == POINTER_PLUS_EXPR)
6267 : : code = PLUS_EXPR;
6268 : 582086 : if (code == POINTER_DIFF_EXPR)
6269 : 1016 : code = MINUS_EXPR;
6270 : :
6271 : : /* Support only unary or binary operations. */
6272 : 596034 : op_type = TREE_CODE_LENGTH (code);
6273 : 596034 : if (op_type != unary_op && op_type != binary_op && op_type != ternary_op)
6274 : : {
6275 : 4 : if (dump_enabled_p ())
6276 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6277 : : "num. args = %d (not unary/binary/ternary op).\n",
6278 : : op_type);
6279 : 4 : return false;
6280 : : }
6281 : :
6282 : 596030 : scalar_dest = gimple_assign_lhs (stmt);
6283 : 596030 : vectype_out = SLP_TREE_VECTYPE (slp_node);
6284 : :
6285 : : /* Most operations cannot handle bit-precision types without extra
6286 : : truncations. */
6287 : 596030 : bool mask_op_p = VECTOR_BOOLEAN_TYPE_P (vectype_out);
6288 : 589028 : if (!mask_op_p
6289 : 589028 : && !type_has_mode_precision_p (TREE_TYPE (scalar_dest))
6290 : : /* Exception are bitwise binary operations. */
6291 : : && code != BIT_IOR_EXPR
6292 : 1443 : && code != BIT_XOR_EXPR
6293 : 1314 : && code != BIT_AND_EXPR)
6294 : : {
6295 : 1066 : if (dump_enabled_p ())
6296 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6297 : : "bit-precision arithmetic not supported.\n");
6298 : 1066 : return false;
6299 : : }
6300 : :
6301 : 594964 : slp_tree slp_op0;
6302 : 594964 : if (!vect_is_simple_use (vinfo, slp_node,
6303 : : 0, &op0, &slp_op0, &dt[0], &vectype))
6304 : : {
6305 : 0 : if (dump_enabled_p ())
6306 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6307 : : "use not simple.\n");
6308 : 0 : return false;
6309 : : }
6310 : 594964 : bool is_invariant = (dt[0] == vect_external_def
6311 : 594964 : || dt[0] == vect_constant_def);
6312 : : /* If op0 is an external or constant def, infer the vector type
6313 : : from the scalar type. */
6314 : 594964 : if (!vectype)
6315 : : {
6316 : : /* For boolean type we cannot determine vectype by
6317 : : invariant value (don't know whether it is a vector
6318 : : of booleans or vector of integers). We use output
6319 : : vectype because operations on boolean don't change
6320 : : type. */
6321 : 69571 : if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op0)))
6322 : : {
6323 : 1101 : if (!VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (scalar_dest)))
6324 : : {
6325 : 235 : if (dump_enabled_p ())
6326 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6327 : : "not supported operation on bool value.\n");
6328 : 235 : return false;
6329 : : }
6330 : 866 : vectype = vectype_out;
6331 : : }
6332 : : else
6333 : 68470 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0),
6334 : : slp_node);
6335 : : }
6336 : 594729 : if (!cost_vec)
6337 : 108708 : gcc_assert (vectype);
6338 : 594729 : if (!vectype)
6339 : : {
6340 : 304 : if (dump_enabled_p ())
6341 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6342 : : "no vectype for scalar type %T\n",
6343 : 0 : TREE_TYPE (op0));
6344 : :
6345 : 304 : return false;
6346 : : }
6347 : :
6348 : 594425 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
6349 : 594425 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
6350 : 594425 : if (maybe_ne (nunits_out, nunits_in)
6351 : 594425 : || !tree_nop_conversion_p (TREE_TYPE (vectype_out), TREE_TYPE (vectype)))
6352 : 10460 : return false;
6353 : :
6354 : 583965 : tree vectype2 = NULL_TREE, vectype3 = NULL_TREE;
6355 : 583965 : slp_tree slp_op1 = NULL, slp_op2 = NULL;
6356 : 583965 : if (op_type == binary_op || op_type == ternary_op)
6357 : : {
6358 : 518055 : if (!vect_is_simple_use (vinfo, slp_node,
6359 : : 1, &op1, &slp_op1, &dt[1], &vectype2))
6360 : : {
6361 : 0 : if (dump_enabled_p ())
6362 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6363 : : "use not simple.\n");
6364 : 0 : return false;
6365 : : }
6366 : 518055 : is_invariant &= (dt[1] == vect_external_def
6367 : 518055 : || dt[1] == vect_constant_def);
6368 : 518055 : if (vectype2
6369 : 865306 : && (maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype2))
6370 : 347251 : || !tree_nop_conversion_p (TREE_TYPE (vectype_out),
6371 : 347251 : TREE_TYPE (vectype2))))
6372 : 328 : return false;
6373 : : }
6374 : 583637 : if (op_type == ternary_op)
6375 : : {
6376 : 0 : if (!vect_is_simple_use (vinfo, slp_node,
6377 : : 2, &op2, &slp_op2, &dt[2], &vectype3))
6378 : : {
6379 : 0 : if (dump_enabled_p ())
6380 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6381 : : "use not simple.\n");
6382 : 0 : return false;
6383 : : }
6384 : 0 : is_invariant &= (dt[2] == vect_external_def
6385 : 0 : || dt[2] == vect_constant_def);
6386 : 0 : if (vectype3
6387 : 0 : && (maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype3))
6388 : 0 : || !tree_nop_conversion_p (TREE_TYPE (vectype_out),
6389 : 0 : TREE_TYPE (vectype3))))
6390 : 0 : return false;
6391 : : }
6392 : :
6393 : : /* Multiple types in SLP are handled by creating the appropriate number of
6394 : : vectorized stmts for each SLP node. */
6395 : 583637 : auto vec_num = vect_get_num_copies (vinfo, slp_node);
6396 : :
6397 : : /* Reject attempts to combine mask types with nonmask types, e.g. if
6398 : : we have an AND between a (nonmask) boolean loaded from memory and
6399 : : a (mask) boolean result of a comparison.
6400 : :
6401 : : TODO: We could easily fix these cases up using pattern statements. */
6402 : 583637 : if (VECTOR_BOOLEAN_TYPE_P (vectype) != mask_op_p
6403 : 926716 : || (vectype2 && VECTOR_BOOLEAN_TYPE_P (vectype2) != mask_op_p)
6404 : 1167274 : || (vectype3 && VECTOR_BOOLEAN_TYPE_P (vectype3) != mask_op_p))
6405 : : {
6406 : 0 : if (dump_enabled_p ())
6407 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6408 : : "mixed mask and nonmask vector types\n");
6409 : 0 : return false;
6410 : : }
6411 : :
6412 : : /* Supportable by target? */
6413 : :
6414 : 583637 : vec_mode = TYPE_MODE (vectype);
6415 : 583637 : optab = optab_for_tree_code (code, vectype, optab_default);
6416 : 583637 : if (!optab)
6417 : : {
6418 : 54929 : if (dump_enabled_p ())
6419 : 5716 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6420 : : "no optab.\n");
6421 : 54929 : return false;
6422 : : }
6423 : 528708 : target_support_p = can_implement_p (optab, vec_mode);
6424 : :
6425 : 528708 : bool using_emulated_vectors_p = vect_emulated_vector_p (vectype);
6426 : 528708 : if (!target_support_p || using_emulated_vectors_p)
6427 : : {
6428 : 28774 : if (dump_enabled_p ())
6429 : 1073 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6430 : : "op not supported by target.\n");
6431 : : /* When vec_mode is not a vector mode and we verified ops we
6432 : : do not have to lower like AND are natively supported let
6433 : : those through even when the mode isn't word_mode. For
6434 : : ops we have to lower the lowering code assumes we are
6435 : : dealing with word_mode. */
6436 : 57548 : if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype))
6437 : 28680 : || !GET_MODE_SIZE (vec_mode).is_constant ()
6438 : 28680 : || (((code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR)
6439 : 23380 : || !target_support_p)
6440 : 61211 : && maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD))
6441 : : /* Check only during analysis. */
6442 : 39421 : || (cost_vec && !vect_can_vectorize_without_simd_p (code)))
6443 : : {
6444 : 28008 : if (dump_enabled_p ())
6445 : 1073 : dump_printf (MSG_NOTE, "using word mode not possible.\n");
6446 : 28008 : return false;
6447 : : }
6448 : 766 : if (dump_enabled_p ())
6449 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
6450 : : "proceeding using word mode.\n");
6451 : : using_emulated_vectors_p = true;
6452 : : }
6453 : :
6454 : 500700 : int reduc_idx = SLP_TREE_REDUC_IDX (slp_node);
6455 : 500700 : vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL);
6456 : 321734 : vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL);
6457 : 500700 : internal_fn cond_fn = get_conditional_internal_fn (code);
6458 : 500700 : internal_fn cond_len_fn = get_conditional_len_internal_fn (code);
6459 : :
6460 : : /* If operating on inactive elements could generate spurious traps,
6461 : : we need to restrict the operation to active lanes. Note that this
6462 : : specifically doesn't apply to unhoisted invariants, since they
6463 : : operate on the same value for every lane.
6464 : :
6465 : : Similarly, if this operation is part of a reduction, a fully-masked
6466 : : loop should only change the active lanes of the reduction chain,
6467 : : keeping the inactive lanes as-is. */
6468 : 473100 : bool mask_out_inactive = ((!is_invariant && gimple_could_trap_p (stmt))
6469 : 919767 : || reduc_idx >= 0);
6470 : :
6471 : 500700 : if (cost_vec) /* transformation not required. */
6472 : : {
6473 : 391992 : if (loop_vinfo
6474 : 224700 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
6475 : 75 : && mask_out_inactive)
6476 : : {
6477 : 42 : if (cond_len_fn != IFN_LAST
6478 : 42 : && direct_internal_fn_supported_p (cond_len_fn, vectype,
6479 : : OPTIMIZE_FOR_SPEED))
6480 : 0 : vect_record_loop_len (loop_vinfo, lens, vec_num, vectype,
6481 : : 1);
6482 : 42 : else if (cond_fn != IFN_LAST
6483 : 42 : && direct_internal_fn_supported_p (cond_fn, vectype,
6484 : : OPTIMIZE_FOR_SPEED))
6485 : 15 : vect_record_loop_mask (loop_vinfo, masks, vec_num,
6486 : : vectype, NULL);
6487 : : else
6488 : : {
6489 : 27 : if (dump_enabled_p ())
6490 : 27 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6491 : : "can't use a fully-masked loop because no"
6492 : : " conditional operation is available.\n");
6493 : 27 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
6494 : : }
6495 : : }
6496 : :
6497 : : /* Put types on constant and invariant SLP children. */
6498 : 391992 : if (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
6499 : 391794 : || !vect_maybe_update_slp_op_vectype (slp_op1, vectype)
6500 : 783685 : || !vect_maybe_update_slp_op_vectype (slp_op2, vectype))
6501 : : {
6502 : 299 : if (dump_enabled_p ())
6503 : 4 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6504 : : "incompatible vector types for invariants\n");
6505 : 299 : return false;
6506 : : }
6507 : :
6508 : 391693 : SLP_TREE_TYPE (slp_node) = op_vec_info_type;
6509 : 391693 : DUMP_VECT_SCOPE ("vectorizable_operation");
6510 : 391693 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
6511 : 391693 : if (using_emulated_vectors_p)
6512 : : {
6513 : : /* The above vect_model_simple_cost call handles constants
6514 : : in the prologue and (mis-)costs one of the stmts as
6515 : : vector stmt. See below for the actual lowering that will
6516 : : be applied. */
6517 : 764 : unsigned n = vect_get_num_copies (vinfo, slp_node);
6518 : 764 : switch (code)
6519 : : {
6520 : 267 : case PLUS_EXPR:
6521 : 267 : n *= 5;
6522 : 267 : break;
6523 : 462 : case MINUS_EXPR:
6524 : 462 : n *= 6;
6525 : 462 : break;
6526 : 0 : case NEGATE_EXPR:
6527 : 0 : n *= 4;
6528 : 0 : break;
6529 : : default:
6530 : : /* Bit operations do not have extra cost and are accounted
6531 : : as vector stmt by vect_model_simple_cost. */
6532 : : n = 0;
6533 : : break;
6534 : : }
6535 : 729 : if (n != 0)
6536 : : {
6537 : : /* We also need to materialize two large constants. */
6538 : 729 : record_stmt_cost (cost_vec, 2, scalar_stmt, stmt_info,
6539 : : 0, vect_prologue);
6540 : 729 : record_stmt_cost (cost_vec, n, scalar_stmt, stmt_info,
6541 : : 0, vect_body);
6542 : : }
6543 : : }
6544 : 391693 : return true;
6545 : : }
6546 : :
6547 : : /* Transform. */
6548 : :
6549 : 108708 : if (dump_enabled_p ())
6550 : 15802 : dump_printf_loc (MSG_NOTE, vect_location,
6551 : : "transform binary/unary operation.\n");
6552 : :
6553 : 108708 : bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
6554 : 97034 : bool len_loop_p = loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
6555 : :
6556 : : /* POINTER_DIFF_EXPR has pointer arguments which are vectorized as
6557 : : vectors with unsigned elements, but the result is signed. So, we
6558 : : need to compute the MINUS_EXPR into vectype temporary and
6559 : : VIEW_CONVERT_EXPR it into the final vectype_out result. */
6560 : 108708 : tree vec_cvt_dest = NULL_TREE;
6561 : 108708 : if (orig_code == POINTER_DIFF_EXPR)
6562 : : {
6563 : 128 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6564 : 128 : vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out);
6565 : : }
6566 : : /* For reduction operations with undefined overflow behavior make sure to
6567 : : pun them to unsigned since we change the order of evaluation.
6568 : : ??? Avoid for in-order reductions? */
6569 : 108580 : else if (arith_code_with_undefined_signed_overflow (orig_code)
6570 : 94303 : && ANY_INTEGRAL_TYPE_P (vectype)
6571 : 49176 : && TYPE_OVERFLOW_UNDEFINED (vectype)
6572 : 135120 : && SLP_TREE_REDUC_IDX (slp_node) != -1)
6573 : : {
6574 : 2256 : gcc_assert (orig_code == PLUS_EXPR || orig_code == MINUS_EXPR
6575 : : || orig_code == MULT_EXPR || orig_code == POINTER_PLUS_EXPR);
6576 : 2256 : vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out);
6577 : 2256 : vectype = unsigned_type_for (vectype);
6578 : 2256 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6579 : : }
6580 : : /* Handle def. */
6581 : : else
6582 : 106324 : vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
6583 : :
6584 : 108708 : vect_get_vec_defs (vinfo, slp_node,
6585 : : op0, &vec_oprnds0, op1, &vec_oprnds1, op2, &vec_oprnds2);
6586 : : /* Arguments are ready. Create the new vector stmt. */
6587 : 243007 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6588 : : {
6589 : 134299 : gimple *new_stmt = NULL;
6590 : 268598 : vop1 = ((op_type == binary_op || op_type == ternary_op)
6591 : 134299 : ? vec_oprnds1[i] : NULL_TREE);
6592 : 134299 : vop2 = ((op_type == ternary_op) ? vec_oprnds2[i] : NULL_TREE);
6593 : :
6594 : 134299 : if (vec_cvt_dest
6595 : 134299 : && !useless_type_conversion_p (vectype, TREE_TYPE (vop0)))
6596 : : {
6597 : 2588 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype, vop0);
6598 : 2588 : new_stmt = gimple_build_assign (vec_dest, VIEW_CONVERT_EXPR,
6599 : : new_temp);
6600 : 2588 : new_temp = make_ssa_name (vec_dest, new_stmt);
6601 : 2588 : gimple_assign_set_lhs (new_stmt, new_temp);
6602 : 2588 : vect_finish_stmt_generation (vinfo, stmt_info,
6603 : : new_stmt, gsi);
6604 : 2588 : vop0 = new_temp;
6605 : : }
6606 : 134299 : if (vop1
6607 : 131925 : && vec_cvt_dest
6608 : 137030 : && !useless_type_conversion_p (vectype, TREE_TYPE (vop1)))
6609 : : {
6610 : 2588 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype, vop1);
6611 : 2588 : new_stmt = gimple_build_assign (vec_dest, VIEW_CONVERT_EXPR,
6612 : : new_temp);
6613 : 2588 : new_temp = make_ssa_name (vec_dest, new_stmt);
6614 : 2588 : gimple_assign_set_lhs (new_stmt, new_temp);
6615 : 2588 : vect_finish_stmt_generation (vinfo, stmt_info,
6616 : : new_stmt, gsi);
6617 : 2588 : vop1 = new_temp;
6618 : : }
6619 : 134299 : if (vop2
6620 : 0 : && vec_cvt_dest
6621 : 134299 : && !useless_type_conversion_p (vectype, TREE_TYPE (vop2)))
6622 : : {
6623 : 0 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype, vop2);
6624 : 0 : new_stmt = gimple_build_assign (vec_dest, VIEW_CONVERT_EXPR,
6625 : : new_temp);
6626 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
6627 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
6628 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
6629 : : new_stmt, gsi);
6630 : 0 : vop2 = new_temp;
6631 : : }
6632 : :
6633 : 134299 : if (using_emulated_vectors_p)
6634 : : {
6635 : : /* Lower the operation. This follows vector lowering. */
6636 : 2 : tree word_type = build_nonstandard_integer_type
6637 : 2 : (GET_MODE_BITSIZE (vec_mode).to_constant (), 1);
6638 : 2 : tree wvop0 = make_ssa_name (word_type);
6639 : 2 : new_stmt = gimple_build_assign (wvop0, VIEW_CONVERT_EXPR,
6640 : : build1 (VIEW_CONVERT_EXPR,
6641 : : word_type, vop0));
6642 : 2 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6643 : 2 : tree wvop1 = NULL_TREE;
6644 : 2 : if (vop1)
6645 : : {
6646 : 2 : wvop1 = make_ssa_name (word_type);
6647 : 2 : new_stmt = gimple_build_assign (wvop1, VIEW_CONVERT_EXPR,
6648 : : build1 (VIEW_CONVERT_EXPR,
6649 : : word_type, vop1));
6650 : 2 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6651 : : }
6652 : :
6653 : 2 : tree result_low;
6654 : 2 : if (code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR)
6655 : : {
6656 : 1 : unsigned int width = vector_element_bits (vectype);
6657 : 1 : tree inner_type = TREE_TYPE (vectype);
6658 : 1 : HOST_WIDE_INT max = GET_MODE_MASK (TYPE_MODE (inner_type));
6659 : 1 : tree low_bits
6660 : 1 : = build_replicated_int_cst (word_type, width, max >> 1);
6661 : 1 : tree high_bits
6662 : 2 : = build_replicated_int_cst (word_type,
6663 : 1 : width, max & ~(max >> 1));
6664 : 1 : tree signs;
6665 : 1 : if (code == PLUS_EXPR || code == MINUS_EXPR)
6666 : : {
6667 : 1 : signs = make_ssa_name (word_type);
6668 : 1 : new_stmt = gimple_build_assign (signs,
6669 : : BIT_XOR_EXPR, wvop0, wvop1);
6670 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6671 : 1 : tree b_low = make_ssa_name (word_type);
6672 : 1 : new_stmt = gimple_build_assign (b_low, BIT_AND_EXPR,
6673 : : wvop1, low_bits);
6674 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6675 : 1 : tree a_low = make_ssa_name (word_type);
6676 : 1 : if (code == PLUS_EXPR)
6677 : 1 : new_stmt = gimple_build_assign (a_low, BIT_AND_EXPR,
6678 : : wvop0, low_bits);
6679 : : else
6680 : 0 : new_stmt = gimple_build_assign (a_low, BIT_IOR_EXPR,
6681 : : wvop0, high_bits);
6682 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6683 : 1 : if (code == MINUS_EXPR)
6684 : : {
6685 : 0 : new_stmt = gimple_build_assign (NULL_TREE,
6686 : : BIT_NOT_EXPR, signs);
6687 : 0 : signs = make_ssa_name (word_type);
6688 : 0 : gimple_assign_set_lhs (new_stmt, signs);
6689 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
6690 : : new_stmt, gsi);
6691 : : }
6692 : 1 : new_stmt = gimple_build_assign (NULL_TREE, BIT_AND_EXPR,
6693 : : signs, high_bits);
6694 : 1 : signs = make_ssa_name (word_type);
6695 : 1 : gimple_assign_set_lhs (new_stmt, signs);
6696 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6697 : 1 : result_low = make_ssa_name (word_type);
6698 : 1 : new_stmt = gimple_build_assign (result_low, code,
6699 : : a_low, b_low);
6700 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6701 : : }
6702 : : else /* if (code == NEGATE_EXPR) */
6703 : : {
6704 : 0 : tree a_low = make_ssa_name (word_type);
6705 : 0 : new_stmt = gimple_build_assign (a_low, BIT_AND_EXPR,
6706 : : wvop0, low_bits);
6707 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6708 : 0 : signs = make_ssa_name (word_type);
6709 : 0 : new_stmt = gimple_build_assign (signs, BIT_NOT_EXPR, wvop0);
6710 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6711 : 0 : new_stmt = gimple_build_assign (NULL_TREE, BIT_AND_EXPR,
6712 : : signs, high_bits);
6713 : 0 : signs = make_ssa_name (word_type);
6714 : 0 : gimple_assign_set_lhs (new_stmt, signs);
6715 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6716 : 0 : result_low = make_ssa_name (word_type);
6717 : 0 : new_stmt = gimple_build_assign (result_low,
6718 : : MINUS_EXPR, high_bits, a_low);
6719 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6720 : : }
6721 : 1 : new_stmt = gimple_build_assign (NULL_TREE, BIT_XOR_EXPR,
6722 : : result_low, signs);
6723 : 1 : result_low = make_ssa_name (word_type);
6724 : 1 : gimple_assign_set_lhs (new_stmt, result_low);
6725 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6726 : : }
6727 : : else
6728 : : {
6729 : 1 : new_stmt = gimple_build_assign (NULL_TREE, code, wvop0, wvop1);
6730 : 1 : result_low = make_ssa_name (word_type);
6731 : 1 : gimple_assign_set_lhs (new_stmt, result_low);
6732 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6733 : :
6734 : : }
6735 : 2 : new_stmt = gimple_build_assign (NULL_TREE, VIEW_CONVERT_EXPR,
6736 : : build1 (VIEW_CONVERT_EXPR,
6737 : : vectype, result_low));
6738 : 2 : new_temp = make_ssa_name (vectype);
6739 : 2 : gimple_assign_set_lhs (new_stmt, new_temp);
6740 : 2 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6741 : : }
6742 : 134297 : else if ((masked_loop_p || len_loop_p) && mask_out_inactive)
6743 : : {
6744 : 16 : tree mask;
6745 : 16 : if (masked_loop_p)
6746 : 16 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
6747 : : vec_num, vectype, i);
6748 : : else
6749 : : /* Dummy mask. */
6750 : 0 : mask = build_minus_one_cst (truth_type_for (vectype));
6751 : 16 : auto_vec<tree> vops (6);
6752 : 16 : vops.quick_push (mask);
6753 : 16 : vops.quick_push (vop0);
6754 : 16 : if (vop1)
6755 : 16 : vops.quick_push (vop1);
6756 : 16 : if (vop2)
6757 : 0 : vops.quick_push (vop2);
6758 : 16 : if (reduc_idx >= 0)
6759 : : {
6760 : : /* Perform the operation on active elements only and take
6761 : : inactive elements from the reduction chain input. */
6762 : 8 : gcc_assert (!vop2);
6763 : 8 : vops.quick_push (reduc_idx == 1 ? vop1 : vop0);
6764 : : }
6765 : : else
6766 : : {
6767 : 8 : auto else_value = targetm.preferred_else_value
6768 : 8 : (cond_fn, vectype, vops.length () - 1, &vops[1]);
6769 : 8 : vops.quick_push (else_value);
6770 : : }
6771 : 16 : if (len_loop_p)
6772 : : {
6773 : 0 : tree len = vect_get_loop_len (loop_vinfo, gsi, lens,
6774 : 0 : vec_num, vectype, i, 1);
6775 : 0 : signed char biasval
6776 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
6777 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
6778 : 0 : vops.quick_push (len);
6779 : 0 : vops.quick_push (bias);
6780 : : }
6781 : 16 : gcall *call
6782 : 16 : = gimple_build_call_internal_vec (masked_loop_p ? cond_fn
6783 : : : cond_len_fn,
6784 : : vops);
6785 : 16 : new_temp = make_ssa_name (vec_dest, call);
6786 : 16 : gimple_call_set_lhs (call, new_temp);
6787 : 16 : gimple_call_set_nothrow (call, true);
6788 : 16 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
6789 : 16 : new_stmt = call;
6790 : 16 : }
6791 : : else
6792 : : {
6793 : 134281 : tree mask = NULL_TREE;
6794 : : /* When combining two masks check if either of them is elsewhere
6795 : : combined with a loop mask, if that's the case we can mark that the
6796 : : new combined mask doesn't need to be combined with a loop mask. */
6797 : 134281 : if (masked_loop_p
6798 : 134281 : && code == BIT_AND_EXPR
6799 : 134281 : && VECTOR_BOOLEAN_TYPE_P (vectype))
6800 : : {
6801 : 8 : if (loop_vinfo->scalar_cond_masked_set.contains ({ op0, vec_num }))
6802 : : {
6803 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
6804 : : vec_num, vectype, i);
6805 : :
6806 : 0 : vop0 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
6807 : : vop0, gsi);
6808 : : }
6809 : :
6810 : 8 : if (loop_vinfo->scalar_cond_masked_set.contains ({ op1, vec_num }))
6811 : : {
6812 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
6813 : : vec_num, vectype, i);
6814 : :
6815 : 0 : vop1 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
6816 : : vop1, gsi);
6817 : : }
6818 : : }
6819 : :
6820 : 134281 : new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1, vop2);
6821 : 134281 : new_temp = make_ssa_name (vec_dest, new_stmt);
6822 : 134281 : gimple_assign_set_lhs (new_stmt, new_temp);
6823 : 134281 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6824 : 134281 : if (using_emulated_vectors_p)
6825 : : suppress_warning (new_stmt, OPT_Wvector_operation_performance);
6826 : :
6827 : : /* Enter the combined value into the vector cond hash so we don't
6828 : : AND it with a loop mask again. */
6829 : 134281 : if (mask)
6830 : 0 : loop_vinfo->vec_cond_masked_set.add ({ new_temp, mask });
6831 : : }
6832 : :
6833 : 134299 : if (vec_cvt_dest)
6834 : : {
6835 : 2731 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype_out, new_temp);
6836 : 2731 : new_stmt = gimple_build_assign (vec_cvt_dest, VIEW_CONVERT_EXPR,
6837 : : new_temp);
6838 : 2731 : new_temp = make_ssa_name (vec_cvt_dest, new_stmt);
6839 : 2731 : gimple_assign_set_lhs (new_stmt, new_temp);
6840 : 2731 : vect_finish_stmt_generation (vinfo, stmt_info,
6841 : : new_stmt, gsi);
6842 : : }
6843 : :
6844 : 134299 : slp_node->push_vec_def (new_stmt);
6845 : : }
6846 : :
6847 : 108708 : vec_oprnds0.release ();
6848 : 108708 : vec_oprnds1.release ();
6849 : 108708 : vec_oprnds2.release ();
6850 : :
6851 : 108708 : return true;
6852 : : }
6853 : :
6854 : : /* A helper function to ensure data reference DR_INFO's base alignment. */
6855 : :
6856 : : static void
6857 : 1861407 : ensure_base_align (dr_vec_info *dr_info)
6858 : : {
6859 : : /* Alignment is only analyzed for the first element of a DR group,
6860 : : use that to look at base alignment we need to enforce. */
6861 : 1861407 : if (STMT_VINFO_GROUPED_ACCESS (dr_info->stmt))
6862 : 1435168 : dr_info = STMT_VINFO_DR_INFO (DR_GROUP_FIRST_ELEMENT (dr_info->stmt));
6863 : :
6864 : 1861407 : gcc_assert (dr_info->misalignment != DR_MISALIGNMENT_UNINITIALIZED);
6865 : :
6866 : 1861407 : if (dr_info->base_misaligned)
6867 : : {
6868 : 169148 : tree base_decl = dr_info->base_decl;
6869 : :
6870 : : // We should only be able to increase the alignment of a base object if
6871 : : // we know what its new alignment should be at compile time.
6872 : 169148 : unsigned HOST_WIDE_INT align_base_to =
6873 : 169148 : DR_TARGET_ALIGNMENT (dr_info).to_constant () * BITS_PER_UNIT;
6874 : :
6875 : 169148 : if (decl_in_symtab_p (base_decl))
6876 : 4651 : symtab_node::get (base_decl)->increase_alignment (align_base_to);
6877 : 164497 : else if (DECL_ALIGN (base_decl) < align_base_to)
6878 : : {
6879 : 131800 : SET_DECL_ALIGN (base_decl, align_base_to);
6880 : 131800 : DECL_USER_ALIGN (base_decl) = 1;
6881 : : }
6882 : 169148 : dr_info->base_misaligned = false;
6883 : : }
6884 : 1861407 : }
6885 : :
6886 : :
6887 : : /* Function get_group_alias_ptr_type.
6888 : :
6889 : : Return the alias type for the group starting at FIRST_STMT_INFO. */
6890 : :
6891 : : static tree
6892 : 1585946 : get_group_alias_ptr_type (stmt_vec_info first_stmt_info)
6893 : : {
6894 : 1585946 : struct data_reference *first_dr, *next_dr;
6895 : :
6896 : 1585946 : first_dr = STMT_VINFO_DATA_REF (first_stmt_info);
6897 : 1585946 : stmt_vec_info next_stmt_info = DR_GROUP_NEXT_ELEMENT (first_stmt_info);
6898 : 3843852 : while (next_stmt_info)
6899 : : {
6900 : 2415118 : next_dr = STMT_VINFO_DATA_REF (next_stmt_info);
6901 : 4830236 : if (get_alias_set (DR_REF (first_dr))
6902 : 2415118 : != get_alias_set (DR_REF (next_dr)))
6903 : : {
6904 : 157212 : if (dump_enabled_p ())
6905 : 36 : dump_printf_loc (MSG_NOTE, vect_location,
6906 : : "conflicting alias set types.\n");
6907 : 157212 : return ptr_type_node;
6908 : : }
6909 : 2257906 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
6910 : : }
6911 : 1428734 : return reference_alias_ptr_type (DR_REF (first_dr));
6912 : : }
6913 : :
6914 : :
6915 : : /* Function scan_operand_equal_p.
6916 : :
6917 : : Helper function for check_scan_store. Compare two references
6918 : : with .GOMP_SIMD_LANE bases. */
6919 : :
6920 : : static bool
6921 : 1284 : scan_operand_equal_p (tree ref1, tree ref2)
6922 : : {
6923 : 1284 : tree ref[2] = { ref1, ref2 };
6924 : 1284 : poly_int64 bitsize[2], bitpos[2];
6925 : : tree offset[2], base[2];
6926 : 3852 : for (int i = 0; i < 2; ++i)
6927 : : {
6928 : 2568 : machine_mode mode;
6929 : 2568 : int unsignedp, reversep, volatilep = 0;
6930 : 2568 : base[i] = get_inner_reference (ref[i], &bitsize[i], &bitpos[i],
6931 : : &offset[i], &mode, &unsignedp,
6932 : : &reversep, &volatilep);
6933 : 2568 : if (reversep || volatilep || maybe_ne (bitpos[i], 0))
6934 : 0 : return false;
6935 : 2568 : if (TREE_CODE (base[i]) == MEM_REF
6936 : 42 : && offset[i] == NULL_TREE
6937 : 2610 : && TREE_CODE (TREE_OPERAND (base[i], 0)) == SSA_NAME)
6938 : : {
6939 : 42 : gimple *def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (base[i], 0));
6940 : 42 : if (is_gimple_assign (def_stmt)
6941 : 42 : && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR
6942 : 42 : && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == ADDR_EXPR
6943 : 84 : && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME)
6944 : : {
6945 : 42 : if (maybe_ne (mem_ref_offset (base[i]), 0))
6946 : : return false;
6947 : 42 : base[i] = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0);
6948 : 42 : offset[i] = gimple_assign_rhs2 (def_stmt);
6949 : : }
6950 : : }
6951 : : }
6952 : :
6953 : 1284 : if (!operand_equal_p (base[0], base[1], 0))
6954 : : return false;
6955 : 934 : if (maybe_ne (bitsize[0], bitsize[1]))
6956 : : return false;
6957 : 934 : if (offset[0] != offset[1])
6958 : : {
6959 : 916 : if (!offset[0] || !offset[1])
6960 : : return false;
6961 : 916 : if (!operand_equal_p (offset[0], offset[1], 0))
6962 : : {
6963 : : tree step[2];
6964 : 0 : for (int i = 0; i < 2; ++i)
6965 : : {
6966 : 0 : step[i] = integer_one_node;
6967 : 0 : if (TREE_CODE (offset[i]) == SSA_NAME)
6968 : : {
6969 : 0 : gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]);
6970 : 0 : if (is_gimple_assign (def_stmt)
6971 : 0 : && gimple_assign_rhs_code (def_stmt) == MULT_EXPR
6972 : 0 : && (TREE_CODE (gimple_assign_rhs2 (def_stmt))
6973 : : == INTEGER_CST))
6974 : : {
6975 : 0 : step[i] = gimple_assign_rhs2 (def_stmt);
6976 : 0 : offset[i] = gimple_assign_rhs1 (def_stmt);
6977 : : }
6978 : : }
6979 : 0 : else if (TREE_CODE (offset[i]) == MULT_EXPR)
6980 : : {
6981 : 0 : step[i] = TREE_OPERAND (offset[i], 1);
6982 : 0 : offset[i] = TREE_OPERAND (offset[i], 0);
6983 : : }
6984 : 0 : tree rhs1 = NULL_TREE;
6985 : 0 : if (TREE_CODE (offset[i]) == SSA_NAME)
6986 : : {
6987 : 0 : gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]);
6988 : 0 : if (gimple_assign_cast_p (def_stmt))
6989 : 0 : rhs1 = gimple_assign_rhs1 (def_stmt);
6990 : : }
6991 : 0 : else if (CONVERT_EXPR_P (offset[i]))
6992 : 0 : rhs1 = TREE_OPERAND (offset[i], 0);
6993 : 0 : if (rhs1
6994 : 0 : && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
6995 : 0 : && INTEGRAL_TYPE_P (TREE_TYPE (offset[i]))
6996 : 0 : && (TYPE_PRECISION (TREE_TYPE (offset[i]))
6997 : 0 : >= TYPE_PRECISION (TREE_TYPE (rhs1))))
6998 : 0 : offset[i] = rhs1;
6999 : : }
7000 : 0 : if (!operand_equal_p (offset[0], offset[1], 0)
7001 : 0 : || !operand_equal_p (step[0], step[1], 0))
7002 : 0 : return false;
7003 : : }
7004 : : }
7005 : : return true;
7006 : : }
7007 : :
7008 : :
7009 : : enum scan_store_kind {
7010 : : /* Normal permutation. */
7011 : : scan_store_kind_perm,
7012 : :
7013 : : /* Whole vector left shift permutation with zero init. */
7014 : : scan_store_kind_lshift_zero,
7015 : :
7016 : : /* Whole vector left shift permutation and VEC_COND_EXPR. */
7017 : : scan_store_kind_lshift_cond
7018 : : };
7019 : :
7020 : : /* Function check_scan_store.
7021 : :
7022 : : Verify if we can perform the needed permutations or whole vector shifts.
7023 : : Return -1 on failure, otherwise exact log2 of vectype's nunits.
7024 : : USE_WHOLE_VECTOR is a vector of enum scan_store_kind which operation
7025 : : to do at each step. */
7026 : :
7027 : : static int
7028 : 1024 : scan_store_can_perm_p (tree vectype, tree init,
7029 : : vec<enum scan_store_kind> *use_whole_vector = NULL)
7030 : : {
7031 : 1024 : enum machine_mode vec_mode = TYPE_MODE (vectype);
7032 : 1024 : unsigned HOST_WIDE_INT nunits;
7033 : 1024 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits))
7034 : : return -1;
7035 : 1024 : int units_log2 = exact_log2 (nunits);
7036 : 1024 : if (units_log2 <= 0)
7037 : : return -1;
7038 : :
7039 : : int i;
7040 : : enum scan_store_kind whole_vector_shift_kind = scan_store_kind_perm;
7041 : 4784 : for (i = 0; i <= units_log2; ++i)
7042 : : {
7043 : 3760 : unsigned HOST_WIDE_INT j, k;
7044 : 3760 : enum scan_store_kind kind = scan_store_kind_perm;
7045 : 3760 : vec_perm_builder sel (nunits, nunits, 1);
7046 : 3760 : sel.quick_grow (nunits);
7047 : 3760 : if (i == units_log2)
7048 : : {
7049 : 9728 : for (j = 0; j < nunits; ++j)
7050 : 8704 : sel[j] = nunits - 1;
7051 : : }
7052 : : else
7053 : : {
7054 : 10416 : for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j)
7055 : 7680 : sel[j] = j;
7056 : 26416 : for (k = 0; j < nunits; ++j, ++k)
7057 : 23680 : sel[j] = nunits + k;
7058 : : }
7059 : 6496 : vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits);
7060 : 3760 : if (!can_vec_perm_const_p (vec_mode, vec_mode, indices))
7061 : : {
7062 : 0 : if (i == units_log2)
7063 : : return -1;
7064 : :
7065 : 0 : if (whole_vector_shift_kind == scan_store_kind_perm)
7066 : : {
7067 : 0 : if (!can_implement_p (vec_shl_optab, vec_mode))
7068 : : return -1;
7069 : 0 : whole_vector_shift_kind = scan_store_kind_lshift_zero;
7070 : : /* Whole vector shifts shift in zeros, so if init is all zero
7071 : : constant, there is no need to do anything further. */
7072 : 0 : if ((TREE_CODE (init) != INTEGER_CST
7073 : 0 : && TREE_CODE (init) != REAL_CST)
7074 : 0 : || !initializer_zerop (init))
7075 : : {
7076 : 0 : tree masktype = truth_type_for (vectype);
7077 : 0 : if (!expand_vec_cond_expr_p (vectype, masktype))
7078 : : return -1;
7079 : : whole_vector_shift_kind = scan_store_kind_lshift_cond;
7080 : : }
7081 : : }
7082 : 0 : kind = whole_vector_shift_kind;
7083 : : }
7084 : 3760 : if (use_whole_vector)
7085 : : {
7086 : 1880 : if (kind != scan_store_kind_perm && use_whole_vector->is_empty ())
7087 : 0 : use_whole_vector->safe_grow_cleared (i, true);
7088 : 5640 : if (kind != scan_store_kind_perm || !use_whole_vector->is_empty ())
7089 : 0 : use_whole_vector->safe_push (kind);
7090 : : }
7091 : 3760 : }
7092 : :
7093 : : return units_log2;
7094 : : }
7095 : :
7096 : :
7097 : : /* Function check_scan_store.
7098 : :
7099 : : Check magic stores for #pragma omp scan {in,ex}clusive reductions. */
7100 : :
7101 : : static bool
7102 : 1076 : check_scan_store (vec_info *vinfo, stmt_vec_info stmt_info, tree vectype,
7103 : : enum vect_def_type rhs_dt, slp_tree slp_node,
7104 : : slp_tree mask_node,
7105 : : vect_memory_access_type memory_access_type)
7106 : : {
7107 : 1076 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
7108 : 1076 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
7109 : 1076 : tree ref_type;
7110 : :
7111 : 1076 : gcc_assert (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1);
7112 : 1076 : if (SLP_TREE_LANES (slp_node) > 1
7113 : 1076 : || mask_node
7114 : 1076 : || memory_access_type != VMAT_CONTIGUOUS
7115 : 1076 : || TREE_CODE (DR_BASE_ADDRESS (dr_info->dr)) != ADDR_EXPR
7116 : 1076 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0))
7117 : 1076 : || loop_vinfo == NULL
7118 : 1076 : || LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
7119 : 1076 : || LOOP_VINFO_EPILOGUE_P (loop_vinfo)
7120 : 1076 : || STMT_VINFO_GROUPED_ACCESS (stmt_info)
7121 : 1076 : || !integer_zerop (get_dr_vinfo_offset (vinfo, dr_info))
7122 : 1076 : || !integer_zerop (DR_INIT (dr_info->dr))
7123 : 1076 : || !(ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr)))
7124 : 2152 : || !alias_sets_conflict_p (get_alias_set (vectype),
7125 : 1076 : get_alias_set (TREE_TYPE (ref_type))))
7126 : : {
7127 : 0 : if (dump_enabled_p ())
7128 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7129 : : "unsupported OpenMP scan store.\n");
7130 : 0 : return false;
7131 : : }
7132 : :
7133 : : /* We need to pattern match code built by OpenMP lowering and simplified
7134 : : by following optimizations into something we can handle.
7135 : : #pragma omp simd reduction(inscan,+:r)
7136 : : for (...)
7137 : : {
7138 : : r += something ();
7139 : : #pragma omp scan inclusive (r)
7140 : : use (r);
7141 : : }
7142 : : shall have body with:
7143 : : // Initialization for input phase, store the reduction initializer:
7144 : : _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0);
7145 : : _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1);
7146 : : D.2042[_21] = 0;
7147 : : // Actual input phase:
7148 : : ...
7149 : : r.0_5 = D.2042[_20];
7150 : : _6 = _4 + r.0_5;
7151 : : D.2042[_20] = _6;
7152 : : // Initialization for scan phase:
7153 : : _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 2);
7154 : : _26 = D.2043[_25];
7155 : : _27 = D.2042[_25];
7156 : : _28 = _26 + _27;
7157 : : D.2043[_25] = _28;
7158 : : D.2042[_25] = _28;
7159 : : // Actual scan phase:
7160 : : ...
7161 : : r.1_8 = D.2042[_20];
7162 : : ...
7163 : : The "omp simd array" variable D.2042 holds the privatized copy used
7164 : : inside of the loop and D.2043 is another one that holds copies of
7165 : : the current original list item. The separate GOMP_SIMD_LANE ifn
7166 : : kinds are there in order to allow optimizing the initializer store
7167 : : and combiner sequence, e.g. if it is originally some C++ish user
7168 : : defined reduction, but allow the vectorizer to pattern recognize it
7169 : : and turn into the appropriate vectorized scan.
7170 : :
7171 : : For exclusive scan, this is slightly different:
7172 : : #pragma omp simd reduction(inscan,+:r)
7173 : : for (...)
7174 : : {
7175 : : use (r);
7176 : : #pragma omp scan exclusive (r)
7177 : : r += something ();
7178 : : }
7179 : : shall have body with:
7180 : : // Initialization for input phase, store the reduction initializer:
7181 : : _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0);
7182 : : _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1);
7183 : : D.2042[_21] = 0;
7184 : : // Actual input phase:
7185 : : ...
7186 : : r.0_5 = D.2042[_20];
7187 : : _6 = _4 + r.0_5;
7188 : : D.2042[_20] = _6;
7189 : : // Initialization for scan phase:
7190 : : _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 3);
7191 : : _26 = D.2043[_25];
7192 : : D.2044[_25] = _26;
7193 : : _27 = D.2042[_25];
7194 : : _28 = _26 + _27;
7195 : : D.2043[_25] = _28;
7196 : : // Actual scan phase:
7197 : : ...
7198 : : r.1_8 = D.2044[_20];
7199 : : ... */
7200 : :
7201 : 1076 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 2)
7202 : : {
7203 : : /* Match the D.2042[_21] = 0; store above. Just require that
7204 : : it is a constant or external definition store. */
7205 : 564 : if (rhs_dt != vect_constant_def && rhs_dt != vect_external_def)
7206 : : {
7207 : 0 : fail_init:
7208 : 0 : if (dump_enabled_p ())
7209 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7210 : : "unsupported OpenMP scan initializer store.\n");
7211 : 0 : return false;
7212 : : }
7213 : :
7214 : 564 : if (! loop_vinfo->scan_map)
7215 : 322 : loop_vinfo->scan_map = new hash_map<tree, tree>;
7216 : 564 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7217 : 564 : tree &cached = loop_vinfo->scan_map->get_or_insert (var);
7218 : 564 : if (cached)
7219 : 0 : goto fail_init;
7220 : 564 : cached = gimple_assign_rhs1 (STMT_VINFO_STMT (stmt_info));
7221 : :
7222 : : /* These stores can be vectorized normally. */
7223 : 564 : return true;
7224 : : }
7225 : :
7226 : 512 : if (rhs_dt != vect_internal_def)
7227 : : {
7228 : 0 : fail:
7229 : 0 : if (dump_enabled_p ())
7230 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7231 : : "unsupported OpenMP scan combiner pattern.\n");
7232 : 0 : return false;
7233 : : }
7234 : :
7235 : 512 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
7236 : 512 : tree rhs = gimple_assign_rhs1 (stmt);
7237 : 512 : if (TREE_CODE (rhs) != SSA_NAME)
7238 : 0 : goto fail;
7239 : :
7240 : 512 : gimple *other_store_stmt = NULL;
7241 : 512 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7242 : 512 : bool inscan_var_store
7243 : 512 : = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL;
7244 : :
7245 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7246 : : {
7247 : 252 : if (!inscan_var_store)
7248 : : {
7249 : 126 : use_operand_p use_p;
7250 : 126 : imm_use_iterator iter;
7251 : 378 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7252 : : {
7253 : 252 : gimple *use_stmt = USE_STMT (use_p);
7254 : 252 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7255 : 126 : continue;
7256 : 126 : if (gimple_bb (use_stmt) != gimple_bb (stmt)
7257 : 126 : || !is_gimple_assign (use_stmt)
7258 : 126 : || gimple_assign_rhs_class (use_stmt) != GIMPLE_BINARY_RHS
7259 : 126 : || other_store_stmt
7260 : 252 : || TREE_CODE (gimple_assign_lhs (use_stmt)) != SSA_NAME)
7261 : 0 : goto fail;
7262 : 126 : other_store_stmt = use_stmt;
7263 : : }
7264 : 126 : if (other_store_stmt == NULL)
7265 : 0 : goto fail;
7266 : 126 : rhs = gimple_assign_lhs (other_store_stmt);
7267 : 126 : if (!single_imm_use (rhs, &use_p, &other_store_stmt))
7268 : 0 : goto fail;
7269 : : }
7270 : : }
7271 : 260 : else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3)
7272 : : {
7273 : 260 : use_operand_p use_p;
7274 : 260 : imm_use_iterator iter;
7275 : 780 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7276 : : {
7277 : 520 : gimple *use_stmt = USE_STMT (use_p);
7278 : 520 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7279 : 260 : continue;
7280 : 260 : if (other_store_stmt)
7281 : 0 : goto fail;
7282 : 260 : other_store_stmt = use_stmt;
7283 : : }
7284 : : }
7285 : : else
7286 : 0 : goto fail;
7287 : :
7288 : 512 : gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
7289 : 512 : if (gimple_bb (def_stmt) != gimple_bb (stmt)
7290 : 512 : || !is_gimple_assign (def_stmt)
7291 : 1024 : || gimple_assign_rhs_class (def_stmt) != GIMPLE_BINARY_RHS)
7292 : 0 : goto fail;
7293 : :
7294 : 512 : enum tree_code code = gimple_assign_rhs_code (def_stmt);
7295 : : /* For pointer addition, we should use the normal plus for the vector
7296 : : operation. */
7297 : 512 : switch (code)
7298 : : {
7299 : 0 : case POINTER_PLUS_EXPR:
7300 : 0 : code = PLUS_EXPR;
7301 : 0 : break;
7302 : 0 : case MULT_HIGHPART_EXPR:
7303 : 0 : goto fail;
7304 : : default:
7305 : : break;
7306 : : }
7307 : 512 : if (TREE_CODE_LENGTH (code) != binary_op || !commutative_tree_code (code))
7308 : 0 : goto fail;
7309 : :
7310 : 512 : tree rhs1 = gimple_assign_rhs1 (def_stmt);
7311 : 512 : tree rhs2 = gimple_assign_rhs2 (def_stmt);
7312 : 512 : if (TREE_CODE (rhs1) != SSA_NAME || TREE_CODE (rhs2) != SSA_NAME)
7313 : 0 : goto fail;
7314 : :
7315 : 512 : gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1);
7316 : 512 : gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2);
7317 : 512 : if (gimple_bb (load1_stmt) != gimple_bb (stmt)
7318 : 512 : || !gimple_assign_load_p (load1_stmt)
7319 : 512 : || gimple_bb (load2_stmt) != gimple_bb (stmt)
7320 : 1024 : || !gimple_assign_load_p (load2_stmt))
7321 : 0 : goto fail;
7322 : :
7323 : 512 : stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt);
7324 : 512 : stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt);
7325 : 512 : if (load1_stmt_info == NULL
7326 : 512 : || load2_stmt_info == NULL
7327 : 512 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (load1_stmt_info)
7328 : 512 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info))
7329 : 512 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (load2_stmt_info)
7330 : 512 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)))
7331 : 0 : goto fail;
7332 : :
7333 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && inscan_var_store)
7334 : : {
7335 : 126 : dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info);
7336 : 126 : if (TREE_CODE (DR_BASE_ADDRESS (load1_dr_info->dr)) != ADDR_EXPR
7337 : 126 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0)))
7338 : 0 : goto fail;
7339 : 126 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0);
7340 : 126 : tree lrhs;
7341 : 126 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7342 : : lrhs = rhs1;
7343 : : else
7344 : 16 : lrhs = rhs2;
7345 : 126 : use_operand_p use_p;
7346 : 126 : imm_use_iterator iter;
7347 : 378 : FOR_EACH_IMM_USE_FAST (use_p, iter, lrhs)
7348 : : {
7349 : 252 : gimple *use_stmt = USE_STMT (use_p);
7350 : 252 : if (use_stmt == def_stmt || is_gimple_debug (use_stmt))
7351 : 126 : continue;
7352 : 126 : if (other_store_stmt)
7353 : 0 : goto fail;
7354 : 126 : other_store_stmt = use_stmt;
7355 : : }
7356 : : }
7357 : :
7358 : 512 : if (other_store_stmt == NULL)
7359 : 0 : goto fail;
7360 : 512 : if (gimple_bb (other_store_stmt) != gimple_bb (stmt)
7361 : 512 : || !gimple_store_p (other_store_stmt))
7362 : 0 : goto fail;
7363 : :
7364 : 512 : stmt_vec_info other_store_stmt_info
7365 : 512 : = loop_vinfo->lookup_stmt (other_store_stmt);
7366 : 512 : if (other_store_stmt_info == NULL
7367 : 512 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (other_store_stmt_info)
7368 : 512 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)))
7369 : 0 : goto fail;
7370 : :
7371 : 512 : gimple *stmt1 = stmt;
7372 : 512 : gimple *stmt2 = other_store_stmt;
7373 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7374 : : std::swap (stmt1, stmt2);
7375 : 512 : if (scan_operand_equal_p (gimple_assign_lhs (stmt1),
7376 : : gimple_assign_rhs1 (load2_stmt)))
7377 : : {
7378 : 162 : std::swap (rhs1, rhs2);
7379 : 162 : std::swap (load1_stmt, load2_stmt);
7380 : 162 : std::swap (load1_stmt_info, load2_stmt_info);
7381 : : }
7382 : 512 : if (!scan_operand_equal_p (gimple_assign_lhs (stmt1),
7383 : : gimple_assign_rhs1 (load1_stmt)))
7384 : 0 : goto fail;
7385 : :
7386 : 512 : tree var3 = NULL_TREE;
7387 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3
7388 : 512 : && !scan_operand_equal_p (gimple_assign_lhs (stmt2),
7389 : : gimple_assign_rhs1 (load2_stmt)))
7390 : 0 : goto fail;
7391 : 512 : else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7392 : : {
7393 : 252 : dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info);
7394 : 252 : if (TREE_CODE (DR_BASE_ADDRESS (load2_dr_info->dr)) != ADDR_EXPR
7395 : 252 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0)))
7396 : 0 : goto fail;
7397 : 252 : var3 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0);
7398 : 252 : if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var3))
7399 : 252 : || lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var3))
7400 : 504 : || lookup_attribute ("omp simd inscan exclusive",
7401 : 252 : DECL_ATTRIBUTES (var3)))
7402 : 0 : goto fail;
7403 : : }
7404 : :
7405 : 512 : dr_vec_info *other_dr_info = STMT_VINFO_DR_INFO (other_store_stmt_info);
7406 : 512 : if (TREE_CODE (DR_BASE_ADDRESS (other_dr_info->dr)) != ADDR_EXPR
7407 : 512 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0)))
7408 : 0 : goto fail;
7409 : :
7410 : 512 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7411 : 512 : tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0);
7412 : 512 : if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var1))
7413 : 512 : || !lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var2))
7414 : 1024 : || (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7415 : 512 : == (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var2))))
7416 : 0 : goto fail;
7417 : :
7418 : 512 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7419 : 256 : std::swap (var1, var2);
7420 : :
7421 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7422 : : {
7423 : 252 : if (!lookup_attribute ("omp simd inscan exclusive",
7424 : 252 : DECL_ATTRIBUTES (var1)))
7425 : 0 : goto fail;
7426 : 252 : var1 = var3;
7427 : : }
7428 : :
7429 : 512 : if (loop_vinfo->scan_map == NULL)
7430 : 0 : goto fail;
7431 : 512 : tree *init = loop_vinfo->scan_map->get (var1);
7432 : 512 : if (init == NULL)
7433 : 0 : goto fail;
7434 : :
7435 : : /* The IL is as expected, now check if we can actually vectorize it.
7436 : : Inclusive scan:
7437 : : _26 = D.2043[_25];
7438 : : _27 = D.2042[_25];
7439 : : _28 = _26 + _27;
7440 : : D.2043[_25] = _28;
7441 : : D.2042[_25] = _28;
7442 : : should be vectorized as (where _40 is the vectorized rhs
7443 : : from the D.2042[_21] = 0; store):
7444 : : _30 = MEM <vector(8) int> [(int *)&D.2043];
7445 : : _31 = MEM <vector(8) int> [(int *)&D.2042];
7446 : : _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
7447 : : _33 = _31 + _32;
7448 : : // _33 = { _31[0], _31[0]+_31[1], _31[1]+_31[2], ..., _31[6]+_31[7] };
7449 : : _34 = VEC_PERM_EXPR <_40, _33, { 0, 1, 8, 9, 10, 11, 12, 13 }>;
7450 : : _35 = _33 + _34;
7451 : : // _35 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7452 : : // _31[1]+.._31[4], ... _31[4]+.._31[7] };
7453 : : _36 = VEC_PERM_EXPR <_40, _35, { 0, 1, 2, 3, 8, 9, 10, 11 }>;
7454 : : _37 = _35 + _36;
7455 : : // _37 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7456 : : // _31[0]+.._31[4], ... _31[0]+.._31[7] };
7457 : : _38 = _30 + _37;
7458 : : _39 = VEC_PERM_EXPR <_38, _38, { 7, 7, 7, 7, 7, 7, 7, 7 }>;
7459 : : MEM <vector(8) int> [(int *)&D.2043] = _39;
7460 : : MEM <vector(8) int> [(int *)&D.2042] = _38;
7461 : : Exclusive scan:
7462 : : _26 = D.2043[_25];
7463 : : D.2044[_25] = _26;
7464 : : _27 = D.2042[_25];
7465 : : _28 = _26 + _27;
7466 : : D.2043[_25] = _28;
7467 : : should be vectorized as (where _40 is the vectorized rhs
7468 : : from the D.2042[_21] = 0; store):
7469 : : _30 = MEM <vector(8) int> [(int *)&D.2043];
7470 : : _31 = MEM <vector(8) int> [(int *)&D.2042];
7471 : : _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
7472 : : _33 = VEC_PERM_EXPR <_40, _32, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
7473 : : _34 = _32 + _33;
7474 : : // _34 = { 0, _31[0], _31[0]+_31[1], _31[1]+_31[2], _31[2]+_31[3],
7475 : : // _31[3]+_31[4], ... _31[5]+.._31[6] };
7476 : : _35 = VEC_PERM_EXPR <_40, _34, { 0, 1, 8, 9, 10, 11, 12, 13 }>;
7477 : : _36 = _34 + _35;
7478 : : // _36 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7479 : : // _31[1]+.._31[4], ... _31[3]+.._31[6] };
7480 : : _37 = VEC_PERM_EXPR <_40, _36, { 0, 1, 2, 3, 8, 9, 10, 11 }>;
7481 : : _38 = _36 + _37;
7482 : : // _38 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7483 : : // _31[0]+.._31[4], ... _31[0]+.._31[6] };
7484 : : _39 = _30 + _38;
7485 : : _50 = _31 + _39;
7486 : : _51 = VEC_PERM_EXPR <_50, _50, { 7, 7, 7, 7, 7, 7, 7, 7 }>;
7487 : : MEM <vector(8) int> [(int *)&D.2044] = _39;
7488 : : MEM <vector(8) int> [(int *)&D.2042] = _51; */
7489 : 512 : enum machine_mode vec_mode = TYPE_MODE (vectype);
7490 : 512 : optab optab = optab_for_tree_code (code, vectype, optab_default);
7491 : 512 : if (!optab || !can_implement_p (optab, vec_mode))
7492 : 0 : goto fail;
7493 : :
7494 : 512 : int units_log2 = scan_store_can_perm_p (vectype, *init);
7495 : 512 : if (units_log2 == -1)
7496 : 0 : goto fail;
7497 : :
7498 : : return true;
7499 : : }
7500 : :
7501 : :
7502 : : /* Function vectorizable_scan_store.
7503 : :
7504 : : Helper of vectorizable_score, arguments like on vectorizable_store.
7505 : : Handle only the transformation, checking is done in check_scan_store. */
7506 : :
7507 : : static bool
7508 : 512 : vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
7509 : : slp_tree slp_node, gimple_stmt_iterator *gsi)
7510 : : {
7511 : 512 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
7512 : 512 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
7513 : 512 : tree ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr));
7514 : 512 : tree vectype = SLP_TREE_VECTYPE (slp_node);
7515 : :
7516 : 512 : if (dump_enabled_p ())
7517 : 492 : dump_printf_loc (MSG_NOTE, vect_location,
7518 : : "transform scan store.\n");
7519 : :
7520 : 512 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
7521 : 512 : tree rhs = gimple_assign_rhs1 (stmt);
7522 : 512 : gcc_assert (TREE_CODE (rhs) == SSA_NAME);
7523 : :
7524 : 512 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7525 : 512 : bool inscan_var_store
7526 : 512 : = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL;
7527 : :
7528 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7529 : : {
7530 : 126 : use_operand_p use_p;
7531 : 126 : imm_use_iterator iter;
7532 : 126 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7533 : : {
7534 : 126 : gimple *use_stmt = USE_STMT (use_p);
7535 : 126 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7536 : 0 : continue;
7537 : 126 : rhs = gimple_assign_lhs (use_stmt);
7538 : 126 : break;
7539 : : }
7540 : : }
7541 : :
7542 : 512 : gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
7543 : 512 : enum tree_code code = gimple_assign_rhs_code (def_stmt);
7544 : 512 : if (code == POINTER_PLUS_EXPR)
7545 : 0 : code = PLUS_EXPR;
7546 : 512 : gcc_assert (TREE_CODE_LENGTH (code) == binary_op
7547 : : && commutative_tree_code (code));
7548 : 512 : tree rhs1 = gimple_assign_rhs1 (def_stmt);
7549 : 512 : tree rhs2 = gimple_assign_rhs2 (def_stmt);
7550 : 512 : gcc_assert (TREE_CODE (rhs1) == SSA_NAME && TREE_CODE (rhs2) == SSA_NAME);
7551 : 512 : gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1);
7552 : 512 : gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2);
7553 : 512 : stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt);
7554 : 512 : stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt);
7555 : 512 : dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info);
7556 : 512 : dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info);
7557 : 512 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0);
7558 : 512 : tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0);
7559 : :
7560 : 512 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7561 : : {
7562 : 436 : std::swap (rhs1, rhs2);
7563 : 436 : std::swap (var1, var2);
7564 : 436 : std::swap (load1_dr_info, load2_dr_info);
7565 : : }
7566 : :
7567 : 512 : tree *init = loop_vinfo->scan_map->get (var1);
7568 : 512 : gcc_assert (init);
7569 : :
7570 : 512 : unsigned HOST_WIDE_INT nunits;
7571 : 512 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits))
7572 : : gcc_unreachable ();
7573 : 512 : auto_vec<enum scan_store_kind, 16> use_whole_vector;
7574 : 512 : int units_log2 = scan_store_can_perm_p (vectype, *init, &use_whole_vector);
7575 : 512 : gcc_assert (units_log2 > 0);
7576 : 512 : auto_vec<tree, 16> perms;
7577 : 512 : perms.quick_grow (units_log2 + 1);
7578 : 512 : tree zero_vec = NULL_TREE, masktype = NULL_TREE;
7579 : 2392 : for (int i = 0; i <= units_log2; ++i)
7580 : : {
7581 : 1880 : unsigned HOST_WIDE_INT j, k;
7582 : 1880 : vec_perm_builder sel (nunits, nunits, 1);
7583 : 1880 : sel.quick_grow (nunits);
7584 : 1880 : if (i == units_log2)
7585 : 4864 : for (j = 0; j < nunits; ++j)
7586 : 4352 : sel[j] = nunits - 1;
7587 : : else
7588 : : {
7589 : 5208 : for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j)
7590 : 3840 : sel[j] = j;
7591 : 13208 : for (k = 0; j < nunits; ++j, ++k)
7592 : 11840 : sel[j] = nunits + k;
7593 : : }
7594 : 3248 : vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits);
7595 : 1880 : if (!use_whole_vector.is_empty ()
7596 : 0 : && use_whole_vector[i] != scan_store_kind_perm)
7597 : : {
7598 : 0 : if (zero_vec == NULL_TREE)
7599 : 0 : zero_vec = build_zero_cst (vectype);
7600 : 0 : if (masktype == NULL_TREE
7601 : 0 : && use_whole_vector[i] == scan_store_kind_lshift_cond)
7602 : 0 : masktype = truth_type_for (vectype);
7603 : 0 : perms[i] = vect_gen_perm_mask_any (vectype, indices);
7604 : : }
7605 : : else
7606 : 1880 : perms[i] = vect_gen_perm_mask_checked (vectype, indices);
7607 : 1880 : }
7608 : :
7609 : 512 : tree vec_oprnd1 = NULL_TREE;
7610 : 512 : tree vec_oprnd2 = NULL_TREE;
7611 : 512 : tree vec_oprnd3 = NULL_TREE;
7612 : 512 : tree dataref_ptr = DR_BASE_ADDRESS (dr_info->dr);
7613 : 512 : tree dataref_offset = build_int_cst (ref_type, 0);
7614 : 512 : tree bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info,
7615 : : vectype, VMAT_CONTIGUOUS);
7616 : 512 : tree ldataref_ptr = NULL_TREE;
7617 : 512 : tree orig = NULL_TREE;
7618 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7619 : 126 : ldataref_ptr = DR_BASE_ADDRESS (load1_dr_info->dr);
7620 : : /* The initialization is invariant. */
7621 : 512 : vec_oprnd1 = vect_init_vector (vinfo, stmt_info, *init, vectype, NULL);
7622 : 512 : auto_vec<tree> vec_oprnds2;
7623 : 512 : auto_vec<tree> vec_oprnds3;
7624 : 512 : if (ldataref_ptr == NULL)
7625 : : {
7626 : : /* We want to lookup the vector operands of the reduction, not those
7627 : : of the store - for SLP we have to use the proper SLP node for the
7628 : : lookup, which should be the single child of the scan store. */
7629 : 386 : vect_get_vec_defs (vinfo, SLP_TREE_CHILDREN (slp_node)[0],
7630 : : rhs1, &vec_oprnds2, rhs2, &vec_oprnds3);
7631 : : /* ??? For SLP we do not key the def on 'rhs1' or 'rhs2' but get
7632 : : them in SLP child order. So we have to swap here with logic
7633 : : similar to above. */
7634 : 386 : stmt_vec_info load
7635 : 386 : = SLP_TREE_SCALAR_STMTS (SLP_TREE_CHILDREN
7636 : 386 : (SLP_TREE_CHILDREN (slp_node)[0])[0])[0];
7637 : 386 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (load);
7638 : 386 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7639 : 386 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)))
7640 : 820 : for (unsigned i = 0; i < vec_oprnds2.length (); ++i)
7641 : 494 : std::swap (vec_oprnds2[i], vec_oprnds3[i]);;
7642 : : }
7643 : : else
7644 : 126 : vect_get_vec_defs (vinfo, slp_node,
7645 : : rhs2, &vec_oprnds3);
7646 : 1248 : for (unsigned j = 0; j < vec_oprnds3.length (); j++)
7647 : : {
7648 : 736 : if (ldataref_ptr == NULL)
7649 : 554 : vec_oprnd2 = vec_oprnds2[j];
7650 : 736 : vec_oprnd3 = vec_oprnds3[j];
7651 : 736 : if (j == 0)
7652 : : orig = vec_oprnd3;
7653 : 224 : else if (!inscan_var_store)
7654 : 112 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
7655 : :
7656 : 736 : if (ldataref_ptr)
7657 : : {
7658 : 182 : vec_oprnd2 = make_ssa_name (vectype);
7659 : 182 : tree data_ref = fold_build2 (MEM_REF, vectype,
7660 : : unshare_expr (ldataref_ptr),
7661 : : dataref_offset);
7662 : 182 : vect_copy_ref_info (data_ref, DR_REF (load1_dr_info->dr));
7663 : 182 : gimple *g = gimple_build_assign (vec_oprnd2, data_ref);
7664 : 182 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7665 : : }
7666 : :
7667 : 736 : tree v = vec_oprnd2;
7668 : 3068 : for (int i = 0; i < units_log2; ++i)
7669 : : {
7670 : 2332 : tree new_temp = make_ssa_name (vectype);
7671 : 2332 : gimple *g = gimple_build_assign (new_temp, VEC_PERM_EXPR,
7672 : : (zero_vec
7673 : 0 : && (use_whole_vector[i]
7674 : 0 : != scan_store_kind_perm))
7675 : : ? zero_vec : vec_oprnd1, v,
7676 : 2332 : perms[i]);
7677 : 2332 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7678 : :
7679 : 2332 : if (zero_vec && use_whole_vector[i] == scan_store_kind_lshift_cond)
7680 : : {
7681 : : /* Whole vector shift shifted in zero bits, but if *init
7682 : : is not initializer_zerop, we need to replace those elements
7683 : : with elements from vec_oprnd1. */
7684 : 0 : tree_vector_builder vb (masktype, nunits, 1);
7685 : 0 : for (unsigned HOST_WIDE_INT k = 0; k < nunits; ++k)
7686 : 0 : vb.quick_push (k < (HOST_WIDE_INT_1U << i)
7687 : : ? boolean_false_node : boolean_true_node);
7688 : :
7689 : 0 : tree new_temp2 = make_ssa_name (vectype);
7690 : 0 : g = gimple_build_assign (new_temp2, VEC_COND_EXPR, vb.build (),
7691 : : new_temp, vec_oprnd1);
7692 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
7693 : : g, gsi);
7694 : 0 : new_temp = new_temp2;
7695 : 0 : }
7696 : :
7697 : : /* For exclusive scan, perform the perms[i] permutation once
7698 : : more. */
7699 : 2332 : if (i == 0
7700 : 1100 : && STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4
7701 : 728 : && v == vec_oprnd2)
7702 : : {
7703 : 364 : v = new_temp;
7704 : 364 : --i;
7705 : 364 : continue;
7706 : : }
7707 : :
7708 : 1968 : tree new_temp2 = make_ssa_name (vectype);
7709 : 1968 : g = gimple_build_assign (new_temp2, code, v, new_temp);
7710 : 1968 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7711 : :
7712 : 1968 : v = new_temp2;
7713 : : }
7714 : :
7715 : 736 : tree new_temp = make_ssa_name (vectype);
7716 : 736 : gimple *g = gimple_build_assign (new_temp, code, orig, v);
7717 : 736 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7718 : :
7719 : 736 : tree last_perm_arg = new_temp;
7720 : : /* For exclusive scan, new_temp computed above is the exclusive scan
7721 : : prefix sum. Turn it into inclusive prefix sum for the broadcast
7722 : : of the last element into orig. */
7723 : 736 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7724 : : {
7725 : 364 : last_perm_arg = make_ssa_name (vectype);
7726 : 364 : g = gimple_build_assign (last_perm_arg, code, new_temp, vec_oprnd2);
7727 : 364 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7728 : : }
7729 : :
7730 : 736 : orig = make_ssa_name (vectype);
7731 : 2208 : g = gimple_build_assign (orig, VEC_PERM_EXPR, last_perm_arg,
7732 : 736 : last_perm_arg, perms[units_log2]);
7733 : 736 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7734 : :
7735 : 736 : if (!inscan_var_store)
7736 : : {
7737 : 368 : tree data_ref = fold_build2 (MEM_REF, vectype,
7738 : : unshare_expr (dataref_ptr),
7739 : : dataref_offset);
7740 : 368 : vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
7741 : 368 : g = gimple_build_assign (data_ref, new_temp);
7742 : 368 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7743 : : }
7744 : : }
7745 : :
7746 : 512 : if (inscan_var_store)
7747 : 624 : for (unsigned j = 0; j < vec_oprnds3.length (); j++)
7748 : : {
7749 : 368 : if (j != 0)
7750 : 112 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
7751 : :
7752 : 368 : tree data_ref = fold_build2 (MEM_REF, vectype,
7753 : : unshare_expr (dataref_ptr),
7754 : : dataref_offset);
7755 : 368 : vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
7756 : 368 : gimple *g = gimple_build_assign (data_ref, orig);
7757 : 368 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7758 : : }
7759 : 512 : return true;
7760 : 512 : }
7761 : :
7762 : :
7763 : : /* Function vectorizable_store.
7764 : :
7765 : : Check if STMT_INFO defines a non scalar data-ref (array/pointer/structure)
7766 : : that can be vectorized.
7767 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
7768 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
7769 : : Return true if STMT_INFO is vectorizable in this way. */
7770 : :
7771 : : static bool
7772 : 1944684 : vectorizable_store (vec_info *vinfo,
7773 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
7774 : : slp_tree slp_node,
7775 : : stmt_vector_for_cost *cost_vec)
7776 : : {
7777 : 1944684 : tree data_ref;
7778 : 1944684 : tree vec_oprnd = NULL_TREE;
7779 : 1944684 : tree elem_type;
7780 : 1944684 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
7781 : 1944684 : class loop *loop = NULL;
7782 : 1944684 : machine_mode vec_mode;
7783 : 1944684 : tree dummy;
7784 : 1944684 : enum vect_def_type rhs_dt = vect_unknown_def_type;
7785 : 1944684 : enum vect_def_type mask_dt = vect_unknown_def_type;
7786 : 1944684 : tree dataref_ptr = NULL_TREE;
7787 : 1944684 : tree dataref_offset = NULL_TREE;
7788 : 1944684 : gimple *ptr_incr = NULL;
7789 : 1944684 : int j;
7790 : 1944684 : stmt_vec_info first_stmt_info;
7791 : 1944684 : bool grouped_store;
7792 : 1944684 : unsigned int group_size, i;
7793 : 1944684 : unsigned int vec_num;
7794 : 1944684 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
7795 : 1944684 : tree aggr_type;
7796 : 1944684 : poly_uint64 vf;
7797 : 1944684 : vec_load_store_type vls_type;
7798 : 1944684 : tree ref_type;
7799 : :
7800 : 1944684 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
7801 : : return false;
7802 : :
7803 : 1944684 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
7804 : 180307 : && cost_vec)
7805 : : return false;
7806 : :
7807 : : /* Is vectorizable store? */
7808 : :
7809 : 1764377 : tree mask_vectype = NULL_TREE;
7810 : 1764377 : slp_tree mask_node = NULL;
7811 : 1764377 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
7812 : : {
7813 : 1692685 : tree scalar_dest = gimple_assign_lhs (assign);
7814 : 1692685 : if (TREE_CODE (scalar_dest) == VIEW_CONVERT_EXPR
7815 : 1692685 : && is_pattern_stmt_p (stmt_info))
7816 : 1021 : scalar_dest = TREE_OPERAND (scalar_dest, 0);
7817 : 1692685 : if (TREE_CODE (scalar_dest) != ARRAY_REF
7818 : 1692685 : && TREE_CODE (scalar_dest) != BIT_FIELD_REF
7819 : : && TREE_CODE (scalar_dest) != INDIRECT_REF
7820 : : && TREE_CODE (scalar_dest) != COMPONENT_REF
7821 : : && TREE_CODE (scalar_dest) != IMAGPART_EXPR
7822 : : && TREE_CODE (scalar_dest) != REALPART_EXPR
7823 : : && TREE_CODE (scalar_dest) != MEM_REF)
7824 : : return false;
7825 : : }
7826 : : else
7827 : : {
7828 : 629568 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
7829 : 8334 : if (!call || !gimple_call_internal_p (call))
7830 : : return false;
7831 : :
7832 : 4741 : internal_fn ifn = gimple_call_internal_fn (call);
7833 : 4741 : if (!internal_store_fn_p (ifn))
7834 : : return false;
7835 : :
7836 : 1417 : int mask_index = internal_fn_mask_index (ifn);
7837 : 1417 : if (mask_index >= 0)
7838 : 1417 : mask_index = vect_slp_child_index_for_operand
7839 : 1417 : (call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
7840 : 1417 : if (mask_index >= 0
7841 : 1417 : && !vect_check_scalar_mask (vinfo, slp_node, mask_index,
7842 : : &mask_node, &mask_dt,
7843 : : &mask_vectype))
7844 : : return false;
7845 : : }
7846 : :
7847 : 1323482 : tree vectype = SLP_TREE_VECTYPE (slp_node), rhs_vectype = NULL_TREE;
7848 : 1323482 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
7849 : :
7850 : 1323482 : if (loop_vinfo)
7851 : : {
7852 : 180518 : loop = LOOP_VINFO_LOOP (loop_vinfo);
7853 : 180518 : vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
7854 : : }
7855 : : else
7856 : : vf = 1;
7857 : 1323482 : vec_num = vect_get_num_copies (vinfo, slp_node);
7858 : :
7859 : : /* FORNOW. This restriction should be relaxed. */
7860 : 1323482 : if (loop
7861 : 1323719 : && nested_in_vect_loop_p (loop, stmt_info)
7862 : 1323727 : && vec_num > 1)
7863 : : {
7864 : 8 : if (dump_enabled_p ())
7865 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7866 : : "multiple types in nested loop.\n");
7867 : 8 : return false;
7868 : : }
7869 : :
7870 : 1323474 : slp_tree op_node;
7871 : 1323474 : if (!vect_check_store_rhs (vinfo, stmt_info, slp_node,
7872 : : &op_node, &rhs_dt, &rhs_vectype, &vls_type))
7873 : : return false;
7874 : :
7875 : 1323450 : elem_type = TREE_TYPE (vectype);
7876 : 1323450 : vec_mode = TYPE_MODE (vectype);
7877 : :
7878 : 1323450 : if (!STMT_VINFO_DATA_REF (stmt_info))
7879 : : return false;
7880 : :
7881 : 1323450 : vect_load_store_data _ls_data{};
7882 : 1323450 : vect_load_store_data &ls = slp_node->get_data (_ls_data);
7883 : 1323450 : if (cost_vec
7884 : 1323450 : && !get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask_node,
7885 : : vls_type, false, &_ls_data))
7886 : : return false;
7887 : : /* Temporary aliases to analysis data, should not be modified through
7888 : : these. */
7889 : 1322902 : const vect_memory_access_type memory_access_type = ls.memory_access_type;
7890 : 1322902 : const dr_alignment_support alignment_support_scheme
7891 : : = ls.alignment_support_scheme;
7892 : 1322902 : const int misalignment = ls.misalignment;
7893 : 1322902 : const poly_int64 poffset = ls.poffset;
7894 : :
7895 : 1322902 : if (slp_node->ldst_lanes
7896 : 0 : && memory_access_type != VMAT_LOAD_STORE_LANES)
7897 : : {
7898 : 0 : if (dump_enabled_p ())
7899 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7900 : : "discovered store-lane but cannot use it.\n");
7901 : 0 : return false;
7902 : : }
7903 : :
7904 : 1322902 : if (mask_node)
7905 : : {
7906 : 1327 : if (memory_access_type == VMAT_CONTIGUOUS)
7907 : : {
7908 : 453 : if (!VECTOR_MODE_P (vec_mode)
7909 : 2154 : || !can_vec_mask_load_store_p (vec_mode,
7910 : 1077 : TYPE_MODE (mask_vectype), false))
7911 : 16 : return false;
7912 : : }
7913 : 250 : else if (memory_access_type != VMAT_LOAD_STORE_LANES
7914 : 250 : && (!mat_gather_scatter_p (memory_access_type)
7915 : 222 : || (memory_access_type == VMAT_GATHER_SCATTER_LEGACY
7916 : 154 : && !VECTOR_BOOLEAN_TYPE_P (mask_vectype))))
7917 : : {
7918 : 28 : if (dump_enabled_p ())
7919 : 28 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7920 : : "unsupported access type for masked store.\n");
7921 : 28 : return false;
7922 : : }
7923 : 222 : else if (memory_access_type == VMAT_GATHER_SCATTER_EMULATED)
7924 : : {
7925 : 68 : if (dump_enabled_p ())
7926 : 24 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7927 : : "unsupported masked emulated scatter.\n");
7928 : 68 : return false;
7929 : : }
7930 : : }
7931 : : else
7932 : : {
7933 : : /* FORNOW. In some cases can vectorize even if data-type not supported
7934 : : (e.g. - array initialization with 0). */
7935 : 1321575 : if (!can_implement_p (mov_optab, vec_mode))
7936 : : return false;
7937 : : }
7938 : :
7939 : 1322790 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL;
7940 : 1322790 : grouped_store = (STMT_VINFO_GROUPED_ACCESS (stmt_info)
7941 : 2482813 : && !mat_gather_scatter_p (memory_access_type));
7942 : 1160023 : if (grouped_store)
7943 : : {
7944 : 1160023 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
7945 : 1160023 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
7946 : 1160023 : group_size = DR_GROUP_SIZE (first_stmt_info);
7947 : : }
7948 : : else
7949 : : {
7950 : 1322790 : first_stmt_info = stmt_info;
7951 : 1322790 : first_dr_info = dr_info;
7952 : : group_size = 1;
7953 : : }
7954 : :
7955 : 1322790 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1 && cost_vec)
7956 : : {
7957 : 1076 : if (!check_scan_store (vinfo, stmt_info, vectype, rhs_dt, slp_node,
7958 : : mask_node, memory_access_type))
7959 : : return false;
7960 : : }
7961 : :
7962 : 2644812 : bool costing_p = cost_vec;
7963 : 1322022 : if (costing_p) /* transformation not required. */
7964 : : {
7965 : 777129 : if (loop_vinfo
7966 : 120591 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
7967 : 37 : check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
7968 : : vls_type, group_size, &ls,
7969 : : mask_node);
7970 : :
7971 : 777129 : if (!vect_maybe_update_slp_op_vectype (op_node, vectype)
7972 : 777129 : || (mask_node
7973 : 692 : && !vect_maybe_update_slp_op_vectype (mask_node,
7974 : : mask_vectype)))
7975 : : {
7976 : 0 : if (dump_enabled_p ())
7977 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7978 : : "incompatible vector types for invariants\n");
7979 : 0 : return false;
7980 : : }
7981 : :
7982 : 777129 : if (dump_enabled_p ()
7983 : : && memory_access_type != VMAT_ELEMENTWISE
7984 : 14100 : && memory_access_type != VMAT_STRIDED_SLP
7985 : 13478 : && memory_access_type != VMAT_INVARIANT
7986 : 790607 : && alignment_support_scheme != dr_aligned)
7987 : 4554 : dump_printf_loc (MSG_NOTE, vect_location,
7988 : : "Vectorizing an unaligned access.\n");
7989 : :
7990 : 777129 : SLP_TREE_TYPE (slp_node) = store_vec_info_type;
7991 : 777129 : slp_node->data = new vect_load_store_data (std::move (ls));
7992 : : }
7993 : :
7994 : : /* Transform. */
7995 : :
7996 : 1322790 : ensure_base_align (dr_info);
7997 : :
7998 : 1322790 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) >= 3)
7999 : : {
8000 : 1024 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS);
8001 : 1024 : gcc_assert (SLP_TREE_LANES (slp_node) == 1);
8002 : 1024 : if (costing_p)
8003 : : {
8004 : 512 : unsigned int inside_cost = 0, prologue_cost = 0;
8005 : 512 : if (vls_type == VLS_STORE_INVARIANT)
8006 : 0 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
8007 : : slp_node, 0, vect_prologue);
8008 : 512 : vect_get_store_cost (vinfo, stmt_info, slp_node, 1,
8009 : : alignment_support_scheme, misalignment,
8010 : : &inside_cost, cost_vec);
8011 : :
8012 : 512 : if (dump_enabled_p ())
8013 : 492 : dump_printf_loc (MSG_NOTE, vect_location,
8014 : : "vect_model_store_cost: inside_cost = %d, "
8015 : : "prologue_cost = %d .\n",
8016 : : inside_cost, prologue_cost);
8017 : :
8018 : 512 : return true;
8019 : : }
8020 : 512 : return vectorizable_scan_store (vinfo, stmt_info, slp_node, gsi);
8021 : : }
8022 : :
8023 : : /* FORNOW */
8024 : 1321766 : gcc_assert (!grouped_store
8025 : : || !loop
8026 : : || !nested_in_vect_loop_p (loop, stmt_info));
8027 : :
8028 : 1321766 : grouped_store = false;
8029 : 1321766 : first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
8030 : 1321766 : gcc_assert (!STMT_VINFO_GROUPED_ACCESS (first_stmt_info)
8031 : : || (DR_GROUP_FIRST_ELEMENT (first_stmt_info) == first_stmt_info));
8032 : 1321766 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
8033 : :
8034 : 1321766 : ref_type = get_group_alias_ptr_type (first_stmt_info);
8035 : :
8036 : 1321766 : if (!costing_p && dump_enabled_p ())
8037 : 11714 : dump_printf_loc (MSG_NOTE, vect_location, "transform store.\n");
8038 : :
8039 : 1321766 : if (memory_access_type == VMAT_ELEMENTWISE
8040 : 1321766 : || memory_access_type == VMAT_STRIDED_SLP)
8041 : : {
8042 : 28554 : unsigned inside_cost = 0, prologue_cost = 0;
8043 : 28554 : gimple_stmt_iterator incr_gsi;
8044 : 28554 : bool insert_after;
8045 : 28554 : tree offvar = NULL_TREE;
8046 : 28554 : tree ivstep;
8047 : 28554 : tree running_off;
8048 : 28554 : tree stride_base, stride_step, alias_off;
8049 : 28554 : tree vec_oprnd = NULL_TREE;
8050 : 28554 : tree dr_offset;
8051 : : /* Checked by get_load_store_type. */
8052 : 28554 : unsigned int const_nunits = nunits.to_constant ();
8053 : :
8054 : 28554 : gcc_assert (!LOOP_VINFO_FULLY_MASKED_P (loop_vinfo));
8055 : 28554 : gcc_assert (!nested_in_vect_loop_p (loop, stmt_info));
8056 : :
8057 : 28554 : dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info);
8058 : 28554 : stride_base
8059 : 28554 : = fold_build_pointer_plus
8060 : : (DR_BASE_ADDRESS (first_dr_info->dr),
8061 : : size_binop (PLUS_EXPR,
8062 : : convert_to_ptrofftype (dr_offset),
8063 : : convert_to_ptrofftype (DR_INIT (first_dr_info->dr))));
8064 : 28554 : stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr));
8065 : :
8066 : : /* For a store with loop-invariant (but other than power-of-2)
8067 : : stride (i.e. not a grouped access) like so:
8068 : :
8069 : : for (i = 0; i < n; i += stride)
8070 : : array[i] = ...;
8071 : :
8072 : : we generate a new induction variable and new stores from
8073 : : the components of the (vectorized) rhs:
8074 : :
8075 : : for (j = 0; ; j += VF*stride)
8076 : : vectemp = ...;
8077 : : tmp1 = vectemp[0];
8078 : : array[j] = tmp1;
8079 : : tmp2 = vectemp[1];
8080 : : array[j + stride] = tmp2;
8081 : : ...
8082 : : */
8083 : :
8084 : : /* ??? Modify local copies of alignment_support_scheme and
8085 : : misalignment, but this part of analysis should be done
8086 : : earlier and remembered, likewise the chosen load mode. */
8087 : 28554 : const dr_alignment_support tem = alignment_support_scheme;
8088 : 28554 : dr_alignment_support alignment_support_scheme = tem;
8089 : 28554 : const int tem2 = misalignment;
8090 : 28554 : int misalignment = tem2;
8091 : :
8092 : 28554 : unsigned nstores = const_nunits;
8093 : 28554 : unsigned lnel = 1;
8094 : 28554 : tree ltype = elem_type;
8095 : 28554 : tree lvectype = vectype;
8096 : 28554 : HOST_WIDE_INT n = gcd (group_size, const_nunits);
8097 : 28554 : if (n == const_nunits)
8098 : : {
8099 : 2522 : int mis_align = dr_misalignment (first_dr_info, vectype);
8100 : : /* With VF > 1 we advance the DR by step, if that is constant
8101 : : and only aligned when performed VF times, DR alignment
8102 : : analysis can analyze this as aligned since it assumes
8103 : : contiguous accesses. But that is not how we code generate
8104 : : here, so adjust for this. */
8105 : 2522 : if (maybe_gt (vf, 1u)
8106 : 4035 : && !multiple_p (DR_STEP_ALIGNMENT (first_dr_info->dr),
8107 : 3807 : DR_TARGET_ALIGNMENT (first_dr_info)))
8108 : 228 : mis_align = -1;
8109 : 2522 : dr_alignment_support dr_align
8110 : 2522 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype,
8111 : : mis_align);
8112 : 2522 : if (dr_align == dr_aligned
8113 : 2522 : || dr_align == dr_unaligned_supported)
8114 : : {
8115 : 28554 : nstores = 1;
8116 : 28554 : lnel = const_nunits;
8117 : 28554 : ltype = vectype;
8118 : 28554 : lvectype = vectype;
8119 : 28554 : alignment_support_scheme = dr_align;
8120 : 28554 : misalignment = mis_align;
8121 : : }
8122 : : }
8123 : 26032 : else if (n > 1)
8124 : : {
8125 : 1795 : nstores = const_nunits / n;
8126 : 1795 : lnel = n;
8127 : 1795 : ltype = build_vector_type (elem_type, n);
8128 : 1795 : lvectype = vectype;
8129 : 1795 : int mis_align = dr_misalignment (first_dr_info, ltype);
8130 : 1795 : if (maybe_gt (vf, 1u)
8131 : 3590 : && !multiple_p (DR_STEP_ALIGNMENT (first_dr_info->dr),
8132 : 2883 : DR_TARGET_ALIGNMENT (first_dr_info)))
8133 : 707 : mis_align = -1;
8134 : 1795 : dr_alignment_support dr_align
8135 : 1795 : = vect_supportable_dr_alignment (vinfo, dr_info, ltype,
8136 : : mis_align);
8137 : 1795 : alignment_support_scheme = dr_align;
8138 : 1795 : misalignment = mis_align;
8139 : :
8140 : : /* First check if vec_extract optab doesn't support extraction
8141 : : of vector elts directly. */
8142 : 1795 : scalar_mode elmode = SCALAR_TYPE_MODE (elem_type);
8143 : 1795 : machine_mode vmode;
8144 : 3590 : if (!VECTOR_MODE_P (TYPE_MODE (vectype))
8145 : 2021 : || !related_vector_mode (TYPE_MODE (vectype), elmode,
8146 : 1795 : n).exists (&vmode)
8147 : 1619 : || (convert_optab_handler (vec_extract_optab,
8148 : 1619 : TYPE_MODE (vectype), vmode)
8149 : : == CODE_FOR_nothing)
8150 : 1795 : || !(dr_align == dr_aligned
8151 : 226 : || dr_align == dr_unaligned_supported))
8152 : : {
8153 : : /* Try to avoid emitting an extract of vector elements
8154 : : by performing the extracts using an integer type of the
8155 : : same size, extracting from a vector of those and then
8156 : : re-interpreting it as the original vector type if
8157 : : supported. */
8158 : 1569 : unsigned lsize = n * GET_MODE_BITSIZE (elmode);
8159 : 1569 : unsigned int lnunits = const_nunits / n;
8160 : : /* If we can't construct such a vector fall back to
8161 : : element extracts from the original vector type and
8162 : : element size stores. */
8163 : 1569 : if (int_mode_for_size (lsize, 0).exists (&elmode)
8164 : 1569 : && VECTOR_MODE_P (TYPE_MODE (vectype))
8165 : 1569 : && related_vector_mode (TYPE_MODE (vectype), elmode,
8166 : 1569 : lnunits).exists (&vmode)
8167 : 1535 : && (convert_optab_handler (vec_extract_optab,
8168 : : vmode, elmode)
8169 : : != CODE_FOR_nothing))
8170 : : {
8171 : 1535 : nstores = lnunits;
8172 : 1535 : lnel = n;
8173 : 1535 : ltype = build_nonstandard_integer_type (lsize, 1);
8174 : 1535 : lvectype = build_vector_type (ltype, nstores);
8175 : : }
8176 : : /* Else fall back to vector extraction anyway.
8177 : : Fewer stores are more important than avoiding spilling
8178 : : of the vector we extract from. Compared to the
8179 : : construction case in vectorizable_load no store-forwarding
8180 : : issue exists here for reasonable archs. But only
8181 : : if the store is supported. */
8182 : 34 : else if (!(dr_align == dr_aligned
8183 : 34 : || dr_align == dr_unaligned_supported))
8184 : : {
8185 : : nstores = const_nunits;
8186 : : lnel = 1;
8187 : : ltype = elem_type;
8188 : : lvectype = vectype;
8189 : : }
8190 : : }
8191 : : }
8192 : 28554 : unsigned align;
8193 : 28554 : if (alignment_support_scheme == dr_aligned)
8194 : 1118 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
8195 : : else
8196 : 27436 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
8197 : : /* Alignment is at most the access size if we do multiple stores. */
8198 : 28554 : if (nstores > 1)
8199 : 26032 : align = MIN (tree_to_uhwi (TYPE_SIZE_UNIT (ltype)), align);
8200 : 28554 : ltype = build_aligned_type (ltype, align * BITS_PER_UNIT);
8201 : 28554 : int ncopies = vec_num;
8202 : :
8203 : 28554 : if (!costing_p)
8204 : : {
8205 : 3254 : ivstep = stride_step;
8206 : 3254 : ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (ivstep), ivstep,
8207 : : build_int_cst (TREE_TYPE (ivstep), vf));
8208 : :
8209 : 3254 : standard_iv_increment_position (loop, &incr_gsi, &insert_after);
8210 : :
8211 : 3254 : stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base);
8212 : 3254 : ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep);
8213 : 3254 : create_iv (stride_base, PLUS_EXPR, ivstep, NULL, loop, &incr_gsi,
8214 : : insert_after, &offvar, NULL);
8215 : :
8216 : 3254 : stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step);
8217 : : }
8218 : :
8219 : 28554 : alias_off = build_int_cst (ref_type, 0);
8220 : 28554 : auto_vec<tree> vec_oprnds;
8221 : : /* For costing some adjacent vector stores, we'd like to cost with
8222 : : the total number of them once instead of cost each one by one. */
8223 : 28554 : unsigned int n_adjacent_stores = 0;
8224 : 28554 : running_off = offvar;
8225 : 28554 : if (!costing_p)
8226 : 3254 : vect_get_slp_defs (op_node, &vec_oprnds);
8227 : 28554 : unsigned int group_el = 0;
8228 : 28554 : unsigned HOST_WIDE_INT elsz
8229 : 28554 : = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
8230 : 67935 : for (j = 0; j < ncopies; j++)
8231 : : {
8232 : 39381 : if (!costing_p)
8233 : : {
8234 : 4981 : vec_oprnd = vec_oprnds[j];
8235 : : /* Pun the vector to extract from if necessary. */
8236 : 4981 : if (lvectype != vectype)
8237 : : {
8238 : 1210 : tree tem = make_ssa_name (lvectype);
8239 : 1210 : tree cvt = build1 (VIEW_CONVERT_EXPR, lvectype, vec_oprnd);
8240 : 1210 : gimple *pun = gimple_build_assign (tem, cvt);
8241 : 1210 : vect_finish_stmt_generation (vinfo, stmt_info, pun, gsi);
8242 : 1210 : vec_oprnd = tem;
8243 : : }
8244 : : }
8245 : 176838 : for (i = 0; i < nstores; i++)
8246 : : {
8247 : 137457 : if (costing_p)
8248 : : {
8249 : 121711 : n_adjacent_stores++;
8250 : 121711 : continue;
8251 : : }
8252 : 15746 : tree newref, newoff;
8253 : 15746 : gimple *incr, *assign;
8254 : 15746 : tree size = TYPE_SIZE (ltype);
8255 : : /* Extract the i'th component. */
8256 : 15746 : tree pos = fold_build2 (MULT_EXPR, bitsizetype,
8257 : : bitsize_int (i), size);
8258 : 15746 : tree elem = fold_build3 (BIT_FIELD_REF, ltype, vec_oprnd,
8259 : : size, pos);
8260 : :
8261 : 15746 : elem = force_gimple_operand_gsi (gsi, elem, true, NULL_TREE, true,
8262 : : GSI_SAME_STMT);
8263 : :
8264 : 15746 : tree this_off = build_int_cst (TREE_TYPE (alias_off),
8265 : 15746 : group_el * elsz);
8266 : 15746 : newref = build2 (MEM_REF, ltype, running_off, this_off);
8267 : 15746 : vect_copy_ref_info (newref, DR_REF (first_dr_info->dr));
8268 : :
8269 : : /* And store it to *running_off. */
8270 : 15746 : assign = gimple_build_assign (newref, elem);
8271 : 15746 : vect_finish_stmt_generation (vinfo, stmt_info, assign, gsi);
8272 : :
8273 : 15746 : group_el += lnel;
8274 : 15746 : if (group_el == group_size)
8275 : : {
8276 : 14619 : newoff = copy_ssa_name (running_off, NULL);
8277 : 14619 : incr = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
8278 : : running_off, stride_step);
8279 : 14619 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
8280 : :
8281 : 14619 : running_off = newoff;
8282 : 14619 : group_el = 0;
8283 : : }
8284 : : }
8285 : : }
8286 : :
8287 : 28554 : if (costing_p)
8288 : : {
8289 : 25300 : if (n_adjacent_stores > 0)
8290 : : {
8291 : : /* Take a single lane vector type store as scalar
8292 : : store to avoid ICE like 110776. */
8293 : 25300 : if (VECTOR_TYPE_P (ltype)
8294 : 25300 : && maybe_ne (TYPE_VECTOR_SUBPARTS (ltype), 1U))
8295 : 1198 : vect_get_store_cost (vinfo, stmt_info, slp_node,
8296 : : n_adjacent_stores, alignment_support_scheme,
8297 : : misalignment, &inside_cost, cost_vec);
8298 : : else
8299 : 24102 : inside_cost
8300 : 24102 : += record_stmt_cost (cost_vec, n_adjacent_stores,
8301 : : scalar_store, slp_node, 0, vect_body);
8302 : : /* Only need vector extracting when there are more
8303 : : than one stores. */
8304 : 25300 : if (nstores > 1)
8305 : 23516 : inside_cost
8306 : 23516 : += record_stmt_cost (cost_vec, n_adjacent_stores,
8307 : : vec_to_scalar, slp_node, 0, vect_body);
8308 : : }
8309 : 25300 : if (dump_enabled_p ())
8310 : 622 : dump_printf_loc (MSG_NOTE, vect_location,
8311 : : "vect_model_store_cost: inside_cost = %d, "
8312 : : "prologue_cost = %d .\n",
8313 : : inside_cost, prologue_cost);
8314 : : }
8315 : :
8316 : 28554 : return true;
8317 : 28554 : }
8318 : :
8319 : 1293212 : gcc_assert (alignment_support_scheme);
8320 : 1293212 : vec_loop_masks *loop_masks
8321 : 150248 : = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
8322 : 1293212 : ? &LOOP_VINFO_MASKS (loop_vinfo)
8323 : 10 : : NULL);
8324 : 10 : vec_loop_lens *loop_lens
8325 : 150248 : = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)
8326 : : ? &LOOP_VINFO_LENS (loop_vinfo)
8327 : 0 : : NULL);
8328 : :
8329 : : /* The vect_transform_stmt and vect_analyze_stmt will go here but there
8330 : : are some difference here. We cannot enable both the lens and masks
8331 : : during transform but it is allowed during analysis.
8332 : : Shouldn't go with length-based approach if fully masked. */
8333 : 1293212 : if (cost_vec == NULL)
8334 : : /* The cost_vec is NULL during transfrom. */
8335 : 541895 : gcc_assert ((!loop_lens || !loop_masks));
8336 : :
8337 : : /* Targets with store-lane instructions must not require explicit
8338 : : realignment. vect_supportable_dr_alignment always returns either
8339 : : dr_aligned or dr_unaligned_supported for masked operations. */
8340 : 1293212 : gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES
8341 : : && !mask_node
8342 : : && !loop_masks)
8343 : : || alignment_support_scheme == dr_aligned
8344 : : || alignment_support_scheme == dr_unaligned_supported);
8345 : :
8346 : 1293212 : tree offset = NULL_TREE;
8347 : 1293212 : if (!known_eq (poffset, 0))
8348 : 4102 : offset = size_int (poffset);
8349 : :
8350 : 1293212 : tree bump;
8351 : 1293212 : tree vec_offset = NULL_TREE;
8352 : 1293212 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
8353 : : {
8354 : 2397 : aggr_type = NULL_TREE;
8355 : 2397 : bump = NULL_TREE;
8356 : : }
8357 : 1290815 : else if (mat_gather_scatter_p (memory_access_type))
8358 : : {
8359 : 0 : aggr_type = elem_type;
8360 : 0 : if (!costing_p)
8361 : 0 : vect_get_strided_load_store_ops (stmt_info, slp_node, vectype,
8362 : : ls.strided_offset_vectype,
8363 : : loop_vinfo, gsi,
8364 : : &bump, &vec_offset, loop_lens);
8365 : : }
8366 : : else
8367 : : {
8368 : 1290815 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
8369 : 0 : aggr_type = build_array_type_nelts (elem_type, group_size * nunits);
8370 : : else
8371 : : aggr_type = vectype;
8372 : 1290815 : if (!costing_p)
8373 : 541421 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
8374 : : memory_access_type, loop_lens);
8375 : : }
8376 : :
8377 : 1293212 : if (mask_node && !costing_p)
8378 : 523 : LOOP_VINFO_HAS_MASK_STORE (loop_vinfo) = true;
8379 : :
8380 : : /* In case the vectorization factor (VF) is bigger than the number
8381 : : of elements that we can fit in a vectype (nunits), we have to generate
8382 : : more than one vector stmt - i.e - we need to "unroll" the
8383 : : vector stmt by a factor VF/nunits. */
8384 : :
8385 : 1293212 : auto_vec<tree> dr_chain (group_size);
8386 : 1293212 : auto_vec<tree> vec_masks;
8387 : 1293212 : tree vec_mask = NULL;
8388 : 1293212 : auto_delete_vec<auto_vec<tree>> gvec_oprnds (group_size);
8389 : 5896228 : for (i = 0; i < group_size; i++)
8390 : 3309804 : gvec_oprnds.quick_push (new auto_vec<tree> ());
8391 : :
8392 : 1293212 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
8393 : : {
8394 : 0 : const internal_fn lanes_ifn = ls.lanes_ifn;
8395 : :
8396 : 0 : if (costing_p)
8397 : : /* Update all incoming store operand nodes, the general handling
8398 : : above only handles the mask and the first store operand node. */
8399 : 0 : for (slp_tree child : SLP_TREE_CHILDREN (slp_node))
8400 : 0 : if (child != mask_node
8401 : 0 : && !vect_maybe_update_slp_op_vectype (child, vectype))
8402 : : {
8403 : 0 : if (dump_enabled_p ())
8404 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8405 : : "incompatible vector types for invariants\n");
8406 : 0 : return false;
8407 : : }
8408 : 0 : unsigned inside_cost = 0, prologue_cost = 0;
8409 : : /* For costing some adjacent vector stores, we'd like to cost with
8410 : : the total number of them once instead of cost each one by one. */
8411 : 0 : unsigned int n_adjacent_stores = 0;
8412 : 0 : int ncopies = vec_num / group_size;
8413 : 0 : for (j = 0; j < ncopies; j++)
8414 : : {
8415 : 0 : if (j == 0)
8416 : : {
8417 : 0 : if (!costing_p)
8418 : : {
8419 : 0 : if (mask_node)
8420 : : {
8421 : 0 : vect_get_slp_defs (mask_node, &vec_masks);
8422 : 0 : vec_mask = vec_masks[0];
8423 : : }
8424 : 0 : dataref_ptr
8425 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info,
8426 : : aggr_type, NULL, offset, &dummy,
8427 : : gsi, &ptr_incr, false, bump);
8428 : : }
8429 : : }
8430 : 0 : else if (!costing_p)
8431 : : {
8432 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
8433 : 0 : if (mask_node)
8434 : 0 : vec_mask = vec_masks[j];
8435 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
8436 : : stmt_info, bump);
8437 : : }
8438 : :
8439 : 0 : if (costing_p)
8440 : : {
8441 : 0 : n_adjacent_stores += group_size;
8442 : 0 : continue;
8443 : : }
8444 : :
8445 : : /* Get an array into which we can store the individual vectors. */
8446 : 0 : tree vec_array = create_vector_array (vectype, group_size);
8447 : :
8448 : : /* Invalidate the current contents of VEC_ARRAY. This should
8449 : : become an RTL clobber too, which prevents the vector registers
8450 : : from being upward-exposed. */
8451 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
8452 : :
8453 : : /* Store the individual vectors into the array. */
8454 : 0 : for (i = 0; i < group_size; i++)
8455 : : {
8456 : 0 : slp_tree child;
8457 : 0 : if (i == 0 || !mask_node)
8458 : 0 : child = SLP_TREE_CHILDREN (slp_node)[i];
8459 : : else
8460 : 0 : child = SLP_TREE_CHILDREN (slp_node)[i + 1];
8461 : 0 : vec_oprnd = SLP_TREE_VEC_DEFS (child)[j];
8462 : 0 : write_vector_array (vinfo, stmt_info, gsi, vec_oprnd, vec_array,
8463 : : i);
8464 : : }
8465 : :
8466 : 0 : tree final_mask = NULL;
8467 : 0 : tree final_len = NULL;
8468 : 0 : tree bias = NULL;
8469 : 0 : if (loop_masks)
8470 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
8471 : : ncopies, vectype, j);
8472 : 0 : if (vec_mask)
8473 : 0 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
8474 : : vec_mask, gsi);
8475 : :
8476 : 0 : if (lanes_ifn == IFN_MASK_LEN_STORE_LANES)
8477 : : {
8478 : 0 : if (loop_lens)
8479 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
8480 : : ncopies, vectype, j, 1);
8481 : : else
8482 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
8483 : 0 : signed char biasval
8484 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
8485 : 0 : bias = build_int_cst (intQI_type_node, biasval);
8486 : 0 : if (!final_mask)
8487 : : {
8488 : 0 : mask_vectype = truth_type_for (vectype);
8489 : 0 : final_mask = build_minus_one_cst (mask_vectype);
8490 : : }
8491 : : }
8492 : :
8493 : 0 : gcall *call;
8494 : 0 : if (final_len && final_mask)
8495 : : {
8496 : : /* Emit:
8497 : : MASK_LEN_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
8498 : : LEN, BIAS, VEC_ARRAY). */
8499 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
8500 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
8501 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_STORE_LANES, 6,
8502 : : dataref_ptr, alias_ptr,
8503 : : final_mask, final_len, bias,
8504 : : vec_array);
8505 : : }
8506 : 0 : else if (final_mask)
8507 : : {
8508 : : /* Emit:
8509 : : MASK_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
8510 : : VEC_ARRAY). */
8511 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
8512 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
8513 : 0 : call = gimple_build_call_internal (IFN_MASK_STORE_LANES, 4,
8514 : : dataref_ptr, alias_ptr,
8515 : : final_mask, vec_array);
8516 : : }
8517 : : else
8518 : : {
8519 : : /* Emit:
8520 : : MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY). */
8521 : 0 : data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
8522 : 0 : call = gimple_build_call_internal (IFN_STORE_LANES, 1, vec_array);
8523 : 0 : gimple_call_set_lhs (call, data_ref);
8524 : : }
8525 : 0 : gimple_call_set_nothrow (call, true);
8526 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
8527 : :
8528 : : /* Record that VEC_ARRAY is now dead. */
8529 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
8530 : : }
8531 : :
8532 : 0 : if (costing_p)
8533 : : {
8534 : 0 : if (n_adjacent_stores > 0)
8535 : 0 : vect_get_store_cost (vinfo, stmt_info, slp_node, n_adjacent_stores,
8536 : : alignment_support_scheme, misalignment,
8537 : : &inside_cost, cost_vec);
8538 : 0 : if (dump_enabled_p ())
8539 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
8540 : : "vect_model_store_cost: inside_cost = %d, "
8541 : : "prologue_cost = %d .\n",
8542 : : inside_cost, prologue_cost);
8543 : : }
8544 : :
8545 : 0 : return true;
8546 : : }
8547 : :
8548 : 1293212 : if (mat_gather_scatter_p (memory_access_type))
8549 : : {
8550 : 2397 : gcc_assert (!grouped_store);
8551 : 2397 : auto_vec<tree> vec_offsets;
8552 : 2397 : unsigned int inside_cost = 0, prologue_cost = 0;
8553 : 2397 : int num_stmts = vec_num;
8554 : 5196 : for (j = 0; j < num_stmts; j++)
8555 : : {
8556 : 2799 : gimple *new_stmt;
8557 : 2799 : if (j == 0)
8558 : : {
8559 : 2397 : if (costing_p && vls_type == VLS_STORE_INVARIANT)
8560 : 202 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
8561 : : slp_node, 0, vect_prologue);
8562 : : else if (!costing_p)
8563 : : {
8564 : : /* Since the store is not grouped, DR_GROUP_SIZE is 1, and
8565 : : DR_CHAIN is of size 1. */
8566 : 474 : gcc_assert (group_size == 1);
8567 : 474 : vect_get_slp_defs (op_node, gvec_oprnds[0]);
8568 : 474 : if (mask_node)
8569 : 70 : vect_get_slp_defs (mask_node, &vec_masks);
8570 : :
8571 : 474 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
8572 : 474 : vect_get_gather_scatter_ops (loop, slp_node,
8573 : : &dataref_ptr, &vec_offsets);
8574 : : else
8575 : 0 : dataref_ptr
8576 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info,
8577 : : aggr_type, NULL, offset,
8578 : : &dummy, gsi, &ptr_incr, false,
8579 : : bump);
8580 : : }
8581 : : }
8582 : 402 : else if (!costing_p)
8583 : : {
8584 : 38 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
8585 : 38 : if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info))
8586 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
8587 : : gsi, stmt_info, bump);
8588 : : }
8589 : :
8590 : 3513 : new_stmt = NULL;
8591 : 714 : if (!costing_p)
8592 : : {
8593 : 512 : vec_oprnd = (*gvec_oprnds[0])[j];
8594 : 512 : if (mask_node)
8595 : 90 : vec_mask = vec_masks[j];
8596 : : /* We should have catched mismatched types earlier. */
8597 : 512 : gcc_assert (useless_type_conversion_p (vectype,
8598 : : TREE_TYPE (vec_oprnd)));
8599 : : }
8600 : 512 : tree final_mask = NULL_TREE;
8601 : 3311 : tree final_len = NULL_TREE;
8602 : 3311 : tree bias = NULL_TREE;
8603 : 512 : if (!costing_p)
8604 : : {
8605 : 512 : if (loop_masks)
8606 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi,
8607 : : loop_masks, num_stmts,
8608 : : vectype, j);
8609 : 512 : if (vec_mask)
8610 : 90 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
8611 : : final_mask, vec_mask, gsi);
8612 : : }
8613 : :
8614 : 2799 : unsigned align = get_object_alignment (DR_REF (first_dr_info->dr));
8615 : 2799 : tree alias_align_ptr = build_int_cst (ref_type, align);
8616 : 2799 : if (memory_access_type == VMAT_GATHER_SCATTER_IFN)
8617 : : {
8618 : 0 : if (costing_p)
8619 : : {
8620 : 0 : unsigned int cnunits = vect_nunits_for_cost (vectype);
8621 : 0 : inside_cost
8622 : 0 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
8623 : : slp_node, 0, vect_body);
8624 : 2799 : continue;
8625 : 0 : }
8626 : :
8627 : 0 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
8628 : 0 : vec_offset = vec_offsets[j];
8629 : :
8630 : 0 : tree scale = size_int (SLP_TREE_GS_SCALE (slp_node));
8631 : :
8632 : 0 : if (ls.gs.ifn == IFN_MASK_LEN_SCATTER_STORE)
8633 : : {
8634 : 0 : if (loop_lens)
8635 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi,
8636 : : loop_lens, num_stmts,
8637 : : vectype, j, 1);
8638 : : else
8639 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
8640 : :
8641 : 0 : signed char biasval
8642 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
8643 : 0 : bias = build_int_cst (intQI_type_node, biasval);
8644 : 0 : if (!final_mask)
8645 : : {
8646 : 0 : mask_vectype = truth_type_for (vectype);
8647 : 0 : final_mask = build_minus_one_cst (mask_vectype);
8648 : : }
8649 : : }
8650 : :
8651 : 0 : gcall *call;
8652 : 0 : if (final_len && final_mask)
8653 : : {
8654 : 0 : if (VECTOR_TYPE_P (TREE_TYPE (vec_offset)))
8655 : 0 : call = gimple_build_call_internal (
8656 : : IFN_MASK_LEN_SCATTER_STORE, 8, dataref_ptr,
8657 : : alias_align_ptr,
8658 : : vec_offset, scale, vec_oprnd, final_mask, final_len,
8659 : : bias);
8660 : : else
8661 : : /* Non-vector offset indicates that prefer to take
8662 : : MASK_LEN_STRIDED_STORE instead of the
8663 : : IFN_MASK_SCATTER_STORE with direct stride arg.
8664 : : Similar to the gather case we have checked the
8665 : : alignment for a scatter already and assume
8666 : : that the strided store has the same requirements. */
8667 : 0 : call = gimple_build_call_internal (
8668 : : IFN_MASK_LEN_STRIDED_STORE, 6, dataref_ptr,
8669 : : vec_offset, vec_oprnd, final_mask, final_len, bias);
8670 : : }
8671 : 0 : else if (final_mask)
8672 : 0 : call = gimple_build_call_internal
8673 : 0 : (IFN_MASK_SCATTER_STORE, 6, dataref_ptr,
8674 : : alias_align_ptr,
8675 : : vec_offset, scale, vec_oprnd, final_mask);
8676 : : else
8677 : 0 : call = gimple_build_call_internal (IFN_SCATTER_STORE, 5,
8678 : : dataref_ptr,
8679 : : alias_align_ptr,
8680 : : vec_offset,
8681 : : scale, vec_oprnd);
8682 : 0 : gimple_call_set_nothrow (call, true);
8683 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
8684 : 0 : new_stmt = call;
8685 : : }
8686 : 2799 : else if (memory_access_type == VMAT_GATHER_SCATTER_LEGACY)
8687 : : {
8688 : : /* The builtin decls path for scatter is legacy, x86 only. */
8689 : 326 : gcc_assert (nunits.is_constant ()
8690 : : && (!final_mask
8691 : : || SCALAR_INT_MODE_P
8692 : : (TYPE_MODE (TREE_TYPE (final_mask)))));
8693 : 326 : if (costing_p)
8694 : : {
8695 : 187 : unsigned int cnunits = vect_nunits_for_cost (vectype);
8696 : 187 : inside_cost
8697 : 187 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
8698 : : slp_node, 0, vect_body);
8699 : 187 : continue;
8700 : 187 : }
8701 : :
8702 : 139 : tree offset_vectype = TREE_TYPE (vec_offsets[0]);
8703 : 139 : poly_uint64 offset_nunits
8704 : 139 : = TYPE_VECTOR_SUBPARTS (offset_vectype);
8705 : 139 : if (known_eq (nunits, offset_nunits))
8706 : : {
8707 : 63 : new_stmt = vect_build_one_scatter_store_call
8708 : 126 : (vinfo, stmt_info, slp_node, gsi,
8709 : 63 : ls.gs.decl, dataref_ptr, vec_offsets[j],
8710 : : vec_oprnd, final_mask);
8711 : 63 : vect_finish_stmt_generation (vinfo, stmt_info,
8712 : : new_stmt, gsi);
8713 : : }
8714 : 76 : else if (known_eq (nunits, offset_nunits * 2))
8715 : : {
8716 : : /* We have a offset vector with half the number of
8717 : : lanes but the builtins will store full vectype
8718 : : data from the lower lanes. */
8719 : 30 : new_stmt = vect_build_one_scatter_store_call
8720 : 60 : (vinfo, stmt_info, slp_node, gsi, ls.gs.decl,
8721 : 30 : dataref_ptr, vec_offsets[2 * j],
8722 : : vec_oprnd, final_mask);
8723 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
8724 : : new_stmt, gsi);
8725 : 30 : int count = nunits.to_constant ();
8726 : 30 : vec_perm_builder sel (count, count, 1);
8727 : 30 : sel.quick_grow (count);
8728 : 382 : for (int i = 0; i < count; ++i)
8729 : 352 : sel[i] = i | (count / 2);
8730 : 30 : vec_perm_indices indices (sel, 2, count);
8731 : 30 : tree perm_mask
8732 : 30 : = vect_gen_perm_mask_checked (vectype, indices);
8733 : 30 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
8734 : : vec_oprnd, vec_oprnd,
8735 : : perm_mask);
8736 : 30 : vec_oprnd = make_ssa_name (vectype);
8737 : 30 : gimple_set_lhs (new_stmt, vec_oprnd);
8738 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
8739 : : new_stmt, gsi);
8740 : 30 : if (final_mask)
8741 : : {
8742 : 20 : new_stmt = gimple_build_assign (NULL_TREE,
8743 : : VEC_UNPACK_HI_EXPR,
8744 : : final_mask);
8745 : 20 : final_mask = make_ssa_name
8746 : 20 : (truth_type_for (offset_vectype));
8747 : 20 : gimple_set_lhs (new_stmt, final_mask);
8748 : 20 : vect_finish_stmt_generation (vinfo, stmt_info,
8749 : : new_stmt, gsi);
8750 : : }
8751 : :
8752 : 30 : new_stmt = vect_build_one_scatter_store_call
8753 : 60 : (vinfo, stmt_info, slp_node, gsi, ls.gs.decl,
8754 : 30 : dataref_ptr, vec_offsets[2 * j + 1],
8755 : : vec_oprnd, final_mask);
8756 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
8757 : : new_stmt, gsi);
8758 : 30 : }
8759 : 46 : else if (known_eq (nunits * 2, offset_nunits))
8760 : : {
8761 : : /* We have a offset vector with double the number of
8762 : : lanes. Select the low/high part accordingly. */
8763 : 46 : vec_offset = vec_offsets[j / 2];
8764 : 46 : if (j & 1)
8765 : : {
8766 : 23 : int count = offset_nunits.to_constant ();
8767 : 23 : vec_perm_builder sel (count, count, 1);
8768 : 23 : sel.quick_grow (count);
8769 : 263 : for (int i = 0; i < count; ++i)
8770 : 240 : sel[i] = i | (count / 2);
8771 : 23 : vec_perm_indices indices (sel, 2, count);
8772 : 23 : tree perm_mask = vect_gen_perm_mask_checked
8773 : 23 : (TREE_TYPE (vec_offset), indices);
8774 : 23 : new_stmt = gimple_build_assign (NULL_TREE,
8775 : : VEC_PERM_EXPR,
8776 : : vec_offset,
8777 : : vec_offset,
8778 : : perm_mask);
8779 : 23 : vec_offset = make_ssa_name (TREE_TYPE (vec_offset));
8780 : 23 : gimple_set_lhs (new_stmt, vec_offset);
8781 : 23 : vect_finish_stmt_generation (vinfo, stmt_info,
8782 : : new_stmt, gsi);
8783 : 23 : }
8784 : :
8785 : 46 : new_stmt = vect_build_one_scatter_store_call
8786 : 46 : (vinfo, stmt_info, slp_node, gsi,
8787 : : ls.gs.decl, dataref_ptr, vec_offset,
8788 : : vec_oprnd, final_mask);
8789 : 46 : vect_finish_stmt_generation (vinfo, stmt_info,
8790 : : new_stmt, gsi);
8791 : : }
8792 : : else
8793 : 0 : gcc_unreachable ();
8794 : : }
8795 : : else
8796 : : {
8797 : : /* Emulated scatter. */
8798 : 2473 : gcc_assert (!final_mask);
8799 : 2473 : if (costing_p)
8800 : : {
8801 : 2100 : unsigned int cnunits = vect_nunits_for_cost (vectype);
8802 : : /* For emulated scatter N offset vector element extracts
8803 : : (we assume the scalar scaling and ptr + offset add is
8804 : : consumed by the load). */
8805 : 2100 : inside_cost
8806 : 2100 : += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
8807 : : slp_node, 0, vect_body);
8808 : : /* N scalar stores plus extracting the elements. */
8809 : 2100 : inside_cost
8810 : 2100 : += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
8811 : : slp_node, 0, vect_body);
8812 : 2100 : inside_cost
8813 : 2100 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
8814 : : slp_node, 0, vect_body);
8815 : 2100 : continue;
8816 : 2100 : }
8817 : :
8818 : 373 : tree offset_vectype = TREE_TYPE (vec_offsets[0]);
8819 : 373 : unsigned HOST_WIDE_INT const_nunits = nunits.to_constant ();
8820 : 373 : unsigned HOST_WIDE_INT const_offset_nunits
8821 : 373 : = TYPE_VECTOR_SUBPARTS (offset_vectype).to_constant ();
8822 : 373 : vec<constructor_elt, va_gc> *ctor_elts;
8823 : 373 : vec_alloc (ctor_elts, const_nunits);
8824 : 373 : gimple_seq stmts = NULL;
8825 : 373 : tree elt_type = TREE_TYPE (vectype);
8826 : 373 : unsigned HOST_WIDE_INT elt_size
8827 : 373 : = tree_to_uhwi (TYPE_SIZE (elt_type));
8828 : : /* We support offset vectors with more elements
8829 : : than the data vector for now. */
8830 : 373 : unsigned HOST_WIDE_INT factor
8831 : : = const_offset_nunits / const_nunits;
8832 : 373 : vec_offset = vec_offsets[j / factor];
8833 : 373 : unsigned elt_offset
8834 : 373 : = (j % factor) * const_nunits;
8835 : 373 : tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset));
8836 : 373 : tree scale = size_int (SLP_TREE_GS_SCALE (slp_node));
8837 : 373 : tree ltype = build_aligned_type (TREE_TYPE (vectype), align);
8838 : 1519 : for (unsigned k = 0; k < const_nunits; ++k)
8839 : : {
8840 : : /* Compute the offsetted pointer. */
8841 : 1146 : tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type),
8842 : : bitsize_int (k + elt_offset));
8843 : 1146 : tree idx
8844 : 2292 : = gimple_build (&stmts, BIT_FIELD_REF, idx_type,
8845 : 1146 : vec_offset, TYPE_SIZE (idx_type), boff);
8846 : 1146 : idx = gimple_convert (&stmts, sizetype, idx);
8847 : 1146 : idx = gimple_build (&stmts, MULT_EXPR, sizetype,
8848 : : idx, scale);
8849 : 1146 : tree ptr
8850 : 1146 : = gimple_build (&stmts, PLUS_EXPR,
8851 : 1146 : TREE_TYPE (dataref_ptr),
8852 : : dataref_ptr, idx);
8853 : 1146 : ptr = gimple_convert (&stmts, ptr_type_node, ptr);
8854 : : /* Extract the element to be stored. */
8855 : 1146 : tree elt
8856 : 2292 : = gimple_build (&stmts, BIT_FIELD_REF,
8857 : 1146 : TREE_TYPE (vectype),
8858 : 1146 : vec_oprnd, TYPE_SIZE (elt_type),
8859 : 1146 : bitsize_int (k * elt_size));
8860 : 1146 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
8861 : 1146 : stmts = NULL;
8862 : 1146 : tree ref
8863 : 1146 : = build2 (MEM_REF, ltype, ptr,
8864 : : build_int_cst (ref_type, 0));
8865 : 1146 : new_stmt = gimple_build_assign (ref, elt);
8866 : 1146 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
8867 : : }
8868 : :
8869 : 373 : slp_node->push_vec_def (new_stmt);
8870 : : }
8871 : : }
8872 : :
8873 : 2397 : if (costing_p && dump_enabled_p ())
8874 : 68 : dump_printf_loc (MSG_NOTE, vect_location,
8875 : : "vect_model_store_cost: inside_cost = %d, "
8876 : : "prologue_cost = %d .\n",
8877 : : inside_cost, prologue_cost);
8878 : :
8879 : 2397 : return true;
8880 : 2397 : }
8881 : :
8882 : 1290815 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS
8883 : : || memory_access_type == VMAT_CONTIGUOUS_DOWN
8884 : : || memory_access_type == VMAT_CONTIGUOUS_REVERSE);
8885 : :
8886 : 1290815 : unsigned inside_cost = 0, prologue_cost = 0;
8887 : : /* For costing some adjacent vector stores, we'd like to cost with
8888 : : the total number of them once instead of cost each one by one. */
8889 : 1290815 : unsigned int n_adjacent_stores = 0;
8890 : 1290815 : auto_vec<tree> result_chain (group_size);
8891 : 1290815 : auto_vec<tree, 1> vec_oprnds;
8892 : 1290815 : gimple *new_stmt;
8893 : 1290815 : if (!costing_p)
8894 : : {
8895 : : /* Get vectorized arguments for SLP_NODE. */
8896 : 541421 : vect_get_slp_defs (op_node, &vec_oprnds);
8897 : 541421 : vec_oprnd = vec_oprnds[0];
8898 : 541421 : if (mask_node)
8899 : : {
8900 : 453 : vect_get_slp_defs (mask_node, &vec_masks);
8901 : 453 : vec_mask = vec_masks[0];
8902 : : }
8903 : : }
8904 : :
8905 : : /* We should have catched mismatched types earlier. */
8906 : 541421 : gcc_assert (costing_p
8907 : : || useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd)));
8908 : 1290815 : bool simd_lane_access_p
8909 : 1290815 : = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0;
8910 : 1290815 : if (!costing_p
8911 : 1290815 : && simd_lane_access_p
8912 : 4366 : && !loop_masks
8913 : 4366 : && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR
8914 : 4366 : && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0))
8915 : 4366 : && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info))
8916 : 4366 : && integer_zerop (DR_INIT (first_dr_info->dr))
8917 : 1295181 : && alias_sets_conflict_p (get_alias_set (aggr_type),
8918 : 4366 : get_alias_set (TREE_TYPE (ref_type))))
8919 : : {
8920 : 4358 : dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr));
8921 : 4358 : dataref_offset = build_int_cst (ref_type, 0);
8922 : : }
8923 : 1286457 : else if (!costing_p)
8924 : 1074118 : dataref_ptr = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
8925 : : simd_lane_access_p ? loop : NULL,
8926 : : offset, &dummy, gsi, &ptr_incr,
8927 : : simd_lane_access_p, bump);
8928 : :
8929 : 1290815 : new_stmt = NULL;
8930 : 1290815 : gcc_assert (!grouped_store);
8931 : 2870773 : for (i = 0; i < vec_num; i++)
8932 : : {
8933 : 1579958 : if (!costing_p)
8934 : 671432 : vec_oprnd = vec_oprnds[i];
8935 : :
8936 : 1579958 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
8937 : : {
8938 : 3158 : if (costing_p)
8939 : 2025 : inside_cost += record_stmt_cost (cost_vec, 1, vec_perm,
8940 : : slp_node, 0, vect_body);
8941 : : else
8942 : : {
8943 : 1133 : tree perm_mask = perm_mask_for_reverse (vectype);
8944 : 1133 : tree new_temp = make_ssa_name (vectype);
8945 : :
8946 : : /* Generate the permute statement. */
8947 : 1133 : gimple *perm_stmt
8948 : 1133 : = gimple_build_assign (new_temp, VEC_PERM_EXPR, vec_oprnd,
8949 : : vec_oprnd, perm_mask);
8950 : 1133 : vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
8951 : :
8952 : 1133 : perm_stmt = SSA_NAME_DEF_STMT (new_temp);
8953 : 1579958 : vec_oprnd = new_temp;
8954 : : }
8955 : : }
8956 : :
8957 : 1579958 : if (costing_p)
8958 : : {
8959 : 908526 : n_adjacent_stores++;
8960 : 908526 : continue;
8961 : : }
8962 : :
8963 : 671432 : tree final_mask = NULL_TREE;
8964 : 671432 : tree final_len = NULL_TREE;
8965 : 671432 : tree bias = NULL_TREE;
8966 : 671432 : if (loop_masks)
8967 : 76 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
8968 : : vec_num, vectype, i);
8969 : 671432 : if (vec_mask)
8970 : 634 : vec_mask = vec_masks[i];
8971 : 634 : if (vec_mask)
8972 : 634 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
8973 : : vec_mask, gsi);
8974 : :
8975 : 671432 : if (i > 0)
8976 : : /* Bump the vector pointer. */
8977 : 130011 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
8978 : : stmt_info, bump);
8979 : :
8980 : 671432 : unsigned misalign;
8981 : 671432 : unsigned HOST_WIDE_INT align;
8982 : 671432 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
8983 : 671432 : if (alignment_support_scheme == dr_aligned)
8984 : : misalign = 0;
8985 : 307383 : else if (misalignment == DR_MISALIGNMENT_UNKNOWN)
8986 : : {
8987 : 157634 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
8988 : 157634 : misalign = 0;
8989 : : }
8990 : : else
8991 : 149749 : misalign = misalignment;
8992 : 671432 : if (dataref_offset == NULL_TREE
8993 : 666060 : && TREE_CODE (dataref_ptr) == SSA_NAME)
8994 : 175825 : set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, misalign);
8995 : 671432 : align = least_bit_hwi (misalign | align);
8996 : :
8997 : : /* Compute IFN when LOOP_LENS or final_mask valid. */
8998 : 671432 : machine_mode vmode = TYPE_MODE (vectype);
8999 : 671432 : machine_mode new_vmode = vmode;
9000 : 671432 : internal_fn partial_ifn = IFN_LAST;
9001 : 671432 : if (loop_lens)
9002 : : {
9003 : 0 : opt_machine_mode new_ovmode
9004 : 0 : = get_len_load_store_mode (vmode, false, &partial_ifn);
9005 : 0 : new_vmode = new_ovmode.require ();
9006 : 0 : unsigned factor
9007 : 0 : = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode);
9008 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
9009 : : vec_num, vectype, i, factor);
9010 : : }
9011 : 671432 : else if (final_mask)
9012 : : {
9013 : 646 : if (!can_vec_mask_load_store_p (vmode,
9014 : 646 : TYPE_MODE (TREE_TYPE (final_mask)),
9015 : : false, &partial_ifn))
9016 : 0 : gcc_unreachable ();
9017 : : }
9018 : :
9019 : 671432 : if (partial_ifn == IFN_MASK_LEN_STORE)
9020 : : {
9021 : 0 : if (!final_len)
9022 : : {
9023 : : /* Pass VF value to 'len' argument of
9024 : : MASK_LEN_STORE if LOOP_LENS is invalid. */
9025 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
9026 : : }
9027 : 0 : if (!final_mask)
9028 : : {
9029 : : /* Pass all ones value to 'mask' argument of
9030 : : MASK_LEN_STORE if final_mask is invalid. */
9031 : 0 : mask_vectype = truth_type_for (vectype);
9032 : 0 : final_mask = build_minus_one_cst (mask_vectype);
9033 : : }
9034 : : }
9035 : 671432 : if (final_len)
9036 : : {
9037 : 0 : signed char biasval = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
9038 : 0 : bias = build_int_cst (intQI_type_node, biasval);
9039 : : }
9040 : :
9041 : : /* Arguments are ready. Create the new vector stmt. */
9042 : 671432 : if (final_len)
9043 : : {
9044 : 0 : gcall *call;
9045 : 0 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
9046 : : /* Need conversion if it's wrapped with VnQI. */
9047 : 0 : if (vmode != new_vmode)
9048 : : {
9049 : 0 : tree new_vtype
9050 : 0 : = build_vector_type_for_mode (unsigned_intQI_type_node,
9051 : : new_vmode);
9052 : 0 : tree var = vect_get_new_ssa_name (new_vtype, vect_simple_var);
9053 : 0 : vec_oprnd = build1 (VIEW_CONVERT_EXPR, new_vtype, vec_oprnd);
9054 : 0 : gassign *new_stmt
9055 : 0 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, vec_oprnd);
9056 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
9057 : 0 : vec_oprnd = var;
9058 : : }
9059 : :
9060 : 0 : if (partial_ifn == IFN_MASK_LEN_STORE)
9061 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_STORE, 6,
9062 : : dataref_ptr, ptr, final_mask,
9063 : : final_len, bias, vec_oprnd);
9064 : : else
9065 : 0 : call = gimple_build_call_internal (IFN_LEN_STORE, 5,
9066 : : dataref_ptr, ptr, final_len,
9067 : : bias, vec_oprnd);
9068 : 0 : gimple_call_set_nothrow (call, true);
9069 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9070 : 0 : new_stmt = call;
9071 : : }
9072 : 671432 : else if (final_mask)
9073 : : {
9074 : 646 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
9075 : 646 : gcall *call
9076 : 646 : = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr,
9077 : : ptr, final_mask, vec_oprnd);
9078 : 646 : gimple_call_set_nothrow (call, true);
9079 : 646 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9080 : 646 : new_stmt = call;
9081 : : }
9082 : : else
9083 : : {
9084 : 670786 : data_ref = fold_build2 (MEM_REF, vectype, dataref_ptr,
9085 : : dataref_offset ? dataref_offset
9086 : : : build_int_cst (ref_type, 0));
9087 : 670786 : if (alignment_support_scheme == dr_aligned
9088 : 670786 : && align >= TYPE_ALIGN_UNIT (vectype))
9089 : : ;
9090 : : else
9091 : 306895 : TREE_TYPE (data_ref)
9092 : 613790 : = build_aligned_type (TREE_TYPE (data_ref),
9093 : : align * BITS_PER_UNIT);
9094 : 670786 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
9095 : 670786 : new_stmt = gimple_build_assign (data_ref, vec_oprnd);
9096 : 670786 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
9097 : : }
9098 : : }
9099 : :
9100 : 1290815 : if (costing_p)
9101 : : {
9102 : 749394 : if (n_adjacent_stores > 0)
9103 : 749394 : vect_get_store_cost (vinfo, stmt_info, slp_node, n_adjacent_stores,
9104 : : alignment_support_scheme, misalignment,
9105 : : &inside_cost, cost_vec);
9106 : :
9107 : : /* When vectorizing a store into the function result assign
9108 : : a penalty if the function returns in a multi-register location.
9109 : : In this case we assume we'll end up with having to spill the
9110 : : vector result and do piecewise loads as a conservative estimate. */
9111 : 749394 : tree base = get_base_address (STMT_VINFO_DATA_REF (stmt_info)->ref);
9112 : 749394 : if (base
9113 : 749394 : && (TREE_CODE (base) == RESULT_DECL
9114 : 698692 : || (DECL_P (base) && cfun_returns (base)))
9115 : 812086 : && !aggregate_value_p (base, cfun->decl))
9116 : : {
9117 : 11323 : rtx reg = hard_function_value (TREE_TYPE (base), cfun->decl, 0, 1);
9118 : : /* ??? Handle PARALLEL in some way. */
9119 : 11323 : if (REG_P (reg))
9120 : : {
9121 : 11127 : int nregs = hard_regno_nregs (REGNO (reg), GET_MODE (reg));
9122 : : /* Assume that a single reg-reg move is possible and cheap,
9123 : : do not account for vector to gp register move cost. */
9124 : 11127 : if (nregs > 1)
9125 : : {
9126 : : /* Spill. */
9127 : 10255 : prologue_cost
9128 : 10255 : += record_stmt_cost (cost_vec, 1, vector_store,
9129 : : slp_node, 0, vect_epilogue);
9130 : : /* Loads. */
9131 : 10255 : prologue_cost
9132 : 10255 : += record_stmt_cost (cost_vec, nregs, scalar_load,
9133 : : slp_node, 0, vect_epilogue);
9134 : : }
9135 : : }
9136 : : }
9137 : 749394 : if (dump_enabled_p ())
9138 : 12918 : dump_printf_loc (MSG_NOTE, vect_location,
9139 : : "vect_model_store_cost: inside_cost = %d, "
9140 : : "prologue_cost = %d .\n",
9141 : : inside_cost, prologue_cost);
9142 : : }
9143 : :
9144 : 1290815 : return true;
9145 : 2614265 : }
9146 : :
9147 : : /* Given a vector type VECTYPE, turns permutation SEL into the equivalent
9148 : : VECTOR_CST mask. No checks are made that the target platform supports the
9149 : : mask, so callers may wish to test can_vec_perm_const_p separately, or use
9150 : : vect_gen_perm_mask_checked. */
9151 : :
9152 : : tree
9153 : 59624 : vect_gen_perm_mask_any (tree vectype, const vec_perm_indices &sel)
9154 : : {
9155 : 59624 : tree mask_type;
9156 : :
9157 : 59624 : poly_uint64 nunits = sel.length ();
9158 : 59624 : gcc_assert (known_eq (nunits, TYPE_VECTOR_SUBPARTS (vectype)));
9159 : :
9160 : 59624 : mask_type = build_vector_type (ssizetype, nunits);
9161 : 59624 : return vec_perm_indices_to_tree (mask_type, sel);
9162 : : }
9163 : :
9164 : : /* Checked version of vect_gen_perm_mask_any. Asserts can_vec_perm_const_p,
9165 : : i.e. that the target supports the pattern _for arbitrary input vectors_. */
9166 : :
9167 : : tree
9168 : 57158 : vect_gen_perm_mask_checked (tree vectype, const vec_perm_indices &sel)
9169 : : {
9170 : 57158 : machine_mode vmode = TYPE_MODE (vectype);
9171 : 57158 : gcc_assert (can_vec_perm_const_p (vmode, vmode, sel));
9172 : 57158 : return vect_gen_perm_mask_any (vectype, sel);
9173 : : }
9174 : :
9175 : : /* Given a vector variable X and Y, that was generated for the scalar
9176 : : STMT_INFO, generate instructions to permute the vector elements of X and Y
9177 : : using permutation mask MASK_VEC, insert them at *GSI and return the
9178 : : permuted vector variable. */
9179 : :
9180 : : static tree
9181 : 1422 : permute_vec_elements (vec_info *vinfo,
9182 : : tree x, tree y, tree mask_vec, stmt_vec_info stmt_info,
9183 : : gimple_stmt_iterator *gsi)
9184 : : {
9185 : 1422 : tree vectype = TREE_TYPE (x);
9186 : 1422 : tree perm_dest, data_ref;
9187 : 1422 : gimple *perm_stmt;
9188 : :
9189 : 1422 : tree scalar_dest = gimple_get_lhs (stmt_info->stmt);
9190 : 1422 : if (scalar_dest && TREE_CODE (scalar_dest) == SSA_NAME)
9191 : 1422 : perm_dest = vect_create_destination_var (scalar_dest, vectype);
9192 : : else
9193 : 0 : perm_dest = vect_get_new_vect_var (vectype, vect_simple_var, NULL);
9194 : 1422 : data_ref = make_ssa_name (perm_dest);
9195 : :
9196 : : /* Generate the permute statement. */
9197 : 1422 : perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, x, y, mask_vec);
9198 : 1422 : vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
9199 : :
9200 : 1422 : return data_ref;
9201 : : }
9202 : :
9203 : : /* Hoist the definitions of all SSA uses on STMT_INFO out of the loop LOOP,
9204 : : inserting them on the loops preheader edge. Returns true if we
9205 : : were successful in doing so (and thus STMT_INFO can be moved then),
9206 : : otherwise returns false. HOIST_P indicates if we want to hoist the
9207 : : definitions of all SSA uses, it would be false when we are costing. */
9208 : :
9209 : : static bool
9210 : 3831 : hoist_defs_of_uses (gimple *stmt, class loop *loop, bool hoist_p)
9211 : : {
9212 : 3831 : ssa_op_iter i;
9213 : 3831 : use_operand_p use_p;
9214 : 3831 : auto_vec<use_operand_p, 8> to_hoist;
9215 : :
9216 : 7281 : FOR_EACH_SSA_USE_OPERAND (use_p, stmt, i, SSA_OP_USE)
9217 : : {
9218 : 3470 : gimple *def_stmt = SSA_NAME_DEF_STMT (USE_FROM_PTR (use_p));
9219 : 3470 : if (!gimple_nop_p (def_stmt)
9220 : 3470 : && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)))
9221 : : {
9222 : : /* Make sure we don't need to recurse. While we could do
9223 : : so in simple cases when there are more complex use webs
9224 : : we don't have an easy way to preserve stmt order to fulfil
9225 : : dependencies within them. */
9226 : 71 : tree op2;
9227 : 71 : ssa_op_iter i2;
9228 : 71 : if (gimple_code (def_stmt) == GIMPLE_PHI
9229 : 71 : || (single_ssa_def_operand (def_stmt, SSA_OP_DEF)
9230 : : == NULL_DEF_OPERAND_P))
9231 : 20 : return false;
9232 : 138 : FOR_EACH_SSA_TREE_OPERAND (op2, def_stmt, i2, SSA_OP_USE)
9233 : : {
9234 : 87 : gimple *def_stmt2 = SSA_NAME_DEF_STMT (op2);
9235 : 87 : if (!gimple_nop_p (def_stmt2)
9236 : 87 : && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt2)))
9237 : : return false;
9238 : : }
9239 : 51 : to_hoist.safe_push (use_p);
9240 : : }
9241 : : }
9242 : :
9243 : 7622 : if (to_hoist.is_empty ())
9244 : : return true;
9245 : :
9246 : 51 : if (!hoist_p)
9247 : : return true;
9248 : :
9249 : : /* Instead of moving defs we copy them so we can zero their UID to not
9250 : : confuse dominance queries in the preheader. */
9251 : 13 : gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
9252 : 52 : for (use_operand_p use_p : to_hoist)
9253 : : {
9254 : 13 : gimple *def_stmt = SSA_NAME_DEF_STMT (USE_FROM_PTR (use_p));
9255 : 13 : gimple *copy = gimple_copy (def_stmt);
9256 : 13 : gimple_set_uid (copy, 0);
9257 : 13 : def_operand_p def_p = single_ssa_def_operand (def_stmt, SSA_OP_DEF);
9258 : 13 : tree new_def = duplicate_ssa_name (DEF_FROM_PTR (def_p), copy);
9259 : 13 : update_stmt (copy);
9260 : 13 : def_p = single_ssa_def_operand (copy, SSA_OP_DEF);
9261 : 13 : SET_DEF (def_p, new_def);
9262 : 13 : SET_USE (use_p, new_def);
9263 : 13 : gsi_insert_before (&gsi, copy, GSI_SAME_STMT);
9264 : : }
9265 : :
9266 : : return true;
9267 : 3831 : }
9268 : :
9269 : : /* vectorizable_load.
9270 : :
9271 : : Check if STMT_INFO reads a non scalar data-ref (array/pointer/structure)
9272 : : that can be vectorized.
9273 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
9274 : : stmt to replace it, put it in VEC_STMT, and insert it at GSI.
9275 : : Return true if STMT_INFO is vectorizable in this way. */
9276 : :
9277 : : static bool
9278 : 1937640 : vectorizable_load (vec_info *vinfo,
9279 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
9280 : : slp_tree slp_node,
9281 : : stmt_vector_for_cost *cost_vec)
9282 : : {
9283 : 1937640 : tree scalar_dest;
9284 : 1937640 : tree vec_dest = NULL;
9285 : 1937640 : tree data_ref = NULL;
9286 : 1937640 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
9287 : 1937640 : class loop *loop = NULL;
9288 : 1937640 : class loop *containing_loop = gimple_bb (stmt_info->stmt)->loop_father;
9289 : 1937640 : bool nested_in_vect_loop = false;
9290 : 1937640 : tree elem_type;
9291 : : /* Avoid false positive uninitialized warning, see PR110652. */
9292 : 1937640 : tree new_temp = NULL_TREE;
9293 : 1937640 : machine_mode mode;
9294 : 1937640 : tree dummy;
9295 : 1937640 : tree dataref_ptr = NULL_TREE;
9296 : 1937640 : tree dataref_offset = NULL_TREE;
9297 : 1937640 : gimple *ptr_incr = NULL;
9298 : 1937640 : int i, j;
9299 : 1937640 : unsigned int group_size;
9300 : 1937640 : poly_uint64 group_gap_adj;
9301 : 1937640 : tree msq = NULL_TREE, lsq;
9302 : 1937640 : tree realignment_token = NULL_TREE;
9303 : 1937640 : gphi *phi = NULL;
9304 : 1937640 : vec<tree> dr_chain = vNULL;
9305 : 1937640 : bool grouped_load = false;
9306 : 1937640 : stmt_vec_info first_stmt_info;
9307 : 1937640 : stmt_vec_info first_stmt_info_for_drptr = NULL;
9308 : 1937640 : bool compute_in_loop = false;
9309 : 1937640 : class loop *at_loop;
9310 : 1937640 : int vec_num;
9311 : 1937640 : bool slp_perm = false;
9312 : 1937640 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
9313 : 1937640 : poly_uint64 vf;
9314 : 1937640 : tree aggr_type;
9315 : 1937640 : tree ref_type;
9316 : 1937640 : enum vect_def_type mask_dt = vect_unknown_def_type;
9317 : 1937640 : enum vect_def_type els_dt = vect_unknown_def_type;
9318 : :
9319 : 1937640 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
9320 : : return false;
9321 : :
9322 : 1937640 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
9323 : 180307 : && cost_vec)
9324 : : return false;
9325 : :
9326 : 1757333 : if (!STMT_VINFO_DATA_REF (stmt_info))
9327 : : return false;
9328 : :
9329 : 1406700 : tree mask_vectype = NULL_TREE;
9330 : 1406700 : tree els = NULL_TREE; tree els_vectype = NULL_TREE;
9331 : :
9332 : 1406700 : int mask_index = -1;
9333 : 1406700 : int els_index = -1;
9334 : 1406700 : slp_tree mask_node = NULL;
9335 : 1406700 : slp_tree els_op = NULL;
9336 : 1406700 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
9337 : : {
9338 : 1403540 : scalar_dest = gimple_assign_lhs (assign);
9339 : 1403540 : if (TREE_CODE (scalar_dest) != SSA_NAME)
9340 : : return false;
9341 : :
9342 : 626613 : tree_code code = gimple_assign_rhs_code (assign);
9343 : 626613 : if (code != ARRAY_REF
9344 : 626613 : && code != BIT_FIELD_REF
9345 : 626613 : && code != INDIRECT_REF
9346 : 426812 : && code != COMPONENT_REF
9347 : 426812 : && code != IMAGPART_EXPR
9348 : 282927 : && code != REALPART_EXPR
9349 : 282927 : && code != MEM_REF
9350 : 215 : && TREE_CODE_CLASS (code) != tcc_declaration)
9351 : : return false;
9352 : : }
9353 : : else
9354 : : {
9355 : 1312298 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
9356 : 3160 : if (!call || !gimple_call_internal_p (call))
9357 : : return false;
9358 : :
9359 : 3160 : internal_fn ifn = gimple_call_internal_fn (call);
9360 : 3160 : if (!internal_load_fn_p (ifn))
9361 : : return false;
9362 : :
9363 : 2266 : scalar_dest = gimple_call_lhs (call);
9364 : 2266 : if (!scalar_dest)
9365 : : return false;
9366 : :
9367 : 2266 : mask_index = internal_fn_mask_index (ifn);
9368 : 2266 : if (mask_index >= 0)
9369 : 2266 : mask_index = vect_slp_child_index_for_operand
9370 : 2266 : (call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
9371 : 2266 : if (mask_index >= 0
9372 : 2266 : && !vect_check_scalar_mask (vinfo, slp_node, mask_index,
9373 : : &mask_node, &mask_dt, &mask_vectype))
9374 : : return false;
9375 : :
9376 : 2266 : els_index = internal_fn_else_index (ifn);
9377 : 2266 : if (els_index >= 0)
9378 : 2266 : els_index = vect_slp_child_index_for_operand
9379 : 2266 : (call, els_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
9380 : 2266 : if (els_index >= 0
9381 : 2266 : && !vect_is_simple_use (vinfo, slp_node, els_index,
9382 : : &els, &els_op, &els_dt, &els_vectype))
9383 : : return false;
9384 : : }
9385 : :
9386 : 628812 : tree vectype = SLP_TREE_VECTYPE (slp_node);
9387 : 628812 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
9388 : :
9389 : 628812 : if (loop_vinfo)
9390 : : {
9391 : 410657 : loop = LOOP_VINFO_LOOP (loop_vinfo);
9392 : 410657 : nested_in_vect_loop = nested_in_vect_loop_p (loop, stmt_info);
9393 : 410657 : vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
9394 : : }
9395 : : else
9396 : : vf = 1;
9397 : :
9398 : 628812 : vec_num = vect_get_num_copies (vinfo, slp_node);
9399 : :
9400 : : /* FORNOW. This restriction should be relaxed. */
9401 : 628812 : if (nested_in_vect_loop && vec_num > 1)
9402 : : {
9403 : 298 : if (dump_enabled_p ())
9404 : 66 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9405 : : "multiple types in nested loop.\n");
9406 : 298 : return false;
9407 : : }
9408 : :
9409 : 628514 : elem_type = TREE_TYPE (vectype);
9410 : 628514 : mode = TYPE_MODE (vectype);
9411 : :
9412 : : /* FORNOW. In some cases can vectorize even if data-type not supported
9413 : : (e.g. - data copies). */
9414 : 628514 : if (!can_implement_p (mov_optab, mode))
9415 : : {
9416 : 0 : if (dump_enabled_p ())
9417 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9418 : : "Aligned load, but unsupported type.\n");
9419 : 0 : return false;
9420 : : }
9421 : :
9422 : : /* Check if the load is a part of an interleaving chain. */
9423 : 628514 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
9424 : : {
9425 : 306319 : grouped_load = true;
9426 : : /* FORNOW */
9427 : 306319 : gcc_assert (!nested_in_vect_loop);
9428 : 306319 : gcc_assert (!STMT_VINFO_GATHER_SCATTER_P (stmt_info));
9429 : :
9430 : 306319 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
9431 : 306319 : group_size = DR_GROUP_SIZE (first_stmt_info);
9432 : :
9433 : : /* Invalidate assumptions made by dependence analysis when vectorization
9434 : : on the unrolled body effectively re-orders stmts. */
9435 : 306319 : if (STMT_VINFO_MIN_NEG_DIST (stmt_info) != 0
9436 : 306319 : && maybe_gt (LOOP_VINFO_VECT_FACTOR (loop_vinfo),
9437 : : STMT_VINFO_MIN_NEG_DIST (stmt_info)))
9438 : : {
9439 : 12 : if (dump_enabled_p ())
9440 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9441 : : "cannot perform implicit CSE when performing "
9442 : : "group loads with negative dependence distance\n");
9443 : 12 : return false;
9444 : : }
9445 : : }
9446 : : else
9447 : : group_size = 1;
9448 : :
9449 : 628502 : bool perm_ok = true;
9450 : 628502 : unsigned n_perms = -1U;
9451 : 628502 : if (cost_vec && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
9452 : 60515 : perm_ok = vect_transform_slp_perm_load (vinfo, slp_node, vNULL, NULL, vf,
9453 : : true, &n_perms);
9454 : :
9455 : 628502 : vect_load_store_data _ls_data{};
9456 : 628502 : vect_load_store_data &ls = slp_node->get_data (_ls_data);
9457 : 628502 : if (cost_vec
9458 : 628502 : && !get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask_node,
9459 : : VLS_LOAD, perm_ok, &ls))
9460 : : return false;
9461 : : /* Temporary aliases to analysis data, should not be modified through
9462 : : these. */
9463 : 546269 : const vect_memory_access_type memory_access_type = ls.memory_access_type;
9464 : 546269 : const dr_alignment_support alignment_support_scheme
9465 : : = ls.alignment_support_scheme;
9466 : 546269 : const int misalignment = ls.misalignment;
9467 : 546269 : const poly_int64 poffset = ls.poffset;
9468 : 546269 : const vec<int> &elsvals = ls.elsvals;
9469 : :
9470 : 546269 : int maskload_elsval = 0;
9471 : 546269 : bool need_zeroing = false;
9472 : :
9473 : : /* We might need to explicitly zero inactive elements if there are
9474 : : padding bits in the type that might leak otherwise.
9475 : : Refer to PR115336. */
9476 : 546269 : tree scalar_type = TREE_TYPE (scalar_dest);
9477 : 546269 : bool type_mode_padding_p
9478 : 1092538 : = TYPE_PRECISION (scalar_type) < GET_MODE_PRECISION (GET_MODE_INNER (mode));
9479 : :
9480 : : /* ??? The following checks should really be part of
9481 : : get_load_store_type. */
9482 : 546269 : if (SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
9483 : 557401 : && !((memory_access_type == VMAT_ELEMENTWISE
9484 : 57148 : || mat_gather_scatter_p (memory_access_type))
9485 : 11132 : && SLP_TREE_LANES (slp_node) == 1
9486 : : && (!grouped_load
9487 : 11132 : || !DR_GROUP_NEXT_ELEMENT (first_stmt_info))))
9488 : : {
9489 : 57148 : slp_perm = true;
9490 : :
9491 : 57148 : if (!loop_vinfo && cost_vec)
9492 : : {
9493 : : /* In BB vectorization we may not actually use a loaded vector
9494 : : accessing elements in excess of DR_GROUP_SIZE. */
9495 : 23707 : stmt_vec_info group_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
9496 : 23707 : group_info = DR_GROUP_FIRST_ELEMENT (group_info);
9497 : 23707 : unsigned HOST_WIDE_INT nunits;
9498 : 23707 : unsigned j, k, maxk = 0;
9499 : 85097 : FOR_EACH_VEC_ELT (SLP_TREE_LOAD_PERMUTATION (slp_node), j, k)
9500 : 61390 : if (k > maxk)
9501 : : maxk = k;
9502 : 23707 : tree vectype = SLP_TREE_VECTYPE (slp_node);
9503 : 42886 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits)
9504 : 23707 : || maxk >= (DR_GROUP_SIZE (group_info) & ~(nunits - 1)))
9505 : : {
9506 : 4528 : if (dump_enabled_p ())
9507 : 31 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9508 : : "BB vectorization with gaps at the end of "
9509 : : "a load is not supported\n");
9510 : 4528 : return false;
9511 : : }
9512 : : }
9513 : :
9514 : 52620 : if (cost_vec)
9515 : : {
9516 : 34954 : if (!perm_ok)
9517 : : {
9518 : 2525 : if (dump_enabled_p ())
9519 : 122 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
9520 : : vect_location,
9521 : : "unsupported load permutation\n");
9522 : 2525 : return false;
9523 : : }
9524 : 32429 : ls.n_perms = n_perms;
9525 : : }
9526 : : else
9527 : 17666 : n_perms = ls.n_perms;
9528 : : }
9529 : :
9530 : 539216 : if (slp_node->ldst_lanes
9531 : 0 : && memory_access_type != VMAT_LOAD_STORE_LANES)
9532 : : {
9533 : 0 : if (dump_enabled_p ())
9534 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9535 : : "discovered load-lane but cannot use it.\n");
9536 : 0 : return false;
9537 : : }
9538 : :
9539 : 539216 : if (mask_node)
9540 : : {
9541 : 2146 : if (memory_access_type == VMAT_CONTIGUOUS)
9542 : : {
9543 : 1364 : machine_mode vec_mode = TYPE_MODE (vectype);
9544 : 361 : if (!VECTOR_MODE_P (vec_mode)
9545 : 2728 : || !can_vec_mask_load_store_p (vec_mode,
9546 : 1364 : TYPE_MODE (mask_vectype),
9547 : : true, NULL, &ls.elsvals))
9548 : 61 : return false;
9549 : : }
9550 : 782 : else if (memory_access_type != VMAT_LOAD_STORE_LANES
9551 : 782 : && !mat_gather_scatter_p (memory_access_type))
9552 : : {
9553 : 62 : if (dump_enabled_p ())
9554 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9555 : : "unsupported access type for masked load.\n");
9556 : 62 : return false;
9557 : : }
9558 : 720 : else if (memory_access_type == VMAT_GATHER_SCATTER_EMULATED)
9559 : : {
9560 : 476 : if (dump_enabled_p ())
9561 : 26 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9562 : : "unsupported masked emulated gather.\n");
9563 : 476 : return false;
9564 : : }
9565 : : else if (memory_access_type == VMAT_ELEMENTWISE
9566 : : || memory_access_type == VMAT_STRIDED_SLP)
9567 : : {
9568 : : if (dump_enabled_p ())
9569 : : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9570 : : "unsupported masked strided access.\n");
9571 : : return false;
9572 : : }
9573 : : }
9574 : :
9575 : 538617 : bool costing_p = cost_vec;
9576 : :
9577 : 538617 : if (costing_p) /* transformation not required. */
9578 : : {
9579 : 374518 : if (mask_node
9580 : 374518 : && !vect_maybe_update_slp_op_vectype (mask_node,
9581 : : mask_vectype))
9582 : : {
9583 : 0 : if (dump_enabled_p ())
9584 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9585 : : "incompatible vector types for invariants\n");
9586 : 0 : return false;
9587 : : }
9588 : :
9589 : 374518 : if (loop_vinfo
9590 : 248471 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
9591 : 90 : check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
9592 : : VLS_LOAD, group_size, &ls,
9593 : : mask_node, &ls.elsvals);
9594 : :
9595 : 374518 : if (dump_enabled_p ()
9596 : 23475 : && memory_access_type != VMAT_ELEMENTWISE
9597 : 23370 : && !mat_gather_scatter_p (memory_access_type)
9598 : 23148 : && memory_access_type != VMAT_STRIDED_SLP
9599 : 23148 : && memory_access_type != VMAT_INVARIANT
9600 : 396830 : && alignment_support_scheme != dr_aligned)
9601 : 8805 : dump_printf_loc (MSG_NOTE, vect_location,
9602 : : "Vectorizing an unaligned access.\n");
9603 : :
9604 : 374518 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
9605 : 0 : vinfo->any_known_not_updated_vssa = true;
9606 : :
9607 : 374518 : SLP_TREE_TYPE (slp_node) = load_vec_info_type;
9608 : 374518 : slp_node->data = new vect_load_store_data (std::move (ls));
9609 : : }
9610 : :
9611 : : /* If the type needs padding we must zero inactive elements.
9612 : : Check if we can do that with a VEC_COND_EXPR and store the
9613 : : elsval we choose in MASKLOAD_ELSVAL. */
9614 : 538617 : if (elsvals.length ()
9615 : 506 : && type_mode_padding_p
9616 : 0 : && !elsvals.contains (MASK_LOAD_ELSE_ZERO)
9617 : 506 : && !expand_vec_cond_expr_p (vectype, truth_type_for (vectype)))
9618 : : {
9619 : 0 : if (dump_enabled_p ())
9620 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9621 : : "cannot zero inactive elements.\n");
9622 : 0 : return false;
9623 : : }
9624 : :
9625 : : /* For now just use the first available else value.
9626 : : get_supported_else_vals tries MASK_LOAD_ELSE_ZERO first so we will
9627 : : select it here if it is supported. */
9628 : 538617 : if (elsvals.length ())
9629 : 506 : maskload_elsval = *elsvals.begin ();
9630 : :
9631 : 538617 : if (dump_enabled_p () && !costing_p)
9632 : 15773 : dump_printf_loc (MSG_NOTE, vect_location, "transform load.\n");
9633 : :
9634 : : /* Transform. */
9635 : :
9636 : 538617 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL;
9637 : 538617 : ensure_base_align (dr_info);
9638 : :
9639 : 538617 : if (memory_access_type == VMAT_INVARIANT)
9640 : : {
9641 : 3813 : gcc_assert (!grouped_load && !mask_node && !bb_vinfo);
9642 : : /* If we have versioned for aliasing or the loop doesn't
9643 : : have any data dependencies that would preclude this,
9644 : : then we are sure this is a loop invariant load and
9645 : : thus we can insert it on the preheader edge.
9646 : : TODO: hoist_defs_of_uses should ideally be computed
9647 : : once at analysis time, remembered and used in the
9648 : : transform time. */
9649 : 3813 : bool hoist_p = (LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo)
9650 : 3617 : && !nested_in_vect_loop
9651 : 7014 : && hoist_defs_of_uses (stmt_info->stmt, loop, false));
9652 : 3813 : if (costing_p)
9653 : : {
9654 : 438 : enum vect_cost_model_location cost_loc
9655 : 2989 : = hoist_p ? vect_prologue : vect_body;
9656 : 2989 : unsigned int cost = record_stmt_cost (cost_vec, 1, scalar_load,
9657 : : slp_node, 0, cost_loc);
9658 : 2989 : cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
9659 : : slp_node, 0, cost_loc);
9660 : 2989 : unsigned int prologue_cost = hoist_p ? cost : 0;
9661 : 438 : unsigned int inside_cost = hoist_p ? 0 : cost;
9662 : 2989 : if (dump_enabled_p ())
9663 : 451 : dump_printf_loc (MSG_NOTE, vect_location,
9664 : : "vect_model_load_cost: inside_cost = %d, "
9665 : : "prologue_cost = %d .\n",
9666 : : inside_cost, prologue_cost);
9667 : 2989 : return true;
9668 : : }
9669 : 824 : if (hoist_p)
9670 : : {
9671 : 630 : gassign *stmt = as_a <gassign *> (stmt_info->stmt);
9672 : 630 : if (dump_enabled_p ())
9673 : 210 : dump_printf_loc (MSG_NOTE, vect_location,
9674 : : "hoisting out of the vectorized loop: %G",
9675 : : (gimple *) stmt);
9676 : 630 : scalar_dest = copy_ssa_name (scalar_dest);
9677 : 630 : tree rhs = unshare_expr (gimple_assign_rhs1 (stmt));
9678 : 630 : edge pe = loop_preheader_edge (loop);
9679 : 630 : gphi *vphi = get_virtual_phi (loop->header);
9680 : 630 : tree vuse;
9681 : 630 : if (vphi)
9682 : 624 : vuse = PHI_ARG_DEF_FROM_EDGE (vphi, pe);
9683 : : else
9684 : 6 : vuse = gimple_vuse (gsi_stmt (*gsi));
9685 : 630 : gimple *new_stmt = gimple_build_assign (scalar_dest, rhs);
9686 : 630 : gimple_set_vuse (new_stmt, vuse);
9687 : 630 : gsi_insert_on_edge_immediate (pe, new_stmt);
9688 : 630 : hoist_defs_of_uses (new_stmt, loop, true);
9689 : : }
9690 : : /* These copies are all equivalent. */
9691 : 824 : if (hoist_p)
9692 : 630 : new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest,
9693 : : vectype, NULL);
9694 : : else
9695 : : {
9696 : 194 : gimple_stmt_iterator gsi2 = *gsi;
9697 : 194 : gsi_next (&gsi2);
9698 : 194 : new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest,
9699 : : vectype, &gsi2);
9700 : : }
9701 : 824 : gimple *new_stmt = SSA_NAME_DEF_STMT (new_temp);
9702 : 1725 : for (j = 0; j < (int) vec_num; ++j)
9703 : 901 : slp_node->push_vec_def (new_stmt);
9704 : : return true;
9705 : : }
9706 : :
9707 : 534804 : if (memory_access_type == VMAT_ELEMENTWISE
9708 : 534804 : || memory_access_type == VMAT_STRIDED_SLP)
9709 : : {
9710 : 27997 : gimple_stmt_iterator incr_gsi;
9711 : 27997 : bool insert_after;
9712 : 27997 : tree offvar = NULL_TREE;
9713 : 27997 : tree ivstep;
9714 : 27997 : tree running_off;
9715 : 27997 : vec<constructor_elt, va_gc> *v = NULL;
9716 : 27997 : tree stride_base, stride_step, alias_off;
9717 : : /* Checked by get_load_store_type. */
9718 : 27997 : unsigned int const_nunits = nunits.to_constant ();
9719 : 27997 : unsigned HOST_WIDE_INT cst_offset = 0;
9720 : 27997 : tree dr_offset;
9721 : 27997 : unsigned int inside_cost = 0;
9722 : :
9723 : 27997 : gcc_assert (!LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo));
9724 : 27997 : gcc_assert (!nested_in_vect_loop);
9725 : :
9726 : 27997 : if (grouped_load)
9727 : : {
9728 : 15398 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
9729 : 15398 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
9730 : : }
9731 : : else
9732 : : {
9733 : : first_stmt_info = stmt_info;
9734 : : first_dr_info = dr_info;
9735 : : }
9736 : :
9737 : 27997 : if (grouped_load && memory_access_type == VMAT_STRIDED_SLP)
9738 : : {
9739 : 4186 : group_size = DR_GROUP_SIZE (first_stmt_info);
9740 : 4186 : ref_type = get_group_alias_ptr_type (first_stmt_info);
9741 : : }
9742 : : else
9743 : : {
9744 : 23811 : if (grouped_load)
9745 : 11212 : cst_offset
9746 : 11212 : = (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)))
9747 : 11212 : * vect_get_place_in_interleaving_chain (stmt_info,
9748 : : first_stmt_info));
9749 : 23811 : group_size = 1;
9750 : 23811 : ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr));
9751 : : }
9752 : :
9753 : 27997 : if (!costing_p)
9754 : : {
9755 : 3365 : dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info);
9756 : 3365 : stride_base = fold_build_pointer_plus (
9757 : : DR_BASE_ADDRESS (first_dr_info->dr),
9758 : : size_binop (PLUS_EXPR, convert_to_ptrofftype (dr_offset),
9759 : : convert_to_ptrofftype (DR_INIT (first_dr_info->dr))));
9760 : 3365 : stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr));
9761 : :
9762 : : /* For a load with loop-invariant (but other than power-of-2)
9763 : : stride (i.e. not a grouped access) like so:
9764 : :
9765 : : for (i = 0; i < n; i += stride)
9766 : : ... = array[i];
9767 : :
9768 : : we generate a new induction variable and new accesses to
9769 : : form a new vector (or vectors, depending on ncopies):
9770 : :
9771 : : for (j = 0; ; j += VF*stride)
9772 : : tmp1 = array[j];
9773 : : tmp2 = array[j + stride];
9774 : : ...
9775 : : vectemp = {tmp1, tmp2, ...}
9776 : : */
9777 : :
9778 : 3365 : ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (stride_step), stride_step,
9779 : : build_int_cst (TREE_TYPE (stride_step), vf));
9780 : :
9781 : 3365 : standard_iv_increment_position (loop, &incr_gsi, &insert_after);
9782 : :
9783 : 3365 : stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base);
9784 : 3365 : ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep);
9785 : 3365 : create_iv (stride_base, PLUS_EXPR, ivstep, NULL,
9786 : : loop, &incr_gsi, insert_after,
9787 : : &offvar, NULL);
9788 : :
9789 : 3365 : stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step);
9790 : : }
9791 : :
9792 : 27997 : running_off = offvar;
9793 : 27997 : alias_off = build_int_cst (ref_type, 0);
9794 : 27997 : int nloads = const_nunits;
9795 : 27997 : int lnel = 1;
9796 : 27997 : tree ltype = TREE_TYPE (vectype);
9797 : 27997 : tree lvectype = vectype;
9798 : 27997 : auto_vec<tree> dr_chain;
9799 : : /* ??? Modify local copies of alignment_support_scheme and
9800 : : misalignment, but this part of analysis should be done
9801 : : earlier and remembered, likewise the chosen load mode. */
9802 : 27997 : const dr_alignment_support tem = alignment_support_scheme;
9803 : 27997 : dr_alignment_support alignment_support_scheme = tem;
9804 : 27997 : const int tem2 = misalignment;
9805 : 27997 : int misalignment = tem2;
9806 : 27997 : if (memory_access_type == VMAT_STRIDED_SLP)
9807 : : {
9808 : 16785 : HOST_WIDE_INT n = gcd (group_size, const_nunits);
9809 : : /* Use the target vector type if the group size is a multiple
9810 : : of it. */
9811 : 16785 : if (n == const_nunits)
9812 : : {
9813 : 2268 : int mis_align = dr_misalignment (first_dr_info, vectype);
9814 : : /* With VF > 1 we advance the DR by step, if that is constant
9815 : : and only aligned when performed VF times, DR alignment
9816 : : analysis can analyze this as aligned since it assumes
9817 : : contiguous accesses. But that is not how we code generate
9818 : : here, so adjust for this. */
9819 : 2268 : if (maybe_gt (vf, 1u)
9820 : 3970 : && !multiple_p (DR_STEP_ALIGNMENT (first_dr_info->dr),
9821 : 3766 : DR_TARGET_ALIGNMENT (first_dr_info)))
9822 : 204 : mis_align = -1;
9823 : 2268 : dr_alignment_support dr_align
9824 : 2268 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype,
9825 : : mis_align);
9826 : 2268 : if (dr_align == dr_aligned
9827 : 2268 : || dr_align == dr_unaligned_supported)
9828 : : {
9829 : 16785 : nloads = 1;
9830 : 16785 : lnel = const_nunits;
9831 : 16785 : ltype = vectype;
9832 : 16785 : alignment_support_scheme = dr_align;
9833 : 16785 : misalignment = mis_align;
9834 : : }
9835 : : }
9836 : : /* Else use the biggest vector we can load the group without
9837 : : accessing excess elements. */
9838 : 14517 : else if (n > 1)
9839 : : {
9840 : 1925 : tree ptype;
9841 : 1925 : tree vtype
9842 : 1925 : = vector_vector_composition_type (vectype, const_nunits / n,
9843 : : &ptype);
9844 : 1925 : if (vtype != NULL_TREE)
9845 : : {
9846 : 1883 : dr_alignment_support dr_align;
9847 : 1883 : int mis_align = 0;
9848 : 1883 : if (VECTOR_TYPE_P (ptype))
9849 : : {
9850 : 971 : mis_align = dr_misalignment (first_dr_info, ptype);
9851 : 971 : if (maybe_gt (vf, 1u)
9852 : 1914 : && !multiple_p (DR_STEP_ALIGNMENT (first_dr_info->dr),
9853 : 977 : DR_TARGET_ALIGNMENT (first_dr_info)))
9854 : 937 : mis_align = -1;
9855 : 971 : dr_align
9856 : 971 : = vect_supportable_dr_alignment (vinfo, dr_info, ptype,
9857 : : mis_align);
9858 : : }
9859 : : else
9860 : : dr_align = dr_unaligned_supported;
9861 : 1883 : if (dr_align == dr_aligned
9862 : 1883 : || dr_align == dr_unaligned_supported)
9863 : : {
9864 : 1883 : nloads = const_nunits / n;
9865 : 1883 : lnel = n;
9866 : 1883 : lvectype = vtype;
9867 : 1883 : ltype = ptype;
9868 : 1883 : alignment_support_scheme = dr_align;
9869 : 1883 : misalignment = mis_align;
9870 : : }
9871 : : }
9872 : : }
9873 : 16785 : unsigned align;
9874 : 16785 : if (alignment_support_scheme == dr_aligned)
9875 : 20 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
9876 : : else
9877 : 16765 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
9878 : : /* Alignment is at most the access size if we do multiple loads. */
9879 : 16785 : if (nloads > 1)
9880 : 14517 : align = MIN (tree_to_uhwi (TYPE_SIZE_UNIT (ltype)), align);
9881 : 16785 : ltype = build_aligned_type (ltype, align * BITS_PER_UNIT);
9882 : : }
9883 : :
9884 : : /* For SLP permutation support we need to load the whole group,
9885 : : not only the number of vector stmts the permutation result
9886 : : fits in. */
9887 : 27997 : int ncopies;
9888 : 27997 : if (slp_perm)
9889 : : {
9890 : : /* We don't yet generate SLP_TREE_LOAD_PERMUTATIONs for
9891 : : variable VF. */
9892 : 2501 : unsigned int const_vf = vf.to_constant ();
9893 : 2501 : ncopies = CEIL (group_size * const_vf, const_nunits);
9894 : 2501 : dr_chain.create (ncopies);
9895 : : }
9896 : : else
9897 : : ncopies = vec_num;
9898 : :
9899 : 27997 : unsigned int group_el = 0;
9900 : 27997 : unsigned HOST_WIDE_INT
9901 : 27997 : elsz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
9902 : 27997 : unsigned int n_groups = 0;
9903 : : /* For costing some adjacent vector loads, we'd like to cost with
9904 : : the total number of them once instead of cost each one by one. */
9905 : 27997 : unsigned int n_adjacent_loads = 0;
9906 : 69856 : for (j = 0; j < ncopies; j++)
9907 : : {
9908 : 41859 : if (nloads > 1 && !costing_p)
9909 : 2755 : vec_alloc (v, nloads);
9910 : : gimple *new_stmt = NULL;
9911 : 168597 : for (i = 0; i < nloads; i++)
9912 : : {
9913 : 126738 : if (costing_p)
9914 : : {
9915 : : /* For VMAT_ELEMENTWISE, just cost it as scalar_load to
9916 : : avoid ICE, see PR110776. */
9917 : 116726 : if (VECTOR_TYPE_P (ltype)
9918 : 5722 : && memory_access_type != VMAT_ELEMENTWISE)
9919 : 5722 : n_adjacent_loads++;
9920 : : else
9921 : 111004 : inside_cost += record_stmt_cost (cost_vec, 1, scalar_load,
9922 : : slp_node, 0, vect_body);
9923 : 116726 : continue;
9924 : : }
9925 : 10012 : tree this_off = build_int_cst (TREE_TYPE (alias_off),
9926 : 10012 : group_el * elsz + cst_offset);
9927 : 10012 : tree data_ref = build2 (MEM_REF, ltype, running_off, this_off);
9928 : 10012 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
9929 : 10012 : new_temp = make_ssa_name (ltype);
9930 : 10012 : new_stmt = gimple_build_assign (new_temp, data_ref);
9931 : 10012 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
9932 : 10012 : if (nloads > 1)
9933 : 7988 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, new_temp);
9934 : :
9935 : 10012 : group_el += lnel;
9936 : 10012 : if (group_el == group_size)
9937 : : {
9938 : 9666 : n_groups++;
9939 : : /* When doing SLP make sure to not load elements from
9940 : : the next vector iteration, those will not be accessed
9941 : : so just use the last element again. See PR107451. */
9942 : 9666 : if (known_lt (n_groups, vf))
9943 : : {
9944 : 6279 : tree newoff = copy_ssa_name (running_off);
9945 : 6279 : gimple *incr
9946 : 6279 : = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
9947 : : running_off, stride_step);
9948 : 6279 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
9949 : 6279 : running_off = newoff;
9950 : : }
9951 : : group_el = 0;
9952 : : }
9953 : : }
9954 : :
9955 : 41859 : if (nloads > 1)
9956 : : {
9957 : 31529 : if (costing_p)
9958 : 28774 : inside_cost += record_stmt_cost (cost_vec, 1, vec_construct,
9959 : : slp_node, 0, vect_body);
9960 : : else
9961 : : {
9962 : 2755 : tree vec_inv = build_constructor (lvectype, v);
9963 : 2755 : new_temp = vect_init_vector (vinfo, stmt_info, vec_inv,
9964 : : lvectype, gsi);
9965 : 2755 : new_stmt = SSA_NAME_DEF_STMT (new_temp);
9966 : 2755 : if (lvectype != vectype)
9967 : : {
9968 : 241 : new_stmt
9969 : 241 : = gimple_build_assign (make_ssa_name (vectype),
9970 : : VIEW_CONVERT_EXPR,
9971 : : build1 (VIEW_CONVERT_EXPR,
9972 : : vectype, new_temp));
9973 : 241 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
9974 : : gsi);
9975 : : }
9976 : : }
9977 : : }
9978 : 10330 : else if (!costing_p && ltype != vectype)
9979 : : {
9980 : 1999 : new_stmt = gimple_build_assign (make_ssa_name (vectype),
9981 : : VIEW_CONVERT_EXPR,
9982 : : build1 (VIEW_CONVERT_EXPR,
9983 : : vectype, new_temp));
9984 : 1999 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
9985 : : gsi);
9986 : : }
9987 : :
9988 : 41859 : if (!costing_p)
9989 : : {
9990 : 4779 : if (slp_perm)
9991 : 1464 : dr_chain.quick_push (gimple_assign_lhs (new_stmt));
9992 : : else
9993 : 3315 : slp_node->push_vec_def (new_stmt);
9994 : : }
9995 : : }
9996 : 27997 : if (slp_perm)
9997 : : {
9998 : 2501 : if (costing_p)
9999 : : {
10000 : 1829 : gcc_assert (n_perms != -1U);
10001 : 1829 : inside_cost += record_stmt_cost (cost_vec, n_perms, vec_perm,
10002 : : slp_node, 0, vect_body);
10003 : : }
10004 : : else
10005 : : {
10006 : 672 : unsigned n_perms2;
10007 : 672 : vect_transform_slp_perm_load (vinfo, slp_node, dr_chain, gsi, vf,
10008 : : false, &n_perms2);
10009 : 672 : gcc_assert (n_perms == n_perms2);
10010 : : }
10011 : : }
10012 : :
10013 : 27997 : if (costing_p)
10014 : : {
10015 : 24632 : if (n_adjacent_loads > 0)
10016 : 2078 : vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
10017 : : alignment_support_scheme, misalignment, false,
10018 : : &inside_cost, nullptr, cost_vec, cost_vec,
10019 : : true);
10020 : 24632 : if (dump_enabled_p ())
10021 : 490 : dump_printf_loc (MSG_NOTE, vect_location,
10022 : : "vect_model_load_cost: inside_cost = %u, "
10023 : : "prologue_cost = 0 .\n",
10024 : : inside_cost);
10025 : : }
10026 : :
10027 : 27997 : return true;
10028 : 27997 : }
10029 : :
10030 : 506807 : if (mat_gather_scatter_p (memory_access_type))
10031 : : grouped_load = false;
10032 : :
10033 : 504116 : if (grouped_load
10034 : 506807 : || SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
10035 : : {
10036 : 259994 : if (grouped_load)
10037 : : {
10038 : 259747 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
10039 : 259747 : group_size = DR_GROUP_SIZE (first_stmt_info);
10040 : : }
10041 : : else
10042 : : {
10043 : : first_stmt_info = stmt_info;
10044 : : group_size = 1;
10045 : : }
10046 : : /* For SLP vectorization we directly vectorize a subchain
10047 : : without permutation. */
10048 : 259994 : if (! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
10049 : 212827 : first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
10050 : : /* For BB vectorization always use the first stmt to base
10051 : : the data ref pointer on. */
10052 : 259994 : if (bb_vinfo)
10053 : 211554 : first_stmt_info_for_drptr
10054 : 211554 : = vect_find_first_scalar_stmt_in_slp (slp_node);
10055 : :
10056 : 259994 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
10057 : 259994 : group_gap_adj = 0;
10058 : :
10059 : : /* VEC_NUM is the number of vect stmts to be created for this group. */
10060 : 259994 : grouped_load = false;
10061 : : /* If an SLP permutation is from N elements to N elements,
10062 : : and if one vector holds a whole number of N, we can load
10063 : : the inputs to the permutation in the same way as an
10064 : : unpermuted sequence. In other cases we need to load the
10065 : : whole group, not only the number of vector stmts the
10066 : : permutation result fits in. */
10067 : 259994 : unsigned scalar_lanes = SLP_TREE_LANES (slp_node);
10068 : 259994 : if (nested_in_vect_loop)
10069 : : /* We do not support grouped accesses in a nested loop,
10070 : : instead the access is contiguous but it might be
10071 : : permuted. No gap adjustment is needed though. */
10072 : : ;
10073 : 259992 : else if (slp_perm
10074 : 259992 : && (group_size != scalar_lanes
10075 : 13777 : || !multiple_p (nunits, group_size)))
10076 : : {
10077 : : /* We don't yet generate such SLP_TREE_LOAD_PERMUTATIONs for
10078 : : variable VF; see vect_transform_slp_perm_load. */
10079 : 34458 : unsigned int const_vf = vf.to_constant ();
10080 : 34458 : unsigned int const_nunits = nunits.to_constant ();
10081 : 34458 : vec_num = CEIL (group_size * const_vf, const_nunits);
10082 : 34458 : group_gap_adj = vf * group_size - nunits * vec_num;
10083 : : }
10084 : : else
10085 : : {
10086 : 225534 : group_gap_adj = group_size - scalar_lanes;
10087 : : }
10088 : :
10089 : 259994 : ref_type = get_group_alias_ptr_type (first_stmt_info);
10090 : : }
10091 : : else
10092 : : {
10093 : 246813 : first_stmt_info = stmt_info;
10094 : 246813 : first_dr_info = dr_info;
10095 : 246813 : group_size = 1;
10096 : 246813 : group_gap_adj = 0;
10097 : 246813 : ref_type = reference_alias_ptr_type (DR_REF (first_dr_info->dr));
10098 : : }
10099 : :
10100 : 506807 : vec_loop_masks *loop_masks
10101 : 295253 : = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
10102 : 506807 : ? &LOOP_VINFO_MASKS (loop_vinfo)
10103 : 23 : : NULL);
10104 : 23 : vec_loop_lens *loop_lens
10105 : 295253 : = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)
10106 : : ? &LOOP_VINFO_LENS (loop_vinfo)
10107 : 0 : : NULL);
10108 : :
10109 : : /* The vect_transform_stmt and vect_analyze_stmt will go here but there
10110 : : are some difference here. We cannot enable both the lens and masks
10111 : : during transform but it is allowed during analysis.
10112 : : Shouldn't go with length-based approach if fully masked. */
10113 : 506807 : if (cost_vec == NULL)
10114 : : /* The cost_vec is NULL during transfrom. */
10115 : 159910 : gcc_assert ((!loop_lens || !loop_masks));
10116 : :
10117 : : /* Targets with store-lane instructions must not require explicit
10118 : : realignment. vect_supportable_dr_alignment always returns either
10119 : : dr_aligned or dr_unaligned_supported for (non-length) masked
10120 : : operations. */
10121 : 506807 : gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES
10122 : : && !mask_node
10123 : : && !loop_masks)
10124 : : || mat_gather_scatter_p (memory_access_type)
10125 : : || alignment_support_scheme == dr_aligned
10126 : : || alignment_support_scheme == dr_unaligned_supported);
10127 : :
10128 : : /* In case the vectorization factor (VF) is bigger than the number
10129 : : of elements that we can fit in a vectype (nunits), we have to generate
10130 : : more than one vector stmt - i.e - we need to "unroll" the
10131 : : vector stmt by a factor VF/nunits. In doing so, we record a pointer
10132 : : from one copy of the vector stmt to the next, in the field
10133 : : STMT_VINFO_RELATED_STMT. This is necessary in order to allow following
10134 : : stages to find the correct vector defs to be used when vectorizing
10135 : : stmts that use the defs of the current stmt. The example below
10136 : : illustrates the vectorization process when VF=16 and nunits=4 (i.e., we
10137 : : need to create 4 vectorized stmts):
10138 : :
10139 : : before vectorization:
10140 : : RELATED_STMT VEC_STMT
10141 : : S1: x = memref - -
10142 : : S2: z = x + 1 - -
10143 : :
10144 : : step 1: vectorize stmt S1:
10145 : : We first create the vector stmt VS1_0, and, as usual, record a
10146 : : pointer to it in the STMT_VINFO_VEC_STMT of the scalar stmt S1.
10147 : : Next, we create the vector stmt VS1_1, and record a pointer to
10148 : : it in the STMT_VINFO_RELATED_STMT of the vector stmt VS1_0.
10149 : : Similarly, for VS1_2 and VS1_3. This is the resulting chain of
10150 : : stmts and pointers:
10151 : : RELATED_STMT VEC_STMT
10152 : : VS1_0: vx0 = memref0 VS1_1 -
10153 : : VS1_1: vx1 = memref1 VS1_2 -
10154 : : VS1_2: vx2 = memref2 VS1_3 -
10155 : : VS1_3: vx3 = memref3 - -
10156 : : S1: x = load - VS1_0
10157 : : S2: z = x + 1 - -
10158 : : */
10159 : :
10160 : : /* If the data reference is aligned (dr_aligned) or potentially unaligned
10161 : : on a target that supports unaligned accesses (dr_unaligned_supported)
10162 : : we generate the following code:
10163 : : p = initial_addr;
10164 : : indx = 0;
10165 : : loop {
10166 : : p = p + indx * vectype_size;
10167 : : vec_dest = *(p);
10168 : : indx = indx + 1;
10169 : : }
10170 : :
10171 : : Otherwise, the data reference is potentially unaligned on a target that
10172 : : does not support unaligned accesses (dr_explicit_realign_optimized) -
10173 : : then generate the following code, in which the data in each iteration is
10174 : : obtained by two vector loads, one from the previous iteration, and one
10175 : : from the current iteration:
10176 : : p1 = initial_addr;
10177 : : msq_init = *(floor(p1))
10178 : : p2 = initial_addr + VS - 1;
10179 : : realignment_token = call target_builtin;
10180 : : indx = 0;
10181 : : loop {
10182 : : p2 = p2 + indx * vectype_size
10183 : : lsq = *(floor(p2))
10184 : : vec_dest = realign_load (msq, lsq, realignment_token)
10185 : : indx = indx + 1;
10186 : : msq = lsq;
10187 : : } */
10188 : :
10189 : : /* If the misalignment remains the same throughout the execution of the
10190 : : loop, we can create the init_addr and permutation mask at the loop
10191 : : preheader. Otherwise, it needs to be created inside the loop.
10192 : : This can only occur when vectorizing memory accesses in the inner-loop
10193 : : nested within an outer-loop that is being vectorized. */
10194 : :
10195 : 506807 : if (nested_in_vect_loop
10196 : 506807 : && !multiple_p (DR_STEP_ALIGNMENT (dr_info->dr),
10197 : 1228 : GET_MODE_SIZE (TYPE_MODE (vectype))))
10198 : : {
10199 : 191 : gcc_assert (alignment_support_scheme != dr_explicit_realign_optimized);
10200 : : compute_in_loop = true;
10201 : : }
10202 : :
10203 : 506807 : bool diff_first_stmt_info
10204 : 506807 : = first_stmt_info_for_drptr && first_stmt_info != first_stmt_info_for_drptr;
10205 : :
10206 : 506807 : tree offset = NULL_TREE;
10207 : 506807 : if ((alignment_support_scheme == dr_explicit_realign_optimized
10208 : 506807 : || alignment_support_scheme == dr_explicit_realign)
10209 : 0 : && !compute_in_loop)
10210 : : {
10211 : : /* If we have different first_stmt_info, we can't set up realignment
10212 : : here, since we can't guarantee first_stmt_info DR has been
10213 : : initialized yet, use first_stmt_info_for_drptr DR by bumping the
10214 : : distance from first_stmt_info DR instead as below. */
10215 : 0 : if (!costing_p)
10216 : : {
10217 : 0 : if (!diff_first_stmt_info)
10218 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info, vectype, gsi,
10219 : : &realignment_token,
10220 : : alignment_support_scheme, NULL_TREE,
10221 : : &at_loop);
10222 : 0 : if (alignment_support_scheme == dr_explicit_realign_optimized)
10223 : : {
10224 : 0 : phi = as_a<gphi *> (SSA_NAME_DEF_STMT (msq));
10225 : 0 : offset = size_binop (MINUS_EXPR, TYPE_SIZE_UNIT (vectype),
10226 : : size_one_node);
10227 : 0 : gcc_assert (!first_stmt_info_for_drptr);
10228 : : }
10229 : : }
10230 : : }
10231 : : else
10232 : 506807 : at_loop = loop;
10233 : :
10234 : 506807 : if (!known_eq (poffset, 0))
10235 : 4449 : offset = (offset
10236 : 4449 : ? size_binop (PLUS_EXPR, offset, size_int (poffset))
10237 : 4449 : : size_int (poffset));
10238 : :
10239 : 506807 : tree bump;
10240 : 506807 : tree vec_offset = NULL_TREE;
10241 : :
10242 : 506807 : auto_vec<tree> vec_offsets;
10243 : 506807 : auto_vec<tree> vec_masks;
10244 : 506807 : if (mask_node && !costing_p)
10245 : 584 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[mask_index],
10246 : : &vec_masks);
10247 : :
10248 : 506807 : tree vec_mask = NULL_TREE;
10249 : 506807 : tree vec_els = NULL_TREE;
10250 : 506807 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
10251 : : {
10252 : 0 : const internal_fn lanes_ifn = ls.lanes_ifn;
10253 : :
10254 : 0 : gcc_assert (alignment_support_scheme == dr_aligned
10255 : : || alignment_support_scheme == dr_unaligned_supported);
10256 : :
10257 : 0 : aggr_type = build_array_type_nelts (elem_type, group_size * nunits);
10258 : 0 : if (!costing_p)
10259 : 0 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
10260 : : memory_access_type, loop_lens);
10261 : :
10262 : 0 : unsigned int inside_cost = 0, prologue_cost = 0;
10263 : : /* For costing some adjacent vector loads, we'd like to cost with
10264 : : the total number of them once instead of cost each one by one. */
10265 : 0 : unsigned int n_adjacent_loads = 0;
10266 : 0 : int ncopies = vec_num / group_size;
10267 : 0 : for (j = 0; j < ncopies; j++)
10268 : : {
10269 : 0 : if (costing_p)
10270 : : {
10271 : : /* An IFN_LOAD_LANES will load all its vector results,
10272 : : regardless of which ones we actually need. Account
10273 : : for the cost of unused results. */
10274 : 0 : if (first_stmt_info == stmt_info)
10275 : : {
10276 : 0 : unsigned int gaps = DR_GROUP_SIZE (first_stmt_info);
10277 : 0 : stmt_vec_info next_stmt_info = first_stmt_info;
10278 : 0 : do
10279 : : {
10280 : 0 : gaps -= 1;
10281 : 0 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
10282 : : }
10283 : 0 : while (next_stmt_info);
10284 : 0 : if (gaps)
10285 : : {
10286 : 0 : if (dump_enabled_p ())
10287 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
10288 : : "vect_model_load_cost: %d "
10289 : : "unused vectors.\n",
10290 : : gaps);
10291 : 0 : vect_get_load_cost (vinfo, stmt_info, slp_node, gaps,
10292 : : alignment_support_scheme,
10293 : : misalignment, false, &inside_cost,
10294 : : &prologue_cost, cost_vec, cost_vec,
10295 : : true);
10296 : : }
10297 : : }
10298 : 0 : n_adjacent_loads++;
10299 : 0 : continue;
10300 : 0 : }
10301 : :
10302 : : /* 1. Create the vector or array pointer update chain. */
10303 : 0 : if (j == 0)
10304 : 0 : dataref_ptr
10305 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
10306 : : at_loop, offset, &dummy, gsi,
10307 : : &ptr_incr, false, bump);
10308 : : else
10309 : : {
10310 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
10311 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
10312 : : stmt_info, bump);
10313 : : }
10314 : 0 : if (mask_node)
10315 : 0 : vec_mask = vec_masks[j];
10316 : :
10317 : 0 : tree vec_array = create_vector_array (vectype, group_size);
10318 : :
10319 : 0 : tree final_mask = NULL_TREE;
10320 : 0 : tree final_len = NULL_TREE;
10321 : 0 : tree bias = NULL_TREE;
10322 : 0 : if (loop_masks)
10323 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
10324 : : ncopies, vectype, j);
10325 : 0 : if (vec_mask)
10326 : 0 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
10327 : : vec_mask, gsi);
10328 : :
10329 : 0 : if (lanes_ifn == IFN_MASK_LEN_LOAD_LANES)
10330 : : {
10331 : 0 : if (loop_lens)
10332 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
10333 : : ncopies, vectype, j, 1);
10334 : : else
10335 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
10336 : 0 : signed char biasval
10337 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
10338 : 0 : bias = build_int_cst (intQI_type_node, biasval);
10339 : 0 : if (!final_mask)
10340 : : {
10341 : 0 : mask_vectype = truth_type_for (vectype);
10342 : 0 : final_mask = build_minus_one_cst (mask_vectype);
10343 : : }
10344 : : }
10345 : :
10346 : 0 : if (final_mask)
10347 : : {
10348 : 0 : vec_els = vect_get_mask_load_else (maskload_elsval, vectype);
10349 : 0 : if (type_mode_padding_p
10350 : 0 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
10351 : 0 : need_zeroing = true;
10352 : : }
10353 : :
10354 : 0 : gcall *call;
10355 : 0 : if (final_len && final_mask)
10356 : : {
10357 : : /* Emit:
10358 : : VEC_ARRAY = MASK_LEN_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,
10359 : : VEC_MASK, LEN, BIAS). */
10360 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
10361 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
10362 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_LOAD_LANES, 6,
10363 : : dataref_ptr, alias_ptr,
10364 : : final_mask, vec_els,
10365 : : final_len, bias);
10366 : : }
10367 : 0 : else if (final_mask)
10368 : : {
10369 : : /* Emit:
10370 : : VEC_ARRAY = MASK_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,
10371 : : VEC_MASK). */
10372 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
10373 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
10374 : 0 : call = gimple_build_call_internal (IFN_MASK_LOAD_LANES, 4,
10375 : : dataref_ptr, alias_ptr,
10376 : : final_mask, vec_els);
10377 : : }
10378 : : else
10379 : : {
10380 : : /* Emit:
10381 : : VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]). */
10382 : 0 : data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
10383 : 0 : call = gimple_build_call_internal (IFN_LOAD_LANES, 1, data_ref);
10384 : : }
10385 : 0 : gimple_call_set_lhs (call, vec_array);
10386 : 0 : gimple_call_set_nothrow (call, true);
10387 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
10388 : :
10389 : : /* Extract each vector into an SSA_NAME. */
10390 : 0 : for (unsigned i = 0; i < group_size; i++)
10391 : : {
10392 : 0 : new_temp = read_vector_array (vinfo, stmt_info, gsi, scalar_dest,
10393 : : vec_array, i, need_zeroing,
10394 : : final_mask);
10395 : 0 : slp_node->push_vec_def (new_temp);
10396 : : }
10397 : :
10398 : : /* Record that VEC_ARRAY is now dead. */
10399 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
10400 : : }
10401 : :
10402 : 0 : if (costing_p)
10403 : : {
10404 : 0 : if (n_adjacent_loads > 0)
10405 : 0 : vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
10406 : : alignment_support_scheme, misalignment, false,
10407 : : &inside_cost, &prologue_cost, cost_vec,
10408 : : cost_vec, true);
10409 : 0 : if (dump_enabled_p ())
10410 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
10411 : : "vect_model_load_cost: inside_cost = %u, "
10412 : : "prologue_cost = %u .\n",
10413 : : inside_cost, prologue_cost);
10414 : : }
10415 : :
10416 : 0 : return true;
10417 : : }
10418 : :
10419 : 506807 : if (mat_gather_scatter_p (memory_access_type))
10420 : : {
10421 : 2691 : gcc_assert (!grouped_load && !slp_perm);
10422 : :
10423 : : /* 1. Create the vector or array pointer update chain. */
10424 : 2691 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
10425 : : {
10426 : 2691 : aggr_type = NULL_TREE;
10427 : 2691 : bump = NULL_TREE;
10428 : 2691 : if (!costing_p)
10429 : 747 : vect_get_gather_scatter_ops (loop, slp_node, &dataref_ptr,
10430 : : &vec_offsets);
10431 : : }
10432 : : else
10433 : : {
10434 : 0 : aggr_type = elem_type;
10435 : 0 : if (!costing_p)
10436 : : {
10437 : 0 : vect_get_strided_load_store_ops (stmt_info, slp_node, vectype,
10438 : : ls.strided_offset_vectype,
10439 : : loop_vinfo, gsi,
10440 : : &bump, &vec_offset, loop_lens);
10441 : 0 : dataref_ptr
10442 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
10443 : : at_loop, offset, &dummy, gsi,
10444 : : &ptr_incr, false, bump);
10445 : : }
10446 : : }
10447 : :
10448 : : unsigned int inside_cost = 0, prologue_cost = 0;
10449 : :
10450 : 6077 : gimple *new_stmt = NULL;
10451 : 6077 : for (i = 0; i < vec_num; i++)
10452 : : {
10453 : 3386 : tree final_mask = NULL_TREE;
10454 : 3386 : tree final_len = NULL_TREE;
10455 : 3386 : tree bias = NULL_TREE;
10456 : 3386 : if (!costing_p)
10457 : : {
10458 : 959 : if (mask_node)
10459 : 153 : vec_mask = vec_masks[i];
10460 : 959 : if (loop_masks)
10461 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
10462 : : vec_num, vectype, i);
10463 : 959 : if (vec_mask)
10464 : 153 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
10465 : : final_mask, vec_mask, gsi);
10466 : :
10467 : 959 : if (i > 0 && !STMT_VINFO_GATHER_SCATTER_P (stmt_info))
10468 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
10469 : : gsi, stmt_info, bump);
10470 : : }
10471 : :
10472 : : /* 2. Create the vector-load in the loop. */
10473 : 3386 : unsigned align = get_object_alignment (DR_REF (first_dr_info->dr));
10474 : 3386 : tree alias_align_ptr = build_int_cst (ref_type, align);
10475 : 3386 : if (memory_access_type == VMAT_GATHER_SCATTER_IFN)
10476 : : {
10477 : 0 : if (costing_p)
10478 : : {
10479 : 0 : unsigned int cnunits = vect_nunits_for_cost (vectype);
10480 : 0 : inside_cost
10481 : 0 : = record_stmt_cost (cost_vec, cnunits, scalar_load,
10482 : : slp_node, 0, vect_body);
10483 : 3386 : continue;
10484 : 0 : }
10485 : 0 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
10486 : 0 : vec_offset = vec_offsets[i];
10487 : 0 : tree zero = build_zero_cst (vectype);
10488 : 0 : tree scale = size_int (SLP_TREE_GS_SCALE (slp_node));
10489 : :
10490 : 0 : if (ls.gs.ifn == IFN_MASK_LEN_GATHER_LOAD)
10491 : : {
10492 : 0 : if (loop_lens)
10493 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
10494 : : vec_num, vectype, i, 1);
10495 : : else
10496 : 0 : final_len = build_int_cst (sizetype,
10497 : 0 : TYPE_VECTOR_SUBPARTS (vectype));
10498 : 0 : signed char biasval
10499 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
10500 : 0 : bias = build_int_cst (intQI_type_node, biasval);
10501 : 0 : if (!final_mask)
10502 : : {
10503 : 0 : mask_vectype = truth_type_for (vectype);
10504 : 0 : final_mask = build_minus_one_cst (mask_vectype);
10505 : : }
10506 : : }
10507 : :
10508 : 0 : if (final_mask)
10509 : : {
10510 : 0 : vec_els = vect_get_mask_load_else (maskload_elsval, vectype);
10511 : 0 : if (type_mode_padding_p
10512 : 0 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
10513 : 0 : need_zeroing = true;
10514 : : }
10515 : :
10516 : 0 : gcall *call;
10517 : 0 : if (final_len && final_mask)
10518 : : {
10519 : 0 : if (VECTOR_TYPE_P (TREE_TYPE (vec_offset)))
10520 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_GATHER_LOAD,
10521 : : 9, dataref_ptr,
10522 : : alias_align_ptr,
10523 : : vec_offset, scale, zero,
10524 : : final_mask, vec_els,
10525 : : final_len, bias);
10526 : : else
10527 : : /* Non-vector offset indicates that prefer to take
10528 : : MASK_LEN_STRIDED_LOAD instead of the
10529 : : MASK_LEN_GATHER_LOAD with direct stride arg. */
10530 : 0 : call = gimple_build_call_internal
10531 : 0 : (IFN_MASK_LEN_STRIDED_LOAD, 7, dataref_ptr,
10532 : : vec_offset, zero, final_mask, vec_els, final_len,
10533 : : bias);
10534 : : }
10535 : 0 : else if (final_mask)
10536 : 0 : call = gimple_build_call_internal (IFN_MASK_GATHER_LOAD,
10537 : : 7, dataref_ptr,
10538 : : alias_align_ptr,
10539 : : vec_offset, scale,
10540 : : zero, final_mask, vec_els);
10541 : : else
10542 : 0 : call = gimple_build_call_internal (IFN_GATHER_LOAD, 5,
10543 : : dataref_ptr,
10544 : : alias_align_ptr,
10545 : : vec_offset, scale, zero);
10546 : 0 : gimple_call_set_nothrow (call, true);
10547 : 0 : new_stmt = call;
10548 : 0 : data_ref = NULL_TREE;
10549 : : }
10550 : 3386 : else if (memory_access_type == VMAT_GATHER_SCATTER_LEGACY)
10551 : : {
10552 : : /* The builtin decls path for gather is legacy, x86 only. */
10553 : 570 : gcc_assert (!final_len && nunits.is_constant ());
10554 : 570 : if (costing_p)
10555 : : {
10556 : 287 : unsigned int cnunits = vect_nunits_for_cost (vectype);
10557 : 287 : inside_cost
10558 : 287 : = record_stmt_cost (cost_vec, cnunits, scalar_load,
10559 : : slp_node, 0, vect_body);
10560 : 287 : continue;
10561 : 287 : }
10562 : 283 : tree offset_vectype = TREE_TYPE (vec_offsets[0]);
10563 : 283 : poly_uint64 offset_nunits = TYPE_VECTOR_SUBPARTS (offset_vectype);
10564 : 283 : if (known_eq (nunits, offset_nunits))
10565 : : {
10566 : 134 : new_stmt = vect_build_one_gather_load_call
10567 : 134 : (vinfo, stmt_info, slp_node, vectype, gsi,
10568 : 134 : ls.gs.decl, dataref_ptr, vec_offsets[i],
10569 : : final_mask);
10570 : 134 : data_ref = NULL_TREE;
10571 : : }
10572 : 149 : else if (known_eq (nunits, offset_nunits * 2))
10573 : : {
10574 : : /* We have a offset vector with half the number of
10575 : : lanes but the builtins will produce full vectype
10576 : : data with just the lower lanes filled. */
10577 : 63 : new_stmt = vect_build_one_gather_load_call
10578 : 126 : (vinfo, stmt_info, slp_node, vectype, gsi,
10579 : 63 : ls.gs.decl, dataref_ptr, vec_offsets[2 * i],
10580 : : final_mask);
10581 : 63 : tree low = make_ssa_name (vectype);
10582 : 63 : gimple_set_lhs (new_stmt, low);
10583 : 63 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10584 : :
10585 : : /* now put upper half of final_mask in final_mask low. */
10586 : 63 : if (final_mask
10587 : 63 : && !SCALAR_INT_MODE_P (TYPE_MODE (TREE_TYPE (final_mask))))
10588 : : {
10589 : 10 : int count = nunits.to_constant ();
10590 : 10 : vec_perm_builder sel (count, count, 1);
10591 : 10 : sel.quick_grow (count);
10592 : 78 : for (int i = 0; i < count; ++i)
10593 : 68 : sel[i] = i | (count / 2);
10594 : 10 : vec_perm_indices indices (sel, 2, count);
10595 : 10 : tree perm_mask = vect_gen_perm_mask_checked
10596 : 10 : (TREE_TYPE (final_mask), indices);
10597 : 10 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
10598 : : final_mask, final_mask,
10599 : : perm_mask);
10600 : 10 : final_mask = make_ssa_name (TREE_TYPE (final_mask));
10601 : 10 : gimple_set_lhs (new_stmt, final_mask);
10602 : 10 : vect_finish_stmt_generation (vinfo, stmt_info,
10603 : : new_stmt, gsi);
10604 : 10 : }
10605 : 53 : else if (final_mask)
10606 : : {
10607 : 25 : new_stmt = gimple_build_assign (NULL_TREE,
10608 : : VEC_UNPACK_HI_EXPR,
10609 : : final_mask);
10610 : 25 : final_mask = make_ssa_name
10611 : 25 : (truth_type_for (offset_vectype));
10612 : 25 : gimple_set_lhs (new_stmt, final_mask);
10613 : 25 : vect_finish_stmt_generation (vinfo, stmt_info,
10614 : : new_stmt, gsi);
10615 : : }
10616 : :
10617 : 63 : new_stmt = vect_build_one_gather_load_call
10618 : 126 : (vinfo, stmt_info, slp_node, vectype, gsi,
10619 : : ls.gs.decl, dataref_ptr,
10620 : 63 : vec_offsets[2 * i + 1], final_mask);
10621 : 63 : tree high = make_ssa_name (vectype);
10622 : 63 : gimple_set_lhs (new_stmt, high);
10623 : 63 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10624 : :
10625 : : /* compose low + high. */
10626 : 63 : int count = nunits.to_constant ();
10627 : 63 : vec_perm_builder sel (count, count, 1);
10628 : 63 : sel.quick_grow (count);
10629 : 655 : for (int i = 0; i < count; ++i)
10630 : 592 : sel[i] = i < count / 2 ? i : i + count / 2;
10631 : 63 : vec_perm_indices indices (sel, 2, count);
10632 : 63 : tree perm_mask
10633 : 63 : = vect_gen_perm_mask_checked (vectype, indices);
10634 : 63 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
10635 : : low, high, perm_mask);
10636 : 63 : data_ref = NULL_TREE;
10637 : 63 : }
10638 : 86 : else if (known_eq (nunits * 2, offset_nunits))
10639 : : {
10640 : : /* We have a offset vector with double the number of
10641 : : lanes. Select the low/high part accordingly. */
10642 : 86 : vec_offset = vec_offsets[i / 2];
10643 : 86 : if (i & 1)
10644 : : {
10645 : 43 : int count = offset_nunits.to_constant ();
10646 : 43 : vec_perm_builder sel (count, count, 1);
10647 : 43 : sel.quick_grow (count);
10648 : 463 : for (int i = 0; i < count; ++i)
10649 : 420 : sel[i] = i | (count / 2);
10650 : 43 : vec_perm_indices indices (sel, 2, count);
10651 : 43 : tree perm_mask = vect_gen_perm_mask_checked
10652 : 43 : (TREE_TYPE (vec_offset), indices);
10653 : 43 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
10654 : : vec_offset, vec_offset,
10655 : : perm_mask);
10656 : 43 : vec_offset = make_ssa_name (TREE_TYPE (vec_offset));
10657 : 43 : gimple_set_lhs (new_stmt, vec_offset);
10658 : 43 : vect_finish_stmt_generation (vinfo, stmt_info,
10659 : : new_stmt, gsi);
10660 : 43 : }
10661 : 86 : new_stmt = vect_build_one_gather_load_call
10662 : 86 : (vinfo, stmt_info, slp_node, vectype, gsi,
10663 : : ls.gs.decl,
10664 : : dataref_ptr, vec_offset, final_mask);
10665 : 86 : data_ref = NULL_TREE;
10666 : : }
10667 : : else
10668 : 0 : gcc_unreachable ();
10669 : : }
10670 : : else
10671 : : {
10672 : : /* Emulated gather-scatter. */
10673 : 2816 : gcc_assert (!final_mask);
10674 : 2816 : unsigned HOST_WIDE_INT const_nunits = nunits.to_constant ();
10675 : 2816 : if (costing_p)
10676 : : {
10677 : : /* For emulated gathers N offset vector element
10678 : : offset add is consumed by the load). */
10679 : 2140 : inside_cost = record_stmt_cost (cost_vec, const_nunits,
10680 : : vec_to_scalar,
10681 : : slp_node, 0, vect_body);
10682 : : /* N scalar loads plus gathering them into a
10683 : : vector. */
10684 : 2140 : inside_cost
10685 : 2140 : = record_stmt_cost (cost_vec, const_nunits, scalar_load,
10686 : : slp_node, 0, vect_body);
10687 : 2140 : inside_cost
10688 : 2140 : = record_stmt_cost (cost_vec, 1, vec_construct,
10689 : : slp_node, 0, vect_body);
10690 : 2140 : continue;
10691 : : }
10692 : 676 : tree offset_vectype = TREE_TYPE (vec_offsets[0]);
10693 : 676 : unsigned HOST_WIDE_INT const_offset_nunits
10694 : 676 : = TYPE_VECTOR_SUBPARTS (offset_vectype).to_constant ();
10695 : 676 : vec<constructor_elt, va_gc> *ctor_elts;
10696 : 676 : vec_alloc (ctor_elts, const_nunits);
10697 : 676 : gimple_seq stmts = NULL;
10698 : : /* We support offset vectors with more elements
10699 : : than the data vector for now. */
10700 : 676 : unsigned HOST_WIDE_INT factor
10701 : : = const_offset_nunits / const_nunits;
10702 : 676 : vec_offset = vec_offsets[i / factor];
10703 : 676 : unsigned elt_offset = (i % factor) * const_nunits;
10704 : 676 : tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset));
10705 : 676 : tree scale = size_int (SLP_TREE_GS_SCALE (slp_node));
10706 : 676 : tree ltype = build_aligned_type (TREE_TYPE (vectype), align);
10707 : 2816 : for (unsigned k = 0; k < const_nunits; ++k)
10708 : : {
10709 : 2140 : tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type),
10710 : : bitsize_int (k + elt_offset));
10711 : 6420 : tree idx = gimple_build (&stmts, BIT_FIELD_REF, idx_type,
10712 : 2140 : vec_offset, TYPE_SIZE (idx_type),
10713 : : boff);
10714 : 2140 : idx = gimple_convert (&stmts, sizetype, idx);
10715 : 2140 : idx = gimple_build (&stmts, MULT_EXPR, sizetype, idx, scale);
10716 : 2140 : tree ptr = gimple_build (&stmts, PLUS_EXPR,
10717 : 2140 : TREE_TYPE (dataref_ptr),
10718 : : dataref_ptr, idx);
10719 : 2140 : ptr = gimple_convert (&stmts, ptr_type_node, ptr);
10720 : 2140 : tree elt = make_ssa_name (TREE_TYPE (vectype));
10721 : 2140 : tree ref = build2 (MEM_REF, ltype, ptr,
10722 : : build_int_cst (ref_type, 0));
10723 : 2140 : new_stmt = gimple_build_assign (elt, ref);
10724 : 4280 : gimple_set_vuse (new_stmt, gimple_vuse (gsi_stmt (*gsi)));
10725 : 2140 : gimple_seq_add_stmt (&stmts, new_stmt);
10726 : 2140 : CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE, elt);
10727 : : }
10728 : 676 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
10729 : 676 : new_stmt = gimple_build_assign (NULL_TREE,
10730 : : build_constructor (vectype,
10731 : : ctor_elts));
10732 : 676 : data_ref = NULL_TREE;
10733 : : }
10734 : :
10735 : 959 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
10736 : : /* DATA_REF is null if we've already built the statement. */
10737 : 959 : if (data_ref)
10738 : : {
10739 : : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
10740 : : new_stmt = gimple_build_assign (vec_dest, data_ref);
10741 : : }
10742 : 1918 : new_temp = (need_zeroing
10743 : 959 : ? make_ssa_name (vectype)
10744 : 959 : : make_ssa_name (vec_dest, new_stmt));
10745 : 959 : gimple_set_lhs (new_stmt, new_temp);
10746 : 959 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10747 : :
10748 : : /* If we need to explicitly zero inactive elements emit a
10749 : : VEC_COND_EXPR that does so. */
10750 : 959 : if (need_zeroing)
10751 : : {
10752 : 0 : vec_els = vect_get_mask_load_else (MASK_LOAD_ELSE_ZERO,
10753 : : vectype);
10754 : :
10755 : 0 : tree new_temp2 = make_ssa_name (vec_dest, new_stmt);
10756 : 0 : new_stmt = gimple_build_assign (new_temp2, VEC_COND_EXPR,
10757 : : final_mask, new_temp, vec_els);
10758 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10759 : 0 : new_temp = new_temp2;
10760 : : }
10761 : :
10762 : : /* Store vector loads in the corresponding SLP_NODE. */
10763 : 959 : slp_node->push_vec_def (new_stmt);
10764 : : }
10765 : :
10766 : 2691 : if (costing_p && dump_enabled_p ())
10767 : 222 : dump_printf_loc (MSG_NOTE, vect_location,
10768 : : "vect_model_load_cost: inside_cost = %u, "
10769 : : "prologue_cost = %u .\n",
10770 : : inside_cost, prologue_cost);
10771 : 2691 : return true;
10772 : : }
10773 : :
10774 : 504116 : aggr_type = vectype;
10775 : 504116 : if (!costing_p)
10776 : 159163 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
10777 : : memory_access_type, loop_lens);
10778 : :
10779 : 504116 : poly_uint64 group_elt = 0;
10780 : 504116 : unsigned int inside_cost = 0, prologue_cost = 0;
10781 : : /* For costing some adjacent vector loads, we'd like to cost with
10782 : : the total number of them once instead of cost each one by one. */
10783 : 504116 : unsigned int n_adjacent_loads = 0;
10784 : :
10785 : : /* 1. Create the vector or array pointer update chain. */
10786 : 504116 : if (!costing_p)
10787 : : {
10788 : 159163 : bool simd_lane_access_p
10789 : 159163 : = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0;
10790 : 159163 : if (simd_lane_access_p
10791 : 1629 : && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR
10792 : 1629 : && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0))
10793 : 1629 : && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info))
10794 : 1629 : && integer_zerop (DR_INIT (first_dr_info->dr))
10795 : 1629 : && alias_sets_conflict_p (get_alias_set (aggr_type),
10796 : 1629 : get_alias_set (TREE_TYPE (ref_type)))
10797 : 159163 : && (alignment_support_scheme == dr_aligned
10798 : 1629 : || alignment_support_scheme == dr_unaligned_supported))
10799 : : {
10800 : 1629 : dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr));
10801 : 1629 : dataref_offset = build_int_cst (ref_type, 0);
10802 : : }
10803 : 157534 : else if (diff_first_stmt_info)
10804 : : {
10805 : 3157 : dataref_ptr
10806 : 3157 : = vect_create_data_ref_ptr (vinfo, first_stmt_info_for_drptr,
10807 : : aggr_type, at_loop, offset, &dummy,
10808 : : gsi, &ptr_incr, simd_lane_access_p,
10809 : : bump);
10810 : : /* Adjust the pointer by the difference to first_stmt. */
10811 : 3157 : data_reference_p ptrdr
10812 : : = STMT_VINFO_DATA_REF (first_stmt_info_for_drptr);
10813 : 3157 : tree diff = fold_convert (sizetype,
10814 : : size_binop (MINUS_EXPR,
10815 : : DR_INIT (first_dr_info->dr),
10816 : : DR_INIT (ptrdr)));
10817 : 3157 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
10818 : : stmt_info, diff);
10819 : 3157 : if (alignment_support_scheme == dr_explicit_realign)
10820 : : {
10821 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info_for_drptr,
10822 : : vectype, gsi,
10823 : : &realignment_token,
10824 : : alignment_support_scheme,
10825 : : dataref_ptr, &at_loop);
10826 : 0 : gcc_assert (!compute_in_loop);
10827 : : }
10828 : : }
10829 : : else
10830 : 154377 : dataref_ptr
10831 : 154377 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
10832 : : at_loop,
10833 : : offset, &dummy, gsi, &ptr_incr,
10834 : : simd_lane_access_p, bump);
10835 : : }
10836 : : else if (!costing_p)
10837 : : {
10838 : : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
10839 : : if (dataref_offset)
10840 : : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
10841 : : else
10842 : : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
10843 : : stmt_info, bump);
10844 : : }
10845 : :
10846 : 504116 : if (grouped_load || slp_perm)
10847 : 47167 : dr_chain.create (vec_num);
10848 : :
10849 : : gimple *new_stmt = NULL;
10850 : 1320679 : for (i = 0; i < vec_num; i++)
10851 : : {
10852 : 816563 : tree final_mask = NULL_TREE;
10853 : 816563 : tree final_len = NULL_TREE;
10854 : 816563 : tree bias = NULL_TREE;
10855 : :
10856 : 816563 : if (!costing_p)
10857 : : {
10858 : 210873 : if (mask_node)
10859 : 530 : vec_mask = vec_masks[i];
10860 : 210873 : if (loop_masks)
10861 : 26 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
10862 : : vec_num, vectype, i);
10863 : 210873 : if (vec_mask)
10864 : 530 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
10865 : : final_mask, vec_mask, gsi);
10866 : :
10867 : 210873 : if (i > 0)
10868 : 51710 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
10869 : : gsi, stmt_info, bump);
10870 : : }
10871 : :
10872 : : /* 2. Create the vector-load in the loop. */
10873 : 816563 : switch (alignment_support_scheme)
10874 : : {
10875 : 816563 : case dr_aligned:
10876 : 816563 : case dr_unaligned_supported:
10877 : 816563 : {
10878 : 816563 : if (costing_p)
10879 : : break;
10880 : :
10881 : 210873 : unsigned int misalign;
10882 : 210873 : unsigned HOST_WIDE_INT align;
10883 : 210873 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
10884 : 210873 : if (alignment_support_scheme == dr_aligned)
10885 : : misalign = 0;
10886 : 129349 : else if (misalignment == DR_MISALIGNMENT_UNKNOWN)
10887 : : {
10888 : 104646 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
10889 : 104646 : misalign = 0;
10890 : : }
10891 : : else
10892 : 24703 : misalign = misalignment;
10893 : 210873 : if (dataref_offset == NULL_TREE
10894 : 208746 : && TREE_CODE (dataref_ptr) == SSA_NAME)
10895 : 140722 : set_ptr_info_alignment (get_ptr_info (dataref_ptr), align,
10896 : : misalign);
10897 : 210873 : align = least_bit_hwi (misalign | align);
10898 : :
10899 : : /* Compute IFN when LOOP_LENS or final_mask valid. */
10900 : 210873 : machine_mode vmode = TYPE_MODE (vectype);
10901 : 210873 : machine_mode new_vmode = vmode;
10902 : 210873 : internal_fn partial_ifn = IFN_LAST;
10903 : 210873 : if (loop_lens)
10904 : : {
10905 : 0 : opt_machine_mode new_ovmode
10906 : 0 : = get_len_load_store_mode (vmode, true, &partial_ifn);
10907 : 0 : new_vmode = new_ovmode.require ();
10908 : 0 : unsigned factor
10909 : 0 : = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode);
10910 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
10911 : : vec_num, vectype, i, factor);
10912 : : }
10913 : 210873 : else if (final_mask)
10914 : : {
10915 : 554 : if (!can_vec_mask_load_store_p (vmode,
10916 : 554 : TYPE_MODE
10917 : : (TREE_TYPE (final_mask)),
10918 : : true, &partial_ifn))
10919 : 0 : gcc_unreachable ();
10920 : : }
10921 : :
10922 : 210873 : if (partial_ifn == IFN_MASK_LEN_LOAD)
10923 : : {
10924 : 0 : if (!final_len)
10925 : : {
10926 : : /* Pass VF value to 'len' argument of
10927 : : MASK_LEN_LOAD if LOOP_LENS is invalid. */
10928 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
10929 : : }
10930 : 0 : if (!final_mask)
10931 : : {
10932 : : /* Pass all ones value to 'mask' argument of
10933 : : MASK_LEN_LOAD if final_mask is invalid. */
10934 : 0 : mask_vectype = truth_type_for (vectype);
10935 : 0 : final_mask = build_minus_one_cst (mask_vectype);
10936 : : }
10937 : : }
10938 : 210873 : if (final_len)
10939 : : {
10940 : 0 : signed char biasval
10941 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
10942 : 0 : bias = build_int_cst (intQI_type_node, biasval);
10943 : : }
10944 : :
10945 : 210873 : tree vec_els;
10946 : :
10947 : 210873 : if (final_len)
10948 : : {
10949 : 0 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
10950 : 0 : gcall *call;
10951 : 0 : if (partial_ifn == IFN_MASK_LEN_LOAD)
10952 : : {
10953 : 0 : vec_els = vect_get_mask_load_else (maskload_elsval,
10954 : : vectype);
10955 : 0 : if (type_mode_padding_p
10956 : 0 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
10957 : 0 : need_zeroing = true;
10958 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_LOAD,
10959 : : 6, dataref_ptr, ptr,
10960 : : final_mask, vec_els,
10961 : : final_len, bias);
10962 : : }
10963 : : else
10964 : 0 : call = gimple_build_call_internal (IFN_LEN_LOAD, 4,
10965 : : dataref_ptr, ptr,
10966 : : final_len, bias);
10967 : 0 : gimple_call_set_nothrow (call, true);
10968 : 0 : new_stmt = call;
10969 : 0 : data_ref = NULL_TREE;
10970 : :
10971 : : /* Need conversion if it's wrapped with VnQI. */
10972 : 0 : if (vmode != new_vmode)
10973 : : {
10974 : 0 : tree new_vtype
10975 : 0 : = build_vector_type_for_mode (unsigned_intQI_type_node,
10976 : : new_vmode);
10977 : 0 : tree var = vect_get_new_ssa_name (new_vtype,
10978 : : vect_simple_var);
10979 : 0 : gimple_set_lhs (call, var);
10980 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call,
10981 : : gsi);
10982 : 0 : tree op = build1 (VIEW_CONVERT_EXPR, vectype, var);
10983 : 0 : new_stmt = gimple_build_assign (vec_dest,
10984 : : VIEW_CONVERT_EXPR, op);
10985 : : }
10986 : : }
10987 : 210873 : else if (final_mask)
10988 : : {
10989 : 554 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
10990 : 554 : vec_els = vect_get_mask_load_else (maskload_elsval, vectype);
10991 : 554 : if (type_mode_padding_p
10992 : 554 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
10993 : 0 : need_zeroing = true;
10994 : 554 : gcall *call = gimple_build_call_internal (IFN_MASK_LOAD, 4,
10995 : : dataref_ptr, ptr,
10996 : : final_mask,
10997 : : vec_els);
10998 : 554 : gimple_call_set_nothrow (call, true);
10999 : 554 : new_stmt = call;
11000 : 554 : data_ref = NULL_TREE;
11001 : : }
11002 : : else
11003 : : {
11004 : 210319 : tree ltype = vectype;
11005 : 210319 : tree new_vtype = NULL_TREE;
11006 : 210319 : unsigned HOST_WIDE_INT gap = DR_GROUP_GAP (first_stmt_info);
11007 : 210319 : unsigned HOST_WIDE_INT dr_size
11008 : 210319 : = vect_get_scalar_dr_size (first_dr_info);
11009 : 210319 : poly_int64 off = 0;
11010 : 210319 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11011 : 1422 : off = (TYPE_VECTOR_SUBPARTS (vectype) - 1) * -dr_size;
11012 : 210319 : unsigned int vect_align
11013 : 210319 : = vect_known_alignment_in_bytes (first_dr_info, vectype,
11014 : 210319 : off);
11015 : : /* Try to use a single smaller load when we are about
11016 : : to load excess elements compared to the unrolled
11017 : : scalar loop. */
11018 : 210319 : if (known_gt ((i + 1) * nunits,
11019 : : (group_size * vf - gap)))
11020 : : {
11021 : 2181 : poly_uint64 remain = ((group_size * vf - gap) - i * nunits);
11022 : 2181 : if (known_ge ((i + 1) * nunits - (group_size * vf - gap),
11023 : : nunits))
11024 : : /* DR will be unused. */
11025 : : ltype = NULL_TREE;
11026 : 1656 : else if (known_ge (vect_align,
11027 : : tree_to_poly_uint64
11028 : : (TYPE_SIZE_UNIT (vectype))))
11029 : : /* Aligned access to excess elements is OK if
11030 : : at least one element is accessed in the
11031 : : scalar loop. */
11032 : : ;
11033 : 1424 : else if (known_gt (vect_align,
11034 : : ((nunits - remain) * dr_size)))
11035 : : /* Aligned access to the gap area when there's
11036 : : at least one element in it is OK. */
11037 : : ;
11038 : : else
11039 : : {
11040 : : /* remain should now be > 0 and < nunits. */
11041 : 1421 : unsigned num;
11042 : 1421 : if (known_ne (remain, 0u)
11043 : 1421 : && constant_multiple_p (nunits, remain, &num))
11044 : : {
11045 : 1036 : tree ptype;
11046 : 1036 : new_vtype
11047 : 1036 : = vector_vector_composition_type (vectype, num,
11048 : : &ptype);
11049 : 1036 : if (new_vtype)
11050 : 1036 : ltype = ptype;
11051 : : }
11052 : : /* Else use multiple loads or a masked load? */
11053 : : /* For loop vectorization we now should have
11054 : : an alternate type or LOOP_VINFO_PEELING_FOR_GAPS
11055 : : set. */
11056 : 1421 : if (loop_vinfo)
11057 : 1352 : gcc_assert (new_vtype
11058 : : || LOOP_VINFO_PEELING_FOR_GAPS
11059 : : (loop_vinfo));
11060 : : /* But still reduce the access size to the next
11061 : : required power-of-two so peeling a single
11062 : : scalar iteration is sufficient. */
11063 : 1421 : unsigned HOST_WIDE_INT cremain;
11064 : 1421 : if (remain.is_constant (&cremain))
11065 : : {
11066 : 1421 : unsigned HOST_WIDE_INT cpart_size
11067 : 1421 : = 1 << ceil_log2 (cremain);
11068 : 1421 : if (known_gt (nunits, cpart_size)
11069 : 1421 : && constant_multiple_p (nunits, cpart_size,
11070 : : &num))
11071 : : {
11072 : 1048 : tree ptype;
11073 : 1048 : new_vtype
11074 : 2096 : = vector_vector_composition_type (vectype,
11075 : 1048 : num,
11076 : : &ptype);
11077 : 1048 : if (new_vtype)
11078 : 1048 : ltype = ptype;
11079 : : }
11080 : : }
11081 : : }
11082 : : }
11083 : 210319 : tree offset = (dataref_offset ? dataref_offset
11084 : 208192 : : build_int_cst (ref_type, 0));
11085 : 210319 : if (!ltype)
11086 : : ;
11087 : 209794 : else if (ltype != vectype
11088 : 209794 : && memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11089 : : {
11090 : 21 : poly_uint64 gap_offset
11091 : 21 : = (tree_to_poly_uint64 (TYPE_SIZE_UNIT (vectype))
11092 : 21 : - tree_to_poly_uint64 (TYPE_SIZE_UNIT (ltype)));
11093 : 21 : tree gapcst = build_int_cstu (ref_type, gap_offset);
11094 : 21 : offset = size_binop (PLUS_EXPR, offset, gapcst);
11095 : : }
11096 : 210319 : if (ltype)
11097 : : {
11098 : 209794 : data_ref = fold_build2 (MEM_REF, ltype,
11099 : : dataref_ptr, offset);
11100 : 209794 : if (alignment_support_scheme == dr_aligned
11101 : 209794 : && align >= TYPE_ALIGN_UNIT (ltype))
11102 : : ;
11103 : : else
11104 : 128691 : TREE_TYPE (data_ref)
11105 : 257382 : = build_aligned_type (TREE_TYPE (data_ref),
11106 : : align * BITS_PER_UNIT);
11107 : : }
11108 : 210319 : if (!ltype)
11109 : 525 : data_ref = build_constructor (vectype, NULL);
11110 : 209794 : else if (ltype != vectype)
11111 : : {
11112 : 1048 : vect_copy_ref_info (data_ref,
11113 : 1048 : DR_REF (first_dr_info->dr));
11114 : 1048 : tree tem = make_ssa_name (ltype);
11115 : 1048 : new_stmt = gimple_build_assign (tem, data_ref);
11116 : 1048 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
11117 : : gsi);
11118 : 1048 : data_ref = NULL;
11119 : 1048 : vec<constructor_elt, va_gc> *v;
11120 : : /* We've computed 'num' above to statically two
11121 : : or via constant_multiple_p. */
11122 : 1048 : unsigned num
11123 : 1048 : = (exact_div (tree_to_poly_uint64
11124 : 1048 : (TYPE_SIZE_UNIT (vectype)),
11125 : : tree_to_poly_uint64
11126 : 1048 : (TYPE_SIZE_UNIT (ltype)))
11127 : 1048 : .to_constant ());
11128 : 1048 : vec_alloc (v, num);
11129 : 1048 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11130 : : {
11131 : 54 : while (--num)
11132 : 54 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
11133 : : build_zero_cst (ltype));
11134 : 21 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem);
11135 : : }
11136 : : else
11137 : : {
11138 : 1027 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem);
11139 : 1027 : while (--num)
11140 : 2416 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
11141 : : build_zero_cst (ltype));
11142 : : }
11143 : 1048 : gcc_assert (new_vtype != NULL_TREE);
11144 : 1048 : if (new_vtype == vectype)
11145 : 1018 : new_stmt
11146 : 1018 : = gimple_build_assign (vec_dest,
11147 : : build_constructor (vectype, v));
11148 : : else
11149 : : {
11150 : 30 : tree new_vname = make_ssa_name (new_vtype);
11151 : 30 : new_stmt
11152 : 30 : = gimple_build_assign (new_vname,
11153 : : build_constructor (new_vtype,
11154 : : v));
11155 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
11156 : : new_stmt, gsi);
11157 : 30 : new_stmt
11158 : 30 : = gimple_build_assign (vec_dest,
11159 : : build1 (VIEW_CONVERT_EXPR,
11160 : : vectype, new_vname));
11161 : : }
11162 : : }
11163 : : }
11164 : : break;
11165 : : }
11166 : 0 : case dr_explicit_realign:
11167 : 0 : {
11168 : 0 : if (costing_p)
11169 : : break;
11170 : 0 : tree ptr, bump;
11171 : :
11172 : 0 : tree vs = size_int (TYPE_VECTOR_SUBPARTS (vectype));
11173 : :
11174 : 0 : if (compute_in_loop)
11175 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info, vectype,
11176 : : gsi, &realignment_token,
11177 : : dr_explicit_realign,
11178 : : dataref_ptr, NULL);
11179 : :
11180 : 0 : if (TREE_CODE (dataref_ptr) == SSA_NAME)
11181 : 0 : ptr = copy_ssa_name (dataref_ptr);
11182 : : else
11183 : 0 : ptr = make_ssa_name (TREE_TYPE (dataref_ptr));
11184 : : // For explicit realign the target alignment should be
11185 : : // known at compile time.
11186 : 0 : unsigned HOST_WIDE_INT align
11187 : 0 : = DR_TARGET_ALIGNMENT (first_dr_info).to_constant ();
11188 : 0 : new_stmt = gimple_build_assign (ptr, BIT_AND_EXPR, dataref_ptr,
11189 : : build_int_cst
11190 : 0 : (TREE_TYPE (dataref_ptr),
11191 : 0 : -(HOST_WIDE_INT) align));
11192 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11193 : 0 : data_ref = build2 (MEM_REF, vectype,
11194 : : ptr, build_int_cst (ref_type, 0));
11195 : 0 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
11196 : 0 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11197 : 0 : new_stmt = gimple_build_assign (vec_dest, data_ref);
11198 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
11199 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
11200 : 0 : gimple_move_vops (new_stmt, stmt_info->stmt);
11201 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11202 : 0 : msq = new_temp;
11203 : :
11204 : 0 : bump = size_binop (MULT_EXPR, vs, TYPE_SIZE_UNIT (elem_type));
11205 : 0 : bump = size_binop (MINUS_EXPR, bump, size_one_node);
11206 : 0 : ptr = bump_vector_ptr (vinfo, dataref_ptr, NULL, gsi, stmt_info,
11207 : : bump);
11208 : 0 : new_stmt = gimple_build_assign (NULL_TREE, BIT_AND_EXPR, ptr,
11209 : 0 : build_int_cst (TREE_TYPE (ptr),
11210 : 0 : -(HOST_WIDE_INT) align));
11211 : 0 : if (TREE_CODE (ptr) == SSA_NAME)
11212 : 0 : ptr = copy_ssa_name (ptr, new_stmt);
11213 : : else
11214 : 0 : ptr = make_ssa_name (TREE_TYPE (ptr), new_stmt);
11215 : 0 : gimple_assign_set_lhs (new_stmt, ptr);
11216 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11217 : 0 : data_ref = build2 (MEM_REF, vectype,
11218 : : ptr, build_int_cst (ref_type, 0));
11219 : 0 : break;
11220 : : }
11221 : 0 : case dr_explicit_realign_optimized:
11222 : 0 : {
11223 : 0 : if (costing_p)
11224 : : break;
11225 : 0 : if (TREE_CODE (dataref_ptr) == SSA_NAME)
11226 : 0 : new_temp = copy_ssa_name (dataref_ptr);
11227 : : else
11228 : 0 : new_temp = make_ssa_name (TREE_TYPE (dataref_ptr));
11229 : : // We should only be doing this if we know the target
11230 : : // alignment at compile time.
11231 : 0 : unsigned HOST_WIDE_INT align
11232 : 0 : = DR_TARGET_ALIGNMENT (first_dr_info).to_constant ();
11233 : 0 : new_stmt = gimple_build_assign (new_temp, BIT_AND_EXPR, dataref_ptr,
11234 : 0 : build_int_cst (TREE_TYPE (dataref_ptr),
11235 : 0 : -(HOST_WIDE_INT) align));
11236 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11237 : 0 : data_ref = build2 (MEM_REF, vectype, new_temp,
11238 : : build_int_cst (ref_type, 0));
11239 : 0 : break;
11240 : : }
11241 : 0 : default:
11242 : 0 : gcc_unreachable ();
11243 : : }
11244 : :
11245 : : /* One common place to cost the above vect load for different
11246 : : alignment support schemes. */
11247 : 816563 : if (costing_p)
11248 : : {
11249 : : /* For the prologue cost for realign,
11250 : : we only need to count it once for the whole group. */
11251 : 605690 : bool first_stmt_info_p = first_stmt_info == stmt_info;
11252 : 605690 : bool add_realign_cost = first_stmt_info_p && i == 0;
11253 : 605690 : if (memory_access_type == VMAT_CONTIGUOUS
11254 : 605690 : || memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11255 : : {
11256 : : /* Leave realign cases alone to keep them simple. */
11257 : 605690 : if (alignment_support_scheme == dr_explicit_realign_optimized
11258 : : || alignment_support_scheme == dr_explicit_realign)
11259 : 0 : vect_get_load_cost (vinfo, stmt_info, slp_node, 1,
11260 : : alignment_support_scheme, misalignment,
11261 : : add_realign_cost, &inside_cost,
11262 : : &prologue_cost, cost_vec, cost_vec,
11263 : : true);
11264 : : else
11265 : 605690 : n_adjacent_loads++;
11266 : : }
11267 : : }
11268 : : else
11269 : : {
11270 : 210873 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11271 : : /* DATA_REF is null if we've already built the statement. */
11272 : 210873 : if (data_ref)
11273 : : {
11274 : 209271 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
11275 : 209271 : new_stmt = gimple_build_assign (vec_dest, data_ref);
11276 : : }
11277 : :
11278 : 421746 : new_temp = (need_zeroing
11279 : 210873 : ? make_ssa_name (vectype)
11280 : 210873 : : make_ssa_name (vec_dest, new_stmt));
11281 : 210873 : gimple_set_lhs (new_stmt, new_temp);
11282 : 210873 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11283 : :
11284 : : /* If we need to explicitly zero inactive elements emit a
11285 : : VEC_COND_EXPR that does so. */
11286 : 210873 : if (need_zeroing)
11287 : : {
11288 : 0 : vec_els = vect_get_mask_load_else (MASK_LOAD_ELSE_ZERO,
11289 : : vectype);
11290 : :
11291 : 0 : tree new_temp2 = make_ssa_name (vec_dest, new_stmt);
11292 : 0 : new_stmt = gimple_build_assign (new_temp2, VEC_COND_EXPR,
11293 : : final_mask, new_temp, vec_els);
11294 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
11295 : : gsi);
11296 : 0 : new_temp = new_temp2;
11297 : : }
11298 : : }
11299 : :
11300 : : /* 3. Handle explicit realignment if necessary/supported.
11301 : : Create in loop:
11302 : : vec_dest = realign_load (msq, lsq, realignment_token) */
11303 : 816563 : if (!costing_p
11304 : 210873 : && (alignment_support_scheme == dr_explicit_realign_optimized
11305 : : || alignment_support_scheme == dr_explicit_realign))
11306 : : {
11307 : 0 : lsq = gimple_assign_lhs (new_stmt);
11308 : 0 : if (!realignment_token)
11309 : 0 : realignment_token = dataref_ptr;
11310 : 0 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11311 : 0 : new_stmt = gimple_build_assign (vec_dest, REALIGN_LOAD_EXPR, msq,
11312 : : lsq, realignment_token);
11313 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
11314 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
11315 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11316 : :
11317 : 0 : if (alignment_support_scheme == dr_explicit_realign_optimized)
11318 : : {
11319 : 0 : gcc_assert (phi);
11320 : 0 : if (i == vec_num - 1)
11321 : 0 : add_phi_arg (phi, lsq, loop_latch_edge (containing_loop),
11322 : : UNKNOWN_LOCATION);
11323 : : msq = lsq;
11324 : : }
11325 : : }
11326 : :
11327 : 816563 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11328 : : {
11329 : 5880 : if (costing_p)
11330 : 4458 : inside_cost = record_stmt_cost (cost_vec, 1, vec_perm,
11331 : : slp_node, 0, vect_body);
11332 : : else
11333 : : {
11334 : 1422 : tree perm_mask = perm_mask_for_reverse (vectype);
11335 : 1422 : new_temp = permute_vec_elements (vinfo, new_temp, new_temp,
11336 : : perm_mask, stmt_info, gsi);
11337 : 1422 : new_stmt = SSA_NAME_DEF_STMT (new_temp);
11338 : : }
11339 : : }
11340 : :
11341 : : /* Collect vector loads and later create their permutation in
11342 : : vect_transform_slp_perm_load. */
11343 : 816563 : if (!costing_p && (grouped_load || slp_perm))
11344 : 34485 : dr_chain.quick_push (new_temp);
11345 : :
11346 : : /* Store vector loads in the corresponding SLP_NODE. */
11347 : 816563 : if (!costing_p && !slp_perm)
11348 : 176388 : slp_node->push_vec_def (new_stmt);
11349 : :
11350 : : /* With SLP permutation we load the gaps as well, without
11351 : : we need to skip the gaps after we manage to fully load
11352 : : all elements. group_gap_adj is DR_GROUP_SIZE here. */
11353 : 816563 : group_elt += nunits;
11354 : 816563 : if (!costing_p
11355 : 210873 : && maybe_ne (group_gap_adj, 0U)
11356 : 19522 : && !slp_perm
11357 : 835655 : && known_eq (group_elt, group_size - group_gap_adj))
11358 : : {
11359 : 15887 : poly_wide_int bump_val
11360 : 15887 : = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj);
11361 : 15887 : if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step) == -1)
11362 : 0 : bump_val = -bump_val;
11363 : 15887 : tree bump = wide_int_to_tree (sizetype, bump_val);
11364 : 15887 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11365 : : stmt_info, bump);
11366 : 15887 : group_elt = 0;
11367 : 15887 : }
11368 : : }
11369 : : /* Bump the vector pointer to account for a gap or for excess
11370 : : elements loaded for a permuted SLP load. */
11371 : 504116 : if (!costing_p
11372 : 159163 : && maybe_ne (group_gap_adj, 0U)
11373 : 520207 : && slp_perm)
11374 : : {
11375 : 204 : poly_wide_int bump_val
11376 : 204 : = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj);
11377 : 204 : if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step) == -1)
11378 : 9 : bump_val = -bump_val;
11379 : 204 : tree bump = wide_int_to_tree (sizetype, bump_val);
11380 : 204 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11381 : : stmt_info, bump);
11382 : 204 : }
11383 : :
11384 : 504116 : if (slp_perm)
11385 : : {
11386 : : /* For SLP we know we've seen all possible uses of dr_chain so
11387 : : direct vect_transform_slp_perm_load to DCE the unused parts.
11388 : : ??? This is a hack to prevent compile-time issues as seen
11389 : : in PR101120 and friends. */
11390 : 47167 : if (costing_p)
11391 : : {
11392 : 30377 : gcc_assert (n_perms != -1U);
11393 : 30377 : if (n_perms != 0)
11394 : 29986 : inside_cost = record_stmt_cost (cost_vec, n_perms, vec_perm,
11395 : : slp_node, 0, vect_body);
11396 : : }
11397 : : else
11398 : : {
11399 : 16790 : unsigned n_perms2;
11400 : 16790 : bool ok = vect_transform_slp_perm_load (vinfo, slp_node, dr_chain,
11401 : : gsi, vf, false, &n_perms2,
11402 : : nullptr, true);
11403 : 16790 : gcc_assert (ok && n_perms == n_perms2);
11404 : : }
11405 : 47167 : dr_chain.release ();
11406 : : }
11407 : :
11408 : 504116 : if (costing_p)
11409 : : {
11410 : 344953 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS
11411 : : || memory_access_type == VMAT_CONTIGUOUS_REVERSE);
11412 : 344953 : if (n_adjacent_loads > 0)
11413 : 344953 : vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
11414 : : alignment_support_scheme, misalignment, false,
11415 : : &inside_cost, &prologue_cost, cost_vec, cost_vec,
11416 : : true);
11417 : 344953 : if (dump_enabled_p ())
11418 : 22312 : dump_printf_loc (MSG_NOTE, vect_location,
11419 : : "vect_model_load_cost: inside_cost = %u, "
11420 : : "prologue_cost = %u .\n",
11421 : : inside_cost, prologue_cost);
11422 : : }
11423 : :
11424 : : return true;
11425 : 1135309 : }
11426 : :
11427 : : /* Function vect_is_simple_cond.
11428 : :
11429 : : Input:
11430 : : LOOP - the loop that is being vectorized.
11431 : : COND - Condition that is checked for simple use.
11432 : :
11433 : : Output:
11434 : : *COMP_VECTYPE - the vector type for the comparison.
11435 : : *DTS - The def types for the arguments of the comparison
11436 : :
11437 : : Returns whether a COND can be vectorized. Checks whether
11438 : : condition operands are supportable using vec_is_simple_use. */
11439 : :
11440 : : static bool
11441 : 23996 : vect_is_simple_cond (tree cond, vec_info *vinfo,
11442 : : slp_tree slp_node, tree *comp_vectype,
11443 : : enum vect_def_type *dts, tree vectype)
11444 : : {
11445 : 23996 : tree lhs, rhs;
11446 : 23996 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
11447 : 23996 : slp_tree slp_op;
11448 : :
11449 : : /* Mask case. */
11450 : 23996 : if (TREE_CODE (cond) == SSA_NAME
11451 : 23996 : && VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (cond)))
11452 : : {
11453 : 23984 : if (!vect_is_simple_use (vinfo, slp_node, 0, &cond,
11454 : : &slp_op, &dts[0], comp_vectype)
11455 : 23984 : || !*comp_vectype
11456 : 47938 : || !VECTOR_BOOLEAN_TYPE_P (*comp_vectype))
11457 : : return false;
11458 : : return true;
11459 : : }
11460 : :
11461 : 12 : if (!COMPARISON_CLASS_P (cond))
11462 : : return false;
11463 : :
11464 : 0 : lhs = TREE_OPERAND (cond, 0);
11465 : 0 : rhs = TREE_OPERAND (cond, 1);
11466 : :
11467 : 0 : if (TREE_CODE (lhs) == SSA_NAME)
11468 : : {
11469 : 0 : if (!vect_is_simple_use (vinfo, slp_node, 0,
11470 : : &lhs, &slp_op, &dts[0], &vectype1))
11471 : : return false;
11472 : : }
11473 : 0 : else if (TREE_CODE (lhs) == INTEGER_CST || TREE_CODE (lhs) == REAL_CST
11474 : 0 : || TREE_CODE (lhs) == FIXED_CST)
11475 : 0 : dts[0] = vect_constant_def;
11476 : : else
11477 : : return false;
11478 : :
11479 : 0 : if (TREE_CODE (rhs) == SSA_NAME)
11480 : : {
11481 : 0 : if (!vect_is_simple_use (vinfo, slp_node, 1,
11482 : : &rhs, &slp_op, &dts[1], &vectype2))
11483 : : return false;
11484 : : }
11485 : 0 : else if (TREE_CODE (rhs) == INTEGER_CST || TREE_CODE (rhs) == REAL_CST
11486 : 0 : || TREE_CODE (rhs) == FIXED_CST)
11487 : 0 : dts[1] = vect_constant_def;
11488 : : else
11489 : : return false;
11490 : :
11491 : 0 : if (vectype1 && vectype2
11492 : 0 : && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1),
11493 : 0 : TYPE_VECTOR_SUBPARTS (vectype2)))
11494 : 0 : return false;
11495 : :
11496 : 0 : *comp_vectype = vectype1 ? vectype1 : vectype2;
11497 : : /* Invariant comparison. */
11498 : 0 : if (! *comp_vectype)
11499 : : {
11500 : 0 : tree scalar_type = TREE_TYPE (lhs);
11501 : 0 : if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type))
11502 : 0 : *comp_vectype = truth_type_for (vectype);
11503 : : else
11504 : : {
11505 : : /* If we can widen the comparison to match vectype do so. */
11506 : 0 : if (INTEGRAL_TYPE_P (scalar_type)
11507 : 0 : && !slp_node
11508 : 0 : && tree_int_cst_lt (TYPE_SIZE (scalar_type),
11509 : 0 : TYPE_SIZE (TREE_TYPE (vectype))))
11510 : 0 : scalar_type = build_nonstandard_integer_type
11511 : 0 : (vector_element_bits (vectype), TYPE_UNSIGNED (scalar_type));
11512 : 0 : *comp_vectype = get_vectype_for_scalar_type (vinfo, scalar_type,
11513 : : slp_node);
11514 : : }
11515 : : }
11516 : :
11517 : : return true;
11518 : : }
11519 : :
11520 : : /* vectorizable_condition.
11521 : :
11522 : : Check if STMT_INFO is conditional modify expression that can be vectorized.
11523 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
11524 : : stmt using VEC_COND_EXPR to replace it, put it in VEC_STMT, and insert it
11525 : : at GSI.
11526 : :
11527 : : When STMT_INFO is vectorized as a nested cycle, for_reduction is true.
11528 : :
11529 : : Return true if STMT_INFO is vectorizable in this way. */
11530 : :
11531 : : static bool
11532 : 590731 : vectorizable_condition (vec_info *vinfo,
11533 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
11534 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
11535 : : {
11536 : 590731 : tree scalar_dest = NULL_TREE;
11537 : 590731 : tree vec_dest = NULL_TREE;
11538 : 590731 : tree cond_expr, cond_expr0 = NULL_TREE, cond_expr1 = NULL_TREE;
11539 : 590731 : tree then_clause, else_clause;
11540 : 590731 : tree comp_vectype = NULL_TREE;
11541 : 590731 : tree vec_cond_lhs = NULL_TREE, vec_cond_rhs = NULL_TREE;
11542 : 590731 : tree vec_then_clause = NULL_TREE, vec_else_clause = NULL_TREE;
11543 : 590731 : tree vec_compare;
11544 : 590731 : tree new_temp;
11545 : 590731 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
11546 : 590731 : enum vect_def_type dts[4]
11547 : : = {vect_unknown_def_type, vect_unknown_def_type,
11548 : : vect_unknown_def_type, vect_unknown_def_type};
11549 : 590731 : enum tree_code code, cond_code, bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
11550 : 590731 : int i;
11551 : 590731 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
11552 : 590731 : vec<tree> vec_oprnds0 = vNULL;
11553 : 590731 : vec<tree> vec_oprnds1 = vNULL;
11554 : 590731 : vec<tree> vec_oprnds2 = vNULL;
11555 : 590731 : vec<tree> vec_oprnds3 = vNULL;
11556 : 590731 : tree vec_cmp_type;
11557 : 590731 : bool masked = false;
11558 : :
11559 : 590731 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
11560 : : return false;
11561 : :
11562 : : /* Is vectorizable conditional operation? */
11563 : 913832 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
11564 : 346160 : if (!stmt)
11565 : : return false;
11566 : :
11567 : 346160 : code = gimple_assign_rhs_code (stmt);
11568 : 346160 : if (code != COND_EXPR)
11569 : : return false;
11570 : :
11571 : 23996 : int reduc_index = SLP_TREE_REDUC_IDX (slp_node);
11572 : 23996 : vect_reduction_type reduction_type = TREE_CODE_REDUCTION;
11573 : 23996 : bool nested_cycle_p = false;
11574 : 23996 : bool for_reduction = vect_is_reduction (stmt_info);
11575 : 23996 : if (for_reduction)
11576 : : {
11577 : 473 : if (SLP_TREE_LANES (slp_node) > 1)
11578 : : return false;
11579 : : /* ??? With a reduction path we do not get at the reduction info from
11580 : : every stmt, use the conservative default setting then. */
11581 : 525 : if (STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)))
11582 : : {
11583 : 443 : vect_reduc_info reduc_info
11584 : 443 : = info_for_reduction (loop_vinfo, slp_node);
11585 : 443 : reduction_type = VECT_REDUC_INFO_TYPE (reduc_info);
11586 : 443 : nested_cycle_p = nested_in_vect_loop_p (LOOP_VINFO_LOOP (loop_vinfo),
11587 : : stmt_info);
11588 : : }
11589 : : }
11590 : : else
11591 : : {
11592 : 23523 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
11593 : : return false;
11594 : : }
11595 : :
11596 : 23996 : tree vectype = SLP_TREE_VECTYPE (slp_node);
11597 : 23996 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
11598 : :
11599 : 23996 : int vec_num = vect_get_num_copies (vinfo, slp_node);
11600 : :
11601 : 23996 : cond_expr = gimple_assign_rhs1 (stmt);
11602 : 23996 : gcc_assert (! COMPARISON_CLASS_P (cond_expr));
11603 : :
11604 : 23996 : if (!vect_is_simple_cond (cond_expr, vinfo, slp_node,
11605 : : &comp_vectype, &dts[0], vectype)
11606 : 23996 : || !comp_vectype)
11607 : : return false;
11608 : :
11609 : 23954 : unsigned op_adjust = COMPARISON_CLASS_P (cond_expr) ? 1 : 0;
11610 : 23954 : slp_tree then_slp_node, else_slp_node;
11611 : 23954 : if (!vect_is_simple_use (vinfo, slp_node, 1 + op_adjust,
11612 : : &then_clause, &then_slp_node, &dts[2], &vectype1))
11613 : : return false;
11614 : 23954 : if (!vect_is_simple_use (vinfo, slp_node, 2 + op_adjust,
11615 : : &else_clause, &else_slp_node, &dts[3], &vectype2))
11616 : : return false;
11617 : :
11618 : 23954 : if (vectype1 && !useless_type_conversion_p (vectype, vectype1))
11619 : : return false;
11620 : :
11621 : 23954 : if (vectype2 && !useless_type_conversion_p (vectype, vectype2))
11622 : : return false;
11623 : :
11624 : 23954 : masked = !COMPARISON_CLASS_P (cond_expr);
11625 : 23954 : vec_cmp_type = truth_type_for (comp_vectype);
11626 : 23954 : if (vec_cmp_type == NULL_TREE
11627 : 47908 : || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype),
11628 : 23954 : TYPE_VECTOR_SUBPARTS (vec_cmp_type)))
11629 : 767 : return false;
11630 : :
11631 : 23187 : cond_code = TREE_CODE (cond_expr);
11632 : 23187 : if (!masked)
11633 : : {
11634 : 0 : cond_expr0 = TREE_OPERAND (cond_expr, 0);
11635 : 0 : cond_expr1 = TREE_OPERAND (cond_expr, 1);
11636 : : }
11637 : :
11638 : : /* For conditional reductions, the "then" value needs to be the candidate
11639 : : value calculated by this iteration while the "else" value needs to be
11640 : : the result carried over from previous iterations. If the COND_EXPR
11641 : : is the other way around, we need to swap it. */
11642 : 23187 : bool must_invert_cmp_result = false;
11643 : 23187 : if (reduction_type == EXTRACT_LAST_REDUCTION && reduc_index == 1)
11644 : : {
11645 : 0 : if (masked)
11646 : 0 : must_invert_cmp_result = true;
11647 : : else
11648 : : {
11649 : 0 : bool honor_nans = HONOR_NANS (TREE_TYPE (cond_expr0));
11650 : 0 : tree_code new_code = invert_tree_comparison (cond_code, honor_nans);
11651 : 0 : if (new_code == ERROR_MARK)
11652 : : must_invert_cmp_result = true;
11653 : : else
11654 : : {
11655 : 0 : cond_code = new_code;
11656 : : /* Make sure we don't accidentally use the old condition. */
11657 : 0 : cond_expr = NULL_TREE;
11658 : : }
11659 : : }
11660 : : /* ??? The vectorized operand query below doesn't allow swapping
11661 : : this way for SLP. */
11662 : 0 : return false;
11663 : : /* std::swap (then_clause, else_clause); */
11664 : : }
11665 : :
11666 : 23187 : if (!masked && VECTOR_BOOLEAN_TYPE_P (comp_vectype))
11667 : : {
11668 : : /* Boolean values may have another representation in vectors
11669 : : and therefore we prefer bit operations over comparison for
11670 : : them (which also works for scalar masks). We store opcodes
11671 : : to use in bitop1 and bitop2. Statement is vectorized as
11672 : : BITOP2 (rhs1 BITOP1 rhs2) or rhs1 BITOP2 (BITOP1 rhs2)
11673 : : depending on bitop1 and bitop2 arity. */
11674 : 0 : switch (cond_code)
11675 : : {
11676 : : case GT_EXPR:
11677 : : bitop1 = BIT_NOT_EXPR;
11678 : : bitop2 = BIT_AND_EXPR;
11679 : : break;
11680 : 0 : case GE_EXPR:
11681 : 0 : bitop1 = BIT_NOT_EXPR;
11682 : 0 : bitop2 = BIT_IOR_EXPR;
11683 : 0 : break;
11684 : 0 : case LT_EXPR:
11685 : 0 : bitop1 = BIT_NOT_EXPR;
11686 : 0 : bitop2 = BIT_AND_EXPR;
11687 : 0 : std::swap (cond_expr0, cond_expr1);
11688 : 0 : break;
11689 : 0 : case LE_EXPR:
11690 : 0 : bitop1 = BIT_NOT_EXPR;
11691 : 0 : bitop2 = BIT_IOR_EXPR;
11692 : 0 : std::swap (cond_expr0, cond_expr1);
11693 : 0 : break;
11694 : 0 : case NE_EXPR:
11695 : 0 : bitop1 = BIT_XOR_EXPR;
11696 : 0 : break;
11697 : 0 : case EQ_EXPR:
11698 : 0 : bitop1 = BIT_XOR_EXPR;
11699 : 0 : bitop2 = BIT_NOT_EXPR;
11700 : 0 : break;
11701 : : default:
11702 : : return false;
11703 : : }
11704 : : cond_code = SSA_NAME;
11705 : : }
11706 : :
11707 : 23187 : if (TREE_CODE_CLASS (cond_code) == tcc_comparison
11708 : 0 : && reduction_type == EXTRACT_LAST_REDUCTION
11709 : 23187 : && !expand_vec_cmp_expr_p (comp_vectype, vec_cmp_type, cond_code))
11710 : : {
11711 : 0 : if (dump_enabled_p ())
11712 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
11713 : : "reduction comparison operation not supported.\n");
11714 : 0 : return false;
11715 : : }
11716 : :
11717 : 23187 : if (cost_vec)
11718 : : {
11719 : 16648 : if (bitop1 != NOP_EXPR)
11720 : : {
11721 : 0 : machine_mode mode = TYPE_MODE (comp_vectype);
11722 : 0 : optab optab;
11723 : :
11724 : 0 : optab = optab_for_tree_code (bitop1, comp_vectype, optab_default);
11725 : 0 : if (!optab || !can_implement_p (optab, mode))
11726 : 0 : return false;
11727 : :
11728 : 0 : if (bitop2 != NOP_EXPR)
11729 : : {
11730 : 0 : optab = optab_for_tree_code (bitop2, comp_vectype,
11731 : : optab_default);
11732 : 0 : if (!optab || !can_implement_p (optab, mode))
11733 : 0 : return false;
11734 : : }
11735 : : }
11736 : :
11737 : 16648 : vect_cost_for_stmt kind = vector_stmt;
11738 : 16648 : if (reduction_type == EXTRACT_LAST_REDUCTION)
11739 : : /* Count one reduction-like operation per vector. */
11740 : : kind = vec_to_scalar;
11741 : 16648 : else if ((masked && !expand_vec_cond_expr_p (vectype, comp_vectype))
11742 : 16648 : || (!masked
11743 : 0 : && (!expand_vec_cmp_expr_p (comp_vectype, vec_cmp_type,
11744 : : cond_code)
11745 : 0 : || !expand_vec_cond_expr_p (vectype, vec_cmp_type))))
11746 : 128 : return false;
11747 : :
11748 : 16520 : if (!vect_maybe_update_slp_op_vectype (SLP_TREE_CHILDREN (slp_node)[0],
11749 : : comp_vectype)
11750 : 16520 : || (op_adjust == 1
11751 : 0 : && !vect_maybe_update_slp_op_vectype
11752 : 0 : (SLP_TREE_CHILDREN (slp_node)[1], comp_vectype))
11753 : 16520 : || !vect_maybe_update_slp_op_vectype (then_slp_node, vectype)
11754 : 33040 : || !vect_maybe_update_slp_op_vectype (else_slp_node, vectype))
11755 : : {
11756 : 0 : if (dump_enabled_p ())
11757 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
11758 : : "incompatible vector types for invariants\n");
11759 : 0 : return false;
11760 : : }
11761 : :
11762 : 16520 : if (loop_vinfo && for_reduction
11763 : 316 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
11764 : : {
11765 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
11766 : : {
11767 : 0 : if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST,
11768 : : vectype, OPTIMIZE_FOR_SPEED))
11769 : 0 : vect_record_loop_len (loop_vinfo,
11770 : : &LOOP_VINFO_LENS (loop_vinfo),
11771 : : vec_num, vectype, 1);
11772 : : else
11773 : 0 : vect_record_loop_mask (loop_vinfo,
11774 : : &LOOP_VINFO_MASKS (loop_vinfo),
11775 : : vec_num, vectype, NULL);
11776 : : }
11777 : : /* Extra inactive lanes should be safe for vect_nested_cycle. */
11778 : 0 : else if (!nested_cycle_p)
11779 : : {
11780 : 0 : if (dump_enabled_p ())
11781 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
11782 : : "conditional reduction prevents the use"
11783 : : " of partial vectors.\n");
11784 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
11785 : : }
11786 : : }
11787 : :
11788 : 16520 : SLP_TREE_TYPE (slp_node) = condition_vec_info_type;
11789 : 16520 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec, kind);
11790 : 16520 : return true;
11791 : : }
11792 : :
11793 : : /* Transform. */
11794 : :
11795 : : /* Handle def. */
11796 : 6539 : scalar_dest = gimple_assign_lhs (stmt);
11797 : 6539 : if (reduction_type != EXTRACT_LAST_REDUCTION)
11798 : 6539 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11799 : :
11800 : 6539 : bool swap_cond_operands = false;
11801 : :
11802 : : /* See whether another part of the vectorized code applies a loop
11803 : : mask to the condition, or to its inverse. */
11804 : :
11805 : 6539 : vec_loop_masks *masks = NULL;
11806 : 6539 : vec_loop_lens *lens = NULL;
11807 : 6539 : if (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo))
11808 : : {
11809 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
11810 : 0 : lens = &LOOP_VINFO_LENS (loop_vinfo);
11811 : : }
11812 : 6539 : else if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
11813 : : {
11814 : 3 : if (reduction_type == EXTRACT_LAST_REDUCTION)
11815 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
11816 : : else
11817 : : {
11818 : 3 : scalar_cond_masked_key cond (cond_expr, 1);
11819 : 3 : if (loop_vinfo->scalar_cond_masked_set.contains (cond))
11820 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
11821 : : else
11822 : : {
11823 : 3 : bool honor_nans = HONOR_NANS (TREE_TYPE (cond.op0));
11824 : 3 : tree_code orig_code = cond.code;
11825 : 3 : cond.code = invert_tree_comparison (cond.code, honor_nans);
11826 : 3 : if (!masked && loop_vinfo->scalar_cond_masked_set.contains (cond))
11827 : : {
11828 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
11829 : 0 : cond_code = cond.code;
11830 : 0 : swap_cond_operands = true;
11831 : : }
11832 : : else
11833 : : {
11834 : : /* Try the inverse of the current mask. We check if the
11835 : : inverse mask is live and if so we generate a negate of
11836 : : the current mask such that we still honor NaNs. */
11837 : 3 : cond.inverted_p = true;
11838 : 3 : cond.code = orig_code;
11839 : 3 : if (loop_vinfo->scalar_cond_masked_set.contains (cond))
11840 : : {
11841 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
11842 : 0 : cond_code = cond.code;
11843 : 0 : swap_cond_operands = true;
11844 : 0 : must_invert_cmp_result = true;
11845 : : }
11846 : : }
11847 : : }
11848 : : }
11849 : : }
11850 : :
11851 : : /* Handle cond expr. */
11852 : 6539 : if (masked)
11853 : 6539 : vect_get_vec_defs (vinfo, slp_node,
11854 : : cond_expr, &vec_oprnds0,
11855 : : then_clause, &vec_oprnds2,
11856 : : reduction_type != EXTRACT_LAST_REDUCTION
11857 : : ? else_clause : NULL, &vec_oprnds3);
11858 : : else
11859 : 0 : vect_get_vec_defs (vinfo, slp_node,
11860 : : cond_expr0, &vec_oprnds0,
11861 : : cond_expr1, &vec_oprnds1,
11862 : : then_clause, &vec_oprnds2,
11863 : : reduction_type != EXTRACT_LAST_REDUCTION
11864 : : ? else_clause : NULL, &vec_oprnds3);
11865 : :
11866 : 6539 : if (reduction_type == EXTRACT_LAST_REDUCTION)
11867 : 0 : vec_else_clause = else_clause;
11868 : :
11869 : : /* Arguments are ready. Create the new vector stmt. */
11870 : 15703 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_cond_lhs)
11871 : : {
11872 : 9164 : vec_then_clause = vec_oprnds2[i];
11873 : 9164 : if (reduction_type != EXTRACT_LAST_REDUCTION)
11874 : 9164 : vec_else_clause = vec_oprnds3[i];
11875 : :
11876 : 9164 : if (swap_cond_operands)
11877 : 0 : std::swap (vec_then_clause, vec_else_clause);
11878 : :
11879 : 9164 : if (masked)
11880 : : vec_compare = vec_cond_lhs;
11881 : : else
11882 : : {
11883 : 0 : vec_cond_rhs = vec_oprnds1[i];
11884 : 0 : if (bitop1 == NOP_EXPR)
11885 : : {
11886 : 0 : gimple_seq stmts = NULL;
11887 : 0 : vec_compare = gimple_build (&stmts, cond_code, vec_cmp_type,
11888 : : vec_cond_lhs, vec_cond_rhs);
11889 : 0 : gsi_insert_before (gsi, stmts, GSI_SAME_STMT);
11890 : : }
11891 : : else
11892 : : {
11893 : 0 : new_temp = make_ssa_name (vec_cmp_type);
11894 : 0 : gassign *new_stmt;
11895 : 0 : if (bitop1 == BIT_NOT_EXPR)
11896 : 0 : new_stmt = gimple_build_assign (new_temp, bitop1,
11897 : : vec_cond_rhs);
11898 : : else
11899 : 0 : new_stmt
11900 : 0 : = gimple_build_assign (new_temp, bitop1, vec_cond_lhs,
11901 : : vec_cond_rhs);
11902 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11903 : 0 : if (bitop2 == NOP_EXPR)
11904 : : vec_compare = new_temp;
11905 : 0 : else if (bitop2 == BIT_NOT_EXPR
11906 : 0 : && reduction_type != EXTRACT_LAST_REDUCTION)
11907 : : {
11908 : : /* Instead of doing ~x ? y : z do x ? z : y. */
11909 : : vec_compare = new_temp;
11910 : : std::swap (vec_then_clause, vec_else_clause);
11911 : : }
11912 : : else
11913 : : {
11914 : 0 : vec_compare = make_ssa_name (vec_cmp_type);
11915 : 0 : if (bitop2 == BIT_NOT_EXPR)
11916 : 0 : new_stmt
11917 : 0 : = gimple_build_assign (vec_compare, bitop2, new_temp);
11918 : : else
11919 : 0 : new_stmt
11920 : 0 : = gimple_build_assign (vec_compare, bitop2,
11921 : : vec_cond_lhs, new_temp);
11922 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
11923 : : new_stmt, gsi);
11924 : : }
11925 : : }
11926 : : }
11927 : :
11928 : : /* If we decided to apply a loop mask to the result of the vector
11929 : : comparison, AND the comparison with the mask now. Later passes
11930 : : should then be able to reuse the AND results between mulitple
11931 : : vector statements.
11932 : :
11933 : : For example:
11934 : : for (int i = 0; i < 100; ++i)
11935 : : x[i] = y[i] ? z[i] : 10;
11936 : :
11937 : : results in following optimized GIMPLE:
11938 : :
11939 : : mask__35.8_43 = vect__4.7_41 != { 0, ... };
11940 : : vec_mask_and_46 = loop_mask_40 & mask__35.8_43;
11941 : : _19 = &MEM[base: z_12(D), index: ivtmp_56, step: 4, offset: 0B];
11942 : : vect_iftmp.11_47 = .MASK_LOAD (_19, 4B, vec_mask_and_46);
11943 : : vect_iftmp.12_52 = VEC_COND_EXPR <vec_mask_and_46,
11944 : : vect_iftmp.11_47, { 10, ... }>;
11945 : :
11946 : : instead of using a masked and unmasked forms of
11947 : : vec != { 0, ... } (masked in the MASK_LOAD,
11948 : : unmasked in the VEC_COND_EXPR). */
11949 : :
11950 : : /* Force vec_compare to be an SSA_NAME rather than a comparison,
11951 : : in cases where that's necessary. */
11952 : :
11953 : 9164 : tree len = NULL_TREE, bias = NULL_TREE;
11954 : 9164 : if (masks || lens || reduction_type == EXTRACT_LAST_REDUCTION)
11955 : : {
11956 : 0 : if (!is_gimple_val (vec_compare))
11957 : : {
11958 : 0 : tree vec_compare_name = make_ssa_name (vec_cmp_type);
11959 : 0 : gassign *new_stmt = gimple_build_assign (vec_compare_name,
11960 : : vec_compare);
11961 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11962 : 0 : vec_compare = vec_compare_name;
11963 : : }
11964 : :
11965 : 0 : if (must_invert_cmp_result)
11966 : : {
11967 : 0 : tree vec_compare_name = make_ssa_name (vec_cmp_type);
11968 : 0 : gassign *new_stmt = gimple_build_assign (vec_compare_name,
11969 : : BIT_NOT_EXPR,
11970 : : vec_compare);
11971 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11972 : 0 : vec_compare = vec_compare_name;
11973 : : }
11974 : :
11975 : 0 : if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST,
11976 : : vectype, OPTIMIZE_FOR_SPEED))
11977 : : {
11978 : 0 : if (lens)
11979 : : {
11980 : 0 : len = vect_get_loop_len (loop_vinfo, gsi, lens,
11981 : : vec_num, vectype, i, 1);
11982 : 0 : signed char biasval
11983 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
11984 : 0 : bias = build_int_cst (intQI_type_node, biasval);
11985 : : }
11986 : : else
11987 : : {
11988 : 0 : len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
11989 : 0 : bias = build_int_cst (intQI_type_node, 0);
11990 : : }
11991 : : }
11992 : 0 : if (masks)
11993 : : {
11994 : 0 : tree loop_mask
11995 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, vec_num,
11996 : : vectype, i);
11997 : 0 : tree tmp2 = make_ssa_name (vec_cmp_type);
11998 : 0 : gassign *g
11999 : 0 : = gimple_build_assign (tmp2, BIT_AND_EXPR, vec_compare,
12000 : : loop_mask);
12001 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
12002 : 0 : vec_compare = tmp2;
12003 : : }
12004 : : }
12005 : :
12006 : 0 : gimple *new_stmt;
12007 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12008 : : {
12009 : 0 : gimple *old_stmt = vect_orig_stmt (stmt_info)->stmt;
12010 : 0 : tree lhs = gimple_get_lhs (old_stmt);
12011 : 0 : if ((unsigned)i != vec_oprnds0.length () - 1)
12012 : 0 : lhs = copy_ssa_name (lhs);
12013 : 0 : if (len)
12014 : 0 : new_stmt = gimple_build_call_internal
12015 : 0 : (IFN_LEN_FOLD_EXTRACT_LAST, 5, vec_else_clause, vec_compare,
12016 : : vec_then_clause, len, bias);
12017 : : else
12018 : 0 : new_stmt = gimple_build_call_internal
12019 : 0 : (IFN_FOLD_EXTRACT_LAST, 3, vec_else_clause, vec_compare,
12020 : : vec_then_clause);
12021 : 0 : gimple_call_set_lhs (new_stmt, lhs);
12022 : 0 : SSA_NAME_DEF_STMT (lhs) = new_stmt;
12023 : 0 : if ((unsigned)i != vec_oprnds0.length () - 1)
12024 : : {
12025 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12026 : 0 : vec_else_clause = lhs;
12027 : : }
12028 : 0 : else if (old_stmt == gsi_stmt (*gsi))
12029 : 0 : vect_finish_replace_stmt (vinfo, stmt_info, new_stmt);
12030 : : else
12031 : : {
12032 : : /* In this case we're moving the definition to later in the
12033 : : block. That doesn't matter because the only uses of the
12034 : : lhs are in phi statements. */
12035 : 0 : gimple_stmt_iterator old_gsi = gsi_for_stmt (old_stmt);
12036 : 0 : gsi_remove (&old_gsi, true);
12037 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12038 : : }
12039 : : }
12040 : : else
12041 : : {
12042 : 9164 : new_temp = make_ssa_name (vec_dest);
12043 : 9164 : new_stmt = gimple_build_assign (new_temp, VEC_COND_EXPR, vec_compare,
12044 : : vec_then_clause, vec_else_clause);
12045 : 9164 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12046 : : }
12047 : 9164 : slp_node->push_vec_def (new_stmt);
12048 : : }
12049 : :
12050 : 6539 : vec_oprnds0.release ();
12051 : 6539 : vec_oprnds1.release ();
12052 : 6539 : vec_oprnds2.release ();
12053 : 6539 : vec_oprnds3.release ();
12054 : :
12055 : 6539 : return true;
12056 : : }
12057 : :
12058 : : /* Helper of vectorizable_comparison.
12059 : :
12060 : : Check if STMT_INFO is comparison expression CODE that can be vectorized.
12061 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
12062 : : comparison, put it in VEC_STMT, and insert it at GSI.
12063 : :
12064 : : Return true if STMT_INFO is vectorizable in this way. */
12065 : :
12066 : : static bool
12067 : 328899 : vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
12068 : : stmt_vec_info stmt_info, tree_code code,
12069 : : gimple_stmt_iterator *gsi,
12070 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12071 : : {
12072 : 328899 : tree lhs, rhs1, rhs2;
12073 : 328899 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
12074 : 328899 : tree vec_rhs1 = NULL_TREE, vec_rhs2 = NULL_TREE;
12075 : 328899 : tree new_temp;
12076 : 328899 : enum vect_def_type dts[2] = {vect_unknown_def_type, vect_unknown_def_type};
12077 : 328899 : poly_uint64 nunits;
12078 : 328899 : enum tree_code bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
12079 : 328899 : int i;
12080 : 328899 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
12081 : 328899 : vec<tree> vec_oprnds0 = vNULL;
12082 : 328899 : vec<tree> vec_oprnds1 = vNULL;
12083 : 328899 : tree mask_type;
12084 : 328899 : tree mask = NULL_TREE;
12085 : :
12086 : 328899 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
12087 : : return false;
12088 : :
12089 : 328899 : if (!vectype || !VECTOR_BOOLEAN_TYPE_P (vectype))
12090 : : return false;
12091 : :
12092 : 140933 : mask_type = vectype;
12093 : 140933 : nunits = TYPE_VECTOR_SUBPARTS (vectype);
12094 : :
12095 : 140933 : if (TREE_CODE_CLASS (code) != tcc_comparison)
12096 : : return false;
12097 : :
12098 : 139199 : slp_tree slp_rhs1, slp_rhs2;
12099 : 139199 : if (!vect_is_simple_use (vinfo, slp_node,
12100 : : 0, &rhs1, &slp_rhs1, &dts[0], &vectype1))
12101 : : return false;
12102 : :
12103 : 139199 : if (!vect_is_simple_use (vinfo, slp_node,
12104 : : 1, &rhs2, &slp_rhs2, &dts[1], &vectype2))
12105 : : return false;
12106 : :
12107 : 105199 : if (vectype1 && vectype2
12108 : 203120 : && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1),
12109 : 63921 : TYPE_VECTOR_SUBPARTS (vectype2)))
12110 : 16 : return false;
12111 : :
12112 : 139183 : vectype = vectype1 ? vectype1 : vectype2;
12113 : :
12114 : : /* Invariant comparison. */
12115 : 139183 : if (!vectype)
12116 : : {
12117 : 29602 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (rhs1), slp_node);
12118 : 29602 : if (!vectype || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype), nunits))
12119 : 7 : return false;
12120 : : }
12121 : 109581 : else if (maybe_ne (nunits, TYPE_VECTOR_SUBPARTS (vectype)))
12122 : : return false;
12123 : :
12124 : : /* Can't compare mask and non-mask types. */
12125 : 105183 : if (vectype1 && vectype2
12126 : 330277 : && (VECTOR_BOOLEAN_TYPE_P (vectype1) ^ VECTOR_BOOLEAN_TYPE_P (vectype2)))
12127 : : return false;
12128 : :
12129 : : /* Boolean values may have another representation in vectors
12130 : : and therefore we prefer bit operations over comparison for
12131 : : them (which also works for scalar masks). We store opcodes
12132 : : to use in bitop1 and bitop2. Statement is vectorized as
12133 : : BITOP2 (rhs1 BITOP1 rhs2) or
12134 : : rhs1 BITOP2 (BITOP1 rhs2)
12135 : : depending on bitop1 and bitop2 arity. */
12136 : 139168 : bool swap_p = false;
12137 : 139168 : if (VECTOR_BOOLEAN_TYPE_P (vectype))
12138 : : {
12139 : 671 : if (code == GT_EXPR)
12140 : : {
12141 : : bitop1 = BIT_NOT_EXPR;
12142 : : bitop2 = BIT_AND_EXPR;
12143 : : }
12144 : : else if (code == GE_EXPR)
12145 : : {
12146 : : bitop1 = BIT_NOT_EXPR;
12147 : : bitop2 = BIT_IOR_EXPR;
12148 : : }
12149 : : else if (code == LT_EXPR)
12150 : : {
12151 : : bitop1 = BIT_NOT_EXPR;
12152 : : bitop2 = BIT_AND_EXPR;
12153 : : swap_p = true;
12154 : : }
12155 : : else if (code == LE_EXPR)
12156 : : {
12157 : : bitop1 = BIT_NOT_EXPR;
12158 : : bitop2 = BIT_IOR_EXPR;
12159 : : swap_p = true;
12160 : : }
12161 : : else
12162 : : {
12163 : : bitop1 = BIT_XOR_EXPR;
12164 : : if (code == EQ_EXPR)
12165 : : bitop2 = BIT_NOT_EXPR;
12166 : : }
12167 : : }
12168 : :
12169 : 139168 : if (cost_vec)
12170 : : {
12171 : 129340 : if (bitop1 == NOP_EXPR)
12172 : : {
12173 : 128819 : if (!expand_vec_cmp_expr_p (vectype, mask_type, code))
12174 : : return false;
12175 : : }
12176 : : else
12177 : : {
12178 : 521 : machine_mode mode = TYPE_MODE (vectype);
12179 : 521 : optab optab;
12180 : :
12181 : 521 : optab = optab_for_tree_code (bitop1, vectype, optab_default);
12182 : 521 : if (!optab || !can_implement_p (optab, mode))
12183 : 0 : return false;
12184 : :
12185 : 521 : if (bitop2 != NOP_EXPR)
12186 : : {
12187 : 91 : optab = optab_for_tree_code (bitop2, vectype, optab_default);
12188 : 91 : if (!optab || !can_implement_p (optab, mode))
12189 : 0 : return false;
12190 : : }
12191 : : }
12192 : :
12193 : : /* Put types on constant and invariant SLP children. */
12194 : 119998 : if (!vect_maybe_update_slp_op_vectype (slp_rhs1, vectype)
12195 : 119998 : || !vect_maybe_update_slp_op_vectype (slp_rhs2, vectype))
12196 : : {
12197 : 2 : if (dump_enabled_p ())
12198 : 2 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12199 : : "incompatible vector types for invariants\n");
12200 : 2 : return false;
12201 : : }
12202 : :
12203 : 119996 : vect_model_simple_cost (vinfo, 1 + (bitop2 != NOP_EXPR),
12204 : : slp_node, cost_vec);
12205 : 119996 : return true;
12206 : : }
12207 : :
12208 : : /* Transform. */
12209 : :
12210 : : /* Handle def. */
12211 : 9828 : lhs = gimple_get_lhs (STMT_VINFO_STMT (stmt_info));
12212 : 9828 : if (lhs)
12213 : 9828 : mask = vect_create_destination_var (lhs, mask_type);
12214 : :
12215 : 9828 : vect_get_vec_defs (vinfo, slp_node, rhs1, &vec_oprnds0, rhs2, &vec_oprnds1);
12216 : 9828 : if (swap_p)
12217 : 58 : std::swap (vec_oprnds0, vec_oprnds1);
12218 : :
12219 : : /* Arguments are ready. Create the new vector stmt. */
12220 : 22959 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_rhs1)
12221 : : {
12222 : 13131 : gimple *new_stmt;
12223 : 13131 : vec_rhs2 = vec_oprnds1[i];
12224 : :
12225 : 13131 : if (lhs)
12226 : 13131 : new_temp = make_ssa_name (mask);
12227 : : else
12228 : 0 : new_temp = make_temp_ssa_name (mask_type, NULL, "cmp");
12229 : 13131 : if (bitop1 == NOP_EXPR)
12230 : : {
12231 : 12976 : new_stmt = gimple_build_assign (new_temp, code,
12232 : : vec_rhs1, vec_rhs2);
12233 : 12976 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12234 : : }
12235 : : else
12236 : : {
12237 : 155 : if (bitop1 == BIT_NOT_EXPR)
12238 : 84 : new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs2);
12239 : : else
12240 : 71 : new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs1,
12241 : : vec_rhs2);
12242 : 155 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12243 : 155 : if (bitop2 != NOP_EXPR)
12244 : : {
12245 : 84 : tree res = make_ssa_name (mask);
12246 : 84 : if (bitop2 == BIT_NOT_EXPR)
12247 : 0 : new_stmt = gimple_build_assign (res, bitop2, new_temp);
12248 : : else
12249 : 84 : new_stmt = gimple_build_assign (res, bitop2, vec_rhs1,
12250 : : new_temp);
12251 : 84 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12252 : : }
12253 : : }
12254 : 13131 : slp_node->push_vec_def (new_stmt);
12255 : : }
12256 : :
12257 : 9828 : vec_oprnds0.release ();
12258 : 9828 : vec_oprnds1.release ();
12259 : :
12260 : 9828 : return true;
12261 : : }
12262 : :
12263 : : /* vectorizable_comparison.
12264 : :
12265 : : Check if STMT_INFO is comparison expression that can be vectorized.
12266 : : If VEC_STMT is also passed, vectorize STMT_INFO: create a vectorized
12267 : : comparison, put it in VEC_STMT, and insert it at GSI.
12268 : :
12269 : : Return true if STMT_INFO is vectorizable in this way. */
12270 : :
12271 : : static bool
12272 : 577500 : vectorizable_comparison (vec_info *vinfo,
12273 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
12274 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12275 : : {
12276 : 577500 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
12277 : :
12278 : 577500 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
12279 : : return false;
12280 : :
12281 : 577500 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
12282 : : return false;
12283 : :
12284 : 776575 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
12285 : 326716 : if (!stmt)
12286 : : return false;
12287 : :
12288 : 326716 : enum tree_code code = gimple_assign_rhs_code (stmt);
12289 : 326716 : tree vectype = SLP_TREE_VECTYPE (slp_node);
12290 : 326716 : if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
12291 : : slp_node, cost_vec))
12292 : : return false;
12293 : :
12294 : 127641 : if (cost_vec)
12295 : 117813 : SLP_TREE_TYPE (slp_node) = comparison_vec_info_type;
12296 : :
12297 : : return true;
12298 : : }
12299 : :
12300 : : /* Check to see if the current early break given in STMT_INFO is valid for
12301 : : vectorization. */
12302 : :
12303 : : bool
12304 : 221787 : vectorizable_early_exit (loop_vec_info loop_vinfo, stmt_vec_info stmt_info,
12305 : : gimple_stmt_iterator *gsi,
12306 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12307 : : {
12308 : 221787 : if (!is_a <gcond *> (STMT_VINFO_STMT (stmt_info)))
12309 : : return false;
12310 : :
12311 : 58096 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_condition_def)
12312 : : return false;
12313 : :
12314 : 58096 : if (!STMT_VINFO_RELEVANT_P (stmt_info))
12315 : : return false;
12316 : :
12317 : 58096 : DUMP_VECT_SCOPE ("vectorizable_early_exit");
12318 : :
12319 : 58096 : auto code = gimple_cond_code (STMT_VINFO_STMT (stmt_info));
12320 : :
12321 : : /* For SLP we don't want to use the type of the operands of the SLP node, when
12322 : : vectorizing using SLP slp_node will be the children of the gcond and we
12323 : : want to use the type of the direct children which since the gcond is root
12324 : : will be the current node, rather than a child node as vect_is_simple_use
12325 : : assumes. */
12326 : 58096 : tree vectype = SLP_TREE_VECTYPE (slp_node);
12327 : 58096 : if (!vectype)
12328 : : return false;
12329 : :
12330 : 58096 : machine_mode mode = TYPE_MODE (vectype);
12331 : 58096 : int vec_num = vect_get_num_copies (loop_vinfo, slp_node);
12332 : :
12333 : 58096 : vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
12334 : 58096 : vec_loop_lens *lens = &LOOP_VINFO_LENS (loop_vinfo);
12335 : 58096 : bool masked_loop_p = LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
12336 : 58096 : bool len_loop_p = LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
12337 : :
12338 : : /* Now build the new conditional. Pattern gimple_conds get dropped during
12339 : : codegen so we must replace the original insn. */
12340 : 58096 : gimple *orig_stmt = STMT_VINFO_STMT (vect_orig_stmt (stmt_info));
12341 : 58096 : gcond *cond_stmt = as_a <gcond *>(orig_stmt);
12342 : :
12343 : 58096 : tree vectype_out = vectype;
12344 : 58096 : auto bb = gimple_bb (cond_stmt);
12345 : 58096 : edge exit_true_edge = EDGE_SUCC (bb, 0);
12346 : 58096 : if (exit_true_edge->flags & EDGE_FALSE_VALUE)
12347 : 806 : exit_true_edge = EDGE_SUCC (bb, 1);
12348 : 58096 : gcc_assert (exit_true_edge->flags & EDGE_TRUE_VALUE);
12349 : :
12350 : : /* When vectorizing we assume that if the branch edge is taken that we're
12351 : : exiting the loop. This is not however always the case as the compiler will
12352 : : rewrite conditions to always be a comparison against 0. To do this it
12353 : : sometimes flips the edges. This is fine for scalar, but for vector we
12354 : : then have to negate the result of the test, as we're still assuming that if
12355 : : you take the branch edge that we found the exit condition. i.e. we need to
12356 : : know whether we are generating a `forall` or an `exist` condition. */
12357 : 116192 : bool flipped = flow_bb_inside_loop_p (LOOP_VINFO_LOOP (loop_vinfo),
12358 : 58096 : exit_true_edge->dest);
12359 : :
12360 : : /* See if we support ADDHN and use that for the reduction. */
12361 : 58096 : internal_fn ifn = IFN_VEC_TRUNC_ADD_HIGH;
12362 : 58096 : bool addhn_supported_p
12363 : 58096 : = direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_BOTH);
12364 : 58096 : tree narrow_type = NULL_TREE;
12365 : 58096 : if (addhn_supported_p)
12366 : : {
12367 : : /* Calculate the narrowing type for the result. */
12368 : 0 : auto halfprec = TYPE_PRECISION (TREE_TYPE (vectype)) / 2;
12369 : 0 : auto unsignedp = TYPE_UNSIGNED (TREE_TYPE (vectype));
12370 : 0 : tree itype = build_nonstandard_integer_type (halfprec, unsignedp);
12371 : 0 : tree tmp_type = build_vector_type (itype, TYPE_VECTOR_SUBPARTS (vectype));
12372 : 0 : narrow_type = truth_type_for (tmp_type);
12373 : :
12374 : 0 : if (direct_optab_handler (cbranch_optab, TYPE_MODE (narrow_type))
12375 : : == CODE_FOR_nothing)
12376 : : {
12377 : 0 : if (dump_enabled_p ())
12378 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12379 : : "can't use ADDHN reduction because cbranch for "
12380 : : "the narrowed type is not supported by the "
12381 : : "target.\n");
12382 : : addhn_supported_p = false;
12383 : : }
12384 : : }
12385 : :
12386 : : /* Analyze only. */
12387 : 58096 : if (cost_vec)
12388 : : {
12389 : 56476 : if (!addhn_supported_p
12390 : 112952 : && direct_optab_handler (cbranch_optab, mode) == CODE_FOR_nothing)
12391 : : {
12392 : 54293 : if (dump_enabled_p ())
12393 : 567 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12394 : : "can't vectorize early exit because the "
12395 : : "target doesn't support flag setting vector "
12396 : : "comparisons.\n");
12397 : 54293 : return false;
12398 : : }
12399 : :
12400 : 2183 : if (!vectorizable_comparison_1 (loop_vinfo, vectype, stmt_info, code, gsi,
12401 : : slp_node, cost_vec))
12402 : : return false;
12403 : :
12404 : 2183 : if (LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
12405 : : {
12406 : 1 : if (direct_internal_fn_supported_p (IFN_VCOND_MASK_LEN, vectype,
12407 : : OPTIMIZE_FOR_SPEED))
12408 : 0 : vect_record_loop_len (loop_vinfo, lens, vec_num, vectype, 1);
12409 : : else
12410 : 1 : vect_record_loop_mask (loop_vinfo, masks, vec_num, vectype, NULL);
12411 : : }
12412 : :
12413 : 2183 : return true;
12414 : : }
12415 : :
12416 : : /* Tranform. */
12417 : :
12418 : 1620 : tree new_temp = NULL_TREE;
12419 : 1620 : gimple *new_stmt = NULL;
12420 : :
12421 : 1620 : if (dump_enabled_p ())
12422 : 345 : dump_printf_loc (MSG_NOTE, vect_location, "transform early-exit.\n");
12423 : :
12424 : : /* For SLP we don't do codegen of the body starting from the gcond, the gconds are
12425 : : roots and so by the time we get to them we have already codegened the SLP tree
12426 : : and so we shouldn't try to do so again. The arguments have already been
12427 : : vectorized. It's not very clean to do this here, But the masking code below is
12428 : : complex and this keeps it all in one place to ease fixes and backports. Once we
12429 : : drop the non-SLP loop vect or split vectorizable_* this can be simplified. */
12430 : :
12431 : 1620 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
12432 : 1620 : basic_block cond_bb = gimple_bb (stmt);
12433 : 1620 : gimple_stmt_iterator cond_gsi = gsi_last_bb (cond_bb);
12434 : :
12435 : 1620 : auto_vec<tree> stmts;
12436 : 1620 : stmts.safe_splice (SLP_TREE_VEC_DEFS (slp_node));
12437 : :
12438 : : /* If we're comparing against a previous forall we need to negate the resullts
12439 : : before we do the final comparison or reduction. */
12440 : 1620 : if (flipped)
12441 : : {
12442 : : /* Rewrite the if(all(mask)) into if (!all(mask)) which is the same as
12443 : : if (any(~mask)) by negating the masks and flipping the branches.
12444 : :
12445 : : 1. For unmasked loops we simply reduce the ~mask.
12446 : : 2. For masked loops we reduce (~mask & loop_mask) which is the same as
12447 : : doing (mask & loop_mask) ^ loop_mask. */
12448 : 222 : for (unsigned i = 0; i < stmts.length (); i++)
12449 : : {
12450 : 133 : tree inv_lhs = make_temp_ssa_name (vectype, NULL, "vexit_inv");
12451 : 133 : auto inv_stmt = gimple_build_assign (inv_lhs, BIT_NOT_EXPR, stmts[i]);
12452 : 133 : vect_finish_stmt_generation (loop_vinfo, stmt_info, inv_stmt,
12453 : : &cond_gsi);
12454 : 133 : stmts[i] = inv_lhs;
12455 : : }
12456 : :
12457 : 89 : EDGE_SUCC (bb, 0)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
12458 : 89 : EDGE_SUCC (bb, 1)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
12459 : : }
12460 : :
12461 : : /* Determine if we need to reduce the final value. */
12462 : 1620 : if (stmts.length () > 1)
12463 : : {
12464 : : /* We build the reductions in a way to maintain as much parallelism as
12465 : : possible. */
12466 : 399 : auto_vec<tree> workset (stmts.length ());
12467 : :
12468 : : /* Mask the statements as we queue them up. Normally we loop over
12469 : : vec_num, but since we inspect the exact results of vectorization
12470 : : we don't need to and instead can just use the stmts themselves. */
12471 : 399 : if (masked_loop_p)
12472 : 0 : for (unsigned i = 0; i < stmts.length (); i++)
12473 : : {
12474 : 0 : tree stmt_mask
12475 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, vec_num,
12476 : : vectype, i);
12477 : 0 : stmt_mask
12478 : 0 : = prepare_vec_mask (loop_vinfo, TREE_TYPE (stmt_mask), stmt_mask,
12479 : 0 : stmts[i], &cond_gsi);
12480 : 0 : workset.quick_push (stmt_mask);
12481 : : }
12482 : 399 : else if (len_loop_p)
12483 : 0 : for (unsigned i = 0; i < stmts.length (); i++)
12484 : : {
12485 : 0 : tree len_mask = vect_gen_loop_len_mask (loop_vinfo, gsi, &cond_gsi,
12486 : : lens, vec_num,
12487 : 0 : vectype, stmts[i], i, 1);
12488 : :
12489 : 0 : workset.quick_push (len_mask);
12490 : : }
12491 : : else
12492 : 399 : workset.splice (stmts);
12493 : :
12494 : 938 : while (workset.length () > 1)
12495 : : {
12496 : 539 : tree arg0 = workset.pop ();
12497 : 539 : tree arg1 = workset.pop ();
12498 : 539 : if (addhn_supported_p && workset.length () == 0)
12499 : : {
12500 : 0 : new_stmt = gimple_build_call_internal (ifn, 2, arg0, arg1);
12501 : 0 : vectype_out = narrow_type;
12502 : 0 : new_temp = make_temp_ssa_name (vectype_out, NULL, "vexit_reduc");
12503 : 0 : gimple_call_set_lhs (as_a <gcall *> (new_stmt), new_temp);
12504 : 0 : gimple_call_set_nothrow (as_a <gcall *> (new_stmt), true);
12505 : : }
12506 : : else
12507 : : {
12508 : 539 : new_temp = make_temp_ssa_name (vectype_out, NULL, "vexit_reduc");
12509 : 539 : new_stmt
12510 : 539 : = gimple_build_assign (new_temp, BIT_IOR_EXPR, arg0, arg1);
12511 : : }
12512 : 539 : vect_finish_stmt_generation (loop_vinfo, stmt_info, new_stmt,
12513 : : &cond_gsi);
12514 : 539 : workset.quick_insert (0, new_temp);
12515 : : }
12516 : 399 : }
12517 : : else
12518 : : {
12519 : 1221 : new_temp = stmts[0];
12520 : 1221 : if (masked_loop_p)
12521 : : {
12522 : 0 : tree mask
12523 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, 1, vectype, 0);
12524 : 0 : new_temp = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
12525 : : new_temp, &cond_gsi);
12526 : : }
12527 : 1221 : else if (len_loop_p)
12528 : 0 : new_temp = vect_gen_loop_len_mask (loop_vinfo, gsi, &cond_gsi, lens,
12529 : : 1, vectype, new_temp, 0, 1);
12530 : : }
12531 : :
12532 : 1620 : gcc_assert (new_temp);
12533 : :
12534 : 1620 : tree cst = build_zero_cst (vectype_out);
12535 : 1620 : gimple_cond_set_condition (cond_stmt, NE_EXPR, new_temp, cst);
12536 : 1620 : update_stmt (orig_stmt);
12537 : :
12538 : : /* ??? */
12539 : 1620 : SLP_TREE_VEC_DEFS (slp_node).truncate (0);
12540 : :
12541 : 1620 : return true;
12542 : 1620 : }
12543 : :
12544 : : /* If SLP_NODE is nonnull, return true if vectorizable_live_operation
12545 : : can handle all live statements in the node. Otherwise return true
12546 : : if STMT_INFO is not live or if vectorizable_live_operation can handle it.
12547 : : VEC_STMT_P is as for vectorizable_live_operation. */
12548 : :
12549 : : static bool
12550 : 1346408 : can_vectorize_live_stmts (vec_info *vinfo,
12551 : : slp_tree slp_node, slp_instance slp_node_instance,
12552 : : bool vec_stmt_p,
12553 : : stmt_vector_for_cost *cost_vec)
12554 : : {
12555 : 1346408 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
12556 : 1346408 : stmt_vec_info slp_stmt_info;
12557 : 1346408 : unsigned int i;
12558 : 3061834 : FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (slp_node), i, slp_stmt_info)
12559 : : {
12560 : 1715426 : if (slp_stmt_info
12561 : 1696570 : && (STMT_VINFO_LIVE_P (slp_stmt_info)
12562 : 1513028 : || (loop_vinfo
12563 : 1230417 : && LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
12564 : 225580 : && STMT_VINFO_DEF_TYPE (slp_stmt_info)
12565 : : == vect_induction_def))
12566 : 1898968 : && !vectorizable_live_operation (vinfo, slp_stmt_info, slp_node,
12567 : : slp_node_instance, i,
12568 : : vec_stmt_p, cost_vec))
12569 : : return false;
12570 : : }
12571 : :
12572 : : return true;
12573 : : }
12574 : :
12575 : : /* Make sure the statement is vectorizable. */
12576 : :
12577 : : opt_result
12578 : 2286090 : vect_analyze_stmt (vec_info *vinfo,
12579 : : slp_tree node, slp_instance node_instance,
12580 : : stmt_vector_for_cost *cost_vec)
12581 : : {
12582 : 2286090 : stmt_vec_info stmt_info = SLP_TREE_REPRESENTATIVE (node);
12583 : 2286090 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
12584 : 2286090 : enum vect_relevant relevance = STMT_VINFO_RELEVANT (stmt_info);
12585 : 2286090 : bool ok;
12586 : :
12587 : 2286090 : if (dump_enabled_p ())
12588 : 93508 : dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: %G",
12589 : : stmt_info->stmt);
12590 : :
12591 : 4335324 : if (gimple_has_volatile_ops (stmt_info->stmt))
12592 : : {
12593 : : /* ??? This shouldn't really happen, volatile stmts should
12594 : : not end up in the SLP graph. */
12595 : 0 : return opt_result::failure_at (stmt_info->stmt,
12596 : : "not vectorized:"
12597 : : " stmt has volatile operands: %G\n",
12598 : : stmt_info->stmt);
12599 : : }
12600 : :
12601 : : /* Skip stmts that do not need to be vectorized. */
12602 : 2286090 : if (!STMT_VINFO_RELEVANT_P (stmt_info)
12603 : 0 : && !STMT_VINFO_LIVE_P (stmt_info))
12604 : : {
12605 : 0 : if (dump_enabled_p ())
12606 : 0 : dump_printf_loc (MSG_NOTE, vect_location, "irrelevant.\n");
12607 : :
12608 : : /* ??? This shouldn't really happen, irrelevant stmts should
12609 : : not end up in the SLP graph. */
12610 : 0 : return opt_result::failure_at (stmt_info->stmt,
12611 : : "not vectorized:"
12612 : : " irrelevant stmt as SLP node %p "
12613 : : "representative.\n",
12614 : : (void *)node);
12615 : : }
12616 : :
12617 : 2286090 : switch (STMT_VINFO_DEF_TYPE (stmt_info))
12618 : : {
12619 : : case vect_internal_def:
12620 : : case vect_condition_def:
12621 : : break;
12622 : :
12623 : 53533 : case vect_reduction_def:
12624 : 53533 : case vect_nested_cycle:
12625 : 53533 : gcc_assert (!bb_vinfo
12626 : : && (relevance == vect_used_in_outer
12627 : : || relevance == vect_used_in_outer_by_reduction
12628 : : || relevance == vect_used_by_reduction
12629 : : || relevance == vect_unused_in_scope
12630 : : || relevance == vect_used_only_live));
12631 : : break;
12632 : :
12633 : 388 : case vect_double_reduction_def:
12634 : 388 : gcc_assert (!bb_vinfo && node);
12635 : : break;
12636 : :
12637 : 126386 : case vect_induction_def:
12638 : 126386 : case vect_first_order_recurrence:
12639 : 126386 : gcc_assert (!bb_vinfo);
12640 : : break;
12641 : :
12642 : 0 : case vect_constant_def:
12643 : 0 : case vect_external_def:
12644 : 0 : case vect_unknown_def_type:
12645 : 0 : default:
12646 : 0 : gcc_unreachable ();
12647 : : }
12648 : :
12649 : 2286090 : tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info);
12650 : 2286090 : STMT_VINFO_VECTYPE (stmt_info) = NULL_TREE;
12651 : :
12652 : 2286090 : if (STMT_VINFO_RELEVANT_P (stmt_info))
12653 : : {
12654 : 2286090 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
12655 : 2286090 : gcc_assert (SLP_TREE_VECTYPE (node)
12656 : : || gimple_code (stmt_info->stmt) == GIMPLE_COND
12657 : : || (call && gimple_call_lhs (call) == NULL_TREE));
12658 : : }
12659 : :
12660 : 2286090 : ok = true;
12661 : 2286090 : if (bb_vinfo
12662 : 1111170 : || (STMT_VINFO_RELEVANT_P (stmt_info)
12663 : 0 : || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def))
12664 : : /* Prefer vectorizable_call over vectorizable_simd_clone_call so
12665 : : -mveclibabi= takes preference over library functions with
12666 : : the simd attribute. */
12667 : 2286090 : ok = (vectorizable_call (vinfo, stmt_info, NULL, node, cost_vec)
12668 : 2280620 : || vectorizable_simd_clone_call (vinfo, stmt_info, NULL, node,
12669 : : cost_vec)
12670 : 2280181 : || vectorizable_conversion (vinfo, stmt_info, NULL, node, cost_vec)
12671 : 2220575 : || vectorizable_operation (vinfo, stmt_info, NULL, node, cost_vec)
12672 : 1828882 : || vectorizable_assignment (vinfo, stmt_info, NULL, node, cost_vec)
12673 : 1773541 : || vectorizable_load (vinfo, stmt_info, NULL, node, cost_vec)
12674 : 1399023 : || vectorizable_store (vinfo, stmt_info, NULL, node, cost_vec)
12675 : 621894 : || vectorizable_shift (vinfo, stmt_info, NULL, node, cost_vec)
12676 : 584192 : || vectorizable_condition (vinfo, stmt_info, NULL, node, cost_vec)
12677 : 567672 : || vectorizable_comparison (vinfo, stmt_info, NULL, node, cost_vec)
12678 : 449859 : || (bb_vinfo
12679 : 134690 : && vectorizable_phi (bb_vinfo, stmt_info, node, cost_vec))
12680 : 2673200 : || (is_a <loop_vec_info> (vinfo)
12681 : 315169 : && (vectorizable_lane_reducing (as_a <loop_vec_info> (vinfo),
12682 : : stmt_info, node, cost_vec)
12683 : 314730 : || vectorizable_reduction (as_a <loop_vec_info> (vinfo),
12684 : : stmt_info,
12685 : : node, node_instance, cost_vec)
12686 : 263958 : || vectorizable_induction (as_a <loop_vec_info> (vinfo),
12687 : : stmt_info, node, cost_vec)
12688 : 164590 : || vectorizable_lc_phi (as_a <loop_vec_info> (vinfo),
12689 : : stmt_info, node)
12690 : 163917 : || vectorizable_recurr (as_a <loop_vec_info> (vinfo),
12691 : : stmt_info, node, cost_vec)
12692 : 163691 : || vectorizable_early_exit (as_a <loop_vec_info> (vinfo),
12693 : : stmt_info, NULL, node,
12694 : : cost_vec))));
12695 : :
12696 : 2286090 : STMT_VINFO_VECTYPE (stmt_info) = saved_vectype;
12697 : :
12698 : 2050458 : if (!ok)
12699 : 235632 : return opt_result::failure_at (stmt_info->stmt,
12700 : : "not vectorized:"
12701 : : " relevant stmt not supported: %G",
12702 : : stmt_info->stmt);
12703 : :
12704 : : /* Stmts that are (also) "live" (i.e. - that are used out of the loop)
12705 : : need extra handling, except for vectorizable reductions. */
12706 : 2050458 : if (!bb_vinfo
12707 : 947479 : && SLP_TREE_TYPE (node) != reduc_vec_info_type
12708 : 940231 : && (SLP_TREE_TYPE (node) != lc_phi_info_type
12709 : 673 : || SLP_TREE_DEF_TYPE (node) == vect_internal_def)
12710 : 940231 : && (!node->ldst_lanes || SLP_TREE_PERMUTE_P (node))
12711 : 2990689 : && !can_vectorize_live_stmts (as_a <loop_vec_info> (vinfo),
12712 : : node, node_instance,
12713 : : false, cost_vec))
12714 : 0 : return opt_result::failure_at (stmt_info->stmt,
12715 : : "not vectorized:"
12716 : : " live stmt not supported: %G",
12717 : : stmt_info->stmt);
12718 : :
12719 : 2050458 : return opt_result::success ();
12720 : : }
12721 : :
12722 : :
12723 : : /* Function vect_transform_stmt.
12724 : :
12725 : : Create a vectorized stmt to replace STMT_INFO, and insert it at GSI. */
12726 : :
12727 : : bool
12728 : 951838 : vect_transform_stmt (vec_info *vinfo,
12729 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
12730 : : slp_tree slp_node, slp_instance slp_node_instance)
12731 : : {
12732 : 951838 : bool is_store = false;
12733 : 951838 : bool done;
12734 : :
12735 : 951838 : gcc_assert (slp_node);
12736 : :
12737 : 951838 : if (stmt_info)
12738 : 950977 : STMT_VINFO_VECTYPE (stmt_info) = NULL_TREE;
12739 : :
12740 : 951838 : switch (SLP_TREE_TYPE (slp_node))
12741 : : {
12742 : 19581 : case type_demotion_vec_info_type:
12743 : 19581 : case type_promotion_vec_info_type:
12744 : 19581 : case type_conversion_vec_info_type:
12745 : 19581 : done = vectorizable_conversion (vinfo, stmt_info, gsi, slp_node, NULL);
12746 : 19581 : gcc_assert (done);
12747 : : break;
12748 : :
12749 : 16109 : case induc_vec_info_type:
12750 : 16109 : done = vectorizable_induction (as_a <loop_vec_info> (vinfo),
12751 : : stmt_info, slp_node, NULL);
12752 : 16109 : gcc_assert (done);
12753 : : break;
12754 : :
12755 : 6195 : case shift_vec_info_type:
12756 : 6195 : done = vectorizable_shift (vinfo, stmt_info, gsi, slp_node, NULL);
12757 : 6195 : gcc_assert (done);
12758 : : break;
12759 : :
12760 : 108708 : case op_vec_info_type:
12761 : 108708 : done = vectorizable_operation (vinfo, stmt_info, gsi, slp_node, NULL);
12762 : 108708 : gcc_assert (done);
12763 : : break;
12764 : :
12765 : 13964 : case assignment_vec_info_type:
12766 : 13964 : done = vectorizable_assignment (vinfo, stmt_info, gsi, slp_node, NULL);
12767 : 13964 : gcc_assert (done);
12768 : : break;
12769 : :
12770 : 164099 : case load_vec_info_type:
12771 : 164099 : done = vectorizable_load (vinfo, stmt_info, gsi, slp_node, NULL);
12772 : 164099 : gcc_assert (done);
12773 : : break;
12774 : :
12775 : 545661 : case store_vec_info_type:
12776 : 545661 : done = vectorizable_store (vinfo, stmt_info, gsi, slp_node, NULL);
12777 : 545661 : gcc_assert (done);
12778 : : is_store = true;
12779 : : break;
12780 : :
12781 : 6539 : case condition_vec_info_type:
12782 : 6539 : done = vectorizable_condition (vinfo, stmt_info, gsi, slp_node, NULL);
12783 : 6539 : gcc_assert (done);
12784 : : break;
12785 : :
12786 : 9828 : case comparison_vec_info_type:
12787 : 9828 : done = vectorizable_comparison (vinfo, stmt_info, gsi, slp_node, NULL);
12788 : 9828 : gcc_assert (done);
12789 : : break;
12790 : :
12791 : 4195 : case call_vec_info_type:
12792 : 4195 : done = vectorizable_call (vinfo, stmt_info, gsi, slp_node, NULL);
12793 : 4195 : break;
12794 : :
12795 : 344 : case call_simd_clone_vec_info_type:
12796 : 344 : done = vectorizable_simd_clone_call (vinfo, stmt_info, gsi,
12797 : : slp_node, NULL);
12798 : 344 : break;
12799 : :
12800 : 2325 : case reduc_vec_info_type:
12801 : 2325 : done = vect_transform_reduction (as_a <loop_vec_info> (vinfo), stmt_info,
12802 : : gsi, slp_node);
12803 : 2325 : gcc_assert (done);
12804 : : break;
12805 : :
12806 : 22612 : case cycle_phi_info_type:
12807 : 22612 : done = vect_transform_cycle_phi (as_a <loop_vec_info> (vinfo), stmt_info,
12808 : : slp_node, slp_node_instance);
12809 : 22612 : gcc_assert (done);
12810 : : break;
12811 : :
12812 : 428 : case lc_phi_info_type:
12813 : 428 : done = vect_transform_lc_phi (as_a <loop_vec_info> (vinfo),
12814 : : stmt_info, slp_node);
12815 : 428 : gcc_assert (done);
12816 : : break;
12817 : :
12818 : 42 : case recurr_info_type:
12819 : 42 : done = vectorizable_recurr (as_a <loop_vec_info> (vinfo),
12820 : : stmt_info, slp_node, NULL);
12821 : 42 : gcc_assert (done);
12822 : : break;
12823 : :
12824 : 15249 : case phi_info_type:
12825 : 15249 : done = vectorizable_phi (as_a <bb_vec_info> (vinfo),
12826 : : stmt_info, slp_node, NULL);
12827 : 15249 : gcc_assert (done);
12828 : : break;
12829 : :
12830 : 0 : case loop_exit_ctrl_vec_info_type:
12831 : 0 : done = vectorizable_early_exit (as_a <loop_vec_info> (vinfo),
12832 : : stmt_info, gsi, slp_node, NULL);
12833 : 0 : gcc_assert (done);
12834 : : break;
12835 : :
12836 : 15959 : case permute_info_type:
12837 : 15959 : done = vectorizable_slp_permutation (vinfo, gsi, slp_node, NULL);
12838 : 15959 : gcc_assert (done);
12839 : : break;
12840 : :
12841 : 0 : default:
12842 : 0 : if (!STMT_VINFO_LIVE_P (stmt_info))
12843 : : {
12844 : 0 : if (dump_enabled_p ())
12845 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12846 : : "stmt not supported.\n");
12847 : 0 : gcc_unreachable ();
12848 : : }
12849 : 951838 : done = true;
12850 : : }
12851 : :
12852 : 951838 : if (SLP_TREE_TYPE (slp_node) != store_vec_info_type
12853 : 406177 : && (!slp_node->ldst_lanes || SLP_TREE_PERMUTE_P (slp_node)))
12854 : : {
12855 : : /* Handle stmts whose DEF is used outside the loop-nest that is
12856 : : being vectorized. */
12857 : 406177 : done = can_vectorize_live_stmts (vinfo, slp_node,
12858 : : slp_node_instance, true, NULL);
12859 : 406177 : gcc_assert (done);
12860 : : }
12861 : :
12862 : 951838 : return is_store;
12863 : : }
12864 : :
12865 : :
12866 : : /* Remove a group of stores (for SLP or interleaving), free their
12867 : : stmt_vec_info. */
12868 : :
12869 : : void
12870 : 0 : vect_remove_stores (vec_info *vinfo, stmt_vec_info first_stmt_info)
12871 : : {
12872 : 0 : stmt_vec_info next_stmt_info = first_stmt_info;
12873 : :
12874 : 0 : while (next_stmt_info)
12875 : : {
12876 : 0 : stmt_vec_info tmp = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
12877 : 0 : next_stmt_info = vect_orig_stmt (next_stmt_info);
12878 : : /* Free the attached stmt_vec_info and remove the stmt. */
12879 : 0 : vinfo->remove_stmt (next_stmt_info);
12880 : 0 : next_stmt_info = tmp;
12881 : : }
12882 : 0 : }
12883 : :
12884 : : /* If NUNITS is nonzero, return a vector type that contains NUNITS
12885 : : elements of type SCALAR_TYPE, or null if the target doesn't support
12886 : : such a type.
12887 : :
12888 : : If NUNITS is zero, return a vector type that contains elements of
12889 : : type SCALAR_TYPE, choosing whichever vector size the target prefers.
12890 : :
12891 : : If PREVAILING_MODE is VOIDmode, we have not yet chosen a vector mode
12892 : : for this vectorization region and want to "autodetect" the best choice.
12893 : : Otherwise, PREVAILING_MODE is a previously-chosen vector TYPE_MODE
12894 : : and we want the new type to be interoperable with it. PREVAILING_MODE
12895 : : in this case can be a scalar integer mode or a vector mode; when it
12896 : : is a vector mode, the function acts like a tree-level version of
12897 : : related_vector_mode. */
12898 : :
12899 : : tree
12900 : 31102122 : get_related_vectype_for_scalar_type (machine_mode prevailing_mode,
12901 : : tree scalar_type, poly_uint64 nunits)
12902 : : {
12903 : 31102122 : tree orig_scalar_type = scalar_type;
12904 : 31102122 : scalar_mode inner_mode;
12905 : 31102122 : machine_mode simd_mode;
12906 : 31102122 : tree vectype;
12907 : :
12908 : 31102122 : if ((!INTEGRAL_TYPE_P (scalar_type)
12909 : 10531276 : && !POINTER_TYPE_P (scalar_type)
12910 : 1651800 : && !SCALAR_FLOAT_TYPE_P (scalar_type))
12911 : 41154254 : || (!is_int_mode (TYPE_MODE (scalar_type), &inner_mode)
12912 : 1172738 : && !is_float_mode (TYPE_MODE (scalar_type), &inner_mode)))
12913 : 482359 : return NULL_TREE;
12914 : :
12915 : 30619763 : unsigned int nbytes = GET_MODE_SIZE (inner_mode);
12916 : :
12917 : : /* Interoperability between modes requires one to be a constant multiple
12918 : : of the other, so that the number of vectors required for each operation
12919 : : is a compile-time constant. */
12920 : 30619763 : if (prevailing_mode != VOIDmode
12921 : 29537474 : && !constant_multiple_p (nunits * nbytes,
12922 : 29537474 : GET_MODE_SIZE (prevailing_mode))
12923 : 32134343 : && !constant_multiple_p (GET_MODE_SIZE (prevailing_mode),
12924 : 1514580 : nunits * nbytes))
12925 : : return NULL_TREE;
12926 : :
12927 : : /* For vector types of elements whose mode precision doesn't
12928 : : match their types precision we use a element type of mode
12929 : : precision. The vectorization routines will have to make sure
12930 : : they support the proper result truncation/extension.
12931 : : We also make sure to build vector types with INTEGER_TYPE
12932 : : component type only. */
12933 : 30619763 : if (INTEGRAL_TYPE_P (scalar_type)
12934 : 51190527 : && (GET_MODE_BITSIZE (inner_mode) != TYPE_PRECISION (scalar_type)
12935 : 18625707 : || TREE_CODE (scalar_type) != INTEGER_TYPE))
12936 : 2223657 : scalar_type = build_nonstandard_integer_type (GET_MODE_BITSIZE (inner_mode),
12937 : 2223657 : TYPE_UNSIGNED (scalar_type));
12938 : :
12939 : : /* We shouldn't end up building VECTOR_TYPEs of non-scalar components.
12940 : : When the component mode passes the above test simply use a type
12941 : : corresponding to that mode. The theory is that any use that
12942 : : would cause problems with this will disable vectorization anyway. */
12943 : 28396106 : else if (!SCALAR_FLOAT_TYPE_P (scalar_type)
12944 : : && !INTEGRAL_TYPE_P (scalar_type))
12945 : 8879476 : scalar_type = lang_hooks.types.type_for_mode (inner_mode, 1);
12946 : :
12947 : : /* We can't build a vector type of elements with alignment bigger than
12948 : : their size. */
12949 : 19516630 : else if (nbytes < TYPE_ALIGN_UNIT (scalar_type))
12950 : 338070 : scalar_type = lang_hooks.types.type_for_mode (inner_mode,
12951 : 169035 : TYPE_UNSIGNED (scalar_type));
12952 : :
12953 : : /* If we felt back to using the mode fail if there was
12954 : : no scalar type for it. */
12955 : 30619763 : if (scalar_type == NULL_TREE)
12956 : : return NULL_TREE;
12957 : :
12958 : : /* If no prevailing mode was supplied, use the mode the target prefers.
12959 : : Otherwise lookup a vector mode based on the prevailing mode. */
12960 : 30619763 : if (prevailing_mode == VOIDmode)
12961 : : {
12962 : 1082289 : gcc_assert (known_eq (nunits, 0U));
12963 : 1082289 : simd_mode = targetm.vectorize.preferred_simd_mode (inner_mode);
12964 : 1082289 : if (SCALAR_INT_MODE_P (simd_mode))
12965 : : {
12966 : : /* Traditional behavior is not to take the integer mode
12967 : : literally, but simply to use it as a way of determining
12968 : : the vector size. It is up to mode_for_vector to decide
12969 : : what the TYPE_MODE should be.
12970 : :
12971 : : Note that nunits == 1 is allowed in order to support single
12972 : : element vector types. */
12973 : 34400 : if (!multiple_p (GET_MODE_SIZE (simd_mode), nbytes, &nunits)
12974 : 344 : || !mode_for_vector (inner_mode, nunits).exists (&simd_mode))
12975 : 16856 : return NULL_TREE;
12976 : : }
12977 : : }
12978 : 29537474 : else if (SCALAR_INT_MODE_P (prevailing_mode)
12979 : 29537474 : || !related_vector_mode (prevailing_mode,
12980 : 27543929 : inner_mode, nunits).exists (&simd_mode))
12981 : : {
12982 : : /* Fall back to using mode_for_vector, mostly in the hope of being
12983 : : able to use an integer mode. */
12984 : 1993545 : if (known_eq (nunits, 0U)
12985 : 4626024 : && !multiple_p (GET_MODE_SIZE (prevailing_mode), nbytes, &nunits))
12986 : : return NULL_TREE;
12987 : :
12988 : 146958 : if (!mode_for_vector (inner_mode, nunits).exists (&simd_mode))
12989 : 136940 : return NULL_TREE;
12990 : : }
12991 : :
12992 : 28619380 : vectype = build_vector_type_for_mode (scalar_type, simd_mode);
12993 : :
12994 : : /* In cases where the mode was chosen by mode_for_vector, check that
12995 : : the target actually supports the chosen mode, or that it at least
12996 : : allows the vector mode to be replaced by a like-sized integer. */
12997 : 57238760 : if (!VECTOR_MODE_P (TYPE_MODE (vectype))
12998 : 28629653 : && !INTEGRAL_MODE_P (TYPE_MODE (vectype)))
12999 : : return NULL_TREE;
13000 : :
13001 : : /* Re-attach the address-space qualifier if we canonicalized the scalar
13002 : : type. */
13003 : 28611262 : if (TYPE_ADDR_SPACE (orig_scalar_type) != TYPE_ADDR_SPACE (vectype))
13004 : 5 : return build_qualified_type
13005 : 5 : (vectype, KEEP_QUAL_ADDR_SPACE (TYPE_QUALS (orig_scalar_type)));
13006 : :
13007 : : return vectype;
13008 : : }
13009 : :
13010 : : /* Function get_vectype_for_scalar_type.
13011 : :
13012 : : Returns the vector type corresponding to SCALAR_TYPE as supported
13013 : : by the target. If GROUP_SIZE is nonzero and we're performing BB
13014 : : vectorization, make sure that the number of elements in the vector
13015 : : is no bigger than GROUP_SIZE. */
13016 : :
13017 : : tree
13018 : 27904320 : get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type,
13019 : : unsigned int group_size)
13020 : : {
13021 : : /* For BB vectorization, we should always have a group size once we've
13022 : : constructed the SLP tree; the only valid uses of zero GROUP_SIZEs
13023 : : are tentative requests during things like early data reference
13024 : : analysis and pattern recognition. */
13025 : 27904320 : if (is_a <bb_vec_info> (vinfo))
13026 : 25618029 : gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0);
13027 : : else
13028 : : group_size = 0;
13029 : :
13030 : 27904320 : tree vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode,
13031 : : scalar_type);
13032 : 27904320 : if (vectype && vinfo->vector_mode == VOIDmode)
13033 : 1065431 : vinfo->vector_mode = TYPE_MODE (vectype);
13034 : :
13035 : : /* Register the natural choice of vector type, before the group size
13036 : : has been applied. */
13037 : 0 : if (vectype)
13038 : 25417407 : vinfo->used_vector_modes.add (TYPE_MODE (vectype));
13039 : :
13040 : : /* If the natural choice of vector type doesn't satisfy GROUP_SIZE,
13041 : : try again with an explicit number of elements. */
13042 : 25417407 : if (vectype
13043 : 25417407 : && group_size
13044 : 27904320 : && maybe_ge (TYPE_VECTOR_SUBPARTS (vectype), group_size))
13045 : : {
13046 : : /* Start with the biggest number of units that fits within
13047 : : GROUP_SIZE and halve it until we find a valid vector type.
13048 : : Usually either the first attempt will succeed or all will
13049 : : fail (in the latter case because GROUP_SIZE is too small
13050 : : for the target), but it's possible that a target could have
13051 : : a hole between supported vector types.
13052 : :
13053 : : If GROUP_SIZE is not a power of 2, this has the effect of
13054 : : trying the largest power of 2 that fits within the group,
13055 : : even though the group is not a multiple of that vector size.
13056 : : The BB vectorizer will then try to carve up the group into
13057 : : smaller pieces. */
13058 : 3055411 : unsigned int nunits = 1 << floor_log2 (group_size);
13059 : 3055411 : do
13060 : : {
13061 : 3055411 : vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode,
13062 : 3055411 : scalar_type, nunits);
13063 : 3055411 : nunits /= 2;
13064 : : }
13065 : 3055411 : while (nunits > 1 && !vectype);
13066 : : }
13067 : :
13068 : 27904320 : return vectype;
13069 : : }
13070 : :
13071 : : /* Return the vector type corresponding to SCALAR_TYPE as supported
13072 : : by the target. NODE, if nonnull, is the SLP tree node that will
13073 : : use the returned vector type. */
13074 : :
13075 : : tree
13076 : 162354 : get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type, slp_tree node)
13077 : : {
13078 : 162354 : unsigned int group_size = 0;
13079 : 162354 : if (node)
13080 : 162354 : group_size = SLP_TREE_LANES (node);
13081 : 162354 : return get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
13082 : : }
13083 : :
13084 : : /* Function get_mask_type_for_scalar_type.
13085 : :
13086 : : Returns the mask type corresponding to a result of comparison
13087 : : of vectors of specified SCALAR_TYPE as supported by target.
13088 : : If GROUP_SIZE is nonzero and we're performing BB vectorization,
13089 : : make sure that the number of elements in the vector is no bigger
13090 : : than GROUP_SIZE. */
13091 : :
13092 : : tree
13093 : 1750077 : get_mask_type_for_scalar_type (vec_info *vinfo, tree scalar_type,
13094 : : unsigned int group_size)
13095 : : {
13096 : 1750077 : tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
13097 : :
13098 : 1750077 : if (!vectype)
13099 : : return NULL;
13100 : :
13101 : 1730014 : return truth_type_for (vectype);
13102 : : }
13103 : :
13104 : : /* Function get_mask_type_for_scalar_type.
13105 : :
13106 : : Returns the mask type corresponding to a result of comparison
13107 : : of vectors of specified SCALAR_TYPE as supported by target.
13108 : : NODE, if nonnull, is the SLP tree node that will use the returned
13109 : : vector type. */
13110 : :
13111 : : tree
13112 : 17 : get_mask_type_for_scalar_type (vec_info *vinfo, tree scalar_type,
13113 : : slp_tree node)
13114 : : {
13115 : 17 : tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type, node);
13116 : :
13117 : 17 : if (!vectype)
13118 : : return NULL;
13119 : :
13120 : 17 : return truth_type_for (vectype);
13121 : : }
13122 : :
13123 : : /* Function get_same_sized_vectype
13124 : :
13125 : : Returns a vector type corresponding to SCALAR_TYPE of size
13126 : : VECTOR_TYPE if supported by the target. */
13127 : :
13128 : : tree
13129 : 133327 : get_same_sized_vectype (tree scalar_type, tree vector_type)
13130 : : {
13131 : 133327 : if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type))
13132 : 0 : return truth_type_for (vector_type);
13133 : :
13134 : 133327 : poly_uint64 nunits;
13135 : 266654 : if (!multiple_p (GET_MODE_SIZE (TYPE_MODE (vector_type)),
13136 : 266654 : GET_MODE_SIZE (TYPE_MODE (scalar_type)), &nunits))
13137 : : return NULL_TREE;
13138 : :
13139 : 133327 : return get_related_vectype_for_scalar_type (TYPE_MODE (vector_type),
13140 : 133327 : scalar_type, nunits);
13141 : : }
13142 : :
13143 : : /* Return true if replacing LOOP_VINFO->vector_mode with VECTOR_MODE
13144 : : would not change the chosen vector modes. */
13145 : :
13146 : : bool
13147 : 1430227 : vect_chooses_same_modes_p (vec_info *vinfo, machine_mode vector_mode)
13148 : : {
13149 : 1430227 : for (vec_info::mode_set::iterator i = vinfo->used_vector_modes.begin ();
13150 : 3407741 : i != vinfo->used_vector_modes.end (); ++i)
13151 : 1753627 : if (!VECTOR_MODE_P (*i)
13152 : 5260881 : || related_vector_mode (vector_mode, GET_MODE_INNER (*i), 0) != *i)
13153 : 764870 : return false;
13154 : 665357 : return true;
13155 : : }
13156 : :
13157 : : /* Return true if replacing VECTOR_MODE with ALT_VECTOR_MODE would not
13158 : : change the chosen vector modes for analysis of a loop. */
13159 : :
13160 : : bool
13161 : 295063 : vect_chooses_same_modes_p (machine_mode vector_mode,
13162 : : machine_mode alt_vector_mode)
13163 : : {
13164 : 50170 : return (VECTOR_MODE_P (vector_mode)
13165 : 295063 : && VECTOR_MODE_P (alt_vector_mode)
13166 : 590126 : && (related_vector_mode (vector_mode,
13167 : : GET_MODE_INNER (alt_vector_mode))
13168 : 295063 : == alt_vector_mode)
13169 : 320127 : && (related_vector_mode (alt_vector_mode,
13170 : : GET_MODE_INNER (vector_mode))
13171 : 12532 : == vector_mode));
13172 : : }
13173 : :
13174 : : /* Function vect_is_simple_use.
13175 : :
13176 : : Input:
13177 : : VINFO - the vect info of the loop or basic block that is being vectorized.
13178 : : OPERAND - operand in the loop or bb.
13179 : : Output:
13180 : : DEF_STMT_INFO_OUT (optional) - information about the defining stmt in
13181 : : case OPERAND is an SSA_NAME that is defined in the vectorizable region
13182 : : DEF_STMT_OUT (optional) - the defining stmt in case OPERAND is an SSA_NAME;
13183 : : the definition could be anywhere in the function
13184 : : DT - the type of definition
13185 : :
13186 : : Returns whether a stmt with OPERAND can be vectorized.
13187 : : For loops, supportable operands are constants, loop invariants, and operands
13188 : : that are defined by the current iteration of the loop. Unsupportable
13189 : : operands are those that are defined by a previous iteration of the loop (as
13190 : : is the case in reduction/induction computations).
13191 : : For basic blocks, supportable operands are constants and bb invariants.
13192 : : For now, operands defined outside the basic block are not supported. */
13193 : :
13194 : : bool
13195 : 39752955 : vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
13196 : : stmt_vec_info *def_stmt_info_out, gimple **def_stmt_out)
13197 : : {
13198 : 39752955 : if (def_stmt_info_out)
13199 : 38060710 : *def_stmt_info_out = NULL;
13200 : 39752955 : if (def_stmt_out)
13201 : 8762449 : *def_stmt_out = NULL;
13202 : 39752955 : *dt = vect_unknown_def_type;
13203 : :
13204 : 39752955 : if (dump_enabled_p ())
13205 : : {
13206 : 701429 : dump_printf_loc (MSG_NOTE, vect_location,
13207 : : "vect_is_simple_use: operand ");
13208 : 701429 : if (TREE_CODE (operand) == SSA_NAME
13209 : 701429 : && !SSA_NAME_IS_DEFAULT_DEF (operand))
13210 : 635679 : dump_gimple_expr (MSG_NOTE, TDF_SLIM, SSA_NAME_DEF_STMT (operand), 0);
13211 : : else
13212 : 65750 : dump_generic_expr (MSG_NOTE, TDF_SLIM, operand);
13213 : : }
13214 : :
13215 : 39752955 : if (CONSTANT_CLASS_P (operand))
13216 : 3229316 : *dt = vect_constant_def;
13217 : 36523639 : else if (is_gimple_min_invariant (operand))
13218 : 342518 : *dt = vect_external_def;
13219 : 36181121 : else if (TREE_CODE (operand) != SSA_NAME)
13220 : 1117 : *dt = vect_unknown_def_type;
13221 : 36180004 : else if (SSA_NAME_IS_DEFAULT_DEF (operand))
13222 : 505495 : *dt = vect_external_def;
13223 : : else
13224 : : {
13225 : 35674509 : gimple *def_stmt = SSA_NAME_DEF_STMT (operand);
13226 : 35674509 : stmt_vec_info stmt_vinfo = vinfo->lookup_def (operand);
13227 : 35674509 : if (!stmt_vinfo)
13228 : 738135 : *dt = vect_external_def;
13229 : : else
13230 : : {
13231 : 34936374 : stmt_vinfo = vect_stmt_to_vectorize (stmt_vinfo);
13232 : 34936374 : def_stmt = stmt_vinfo->stmt;
13233 : 34936374 : *dt = STMT_VINFO_DEF_TYPE (stmt_vinfo);
13234 : 34936374 : if (def_stmt_info_out)
13235 : 33250458 : *def_stmt_info_out = stmt_vinfo;
13236 : : }
13237 : 35674509 : if (def_stmt_out)
13238 : 8553656 : *def_stmt_out = def_stmt;
13239 : : }
13240 : :
13241 : 39752955 : if (dump_enabled_p ())
13242 : : {
13243 : 701429 : dump_printf (MSG_NOTE, ", type of def: ");
13244 : 701429 : switch (*dt)
13245 : : {
13246 : 0 : case vect_uninitialized_def:
13247 : 0 : dump_printf (MSG_NOTE, "uninitialized\n");
13248 : 0 : break;
13249 : 55013 : case vect_constant_def:
13250 : 55013 : dump_printf (MSG_NOTE, "constant\n");
13251 : 55013 : break;
13252 : 24692 : case vect_external_def:
13253 : 24692 : dump_printf (MSG_NOTE, "external\n");
13254 : 24692 : break;
13255 : 505516 : case vect_internal_def:
13256 : 505516 : dump_printf (MSG_NOTE, "internal\n");
13257 : 505516 : break;
13258 : 91053 : case vect_induction_def:
13259 : 91053 : dump_printf (MSG_NOTE, "induction\n");
13260 : 91053 : break;
13261 : 22172 : case vect_reduction_def:
13262 : 22172 : dump_printf (MSG_NOTE, "reduction\n");
13263 : 22172 : break;
13264 : 484 : case vect_double_reduction_def:
13265 : 484 : dump_printf (MSG_NOTE, "double reduction\n");
13266 : 484 : break;
13267 : 1898 : case vect_nested_cycle:
13268 : 1898 : dump_printf (MSG_NOTE, "nested cycle\n");
13269 : 1898 : break;
13270 : 264 : case vect_first_order_recurrence:
13271 : 264 : dump_printf (MSG_NOTE, "first order recurrence\n");
13272 : 264 : break;
13273 : 0 : case vect_condition_def:
13274 : 0 : dump_printf (MSG_NOTE, "control flow\n");
13275 : 0 : break;
13276 : 337 : case vect_unknown_def_type:
13277 : 337 : dump_printf (MSG_NOTE, "unknown\n");
13278 : 337 : break;
13279 : : }
13280 : : }
13281 : :
13282 : 39752955 : if (*dt == vect_unknown_def_type)
13283 : : {
13284 : 14653 : if (dump_enabled_p ())
13285 : 337 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
13286 : : "Unsupported pattern.\n");
13287 : 14653 : return false;
13288 : : }
13289 : :
13290 : : return true;
13291 : : }
13292 : :
13293 : : /* Function vect_is_simple_use.
13294 : :
13295 : : Same as vect_is_simple_use but determines the operand by operand
13296 : : position OPERAND from either STMT or SLP_NODE, filling in *OP
13297 : : and *SLP_DEF (when SLP_NODE is not NULL). */
13298 : :
13299 : : bool
13300 : 3262850 : vect_is_simple_use (vec_info *vinfo, slp_tree slp_node,
13301 : : unsigned operand, tree *op, slp_tree *slp_def,
13302 : : enum vect_def_type *dt,
13303 : : tree *vectype, stmt_vec_info *def_stmt_info_out)
13304 : : {
13305 : 3262850 : slp_tree child = SLP_TREE_CHILDREN (slp_node)[operand];
13306 : 3262850 : *slp_def = child;
13307 : 3262850 : *vectype = SLP_TREE_VECTYPE (child);
13308 : 3262850 : if (SLP_TREE_DEF_TYPE (child) == vect_internal_def)
13309 : : {
13310 : : /* ??? VEC_PERM nodes might be intermediate and their lane value
13311 : : have no representative (nor do we build a VEC_PERM stmt for
13312 : : the actual operation). Note for two-operator nodes we set
13313 : : a representative but leave scalar stmts empty as we'd only
13314 : : have one for a subset of lanes. Ideally no caller would
13315 : : require *op for internal defs. */
13316 : 1657475 : if (SLP_TREE_REPRESENTATIVE (child))
13317 : : {
13318 : 1656749 : *op = gimple_get_lhs (SLP_TREE_REPRESENTATIVE (child)->stmt);
13319 : 1656749 : return vect_is_simple_use (*op, vinfo, dt, def_stmt_info_out);
13320 : : }
13321 : : else
13322 : : {
13323 : 726 : gcc_assert (SLP_TREE_PERMUTE_P (child));
13324 : 726 : *op = error_mark_node;
13325 : 726 : *dt = vect_internal_def;
13326 : 726 : if (def_stmt_info_out)
13327 : 0 : *def_stmt_info_out = NULL;
13328 : 726 : return true;
13329 : : }
13330 : : }
13331 : : else
13332 : : {
13333 : 1605375 : if (def_stmt_info_out)
13334 : 45209 : *def_stmt_info_out = NULL;
13335 : 1605375 : *op = SLP_TREE_SCALAR_OPS (child)[0];
13336 : 1605375 : *dt = SLP_TREE_DEF_TYPE (child);
13337 : 1605375 : return true;
13338 : : }
13339 : : }
13340 : :
13341 : : /* If OP is not NULL and is external or constant update its vector
13342 : : type with VECTYPE. Returns true if successful or false if not,
13343 : : for example when conflicting vector types are present. */
13344 : :
13345 : : bool
13346 : 2829163 : vect_maybe_update_slp_op_vectype (slp_tree op, tree vectype)
13347 : : {
13348 : 2829163 : if (!op || SLP_TREE_DEF_TYPE (op) == vect_internal_def)
13349 : : return true;
13350 : 1046018 : if (SLP_TREE_VECTYPE (op))
13351 : 66292 : return types_compatible_p (SLP_TREE_VECTYPE (op), vectype);
13352 : : /* For external defs refuse to produce VECTOR_BOOLEAN_TYPE_P, those
13353 : : should be handled by patters. Allow vect_constant_def for now
13354 : : as well as the trivial single-lane uniform vect_external_def case
13355 : : both of which we code-generate reasonably. */
13356 : 979726 : if (VECTOR_BOOLEAN_TYPE_P (vectype)
13357 : 1080 : && SLP_TREE_DEF_TYPE (op) == vect_external_def
13358 : 980438 : && SLP_TREE_LANES (op) > 1)
13359 : : return false;
13360 : 979406 : SLP_TREE_VECTYPE (op) = vectype;
13361 : 979406 : return true;
13362 : : }
13363 : :
13364 : : /* Function supportable_widening_operation
13365 : :
13366 : : Check whether an operation represented by the code CODE is a
13367 : : widening operation that is supported by the target platform in
13368 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
13369 : : producing a result of type VECTYPE_OUT).
13370 : :
13371 : : Widening operations we currently support are NOP (CONVERT), FLOAT,
13372 : : FIX_TRUNC and WIDEN_MULT. This function checks if these operations
13373 : : are supported by the target platform either directly (via vector
13374 : : tree-codes), or via target builtins.
13375 : :
13376 : : Output:
13377 : : - CODE1 and CODE2 are codes of vector operations to be used when
13378 : : vectorizing the operation, if available.
13379 : : - MULTI_STEP_CVT determines the number of required intermediate steps in
13380 : : case of multi-step conversion (like char->short->int - in that case
13381 : : MULTI_STEP_CVT will be 1).
13382 : : - INTERM_TYPES contains the intermediate type required to perform the
13383 : : widening operation (short in the above example). */
13384 : :
13385 : : bool
13386 : 306295 : supportable_widening_operation (vec_info *vinfo,
13387 : : code_helper code,
13388 : : stmt_vec_info stmt_info,
13389 : : tree vectype_out, tree vectype_in,
13390 : : code_helper *code1,
13391 : : code_helper *code2,
13392 : : int *multi_step_cvt,
13393 : : vec<tree> *interm_types)
13394 : : {
13395 : 306295 : loop_vec_info loop_info = dyn_cast <loop_vec_info> (vinfo);
13396 : 306295 : class loop *vect_loop = NULL;
13397 : 306295 : machine_mode vec_mode;
13398 : 306295 : enum insn_code icode1, icode2;
13399 : 306295 : optab optab1 = unknown_optab, optab2 = unknown_optab;
13400 : 306295 : tree vectype = vectype_in;
13401 : 306295 : tree wide_vectype = vectype_out;
13402 : 306295 : tree_code c1 = MAX_TREE_CODES, c2 = MAX_TREE_CODES;
13403 : 306295 : int i;
13404 : 306295 : tree prev_type, intermediate_type;
13405 : 306295 : machine_mode intermediate_mode, prev_mode;
13406 : 306295 : optab optab3, optab4;
13407 : :
13408 : 306295 : *multi_step_cvt = 0;
13409 : 178281 : if (loop_info)
13410 : 128014 : vect_loop = LOOP_VINFO_LOOP (loop_info);
13411 : :
13412 : 306295 : switch (code.safe_as_tree_code ())
13413 : : {
13414 : : case MAX_TREE_CODES:
13415 : : /* Don't set c1 and c2 if code is not a tree_code. */
13416 : : break;
13417 : :
13418 : 166319 : case WIDEN_MULT_EXPR:
13419 : : /* The result of a vectorized widening operation usually requires
13420 : : two vectors (because the widened results do not fit into one vector).
13421 : : The generated vector results would normally be expected to be
13422 : : generated in the same order as in the original scalar computation,
13423 : : i.e. if 8 results are generated in each vector iteration, they are
13424 : : to be organized as follows:
13425 : : vect1: [res1,res2,res3,res4],
13426 : : vect2: [res5,res6,res7,res8].
13427 : :
13428 : : However, in the special case that the result of the widening
13429 : : operation is used in a reduction computation only, the order doesn't
13430 : : matter (because when vectorizing a reduction we change the order of
13431 : : the computation). Some targets can take advantage of this and
13432 : : generate more efficient code. For example, targets like Altivec,
13433 : : that support widen_mult using a sequence of {mult_even,mult_odd}
13434 : : generate the following vectors:
13435 : : vect1: [res1,res3,res5,res7],
13436 : : vect2: [res2,res4,res6,res8].
13437 : :
13438 : : When vectorizing outer-loops, we execute the inner-loop sequentially
13439 : : (each vectorized inner-loop iteration contributes to VF outer-loop
13440 : : iterations in parallel). We therefore don't allow to change the
13441 : : order of the computation in the inner-loop during outer-loop
13442 : : vectorization. */
13443 : : /* TODO: Another case in which order doesn't *really* matter is when we
13444 : : widen and then contract again, e.g. (short)((int)x * y >> 8).
13445 : : Normally, pack_trunc performs an even/odd permute, whereas the
13446 : : repack from an even/odd expansion would be an interleave, which
13447 : : would be significantly simpler for e.g. AVX2. */
13448 : : /* In any case, in order to avoid duplicating the code below, recurse
13449 : : on VEC_WIDEN_MULT_EVEN_EXPR. If it succeeds, all the return values
13450 : : are properly set up for the caller. If we fail, we'll continue with
13451 : : a VEC_WIDEN_MULT_LO/HI_EXPR check. */
13452 : 166319 : if (vect_loop
13453 : 43441 : && !nested_in_vect_loop_p (vect_loop, stmt_info)
13454 : 210224 : && supportable_widening_operation (vinfo, VEC_WIDEN_MULT_EVEN_EXPR,
13455 : : stmt_info, vectype_out,
13456 : : vectype_in, code1,
13457 : : code2, multi_step_cvt,
13458 : : interm_types))
13459 : : {
13460 : : /* Elements in a vector with vect_used_by_reduction property cannot
13461 : : be reordered if the use chain with this property does not have the
13462 : : same operation. One such an example is s += a * b, where elements
13463 : : in a and b cannot be reordered. Here we check if the vector defined
13464 : : by STMT is only directly used in the reduction statement. */
13465 : 29782 : tree lhs = gimple_assign_lhs (vect_orig_stmt (stmt_info)->stmt);
13466 : 28141 : stmt_vec_info use_stmt_info = loop_info->lookup_single_use (lhs);
13467 : 28141 : if (use_stmt_info && STMT_VINFO_REDUC_DEF (use_stmt_info))
13468 : : return true;
13469 : : }
13470 : : c1 = VEC_WIDEN_MULT_LO_EXPR;
13471 : : c2 = VEC_WIDEN_MULT_HI_EXPR;
13472 : : break;
13473 : :
13474 : : case DOT_PROD_EXPR:
13475 : 306114 : c1 = DOT_PROD_EXPR;
13476 : 306114 : c2 = DOT_PROD_EXPR;
13477 : : break;
13478 : :
13479 : 0 : case SAD_EXPR:
13480 : 0 : c1 = SAD_EXPR;
13481 : 0 : c2 = SAD_EXPR;
13482 : 0 : break;
13483 : :
13484 : 43441 : case VEC_WIDEN_MULT_EVEN_EXPR:
13485 : : /* Support the recursion induced just above. */
13486 : 43441 : c1 = VEC_WIDEN_MULT_EVEN_EXPR;
13487 : 43441 : c2 = VEC_WIDEN_MULT_ODD_EXPR;
13488 : 43441 : break;
13489 : :
13490 : 9036 : case WIDEN_LSHIFT_EXPR:
13491 : 9036 : c1 = VEC_WIDEN_LSHIFT_LO_EXPR;
13492 : 9036 : c2 = VEC_WIDEN_LSHIFT_HI_EXPR;
13493 : 9036 : break;
13494 : :
13495 : 27095 : CASE_CONVERT:
13496 : 27095 : c1 = VEC_UNPACK_LO_EXPR;
13497 : 27095 : c2 = VEC_UNPACK_HI_EXPR;
13498 : 27095 : break;
13499 : :
13500 : 6679 : case FLOAT_EXPR:
13501 : 6679 : c1 = VEC_UNPACK_FLOAT_LO_EXPR;
13502 : 6679 : c2 = VEC_UNPACK_FLOAT_HI_EXPR;
13503 : 6679 : break;
13504 : :
13505 : 206 : case FIX_TRUNC_EXPR:
13506 : 206 : c1 = VEC_UNPACK_FIX_TRUNC_LO_EXPR;
13507 : 206 : c2 = VEC_UNPACK_FIX_TRUNC_HI_EXPR;
13508 : 206 : break;
13509 : :
13510 : 0 : default:
13511 : 0 : gcc_unreachable ();
13512 : : }
13513 : :
13514 : 306114 : if (BYTES_BIG_ENDIAN && c1 != VEC_WIDEN_MULT_EVEN_EXPR)
13515 : : std::swap (c1, c2);
13516 : :
13517 : 306114 : if (code == FIX_TRUNC_EXPR)
13518 : : {
13519 : : /* The signedness is determined from output operand. */
13520 : 206 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
13521 : 206 : optab2 = optab_for_tree_code (c2, vectype_out, optab_default);
13522 : : }
13523 : 536284 : else if (CONVERT_EXPR_CODE_P (code.safe_as_tree_code ())
13524 : 27095 : && VECTOR_BOOLEAN_TYPE_P (wide_vectype)
13525 : 4792 : && VECTOR_BOOLEAN_TYPE_P (vectype)
13526 : 4792 : && TYPE_MODE (wide_vectype) == TYPE_MODE (vectype)
13527 : 252644 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype)))
13528 : : {
13529 : : /* If the input and result modes are the same, a different optab
13530 : : is needed where we pass in the number of units in vectype. */
13531 : : optab1 = vec_unpacks_sbool_lo_optab;
13532 : : optab2 = vec_unpacks_sbool_hi_optab;
13533 : : }
13534 : :
13535 : 306114 : vec_mode = TYPE_MODE (vectype);
13536 : 306114 : if (widening_fn_p (code))
13537 : : {
13538 : : /* If this is an internal fn then we must check whether the target
13539 : : supports either a low-high split or an even-odd split. */
13540 : 53519 : internal_fn ifn = as_internal_fn ((combined_fn) code);
13541 : :
13542 : 53519 : internal_fn lo, hi, even, odd;
13543 : 53519 : lookup_hilo_internal_fn (ifn, &lo, &hi);
13544 : 53519 : if (BYTES_BIG_ENDIAN)
13545 : : std::swap (lo, hi);
13546 : 53519 : *code1 = as_combined_fn (lo);
13547 : 53519 : *code2 = as_combined_fn (hi);
13548 : 53519 : optab1 = direct_internal_fn_optab (lo, {vectype, vectype});
13549 : 53519 : optab2 = direct_internal_fn_optab (hi, {vectype, vectype});
13550 : :
13551 : : /* If we don't support low-high, then check for even-odd. */
13552 : 53519 : if (!optab1
13553 : 53519 : || (icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing
13554 : 0 : || !optab2
13555 : 53519 : || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing)
13556 : : {
13557 : 53519 : lookup_evenodd_internal_fn (ifn, &even, &odd);
13558 : 53519 : *code1 = as_combined_fn (even);
13559 : 53519 : *code2 = as_combined_fn (odd);
13560 : 53519 : optab1 = direct_internal_fn_optab (even, {vectype, vectype});
13561 : 53519 : optab2 = direct_internal_fn_optab (odd, {vectype, vectype});
13562 : : }
13563 : : }
13564 : 252595 : else if (code.is_tree_code ())
13565 : : {
13566 : 252595 : if (code == FIX_TRUNC_EXPR)
13567 : : {
13568 : : /* The signedness is determined from output operand. */
13569 : 206 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
13570 : 206 : optab2 = optab_for_tree_code (c2, vectype_out, optab_default);
13571 : : }
13572 : 252389 : else if (CONVERT_EXPR_CODE_P ((tree_code) code.safe_as_tree_code ())
13573 : 27095 : && VECTOR_BOOLEAN_TYPE_P (wide_vectype)
13574 : 4792 : && VECTOR_BOOLEAN_TYPE_P (vectype)
13575 : 4792 : && TYPE_MODE (wide_vectype) == TYPE_MODE (vectype)
13576 : 252644 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype)))
13577 : : {
13578 : : /* If the input and result modes are the same, a different optab
13579 : : is needed where we pass in the number of units in vectype. */
13580 : : optab1 = vec_unpacks_sbool_lo_optab;
13581 : : optab2 = vec_unpacks_sbool_hi_optab;
13582 : : }
13583 : : else
13584 : : {
13585 : 252134 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
13586 : 252134 : optab2 = optab_for_tree_code (c2, vectype, optab_default);
13587 : : }
13588 : 252595 : *code1 = c1;
13589 : 252595 : *code2 = c2;
13590 : : }
13591 : :
13592 : 306114 : if (!optab1 || !optab2)
13593 : : return false;
13594 : :
13595 : 306114 : if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing
13596 : 306114 : || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing)
13597 : 151753 : return false;
13598 : :
13599 : :
13600 : 154361 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype)
13601 : 154361 : && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype))
13602 : : {
13603 : 145549 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
13604 : : return true;
13605 : : /* For scalar masks we may have different boolean
13606 : : vector types having the same QImode. Thus we
13607 : : add additional check for elements number. */
13608 : 2675 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype),
13609 : : TYPE_VECTOR_SUBPARTS (wide_vectype) * 2))
13610 : : return true;
13611 : : }
13612 : :
13613 : : /* Check if it's a multi-step conversion that can be done using intermediate
13614 : : types. */
13615 : :
13616 : 8912 : prev_type = vectype;
13617 : 8912 : prev_mode = vec_mode;
13618 : :
13619 : 160955 : if (!CONVERT_EXPR_CODE_P (code.safe_as_tree_code ()))
13620 : : return false;
13621 : :
13622 : : /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS
13623 : : intermediate steps in promotion sequence. We try
13624 : : MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do
13625 : : not. */
13626 : 8860 : interm_types->create (MAX_INTERM_CVT_STEPS);
13627 : 10242 : for (i = 0; i < MAX_INTERM_CVT_STEPS; i++)
13628 : : {
13629 : 10242 : intermediate_mode = insn_data[icode1].operand[0].mode;
13630 : 10242 : if (VECTOR_BOOLEAN_TYPE_P (prev_type))
13631 : 3102 : intermediate_type
13632 : 3102 : = vect_halve_mask_nunits (prev_type, intermediate_mode);
13633 : 7140 : else if (VECTOR_MODE_P (intermediate_mode))
13634 : : {
13635 : 7140 : tree intermediate_element_type
13636 : 7140 : = lang_hooks.types.type_for_mode (GET_MODE_INNER (intermediate_mode),
13637 : 7140 : TYPE_UNSIGNED (prev_type));
13638 : 7140 : intermediate_type
13639 : 7140 : = build_vector_type_for_mode (intermediate_element_type,
13640 : : intermediate_mode);
13641 : 7140 : }
13642 : : else
13643 : 0 : intermediate_type
13644 : 0 : = lang_hooks.types.type_for_mode (intermediate_mode,
13645 : 0 : TYPE_UNSIGNED (prev_type));
13646 : :
13647 : 10242 : if (VECTOR_BOOLEAN_TYPE_P (intermediate_type)
13648 : 3102 : && VECTOR_BOOLEAN_TYPE_P (prev_type)
13649 : 3102 : && intermediate_mode == prev_mode
13650 : 10242 : && SCALAR_INT_MODE_P (prev_mode))
13651 : : {
13652 : : /* If the input and result modes are the same, a different optab
13653 : : is needed where we pass in the number of units in vectype. */
13654 : : optab3 = vec_unpacks_sbool_lo_optab;
13655 : : optab4 = vec_unpacks_sbool_hi_optab;
13656 : : }
13657 : : else
13658 : : {
13659 : 10242 : optab3 = optab_for_tree_code (c1, intermediate_type, optab_default);
13660 : 10242 : optab4 = optab_for_tree_code (c2, intermediate_type, optab_default);
13661 : : }
13662 : :
13663 : 10242 : if (!optab3 || !optab4
13664 : 10242 : || (icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing
13665 : 10242 : || insn_data[icode1].operand[0].mode != intermediate_mode
13666 : 10242 : || (icode2 = optab_handler (optab2, prev_mode)) == CODE_FOR_nothing
13667 : 10242 : || insn_data[icode2].operand[0].mode != intermediate_mode
13668 : 10242 : || ((icode1 = optab_handler (optab3, intermediate_mode))
13669 : : == CODE_FOR_nothing)
13670 : 20194 : || ((icode2 = optab_handler (optab4, intermediate_mode))
13671 : : == CODE_FOR_nothing))
13672 : : break;
13673 : :
13674 : 9952 : interm_types->quick_push (intermediate_type);
13675 : 9952 : (*multi_step_cvt)++;
13676 : :
13677 : 9952 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype)
13678 : 9952 : && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype))
13679 : : {
13680 : 8590 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
13681 : : return true;
13682 : 1925 : if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type),
13683 : : TYPE_VECTOR_SUBPARTS (wide_vectype) * 2))
13684 : : return true;
13685 : : }
13686 : :
13687 : 1382 : prev_type = intermediate_type;
13688 : 1382 : prev_mode = intermediate_mode;
13689 : : }
13690 : :
13691 : 290 : interm_types->release ();
13692 : 290 : return false;
13693 : : }
13694 : :
13695 : :
13696 : : /* Function supportable_narrowing_operation
13697 : :
13698 : : Check whether an operation represented by the code CODE is a
13699 : : narrowing operation that is supported by the target platform in
13700 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
13701 : : and producing a result of type VECTYPE_OUT).
13702 : :
13703 : : Narrowing operations we currently support are NOP (CONVERT), FIX_TRUNC
13704 : : and FLOAT. This function checks if these operations are supported by
13705 : : the target platform directly via vector tree-codes.
13706 : :
13707 : : Output:
13708 : : - CODE1 is the code of a vector operation to be used when
13709 : : vectorizing the operation, if available.
13710 : : - MULTI_STEP_CVT determines the number of required intermediate steps in
13711 : : case of multi-step conversion (like int->short->char - in that case
13712 : : MULTI_STEP_CVT will be 1).
13713 : : - INTERM_TYPES contains the intermediate type required to perform the
13714 : : narrowing operation (short in the above example). */
13715 : :
13716 : : bool
13717 : 32211 : supportable_narrowing_operation (code_helper code,
13718 : : tree vectype_out, tree vectype_in,
13719 : : code_helper *code1, int *multi_step_cvt,
13720 : : vec<tree> *interm_types)
13721 : : {
13722 : 32211 : machine_mode vec_mode;
13723 : 32211 : enum insn_code icode1;
13724 : 32211 : optab optab1, interm_optab;
13725 : 32211 : tree vectype = vectype_in;
13726 : 32211 : tree narrow_vectype = vectype_out;
13727 : 32211 : enum tree_code c1;
13728 : 32211 : tree intermediate_type, prev_type;
13729 : 32211 : machine_mode intermediate_mode, prev_mode;
13730 : 32211 : int i;
13731 : 32211 : unsigned HOST_WIDE_INT n_elts;
13732 : 32211 : bool uns;
13733 : :
13734 : 32211 : if (!code.is_tree_code ())
13735 : : return false;
13736 : :
13737 : 32211 : *multi_step_cvt = 0;
13738 : 32211 : switch ((tree_code) code)
13739 : : {
13740 : 31209 : CASE_CONVERT:
13741 : 31209 : c1 = VEC_PACK_TRUNC_EXPR;
13742 : 31209 : if (VECTOR_BOOLEAN_TYPE_P (narrow_vectype)
13743 : 4747 : && VECTOR_BOOLEAN_TYPE_P (vectype)
13744 : 4747 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype))
13745 : 1717 : && TYPE_VECTOR_SUBPARTS (vectype).is_constant (&n_elts)
13746 : 32926 : && n_elts < BITS_PER_UNIT)
13747 : : optab1 = vec_pack_sbool_trunc_optab;
13748 : : else
13749 : 30442 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
13750 : : break;
13751 : :
13752 : 810 : case FIX_TRUNC_EXPR:
13753 : 810 : c1 = VEC_PACK_FIX_TRUNC_EXPR;
13754 : : /* The signedness is determined from output operand. */
13755 : 810 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
13756 : 810 : break;
13757 : :
13758 : 192 : case FLOAT_EXPR:
13759 : 192 : c1 = VEC_PACK_FLOAT_EXPR;
13760 : 192 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
13761 : 192 : break;
13762 : :
13763 : 0 : default:
13764 : 0 : gcc_unreachable ();
13765 : : }
13766 : :
13767 : 32211 : if (!optab1)
13768 : : return false;
13769 : :
13770 : 32211 : vec_mode = TYPE_MODE (vectype);
13771 : 32211 : if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing)
13772 : : return false;
13773 : :
13774 : 28284 : *code1 = c1;
13775 : :
13776 : 28284 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype))
13777 : : {
13778 : 17431 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
13779 : : return true;
13780 : : /* For scalar masks we may have different boolean
13781 : : vector types having the same QImode. Thus we
13782 : : add additional check for elements number. */
13783 : 3118 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype) * 2,
13784 : : TYPE_VECTOR_SUBPARTS (narrow_vectype)))
13785 : : return true;
13786 : : }
13787 : :
13788 : 10854 : if (code == FLOAT_EXPR)
13789 : : return false;
13790 : :
13791 : : /* Check if it's a multi-step conversion that can be done using intermediate
13792 : : types. */
13793 : 10854 : prev_mode = vec_mode;
13794 : 10854 : prev_type = vectype;
13795 : 10854 : if (code == FIX_TRUNC_EXPR)
13796 : 172 : uns = TYPE_UNSIGNED (vectype_out);
13797 : : else
13798 : 10682 : uns = TYPE_UNSIGNED (vectype);
13799 : :
13800 : : /* For multi-step FIX_TRUNC_EXPR prefer signed floating to integer
13801 : : conversion over unsigned, as unsigned FIX_TRUNC_EXPR is often more
13802 : : costly than signed. */
13803 : 10854 : if (code == FIX_TRUNC_EXPR && uns)
13804 : : {
13805 : 76 : enum insn_code icode2;
13806 : :
13807 : 76 : intermediate_type
13808 : 76 : = lang_hooks.types.type_for_mode (TYPE_MODE (vectype_out), 0);
13809 : 76 : interm_optab
13810 : 76 : = optab_for_tree_code (c1, intermediate_type, optab_default);
13811 : 76 : if (interm_optab != unknown_optab
13812 : 76 : && (icode2 = optab_handler (optab1, vec_mode)) != CODE_FOR_nothing
13813 : 76 : && insn_data[icode1].operand[0].mode
13814 : 76 : == insn_data[icode2].operand[0].mode)
13815 : : {
13816 : : uns = false;
13817 : : optab1 = interm_optab;
13818 : : icode1 = icode2;
13819 : : }
13820 : : }
13821 : :
13822 : : /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS
13823 : : intermediate steps in promotion sequence. We try
13824 : : MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do not. */
13825 : 10854 : interm_types->create (MAX_INTERM_CVT_STEPS);
13826 : 22988 : for (i = 0; i < MAX_INTERM_CVT_STEPS; i++)
13827 : : {
13828 : 12134 : intermediate_mode = insn_data[icode1].operand[0].mode;
13829 : 12134 : if (VECTOR_BOOLEAN_TYPE_P (prev_type))
13830 : 2077 : intermediate_type
13831 : 2077 : = vect_double_mask_nunits (prev_type, intermediate_mode);
13832 : : else
13833 : 10057 : intermediate_type
13834 : 10057 : = lang_hooks.types.type_for_mode (intermediate_mode, uns);
13835 : 12134 : if (VECTOR_BOOLEAN_TYPE_P (intermediate_type)
13836 : 2077 : && VECTOR_BOOLEAN_TYPE_P (prev_type)
13837 : 2077 : && SCALAR_INT_MODE_P (prev_mode)
13838 : 773 : && TYPE_VECTOR_SUBPARTS (intermediate_type).is_constant (&n_elts)
13839 : 12907 : && n_elts < BITS_PER_UNIT)
13840 : : interm_optab = vec_pack_sbool_trunc_optab;
13841 : : else
13842 : 12093 : interm_optab
13843 : 12093 : = optab_for_tree_code (VEC_PACK_TRUNC_EXPR, intermediate_type,
13844 : : optab_default);
13845 : 41 : if (!interm_optab
13846 : 12134 : || ((icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing)
13847 : 12134 : || insn_data[icode1].operand[0].mode != intermediate_mode
13848 : 24227 : || ((icode1 = optab_handler (interm_optab, intermediate_mode))
13849 : : == CODE_FOR_nothing))
13850 : : break;
13851 : :
13852 : 11600 : interm_types->quick_push (intermediate_type);
13853 : 11600 : (*multi_step_cvt)++;
13854 : :
13855 : 11600 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype))
13856 : : {
13857 : 10320 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
13858 : : return true;
13859 : 1044 : if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type) * 2,
13860 : : TYPE_VECTOR_SUBPARTS (narrow_vectype)))
13861 : : return true;
13862 : : }
13863 : :
13864 : 1280 : prev_mode = intermediate_mode;
13865 : 1280 : prev_type = intermediate_type;
13866 : 1280 : optab1 = interm_optab;
13867 : : }
13868 : :
13869 : 534 : interm_types->release ();
13870 : 534 : return false;
13871 : : }
13872 : :
13873 : : /* Function supportable_indirect_convert_operation
13874 : :
13875 : : Check whether an operation represented by the code CODE is single or multi
13876 : : operations that are supported by the target platform in
13877 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
13878 : : producing a result of type VECTYPE_OUT).
13879 : :
13880 : : Convert operations we currently support directly are FIX_TRUNC and FLOAT.
13881 : : This function checks if these operations are supported
13882 : : by the target platform directly (via vector tree-codes).
13883 : :
13884 : : Output:
13885 : : - converts contains some pairs to perform the convert operation,
13886 : : the pair's first is the intermediate type, and its second is the code of
13887 : : a vector operation to be used when converting the operation from the
13888 : : previous type to the intermediate type. */
13889 : : bool
13890 : 69812 : supportable_indirect_convert_operation (code_helper code,
13891 : : tree vectype_out,
13892 : : tree vectype_in,
13893 : : vec<std::pair<tree, tree_code> > &converts,
13894 : : tree op0, slp_tree slp_op0)
13895 : : {
13896 : 69812 : bool found_mode = false;
13897 : 69812 : scalar_mode lhs_mode = GET_MODE_INNER (TYPE_MODE (vectype_out));
13898 : 69812 : scalar_mode rhs_mode = GET_MODE_INNER (TYPE_MODE (vectype_in));
13899 : 69812 : tree_code tc1, tc2, code1, code2;
13900 : :
13901 : 69812 : tree cvt_type = NULL_TREE;
13902 : 69812 : poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (vectype_in);
13903 : :
13904 : 69812 : if (supportable_convert_operation ((tree_code) code,
13905 : : vectype_out,
13906 : : vectype_in,
13907 : : &tc1))
13908 : : {
13909 : 17492 : converts.safe_push (std::make_pair (vectype_out, tc1));
13910 : 17492 : return true;
13911 : : }
13912 : :
13913 : : /* For conversions between float and integer types try whether
13914 : : we can use intermediate signed integer types to support the
13915 : : conversion. */
13916 : 104640 : if (GET_MODE_SIZE (lhs_mode) != GET_MODE_SIZE (rhs_mode)
13917 : 52320 : && (code == FLOAT_EXPR
13918 : 2919 : || (code == FIX_TRUNC_EXPR && !flag_trapping_math)))
13919 : : {
13920 : 376 : bool demotion = GET_MODE_SIZE (rhs_mode) > GET_MODE_SIZE (lhs_mode);
13921 : 188 : bool float_expr_p = code == FLOAT_EXPR;
13922 : 188 : unsigned short target_size;
13923 : 188 : scalar_mode intermediate_mode;
13924 : 188 : if (demotion)
13925 : : {
13926 : 84 : intermediate_mode = lhs_mode;
13927 : 84 : target_size = GET_MODE_SIZE (rhs_mode);
13928 : : }
13929 : : else
13930 : : {
13931 : 104 : target_size = GET_MODE_SIZE (lhs_mode);
13932 : 104 : if (!int_mode_for_size
13933 : 104 : (GET_MODE_BITSIZE (rhs_mode), 0).exists (&intermediate_mode))
13934 : 122 : return false;
13935 : : }
13936 : 188 : code1 = float_expr_p ? (tree_code) code : NOP_EXPR;
13937 : : code2 = float_expr_p ? NOP_EXPR : (tree_code) code;
13938 : 188 : opt_scalar_mode mode_iter;
13939 : 292 : FOR_EACH_2XWIDER_MODE (mode_iter, intermediate_mode)
13940 : : {
13941 : 292 : intermediate_mode = mode_iter.require ();
13942 : :
13943 : 584 : if (GET_MODE_SIZE (intermediate_mode) > target_size)
13944 : : break;
13945 : :
13946 : 264 : scalar_mode cvt_mode;
13947 : 264 : if (!int_mode_for_size
13948 : 264 : (GET_MODE_BITSIZE (intermediate_mode), 0).exists (&cvt_mode))
13949 : : break;
13950 : :
13951 : 234 : cvt_type = build_nonstandard_integer_type
13952 : 234 : (GET_MODE_BITSIZE (cvt_mode), 0);
13953 : :
13954 : : /* Check if the intermediate type can hold OP0's range.
13955 : : When converting from float to integer this is not necessary
13956 : : because values that do not fit the (smaller) target type are
13957 : : unspecified anyway. */
13958 : 234 : if (demotion && float_expr_p)
13959 : : {
13960 : 8 : wide_int op_min_value, op_max_value;
13961 : : /* For vector form, it looks like op0 doesn't have RANGE_INFO.
13962 : : In the future, if it is supported, changes may need to be made
13963 : : to this part, such as checking the RANGE of each element
13964 : : in the vector. */
13965 : 8 : if (slp_op0)
13966 : : {
13967 : 4 : tree def;
13968 : : /* ??? Merge ranges in case of more than one lane. */
13969 : 4 : if (SLP_TREE_LANES (slp_op0) != 1
13970 : 0 : || !(def = vect_get_slp_scalar_def (slp_op0, 0))
13971 : 4 : || !vect_get_range_info (def,
13972 : : &op_min_value, &op_max_value))
13973 : : break;
13974 : : }
13975 : 4 : else if (!op0
13976 : 0 : || TREE_CODE (op0) != SSA_NAME
13977 : 0 : || !SSA_NAME_RANGE_INFO (op0)
13978 : 4 : || !vect_get_range_info (op0, &op_min_value,
13979 : : &op_max_value))
13980 : : break;
13981 : :
13982 : 0 : if (cvt_type == NULL_TREE
13983 : 0 : || (wi::min_precision (op_max_value, SIGNED)
13984 : 0 : > TYPE_PRECISION (cvt_type))
13985 : 0 : || (wi::min_precision (op_min_value, SIGNED)
13986 : 0 : > TYPE_PRECISION (cvt_type)))
13987 : 0 : continue;
13988 : 8 : }
13989 : :
13990 : 226 : cvt_type = get_related_vectype_for_scalar_type (TYPE_MODE (vectype_in),
13991 : : cvt_type,
13992 : : nelts);
13993 : : /* This should only happened for SLP as long as loop vectorizer
13994 : : only supports same-sized vector. */
13995 : 330 : if (cvt_type == NULL_TREE
13996 : 348 : || maybe_ne (TYPE_VECTOR_SUBPARTS (cvt_type), nelts)
13997 : 226 : || !supportable_convert_operation ((tree_code) code1,
13998 : : vectype_out,
13999 : : cvt_type, &tc1)
14000 : 396 : || !supportable_convert_operation ((tree_code) code2,
14001 : : cvt_type,
14002 : : vectype_in, &tc2))
14003 : 104 : continue;
14004 : :
14005 : : found_mode = true;
14006 : : break;
14007 : : }
14008 : :
14009 : 188 : if (found_mode)
14010 : : {
14011 : 122 : converts.safe_push (std::make_pair (cvt_type, tc2));
14012 : 122 : if (TYPE_MODE (cvt_type) != TYPE_MODE (vectype_out))
14013 : 122 : converts.safe_push (std::make_pair (vectype_out, tc1));
14014 : 122 : return true;
14015 : : }
14016 : : }
14017 : : return false;
14018 : : }
14019 : :
14020 : : /* Generate and return a vector mask of MASK_TYPE such that
14021 : : mask[I] is true iff J + START_INDEX < END_INDEX for all J <= I.
14022 : : Add the statements to SEQ. */
14023 : :
14024 : : tree
14025 : 0 : vect_gen_while (gimple_seq *seq, tree mask_type, tree start_index,
14026 : : tree end_index, const char *name)
14027 : : {
14028 : 0 : tree cmp_type = TREE_TYPE (start_index);
14029 : 0 : gcc_checking_assert (direct_internal_fn_supported_p (IFN_WHILE_ULT,
14030 : : cmp_type, mask_type,
14031 : : OPTIMIZE_FOR_SPEED));
14032 : 0 : gcall *call = gimple_build_call_internal (IFN_WHILE_ULT, 3,
14033 : : start_index, end_index,
14034 : : build_zero_cst (mask_type));
14035 : 0 : tree tmp;
14036 : 0 : if (name)
14037 : 0 : tmp = make_temp_ssa_name (mask_type, NULL, name);
14038 : : else
14039 : 0 : tmp = make_ssa_name (mask_type);
14040 : 0 : gimple_call_set_lhs (call, tmp);
14041 : 0 : gimple_seq_add_stmt (seq, call);
14042 : 0 : return tmp;
14043 : : }
14044 : :
14045 : : /* Generate a vector mask of type MASK_TYPE for which index I is false iff
14046 : : J + START_INDEX < END_INDEX for all J <= I. Add the statements to SEQ. */
14047 : :
14048 : : tree
14049 : 0 : vect_gen_while_not (gimple_seq *seq, tree mask_type, tree start_index,
14050 : : tree end_index)
14051 : : {
14052 : 0 : tree tmp = vect_gen_while (seq, mask_type, start_index, end_index);
14053 : 0 : return gimple_build (seq, BIT_NOT_EXPR, mask_type, tmp);
14054 : : }
14055 : :
14056 : : /* Try to compute the vector types required to vectorize STMT_INFO,
14057 : : returning true on success and false if vectorization isn't possible.
14058 : : If GROUP_SIZE is nonzero and we're performing BB vectorization,
14059 : : take sure that the number of elements in the vectors is no bigger
14060 : : than GROUP_SIZE.
14061 : :
14062 : : On success:
14063 : :
14064 : : - Set *STMT_VECTYPE_OUT to:
14065 : : - NULL_TREE if the statement doesn't need to be vectorized;
14066 : : - the equivalent of STMT_VINFO_VECTYPE otherwise.
14067 : :
14068 : : - Set *NUNITS_VECTYPE_OUT to the vector type that contains the maximum
14069 : : number of units needed to vectorize STMT_INFO, or NULL_TREE if the
14070 : : statement does not help to determine the overall number of units. */
14071 : :
14072 : : opt_result
14073 : 5734925 : vect_get_vector_types_for_stmt (vec_info *vinfo, stmt_vec_info stmt_info,
14074 : : tree *stmt_vectype_out,
14075 : : tree *nunits_vectype_out,
14076 : : unsigned int group_size)
14077 : : {
14078 : 5734925 : gimple *stmt = stmt_info->stmt;
14079 : :
14080 : : /* For BB vectorization, we should always have a group size once we've
14081 : : constructed the SLP tree; the only valid uses of zero GROUP_SIZEs
14082 : : are tentative requests during things like early data reference
14083 : : analysis and pattern recognition. */
14084 : 5734925 : if (is_a <bb_vec_info> (vinfo))
14085 : 4455172 : gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0);
14086 : : else
14087 : : group_size = 0;
14088 : :
14089 : 5734925 : *stmt_vectype_out = NULL_TREE;
14090 : 5734925 : *nunits_vectype_out = NULL_TREE;
14091 : :
14092 : 5734925 : if (gimple_get_lhs (stmt) == NULL_TREE
14093 : : /* Allow vector conditionals through here. */
14094 : 1528 : && !is_a <gcond *> (stmt)
14095 : : /* MASK_STORE and friends have no lhs, but are ok. */
14096 : 5737961 : && !(is_gimple_call (stmt)
14097 : 1528 : && gimple_call_internal_p (stmt)
14098 : 1508 : && internal_store_fn_p (gimple_call_internal_fn (stmt))))
14099 : : {
14100 : 20 : if (is_a <gcall *> (stmt))
14101 : : {
14102 : : /* Ignore calls with no lhs. These must be calls to
14103 : : #pragma omp simd functions, and what vectorization factor
14104 : : it really needs can't be determined until
14105 : : vectorizable_simd_clone_call. */
14106 : 20 : if (dump_enabled_p ())
14107 : 18 : dump_printf_loc (MSG_NOTE, vect_location,
14108 : : "defer to SIMD clone analysis.\n");
14109 : 20 : return opt_result::success ();
14110 : : }
14111 : :
14112 : 0 : return opt_result::failure_at (stmt,
14113 : : "not vectorized: irregular stmt: %G", stmt);
14114 : : }
14115 : :
14116 : 5734905 : tree vectype;
14117 : 5734905 : tree scalar_type = NULL_TREE;
14118 : 5734905 : if (group_size == 0 && STMT_VINFO_VECTYPE (stmt_info))
14119 : : {
14120 : 1297840 : vectype = STMT_VINFO_VECTYPE (stmt_info);
14121 : 1297840 : if (dump_enabled_p ())
14122 : 72828 : dump_printf_loc (MSG_NOTE, vect_location,
14123 : : "precomputed vectype: %T\n", vectype);
14124 : : }
14125 : 4437065 : else if (vect_use_mask_type_p (stmt_info))
14126 : : {
14127 : 194715 : unsigned int precision = stmt_info->mask_precision;
14128 : 194715 : scalar_type = build_nonstandard_integer_type (precision, 1);
14129 : 194715 : vectype = get_mask_type_for_scalar_type (vinfo, scalar_type, group_size);
14130 : 194715 : if (!vectype)
14131 : 0 : return opt_result::failure_at (stmt, "not vectorized: unsupported"
14132 : : " data-type %T\n", scalar_type);
14133 : 194715 : if (dump_enabled_p ())
14134 : 4081 : dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype);
14135 : : }
14136 : : else
14137 : : {
14138 : : /* If we got here with a gcond it means that the target had no available vector
14139 : : mode for the scalar type. We can't vectorize so abort. */
14140 : 4242350 : if (is_a <gcond *> (stmt))
14141 : 0 : return opt_result::failure_at (stmt,
14142 : : "not vectorized:"
14143 : : " unsupported data-type for gcond %T\n",
14144 : : scalar_type);
14145 : :
14146 : 4242350 : if (data_reference *dr = STMT_VINFO_DATA_REF (stmt_info))
14147 : 1465552 : scalar_type = TREE_TYPE (DR_REF (dr));
14148 : : else
14149 : 2776798 : scalar_type = TREE_TYPE (gimple_get_lhs (stmt));
14150 : :
14151 : 4242350 : if (dump_enabled_p ())
14152 : : {
14153 : 64787 : if (group_size)
14154 : 7272 : dump_printf_loc (MSG_NOTE, vect_location,
14155 : : "get vectype for scalar type (group size %d):"
14156 : : " %T\n", group_size, scalar_type);
14157 : : else
14158 : 57515 : dump_printf_loc (MSG_NOTE, vect_location,
14159 : : "get vectype for scalar type: %T\n", scalar_type);
14160 : : }
14161 : 4242350 : vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
14162 : 4242350 : if (!vectype)
14163 : 204536 : return opt_result::failure_at (stmt,
14164 : : "not vectorized:"
14165 : : " unsupported data-type %T\n",
14166 : : scalar_type);
14167 : :
14168 : 4037814 : if (dump_enabled_p ())
14169 : 64621 : dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype);
14170 : : }
14171 : :
14172 : 4305357 : if (scalar_type && VECTOR_MODE_P (TYPE_MODE (scalar_type)))
14173 : 0 : return opt_result::failure_at (stmt,
14174 : : "not vectorized: vector stmt in loop:%G",
14175 : : stmt);
14176 : :
14177 : 5530369 : *stmt_vectype_out = vectype;
14178 : :
14179 : : /* Don't try to compute scalar types if the stmt produces a boolean
14180 : : vector; use the existing vector type instead. */
14181 : 5530369 : tree nunits_vectype = vectype;
14182 : 5530369 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14183 : : {
14184 : : /* The number of units is set according to the smallest scalar
14185 : : type (or the largest vector size, but we only support one
14186 : : vector size per vectorization). */
14187 : 5061879 : scalar_type = vect_get_smallest_scalar_type (stmt_info,
14188 : 5061879 : TREE_TYPE (vectype));
14189 : 5061879 : if (!types_compatible_p (scalar_type, TREE_TYPE (vectype)))
14190 : : {
14191 : 1016132 : if (dump_enabled_p ())
14192 : 9448 : dump_printf_loc (MSG_NOTE, vect_location,
14193 : : "get vectype for smallest scalar type: %T\n",
14194 : : scalar_type);
14195 : 1016132 : nunits_vectype = get_vectype_for_scalar_type (vinfo, scalar_type,
14196 : : group_size);
14197 : 1016132 : if (!nunits_vectype)
14198 : 7 : return opt_result::failure_at
14199 : 7 : (stmt, "not vectorized: unsupported data-type %T\n",
14200 : : scalar_type);
14201 : 1016125 : if (dump_enabled_p ())
14202 : 9448 : dump_printf_loc (MSG_NOTE, vect_location, "nunits vectype: %T\n",
14203 : : nunits_vectype);
14204 : : }
14205 : : }
14206 : :
14207 : 5530362 : if (!multiple_p (TYPE_VECTOR_SUBPARTS (nunits_vectype),
14208 : 5530362 : TYPE_VECTOR_SUBPARTS (*stmt_vectype_out)))
14209 : 0 : return opt_result::failure_at (stmt,
14210 : : "Not vectorized: Incompatible number "
14211 : : "of vector subparts between %T and %T\n",
14212 : : nunits_vectype, *stmt_vectype_out);
14213 : :
14214 : 5530362 : if (dump_enabled_p ())
14215 : : {
14216 : 141530 : dump_printf_loc (MSG_NOTE, vect_location, "nunits = ");
14217 : 141530 : dump_dec (MSG_NOTE, TYPE_VECTOR_SUBPARTS (nunits_vectype));
14218 : 141530 : dump_printf (MSG_NOTE, "\n");
14219 : : }
14220 : :
14221 : 5530362 : *nunits_vectype_out = nunits_vectype;
14222 : 5530362 : return opt_result::success ();
14223 : : }
14224 : :
14225 : : /* Generate and return statement sequence that sets vector length LEN that is:
14226 : :
14227 : : min_of_start_and_end = min (START_INDEX, END_INDEX);
14228 : : left_len = END_INDEX - min_of_start_and_end;
14229 : : rhs = min (left_len, LEN_LIMIT);
14230 : : LEN = rhs;
14231 : :
14232 : : Note: the cost of the code generated by this function is modeled
14233 : : by vect_estimate_min_profitable_iters, so changes here may need
14234 : : corresponding changes there. */
14235 : :
14236 : : gimple_seq
14237 : 0 : vect_gen_len (tree len, tree start_index, tree end_index, tree len_limit)
14238 : : {
14239 : 0 : gimple_seq stmts = NULL;
14240 : 0 : tree len_type = TREE_TYPE (len);
14241 : 0 : gcc_assert (TREE_TYPE (start_index) == len_type);
14242 : :
14243 : 0 : tree min = gimple_build (&stmts, MIN_EXPR, len_type, start_index, end_index);
14244 : 0 : tree left_len = gimple_build (&stmts, MINUS_EXPR, len_type, end_index, min);
14245 : 0 : tree rhs = gimple_build (&stmts, MIN_EXPR, len_type, left_len, len_limit);
14246 : 0 : gimple* stmt = gimple_build_assign (len, rhs);
14247 : 0 : gimple_seq_add_stmt (&stmts, stmt);
14248 : :
14249 : 0 : return stmts;
14250 : : }
14251 : :
|