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 : : static tree vector_vector_composition_type (tree, poly_uint64, tree *,
66 : : bool = false);
67 : :
68 : : /* Return TRUE iff the given statement is in an inner loop relative to
69 : : the loop being vectorized. */
70 : : bool
71 : 3809415 : stmt_in_inner_loop_p (vec_info *vinfo, class _stmt_vec_info *stmt_info)
72 : : {
73 : 3809415 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
74 : 3809415 : basic_block bb = gimple_bb (stmt);
75 : 3809415 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
76 : 767474 : class loop* loop;
77 : :
78 : 767474 : if (!loop_vinfo)
79 : : return false;
80 : :
81 : 767474 : loop = LOOP_VINFO_LOOP (loop_vinfo);
82 : :
83 : 767474 : return (bb->loop_father == loop->inner);
84 : : }
85 : :
86 : : /* Record the cost of a statement, either by directly informing the
87 : : target model or by saving it in a vector for later processing.
88 : : Return a preliminary estimate of the statement's cost. */
89 : :
90 : : unsigned
91 : 9154578 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
92 : : enum vect_cost_for_stmt kind,
93 : : stmt_vec_info stmt_info, slp_tree node,
94 : : tree vectype, int misalign,
95 : : enum vect_cost_model_location where)
96 : : {
97 : 9154578 : if ((kind == vector_load || kind == unaligned_load)
98 : 1333213 : && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info)))
99 : : kind = vector_gather_load;
100 : 9154578 : if ((kind == vector_store || kind == unaligned_store)
101 : 907391 : && (stmt_info && STMT_VINFO_GATHER_SCATTER_P (stmt_info)))
102 : 9154578 : kind = vector_scatter_store;
103 : :
104 : 9154578 : stmt_info_for_cost si
105 : 9154578 : = { count, kind, where, stmt_info, node, vectype, misalign };
106 : 9154578 : body_cost_vec->safe_push (si);
107 : :
108 : 9154578 : return (unsigned)
109 : 9154578 : (builtin_vectorization_cost (kind, vectype, misalign) * count);
110 : : }
111 : :
112 : : unsigned
113 : 4822361 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
114 : : enum vect_cost_for_stmt kind, stmt_vec_info stmt_info,
115 : : tree vectype, int misalign,
116 : : enum vect_cost_model_location where)
117 : : {
118 : 4822361 : return record_stmt_cost (body_cost_vec, count, kind, stmt_info, NULL,
119 : 4822361 : vectype, misalign, where);
120 : : }
121 : :
122 : : unsigned
123 : 1494907 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
124 : : enum vect_cost_for_stmt kind, slp_tree node,
125 : : tree vectype, int misalign,
126 : : enum vect_cost_model_location where)
127 : : {
128 : 1494907 : return record_stmt_cost (body_cost_vec, count, kind,
129 : : SLP_TREE_REPRESENTATIVE (node), node,
130 : 1494907 : vectype, misalign, where);
131 : : }
132 : :
133 : : unsigned
134 : 144427 : record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
135 : : enum vect_cost_for_stmt kind,
136 : : enum vect_cost_model_location where)
137 : : {
138 : 144427 : gcc_assert (kind == cond_branch_taken || kind == cond_branch_not_taken
139 : : || kind == scalar_stmt);
140 : 144427 : return record_stmt_cost (body_cost_vec, count, kind, NULL, NULL,
141 : 144427 : NULL_TREE, 0, where);
142 : : }
143 : :
144 : : /* Return a variable of type ELEM_TYPE[NELEMS]. */
145 : :
146 : : static tree
147 : 0 : create_vector_array (tree elem_type, unsigned HOST_WIDE_INT nelems)
148 : : {
149 : 0 : return create_tmp_var (build_array_type_nelts (elem_type, nelems),
150 : 0 : "vect_array");
151 : : }
152 : :
153 : : /* ARRAY is an array of vectors created by create_vector_array.
154 : : Return an SSA_NAME for the vector in index N. The reference
155 : : is part of the vectorization of STMT_INFO and the vector is associated
156 : : with scalar destination SCALAR_DEST.
157 : : If we need to ensure that inactive elements are set to zero,
158 : : NEED_ZEROING is true, MASK contains the loop mask to be used. */
159 : :
160 : : static tree
161 : 0 : read_vector_array (vec_info *vinfo,
162 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
163 : : tree scalar_dest, tree array, unsigned HOST_WIDE_INT n,
164 : : bool need_zeroing, tree mask)
165 : : {
166 : 0 : tree vect_type, vect, vect_name, tmp, tmp_name, array_ref;
167 : 0 : gimple *new_stmt;
168 : :
169 : 0 : gcc_assert (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE);
170 : 0 : vect_type = TREE_TYPE (TREE_TYPE (array));
171 : 0 : tmp = vect_create_destination_var (scalar_dest, vect_type);
172 : 0 : vect = vect_create_destination_var (scalar_dest, vect_type);
173 : 0 : array_ref = build4 (ARRAY_REF, vect_type, array,
174 : 0 : build_int_cst (size_type_node, n),
175 : : NULL_TREE, NULL_TREE);
176 : :
177 : 0 : new_stmt = gimple_build_assign (tmp, array_ref);
178 : 0 : tmp_name = make_ssa_name (vect, new_stmt);
179 : 0 : gimple_assign_set_lhs (new_stmt, tmp_name);
180 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
181 : :
182 : 0 : if (need_zeroing)
183 : : {
184 : 0 : tree vec_els = vect_get_mask_load_else (MASK_LOAD_ELSE_ZERO,
185 : : vect_type);
186 : 0 : vect_name = make_ssa_name (vect, new_stmt);
187 : 0 : new_stmt
188 : 0 : = gimple_build_assign (vect_name, VEC_COND_EXPR,
189 : : mask, tmp_name, vec_els);
190 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
191 : : }
192 : : else
193 : : vect_name = tmp_name;
194 : :
195 : 0 : return vect_name;
196 : : }
197 : :
198 : : /* ARRAY is an array of vectors created by create_vector_array.
199 : : Emit code to store SSA_NAME VECT in index N of the array.
200 : : The store is part of the vectorization of STMT_INFO. */
201 : :
202 : : static void
203 : 0 : write_vector_array (vec_info *vinfo,
204 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
205 : : tree vect, tree array, unsigned HOST_WIDE_INT n)
206 : : {
207 : 0 : tree array_ref;
208 : 0 : gimple *new_stmt;
209 : :
210 : 0 : array_ref = build4 (ARRAY_REF, TREE_TYPE (vect), array,
211 : 0 : build_int_cst (size_type_node, n),
212 : : NULL_TREE, NULL_TREE);
213 : :
214 : 0 : new_stmt = gimple_build_assign (array_ref, vect);
215 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
216 : 0 : }
217 : :
218 : : /* PTR is a pointer to an array of type TYPE. Return a representation
219 : : of *PTR. The memory reference replaces those in FIRST_DR
220 : : (and its group). */
221 : :
222 : : static tree
223 : 0 : create_array_ref (tree type, tree ptr, tree alias_ptr_type)
224 : : {
225 : 0 : tree mem_ref;
226 : :
227 : 0 : mem_ref = build2 (MEM_REF, type, ptr, build_int_cst (alias_ptr_type, 0));
228 : : /* Arrays have the same alignment as their type. */
229 : 0 : set_ptr_info_alignment (get_ptr_info (ptr), TYPE_ALIGN_UNIT (type), 0);
230 : 0 : return mem_ref;
231 : : }
232 : :
233 : : /* Add a clobber of variable VAR to the vectorization of STMT_INFO.
234 : : Emit the clobber before *GSI. */
235 : :
236 : : static void
237 : 15 : vect_clobber_variable (vec_info *vinfo, stmt_vec_info stmt_info,
238 : : gimple_stmt_iterator *gsi, tree var)
239 : : {
240 : 15 : tree clobber = build_clobber (TREE_TYPE (var));
241 : 15 : gimple *new_stmt = gimple_build_assign (var, clobber);
242 : 15 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
243 : 15 : }
244 : :
245 : : /* Utility functions used by vect_mark_stmts_to_be_vectorized. */
246 : :
247 : : /* Function vect_mark_relevant.
248 : :
249 : : Mark STMT_INFO as "relevant for vectorization" and add it to WORKLIST. */
250 : :
251 : : static void
252 : 2428351 : vect_mark_relevant (vec<stmt_vec_info> *worklist, stmt_vec_info stmt_info,
253 : : enum vect_relevant relevant, bool live_p)
254 : : {
255 : 2428351 : enum vect_relevant save_relevant = STMT_VINFO_RELEVANT (stmt_info);
256 : 2428351 : bool save_live_p = STMT_VINFO_LIVE_P (stmt_info);
257 : :
258 : 2428351 : if (dump_enabled_p ())
259 : 152522 : dump_printf_loc (MSG_NOTE, vect_location,
260 : : "mark relevant %d, live %d: %G", relevant, live_p,
261 : : stmt_info->stmt);
262 : :
263 : : /* If this stmt is an original stmt in a pattern, we might need to mark its
264 : : related pattern stmt instead of the original stmt. However, such stmts
265 : : may have their own uses that are not in any pattern, in such cases the
266 : : stmt itself should be marked. */
267 : 2428351 : if (STMT_VINFO_IN_PATTERN_P (stmt_info))
268 : : {
269 : : /* This is the last stmt in a sequence that was detected as a
270 : : pattern that can potentially be vectorized. Don't mark the stmt
271 : : as relevant/live because it's not going to be vectorized.
272 : : Instead mark the pattern-stmt that replaces it. */
273 : :
274 : 170022 : if (dump_enabled_p ())
275 : 2317 : dump_printf_loc (MSG_NOTE, vect_location,
276 : : "last stmt in pattern. don't mark"
277 : : " relevant/live.\n");
278 : :
279 : 170022 : stmt_vec_info old_stmt_info = stmt_info;
280 : 170022 : stmt_info = STMT_VINFO_RELATED_STMT (stmt_info);
281 : 170022 : gcc_assert (STMT_VINFO_RELATED_STMT (stmt_info) == old_stmt_info);
282 : 170022 : save_relevant = STMT_VINFO_RELEVANT (stmt_info);
283 : 170022 : save_live_p = STMT_VINFO_LIVE_P (stmt_info);
284 : :
285 : 170022 : if (live_p && relevant == vect_unused_in_scope)
286 : : {
287 : 92 : if (dump_enabled_p ())
288 : 4 : dump_printf_loc (MSG_NOTE, vect_location,
289 : : "vec_stmt_relevant_p: forcing live pattern stmt "
290 : : "relevant.\n");
291 : : relevant = vect_used_only_live;
292 : : }
293 : :
294 : 170022 : if (dump_enabled_p ())
295 : 2317 : dump_printf_loc (MSG_NOTE, vect_location,
296 : : "mark relevant %d, live %d: %G", relevant, live_p,
297 : : stmt_info->stmt);
298 : : }
299 : :
300 : 2428351 : STMT_VINFO_LIVE_P (stmt_info) |= live_p;
301 : 2428351 : if (relevant > STMT_VINFO_RELEVANT (stmt_info))
302 : 2130124 : STMT_VINFO_RELEVANT (stmt_info) = relevant;
303 : :
304 : 2428351 : if (STMT_VINFO_RELEVANT (stmt_info) == save_relevant
305 : 298227 : && STMT_VINFO_LIVE_P (stmt_info) == save_live_p)
306 : : {
307 : 297586 : if (dump_enabled_p ())
308 : 18355 : dump_printf_loc (MSG_NOTE, vect_location,
309 : : "already marked relevant/live.\n");
310 : 297586 : return;
311 : : }
312 : :
313 : 2130765 : worklist->safe_push (stmt_info);
314 : : }
315 : :
316 : :
317 : : /* Function is_simple_and_all_uses_invariant
318 : :
319 : : Return true if STMT_INFO is simple and all uses of it are invariant. */
320 : :
321 : : bool
322 : 149690 : is_simple_and_all_uses_invariant (stmt_vec_info stmt_info,
323 : : loop_vec_info loop_vinfo)
324 : : {
325 : 149690 : tree op;
326 : 149690 : ssa_op_iter iter;
327 : :
328 : 263049 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
329 : 114092 : if (!stmt)
330 : : return false;
331 : :
332 : 119174 : FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
333 : : {
334 : 118441 : enum vect_def_type dt = vect_uninitialized_def;
335 : :
336 : 118441 : if (!vect_is_simple_use (op, loop_vinfo, &dt))
337 : : {
338 : 969 : if (dump_enabled_p ())
339 : 15 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
340 : : "use not simple.\n");
341 : 113359 : return false;
342 : : }
343 : :
344 : 117472 : if (dt != vect_external_def && dt != vect_constant_def)
345 : : return false;
346 : : }
347 : : return true;
348 : : }
349 : :
350 : : /* Function vect_stmt_relevant_p.
351 : :
352 : : Return true if STMT_INFO, in the loop that is represented by LOOP_VINFO,
353 : : is "relevant for vectorization".
354 : :
355 : : A stmt is considered "relevant for vectorization" if:
356 : : - it has uses outside the loop.
357 : : - it has vdefs (it alters memory).
358 : : - control stmts in the loop (except for the exit condition).
359 : :
360 : : CHECKME: what other side effects would the vectorizer allow? */
361 : :
362 : : static bool
363 : 3803374 : vect_stmt_relevant_p (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
364 : : enum vect_relevant *relevant, bool *live_p)
365 : : {
366 : 3803374 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
367 : 3803374 : ssa_op_iter op_iter;
368 : 3803374 : imm_use_iterator imm_iter;
369 : 3803374 : use_operand_p use_p;
370 : 3803374 : def_operand_p def_p;
371 : :
372 : 3803374 : *relevant = vect_unused_in_scope;
373 : 3803374 : *live_p = false;
374 : :
375 : : /* cond stmt other than loop exit cond. */
376 : 3803374 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
377 : 3803374 : if (is_ctrl_stmt (stmt)
378 : 477744 : && LOOP_VINFO_LOOP_IV_COND (loop_vinfo) != stmt
379 : 3969320 : && (!loop->inner || gimple_bb (stmt)->loop_father == loop))
380 : 164307 : *relevant = vect_used_in_scope;
381 : :
382 : : /* changing memory. */
383 : 3803374 : if (gimple_code (stmt_info->stmt) != GIMPLE_PHI)
384 : 3158674 : if (gimple_vdef (stmt_info->stmt)
385 : 2680930 : && !gimple_clobber_p (stmt_info->stmt))
386 : : {
387 : 270706 : if (dump_enabled_p ())
388 : 25998 : dump_printf_loc (MSG_NOTE, vect_location,
389 : : "vec_stmt_relevant_p: stmt has vdefs.\n");
390 : 270706 : *relevant = vect_used_in_scope;
391 : 270706 : if (! STMT_VINFO_DATA_REF (stmt_info)
392 : 270706 : && zero_ssa_operands (stmt_info->stmt, SSA_OP_DEF))
393 : 20 : LOOP_VINFO_ALTERNATE_DEFS (loop_vinfo).safe_push (stmt_info);
394 : : }
395 : :
396 : : /* uses outside the loop. */
397 : 10655298 : FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt_info->stmt, op_iter, SSA_OP_DEF)
398 : : {
399 : 11158814 : FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
400 : : {
401 : 5061714 : basic_block bb = gimple_bb (USE_STMT (use_p));
402 : 5061714 : if (!flow_bb_inside_loop_p (loop, bb))
403 : : {
404 : 161129 : if (is_gimple_debug (USE_STMT (use_p)))
405 : 678 : continue;
406 : :
407 : 160451 : if (dump_enabled_p ())
408 : 5383 : dump_printf_loc (MSG_NOTE, vect_location,
409 : : "vec_stmt_relevant_p: used out of loop.\n");
410 : :
411 : : /* We expect all such uses to be in the loop exit phis
412 : : (because of loop closed form) */
413 : 160451 : gcc_assert (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI);
414 : :
415 : 160451 : *live_p = true;
416 : : }
417 : 3048550 : }
418 : : }
419 : :
420 : 149692 : if (*live_p && *relevant == vect_unused_in_scope
421 : 3953064 : && !is_simple_and_all_uses_invariant (stmt_info, loop_vinfo))
422 : : {
423 : 148957 : if (dump_enabled_p ())
424 : 5253 : dump_printf_loc (MSG_NOTE, vect_location,
425 : : "vec_stmt_relevant_p: stmt live but not relevant.\n");
426 : 148957 : *relevant = vect_used_only_live;
427 : : }
428 : :
429 : 3803374 : return (*live_p || *relevant);
430 : : }
431 : :
432 : :
433 : : /* Function exist_non_indexing_operands_for_use_p
434 : :
435 : : USE is one of the uses attached to STMT_INFO. Check if USE is
436 : : used in STMT_INFO for anything other than indexing an array. */
437 : :
438 : : static bool
439 : 3232739 : exist_non_indexing_operands_for_use_p (tree use, stmt_vec_info stmt_info)
440 : : {
441 : 3232739 : tree operand;
442 : :
443 : : /* USE corresponds to some operand in STMT. If there is no data
444 : : reference in STMT, then any operand that corresponds to USE
445 : : is not indexing an array. */
446 : 3232739 : if (!STMT_VINFO_DATA_REF (stmt_info))
447 : : return true;
448 : :
449 : : /* STMT has a data_ref. FORNOW this means that its of one of
450 : : the following forms:
451 : : -1- ARRAY_REF = var
452 : : -2- var = ARRAY_REF
453 : : (This should have been verified in analyze_data_refs).
454 : :
455 : : 'var' in the second case corresponds to a def, not a use,
456 : : so USE cannot correspond to any operands that are not used
457 : : for array indexing.
458 : :
459 : : Therefore, all we need to check is if STMT falls into the
460 : : first case, and whether var corresponds to USE. */
461 : :
462 : 1125401 : gassign *assign = dyn_cast <gassign *> (stmt_info->stmt);
463 : 1112934 : if (!assign || !gimple_assign_copy_p (assign))
464 : : {
465 : 618284 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
466 : 12467 : if (call && gimple_call_internal_p (call))
467 : : {
468 : 12467 : internal_fn ifn = gimple_call_internal_fn (call);
469 : 12467 : int mask_index = internal_fn_mask_index (ifn);
470 : 12467 : if (mask_index >= 0
471 : 12467 : && use == gimple_call_arg (call, mask_index))
472 : : return true;
473 : 8207 : int els_index = internal_fn_else_index (ifn);
474 : 8207 : if (els_index >= 0
475 : 8207 : && use == gimple_call_arg (call, els_index))
476 : : return true;
477 : 6980 : int stored_value_index = internal_fn_stored_value_index (ifn);
478 : 6980 : if (stored_value_index >= 0
479 : 6980 : && use == gimple_call_arg (call, stored_value_index))
480 : : return true;
481 : 5683 : if (internal_gather_scatter_fn_p (ifn)
482 : 5683 : && use == gimple_call_arg (call, 1))
483 : : return true;
484 : : }
485 : 611500 : return false;
486 : : }
487 : :
488 : 507117 : if (TREE_CODE (gimple_assign_lhs (assign)) == SSA_NAME)
489 : : return false;
490 : 507117 : operand = gimple_assign_rhs1 (assign);
491 : 507117 : if (TREE_CODE (operand) != SSA_NAME)
492 : : return false;
493 : :
494 : 438269 : if (operand == use)
495 : : return true;
496 : :
497 : : return false;
498 : : }
499 : :
500 : :
501 : : /*
502 : : Function process_use.
503 : :
504 : : Inputs:
505 : : - a USE in STMT_VINFO in a loop represented by LOOP_VINFO
506 : : - RELEVANT - enum value to be set in the STMT_VINFO of the stmt
507 : : that defined USE. This is done by calling mark_relevant and passing it
508 : : the WORKLIST (to add DEF_STMT to the WORKLIST in case it is relevant).
509 : : - FORCE is true if exist_non_indexing_operands_for_use_p check shouldn't
510 : : be performed.
511 : :
512 : : Outputs:
513 : : Generally, LIVE_P and RELEVANT are used to define the liveness and
514 : : relevance info of the DEF_STMT of this USE:
515 : : STMT_VINFO_LIVE_P (DEF_stmt_vinfo) <-- live_p
516 : : STMT_VINFO_RELEVANT (DEF_stmt_vinfo) <-- relevant
517 : : Exceptions:
518 : : - case 1: If USE is used only for address computations (e.g. array indexing),
519 : : which does not need to be directly vectorized, then the liveness/relevance
520 : : of the respective DEF_STMT is left unchanged.
521 : : - case 2: If STMT_VINFO is a reduction phi and DEF_STMT is a reduction stmt,
522 : : we skip DEF_STMT cause it had already been processed.
523 : : - case 3: If DEF_STMT and STMT_VINFO are in different nests, then
524 : : "relevant" will be modified accordingly.
525 : :
526 : : Return true if everything is as expected. Return false otherwise. */
527 : :
528 : : static opt_result
529 : 3262309 : process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
530 : : enum vect_relevant relevant, vec<stmt_vec_info> *worklist,
531 : : bool force)
532 : : {
533 : 3262309 : stmt_vec_info dstmt_vinfo;
534 : 3262309 : enum vect_def_type dt;
535 : :
536 : : /* case 1: we are only interested in uses that need to be vectorized. Uses
537 : : that are used for address computation are not considered relevant. */
538 : 3262309 : if (!force && !exist_non_indexing_operands_for_use_p (use, stmt_vinfo))
539 : 911979 : return opt_result::success ();
540 : :
541 : 2350330 : if (!vect_is_simple_use (use, loop_vinfo, &dt, &dstmt_vinfo))
542 : 10807 : return opt_result::failure_at (stmt_vinfo->stmt,
543 : : "not vectorized:"
544 : : " unsupported use in stmt.\n");
545 : :
546 : 2339523 : if (!dstmt_vinfo)
547 : 440091 : return opt_result::success ();
548 : :
549 : 1899432 : basic_block def_bb = gimple_bb (dstmt_vinfo->stmt);
550 : 1899432 : basic_block bb = gimple_bb (stmt_vinfo->stmt);
551 : :
552 : : /* case 2: A reduction phi (STMT) defined by a reduction stmt (DSTMT_VINFO).
553 : : We have to force the stmt live since the epilogue loop needs it to
554 : : continue computing the reduction. */
555 : 1899432 : if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI
556 : 195606 : && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
557 : 57709 : && gimple_code (dstmt_vinfo->stmt) != GIMPLE_PHI
558 : 57709 : && STMT_VINFO_DEF_TYPE (dstmt_vinfo) == vect_reduction_def
559 : 1957141 : && bb->loop_father == def_bb->loop_father)
560 : : {
561 : 57709 : if (dump_enabled_p ())
562 : 3540 : dump_printf_loc (MSG_NOTE, vect_location,
563 : : "reduc-stmt defining reduc-phi in the same nest.\n");
564 : 57709 : vect_mark_relevant (worklist, dstmt_vinfo, relevant, true);
565 : 57709 : return opt_result::success ();
566 : : }
567 : :
568 : : /* case 3a: outer-loop stmt defining an inner-loop stmt:
569 : : outer-loop-header-bb:
570 : : d = dstmt_vinfo
571 : : inner-loop:
572 : : stmt # use (d)
573 : : outer-loop-tail-bb:
574 : : ... */
575 : 1841723 : if (flow_loop_nested_p (def_bb->loop_father, bb->loop_father))
576 : : {
577 : 1852 : if (dump_enabled_p ())
578 : 281 : dump_printf_loc (MSG_NOTE, vect_location,
579 : : "outer-loop def-stmt defining inner-loop stmt.\n");
580 : :
581 : 1852 : switch (relevant)
582 : : {
583 : 0 : case vect_unused_in_scope:
584 : 0 : relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_nested_cycle) ?
585 : : vect_used_in_scope : vect_unused_in_scope;
586 : : break;
587 : :
588 : 614 : case vect_used_in_outer_by_reduction:
589 : 614 : gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def);
590 : : relevant = vect_used_by_reduction;
591 : : break;
592 : :
593 : 1007 : case vect_used_in_outer:
594 : 1007 : gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def);
595 : : relevant = vect_used_in_scope;
596 : : break;
597 : :
598 : : case vect_used_in_scope:
599 : : break;
600 : :
601 : 0 : default:
602 : 0 : gcc_unreachable ();
603 : : }
604 : : }
605 : :
606 : : /* case 3b: inner-loop stmt defining an outer-loop stmt:
607 : : outer-loop-header-bb:
608 : : ...
609 : : inner-loop:
610 : : d = dstmt_vinfo
611 : : outer-loop-tail-bb (or outer-loop-exit-bb in double reduction):
612 : : stmt # use (d) */
613 : 1839871 : else if (flow_loop_nested_p (bb->loop_father, def_bb->loop_father))
614 : : {
615 : 1724 : if (dump_enabled_p ())
616 : 534 : dump_printf_loc (MSG_NOTE, vect_location,
617 : : "inner-loop def-stmt defining outer-loop stmt.\n");
618 : :
619 : 1724 : switch (relevant)
620 : : {
621 : 0 : case vect_unused_in_scope:
622 : 0 : relevant = (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
623 : 0 : || STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_double_reduction_def) ?
624 : : vect_used_in_outer_by_reduction : vect_unused_in_scope;
625 : : break;
626 : :
627 : : case vect_used_by_reduction:
628 : : case vect_used_only_live:
629 : : relevant = vect_used_in_outer_by_reduction;
630 : : break;
631 : :
632 : : case vect_used_in_scope:
633 : 1788576 : relevant = vect_used_in_outer;
634 : : break;
635 : :
636 : 0 : default:
637 : 0 : gcc_unreachable ();
638 : : }
639 : : }
640 : : /* We are also not interested in uses on loop PHI backedges that are
641 : : inductions. Otherwise we'll needlessly vectorize the IV increment
642 : : and cause hybrid SLP for SLP inductions. */
643 : 1838147 : else if (gimple_code (stmt_vinfo->stmt) == GIMPLE_PHI
644 : 135104 : && STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_induction_def
645 : 132450 : && (PHI_ARG_DEF_FROM_EDGE (stmt_vinfo->stmt,
646 : : loop_latch_edge (bb->loop_father))
647 : : == use)
648 : 1970597 : && (!LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
649 : 79303 : || (gimple_bb (stmt_vinfo->stmt)
650 : 79303 : != LOOP_VINFO_LOOP (loop_vinfo)->header)))
651 : : {
652 : 53147 : if (dump_enabled_p ())
653 : 3433 : dump_printf_loc (MSG_NOTE, vect_location,
654 : : "induction value on backedge.\n");
655 : 53147 : return opt_result::success ();
656 : : }
657 : :
658 : 1788576 : vect_mark_relevant (worklist, dstmt_vinfo, relevant, false);
659 : 1788576 : return opt_result::success ();
660 : : }
661 : :
662 : :
663 : : /* Function vect_mark_stmts_to_be_vectorized.
664 : :
665 : : Not all stmts in the loop need to be vectorized. For example:
666 : :
667 : : for i...
668 : : for j...
669 : : 1. T0 = i + j
670 : : 2. T1 = a[T0]
671 : :
672 : : 3. j = j + 1
673 : :
674 : : Stmt 1 and 3 do not need to be vectorized, because loop control and
675 : : addressing of vectorized data-refs are handled differently.
676 : :
677 : : This pass detects such stmts. */
678 : :
679 : : opt_result
680 : 314554 : vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo, bool *fatal)
681 : : {
682 : 314554 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
683 : 314554 : basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
684 : 314554 : unsigned int nbbs = loop->num_nodes;
685 : 314554 : gimple_stmt_iterator si;
686 : 314554 : unsigned int i;
687 : 314554 : basic_block bb;
688 : 314554 : bool live_p;
689 : 314554 : enum vect_relevant relevant;
690 : :
691 : 314554 : DUMP_VECT_SCOPE ("vect_mark_stmts_to_be_vectorized");
692 : :
693 : 314554 : auto_vec<stmt_vec_info, 64> worklist;
694 : :
695 : : /* 1. Init worklist. */
696 : 1107386 : for (i = 0; i < nbbs; i++)
697 : : {
698 : 795588 : bb = bbs[i];
699 : 1605305 : for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
700 : : {
701 : 1624708 : if (virtual_operand_p (gimple_phi_result (gsi_stmt (si))))
702 : 167654 : continue;
703 : 644700 : stmt_vec_info phi_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
704 : 644700 : if (dump_enabled_p ())
705 : 38177 : dump_printf_loc (MSG_NOTE, vect_location, "init: phi relevant? %G",
706 : : phi_info->stmt);
707 : :
708 : 644700 : if (vect_stmt_relevant_p (phi_info, loop_vinfo, &relevant, &live_p))
709 : : {
710 : 29390 : if (STMT_VINFO_DEF_TYPE (phi_info) == vect_unknown_def_type)
711 : 2637 : return opt_result::failure_at
712 : 2637 : (*si, "not vectorized: unhandled relevant PHI: %G", *si);
713 : 26753 : vect_mark_relevant (&worklist, phi_info, relevant, live_p);
714 : : }
715 : : }
716 : 5718646 : for (si = gsi_after_labels (bb); !gsi_end_p (si); gsi_next (&si))
717 : : {
718 : 4925814 : gimple *stmt = gsi_stmt (si);
719 : 4925814 : if (is_gimple_debug (stmt))
720 : 1767021 : continue;
721 : 3158793 : stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (stmt);
722 : 3158793 : if (dump_enabled_p ())
723 : 204472 : dump_printf_loc (MSG_NOTE, vect_location,
724 : : "init: stmt relevant? %G", stmt);
725 : :
726 : 3158793 : if (gimple_get_lhs (stmt) == NULL_TREE
727 : 483043 : && !is_a <gcond *> (stmt)
728 : 3164092 : && !is_a <gcall *> (stmt))
729 : 119 : return opt_result::failure_at
730 : 119 : (stmt, "not vectorized: irregular stmt: %G", stmt);
731 : :
732 : 3158674 : if (vect_stmt_relevant_p (stmt_info, loop_vinfo, &relevant, &live_p))
733 : 555313 : vect_mark_relevant (&worklist, stmt_info, relevant, live_p);
734 : : }
735 : : }
736 : :
737 : : /* 2. Process_worklist */
738 : 2405587 : while (worklist.length () > 0)
739 : : {
740 : 2104598 : use_operand_p use_p;
741 : 2104598 : ssa_op_iter iter;
742 : :
743 : 2104598 : stmt_vec_info stmt_vinfo = worklist.pop ();
744 : 2104598 : if (dump_enabled_p ())
745 : 133752 : dump_printf_loc (MSG_NOTE, vect_location,
746 : : "worklist: examine stmt: %G", stmt_vinfo->stmt);
747 : :
748 : : /* Examine the USEs of STMT. For each USE, mark the stmt that defines it
749 : : (DEF_STMT) as relevant/irrelevant according to the relevance property
750 : : of STMT. */
751 : 2104598 : relevant = STMT_VINFO_RELEVANT (stmt_vinfo);
752 : :
753 : : /* Generally, the relevance property of STMT (in STMT_VINFO_RELEVANT) is
754 : : propagated as is to the DEF_STMTs of its USEs.
755 : :
756 : : One exception is when STMT has been identified as defining a reduction
757 : : variable; in this case we set the relevance to vect_used_by_reduction.
758 : : This is because we distinguish between two kinds of relevant stmts -
759 : : those that are used by a reduction computation, and those that are
760 : : (also) used by a regular computation. This allows us later on to
761 : : identify stmts that are used solely by a reduction, and therefore the
762 : : order of the results that they produce does not have to be kept. */
763 : :
764 : 2104598 : switch (STMT_VINFO_DEF_TYPE (stmt_vinfo))
765 : : {
766 : 115976 : case vect_reduction_def:
767 : 115976 : gcc_assert (relevant != vect_unused_in_scope);
768 : 115976 : if (relevant != vect_unused_in_scope
769 : 115976 : && relevant != vect_used_in_scope
770 : 115976 : && relevant != vect_used_by_reduction
771 : 115976 : && relevant != vect_used_only_live)
772 : 0 : return opt_result::failure_at
773 : 0 : (stmt_vinfo->stmt, "unsupported use of reduction.\n");
774 : : break;
775 : :
776 : 1905 : case vect_nested_cycle:
777 : 1905 : if (relevant != vect_unused_in_scope
778 : 1905 : && relevant != vect_used_in_outer_by_reduction
779 : 1420 : && relevant != vect_used_in_outer)
780 : 2 : return opt_result::failure_at
781 : 2 : (stmt_vinfo->stmt, "unsupported use of nested cycle.\n");
782 : : break;
783 : :
784 : 989 : case vect_double_reduction_def:
785 : 989 : if (relevant != vect_unused_in_scope
786 : 989 : && relevant != vect_used_by_reduction
787 : 335 : && relevant != vect_used_only_live)
788 : 0 : return opt_result::failure_at
789 : 0 : (stmt_vinfo->stmt, "unsupported use of double reduction.\n");
790 : : break;
791 : :
792 : : default:
793 : : break;
794 : : }
795 : :
796 : 2104596 : if (is_pattern_stmt_p (stmt_vinfo))
797 : : {
798 : : /* Pattern statements are not inserted into the code, so
799 : : FOR_EACH_PHI_OR_STMT_USE optimizes their operands out, and we
800 : : have to scan the RHS or function arguments instead. */
801 : 459227 : if (gassign *assign = dyn_cast <gassign *> (stmt_vinfo->stmt))
802 : : {
803 : 296340 : enum tree_code rhs_code = gimple_assign_rhs_code (assign);
804 : 296340 : tree op = gimple_assign_rhs1 (assign);
805 : :
806 : 296340 : i = 1;
807 : 296340 : if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op))
808 : : {
809 : 0 : opt_result res
810 : 0 : = process_use (stmt_vinfo, TREE_OPERAND (op, 0),
811 : : loop_vinfo, relevant, &worklist, false);
812 : 0 : if (!res)
813 : 0 : return res;
814 : 0 : res = process_use (stmt_vinfo, TREE_OPERAND (op, 1),
815 : : loop_vinfo, relevant, &worklist, false);
816 : 0 : if (!res)
817 : 0 : return res;
818 : : i = 2;
819 : : }
820 : 853154 : for (; i < gimple_num_ops (assign); i++)
821 : : {
822 : 557680 : op = gimple_op (assign, i);
823 : 557680 : if (TREE_CODE (op) == SSA_NAME)
824 : : {
825 : 426492 : opt_result res
826 : 426492 : = process_use (stmt_vinfo, op, loop_vinfo, relevant,
827 : : &worklist, false);
828 : 426492 : if (!res)
829 : 866 : return res;
830 : : }
831 : : }
832 : : }
833 : 162887 : else if (gcond *cond = dyn_cast <gcond *> (stmt_vinfo->stmt))
834 : : {
835 : 158616 : tree_code rhs_code = gimple_cond_code (cond);
836 : 158616 : gcc_assert (TREE_CODE_CLASS (rhs_code) == tcc_comparison);
837 : 158616 : opt_result res
838 : 158616 : = process_use (stmt_vinfo, gimple_cond_lhs (cond),
839 : : loop_vinfo, relevant, &worklist, false);
840 : 158616 : if (!res)
841 : 10809 : return res;
842 : 158616 : res = process_use (stmt_vinfo, gimple_cond_rhs (cond),
843 : : loop_vinfo, relevant, &worklist, false);
844 : 158616 : if (!res)
845 : 0 : return res;
846 : : }
847 : 4271 : else if (gcall *call = dyn_cast <gcall *> (stmt_vinfo->stmt))
848 : : {
849 : 20603 : for (i = 0; i < gimple_call_num_args (call); i++)
850 : : {
851 : 16332 : tree arg = gimple_call_arg (call, i);
852 : 16332 : opt_result res
853 : 16332 : = process_use (stmt_vinfo, arg, loop_vinfo, relevant,
854 : : &worklist, false);
855 : 16332 : if (!res)
856 : 0 : return res;
857 : : }
858 : : }
859 : : else
860 : 0 : gcc_unreachable ();
861 : : }
862 : : else
863 : 5754463 : FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE)
864 : : {
865 : 2472683 : tree op = USE_FROM_PTR (use_p);
866 : 2472683 : opt_result res
867 : 2472683 : = process_use (stmt_vinfo, op, loop_vinfo, relevant,
868 : : &worklist, false);
869 : 2472683 : if (!res)
870 : 8958 : return res;
871 : : }
872 : :
873 : 2094772 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo))
874 : : {
875 : 29570 : gather_scatter_info gs_info;
876 : 29570 : if (!vect_check_gather_scatter (stmt_vinfo,
877 : : STMT_VINFO_VECTYPE (stmt_vinfo),
878 : : loop_vinfo, &gs_info))
879 : 0 : gcc_unreachable ();
880 : 29570 : opt_result res
881 : 29570 : = process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
882 : : &worklist, true);
883 : 29570 : if (!res)
884 : : {
885 : 983 : if (fatal)
886 : 983 : *fatal = false;
887 : 983 : return res;
888 : : }
889 : : }
890 : : } /* while worklist */
891 : :
892 : 300989 : return opt_result::success ();
893 : 314554 : }
894 : :
895 : : /* Function vect_model_simple_cost.
896 : :
897 : : Models cost for simple operations, i.e. those that only emit N operations
898 : : of the same KIND. */
899 : :
900 : : static void
901 : 610170 : vect_model_simple_cost (vec_info *vinfo, int n, slp_tree node,
902 : : stmt_vector_for_cost *cost_vec,
903 : : vect_cost_for_stmt kind = vector_stmt)
904 : : {
905 : 610170 : int inside_cost = 0, prologue_cost = 0;
906 : :
907 : 610170 : gcc_assert (cost_vec != NULL);
908 : :
909 : 610170 : n *= vect_get_num_copies (vinfo, node);
910 : :
911 : : /* Pass the inside-of-loop statements to the target-specific cost model. */
912 : 610170 : inside_cost += record_stmt_cost (cost_vec, n, kind, node, 0, vect_body);
913 : :
914 : 610170 : if (dump_enabled_p ())
915 : 31645 : dump_printf_loc (MSG_NOTE, vect_location,
916 : : "vect_model_simple_cost: inside_cost = %d, "
917 : : "prologue_cost = %d .\n", inside_cost, prologue_cost);
918 : 610170 : }
919 : :
920 : :
921 : : /* Model cost for type demotion and promotion operations. PWR is
922 : : normally zero for single-step promotions and demotions. It will be
923 : : one if two-step promotion/demotion is required, and so on. NCOPIES
924 : : is the number of vector results (and thus number of instructions)
925 : : for the narrowest end of the operation chain. Each additional
926 : : step doubles the number of instructions required. If WIDEN_ARITH
927 : : is true the stmt is doing widening arithmetic. */
928 : :
929 : : static void
930 : 55332 : vect_model_promotion_demotion_cost (slp_tree slp_node,
931 : : unsigned int ncopies, int pwr,
932 : : stmt_vector_for_cost *cost_vec,
933 : : bool widen_arith)
934 : : {
935 : 55332 : int i;
936 : 55332 : int inside_cost = 0, prologue_cost = 0;
937 : :
938 : 130626 : for (i = 0; i < pwr + 1; i++)
939 : : {
940 : 148623 : inside_cost += record_stmt_cost (cost_vec, ncopies,
941 : : widen_arith
942 : : ? vector_stmt : vec_promote_demote,
943 : : slp_node, 0, vect_body);
944 : 75294 : ncopies *= 2;
945 : : }
946 : :
947 : 55332 : if (dump_enabled_p ())
948 : 6114 : dump_printf_loc (MSG_NOTE, vect_location,
949 : : "vect_model_promotion_demotion_cost: inside_cost = %d, "
950 : : "prologue_cost = %d .\n", inside_cost, prologue_cost);
951 : 55332 : }
952 : :
953 : : /* Returns true if the current function returns DECL. */
954 : :
955 : : static bool
956 : 547575 : cfun_returns (tree decl)
957 : : {
958 : 547575 : edge_iterator ei;
959 : 547575 : edge e;
960 : 1077852 : FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
961 : : {
962 : 1084290 : greturn *ret = safe_dyn_cast <greturn *> (*gsi_last_bb (e->src));
963 : 542145 : if (!ret)
964 : 0 : continue;
965 : 542145 : if (gimple_return_retval (ret) == decl)
966 : : return true;
967 : : /* We often end up with an aggregate copy to the result decl,
968 : : handle that case as well. First skip intermediate clobbers
969 : : though. */
970 : : gimple *def = ret;
971 : 1593440 : do
972 : : {
973 : 3186880 : def = SSA_NAME_DEF_STMT (gimple_vuse (def));
974 : : }
975 : 1593440 : while (gimple_clobber_p (def));
976 : 530955 : if (is_a <gassign *> (def)
977 : 62871 : && gimple_assign_lhs (def) == gimple_return_retval (ret)
978 : 539165 : && gimple_assign_rhs1 (def) == decl)
979 : : return true;
980 : : }
981 : : return false;
982 : : }
983 : :
984 : : /* Calculate cost of DR's memory access. */
985 : : void
986 : 897177 : vect_get_store_cost (vec_info *, stmt_vec_info stmt_info, slp_tree slp_node,
987 : : int ncopies, dr_alignment_support alignment_support_scheme,
988 : : int misalignment,
989 : : unsigned int *inside_cost,
990 : : stmt_vector_for_cost *body_cost_vec)
991 : : {
992 : 897177 : tree vectype
993 : 897177 : = slp_node ? SLP_TREE_VECTYPE (slp_node) : STMT_VINFO_VECTYPE (stmt_info);
994 : 897177 : switch (alignment_support_scheme)
995 : : {
996 : 475846 : case dr_aligned:
997 : 475846 : {
998 : 475846 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
999 : : vector_store, stmt_info, slp_node,
1000 : : vectype, 0, vect_body);
1001 : :
1002 : 475846 : if (dump_enabled_p ())
1003 : 13481 : dump_printf_loc (MSG_NOTE, vect_location,
1004 : : "vect_model_store_cost: aligned.\n");
1005 : : break;
1006 : : }
1007 : :
1008 : 421331 : case dr_unaligned_supported:
1009 : 421331 : {
1010 : : /* Here, we assign an additional cost for the unaligned store. */
1011 : 421331 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1012 : : unaligned_store, stmt_info, slp_node,
1013 : : vectype, misalignment, vect_body);
1014 : 421331 : if (dump_enabled_p ())
1015 : 12356 : dump_printf_loc (MSG_NOTE, vect_location,
1016 : : "vect_model_store_cost: unaligned supported by "
1017 : : "hardware.\n");
1018 : : break;
1019 : : }
1020 : :
1021 : 0 : case dr_unaligned_unsupported:
1022 : 0 : {
1023 : 0 : *inside_cost = VECT_MAX_COST;
1024 : :
1025 : 0 : if (dump_enabled_p ())
1026 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1027 : : "vect_model_store_cost: unsupported access.\n");
1028 : : break;
1029 : : }
1030 : :
1031 : 0 : default:
1032 : 0 : gcc_unreachable ();
1033 : : }
1034 : 897177 : }
1035 : :
1036 : : /* Calculate cost of DR's memory access. */
1037 : : void
1038 : 733763 : vect_get_load_cost (vec_info *, stmt_vec_info stmt_info, slp_tree slp_node,
1039 : : int ncopies, dr_alignment_support alignment_support_scheme,
1040 : : int misalignment,
1041 : : bool add_realign_cost, unsigned int *inside_cost,
1042 : : unsigned int *prologue_cost,
1043 : : stmt_vector_for_cost *prologue_cost_vec,
1044 : : stmt_vector_for_cost *body_cost_vec,
1045 : : bool record_prologue_costs)
1046 : : {
1047 : 733763 : tree vectype
1048 : 733763 : = slp_node ? SLP_TREE_VECTYPE (slp_node) : STMT_VINFO_VECTYPE (stmt_info);
1049 : 733763 : switch (alignment_support_scheme)
1050 : : {
1051 : 424365 : case dr_aligned:
1052 : 424365 : {
1053 : 424365 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load,
1054 : : stmt_info, slp_node, vectype,
1055 : : 0, vect_body);
1056 : :
1057 : 424365 : if (dump_enabled_p ())
1058 : 17651 : dump_printf_loc (MSG_NOTE, vect_location,
1059 : : "vect_model_load_cost: aligned.\n");
1060 : :
1061 : : break;
1062 : : }
1063 : 255453 : case dr_unaligned_supported:
1064 : 255453 : {
1065 : : /* Here, we assign an additional cost for the unaligned load. */
1066 : 255453 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1067 : : unaligned_load, stmt_info, slp_node,
1068 : : vectype, misalignment, vect_body);
1069 : :
1070 : 255453 : if (dump_enabled_p ())
1071 : 20462 : dump_printf_loc (MSG_NOTE, vect_location,
1072 : : "vect_model_load_cost: unaligned supported by "
1073 : : "hardware.\n");
1074 : :
1075 : : break;
1076 : : }
1077 : 0 : case dr_explicit_realign:
1078 : 0 : {
1079 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies * 2,
1080 : : vector_load, stmt_info, slp_node,
1081 : : vectype, 0, vect_body);
1082 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies,
1083 : : vec_perm, stmt_info, slp_node,
1084 : : vectype, 0, vect_body);
1085 : :
1086 : : /* FIXME: If the misalignment remains fixed across the iterations of
1087 : : the containing loop, the following cost should be added to the
1088 : : prologue costs. */
1089 : 0 : if (targetm.vectorize.builtin_mask_for_load)
1090 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, 1, vector_stmt,
1091 : : stmt_info, slp_node, vectype,
1092 : : 0, vect_body);
1093 : :
1094 : 0 : if (dump_enabled_p ())
1095 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1096 : : "vect_model_load_cost: explicit realign\n");
1097 : :
1098 : : break;
1099 : : }
1100 : 0 : case dr_explicit_realign_optimized:
1101 : 0 : {
1102 : 0 : if (dump_enabled_p ())
1103 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1104 : : "vect_model_load_cost: unaligned software "
1105 : : "pipelined.\n");
1106 : :
1107 : : /* Unaligned software pipeline has a load of an address, an initial
1108 : : load, and possibly a mask operation to "prime" the loop. However,
1109 : : if this is an access in a group of loads, which provide grouped
1110 : : access, then the above cost should only be considered for one
1111 : : access in the group. Inside the loop, there is a load op
1112 : : and a realignment op. */
1113 : :
1114 : 0 : if (add_realign_cost && record_prologue_costs)
1115 : : {
1116 : 0 : *prologue_cost += record_stmt_cost (prologue_cost_vec, 2,
1117 : : vector_stmt, stmt_info,
1118 : : slp_node, vectype,
1119 : : 0, vect_prologue);
1120 : 0 : if (targetm.vectorize.builtin_mask_for_load)
1121 : 0 : *prologue_cost += record_stmt_cost (prologue_cost_vec, 1,
1122 : : vector_stmt, stmt_info,
1123 : : slp_node, vectype,
1124 : : 0, vect_prologue);
1125 : : }
1126 : :
1127 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vector_load,
1128 : : stmt_info, slp_node, vectype,
1129 : : 0, vect_body);
1130 : 0 : *inside_cost += record_stmt_cost (body_cost_vec, ncopies, vec_perm,
1131 : : stmt_info, slp_node, vectype,
1132 : : 0, vect_body);
1133 : :
1134 : 0 : if (dump_enabled_p ())
1135 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1136 : : "vect_model_load_cost: explicit realign optimized"
1137 : : "\n");
1138 : :
1139 : : break;
1140 : : }
1141 : :
1142 : 53945 : case dr_unaligned_unsupported:
1143 : 53945 : {
1144 : 53945 : *inside_cost = VECT_MAX_COST;
1145 : :
1146 : 53945 : if (dump_enabled_p ())
1147 : 93 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1148 : : "vect_model_load_cost: unsupported access.\n");
1149 : : break;
1150 : : }
1151 : :
1152 : 0 : default:
1153 : 0 : gcc_unreachable ();
1154 : : }
1155 : 733763 : }
1156 : :
1157 : : /* Insert the new stmt NEW_STMT at *GSI or at the appropriate place in
1158 : : the loop preheader for the vectorized stmt STMT_VINFO. */
1159 : :
1160 : : static void
1161 : 6250 : vect_init_vector_1 (vec_info *vinfo, stmt_vec_info stmt_vinfo, gimple *new_stmt,
1162 : : gimple_stmt_iterator *gsi)
1163 : : {
1164 : 6250 : if (gsi)
1165 : 2992 : vect_finish_stmt_generation (vinfo, stmt_vinfo, new_stmt, gsi);
1166 : : else
1167 : 3258 : vinfo->insert_on_entry (stmt_vinfo, new_stmt);
1168 : :
1169 : 6250 : if (dump_enabled_p ())
1170 : 1757 : dump_printf_loc (MSG_NOTE, vect_location,
1171 : : "created new init_stmt: %G", new_stmt);
1172 : 6250 : }
1173 : :
1174 : : /* Function vect_init_vector.
1175 : :
1176 : : Insert a new stmt (INIT_STMT) that initializes a new variable of type
1177 : : TYPE with the value VAL. If TYPE is a vector type and VAL does not have
1178 : : vector type a vector with all elements equal to VAL is created first.
1179 : : Place the initialization at GSI if it is not NULL. Otherwise, place the
1180 : : initialization at the loop preheader.
1181 : : Return the DEF of INIT_STMT.
1182 : : It will be used in the vectorization of STMT_INFO. */
1183 : :
1184 : : tree
1185 : 4534 : vect_init_vector (vec_info *vinfo, stmt_vec_info stmt_info, tree val, tree type,
1186 : : gimple_stmt_iterator *gsi)
1187 : : {
1188 : 4534 : gimple *init_stmt;
1189 : 4534 : tree new_temp;
1190 : :
1191 : : /* We abuse this function to push sth to a SSA name with initial 'val'. */
1192 : 4534 : if (! useless_type_conversion_p (type, TREE_TYPE (val)))
1193 : : {
1194 : 1324 : gcc_assert (VECTOR_TYPE_P (type));
1195 : 1324 : if (! types_compatible_p (TREE_TYPE (type), TREE_TYPE (val)))
1196 : : {
1197 : : /* Scalar boolean value should be transformed into
1198 : : all zeros or all ones value before building a vector. */
1199 : 8 : if (VECTOR_BOOLEAN_TYPE_P (type))
1200 : : {
1201 : 0 : tree true_val = build_all_ones_cst (TREE_TYPE (type));
1202 : 0 : tree false_val = build_zero_cst (TREE_TYPE (type));
1203 : :
1204 : 0 : if (CONSTANT_CLASS_P (val))
1205 : 0 : val = integer_zerop (val) ? false_val : true_val;
1206 : : else
1207 : : {
1208 : 0 : new_temp = make_ssa_name (TREE_TYPE (type));
1209 : 0 : init_stmt = gimple_build_assign (new_temp, COND_EXPR,
1210 : : val, true_val, false_val);
1211 : 0 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1212 : 0 : val = new_temp;
1213 : : }
1214 : : }
1215 : : else
1216 : : {
1217 : 8 : gimple_seq stmts = NULL;
1218 : 8 : if (! INTEGRAL_TYPE_P (TREE_TYPE (val)))
1219 : 8 : val = gimple_build (&stmts, VIEW_CONVERT_EXPR,
1220 : 8 : TREE_TYPE (type), val);
1221 : : else
1222 : : /* ??? Condition vectorization expects us to do
1223 : : promotion of invariant/external defs. */
1224 : 0 : val = gimple_convert (&stmts, TREE_TYPE (type), val);
1225 : 16 : for (gimple_stmt_iterator gsi2 = gsi_start (stmts);
1226 : 16 : !gsi_end_p (gsi2); )
1227 : : {
1228 : 8 : init_stmt = gsi_stmt (gsi2);
1229 : 8 : gsi_remove (&gsi2, false);
1230 : 8 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1231 : : }
1232 : : }
1233 : : }
1234 : 1324 : val = build_vector_from_val (type, val);
1235 : : }
1236 : :
1237 : 4534 : new_temp = vect_get_new_ssa_name (type, vect_simple_var, "cst_");
1238 : 4534 : init_stmt = gimple_build_assign (new_temp, val);
1239 : 4534 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, gsi);
1240 : 4534 : return new_temp;
1241 : : }
1242 : :
1243 : :
1244 : : /* Get vectorized definitions for OP0 and OP1. */
1245 : :
1246 : : void
1247 : 184116 : vect_get_vec_defs (vec_info *, slp_tree slp_node,
1248 : : tree op0, vec<tree> *vec_oprnds0,
1249 : : tree op1, vec<tree> *vec_oprnds1,
1250 : : tree op2, vec<tree> *vec_oprnds2,
1251 : : tree op3, vec<tree> *vec_oprnds3)
1252 : : {
1253 : 184116 : if (op0)
1254 : 182479 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_oprnds0);
1255 : 184116 : if (op1)
1256 : 137400 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[1], vec_oprnds1);
1257 : 184116 : if (op2)
1258 : 9192 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[2], vec_oprnds2);
1259 : 184116 : if (op3)
1260 : 0 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[3], vec_oprnds3);
1261 : 184116 : }
1262 : :
1263 : : /* Helper function called by vect_finish_replace_stmt and
1264 : : vect_finish_stmt_generation. Set the location of the new
1265 : : statement and create and return a stmt_vec_info for it. */
1266 : :
1267 : : static void
1268 : 1341623 : vect_finish_stmt_generation_1 (vec_info *,
1269 : : stmt_vec_info stmt_info, gimple *vec_stmt)
1270 : : {
1271 : 1341623 : if (dump_enabled_p ())
1272 : 140364 : dump_printf_loc (MSG_NOTE, vect_location, "add new stmt: %G", vec_stmt);
1273 : :
1274 : 1341623 : if (stmt_info)
1275 : : {
1276 : 1311353 : gimple_set_location (vec_stmt, gimple_location (stmt_info->stmt));
1277 : :
1278 : : /* While EH edges will generally prevent vectorization, stmt might
1279 : : e.g. be in a must-not-throw region. Ensure newly created stmts
1280 : : that could throw are part of the same region. */
1281 : 1311353 : int lp_nr = lookup_stmt_eh_lp (stmt_info->stmt);
1282 : 1311353 : if (lp_nr != 0 && stmt_could_throw_p (cfun, vec_stmt))
1283 : 48 : add_stmt_to_eh_lp (vec_stmt, lp_nr);
1284 : : }
1285 : : else
1286 : 30270 : gcc_assert (!stmt_could_throw_p (cfun, vec_stmt));
1287 : 1341623 : }
1288 : :
1289 : : /* Replace the scalar statement STMT_INFO with a new vector statement VEC_STMT,
1290 : : which sets the same scalar result as STMT_INFO did. Create and return a
1291 : : stmt_vec_info for VEC_STMT. */
1292 : :
1293 : : void
1294 : 830 : vect_finish_replace_stmt (vec_info *vinfo,
1295 : : stmt_vec_info stmt_info, gimple *vec_stmt)
1296 : : {
1297 : 830 : gimple *scalar_stmt = vect_orig_stmt (stmt_info)->stmt;
1298 : 830 : gcc_assert (gimple_get_lhs (scalar_stmt) == gimple_get_lhs (vec_stmt));
1299 : :
1300 : 830 : gimple_stmt_iterator gsi = gsi_for_stmt (scalar_stmt);
1301 : 830 : gsi_replace (&gsi, vec_stmt, true);
1302 : :
1303 : 830 : vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt);
1304 : 830 : }
1305 : :
1306 : : /* Add VEC_STMT to the vectorized implementation of STMT_INFO and insert it
1307 : : before *GSI. Create and return a stmt_vec_info for VEC_STMT. */
1308 : :
1309 : : void
1310 : 1340793 : vect_finish_stmt_generation (vec_info *vinfo,
1311 : : stmt_vec_info stmt_info, gimple *vec_stmt,
1312 : : gimple_stmt_iterator *gsi)
1313 : : {
1314 : 1340793 : gcc_assert (!stmt_info || gimple_code (stmt_info->stmt) != GIMPLE_LABEL);
1315 : :
1316 : 1340793 : if (!gsi_end_p (*gsi)
1317 : 2680573 : && gimple_has_mem_ops (vec_stmt))
1318 : : {
1319 : 1339780 : gimple *at_stmt = gsi_stmt (*gsi);
1320 : 1339780 : tree vuse = gimple_vuse (at_stmt);
1321 : 1333648 : if (vuse && TREE_CODE (vuse) == SSA_NAME)
1322 : : {
1323 : 1194293 : tree vdef = gimple_vdef (at_stmt);
1324 : 1194293 : gimple_set_vuse (vec_stmt, gimple_vuse (at_stmt));
1325 : 1194293 : gimple_set_modified (vec_stmt, true);
1326 : : /* If we have an SSA vuse and insert a store, update virtual
1327 : : SSA form to avoid triggering the renamer. Do so only
1328 : : if we can easily see all uses - which is what almost always
1329 : : happens with the way vectorized stmts are inserted. */
1330 : 747673 : if ((vdef && TREE_CODE (vdef) == SSA_NAME)
1331 : 1941930 : && ((is_gimple_assign (vec_stmt)
1332 : 746812 : && !is_gimple_reg (gimple_assign_lhs (vec_stmt)))
1333 : 63138 : || (is_gimple_call (vec_stmt)
1334 : 825 : && (!(gimple_call_flags (vec_stmt)
1335 : 825 : & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
1336 : 1 : || (gimple_call_lhs (vec_stmt)
1337 : 1 : && !is_gimple_reg (gimple_call_lhs (vec_stmt)))))))
1338 : : {
1339 : 685323 : tree new_vdef = copy_ssa_name (vuse, vec_stmt);
1340 : 685323 : gimple_set_vdef (vec_stmt, new_vdef);
1341 : 685323 : SET_USE (gimple_vuse_op (at_stmt), new_vdef);
1342 : : }
1343 : : }
1344 : : }
1345 : 1340793 : gsi_insert_before (gsi, vec_stmt, GSI_SAME_STMT);
1346 : 1340793 : vect_finish_stmt_generation_1 (vinfo, stmt_info, vec_stmt);
1347 : 1340793 : }
1348 : :
1349 : : /* We want to vectorize a call to combined function CFN with function
1350 : : decl FNDECL, using VECTYPE_OUT as the type of the output and VECTYPE_IN
1351 : : as the types of all inputs. Check whether this is possible using
1352 : : an internal function, returning its code if so or IFN_LAST if not. */
1353 : :
1354 : : static internal_fn
1355 : 12086 : vectorizable_internal_function (combined_fn cfn, tree fndecl,
1356 : : tree vectype_out, tree vectype_in)
1357 : : {
1358 : 12086 : internal_fn ifn;
1359 : 12086 : if (internal_fn_p (cfn))
1360 : 9675 : ifn = as_internal_fn (cfn);
1361 : : else
1362 : 2411 : ifn = associated_internal_fn (fndecl);
1363 : 12086 : if (ifn != IFN_LAST && direct_internal_fn_p (ifn))
1364 : : {
1365 : 8642 : const direct_internal_fn_info &info = direct_internal_fn (ifn);
1366 : 8642 : if (info.vectorizable)
1367 : : {
1368 : 8642 : bool same_size_p = TYPE_SIZE (vectype_in) == TYPE_SIZE (vectype_out);
1369 : 8642 : tree type0 = (info.type0 < 0 ? vectype_out : vectype_in);
1370 : 8642 : tree type1 = (info.type1 < 0 ? vectype_out : vectype_in);
1371 : :
1372 : : /* The type size of both the vectype_in and vectype_out should be
1373 : : exactly the same when vectype_out isn't participating the optab.
1374 : : While there is no restriction for type size when vectype_out
1375 : : is part of the optab query. */
1376 : 8642 : if (type0 != vectype_out && type1 != vectype_out && !same_size_p)
1377 : : return IFN_LAST;
1378 : :
1379 : 8622 : if (direct_internal_fn_supported_p (ifn, tree_pair (type0, type1),
1380 : : OPTIMIZE_FOR_SPEED))
1381 : : return ifn;
1382 : : }
1383 : : }
1384 : : return IFN_LAST;
1385 : : }
1386 : :
1387 : :
1388 : : static tree permute_vec_elements (vec_info *, tree, tree, tree, stmt_vec_info,
1389 : : gimple_stmt_iterator *);
1390 : :
1391 : : /* Check whether a load or store statement in the loop described by
1392 : : LOOP_VINFO is possible in a loop using partial vectors. This is
1393 : : testing whether the vectorizer pass has the appropriate support,
1394 : : as well as whether the target does.
1395 : :
1396 : : VLS_TYPE says whether the statement is a load or store and VECTYPE
1397 : : is the type of the vector being loaded or stored. SLP_NODE is the SLP
1398 : : node that contains the statement, or null if none. MEMORY_ACCESS_TYPE
1399 : : says how the load or store is going to be implemented and GROUP_SIZE
1400 : : is the number of load or store statements in the containing group.
1401 : : If the access is a gather load or scatter store, GS_INFO describes
1402 : : its arguments. If the load or store is conditional, SCALAR_MASK is the
1403 : : condition under which it occurs.
1404 : :
1405 : : Clear LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P if a loop using partial
1406 : : vectors is not supported, otherwise record the required rgroup control
1407 : : types.
1408 : :
1409 : : If partial vectors can be used and ELSVALS is nonzero the supported
1410 : : else values will be added to the vector ELSVALS points to. */
1411 : :
1412 : : static void
1413 : 231448 : check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype,
1414 : : slp_tree slp_node,
1415 : : vec_load_store_type vls_type,
1416 : : int group_size,
1417 : : vect_load_store_data *ls,
1418 : : slp_tree mask_node,
1419 : : vec<int> *elsvals = nullptr)
1420 : : {
1421 : 231448 : vect_memory_access_type memory_access_type = ls->memory_access_type;
1422 : :
1423 : : /* Invariant loads need no special support. */
1424 : 231448 : if (memory_access_type == VMAT_INVARIANT)
1425 : 31280 : return;
1426 : :
1427 : : /* Figure whether the mask is uniform. scalar_mask is used to
1428 : : populate the scalar_cond_masked_set. */
1429 : 230049 : tree scalar_mask = NULL_TREE;
1430 : 230049 : if (mask_node)
1431 : 3448 : for (unsigned i = 0; i < SLP_TREE_LANES (mask_node); ++i)
1432 : : {
1433 : 1740 : tree def = vect_get_slp_scalar_def (mask_node, i);
1434 : 1740 : if (!def
1435 : 1740 : || (scalar_mask && def != scalar_mask))
1436 : : {
1437 : : scalar_mask = NULL;
1438 : : break;
1439 : : }
1440 : : else
1441 : 1724 : scalar_mask = def;
1442 : : }
1443 : :
1444 : 230049 : unsigned int nvectors = vect_get_num_copies (loop_vinfo, slp_node);
1445 : 230049 : vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
1446 : 230049 : vec_loop_lens *lens = &LOOP_VINFO_LENS (loop_vinfo);
1447 : 230049 : machine_mode vecmode = TYPE_MODE (vectype);
1448 : 230049 : bool is_load = (vls_type == VLS_LOAD);
1449 : 230049 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
1450 : : {
1451 : 0 : nvectors /= group_size;
1452 : 0 : internal_fn ifn
1453 : 0 : = (is_load ? vect_load_lanes_supported (vectype, group_size, true,
1454 : : elsvals)
1455 : 0 : : vect_store_lanes_supported (vectype, group_size, true));
1456 : 0 : if (ifn == IFN_MASK_LEN_LOAD_LANES || ifn == IFN_MASK_LEN_STORE_LANES)
1457 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1);
1458 : 0 : else if (ifn == IFN_MASK_LOAD_LANES || ifn == IFN_MASK_STORE_LANES)
1459 : 0 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
1460 : : scalar_mask);
1461 : : else
1462 : : {
1463 : 0 : if (dump_enabled_p ())
1464 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1465 : : "can't operate on partial vectors because"
1466 : : " the target doesn't have an appropriate"
1467 : : " load/store-lanes instruction.\n");
1468 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1469 : : }
1470 : 0 : return;
1471 : : }
1472 : :
1473 : 230049 : if (mat_gather_scatter_p (memory_access_type))
1474 : : {
1475 : 1443 : internal_fn ifn = (is_load
1476 : 1443 : ? IFN_MASK_GATHER_LOAD
1477 : : : IFN_MASK_SCATTER_STORE);
1478 : 334 : internal_fn len_ifn = (is_load
1479 : : ? IFN_MASK_LEN_GATHER_LOAD
1480 : : : IFN_MASK_LEN_SCATTER_STORE);
1481 : 1443 : stmt_vec_info repr = SLP_TREE_REPRESENTATIVE (slp_node);
1482 : 1443 : tree off_vectype = (STMT_VINFO_GATHER_SCATTER_P (repr)
1483 : 1443 : ? SLP_TREE_VECTYPE (SLP_TREE_CHILDREN (slp_node)[0])
1484 : 1443 : : ls->strided_offset_vectype);
1485 : 1443 : tree memory_type = TREE_TYPE (DR_REF (STMT_VINFO_DR_INFO (repr)->dr));
1486 : 1443 : int scale = SLP_TREE_GS_SCALE (slp_node);
1487 : :
1488 : : /* The following "supported" checks just verify what we established in
1489 : : get_load_store_type and don't try different offset types.
1490 : : Therefore, off_vectype must be a supported offset type. In case
1491 : : we chose a different one use this instead. */
1492 : 1443 : if (ls->supported_offset_vectype)
1493 : 0 : off_vectype = ls->supported_offset_vectype;
1494 : : /* Same for scale. */
1495 : 1443 : if (ls->supported_scale)
1496 : 0 : scale = ls->supported_scale;
1497 : :
1498 : 1443 : if (internal_gather_scatter_fn_supported_p (len_ifn, vectype,
1499 : : memory_type,
1500 : : off_vectype, scale,
1501 : : elsvals))
1502 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1);
1503 : 1443 : else if (internal_gather_scatter_fn_supported_p (ifn, vectype,
1504 : : memory_type,
1505 : : off_vectype, scale,
1506 : : elsvals)
1507 : 1443 : || memory_access_type == VMAT_GATHER_SCATTER_LEGACY)
1508 : 339 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
1509 : : scalar_mask);
1510 : : else
1511 : : {
1512 : 1104 : if (dump_enabled_p ())
1513 : 22 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1514 : : "can't operate on partial vectors because"
1515 : : " the target doesn't have an appropriate"
1516 : : " gather load or scatter store instruction.\n");
1517 : 1104 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1518 : : }
1519 : 1443 : return;
1520 : : }
1521 : :
1522 : 228606 : if (memory_access_type != VMAT_CONTIGUOUS)
1523 : : {
1524 : : /* Element X of the data must come from iteration i * VF + X of the
1525 : : scalar loop. We need more work to support other mappings. */
1526 : 28438 : if (dump_enabled_p ())
1527 : 719 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1528 : : "can't operate on partial vectors because an"
1529 : : " access isn't contiguous.\n");
1530 : 28438 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1531 : 28438 : return;
1532 : : }
1533 : :
1534 : 200168 : if (!VECTOR_MODE_P (vecmode))
1535 : : {
1536 : 0 : if (dump_enabled_p ())
1537 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1538 : : "can't operate on partial vectors when emulating"
1539 : : " vector operations.\n");
1540 : 0 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1541 : 0 : return;
1542 : : }
1543 : :
1544 : : /* We might load more scalars than we need for permuting SLP loads.
1545 : : We checked in get_load_store_type that the extra elements
1546 : : don't leak into a new vector. */
1547 : 265917 : auto group_memory_nvectors = [](poly_uint64 size, poly_uint64 nunits)
1548 : : {
1549 : 65749 : unsigned int nvectors;
1550 : 131498 : if (can_div_away_from_zero_p (size, nunits, &nvectors))
1551 : 65749 : return nvectors;
1552 : : gcc_unreachable ();
1553 : : };
1554 : :
1555 : 200168 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
1556 : 200168 : poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
1557 : 200168 : machine_mode mask_mode;
1558 : 200168 : machine_mode vmode;
1559 : 200168 : bool using_partial_vectors_p = false;
1560 : 200168 : if (get_len_load_store_mode
1561 : 200168 : (vecmode, is_load, nullptr, elsvals).exists (&vmode))
1562 : : {
1563 : 0 : nvectors = group_memory_nvectors (group_size * vf, nunits);
1564 : 0 : unsigned factor = (vecmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vecmode);
1565 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, factor);
1566 : 0 : using_partial_vectors_p = true;
1567 : : }
1568 : 265917 : else if (targetm.vectorize.get_mask_mode (vecmode).exists (&mask_mode)
1569 : 200168 : && can_vec_mask_load_store_p (vecmode, mask_mode, is_load, NULL,
1570 : : elsvals))
1571 : : {
1572 : 65749 : nvectors = group_memory_nvectors (group_size * vf, nunits);
1573 : 65749 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, scalar_mask);
1574 : 65749 : using_partial_vectors_p = true;
1575 : : }
1576 : :
1577 : 65749 : if (!using_partial_vectors_p)
1578 : : {
1579 : 134419 : if (dump_enabled_p ())
1580 : 10922 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1581 : : "can't operate on partial vectors because the"
1582 : : " target doesn't have the appropriate partial"
1583 : : " vectorization load or store.\n");
1584 : 134419 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
1585 : : }
1586 : : }
1587 : :
1588 : : /* Return the mask input to a masked load or store. VEC_MASK is the vectorized
1589 : : form of the scalar mask condition and LOOP_MASK, if nonnull, is the mask
1590 : : that needs to be applied to all loads and stores in a vectorized loop.
1591 : : Return VEC_MASK if LOOP_MASK is null or if VEC_MASK is already masked,
1592 : : otherwise return VEC_MASK & LOOP_MASK.
1593 : :
1594 : : MASK_TYPE is the type of both masks. If new statements are needed,
1595 : : insert them before GSI. */
1596 : :
1597 : : tree
1598 : 1580 : prepare_vec_mask (loop_vec_info loop_vinfo, tree mask_type, tree loop_mask,
1599 : : tree vec_mask, gimple_stmt_iterator *gsi)
1600 : : {
1601 : 1580 : gcc_assert (useless_type_conversion_p (mask_type, TREE_TYPE (vec_mask)));
1602 : 1580 : if (!loop_mask)
1603 : : return vec_mask;
1604 : :
1605 : 139 : gcc_assert (TREE_TYPE (loop_mask) == mask_type);
1606 : :
1607 : 139 : if (loop_vinfo->vec_cond_masked_set.contains ({ vec_mask, loop_mask }))
1608 : : return vec_mask;
1609 : :
1610 : 139 : tree and_res = make_temp_ssa_name (mask_type, NULL, "vec_mask_and");
1611 : 139 : gimple *and_stmt = gimple_build_assign (and_res, BIT_AND_EXPR,
1612 : : vec_mask, loop_mask);
1613 : :
1614 : 139 : gsi_insert_before (gsi, and_stmt, GSI_SAME_STMT);
1615 : 139 : return and_res;
1616 : : }
1617 : :
1618 : : /* Determine whether we can use a gather load or scatter store to vectorize
1619 : : strided load or store STMT_INFO by truncating the current offset to a
1620 : : smaller width. We need to be able to construct an offset vector:
1621 : :
1622 : : { 0, X, X*2, X*3, ... }
1623 : :
1624 : : without loss of precision, where X is STMT_INFO's DR_STEP.
1625 : :
1626 : : Return true if this is possible, describing the gather load or scatter
1627 : : store in GS_INFO. MASKED_P is true if the load or store is conditional.
1628 : :
1629 : : If we can use gather/scatter and ELSVALS is nonzero the supported
1630 : : else values will be stored in the vector ELSVALS points to. */
1631 : :
1632 : : static bool
1633 : 60736 : vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info, tree vectype,
1634 : : loop_vec_info loop_vinfo, bool masked_p,
1635 : : gather_scatter_info *gs_info,
1636 : : vec<int> *elsvals)
1637 : : {
1638 : 60736 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1639 : 60736 : data_reference *dr = dr_info->dr;
1640 : 60736 : tree step = DR_STEP (dr);
1641 : 60736 : if (TREE_CODE (step) != INTEGER_CST)
1642 : : {
1643 : : /* ??? Perhaps we could use range information here? */
1644 : 30353 : if (dump_enabled_p ())
1645 : 229 : dump_printf_loc (MSG_NOTE, vect_location,
1646 : : "cannot truncate variable step.\n");
1647 : 30353 : return false;
1648 : : }
1649 : :
1650 : : /* Get the number of bits in an element. */
1651 : 30383 : scalar_mode element_mode = SCALAR_TYPE_MODE (TREE_TYPE (vectype));
1652 : 30383 : unsigned int element_bits = GET_MODE_BITSIZE (element_mode);
1653 : :
1654 : : /* Set COUNT to the upper limit on the number of elements - 1.
1655 : : Start with the maximum vectorization factor. */
1656 : 30383 : unsigned HOST_WIDE_INT count = vect_max_vf (loop_vinfo) - 1;
1657 : :
1658 : : /* Try lowering COUNT to the number of scalar latch iterations. */
1659 : 30383 : class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
1660 : 30383 : widest_int max_iters;
1661 : 30383 : if (max_loop_iterations (loop, &max_iters)
1662 : 60766 : && max_iters < count)
1663 : 2344 : count = max_iters.to_shwi ();
1664 : :
1665 : : /* Try scales of 1 and the element size. */
1666 : 30383 : unsigned int scales[] = { 1, vect_get_scalar_dr_size (dr_info) };
1667 : 30383 : wi::overflow_type overflow = wi::OVF_NONE;
1668 : 91149 : for (int i = 0; i < 2; ++i)
1669 : : {
1670 : 60766 : unsigned int scale = scales[i];
1671 : 60766 : widest_int factor;
1672 : 60766 : if (!wi::multiple_of_p (wi::to_widest (step), scale, SIGNED, &factor))
1673 : 0 : continue;
1674 : :
1675 : : /* Determine the minimum precision of (COUNT - 1) * STEP / SCALE. */
1676 : 60766 : widest_int range = wi::mul (count, factor, SIGNED, &overflow);
1677 : 60766 : if (overflow)
1678 : 0 : continue;
1679 : 60766 : signop sign = range >= 0 ? UNSIGNED : SIGNED;
1680 : 60766 : unsigned int min_offset_bits = wi::min_precision (range, sign);
1681 : :
1682 : : /* Find the narrowest viable offset type. */
1683 : 60766 : unsigned int offset_bits = 1U << ceil_log2 (min_offset_bits);
1684 : 60766 : tree offset_type = build_nonstandard_integer_type (offset_bits,
1685 : : sign == UNSIGNED);
1686 : :
1687 : : /* See whether the target supports the operation with an offset
1688 : : no narrower than OFFSET_TYPE. */
1689 : 60766 : tree memory_type = TREE_TYPE (DR_REF (dr));
1690 : 60766 : tree tmp_offset_vectype;
1691 : 60766 : int tmp_scale;
1692 : 60766 : if (!vect_gather_scatter_fn_p (loop_vinfo, DR_IS_READ (dr), masked_p,
1693 : : vectype, memory_type, offset_type,
1694 : : scale, &tmp_scale,
1695 : : &gs_info->ifn, &gs_info->offset_vectype,
1696 : : &tmp_offset_vectype, elsvals)
1697 : 60766 : || gs_info->ifn == IFN_LAST)
1698 : 60766 : continue;
1699 : :
1700 : 0 : gs_info->decl = NULL_TREE;
1701 : : /* Logically the sum of DR_BASE_ADDRESS, DR_INIT and DR_OFFSET,
1702 : : but we don't need to store that here. */
1703 : 0 : gs_info->base = NULL_TREE;
1704 : 0 : gs_info->alias_ptr = build_int_cst
1705 : 0 : (reference_alias_ptr_type (DR_REF (dr)),
1706 : 0 : get_object_alignment (DR_REF (dr)));
1707 : 0 : gs_info->element_type = TREE_TYPE (vectype);
1708 : 0 : gs_info->offset = fold_convert (offset_type, step);
1709 : 0 : gs_info->scale = scale;
1710 : 0 : gs_info->memory_type = memory_type;
1711 : 0 : return true;
1712 : 121532 : }
1713 : :
1714 : 30383 : if (overflow && dump_enabled_p ())
1715 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1716 : : "truncating gather/scatter offset to %d bits"
1717 : : " might change its value.\n", element_bits);
1718 : :
1719 : : return false;
1720 : 30383 : }
1721 : :
1722 : : /* Return true if we can use gather/scatter or strided internal functions
1723 : : to vectorize STMT_INFO, which is a grouped or strided load or store
1724 : : with multiple lanes and will be implemented by a type-punned access
1725 : : of a vector with element size that matches the number of lanes.
1726 : :
1727 : : MASKED_P is true if load or store is conditional.
1728 : : When returning true, fill in GS_INFO with the information required to
1729 : : perform the operation. Also, store the punning type in PUNNED_VECTYPE.
1730 : :
1731 : : If successful and ELSVALS is nonzero the supported
1732 : : else values will be stored in the vector ELSVALS points to. */
1733 : :
1734 : : static bool
1735 : 3646 : vect_use_grouped_gather (dr_vec_info *dr_info, tree vectype,
1736 : : loop_vec_info loop_vinfo, bool masked_p,
1737 : : unsigned int nelts,
1738 : : gather_scatter_info *info, vec<int> *elsvals,
1739 : : tree *pun_vectype)
1740 : : {
1741 : 3646 : data_reference *dr = dr_info->dr;
1742 : :
1743 : : /* TODO: We can support nelts > BITS_PER_UNIT or non-power-of-two by
1744 : : multiple gathers/scatter. */
1745 : 6994 : if (nelts > BITS_PER_UNIT || !pow2p_hwi (nelts))
1746 : : return false;
1747 : :
1748 : : /* Pun the vectype with one of the same size but an element spanning
1749 : : NELTS elements of VECTYPE.
1750 : : The punned type of a V16QI with NELTS = 4 would be V4SI.
1751 : : */
1752 : 3111 : tree tmp;
1753 : 3111 : unsigned int pieces;
1754 : 3111 : if (!can_div_trunc_p (TYPE_VECTOR_SUBPARTS (vectype), nelts, &pieces)
1755 : 3111 : || !pieces)
1756 : 221 : return false;
1757 : :
1758 : 2890 : *pun_vectype = vector_vector_composition_type (vectype, pieces, &tmp, true);
1759 : :
1760 : 2890 : if (!*pun_vectype || !VECTOR_TYPE_P (*pun_vectype))
1761 : : return false;
1762 : :
1763 : 2518 : internal_fn ifn;
1764 : 2518 : tree offset_vectype = *pun_vectype;
1765 : :
1766 : 1611 : internal_fn strided_ifn = DR_IS_READ (dr)
1767 : 2518 : ? IFN_MASK_LEN_STRIDED_LOAD : IFN_MASK_LEN_STRIDED_STORE;
1768 : :
1769 : : /* Check if we have a gather/scatter with the new type. We're just trying
1770 : : with the type itself as offset for now. If not, check if we have a
1771 : : strided load/store. These have fewer constraints (for example no offset
1772 : : type must exist) so it is possible that even though a gather/scatter is
1773 : : not available we still have a strided load/store. */
1774 : 2518 : bool ok = false;
1775 : 2518 : tree tmp_vectype;
1776 : 2518 : int tmp_scale;
1777 : 2518 : if (vect_gather_scatter_fn_p
1778 : 2518 : (loop_vinfo, DR_IS_READ (dr), masked_p, *pun_vectype,
1779 : 2518 : TREE_TYPE (*pun_vectype), *pun_vectype, 1, &tmp_scale, &ifn,
1780 : : &offset_vectype, &tmp_vectype, elsvals))
1781 : : ok = true;
1782 : 2518 : else if (internal_strided_fn_supported_p (strided_ifn, *pun_vectype,
1783 : : elsvals))
1784 : : {
1785 : : /* Use gather/scatter IFNs, vect_get_strided_load_store_ops
1786 : : will switch back to the strided variants. */
1787 : 0 : ifn = DR_IS_READ (dr) ? IFN_MASK_LEN_GATHER_LOAD :
1788 : : IFN_MASK_LEN_SCATTER_STORE;
1789 : 0 : ok = true;
1790 : : }
1791 : :
1792 : 0 : if (ok)
1793 : : {
1794 : 0 : info->ifn = ifn;
1795 : 0 : info->decl = NULL_TREE;
1796 : 0 : info->base = dr->ref;
1797 : 0 : info->alias_ptr = build_int_cst
1798 : 0 : (reference_alias_ptr_type (DR_REF (dr)),
1799 : 0 : get_object_alignment (DR_REF (dr)));
1800 : 0 : info->element_type = TREE_TYPE (*pun_vectype);
1801 : 0 : info->offset_vectype = offset_vectype;
1802 : : /* No need to set the offset, vect_get_strided_load_store_ops
1803 : : will do that. */
1804 : 0 : info->scale = 1;
1805 : 0 : info->memory_type = TREE_TYPE (DR_REF (dr));
1806 : 0 : return true;
1807 : : }
1808 : :
1809 : : return false;
1810 : : }
1811 : :
1812 : :
1813 : : /* Return true if we can use gather/scatter internal functions to
1814 : : vectorize STMT_INFO, which is a grouped or strided load or store.
1815 : : MASKED_P is true if load or store is conditional. When returning
1816 : : true, fill in GS_INFO with the information required to perform the
1817 : : operation.
1818 : :
1819 : : If we can use gather/scatter and ELSVALS is nonzero the supported
1820 : : else values will be stored in the vector ELSVALS points to. */
1821 : :
1822 : : static bool
1823 : 60736 : vect_use_strided_gather_scatters_p (stmt_vec_info stmt_info, tree vectype,
1824 : : loop_vec_info loop_vinfo, bool masked_p,
1825 : : gather_scatter_info *gs_info,
1826 : : vec<int> *elsvals,
1827 : : unsigned int group_size,
1828 : : bool single_element_p)
1829 : : {
1830 : 60736 : if (!vect_check_gather_scatter (stmt_info, vectype,
1831 : : loop_vinfo, gs_info, elsvals)
1832 : 60736 : || gs_info->ifn == IFN_LAST)
1833 : : {
1834 : 60736 : if (!vect_truncate_gather_scatter_offset (stmt_info, vectype, loop_vinfo,
1835 : : masked_p, gs_info, elsvals))
1836 : : return false;
1837 : : }
1838 : :
1839 : 0 : if (!single_element_p
1840 : 0 : && !targetm.vectorize.prefer_gather_scatter (TYPE_MODE (vectype),
1841 : : gs_info->scale,
1842 : : group_size))
1843 : : return false;
1844 : :
1845 : 0 : if (dump_enabled_p ())
1846 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
1847 : : "using gather/scatter for strided/grouped access,"
1848 : : " scale = %d\n", gs_info->scale);
1849 : :
1850 : : return true;
1851 : : }
1852 : :
1853 : : /* STMT_INFO is a non-strided load or store, meaning that it accesses
1854 : : elements with a known constant step. Return -1 if that step
1855 : : is negative, 0 if it is zero, and 1 if it is greater than zero. */
1856 : :
1857 : : int
1858 : 1347500 : compare_step_with_zero (vec_info *vinfo, stmt_vec_info stmt_info)
1859 : : {
1860 : 1347500 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1861 : 1347500 : return tree_int_cst_compare (vect_dr_behavior (vinfo, dr_info)->step,
1862 : 1347500 : size_zero_node);
1863 : : }
1864 : :
1865 : : /* If the target supports a permute mask that reverses the elements in
1866 : : a vector of type VECTYPE, return that mask, otherwise return null. */
1867 : :
1868 : : tree
1869 : 8873 : perm_mask_for_reverse (tree vectype)
1870 : : {
1871 : 8873 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
1872 : :
1873 : : /* The encoding has a single stepped pattern. */
1874 : 8873 : vec_perm_builder sel (nunits, 1, 3);
1875 : 35492 : for (int i = 0; i < 3; ++i)
1876 : 26619 : sel.quick_push (nunits - 1 - i);
1877 : :
1878 : 8873 : vec_perm_indices indices (sel, 1, nunits);
1879 : 8873 : if (!can_vec_perm_const_p (TYPE_MODE (vectype), TYPE_MODE (vectype),
1880 : : indices))
1881 : : return NULL_TREE;
1882 : 7727 : return vect_gen_perm_mask_checked (vectype, indices);
1883 : 8873 : }
1884 : :
1885 : : /* A subroutine of get_load_store_type, with a subset of the same
1886 : : arguments. Handle the case where STMT_INFO is a load or store that
1887 : : accesses consecutive elements with a negative step. Sets *POFFSET
1888 : : to the offset to be applied to the DR for the first access. */
1889 : :
1890 : : static vect_memory_access_type
1891 : 10432 : get_negative_load_store_type (vec_info *vinfo,
1892 : : stmt_vec_info stmt_info, tree vectype,
1893 : : vec_load_store_type vls_type,
1894 : : unsigned int ncopies, poly_int64 *poffset)
1895 : : {
1896 : 10432 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
1897 : 10432 : dr_alignment_support alignment_support_scheme;
1898 : :
1899 : 10432 : if (ncopies > 1)
1900 : : {
1901 : 0 : if (dump_enabled_p ())
1902 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1903 : : "multiple types with negative step.\n");
1904 : 0 : return VMAT_ELEMENTWISE;
1905 : : }
1906 : :
1907 : : /* For backward running DRs the first access in vectype actually is
1908 : : N-1 elements before the address of the DR. */
1909 : 10432 : *poffset = ((-TYPE_VECTOR_SUBPARTS (vectype) + 1)
1910 : 10432 : * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype))));
1911 : :
1912 : 10432 : int misalignment = dr_misalignment (dr_info, vectype, *poffset);
1913 : 10432 : alignment_support_scheme
1914 : 10432 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype, misalignment);
1915 : 10432 : if (alignment_support_scheme != dr_aligned
1916 : 10432 : && alignment_support_scheme != dr_unaligned_supported)
1917 : : {
1918 : 3388 : if (dump_enabled_p ())
1919 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1920 : : "negative step but alignment required.\n");
1921 : 3388 : *poffset = 0;
1922 : 3388 : return VMAT_ELEMENTWISE;
1923 : : }
1924 : :
1925 : 7044 : if (vls_type == VLS_STORE_INVARIANT)
1926 : : {
1927 : 711 : if (dump_enabled_p ())
1928 : 21 : dump_printf_loc (MSG_NOTE, vect_location,
1929 : : "negative step with invariant source;"
1930 : : " no permute needed.\n");
1931 : 711 : return VMAT_CONTIGUOUS_DOWN;
1932 : : }
1933 : :
1934 : 6333 : if (!perm_mask_for_reverse (vectype))
1935 : : {
1936 : 1146 : if (dump_enabled_p ())
1937 : 50 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1938 : : "negative step and reversing not supported.\n");
1939 : 1146 : *poffset = 0;
1940 : 1146 : return VMAT_ELEMENTWISE;
1941 : : }
1942 : :
1943 : : return VMAT_CONTIGUOUS_REVERSE;
1944 : : }
1945 : :
1946 : : /* STMT_INFO is either a masked or unconditional store. Return the value
1947 : : being stored. */
1948 : :
1949 : : tree
1950 : 0 : vect_get_store_rhs (stmt_vec_info stmt_info)
1951 : : {
1952 : 0 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
1953 : : {
1954 : 0 : gcc_assert (gimple_assign_single_p (assign));
1955 : 0 : return gimple_assign_rhs1 (assign);
1956 : : }
1957 : 0 : if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt))
1958 : : {
1959 : 0 : internal_fn ifn = gimple_call_internal_fn (call);
1960 : 0 : int index = internal_fn_stored_value_index (ifn);
1961 : 0 : gcc_assert (index >= 0);
1962 : 0 : return gimple_call_arg (call, index);
1963 : : }
1964 : 0 : gcc_unreachable ();
1965 : : }
1966 : :
1967 : : /* Function VECTOR_VECTOR_COMPOSITION_TYPE
1968 : :
1969 : : This function returns a vector type which can be composed with NELTS pieces,
1970 : : whose type is recorded in PTYPE. VTYPE should be a vector type, and has the
1971 : : same vector size as the return vector. It checks target whether supports
1972 : : pieces-size vector mode for construction firstly, if target fails to, check
1973 : : pieces-size scalar mode for construction further. It returns NULL_TREE if
1974 : : fails to find the available composition. If the caller only wants scalar
1975 : : pieces where PTYPE e.g. is a possible gather/scatter element type
1976 : : SCALAR_PTYPE_ONLY must be true.
1977 : :
1978 : : For example, for (vtype=V16QI, nelts=4), we can probably get:
1979 : : - V16QI with PTYPE V4QI.
1980 : : - V4SI with PTYPE SI.
1981 : : - NULL_TREE. */
1982 : :
1983 : : static tree
1984 : 12278 : vector_vector_composition_type (tree vtype, poly_uint64 nelts, tree *ptype,
1985 : : bool scalar_ptype_only)
1986 : : {
1987 : 12278 : gcc_assert (VECTOR_TYPE_P (vtype));
1988 : 12278 : gcc_assert (known_gt (nelts, 0U));
1989 : :
1990 : 12278 : machine_mode vmode = TYPE_MODE (vtype);
1991 : 12278 : if (!VECTOR_MODE_P (vmode))
1992 : : return NULL_TREE;
1993 : :
1994 : : /* When we are asked to compose the vector from its components let
1995 : : that happen directly. */
1996 : 12278 : if (known_eq (TYPE_VECTOR_SUBPARTS (vtype), nelts))
1997 : : {
1998 : 5144 : *ptype = TREE_TYPE (vtype);
1999 : 5144 : return vtype;
2000 : : }
2001 : :
2002 : 14268 : poly_uint64 vbsize = GET_MODE_BITSIZE (vmode);
2003 : 7134 : unsigned int pbsize;
2004 : 7134 : if (constant_multiple_p (vbsize, nelts, &pbsize))
2005 : : {
2006 : : /* First check if vec_init optab supports construction from
2007 : : vector pieces directly. */
2008 : 7134 : scalar_mode elmode = SCALAR_TYPE_MODE (TREE_TYPE (vtype));
2009 : 14268 : poly_uint64 inelts = pbsize / GET_MODE_BITSIZE (elmode);
2010 : 7134 : machine_mode rmode;
2011 : 7134 : if (!scalar_ptype_only
2012 : 4244 : && related_vector_mode (vmode, elmode, inelts).exists (&rmode)
2013 : 11000 : && (convert_optab_handler (vec_init_optab, vmode, rmode)
2014 : : != CODE_FOR_nothing))
2015 : : {
2016 : 3249 : *ptype = build_vector_type (TREE_TYPE (vtype), inelts);
2017 : 3249 : return vtype;
2018 : : }
2019 : :
2020 : : /* Otherwise check if exists an integer type of the same piece size and
2021 : : if vec_init optab supports construction from it directly. */
2022 : 3885 : if (int_mode_for_size (pbsize, 0).exists (&elmode)
2023 : 3885 : && related_vector_mode (vmode, elmode, nelts).exists (&rmode))
2024 : : {
2025 : 3477 : if (scalar_ptype_only
2026 : 3477 : || convert_optab_handler (vec_init_optab, rmode, elmode)
2027 : : != CODE_FOR_nothing)
2028 : : {
2029 : 3477 : *ptype = build_nonstandard_integer_type (pbsize, 1);
2030 : 3477 : return build_vector_type (*ptype, nelts);
2031 : : }
2032 : : }
2033 : : }
2034 : :
2035 : : return NULL_TREE;
2036 : : }
2037 : :
2038 : : /* Check if the load permutation of NODE only refers to a consecutive
2039 : : subset of the group indices where GROUP_SIZE is the size of the
2040 : : dataref's group. We also assert that the length of the permutation
2041 : : divides the group size and is a power of two.
2042 : : Such load permutations can be elided in strided access schemes as
2043 : : we can "jump over" the gap they leave. */
2044 : :
2045 : : bool
2046 : 46241 : has_consecutive_load_permutation (slp_tree node, unsigned group_size)
2047 : : {
2048 : 46241 : load_permutation_t perm = SLP_TREE_LOAD_PERMUTATION (node);
2049 : 46241 : if (!perm.exists ()
2050 : 1847 : || perm.length () <= 1
2051 : 419 : || !pow2p_hwi (perm.length ())
2052 : 46646 : || group_size % perm.length ())
2053 : : return false;
2054 : :
2055 : 362 : return vect_load_perm_consecutive_p (node);
2056 : : }
2057 : :
2058 : :
2059 : : /* Analyze load or store SLP_NODE of type VLS_TYPE. Return true
2060 : : if there is a memory access type that the vectorized form can use,
2061 : : storing it in *MEMORY_ACCESS_TYPE if so. If we decide to use gathers
2062 : : or scatters, fill in GS_INFO accordingly. In addition
2063 : : *ALIGNMENT_SUPPORT_SCHEME is filled out and false is returned if
2064 : : the target does not support the alignment scheme. *MISALIGNMENT
2065 : : is set according to the alignment of the access (including
2066 : : DR_MISALIGNMENT_UNKNOWN when it is unknown).
2067 : :
2068 : : MASKED_P is true if the statement is conditional on a vectorized mask.
2069 : : VECTYPE is the vector type that the vectorized statements will use.
2070 : :
2071 : : If ELSVALS is nonzero the supported else values will be stored in the
2072 : : vector ELSVALS points to. */
2073 : :
2074 : : static bool
2075 : 1250649 : get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
2076 : : tree vectype, slp_tree slp_node,
2077 : : bool masked_p, vec_load_store_type vls_type,
2078 : : vect_load_store_data *ls)
2079 : : {
2080 : 1250649 : vect_memory_access_type *memory_access_type = &ls->memory_access_type;
2081 : 1250649 : poly_int64 *poffset = &ls->poffset;
2082 : 1250649 : dr_alignment_support *alignment_support_scheme
2083 : : = &ls->alignment_support_scheme;
2084 : 1250649 : int *misalignment = &ls->misalignment;
2085 : 1250649 : internal_fn *lanes_ifn = &ls->lanes_ifn;
2086 : 1250649 : vec<int> *elsvals = &ls->elsvals;
2087 : 1250649 : tree *ls_type = &ls->ls_type;
2088 : 1250649 : bool *slp_perm = &ls->slp_perm;
2089 : 1250649 : unsigned *n_perms = &ls->n_perms;
2090 : 1250649 : tree *supported_offset_vectype = &ls->supported_offset_vectype;
2091 : 1250649 : int *supported_scale = &ls->supported_scale;
2092 : 1250649 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
2093 : 1250649 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
2094 : 1250649 : class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
2095 : 1250649 : stmt_vec_info first_stmt_info;
2096 : 1250649 : unsigned int group_size;
2097 : 1250649 : unsigned HOST_WIDE_INT gap;
2098 : 1250649 : bool single_element_p;
2099 : 1250649 : poly_int64 neg_ldst_offset = 0;
2100 : :
2101 : 1250649 : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2102 : 1250649 : *poffset = 0;
2103 : 1250649 : *ls_type = NULL_TREE;
2104 : 1250649 : *slp_perm = false;
2105 : 1250649 : *n_perms = -1U;
2106 : 1250649 : ls->subchain_p = false;
2107 : :
2108 : 1250649 : bool perm_ok = true;
2109 : 1250649 : poly_int64 vf = loop_vinfo ? LOOP_VINFO_VECT_FACTOR (loop_vinfo) : 1;
2110 : :
2111 : 1250649 : if (SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
2112 : 61722 : perm_ok = vect_transform_slp_perm_load (vinfo, slp_node, vNULL, NULL,
2113 : 61722 : vf, true, n_perms);
2114 : :
2115 : 1250649 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
2116 : : {
2117 : 864862 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
2118 : 864862 : group_size = DR_GROUP_SIZE (first_stmt_info);
2119 : 864862 : gap = DR_GROUP_GAP (first_stmt_info);
2120 : 864862 : single_element_p = (stmt_info == first_stmt_info
2121 : 864862 : && !DR_GROUP_NEXT_ELEMENT (stmt_info));
2122 : : }
2123 : : else
2124 : : {
2125 : : first_stmt_info = stmt_info;
2126 : : group_size = 1;
2127 : : gap = 0;
2128 : : single_element_p = true;
2129 : : }
2130 : 1250649 : dr_vec_info *first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
2131 : :
2132 : : /* True if the vectorized statements would access beyond the last
2133 : : statement in the group. */
2134 : 1250649 : bool overrun_p = false;
2135 : :
2136 : : /* True if we can cope with such overrun by peeling for gaps, so that
2137 : : there is at least one final scalar iteration after the vector loop. */
2138 : 2501298 : bool can_overrun_p = (!masked_p
2139 : 1250649 : && vls_type == VLS_LOAD
2140 : 467619 : && loop_vinfo
2141 : 1589522 : && !loop->inner);
2142 : :
2143 : : /* There can only be a gap at the end of the group if the stride is
2144 : : known at compile time. */
2145 : 1250649 : gcc_assert (!STMT_VINFO_STRIDED_P (first_stmt_info) || gap == 0);
2146 : :
2147 : : /* For SLP vectorization we directly vectorize a subchain
2148 : : without permutation. */
2149 : 1250649 : if (! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
2150 : 1188927 : first_dr_info = STMT_VINFO_DR_INFO (SLP_TREE_SCALAR_STMTS (slp_node)[0]);
2151 : :
2152 : 1250649 : if (STMT_VINFO_STRIDED_P (first_stmt_info))
2153 : : {
2154 : : /* Try to use consecutive accesses of as many elements as possible,
2155 : : separated by the stride, until we have a complete vector.
2156 : : Fall back to scalar accesses if that isn't possible. */
2157 : 46241 : *memory_access_type = VMAT_STRIDED_SLP;
2158 : :
2159 : : /* If the load permutation is consecutive we can reduce the group to
2160 : : the elements the permutation accesses. Then we release the
2161 : : permutation. */
2162 : 46241 : if (has_consecutive_load_permutation (slp_node, group_size))
2163 : : {
2164 : 20 : ls->subchain_p = true;
2165 : 20 : group_size = SLP_TREE_LANES (slp_node);
2166 : 20 : SLP_TREE_LOAD_PERMUTATION (slp_node).release ();
2167 : : }
2168 : : }
2169 : 1204408 : else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
2170 : : {
2171 : 6365 : slp_tree offset_node = SLP_TREE_CHILDREN (slp_node)[0];
2172 : 6365 : tree offset_vectype = SLP_TREE_VECTYPE (offset_node);
2173 : 6365 : int scale = SLP_TREE_GS_SCALE (slp_node);
2174 : 6365 : tree memory_type = TREE_TYPE (DR_REF (first_dr_info->dr));
2175 : 6365 : tree tem;
2176 : 6365 : if (vect_gather_scatter_fn_p (loop_vinfo, vls_type == VLS_LOAD,
2177 : : masked_p, vectype, memory_type,
2178 : : offset_vectype, scale, supported_scale,
2179 : : &ls->gs.ifn, &tem,
2180 : : supported_offset_vectype, elsvals))
2181 : : {
2182 : 0 : if (dump_enabled_p ())
2183 : : {
2184 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
2185 : : "gather/scatter with required "
2186 : : "offset type "
2187 : : "%T and offset scale %d.\n",
2188 : : offset_vectype, scale);
2189 : 0 : if (*supported_offset_vectype)
2190 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
2191 : : " target supports offset type %T.\n",
2192 : : *supported_offset_vectype);
2193 : 0 : if (*supported_scale)
2194 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
2195 : : " target supports offset scale %d.\n",
2196 : : *supported_scale);
2197 : : }
2198 : 0 : *memory_access_type = VMAT_GATHER_SCATTER_IFN;
2199 : : }
2200 : 6365 : else if (vls_type == VLS_LOAD
2201 : 6365 : ? (targetm.vectorize.builtin_gather
2202 : 4960 : && (ls->gs.decl
2203 : 4960 : = targetm.vectorize.builtin_gather (vectype,
2204 : 4960 : TREE_TYPE
2205 : : (offset_vectype),
2206 : : scale)))
2207 : 1405 : : (targetm.vectorize.builtin_scatter
2208 : 1405 : && (ls->gs.decl
2209 : 1405 : = targetm.vectorize.builtin_scatter (vectype,
2210 : 1405 : TREE_TYPE
2211 : : (offset_vectype),
2212 : : scale))))
2213 : 345 : *memory_access_type = VMAT_GATHER_SCATTER_LEGACY;
2214 : : else
2215 : : {
2216 : : /* GATHER_SCATTER_EMULATED_P. */
2217 : 6020 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant ()
2218 : 6020 : || !TYPE_VECTOR_SUBPARTS (offset_vectype).is_constant ()
2219 : 6020 : || VECTOR_BOOLEAN_TYPE_P (offset_vectype)
2220 : 6020 : || !constant_multiple_p (TYPE_VECTOR_SUBPARTS (offset_vectype),
2221 : 6020 : TYPE_VECTOR_SUBPARTS (vectype)))
2222 : : {
2223 : 2594 : if (dump_enabled_p ())
2224 : 442 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2225 : : "unsupported vector types for emulated "
2226 : : "gather.\n");
2227 : 2594 : return false;
2228 : : }
2229 : 3426 : *memory_access_type = VMAT_GATHER_SCATTER_EMULATED;
2230 : : }
2231 : : }
2232 : : else
2233 : : {
2234 : 1198043 : int cmp = compare_step_with_zero (vinfo, stmt_info);
2235 : 1198043 : if (cmp < 0)
2236 : : {
2237 : 10587 : if (single_element_p)
2238 : : /* ??? The VMAT_CONTIGUOUS_REVERSE code generation is
2239 : : only correct for single element "interleaving" SLP. */
2240 : 10432 : *memory_access_type = get_negative_load_store_type
2241 : 10432 : (vinfo, stmt_info, vectype, vls_type, 1,
2242 : : &neg_ldst_offset);
2243 : : else
2244 : : /* We can fall back to VMAT_STRIDED_SLP since that does
2245 : : not care whether the stride between the group instances
2246 : : is positive or negative. */
2247 : 155 : *memory_access_type = VMAT_STRIDED_SLP;
2248 : : }
2249 : 1187456 : else if (cmp == 0 && loop_vinfo)
2250 : : {
2251 : 3003 : gcc_assert (vls_type == VLS_LOAD);
2252 : 3003 : *memory_access_type = VMAT_INVARIANT;
2253 : : }
2254 : : /* Try using LOAD/STORE_LANES. */
2255 : 1184453 : else if (slp_node->ldst_lanes
2256 : 1184453 : && (*lanes_ifn
2257 : 0 : = (vls_type == VLS_LOAD
2258 : 0 : ? vect_load_lanes_supported (vectype, group_size,
2259 : : masked_p, elsvals)
2260 : 0 : : vect_store_lanes_supported (vectype, group_size,
2261 : : masked_p))) != IFN_LAST)
2262 : 0 : *memory_access_type = VMAT_LOAD_STORE_LANES;
2263 : 1184453 : else if (!loop_vinfo && slp_node->avoid_stlf_fail)
2264 : : {
2265 : 70 : *memory_access_type = VMAT_ELEMENTWISE;
2266 : 70 : if (dump_enabled_p ())
2267 : 2 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2268 : : "using element-wise load to avoid disrupting "
2269 : : "cross iteration store-to-load forwarding\n");
2270 : : }
2271 : : else
2272 : 1184383 : *memory_access_type = VMAT_CONTIGUOUS;
2273 : :
2274 : : /* If this is single-element interleaving with an element
2275 : : distance that leaves unused vector loads around fall back
2276 : : to elementwise access if possible - we otherwise least
2277 : : create very sub-optimal code in that case (and
2278 : : blow up memory, see PR65518). */
2279 : 1198043 : if (loop_vinfo
2280 : 1198043 : && single_element_p
2281 : 364255 : && (*memory_access_type == VMAT_CONTIGUOUS
2282 : 13435 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2283 : 1562298 : && maybe_gt (group_size, TYPE_VECTOR_SUBPARTS (vectype)))
2284 : : {
2285 : 13381 : *memory_access_type = VMAT_ELEMENTWISE;
2286 : 13381 : if (dump_enabled_p ())
2287 : 175 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2288 : : "single-element interleaving not supported "
2289 : : "for not adjacent vector loads, using "
2290 : : "elementwise access\n");
2291 : : }
2292 : :
2293 : : /* Also fall back to elementwise access in case we did not lower a
2294 : : permutation and cannot code generate it. */
2295 : 1198043 : if (loop_vinfo
2296 : 415220 : && *memory_access_type != VMAT_ELEMENTWISE
2297 : 397305 : && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2298 : 1220752 : && !perm_ok)
2299 : : {
2300 : 2052 : *memory_access_type = VMAT_ELEMENTWISE;
2301 : 2052 : if (dump_enabled_p ())
2302 : 212 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2303 : : "permutation not supported, using elementwise "
2304 : : "access\n");
2305 : : }
2306 : :
2307 : 415220 : overrun_p = (loop_vinfo && gap != 0
2308 : 1241971 : && *memory_access_type != VMAT_ELEMENTWISE);
2309 : 1198043 : if (overrun_p && vls_type != VLS_LOAD)
2310 : : {
2311 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2312 : : "Grouped store with gaps requires"
2313 : : " non-consecutive accesses\n");
2314 : 9 : return false;
2315 : : }
2316 : :
2317 : 1198043 : unsigned HOST_WIDE_INT dr_size = vect_get_scalar_dr_size (first_dr_info);
2318 : 1198043 : poly_int64 off = 0;
2319 : 1198043 : if (*memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2320 : 5035 : off = (TYPE_VECTOR_SUBPARTS (vectype) - 1) * -dr_size;
2321 : :
2322 : : /* An overrun is fine if the trailing elements are smaller
2323 : : than the alignment boundary B. Every vector access will
2324 : : be a multiple of B and so we are guaranteed to access a
2325 : : non-gap element in the same B-sized block. */
2326 : 1198043 : if (overrun_p
2327 : 1198043 : && gap < (vect_known_alignment_in_bytes (first_dr_info,
2328 : 28445 : vectype, off) / dr_size))
2329 : : overrun_p = false;
2330 : :
2331 : : /* When we have a contiguous access across loop iterations
2332 : : but the access in the loop doesn't cover the full vector
2333 : : we can end up with no gap recorded but still excess
2334 : : elements accessed, see PR103116. Make sure we peel for
2335 : : gaps if necessary and sufficient and give up if not.
2336 : :
2337 : : If there is a combination of the access not covering the full
2338 : : vector and a gap recorded then we may need to peel twice. */
2339 : 1198043 : bool large_vector_overrun_p = false;
2340 : 1198043 : if (loop_vinfo
2341 : 415220 : && (*memory_access_type == VMAT_CONTIGUOUS
2342 : 28868 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2343 : 391387 : && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2344 : 1218416 : && !multiple_p (group_size * LOOP_VINFO_VECT_FACTOR (loop_vinfo),
2345 : : nunits))
2346 : : large_vector_overrun_p = overrun_p = true;
2347 : :
2348 : : /* If the gap splits the vector in half and the target
2349 : : can do half-vector operations avoid the epilogue peeling
2350 : : by simply loading half of the vector only. Usually
2351 : : the construction with an upper zero half will be elided. */
2352 : 1198043 : dr_alignment_support alss;
2353 : 1198043 : int misalign = dr_misalignment (first_dr_info, vectype, off);
2354 : 1198043 : tree half_vtype;
2355 : 1198043 : poly_uint64 remain;
2356 : 1198043 : unsigned HOST_WIDE_INT tem, num;
2357 : 1198043 : if (overrun_p
2358 : 1198043 : && !masked_p
2359 : 22685 : && *memory_access_type != VMAT_LOAD_STORE_LANES
2360 : 22685 : && (((alss = vect_supportable_dr_alignment (vinfo, first_dr_info,
2361 : : vectype, misalign)))
2362 : : == dr_aligned
2363 : 17529 : || alss == dr_unaligned_supported)
2364 : 12303 : && can_div_trunc_p (group_size
2365 : 12303 : * LOOP_VINFO_VECT_FACTOR (loop_vinfo) - gap,
2366 : : nunits, &tem, &remain)
2367 : 1210346 : && (known_eq (remain, 0u)
2368 : 7170 : || (known_ne (remain, 0u)
2369 : 5539 : && constant_multiple_p (nunits, remain, &num)
2370 : 1192910 : && (vector_vector_composition_type (vectype, num, &half_vtype)
2371 : : != NULL_TREE))))
2372 : 10672 : overrun_p = false;
2373 : :
2374 : 1198043 : if (overrun_p && !can_overrun_p)
2375 : : {
2376 : 6 : if (dump_enabled_p ())
2377 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2378 : : "Peeling for outer loop is not supported\n");
2379 : 6 : return false;
2380 : : }
2381 : :
2382 : : /* Peeling for gaps assumes that a single scalar iteration
2383 : : is enough to make sure the last vector iteration doesn't
2384 : : access excess elements. */
2385 : 1198037 : if (overrun_p
2386 : 1198037 : && (!can_div_trunc_p (group_size
2387 : 12007 : * LOOP_VINFO_VECT_FACTOR (loop_vinfo) - gap,
2388 : : nunits, &tem, &remain)
2389 : 12007 : || maybe_lt (remain + group_size, nunits)))
2390 : : {
2391 : : /* But peeling a single scalar iteration is enough if
2392 : : we can use the next power-of-two sized partial
2393 : : access and that is sufficiently small to be covered
2394 : : by the single scalar iteration. */
2395 : 16 : unsigned HOST_WIDE_INT cnunits, cvf, cremain, cpart_size;
2396 : 16 : if (masked_p
2397 : 16 : || !nunits.is_constant (&cnunits)
2398 : 16 : || !LOOP_VINFO_VECT_FACTOR (loop_vinfo).is_constant (&cvf)
2399 : 16 : || (((cremain = (group_size * cvf - gap) % cnunits), true)
2400 : 16 : && ((cpart_size = (1 << ceil_log2 (cremain))), true)
2401 : 16 : && (cremain + group_size < cpart_size
2402 : 13 : || (vector_vector_composition_type (vectype,
2403 : 13 : cnunits / cpart_size,
2404 : : &half_vtype)
2405 : : == NULL_TREE))))
2406 : : {
2407 : : /* If all fails we can still resort to niter masking unless
2408 : : the vectors used are too big, so enforce the use of
2409 : : partial vectors. */
2410 : 3 : if (LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
2411 : 3 : && !large_vector_overrun_p)
2412 : : {
2413 : 0 : if (dump_enabled_p ())
2414 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2415 : : "peeling for gaps insufficient for "
2416 : : "access unless using partial "
2417 : : "vectors\n");
2418 : 0 : LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
2419 : : }
2420 : : else
2421 : : {
2422 : 3 : if (dump_enabled_p ())
2423 : 3 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2424 : : "peeling for gaps insufficient for "
2425 : : "access\n");
2426 : 3 : return false;
2427 : : }
2428 : : }
2429 : 13 : else if (large_vector_overrun_p)
2430 : : {
2431 : 13 : if (dump_enabled_p ())
2432 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2433 : : "can't operate on partial vectors because "
2434 : : "only unmasked loads handle access "
2435 : : "shortening required because of gaps at "
2436 : : "the end of the access\n");
2437 : 13 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
2438 : : }
2439 : : }
2440 : : }
2441 : :
2442 : : /* As a last resort, trying using a gather load or scatter store.
2443 : :
2444 : : ??? Although the code can handle all group sizes correctly,
2445 : : it probably isn't a win to use separate strided accesses based
2446 : : on nearby locations. Or, even if it's a win over scalar code,
2447 : : it might not be a win over vectorizing at a lower VF, if that
2448 : : allows us to use contiguous accesses. */
2449 : 1248046 : vect_memory_access_type grouped_gather_fallback = VMAT_UNINITIALIZED;
2450 : 1248046 : if (loop_vinfo
2451 : 465223 : && (*memory_access_type == VMAT_ELEMENTWISE
2452 : 465223 : || *memory_access_type == VMAT_STRIDED_SLP))
2453 : : {
2454 : 66360 : gather_scatter_info gs_info;
2455 : 66360 : if (SLP_TREE_LANES (slp_node) == 1
2456 : 62516 : && (!SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2457 : 16882 : || single_element_p)
2458 : 127096 : && vect_use_strided_gather_scatters_p (stmt_info, vectype, loop_vinfo,
2459 : : masked_p, &gs_info, elsvals,
2460 : : group_size, single_element_p))
2461 : : {
2462 : : /* vect_use_strided_gather_scatters_p does not save the actually
2463 : : supported scale and offset type so do that here.
2464 : : We need it later in check_load_store_for_partial_vectors
2465 : : where we only check if the given internal function is supported
2466 : : (to choose whether to use the IFN, LEGACY, or EMULATED flavor
2467 : : of gather/scatter) and don't re-do the full analysis. */
2468 : 0 : tree tmp;
2469 : 0 : gcc_assert (vect_gather_scatter_fn_p
2470 : : (loop_vinfo, vls_type == VLS_LOAD, masked_p, vectype,
2471 : : gs_info.memory_type, TREE_TYPE (gs_info.offset),
2472 : : gs_info.scale, supported_scale, &gs_info.ifn,
2473 : : &tmp, supported_offset_vectype, elsvals));
2474 : :
2475 : 0 : SLP_TREE_GS_SCALE (slp_node) = gs_info.scale;
2476 : 0 : SLP_TREE_GS_BASE (slp_node) = error_mark_node;
2477 : 0 : ls->gs.ifn = gs_info.ifn;
2478 : 0 : ls->strided_offset_vectype = gs_info.offset_vectype;
2479 : 0 : *memory_access_type = VMAT_GATHER_SCATTER_IFN;
2480 : : }
2481 : 66360 : else if (SLP_TREE_LANES (slp_node) > 1
2482 : : && !masked_p
2483 : 3844 : && !single_element_p
2484 : 70006 : && vect_use_grouped_gather (STMT_VINFO_DR_INFO (stmt_info),
2485 : : vectype, loop_vinfo,
2486 : : masked_p, group_size,
2487 : : &gs_info, elsvals, ls_type))
2488 : : {
2489 : 0 : SLP_TREE_GS_SCALE (slp_node) = gs_info.scale;
2490 : 0 : SLP_TREE_GS_BASE (slp_node) = error_mark_node;
2491 : 0 : grouped_gather_fallback = *memory_access_type;
2492 : 0 : *memory_access_type = VMAT_GATHER_SCATTER_IFN;
2493 : 0 : ls->gs.ifn = gs_info.ifn;
2494 : 0 : vectype = *ls_type;
2495 : 0 : ls->strided_offset_vectype = gs_info.offset_vectype;
2496 : : }
2497 : : }
2498 : :
2499 : 1248046 : if (*memory_access_type == VMAT_CONTIGUOUS_DOWN
2500 : 1248046 : || *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
2501 : 5742 : *poffset = neg_ldst_offset;
2502 : :
2503 : 1248046 : if (*memory_access_type == VMAT_ELEMENTWISE
2504 : 1228009 : || *memory_access_type == VMAT_GATHER_SCATTER_LEGACY
2505 : 1227664 : || *memory_access_type == VMAT_STRIDED_SLP
2506 : 1181271 : || *memory_access_type == VMAT_INVARIANT)
2507 : : {
2508 : 69778 : *alignment_support_scheme = dr_unaligned_supported;
2509 : 69778 : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2510 : : }
2511 : : else
2512 : : {
2513 : 1178268 : if (mat_gather_scatter_p (*memory_access_type)
2514 : : && !first_dr_info)
2515 : : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2516 : : else
2517 : 1178268 : *misalignment = dr_misalignment (first_dr_info, vectype, *poffset);
2518 : 1178268 : *alignment_support_scheme
2519 : 1178268 : = vect_supportable_dr_alignment
2520 : 1178268 : (vinfo, first_dr_info, vectype, *misalignment,
2521 : 1178268 : mat_gather_scatter_p (*memory_access_type));
2522 : 1178268 : if (grouped_gather_fallback != VMAT_UNINITIALIZED
2523 : 0 : && *alignment_support_scheme != dr_aligned
2524 : 0 : && *alignment_support_scheme != dr_unaligned_supported)
2525 : : {
2526 : : /* No supportable alignment for a grouped gather, fall back to the
2527 : : original memory access type. Even though VMAT_STRIDED_SLP might
2528 : : also try aligned vector loads it can still choose vector
2529 : : construction from scalars. */
2530 : 0 : *memory_access_type = grouped_gather_fallback;
2531 : 0 : *alignment_support_scheme = dr_unaligned_supported;
2532 : 0 : *misalignment = DR_MISALIGNMENT_UNKNOWN;
2533 : : }
2534 : : }
2535 : :
2536 : 1248046 : if (overrun_p)
2537 : : {
2538 : 12004 : gcc_assert (can_overrun_p);
2539 : 12004 : if (dump_enabled_p ())
2540 : 507 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2541 : : "Data access with gaps requires scalar "
2542 : : "epilogue loop\n");
2543 : 12004 : LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo) = true;
2544 : : }
2545 : :
2546 : 1248046 : if ((*memory_access_type == VMAT_ELEMENTWISE
2547 : 1248046 : || *memory_access_type == VMAT_STRIDED_SLP)
2548 : : && !nunits.is_constant ())
2549 : : {
2550 : : if (dump_enabled_p ())
2551 : : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2552 : : "Not using elementwise accesses due to variable "
2553 : : "vectorization factor.\n");
2554 : : return false;
2555 : : }
2556 : :
2557 : : /* Checks if all scalar iterations are known to be inbounds. */
2558 : 1248046 : bool inbounds = DR_SCALAR_KNOWN_BOUNDS (STMT_VINFO_DR_INFO (stmt_info));
2559 : :
2560 : : /* Check if we support the operation if early breaks are needed. Here we
2561 : : must ensure that we don't access any more than the scalar code would
2562 : : have. A masked operation would ensure this, so for these load types
2563 : : force masking. */
2564 : 1248046 : if (loop_vinfo
2565 : 465223 : && dr_safe_speculative_read_required (stmt_info)
2566 : 169913 : && LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
2567 : 1417959 : && (mat_gather_scatter_p (*memory_access_type)
2568 : 169513 : || *memory_access_type == VMAT_STRIDED_SLP))
2569 : : {
2570 : 6270 : if (dump_enabled_p ())
2571 : 8 : dump_printf_loc (MSG_NOTE, vect_location,
2572 : : "early break not supported: cannot peel for "
2573 : : "alignment. With non-contiguous memory vectorization"
2574 : : " could read out of bounds at %G ",
2575 : : STMT_VINFO_STMT (stmt_info));
2576 : 6270 : if (inbounds)
2577 : 0 : LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
2578 : : else
2579 : : return false;
2580 : : }
2581 : :
2582 : : /* If this DR needs alignment for correctness, we must ensure the target
2583 : : alignment is a constant power-of-two multiple of the amount read per
2584 : : vector iteration or force masking. */
2585 : 1241776 : if (dr_safe_speculative_read_required (stmt_info)
2586 : 1241776 : && (*alignment_support_scheme == dr_aligned
2587 : 86889 : && !mat_gather_scatter_p (*memory_access_type)))
2588 : : {
2589 : : /* We can only peel for loops, of course. */
2590 : 86889 : gcc_checking_assert (loop_vinfo);
2591 : :
2592 : 86889 : poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
2593 : 86889 : poly_uint64 read_amount
2594 : 86889 : = vf * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
2595 : 86889 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
2596 : 86889 : read_amount *= group_size;
2597 : :
2598 : 86889 : auto target_alignment
2599 : 86889 : = DR_TARGET_ALIGNMENT (STMT_VINFO_DR_INFO (stmt_info));
2600 : 86889 : if (!multiple_p (target_alignment, read_amount))
2601 : : {
2602 : 5892 : if (dump_enabled_p ())
2603 : : {
2604 : 10 : dump_printf_loc (MSG_NOTE, vect_location,
2605 : : "desired alignment not met, target was ");
2606 : 10 : dump_dec (MSG_NOTE, target_alignment);
2607 : 10 : dump_printf (MSG_NOTE, " previously, but read amount is ");
2608 : 10 : dump_dec (MSG_NOTE, read_amount);
2609 : 10 : dump_printf (MSG_NOTE, " at %G.\n", STMT_VINFO_STMT (stmt_info));
2610 : : }
2611 : 7092 : return false;
2612 : : }
2613 : :
2614 : : /* When using a group access the first element may be aligned but the
2615 : : subsequent loads may not be. For LOAD_LANES since the loads are based
2616 : : on the first DR then all loads in the group are aligned. For
2617 : : non-LOAD_LANES this is not the case. In particular a load + blend when
2618 : : there are gaps can have the non first loads issued unaligned, even
2619 : : partially overlapping the memory of the first load in order to simplify
2620 : : the blend. This is what the x86_64 backend does for instance. As
2621 : : such only the first load in the group is aligned, the rest are not.
2622 : : Because of this the permutes may break the alignment requirements that
2623 : : have been set, and as such we should for now, reject them. */
2624 : 80997 : if (SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
2625 : : {
2626 : 1200 : if (dump_enabled_p ())
2627 : 72 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2628 : : "loads with load permutations not supported for "
2629 : : "speculative early break loads for %G",
2630 : : STMT_VINFO_STMT (stmt_info));
2631 : 1200 : return false;
2632 : : }
2633 : :
2634 : : /* Reject vectorization if we know the read mount per vector iteration
2635 : : exceeds the min page size. */
2636 : 79797 : if (known_gt (read_amount, (unsigned) param_min_pagesize))
2637 : : {
2638 : 0 : if (dump_enabled_p ())
2639 : : {
2640 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2641 : : "alignment required for correctness (");
2642 : 0 : dump_dec (MSG_MISSED_OPTIMIZATION, read_amount);
2643 : 0 : dump_printf (MSG_NOTE, ") may exceed page size.\n");
2644 : : }
2645 : 0 : return false;
2646 : : }
2647 : :
2648 : 79797 : if (!vf.is_constant ())
2649 : : {
2650 : : /* For VLA modes, we need a runtime check to ensure any speculative
2651 : : read amount does not exceed the page size. Here we record the max
2652 : : possible read amount for the check. */
2653 : : if (maybe_gt (read_amount,
2654 : : LOOP_VINFO_MAX_SPEC_READ_AMOUNT (loop_vinfo)))
2655 : : LOOP_VINFO_MAX_SPEC_READ_AMOUNT (loop_vinfo) = read_amount;
2656 : :
2657 : : /* For VLA modes, we must use partial vectors. */
2658 : : LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
2659 : : }
2660 : : }
2661 : :
2662 : 1234684 : if (*alignment_support_scheme == dr_unaligned_unsupported)
2663 : : {
2664 : 63809 : if (dump_enabled_p ())
2665 : 270 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2666 : : "unsupported unaligned access\n");
2667 : 63809 : return false;
2668 : : }
2669 : :
2670 : : /* FIXME: At the moment the cost model seems to underestimate the
2671 : : cost of using elementwise accesses. This check preserves the
2672 : : traditional behavior until that can be fixed. */
2673 : 1170875 : if (*memory_access_type == VMAT_ELEMENTWISE
2674 : 20037 : && !STMT_VINFO_STRIDED_P (first_stmt_info)
2675 : 1190912 : && !(STMT_VINFO_GROUPED_ACCESS (stmt_info)
2676 : 15876 : && single_element_p
2677 : 15262 : && !pow2p_hwi (group_size)))
2678 : : {
2679 : 9373 : if (dump_enabled_p ())
2680 : 331 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2681 : : "not falling back to elementwise accesses\n");
2682 : 9373 : return false;
2683 : : }
2684 : :
2685 : : /* For BB vectorization build up the vector from existing scalar defs. */
2686 : 1161502 : if (!loop_vinfo && *memory_access_type == VMAT_ELEMENTWISE)
2687 : : return false;
2688 : :
2689 : : /* Some loads need to explicitly permute the loaded data if there
2690 : : is a load permutation. Among those are:
2691 : : - VMAT_ELEMENTWISE.
2692 : : - VMAT_STRIDED_SLP.
2693 : : - VMAT_GATHER_SCATTER:
2694 : : - Strided gather (fallback for VMAT_STRIDED_SLP if #lanes == 1).
2695 : : - Grouped strided gather (ditto but for #lanes > 1).
2696 : :
2697 : : For VMAT_ELEMENTWISE we can fold the load permutation into the
2698 : : individual indices we access directly, eliding the permutation.
2699 : : Strided gather only allows load permutations for the
2700 : : single-element case. */
2701 : :
2702 : 1161502 : if (SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()
2703 : 1161502 : && !(*memory_access_type == VMAT_ELEMENTWISE
2704 : 39137 : || (mat_gather_scatter_p (*memory_access_type)
2705 : 0 : && SLP_TREE_LANES (slp_node) == 1
2706 : 0 : && single_element_p)))
2707 : : {
2708 : 39137 : if (!loop_vinfo)
2709 : : {
2710 : : /* In BB vectorization we may not actually use a loaded vector
2711 : : accessing elements in excess of DR_GROUP_SIZE. */
2712 : 23536 : stmt_vec_info group_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
2713 : 23536 : group_info = DR_GROUP_FIRST_ELEMENT (group_info);
2714 : 23536 : unsigned HOST_WIDE_INT nunits;
2715 : 23536 : unsigned j, k, maxk = 0;
2716 : 84384 : FOR_EACH_VEC_ELT (SLP_TREE_LOAD_PERMUTATION (slp_node), j, k)
2717 : 60848 : if (k > maxk)
2718 : : maxk = k;
2719 : 23536 : tree vectype = SLP_TREE_VECTYPE (slp_node);
2720 : 42781 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits)
2721 : 23536 : || maxk >= (DR_GROUP_SIZE (group_info) & ~(nunits - 1)))
2722 : : {
2723 : 4291 : if (dump_enabled_p ())
2724 : 31 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2725 : : "BB vectorization with gaps at the end of "
2726 : : "a load is not supported\n");
2727 : 4291 : return false;
2728 : : }
2729 : : }
2730 : :
2731 : 34846 : if (!perm_ok)
2732 : : {
2733 : 1964 : if (dump_enabled_p ())
2734 : 8 : dump_printf_loc (MSG_MISSED_OPTIMIZATION,
2735 : : vect_location,
2736 : : "unsupported load permutation\n");
2737 : 1964 : return false;
2738 : : }
2739 : :
2740 : 32882 : *slp_perm = true;
2741 : : }
2742 : :
2743 : : return true;
2744 : : }
2745 : :
2746 : : /* Return true if boolean argument at MASK_INDEX is suitable for vectorizing
2747 : : conditional operation STMT_INFO. When returning true, store the mask
2748 : : in *MASK_NODE, the type of its definition in *MASK_DT_OUT and the type of
2749 : : the vectorized mask in *MASK_VECTYPE_OUT. */
2750 : :
2751 : : static bool
2752 : 7817 : vect_check_scalar_mask (vec_info *vinfo,
2753 : : slp_tree slp_node, unsigned mask_index,
2754 : : slp_tree *mask_node,
2755 : : vect_def_type *mask_dt_out, tree *mask_vectype_out)
2756 : : {
2757 : 7817 : enum vect_def_type mask_dt;
2758 : 7817 : tree mask_vectype;
2759 : 7817 : slp_tree mask_node_1;
2760 : 7817 : tree mask_;
2761 : 7817 : if (!vect_is_simple_use (vinfo, slp_node, mask_index,
2762 : : &mask_, &mask_node_1, &mask_dt, &mask_vectype))
2763 : : {
2764 : 0 : if (dump_enabled_p ())
2765 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2766 : : "mask use not simple.\n");
2767 : 0 : return false;
2768 : : }
2769 : :
2770 : 7817 : if ((mask_dt == vect_constant_def || mask_dt == vect_external_def)
2771 : 7817 : && !VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (mask_)))
2772 : : {
2773 : 0 : if (dump_enabled_p ())
2774 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2775 : : "mask argument is not a boolean.\n");
2776 : 0 : return false;
2777 : : }
2778 : :
2779 : 7817 : tree vectype = SLP_TREE_VECTYPE (slp_node);
2780 : 7817 : if (!mask_vectype)
2781 : 17 : mask_vectype = get_mask_type_for_scalar_type (vinfo, TREE_TYPE (vectype),
2782 : : mask_node_1);
2783 : :
2784 : 7817 : if (!mask_vectype || !VECTOR_BOOLEAN_TYPE_P (mask_vectype))
2785 : : {
2786 : 0 : if (dump_enabled_p ())
2787 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2788 : : "could not find an appropriate vector mask type.\n");
2789 : 0 : return false;
2790 : : }
2791 : :
2792 : 7817 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (mask_vectype),
2793 : 15634 : TYPE_VECTOR_SUBPARTS (vectype)))
2794 : : {
2795 : 0 : if (dump_enabled_p ())
2796 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2797 : : "vector mask type %T"
2798 : : " does not match vector data type %T.\n",
2799 : : mask_vectype, vectype);
2800 : :
2801 : 0 : return false;
2802 : : }
2803 : :
2804 : 7817 : *mask_dt_out = mask_dt;
2805 : 7817 : *mask_vectype_out = mask_vectype;
2806 : 7817 : *mask_node = mask_node_1;
2807 : 7817 : return true;
2808 : : }
2809 : :
2810 : :
2811 : : /* Return true if stored value is suitable for vectorizing store
2812 : : statement STMT_INFO. When returning true, store the scalar stored
2813 : : in *RHS and *RHS_NODE, the type of the definition in *RHS_DT_OUT,
2814 : : the type of the vectorized store value in
2815 : : *RHS_VECTYPE_OUT and the type of the store in *VLS_TYPE_OUT. */
2816 : :
2817 : : static bool
2818 : 1325179 : vect_check_store_rhs (vec_info *vinfo, stmt_vec_info stmt_info,
2819 : : slp_tree slp_node, slp_tree *rhs_node,
2820 : : vect_def_type *rhs_dt_out, tree *rhs_vectype_out,
2821 : : vec_load_store_type *vls_type_out)
2822 : : {
2823 : 1325179 : int op_no = 0;
2824 : 1325179 : if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt))
2825 : : {
2826 : 1448 : if (gimple_call_internal_p (call)
2827 : 1448 : && internal_store_fn_p (gimple_call_internal_fn (call)))
2828 : 1448 : op_no = internal_fn_stored_value_index (gimple_call_internal_fn (call));
2829 : : }
2830 : 1325179 : op_no = vect_slp_child_index_for_operand
2831 : 1325179 : (stmt_info->stmt, op_no, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
2832 : :
2833 : 1325179 : enum vect_def_type rhs_dt;
2834 : 1325179 : tree rhs_vectype;
2835 : 1325179 : tree rhs;
2836 : 1325179 : if (!vect_is_simple_use (vinfo, slp_node, op_no,
2837 : : &rhs, rhs_node, &rhs_dt, &rhs_vectype))
2838 : : {
2839 : 0 : if (dump_enabled_p ())
2840 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2841 : : "use not simple.\n");
2842 : 0 : return false;
2843 : : }
2844 : :
2845 : : /* In the case this is a store from a constant make sure
2846 : : native_encode_expr can handle it. */
2847 : 1325179 : if (rhs_dt == vect_constant_def
2848 : 1325179 : && CONSTANT_CLASS_P (rhs) && native_encode_expr (rhs, NULL, 64) == 0)
2849 : : {
2850 : 0 : if (dump_enabled_p ())
2851 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2852 : : "cannot encode constant as a byte sequence.\n");
2853 : 0 : return false;
2854 : : }
2855 : :
2856 : 1325179 : tree vectype = SLP_TREE_VECTYPE (slp_node);
2857 : 1325179 : if (rhs_vectype && !useless_type_conversion_p (vectype, rhs_vectype))
2858 : : {
2859 : 24 : if (dump_enabled_p ())
2860 : 24 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2861 : : "incompatible vector types.\n");
2862 : 24 : return false;
2863 : : }
2864 : :
2865 : 1325155 : *rhs_dt_out = rhs_dt;
2866 : 1325155 : *rhs_vectype_out = rhs_vectype;
2867 : 1325155 : if (rhs_dt == vect_constant_def || rhs_dt == vect_external_def)
2868 : 1006674 : *vls_type_out = VLS_STORE_INVARIANT;
2869 : : else
2870 : 318481 : *vls_type_out = VLS_STORE;
2871 : : return true;
2872 : : }
2873 : :
2874 : : /* Build an all-ones vector mask of type MASKTYPE while vectorizing STMT_INFO.
2875 : : Note that we support masks with floating-point type, in which case the
2876 : : floats are interpreted as a bitmask. */
2877 : :
2878 : : static tree
2879 : 165 : vect_build_all_ones_mask (vec_info *vinfo,
2880 : : stmt_vec_info stmt_info, tree masktype)
2881 : : {
2882 : 165 : if (TREE_CODE (masktype) == INTEGER_TYPE)
2883 : 98 : return build_int_cst (masktype, -1);
2884 : 67 : else if (VECTOR_BOOLEAN_TYPE_P (masktype)
2885 : 134 : || TREE_CODE (TREE_TYPE (masktype)) == INTEGER_TYPE)
2886 : : {
2887 : 14 : tree mask = build_int_cst (TREE_TYPE (masktype), -1);
2888 : 14 : mask = build_vector_from_val (masktype, mask);
2889 : 14 : return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL);
2890 : : }
2891 : 53 : else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (masktype)))
2892 : : {
2893 : : REAL_VALUE_TYPE r;
2894 : : long tmp[6];
2895 : 371 : for (int j = 0; j < 6; ++j)
2896 : 318 : tmp[j] = -1;
2897 : 53 : real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (masktype)));
2898 : 53 : tree mask = build_real (TREE_TYPE (masktype), r);
2899 : 53 : mask = build_vector_from_val (masktype, mask);
2900 : 53 : return vect_init_vector (vinfo, stmt_info, mask, masktype, NULL);
2901 : : }
2902 : 0 : gcc_unreachable ();
2903 : : }
2904 : :
2905 : : /* Build an all-zero merge value of type VECTYPE while vectorizing
2906 : : STMT_INFO as a gather load. */
2907 : :
2908 : : static tree
2909 : 158 : vect_build_zero_merge_argument (vec_info *vinfo,
2910 : : stmt_vec_info stmt_info, tree vectype)
2911 : : {
2912 : 158 : tree merge;
2913 : 158 : if (TREE_CODE (TREE_TYPE (vectype)) == INTEGER_TYPE)
2914 : 49 : merge = build_int_cst (TREE_TYPE (vectype), 0);
2915 : 109 : else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (vectype)))
2916 : : {
2917 : : REAL_VALUE_TYPE r;
2918 : : long tmp[6];
2919 : 763 : for (int j = 0; j < 6; ++j)
2920 : 654 : tmp[j] = 0;
2921 : 109 : real_from_target (&r, tmp, TYPE_MODE (TREE_TYPE (vectype)));
2922 : 109 : merge = build_real (TREE_TYPE (vectype), r);
2923 : : }
2924 : : else
2925 : 0 : gcc_unreachable ();
2926 : 158 : merge = build_vector_from_val (vectype, merge);
2927 : 158 : return vect_init_vector (vinfo, stmt_info, merge, vectype, NULL);
2928 : : }
2929 : :
2930 : : /* Return the corresponding else value for an else value constant
2931 : : ELSVAL with type TYPE. */
2932 : :
2933 : : tree
2934 : 1787 : vect_get_mask_load_else (int elsval, tree type)
2935 : : {
2936 : 1787 : tree els;
2937 : 1787 : if (elsval == MASK_LOAD_ELSE_UNDEFINED)
2938 : : {
2939 : 0 : tree tmp = create_tmp_var (type);
2940 : : /* No need to warn about anything. */
2941 : 0 : TREE_NO_WARNING (tmp) = 1;
2942 : 0 : els = get_or_create_ssa_default_def (cfun, tmp);
2943 : : }
2944 : 1787 : else if (elsval == MASK_LOAD_ELSE_M1)
2945 : 0 : els = build_minus_one_cst (type);
2946 : 1787 : else if (elsval == MASK_LOAD_ELSE_ZERO)
2947 : 1787 : els = build_zero_cst (type);
2948 : : else
2949 : 0 : gcc_unreachable ();
2950 : :
2951 : 1787 : return els;
2952 : : }
2953 : :
2954 : : /* Build a gather load call while vectorizing STMT_INFO. Insert new
2955 : : instructions before GSI and add them to VEC_STMT. GS_INFO describes
2956 : : the gather load operation. If the load is conditional, MASK is the
2957 : : vectorized condition, otherwise MASK is null. PTR is the base
2958 : : pointer and OFFSET is the vectorized offset. */
2959 : :
2960 : : static gimple *
2961 : 346 : vect_build_one_gather_load_call (vec_info *vinfo, stmt_vec_info stmt_info,
2962 : : slp_tree slp_node, tree vectype,
2963 : : gimple_stmt_iterator *gsi, tree decl,
2964 : : tree ptr, tree offset, tree mask)
2965 : : {
2966 : 346 : tree arglist = TYPE_ARG_TYPES (TREE_TYPE (decl));
2967 : 346 : tree rettype = TREE_TYPE (TREE_TYPE (decl));
2968 : 346 : tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2969 : 346 : /* ptrtype */ arglist = TREE_CHAIN (arglist);
2970 : 346 : tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2971 : 346 : tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
2972 : 346 : tree scaletype = TREE_VALUE (arglist);
2973 : 346 : tree var;
2974 : 346 : gcc_checking_assert (types_compatible_p (srctype, rettype)
2975 : : && (!mask
2976 : : || TREE_CODE (masktype) == INTEGER_TYPE
2977 : : || types_compatible_p (srctype, masktype)));
2978 : :
2979 : 346 : tree op = offset;
2980 : 346 : if (!useless_type_conversion_p (idxtype, TREE_TYPE (op)))
2981 : : {
2982 : 100 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)),
2983 : : TYPE_VECTOR_SUBPARTS (idxtype)));
2984 : 100 : var = vect_get_new_ssa_name (idxtype, vect_simple_var);
2985 : 100 : op = build1 (VIEW_CONVERT_EXPR, idxtype, op);
2986 : 100 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op);
2987 : 100 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
2988 : 100 : op = var;
2989 : : }
2990 : :
2991 : 346 : tree src_op = NULL_TREE;
2992 : 346 : tree mask_op = NULL_TREE;
2993 : 346 : if (mask)
2994 : : {
2995 : 188 : if (!useless_type_conversion_p (masktype, TREE_TYPE (mask)))
2996 : : {
2997 : 188 : tree utype, optype = TREE_TYPE (mask);
2998 : 188 : if (VECTOR_TYPE_P (masktype)
2999 : 188 : || TYPE_MODE (masktype) == TYPE_MODE (optype))
3000 : : utype = masktype;
3001 : : else
3002 : 6 : utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1);
3003 : 188 : var = vect_get_new_ssa_name (utype, vect_scalar_var);
3004 : 188 : tree mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask);
3005 : 188 : gassign *new_stmt
3006 : 188 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg);
3007 : 188 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3008 : 188 : mask_arg = var;
3009 : 188 : if (!useless_type_conversion_p (masktype, utype))
3010 : : {
3011 : 6 : gcc_assert (TYPE_PRECISION (utype)
3012 : : <= TYPE_PRECISION (masktype));
3013 : 6 : var = vect_get_new_ssa_name (masktype, vect_scalar_var);
3014 : 6 : new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg);
3015 : 6 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3016 : 6 : mask_arg = var;
3017 : : }
3018 : 188 : src_op = build_zero_cst (srctype);
3019 : 188 : mask_op = mask_arg;
3020 : : }
3021 : : else
3022 : : {
3023 : : src_op = mask;
3024 : : mask_op = mask;
3025 : : }
3026 : : }
3027 : : else
3028 : : {
3029 : 158 : src_op = vect_build_zero_merge_argument (vinfo, stmt_info, rettype);
3030 : 158 : mask_op = vect_build_all_ones_mask (vinfo, stmt_info, masktype);
3031 : : }
3032 : :
3033 : 346 : tree scale = build_int_cst (scaletype, SLP_TREE_GS_SCALE (slp_node));
3034 : 346 : gimple *new_stmt = gimple_build_call (decl, 5, src_op, ptr, op,
3035 : : mask_op, scale);
3036 : :
3037 : 346 : if (!useless_type_conversion_p (vectype, rettype))
3038 : : {
3039 : 49 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (vectype),
3040 : : TYPE_VECTOR_SUBPARTS (rettype)));
3041 : 49 : op = vect_get_new_ssa_name (rettype, vect_simple_var);
3042 : 49 : gimple_call_set_lhs (new_stmt, op);
3043 : 49 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3044 : 49 : op = build1 (VIEW_CONVERT_EXPR, vectype, op);
3045 : 49 : new_stmt = gimple_build_assign (NULL_TREE, VIEW_CONVERT_EXPR, op);
3046 : : }
3047 : :
3048 : 346 : return new_stmt;
3049 : : }
3050 : :
3051 : : /* Build a scatter store call while vectorizing STMT_INFO. Insert new
3052 : : instructions before GSI. GS_INFO describes the scatter store operation.
3053 : : PTR is the base pointer, OFFSET the vectorized offsets and OPRND the
3054 : : vectorized data to store.
3055 : : If the store is conditional, MASK is the vectorized condition, otherwise
3056 : : MASK is null. */
3057 : :
3058 : : static gimple *
3059 : 161 : vect_build_one_scatter_store_call (vec_info *vinfo, stmt_vec_info stmt_info,
3060 : : slp_tree slp_node,
3061 : : gimple_stmt_iterator *gsi,
3062 : : tree decl,
3063 : : tree ptr, tree offset, tree oprnd, tree mask)
3064 : : {
3065 : 161 : tree rettype = TREE_TYPE (TREE_TYPE (decl));
3066 : 161 : tree arglist = TYPE_ARG_TYPES (TREE_TYPE (decl));
3067 : 161 : /* tree ptrtype = TREE_VALUE (arglist); */ arglist = TREE_CHAIN (arglist);
3068 : 161 : tree masktype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
3069 : 161 : tree idxtype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
3070 : 161 : tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
3071 : 161 : tree scaletype = TREE_VALUE (arglist);
3072 : 161 : gcc_checking_assert (TREE_CODE (masktype) == INTEGER_TYPE
3073 : : && TREE_CODE (rettype) == VOID_TYPE);
3074 : :
3075 : 161 : tree mask_arg = NULL_TREE;
3076 : 161 : if (mask)
3077 : : {
3078 : 110 : mask_arg = mask;
3079 : 110 : tree optype = TREE_TYPE (mask_arg);
3080 : 110 : tree utype;
3081 : 110 : if (TYPE_MODE (masktype) == TYPE_MODE (optype))
3082 : : utype = masktype;
3083 : : else
3084 : 8 : utype = lang_hooks.types.type_for_mode (TYPE_MODE (optype), 1);
3085 : 110 : tree var = vect_get_new_ssa_name (utype, vect_scalar_var);
3086 : 110 : mask_arg = build1 (VIEW_CONVERT_EXPR, utype, mask_arg);
3087 : 110 : gassign *new_stmt
3088 : 110 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, mask_arg);
3089 : 110 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3090 : 110 : mask_arg = var;
3091 : 110 : if (!useless_type_conversion_p (masktype, utype))
3092 : : {
3093 : 8 : gcc_assert (TYPE_PRECISION (utype) <= TYPE_PRECISION (masktype));
3094 : 8 : tree var = vect_get_new_ssa_name (masktype, vect_scalar_var);
3095 : 8 : new_stmt = gimple_build_assign (var, NOP_EXPR, mask_arg);
3096 : 8 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3097 : 8 : mask_arg = var;
3098 : : }
3099 : : }
3100 : : else
3101 : : {
3102 : 51 : mask_arg = build_int_cst (masktype, -1);
3103 : 51 : mask_arg = vect_init_vector (vinfo, stmt_info, mask_arg, masktype, NULL);
3104 : : }
3105 : :
3106 : 161 : tree src = oprnd;
3107 : 161 : if (!useless_type_conversion_p (srctype, TREE_TYPE (src)))
3108 : : {
3109 : 0 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (src)),
3110 : : TYPE_VECTOR_SUBPARTS (srctype)));
3111 : 0 : tree var = vect_get_new_ssa_name (srctype, vect_simple_var);
3112 : 0 : src = build1 (VIEW_CONVERT_EXPR, srctype, src);
3113 : 0 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, src);
3114 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3115 : 0 : src = var;
3116 : : }
3117 : :
3118 : 161 : tree op = offset;
3119 : 161 : if (!useless_type_conversion_p (idxtype, TREE_TYPE (op)))
3120 : : {
3121 : 16 : gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (op)),
3122 : : TYPE_VECTOR_SUBPARTS (idxtype)));
3123 : 16 : tree var = vect_get_new_ssa_name (idxtype, vect_simple_var);
3124 : 16 : op = build1 (VIEW_CONVERT_EXPR, idxtype, op);
3125 : 16 : gassign *new_stmt = gimple_build_assign (var, VIEW_CONVERT_EXPR, op);
3126 : 16 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3127 : 16 : op = var;
3128 : : }
3129 : :
3130 : 161 : tree scale = build_int_cst (scaletype, SLP_TREE_GS_SCALE (slp_node));
3131 : 161 : gcall *new_stmt
3132 : 161 : = gimple_build_call (decl, 5, ptr, mask_arg, op, src, scale);
3133 : 161 : return new_stmt;
3134 : : }
3135 : :
3136 : : /* Prepare the base and offset in GS_INFO for vectorization.
3137 : : Set *DATAREF_PTR to the loop-invariant base address and *VEC_OFFSET
3138 : : to the vectorized offset argument for the first copy of STMT_INFO.
3139 : : STMT_INFO is the statement described by GS_INFO and LOOP is the
3140 : : containing loop. */
3141 : :
3142 : : static void
3143 : 1219 : vect_get_gather_scatter_ops (class loop *loop, slp_tree slp_node,
3144 : : tree *dataref_ptr, vec<tree> *vec_offset)
3145 : : {
3146 : 1219 : gimple_seq stmts = NULL;
3147 : 1219 : *dataref_ptr = force_gimple_operand (SLP_TREE_GS_BASE (slp_node),
3148 : : &stmts, true, NULL_TREE);
3149 : 1219 : if (stmts != NULL)
3150 : : {
3151 : 986 : basic_block new_bb;
3152 : 986 : edge pe = loop_preheader_edge (loop);
3153 : 986 : new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
3154 : 986 : gcc_assert (!new_bb);
3155 : : }
3156 : 1219 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_offset);
3157 : 1219 : }
3158 : :
3159 : : /* Prepare to implement a grouped or strided load or store using
3160 : : the gather load or scatter store operation described by GS_INFO.
3161 : : STMT_INFO is the load or store statement.
3162 : :
3163 : : Set *DATAREF_BUMP to the amount that should be added to the base
3164 : : address after each copy of the vectorized statement. Set *VEC_OFFSET
3165 : : to an invariant offset vector in which element I has the value
3166 : : I * DR_STEP / SCALE. */
3167 : :
3168 : : static void
3169 : 0 : vect_get_strided_load_store_ops (stmt_vec_info stmt_info, slp_tree node,
3170 : : tree vectype, tree offset_vectype,
3171 : : loop_vec_info loop_vinfo,
3172 : : gimple_stmt_iterator *gsi,
3173 : : tree *dataref_bump, tree *vec_offset,
3174 : : vec_loop_lens *loop_lens)
3175 : : {
3176 : 0 : struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
3177 : :
3178 : 0 : if (LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo))
3179 : : {
3180 : : /* _31 = .SELECT_VL (ivtmp_29, POLY_INT_CST [4, 4]);
3181 : : ivtmp_8 = _31 * 16 (step in bytes);
3182 : : .MASK_LEN_SCATTER_STORE (vectp_a.9_7, ... );
3183 : : vectp_a.9_26 = vectp_a.9_7 + ivtmp_8; */
3184 : 0 : tree loop_len
3185 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens, 1, vectype, 0, 0);
3186 : 0 : tree tmp
3187 : 0 : = fold_build2 (MULT_EXPR, sizetype,
3188 : : fold_convert (sizetype, unshare_expr (DR_STEP (dr))),
3189 : : loop_len);
3190 : 0 : *dataref_bump = force_gimple_operand_gsi (gsi, tmp, true, NULL_TREE, true,
3191 : : GSI_SAME_STMT);
3192 : : }
3193 : : else
3194 : : {
3195 : 0 : tree bump
3196 : 0 : = size_binop (MULT_EXPR,
3197 : : fold_convert (sizetype, unshare_expr (DR_STEP (dr))),
3198 : : size_int (TYPE_VECTOR_SUBPARTS (vectype)));
3199 : 0 : *dataref_bump = cse_and_gimplify_to_preheader (loop_vinfo, bump);
3200 : : }
3201 : :
3202 : 0 : internal_fn ifn
3203 : 0 : = DR_IS_READ (dr) ? IFN_MASK_LEN_STRIDED_LOAD : IFN_MASK_LEN_STRIDED_STORE;
3204 : 0 : if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
3205 : : {
3206 : 0 : *vec_offset = cse_and_gimplify_to_preheader (loop_vinfo,
3207 : : unshare_expr (DR_STEP (dr)));
3208 : 0 : return;
3209 : : }
3210 : :
3211 : : /* The offset given in GS_INFO can have pointer type, so use the element
3212 : : type of the vector instead. */
3213 : 0 : tree offset_type = TREE_TYPE (offset_vectype);
3214 : :
3215 : : /* Calculate X = DR_STEP / SCALE and convert it to the appropriate type. */
3216 : 0 : tree step = size_binop (EXACT_DIV_EXPR, unshare_expr (DR_STEP (dr)),
3217 : : ssize_int (SLP_TREE_GS_SCALE (node)));
3218 : 0 : step = fold_convert (offset_type, step);
3219 : :
3220 : : /* Create {0, X, X*2, X*3, ...}. */
3221 : 0 : tree offset = fold_build2 (VEC_SERIES_EXPR, offset_vectype,
3222 : : build_zero_cst (offset_type), step);
3223 : 0 : *vec_offset = cse_and_gimplify_to_preheader (loop_vinfo, offset);
3224 : : }
3225 : :
3226 : : /* Prepare the pointer IVs which needs to be updated by a variable amount.
3227 : : Such variable amount is the outcome of .SELECT_VL. In this case, we can
3228 : : allow each iteration process the flexible number of elements as long as
3229 : : the number <= vf elments.
3230 : :
3231 : : Return data reference according to SELECT_VL.
3232 : : If new statements are needed, insert them before GSI. */
3233 : :
3234 : : static tree
3235 : 0 : vect_get_loop_variant_data_ptr_increment (
3236 : : vec_info *vinfo, tree aggr_type, gimple_stmt_iterator *gsi,
3237 : : vec_loop_lens *loop_lens, dr_vec_info *dr_info,
3238 : : vect_memory_access_type memory_access_type)
3239 : : {
3240 : 0 : loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (vinfo);
3241 : 0 : tree step = vect_dr_behavior (vinfo, dr_info)->step;
3242 : :
3243 : : /* gather/scatter never reach here. */
3244 : 0 : gcc_assert (!mat_gather_scatter_p (memory_access_type));
3245 : :
3246 : : /* When we support SELECT_VL pattern, we dynamic adjust
3247 : : the memory address by .SELECT_VL result.
3248 : :
3249 : : The result of .SELECT_VL is the number of elements to
3250 : : be processed of each iteration. So the memory address
3251 : : adjustment operation should be:
3252 : :
3253 : : addr = addr + .SELECT_VL (ARG..) * step;
3254 : : */
3255 : 0 : tree loop_len
3256 : 0 : = vect_get_loop_len (loop_vinfo, gsi, loop_lens, 1, aggr_type, 0, 0);
3257 : 0 : tree len_type = TREE_TYPE (loop_len);
3258 : : /* Since the outcome of .SELECT_VL is element size, we should adjust
3259 : : it into bytesize so that it can be used in address pointer variable
3260 : : amount IVs adjustment. */
3261 : 0 : tree tmp = fold_build2 (MULT_EXPR, len_type, loop_len,
3262 : : wide_int_to_tree (len_type, wi::to_widest (step)));
3263 : 0 : tree bump = make_temp_ssa_name (len_type, NULL, "ivtmp");
3264 : 0 : gassign *assign = gimple_build_assign (bump, tmp);
3265 : 0 : gsi_insert_before (gsi, assign, GSI_SAME_STMT);
3266 : 0 : return bump;
3267 : : }
3268 : :
3269 : : /* Return the amount that should be added to a vector pointer to move
3270 : : to the next or previous copy of AGGR_TYPE. DR_INFO is the data reference
3271 : : being vectorized and MEMORY_ACCESS_TYPE describes the type of
3272 : : vectorization. */
3273 : :
3274 : : static tree
3275 : 696118 : vect_get_data_ptr_increment (vec_info *vinfo, gimple_stmt_iterator *gsi,
3276 : : dr_vec_info *dr_info, tree aggr_type,
3277 : : vect_memory_access_type memory_access_type,
3278 : : vec_loop_lens *loop_lens)
3279 : : {
3280 : 696118 : if (memory_access_type == VMAT_INVARIANT)
3281 : 0 : return size_zero_node;
3282 : :
3283 : 696118 : loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (vinfo);
3284 : 132139 : if (loop_vinfo && LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo))
3285 : 0 : return vect_get_loop_variant_data_ptr_increment (vinfo, aggr_type, gsi,
3286 : : loop_lens, dr_info,
3287 : 0 : memory_access_type);
3288 : :
3289 : 696118 : tree iv_step = TYPE_SIZE_UNIT (aggr_type);
3290 : 696118 : tree step = vect_dr_behavior (vinfo, dr_info)->step;
3291 : 696118 : if (tree_int_cst_sgn (step) == -1)
3292 : 2801 : iv_step = fold_build1 (NEGATE_EXPR, TREE_TYPE (iv_step), iv_step);
3293 : : return iv_step;
3294 : : }
3295 : :
3296 : : /* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64,128}. */
3297 : :
3298 : : static bool
3299 : 206 : vectorizable_bswap (vec_info *vinfo,
3300 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
3301 : : slp_tree slp_node,
3302 : : slp_tree *slp_op,
3303 : : tree vectype_in, stmt_vector_for_cost *cost_vec)
3304 : : {
3305 : 206 : tree op, vectype;
3306 : 206 : gcall *stmt = as_a <gcall *> (stmt_info->stmt);
3307 : :
3308 : 206 : op = gimple_call_arg (stmt, 0);
3309 : 206 : vectype = SLP_TREE_VECTYPE (slp_node);
3310 : 206 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
3311 : :
3312 : 206 : if (TYPE_SIZE (vectype_in) != TYPE_SIZE (vectype))
3313 : : {
3314 : 0 : if (dump_enabled_p ())
3315 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3316 : : "mismatched vector sizes %T and %T\n",
3317 : : vectype_in, vectype);
3318 : 0 : return false;
3319 : : }
3320 : :
3321 : 206 : tree char_vectype = get_same_sized_vectype (char_type_node, vectype_in);
3322 : 206 : if (! char_vectype)
3323 : : return false;
3324 : :
3325 : 206 : poly_uint64 num_bytes = TYPE_VECTOR_SUBPARTS (char_vectype);
3326 : 206 : unsigned word_bytes;
3327 : 206 : if (!constant_multiple_p (num_bytes, nunits, &word_bytes))
3328 : : return false;
3329 : :
3330 : : /* The encoding uses one stepped pattern for each byte in the word. */
3331 : 206 : vec_perm_builder elts (num_bytes, word_bytes, 3);
3332 : 824 : for (unsigned i = 0; i < 3; ++i)
3333 : 3318 : for (unsigned j = 0; j < word_bytes; ++j)
3334 : 2700 : elts.quick_push ((i + 1) * word_bytes - j - 1);
3335 : :
3336 : 206 : vec_perm_indices indices (elts, 1, num_bytes);
3337 : 206 : machine_mode vmode = TYPE_MODE (char_vectype);
3338 : 206 : if (!can_vec_perm_const_p (vmode, vmode, indices))
3339 : : return false;
3340 : :
3341 : 152 : if (cost_vec)
3342 : : {
3343 : 140 : if (!vect_maybe_update_slp_op_vectype (slp_op[0], vectype_in))
3344 : : {
3345 : 0 : if (dump_enabled_p ())
3346 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3347 : : "incompatible vector types for invariants\n");
3348 : 0 : return false;
3349 : : }
3350 : :
3351 : 140 : SLP_TREE_TYPE (slp_node) = call_vec_info_type;
3352 : 140 : DUMP_VECT_SCOPE ("vectorizable_bswap");
3353 : 140 : record_stmt_cost (cost_vec,
3354 : : 1, vector_stmt, slp_node, 0, vect_prologue);
3355 : 140 : record_stmt_cost (cost_vec,
3356 : 140 : vect_get_num_copies (vinfo, slp_node),
3357 : : vec_perm, slp_node, 0, vect_body);
3358 : 140 : return true;
3359 : : }
3360 : :
3361 : 12 : tree bswap_vconst = vec_perm_indices_to_tree (char_vectype, indices);
3362 : :
3363 : : /* Transform. */
3364 : 12 : vec<tree> vec_oprnds = vNULL;
3365 : 12 : vect_get_vec_defs (vinfo, slp_node, op, &vec_oprnds);
3366 : : /* Arguments are ready. create the new vector stmt. */
3367 : 12 : unsigned i;
3368 : 12 : tree vop;
3369 : 24 : FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
3370 : : {
3371 : 12 : gimple *new_stmt;
3372 : 12 : tree tem = make_ssa_name (char_vectype);
3373 : 12 : new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
3374 : : char_vectype, vop));
3375 : 12 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3376 : 12 : tree tem2 = make_ssa_name (char_vectype);
3377 : 12 : new_stmt = gimple_build_assign (tem2, VEC_PERM_EXPR,
3378 : : tem, tem, bswap_vconst);
3379 : 12 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3380 : 12 : tem = make_ssa_name (vectype);
3381 : 12 : new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
3382 : : vectype, tem2));
3383 : 12 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3384 : 12 : slp_node->push_vec_def (new_stmt);
3385 : : }
3386 : :
3387 : 12 : vec_oprnds.release ();
3388 : 12 : return true;
3389 : 206 : }
3390 : :
3391 : : /* Return true if vector types VECTYPE_IN and VECTYPE_OUT have
3392 : : integer elements and if we can narrow VECTYPE_IN to VECTYPE_OUT
3393 : : in a single step. On success, store the binary pack code in
3394 : : *CONVERT_CODE. */
3395 : :
3396 : : static bool
3397 : 156 : simple_integer_narrowing (tree vectype_out, tree vectype_in,
3398 : : code_helper *convert_code)
3399 : : {
3400 : 312 : if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype_out))
3401 : 312 : || !INTEGRAL_TYPE_P (TREE_TYPE (vectype_in)))
3402 : : return false;
3403 : :
3404 : 66 : code_helper code;
3405 : 66 : int multi_step_cvt = 0;
3406 : 66 : auto_vec <tree, 8> interm_types;
3407 : 97 : if (!supportable_narrowing_operation (NOP_EXPR, vectype_out, vectype_in,
3408 : : &code, &multi_step_cvt, &interm_types)
3409 : 66 : || multi_step_cvt)
3410 : 31 : return false;
3411 : :
3412 : 35 : *convert_code = code;
3413 : 35 : return true;
3414 : 66 : }
3415 : :
3416 : : /* Function vectorizable_call.
3417 : :
3418 : : Check if STMT_INFO performs a function call that can be vectorized.
3419 : : If COST_VEC is passed, calculate costs but don't change anything,
3420 : : otherwise, vectorize STMT_INFO: create a vectorized stmt to replace
3421 : : it, and insert it at GSI.
3422 : : Return true if STMT_INFO is vectorizable in this way. */
3423 : :
3424 : : static bool
3425 : 2313921 : vectorizable_call (vec_info *vinfo,
3426 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
3427 : : slp_tree slp_node,
3428 : : stmt_vector_for_cost *cost_vec)
3429 : : {
3430 : 2313921 : gcall *stmt;
3431 : 2313921 : tree vec_dest;
3432 : 2313921 : tree scalar_dest;
3433 : 2313921 : tree op;
3434 : 2313921 : tree vec_oprnd0 = NULL_TREE;
3435 : 2313921 : tree vectype_out, vectype_in;
3436 : 2313921 : poly_uint64 nunits_in;
3437 : 2313921 : poly_uint64 nunits_out;
3438 : 2313921 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
3439 : 2313921 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
3440 : 2313921 : tree fndecl, new_temp, rhs_type;
3441 : 2313921 : enum vect_def_type dt[4]
3442 : : = { vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type,
3443 : : vect_unknown_def_type };
3444 : 2313921 : tree vectypes[ARRAY_SIZE (dt)] = {};
3445 : 2313921 : slp_tree slp_op[ARRAY_SIZE (dt)] = {};
3446 : 2313921 : auto_vec<tree, 8> vargs;
3447 : 2313921 : enum { NARROW, NONE, WIDEN } modifier;
3448 : 2313921 : size_t i, nargs;
3449 : 2313921 : tree clz_ctz_arg1 = NULL_TREE;
3450 : :
3451 : 2313921 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
3452 : : return false;
3453 : :
3454 : 2313921 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
3455 : 176586 : && cost_vec)
3456 : : return false;
3457 : :
3458 : : /* Is STMT_INFO a vectorizable call? */
3459 : 2323465 : stmt = dyn_cast <gcall *> (stmt_info->stmt);
3460 : 19319 : if (!stmt)
3461 : : return false;
3462 : :
3463 : 19319 : if (gimple_call_internal_p (stmt)
3464 : 19319 : && (internal_load_fn_p (gimple_call_internal_fn (stmt))
3465 : 11919 : || internal_store_fn_p (gimple_call_internal_fn (stmt))))
3466 : : /* Handled by vectorizable_load and vectorizable_store. */
3467 : 2666 : return false;
3468 : :
3469 : 16653 : if (gimple_call_lhs (stmt) == NULL_TREE
3470 : 16653 : || TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME)
3471 : : return false;
3472 : :
3473 : 16647 : gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
3474 : :
3475 : 16647 : vectype_out = SLP_TREE_VECTYPE (slp_node);
3476 : :
3477 : : /* Process function arguments. */
3478 : 16647 : rhs_type = NULL_TREE;
3479 : 16647 : vectype_in = NULL_TREE;
3480 : 16647 : nargs = gimple_call_num_args (stmt);
3481 : :
3482 : : /* Bail out if the function has more than four arguments, we do not have
3483 : : interesting builtin functions to vectorize with more than two arguments
3484 : : except for fma. No arguments is also not good. */
3485 : 16647 : if (nargs == 0 || nargs > 4)
3486 : : return false;
3487 : :
3488 : : /* Ignore the arguments of IFN_GOMP_SIMD_LANE, they are magic. */
3489 : 16567 : combined_fn cfn = gimple_call_combined_fn (stmt);
3490 : 16567 : if (cfn == CFN_GOMP_SIMD_LANE)
3491 : : {
3492 : 3207 : nargs = 0;
3493 : 3207 : rhs_type = unsigned_type_node;
3494 : : }
3495 : : /* Similarly pretend IFN_CLZ and IFN_CTZ only has one argument, the second
3496 : : argument just says whether it is well-defined at zero or not and what
3497 : : value should be returned for it. */
3498 : 16567 : if ((cfn == CFN_CLZ || cfn == CFN_CTZ) && nargs == 2)
3499 : : {
3500 : 118 : nargs = 1;
3501 : 118 : clz_ctz_arg1 = gimple_call_arg (stmt, 1);
3502 : : }
3503 : :
3504 : 16567 : int mask_opno = -1;
3505 : 16567 : if (internal_fn_p (cfn))
3506 : : {
3507 : : /* We can only handle direct internal masked calls here,
3508 : : vectorizable_simd_clone_call is for the rest. */
3509 : 13685 : if (cfn == CFN_MASK_CALL)
3510 : : return false;
3511 : 13531 : mask_opno = internal_fn_mask_index (as_internal_fn (cfn));
3512 : : }
3513 : :
3514 : 45490 : for (i = 0; i < nargs; i++)
3515 : : {
3516 : 30156 : if ((int) i == mask_opno)
3517 : : {
3518 : 3992 : if (!vect_check_scalar_mask (vinfo, slp_node, mask_opno,
3519 : : &slp_op[i], &dt[i], &vectypes[i]))
3520 : : return false;
3521 : 3992 : continue;
3522 : : }
3523 : :
3524 : 26164 : if (!vect_is_simple_use (vinfo, slp_node,
3525 : : i, &op, &slp_op[i], &dt[i], &vectypes[i]))
3526 : : {
3527 : 0 : if (dump_enabled_p ())
3528 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3529 : : "use not simple.\n");
3530 : 0 : return false;
3531 : : }
3532 : :
3533 : : /* We can only handle calls with arguments of the same type. */
3534 : 26164 : if (rhs_type
3535 : 26164 : && !types_compatible_p (rhs_type, TREE_TYPE (op)))
3536 : : {
3537 : 1079 : if (dump_enabled_p ())
3538 : 200 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3539 : : "argument types differ.\n");
3540 : 1079 : return false;
3541 : : }
3542 : 25085 : if (!rhs_type)
3543 : 13206 : rhs_type = TREE_TYPE (op);
3544 : :
3545 : 25085 : if (!vectype_in)
3546 : 13677 : vectype_in = vectypes[i];
3547 : 11408 : else if (vectypes[i]
3548 : 11408 : && !types_compatible_p (vectypes[i], vectype_in))
3549 : : {
3550 : 0 : if (dump_enabled_p ())
3551 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3552 : : "argument vector types differ.\n");
3553 : 0 : return false;
3554 : : }
3555 : : }
3556 : : /* If all arguments are external or constant defs, infer the vector type
3557 : : from the scalar type. */
3558 : 15334 : if (!vectype_in)
3559 : 5535 : vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
3560 : 15334 : if (!cost_vec)
3561 : 4200 : gcc_assert (vectype_in);
3562 : 11134 : if (!vectype_in)
3563 : : {
3564 : 1056 : if (dump_enabled_p ())
3565 : 4 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3566 : : "no vectype for scalar type %T\n", rhs_type);
3567 : :
3568 : 1056 : return false;
3569 : : }
3570 : :
3571 : 28556 : if (VECTOR_BOOLEAN_TYPE_P (vectype_out)
3572 : 14278 : != VECTOR_BOOLEAN_TYPE_P (vectype_in))
3573 : : {
3574 : 12 : if (dump_enabled_p ())
3575 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3576 : : "mixed mask and nonmask vector types\n");
3577 : 12 : return false;
3578 : : }
3579 : :
3580 : 14266 : if (vect_emulated_vector_p (vectype_in)
3581 : 14266 : || vect_emulated_vector_p (vectype_out))
3582 : : {
3583 : 0 : if (dump_enabled_p ())
3584 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3585 : : "use emulated vector type for call\n");
3586 : 0 : return false;
3587 : : }
3588 : :
3589 : : /* FORNOW */
3590 : 14266 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
3591 : 14266 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
3592 : 14266 : if (known_eq (nunits_in * 2, nunits_out))
3593 : : modifier = NARROW;
3594 : 13724 : else if (known_eq (nunits_out, nunits_in))
3595 : : modifier = NONE;
3596 : 45 : else if (known_eq (nunits_out * 2, nunits_in))
3597 : : modifier = WIDEN;
3598 : : else
3599 : : return false;
3600 : :
3601 : : /* We only handle functions that do not read or clobber memory. */
3602 : 28532 : if (gimple_vuse (stmt))
3603 : : {
3604 : 1230 : if (dump_enabled_p ())
3605 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3606 : : "function reads from or writes to memory.\n");
3607 : 1230 : return false;
3608 : : }
3609 : :
3610 : : /* For now, we only vectorize functions if a target specific builtin
3611 : : is available. TODO -- in some cases, it might be profitable to
3612 : : insert the calls for pieces of the vector, in order to be able
3613 : : to vectorize other operations in the loop. */
3614 : 13036 : fndecl = NULL_TREE;
3615 : 13036 : internal_fn ifn = IFN_LAST;
3616 : 13036 : tree callee = gimple_call_fndecl (stmt);
3617 : :
3618 : : /* First try using an internal function. */
3619 : 13036 : code_helper convert_code = MAX_TREE_CODES;
3620 : 13036 : if (cfn != CFN_LAST
3621 : 13036 : && (modifier == NONE
3622 : 168 : || (modifier == NARROW
3623 : 156 : && simple_integer_narrowing (vectype_out, vectype_in,
3624 : : &convert_code))))
3625 : 12086 : ifn = vectorizable_internal_function (cfn, callee, vectype_out,
3626 : : vectype_in);
3627 : :
3628 : : /* If that fails, try asking for a target-specific built-in function. */
3629 : 12086 : if (ifn == IFN_LAST)
3630 : : {
3631 : 6968 : if (cfn != CFN_LAST)
3632 : 6151 : fndecl = targetm.vectorize.builtin_vectorized_function
3633 : 6151 : (cfn, vectype_out, vectype_in);
3634 : 817 : else if (callee && fndecl_built_in_p (callee, BUILT_IN_MD))
3635 : 24 : fndecl = targetm.vectorize.builtin_md_vectorized_function
3636 : 24 : (callee, vectype_out, vectype_in);
3637 : : }
3638 : :
3639 : 13036 : if (ifn == IFN_LAST && !fndecl)
3640 : : {
3641 : 6674 : if (cfn == CFN_GOMP_SIMD_LANE
3642 : 3207 : && SLP_TREE_LANES (slp_node) == 1
3643 : 3207 : && loop_vinfo
3644 : 3207 : && LOOP_VINFO_LOOP (loop_vinfo)->simduid
3645 : 3207 : && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME
3646 : 13088 : && LOOP_VINFO_LOOP (loop_vinfo)->simduid
3647 : 3207 : == SSA_NAME_VAR (gimple_call_arg (stmt, 0)))
3648 : : {
3649 : : /* We can handle IFN_GOMP_SIMD_LANE by returning a
3650 : : { 0, 1, 2, ... vf - 1 } vector. */
3651 : 3207 : gcc_assert (nargs == 0);
3652 : : }
3653 : 3467 : else if (modifier == NONE
3654 : 3467 : && (gimple_call_builtin_p (stmt, BUILT_IN_BSWAP16)
3655 : 3137 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP32)
3656 : 2989 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64)
3657 : 2957 : || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP128)))
3658 : 206 : return vectorizable_bswap (vinfo, stmt_info, gsi, slp_node,
3659 : 206 : slp_op, vectype_in, cost_vec);
3660 : : else
3661 : : {
3662 : 3261 : if (dump_enabled_p ())
3663 : 238 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3664 : : "function is not vectorizable.\n");
3665 : 3261 : return false;
3666 : : }
3667 : : }
3668 : :
3669 : 9569 : int reduc_idx = SLP_TREE_REDUC_IDX (slp_node);
3670 : 9569 : internal_fn cond_fn = (internal_fn_mask_index (ifn) != -1
3671 : 9569 : ? ifn : get_conditional_internal_fn (ifn));
3672 : 9569 : internal_fn cond_len_fn = get_len_internal_fn (ifn);
3673 : 9569 : int len_opno = internal_fn_len_index (cond_len_fn);
3674 : 9569 : vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL);
3675 : 7715 : vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL);
3676 : 9569 : unsigned int nvectors = vect_get_num_copies (vinfo, slp_node);
3677 : 9569 : if (cost_vec) /* transformation not required. */
3678 : : {
3679 : 16169 : for (i = 0; i < nargs; ++i)
3680 : 10788 : if (!vect_maybe_update_slp_op_vectype (slp_op[i],
3681 : 10788 : vectypes[i]
3682 : : ? vectypes[i] : vectype_in))
3683 : : {
3684 : 0 : if (dump_enabled_p ())
3685 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3686 : : "incompatible vector types for invariants\n");
3687 : 0 : return false;
3688 : : }
3689 : 5381 : SLP_TREE_TYPE (slp_node) = call_vec_info_type;
3690 : 5381 : DUMP_VECT_SCOPE ("vectorizable_call");
3691 : 5381 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
3692 : :
3693 : 5381 : if (loop_vinfo
3694 : 4447 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
3695 : 3117 : && (reduc_idx >= 0 || mask_opno >= 0))
3696 : : {
3697 : 1812 : if (reduc_idx >= 0
3698 : 1440 : && (cond_fn == IFN_LAST
3699 : 1440 : || !direct_internal_fn_supported_p (cond_fn, vectype_out,
3700 : : OPTIMIZE_FOR_SPEED))
3701 : 1824 : && (cond_len_fn == IFN_LAST
3702 : 0 : || !direct_internal_fn_supported_p (cond_len_fn, vectype_out,
3703 : : OPTIMIZE_FOR_SPEED)))
3704 : : {
3705 : 12 : if (dump_enabled_p ())
3706 : 8 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3707 : : "can't use a fully-masked loop because no"
3708 : : " conditional operation is available.\n");
3709 : 12 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
3710 : : }
3711 : : else
3712 : : {
3713 : 1800 : tree scalar_mask = NULL_TREE;
3714 : 1800 : if (mask_opno >= 0)
3715 : 1800 : scalar_mask = gimple_call_arg (stmt_info->stmt, mask_opno);
3716 : 1800 : if (cond_len_fn != IFN_LAST
3717 : 1800 : && direct_internal_fn_supported_p (cond_len_fn, vectype_out,
3718 : : OPTIMIZE_FOR_SPEED))
3719 : 0 : vect_record_loop_len (loop_vinfo, lens, nvectors, vectype_out,
3720 : : 1);
3721 : : else
3722 : 1800 : vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype_out,
3723 : : scalar_mask);
3724 : : }
3725 : : }
3726 : 5381 : return true;
3727 : : }
3728 : :
3729 : : /* Transform. */
3730 : :
3731 : 4188 : if (dump_enabled_p ())
3732 : 416 : dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n");
3733 : :
3734 : : /* Handle def. */
3735 : 4188 : scalar_dest = gimple_call_lhs (stmt);
3736 : 4188 : vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
3737 : :
3738 : 4188 : bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
3739 : 3268 : bool len_loop_p = loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
3740 : 4188 : unsigned int vect_nargs = nargs;
3741 : 4188 : if (len_loop_p)
3742 : : {
3743 : 0 : if (len_opno >= 0)
3744 : : {
3745 : 0 : ifn = cond_len_fn;
3746 : : /* COND_* -> COND_LEN_* takes 2 extra arguments:LEN,BIAS. */
3747 : 0 : vect_nargs += 2;
3748 : : }
3749 : 0 : else if (reduc_idx >= 0)
3750 : 0 : gcc_unreachable ();
3751 : : }
3752 : 4188 : else if (masked_loop_p && mask_opno == -1 && reduc_idx >= 0)
3753 : : {
3754 : 0 : ifn = cond_fn;
3755 : 0 : vect_nargs += 2;
3756 : : }
3757 : 4188 : if (clz_ctz_arg1)
3758 : 59 : ++vect_nargs;
3759 : :
3760 : 4188 : if (modifier == NONE || ifn != IFN_LAST)
3761 : : {
3762 : 4156 : tree prev_res = NULL_TREE;
3763 : 4156 : vargs.safe_grow (vect_nargs, true);
3764 : 4156 : auto_vec<vec<tree> > vec_defs (nargs);
3765 : :
3766 : : /* Build argument list for the vectorized call. */
3767 : 4156 : if (cfn == CFN_GOMP_SIMD_LANE)
3768 : : {
3769 : 3308 : for (i = 0; i < nvectors; ++i)
3770 : : {
3771 : : /* ??? For multi-lane SLP we'd need to build
3772 : : { 0, 0, .., 1, 1, ... }. */
3773 : 1708 : tree cst = build_index_vector (vectype_out,
3774 : : i * nunits_out, 1);
3775 : 1708 : tree new_var
3776 : 1708 : = vect_get_new_ssa_name (vectype_out, vect_simple_var, "cst_");
3777 : 1708 : gimple *init_stmt = gimple_build_assign (new_var, cst);
3778 : 1708 : vect_init_vector_1 (vinfo, stmt_info, init_stmt, NULL);
3779 : 1708 : new_temp = make_ssa_name (vec_dest);
3780 : 1708 : gimple *new_stmt = gimple_build_assign (new_temp, new_var);
3781 : 1708 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3782 : 1708 : slp_node->push_vec_def (new_stmt);
3783 : : }
3784 : : }
3785 : : else
3786 : : {
3787 : 2556 : vec<tree> vec_oprnds0;
3788 : 2556 : vect_get_slp_defs (vinfo, slp_node, &vec_defs);
3789 : 2556 : vec_oprnds0 = vec_defs[0];
3790 : :
3791 : : /* Arguments are ready. Create the new vector stmt. */
3792 : 5259 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_oprnd0)
3793 : : {
3794 : 2703 : int varg = 0;
3795 : : /* Add the mask if necessary. */
3796 : 2703 : if (masked_loop_p && mask_opno == -1 && reduc_idx >= 0)
3797 : : {
3798 : 0 : gcc_assert (internal_fn_mask_index (ifn) == varg);
3799 : 0 : unsigned int vec_num = vec_oprnds0.length ();
3800 : 0 : vargs[varg++] = vect_get_loop_mask (loop_vinfo, gsi, masks,
3801 : : vec_num, vectype_out, i);
3802 : : }
3803 : : size_t k;
3804 : 9679 : for (k = 0; k < nargs; k++)
3805 : : {
3806 : 6976 : vec<tree> vec_oprndsk = vec_defs[k];
3807 : 6976 : vargs[varg++] = vec_oprndsk[i];
3808 : : }
3809 : : /* Add the else value if necessary. */
3810 : 2703 : if (masked_loop_p && mask_opno == -1 && reduc_idx >= 0)
3811 : : {
3812 : 0 : gcc_assert (internal_fn_else_index (ifn) == varg);
3813 : 0 : vargs[varg++] = vargs[reduc_idx + 1];
3814 : : }
3815 : 2703 : if (clz_ctz_arg1)
3816 : 59 : vargs[varg++] = clz_ctz_arg1;
3817 : :
3818 : 2703 : gimple *new_stmt;
3819 : 2703 : if (modifier == NARROW)
3820 : : {
3821 : : /* We don't define any narrowing conditional functions
3822 : : at present. */
3823 : 0 : gcc_assert (mask_opno < 0);
3824 : 0 : tree half_res = make_ssa_name (vectype_in);
3825 : 0 : gcall *call = gimple_build_call_internal_vec (ifn, vargs);
3826 : 0 : gimple_call_set_lhs (call, half_res);
3827 : 0 : gimple_call_set_nothrow (call, true);
3828 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3829 : 0 : if ((i & 1) == 0)
3830 : : {
3831 : 0 : prev_res = half_res;
3832 : 0 : continue;
3833 : : }
3834 : 0 : new_temp = make_ssa_name (vec_dest);
3835 : 0 : new_stmt = vect_gimple_build (new_temp, convert_code,
3836 : : prev_res, half_res);
3837 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
3838 : : }
3839 : : else
3840 : : {
3841 : 2703 : if (len_opno >= 0 && len_loop_p)
3842 : : {
3843 : 0 : unsigned int vec_num = vec_oprnds0.length ();
3844 : 0 : tree len = vect_get_loop_len (loop_vinfo, gsi, lens,
3845 : : vec_num, vectype_out, i, 1);
3846 : 0 : signed char biasval
3847 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
3848 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
3849 : 0 : vargs[len_opno] = len;
3850 : 0 : vargs[len_opno + 1] = bias;
3851 : : }
3852 : 2703 : else if (mask_opno >= 0 && masked_loop_p)
3853 : : {
3854 : 36 : unsigned int vec_num = vec_oprnds0.length ();
3855 : 36 : tree mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
3856 : : vec_num, vectype_out, i);
3857 : 36 : vargs[mask_opno]
3858 : 72 : = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
3859 : 36 : vargs[mask_opno], gsi);
3860 : : }
3861 : :
3862 : 2703 : gcall *call;
3863 : 2703 : if (ifn != IFN_LAST)
3864 : 2622 : call = gimple_build_call_internal_vec (ifn, vargs);
3865 : : else
3866 : 81 : call = gimple_build_call_vec (fndecl, vargs);
3867 : 2703 : new_temp = make_ssa_name (vec_dest, call);
3868 : 2703 : gimple_call_set_lhs (call, new_temp);
3869 : 2703 : gimple_call_set_nothrow (call, true);
3870 : 2703 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3871 : 2703 : new_stmt = call;
3872 : : }
3873 : 2703 : slp_node->push_vec_def (new_stmt);
3874 : : }
3875 : : }
3876 : :
3877 : 10782 : for (i = 0; i < nargs; i++)
3878 : : {
3879 : 6626 : vec<tree> vec_oprndsi = vec_defs[i];
3880 : 6626 : vec_oprndsi.release ();
3881 : : }
3882 : 4156 : }
3883 : 32 : else if (modifier == NARROW)
3884 : : {
3885 : 32 : auto_vec<vec<tree> > vec_defs (nargs);
3886 : : /* We don't define any narrowing conditional functions at present. */
3887 : 32 : gcc_assert (mask_opno < 0);
3888 : :
3889 : : /* Build argument list for the vectorized call. */
3890 : 32 : vargs.create (nargs * 2);
3891 : :
3892 : 32 : vect_get_slp_defs (vinfo, slp_node, &vec_defs);
3893 : 32 : vec<tree> vec_oprnds0 = vec_defs[0];
3894 : :
3895 : : /* Arguments are ready. Create the new vector stmt. */
3896 : 64 : for (i = 0; vec_oprnds0.iterate (i, &vec_oprnd0); i += 2)
3897 : : {
3898 : 32 : size_t k;
3899 : 32 : vargs.truncate (0);
3900 : 64 : for (k = 0; k < nargs; k++)
3901 : : {
3902 : 32 : vec<tree> vec_oprndsk = vec_defs[k];
3903 : 32 : vargs.quick_push (vec_oprndsk[i]);
3904 : 32 : vargs.quick_push (vec_oprndsk[i + 1]);
3905 : : }
3906 : 32 : gcall *call;
3907 : 32 : if (ifn != IFN_LAST)
3908 : : call = gimple_build_call_internal_vec (ifn, vargs);
3909 : : else
3910 : 32 : call = gimple_build_call_vec (fndecl, vargs);
3911 : 32 : new_temp = make_ssa_name (vec_dest, call);
3912 : 32 : gimple_call_set_lhs (call, new_temp);
3913 : 32 : gimple_call_set_nothrow (call, true);
3914 : 32 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
3915 : 32 : slp_node->push_vec_def (call);
3916 : : }
3917 : :
3918 : 64 : for (i = 0; i < nargs; i++)
3919 : : {
3920 : 32 : vec<tree> vec_oprndsi = vec_defs[i];
3921 : 32 : vec_oprndsi.release ();
3922 : : }
3923 : 32 : }
3924 : : else
3925 : : /* No current target implements this case. */
3926 : : return false;
3927 : :
3928 : 4188 : vargs.release ();
3929 : :
3930 : 4188 : return true;
3931 : 2313921 : }
3932 : :
3933 : :
3934 : : struct simd_call_arg_info
3935 : : {
3936 : : tree vectype;
3937 : : tree op;
3938 : : HOST_WIDE_INT linear_step;
3939 : : enum vect_def_type dt;
3940 : : unsigned int align;
3941 : : bool simd_lane_linear;
3942 : : };
3943 : :
3944 : : /* Helper function of vectorizable_simd_clone_call. If OP, an SSA_NAME,
3945 : : is linear within simd lane (but not within whole loop), note it in
3946 : : *ARGINFO. */
3947 : :
3948 : : static void
3949 : 15 : vect_simd_lane_linear (tree op, class loop *loop,
3950 : : struct simd_call_arg_info *arginfo)
3951 : : {
3952 : 15 : gimple *def_stmt = SSA_NAME_DEF_STMT (op);
3953 : :
3954 : 15 : if (!is_gimple_assign (def_stmt)
3955 : 15 : || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR
3956 : 27 : || !is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt)))
3957 : 3 : return;
3958 : :
3959 : 12 : tree base = gimple_assign_rhs1 (def_stmt);
3960 : 12 : HOST_WIDE_INT linear_step = 0;
3961 : 12 : tree v = gimple_assign_rhs2 (def_stmt);
3962 : 48 : while (TREE_CODE (v) == SSA_NAME)
3963 : : {
3964 : 36 : tree t;
3965 : 36 : def_stmt = SSA_NAME_DEF_STMT (v);
3966 : 36 : if (is_gimple_assign (def_stmt))
3967 : 24 : switch (gimple_assign_rhs_code (def_stmt))
3968 : : {
3969 : 0 : case PLUS_EXPR:
3970 : 0 : t = gimple_assign_rhs2 (def_stmt);
3971 : 0 : if (linear_step || TREE_CODE (t) != INTEGER_CST)
3972 : : return;
3973 : 0 : base = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, t);
3974 : 0 : v = gimple_assign_rhs1 (def_stmt);
3975 : 0 : continue;
3976 : 12 : case MULT_EXPR:
3977 : 12 : t = gimple_assign_rhs2 (def_stmt);
3978 : 12 : if (linear_step || !tree_fits_shwi_p (t) || integer_zerop (t))
3979 : 0 : return;
3980 : 12 : linear_step = tree_to_shwi (t);
3981 : 12 : v = gimple_assign_rhs1 (def_stmt);
3982 : 12 : continue;
3983 : 12 : CASE_CONVERT:
3984 : 12 : t = gimple_assign_rhs1 (def_stmt);
3985 : 12 : if (TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE
3986 : 12 : || (TYPE_PRECISION (TREE_TYPE (v))
3987 : 12 : < TYPE_PRECISION (TREE_TYPE (t))))
3988 : : return;
3989 : 12 : if (!linear_step)
3990 : 0 : linear_step = 1;
3991 : 12 : v = t;
3992 : 12 : continue;
3993 : : default:
3994 : : return;
3995 : : }
3996 : 12 : else if (gimple_call_internal_p (def_stmt, IFN_GOMP_SIMD_LANE)
3997 : 12 : && loop->simduid
3998 : 12 : && TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME
3999 : 24 : && (SSA_NAME_VAR (gimple_call_arg (def_stmt, 0))
4000 : : == loop->simduid))
4001 : : {
4002 : 12 : if (!linear_step)
4003 : 0 : linear_step = 1;
4004 : 12 : arginfo->linear_step = linear_step;
4005 : 12 : arginfo->op = base;
4006 : 12 : arginfo->simd_lane_linear = true;
4007 : 12 : return;
4008 : : }
4009 : : }
4010 : : }
4011 : :
4012 : : /* Function vectorizable_simd_clone_call.
4013 : :
4014 : : Check if STMT_INFO performs a function call that can be vectorized
4015 : : by calling a simd clone of the function.
4016 : : If COST_VEC is passed, calculate costs but don't change anything,
4017 : : otherwise, vectorize STMT_INFO: create a vectorized stmt to replace
4018 : : it, and insert it at GSI.
4019 : : Return true if STMT_INFO is vectorizable in this way. */
4020 : :
4021 : : static bool
4022 : 2304552 : vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
4023 : : gimple_stmt_iterator *gsi,
4024 : : slp_tree slp_node,
4025 : : stmt_vector_for_cost *cost_vec)
4026 : : {
4027 : 2304552 : tree vec_dest;
4028 : 2304552 : tree scalar_dest;
4029 : 2304552 : tree vec_oprnd0 = NULL_TREE;
4030 : 2304552 : tree vectype;
4031 : 2304552 : poly_uint64 nunits;
4032 : 2304552 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
4033 : 2304552 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
4034 : 2304552 : class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
4035 : 2304552 : tree fndecl, new_temp;
4036 : 2304552 : int j;
4037 : 2304552 : auto_vec<simd_call_arg_info> arginfo;
4038 : 2304552 : vec<tree> vargs = vNULL;
4039 : 2304552 : size_t i, nargs;
4040 : 2304552 : tree rtype, ratype;
4041 : 2304552 : vec<constructor_elt, va_gc> *ret_ctor_elts = NULL;
4042 : 2304552 : int masked_call_offset = 0;
4043 : :
4044 : : /* Is STMT a vectorizable call? */
4045 : 2304552 : gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt);
4046 : 10876 : if (!stmt)
4047 : : return false;
4048 : :
4049 : 10876 : fndecl = gimple_call_fndecl (stmt);
4050 : 10876 : if (fndecl == NULL_TREE
4051 : 10876 : && gimple_call_internal_p (stmt, IFN_MASK_CALL))
4052 : : {
4053 : 220 : fndecl = gimple_call_arg (stmt, 0);
4054 : 220 : gcc_checking_assert (TREE_CODE (fndecl) == ADDR_EXPR);
4055 : 220 : fndecl = TREE_OPERAND (fndecl, 0);
4056 : 220 : gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
4057 : : masked_call_offset = 1;
4058 : : }
4059 : 10656 : if (fndecl == NULL_TREE)
4060 : : return false;
4061 : :
4062 : 4677 : struct cgraph_node *node = cgraph_node::get (fndecl);
4063 : 4677 : if (node == NULL || node->simd_clones == NULL)
4064 : : return false;
4065 : :
4066 : 1441 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
4067 : : return false;
4068 : :
4069 : 1441 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
4070 : 0 : && cost_vec)
4071 : : return false;
4072 : :
4073 : 1441 : if (gimple_call_lhs (stmt)
4074 : 1441 : && TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME)
4075 : : return false;
4076 : :
4077 : 1441 : gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
4078 : :
4079 : 1441 : vectype = SLP_TREE_VECTYPE (slp_node);
4080 : :
4081 : 2304616 : if (loop_vinfo && nested_in_vect_loop_p (loop, stmt_info))
4082 : : return false;
4083 : :
4084 : : /* Process function arguments. */
4085 : 1441 : nargs = gimple_call_num_args (stmt) - masked_call_offset;
4086 : :
4087 : : /* Bail out if the function has zero arguments. */
4088 : 1441 : if (nargs == 0)
4089 : : return false;
4090 : :
4091 : 1377 : vect_simd_clone_data _data;
4092 : 1377 : vect_simd_clone_data &data = slp_node->get_data (_data);
4093 : 1377 : vec<tree>& simd_clone_info = data.simd_clone_info;
4094 : 1377 : arginfo.reserve (nargs, true);
4095 : 1377 : auto_vec<slp_tree> slp_op;
4096 : 1377 : slp_op.safe_grow_cleared (nargs);
4097 : :
4098 : 3967 : for (i = 0; i < nargs; i++)
4099 : : {
4100 : 2590 : simd_call_arg_info thisarginfo;
4101 : 2590 : affine_iv iv;
4102 : 2590 : tree op;
4103 : :
4104 : 2590 : thisarginfo.linear_step = 0;
4105 : 2590 : thisarginfo.align = 0;
4106 : 2590 : thisarginfo.op = NULL_TREE;
4107 : 2590 : thisarginfo.simd_lane_linear = false;
4108 : :
4109 : 5180 : int op_no = vect_slp_child_index_for_operand (stmt,
4110 : 2590 : i + masked_call_offset,
4111 : : false);
4112 : 5180 : if (!vect_is_simple_use (vinfo, slp_node,
4113 : 2590 : op_no, &op, &slp_op[i],
4114 : : &thisarginfo.dt, &thisarginfo.vectype)
4115 : 2590 : || thisarginfo.dt == vect_uninitialized_def)
4116 : : {
4117 : 0 : if (dump_enabled_p ())
4118 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4119 : : "use not simple.\n");
4120 : 0 : return false;
4121 : : }
4122 : :
4123 : 2590 : if (thisarginfo.dt == vect_constant_def
4124 : 2590 : || thisarginfo.dt == vect_external_def)
4125 : : {
4126 : : /* With SLP we determine the vector type of constants/externals
4127 : : at analysis time, handling conflicts via
4128 : : vect_maybe_update_slp_op_vectype. At transform time
4129 : : we have a vector type recorded for SLP. */
4130 : 696 : gcc_assert (cost_vec
4131 : : || thisarginfo.vectype != NULL_TREE);
4132 : : if (cost_vec)
4133 : 566 : thisarginfo.vectype = get_vectype_for_scalar_type (vinfo,
4134 : 566 : TREE_TYPE (op),
4135 : : slp_node);
4136 : : }
4137 : : else
4138 : 1894 : gcc_assert (thisarginfo.vectype != NULL_TREE);
4139 : :
4140 : : /* For linear arguments, the analyze phase should have saved
4141 : : the base and step. */
4142 : 2460 : if (!cost_vec
4143 : 1572 : && i * 3 + 4 <= simd_clone_info.length ()
4144 : 2670 : && simd_clone_info[i * 3 + 2])
4145 : : {
4146 : 118 : thisarginfo.linear_step = tree_to_shwi (simd_clone_info[i * 3 + 2]);
4147 : 118 : thisarginfo.op = simd_clone_info[i * 3 + 1];
4148 : 118 : thisarginfo.simd_lane_linear
4149 : 118 : = (simd_clone_info[i * 3 + 3] == boolean_true_node);
4150 : : /* If loop has been peeled for alignment, we need to adjust it. */
4151 : 118 : tree n1 = LOOP_VINFO_NITERS_UNCHANGED (loop_vinfo);
4152 : 118 : tree n2 = LOOP_VINFO_NITERS (loop_vinfo);
4153 : 118 : if (n1 != n2 && !thisarginfo.simd_lane_linear)
4154 : : {
4155 : 0 : tree bias = fold_build2 (MINUS_EXPR, TREE_TYPE (n1), n1, n2);
4156 : 0 : tree step = simd_clone_info[i * 3 + 2];
4157 : 0 : tree opt = TREE_TYPE (thisarginfo.op);
4158 : 0 : bias = fold_convert (TREE_TYPE (step), bias);
4159 : 0 : bias = fold_build2 (MULT_EXPR, TREE_TYPE (step), bias, step);
4160 : 0 : thisarginfo.op
4161 : 0 : = fold_build2 (POINTER_TYPE_P (opt)
4162 : : ? POINTER_PLUS_EXPR : PLUS_EXPR, opt,
4163 : : thisarginfo.op, bias);
4164 : : }
4165 : : }
4166 : 2472 : else if (cost_vec
4167 : 1804 : && thisarginfo.dt != vect_constant_def
4168 : 1682 : && thisarginfo.dt != vect_external_def
4169 : 1238 : && loop_vinfo
4170 : 1235 : && SLP_TREE_LANES (slp_node) == 1
4171 : 1211 : && TREE_CODE (op) == SSA_NAME
4172 : 2422 : && simple_iv (loop, loop_containing_stmt (stmt), op,
4173 : : &iv, false)
4174 : 2676 : && tree_fits_shwi_p (iv.step))
4175 : : {
4176 : 204 : thisarginfo.linear_step = tree_to_shwi (iv.step);
4177 : 204 : thisarginfo.op = iv.base;
4178 : : }
4179 : 2268 : else if ((thisarginfo.dt == vect_constant_def
4180 : 2268 : || thisarginfo.dt == vect_external_def)
4181 : 696 : && SLP_TREE_LANES (slp_node) == 1
4182 : 2569 : && POINTER_TYPE_P (TREE_TYPE (op)))
4183 : 86 : thisarginfo.align = get_pointer_alignment (op) / BITS_PER_UNIT;
4184 : : /* Addresses of array elements indexed by GOMP_SIMD_LANE are
4185 : : linear too. */
4186 : 2590 : if (SLP_TREE_LANES (slp_node) == 1
4187 : 2152 : && POINTER_TYPE_P (TREE_TYPE (op))
4188 : 196 : && !thisarginfo.linear_step
4189 : 112 : && cost_vec
4190 : 58 : && thisarginfo.dt != vect_constant_def
4191 : 58 : && thisarginfo.dt != vect_external_def
4192 : 15 : && loop_vinfo
4193 : 2605 : && TREE_CODE (op) == SSA_NAME)
4194 : 15 : vect_simd_lane_linear (op, loop, &thisarginfo);
4195 : :
4196 : 2590 : if (!vectype)
4197 : 12 : vectype = thisarginfo.vectype;
4198 : 2590 : arginfo.quick_push (thisarginfo);
4199 : : }
4200 : :
4201 : 1377 : poly_uint64 vf = loop_vinfo ? LOOP_VINFO_VECT_FACTOR (loop_vinfo) : 1;
4202 : 1377 : unsigned group_size = SLP_TREE_LANES (slp_node);
4203 : 1377 : unsigned int badness = 0;
4204 : 1377 : unsigned int badness_inbranch = 0;
4205 : 1377 : struct cgraph_node *bestn = NULL;
4206 : 1377 : struct cgraph_node *bestn_inbranch = NULL;
4207 : 1377 : if (!cost_vec)
4208 : 352 : bestn = ((loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4209 : 352 : ? data.clone_inbranch : data.clone);
4210 : : else
4211 : 5931 : for (struct cgraph_node *n = node->simd_clones; n != NULL;
4212 : 4906 : n = n->simdclone->next_clone)
4213 : : {
4214 : 4906 : unsigned int this_badness = 0;
4215 : 4906 : unsigned int num_calls;
4216 : : /* The number of arguments in the call and the number of parameters in
4217 : : the simdclone should match. However, when the simdclone is
4218 : : 'inbranch', it could have one more paramater than nargs when using
4219 : : an inbranch simdclone to call a non-inbranch call, either in a
4220 : : non-masked loop using a all true constant mask, or inside a masked
4221 : : loop using it's mask. */
4222 : 4906 : size_t simd_nargs = n->simdclone->nargs;
4223 : 4906 : if (!masked_call_offset && n->simdclone->inbranch)
4224 : 2325 : simd_nargs--;
4225 : 4906 : if (!constant_multiple_p (vf * group_size, n->simdclone->simdlen,
4226 : : &num_calls)
4227 : 1940 : || (!n->simdclone->inbranch && (masked_call_offset > 0))
4228 : 1756 : || (nargs != simd_nargs))
4229 : 3150 : continue;
4230 : 1756 : if (num_calls != 1)
4231 : 1136 : this_badness += floor_log2 (num_calls) * 4096;
4232 : 1756 : if (n->simdclone->inbranch)
4233 : 760 : this_badness += 8192;
4234 : :
4235 : : /* If SLP_TREE_VECTYPE has not been set yet pass the general vector
4236 : : mode, which for targets that use it will determine what ISA we can
4237 : : vectorize this code with. */
4238 : 1756 : machine_mode vector_mode = vinfo->vector_mode;
4239 : 1756 : if (vectype)
4240 : 1756 : vector_mode = TYPE_MODE (vectype);
4241 : 1756 : int target_badness = targetm.simd_clone.usable (n, vector_mode);
4242 : 1756 : if (target_badness < 0)
4243 : 364 : continue;
4244 : 1392 : this_badness += target_badness * 512;
4245 : 4128 : for (i = 0; i < nargs; i++)
4246 : : {
4247 : 2984 : switch (n->simdclone->args[i].arg_type)
4248 : : {
4249 : 2054 : case SIMD_CLONE_ARG_TYPE_VECTOR:
4250 : 2054 : if (VECTOR_BOOLEAN_TYPE_P (n->simdclone->args[i].vector_type))
4251 : : /* Vector mask arguments are not supported. */
4252 : : i = -1;
4253 : 2046 : else if (!useless_type_conversion_p
4254 : 2046 : (n->simdclone->args[i].orig_type,
4255 : 2046 : TREE_TYPE (gimple_call_arg (stmt,
4256 : : i + masked_call_offset))))
4257 : : i = -1;
4258 : 2046 : else if (arginfo[i].dt == vect_constant_def
4259 : 1941 : || arginfo[i].dt == vect_external_def
4260 : 3925 : || arginfo[i].linear_step)
4261 : 386 : this_badness += 64;
4262 : : break;
4263 : 310 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
4264 : 310 : if ((arginfo[i].dt != vect_constant_def
4265 : 145 : && arginfo[i].dt != vect_external_def)
4266 : 410 : || SLP_TREE_LANES (slp_node) != 1)
4267 : : i = -1;
4268 : : break;
4269 : 324 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4270 : 324 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4271 : 324 : if (arginfo[i].dt == vect_constant_def
4272 : 324 : || arginfo[i].dt == vect_external_def
4273 : 324 : || (arginfo[i].linear_step
4274 : 324 : != n->simdclone->args[i].linear_step))
4275 : : i = -1;
4276 : : break;
4277 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
4278 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
4279 : : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
4280 : : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
4281 : : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
4282 : : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
4283 : : /* FORNOW */
4284 : : i = -1;
4285 : : break;
4286 : 296 : case SIMD_CLONE_ARG_TYPE_MASK:
4287 : 296 : if (!SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4288 : 264 : && n->simdclone->mask_mode != VOIDmode)
4289 : : i = -1;
4290 : : /* While we can create a traditional data vector from
4291 : : an incoming integer mode mask we have no good way to
4292 : : force generate an integer mode mask from a traditional
4293 : : boolean vector input. */
4294 : 296 : else if (SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4295 : 296 : && !SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype)))
4296 : : i = -1;
4297 : 290 : else if (n->simdclone->mask_mode == VOIDmode
4298 : : /* FORNOW we only have partial support for vector-type
4299 : : masks that can't hold all of simdlen. */
4300 : 554 : && (maybe_ne (TYPE_VECTOR_SUBPARTS (n->simdclone->args[i].vector_type),
4301 : 264 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype))
4302 : : /* Verify we can compute the mask argument. */
4303 : 111 : || !expand_vec_cond_expr_p (n->simdclone->args[i].vector_type,
4304 : 111 : arginfo[i].vectype)))
4305 : : i = -1;
4306 : 125 : else if (SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4307 : : /* FORNOW we only have partial support for
4308 : : integer-type masks that represent the same number
4309 : : of lanes as the vectorized mask inputs. */
4310 : 151 : && maybe_ne (exact_div (n->simdclone->simdlen,
4311 : : n->simdclone->args[i].linear_step),
4312 : 26 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4313 : : i = -1;
4314 : 107 : else if (!SCALAR_INT_MODE_P (n->simdclone->mask_mode)
4315 : 107 : && SCALAR_INT_MODE_P (TYPE_MODE (arginfo[i].vectype)))
4316 : 8 : this_badness += 2048;
4317 : : break;
4318 : : }
4319 : 183 : if (i == (size_t) -1)
4320 : : break;
4321 : 2736 : if (n->simdclone->args[i].alignment > arginfo[i].align)
4322 : : {
4323 : : i = -1;
4324 : : break;
4325 : : }
4326 : 2736 : if (arginfo[i].align)
4327 : 110 : this_badness += (exact_log2 (arginfo[i].align)
4328 : 160 : - exact_log2 (n->simdclone->args[i].alignment));
4329 : : }
4330 : 1392 : if (i == (size_t) -1)
4331 : 248 : continue;
4332 : 1144 : if (masked_call_offset == 0
4333 : 1037 : && n->simdclone->inbranch
4334 : 338 : && n->simdclone->nargs > nargs)
4335 : : {
4336 : 338 : gcc_assert (n->simdclone->args[n->simdclone->nargs - 1].arg_type ==
4337 : : SIMD_CLONE_ARG_TYPE_MASK);
4338 : : /* Penalize using a masked SIMD clone in a non-masked loop, that is
4339 : : not in a branch, as we'd have to construct an all-true mask. */
4340 : 338 : this_badness += 64;
4341 : : }
4342 : 1144 : if (bestn == NULL || this_badness < badness)
4343 : : {
4344 : 791 : bestn = n;
4345 : 791 : badness = this_badness;
4346 : : }
4347 : 1144 : if (n->simdclone->inbranch
4348 : 445 : && (bestn_inbranch == NULL || this_badness < badness_inbranch))
4349 : : {
4350 : 4906 : bestn_inbranch = n;
4351 : 4906 : badness_inbranch = this_badness;
4352 : : }
4353 : : }
4354 : :
4355 : 1377 : if (bestn == NULL)
4356 : : return false;
4357 : :
4358 : 798 : fndecl = bestn->decl;
4359 : 798 : nunits = bestn->simdclone->simdlen;
4360 : 798 : int ncopies = vector_unroll_factor (vf * group_size, nunits);
4361 : :
4362 : : /* If the function isn't const, only allow it in simd loops where user
4363 : : has asserted that at least nunits consecutive iterations can be
4364 : : performed using SIMD instructions. */
4365 : 796 : if ((loop == NULL || maybe_lt ((unsigned) loop->safelen, nunits))
4366 : 948 : && gimple_vuse (stmt))
4367 : : return false;
4368 : :
4369 : : /* ncopies is the number of SIMD clone calls we create, since simdlen
4370 : : is not necessarily matching nunits of the vector types used, track
4371 : : that in ncopies_in. */
4372 : 798 : int ncopies_in = vect_get_num_vectors (vf * group_size, vectype);
4373 : :
4374 : : /* Sanity check: make sure that at least one copy of the vectorized stmt
4375 : : needs to be generated. */
4376 : 798 : gcc_assert (ncopies >= 1);
4377 : :
4378 : 798 : if (cost_vec) /* transformation not required. */
4379 : : {
4380 : 1469 : for (unsigned i = 0; i < nargs; ++i)
4381 : 1023 : if (!vect_maybe_update_slp_op_vectype (slp_op[i], arginfo[i].vectype))
4382 : : {
4383 : 0 : if (dump_enabled_p ())
4384 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4385 : : "incompatible vector types for invariants\n");
4386 : 0 : return false;
4387 : : }
4388 : :
4389 : 446 : if (!bestn_inbranch && loop_vinfo)
4390 : : {
4391 : 235 : if (dump_enabled_p ()
4392 : 235 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
4393 : 170 : dump_printf_loc (MSG_NOTE, vect_location,
4394 : : "can't use a fully-masked loop because no"
4395 : : " masked simd clone was available.\n");
4396 : 235 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
4397 : : }
4398 : :
4399 : : /* When the original call is pure or const but the SIMD ABI dictates
4400 : : an aggregate return we will have to use a virtual definition and
4401 : : in a loop eventually even need to add a virtual PHI. That's
4402 : : not straight-forward so allow to fix this up via renaming. */
4403 : 446 : if (gimple_call_lhs (stmt)
4404 : 440 : && !gimple_vdef (stmt)
4405 : 792 : && TREE_CODE (TREE_TYPE (TREE_TYPE (bestn->decl))) == ARRAY_TYPE)
4406 : 27 : vinfo->any_known_not_updated_vssa = true;
4407 : : /* ??? For SLP code-gen we end up inserting after the last
4408 : : vector argument def rather than at the original call position
4409 : : so automagic virtual operand updating doesn't work. */
4410 : 892 : if (gimple_vuse (stmt))
4411 : 137 : vinfo->any_known_not_updated_vssa = true;
4412 : :
4413 : 446 : data.clone = bestn;
4414 : 446 : data.clone_inbranch = bestn_inbranch;
4415 : :
4416 : 446 : simd_clone_info.safe_push (NULL_TREE);
4417 : 1612 : for (i = 0;
4418 : 2419 : i < (bestn_inbranch ? bestn_inbranch : bestn)->simdclone->nargs; i++)
4419 : : {
4420 : 1166 : if (loop_vinfo
4421 : 1164 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
4422 : 469 : && (bestn_inbranch->simdclone->args[i].arg_type
4423 : : == SIMD_CLONE_ARG_TYPE_MASK))
4424 : : {
4425 : 168 : if (masked_call_offset)
4426 : : /* When there is an explicit mask we require the
4427 : : number of elements to match up. */
4428 : 49 : vect_record_loop_mask (loop_vinfo,
4429 : : &LOOP_VINFO_MASKS (loop_vinfo),
4430 : : ncopies_in, vectype, NULL_TREE);
4431 : : else
4432 : : {
4433 : : /* When there is no explicit mask on the call we have
4434 : : more relaxed requirements. */
4435 : 119 : tree masktype;
4436 : 119 : poly_uint64 callee_nelements;
4437 : 119 : if (SCALAR_INT_MODE_P (bestn_inbranch->simdclone->mask_mode))
4438 : : {
4439 : 12 : callee_nelements
4440 : 12 : = exact_div (bestn_inbranch->simdclone->simdlen,
4441 : : bestn_inbranch->simdclone->args[i].linear_step);
4442 : 12 : masktype = get_related_vectype_for_scalar_type
4443 : 12 : (vinfo->vector_mode, TREE_TYPE (vectype),
4444 : : callee_nelements);
4445 : : }
4446 : : else
4447 : : {
4448 : 107 : masktype = bestn_inbranch->simdclone->args[i].vector_type;
4449 : 107 : callee_nelements = TYPE_VECTOR_SUBPARTS (masktype);
4450 : : }
4451 : 119 : auto o = vector_unroll_factor (nunits, callee_nelements);
4452 : 119 : vect_record_loop_mask (loop_vinfo,
4453 : : &LOOP_VINFO_MASKS (loop_vinfo),
4454 : : ncopies * o, masktype, NULL_TREE);
4455 : : }
4456 : : }
4457 : 998 : else if ((bestn->simdclone->args[i].arg_type
4458 : : == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP)
4459 : 891 : || (bestn->simdclone->args[i].arg_type
4460 : : == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)
4461 : 880 : || (bestn_inbranch
4462 : 357 : && ((bestn_inbranch->simdclone->args[i].arg_type
4463 : : == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP)
4464 : 357 : || (bestn_inbranch->simdclone->args[i].arg_type
4465 : : == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP))))
4466 : : {
4467 : 118 : simd_clone_info.safe_grow_cleared (i * 3 + 1, true);
4468 : 118 : simd_clone_info.safe_push (arginfo[i].op);
4469 : 202 : tree lst = (POINTER_TYPE_P (TREE_TYPE (arginfo[i].op))
4470 : 202 : ? size_type_node : TREE_TYPE (arginfo[i].op));
4471 : 118 : tree ls = build_int_cst (lst, arginfo[i].linear_step);
4472 : 118 : simd_clone_info.safe_push (ls);
4473 : 118 : tree sll = (arginfo[i].simd_lane_linear
4474 : 118 : ? boolean_true_node : boolean_false_node);
4475 : 118 : simd_clone_info.safe_push (sll);
4476 : : }
4477 : : }
4478 : :
4479 : 446 : SLP_TREE_TYPE (slp_node) = call_simd_clone_vec_info_type;
4480 : 446 : slp_node->data = new vect_simd_clone_data (std::move (_data));
4481 : 446 : DUMP_VECT_SCOPE ("vectorizable_simd_clone_call");
4482 : : /* vect_model_simple_cost (vinfo, 1, slp_node, cost_vec); */
4483 : 446 : return true;
4484 : : }
4485 : :
4486 : : /* Transform. */
4487 : :
4488 : 352 : if (dump_enabled_p ())
4489 : 242 : dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n");
4490 : :
4491 : : /* Handle def. */
4492 : 352 : scalar_dest = gimple_call_lhs (stmt);
4493 : 352 : vec_dest = NULL_TREE;
4494 : 352 : rtype = NULL_TREE;
4495 : 352 : ratype = NULL_TREE;
4496 : 352 : if (scalar_dest)
4497 : : {
4498 : 346 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
4499 : 346 : rtype = TREE_TYPE (TREE_TYPE (fndecl));
4500 : 346 : if (TREE_CODE (rtype) == ARRAY_TYPE)
4501 : : {
4502 : 9 : ratype = rtype;
4503 : 9 : rtype = TREE_TYPE (ratype);
4504 : : }
4505 : : }
4506 : :
4507 : 704 : auto_vec<vec<tree> > vec_oprnds;
4508 : 352 : auto_vec<unsigned> vec_oprnds_i;
4509 : 352 : vec_oprnds_i.safe_grow_cleared (nargs, true);
4510 : 352 : vec_oprnds.reserve_exact (nargs);
4511 : 352 : vect_get_slp_defs (vinfo, slp_node, &vec_oprnds);
4512 : 813 : for (j = 0; j < ncopies; ++j)
4513 : : {
4514 : 461 : poly_uint64 callee_nelements;
4515 : 461 : poly_uint64 caller_nelements;
4516 : : /* Build argument list for the vectorized call. */
4517 : 461 : if (j == 0)
4518 : 352 : vargs.create (nargs);
4519 : : else
4520 : 109 : vargs.truncate (0);
4521 : :
4522 : 1559 : for (i = 0; i < nargs; i++)
4523 : : {
4524 : 1098 : unsigned int k, l, m, o;
4525 : 1098 : tree atype;
4526 : 1098 : tree op = gimple_call_arg (stmt, i + masked_call_offset);
4527 : 1098 : switch (bestn->simdclone->args[i].arg_type)
4528 : : {
4529 : 809 : case SIMD_CLONE_ARG_TYPE_VECTOR:
4530 : 809 : atype = bestn->simdclone->args[i].vector_type;
4531 : 809 : caller_nelements = TYPE_VECTOR_SUBPARTS (arginfo[i].vectype);
4532 : 809 : callee_nelements = TYPE_VECTOR_SUBPARTS (atype);
4533 : 809 : o = vector_unroll_factor (nunits, callee_nelements);
4534 : 1848 : for (m = j * o; m < (j + 1) * o; m++)
4535 : : {
4536 : 1039 : if (known_lt (callee_nelements, caller_nelements))
4537 : : {
4538 : 516 : poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (atype));
4539 : 258 : if (!constant_multiple_p (caller_nelements,
4540 : : callee_nelements, &k))
4541 : 0 : gcc_unreachable ();
4542 : :
4543 : 258 : gcc_assert ((k & (k - 1)) == 0);
4544 : 258 : if (m == 0)
4545 : : {
4546 : 57 : vec_oprnds_i[i] = 0;
4547 : 57 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4548 : : }
4549 : : else
4550 : : {
4551 : 201 : vec_oprnd0 = arginfo[i].op;
4552 : 201 : if ((m & (k - 1)) == 0)
4553 : 72 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4554 : : }
4555 : 258 : arginfo[i].op = vec_oprnd0;
4556 : 258 : vec_oprnd0
4557 : 258 : = build3 (BIT_FIELD_REF, atype, vec_oprnd0,
4558 : 258 : bitsize_int (prec),
4559 : 258 : bitsize_int ((m & (k - 1)) * prec));
4560 : 258 : gassign *new_stmt
4561 : 258 : = gimple_build_assign (make_ssa_name (atype),
4562 : : vec_oprnd0);
4563 : 258 : vect_finish_stmt_generation (vinfo, stmt_info,
4564 : : new_stmt, gsi);
4565 : 258 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4566 : : }
4567 : : else
4568 : : {
4569 : 781 : if (!constant_multiple_p (callee_nelements,
4570 : : caller_nelements, &k))
4571 : 0 : gcc_unreachable ();
4572 : 781 : gcc_assert ((k & (k - 1)) == 0);
4573 : 781 : vec<constructor_elt, va_gc> *ctor_elts;
4574 : 781 : if (k != 1)
4575 : 14 : vec_alloc (ctor_elts, k);
4576 : : else
4577 : 767 : ctor_elts = NULL;
4578 : 809 : for (l = 0; l < k; l++)
4579 : : {
4580 : 795 : if (m == 0 && l == 0)
4581 : : {
4582 : 443 : vec_oprnds_i[i] = 0;
4583 : 443 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4584 : : }
4585 : : else
4586 : 352 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4587 : 795 : arginfo[i].op = vec_oprnd0;
4588 : 795 : if (k == 1)
4589 : : break;
4590 : 28 : CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE,
4591 : : vec_oprnd0);
4592 : : }
4593 : 781 : if (k == 1)
4594 : 767 : if (!useless_type_conversion_p (TREE_TYPE (vec_oprnd0),
4595 : : atype))
4596 : : {
4597 : 0 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, atype,
4598 : : vec_oprnd0);
4599 : 0 : gassign *new_stmt
4600 : 0 : = gimple_build_assign (make_ssa_name (atype),
4601 : : vec_oprnd0);
4602 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
4603 : : new_stmt, gsi);
4604 : 0 : vargs.safe_push (gimple_get_lhs (new_stmt));
4605 : : }
4606 : : else
4607 : 767 : vargs.safe_push (vec_oprnd0);
4608 : : else
4609 : : {
4610 : 14 : vec_oprnd0 = build_constructor (atype, ctor_elts);
4611 : 14 : gassign *new_stmt
4612 : 14 : = gimple_build_assign (make_ssa_name (atype),
4613 : : vec_oprnd0);
4614 : 14 : vect_finish_stmt_generation (vinfo, stmt_info,
4615 : : new_stmt, gsi);
4616 : 14 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4617 : : }
4618 : : }
4619 : : }
4620 : : break;
4621 : 66 : case SIMD_CLONE_ARG_TYPE_MASK:
4622 : 66 : if (bestn->simdclone->mask_mode == VOIDmode)
4623 : : {
4624 : 60 : atype = bestn->simdclone->args[i].vector_type;
4625 : 60 : tree elt_type = TREE_TYPE (atype);
4626 : 60 : tree one = fold_convert (elt_type, integer_one_node);
4627 : 60 : tree zero = fold_convert (elt_type, integer_zero_node);
4628 : 60 : callee_nelements = TYPE_VECTOR_SUBPARTS (atype);
4629 : 60 : caller_nelements = TYPE_VECTOR_SUBPARTS (arginfo[i].vectype);
4630 : 60 : o = vector_unroll_factor (nunits, callee_nelements);
4631 : 120 : for (m = j * o; m < (j + 1) * o; m++)
4632 : : {
4633 : 60 : if (maybe_lt (callee_nelements, caller_nelements))
4634 : : {
4635 : : /* The mask type has fewer elements than simdlen. */
4636 : :
4637 : : /* FORNOW */
4638 : 0 : gcc_unreachable ();
4639 : : }
4640 : 60 : else if (known_eq (callee_nelements, caller_nelements))
4641 : : {
4642 : : /* The SIMD clone function has the same number of
4643 : : elements as the current function. */
4644 : 60 : if (m == 0)
4645 : 60 : vec_oprnds_i[i] = 0;
4646 : 60 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4647 : 60 : if (loop_vinfo
4648 : 60 : && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4649 : : {
4650 : 0 : vec_loop_masks *loop_masks
4651 : : = &LOOP_VINFO_MASKS (loop_vinfo);
4652 : 0 : tree loop_mask
4653 : 0 : = vect_get_loop_mask (loop_vinfo, gsi,
4654 : : loop_masks, ncopies_in,
4655 : 0 : vectype, j);
4656 : 0 : vec_oprnd0
4657 : 0 : = prepare_vec_mask (loop_vinfo,
4658 : 0 : TREE_TYPE (loop_mask),
4659 : : loop_mask, vec_oprnd0,
4660 : : gsi);
4661 : 0 : loop_vinfo->vec_cond_masked_set.add ({ vec_oprnd0,
4662 : : loop_mask });
4663 : :
4664 : : }
4665 : 60 : vec_oprnd0
4666 : 60 : = build3 (VEC_COND_EXPR, atype, vec_oprnd0,
4667 : : build_vector_from_val (atype, one),
4668 : : build_vector_from_val (atype, zero));
4669 : 60 : gassign *new_stmt
4670 : 60 : = gimple_build_assign (make_ssa_name (atype),
4671 : : vec_oprnd0);
4672 : 60 : vect_finish_stmt_generation (vinfo, stmt_info,
4673 : : new_stmt, gsi);
4674 : 60 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4675 : : }
4676 : : else
4677 : : {
4678 : : /* The mask type has more elements than simdlen. */
4679 : :
4680 : : /* FORNOW */
4681 : 0 : gcc_unreachable ();
4682 : : }
4683 : : }
4684 : : }
4685 : 6 : else if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4686 : : {
4687 : 6 : atype = bestn->simdclone->args[i].vector_type;
4688 : 6 : poly_uint64 atype_subparts
4689 : 6 : = exact_div (bestn->simdclone->simdlen,
4690 : : bestn->simdclone->args[i].linear_step);
4691 : 6 : o = bestn->simdclone->args[i].linear_step;
4692 : 12 : for (m = j * o; m < (j + 1) * o; m++)
4693 : : {
4694 : 6 : if (m == 0)
4695 : 6 : vec_oprnds_i[i] = 0;
4696 : 6 : if (maybe_lt (atype_subparts,
4697 : 6 : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4698 : : {
4699 : : /* The mask argument has fewer elements than the
4700 : : input vector. */
4701 : : /* FORNOW */
4702 : 0 : gcc_unreachable ();
4703 : : }
4704 : 6 : else if (known_eq (atype_subparts,
4705 : : TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
4706 : : {
4707 : 6 : vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
4708 : 6 : if (loop_vinfo
4709 : 6 : && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4710 : : {
4711 : 1 : vec_loop_masks *loop_masks
4712 : : = &LOOP_VINFO_MASKS (loop_vinfo);
4713 : 1 : tree loop_mask
4714 : 1 : = vect_get_loop_mask (loop_vinfo, gsi,
4715 : : loop_masks, ncopies_in,
4716 : : vectype, j);
4717 : 1 : vec_oprnd0
4718 : 1 : = prepare_vec_mask (loop_vinfo,
4719 : 1 : TREE_TYPE (loop_mask),
4720 : : loop_mask, vec_oprnd0,
4721 : : gsi);
4722 : : }
4723 : : /* The vector mask argument matches the input
4724 : : in the number of lanes, but not necessarily
4725 : : in the mode. */
4726 : 6 : tree st = lang_hooks.types.type_for_mode
4727 : 6 : (TYPE_MODE (TREE_TYPE (vec_oprnd0)), 1);
4728 : 6 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, st,
4729 : : vec_oprnd0);
4730 : 6 : gassign *new_stmt
4731 : 6 : = gimple_build_assign (make_ssa_name (st),
4732 : : vec_oprnd0);
4733 : 6 : vect_finish_stmt_generation (vinfo, stmt_info,
4734 : : new_stmt, gsi);
4735 : 6 : if (!types_compatible_p (atype, st))
4736 : : {
4737 : 6 : new_stmt
4738 : 6 : = gimple_build_assign (make_ssa_name (atype),
4739 : : NOP_EXPR,
4740 : : gimple_assign_lhs
4741 : : (new_stmt));
4742 : 6 : vect_finish_stmt_generation (vinfo, stmt_info,
4743 : : new_stmt, gsi);
4744 : : }
4745 : 6 : vargs.safe_push (gimple_assign_lhs (new_stmt));
4746 : : }
4747 : : else
4748 : : {
4749 : : /* The mask argument has more elements than the
4750 : : input vector. */
4751 : : /* FORNOW */
4752 : 0 : gcc_unreachable ();
4753 : : }
4754 : : }
4755 : : }
4756 : : else
4757 : 0 : gcc_unreachable ();
4758 : : break;
4759 : 102 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
4760 : 102 : vargs.safe_push (op);
4761 : 102 : break;
4762 : 121 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
4763 : 121 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
4764 : 121 : if (j == 0)
4765 : : {
4766 : 118 : gimple_seq stmts;
4767 : 118 : arginfo[i].op
4768 : 118 : = force_gimple_operand (unshare_expr (arginfo[i].op),
4769 : : &stmts, true, NULL_TREE);
4770 : 118 : if (stmts != NULL)
4771 : : {
4772 : 0 : basic_block new_bb;
4773 : 0 : edge pe = loop_preheader_edge (loop);
4774 : 0 : new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
4775 : 0 : gcc_assert (!new_bb);
4776 : : }
4777 : 118 : if (arginfo[i].simd_lane_linear)
4778 : : {
4779 : 6 : vargs.safe_push (arginfo[i].op);
4780 : 6 : break;
4781 : : }
4782 : 112 : tree phi_res = copy_ssa_name (op);
4783 : 112 : gphi *new_phi = create_phi_node (phi_res, loop->header);
4784 : 112 : add_phi_arg (new_phi, arginfo[i].op,
4785 : : loop_preheader_edge (loop), UNKNOWN_LOCATION);
4786 : 112 : enum tree_code code
4787 : 196 : = POINTER_TYPE_P (TREE_TYPE (op))
4788 : 112 : ? POINTER_PLUS_EXPR : PLUS_EXPR;
4789 : 196 : tree type = POINTER_TYPE_P (TREE_TYPE (op))
4790 : 196 : ? sizetype : TREE_TYPE (op);
4791 : 112 : poly_widest_int cst
4792 : 112 : = wi::mul (bestn->simdclone->args[i].linear_step,
4793 : 112 : ncopies * nunits);
4794 : 112 : tree tcst = wide_int_to_tree (type, cst);
4795 : 112 : tree phi_arg = copy_ssa_name (op);
4796 : 112 : gassign *new_stmt
4797 : 112 : = gimple_build_assign (phi_arg, code, phi_res, tcst);
4798 : 112 : gimple_stmt_iterator si = gsi_after_labels (loop->header);
4799 : 112 : gsi_insert_after (&si, new_stmt, GSI_NEW_STMT);
4800 : 112 : add_phi_arg (new_phi, phi_arg, loop_latch_edge (loop),
4801 : : UNKNOWN_LOCATION);
4802 : 112 : arginfo[i].op = phi_res;
4803 : 112 : vargs.safe_push (phi_res);
4804 : 112 : }
4805 : : else
4806 : : {
4807 : 3 : enum tree_code code
4808 : 6 : = POINTER_TYPE_P (TREE_TYPE (op))
4809 : 3 : ? POINTER_PLUS_EXPR : PLUS_EXPR;
4810 : 6 : tree type = POINTER_TYPE_P (TREE_TYPE (op))
4811 : 6 : ? sizetype : TREE_TYPE (op);
4812 : 3 : poly_widest_int cst
4813 : 3 : = wi::mul (bestn->simdclone->args[i].linear_step,
4814 : 3 : j * nunits);
4815 : 3 : tree tcst = wide_int_to_tree (type, cst);
4816 : 3 : new_temp = make_ssa_name (TREE_TYPE (op));
4817 : 3 : gassign *new_stmt
4818 : 6 : = gimple_build_assign (new_temp, code,
4819 : 3 : arginfo[i].op, tcst);
4820 : 3 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4821 : 3 : vargs.safe_push (new_temp);
4822 : 3 : }
4823 : : break;
4824 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
4825 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
4826 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
4827 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
4828 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
4829 : 0 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
4830 : 0 : default:
4831 : 0 : gcc_unreachable ();
4832 : : }
4833 : : }
4834 : :
4835 : 461 : if (masked_call_offset == 0
4836 : 395 : && bestn->simdclone->inbranch
4837 : 8 : && bestn->simdclone->nargs > nargs)
4838 : : {
4839 : 8 : unsigned long m, o;
4840 : 8 : size_t mask_i = bestn->simdclone->nargs - 1;
4841 : 8 : tree mask;
4842 : 8 : gcc_assert (bestn->simdclone->args[mask_i].arg_type ==
4843 : : SIMD_CLONE_ARG_TYPE_MASK);
4844 : :
4845 : 8 : tree mask_argtype = bestn->simdclone->args[mask_i].vector_type;
4846 : 8 : tree mask_vectype;
4847 : 8 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4848 : : {
4849 : 2 : callee_nelements = exact_div (bestn->simdclone->simdlen,
4850 : : bestn->simdclone->args[i].linear_step);
4851 : 2 : mask_vectype = get_related_vectype_for_scalar_type
4852 : 2 : (vinfo->vector_mode, TREE_TYPE (vectype), callee_nelements);
4853 : : }
4854 : : else
4855 : : {
4856 : 6 : mask_vectype = mask_argtype;
4857 : 6 : callee_nelements = TYPE_VECTOR_SUBPARTS (mask_vectype);
4858 : : }
4859 : 8 : o = vector_unroll_factor (nunits, callee_nelements);
4860 : 16 : for (m = j * o; m < (j + 1) * o; m++)
4861 : : {
4862 : 8 : if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
4863 : : {
4864 : 1 : vec_loop_masks *loop_masks = &LOOP_VINFO_MASKS (loop_vinfo);
4865 : 1 : mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
4866 : : ncopies * o, mask_vectype, m);
4867 : : }
4868 : : else
4869 : 7 : mask = vect_build_all_ones_mask (vinfo, stmt_info,
4870 : : mask_argtype);
4871 : :
4872 : 8 : gassign *new_stmt;
4873 : 8 : if (SCALAR_INT_MODE_P (bestn->simdclone->mask_mode))
4874 : : {
4875 : : /* This means we are dealing with integer mask modes.
4876 : : First convert to an integer type with the same size as
4877 : : the current vector type. */
4878 : 2 : unsigned HOST_WIDE_INT intermediate_size
4879 : 2 : = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (mask)));
4880 : 2 : tree mid_int_type =
4881 : 2 : build_nonstandard_integer_type (intermediate_size, 1);
4882 : 2 : mask = build1 (VIEW_CONVERT_EXPR, mid_int_type, mask);
4883 : 2 : new_stmt
4884 : 2 : = gimple_build_assign (make_ssa_name (mid_int_type),
4885 : : mask);
4886 : 2 : gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
4887 : : /* Then zero-extend to the mask mode. */
4888 : 2 : mask = fold_build1 (NOP_EXPR, mask_argtype,
4889 : : gimple_get_lhs (new_stmt));
4890 : : }
4891 : 6 : else if (bestn->simdclone->mask_mode == VOIDmode)
4892 : 6 : mask = build3 (VEC_COND_EXPR, mask_argtype, mask,
4893 : : build_one_cst (mask_argtype),
4894 : : build_zero_cst (mask_argtype));
4895 : : else
4896 : 0 : gcc_unreachable ();
4897 : :
4898 : 8 : new_stmt = gimple_build_assign (make_ssa_name (mask_argtype),
4899 : : mask);
4900 : 8 : vect_finish_stmt_generation (vinfo, stmt_info,
4901 : : new_stmt, gsi);
4902 : 8 : mask = gimple_assign_lhs (new_stmt);
4903 : 8 : vargs.safe_push (mask);
4904 : : }
4905 : : }
4906 : :
4907 : 461 : gcall *new_call = gimple_build_call_vec (fndecl, vargs);
4908 : 461 : if (vec_dest)
4909 : : {
4910 : 455 : gcc_assert (ratype
4911 : : || known_eq (TYPE_VECTOR_SUBPARTS (rtype), nunits));
4912 : 455 : if (ratype)
4913 : 15 : new_temp = create_tmp_var (ratype);
4914 : 440 : else if (useless_type_conversion_p (vectype, rtype))
4915 : 418 : new_temp = make_ssa_name (vec_dest, new_call);
4916 : : else
4917 : 22 : new_temp = make_ssa_name (rtype, new_call);
4918 : 455 : gimple_call_set_lhs (new_call, new_temp);
4919 : : }
4920 : 461 : vect_finish_stmt_generation (vinfo, stmt_info, new_call, gsi);
4921 : 461 : gimple *new_stmt = new_call;
4922 : :
4923 : 461 : if (vec_dest)
4924 : : {
4925 : 455 : if (!multiple_p (TYPE_VECTOR_SUBPARTS (vectype), nunits))
4926 : : {
4927 : 21 : unsigned int k, l;
4928 : 42 : poly_uint64 prec = GET_MODE_BITSIZE (TYPE_MODE (vectype));
4929 : 42 : poly_uint64 bytes = GET_MODE_SIZE (TYPE_MODE (vectype));
4930 : 21 : k = vector_unroll_factor (nunits,
4931 : : TYPE_VECTOR_SUBPARTS (vectype));
4932 : 21 : gcc_assert ((k & (k - 1)) == 0);
4933 : 75 : for (l = 0; l < k; l++)
4934 : : {
4935 : 54 : tree t;
4936 : 54 : if (ratype)
4937 : : {
4938 : 42 : t = build_fold_addr_expr (new_temp);
4939 : 42 : t = build2 (MEM_REF, vectype, t,
4940 : 42 : build_int_cst (TREE_TYPE (t), l * bytes));
4941 : : }
4942 : : else
4943 : 12 : t = build3 (BIT_FIELD_REF, vectype, new_temp,
4944 : 12 : bitsize_int (prec), bitsize_int (l * prec));
4945 : 54 : new_stmt = gimple_build_assign (make_ssa_name (vectype), t);
4946 : 54 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4947 : :
4948 : 54 : SLP_TREE_VEC_DEFS (slp_node)
4949 : 54 : .quick_push (gimple_assign_lhs (new_stmt));
4950 : : }
4951 : :
4952 : 21 : if (ratype)
4953 : 15 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
4954 : 21 : continue;
4955 : 21 : }
4956 : 434 : else if (!multiple_p (nunits, TYPE_VECTOR_SUBPARTS (vectype)))
4957 : : {
4958 : 16 : unsigned int k;
4959 : 16 : if (!constant_multiple_p (TYPE_VECTOR_SUBPARTS (vectype),
4960 : 16 : TYPE_VECTOR_SUBPARTS (rtype), &k))
4961 : 0 : gcc_unreachable ();
4962 : 16 : gcc_assert ((k & (k - 1)) == 0);
4963 : 16 : if ((j & (k - 1)) == 0)
4964 : 8 : vec_alloc (ret_ctor_elts, k);
4965 : 16 : if (ratype)
4966 : : {
4967 : 0 : unsigned int m, o;
4968 : 0 : o = vector_unroll_factor (nunits,
4969 : : TYPE_VECTOR_SUBPARTS (rtype));
4970 : 0 : for (m = 0; m < o; m++)
4971 : : {
4972 : 0 : tree tem = build4 (ARRAY_REF, rtype, new_temp,
4973 : 0 : size_int (m), NULL_TREE, NULL_TREE);
4974 : 0 : new_stmt = gimple_build_assign (make_ssa_name (rtype),
4975 : : tem);
4976 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
4977 : : new_stmt, gsi);
4978 : 0 : CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE,
4979 : : gimple_assign_lhs (new_stmt));
4980 : : }
4981 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
4982 : : }
4983 : : else
4984 : 16 : CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE, new_temp);
4985 : 16 : if ((j & (k - 1)) != k - 1)
4986 : 8 : continue;
4987 : 8 : vec_oprnd0 = build_constructor (vectype, ret_ctor_elts);
4988 : 8 : new_stmt
4989 : 8 : = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0);
4990 : 8 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
4991 : :
4992 : 8 : SLP_TREE_VEC_DEFS (slp_node)
4993 : 8 : .quick_push (gimple_assign_lhs (new_stmt));
4994 : 8 : continue;
4995 : 8 : }
4996 : 418 : else if (ratype)
4997 : : {
4998 : 0 : tree t = build_fold_addr_expr (new_temp);
4999 : 0 : t = build2 (MEM_REF, vectype, t,
5000 : 0 : build_int_cst (TREE_TYPE (t), 0));
5001 : 0 : new_stmt = gimple_build_assign (make_ssa_name (vec_dest), t);
5002 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5003 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, new_temp);
5004 : : }
5005 : 418 : else if (!useless_type_conversion_p (vectype, rtype))
5006 : : {
5007 : 0 : vec_oprnd0 = build1 (VIEW_CONVERT_EXPR, vectype, new_temp);
5008 : 0 : new_stmt
5009 : 0 : = gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0);
5010 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5011 : : }
5012 : : }
5013 : :
5014 : 424 : if (gimple_get_lhs (new_stmt))
5015 : 418 : SLP_TREE_VEC_DEFS (slp_node).quick_push (gimple_get_lhs (new_stmt));
5016 : : }
5017 : :
5018 : 1138 : for (i = 0; i < nargs; ++i)
5019 : : {
5020 : 786 : vec<tree> oprndsi = vec_oprnds[i];
5021 : 786 : oprndsi.release ();
5022 : : }
5023 : 352 : vargs.release ();
5024 : :
5025 : : /* Mark the clone as no longer being a candidate for GC. */
5026 : 352 : bestn->gc_candidate = false;
5027 : :
5028 : 352 : return true;
5029 : 1377 : }
5030 : :
5031 : :
5032 : : /* Function vect_gen_widened_results_half
5033 : :
5034 : : Create a vector stmt whose code, type, number of arguments, and result
5035 : : variable are CODE, OP_TYPE, and VEC_DEST, and its arguments are
5036 : : VEC_OPRND0 and VEC_OPRND1. The new vector stmt is to be inserted at GSI.
5037 : : In the case that CODE is a CALL_EXPR, this means that a call to DECL
5038 : : needs to be created (DECL is a function-decl of a target-builtin).
5039 : : STMT_INFO is the original scalar stmt that we are vectorizing. */
5040 : :
5041 : : static gimple *
5042 : 31168 : vect_gen_widened_results_half (vec_info *vinfo, code_helper ch,
5043 : : tree vec_oprnd0, tree vec_oprnd1, int op_type,
5044 : : tree vec_dest, gimple_stmt_iterator *gsi,
5045 : : stmt_vec_info stmt_info)
5046 : : {
5047 : 31168 : gimple *new_stmt;
5048 : 31168 : tree new_temp;
5049 : :
5050 : : /* Generate half of the widened result: */
5051 : 31168 : if (op_type != binary_op)
5052 : 30072 : vec_oprnd1 = NULL;
5053 : 31168 : new_stmt = vect_gimple_build (vec_dest, ch, vec_oprnd0, vec_oprnd1);
5054 : 31168 : new_temp = make_ssa_name (vec_dest, new_stmt);
5055 : 31168 : gimple_set_lhs (new_stmt, new_temp);
5056 : 31168 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5057 : :
5058 : 31168 : return new_stmt;
5059 : : }
5060 : :
5061 : :
5062 : : /* Create vectorized demotion statements for vector operands from VEC_OPRNDS.
5063 : : For multi-step conversions store the resulting vectors and call the function
5064 : : recursively. When NARROW_SRC_P is true, there's still a conversion after
5065 : : narrowing, don't store the vectors in the SLP_NODE or in vector info of
5066 : : the scalar statement(or in STMT_VINFO_RELATED_STMT chain). */
5067 : :
5068 : : static void
5069 : 11850 : vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
5070 : : int multi_step_cvt,
5071 : : stmt_vec_info stmt_info,
5072 : : vec<tree> &vec_dsts,
5073 : : gimple_stmt_iterator *gsi,
5074 : : slp_tree slp_node, code_helper code,
5075 : : bool narrow_src_p)
5076 : : {
5077 : 11850 : unsigned int i;
5078 : 11850 : tree vop0, vop1, new_tmp, vec_dest;
5079 : :
5080 : 11850 : vec_dest = vec_dsts.pop ();
5081 : :
5082 : 27966 : for (i = 0; i < vec_oprnds->length (); i += 2)
5083 : : {
5084 : : /* Create demotion operation. */
5085 : 16116 : vop0 = (*vec_oprnds)[i];
5086 : 16116 : vop1 = (*vec_oprnds)[i + 1];
5087 : 16116 : gimple *new_stmt = vect_gimple_build (vec_dest, code, vop0, vop1);
5088 : 16116 : new_tmp = make_ssa_name (vec_dest, new_stmt);
5089 : 16116 : gimple_set_lhs (new_stmt, new_tmp);
5090 : 16116 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5091 : 16116 : if (multi_step_cvt || narrow_src_p)
5092 : : /* Store the resulting vector for next recursive call,
5093 : : or return the resulting vector_tmp for NARROW FLOAT_EXPR. */
5094 : 6647 : (*vec_oprnds)[i/2] = new_tmp;
5095 : : else
5096 : : {
5097 : : /* This is the last step of the conversion sequence. Store the
5098 : : vectors in SLP_NODE. */
5099 : 9469 : slp_node->push_vec_def (new_stmt);
5100 : : }
5101 : : }
5102 : :
5103 : : /* For multi-step demotion operations we first generate demotion operations
5104 : : from the source type to the intermediate types, and then combine the
5105 : : results (stored in VEC_OPRNDS) in demotion operation to the destination
5106 : : type. */
5107 : 11850 : if (multi_step_cvt)
5108 : : {
5109 : : /* At each level of recursion we have half of the operands we had at the
5110 : : previous level. */
5111 : 2947 : vec_oprnds->truncate ((i+1)/2);
5112 : 2947 : vect_create_vectorized_demotion_stmts (vinfo, vec_oprnds,
5113 : : multi_step_cvt - 1,
5114 : : stmt_info, vec_dsts, gsi,
5115 : 2947 : slp_node, VEC_PACK_TRUNC_EXPR,
5116 : : narrow_src_p);
5117 : : }
5118 : :
5119 : 11850 : vec_dsts.quick_push (vec_dest);
5120 : 11850 : }
5121 : :
5122 : :
5123 : : /* Create vectorized promotion statements for vector operands from VEC_OPRNDS0
5124 : : and VEC_OPRNDS1, for a binary operation associated with scalar statement
5125 : : STMT_INFO. For multi-step conversions store the resulting vectors and
5126 : : call the function recursively. */
5127 : :
5128 : : static void
5129 : 11384 : vect_create_vectorized_promotion_stmts (vec_info *vinfo,
5130 : : vec<tree> *vec_oprnds0,
5131 : : vec<tree> *vec_oprnds1,
5132 : : stmt_vec_info stmt_info, tree vec_dest,
5133 : : gimple_stmt_iterator *gsi,
5134 : : code_helper ch1,
5135 : : code_helper ch2, int op_type)
5136 : : {
5137 : 11384 : int i;
5138 : 11384 : tree vop0, vop1, new_tmp1, new_tmp2;
5139 : 11384 : gimple *new_stmt1, *new_stmt2;
5140 : 11384 : vec<tree> vec_tmp = vNULL;
5141 : :
5142 : 11384 : vec_tmp.create (vec_oprnds0->length () * 2);
5143 : 38352 : FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0)
5144 : : {
5145 : 15584 : if (op_type == binary_op)
5146 : 548 : vop1 = (*vec_oprnds1)[i];
5147 : : else
5148 : : vop1 = NULL_TREE;
5149 : :
5150 : : /* Generate the two halves of promotion operation. */
5151 : 15584 : new_stmt1 = vect_gen_widened_results_half (vinfo, ch1, vop0, vop1,
5152 : : op_type, vec_dest, gsi,
5153 : : stmt_info);
5154 : 15584 : new_stmt2 = vect_gen_widened_results_half (vinfo, ch2, vop0, vop1,
5155 : : op_type, vec_dest, gsi,
5156 : : stmt_info);
5157 : 15584 : if (is_gimple_call (new_stmt1))
5158 : : {
5159 : 0 : new_tmp1 = gimple_call_lhs (new_stmt1);
5160 : 0 : new_tmp2 = gimple_call_lhs (new_stmt2);
5161 : : }
5162 : : else
5163 : : {
5164 : 15584 : new_tmp1 = gimple_assign_lhs (new_stmt1);
5165 : 15584 : new_tmp2 = gimple_assign_lhs (new_stmt2);
5166 : : }
5167 : :
5168 : : /* Store the results for the next step. */
5169 : 15584 : vec_tmp.quick_push (new_tmp1);
5170 : 15584 : vec_tmp.quick_push (new_tmp2);
5171 : : }
5172 : :
5173 : 11384 : vec_oprnds0->release ();
5174 : 11384 : *vec_oprnds0 = vec_tmp;
5175 : 11384 : }
5176 : :
5177 : : /* Create vectorized promotion stmts for widening stmts using only half the
5178 : : potential vector size for input. */
5179 : : static void
5180 : 14 : vect_create_half_widening_stmts (vec_info *vinfo,
5181 : : vec<tree> *vec_oprnds0,
5182 : : vec<tree> *vec_oprnds1,
5183 : : stmt_vec_info stmt_info, tree vec_dest,
5184 : : gimple_stmt_iterator *gsi,
5185 : : code_helper code1,
5186 : : int op_type)
5187 : : {
5188 : 14 : int i;
5189 : 14 : tree vop0, vop1;
5190 : 14 : gimple *new_stmt1;
5191 : 14 : gimple *new_stmt2;
5192 : 14 : gimple *new_stmt3;
5193 : 14 : vec<tree> vec_tmp = vNULL;
5194 : :
5195 : 14 : vec_tmp.create (vec_oprnds0->length ());
5196 : 28 : FOR_EACH_VEC_ELT (*vec_oprnds0, i, vop0)
5197 : : {
5198 : 14 : tree new_tmp1, new_tmp2, new_tmp3, out_type;
5199 : :
5200 : 14 : gcc_assert (op_type == binary_op);
5201 : 14 : vop1 = (*vec_oprnds1)[i];
5202 : :
5203 : : /* Widen the first vector input. */
5204 : 14 : out_type = TREE_TYPE (vec_dest);
5205 : 14 : new_tmp1 = make_ssa_name (out_type);
5206 : 14 : new_stmt1 = gimple_build_assign (new_tmp1, NOP_EXPR, vop0);
5207 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt1, gsi);
5208 : 14 : if (VECTOR_TYPE_P (TREE_TYPE (vop1)))
5209 : : {
5210 : : /* Widen the second vector input. */
5211 : 14 : new_tmp2 = make_ssa_name (out_type);
5212 : 14 : new_stmt2 = gimple_build_assign (new_tmp2, NOP_EXPR, vop1);
5213 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt2, gsi);
5214 : : /* Perform the operation. With both vector inputs widened. */
5215 : 14 : new_stmt3 = vect_gimple_build (vec_dest, code1, new_tmp1, new_tmp2);
5216 : : }
5217 : : else
5218 : : {
5219 : : /* Perform the operation. With the single vector input widened. */
5220 : 0 : new_stmt3 = vect_gimple_build (vec_dest, code1, new_tmp1, vop1);
5221 : : }
5222 : :
5223 : 14 : new_tmp3 = make_ssa_name (vec_dest, new_stmt3);
5224 : 14 : gimple_assign_set_lhs (new_stmt3, new_tmp3);
5225 : 14 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt3, gsi);
5226 : :
5227 : : /* Store the results for the next step. */
5228 : 14 : vec_tmp.quick_push (new_tmp3);
5229 : : }
5230 : :
5231 : 14 : vec_oprnds0->release ();
5232 : 14 : *vec_oprnds0 = vec_tmp;
5233 : 14 : }
5234 : :
5235 : :
5236 : : /* Check if STMT_INFO performs a conversion operation that can be vectorized.
5237 : : If COST_VEC is passed, calculate costs but don't change anything,
5238 : : otherwise, vectorize STMT_INFO: create a vectorized stmt to replace
5239 : : it, and insert it at GSI.
5240 : : Return true if STMT_INFO is vectorizable in this way. */
5241 : :
5242 : : static bool
5243 : 2326291 : vectorizable_conversion (vec_info *vinfo,
5244 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
5245 : : slp_tree slp_node,
5246 : : stmt_vector_for_cost *cost_vec)
5247 : : {
5248 : 2326291 : tree vec_dest, cvt_op = NULL_TREE;
5249 : 2326291 : tree scalar_dest;
5250 : 2326291 : tree op0, op1 = NULL_TREE;
5251 : 2326291 : tree_code tc1;
5252 : 2326291 : code_helper code, code1, code2;
5253 : 2326291 : code_helper codecvt1 = ERROR_MARK, codecvt2 = ERROR_MARK;
5254 : 2326291 : tree new_temp;
5255 : 2326291 : enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
5256 : 2326291 : poly_uint64 nunits_in;
5257 : 2326291 : poly_uint64 nunits_out;
5258 : 2326291 : tree vectype_out, vectype_in;
5259 : 2326291 : int i;
5260 : 2326291 : tree lhs_type, rhs_type;
5261 : : /* For conversions between floating point and integer, there're 2 NARROW
5262 : : cases. NARROW_SRC is for FLOAT_EXPR, means
5263 : : integer --DEMOTION--> integer --FLOAT_EXPR--> floating point.
5264 : : This is safe when the range of the source integer can fit into the lower
5265 : : precision. NARROW_DST is for FIX_TRUNC_EXPR, means
5266 : : floating point --FIX_TRUNC_EXPR--> integer --DEMOTION--> INTEGER.
5267 : : For other conversions, when there's narrowing, NARROW_DST is used as
5268 : : default. */
5269 : 2326291 : enum { NARROW_SRC, NARROW_DST, NONE, WIDEN } modifier;
5270 : 2326291 : vec<tree> vec_oprnds0 = vNULL;
5271 : 2326291 : vec<tree> vec_oprnds1 = vNULL;
5272 : 2326291 : tree vop0;
5273 : 2326291 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
5274 : 2326291 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
5275 : 2326291 : int multi_step_cvt = 0;
5276 : 2326291 : vec<tree> interm_types = vNULL;
5277 : 2326291 : tree intermediate_type, cvt_type = NULL_TREE;
5278 : 2326291 : int op_type;
5279 : 2326291 : unsigned short fltsz;
5280 : :
5281 : : /* Is STMT a vectorizable conversion? */
5282 : :
5283 : 2326291 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
5284 : : return false;
5285 : :
5286 : 2326291 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
5287 : 176586 : && cost_vec)
5288 : : return false;
5289 : :
5290 : 2149705 : gimple* stmt = stmt_info->stmt;
5291 : 2149705 : if (!(is_gimple_assign (stmt) || is_gimple_call (stmt)))
5292 : : return false;
5293 : :
5294 : 2094417 : if (gimple_get_lhs (stmt) == NULL_TREE
5295 : 2094417 : || TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME)
5296 : 781304 : return false;
5297 : :
5298 : 1313113 : if (TREE_CODE (gimple_get_lhs (stmt)) != SSA_NAME)
5299 : : return false;
5300 : :
5301 : 1313113 : if (is_gimple_assign (stmt))
5302 : : {
5303 : 1304869 : code = gimple_assign_rhs_code (stmt);
5304 : 1304869 : op_type = TREE_CODE_LENGTH ((tree_code) code);
5305 : : }
5306 : 8244 : else if (gimple_call_internal_p (stmt))
5307 : : {
5308 : 4344 : code = gimple_call_internal_fn (stmt);
5309 : 4344 : op_type = gimple_call_num_args (stmt);
5310 : : }
5311 : : else
5312 : : return false;
5313 : :
5314 : 1309213 : bool widen_arith = (code == WIDEN_MULT_EXPR
5315 : 1306645 : || code == WIDEN_LSHIFT_EXPR
5316 : 2615858 : || widening_fn_p (code));
5317 : :
5318 : 1306645 : if (!widen_arith
5319 : 1306645 : && !CONVERT_EXPR_CODE_P (code)
5320 : 1168113 : && code != FIX_TRUNC_EXPR
5321 : 1166097 : && code != FLOAT_EXPR)
5322 : : return false;
5323 : :
5324 : : /* Check types of lhs and rhs. */
5325 : 157539 : scalar_dest = gimple_get_lhs (stmt);
5326 : 157539 : lhs_type = TREE_TYPE (scalar_dest);
5327 : 157539 : vectype_out = SLP_TREE_VECTYPE (slp_node);
5328 : :
5329 : : /* Check the operands of the operation. */
5330 : 157539 : slp_tree slp_op0, slp_op1 = NULL;
5331 : 157539 : if (!vect_is_simple_use (vinfo, slp_node,
5332 : : 0, &op0, &slp_op0, &dt[0], &vectype_in))
5333 : : {
5334 : 0 : if (dump_enabled_p ())
5335 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5336 : : "use not simple.\n");
5337 : 0 : return false;
5338 : : }
5339 : :
5340 : 157539 : rhs_type = TREE_TYPE (op0);
5341 : 155523 : if ((code != FIX_TRUNC_EXPR && code != FLOAT_EXPR)
5342 : 301968 : && !((INTEGRAL_TYPE_P (lhs_type)
5343 : 132771 : && INTEGRAL_TYPE_P (rhs_type))
5344 : : || (SCALAR_FLOAT_TYPE_P (lhs_type)
5345 : 7241 : && SCALAR_FLOAT_TYPE_P (rhs_type))))
5346 : : return false;
5347 : :
5348 : 153122 : if (!VECTOR_BOOLEAN_TYPE_P (vectype_out)
5349 : 137281 : && INTEGRAL_TYPE_P (lhs_type)
5350 : 268739 : && !type_has_mode_precision_p (lhs_type))
5351 : : {
5352 : 467 : if (dump_enabled_p ())
5353 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5354 : : "type conversion to bit-precision unsupported\n");
5355 : 467 : return false;
5356 : : }
5357 : :
5358 : 152655 : if (op_type == binary_op)
5359 : : {
5360 : 2568 : gcc_assert (code == WIDEN_MULT_EXPR
5361 : : || code == WIDEN_LSHIFT_EXPR
5362 : : || widening_fn_p (code));
5363 : :
5364 : 2568 : op1 = is_gimple_assign (stmt) ? gimple_assign_rhs2 (stmt) :
5365 : 0 : gimple_call_arg (stmt, 0);
5366 : 2568 : tree vectype1_in;
5367 : 2568 : if (!vect_is_simple_use (vinfo, slp_node, 1,
5368 : : &op1, &slp_op1, &dt[1], &vectype1_in))
5369 : : {
5370 : 0 : if (dump_enabled_p ())
5371 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5372 : : "use not simple.\n");
5373 : 0 : return false;
5374 : : }
5375 : : /* For WIDEN_MULT_EXPR, if OP0 is a constant, use the type of
5376 : : OP1. */
5377 : 2568 : if (!vectype_in)
5378 : 99 : vectype_in = vectype1_in;
5379 : : }
5380 : :
5381 : : /* If op0 is an external or constant def, infer the vector type
5382 : : from the scalar type. */
5383 : 152655 : if (!vectype_in)
5384 : 20177 : vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
5385 : 152655 : if (!cost_vec)
5386 : 22537 : gcc_assert (vectype_in);
5387 : 152655 : if (!vectype_in)
5388 : : {
5389 : 260 : if (dump_enabled_p ())
5390 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5391 : : "no vectype for scalar type %T\n", rhs_type);
5392 : :
5393 : 260 : return false;
5394 : : }
5395 : :
5396 : 304790 : if (VECTOR_BOOLEAN_TYPE_P (vectype_out)
5397 : 152395 : != VECTOR_BOOLEAN_TYPE_P (vectype_in))
5398 : : {
5399 : 233 : if (dump_enabled_p ())
5400 : 36 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5401 : : "can't convert between boolean and non "
5402 : : "boolean vectors %T\n", rhs_type);
5403 : :
5404 : 233 : return false;
5405 : : }
5406 : :
5407 : 152162 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
5408 : 152162 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
5409 : 152162 : if (known_eq (nunits_out, nunits_in))
5410 : 72142 : if (widen_arith)
5411 : : modifier = WIDEN;
5412 : : else
5413 : 152162 : modifier = NONE;
5414 : 80020 : else if (multiple_p (nunits_out, nunits_in))
5415 : : modifier = NARROW_DST;
5416 : : else
5417 : : {
5418 : 44088 : gcc_checking_assert (multiple_p (nunits_in, nunits_out));
5419 : : modifier = WIDEN;
5420 : : }
5421 : :
5422 : 152162 : bool found_mode = false;
5423 : 152162 : scalar_mode lhs_mode = SCALAR_TYPE_MODE (lhs_type);
5424 : 152162 : scalar_mode rhs_mode = SCALAR_TYPE_MODE (rhs_type);
5425 : 152162 : opt_scalar_mode rhs_mode_iter;
5426 : 152162 : auto_vec<std::pair<tree, tree_code>, 2> converts;
5427 : 152162 : bool evenodd_ok = false;
5428 : :
5429 : : /* Supportable by target? */
5430 : 152162 : switch (modifier)
5431 : : {
5432 : 71908 : case NONE:
5433 : 71908 : if (code != FIX_TRUNC_EXPR
5434 : 70889 : && code != FLOAT_EXPR
5435 : 135798 : && !CONVERT_EXPR_CODE_P (code))
5436 : : return false;
5437 : 71908 : gcc_assert (code.is_tree_code ());
5438 : 71908 : if (supportable_indirect_convert_operation (code,
5439 : : vectype_out, vectype_in,
5440 : : converts, op0, slp_op0))
5441 : : {
5442 : 16791 : gcc_assert (converts.length () <= 2);
5443 : 16791 : if (converts.length () == 1)
5444 : 16717 : code1 = converts[0].second;
5445 : : else
5446 : : {
5447 : 74 : cvt_type = NULL_TREE;
5448 : 74 : multi_step_cvt = converts.length () - 1;
5449 : 74 : codecvt1 = converts[0].second;
5450 : 74 : code1 = converts[1].second;
5451 : 74 : interm_types.safe_push (converts[0].first);
5452 : : }
5453 : : break;
5454 : : }
5455 : :
5456 : : /* FALLTHRU */
5457 : 55117 : unsupported:
5458 : 61391 : if (dump_enabled_p ())
5459 : 5779 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5460 : : "conversion not supported by target.\n");
5461 : : return false;
5462 : :
5463 : 44322 : case WIDEN:
5464 : 44322 : if (known_eq (nunits_in, nunits_out))
5465 : : {
5466 : 468 : if (!(code.is_tree_code ()
5467 : 234 : && supportable_half_widening_operation ((tree_code) code,
5468 : : vectype_out, vectype_in,
5469 : : &tc1)))
5470 : 71 : goto unsupported;
5471 : 163 : code1 = tc1;
5472 : 163 : gcc_assert (!(multi_step_cvt && op_type == binary_op));
5473 : : break;
5474 : : }
5475 : : /* Elements in a vector can only be reordered if used in a reduction
5476 : : operation only. */
5477 : 44088 : if (code == WIDEN_MULT_EXPR
5478 : 2334 : && loop_vinfo
5479 : 2285 : && !nested_in_vect_loop_p (LOOP_VINFO_LOOP (loop_vinfo), stmt_info)
5480 : : /* For a SLP reduction we cannot swizzle lanes, detecting a
5481 : : reduction chain isn't possible here. */
5482 : 46351 : && SLP_TREE_LANES (slp_node) == 1)
5483 : : {
5484 : : /* ??? There is no way to look for SLP uses, so work on
5485 : : the stmt and what the stmt-based cycle detection gives us. */
5486 : 2165 : tree lhs = gimple_get_lhs (vect_orig_stmt (stmt_info)->stmt);
5487 : 2165 : stmt_vec_info use_stmt_info
5488 : 2165 : = lhs ? loop_vinfo->lookup_single_use (lhs) : NULL;
5489 : 2165 : if (use_stmt_info
5490 : 2023 : && STMT_VINFO_REDUC_DEF (use_stmt_info))
5491 : 44088 : evenodd_ok = true;
5492 : : }
5493 : 44088 : if (supportable_widening_operation (code, vectype_out, vectype_in,
5494 : : evenodd_ok, &code1,
5495 : : &code2, &multi_step_cvt,
5496 : : &interm_types))
5497 : : {
5498 : : /* Binary widening operation can only be supported directly by the
5499 : : architecture. */
5500 : 42212 : gcc_assert (!(multi_step_cvt && op_type == binary_op));
5501 : : break;
5502 : : }
5503 : :
5504 : 1876 : if (code != FLOAT_EXPR
5505 : 2200 : || GET_MODE_SIZE (lhs_mode) <= GET_MODE_SIZE (rhs_mode))
5506 : 1714 : goto unsupported;
5507 : :
5508 : 162 : fltsz = GET_MODE_SIZE (lhs_mode);
5509 : 237 : FOR_EACH_2XWIDER_MODE (rhs_mode_iter, rhs_mode)
5510 : : {
5511 : 237 : rhs_mode = rhs_mode_iter.require ();
5512 : 474 : if (GET_MODE_SIZE (rhs_mode) > fltsz)
5513 : : break;
5514 : :
5515 : 237 : cvt_type
5516 : 237 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0);
5517 : 237 : cvt_type = get_same_sized_vectype (cvt_type, vectype_in);
5518 : 237 : if (cvt_type == NULL_TREE)
5519 : 0 : goto unsupported;
5520 : :
5521 : 474 : if (GET_MODE_SIZE (rhs_mode) == fltsz)
5522 : : {
5523 : 57 : tc1 = ERROR_MARK;
5524 : 57 : gcc_assert (code.is_tree_code ());
5525 : 57 : if (!supportable_convert_operation ((tree_code) code, vectype_out,
5526 : : cvt_type, &tc1))
5527 : 22 : goto unsupported;
5528 : 35 : codecvt1 = tc1;
5529 : : }
5530 : 180 : else if (!supportable_widening_operation (code, vectype_out,
5531 : : cvt_type, evenodd_ok,
5532 : : &codecvt1,
5533 : : &codecvt2, &multi_step_cvt,
5534 : : &interm_types))
5535 : 75 : continue;
5536 : : else
5537 : 105 : gcc_assert (multi_step_cvt == 0);
5538 : :
5539 : 140 : if (supportable_widening_operation (NOP_EXPR, cvt_type,
5540 : : vectype_in, evenodd_ok, &code1,
5541 : : &code2, &multi_step_cvt,
5542 : : &interm_types))
5543 : : {
5544 : : found_mode = true;
5545 : : break;
5546 : : }
5547 : : }
5548 : :
5549 : 140 : if (!found_mode)
5550 : 0 : goto unsupported;
5551 : :
5552 : 280 : if (GET_MODE_SIZE (rhs_mode) == fltsz)
5553 : 35 : codecvt2 = ERROR_MARK;
5554 : : else
5555 : : {
5556 : 105 : multi_step_cvt++;
5557 : 105 : interm_types.safe_push (cvt_type);
5558 : 105 : cvt_type = NULL_TREE;
5559 : : }
5560 : : break;
5561 : :
5562 : 35932 : case NARROW_DST:
5563 : 35932 : gcc_assert (op_type == unary_op);
5564 : 35932 : if (supportable_narrowing_operation (code, vectype_out, vectype_in,
5565 : : &code1, &multi_step_cvt,
5566 : : &interm_types))
5567 : : break;
5568 : :
5569 : 14235 : if (GET_MODE_SIZE (lhs_mode) >= GET_MODE_SIZE (rhs_mode))
5570 : 805 : goto unsupported;
5571 : :
5572 : 3940 : if (code == FIX_TRUNC_EXPR)
5573 : : {
5574 : 274 : cvt_type
5575 : 274 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (rhs_mode), 0);
5576 : 274 : cvt_type = get_same_sized_vectype (cvt_type, vectype_in);
5577 : 274 : if (cvt_type == NULL_TREE)
5578 : 0 : goto unsupported;
5579 : 274 : if (supportable_convert_operation ((tree_code) code, cvt_type, vectype_in,
5580 : : &tc1))
5581 : 272 : codecvt1 = tc1;
5582 : : else
5583 : 2 : goto unsupported;
5584 : 272 : if (supportable_narrowing_operation (NOP_EXPR, vectype_out, cvt_type,
5585 : : &code1, &multi_step_cvt,
5586 : : &interm_types))
5587 : : break;
5588 : : }
5589 : : /* If op0 can be represented with low precision integer,
5590 : : truncate it to cvt_type and the do FLOAT_EXPR. */
5591 : 3666 : else if (code == FLOAT_EXPR)
5592 : : {
5593 : 104 : if (cost_vec)
5594 : : {
5595 : 99 : wide_int op_min_value, op_max_value;
5596 : 99 : tree def;
5597 : :
5598 : : /* ??? Merge ranges in case of more than one lane. */
5599 : 99 : if (SLP_TREE_LANES (slp_op0) != 1
5600 : 97 : || !(def = vect_get_slp_scalar_def (slp_op0, 0))
5601 : 196 : || !vect_get_range_info (def, &op_min_value, &op_max_value))
5602 : 94 : goto unsupported;
5603 : :
5604 : 5 : if ((wi::min_precision (op_max_value, SIGNED)
5605 : 5 : > GET_MODE_BITSIZE (lhs_mode))
5606 : 5 : || (wi::min_precision (op_min_value, SIGNED)
5607 : 5 : > GET_MODE_BITSIZE (lhs_mode)))
5608 : 0 : goto unsupported;
5609 : 99 : }
5610 : :
5611 : 10 : cvt_type
5612 : 10 : = build_nonstandard_integer_type (GET_MODE_BITSIZE (lhs_mode), 0);
5613 : 10 : cvt_type = get_same_sized_vectype (cvt_type, vectype_out);
5614 : 10 : if (cvt_type == NULL_TREE)
5615 : 0 : goto unsupported;
5616 : 10 : if (!supportable_narrowing_operation (NOP_EXPR, cvt_type, vectype_in,
5617 : : &code1, &multi_step_cvt,
5618 : : &interm_types))
5619 : 0 : goto unsupported;
5620 : 10 : if (supportable_convert_operation ((tree_code) code, vectype_out,
5621 : : cvt_type, &tc1))
5622 : : {
5623 : 10 : codecvt1 = tc1;
5624 : 10 : modifier = NARROW_SRC;
5625 : 10 : break;
5626 : : }
5627 : : }
5628 : :
5629 : 3566 : goto unsupported;
5630 : :
5631 : : default:
5632 : : gcc_unreachable ();
5633 : : }
5634 : :
5635 : 90771 : if (modifier == WIDEN
5636 : 90771 : && loop_vinfo
5637 : 41428 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
5638 : 108121 : && (code1 == VEC_WIDEN_MULT_EVEN_EXPR
5639 : 17334 : || widening_evenodd_fn_p (code1)))
5640 : : {
5641 : 16 : if (dump_enabled_p ())
5642 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5643 : : "can't use a fully-masked loop because"
5644 : : " widening operation on even/odd elements"
5645 : : " mixes up lanes.\n");
5646 : 16 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
5647 : : }
5648 : :
5649 : 90771 : if (cost_vec) /* transformation not required. */
5650 : : {
5651 : 68234 : if (!vect_maybe_update_slp_op_vectype (slp_op0, vectype_in)
5652 : 68234 : || !vect_maybe_update_slp_op_vectype (slp_op1, vectype_in))
5653 : : {
5654 : 0 : if (dump_enabled_p ())
5655 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5656 : : "incompatible vector types for invariants\n");
5657 : 0 : return false;
5658 : : }
5659 : 68234 : DUMP_VECT_SCOPE ("vectorizable_conversion");
5660 : 68234 : unsigned int nvectors = vect_get_num_copies (vinfo, slp_node);
5661 : 68234 : if (modifier == NONE)
5662 : : {
5663 : 12902 : SLP_TREE_TYPE (slp_node) = type_conversion_vec_info_type;
5664 : 12902 : vect_model_simple_cost (vinfo, (1 + multi_step_cvt),
5665 : : slp_node, cost_vec);
5666 : : }
5667 : 55332 : else if (modifier == NARROW_SRC || modifier == NARROW_DST)
5668 : : {
5669 : 22562 : SLP_TREE_TYPE (slp_node) = type_demotion_vec_info_type;
5670 : : /* The final packing step produces one vector result per copy. */
5671 : 22562 : vect_model_promotion_demotion_cost (slp_node, nvectors,
5672 : : multi_step_cvt, cost_vec,
5673 : : widen_arith);
5674 : : }
5675 : : else
5676 : : {
5677 : 32770 : SLP_TREE_TYPE (slp_node) = type_promotion_vec_info_type;
5678 : : /* The initial unpacking step produces two vector results
5679 : : per copy. MULTI_STEP_CVT is 0 for a single conversion,
5680 : : so >> MULTI_STEP_CVT divides by 2^(number of steps - 1). */
5681 : 32770 : vect_model_promotion_demotion_cost (slp_node,
5682 : : nvectors >> multi_step_cvt,
5683 : : multi_step_cvt, cost_vec,
5684 : : widen_arith);
5685 : : }
5686 : 68234 : interm_types.release ();
5687 : 68234 : return true;
5688 : 68234 : }
5689 : :
5690 : : /* Transform. */
5691 : 22537 : if (dump_enabled_p ())
5692 : 4245 : dump_printf_loc (MSG_NOTE, vect_location, "transform conversion.\n");
5693 : :
5694 : 22537 : if (op_type == binary_op)
5695 : : {
5696 : 504 : if (CONSTANT_CLASS_P (op0))
5697 : 0 : op0 = fold_convert (TREE_TYPE (op1), op0);
5698 : 504 : else if (CONSTANT_CLASS_P (op1))
5699 : 232 : op1 = fold_convert (TREE_TYPE (op0), op1);
5700 : : }
5701 : :
5702 : : /* In case of multi-step conversion, we first generate conversion operations
5703 : : to the intermediate types, and then from that types to the final one.
5704 : : We create vector destinations for the intermediate type (TYPES) received
5705 : : from supportable_*_operation, and store them in the correct order
5706 : : for future use in vect_create_vectorized_*_stmts (). */
5707 : 22537 : auto_vec<tree> vec_dsts (multi_step_cvt + 1);
5708 : 22537 : bool widen_or_narrow_float_p
5709 : 22537 : = cvt_type && (modifier == WIDEN || modifier == NARROW_SRC);
5710 : 22537 : vec_dest = vect_create_destination_var (scalar_dest,
5711 : : widen_or_narrow_float_p
5712 : : ? cvt_type : vectype_out);
5713 : 22537 : vec_dsts.quick_push (vec_dest);
5714 : :
5715 : 22537 : if (multi_step_cvt)
5716 : : {
5717 : 8755 : for (i = interm_types.length () - 1;
5718 : 8755 : interm_types.iterate (i, &intermediate_type); i--)
5719 : : {
5720 : 4621 : vec_dest = vect_create_destination_var (scalar_dest,
5721 : : intermediate_type);
5722 : 4621 : vec_dsts.quick_push (vec_dest);
5723 : : }
5724 : : }
5725 : :
5726 : 22537 : if (cvt_type)
5727 : 73 : vec_dest = vect_create_destination_var (scalar_dest,
5728 : : widen_or_narrow_float_p
5729 : : ? vectype_out : cvt_type);
5730 : :
5731 : 22537 : switch (modifier)
5732 : : {
5733 : 3889 : case NONE:
5734 : 3889 : vect_get_vec_defs (vinfo, slp_node, op0, &vec_oprnds0);
5735 : : /* vec_dest is intermediate type operand when multi_step_cvt. */
5736 : 3889 : if (multi_step_cvt)
5737 : : {
5738 : 21 : cvt_op = vec_dest;
5739 : 21 : vec_dest = vec_dsts[0];
5740 : : }
5741 : :
5742 : 8110 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
5743 : : {
5744 : : /* Arguments are ready, create the new vector stmt. */
5745 : 4221 : gimple* new_stmt;
5746 : 4221 : if (multi_step_cvt)
5747 : : {
5748 : 21 : gcc_assert (multi_step_cvt == 1);
5749 : 21 : new_stmt = vect_gimple_build (cvt_op, codecvt1, vop0);
5750 : 21 : new_temp = make_ssa_name (cvt_op, new_stmt);
5751 : 21 : gimple_assign_set_lhs (new_stmt, new_temp);
5752 : 21 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5753 : 21 : vop0 = new_temp;
5754 : : }
5755 : 4221 : new_stmt = vect_gimple_build (vec_dest, code1, vop0);
5756 : 4221 : new_temp = make_ssa_name (vec_dest, new_stmt);
5757 : 4221 : gimple_set_lhs (new_stmt, new_temp);
5758 : 4221 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5759 : :
5760 : 4221 : slp_node->push_vec_def (new_stmt);
5761 : : }
5762 : : break;
5763 : :
5764 : 9745 : case WIDEN:
5765 : : /* In case the vectorization factor (VF) is bigger than the number
5766 : : of elements that we can fit in a vectype (nunits), we have to
5767 : : generate more than one vector stmt - i.e - we need to "unroll"
5768 : : the vector stmt by a factor VF/nunits. */
5769 : 9745 : vect_get_vec_defs (vinfo, slp_node, op0, &vec_oprnds0,
5770 : 9745 : code == WIDEN_LSHIFT_EXPR ? NULL_TREE : op1,
5771 : : &vec_oprnds1);
5772 : 9745 : if (code == WIDEN_LSHIFT_EXPR)
5773 : : {
5774 : 0 : int oprnds_size = vec_oprnds0.length ();
5775 : 0 : vec_oprnds1.create (oprnds_size);
5776 : 0 : for (i = 0; i < oprnds_size; ++i)
5777 : 0 : vec_oprnds1.quick_push (op1);
5778 : : }
5779 : : /* Arguments are ready. Create the new vector stmts. */
5780 : 21143 : for (i = multi_step_cvt; i >= 0; i--)
5781 : : {
5782 : 11398 : tree this_dest = vec_dsts[i];
5783 : 11398 : code_helper c1 = code1, c2 = code2;
5784 : 11398 : if (i == 0 && codecvt2 != ERROR_MARK)
5785 : : {
5786 : 48 : c1 = codecvt1;
5787 : 48 : c2 = codecvt2;
5788 : : }
5789 : 11398 : if (known_eq (nunits_out, nunits_in))
5790 : 14 : vect_create_half_widening_stmts (vinfo, &vec_oprnds0, &vec_oprnds1,
5791 : : stmt_info, this_dest, gsi, c1,
5792 : : op_type);
5793 : : else
5794 : 11384 : vect_create_vectorized_promotion_stmts (vinfo, &vec_oprnds0,
5795 : : &vec_oprnds1, stmt_info,
5796 : : this_dest, gsi,
5797 : : c1, c2, op_type);
5798 : : }
5799 : :
5800 : 37007 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
5801 : : {
5802 : 27262 : gimple *new_stmt;
5803 : 27262 : if (cvt_type)
5804 : : {
5805 : 120 : new_temp = make_ssa_name (vec_dest);
5806 : 120 : new_stmt = vect_gimple_build (new_temp, codecvt1, vop0);
5807 : 120 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5808 : : }
5809 : : else
5810 : 27142 : new_stmt = SSA_NAME_DEF_STMT (vop0);
5811 : :
5812 : 27262 : slp_node->push_vec_def (new_stmt);
5813 : : }
5814 : : break;
5815 : :
5816 : 8903 : case NARROW_SRC:
5817 : 8903 : case NARROW_DST:
5818 : : /* In case the vectorization factor (VF) is bigger than the number
5819 : : of elements that we can fit in a vectype (nunits), we have to
5820 : : generate more than one vector stmt - i.e - we need to "unroll"
5821 : : the vector stmt by a factor VF/nunits. */
5822 : 8903 : vect_get_vec_defs (vinfo, slp_node, op0, &vec_oprnds0);
5823 : : /* Arguments are ready. Create the new vector stmts. */
5824 : 8903 : if (cvt_type && modifier == NARROW_DST)
5825 : 153 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
5826 : : {
5827 : 124 : new_temp = make_ssa_name (vec_dest);
5828 : 124 : gimple *new_stmt = vect_gimple_build (new_temp, codecvt1, vop0);
5829 : 124 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5830 : 124 : vec_oprnds0[i] = new_temp;
5831 : : }
5832 : :
5833 : 8903 : vect_create_vectorized_demotion_stmts (vinfo, &vec_oprnds0,
5834 : : multi_step_cvt,
5835 : : stmt_info, vec_dsts, gsi,
5836 : : slp_node, code1,
5837 : : modifier == NARROW_SRC);
5838 : : /* After demoting op0 to cvt_type, convert it to dest. */
5839 : 8903 : if (cvt_type && code == FLOAT_EXPR)
5840 : : {
5841 : 10 : for (unsigned int i = 0; i != vec_oprnds0.length() / 2; i++)
5842 : : {
5843 : : /* Arguments are ready, create the new vector stmt. */
5844 : 5 : gcc_assert (TREE_CODE_LENGTH ((tree_code) codecvt1) == unary_op);
5845 : 5 : gimple *new_stmt
5846 : 5 : = vect_gimple_build (vec_dest, codecvt1, vec_oprnds0[i]);
5847 : 5 : new_temp = make_ssa_name (vec_dest, new_stmt);
5848 : 5 : gimple_set_lhs (new_stmt, new_temp);
5849 : 5 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
5850 : :
5851 : : /* This is the last step of the conversion sequence. Store the
5852 : : vectors in SLP_NODE or in vector info of the scalar statement
5853 : : (or in STMT_VINFO_RELATED_STMT chain). */
5854 : 5 : slp_node->push_vec_def (new_stmt);
5855 : : }
5856 : : }
5857 : : break;
5858 : : }
5859 : :
5860 : 22537 : vec_oprnds0.release ();
5861 : 22537 : vec_oprnds1.release ();
5862 : 22537 : interm_types.release ();
5863 : :
5864 : 22537 : return true;
5865 : 152162 : }
5866 : :
5867 : : /* Return true if we can assume from the scalar form of STMT_INFO that
5868 : : neither the scalar nor the vector forms will generate code. STMT_INFO
5869 : : is known not to involve a data reference. */
5870 : :
5871 : : bool
5872 : 1020549 : vect_nop_conversion_p (stmt_vec_info stmt_info)
5873 : : {
5874 : 1020549 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
5875 : 774580 : if (!stmt)
5876 : : return false;
5877 : :
5878 : 774580 : tree lhs = gimple_assign_lhs (stmt);
5879 : 774580 : tree_code code = gimple_assign_rhs_code (stmt);
5880 : 774580 : tree rhs = gimple_assign_rhs1 (stmt);
5881 : :
5882 : 774580 : if (code == SSA_NAME || code == VIEW_CONVERT_EXPR)
5883 : : return true;
5884 : :
5885 : 772313 : if (CONVERT_EXPR_CODE_P (code))
5886 : 192292 : return tree_nop_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs));
5887 : :
5888 : : return false;
5889 : : }
5890 : :
5891 : : /* Function vectorizable_assignment.
5892 : :
5893 : : Check if STMT_INFO performs an assignment (copy) that can be vectorized.
5894 : : If COST_VEC is passed, calculate costs but don't change anything,
5895 : : otherwise, vectorize STMT_INFO: create a vectorized stmt to replace
5896 : : it, and insert it at GSI.
5897 : : Return true if STMT_INFO is vectorizable in this way. */
5898 : :
5899 : : static bool
5900 : 1843528 : vectorizable_assignment (vec_info *vinfo,
5901 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
5902 : : slp_tree slp_node,
5903 : : stmt_vector_for_cost *cost_vec)
5904 : : {
5905 : 1843528 : tree vec_dest;
5906 : 1843528 : tree scalar_dest;
5907 : 1843528 : tree op;
5908 : 1843528 : tree new_temp;
5909 : 1843528 : enum vect_def_type dt[1] = {vect_unknown_def_type};
5910 : 1843528 : int i;
5911 : 1843528 : vec<tree> vec_oprnds = vNULL;
5912 : 1843528 : tree vop;
5913 : 1843528 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
5914 : 1843528 : enum tree_code code;
5915 : 1843528 : tree vectype_in;
5916 : :
5917 : 1843528 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
5918 : : return false;
5919 : :
5920 : 1843528 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
5921 : 176586 : && cost_vec)
5922 : : return false;
5923 : :
5924 : : /* Is vectorizable assignment? */
5925 : 3373130 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
5926 : 1602502 : if (!stmt)
5927 : : return false;
5928 : :
5929 : 1602502 : scalar_dest = gimple_assign_lhs (stmt);
5930 : 1602502 : if (TREE_CODE (scalar_dest) != SSA_NAME)
5931 : : return false;
5932 : :
5933 : 822106 : if (STMT_VINFO_DATA_REF (stmt_info))
5934 : : return false;
5935 : :
5936 : 354110 : code = gimple_assign_rhs_code (stmt);
5937 : 354110 : if (!(gimple_assign_single_p (stmt)
5938 : 352776 : || code == PAREN_EXPR
5939 : 351194 : || CONVERT_EXPR_CODE_P (code)))
5940 : : return false;
5941 : :
5942 : 83007 : tree vectype = SLP_TREE_VECTYPE (slp_node);
5943 : 83007 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
5944 : :
5945 : 83007 : slp_tree slp_op;
5946 : 83007 : if (!vect_is_simple_use (vinfo, slp_node, 0, &op, &slp_op,
5947 : : &dt[0], &vectype_in))
5948 : : {
5949 : 0 : if (dump_enabled_p ())
5950 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5951 : : "use not simple.\n");
5952 : 0 : return false;
5953 : : }
5954 : 83007 : if (!vectype_in)
5955 : 18060 : vectype_in = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op), slp_node);
5956 : :
5957 : : /* We can handle VIEW_CONVERT conversions that do not change the number
5958 : : of elements or the vector size or other conversions when the component
5959 : : types are nop-convertible. */
5960 : 83007 : if (!vectype_in
5961 : 82727 : || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype_in), nunits)
5962 : 76174 : || (code == VIEW_CONVERT_EXPR
5963 : 2412 : && maybe_ne (GET_MODE_SIZE (TYPE_MODE (vectype)),
5964 : 2412 : GET_MODE_SIZE (TYPE_MODE (vectype_in))))
5965 : 159181 : || (CONVERT_EXPR_CODE_P (code)
5966 : 73290 : && !tree_nop_conversion_p (TREE_TYPE (vectype),
5967 : 73290 : TREE_TYPE (vectype_in))))
5968 : 9845 : return false;
5969 : :
5970 : 219408 : if (VECTOR_BOOLEAN_TYPE_P (vectype) != VECTOR_BOOLEAN_TYPE_P (vectype_in))
5971 : : {
5972 : 2 : if (dump_enabled_p ())
5973 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5974 : : "can't convert between boolean and non "
5975 : 0 : "boolean vectors %T\n", TREE_TYPE (op));
5976 : :
5977 : 2 : return false;
5978 : : }
5979 : :
5980 : : /* We do not handle bit-precision changes. */
5981 : 73160 : if ((CONVERT_EXPR_CODE_P (code)
5982 : 2884 : || code == VIEW_CONVERT_EXPR)
5983 : 71482 : && ((INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
5984 : 70216 : && !type_has_mode_precision_p (TREE_TYPE (scalar_dest)))
5985 : 71182 : || (INTEGRAL_TYPE_P (TREE_TYPE (op))
5986 : 66747 : && !type_has_mode_precision_p (TREE_TYPE (op))))
5987 : : /* But a conversion that does not change the bit-pattern is ok. */
5988 : 73828 : && !(INTEGRAL_TYPE_P (TREE_TYPE (scalar_dest))
5989 : 668 : && INTEGRAL_TYPE_P (TREE_TYPE (op))
5990 : 668 : && (((TYPE_PRECISION (TREE_TYPE (scalar_dest))
5991 : 668 : > TYPE_PRECISION (TREE_TYPE (op)))
5992 : 368 : && TYPE_UNSIGNED (TREE_TYPE (op)))
5993 : 316 : || (TYPE_PRECISION (TREE_TYPE (scalar_dest))
5994 : 316 : == TYPE_PRECISION (TREE_TYPE (op))))))
5995 : : {
5996 : 260 : if (dump_enabled_p ())
5997 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5998 : : "type conversion to/from bit-precision "
5999 : : "unsupported.\n");
6000 : 260 : return false;
6001 : : }
6002 : :
6003 : 72900 : if (cost_vec) /* transformation not required. */
6004 : : {
6005 : 58203 : if (!vect_maybe_update_slp_op_vectype (slp_op, vectype_in))
6006 : : {
6007 : 0 : if (dump_enabled_p ())
6008 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6009 : : "incompatible vector types for invariants\n");
6010 : 0 : return false;
6011 : : }
6012 : 58203 : SLP_TREE_TYPE (slp_node) = assignment_vec_info_type;
6013 : 58203 : DUMP_VECT_SCOPE ("vectorizable_assignment");
6014 : 58203 : if (!vect_nop_conversion_p (stmt_info))
6015 : 1329 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
6016 : 58203 : return true;
6017 : : }
6018 : :
6019 : : /* Transform. */
6020 : 14697 : if (dump_enabled_p ())
6021 : 3498 : dump_printf_loc (MSG_NOTE, vect_location, "transform assignment.\n");
6022 : :
6023 : : /* Handle def. */
6024 : 14697 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6025 : :
6026 : : /* Handle use. */
6027 : 14697 : vect_get_vec_defs (vinfo, slp_node, op, &vec_oprnds);
6028 : :
6029 : : /* Arguments are ready. create the new vector stmt. */
6030 : 33462 : FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
6031 : : {
6032 : 18765 : if (CONVERT_EXPR_CODE_P (code)
6033 : 682 : || code == VIEW_CONVERT_EXPR)
6034 : 18215 : vop = build1 (VIEW_CONVERT_EXPR, vectype, vop);
6035 : 18765 : gassign *new_stmt = gimple_build_assign (vec_dest, vop);
6036 : 18765 : new_temp = make_ssa_name (vec_dest, new_stmt);
6037 : 18765 : gimple_assign_set_lhs (new_stmt, new_temp);
6038 : 18765 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6039 : 18765 : slp_node->push_vec_def (new_stmt);
6040 : : }
6041 : :
6042 : 14697 : vec_oprnds.release ();
6043 : 14697 : return true;
6044 : : }
6045 : :
6046 : :
6047 : : /* Return TRUE if CODE (a shift operation) is supported for SCALAR_TYPE
6048 : : either as shift by a scalar or by a vector. */
6049 : :
6050 : : bool
6051 : 272455 : vect_supportable_shift (vec_info *vinfo, enum tree_code code, tree scalar_type)
6052 : : {
6053 : 272455 : optab optab;
6054 : 272455 : tree vectype;
6055 : :
6056 : 272455 : vectype = get_vectype_for_scalar_type (vinfo, scalar_type);
6057 : 272455 : if (!vectype)
6058 : : return false;
6059 : :
6060 : 272455 : optab = optab_for_tree_code (code, vectype, optab_scalar);
6061 : 272455 : if (optab && can_implement_p (optab, TYPE_MODE (vectype)))
6062 : : return true;
6063 : :
6064 : 239091 : optab = optab_for_tree_code (code, vectype, optab_vector);
6065 : 239091 : if (optab && can_implement_p (optab, TYPE_MODE (vectype)))
6066 : : return true;
6067 : :
6068 : : return false;
6069 : : }
6070 : :
6071 : :
6072 : : /* Function vectorizable_shift.
6073 : :
6074 : : Check if STMT_INFO performs a shift operation that can be vectorized.
6075 : : If COST_VEC is passed, calculate costs but don't change anything,
6076 : : otherwise, vectorize STMT_INFO: create a vectorized stmt to replace
6077 : : it, and insert it at GSI.
6078 : : Return true if STMT_INFO is vectorizable in this way. */
6079 : :
6080 : : static bool
6081 : 623671 : vectorizable_shift (vec_info *vinfo,
6082 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
6083 : : slp_tree slp_node,
6084 : : stmt_vector_for_cost *cost_vec)
6085 : : {
6086 : 623671 : tree vec_dest;
6087 : 623671 : tree scalar_dest;
6088 : 623671 : tree op0, op1 = NULL;
6089 : 623671 : tree vec_oprnd1 = NULL_TREE;
6090 : 623671 : tree vectype;
6091 : 623671 : enum tree_code code;
6092 : 623671 : machine_mode vec_mode;
6093 : 623671 : tree new_temp;
6094 : 623671 : optab optab;
6095 : 623671 : int icode;
6096 : 623671 : machine_mode optab_op2_mode;
6097 : 623671 : enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
6098 : 623671 : poly_uint64 nunits_in;
6099 : 623671 : poly_uint64 nunits_out;
6100 : 623671 : tree vectype_out;
6101 : 623671 : tree op1_vectype;
6102 : 623671 : int i;
6103 : 623671 : vec<tree> vec_oprnds0 = vNULL;
6104 : 623671 : vec<tree> vec_oprnds1 = vNULL;
6105 : 623671 : tree vop0, vop1;
6106 : 623671 : unsigned int k;
6107 : 623671 : bool scalar_shift_arg = true;
6108 : 623671 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
6109 : 623671 : bool incompatible_op1_vectype_p = false;
6110 : :
6111 : 623671 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
6112 : : return false;
6113 : :
6114 : 623671 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
6115 : 176586 : && STMT_VINFO_DEF_TYPE (stmt_info) != vect_nested_cycle
6116 : 175247 : && cost_vec)
6117 : : return false;
6118 : :
6119 : : /* Is STMT a vectorizable binary/unary operation? */
6120 : 959573 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
6121 : 384392 : if (!stmt)
6122 : : return false;
6123 : :
6124 : 384392 : if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
6125 : : return false;
6126 : :
6127 : 383908 : code = gimple_assign_rhs_code (stmt);
6128 : :
6129 : 383908 : if (!(code == LSHIFT_EXPR || code == RSHIFT_EXPR || code == LROTATE_EXPR
6130 : : || code == RROTATE_EXPR))
6131 : : return false;
6132 : :
6133 : 54540 : scalar_dest = gimple_assign_lhs (stmt);
6134 : 54540 : vectype_out = SLP_TREE_VECTYPE (slp_node);
6135 : 54540 : if (!type_has_mode_precision_p (TREE_TYPE (scalar_dest)))
6136 : : {
6137 : 0 : if (dump_enabled_p ())
6138 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6139 : : "bit-precision shifts not supported.\n");
6140 : 0 : return false;
6141 : : }
6142 : :
6143 : 54540 : slp_tree slp_op0;
6144 : 54540 : if (!vect_is_simple_use (vinfo, slp_node,
6145 : : 0, &op0, &slp_op0, &dt[0], &vectype))
6146 : : {
6147 : 0 : if (dump_enabled_p ())
6148 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6149 : : "use not simple.\n");
6150 : 0 : return false;
6151 : : }
6152 : : /* If op0 is an external or constant def, infer the vector type
6153 : : from the scalar type. */
6154 : 54540 : if (!vectype)
6155 : 12289 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0), slp_node);
6156 : 54540 : if (!cost_vec)
6157 : 7579 : gcc_assert (vectype);
6158 : 54540 : if (!vectype)
6159 : : {
6160 : 0 : if (dump_enabled_p ())
6161 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6162 : : "no vectype for scalar type\n");
6163 : 0 : return false;
6164 : : }
6165 : :
6166 : 54540 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
6167 : 54540 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
6168 : 54540 : if (maybe_ne (nunits_out, nunits_in))
6169 : : return false;
6170 : :
6171 : 54540 : stmt_vec_info op1_def_stmt_info;
6172 : 54540 : slp_tree slp_op1;
6173 : 54540 : if (!vect_is_simple_use (vinfo, slp_node, 1, &op1, &slp_op1,
6174 : : &dt[1], &op1_vectype, &op1_def_stmt_info))
6175 : : {
6176 : 0 : if (dump_enabled_p ())
6177 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6178 : : "use not simple.\n");
6179 : 0 : return false;
6180 : : }
6181 : :
6182 : : /* Determine whether the shift amount is a vector, or scalar. If the
6183 : : shift/rotate amount is a vector, use the vector/vector shift optabs. */
6184 : :
6185 : 54540 : if ((dt[1] == vect_internal_def
6186 : 54540 : || dt[1] == vect_induction_def
6187 : 41478 : || dt[1] == vect_nested_cycle)
6188 : 13080 : && SLP_TREE_LANES (slp_node) == 1)
6189 : : scalar_shift_arg = false;
6190 : 41515 : else if (dt[1] == vect_constant_def
6191 : : || dt[1] == vect_external_def
6192 : 41515 : || dt[1] == vect_internal_def)
6193 : : {
6194 : : /* In SLP, need to check whether the shift count is the same,
6195 : : in loops if it is a constant or invariant, it is always
6196 : : a scalar shift. */
6197 : 41509 : vec<stmt_vec_info> stmts = SLP_TREE_SCALAR_STMTS (slp_node);
6198 : 41509 : stmt_vec_info slpstmt_info;
6199 : :
6200 : 113970 : FOR_EACH_VEC_ELT (stmts, k, slpstmt_info)
6201 : 72461 : if (slpstmt_info)
6202 : : {
6203 : 72461 : gassign *slpstmt = as_a <gassign *> (slpstmt_info->stmt);
6204 : 144922 : if (!operand_equal_p (gimple_assign_rhs2 (slpstmt), op1, 0))
6205 : 72461 : scalar_shift_arg = false;
6206 : : }
6207 : :
6208 : : /* For internal SLP defs we have to make sure we see scalar stmts
6209 : : for all vector elements.
6210 : : ??? For different vectors we could resort to a different
6211 : : scalar shift operand but code-generation below simply always
6212 : : takes the first. */
6213 : 41509 : if (dt[1] == vect_internal_def
6214 : 41558 : && maybe_ne (nunits_out * vect_get_num_copies (vinfo, slp_node),
6215 : 49 : stmts.length ()))
6216 : : scalar_shift_arg = false;
6217 : :
6218 : : /* If the shift amount is computed by a pattern stmt we cannot
6219 : : use the scalar amount directly thus give up and use a vector
6220 : : shift. */
6221 : 41509 : if (op1_def_stmt_info && is_pattern_stmt_p (op1_def_stmt_info))
6222 : : scalar_shift_arg = false;
6223 : : }
6224 : : else
6225 : : {
6226 : 6 : if (dump_enabled_p ())
6227 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6228 : : "operand mode requires invariant argument.\n");
6229 : 6 : return false;
6230 : : }
6231 : :
6232 : : /* Vector shifted by vector. */
6233 : 54572 : bool was_scalar_shift_arg = scalar_shift_arg;
6234 : 41500 : if (!scalar_shift_arg)
6235 : : {
6236 : 13072 : optab = optab_for_tree_code (code, vectype, optab_vector);
6237 : 13072 : if (dump_enabled_p ())
6238 : 1193 : dump_printf_loc (MSG_NOTE, vect_location,
6239 : : "vector/vector shift/rotate found.\n");
6240 : :
6241 : 13072 : if (!op1_vectype)
6242 : 15 : op1_vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op1),
6243 : : slp_op1);
6244 : 13072 : incompatible_op1_vectype_p
6245 : 26144 : = (op1_vectype == NULL_TREE
6246 : 13072 : || maybe_ne (TYPE_VECTOR_SUBPARTS (op1_vectype),
6247 : 13072 : TYPE_VECTOR_SUBPARTS (vectype))
6248 : 26142 : || TYPE_MODE (op1_vectype) != TYPE_MODE (vectype));
6249 : 13065 : if (incompatible_op1_vectype_p
6250 : 7 : && (SLP_TREE_DEF_TYPE (slp_op1) != vect_constant_def
6251 : 1 : || slp_op1->refcnt != 1))
6252 : : {
6253 : 6 : if (dump_enabled_p ())
6254 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6255 : : "unusable type for last operand in"
6256 : : " vector/vector shift/rotate.\n");
6257 : 6 : return false;
6258 : : }
6259 : : }
6260 : : /* See if the machine has a vector shifted by scalar insn and if not
6261 : : then see if it has a vector shifted by vector insn. */
6262 : : else
6263 : : {
6264 : 41462 : optab = optab_for_tree_code (code, vectype, optab_scalar);
6265 : 41462 : if (optab
6266 : 41462 : && can_implement_p (optab, TYPE_MODE (vectype)))
6267 : : {
6268 : 41462 : if (dump_enabled_p ())
6269 : 4882 : dump_printf_loc (MSG_NOTE, vect_location,
6270 : : "vector/scalar shift/rotate found.\n");
6271 : : }
6272 : : else
6273 : : {
6274 : 0 : optab = optab_for_tree_code (code, vectype, optab_vector);
6275 : 0 : if (optab
6276 : 0 : && can_implement_p (optab, TYPE_MODE (vectype)))
6277 : : {
6278 : 0 : scalar_shift_arg = false;
6279 : :
6280 : 0 : if (dump_enabled_p ())
6281 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
6282 : : "vector/vector shift/rotate found.\n");
6283 : :
6284 : 0 : if (!op1_vectype)
6285 : 0 : op1_vectype = get_vectype_for_scalar_type (vinfo,
6286 : 0 : TREE_TYPE (op1),
6287 : : slp_op1);
6288 : :
6289 : : /* Unlike the other binary operators, shifts/rotates have
6290 : : the rhs being int, instead of the same type as the lhs,
6291 : : so make sure the scalar is the right type if we are
6292 : : dealing with vectors of long long/long/short/char. */
6293 : 0 : incompatible_op1_vectype_p
6294 : 0 : = (!op1_vectype
6295 : 0 : || !tree_nop_conversion_p (TREE_TYPE (vectype),
6296 : 0 : TREE_TYPE (op1)));
6297 : 0 : if (incompatible_op1_vectype_p
6298 : 0 : && dt[1] == vect_internal_def)
6299 : : {
6300 : 0 : if (dump_enabled_p ())
6301 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6302 : : "unusable type for last operand in"
6303 : : " vector/vector shift/rotate.\n");
6304 : 0 : return false;
6305 : : }
6306 : : }
6307 : : }
6308 : : }
6309 : :
6310 : : /* Supportable by target? */
6311 : 54528 : if (!optab)
6312 : : {
6313 : 0 : if (dump_enabled_p ())
6314 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6315 : : "no optab.\n");
6316 : 0 : return false;
6317 : : }
6318 : 54528 : vec_mode = TYPE_MODE (vectype);
6319 : 54528 : icode = (int) optab_handler (optab, vec_mode);
6320 : 54528 : if (icode == CODE_FOR_nothing)
6321 : : {
6322 : 6038 : if (dump_enabled_p ())
6323 : 886 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6324 : : "op not supported by target.\n");
6325 : 6038 : return false;
6326 : : }
6327 : : /* vector lowering cannot optimize vector shifts using word arithmetic. */
6328 : 48490 : if (vect_emulated_vector_p (vectype))
6329 : : return false;
6330 : :
6331 : 48490 : if (cost_vec) /* transformation not required. */
6332 : : {
6333 : 40911 : if (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
6334 : 40911 : || ((!scalar_shift_arg || dt[1] == vect_internal_def)
6335 : 4948 : && (!incompatible_op1_vectype_p
6336 : 1 : || dt[1] == vect_constant_def)
6337 : 4948 : && !vect_maybe_update_slp_op_vectype
6338 : 4948 : (slp_op1,
6339 : : incompatible_op1_vectype_p ? vectype : op1_vectype)))
6340 : : {
6341 : 0 : if (dump_enabled_p ())
6342 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6343 : : "incompatible vector types for invariants\n");
6344 : 0 : return false;
6345 : : }
6346 : : /* Now adjust the constant shift amount in place. */
6347 : 40911 : if (incompatible_op1_vectype_p
6348 : 1 : && dt[1] == vect_constant_def)
6349 : 4 : for (unsigned i = 0;
6350 : 5 : i < SLP_TREE_SCALAR_OPS (slp_op1).length (); ++i)
6351 : : {
6352 : 4 : SLP_TREE_SCALAR_OPS (slp_op1)[i]
6353 : 4 : = fold_convert (TREE_TYPE (vectype),
6354 : : SLP_TREE_SCALAR_OPS (slp_op1)[i]);
6355 : 4 : gcc_assert ((TREE_CODE (SLP_TREE_SCALAR_OPS (slp_op1)[i])
6356 : : == INTEGER_CST));
6357 : : }
6358 : 40911 : SLP_TREE_TYPE (slp_node) = shift_vec_info_type;
6359 : 40911 : DUMP_VECT_SCOPE ("vectorizable_shift");
6360 : 40911 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
6361 : 40911 : return true;
6362 : : }
6363 : :
6364 : : /* Transform. */
6365 : :
6366 : 7579 : if (dump_enabled_p ())
6367 : 1992 : dump_printf_loc (MSG_NOTE, vect_location,
6368 : : "transform binary/unary operation.\n");
6369 : :
6370 : : /* Handle def. */
6371 : 7579 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6372 : :
6373 : 7579 : unsigned nvectors = vect_get_num_copies (vinfo, slp_node);
6374 : 7579 : if (scalar_shift_arg && dt[1] != vect_internal_def)
6375 : : {
6376 : : /* Vector shl and shr insn patterns can be defined with scalar
6377 : : operand 2 (shift operand). In this case, use constant or loop
6378 : : invariant op1 directly, without extending it to vector mode
6379 : : first. */
6380 : 5479 : optab_op2_mode = insn_data[icode].operand[2].mode;
6381 : 5479 : if (!VECTOR_MODE_P (optab_op2_mode))
6382 : : {
6383 : 5479 : if (dump_enabled_p ())
6384 : 1878 : dump_printf_loc (MSG_NOTE, vect_location,
6385 : : "operand 1 using scalar mode.\n");
6386 : 5479 : vec_oprnd1 = op1;
6387 : 5479 : vec_oprnds1.create (nvectors);
6388 : 5479 : vec_oprnds1.quick_push (vec_oprnd1);
6389 : : /* Store vec_oprnd1 for every vector stmt to be created.
6390 : : We check during the analysis that all the shift arguments
6391 : : are the same.
6392 : : TODO: Allow different constants for different vector
6393 : : stmts generated for an SLP instance. */
6394 : 12975 : for (k = 0; k < nvectors - 1; k++)
6395 : 2017 : vec_oprnds1.quick_push (vec_oprnd1);
6396 : : }
6397 : : }
6398 : 2100 : else if (!scalar_shift_arg && incompatible_op1_vectype_p)
6399 : : {
6400 : 0 : if (was_scalar_shift_arg)
6401 : : {
6402 : : /* If the argument was the same in all lanes create the
6403 : : correctly typed vector shift amount directly. Note
6404 : : we made SLP scheduling think we use the original scalars,
6405 : : so place the compensation code next to the shift which
6406 : : is conservative. See PR119640 where it otherwise breaks. */
6407 : 0 : op1 = fold_convert (TREE_TYPE (vectype), op1);
6408 : 0 : op1 = vect_init_vector (vinfo, stmt_info, op1, TREE_TYPE (vectype),
6409 : : gsi);
6410 : 0 : vec_oprnd1 = vect_init_vector (vinfo, stmt_info, op1, vectype,
6411 : : gsi);
6412 : 0 : vec_oprnds1.create (nvectors);
6413 : 0 : for (k = 0; k < nvectors; k++)
6414 : 0 : vec_oprnds1.quick_push (vec_oprnd1);
6415 : : }
6416 : 0 : else if (dt[1] == vect_constant_def)
6417 : : /* The constant shift amount has been adjusted in place. */
6418 : : ;
6419 : : else
6420 : 0 : gcc_assert (TYPE_MODE (op1_vectype) == TYPE_MODE (vectype));
6421 : : }
6422 : :
6423 : : /* vec_oprnd1 is available if operand 1 should be of a scalar-type
6424 : : (a special case for certain kind of vector shifts); otherwise,
6425 : : operand 1 should be of a vector type (the usual case). */
6426 : 2100 : vect_get_vec_defs (vinfo, slp_node,
6427 : : op0, &vec_oprnds0,
6428 : 7579 : vec_oprnd1 ? NULL_TREE : op1, &vec_oprnds1);
6429 : :
6430 : : /* Arguments are ready. Create the new vector stmt. */
6431 : 20606 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6432 : : {
6433 : : /* For internal defs where we need to use a scalar shift arg
6434 : : extract the first lane. */
6435 : 13027 : if (scalar_shift_arg && dt[1] == vect_internal_def)
6436 : : {
6437 : 10 : vop1 = vec_oprnds1[0];
6438 : 10 : new_temp = make_ssa_name (TREE_TYPE (TREE_TYPE (vop1)));
6439 : 10 : gassign *new_stmt
6440 : 10 : = gimple_build_assign (new_temp,
6441 : 10 : build3 (BIT_FIELD_REF, TREE_TYPE (new_temp),
6442 : : vop1,
6443 : 10 : TYPE_SIZE (TREE_TYPE (new_temp)),
6444 : : bitsize_zero_node));
6445 : 10 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6446 : 10 : vop1 = new_temp;
6447 : 10 : }
6448 : : else
6449 : 13017 : vop1 = vec_oprnds1[i];
6450 : 13027 : gassign *new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1);
6451 : 13027 : new_temp = make_ssa_name (vec_dest, new_stmt);
6452 : 13027 : gimple_assign_set_lhs (new_stmt, new_temp);
6453 : 13027 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6454 : 13027 : slp_node->push_vec_def (new_stmt);
6455 : : }
6456 : :
6457 : 7579 : vec_oprnds0.release ();
6458 : 7579 : vec_oprnds1.release ();
6459 : :
6460 : 7579 : return true;
6461 : : }
6462 : :
6463 : : /* Function vectorizable_operation.
6464 : :
6465 : : Check if STMT_INFO performs a binary, unary or ternary operation that can
6466 : : be vectorized.
6467 : : If COST_VEC is passed, calculate costs but don't change anything,
6468 : : otherwise, vectorize STMT_INFO: create a vectorized stmt to replace
6469 : : it, and insert it at GSI.
6470 : : Return true if STMT_INFO is vectorizable in this way. */
6471 : :
6472 : : static bool
6473 : 2349587 : vectorizable_operation (vec_info *vinfo,
6474 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
6475 : : slp_tree slp_node,
6476 : : stmt_vector_for_cost *cost_vec)
6477 : : {
6478 : 2349587 : tree vec_dest;
6479 : 2349587 : tree scalar_dest;
6480 : 2349587 : tree op0, op1 = NULL_TREE, op2 = NULL_TREE;
6481 : 2349587 : tree vectype;
6482 : 2349587 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
6483 : 2349587 : enum tree_code code, orig_code;
6484 : 2349587 : machine_mode vec_mode;
6485 : 2349587 : tree new_temp;
6486 : 2349587 : int op_type;
6487 : 2349587 : optab optab;
6488 : 2349587 : bool target_support_p;
6489 : 2349587 : enum vect_def_type dt[3]
6490 : : = {vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type};
6491 : 2349587 : poly_uint64 nunits_in;
6492 : 2349587 : poly_uint64 nunits_out;
6493 : 2349587 : tree vectype_out;
6494 : 2349587 : int i;
6495 : 2349587 : vec<tree> vec_oprnds0 = vNULL;
6496 : 2349587 : vec<tree> vec_oprnds1 = vNULL;
6497 : 2349587 : vec<tree> vec_oprnds2 = vNULL;
6498 : 2349587 : tree vop0, vop1, vop2;
6499 : 2349587 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
6500 : :
6501 : 2349587 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
6502 : : return false;
6503 : :
6504 : 2349587 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
6505 : 176586 : && cost_vec)
6506 : : return false;
6507 : :
6508 : : /* Is STMT a vectorizable binary/unary operation? */
6509 : 3937392 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
6510 : 2108561 : if (!stmt)
6511 : : return false;
6512 : :
6513 : : /* Loads and stores are handled in vectorizable_{load,store}. */
6514 : 2108561 : if (STMT_VINFO_DATA_REF (stmt_info))
6515 : : return false;
6516 : :
6517 : 860169 : orig_code = code = gimple_assign_rhs_code (stmt);
6518 : :
6519 : : /* Shifts are handled in vectorizable_shift. */
6520 : 860169 : if (code == LSHIFT_EXPR
6521 : : || code == RSHIFT_EXPR
6522 : : || code == LROTATE_EXPR
6523 : 860169 : || code == RROTATE_EXPR)
6524 : : return false;
6525 : :
6526 : : /* Comparisons are handled in vectorizable_comparison. */
6527 : 813208 : if (TREE_CODE_CLASS (code) == tcc_comparison)
6528 : : return false;
6529 : :
6530 : : /* Conditions are handled in vectorizable_condition. */
6531 : 638653 : if (code == COND_EXPR)
6532 : : return false;
6533 : :
6534 : : /* For pointer addition and subtraction, we should use the normal
6535 : : plus and minus for the vector operation. */
6536 : 619103 : if (code == POINTER_PLUS_EXPR)
6537 : : code = PLUS_EXPR;
6538 : 604891 : if (code == POINTER_DIFF_EXPR)
6539 : 980 : code = MINUS_EXPR;
6540 : :
6541 : : /* Support only unary or binary operations. */
6542 : 619103 : op_type = TREE_CODE_LENGTH (code);
6543 : 619103 : if (op_type != unary_op && op_type != binary_op && op_type != ternary_op)
6544 : : {
6545 : 0 : if (dump_enabled_p ())
6546 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6547 : : "num. args = %d (not unary/binary/ternary op).\n",
6548 : : op_type);
6549 : 0 : return false;
6550 : : }
6551 : :
6552 : 619103 : scalar_dest = gimple_assign_lhs (stmt);
6553 : 619103 : vectype_out = SLP_TREE_VECTYPE (slp_node);
6554 : :
6555 : : /* Most operations cannot handle bit-precision types without extra
6556 : : truncations. */
6557 : 619103 : bool mask_op_p = VECTOR_BOOLEAN_TYPE_P (vectype_out);
6558 : 610675 : if (!mask_op_p
6559 : 610675 : && !type_has_mode_precision_p (TREE_TYPE (scalar_dest))
6560 : : /* Exception are bitwise binary operations. */
6561 : : && code != BIT_IOR_EXPR
6562 : 1531 : && code != BIT_XOR_EXPR
6563 : 1248 : && code != BIT_AND_EXPR)
6564 : : {
6565 : 1010 : if (dump_enabled_p ())
6566 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6567 : : "bit-precision arithmetic not supported.\n");
6568 : 1010 : return false;
6569 : : }
6570 : :
6571 : 618093 : slp_tree slp_op0;
6572 : 618093 : if (!vect_is_simple_use (vinfo, slp_node,
6573 : : 0, &op0, &slp_op0, &dt[0], &vectype))
6574 : : {
6575 : 0 : if (dump_enabled_p ())
6576 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6577 : : "use not simple.\n");
6578 : 0 : return false;
6579 : : }
6580 : 618093 : bool is_invariant = (dt[0] == vect_external_def
6581 : 618093 : || dt[0] == vect_constant_def);
6582 : : /* If op0 is an external or constant def, infer the vector type
6583 : : from the scalar type. */
6584 : 618093 : if (!vectype)
6585 : : {
6586 : : /* For boolean type we cannot determine vectype by
6587 : : invariant value (don't know whether it is a vector
6588 : : of booleans or vector of integers). We use output
6589 : : vectype because operations on boolean don't change
6590 : : type. */
6591 : 70053 : if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op0)))
6592 : : {
6593 : 1077 : if (!VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (scalar_dest)))
6594 : : {
6595 : 229 : if (dump_enabled_p ())
6596 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6597 : : "not supported operation on bool value.\n");
6598 : 229 : return false;
6599 : : }
6600 : 848 : vectype = vectype_out;
6601 : : }
6602 : : else
6603 : 68976 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0),
6604 : : slp_node);
6605 : : }
6606 : 617864 : if (!cost_vec)
6607 : 114067 : gcc_assert (vectype);
6608 : 617864 : if (!vectype)
6609 : : {
6610 : 292 : if (dump_enabled_p ())
6611 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6612 : : "no vectype for scalar type %T\n",
6613 : 0 : TREE_TYPE (op0));
6614 : :
6615 : 292 : return false;
6616 : : }
6617 : :
6618 : 617572 : nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
6619 : 617572 : nunits_in = TYPE_VECTOR_SUBPARTS (vectype);
6620 : 617572 : if (maybe_ne (nunits_out, nunits_in)
6621 : 617572 : || !tree_nop_conversion_p (TREE_TYPE (vectype_out), TREE_TYPE (vectype)))
6622 : 10688 : return false;
6623 : :
6624 : 606884 : tree vectype2 = NULL_TREE, vectype3 = NULL_TREE;
6625 : 606884 : slp_tree slp_op1 = NULL, slp_op2 = NULL;
6626 : 606884 : if (op_type == binary_op || op_type == ternary_op)
6627 : : {
6628 : 537888 : if (!vect_is_simple_use (vinfo, slp_node,
6629 : : 1, &op1, &slp_op1, &dt[1], &vectype2))
6630 : : {
6631 : 0 : if (dump_enabled_p ())
6632 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6633 : : "use not simple.\n");
6634 : 0 : return false;
6635 : : }
6636 : 537888 : is_invariant &= (dt[1] == vect_external_def
6637 : 537888 : || dt[1] == vect_constant_def);
6638 : 537888 : if (vectype2
6639 : 903433 : && (maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype2))
6640 : 365545 : || !tree_nop_conversion_p (TREE_TYPE (vectype_out),
6641 : 365545 : TREE_TYPE (vectype2))))
6642 : 4 : return false;
6643 : : }
6644 : 606880 : if (op_type == ternary_op)
6645 : : {
6646 : 0 : if (!vect_is_simple_use (vinfo, slp_node,
6647 : : 2, &op2, &slp_op2, &dt[2], &vectype3))
6648 : : {
6649 : 0 : if (dump_enabled_p ())
6650 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6651 : : "use not simple.\n");
6652 : 0 : return false;
6653 : : }
6654 : 0 : is_invariant &= (dt[2] == vect_external_def
6655 : 0 : || dt[2] == vect_constant_def);
6656 : 0 : if (vectype3
6657 : 0 : && (maybe_ne (nunits_out, TYPE_VECTOR_SUBPARTS (vectype3))
6658 : 0 : || !tree_nop_conversion_p (TREE_TYPE (vectype_out),
6659 : 0 : TREE_TYPE (vectype3))))
6660 : 0 : return false;
6661 : : }
6662 : :
6663 : : /* Multiple types in SLP are handled by creating the appropriate number of
6664 : : vectorized stmts for each SLP node. */
6665 : 606880 : auto vec_num = vect_get_num_copies (vinfo, slp_node);
6666 : :
6667 : : /* Reject attempts to combine mask types with nonmask types, e.g. if
6668 : : we have an AND between a (nonmask) boolean loaded from memory and
6669 : : a (mask) boolean result of a comparison.
6670 : :
6671 : : TODO: We could easily fix these cases up using pattern statements. */
6672 : 606880 : if (VECTOR_BOOLEAN_TYPE_P (vectype) != mask_op_p
6673 : 966658 : || (vectype2 && VECTOR_BOOLEAN_TYPE_P (vectype2) != mask_op_p)
6674 : 1213760 : || (vectype3 && VECTOR_BOOLEAN_TYPE_P (vectype3) != mask_op_p))
6675 : : {
6676 : 0 : if (dump_enabled_p ())
6677 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6678 : : "mixed mask and nonmask vector types\n");
6679 : 0 : return false;
6680 : : }
6681 : :
6682 : : /* Supportable by target? */
6683 : :
6684 : 606880 : vec_mode = TYPE_MODE (vectype);
6685 : 606880 : optab = optab_for_tree_code (code, vectype, optab_default);
6686 : 606880 : if (!optab)
6687 : : {
6688 : 57649 : if (dump_enabled_p ())
6689 : 5699 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6690 : : "no optab.\n");
6691 : 57649 : return false;
6692 : : }
6693 : 549231 : target_support_p = can_implement_p (optab, vec_mode);
6694 : :
6695 : 549231 : bool using_emulated_vectors_p = vect_emulated_vector_p (vectype);
6696 : 549231 : if (!target_support_p || using_emulated_vectors_p)
6697 : : {
6698 : 29116 : if (dump_enabled_p ())
6699 : 1088 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6700 : : "op not supported by target.\n");
6701 : : /* When vec_mode is not a vector mode and we verified ops we
6702 : : do not have to lower like AND are natively supported let
6703 : : those through even when the mode isn't word_mode. For
6704 : : ops we have to lower the lowering code assumes we are
6705 : : dealing with word_mode. */
6706 : 58232 : if (!INTEGRAL_TYPE_P (TREE_TYPE (vectype))
6707 : 29022 : || !GET_MODE_SIZE (vec_mode).is_constant ()
6708 : 29022 : || (((code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR)
6709 : 23640 : || !target_support_p)
6710 : 61844 : && maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD))
6711 : : /* Check only during analysis. */
6712 : 39883 : || (cost_vec && !vect_can_vectorize_without_simd_p (code)))
6713 : : {
6714 : 28312 : if (dump_enabled_p ())
6715 : 1088 : dump_printf (MSG_NOTE, "using word mode not possible.\n");
6716 : 28312 : return false;
6717 : : }
6718 : 804 : if (dump_enabled_p ())
6719 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
6720 : : "proceeding using word mode.\n");
6721 : : using_emulated_vectors_p = true;
6722 : : }
6723 : :
6724 : 520919 : int reduc_idx = SLP_TREE_REDUC_IDX (slp_node);
6725 : 520919 : vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL);
6726 : 342137 : vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL);
6727 : 520919 : internal_fn cond_fn = get_conditional_internal_fn (code);
6728 : 520919 : internal_fn cond_len_fn = get_conditional_len_internal_fn (code);
6729 : :
6730 : : /* If operating on inactive elements could generate spurious traps,
6731 : : we need to restrict the operation to active lanes. Note that this
6732 : : specifically doesn't apply to unhoisted invariants, since they
6733 : : operate on the same value for every lane.
6734 : :
6735 : : Similarly, if this operation is part of a reduction, a fully-masked
6736 : : loop should only change the active lanes of the reduction chain,
6737 : : keeping the inactive lanes as-is. */
6738 : 493302 : bool mask_out_inactive = ((!is_invariant && gimple_could_trap_p (stmt))
6739 : 959508 : || reduc_idx >= 0);
6740 : :
6741 : 520919 : if (cost_vec) /* transformation not required. */
6742 : : {
6743 : 406852 : if (loop_vinfo
6744 : 239454 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
6745 : 68451 : && mask_out_inactive)
6746 : : {
6747 : 14998 : if (cond_len_fn != IFN_LAST
6748 : 14998 : && direct_internal_fn_supported_p (cond_len_fn, vectype,
6749 : : OPTIMIZE_FOR_SPEED))
6750 : 0 : vect_record_loop_len (loop_vinfo, lens, vec_num, vectype,
6751 : : 1);
6752 : 14998 : else if (cond_fn != IFN_LAST
6753 : 14998 : && direct_internal_fn_supported_p (cond_fn, vectype,
6754 : : OPTIMIZE_FOR_SPEED))
6755 : 6893 : vect_record_loop_mask (loop_vinfo, masks, vec_num,
6756 : : vectype, NULL);
6757 : : else
6758 : : {
6759 : 8105 : if (dump_enabled_p ())
6760 : 524 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6761 : : "can't use a fully-masked loop because no"
6762 : : " conditional operation is available.\n");
6763 : 8105 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
6764 : : }
6765 : : }
6766 : :
6767 : : /* Put types on constant and invariant SLP children. */
6768 : 406852 : if (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
6769 : 406792 : || !vect_maybe_update_slp_op_vectype (slp_op1, vectype)
6770 : 813541 : || !vect_maybe_update_slp_op_vectype (slp_op2, vectype))
6771 : : {
6772 : 163 : if (dump_enabled_p ())
6773 : 4 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
6774 : : "incompatible vector types for invariants\n");
6775 : 163 : return false;
6776 : : }
6777 : :
6778 : 406689 : SLP_TREE_TYPE (slp_node) = op_vec_info_type;
6779 : 406689 : DUMP_VECT_SCOPE ("vectorizable_operation");
6780 : 406689 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
6781 : 406689 : if (using_emulated_vectors_p)
6782 : : {
6783 : : /* The above vect_model_simple_cost call handles constants
6784 : : in the prologue and (mis-)costs one of the stmts as
6785 : : vector stmt. See below for the actual lowering that will
6786 : : be applied. */
6787 : 802 : unsigned n = vect_get_num_copies (vinfo, slp_node);
6788 : 802 : switch (code)
6789 : : {
6790 : 281 : case PLUS_EXPR:
6791 : 281 : n *= 5;
6792 : 281 : break;
6793 : 494 : case MINUS_EXPR:
6794 : 494 : n *= 6;
6795 : 494 : break;
6796 : 0 : case NEGATE_EXPR:
6797 : 0 : n *= 4;
6798 : 0 : break;
6799 : : default:
6800 : : /* Bit operations do not have extra cost and are accounted
6801 : : as vector stmt by vect_model_simple_cost. */
6802 : : n = 0;
6803 : : break;
6804 : : }
6805 : 775 : if (n != 0)
6806 : : {
6807 : : /* We also need to materialize two large constants. */
6808 : 775 : record_stmt_cost (cost_vec, 2, scalar_stmt, stmt_info,
6809 : : 0, vect_prologue);
6810 : 775 : record_stmt_cost (cost_vec, n, scalar_stmt, stmt_info,
6811 : : 0, vect_body);
6812 : : }
6813 : : }
6814 : 406689 : return true;
6815 : : }
6816 : :
6817 : : /* Transform. */
6818 : :
6819 : 114067 : if (dump_enabled_p ())
6820 : 16151 : dump_printf_loc (MSG_NOTE, vect_location,
6821 : : "transform binary/unary operation.\n");
6822 : :
6823 : 114067 : bool masked_loop_p = loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
6824 : 102683 : bool len_loop_p = loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
6825 : :
6826 : : /* POINTER_DIFF_EXPR has pointer arguments which are vectorized as
6827 : : vectors with unsigned elements, but the result is signed. So, we
6828 : : need to compute the MINUS_EXPR into vectype temporary and
6829 : : VIEW_CONVERT_EXPR it into the final vectype_out result. */
6830 : 114067 : tree vec_cvt_dest = NULL_TREE;
6831 : 114067 : if (orig_code == POINTER_DIFF_EXPR)
6832 : : {
6833 : 131 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6834 : 131 : vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out);
6835 : : }
6836 : : /* For reduction operations with undefined overflow behavior make sure to
6837 : : pun them to unsigned since we change the order of evaluation.
6838 : : ??? Avoid for in-order reductions? */
6839 : 113936 : else if (arith_code_with_undefined_signed_overflow (orig_code)
6840 : 97608 : && ANY_INTEGRAL_TYPE_P (vectype)
6841 : 47886 : && TYPE_OVERFLOW_UNDEFINED (vectype)
6842 : 139821 : && SLP_TREE_REDUC_IDX (slp_node) != -1)
6843 : : {
6844 : 2393 : gcc_assert (orig_code == PLUS_EXPR || orig_code == MINUS_EXPR
6845 : : || orig_code == MULT_EXPR || orig_code == POINTER_PLUS_EXPR);
6846 : 2393 : vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out);
6847 : 2393 : vectype = unsigned_type_for (vectype);
6848 : 2393 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
6849 : : }
6850 : : /* Handle def. */
6851 : : else
6852 : 111543 : vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
6853 : :
6854 : 114067 : vect_get_vec_defs (vinfo, slp_node,
6855 : : op0, &vec_oprnds0, op1, &vec_oprnds1, op2, &vec_oprnds2);
6856 : : /* Arguments are ready. Create the new vector stmt. */
6857 : 251667 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
6858 : : {
6859 : 137600 : gimple *new_stmt = NULL;
6860 : 275200 : vop1 = ((op_type == binary_op || op_type == ternary_op)
6861 : 137600 : ? vec_oprnds1[i] : NULL_TREE);
6862 : 137600 : vop2 = ((op_type == ternary_op) ? vec_oprnds2[i] : NULL_TREE);
6863 : :
6864 : 137600 : if (vec_cvt_dest
6865 : 137600 : && !useless_type_conversion_p (vectype, TREE_TYPE (vop0)))
6866 : : {
6867 : 2816 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype, vop0);
6868 : 2816 : new_stmt = gimple_build_assign (vec_dest, VIEW_CONVERT_EXPR,
6869 : : new_temp);
6870 : 2816 : new_temp = make_ssa_name (vec_dest, new_stmt);
6871 : 2816 : gimple_assign_set_lhs (new_stmt, new_temp);
6872 : 2816 : vect_finish_stmt_generation (vinfo, stmt_info,
6873 : : new_stmt, gsi);
6874 : 2816 : vop0 = new_temp;
6875 : : }
6876 : 137600 : if (vop1
6877 : 135107 : && vec_cvt_dest
6878 : 140562 : && !useless_type_conversion_p (vectype, TREE_TYPE (vop1)))
6879 : : {
6880 : 2816 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype, vop1);
6881 : 2816 : new_stmt = gimple_build_assign (vec_dest, VIEW_CONVERT_EXPR,
6882 : : new_temp);
6883 : 2816 : new_temp = make_ssa_name (vec_dest, new_stmt);
6884 : 2816 : gimple_assign_set_lhs (new_stmt, new_temp);
6885 : 2816 : vect_finish_stmt_generation (vinfo, stmt_info,
6886 : : new_stmt, gsi);
6887 : 2816 : vop1 = new_temp;
6888 : : }
6889 : 137600 : if (vop2
6890 : 0 : && vec_cvt_dest
6891 : 137600 : && !useless_type_conversion_p (vectype, TREE_TYPE (vop2)))
6892 : : {
6893 : 0 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype, vop2);
6894 : 0 : new_stmt = gimple_build_assign (vec_dest, VIEW_CONVERT_EXPR,
6895 : : new_temp);
6896 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
6897 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
6898 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
6899 : : new_stmt, gsi);
6900 : 0 : vop2 = new_temp;
6901 : : }
6902 : :
6903 : 137600 : if (using_emulated_vectors_p)
6904 : : {
6905 : : /* Lower the operation. This follows vector lowering. */
6906 : 2 : tree word_type = build_nonstandard_integer_type
6907 : 2 : (GET_MODE_BITSIZE (vec_mode).to_constant (), 1);
6908 : 2 : tree wvop0 = make_ssa_name (word_type);
6909 : 2 : new_stmt = gimple_build_assign (wvop0, VIEW_CONVERT_EXPR,
6910 : : build1 (VIEW_CONVERT_EXPR,
6911 : : word_type, vop0));
6912 : 2 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6913 : 2 : tree wvop1 = NULL_TREE;
6914 : 2 : if (vop1)
6915 : : {
6916 : 2 : wvop1 = make_ssa_name (word_type);
6917 : 2 : new_stmt = gimple_build_assign (wvop1, VIEW_CONVERT_EXPR,
6918 : : build1 (VIEW_CONVERT_EXPR,
6919 : : word_type, vop1));
6920 : 2 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6921 : : }
6922 : :
6923 : 2 : tree result_low;
6924 : 2 : if (code == PLUS_EXPR || code == MINUS_EXPR || code == NEGATE_EXPR)
6925 : : {
6926 : 1 : unsigned int width = vector_element_bits (vectype);
6927 : 1 : tree inner_type = TREE_TYPE (vectype);
6928 : 1 : HOST_WIDE_INT max = GET_MODE_MASK (TYPE_MODE (inner_type));
6929 : 1 : tree low_bits
6930 : 1 : = build_replicated_int_cst (word_type, width, max >> 1);
6931 : 1 : tree high_bits
6932 : 2 : = build_replicated_int_cst (word_type,
6933 : 1 : width, max & ~(max >> 1));
6934 : 1 : tree signs;
6935 : 1 : if (code == PLUS_EXPR || code == MINUS_EXPR)
6936 : : {
6937 : 1 : signs = make_ssa_name (word_type);
6938 : 1 : new_stmt = gimple_build_assign (signs,
6939 : : BIT_XOR_EXPR, wvop0, wvop1);
6940 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6941 : 1 : tree b_low = make_ssa_name (word_type);
6942 : 1 : new_stmt = gimple_build_assign (b_low, BIT_AND_EXPR,
6943 : : wvop1, low_bits);
6944 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6945 : 1 : tree a_low = make_ssa_name (word_type);
6946 : 1 : if (code == PLUS_EXPR)
6947 : 1 : new_stmt = gimple_build_assign (a_low, BIT_AND_EXPR,
6948 : : wvop0, low_bits);
6949 : : else
6950 : 0 : new_stmt = gimple_build_assign (a_low, BIT_IOR_EXPR,
6951 : : wvop0, high_bits);
6952 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6953 : 1 : if (code == MINUS_EXPR)
6954 : : {
6955 : 0 : new_stmt = gimple_build_assign (NULL_TREE,
6956 : : BIT_NOT_EXPR, signs);
6957 : 0 : signs = make_ssa_name (word_type);
6958 : 0 : gimple_assign_set_lhs (new_stmt, signs);
6959 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
6960 : : new_stmt, gsi);
6961 : : }
6962 : 1 : new_stmt = gimple_build_assign (NULL_TREE, BIT_AND_EXPR,
6963 : : signs, high_bits);
6964 : 1 : signs = make_ssa_name (word_type);
6965 : 1 : gimple_assign_set_lhs (new_stmt, signs);
6966 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6967 : 1 : result_low = make_ssa_name (word_type);
6968 : 1 : new_stmt = gimple_build_assign (result_low, code,
6969 : : a_low, b_low);
6970 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6971 : : }
6972 : : else /* if (code == NEGATE_EXPR) */
6973 : : {
6974 : 0 : tree a_low = make_ssa_name (word_type);
6975 : 0 : new_stmt = gimple_build_assign (a_low, BIT_AND_EXPR,
6976 : : wvop0, low_bits);
6977 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6978 : 0 : signs = make_ssa_name (word_type);
6979 : 0 : new_stmt = gimple_build_assign (signs, BIT_NOT_EXPR, wvop0);
6980 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6981 : 0 : new_stmt = gimple_build_assign (NULL_TREE, BIT_AND_EXPR,
6982 : : signs, high_bits);
6983 : 0 : signs = make_ssa_name (word_type);
6984 : 0 : gimple_assign_set_lhs (new_stmt, signs);
6985 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6986 : 0 : result_low = make_ssa_name (word_type);
6987 : 0 : new_stmt = gimple_build_assign (result_low,
6988 : : MINUS_EXPR, high_bits, a_low);
6989 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6990 : : }
6991 : 1 : new_stmt = gimple_build_assign (NULL_TREE, BIT_XOR_EXPR,
6992 : : result_low, signs);
6993 : 1 : result_low = make_ssa_name (word_type);
6994 : 1 : gimple_assign_set_lhs (new_stmt, result_low);
6995 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
6996 : : }
6997 : : else
6998 : : {
6999 : 1 : new_stmt = gimple_build_assign (NULL_TREE, code, wvop0, wvop1);
7000 : 1 : result_low = make_ssa_name (word_type);
7001 : 1 : gimple_assign_set_lhs (new_stmt, result_low);
7002 : 1 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7003 : :
7004 : : }
7005 : 2 : new_stmt = gimple_build_assign (NULL_TREE, VIEW_CONVERT_EXPR,
7006 : : build1 (VIEW_CONVERT_EXPR,
7007 : : vectype, result_low));
7008 : 2 : new_temp = make_ssa_name (vectype);
7009 : 2 : gimple_assign_set_lhs (new_stmt, new_temp);
7010 : 2 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7011 : : }
7012 : 137598 : else if ((masked_loop_p || len_loop_p) && mask_out_inactive)
7013 : : {
7014 : 16 : tree mask;
7015 : 16 : if (masked_loop_p)
7016 : 16 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
7017 : : vec_num, vectype, i);
7018 : : else
7019 : : /* Dummy mask. */
7020 : 0 : mask = build_minus_one_cst (truth_type_for (vectype));
7021 : 16 : auto_vec<tree> vops (6);
7022 : 16 : vops.quick_push (mask);
7023 : 16 : vops.quick_push (vop0);
7024 : 16 : if (vop1)
7025 : 16 : vops.quick_push (vop1);
7026 : 16 : if (vop2)
7027 : 0 : vops.quick_push (vop2);
7028 : 16 : if (reduc_idx >= 0)
7029 : : {
7030 : : /* Perform the operation on active elements only and take
7031 : : inactive elements from the reduction chain input. */
7032 : 8 : gcc_assert (!vop2);
7033 : 8 : vops.quick_push (reduc_idx == 1 ? vop1 : vop0);
7034 : : }
7035 : : else
7036 : : {
7037 : 8 : auto else_value = targetm.preferred_else_value
7038 : 8 : (cond_fn, vectype, vops.length () - 1, &vops[1]);
7039 : 8 : vops.quick_push (else_value);
7040 : : }
7041 : 16 : if (len_loop_p)
7042 : : {
7043 : 0 : tree len = vect_get_loop_len (loop_vinfo, gsi, lens,
7044 : 0 : vec_num, vectype, i, 1);
7045 : 0 : signed char biasval
7046 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
7047 : 0 : tree bias = build_int_cst (intQI_type_node, biasval);
7048 : 0 : vops.quick_push (len);
7049 : 0 : vops.quick_push (bias);
7050 : : }
7051 : 16 : gcall *call
7052 : 16 : = gimple_build_call_internal_vec (masked_loop_p ? cond_fn
7053 : : : cond_len_fn,
7054 : : vops);
7055 : 16 : new_temp = make_ssa_name (vec_dest, call);
7056 : 16 : gimple_call_set_lhs (call, new_temp);
7057 : 16 : gimple_call_set_nothrow (call, true);
7058 : 16 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
7059 : 16 : new_stmt = call;
7060 : 16 : }
7061 : : else
7062 : : {
7063 : 137582 : tree mask = NULL_TREE;
7064 : : /* When combining two masks check if either of them is elsewhere
7065 : : combined with a loop mask, if that's the case we can mark that the
7066 : : new combined mask doesn't need to be combined with a loop mask. */
7067 : 137582 : if (masked_loop_p
7068 : 137582 : && code == BIT_AND_EXPR
7069 : 137582 : && VECTOR_BOOLEAN_TYPE_P (vectype))
7070 : : {
7071 : 8 : if (loop_vinfo->scalar_cond_masked_set.contains ({ op0, vec_num }))
7072 : : {
7073 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
7074 : : vec_num, vectype, i);
7075 : :
7076 : 0 : vop0 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
7077 : : vop0, gsi);
7078 : : }
7079 : :
7080 : 8 : if (loop_vinfo->scalar_cond_masked_set.contains ({ op1, vec_num }))
7081 : : {
7082 : 0 : mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
7083 : : vec_num, vectype, i);
7084 : :
7085 : 0 : vop1 = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
7086 : : vop1, gsi);
7087 : : }
7088 : : }
7089 : :
7090 : 137582 : new_stmt = gimple_build_assign (vec_dest, code, vop0, vop1, vop2);
7091 : 137582 : new_temp = make_ssa_name (vec_dest, new_stmt);
7092 : 137582 : gimple_assign_set_lhs (new_stmt, new_temp);
7093 : 137582 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
7094 : 137582 : if (using_emulated_vectors_p)
7095 : : suppress_warning (new_stmt, OPT_Wvector_operation_performance);
7096 : :
7097 : : /* Enter the combined value into the vector cond hash so we don't
7098 : : AND it with a loop mask again. */
7099 : 137582 : if (mask)
7100 : 0 : loop_vinfo->vec_cond_masked_set.add ({ new_temp, mask });
7101 : : }
7102 : :
7103 : 137600 : if (vec_cvt_dest)
7104 : : {
7105 : 2962 : new_temp = build1 (VIEW_CONVERT_EXPR, vectype_out, new_temp);
7106 : 2962 : new_stmt = gimple_build_assign (vec_cvt_dest, VIEW_CONVERT_EXPR,
7107 : : new_temp);
7108 : 2962 : new_temp = make_ssa_name (vec_cvt_dest, new_stmt);
7109 : 2962 : gimple_assign_set_lhs (new_stmt, new_temp);
7110 : 2962 : vect_finish_stmt_generation (vinfo, stmt_info,
7111 : : new_stmt, gsi);
7112 : : }
7113 : :
7114 : 137600 : slp_node->push_vec_def (new_stmt);
7115 : : }
7116 : :
7117 : 114067 : vec_oprnds0.release ();
7118 : 114067 : vec_oprnds1.release ();
7119 : 114067 : vec_oprnds2.release ();
7120 : :
7121 : 114067 : return true;
7122 : : }
7123 : :
7124 : : /* A helper function to ensure data reference DR_INFO's base alignment. */
7125 : :
7126 : : static void
7127 : 1859161 : ensure_base_align (dr_vec_info *dr_info)
7128 : : {
7129 : : /* Alignment is only analyzed for the first element of a DR group,
7130 : : use that to look at base alignment we need to enforce. */
7131 : 1859161 : if (STMT_VINFO_GROUPED_ACCESS (dr_info->stmt))
7132 : 1418828 : dr_info = STMT_VINFO_DR_INFO (DR_GROUP_FIRST_ELEMENT (dr_info->stmt));
7133 : :
7134 : 1859161 : gcc_assert (dr_info->misalignment != DR_MISALIGNMENT_UNINITIALIZED);
7135 : :
7136 : 1859161 : if (dr_info->base_misaligned)
7137 : : {
7138 : 170160 : tree base_decl = dr_info->base_decl;
7139 : :
7140 : : // We should only be able to increase the alignment of a base object if
7141 : : // we know what its new alignment should be at compile time.
7142 : 170160 : unsigned HOST_WIDE_INT align_base_to =
7143 : 170160 : DR_TARGET_ALIGNMENT (dr_info).to_constant () * BITS_PER_UNIT;
7144 : :
7145 : 170160 : if (decl_in_symtab_p (base_decl))
7146 : 4596 : symtab_node::get (base_decl)->increase_alignment (align_base_to);
7147 : 165564 : else if (DECL_ALIGN (base_decl) < align_base_to)
7148 : : {
7149 : 132484 : SET_DECL_ALIGN (base_decl, align_base_to);
7150 : 132484 : DECL_USER_ALIGN (base_decl) = 1;
7151 : : }
7152 : 170160 : dr_info->base_misaligned = false;
7153 : : }
7154 : 1859161 : }
7155 : :
7156 : :
7157 : : /* Function get_group_alias_ptr_type.
7158 : :
7159 : : Return the alias type for the group starting at FIRST_STMT_INFO. */
7160 : :
7161 : : static tree
7162 : 1589224 : get_group_alias_ptr_type (stmt_vec_info first_stmt_info)
7163 : : {
7164 : 1589224 : struct data_reference *first_dr, *next_dr;
7165 : :
7166 : 1589224 : first_dr = STMT_VINFO_DATA_REF (first_stmt_info);
7167 : 1589224 : stmt_vec_info next_stmt_info = DR_GROUP_NEXT_ELEMENT (first_stmt_info);
7168 : 3842593 : while (next_stmt_info)
7169 : : {
7170 : 2394267 : next_dr = STMT_VINFO_DATA_REF (next_stmt_info);
7171 : 4788534 : if (get_alias_set (DR_REF (first_dr))
7172 : 2394267 : != get_alias_set (DR_REF (next_dr)))
7173 : : {
7174 : 140898 : if (dump_enabled_p ())
7175 : 27 : dump_printf_loc (MSG_NOTE, vect_location,
7176 : : "conflicting alias set types.\n");
7177 : 140898 : return ptr_type_node;
7178 : : }
7179 : 2253369 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
7180 : : }
7181 : 1448326 : return reference_alias_ptr_type (DR_REF (first_dr));
7182 : : }
7183 : :
7184 : :
7185 : : /* Function scan_operand_equal_p.
7186 : :
7187 : : Helper function for check_scan_store. Compare two references
7188 : : with .GOMP_SIMD_LANE bases. */
7189 : :
7190 : : static bool
7191 : 1284 : scan_operand_equal_p (tree ref1, tree ref2)
7192 : : {
7193 : 1284 : tree ref[2] = { ref1, ref2 };
7194 : 1284 : poly_int64 bitsize[2], bitpos[2];
7195 : : tree offset[2], base[2];
7196 : 3852 : for (int i = 0; i < 2; ++i)
7197 : : {
7198 : 2568 : machine_mode mode;
7199 : 2568 : int unsignedp, reversep, volatilep = 0;
7200 : 2568 : base[i] = get_inner_reference (ref[i], &bitsize[i], &bitpos[i],
7201 : : &offset[i], &mode, &unsignedp,
7202 : : &reversep, &volatilep);
7203 : 2568 : if (reversep || volatilep || maybe_ne (bitpos[i], 0))
7204 : 0 : return false;
7205 : 2568 : if (TREE_CODE (base[i]) == MEM_REF
7206 : 42 : && offset[i] == NULL_TREE
7207 : 2610 : && TREE_CODE (TREE_OPERAND (base[i], 0)) == SSA_NAME)
7208 : : {
7209 : 42 : gimple *def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (base[i], 0));
7210 : 42 : if (is_gimple_assign (def_stmt)
7211 : 42 : && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR
7212 : 42 : && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == ADDR_EXPR
7213 : 84 : && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME)
7214 : : {
7215 : 42 : if (maybe_ne (mem_ref_offset (base[i]), 0))
7216 : : return false;
7217 : 42 : base[i] = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0);
7218 : 42 : offset[i] = gimple_assign_rhs2 (def_stmt);
7219 : : }
7220 : : }
7221 : : }
7222 : :
7223 : 1284 : if (!operand_equal_p (base[0], base[1], 0))
7224 : : return false;
7225 : 934 : if (maybe_ne (bitsize[0], bitsize[1]))
7226 : : return false;
7227 : 934 : if (offset[0] != offset[1])
7228 : : {
7229 : 916 : if (!offset[0] || !offset[1])
7230 : : return false;
7231 : 916 : if (!operand_equal_p (offset[0], offset[1], 0))
7232 : : {
7233 : : tree step[2];
7234 : 0 : for (int i = 0; i < 2; ++i)
7235 : : {
7236 : 0 : step[i] = integer_one_node;
7237 : 0 : if (TREE_CODE (offset[i]) == SSA_NAME)
7238 : : {
7239 : 0 : gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]);
7240 : 0 : if (is_gimple_assign (def_stmt)
7241 : 0 : && gimple_assign_rhs_code (def_stmt) == MULT_EXPR
7242 : 0 : && (TREE_CODE (gimple_assign_rhs2 (def_stmt))
7243 : : == INTEGER_CST))
7244 : : {
7245 : 0 : step[i] = gimple_assign_rhs2 (def_stmt);
7246 : 0 : offset[i] = gimple_assign_rhs1 (def_stmt);
7247 : : }
7248 : : }
7249 : 0 : else if (TREE_CODE (offset[i]) == MULT_EXPR)
7250 : : {
7251 : 0 : step[i] = TREE_OPERAND (offset[i], 1);
7252 : 0 : offset[i] = TREE_OPERAND (offset[i], 0);
7253 : : }
7254 : 0 : tree rhs1 = NULL_TREE;
7255 : 0 : if (TREE_CODE (offset[i]) == SSA_NAME)
7256 : : {
7257 : 0 : gimple *def_stmt = SSA_NAME_DEF_STMT (offset[i]);
7258 : 0 : if (gimple_assign_cast_p (def_stmt))
7259 : 0 : rhs1 = gimple_assign_rhs1 (def_stmt);
7260 : : }
7261 : 0 : else if (CONVERT_EXPR_P (offset[i]))
7262 : 0 : rhs1 = TREE_OPERAND (offset[i], 0);
7263 : 0 : if (rhs1
7264 : 0 : && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
7265 : 0 : && INTEGRAL_TYPE_P (TREE_TYPE (offset[i]))
7266 : 0 : && (TYPE_PRECISION (TREE_TYPE (offset[i]))
7267 : 0 : >= TYPE_PRECISION (TREE_TYPE (rhs1))))
7268 : 0 : offset[i] = rhs1;
7269 : : }
7270 : 0 : if (!operand_equal_p (offset[0], offset[1], 0)
7271 : 0 : || !operand_equal_p (step[0], step[1], 0))
7272 : 0 : return false;
7273 : : }
7274 : : }
7275 : : return true;
7276 : : }
7277 : :
7278 : :
7279 : : enum scan_store_kind {
7280 : : /* Normal permutation. */
7281 : : scan_store_kind_perm,
7282 : :
7283 : : /* Whole vector left shift permutation with zero init. */
7284 : : scan_store_kind_lshift_zero,
7285 : :
7286 : : /* Whole vector left shift permutation and VEC_COND_EXPR. */
7287 : : scan_store_kind_lshift_cond
7288 : : };
7289 : :
7290 : : /* Function check_scan_store.
7291 : :
7292 : : Verify if we can perform the needed permutations or whole vector shifts.
7293 : : Return -1 on failure, otherwise exact log2 of vectype's nunits.
7294 : : USE_WHOLE_VECTOR is a vector of enum scan_store_kind which operation
7295 : : to do at each step. */
7296 : :
7297 : : static int
7298 : 1024 : scan_store_can_perm_p (tree vectype, tree init,
7299 : : vec<enum scan_store_kind> *use_whole_vector = NULL)
7300 : : {
7301 : 1024 : enum machine_mode vec_mode = TYPE_MODE (vectype);
7302 : 1024 : unsigned HOST_WIDE_INT nunits;
7303 : 1024 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits))
7304 : : return -1;
7305 : 1024 : int units_log2 = exact_log2 (nunits);
7306 : 1024 : if (units_log2 <= 0)
7307 : : return -1;
7308 : :
7309 : : int i;
7310 : : enum scan_store_kind whole_vector_shift_kind = scan_store_kind_perm;
7311 : 4784 : for (i = 0; i <= units_log2; ++i)
7312 : : {
7313 : 3760 : unsigned HOST_WIDE_INT j, k;
7314 : 3760 : enum scan_store_kind kind = scan_store_kind_perm;
7315 : 3760 : vec_perm_builder sel (nunits, nunits, 1);
7316 : 3760 : sel.quick_grow (nunits);
7317 : 3760 : if (i == units_log2)
7318 : : {
7319 : 9728 : for (j = 0; j < nunits; ++j)
7320 : 8704 : sel[j] = nunits - 1;
7321 : : }
7322 : : else
7323 : : {
7324 : 10416 : for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j)
7325 : 7680 : sel[j] = j;
7326 : 26416 : for (k = 0; j < nunits; ++j, ++k)
7327 : 23680 : sel[j] = nunits + k;
7328 : : }
7329 : 6496 : vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits);
7330 : 3760 : if (!can_vec_perm_const_p (vec_mode, vec_mode, indices))
7331 : : {
7332 : 0 : if (i == units_log2)
7333 : : return -1;
7334 : :
7335 : 0 : if (whole_vector_shift_kind == scan_store_kind_perm)
7336 : : {
7337 : 0 : if (!can_implement_p (vec_shl_optab, vec_mode))
7338 : : return -1;
7339 : 0 : whole_vector_shift_kind = scan_store_kind_lshift_zero;
7340 : : /* Whole vector shifts shift in zeros, so if init is all zero
7341 : : constant, there is no need to do anything further. */
7342 : 0 : if ((TREE_CODE (init) != INTEGER_CST
7343 : 0 : && TREE_CODE (init) != REAL_CST)
7344 : 0 : || !initializer_zerop (init))
7345 : : {
7346 : 0 : tree masktype = truth_type_for (vectype);
7347 : 0 : if (!expand_vec_cond_expr_p (vectype, masktype))
7348 : : return -1;
7349 : : whole_vector_shift_kind = scan_store_kind_lshift_cond;
7350 : : }
7351 : : }
7352 : 0 : kind = whole_vector_shift_kind;
7353 : : }
7354 : 3760 : if (use_whole_vector)
7355 : : {
7356 : 1880 : if (kind != scan_store_kind_perm && use_whole_vector->is_empty ())
7357 : 0 : use_whole_vector->safe_grow_cleared (i, true);
7358 : 5640 : if (kind != scan_store_kind_perm || !use_whole_vector->is_empty ())
7359 : 0 : use_whole_vector->safe_push (kind);
7360 : : }
7361 : 3760 : }
7362 : :
7363 : : return units_log2;
7364 : : }
7365 : :
7366 : :
7367 : : /* Function check_scan_store.
7368 : :
7369 : : Check magic stores for #pragma omp scan {in,ex}clusive reductions. */
7370 : :
7371 : : static bool
7372 : 1076 : check_scan_store (vec_info *vinfo, stmt_vec_info stmt_info, tree vectype,
7373 : : enum vect_def_type rhs_dt, slp_tree slp_node,
7374 : : slp_tree mask_node,
7375 : : vect_memory_access_type memory_access_type)
7376 : : {
7377 : 1076 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
7378 : 1076 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
7379 : 1076 : tree ref_type;
7380 : :
7381 : 1076 : gcc_assert (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1);
7382 : 1076 : if (SLP_TREE_LANES (slp_node) > 1
7383 : 1076 : || mask_node
7384 : 1076 : || memory_access_type != VMAT_CONTIGUOUS
7385 : 1076 : || TREE_CODE (DR_BASE_ADDRESS (dr_info->dr)) != ADDR_EXPR
7386 : 1076 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0))
7387 : 1076 : || loop_vinfo == NULL
7388 : 1076 : || LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
7389 : 1076 : || LOOP_VINFO_EPILOGUE_P (loop_vinfo)
7390 : 1076 : || STMT_VINFO_GROUPED_ACCESS (stmt_info)
7391 : 1076 : || !integer_zerop (get_dr_vinfo_offset (vinfo, dr_info))
7392 : 1076 : || !integer_zerop (DR_INIT (dr_info->dr))
7393 : 1076 : || !(ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr)))
7394 : 2152 : || !alias_sets_conflict_p (get_alias_set (vectype),
7395 : 1076 : get_alias_set (TREE_TYPE (ref_type))))
7396 : : {
7397 : 0 : if (dump_enabled_p ())
7398 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7399 : : "unsupported OpenMP scan store.\n");
7400 : 0 : return false;
7401 : : }
7402 : :
7403 : : /* We need to pattern match code built by OpenMP lowering and simplified
7404 : : by following optimizations into something we can handle.
7405 : : #pragma omp simd reduction(inscan,+:r)
7406 : : for (...)
7407 : : {
7408 : : r += something ();
7409 : : #pragma omp scan inclusive (r)
7410 : : use (r);
7411 : : }
7412 : : shall have body with:
7413 : : // Initialization for input phase, store the reduction initializer:
7414 : : _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0);
7415 : : _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1);
7416 : : D.2042[_21] = 0;
7417 : : // Actual input phase:
7418 : : ...
7419 : : r.0_5 = D.2042[_20];
7420 : : _6 = _4 + r.0_5;
7421 : : D.2042[_20] = _6;
7422 : : // Initialization for scan phase:
7423 : : _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 2);
7424 : : _26 = D.2043[_25];
7425 : : _27 = D.2042[_25];
7426 : : _28 = _26 + _27;
7427 : : D.2043[_25] = _28;
7428 : : D.2042[_25] = _28;
7429 : : // Actual scan phase:
7430 : : ...
7431 : : r.1_8 = D.2042[_20];
7432 : : ...
7433 : : The "omp simd array" variable D.2042 holds the privatized copy used
7434 : : inside of the loop and D.2043 is another one that holds copies of
7435 : : the current original list item. The separate GOMP_SIMD_LANE ifn
7436 : : kinds are there in order to allow optimizing the initializer store
7437 : : and combiner sequence, e.g. if it is originally some C++ish user
7438 : : defined reduction, but allow the vectorizer to pattern recognize it
7439 : : and turn into the appropriate vectorized scan.
7440 : :
7441 : : For exclusive scan, this is slightly different:
7442 : : #pragma omp simd reduction(inscan,+:r)
7443 : : for (...)
7444 : : {
7445 : : use (r);
7446 : : #pragma omp scan exclusive (r)
7447 : : r += something ();
7448 : : }
7449 : : shall have body with:
7450 : : // Initialization for input phase, store the reduction initializer:
7451 : : _20 = .GOMP_SIMD_LANE (simduid.3_14(D), 0);
7452 : : _21 = .GOMP_SIMD_LANE (simduid.3_14(D), 1);
7453 : : D.2042[_21] = 0;
7454 : : // Actual input phase:
7455 : : ...
7456 : : r.0_5 = D.2042[_20];
7457 : : _6 = _4 + r.0_5;
7458 : : D.2042[_20] = _6;
7459 : : // Initialization for scan phase:
7460 : : _25 = .GOMP_SIMD_LANE (simduid.3_14(D), 3);
7461 : : _26 = D.2043[_25];
7462 : : D.2044[_25] = _26;
7463 : : _27 = D.2042[_25];
7464 : : _28 = _26 + _27;
7465 : : D.2043[_25] = _28;
7466 : : // Actual scan phase:
7467 : : ...
7468 : : r.1_8 = D.2044[_20];
7469 : : ... */
7470 : :
7471 : 1076 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 2)
7472 : : {
7473 : : /* Match the D.2042[_21] = 0; store above. Just require that
7474 : : it is a constant or external definition store. */
7475 : 564 : if (rhs_dt != vect_constant_def && rhs_dt != vect_external_def)
7476 : : {
7477 : 0 : fail_init:
7478 : 0 : if (dump_enabled_p ())
7479 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7480 : : "unsupported OpenMP scan initializer store.\n");
7481 : 0 : return false;
7482 : : }
7483 : :
7484 : 564 : if (! loop_vinfo->scan_map)
7485 : 322 : loop_vinfo->scan_map = new hash_map<tree, tree>;
7486 : 564 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7487 : 564 : tree &cached = loop_vinfo->scan_map->get_or_insert (var);
7488 : 564 : if (cached)
7489 : 0 : goto fail_init;
7490 : 564 : cached = gimple_assign_rhs1 (STMT_VINFO_STMT (stmt_info));
7491 : :
7492 : : /* These stores can be vectorized normally. */
7493 : 564 : return true;
7494 : : }
7495 : :
7496 : 512 : if (rhs_dt != vect_internal_def)
7497 : : {
7498 : 0 : fail:
7499 : 0 : if (dump_enabled_p ())
7500 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
7501 : : "unsupported OpenMP scan combiner pattern.\n");
7502 : 0 : return false;
7503 : : }
7504 : :
7505 : 512 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
7506 : 512 : tree rhs = gimple_assign_rhs1 (stmt);
7507 : 512 : if (TREE_CODE (rhs) != SSA_NAME)
7508 : 0 : goto fail;
7509 : :
7510 : 512 : gimple *other_store_stmt = NULL;
7511 : 512 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7512 : 512 : bool inscan_var_store
7513 : 512 : = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL;
7514 : :
7515 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7516 : : {
7517 : 252 : if (!inscan_var_store)
7518 : : {
7519 : 126 : use_operand_p use_p;
7520 : 126 : imm_use_iterator iter;
7521 : 378 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7522 : : {
7523 : 252 : gimple *use_stmt = USE_STMT (use_p);
7524 : 252 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7525 : 126 : continue;
7526 : 126 : if (gimple_bb (use_stmt) != gimple_bb (stmt)
7527 : 126 : || !is_gimple_assign (use_stmt)
7528 : 126 : || gimple_assign_rhs_class (use_stmt) != GIMPLE_BINARY_RHS
7529 : 126 : || other_store_stmt
7530 : 252 : || TREE_CODE (gimple_assign_lhs (use_stmt)) != SSA_NAME)
7531 : 0 : goto fail;
7532 : 126 : other_store_stmt = use_stmt;
7533 : 0 : }
7534 : 126 : if (other_store_stmt == NULL)
7535 : 0 : goto fail;
7536 : 126 : rhs = gimple_assign_lhs (other_store_stmt);
7537 : 126 : if (!single_imm_use (rhs, &use_p, &other_store_stmt))
7538 : 0 : goto fail;
7539 : : }
7540 : : }
7541 : 260 : else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3)
7542 : : {
7543 : 260 : use_operand_p use_p;
7544 : 260 : imm_use_iterator iter;
7545 : 1040 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7546 : : {
7547 : 520 : gimple *use_stmt = USE_STMT (use_p);
7548 : 520 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7549 : 260 : continue;
7550 : 260 : if (other_store_stmt)
7551 : 0 : goto fail;
7552 : 260 : other_store_stmt = use_stmt;
7553 : 260 : }
7554 : : }
7555 : : else
7556 : 0 : goto fail;
7557 : :
7558 : 512 : gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
7559 : 512 : if (gimple_bb (def_stmt) != gimple_bb (stmt)
7560 : 512 : || !is_gimple_assign (def_stmt)
7561 : 1024 : || gimple_assign_rhs_class (def_stmt) != GIMPLE_BINARY_RHS)
7562 : 0 : goto fail;
7563 : :
7564 : 512 : enum tree_code code = gimple_assign_rhs_code (def_stmt);
7565 : : /* For pointer addition, we should use the normal plus for the vector
7566 : : operation. */
7567 : 512 : switch (code)
7568 : : {
7569 : 0 : case POINTER_PLUS_EXPR:
7570 : 0 : code = PLUS_EXPR;
7571 : 0 : break;
7572 : 0 : case MULT_HIGHPART_EXPR:
7573 : 0 : goto fail;
7574 : : default:
7575 : : break;
7576 : : }
7577 : 512 : if (TREE_CODE_LENGTH (code) != binary_op || !commutative_tree_code (code))
7578 : 0 : goto fail;
7579 : :
7580 : 512 : tree rhs1 = gimple_assign_rhs1 (def_stmt);
7581 : 512 : tree rhs2 = gimple_assign_rhs2 (def_stmt);
7582 : 512 : if (TREE_CODE (rhs1) != SSA_NAME || TREE_CODE (rhs2) != SSA_NAME)
7583 : 0 : goto fail;
7584 : :
7585 : 512 : gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1);
7586 : 512 : gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2);
7587 : 512 : if (gimple_bb (load1_stmt) != gimple_bb (stmt)
7588 : 512 : || !gimple_assign_load_p (load1_stmt)
7589 : 512 : || gimple_bb (load2_stmt) != gimple_bb (stmt)
7590 : 1024 : || !gimple_assign_load_p (load2_stmt))
7591 : 0 : goto fail;
7592 : :
7593 : 512 : stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt);
7594 : 512 : stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt);
7595 : 512 : if (load1_stmt_info == NULL
7596 : 512 : || load2_stmt_info == NULL
7597 : 512 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (load1_stmt_info)
7598 : 512 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info))
7599 : 512 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (load2_stmt_info)
7600 : 512 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)))
7601 : 0 : goto fail;
7602 : :
7603 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && inscan_var_store)
7604 : : {
7605 : 126 : dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info);
7606 : 126 : if (TREE_CODE (DR_BASE_ADDRESS (load1_dr_info->dr)) != ADDR_EXPR
7607 : 126 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0)))
7608 : 0 : goto fail;
7609 : 126 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0);
7610 : 126 : tree lrhs;
7611 : 126 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7612 : : lrhs = rhs1;
7613 : : else
7614 : 16 : lrhs = rhs2;
7615 : 126 : use_operand_p use_p;
7616 : 126 : imm_use_iterator iter;
7617 : 504 : FOR_EACH_IMM_USE_FAST (use_p, iter, lrhs)
7618 : : {
7619 : 252 : gimple *use_stmt = USE_STMT (use_p);
7620 : 252 : if (use_stmt == def_stmt || is_gimple_debug (use_stmt))
7621 : 126 : continue;
7622 : 126 : if (other_store_stmt)
7623 : 0 : goto fail;
7624 : 126 : other_store_stmt = use_stmt;
7625 : 126 : }
7626 : : }
7627 : :
7628 : 512 : if (other_store_stmt == NULL)
7629 : 0 : goto fail;
7630 : 512 : if (gimple_bb (other_store_stmt) != gimple_bb (stmt)
7631 : 512 : || !gimple_store_p (other_store_stmt))
7632 : 0 : goto fail;
7633 : :
7634 : 512 : stmt_vec_info other_store_stmt_info
7635 : 512 : = loop_vinfo->lookup_stmt (other_store_stmt);
7636 : 512 : if (other_store_stmt_info == NULL
7637 : 512 : || (STMT_VINFO_SIMD_LANE_ACCESS_P (other_store_stmt_info)
7638 : 512 : != STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)))
7639 : 0 : goto fail;
7640 : :
7641 : 512 : gimple *stmt1 = stmt;
7642 : 512 : gimple *stmt2 = other_store_stmt;
7643 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7644 : : std::swap (stmt1, stmt2);
7645 : 512 : if (scan_operand_equal_p (gimple_assign_lhs (stmt1),
7646 : : gimple_assign_rhs1 (load2_stmt)))
7647 : : {
7648 : 162 : std::swap (rhs1, rhs2);
7649 : 162 : std::swap (load1_stmt, load2_stmt);
7650 : 162 : std::swap (load1_stmt_info, load2_stmt_info);
7651 : : }
7652 : 512 : if (!scan_operand_equal_p (gimple_assign_lhs (stmt1),
7653 : : gimple_assign_rhs1 (load1_stmt)))
7654 : 0 : goto fail;
7655 : :
7656 : 512 : tree var3 = NULL_TREE;
7657 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 3
7658 : 512 : && !scan_operand_equal_p (gimple_assign_lhs (stmt2),
7659 : : gimple_assign_rhs1 (load2_stmt)))
7660 : 0 : goto fail;
7661 : 512 : else if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7662 : : {
7663 : 252 : dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info);
7664 : 252 : if (TREE_CODE (DR_BASE_ADDRESS (load2_dr_info->dr)) != ADDR_EXPR
7665 : 252 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0)))
7666 : 0 : goto fail;
7667 : 252 : var3 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0);
7668 : 252 : if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var3))
7669 : 252 : || lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var3))
7670 : 504 : || lookup_attribute ("omp simd inscan exclusive",
7671 : 252 : DECL_ATTRIBUTES (var3)))
7672 : 0 : goto fail;
7673 : : }
7674 : :
7675 : 512 : dr_vec_info *other_dr_info = STMT_VINFO_DR_INFO (other_store_stmt_info);
7676 : 512 : if (TREE_CODE (DR_BASE_ADDRESS (other_dr_info->dr)) != ADDR_EXPR
7677 : 512 : || !VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0)))
7678 : 0 : goto fail;
7679 : :
7680 : 512 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7681 : 512 : tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (other_dr_info->dr), 0);
7682 : 512 : if (!lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var1))
7683 : 512 : || !lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var2))
7684 : 1024 : || (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7685 : 512 : == (!lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var2))))
7686 : 0 : goto fail;
7687 : :
7688 : 512 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7689 : 256 : std::swap (var1, var2);
7690 : :
7691 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
7692 : : {
7693 : 252 : if (!lookup_attribute ("omp simd inscan exclusive",
7694 : 252 : DECL_ATTRIBUTES (var1)))
7695 : 0 : goto fail;
7696 : 252 : var1 = var3;
7697 : : }
7698 : :
7699 : 512 : if (loop_vinfo->scan_map == NULL)
7700 : 0 : goto fail;
7701 : 512 : tree *init = loop_vinfo->scan_map->get (var1);
7702 : 512 : if (init == NULL)
7703 : 0 : goto fail;
7704 : :
7705 : : /* The IL is as expected, now check if we can actually vectorize it.
7706 : : Inclusive scan:
7707 : : _26 = D.2043[_25];
7708 : : _27 = D.2042[_25];
7709 : : _28 = _26 + _27;
7710 : : D.2043[_25] = _28;
7711 : : D.2042[_25] = _28;
7712 : : should be vectorized as (where _40 is the vectorized rhs
7713 : : from the D.2042[_21] = 0; store):
7714 : : _30 = MEM <vector(8) int> [(int *)&D.2043];
7715 : : _31 = MEM <vector(8) int> [(int *)&D.2042];
7716 : : _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
7717 : : _33 = _31 + _32;
7718 : : // _33 = { _31[0], _31[0]+_31[1], _31[1]+_31[2], ..., _31[6]+_31[7] };
7719 : : _34 = VEC_PERM_EXPR <_40, _33, { 0, 1, 8, 9, 10, 11, 12, 13 }>;
7720 : : _35 = _33 + _34;
7721 : : // _35 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7722 : : // _31[1]+.._31[4], ... _31[4]+.._31[7] };
7723 : : _36 = VEC_PERM_EXPR <_40, _35, { 0, 1, 2, 3, 8, 9, 10, 11 }>;
7724 : : _37 = _35 + _36;
7725 : : // _37 = { _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7726 : : // _31[0]+.._31[4], ... _31[0]+.._31[7] };
7727 : : _38 = _30 + _37;
7728 : : _39 = VEC_PERM_EXPR <_38, _38, { 7, 7, 7, 7, 7, 7, 7, 7 }>;
7729 : : MEM <vector(8) int> [(int *)&D.2043] = _39;
7730 : : MEM <vector(8) int> [(int *)&D.2042] = _38;
7731 : : Exclusive scan:
7732 : : _26 = D.2043[_25];
7733 : : D.2044[_25] = _26;
7734 : : _27 = D.2042[_25];
7735 : : _28 = _26 + _27;
7736 : : D.2043[_25] = _28;
7737 : : should be vectorized as (where _40 is the vectorized rhs
7738 : : from the D.2042[_21] = 0; store):
7739 : : _30 = MEM <vector(8) int> [(int *)&D.2043];
7740 : : _31 = MEM <vector(8) int> [(int *)&D.2042];
7741 : : _32 = VEC_PERM_EXPR <_40, _31, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
7742 : : _33 = VEC_PERM_EXPR <_40, _32, { 0, 8, 9, 10, 11, 12, 13, 14 }>;
7743 : : _34 = _32 + _33;
7744 : : // _34 = { 0, _31[0], _31[0]+_31[1], _31[1]+_31[2], _31[2]+_31[3],
7745 : : // _31[3]+_31[4], ... _31[5]+.._31[6] };
7746 : : _35 = VEC_PERM_EXPR <_40, _34, { 0, 1, 8, 9, 10, 11, 12, 13 }>;
7747 : : _36 = _34 + _35;
7748 : : // _36 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7749 : : // _31[1]+.._31[4], ... _31[3]+.._31[6] };
7750 : : _37 = VEC_PERM_EXPR <_40, _36, { 0, 1, 2, 3, 8, 9, 10, 11 }>;
7751 : : _38 = _36 + _37;
7752 : : // _38 = { 0, _31[0], _31[0]+_31[1], _31[0]+.._31[2], _31[0]+.._31[3],
7753 : : // _31[0]+.._31[4], ... _31[0]+.._31[6] };
7754 : : _39 = _30 + _38;
7755 : : _50 = _31 + _39;
7756 : : _51 = VEC_PERM_EXPR <_50, _50, { 7, 7, 7, 7, 7, 7, 7, 7 }>;
7757 : : MEM <vector(8) int> [(int *)&D.2044] = _39;
7758 : : MEM <vector(8) int> [(int *)&D.2042] = _51; */
7759 : 512 : enum machine_mode vec_mode = TYPE_MODE (vectype);
7760 : 512 : optab optab = optab_for_tree_code (code, vectype, optab_default);
7761 : 512 : if (!optab || !can_implement_p (optab, vec_mode))
7762 : 0 : goto fail;
7763 : :
7764 : 512 : int units_log2 = scan_store_can_perm_p (vectype, *init);
7765 : 512 : if (units_log2 == -1)
7766 : 0 : goto fail;
7767 : :
7768 : : return true;
7769 : : }
7770 : :
7771 : :
7772 : : /* Function vectorizable_scan_store.
7773 : :
7774 : : Helper of vectorizable_score, arguments like on vectorizable_store.
7775 : : Handle only the transformation, checking is done in check_scan_store. */
7776 : :
7777 : : static bool
7778 : 512 : vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
7779 : : slp_tree slp_node, gimple_stmt_iterator *gsi)
7780 : : {
7781 : 512 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
7782 : 512 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
7783 : 512 : tree ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr));
7784 : 512 : tree vectype = SLP_TREE_VECTYPE (slp_node);
7785 : :
7786 : 512 : if (dump_enabled_p ())
7787 : 492 : dump_printf_loc (MSG_NOTE, vect_location,
7788 : : "transform scan store.\n");
7789 : :
7790 : 512 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
7791 : 512 : tree rhs = gimple_assign_rhs1 (stmt);
7792 : 512 : gcc_assert (TREE_CODE (rhs) == SSA_NAME);
7793 : :
7794 : 512 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7795 : 512 : bool inscan_var_store
7796 : 512 : = lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)) != NULL;
7797 : :
7798 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7799 : : {
7800 : 126 : use_operand_p use_p;
7801 : 126 : imm_use_iterator iter;
7802 : 252 : FOR_EACH_IMM_USE_FAST (use_p, iter, rhs)
7803 : : {
7804 : 126 : gimple *use_stmt = USE_STMT (use_p);
7805 : 126 : if (use_stmt == stmt || is_gimple_debug (use_stmt))
7806 : 0 : continue;
7807 : 126 : rhs = gimple_assign_lhs (use_stmt);
7808 : 126 : break;
7809 : 126 : }
7810 : : }
7811 : :
7812 : 512 : gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
7813 : 512 : enum tree_code code = gimple_assign_rhs_code (def_stmt);
7814 : 512 : if (code == POINTER_PLUS_EXPR)
7815 : 0 : code = PLUS_EXPR;
7816 : 512 : gcc_assert (TREE_CODE_LENGTH (code) == binary_op
7817 : : && commutative_tree_code (code));
7818 : 512 : tree rhs1 = gimple_assign_rhs1 (def_stmt);
7819 : 512 : tree rhs2 = gimple_assign_rhs2 (def_stmt);
7820 : 512 : gcc_assert (TREE_CODE (rhs1) == SSA_NAME && TREE_CODE (rhs2) == SSA_NAME);
7821 : 512 : gimple *load1_stmt = SSA_NAME_DEF_STMT (rhs1);
7822 : 512 : gimple *load2_stmt = SSA_NAME_DEF_STMT (rhs2);
7823 : 512 : stmt_vec_info load1_stmt_info = loop_vinfo->lookup_stmt (load1_stmt);
7824 : 512 : stmt_vec_info load2_stmt_info = loop_vinfo->lookup_stmt (load2_stmt);
7825 : 512 : dr_vec_info *load1_dr_info = STMT_VINFO_DR_INFO (load1_stmt_info);
7826 : 512 : dr_vec_info *load2_dr_info = STMT_VINFO_DR_INFO (load2_stmt_info);
7827 : 512 : tree var1 = TREE_OPERAND (DR_BASE_ADDRESS (load1_dr_info->dr), 0);
7828 : 512 : tree var2 = TREE_OPERAND (DR_BASE_ADDRESS (load2_dr_info->dr), 0);
7829 : :
7830 : 512 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var1)))
7831 : : {
7832 : 436 : std::swap (rhs1, rhs2);
7833 : 436 : std::swap (var1, var2);
7834 : 436 : std::swap (load1_dr_info, load2_dr_info);
7835 : : }
7836 : :
7837 : 512 : tree *init = loop_vinfo->scan_map->get (var1);
7838 : 512 : gcc_assert (init);
7839 : :
7840 : 512 : unsigned HOST_WIDE_INT nunits;
7841 : 512 : if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits))
7842 : : gcc_unreachable ();
7843 : 512 : auto_vec<enum scan_store_kind, 16> use_whole_vector;
7844 : 512 : int units_log2 = scan_store_can_perm_p (vectype, *init, &use_whole_vector);
7845 : 512 : gcc_assert (units_log2 > 0);
7846 : 512 : auto_vec<tree, 16> perms;
7847 : 512 : perms.quick_grow (units_log2 + 1);
7848 : 512 : tree zero_vec = NULL_TREE, masktype = NULL_TREE;
7849 : 2392 : for (int i = 0; i <= units_log2; ++i)
7850 : : {
7851 : 1880 : unsigned HOST_WIDE_INT j, k;
7852 : 1880 : vec_perm_builder sel (nunits, nunits, 1);
7853 : 1880 : sel.quick_grow (nunits);
7854 : 1880 : if (i == units_log2)
7855 : 4864 : for (j = 0; j < nunits; ++j)
7856 : 4352 : sel[j] = nunits - 1;
7857 : : else
7858 : : {
7859 : 5208 : for (j = 0; j < (HOST_WIDE_INT_1U << i); ++j)
7860 : 3840 : sel[j] = j;
7861 : 13208 : for (k = 0; j < nunits; ++j, ++k)
7862 : 11840 : sel[j] = nunits + k;
7863 : : }
7864 : 3248 : vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits);
7865 : 1880 : if (!use_whole_vector.is_empty ()
7866 : 0 : && use_whole_vector[i] != scan_store_kind_perm)
7867 : : {
7868 : 0 : if (zero_vec == NULL_TREE)
7869 : 0 : zero_vec = build_zero_cst (vectype);
7870 : 0 : if (masktype == NULL_TREE
7871 : 0 : && use_whole_vector[i] == scan_store_kind_lshift_cond)
7872 : 0 : masktype = truth_type_for (vectype);
7873 : 0 : perms[i] = vect_gen_perm_mask_any (vectype, indices);
7874 : : }
7875 : : else
7876 : 1880 : perms[i] = vect_gen_perm_mask_checked (vectype, indices);
7877 : 1880 : }
7878 : :
7879 : 512 : vec_loop_lens *loop_lens
7880 : 512 : = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)
7881 : : ? &LOOP_VINFO_LENS (loop_vinfo)
7882 : 0 : : NULL);
7883 : :
7884 : 512 : tree vec_oprnd1 = NULL_TREE;
7885 : 512 : tree vec_oprnd2 = NULL_TREE;
7886 : 512 : tree vec_oprnd3 = NULL_TREE;
7887 : 512 : tree dataref_ptr = DR_BASE_ADDRESS (dr_info->dr);
7888 : 512 : tree dataref_offset = build_int_cst (ref_type, 0);
7889 : 512 : tree bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info,
7890 : : vectype, VMAT_CONTIGUOUS,
7891 : : loop_lens);
7892 : 512 : tree ldataref_ptr = NULL_TREE;
7893 : 512 : tree orig = NULL_TREE;
7894 : 512 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4 && !inscan_var_store)
7895 : 126 : ldataref_ptr = DR_BASE_ADDRESS (load1_dr_info->dr);
7896 : : /* The initialization is invariant. */
7897 : 512 : vec_oprnd1 = vect_init_vector (vinfo, stmt_info, *init, vectype, NULL);
7898 : 512 : auto_vec<tree> vec_oprnds2;
7899 : 512 : auto_vec<tree> vec_oprnds3;
7900 : 512 : if (ldataref_ptr == NULL)
7901 : : {
7902 : : /* We want to lookup the vector operands of the reduction, not those
7903 : : of the store - for SLP we have to use the proper SLP node for the
7904 : : lookup, which should be the single child of the scan store. */
7905 : 386 : vect_get_vec_defs (vinfo, SLP_TREE_CHILDREN (slp_node)[0],
7906 : : rhs1, &vec_oprnds2, rhs2, &vec_oprnds3);
7907 : : /* ??? For SLP we do not key the def on 'rhs1' or 'rhs2' but get
7908 : : them in SLP child order. So we have to swap here with logic
7909 : : similar to above. */
7910 : 386 : stmt_vec_info load
7911 : 386 : = SLP_TREE_SCALAR_STMTS (SLP_TREE_CHILDREN
7912 : 386 : (SLP_TREE_CHILDREN (slp_node)[0])[0])[0];
7913 : 386 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (load);
7914 : 386 : tree var = TREE_OPERAND (DR_BASE_ADDRESS (dr_info->dr), 0);
7915 : 386 : if (lookup_attribute ("omp simd inscan", DECL_ATTRIBUTES (var)))
7916 : 820 : for (unsigned i = 0; i < vec_oprnds2.length (); ++i)
7917 : 494 : std::swap (vec_oprnds2[i], vec_oprnds3[i]);;
7918 : : }
7919 : : else
7920 : 126 : vect_get_vec_defs (vinfo, slp_node,
7921 : : rhs2, &vec_oprnds3);
7922 : 1248 : for (unsigned j = 0; j < vec_oprnds3.length (); j++)
7923 : : {
7924 : 736 : if (ldataref_ptr == NULL)
7925 : 554 : vec_oprnd2 = vec_oprnds2[j];
7926 : 736 : vec_oprnd3 = vec_oprnds3[j];
7927 : 736 : if (j == 0)
7928 : : orig = vec_oprnd3;
7929 : 224 : else if (!inscan_var_store)
7930 : 112 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
7931 : :
7932 : 736 : if (ldataref_ptr)
7933 : : {
7934 : 182 : vec_oprnd2 = make_ssa_name (vectype);
7935 : 182 : tree data_ref = fold_build2 (MEM_REF, vectype,
7936 : : unshare_expr (ldataref_ptr),
7937 : : dataref_offset);
7938 : 182 : vect_copy_ref_info (data_ref, DR_REF (load1_dr_info->dr));
7939 : 182 : gimple *g = gimple_build_assign (vec_oprnd2, data_ref);
7940 : 182 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7941 : : }
7942 : :
7943 : 736 : tree v = vec_oprnd2;
7944 : 3068 : for (int i = 0; i < units_log2; ++i)
7945 : : {
7946 : 2332 : tree new_temp = make_ssa_name (vectype);
7947 : 2332 : gimple *g = gimple_build_assign (new_temp, VEC_PERM_EXPR,
7948 : : (zero_vec
7949 : 0 : && (use_whole_vector[i]
7950 : 0 : != scan_store_kind_perm))
7951 : : ? zero_vec : vec_oprnd1, v,
7952 : 2332 : perms[i]);
7953 : 2332 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7954 : :
7955 : 2332 : if (zero_vec && use_whole_vector[i] == scan_store_kind_lshift_cond)
7956 : : {
7957 : : /* Whole vector shift shifted in zero bits, but if *init
7958 : : is not initializer_zerop, we need to replace those elements
7959 : : with elements from vec_oprnd1. */
7960 : 0 : tree_vector_builder vb (masktype, nunits, 1);
7961 : 0 : for (unsigned HOST_WIDE_INT k = 0; k < nunits; ++k)
7962 : 0 : vb.quick_push (k < (HOST_WIDE_INT_1U << i)
7963 : : ? boolean_false_node : boolean_true_node);
7964 : :
7965 : 0 : tree new_temp2 = make_ssa_name (vectype);
7966 : 0 : g = gimple_build_assign (new_temp2, VEC_COND_EXPR, vb.build (),
7967 : : new_temp, vec_oprnd1);
7968 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
7969 : : g, gsi);
7970 : 0 : new_temp = new_temp2;
7971 : 0 : }
7972 : :
7973 : : /* For exclusive scan, perform the perms[i] permutation once
7974 : : more. */
7975 : 2332 : if (i == 0
7976 : 1100 : && STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4
7977 : 728 : && v == vec_oprnd2)
7978 : : {
7979 : 364 : v = new_temp;
7980 : 364 : --i;
7981 : 364 : continue;
7982 : : }
7983 : :
7984 : 1968 : tree new_temp2 = make_ssa_name (vectype);
7985 : 1968 : g = gimple_build_assign (new_temp2, code, v, new_temp);
7986 : 1968 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7987 : :
7988 : 1968 : v = new_temp2;
7989 : : }
7990 : :
7991 : 736 : tree new_temp = make_ssa_name (vectype);
7992 : 736 : gimple *g = gimple_build_assign (new_temp, code, orig, v);
7993 : 736 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
7994 : :
7995 : 736 : tree last_perm_arg = new_temp;
7996 : : /* For exclusive scan, new_temp computed above is the exclusive scan
7997 : : prefix sum. Turn it into inclusive prefix sum for the broadcast
7998 : : of the last element into orig. */
7999 : 736 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) == 4)
8000 : : {
8001 : 364 : last_perm_arg = make_ssa_name (vectype);
8002 : 364 : g = gimple_build_assign (last_perm_arg, code, new_temp, vec_oprnd2);
8003 : 364 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8004 : : }
8005 : :
8006 : 736 : orig = make_ssa_name (vectype);
8007 : 2208 : g = gimple_build_assign (orig, VEC_PERM_EXPR, last_perm_arg,
8008 : 736 : last_perm_arg, perms[units_log2]);
8009 : 736 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8010 : :
8011 : 736 : if (!inscan_var_store)
8012 : : {
8013 : 368 : tree data_ref = fold_build2 (MEM_REF, vectype,
8014 : : unshare_expr (dataref_ptr),
8015 : : dataref_offset);
8016 : 368 : vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
8017 : 368 : g = gimple_build_assign (data_ref, new_temp);
8018 : 368 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8019 : : }
8020 : : }
8021 : :
8022 : 512 : if (inscan_var_store)
8023 : 624 : for (unsigned j = 0; j < vec_oprnds3.length (); j++)
8024 : : {
8025 : 368 : if (j != 0)
8026 : 112 : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
8027 : :
8028 : 368 : tree data_ref = fold_build2 (MEM_REF, vectype,
8029 : : unshare_expr (dataref_ptr),
8030 : : dataref_offset);
8031 : 368 : vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
8032 : 368 : gimple *g = gimple_build_assign (data_ref, orig);
8033 : 368 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
8034 : : }
8035 : 512 : return true;
8036 : 512 : }
8037 : :
8038 : :
8039 : : /* Function vectorizable_store.
8040 : :
8041 : : Check if STMT_INFO defines a non scalar data-ref (array/pointer/structure)
8042 : : that can be vectorized.
8043 : : If COST_VEC is passed, calculate costs but don't change anything,
8044 : : otherwise, vectorize STMT_INFO: create a vectorized stmt to replace
8045 : : it, and insert it at GSI.
8046 : : Return true if STMT_INFO is vectorizable in this way. */
8047 : :
8048 : : static bool
8049 : 1940599 : vectorizable_store (vec_info *vinfo,
8050 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
8051 : : slp_tree slp_node,
8052 : : stmt_vector_for_cost *cost_vec)
8053 : : {
8054 : 1940599 : tree data_ref;
8055 : 1940599 : tree vec_oprnd = NULL_TREE;
8056 : 1940599 : tree elem_type;
8057 : 1940599 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
8058 : 1940599 : class loop *loop = NULL;
8059 : 1940599 : machine_mode vec_mode;
8060 : 1940599 : tree dummy;
8061 : 1940599 : enum vect_def_type rhs_dt = vect_unknown_def_type;
8062 : 1940599 : enum vect_def_type mask_dt = vect_unknown_def_type;
8063 : 1940599 : tree dataref_ptr = NULL_TREE;
8064 : 1940599 : tree dataref_offset = NULL_TREE;
8065 : 1940599 : gimple *ptr_incr = NULL;
8066 : 1940599 : int j;
8067 : 1940599 : stmt_vec_info first_stmt_info;
8068 : 1940599 : bool grouped_store;
8069 : 1940599 : unsigned int group_size, i;
8070 : 1940599 : unsigned int vec_num;
8071 : 1940599 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
8072 : 1940599 : tree aggr_type;
8073 : 1940599 : poly_uint64 vf;
8074 : 1940599 : vec_load_store_type vls_type;
8075 : 1940599 : tree ref_type;
8076 : :
8077 : 1940599 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
8078 : : return false;
8079 : :
8080 : 1940599 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
8081 : 176586 : && cost_vec)
8082 : : return false;
8083 : :
8084 : : /* Is vectorizable store? */
8085 : :
8086 : 1764013 : tree mask_vectype = NULL_TREE;
8087 : 1764013 : slp_tree mask_node = NULL;
8088 : 1764013 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
8089 : : {
8090 : 1700068 : tree scalar_dest = gimple_assign_lhs (assign);
8091 : 1700068 : if (TREE_CODE (scalar_dest) == VIEW_CONVERT_EXPR
8092 : 1700068 : && is_pattern_stmt_p (stmt_info))
8093 : 1371 : scalar_dest = TREE_OPERAND (scalar_dest, 0);
8094 : 1700068 : if (TREE_CODE (scalar_dest) != ARRAY_REF
8095 : 1700068 : && TREE_CODE (scalar_dest) != BIT_FIELD_REF
8096 : : && TREE_CODE (scalar_dest) != INDIRECT_REF
8097 : : && TREE_CODE (scalar_dest) != COMPONENT_REF
8098 : : && TREE_CODE (scalar_dest) != IMAGPART_EXPR
8099 : : && TREE_CODE (scalar_dest) != REALPART_EXPR
8100 : : && TREE_CODE (scalar_dest) != MEM_REF)
8101 : : return false;
8102 : : }
8103 : : else
8104 : : {
8105 : 624101 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
8106 : 8657 : if (!call || !gimple_call_internal_p (call))
8107 : : return false;
8108 : :
8109 : 4757 : internal_fn ifn = gimple_call_internal_fn (call);
8110 : 4757 : if (!internal_store_fn_p (ifn))
8111 : : return false;
8112 : :
8113 : 1448 : int mask_index = internal_fn_mask_index (ifn);
8114 : 1448 : if (mask_index >= 0)
8115 : 1448 : mask_index = vect_slp_child_index_for_operand
8116 : 1448 : (call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
8117 : 1448 : if (mask_index >= 0
8118 : 1448 : && !vect_check_scalar_mask (vinfo, slp_node, mask_index,
8119 : : &mask_node, &mask_dt,
8120 : : &mask_vectype))
8121 : : return false;
8122 : : }
8123 : :
8124 : 1325187 : tree vectype = SLP_TREE_VECTYPE (slp_node), rhs_vectype = NULL_TREE;
8125 : 1325187 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
8126 : :
8127 : 1325187 : if (loop_vinfo)
8128 : : {
8129 : 188841 : loop = LOOP_VINFO_LOOP (loop_vinfo);
8130 : 188841 : vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
8131 : : }
8132 : : else
8133 : : vf = 1;
8134 : 1325187 : vec_num = vect_get_num_copies (vinfo, slp_node);
8135 : :
8136 : : /* FORNOW. This restriction should be relaxed. */
8137 : 1325187 : if (loop
8138 : 1325408 : && nested_in_vect_loop_p (loop, stmt_info)
8139 : 1325416 : && vec_num > 1)
8140 : : {
8141 : 8 : if (dump_enabled_p ())
8142 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8143 : : "multiple types in nested loop.\n");
8144 : 8 : return false;
8145 : : }
8146 : :
8147 : 1325179 : slp_tree op_node;
8148 : 1325179 : if (!vect_check_store_rhs (vinfo, stmt_info, slp_node,
8149 : : &op_node, &rhs_dt, &rhs_vectype, &vls_type))
8150 : : return false;
8151 : :
8152 : 1325155 : elem_type = TREE_TYPE (vectype);
8153 : 1325155 : vec_mode = TYPE_MODE (vectype);
8154 : :
8155 : 1325155 : if (!STMT_VINFO_DATA_REF (stmt_info))
8156 : : return false;
8157 : :
8158 : 1325155 : vect_load_store_data _ls_data{};
8159 : 1325155 : vect_load_store_data &ls = slp_node->get_data (_ls_data);
8160 : 1325155 : if (cost_vec
8161 : 1325155 : && !get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask_node,
8162 : : vls_type, &_ls_data))
8163 : : return false;
8164 : : /* Temporary aliases to analysis data, should not be modified through
8165 : : these. */
8166 : 1324613 : const vect_memory_access_type memory_access_type = ls.memory_access_type;
8167 : 1324613 : const dr_alignment_support alignment_support_scheme
8168 : : = ls.alignment_support_scheme;
8169 : 1324613 : const int misalignment = ls.misalignment;
8170 : 1324613 : const poly_int64 poffset = ls.poffset;
8171 : :
8172 : 1324613 : if (slp_node->ldst_lanes
8173 : 0 : && memory_access_type != VMAT_LOAD_STORE_LANES)
8174 : : {
8175 : 0 : if (dump_enabled_p ())
8176 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8177 : : "discovered store-lane but cannot use it.\n");
8178 : 0 : return false;
8179 : : }
8180 : :
8181 : 1324613 : if (mask_node)
8182 : : {
8183 : 1358 : if (memory_access_type == VMAT_CONTIGUOUS)
8184 : : {
8185 : 459 : if (!VECTOR_MODE_P (vec_mode)
8186 : 2232 : || !can_vec_mask_load_store_p (vec_mode,
8187 : 1116 : TYPE_MODE (mask_vectype), false))
8188 : 18 : return false;
8189 : : }
8190 : 242 : else if (memory_access_type != VMAT_LOAD_STORE_LANES
8191 : 242 : && (!mat_gather_scatter_p (memory_access_type)
8192 : 218 : || (memory_access_type == VMAT_GATHER_SCATTER_LEGACY
8193 : 154 : && !VECTOR_BOOLEAN_TYPE_P (mask_vectype))))
8194 : : {
8195 : 24 : if (dump_enabled_p ())
8196 : 24 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8197 : : "unsupported access type for masked store.\n");
8198 : 24 : return false;
8199 : : }
8200 : 218 : else if (memory_access_type == VMAT_GATHER_SCATTER_EMULATED)
8201 : : {
8202 : 64 : if (dump_enabled_p ())
8203 : 24 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8204 : : "unsupported masked emulated scatter.\n");
8205 : 64 : return false;
8206 : : }
8207 : : }
8208 : : else
8209 : : {
8210 : : /* FORNOW. In some cases can vectorize even if data-type not supported
8211 : : (e.g. - array initialization with 0). */
8212 : 1323255 : if (!can_implement_p (mov_optab, vec_mode))
8213 : : return false;
8214 : : }
8215 : :
8216 : 1324507 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL;
8217 : 1324507 : grouped_store = (STMT_VINFO_GROUPED_ACCESS (stmt_info)
8218 : 2477915 : && !mat_gather_scatter_p (memory_access_type));
8219 : 1153408 : if (grouped_store)
8220 : : {
8221 : 1153408 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
8222 : 1153408 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
8223 : 1153408 : group_size = DR_GROUP_SIZE (first_stmt_info);
8224 : : }
8225 : : else
8226 : : {
8227 : 1324507 : first_stmt_info = stmt_info;
8228 : 1324507 : first_dr_info = dr_info;
8229 : : group_size = 1;
8230 : : }
8231 : :
8232 : 1324507 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1 && cost_vec)
8233 : : {
8234 : 1076 : if (!check_scan_store (vinfo, stmt_info, vectype, rhs_dt, slp_node,
8235 : : mask_node, memory_access_type))
8236 : : return false;
8237 : : }
8238 : :
8239 : 2648246 : bool costing_p = cost_vec;
8240 : 1323739 : if (costing_p) /* transformation not required. */
8241 : : {
8242 : 780624 : if (loop_vinfo
8243 : 126550 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
8244 : 58599 : check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
8245 : : vls_type, group_size, &ls,
8246 : : mask_node);
8247 : :
8248 : 780624 : if (!vect_maybe_update_slp_op_vectype (op_node, vectype)
8249 : 780624 : || (mask_node
8250 : 712 : && !vect_maybe_update_slp_op_vectype (mask_node,
8251 : : mask_vectype)))
8252 : : {
8253 : 0 : if (dump_enabled_p ())
8254 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8255 : : "incompatible vector types for invariants\n");
8256 : 0 : return false;
8257 : : }
8258 : :
8259 : 780624 : if (dump_enabled_p ()
8260 : : && memory_access_type != VMAT_ELEMENTWISE
8261 : 14275 : && memory_access_type != VMAT_STRIDED_SLP
8262 : 13643 : && memory_access_type != VMAT_INVARIANT
8263 : 794267 : && alignment_support_scheme != dr_aligned)
8264 : 4671 : dump_printf_loc (MSG_NOTE, vect_location,
8265 : : "Vectorizing an unaligned access.\n");
8266 : :
8267 : 780624 : SLP_TREE_TYPE (slp_node) = store_vec_info_type;
8268 : 780624 : slp_node->data = new vect_load_store_data (std::move (ls));
8269 : : }
8270 : :
8271 : : /* Transform. */
8272 : :
8273 : 1324507 : ensure_base_align (dr_info);
8274 : :
8275 : 1324507 : if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) >= 3)
8276 : : {
8277 : 1024 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS);
8278 : 1024 : gcc_assert (SLP_TREE_LANES (slp_node) == 1);
8279 : 1024 : if (costing_p)
8280 : : {
8281 : 512 : unsigned int inside_cost = 0, prologue_cost = 0;
8282 : 512 : if (vls_type == VLS_STORE_INVARIANT)
8283 : 0 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
8284 : : slp_node, 0, vect_prologue);
8285 : 512 : vect_get_store_cost (vinfo, stmt_info, slp_node, 1,
8286 : : alignment_support_scheme, misalignment,
8287 : : &inside_cost, cost_vec);
8288 : :
8289 : 512 : if (dump_enabled_p ())
8290 : 492 : dump_printf_loc (MSG_NOTE, vect_location,
8291 : : "vect_model_store_cost: inside_cost = %d, "
8292 : : "prologue_cost = %d .\n",
8293 : : inside_cost, prologue_cost);
8294 : :
8295 : 512 : return true;
8296 : : }
8297 : 512 : return vectorizable_scan_store (vinfo, stmt_info, slp_node, gsi);
8298 : : }
8299 : :
8300 : : /* FORNOW */
8301 : 1323483 : gcc_assert (!grouped_store
8302 : : || !loop
8303 : : || !nested_in_vect_loop_p (loop, stmt_info));
8304 : :
8305 : 1323483 : grouped_store = false;
8306 : 1323483 : first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
8307 : 1323483 : gcc_assert (!STMT_VINFO_GROUPED_ACCESS (first_stmt_info)
8308 : : || (DR_GROUP_FIRST_ELEMENT (first_stmt_info) == first_stmt_info));
8309 : 1323483 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
8310 : :
8311 : 1323483 : ref_type = get_group_alias_ptr_type (first_stmt_info);
8312 : :
8313 : 1323483 : if (!costing_p && dump_enabled_p ())
8314 : 11852 : dump_printf_loc (MSG_NOTE, vect_location, "transform store.\n");
8315 : :
8316 : 1323483 : if (memory_access_type == VMAT_ELEMENTWISE
8317 : 1323483 : || memory_access_type == VMAT_STRIDED_SLP)
8318 : : {
8319 : 29977 : unsigned inside_cost = 0, prologue_cost = 0;
8320 : 29977 : gimple_stmt_iterator incr_gsi;
8321 : 29977 : bool insert_after;
8322 : 29977 : tree offvar = NULL_TREE;
8323 : 29977 : tree ivstep;
8324 : 29977 : tree running_off;
8325 : 29977 : tree stride_base, stride_step, alias_off;
8326 : 29977 : tree vec_oprnd = NULL_TREE;
8327 : 29977 : tree dr_offset;
8328 : : /* Checked by get_load_store_type. */
8329 : 29977 : unsigned int const_nunits = nunits.to_constant ();
8330 : :
8331 : 29977 : gcc_assert (!LOOP_VINFO_FULLY_MASKED_P (loop_vinfo));
8332 : 29977 : gcc_assert (!nested_in_vect_loop_p (loop, stmt_info));
8333 : :
8334 : 29977 : dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info);
8335 : 29977 : stride_base
8336 : 29977 : = fold_build_pointer_plus
8337 : : (DR_BASE_ADDRESS (first_dr_info->dr),
8338 : : size_binop (PLUS_EXPR,
8339 : : convert_to_ptrofftype (dr_offset),
8340 : : convert_to_ptrofftype (DR_INIT (first_dr_info->dr))));
8341 : 29977 : stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr));
8342 : :
8343 : : /* For a store with loop-invariant (but other than power-of-2)
8344 : : stride (i.e. not a grouped access) like so:
8345 : :
8346 : : for (i = 0; i < n; i += stride)
8347 : : array[i] = ...;
8348 : :
8349 : : we generate a new induction variable and new stores from
8350 : : the components of the (vectorized) rhs:
8351 : :
8352 : : for (j = 0; ; j += VF*stride)
8353 : : vectemp = ...;
8354 : : tmp1 = vectemp[0];
8355 : : array[j] = tmp1;
8356 : : tmp2 = vectemp[1];
8357 : : array[j + stride] = tmp2;
8358 : : ...
8359 : : */
8360 : :
8361 : : /* ??? Modify local copies of alignment_support_scheme and
8362 : : misalignment, but this part of analysis should be done
8363 : : earlier and remembered, likewise the chosen load mode. */
8364 : 29977 : const dr_alignment_support tem = alignment_support_scheme;
8365 : 29977 : dr_alignment_support alignment_support_scheme = tem;
8366 : 29977 : const int tem2 = misalignment;
8367 : 29977 : int misalignment = tem2;
8368 : :
8369 : 29977 : unsigned nstores = const_nunits;
8370 : 29977 : unsigned lnel = 1;
8371 : 29977 : tree ltype = elem_type;
8372 : 29977 : tree lvectype = vectype;
8373 : 29977 : HOST_WIDE_INT n = gcd (group_size, const_nunits);
8374 : 29977 : if (n == const_nunits)
8375 : : {
8376 : 2553 : int mis_align = dr_misalignment (first_dr_info, vectype);
8377 : : /* With VF > 1 we advance the DR by step, if that is constant
8378 : : and only aligned when performed VF times, DR alignment
8379 : : analysis can analyze this as aligned since it assumes
8380 : : contiguous accesses. But that is not how we code generate
8381 : : here, so adjust for this. */
8382 : 2553 : if (maybe_gt (vf, 1u)
8383 : 4066 : && !multiple_p (DR_STEP_ALIGNMENT (first_dr_info->dr),
8384 : 3838 : DR_TARGET_ALIGNMENT (first_dr_info)))
8385 : 228 : mis_align = -1;
8386 : 2553 : dr_alignment_support dr_align
8387 : 2553 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype,
8388 : : mis_align);
8389 : 2553 : if (dr_align == dr_aligned
8390 : 2553 : || dr_align == dr_unaligned_supported)
8391 : : {
8392 : 29977 : nstores = 1;
8393 : 29977 : lnel = const_nunits;
8394 : 29977 : ltype = vectype;
8395 : 29977 : lvectype = vectype;
8396 : 29977 : alignment_support_scheme = dr_align;
8397 : 29977 : misalignment = mis_align;
8398 : : }
8399 : : }
8400 : 27424 : else if (n > 1)
8401 : : {
8402 : 1811 : nstores = const_nunits / n;
8403 : 1811 : lnel = n;
8404 : 1811 : ltype = build_vector_type (elem_type, n);
8405 : 1811 : lvectype = vectype;
8406 : 1811 : int mis_align = dr_misalignment (first_dr_info, ltype);
8407 : 1811 : if (maybe_gt (vf, 1u)
8408 : 3622 : && !multiple_p (DR_STEP_ALIGNMENT (first_dr_info->dr),
8409 : 2899 : DR_TARGET_ALIGNMENT (first_dr_info)))
8410 : 723 : mis_align = -1;
8411 : 1811 : dr_alignment_support dr_align
8412 : 1811 : = vect_supportable_dr_alignment (vinfo, dr_info, ltype,
8413 : : mis_align);
8414 : 1811 : alignment_support_scheme = dr_align;
8415 : 1811 : misalignment = mis_align;
8416 : :
8417 : : /* First check if vec_extract optab doesn't support extraction
8418 : : of vector elts directly. */
8419 : 1811 : scalar_mode elmode = SCALAR_TYPE_MODE (elem_type);
8420 : 1811 : machine_mode vmode;
8421 : 3622 : if (!VECTOR_MODE_P (TYPE_MODE (vectype))
8422 : 2037 : || !related_vector_mode (TYPE_MODE (vectype), elmode,
8423 : 1811 : n).exists (&vmode)
8424 : 1627 : || (convert_optab_handler (vec_extract_optab,
8425 : 1627 : TYPE_MODE (vectype), vmode)
8426 : : == CODE_FOR_nothing)
8427 : 1811 : || !(dr_align == dr_aligned
8428 : 226 : || dr_align == dr_unaligned_supported))
8429 : : {
8430 : : /* Try to avoid emitting an extract of vector elements
8431 : : by performing the extracts using an integer type of the
8432 : : same size, extracting from a vector of those and then
8433 : : re-interpreting it as the original vector type if
8434 : : supported. */
8435 : 1585 : unsigned lsize = n * GET_MODE_BITSIZE (elmode);
8436 : 1585 : unsigned int lnunits = const_nunits / n;
8437 : : /* If we can't construct such a vector fall back to
8438 : : element extracts from the original vector type and
8439 : : element size stores. */
8440 : 1585 : if (int_mode_for_size (lsize, 0).exists (&elmode)
8441 : 1585 : && VECTOR_MODE_P (TYPE_MODE (vectype))
8442 : 1585 : && related_vector_mode (TYPE_MODE (vectype), elmode,
8443 : 1585 : lnunits).exists (&vmode)
8444 : 1551 : && (convert_optab_handler (vec_extract_optab,
8445 : : vmode, elmode)
8446 : : != CODE_FOR_nothing))
8447 : : {
8448 : 1551 : nstores = lnunits;
8449 : 1551 : lnel = n;
8450 : 1551 : ltype = build_nonstandard_integer_type (lsize, 1);
8451 : 1551 : lvectype = build_vector_type (ltype, nstores);
8452 : : }
8453 : : /* Else fall back to vector extraction anyway.
8454 : : Fewer stores are more important than avoiding spilling
8455 : : of the vector we extract from. Compared to the
8456 : : construction case in vectorizable_load no store-forwarding
8457 : : issue exists here for reasonable archs. But only
8458 : : if the store is supported. */
8459 : 34 : else if (!(dr_align == dr_aligned
8460 : 34 : || dr_align == dr_unaligned_supported))
8461 : : {
8462 : : nstores = const_nunits;
8463 : : lnel = 1;
8464 : : ltype = elem_type;
8465 : : lvectype = vectype;
8466 : : }
8467 : : }
8468 : : }
8469 : 29977 : unsigned align;
8470 : 29977 : if (alignment_support_scheme == dr_aligned)
8471 : 1118 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
8472 : : else
8473 : 28859 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
8474 : : /* Alignment is at most the access size if we do multiple stores. */
8475 : 29977 : if (nstores > 1)
8476 : 27424 : align = MIN (tree_to_uhwi (TYPE_SIZE_UNIT (ltype)), align);
8477 : 29977 : ltype = build_aligned_type (ltype, align * BITS_PER_UNIT);
8478 : 29977 : int ncopies = vec_num;
8479 : :
8480 : 29977 : if (!costing_p)
8481 : : {
8482 : 3252 : ivstep = stride_step;
8483 : 3252 : ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (ivstep), ivstep,
8484 : : build_int_cst (TREE_TYPE (ivstep), vf));
8485 : :
8486 : 3252 : standard_iv_increment_position (loop, &incr_gsi, &insert_after);
8487 : :
8488 : 3252 : stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base);
8489 : 3252 : ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep);
8490 : 3252 : create_iv (stride_base, PLUS_EXPR, ivstep, NULL, loop, &incr_gsi,
8491 : : insert_after, &offvar, NULL);
8492 : :
8493 : 3252 : stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step);
8494 : : }
8495 : :
8496 : 29977 : alias_off = build_int_cst (ref_type, 0);
8497 : 29977 : auto_vec<tree> vec_oprnds;
8498 : : /* For costing some adjacent vector stores, we'd like to cost with
8499 : : the total number of them once instead of cost each one by one. */
8500 : 29977 : unsigned int n_adjacent_stores = 0;
8501 : 29977 : running_off = offvar;
8502 : 29977 : if (!costing_p)
8503 : 3252 : vect_get_slp_defs (op_node, &vec_oprnds);
8504 : 29977 : unsigned int group_el = 0;
8505 : 29977 : unsigned HOST_WIDE_INT elsz
8506 : 29977 : = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
8507 : 70888 : for (j = 0; j < ncopies; j++)
8508 : : {
8509 : 40911 : if (!costing_p)
8510 : : {
8511 : 4971 : vec_oprnd = vec_oprnds[j];
8512 : : /* Pun the vector to extract from if necessary. */
8513 : 4971 : if (lvectype != vectype)
8514 : : {
8515 : 1210 : tree tem = make_ssa_name (lvectype);
8516 : 1210 : tree cvt = build1 (VIEW_CONVERT_EXPR, lvectype, vec_oprnd);
8517 : 1210 : gimple *pun = gimple_build_assign (tem, cvt);
8518 : 1210 : vect_finish_stmt_generation (vinfo, stmt_info, pun, gsi);
8519 : 1210 : vec_oprnd = tem;
8520 : : }
8521 : : }
8522 : 184719 : for (i = 0; i < nstores; i++)
8523 : : {
8524 : 143808 : if (costing_p)
8525 : : {
8526 : 128133 : n_adjacent_stores++;
8527 : 128133 : continue;
8528 : : }
8529 : 15675 : tree newref, newoff;
8530 : 15675 : gimple *incr, *assign;
8531 : 15675 : tree size = TYPE_SIZE (ltype);
8532 : : /* Extract the i'th component. */
8533 : 15675 : tree pos = fold_build2 (MULT_EXPR, bitsizetype,
8534 : : bitsize_int (i), size);
8535 : 15675 : tree elem = fold_build3 (BIT_FIELD_REF, ltype, vec_oprnd,
8536 : : size, pos);
8537 : :
8538 : 15675 : elem = force_gimple_operand_gsi (gsi, elem, true, NULL_TREE, true,
8539 : : GSI_SAME_STMT);
8540 : :
8541 : 15675 : tree this_off = build_int_cst (TREE_TYPE (alias_off),
8542 : 15675 : group_el * elsz);
8543 : 15675 : newref = build2 (MEM_REF, ltype, running_off, this_off);
8544 : 15675 : vect_copy_ref_info (newref, DR_REF (first_dr_info->dr));
8545 : :
8546 : : /* And store it to *running_off. */
8547 : 15675 : assign = gimple_build_assign (newref, elem);
8548 : 15675 : vect_finish_stmt_generation (vinfo, stmt_info, assign, gsi);
8549 : :
8550 : 15675 : group_el += lnel;
8551 : 15675 : if (group_el == group_size)
8552 : : {
8553 : 14572 : newoff = copy_ssa_name (running_off, NULL);
8554 : 14572 : incr = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
8555 : : running_off, stride_step);
8556 : 14572 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
8557 : :
8558 : 14572 : running_off = newoff;
8559 : 14572 : group_el = 0;
8560 : : }
8561 : : }
8562 : : }
8563 : :
8564 : 29977 : if (costing_p)
8565 : : {
8566 : 26725 : if (n_adjacent_stores > 0)
8567 : : {
8568 : : /* Take a single lane vector type store as scalar
8569 : : store to avoid ICE like 110776. */
8570 : 26725 : if (VECTOR_TYPE_P (ltype)
8571 : 26725 : && maybe_ne (TYPE_VECTOR_SUBPARTS (ltype), 1U))
8572 : 1226 : vect_get_store_cost (vinfo, stmt_info, slp_node,
8573 : : n_adjacent_stores, alignment_support_scheme,
8574 : : misalignment, &inside_cost, cost_vec);
8575 : : else
8576 : 25499 : inside_cost
8577 : 25499 : += record_stmt_cost (cost_vec, n_adjacent_stores,
8578 : : scalar_store, slp_node, 0, vect_body);
8579 : : /* Only need vector extracting when there are more
8580 : : than one stores. */
8581 : 26725 : if (nstores > 1)
8582 : 24913 : inside_cost
8583 : 24913 : += record_stmt_cost (cost_vec, n_adjacent_stores,
8584 : : vec_to_scalar, slp_node, 0, vect_body);
8585 : : }
8586 : 26725 : if (dump_enabled_p ())
8587 : 632 : dump_printf_loc (MSG_NOTE, vect_location,
8588 : : "vect_model_store_cost: inside_cost = %d, "
8589 : : "prologue_cost = %d .\n",
8590 : : inside_cost, prologue_cost);
8591 : : }
8592 : :
8593 : 29977 : return true;
8594 : 29977 : }
8595 : :
8596 : 1293506 : gcc_assert (alignment_support_scheme);
8597 : 1293506 : vec_loop_masks *loop_masks
8598 : 157160 : = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
8599 : 1293506 : ? &LOOP_VINFO_MASKS (loop_vinfo)
8600 : 11 : : NULL);
8601 : 11 : vec_loop_lens *loop_lens
8602 : 157160 : = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)
8603 : : ? &LOOP_VINFO_LENS (loop_vinfo)
8604 : 0 : : NULL);
8605 : :
8606 : : /* The vect_transform_stmt and vect_analyze_stmt will go here but there
8607 : : are some difference here. We cannot enable both the lens and masks
8608 : : during transform but it is allowed during analysis.
8609 : : Shouldn't go with length-based approach if fully masked. */
8610 : 1293506 : if (cost_vec == NULL)
8611 : : /* The cost_vec is NULL during transfrom. */
8612 : 540119 : gcc_assert ((!loop_lens || !loop_masks));
8613 : :
8614 : : /* Targets with store-lane instructions must not require explicit
8615 : : realignment. vect_supportable_dr_alignment always returns either
8616 : : dr_aligned or dr_unaligned_supported for masked operations. */
8617 : 1293506 : gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES
8618 : : && !mask_node
8619 : : && !loop_masks)
8620 : : || alignment_support_scheme == dr_aligned
8621 : : || alignment_support_scheme == dr_unaligned_supported);
8622 : :
8623 : 1293506 : tree offset = NULL_TREE;
8624 : 1293506 : if (!known_eq (poffset, 0))
8625 : 4086 : offset = size_int (poffset);
8626 : :
8627 : 1293506 : tree bump;
8628 : 1293506 : tree vec_offset = NULL_TREE;
8629 : 1293506 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
8630 : : {
8631 : 1353 : aggr_type = NULL_TREE;
8632 : 1353 : bump = NULL_TREE;
8633 : : }
8634 : 1292153 : else if (mat_gather_scatter_p (memory_access_type))
8635 : : {
8636 : 0 : aggr_type = elem_type;
8637 : 0 : if (!costing_p)
8638 : : {
8639 : 0 : tree vtype = ls.ls_type ? ls.ls_type : vectype;
8640 : 0 : vect_get_strided_load_store_ops (stmt_info, slp_node, vtype,
8641 : : ls.strided_offset_vectype,
8642 : : loop_vinfo, gsi,
8643 : : &bump, &vec_offset, loop_lens);
8644 : : }
8645 : : }
8646 : : else
8647 : : {
8648 : 1292153 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
8649 : 0 : aggr_type = build_array_type_nelts (elem_type, group_size * nunits);
8650 : : else
8651 : : aggr_type = vectype;
8652 : 1292153 : if (!costing_p)
8653 : 539649 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
8654 : : memory_access_type, loop_lens);
8655 : : }
8656 : :
8657 : 1293506 : if (mask_node && !costing_p)
8658 : 540 : LOOP_VINFO_HAS_MASK_STORE (loop_vinfo) = true;
8659 : :
8660 : : /* In case the vectorization factor (VF) is bigger than the number
8661 : : of elements that we can fit in a vectype (nunits), we have to generate
8662 : : more than one vector stmt - i.e - we need to "unroll" the
8663 : : vector stmt by a factor VF/nunits. */
8664 : :
8665 : 1293506 : auto_vec<tree> dr_chain (group_size);
8666 : 1293506 : auto_vec<tree> vec_masks;
8667 : 1293506 : tree vec_mask = NULL;
8668 : 1293506 : auto_delete_vec<auto_vec<tree>> gvec_oprnds (group_size);
8669 : 5880167 : for (i = 0; i < group_size; i++)
8670 : 3293155 : gvec_oprnds.quick_push (new auto_vec<tree> ());
8671 : :
8672 : 1293506 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
8673 : : {
8674 : 0 : const internal_fn lanes_ifn = ls.lanes_ifn;
8675 : :
8676 : 0 : if (costing_p)
8677 : : /* Update all incoming store operand nodes, the general handling
8678 : : above only handles the mask and the first store operand node. */
8679 : 0 : for (slp_tree child : SLP_TREE_CHILDREN (slp_node))
8680 : 0 : if (child != mask_node
8681 : 0 : && !vect_maybe_update_slp_op_vectype (child, vectype))
8682 : : {
8683 : 0 : if (dump_enabled_p ())
8684 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
8685 : : "incompatible vector types for invariants\n");
8686 : 0 : return false;
8687 : : }
8688 : 0 : unsigned inside_cost = 0, prologue_cost = 0;
8689 : : /* For costing some adjacent vector stores, we'd like to cost with
8690 : : the total number of them once instead of cost each one by one. */
8691 : 0 : unsigned int n_adjacent_stores = 0;
8692 : 0 : int ncopies = vec_num / group_size;
8693 : 0 : for (j = 0; j < ncopies; j++)
8694 : : {
8695 : 0 : if (j == 0)
8696 : : {
8697 : 0 : if (!costing_p)
8698 : : {
8699 : 0 : if (mask_node)
8700 : : {
8701 : 0 : vect_get_slp_defs (mask_node, &vec_masks);
8702 : 0 : vec_mask = vec_masks[0];
8703 : : }
8704 : 0 : dataref_ptr
8705 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info,
8706 : : aggr_type, NULL, offset, &dummy,
8707 : : gsi, &ptr_incr, false, bump);
8708 : : }
8709 : : }
8710 : 0 : else if (!costing_p)
8711 : : {
8712 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
8713 : 0 : if (mask_node)
8714 : 0 : vec_mask = vec_masks[j];
8715 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
8716 : : stmt_info, bump);
8717 : : }
8718 : :
8719 : 0 : if (costing_p)
8720 : : {
8721 : 0 : n_adjacent_stores += group_size;
8722 : 0 : continue;
8723 : : }
8724 : :
8725 : : /* Get an array into which we can store the individual vectors. */
8726 : 0 : tree vec_array = create_vector_array (vectype, group_size);
8727 : :
8728 : : /* Invalidate the current contents of VEC_ARRAY. This should
8729 : : become an RTL clobber too, which prevents the vector registers
8730 : : from being upward-exposed. */
8731 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
8732 : :
8733 : : /* Store the individual vectors into the array. */
8734 : 0 : for (i = 0; i < group_size; i++)
8735 : : {
8736 : 0 : slp_tree child;
8737 : 0 : if (i == 0 || !mask_node)
8738 : 0 : child = SLP_TREE_CHILDREN (slp_node)[i];
8739 : : else
8740 : 0 : child = SLP_TREE_CHILDREN (slp_node)[i + 1];
8741 : 0 : vec_oprnd = SLP_TREE_VEC_DEFS (child)[j];
8742 : 0 : write_vector_array (vinfo, stmt_info, gsi, vec_oprnd, vec_array,
8743 : : i);
8744 : : }
8745 : :
8746 : 0 : tree final_mask = NULL;
8747 : 0 : tree final_len = NULL;
8748 : 0 : tree bias = NULL;
8749 : 0 : if (loop_masks)
8750 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
8751 : : ncopies, vectype, j);
8752 : 0 : if (vec_mask)
8753 : 0 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
8754 : : vec_mask, gsi);
8755 : :
8756 : 0 : if (lanes_ifn == IFN_MASK_LEN_STORE_LANES)
8757 : : {
8758 : 0 : if (loop_lens)
8759 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
8760 : : ncopies, vectype, j, 1);
8761 : : else
8762 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
8763 : 0 : signed char biasval
8764 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
8765 : 0 : bias = build_int_cst (intQI_type_node, biasval);
8766 : 0 : if (!final_mask)
8767 : : {
8768 : 0 : mask_vectype = truth_type_for (vectype);
8769 : 0 : final_mask = build_minus_one_cst (mask_vectype);
8770 : : }
8771 : : }
8772 : :
8773 : 0 : gcall *call;
8774 : 0 : if (final_len && final_mask)
8775 : : {
8776 : : /* Emit:
8777 : : MASK_LEN_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
8778 : : LEN, BIAS, VEC_ARRAY). */
8779 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
8780 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
8781 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_STORE_LANES, 6,
8782 : : dataref_ptr, alias_ptr,
8783 : : final_mask, final_len, bias,
8784 : : vec_array);
8785 : : }
8786 : 0 : else if (final_mask)
8787 : : {
8788 : : /* Emit:
8789 : : MASK_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
8790 : : VEC_ARRAY). */
8791 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
8792 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
8793 : 0 : call = gimple_build_call_internal (IFN_MASK_STORE_LANES, 4,
8794 : : dataref_ptr, alias_ptr,
8795 : : final_mask, vec_array);
8796 : : }
8797 : : else
8798 : : {
8799 : : /* Emit:
8800 : : MEM_REF[...all elements...] = STORE_LANES (VEC_ARRAY). */
8801 : 0 : data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
8802 : 0 : call = gimple_build_call_internal (IFN_STORE_LANES, 1, vec_array);
8803 : 0 : gimple_call_set_lhs (call, data_ref);
8804 : : }
8805 : 0 : gimple_call_set_nothrow (call, true);
8806 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
8807 : :
8808 : : /* Record that VEC_ARRAY is now dead. */
8809 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
8810 : : }
8811 : :
8812 : 0 : if (costing_p)
8813 : : {
8814 : 0 : if (n_adjacent_stores > 0)
8815 : 0 : vect_get_store_cost (vinfo, stmt_info, slp_node, n_adjacent_stores,
8816 : : alignment_support_scheme, misalignment,
8817 : : &inside_cost, cost_vec);
8818 : 0 : if (dump_enabled_p ())
8819 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
8820 : : "vect_model_store_cost: inside_cost = %d, "
8821 : : "prologue_cost = %d .\n",
8822 : : inside_cost, prologue_cost);
8823 : : }
8824 : :
8825 : 0 : return true;
8826 : : }
8827 : :
8828 : 1293506 : if (mat_gather_scatter_p (memory_access_type))
8829 : : {
8830 : 1353 : gcc_assert (!grouped_store || ls.ls_type);
8831 : 1353 : if (ls.ls_type)
8832 : 0 : vectype = ls.ls_type;
8833 : 1353 : auto_vec<tree> vec_offsets;
8834 : 1353 : unsigned int inside_cost = 0, prologue_cost = 0;
8835 : 1353 : int num_stmts = vec_num;
8836 : 3102 : for (j = 0; j < num_stmts; j++)
8837 : : {
8838 : 1749 : gimple *new_stmt;
8839 : 1749 : if (j == 0)
8840 : : {
8841 : 1353 : if (costing_p && vls_type == VLS_STORE_INVARIANT)
8842 : 206 : prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
8843 : : slp_node, 0, vect_prologue);
8844 : : else if (!costing_p)
8845 : : {
8846 : : /* Since the store is not grouped, DR_GROUP_SIZE is 1, and
8847 : : DR_CHAIN is of size 1. */
8848 : 470 : gcc_assert (group_size == 1);
8849 : 470 : vect_get_slp_defs (op_node, gvec_oprnds[0]);
8850 : 470 : if (mask_node)
8851 : 70 : vect_get_slp_defs (mask_node, &vec_masks);
8852 : :
8853 : 470 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
8854 : 470 : vect_get_gather_scatter_ops (loop, slp_node,
8855 : : &dataref_ptr, &vec_offsets);
8856 : : else
8857 : 0 : dataref_ptr
8858 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info,
8859 : : aggr_type, NULL, offset,
8860 : : &dummy, gsi, &ptr_incr, false,
8861 : : bump);
8862 : : }
8863 : : }
8864 : 396 : else if (!costing_p)
8865 : : {
8866 : 34 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
8867 : 34 : if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info))
8868 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
8869 : : gsi, stmt_info, bump);
8870 : : }
8871 : :
8872 : 2459 : new_stmt = NULL;
8873 : 710 : if (!costing_p)
8874 : : {
8875 : 504 : vec_oprnd = (*gvec_oprnds[0])[j];
8876 : 504 : if (mask_node)
8877 : 90 : vec_mask = vec_masks[j];
8878 : : /* We should have catched mismatched types earlier. */
8879 : 504 : gcc_assert (ls.ls_type
8880 : : || useless_type_conversion_p
8881 : : (vectype, TREE_TYPE (vec_oprnd)));
8882 : : }
8883 : 504 : tree final_mask = NULL_TREE;
8884 : 2253 : tree final_len = NULL_TREE;
8885 : 2253 : tree bias = NULL_TREE;
8886 : 504 : if (!costing_p)
8887 : : {
8888 : 504 : if (loop_masks)
8889 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi,
8890 : : loop_masks, num_stmts,
8891 : : vectype, j);
8892 : 504 : if (vec_mask)
8893 : 90 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
8894 : : final_mask, vec_mask, gsi);
8895 : : }
8896 : :
8897 : 1749 : unsigned align = get_object_alignment (DR_REF (first_dr_info->dr));
8898 : 1749 : tree alias_align_ptr = build_int_cst (ref_type, align);
8899 : 1749 : if (memory_access_type == VMAT_GATHER_SCATTER_IFN)
8900 : : {
8901 : 0 : if (costing_p)
8902 : : {
8903 : 0 : if (ls.supported_offset_vectype)
8904 : 0 : inside_cost
8905 : 0 : += record_stmt_cost (cost_vec, 1, vector_stmt,
8906 : : slp_node, 0, vect_body);
8907 : 0 : if (ls.supported_scale)
8908 : 0 : inside_cost
8909 : 0 : += record_stmt_cost (cost_vec, 1, vector_stmt,
8910 : : slp_node, 0, vect_body);
8911 : :
8912 : 0 : unsigned int cnunits = vect_nunits_for_cost (vectype);
8913 : 0 : inside_cost
8914 : 0 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
8915 : : slp_node, 0, vect_body);
8916 : 1749 : continue;
8917 : 0 : }
8918 : :
8919 : 0 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
8920 : 0 : vec_offset = vec_offsets[j];
8921 : :
8922 : 0 : tree scale = size_int (SLP_TREE_GS_SCALE (slp_node));
8923 : 0 : bool strided = !VECTOR_TYPE_P (TREE_TYPE (vec_offset));
8924 : :
8925 : : /* Perform the offset conversion and scaling if necessary. */
8926 : 0 : if (!strided
8927 : 0 : && (ls.supported_offset_vectype || ls.supported_scale))
8928 : : {
8929 : 0 : gimple_seq stmts = NULL;
8930 : 0 : if (ls.supported_offset_vectype)
8931 : 0 : vec_offset = gimple_convert
8932 : 0 : (&stmts, ls.supported_offset_vectype, vec_offset);
8933 : 0 : if (ls.supported_scale)
8934 : : {
8935 : 0 : tree mult_cst = build_int_cst
8936 : 0 : (TREE_TYPE (TREE_TYPE (vec_offset)),
8937 : 0 : SLP_TREE_GS_SCALE (slp_node) / ls.supported_scale);
8938 : 0 : tree mult = build_vector_from_val
8939 : 0 : (TREE_TYPE (vec_offset), mult_cst);
8940 : 0 : vec_offset = gimple_build
8941 : 0 : (&stmts, MULT_EXPR, TREE_TYPE (vec_offset),
8942 : : vec_offset, mult);
8943 : 0 : scale = size_int (ls.supported_scale);
8944 : : }
8945 : 0 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
8946 : : }
8947 : :
8948 : 0 : if (ls.gs.ifn == IFN_MASK_LEN_SCATTER_STORE)
8949 : : {
8950 : 0 : if (loop_lens)
8951 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi,
8952 : : loop_lens, num_stmts,
8953 : : vectype, j, 1);
8954 : : else
8955 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
8956 : :
8957 : 0 : signed char biasval
8958 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
8959 : 0 : bias = build_int_cst (intQI_type_node, biasval);
8960 : 0 : if (!final_mask)
8961 : : {
8962 : 0 : mask_vectype = truth_type_for (vectype);
8963 : 0 : final_mask = build_minus_one_cst (mask_vectype);
8964 : : }
8965 : : }
8966 : :
8967 : 0 : if (ls.ls_type)
8968 : : {
8969 : 0 : gimple *conv_stmt
8970 : 0 : = gimple_build_assign (make_ssa_name (vectype),
8971 : : VIEW_CONVERT_EXPR,
8972 : : build1 (VIEW_CONVERT_EXPR, vectype,
8973 : : vec_oprnd));
8974 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, conv_stmt,
8975 : : gsi);
8976 : 0 : vec_oprnd = gimple_get_lhs (conv_stmt);
8977 : : }
8978 : :
8979 : 0 : gcall *call;
8980 : 0 : if (final_len && final_mask)
8981 : : {
8982 : 0 : if (VECTOR_TYPE_P (TREE_TYPE (vec_offset)))
8983 : 0 : call = gimple_build_call_internal (
8984 : : IFN_MASK_LEN_SCATTER_STORE, 8, dataref_ptr,
8985 : : alias_align_ptr,
8986 : : vec_offset, scale, vec_oprnd, final_mask, final_len,
8987 : : bias);
8988 : : else
8989 : : /* Non-vector offset indicates that prefer to take
8990 : : MASK_LEN_STRIDED_STORE instead of the
8991 : : IFN_MASK_SCATTER_STORE with direct stride arg.
8992 : : Similar to the gather case we have checked the
8993 : : alignment for a scatter already and assume
8994 : : that the strided store has the same requirements. */
8995 : 0 : call = gimple_build_call_internal (
8996 : : IFN_MASK_LEN_STRIDED_STORE, 6, dataref_ptr,
8997 : : vec_offset, vec_oprnd, final_mask, final_len, bias);
8998 : : }
8999 : 0 : else if (final_mask)
9000 : 0 : call = gimple_build_call_internal
9001 : 0 : (IFN_MASK_SCATTER_STORE, 6, dataref_ptr,
9002 : : alias_align_ptr,
9003 : : vec_offset, scale, vec_oprnd, final_mask);
9004 : : else
9005 : 0 : call = gimple_build_call_internal (IFN_SCATTER_STORE, 5,
9006 : : dataref_ptr,
9007 : : alias_align_ptr,
9008 : : vec_offset,
9009 : : scale, vec_oprnd);
9010 : 0 : gimple_call_set_nothrow (call, true);
9011 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9012 : 0 : new_stmt = call;
9013 : : }
9014 : 1749 : else if (memory_access_type == VMAT_GATHER_SCATTER_LEGACY)
9015 : : {
9016 : : /* The builtin decls path for scatter is legacy, x86 only. */
9017 : 310 : gcc_assert (nunits.is_constant ()
9018 : : && (!final_mask
9019 : : || SCALAR_INT_MODE_P
9020 : : (TYPE_MODE (TREE_TYPE (final_mask)))));
9021 : 310 : if (costing_p)
9022 : : {
9023 : 179 : unsigned int cnunits = vect_nunits_for_cost (vectype);
9024 : 179 : inside_cost
9025 : 179 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
9026 : : slp_node, 0, vect_body);
9027 : 179 : continue;
9028 : 179 : }
9029 : :
9030 : 131 : tree offset_vectype = TREE_TYPE (vec_offsets[0]);
9031 : 131 : poly_uint64 offset_nunits
9032 : 131 : = TYPE_VECTOR_SUBPARTS (offset_vectype);
9033 : 131 : if (known_eq (nunits, offset_nunits))
9034 : : {
9035 : 55 : new_stmt = vect_build_one_scatter_store_call
9036 : 110 : (vinfo, stmt_info, slp_node, gsi,
9037 : 55 : ls.gs.decl, dataref_ptr, vec_offsets[j],
9038 : : vec_oprnd, final_mask);
9039 : 55 : vect_finish_stmt_generation (vinfo, stmt_info,
9040 : : new_stmt, gsi);
9041 : : }
9042 : 76 : else if (known_eq (nunits, offset_nunits * 2))
9043 : : {
9044 : : /* We have a offset vector with half the number of
9045 : : lanes but the builtins will store full vectype
9046 : : data from the lower lanes. */
9047 : 30 : new_stmt = vect_build_one_scatter_store_call
9048 : 60 : (vinfo, stmt_info, slp_node, gsi, ls.gs.decl,
9049 : 30 : dataref_ptr, vec_offsets[2 * j],
9050 : : vec_oprnd, final_mask);
9051 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
9052 : : new_stmt, gsi);
9053 : 30 : int count = nunits.to_constant ();
9054 : 30 : vec_perm_builder sel (count, count, 1);
9055 : 30 : sel.quick_grow (count);
9056 : 382 : for (int i = 0; i < count; ++i)
9057 : 352 : sel[i] = i | (count / 2);
9058 : 30 : vec_perm_indices indices (sel, 2, count);
9059 : 30 : tree perm_mask
9060 : 30 : = vect_gen_perm_mask_checked (vectype, indices);
9061 : 30 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
9062 : : vec_oprnd, vec_oprnd,
9063 : : perm_mask);
9064 : 30 : vec_oprnd = make_ssa_name (vectype);
9065 : 30 : gimple_set_lhs (new_stmt, vec_oprnd);
9066 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
9067 : : new_stmt, gsi);
9068 : 30 : if (final_mask)
9069 : : {
9070 : 20 : new_stmt = gimple_build_assign (NULL_TREE,
9071 : : VEC_UNPACK_HI_EXPR,
9072 : : final_mask);
9073 : 20 : final_mask = make_ssa_name
9074 : 20 : (truth_type_for (offset_vectype));
9075 : 20 : gimple_set_lhs (new_stmt, final_mask);
9076 : 20 : vect_finish_stmt_generation (vinfo, stmt_info,
9077 : : new_stmt, gsi);
9078 : : }
9079 : :
9080 : 30 : new_stmt = vect_build_one_scatter_store_call
9081 : 60 : (vinfo, stmt_info, slp_node, gsi, ls.gs.decl,
9082 : 30 : dataref_ptr, vec_offsets[2 * j + 1],
9083 : : vec_oprnd, final_mask);
9084 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
9085 : : new_stmt, gsi);
9086 : 30 : }
9087 : 46 : else if (known_eq (nunits * 2, offset_nunits))
9088 : : {
9089 : : /* We have a offset vector with double the number of
9090 : : lanes. Select the low/high part accordingly. */
9091 : 46 : vec_offset = vec_offsets[j / 2];
9092 : 46 : if (j & 1)
9093 : : {
9094 : 23 : int count = offset_nunits.to_constant ();
9095 : 23 : vec_perm_builder sel (count, count, 1);
9096 : 23 : sel.quick_grow (count);
9097 : 263 : for (int i = 0; i < count; ++i)
9098 : 240 : sel[i] = i | (count / 2);
9099 : 23 : vec_perm_indices indices (sel, 2, count);
9100 : 23 : tree perm_mask = vect_gen_perm_mask_checked
9101 : 23 : (TREE_TYPE (vec_offset), indices);
9102 : 23 : new_stmt = gimple_build_assign (NULL_TREE,
9103 : : VEC_PERM_EXPR,
9104 : : vec_offset,
9105 : : vec_offset,
9106 : : perm_mask);
9107 : 23 : vec_offset = make_ssa_name (TREE_TYPE (vec_offset));
9108 : 23 : gimple_set_lhs (new_stmt, vec_offset);
9109 : 23 : vect_finish_stmt_generation (vinfo, stmt_info,
9110 : : new_stmt, gsi);
9111 : 23 : }
9112 : :
9113 : 46 : new_stmt = vect_build_one_scatter_store_call
9114 : 46 : (vinfo, stmt_info, slp_node, gsi,
9115 : : ls.gs.decl, dataref_ptr, vec_offset,
9116 : : vec_oprnd, final_mask);
9117 : 46 : vect_finish_stmt_generation (vinfo, stmt_info,
9118 : : new_stmt, gsi);
9119 : : }
9120 : : else
9121 : 0 : gcc_unreachable ();
9122 : : }
9123 : : else
9124 : : {
9125 : : /* Emulated scatter. */
9126 : 1439 : gcc_assert (!final_mask);
9127 : 1439 : if (costing_p)
9128 : : {
9129 : 1066 : unsigned int cnunits = vect_nunits_for_cost (vectype);
9130 : : /* For emulated scatter N offset vector element extracts
9131 : : (we assume the scalar scaling and ptr + offset add is
9132 : : consumed by the load). */
9133 : 1066 : inside_cost
9134 : 1066 : += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
9135 : : slp_node, 0, vect_body);
9136 : : /* N scalar stores plus extracting the elements. */
9137 : 1066 : inside_cost
9138 : 1066 : += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
9139 : : slp_node, 0, vect_body);
9140 : 1066 : inside_cost
9141 : 1066 : += record_stmt_cost (cost_vec, cnunits, scalar_store,
9142 : : slp_node, 0, vect_body);
9143 : 1066 : continue;
9144 : 1066 : }
9145 : :
9146 : 373 : tree offset_vectype = TREE_TYPE (vec_offsets[0]);
9147 : 373 : unsigned HOST_WIDE_INT const_nunits = nunits.to_constant ();
9148 : 373 : unsigned HOST_WIDE_INT const_offset_nunits
9149 : 373 : = TYPE_VECTOR_SUBPARTS (offset_vectype).to_constant ();
9150 : 373 : vec<constructor_elt, va_gc> *ctor_elts;
9151 : 373 : vec_alloc (ctor_elts, const_nunits);
9152 : 373 : gimple_seq stmts = NULL;
9153 : 373 : tree elt_type = TREE_TYPE (vectype);
9154 : 373 : unsigned HOST_WIDE_INT elt_size
9155 : 373 : = tree_to_uhwi (TYPE_SIZE (elt_type));
9156 : : /* We support offset vectors with more elements
9157 : : than the data vector for now. */
9158 : 373 : unsigned HOST_WIDE_INT factor
9159 : : = const_offset_nunits / const_nunits;
9160 : 373 : vec_offset = vec_offsets[j / factor];
9161 : 373 : unsigned elt_offset
9162 : 373 : = (j % factor) * const_nunits;
9163 : 373 : tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset));
9164 : 373 : tree scale = size_int (SLP_TREE_GS_SCALE (slp_node));
9165 : 373 : tree ltype = build_aligned_type (TREE_TYPE (vectype), align);
9166 : 1519 : for (unsigned k = 0; k < const_nunits; ++k)
9167 : : {
9168 : : /* Compute the offsetted pointer. */
9169 : 1146 : tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type),
9170 : : bitsize_int (k + elt_offset));
9171 : 1146 : tree idx
9172 : 2292 : = gimple_build (&stmts, BIT_FIELD_REF, idx_type,
9173 : 1146 : vec_offset, TYPE_SIZE (idx_type), boff);
9174 : 1146 : idx = gimple_convert (&stmts, sizetype, idx);
9175 : 1146 : idx = gimple_build (&stmts, MULT_EXPR, sizetype,
9176 : : idx, scale);
9177 : 1146 : tree ptr
9178 : 1146 : = gimple_build (&stmts, PLUS_EXPR,
9179 : 1146 : TREE_TYPE (dataref_ptr),
9180 : : dataref_ptr, idx);
9181 : 1146 : ptr = gimple_convert (&stmts, ptr_type_node, ptr);
9182 : : /* Extract the element to be stored. */
9183 : 1146 : tree elt
9184 : 2292 : = gimple_build (&stmts, BIT_FIELD_REF,
9185 : 1146 : TREE_TYPE (vectype),
9186 : 1146 : vec_oprnd, TYPE_SIZE (elt_type),
9187 : 1146 : bitsize_int (k * elt_size));
9188 : 1146 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
9189 : 1146 : stmts = NULL;
9190 : 1146 : tree ref
9191 : 1146 : = build2 (MEM_REF, ltype, ptr,
9192 : : build_int_cst (ref_type, 0));
9193 : 1146 : new_stmt = gimple_build_assign (ref, elt);
9194 : 1146 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
9195 : : }
9196 : :
9197 : 373 : slp_node->push_vec_def (new_stmt);
9198 : : }
9199 : : }
9200 : :
9201 : 1353 : if (costing_p && dump_enabled_p ())
9202 : 68 : dump_printf_loc (MSG_NOTE, vect_location,
9203 : : "vect_model_store_cost: inside_cost = %d, "
9204 : : "prologue_cost = %d .\n",
9205 : : inside_cost, prologue_cost);
9206 : :
9207 : 1353 : return true;
9208 : 1353 : }
9209 : :
9210 : 1292153 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS
9211 : : || memory_access_type == VMAT_CONTIGUOUS_DOWN
9212 : : || memory_access_type == VMAT_CONTIGUOUS_REVERSE);
9213 : :
9214 : 1292153 : unsigned inside_cost = 0, prologue_cost = 0;
9215 : : /* For costing some adjacent vector stores, we'd like to cost with
9216 : : the total number of them once instead of cost each one by one. */
9217 : 1292153 : unsigned int n_adjacent_stores = 0;
9218 : 1292153 : auto_vec<tree> result_chain (group_size);
9219 : 1292153 : auto_vec<tree, 1> vec_oprnds;
9220 : 1292153 : gimple *new_stmt;
9221 : 1292153 : if (!costing_p)
9222 : : {
9223 : : /* Get vectorized arguments for SLP_NODE. */
9224 : 539649 : vect_get_slp_defs (op_node, &vec_oprnds);
9225 : 539649 : vec_oprnd = vec_oprnds[0];
9226 : 539649 : if (mask_node)
9227 : : {
9228 : 470 : vect_get_slp_defs (mask_node, &vec_masks);
9229 : 470 : vec_mask = vec_masks[0];
9230 : : }
9231 : : }
9232 : :
9233 : : /* We should have catched mismatched types earlier. */
9234 : 539649 : gcc_assert (costing_p
9235 : : || useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd)));
9236 : 1292153 : bool simd_lane_access_p
9237 : 1292153 : = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0;
9238 : 1292153 : if (!costing_p
9239 : 1292153 : && simd_lane_access_p
9240 : 4374 : && !loop_masks
9241 : 4374 : && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR
9242 : 4374 : && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0))
9243 : 4374 : && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info))
9244 : 4374 : && integer_zerop (DR_INIT (first_dr_info->dr))
9245 : 1296527 : && alias_sets_conflict_p (get_alias_set (aggr_type),
9246 : 4374 : get_alias_set (TREE_TYPE (ref_type))))
9247 : : {
9248 : 4366 : dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr));
9249 : 4366 : dataref_offset = build_int_cst (ref_type, 0);
9250 : : }
9251 : 1287787 : else if (!costing_p)
9252 : 1070558 : dataref_ptr = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
9253 : : simd_lane_access_p ? loop : NULL,
9254 : : offset, &dummy, gsi, &ptr_incr,
9255 : : simd_lane_access_p, bump);
9256 : :
9257 : 1292153 : new_stmt = NULL;
9258 : 1292153 : gcc_assert (!grouped_store);
9259 : 2871351 : for (i = 0; i < vec_num; i++)
9260 : : {
9261 : 1579198 : if (!costing_p)
9262 : 667605 : vec_oprnd = vec_oprnds[i];
9263 : :
9264 : 1579198 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
9265 : : {
9266 : 3142 : if (costing_p)
9267 : 2015 : inside_cost += record_stmt_cost (cost_vec, 1, vec_perm,
9268 : : slp_node, 0, vect_body);
9269 : : else
9270 : : {
9271 : 1127 : tree perm_mask = perm_mask_for_reverse (vectype);
9272 : 1127 : tree new_temp = make_ssa_name (vectype);
9273 : :
9274 : : /* Generate the permute statement. */
9275 : 1127 : gimple *perm_stmt
9276 : 1127 : = gimple_build_assign (new_temp, VEC_PERM_EXPR, vec_oprnd,
9277 : : vec_oprnd, perm_mask);
9278 : 1127 : vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
9279 : :
9280 : 1127 : perm_stmt = SSA_NAME_DEF_STMT (new_temp);
9281 : 1579198 : vec_oprnd = new_temp;
9282 : : }
9283 : : }
9284 : :
9285 : 1579198 : if (costing_p)
9286 : : {
9287 : 911593 : n_adjacent_stores++;
9288 : 911593 : continue;
9289 : : }
9290 : :
9291 : 667605 : tree final_mask = NULL_TREE;
9292 : 667605 : tree final_len = NULL_TREE;
9293 : 667605 : tree bias = NULL_TREE;
9294 : 667605 : if (loop_masks)
9295 : 77 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
9296 : : vec_num, vectype, i);
9297 : 667605 : if (vec_mask)
9298 : 651 : vec_mask = vec_masks[i];
9299 : 651 : if (vec_mask)
9300 : 651 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
9301 : : vec_mask, gsi);
9302 : :
9303 : 667605 : if (i > 0)
9304 : : /* Bump the vector pointer. */
9305 : 127956 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
9306 : : stmt_info, bump);
9307 : :
9308 : 667605 : unsigned misalign;
9309 : 667605 : unsigned HOST_WIDE_INT align;
9310 : 667605 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
9311 : 667605 : if (alignment_support_scheme == dr_aligned)
9312 : : misalign = 0;
9313 : 308196 : else if (misalignment == DR_MISALIGNMENT_UNKNOWN)
9314 : : {
9315 : 158186 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
9316 : 158186 : misalign = 0;
9317 : : }
9318 : : else
9319 : 150010 : misalign = misalignment;
9320 : 667605 : if (dataref_offset == NULL_TREE
9321 : 662225 : && TREE_CODE (dataref_ptr) == SSA_NAME)
9322 : 175610 : set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, misalign);
9323 : 667605 : align = least_bit_hwi (misalign | align);
9324 : :
9325 : : /* Compute IFN when LOOP_LENS or final_mask valid. */
9326 : 667605 : machine_mode vmode = TYPE_MODE (vectype);
9327 : 667605 : machine_mode new_vmode = vmode;
9328 : 667605 : internal_fn partial_ifn = IFN_LAST;
9329 : 667605 : if (loop_lens)
9330 : : {
9331 : 0 : opt_machine_mode new_ovmode
9332 : 0 : = get_len_load_store_mode (vmode, false, &partial_ifn);
9333 : 0 : new_vmode = new_ovmode.require ();
9334 : 0 : unsigned factor
9335 : 0 : = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode);
9336 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
9337 : : vec_num, vectype, i, factor);
9338 : : }
9339 : 667605 : else if (final_mask)
9340 : : {
9341 : 663 : if (!can_vec_mask_load_store_p (vmode,
9342 : 663 : TYPE_MODE (TREE_TYPE (final_mask)),
9343 : : false, &partial_ifn))
9344 : 0 : gcc_unreachable ();
9345 : : }
9346 : :
9347 : 667605 : if (partial_ifn == IFN_MASK_LEN_STORE)
9348 : : {
9349 : 0 : if (!final_len)
9350 : : {
9351 : : /* Pass VF value to 'len' argument of
9352 : : MASK_LEN_STORE if LOOP_LENS is invalid. */
9353 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
9354 : : }
9355 : 0 : if (!final_mask)
9356 : : {
9357 : : /* Pass all ones value to 'mask' argument of
9358 : : MASK_LEN_STORE if final_mask is invalid. */
9359 : 0 : mask_vectype = truth_type_for (vectype);
9360 : 0 : final_mask = build_minus_one_cst (mask_vectype);
9361 : : }
9362 : : }
9363 : 667605 : if (final_len)
9364 : : {
9365 : 0 : signed char biasval = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
9366 : 0 : bias = build_int_cst (intQI_type_node, biasval);
9367 : : }
9368 : :
9369 : : /* Arguments are ready. Create the new vector stmt. */
9370 : 667605 : if (final_len)
9371 : : {
9372 : 0 : gcall *call;
9373 : 0 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
9374 : : /* Need conversion if it's wrapped with VnQI. */
9375 : 0 : if (vmode != new_vmode)
9376 : : {
9377 : 0 : tree new_vtype
9378 : 0 : = build_vector_type_for_mode (unsigned_intQI_type_node,
9379 : : new_vmode);
9380 : 0 : tree var = vect_get_new_ssa_name (new_vtype, vect_simple_var);
9381 : 0 : vec_oprnd = build1 (VIEW_CONVERT_EXPR, new_vtype, vec_oprnd);
9382 : 0 : gassign *new_stmt
9383 : 0 : = gimple_build_assign (var, VIEW_CONVERT_EXPR, vec_oprnd);
9384 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
9385 : 0 : vec_oprnd = var;
9386 : : }
9387 : :
9388 : 0 : if (partial_ifn == IFN_MASK_LEN_STORE)
9389 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_STORE, 6,
9390 : : dataref_ptr, ptr, final_mask,
9391 : : final_len, bias, vec_oprnd);
9392 : : else
9393 : 0 : call = gimple_build_call_internal (IFN_LEN_STORE, 5,
9394 : : dataref_ptr, ptr, final_len,
9395 : : bias, vec_oprnd);
9396 : 0 : gimple_call_set_nothrow (call, true);
9397 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9398 : 0 : new_stmt = call;
9399 : : }
9400 : 667605 : else if (final_mask)
9401 : : {
9402 : 663 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
9403 : 663 : gcall *call
9404 : 663 : = gimple_build_call_internal (IFN_MASK_STORE, 4, dataref_ptr,
9405 : : ptr, final_mask, vec_oprnd);
9406 : 663 : gimple_call_set_nothrow (call, true);
9407 : 663 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
9408 : 663 : new_stmt = call;
9409 : : }
9410 : : else
9411 : : {
9412 : 666942 : data_ref = fold_build2 (MEM_REF, vectype, dataref_ptr,
9413 : : dataref_offset ? dataref_offset
9414 : : : build_int_cst (ref_type, 0));
9415 : 666942 : if (alignment_support_scheme == dr_aligned
9416 : 666942 : && align >= TYPE_ALIGN_UNIT (vectype))
9417 : : ;
9418 : : else
9419 : 307703 : TREE_TYPE (data_ref)
9420 : 615406 : = build_aligned_type (TREE_TYPE (data_ref),
9421 : : align * BITS_PER_UNIT);
9422 : 666942 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
9423 : 666942 : new_stmt = gimple_build_assign (data_ref, vec_oprnd);
9424 : 666942 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
9425 : : }
9426 : : }
9427 : :
9428 : 1292153 : if (costing_p)
9429 : : {
9430 : 752504 : if (n_adjacent_stores > 0)
9431 : 752504 : vect_get_store_cost (vinfo, stmt_info, slp_node, n_adjacent_stores,
9432 : : alignment_support_scheme, misalignment,
9433 : : &inside_cost, cost_vec);
9434 : :
9435 : : /* When vectorizing a store into the function result assign
9436 : : a penalty if the function returns in a multi-register location.
9437 : : In this case we assume we'll end up with having to spill the
9438 : : vector result and do piecewise loads as a conservative estimate. */
9439 : 752504 : tree base = get_base_address (STMT_VINFO_DATA_REF (stmt_info)->ref);
9440 : 752504 : if (base
9441 : 752504 : && (TREE_CODE (base) == RESULT_DECL
9442 : 701984 : || (DECL_P (base) && cfun_returns (base)))
9443 : 814892 : && !aggregate_value_p (base, cfun->decl))
9444 : : {
9445 : 11285 : rtx reg = hard_function_value (TREE_TYPE (base), cfun->decl, 0, 1);
9446 : : /* ??? Handle PARALLEL in some way. */
9447 : 11285 : if (REG_P (reg))
9448 : : {
9449 : 11086 : int nregs = hard_regno_nregs (REGNO (reg), GET_MODE (reg));
9450 : : /* Assume that a single reg-reg move is possible and cheap,
9451 : : do not account for vector to gp register move cost. */
9452 : 11086 : if (nregs > 1)
9453 : : {
9454 : : /* Spill. */
9455 : 10214 : prologue_cost
9456 : 10214 : += record_stmt_cost (cost_vec, 1, vector_store,
9457 : : slp_node, 0, vect_epilogue);
9458 : : /* Loads. */
9459 : 10214 : prologue_cost
9460 : 10214 : += record_stmt_cost (cost_vec, nregs, scalar_load,
9461 : : slp_node, 0, vect_epilogue);
9462 : : }
9463 : : }
9464 : : }
9465 : 752504 : if (dump_enabled_p ())
9466 : 13083 : dump_printf_loc (MSG_NOTE, vect_location,
9467 : : "vect_model_store_cost: inside_cost = %d, "
9468 : : "prologue_cost = %d .\n",
9469 : : inside_cost, prologue_cost);
9470 : : }
9471 : :
9472 : 1292153 : return true;
9473 : 2617308 : }
9474 : :
9475 : : /* Given a vector type VECTYPE, turns permutation SEL into the equivalent
9476 : : VECTOR_CST mask. No checks are made that the target platform supports the
9477 : : mask, so callers may wish to test can_vec_perm_const_p separately, or use
9478 : : vect_gen_perm_mask_checked. */
9479 : :
9480 : : tree
9481 : 58669 : vect_gen_perm_mask_any (tree vectype, const vec_perm_indices &sel)
9482 : : {
9483 : 58669 : tree mask_type;
9484 : :
9485 : 58669 : poly_uint64 nunits = sel.length ();
9486 : 58669 : gcc_assert (known_eq (nunits, TYPE_VECTOR_SUBPARTS (vectype)));
9487 : :
9488 : 58669 : mask_type = build_vector_type (ssizetype, nunits);
9489 : 58669 : return vec_perm_indices_to_tree (mask_type, sel);
9490 : : }
9491 : :
9492 : : /* Checked version of vect_gen_perm_mask_any. Asserts can_vec_perm_const_p,
9493 : : i.e. that the target supports the pattern _for arbitrary input vectors_. */
9494 : :
9495 : : tree
9496 : 55949 : vect_gen_perm_mask_checked (tree vectype, const vec_perm_indices &sel)
9497 : : {
9498 : 55949 : machine_mode vmode = TYPE_MODE (vectype);
9499 : 55949 : gcc_assert (can_vec_perm_const_p (vmode, vmode, sel));
9500 : 55949 : return vect_gen_perm_mask_any (vectype, sel);
9501 : : }
9502 : :
9503 : : /* Given a vector variable X and Y, that was generated for the scalar
9504 : : STMT_INFO, generate instructions to permute the vector elements of X and Y
9505 : : using permutation mask MASK_VEC, insert them at *GSI and return the
9506 : : permuted vector variable. */
9507 : :
9508 : : static tree
9509 : 1413 : permute_vec_elements (vec_info *vinfo,
9510 : : tree x, tree y, tree mask_vec, stmt_vec_info stmt_info,
9511 : : gimple_stmt_iterator *gsi)
9512 : : {
9513 : 1413 : tree vectype = TREE_TYPE (x);
9514 : 1413 : tree perm_dest, data_ref;
9515 : 1413 : gimple *perm_stmt;
9516 : :
9517 : 1413 : tree scalar_dest = gimple_get_lhs (stmt_info->stmt);
9518 : 1413 : if (scalar_dest && TREE_CODE (scalar_dest) == SSA_NAME)
9519 : 1413 : perm_dest = vect_create_destination_var (scalar_dest, vectype);
9520 : : else
9521 : 0 : perm_dest = vect_get_new_vect_var (vectype, vect_simple_var, NULL);
9522 : 1413 : data_ref = make_ssa_name (perm_dest);
9523 : :
9524 : : /* Generate the permute statement. */
9525 : 1413 : perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, x, y, mask_vec);
9526 : 1413 : vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
9527 : :
9528 : 1413 : return data_ref;
9529 : : }
9530 : :
9531 : : /* Hoist the definitions of all SSA uses on STMT_INFO out of the loop LOOP,
9532 : : inserting them on the loops preheader edge. Returns true if we
9533 : : were successful in doing so (and thus STMT_INFO can be moved then),
9534 : : otherwise returns false. HOIST_P indicates if we want to hoist the
9535 : : definitions of all SSA uses, it would be false when we are costing. */
9536 : :
9537 : : static bool
9538 : 3342 : hoist_defs_of_uses (gimple *stmt, class loop *loop, bool hoist_p)
9539 : : {
9540 : 3342 : ssa_op_iter i;
9541 : 3342 : use_operand_p use_p;
9542 : 3342 : auto_vec<use_operand_p, 8> to_hoist;
9543 : :
9544 : 6315 : FOR_EACH_SSA_USE_OPERAND (use_p, stmt, i, SSA_OP_USE)
9545 : : {
9546 : 2981 : gimple *def_stmt = SSA_NAME_DEF_STMT (USE_FROM_PTR (use_p));
9547 : 2981 : if (!gimple_nop_p (def_stmt)
9548 : 2981 : && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)))
9549 : : {
9550 : : /* Make sure we don't need to recurse. While we could do
9551 : : so in simple cases when there are more complex use webs
9552 : : we don't have an easy way to preserve stmt order to fulfil
9553 : : dependencies within them. */
9554 : 43 : tree op2;
9555 : 43 : ssa_op_iter i2;
9556 : 43 : if (gimple_code (def_stmt) == GIMPLE_PHI
9557 : 43 : || (single_ssa_def_operand (def_stmt, SSA_OP_DEF)
9558 : : == NULL_DEF_OPERAND_P))
9559 : 8 : return false;
9560 : 86 : FOR_EACH_SSA_TREE_OPERAND (op2, def_stmt, i2, SSA_OP_USE)
9561 : : {
9562 : 51 : gimple *def_stmt2 = SSA_NAME_DEF_STMT (op2);
9563 : 51 : if (!gimple_nop_p (def_stmt2)
9564 : 51 : && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt2)))
9565 : : return false;
9566 : : }
9567 : 35 : to_hoist.safe_push (use_p);
9568 : : }
9569 : : }
9570 : :
9571 : 6668 : if (to_hoist.is_empty ())
9572 : : return true;
9573 : :
9574 : 35 : if (!hoist_p)
9575 : : return true;
9576 : :
9577 : : /* Instead of moving defs we copy them so we can zero their UID to not
9578 : : confuse dominance queries in the preheader. */
9579 : 9 : gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
9580 : 36 : for (use_operand_p use_p : to_hoist)
9581 : : {
9582 : 9 : gimple *def_stmt = SSA_NAME_DEF_STMT (USE_FROM_PTR (use_p));
9583 : 9 : gimple *copy = gimple_copy (def_stmt);
9584 : 9 : gimple_set_uid (copy, 0);
9585 : 9 : def_operand_p def_p = single_ssa_def_operand (def_stmt, SSA_OP_DEF);
9586 : 9 : tree new_def = duplicate_ssa_name (DEF_FROM_PTR (def_p), copy);
9587 : 9 : update_stmt (copy);
9588 : 9 : def_p = single_ssa_def_operand (copy, SSA_OP_DEF);
9589 : 9 : SET_DEF (def_p, new_def);
9590 : 9 : SET_USE (use_p, new_def);
9591 : 9 : gsi_insert_before (&gsi, copy, GSI_SAME_STMT);
9592 : : }
9593 : :
9594 : : return true;
9595 : 3342 : }
9596 : :
9597 : : /* vectorizable_load.
9598 : :
9599 : : Check if STMT_INFO reads a non scalar data-ref (array/pointer/structure)
9600 : : that can be vectorized.
9601 : : If COST_VEC is passed, calculate costs but don't change anything,
9602 : : otherwise, vectorize STMT_INFO: create a vectorized stmt to replace
9603 : : it, and insert it at GSI.
9604 : : Return true if STMT_INFO is vectorizable in this way. */
9605 : :
9606 : : static bool
9607 : 1931370 : vectorizable_load (vec_info *vinfo,
9608 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
9609 : : slp_tree slp_node,
9610 : : stmt_vector_for_cost *cost_vec)
9611 : : {
9612 : 1931370 : tree scalar_dest;
9613 : 1931370 : tree vec_dest = NULL;
9614 : 1931370 : tree data_ref = NULL;
9615 : 1931370 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
9616 : 1931370 : class loop *loop = NULL;
9617 : 1931370 : class loop *containing_loop = gimple_bb (stmt_info->stmt)->loop_father;
9618 : 1931370 : bool nested_in_vect_loop = false;
9619 : 1931370 : tree elem_type;
9620 : : /* Avoid false positive uninitialized warning, see PR110652. */
9621 : 1931370 : tree new_temp = NULL_TREE;
9622 : 1931370 : machine_mode mode;
9623 : 1931370 : tree dummy;
9624 : 1931370 : tree dataref_ptr = NULL_TREE;
9625 : 1931370 : tree dataref_offset = NULL_TREE;
9626 : 1931370 : gimple *ptr_incr = NULL;
9627 : 1931370 : int i, j;
9628 : 1931370 : unsigned int group_size;
9629 : 1931370 : poly_uint64 group_gap_adj;
9630 : 1931370 : tree msq = NULL_TREE, lsq;
9631 : 1931370 : tree realignment_token = NULL_TREE;
9632 : 1931370 : gphi *phi = NULL;
9633 : 1931370 : bool grouped_load = false;
9634 : 1931370 : stmt_vec_info first_stmt_info;
9635 : 1931370 : stmt_vec_info first_stmt_info_for_drptr = NULL;
9636 : 1931370 : bool compute_in_loop = false;
9637 : 1931370 : class loop *at_loop;
9638 : 1931370 : int vec_num;
9639 : 1931370 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
9640 : 1931370 : poly_uint64 vf;
9641 : 1931370 : tree aggr_type;
9642 : 1931370 : tree ref_type;
9643 : 1931370 : enum vect_def_type mask_dt = vect_unknown_def_type;
9644 : 1931370 : enum vect_def_type els_dt = vect_unknown_def_type;
9645 : :
9646 : 1931370 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
9647 : : return false;
9648 : :
9649 : 1931370 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
9650 : 176586 : && cost_vec)
9651 : : return false;
9652 : :
9653 : 1754784 : if (!STMT_VINFO_DATA_REF (stmt_info))
9654 : : return false;
9655 : :
9656 : 1411800 : tree mask_vectype = NULL_TREE;
9657 : 1411800 : tree els = NULL_TREE; tree els_vectype = NULL_TREE;
9658 : :
9659 : 1411800 : int mask_index = -1;
9660 : 1411800 : int els_index = -1;
9661 : 1411800 : slp_tree mask_node = NULL;
9662 : 1411800 : slp_tree els_op = NULL;
9663 : 1411800 : if (gassign *assign = dyn_cast <gassign *> (stmt_info->stmt))
9664 : : {
9665 : 1408515 : scalar_dest = gimple_assign_lhs (assign);
9666 : 1408515 : if (TREE_CODE (scalar_dest) != SSA_NAME)
9667 : : return false;
9668 : :
9669 : 628119 : tree_code code = gimple_assign_rhs_code (assign);
9670 : 628119 : if (code != ARRAY_REF
9671 : 628119 : && code != BIT_FIELD_REF
9672 : 628119 : && code != INDIRECT_REF
9673 : 427672 : && code != COMPONENT_REF
9674 : 427672 : && code != IMAGPART_EXPR
9675 : 291177 : && code != REALPART_EXPR
9676 : 291177 : && code != MEM_REF
9677 : 199 : && TREE_CODE_CLASS (code) != tcc_declaration)
9678 : : return false;
9679 : : }
9680 : : else
9681 : : {
9682 : 1304536 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
9683 : 3285 : if (!call || !gimple_call_internal_p (call))
9684 : : return false;
9685 : :
9686 : 3285 : internal_fn ifn = gimple_call_internal_fn (call);
9687 : 3285 : if (!internal_load_fn_p (ifn))
9688 : : return false;
9689 : :
9690 : 2377 : scalar_dest = gimple_call_lhs (call);
9691 : 2377 : if (!scalar_dest)
9692 : : return false;
9693 : :
9694 : 2377 : mask_index = internal_fn_mask_index (ifn);
9695 : 2377 : if (mask_index >= 0)
9696 : 2377 : mask_index = vect_slp_child_index_for_operand
9697 : 2377 : (call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
9698 : 2377 : if (mask_index >= 0
9699 : 2377 : && !vect_check_scalar_mask (vinfo, slp_node, mask_index,
9700 : : &mask_node, &mask_dt, &mask_vectype))
9701 : : return false;
9702 : :
9703 : 2377 : els_index = internal_fn_else_index (ifn);
9704 : 2377 : if (els_index >= 0)
9705 : 2377 : els_index = vect_slp_child_index_for_operand
9706 : 2377 : (call, els_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
9707 : 2377 : if (els_index >= 0
9708 : 2377 : && !vect_is_simple_use (vinfo, slp_node, els_index,
9709 : : &els, &els_op, &els_dt, &els_vectype))
9710 : : return false;
9711 : : }
9712 : :
9713 : 630429 : tree vectype = SLP_TREE_VECTYPE (slp_node);
9714 : 630429 : poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
9715 : :
9716 : 630429 : if (loop_vinfo)
9717 : : {
9718 : 419973 : loop = LOOP_VINFO_LOOP (loop_vinfo);
9719 : 419973 : nested_in_vect_loop = nested_in_vect_loop_p (loop, stmt_info);
9720 : 419973 : vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
9721 : : }
9722 : : else
9723 : : vf = 1;
9724 : :
9725 : 630429 : vec_num = vect_get_num_copies (vinfo, slp_node);
9726 : :
9727 : : /* FORNOW. This restriction should be relaxed. */
9728 : 630429 : if (nested_in_vect_loop && vec_num > 1)
9729 : : {
9730 : 298 : if (dump_enabled_p ())
9731 : 66 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9732 : : "multiple types in nested loop.\n");
9733 : 298 : return false;
9734 : : }
9735 : :
9736 : 630131 : elem_type = TREE_TYPE (vectype);
9737 : 630131 : mode = TYPE_MODE (vectype);
9738 : :
9739 : : /* FORNOW. In some cases can vectorize even if data-type not supported
9740 : : (e.g. - data copies). */
9741 : 630131 : if (!can_implement_p (mov_optab, mode))
9742 : : {
9743 : 0 : if (dump_enabled_p ())
9744 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9745 : : "Aligned load, but unsupported type.\n");
9746 : 0 : return false;
9747 : : }
9748 : :
9749 : : /* Check if the load is a part of an interleaving chain. */
9750 : 630131 : if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
9751 : : {
9752 : 297688 : grouped_load = true;
9753 : : /* FORNOW */
9754 : 297688 : gcc_assert (!nested_in_vect_loop);
9755 : 297688 : gcc_assert (!STMT_VINFO_GATHER_SCATTER_P (stmt_info));
9756 : :
9757 : 297688 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
9758 : 297688 : group_size = DR_GROUP_SIZE (first_stmt_info);
9759 : :
9760 : : /* Invalidate assumptions made by dependence analysis when vectorization
9761 : : on the unrolled body effectively re-orders stmts. */
9762 : 297688 : if (STMT_VINFO_MIN_NEG_DIST (stmt_info) != 0
9763 : 297688 : && maybe_gt (LOOP_VINFO_VECT_FACTOR (loop_vinfo),
9764 : : STMT_VINFO_MIN_NEG_DIST (stmt_info)))
9765 : : {
9766 : 12 : if (dump_enabled_p ())
9767 : 12 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9768 : : "cannot perform implicit CSE when performing "
9769 : : "group loads with negative dependence distance\n");
9770 : 12 : return false;
9771 : : }
9772 : : }
9773 : : else
9774 : : group_size = 1;
9775 : :
9776 : 630119 : vect_load_store_data _ls_data{};
9777 : 630119 : vect_load_store_data &ls = slp_node->get_data (_ls_data);
9778 : 630119 : if (cost_vec
9779 : 630119 : && !get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask_node,
9780 : : VLS_LOAD, &ls))
9781 : : return false;
9782 : : /* Temporary aliases to analysis data, should not be modified through
9783 : : these. */
9784 : 535259 : const vect_memory_access_type memory_access_type = ls.memory_access_type;
9785 : 535259 : const dr_alignment_support alignment_support_scheme
9786 : : = ls.alignment_support_scheme;
9787 : 535259 : const int misalignment = ls.misalignment;
9788 : 535259 : const poly_int64 poffset = ls.poffset;
9789 : 535259 : const vec<int> &elsvals = ls.elsvals;
9790 : :
9791 : 535259 : int maskload_elsval = 0;
9792 : 535259 : bool need_zeroing = false;
9793 : :
9794 : : /* We might need to explicitly zero inactive elements if there are
9795 : : padding bits in the type that might leak otherwise.
9796 : : Refer to PR115336. */
9797 : 535259 : tree scalar_type = TREE_TYPE (scalar_dest);
9798 : 535259 : bool type_mode_padding_p
9799 : 1070518 : = TYPE_PRECISION (scalar_type) < GET_MODE_PRECISION (GET_MODE_INNER (mode));
9800 : :
9801 : 535259 : if (slp_node->ldst_lanes
9802 : 0 : && memory_access_type != VMAT_LOAD_STORE_LANES)
9803 : : {
9804 : 0 : if (dump_enabled_p ())
9805 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9806 : : "discovered load-lane but cannot use it.\n");
9807 : 0 : return false;
9808 : : }
9809 : :
9810 : 535259 : if (mask_node)
9811 : : {
9812 : 2259 : if (memory_access_type == VMAT_CONTIGUOUS)
9813 : : {
9814 : 1477 : machine_mode vec_mode = TYPE_MODE (vectype);
9815 : 395 : if (!VECTOR_MODE_P (vec_mode)
9816 : 2954 : || !can_vec_mask_load_store_p (vec_mode,
9817 : 1477 : TYPE_MODE (mask_vectype),
9818 : : true, NULL, &ls.elsvals))
9819 : 67 : return false;
9820 : : }
9821 : 782 : else if (memory_access_type != VMAT_LOAD_STORE_LANES
9822 : 782 : && !mat_gather_scatter_p (memory_access_type))
9823 : : {
9824 : 62 : if (dump_enabled_p ())
9825 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9826 : : "unsupported access type for masked load.\n");
9827 : 62 : return false;
9828 : : }
9829 : 720 : else if (memory_access_type == VMAT_GATHER_SCATTER_EMULATED)
9830 : : {
9831 : 476 : if (dump_enabled_p ())
9832 : 26 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9833 : : "unsupported masked emulated gather.\n");
9834 : 476 : return false;
9835 : : }
9836 : : else if (memory_access_type == VMAT_ELEMENTWISE
9837 : : || memory_access_type == VMAT_STRIDED_SLP)
9838 : : {
9839 : : if (dump_enabled_p ())
9840 : : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9841 : : "unsupported masked strided access.\n");
9842 : : return false;
9843 : : }
9844 : : }
9845 : :
9846 : 534654 : bool costing_p = cost_vec;
9847 : :
9848 : 534654 : if (costing_p) /* transformation not required. */
9849 : : {
9850 : 373912 : if (mask_node
9851 : 373912 : && !vect_maybe_update_slp_op_vectype (mask_node,
9852 : : mask_vectype))
9853 : : {
9854 : 0 : if (dump_enabled_p ())
9855 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9856 : : "incompatible vector types for invariants\n");
9857 : 0 : return false;
9858 : : }
9859 : :
9860 : 373912 : if (loop_vinfo
9861 : 251479 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
9862 : 172849 : check_load_store_for_partial_vectors (loop_vinfo, vectype, slp_node,
9863 : : VLS_LOAD, group_size, &ls,
9864 : : mask_node, &ls.elsvals);
9865 : :
9866 : 373912 : if (dump_enabled_p ()
9867 : 23960 : && memory_access_type != VMAT_ELEMENTWISE
9868 : 23852 : && !mat_gather_scatter_p (memory_access_type)
9869 : 23630 : && memory_access_type != VMAT_STRIDED_SLP
9870 : 23630 : && memory_access_type != VMAT_INVARIANT
9871 : 396693 : && alignment_support_scheme != dr_aligned)
9872 : 9054 : dump_printf_loc (MSG_NOTE, vect_location,
9873 : : "Vectorizing an unaligned access.\n");
9874 : :
9875 : 373912 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
9876 : 0 : vinfo->any_known_not_updated_vssa = true;
9877 : :
9878 : 373912 : SLP_TREE_TYPE (slp_node) = load_vec_info_type;
9879 : 373912 : slp_node->data = new vect_load_store_data (std::move (ls));
9880 : : }
9881 : :
9882 : : /* If the type needs padding we must zero inactive elements.
9883 : : Check if we can do that with a VEC_COND_EXPR and store the
9884 : : elsval we choose in MASKLOAD_ELSVAL. */
9885 : 534654 : if (elsvals.length ()
9886 : 23239 : && type_mode_padding_p
9887 : 3 : && !elsvals.contains (MASK_LOAD_ELSE_ZERO)
9888 : 23239 : && !expand_vec_cond_expr_p (vectype, truth_type_for (vectype)))
9889 : : {
9890 : 0 : if (dump_enabled_p ())
9891 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9892 : : "cannot zero inactive elements.\n");
9893 : 0 : return false;
9894 : : }
9895 : :
9896 : : /* For now just use the first available else value.
9897 : : get_supported_else_vals tries MASK_LOAD_ELSE_ZERO first so we will
9898 : : select it here if it is supported. */
9899 : 534654 : if (elsvals.length ())
9900 : 23239 : maskload_elsval = *elsvals.begin ();
9901 : :
9902 : 534654 : if (dump_enabled_p () && !costing_p)
9903 : 16122 : dump_printf_loc (MSG_NOTE, vect_location, "transform load.\n");
9904 : :
9905 : : /* Transform. */
9906 : :
9907 : 534654 : dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info), *first_dr_info = NULL;
9908 : 534654 : ensure_base_align (dr_info);
9909 : :
9910 : 534654 : if (memory_access_type == VMAT_INVARIANT)
9911 : : {
9912 : 3746 : gcc_assert (!grouped_load && !mask_node && !bb_vinfo);
9913 : : /* If we have versioned for aliasing or the loop doesn't
9914 : : have any data dependencies that would preclude this,
9915 : : then we are sure this is a loop invariant load and
9916 : : thus we can insert it on the preheader edge.
9917 : : TODO: hoist_defs_of_uses should ideally be computed
9918 : : once at analysis time, remembered and used in the
9919 : : transform time. */
9920 : 7492 : bool hoist_p = (LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo)
9921 : 3746 : && !nested_in_vect_loop);
9922 : :
9923 : : /* It is unsafe to hoist a conditional load over the conditions that make
9924 : : it valid. When early break this means that any invariant load can't be
9925 : : hoisted unless it's in the loop header or if we know something else has
9926 : : verified the load is valid to do. Alignment peeling would do this
9927 : : since getting through the prologue means the load was done at least
9928 : : once and so the vector main body is free to hoist it. However today
9929 : : GCC will hoist the load above the PFA loop. As such that makes it
9930 : : still invalid and so we can't allow it today. */
9931 : 3746 : auto stmt_bb
9932 : 3746 : = gimple_bb (STMT_VINFO_STMT (
9933 : : vect_orig_stmt (SLP_TREE_SCALAR_STMTS (slp_node)[0])));
9934 : 3746 : if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo)
9935 : 1076 : && !DR_SCALAR_KNOWN_BOUNDS (dr_info)
9936 : 1076 : && stmt_bb != loop->header)
9937 : : {
9938 : 1044 : if (LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo)
9939 : 1044 : && dump_enabled_p ())
9940 : 6 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9941 : : "not hoisting invariant load due to early break"
9942 : : "constraints\n");
9943 : 1038 : else if (dump_enabled_p ())
9944 : 16 : dump_printf_loc (MSG_NOTE, vect_location,
9945 : : "not hoisting invariant load due to early break"
9946 : : "constraints\n");
9947 : : hoist_p = false;
9948 : : }
9949 : :
9950 : 3746 : bool uniform_p = true;
9951 : 15568 : for (stmt_vec_info sinfo : SLP_TREE_SCALAR_STMTS (slp_node))
9952 : : {
9953 : 4330 : hoist_p = hoist_p && hoist_defs_of_uses (sinfo->stmt, loop, false);
9954 : 4330 : if (sinfo != SLP_TREE_SCALAR_STMTS (slp_node)[0])
9955 : 155 : uniform_p = false;
9956 : : }
9957 : 3746 : if (costing_p)
9958 : : {
9959 : 2941 : if (!uniform_p && (!hoist_p || !vf.is_constant ()))
9960 : : {
9961 : 0 : if (dump_enabled_p ())
9962 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
9963 : : "not vectorizing non-uniform invariant "
9964 : : "load\n");
9965 : 0 : return false;
9966 : : }
9967 : 1485 : enum vect_cost_model_location cost_loc
9968 : 2941 : = hoist_p ? vect_prologue : vect_body;
9969 : 2941 : unsigned int cost = record_stmt_cost (cost_vec, 1, scalar_load,
9970 : : slp_node, 0, cost_loc);
9971 : 2941 : cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
9972 : : slp_node, 0, cost_loc);
9973 : 2941 : unsigned int prologue_cost = hoist_p ? cost : 0;
9974 : 1485 : unsigned int inside_cost = hoist_p ? 0 : cost;
9975 : 2941 : if (dump_enabled_p ())
9976 : 458 : dump_printf_loc (MSG_NOTE, vect_location,
9977 : : "vect_model_load_cost: inside_cost = %d, "
9978 : : "prologue_cost = %d .\n",
9979 : : inside_cost, prologue_cost);
9980 : 2941 : return true;
9981 : : }
9982 : 805 : if (hoist_p)
9983 : : {
9984 : : /* ??? For non-uniform lanes there could be still duplicates.
9985 : : We're leaving those to post-vectorizer CSE for the moment. */
9986 : 610 : auto_vec<tree> scalar_defs (SLP_TREE_LANES (slp_node));
9987 : 1931 : for (stmt_vec_info sinfo : SLP_TREE_SCALAR_STMTS (slp_node))
9988 : : {
9989 : 684 : gassign *stmt = as_a <gassign *> (sinfo->stmt);
9990 : 684 : if (dump_enabled_p ())
9991 : 290 : dump_printf_loc (MSG_NOTE, vect_location,
9992 : : "hoisting out of the vectorized loop: %G",
9993 : : (gimple *) stmt);
9994 : 684 : scalar_dest = copy_ssa_name (gimple_assign_lhs (stmt));
9995 : 684 : tree rhs = unshare_expr (gimple_assign_rhs1 (stmt));
9996 : 684 : edge pe = loop_preheader_edge (loop);
9997 : 684 : gphi *vphi = get_virtual_phi (loop->header);
9998 : 684 : tree vuse;
9999 : 684 : if (vphi)
10000 : 678 : vuse = PHI_ARG_DEF_FROM_EDGE (vphi, pe);
10001 : : else
10002 : 6 : vuse = gimple_vuse (gsi_stmt (*gsi));
10003 : 684 : gimple *new_stmt = gimple_build_assign (scalar_dest, rhs);
10004 : 684 : gimple_set_vuse (new_stmt, vuse);
10005 : 684 : gsi_insert_on_edge_immediate (pe, new_stmt);
10006 : 684 : hoist_defs_of_uses (new_stmt, loop, true);
10007 : 684 : if (!useless_type_conversion_p (TREE_TYPE (vectype),
10008 : 684 : TREE_TYPE (scalar_dest)))
10009 : : {
10010 : 10 : tree tem = make_ssa_name (TREE_TYPE (vectype));
10011 : 10 : new_stmt = gimple_build_assign (tem,
10012 : : NOP_EXPR, scalar_dest);
10013 : 10 : gsi_insert_on_edge_immediate (pe, new_stmt);
10014 : 10 : scalar_dest = tem;
10015 : : }
10016 : 684 : scalar_defs.quick_push (scalar_dest);
10017 : 684 : if (uniform_p)
10018 : : break;
10019 : : }
10020 : 610 : if (!uniform_p)
10021 : : {
10022 : 27 : unsigned const_nunits
10023 : 27 : = TYPE_VECTOR_SUBPARTS (vectype).to_constant ();
10024 : 68 : for (j = 0; j < (int) vec_num; ++j)
10025 : : {
10026 : 41 : vec<constructor_elt, va_gc> *v = NULL;
10027 : 41 : vec_safe_reserve (v, const_nunits, true);
10028 : 293 : for (unsigned i = 0; i < const_nunits; ++i)
10029 : : {
10030 : 252 : unsigned def_idx
10031 : 252 : = (j * const_nunits + i) % SLP_TREE_LANES (slp_node);
10032 : 252 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
10033 : : scalar_defs[def_idx]);
10034 : : }
10035 : 41 : scalar_dest = build_constructor (vectype, v);
10036 : 41 : new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest,
10037 : : vectype, NULL);
10038 : 41 : slp_node->push_vec_def (new_temp);
10039 : : }
10040 : 27 : return true;
10041 : : }
10042 : 583 : new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest,
10043 : : vectype, NULL);
10044 : 610 : }
10045 : : else
10046 : : {
10047 : 195 : gcc_assert (uniform_p);
10048 : 195 : gimple_stmt_iterator gsi2 = *gsi;
10049 : 195 : gsi_next (&gsi2);
10050 : 195 : new_temp = vect_init_vector (vinfo, stmt_info, scalar_dest,
10051 : : vectype, &gsi2);
10052 : : }
10053 : 1630 : for (j = 0; j < (int) vec_num; ++j)
10054 : 852 : slp_node->push_vec_def (new_temp);
10055 : : return true;
10056 : : }
10057 : :
10058 : 530908 : if (memory_access_type == VMAT_ELEMENTWISE
10059 : 530908 : || memory_access_type == VMAT_STRIDED_SLP)
10060 : : {
10061 : 27656 : gimple_stmt_iterator incr_gsi;
10062 : 27656 : bool insert_after;
10063 : 27656 : tree offvar = NULL_TREE;
10064 : 27656 : tree ivstep;
10065 : 27656 : tree running_off;
10066 : 27656 : vec<constructor_elt, va_gc> *v = NULL;
10067 : 27656 : tree stride_base, stride_step, alias_off;
10068 : : /* Checked by get_load_store_type. */
10069 : 27656 : unsigned int const_nunits = nunits.to_constant ();
10070 : 27656 : unsigned HOST_WIDE_INT cst_offset = 0;
10071 : 27656 : tree dr_offset;
10072 : 27656 : unsigned int inside_cost = 0;
10073 : :
10074 : 27656 : gcc_assert (!LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo));
10075 : 27656 : gcc_assert (!nested_in_vect_loop);
10076 : :
10077 : 27656 : if (grouped_load)
10078 : : {
10079 : : /* If we elided a consecutive load permutation, don't
10080 : : use the original first statement (which could be elided)
10081 : : but the one the load permutation starts with.
10082 : : This ensures the stride_base below is correct. */
10083 : 15113 : if (!ls.subchain_p)
10084 : 15081 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
10085 : : else
10086 : 32 : first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
10087 : 15113 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
10088 : 15113 : ref_type = get_group_alias_ptr_type (first_stmt_info);
10089 : : }
10090 : : else
10091 : : {
10092 : 12543 : first_stmt_info = stmt_info;
10093 : 12543 : first_dr_info = dr_info;
10094 : 12543 : ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr));
10095 : : }
10096 : :
10097 : 27656 : if (grouped_load)
10098 : : {
10099 : 15113 : if (memory_access_type == VMAT_STRIDED_SLP)
10100 : : {
10101 : : /* If we elided a consecutive load permutation, adjust
10102 : : the group size here. */
10103 : 3685 : if (!ls.subchain_p)
10104 : 3653 : group_size = DR_GROUP_SIZE (first_stmt_info);
10105 : : else
10106 : 32 : group_size = SLP_TREE_LANES (slp_node);
10107 : : }
10108 : : else /* VMAT_ELEMENTWISE */
10109 : 11428 : group_size = SLP_TREE_LANES (slp_node);
10110 : : }
10111 : : else
10112 : : group_size = 1;
10113 : :
10114 : 27656 : if (!costing_p)
10115 : : {
10116 : 3231 : dr_offset = get_dr_vinfo_offset (vinfo, first_dr_info);
10117 : 3231 : stride_base = fold_build_pointer_plus (
10118 : : DR_BASE_ADDRESS (first_dr_info->dr),
10119 : : size_binop (PLUS_EXPR, convert_to_ptrofftype (dr_offset),
10120 : : convert_to_ptrofftype (DR_INIT (first_dr_info->dr))));
10121 : 3231 : stride_step = fold_convert (sizetype, DR_STEP (first_dr_info->dr));
10122 : :
10123 : : /* For a load with loop-invariant (but other than power-of-2)
10124 : : stride (i.e. not a grouped access) like so:
10125 : :
10126 : : for (i = 0; i < n; i += stride)
10127 : : ... = array[i];
10128 : :
10129 : : we generate a new induction variable and new accesses to
10130 : : form a new vector (or vectors, depending on ncopies):
10131 : :
10132 : : for (j = 0; ; j += VF*stride)
10133 : : tmp1 = array[j];
10134 : : tmp2 = array[j + stride];
10135 : : ...
10136 : : vectemp = {tmp1, tmp2, ...}
10137 : : */
10138 : :
10139 : 3231 : ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (stride_step), stride_step,
10140 : : build_int_cst (TREE_TYPE (stride_step), vf));
10141 : :
10142 : 3231 : standard_iv_increment_position (loop, &incr_gsi, &insert_after);
10143 : :
10144 : 3231 : stride_base = cse_and_gimplify_to_preheader (loop_vinfo, stride_base);
10145 : 3231 : ivstep = cse_and_gimplify_to_preheader (loop_vinfo, ivstep);
10146 : 3231 : create_iv (stride_base, PLUS_EXPR, ivstep, NULL,
10147 : : loop, &incr_gsi, insert_after,
10148 : : &offvar, NULL);
10149 : :
10150 : 3231 : stride_step = cse_and_gimplify_to_preheader (loop_vinfo, stride_step);
10151 : : }
10152 : :
10153 : 27656 : running_off = offvar;
10154 : 27656 : alias_off = build_int_cst (ref_type, 0);
10155 : 27656 : int nloads = const_nunits;
10156 : 27656 : int lnel = 1;
10157 : 27656 : tree ltype = TREE_TYPE (vectype);
10158 : 27656 : tree lvectype = vectype;
10159 : 27656 : auto_vec<tree> dr_chain;
10160 : : /* ??? Modify local copies of alignment_support_scheme and
10161 : : misalignment, but this part of analysis should be done
10162 : : earlier and remembered, likewise the chosen load mode. */
10163 : 27656 : const dr_alignment_support tem = alignment_support_scheme;
10164 : 27656 : dr_alignment_support alignment_support_scheme = tem;
10165 : 27656 : const int tem2 = misalignment;
10166 : 27656 : int misalignment = tem2;
10167 : 27656 : if (memory_access_type == VMAT_STRIDED_SLP)
10168 : : {
10169 : 16228 : HOST_WIDE_INT n = gcd (group_size, const_nunits);
10170 : : /* Use the target vector type if the group size is a multiple
10171 : : of it. */
10172 : 16228 : if (n == const_nunits)
10173 : : {
10174 : 1906 : int mis_align = dr_misalignment (first_dr_info, vectype);
10175 : : /* With VF > 1 we advance the DR by step, if that is constant
10176 : : and only aligned when performed VF times, DR alignment
10177 : : analysis can analyze this as aligned since it assumes
10178 : : contiguous accesses. But that is not how we code generate
10179 : : here, so adjust for this. */
10180 : 1906 : if (maybe_gt (vf, 1u)
10181 : 3148 : && !multiple_p (DR_STEP_ALIGNMENT (first_dr_info->dr),
10182 : 2944 : DR_TARGET_ALIGNMENT (first_dr_info)))
10183 : 204 : mis_align = -1;
10184 : 1906 : dr_alignment_support dr_align
10185 : 1906 : = vect_supportable_dr_alignment (vinfo, dr_info, vectype,
10186 : : mis_align);
10187 : 1906 : if (dr_align == dr_aligned
10188 : 1906 : || dr_align == dr_unaligned_supported)
10189 : : {
10190 : 16228 : nloads = 1;
10191 : 16228 : lnel = const_nunits;
10192 : 16228 : ltype = vectype;
10193 : 16228 : alignment_support_scheme = dr_align;
10194 : 16228 : misalignment = mis_align;
10195 : : }
10196 : : }
10197 : : /* Else use the biggest vector we can load the group without
10198 : : accessing excess elements. */
10199 : 14322 : else if (n > 1)
10200 : : {
10201 : 1786 : tree ptype;
10202 : 1786 : tree vtype
10203 : 1786 : = vector_vector_composition_type (vectype, const_nunits / n,
10204 : : &ptype);
10205 : 1786 : if (vtype != NULL_TREE)
10206 : : {
10207 : 1750 : dr_alignment_support dr_align;
10208 : 1750 : int mis_align = 0;
10209 : 1750 : if (VECTOR_TYPE_P (ptype))
10210 : : {
10211 : 904 : mis_align = dr_misalignment (first_dr_info, ptype);
10212 : 904 : if (maybe_gt (vf, 1u)
10213 : 1780 : && !multiple_p (DR_STEP_ALIGNMENT (first_dr_info->dr),
10214 : 910 : DR_TARGET_ALIGNMENT (first_dr_info)))
10215 : 870 : mis_align = -1;
10216 : 904 : dr_align
10217 : 904 : = vect_supportable_dr_alignment (vinfo, dr_info, ptype,
10218 : : mis_align);
10219 : : }
10220 : : else
10221 : : dr_align = dr_unaligned_supported;
10222 : 1750 : if (dr_align == dr_aligned
10223 : 1750 : || dr_align == dr_unaligned_supported)
10224 : : {
10225 : 1750 : nloads = const_nunits / n;
10226 : 1750 : lnel = n;
10227 : 1750 : lvectype = vtype;
10228 : 1750 : ltype = ptype;
10229 : 1750 : alignment_support_scheme = dr_align;
10230 : 1750 : misalignment = mis_align;
10231 : : }
10232 : : }
10233 : : }
10234 : 16228 : unsigned align;
10235 : 16228 : if (alignment_support_scheme == dr_aligned)
10236 : 20 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
10237 : : else
10238 : 16208 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
10239 : : /* Alignment is at most the access size if we do multiple loads. */
10240 : 16228 : if (nloads > 1)
10241 : 14322 : align = MIN (tree_to_uhwi (TYPE_SIZE_UNIT (ltype)), align);
10242 : 16228 : ltype = build_aligned_type (ltype, align * BITS_PER_UNIT);
10243 : : }
10244 : :
10245 : : /* For SLP permutation support we need to load the whole group,
10246 : : not only the number of vector stmts the permutation result
10247 : : fits in. */
10248 : 27656 : int ncopies;
10249 : 27656 : if (ls.slp_perm)
10250 : : {
10251 : 2416 : gcc_assert (memory_access_type != VMAT_ELEMENTWISE);
10252 : : /* We don't yet generate SLP_TREE_LOAD_PERMUTATIONs for
10253 : : variable VF. */
10254 : 2416 : unsigned int const_vf = vf.to_constant ();
10255 : 2416 : ncopies = CEIL (group_size * const_vf, const_nunits);
10256 : 2416 : dr_chain.create (ncopies);
10257 : : }
10258 : : else
10259 : : ncopies = vec_num;
10260 : :
10261 : 27656 : unsigned int group_el = 0;
10262 : 27656 : unsigned HOST_WIDE_INT
10263 : 27656 : elsz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
10264 : 27656 : unsigned int n_groups = 0;
10265 : : /* For costing some adjacent vector loads, we'd like to cost with
10266 : : the total number of them once instead of cost each one by one. */
10267 : 27656 : unsigned int n_adjacent_loads = 0;
10268 : 65487 : for (j = 0; j < ncopies; j++)
10269 : : {
10270 : 37831 : if (nloads > 1 && !costing_p)
10271 : 2793 : vec_alloc (v, nloads);
10272 : : gimple *new_stmt = NULL;
10273 : 157321 : for (i = 0; i < nloads; i++)
10274 : : {
10275 : 119490 : if (costing_p)
10276 : : {
10277 : : /* For VMAT_ELEMENTWISE, just cost it as scalar_load to
10278 : : avoid ICE, see PR110776. */
10279 : 109746 : if (VECTOR_TYPE_P (ltype)
10280 : 4706 : && memory_access_type != VMAT_ELEMENTWISE)
10281 : 4706 : n_adjacent_loads++;
10282 : : else
10283 : 105040 : inside_cost += record_stmt_cost (cost_vec, 1, scalar_load,
10284 : : slp_node, 0, vect_body);
10285 : 109746 : continue;
10286 : : }
10287 : 9744 : unsigned int load_el = group_el;
10288 : : /* For elementwise accesses apply a load permutation directly. */
10289 : 9744 : if (memory_access_type == VMAT_ELEMENTWISE
10290 : 9744 : && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
10291 : 1884 : load_el = SLP_TREE_LOAD_PERMUTATION (slp_node)[group_el];
10292 : 9744 : tree this_off = build_int_cst (TREE_TYPE (alias_off),
10293 : 9744 : load_el * elsz + cst_offset);
10294 : 9744 : tree data_ref = build2 (MEM_REF, ltype, running_off, this_off);
10295 : 9744 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
10296 : 9744 : new_temp = make_ssa_name (ltype);
10297 : 9744 : new_stmt = gimple_build_assign (new_temp, data_ref);
10298 : 9744 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10299 : 9744 : if (nloads > 1)
10300 : 8152 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, new_temp);
10301 : :
10302 : 9744 : group_el += lnel;
10303 : 9744 : if (group_el == group_size)
10304 : : {
10305 : 9349 : n_groups++;
10306 : : /* When doing SLP make sure to not load elements from
10307 : : the next vector iteration, those will not be accessed
10308 : : so just use the last element again. See PR107451. */
10309 : 9349 : if (known_lt (n_groups, vf))
10310 : : {
10311 : 6096 : tree newoff = copy_ssa_name (running_off);
10312 : 6096 : gimple *incr
10313 : 6096 : = gimple_build_assign (newoff, POINTER_PLUS_EXPR,
10314 : : running_off, stride_step);
10315 : 6096 : vect_finish_stmt_generation (vinfo, stmt_info, incr, gsi);
10316 : 6096 : running_off = newoff;
10317 : : }
10318 : : group_el = 0;
10319 : : }
10320 : : }
10321 : :
10322 : 37831 : if (nloads > 1)
10323 : : {
10324 : 28459 : if (costing_p)
10325 : 25666 : inside_cost += record_stmt_cost (cost_vec, 1, vec_construct,
10326 : : slp_node, 0, vect_body);
10327 : : else
10328 : : {
10329 : 2793 : tree vec_inv = build_constructor (lvectype, v);
10330 : 2793 : new_temp = vect_init_vector (vinfo, stmt_info, vec_inv,
10331 : : lvectype, gsi);
10332 : 2793 : new_stmt = SSA_NAME_DEF_STMT (new_temp);
10333 : 2793 : if (lvectype != vectype)
10334 : : {
10335 : 239 : new_stmt
10336 : 239 : = gimple_build_assign (make_ssa_name (vectype),
10337 : : VIEW_CONVERT_EXPR,
10338 : : build1 (VIEW_CONVERT_EXPR,
10339 : : vectype, new_temp));
10340 : 239 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
10341 : : gsi);
10342 : : }
10343 : : }
10344 : : }
10345 : 9372 : else if (!costing_p && ltype != vectype)
10346 : : {
10347 : 1567 : new_stmt = gimple_build_assign (make_ssa_name (vectype),
10348 : : VIEW_CONVERT_EXPR,
10349 : : build1 (VIEW_CONVERT_EXPR,
10350 : : vectype, new_temp));
10351 : 1567 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
10352 : : gsi);
10353 : : }
10354 : :
10355 : 37831 : if (!costing_p)
10356 : : {
10357 : 4385 : if (ls.slp_perm)
10358 : 1338 : dr_chain.quick_push (gimple_assign_lhs (new_stmt));
10359 : : else
10360 : 3047 : slp_node->push_vec_def (new_stmt);
10361 : : }
10362 : : }
10363 : 27656 : if (ls.slp_perm)
10364 : : {
10365 : 2416 : if (costing_p)
10366 : : {
10367 : 1787 : gcc_assert (ls.n_perms != -1U);
10368 : 1787 : inside_cost += record_stmt_cost (cost_vec, ls.n_perms, vec_perm,
10369 : : slp_node, 0, vect_body);
10370 : : }
10371 : : else
10372 : : {
10373 : 629 : unsigned n_perms2;
10374 : 629 : vect_transform_slp_perm_load (vinfo, slp_node, dr_chain, gsi, vf,
10375 : : false, &n_perms2);
10376 : 629 : gcc_assert (ls.n_perms == n_perms2);
10377 : : }
10378 : : }
10379 : :
10380 : 27656 : if (costing_p)
10381 : : {
10382 : 24425 : if (n_adjacent_loads > 0)
10383 : 1796 : vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
10384 : : alignment_support_scheme, misalignment, false,
10385 : : &inside_cost, nullptr, cost_vec, cost_vec,
10386 : : true);
10387 : 24425 : if (dump_enabled_p ())
10388 : 499 : dump_printf_loc (MSG_NOTE, vect_location,
10389 : : "vect_model_load_cost: inside_cost = %u, "
10390 : : "prologue_cost = 0 .\n",
10391 : : inside_cost);
10392 : : }
10393 : :
10394 : 27656 : return true;
10395 : 27656 : }
10396 : :
10397 : 503252 : if (mat_gather_scatter_p (memory_access_type)
10398 : 503252 : && !ls.ls_type)
10399 : : grouped_load = false;
10400 : :
10401 : 500555 : if (grouped_load
10402 : 503252 : || SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
10403 : : {
10404 : 250628 : if (grouped_load)
10405 : : {
10406 : 250307 : first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
10407 : 250307 : group_size = DR_GROUP_SIZE (first_stmt_info);
10408 : : }
10409 : : else
10410 : : {
10411 : : first_stmt_info = stmt_info;
10412 : : group_size = 1;
10413 : : }
10414 : : /* For SLP vectorization we directly vectorize a subchain
10415 : : without permutation. */
10416 : 250628 : if (! SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
10417 : 204094 : first_stmt_info = SLP_TREE_SCALAR_STMTS (slp_node)[0];
10418 : : /* For BB vectorization always use the first stmt to base
10419 : : the data ref pointer on. */
10420 : 250628 : if (bb_vinfo)
10421 : 204140 : first_stmt_info_for_drptr
10422 : 204140 : = vect_find_first_scalar_stmt_in_slp (slp_node);
10423 : :
10424 : 250628 : first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info);
10425 : 250628 : group_gap_adj = 0;
10426 : :
10427 : : /* VEC_NUM is the number of vect stmts to be created for this group. */
10428 : 250628 : grouped_load = false;
10429 : : /* If an SLP permutation is from N elements to N elements,
10430 : : and if one vector holds a whole number of N, we can load
10431 : : the inputs to the permutation in the same way as an
10432 : : unpermuted sequence. In other cases we need to load the
10433 : : whole group, not only the number of vector stmts the
10434 : : permutation result fits in. */
10435 : 250628 : unsigned scalar_lanes = SLP_TREE_LANES (slp_node);
10436 : 250628 : if (nested_in_vect_loop)
10437 : : /* We do not support grouped accesses in a nested loop,
10438 : : instead the access is contiguous but it might be
10439 : : permuted. No gap adjustment is needed though. */
10440 : : ;
10441 : 250626 : else if (ls.slp_perm
10442 : 250626 : && (group_size != scalar_lanes
10443 : 11183 : || !multiple_p (nunits, group_size)))
10444 : : {
10445 : : /* We don't yet generate such SLP_TREE_LOAD_PERMUTATIONs for
10446 : : variable VF; see vect_transform_slp_perm_load. */
10447 : 36427 : unsigned int const_vf = vf.to_constant ();
10448 : 36427 : unsigned int const_nunits = nunits.to_constant ();
10449 : 36427 : vec_num = CEIL (group_size * const_vf, const_nunits);
10450 : 36427 : group_gap_adj = vf * group_size - nunits * vec_num;
10451 : : }
10452 : : else
10453 : : {
10454 : 214199 : group_gap_adj = group_size - scalar_lanes;
10455 : : }
10456 : :
10457 : 250628 : ref_type = get_group_alias_ptr_type (first_stmt_info);
10458 : : }
10459 : : else
10460 : : {
10461 : 252624 : first_stmt_info = stmt_info;
10462 : 252624 : first_dr_info = dr_info;
10463 : 252624 : group_size = 1;
10464 : 252624 : group_gap_adj = 0;
10465 : 252624 : ref_type = reference_alias_ptr_type (DR_REF (first_dr_info->dr));
10466 : : }
10467 : :
10468 : 503252 : vec_loop_masks *loop_masks
10469 : 299112 : = (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
10470 : 503252 : ? &LOOP_VINFO_MASKS (loop_vinfo)
10471 : 31 : : NULL);
10472 : 31 : vec_loop_lens *loop_lens
10473 : 299112 : = (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo)
10474 : : ? &LOOP_VINFO_LENS (loop_vinfo)
10475 : 0 : : NULL);
10476 : :
10477 : : /* The vect_transform_stmt and vect_analyze_stmt will go here but there
10478 : : are some difference here. We cannot enable both the lens and masks
10479 : : during transform but it is allowed during analysis.
10480 : : Shouldn't go with length-based approach if fully masked. */
10481 : 503252 : if (cost_vec == NULL)
10482 : : /* The cost_vec is NULL during transfrom. */
10483 : 156706 : gcc_assert ((!loop_lens || !loop_masks));
10484 : :
10485 : : /* Targets with store-lane instructions must not require explicit
10486 : : realignment. vect_supportable_dr_alignment always returns either
10487 : : dr_aligned or dr_unaligned_supported for (non-length) masked
10488 : : operations. */
10489 : 503252 : gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES
10490 : : && !mask_node
10491 : : && !loop_masks)
10492 : : || mat_gather_scatter_p (memory_access_type)
10493 : : || alignment_support_scheme == dr_aligned
10494 : : || alignment_support_scheme == dr_unaligned_supported);
10495 : :
10496 : : /* In case the vectorization factor (VF) is bigger than the number
10497 : : of elements that we can fit in a vectype (nunits), we have to generate
10498 : : more than one vector stmt - i.e - we need to "unroll" the
10499 : : vector stmt by a factor VF/nunits. In doing so, we record a pointer
10500 : : from one copy of the vector stmt to the next, in the field
10501 : : STMT_VINFO_RELATED_STMT. This is necessary in order to allow following
10502 : : stages to find the correct vector defs to be used when vectorizing
10503 : : stmts that use the defs of the current stmt. The example below
10504 : : illustrates the vectorization process when VF=16 and nunits=4 (i.e., we
10505 : : need to create 4 vectorized stmts):
10506 : :
10507 : : before vectorization:
10508 : : RELATED_STMT VEC_STMT
10509 : : S1: x = memref - -
10510 : : S2: z = x + 1 - -
10511 : :
10512 : : step 1: vectorize stmt S1:
10513 : : We first create the vector stmt VS1_0, and, as usual, record a
10514 : : pointer to it in the STMT_VINFO_VEC_STMT of the scalar stmt S1.
10515 : : Next, we create the vector stmt VS1_1, and record a pointer to
10516 : : it in the STMT_VINFO_RELATED_STMT of the vector stmt VS1_0.
10517 : : Similarly, for VS1_2 and VS1_3. This is the resulting chain of
10518 : : stmts and pointers:
10519 : : RELATED_STMT VEC_STMT
10520 : : VS1_0: vx0 = memref0 VS1_1 -
10521 : : VS1_1: vx1 = memref1 VS1_2 -
10522 : : VS1_2: vx2 = memref2 VS1_3 -
10523 : : VS1_3: vx3 = memref3 - -
10524 : : S1: x = load - VS1_0
10525 : : S2: z = x + 1 - -
10526 : : */
10527 : :
10528 : : /* If the data reference is aligned (dr_aligned) or potentially unaligned
10529 : : on a target that supports unaligned accesses (dr_unaligned_supported)
10530 : : we generate the following code:
10531 : : p = initial_addr;
10532 : : indx = 0;
10533 : : loop {
10534 : : p = p + indx * vectype_size;
10535 : : vec_dest = *(p);
10536 : : indx = indx + 1;
10537 : : }
10538 : :
10539 : : Otherwise, the data reference is potentially unaligned on a target that
10540 : : does not support unaligned accesses (dr_explicit_realign_optimized) -
10541 : : then generate the following code, in which the data in each iteration is
10542 : : obtained by two vector loads, one from the previous iteration, and one
10543 : : from the current iteration:
10544 : : p1 = initial_addr;
10545 : : msq_init = *(floor(p1))
10546 : : p2 = initial_addr + VS - 1;
10547 : : realignment_token = call target_builtin;
10548 : : indx = 0;
10549 : : loop {
10550 : : p2 = p2 + indx * vectype_size
10551 : : lsq = *(floor(p2))
10552 : : vec_dest = realign_load (msq, lsq, realignment_token)
10553 : : indx = indx + 1;
10554 : : msq = lsq;
10555 : : } */
10556 : :
10557 : : /* If the misalignment remains the same throughout the execution of the
10558 : : loop, we can create the init_addr and permutation mask at the loop
10559 : : preheader. Otherwise, it needs to be created inside the loop.
10560 : : This can only occur when vectorizing memory accesses in the inner-loop
10561 : : nested within an outer-loop that is being vectorized. */
10562 : :
10563 : 503252 : if (nested_in_vect_loop
10564 : 503252 : && !multiple_p (DR_STEP_ALIGNMENT (dr_info->dr),
10565 : 1196 : GET_MODE_SIZE (TYPE_MODE (vectype))))
10566 : : {
10567 : 191 : gcc_assert (alignment_support_scheme != dr_explicit_realign_optimized);
10568 : : compute_in_loop = true;
10569 : : }
10570 : :
10571 : 503252 : bool diff_first_stmt_info
10572 : 503252 : = first_stmt_info_for_drptr && first_stmt_info != first_stmt_info_for_drptr;
10573 : :
10574 : 503252 : tree offset = NULL_TREE;
10575 : 503252 : if ((alignment_support_scheme == dr_explicit_realign_optimized
10576 : 503252 : || alignment_support_scheme == dr_explicit_realign)
10577 : 0 : && !compute_in_loop)
10578 : : {
10579 : : /* If we have different first_stmt_info, we can't set up realignment
10580 : : here, since we can't guarantee first_stmt_info DR has been
10581 : : initialized yet, use first_stmt_info_for_drptr DR by bumping the
10582 : : distance from first_stmt_info DR instead as below. */
10583 : 0 : if (!costing_p)
10584 : : {
10585 : 0 : if (!diff_first_stmt_info)
10586 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info, vectype, gsi,
10587 : : &realignment_token,
10588 : : alignment_support_scheme, NULL_TREE,
10589 : : &at_loop);
10590 : 0 : if (alignment_support_scheme == dr_explicit_realign_optimized)
10591 : : {
10592 : 0 : phi = as_a<gphi *> (SSA_NAME_DEF_STMT (msq));
10593 : 0 : offset = size_binop (MINUS_EXPR, TYPE_SIZE_UNIT (vectype),
10594 : : size_one_node);
10595 : 0 : gcc_assert (!first_stmt_info_for_drptr);
10596 : : }
10597 : : }
10598 : : }
10599 : : else
10600 : 503252 : at_loop = loop;
10601 : :
10602 : 503252 : if (!known_eq (poffset, 0))
10603 : 4431 : offset = (offset
10604 : 4431 : ? size_binop (PLUS_EXPR, offset, size_int (poffset))
10605 : 4431 : : size_int (poffset));
10606 : :
10607 : 503252 : tree bump;
10608 : 503252 : tree vec_offset = NULL_TREE;
10609 : :
10610 : 503252 : auto_vec<tree> vec_offsets;
10611 : 503252 : auto_vec<tree> vec_masks;
10612 : 503252 : if (mask_node && !costing_p)
10613 : 619 : vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[mask_index],
10614 : : &vec_masks);
10615 : :
10616 : 503252 : tree vec_mask = NULL_TREE;
10617 : 503252 : tree vec_els = NULL_TREE;
10618 : 503252 : if (memory_access_type == VMAT_LOAD_STORE_LANES)
10619 : : {
10620 : 0 : const internal_fn lanes_ifn = ls.lanes_ifn;
10621 : :
10622 : 0 : gcc_assert (alignment_support_scheme == dr_aligned
10623 : : || alignment_support_scheme == dr_unaligned_supported);
10624 : :
10625 : 0 : aggr_type = build_array_type_nelts (elem_type, group_size * nunits);
10626 : 0 : if (!costing_p)
10627 : 0 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
10628 : : memory_access_type, loop_lens);
10629 : :
10630 : 0 : unsigned int inside_cost = 0, prologue_cost = 0;
10631 : : /* For costing some adjacent vector loads, we'd like to cost with
10632 : : the total number of them once instead of cost each one by one. */
10633 : 0 : unsigned int n_adjacent_loads = 0;
10634 : 0 : int ncopies = vec_num / group_size;
10635 : 0 : for (j = 0; j < ncopies; j++)
10636 : : {
10637 : 0 : if (costing_p)
10638 : : {
10639 : : /* An IFN_LOAD_LANES will load all its vector results,
10640 : : regardless of which ones we actually need. Account
10641 : : for the cost of unused results. */
10642 : 0 : if (first_stmt_info == stmt_info)
10643 : : {
10644 : 0 : unsigned int gaps = DR_GROUP_SIZE (first_stmt_info);
10645 : 0 : stmt_vec_info next_stmt_info = first_stmt_info;
10646 : 0 : do
10647 : : {
10648 : 0 : gaps -= 1;
10649 : 0 : next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
10650 : : }
10651 : 0 : while (next_stmt_info);
10652 : 0 : if (gaps)
10653 : : {
10654 : 0 : if (dump_enabled_p ())
10655 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
10656 : : "vect_model_load_cost: %d "
10657 : : "unused vectors.\n",
10658 : : gaps);
10659 : 0 : vect_get_load_cost (vinfo, stmt_info, slp_node, gaps,
10660 : : alignment_support_scheme,
10661 : : misalignment, false, &inside_cost,
10662 : : &prologue_cost, cost_vec, cost_vec,
10663 : : true);
10664 : : }
10665 : : }
10666 : 0 : n_adjacent_loads++;
10667 : 0 : continue;
10668 : 0 : }
10669 : :
10670 : : /* 1. Create the vector or array pointer update chain. */
10671 : 0 : if (j == 0)
10672 : 0 : dataref_ptr
10673 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
10674 : : at_loop, offset, &dummy, gsi,
10675 : : &ptr_incr, false, bump);
10676 : : else
10677 : : {
10678 : 0 : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
10679 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
10680 : : stmt_info, bump);
10681 : : }
10682 : 0 : if (mask_node)
10683 : 0 : vec_mask = vec_masks[j];
10684 : :
10685 : 0 : tree vec_array = create_vector_array (vectype, group_size);
10686 : :
10687 : 0 : tree final_mask = NULL_TREE;
10688 : 0 : tree final_len = NULL_TREE;
10689 : 0 : tree bias = NULL_TREE;
10690 : 0 : if (loop_masks)
10691 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
10692 : : ncopies, vectype, j);
10693 : 0 : if (vec_mask)
10694 : 0 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
10695 : : vec_mask, gsi);
10696 : :
10697 : 0 : if (lanes_ifn == IFN_MASK_LEN_LOAD_LANES)
10698 : : {
10699 : 0 : if (loop_lens)
10700 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
10701 : : ncopies, vectype, j, 1);
10702 : : else
10703 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
10704 : 0 : signed char biasval
10705 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
10706 : 0 : bias = build_int_cst (intQI_type_node, biasval);
10707 : 0 : if (!final_mask)
10708 : : {
10709 : 0 : mask_vectype = truth_type_for (vectype);
10710 : 0 : final_mask = build_minus_one_cst (mask_vectype);
10711 : : }
10712 : : }
10713 : :
10714 : 0 : if (final_mask)
10715 : : {
10716 : 0 : vec_els = vect_get_mask_load_else (maskload_elsval, vectype);
10717 : 0 : if (type_mode_padding_p
10718 : 0 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
10719 : 0 : need_zeroing = true;
10720 : : }
10721 : :
10722 : 0 : gcall *call;
10723 : 0 : if (final_len && final_mask)
10724 : : {
10725 : : /* Emit:
10726 : : VEC_ARRAY = MASK_LEN_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,
10727 : : VEC_MASK, LEN, BIAS). */
10728 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
10729 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
10730 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_LOAD_LANES, 6,
10731 : : dataref_ptr, alias_ptr,
10732 : : final_mask, vec_els,
10733 : : final_len, bias);
10734 : : }
10735 : 0 : else if (final_mask)
10736 : : {
10737 : : /* Emit:
10738 : : VEC_ARRAY = MASK_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,
10739 : : VEC_MASK). */
10740 : 0 : unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
10741 : 0 : tree alias_ptr = build_int_cst (ref_type, align);
10742 : 0 : call = gimple_build_call_internal (IFN_MASK_LOAD_LANES, 4,
10743 : : dataref_ptr, alias_ptr,
10744 : : final_mask, vec_els);
10745 : : }
10746 : : else
10747 : : {
10748 : : /* Emit:
10749 : : VEC_ARRAY = LOAD_LANES (MEM_REF[...all elements...]). */
10750 : 0 : data_ref = create_array_ref (aggr_type, dataref_ptr, ref_type);
10751 : 0 : call = gimple_build_call_internal (IFN_LOAD_LANES, 1, data_ref);
10752 : : }
10753 : 0 : gimple_call_set_lhs (call, vec_array);
10754 : 0 : gimple_call_set_nothrow (call, true);
10755 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
10756 : :
10757 : : /* Extract each vector into an SSA_NAME. */
10758 : 0 : for (unsigned i = 0; i < group_size; i++)
10759 : : {
10760 : 0 : new_temp = read_vector_array (vinfo, stmt_info, gsi, scalar_dest,
10761 : : vec_array, i, need_zeroing,
10762 : : final_mask);
10763 : 0 : slp_node->push_vec_def (new_temp);
10764 : : }
10765 : :
10766 : : /* Record that VEC_ARRAY is now dead. */
10767 : 0 : vect_clobber_variable (vinfo, stmt_info, gsi, vec_array);
10768 : : }
10769 : :
10770 : 0 : if (costing_p)
10771 : : {
10772 : 0 : if (n_adjacent_loads > 0)
10773 : 0 : vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
10774 : : alignment_support_scheme, misalignment, false,
10775 : : &inside_cost, &prologue_cost, cost_vec,
10776 : : cost_vec, true);
10777 : 0 : if (dump_enabled_p ())
10778 : 0 : dump_printf_loc (MSG_NOTE, vect_location,
10779 : : "vect_model_load_cost: inside_cost = %u, "
10780 : : "prologue_cost = %u .\n",
10781 : : inside_cost, prologue_cost);
10782 : : }
10783 : :
10784 : 0 : return true;
10785 : : }
10786 : :
10787 : 503252 : if (mat_gather_scatter_p (memory_access_type))
10788 : : {
10789 : 2697 : gcc_assert ((!grouped_load && !ls.slp_perm) || ls.ls_type);
10790 : :
10791 : 2697 : auto_vec<tree> dr_chain (vec_num);
10792 : :
10793 : : /* If we pun the original vectype the loads as well as costing, length,
10794 : : etc. is performed with the new type. After loading we VIEW_CONVERT
10795 : : the data to the original vectype. */
10796 : 2697 : tree original_vectype = vectype;
10797 : 2697 : if (ls.ls_type)
10798 : 0 : vectype = ls.ls_type;
10799 : :
10800 : : /* 1. Create the vector or array pointer update chain. */
10801 : 2697 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
10802 : : {
10803 : 2697 : aggr_type = NULL_TREE;
10804 : 2697 : bump = NULL_TREE;
10805 : 2697 : if (!costing_p)
10806 : 749 : vect_get_gather_scatter_ops (loop, slp_node, &dataref_ptr,
10807 : : &vec_offsets);
10808 : : }
10809 : : else
10810 : : {
10811 : 0 : aggr_type = elem_type;
10812 : 0 : if (!costing_p)
10813 : : {
10814 : 0 : vect_get_strided_load_store_ops (stmt_info, slp_node, vectype,
10815 : : ls.strided_offset_vectype,
10816 : : loop_vinfo, gsi,
10817 : : &bump, &vec_offset, loop_lens);
10818 : 0 : dataref_ptr
10819 : 0 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
10820 : : at_loop, offset, &dummy, gsi,
10821 : : &ptr_incr, false, bump);
10822 : : }
10823 : : }
10824 : :
10825 : : unsigned int inside_cost = 0, prologue_cost = 0;
10826 : :
10827 : 6097 : gimple *new_stmt = NULL;
10828 : 6097 : for (i = 0; i < vec_num; i++)
10829 : : {
10830 : 3400 : tree final_mask = NULL_TREE;
10831 : 3400 : tree final_len = NULL_TREE;
10832 : 3400 : tree bias = NULL_TREE;
10833 : 3400 : if (!costing_p)
10834 : : {
10835 : 963 : if (mask_node)
10836 : 153 : vec_mask = vec_masks[i];
10837 : 963 : if (loop_masks)
10838 : 0 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
10839 : : vec_num, vectype, i);
10840 : 963 : if (vec_mask)
10841 : 153 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
10842 : : final_mask, vec_mask, gsi);
10843 : :
10844 : 963 : if (i > 0 && !STMT_VINFO_GATHER_SCATTER_P (stmt_info))
10845 : 0 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
10846 : : gsi, stmt_info, bump);
10847 : : }
10848 : :
10849 : : /* 2. Create the vector-load in the loop. */
10850 : 3400 : unsigned align = get_object_alignment (DR_REF (first_dr_info->dr));
10851 : 3400 : tree alias_align_ptr = build_int_cst (ref_type, align);
10852 : 3400 : if (memory_access_type == VMAT_GATHER_SCATTER_IFN)
10853 : : {
10854 : 0 : if (costing_p)
10855 : : {
10856 : 0 : if (ls.supported_offset_vectype)
10857 : 0 : inside_cost
10858 : 0 : += record_stmt_cost (cost_vec, 1, vector_stmt,
10859 : : slp_node, 0, vect_body);
10860 : 0 : if (ls.supported_scale)
10861 : 0 : inside_cost
10862 : 0 : += record_stmt_cost (cost_vec, 1, vector_stmt,
10863 : : slp_node, 0, vect_body);
10864 : :
10865 : 0 : unsigned int cnunits = vect_nunits_for_cost (vectype);
10866 : 0 : inside_cost
10867 : 0 : = record_stmt_cost (cost_vec, cnunits, scalar_load,
10868 : : slp_node, 0, vect_body);
10869 : 3400 : continue;
10870 : 0 : }
10871 : 0 : if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
10872 : 0 : vec_offset = vec_offsets[i];
10873 : 0 : tree zero = build_zero_cst (vectype);
10874 : 0 : tree scale = size_int (SLP_TREE_GS_SCALE (slp_node));
10875 : 0 : bool strided = !VECTOR_TYPE_P (TREE_TYPE (vec_offset));
10876 : :
10877 : : /* Perform the offset conversion and scaling if necessary. */
10878 : 0 : if (!strided
10879 : 0 : && (ls.supported_offset_vectype || ls.supported_scale))
10880 : : {
10881 : 0 : gimple_seq stmts = NULL;
10882 : 0 : if (ls.supported_offset_vectype)
10883 : 0 : vec_offset = gimple_convert
10884 : 0 : (&stmts, ls.supported_offset_vectype, vec_offset);
10885 : 0 : if (ls.supported_scale)
10886 : : {
10887 : 0 : tree mult_cst = build_int_cst
10888 : 0 : (TREE_TYPE (TREE_TYPE (vec_offset)),
10889 : 0 : SLP_TREE_GS_SCALE (slp_node) / ls.supported_scale);
10890 : 0 : tree mult = build_vector_from_val
10891 : 0 : (TREE_TYPE (vec_offset), mult_cst);
10892 : 0 : vec_offset = gimple_build
10893 : 0 : (&stmts, MULT_EXPR, TREE_TYPE (vec_offset),
10894 : : vec_offset, mult);
10895 : 0 : scale = size_int (ls.supported_scale);
10896 : : }
10897 : 0 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
10898 : : }
10899 : :
10900 : 0 : if (ls.gs.ifn == IFN_MASK_LEN_GATHER_LOAD)
10901 : : {
10902 : 0 : if (loop_lens)
10903 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
10904 : : vec_num, vectype, i, 1);
10905 : : else
10906 : 0 : final_len = build_int_cst (sizetype,
10907 : 0 : TYPE_VECTOR_SUBPARTS (vectype));
10908 : 0 : signed char biasval
10909 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
10910 : 0 : bias = build_int_cst (intQI_type_node, biasval);
10911 : 0 : if (!final_mask)
10912 : : {
10913 : 0 : mask_vectype = truth_type_for (vectype);
10914 : 0 : final_mask = build_minus_one_cst (mask_vectype);
10915 : : }
10916 : : }
10917 : :
10918 : 0 : if (final_mask)
10919 : : {
10920 : 0 : vec_els = vect_get_mask_load_else (maskload_elsval, vectype);
10921 : 0 : if (type_mode_padding_p
10922 : 0 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
10923 : 0 : need_zeroing = true;
10924 : : }
10925 : :
10926 : 0 : gcall *call;
10927 : 0 : if (final_len && final_mask)
10928 : : {
10929 : 0 : if (VECTOR_TYPE_P (TREE_TYPE (vec_offset)))
10930 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_GATHER_LOAD,
10931 : : 9, dataref_ptr,
10932 : : alias_align_ptr,
10933 : : vec_offset, scale, zero,
10934 : : final_mask, vec_els,
10935 : : final_len, bias);
10936 : : else
10937 : : /* Non-vector offset indicates that prefer to take
10938 : : MASK_LEN_STRIDED_LOAD instead of the
10939 : : MASK_LEN_GATHER_LOAD with direct stride arg. */
10940 : 0 : call = gimple_build_call_internal
10941 : 0 : (IFN_MASK_LEN_STRIDED_LOAD, 7, dataref_ptr,
10942 : : vec_offset, zero, final_mask, vec_els, final_len,
10943 : : bias);
10944 : : }
10945 : 0 : else if (final_mask)
10946 : 0 : call = gimple_build_call_internal (IFN_MASK_GATHER_LOAD,
10947 : : 7, dataref_ptr,
10948 : : alias_align_ptr,
10949 : : vec_offset, scale,
10950 : : zero, final_mask, vec_els);
10951 : : else
10952 : 0 : call = gimple_build_call_internal (IFN_GATHER_LOAD, 5,
10953 : : dataref_ptr,
10954 : : alias_align_ptr,
10955 : : vec_offset, scale, zero);
10956 : 0 : gimple_call_set_nothrow (call, true);
10957 : 0 : new_stmt = call;
10958 : 0 : data_ref = NULL_TREE;
10959 : : }
10960 : 3400 : else if (memory_access_type == VMAT_GATHER_SCATTER_LEGACY)
10961 : : {
10962 : : /* The builtin decls path for gather is legacy, x86 only. */
10963 : 570 : gcc_assert (!final_len && nunits.is_constant ());
10964 : 570 : if (costing_p)
10965 : : {
10966 : 287 : unsigned int cnunits = vect_nunits_for_cost (vectype);
10967 : 287 : inside_cost
10968 : 287 : = record_stmt_cost (cost_vec, cnunits, scalar_load,
10969 : : slp_node, 0, vect_body);
10970 : 287 : continue;
10971 : 287 : }
10972 : 283 : tree offset_vectype = TREE_TYPE (vec_offsets[0]);
10973 : 283 : poly_uint64 offset_nunits = TYPE_VECTOR_SUBPARTS (offset_vectype);
10974 : 283 : if (known_eq (nunits, offset_nunits))
10975 : : {
10976 : 134 : new_stmt = vect_build_one_gather_load_call
10977 : 134 : (vinfo, stmt_info, slp_node, vectype, gsi,
10978 : 134 : ls.gs.decl, dataref_ptr, vec_offsets[i],
10979 : : final_mask);
10980 : 134 : data_ref = NULL_TREE;
10981 : : }
10982 : 149 : else if (known_eq (nunits, offset_nunits * 2))
10983 : : {
10984 : : /* We have a offset vector with half the number of
10985 : : lanes but the builtins will produce full vectype
10986 : : data with just the lower lanes filled. */
10987 : 63 : new_stmt = vect_build_one_gather_load_call
10988 : 126 : (vinfo, stmt_info, slp_node, vectype, gsi,
10989 : 63 : ls.gs.decl, dataref_ptr, vec_offsets[2 * i],
10990 : : final_mask);
10991 : 63 : tree low = make_ssa_name (vectype);
10992 : 63 : gimple_set_lhs (new_stmt, low);
10993 : 63 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
10994 : :
10995 : : /* now put upper half of final_mask in final_mask low. */
10996 : 63 : if (final_mask
10997 : 63 : && !SCALAR_INT_MODE_P (TYPE_MODE (TREE_TYPE (final_mask))))
10998 : : {
10999 : 11 : int count = nunits.to_constant ();
11000 : 11 : vec_perm_builder sel (count, count, 1);
11001 : 11 : sel.quick_grow (count);
11002 : 87 : for (int i = 0; i < count; ++i)
11003 : 76 : sel[i] = i | (count / 2);
11004 : 11 : vec_perm_indices indices (sel, 2, count);
11005 : 11 : tree perm_mask = vect_gen_perm_mask_checked
11006 : 11 : (TREE_TYPE (final_mask), indices);
11007 : 11 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
11008 : : final_mask, final_mask,
11009 : : perm_mask);
11010 : 11 : final_mask = make_ssa_name (TREE_TYPE (final_mask));
11011 : 11 : gimple_set_lhs (new_stmt, final_mask);
11012 : 11 : vect_finish_stmt_generation (vinfo, stmt_info,
11013 : : new_stmt, gsi);
11014 : 11 : }
11015 : 52 : else if (final_mask)
11016 : : {
11017 : 24 : new_stmt = gimple_build_assign (NULL_TREE,
11018 : : VEC_UNPACK_HI_EXPR,
11019 : : final_mask);
11020 : 24 : final_mask = make_ssa_name
11021 : 24 : (truth_type_for (offset_vectype));
11022 : 24 : gimple_set_lhs (new_stmt, final_mask);
11023 : 24 : vect_finish_stmt_generation (vinfo, stmt_info,
11024 : : new_stmt, gsi);
11025 : : }
11026 : :
11027 : 63 : new_stmt = vect_build_one_gather_load_call
11028 : 126 : (vinfo, stmt_info, slp_node, vectype, gsi,
11029 : : ls.gs.decl, dataref_ptr,
11030 : 63 : vec_offsets[2 * i + 1], final_mask);
11031 : 63 : tree high = make_ssa_name (vectype);
11032 : 63 : gimple_set_lhs (new_stmt, high);
11033 : 63 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11034 : :
11035 : : /* compose low + high. */
11036 : 63 : int count = nunits.to_constant ();
11037 : 63 : vec_perm_builder sel (count, count, 1);
11038 : 63 : sel.quick_grow (count);
11039 : 647 : for (int i = 0; i < count; ++i)
11040 : 584 : sel[i] = i < count / 2 ? i : i + count / 2;
11041 : 63 : vec_perm_indices indices (sel, 2, count);
11042 : 63 : tree perm_mask
11043 : 63 : = vect_gen_perm_mask_checked (vectype, indices);
11044 : 63 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
11045 : : low, high, perm_mask);
11046 : 63 : data_ref = NULL_TREE;
11047 : 63 : }
11048 : 86 : else if (known_eq (nunits * 2, offset_nunits))
11049 : : {
11050 : : /* We have a offset vector with double the number of
11051 : : lanes. Select the low/high part accordingly. */
11052 : 86 : vec_offset = vec_offsets[i / 2];
11053 : 86 : if (i & 1)
11054 : : {
11055 : 43 : int count = offset_nunits.to_constant ();
11056 : 43 : vec_perm_builder sel (count, count, 1);
11057 : 43 : sel.quick_grow (count);
11058 : 463 : for (int i = 0; i < count; ++i)
11059 : 420 : sel[i] = i | (count / 2);
11060 : 43 : vec_perm_indices indices (sel, 2, count);
11061 : 43 : tree perm_mask = vect_gen_perm_mask_checked
11062 : 43 : (TREE_TYPE (vec_offset), indices);
11063 : 43 : new_stmt = gimple_build_assign (NULL_TREE, VEC_PERM_EXPR,
11064 : : vec_offset, vec_offset,
11065 : : perm_mask);
11066 : 43 : vec_offset = make_ssa_name (TREE_TYPE (vec_offset));
11067 : 43 : gimple_set_lhs (new_stmt, vec_offset);
11068 : 43 : vect_finish_stmt_generation (vinfo, stmt_info,
11069 : : new_stmt, gsi);
11070 : 43 : }
11071 : 86 : new_stmt = vect_build_one_gather_load_call
11072 : 86 : (vinfo, stmt_info, slp_node, vectype, gsi,
11073 : : ls.gs.decl,
11074 : : dataref_ptr, vec_offset, final_mask);
11075 : 86 : data_ref = NULL_TREE;
11076 : : }
11077 : : else
11078 : 0 : gcc_unreachable ();
11079 : : }
11080 : : else
11081 : : {
11082 : : /* Emulated gather-scatter. */
11083 : 2830 : gcc_assert (!final_mask);
11084 : 2830 : unsigned HOST_WIDE_INT const_nunits = nunits.to_constant ();
11085 : 2830 : if (costing_p)
11086 : : {
11087 : : /* For emulated gathers N offset vector element
11088 : : offset add is consumed by the load). */
11089 : 2150 : inside_cost = record_stmt_cost (cost_vec, const_nunits,
11090 : : vec_to_scalar,
11091 : : slp_node, 0, vect_body);
11092 : : /* N scalar loads plus gathering them into a
11093 : : vector. */
11094 : 2150 : inside_cost
11095 : 2150 : = record_stmt_cost (cost_vec, const_nunits, scalar_load,
11096 : : slp_node, 0, vect_body);
11097 : 2150 : inside_cost
11098 : 2150 : = record_stmt_cost (cost_vec, 1, vec_construct,
11099 : : slp_node, 0, vect_body);
11100 : 2150 : continue;
11101 : : }
11102 : 680 : tree offset_vectype = TREE_TYPE (vec_offsets[0]);
11103 : 680 : unsigned HOST_WIDE_INT const_offset_nunits
11104 : 680 : = TYPE_VECTOR_SUBPARTS (offset_vectype).to_constant ();
11105 : 680 : vec<constructor_elt, va_gc> *ctor_elts;
11106 : 680 : vec_alloc (ctor_elts, const_nunits);
11107 : 680 : gimple_seq stmts = NULL;
11108 : : /* We support offset vectors with more elements
11109 : : than the data vector for now. */
11110 : 680 : unsigned HOST_WIDE_INT factor
11111 : : = const_offset_nunits / const_nunits;
11112 : 680 : vec_offset = vec_offsets[i / factor];
11113 : 680 : unsigned elt_offset = (i % factor) * const_nunits;
11114 : 680 : tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset));
11115 : 680 : tree scale = size_int (SLP_TREE_GS_SCALE (slp_node));
11116 : 680 : tree ltype = build_aligned_type (TREE_TYPE (vectype), align);
11117 : 2828 : for (unsigned k = 0; k < const_nunits; ++k)
11118 : : {
11119 : 2148 : tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type),
11120 : : bitsize_int (k + elt_offset));
11121 : 6444 : tree idx = gimple_build (&stmts, BIT_FIELD_REF, idx_type,
11122 : 2148 : vec_offset, TYPE_SIZE (idx_type),
11123 : : boff);
11124 : 2148 : idx = gimple_convert (&stmts, sizetype, idx);
11125 : 2148 : idx = gimple_build (&stmts, MULT_EXPR, sizetype, idx, scale);
11126 : 2148 : tree ptr = gimple_build (&stmts, PLUS_EXPR,
11127 : 2148 : TREE_TYPE (dataref_ptr),
11128 : : dataref_ptr, idx);
11129 : 2148 : ptr = gimple_convert (&stmts, ptr_type_node, ptr);
11130 : 2148 : tree elt = make_ssa_name (TREE_TYPE (vectype));
11131 : 2148 : tree ref = build2 (MEM_REF, ltype, ptr,
11132 : : build_int_cst (ref_type, 0));
11133 : 2148 : new_stmt = gimple_build_assign (elt, ref);
11134 : 4296 : gimple_set_vuse (new_stmt, gimple_vuse (gsi_stmt (*gsi)));
11135 : 2148 : gimple_seq_add_stmt (&stmts, new_stmt);
11136 : 2148 : CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE, elt);
11137 : : }
11138 : 680 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
11139 : 680 : new_stmt = gimple_build_assign (NULL_TREE,
11140 : : build_constructor (vectype,
11141 : : ctor_elts));
11142 : 680 : data_ref = NULL_TREE;
11143 : : }
11144 : :
11145 : 963 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11146 : : /* DATA_REF is null if we've already built the statement. */
11147 : 963 : if (data_ref)
11148 : : {
11149 : : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
11150 : : new_stmt = gimple_build_assign (vec_dest, data_ref);
11151 : : }
11152 : 1926 : new_temp = (need_zeroing
11153 : 963 : ? make_ssa_name (vectype)
11154 : 963 : : make_ssa_name (vec_dest, new_stmt));
11155 : 963 : gimple_set_lhs (new_stmt, new_temp);
11156 : 963 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11157 : :
11158 : : /* If we need to explicitly zero inactive elements emit a
11159 : : VEC_COND_EXPR that does so. */
11160 : 963 : if (need_zeroing)
11161 : : {
11162 : 0 : vec_els = vect_get_mask_load_else (MASK_LOAD_ELSE_ZERO,
11163 : : vectype);
11164 : :
11165 : 0 : tree new_temp2 = make_ssa_name (vec_dest, new_stmt);
11166 : 0 : new_stmt = gimple_build_assign (new_temp2, VEC_COND_EXPR,
11167 : : final_mask, new_temp, vec_els);
11168 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11169 : 0 : new_temp = new_temp2;
11170 : : }
11171 : :
11172 : 963 : if (ls.ls_type)
11173 : : {
11174 : 0 : new_stmt = gimple_build_assign (make_ssa_name
11175 : : (original_vectype),
11176 : : VIEW_CONVERT_EXPR,
11177 : : build1 (VIEW_CONVERT_EXPR,
11178 : : original_vectype,
11179 : : new_temp));
11180 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11181 : : }
11182 : :
11183 : : /* Store vector loads in the corresponding SLP_NODE. */
11184 : 963 : if (!costing_p)
11185 : : {
11186 : 963 : if (ls.slp_perm)
11187 : 0 : dr_chain.quick_push (gimple_assign_lhs (new_stmt));
11188 : : else
11189 : 963 : slp_node->push_vec_def (new_stmt);
11190 : : }
11191 : : }
11192 : :
11193 : 2697 : if (ls.slp_perm)
11194 : : {
11195 : 0 : if (costing_p)
11196 : : {
11197 : 0 : gcc_assert (ls.n_perms != -1U);
11198 : 0 : inside_cost += record_stmt_cost (cost_vec, ls.n_perms, vec_perm,
11199 : : slp_node, 0, vect_body);
11200 : : }
11201 : : else
11202 : : {
11203 : 0 : unsigned n_perms2;
11204 : 0 : vect_transform_slp_perm_load (vinfo, slp_node, dr_chain, gsi, vf,
11205 : : false, &n_perms2);
11206 : 0 : gcc_assert (ls.n_perms == n_perms2);
11207 : : }
11208 : : }
11209 : :
11210 : 2697 : if (costing_p && dump_enabled_p ())
11211 : 222 : dump_printf_loc (MSG_NOTE, vect_location,
11212 : : "vect_model_load_cost: inside_cost = %u, "
11213 : : "prologue_cost = %u .\n",
11214 : : inside_cost, prologue_cost);
11215 : 2697 : return true;
11216 : 2697 : }
11217 : :
11218 : 500555 : aggr_type = vectype;
11219 : 500555 : if (!costing_p)
11220 : 155957 : bump = vect_get_data_ptr_increment (vinfo, gsi, dr_info, aggr_type,
11221 : : memory_access_type, loop_lens);
11222 : :
11223 : 500555 : poly_uint64 group_elt = 0;
11224 : 500555 : unsigned int inside_cost = 0, prologue_cost = 0;
11225 : : /* For costing some adjacent vector loads, we'd like to cost with
11226 : : the total number of them once instead of cost each one by one. */
11227 : 500555 : unsigned int n_adjacent_loads = 0;
11228 : :
11229 : : /* 1. Create the vector or array pointer update chain. */
11230 : 500555 : if (!costing_p)
11231 : : {
11232 : 155957 : bool simd_lane_access_p
11233 : 155957 : = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) != 0;
11234 : 155957 : if (simd_lane_access_p
11235 : 1629 : && TREE_CODE (DR_BASE_ADDRESS (first_dr_info->dr)) == ADDR_EXPR
11236 : 1629 : && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr_info->dr), 0))
11237 : 1629 : && integer_zerop (get_dr_vinfo_offset (vinfo, first_dr_info))
11238 : 1629 : && integer_zerop (DR_INIT (first_dr_info->dr))
11239 : 1629 : && alias_sets_conflict_p (get_alias_set (aggr_type),
11240 : 1629 : get_alias_set (TREE_TYPE (ref_type)))
11241 : 155957 : && (alignment_support_scheme == dr_aligned
11242 : 1629 : || alignment_support_scheme == dr_unaligned_supported))
11243 : : {
11244 : 1629 : dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr));
11245 : 1629 : dataref_offset = build_int_cst (ref_type, 0);
11246 : : }
11247 : 154328 : else if (diff_first_stmt_info)
11248 : : {
11249 : 3178 : dataref_ptr
11250 : 3178 : = vect_create_data_ref_ptr (vinfo, first_stmt_info_for_drptr,
11251 : : aggr_type, at_loop, offset, &dummy,
11252 : : gsi, &ptr_incr, simd_lane_access_p,
11253 : : bump);
11254 : : /* Adjust the pointer by the difference to first_stmt. */
11255 : 3178 : data_reference_p ptrdr
11256 : : = STMT_VINFO_DATA_REF (first_stmt_info_for_drptr);
11257 : 3178 : tree diff = fold_convert (sizetype,
11258 : : size_binop (MINUS_EXPR,
11259 : : DR_INIT (first_dr_info->dr),
11260 : : DR_INIT (ptrdr)));
11261 : 3178 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11262 : : stmt_info, diff);
11263 : 3178 : if (alignment_support_scheme == dr_explicit_realign)
11264 : : {
11265 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info_for_drptr,
11266 : : vectype, gsi,
11267 : : &realignment_token,
11268 : : alignment_support_scheme,
11269 : : dataref_ptr, &at_loop);
11270 : 0 : gcc_assert (!compute_in_loop);
11271 : : }
11272 : : }
11273 : : else
11274 : 151150 : dataref_ptr
11275 : 151150 : = vect_create_data_ref_ptr (vinfo, first_stmt_info, aggr_type,
11276 : : at_loop,
11277 : : offset, &dummy, gsi, &ptr_incr,
11278 : : simd_lane_access_p, bump);
11279 : : }
11280 : : else if (!costing_p)
11281 : : {
11282 : : gcc_assert (!LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo));
11283 : : if (dataref_offset)
11284 : : dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump);
11285 : : else
11286 : : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11287 : : stmt_info, bump);
11288 : : }
11289 : :
11290 : 500555 : auto_vec<tree> dr_chain;
11291 : 500555 : if (grouped_load || ls.slp_perm)
11292 : 46534 : dr_chain.create (vec_num);
11293 : :
11294 : : gimple *new_stmt = NULL;
11295 : 1300855 : for (i = 0; i < vec_num; i++)
11296 : : {
11297 : 800300 : tree final_mask = NULL_TREE;
11298 : 800300 : tree final_len = NULL_TREE;
11299 : 800300 : tree bias = NULL_TREE;
11300 : :
11301 : 800300 : if (!costing_p)
11302 : : {
11303 : 206259 : if (mask_node)
11304 : 632 : vec_mask = vec_masks[i];
11305 : 206259 : if (loop_masks)
11306 : 48 : final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
11307 : : vec_num, vectype, i);
11308 : 206259 : if (vec_mask)
11309 : 632 : final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
11310 : : final_mask, vec_mask, gsi);
11311 : :
11312 : 206259 : if (i > 0)
11313 : 50302 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr,
11314 : : gsi, stmt_info, bump);
11315 : : }
11316 : :
11317 : : /* 2. Create the vector-load in the loop. */
11318 : 800300 : switch (alignment_support_scheme)
11319 : : {
11320 : 800300 : case dr_aligned:
11321 : 800300 : case dr_unaligned_supported:
11322 : 800300 : {
11323 : 800300 : if (costing_p)
11324 : : break;
11325 : :
11326 : 206259 : unsigned int misalign;
11327 : 206259 : unsigned HOST_WIDE_INT align;
11328 : 206259 : align = known_alignment (DR_TARGET_ALIGNMENT (first_dr_info));
11329 : 206259 : if (alignment_support_scheme == dr_aligned)
11330 : : misalign = 0;
11331 : 127160 : else if (misalignment == DR_MISALIGNMENT_UNKNOWN)
11332 : : {
11333 : 102601 : align = dr_alignment (vect_dr_behavior (vinfo, first_dr_info));
11334 : 102601 : misalign = 0;
11335 : : }
11336 : : else
11337 : 24559 : misalign = misalignment;
11338 : 206259 : if (dataref_offset == NULL_TREE
11339 : 204132 : && TREE_CODE (dataref_ptr) == SSA_NAME)
11340 : 137824 : set_ptr_info_alignment (get_ptr_info (dataref_ptr), align,
11341 : : misalign);
11342 : 206259 : align = least_bit_hwi (misalign | align);
11343 : :
11344 : : /* Compute IFN when LOOP_LENS or final_mask valid. */
11345 : 206259 : machine_mode vmode = TYPE_MODE (vectype);
11346 : 206259 : machine_mode new_vmode = vmode;
11347 : 206259 : internal_fn partial_ifn = IFN_LAST;
11348 : 206259 : if (loop_lens)
11349 : : {
11350 : 0 : opt_machine_mode new_ovmode
11351 : 0 : = get_len_load_store_mode (vmode, true, &partial_ifn);
11352 : 0 : new_vmode = new_ovmode.require ();
11353 : 0 : unsigned factor
11354 : 0 : = (new_ovmode == vmode) ? 1 : GET_MODE_UNIT_SIZE (vmode);
11355 : 0 : final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
11356 : : vec_num, vectype, i, factor);
11357 : : }
11358 : 206259 : else if (final_mask)
11359 : : {
11360 : 660 : if (!can_vec_mask_load_store_p (vmode,
11361 : 660 : TYPE_MODE
11362 : : (TREE_TYPE (final_mask)),
11363 : : true, &partial_ifn))
11364 : 0 : gcc_unreachable ();
11365 : : }
11366 : :
11367 : 206259 : if (partial_ifn == IFN_MASK_LEN_LOAD)
11368 : : {
11369 : 0 : if (!final_len)
11370 : : {
11371 : : /* Pass VF value to 'len' argument of
11372 : : MASK_LEN_LOAD if LOOP_LENS is invalid. */
11373 : 0 : final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
11374 : : }
11375 : 0 : if (!final_mask)
11376 : : {
11377 : : /* Pass all ones value to 'mask' argument of
11378 : : MASK_LEN_LOAD if final_mask is invalid. */
11379 : 0 : mask_vectype = truth_type_for (vectype);
11380 : 0 : final_mask = build_minus_one_cst (mask_vectype);
11381 : : }
11382 : : }
11383 : 206259 : if (final_len)
11384 : : {
11385 : 0 : signed char biasval
11386 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
11387 : 0 : bias = build_int_cst (intQI_type_node, biasval);
11388 : : }
11389 : :
11390 : 206259 : tree vec_els;
11391 : :
11392 : 206259 : if (final_len)
11393 : : {
11394 : 0 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
11395 : 0 : gcall *call;
11396 : 0 : if (partial_ifn == IFN_MASK_LEN_LOAD)
11397 : : {
11398 : 0 : vec_els = vect_get_mask_load_else (maskload_elsval,
11399 : : vectype);
11400 : 0 : if (type_mode_padding_p
11401 : 0 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
11402 : 0 : need_zeroing = true;
11403 : 0 : call = gimple_build_call_internal (IFN_MASK_LEN_LOAD,
11404 : : 6, dataref_ptr, ptr,
11405 : : final_mask, vec_els,
11406 : : final_len, bias);
11407 : : }
11408 : : else
11409 : 0 : call = gimple_build_call_internal (IFN_LEN_LOAD, 4,
11410 : : dataref_ptr, ptr,
11411 : : final_len, bias);
11412 : 0 : gimple_call_set_nothrow (call, true);
11413 : 0 : new_stmt = call;
11414 : 0 : data_ref = NULL_TREE;
11415 : :
11416 : : /* Need conversion if it's wrapped with VnQI. */
11417 : 0 : if (vmode != new_vmode)
11418 : : {
11419 : 0 : tree new_vtype
11420 : 0 : = build_vector_type_for_mode (unsigned_intQI_type_node,
11421 : : new_vmode);
11422 : 0 : tree var = vect_get_new_ssa_name (new_vtype,
11423 : : vect_simple_var);
11424 : 0 : gimple_set_lhs (call, var);
11425 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, call,
11426 : : gsi);
11427 : 0 : tree op = build1 (VIEW_CONVERT_EXPR, vectype, var);
11428 : 0 : new_stmt = gimple_build_assign (vec_dest,
11429 : : VIEW_CONVERT_EXPR, op);
11430 : : }
11431 : : }
11432 : 206259 : else if (final_mask)
11433 : : {
11434 : 660 : tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT);
11435 : 660 : vec_els = vect_get_mask_load_else (maskload_elsval, vectype);
11436 : 660 : if (type_mode_padding_p
11437 : 660 : && maskload_elsval != MASK_LOAD_ELSE_ZERO)
11438 : 0 : need_zeroing = true;
11439 : 660 : gcall *call = gimple_build_call_internal (IFN_MASK_LOAD, 4,
11440 : : dataref_ptr, ptr,
11441 : : final_mask,
11442 : : vec_els);
11443 : 660 : gimple_call_set_nothrow (call, true);
11444 : 660 : new_stmt = call;
11445 : 660 : data_ref = NULL_TREE;
11446 : : }
11447 : : else
11448 : : {
11449 : 205599 : tree ltype = vectype;
11450 : 205599 : tree new_vtype = NULL_TREE;
11451 : 205599 : unsigned HOST_WIDE_INT gap = DR_GROUP_GAP (first_stmt_info);
11452 : 205599 : unsigned HOST_WIDE_INT dr_size
11453 : 205599 : = vect_get_scalar_dr_size (first_dr_info);
11454 : 205599 : poly_int64 off = 0;
11455 : 205599 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11456 : 1413 : off = (TYPE_VECTOR_SUBPARTS (vectype) - 1) * -dr_size;
11457 : 205599 : unsigned int vect_align
11458 : 205599 : = vect_known_alignment_in_bytes (first_dr_info, vectype,
11459 : 205599 : off);
11460 : : /* Try to use a single smaller load when we are about
11461 : : to load excess elements compared to the unrolled
11462 : : scalar loop. */
11463 : 205599 : if (known_gt ((i + 1) * nunits,
11464 : : (group_size * vf - gap)))
11465 : : {
11466 : 2086 : poly_uint64 remain = ((group_size * vf - gap) - i * nunits);
11467 : 2086 : if (known_ge ((i + 1) * nunits - (group_size * vf - gap),
11468 : : nunits))
11469 : : /* DR will be unused. */
11470 : : ltype = NULL_TREE;
11471 : 1661 : else if (known_ge (vect_align,
11472 : : tree_to_poly_uint64
11473 : : (TYPE_SIZE_UNIT (vectype))))
11474 : : /* Aligned access to excess elements is OK if
11475 : : at least one element is accessed in the
11476 : : scalar loop. */
11477 : : ;
11478 : 1427 : else if (known_gt (vect_align,
11479 : : ((nunits - remain) * dr_size)))
11480 : : /* Aligned access to the gap area when there's
11481 : : at least one element in it is OK. */
11482 : : ;
11483 : : else
11484 : : {
11485 : : /* remain should now be > 0 and < nunits. */
11486 : 1424 : unsigned num;
11487 : 1424 : if (known_ne (remain, 0u)
11488 : 1424 : && constant_multiple_p (nunits, remain, &num))
11489 : : {
11490 : 1019 : tree ptype;
11491 : 1019 : new_vtype
11492 : 1019 : = vector_vector_composition_type (vectype, num,
11493 : : &ptype);
11494 : 1019 : if (new_vtype)
11495 : 1019 : ltype = ptype;
11496 : : }
11497 : : /* Else use multiple loads or a masked load? */
11498 : : /* For loop vectorization we now should have
11499 : : an alternate type or LOOP_VINFO_PEELING_FOR_GAPS
11500 : : set. */
11501 : 1424 : if (loop_vinfo)
11502 : 1387 : gcc_assert (new_vtype
11503 : : || LOOP_VINFO_PEELING_FOR_GAPS
11504 : : (loop_vinfo));
11505 : : /* But still reduce the access size to the next
11506 : : required power-of-two so peeling a single
11507 : : scalar iteration is sufficient. */
11508 : 1424 : unsigned HOST_WIDE_INT cremain;
11509 : 1424 : if (remain.is_constant (&cremain))
11510 : : {
11511 : 1424 : unsigned HOST_WIDE_INT cpart_size
11512 : 1424 : = 1 << ceil_log2 (cremain);
11513 : 1424 : if (known_gt (nunits, cpart_size)
11514 : 1424 : && constant_multiple_p (nunits, cpart_size,
11515 : : &num))
11516 : : {
11517 : 1031 : tree ptype;
11518 : 1031 : new_vtype
11519 : 2062 : = vector_vector_composition_type (vectype,
11520 : 1031 : num,
11521 : : &ptype);
11522 : 1031 : if (new_vtype)
11523 : 1031 : ltype = ptype;
11524 : : }
11525 : : }
11526 : : }
11527 : : }
11528 : 205599 : tree offset = (dataref_offset ? dataref_offset
11529 : 203472 : : build_int_cst (ref_type, 0));
11530 : 205599 : if (!ltype)
11531 : : ;
11532 : 205174 : else if (ltype != vectype
11533 : 205174 : && memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11534 : : {
11535 : 21 : poly_uint64 gap_offset
11536 : 21 : = (tree_to_poly_uint64 (TYPE_SIZE_UNIT (vectype))
11537 : 21 : - tree_to_poly_uint64 (TYPE_SIZE_UNIT (ltype)));
11538 : 21 : tree gapcst = build_int_cstu (ref_type, gap_offset);
11539 : 21 : offset = size_binop (PLUS_EXPR, offset, gapcst);
11540 : : }
11541 : 205599 : if (ltype)
11542 : : {
11543 : 205174 : data_ref = fold_build2 (MEM_REF, ltype,
11544 : : dataref_ptr, offset);
11545 : 205174 : if (alignment_support_scheme == dr_aligned
11546 : 205174 : && align >= TYPE_ALIGN_UNIT (ltype))
11547 : : ;
11548 : : else
11549 : 126524 : TREE_TYPE (data_ref)
11550 : 253048 : = build_aligned_type (TREE_TYPE (data_ref),
11551 : : align * BITS_PER_UNIT);
11552 : : }
11553 : 205599 : if (!ltype)
11554 : 425 : data_ref = build_constructor (vectype, NULL);
11555 : 205174 : else if (ltype != vectype)
11556 : : {
11557 : 1031 : vect_copy_ref_info (data_ref,
11558 : 1031 : DR_REF (first_dr_info->dr));
11559 : 1031 : tree tem = make_ssa_name (ltype);
11560 : 1031 : new_stmt = gimple_build_assign (tem, data_ref);
11561 : 1031 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
11562 : : gsi);
11563 : 1031 : data_ref = NULL;
11564 : 1031 : vec<constructor_elt, va_gc> *v;
11565 : : /* We've computed 'num' above to statically two
11566 : : or via constant_multiple_p. */
11567 : 1031 : unsigned num
11568 : 1031 : = (exact_div (tree_to_poly_uint64
11569 : 1031 : (TYPE_SIZE_UNIT (vectype)),
11570 : : tree_to_poly_uint64
11571 : 1031 : (TYPE_SIZE_UNIT (ltype)))
11572 : 1031 : .to_constant ());
11573 : 1031 : vec_alloc (v, num);
11574 : 1031 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11575 : : {
11576 : 54 : while (--num)
11577 : 54 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
11578 : : build_zero_cst (ltype));
11579 : 21 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem);
11580 : : }
11581 : : else
11582 : : {
11583 : 1010 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tem);
11584 : 1010 : while (--num)
11585 : 2350 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
11586 : : build_zero_cst (ltype));
11587 : : }
11588 : 1031 : gcc_assert (new_vtype != NULL_TREE);
11589 : 1031 : if (new_vtype == vectype)
11590 : 1001 : new_stmt
11591 : 1001 : = gimple_build_assign (vec_dest,
11592 : : build_constructor (vectype, v));
11593 : : else
11594 : : {
11595 : 30 : tree new_vname = make_ssa_name (new_vtype);
11596 : 30 : new_stmt
11597 : 30 : = gimple_build_assign (new_vname,
11598 : : build_constructor (new_vtype,
11599 : : v));
11600 : 30 : vect_finish_stmt_generation (vinfo, stmt_info,
11601 : : new_stmt, gsi);
11602 : 30 : new_stmt
11603 : 30 : = gimple_build_assign (vec_dest,
11604 : : build1 (VIEW_CONVERT_EXPR,
11605 : : vectype, new_vname));
11606 : : }
11607 : : }
11608 : : }
11609 : : break;
11610 : : }
11611 : 0 : case dr_explicit_realign:
11612 : 0 : {
11613 : 0 : if (costing_p)
11614 : : break;
11615 : 0 : tree ptr, bump;
11616 : :
11617 : 0 : tree vs = size_int (TYPE_VECTOR_SUBPARTS (vectype));
11618 : :
11619 : 0 : if (compute_in_loop)
11620 : 0 : msq = vect_setup_realignment (vinfo, first_stmt_info, vectype,
11621 : : gsi, &realignment_token,
11622 : : dr_explicit_realign,
11623 : : dataref_ptr, NULL);
11624 : :
11625 : 0 : if (TREE_CODE (dataref_ptr) == SSA_NAME)
11626 : 0 : ptr = copy_ssa_name (dataref_ptr);
11627 : : else
11628 : 0 : ptr = make_ssa_name (TREE_TYPE (dataref_ptr));
11629 : : // For explicit realign the target alignment should be
11630 : : // known at compile time.
11631 : 0 : unsigned HOST_WIDE_INT align
11632 : 0 : = DR_TARGET_ALIGNMENT (first_dr_info).to_constant ();
11633 : 0 : new_stmt = gimple_build_assign (ptr, BIT_AND_EXPR, dataref_ptr,
11634 : : build_int_cst
11635 : 0 : (TREE_TYPE (dataref_ptr),
11636 : 0 : -(HOST_WIDE_INT) align));
11637 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11638 : 0 : data_ref = build2 (MEM_REF, vectype,
11639 : : ptr, build_int_cst (ref_type, 0));
11640 : 0 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
11641 : 0 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11642 : 0 : new_stmt = gimple_build_assign (vec_dest, data_ref);
11643 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
11644 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
11645 : 0 : gimple_move_vops (new_stmt, stmt_info->stmt);
11646 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11647 : 0 : msq = new_temp;
11648 : :
11649 : 0 : bump = size_binop (MULT_EXPR, vs, TYPE_SIZE_UNIT (elem_type));
11650 : 0 : bump = size_binop (MINUS_EXPR, bump, size_one_node);
11651 : 0 : ptr = bump_vector_ptr (vinfo, dataref_ptr, NULL, gsi, stmt_info,
11652 : : bump);
11653 : 0 : new_stmt = gimple_build_assign (NULL_TREE, BIT_AND_EXPR, ptr,
11654 : 0 : build_int_cst (TREE_TYPE (ptr),
11655 : 0 : -(HOST_WIDE_INT) align));
11656 : 0 : if (TREE_CODE (ptr) == SSA_NAME)
11657 : 0 : ptr = copy_ssa_name (ptr, new_stmt);
11658 : : else
11659 : 0 : ptr = make_ssa_name (TREE_TYPE (ptr), new_stmt);
11660 : 0 : gimple_assign_set_lhs (new_stmt, ptr);
11661 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11662 : 0 : data_ref = build2 (MEM_REF, vectype,
11663 : : ptr, build_int_cst (ref_type, 0));
11664 : 0 : break;
11665 : : }
11666 : 0 : case dr_explicit_realign_optimized:
11667 : 0 : {
11668 : 0 : if (costing_p)
11669 : : break;
11670 : 0 : if (TREE_CODE (dataref_ptr) == SSA_NAME)
11671 : 0 : new_temp = copy_ssa_name (dataref_ptr);
11672 : : else
11673 : 0 : new_temp = make_ssa_name (TREE_TYPE (dataref_ptr));
11674 : : // We should only be doing this if we know the target
11675 : : // alignment at compile time.
11676 : 0 : unsigned HOST_WIDE_INT align
11677 : 0 : = DR_TARGET_ALIGNMENT (first_dr_info).to_constant ();
11678 : 0 : new_stmt = gimple_build_assign (new_temp, BIT_AND_EXPR, dataref_ptr,
11679 : 0 : build_int_cst (TREE_TYPE (dataref_ptr),
11680 : 0 : -(HOST_WIDE_INT) align));
11681 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11682 : 0 : data_ref = build2 (MEM_REF, vectype, new_temp,
11683 : : build_int_cst (ref_type, 0));
11684 : 0 : break;
11685 : : }
11686 : 0 : default:
11687 : 0 : gcc_unreachable ();
11688 : : }
11689 : :
11690 : : /* One common place to cost the above vect load for different
11691 : : alignment support schemes. */
11692 : 800300 : if (costing_p)
11693 : : {
11694 : : /* For the prologue cost for realign,
11695 : : we only need to count it once for the whole group. */
11696 : 594041 : bool first_stmt_info_p = first_stmt_info == stmt_info;
11697 : 594041 : bool add_realign_cost = first_stmt_info_p && i == 0;
11698 : 594041 : if (memory_access_type == VMAT_CONTIGUOUS
11699 : 594041 : || memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11700 : : {
11701 : : /* Leave realign cases alone to keep them simple. */
11702 : 594041 : if (alignment_support_scheme == dr_explicit_realign_optimized
11703 : : || alignment_support_scheme == dr_explicit_realign)
11704 : 0 : vect_get_load_cost (vinfo, stmt_info, slp_node, 1,
11705 : : alignment_support_scheme, misalignment,
11706 : : add_realign_cost, &inside_cost,
11707 : : &prologue_cost, cost_vec, cost_vec,
11708 : : true);
11709 : : else
11710 : 594041 : n_adjacent_loads++;
11711 : : }
11712 : : }
11713 : : else
11714 : : {
11715 : 206259 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11716 : : /* DATA_REF is null if we've already built the statement. */
11717 : 206259 : if (data_ref)
11718 : : {
11719 : 204568 : vect_copy_ref_info (data_ref, DR_REF (first_dr_info->dr));
11720 : 204568 : new_stmt = gimple_build_assign (vec_dest, data_ref);
11721 : : }
11722 : :
11723 : 412518 : new_temp = (need_zeroing
11724 : 206259 : ? make_ssa_name (vectype)
11725 : 206259 : : make_ssa_name (vec_dest, new_stmt));
11726 : 206259 : gimple_set_lhs (new_stmt, new_temp);
11727 : 206259 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11728 : :
11729 : : /* If we need to explicitly zero inactive elements emit a
11730 : : VEC_COND_EXPR that does so. */
11731 : 206259 : if (need_zeroing)
11732 : : {
11733 : 0 : vec_els = vect_get_mask_load_else (MASK_LOAD_ELSE_ZERO,
11734 : : vectype);
11735 : :
11736 : 0 : tree new_temp2 = make_ssa_name (vec_dest, new_stmt);
11737 : 0 : new_stmt = gimple_build_assign (new_temp2, VEC_COND_EXPR,
11738 : : final_mask, new_temp, vec_els);
11739 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
11740 : : gsi);
11741 : 0 : new_temp = new_temp2;
11742 : : }
11743 : : }
11744 : :
11745 : : /* 3. Handle explicit realignment if necessary/supported.
11746 : : Create in loop:
11747 : : vec_dest = realign_load (msq, lsq, realignment_token) */
11748 : 800300 : if (!costing_p
11749 : 206259 : && (alignment_support_scheme == dr_explicit_realign_optimized
11750 : : || alignment_support_scheme == dr_explicit_realign))
11751 : : {
11752 : 0 : lsq = gimple_assign_lhs (new_stmt);
11753 : 0 : if (!realignment_token)
11754 : 0 : realignment_token = dataref_ptr;
11755 : 0 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
11756 : 0 : new_stmt = gimple_build_assign (vec_dest, REALIGN_LOAD_EXPR, msq,
11757 : : lsq, realignment_token);
11758 : 0 : new_temp = make_ssa_name (vec_dest, new_stmt);
11759 : 0 : gimple_assign_set_lhs (new_stmt, new_temp);
11760 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
11761 : :
11762 : 0 : if (alignment_support_scheme == dr_explicit_realign_optimized)
11763 : : {
11764 : 0 : gcc_assert (phi);
11765 : 0 : if (i == vec_num - 1)
11766 : 0 : add_phi_arg (phi, lsq, loop_latch_edge (containing_loop),
11767 : : UNKNOWN_LOCATION);
11768 : : msq = lsq;
11769 : : }
11770 : : }
11771 : :
11772 : 800300 : if (memory_access_type == VMAT_CONTIGUOUS_REVERSE)
11773 : : {
11774 : 5840 : if (costing_p)
11775 : 4427 : inside_cost = record_stmt_cost (cost_vec, 1, vec_perm,
11776 : : slp_node, 0, vect_body);
11777 : : else
11778 : : {
11779 : 1413 : tree perm_mask = perm_mask_for_reverse (vectype);
11780 : 1413 : new_temp = permute_vec_elements (vinfo, new_temp, new_temp,
11781 : : perm_mask, stmt_info, gsi);
11782 : 1413 : new_stmt = SSA_NAME_DEF_STMT (new_temp);
11783 : : }
11784 : : }
11785 : :
11786 : : /* Collect vector loads and later create their permutation in
11787 : : vect_transform_slp_perm_load. */
11788 : 800300 : if (!costing_p && (grouped_load || ls.slp_perm))
11789 : 32053 : dr_chain.quick_push (new_temp);
11790 : :
11791 : : /* Store vector loads in the corresponding SLP_NODE. */
11792 : 206259 : if (!costing_p && !ls.slp_perm)
11793 : 174206 : slp_node->push_vec_def (new_stmt);
11794 : :
11795 : : /* With SLP permutation we load the gaps as well, without
11796 : : we need to skip the gaps after we manage to fully load
11797 : : all elements. group_gap_adj is DR_GROUP_SIZE here. */
11798 : 800300 : group_elt += nunits;
11799 : 800300 : if (!costing_p
11800 : 206259 : && maybe_ne (group_gap_adj, 0U)
11801 : 18712 : && !ls.slp_perm
11802 : 818650 : && known_eq (group_elt, group_size - group_gap_adj))
11803 : : {
11804 : 15059 : poly_wide_int bump_val
11805 : 15059 : = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj);
11806 : 15059 : if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step) == -1)
11807 : 0 : bump_val = -bump_val;
11808 : 15059 : tree bump = wide_int_to_tree (sizetype, bump_val);
11809 : 15059 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11810 : : stmt_info, bump);
11811 : 15059 : group_elt = 0;
11812 : 15059 : }
11813 : : }
11814 : : /* Bump the vector pointer to account for a gap or for excess
11815 : : elements loaded for a permuted SLP load. */
11816 : 500555 : if (!costing_p
11817 : 155957 : && maybe_ne (group_gap_adj, 0U)
11818 : 515798 : && ls.slp_perm)
11819 : : {
11820 : 184 : poly_wide_int bump_val
11821 : 184 : = (wi::to_wide (TYPE_SIZE_UNIT (elem_type)) * group_gap_adj);
11822 : 184 : if (tree_int_cst_sgn (vect_dr_behavior (vinfo, dr_info)->step) == -1)
11823 : 9 : bump_val = -bump_val;
11824 : 184 : tree bump = wide_int_to_tree (sizetype, bump_val);
11825 : 184 : dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi,
11826 : : stmt_info, bump);
11827 : 184 : }
11828 : :
11829 : 500555 : if (ls.slp_perm)
11830 : : {
11831 : : /* For SLP we know we've seen all possible uses of dr_chain so
11832 : : direct vect_transform_slp_perm_load to DCE the unused parts.
11833 : : ??? This is a hack to prevent compile-time issues as seen
11834 : : in PR101120 and friends. */
11835 : 46534 : if (costing_p)
11836 : : {
11837 : 30860 : gcc_assert (ls.n_perms != -1U);
11838 : 30860 : if (ls.n_perms != 0)
11839 : 30461 : inside_cost = record_stmt_cost (cost_vec, ls.n_perms, vec_perm,
11840 : : slp_node, 0, vect_body);
11841 : : }
11842 : : else
11843 : : {
11844 : 15674 : unsigned n_perms2;
11845 : 15674 : bool ok = vect_transform_slp_perm_load (vinfo, slp_node, dr_chain,
11846 : : gsi, vf, false, &n_perms2,
11847 : : nullptr, true);
11848 : 15674 : gcc_assert (ok && ls.n_perms == n_perms2);
11849 : : }
11850 : : }
11851 : :
11852 : 500555 : if (costing_p)
11853 : : {
11854 : 344598 : gcc_assert (memory_access_type == VMAT_CONTIGUOUS
11855 : : || memory_access_type == VMAT_CONTIGUOUS_REVERSE);
11856 : 344598 : if (n_adjacent_loads > 0)
11857 : 344598 : vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
11858 : : alignment_support_scheme, misalignment, false,
11859 : : &inside_cost, &prologue_cost, cost_vec, cost_vec,
11860 : : true);
11861 : 344598 : if (dump_enabled_p ())
11862 : 22781 : dump_printf_loc (MSG_NOTE, vect_location,
11863 : : "vect_model_load_cost: inside_cost = %u, "
11864 : : "prologue_cost = %u .\n",
11865 : : inside_cost, prologue_cost);
11866 : : }
11867 : :
11868 : 500555 : return true;
11869 : 1633926 : }
11870 : :
11871 : : /* Function vect_is_simple_cond.
11872 : :
11873 : : Input:
11874 : : LOOP - the loop that is being vectorized.
11875 : : COND - Condition that is checked for simple use.
11876 : :
11877 : : Output:
11878 : : *COMP_VECTYPE - the vector type for the comparison.
11879 : : *DTS - The def types for the arguments of the comparison
11880 : :
11881 : : Returns whether a COND can be vectorized. Checks whether
11882 : : condition operands are supportable using vec_is_simple_use. */
11883 : :
11884 : : static bool
11885 : 28037 : vect_is_simple_cond (tree cond, vec_info *vinfo,
11886 : : slp_tree slp_node, tree *comp_vectype,
11887 : : enum vect_def_type *dts, tree vectype)
11888 : : {
11889 : 28037 : tree lhs, rhs;
11890 : 28037 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
11891 : 28037 : slp_tree slp_op;
11892 : :
11893 : : /* Mask case. */
11894 : 28037 : if (TREE_CODE (cond) == SSA_NAME
11895 : 28037 : && VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (cond)))
11896 : : {
11897 : 28025 : if (!vect_is_simple_use (vinfo, slp_node, 0, &cond,
11898 : : &slp_op, &dts[0], comp_vectype)
11899 : 28025 : || !*comp_vectype
11900 : 56031 : || !VECTOR_BOOLEAN_TYPE_P (*comp_vectype))
11901 : : return false;
11902 : : return true;
11903 : : }
11904 : :
11905 : 12 : if (!COMPARISON_CLASS_P (cond))
11906 : : return false;
11907 : :
11908 : 0 : lhs = TREE_OPERAND (cond, 0);
11909 : 0 : rhs = TREE_OPERAND (cond, 1);
11910 : :
11911 : 0 : if (TREE_CODE (lhs) == SSA_NAME)
11912 : : {
11913 : 0 : if (!vect_is_simple_use (vinfo, slp_node, 0,
11914 : : &lhs, &slp_op, &dts[0], &vectype1))
11915 : : return false;
11916 : : }
11917 : 0 : else if (TREE_CODE (lhs) == INTEGER_CST || TREE_CODE (lhs) == REAL_CST
11918 : 0 : || TREE_CODE (lhs) == FIXED_CST)
11919 : 0 : dts[0] = vect_constant_def;
11920 : : else
11921 : : return false;
11922 : :
11923 : 0 : if (TREE_CODE (rhs) == SSA_NAME)
11924 : : {
11925 : 0 : if (!vect_is_simple_use (vinfo, slp_node, 1,
11926 : : &rhs, &slp_op, &dts[1], &vectype2))
11927 : : return false;
11928 : : }
11929 : 0 : else if (TREE_CODE (rhs) == INTEGER_CST || TREE_CODE (rhs) == REAL_CST
11930 : 0 : || TREE_CODE (rhs) == FIXED_CST)
11931 : 0 : dts[1] = vect_constant_def;
11932 : : else
11933 : : return false;
11934 : :
11935 : 0 : if (vectype1 && vectype2
11936 : 0 : && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1),
11937 : 0 : TYPE_VECTOR_SUBPARTS (vectype2)))
11938 : 0 : return false;
11939 : :
11940 : 0 : *comp_vectype = vectype1 ? vectype1 : vectype2;
11941 : : /* Invariant comparison. */
11942 : 0 : if (! *comp_vectype)
11943 : : {
11944 : 0 : tree scalar_type = TREE_TYPE (lhs);
11945 : 0 : if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type))
11946 : 0 : *comp_vectype = truth_type_for (vectype);
11947 : : else
11948 : : {
11949 : : /* If we can widen the comparison to match vectype do so. */
11950 : 0 : if (INTEGRAL_TYPE_P (scalar_type)
11951 : 0 : && !slp_node
11952 : 0 : && tree_int_cst_lt (TYPE_SIZE (scalar_type),
11953 : 0 : TYPE_SIZE (TREE_TYPE (vectype))))
11954 : 0 : scalar_type = build_nonstandard_integer_type
11955 : 0 : (vector_element_bits (vectype), TYPE_UNSIGNED (scalar_type));
11956 : 0 : *comp_vectype = get_vectype_for_scalar_type (vinfo, scalar_type,
11957 : : slp_node);
11958 : : }
11959 : : }
11960 : :
11961 : : return true;
11962 : : }
11963 : :
11964 : : /* vectorizable_condition.
11965 : :
11966 : : Check if STMT_INFO is conditional modify expression that can be vectorized.
11967 : : If COST_VEC is passed, calculate costs but don't change anything,
11968 : : otherwise, vectorize STMT_INFO: create a vectorized stmt using
11969 : : VEC_COND_EXPR to replace it, and insert it at GSI.
11970 : :
11971 : : When STMT_INFO is vectorized as a nested cycle, for_reduction is true.
11972 : :
11973 : : Return true if STMT_INFO is vectorizable in this way. */
11974 : :
11975 : : static bool
11976 : 583668 : vectorizable_condition (vec_info *vinfo,
11977 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
11978 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
11979 : : {
11980 : 583668 : tree scalar_dest = NULL_TREE;
11981 : 583668 : tree vec_dest = NULL_TREE;
11982 : 583668 : tree cond_expr, cond_expr0 = NULL_TREE, cond_expr1 = NULL_TREE;
11983 : 583668 : tree then_clause, else_clause;
11984 : 583668 : tree comp_vectype = NULL_TREE;
11985 : 583668 : tree vec_cond_lhs = NULL_TREE, vec_cond_rhs = NULL_TREE;
11986 : 583668 : tree vec_then_clause = NULL_TREE, vec_else_clause = NULL_TREE;
11987 : 583668 : tree vec_compare;
11988 : 583668 : tree new_temp;
11989 : 583668 : loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
11990 : 583668 : enum vect_def_type dts[4]
11991 : : = {vect_unknown_def_type, vect_unknown_def_type,
11992 : : vect_unknown_def_type, vect_unknown_def_type};
11993 : 583668 : enum tree_code code, cond_code, bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
11994 : 583668 : int i;
11995 : 583668 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
11996 : 583668 : vec<tree> vec_oprnds0 = vNULL;
11997 : 583668 : vec<tree> vec_oprnds1 = vNULL;
11998 : 583668 : vec<tree> vec_oprnds2 = vNULL;
11999 : 583668 : vec<tree> vec_oprnds3 = vNULL;
12000 : 583668 : tree vec_cmp_type;
12001 : 583668 : bool masked = false;
12002 : :
12003 : 583668 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
12004 : : return false;
12005 : :
12006 : : /* Is vectorizable conditional operation? */
12007 : 906151 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
12008 : 350487 : if (!stmt)
12009 : : return false;
12010 : :
12011 : 350487 : code = gimple_assign_rhs_code (stmt);
12012 : 350487 : if (code != COND_EXPR)
12013 : : return false;
12014 : :
12015 : 28037 : int reduc_index = SLP_TREE_REDUC_IDX (slp_node);
12016 : 28037 : vect_reduction_type reduction_type = TREE_CODE_REDUCTION;
12017 : 28037 : bool nested_cycle_p = false;
12018 : 28037 : bool for_reduction = vect_is_reduction (stmt_info);
12019 : 28037 : if (for_reduction)
12020 : : {
12021 : 545 : if (SLP_TREE_LANES (slp_node) > 1)
12022 : : return false;
12023 : : /* ??? With a reduction path we do not get at the reduction info from
12024 : : every stmt, use the conservative default setting then. */
12025 : 623 : if (STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)))
12026 : : {
12027 : 527 : vect_reduc_info reduc_info
12028 : 527 : = info_for_reduction (loop_vinfo, slp_node);
12029 : 527 : reduction_type = VECT_REDUC_INFO_TYPE (reduc_info);
12030 : 527 : nested_cycle_p = nested_in_vect_loop_p (LOOP_VINFO_LOOP (loop_vinfo),
12031 : : stmt_info);
12032 : : }
12033 : : }
12034 : : else
12035 : : {
12036 : 27492 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
12037 : : return false;
12038 : : }
12039 : :
12040 : 28037 : tree vectype = SLP_TREE_VECTYPE (slp_node);
12041 : 28037 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
12042 : :
12043 : 28037 : int vec_num = vect_get_num_copies (vinfo, slp_node);
12044 : :
12045 : 28037 : cond_expr = gimple_assign_rhs1 (stmt);
12046 : 28037 : gcc_assert (! COMPARISON_CLASS_P (cond_expr));
12047 : :
12048 : 28037 : if (!vect_is_simple_cond (cond_expr, vinfo, slp_node,
12049 : : &comp_vectype, &dts[0], vectype)
12050 : 28037 : || !comp_vectype)
12051 : : return false;
12052 : :
12053 : 28006 : unsigned op_adjust = COMPARISON_CLASS_P (cond_expr) ? 1 : 0;
12054 : 28006 : slp_tree then_slp_node, else_slp_node;
12055 : 28006 : if (!vect_is_simple_use (vinfo, slp_node, 1 + op_adjust,
12056 : : &then_clause, &then_slp_node, &dts[2], &vectype1))
12057 : : return false;
12058 : 28006 : if (!vect_is_simple_use (vinfo, slp_node, 2 + op_adjust,
12059 : : &else_clause, &else_slp_node, &dts[3], &vectype2))
12060 : : return false;
12061 : :
12062 : 28006 : if (vectype1 && !useless_type_conversion_p (vectype, vectype1))
12063 : : return false;
12064 : :
12065 : 28006 : if (vectype2 && !useless_type_conversion_p (vectype, vectype2))
12066 : : return false;
12067 : :
12068 : 28006 : masked = !COMPARISON_CLASS_P (cond_expr);
12069 : 28006 : vec_cmp_type = truth_type_for (comp_vectype);
12070 : 28006 : if (vec_cmp_type == NULL_TREE
12071 : 56012 : || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype),
12072 : 28006 : TYPE_VECTOR_SUBPARTS (vec_cmp_type)))
12073 : 0 : return false;
12074 : :
12075 : 28006 : cond_code = TREE_CODE (cond_expr);
12076 : 28006 : if (!masked)
12077 : : {
12078 : 0 : cond_expr0 = TREE_OPERAND (cond_expr, 0);
12079 : 0 : cond_expr1 = TREE_OPERAND (cond_expr, 1);
12080 : : }
12081 : :
12082 : : /* For conditional reductions, the "then" value needs to be the candidate
12083 : : value calculated by this iteration while the "else" value needs to be
12084 : : the result carried over from previous iterations. If the COND_EXPR
12085 : : is the other way around, we need to swap it. */
12086 : 28006 : bool must_invert_cmp_result = false;
12087 : 28006 : if (reduction_type == EXTRACT_LAST_REDUCTION && reduc_index == 1)
12088 : : {
12089 : 0 : if (masked)
12090 : 0 : must_invert_cmp_result = true;
12091 : : else
12092 : : {
12093 : 0 : bool honor_nans = HONOR_NANS (TREE_TYPE (cond_expr0));
12094 : 0 : tree_code new_code = invert_tree_comparison (cond_code, honor_nans);
12095 : 0 : if (new_code == ERROR_MARK)
12096 : : must_invert_cmp_result = true;
12097 : : else
12098 : : {
12099 : 0 : cond_code = new_code;
12100 : : /* Make sure we don't accidentally use the old condition. */
12101 : 0 : cond_expr = NULL_TREE;
12102 : : }
12103 : : }
12104 : : /* ??? The vectorized operand query below doesn't allow swapping
12105 : : this way for SLP. */
12106 : 0 : return false;
12107 : : /* std::swap (then_clause, else_clause); */
12108 : : }
12109 : :
12110 : 28006 : if (!masked && VECTOR_BOOLEAN_TYPE_P (comp_vectype))
12111 : : {
12112 : : /* Boolean values may have another representation in vectors
12113 : : and therefore we prefer bit operations over comparison for
12114 : : them (which also works for scalar masks). We store opcodes
12115 : : to use in bitop1 and bitop2. Statement is vectorized as
12116 : : BITOP2 (rhs1 BITOP1 rhs2) or rhs1 BITOP2 (BITOP1 rhs2)
12117 : : depending on bitop1 and bitop2 arity. */
12118 : 0 : switch (cond_code)
12119 : : {
12120 : : case GT_EXPR:
12121 : : bitop1 = BIT_NOT_EXPR;
12122 : : bitop2 = BIT_AND_EXPR;
12123 : : break;
12124 : 0 : case GE_EXPR:
12125 : 0 : bitop1 = BIT_NOT_EXPR;
12126 : 0 : bitop2 = BIT_IOR_EXPR;
12127 : 0 : break;
12128 : 0 : case LT_EXPR:
12129 : 0 : bitop1 = BIT_NOT_EXPR;
12130 : 0 : bitop2 = BIT_AND_EXPR;
12131 : 0 : std::swap (cond_expr0, cond_expr1);
12132 : 0 : break;
12133 : 0 : case LE_EXPR:
12134 : 0 : bitop1 = BIT_NOT_EXPR;
12135 : 0 : bitop2 = BIT_IOR_EXPR;
12136 : 0 : std::swap (cond_expr0, cond_expr1);
12137 : 0 : break;
12138 : 0 : case NE_EXPR:
12139 : 0 : bitop1 = BIT_XOR_EXPR;
12140 : 0 : break;
12141 : 0 : case EQ_EXPR:
12142 : 0 : bitop1 = BIT_XOR_EXPR;
12143 : 0 : bitop2 = BIT_NOT_EXPR;
12144 : 0 : break;
12145 : : default:
12146 : : return false;
12147 : : }
12148 : : cond_code = SSA_NAME;
12149 : : }
12150 : :
12151 : 28006 : if (TREE_CODE_CLASS (cond_code) == tcc_comparison
12152 : 0 : && reduction_type == EXTRACT_LAST_REDUCTION
12153 : 28006 : && !expand_vec_cmp_expr_p (comp_vectype, vec_cmp_type, cond_code))
12154 : : {
12155 : 0 : if (dump_enabled_p ())
12156 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12157 : : "reduction comparison operation not supported.\n");
12158 : 0 : return false;
12159 : : }
12160 : :
12161 : 28006 : if (cost_vec)
12162 : : {
12163 : 19519 : if (bitop1 != NOP_EXPR)
12164 : : {
12165 : 0 : machine_mode mode = TYPE_MODE (comp_vectype);
12166 : 0 : optab optab;
12167 : :
12168 : 0 : optab = optab_for_tree_code (bitop1, comp_vectype, optab_default);
12169 : 0 : if (!optab || !can_implement_p (optab, mode))
12170 : 0 : return false;
12171 : :
12172 : 0 : if (bitop2 != NOP_EXPR)
12173 : : {
12174 : 0 : optab = optab_for_tree_code (bitop2, comp_vectype,
12175 : : optab_default);
12176 : 0 : if (!optab || !can_implement_p (optab, mode))
12177 : 0 : return false;
12178 : : }
12179 : : }
12180 : :
12181 : 19519 : vect_cost_for_stmt kind = vector_stmt;
12182 : 19519 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12183 : : /* Count one reduction-like operation per vector. */
12184 : : kind = vec_to_scalar;
12185 : 19519 : else if ((masked && !expand_vec_cond_expr_p (vectype, comp_vectype))
12186 : 19519 : || (!masked
12187 : 0 : && (!expand_vec_cmp_expr_p (comp_vectype, vec_cmp_type,
12188 : : cond_code)
12189 : 0 : || !expand_vec_cond_expr_p (vectype, vec_cmp_type))))
12190 : 2 : return false;
12191 : :
12192 : 19517 : if (!vect_maybe_update_slp_op_vectype (SLP_TREE_CHILDREN (slp_node)[0],
12193 : : comp_vectype)
12194 : 19517 : || (op_adjust == 1
12195 : 0 : && !vect_maybe_update_slp_op_vectype
12196 : 0 : (SLP_TREE_CHILDREN (slp_node)[1], comp_vectype))
12197 : 19517 : || !vect_maybe_update_slp_op_vectype (then_slp_node, vectype)
12198 : 39034 : || !vect_maybe_update_slp_op_vectype (else_slp_node, vectype))
12199 : : {
12200 : 0 : if (dump_enabled_p ())
12201 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12202 : : "incompatible vector types for invariants\n");
12203 : 0 : return false;
12204 : : }
12205 : :
12206 : 19517 : if (loop_vinfo && for_reduction
12207 : 398 : && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
12208 : : {
12209 : 65 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12210 : : {
12211 : 0 : if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST,
12212 : : vectype, OPTIMIZE_FOR_SPEED))
12213 : 0 : vect_record_loop_len (loop_vinfo,
12214 : : &LOOP_VINFO_LENS (loop_vinfo),
12215 : : vec_num, vectype, 1);
12216 : : else
12217 : 0 : vect_record_loop_mask (loop_vinfo,
12218 : : &LOOP_VINFO_MASKS (loop_vinfo),
12219 : : vec_num, vectype, NULL);
12220 : : }
12221 : : /* Extra inactive lanes should be safe for vect_nested_cycle. */
12222 : 65 : else if (!nested_cycle_p)
12223 : : {
12224 : 65 : if (dump_enabled_p ())
12225 : 8 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12226 : : "conditional reduction prevents the use"
12227 : : " of partial vectors.\n");
12228 : 65 : LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
12229 : : }
12230 : : }
12231 : :
12232 : 19517 : SLP_TREE_TYPE (slp_node) = condition_vec_info_type;
12233 : 19517 : vect_model_simple_cost (vinfo, 1, slp_node, cost_vec, kind);
12234 : 19517 : return true;
12235 : : }
12236 : :
12237 : : /* Transform. */
12238 : :
12239 : : /* Handle def. */
12240 : 8487 : scalar_dest = gimple_assign_lhs (stmt);
12241 : 8487 : if (reduction_type != EXTRACT_LAST_REDUCTION)
12242 : 8487 : vec_dest = vect_create_destination_var (scalar_dest, vectype);
12243 : :
12244 : 8487 : bool swap_cond_operands = false;
12245 : :
12246 : : /* See whether another part of the vectorized code applies a loop
12247 : : mask to the condition, or to its inverse. */
12248 : :
12249 : 8487 : vec_loop_masks *masks = NULL;
12250 : 8487 : vec_loop_lens *lens = NULL;
12251 : 8487 : if (loop_vinfo && LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo))
12252 : : {
12253 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12254 : 0 : lens = &LOOP_VINFO_LENS (loop_vinfo);
12255 : : }
12256 : 8487 : else if (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
12257 : : {
12258 : 3 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12259 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
12260 : : else
12261 : : {
12262 : 3 : scalar_cond_masked_key cond (cond_expr, 1);
12263 : 3 : if (loop_vinfo->scalar_cond_masked_set.contains (cond))
12264 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
12265 : : else
12266 : : {
12267 : 3 : bool honor_nans = HONOR_NANS (TREE_TYPE (cond.op0));
12268 : 3 : tree_code orig_code = cond.code;
12269 : 3 : cond.code = invert_tree_comparison (cond.code, honor_nans);
12270 : 3 : if (!masked && loop_vinfo->scalar_cond_masked_set.contains (cond))
12271 : : {
12272 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
12273 : 0 : cond_code = cond.code;
12274 : 0 : swap_cond_operands = true;
12275 : : }
12276 : : else
12277 : : {
12278 : : /* Try the inverse of the current mask. We check if the
12279 : : inverse mask is live and if so we generate a negate of
12280 : : the current mask such that we still honor NaNs. */
12281 : 3 : cond.inverted_p = true;
12282 : 3 : cond.code = orig_code;
12283 : 3 : if (loop_vinfo->scalar_cond_masked_set.contains (cond))
12284 : : {
12285 : 0 : masks = &LOOP_VINFO_MASKS (loop_vinfo);
12286 : 0 : cond_code = cond.code;
12287 : 0 : swap_cond_operands = true;
12288 : 0 : must_invert_cmp_result = true;
12289 : : }
12290 : : }
12291 : : }
12292 : : }
12293 : : }
12294 : :
12295 : : /* Handle cond expr. */
12296 : 8487 : if (masked)
12297 : 8487 : vect_get_vec_defs (vinfo, slp_node,
12298 : : cond_expr, &vec_oprnds0,
12299 : : then_clause, &vec_oprnds2,
12300 : : reduction_type != EXTRACT_LAST_REDUCTION
12301 : : ? else_clause : NULL, &vec_oprnds3);
12302 : : else
12303 : 0 : vect_get_vec_defs (vinfo, slp_node,
12304 : : cond_expr0, &vec_oprnds0,
12305 : : cond_expr1, &vec_oprnds1,
12306 : : then_clause, &vec_oprnds2,
12307 : : reduction_type != EXTRACT_LAST_REDUCTION
12308 : : ? else_clause : NULL, &vec_oprnds3);
12309 : :
12310 : 8487 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12311 : 0 : vec_else_clause = else_clause;
12312 : :
12313 : : /* Arguments are ready. Create the new vector stmt. */
12314 : 19938 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_cond_lhs)
12315 : : {
12316 : 11451 : vec_then_clause = vec_oprnds2[i];
12317 : 11451 : if (reduction_type != EXTRACT_LAST_REDUCTION)
12318 : 11451 : vec_else_clause = vec_oprnds3[i];
12319 : :
12320 : 11451 : if (swap_cond_operands)
12321 : 0 : std::swap (vec_then_clause, vec_else_clause);
12322 : :
12323 : 11451 : if (masked)
12324 : : vec_compare = vec_cond_lhs;
12325 : : else
12326 : : {
12327 : 0 : vec_cond_rhs = vec_oprnds1[i];
12328 : 0 : if (bitop1 == NOP_EXPR)
12329 : : {
12330 : 0 : gimple_seq stmts = NULL;
12331 : 0 : vec_compare = gimple_build (&stmts, cond_code, vec_cmp_type,
12332 : : vec_cond_lhs, vec_cond_rhs);
12333 : 0 : gsi_insert_before (gsi, stmts, GSI_SAME_STMT);
12334 : : }
12335 : : else
12336 : : {
12337 : 0 : new_temp = make_ssa_name (vec_cmp_type);
12338 : 0 : gassign *new_stmt;
12339 : 0 : if (bitop1 == BIT_NOT_EXPR)
12340 : 0 : new_stmt = gimple_build_assign (new_temp, bitop1,
12341 : : vec_cond_rhs);
12342 : : else
12343 : 0 : new_stmt
12344 : 0 : = gimple_build_assign (new_temp, bitop1, vec_cond_lhs,
12345 : : vec_cond_rhs);
12346 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12347 : 0 : if (bitop2 == NOP_EXPR)
12348 : : vec_compare = new_temp;
12349 : 0 : else if (bitop2 == BIT_NOT_EXPR
12350 : 0 : && reduction_type != EXTRACT_LAST_REDUCTION)
12351 : : {
12352 : : /* Instead of doing ~x ? y : z do x ? z : y. */
12353 : : vec_compare = new_temp;
12354 : : std::swap (vec_then_clause, vec_else_clause);
12355 : : }
12356 : : else
12357 : : {
12358 : 0 : vec_compare = make_ssa_name (vec_cmp_type);
12359 : 0 : if (bitop2 == BIT_NOT_EXPR)
12360 : 0 : new_stmt
12361 : 0 : = gimple_build_assign (vec_compare, bitop2, new_temp);
12362 : : else
12363 : 0 : new_stmt
12364 : 0 : = gimple_build_assign (vec_compare, bitop2,
12365 : : vec_cond_lhs, new_temp);
12366 : 0 : vect_finish_stmt_generation (vinfo, stmt_info,
12367 : : new_stmt, gsi);
12368 : : }
12369 : : }
12370 : : }
12371 : :
12372 : : /* If we decided to apply a loop mask to the result of the vector
12373 : : comparison, AND the comparison with the mask now. Later passes
12374 : : should then be able to reuse the AND results between mulitple
12375 : : vector statements.
12376 : :
12377 : : For example:
12378 : : for (int i = 0; i < 100; ++i)
12379 : : x[i] = y[i] ? z[i] : 10;
12380 : :
12381 : : results in following optimized GIMPLE:
12382 : :
12383 : : mask__35.8_43 = vect__4.7_41 != { 0, ... };
12384 : : vec_mask_and_46 = loop_mask_40 & mask__35.8_43;
12385 : : _19 = &MEM[base: z_12(D), index: ivtmp_56, step: 4, offset: 0B];
12386 : : vect_iftmp.11_47 = .MASK_LOAD (_19, 4B, vec_mask_and_46);
12387 : : vect_iftmp.12_52 = VEC_COND_EXPR <vec_mask_and_46,
12388 : : vect_iftmp.11_47, { 10, ... }>;
12389 : :
12390 : : instead of using a masked and unmasked forms of
12391 : : vec != { 0, ... } (masked in the MASK_LOAD,
12392 : : unmasked in the VEC_COND_EXPR). */
12393 : :
12394 : : /* Force vec_compare to be an SSA_NAME rather than a comparison,
12395 : : in cases where that's necessary. */
12396 : :
12397 : 11451 : tree len = NULL_TREE, bias = NULL_TREE;
12398 : 11451 : if (masks || lens || reduction_type == EXTRACT_LAST_REDUCTION)
12399 : : {
12400 : 0 : if (!is_gimple_val (vec_compare))
12401 : : {
12402 : 0 : tree vec_compare_name = make_ssa_name (vec_cmp_type);
12403 : 0 : gassign *new_stmt = gimple_build_assign (vec_compare_name,
12404 : : vec_compare);
12405 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12406 : 0 : vec_compare = vec_compare_name;
12407 : : }
12408 : :
12409 : 0 : if (must_invert_cmp_result)
12410 : : {
12411 : 0 : tree vec_compare_name = make_ssa_name (vec_cmp_type);
12412 : 0 : gassign *new_stmt = gimple_build_assign (vec_compare_name,
12413 : : BIT_NOT_EXPR,
12414 : : vec_compare);
12415 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12416 : 0 : vec_compare = vec_compare_name;
12417 : : }
12418 : :
12419 : 0 : if (direct_internal_fn_supported_p (IFN_LEN_FOLD_EXTRACT_LAST,
12420 : : vectype, OPTIMIZE_FOR_SPEED))
12421 : : {
12422 : 0 : if (lens)
12423 : : {
12424 : 0 : len = vect_get_loop_len (loop_vinfo, gsi, lens,
12425 : : vec_num, vectype, i, 1);
12426 : 0 : signed char biasval
12427 : 0 : = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
12428 : 0 : bias = build_int_cst (intQI_type_node, biasval);
12429 : : }
12430 : : else
12431 : : {
12432 : 0 : len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
12433 : 0 : bias = build_int_cst (intQI_type_node, 0);
12434 : : }
12435 : : }
12436 : 0 : if (masks)
12437 : : {
12438 : 0 : tree loop_mask
12439 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, vec_num,
12440 : : vectype, i);
12441 : 0 : tree tmp2 = make_ssa_name (vec_cmp_type);
12442 : 0 : gassign *g
12443 : 0 : = gimple_build_assign (tmp2, BIT_AND_EXPR, vec_compare,
12444 : : loop_mask);
12445 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
12446 : 0 : vec_compare = tmp2;
12447 : : }
12448 : : }
12449 : :
12450 : 0 : gimple *new_stmt;
12451 : 0 : if (reduction_type == EXTRACT_LAST_REDUCTION)
12452 : : {
12453 : 0 : gimple *old_stmt = vect_orig_stmt (stmt_info)->stmt;
12454 : 0 : tree lhs = gimple_get_lhs (old_stmt);
12455 : 0 : if ((unsigned)i != vec_oprnds0.length () - 1)
12456 : 0 : lhs = copy_ssa_name (lhs);
12457 : 0 : if (len)
12458 : 0 : new_stmt = gimple_build_call_internal
12459 : 0 : (IFN_LEN_FOLD_EXTRACT_LAST, 5, vec_else_clause, vec_compare,
12460 : : vec_then_clause, len, bias);
12461 : : else
12462 : 0 : new_stmt = gimple_build_call_internal
12463 : 0 : (IFN_FOLD_EXTRACT_LAST, 3, vec_else_clause, vec_compare,
12464 : : vec_then_clause);
12465 : 0 : gimple_call_set_lhs (new_stmt, lhs);
12466 : 0 : SSA_NAME_DEF_STMT (lhs) = new_stmt;
12467 : 0 : if ((unsigned)i != vec_oprnds0.length () - 1)
12468 : : {
12469 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12470 : 0 : vec_else_clause = lhs;
12471 : : }
12472 : 0 : else if (old_stmt == gsi_stmt (*gsi))
12473 : 0 : vect_finish_replace_stmt (vinfo, stmt_info, new_stmt);
12474 : : else
12475 : : {
12476 : : /* In this case we're moving the definition to later in the
12477 : : block. That doesn't matter because the only uses of the
12478 : : lhs are in phi statements. */
12479 : 0 : gimple_stmt_iterator old_gsi = gsi_for_stmt (old_stmt);
12480 : 0 : gsi_remove (&old_gsi, true);
12481 : 0 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12482 : : }
12483 : : }
12484 : : else
12485 : : {
12486 : 11451 : new_temp = make_ssa_name (vec_dest);
12487 : 11451 : new_stmt = gimple_build_assign (new_temp, VEC_COND_EXPR, vec_compare,
12488 : : vec_then_clause, vec_else_clause);
12489 : 11451 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12490 : : }
12491 : 11451 : slp_node->push_vec_def (new_stmt);
12492 : : }
12493 : :
12494 : 8487 : vec_oprnds0.release ();
12495 : 8487 : vec_oprnds1.release ();
12496 : 8487 : vec_oprnds2.release ();
12497 : 8487 : vec_oprnds3.release ();
12498 : :
12499 : 8487 : return true;
12500 : : }
12501 : :
12502 : : /* Helper of vectorizable_comparison.
12503 : :
12504 : : Check if STMT_INFO is comparison expression CODE that can be vectorized.
12505 : : If COST_VEC is passed, calculate costs but don't change anything,
12506 : : otherwise, vectorize STMT_INFO: create a vectorized comparison, and insert
12507 : : it at GSI.
12508 : :
12509 : : Return true if STMT_INFO is vectorizable in this way. */
12510 : :
12511 : : static bool
12512 : 330792 : vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
12513 : : stmt_vec_info stmt_info, tree_code code,
12514 : : gimple_stmt_iterator *gsi,
12515 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12516 : : {
12517 : 330792 : tree lhs, rhs1, rhs2;
12518 : 330792 : tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
12519 : 330792 : tree vec_rhs1 = NULL_TREE, vec_rhs2 = NULL_TREE;
12520 : 330792 : tree new_temp;
12521 : 330792 : enum vect_def_type dts[2] = {vect_unknown_def_type, vect_unknown_def_type};
12522 : 330792 : poly_uint64 nunits;
12523 : 330792 : enum tree_code bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
12524 : 330792 : int i;
12525 : 330792 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
12526 : 330792 : vec<tree> vec_oprnds0 = vNULL;
12527 : 330792 : vec<tree> vec_oprnds1 = vNULL;
12528 : 330792 : tree mask_type;
12529 : 330792 : tree mask = NULL_TREE;
12530 : :
12531 : 330792 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
12532 : : return false;
12533 : :
12534 : 330792 : if (!vectype || !VECTOR_BOOLEAN_TYPE_P (vectype))
12535 : : return false;
12536 : :
12537 : 146606 : mask_type = vectype;
12538 : 146606 : nunits = TYPE_VECTOR_SUBPARTS (vectype);
12539 : :
12540 : 146606 : if (TREE_CODE_CLASS (code) != tcc_comparison)
12541 : : return false;
12542 : :
12543 : 145027 : slp_tree slp_rhs1, slp_rhs2;
12544 : 145027 : if (!vect_is_simple_use (vinfo, slp_node,
12545 : : 0, &rhs1, &slp_rhs1, &dts[0], &vectype1))
12546 : : return false;
12547 : :
12548 : 145027 : if (!vect_is_simple_use (vinfo, slp_node,
12549 : : 1, &rhs2, &slp_rhs2, &dts[1], &vectype2))
12550 : : return false;
12551 : :
12552 : 110577 : if (vectype1 && vectype2
12553 : 211569 : && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype1),
12554 : 66542 : TYPE_VECTOR_SUBPARTS (vectype2)))
12555 : 16 : return false;
12556 : :
12557 : 145011 : vectype = vectype1 ? vectype1 : vectype2;
12558 : :
12559 : : /* Invariant comparison. */
12560 : 145011 : if (!vectype)
12561 : : {
12562 : 30089 : vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (rhs1), slp_node);
12563 : 30089 : if (!vectype || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype), nunits))
12564 : 7 : return false;
12565 : : }
12566 : 114922 : else if (maybe_ne (nunits, TYPE_VECTOR_SUBPARTS (vectype)))
12567 : : return false;
12568 : :
12569 : : /* Can't compare mask and non-mask types. */
12570 : 110561 : if (vectype1 && vectype2
12571 : 343996 : && (VECTOR_BOOLEAN_TYPE_P (vectype1) ^ VECTOR_BOOLEAN_TYPE_P (vectype2)))
12572 : : return false;
12573 : :
12574 : : /* Boolean values may have another representation in vectors
12575 : : and therefore we prefer bit operations over comparison for
12576 : : them (which also works for scalar masks). We store opcodes
12577 : : to use in bitop1 and bitop2. Statement is vectorized as
12578 : : BITOP2 (rhs1 BITOP1 rhs2) or
12579 : : rhs1 BITOP2 (BITOP1 rhs2)
12580 : : depending on bitop1 and bitop2 arity. */
12581 : 144996 : bool swap_p = false;
12582 : 144996 : if (VECTOR_BOOLEAN_TYPE_P (vectype))
12583 : : {
12584 : 661 : if (code == GT_EXPR)
12585 : : {
12586 : : bitop1 = BIT_NOT_EXPR;
12587 : : bitop2 = BIT_AND_EXPR;
12588 : : }
12589 : : else if (code == GE_EXPR)
12590 : : {
12591 : : bitop1 = BIT_NOT_EXPR;
12592 : : bitop2 = BIT_IOR_EXPR;
12593 : : }
12594 : : else if (code == LT_EXPR)
12595 : : {
12596 : : bitop1 = BIT_NOT_EXPR;
12597 : : bitop2 = BIT_AND_EXPR;
12598 : : swap_p = true;
12599 : : }
12600 : : else if (code == LE_EXPR)
12601 : : {
12602 : : bitop1 = BIT_NOT_EXPR;
12603 : : bitop2 = BIT_IOR_EXPR;
12604 : : swap_p = true;
12605 : : }
12606 : : else
12607 : : {
12608 : : bitop1 = BIT_XOR_EXPR;
12609 : : if (code == EQ_EXPR)
12610 : : bitop2 = BIT_NOT_EXPR;
12611 : : }
12612 : : }
12613 : :
12614 : 144996 : if (cost_vec)
12615 : : {
12616 : 132577 : if (bitop1 == NOP_EXPR)
12617 : : {
12618 : 132060 : if (!expand_vec_cmp_expr_p (vectype, mask_type, code))
12619 : : return false;
12620 : : }
12621 : : else
12622 : : {
12623 : 517 : machine_mode mode = TYPE_MODE (vectype);
12624 : 517 : optab optab;
12625 : :
12626 : 517 : optab = optab_for_tree_code (bitop1, vectype, optab_default);
12627 : 517 : if (!optab || !can_implement_p (optab, mode))
12628 : 0 : return false;
12629 : :
12630 : 517 : if (bitop2 != NOP_EXPR)
12631 : : {
12632 : 91 : optab = optab_for_tree_code (bitop2, vectype, optab_default);
12633 : 91 : if (!optab || !can_implement_p (optab, mode))
12634 : 0 : return false;
12635 : : }
12636 : : }
12637 : :
12638 : : /* Put types on constant and invariant SLP children. */
12639 : 123443 : if (!vect_maybe_update_slp_op_vectype (slp_rhs1, vectype)
12640 : 123443 : || !vect_maybe_update_slp_op_vectype (slp_rhs2, vectype))
12641 : : {
12642 : 2 : if (dump_enabled_p ())
12643 : 2 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12644 : : "incompatible vector types for invariants\n");
12645 : 2 : return false;
12646 : : }
12647 : :
12648 : 123441 : vect_model_simple_cost (vinfo, 1 + (bitop2 != NOP_EXPR),
12649 : : slp_node, cost_vec);
12650 : 123441 : return true;
12651 : : }
12652 : :
12653 : : /* Transform. */
12654 : :
12655 : : /* Handle def. */
12656 : 12419 : lhs = gimple_get_lhs (STMT_VINFO_STMT (stmt_info));
12657 : 12419 : if (lhs)
12658 : 12419 : mask = vect_create_destination_var (lhs, mask_type);
12659 : :
12660 : 12419 : vect_get_vec_defs (vinfo, slp_node, rhs1, &vec_oprnds0, rhs2, &vec_oprnds1);
12661 : 12419 : if (swap_p)
12662 : 58 : std::swap (vec_oprnds0, vec_oprnds1);
12663 : :
12664 : : /* Arguments are ready. Create the new vector stmt. */
12665 : 31191 : FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_rhs1)
12666 : : {
12667 : 18772 : gimple *new_stmt;
12668 : 18772 : vec_rhs2 = vec_oprnds1[i];
12669 : :
12670 : 18772 : if (lhs)
12671 : 18772 : new_temp = make_ssa_name (mask);
12672 : : else
12673 : 0 : new_temp = make_temp_ssa_name (mask_type, NULL, "cmp");
12674 : 18772 : if (bitop1 == NOP_EXPR)
12675 : : {
12676 : 18623 : new_stmt = gimple_build_assign (new_temp, code,
12677 : : vec_rhs1, vec_rhs2);
12678 : 18623 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12679 : : }
12680 : : else
12681 : : {
12682 : 149 : if (bitop1 == BIT_NOT_EXPR)
12683 : 84 : new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs2);
12684 : : else
12685 : 65 : new_stmt = gimple_build_assign (new_temp, bitop1, vec_rhs1,
12686 : : vec_rhs2);
12687 : 149 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12688 : 149 : if (bitop2 != NOP_EXPR)
12689 : : {
12690 : 84 : tree res = make_ssa_name (mask);
12691 : 84 : if (bitop2 == BIT_NOT_EXPR)
12692 : 0 : new_stmt = gimple_build_assign (res, bitop2, new_temp);
12693 : : else
12694 : 84 : new_stmt = gimple_build_assign (res, bitop2, vec_rhs1,
12695 : : new_temp);
12696 : 84 : vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
12697 : : }
12698 : : }
12699 : 18772 : slp_node->push_vec_def (new_stmt);
12700 : : }
12701 : :
12702 : 12419 : vec_oprnds0.release ();
12703 : 12419 : vec_oprnds1.release ();
12704 : :
12705 : 12419 : return true;
12706 : : }
12707 : :
12708 : : /* vectorizable_comparison.
12709 : :
12710 : : Check if STMT_INFO is comparison expression that can be vectorized.
12711 : : If COST_VEC is passed, calculate costs but don't change anything,
12712 : : otherwise, vectorize STMT_INFO: create a vectorized comparison, and insert
12713 : : it at GSI.
12714 : :
12715 : : Return true if STMT_INFO is vectorizable in this way. */
12716 : :
12717 : : static bool
12718 : 568083 : vectorizable_comparison (vec_info *vinfo,
12719 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
12720 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12721 : : {
12722 : 568083 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
12723 : :
12724 : 568083 : if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
12725 : : return false;
12726 : :
12727 : 568083 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
12728 : : return false;
12729 : :
12730 : 763015 : gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt);
12731 : 328804 : if (!stmt)
12732 : : return false;
12733 : :
12734 : 328804 : enum tree_code code = gimple_assign_rhs_code (stmt);
12735 : 328804 : tree vectype = SLP_TREE_VECTYPE (slp_node);
12736 : 328804 : if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
12737 : : slp_node, cost_vec))
12738 : : return false;
12739 : :
12740 : 133872 : if (cost_vec)
12741 : 121453 : SLP_TREE_TYPE (slp_node) = comparison_vec_info_type;
12742 : :
12743 : : return true;
12744 : : }
12745 : :
12746 : : /* Check to see if the target supports any of the compare and branch optabs for
12747 : : vectors with MODE as these would be required when expanding. */
12748 : : static bool
12749 : 56860 : supports_vector_compare_and_branch (loop_vec_info loop_vinfo, machine_mode mode)
12750 : : {
12751 : 56860 : bool masked_loop_p = LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
12752 : 56860 : bool len_loop_p = LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
12753 : :
12754 : : /* The vectorizer only produces vec_cbranch_any_optab directly. So only
12755 : : check for support for that or vec_cbranch_any_optab when masked.
12756 : : We can't produce vcond_cbranch_any directly from the vectorizer as we
12757 : : want to keep gimple_cond as the GIMPLE representation. But we'll fold
12758 : : it in expand. For that reason we require a backend to support the
12759 : : unconditional vector cbranch optab if they support the conditional one,
12760 : : which is just an optimization on the unconditional one. */
12761 : 56860 : if (masked_loop_p
12762 : 56860 : && direct_optab_handler (cond_vec_cbranch_any_optab, mode)
12763 : : != CODE_FOR_nothing)
12764 : : return true;
12765 : 56860 : else if (len_loop_p
12766 : 56860 : && direct_optab_handler (cond_len_vec_cbranch_any_optab, mode)
12767 : : != CODE_FOR_nothing)
12768 : : return true;
12769 : 56860 : else if (!masked_loop_p && !len_loop_p
12770 : 113720 : && direct_optab_handler (vec_cbranch_any_optab, mode)
12771 : : != CODE_FOR_nothing)
12772 : : return true;
12773 : :
12774 : : /* The target can implement cbranch to distinguish between boolean vector
12775 : : types and data types if they don't have a different mode for both. */
12776 : 56860 : return direct_optab_handler (cbranch_optab, mode) != CODE_FOR_nothing;
12777 : : }
12778 : :
12779 : : /* Check to see if the current early break given in STMT_INFO is valid for
12780 : : vectorization. */
12781 : :
12782 : : bool
12783 : 218914 : vectorizable_early_exit (loop_vec_info loop_vinfo, stmt_vec_info stmt_info,
12784 : : gimple_stmt_iterator *gsi,
12785 : : slp_tree slp_node, stmt_vector_for_cost *cost_vec)
12786 : : {
12787 : 218914 : if (!is_a <gcond *> (STMT_VINFO_STMT (stmt_info)))
12788 : : return false;
12789 : :
12790 : 58547 : if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_condition_def)
12791 : : return false;
12792 : :
12793 : 58547 : if (!STMT_VINFO_RELEVANT_P (stmt_info))
12794 : : return false;
12795 : :
12796 : 58547 : DUMP_VECT_SCOPE ("vectorizable_early_exit");
12797 : :
12798 : 58547 : auto code = gimple_cond_code (STMT_VINFO_STMT (stmt_info));
12799 : :
12800 : : /* For SLP we don't want to use the type of the operands of the SLP node, when
12801 : : vectorizing using SLP slp_node will be the children of the gcond and we
12802 : : want to use the type of the direct children which since the gcond is root
12803 : : will be the current node, rather than a child node as vect_is_simple_use
12804 : : assumes. */
12805 : 58547 : tree vectype = SLP_TREE_VECTYPE (slp_node);
12806 : 58547 : if (!vectype)
12807 : : return false;
12808 : :
12809 : 58547 : machine_mode mode = TYPE_MODE (vectype);
12810 : 58547 : int vec_num = vect_get_num_copies (loop_vinfo, slp_node);
12811 : :
12812 : 58547 : vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
12813 : 58547 : vec_loop_lens *lens = &LOOP_VINFO_LENS (loop_vinfo);
12814 : 58547 : bool masked_loop_p = LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
12815 : 58547 : bool len_loop_p = LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
12816 : :
12817 : : /* Now build the new conditional. Pattern gimple_conds get dropped during
12818 : : codegen so we must replace the original insn. */
12819 : 58547 : gimple *orig_stmt = STMT_VINFO_STMT (vect_orig_stmt (stmt_info));
12820 : 58547 : gcond *cond_stmt = as_a <gcond *>(orig_stmt);
12821 : :
12822 : 58547 : tree vectype_out = vectype;
12823 : 58547 : auto bb = gimple_bb (cond_stmt);
12824 : 58547 : edge exit_true_edge = EDGE_SUCC (bb, 0);
12825 : 58547 : if (exit_true_edge->flags & EDGE_FALSE_VALUE)
12826 : 888 : exit_true_edge = EDGE_SUCC (bb, 1);
12827 : 58547 : gcc_assert (exit_true_edge->flags & EDGE_TRUE_VALUE);
12828 : :
12829 : : /* When vectorizing we assume that if the branch edge is taken that we're
12830 : : exiting the loop. This is not however always the case as the compiler will
12831 : : rewrite conditions to always be a comparison against 0. To do this it
12832 : : sometimes flips the edges. This is fine for scalar, but for vector we
12833 : : then have to negate the result of the test, as we're still assuming that if
12834 : : you take the branch edge that we found the exit condition. i.e. we need to
12835 : : know whether we are generating a `forall` or an `exist` condition. */
12836 : 117094 : bool flipped = flow_bb_inside_loop_p (LOOP_VINFO_LOOP (loop_vinfo),
12837 : 58547 : exit_true_edge->dest);
12838 : :
12839 : : /* See if we support ADDHN and use that for the reduction. */
12840 : 58547 : internal_fn ifn = IFN_VEC_TRUNC_ADD_HIGH;
12841 : 58547 : bool addhn_supported_p
12842 : 58547 : = direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_BOTH);
12843 : 58547 : tree narrow_type = NULL_TREE;
12844 : 58547 : if (addhn_supported_p)
12845 : : {
12846 : : /* Calculate the narrowing type for the result. */
12847 : 0 : auto halfprec = TYPE_PRECISION (TREE_TYPE (vectype)) / 2;
12848 : 0 : auto unsignedp = TYPE_UNSIGNED (TREE_TYPE (vectype));
12849 : 0 : tree itype = build_nonstandard_integer_type (halfprec, unsignedp);
12850 : 0 : tree tmp_type = build_vector_type (itype, TYPE_VECTOR_SUBPARTS (vectype));
12851 : 0 : narrow_type = truth_type_for (tmp_type);
12852 : :
12853 : 0 : if (!supports_vector_compare_and_branch (loop_vinfo,
12854 : 0 : TYPE_MODE (narrow_type)))
12855 : : {
12856 : 0 : if (dump_enabled_p ())
12857 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12858 : : "can't use ADDHN reduction because cbranch for "
12859 : : "the narrowed type is not supported by the "
12860 : : "target.\n");
12861 : : addhn_supported_p = false;
12862 : : }
12863 : : }
12864 : :
12865 : : /* Analyze only. */
12866 : 58547 : if (cost_vec)
12867 : : {
12868 : 56860 : if (!addhn_supported_p
12869 : 56860 : && !supports_vector_compare_and_branch (loop_vinfo, mode))
12870 : : {
12871 : 54872 : if (dump_enabled_p ())
12872 : 567 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
12873 : : "can't vectorize early exit because the "
12874 : : "target doesn't support flag setting vector "
12875 : : "comparisons.\n");
12876 : 54872 : return false;
12877 : : }
12878 : :
12879 : 1988 : if (!vectorizable_comparison_1 (loop_vinfo, vectype, stmt_info, code, gsi,
12880 : : slp_node, cost_vec))
12881 : : return false;
12882 : :
12883 : 1988 : if (LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
12884 : : {
12885 : 1155 : if (direct_internal_fn_supported_p (IFN_VCOND_MASK_LEN, vectype,
12886 : : OPTIMIZE_FOR_SPEED))
12887 : 0 : vect_record_loop_len (loop_vinfo, lens, vec_num, vectype, 1);
12888 : : else
12889 : 1155 : vect_record_loop_mask (loop_vinfo, masks, vec_num, vectype, NULL);
12890 : : }
12891 : :
12892 : 1988 : return true;
12893 : : }
12894 : :
12895 : : /* Tranform. */
12896 : :
12897 : 1687 : tree new_temp = NULL_TREE;
12898 : 1687 : gimple *new_stmt = NULL;
12899 : :
12900 : 1687 : if (dump_enabled_p ())
12901 : 367 : dump_printf_loc (MSG_NOTE, vect_location, "transform early-exit.\n");
12902 : :
12903 : : /* For SLP we don't do codegen of the body starting from the gcond, the gconds are
12904 : : roots and so by the time we get to them we have already codegened the SLP tree
12905 : : and so we shouldn't try to do so again. The arguments have already been
12906 : : vectorized. It's not very clean to do this here, But the masking code below is
12907 : : complex and this keeps it all in one place to ease fixes and backports. Once we
12908 : : drop the non-SLP loop vect or split vectorizable_* this can be simplified. */
12909 : :
12910 : 1687 : gimple *stmt = STMT_VINFO_STMT (stmt_info);
12911 : 1687 : basic_block cond_bb = gimple_bb (stmt);
12912 : 1687 : gimple_stmt_iterator cond_gsi = gsi_last_bb (cond_bb);
12913 : :
12914 : 1687 : auto_vec<tree> stmts;
12915 : 1687 : stmts.safe_splice (SLP_TREE_VEC_DEFS (slp_node));
12916 : :
12917 : : /* If we're comparing against a previous forall we need to negate the resullts
12918 : : before we do the final comparison or reduction. */
12919 : 1687 : if (flipped)
12920 : : {
12921 : : /* Rewrite the if(all(mask)) into if (!all(mask)) which is the same as
12922 : : if (any(~mask)) by negating the masks and flipping the branches.
12923 : :
12924 : : 1. For unmasked loops we simply reduce the ~mask.
12925 : : 2. For masked loops we reduce (~mask & loop_mask) which is the same as
12926 : : doing (mask & loop_mask) ^ loop_mask. */
12927 : 238 : for (unsigned i = 0; i < stmts.length (); i++)
12928 : : {
12929 : 141 : tree inv_lhs = make_temp_ssa_name (vectype, NULL, "vexit_inv");
12930 : 141 : auto inv_stmt = gimple_build_assign (inv_lhs, BIT_NOT_EXPR, stmts[i]);
12931 : 141 : vect_finish_stmt_generation (loop_vinfo, stmt_info, inv_stmt,
12932 : : &cond_gsi);
12933 : 141 : stmts[i] = inv_lhs;
12934 : : }
12935 : :
12936 : 97 : EDGE_SUCC (bb, 0)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
12937 : 97 : EDGE_SUCC (bb, 1)->flags ^= (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
12938 : : }
12939 : :
12940 : : /* Determine if we need to reduce the final value. */
12941 : 1687 : if (stmts.length () > 1)
12942 : : {
12943 : : /* We build the reductions in a way to maintain as much parallelism as
12944 : : possible. */
12945 : 221 : auto_vec<tree> workset (stmts.length ());
12946 : :
12947 : : /* Mask the statements as we queue them up. Normally we loop over
12948 : : vec_num, but since we inspect the exact results of vectorization
12949 : : we don't need to and instead can just use the stmts themselves. */
12950 : 221 : if (masked_loop_p)
12951 : 0 : for (unsigned i = 0; i < stmts.length (); i++)
12952 : : {
12953 : 0 : tree stmt_mask
12954 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, vec_num,
12955 : : vectype, i);
12956 : 0 : stmt_mask
12957 : 0 : = prepare_vec_mask (loop_vinfo, TREE_TYPE (stmt_mask), stmt_mask,
12958 : 0 : stmts[i], &cond_gsi);
12959 : 0 : workset.quick_push (stmt_mask);
12960 : : }
12961 : 221 : else if (len_loop_p)
12962 : 0 : for (unsigned i = 0; i < stmts.length (); i++)
12963 : : {
12964 : 0 : tree len_mask = vect_gen_loop_len_mask (loop_vinfo, gsi, &cond_gsi,
12965 : : lens, vec_num,
12966 : 0 : vectype, stmts[i], i, 1);
12967 : :
12968 : 0 : workset.quick_push (len_mask);
12969 : : }
12970 : : else
12971 : 221 : workset.splice (stmts);
12972 : :
12973 : 588 : while (workset.length () > 1)
12974 : : {
12975 : 367 : tree arg0 = workset.pop ();
12976 : 367 : tree arg1 = workset.pop ();
12977 : 367 : if (addhn_supported_p && workset.length () == 0)
12978 : : {
12979 : 0 : new_stmt = gimple_build_call_internal (ifn, 2, arg0, arg1);
12980 : 0 : vectype_out = narrow_type;
12981 : 0 : new_temp = make_temp_ssa_name (vectype_out, NULL, "vexit_reduc");
12982 : 0 : gimple_call_set_lhs (as_a <gcall *> (new_stmt), new_temp);
12983 : 0 : gimple_call_set_nothrow (as_a <gcall *> (new_stmt), true);
12984 : : }
12985 : : else
12986 : : {
12987 : 367 : new_temp = make_temp_ssa_name (vectype_out, NULL, "vexit_reduc");
12988 : 367 : new_stmt
12989 : 367 : = gimple_build_assign (new_temp, BIT_IOR_EXPR, arg0, arg1);
12990 : : }
12991 : 367 : vect_finish_stmt_generation (loop_vinfo, stmt_info, new_stmt,
12992 : : &cond_gsi);
12993 : 367 : workset.quick_insert (0, new_temp);
12994 : : }
12995 : 221 : }
12996 : : else
12997 : : {
12998 : 1466 : new_temp = stmts[0];
12999 : 1466 : if (masked_loop_p)
13000 : : {
13001 : 0 : tree mask
13002 : 0 : = vect_get_loop_mask (loop_vinfo, gsi, masks, 1, vectype, 0);
13003 : 0 : new_temp = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
13004 : : new_temp, &cond_gsi);
13005 : : }
13006 : 1466 : else if (len_loop_p)
13007 : 0 : new_temp = vect_gen_loop_len_mask (loop_vinfo, gsi, &cond_gsi, lens,
13008 : : 1, vectype, new_temp, 0, 1);
13009 : : }
13010 : :
13011 : 1687 : gcc_assert (new_temp);
13012 : :
13013 : 1687 : tree cst = build_zero_cst (vectype_out);
13014 : 1687 : gimple_cond_set_condition (cond_stmt, NE_EXPR, new_temp, cst);
13015 : 1687 : update_stmt (orig_stmt);
13016 : :
13017 : : /* ??? */
13018 : 1687 : SLP_TREE_VEC_DEFS (slp_node).truncate (0);
13019 : :
13020 : 1687 : return true;
13021 : 1687 : }
13022 : :
13023 : : /* If SLP_NODE is nonnull, return true if vectorizable_live_operation
13024 : : can handle all live statements in the node. Otherwise return true
13025 : : if STMT_INFO is not live or if vectorizable_live_operation can handle it.
13026 : : VEC_STMT_P is as for vectorizable_live_operation. */
13027 : :
13028 : : static bool
13029 : 1396948 : can_vectorize_live_stmts (vec_info *vinfo,
13030 : : slp_tree slp_node, slp_instance slp_node_instance,
13031 : : bool vec_stmt_p,
13032 : : stmt_vector_for_cost *cost_vec)
13033 : : {
13034 : 1396948 : stmt_vec_info slp_stmt_info;
13035 : 1396948 : unsigned int i;
13036 : 3146281 : FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (slp_node), i, slp_stmt_info)
13037 : : {
13038 : 1749333 : if (slp_stmt_info
13039 : 1729905 : && STMT_VINFO_LIVE_P (slp_stmt_info)
13040 : 1894636 : && !vectorizable_live_operation (vinfo, slp_stmt_info, slp_node,
13041 : : slp_node_instance, i,
13042 : : vec_stmt_p, cost_vec))
13043 : : return false;
13044 : : }
13045 : :
13046 : : return true;
13047 : : }
13048 : :
13049 : : /* Make sure the statement is vectorizable. */
13050 : :
13051 : : opt_result
13052 : 2309721 : vect_analyze_stmt (vec_info *vinfo,
13053 : : slp_tree node, slp_instance node_instance,
13054 : : stmt_vector_for_cost *cost_vec)
13055 : : {
13056 : 2309721 : stmt_vec_info stmt_info = SLP_TREE_REPRESENTATIVE (node);
13057 : 2309721 : bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
13058 : 2309721 : enum vect_relevant relevance = STMT_VINFO_RELEVANT (stmt_info);
13059 : 2309721 : bool ok;
13060 : :
13061 : 2309721 : if (dump_enabled_p ())
13062 : 95195 : dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: %G",
13063 : : stmt_info->stmt);
13064 : :
13065 : 4394592 : if (gimple_has_volatile_ops (stmt_info->stmt))
13066 : : {
13067 : : /* ??? This shouldn't really happen, volatile stmts should
13068 : : not end up in the SLP graph. */
13069 : 0 : return opt_result::failure_at (stmt_info->stmt,
13070 : : "not vectorized:"
13071 : : " stmt has volatile operands: %G\n",
13072 : : stmt_info->stmt);
13073 : : }
13074 : :
13075 : : /* Skip stmts that do not need to be vectorized. */
13076 : 2309721 : if (!STMT_VINFO_RELEVANT_P (stmt_info)
13077 : 0 : && !STMT_VINFO_LIVE_P (stmt_info))
13078 : : {
13079 : 0 : if (dump_enabled_p ())
13080 : 0 : dump_printf_loc (MSG_NOTE, vect_location, "irrelevant.\n");
13081 : :
13082 : : /* ??? This shouldn't really happen, irrelevant stmts should
13083 : : not end up in the SLP graph. */
13084 : 0 : return opt_result::failure_at (stmt_info->stmt,
13085 : : "not vectorized:"
13086 : : " irrelevant stmt as SLP node %p "
13087 : : "representative.\n",
13088 : : (void *)node);
13089 : : }
13090 : :
13091 : 2309721 : switch (STMT_VINFO_DEF_TYPE (stmt_info))
13092 : : {
13093 : : case vect_internal_def:
13094 : : case vect_condition_def:
13095 : : break;
13096 : :
13097 : 56813 : case vect_reduction_def:
13098 : 56813 : case vect_nested_cycle:
13099 : 56813 : gcc_assert (!bb_vinfo
13100 : : && (relevance == vect_used_in_outer
13101 : : || relevance == vect_used_in_outer_by_reduction
13102 : : || relevance == vect_used_by_reduction
13103 : : || relevance == vect_unused_in_scope
13104 : : || relevance == vect_used_only_live));
13105 : : break;
13106 : :
13107 : 266 : case vect_double_reduction_def:
13108 : 266 : gcc_assert (!bb_vinfo && node);
13109 : : break;
13110 : :
13111 : 119501 : case vect_induction_def:
13112 : 119501 : case vect_first_order_recurrence:
13113 : 119501 : gcc_assert (!bb_vinfo);
13114 : : break;
13115 : :
13116 : 0 : case vect_constant_def:
13117 : 0 : case vect_external_def:
13118 : 0 : case vect_unknown_def_type:
13119 : 0 : default:
13120 : 0 : gcc_unreachable ();
13121 : : }
13122 : :
13123 : 2309721 : tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info);
13124 : 2309721 : STMT_VINFO_VECTYPE (stmt_info) = NULL_TREE;
13125 : :
13126 : 2309721 : if (STMT_VINFO_RELEVANT_P (stmt_info))
13127 : : {
13128 : 2309721 : gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
13129 : 2309721 : gcc_assert (SLP_TREE_VECTYPE (node)
13130 : : || gimple_code (stmt_info->stmt) == GIMPLE_COND
13131 : : || (call && gimple_call_lhs (call) == NULL_TREE));
13132 : : }
13133 : :
13134 : 2309721 : ok = true;
13135 : 2309721 : if (bb_vinfo
13136 : 1147949 : || (STMT_VINFO_RELEVANT_P (stmt_info)
13137 : 0 : || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def))
13138 : : /* Prefer vectorizable_call over vectorizable_simd_clone_call so
13139 : : -mveclibabi= takes preference over library functions with
13140 : : the simd attribute. */
13141 : 2309721 : ok = (vectorizable_call (vinfo, stmt_info, NULL, node, cost_vec)
13142 : 2304200 : || vectorizable_simd_clone_call (vinfo, stmt_info, NULL, node,
13143 : : cost_vec)
13144 : 2303754 : || vectorizable_conversion (vinfo, stmt_info, NULL, node, cost_vec)
13145 : 2235520 : || vectorizable_operation (vinfo, stmt_info, NULL, node, cost_vec)
13146 : 1828831 : || vectorizable_assignment (vinfo, stmt_info, NULL, node, cost_vec)
13147 : 1770628 : || vectorizable_load (vinfo, stmt_info, NULL, node, cost_vec)
13148 : 1396716 : || vectorizable_store (vinfo, stmt_info, NULL, node, cost_vec)
13149 : 616092 : || vectorizable_shift (vinfo, stmt_info, NULL, node, cost_vec)
13150 : 575181 : || vectorizable_condition (vinfo, stmt_info, NULL, node, cost_vec)
13151 : 555664 : || vectorizable_comparison (vinfo, stmt_info, NULL, node, cost_vec)
13152 : 434211 : || (bb_vinfo
13153 : 125928 : && vectorizable_phi (bb_vinfo, stmt_info, node, cost_vec))
13154 : 2689382 : || (is_a <loop_vec_info> (vinfo)
13155 : 308283 : && (vectorizable_lane_reducing (as_a <loop_vec_info> (vinfo),
13156 : : stmt_info, node, cost_vec)
13157 : 307827 : || vectorizable_reduction (as_a <loop_vec_info> (vinfo),
13158 : : stmt_info,
13159 : : node, node_instance, cost_vec)
13160 : 253226 : || vectorizable_induction (as_a <loop_vec_info> (vinfo),
13161 : : stmt_info, node, cost_vec)
13162 : 161325 : || vectorizable_lc_phi (as_a <loop_vec_info> (vinfo),
13163 : : stmt_info, node)
13164 : 160623 : || vectorizable_recurr (as_a <loop_vec_info> (vinfo),
13165 : : stmt_info, node, cost_vec)
13166 : 160367 : || vectorizable_early_exit (as_a <loop_vec_info> (vinfo),
13167 : : stmt_info, NULL, node,
13168 : : cost_vec))));
13169 : :
13170 : 2309721 : STMT_VINFO_VECTYPE (stmt_info) = saved_vectype;
13171 : :
13172 : 2077976 : if (!ok)
13173 : 231745 : return opt_result::failure_at (stmt_info->stmt,
13174 : : "not vectorized:"
13175 : : " relevant stmt not supported: %G",
13176 : : stmt_info->stmt);
13177 : :
13178 : : /* Stmts that are (also) "live" (i.e. - that are used out of the loop)
13179 : : need extra handling, except for vectorizable reductions. */
13180 : 2077976 : if (!bb_vinfo
13181 : 987582 : && SLP_TREE_TYPE (node) != reduc_vec_info_type
13182 : 980108 : && (SLP_TREE_TYPE (node) != lc_phi_info_type
13183 : 702 : || SLP_TREE_DEF_TYPE (node) == vect_internal_def)
13184 : 980108 : && (!node->ldst_lanes || SLP_TREE_PERMUTE_P (node))
13185 : 3058084 : && !can_vectorize_live_stmts (as_a <loop_vec_info> (vinfo),
13186 : : node, node_instance,
13187 : : false, cost_vec))
13188 : 0 : return opt_result::failure_at (stmt_info->stmt,
13189 : : "not vectorized:"
13190 : : " live stmt not supported: %G",
13191 : : stmt_info->stmt);
13192 : :
13193 : 2077976 : return opt_result::success ();
13194 : : }
13195 : :
13196 : :
13197 : : /* Function vect_transform_stmt.
13198 : :
13199 : : Create a vectorized stmt to replace STMT_INFO, and insert it at GSI. */
13200 : :
13201 : : bool
13202 : 960723 : vect_transform_stmt (vec_info *vinfo,
13203 : : stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
13204 : : slp_tree slp_node, slp_instance slp_node_instance)
13205 : : {
13206 : 960723 : bool is_store = false;
13207 : 960723 : bool done;
13208 : :
13209 : 960723 : gcc_assert (slp_node);
13210 : :
13211 : 960723 : if (stmt_info)
13212 : 959892 : STMT_VINFO_VECTYPE (stmt_info) = NULL_TREE;
13213 : :
13214 : 960723 : switch (SLP_TREE_TYPE (slp_node))
13215 : : {
13216 : 22537 : case type_demotion_vec_info_type:
13217 : 22537 : case type_promotion_vec_info_type:
13218 : 22537 : case type_conversion_vec_info_type:
13219 : 22537 : done = vectorizable_conversion (vinfo, stmt_info, gsi, slp_node, NULL);
13220 : 22537 : gcc_assert (done);
13221 : : break;
13222 : :
13223 : 15864 : case induc_vec_info_type:
13224 : 15864 : done = vectorizable_induction (as_a <loop_vec_info> (vinfo),
13225 : : stmt_info, slp_node, NULL);
13226 : 15864 : gcc_assert (done);
13227 : : break;
13228 : :
13229 : 7579 : case shift_vec_info_type:
13230 : 7579 : done = vectorizable_shift (vinfo, stmt_info, gsi, slp_node, NULL);
13231 : 7579 : gcc_assert (done);
13232 : : break;
13233 : :
13234 : 114067 : case op_vec_info_type:
13235 : 114067 : done = vectorizable_operation (vinfo, stmt_info, gsi, slp_node, NULL);
13236 : 114067 : gcc_assert (done);
13237 : : break;
13238 : :
13239 : 14697 : case assignment_vec_info_type:
13240 : 14697 : done = vectorizable_assignment (vinfo, stmt_info, gsi, slp_node, NULL);
13241 : 14697 : gcc_assert (done);
13242 : : break;
13243 : :
13244 : 160742 : case load_vec_info_type:
13245 : 160742 : done = vectorizable_load (vinfo, stmt_info, gsi, slp_node, NULL);
13246 : 160742 : gcc_assert (done);
13247 : : break;
13248 : :
13249 : 543883 : case store_vec_info_type:
13250 : 543883 : done = vectorizable_store (vinfo, stmt_info, gsi, slp_node, NULL);
13251 : 543883 : gcc_assert (done);
13252 : : is_store = true;
13253 : : break;
13254 : :
13255 : 8487 : case condition_vec_info_type:
13256 : 8487 : done = vectorizable_condition (vinfo, stmt_info, gsi, slp_node, NULL);
13257 : 8487 : gcc_assert (done);
13258 : : break;
13259 : :
13260 : 12419 : case comparison_vec_info_type:
13261 : 12419 : done = vectorizable_comparison (vinfo, stmt_info, gsi, slp_node, NULL);
13262 : 12419 : gcc_assert (done);
13263 : : break;
13264 : :
13265 : 4200 : case call_vec_info_type:
13266 : 4200 : done = vectorizable_call (vinfo, stmt_info, gsi, slp_node, NULL);
13267 : 4200 : break;
13268 : :
13269 : 352 : case call_simd_clone_vec_info_type:
13270 : 352 : done = vectorizable_simd_clone_call (vinfo, stmt_info, gsi,
13271 : : slp_node, NULL);
13272 : 352 : break;
13273 : :
13274 : 2552 : case reduc_vec_info_type:
13275 : 2552 : done = vect_transform_reduction (as_a <loop_vec_info> (vinfo), stmt_info,
13276 : : gsi, slp_node);
13277 : 2552 : gcc_assert (done);
13278 : : break;
13279 : :
13280 : 23438 : case cycle_phi_info_type:
13281 : 23438 : done = vect_transform_cycle_phi (as_a <loop_vec_info> (vinfo), stmt_info,
13282 : : slp_node, slp_node_instance);
13283 : 23438 : gcc_assert (done);
13284 : : break;
13285 : :
13286 : 447 : case lc_phi_info_type:
13287 : 447 : done = vect_transform_lc_phi (as_a <loop_vec_info> (vinfo),
13288 : : stmt_info, slp_node);
13289 : 447 : gcc_assert (done);
13290 : : break;
13291 : :
13292 : 40 : case recurr_info_type:
13293 : 40 : done = vectorizable_recurr (as_a <loop_vec_info> (vinfo),
13294 : : stmt_info, slp_node, NULL);
13295 : 40 : gcc_assert (done);
13296 : : break;
13297 : :
13298 : 13469 : case phi_info_type:
13299 : 13469 : done = vectorizable_phi (as_a <bb_vec_info> (vinfo),
13300 : : stmt_info, slp_node, NULL);
13301 : 13469 : gcc_assert (done);
13302 : : break;
13303 : :
13304 : 0 : case loop_exit_ctrl_vec_info_type:
13305 : 0 : done = vectorizable_early_exit (as_a <loop_vec_info> (vinfo),
13306 : : stmt_info, gsi, slp_node, NULL);
13307 : 0 : gcc_assert (done);
13308 : : break;
13309 : :
13310 : 15950 : case permute_info_type:
13311 : 15950 : done = vectorizable_slp_permutation (vinfo, gsi, slp_node, NULL);
13312 : 15950 : gcc_assert (done);
13313 : : break;
13314 : :
13315 : 0 : default:
13316 : 0 : if (!STMT_VINFO_LIVE_P (stmt_info))
13317 : : {
13318 : 0 : if (dump_enabled_p ())
13319 : 0 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
13320 : : "stmt not supported.\n");
13321 : 0 : gcc_unreachable ();
13322 : : }
13323 : 960723 : done = true;
13324 : : }
13325 : :
13326 : 960723 : if (SLP_TREE_TYPE (slp_node) != store_vec_info_type
13327 : 416840 : && (!slp_node->ldst_lanes || SLP_TREE_PERMUTE_P (slp_node)))
13328 : : {
13329 : : /* Handle stmts whose DEF is used outside the loop-nest that is
13330 : : being vectorized. */
13331 : 416840 : done = can_vectorize_live_stmts (vinfo, slp_node,
13332 : : slp_node_instance, true, NULL);
13333 : 416840 : gcc_assert (done);
13334 : : }
13335 : :
13336 : 960723 : return is_store;
13337 : : }
13338 : :
13339 : :
13340 : : /* Remove a group of stores (for SLP or interleaving), free their
13341 : : stmt_vec_info. */
13342 : :
13343 : : void
13344 : 0 : vect_remove_stores (vec_info *vinfo, stmt_vec_info first_stmt_info)
13345 : : {
13346 : 0 : stmt_vec_info next_stmt_info = first_stmt_info;
13347 : :
13348 : 0 : while (next_stmt_info)
13349 : : {
13350 : 0 : stmt_vec_info tmp = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
13351 : 0 : next_stmt_info = vect_orig_stmt (next_stmt_info);
13352 : : /* Free the attached stmt_vec_info and remove the stmt. */
13353 : 0 : vinfo->remove_stmt (next_stmt_info);
13354 : 0 : next_stmt_info = tmp;
13355 : : }
13356 : 0 : }
13357 : :
13358 : : /* If NUNITS is nonzero, return a vector type that contains NUNITS
13359 : : elements of type SCALAR_TYPE, or null if the target doesn't support
13360 : : such a type.
13361 : :
13362 : : If NUNITS is zero, return a vector type that contains elements of
13363 : : type SCALAR_TYPE, choosing whichever vector size the target prefers.
13364 : :
13365 : : If PREVAILING_MODE is VOIDmode, we have not yet chosen a vector mode
13366 : : for this vectorization region and want to "autodetect" the best choice.
13367 : : Otherwise, PREVAILING_MODE is a previously-chosen vector TYPE_MODE
13368 : : and we want the new type to be interoperable with it. PREVAILING_MODE
13369 : : in this case can be a scalar integer mode or a vector mode; when it
13370 : : is a vector mode, the function acts like a tree-level version of
13371 : : related_vector_mode. */
13372 : :
13373 : : tree
13374 : 30058858 : get_related_vectype_for_scalar_type (machine_mode prevailing_mode,
13375 : : tree scalar_type, poly_uint64 nunits)
13376 : : {
13377 : 30058858 : tree orig_scalar_type = scalar_type;
13378 : 30058858 : scalar_mode inner_mode;
13379 : 30058858 : machine_mode simd_mode;
13380 : 30058858 : tree vectype;
13381 : :
13382 : 30058858 : if ((!INTEGRAL_TYPE_P (scalar_type)
13383 : 10414192 : && !POINTER_TYPE_P (scalar_type)
13384 : 1647973 : && !SCALAR_FLOAT_TYPE_P (scalar_type))
13385 : 39983122 : || (!is_int_mode (TYPE_MODE (scalar_type), &inner_mode)
13386 : 1158127 : && !is_float_mode (TYPE_MODE (scalar_type), &inner_mode)))
13387 : 493143 : return NULL_TREE;
13388 : :
13389 : 29565715 : unsigned int nbytes = GET_MODE_SIZE (inner_mode);
13390 : :
13391 : : /* Interoperability between modes requires one to be a constant multiple
13392 : : of the other, so that the number of vectors required for each operation
13393 : : is a compile-time constant. */
13394 : 29565715 : if (prevailing_mode != VOIDmode
13395 : 28424288 : && !constant_multiple_p (nunits * nbytes,
13396 : 28424288 : GET_MODE_SIZE (prevailing_mode))
13397 : 31079303 : && !constant_multiple_p (GET_MODE_SIZE (prevailing_mode),
13398 : 1513588 : nunits * nbytes))
13399 : : return NULL_TREE;
13400 : :
13401 : : /* For vector types of elements whose mode precision doesn't
13402 : : match their types precision we use a element type of mode
13403 : : precision. The vectorization routines will have to make sure
13404 : : they support the proper result truncation/extension.
13405 : : We also make sure to build vector types with INTEGER_TYPE
13406 : : component type only. */
13407 : 29565715 : if (INTEGRAL_TYPE_P (scalar_type)
13408 : 49210299 : && (GET_MODE_BITSIZE (inner_mode) != TYPE_PRECISION (scalar_type)
13409 : 18064870 : || TREE_CODE (scalar_type) != INTEGER_TYPE))
13410 : 1804487 : scalar_type = build_nonstandard_integer_type (GET_MODE_BITSIZE (inner_mode),
13411 : 1804487 : TYPE_UNSIGNED (scalar_type));
13412 : :
13413 : : /* We shouldn't end up building VECTOR_TYPEs of non-scalar components.
13414 : : When the component mode passes the above test simply use a type
13415 : : corresponding to that mode. The theory is that any use that
13416 : : would cause problems with this will disable vectorization anyway. */
13417 : 27761228 : else if (!SCALAR_FLOAT_TYPE_P (scalar_type)
13418 : : && !INTEGRAL_TYPE_P (scalar_type))
13419 : 8766219 : scalar_type = lang_hooks.types.type_for_mode (inner_mode, 1);
13420 : :
13421 : : /* We can't build a vector type of elements with alignment bigger than
13422 : : their size. */
13423 : 18995009 : else if (nbytes < TYPE_ALIGN_UNIT (scalar_type))
13424 : 346338 : scalar_type = lang_hooks.types.type_for_mode (inner_mode,
13425 : 173169 : TYPE_UNSIGNED (scalar_type));
13426 : :
13427 : : /* If we felt back to using the mode fail if there was
13428 : : no scalar type for it. */
13429 : 29565715 : if (scalar_type == NULL_TREE)
13430 : : return NULL_TREE;
13431 : :
13432 : : /* If no prevailing mode was supplied, use the mode the target prefers.
13433 : : Otherwise lookup a vector mode based on the prevailing mode. */
13434 : 29565715 : if (prevailing_mode == VOIDmode)
13435 : : {
13436 : 1141427 : gcc_assert (known_eq (nunits, 0U));
13437 : 1141427 : simd_mode = targetm.vectorize.preferred_simd_mode (inner_mode);
13438 : 1141427 : if (SCALAR_INT_MODE_P (simd_mode))
13439 : : {
13440 : : /* Traditional behavior is not to take the integer mode
13441 : : literally, but simply to use it as a way of determining
13442 : : the vector size. It is up to mode_for_vector to decide
13443 : : what the TYPE_MODE should be.
13444 : :
13445 : : Note that nunits == 1 is allowed in order to support single
13446 : : element vector types. */
13447 : 55904 : if (!multiple_p (GET_MODE_SIZE (simd_mode), nbytes, &nunits)
13448 : 545 : || !mode_for_vector (inner_mode, nunits).exists (&simd_mode))
13449 : 27407 : return NULL_TREE;
13450 : : }
13451 : : }
13452 : 28424288 : else if (SCALAR_INT_MODE_P (prevailing_mode)
13453 : 28424288 : || !related_vector_mode (prevailing_mode,
13454 : 26402124 : inner_mode, nunits).exists (&simd_mode))
13455 : : {
13456 : : /* Fall back to using mode_for_vector, mostly in the hope of being
13457 : : able to use an integer mode. */
13458 : 2022164 : if (known_eq (nunits, 0U)
13459 : 4696103 : && !multiple_p (GET_MODE_SIZE (prevailing_mode), nbytes, &nunits))
13460 : : return NULL_TREE;
13461 : :
13462 : 138559 : if (!mode_for_vector (inner_mode, nunits).exists (&simd_mode))
13463 : 128514 : return NULL_TREE;
13464 : : }
13465 : :
13466 : 27526189 : vectype = build_vector_type_for_mode (scalar_type, simd_mode);
13467 : :
13468 : : /* In cases where the mode was chosen by mode_for_vector, check that
13469 : : the target actually supports the chosen mode, or that it at least
13470 : : allows the vector mode to be replaced by a like-sized integer. */
13471 : 55052378 : if (!VECTOR_MODE_P (TYPE_MODE (vectype))
13472 : 27536492 : && !INTEGRAL_MODE_P (TYPE_MODE (vectype)))
13473 : : return NULL_TREE;
13474 : :
13475 : : /* Re-attach the address-space qualifier if we canonicalized the scalar
13476 : : type. */
13477 : 27518109 : if (TYPE_ADDR_SPACE (orig_scalar_type) != TYPE_ADDR_SPACE (vectype))
13478 : 5 : return build_qualified_type
13479 : 5 : (vectype, KEEP_QUAL_ADDR_SPACE (TYPE_QUALS (orig_scalar_type)));
13480 : :
13481 : : return vectype;
13482 : : }
13483 : :
13484 : : /* Function get_vectype_for_scalar_type.
13485 : :
13486 : : Returns the vector type corresponding to SCALAR_TYPE as supported
13487 : : by the target. If GROUP_SIZE is nonzero and we're performing BB
13488 : : vectorization, make sure that the number of elements in the vector
13489 : : is no bigger than GROUP_SIZE. */
13490 : :
13491 : : tree
13492 : 25560923 : get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type,
13493 : : unsigned int group_size)
13494 : : {
13495 : : /* For BB vectorization, we should always have a group size once we've
13496 : : constructed the SLP tree; the only valid uses of zero GROUP_SIZEs
13497 : : are tentative requests during things like early data reference
13498 : : analysis and pattern recognition. */
13499 : 25560923 : if (is_a <bb_vec_info> (vinfo))
13500 : 23869545 : gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0);
13501 : : else
13502 : : group_size = 0;
13503 : :
13504 : 25560923 : tree vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode,
13505 : : scalar_type);
13506 : 25560923 : if (vectype && vinfo->vector_mode == VOIDmode)
13507 : 1066776 : vinfo->vector_mode = TYPE_MODE (vectype);
13508 : :
13509 : : /* Register the natural choice of vector type, before the group size
13510 : : has been applied. */
13511 : 0 : if (vectype)
13512 : 23192823 : vinfo->used_vector_modes.add (TYPE_MODE (vectype));
13513 : :
13514 : : /* If the natural choice of vector type doesn't satisfy GROUP_SIZE,
13515 : : try again with an explicit number of elements. */
13516 : 23192823 : if (vectype
13517 : 23192823 : && group_size
13518 : 25560923 : && maybe_ge (TYPE_VECTOR_SUBPARTS (vectype), group_size))
13519 : : {
13520 : : /* Start with the biggest number of units that fits within
13521 : : GROUP_SIZE and halve it until we find a valid vector type.
13522 : : Usually either the first attempt will succeed or all will
13523 : : fail (in the latter case because GROUP_SIZE is too small
13524 : : for the target), but it's possible that a target could have
13525 : : a hole between supported vector types.
13526 : :
13527 : : If GROUP_SIZE is not a power of 2, this has the effect of
13528 : : trying the largest power of 2 that fits within the group,
13529 : : even though the group is not a multiple of that vector size.
13530 : : The BB vectorizer will then try to carve up the group into
13531 : : smaller pieces. */
13532 : 3056788 : unsigned int nunits = 1 << floor_log2 (group_size);
13533 : 3056788 : do
13534 : : {
13535 : 3056788 : vectype = get_related_vectype_for_scalar_type (vinfo->vector_mode,
13536 : 3056788 : scalar_type, nunits);
13537 : 3056788 : nunits /= 2;
13538 : : }
13539 : 3056788 : while (nunits > 1 && !vectype);
13540 : : }
13541 : :
13542 : 25560923 : return vectype;
13543 : : }
13544 : :
13545 : : /* Return the vector type corresponding to SCALAR_TYPE as supported
13546 : : by the target. NODE, if nonnull, is the SLP tree node that will
13547 : : use the returned vector type. */
13548 : :
13549 : : tree
13550 : 160157 : get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type, slp_tree node)
13551 : : {
13552 : 160157 : unsigned int group_size = 0;
13553 : 160157 : if (node)
13554 : 160157 : group_size = SLP_TREE_LANES (node);
13555 : 160157 : return get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
13556 : : }
13557 : :
13558 : : /* Function get_mask_type_for_scalar_type.
13559 : :
13560 : : Returns the mask type corresponding to a result of comparison
13561 : : of vectors of specified SCALAR_TYPE as supported by target.
13562 : : If GROUP_SIZE is nonzero and we're performing BB vectorization,
13563 : : make sure that the number of elements in the vector is no bigger
13564 : : than GROUP_SIZE. */
13565 : :
13566 : : tree
13567 : 996651 : get_mask_type_for_scalar_type (vec_info *vinfo, tree scalar_type,
13568 : : unsigned int group_size)
13569 : : {
13570 : 996651 : tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
13571 : :
13572 : 996651 : if (!vectype)
13573 : : return NULL;
13574 : :
13575 : 976111 : return truth_type_for (vectype);
13576 : : }
13577 : :
13578 : : /* Function get_mask_type_for_scalar_type.
13579 : :
13580 : : Returns the mask type corresponding to a result of comparison
13581 : : of vectors of specified SCALAR_TYPE as supported by target.
13582 : : NODE, if nonnull, is the SLP tree node that will use the returned
13583 : : vector type. */
13584 : :
13585 : : tree
13586 : 17 : get_mask_type_for_scalar_type (vec_info *vinfo, tree scalar_type,
13587 : : slp_tree node)
13588 : : {
13589 : 17 : tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type, node);
13590 : :
13591 : 17 : if (!vectype)
13592 : : return NULL;
13593 : :
13594 : 17 : return truth_type_for (vectype);
13595 : : }
13596 : :
13597 : : /* Function get_same_sized_vectype
13598 : :
13599 : : Returns a vector type corresponding to SCALAR_TYPE of size
13600 : : VECTOR_TYPE if supported by the target. */
13601 : :
13602 : : tree
13603 : 125654 : get_same_sized_vectype (tree scalar_type, tree vector_type)
13604 : : {
13605 : 125654 : if (VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type))
13606 : 0 : return truth_type_for (vector_type);
13607 : :
13608 : 125654 : poly_uint64 nunits;
13609 : 251308 : if (!multiple_p (GET_MODE_SIZE (TYPE_MODE (vector_type)),
13610 : 251308 : GET_MODE_SIZE (TYPE_MODE (scalar_type)), &nunits))
13611 : : return NULL_TREE;
13612 : :
13613 : 125654 : return get_related_vectype_for_scalar_type (TYPE_MODE (vector_type),
13614 : 125654 : scalar_type, nunits);
13615 : : }
13616 : :
13617 : : /* Return true if replacing LOOP_VINFO->vector_mode with VECTOR_MODE
13618 : : would not change the chosen vector modes. */
13619 : :
13620 : : bool
13621 : 1442853 : vect_chooses_same_modes_p (vec_info *vinfo, machine_mode vector_mode)
13622 : : {
13623 : 1442853 : for (vec_info::mode_set::iterator i = vinfo->used_vector_modes.begin ();
13624 : 3393763 : i != vinfo->used_vector_modes.end (); ++i)
13625 : 1747161 : if (!VECTOR_MODE_P (*i)
13626 : 5241483 : || related_vector_mode (vector_mode, GET_MODE_INNER (*i), 0) != *i)
13627 : 771706 : return false;
13628 : 671147 : return true;
13629 : : }
13630 : :
13631 : : /* Return true if replacing VECTOR_MODE with ALT_VECTOR_MODE would not
13632 : : change the chosen vector modes for analysis of a loop. */
13633 : :
13634 : : bool
13635 : 297835 : vect_chooses_same_modes_p (machine_mode vector_mode,
13636 : : machine_mode alt_vector_mode)
13637 : : {
13638 : 50071 : return (VECTOR_MODE_P (vector_mode)
13639 : 297835 : && VECTOR_MODE_P (alt_vector_mode)
13640 : 595670 : && (related_vector_mode (vector_mode,
13641 : : GET_MODE_INNER (alt_vector_mode))
13642 : 297835 : == alt_vector_mode)
13643 : 323277 : && (related_vector_mode (alt_vector_mode,
13644 : : GET_MODE_INNER (vector_mode))
13645 : 12721 : == vector_mode));
13646 : : }
13647 : :
13648 : : /* Function vect_is_simple_use.
13649 : :
13650 : : Input:
13651 : : VINFO - the vect info of the loop or basic block that is being vectorized.
13652 : : OPERAND - operand in the loop or bb.
13653 : : Output:
13654 : : DEF_STMT_INFO_OUT (optional) - information about the defining stmt in
13655 : : case OPERAND is an SSA_NAME that is defined in the vectorizable region
13656 : : DEF_STMT_OUT (optional) - the defining stmt in case OPERAND is an SSA_NAME;
13657 : : the definition could be anywhere in the function
13658 : : DT - the type of definition
13659 : :
13660 : : Returns whether a stmt with OPERAND can be vectorized.
13661 : : For loops, supportable operands are constants, loop invariants, and operands
13662 : : that are defined by the current iteration of the loop. Unsupportable
13663 : : operands are those that are defined by a previous iteration of the loop (as
13664 : : is the case in reduction/induction computations).
13665 : : For basic blocks, supportable operands are constants and bb invariants.
13666 : : For now, operands defined outside the basic block are not supported. */
13667 : :
13668 : : bool
13669 : 39002743 : vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
13670 : : stmt_vec_info *def_stmt_info_out, gimple **def_stmt_out)
13671 : : {
13672 : 39002743 : if (def_stmt_info_out)
13673 : 37239660 : *def_stmt_info_out = NULL;
13674 : 39002743 : if (def_stmt_out)
13675 : 9141258 : *def_stmt_out = NULL;
13676 : 39002743 : *dt = vect_unknown_def_type;
13677 : :
13678 : 39002743 : if (dump_enabled_p ())
13679 : : {
13680 : 716732 : dump_printf_loc (MSG_NOTE, vect_location,
13681 : : "vect_is_simple_use: operand ");
13682 : 716732 : if (TREE_CODE (operand) == SSA_NAME
13683 : 716732 : && !SSA_NAME_IS_DEFAULT_DEF (operand))
13684 : 658102 : dump_gimple_expr (MSG_NOTE, TDF_SLIM, SSA_NAME_DEF_STMT (operand), 0);
13685 : : else
13686 : 58630 : dump_generic_expr (MSG_NOTE, TDF_SLIM, operand);
13687 : : }
13688 : :
13689 : 39002743 : if (CONSTANT_CLASS_P (operand))
13690 : 2543928 : *dt = vect_constant_def;
13691 : 36458815 : else if (is_gimple_min_invariant (operand))
13692 : 339869 : *dt = vect_external_def;
13693 : 36118946 : else if (TREE_CODE (operand) != SSA_NAME)
13694 : 1109 : *dt = vect_unknown_def_type;
13695 : 36117837 : else if (SSA_NAME_IS_DEFAULT_DEF (operand))
13696 : 516333 : *dt = vect_external_def;
13697 : : else
13698 : : {
13699 : 35601504 : gimple *def_stmt = SSA_NAME_DEF_STMT (operand);
13700 : 35601504 : stmt_vec_info stmt_vinfo = vinfo->lookup_def (operand);
13701 : 35601504 : if (!stmt_vinfo)
13702 : 730534 : *dt = vect_external_def;
13703 : : else
13704 : : {
13705 : 34870970 : stmt_vinfo = vect_stmt_to_vectorize (stmt_vinfo);
13706 : 34870970 : def_stmt = stmt_vinfo->stmt;
13707 : 34870970 : *dt = STMT_VINFO_DEF_TYPE (stmt_vinfo);
13708 : 34870970 : if (def_stmt_info_out)
13709 : 33114265 : *def_stmt_info_out = stmt_vinfo;
13710 : : }
13711 : 35601504 : if (def_stmt_out)
13712 : 8925782 : *def_stmt_out = def_stmt;
13713 : : }
13714 : :
13715 : 39002743 : if (dump_enabled_p ())
13716 : : {
13717 : 716732 : dump_printf (MSG_NOTE, ", type of def: ");
13718 : 716732 : switch (*dt)
13719 : : {
13720 : 0 : case vect_uninitialized_def:
13721 : 0 : dump_printf (MSG_NOTE, "uninitialized\n");
13722 : 0 : break;
13723 : 48318 : case vect_constant_def:
13724 : 48318 : dump_printf (MSG_NOTE, "constant\n");
13725 : 48318 : break;
13726 : 24498 : case vect_external_def:
13727 : 24498 : dump_printf (MSG_NOTE, "external\n");
13728 : 24498 : break;
13729 : 516295 : case vect_internal_def:
13730 : 516295 : dump_printf (MSG_NOTE, "internal\n");
13731 : 516295 : break;
13732 : 99754 : case vect_induction_def:
13733 : 99754 : dump_printf (MSG_NOTE, "induction\n");
13734 : 99754 : break;
13735 : 24883 : case vect_reduction_def:
13736 : 24883 : dump_printf (MSG_NOTE, "reduction\n");
13737 : 24883 : break;
13738 : 464 : case vect_double_reduction_def:
13739 : 464 : dump_printf (MSG_NOTE, "double reduction\n");
13740 : 464 : break;
13741 : 1857 : case vect_nested_cycle:
13742 : 1857 : dump_printf (MSG_NOTE, "nested cycle\n");
13743 : 1857 : break;
13744 : 264 : case vect_first_order_recurrence:
13745 : 264 : dump_printf (MSG_NOTE, "first order recurrence\n");
13746 : 264 : break;
13747 : 0 : case vect_condition_def:
13748 : 0 : dump_printf (MSG_NOTE, "control flow\n");
13749 : 0 : break;
13750 : 399 : case vect_unknown_def_type:
13751 : 399 : dump_printf (MSG_NOTE, "unknown\n");
13752 : 399 : break;
13753 : : }
13754 : : }
13755 : :
13756 : 39002743 : if (*dt == vect_unknown_def_type)
13757 : : {
13758 : 17788 : if (dump_enabled_p ())
13759 : 399 : dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
13760 : : "Unsupported pattern.\n");
13761 : 17788 : return false;
13762 : : }
13763 : :
13764 : : return true;
13765 : : }
13766 : :
13767 : : /* Function vect_is_simple_use.
13768 : :
13769 : : Same as vect_is_simple_use but determines the operand by operand
13770 : : position OPERAND from either STMT or SLP_NODE, filling in *OP
13771 : : and *SLP_DEF (when SLP_NODE is not NULL). */
13772 : :
13773 : : bool
13774 : 3350730 : vect_is_simple_use (vec_info *vinfo, slp_tree slp_node,
13775 : : unsigned operand, tree *op, slp_tree *slp_def,
13776 : : enum vect_def_type *dt,
13777 : : tree *vectype, stmt_vec_info *def_stmt_info_out)
13778 : : {
13779 : 3350730 : slp_tree child = SLP_TREE_CHILDREN (slp_node)[operand];
13780 : 3350730 : *slp_def = child;
13781 : 3350730 : *vectype = SLP_TREE_VECTYPE (child);
13782 : 3350730 : if (SLP_TREE_DEF_TYPE (child) == vect_internal_def)
13783 : : {
13784 : : /* ??? VEC_PERM nodes might be intermediate and their lane value
13785 : : have no representative (nor do we build a VEC_PERM stmt for
13786 : : the actual operation). Note for two-operator nodes we set
13787 : : a representative but leave scalar stmts empty as we'd only
13788 : : have one for a subset of lanes. Ideally no caller would
13789 : : require *op for internal defs. */
13790 : 1731324 : if (SLP_TREE_REPRESENTATIVE (child))
13791 : : {
13792 : 1730658 : *op = gimple_get_lhs (SLP_TREE_REPRESENTATIVE (child)->stmt);
13793 : 1730658 : return vect_is_simple_use (*op, vinfo, dt, def_stmt_info_out);
13794 : : }
13795 : : else
13796 : : {
13797 : 666 : gcc_assert (SLP_TREE_PERMUTE_P (child));
13798 : 666 : *op = error_mark_node;
13799 : 666 : *dt = vect_internal_def;
13800 : 666 : if (def_stmt_info_out)
13801 : 0 : *def_stmt_info_out = NULL;
13802 : 666 : return true;
13803 : : }
13804 : : }
13805 : : else
13806 : : {
13807 : 1619406 : if (def_stmt_info_out)
13808 : 45896 : *def_stmt_info_out = NULL;
13809 : 1619406 : *op = SLP_TREE_SCALAR_OPS (child)[0];
13810 : 1619406 : *dt = SLP_TREE_DEF_TYPE (child);
13811 : 1619406 : return true;
13812 : : }
13813 : : }
13814 : :
13815 : : /* If OP is not NULL and is external or constant update its vector
13816 : : type with VECTYPE. Returns true if successful or false if not,
13817 : : for example when conflicting vector types are present. */
13818 : :
13819 : : bool
13820 : 2902134 : vect_maybe_update_slp_op_vectype (slp_tree op, tree vectype)
13821 : : {
13822 : 2902134 : if (!op || SLP_TREE_DEF_TYPE (op) == vect_internal_def)
13823 : : return true;
13824 : 1062079 : if (SLP_TREE_VECTYPE (op))
13825 : 66270 : return types_compatible_p (SLP_TREE_VECTYPE (op), vectype);
13826 : : /* For external defs refuse to produce VECTOR_BOOLEAN_TYPE_P, those
13827 : : should be handled by patters. Allow vect_constant_def for now
13828 : : as well as the trivial single-lane uniform vect_external_def case
13829 : : both of which we code-generate reasonably. */
13830 : 995809 : if (VECTOR_BOOLEAN_TYPE_P (vectype)
13831 : 1035 : && SLP_TREE_DEF_TYPE (op) == vect_external_def
13832 : 996466 : && SLP_TREE_LANES (op) > 1)
13833 : : return false;
13834 : 995626 : SLP_TREE_VECTYPE (op) = vectype;
13835 : 995626 : return true;
13836 : : }
13837 : :
13838 : : /* Function supportable_widening_operation
13839 : :
13840 : : Check whether an operation represented by the code CODE is a
13841 : : widening operation that is supported by the target platform in
13842 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
13843 : : producing a result of type VECTYPE_OUT).
13844 : :
13845 : : Widening operations we currently support are NOP (CONVERT), FLOAT,
13846 : : FIX_TRUNC and WIDEN_MULT. This function checks if these operations
13847 : : are supported by the target platform either directly (via vector
13848 : : tree-codes), or via target builtins.
13849 : :
13850 : : When EVENODD_OK then also lane-swizzling operations are considered.
13851 : :
13852 : : Output:
13853 : : - CODE1 and CODE2 are codes of vector operations to be used when
13854 : : vectorizing the operation, if available.
13855 : : - MULTI_STEP_CVT determines the number of required intermediate steps in
13856 : : case of multi-step conversion (like char->short->int - in that case
13857 : : MULTI_STEP_CVT will be 1).
13858 : : - INTERM_TYPES contains the intermediate type required to perform the
13859 : : widening operation (short in the above example). */
13860 : :
13861 : : bool
13862 : 436503 : supportable_widening_operation (code_helper code,
13863 : : tree vectype_out, tree vectype_in,
13864 : : bool evenodd_ok,
13865 : : code_helper *code1,
13866 : : code_helper *code2,
13867 : : int *multi_step_cvt,
13868 : : vec<tree> *interm_types)
13869 : : {
13870 : 436503 : machine_mode vec_mode;
13871 : 436503 : enum insn_code icode1, icode2;
13872 : 436503 : optab optab1 = unknown_optab, optab2 = unknown_optab;
13873 : 436503 : tree vectype = vectype_in;
13874 : 436503 : tree wide_vectype = vectype_out;
13875 : 436503 : tree_code c1 = MAX_TREE_CODES, c2 = MAX_TREE_CODES;
13876 : 436503 : int i;
13877 : 436503 : tree prev_type, intermediate_type;
13878 : 436503 : machine_mode intermediate_mode, prev_mode;
13879 : 436503 : optab optab3, optab4;
13880 : :
13881 : 436503 : *multi_step_cvt = 0;
13882 : :
13883 : 436503 : switch (code.safe_as_tree_code ())
13884 : : {
13885 : : case MAX_TREE_CODES:
13886 : : /* Don't set c1 and c2 if code is not a tree_code. */
13887 : : break;
13888 : :
13889 : 167052 : case WIDEN_MULT_EXPR:
13890 : : /* The result of a vectorized widening operation usually requires
13891 : : two vectors (because the widened results do not fit into one vector).
13892 : : The generated vector results would normally be expected to be
13893 : : generated in the same order as in the original scalar computation,
13894 : : i.e. if 8 results are generated in each vector iteration, they are
13895 : : to be organized as follows:
13896 : : vect1: [res1,res2,res3,res4],
13897 : : vect2: [res5,res6,res7,res8].
13898 : :
13899 : : However, in the special case that the result of the widening
13900 : : operation is used in a reduction computation only, the order doesn't
13901 : : matter (because when vectorizing a reduction we change the order of
13902 : : the computation). Some targets can take advantage of this and
13903 : : generate more efficient code. For example, targets like Altivec,
13904 : : that support widen_mult using a sequence of {mult_even,mult_odd}
13905 : : generate the following vectors:
13906 : : vect1: [res1,res3,res5,res7],
13907 : : vect2: [res2,res4,res6,res8].
13908 : :
13909 : : When vectorizing outer-loops, we execute the inner-loop sequentially
13910 : : (each vectorized inner-loop iteration contributes to VF outer-loop
13911 : : iterations in parallel). We therefore don't allow to change the
13912 : : order of the computation in the inner-loop during outer-loop
13913 : : vectorization. */
13914 : : /* TODO: Another case in which order doesn't *really* matter is when we
13915 : : widen and then contract again, e.g. (short)((int)x * y >> 8).
13916 : : Normally, pack_trunc performs an even/odd permute, whereas the
13917 : : repack from an even/odd expansion would be an interleave, which
13918 : : would be significantly simpler for e.g. AVX2. */
13919 : : /* In any case, in order to avoid duplicating the code below, recurse
13920 : : on VEC_WIDEN_MULT_EVEN_EXPR. If it succeeds, all the return values
13921 : : are properly set up for the caller. If we fail, we'll continue with
13922 : : a VEC_WIDEN_MULT_LO/HI_EXPR check. */
13923 : 167052 : if (evenodd_ok
13924 : 167052 : && supportable_widening_operation (VEC_WIDEN_MULT_EVEN_EXPR,
13925 : : vectype_out, vectype_in,
13926 : : evenodd_ok, code1,
13927 : : code2, multi_step_cvt,
13928 : : interm_types))
13929 : 88541 : return true;
13930 : : c1 = VEC_WIDEN_MULT_LO_EXPR;
13931 : : c2 = VEC_WIDEN_MULT_HI_EXPR;
13932 : : break;
13933 : :
13934 : : case DOT_PROD_EXPR:
13935 : 347962 : c1 = DOT_PROD_EXPR;
13936 : 347962 : c2 = DOT_PROD_EXPR;
13937 : : break;
13938 : :
13939 : 0 : case SAD_EXPR:
13940 : 0 : c1 = SAD_EXPR;
13941 : 0 : c2 = SAD_EXPR;
13942 : 0 : break;
13943 : :
13944 : 164856 : case VEC_WIDEN_MULT_EVEN_EXPR:
13945 : : /* Support the recursion induced just above. */
13946 : 164856 : c1 = VEC_WIDEN_MULT_EVEN_EXPR;
13947 : 164856 : c2 = VEC_WIDEN_MULT_ODD_EXPR;
13948 : 164856 : break;
13949 : :
13950 : 9648 : case WIDEN_LSHIFT_EXPR:
13951 : 9648 : c1 = VEC_WIDEN_LSHIFT_LO_EXPR;
13952 : 9648 : c2 = VEC_WIDEN_LSHIFT_HI_EXPR;
13953 : 9648 : break;
13954 : :
13955 : 34530 : CASE_CONVERT:
13956 : 34530 : c1 = VEC_UNPACK_LO_EXPR;
13957 : 34530 : c2 = VEC_UNPACK_HI_EXPR;
13958 : 34530 : break;
13959 : :
13960 : 7386 : case FLOAT_EXPR:
13961 : 7386 : c1 = VEC_UNPACK_FLOAT_LO_EXPR;
13962 : 7386 : c2 = VEC_UNPACK_FLOAT_HI_EXPR;
13963 : 7386 : break;
13964 : :
13965 : 158 : case FIX_TRUNC_EXPR:
13966 : 158 : c1 = VEC_UNPACK_FIX_TRUNC_LO_EXPR;
13967 : 158 : c2 = VEC_UNPACK_FIX_TRUNC_HI_EXPR;
13968 : 158 : break;
13969 : :
13970 : 0 : default:
13971 : 0 : gcc_unreachable ();
13972 : : }
13973 : :
13974 : 347962 : if (BYTES_BIG_ENDIAN && c1 != VEC_WIDEN_MULT_EVEN_EXPR)
13975 : : std::swap (c1, c2);
13976 : :
13977 : 347962 : if (code == FIX_TRUNC_EXPR)
13978 : : {
13979 : : /* The signedness is determined from output operand. */
13980 : 158 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
13981 : 158 : optab2 = optab_for_tree_code (c2, vectype_out, optab_default);
13982 : : }
13983 : 614375 : else if (CONVERT_EXPR_CODE_P (code.safe_as_tree_code ())
13984 : 34530 : && VECTOR_BOOLEAN_TYPE_P (wide_vectype)
13985 : 5928 : && VECTOR_BOOLEAN_TYPE_P (vectype)
13986 : 5928 : && TYPE_MODE (wide_vectype) == TYPE_MODE (vectype)
13987 : 295246 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype)))
13988 : : {
13989 : : /* If the input and result modes are the same, a different optab
13990 : : is needed where we pass in the number of units in vectype. */
13991 : : optab1 = vec_unpacks_sbool_lo_optab;
13992 : : optab2 = vec_unpacks_sbool_hi_optab;
13993 : : }
13994 : :
13995 : 347962 : vec_mode = TYPE_MODE (vectype);
13996 : 347962 : if (widening_fn_p (code))
13997 : : {
13998 : : /* If this is an internal fn then we must check whether the target
13999 : : supports either a low-high split or an even-odd split. */
14000 : 52873 : internal_fn ifn = as_internal_fn ((combined_fn) code);
14001 : :
14002 : 52873 : internal_fn lo, hi, even, odd;
14003 : 52873 : lookup_hilo_internal_fn (ifn, &lo, &hi);
14004 : 52873 : if (BYTES_BIG_ENDIAN)
14005 : : std::swap (lo, hi);
14006 : 52873 : *code1 = as_combined_fn (lo);
14007 : 52873 : *code2 = as_combined_fn (hi);
14008 : 52873 : optab1 = direct_internal_fn_optab (lo, {vectype, vectype});
14009 : 52873 : optab2 = direct_internal_fn_optab (hi, {vectype, vectype});
14010 : :
14011 : : /* If we don't support low-high, then check for even-odd. */
14012 : 52873 : if (!optab1
14013 : 52873 : || (icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing
14014 : 0 : || !optab2
14015 : 52873 : || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing)
14016 : : {
14017 : 52873 : lookup_evenodd_internal_fn (ifn, &even, &odd);
14018 : 52873 : *code1 = as_combined_fn (even);
14019 : 52873 : *code2 = as_combined_fn (odd);
14020 : 52873 : optab1 = direct_internal_fn_optab (even, {vectype, vectype});
14021 : 52873 : optab2 = direct_internal_fn_optab (odd, {vectype, vectype});
14022 : : }
14023 : : }
14024 : 295089 : else if (code.is_tree_code ())
14025 : : {
14026 : 295089 : if (code == FIX_TRUNC_EXPR)
14027 : : {
14028 : : /* The signedness is determined from output operand. */
14029 : 158 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
14030 : 158 : optab2 = optab_for_tree_code (c2, vectype_out, optab_default);
14031 : : }
14032 : 294931 : else if (CONVERT_EXPR_CODE_P ((tree_code) code.safe_as_tree_code ())
14033 : 34530 : && VECTOR_BOOLEAN_TYPE_P (wide_vectype)
14034 : 5928 : && VECTOR_BOOLEAN_TYPE_P (vectype)
14035 : 5928 : && TYPE_MODE (wide_vectype) == TYPE_MODE (vectype)
14036 : 295246 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype)))
14037 : : {
14038 : : /* If the input and result modes are the same, a different optab
14039 : : is needed where we pass in the number of units in vectype. */
14040 : : optab1 = vec_unpacks_sbool_lo_optab;
14041 : : optab2 = vec_unpacks_sbool_hi_optab;
14042 : : }
14043 : : else
14044 : : {
14045 : 294616 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
14046 : 294616 : optab2 = optab_for_tree_code (c2, vectype, optab_default);
14047 : : }
14048 : 295089 : *code1 = c1;
14049 : 295089 : *code2 = c2;
14050 : : }
14051 : :
14052 : 347962 : if (!optab1 || !optab2)
14053 : : return false;
14054 : :
14055 : 347962 : if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing
14056 : 347962 : || (icode2 = optab_handler (optab2, vec_mode)) == CODE_FOR_nothing)
14057 : 207308 : return false;
14058 : :
14059 : :
14060 : 140654 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype)
14061 : 140654 : && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype))
14062 : : {
14063 : 130914 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14064 : : return true;
14065 : : /* For scalar masks we may have different boolean
14066 : : vector types having the same QImode. Thus we
14067 : : add additional check for elements number. */
14068 : 2992 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype),
14069 : : TYPE_VECTOR_SUBPARTS (wide_vectype) * 2))
14070 : : return true;
14071 : : }
14072 : :
14073 : : /* Check if it's a multi-step conversion that can be done using intermediate
14074 : : types. */
14075 : :
14076 : 9861 : prev_type = vectype;
14077 : 9861 : prev_mode = vec_mode;
14078 : :
14079 : 217394 : if (!CONVERT_EXPR_CODE_P (code.safe_as_tree_code ()))
14080 : : return false;
14081 : :
14082 : : /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS
14083 : : intermediate steps in promotion sequence. We try
14084 : : MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do
14085 : : not. */
14086 : 9809 : interm_types->create (MAX_INTERM_CVT_STEPS);
14087 : 11171 : for (i = 0; i < MAX_INTERM_CVT_STEPS; i++)
14088 : : {
14089 : 11171 : intermediate_mode = insn_data[icode1].operand[0].mode;
14090 : 11171 : if (VECTOR_BOOLEAN_TYPE_P (prev_type))
14091 : 3920 : intermediate_type
14092 : 3920 : = vect_halve_mask_nunits (prev_type, intermediate_mode);
14093 : 7251 : else if (VECTOR_MODE_P (intermediate_mode))
14094 : : {
14095 : 7251 : tree intermediate_element_type
14096 : 7251 : = lang_hooks.types.type_for_mode (GET_MODE_INNER (intermediate_mode),
14097 : 7251 : TYPE_UNSIGNED (prev_type));
14098 : 7251 : intermediate_type
14099 : 7251 : = build_vector_type_for_mode (intermediate_element_type,
14100 : : intermediate_mode);
14101 : 7251 : }
14102 : : else
14103 : 0 : intermediate_type
14104 : 0 : = lang_hooks.types.type_for_mode (intermediate_mode,
14105 : 0 : TYPE_UNSIGNED (prev_type));
14106 : :
14107 : 11171 : if (VECTOR_BOOLEAN_TYPE_P (intermediate_type)
14108 : 3920 : && VECTOR_BOOLEAN_TYPE_P (wide_vectype)
14109 : 3920 : && intermediate_mode == TYPE_MODE (wide_vectype)
14110 : 11328 : && SCALAR_INT_MODE_P (intermediate_mode))
14111 : : {
14112 : : /* If the input and result modes are the same, a different optab
14113 : : is needed where we pass in the number of units in vectype. */
14114 : : optab3 = vec_unpacks_sbool_lo_optab;
14115 : : optab4 = vec_unpacks_sbool_hi_optab;
14116 : : }
14117 : : else
14118 : : {
14119 : 11014 : optab3 = optab_for_tree_code (c1, intermediate_type, optab_default);
14120 : 11014 : optab4 = optab_for_tree_code (c2, intermediate_type, optab_default);
14121 : : }
14122 : :
14123 : 11171 : if (!optab3 || !optab4
14124 : 11171 : || (icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing
14125 : 11155 : || insn_data[icode1].operand[0].mode != intermediate_mode
14126 : 11155 : || (icode2 = optab_handler (optab2, prev_mode)) == CODE_FOR_nothing
14127 : 11155 : || insn_data[icode2].operand[0].mode != intermediate_mode
14128 : 11155 : || ((icode1 = optab_handler (optab3, intermediate_mode))
14129 : : == CODE_FOR_nothing)
14130 : 22117 : || ((icode2 = optab_handler (optab4, intermediate_mode))
14131 : : == CODE_FOR_nothing))
14132 : : break;
14133 : :
14134 : 10946 : interm_types->quick_push (intermediate_type);
14135 : 10946 : (*multi_step_cvt)++;
14136 : :
14137 : 10946 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (wide_vectype)
14138 : 10946 : && insn_data[icode2].operand[0].mode == TYPE_MODE (wide_vectype))
14139 : : {
14140 : 9620 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14141 : : return true;
14142 : 2874 : if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type),
14143 : : TYPE_VECTOR_SUBPARTS (wide_vectype) * 2))
14144 : : return true;
14145 : : }
14146 : :
14147 : 1362 : prev_type = intermediate_type;
14148 : 1362 : prev_mode = intermediate_mode;
14149 : : }
14150 : :
14151 : 225 : interm_types->release ();
14152 : 225 : return false;
14153 : : }
14154 : :
14155 : :
14156 : : /* Function supportable_narrowing_operation
14157 : :
14158 : : Check whether an operation represented by the code CODE is a
14159 : : narrowing operation that is supported by the target platform in
14160 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
14161 : : and producing a result of type VECTYPE_OUT).
14162 : :
14163 : : Narrowing operations we currently support are NOP (CONVERT), FIX_TRUNC
14164 : : and FLOAT. This function checks if these operations are supported by
14165 : : the target platform directly via vector tree-codes.
14166 : :
14167 : : Output:
14168 : : - CODE1 is the code of a vector operation to be used when
14169 : : vectorizing the operation, if available.
14170 : : - MULTI_STEP_CVT determines the number of required intermediate steps in
14171 : : case of multi-step conversion (like int->short->char - in that case
14172 : : MULTI_STEP_CVT will be 1).
14173 : : - INTERM_TYPES contains the intermediate type required to perform the
14174 : : narrowing operation (short in the above example). */
14175 : :
14176 : : bool
14177 : 36280 : supportable_narrowing_operation (code_helper code,
14178 : : tree vectype_out, tree vectype_in,
14179 : : code_helper *code1, int *multi_step_cvt,
14180 : : vec<tree> *interm_types)
14181 : : {
14182 : 36280 : machine_mode vec_mode;
14183 : 36280 : enum insn_code icode1;
14184 : 36280 : optab optab1, interm_optab;
14185 : 36280 : tree vectype = vectype_in;
14186 : 36280 : tree narrow_vectype = vectype_out;
14187 : 36280 : enum tree_code c1;
14188 : 36280 : tree intermediate_type, prev_type;
14189 : 36280 : machine_mode intermediate_mode, prev_mode;
14190 : 36280 : int i;
14191 : 36280 : unsigned HOST_WIDE_INT n_elts;
14192 : 36280 : bool uns;
14193 : :
14194 : 36280 : if (!code.is_tree_code ())
14195 : : return false;
14196 : :
14197 : 36280 : *multi_step_cvt = 0;
14198 : 36280 : switch ((tree_code) code)
14199 : : {
14200 : 35237 : CASE_CONVERT:
14201 : 35237 : c1 = VEC_PACK_TRUNC_EXPR;
14202 : 35237 : if (VECTOR_BOOLEAN_TYPE_P (narrow_vectype)
14203 : 9461 : && VECTOR_BOOLEAN_TYPE_P (vectype)
14204 : 9461 : && SCALAR_INT_MODE_P (TYPE_MODE (vectype))
14205 : 4386 : && TYPE_VECTOR_SUBPARTS (vectype).is_constant (&n_elts)
14206 : 39623 : && n_elts < BITS_PER_UNIT)
14207 : : optab1 = vec_pack_sbool_trunc_optab;
14208 : : else
14209 : 33434 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
14210 : : break;
14211 : :
14212 : 825 : case FIX_TRUNC_EXPR:
14213 : 825 : c1 = VEC_PACK_FIX_TRUNC_EXPR;
14214 : : /* The signedness is determined from output operand. */
14215 : 825 : optab1 = optab_for_tree_code (c1, vectype_out, optab_default);
14216 : 825 : break;
14217 : :
14218 : 218 : case FLOAT_EXPR:
14219 : 218 : c1 = VEC_PACK_FLOAT_EXPR;
14220 : 218 : optab1 = optab_for_tree_code (c1, vectype, optab_default);
14221 : 218 : break;
14222 : :
14223 : 0 : default:
14224 : 0 : gcc_unreachable ();
14225 : : }
14226 : :
14227 : 36280 : if (!optab1)
14228 : : return false;
14229 : :
14230 : 36280 : vec_mode = TYPE_MODE (vectype);
14231 : 36280 : if ((icode1 = optab_handler (optab1, vec_mode)) == CODE_FOR_nothing)
14232 : : return false;
14233 : :
14234 : 32328 : *code1 = c1;
14235 : :
14236 : 32328 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype))
14237 : : {
14238 : 19171 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14239 : : return true;
14240 : : /* For scalar masks we may have different boolean
14241 : : vector types having the same QImode. Thus we
14242 : : add additional check for elements number. */
14243 : 4647 : if (known_eq (TYPE_VECTOR_SUBPARTS (vectype) * 2,
14244 : : TYPE_VECTOR_SUBPARTS (narrow_vectype)))
14245 : : return true;
14246 : : }
14247 : :
14248 : 13158 : if (code == FLOAT_EXPR)
14249 : : return false;
14250 : :
14251 : : /* Check if it's a multi-step conversion that can be done using intermediate
14252 : : types. */
14253 : 13158 : prev_mode = vec_mode;
14254 : 13158 : prev_type = vectype;
14255 : 13158 : if (code == FIX_TRUNC_EXPR)
14256 : 183 : uns = TYPE_UNSIGNED (vectype_out);
14257 : : else
14258 : 12975 : uns = TYPE_UNSIGNED (vectype);
14259 : :
14260 : : /* For multi-step FIX_TRUNC_EXPR prefer signed floating to integer
14261 : : conversion over unsigned, as unsigned FIX_TRUNC_EXPR is often more
14262 : : costly than signed. */
14263 : 13158 : if (code == FIX_TRUNC_EXPR && uns)
14264 : : {
14265 : 76 : enum insn_code icode2;
14266 : :
14267 : 76 : intermediate_type
14268 : 76 : = lang_hooks.types.type_for_mode (TYPE_MODE (vectype_out), 0);
14269 : 76 : interm_optab
14270 : 76 : = optab_for_tree_code (c1, intermediate_type, optab_default);
14271 : 76 : if (interm_optab != unknown_optab
14272 : 76 : && (icode2 = optab_handler (optab1, vec_mode)) != CODE_FOR_nothing
14273 : 76 : && insn_data[icode1].operand[0].mode
14274 : 76 : == insn_data[icode2].operand[0].mode)
14275 : : {
14276 : : uns = false;
14277 : : optab1 = interm_optab;
14278 : : icode1 = icode2;
14279 : : }
14280 : : }
14281 : :
14282 : : /* We assume here that there will not be more than MAX_INTERM_CVT_STEPS
14283 : : intermediate steps in promotion sequence. We try
14284 : : MAX_INTERM_CVT_STEPS to get to NARROW_VECTYPE, and fail if we do not. */
14285 : 13158 : interm_types->create (MAX_INTERM_CVT_STEPS);
14286 : 28323 : for (i = 0; i < MAX_INTERM_CVT_STEPS; i++)
14287 : : {
14288 : 15165 : intermediate_mode = insn_data[icode1].operand[0].mode;
14289 : 15165 : if (VECTOR_BOOLEAN_TYPE_P (prev_type))
14290 : 5911 : intermediate_type
14291 : 5911 : = vect_double_mask_nunits (prev_type, intermediate_mode);
14292 : : else
14293 : 9254 : intermediate_type
14294 : 9254 : = lang_hooks.types.type_for_mode (intermediate_mode, uns);
14295 : 15165 : if (VECTOR_BOOLEAN_TYPE_P (intermediate_type)
14296 : 5911 : && VECTOR_BOOLEAN_TYPE_P (prev_type)
14297 : 5911 : && SCALAR_INT_MODE_P (prev_mode)
14298 : 2617 : && TYPE_VECTOR_SUBPARTS (intermediate_type).is_constant (&n_elts)
14299 : 17782 : && n_elts < BITS_PER_UNIT)
14300 : : interm_optab = vec_pack_sbool_trunc_optab;
14301 : : else
14302 : 15048 : interm_optab
14303 : 15048 : = optab_for_tree_code (VEC_PACK_TRUNC_EXPR, intermediate_type,
14304 : : optab_default);
14305 : 117 : if (!interm_optab
14306 : 15165 : || ((icode1 = optab_handler (optab1, prev_mode)) == CODE_FOR_nothing)
14307 : 15165 : || insn_data[icode1].operand[0].mode != intermediate_mode
14308 : 30213 : || ((icode1 = optab_handler (interm_optab, intermediate_mode))
14309 : : == CODE_FOR_nothing))
14310 : : break;
14311 : :
14312 : 14337 : interm_types->quick_push (intermediate_type);
14313 : 14337 : (*multi_step_cvt)++;
14314 : :
14315 : 14337 : if (insn_data[icode1].operand[0].mode == TYPE_MODE (narrow_vectype))
14316 : : {
14317 : 12330 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14318 : : return true;
14319 : 4010 : if (known_eq (TYPE_VECTOR_SUBPARTS (intermediate_type) * 2,
14320 : : TYPE_VECTOR_SUBPARTS (narrow_vectype)))
14321 : : return true;
14322 : : }
14323 : :
14324 : 2007 : prev_mode = intermediate_mode;
14325 : 2007 : prev_type = intermediate_type;
14326 : 2007 : optab1 = interm_optab;
14327 : : }
14328 : :
14329 : 828 : interm_types->release ();
14330 : 828 : return false;
14331 : : }
14332 : :
14333 : : /* Function supportable_indirect_convert_operation
14334 : :
14335 : : Check whether an operation represented by the code CODE is single or multi
14336 : : operations that are supported by the target platform in
14337 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
14338 : : producing a result of type VECTYPE_OUT).
14339 : :
14340 : : Convert operations we currently support directly are FIX_TRUNC and FLOAT.
14341 : : This function checks if these operations are supported
14342 : : by the target platform directly (via vector tree-codes).
14343 : :
14344 : : Output:
14345 : : - converts contains some pairs to perform the convert operation,
14346 : : the pair's first is the intermediate type, and its second is the code of
14347 : : a vector operation to be used when converting the operation from the
14348 : : previous type to the intermediate type. */
14349 : : bool
14350 : 72356 : supportable_indirect_convert_operation (code_helper code,
14351 : : tree vectype_out,
14352 : : tree vectype_in,
14353 : : vec<std::pair<tree, tree_code> > &converts,
14354 : : tree op0, slp_tree slp_op0)
14355 : : {
14356 : 72356 : bool found_mode = false;
14357 : 72356 : scalar_mode lhs_mode = GET_MODE_INNER (TYPE_MODE (vectype_out));
14358 : 72356 : scalar_mode rhs_mode = GET_MODE_INNER (TYPE_MODE (vectype_in));
14359 : 72356 : tree_code tc1, tc2, code1, code2;
14360 : :
14361 : 72356 : tree cvt_type = NULL_TREE;
14362 : 72356 : poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (vectype_in);
14363 : :
14364 : 72356 : if (supportable_convert_operation ((tree_code) code,
14365 : : vectype_out,
14366 : : vectype_in,
14367 : : &tc1))
14368 : : {
14369 : 16951 : converts.safe_push (std::make_pair (vectype_out, tc1));
14370 : 16951 : return true;
14371 : : }
14372 : :
14373 : : /* For conversions between float and integer types try whether
14374 : : we can use intermediate signed integer types to support the
14375 : : conversion. */
14376 : 110810 : if (GET_MODE_SIZE (lhs_mode) != GET_MODE_SIZE (rhs_mode)
14377 : 55405 : && (code == FLOAT_EXPR
14378 : 3109 : || (code == FIX_TRUNC_EXPR && !flag_trapping_math)))
14379 : : {
14380 : 376 : bool demotion = GET_MODE_SIZE (rhs_mode) > GET_MODE_SIZE (lhs_mode);
14381 : 188 : bool float_expr_p = code == FLOAT_EXPR;
14382 : 188 : unsigned short target_size;
14383 : 188 : scalar_mode intermediate_mode;
14384 : 188 : if (demotion)
14385 : : {
14386 : 84 : intermediate_mode = lhs_mode;
14387 : 84 : target_size = GET_MODE_SIZE (rhs_mode);
14388 : : }
14389 : : else
14390 : : {
14391 : 104 : target_size = GET_MODE_SIZE (lhs_mode);
14392 : 104 : if (!int_mode_for_size
14393 : 104 : (GET_MODE_BITSIZE (rhs_mode), 0).exists (&intermediate_mode))
14394 : 122 : return false;
14395 : : }
14396 : 188 : code1 = float_expr_p ? (tree_code) code : NOP_EXPR;
14397 : : code2 = float_expr_p ? NOP_EXPR : (tree_code) code;
14398 : 188 : opt_scalar_mode mode_iter;
14399 : 292 : FOR_EACH_2XWIDER_MODE (mode_iter, intermediate_mode)
14400 : : {
14401 : 292 : intermediate_mode = mode_iter.require ();
14402 : :
14403 : 584 : if (GET_MODE_SIZE (intermediate_mode) > target_size)
14404 : : break;
14405 : :
14406 : 264 : scalar_mode cvt_mode;
14407 : 264 : if (!int_mode_for_size
14408 : 264 : (GET_MODE_BITSIZE (intermediate_mode), 0).exists (&cvt_mode))
14409 : : break;
14410 : :
14411 : 234 : cvt_type = build_nonstandard_integer_type
14412 : 234 : (GET_MODE_BITSIZE (cvt_mode), 0);
14413 : :
14414 : : /* Check if the intermediate type can hold OP0's range.
14415 : : When converting from float to integer this is not necessary
14416 : : because values that do not fit the (smaller) target type are
14417 : : unspecified anyway. */
14418 : 234 : if (demotion && float_expr_p)
14419 : : {
14420 : 8 : wide_int op_min_value, op_max_value;
14421 : : /* For vector form, it looks like op0 doesn't have RANGE_INFO.
14422 : : In the future, if it is supported, changes may need to be made
14423 : : to this part, such as checking the RANGE of each element
14424 : : in the vector. */
14425 : 8 : if (slp_op0)
14426 : : {
14427 : 4 : tree def;
14428 : : /* ??? Merge ranges in case of more than one lane. */
14429 : 4 : if (SLP_TREE_LANES (slp_op0) != 1
14430 : 0 : || !(def = vect_get_slp_scalar_def (slp_op0, 0))
14431 : 4 : || !vect_get_range_info (def,
14432 : : &op_min_value, &op_max_value))
14433 : : break;
14434 : : }
14435 : 4 : else if (!op0
14436 : 0 : || TREE_CODE (op0) != SSA_NAME
14437 : 0 : || !SSA_NAME_RANGE_INFO (op0)
14438 : 4 : || !vect_get_range_info (op0, &op_min_value,
14439 : : &op_max_value))
14440 : : break;
14441 : :
14442 : 0 : if (cvt_type == NULL_TREE
14443 : 0 : || (wi::min_precision (op_max_value, SIGNED)
14444 : 0 : > TYPE_PRECISION (cvt_type))
14445 : 0 : || (wi::min_precision (op_min_value, SIGNED)
14446 : 0 : > TYPE_PRECISION (cvt_type)))
14447 : 0 : continue;
14448 : 8 : }
14449 : :
14450 : 226 : cvt_type = get_related_vectype_for_scalar_type (TYPE_MODE (vectype_in),
14451 : : cvt_type,
14452 : : nelts);
14453 : : /* This should only happened for SLP as long as loop vectorizer
14454 : : only supports same-sized vector. */
14455 : 330 : if (cvt_type == NULL_TREE
14456 : 348 : || maybe_ne (TYPE_VECTOR_SUBPARTS (cvt_type), nelts)
14457 : 226 : || !supportable_convert_operation ((tree_code) code1,
14458 : : vectype_out,
14459 : : cvt_type, &tc1)
14460 : 396 : || !supportable_convert_operation ((tree_code) code2,
14461 : : cvt_type,
14462 : : vectype_in, &tc2))
14463 : 104 : continue;
14464 : :
14465 : : found_mode = true;
14466 : : break;
14467 : : }
14468 : :
14469 : 188 : if (found_mode)
14470 : : {
14471 : 122 : converts.safe_push (std::make_pair (cvt_type, tc2));
14472 : 122 : if (TYPE_MODE (cvt_type) != TYPE_MODE (vectype_out))
14473 : 122 : converts.safe_push (std::make_pair (vectype_out, tc1));
14474 : 122 : return true;
14475 : : }
14476 : : }
14477 : : return false;
14478 : : }
14479 : :
14480 : : /* Generate and return a vector mask of MASK_TYPE such that
14481 : : mask[I] is true iff J + START_INDEX < END_INDEX for all J <= I.
14482 : : Add the statements to SEQ. */
14483 : :
14484 : : tree
14485 : 0 : vect_gen_while (gimple_seq *seq, tree mask_type, tree start_index,
14486 : : tree end_index, const char *name)
14487 : : {
14488 : 0 : tree cmp_type = TREE_TYPE (start_index);
14489 : 0 : gcc_checking_assert (direct_internal_fn_supported_p (IFN_WHILE_ULT,
14490 : : cmp_type, mask_type,
14491 : : OPTIMIZE_FOR_SPEED));
14492 : 0 : gcall *call = gimple_build_call_internal (IFN_WHILE_ULT, 3,
14493 : : start_index, end_index,
14494 : : build_zero_cst (mask_type));
14495 : 0 : tree tmp;
14496 : 0 : if (name)
14497 : 0 : tmp = make_temp_ssa_name (mask_type, NULL, name);
14498 : : else
14499 : 0 : tmp = make_ssa_name (mask_type);
14500 : 0 : gimple_call_set_lhs (call, tmp);
14501 : 0 : gimple_seq_add_stmt (seq, call);
14502 : 0 : return tmp;
14503 : : }
14504 : :
14505 : : /* Generate a vector mask of type MASK_TYPE for which index I is false iff
14506 : : J + START_INDEX < END_INDEX for all J <= I. Add the statements to SEQ. */
14507 : :
14508 : : tree
14509 : 0 : vect_gen_while_not (gimple_seq *seq, tree mask_type, tree start_index,
14510 : : tree end_index)
14511 : : {
14512 : 0 : tree tmp = vect_gen_while (seq, mask_type, start_index, end_index);
14513 : 0 : return gimple_build (seq, BIT_NOT_EXPR, mask_type, tmp);
14514 : : }
14515 : :
14516 : : /* Try to compute the vector types required to vectorize STMT_INFO,
14517 : : returning true on success and false if vectorization isn't possible.
14518 : : If GROUP_SIZE is nonzero and we're performing BB vectorization,
14519 : : take sure that the number of elements in the vectors is no bigger
14520 : : than GROUP_SIZE.
14521 : :
14522 : : On success:
14523 : :
14524 : : - Set *STMT_VECTYPE_OUT to:
14525 : : - NULL_TREE if the statement doesn't need to be vectorized;
14526 : : - the equivalent of STMT_VINFO_VECTYPE otherwise.
14527 : :
14528 : : - Set *NUNITS_VECTYPE_OUT to the vector type that contains the maximum
14529 : : number of units needed to vectorize STMT_INFO, or NULL_TREE if the
14530 : : statement does not help to determine the overall number of units. */
14531 : :
14532 : : opt_result
14533 : 5236062 : vect_get_vector_types_for_stmt (vec_info *vinfo, stmt_vec_info stmt_info,
14534 : : tree *stmt_vectype_out,
14535 : : tree *nunits_vectype_out,
14536 : : unsigned int group_size)
14537 : : {
14538 : 5236062 : gimple *stmt = stmt_info->stmt;
14539 : :
14540 : : /* For BB vectorization, we should always have a group size once we've
14541 : : constructed the SLP tree; the only valid uses of zero GROUP_SIZEs
14542 : : are tentative requests during things like early data reference
14543 : : analysis and pattern recognition. */
14544 : 5236062 : if (is_a <bb_vec_info> (vinfo))
14545 : 4443030 : gcc_assert (vinfo->slp_instances.is_empty () || group_size != 0);
14546 : : else
14547 : : group_size = 0;
14548 : :
14549 : 5236062 : *stmt_vectype_out = NULL_TREE;
14550 : 5236062 : *nunits_vectype_out = NULL_TREE;
14551 : :
14552 : 5236062 : if (gimple_get_lhs (stmt) == NULL_TREE
14553 : : /* Allow vector conditionals through here. */
14554 : 1461 : && !is_a <gcond *> (stmt)
14555 : : /* MASK_STORE and friends have no lhs, but are ok. */
14556 : 5238964 : && !(is_gimple_call (stmt)
14557 : 1461 : && gimple_call_internal_p (stmt)
14558 : 1441 : && internal_store_fn_p (gimple_call_internal_fn (stmt))))
14559 : : {
14560 : 20 : if (is_a <gcall *> (stmt))
14561 : : {
14562 : : /* Ignore calls with no lhs. These must be calls to
14563 : : #pragma omp simd functions, and what vectorization factor
14564 : : it really needs can't be determined until
14565 : : vectorizable_simd_clone_call. */
14566 : 20 : if (dump_enabled_p ())
14567 : 18 : dump_printf_loc (MSG_NOTE, vect_location,
14568 : : "defer to SIMD clone analysis.\n");
14569 : 20 : return opt_result::success ();
14570 : : }
14571 : :
14572 : 0 : return opt_result::failure_at (stmt,
14573 : : "not vectorized: irregular stmt: %G", stmt);
14574 : : }
14575 : :
14576 : 5236042 : tree vectype;
14577 : 5236042 : tree scalar_type = NULL_TREE;
14578 : 5236042 : if (group_size == 0 && STMT_VINFO_VECTYPE (stmt_info))
14579 : : {
14580 : 1331637 : vectype = STMT_VINFO_VECTYPE (stmt_info);
14581 : 1331637 : if (dump_enabled_p ())
14582 : 75020 : dump_printf_loc (MSG_NOTE, vect_location,
14583 : : "precomputed vectype: %T\n", vectype);
14584 : : }
14585 : 3904405 : else if (vect_use_mask_type_p (stmt_info))
14586 : : {
14587 : 193534 : unsigned int precision = stmt_info->mask_precision;
14588 : 193534 : scalar_type = build_nonstandard_integer_type (precision, 1);
14589 : 193534 : vectype = get_mask_type_for_scalar_type (vinfo, scalar_type, group_size);
14590 : 193534 : if (!vectype)
14591 : 0 : return opt_result::failure_at (stmt, "not vectorized: unsupported"
14592 : : " data-type %T\n", scalar_type);
14593 : 193534 : if (dump_enabled_p ())
14594 : 4352 : dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype);
14595 : : }
14596 : : else
14597 : : {
14598 : : /* If we got here with a gcond it means that the target had no available vector
14599 : : mode for the scalar type. We can't vectorize so abort. */
14600 : 3710871 : if (is_a <gcond *> (stmt))
14601 : 0 : return opt_result::failure_at (stmt,
14602 : : "not vectorized:"
14603 : : " unsupported data-type for gcond %T\n",
14604 : : scalar_type);
14605 : :
14606 : 3710871 : if (data_reference *dr = STMT_VINFO_DATA_REF (stmt_info))
14607 : 1461247 : scalar_type = TREE_TYPE (DR_REF (dr));
14608 : : else
14609 : 2249624 : scalar_type = TREE_TYPE (gimple_get_lhs (stmt));
14610 : :
14611 : 3710871 : if (dump_enabled_p ())
14612 : : {
14613 : 58747 : if (group_size)
14614 : 7218 : dump_printf_loc (MSG_NOTE, vect_location,
14615 : : "get vectype for scalar type (group size %d):"
14616 : : " %T\n", group_size, scalar_type);
14617 : : else
14618 : 51529 : dump_printf_loc (MSG_NOTE, vect_location,
14619 : : "get vectype for scalar type: %T\n", scalar_type);
14620 : : }
14621 : 3710871 : vectype = get_vectype_for_scalar_type (vinfo, scalar_type, group_size);
14622 : 3710871 : if (!vectype)
14623 : 197738 : return opt_result::failure_at (stmt,
14624 : : "not vectorized:"
14625 : : " unsupported data-type %T\n",
14626 : : scalar_type);
14627 : :
14628 : 3513133 : if (dump_enabled_p ())
14629 : 58585 : dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype);
14630 : : }
14631 : :
14632 : 3781687 : if (scalar_type && VECTOR_MODE_P (TYPE_MODE (scalar_type)))
14633 : 0 : return opt_result::failure_at (stmt,
14634 : : "not vectorized: vector stmt in loop:%G",
14635 : : stmt);
14636 : :
14637 : 5038304 : *stmt_vectype_out = vectype;
14638 : :
14639 : : /* Don't try to compute scalar types if the stmt produces a boolean
14640 : : vector; use the existing vector type instead. */
14641 : 5038304 : tree nunits_vectype = vectype;
14642 : 5038304 : if (!VECTOR_BOOLEAN_TYPE_P (vectype))
14643 : : {
14644 : : /* The number of units is set according to the smallest scalar
14645 : : type (or the largest vector size, but we only support one
14646 : : vector size per vectorization). */
14647 : 4560706 : scalar_type = vect_get_smallest_scalar_type (stmt_info,
14648 : 4560706 : TREE_TYPE (vectype));
14649 : 4560706 : if (!types_compatible_p (scalar_type, TREE_TYPE (vectype)))
14650 : : {
14651 : 992387 : if (dump_enabled_p ())
14652 : 9436 : dump_printf_loc (MSG_NOTE, vect_location,
14653 : : "get vectype for smallest scalar type: %T\n",
14654 : : scalar_type);
14655 : 992387 : nunits_vectype = get_vectype_for_scalar_type (vinfo, scalar_type,
14656 : : group_size);
14657 : 992387 : if (!nunits_vectype)
14658 : 7 : return opt_result::failure_at
14659 : 7 : (stmt, "not vectorized: unsupported data-type %T\n",
14660 : : scalar_type);
14661 : 992380 : if (dump_enabled_p ())
14662 : 9436 : dump_printf_loc (MSG_NOTE, vect_location, "nunits vectype: %T\n",
14663 : : nunits_vectype);
14664 : : }
14665 : : }
14666 : :
14667 : 5038297 : if (!multiple_p (TYPE_VECTOR_SUBPARTS (nunits_vectype),
14668 : 5038297 : TYPE_VECTOR_SUBPARTS (*stmt_vectype_out)))
14669 : 0 : return opt_result::failure_at (stmt,
14670 : : "Not vectorized: Incompatible number "
14671 : : "of vector subparts between %T and %T\n",
14672 : : nunits_vectype, *stmt_vectype_out);
14673 : :
14674 : 5038297 : if (dump_enabled_p ())
14675 : : {
14676 : 137957 : dump_printf_loc (MSG_NOTE, vect_location, "nunits = ");
14677 : 137957 : dump_dec (MSG_NOTE, TYPE_VECTOR_SUBPARTS (nunits_vectype));
14678 : 137957 : dump_printf (MSG_NOTE, "\n");
14679 : : }
14680 : :
14681 : 5038297 : *nunits_vectype_out = nunits_vectype;
14682 : 5038297 : return opt_result::success ();
14683 : : }
14684 : :
14685 : : /* Generate and return statement sequence that sets vector length LEN that is:
14686 : :
14687 : : min_of_start_and_end = min (START_INDEX, END_INDEX);
14688 : : left_len = END_INDEX - min_of_start_and_end;
14689 : : rhs = min (left_len, LEN_LIMIT);
14690 : : LEN = rhs;
14691 : :
14692 : : Note: the cost of the code generated by this function is modeled
14693 : : by vect_estimate_min_profitable_iters, so changes here may need
14694 : : corresponding changes there. */
14695 : :
14696 : : gimple_seq
14697 : 0 : vect_gen_len (tree len, tree start_index, tree end_index, tree len_limit)
14698 : : {
14699 : 0 : gimple_seq stmts = NULL;
14700 : 0 : tree len_type = TREE_TYPE (len);
14701 : 0 : gcc_assert (TREE_TYPE (start_index) == len_type);
14702 : :
14703 : 0 : tree min = gimple_build (&stmts, MIN_EXPR, len_type, start_index, end_index);
14704 : 0 : tree left_len = gimple_build (&stmts, MINUS_EXPR, len_type, end_index, min);
14705 : 0 : tree rhs = gimple_build (&stmts, MIN_EXPR, len_type, left_len, len_limit);
14706 : 0 : gimple* stmt = gimple_build_assign (len, rhs);
14707 : 0 : gimple_seq_add_stmt (&stmts, stmt);
14708 : :
14709 : 0 : return stmts;
14710 : : }
14711 : :
|