diff options
author | Richard Sandiford <richard.sandiford@linaro.org> | 2018-01-13 18:01:34 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2018-01-13 18:01:34 +0000 |
commit | bfaa08b7ba1b00bbcc00bb76735c6b3547f5830f (patch) | |
tree | 6fe04d13cf93a02e0cafba41edbff553c1e4de54 /gcc/tree-vect-patterns.c | |
parent | b781a135a06fc1805c072778d7513df09a32171d (diff) | |
download | gcc-bfaa08b7ba1b00bbcc00bb76735c6b3547f5830f.zip gcc-bfaa08b7ba1b00bbcc00bb76735c6b3547f5830f.tar.gz gcc-bfaa08b7ba1b00bbcc00bb76735c6b3547f5830f.tar.bz2 |
Add support for SVE gather loads
This patch adds support for SVE gather loads. It uses the basically
the same analysis code as the AVX gather support, but after that
there are two major differences:
- It uses new internal functions rather than target built-ins.
The interface is:
IFN_GATHER_LOAD (base, offsets scale)
IFN_MASK_GATHER_LOAD (base, offsets scale, mask)
which should be reasonably generic. One of the advantages of
using internal functions is that other passes can understand what
the functions do, but a more immediate advantage is that we can
query the underlying target pattern to see which scales it supports.
- It uses pattern recognition to convert the offset to the right width,
if it was originally narrower than that. This avoids having to do
a widening operation as part of the gather expansion itself.
2018-01-13 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
gcc/
* doc/md.texi (gather_load@var{m}): Document.
(mask_gather_load@var{m}): Likewise.
* genopinit.c (main): Add supports_vec_gather_load and
supports_vec_gather_load_cached to target_optabs.
* optabs-tree.c (init_tree_optimization_optabs): Use
ggc_cleared_alloc to allocate target_optabs.
* optabs.def (gather_load_optab, mask_gather_laod_optab): New optabs.
* internal-fn.def (GATHER_LOAD, MASK_GATHER_LOAD): New internal
functions.
* internal-fn.h (internal_load_fn_p): Declare.
(internal_gather_scatter_fn_p): Likewise.
(internal_fn_mask_index): Likewise.
(internal_gather_scatter_fn_supported_p): Likewise.
* internal-fn.c (gather_load_direct): New macro.
(expand_gather_load_optab_fn): New function.
(direct_gather_load_optab_supported_p): New macro.
(direct_internal_fn_optab): New function.
(internal_load_fn_p): Likewise.
(internal_gather_scatter_fn_p): Likewise.
(internal_fn_mask_index): Likewise.
(internal_gather_scatter_fn_supported_p): Likewise.
* optabs-query.c (supports_at_least_one_mode_p): New function.
(supports_vec_gather_load_p): Likewise.
* optabs-query.h (supports_vec_gather_load_p): Declare.
* tree-vectorizer.h (gather_scatter_info): Add ifn, element_type
and memory_type field.
(NUM_PATTERNS): Bump to 15.
* tree-vect-data-refs.c: Include internal-fn.h.
(vect_gather_scatter_fn_p): New function.
(vect_describe_gather_scatter_call): Likewise.
(vect_check_gather_scatter): Try using internal functions for
gather loads. Recognize existing calls to a gather load function.
(vect_analyze_data_refs): Consider using gather loads if
supports_vec_gather_load_p.
* tree-vect-patterns.c (vect_get_load_store_mask): New function.
(vect_get_gather_scatter_offset_type): Likewise.
(vect_convert_mask_for_vectype): Likewise.
(vect_add_conversion_to_patterm): Likewise.
(vect_try_gather_scatter_pattern): Likewise.
(vect_recog_gather_scatter_pattern): New pattern recognizer.
(vect_vect_recog_func_ptrs): Add it.
* tree-vect-stmts.c (exist_non_indexing_operands_for_use_p): Use
internal_fn_mask_index and internal_gather_scatter_fn_p.
(check_load_store_masking): Take the gather_scatter_info as an
argument and handle gather loads.
(vect_get_gather_scatter_ops): New function.
(vectorizable_call): Check internal_load_fn_p.
(vectorizable_load): Likewise. Handle gather load internal
functions.
(vectorizable_store): Update call to check_load_store_masking.
* config/aarch64/aarch64.md (UNSPEC_LD1_GATHER): New unspec.
* config/aarch64/iterators.md (SVE_S, SVE_D): New mode iterators.
* config/aarch64/predicates.md (aarch64_gather_scale_operand_w)
(aarch64_gather_scale_operand_d): New predicates.
* config/aarch64/aarch64-sve.md (gather_load<mode>): New expander.
(mask_gather_load<mode>): New insns.
gcc/testsuite/
* gcc.target/aarch64/sve/gather_load_1.c: New test.
* gcc.target/aarch64/sve/gather_load_2.c: Likewise.
* gcc.target/aarch64/sve/gather_load_3.c: Likewise.
* gcc.target/aarch64/sve/gather_load_4.c: Likewise.
* gcc.target/aarch64/sve/gather_load_5.c: Likewise.
* gcc.target/aarch64/sve/gather_load_6.c: Likewise.
* gcc.target/aarch64/sve/gather_load_7.c: Likewise.
* gcc.target/aarch64/sve/mask_gather_load_1.c: Likewise.
* gcc.target/aarch64/sve/mask_gather_load_2.c: Likewise.
* gcc.target/aarch64/sve/mask_gather_load_3.c: Likewise.
* gcc.target/aarch64/sve/mask_gather_load_4.c: Likewise.
* gcc.target/aarch64/sve/mask_gather_load_5.c: Likewise.
* gcc.target/aarch64/sve/mask_gather_load_6.c: Likewise.
* gcc.target/aarch64/sve/mask_gather_load_7.c: Likewise.
Co-Authored-By: Alan Hayward <alan.hayward@arm.com>
Co-Authored-By: David Sherwood <david.sherwood@arm.com>
From-SVN: r256640
Diffstat (limited to 'gcc/tree-vect-patterns.c')
-rw-r--r-- | gcc/tree-vect-patterns.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 5124c11..f4b1b3e 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -69,6 +69,8 @@ static gimple *vect_recog_mixed_size_cond_pattern (vec<gimple *> *, tree *, tree *); static gimple *vect_recog_bool_pattern (vec<gimple *> *, tree *, tree *); static gimple *vect_recog_mask_conversion_pattern (vec<gimple *> *, tree *, tree *); +static gimple *vect_recog_gather_scatter_pattern (vec<gimple *> *, tree *, + tree *); struct vect_recog_func { @@ -93,6 +95,10 @@ static vect_recog_func vect_vect_recog_func_ptrs[NUM_PATTERNS] = { { vect_recog_mult_pattern, "mult" }, { vect_recog_mixed_size_cond_pattern, "mixed_size_cond" }, { vect_recog_bool_pattern, "bool" }, + /* This must come before mask conversion, and includes the parts + of mask conversion that are needed for gather and scatter + internal functions. */ + { vect_recog_gather_scatter_pattern, "gather_scatter" }, { vect_recog_mask_conversion_pattern, "mask_conversion" } }; @@ -4117,6 +4123,203 @@ vect_recog_mask_conversion_pattern (vec<gimple *> *stmts, tree *type_in, return pattern_stmt; } +/* STMT is a load or store. If the load or store is conditional, return + the boolean condition under which it occurs, otherwise return null. */ + +static tree +vect_get_load_store_mask (gimple *stmt) +{ + if (gassign *def_assign = dyn_cast <gassign *> (stmt)) + { + gcc_assert (gimple_assign_single_p (def_assign)); + return NULL_TREE; + } + + if (gcall *def_call = dyn_cast <gcall *> (stmt)) + { + internal_fn ifn = gimple_call_internal_fn (def_call); + int mask_index = internal_fn_mask_index (ifn); + return gimple_call_arg (def_call, mask_index); + } + + gcc_unreachable (); +} + +/* Return the scalar offset type that an internal gather/scatter function + should use. GS_INFO describes the gather/scatter operation. */ + +static tree +vect_get_gather_scatter_offset_type (gather_scatter_info *gs_info) +{ + tree offset_type = TREE_TYPE (gs_info->offset); + unsigned int element_bits = tree_to_uhwi (TYPE_SIZE (gs_info->element_type)); + + /* Enforced by vect_check_gather_scatter. */ + unsigned int offset_bits = TYPE_PRECISION (offset_type); + gcc_assert (element_bits >= offset_bits); + + /* If the offset is narrower than the elements, extend it according + to its sign. */ + if (element_bits > offset_bits) + return build_nonstandard_integer_type (element_bits, + TYPE_UNSIGNED (offset_type)); + + return offset_type; +} + +/* Return MASK if MASK is suitable for masking an operation on vectors + of type VECTYPE, otherwise convert it into such a form and return + the result. Associate any conversion statements with STMT_INFO's + pattern. */ + +static tree +vect_convert_mask_for_vectype (tree mask, tree vectype, + stmt_vec_info stmt_info, vec_info *vinfo) +{ + tree mask_type = search_type_for_mask (mask, vinfo); + if (mask_type) + { + tree mask_vectype = get_mask_type_for_scalar_type (mask_type); + if (mask_vectype + && maybe_ne (TYPE_VECTOR_SUBPARTS (vectype), + TYPE_VECTOR_SUBPARTS (mask_vectype))) + mask = build_mask_conversion (mask, vectype, stmt_info, vinfo); + } + return mask; +} + +/* Return the equivalent of: + + fold_convert (TYPE, VALUE) + + with the expectation that the operation will be vectorized. + If new statements are needed, add them as pattern statements + to STMT_INFO. */ + +static tree +vect_add_conversion_to_patterm (tree type, tree value, + stmt_vec_info stmt_info, + vec_info *vinfo) +{ + if (useless_type_conversion_p (type, TREE_TYPE (value))) + return value; + + tree new_value = vect_recog_temp_ssa_var (type, NULL); + gassign *conversion = gimple_build_assign (new_value, CONVERT_EXPR, value); + stmt_vec_info new_stmt_info = new_stmt_vec_info (conversion, vinfo); + set_vinfo_for_stmt (conversion, new_stmt_info); + STMT_VINFO_VECTYPE (new_stmt_info) = get_vectype_for_scalar_type (type); + append_pattern_def_seq (stmt_info, conversion); + return new_value; +} + +/* Try to convert STMT into a call to a gather load or scatter store + internal function. Return the final statement on success and set + *TYPE_IN and *TYPE_OUT to the vector type being loaded or stored. + + This function only handles gathers and scatters that were recognized + as such from the outset (indicated by STMT_VINFO_GATHER_SCATTER_P). */ + +static gimple * +vect_try_gather_scatter_pattern (gimple *stmt, stmt_vec_info last_stmt_info, + tree *type_in, tree *type_out) +{ + /* Currently we only support this for loop vectorization. */ + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (stmt_info->vinfo); + if (!loop_vinfo) + return NULL; + + /* Make sure that we're looking at a gather load or scatter store. */ + data_reference *dr = STMT_VINFO_DATA_REF (stmt_info); + if (!dr || !STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + return NULL; + + /* Reject stores for now. */ + if (!DR_IS_READ (dr)) + return NULL; + + /* Get the boolean that controls whether the load or store happens. + This is null if the operation is unconditional. */ + tree mask = vect_get_load_store_mask (stmt); + + /* Make sure that the target supports an appropriate internal + function for the gather/scatter operation. */ + gather_scatter_info gs_info; + if (!vect_check_gather_scatter (stmt, loop_vinfo, &gs_info) + || gs_info.decl) + return NULL; + + /* Convert the mask to the right form. */ + tree gs_vectype = get_vectype_for_scalar_type (gs_info.element_type); + if (mask) + mask = vect_convert_mask_for_vectype (mask, gs_vectype, last_stmt_info, + loop_vinfo); + + /* Get the invariant base and non-invariant offset, converting the + latter to the same width as the vector elements. */ + tree base = gs_info.base; + tree offset_type = vect_get_gather_scatter_offset_type (&gs_info); + tree offset = vect_add_conversion_to_patterm (offset_type, gs_info.offset, + last_stmt_info, loop_vinfo); + + /* Build the new pattern statement. */ + tree scale = size_int (gs_info.scale); + gcall *pattern_stmt; + if (DR_IS_READ (dr)) + { + if (mask != NULL) + pattern_stmt = gimple_build_call_internal (gs_info.ifn, 4, base, + offset, scale, mask); + else + pattern_stmt = gimple_build_call_internal (gs_info.ifn, 3, base, + offset, scale); + tree load_lhs = vect_recog_temp_ssa_var (gs_info.element_type, NULL); + gimple_call_set_lhs (pattern_stmt, load_lhs); + } + else + /* Not yet supported. */ + gcc_unreachable (); + gimple_call_set_nothrow (pattern_stmt, true); + + /* Copy across relevant vectorization info and associate DR with the + new pattern statement instead of the original statement. */ + stmt_vec_info pattern_stmt_info = new_stmt_vec_info (pattern_stmt, + loop_vinfo); + set_vinfo_for_stmt (pattern_stmt, pattern_stmt_info); + STMT_VINFO_DATA_REF (pattern_stmt_info) = dr; + STMT_VINFO_DR_WRT_VEC_LOOP (pattern_stmt_info) + = STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info); + STMT_VINFO_GATHER_SCATTER_P (pattern_stmt_info) + = STMT_VINFO_GATHER_SCATTER_P (stmt_info); + DR_STMT (dr) = pattern_stmt; + + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + *type_out = vectype; + *type_in = vectype; + + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "gather/scatter pattern detected:\n"); + + return pattern_stmt; +} + +/* Pattern wrapper around vect_try_gather_scatter_pattern. */ + +static gimple * +vect_recog_gather_scatter_pattern (vec<gimple *> *stmts, tree *type_in, + tree *type_out) +{ + gimple *last_stmt = stmts->pop (); + stmt_vec_info last_stmt_info = vinfo_for_stmt (last_stmt); + gimple *pattern_stmt = vect_try_gather_scatter_pattern (last_stmt, + last_stmt_info, + type_in, type_out); + if (pattern_stmt) + stmts->safe_push (last_stmt); + return pattern_stmt; +} /* Mark statements that are involved in a pattern. */ |