Use VEC_PERM_EXPR in the vectorizer.
* tree-vect-slp.c: Include langhooks.h. (vect_create_mask_and_perm): Emit VEC_PERM_EXPR, not a builtin. (vect_transform_slp_perm_load): Use can_vec_perm_expr_p. Simplify mask creation for VEC_PERM_EXPR. * tree-vect-stmts.c (perm_mask_for_reverse): Return the mask, not the builtin. (reverse_vec_elements): Emit VEC_PERM_EXPR not a builtin. * Makefile.in (tree-vect-slp.o): Update dependency. * optabs.c (can_vec_perm_expr_p): Allow NULL as unknown constant. From-SVN: r180047
This commit is contained in:
parent
f3b3dc6a7e
commit
2635892a1c
|
@ -1,3 +1,15 @@
|
|||
2011-10-15 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* tree-vect-slp.c: Include langhooks.h.
|
||||
(vect_create_mask_and_perm): Emit VEC_PERM_EXPR, not a builtin.
|
||||
(vect_transform_slp_perm_load): Use can_vec_perm_expr_p. Simplify
|
||||
mask creation for VEC_PERM_EXPR.
|
||||
* tree-vect-stmts.c (perm_mask_for_reverse): Return the mask,
|
||||
not the builtin.
|
||||
(reverse_vec_elements): Emit VEC_PERM_EXPR not a builtin.
|
||||
* Makefile.in (tree-vect-slp.o): Update dependency.
|
||||
* optabs.c (can_vec_perm_expr_p): Allow NULL as unknown constant.
|
||||
|
||||
2011-10-15 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR bootstrap/50738
|
||||
|
|
|
@ -2753,7 +2753,7 @@ tree-vect-slp.o: tree-vect-slp.c $(CONFIG_H) $(SYSTEM_H) \
|
|||
coretypes.h $(TM_H) $(GGC_H) $(TREE_H) $(TARGET_H) $(BASIC_BLOCK_H) \
|
||||
$(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(CFGLOOP_H) $(CFGLAYOUT_H) \
|
||||
$(EXPR_H) $(RECOG_H) $(OPTABS_H) $(TREE_VECTORIZER_H) tree-pretty-print.h \
|
||||
gimple-pretty-print.h $(TREE_DATA_REF_H)
|
||||
gimple-pretty-print.h $(TREE_DATA_REF_H) langhooks.h
|
||||
tree-vect-stmts.o: tree-vect-stmts.c $(CONFIG_H) $(SYSTEM_H) \
|
||||
coretypes.h $(TM_H) $(GGC_H) $(TREE_H) $(TARGET_H) $(BASIC_BLOCK_H) \
|
||||
$(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(CFGLOOP_H) $(CFGLAYOUT_H) \
|
||||
|
|
|
@ -6686,7 +6686,7 @@ vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
|
|||
}
|
||||
|
||||
/* Return true if VEC_PERM_EXPR can be expanded using SIMD extensions
|
||||
of the CPU. */
|
||||
of the CPU. SEL may be NULL, which stands for an unknown constant. */
|
||||
|
||||
bool
|
||||
can_vec_perm_expr_p (tree type, tree sel)
|
||||
|
@ -6699,10 +6699,10 @@ can_vec_perm_expr_p (tree type, tree sel)
|
|||
if (!VECTOR_MODE_P (mode))
|
||||
return false;
|
||||
|
||||
if (TREE_CODE (sel) == VECTOR_CST)
|
||||
if (sel == NULL || TREE_CODE (sel) == VECTOR_CST)
|
||||
{
|
||||
if (direct_optab_handler (vec_perm_const_optab, mode) != CODE_FOR_nothing
|
||||
&& targetm.vectorize.builtin_vec_perm_ok (type, sel))
|
||||
&& (sel == NULL || targetm.vectorize.builtin_vec_perm_ok (type, sel)))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6722,7 +6722,7 @@ can_vec_perm_expr_p (tree type, tree sel)
|
|||
|
||||
/* In order to support the lowering of non-constant permutations,
|
||||
we need to support shifts and adds. */
|
||||
if (TREE_CODE (sel) != VECTOR_CST)
|
||||
if (sel != NULL && TREE_CODE (sel) != VECTOR_CST)
|
||||
{
|
||||
if (GET_MODE_UNIT_SIZE (mode) > 2
|
||||
&& optab_handler (ashl_optab, mode) == CODE_FOR_nothing
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* SLP - Basic Block Vectorization
|
||||
Copyright (C) 2007, 2008, 2009, 2010
|
||||
Copyright (C) 2007, 2008, 2009, 2010, 2011
|
||||
Free Software Foundation, Inc.
|
||||
Contributed by Dorit Naishlos <dorit@il.ibm.com>
|
||||
and Ira Rosen <irar@il.ibm.com>
|
||||
|
@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "recog.h"
|
||||
#include "optabs.h"
|
||||
#include "tree-vectorizer.h"
|
||||
#include "langhooks.h"
|
||||
|
||||
/* Extract the location of the basic block in the source code.
|
||||
Return the basic block location if succeed and NULL if not. */
|
||||
|
@ -2226,8 +2227,7 @@ static inline void
|
|||
vect_create_mask_and_perm (gimple stmt, gimple next_scalar_stmt,
|
||||
tree mask, int first_vec_indx, int second_vec_indx,
|
||||
gimple_stmt_iterator *gsi, slp_tree node,
|
||||
tree builtin_decl, tree vectype,
|
||||
VEC(tree,heap) *dr_chain,
|
||||
tree vectype, VEC(tree,heap) *dr_chain,
|
||||
int ncopies, int vect_stmts_counter)
|
||||
{
|
||||
tree perm_dest;
|
||||
|
@ -2251,10 +2251,10 @@ vect_create_mask_and_perm (gimple stmt, gimple next_scalar_stmt,
|
|||
second_vec = VEC_index (tree, dr_chain, second_vec_indx);
|
||||
|
||||
/* Generate the permute statement. */
|
||||
perm_stmt = gimple_build_call (builtin_decl,
|
||||
3, first_vec, second_vec, mask);
|
||||
perm_stmt = gimple_build_assign_with_ops3 (VEC_PERM_EXPR, perm_dest,
|
||||
first_vec, second_vec, mask);
|
||||
data_ref = make_ssa_name (perm_dest, perm_stmt);
|
||||
gimple_call_set_lhs (perm_stmt, data_ref);
|
||||
gimple_set_lhs (perm_stmt, data_ref);
|
||||
vect_finish_stmt_generation (stmt, perm_stmt, gsi);
|
||||
|
||||
/* Store the vector statement in NODE. */
|
||||
|
@ -2361,9 +2361,9 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
|
|||
{
|
||||
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
|
||||
tree mask_element_type = NULL_TREE, mask_type;
|
||||
int i, j, k, m, scale, mask_nunits, nunits, vec_index = 0, scalar_index;
|
||||
int i, j, k, nunits, vec_index = 0, scalar_index;
|
||||
slp_tree node;
|
||||
tree vectype = STMT_VINFO_VECTYPE (stmt_info), builtin_decl;
|
||||
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
|
||||
gimple next_scalar_stmt;
|
||||
int group_size = SLP_INSTANCE_GROUP_SIZE (slp_node_instance);
|
||||
int first_mask_element;
|
||||
|
@ -2374,35 +2374,24 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
|
|||
bool mask_fixed = false;
|
||||
bool needs_first_vector = false;
|
||||
|
||||
if (!targetm.vectorize.builtin_vec_perm)
|
||||
if (!can_vec_perm_expr_p (vectype, NULL_TREE))
|
||||
{
|
||||
if (vect_print_dump_info (REPORT_DETAILS))
|
||||
{
|
||||
fprintf (vect_dump, "no builtin for vect permute for ");
|
||||
fprintf (vect_dump, "no vect permute for ");
|
||||
print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
builtin_decl = targetm.vectorize.builtin_vec_perm (vectype,
|
||||
&mask_element_type);
|
||||
if (!builtin_decl || !mask_element_type)
|
||||
{
|
||||
if (vect_print_dump_info (REPORT_DETAILS))
|
||||
{
|
||||
fprintf (vect_dump, "no builtin for vect permute for ");
|
||||
print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM);
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The generic VEC_PERM_EXPR code always uses an integral type of the
|
||||
same size as the vector element being permuted. */
|
||||
mask_element_type
|
||||
= lang_hooks.types.type_for_size
|
||||
(TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (vectype))), 1);
|
||||
mask_type = get_vectype_for_scalar_type (mask_element_type);
|
||||
mask_nunits = TYPE_VECTOR_SUBPARTS (mask_type);
|
||||
mask = (int *) xmalloc (sizeof (int) * mask_nunits);
|
||||
nunits = TYPE_VECTOR_SUBPARTS (vectype);
|
||||
scale = mask_nunits / nunits;
|
||||
mask = (int *) xmalloc (sizeof (int) * nunits);
|
||||
unroll_factor = SLP_INSTANCE_UNROLLING_FACTOR (slp_node_instance);
|
||||
|
||||
/* The number of vector stmts to generate based only on SLP_NODE_INSTANCE
|
||||
|
@ -2425,8 +2414,7 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
|
|||
for b's: b0b0b0b1 b1b1b2b2 b2b3b3b3
|
||||
...
|
||||
|
||||
The masks for a's should be: {0,0,0,3} {3,3,6,6} {6,9,9,9} (in target
|
||||
scpecific type, e.g., in bytes for Altivec.
|
||||
The masks for a's should be: {0,0,0,3} {3,3,6,6} {6,9,9,9}.
|
||||
The last mask is illegal since we assume two operands for permute
|
||||
operation, and the mask element values can't be outside that range.
|
||||
Hence, the last mask must be converted into {2,5,5,5}.
|
||||
|
@ -2451,20 +2439,17 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
|
|||
{
|
||||
for (k = 0; k < group_size; k++)
|
||||
{
|
||||
first_mask_element = (i + j * group_size) * scale;
|
||||
for (m = 0; m < scale; m++)
|
||||
{
|
||||
if (!vect_get_mask_element (stmt, first_mask_element, m,
|
||||
mask_nunits, only_one_vec, index, mask,
|
||||
¤t_mask_element, &need_next_vector,
|
||||
&number_of_mask_fixes, &mask_fixed,
|
||||
&needs_first_vector))
|
||||
return false;
|
||||
first_mask_element = i + j * group_size;
|
||||
if (!vect_get_mask_element (stmt, first_mask_element, 0,
|
||||
nunits, only_one_vec, index,
|
||||
mask, ¤t_mask_element,
|
||||
&need_next_vector,
|
||||
&number_of_mask_fixes, &mask_fixed,
|
||||
&needs_first_vector))
|
||||
return false;
|
||||
mask[index++] = current_mask_element;
|
||||
|
||||
mask[index++] = current_mask_element;
|
||||
}
|
||||
|
||||
if (index == mask_nunits)
|
||||
if (index == nunits)
|
||||
{
|
||||
tree mask_vec = NULL;
|
||||
|
||||
|
@ -2476,8 +2461,7 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
|
|||
mask_vec = build_vector (mask_type, mask_vec);
|
||||
index = 0;
|
||||
|
||||
if (!targetm.vectorize.builtin_vec_perm_ok (vectype,
|
||||
mask_vec))
|
||||
if (!can_vec_perm_expr_p (vectype, mask_vec))
|
||||
{
|
||||
if (vect_print_dump_info (REPORT_DETAILS))
|
||||
{
|
||||
|
@ -2501,7 +2485,7 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
|
|||
|
||||
vect_create_mask_and_perm (stmt, next_scalar_stmt,
|
||||
mask_vec, first_vec_index, second_vec_index,
|
||||
gsi, node, builtin_decl, vectype, dr_chain,
|
||||
gsi, node, vectype, dr_chain,
|
||||
ncopies, vect_stmts_counter++);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3996,41 +3996,33 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt,
|
|||
}
|
||||
|
||||
/* Given a vector type VECTYPE returns a builtin DECL to be used
|
||||
for vector permutation and stores a mask into *MASK that implements
|
||||
reversal of the vector elements. If that is impossible to do
|
||||
returns NULL (and *MASK is unchanged). */
|
||||
for vector permutation and returns the mask that implements
|
||||
reversal of the vector elements. If that is impossible to do,
|
||||
returns NULL. */
|
||||
|
||||
static tree
|
||||
perm_mask_for_reverse (tree vectype, tree *mask)
|
||||
perm_mask_for_reverse (tree vectype)
|
||||
{
|
||||
tree builtin_decl;
|
||||
tree mask_element_type, mask_type;
|
||||
tree mask_vec = NULL;
|
||||
int i;
|
||||
int nunits;
|
||||
if (!targetm.vectorize.builtin_vec_perm)
|
||||
return NULL;
|
||||
|
||||
builtin_decl = targetm.vectorize.builtin_vec_perm (vectype,
|
||||
&mask_element_type);
|
||||
if (!builtin_decl || !mask_element_type)
|
||||
tree mask_element_type, mask_type, mask_vec = NULL;
|
||||
int i, nunits;
|
||||
|
||||
if (!can_vec_perm_expr_p (vectype, NULL_TREE))
|
||||
return NULL;
|
||||
|
||||
mask_element_type
|
||||
= lang_hooks.types.type_for_size
|
||||
(TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (vectype))), 1);
|
||||
mask_type = get_vectype_for_scalar_type (mask_element_type);
|
||||
nunits = TYPE_VECTOR_SUBPARTS (vectype);
|
||||
if (!mask_type
|
||||
|| TYPE_VECTOR_SUBPARTS (vectype) != TYPE_VECTOR_SUBPARTS (mask_type))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < nunits; i++)
|
||||
mask_vec = tree_cons (NULL, build_int_cst (mask_element_type, i), mask_vec);
|
||||
mask_vec = build_vector (mask_type, mask_vec);
|
||||
|
||||
if (!targetm.vectorize.builtin_vec_perm_ok (vectype, mask_vec))
|
||||
if (!can_vec_perm_expr_p (vectype, mask_vec))
|
||||
return NULL;
|
||||
if (mask)
|
||||
*mask = mask_vec;
|
||||
return builtin_decl;
|
||||
|
||||
return mask_vec;
|
||||
}
|
||||
|
||||
/* Given a vector variable X, that was generated for the scalar LHS of
|
||||
|
@ -4041,27 +4033,16 @@ static tree
|
|||
reverse_vec_elements (tree x, gimple stmt, gimple_stmt_iterator *gsi)
|
||||
{
|
||||
tree vectype = TREE_TYPE (x);
|
||||
tree mask_vec, builtin_decl;
|
||||
tree perm_dest, data_ref;
|
||||
tree mask_vec, perm_dest, data_ref;
|
||||
gimple perm_stmt;
|
||||
|
||||
builtin_decl = perm_mask_for_reverse (vectype, &mask_vec);
|
||||
mask_vec = perm_mask_for_reverse (vectype);
|
||||
|
||||
perm_dest = vect_create_destination_var (gimple_assign_lhs (stmt), vectype);
|
||||
|
||||
/* Generate the permute statement. */
|
||||
perm_stmt = gimple_build_call (builtin_decl, 3, x, x, mask_vec);
|
||||
if (!useless_type_conversion_p (vectype,
|
||||
TREE_TYPE (TREE_TYPE (builtin_decl))))
|
||||
{
|
||||
tree tem = create_tmp_reg (TREE_TYPE (TREE_TYPE (builtin_decl)), NULL);
|
||||
tem = make_ssa_name (tem, perm_stmt);
|
||||
gimple_call_set_lhs (perm_stmt, tem);
|
||||
vect_finish_stmt_generation (stmt, perm_stmt, gsi);
|
||||
perm_stmt = gimple_build_assign (NULL_TREE,
|
||||
build1 (VIEW_CONVERT_EXPR,
|
||||
vectype, tem));
|
||||
}
|
||||
perm_stmt = gimple_build_assign_with_ops3 (VEC_PERM_EXPR, perm_dest,
|
||||
x, x, mask_vec);
|
||||
data_ref = make_ssa_name (perm_dest, perm_stmt);
|
||||
gimple_set_lhs (perm_stmt, data_ref);
|
||||
vect_finish_stmt_generation (stmt, perm_stmt, gsi);
|
||||
|
@ -4237,7 +4218,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt,
|
|||
fprintf (vect_dump, "negative step but alignment required.");
|
||||
return false;
|
||||
}
|
||||
if (!perm_mask_for_reverse (vectype, NULL))
|
||||
if (!perm_mask_for_reverse (vectype))
|
||||
{
|
||||
if (vect_print_dump_info (REPORT_DETAILS))
|
||||
fprintf (vect_dump, "negative step and reversing not supported.");
|
||||
|
|
Loading…
Reference in New Issue