1 /* Analysis Utilities for Loop Vectorization.
2 Copyright (C) 2006, 2007 Free Software Foundation, Inc.
3 Contributed by Dorit Nuzman <dorit@il.ibm.com>
5 This file is part of GCC.
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
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
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/>. */
23 #include "coretypes.h"
29 #include "basic-block.h"
30 #include "diagnostic.h"
31 #include "tree-flow.h"
32 #include "tree-dump.h"
38 #include "tree-data-ref.h"
39 #include "tree-vectorizer.h"
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 *);
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};
60 /* Function widened_name_p
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.
69 widened_name_p (tree name, tree use_stmt, tree *half_type, tree *def_stmt)
72 loop_vec_info loop_vinfo;
73 stmt_vec_info stmt_vinfo;
75 tree type = TREE_TYPE (name);
77 enum vect_def_type dt;
80 stmt_vinfo = vinfo_for_stmt (use_stmt);
81 loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
83 if (!vect_is_simple_use (name, loop_vinfo, def_stmt, &def, &dt))
86 if (dt != vect_loop_def
87 && dt != vect_invariant_def && dt != vect_constant_def)
93 if (TREE_CODE (*def_stmt) != GIMPLE_MODIFY_STMT)
96 expr = GIMPLE_STMT_OPERAND (*def_stmt, 1);
97 if (TREE_CODE (expr) != NOP_EXPR)
100 oprnd0 = TREE_OPERAND (expr, 0);
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)))
108 if (!vect_is_simple_use (oprnd0, loop_vinfo, &dummy, &dummy, &dt))
115 /* Function vect_recog_dot_prod_pattern
117 Try to find the following pattern:
123 sum_0 = phi <init, sum_1>
126 S3 x_T = (TYPE1) x_t;
127 S4 y_T = (TYPE1) y_t;
129 [S6 prod = (TYPE2) prod; #optional]
130 S7 sum_1 = prod + sum_0;
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
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
144 * TYPE_IN: The type of the input arguments to the pattern.
146 * TYPE_OUT: The type of the output of this pattern.
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>
154 vect_recog_dot_prod_pattern (tree last_stmt, tree *type_in, tree *type_out)
158 tree oprnd00, oprnd01;
159 stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
160 tree type, half_type;
164 if (TREE_CODE (last_stmt) != GIMPLE_MODIFY_STMT)
167 expr = GIMPLE_STMT_OPERAND (last_stmt, 1);
168 type = TREE_TYPE (expr);
170 /* Look for the following pattern
174 DDPROD = (TYPE2) DPROD;
175 sum_1 = DDPROD + sum_0;
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.
183 This is equivalent to:
184 DPROD = X w* Y; #widen mult
185 sum_1 = DPROD w+ sum_0; #widen summation
187 DPROD = X w* Y; #widen mult
188 sum_1 = DPROD + sum_0; #summation
191 /* Starting from LAST_STMT, follow the defs of its uses in search
192 of the above pattern. */
194 if (TREE_CODE (expr) != PLUS_EXPR)
197 if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
199 /* Has been detected as widening-summation? */
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)
206 oprnd0 = TREE_OPERAND (expr, 0);
207 oprnd1 = TREE_OPERAND (expr, 1);
208 half_type = TREE_TYPE (oprnd0);
214 if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def)
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))
223 if (widened_name_p (oprnd0, stmt, &half_type, &def_stmt))
226 expr = GIMPLE_STMT_OPERAND (stmt, 1);
227 oprnd0 = TREE_OPERAND (expr, 0);
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 */
238 prod_type = half_type;
239 stmt = SSA_NAME_DEF_STMT (oprnd0);
241 stmt_vinfo = vinfo_for_stmt (stmt);
242 gcc_assert (stmt_vinfo);
243 if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_loop_def)
245 expr = GIMPLE_STMT_OPERAND (stmt, 1);
246 if (TREE_CODE (expr) != MULT_EXPR)
248 if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
250 /* Has been detected as a widening multiplication? */
252 stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
253 expr = GIMPLE_STMT_OPERAND (stmt, 1);
254 if (TREE_CODE (expr) != WIDEN_MULT_EXPR)
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);
264 tree half_type0, half_type1;
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))
275 if (!widened_name_p (oprnd0, stmt, &half_type0, &def_stmt))
277 oprnd00 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt, 1), 0);
278 if (!widened_name_p (oprnd1, stmt, &half_type1, &def_stmt))
280 oprnd01 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt, 1), 0);
281 if (TYPE_MAIN_VARIANT (half_type0) != TYPE_MAIN_VARIANT (half_type1))
283 if (TYPE_PRECISION (prod_type) != TYPE_PRECISION (half_type0) * 2)
287 half_type = TREE_TYPE (oprnd00);
288 *type_in = half_type;
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))
295 fprintf (vect_dump, "vect_recog_dot_prod_pattern: detected: ");
296 print_generic_expr (vect_dump, pattern_expr, TDF_SLIM);
302 /* Function vect_recog_widen_mult_pattern
304 Try to find the following pattern:
307 TYPE a_T, b_T, prod_T;
313 S5 prod_T = a_T * b_T;
315 where type 'TYPE' is at least double the size of type 'type'.
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.
324 * TYPE_IN: The type of the input arguments to the pattern.
326 * TYPE_OUT: The type of the output of this pattern.
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>
334 vect_recog_widen_mult_pattern (tree last_stmt,
339 tree def_stmt0, def_stmt1;
341 tree type, half_type0, half_type1;
345 enum tree_code dummy_code;
347 if (TREE_CODE (last_stmt) != GIMPLE_MODIFY_STMT)
350 expr = GIMPLE_STMT_OPERAND (last_stmt, 1);
351 type = TREE_TYPE (expr);
353 /* Starting from LAST_STMT, follow the defs of its uses in search
354 of the above pattern. */
356 if (TREE_CODE (expr) != MULT_EXPR)
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))
365 /* Check argument 0 */
366 if (!widened_name_p (oprnd0, last_stmt, &half_type0, &def_stmt0))
368 oprnd0 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt0, 1), 0);
370 /* Check argument 1 */
371 if (!widened_name_p (oprnd1, last_stmt, &half_type1, &def_stmt1))
373 oprnd1 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt1, 1), 0);
375 if (TYPE_MAIN_VARIANT (half_type0) != TYPE_MAIN_VARIANT (half_type1))
378 /* Pattern detected. */
379 if (vect_print_dump_info (REPORT_DETAILS))
380 fprintf (vect_dump, "vect_recog_widen_mult_pattern: detected: ");
382 /* Check target support */
383 vectype = get_vectype_for_scalar_type (half_type0);
385 || !supportable_widening_operation (WIDEN_MULT_EXPR, last_stmt, vectype,
386 &dummy, &dummy, &dummy_code,
391 *type_out = NULL_TREE;
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);
401 /* Function vect_recog_pow_pattern
403 Try to find the following pattern:
407 with POW being one of pow, powf, powi, powif and N being
412 * LAST_STMT: A stmt from which the pattern search begins.
416 * TYPE_IN: The type of the input arguments to the pattern.
418 * TYPE_OUT: The type of the output of this pattern.
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:
428 vect_recog_pow_pattern (tree last_stmt, tree *type_in, tree *type_out)
434 if (TREE_CODE (last_stmt) != GIMPLE_MODIFY_STMT)
437 expr = GIMPLE_STMT_OPERAND (last_stmt, 1);
438 type = TREE_TYPE (expr);
440 if (TREE_CODE (expr) != CALL_EXPR)
443 fn = get_callee_fndecl (expr);
444 switch (DECL_FUNCTION_CODE (fn))
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)
461 /* We now have a pow or powi builtin function call with a constant
464 *type_out = NULL_TREE;
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)))
472 *type_in = TREE_TYPE (base);
473 return build2 (MULT_EXPR, TREE_TYPE (base), base, base);
476 /* Catch square root. */
477 if (TREE_CODE (exp) == REAL_CST
478 && REAL_VALUES_EQUAL (TREE_REAL_CST (exp), dconsthalf))
480 tree newfn = mathfn_built_in (TREE_TYPE (base), BUILT_IN_SQRT);
481 *type_in = get_vectype_for_scalar_type (TREE_TYPE (base));
484 newfn = build_call_expr (newfn, 1, base);
485 if (vectorizable_function (newfn, *type_in, *type_in) != NULL_TREE)
494 /* Function vect_recog_widen_sum_pattern
496 Try to find the following pattern:
499 TYPE x_T, sum = init;
501 sum_0 = phi <init, sum_1>
504 S3 sum_1 = x_T + sum_0;
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.
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.
517 * TYPE_IN: The type of the input arguments to the pattern.
519 * TYPE_OUT: The type of the output of this pattern.
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>
527 vect_recog_widen_sum_pattern (tree last_stmt, tree *type_in, tree *type_out)
531 stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
532 tree type, half_type;
535 if (TREE_CODE (last_stmt) != GIMPLE_MODIFY_STMT)
538 expr = GIMPLE_STMT_OPERAND (last_stmt, 1);
539 type = TREE_TYPE (expr);
541 /* Look for the following pattern
544 In which DX is at least double the size of X, and sum_1 has been
545 recognized as a reduction variable.
548 /* Starting from LAST_STMT, follow the defs of its uses in search
549 of the above pattern. */
551 if (TREE_CODE (expr) != PLUS_EXPR)
554 if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_reduction_def)
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))
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
569 if (!widened_name_p (oprnd0, last_stmt, &half_type, &stmt))
572 oprnd0 = TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0);
573 *type_in = half_type;
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))
580 fprintf (vect_dump, "vect_recog_widen_sum_pattern: detected: ");
581 print_generic_expr (vect_dump, pattern_expr, TDF_SLIM);
587 /* Function vect_pattern_recog_1
590 PATTERN_RECOG_FUNC: A pointer to a function that detects a certain
592 STMT: A stmt from which the pattern search should start.
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.
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.
606 This function also does some bookkeeping, as explained in the documentation
607 for vect_recog_pattern. */
610 vect_pattern_recog_1 (
611 tree (* vect_recog_func) (tree, tree *, tree *),
612 block_stmt_iterator si)
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);
619 tree pattern_vectype;
620 tree type_in, type_out;
626 pattern_expr = (* vect_recog_func) (stmt, &type_in, &type_out);
630 if (VECTOR_MODE_P (TYPE_MODE (type_in)))
632 /* No need to check target support (already checked by the pattern
633 recognition function). */
634 pattern_vectype = type_in;
638 enum tree_code vec_mode;
639 enum insn_code icode;
642 /* Check target support */
643 pattern_vectype = get_vectype_for_scalar_type (type_in);
644 if (!pattern_vectype)
647 optab = optab_for_tree_code (TREE_CODE (pattern_expr), pattern_vectype);
648 vec_mode = TYPE_MODE (pattern_vectype);
650 || (icode = optab_handler (optab, vec_mode)->insn_code) ==
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))))))
659 /* Found a vectorizable pattern. */
660 if (vect_print_dump_info (REPORT_DETAILS))
662 fprintf (vect_dump, "pattern recognized: ");
663 print_generic_expr (vect_dump, pattern_expr, TDF_SLIM);
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);
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;
690 /* Function vect_pattern_recog
693 LOOP_VINFO - a struct_loop_info of a loop in which we want to look for
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:
701 At the entry to this function we have the following stmts, with the
702 following initial value in the STMT_VINFO fields:
704 stmt in_pattern_p related_stmt vec_stmt
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).. - - -
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:
717 in_pattern_p related_stmt vec_stmt
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).. - - -
725 (the last stmt in the pattern (S4) and the new pattern stmt (S6) point
726 to each other through the RELATED_STMT field).
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.
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:
739 in_pattern_p related_stmt vec_stmt
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).. - - -
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:
753 VS5: ... = ..vuse(va_new)..
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.
760 vect_pattern_recog (loop_vec_info loop_vinfo)
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;
768 tree (* vect_recog_func_ptr) (tree, tree *, tree *);
770 if (vect_print_dump_info (REPORT_DETAILS))
771 fprintf (vect_dump, "=== vect_pattern_recog ===");
773 /* Scan through the loop stmts, applying the pattern recognition
774 functions starting at each stmt visited: */
775 for (i = 0; i < nbbs; i++)
777 basic_block bb = bbs[i];
778 for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
780 stmt = bsi_stmt (si);
782 /* Scan over all generic vect_recog_xxx_pattern functions. */
783 for (j = 0; j < NUM_PATTERNS; j++)
785 vect_recog_func_ptr = vect_vect_recog_func_ptrs[j];
786 vect_pattern_recog_1 (vect_recog_func_ptr, si);