Bug Summary

File:build/gcc/tree-vect-data-refs.cc
Warning:line 128, column 9
Although the value stored to 'rhs' is used in the enclosing expression, the value is never actually read from 'rhs'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-suse-linux -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tree-vect-data-refs.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model static -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/gcc -resource-dir /usr/lib64/clang/15.0.7 -D IN_GCC -D HAVE_CONFIG_H -I . -I . -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/. -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../include -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcpp/include -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libcody -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libdecnumber/bid -I ../libdecnumber -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/../libbacktrace -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../include/c++/13/x86_64-suse-linux -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../include/c++/13/backward -internal-isystem /usr/lib64/clang/15.0.7/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../x86_64-suse-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-narrowing -Wwrite-strings -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -fdeprecated-macro -fdebug-compilation-dir=/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/gcc -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=plist-html -analyzer-config silence-checkers=core.NullDereference -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /buildworker/marxinbox-gcc-clang-static-analyzer/objdir/clang-static-analyzer/2023-03-27-141847-20772-1/report-jELz2t.plist -x c++ /buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc
1/* Data References Analysis and Manipulation Utilities for Vectorization.
2 Copyright (C) 2003-2023 Free Software Foundation, Inc.
3 Contributed by Dorit Naishlos <dorit@il.ibm.com>
4 and Ira Rosen <irar@il.ibm.com>
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 3, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along 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 "predict.h"
31#include "memmodel.h"
32#include "tm_p.h"
33#include "ssa.h"
34#include "optabs-tree.h"
35#include "cgraph.h"
36#include "dumpfile.h"
37#include "alias.h"
38#include "fold-const.h"
39#include "stor-layout.h"
40#include "tree-eh.h"
41#include "gimplify.h"
42#include "gimple-iterator.h"
43#include "gimplify-me.h"
44#include "tree-ssa-loop-ivopts.h"
45#include "tree-ssa-loop-manip.h"
46#include "tree-ssa-loop.h"
47#include "cfgloop.h"
48#include "tree-scalar-evolution.h"
49#include "tree-vectorizer.h"
50#include "expr.h"
51#include "builtins.h"
52#include "tree-cfg.h"
53#include "tree-hash-traits.h"
54#include "vec-perm-indices.h"
55#include "internal-fn.h"
56#include "gimple-fold.h"
57
58/* Return true if load- or store-lanes optab OPTAB is implemented for
59 COUNT vectors of type VECTYPE. NAME is the name of OPTAB. */
60
61static bool
62vect_lanes_optab_supported_p (const char *name, convert_optab optab,
63 tree vectype, unsigned HOST_WIDE_INTlong count)
64{
65 machine_mode mode, array_mode;
66 bool limit_p;
67
68 mode = TYPE_MODE (vectype)((((enum tree_code) ((tree_class_check ((vectype), (tcc_type)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 68, __FUNCTION__)))->base.code) == VECTOR_TYPE) ? vector_type_mode
(vectype) : (vectype)->type_common.mode)
;
69 if (!targetm.array_mode (mode, count).exists (&array_mode))
70 {
71 poly_uint64 bits = count * GET_MODE_BITSIZE (mode);
72 limit_p = !targetm.array_mode_supported_p (mode, count);
73 if (!int_mode_for_size (bits, limit_p).exists (&array_mode))
74 {
75 if (dump_enabled_p ())
76 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
77 "no array mode for %s[%wu]\n",
78 GET_MODE_NAME (mode)mode_name[mode], count);
79 return false;
80 }
81 }
82
83 if (convert_optab_handler (optab, array_mode, mode) == CODE_FOR_nothing)
84 {
85 if (dump_enabled_p ())
86 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
87 "cannot use %s<%s><%s>\n", name,
88 GET_MODE_NAME (array_mode)mode_name[array_mode], GET_MODE_NAME (mode)mode_name[mode]);
89 return false;
90 }
91
92 if (dump_enabled_p ())
93 dump_printf_loc (MSG_NOTE, vect_location,
94 "can use %s<%s><%s>\n", name, GET_MODE_NAME (array_mode)mode_name[array_mode],
95 GET_MODE_NAME (mode)mode_name[mode]);
96
97 return true;
98}
99
100
101/* Return the smallest scalar part of STMT_INFO.
102 This is used to determine the vectype of the stmt. We generally set the
103 vectype according to the type of the result (lhs). For stmts whose
104 result-type is different than the type of the arguments (e.g., demotion,
105 promotion), vectype will be reset appropriately (later). Note that we have
106 to visit the smallest datatype in this function, because that determines the
107 VF. If the smallest datatype in the loop is present only as the rhs of a
108 promotion operation - we'd miss it.
109 Such a case, where a variable of this datatype does not appear in the lhs
110 anywhere in the loop, can only occur if it's an invariant: e.g.:
111 'int_x = (int) short_inv', which we'd expect to have been optimized away by
112 invariant motion. However, we cannot rely on invariant motion to always
113 take invariants out of the loop, and so in the case of promotion we also
114 have to check the rhs.
115 LHS_SIZE_UNIT and RHS_SIZE_UNIT contain the sizes of the corresponding
116 types. */
117
118tree
119vect_get_smallest_scalar_type (stmt_vec_info stmt_info, tree scalar_type)
120{
121 HOST_WIDE_INTlong lhs, rhs;
122
123 /* During the analysis phase, this function is called on arbitrary
124 statements that might not have scalar results. */
125 if (!tree_fits_uhwi_p (TYPE_SIZE_UNIT (scalar_type)((tree_class_check ((scalar_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 125, __FUNCTION__))->type_common.size_unit)
))
126 return scalar_type;
127
128 lhs = rhs = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (scalar_type))((unsigned long) (*tree_int_cst_elt_check ((((tree_class_check
((scalar_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 128, __FUNCTION__))->type_common.size_unit)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 128, __FUNCTION__)))
;
Although the value stored to 'rhs' is used in the enclosing expression, the value is never actually read from 'rhs'
129
130 gassign *assign = dyn_cast <gassign *> (stmt_info->stmt);
131 if (assign)
132 {
133 scalar_type = TREE_TYPE (gimple_assign_lhs (assign))((contains_struct_check ((gimple_assign_lhs (assign)), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 133, __FUNCTION__))->typed.type)
;
134 if (gimple_assign_cast_p (assign)
135 || gimple_assign_rhs_code (assign) == DOT_PROD_EXPR
136 || gimple_assign_rhs_code (assign) == WIDEN_SUM_EXPR
137 || gimple_assign_rhs_code (assign) == WIDEN_MULT_EXPR
138 || gimple_assign_rhs_code (assign) == WIDEN_LSHIFT_EXPR
139 || gimple_assign_rhs_code (assign) == WIDEN_PLUS_EXPR
140 || gimple_assign_rhs_code (assign) == WIDEN_MINUS_EXPR
141 || gimple_assign_rhs_code (assign) == FLOAT_EXPR)
142 {
143 tree rhs_type = TREE_TYPE (gimple_assign_rhs1 (assign))((contains_struct_check ((gimple_assign_rhs1 (assign)), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 143, __FUNCTION__))->typed.type)
;
144
145 rhs = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (rhs_type))((unsigned long) (*tree_int_cst_elt_check ((((tree_class_check
((rhs_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 145, __FUNCTION__))->type_common.size_unit)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 145, __FUNCTION__)))
;
146 if (rhs < lhs)
147 scalar_type = rhs_type;
148 }
149 }
150 else if (gcall *call = dyn_cast <gcall *> (stmt_info->stmt))
151 {
152 unsigned int i = 0;
153 if (gimple_call_internal_p (call))
154 {
155 internal_fn ifn = gimple_call_internal_fn (call);
156 if (internal_load_fn_p (ifn))
157 /* For loads the LHS type does the trick. */
158 i = ~0U;
159 else if (internal_store_fn_p (ifn))
160 {
161 /* For stores use the tyep of the stored value. */
162 i = internal_fn_stored_value_index (ifn);
163 scalar_type = TREE_TYPE (gimple_call_arg (call, i))((contains_struct_check ((gimple_call_arg (call, i)), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 163, __FUNCTION__))->typed.type)
;
164 i = ~0U;
165 }
166 else if (internal_fn_mask_index (ifn) == 0)
167 i = 1;
168 }
169 if (i < gimple_call_num_args (call))
170 {
171 tree rhs_type = TREE_TYPE (gimple_call_arg (call, i))((contains_struct_check ((gimple_call_arg (call, i)), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 171, __FUNCTION__))->typed.type)
;
172 if (tree_fits_uhwi_p (TYPE_SIZE_UNIT (rhs_type)((tree_class_check ((rhs_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 172, __FUNCTION__))->type_common.size_unit)
))
173 {
174 rhs = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (rhs_type))((unsigned long) (*tree_int_cst_elt_check ((((tree_class_check
((rhs_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 174, __FUNCTION__))->type_common.size_unit)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 174, __FUNCTION__)))
;
175 if (rhs < lhs)
176 scalar_type = rhs_type;
177 }
178 }
179 }
180
181 return scalar_type;
182}
183
184
185/* Insert DDR into LOOP_VINFO list of ddrs that may alias and need to be
186 tested at run-time. Return TRUE if DDR was successfully inserted.
187 Return false if versioning is not supported. */
188
189static opt_result
190vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
191{
192 class loop *loop = LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop;
193
194 if ((unsigned) param_vect_max_version_for_alias_checksglobal_options.x_param_vect_max_version_for_alias_checks == 0)
195 return opt_result::failure_at (vect_location,
196 "will not create alias checks, as"
197 " --param vect-max-version-for-alias-checks"
198 " == 0\n");
199
200 opt_result res
201 = runtime_alias_check_p (ddr, loop,
202 optimize_loop_nest_for_speed_p (loop));
203 if (!res)
204 return res;
205
206 LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo)(loop_vinfo)->may_alias_ddrs.safe_push (ddr);
207 return opt_result::success ();
208}
209
210/* Record that loop LOOP_VINFO needs to check that VALUE is nonzero. */
211
212static void
213vect_check_nonzero_value (loop_vec_info loop_vinfo, tree value)
214{
215 const vec<tree> &checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo)(loop_vinfo)->check_nonzero;
216 for (unsigned int i = 0; i < checks.length(); ++i)
217 if (checks[i] == value)
218 return;
219
220 if (dump_enabled_p ())
221 dump_printf_loc (MSG_NOTE, vect_location,
222 "need run-time check that %T is nonzero\n",
223 value);
224 LOOP_VINFO_CHECK_NONZERO (loop_vinfo)(loop_vinfo)->check_nonzero.safe_push (value);
225}
226
227/* Return true if we know that the order of vectorized DR_INFO_A and
228 vectorized DR_INFO_B will be the same as the order of DR_INFO_A and
229 DR_INFO_B. At least one of the accesses is a write. */
230
231static bool
232vect_preserves_scalar_order_p (dr_vec_info *dr_info_a, dr_vec_info *dr_info_b)
233{
234 stmt_vec_info stmtinfo_a = dr_info_a->stmt;
235 stmt_vec_info stmtinfo_b = dr_info_b->stmt;
236
237 /* Single statements are always kept in their original order. */
238 if (!STMT_VINFO_GROUPED_ACCESS (stmtinfo_a)((stmtinfo_a)->dr_aux.dr && (((void)(!((stmtinfo_a
)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 238, __FUNCTION__), 0 : 0)), (stmtinfo_a)->first_element
))
239 && !STMT_VINFO_GROUPED_ACCESS (stmtinfo_b)((stmtinfo_b)->dr_aux.dr && (((void)(!((stmtinfo_b
)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 239, __FUNCTION__), 0 : 0)), (stmtinfo_b)->first_element
))
)
240 return true;
241
242 /* STMT_A and STMT_B belong to overlapping groups. All loads are
243 emitted at the position of the first scalar load.
244 Stores in a group are emitted at the position of the last scalar store.
245 Compute that position and check whether the resulting order matches
246 the current one. */
247 stmt_vec_info il_a = DR_GROUP_FIRST_ELEMENT (stmtinfo_a)(((void)(!((stmtinfo_a)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 247, __FUNCTION__), 0 : 0)), (stmtinfo_a)->first_element
)
;
248 if (il_a)
249 {
250 if (DR_IS_WRITE (STMT_VINFO_DATA_REF (stmtinfo_a))(!(((stmtinfo_a)->dr_aux.dr + 0))->is_read))
251 for (stmt_vec_info s = DR_GROUP_NEXT_ELEMENT (il_a)(((void)(!((il_a)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 251, __FUNCTION__), 0 : 0)), (il_a)->next_element)
; s;
252 s = DR_GROUP_NEXT_ELEMENT (s)(((void)(!((s)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 252, __FUNCTION__), 0 : 0)), (s)->next_element)
)
253 il_a = get_later_stmt (il_a, s);
254 else /* DR_IS_READ */
255 for (stmt_vec_info s = DR_GROUP_NEXT_ELEMENT (il_a)(((void)(!((il_a)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 255, __FUNCTION__), 0 : 0)), (il_a)->next_element)
; s;
256 s = DR_GROUP_NEXT_ELEMENT (s)(((void)(!((s)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 256, __FUNCTION__), 0 : 0)), (s)->next_element)
)
257 if (get_later_stmt (il_a, s) == il_a)
258 il_a = s;
259 }
260 else
261 il_a = stmtinfo_a;
262 stmt_vec_info il_b = DR_GROUP_FIRST_ELEMENT (stmtinfo_b)(((void)(!((stmtinfo_b)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 262, __FUNCTION__), 0 : 0)), (stmtinfo_b)->first_element
)
;
263 if (il_b)
264 {
265 if (DR_IS_WRITE (STMT_VINFO_DATA_REF (stmtinfo_b))(!(((stmtinfo_b)->dr_aux.dr + 0))->is_read))
266 for (stmt_vec_info s = DR_GROUP_NEXT_ELEMENT (il_b)(((void)(!((il_b)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 266, __FUNCTION__), 0 : 0)), (il_b)->next_element)
; s;
267 s = DR_GROUP_NEXT_ELEMENT (s)(((void)(!((s)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 267, __FUNCTION__), 0 : 0)), (s)->next_element)
)
268 il_b = get_later_stmt (il_b, s);
269 else /* DR_IS_READ */
270 for (stmt_vec_info s = DR_GROUP_NEXT_ELEMENT (il_b)(((void)(!((il_b)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 270, __FUNCTION__), 0 : 0)), (il_b)->next_element)
; s;
271 s = DR_GROUP_NEXT_ELEMENT (s)(((void)(!((s)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 271, __FUNCTION__), 0 : 0)), (s)->next_element)
)
272 if (get_later_stmt (il_b, s) == il_b)
273 il_b = s;
274 }
275 else
276 il_b = stmtinfo_b;
277 bool a_after_b = (get_later_stmt (stmtinfo_a, stmtinfo_b) == stmtinfo_a);
278 return (get_later_stmt (il_a, il_b) == il_a) == a_after_b;
279}
280
281/* A subroutine of vect_analyze_data_ref_dependence. Handle
282 DDR_COULD_BE_INDEPENDENT_P ddr DDR that has a known set of dependence
283 distances. These distances are conservatively correct but they don't
284 reflect a guaranteed dependence.
285
286 Return true if this function does all the work necessary to avoid
287 an alias or false if the caller should use the dependence distances
288 to limit the vectorization factor in the usual way. LOOP_DEPTH is
289 the depth of the loop described by LOOP_VINFO and the other arguments
290 are as for vect_analyze_data_ref_dependence. */
291
292static bool
293vect_analyze_possibly_independent_ddr (data_dependence_relation *ddr,
294 loop_vec_info loop_vinfo,
295 int loop_depth, unsigned int *max_vf)
296{
297 class loop *loop = LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop;
298 for (lambda_vector &dist_v : DDR_DIST_VECTS (ddr)((ddr)->dist_vects))
299 {
300 int dist = dist_v[loop_depth];
301 if (dist != 0 && !(dist > 0 && DDR_REVERSED_P (ddr)(ddr)->reversed_p))
302 {
303 /* If the user asserted safelen >= DIST consecutive iterations
304 can be executed concurrently, assume independence.
305
306 ??? An alternative would be to add the alias check even
307 in this case, and vectorize the fallback loop with the
308 maximum VF set to safelen. However, if the user has
309 explicitly given a length, it's less likely that that
310 would be a win. */
311 if (loop->safelen >= 2 && abs_hwi (dist) <= loop->safelen)
312 {
313 if ((unsigned int) loop->safelen < *max_vf)
314 *max_vf = loop->safelen;
315 LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo)(loop_vinfo)->no_data_dependencies = false;
316 continue;
317 }
318
319 /* For dependence distances of 2 or more, we have the option
320 of limiting VF or checking for an alias at runtime.
321 Prefer to check at runtime if we can, to avoid limiting
322 the VF unnecessarily when the bases are in fact independent.
323
324 Note that the alias checks will be removed if the VF ends up
325 being small enough. */
326 dr_vec_info *dr_info_a = loop_vinfo->lookup_dr (DDR_A (ddr)(ddr)->a);
327 dr_vec_info *dr_info_b = loop_vinfo->lookup_dr (DDR_B (ddr)(ddr)->b);
328 return (!STMT_VINFO_GATHER_SCATTER_P (dr_info_a->stmt)(dr_info_a->stmt)->gather_scatter_p
329 && !STMT_VINFO_GATHER_SCATTER_P (dr_info_b->stmt)(dr_info_b->stmt)->gather_scatter_p
330 && vect_mark_for_runtime_alias_test (ddr, loop_vinfo));
331 }
332 }
333 return true;
334}
335
336
337/* Function vect_analyze_data_ref_dependence.
338
339 FIXME: I needed to change the sense of the returned flag.
340
341 Return FALSE if there (might) exist a dependence between a memory-reference
342 DRA and a memory-reference DRB. When versioning for alias may check a
343 dependence at run-time, return TRUE. Adjust *MAX_VF according to
344 the data dependence. */
345
346static opt_result
347vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
348 loop_vec_info loop_vinfo,
349 unsigned int *max_vf)
350{
351 unsigned int i;
352 class loop *loop = LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop;
353 struct data_reference *dra = DDR_A (ddr)(ddr)->a;
354 struct data_reference *drb = DDR_B (ddr)(ddr)->b;
355 dr_vec_info *dr_info_a = loop_vinfo->lookup_dr (dra);
356 dr_vec_info *dr_info_b = loop_vinfo->lookup_dr (drb);
357 stmt_vec_info stmtinfo_a = dr_info_a->stmt;
358 stmt_vec_info stmtinfo_b = dr_info_b->stmt;
359 lambda_vector dist_v;
360 unsigned int loop_depth;
361
362 /* If user asserted safelen consecutive iterations can be
363 executed concurrently, assume independence. */
364 auto apply_safelen = [&]()
365 {
366 if (loop->safelen >= 2)
367 {
368 if ((unsigned int) loop->safelen < *max_vf)
369 *max_vf = loop->safelen;
370 LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo)(loop_vinfo)->no_data_dependencies = false;
371 return true;
372 }
373 return false;
374 };
375
376 /* In loop analysis all data references should be vectorizable. */
377 if (!STMT_VINFO_VECTORIZABLE (stmtinfo_a)(stmtinfo_a)->vectorizable
378 || !STMT_VINFO_VECTORIZABLE (stmtinfo_b)(stmtinfo_b)->vectorizable)
379 gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 379, __FUNCTION__))
;
380
381 /* Independent data accesses. */
382 if (DDR_ARE_DEPENDENT (ddr)(ddr)->are_dependent == chrec_knownglobal_trees[TI_CHREC_KNOWN])
383 return opt_result::success ();
384
385 if (dra == drb
386 || (DR_IS_READ (dra)(dra)->is_read && DR_IS_READ (drb)(drb)->is_read))
387 return opt_result::success ();
388
389 /* We do not have to consider dependences between accesses that belong
390 to the same group, unless the stride could be smaller than the
391 group size. */
392 if (DR_GROUP_FIRST_ELEMENT (stmtinfo_a)(((void)(!((stmtinfo_a)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 392, __FUNCTION__), 0 : 0)), (stmtinfo_a)->first_element
)
393 && (DR_GROUP_FIRST_ELEMENT (stmtinfo_a)(((void)(!((stmtinfo_a)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 393, __FUNCTION__), 0 : 0)), (stmtinfo_a)->first_element
)
394 == DR_GROUP_FIRST_ELEMENT (stmtinfo_b)(((void)(!((stmtinfo_b)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 394, __FUNCTION__), 0 : 0)), (stmtinfo_b)->first_element
)
)
395 && !STMT_VINFO_STRIDED_P (stmtinfo_a)(stmtinfo_a)->strided_p)
396 return opt_result::success ();
397
398 /* Even if we have an anti-dependence then, as the vectorized loop covers at
399 least two scalar iterations, there is always also a true dependence.
400 As the vectorizer does not re-order loads and stores we can ignore
401 the anti-dependence if TBAA can disambiguate both DRs similar to the
402 case with known negative distance anti-dependences (positive
403 distance anti-dependences would violate TBAA constraints). */
404 if (((DR_IS_READ (dra)(dra)->is_read && DR_IS_WRITE (drb)(!(drb)->is_read))
405 || (DR_IS_WRITE (dra)(!(dra)->is_read) && DR_IS_READ (drb)(drb)->is_read))
406 && !alias_sets_conflict_p (get_alias_set (DR_REF (dra)(dra)->ref),
407 get_alias_set (DR_REF (drb)(drb)->ref)))
408 return opt_result::success ();
409
410 if (STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)(stmtinfo_a)->gather_scatter_p
411 || STMT_VINFO_GATHER_SCATTER_P (stmtinfo_b)(stmtinfo_b)->gather_scatter_p)
412 {
413 if (apply_safelen ())
414 return opt_result::success ();
415
416 return opt_result::failure_at
417 (stmtinfo_a->stmt,
418 "possible alias involving gather/scatter between %T and %T\n",
419 DR_REF (dra)(dra)->ref, DR_REF (drb)(drb)->ref);
420 }
421
422 /* Unknown data dependence. */
423 if (DDR_ARE_DEPENDENT (ddr)(ddr)->are_dependent == chrec_dont_knowglobal_trees[TI_CHREC_DONT_KNOW])
424 {
425 if (apply_safelen ())
426 return opt_result::success ();
427
428 if (dump_enabled_p ())
429 dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmtinfo_a->stmt,
430 "versioning for alias required: "
431 "can't determine dependence between %T and %T\n",
432 DR_REF (dra)(dra)->ref, DR_REF (drb)(drb)->ref);
433
434 /* Add to list of ddrs that need to be tested at run-time. */
435 return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
436 }
437
438 /* Known data dependence. */
439 if (DDR_NUM_DIST_VECTS (ddr)(((ddr)->dist_vects).length ()) == 0)
440 {
441 if (apply_safelen ())
442 return opt_result::success ();
443
444 if (dump_enabled_p ())
445 dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmtinfo_a->stmt,
446 "versioning for alias required: "
447 "bad dist vector for %T and %T\n",
448 DR_REF (dra)(dra)->ref, DR_REF (drb)(drb)->ref);
449 /* Add to list of ddrs that need to be tested at run-time. */
450 return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
451 }
452
453 loop_depth = index_in_loop_nest (loop->num, DDR_LOOP_NEST (ddr)(ddr)->loop_nest);
454
455 if (DDR_COULD_BE_INDEPENDENT_P (ddr)(ddr)->could_be_independent_p
456 && vect_analyze_possibly_independent_ddr (ddr, loop_vinfo,
457 loop_depth, max_vf))
458 return opt_result::success ();
459
460 FOR_EACH_VEC_ELT (DDR_DIST_VECTS (ddr), i, dist_v)for (i = 0; (((ddr)->dist_vects)).iterate ((i), &(dist_v
)); ++(i))
461 {
462 int dist = dist_v[loop_depth];
463
464 if (dump_enabled_p ())
465 dump_printf_loc (MSG_NOTE, vect_location,
466 "dependence distance = %d.\n", dist);
467
468 if (dist == 0)
469 {
470 if (dump_enabled_p ())
471 dump_printf_loc (MSG_NOTE, vect_location,
472 "dependence distance == 0 between %T and %T\n",
473 DR_REF (dra)(dra)->ref, DR_REF (drb)(drb)->ref);
474
475 /* When we perform grouped accesses and perform implicit CSE
476 by detecting equal accesses and doing disambiguation with
477 runtime alias tests like for
478 .. = a[i];
479 .. = a[i+1];
480 a[i] = ..;
481 a[i+1] = ..;
482 *p = ..;
483 .. = a[i];
484 .. = a[i+1];
485 where we will end up loading { a[i], a[i+1] } once, make
486 sure that inserting group loads before the first load and
487 stores after the last store will do the right thing.
488 Similar for groups like
489 a[i] = ...;
490 ... = a[i];
491 a[i+1] = ...;
492 where loads from the group interleave with the store. */
493 if (!vect_preserves_scalar_order_p (dr_info_a, dr_info_b))
494 return opt_result::failure_at (stmtinfo_a->stmt,
495 "READ_WRITE dependence"
496 " in interleaving.\n");
497
498 if (loop->safelen < 2)
499 {
500 tree indicator = dr_zero_step_indicator (dra);
501 if (!indicator || integer_zerop (indicator))
502 return opt_result::failure_at (stmtinfo_a->stmt,
503 "access also has a zero step\n");
504 else if (TREE_CODE (indicator)((enum tree_code) (indicator)->base.code) != INTEGER_CST)
505 vect_check_nonzero_value (loop_vinfo, indicator);
506 }
507 continue;
508 }
509
510 if (dist > 0 && DDR_REVERSED_P (ddr)(ddr)->reversed_p)
511 {
512 /* If DDR_REVERSED_P the order of the data-refs in DDR was
513 reversed (to make distance vector positive), and the actual
514 distance is negative. */
515 if (dump_enabled_p ())
516 dump_printf_loc (MSG_NOTE, vect_location,
517 "dependence distance negative.\n");
518 /* When doing outer loop vectorization, we need to check if there is
519 a backward dependence at the inner loop level if the dependence
520 at the outer loop is reversed. See PR81740. */
521 if (nested_in_vect_loop_p (loop, stmtinfo_a)
522 || nested_in_vect_loop_p (loop, stmtinfo_b))
523 {
524 unsigned inner_depth = index_in_loop_nest (loop->inner->num,
525 DDR_LOOP_NEST (ddr)(ddr)->loop_nest);
526 if (dist_v[inner_depth] < 0)
527 return opt_result::failure_at (stmtinfo_a->stmt,
528 "not vectorized, dependence "
529 "between data-refs %T and %T\n",
530 DR_REF (dra)(dra)->ref, DR_REF (drb)(drb)->ref);
531 }
532 /* Record a negative dependence distance to later limit the
533 amount of stmt copying / unrolling we can perform.
534 Only need to handle read-after-write dependence. */
535 if (DR_IS_READ (drb)(drb)->is_read
536 && (STMT_VINFO_MIN_NEG_DIST (stmtinfo_b)(stmtinfo_b)->min_neg_dist == 0
537 || STMT_VINFO_MIN_NEG_DIST (stmtinfo_b)(stmtinfo_b)->min_neg_dist > (unsigned)dist))
538 STMT_VINFO_MIN_NEG_DIST (stmtinfo_b)(stmtinfo_b)->min_neg_dist = dist;
539 continue;
540 }
541
542 unsigned int abs_dist = abs (dist);
543 if (abs_dist >= 2 && abs_dist < *max_vf)
544 {
545 /* The dependence distance requires reduction of the maximal
546 vectorization factor. */
547 *max_vf = abs_dist;
548 if (dump_enabled_p ())
549 dump_printf_loc (MSG_NOTE, vect_location,
550 "adjusting maximal vectorization factor to %i\n",
551 *max_vf);
552 }
553
554 if (abs_dist >= *max_vf)
555 {
556 /* Dependence distance does not create dependence, as far as
557 vectorization is concerned, in this case. */
558 if (dump_enabled_p ())
559 dump_printf_loc (MSG_NOTE, vect_location,
560 "dependence distance >= VF.\n");
561 continue;
562 }
563
564 return opt_result::failure_at (stmtinfo_a->stmt,
565 "not vectorized, possible dependence "
566 "between data-refs %T and %T\n",
567 DR_REF (dra)(dra)->ref, DR_REF (drb)(drb)->ref);
568 }
569
570 return opt_result::success ();
571}
572
573/* Function vect_analyze_data_ref_dependences.
574
575 Examine all the data references in the loop, and make sure there do not
576 exist any data dependences between them. Set *MAX_VF according to
577 the maximum vectorization factor the data dependences allow. */
578
579opt_result
580vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
581 unsigned int *max_vf)
582{
583 unsigned int i;
584 struct data_dependence_relation *ddr;
585
586 DUMP_VECT_SCOPE ("vect_analyze_data_ref_dependences")auto_dump_scope scope ("vect_analyze_data_ref_dependences", vect_location
)
;
587
588 if (!LOOP_VINFO_DDRS (loop_vinfo)(loop_vinfo)->shared->ddrs.exists ())
589 {
590 LOOP_VINFO_DDRS (loop_vinfo)(loop_vinfo)->shared->ddrs
591 .create (LOOP_VINFO_DATAREFS (loop_vinfo)(loop_vinfo)->shared->datarefs.length ()
592 * LOOP_VINFO_DATAREFS (loop_vinfo)(loop_vinfo)->shared->datarefs.length ());
593 /* We do not need read-read dependences. */
594 bool res = compute_all_dependences (LOOP_VINFO_DATAREFS (loop_vinfo)(loop_vinfo)->shared->datarefs,
595 &LOOP_VINFO_DDRS (loop_vinfo)(loop_vinfo)->shared->ddrs,
596 LOOP_VINFO_LOOP_NEST (loop_vinfo)(loop_vinfo)->shared->loop_nest,
597 false);
598 gcc_assert (res)((void)(!(res) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 598, __FUNCTION__), 0 : 0))
;
599 }
600
601 LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo)(loop_vinfo)->no_data_dependencies = true;
602
603 /* For epilogues we either have no aliases or alias versioning
604 was applied to original loop. Therefore we may just get max_vf
605 using VF of original loop. */
606 if (LOOP_VINFO_EPILOGUE_P (loop_vinfo)((loop_vinfo)->orig_loop_info != nullptr))
607 *max_vf = LOOP_VINFO_ORIG_MAX_VECT_FACTOR (loop_vinfo)(((loop_vinfo)->orig_loop_info)->max_vectorization_factor
)
;
608 else
609 FOR_EACH_VEC_ELT (LOOP_VINFO_DDRS (loop_vinfo), i, ddr)for (i = 0; ((loop_vinfo)->shared->ddrs).iterate ((i), &
(ddr)); ++(i))
610 {
611 opt_result res
612 = vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf);
613 if (!res)
614 return res;
615 }
616
617 return opt_result::success ();
618}
619
620
621/* Function vect_slp_analyze_data_ref_dependence.
622
623 Return TRUE if there (might) exist a dependence between a memory-reference
624 DRA and a memory-reference DRB for VINFO. When versioning for alias
625 may check a dependence at run-time, return FALSE. Adjust *MAX_VF
626 according to the data dependence. */
627
628static bool
629vect_slp_analyze_data_ref_dependence (vec_info *vinfo,
630 struct data_dependence_relation *ddr)
631{
632 struct data_reference *dra = DDR_A (ddr)(ddr)->a;
633 struct data_reference *drb = DDR_B (ddr)(ddr)->b;
634 dr_vec_info *dr_info_a = vinfo->lookup_dr (dra);
635 dr_vec_info *dr_info_b = vinfo->lookup_dr (drb);
636
637 /* We need to check dependences of statements marked as unvectorizable
638 as well, they still can prohibit vectorization. */
639
640 /* Independent data accesses. */
641 if (DDR_ARE_DEPENDENT (ddr)(ddr)->are_dependent == chrec_knownglobal_trees[TI_CHREC_KNOWN])
642 return false;
643
644 if (dra == drb)
645 return false;
646
647 /* Read-read is OK. */
648 if (DR_IS_READ (dra)(dra)->is_read && DR_IS_READ (drb)(drb)->is_read)
649 return false;
650
651 /* If dra and drb are part of the same interleaving chain consider
652 them independent. */
653 if (STMT_VINFO_GROUPED_ACCESS (dr_info_a->stmt)((dr_info_a->stmt)->dr_aux.dr && (((void)(!((dr_info_a
->stmt)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 653, __FUNCTION__), 0 : 0)), (dr_info_a->stmt)->first_element
))
654 && (DR_GROUP_FIRST_ELEMENT (dr_info_a->stmt)(((void)(!((dr_info_a->stmt)->dr_aux.dr) ? fancy_abort (
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 654, __FUNCTION__), 0 : 0)), (dr_info_a->stmt)->first_element
)
655 == DR_GROUP_FIRST_ELEMENT (dr_info_b->stmt)(((void)(!((dr_info_b->stmt)->dr_aux.dr) ? fancy_abort (
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 655, __FUNCTION__), 0 : 0)), (dr_info_b->stmt)->first_element
)
))
656 return false;
657
658 /* Unknown data dependence. */
659 if (DDR_ARE_DEPENDENT (ddr)(ddr)->are_dependent == chrec_dont_knowglobal_trees[TI_CHREC_DONT_KNOW])
660 {
661 if (dump_enabled_p ())
662 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
663 "can't determine dependence between %T and %T\n",
664 DR_REF (dra)(dra)->ref, DR_REF (drb)(drb)->ref);
665 }
666 else if (dump_enabled_p ())
667 dump_printf_loc (MSG_NOTE, vect_location,
668 "determined dependence between %T and %T\n",
669 DR_REF (dra)(dra)->ref, DR_REF (drb)(drb)->ref);
670
671 return true;
672}
673
674
675/* Analyze dependences involved in the transform of SLP NODE. STORES
676 contain the vector of scalar stores of this instance if we are
677 disambiguating the loads. */
678
679static bool
680vect_slp_analyze_node_dependences (vec_info *vinfo, slp_tree node,
681 vec<stmt_vec_info> stores,
682 stmt_vec_info last_store_info)
683{
684 /* This walks over all stmts involved in the SLP load/store done
685 in NODE verifying we can sink them up to the last stmt in the
686 group. */
687 if (DR_IS_WRITE (STMT_VINFO_DATA_REF (SLP_TREE_REPRESENTATIVE (node)))(!((((node)->representative)->dr_aux.dr + 0))->is_read
)
)
688 {
689 stmt_vec_info last_access_info = vect_find_last_scalar_stmt_in_slp (node);
690 for (unsigned k = 0; k < SLP_TREE_SCALAR_STMTS (node)(node)->stmts.length (); ++k)
691 {
692 stmt_vec_info access_info
693 = vect_orig_stmt (SLP_TREE_SCALAR_STMTS (node)(node)->stmts[k]);
694 if (access_info == last_access_info)
695 continue;
696 data_reference *dr_a = STMT_VINFO_DATA_REF (access_info)((access_info)->dr_aux.dr + 0);
697 ao_ref ref;
698 bool ref_initialized_p = false;
699 for (gimple_stmt_iterator gsi = gsi_for_stmt (access_info->stmt);
700 gsi_stmt (gsi) != last_access_info->stmt; gsi_next (&gsi))
701 {
702 gimple *stmt = gsi_stmt (gsi);
703 if (! gimple_vuse (stmt))
704 continue;
705
706 /* If we couldn't record a (single) data reference for this
707 stmt we have to resort to the alias oracle. */
708 stmt_vec_info stmt_info = vinfo->lookup_stmt (stmt);
709 data_reference *dr_b = STMT_VINFO_DATA_REF (stmt_info)((stmt_info)->dr_aux.dr + 0);
710 if (!dr_b)
711 {
712 /* We are moving a store - this means
713 we cannot use TBAA for disambiguation. */
714 if (!ref_initialized_p)
715 ao_ref_init (&ref, DR_REF (dr_a)(dr_a)->ref);
716 if (stmt_may_clobber_ref_p_1 (stmt, &ref, false)
717 || ref_maybe_used_by_stmt_p (stmt, &ref, false))
718 return false;
719 continue;
720 }
721
722 bool dependent = false;
723 /* If we run into a store of this same instance (we've just
724 marked those) then delay dependence checking until we run
725 into the last store because this is where it will have
726 been sunk to (and we verify if we can do that as well). */
727 if (gimple_visited_p (stmt))
728 {
729 if (stmt_info != last_store_info)
730 continue;
731
732 for (stmt_vec_info &store_info : stores)
733 {
734 data_reference *store_dr
735 = STMT_VINFO_DATA_REF (store_info)((store_info)->dr_aux.dr + 0);
736 ddr_p ddr = initialize_data_dependence_relation
737 (dr_a, store_dr, vNULL);
738 dependent
739 = vect_slp_analyze_data_ref_dependence (vinfo, ddr);
740 free_dependence_relation (ddr);
741 if (dependent)
742 break;
743 }
744 }
745 else
746 {
747 ddr_p ddr = initialize_data_dependence_relation (dr_a,
748 dr_b, vNULL);
749 dependent = vect_slp_analyze_data_ref_dependence (vinfo, ddr);
750 free_dependence_relation (ddr);
751 }
752 if (dependent)
753 return false;
754 }
755 }
756 }
757 else /* DR_IS_READ */
758 {
759 stmt_vec_info first_access_info
760 = vect_find_first_scalar_stmt_in_slp (node);
761 for (unsigned k = 0; k < SLP_TREE_SCALAR_STMTS (node)(node)->stmts.length (); ++k)
762 {
763 stmt_vec_info access_info
764 = vect_orig_stmt (SLP_TREE_SCALAR_STMTS (node)(node)->stmts[k]);
765 if (access_info == first_access_info)
766 continue;
767 data_reference *dr_a = STMT_VINFO_DATA_REF (access_info)((access_info)->dr_aux.dr + 0);
768 ao_ref ref;
769 bool ref_initialized_p = false;
770 for (gimple_stmt_iterator gsi = gsi_for_stmt (access_info->stmt);
771 gsi_stmt (gsi) != first_access_info->stmt; gsi_prev (&gsi))
772 {
773 gimple *stmt = gsi_stmt (gsi);
774 if (! gimple_vdef (stmt))
775 continue;
776
777 /* If we couldn't record a (single) data reference for this
778 stmt we have to resort to the alias oracle. */
779 stmt_vec_info stmt_info = vinfo->lookup_stmt (stmt);
780 data_reference *dr_b = STMT_VINFO_DATA_REF (stmt_info)((stmt_info)->dr_aux.dr + 0);
781
782 /* We are hoisting a load - this means we can use
783 TBAA for disambiguation. */
784 if (!ref_initialized_p)
785 ao_ref_init (&ref, DR_REF (dr_a)(dr_a)->ref);
786 if (stmt_may_clobber_ref_p_1 (stmt, &ref, true))
787 {
788 if (!dr_b)
789 return false;
790 /* Resort to dependence checking below. */
791 }
792 else
793 /* No dependence. */
794 continue;
795
796 bool dependent = false;
797 /* If we run into a store of this same instance (we've just
798 marked those) then delay dependence checking until we run
799 into the last store because this is where it will have
800 been sunk to (and we verify if we can do that as well). */
801 if (gimple_visited_p (stmt))
802 {
803 if (stmt_info != last_store_info)
804 continue;
805
806 for (stmt_vec_info &store_info : stores)
807 {
808 data_reference *store_dr
809 = STMT_VINFO_DATA_REF (store_info)((store_info)->dr_aux.dr + 0);
810 ddr_p ddr = initialize_data_dependence_relation
811 (dr_a, store_dr, vNULL);
812 dependent
813 = vect_slp_analyze_data_ref_dependence (vinfo, ddr);
814 free_dependence_relation (ddr);
815 if (dependent)
816 break;
817 }
818 }
819 else
820 {
821 ddr_p ddr = initialize_data_dependence_relation (dr_a,
822 dr_b, vNULL);
823 dependent = vect_slp_analyze_data_ref_dependence (vinfo, ddr);
824 free_dependence_relation (ddr);
825 }
826 if (dependent)
827 return false;
828 }
829 }
830 }
831 return true;
832}
833
834
835/* Function vect_analyze_data_ref_dependences.
836
837 Examine all the data references in the basic-block, and make sure there
838 do not exist any data dependences between them. Set *MAX_VF according to
839 the maximum vectorization factor the data dependences allow. */
840
841bool
842vect_slp_analyze_instance_dependence (vec_info *vinfo, slp_instance instance)
843{
844 DUMP_VECT_SCOPE ("vect_slp_analyze_instance_dependence")auto_dump_scope scope ("vect_slp_analyze_instance_dependence"
, vect_location)
;
845
846 /* The stores of this instance are at the root of the SLP tree. */
847 slp_tree store = NULLnullptr;
848 if (SLP_INSTANCE_KIND (instance)(instance)->kind == slp_inst_kind_store)
849 store = SLP_INSTANCE_TREE (instance)(instance)->root;
850
851 /* Verify we can sink stores to the vectorized stmt insert location. */
852 stmt_vec_info last_store_info = NULLnullptr;
853 if (store)
854 {
855 if (! vect_slp_analyze_node_dependences (vinfo, store, vNULL, NULLnullptr))
856 return false;
857
858 /* Mark stores in this instance and remember the last one. */
859 last_store_info = vect_find_last_scalar_stmt_in_slp (store);
860 for (unsigned k = 0; k < SLP_TREE_SCALAR_STMTS (store)(store)->stmts.length (); ++k)
861 gimple_set_visited (SLP_TREE_SCALAR_STMTS (store)(store)->stmts[k]->stmt, true);
862 }
863
864 bool res = true;
865
866 /* Verify we can sink loads to the vectorized stmt insert location,
867 special-casing stores of this instance. */
868 for (slp_tree &load : SLP_INSTANCE_LOADS (instance)(instance)->loads)
869 if (! vect_slp_analyze_node_dependences (vinfo, load,
870 store
871 ? SLP_TREE_SCALAR_STMTS (store)(store)->stmts
872 : vNULL, last_store_info))
873 {
874 res = false;
875 break;
876 }
877
878 /* Unset the visited flag. */
879 if (store)
880 for (unsigned k = 0; k < SLP_TREE_SCALAR_STMTS (store)(store)->stmts.length (); ++k)
881 gimple_set_visited (SLP_TREE_SCALAR_STMTS (store)(store)->stmts[k]->stmt, false);
882
883 return res;
884}
885
886/* Return the misalignment of DR_INFO accessed in VECTYPE with OFFSET
887 applied. */
888
889int
890dr_misalignment (dr_vec_info *dr_info, tree vectype, poly_int64 offset)
891{
892 HOST_WIDE_INTlong diff = 0;
893 /* Alignment is only analyzed for the first element of a DR group,
894 use that but adjust misalignment by the offset of the access. */
895 if (STMT_VINFO_GROUPED_ACCESS (dr_info->stmt)((dr_info->stmt)->dr_aux.dr && (((void)(!((dr_info
->stmt)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 895, __FUNCTION__), 0 : 0)), (dr_info->stmt)->first_element
))
)
896 {
897 dr_vec_info *first_dr
898 = STMT_VINFO_DR_INFO (DR_GROUP_FIRST_ELEMENT (dr_info->stmt))(((void)(!(((((void)(!((dr_info->stmt)->dr_aux.dr) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 898, __FUNCTION__), 0 : 0)), (dr_info->stmt)->first_element
))->dr_aux.stmt == ((((void)(!((dr_info->stmt)->dr_aux
.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 898, __FUNCTION__), 0 : 0)), (dr_info->stmt)->first_element
))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 898, __FUNCTION__), 0 : 0)), &((((void)(!((dr_info->
stmt)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 898, __FUNCTION__), 0 : 0)), (dr_info->stmt)->first_element
))->dr_aux)
;
899 /* vect_analyze_data_ref_accesses guarantees that DR_INIT are
900 INTEGER_CSTs and the first element in the group has the lowest
901 address. */
902 diff = (TREE_INT_CST_LOW (DR_INIT (dr_info->dr))((unsigned long) (*tree_int_cst_elt_check (((dr_info->dr)->
innermost.init), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 902, __FUNCTION__)))
903 - TREE_INT_CST_LOW (DR_INIT (first_dr->dr))((unsigned long) (*tree_int_cst_elt_check (((first_dr->dr)
->innermost.init), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 903, __FUNCTION__)))
);
904 gcc_assert (diff >= 0)((void)(!(diff >= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 904, __FUNCTION__), 0 : 0))
;
905 dr_info = first_dr;
906 }
907
908 int misalign = dr_info->misalignment;
909 gcc_assert (misalign != DR_MISALIGNMENT_UNINITIALIZED)((void)(!(misalign != (-2)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 909, __FUNCTION__), 0 : 0))
;
910 if (misalign == DR_MISALIGNMENT_UNKNOWN(-1))
911 return misalign;
912
913 /* If the access is only aligned for a vector type with smaller alignment
914 requirement the access has unknown misalignment. */
915 if (maybe_lt (dr_info->target_alignment * BITS_PER_UNIT(8),
916 targetm.vectorize.preferred_vector_alignment (vectype)))
917 return DR_MISALIGNMENT_UNKNOWN(-1);
918
919 /* Apply the offset from the DR group start and the externally supplied
920 offset which can for example result from a negative stride access. */
921 poly_int64 misalignment = misalign + diff + offset;
922
923 /* vect_compute_data_ref_alignment will have ensured that target_alignment
924 is constant and otherwise set misalign to DR_MISALIGNMENT_UNKNOWN. */
925 unsigned HOST_WIDE_INTlong target_alignment_c
926 = dr_info->target_alignment.to_constant ();
927 if (!known_misalignment (misalignment, target_alignment_c, &misalign))
928 return DR_MISALIGNMENT_UNKNOWN(-1);
929 return misalign;
930}
931
932/* Record the base alignment guarantee given by DRB, which occurs
933 in STMT_INFO. */
934
935static void
936vect_record_base_alignment (vec_info *vinfo, stmt_vec_info stmt_info,
937 innermost_loop_behavior *drb)
938{
939 bool existed;
940 std::pair<stmt_vec_info, innermost_loop_behavior *> &entry
941 = vinfo->base_alignments.get_or_insert (drb->base_address, &existed);
942 if (!existed || entry.second->base_alignment < drb->base_alignment)
943 {
944 entry = std::make_pair (stmt_info, drb);
945 if (dump_enabled_p ())
946 dump_printf_loc (MSG_NOTE, vect_location,
947 "recording new base alignment for %T\n"
948 " alignment: %d\n"
949 " misalignment: %d\n"
950 " based on: %G",
951 drb->base_address,
952 drb->base_alignment,
953 drb->base_misalignment,
954 stmt_info->stmt);
955 }
956}
957
958/* If the region we're going to vectorize is reached, all unconditional
959 data references occur at least once. We can therefore pool the base
960 alignment guarantees from each unconditional reference. Do this by
961 going through all the data references in VINFO and checking whether
962 the containing statement makes the reference unconditionally. If so,
963 record the alignment of the base address in VINFO so that it can be
964 used for all other references with the same base. */
965
966void
967vect_record_base_alignments (vec_info *vinfo)
968{
969 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
970 class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop : NULLnullptr;
971 for (data_reference *dr : vinfo->shared->datarefs)
972 {
973 dr_vec_info *dr_info = vinfo->lookup_dr (dr);
974 stmt_vec_info stmt_info = dr_info->stmt;
975 if (!DR_IS_CONDITIONAL_IN_STMT (dr)(dr)->is_conditional_in_stmt
976 && STMT_VINFO_VECTORIZABLE (stmt_info)(stmt_info)->vectorizable
977 && !STMT_VINFO_GATHER_SCATTER_P (stmt_info)(stmt_info)->gather_scatter_p)
978 {
979 vect_record_base_alignment (vinfo, stmt_info, &DR_INNERMOST (dr)(dr)->innermost);
980
981 /* If DR is nested in the loop that is being vectorized, we can also
982 record the alignment of the base wrt the outer loop. */
983 if (loop && nested_in_vect_loop_p (loop, stmt_info))
984 vect_record_base_alignment
985 (vinfo, stmt_info, &STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info)(stmt_info)->dr_wrt_vec_loop);
986 }
987 }
988}
989
990/* Function vect_compute_data_ref_alignment
991
992 Compute the misalignment of the data reference DR_INFO when vectorizing
993 with VECTYPE.
994
995 Output:
996 1. initialized misalignment info for DR_INFO
997
998 FOR NOW: No analysis is actually performed. Misalignment is calculated
999 only for trivial cases. TODO. */
1000
1001static void
1002vect_compute_data_ref_alignment (vec_info *vinfo, dr_vec_info *dr_info,
1003 tree vectype)
1004{
1005 stmt_vec_info stmt_info = dr_info->stmt;
1006 vec_base_alignments *base_alignments = &vinfo->base_alignments;
1007 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
1008 class loop *loop = NULLnullptr;
1009 tree ref = DR_REF (dr_info->dr)(dr_info->dr)->ref;
1010
1011 if (dump_enabled_p ())
1012 dump_printf_loc (MSG_NOTE, vect_location,
1013 "vect_compute_data_ref_alignment:\n");
1014
1015 if (loop_vinfo)
1016 loop = LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop;
1017
1018 /* Initialize misalignment to unknown. */
1019 SET_DR_MISALIGNMENT (dr_info, DR_MISALIGNMENT_UNKNOWN)set_dr_misalignment (dr_info, (-1));
1020
1021 if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)(stmt_info)->gather_scatter_p)
1022 return;
1023
1024 innermost_loop_behavior *drb = vect_dr_behavior (vinfo, dr_info);
1025 bool step_preserves_misalignment_p;
1026
1027 poly_uint64 vector_alignment
1028 = exact_div (targetm.vectorize.preferred_vector_alignment (vectype),
1029 BITS_PER_UNIT(8));
1030 SET_DR_TARGET_ALIGNMENT (dr_info, vector_alignment)set_dr_target_alignment (dr_info, vector_alignment);
1031
1032 /* If the main loop has peeled for alignment we have no way of knowing
1033 whether the data accesses in the epilogues are aligned. We can't at
1034 compile time answer the question whether we have entered the main loop or
1035 not. Fixes PR 92351. */
1036 if (loop_vinfo)
1037 {
1038 loop_vec_info orig_loop_vinfo = LOOP_VINFO_ORIG_LOOP_INFO (loop_vinfo)(loop_vinfo)->orig_loop_info;
1039 if (orig_loop_vinfo
1040 && LOOP_VINFO_PEELING_FOR_ALIGNMENT (orig_loop_vinfo)(orig_loop_vinfo)->peeling_for_alignment != 0)
1041 return;
1042 }
1043
1044 unsigned HOST_WIDE_INTlong vect_align_c;
1045 if (!vector_alignment.is_constant (&vect_align_c))
1046 return;
1047
1048 /* No step for BB vectorization. */
1049 if (!loop)
1050 {
1051 gcc_assert (integer_zerop (drb->step))((void)(!(integer_zerop (drb->step)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1051, __FUNCTION__), 0 : 0))
;
1052 step_preserves_misalignment_p = true;
1053 }
1054
1055 /* In case the dataref is in an inner-loop of the loop that is being
1056 vectorized (LOOP), we use the base and misalignment information
1057 relative to the outer-loop (LOOP). This is ok only if the misalignment
1058 stays the same throughout the execution of the inner-loop, which is why
1059 we have to check that the stride of the dataref in the inner-loop evenly
1060 divides by the vector alignment. */
1061 else if (nested_in_vect_loop_p (loop, stmt_info))
1062 {
1063 step_preserves_misalignment_p
1064 = (DR_STEP_ALIGNMENT (dr_info->dr)(dr_info->dr)->innermost.step_alignment % vect_align_c) == 0;
1065
1066 if (dump_enabled_p ())
1067 {
1068 if (step_preserves_misalignment_p)
1069 dump_printf_loc (MSG_NOTE, vect_location,
1070 "inner step divides the vector alignment.\n");
1071 else
1072 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1073 "inner step doesn't divide the vector"
1074 " alignment.\n");
1075 }
1076 }
1077
1078 /* Similarly we can only use base and misalignment information relative to
1079 an innermost loop if the misalignment stays the same throughout the
1080 execution of the loop. As above, this is the case if the stride of
1081 the dataref evenly divides by the alignment. */
1082 else
1083 {
1084 poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo)(loop_vinfo)->vectorization_factor;
1085 step_preserves_misalignment_p
1086 = multiple_p (DR_STEP_ALIGNMENT (dr_info->dr)(dr_info->dr)->innermost.step_alignment * vf, vect_align_c);
1087
1088 if (!step_preserves_misalignment_p && dump_enabled_p ())
1089 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1090 "step doesn't divide the vector alignment.\n");
1091 }
1092
1093 unsigned int base_alignment = drb->base_alignment;
1094 unsigned int base_misalignment = drb->base_misalignment;
1095
1096 /* Calculate the maximum of the pooled base address alignment and the
1097 alignment that we can compute for DR itself. */
1098 std::pair<stmt_vec_info, innermost_loop_behavior *> *entry
1099 = base_alignments->get (drb->base_address);
1100 if (entry
1101 && base_alignment < (*entry).second->base_alignment
1102 && (loop_vinfo
1103 || (dominated_by_p (CDI_DOMINATORS, gimple_bb (stmt_info->stmt),
1104 gimple_bb (entry->first->stmt))
1105 && (gimple_bb (stmt_info->stmt) != gimple_bb (entry->first->stmt)
1106 || (entry->first->dr_aux.group <= dr_info->group)))))
1107 {
1108 base_alignment = entry->second->base_alignment;
1109 base_misalignment = entry->second->base_misalignment;
1110 }
1111
1112 if (drb->offset_alignment < vect_align_c
1113 || !step_preserves_misalignment_p
1114 /* We need to know whether the step wrt the vectorized loop is
1115 negative when computing the starting misalignment below. */
1116 || TREE_CODE (drb->step)((enum tree_code) (drb->step)->base.code) != INTEGER_CST)
1117 {
1118 if (dump_enabled_p ())
1119 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1120 "Unknown alignment for access: %T\n", ref);
1121 return;
1122 }
1123
1124 if (base_alignment < vect_align_c)
1125 {
1126 unsigned int max_alignment;
1127 tree base = get_base_for_alignment (drb->base_address, &max_alignment);
1128 if (max_alignment < vect_align_c
1129 || !vect_can_force_dr_alignment_p (base,
1130 vect_align_c * BITS_PER_UNIT(8)))
1131 {
1132 if (dump_enabled_p ())
1133 dump_printf_loc (MSG_NOTE, vect_location,
1134 "can't force alignment of ref: %T\n", ref);
1135 return;
1136 }
1137
1138 /* Force the alignment of the decl.
1139 NOTE: This is the only change to the code we make during
1140 the analysis phase, before deciding to vectorize the loop. */
1141 if (dump_enabled_p ())
1142 dump_printf_loc (MSG_NOTE, vect_location,
1143 "force alignment of %T\n", ref);
1144
1145 dr_info->base_decl = base;
1146 dr_info->base_misaligned = true;
1147 base_misalignment = 0;
1148 }
1149 poly_int64 misalignment
1150 = base_misalignment + wi::to_poly_offset (drb->init).force_shwi ();
1151
1152 unsigned int const_misalignment;
1153 if (!known_misalignment (misalignment, vect_align_c, &const_misalignment))
1154 {
1155 if (dump_enabled_p ())
1156 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1157 "Non-constant misalignment for access: %T\n", ref);
1158 return;
1159 }
1160
1161 SET_DR_MISALIGNMENT (dr_info, const_misalignment)set_dr_misalignment (dr_info, const_misalignment);
1162
1163 if (dump_enabled_p ())
1164 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1165 "misalign = %d bytes of ref %T\n",
1166 const_misalignment, ref);
1167
1168 return;
1169}
1170
1171/* Return whether DR_INFO, which is related to DR_PEEL_INFO in
1172 that it only differs in DR_INIT, is aligned if DR_PEEL_INFO
1173 is made aligned via peeling. */
1174
1175static bool
1176vect_dr_aligned_if_related_peeled_dr_is (dr_vec_info *dr_info,
1177 dr_vec_info *dr_peel_info)
1178{
1179 if (multiple_p (DR_TARGET_ALIGNMENT (dr_peel_info)dr_target_alignment (dr_peel_info),
1180 DR_TARGET_ALIGNMENT (dr_info)dr_target_alignment (dr_info)))
1181 {
1182 poly_offset_int diff
1183 = (wi::to_poly_offset (DR_INIT (dr_peel_info->dr)(dr_peel_info->dr)->innermost.init)
1184 - wi::to_poly_offset (DR_INIT (dr_info->dr)(dr_info->dr)->innermost.init));
1185 if (known_eq (diff, 0)(!maybe_ne (diff, 0))
1186 || multiple_p (diff, DR_TARGET_ALIGNMENT (dr_info)dr_target_alignment (dr_info)))
1187 return true;
1188 }
1189 return false;
1190}
1191
1192/* Return whether DR_INFO is aligned if DR_PEEL_INFO is made
1193 aligned via peeling. */
1194
1195static bool
1196vect_dr_aligned_if_peeled_dr_is (dr_vec_info *dr_info,
1197 dr_vec_info *dr_peel_info)
1198{
1199 if (!operand_equal_p (DR_BASE_ADDRESS (dr_info->dr)(dr_info->dr)->innermost.base_address,
1200 DR_BASE_ADDRESS (dr_peel_info->dr)(dr_peel_info->dr)->innermost.base_address, 0)
1201 || !operand_equal_p (DR_OFFSET (dr_info->dr)(dr_info->dr)->innermost.offset,
1202 DR_OFFSET (dr_peel_info->dr)(dr_peel_info->dr)->innermost.offset, 0)
1203 || !operand_equal_p (DR_STEP (dr_info->dr)(dr_info->dr)->innermost.step,
1204 DR_STEP (dr_peel_info->dr)(dr_peel_info->dr)->innermost.step, 0))
1205 return false;
1206
1207 return vect_dr_aligned_if_related_peeled_dr_is (dr_info, dr_peel_info);
1208}
1209
1210/* Compute the value for dr_info->misalign so that the access appears
1211 aligned. This is used by peeling to compensate for dr_misalignment
1212 applying the offset for negative step. */
1213
1214int
1215vect_dr_misalign_for_aligned_access (dr_vec_info *dr_info)
1216{
1217 if (tree_int_cst_sgn (DR_STEP (dr_info->dr)(dr_info->dr)->innermost.step) >= 0)
1218 return 0;
1219
1220 tree vectype = STMT_VINFO_VECTYPE (dr_info->stmt)(dr_info->stmt)->vectype;
1221 poly_int64 misalignment
1222 = ((TYPE_VECTOR_SUBPARTS (vectype) - 1)
1223 * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype)))((unsigned long) (*tree_int_cst_elt_check ((((tree_class_check
((((contains_struct_check ((vectype), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1223, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1223, __FUNCTION__))->type_common.size_unit)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1223, __FUNCTION__)))
);
1224
1225 unsigned HOST_WIDE_INTlong target_alignment_c;
1226 int misalign;
1227 if (!dr_info->target_alignment.is_constant (&target_alignment_c)
1228 || !known_misalignment (misalignment, target_alignment_c, &misalign))
1229 return DR_MISALIGNMENT_UNKNOWN(-1);
1230 return misalign;
1231}
1232
1233/* Function vect_update_misalignment_for_peel.
1234 Sets DR_INFO's misalignment
1235 - to 0 if it has the same alignment as DR_PEEL_INFO,
1236 - to the misalignment computed using NPEEL if DR_INFO's salignment is known,
1237 - to -1 (unknown) otherwise.
1238
1239 DR_INFO - the data reference whose misalignment is to be adjusted.
1240 DR_PEEL_INFO - the data reference whose misalignment is being made
1241 zero in the vector loop by the peel.
1242 NPEEL - the number of iterations in the peel loop if the misalignment
1243 of DR_PEEL_INFO is known at compile time. */
1244
1245static void
1246vect_update_misalignment_for_peel (dr_vec_info *dr_info,
1247 dr_vec_info *dr_peel_info, int npeel)
1248{
1249 /* If dr_info is aligned of dr_peel_info is, then mark it so. */
1250 if (vect_dr_aligned_if_peeled_dr_is (dr_info, dr_peel_info))
1251 {
1252 SET_DR_MISALIGNMENT (dr_info,set_dr_misalignment (dr_info, vect_dr_misalign_for_aligned_access
(dr_peel_info))
1253 vect_dr_misalign_for_aligned_access (dr_peel_info))set_dr_misalignment (dr_info, vect_dr_misalign_for_aligned_access
(dr_peel_info))
;
1254 return;
1255 }
1256
1257 unsigned HOST_WIDE_INTlong alignment;
1258 if (DR_TARGET_ALIGNMENT (dr_info)dr_target_alignment (dr_info).is_constant (&alignment)
1259 && known_alignment_for_access_p (dr_info,
1260 STMT_VINFO_VECTYPE (dr_info->stmt)(dr_info->stmt)->vectype)
1261 && known_alignment_for_access_p (dr_peel_info,
1262 STMT_VINFO_VECTYPE (dr_peel_info->stmt)(dr_peel_info->stmt)->vectype))
1263 {
1264 int misal = dr_info->misalignment;
1265 misal += npeel * TREE_INT_CST_LOW (DR_STEP (dr_info->dr))((unsigned long) (*tree_int_cst_elt_check (((dr_info->dr)->
innermost.step), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1265, __FUNCTION__)))
;
1266 misal &= alignment - 1;
1267 set_dr_misalignment (dr_info, misal);
1268 return;
1269 }
1270
1271 if (dump_enabled_p ())
1272 dump_printf_loc (MSG_NOTE, vect_location, "Setting misalignment " \
1273 "to unknown (-1).\n");
1274 SET_DR_MISALIGNMENT (dr_info, DR_MISALIGNMENT_UNKNOWN)set_dr_misalignment (dr_info, (-1));
1275}
1276
1277/* Return true if alignment is relevant for DR_INFO. */
1278
1279static bool
1280vect_relevant_for_alignment_p (dr_vec_info *dr_info)
1281{
1282 stmt_vec_info stmt_info = dr_info->stmt;
1283
1284 if (!STMT_VINFO_RELEVANT_P (stmt_info)((stmt_info)->relevant != vect_unused_in_scope))
1285 return false;
1286
1287 /* For interleaving, only the alignment of the first access matters. */
1288 if (STMT_VINFO_GROUPED_ACCESS (stmt_info)((stmt_info)->dr_aux.dr && (((void)(!((stmt_info)->
dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1288, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
))
1289 && DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1289, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
!= stmt_info)
1290 return false;
1291
1292 /* Scatter-gather and invariant accesses continue to address individual
1293 scalars, so vector-level alignment is irrelevant. */
1294 if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)(stmt_info)->gather_scatter_p
1295 || integer_zerop (DR_STEP (dr_info->dr)(dr_info->dr)->innermost.step))
1296 return false;
1297
1298 /* Strided accesses perform only component accesses, alignment is
1299 irrelevant for them. */
1300 if (STMT_VINFO_STRIDED_P (stmt_info)(stmt_info)->strided_p
1301 && !STMT_VINFO_GROUPED_ACCESS (stmt_info)((stmt_info)->dr_aux.dr && (((void)(!((stmt_info)->
dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1301, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
))
)
1302 return false;
1303
1304 return true;
1305}
1306
1307/* Given an memory reference EXP return whether its alignment is less
1308 than its size. */
1309
1310static bool
1311not_size_aligned (tree exp)
1312{
1313 if (!tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (exp))((tree_class_check ((((contains_struct_check ((exp), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1313, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1313, __FUNCTION__))->type_common.size)
))
1314 return true;
1315
1316 return (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (exp))((tree_class_check ((((contains_struct_check ((exp), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1316, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1316, __FUNCTION__))->type_common.size)
)
1317 > get_object_alignment (exp));
1318}
1319
1320/* Function vector_alignment_reachable_p
1321
1322 Return true if vector alignment for DR_INFO is reachable by peeling
1323 a few loop iterations. Return false otherwise. */
1324
1325static bool
1326vector_alignment_reachable_p (dr_vec_info *dr_info)
1327{
1328 stmt_vec_info stmt_info = dr_info->stmt;
1329 tree vectype = STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype;
1330
1331 if (STMT_VINFO_GROUPED_ACCESS (stmt_info)((stmt_info)->dr_aux.dr && (((void)(!((stmt_info)->
dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1331, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
))
)
1332 {
1333 /* For interleaved access we peel only if number of iterations in
1334 the prolog loop ({VF - misalignment}), is a multiple of the
1335 number of the interleaved accesses. */
1336 int elem_size, mis_in_elements;
1337
1338 /* FORNOW: handle only known alignment. */
1339 if (!known_alignment_for_access_p (dr_info, vectype))
1340 return false;
1341
1342 poly_uint64 nelements = TYPE_VECTOR_SUBPARTS (vectype);
1343 poly_uint64 vector_size = GET_MODE_SIZE (TYPE_MODE (vectype)((((enum tree_code) ((tree_class_check ((vectype), (tcc_type)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1343, __FUNCTION__)))->base.code) == VECTOR_TYPE) ? vector_type_mode
(vectype) : (vectype)->type_common.mode)
);
1344 elem_size = vector_element_size (vector_size, nelements)(exact_div (vector_size, nelements).to_constant ());
1345 mis_in_elements = dr_misalignment (dr_info, vectype) / elem_size;
1346
1347 if (!multiple_p (nelements - mis_in_elements, DR_GROUP_SIZE (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1347, __FUNCTION__), 0 : 0)), (stmt_info)->size)
))
1348 return false;
1349 }
1350
1351 /* If misalignment is known at the compile time then allow peeling
1352 only if natural alignment is reachable through peeling. */
1353 if (known_alignment_for_access_p (dr_info, vectype)
1354 && !aligned_access_p (dr_info, vectype))
1355 {
1356 HOST_WIDE_INTlong elmsize =
1357 int_cst_value (TYPE_SIZE_UNIT (TREE_TYPE (vectype))((tree_class_check ((((contains_struct_check ((vectype), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1357, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1357, __FUNCTION__))->type_common.size_unit)
);
1358 if (dump_enabled_p ())
1359 {
1360 dump_printf_loc (MSG_NOTE, vect_location,
1361 "data size = %wd. misalignment = %d.\n", elmsize,
1362 dr_misalignment (dr_info, vectype));
1363 }
1364 if (dr_misalignment (dr_info, vectype) % elmsize)
1365 {
1366 if (dump_enabled_p ())
1367 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1368 "data size does not divide the misalignment.\n");
1369 return false;
1370 }
1371 }
1372
1373 if (!known_alignment_for_access_p (dr_info, vectype))
1374 {
1375 tree type = TREE_TYPE (DR_REF (dr_info->dr))((contains_struct_check (((dr_info->dr)->ref), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1375, __FUNCTION__))->typed.type)
;
1376 bool is_packed = not_size_aligned (DR_REF (dr_info->dr)(dr_info->dr)->ref);
1377 if (dump_enabled_p ())
1378 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
1379 "Unknown misalignment, %snaturally aligned\n",
1380 is_packed ? "not " : "");
1381 return targetm.vectorize.vector_alignment_reachable (type, is_packed);
1382 }
1383
1384 return true;
1385}
1386
1387
1388/* Calculate the cost of the memory access represented by DR_INFO. */
1389
1390static void
1391vect_get_data_access_cost (vec_info *vinfo, dr_vec_info *dr_info,
1392 dr_alignment_support alignment_support_scheme,
1393 int misalignment,
1394 unsigned int *inside_cost,
1395 unsigned int *outside_cost,
1396 stmt_vector_for_cost *body_cost_vec,
1397 stmt_vector_for_cost *prologue_cost_vec)
1398{
1399 stmt_vec_info stmt_info = dr_info->stmt;
1400 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
1401 int ncopies;
1402
1403 if (PURE_SLP_STMT (stmt_info)((stmt_info)->slp_type == pure_slp))
1404 ncopies = 1;
1405 else
1406 ncopies = vect_get_num_copies (loop_vinfo, STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype);
1407
1408 if (DR_IS_READ (dr_info->dr)(dr_info->dr)->is_read)
1409 vect_get_load_cost (vinfo, stmt_info, ncopies, alignment_support_scheme,
1410 misalignment, true, inside_cost,
1411 outside_cost, prologue_cost_vec, body_cost_vec, false);
1412 else
1413 vect_get_store_cost (vinfo,stmt_info, ncopies, alignment_support_scheme,
1414 misalignment, inside_cost, body_cost_vec);
1415
1416 if (dump_enabled_p ())
1417 dump_printf_loc (MSG_NOTE, vect_location,
1418 "vect_get_data_access_cost: inside_cost = %d, "
1419 "outside_cost = %d.\n", *inside_cost, *outside_cost);
1420}
1421
1422
1423typedef struct _vect_peel_info
1424{
1425 dr_vec_info *dr_info;
1426 int npeel;
1427 unsigned int count;
1428} *vect_peel_info;
1429
1430typedef struct _vect_peel_extended_info
1431{
1432 vec_info *vinfo;
1433 struct _vect_peel_info peel_info;
1434 unsigned int inside_cost;
1435 unsigned int outside_cost;
1436} *vect_peel_extended_info;
1437
1438
1439/* Peeling hashtable helpers. */
1440
1441struct peel_info_hasher : free_ptr_hash <_vect_peel_info>
1442{
1443 static inline hashval_t hash (const _vect_peel_info *);
1444 static inline bool equal (const _vect_peel_info *, const _vect_peel_info *);
1445};
1446
1447inline hashval_t
1448peel_info_hasher::hash (const _vect_peel_info *peel_info)
1449{
1450 return (hashval_t) peel_info->npeel;
1451}
1452
1453inline bool
1454peel_info_hasher::equal (const _vect_peel_info *a, const _vect_peel_info *b)
1455{
1456 return (a->npeel == b->npeel);
1457}
1458
1459
1460/* Insert DR_INFO into peeling hash table with NPEEL as key. */
1461
1462static void
1463vect_peeling_hash_insert (hash_table<peel_info_hasher> *peeling_htab,
1464 loop_vec_info loop_vinfo, dr_vec_info *dr_info,
1465 int npeel, bool supportable_if_not_aligned)
1466{
1467 struct _vect_peel_info elem, *slot;
1468 _vect_peel_info **new_slot;
1469
1470 elem.npeel = npeel;
1471 slot = peeling_htab->find (&elem);
1472 if (slot)
1473 slot->count++;
1474 else
1475 {
1476 slot = XNEW (struct _vect_peel_info)((struct _vect_peel_info *) xmalloc (sizeof (struct _vect_peel_info
)))
;
1477 slot->npeel = npeel;
1478 slot->dr_info = dr_info;
1479 slot->count = 1;
1480 new_slot = peeling_htab->find_slot (slot, INSERT);
1481 *new_slot = slot;
1482 }
1483
1484 /* If this DR is not supported with unknown misalignment then bias
1485 this slot when the cost model is disabled. */
1486 if (!supportable_if_not_aligned
1487 && unlimited_cost_model (LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop))
1488 slot->count += VECT_MAX_COST1000;
1489}
1490
1491
1492/* Traverse peeling hash table to find peeling option that aligns maximum
1493 number of data accesses. */
1494
1495int
1496vect_peeling_hash_get_most_frequent (_vect_peel_info **slot,
1497 _vect_peel_extended_info *max)
1498{
1499 vect_peel_info elem = *slot;
1500
1501 if (elem->count > max->peel_info.count
1502 || (elem->count == max->peel_info.count
1503 && max->peel_info.npeel > elem->npeel))
1504 {
1505 max->peel_info.npeel = elem->npeel;
1506 max->peel_info.count = elem->count;
1507 max->peel_info.dr_info = elem->dr_info;
1508 }
1509
1510 return 1;
1511}
1512
1513/* Get the costs of peeling NPEEL iterations for LOOP_VINFO, checking
1514 data access costs for all data refs. If UNKNOWN_MISALIGNMENT is true,
1515 npeel is computed at runtime but DR0_INFO's misalignment will be zero
1516 after peeling. */
1517
1518static void
1519vect_get_peeling_costs_all_drs (loop_vec_info loop_vinfo,
1520 dr_vec_info *dr0_info,
1521 unsigned int *inside_cost,
1522 unsigned int *outside_cost,
1523 stmt_vector_for_cost *body_cost_vec,
1524 stmt_vector_for_cost *prologue_cost_vec,
1525 unsigned int npeel)
1526{
1527 vec<data_reference_p> datarefs = LOOP_VINFO_DATAREFS (loop_vinfo)(loop_vinfo)->shared->datarefs;
1528
1529 bool dr0_alignment_known_p
1530 = (dr0_info
1531 && known_alignment_for_access_p (dr0_info,
1532 STMT_VINFO_VECTYPE (dr0_info->stmt)(dr0_info->stmt)->vectype));
1533
1534 for (data_reference *dr : datarefs)
1535 {
1536 dr_vec_info *dr_info = loop_vinfo->lookup_dr (dr);
1537 if (!vect_relevant_for_alignment_p (dr_info))
1538 continue;
1539
1540 tree vectype = STMT_VINFO_VECTYPE (dr_info->stmt)(dr_info->stmt)->vectype;
1541 dr_alignment_support alignment_support_scheme;
1542 int misalignment;
1543 unsigned HOST_WIDE_INTlong alignment;
1544
1545 bool negative = tree_int_cst_compare (DR_STEP (dr_info->dr)(dr_info->dr)->innermost.step,
1546 size_zero_nodeglobal_trees[TI_SIZE_ZERO]) < 0;
1547 poly_int64 off = 0;
1548 if (negative)
1549 off = ((TYPE_VECTOR_SUBPARTS (vectype) - 1)
1550 * -TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype)))((unsigned long) (*tree_int_cst_elt_check ((((tree_class_check
((((contains_struct_check ((vectype), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1550, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1550, __FUNCTION__))->type_common.size_unit)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1550, __FUNCTION__)))
);
1551
1552 if (npeel == 0)
1553 misalignment = dr_misalignment (dr_info, vectype, off);
1554 else if (dr_info == dr0_info
1555 || vect_dr_aligned_if_peeled_dr_is (dr_info, dr0_info))
1556 misalignment = 0;
1557 else if (!dr0_alignment_known_p
1558 || !known_alignment_for_access_p (dr_info, vectype)
1559 || !DR_TARGET_ALIGNMENT (dr_info)dr_target_alignment (dr_info).is_constant (&alignment))
1560 misalignment = DR_MISALIGNMENT_UNKNOWN(-1);
1561 else
1562 {
1563 misalignment = dr_misalignment (dr_info, vectype, off);
1564 misalignment += npeel * TREE_INT_CST_LOW (DR_STEP (dr_info->dr))((unsigned long) (*tree_int_cst_elt_check (((dr_info->dr)->
innermost.step), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1564, __FUNCTION__)))
;
1565 misalignment &= alignment - 1;
1566 }
1567 alignment_support_scheme
1568 = vect_supportable_dr_alignment (loop_vinfo, dr_info, vectype,
1569 misalignment);
1570
1571 vect_get_data_access_cost (loop_vinfo, dr_info,
1572 alignment_support_scheme, misalignment,
1573 inside_cost, outside_cost,
1574 body_cost_vec, prologue_cost_vec);
1575 }
1576}
1577
1578/* Traverse peeling hash table and calculate cost for each peeling option.
1579 Find the one with the lowest cost. */
1580
1581int
1582vect_peeling_hash_get_lowest_cost (_vect_peel_info **slot,
1583 _vect_peel_extended_info *min)
1584{
1585 vect_peel_info elem = *slot;
1586 int dummy;
1587 unsigned int inside_cost = 0, outside_cost = 0;
1588 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (min->vinfo);
1589 stmt_vector_for_cost prologue_cost_vec, body_cost_vec,
1590 epilogue_cost_vec;
1591
1592 prologue_cost_vec.create (2);
1593 body_cost_vec.create (2);
1594 epilogue_cost_vec.create (2);
1595
1596 vect_get_peeling_costs_all_drs (loop_vinfo, elem->dr_info, &inside_cost,
1597 &outside_cost, &body_cost_vec,
1598 &prologue_cost_vec, elem->npeel);
1599
1600 body_cost_vec.release ();
1601
1602 outside_cost += vect_get_known_peeling_cost
1603 (loop_vinfo, elem->npeel, &dummy,
1604 &LOOP_VINFO_SCALAR_ITERATION_COST (loop_vinfo)(loop_vinfo)->scalar_cost_vec,
1605 &prologue_cost_vec, &epilogue_cost_vec);
1606
1607 /* Prologue and epilogue costs are added to the target model later.
1608 These costs depend only on the scalar iteration cost, the
1609 number of peeling iterations finally chosen, and the number of
1610 misaligned statements. So discard the information found here. */
1611 prologue_cost_vec.release ();
1612 epilogue_cost_vec.release ();
1613
1614 if (inside_cost < min->inside_cost
1615 || (inside_cost == min->inside_cost
1616 && outside_cost < min->outside_cost))
1617 {
1618 min->inside_cost = inside_cost;
1619 min->outside_cost = outside_cost;
1620 min->peel_info.dr_info = elem->dr_info;
1621 min->peel_info.npeel = elem->npeel;
1622 min->peel_info.count = elem->count;
1623 }
1624
1625 return 1;
1626}
1627
1628
1629/* Choose best peeling option by traversing peeling hash table and either
1630 choosing an option with the lowest cost (if cost model is enabled) or the
1631 option that aligns as many accesses as possible. */
1632
1633static struct _vect_peel_extended_info
1634vect_peeling_hash_choose_best_peeling (hash_table<peel_info_hasher> *peeling_htab,
1635 loop_vec_info loop_vinfo)
1636{
1637 struct _vect_peel_extended_info res;
1638
1639 res.peel_info.dr_info = NULLnullptr;
1640 res.vinfo = loop_vinfo;
1641
1642 if (!unlimited_cost_model (LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop))
1643 {
1644 res.inside_cost = INT_MAX2147483647;
1645 res.outside_cost = INT_MAX2147483647;
1646 peeling_htab->traverse <_vect_peel_extended_info *,
1647 vect_peeling_hash_get_lowest_cost> (&res);
1648 }
1649 else
1650 {
1651 res.peel_info.count = 0;
1652 peeling_htab->traverse <_vect_peel_extended_info *,
1653 vect_peeling_hash_get_most_frequent> (&res);
1654 res.inside_cost = 0;
1655 res.outside_cost = 0;
1656 }
1657
1658 return res;
1659}
1660
1661/* Return true if the new peeling NPEEL is supported. */
1662
1663static bool
1664vect_peeling_supportable (loop_vec_info loop_vinfo, dr_vec_info *dr0_info,
1665 unsigned npeel)
1666{
1667 vec<data_reference_p> datarefs = LOOP_VINFO_DATAREFS (loop_vinfo)(loop_vinfo)->shared->datarefs;
1668 enum dr_alignment_support supportable_dr_alignment;
1669
1670 bool dr0_alignment_known_p
1671 = known_alignment_for_access_p (dr0_info,
1672 STMT_VINFO_VECTYPE (dr0_info->stmt)(dr0_info->stmt)->vectype);
1673
1674 /* Ensure that all data refs can be vectorized after the peel. */
1675 for (data_reference *dr : datarefs)
1676 {
1677 if (dr == dr0_info->dr)
1678 continue;
1679
1680 dr_vec_info *dr_info = loop_vinfo->lookup_dr (dr);
1681 if (!vect_relevant_for_alignment_p (dr_info)
1682 || vect_dr_aligned_if_peeled_dr_is (dr_info, dr0_info))
1683 continue;
1684
1685 tree vectype = STMT_VINFO_VECTYPE (dr_info->stmt)(dr_info->stmt)->vectype;
1686 int misalignment;
1687 unsigned HOST_WIDE_INTlong alignment;
1688 if (!dr0_alignment_known_p
1689 || !known_alignment_for_access_p (dr_info, vectype)
1690 || !DR_TARGET_ALIGNMENT (dr_info)dr_target_alignment (dr_info).is_constant (&alignment))
1691 misalignment = DR_MISALIGNMENT_UNKNOWN(-1);
1692 else
1693 {
1694 misalignment = dr_misalignment (dr_info, vectype);
1695 misalignment += npeel * TREE_INT_CST_LOW (DR_STEP (dr_info->dr))((unsigned long) (*tree_int_cst_elt_check (((dr_info->dr)->
innermost.step), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1695, __FUNCTION__)))
;
1696 misalignment &= alignment - 1;
1697 }
1698 supportable_dr_alignment
1699 = vect_supportable_dr_alignment (loop_vinfo, dr_info, vectype,
1700 misalignment);
1701 if (supportable_dr_alignment == dr_unaligned_unsupported)
1702 return false;
1703 }
1704
1705 return true;
1706}
1707
1708/* Compare two data-references DRA and DRB to group them into chunks
1709 with related alignment. */
1710
1711static int
1712dr_align_group_sort_cmp (const void *dra_, const void *drb_)
1713{
1714 data_reference_p dra = *(data_reference_p *)const_cast<void *>(dra_);
1715 data_reference_p drb = *(data_reference_p *)const_cast<void *>(drb_);
1716 int cmp;
1717
1718 /* Stabilize sort. */
1719 if (dra == drb)
1720 return 0;
1721
1722 /* Ordering of DRs according to base. */
1723 cmp = data_ref_compare_tree (DR_BASE_ADDRESS (dra)(dra)->innermost.base_address,
1724 DR_BASE_ADDRESS (drb)(drb)->innermost.base_address);
1725 if (cmp != 0)
1726 return cmp;
1727
1728 /* And according to DR_OFFSET. */
1729 cmp = data_ref_compare_tree (DR_OFFSET (dra)(dra)->innermost.offset, DR_OFFSET (drb)(drb)->innermost.offset);
1730 if (cmp != 0)
1731 return cmp;
1732
1733 /* And after step. */
1734 cmp = data_ref_compare_tree (DR_STEP (dra)(dra)->innermost.step, DR_STEP (drb)(drb)->innermost.step);
1735 if (cmp != 0)
1736 return cmp;
1737
1738 /* Then sort after DR_INIT. In case of identical DRs sort after stmt UID. */
1739 cmp = data_ref_compare_tree (DR_INIT (dra)(dra)->innermost.init, DR_INIT (drb)(drb)->innermost.init);
1740 if (cmp == 0)
1741 return gimple_uid (DR_STMT (dra)(dra)->stmt) < gimple_uid (DR_STMT (drb)(drb)->stmt) ? -1 : 1;
1742 return cmp;
1743}
1744
1745/* Function vect_enhance_data_refs_alignment
1746
1747 This pass will use loop versioning and loop peeling in order to enhance
1748 the alignment of data references in the loop.
1749
1750 FOR NOW: we assume that whatever versioning/peeling takes place, only the
1751 original loop is to be vectorized. Any other loops that are created by
1752 the transformations performed in this pass - are not supposed to be
1753 vectorized. This restriction will be relaxed.
1754
1755 This pass will require a cost model to guide it whether to apply peeling
1756 or versioning or a combination of the two. For example, the scheme that
1757 intel uses when given a loop with several memory accesses, is as follows:
1758 choose one memory access ('p') which alignment you want to force by doing
1759 peeling. Then, either (1) generate a loop in which 'p' is aligned and all
1760 other accesses are not necessarily aligned, or (2) use loop versioning to
1761 generate one loop in which all accesses are aligned, and another loop in
1762 which only 'p' is necessarily aligned.
1763
1764 ("Automatic Intra-Register Vectorization for the Intel Architecture",
1765 Aart J.C. Bik, Milind Girkar, Paul M. Grey and Ximmin Tian, International
1766 Journal of Parallel Programming, Vol. 30, No. 2, April 2002.)
1767
1768 Devising a cost model is the most critical aspect of this work. It will
1769 guide us on which access to peel for, whether to use loop versioning, how
1770 many versions to create, etc. The cost model will probably consist of
1771 generic considerations as well as target specific considerations (on
1772 powerpc for example, misaligned stores are more painful than misaligned
1773 loads).
1774
1775 Here are the general steps involved in alignment enhancements:
1776
1777 -- original loop, before alignment analysis:
1778 for (i=0; i<N; i++){
1779 x = q[i]; # DR_MISALIGNMENT(q) = unknown
1780 p[i] = y; # DR_MISALIGNMENT(p) = unknown
1781 }
1782
1783 -- After vect_compute_data_refs_alignment:
1784 for (i=0; i<N; i++){
1785 x = q[i]; # DR_MISALIGNMENT(q) = 3
1786 p[i] = y; # DR_MISALIGNMENT(p) = unknown
1787 }
1788
1789 -- Possibility 1: we do loop versioning:
1790 if (p is aligned) {
1791 for (i=0; i<N; i++){ # loop 1A
1792 x = q[i]; # DR_MISALIGNMENT(q) = 3
1793 p[i] = y; # DR_MISALIGNMENT(p) = 0
1794 }
1795 }
1796 else {
1797 for (i=0; i<N; i++){ # loop 1B
1798 x = q[i]; # DR_MISALIGNMENT(q) = 3
1799 p[i] = y; # DR_MISALIGNMENT(p) = unaligned
1800 }
1801 }
1802
1803 -- Possibility 2: we do loop peeling:
1804 for (i = 0; i < 3; i++){ # (scalar loop, not to be vectorized).
1805 x = q[i];
1806 p[i] = y;
1807 }
1808 for (i = 3; i < N; i++){ # loop 2A
1809 x = q[i]; # DR_MISALIGNMENT(q) = 0
1810 p[i] = y; # DR_MISALIGNMENT(p) = unknown
1811 }
1812
1813 -- Possibility 3: combination of loop peeling and versioning:
1814 for (i = 0; i < 3; i++){ # (scalar loop, not to be vectorized).
1815 x = q[i];
1816 p[i] = y;
1817 }
1818 if (p is aligned) {
1819 for (i = 3; i<N; i++){ # loop 3A
1820 x = q[i]; # DR_MISALIGNMENT(q) = 0
1821 p[i] = y; # DR_MISALIGNMENT(p) = 0
1822 }
1823 }
1824 else {
1825 for (i = 3; i<N; i++){ # loop 3B
1826 x = q[i]; # DR_MISALIGNMENT(q) = 0
1827 p[i] = y; # DR_MISALIGNMENT(p) = unaligned
1828 }
1829 }
1830
1831 These loops are later passed to loop_transform to be vectorized. The
1832 vectorizer will use the alignment information to guide the transformation
1833 (whether to generate regular loads/stores, or with special handling for
1834 misalignment). */
1835
1836opt_result
1837vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
1838{
1839 class loop *loop = LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop;
1840 dr_vec_info *first_store = NULLnullptr;
1841 dr_vec_info *dr0_info = NULLnullptr;
1842 struct data_reference *dr;
1843 unsigned int i;
1844 bool do_peeling = false;
1845 bool do_versioning = false;
1846 unsigned int npeel = 0;
1847 bool one_misalignment_known = false;
1848 bool one_misalignment_unknown = false;
1849 bool one_dr_unsupportable = false;
1850 dr_vec_info *unsupportable_dr_info = NULLnullptr;
1851 unsigned int dr0_same_align_drs = 0, first_store_same_align_drs = 0;
1852 hash_table<peel_info_hasher> peeling_htab (1);
1853
1854 DUMP_VECT_SCOPE ("vect_enhance_data_refs_alignment")auto_dump_scope scope ("vect_enhance_data_refs_alignment", vect_location
)
;
1855
1856 /* Reset data so we can safely be called multiple times. */
1857 LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo)(loop_vinfo)->may_misalign_stmts.truncate (0);
1858 LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo)(loop_vinfo)->peeling_for_alignment = 0;
1859
1860 if (LOOP_VINFO_DATAREFS (loop_vinfo)(loop_vinfo)->shared->datarefs.is_empty ())
1861 return opt_result::success ();
1862
1863 /* Sort the vector of datarefs so DRs that have the same or dependent
1864 alignment are next to each other. */
1865 auto_vec<data_reference_p> datarefs
1866 = LOOP_VINFO_DATAREFS (loop_vinfo)(loop_vinfo)->shared->datarefs.copy ();
1867 datarefs.qsort (dr_align_group_sort_cmp)qsort (dr_align_group_sort_cmp);
1868
1869 /* Compute the number of DRs that become aligned when we peel
1870 a dataref so it becomes aligned. */
1871 auto_vec<unsigned> n_same_align_refs (datarefs.length ());
1872 n_same_align_refs.quick_grow_cleared (datarefs.length ());
1873 unsigned i0;
1874 for (i0 = 0; i0 < datarefs.length (); ++i0)
1875 if (DR_BASE_ADDRESS (datarefs[i0])(datarefs[i0])->innermost.base_address)
1876 break;
1877 for (i = i0 + 1; i <= datarefs.length (); ++i)
1878 {
1879 if (i == datarefs.length ()
1880 || !operand_equal_p (DR_BASE_ADDRESS (datarefs[i0])(datarefs[i0])->innermost.base_address,
1881 DR_BASE_ADDRESS (datarefs[i])(datarefs[i])->innermost.base_address, 0)
1882 || !operand_equal_p (DR_OFFSET (datarefs[i0])(datarefs[i0])->innermost.offset,
1883 DR_OFFSET (datarefs[i])(datarefs[i])->innermost.offset, 0)
1884 || !operand_equal_p (DR_STEP (datarefs[i0])(datarefs[i0])->innermost.step,
1885 DR_STEP (datarefs[i])(datarefs[i])->innermost.step, 0))
1886 {
1887 /* The subgroup [i0, i-1] now only differs in DR_INIT and
1888 possibly DR_TARGET_ALIGNMENT. Still the whole subgroup
1889 will get known misalignment if we align one of the refs
1890 with the largest DR_TARGET_ALIGNMENT. */
1891 for (unsigned j = i0; j < i; ++j)
1892 {
1893 dr_vec_info *dr_infoj = loop_vinfo->lookup_dr (datarefs[j]);
1894 for (unsigned k = i0; k < i; ++k)
1895 {
1896 if (k == j)
1897 continue;
1898 dr_vec_info *dr_infok = loop_vinfo->lookup_dr (datarefs[k]);
1899 if (vect_dr_aligned_if_related_peeled_dr_is (dr_infok,
1900 dr_infoj))
1901 n_same_align_refs[j]++;
1902 }
1903 }
1904 i0 = i;
1905 }
1906 }
1907
1908 /* While cost model enhancements are expected in the future, the high level
1909 view of the code at this time is as follows:
1910
1911 A) If there is a misaligned access then see if peeling to align
1912 this access can make all data references satisfy
1913 vect_supportable_dr_alignment. If so, update data structures
1914 as needed and return true.
1915
1916 B) If peeling wasn't possible and there is a data reference with an
1917 unknown misalignment that does not satisfy vect_supportable_dr_alignment
1918 then see if loop versioning checks can be used to make all data
1919 references satisfy vect_supportable_dr_alignment. If so, update
1920 data structures as needed and return true.
1921
1922 C) If neither peeling nor versioning were successful then return false if
1923 any data reference does not satisfy vect_supportable_dr_alignment.
1924
1925 D) Return true (all data references satisfy vect_supportable_dr_alignment).
1926
1927 Note, Possibility 3 above (which is peeling and versioning together) is not
1928 being done at this time. */
1929
1930 /* (1) Peeling to force alignment. */
1931
1932 /* (1.1) Decide whether to perform peeling, and how many iterations to peel:
1933 Considerations:
1934 + How many accesses will become aligned due to the peeling
1935 - How many accesses will become unaligned due to the peeling,
1936 and the cost of misaligned accesses.
1937 - The cost of peeling (the extra runtime checks, the increase
1938 in code size). */
1939
1940 FOR_EACH_VEC_ELT (datarefs, i, dr)for (i = 0; (datarefs).iterate ((i), &(dr)); ++(i))
1941 {
1942 dr_vec_info *dr_info = loop_vinfo->lookup_dr (dr);
1943 if (!vect_relevant_for_alignment_p (dr_info))
1944 continue;
1945
1946 stmt_vec_info stmt_info = dr_info->stmt;
1947 tree vectype = STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype;
1948 do_peeling = vector_alignment_reachable_p (dr_info);
1949 if (do_peeling)
1950 {
1951 if (known_alignment_for_access_p (dr_info, vectype))
1952 {
1953 unsigned int npeel_tmp = 0;
1954 bool negative = tree_int_cst_compare (DR_STEP (dr)(dr)->innermost.step,
1955 size_zero_nodeglobal_trees[TI_SIZE_ZERO]) < 0;
1956
1957 /* If known_alignment_for_access_p then we have set
1958 DR_MISALIGNMENT which is only done if we know it at compiler
1959 time, so it is safe to assume target alignment is constant.
1960 */
1961 unsigned int target_align =
1962 DR_TARGET_ALIGNMENT (dr_info)dr_target_alignment (dr_info).to_constant ();
1963 unsigned HOST_WIDE_INTlong dr_size = vect_get_scalar_dr_size (dr_info);
1964 poly_int64 off = 0;
1965 if (negative)
1966 off = (TYPE_VECTOR_SUBPARTS (vectype) - 1) * -dr_size;
1967 unsigned int mis = dr_misalignment (dr_info, vectype, off);
1968 mis = negative ? mis : -mis;
1969 if (mis != 0)
1970 npeel_tmp = (mis & (target_align - 1)) / dr_size;
1971
1972 /* For multiple types, it is possible that the bigger type access
1973 will have more than one peeling option. E.g., a loop with two
1974 types: one of size (vector size / 4), and the other one of
1975 size (vector size / 8). Vectorization factor will 8. If both
1976 accesses are misaligned by 3, the first one needs one scalar
1977 iteration to be aligned, and the second one needs 5. But the
1978 first one will be aligned also by peeling 5 scalar
1979 iterations, and in that case both accesses will be aligned.
1980 Hence, except for the immediate peeling amount, we also want
1981 to try to add full vector size, while we don't exceed
1982 vectorization factor.
1983 We do this automatically for cost model, since we calculate
1984 cost for every peeling option. */
1985 poly_uint64 nscalars = npeel_tmp;
1986 if (unlimited_cost_model (LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop))
1987 {
1988 poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo)(loop_vinfo)->vectorization_factor;
1989 nscalars = (STMT_SLP_TYPE (stmt_info)(stmt_info)->slp_type
1990 ? vf * DR_GROUP_SIZE (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 1990, __FUNCTION__), 0 : 0)), (stmt_info)->size)
: vf);
1991 }
1992
1993 /* Save info about DR in the hash table. Also include peeling
1994 amounts according to the explanation above. Indicate
1995 the alignment status when the ref is not aligned.
1996 ??? Rather than using unknown alignment here we should
1997 prune all entries from the peeling hashtable which cause
1998 DRs to be not supported. */
1999 bool supportable_if_not_aligned
2000 = vect_supportable_dr_alignment
2001 (loop_vinfo, dr_info, vectype, DR_MISALIGNMENT_UNKNOWN(-1));
2002 while (known_le (npeel_tmp, nscalars)(!maybe_lt (nscalars, npeel_tmp)))
2003 {
2004 vect_peeling_hash_insert (&peeling_htab, loop_vinfo,
2005 dr_info, npeel_tmp,
2006 supportable_if_not_aligned);
2007 npeel_tmp += MAX (1, target_align / dr_size)((1) > (target_align / dr_size) ? (1) : (target_align / dr_size
))
;
2008 }
2009
2010 one_misalignment_known = true;
2011 }
2012 else
2013 {
2014 /* If we don't know any misalignment values, we prefer
2015 peeling for data-ref that has the maximum number of data-refs
2016 with the same alignment, unless the target prefers to align
2017 stores over load. */
2018 unsigned same_align_drs = n_same_align_refs[i];
2019 if (!dr0_info
2020 || dr0_same_align_drs < same_align_drs)
2021 {
2022 dr0_same_align_drs = same_align_drs;
2023 dr0_info = dr_info;
2024 }
2025 /* For data-refs with the same number of related
2026 accesses prefer the one where the misalign
2027 computation will be invariant in the outermost loop. */
2028 else if (dr0_same_align_drs == same_align_drs)
2029 {
2030 class loop *ivloop0, *ivloop;
2031 ivloop0 = outermost_invariant_loop_for_expr
2032 (loop, DR_BASE_ADDRESS (dr0_info->dr)(dr0_info->dr)->innermost.base_address);
2033 ivloop = outermost_invariant_loop_for_expr
2034 (loop, DR_BASE_ADDRESS (dr)(dr)->innermost.base_address);
2035 if ((ivloop && !ivloop0)
2036 || (ivloop && ivloop0
2037 && flow_loop_nested_p (ivloop, ivloop0)))
2038 dr0_info = dr_info;
2039 }
2040
2041 one_misalignment_unknown = true;
2042
2043 /* Check for data refs with unsupportable alignment that
2044 can be peeled. */
2045 enum dr_alignment_support supportable_dr_alignment
2046 = vect_supportable_dr_alignment (loop_vinfo, dr_info, vectype,
2047 DR_MISALIGNMENT_UNKNOWN(-1));
2048 if (supportable_dr_alignment == dr_unaligned_unsupported)
2049 {
2050 one_dr_unsupportable = true;
2051 unsupportable_dr_info = dr_info;
2052 }
2053
2054 if (!first_store && DR_IS_WRITE (dr)(!(dr)->is_read))
2055 {
2056 first_store = dr_info;
2057 first_store_same_align_drs = same_align_drs;
2058 }
2059 }
2060 }
2061 else
2062 {
2063 if (!aligned_access_p (dr_info, vectype))
2064 {
2065 if (dump_enabled_p ())
2066 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2067 "vector alignment may not be reachable\n");
2068 break;
2069 }
2070 }
2071 }
2072
2073 /* Check if we can possibly peel the loop. */
2074 if (!vect_can_advance_ivs_p (loop_vinfo)
2075 || !slpeel_can_duplicate_loop_p (loop, single_exit (loop))
2076 || loop->inner)
2077 do_peeling = false;
2078
2079 struct _vect_peel_extended_info peel_for_known_alignment;
2080 struct _vect_peel_extended_info peel_for_unknown_alignment;
2081 struct _vect_peel_extended_info best_peel;
2082
2083 peel_for_unknown_alignment.inside_cost = INT_MAX2147483647;
2084 peel_for_unknown_alignment.outside_cost = INT_MAX2147483647;
2085 peel_for_unknown_alignment.peel_info.count = 0;
2086
2087 if (do_peeling
2088 && one_misalignment_unknown)
2089 {
2090 /* Check if the target requires to prefer stores over loads, i.e., if
2091 misaligned stores are more expensive than misaligned loads (taking
2092 drs with same alignment into account). */
2093 unsigned int load_inside_cost = 0;
2094 unsigned int load_outside_cost = 0;
2095 unsigned int store_inside_cost = 0;
2096 unsigned int store_outside_cost = 0;
2097 unsigned int estimated_npeels = vect_vf_for_cost (loop_vinfo) / 2;
2098
2099 stmt_vector_for_cost dummy;
2100 dummy.create (2);
2101 vect_get_peeling_costs_all_drs (loop_vinfo, dr0_info,
2102 &load_inside_cost,
2103 &load_outside_cost,
2104 &dummy, &dummy, estimated_npeels);
2105 dummy.release ();
2106
2107 if (first_store)
2108 {
2109 dummy.create (2);
2110 vect_get_peeling_costs_all_drs (loop_vinfo, first_store,
2111 &store_inside_cost,
2112 &store_outside_cost,
2113 &dummy, &dummy,
2114 estimated_npeels);
2115 dummy.release ();
2116 }
2117 else
2118 {
2119 store_inside_cost = INT_MAX2147483647;
2120 store_outside_cost = INT_MAX2147483647;
2121 }
2122
2123 if (load_inside_cost > store_inside_cost
2124 || (load_inside_cost == store_inside_cost
2125 && load_outside_cost > store_outside_cost))
2126 {
2127 dr0_info = first_store;
2128 dr0_same_align_drs = first_store_same_align_drs;
2129 peel_for_unknown_alignment.inside_cost = store_inside_cost;
2130 peel_for_unknown_alignment.outside_cost = store_outside_cost;
2131 }
2132 else
2133 {
2134 peel_for_unknown_alignment.inside_cost = load_inside_cost;
2135 peel_for_unknown_alignment.outside_cost = load_outside_cost;
2136 }
2137
2138 stmt_vector_for_cost prologue_cost_vec, epilogue_cost_vec;
2139 prologue_cost_vec.create (2);
2140 epilogue_cost_vec.create (2);
2141
2142 int dummy2;
2143 peel_for_unknown_alignment.outside_cost += vect_get_known_peeling_cost
2144 (loop_vinfo, estimated_npeels, &dummy2,
2145 &LOOP_VINFO_SCALAR_ITERATION_COST (loop_vinfo)(loop_vinfo)->scalar_cost_vec,
2146 &prologue_cost_vec, &epilogue_cost_vec);
2147
2148 prologue_cost_vec.release ();
2149 epilogue_cost_vec.release ();
2150
2151 peel_for_unknown_alignment.peel_info.count = dr0_same_align_drs + 1;
2152 }
2153
2154 peel_for_unknown_alignment.peel_info.npeel = 0;
2155 peel_for_unknown_alignment.peel_info.dr_info = dr0_info;
2156
2157 best_peel = peel_for_unknown_alignment;
2158
2159 peel_for_known_alignment.inside_cost = INT_MAX2147483647;
2160 peel_for_known_alignment.outside_cost = INT_MAX2147483647;
2161 peel_for_known_alignment.peel_info.count = 0;
2162 peel_for_known_alignment.peel_info.dr_info = NULLnullptr;
2163
2164 if (do_peeling && one_misalignment_known)
2165 {
2166 /* Peeling is possible, but there is no data access that is not supported
2167 unless aligned. So we try to choose the best possible peeling from
2168 the hash table. */
2169 peel_for_known_alignment = vect_peeling_hash_choose_best_peeling
2170 (&peeling_htab, loop_vinfo);
2171 }
2172
2173 /* Compare costs of peeling for known and unknown alignment. */
2174 if (peel_for_known_alignment.peel_info.dr_info != NULLnullptr
2175 && peel_for_unknown_alignment.inside_cost
2176 >= peel_for_known_alignment.inside_cost)
2177 {
2178 best_peel = peel_for_known_alignment;
2179
2180 /* If the best peeling for known alignment has NPEEL == 0, perform no
2181 peeling at all except if there is an unsupportable dr that we can
2182 align. */
2183 if (best_peel.peel_info.npeel == 0 && !one_dr_unsupportable)
2184 do_peeling = false;
2185 }
2186
2187 /* If there is an unsupportable data ref, prefer this over all choices so far
2188 since we'd have to discard a chosen peeling except when it accidentally
2189 aligned the unsupportable data ref. */
2190 if (one_dr_unsupportable)
2191 dr0_info = unsupportable_dr_info;
2192 else if (do_peeling)
2193 {
2194 /* Calculate the penalty for no peeling, i.e. leaving everything as-is.
2195 TODO: Use nopeel_outside_cost or get rid of it? */
2196 unsigned nopeel_inside_cost = 0;
2197 unsigned nopeel_outside_cost = 0;
2198
2199 stmt_vector_for_cost dummy;
2200 dummy.create (2);
2201 vect_get_peeling_costs_all_drs (loop_vinfo, NULLnullptr, &nopeel_inside_cost,
2202 &nopeel_outside_cost, &dummy, &dummy, 0);
2203 dummy.release ();
2204
2205 /* Add epilogue costs. As we do not peel for alignment here, no prologue
2206 costs will be recorded. */
2207 stmt_vector_for_cost prologue_cost_vec, epilogue_cost_vec;
2208 prologue_cost_vec.create (2);
2209 epilogue_cost_vec.create (2);
2210
2211 int dummy2;
2212 nopeel_outside_cost += vect_get_known_peeling_cost
2213 (loop_vinfo, 0, &dummy2,
2214 &LOOP_VINFO_SCALAR_ITERATION_COST (loop_vinfo)(loop_vinfo)->scalar_cost_vec,
2215 &prologue_cost_vec, &epilogue_cost_vec);
2216
2217 prologue_cost_vec.release ();
2218 epilogue_cost_vec.release ();
2219
2220 npeel = best_peel.peel_info.npeel;
2221 dr0_info = best_peel.peel_info.dr_info;
2222
2223 /* If no peeling is not more expensive than the best peeling we
2224 have so far, don't perform any peeling. */
2225 if (nopeel_inside_cost <= best_peel.inside_cost)
2226 do_peeling = false;
2227 }
2228
2229 if (do_peeling)
2230 {
2231 stmt_vec_info stmt_info = dr0_info->stmt;
2232 if (known_alignment_for_access_p (dr0_info,
2233 STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype))
2234 {
2235 bool negative = tree_int_cst_compare (DR_STEP (dr0_info->dr)(dr0_info->dr)->innermost.step,
2236 size_zero_nodeglobal_trees[TI_SIZE_ZERO]) < 0;
2237 if (!npeel)
2238 {
2239 /* Since it's known at compile time, compute the number of
2240 iterations in the peeled loop (the peeling factor) for use in
2241 updating DR_MISALIGNMENT values. The peeling factor is the
2242 vectorization factor minus the misalignment as an element
2243 count. */
2244 tree vectype = STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype;
2245 poly_int64 off = 0;
2246 if (negative)
2247 off = ((TYPE_VECTOR_SUBPARTS (vectype) - 1)
2248 * -TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype)))((unsigned long) (*tree_int_cst_elt_check ((((tree_class_check
((((contains_struct_check ((vectype), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2248, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2248, __FUNCTION__))->type_common.size_unit)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2248, __FUNCTION__)))
);
2249 unsigned int mis
2250 = dr_misalignment (dr0_info, vectype, off);
2251 mis = negative ? mis : -mis;
2252 /* If known_alignment_for_access_p then we have set
2253 DR_MISALIGNMENT which is only done if we know it at compiler
2254 time, so it is safe to assume target alignment is constant.
2255 */
2256 unsigned int target_align =
2257 DR_TARGET_ALIGNMENT (dr0_info)dr_target_alignment (dr0_info).to_constant ();
2258 npeel = ((mis & (target_align - 1))
2259 / vect_get_scalar_dr_size (dr0_info));
2260 }
2261
2262 /* For interleaved data access every iteration accesses all the
2263 members of the group, therefore we divide the number of iterations
2264 by the group size. */
2265 if (STMT_VINFO_GROUPED_ACCESS (stmt_info)((stmt_info)->dr_aux.dr && (((void)(!((stmt_info)->
dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2265, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
))
)
2266 npeel /= DR_GROUP_SIZE (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2266, __FUNCTION__), 0 : 0)), (stmt_info)->size)
;
2267
2268 if (dump_enabled_p ())
2269 dump_printf_loc (MSG_NOTE, vect_location,
2270 "Try peeling by %d\n", npeel);
2271 }
2272
2273 /* Ensure that all datarefs can be vectorized after the peel. */
2274 if (!vect_peeling_supportable (loop_vinfo, dr0_info, npeel))
2275 do_peeling = false;
2276
2277 /* Check if all datarefs are supportable and log. */
2278 if (do_peeling
2279 && npeel == 0
2280 && known_alignment_for_access_p (dr0_info,
2281 STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype))
2282 return opt_result::success ();
2283
2284 /* Cost model #1 - honor --param vect-max-peeling-for-alignment. */
2285 if (do_peeling)
2286 {
2287 unsigned max_allowed_peel
2288 = param_vect_max_peeling_for_alignmentglobal_options.x_param_vect_max_peeling_for_alignment;
2289 if (loop_cost_model (loop) <= VECT_COST_MODEL_CHEAP)
2290 max_allowed_peel = 0;
2291 if (max_allowed_peel != (unsigned)-1)
2292 {
2293 unsigned max_peel = npeel;
2294 if (max_peel == 0)
2295 {
2296 poly_uint64 target_align = DR_TARGET_ALIGNMENT (dr0_info)dr_target_alignment (dr0_info);
2297 unsigned HOST_WIDE_INTlong target_align_c;
2298 if (target_align.is_constant (&target_align_c))
2299 max_peel =
2300 target_align_c / vect_get_scalar_dr_size (dr0_info) - 1;
2301 else
2302 {
2303 do_peeling = false;
2304 if (dump_enabled_p ())
2305 dump_printf_loc (MSG_NOTE, vect_location,
2306 "Disable peeling, max peels set and vector"
2307 " alignment unknown\n");
2308 }
2309 }
2310 if (max_peel > max_allowed_peel)
2311 {
2312 do_peeling = false;
2313 if (dump_enabled_p ())
2314 dump_printf_loc (MSG_NOTE, vect_location,
2315 "Disable peeling, max peels reached: %d\n", max_peel);
2316 }
2317 }
2318 }
2319
2320 /* Cost model #2 - if peeling may result in a remaining loop not
2321 iterating enough to be vectorized then do not peel. Since this
2322 is a cost heuristic rather than a correctness decision, use the
2323 most likely runtime value for variable vectorization factors. */
2324 if (do_peeling
2325 && LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)(tree_fits_shwi_p ((loop_vinfo)->num_iters) && tree_to_shwi
((loop_vinfo)->num_iters) > 0)
)
2326 {
2327 unsigned int assumed_vf = vect_vf_for_cost (loop_vinfo);
2328 unsigned int max_peel = npeel == 0 ? assumed_vf - 1 : npeel;
2329 if ((unsigned HOST_WIDE_INTlong) LOOP_VINFO_INT_NITERS (loop_vinfo)(((unsigned long) (*tree_int_cst_elt_check (((loop_vinfo)->
num_iters), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2329, __FUNCTION__))))
2330 < assumed_vf + max_peel)
2331 do_peeling = false;
2332 }
2333
2334 if (do_peeling)
2335 {
2336 /* (1.2) Update the DR_MISALIGNMENT of each data reference DR_i.
2337 If the misalignment of DR_i is identical to that of dr0 then set
2338 DR_MISALIGNMENT (DR_i) to zero. If the misalignment of DR_i and
2339 dr0 are known at compile time then increment DR_MISALIGNMENT (DR_i)
2340 by the peeling factor times the element size of DR_i (MOD the
2341 vectorization factor times the size). Otherwise, the
2342 misalignment of DR_i must be set to unknown. */
2343 FOR_EACH_VEC_ELT (datarefs, i, dr)for (i = 0; (datarefs).iterate ((i), &(dr)); ++(i))
2344 if (dr != dr0_info->dr)
2345 {
2346 dr_vec_info *dr_info = loop_vinfo->lookup_dr (dr);
2347 if (!vect_relevant_for_alignment_p (dr_info))
2348 continue;
2349
2350 vect_update_misalignment_for_peel (dr_info, dr0_info, npeel);
2351 }
2352
2353 LOOP_VINFO_UNALIGNED_DR (loop_vinfo)(loop_vinfo)->unaligned_dr = dr0_info;
2354 if (npeel)
2355 LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo)(loop_vinfo)->peeling_for_alignment = npeel;
2356 else
2357 LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo)(loop_vinfo)->peeling_for_alignment = -1;
2358 SET_DR_MISALIGNMENT (dr0_info,set_dr_misalignment (dr0_info, vect_dr_misalign_for_aligned_access
(dr0_info))
2359 vect_dr_misalign_for_aligned_access (dr0_info))set_dr_misalignment (dr0_info, vect_dr_misalign_for_aligned_access
(dr0_info))
;
2360 if (dump_enabled_p ())
2361 {
2362 dump_printf_loc (MSG_NOTE, vect_location,
2363 "Alignment of access forced using peeling.\n");
2364 dump_printf_loc (MSG_NOTE, vect_location,
2365 "Peeling for alignment will be applied.\n");
2366 }
2367
2368 /* The inside-loop cost will be accounted for in vectorizable_load
2369 and vectorizable_store correctly with adjusted alignments.
2370 Drop the body_cst_vec on the floor here. */
2371 return opt_result::success ();
2372 }
2373 }
2374
2375 /* (2) Versioning to force alignment. */
2376
2377 /* Try versioning if:
2378 1) optimize loop for speed and the cost-model is not cheap
2379 2) there is at least one unsupported misaligned data ref with an unknown
2380 misalignment, and
2381 3) all misaligned data refs with a known misalignment are supported, and
2382 4) the number of runtime alignment checks is within reason. */
2383
2384 do_versioning
2385 = (optimize_loop_nest_for_speed_p (loop)
2386 && !loop->inner /* FORNOW */
2387 && loop_cost_model (loop) > VECT_COST_MODEL_CHEAP);
2388
2389 if (do_versioning)
2390 {
2391 FOR_EACH_VEC_ELT (datarefs, i, dr)for (i = 0; (datarefs).iterate ((i), &(dr)); ++(i))
2392 {
2393 dr_vec_info *dr_info = loop_vinfo->lookup_dr (dr);
2394 if (!vect_relevant_for_alignment_p (dr_info))
2395 continue;
2396
2397 stmt_vec_info stmt_info = dr_info->stmt;
2398 if (STMT_VINFO_STRIDED_P (stmt_info)(stmt_info)->strided_p)
2399 {
2400 do_versioning = false;
2401 break;
2402 }
2403
2404 tree vectype = STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype;
2405 bool negative = tree_int_cst_compare (DR_STEP (dr)(dr)->innermost.step,
2406 size_zero_nodeglobal_trees[TI_SIZE_ZERO]) < 0;
2407 poly_int64 off = 0;
2408 if (negative)
2409 off = ((TYPE_VECTOR_SUBPARTS (vectype) - 1)
2410 * -TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype)))((unsigned long) (*tree_int_cst_elt_check ((((tree_class_check
((((contains_struct_check ((vectype), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2410, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2410, __FUNCTION__))->type_common.size_unit)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2410, __FUNCTION__)))
);
2411 int misalignment;
2412 if ((misalignment = dr_misalignment (dr_info, vectype, off)) == 0)
2413 continue;
2414
2415 enum dr_alignment_support supportable_dr_alignment
2416 = vect_supportable_dr_alignment (loop_vinfo, dr_info, vectype,
2417 misalignment);
2418 if (supportable_dr_alignment == dr_unaligned_unsupported)
2419 {
2420 if (misalignment != DR_MISALIGNMENT_UNKNOWN(-1)
2421 || (LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo)(loop_vinfo)->may_misalign_stmts.length ()
2422 >= (unsigned) param_vect_max_version_for_alignment_checksglobal_options.x_param_vect_max_version_for_alignment_checks))
2423 {
2424 do_versioning = false;
2425 break;
2426 }
2427
2428 /* At present we don't support versioning for alignment
2429 with variable VF, since there's no guarantee that the
2430 VF is a power of two. We could relax this if we added
2431 a way of enforcing a power-of-two size. */
2432 unsigned HOST_WIDE_INTlong size;
2433 if (!GET_MODE_SIZE (TYPE_MODE (vectype)((((enum tree_code) ((tree_class_check ((vectype), (tcc_type)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2433, __FUNCTION__)))->base.code) == VECTOR_TYPE) ? vector_type_mode
(vectype) : (vectype)->type_common.mode)
).is_constant (&size))
2434 {
2435 do_versioning = false;
2436 break;
2437 }
2438
2439 /* Forcing alignment in the first iteration is no good if
2440 we don't keep it across iterations. For now, just disable
2441 versioning in this case.
2442 ?? We could actually unroll the loop to achieve the required
2443 overall step alignment, and forcing the alignment could be
2444 done by doing some iterations of the non-vectorized loop. */
2445 if (!multiple_p (LOOP_VINFO_VECT_FACTOR (loop_vinfo)(loop_vinfo)->vectorization_factor
2446 * DR_STEP_ALIGNMENT (dr)(dr)->innermost.step_alignment,
2447 DR_TARGET_ALIGNMENT (dr_info)dr_target_alignment (dr_info)))
2448 {
2449 do_versioning = false;
2450 break;
2451 }
2452
2453 /* The rightmost bits of an aligned address must be zeros.
2454 Construct the mask needed for this test. For example,
2455 GET_MODE_SIZE for the vector mode V4SI is 16 bytes so the
2456 mask must be 15 = 0xf. */
2457 int mask = size - 1;
2458
2459 /* FORNOW: use the same mask to test all potentially unaligned
2460 references in the loop. */
2461 if (LOOP_VINFO_PTR_MASK (loop_vinfo)(loop_vinfo)->ptr_mask
2462 && LOOP_VINFO_PTR_MASK (loop_vinfo)(loop_vinfo)->ptr_mask != mask)
2463 {
2464 do_versioning = false;
2465 break;
2466 }
2467
2468 LOOP_VINFO_PTR_MASK (loop_vinfo)(loop_vinfo)->ptr_mask = mask;
2469 LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo)(loop_vinfo)->may_misalign_stmts.safe_push (stmt_info);
2470 }
2471 }
2472
2473 /* Versioning requires at least one misaligned data reference. */
2474 if (!LOOP_REQUIRES_VERSIONING_FOR_ALIGNMENT (loop_vinfo)((loop_vinfo)->may_misalign_stmts.length () > 0))
2475 do_versioning = false;
2476 else if (!do_versioning)
2477 LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo)(loop_vinfo)->may_misalign_stmts.truncate (0);
2478 }
2479
2480 if (do_versioning)
2481 {
2482 const vec<stmt_vec_info> &may_misalign_stmts
2483 = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo)(loop_vinfo)->may_misalign_stmts;
2484 stmt_vec_info stmt_info;
2485
2486 /* It can now be assumed that the data references in the statements
2487 in LOOP_VINFO_MAY_MISALIGN_STMTS will be aligned in the version
2488 of the loop being vectorized. */
2489 FOR_EACH_VEC_ELT (may_misalign_stmts, i, stmt_info)for (i = 0; (may_misalign_stmts).iterate ((i), &(stmt_info
)); ++(i))
2490 {
2491 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info)(((void)(!((stmt_info)->dr_aux.stmt == (stmt_info)) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2491, __FUNCTION__), 0 : 0)), &(stmt_info)->dr_aux)
;
2492 SET_DR_MISALIGNMENT (dr_info,set_dr_misalignment (dr_info, vect_dr_misalign_for_aligned_access
(dr_info))
2493 vect_dr_misalign_for_aligned_access (dr_info))set_dr_misalignment (dr_info, vect_dr_misalign_for_aligned_access
(dr_info))
;
2494 if (dump_enabled_p ())
2495 dump_printf_loc (MSG_NOTE, vect_location,
2496 "Alignment of access forced using versioning.\n");
2497 }
2498
2499 if (dump_enabled_p ())
2500 dump_printf_loc (MSG_NOTE, vect_location,
2501 "Versioning for alignment will be applied.\n");
2502
2503 /* Peeling and versioning can't be done together at this time. */
2504 gcc_assert (! (do_peeling && do_versioning))((void)(!(! (do_peeling && do_versioning)) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2504, __FUNCTION__), 0 : 0))
;
2505
2506 return opt_result::success ();
2507 }
2508
2509 /* This point is reached if neither peeling nor versioning is being done. */
2510 gcc_assert (! (do_peeling || do_versioning))((void)(!(! (do_peeling || do_versioning)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2510, __FUNCTION__), 0 : 0))
;
2511
2512 return opt_result::success ();
2513}
2514
2515
2516/* Function vect_analyze_data_refs_alignment
2517
2518 Analyze the alignment of the data-references in the loop.
2519 Return FALSE if a data reference is found that cannot be vectorized. */
2520
2521opt_result
2522vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo)
2523{
2524 DUMP_VECT_SCOPE ("vect_analyze_data_refs_alignment")auto_dump_scope scope ("vect_analyze_data_refs_alignment", vect_location
)
;
2525
2526 vec<data_reference_p> datarefs = LOOP_VINFO_DATAREFS (loop_vinfo)(loop_vinfo)->shared->datarefs;
2527 struct data_reference *dr;
2528 unsigned int i;
2529
2530 vect_record_base_alignments (loop_vinfo);
2531 FOR_EACH_VEC_ELT (datarefs, i, dr)for (i = 0; (datarefs).iterate ((i), &(dr)); ++(i))
2532 {
2533 dr_vec_info *dr_info = loop_vinfo->lookup_dr (dr);
2534 if (STMT_VINFO_VECTORIZABLE (dr_info->stmt)(dr_info->stmt)->vectorizable)
2535 {
2536 if (STMT_VINFO_GROUPED_ACCESS (dr_info->stmt)((dr_info->stmt)->dr_aux.dr && (((void)(!((dr_info
->stmt)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2536, __FUNCTION__), 0 : 0)), (dr_info->stmt)->first_element
))
2537 && DR_GROUP_FIRST_ELEMENT (dr_info->stmt)(((void)(!((dr_info->stmt)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2537, __FUNCTION__), 0 : 0)), (dr_info->stmt)->first_element
)
!= dr_info->stmt)
2538 continue;
2539 vect_compute_data_ref_alignment (loop_vinfo, dr_info,
2540 STMT_VINFO_VECTYPE (dr_info->stmt)(dr_info->stmt)->vectype);
2541 }
2542 }
2543
2544 return opt_result::success ();
2545}
2546
2547
2548/* Analyze alignment of DRs of stmts in NODE. */
2549
2550static bool
2551vect_slp_analyze_node_alignment (vec_info *vinfo, slp_tree node)
2552{
2553 /* Alignment is maintained in the first element of the group. */
2554 stmt_vec_info first_stmt_info = SLP_TREE_SCALAR_STMTS (node)(node)->stmts[0];
2555 first_stmt_info = DR_GROUP_FIRST_ELEMENT (first_stmt_info)(((void)(!((first_stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2555, __FUNCTION__), 0 : 0)), (first_stmt_info)->first_element
)
;
2556 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (first_stmt_info)(((void)(!((first_stmt_info)->dr_aux.stmt == (first_stmt_info
)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2556, __FUNCTION__), 0 : 0)), &(first_stmt_info)->dr_aux
)
;
2557 tree vectype = SLP_TREE_VECTYPE (node)(node)->vectype;
2558 poly_uint64 vector_alignment
2559 = exact_div (targetm.vectorize.preferred_vector_alignment (vectype),
2560 BITS_PER_UNIT(8));
2561 if (dr_info->misalignment == DR_MISALIGNMENT_UNINITIALIZED(-2))
2562 vect_compute_data_ref_alignment (vinfo, dr_info, SLP_TREE_VECTYPE (node)(node)->vectype);
2563 /* Re-analyze alignment when we're facing a vectorization with a bigger
2564 alignment requirement. */
2565 else if (known_lt (dr_info->target_alignment, vector_alignment)(!maybe_le (vector_alignment, dr_info->target_alignment)))
2566 {
2567 poly_uint64 old_target_alignment = dr_info->target_alignment;
2568 int old_misalignment = dr_info->misalignment;
2569 vect_compute_data_ref_alignment (vinfo, dr_info, SLP_TREE_VECTYPE (node)(node)->vectype);
2570 /* But keep knowledge about a smaller alignment. */
2571 if (old_misalignment != DR_MISALIGNMENT_UNKNOWN(-1)
2572 && dr_info->misalignment == DR_MISALIGNMENT_UNKNOWN(-1))
2573 {
2574 dr_info->target_alignment = old_target_alignment;
2575 dr_info->misalignment = old_misalignment;
2576 }
2577 }
2578 /* When we ever face unordered target alignments the first one wins in terms
2579 of analyzing and the other will become unknown in dr_misalignment. */
2580 return true;
2581}
2582
2583/* Function vect_slp_analyze_instance_alignment
2584
2585 Analyze the alignment of the data-references in the SLP instance.
2586 Return FALSE if a data reference is found that cannot be vectorized. */
2587
2588bool
2589vect_slp_analyze_instance_alignment (vec_info *vinfo,
2590 slp_instance instance)
2591{
2592 DUMP_VECT_SCOPE ("vect_slp_analyze_instance_alignment")auto_dump_scope scope ("vect_slp_analyze_instance_alignment",
vect_location)
;
2593
2594 slp_tree node;
2595 unsigned i;
2596 FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (instance), i, node)for (i = 0; ((instance)->loads).iterate ((i), &(node))
; ++(i))
2597 if (! vect_slp_analyze_node_alignment (vinfo, node))
2598 return false;
2599
2600 if (SLP_INSTANCE_KIND (instance)(instance)->kind == slp_inst_kind_store
2601 && ! vect_slp_analyze_node_alignment
2602 (vinfo, SLP_INSTANCE_TREE (instance)(instance)->root))
2603 return false;
2604
2605 return true;
2606}
2607
2608
2609/* Analyze groups of accesses: check that DR_INFO belongs to a group of
2610 accesses of legal size, step, etc. Detect gaps, single element
2611 interleaving, and other special cases. Set grouped access info.
2612 Collect groups of strided stores for further use in SLP analysis.
2613 Worker for vect_analyze_group_access. */
2614
2615static bool
2616vect_analyze_group_access_1 (vec_info *vinfo, dr_vec_info *dr_info)
2617{
2618 data_reference *dr = dr_info->dr;
2619 tree step = DR_STEP (dr)(dr)->innermost.step;
2620 tree scalar_type = TREE_TYPE (DR_REF (dr))((contains_struct_check (((dr)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2620, __FUNCTION__))->typed.type)
;
2621 HOST_WIDE_INTlong type_size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (scalar_type))((unsigned long) (*tree_int_cst_elt_check ((((tree_class_check
((scalar_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2621, __FUNCTION__))->type_common.size_unit)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2621, __FUNCTION__)))
;
2622 stmt_vec_info stmt_info = dr_info->stmt;
2623 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
2624 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
2625 HOST_WIDE_INTlong dr_step = -1;
2626 HOST_WIDE_INTlong groupsize, last_accessed_element = 1;
2627 bool slp_impossible = false;
2628
2629 /* For interleaving, GROUPSIZE is STEP counted in elements, i.e., the
2630 size of the interleaving group (including gaps). */
2631 if (tree_fits_shwi_p (step))
2632 {
2633 dr_step = tree_to_shwi (step);
2634 /* Check that STEP is a multiple of type size. Otherwise there is
2635 a non-element-sized gap at the end of the group which we
2636 cannot represent in DR_GROUP_GAP or DR_GROUP_SIZE.
2637 ??? As we can handle non-constant step fine here we should
2638 simply remove uses of DR_GROUP_GAP between the last and first
2639 element and instead rely on DR_STEP. DR_GROUP_SIZE then would
2640 simply not include that gap. */
2641 if ((dr_step % type_size) != 0)
2642 {
2643 if (dump_enabled_p ())
2644 dump_printf_loc (MSG_NOTE, vect_location,
2645 "Step %T is not a multiple of the element size"
2646 " for %T\n",
2647 step, DR_REF (dr)(dr)->ref);
2648 return false;
2649 }
2650 groupsize = absu_hwi (dr_step) / type_size;
2651 }
2652 else
2653 groupsize = 0;
2654
2655 /* Not consecutive access is possible only if it is a part of interleaving. */
2656 if (!DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2656, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
)
2657 {
2658 /* Check if it this DR is a part of interleaving, and is a single
2659 element of the group that is accessed in the loop. */
2660
2661 /* Gaps are supported only for loads. STEP must be a multiple of the type
2662 size. */
2663 if (DR_IS_READ (dr)(dr)->is_read
2664 && (dr_step % type_size) == 0
2665 && groupsize > 0
2666 /* This could be UINT_MAX but as we are generating code in a very
2667 inefficient way we have to cap earlier.
2668 See PR91403 for example. */
2669 && groupsize <= 4096)
2670 {
2671 DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2671, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
= stmt_info;
2672 DR_GROUP_SIZE (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2672, __FUNCTION__), 0 : 0)), (stmt_info)->size)
= groupsize;
2673 DR_GROUP_GAP (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2673, __FUNCTION__), 0 : 0)), (stmt_info)->gap)
= groupsize - 1;
2674 if (dump_enabled_p ())
2675 dump_printf_loc (MSG_NOTE, vect_location,
2676 "Detected single element interleaving %T"
2677 " step %T\n",
2678 DR_REF (dr)(dr)->ref, step);
2679
2680 return true;
2681 }
2682
2683 if (dump_enabled_p ())
2684 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2685 "not consecutive access %G", stmt_info->stmt);
2686
2687 if (bb_vinfo)
2688 {
2689 /* Mark the statement as unvectorizable. */
2690 STMT_VINFO_VECTORIZABLE (stmt_info)(stmt_info)->vectorizable = false;
2691 return true;
2692 }
2693
2694 if (dump_enabled_p ())
2695 dump_printf_loc (MSG_NOTE, vect_location, "using strided accesses\n");
2696 STMT_VINFO_STRIDED_P (stmt_info)(stmt_info)->strided_p = true;
2697 return true;
2698 }
2699
2700 if (DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2700, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
== stmt_info)
2701 {
2702 /* First stmt in the interleaving chain. Check the chain. */
2703 stmt_vec_info next = DR_GROUP_NEXT_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2703, __FUNCTION__), 0 : 0)), (stmt_info)->next_element)
;
2704 struct data_reference *data_ref = dr;
2705 unsigned int count = 1;
2706 tree prev_init = DR_INIT (data_ref)(data_ref)->innermost.init;
2707 HOST_WIDE_INTlong diff, gaps = 0;
2708
2709 /* By construction, all group members have INTEGER_CST DR_INITs. */
2710 while (next)
2711 {
2712 /* We never have the same DR multiple times. */
2713 gcc_assert (tree_int_cst_compare (DR_INIT (data_ref),((void)(!(tree_int_cst_compare ((data_ref)->innermost.init
, (((next)->dr_aux.dr + 0))->innermost.init) != 0) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2714, __FUNCTION__), 0 : 0))
2714 DR_INIT (STMT_VINFO_DATA_REF (next))) != 0)((void)(!(tree_int_cst_compare ((data_ref)->innermost.init
, (((next)->dr_aux.dr + 0))->innermost.init) != 0) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2714, __FUNCTION__), 0 : 0))
;
2715
2716 data_ref = STMT_VINFO_DATA_REF (next)((next)->dr_aux.dr + 0);
2717
2718 /* All group members have the same STEP by construction. */
2719 gcc_checking_assert (operand_equal_p (DR_STEP (data_ref), step, 0))((void)(!(operand_equal_p ((data_ref)->innermost.step, step
, 0)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2719, __FUNCTION__), 0 : 0))
;
2720
2721 /* Check that the distance between two accesses is equal to the type
2722 size. Otherwise, we have gaps. */
2723 diff = (TREE_INT_CST_LOW (DR_INIT (data_ref))((unsigned long) (*tree_int_cst_elt_check (((data_ref)->innermost
.init), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2723, __FUNCTION__)))
2724 - TREE_INT_CST_LOW (prev_init)((unsigned long) (*tree_int_cst_elt_check ((prev_init), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2724, __FUNCTION__)))
) / type_size;
2725 if (diff < 1 || diff > UINT_MAX(2147483647 *2U +1U))
2726 {
2727 /* For artificial testcases with array accesses with large
2728 constant indices we can run into overflow issues which
2729 can end up fooling the groupsize constraint below so
2730 check the individual gaps (which are represented as
2731 unsigned int) as well. */
2732 if (dump_enabled_p ())
2733 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2734 "interleaved access with gap larger "
2735 "than representable\n");
2736 return false;
2737 }
2738 if (diff != 1)
2739 {
2740 /* FORNOW: SLP of accesses with gaps is not supported. */
2741 slp_impossible = true;
2742 if (DR_IS_WRITE (data_ref)(!(data_ref)->is_read))
2743 {
2744 if (dump_enabled_p ())
2745 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2746 "interleaved store with gaps\n");
2747 return false;
2748 }
2749
2750 gaps += diff - 1;
2751 }
2752
2753 last_accessed_element += diff;
2754
2755 /* Store the gap from the previous member of the group. If there is no
2756 gap in the access, DR_GROUP_GAP is always 1. */
2757 DR_GROUP_GAP (next)(((void)(!((next)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2757, __FUNCTION__), 0 : 0)), (next)->gap)
= diff;
2758
2759 prev_init = DR_INIT (data_ref)(data_ref)->innermost.init;
2760 next = DR_GROUP_NEXT_ELEMENT (next)(((void)(!((next)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2760, __FUNCTION__), 0 : 0)), (next)->next_element)
;
2761 /* Count the number of data-refs in the chain. */
2762 count++;
2763 }
2764
2765 if (groupsize == 0)
2766 groupsize = count + gaps;
2767
2768 /* This could be UINT_MAX but as we are generating code in a very
2769 inefficient way we have to cap earlier. See PR78699 for example. */
2770 if (groupsize > 4096)
2771 {
2772 if (dump_enabled_p ())
2773 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2774 "group is too large\n");
2775 return false;
2776 }
2777
2778 /* Check that the size of the interleaving is equal to count for stores,
2779 i.e., that there are no gaps. */
2780 if (groupsize != count
2781 && !DR_IS_READ (dr)(dr)->is_read)
2782 {
2783 groupsize = count;
2784 STMT_VINFO_STRIDED_P (stmt_info)(stmt_info)->strided_p = true;
2785 }
2786
2787 /* If there is a gap after the last load in the group it is the
2788 difference between the groupsize and the last accessed
2789 element.
2790 When there is no gap, this difference should be 0. */
2791 DR_GROUP_GAP (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2791, __FUNCTION__), 0 : 0)), (stmt_info)->gap)
= groupsize - last_accessed_element;
2792
2793 DR_GROUP_SIZE (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2793, __FUNCTION__), 0 : 0)), (stmt_info)->size)
= groupsize;
2794 if (dump_enabled_p ())
2795 {
2796 dump_printf_loc (MSG_NOTE, vect_location,
2797 "Detected interleaving ");
2798 if (DR_IS_READ (dr)(dr)->is_read)
2799 dump_printf (MSG_NOTE, "load ");
2800 else if (STMT_VINFO_STRIDED_P (stmt_info)(stmt_info)->strided_p)
2801 dump_printf (MSG_NOTE, "strided store ");
2802 else
2803 dump_printf (MSG_NOTE, "store ");
2804 dump_printf (MSG_NOTE, "of size %u\n",
2805 (unsigned)groupsize);
2806 dump_printf_loc (MSG_NOTE, vect_location, "\t%G", stmt_info->stmt);
2807 next = DR_GROUP_NEXT_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2807, __FUNCTION__), 0 : 0)), (stmt_info)->next_element)
;
2808 while (next)
2809 {
2810 if (DR_GROUP_GAP (next)(((void)(!((next)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2810, __FUNCTION__), 0 : 0)), (next)->gap)
!= 1)
2811 dump_printf_loc (MSG_NOTE, vect_location,
2812 "\t<gap of %d elements>\n",
2813 DR_GROUP_GAP (next)(((void)(!((next)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2813, __FUNCTION__), 0 : 0)), (next)->gap)
- 1);
2814 dump_printf_loc (MSG_NOTE, vect_location, "\t%G", next->stmt);
2815 next = DR_GROUP_NEXT_ELEMENT (next)(((void)(!((next)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2815, __FUNCTION__), 0 : 0)), (next)->next_element)
;
2816 }
2817 if (DR_GROUP_GAP (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2817, __FUNCTION__), 0 : 0)), (stmt_info)->gap)
!= 0)
2818 dump_printf_loc (MSG_NOTE, vect_location,
2819 "\t<gap of %d elements>\n",
2820 DR_GROUP_GAP (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2820, __FUNCTION__), 0 : 0)), (stmt_info)->gap)
);
2821 }
2822
2823 /* SLP: create an SLP data structure for every interleaving group of
2824 stores for further analysis in vect_analyse_slp. */
2825 if (DR_IS_WRITE (dr)(!(dr)->is_read) && !slp_impossible)
2826 {
2827 if (loop_vinfo)
2828 LOOP_VINFO_GROUPED_STORES (loop_vinfo)(loop_vinfo)->grouped_stores.safe_push (stmt_info);
2829 if (bb_vinfo)
2830 BB_VINFO_GROUPED_STORES (bb_vinfo)(bb_vinfo)->grouped_stores.safe_push (stmt_info);
2831 }
2832 }
2833
2834 return true;
2835}
2836
2837/* Analyze groups of accesses: check that DR_INFO belongs to a group of
2838 accesses of legal size, step, etc. Detect gaps, single element
2839 interleaving, and other special cases. Set grouped access info.
2840 Collect groups of strided stores for further use in SLP analysis. */
2841
2842static bool
2843vect_analyze_group_access (vec_info *vinfo, dr_vec_info *dr_info)
2844{
2845 if (!vect_analyze_group_access_1 (vinfo, dr_info))
2846 {
2847 /* Dissolve the group if present. */
2848 stmt_vec_info stmt_info = DR_GROUP_FIRST_ELEMENT (dr_info->stmt)(((void)(!((dr_info->stmt)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2848, __FUNCTION__), 0 : 0)), (dr_info->stmt)->first_element
)
;
2849 while (stmt_info)
2850 {
2851 stmt_vec_info next = DR_GROUP_NEXT_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2851, __FUNCTION__), 0 : 0)), (stmt_info)->next_element)
;
2852 DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2852, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
= NULLnullptr;
2853 DR_GROUP_NEXT_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2853, __FUNCTION__), 0 : 0)), (stmt_info)->next_element)
= NULLnullptr;
2854 stmt_info = next;
2855 }
2856 return false;
2857 }
2858 return true;
2859}
2860
2861/* Analyze the access pattern of the data-reference DR_INFO.
2862 In case of non-consecutive accesses call vect_analyze_group_access() to
2863 analyze groups of accesses. */
2864
2865static bool
2866vect_analyze_data_ref_access (vec_info *vinfo, dr_vec_info *dr_info)
2867{
2868 data_reference *dr = dr_info->dr;
2869 tree step = DR_STEP (dr)(dr)->innermost.step;
2870 tree scalar_type = TREE_TYPE (DR_REF (dr))((contains_struct_check (((dr)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2870, __FUNCTION__))->typed.type)
;
2871 stmt_vec_info stmt_info = dr_info->stmt;
2872 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
2873 class loop *loop = NULLnullptr;
2874
2875 if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)(stmt_info)->gather_scatter_p)
2876 return true;
2877
2878 if (loop_vinfo)
2879 loop = LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop;
2880
2881 if (loop_vinfo && !step)
2882 {
2883 if (dump_enabled_p ())
2884 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
2885 "bad data-ref access in loop\n");
2886 return false;
2887 }
2888
2889 /* Allow loads with zero step in inner-loop vectorization. */
2890 if (loop_vinfo && integer_zerop (step))
2891 {
2892 DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2892, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
= NULLnullptr;
2893 if (!nested_in_vect_loop_p (loop, stmt_info))
2894 return DR_IS_READ (dr)(dr)->is_read;
2895 /* Allow references with zero step for outer loops marked
2896 with pragma omp simd only - it guarantees absence of
2897 loop-carried dependencies between inner loop iterations. */
2898 if (loop->safelen < 2)
2899 {
2900 if (dump_enabled_p ())
2901 dump_printf_loc (MSG_NOTE, vect_location,
2902 "zero step in inner loop of nest\n");
2903 return false;
2904 }
2905 }
2906
2907 if (loop && nested_in_vect_loop_p (loop, stmt_info))
2908 {
2909 /* Interleaved accesses are not yet supported within outer-loop
2910 vectorization for references in the inner-loop. */
2911 DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2911, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
= NULLnullptr;
2912
2913 /* For the rest of the analysis we use the outer-loop step. */
2914 step = STMT_VINFO_DR_STEP (stmt_info)(stmt_info)->dr_wrt_vec_loop.step;
2915 if (integer_zerop (step))
2916 {
2917 if (dump_enabled_p ())
2918 dump_printf_loc (MSG_NOTE, vect_location,
2919 "zero step in outer loop.\n");
2920 return DR_IS_READ (dr)(dr)->is_read;
2921 }
2922 }
2923
2924 /* Consecutive? */
2925 if (TREE_CODE (step)((enum tree_code) (step)->base.code) == INTEGER_CST)
2926 {
2927 HOST_WIDE_INTlong dr_step = TREE_INT_CST_LOW (step)((unsigned long) (*tree_int_cst_elt_check ((step), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2927, __FUNCTION__)))
;
2928 if (!tree_int_cst_compare (step, TYPE_SIZE_UNIT (scalar_type)((tree_class_check ((scalar_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2928, __FUNCTION__))->type_common.size_unit)
)
2929 || (dr_step < 0
2930 && !compare_tree_int (TYPE_SIZE_UNIT (scalar_type)((tree_class_check ((scalar_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2930, __FUNCTION__))->type_common.size_unit)
, -dr_step)))
2931 {
2932 /* Mark that it is not interleaving. */
2933 DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2933, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
= NULLnullptr;
2934 return true;
2935 }
2936 }
2937
2938 if (loop && nested_in_vect_loop_p (loop, stmt_info))
2939 {
2940 if (dump_enabled_p ())
2941 dump_printf_loc (MSG_NOTE, vect_location,
2942 "grouped access in outer loop.\n");
2943 return false;
2944 }
2945
2946
2947 /* Assume this is a DR handled by non-constant strided load case. */
2948 if (TREE_CODE (step)((enum tree_code) (step)->base.code) != INTEGER_CST)
2949 return (STMT_VINFO_STRIDED_P (stmt_info)(stmt_info)->strided_p
2950 && (!STMT_VINFO_GROUPED_ACCESS (stmt_info)((stmt_info)->dr_aux.dr && (((void)(!((stmt_info)->
dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2950, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
))
2951 || vect_analyze_group_access (vinfo, dr_info)));
2952
2953 /* Not consecutive access - check if it's a part of interleaving group. */
2954 return vect_analyze_group_access (vinfo, dr_info);
2955}
2956
2957/* Compare two data-references DRA and DRB to group them into chunks
2958 suitable for grouping. */
2959
2960static int
2961dr_group_sort_cmp (const void *dra_, const void *drb_)
2962{
2963 dr_vec_info *dra_info = *(dr_vec_info **)const_cast<void *>(dra_);
2964 dr_vec_info *drb_info = *(dr_vec_info **)const_cast<void *>(drb_);
2965 data_reference_p dra = dra_info->dr;
2966 data_reference_p drb = drb_info->dr;
2967 int cmp;
2968
2969 /* Stabilize sort. */
2970 if (dra == drb)
2971 return 0;
2972
2973 /* Different group IDs lead never belong to the same group. */
2974 if (dra_info->group != drb_info->group)
2975 return dra_info->group < drb_info->group ? -1 : 1;
2976
2977 /* Ordering of DRs according to base. */
2978 cmp = data_ref_compare_tree (DR_BASE_ADDRESS (dra)(dra)->innermost.base_address,
2979 DR_BASE_ADDRESS (drb)(drb)->innermost.base_address);
2980 if (cmp != 0)
2981 return cmp;
2982
2983 /* And according to DR_OFFSET. */
2984 cmp = data_ref_compare_tree (DR_OFFSET (dra)(dra)->innermost.offset, DR_OFFSET (drb)(drb)->innermost.offset);
2985 if (cmp != 0)
2986 return cmp;
2987
2988 /* Put reads before writes. */
2989 if (DR_IS_READ (dra)(dra)->is_read != DR_IS_READ (drb)(drb)->is_read)
2990 return DR_IS_READ (dra)(dra)->is_read ? -1 : 1;
2991
2992 /* Then sort after access size. */
2993 cmp = data_ref_compare_tree (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dra)))((tree_class_check ((((contains_struct_check (((dra)->ref)
, (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2993, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2993, __FUNCTION__))->type_common.size_unit)
,
2994 TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (drb)))((tree_class_check ((((contains_struct_check (((drb)->ref)
, (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2994, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 2994, __FUNCTION__))->type_common.size_unit)
);
2995 if (cmp != 0)
2996 return cmp;
2997
2998 /* And after step. */
2999 cmp = data_ref_compare_tree (DR_STEP (dra)(dra)->innermost.step, DR_STEP (drb)(drb)->innermost.step);
3000 if (cmp != 0)
3001 return cmp;
3002
3003 /* Then sort after DR_INIT. In case of identical DRs sort after stmt UID. */
3004 cmp = data_ref_compare_tree (DR_INIT (dra)(dra)->innermost.init, DR_INIT (drb)(drb)->innermost.init);
3005 if (cmp == 0)
3006 return gimple_uid (DR_STMT (dra)(dra)->stmt) < gimple_uid (DR_STMT (drb)(drb)->stmt) ? -1 : 1;
3007 return cmp;
3008}
3009
3010/* If OP is the result of a conversion, return the unconverted value,
3011 otherwise return null. */
3012
3013static tree
3014strip_conversion (tree op)
3015{
3016 if (TREE_CODE (op)((enum tree_code) (op)->base.code) != SSA_NAME)
3017 return NULL_TREE(tree) nullptr;
3018 gimple *stmt = SSA_NAME_DEF_STMT (op)(tree_check ((op), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3018, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt
;
3019 if (!is_gimple_assign (stmt)
3020 || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))((gimple_assign_rhs_code (stmt)) == NOP_EXPR || (gimple_assign_rhs_code
(stmt)) == CONVERT_EXPR)
)
3021 return NULL_TREE(tree) nullptr;
3022 return gimple_assign_rhs1 (stmt);
3023}
3024
3025/* Return true if vectorizable_* routines can handle statements STMT1_INFO
3026 and STMT2_INFO being in a single group. When ALLOW_SLP_P, masked loads can
3027 be grouped in SLP mode. */
3028
3029static bool
3030can_group_stmts_p (stmt_vec_info stmt1_info, stmt_vec_info stmt2_info,
3031 bool allow_slp_p)
3032{
3033 if (gimple_assign_single_p (stmt1_info->stmt))
3034 return gimple_assign_single_p (stmt2_info->stmt);
3035
3036 gcall *call1 = dyn_cast <gcall *> (stmt1_info->stmt);
3037 if (call1 && gimple_call_internal_p (call1))
3038 {
3039 /* Check for two masked loads or two masked stores. */
3040 gcall *call2 = dyn_cast <gcall *> (stmt2_info->stmt);
3041 if (!call2 || !gimple_call_internal_p (call2))
3042 return false;
3043 internal_fn ifn = gimple_call_internal_fn (call1);
3044 if (ifn != IFN_MASK_LOAD && ifn != IFN_MASK_STORE)
3045 return false;
3046 if (ifn != gimple_call_internal_fn (call2))
3047 return false;
3048
3049 /* Check that the masks are the same. Cope with casts of masks,
3050 like those created by build_mask_conversion. */
3051 tree mask1 = gimple_call_arg (call1, 2);
3052 tree mask2 = gimple_call_arg (call2, 2);
3053 if (!operand_equal_p (mask1, mask2, 0)
3054 && (ifn == IFN_MASK_STORE || !allow_slp_p))
3055 {
3056 mask1 = strip_conversion (mask1);
3057 if (!mask1)
3058 return false;
3059 mask2 = strip_conversion (mask2);
3060 if (!mask2)
3061 return false;
3062 if (!operand_equal_p (mask1, mask2, 0))
3063 return false;
3064 }
3065 return true;
3066 }
3067
3068 return false;
3069}
3070
3071/* Function vect_analyze_data_ref_accesses.
3072
3073 Analyze the access pattern of all the data references in the loop.
3074
3075 FORNOW: the only access pattern that is considered vectorizable is a
3076 simple step 1 (consecutive) access.
3077
3078 FORNOW: handle only arrays and pointer accesses. */
3079
3080opt_result
3081vect_analyze_data_ref_accesses (vec_info *vinfo,
3082 vec<int> *dataref_groups)
3083{
3084 unsigned int i;
3085 vec<data_reference_p> datarefs = vinfo->shared->datarefs;
3086
3087 DUMP_VECT_SCOPE ("vect_analyze_data_ref_accesses")auto_dump_scope scope ("vect_analyze_data_ref_accesses", vect_location
)
;
3088
3089 if (datarefs.is_empty ())
3090 return opt_result::success ();
3091
3092 /* Sort the array of datarefs to make building the interleaving chains
3093 linear. Don't modify the original vector's order, it is needed for
3094 determining what dependencies are reversed. */
3095 vec<dr_vec_info *> datarefs_copy;
3096 datarefs_copy.create (datarefs.length ());
3097 for (unsigned i = 0; i < datarefs.length (); i++)
3098 {
3099 dr_vec_info *dr_info = vinfo->lookup_dr (datarefs[i]);
3100 /* If the caller computed DR grouping use that, otherwise group by
3101 basic blocks. */
3102 if (dataref_groups)
3103 dr_info->group = (*dataref_groups)[i];
3104 else
3105 dr_info->group = gimple_bb (DR_STMT (datarefs[i])(datarefs[i])->stmt)->index;
3106 datarefs_copy.quick_push (dr_info);
3107 }
3108 datarefs_copy.qsort (dr_group_sort_cmp)qsort (dr_group_sort_cmp);
3109 hash_set<stmt_vec_info> to_fixup;
3110
3111 /* Build the interleaving chains. */
3112 for (i = 0; i < datarefs_copy.length () - 1;)
3113 {
3114 dr_vec_info *dr_info_a = datarefs_copy[i];
3115 data_reference_p dra = dr_info_a->dr;
3116 int dra_group_id = dr_info_a->group;
3117 stmt_vec_info stmtinfo_a = dr_info_a->stmt;
3118 stmt_vec_info lastinfo = NULLnullptr;
3119 if (!STMT_VINFO_VECTORIZABLE (stmtinfo_a)(stmtinfo_a)->vectorizable
3120 || STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)(stmtinfo_a)->gather_scatter_p)
3121 {
3122 ++i;
3123 continue;
3124 }
3125 for (i = i + 1; i < datarefs_copy.length (); ++i)
3126 {
3127 dr_vec_info *dr_info_b = datarefs_copy[i];
3128 data_reference_p drb = dr_info_b->dr;
3129 int drb_group_id = dr_info_b->group;
3130 stmt_vec_info stmtinfo_b = dr_info_b->stmt;
3131 if (!STMT_VINFO_VECTORIZABLE (stmtinfo_b)(stmtinfo_b)->vectorizable
3132 || STMT_VINFO_GATHER_SCATTER_P (stmtinfo_b)(stmtinfo_b)->gather_scatter_p)
3133 break;
3134
3135 /* ??? Imperfect sorting (non-compatible types, non-modulo
3136 accesses, same accesses) can lead to a group to be artificially
3137 split here as we don't just skip over those. If it really
3138 matters we can push those to a worklist and re-iterate
3139 over them. The we can just skip ahead to the next DR here. */
3140
3141 /* DRs in a different DR group should not be put into the same
3142 interleaving group. */
3143 if (dra_group_id != drb_group_id)
3144 break;
3145
3146 /* Check that the data-refs have same first location (except init)
3147 and they are both either store or load (not load and store,
3148 not masked loads or stores). */
3149 if (DR_IS_READ (dra)(dra)->is_read != DR_IS_READ (drb)(drb)->is_read
3150 || data_ref_compare_tree (DR_BASE_ADDRESS (dra)(dra)->innermost.base_address,
3151 DR_BASE_ADDRESS (drb)(drb)->innermost.base_address) != 0
3152 || data_ref_compare_tree (DR_OFFSET (dra)(dra)->innermost.offset, DR_OFFSET (drb)(drb)->innermost.offset) != 0
3153 || !can_group_stmts_p (stmtinfo_a, stmtinfo_b, true))
3154 break;
3155
3156 /* Check that the data-refs have the same constant size. */
3157 tree sza = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dra)))((tree_class_check ((((contains_struct_check (((dra)->ref)
, (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3157, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3157, __FUNCTION__))->type_common.size_unit)
;
3158 tree szb = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (drb)))((tree_class_check ((((contains_struct_check (((drb)->ref)
, (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3158, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3158, __FUNCTION__))->type_common.size_unit)
;
3159 if (!tree_fits_uhwi_p (sza)
3160 || !tree_fits_uhwi_p (szb)
3161 || !tree_int_cst_equal (sza, szb))
3162 break;
3163
3164 /* Check that the data-refs have the same step. */
3165 if (data_ref_compare_tree (DR_STEP (dra)(dra)->innermost.step, DR_STEP (drb)(drb)->innermost.step) != 0)
3166 break;
3167
3168 /* Check the types are compatible.
3169 ??? We don't distinguish this during sorting. */
3170 if (!types_compatible_p (TREE_TYPE (DR_REF (dra))((contains_struct_check (((dra)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3170, __FUNCTION__))->typed.type)
,
3171 TREE_TYPE (DR_REF (drb))((contains_struct_check (((drb)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3171, __FUNCTION__))->typed.type)
))
3172 break;
3173
3174 /* Check that the DR_INITs are compile-time constants. */
3175 if (!tree_fits_shwi_p (DR_INIT (dra)(dra)->innermost.init)
3176 || !tree_fits_shwi_p (DR_INIT (drb)(drb)->innermost.init))
3177 break;
3178
3179 /* Different .GOMP_SIMD_LANE calls still give the same lane,
3180 just hold extra information. */
3181 if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmtinfo_a)(stmtinfo_a)->simd_lane_access_p
3182 && STMT_VINFO_SIMD_LANE_ACCESS_P (stmtinfo_b)(stmtinfo_b)->simd_lane_access_p
3183 && data_ref_compare_tree (DR_INIT (dra)(dra)->innermost.init, DR_INIT (drb)(drb)->innermost.init) == 0)
3184 break;
3185
3186 /* Sorting has ensured that DR_INIT (dra) <= DR_INIT (drb). */
3187 HOST_WIDE_INTlong init_a = TREE_INT_CST_LOW (DR_INIT (dra))((unsigned long) (*tree_int_cst_elt_check (((dra)->innermost
.init), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3187, __FUNCTION__)))
;
3188 HOST_WIDE_INTlong init_b = TREE_INT_CST_LOW (DR_INIT (drb))((unsigned long) (*tree_int_cst_elt_check (((drb)->innermost
.init), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3188, __FUNCTION__)))
;
3189 HOST_WIDE_INTlong init_prev
3190 = TREE_INT_CST_LOW (DR_INIT (datarefs_copy[i-1]->dr))((unsigned long) (*tree_int_cst_elt_check (((datarefs_copy[i-
1]->dr)->innermost.init), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3190, __FUNCTION__)))
;
3191 gcc_assert (init_a <= init_b((void)(!(init_a <= init_b && init_a <= init_prev
&& init_prev <= init_b) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3193, __FUNCTION__), 0 : 0))
3192 && init_a <= init_prev((void)(!(init_a <= init_b && init_a <= init_prev
&& init_prev <= init_b) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3193, __FUNCTION__), 0 : 0))
3193 && init_prev <= init_b)((void)(!(init_a <= init_b && init_a <= init_prev
&& init_prev <= init_b) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3193, __FUNCTION__), 0 : 0))
;
3194
3195 /* Do not place the same access in the interleaving chain twice. */
3196 if (init_b == init_prev)
3197 {
3198 gcc_assert (gimple_uid (DR_STMT (datarefs_copy[i-1]->dr))((void)(!(gimple_uid ((datarefs_copy[i-1]->dr)->stmt) <
gimple_uid ((drb)->stmt)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3199, __FUNCTION__), 0 : 0))
3199 < gimple_uid (DR_STMT (drb)))((void)(!(gimple_uid ((datarefs_copy[i-1]->dr)->stmt) <
gimple_uid ((drb)->stmt)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3199, __FUNCTION__), 0 : 0))
;
3200 /* Simply link in duplicates and fix up the chain below. */
3201 }
3202 else
3203 {
3204 /* If init_b == init_a + the size of the type * k, we have an
3205 interleaving, and DRA is accessed before DRB. */
3206 unsigned HOST_WIDE_INTlong type_size_a = tree_to_uhwi (sza);
3207 if (type_size_a == 0
3208 || (((unsigned HOST_WIDE_INTlong)init_b - init_a)
3209 % type_size_a != 0))
3210 break;
3211
3212 /* If we have a store, the accesses are adjacent. This splits
3213 groups into chunks we support (we don't support vectorization
3214 of stores with gaps). */
3215 if (!DR_IS_READ (dra)(dra)->is_read
3216 && (((unsigned HOST_WIDE_INTlong)init_b - init_prev)
3217 != type_size_a))
3218 break;
3219
3220 /* If the step (if not zero or non-constant) is smaller than the
3221 difference between data-refs' inits this splits groups into
3222 suitable sizes. */
3223 if (tree_fits_shwi_p (DR_STEP (dra)(dra)->innermost.step))
3224 {
3225 unsigned HOST_WIDE_INTlong step
3226 = absu_hwi (tree_to_shwi (DR_STEP (dra)(dra)->innermost.step));
3227 if (step != 0
3228 && step <= ((unsigned HOST_WIDE_INTlong)init_b - init_a))
3229 break;
3230 }
3231 }
3232
3233 if (dump_enabled_p ())
3234 dump_printf_loc (MSG_NOTE, vect_location,
3235 DR_IS_READ (dra)(dra)->is_read
3236 ? "Detected interleaving load %T and %T\n"
3237 : "Detected interleaving store %T and %T\n",
3238 DR_REF (dra)(dra)->ref, DR_REF (drb)(drb)->ref);
3239
3240 /* Link the found element into the group list. */
3241 if (!DR_GROUP_FIRST_ELEMENT (stmtinfo_a)(((void)(!((stmtinfo_a)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3241, __FUNCTION__), 0 : 0)), (stmtinfo_a)->first_element
)
)
3242 {
3243 DR_GROUP_FIRST_ELEMENT (stmtinfo_a)(((void)(!((stmtinfo_a)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3243, __FUNCTION__), 0 : 0)), (stmtinfo_a)->first_element
)
= stmtinfo_a;
3244 lastinfo = stmtinfo_a;
3245 }
3246 DR_GROUP_FIRST_ELEMENT (stmtinfo_b)(((void)(!((stmtinfo_b)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3246, __FUNCTION__), 0 : 0)), (stmtinfo_b)->first_element
)
= stmtinfo_a;
3247 DR_GROUP_NEXT_ELEMENT (lastinfo)(((void)(!((lastinfo)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3247, __FUNCTION__), 0 : 0)), (lastinfo)->next_element)
= stmtinfo_b;
3248 lastinfo = stmtinfo_b;
3249
3250 STMT_VINFO_SLP_VECT_ONLY (stmtinfo_a)(stmtinfo_a)->slp_vect_only_p
3251 = !can_group_stmts_p (stmtinfo_a, stmtinfo_b, false);
3252
3253 if (dump_enabled_p () && STMT_VINFO_SLP_VECT_ONLY (stmtinfo_a)(stmtinfo_a)->slp_vect_only_p)
3254 dump_printf_loc (MSG_NOTE, vect_location,
3255 "Load suitable for SLP vectorization only.\n");
3256
3257 if (init_b == init_prev
3258 && !to_fixup.add (DR_GROUP_FIRST_ELEMENT (stmtinfo_a)(((void)(!((stmtinfo_a)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3258, __FUNCTION__), 0 : 0)), (stmtinfo_a)->first_element
)
)
3259 && dump_enabled_p ())
3260 dump_printf_loc (MSG_NOTE, vect_location,
3261 "Queuing group with duplicate access for fixup\n");
3262 }
3263 }
3264
3265 /* Fixup groups with duplicate entries by splitting it. */
3266 while (1)
3267 {
3268 hash_set<stmt_vec_info>::iterator it = to_fixup.begin ();
3269 if (!(it != to_fixup.end ()))
3270 break;
3271 stmt_vec_info grp = *it;
3272 to_fixup.remove (grp);
3273
3274 /* Find the earliest duplicate group member. */
3275 unsigned first_duplicate = -1u;
3276 stmt_vec_info next, g = grp;
3277 while ((next = DR_GROUP_NEXT_ELEMENT (g)(((void)(!((g)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3277, __FUNCTION__), 0 : 0)), (g)->next_element)
))
3278 {
3279 if (tree_int_cst_equal (DR_INIT (STMT_VINFO_DR_INFO (next)->dr)((((void)(!((next)->dr_aux.stmt == (next)) ? fancy_abort (
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3279, __FUNCTION__), 0 : 0)), &(next)->dr_aux)->dr
)->innermost.init
,
3280 DR_INIT (STMT_VINFO_DR_INFO (g)->dr)((((void)(!((g)->dr_aux.stmt == (g)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3280, __FUNCTION__), 0 : 0)), &(g)->dr_aux)->dr)->
innermost.init
)
3281 && gimple_uid (STMT_VINFO_STMT (next)(next)->stmt) < first_duplicate)
3282 first_duplicate = gimple_uid (STMT_VINFO_STMT (next)(next)->stmt);
3283 g = next;
3284 }
3285 if (first_duplicate == -1U)
3286 continue;
3287
3288 /* Then move all stmts after the first duplicate to a new group.
3289 Note this is a heuristic but one with the property that *it
3290 is fixed up completely. */
3291 g = grp;
3292 stmt_vec_info newgroup = NULLnullptr, ng = grp;
3293 while ((next = DR_GROUP_NEXT_ELEMENT (g)(((void)(!((g)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3293, __FUNCTION__), 0 : 0)), (g)->next_element)
))
3294 {
3295 if (gimple_uid (STMT_VINFO_STMT (next)(next)->stmt) >= first_duplicate)
3296 {
3297 DR_GROUP_NEXT_ELEMENT (g)(((void)(!((g)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3297, __FUNCTION__), 0 : 0)), (g)->next_element)
= DR_GROUP_NEXT_ELEMENT (next)(((void)(!((next)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3297, __FUNCTION__), 0 : 0)), (next)->next_element)
;
3298 if (!newgroup)
3299 newgroup = next;
3300 else
3301 DR_GROUP_NEXT_ELEMENT (ng)(((void)(!((ng)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3301, __FUNCTION__), 0 : 0)), (ng)->next_element)
= next;
3302 ng = next;
3303 DR_GROUP_FIRST_ELEMENT (ng)(((void)(!((ng)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3303, __FUNCTION__), 0 : 0)), (ng)->first_element)
= newgroup;
3304 }
3305 else
3306 g = DR_GROUP_NEXT_ELEMENT (g)(((void)(!((g)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3306, __FUNCTION__), 0 : 0)), (g)->next_element)
;
3307 }
3308 DR_GROUP_NEXT_ELEMENT (ng)(((void)(!((ng)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3308, __FUNCTION__), 0 : 0)), (ng)->next_element)
= NULLnullptr;
3309
3310 /* Fixup the new group which still may contain duplicates. */
3311 to_fixup.add (newgroup);
3312 }
3313
3314 dr_vec_info *dr_info;
3315 FOR_EACH_VEC_ELT (datarefs_copy, i, dr_info)for (i = 0; (datarefs_copy).iterate ((i), &(dr_info)); ++
(i))
3316 {
3317 if (STMT_VINFO_VECTORIZABLE (dr_info->stmt)(dr_info->stmt)->vectorizable
3318 && !vect_analyze_data_ref_access (vinfo, dr_info))
3319 {
3320 if (dump_enabled_p ())
3321 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
3322 "not vectorized: complicated access pattern.\n");
3323
3324 if (is_a <bb_vec_info> (vinfo))
3325 {
3326 /* Mark the statement as not vectorizable. */
3327 STMT_VINFO_VECTORIZABLE (dr_info->stmt)(dr_info->stmt)->vectorizable = false;
3328 continue;
3329 }
3330 else
3331 {
3332 datarefs_copy.release ();
3333 return opt_result::failure_at (dr_info->stmt->stmt,
3334 "not vectorized:"
3335 " complicated access pattern.\n");
3336 }
3337 }
3338 }
3339
3340 datarefs_copy.release ();
3341 return opt_result::success ();
3342}
3343
3344/* Function vect_vfa_segment_size.
3345
3346 Input:
3347 DR_INFO: The data reference.
3348 LENGTH_FACTOR: segment length to consider.
3349
3350 Return a value suitable for the dr_with_seg_len::seg_len field.
3351 This is the "distance travelled" by the pointer from the first
3352 iteration in the segment to the last. Note that it does not include
3353 the size of the access; in effect it only describes the first byte. */
3354
3355static tree
3356vect_vfa_segment_size (dr_vec_info *dr_info, tree length_factor)
3357{
3358 length_factor = size_binop (MINUS_EXPR,size_binop_loc (((location_t) 0), MINUS_EXPR, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], length_factor
), global_trees[TI_SIZE_ONE])
3359 fold_convert (sizetype, length_factor),size_binop_loc (((location_t) 0), MINUS_EXPR, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], length_factor
), global_trees[TI_SIZE_ONE])
3360 size_one_node)size_binop_loc (((location_t) 0), MINUS_EXPR, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], length_factor
), global_trees[TI_SIZE_ONE])
;
3361 return size_binop (MULT_EXPR, fold_convert (sizetype, DR_STEP (dr_info->dr)),size_binop_loc (((location_t) 0), MULT_EXPR, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], (dr_info
->dr)->innermost.step), length_factor)
3362 length_factor)size_binop_loc (((location_t) 0), MULT_EXPR, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], (dr_info
->dr)->innermost.step), length_factor)
;
3363}
3364
3365/* Return a value that, when added to abs (vect_vfa_segment_size (DR_INFO)),
3366 gives the worst-case number of bytes covered by the segment. */
3367
3368static unsigned HOST_WIDE_INTlong
3369vect_vfa_access_size (vec_info *vinfo, dr_vec_info *dr_info)
3370{
3371 stmt_vec_info stmt_vinfo = dr_info->stmt;
3372 tree ref_type = TREE_TYPE (DR_REF (dr_info->dr))((contains_struct_check (((dr_info->dr)->ref), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3372, __FUNCTION__))->typed.type)
;
3373 unsigned HOST_WIDE_INTlong ref_size = tree_to_uhwi (TYPE_SIZE_UNIT (ref_type)((tree_class_check ((ref_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3373, __FUNCTION__))->type_common.size_unit)
);
3374 unsigned HOST_WIDE_INTlong access_size = ref_size;
3375 if (DR_GROUP_FIRST_ELEMENT (stmt_vinfo)(((void)(!((stmt_vinfo)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3375, __FUNCTION__), 0 : 0)), (stmt_vinfo)->first_element
)
)
3376 {
3377 gcc_assert (DR_GROUP_FIRST_ELEMENT (stmt_vinfo) == stmt_vinfo)((void)(!((((void)(!((stmt_vinfo)->dr_aux.dr) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3377, __FUNCTION__), 0 : 0)), (stmt_vinfo)->first_element
) == stmt_vinfo) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3377, __FUNCTION__), 0 : 0))
;
3378 access_size *= DR_GROUP_SIZE (stmt_vinfo)(((void)(!((stmt_vinfo)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3378, __FUNCTION__), 0 : 0)), (stmt_vinfo)->size)
- DR_GROUP_GAP (stmt_vinfo)(((void)(!((stmt_vinfo)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3378, __FUNCTION__), 0 : 0)), (stmt_vinfo)->gap)
;
3379 }
3380 tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo)(stmt_vinfo)->vectype;
3381 int misalignment;
3382 if (STMT_VINFO_VEC_STMTS (stmt_vinfo)(stmt_vinfo)->vec_stmts.exists ()
3383 && ((misalignment = dr_misalignment (dr_info, vectype)), true)
3384 && (vect_supportable_dr_alignment (vinfo, dr_info, vectype, misalignment)
3385 == dr_explicit_realign_optimized))
3386 {
3387 /* We might access a full vector's worth. */
3388 access_size += tree_to_uhwi (TYPE_SIZE_UNIT (vectype)((tree_class_check ((vectype), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3388, __FUNCTION__))->type_common.size_unit)
) - ref_size;
3389 }
3390 return access_size;
3391}
3392
3393/* Get the minimum alignment for all the scalar accesses that DR_INFO
3394 describes. */
3395
3396static unsigned int
3397vect_vfa_align (dr_vec_info *dr_info)
3398{
3399 return dr_alignment (dr_info->dr);
3400}
3401
3402/* Function vect_no_alias_p.
3403
3404 Given data references A and B with equal base and offset, see whether
3405 the alias relation can be decided at compilation time. Return 1 if
3406 it can and the references alias, 0 if it can and the references do
3407 not alias, and -1 if we cannot decide at compile time. SEGMENT_LENGTH_A,
3408 SEGMENT_LENGTH_B, ACCESS_SIZE_A and ACCESS_SIZE_B are the equivalent
3409 of dr_with_seg_len::{seg_len,access_size} for A and B. */
3410
3411static int
3412vect_compile_time_alias (dr_vec_info *a, dr_vec_info *b,
3413 tree segment_length_a, tree segment_length_b,
3414 unsigned HOST_WIDE_INTlong access_size_a,
3415 unsigned HOST_WIDE_INTlong access_size_b)
3416{
3417 poly_offset_int offset_a = wi::to_poly_offset (DR_INIT (a->dr)(a->dr)->innermost.init);
3418 poly_offset_int offset_b = wi::to_poly_offset (DR_INIT (b->dr)(b->dr)->innermost.init);
3419 poly_uint64 const_length_a;
3420 poly_uint64 const_length_b;
3421
3422 /* For negative step, we need to adjust address range by TYPE_SIZE_UNIT
3423 bytes, e.g., int a[3] -> a[1] range is [a+4, a+16) instead of
3424 [a, a+12) */
3425 if (tree_int_cst_compare (DR_STEP (a->dr)(a->dr)->innermost.step, size_zero_nodeglobal_trees[TI_SIZE_ZERO]) < 0)
3426 {
3427 const_length_a = (-wi::to_poly_wide (segment_length_a)).force_uhwi ();
3428 offset_a -= const_length_a;
3429 }
3430 else
3431 const_length_a = tree_to_poly_uint64 (segment_length_a);
3432 if (tree_int_cst_compare (DR_STEP (b->dr)(b->dr)->innermost.step, size_zero_nodeglobal_trees[TI_SIZE_ZERO]) < 0)
3433 {
3434 const_length_b = (-wi::to_poly_wide (segment_length_b)).force_uhwi ();
3435 offset_b -= const_length_b;
3436 }
3437 else
3438 const_length_b = tree_to_poly_uint64 (segment_length_b);
3439
3440 const_length_a += access_size_a;
3441 const_length_b += access_size_b;
3442
3443 if (ranges_known_overlap_p (offset_a, const_length_a,
3444 offset_b, const_length_b))
3445 return 1;
3446
3447 if (!ranges_maybe_overlap_p (offset_a, const_length_a,
3448 offset_b, const_length_b))
3449 return 0;
3450
3451 return -1;
3452}
3453
3454/* Return true if the minimum nonzero dependence distance for loop LOOP_DEPTH
3455 in DDR is >= VF. */
3456
3457static bool
3458dependence_distance_ge_vf (data_dependence_relation *ddr,
3459 unsigned int loop_depth, poly_uint64 vf)
3460{
3461 if (DDR_ARE_DEPENDENT (ddr)(ddr)->are_dependent != NULL_TREE(tree) nullptr
3462 || DDR_NUM_DIST_VECTS (ddr)(((ddr)->dist_vects).length ()) == 0)
3463 return false;
3464
3465 /* If the dependence is exact, we should have limited the VF instead. */
3466 gcc_checking_assert (DDR_COULD_BE_INDEPENDENT_P (ddr))((void)(!((ddr)->could_be_independent_p) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3466, __FUNCTION__), 0 : 0))
;
3467
3468 unsigned int i;
3469 lambda_vector dist_v;
3470 FOR_EACH_VEC_ELT (DDR_DIST_VECTS (ddr), i, dist_v)for (i = 0; (((ddr)->dist_vects)).iterate ((i), &(dist_v
)); ++(i))
3471 {
3472 HOST_WIDE_INTlong dist = dist_v[loop_depth];
3473 if (dist != 0
3474 && !(dist > 0 && DDR_REVERSED_P (ddr)(ddr)->reversed_p)
3475 && maybe_lt ((unsigned HOST_WIDE_INTlong) abs_hwi (dist), vf))
3476 return false;
3477 }
3478
3479 if (dump_enabled_p ())
3480 dump_printf_loc (MSG_NOTE, vect_location,
3481 "dependence distance between %T and %T is >= VF\n",
3482 DR_REF (DDR_A (ddr))((ddr)->a)->ref, DR_REF (DDR_B (ddr))((ddr)->b)->ref);
3483
3484 return true;
3485}
3486
3487/* Dump LOWER_BOUND using flags DUMP_KIND. Dumps are known to be enabled. */
3488
3489static void
3490dump_lower_bound (dump_flags_t dump_kind, const vec_lower_bound &lower_bound)
3491{
3492 dump_printf (dump_kind, "%s (%T) >= ",
3493 lower_bound.unsigned_p ? "unsigned" : "abs",
3494 lower_bound.expr);
3495 dump_dec (dump_kind, lower_bound.min_value);
3496}
3497
3498/* Record that the vectorized loop requires the vec_lower_bound described
3499 by EXPR, UNSIGNED_P and MIN_VALUE. */
3500
3501static void
3502vect_check_lower_bound (loop_vec_info loop_vinfo, tree expr, bool unsigned_p,
3503 poly_uint64 min_value)
3504{
3505 vec<vec_lower_bound> &lower_bounds
3506 = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo)(loop_vinfo)->lower_bounds;
3507 for (unsigned int i = 0; i < lower_bounds.length (); ++i)
3508 if (operand_equal_p (lower_bounds[i].expr, expr, 0))
3509 {
3510 unsigned_p &= lower_bounds[i].unsigned_p;
3511 min_value = upper_bound (lower_bounds[i].min_value, min_value);
3512 if (lower_bounds[i].unsigned_p != unsigned_p
3513 || maybe_lt (lower_bounds[i].min_value, min_value))
3514 {
3515 lower_bounds[i].unsigned_p = unsigned_p;
3516 lower_bounds[i].min_value = min_value;
3517 if (dump_enabled_p ())
3518 {
3519 dump_printf_loc (MSG_NOTE, vect_location,
3520 "updating run-time check to ");
3521 dump_lower_bound (MSG_NOTE, lower_bounds[i]);
3522 dump_printf (MSG_NOTE, "\n");
3523 }
3524 }
3525 return;
3526 }
3527
3528 vec_lower_bound lower_bound (expr, unsigned_p, min_value);
3529 if (dump_enabled_p ())
3530 {
3531 dump_printf_loc (MSG_NOTE, vect_location, "need a run-time check that ");
3532 dump_lower_bound (MSG_NOTE, lower_bound);
3533 dump_printf (MSG_NOTE, "\n");
3534 }
3535 LOOP_VINFO_LOWER_BOUNDS (loop_vinfo)(loop_vinfo)->lower_bounds.safe_push (lower_bound);
3536}
3537
3538/* Return true if it's unlikely that the step of the vectorized form of DR_INFO
3539 will span fewer than GAP bytes. */
3540
3541static bool
3542vect_small_gap_p (loop_vec_info loop_vinfo, dr_vec_info *dr_info,
3543 poly_int64 gap)
3544{
3545 stmt_vec_info stmt_info = dr_info->stmt;
3546 HOST_WIDE_INTlong count
3547 = estimated_poly_value (LOOP_VINFO_VECT_FACTOR (loop_vinfo)(loop_vinfo)->vectorization_factor);
3548 if (DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3548, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
)
3549 count *= DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info))(((void)(!(((((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3549, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
))->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3549, __FUNCTION__), 0 : 0)), ((((void)(!((stmt_info)->dr_aux
.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3549, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
))->size)
;
3550 return (estimated_poly_value (gap)
3551 <= count * vect_get_scalar_dr_size (dr_info));
3552}
3553
3554/* Return true if we know that there is no alias between DR_INFO_A and
3555 DR_INFO_B when abs (DR_STEP (DR_INFO_A->dr)) >= N for some N.
3556 When returning true, set *LOWER_BOUND_OUT to this N. */
3557
3558static bool
3559vectorizable_with_step_bound_p (dr_vec_info *dr_info_a, dr_vec_info *dr_info_b,
3560 poly_uint64 *lower_bound_out)
3561{
3562 /* Check that there is a constant gap of known sign between DR_A
3563 and DR_B. */
3564 data_reference *dr_a = dr_info_a->dr;
3565 data_reference *dr_b = dr_info_b->dr;
3566 poly_int64 init_a, init_b;
3567 if (!operand_equal_p (DR_BASE_ADDRESS (dr_a)(dr_a)->innermost.base_address, DR_BASE_ADDRESS (dr_b)(dr_b)->innermost.base_address, 0)
3568 || !operand_equal_p (DR_OFFSET (dr_a)(dr_a)->innermost.offset, DR_OFFSET (dr_b)(dr_b)->innermost.offset, 0)
3569 || !operand_equal_p (DR_STEP (dr_a)(dr_a)->innermost.step, DR_STEP (dr_b)(dr_b)->innermost.step, 0)
3570 || !poly_int_tree_p (DR_INIT (dr_a)(dr_a)->innermost.init, &init_a)
3571 || !poly_int_tree_p (DR_INIT (dr_b)(dr_b)->innermost.init, &init_b)
3572 || !ordered_p (init_a, init_b))
3573 return false;
3574
3575 /* Sort DR_A and DR_B by the address they access. */
3576 if (maybe_lt (init_b, init_a))
3577 {
3578 std::swap (init_a, init_b);
3579 std::swap (dr_info_a, dr_info_b);
3580 std::swap (dr_a, dr_b);
3581 }
3582
3583 /* If the two accesses could be dependent within a scalar iteration,
3584 make sure that we'd retain their order. */
3585 if (maybe_gt (init_a + vect_get_scalar_dr_size (dr_info_a), init_b)maybe_lt (init_b, init_a + vect_get_scalar_dr_size (dr_info_a
))
3586 && !vect_preserves_scalar_order_p (dr_info_a, dr_info_b))
3587 return false;
3588
3589 /* There is no alias if abs (DR_STEP) is greater than or equal to
3590 the bytes spanned by the combination of the two accesses. */
3591 *lower_bound_out = init_b + vect_get_scalar_dr_size (dr_info_b) - init_a;
3592 return true;
3593}
3594
3595/* Function vect_prune_runtime_alias_test_list.
3596
3597 Prune a list of ddrs to be tested at run-time by versioning for alias.
3598 Merge several alias checks into one if possible.
3599 Return FALSE if resulting list of ddrs is longer then allowed by
3600 PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS, otherwise return TRUE. */
3601
3602opt_result
3603vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
3604{
3605 typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
3606 hash_set <tree_pair_hash> compared_objects;
3607
3608 const vec<ddr_p> &may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo)(loop_vinfo)->may_alias_ddrs;
3609 vec<dr_with_seg_len_pair_t> &comp_alias_ddrs
3610 = LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo)(loop_vinfo)->comp_alias_ddrs;
3611 const vec<vec_object_pair> &check_unequal_addrs
3612 = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo)(loop_vinfo)->check_unequal_addrs;
3613 poly_uint64 vect_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo)(loop_vinfo)->vectorization_factor;
3614 tree scalar_loop_iters = LOOP_VINFO_NITERS (loop_vinfo)(loop_vinfo)->num_iters;
3615
3616 ddr_p ddr;
3617 unsigned int i;
3618 tree length_factor;
3619
3620 DUMP_VECT_SCOPE ("vect_prune_runtime_alias_test_list")auto_dump_scope scope ("vect_prune_runtime_alias_test_list", vect_location
)
;
3621
3622 /* Step values are irrelevant for aliasing if the number of vector
3623 iterations is equal to the number of scalar iterations (which can
3624 happen for fully-SLP loops). */
3625 bool vf_one_p = known_eq (LOOP_VINFO_VECT_FACTOR (loop_vinfo), 1U)(!maybe_ne ((loop_vinfo)->vectorization_factor, 1U));
3626
3627 if (!vf_one_p)
3628 {
3629 /* Convert the checks for nonzero steps into bound tests. */
3630 tree value;
3631 FOR_EACH_VEC_ELT (LOOP_VINFO_CHECK_NONZERO (loop_vinfo), i, value)for (i = 0; ((loop_vinfo)->check_nonzero).iterate ((i), &
(value)); ++(i))
3632 vect_check_lower_bound (loop_vinfo, value, true, 1);
3633 }
3634
3635 if (may_alias_ddrs.is_empty ())
3636 return opt_result::success ();
3637
3638 comp_alias_ddrs.create (may_alias_ddrs.length ());
3639
3640 unsigned int loop_depth
3641 = index_in_loop_nest (LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop->num,
3642 LOOP_VINFO_LOOP_NEST (loop_vinfo)(loop_vinfo)->shared->loop_nest);
3643
3644 /* First, we collect all data ref pairs for aliasing checks. */
3645 FOR_EACH_VEC_ELT (may_alias_ddrs, i, ddr)for (i = 0; (may_alias_ddrs).iterate ((i), &(ddr)); ++(i)
)
3646 {
3647 poly_uint64 lower_bound;
3648 tree segment_length_a, segment_length_b;
3649 unsigned HOST_WIDE_INTlong access_size_a, access_size_b;
3650 unsigned int align_a, align_b;
3651
3652 /* Ignore the alias if the VF we chose ended up being no greater
3653 than the dependence distance. */
3654 if (dependence_distance_ge_vf (ddr, loop_depth, vect_factor))
3655 continue;
3656
3657 if (DDR_OBJECT_A (ddr)(ddr)->object_a)
3658 {
3659 vec_object_pair new_pair (DDR_OBJECT_A (ddr)(ddr)->object_a, DDR_OBJECT_B (ddr)(ddr)->object_b);
3660 if (!compared_objects.add (new_pair))
3661 {
3662 if (dump_enabled_p ())
3663 dump_printf_loc (MSG_NOTE, vect_location,
3664 "checking that %T and %T"
3665 " have different addresses\n",
3666 new_pair.first, new_pair.second);
3667 LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo)(loop_vinfo)->check_unequal_addrs.safe_push (new_pair);
3668 }
3669 continue;
3670 }
3671
3672 dr_vec_info *dr_info_a = loop_vinfo->lookup_dr (DDR_A (ddr)(ddr)->a);
3673 stmt_vec_info stmt_info_a = dr_info_a->stmt;
3674
3675 dr_vec_info *dr_info_b = loop_vinfo->lookup_dr (DDR_B (ddr)(ddr)->b);
3676 stmt_vec_info stmt_info_b = dr_info_b->stmt;
3677
3678 bool preserves_scalar_order_p
3679 = vect_preserves_scalar_order_p (dr_info_a, dr_info_b);
3680 bool ignore_step_p
3681 = (vf_one_p
3682 && (preserves_scalar_order_p
3683 || operand_equal_p (DR_STEP (dr_info_a->dr)(dr_info_a->dr)->innermost.step,
3684 DR_STEP (dr_info_b->dr)(dr_info_b->dr)->innermost.step)));
3685
3686 /* Skip the pair if inter-iteration dependencies are irrelevant
3687 and intra-iteration dependencies are guaranteed to be honored. */
3688 if (ignore_step_p
3689 && (preserves_scalar_order_p
3690 || vectorizable_with_step_bound_p (dr_info_a, dr_info_b,
3691 &lower_bound)))
3692 {
3693 if (dump_enabled_p ())
3694 dump_printf_loc (MSG_NOTE, vect_location,
3695 "no need for alias check between "
3696 "%T and %T when VF is 1\n",
3697 DR_REF (dr_info_a->dr)(dr_info_a->dr)->ref, DR_REF (dr_info_b->dr)(dr_info_b->dr)->ref);
3698 continue;
3699 }
3700
3701 /* See whether we can handle the alias using a bounds check on
3702 the step, and whether that's likely to be the best approach.
3703 (It might not be, for example, if the minimum step is much larger
3704 than the number of bytes handled by one vector iteration.) */
3705 if (!ignore_step_p
3706 && TREE_CODE (DR_STEP (dr_info_a->dr))((enum tree_code) ((dr_info_a->dr)->innermost.step)->
base.code)
!= INTEGER_CST
3707 && vectorizable_with_step_bound_p (dr_info_a, dr_info_b,
3708 &lower_bound)
3709 && (vect_small_gap_p (loop_vinfo, dr_info_a, lower_bound)
3710 || vect_small_gap_p (loop_vinfo, dr_info_b, lower_bound)))
3711 {
3712 bool unsigned_p = dr_known_forward_stride_p (dr_info_a->dr);
3713 if (dump_enabled_p ())
3714 {
3715 dump_printf_loc (MSG_NOTE, vect_location, "no alias between "
3716 "%T and %T when the step %T is outside ",
3717 DR_REF (dr_info_a->dr)(dr_info_a->dr)->ref,
3718 DR_REF (dr_info_b->dr)(dr_info_b->dr)->ref,
3719 DR_STEP (dr_info_a->dr)(dr_info_a->dr)->innermost.step);
3720 if (unsigned_p)
3721 dump_printf (MSG_NOTE, "[0");
3722 else
3723 {
3724 dump_printf (MSG_NOTE, "(");
3725 dump_dec (MSG_NOTE, poly_int64 (-lower_bound));
3726 }
3727 dump_printf (MSG_NOTE, ", ");
3728 dump_dec (MSG_NOTE, lower_bound);
3729 dump_printf (MSG_NOTE, ")\n");
3730 }
3731 vect_check_lower_bound (loop_vinfo, DR_STEP (dr_info_a->dr)(dr_info_a->dr)->innermost.step,
3732 unsigned_p, lower_bound);
3733 continue;
3734 }
3735
3736 stmt_vec_info dr_group_first_a = DR_GROUP_FIRST_ELEMENT (stmt_info_a)(((void)(!((stmt_info_a)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3736, __FUNCTION__), 0 : 0)), (stmt_info_a)->first_element
)
;
3737 if (dr_group_first_a)
3738 {
3739 stmt_info_a = dr_group_first_a;
3740 dr_info_a = STMT_VINFO_DR_INFO (stmt_info_a)(((void)(!((stmt_info_a)->dr_aux.stmt == (stmt_info_a)) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3740, __FUNCTION__), 0 : 0)), &(stmt_info_a)->dr_aux
)
;
3741 }
3742
3743 stmt_vec_info dr_group_first_b = DR_GROUP_FIRST_ELEMENT (stmt_info_b)(((void)(!((stmt_info_b)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3743, __FUNCTION__), 0 : 0)), (stmt_info_b)->first_element
)
;
3744 if (dr_group_first_b)
3745 {
3746 stmt_info_b = dr_group_first_b;
3747 dr_info_b = STMT_VINFO_DR_INFO (stmt_info_b)(((void)(!((stmt_info_b)->dr_aux.stmt == (stmt_info_b)) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3747, __FUNCTION__), 0 : 0)), &(stmt_info_b)->dr_aux
)
;
3748 }
3749
3750 if (ignore_step_p)
3751 {
3752 segment_length_a = size_zero_nodeglobal_trees[TI_SIZE_ZERO];
3753 segment_length_b = size_zero_nodeglobal_trees[TI_SIZE_ZERO];
3754 }
3755 else
3756 {
3757 if (!operand_equal_p (DR_STEP (dr_info_a->dr)(dr_info_a->dr)->innermost.step,
3758 DR_STEP (dr_info_b->dr)(dr_info_b->dr)->innermost.step, 0))
3759 length_factor = scalar_loop_iters;
3760 else
3761 length_factor = size_int (vect_factor)size_int_kind (vect_factor, stk_sizetype);
3762 segment_length_a = vect_vfa_segment_size (dr_info_a, length_factor);
3763 segment_length_b = vect_vfa_segment_size (dr_info_b, length_factor);
3764 }
3765 access_size_a = vect_vfa_access_size (loop_vinfo, dr_info_a);
3766 access_size_b = vect_vfa_access_size (loop_vinfo, dr_info_b);
3767 align_a = vect_vfa_align (dr_info_a);
3768 align_b = vect_vfa_align (dr_info_b);
3769
3770 /* See whether the alias is known at compilation time. */
3771 if (operand_equal_p (DR_BASE_ADDRESS (dr_info_a->dr)(dr_info_a->dr)->innermost.base_address,
3772 DR_BASE_ADDRESS (dr_info_b->dr)(dr_info_b->dr)->innermost.base_address, 0)
3773 && operand_equal_p (DR_OFFSET (dr_info_a->dr)(dr_info_a->dr)->innermost.offset,
3774 DR_OFFSET (dr_info_b->dr)(dr_info_b->dr)->innermost.offset, 0)
3775 && TREE_CODE (DR_STEP (dr_info_a->dr))((enum tree_code) ((dr_info_a->dr)->innermost.step)->
base.code)
== INTEGER_CST
3776 && TREE_CODE (DR_STEP (dr_info_b->dr))((enum tree_code) ((dr_info_b->dr)->innermost.step)->
base.code)
== INTEGER_CST
3777 && poly_int_tree_p (segment_length_a)
3778 && poly_int_tree_p (segment_length_b))
3779 {
3780 int res = vect_compile_time_alias (dr_info_a, dr_info_b,
3781 segment_length_a,
3782 segment_length_b,
3783 access_size_a,
3784 access_size_b);
3785 if (res >= 0 && dump_enabled_p ())
3786 {
3787 dump_printf_loc (MSG_NOTE, vect_location,
3788 "can tell at compile time that %T and %T",
3789 DR_REF (dr_info_a->dr)(dr_info_a->dr)->ref, DR_REF (dr_info_b->dr)(dr_info_b->dr)->ref);
3790 if (res == 0)
3791 dump_printf (MSG_NOTE, " do not alias\n");
3792 else
3793 dump_printf (MSG_NOTE, " alias\n");
3794 }
3795
3796 if (res == 0)
3797 continue;
3798
3799 if (res == 1)
3800 return opt_result::failure_at (stmt_info_b->stmt,
3801 "not vectorized:"
3802 " compilation time alias: %G%G",
3803 stmt_info_a->stmt,
3804 stmt_info_b->stmt);
3805 }
3806
3807 dr_with_seg_len dr_a (dr_info_a->dr, segment_length_a,
3808 access_size_a, align_a);
3809 dr_with_seg_len dr_b (dr_info_b->dr, segment_length_b,
3810 access_size_b, align_b);
3811 /* Canonicalize the order to be the one that's needed for accurate
3812 RAW, WAR and WAW flags, in cases where the data references are
3813 well-ordered. The order doesn't really matter otherwise,
3814 but we might as well be consistent. */
3815 if (get_later_stmt (stmt_info_a, stmt_info_b) == stmt_info_a)
3816 std::swap (dr_a, dr_b);
3817
3818 dr_with_seg_len_pair_t dr_with_seg_len_pair
3819 (dr_a, dr_b, (preserves_scalar_order_p
3820 ? dr_with_seg_len_pair_t::WELL_ORDERED
3821 : dr_with_seg_len_pair_t::REORDERED));
3822
3823 comp_alias_ddrs.safe_push (dr_with_seg_len_pair);
3824 }
3825
3826 prune_runtime_alias_test_list (&comp_alias_ddrs, vect_factor);
3827
3828 unsigned int count = (comp_alias_ddrs.length ()
3829 + check_unequal_addrs.length ());
3830
3831 if (count
3832 && (loop_cost_model (LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop)
3833 == VECT_COST_MODEL_VERY_CHEAP))
3834 return opt_result::failure_at
3835 (vect_location, "would need a runtime alias check\n");
3836
3837 if (dump_enabled_p ())
3838 dump_printf_loc (MSG_NOTE, vect_location,
3839 "improved number of alias checks from %d to %d\n",
3840 may_alias_ddrs.length (), count);
3841 unsigned limit = param_vect_max_version_for_alias_checksglobal_options.x_param_vect_max_version_for_alias_checks;
3842 if (loop_cost_model (LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop) == VECT_COST_MODEL_CHEAP)
3843 limit = param_vect_max_version_for_alias_checksglobal_options.x_param_vect_max_version_for_alias_checks * 6 / 10;
3844 if (count > limit)
3845 return opt_result::failure_at
3846 (vect_location,
3847 "number of versioning for alias run-time tests exceeds %d "
3848 "(--param vect-max-version-for-alias-checks)\n", limit);
3849
3850 return opt_result::success ();
3851}
3852
3853/* Check whether we can use an internal function for a gather load
3854 or scatter store. READ_P is true for loads and false for stores.
3855 MASKED_P is true if the load or store is conditional. MEMORY_TYPE is
3856 the type of the memory elements being loaded or stored. OFFSET_TYPE
3857 is the type of the offset that is being applied to the invariant
3858 base address. SCALE is the amount by which the offset should
3859 be multiplied *after* it has been converted to address width.
3860
3861 Return true if the function is supported, storing the function id in
3862 *IFN_OUT and the vector type for the offset in *OFFSET_VECTYPE_OUT. */
3863
3864bool
3865vect_gather_scatter_fn_p (vec_info *vinfo, bool read_p, bool masked_p,
3866 tree vectype, tree memory_type, tree offset_type,
3867 int scale, internal_fn *ifn_out,
3868 tree *offset_vectype_out)
3869{
3870 unsigned int memory_bits = tree_to_uhwi (TYPE_SIZE (memory_type)((tree_class_check ((memory_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3870, __FUNCTION__))->type_common.size)
);
3871 unsigned int element_bits = vector_element_bits (vectype);
3872 if (element_bits != memory_bits)
3873 /* For now the vector elements must be the same width as the
3874 memory elements. */
3875 return false;
3876
3877 /* Work out which function we need. */
3878 internal_fn ifn, alt_ifn;
3879 if (read_p)
3880 {
3881 ifn = masked_p ? IFN_MASK_GATHER_LOAD : IFN_GATHER_LOAD;
3882 alt_ifn = IFN_MASK_GATHER_LOAD;
3883 }
3884 else
3885 {
3886 ifn = masked_p ? IFN_MASK_SCATTER_STORE : IFN_SCATTER_STORE;
3887 alt_ifn = IFN_MASK_SCATTER_STORE;
3888 }
3889
3890 for (;;)
3891 {
3892 tree offset_vectype = get_vectype_for_scalar_type (vinfo, offset_type);
3893 if (!offset_vectype)
3894 return false;
3895
3896 /* Test whether the target supports this combination. */
3897 if (internal_gather_scatter_fn_supported_p (ifn, vectype, memory_type,
3898 offset_vectype, scale))
3899 {
3900 *ifn_out = ifn;
3901 *offset_vectype_out = offset_vectype;
3902 return true;
3903 }
3904 else if (!masked_p
3905 && internal_gather_scatter_fn_supported_p (alt_ifn, vectype,
3906 memory_type,
3907 offset_vectype,
3908 scale))
3909 {
3910 *ifn_out = alt_ifn;
3911 *offset_vectype_out = offset_vectype;
3912 return true;
3913 }
3914
3915 if (TYPE_PRECISION (offset_type)((tree_class_check ((offset_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3915, __FUNCTION__))->type_common.precision)
>= POINTER_SIZE(((global_options.x_ix86_isa_flags & (1UL << 58)) !=
0) ? 32 : ((8) * (((global_options.x_ix86_isa_flags & (1UL
<< 1)) != 0) ? 8 : 4)))
3916 && TYPE_PRECISION (offset_type)((tree_class_check ((offset_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3916, __FUNCTION__))->type_common.precision)
>= element_bits)
3917 return false;
3918
3919 offset_type = build_nonstandard_integer_type
3920 (TYPE_PRECISION (offset_type)((tree_class_check ((offset_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3920, __FUNCTION__))->type_common.precision)
* 2, TYPE_UNSIGNED (offset_type)((tree_class_check ((offset_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3920, __FUNCTION__))->base.u.bits.unsigned_flag)
);
3921 }
3922}
3923
3924/* STMT_INFO is a call to an internal gather load or scatter store function.
3925 Describe the operation in INFO. */
3926
3927static void
3928vect_describe_gather_scatter_call (stmt_vec_info stmt_info,
3929 gather_scatter_info *info)
3930{
3931 gcall *call = as_a <gcall *> (stmt_info->stmt);
3932 tree vectype = STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype;
3933 data_reference *dr = STMT_VINFO_DATA_REF (stmt_info)((stmt_info)->dr_aux.dr + 0);
3934
3935 info->ifn = gimple_call_internal_fn (call);
3936 info->decl = NULL_TREE(tree) nullptr;
3937 info->base = gimple_call_arg (call, 0);
3938 info->offset = gimple_call_arg (call, 1);
3939 info->offset_dt = vect_unknown_def_type;
3940 info->offset_vectype = NULL_TREE(tree) nullptr;
3941 info->scale = TREE_INT_CST_LOW (gimple_call_arg (call, 2))((unsigned long) (*tree_int_cst_elt_check ((gimple_call_arg (
call, 2)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3941, __FUNCTION__)))
;
3942 info->element_type = TREE_TYPE (vectype)((contains_struct_check ((vectype), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3942, __FUNCTION__))->typed.type)
;
3943 info->memory_type = TREE_TYPE (DR_REF (dr))((contains_struct_check (((dr)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3943, __FUNCTION__))->typed.type)
;
3944}
3945
3946/* Return true if a non-affine read or write in STMT_INFO is suitable for a
3947 gather load or scatter store. Describe the operation in *INFO if so. */
3948
3949bool
3950vect_check_gather_scatter (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
3951 gather_scatter_info *info)
3952{
3953 HOST_WIDE_INTlong scale = 1;
3954 poly_int64 pbitpos, pbitsize;
3955 class loop *loop = LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop;
3956 struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info)((stmt_info)->dr_aux.dr + 0);
3957 tree offtype = NULL_TREE(tree) nullptr;
3958 tree decl = NULL_TREE(tree) nullptr, base, off;
3959 tree vectype = STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype;
3960 tree memory_type = TREE_TYPE (DR_REF (dr))((contains_struct_check (((dr)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3960, __FUNCTION__))->typed.type)
;
3961 machine_mode pmode;
3962 int punsignedp, reversep, pvolatilep = 0;
3963 internal_fn ifn;
3964 tree offset_vectype;
3965 bool masked_p = false;
3966
3967 /* See whether this is already a call to a gather/scatter internal function.
3968 If not, see whether it's a masked load or store. */
3969 gcall *call = dyn_cast <gcall *> (stmt_info->stmt);
3970 if (call && gimple_call_internal_p (call))
3971 {
3972 ifn = gimple_call_internal_fn (call);
3973 if (internal_gather_scatter_fn_p (ifn))
3974 {
3975 vect_describe_gather_scatter_call (stmt_info, info);
3976 return true;
3977 }
3978 masked_p = (ifn == IFN_MASK_LOAD || ifn == IFN_MASK_STORE);
3979 }
3980
3981 /* True if we should aim to use internal functions rather than
3982 built-in functions. */
3983 bool use_ifn_p = (DR_IS_READ (dr)(dr)->is_read
3984 ? supports_vec_gather_load_p (TYPE_MODE (vectype)((((enum tree_code) ((tree_class_check ((vectype), (tcc_type)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3984, __FUNCTION__)))->base.code) == VECTOR_TYPE) ? vector_type_mode
(vectype) : (vectype)->type_common.mode)
)
3985 : supports_vec_scatter_store_p (TYPE_MODE (vectype)((((enum tree_code) ((tree_class_check ((vectype), (tcc_type)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3985, __FUNCTION__)))->base.code) == VECTOR_TYPE) ? vector_type_mode
(vectype) : (vectype)->type_common.mode)
));
3986
3987 base = DR_REF (dr)(dr)->ref;
3988 /* For masked loads/stores, DR_REF (dr) is an artificial MEM_REF,
3989 see if we can use the def stmt of the address. */
3990 if (masked_p
3991 && TREE_CODE (base)((enum tree_code) (base)->base.code) == MEM_REF
3992 && TREE_CODE (TREE_OPERAND (base, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check
((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3992, __FUNCTION__))))))->base.code)
== SSA_NAME
3993 && integer_zerop (TREE_OPERAND (base, 1)(*((const_cast<tree*> (tree_operand_check ((base), (1),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3993, __FUNCTION__)))))
)
3994 && !expr_invariant_in_loop_p (loop, TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3994, __FUNCTION__)))))
))
3995 {
3996 gimple *def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0))(tree_check (((*((const_cast<tree*> (tree_operand_check
((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3996, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3996, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt
;
3997 if (is_gimple_assign (def_stmt)
3998 && gimple_assign_rhs_code (def_stmt) == ADDR_EXPR)
3999 base = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0)(*((const_cast<tree*> (tree_operand_check ((gimple_assign_rhs1
(def_stmt)), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 3999, __FUNCTION__)))))
;
4000 }
4001
4002 /* The gather and scatter builtins need address of the form
4003 loop_invariant + vector * {1, 2, 4, 8}
4004 or
4005 loop_invariant + sign_extend (vector) * { 1, 2, 4, 8 }.
4006 Unfortunately DR_BASE_ADDRESS/DR_OFFSET can be a mixture
4007 of loop invariants/SSA_NAMEs defined in the loop, with casts,
4008 multiplications and additions in it. To get a vector, we need
4009 a single SSA_NAME that will be defined in the loop and will
4010 contain everything that is not loop invariant and that can be
4011 vectorized. The following code attempts to find such a preexistng
4012 SSA_NAME OFF and put the loop invariants into a tree BASE
4013 that can be gimplified before the loop. */
4014 base = get_inner_reference (base, &pbitsize, &pbitpos, &off, &pmode,
4015 &punsignedp, &reversep, &pvolatilep);
4016 if (reversep)
4017 return false;
4018
4019 /* PR 107346. Packed structs can have fields at offsets that are not
4020 multiples of BITS_PER_UNIT. Do not use gather/scatters in such cases. */
4021 if (!multiple_p (pbitpos, BITS_PER_UNIT(8)))
4022 return false;
4023
4024 poly_int64 pbytepos = exact_div (pbitpos, BITS_PER_UNIT(8));
4025
4026 if (TREE_CODE (base)((enum tree_code) (base)->base.code) == MEM_REF)
4027 {
4028 if (!integer_zerop (TREE_OPERAND (base, 1)(*((const_cast<tree*> (tree_operand_check ((base), (1),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4028, __FUNCTION__)))))
))
4029 {
4030 if (off == NULL_TREE(tree) nullptr)
4031 off = wide_int_to_tree (sizetypesizetype_tab[(int) stk_sizetype], mem_ref_offset (base));
4032 else
4033 off = size_binop (PLUS_EXPR, off,size_binop_loc (((location_t) 0), PLUS_EXPR, off, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], (*((const_cast
<tree*> (tree_operand_check ((base), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4034, __FUNCTION__)))))))
4034 fold_convert (sizetype, TREE_OPERAND (base, 1)))size_binop_loc (((location_t) 0), PLUS_EXPR, off, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], (*((const_cast
<tree*> (tree_operand_check ((base), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4034, __FUNCTION__)))))))
;
4035 }
4036 base = TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0),
"/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4036, __FUNCTION__)))))
;
4037 }
4038 else
4039 base = build_fold_addr_expr (base)build_fold_addr_expr_loc (((location_t) 0), (base));
4040
4041 if (off == NULL_TREE(tree) nullptr)
4042 off = size_zero_nodeglobal_trees[TI_SIZE_ZERO];
4043
4044 /* If base is not loop invariant, either off is 0, then we start with just
4045 the constant offset in the loop invariant BASE and continue with base
4046 as OFF, otherwise give up.
4047 We could handle that case by gimplifying the addition of base + off
4048 into some SSA_NAME and use that as off, but for now punt. */
4049 if (!expr_invariant_in_loop_p (loop, base))
4050 {
4051 if (!integer_zerop (off))
4052 return false;
4053 off = base;
4054 base = size_int (pbytepos)size_int_kind (pbytepos, stk_sizetype);
4055 }
4056 /* Otherwise put base + constant offset into the loop invariant BASE
4057 and continue with OFF. */
4058 else
4059 {
4060 base = fold_convert (sizetype, base)fold_convert_loc (((location_t) 0), sizetype_tab[(int) stk_sizetype
], base)
;
4061 base = size_binop (PLUS_EXPR, base, size_int (pbytepos))size_binop_loc (((location_t) 0), PLUS_EXPR, base, size_int_kind
(pbytepos, stk_sizetype))
;
4062 }
4063
4064 /* OFF at this point may be either a SSA_NAME or some tree expression
4065 from get_inner_reference. Try to peel off loop invariants from it
4066 into BASE as long as possible. */
4067 STRIP_NOPS (off)(off) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((off)))))
;
4068 while (offtype == NULL_TREE(tree) nullptr)
4069 {
4070 enum tree_code code;
4071 tree op0, op1, add = NULL_TREE(tree) nullptr;
4072
4073 if (TREE_CODE (off)((enum tree_code) (off)->base.code) == SSA_NAME)
4074 {
4075 gimple *def_stmt = SSA_NAME_DEF_STMT (off)(tree_check ((off), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4075, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt
;
4076
4077 if (expr_invariant_in_loop_p (loop, off))
4078 return false;
4079
4080 if (gimple_code (def_stmt) != GIMPLE_ASSIGN)
4081 break;
4082
4083 op0 = gimple_assign_rhs1 (def_stmt);
4084 code = gimple_assign_rhs_code (def_stmt);
4085 op1 = gimple_assign_rhs2 (def_stmt);
4086 }
4087 else
4088 {
4089 if (get_gimple_rhs_class (TREE_CODE (off)((enum tree_code) (off)->base.code)) == GIMPLE_TERNARY_RHS)
4090 return false;
4091 code = TREE_CODE (off)((enum tree_code) (off)->base.code);
4092 extract_ops_from_tree (off, &code, &op0, &op1);
4093 }
4094 switch (code)
4095 {
4096 case POINTER_PLUS_EXPR:
4097 case PLUS_EXPR:
4098 if (expr_invariant_in_loop_p (loop, op0))
4099 {
4100 add = op0;
4101 off = op1;
4102 do_add:
4103 add = fold_convert (sizetype, add)fold_convert_loc (((location_t) 0), sizetype_tab[(int) stk_sizetype
], add)
;
4104 if (scale != 1)
4105 add = size_binop (MULT_EXPR, add, size_int (scale))size_binop_loc (((location_t) 0), MULT_EXPR, add, size_int_kind
(scale, stk_sizetype))
;
4106 base = size_binop (PLUS_EXPR, base, add)size_binop_loc (((location_t) 0), PLUS_EXPR, base, add);
4107 continue;
4108 }
4109 if (expr_invariant_in_loop_p (loop, op1))
4110 {
4111 add = op1;
4112 off = op0;
4113 goto do_add;
4114 }
4115 break;
4116 case MINUS_EXPR:
4117 if (expr_invariant_in_loop_p (loop, op1))
4118 {
4119 add = fold_convert (sizetype, op1)fold_convert_loc (((location_t) 0), sizetype_tab[(int) stk_sizetype
], op1)
;
4120 add = size_binop (MINUS_EXPR, size_zero_node, add)size_binop_loc (((location_t) 0), MINUS_EXPR, global_trees[TI_SIZE_ZERO
], add)
;
4121 off = op0;
4122 goto do_add;
4123 }
4124 break;
4125 case MULT_EXPR:
4126 if (scale == 1 && tree_fits_shwi_p (op1))
4127 {
4128 int new_scale = tree_to_shwi (op1);
4129 /* Only treat this as a scaling operation if the target
4130 supports it for at least some offset type. */
4131 if (use_ifn_p
4132 && !vect_gather_scatter_fn_p (loop_vinfo, DR_IS_READ (dr)(dr)->is_read,
4133 masked_p, vectype, memory_type,
4134 signed_char_type_nodeinteger_types[itk_signed_char],
4135 new_scale, &ifn,
4136 &offset_vectype)
4137 && !vect_gather_scatter_fn_p (loop_vinfo, DR_IS_READ (dr)(dr)->is_read,
4138 masked_p, vectype, memory_type,
4139 unsigned_char_type_nodeinteger_types[itk_unsigned_char],
4140 new_scale, &ifn,
4141 &offset_vectype))
4142 break;
4143 scale = new_scale;
4144 off = op0;
4145 continue;
4146 }
4147 break;
4148 case SSA_NAME:
4149 off = op0;
4150 continue;
4151 CASE_CONVERTcase NOP_EXPR: case CONVERT_EXPR:
4152 if (!POINTER_TYPE_P (TREE_TYPE (op0))(((enum tree_code) (((contains_struct_check ((op0), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4152, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE
|| ((enum tree_code) (((contains_struct_check ((op0), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4152, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE
)
4153 && !INTEGRAL_TYPE_P (TREE_TYPE (op0))(((enum tree_code) (((contains_struct_check ((op0), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4153, __FUNCTION__))->typed.type))->base.code) == ENUMERAL_TYPE
|| ((enum tree_code) (((contains_struct_check ((op0), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4153, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE
|| ((enum tree_code) (((contains_struct_check ((op0), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4153, __FUNCTION__))->typed.type))->base.code) == INTEGER_TYPE
)
)
4154 break;
4155
4156 /* Don't include the conversion if the target is happy with
4157 the current offset type. */
4158 if (use_ifn_p
4159 && TREE_CODE (off)((enum tree_code) (off)->base.code) == SSA_NAME
4160 && !POINTER_TYPE_P (TREE_TYPE (off))(((enum tree_code) (((contains_struct_check ((off), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4160, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE
|| ((enum tree_code) (((contains_struct_check ((off), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4160, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE
)
4161 && vect_gather_scatter_fn_p (loop_vinfo, DR_IS_READ (dr)(dr)->is_read,
4162 masked_p, vectype, memory_type,
4163 TREE_TYPE (off)((contains_struct_check ((off), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4163, __FUNCTION__))->typed.type)
, scale, &ifn,
4164 &offset_vectype))
4165 break;
4166
4167 if (TYPE_PRECISION (TREE_TYPE (op0))((tree_class_check ((((contains_struct_check ((op0), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4167, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4167, __FUNCTION__))->type_common.precision)
4168 == TYPE_PRECISION (TREE_TYPE (off))((tree_class_check ((((contains_struct_check ((off), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4168, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4168, __FUNCTION__))->type_common.precision)
)
4169 {
4170 off = op0;
4171 continue;
4172 }
4173
4174 /* Include the conversion if it is widening and we're using
4175 the IFN path or the target can handle the converted from
4176 offset or the current size is not already the same as the
4177 data vector element size. */
4178 if ((TYPE_PRECISION (TREE_TYPE (op0))((tree_class_check ((((contains_struct_check ((op0), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4178, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4178, __FUNCTION__))->type_common.precision)
4179 < TYPE_PRECISION (TREE_TYPE (off))((tree_class_check ((((contains_struct_check ((off), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4179, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4179, __FUNCTION__))->type_common.precision)
)
4180 && (use_ifn_p
4181 || (DR_IS_READ (dr)(dr)->is_read
4182 ? (targetm.vectorize.builtin_gather
4183 && targetm.vectorize.builtin_gather (vectype,
4184 TREE_TYPE (op0)((contains_struct_check ((op0), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4184, __FUNCTION__))->typed.type)
,
4185 scale))
4186 : (targetm.vectorize.builtin_scatter
4187 && targetm.vectorize.builtin_scatter (vectype,
4188 TREE_TYPE (op0)((contains_struct_check ((op0), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4188, __FUNCTION__))->typed.type)
,
4189 scale)))
4190 || !operand_equal_p (TYPE_SIZE (TREE_TYPE (off))((tree_class_check ((((contains_struct_check ((off), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4190, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4190, __FUNCTION__))->type_common.size)
,
4191 TYPE_SIZE (TREE_TYPE (vectype))((tree_class_check ((((contains_struct_check ((vectype), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4191, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4191, __FUNCTION__))->type_common.size)
, 0)))
4192 {
4193 off = op0;
4194 offtype = TREE_TYPE (off)((contains_struct_check ((off), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4194, __FUNCTION__))->typed.type)
;
4195 STRIP_NOPS (off)(off) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((off)))))
;
4196 continue;
4197 }
4198 break;
4199 default:
4200 break;
4201 }
4202 break;
4203 }
4204
4205 /* If at the end OFF still isn't a SSA_NAME or isn't
4206 defined in the loop, punt. */
4207 if (TREE_CODE (off)((enum tree_code) (off)->base.code) != SSA_NAME
4208 || expr_invariant_in_loop_p (loop, off))
4209 return false;
4210
4211 if (offtype == NULL_TREE(tree) nullptr)
4212 offtype = TREE_TYPE (off)((contains_struct_check ((off), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4212, __FUNCTION__))->typed.type)
;
4213
4214 if (use_ifn_p)
4215 {
4216 if (!vect_gather_scatter_fn_p (loop_vinfo, DR_IS_READ (dr)(dr)->is_read, masked_p,
4217 vectype, memory_type, offtype, scale,
4218 &ifn, &offset_vectype))
4219 ifn = IFN_LAST;
4220 decl = NULL_TREE(tree) nullptr;
4221 }
4222 else
4223 {
4224 if (DR_IS_READ (dr)(dr)->is_read)
4225 {
4226 if (targetm.vectorize.builtin_gather)
4227 decl = targetm.vectorize.builtin_gather (vectype, offtype, scale);
4228 }
4229 else
4230 {
4231 if (targetm.vectorize.builtin_scatter)
4232 decl = targetm.vectorize.builtin_scatter (vectype, offtype, scale);
4233 }
4234 ifn = IFN_LAST;
4235 /* The offset vector type will be read from DECL when needed. */
4236 offset_vectype = NULL_TREE(tree) nullptr;
4237 }
4238
4239 info->ifn = ifn;
4240 info->decl = decl;
4241 info->base = base;
4242 info->offset = off;
4243 info->offset_dt = vect_unknown_def_type;
4244 info->offset_vectype = offset_vectype;
4245 info->scale = scale;
4246 info->element_type = TREE_TYPE (vectype)((contains_struct_check ((vectype), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4246, __FUNCTION__))->typed.type)
;
4247 info->memory_type = memory_type;
4248 return true;
4249}
4250
4251/* Find the data references in STMT, analyze them with respect to LOOP and
4252 append them to DATAREFS. Return false if datarefs in this stmt cannot
4253 be handled. */
4254
4255opt_result
4256vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
4257 vec<data_reference_p> *datarefs,
4258 vec<int> *dataref_groups, int group_id)
4259{
4260 /* We can ignore clobbers for dataref analysis - they are removed during
4261 loop vectorization and BB vectorization checks dependences with a
4262 stmt walk. */
4263 if (gimple_clobber_p (stmt))
4264 return opt_result::success ();
4265
4266 if (gimple_has_volatile_ops (stmt))
4267 return opt_result::failure_at (stmt, "not vectorized: volatile type: %G",
4268 stmt);
4269
4270 if (stmt_can_throw_internal (cfun(cfun + 0), stmt))
4271 return opt_result::failure_at (stmt,
4272 "not vectorized:"
4273 " statement can throw an exception: %G",
4274 stmt);
4275
4276 auto_vec<data_reference_p, 2> refs;
4277 opt_result res = find_data_references_in_stmt (loop, stmt, &refs);
4278 if (!res)
4279 return res;
4280
4281 if (refs.is_empty ())
4282 return opt_result::success ();
4283
4284 if (refs.length () > 1)
4285 {
4286 while (!refs.is_empty ())
4287 free_data_ref (refs.pop ());
4288 return opt_result::failure_at (stmt,
4289 "not vectorized: more than one "
4290 "data ref in stmt: %G", stmt);
4291 }
4292
4293 data_reference_p dr = refs.pop ();
4294 if (gcall *call = dyn_cast <gcall *> (stmt))
4295 if (!gimple_call_internal_p (call)
4296 || (gimple_call_internal_fn (call) != IFN_MASK_LOAD
4297 && gimple_call_internal_fn (call) != IFN_MASK_STORE))
4298 {
4299 free_data_ref (dr);
4300 return opt_result::failure_at (stmt,
4301 "not vectorized: dr in a call %G", stmt);
4302 }
4303
4304 if (TREE_CODE (DR_REF (dr))((enum tree_code) ((dr)->ref)->base.code) == COMPONENT_REF
4305 && DECL_BIT_FIELD (TREE_OPERAND (DR_REF (dr), 1))((tree_check (((*((const_cast<tree*> (tree_operand_check
(((dr)->ref), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4305, __FUNCTION__)))))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4305, __FUNCTION__, (FIELD_DECL)))->decl_common.decl_flag_1
)
)
4306 {
4307 free_data_ref (dr);
4308 return opt_result::failure_at (stmt,
4309 "not vectorized:"
4310 " statement is an unsupported"
4311 " bitfield access %G", stmt);
4312 }
4313
4314 if (DR_BASE_ADDRESS (dr)(dr)->innermost.base_address
4315 && TREE_CODE (DR_BASE_ADDRESS (dr))((enum tree_code) ((dr)->innermost.base_address)->base.
code)
== INTEGER_CST)
4316 {
4317 free_data_ref (dr);
4318 return opt_result::failure_at (stmt,
4319 "not vectorized:"
4320 " base addr of dr is a constant\n");
4321 }
4322
4323 /* Check whether this may be a SIMD lane access and adjust the
4324 DR to make it easier for us to handle it. */
4325 if (loop
4326 && loop->simduid
4327 && (!DR_BASE_ADDRESS (dr)(dr)->innermost.base_address
4328 || !DR_OFFSET (dr)(dr)->innermost.offset
4329 || !DR_INIT (dr)(dr)->innermost.init
4330 || !DR_STEP (dr)(dr)->innermost.step))
4331 {
4332 struct data_reference *newdr
4333 = create_data_ref (NULLnullptr, loop_containing_stmt (stmt), DR_REF (dr)(dr)->ref, stmt,
4334 DR_IS_READ (dr)(dr)->is_read, DR_IS_CONDITIONAL_IN_STMT (dr)(dr)->is_conditional_in_stmt);
4335 if (DR_BASE_ADDRESS (newdr)(newdr)->innermost.base_address
4336 && DR_OFFSET (newdr)(newdr)->innermost.offset
4337 && DR_INIT (newdr)(newdr)->innermost.init
4338 && DR_STEP (newdr)(newdr)->innermost.step
4339 && TREE_CODE (DR_INIT (newdr))((enum tree_code) ((newdr)->innermost.init)->base.code) == INTEGER_CST
4340 && integer_zerop (DR_STEP (newdr)(newdr)->innermost.step))
4341 {
4342 tree base_address = DR_BASE_ADDRESS (newdr)(newdr)->innermost.base_address;
4343 tree off = DR_OFFSET (newdr)(newdr)->innermost.offset;
4344 tree step = ssize_int (1)size_int_kind (1, stk_ssizetype);
4345 if (integer_zerop (off)
4346 && TREE_CODE (base_address)((enum tree_code) (base_address)->base.code) == POINTER_PLUS_EXPR)
4347 {
4348 off = TREE_OPERAND (base_address, 1)(*((const_cast<tree*> (tree_operand_check ((base_address
), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4348, __FUNCTION__)))))
;
4349 base_address = TREE_OPERAND (base_address, 0)(*((const_cast<tree*> (tree_operand_check ((base_address
), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4349, __FUNCTION__)))))
;
4350 }
4351 STRIP_NOPS (off)(off) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((off)))))
;
4352 if (TREE_CODE (off)((enum tree_code) (off)->base.code) == MULT_EXPR
4353 && tree_fits_uhwi_p (TREE_OPERAND (off, 1)(*((const_cast<tree*> (tree_operand_check ((off), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4353, __FUNCTION__)))))
))
4354 {
4355 step = TREE_OPERAND (off, 1)(*((const_cast<tree*> (tree_operand_check ((off), (1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4355, __FUNCTION__)))))
;
4356 off = TREE_OPERAND (off, 0)(*((const_cast<tree*> (tree_operand_check ((off), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4356, __FUNCTION__)))))
;
4357 STRIP_NOPS (off)(off) = tree_strip_nop_conversions ((const_cast<union tree_node
*> (((off)))))
;
4358 }
4359 if (CONVERT_EXPR_P (off)((((enum tree_code) (off)->base.code)) == NOP_EXPR || (((enum
tree_code) (off)->base.code)) == CONVERT_EXPR)
4360 && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (off, 0)))((tree_class_check ((((contains_struct_check (((*((const_cast
<tree*> (tree_operand_check ((off), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4360, __FUNCTION__)))))), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4360, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4360, __FUNCTION__))->type_common.precision)
4361 < TYPE_PRECISION (TREE_TYPE (off))((tree_class_check ((((contains_struct_check ((off), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4361, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4361, __FUNCTION__))->type_common.precision)
))
4362 off = TREE_OPERAND (off, 0)(*((const_cast<tree*> (tree_operand_check ((off), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4362, __FUNCTION__)))))
;
4363 if (TREE_CODE (off)((enum tree_code) (off)->base.code) == SSA_NAME)
4364 {
4365 gimple *def = SSA_NAME_DEF_STMT (off)(tree_check ((off), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4365, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt
;
4366 /* Look through widening conversion. */
4367 if (is_gimple_assign (def)
4368 && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def))((gimple_assign_rhs_code (def)) == NOP_EXPR || (gimple_assign_rhs_code
(def)) == CONVERT_EXPR)
)
4369 {
4370 tree rhs1 = gimple_assign_rhs1 (def);
4371 if (TREE_CODE (rhs1)((enum tree_code) (rhs1)->base.code) == SSA_NAME
4372 && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))(((enum tree_code) (((contains_struct_check ((rhs1), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4372, __FUNCTION__))->typed.type))->base.code) == ENUMERAL_TYPE
|| ((enum tree_code) (((contains_struct_check ((rhs1), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4372, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE
|| ((enum tree_code) (((contains_struct_check ((rhs1), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4372, __FUNCTION__))->typed.type))->base.code) == INTEGER_TYPE
)
4373 && (TYPE_PRECISION (TREE_TYPE (off))((tree_class_check ((((contains_struct_check ((off), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4373, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4373, __FUNCTION__))->type_common.precision)
4374 > TYPE_PRECISION (TREE_TYPE (rhs1))((tree_class_check ((((contains_struct_check ((rhs1), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4374, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4374, __FUNCTION__))->type_common.precision)
))
4375 def = SSA_NAME_DEF_STMT (rhs1)(tree_check ((rhs1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4375, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt
;
4376 }
4377 if (is_gimple_call (def)
4378 && gimple_call_internal_p (def)
4379 && (gimple_call_internal_fn (def) == IFN_GOMP_SIMD_LANE))
4380 {
4381 tree arg = gimple_call_arg (def, 0);
4382 tree reft = TREE_TYPE (DR_REF (newdr))((contains_struct_check (((newdr)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4382, __FUNCTION__))->typed.type)
;
4383 gcc_assert (TREE_CODE (arg) == SSA_NAME)((void)(!(((enum tree_code) (arg)->base.code) == SSA_NAME)
? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4383, __FUNCTION__), 0 : 0))
;
4384 arg = SSA_NAME_VAR (arg)((tree_check ((arg), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4384, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree)
nullptr || ((enum tree_code) ((arg)->ssa_name.var)->base
.code) == IDENTIFIER_NODE ? (tree) nullptr : (arg)->ssa_name
.var)
;
4385 if (arg == loop->simduid
4386 /* For now. */
4387 && tree_int_cst_equal (TYPE_SIZE_UNIT (reft)((tree_class_check ((reft), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4387, __FUNCTION__))->type_common.size_unit)
, step))
4388 {
4389 DR_BASE_ADDRESS (newdr)(newdr)->innermost.base_address = base_address;
4390 DR_OFFSET (newdr)(newdr)->innermost.offset = ssize_int (0)size_int_kind (0, stk_ssizetype);
4391 DR_STEP (newdr)(newdr)->innermost.step = step;
4392 DR_OFFSET_ALIGNMENT (newdr)(newdr)->innermost.offset_alignment = BIGGEST_ALIGNMENT(((global_options.x_target_flags & (1U << 12)) != 0
) ? 32 : (((global_options.x_ix86_isa_flags & (1UL <<
15)) != 0) ? 512 : (((global_options.x_ix86_isa_flags & (
1UL << 8)) != 0) ? 256 : 128)))
;
4393 DR_STEP_ALIGNMENT (newdr)(newdr)->innermost.step_alignment = highest_pow2_factor (step);
4394 /* Mark as simd-lane access. */
4395 tree arg2 = gimple_call_arg (def, 1);
4396 newdr->aux = (void *) (-1 - tree_to_uhwi (arg2));
4397 free_data_ref (dr);
4398 datarefs->safe_push (newdr);
4399 if (dataref_groups)
4400 dataref_groups->safe_push (group_id);
4401 return opt_result::success ();
4402 }
4403 }
4404 }
4405 }
4406 free_data_ref (newdr);
4407 }
4408
4409 datarefs->safe_push (dr);
4410 if (dataref_groups)
4411 dataref_groups->safe_push (group_id);
4412 return opt_result::success ();
4413}
4414
4415/* Function vect_analyze_data_refs.
4416
4417 Find all the data references in the loop or basic block.
4418
4419 The general structure of the analysis of data refs in the vectorizer is as
4420 follows:
4421 1- vect_analyze_data_refs(loop/bb): call
4422 compute_data_dependences_for_loop/bb to find and analyze all data-refs
4423 in the loop/bb and their dependences.
4424 2- vect_analyze_dependences(): apply dependence testing using ddrs.
4425 3- vect_analyze_drs_alignment(): check that ref_stmt.alignment is ok.
4426 4- vect_analyze_drs_access(): check that ref_stmt.step is ok.
4427
4428*/
4429
4430opt_result
4431vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf, bool *fatal)
4432{
4433 class loop *loop = NULLnullptr;
4434 unsigned int i;
4435 struct data_reference *dr;
4436 tree scalar_type;
4437
4438 DUMP_VECT_SCOPE ("vect_analyze_data_refs")auto_dump_scope scope ("vect_analyze_data_refs", vect_location
)
;
4439
4440 if (loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo))
4441 loop = LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop;
4442
4443 /* Go through the data-refs, check that the analysis succeeded. Update
4444 pointer from stmt_vec_info struct to DR and vectype. */
4445
4446 vec<data_reference_p> datarefs = vinfo->shared->datarefs;
4447 FOR_EACH_VEC_ELT (datarefs, i, dr)for (i = 0; (datarefs).iterate ((i), &(dr)); ++(i))
4448 {
4449 enum { SG_NONE, GATHER, SCATTER } gatherscatter = SG_NONE;
4450 poly_uint64 vf;
4451
4452 gcc_assert (DR_REF (dr))((void)(!((dr)->ref) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4452, __FUNCTION__), 0 : 0))
;
4453 stmt_vec_info stmt_info = vinfo->lookup_stmt (DR_STMT (dr)(dr)->stmt);
4454 gcc_assert (!stmt_info->dr_aux.dr)((void)(!(!stmt_info->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4454, __FUNCTION__), 0 : 0))
;
4455 stmt_info->dr_aux.dr = dr;
4456 stmt_info->dr_aux.stmt = stmt_info;
4457
4458 /* Check that analysis of the data-ref succeeded. */
4459 if (!DR_BASE_ADDRESS (dr)(dr)->innermost.base_address || !DR_OFFSET (dr)(dr)->innermost.offset || !DR_INIT (dr)(dr)->innermost.init
4460 || !DR_STEP (dr)(dr)->innermost.step)
4461 {
4462 bool maybe_gather
4463 = DR_IS_READ (dr)(dr)->is_read
4464 && !TREE_THIS_VOLATILE (DR_REF (dr))(((dr)->ref)->base.volatile_flag);
4465 bool maybe_scatter
4466 = DR_IS_WRITE (dr)(!(dr)->is_read)
4467 && !TREE_THIS_VOLATILE (DR_REF (dr))(((dr)->ref)->base.volatile_flag)
4468 && (targetm.vectorize.builtin_scatter != NULLnullptr
4469 || supports_vec_scatter_store_p ());
4470
4471 /* If target supports vector gather loads or scatter stores,
4472 see if they can't be used. */
4473 if (is_a <loop_vec_info> (vinfo)
4474 && !nested_in_vect_loop_p (loop, stmt_info))
4475 {
4476 if (maybe_gather || maybe_scatter)
4477 {
4478 if (maybe_gather)
4479 gatherscatter = GATHER;
4480 else
4481 gatherscatter = SCATTER;
4482 }
4483 }
4484
4485 if (gatherscatter == SG_NONE)
4486 {
4487 if (dump_enabled_p ())
4488 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4489 "not vectorized: data ref analysis "
4490 "failed %G", stmt_info->stmt);
4491 if (is_a <bb_vec_info> (vinfo))
4492 {
4493 /* In BB vectorization the ref can still participate
4494 in dependence analysis, we just can't vectorize it. */
4495 STMT_VINFO_VECTORIZABLE (stmt_info)(stmt_info)->vectorizable = false;
4496 continue;
4497 }
4498 return opt_result::failure_at (stmt_info->stmt,
4499 "not vectorized:"
4500 " data ref analysis failed: %G",
4501 stmt_info->stmt);
4502 }
4503 }
4504
4505 /* See if this was detected as SIMD lane access. */
4506 if (dr->aux == (void *)-1
4507 || dr->aux == (void *)-2
4508 || dr->aux == (void *)-3
4509 || dr->aux == (void *)-4)
4510 {
4511 if (nested_in_vect_loop_p (loop, stmt_info))
4512 return opt_result::failure_at (stmt_info->stmt,
4513 "not vectorized:"
4514 " data ref analysis failed: %G",
4515 stmt_info->stmt);
4516 STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info)(stmt_info)->simd_lane_access_p
4517 = -(uintptr_t) dr->aux;
4518 }
4519
4520 tree base = get_base_address (DR_REF (dr)(dr)->ref);
4521 if (base && VAR_P (base)(((enum tree_code) (base)->base.code) == VAR_DECL) && DECL_NONALIASED (base)((tree_check ((base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4521, __FUNCTION__, (VAR_DECL)))->base.nothrow_flag)
)
4522 {
4523 if (dump_enabled_p ())
4524 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4525 "not vectorized: base object not addressable "
4526 "for stmt: %G", stmt_info->stmt);
4527 if (is_a <bb_vec_info> (vinfo))
4528 {
4529 /* In BB vectorization the ref can still participate
4530 in dependence analysis, we just can't vectorize it. */
4531 STMT_VINFO_VECTORIZABLE (stmt_info)(stmt_info)->vectorizable = false;
4532 continue;
4533 }
4534 return opt_result::failure_at (stmt_info->stmt,
4535 "not vectorized: base object not"
4536 " addressable for stmt: %G",
4537 stmt_info->stmt);
4538 }
4539
4540 if (is_a <loop_vec_info> (vinfo)
4541 && DR_STEP (dr)(dr)->innermost.step
4542 && TREE_CODE (DR_STEP (dr))((enum tree_code) ((dr)->innermost.step)->base.code) != INTEGER_CST)
4543 {
4544 if (nested_in_vect_loop_p (loop, stmt_info))
4545 return opt_result::failure_at (stmt_info->stmt,
4546 "not vectorized: "
4547 "not suitable for strided load %G",
4548 stmt_info->stmt);
4549 STMT_VINFO_STRIDED_P (stmt_info)(stmt_info)->strided_p = true;
4550 }
4551
4552 /* Update DR field in stmt_vec_info struct. */
4553
4554 /* If the dataref is in an inner-loop of the loop that is considered for
4555 for vectorization, we also want to analyze the access relative to
4556 the outer-loop (DR contains information only relative to the
4557 inner-most enclosing loop). We do that by building a reference to the
4558 first location accessed by the inner-loop, and analyze it relative to
4559 the outer-loop. */
4560 if (loop && nested_in_vect_loop_p (loop, stmt_info))
4561 {
4562 /* Build a reference to the first location accessed by the
4563 inner loop: *(BASE + INIT + OFFSET). By construction,
4564 this address must be invariant in the inner loop, so we
4565 can consider it as being used in the outer loop. */
4566 tree base = unshare_expr (DR_BASE_ADDRESS (dr)(dr)->innermost.base_address);
4567 tree offset = unshare_expr (DR_OFFSET (dr)(dr)->innermost.offset);
4568 tree init = unshare_expr (DR_INIT (dr)(dr)->innermost.init);
4569 tree init_offset = fold_build2 (PLUS_EXPR, TREE_TYPE (offset),fold_build2_loc (((location_t) 0), PLUS_EXPR, ((contains_struct_check
((offset), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4569, __FUNCTION__))->typed.type), init, offset )
4570 init, offset)fold_build2_loc (((location_t) 0), PLUS_EXPR, ((contains_struct_check
((offset), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4569, __FUNCTION__))->typed.type), init, offset )
;
4571 tree init_addr = fold_build_pointer_plus (base, init_offset)fold_build_pointer_plus_loc (((location_t) 0), base, init_offset
)
;
4572 tree init_ref = build_fold_indirect_ref (init_addr)build_fold_indirect_ref_loc (((location_t) 0), init_addr);
4573
4574 if (dump_enabled_p ())
4575 dump_printf_loc (MSG_NOTE, vect_location,
4576 "analyze in outer loop: %T\n", init_ref);
4577
4578 opt_result res
4579 = dr_analyze_innermost (&STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info)(stmt_info)->dr_wrt_vec_loop,
4580 init_ref, loop, stmt_info->stmt);
4581 if (!res)
4582 /* dr_analyze_innermost already explained the failure. */
4583 return res;
4584
4585 if (dump_enabled_p ())
4586 dump_printf_loc (MSG_NOTE, vect_location,
4587 "\touter base_address: %T\n"
4588 "\touter offset from base address: %T\n"
4589 "\touter constant offset from base address: %T\n"
4590 "\touter step: %T\n"
4591 "\touter base alignment: %d\n\n"
4592 "\touter base misalignment: %d\n"
4593 "\touter offset alignment: %d\n"
4594 "\touter step alignment: %d\n",
4595 STMT_VINFO_DR_BASE_ADDRESS (stmt_info)(stmt_info)->dr_wrt_vec_loop.base_address,
4596 STMT_VINFO_DR_OFFSET (stmt_info)(stmt_info)->dr_wrt_vec_loop.offset,
4597 STMT_VINFO_DR_INIT (stmt_info)(stmt_info)->dr_wrt_vec_loop.init,
4598 STMT_VINFO_DR_STEP (stmt_info)(stmt_info)->dr_wrt_vec_loop.step,
4599 STMT_VINFO_DR_BASE_ALIGNMENT (stmt_info)(stmt_info)->dr_wrt_vec_loop.base_alignment,
4600 STMT_VINFO_DR_BASE_MISALIGNMENT (stmt_info)(stmt_info)->dr_wrt_vec_loop.base_misalignment,
4601 STMT_VINFO_DR_OFFSET_ALIGNMENT (stmt_info)(stmt_info)->dr_wrt_vec_loop.offset_alignment,
4602 STMT_VINFO_DR_STEP_ALIGNMENT (stmt_info)(stmt_info)->dr_wrt_vec_loop.step_alignment);
4603 }
4604
4605 /* Set vectype for STMT. */
4606 scalar_type = TREE_TYPE (DR_REF (dr))((contains_struct_check (((dr)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4606, __FUNCTION__))->typed.type)
;
4607 tree vectype = get_vectype_for_scalar_type (vinfo, scalar_type);
4608 if (!vectype)
4609 {
4610 if (dump_enabled_p ())
4611 {
4612 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
4613 "not vectorized: no vectype for stmt: %G",
4614 stmt_info->stmt);
4615 dump_printf (MSG_MISSED_OPTIMIZATION, " scalar_type: ");
4616 dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_DETAILS,
4617 scalar_type);
4618 dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
4619 }
4620
4621 if (is_a <bb_vec_info> (vinfo))
4622 {
4623 /* No vector type is fine, the ref can still participate
4624 in dependence analysis, we just can't vectorize it. */
4625 STMT_VINFO_VECTORIZABLE (stmt_info)(stmt_info)->vectorizable = false;
4626 continue;
4627 }
4628 if (fatal)
4629 *fatal = false;
4630 return opt_result::failure_at (stmt_info->stmt,
4631 "not vectorized:"
4632 " no vectype for stmt: %G"
4633 " scalar_type: %T\n",
4634 stmt_info->stmt, scalar_type);
4635 }
4636 else
4637 {
4638 if (dump_enabled_p ())
4639 dump_printf_loc (MSG_NOTE, vect_location,
4640 "got vectype for stmt: %G%T\n",
4641 stmt_info->stmt, vectype);
4642 }
4643
4644 /* Adjust the minimal vectorization factor according to the
4645 vector type. */
4646 vf = TYPE_VECTOR_SUBPARTS (vectype);
4647 *min_vf = upper_bound (*min_vf, vf);
4648
4649 /* Leave the BB vectorizer to pick the vector type later, based on
4650 the final dataref group size and SLP node size. */
4651 if (is_a <loop_vec_info> (vinfo))
4652 STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype = vectype;
4653
4654 if (gatherscatter != SG_NONE)
4655 {
4656 gather_scatter_info gs_info;
4657 if (!vect_check_gather_scatter (stmt_info,
4658 as_a <loop_vec_info> (vinfo),
4659 &gs_info)
4660 || !get_vectype_for_scalar_type (vinfo,
4661 TREE_TYPE (gs_info.offset)((contains_struct_check ((gs_info.offset), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4661, __FUNCTION__))->typed.type)
))
4662 {
4663 if (fatal)
4664 *fatal = false;
4665 return opt_result::failure_at
4666 (stmt_info->stmt,
4667 (gatherscatter == GATHER)
4668 ? "not vectorized: not suitable for gather load %G"
4669 : "not vectorized: not suitable for scatter store %G",
4670 stmt_info->stmt);
4671 }
4672 STMT_VINFO_GATHER_SCATTER_P (stmt_info)(stmt_info)->gather_scatter_p = gatherscatter;
4673 }
4674 }
4675
4676 /* We used to stop processing and prune the list here. Verify we no
4677 longer need to. */
4678 gcc_assert (i == datarefs.length ())((void)(!(i == datarefs.length ()) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4678, __FUNCTION__), 0 : 0))
;
4679
4680 return opt_result::success ();
4681}
4682
4683
4684/* Function vect_get_new_vect_var.
4685
4686 Returns a name for a new variable. The current naming scheme appends the
4687 prefix "vect_" or "vect_p" (depending on the value of VAR_KIND) to
4688 the name of vectorizer generated variables, and appends that to NAME if
4689 provided. */
4690
4691tree
4692vect_get_new_vect_var (tree type, enum vect_var_kind var_kind, const char *name)
4693{
4694 const char *prefix;
4695 tree new_vect_var;
4696
4697 switch (var_kind)
4698 {
4699 case vect_simple_var:
4700 prefix = "vect";
4701 break;
4702 case vect_scalar_var:
4703 prefix = "stmp";
4704 break;
4705 case vect_mask_var:
4706 prefix = "mask";
4707 break;
4708 case vect_pointer_var:
4709 prefix = "vectp";
4710 break;
4711 default:
4712 gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4712, __FUNCTION__))
;
4713 }
4714
4715 if (name)
4716 {
4717 char* tmp = concat (prefix, "_", name, NULLnullptr);
4718 new_vect_var = create_tmp_reg (type, tmp);
4719 free (tmp);
4720 }
4721 else
4722 new_vect_var = create_tmp_reg (type, prefix);
4723
4724 return new_vect_var;
4725}
4726
4727/* Like vect_get_new_vect_var but return an SSA name. */
4728
4729tree
4730vect_get_new_ssa_name (tree type, enum vect_var_kind var_kind, const char *name)
4731{
4732 const char *prefix;
4733 tree new_vect_var;
4734
4735 switch (var_kind)
4736 {
4737 case vect_simple_var:
4738 prefix = "vect";
4739 break;
4740 case vect_scalar_var:
4741 prefix = "stmp";
4742 break;
4743 case vect_pointer_var:
4744 prefix = "vectp";
4745 break;
4746 default:
4747 gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4747, __FUNCTION__))
;
4748 }
4749
4750 if (name)
4751 {
4752 char* tmp = concat (prefix, "_", name, NULLnullptr);
4753 new_vect_var = make_temp_ssa_name (type, NULLnullptr, tmp);
4754 free (tmp);
4755 }
4756 else
4757 new_vect_var = make_temp_ssa_name (type, NULLnullptr, prefix);
4758
4759 return new_vect_var;
4760}
4761
4762/* Duplicate points-to info on NAME from DR_INFO. */
4763
4764static void
4765vect_duplicate_ssa_name_ptr_info (tree name, dr_vec_info *dr_info)
4766{
4767 duplicate_ssa_name_ptr_info (name, DR_PTR_INFO (dr_info->dr)(dr_info->dr)->alias.ptr_info);
4768 /* DR_PTR_INFO is for a base SSA name, not including constant or
4769 variable offsets in the ref so its alignment info does not apply. */
4770 mark_ptr_info_alignment_unknown (SSA_NAME_PTR_INFO (name)(tree_check ((name), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4770, __FUNCTION__, (SSA_NAME)))->ssa_name.info.ptr_info
);
4771}
4772
4773/* Function vect_create_addr_base_for_vector_ref.
4774
4775 Create an expression that computes the address of the first memory location
4776 that will be accessed for a data reference.
4777
4778 Input:
4779 STMT_INFO: The statement containing the data reference.
4780 NEW_STMT_LIST: Must be initialized to NULL_TREE or a statement list.
4781 OFFSET: Optional. If supplied, it is be added to the initial address.
4782 LOOP: Specify relative to which loop-nest should the address be computed.
4783 For example, when the dataref is in an inner-loop nested in an
4784 outer-loop that is now being vectorized, LOOP can be either the
4785 outer-loop, or the inner-loop. The first memory location accessed
4786 by the following dataref ('in' points to short):
4787
4788 for (i=0; i<N; i++)
4789 for (j=0; j<M; j++)
4790 s += in[i+j]
4791
4792 is as follows:
4793 if LOOP=i_loop: &in (relative to i_loop)
4794 if LOOP=j_loop: &in+i*2B (relative to j_loop)
4795
4796 Output:
4797 1. Return an SSA_NAME whose value is the address of the memory location of
4798 the first vector of the data reference.
4799 2. If new_stmt_list is not NULL_TREE after return then the caller must insert
4800 these statement(s) which define the returned SSA_NAME.
4801
4802 FORNOW: We are only handling array accesses with step 1. */
4803
4804tree
4805vect_create_addr_base_for_vector_ref (vec_info *vinfo, stmt_vec_info stmt_info,
4806 gimple_seq *new_stmt_list,
4807 tree offset)
4808{
4809 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info)(((void)(!((stmt_info)->dr_aux.stmt == (stmt_info)) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4809, __FUNCTION__), 0 : 0)), &(stmt_info)->dr_aux)
;
4810 struct data_reference *dr = dr_info->dr;
4811 const char *base_name;
4812 tree addr_base;
4813 tree dest;
4814 gimple_seq seq = NULLnullptr;
4815 tree vect_ptr_type;
4816 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
4817 innermost_loop_behavior *drb = vect_dr_behavior (vinfo, dr_info);
4818
4819 tree data_ref_base = unshare_expr (drb->base_address);
4820 tree base_offset = unshare_expr (get_dr_vinfo_offset (vinfo, dr_info, true));
4821 tree init = unshare_expr (drb->init);
4822
4823 if (loop_vinfo)
4824 base_name = get_name (data_ref_base);
4825 else
4826 {
4827 base_offset = ssize_int (0)size_int_kind (0, stk_ssizetype);
4828 init = ssize_int (0)size_int_kind (0, stk_ssizetype);
4829 base_name = get_name (DR_REF (dr)(dr)->ref);
4830 }
4831
4832 /* Create base_offset */
4833 base_offset = size_binop (PLUS_EXPR,size_binop_loc (((location_t) 0), PLUS_EXPR, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], base_offset
), fold_convert_loc (((location_t) 0), sizetype_tab[(int) stk_sizetype
], init))
4834 fold_convert (sizetype, base_offset),size_binop_loc (((location_t) 0), PLUS_EXPR, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], base_offset
), fold_convert_loc (((location_t) 0), sizetype_tab[(int) stk_sizetype
], init))
4835 fold_convert (sizetype, init))size_binop_loc (((location_t) 0), PLUS_EXPR, fold_convert_loc
(((location_t) 0), sizetype_tab[(int) stk_sizetype], base_offset
), fold_convert_loc (((location_t) 0), sizetype_tab[(int) stk_sizetype
], init))
;
4836
4837 if (offset)
4838 {
4839 offset = fold_convert (sizetype, offset)fold_convert_loc (((location_t) 0), sizetype_tab[(int) stk_sizetype
], offset)
;
4840 base_offset = fold_build2 (PLUS_EXPR, sizetype,fold_build2_loc (((location_t) 0), PLUS_EXPR, sizetype_tab[(int
) stk_sizetype], base_offset, offset )
4841 base_offset, offset)fold_build2_loc (((location_t) 0), PLUS_EXPR, sizetype_tab[(int
) stk_sizetype], base_offset, offset )
;
4842 }
4843
4844 /* base + base_offset */
4845 if (loop_vinfo)
4846 addr_base = fold_build_pointer_plus (data_ref_base, base_offset)fold_build_pointer_plus_loc (((location_t) 0), data_ref_base,
base_offset)
;
4847 else
4848 addr_base = build1 (ADDR_EXPR,
4849 build_pointer_type (TREE_TYPE (DR_REF (dr))((contains_struct_check (((dr)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4849, __FUNCTION__))->typed.type)
),
4850 /* Strip zero offset components since we don't need
4851 them and they can confuse late diagnostics if
4852 we CSE them wrongly. See PR106904 for example. */
4853 unshare_expr (strip_zero_offset_components
4854 (DR_REF (dr)(dr)->ref)));
4855
4856 vect_ptr_type = build_pointer_type (TREE_TYPE (DR_REF (dr))((contains_struct_check (((dr)->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4856, __FUNCTION__))->typed.type)
);
4857 dest = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var, base_name);
4858 addr_base = force_gimple_operand (addr_base, &seq, true, dest);
4859 gimple_seq_add_seq (new_stmt_list, seq);
4860
4861 if (DR_PTR_INFO (dr)(dr)->alias.ptr_info
4862 && TREE_CODE (addr_base)((enum tree_code) (addr_base)->base.code) == SSA_NAME
4863 /* We should only duplicate pointer info to newly created SSA names. */
4864 && SSA_NAME_VAR (addr_base)((tree_check ((addr_base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4864, __FUNCTION__, (SSA_NAME)))->ssa_name.var == (tree)
nullptr || ((enum tree_code) ((addr_base)->ssa_name.var)->
base.code) == IDENTIFIER_NODE ? (tree) nullptr : (addr_base)->
ssa_name.var)
== dest)
4865 {
4866 gcc_assert (!SSA_NAME_PTR_INFO (addr_base))((void)(!(!(tree_check ((addr_base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4866, __FUNCTION__, (SSA_NAME)))->ssa_name.info.ptr_info
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4866, __FUNCTION__), 0 : 0))
;
4867 vect_duplicate_ssa_name_ptr_info (addr_base, dr_info);
4868 }
4869
4870 if (dump_enabled_p ())
4871 dump_printf_loc (MSG_NOTE, vect_location, "created %T\n", addr_base);
4872
4873 return addr_base;
4874}
4875
4876
4877/* Function vect_create_data_ref_ptr.
4878
4879 Create a new pointer-to-AGGR_TYPE variable (ap), that points to the first
4880 location accessed in the loop by STMT_INFO, along with the def-use update
4881 chain to appropriately advance the pointer through the loop iterations.
4882 Also set aliasing information for the pointer. This pointer is used by
4883 the callers to this function to create a memory reference expression for
4884 vector load/store access.
4885
4886 Input:
4887 1. STMT_INFO: a stmt that references memory. Expected to be of the form
4888 GIMPLE_ASSIGN <name, data-ref> or
4889 GIMPLE_ASSIGN <data-ref, name>.
4890 2. AGGR_TYPE: the type of the reference, which should be either a vector
4891 or an array.
4892 3. AT_LOOP: the loop where the vector memref is to be created.
4893 4. OFFSET (optional): a byte offset to be added to the initial address
4894 accessed by the data-ref in STMT_INFO.
4895 5. BSI: location where the new stmts are to be placed if there is no loop
4896 6. ONLY_INIT: indicate if ap is to be updated in the loop, or remain
4897 pointing to the initial address.
4898 8. IV_STEP (optional, defaults to NULL): the amount that should be added
4899 to the IV during each iteration of the loop. NULL says to move
4900 by one copy of AGGR_TYPE up or down, depending on the step of the
4901 data reference.
4902
4903 Output:
4904 1. Declare a new ptr to vector_type, and have it point to the base of the
4905 data reference (initial addressed accessed by the data reference).
4906 For example, for vector of type V8HI, the following code is generated:
4907
4908 v8hi *ap;
4909 ap = (v8hi *)initial_address;
4910
4911 if OFFSET is not supplied:
4912 initial_address = &a[init];
4913 if OFFSET is supplied:
4914 initial_address = &a[init] + OFFSET;
4915 if BYTE_OFFSET is supplied:
4916 initial_address = &a[init] + BYTE_OFFSET;
4917
4918 Return the initial_address in INITIAL_ADDRESS.
4919
4920 2. If ONLY_INIT is true, just return the initial pointer. Otherwise, also
4921 update the pointer in each iteration of the loop.
4922
4923 Return the increment stmt that updates the pointer in PTR_INCR.
4924
4925 3. Return the pointer. */
4926
4927tree
4928vect_create_data_ref_ptr (vec_info *vinfo, stmt_vec_info stmt_info,
4929 tree aggr_type, class loop *at_loop, tree offset,
4930 tree *initial_address, gimple_stmt_iterator *gsi,
4931 gimple **ptr_incr, bool only_init,
4932 tree iv_step)
4933{
4934 const char *base_name;
4935 loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
4936 class loop *loop = NULLnullptr;
4937 bool nested_in_vect_loop = false;
4938 class loop *containing_loop = NULLnullptr;
4939 tree aggr_ptr_type;
4940 tree aggr_ptr;
4941 tree new_temp;
4942 gimple_seq new_stmt_list = NULLnullptr;
4943 edge pe = NULLnullptr;
4944 basic_block new_bb;
4945 tree aggr_ptr_init;
4946 dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info)(((void)(!((stmt_info)->dr_aux.stmt == (stmt_info)) ? fancy_abort
("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4946, __FUNCTION__), 0 : 0)), &(stmt_info)->dr_aux)
;
4947 struct data_reference *dr = dr_info->dr;
4948 tree aptr;
4949 gimple_stmt_iterator incr_gsi;
4950 bool insert_after;
4951 tree indx_before_incr, indx_after_incr;
4952 gimple *incr;
4953 bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
4954
4955 gcc_assert (iv_step != NULL_TREE((void)(!(iv_step != (tree) nullptr || ((enum tree_code) (aggr_type
)->base.code) == ARRAY_TYPE || ((enum tree_code) (aggr_type
)->base.code) == VECTOR_TYPE) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4957, __FUNCTION__), 0 : 0))
4956 || TREE_CODE (aggr_type) == ARRAY_TYPE((void)(!(iv_step != (tree) nullptr || ((enum tree_code) (aggr_type
)->base.code) == ARRAY_TYPE || ((enum tree_code) (aggr_type
)->base.code) == VECTOR_TYPE) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4957, __FUNCTION__), 0 : 0))
4957 || TREE_CODE (aggr_type) == VECTOR_TYPE)((void)(!(iv_step != (tree) nullptr || ((enum tree_code) (aggr_type
)->base.code) == ARRAY_TYPE || ((enum tree_code) (aggr_type
)->base.code) == VECTOR_TYPE) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4957, __FUNCTION__), 0 : 0))
;
4958
4959 if (loop_vinfo)
4960 {
4961 loop = LOOP_VINFO_LOOP (loop_vinfo)(loop_vinfo)->loop;
4962 nested_in_vect_loop = nested_in_vect_loop_p (loop, stmt_info);
4963 containing_loop = (gimple_bb (stmt_info->stmt))->loop_father;
4964 pe = loop_preheader_edge (loop);
4965 }
4966 else
4967 {
4968 gcc_assert (bb_vinfo)((void)(!(bb_vinfo) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4968, __FUNCTION__), 0 : 0))
;
4969 only_init = true;
4970 *ptr_incr = NULLnullptr;
4971 }
4972
4973 /* Create an expression for the first address accessed by this load
4974 in LOOP. */
4975 base_name = get_name (DR_BASE_ADDRESS (dr)(dr)->innermost.base_address);
4976
4977 if (dump_enabled_p ())
4978 {
4979 tree dr_base_type = TREE_TYPE (DR_BASE_OBJECT (dr))((contains_struct_check (((dr)->indices.base_object), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 4979, __FUNCTION__))->typed.type)
;
4980 dump_printf_loc (MSG_NOTE, vect_location,
4981 "create %s-pointer variable to type: %T",
4982 get_tree_code_name (TREE_CODE (aggr_type)((enum tree_code) (aggr_type)->base.code)),
4983 aggr_type);
4984 if (TREE_CODE (dr_base_type)((enum tree_code) (dr_base_type)->base.code) == ARRAY_TYPE)
4985 dump_printf (MSG_NOTE, " vectorizing an array ref: ");
4986 else if (TREE_CODE (dr_base_type)((enum tree_code) (dr_base_type)->base.code) == VECTOR_TYPE)
4987 dump_printf (MSG_NOTE, " vectorizing a vector ref: ");
4988 else if (TREE_CODE (dr_base_type)((enum tree_code) (dr_base_type)->base.code) == RECORD_TYPE)
4989 dump_printf (MSG_NOTE, " vectorizing a record based array ref: ");
4990 else
4991 dump_printf (MSG_NOTE, " vectorizing a pointer ref: ");
4992 dump_printf (MSG_NOTE, "%T\n", DR_BASE_OBJECT (dr)(dr)->indices.base_object);
4993 }
4994
4995 /* (1) Create the new aggregate-pointer variable.
4996 Vector and array types inherit the alias set of their component
4997 type by default so we need to use a ref-all pointer if the data
4998 reference does not conflict with the created aggregated data
4999 reference because it is not addressable. */
5000 bool need_ref_all = false;
5001 if (!alias_sets_conflict_p (get_alias_set (aggr_type),
5002 get_alias_set (DR_REF (dr)(dr)->ref)))
5003 need_ref_all = true;
5004 /* Likewise for any of the data references in the stmt group. */
5005 else if (DR_GROUP_SIZE (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5005, __FUNCTION__), 0 : 0)), (stmt_info)->size)
> 1)
5006 {
5007 stmt_vec_info sinfo = DR_GROUP_FIRST_ELEMENT (stmt_info)(((void)(!((stmt_info)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5007, __FUNCTION__), 0 : 0)), (stmt_info)->first_element
)
;
5008 do
5009 {
5010 struct data_reference *sdr = STMT_VINFO_DATA_REF (sinfo)((sinfo)->dr_aux.dr + 0);
5011 if (!alias_sets_conflict_p (get_alias_set (aggr_type),
5012 get_alias_set (DR_REF (sdr)(sdr)->ref)))
5013 {
5014 need_ref_all = true;
5015 break;
5016 }
5017 sinfo = DR_GROUP_NEXT_ELEMENT (sinfo)(((void)(!((sinfo)->dr_aux.dr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5017, __FUNCTION__), 0 : 0)), (sinfo)->next_element)
;
5018 }
5019 while (sinfo);
5020 }
5021 aggr_ptr_type = build_pointer_type_for_mode (aggr_type, ptr_mode,
5022 need_ref_all);
5023 aggr_ptr = vect_get_new_vect_var (aggr_ptr_type, vect_pointer_var, base_name);
5024
5025
5026 /* Note: If the dataref is in an inner-loop nested in LOOP, and we are
5027 vectorizing LOOP (i.e., outer-loop vectorization), we need to create two
5028 def-use update cycles for the pointer: one relative to the outer-loop
5029 (LOOP), which is what steps (3) and (4) below do. The other is relative
5030 to the inner-loop (which is the inner-most loop containing the dataref),
5031 and this is done be step (5) below.
5032
5033 When vectorizing inner-most loops, the vectorized loop (LOOP) is also the
5034 inner-most loop, and so steps (3),(4) work the same, and step (5) is
5035 redundant. Steps (3),(4) create the following:
5036
5037 vp0 = &base_addr;
5038 LOOP: vp1 = phi(vp0,vp2)
5039 ...
5040 ...
5041 vp2 = vp1 + step
5042 goto LOOP
5043
5044 If there is an inner-loop nested in loop, then step (5) will also be
5045 applied, and an additional update in the inner-loop will be created:
5046
5047 vp0 = &base_addr;
5048 LOOP: vp1 = phi(vp0,vp2)
5049 ...
5050 inner: vp3 = phi(vp1,vp4)
5051 vp4 = vp3 + inner_step
5052 if () goto inner
5053 ...
5054 vp2 = vp1 + step
5055 if () goto LOOP */
5056
5057 /* (2) Calculate the initial address of the aggregate-pointer, and set
5058 the aggregate-pointer to point to it before the loop. */
5059
5060 /* Create: (&(base[init_val]+offset) in the loop preheader. */
5061
5062 new_temp = vect_create_addr_base_for_vector_ref (vinfo,
5063 stmt_info, &new_stmt_list,
5064 offset);
5065 if (new_stmt_list)
5066 {
5067 if (pe)
5068 {
5069 new_bb = gsi_insert_seq_on_edge_immediate (pe, new_stmt_list);
5070 gcc_assert (!new_bb)((void)(!(!new_bb) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5070, __FUNCTION__), 0 : 0))
;
5071 }
5072 else
5073 gsi_insert_seq_before (gsi, new_stmt_list, GSI_SAME_STMT);
5074 }
5075
5076 *initial_address = new_temp;
5077 aggr_ptr_init = new_temp;
5078
5079 /* (3) Handle the updating of the aggregate-pointer inside the loop.
5080 This is needed when ONLY_INIT is false, and also when AT_LOOP is the
5081 inner-loop nested in LOOP (during outer-loop vectorization). */
5082
5083 /* No update in loop is required. */
5084 if (only_init && (!loop_vinfo || at_loop == loop))
5085 aptr = aggr_ptr_init;
5086 else
5087 {
5088 /* Accesses to invariant addresses should be handled specially
5089 by the caller. */
5090 tree step = vect_dr_behavior (vinfo, dr_info)->step;
5091 gcc_assert (!integer_zerop (step))((void)(!(!integer_zerop (step)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5091, __FUNCTION__), 0 : 0))
;
5092
5093 if (iv_step == NULL_TREE(tree) nullptr)
5094 {
5095 /* The step of the aggregate pointer is the type size,
5096 negated for downward accesses. */
5097 iv_step = TYPE_SIZE_UNIT (aggr_type)((tree_class_check ((aggr_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5097, __FUNCTION__))->type_common.size_unit)
;
5098 if (tree_int_cst_sgn (step) == -1)
5099 iv_step = fold_build1 (NEGATE_EXPR, TREE_TYPE (iv_step), iv_step)fold_build1_loc (((location_t) 0), NEGATE_EXPR, ((contains_struct_check
((iv_step), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5099, __FUNCTION__))->typed.type), iv_step )
;
5100 }
5101
5102 standard_iv_increment_position (loop, &incr_gsi, &insert_after);
5103
5104 create_iv (aggr_ptr_init,
5105 fold_convert (aggr_ptr_type, iv_step)fold_convert_loc (((location_t) 0), aggr_ptr_type, iv_step),
5106 aggr_ptr, loop, &incr_gsi, insert_after,
5107 &indx_before_incr, &indx_after_incr);
5108 incr = gsi_stmt (incr_gsi);
5109
5110 /* Copy the points-to information if it exists. */
5111 if (DR_PTR_INFO (dr)(dr)->alias.ptr_info)
5112 {
5113 vect_duplicate_ssa_name_ptr_info (indx_before_incr, dr_info);
5114 vect_duplicate_ssa_name_ptr_info (indx_after_incr, dr_info);
5115 }
5116 if (ptr_incr)
5117 *ptr_incr = incr;
5118
5119 aptr = indx_before_incr;
5120 }
5121
5122 if (!nested_in_vect_loop || only_init)
5123 return aptr;
5124
5125
5126 /* (4) Handle the updating of the aggregate-pointer inside the inner-loop
5127 nested in LOOP, if exists. */
5128
5129 gcc_assert (nested_in_vect_loop)((void)(!(nested_in_vect_loop) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5129, __FUNCTION__), 0 : 0))
;
5130 if (!only_init)
5131 {
5132 standard_iv_increment_position (containing_loop, &incr_gsi,
5133 &insert_after);
5134 create_iv (aptr, fold_convert (aggr_ptr_type, DR_STEP (dr))fold_convert_loc (((location_t) 0), aggr_ptr_type, (dr)->innermost
.step)
, aggr_ptr,
5135 containing_loop, &incr_gsi, insert_after, &indx_before_incr,
5136 &indx_after_incr);
5137 incr = gsi_stmt (incr_gsi);
5138
5139 /* Copy the points-to information if it exists. */
5140 if (DR_PTR_INFO (dr)(dr)->alias.ptr_info)
5141 {
5142 vect_duplicate_ssa_name_ptr_info (indx_before_incr, dr_info);
5143 vect_duplicate_ssa_name_ptr_info (indx_after_incr, dr_info);
5144 }
5145 if (ptr_incr)
5146 *ptr_incr = incr;
5147
5148 return indx_before_incr;
5149 }
5150 else
5151 gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5151, __FUNCTION__))
;
5152}
5153
5154
5155/* Function bump_vector_ptr
5156
5157 Increment a pointer (to a vector type) by vector-size. If requested,
5158 i.e. if PTR-INCR is given, then also connect the new increment stmt
5159 to the existing def-use update-chain of the pointer, by modifying
5160 the PTR_INCR as illustrated below:
5161
5162 The pointer def-use update-chain before this function:
5163 DATAREF_PTR = phi (p_0, p_2)
5164 ....
5165 PTR_INCR: p_2 = DATAREF_PTR + step
5166
5167 The pointer def-use update-chain after this function:
5168 DATAREF_PTR = phi (p_0, p_2)
5169 ....
5170 NEW_DATAREF_PTR = DATAREF_PTR + BUMP
5171 ....
5172 PTR_INCR: p_2 = NEW_DATAREF_PTR + step
5173
5174 Input:
5175 DATAREF_PTR - ssa_name of a pointer (to vector type) that is being updated
5176 in the loop.
5177 PTR_INCR - optional. The stmt that updates the pointer in each iteration of
5178 the loop. The increment amount across iterations is expected
5179 to be vector_size.
5180 BSI - location where the new update stmt is to be placed.
5181 STMT_INFO - the original scalar memory-access stmt that is being vectorized.
5182 BUMP - optional. The offset by which to bump the pointer. If not given,
5183 the offset is assumed to be vector_size.
5184
5185 Output: Return NEW_DATAREF_PTR as illustrated above.
5186
5187*/
5188
5189tree
5190bump_vector_ptr (vec_info *vinfo,
5191 tree dataref_ptr, gimple *ptr_incr, gimple_stmt_iterator *gsi,
5192 stmt_vec_info stmt_info, tree bump)
5193{
5194 struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info)((stmt_info)->dr_aux.dr + 0);
5195 tree vectype = STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype;
5196 tree update = TYPE_SIZE_UNIT (vectype)((tree_class_check ((vectype), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5196, __FUNCTION__))->type_common.size_unit)
;
5197 gimple *incr_stmt;
5198 ssa_op_iter iter;
5199 use_operand_p use_p;
5200 tree new_dataref_ptr;
5201
5202 if (bump)
5203 update = bump;
5204
5205 if (TREE_CODE (dataref_ptr)((enum tree_code) (dataref_ptr)->base.code) == SSA_NAME)
5206 new_dataref_ptr = copy_ssa_name (dataref_ptr);
5207 else if (is_gimple_min_invariant (dataref_ptr))
5208 /* When possible avoid emitting a separate increment stmt that will
5209 force the addressed object addressable. */
5210 return build1 (ADDR_EXPR, TREE_TYPE (dataref_ptr)((contains_struct_check ((dataref_ptr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5210, __FUNCTION__))->typed.type)
,
5211 fold_build2 (MEM_REF,fold_build2_loc (((location_t) 0), MEM_REF, ((contains_struct_check
((((contains_struct_check ((dataref_ptr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5212, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5212, __FUNCTION__))->typed.type), dataref_ptr, fold_convert_loc
(((location_t) 0), global_trees[TI_PTR_TYPE], update) )
5212 TREE_TYPE (TREE_TYPE (dataref_ptr)),fold_build2_loc (((location_t) 0), MEM_REF, ((contains_struct_check
((((contains_struct_check ((dataref_ptr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5212, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5212, __FUNCTION__))->typed.type), dataref_ptr, fold_convert_loc
(((location_t) 0), global_trees[TI_PTR_TYPE], update) )
5213 dataref_ptr,fold_build2_loc (((location_t) 0), MEM_REF, ((contains_struct_check
((((contains_struct_check ((dataref_ptr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5212, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5212, __FUNCTION__))->typed.type), dataref_ptr, fold_convert_loc
(((location_t) 0), global_trees[TI_PTR_TYPE], update) )
5214 fold_convert (ptr_type_node, update))fold_build2_loc (((location_t) 0), MEM_REF, ((contains_struct_check
((((contains_struct_check ((dataref_ptr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5212, __FUNCTION__))->typed.type)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5212, __FUNCTION__))->typed.type), dataref_ptr, fold_convert_loc
(((location_t) 0), global_trees[TI_PTR_TYPE], update) )
);
5215 else
5216 new_dataref_ptr = make_ssa_name (TREE_TYPE (dataref_ptr)((contains_struct_check ((dataref_ptr), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5216, __FUNCTION__))->typed.type)
);
5217 incr_stmt = gimple_build_assign (new_dataref_ptr, POINTER_PLUS_EXPR,
5218 dataref_ptr, update);
5219 vect_finish_stmt_generation (vinfo, stmt_info, incr_stmt, gsi);
5220 /* Fold the increment, avoiding excessive chains use-def chains of
5221 those, leading to compile-time issues for passes until the next
5222 forwprop pass which would do this as well. */
5223 gimple_stmt_iterator fold_gsi = gsi_for_stmt (incr_stmt);
5224 if (fold_stmt (&fold_gsi, follow_all_ssa_edges))
5225 {
5226 incr_stmt = gsi_stmt (fold_gsi);
5227 update_stmt (incr_stmt);
5228 }
5229
5230 /* Copy the points-to information if it exists. */
5231 if (DR_PTR_INFO (dr)(dr)->alias.ptr_info)
5232 {
5233 duplicate_ssa_name_ptr_info (new_dataref_ptr, DR_PTR_INFO (dr)(dr)->alias.ptr_info);
5234 mark_ptr_info_alignment_unknown (SSA_NAME_PTR_INFO (new_dataref_ptr)(tree_check ((new_dataref_ptr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5234, __FUNCTION__, (SSA_NAME)))->ssa_name.info.ptr_info
);
5235 }
5236
5237 if (!ptr_incr)
5238 return new_dataref_ptr;
5239
5240 /* Update the vector-pointer's cross-iteration increment. */
5241 FOR_EACH_SSA_USE_OPERAND (use_p, ptr_incr, iter, SSA_OP_USE)for (use_p = op_iter_init_use (&(iter), ptr_incr, 0x01); !
op_iter_done (&(iter)); use_p = op_iter_next_use (&(iter
)))
5242 {
5243 tree use = USE_FROM_PTR (use_p)get_use_from_ptr (use_p);
5244
5245 if (use == dataref_ptr)
5246 SET_USE (use_p, new_dataref_ptr)set_ssa_use_from_ptr (use_p, new_dataref_ptr);
5247 else
5248 gcc_assert (operand_equal_p (use, update, 0))((void)(!(operand_equal_p (use, update, 0)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5248, __FUNCTION__), 0 : 0))
;
5249 }
5250
5251 return new_dataref_ptr;
5252}
5253
5254
5255/* Copy memory reference info such as base/clique from the SRC reference
5256 to the DEST MEM_REF. */
5257
5258void
5259vect_copy_ref_info (tree dest, tree src)
5260{
5261 if (TREE_CODE (dest)((enum tree_code) (dest)->base.code) != MEM_REF)
5262 return;
5263
5264 tree src_base = src;
5265 while (handled_component_p (src_base))
5266 src_base = TREE_OPERAND (src_base, 0)(*((const_cast<tree*> (tree_operand_check ((src_base), (
0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5266, __FUNCTION__)))))
;
5267 if (TREE_CODE (src_base)((enum tree_code) (src_base)->base.code) != MEM_REF
5268 && TREE_CODE (src_base)((enum tree_code) (src_base)->base.code) != TARGET_MEM_REF)
5269 return;
5270
5271 MR_DEPENDENCE_CLIQUE (dest)((tree_check2 ((dest), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5271, __FUNCTION__, (MEM_REF), (TARGET_MEM_REF)))->base.
u.dependence_info.clique)
= MR_DEPENDENCE_CLIQUE (src_base)((tree_check2 ((src_base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5271, __FUNCTION__, (MEM_REF), (TARGET_MEM_REF)))->base.
u.dependence_info.clique)
;
5272 MR_DEPENDENCE_BASE (dest)((tree_check2 ((dest), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5272, __FUNCTION__, (MEM_REF), (TARGET_MEM_REF)))->base.
u.dependence_info.base)
= MR_DEPENDENCE_BASE (src_base)((tree_check2 ((src_base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5272, __FUNCTION__, (MEM_REF), (TARGET_MEM_REF)))->base.
u.dependence_info.base)
;
5273}
5274
5275
5276/* Function vect_create_destination_var.
5277
5278 Create a new temporary of type VECTYPE. */
5279
5280tree
5281vect_create_destination_var (tree scalar_dest, tree vectype)
5282{
5283 tree vec_dest;
5284 const char *name;
5285 char *new_name;
5286 tree type;
5287 enum vect_var_kind kind;
5288
5289 kind = vectype
5290 ? VECTOR_BOOLEAN_TYPE_P (vectype)(((enum tree_code) (vectype)->base.code) == VECTOR_TYPE &&
((enum tree_code) (((contains_struct_check ((vectype), (TS_TYPED
), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5290, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE
)
5291 ? vect_mask_var
5292 : vect_simple_var
5293 : vect_scalar_var;
5294 type = vectype ? vectype : TREE_TYPE (scalar_dest)((contains_struct_check ((scalar_dest), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5294, __FUNCTION__))->typed.type)
;
5295
5296 gcc_assert (TREE_CODE (scalar_dest) == SSA_NAME)((void)(!(((enum tree_code) (scalar_dest)->base.code) == SSA_NAME
) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5296, __FUNCTION__), 0 : 0))
;
5297
5298 name = get_name (scalar_dest);
5299 if (name)
5300 new_name = xasprintf ("%s_%u", name, SSA_NAME_VERSION (scalar_dest)(tree_check ((scalar_dest), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5300, __FUNCTION__, (SSA_NAME)))->base.u.version
);
5301 else
5302 new_name = xasprintf ("_%u", SSA_NAME_VERSION (scalar_dest)(tree_check ((scalar_dest), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5302, __FUNCTION__, (SSA_NAME)))->base.u.version
);
5303 vec_dest = vect_get_new_vect_var (type, kind, new_name);
5304 free (new_name);
5305
5306 return vec_dest;
5307}
5308
5309/* Function vect_grouped_store_supported.
5310
5311 Returns TRUE if interleave high and interleave low permutations
5312 are supported, and FALSE otherwise. */
5313
5314bool
5315vect_grouped_store_supported (tree vectype, unsigned HOST_WIDE_INTlong count)
5316{
5317 machine_mode mode = TYPE_MODE (vectype)((((enum tree_code) ((tree_class_check ((vectype), (tcc_type)
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5317, __FUNCTION__)))->base.code) == VECTOR_TYPE) ? vector_type_mode
(vectype) : (vectype)->type_common.mode)
;
5318
5319 /* vect_permute_store_chain requires the group size to be equal to 3 or
5320 be a power of two. */
5321 if (count != 3 && exact_log2 (count) == -1)
5322 {
5323 if (dump_enabled_p ())
5324 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5325 "the size of the group of accesses"
5326 " is not a power of 2 or not eqaul to 3\n");
5327 return false;
5328 }
5329
5330 /* Check that the permutation is supported. */
5331 if (VECTOR_MODE_P (mode)(((enum mode_class) mode_class[mode]) == MODE_VECTOR_BOOL || (
(enum mode_class) mode_class[mode]) == MODE_VECTOR_INT || ((enum
mode_class) mode_class[mode]) == MODE_VECTOR_FLOAT || ((enum
mode_class) mode_class[mode]) == MODE_VECTOR_FRACT || ((enum
mode_class) mode_class[mode]) == MODE_VECTOR_UFRACT || ((enum
mode_class) mode_class[mode]) == MODE_VECTOR_ACCUM || ((enum
mode_class) mode_class[mode]) == MODE_VECTOR_UACCUM)
)
5332 {
5333 unsigned int i;
5334 if (count == 3)
5335 {
5336 unsigned int j0 = 0, j1 = 0, j2 = 0;
5337 unsigned int i, j;
5338
5339 unsigned int nelt;
5340 if (!GET_MODE_NUNITS (mode).is_constant (&nelt))
5341 {
5342 if (dump_enabled_p ())
5343 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
5344 "cannot handle groups of 3 stores for"
5345 " variable-length vectors\n");
5346 return false;
5347 }
5348
5349 vec_perm_builder sel (nelt, nelt, 1);
5350 sel.quick_grow (nelt);
5351 vec_perm_indices indices;
5352 for (j = 0; j < 3; j++)
5353 {
5354 int nelt0 = ((3 - j) * nelt) % 3;
5355 int nelt1 = ((3 - j) * nelt + 1) % 3;
5356 int nelt2 = ((3 - j) * nelt + 2) % 3;
5357 for (i = 0; i < nelt; i++)
5358 {
5359 if (3 * i + nelt0 < nelt)
5360 sel[3 * i + nelt0] = j0++;
5361 if (3 * i + nelt1 < nelt)
5362 sel[3 * i + nelt1] = nelt + j1++;
5363 if (3 * i + nelt2 < nelt)
5364 sel[3 * i + nelt2] = 0;
5365 }
5366 indices.new_vector (sel, 2, nelt);
5367 if (!can_vec_perm_const_p (mode, mode, indices))
5368 {
5369 if (dump_enabled_p ())
5370 dump_printf (MSG_MISSED_OPTIMIZATION,
5371 "permutation op not supported by target.\n");
5372 return false;
5373 }
5374
5375 for (i = 0; i < nelt; i++)
5376 {
5377 if (3 * i + nelt0 < nelt)
5378 sel[3 * i + nelt0] = 3 * i + nelt0;
5379 if (3 * i + nelt1 < nelt)
5380 sel[3 * i + nelt1] = 3 * i + nelt1;
5381 if (3 * i + nelt2 < nelt)
5382 sel[3 * i + nelt2] = nelt + j2++;
5383 }
5384 indices.new_vector (sel, 2, nelt);
5385 if (!can_vec_perm_const_p (mode, mode, indices))
5386 {
5387 if (dump_enabled_p ())
5388 dump_printf (MSG_MISSED_OPTIMIZATION,
5389 "permutation op not supported by target.\n");
5390 return false;
5391 }
5392 }
5393 return true;
5394 }
5395 else
5396 {
5397 /* If length is not equal to 3 then only power of 2 is supported. */
5398 gcc_assert (pow2p_hwi (count))((void)(!(pow2p_hwi (count)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5398, __FUNCTION__), 0 : 0))
;
5399 poly_uint64 nelt = GET_MODE_NUNITS (mode);
5400
5401 /* The encoding has 2 interleaved stepped patterns. */
5402 vec_perm_builder sel (nelt, 2, 3);
5403 sel.quick_grow (6);
5404 for (i = 0; i < 3; i++)
5405 {
5406 sel[i * 2] = i;
5407 sel[i * 2 + 1] = i + nelt;
5408 }
5409 vec_perm_indices indices (sel, 2, nelt);
5410 if (can_vec_perm_const_p (mode, mode, indices))
5411 {
5412 for (i = 0; i < 6; i++)
5413 sel[i] += exact_div (nelt, 2);
5414 indices.new_vector (sel, 2, nelt);
5415 if (can_vec_perm_const_p (mode, mode, indices))
5416 return true;
5417 }
5418 }
5419 }
5420
5421 if (dump_enabled_p ())
5422 dump_printf (MSG_MISSED_OPTIMIZATION,
5423 "permutation op not supported by target.\n");
5424 return false;
5425}
5426
5427
5428/* Return TRUE if vec_{mask_}store_lanes is available for COUNT vectors of
5429 type VECTYPE. MASKED_P says whether the masked form is needed. */
5430
5431bool
5432vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INTlong count,
5433 bool masked_p)
5434{
5435 if (masked_p)
5436 return vect_lanes_optab_supported_p ("vec_mask_store_lanes",
5437 vec_mask_store_lanes_optab,
5438 vectype, count);
5439 else
5440 return vect_lanes_optab_supported_p ("vec_store_lanes",
5441 vec_store_lanes_optab,
5442 vectype, count);
5443}
5444
5445
5446/* Function vect_permute_store_chain.
5447
5448 Given a chain of interleaved stores in DR_CHAIN of LENGTH that must be
5449 a power of 2 or equal to 3, generate interleave_high/low stmts to reorder
5450 the data correctly for the stores. Return the final references for stores
5451 in RESULT_CHAIN.
5452
5453 E.g., LENGTH is 4 and the scalar type is short, i.e., VF is 8.
5454 The input is 4 vectors each containing 8 elements. We assign a number to
5455 each element, the input sequence is:
5456
5457 1st vec: 0 1 2 3 4 5 6 7
5458 2nd vec: 8 9 10 11 12 13 14 15
5459 3rd vec: 16 17 18 19 20 21 22 23
5460 4th vec: 24 25 26 27 28 29 30 31
5461
5462 The output sequence should be:
5463
5464 1st vec: 0 8 16 24 1 9 17 25
5465 2nd vec: 2 10 18 26 3 11 19 27
5466 3rd vec: 4 12 20 28 5 13 21 30
5467 4th vec: 6 14 22 30 7 15 23 31
5468
5469 i.e., we interleave the contents of the four vectors in their order.
5470
5471 We use interleave_high/low instructions to create such output. The input of
5472 each interleave_high/low operation is two vectors:
5473 1st vec 2nd vec
5474 0 1 2 3 4 5 6 7
5475 the even elements of the result vector are obtained left-to-right from the
5476 high/low elements of the first vector. The odd elements of the result are
5477 obtained left-to-right from the high/low elements of the second vector.
5478 The output of interleave_high will be: 0 4 1 5
5479 and of interleave_low: 2 6 3 7
5480
5481
5482 The permutation is done in log LENGTH stages. In each stage interleave_high
5483 and interleave_low stmts are created for each pair of vectors in DR_CHAIN,
5484 where the first argument is taken from the first half of DR_CHAIN and the
5485 second argument from it's second half.
5486 In our example,
5487
5488 I1: interleave_high (1st vec, 3rd vec)
5489 I2: interleave_low (1st vec, 3rd vec)
5490 I3: interleave_high (2nd vec, 4th vec)
5491 I4: interleave_low (2nd vec, 4th vec)
5492
5493 The output for the first stage is:
5494
5495 I1: 0 16 1 17 2 18 3 19
5496 I2: 4 20 5 21 6 22 7 23
5497 I3: 8 24 9 25 10 26 11 27
5498 I4: 12 28 13 29 14 30 15 31
5499
5500 The output of the second stage, i.e. the final result is:
5501
5502 I1: 0 8 16 24 1 9 17 25
5503 I2: 2 10 18 26 3 11 19 27
5504 I3: 4 12 20 28 5 13 21 30
5505 I4: 6 14 22 30 7 15 23 31. */
5506
5507void
5508vect_permute_store_chain (vec_info *vinfo, vec<tree> &dr_chain,
5509 unsigned int length,
5510 stmt_vec_info stmt_info,
5511 gimple_stmt_iterator *gsi,
5512 vec<tree> *result_chain)
5513{
5514 tree vect1, vect2, high, low;
5515 gimple *perm_stmt;
5516 tree vectype = STMT_VINFO_VECTYPE (stmt_info)(stmt_info)->vectype;
5517 tree perm_mask_low, perm_mask_high;
5518 tree data_ref;
5519 tree perm3_mask_low, perm3_mask_high;
5520 unsigned int i, j, n, log_length = exact_log2 (length);
5521
5522 result_chain->quick_grow (length);
5523 memcpy (result_chain->address (), dr_chain.address (),
5524 length * sizeof (tree));
5525
5526 if (length == 3)
5527 {
5528 /* vect_grouped_store_supported ensures that this is constant. */
5529 unsigned int nelt = TYPE_VECTOR_SUBPARTS (vectype).to_constant ();
5530 unsigned int j0 = 0, j1 = 0, j2 = 0;
5531
5532 vec_perm_builder sel (nelt, nelt, 1);
5533 sel.quick_grow (nelt);
5534 vec_perm_indices indices;
5535 for (j = 0; j < 3; j++)
5536 {
5537 int nelt0 = ((3 - j) * nelt) % 3;
5538 int nelt1 = ((3 - j) * nelt + 1) % 3;
5539 int nelt2 = ((3 - j) * nelt + 2) % 3;
5540
5541 for (i = 0; i < nelt; i++)
5542 {
5543 if (3 * i + nelt0 < nelt)
5544 sel[3 * i + nelt0] = j0++;
5545 if (3 * i + nelt1 < nelt)
5546 sel[3 * i + nelt1] = nelt + j1++;
5547 if (3 * i + nelt2 < nelt)
5548 sel[3 * i + nelt2] = 0;
5549 }
5550 indices.new_vector (sel, 2, nelt);
5551 perm3_mask_low = vect_gen_perm_mask_checked (vectype, indices);
5552
5553 for (i = 0; i < nelt; i++)
5554 {
5555 if (3 * i + nelt0 < nelt)
5556 sel[3 * i + nelt0] = 3 * i + nelt0;
5557 if (3 * i + nelt1 < nelt)
5558 sel[3 * i + nelt1] = 3 * i + nelt1;
5559 if (3 * i + nelt2 < nelt)
5560 sel[3 * i + nelt2] = nelt + j2++;
5561 }
5562 indices.new_vector (sel, 2, nelt);
5563 perm3_mask_high = vect_gen_perm_mask_checked (vectype, indices);
5564
5565 vect1 = dr_chain[0];
5566 vect2 = dr_chain[1];
5567
5568 /* Create interleaving stmt:
5569 low = VEC_PERM_EXPR <vect1, vect2,
5570 {j, nelt, *, j + 1, nelt + j + 1, *,
5571 j + 2, nelt + j + 2, *, ...}> */
5572 data_ref = make_temp_ssa_name (vectype, NULLnullptr, "vect_shuffle3_low");
5573 perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, vect1,
5574 vect2, perm3_mask_low);
5575 vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
5576
5577 vect1 = data_ref;
5578 vect2 = dr_chain[2];
5579 /* Create interleaving stmt:
5580 low = VEC_PERM_EXPR <vect1, vect2,
5581 {0, 1, nelt + j, 3, 4, nelt + j + 1,
5582 6, 7, nelt + j + 2, ...}> */
5583 data_ref = make_temp_ssa_name (vectype, NULLnullptr, "vect_shuffle3_high");
5584 perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, vect1,
5585 vect2, perm3_mask_high);
5586 vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
5587 (*result_chain)[j] = data_ref;
5588 }
5589 }
5590 else
5591 {
5592 /* If length is not equal to 3 then only power of 2 is supported. */
5593 gcc_assert (pow2p_hwi (length))((void)(!(pow2p_hwi (length)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-vect-data-refs.cc"
, 5593, __FUNCTION__), 0 : 0))
;
5594
5595 /* The encoding has 2 interleaved stepped patterns. */
5596 poly_uint64 nelt = TYPE_VECTOR_SUBPARTS (vectype);
5597 vec_perm_builder sel (nelt, 2, 3);
5598 sel.quick_grow (6);
5599 for (i = 0; i < 3; i++)
5600 {
5601 sel[i * 2] = i;
5602 sel[i * 2 + 1] = i + nelt;
5603 }
5604 vec_perm_indices indices (sel, 2, nelt);
5605 perm_mask_high = vect_gen_perm_mask_checked (vectype, indices);
5606
5607 for (i = 0; i < 6; i++)
5608 sel[i] += exact_div (nelt, 2);
5609 indices.new_vector (sel, 2, nelt);
5610 perm_mask_low = vect_gen_perm_mask_checked (vectype, indices);
5611
5612 for (i = 0, n = log_length; i < n; i++)
5613 {
5614 for (j = 0; j < length/2; j++)
5615 {
5616 vect1 = dr_chain[j];
5617 vect2 = dr_chain[j+length/2];
5618
5619 /* Create interleaving stmt:
5620 high = VEC_PERM_EXPR <vect1, vect2, {0, nelt, 1, nelt+1,
5621 ...}> */
5622 high = make_temp_ssa_name (vectype, NULLnullptr, "vect_inter_high");
5623 perm_stmt = gimple_build_assign (high, VEC_PERM_EXPR, vect1,
5624 vect2, perm_mask_high);
5625 vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
5626 (*result_chain)[2*j] = high;
5627
5628 /* Create interleaving stmt:
5629 low = VEC_PERM_EXPR <vect1, vect2,
5630 {nelt/2, nelt*3/2, nelt/2+1, nelt*3/2+1,
5631 ...}> */
5632 low = make_temp_ssa_name (vectype, NULLnullptr, "vect_inter_low");
5633 perm_stmt = gimple_build_assign (low, VEC_PERM_EXPR, vect1,
5634 vect2, perm_mask_low);
5635 vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
5636 (*result_chain)[2*j+1] = low;
5637 }
5638 memcpy (dr_chain.address (), result_chain->address (),
5639 length * sizeof (tree));
5640 }
5641 }
5642}
5643
5644/* Function vect_setup_realignment
5645
5646 This function is called when vectorizing an unaligned load using
5647 the dr_explicit_realign[_optimized] scheme.
5648 This function generates the following code at the loop prolog:
5649
5650 p = initial_addr;
5651 x msq_init = *(floor(p)); # prolog load
5652 realignment_token = call target_builtin;
5653 loop:
5654 x msq = phi (msq_init, ---)
5655
5656 The stmts marked with x are generated only for the case of
5657 dr_explicit_realign_optimized.
5658
5659 The code above sets up a new (vector) pointer, pointing to the first
5660 location accessed by STMT_INFO, and a "floor-aligned" load using that
5661 pointer. It also generates code to compute the "realignment-token"
5662 (if the relevant target hook was defined), and creates a phi-node at the
5663 loop-header bb whose arguments are the result of the prolog-load (created
5664 by this function) and the result of a load that takes place in the loop
5665 (to be created by the caller to this function).
5666
5667 For the case of dr_explicit_realign_optimized:
5668 The caller to this function uses the phi-result (msq) to create the
5669 realignment code inside the loop, and sets up the missing phi argument,
5670 as follows:
5671 loop:
5672 msq = phi (msq_init, lsq)
5673 lsq = *(floor(p')); # load in loop
5674 result = realign_load (msq, lsq, realignment_token);
5675