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

Reply via email to