arm.c (neon_immediate_valid_for_shift): New function.
authorDmitry Plotnikov <dplotnikov@ispras.ru>
Wed, 22 Jun 2011 11:57:52 +0000 (11:57 +0000)
committerAlexander Monakov <amonakov@gcc.gnu.org>
Wed, 22 Jun 2011 11:57:52 +0000 (15:57 +0400)
2011-06-22  Dmitry Plotnikov  <dplotnikov@ispras.ru>
Dmitry Melnik  <dm@ispras.ru>

* config/arm/arm.c (neon_immediate_valid_for_shift): New function.
(neon_output_shift_immediate): Ditto.
* config/arm/arm-protos.h (neon_immediate_valid_for_shift): New
prototype.
(neon_output_shift_immediate): Ditto.
* config/arm/neon.md (vashl<mode>3): Modified constraint.
(vashr<mode>3_imm): New insn pattern.
(vlshr<mode>3_imm): Ditto.
(vashr<mode>3): Modified constraint.
(vlshr<mode>3): Ditto.
* config/arm/predicates.md (imm_for_neon_lshift_operand): New
predicate.
(imm_for_neon_rshift_operand): Ditto.
(imm_lshift_or_reg_neon): Ditto.
(imm_rshift_or_reg_neon): Ditto.

* optabs.c (init_optabs): Init optab codes for vashl, vashr, vlshr.

testsuite:

* gcc.target/arm/neon-vshr-imm-1.c: New testcase.
* gcc.target/arm/neon-vshl-imm-1.c: New testcase.
* gcc.target/arm/neon-vlshr-imm-1.c: New testcase.

Co-Authored-By: Dmitry Melnik <dm@ispras.ru>
From-SVN: r175293

gcc/ChangeLog
gcc/config/arm/arm-protos.h
gcc/config/arm/arm.c
gcc/config/arm/neon.md
gcc/config/arm/predicates.md
gcc/optabs.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c [new file with mode: 0644]

index a8e03fdd24f2dba606c96b47a5eed58e02cd0f7e..9a075199c5e558f6f715d2598d057d9c4e6f922f 100644 (file)
@@ -1,3 +1,24 @@
+2011-06-22  Dmitry Plotnikov  <dplotnikov@ispras.ru>
+       Dmitry Melnik  <dm@ispras.ru>
+
+       * config/arm/arm.c (neon_immediate_valid_for_shift): New function.
+       (neon_output_shift_immediate): Ditto.
+       * config/arm/arm-protos.h (neon_immediate_valid_for_shift): New
+       prototype.
+       (neon_output_shift_immediate): Ditto.
+       * config/arm/neon.md (vashl<mode>3): Modified constraint.
+       (vashr<mode>3_imm): New insn pattern.
+       (vlshr<mode>3_imm): Ditto.
+       (vashr<mode>3): Modified constraint.
+       (vlshr<mode>3): Ditto.
+       * config/arm/predicates.md (imm_for_neon_lshift_operand): New
+       predicate.
+       (imm_for_neon_rshift_operand): Ditto.
+       (imm_lshift_or_reg_neon): Ditto.
+       (imm_rshift_or_reg_neon): Ditto.
+
+       * optabs.c (init_optabs): Init optab codes for vashl, vashr, vlshr.
+
 2011-06-22  Jakub Jelinek  <jakub@redhat.com>
 
        * tree-ssa-ccp.c (evaluate_stmt): Try bitwise tracking for
index 2fd75fb3bd625c983403b256f99828ed6312bd3c..3eb21778123bd4f1827caf55bcda690b055d6647 100644 (file)
@@ -66,8 +66,12 @@ extern int vfp3_const_double_rtx (rtx);
 extern int neon_immediate_valid_for_move (rtx, enum machine_mode, rtx *, int *);
 extern int neon_immediate_valid_for_logic (rtx, enum machine_mode, int, rtx *,
                                           int *);
+extern int neon_immediate_valid_for_shift (rtx, enum machine_mode, rtx *,
+                                          int *, bool);
 extern char *neon_output_logic_immediate (const char *, rtx *,
                                          enum machine_mode, int, int);
