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