]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/tree-vect-patterns.c
gigi.h (gnat_mark_addressable): Rename parameter.
[thirdparty/gcc.git] / gcc / tree-vect-patterns.c
CommitLineData
20f06221 1/* Analysis Utilities for Loop Vectorization.
ebfd146a 2 Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
20f06221
DN
3 Contributed by Dorit Nuzman <dorit@il.ibm.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9dcd6f09 9Software Foundation; either version 3, or (at your option) any later
20f06221
DN
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
9dcd6f09
NC
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20f06221
DN
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "ggc.h"
26#include "tree.h"
20f06221
DN
27#include "target.h"
28#include "basic-block.h"
29#include "diagnostic.h"
30#include "tree-flow.h"
31#include "tree-dump.h"
20f06221
DN
32#include "cfgloop.h"
33#include "expr.h"
34#include "optabs.h"
35#include "params.h"
36#include "tree-data-ref.h"
37#include "tree-vectorizer.h"
38#include "recog.h"
39#include "toplev.h"
40
c0220ea4 41/* Function prototypes */
b8698a0f 42static void vect_pattern_recog_1
726a989a
RB
43 (gimple (* ) (gimple, tree *, tree *), gimple_stmt_iterator);
44static bool widened_name_p (tree, gimple, tree *, gimple *);
20f06221
DN
45
46/* Pattern recognition functions */
726a989a
RB
47static gimple vect_recog_widen_sum_pattern (gimple, tree *, tree *);
48static gimple vect_recog_widen_mult_pattern (gimple, tree *, tree *);
49static gimple vect_recog_dot_prod_pattern (gimple, tree *, tree *);
50static gimple vect_recog_pow_pattern (gimple, tree *, tree *);
20f06221
DN
51static vect_recog_func_ptr vect_vect_recog_func_ptrs[NUM_PATTERNS] = {
52 vect_recog_widen_mult_pattern,
53 vect_recog_widen_sum_pattern,
0b2229b0
RG
54 vect_recog_dot_prod_pattern,
55 vect_recog_pow_pattern};
20f06221
DN
56
57
58/* Function widened_name_p
59
60 Check whether NAME, an ssa-name used in USE_STMT,
61 is a result of a type-promotion, such that:
62 DEF_STMT: NAME = NOP (name0)
b8698a0f 63 where the type of name0 (HALF_TYPE) is smaller than the type of NAME.
20f06221
DN
64*/
65
66static bool
726a989a 67widened_name_p (tree name, gimple use_stmt, tree *half_type, gimple *def_stmt)
20f06221
DN
68{
69 tree dummy;
726a989a 70 gimple dummy_gimple;
20f06221
DN
71 loop_vec_info loop_vinfo;
72 stmt_vec_info stmt_vinfo;
20f06221
DN
73 tree type = TREE_TYPE (name);
74 tree oprnd0;
75 enum vect_def_type dt;
76 tree def;
77
78 stmt_vinfo = vinfo_for_stmt (use_stmt);
79 loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
80
a70d6342 81 if (!vect_is_simple_use (name, loop_vinfo, NULL, def_stmt, &def, &dt))
20f06221
DN
82 return false;
83
8644a673
IR
84 if (dt != vect_internal_def
85 && dt != vect_external_def && dt != vect_constant_def)
20f06221
DN
86 return false;
87
88 if (! *def_stmt)
89 return false;
90
726a989a 91 if (!is_gimple_assign (*def_stmt))
20f06221
DN
92 return false;
93
726a989a 94 if (gimple_assign_rhs_code (*def_stmt) != NOP_EXPR)
20f06221
DN
95 return false;
96
726a989a 97 oprnd0 = gimple_assign_rhs1 (*def_stmt);
20f06221
DN
98
99 *half_type = TREE_TYPE (oprnd0);
100 if (!INTEGRAL_TYPE_P (type) || !INTEGRAL_TYPE_P (*half_type)
101 || (TYPE_UNSIGNED (type) != TYPE_UNSIGNED (*half_type))
102 || (TYPE_PRECISION (type) < (TYPE_PRECISION (*half_type) * 2)))
103 return false;
104
b8698a0f 105 if (!vect_is_simple_use (oprnd0, loop_vinfo, NULL, &dummy_gimple, &dummy,
a70d6342 106 &dt))
20f06221
DN
107 return false;
108
20f06221
DN
109 return true;
110}
111
726a989a
RB
112/* Helper to return a new temporary for pattern of TYPE for STMT. If STMT
113 is NULL, the caller must set SSA_NAME_DEF_STMT for the returned SSA var. */
114
115static tree
116vect_recog_temp_ssa_var (tree type, gimple stmt)
117{
118 tree var = create_tmp_var (type, "patt");
119
120 add_referenced_var (var);
121 var = make_ssa_name (var, stmt);
122 return var;
123}
20f06221
DN
124
125/* Function vect_recog_dot_prod_pattern
126
127 Try to find the following pattern:
128
129 type x_t, y_t;
130 TYPE1 prod;
131 TYPE2 sum = init;
132 loop:
133 sum_0 = phi <init, sum_1>
134 S1 x_t = ...
135 S2 y_t = ...
136 S3 x_T = (TYPE1) x_t;
137 S4 y_T = (TYPE1) y_t;
138 S5 prod = x_T * y_T;
139 [S6 prod = (TYPE2) prod; #optional]
140 S7 sum_1 = prod + sum_0;
141
b8698a0f
L
142 where 'TYPE1' is exactly double the size of type 'type', and 'TYPE2' is the
143 same size of 'TYPE1' or bigger. This is a special case of a reduction
20f06221 144 computation.
b8698a0f 145
20f06221
DN
146 Input:
147
148 * LAST_STMT: A stmt from which the pattern search begins. In the example,
149 when this function is called with S7, the pattern {S3,S4,S5,S6,S7} will be
150 detected.
151
152 Output:
153
154 * TYPE_IN: The type of the input arguments to the pattern.
155
156 * TYPE_OUT: The type of the output of this pattern.
157
158 * Return value: A new stmt that will be used to replace the sequence of
159 stmts that constitute the pattern. In this case it will be:
160 WIDEN_DOT_PRODUCT <x_t, y_t, sum_0>
d29de1bf
DN
161
162 Note: The dot-prod idiom is a widening reduction pattern that is
163 vectorized without preserving all the intermediate results. It
164 produces only N/2 (widened) results (by summing up pairs of
165 intermediate results) rather than all N results. Therefore, we
166 cannot allow this pattern when we want to get all the results and in
167 the correct order (as is the case when this computation is in an
168 inner-loop nested in an outer-loop that us being vectorized). */
20f06221 169
726a989a
RB
170static gimple
171vect_recog_dot_prod_pattern (gimple last_stmt, tree *type_in, tree *type_out)
20f06221 172{
726a989a 173 gimple stmt;
20f06221
DN
174 tree oprnd0, oprnd1;
175 tree oprnd00, oprnd01;
176 stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
177 tree type, half_type;
726a989a 178 gimple pattern_stmt;
20f06221 179 tree prod_type;
d29de1bf
DN
180 loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
181 struct loop *loop = LOOP_VINFO_LOOP (loop_info);
726a989a 182 tree var, rhs;
20f06221 183
726a989a 184 if (!is_gimple_assign (last_stmt))
20f06221
DN
185 return NULL;
186
726a989a 187 type = gimple_expr_type (last_stmt);
20f06221 188
b8698a0f 189 /* Look for the following pattern
20f06221
DN
190 DX = (TYPE1) X;
191 DY = (TYPE1) Y;
b8698a0f 192 DPROD = DX * DY;
20f06221
DN
193 DDPROD = (TYPE2) DPROD;
194 sum_1 = DDPROD + sum_0;
b8698a0f 195 In which
20f06221
DN
196 - DX is double the size of X
197 - DY is double the size of Y
198 - DX, DY, DPROD all have the same type
199 - sum is the same size of DPROD or bigger
200 - sum has been recognized as a reduction variable.
201
202 This is equivalent to:
203 DPROD = X w* Y; #widen mult
204 sum_1 = DPROD w+ sum_0; #widen summation
205 or
206 DPROD = X w* Y; #widen mult
207 sum_1 = DPROD + sum_0; #summation
208 */
209
210 /* Starting from LAST_STMT, follow the defs of its uses in search
211 of the above pattern. */
212
726a989a 213 if (gimple_assign_rhs_code (last_stmt) != PLUS_EXPR)
20f06221
DN
214 return NULL;
215
216 if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
217 {
218 /* Has been detected as widening-summation? */
219
220 stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
726a989a
RB
221 type = gimple_expr_type (stmt);
222 if (gimple_assign_rhs_code (stmt) != WIDEN_SUM_EXPR)
20f06221 223 return NULL;
726a989a
RB
224 oprnd0 = gimple_assign_rhs1 (stmt);
225 oprnd1 = gimple_assign_rhs2 (stmt);
20f06221
DN
226 half_type = TREE_TYPE (oprnd0);
227 }
228 else
229 {
726a989a 230 gimple def_stmt;
20f06221
DN
231
232 if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def)
233 return NULL;
726a989a
RB
234 oprnd0 = gimple_assign_rhs1 (last_stmt);
235 oprnd1 = gimple_assign_rhs2 (last_stmt);
9600efe1
MM
236 if (!types_compatible_p (TREE_TYPE (oprnd0), type)
237 || !types_compatible_p (TREE_TYPE (oprnd1), type))
20f06221
DN
238 return NULL;
239 stmt = last_stmt;
240
241 if (widened_name_p (oprnd0, stmt, &half_type, &def_stmt))
242 {
243 stmt = def_stmt;
726a989a 244 oprnd0 = gimple_assign_rhs1 (stmt);
20f06221
DN
245 }
246 else
247 half_type = type;
248 }
249
250 /* So far so good. Since last_stmt was detected as a (summation) reduction,
251 we know that oprnd1 is the reduction variable (defined by a loop-header
252 phi), and oprnd0 is an ssa-name defined by a stmt in the loop body.
253 Left to check that oprnd0 is defined by a (widen_)mult_expr */
254
255 prod_type = half_type;
256 stmt = SSA_NAME_DEF_STMT (oprnd0);
b8698a0f 257 /* FORNOW. Can continue analyzing the def-use chain when this stmt in a phi
8665227f 258 inside the loop (in case we are analyzing an outer-loop). */
726a989a 259 if (!is_gimple_assign (stmt))
b8698a0f 260 return NULL;
20f06221
DN
261 stmt_vinfo = vinfo_for_stmt (stmt);
262 gcc_assert (stmt_vinfo);
8644a673 263 if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_internal_def)
b3130586 264 return NULL;
726a989a 265 if (gimple_assign_rhs_code (stmt) != MULT_EXPR)
20f06221
DN
266 return NULL;
267 if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
268 {
269 /* Has been detected as a widening multiplication? */
270
271 stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
726a989a 272 if (gimple_assign_rhs_code (stmt) != WIDEN_MULT_EXPR)
20f06221
DN
273 return NULL;
274 stmt_vinfo = vinfo_for_stmt (stmt);
275 gcc_assert (stmt_vinfo);
8644a673 276 gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_internal_def);
726a989a
RB
277 oprnd00 = gimple_assign_rhs1 (stmt);
278 oprnd01 = gimple_assign_rhs2 (stmt);
20f06221
DN
279 }
280 else
281 {
282 tree half_type0, half_type1;
726a989a 283 gimple def_stmt;
20f06221
DN
284 tree oprnd0, oprnd1;
285
726a989a
RB
286 oprnd0 = gimple_assign_rhs1 (stmt);
287 oprnd1 = gimple_assign_rhs2 (stmt);
9600efe1
MM
288 if (!types_compatible_p (TREE_TYPE (oprnd0), prod_type)
289 || !types_compatible_p (TREE_TYPE (oprnd1), prod_type))
20f06221
DN
290 return NULL;
291 if (!widened_name_p (oprnd0, stmt, &half_type0, &def_stmt))
292 return NULL;
726a989a 293 oprnd00 = gimple_assign_rhs1 (def_stmt);
20f06221
DN
294 if (!widened_name_p (oprnd1, stmt, &half_type1, &def_stmt))
295 return NULL;
726a989a 296 oprnd01 = gimple_assign_rhs1 (def_stmt);
9600efe1 297 if (!types_compatible_p (half_type0, half_type1))
20f06221
DN
298 return NULL;
299 if (TYPE_PRECISION (prod_type) != TYPE_PRECISION (half_type0) * 2)
300 return NULL;
301 }
302
303 half_type = TREE_TYPE (oprnd00);
304 *type_in = half_type;
305 *type_out = type;
b8698a0f 306
20f06221 307 /* Pattern detected. Create a stmt to be used to replace the pattern: */
726a989a
RB
308 var = vect_recog_temp_ssa_var (type, NULL);
309 rhs = build3 (DOT_PROD_EXPR, type, oprnd00, oprnd01, oprnd1),
310 pattern_stmt = gimple_build_assign (var, rhs);
b8698a0f 311
20f06221
DN
312 if (vect_print_dump_info (REPORT_DETAILS))
313 {
314 fprintf (vect_dump, "vect_recog_dot_prod_pattern: detected: ");
726a989a 315 print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
20f06221 316 }
d29de1bf
DN
317
318 /* We don't allow changing the order of the computation in the inner-loop
319 when doing outer-loop vectorization. */
7c5222ff 320 gcc_assert (!nested_in_vect_loop_p (loop, last_stmt));
d29de1bf 321
726a989a 322 return pattern_stmt;
20f06221 323}
b8698a0f 324
20f06221
DN
325/* Function vect_recog_widen_mult_pattern
326
327 Try to find the following pattern:
328
329 type a_t, b_t;
330 TYPE a_T, b_T, prod_T;
331
332 S1 a_t = ;
333 S2 b_t = ;
334 S3 a_T = (TYPE) a_t;
335 S4 b_T = (TYPE) b_t;
336 S5 prod_T = a_T * b_T;
337
338 where type 'TYPE' is at least double the size of type 'type'.
339
340 Input:
341
342 * LAST_STMT: A stmt from which the pattern search begins. In the example,
343 when this function is called with S5, the pattern {S3,S4,S5} is be detected.
344
345 Output:
346
347 * TYPE_IN: The type of the input arguments to the pattern.
348
349 * TYPE_OUT: The type of the output of this pattern.
350
351 * Return value: A new stmt that will be used to replace the sequence of
352 stmts that constitute the pattern. In this case it will be:
353 WIDEN_MULT <a_t, b_t>
354*/
355
726a989a 356static gimple
b8698a0f
L
357vect_recog_widen_mult_pattern (gimple last_stmt,
358 tree *type_in,
89d67cca 359 tree *type_out)
20f06221 360{
726a989a 361 gimple def_stmt0, def_stmt1;
89d67cca
DN
362 tree oprnd0, oprnd1;
363 tree type, half_type0, half_type1;
726a989a 364 gimple pattern_stmt;
89d67cca
DN
365 tree vectype;
366 tree dummy;
726a989a 367 tree var;
89d67cca 368 enum tree_code dummy_code;
5d593372
IR
369 int dummy_int;
370 VEC (tree, heap) *dummy_vec;
89d67cca 371
726a989a 372 if (!is_gimple_assign (last_stmt))
89d67cca
DN
373 return NULL;
374
726a989a 375 type = gimple_expr_type (last_stmt);
89d67cca
DN
376
377 /* Starting from LAST_STMT, follow the defs of its uses in search
378 of the above pattern. */
379
726a989a 380 if (gimple_assign_rhs_code (last_stmt) != MULT_EXPR)
89d67cca
DN
381 return NULL;
382
726a989a
RB
383 oprnd0 = gimple_assign_rhs1 (last_stmt);
384 oprnd1 = gimple_assign_rhs2 (last_stmt);
9600efe1
MM
385 if (!types_compatible_p (TREE_TYPE (oprnd0), type)
386 || !types_compatible_p (TREE_TYPE (oprnd1), type))
89d67cca
DN
387 return NULL;
388
389 /* Check argument 0 */
390 if (!widened_name_p (oprnd0, last_stmt, &half_type0, &def_stmt0))
391 return NULL;
726a989a 392 oprnd0 = gimple_assign_rhs1 (def_stmt0);
89d67cca
DN
393
394 /* Check argument 1 */
395 if (!widened_name_p (oprnd1, last_stmt, &half_type1, &def_stmt1))
396 return NULL;
726a989a 397 oprnd1 = gimple_assign_rhs1 (def_stmt1);
89d67cca 398
9600efe1 399 if (!types_compatible_p (half_type0, half_type1))
89d67cca
DN
400 return NULL;
401
402 /* Pattern detected. */
403 if (vect_print_dump_info (REPORT_DETAILS))
404 fprintf (vect_dump, "vect_recog_widen_mult_pattern: detected: ");
405
406 /* Check target support */
407 vectype = get_vectype_for_scalar_type (half_type0);
03d3e953
IR
408 if (!vectype
409 || !supportable_widening_operation (WIDEN_MULT_EXPR, last_stmt, vectype,
726a989a 410 &dummy, &dummy, &dummy_code,
5d593372 411 &dummy_code, &dummy_int, &dummy_vec))
89d67cca
DN
412 return NULL;
413
414 *type_in = vectype;
415 *type_out = NULL_TREE;
416
417 /* Pattern supported. Create a stmt to be used to replace the pattern: */
726a989a
RB
418 var = vect_recog_temp_ssa_var (type, NULL);
419 pattern_stmt = gimple_build_assign_with_ops (WIDEN_MULT_EXPR, var, oprnd0,
420 oprnd1);
421 SSA_NAME_DEF_STMT (var) = pattern_stmt;
422
89d67cca 423 if (vect_print_dump_info (REPORT_DETAILS))
726a989a
RB
424 print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
425
426 return pattern_stmt;
20f06221
DN
427}
428
429
0b2229b0
RG
430/* Function vect_recog_pow_pattern
431
432 Try to find the following pattern:
433
434 x = POW (y, N);
435
436 with POW being one of pow, powf, powi, powif and N being
437 either 2 or 0.5.
438
439 Input:
440
441 * LAST_STMT: A stmt from which the pattern search begins.
442
443 Output:
444
445 * TYPE_IN: The type of the input arguments to the pattern.
446
447 * TYPE_OUT: The type of the output of this pattern.
448
449 * Return value: A new stmt that will be used to replace the sequence of
450 stmts that constitute the pattern. In this case it will be:
726a989a 451 x = x * x
0b2229b0 452 or
726a989a 453 x = sqrt (x)
0b2229b0
RG
454*/
455
726a989a
RB
456static gimple
457vect_recog_pow_pattern (gimple last_stmt, tree *type_in, tree *type_out)
0b2229b0 458{
726a989a
RB
459 tree fn, base, exp = NULL;
460 gimple stmt;
461 tree var;
0b2229b0 462
726a989a 463 if (!is_gimple_call (last_stmt) || gimple_call_lhs (last_stmt) == NULL)
0b2229b0
RG
464 return NULL;
465
726a989a 466 fn = gimple_call_fndecl (last_stmt);
0b2229b0
RG
467 switch (DECL_FUNCTION_CODE (fn))
468 {
469 case BUILT_IN_POWIF:
470 case BUILT_IN_POWI:
471 case BUILT_IN_POWF:
472 case BUILT_IN_POW:
726a989a
RB
473 base = gimple_call_arg (last_stmt, 0);
474 exp = gimple_call_arg (last_stmt, 1);
0b2229b0
RG
475 if (TREE_CODE (exp) != REAL_CST
476 && TREE_CODE (exp) != INTEGER_CST)
726a989a 477 return NULL;
0b2229b0
RG
478 break;
479
726a989a
RB
480 default:
481 return NULL;
0b2229b0
RG
482 }
483
484 /* We now have a pow or powi builtin function call with a constant
485 exponent. */
486
0b2229b0
RG
487 *type_out = NULL_TREE;
488
489 /* Catch squaring. */
490 if ((host_integerp (exp, 0)
491 && tree_low_cst (exp, 0) == 2)
492 || (TREE_CODE (exp) == REAL_CST
493 && REAL_VALUES_EQUAL (TREE_REAL_CST (exp), dconst2)))
c6b1b49b
RG
494 {
495 *type_in = TREE_TYPE (base);
726a989a
RB
496
497 var = vect_recog_temp_ssa_var (TREE_TYPE (base), NULL);
498 stmt = gimple_build_assign_with_ops (MULT_EXPR, var, base, base);
499 SSA_NAME_DEF_STMT (var) = stmt;
500 return stmt;
c6b1b49b 501 }
0b2229b0
RG
502
503 /* Catch square root. */
504 if (TREE_CODE (exp) == REAL_CST
505 && REAL_VALUES_EQUAL (TREE_REAL_CST (exp), dconsthalf))
506 {
507 tree newfn = mathfn_built_in (TREE_TYPE (base), BUILT_IN_SQRT);
c6b1b49b
RG
508 *type_in = get_vectype_for_scalar_type (TREE_TYPE (base));
509 if (*type_in)
510 {
726a989a
RB
511 gimple stmt = gimple_build_call (newfn, 1, base);
512 if (vectorizable_function (stmt, *type_in, *type_in)
513 != NULL_TREE)
514 {
515 var = vect_recog_temp_ssa_var (TREE_TYPE (base), stmt);
b8698a0f 516 gimple_call_set_lhs (stmt, var);
726a989a
RB
517 return stmt;
518 }
c6b1b49b 519 }
0b2229b0
RG
520 }
521
726a989a 522 return NULL;
0b2229b0
RG
523}
524
525
20f06221
DN
526/* Function vect_recog_widen_sum_pattern
527
528 Try to find the following pattern:
529
b8698a0f 530 type x_t;
20f06221
DN
531 TYPE x_T, sum = init;
532 loop:
533 sum_0 = phi <init, sum_1>
534 S1 x_t = *p;
535 S2 x_T = (TYPE) x_t;
536 S3 sum_1 = x_T + sum_0;
537
b8698a0f 538 where type 'TYPE' is at least double the size of type 'type', i.e - we're
20f06221 539 summing elements of type 'type' into an accumulator of type 'TYPE'. This is
917f1b7e 540 a special case of a reduction computation.
20f06221
DN
541
542 Input:
543
544 * LAST_STMT: A stmt from which the pattern search begins. In the example,
545 when this function is called with S3, the pattern {S2,S3} will be detected.
b8698a0f 546
20f06221 547 Output:
b8698a0f 548
20f06221
DN
549 * TYPE_IN: The type of the input arguments to the pattern.
550
551 * TYPE_OUT: The type of the output of this pattern.
552
553 * Return value: A new stmt that will be used to replace the sequence of
554 stmts that constitute the pattern. In this case it will be:
555 WIDEN_SUM <x_t, sum_0>
d29de1bf 556
b8698a0f 557 Note: The widening-sum idiom is a widening reduction pattern that is
d29de1bf 558 vectorized without preserving all the intermediate results. It
b8698a0f
L
559 produces only N/2 (widened) results (by summing up pairs of
560 intermediate results) rather than all N results. Therefore, we
561 cannot allow this pattern when we want to get all the results and in
562 the correct order (as is the case when this computation is in an
d29de1bf 563 inner-loop nested in an outer-loop that us being vectorized). */
20f06221 564
726a989a
RB
565static gimple
566vect_recog_widen_sum_pattern (gimple last_stmt, tree *type_in, tree *type_out)
20f06221 567{
726a989a 568 gimple stmt;
20f06221
DN
569 tree oprnd0, oprnd1;
570 stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
571 tree type, half_type;
726a989a 572 gimple pattern_stmt;
d29de1bf
DN
573 loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
574 struct loop *loop = LOOP_VINFO_LOOP (loop_info);
726a989a 575 tree var;
20f06221 576
726a989a 577 if (!is_gimple_assign (last_stmt))
20f06221
DN
578 return NULL;
579
726a989a 580 type = gimple_expr_type (last_stmt);
20f06221
DN
581
582 /* Look for the following pattern
583 DX = (TYPE) X;
584 sum_1 = DX + sum_0;
585 In which DX is at least double the size of X, and sum_1 has been
586 recognized as a reduction variable.
587 */
588
589 /* Starting from LAST_STMT, follow the defs of its uses in search
590 of the above pattern. */
591
726a989a 592 if (gimple_assign_rhs_code (last_stmt) != PLUS_EXPR)
20f06221
DN
593 return NULL;
594
595 if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def)
596 return NULL;
597
726a989a
RB
598 oprnd0 = gimple_assign_rhs1 (last_stmt);
599 oprnd1 = gimple_assign_rhs2 (last_stmt);
9600efe1
MM
600 if (!types_compatible_p (TREE_TYPE (oprnd0), type)
601 || !types_compatible_p (TREE_TYPE (oprnd1), type))
20f06221
DN
602 return NULL;
603
604 /* So far so good. Since last_stmt was detected as a (summation) reduction,
605 we know that oprnd1 is the reduction variable (defined by a loop-header
606 phi), and oprnd0 is an ssa-name defined by a stmt in the loop body.
607 Left to check that oprnd0 is defined by a cast from type 'type' to type
608 'TYPE'. */
609
610 if (!widened_name_p (oprnd0, last_stmt, &half_type, &stmt))
611 return NULL;
612
726a989a 613 oprnd0 = gimple_assign_rhs1 (stmt);
20f06221
DN
614 *type_in = half_type;
615 *type_out = type;
616
617 /* Pattern detected. Create a stmt to be used to replace the pattern: */
726a989a
RB
618 var = vect_recog_temp_ssa_var (type, NULL);
619 pattern_stmt = gimple_build_assign_with_ops (WIDEN_SUM_EXPR, var,
620 oprnd0, oprnd1);
621 SSA_NAME_DEF_STMT (var) = pattern_stmt;
622
20f06221
DN
623 if (vect_print_dump_info (REPORT_DETAILS))
624 {
625 fprintf (vect_dump, "vect_recog_widen_sum_pattern: detected: ");
726a989a 626 print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
20f06221 627 }
d29de1bf
DN
628
629 /* We don't allow changing the order of the computation in the inner-loop
630 when doing outer-loop vectorization. */
7c5222ff 631 gcc_assert (!nested_in_vect_loop_p (loop, last_stmt));
d29de1bf 632
726a989a 633 return pattern_stmt;
20f06221
DN
634}
635
636
b8698a0f 637/* Function vect_pattern_recog_1
20f06221
DN
638
639 Input:
640 PATTERN_RECOG_FUNC: A pointer to a function that detects a certain
641 computation pattern.
642 STMT: A stmt from which the pattern search should start.
643
644 If PATTERN_RECOG_FUNC successfully detected the pattern, it creates an
b8698a0f
L
645 expression that computes the same functionality and can be used to
646 replace the sequence of stmts that are involved in the pattern.
20f06221
DN
647
648 Output:
b8698a0f
L
649 This function checks if the expression returned by PATTERN_RECOG_FUNC is
650 supported in vector form by the target. We use 'TYPE_IN' to obtain the
651 relevant vector type. If 'TYPE_IN' is already a vector type, then this
20f06221
DN
652 indicates that target support had already been checked by PATTERN_RECOG_FUNC.
653 If 'TYPE_OUT' is also returned by PATTERN_RECOG_FUNC, we check that it fits
654 to the available target pattern.
655
b8698a0f 656 This function also does some bookkeeping, as explained in the documentation
20f06221
DN
657 for vect_recog_pattern. */
658
659static void
660vect_pattern_recog_1 (
726a989a
RB
661 gimple (* vect_recog_func) (gimple, tree *, tree *),
662 gimple_stmt_iterator si)
20f06221 663{
726a989a 664 gimple stmt = gsi_stmt (si), pattern_stmt;
20f06221
DN
665 stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
666 stmt_vec_info pattern_stmt_info;
667 loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
20f06221
DN
668 tree pattern_vectype;
669 tree type_in, type_out;
20f06221 670 enum tree_code code;
20f06221 671
726a989a
RB
672 pattern_stmt = (* vect_recog_func) (stmt, &type_in, &type_out);
673 if (!pattern_stmt)
b8698a0f
L
674 return;
675
676 if (VECTOR_MODE_P (TYPE_MODE (type_in)))
677 {
678 /* No need to check target support (already checked by the pattern
679 recognition function). */
20f06221
DN
680 pattern_vectype = type_in;
681 }
682 else
683 {
32e8bb8e 684 enum machine_mode vec_mode;
20f06221
DN
685 enum insn_code icode;
686 optab optab;
687
688 /* Check target support */
689 pattern_vectype = get_vectype_for_scalar_type (type_in);
03d3e953
IR
690 if (!pattern_vectype)
691 return;
692
726a989a
RB
693 if (is_gimple_assign (pattern_stmt))
694 code = gimple_assign_rhs_code (pattern_stmt);
695 else
696 {
697 gcc_assert (is_gimple_call (pattern_stmt));
698 code = CALL_EXPR;
699 }
700
701 optab = optab_for_tree_code (code, pattern_vectype, optab_default);
20f06221
DN
702 vec_mode = TYPE_MODE (pattern_vectype);
703 if (!optab
166cdb08 704 || (icode = optab_handler (optab, vec_mode)->insn_code) ==
20f06221
DN
705 CODE_FOR_nothing
706 || (type_out
6887a8b9
SE
707 && (!get_vectype_for_scalar_type (type_out)
708 || (insn_data[icode].operand[0].mode !=
709 TYPE_MODE (get_vectype_for_scalar_type (type_out))))))
20f06221
DN
710 return;
711 }
712
713 /* Found a vectorizable pattern. */
714 if (vect_print_dump_info (REPORT_DETAILS))
715 {
b8698a0f 716 fprintf (vect_dump, "pattern recognized: ");
726a989a 717 print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
20f06221 718 }
b8698a0f 719
726a989a
RB
720 /* Mark the stmts that are involved in the pattern. */
721 gsi_insert_before (&si, pattern_stmt, GSI_SAME_STMT);
722 set_vinfo_for_stmt (pattern_stmt,
a70d6342 723 new_stmt_vec_info (pattern_stmt, loop_vinfo, NULL));
726a989a 724 pattern_stmt_info = vinfo_for_stmt (pattern_stmt);
b8698a0f 725
20f06221
DN
726 STMT_VINFO_RELATED_STMT (pattern_stmt_info) = stmt;
727 STMT_VINFO_DEF_TYPE (pattern_stmt_info) = STMT_VINFO_DEF_TYPE (stmt_info);
728 STMT_VINFO_VECTYPE (pattern_stmt_info) = pattern_vectype;
729 STMT_VINFO_IN_PATTERN_P (stmt_info) = true;
726a989a 730 STMT_VINFO_RELATED_STMT (stmt_info) = pattern_stmt;
20f06221
DN
731
732 return;
733}
734
735
736/* Function vect_pattern_recog
737
738 Input:
739 LOOP_VINFO - a struct_loop_info of a loop in which we want to look for
740 computation idioms.
741
742 Output - for each computation idiom that is detected we insert a new stmt
743 that provides the same functionality and that can be vectorized. We
744 also record some information in the struct_stmt_info of the relevant
745 stmts, as explained below:
746
747 At the entry to this function we have the following stmts, with the
748 following initial value in the STMT_VINFO fields:
749
750 stmt in_pattern_p related_stmt vec_stmt
751 S1: a_i = .... - - -
752 S2: a_2 = ..use(a_i).. - - -
753 S3: a_1 = ..use(a_2).. - - -
754 S4: a_0 = ..use(a_1).. - - -
755 S5: ... = ..use(a_0).. - - -
756
757 Say the sequence {S1,S2,S3,S4} was detected as a pattern that can be
758 represented by a single stmt. We then:
759 - create a new stmt S6 that will replace the pattern.
760 - insert the new stmt S6 before the last stmt in the pattern
761 - fill in the STMT_VINFO fields as follows:
762
763 in_pattern_p related_stmt vec_stmt
b8698a0f 764 S1: a_i = .... - - -
20f06221
DN
765 S2: a_2 = ..use(a_i).. - - -
766 S3: a_1 = ..use(a_2).. - - -
767 > S6: a_new = .... - S4 -
768 S4: a_0 = ..use(a_1).. true S6 -
769 S5: ... = ..use(a_0).. - - -
770
771 (the last stmt in the pattern (S4) and the new pattern stmt (S6) point
772 to each other through the RELATED_STMT field).
773
774 S6 will be marked as relevant in vect_mark_stmts_to_be_vectorized instead
775 of S4 because it will replace all its uses. Stmts {S1,S2,S3} will
776 remain irrelevant unless used by stmts other than S4.
777
778 If vectorization succeeds, vect_transform_stmt will skip over {S1,S2,S3}
c0220ea4 779 (because they are marked as irrelevant). It will vectorize S6, and record
b8698a0f 780 a pointer to the new vector stmt VS6 both from S6 (as usual), and also
20f06221
DN
781 from S4. We do that so that when we get to vectorizing stmts that use the
782 def of S4 (like S5 that uses a_0), we'll know where to take the relevant
783 vector-def from. S4 will be skipped, and S5 will be vectorized as usual:
784
785 in_pattern_p related_stmt vec_stmt
786 S1: a_i = .... - - -
787 S2: a_2 = ..use(a_i).. - - -
788 S3: a_1 = ..use(a_2).. - - -
789 > VS6: va_new = .... - - -
790 S6: a_new = .... - S4 VS6
791 S4: a_0 = ..use(a_1).. true S6 VS6
792 > VS5: ... = ..vuse(va_new).. - - -
793 S5: ... = ..use(a_0).. - - -
794
795 DCE could then get rid of {S1,S2,S3,S4,S5,S6} (if their defs are not used
796 elsewhere), and we'll end up with:
797
b8698a0f 798 VS6: va_new = ....
20f06221
DN
799 VS5: ... = ..vuse(va_new)..
800
801 If vectorization does not succeed, DCE will clean S6 away (its def is
802 not used), and we'll end up with the original sequence.
803*/
804
805void
806vect_pattern_recog (loop_vec_info loop_vinfo)
807{
808 struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
809 basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
810 unsigned int nbbs = loop->num_nodes;
726a989a 811 gimple_stmt_iterator si;
20f06221 812 unsigned int i, j;
726a989a 813 gimple (* vect_recog_func_ptr) (gimple, tree *, tree *);
20f06221
DN
814
815 if (vect_print_dump_info (REPORT_DETAILS))
816 fprintf (vect_dump, "=== vect_pattern_recog ===");
817
818 /* Scan through the loop stmts, applying the pattern recognition
819 functions starting at each stmt visited: */
820 for (i = 0; i < nbbs; i++)
821 {
822 basic_block bb = bbs[i];
726a989a 823 for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
20f06221 824 {
20f06221
DN
825 /* Scan over all generic vect_recog_xxx_pattern functions. */
826 for (j = 0; j < NUM_PATTERNS; j++)
827 {
828 vect_recog_func_ptr = vect_vect_recog_func_ptrs[j];
829 vect_pattern_recog_1 (vect_recog_func_ptr, si);
830 }
831 }
832 }
833}