On Fri, Jul 10, 2026 at 6:16 PM Robin Dapp <[email protected]> wrote:
>
> From: Robin Dapp <[email protected]>
>
> This patch makes use of the preparational patches and actives
> non-wrapping DR analysis. The resulting nowrap bounds are collected and
> added to the existing niter assumptions by ANDing each term.
>
> 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.
> (vect_reset_dr): New function.
> * 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 (vect_reset_dr): Declare.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/tree-prof/update-loopch.c:
> * gcc.dg/tree-ssa/scev-12.c:
> * gcc.dg/tree-ssa/scev-8.c:
> * 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.
>
> vec
> ---
> .../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 ++
> gcc/tree-vect-data-refs.cc | 15 +-
> gcc/tree-vect-loop.cc | 164 +++++++++++++++---
> gcc/tree-vectorizer.h | 1 +
> 14 files changed, 292 insertions(+), 30 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/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
> index ab850de024b..4d90d285458 100644
> --- a/gcc/tree-vect-data-refs.cc
> +++ b/gcc/tree-vect-data-refs.cc
> @@ -5180,7 +5180,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;
>
> @@ -5237,7 +5237,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)
> @@ -5318,6 +5319,16 @@ vect_find_stmt_data_reference (loop_p loop, gimple
> *stmt,
> return opt_result::success ();
> }
>
> +/* Reset DR_INNERMOST, DR_NOWRAP_BOUND, and access functions of DR. */
> +
> +void
> +vect_reset_dr (data_reference *dr)
I think this belongs in tree-data-ref.cc, but I also wonder whether
it should be done upon analysis therein already?
> +{
> + DR_INNERMOST (dr) = innermost_loop_behavior ();
> + DR_NOWRAP_BOUND (dr) = NULL_TREE;
> + dr->indices.access_fns.release ();
> +}
> +
> /* Function vect_analyze_data_refs.
>
> Find all the data references in the loop or basic block.
> diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
> index 931b942d7cb..3908cad5714 100644
> --- a/gcc/tree-vect-loop.cc
> +++ b/gcc/tree-vect-loop.cc
> @@ -1651,17 +1651,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 ();
> }
>
> @@ -2053,6 +2042,132 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block
> *bbs,
> return opt_result::success ();
> }
>
> +/* Collect the data references of LOOP into SHARED. Return true if
> + all references could be analyzed and false otherwise. */
> +
> +static opt_result
> +vect_get_loop_datarefs (class loop *loop, vec_info_shared *shared)
> +{
> + basic_block *bbs = XCNEWVEC (basic_block, loop->num_nodes);
> + unsigned int nbbs = dfs_enumerate_from (loop->header, 0, bb_in_loop_p, bbs,
> + loop->num_nodes, loop);
> + gcc_assert (nbbs == loop->num_nodes);
> + opt_result res = vect_get_datarefs_in_loop (loop, bbs, &shared->datarefs);
> + free (bbs);
> + if (!res && 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;
> +}
> +
> +/* 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;
> +
> + unsigned int i;
> + struct data_reference *dr;
> + FOR_EACH_VEC_ELT (shared->datarefs, i, dr)
> + {
> + tree bound = DR_NOWRAP_BOUND (dr);
> + if (!bound)
> + continue;
> +
> + /* Build the assumption "NITER <= BOUND" */
> + tree assum = NULL_TREE;
> + if (niter_known)
> + {
> + unsigned prec = MAX (TYPE_PRECISION (TREE_TYPE (niter)),
> + TYPE_PRECISION (TREE_TYPE (bound)));
> + tree t = build_nonstandard_integer_type (prec, 1);
> + assum = fold_build2 (LE_EXPR, boolean_type_node,
> + fold_convert (t, niter),
> + fold_convert (t, bound));
Maybe use ranger to try to simplify this to true/false? I think
you can simply use range_of_expr on assum like
if (get_range_query (cfun)->range_on_edge (vr,
loop_preheader_edge (loop), assum)
&& vr.singleton_p (&new_assum))
assum = new_assum;
or so.
> + }
> +
> + if (assum && integer_onep (assum))
> + continue;
> +
> + if (!assum || integer_zerop (assum))
> + {
> + vect_reset_dr (dr);
See above. Btw, what happens after this? We'll eventually get
gather/scatter?
> +
> + if (dump_enabled_p ())
> + dump_printf_loc (MSG_NOTE, vect_location,
> + "data reference address wraps, discarding "
> + "no-wrap assumption: %G", DR_STMT (dr));
> + continue;
> + }
> +
> + /* Accumulate assumptions. */
> + if (nowrap_assum && nowrap_assum != assum)
> + nowrap_assum = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
> + nowrap_assum, assum);
> + else
> + nowrap_assum = assum;
I wonder how ugly "related" assumptions get for grouped accesses?
> + }
> +
> + /* 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);
So this is still needed?
> + }
> + 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:
> @@ -2952,21 +3067,18 @@ 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))
> - {
> - /* 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);
> +
> + res = vect_get_loop_datarefs (loop, shared);
> + if (!res)
> + return opt_loop_vec_info::propagate_failure (res);
you are not removing the dataref compute from vect_analyze_loop_2?
I think it's OK to do earlier, but can we keep bbs[] computed once?
Like split out a function from the _loop_vec_info CTOR and
put bbs into vect_loop_form_info passing bbs to the CTOR as argument?
Otherwise looks OK to me.
Richard.
> +
> + res = vect_build_assumptions (loop, shared, &loop_form_info);
> + if (!res)
> + return opt_loop_vec_info::propagate_failure (res);
> +
> + /* vect_build_assumptions can still invalidate a dataref
> + but from here on they are fixed. */
> + shared->save_datarefs ();
>
> auto_vector_modes vector_modes;
> /* Autodetect first vector size we try. */
> diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> index 2e4756926f2..d23c618d22c 100644
> --- a/gcc/tree-vectorizer.h
> +++ b/gcc/tree-vectorizer.h
> @@ -2650,6 +2650,7 @@ extern void vect_describe_gather_scatter_call
> (stmt_vec_info,
> extern opt_result vect_find_stmt_data_reference (loop_p, gimple *,
> vec<data_reference_p> *,
> vec<int> *, int);
> +extern void vect_reset_dr (data_reference *);
> extern opt_result vect_analyze_data_refs (vec_info *, bool *);
> extern void vect_record_base_alignments (vec_info *);
> extern tree vect_create_data_ref_ptr (vec_info *,
> --
> 2.54.0
>