+extern char *neon_output_shift_immediate (const char *, char, rtx *,
+                                         enum machine_mode, int, bool);
 extern void neon_pairwise_reduce (rtx, rtx, enum machine_mode,
                                  rtx (*) (rtx, rtx, rtx));
 extern rtx neon_make_constant (rtx);
index 88e3b623562d7c51e075a507546db1ec5f366653..efffcf814057a24cee7127eec589921be6781ca5 100644 (file)
@@ -8608,6 +8608,66 @@ neon_immediate_valid_for_logic (rtx op, enum machine_mode mode, int inverse,
   return 1;
 }
 
+/* Return TRUE if rtx OP is legal for use in a VSHR or VSHL instruction.  If
+   the immediate is valid, write a constant suitable for using as an operand
+   to VSHR/VSHL to *MODCONST and the corresponding element width to
+   *ELEMENTWIDTH. ISLEFTSHIFT is for determine left or right shift,
+   because they have different limitations.  */
+
+int
+neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
+                               rtx *modconst, int *elementwidth,
+                               bool isleftshift)
+{
+  unsigned int innersize = GET_MODE_SIZE (GET_MODE_INNER (mode));
+  unsigned int n_elts = CONST_VECTOR_NUNITS (op), i;
+  unsigned HOST_WIDE_INT last_elt = 0;
+  unsigned HOST_WIDE_INT maxshift;
+
+  /* Split vector constant out into a byte vector.  */
+  for (i = 0; i < n_elts; i++)
+    {
+      rtx el = CONST_VECTOR_ELT (op, i);
+      unsigned HOST_WIDE_INT elpart;
+
+      if (GET_CODE (el) == CONST_INT)
+        elpart = INTVAL (el);
+      else if (GET_CODE (el) == CONST_DOUBLE)
+        return 0;
+      else
+        gcc_unreachable ();
+
+      if (i != 0 && elpart != last_elt)
+        return 0;
+
+      last_elt = elpart;
+    }
+
+  /* Shift less than element size.  */
+  maxshift = innersize * 8;
+
+  if (isleftshift)
+    {
+      /* Left shift immediate value can be from 0 to <size>-1.  */
+      if (last_elt >= maxshift)
+        return 0;
+    }
+  else
+    {
+      /* Right shift immediate value can be from 1 to <size>.  */
+      if (last_elt == 0 || last_elt > maxshift)
+       return 0;
+    }
+
+  if (elementwidth)
+    *elementwidth = innersize * 8;
+
+  if (modconst)
+    *modconst = CONST_VECTOR_ELT (op, 0);
+
+  return 1;
+}
+
 /* Return a string suitable for output of Neon immediate logic operation
    MNEM.  */
 
@@ -8630,6 +8690,28 @@ neon_output_logic_immediate (const char *mnem, rtx *op2, enum machine_mode mode,
   return templ;
 }
 
