From: Richard Henderson <r...@redhat.com> This allows other rtl expanders to rely on shifts of vector by scalar.
This replaces the patch posted a couple of days ago that adds these scalar shifts to the rs6000 backend, following the info that Sparc needs this fallback as well. --- gcc/optabs.c | 65 ++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/vect/vec-scal-opt.c | 2 +- gcc/testsuite/gcc.dg/vect/vec-scal-opt1.c | 2 +- gcc/testsuite/gcc.dg/vect/vec-scal-opt2.c | 2 +- gcc/testsuite/lib/target-supports.exp | 21 --------- gcc/tree-vect-generic.c | 66 +++++++++-------------------- 6 files changed, 88 insertions(+), 70 deletions(-) diff --git a/gcc/optabs.c b/gcc/optabs.c index 0ba1333..e112467 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -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. */ diff --git a/gcc/testsuite/gcc.dg/vect/vec-scal-opt.c b/gcc/testsuite/gcc.dg/vect/vec-scal-opt.c index 6514f05..f53e66d 100644 --- a/gcc/testsuite/gcc.dg/vect/vec-scal-opt.c +++ b/gcc/testsuite/gcc.dg/vect/vec-scal-opt.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vec-scal-opt1.c b/gcc/testsuite/gcc.dg/vect/vec-scal-opt1.c index acab407..4025f67 100644 --- a/gcc/testsuite/gcc.dg/vect/vec-scal-opt1.c +++ b/gcc/testsuite/gcc.dg/vect/vec-scal-opt1.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vec-scal-opt2.c b/gcc/testsuite/gcc.dg/vect/vec-scal-opt2.c index cfaf5e0..677836d 100644 --- a/gcc/testsuite/gcc.dg/vect/vec-scal-opt2.c +++ b/gcc/testsuite/gcc.dg/vect/vec-scal-opt2.c @@ -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" } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index a3b5311..99e83f6 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -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 { } { diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c index 4e79b15..7fba9bb 100644 --- a/gcc/tree-vect-generic.c +++ b/gcc/tree-vect-generic.c @@ -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; -- 1.7.6.4