return false;
}
+/* Return FN if vec_{mask_,mask_len_}store_lanes is available for COUNT vectors
+ of type VECTYPE. MASKED_P says whether the masked form is needed. */
-/* Return TRUE if vec_{mask_}store_lanes is available for COUNT vectors of
- type VECTYPE. MASKED_P says whether the masked form is needed. */
-
-bool
+internal_fn
vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
bool masked_p)
{
- if (masked_p)
- return vect_lanes_optab_supported_p ("vec_mask_store_lanes",
- vec_mask_store_lanes_optab,
- vectype, count);
+ if (vect_lanes_optab_supported_p ("vec_mask_len_store_lanes",
+ vec_mask_len_store_lanes_optab, vectype,
+ count))
+ return IFN_MASK_LEN_STORE_LANES;
+ else if (masked_p)
+ {
+ if (vect_lanes_optab_supported_p ("vec_mask_store_lanes",
+ vec_mask_store_lanes_optab, vectype,
+ count))
+ return IFN_MASK_STORE_LANES;
+ }
else
- return vect_lanes_optab_supported_p ("vec_store_lanes",
- vec_store_lanes_optab,
- vectype, count);
+ {
+ if (vect_lanes_optab_supported_p ("vec_store_lanes",
+ vec_store_lanes_optab, vectype, count))
+ return IFN_STORE_LANES;
+ }
+ return IFN_LAST;
}
return false;
}
-/* Return TRUE if vec_{masked_}load_lanes is available for COUNT vectors of
- type VECTYPE. MASKED_P says whether the masked form is needed. */
+/* Return FN if vec_{masked_,mask_len_}load_lanes is available for COUNT vectors
+ of type VECTYPE. MASKED_P says whether the masked form is needed. */
-bool
+internal_fn
vect_load_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
bool masked_p)
{
- if (masked_p)
- return vect_lanes_optab_supported_p ("vec_mask_load_lanes",
- vec_mask_load_lanes_optab,
- vectype, count);
+ if (vect_lanes_optab_supported_p ("vec_mask_len_load_lanes",
+ vec_mask_len_load_lanes_optab, vectype,
+ count))
+ return IFN_MASK_LEN_LOAD_LANES;
+ else if (masked_p)
+ {
+ if (vect_lanes_optab_supported_p ("vec_mask_load_lanes",
+ vec_mask_load_lanes_optab, vectype,
+ count))
+ return IFN_MASK_LOAD_LANES;
+ }
else
- return vect_lanes_optab_supported_p ("vec_load_lanes",
- vec_load_lanes_optab,
- vectype, count);
+ {
+ if (vect_lanes_optab_supported_p ("vec_load_lanes", vec_load_lanes_optab,
+ vectype, count))
+ return IFN_LOAD_LANES;
+ }
+ return IFN_LAST;
}
/* Function vect_permute_load_chain.
instructions record it and move on to the next instance. */
if (loads_permuted
&& SLP_INSTANCE_KIND (instance) == slp_inst_kind_store
- && vect_store_lanes_supported (vectype, group_size, false))
+ && vect_store_lanes_supported (vectype, group_size, false)
+ != IFN_LAST)
{
FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (instance), i, load_node)
{
/* Use SLP for strided accesses (or if we can't
load-lanes). */
if (STMT_VINFO_STRIDED_P (stmt_vinfo)
- || ! vect_load_lanes_supported
+ || vect_load_lanes_supported
(STMT_VINFO_VECTYPE (stmt_vinfo),
- DR_GROUP_SIZE (stmt_vinfo), false))
+ DR_GROUP_SIZE (stmt_vinfo), false) == IFN_LAST)
break;
}
vinfo = DR_GROUP_FIRST_ELEMENT (vinfo);
unsigned int size = DR_GROUP_SIZE (vinfo);
tree vectype = STMT_VINFO_VECTYPE (vinfo);
- if (! vect_store_lanes_supported (vectype, size, false)
+ if (vect_store_lanes_supported (vectype, size, false) == IFN_LAST
&& ! known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U)
&& ! vect_grouped_store_supported (vectype, size))
return opt_result::failure_at (vinfo->stmt,
bool single_element_p = !DR_GROUP_NEXT_ELEMENT (vinfo);
size = DR_GROUP_SIZE (vinfo);
vectype = STMT_VINFO_VECTYPE (vinfo);
- if (! vect_load_lanes_supported (vectype, size, false)
+ if (vect_load_lanes_supported (vectype, size, false) == IFN_LAST
&& ! vect_grouped_load_supported (vectype, single_element_p,
size))
return opt_result::failure_at (vinfo->stmt,
bool is_load = (vls_type == VLS_LOAD);
if (memory_access_type == VMAT_LOAD_STORE_LANES)
{
- if (is_load
- ? !vect_load_lanes_supported (vectype, group_size, true)
- : !vect_store_lanes_supported (vectype, group_size, true))
+ internal_fn ifn
+ = (is_load ? vect_load_lanes_supported (vectype, group_size, true)
+ : vect_store_lanes_supported (vectype, group_size, true));
+ if (ifn == IFN_MASK_LEN_LOAD_LANES || ifn == IFN_MASK_LEN_STORE_LANES)
+ vect_record_loop_len (loop_vinfo, lens, nvectors, vectype, 1);
+ else if (ifn == IFN_MASK_LOAD_LANES || ifn == IFN_MASK_STORE_LANES)
+ vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
+ scalar_mask);
+ else
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
" the target doesn't have an appropriate"
" load/store-lanes instruction.\n");
LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
- return;
}
- vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype,
- scalar_mask);
return;
}
poly_int64 *poffset,
dr_alignment_support *alignment_support_scheme,
int *misalignment,
- gather_scatter_info *gs_info)
+ gather_scatter_info *gs_info,
+ internal_fn *lanes_ifn)
{
loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
class loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
if (known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U))
;
- /* Otherwise try using LOAD/STORE_LANES. */
- else if (vls_type == VLS_LOAD
- ? vect_load_lanes_supported (vectype, group_size, masked_p)
- : vect_store_lanes_supported (vectype, group_size,
- masked_p))
+ else
{
- *memory_access_type = VMAT_LOAD_STORE_LANES;
- overrun_p = would_overrun_p;
- }
+ /* Otherwise try using LOAD/STORE_LANES. */
+ *lanes_ifn
+ = vls_type == VLS_LOAD
+ ? vect_load_lanes_supported (vectype, group_size, masked_p)
+ : vect_store_lanes_supported (vectype, group_size,
+ masked_p);
+ if (*lanes_ifn != IFN_LAST)
+ {
+ *memory_access_type = VMAT_LOAD_STORE_LANES;
+ overrun_p = would_overrun_p;
+ }
- /* If that fails, try using permuting loads. */
- else if (vls_type == VLS_LOAD
- ? vect_grouped_load_supported (vectype, single_element_p,
- group_size)
- : vect_grouped_store_supported (vectype, group_size))
- {
- *memory_access_type = VMAT_CONTIGUOUS_PERMUTE;
- overrun_p = would_overrun_p;
+ /* If that fails, try using permuting loads. */
+ else if (vls_type == VLS_LOAD
+ ? vect_grouped_load_supported (vectype,
+ single_element_p,
+ group_size)
+ : vect_grouped_store_supported (vectype, group_size))
+ {
+ *memory_access_type = VMAT_CONTIGUOUS_PERMUTE;
+ overrun_p = would_overrun_p;
+ }
}
}
poly_int64 *poffset,
dr_alignment_support *alignment_support_scheme,
int *misalignment,
- gather_scatter_info *gs_info)
+ gather_scatter_info *gs_info,
+ internal_fn *lanes_ifn)
{
loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
masked_p,
vls_type, memory_access_type, poffset,
alignment_support_scheme,
- misalignment, gs_info))
+ misalignment, gs_info, lanes_ifn))
return false;
}
else if (STMT_VINFO_STRIDED_P (stmt_info))
loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (vinfo);
tree step = vect_dr_behavior (vinfo, dr_info)->step;
- /* TODO: We don't support gather/scatter or load_lanes/store_lanes for pointer
- IVs are updated by variable amount but we will support them in the future.
- */
- gcc_assert (memory_access_type != VMAT_GATHER_SCATTER
- && memory_access_type != VMAT_LOAD_STORE_LANES);
+ /* gather/scatter never reach here. */
+ gcc_assert (memory_access_type != VMAT_GATHER_SCATTER);
/* When we support SELECT_VL pattern, we dynamic adjust
the memory address by .SELECT_VL result.
enum dr_alignment_support alignment_support_scheme;
int misalignment;
poly_int64 poffset;
+ internal_fn lanes_ifn;
if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, vls_type,
ncopies, &memory_access_type, &poffset,
- &alignment_support_scheme, &misalignment, &gs_info))
+ &alignment_support_scheme, &misalignment, &gs_info,
+ &lanes_ifn))
return false;
if (mask)
}
tree final_mask = NULL;
+ tree final_len = NULL;
+ tree bias = NULL;
if (loop_masks)
final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
ncopies, vectype, j);
final_mask = prepare_vec_mask (loop_vinfo, mask_vectype,
final_mask, vec_mask, gsi);
+ if (lanes_ifn == IFN_MASK_LEN_STORE_LANES)
+ {
+ if (loop_lens)
+ final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
+ ncopies, vectype, j, 1);
+ else
+ final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
+ signed char biasval
+ = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
+ bias = build_int_cst (intQI_type_node, biasval);
+ if (!final_mask)
+ {
+ mask_vectype = truth_type_for (vectype);
+ final_mask = build_minus_one_cst (mask_vectype);
+ }
+ }
+
gcall *call;
- if (final_mask)
+ if (final_len && final_mask)
+ {
+ /* Emit:
+ MASK_LEN_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
+ LEN, BIAS, VEC_ARRAY). */
+ unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
+ tree alias_ptr = build_int_cst (ref_type, align);
+ call = gimple_build_call_internal (IFN_MASK_LEN_STORE_LANES, 6,
+ dataref_ptr, alias_ptr,
+ final_mask, final_len, bias,
+ vec_array);
+ }
+ else if (final_mask)
{
/* Emit:
MASK_STORE_LANES (DATAREF_PTR, ALIAS_PTR, VEC_MASK,
enum dr_alignment_support alignment_support_scheme;
int misalignment;
poly_int64 poffset;
+ internal_fn lanes_ifn;
if (!get_load_store_type (vinfo, stmt_info, vectype, slp_node, mask, VLS_LOAD,
ncopies, &memory_access_type, &poffset,
- &alignment_support_scheme, &misalignment, &gs_info))
+ &alignment_support_scheme, &misalignment, &gs_info,
+ &lanes_ifn))
return false;
if (mask)
tree vec_array = create_vector_array (vectype, vec_num);
tree final_mask = NULL_TREE;
+ tree final_len = NULL_TREE;
+ tree bias = NULL_TREE;
if (loop_masks)
final_mask = vect_get_loop_mask (loop_vinfo, gsi, loop_masks,
ncopies, vectype, j);
final_mask = prepare_vec_mask (loop_vinfo, mask_vectype, final_mask,
vec_mask, gsi);
+ if (lanes_ifn == IFN_MASK_LEN_LOAD_LANES)
+ {
+ if (loop_lens)
+ final_len = vect_get_loop_len (loop_vinfo, gsi, loop_lens,
+ ncopies, vectype, j, 1);
+ else
+ final_len = size_int (TYPE_VECTOR_SUBPARTS (vectype));
+ signed char biasval
+ = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
+ bias = build_int_cst (intQI_type_node, biasval);
+ if (!final_mask)
+ {
+ mask_vectype = truth_type_for (vectype);
+ final_mask = build_minus_one_cst (mask_vectype);
+ }
+ }
+
gcall *call;
- if (final_mask)
+ if (final_len && final_mask)
+ {
+ /* Emit:
+ VEC_ARRAY = MASK_LEN_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,
+ VEC_MASK, LEN, BIAS). */
+ unsigned int align = TYPE_ALIGN (TREE_TYPE (vectype));
+ tree alias_ptr = build_int_cst (ref_type, align);
+ call = gimple_build_call_internal (IFN_MASK_LEN_LOAD_LANES, 5,
+ dataref_ptr, alias_ptr,
+ final_mask, final_len, bias);
+ }
+ else if (final_mask)
{
/* Emit:
VEC_ARRAY = MASK_LOAD_LANES (DATAREF_PTR, ALIAS_PTR,