Apply maximum nunits for BB SLP
authorRichard Sandiford <richard.sandiford@arm.com>
Sat, 16 Nov 2019 10:29:31 +0000 (10:29 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sat, 16 Nov 2019 10:29:31 +0000 (10:29 +0000)
commit9b75f56d4b7951c60a656396dddd4a65787b95bc
tree5908e1c542d7e66687f8d2141198f3323e3a51eb
parent23ff8c05804c2d3fc6e9179d2e9c2940ae53d592
Apply maximum nunits for BB SLP

The BB vectoriser picked vector types in the same way as the loop
vectoriser: it picked a vector mode/size for the region and then
based all the vector types off that choice.  This meant we could
end up trying to use vector types that had too many elements for
the group size.

The main part of this patch is therefore about passing the SLP
group size down to routines like get_vectype_for_scalar_type and
ensuring that each vector type in the SLP tree is chosen wrt the
group size.  That part in itself is pretty easy and mechanical.

The main warts are:

(1) We normally pick a STMT_VINFO_VECTYPE for data references at an
    early stage (vect_analyze_data_refs).  However, nothing in the
    BB vectoriser relied on this, or on the min_vf calculated from it.
    I couldn't see anything other than vect_recog_bool_pattern that
    tried to access the vector type before the SLP tree is built.

(2) It's possible for the same statement to be used in groups of
    different sizes.  Taking the group size into account meant that
    we could try to pick different vector types for the same statement.

    This problem should go away with the move to doing everything on
    SLP trees, where presumably we would attach the vector type to the
    SLP node rather than the stmt_vec_info.  Until then, the patch just
    uses a first-come, first-served approach.

(3) A similar problem exists for grouped data references, where
    different statements in the same dataref group could be used
    in SLP nodes that have different group sizes.  The patch copes
    with that by making sure that all vector types in a dataref
    group remain consistent.

The patch means that:

    void
    f (int *x, short *y)
    {
      x[0] += y[0];
      x[1] += y[1];
      x[2] += y[2];
      x[3] += y[3];
    }

now produces:

        ldr     q0, [x0]
        ldr     d1, [x1]
        saddw   v0.4s, v0.4s, v1.4h
        str     q0, [x0]
        ret

instead of:

        ldrsh   w2, [x1]
        ldrsh   w3, [x1, 2]
        fmov    s0, w2
        ldrsh   w2, [x1, 4]
        ldrsh   w1, [x1, 6]
        ins     v0.s[1], w3
        ldr     q1, [x0]
        ins     v0.s[2], w2
        ins     v0.s[3], w1
        add     v0.4s, v0.4s, v1.4s
        str     q0, [x0]
        ret

Unfortunately it also means we start to vectorise
gcc.target/i386/pr84101.c for -m32.  That seems like a target
cost issue though; see PR92265 for details.

2019-11-16  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* tree-vectorizer.h (vect_get_vector_types_for_stmt): Take an
optional maximum nunits.
(get_vectype_for_scalar_type): Likewise.  Also declare a form that
takes an slp_tree.
(get_mask_type_for_scalar_type): Take an optional slp_tree.
(vect_get_mask_type_for_stmt): Likewise.
* tree-vect-data-refs.c (vect_analyze_data_refs): Don't store
the vector type in STMT_VINFO_VECTYPE for BB vectorization.
* tree-vect-patterns.c (vect_recog_bool_pattern): Use
vect_get_vector_types_for_stmt instead of STMT_VINFO_VECTYPE
to get an assumed vector type for data references.
* tree-vect-slp.c (vect_update_shared_vectype): New function.
(vect_update_all_shared_vectypes): Likewise.
(vect_build_slp_tree_1): Pass the group size to
vect_get_vector_types_for_stmt.  Use vect_update_shared_vectype
for BB vectorization.
(vect_build_slp_tree_2): Call vect_update_all_shared_vectypes
before building the vectof from scalars.
(vect_analyze_slp_instance): Pass the group size to
get_vectype_for_scalar_type.
(vect_slp_analyze_node_operations_1): Don't recompute the vector
types for BB vectorization here; just handle the case in which
we deferred the choice for booleans.
(vect_get_constant_vectors): Pass the slp_tree to
get_vectype_for_scalar_type.
* tree-vect-stmts.c (vect_prologue_cost_for_slp_op): Likewise.
(vectorizable_call): Likewise.
(vectorizable_simd_clone_call): Likewise.
(vectorizable_conversion): Likewise.
(vectorizable_shift): Likewise.
(vectorizable_operation): Likewise.
(vectorizable_comparison): Likewise.
(vect_is_simple_cond): Take the slp_tree as argument and
pass it to get_vectype_for_scalar_type.
(vectorizable_condition): Update call accordingly.
(get_vectype_for_scalar_type): Take a group_size argument.
For BB vectorization, limit the the vector to that number
of elements.  Also define an overload that takes an slp_tree.
(get_mask_type_for_scalar_type): Add an slp_tree argument and
pass it to get_vectype_for_scalar_type.
(vect_get_vector_types_for_stmt): Add a group_size argument
and pass it to get_vectype_for_scalar_type.  Don't use the
cached vector type for BB vectorization if a group size is given.
Handle data references in that case.
(vect_get_mask_type_for_stmt): Take an slp_tree argument and
pass it to get_mask_type_for_scalar_type.

gcc/testsuite/
* gcc.dg/vect/bb-slp-4.c: Expect the block to be vectorized
with -fno-vect-cost-model.
* gcc.dg/vect/bb-slp-bool-1.c: New test.
* gcc.target/aarch64/vect_mixed_sizes_14.c: Likewise.
* gcc.target/i386/pr84101.c: XFAIL for -m32.

From-SVN: r278334
gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/vect/bb-slp-4.c
gcc/testsuite/gcc.dg/vect/bb-slp-bool-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/vect_mixed_sizes_14.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr84101.c
gcc/tree-vect-data-refs.c
gcc/tree-vect-patterns.c
gcc/tree-vect-slp.c
gcc/tree-vect-stmts.c
gcc/tree-vectorizer.h