+/* Return a string suitable for output of Neon immediate shift operation
+   (VSHR or VSHL) MNEM.  */
+
+char *
+neon_output_shift_immediate (const char *mnem, char sign, rtx *op2,
+                            enum machine_mode mode, int quad,
+                            bool isleftshift)
+{
+  int width, is_valid;
+  static char templ[40];
+
+  is_valid = neon_immediate_valid_for_shift (*op2, mode, op2, &width, isleftshift);
+  gcc_assert (is_valid != 0);
+
+  if (quad)
+    sprintf (templ, "%s.%c%d\t%%q0, %%q1, %%2", mnem, sign, width);
+  else
+    sprintf (templ, "%s.%c%d\t%%P0, %%P1, %%2", mnem, sign, width);
+
+  return templ;
+}
+
 /* Output a sequence of pairwise operations to implement a reduction.
    NOTE: We do "too much work" here, because pairwise operations work on two
    registers-worth of operands in one go. Unfortunately we can't exploit those
index a8c1b878670c36507bba32e407288cbbf6b046e1..2c109e09ac6c22a35a3972d0c0f081a00123c794 100644 (file)
 ; SImode elements.
 
 (define_insn "vashl<mode>3"
+  [(set (match_operand:VDQIW 0 "s_register_operand" "=w,w")
+       (ashift:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w,w")
+                     (match_operand:VDQIW 2 "imm_lshift_or_reg_neon" "w,Dn")))]
+  "TARGET_NEON"
+  {
+    switch (which_alternative)
+      {
+        case 0: return "vshl.<V_s_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2";
+        case 1: return neon_output_shift_immediate ("vshl", 'i', &operands[2],
+                                                   <MODE>mode,
+                                                   VALID_NEON_QREG_MODE (<MODE>mode),
+                                                   true);
+        default: gcc_unreachable ();
+      }
+  }
+  [(set (attr "neon_type")
+      (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+                    (const_string "neon_vshl_ddd")
+                    (const_string "neon_shift_3")))]
+)
+
+(define_insn "vashr<mode>3_imm"
   [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
-       (ashift:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
-                     (match_operand:VDQIW 2 "s_register_operand" "w")))]
+       (ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
+                       (match_operand:VDQIW 2 "imm_for_neon_rshift_operand" "Dn")))]
   "TARGET_NEON"
-  "vshl.<V_s_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2"
+  {
+    return neon_output_shift_immediate ("vshr", 's', &operands[2],
+                                       <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode),
+                                       false);
+  }
   [(set (attr "neon_type")
       (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
                     (const_string "neon_vshl_ddd")
                     (const_string "neon_shift_3")))]
 )
 
+(define_insn "vlshr<mode>3_imm"
+  [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
+       (lshiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
+                       (match_operand:VDQIW 2 "imm_for_neon_rshift_operand" "Dn")))]
+  "TARGET_NEON"
+  {
+    return neon_output_shift_immediate ("vshr", 'u', &operands[2],
+                                       <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode),
+                                       false);
+  }              
+  [(set (attr "neon_type")
+       (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+                     (const_string "neon_vshl_ddd")
+                     (const_string "neon_shift_3")))]
+)
+
 ; Used for implementing logical shift-right, which is a left-shift by a negative
 ; amount, with signed operands. This is essentially the same as ashl<mode>3
 ; above, but using an unspec in case GCC tries anything tricky with negative
 (define_expand "vashr<mode>3"
   [(set (match_operand:VDQIW 0 "s_register_operand" "")
        (ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
-                       (match_operand:VDQIW 2 "s_register_operand" "")))]
+                       (match_operand:VDQIW 2 "imm_rshift_or_reg_neon" "")))]
   "TARGET_NEON"
 {
   rtx neg = gen_reg_rtx (<MODE>mode);
-
-  emit_insn (gen_neg<mode>2 (neg, operands[2]));
-  emit_insn (gen_ashl<mode>3_signed (operands[0], operands[1], neg));
-
+  if (REG_P (operands[2]))
+    {
+      emit_insn (gen_neg<mode>2 (neg, operands[2]));
+      emit_insn (gen_ashl<mode>3_signed (operands[0], operands[1], neg));
+    }
+  else
+    emit_insn (gen_vashr<mode>3_imm (operands[0], operands[1], operands[2]));
   DONE;
 })
 
 (define_expand "vlshr<mode>3"
   [(set (match_operand:VDQIW 0 "s_register_operand" "")
        (lshiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
-                       (match_operand:VDQIW 2 "s_register_operand" "")))]
+                       (match_operand:VDQIW 2 "imm_rshift_or_reg_neon" "")))]
   "TARGET_NEON"
 {
   rtx neg = gen_reg_rtx (<MODE>mode);
-
-  emit_insn (gen_neg<mode>2 (neg, operands[2]));
-  emit_insn (gen_ashl<mode>3_unsigned (operands[0], operands[1], neg));
-
+  if (REG_P (operands[2]))
+    {
+      emit_insn (gen_neg<mode>2 (neg, operands[2]));
+      emit_insn (gen_ashl<mode>3_unsigned (operands[0], operands[1], neg));
+    }
+  else
+    emit_insn (gen_vlshr<mode>3_imm (operands[0], operands[1], operands[2]));
   DONE;
 })
 
index 891a9749bbf8f967c94a100595bd7f61d31e7b1e..ec5de6921e7577725edc440bef268c2d1f895a65 100644 (file)
   return neon_immediate_valid_for_move (op, mode, NULL, NULL);
 })
 
+(define_predicate "imm_for_neon_lshift_operand"
+  (match_code "const_vector")
+{
+  return neon_immediate_valid_for_shift (op, mode, NULL, NULL, true);
+})
+
+(define_predicate "imm_for_neon_rshift_operand"
+  (match_code "const_vector")
+{
+  return neon_immediate_valid_for_shift (op, mode, NULL, NULL, false);
+})
+
+(define_predicate "imm_lshift_or_reg_neon"
+  (ior (match_operand 0 "s_register_operand")
+       (match_operand 0 "imm_for_neon_lshift_operand")))
+
+(define_predicate "imm_rshift_or_reg_neon"
+  (ior (match_operand 0 "s_register_operand")
+       (match_operand 0 "imm_for_neon_rshift_operand")))
+
 (define_predicate "imm_for_neon_logic_operand"
   (match_code "const_vector")
 {
index 969d5cf55948eda7c62e0cf1fdf6d07076fa8531..bf15ab4fbc6e9e2bb1b04272d519001d519d5cd9 100644 (file)
@@ -5925,6 +5925,9 @@ init_optabs (void)
   init_optab (usashl_optab, US_ASHIFT);
   init_optab (ashr_optab, ASHIFTRT);
   init_optab (lshr_optab, LSHIFTRT);
+  init_optabv (vashl_optab, ASHIFT);
+  init_optabv (vashr_optab, ASHIFTRT);
+  init_optabv (vlshr_optab, LSHIFTRT);
   init_optab (rotl_optab, ROTATE);
   init_optab (rotr_optab, ROTATERT);
   init_optab (smin_optab, SMIN);
index a102060360b397eba56b462c59afc1028a66c42d..75796207b6a2d22d978a8cd625bad792b789748e 100644 (file)
@@ -1,3 +1,10 @@
+2011-06-22  Dmitry Plotnikov  <dplotnikov@ispras.ru>
+       Dmitry Melnik  <dm@ispras.ru>
+
+       * gcc.target/arm/neon-vshr-imm-1.c: New testcase.
+       * gcc.target/arm/neon-vshl-imm-1.c: New testcase.
+       * gcc.target/arm/neon-vlshr-imm-1.c: New testcase.
+
 2011-06-22  Uros Bizjak  <ubizjak@gmail.com>
 
        * gcc.dg/torture/tls/run-le.c: Skip for -pie on alpha*-*-linux*.
diff --git a/gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c b/gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c
new file mode 100644 (file)
index 0000000..e666371
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O2 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" } */
+/* { dg-final { scan-assembler "vshr\.u32.*#3" } } */
+
+/* Verify that VSHR immediate is used.  */
+void f1(int n, unsigned int x[], unsigned int y[]) {
+  int i;
+  for (i = 0; i < n; ++i)
+    y[i] = x[i] >> 3;
+}
diff --git a/gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c b/gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c
new file mode 100644 (file)
index 0000000..913d595
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O2 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" } */
+/* { dg-final { scan-assembler "vshl\.i32.*#3" } } */
+
+/* Verify that VSHR immediate is used.  */
+void f1(int n, int x[], int y[]) {
+  int i;
+  for (i = 0; i < n; ++i)
+    y[i] = x[i] << 3;
+}
diff --git a/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c b/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c
new file mode 100644 (file)
index 0000000..82a3c5c
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O2 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" } */
+/* { dg-final { scan-assembler "vshr\.s32.*#3" } } */
+
+/* Verify that VSHR immediate is used.  */
+void f1(int n, int x[], int y[]) {
+  int i;
+  for (i = 0; i < n; ++i)
+    y[i] = x[i] >> 3;
+}