Commit bdc3ee5d by Richard Henderson Committed by Richard Henderson

Move lowering of vector shifts from v/s to v/v from gimple to rtl.

This allows other rtl expanders to rely on shifts of vector by scalar.

From-SVN: r179956
parent 0772d476
......@@ -9,6 +9,12 @@
* config/i386/sse.md (VEC_PERM_CONST): New mode iterator.
(vec_perm_const<VEC_PERM_CONST>): New expander.
* optabs.c (expand_vector_broadcast): New.
(expand_binop): Expand scalar shifts of vectors to vector shifts
of vectors, if the former isn't supported.
* tree-vect-generic.c (expand_vector_operations_1): Don't do that
here; always simplify to scalar shift of vector if possible.
2011-10-13 Jakub Jelinek <jakub@redhat.com>
* config/i386/sse.md (vec_set<mode>): Change V_128 iterator mode
......@@ -735,6 +735,41 @@ expand_vec_shift_expr (sepops ops, rtx target)
return eops[0].value;
}
/* Create a new vector value in VMODE with all elements set to OP. The
mode of OP must be the element mode of VMODE. If OP is a constant,
then the return value will be a constant. */
static rtx
expand_vector_broadcast (enum machine_mode vmode, rtx op)
{
enum insn_code icode;
rtvec vec;
rtx ret;
int i, n;
gcc_checking_assert (VECTOR_MODE_P (vmode));
n = GET_MODE_NUNITS (vmode);
vec = rtvec_alloc (n);
for (i = 0; i < n; ++i)
RTVEC_ELT (vec, i) = op;
if (CONSTANT_P (op))
return gen_rtx_CONST_VECTOR (vmode, vec);
/* ??? If the target doesn't have a vec_init, then we have no easy way
of performing this operation. Most of this sort of generic support
is hidden away in the vector lowering support in gimple. */
icode = optab_handler (vec_init_optab, vmode);
if (icode == CODE_FOR_nothing)
return NULL;
ret = gen_reg_rtx (vmode);
emit_insn (GEN_FCN (icode) (ret, gen_rtx_PARALLEL (vmode, vec)));
return ret;
}
/* This subroutine of expand_doubleword_shift handles the cases in which
the effective shift value is >= BITS_PER_WORD. The arguments and return
value are the same as for the parent routine, except that SUPERWORD_OP1
......@@ -1533,6 +1568,36 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
}
}
/* If this is a vector shift by a scalar, see if we can do a vector
shift by a vector. If so, broadcast the scalar into a vector. */
if (mclass == MODE_VECTOR_INT)
{
optab otheroptab = NULL;
if (binoptab == ashl_optab)
otheroptab = vashl_optab;
else if (binoptab == ashr_optab)
otheroptab = vashr_optab;
else if (binoptab == lshr_optab)
otheroptab = vlshr_optab;
else if (binoptab == rotl_optab)
otheroptab = vrotl_optab;
else if (binoptab == rotr_optab)
otheroptab = vrotr_optab;
if (otheroptab && optab_handler (otheroptab, mode) != CODE_FOR_nothing)
{
rtx vop1 = expand_vector_broadcast (mode, op1);
if (vop1)
{
temp = expand_binop_directly (mode, otheroptab, op0, vop1,
target, unsignedp, methods, last);
if (temp)
return temp;
}
}
}
/* Look for a wider mode of the same class for which we think we
can open-code the operation. Check for a widening multiply at the
wider mode as well. */
......
2011-10-13 Richard Henderson <rth@redhat.com>
* lib/target-supports.exp (check_effective_target_vect_shift_scalar):
Delete.
* gcc.dg/vect/vec-scal-opt.c: Don't test vect_shift_scalar.
* gcc.dg/vect/vec-scal-opt1.c: Likewise.
* gcc.dg/vect/vec-scal-opt2.c: Likewise.
2011-10-13 Jason Merrill <jason@redhat.com>
PR c++/50614
......
......@@ -19,5 +19,5 @@ int main (int argc, char *argv[]) {
return vidx(short, r1, 0);
}
/* { dg-final { scan-tree-dump-times ">> k.\[0-9_\]*" 1 "veclower2" { target vect_shift_scalar } } } */
/* { dg-final { scan-tree-dump-times ">> k.\[0-9_\]*" 1 "veclower2" } } */
/* { dg-final { cleanup-tree-dump "veclower2" } } */
......@@ -17,5 +17,5 @@ int main (int argc, char *argv[]) {
return vidx(short, r1, 0);
}
/* { dg-final { scan-tree-dump-times ">> 2" 1 "veclower2" { target vect_shift_scalar } } } */
/* { dg-final { scan-tree-dump-times ">> 2" 1 "veclower2" } } */
/* { dg-final { cleanup-tree-dump "veclower2" } } */
......@@ -16,5 +16,5 @@ int main (int argc, char *argv[]) {
return vidx(short, r1, 0);
}
/* { dg-final { scan-tree-dump-times ">> 2" 1 "veclower2" { target vect_shift_scalar } } } */
/* { dg-final { scan-tree-dump-times ">> 2" 1 "veclower2" } } */
/* { dg-final { cleanup-tree-dump "veclower2" } } */
......@@ -2421,27 +2421,6 @@ proc check_effective_target_vect_shift { } {
return $et_vect_shift_saved
}
# Return 1 if the target supports hardware vector shift operation with
# scalar shift argument.
proc check_effective_target_vect_shift_scalar { } {
global et_vect_shift_scalar_saved
if [info exists et_vect_shift_scalar_saved] {
verbose "check_effective_target_vect_shift_scalar: using cached result" 2
} else {
set et_vect_shift_scalar_saved 0
if { [istarget x86_64-*-*]
|| [istarget i?86-*-*] } {
set et_vect_shift_scalar_saved 1
}
}
verbose "check_effective_target_vect_shift_scalar: returning $et_vect_shift_scalar_saved" 2
return $et_vect_shift_scalar_saved
}
# Return 1 if the target supports hardware vector shift operation for char.
proc check_effective_target_vect_shift_char { } {
......
......@@ -775,60 +775,39 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
|| code == LROTATE_EXPR
|| code == RROTATE_EXPR)
{
bool vector_scalar_shift;
op = optab_for_tree_code (code, type, optab_scalar);
/* Vector/Scalar shift is supported. */
vector_scalar_shift = (op && (optab_handler (op, TYPE_MODE (type))
!= CODE_FOR_nothing));
/* If the 2nd argument is vector, we need a vector/vector shift.
Except all the elements in the second vector are the same. */
/* Check whether we have vector <op> {x,x,x,x} where x
could be a scalar variable or a constant. Transform
vector <op> {x,x,x,x} ==> vector <op> scalar. */
if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (rhs2))))
{
tree first;
gimple def_stmt;
/* Check whether we have vector <op> {x,x,x,x} where x
could be a scalar variable or a constant. Transform
vector <op> {x,x,x,x} ==> vector <op> scalar. */
if (vector_scalar_shift
&& ((TREE_CODE (rhs2) == VECTOR_CST
&& (first = uniform_vector_p (rhs2)) != NULL_TREE)
|| (TREE_CODE (rhs2) == SSA_NAME
&& (def_stmt = SSA_NAME_DEF_STMT (rhs2))
&& gimple_assign_single_p (def_stmt)
&& (first = uniform_vector_p
(gimple_assign_rhs1 (def_stmt))) != NULL_TREE)))
if ((TREE_CODE (rhs2) == VECTOR_CST
&& (first = uniform_vector_p (rhs2)) != NULL_TREE)
|| (TREE_CODE (rhs2) == SSA_NAME
&& (def_stmt = SSA_NAME_DEF_STMT (rhs2))
&& gimple_assign_single_p (def_stmt)
&& (first = uniform_vector_p
(gimple_assign_rhs1 (def_stmt))) != NULL_TREE))
{
gimple_assign_set_rhs2 (stmt, first);
update_stmt (stmt);
rhs2 = first;
}
else
op = optab_for_tree_code (code, type, optab_vector);
}
/* Try for a vector/scalar shift, and if we don't have one, see if we
have a vector/vector shift */
else if (!vector_scalar_shift)
if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (rhs2))))
op = optab_for_tree_code (code, type, optab_vector);
else
{
op = optab_for_tree_code (code, type, optab_vector);
op = optab_for_tree_code (code, type, optab_scalar);
if (op && (optab_handler (op, TYPE_MODE (type))
!= CODE_FOR_nothing))
{
/* Transform vector <op> scalar => vector <op> {x,x,x,x}. */
int n_parts = TYPE_VECTOR_SUBPARTS (type);
int part_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (type)), 1);
tree part_type = lang_hooks.types.type_for_size (part_size, 1);
tree vect_type = build_vector_type (part_type, n_parts);
rhs2 = fold_convert (part_type, rhs2);
rhs2 = build_vector_from_val (vect_type, rhs2);
gimple_assign_set_rhs2 (stmt, rhs2);
update_stmt (stmt);
}
/* The rtl expander will expand vector/scalar as vector/vector
if necessary. Don't bother converting the stmt here. */
if (op == NULL
|| optab_handler (op, TYPE_MODE (type)) == CODE_FOR_nothing)
op = optab_for_tree_code (code, type, optab_vector);
}
}
else
......@@ -874,12 +853,7 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
if (compute_type == type)
{
compute_mode = TYPE_MODE (compute_type);
if ((GET_MODE_CLASS (compute_mode) == MODE_VECTOR_INT
|| GET_MODE_CLASS (compute_mode) == MODE_VECTOR_FLOAT
|| GET_MODE_CLASS (compute_mode) == MODE_VECTOR_FRACT
|| GET_MODE_CLASS (compute_mode) == MODE_VECTOR_UFRACT
|| GET_MODE_CLASS (compute_mode) == MODE_VECTOR_ACCUM
|| GET_MODE_CLASS (compute_mode) == MODE_VECTOR_UACCUM)
if (VECTOR_MODE_P (compute_mode)
&& op != NULL
&& optab_handler (op, compute_mode) != CODE_FOR_nothing)
return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment