To SLP existing vector statements we must teach analysis how to construct a new
vector type from an existing one and teach passes how to analyze the lanes
produced by the vector statements.
e.g.
typedef unsigned V8 __attribute__((vector_size(32)));
void split_add (V8 *restrict out, const V8 *a, const V8 *b, unsigned n)
{
for (unsigned i = 0; i < n; ++i)
out[i] = a[i] + b[i];
}
To do this we use the innermode of the vector mode as the scalar type and let
the vectorizer request a new vector mode based on VF it requires.
I.e. a V8QI at VF 16 returns a V16QI by requesting a type capable of holding
16 nunits with base type QI. This approach also allows the vectorizer to change
ISAs. So for instance the result of this query can be VNx16QI, i.e. a poly
type.
When doing SLP build we use one scalar statement for the vector stmt but set
that the one statement consumes NUNIT lanes. i.e. SLP_TREE_LANES is adjusted.
But because of this SLP build must handle the gap when doing equivalent
statement checks when building the tree.
For this first bit we introduce a helper vect_can_revectorize_type_p which
indicates what operations we support for revectorization and initially restrict
this to just emulated vectors (i.e. unsupported vector operations). This will
be lifted in patch 7 once enough pieces are in place.
Bootstrapped Regtested on aarch64-none-linux-gnu,
arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
-m32, -m64 and no issues.
Any feedback?
Thanks,
Tamar
gcc/ChangeLog:
PR tree-optimization/119187
* tree-vect-loop.cc (vectorizable_reduction): Use vector element types.
(vect_phi_first_order_recurrence_p): Leave vector PHIs for internal
cycles.
* tree-vect-stmts.cc (vectorizable_conversion): Reject unsupported
source vector conversions.
(vectorizable_operation): Use vector element types.
(get_vectype_for_scalar_type): Accept fixed-length vector source types.
(vect_get_vector_types_for_stmt): Use vector element types.
* tree-vectorizer.cc (vect_can_revectorize_type_p): New.
* tree-vectorizer.h (vect_can_revectorize_type_p): Declare.
* tree-vect-slp.cc (vect_build_slp_tree_2): Represent complete emulated
vectors as SLP lanes rather than scalar splats.
* tree-vect-stmts.cc (vectorizable_call): Reject unsupported vector
reduction calls.
gcc/testsuite/ChangeLog:
PR tree-optimization/119187
* gcc.dg/vect/vect-revectorize-analysis.c: New test.
* gcc.dg/vect/vect-revectorize-first-order.c: New test.
* gcc.target/aarch64/vect-revectorize-first-order.c: New test.
* gcc.dg/vect/vect-revectorize-reduc-call-1.c: New test.
* gcc.dg/vect/vect-revectorize-reduc-call-2.c: New test.
---
--
diff --git a/gcc/testsuite/gcc.dg/vect/vect-revectorize-analysis.c
b/gcc/testsuite/gcc.dg/vect/vect-revectorize-analysis.c
new file mode 100644
index
0000000000000000000000000000000000000000..290dc65d1d6cd29035fc03e756f13986c1b2408e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-revectorize-analysis.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O3 -fno-vect-cost-model" } */
+
+typedef unsigned U __attribute__ ((vector_size (32)));
+typedef float F __attribute__ ((vector_size (32)));
+
+/* Analysis must use element types, and decline vector conversions that
+ need separate lane-count handling without treating vector modes as
+ scalar. */
+void
+convert_vectors (U *restrict out, const F *restrict in, unsigned n)
+{
+ for (unsigned i = 0; i < n; ++i)
+ out[i] = __builtin_convertvector (in[i] + 1.0f, U);
+}
diff --git a/gcc/testsuite/gcc.dg/vect/vect-revectorize-first-order.c
b/gcc/testsuite/gcc.dg/vect/vect-revectorize-first-order.c
new file mode 100644
index
0000000000000000000000000000000000000000..dc13f73d612c99435a627ca280920ec8d2a36c22
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-revectorize-first-order.c
@@ -0,0 +1,80 @@
+/* { dg-do run } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-additional-options "-O3 -fno-vect-cost-model" } */
+
+#include "tree-vect.h"
+
+typedef unsigned V __attribute__ ((vector_size (32)));
+
+/* A whole-vector recurrence must keep the previous source vector's
+ elements in their original lanes, including its initial value. */
+__attribute__ ((noipa)) void
+f (V *restrict out, const V *restrict in, const V *initial, unsigned n)
+{
+ V prev = *initial;
+ for (unsigned i = 0; i < n; ++i)
+ {
+ V curr = in[i];
+ out[i] = curr + prev;
+ prev = curr;
+ }
+}
+
+static const V initial = { 1000, 1017, 1034, 1051, 1068, 1085, 1102, 1119 };
+static const V in[] = {
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 100, 101, 102, 103, 104, 105, 106, 107 },
+ { 200, 201, 202, 203, 204, 205, 206, 207 },
+ { 300, 301, 302, 303, 304, 305, 306, 307 },
+ { 400, 401, 402, 403, 404, 405, 406, 407 },
+ { 500, 501, 502, 503, 504, 505, 506, 507 },
+ { 600, 601, 602, 603, 604, 605, 606, 607 },
+ { 700, 701, 702, 703, 704, 705, 706, 707 },
+ { 800, 801, 802, 803, 804, 805, 806, 807 },
+ { 900, 901, 902, 903, 904, 905, 906, 907 },
+ { 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007 },
+ { 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107 },
+ { 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207 },
+ { 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307 },
+ { 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407 },
+ { 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507 },
+ { 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607 },
+ { 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707 },
+ { 1800, 1801, 1802, 1803, 1804, 1805, 1806, 1807 }
+};
+static const V expected[] = {
+ { 1000, 1018, 1036, 1054, 1072, 1090, 1108, 1126 },
+ { 100, 102, 104, 106, 108, 110, 112, 114 },
+ { 300, 302, 304, 306, 308, 310, 312, 314 },
+ { 500, 502, 504, 506, 508, 510, 512, 514 },
+ { 700, 702, 704, 706, 708, 710, 712, 714 },
+ { 900, 902, 904, 906, 908, 910, 912, 914 },
+ { 1100, 1102, 1104, 1106, 1108, 1110, 1112, 1114 },
+ { 1300, 1302, 1304, 1306, 1308, 1310, 1312, 1314 },
+ { 1500, 1502, 1504, 1506, 1508, 1510, 1512, 1514 },
+ { 1700, 1702, 1704, 1706, 1708, 1710, 1712, 1714 },
+ { 1900, 1902, 1904, 1906, 1908, 1910, 1912, 1914 },
+ { 2100, 2102, 2104, 2106, 2108, 2110, 2112, 2114 },
+ { 2300, 2302, 2304, 2306, 2308, 2310, 2312, 2314 },
+ { 2500, 2502, 2504, 2506, 2508, 2510, 2512, 2514 },
+ { 2700, 2702, 2704, 2706, 2708, 2710, 2712, 2714 },
+ { 2900, 2902, 2904, 2906, 2908, 2910, 2912, 2914 },
+ { 3100, 3102, 3104, 3106, 3108, 3110, 3112, 3114 },
+ { 3300, 3302, 3304, 3306, 3308, 3310, 3312, 3314 },
+ { 3500, 3502, 3504, 3506, 3508, 3510, 3512, 3514 }
+};
+
+int
+main (void)
+{
+ check_vect ();
+ V out[19];
+ for (unsigned n = 0; n <= 19; ++n)
+ {
+ f (out, in, &initial, n);
+ if (__builtin_memcmp (out, expected, n * sizeof (V)) != 0)
+ __builtin_abort ();
+ }
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/vect-revectorize-reduc-call-1.c
b/gcc/testsuite/gcc.dg/vect/vect-revectorize-reduc-call-1.c
new file mode 100644
index
0000000000000000000000000000000000000000..1997f663ec75e53a953b043cff69080d7552bfaf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-revectorize-reduc-call-1.c
@@ -0,0 +1,62 @@
+/* { dg-do run } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-additional-options "-O3 -ffast-math" } */
+
+#include "tree-vect.h"
+
+#ifndef TYPE
+#define TYPE float
+#endif
+
+/* Loop vectorization creates horizontal reductions for the four sums.
+ SLP must not revectorize them as elementwise calls with vector results. */
+__attribute__ ((noipa)) void
+dot_products (TYPE *restrict out, const TYPE *restrict a,
+ const TYPE *restrict b, const TYPE *restrict c,
+ const TYPE *restrict d, unsigned n)
+{
+ TYPE w = out[0], x = out[1], y = out[2], z = out[3];
+ for (unsigned i = 0; i < n; ++i)
+ {
+ w += a[i] * b[i];
+ x += a[i] * c[i];
+ y += b[i] * c[i];
+ z += b[i] * d[i];
+ }
+
+ out[0] = w;
+ out[1] = x;
+ out[2] = y;
+ out[3] = z;
+}
+
+int
+main (void)
+{
+ check_vect ();
+ const TYPE a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ const TYPE b[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
+ const TYPE c[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
+ const TYPE d[] = { 1, 3, 5, 7, 9, 11, 13, 15 };
+ const TYPE expected[][4] = {
+ { 1, 2, 3, 4 },
+ { 3, 10, 19, 6 },
+ { 9, 24, 40, 15 },
+ { 21, 42, 64, 35 },
+ { 41, 62, 89, 70 },
+ { 71, 82, 113, 124 },
+ { 113, 100, 134, 201 },
+ { 169, 114, 150, 305 },
+ { 241, 122, 159, 440 }
+ };
+ for (unsigned n = 0; n <= 8; ++n)
+ {
+ TYPE out[] = { 1, 2, 3, 4 };
+ dot_products (out, a, b, c, d, n);
+ for (unsigned j = 0; j < 4; ++j)
+ if (out[j] != expected[n][j])
+ __builtin_abort ();
+ }
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/vect-revectorize-reduc-call-2.c
b/gcc/testsuite/gcc.dg/vect/vect-revectorize-reduc-call-2.c
new file mode 100644
index
0000000000000000000000000000000000000000..f9af8242ba3d1975d5a5076dcb37a71c90d47297
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-revectorize-reduc-call-2.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-require-effective-target vect_double } */
+/* { dg-additional-options "-O3 -ffast-math" } */
+
+#define TYPE double
+#include "vect-revectorize-reduc-call-1.c"
diff --git a/gcc/testsuite/gcc.target/aarch64/vect-revectorize-first-order.c
b/gcc/testsuite/gcc.target/aarch64/vect-revectorize-first-order.c
new file mode 100644
index
0000000000000000000000000000000000000000..dd4ee5a2fa0c88053af081755394c2ce81c69129
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/vect-revectorize-first-order.c
@@ -0,0 +1,5 @@
+/* { dg-do run { target aarch64_sve512_hw } } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-options "-O3 -march=armv8-a+sve -msve-vector-bits=512
-fno-vect-cost-model" } */
+
+#include "../../gcc.dg/vect/vect-revectorize-first-order.c"
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index
78bfd607c5d7c7548a2b33ceab148ddf98084bdf..787ad1a176f266c5b4129efc52ca24fd70952532
100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -314,6 +314,11 @@ vect_phi_first_order_recurrence_p (loop_vec_info
loop_vinfo, class loop *loop,
tree def = gimple_phi_result (phi);
+ /* First-order recurrence initialization requires scalar PHI arguments.
+ Handle vector PHIs as ordinary internal cycles instead. */
+ if (VECTOR_TYPE_P (TREE_TYPE (def)))
+ return false;
+
/* Ensure every use_stmt of the phi node is dominated by the latch
definition. */
imm_use_iterator imm_iter;
@@ -7305,12 +7310,17 @@ vectorizable_reduction (loop_vec_info loop_vinfo,
gcc_unreachable ();
bool lane_reducing = lane_reducing_op_p (op.code);
- if (!POINTER_TYPE_P (op.type) && !INTEGRAL_TYPE_P (op.type)
- && !SCALAR_FLOAT_TYPE_P (op.type))
+ tree scalar_type = op.type;
+ if (VECTOR_TYPE_P (scalar_type))
+ scalar_type = TREE_TYPE (scalar_type);
+
+ if (!POINTER_TYPE_P (scalar_type)
+ && !INTEGRAL_TYPE_P (scalar_type)
+ && !SCALAR_FLOAT_TYPE_P (scalar_type))
return false;
/* Do not try to vectorize bit-precision reductions. */
- if (!type_has_mode_precision_p (op.type)
+ if (!type_has_mode_precision_p (scalar_type)
&& op.code != BIT_AND_EXPR
&& op.code != BIT_IOR_EXPR
&& op.code != BIT_XOR_EXPR)
@@ -7582,7 +7592,7 @@ vectorizable_reduction (loop_vec_info loop_vinfo,
if (!reduc_chain
&& known_eq (LOOP_VINFO_VECT_FACTOR (loop_vinfo), 1u))
;
- else if (needs_fold_left_reduction_p (op.type, orig_code))
+ else if (needs_fold_left_reduction_p (scalar_type, orig_code))
{
/* When vectorizing a reduction chain w/o SLP the reduction PHI
is not directly used in stmt. */
@@ -7711,7 +7721,7 @@ vectorizable_reduction (loop_vec_info loop_vinfo,
else if (reduction_type == COND_REDUCTION)
{
int scalar_precision
- = GET_MODE_PRECISION (SCALAR_TYPE_MODE (op.type));
+ = GET_MODE_PRECISION (SCALAR_TYPE_MODE (scalar_type));
cr_index_scalar_type = make_unsigned_type (scalar_precision);
cr_index_vector_type = get_same_sized_vectype (cr_index_scalar_type,
vectype_out);
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index
ae73837a76df6ca7dc5a6565f5fd292dd1c40222..e67a53f68f41f9a6605a0ceba6e81495c03c0c38
100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -2145,6 +2145,33 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node,
&& !is_a<gphi *> (stmt_info->stmt))
return NULL;
+ /* A source vector with NUNITS elements occupies NUNITS consecutive SLP
+ lanes, represented by NUNITS copies of the same statement. */
+ tree lhs = gimple_get_lhs (stmt_info->stmt);
+ tree type = lhs ? TREE_TYPE (lhs) : NULL_TREE;
+ if (type && VECTOR_TYPE_P (type))
+ {
+ if (!vect_can_revectorize_type_p (type))
+ return NULL;
+
+ unsigned HOST_WIDE_INT nelts = TYPE_VECTOR_SUBPARTS (type).to_constant
();
+ if (group_size % nelts != 0)
+ return NULL;
+
+ for (unsigned i = 0; i < group_size; i += nelts)
+ {
+ tree lhs = gimple_get_lhs (stmts[i]->stmt);
+ if (!lhs || !types_compatible_p (type, TREE_TYPE (lhs)))
+ return NULL;
+
+ /* Check one source vector at a time; the next vector can have a
+ different defining statement. */
+ for (unsigned j = 1; j < nelts; ++j)
+ if (stmts[i + j] != stmts[i])
+ return NULL;
+ }
+ }
+
nops = gimple_num_args (stmt_info->stmt);
if (const int *map = vect_get_operand_map (stmt_info))
nops = map[0];
@@ -2991,10 +3018,13 @@ out:
bother to continue the build along the single-lane
graph but use a splat of the scalar value. */
stmt_vec_info first_def = oprnd_info->def_stmts[0];
+ tree first_lhs = gimple_get_lhs (first_def->stmt);
for (j = 1; j < group_size; ++j)
if (oprnd_info->def_stmts[j] != first_def)
break;
if (j == group_size
+ && (!first_lhs
+ || !vect_can_revectorize_type_p (TREE_TYPE (first_lhs)))
/* But avoid doing this for loads where we may be
able to CSE things, unless the stmt is not
vectorizable. */
@@ -3316,7 +3346,9 @@ fail:
n_vector_builds++;
}
}
- if (all_uniform_p
+
+ if ((all_uniform_p
+ && !(lhs && vect_can_revectorize_type_p (TREE_TYPE (lhs))))
|| n_vector_builds > 1
|| (n_vector_builds == children.length ()
&& is_a <gphi *> (stmt_info->stmt)))
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index
cd5462f0363b1a72a5372fc1709a0b2cb852a8a1..ddbacb597c1dd8bb516baa59c6a46808cd74a3a2
100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -3544,6 +3544,25 @@ vectorizable_call (vec_info *vinfo,
return false;
}
}
+
+ /* Revectorization here only supports elementwise calls. In particular,
+ a horizontal reduction must not become a call with a vector result.
+ Use the original statement's type, since patterns for vector operations
+ can have scalar results. */
+ tree lhs_type
+ = TREE_TYPE (gimple_get_lhs (vect_orig_stmt (stmt_info)->stmt));
+ if (VECTOR_TYPE_P (rhs_type) != VECTOR_TYPE_P (lhs_type)
+ || (VECTOR_TYPE_P (rhs_type)
+ && maybe_ne (TYPE_VECTOR_SUBPARTS (rhs_type),
+ TYPE_VECTOR_SUBPARTS (lhs_type))))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "call changes the number of source vector lanes.\n");
+
+ return false;
+ }
+
/* If all arguments are external or constant defs, infer the vector type
from the scalar type. */
if (!vectype_in)
@@ -5425,6 +5444,11 @@ vectorizable_conversion (vec_info *vinfo,
/* Check types of lhs and rhs. */
scalar_dest = gimple_get_lhs (stmt);
lhs_type = TREE_TYPE (scalar_dest);
+
+ /* Source vector conversions need separate handling of their lane counts. */
+ if (VECTOR_TYPE_P (lhs_type))
+ return false;
+
vectype_out = SLP_TREE_VECTYPE (slp_node);
/* Check the operands of the operation. */
@@ -6692,13 +6716,17 @@ vectorizable_operation (vec_info *vinfo,
}
scalar_dest = gimple_assign_lhs (stmt);
+ tree scalar_type = TREE_TYPE (scalar_dest);
+ if (VECTOR_TYPE_P (scalar_type))
+ scalar_type = TREE_TYPE (scalar_type);
+
vectype_out = SLP_TREE_VECTYPE (slp_node);
/* Most operations cannot handle bit-precision types without extra
truncations. */
bool mask_op_p = VECTOR_BOOLEAN_TYPE_P (vectype_out);
if (!mask_op_p
- && !type_has_mode_precision_p (TREE_TYPE (scalar_dest))
+ && !type_has_mode_precision_p (scalar_type)
/* Exception are bitwise binary operations. */
&& code != BIT_IOR_EXPR
&& code != BIT_XOR_EXPR
@@ -6732,7 +6760,7 @@ vectorizable_operation (vec_info *vinfo,
type. */
if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op0)))
{
- if (!VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (scalar_dest)))
+ if (!VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -13527,17 +13555,24 @@ get_related_vectype_for_scalar_type (machine_mode
prevailing_mode,
return vectype;
}
-/* Function get_vectype_for_scalar_type.
-
- Returns the vector type corresponding to SCALAR_TYPE as supported
- by the target. If GROUP_SIZE is nonzero and we're performing BB
- vectorization, make sure that the number of elements in the vector
- is no bigger than GROUP_SIZE. */
+/* Return the vector type supported by the target for SCALAR_TYPE, which
+ can also be a fixed-length vector type representing multiple source
+ lanes. If GROUP_SIZE is nonzero and we're performing BB vectorization,
+ make sure that the number of elements in the vector is no bigger than
+ GROUP_SIZE. GROUP_SIZE counts element lanes in either case. */
tree
get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type,
unsigned int group_size)
{
+ if (VECTOR_TYPE_P (scalar_type))
+ {
+ if (!TYPE_VECTOR_SUBPARTS (scalar_type).is_constant ())
+ return NULL_TREE;
+
+ scalar_type = TREE_TYPE (scalar_type);
+ }
+
/* For BB vectorization, we should always have a group size once we've
constructed the SLP tree; the only valid uses of zero GROUP_SIZEs
are tentative requests during things like early data reference
@@ -13588,9 +13623,8 @@ get_vectype_for_scalar_type (vec_info *vinfo, tree
scalar_type,
return vectype;
}
-/* Return the vector type corresponding to SCALAR_TYPE as supported
- by the target. NODE, if nonnull, is the SLP tree node that will
- use the returned vector type. */
+/* Like above, but NODE, if nonnull, is the SLP tree node that will use the
+ returned vector type. */
tree
get_vectype_for_scalar_type (vec_info *vinfo, tree scalar_type, slp_tree node)
@@ -14691,11 +14725,6 @@ vect_get_vector_types_for_stmt (vec_info *vinfo,
stmt_vec_info stmt_info,
dump_printf_loc (MSG_NOTE, vect_location, "vectype: %T\n", vectype);
}
- if (scalar_type && VECTOR_MODE_P (TYPE_MODE (scalar_type)))
- return opt_result::failure_at (stmt,
- "not vectorized: vector stmt in loop:%G",
- stmt);
-
*stmt_vectype_out = vectype;
return opt_result::success ();
}
diff --git a/gcc/tree-vectorizer.cc b/gcc/tree-vectorizer.cc
index
e089adddca0db7238ce0f88f79fb88b3439620d1..496fb5830d2748bcc37785f542d86add5f1b9d18
100644
--- a/gcc/tree-vectorizer.cc
+++ b/gcc/tree-vectorizer.cc
@@ -97,6 +97,16 @@ auto_purge_vect_location::~auto_purge_vect_location ()
vect_location = dump_user_location_t ();
}
+/* Return true if TYPE is a fixed-length emulated source vector type. */
+
+bool
+vect_can_revectorize_type_p (tree type)
+{
+ return (VECTOR_TYPE_P (type)
+ && TYPE_VECTOR_SUBPARTS (type).is_constant ()
+ && vect_emulated_vector_p (type));
+}
+
/* Dump a cost entry according to args to F. */
void
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index
7184f193b0748e94cd226a18918c6283112590df..e1d3fd47af5e7f8c0a968267d700f6a0270321a6
100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -2818,6 +2818,7 @@ extern bool vect_get_range_info (tree, wide_int*,
wide_int*);
void vect_pattern_recog (vec_info *);
/* In tree-vectorizer.cc. */
+extern bool vect_can_revectorize_type_p (tree);
unsigned vectorize_loops (void);
void vect_free_loop_info_assumptions (class loop *);
gimple *vect_loop_vectorized_call (class loop *, gcond **cond = NULL);