From: Robin Dapp <[email protected]>
This patch makes use of the preparational patches and activates
non-wrapping DR analysis. The resulting nowrap bounds for each DR
are collected by taking the minimum and a final new assumption
niter < bounds_min is ANDed into the niter assumptions.
We cannot yet fully get rid of LOOP_C_FINITE but there is not a lot
missing. I hope to finish that after this series.
I needed to move DR analysis a bit earlier in order to re-use niter
checks and dumps. We now retrieve the DRs directly after
vect_analyze_loop_form, then build the assumptions and check them.
Afterwards, the DRs are finalized.
The vect tests are unchanged from my last patch attempt. Test 1-3
are based on 557.xz's hot loop.
PR tree-optimization/121908
gcc/ChangeLog:
* tree-vect-data-refs.cc (vect_find_stmt_data_reference):
Allow non-wrapping DR analysis.
* tree-vect-loop.cc (vect_analyze_loop_form): Defer assumption
checking.
(vect_get_loop_datarefs): New function.
(vect_build_assumptions): New function.
(vect_analyze_loop): Use new functions.
* tree-vectorizer.h (struct vect_loop_form_info): Add BB param.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-prof/update-loopch.c: Disable vectorization.
* gcc.dg/tree-ssa/scev-12.c: Ditto.
* gcc.dg/tree-ssa/scev-8.c: Ditto.
* gcc.target/aarch64/sve2/niter-convert-range.c: Expect one more
dump instance.
* gcc.dg/vect/vect-unsigned-assump-1.c: New test.
* gcc.dg/vect/vect-unsigned-assump-2.c: New test.
* gcc.dg/vect/vect-unsigned-assump-3.c: New test.
* gcc.dg/vect/vect-unsigned-assump-4.c: New test.
* gcc.dg/vect/vect-unsigned-assump-5.c: New test.
* gcc.dg/vect/vect-unsigned-assump-6.c: New test.
* gcc.dg/vect/vect-unsigned-assump-7.c: New test.
* gcc.dg/vect/vect-unsigned-assump-8.c: New test.
---
.../gcc.dg/tree-prof/update-loopch.c | 2 +
gcc/testsuite/gcc.dg/tree-ssa/scev-12.c | 2 +-
gcc/testsuite/gcc.dg/tree-ssa/scev-8.c | 2 +-
.../gcc.dg/vect/vect-unsigned-assump-1.c | 22 ++
.../gcc.dg/vect/vect-unsigned-assump-2.c | 24 ++
.../gcc.dg/vect/vect-unsigned-assump-3.c | 20 ++
.../gcc.dg/vect/vect-unsigned-assump-4.c | 13 ++
.../gcc.dg/vect/vect-unsigned-assump-5.c | 14 ++
.../gcc.dg/vect/vect-unsigned-assump-6.c | 13 ++
.../gcc.dg/vect/vect-unsigned-assump-7.c | 17 ++
.../gcc.dg/vect/vect-unsigned-assump-8.c | 13 ++
.../aarch64/sve2/niter-convert-range.c | 2 +-
gcc/tree-vect-data-refs.cc | 5 +-
gcc/tree-vect-loop.cc | 218 ++++++++++++------
gcc/tree-vectorizer.h | 4 +-
15 files changed, 296 insertions(+), 75 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-1.c
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-2.c
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-3.c
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-4.c
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-5.c
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-6.c
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-7.c
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-8.c
diff --git a/gcc/testsuite/gcc.dg/tree-prof/update-loopch.c
b/gcc/testsuite/gcc.dg/tree-prof/update-loopch.c
index a30b895bb67..efb92b2c4fc 100644
--- a/gcc/testsuite/gcc.dg/tree-prof/update-loopch.c
+++ b/gcc/testsuite/gcc.dg/tree-prof/update-loopch.c
@@ -5,6 +5,8 @@ int
main ()
{
int i;
+/* If we vectorize this, the block count changes which defies the test. */
+#pragma GCC novector
for (i = 0; i < max; i++)
{
a[i % 8]++;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-12.c
b/gcc/testsuite/gcc.dg/tree-ssa/scev-12.c
index e2ded46047e..b0feee911c1 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-12.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-12.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-ivopts-details" } */
+/* { dg-options "-O2 -fno-tree-vectorize -fdump-tree-ivopts-details" } */
int a[128];
extern int b[];
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c
b/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c
index a5b2ff71958..abdbf0250dd 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-ivopts-details" } */
+/* { dg-options "-O2 -fno-tree-vectorize -fdump-tree-ivopts-details" } */
int *a;
diff --git a/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-1.c
b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-1.c
new file mode 100644
index 00000000000..2c64eb890fd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_early_break } */
+
+#define uint8_t unsigned char
+#define uint32_t unsigned int
+
+int foo (const uint8_t *const cur, uint32_t len, uint32_t len_limit,
+ uint32_t pos, uint32_t cur_match)
+{
+ const uint32_t delta = pos - cur_match;
+ const uint8_t *pb = cur - delta;
+
+ while (++len != len_limit)
+ if (pb[len] != cur[len])
+ break;
+
+ return len;
+}
+
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
+/* { dg-final { scan-tree-dump "adding no-wrap assumption" "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-2.c
b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-2.c
new file mode 100644
index 00000000000..a071ec399f0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_early_break } */
+/* { dg-require-effective-target vect_load_lanes } */
+
+#define uint8_t unsigned char
+#define uint32_t unsigned int
+
+int foo (const uint8_t *const cur, uint32_t len, uint32_t len_limit,
+ uint32_t pos, uint32_t cur_match)
+{
+ const uint32_t delta = pos - cur_match;
+ const uint8_t *pb = cur - delta;
+
+ /* We vectorize this with struct loads right now. */
+ while ((len += 2) != len_limit)
+ if (pb[len] != cur[len])
+ break;
+
+ return len;
+}
+
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
+/* { dg-final { scan-tree-dump "adding no-wrap assumption" "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-3.c
b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-3.c
new file mode 100644
index 00000000000..c9f6c2b0ca7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-3.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_early_break } */
+
+#define uint8_t unsigned char
+#define uint32_t unsigned int
+
+int foo (const uint8_t *const cur, uint32_t n)
+{
+ uint32_t i = 15;
+
+ while (i++ != n)
+ if (cur[i - 15] != cur[i])
+ break;
+
+ return i;
+}
+
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
+/* { dg-final { scan-tree-dump "adding no-wrap assumption" "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-4.c
b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-4.c
new file mode 100644
index 00000000000..8ba7ce435f9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-4.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fno-builtin" } */
+/* { dg-require-effective-target vect_int } */
+
+/* We should vectorize this without additional assumptions.
+ The data-ref uses a pointer-based access which never wraps. */
+
+void f4 (int *p, unsigned start, unsigned end) {
+ for (unsigned i = start; i != end; i++)
+ *p++ = 0;
+}
+
+/* { dg-final { scan-tree-dump-not "adding no-wrap assumption" "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-5.c
b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-5.c
new file mode 100644
index 00000000000..2922fd1c114
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-5.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_gather_load_ifn } */
+
+/* This should be vectorized without gather/scatter. */
+
+void f5 (int *__restrict a, int *__restrict b, unsigned start, unsigned end) {
+ for (unsigned i = start; i != end; i++)
+ a[i] = b[i];
+}
+
+/* { dg-final { scan-tree-dump-not "gather" "vect" } } */
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
+/* { dg-final { scan-tree-dump "adding no-wrap assumption" "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-6.c
b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-6.c
new file mode 100644
index 00000000000..e869e8095ea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-6.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_gather_load_ifn } */
+
+/* This should be vectorized without gather/scatter. */
+
+void f6 (int *__restrict a, int *__restrict b, unsigned start, unsigned end) {
+ for (unsigned i = start; i <= end; i++)
+ a[i] = b[i];
+}
+
+/* { dg-final { scan-tree-dump-not "gather" "vect" } } */
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-7.c
b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-7.c
new file mode 100644
index 00000000000..6d7df016a13
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-7.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+
+/* This should be vectorized without gather/scatter. */
+
+void f7 (int *__restrict dst, unsigned n) {
+ unsigned i = 1;
+ while (i != n)
+ {
+ dst[i] = i;
+ i++;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "gather" "vect" } } */
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */
+/* { dg-final { scan-tree-dump "adding no-wrap assumption" "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-8.c
b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-8.c
new file mode 100644
index 00000000000..37d76304274
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-unsigned-assump-8.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fno-builtin" } */
+/* { dg-require-effective-target vect_int } */
+
+/* We should vectorize this without additional assumptions.
+ The data-ref uses a pointer-based access which never wraps. */
+
+void f8 (int *__restrict a, unsigned start, unsigned n) {
+ for (unsigned i = start; i != n; i++)
+ a[i - start] = 0;
+}
+
+/* { dg-final { scan-tree-dump-not "adding no-wrap assumption" "vect" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/niter-convert-range.c
b/gcc/testsuite/gcc.target/aarch64/sve2/niter-convert-range.c
index c96b2f3999c..58b946782cb 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve2/niter-convert-range.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve2/niter-convert-range.c
@@ -64,5 +64,5 @@ niter_convert_range_wrap (unsigned char *buf, uint8_t len)
/* { dg-final { scan-tree-dump-times {bounds on difference of bases: 0
[.][.][.] 126} 3 "vect" } } */
/* { dg-final { scan-tree-dump-times {bounds on difference of bases: 0
[.][.][.] 254} 9 "vect" } } */
-/* { dg-final { scan-tree-dump-times {bounds on difference of bases: -1
[.][.][.] 4294967294} 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times {bounds on difference of bases: -1
[.][.][.] 4294967294} 4 "vect" } } */
/* { dg-final { scan-tree-dump-times "loop vectorized using variable length
vectors" 5 "vect" } } */
diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
index 0bb5ea3115e..a7ef08e9441 100644
--- a/gcc/tree-vect-data-refs.cc
+++ b/gcc/tree-vect-data-refs.cc
@@ -5062,7 +5062,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
stmt);
auto_vec<data_reference_p, 2> refs;
- opt_result res = find_data_references_in_stmt (loop, stmt, &refs);
+ opt_result res = find_data_references_in_stmt (loop, stmt, &refs, true);
if (!res)
return res;
@@ -5119,7 +5119,8 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
{
struct data_reference *newdr
= create_data_ref (NULL, loop_containing_stmt (stmt), DR_REF (dr), stmt,
- DR_IS_READ (dr), DR_IS_CONDITIONAL_IN_STMT (dr));
+ DR_IS_READ (dr), DR_IS_CONDITIONAL_IN_STMT (dr),
+ true);
if (DR_BASE_ADDRESS (newdr)
&& DR_OFFSET (newdr)
&& DR_INIT (newdr)
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index 4a049238142..4d08f6510c8 100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -717,11 +717,28 @@ bb_in_loop_p (const_basic_block bb, const void *data)
return false;
}
+/* Get and return the basic blocks of LOOP in DFS order. Store the number of
+ BBs in NBBS. */
+
+static basic_block *
+vect_get_loop_dfs_bbs (class loop *loop, unsigned int *nbbs)
+{
+ /* CHECKME: We want to visit all BBs before their successors (except for
+ latch blocks, for which this assertion wouldn't hold). In the simple
+ case of the loop forms we allow, a dfs order of the BBs would the same
+ as reversed postorder traversal, so we are safe. */
+ basic_block *bbs = XCNEWVEC (basic_block, loop->num_nodes);
+ *nbbs = dfs_enumerate_from (loop->header, 0, bb_in_loop_p, bbs,
+ loop->num_nodes, loop);
+ gcc_assert (*nbbs == loop->num_nodes);
+ return bbs;
+}
/* Create and initialize a new loop_vec_info struct for LOOP_IN, as well as
stmt_vec_info structs for all the stmts in LOOP_IN. */
-_loop_vec_info::_loop_vec_info (class loop *loop_in, vec_info_shared *shared)
+_loop_vec_info::_loop_vec_info (class loop *loop_in, vec_info_shared *shared,
+ basic_block *bbs_in)
: vec_info (vec_info::loop, shared),
loop (loop_in),
num_itersm1 (NULL_TREE),
@@ -779,15 +796,9 @@ _loop_vec_info::_loop_vec_info (class loop *loop_in,
vec_info_shared *shared)
early_break_needs_epilogue (false),
early_break_niters_var (NULL)
{
- /* CHECKME: We want to visit all BBs before their successors (except for
- latch blocks, for which this assertion wouldn't hold). In the simple
- case of the loop forms we allow, a dfs order of the BBs would the same
- as reversed postorder traversal, so we are safe. */
-
- bbs = XCNEWVEC (basic_block, loop->num_nodes);
- nbbs = dfs_enumerate_from (loop->header, 0, bb_in_loop_p, bbs,
- loop->num_nodes, loop);
- gcc_assert (nbbs == loop->num_nodes);
+ nbbs = loop->num_nodes;
+ bbs = XNEWVEC (basic_block, nbbs);
+ memcpy (bbs, bbs_in, nbbs * sizeof (basic_block));
for (unsigned int i = 0; i < nbbs; i++)
{
@@ -1466,22 +1477,21 @@ vect_analyze_loop_form (class loop *loop, gimple
*loop_vectorized_call,
exit_e->src->index, exit_e->dest->index, exit_e->aux);
/* Check if we have any control flow that doesn't leave the loop. */
- basic_block *bbs = get_loop_body (loop);
- for (unsigned i = 0; i < loop->num_nodes; i++)
- if (EDGE_COUNT (bbs[i]->succs) != 1
- && (EDGE_COUNT (bbs[i]->succs) != 2
- || !loop_exits_from_bb_p (bbs[i]->loop_father, bbs[i])))
- {
- free (bbs);
- return opt_result::failure_at (vect_location,
- "not vectorized:"
- " unsupported control flow in loop.\n");
- }
+ unsigned int nbbs;
+ info->bbs = vect_get_loop_dfs_bbs (loop, &nbbs);
+ for (unsigned i = 0; i < nbbs; i++)
+ if (EDGE_COUNT (info->bbs[i]->succs) != 1
+ && (EDGE_COUNT (info->bbs[i]->succs) != 2
+ || !loop_exits_from_bb_p (info->bbs[i]->loop_father,
+ info->bbs[i])))
+ return opt_result::failure_at (vect_location,
+ "not vectorized:"
+ " unsupported control flow in loop.\n");
/* Check if we have any control flow that doesn't leave the loop. */
bool has_phi = false;
- for (unsigned i = 0; i < loop->num_nodes; i++)
- if (!gimple_seq_empty_p (phi_nodes (bbs[i])))
+ for (unsigned i = 0; i < nbbs; i++)
+ if (!gimple_seq_empty_p (phi_nodes (info->bbs[i])))
{
has_phi = true;
break;
@@ -1491,8 +1501,6 @@ vect_analyze_loop_form (class loop *loop, gimple
*loop_vectorized_call,
"not vectorized:"
" no scalar evolution detected in loop.\n");
- free (bbs);
-
/* Different restrictions apply when we are considering an inner-most loop,
vs. an outer (nested) loop.
(FORNOW. May want to relax some of these restrictions in the future). */
@@ -1651,17 +1659,6 @@ vect_analyze_loop_form (class loop *loop, gimple
*loop_vectorized_call,
}
}
- if (!integer_onep (info->assumptions))
- {
- if (dump_enabled_p ())
- {
- dump_printf_loc (MSG_NOTE, vect_location,
- "Loop to be versioned with niter assumption ");
- dump_generic_expr (MSG_NOTE, TDF_SLIM, info->assumptions);
- dump_printf (MSG_NOTE, "\n");
- }
- }
-
return opt_result::success ();
}
@@ -1673,7 +1670,7 @@ vect_create_loop_vinfo (class loop *loop, vec_info_shared
*shared,
const vect_loop_form_info *info,
loop_vec_info orig_loop_info)
{
- loop_vec_info loop_vinfo = new _loop_vec_info (loop, shared);
+ loop_vec_info loop_vinfo = new _loop_vec_info (loop, shared, info->bbs);
LOOP_VINFO_NITERSM1 (loop_vinfo) = info->number_of_iterationsm1;
LOOP_VINFO_NITERS (loop_vinfo) = info->number_of_iterations;
LOOP_VINFO_NITERS_UNCHANGED (loop_vinfo) = info->number_of_iterations;
@@ -2053,6 +2050,104 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block
*bbs,
return opt_result::success ();
}
+/* Gather no-wrap bounds from SHARED's datarefs and accumulate them in
+ one assumption. Validate this assumption, as well as INFO's niter
+ assumption and return an error on failure.
+ If the assumptions are valid, reset loop properties as well as
+ scev's hashtable and return success. */
+
+static opt_result
+vect_build_assumptions (class loop *loop, vec_info_shared *shared,
+ vect_loop_form_info *info)
+{
+ tree niter = info->number_of_iterations;
+ bool niter_known = niter && !chrec_contains_undetermined (niter);
+
+ /* Accumulate the surviving nowrap predicates separately so we can report
+ just them, rather than the union with the pre-existing niter
+ assumptions. */
+ tree nowrap_assum = NULL_TREE;
+ tree bound_min = NULL_TREE;
+
+ unsigned int i;
+ struct data_reference *dr;
+
+ /* Build the minimum over all nowrap bounds. */
+ FOR_EACH_VEC_ELT (shared->datarefs, i, dr)
+ {
+ tree bound = DR_NOWRAP_BOUND (dr);
+ if (!bound)
+ continue;
+
+ /* Use scev's function to MIN two bounds. */
+ scev_combine_nowrap_bounds (&bound_min, bound);
+ }
+
+ /* Build "NITER < BOUND_MIN". */
+ if (niter_known && bound_min)
+ {
+ unsigned prec = MAX (TYPE_PRECISION (TREE_TYPE (niter)),
+ TYPE_PRECISION (TREE_TYPE (bound_min)));
+ tree t = build_nonstandard_integer_type (prec, 1);
+ nowrap_assum = fold_build2 (LE_EXPR, boolean_type_node,
+ fold_convert (t, niter),
+ fold_convert (t, bound_min));
+
+ /* Try to simplify the assumption with ranger. */
+ value_range vr (TREE_TYPE (nowrap_assum));
+ tree better_assum;
+ if (get_range_query (cfun)->range_on_edge
+ (vr, loop_preheader_edge (loop), nowrap_assum)
+ && vr.singleton_p (&better_assum))
+ nowrap_assum = better_assum;
+ }
+
+ /* Combine nowrap assumptions and niter assumption. */
+ if (nowrap_assum)
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_NOTE, vect_location,
+ "adding no-wrap assumption: %T\n", nowrap_assum);
+
+ if (info->assumptions && !integer_onep (info->assumptions))
+ nowrap_assum = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
+ info->assumptions, nowrap_assum);
+ info->assumptions = nowrap_assum;
+ }
+
+ if (integer_zerop (info->assumptions))
+ return opt_result::failure_at
+ (vect_location,
+ "not vectorized: number of iterations cannot be computed.\n");
+
+ if (!integer_onep (info->assumptions))
+ {
+ if (dump_enabled_p ())
+ {
+ dump_printf_loc (MSG_NOTE, vect_location,
+ "Loop to be versioned with assumption ");
+ dump_generic_expr (MSG_NOTE, TDF_SLIM, info->assumptions);
+ dump_printf (MSG_NOTE, "\n");
+ }
+
+ /* We consider to vectorize this loop by versioning it under
+ some assumptions. In order to do this, we need to clear
+ existing information computed by scev and niter analyzer. */
+ scev_reset_htab ();
+ free_numbers_of_iterations_estimates (loop);
+ /* Also set flag for this loop so that following scev and niter
+ analysis are done under the assumptions. */
+ loop_constraint_set (loop, LOOP_C_FINITE);
+ }
+ else
+ /* Clear the existing niter information to make sure the nonwrapping flag
+ will be calculated and set propriately. */
+ free_numbers_of_iterations_estimates (loop);
+
+ return opt_result::success ();
+}
+
+
/* Determine if operating on full vectors for LOOP_VINFO might leave
some scalar iterations still to do. If so, decide how we should
handle those scalar iterations. The possibilities are:
@@ -2185,25 +2280,8 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, int
masked_p, bool &fatal,
loop_p loop = LOOP_VINFO_LOOP (loop_vinfo);
- /* Gather the data references. */
- if (!LOOP_VINFO_DATAREFS (loop_vinfo).exists ())
- {
- opt_result res
- = vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
- &LOOP_VINFO_DATAREFS (loop_vinfo));
- if (!res)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "not vectorized: loop contains function "
- "calls or data references that cannot "
- "be analyzed\n");
- return res;
- }
- loop_vinfo->shared->save_datarefs ();
- }
- else
- loop_vinfo->shared->check_datarefs ();
+ /* Check the data references. */
+ loop_vinfo->shared->check_datarefs ();
/* Analyze the data references and also adjust the minimal
vectorization factor according to the loads and stores. */
@@ -2952,21 +3030,23 @@ vect_analyze_loop (class loop *loop, gimple
*loop_vectorized_call,
"bad loop form.\n");
return opt_loop_vec_info::propagate_failure (res);
}
- if (!integer_onep (loop_form_info.assumptions))
+
+ res = vect_get_datarefs_in_loop (loop, loop_form_info.bbs,
+ &shared->datarefs);
+ if (!res)
{
- /* We consider to vectorize this loop by versioning it under
- some assumptions. In order to do this, we need to clear
- existing information computed by scev and niter analyzer. */
- scev_reset_htab ();
- free_numbers_of_iterations_estimates (loop);
- /* Also set flag for this loop so that following scev and niter
- analysis are done under the assumptions. */
- loop_constraint_set (loop, LOOP_C_FINITE);
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "not vectorized: loop contains function "
+ "calls or data references that cannot "
+ "be analyzed\n");
+ return opt_loop_vec_info::propagate_failure (res);
}
- else
- /* Clear the existing niter information to make sure the nonwrapping flag
- will be calculated and set propriately. */
- free_numbers_of_iterations_estimates (loop);
+ shared->save_datarefs ();
+
+ res = vect_build_assumptions (loop, shared, &loop_form_info);
+ if (!res)
+ return opt_loop_vec_info::propagate_failure (res);
auto_vector_modes vector_modes;
/* Autodetect first vector size we try. */
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index facbf90c089..4108ebb02ee 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -950,7 +950,7 @@ struct vect_reusable_accumulator {
/*-----------------------------------------------------------------*/
typedef class _loop_vec_info : public vec_info {
public:
- _loop_vec_info (class loop *, vec_info_shared *);
+ _loop_vec_info (class loop *, vec_info_shared *, basic_block *);
~_loop_vec_info ();
/* The loop to which this info struct refers to. */
@@ -2709,6 +2709,8 @@ struct vect_loop_form_info
auto_vec<gcond *> conds;
gcond *inner_loop_cond;
edge loop_exit;
+ basic_block *bbs = nullptr;
+ ~vect_loop_form_info () { free (bbs); }
};
extern opt_result vect_analyze_loop_form (class loop *, gimple *,
vect_loop_form_info *);
--
2.55.0