public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
@ 2010-06-22 13:29 Dmitry Plotnikov
  2010-11-23 18:13 ` Tejas Belagod
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Plotnikov @ 2010-06-22 13:29 UTC (permalink / raw)
  To: gcc-patches; +Cc: rearnsha, dm

[-- Attachment #1: Type: text/plain, Size: 1357 bytes --]

This is repost of our patch ( 
http://gcc.gnu.org/ml/gcc-patches/2010-02/msg00462.html), which also 
includes a bugfix to previous patch.
This patch adds support for immediate shift values for NEON in ARM 
backend.  We added new predicates for immediate shift value or register 
operands and used them in new patterns. The only tiny modification in 
target-independent part is in optabs.c and it has been tested on x86_64 
without any regressions.

Example:
   a[i] = a[i]>>4;

Before:
   vmov.i32  q9, #4294967292  @ v4si
   ...
   vshl.u32  q8, q8, q9

With patch:
   vshr.u32  q8, q8, #4

The patch was tested on 2010-06-03 snapshot.

OK for trunk?

2010-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): New function.

    * config/arm/neon.md (vashl<mode>3): Modified constraint.
    (vashr<mode>3_imm): New insn pattern.
    (vlshr<mode>3_imm): New insn pattern.
    (vashr<mode>3): Modified constraint.
    (vlshr<mode>3): Modified constraint.

    * config/arm/predicates.md (imm_for_neon_shift_operand): New predicate.
    (imm_shift_or_reg_neon): New predicate.

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

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


[-- Attachment #2: neon-immediates.diff --]
[-- Type: text/x-patch, Size: 8286 bytes --]

2010-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): New function.


   * config/arm/neon.md (vashl<mode>3): Modified constraint.
   (vashr<mode>3_imm): New insn pattern.
   (vlshr<mode>3_imm): New insn pattern.
   (vashr<mode>3): Modified constraint.
   (vlshr<mode>3): Modified constraint.


   * config/arm/predicates.md (imm_for_neon_shift_operand): New predicate.
   (imm_shift_or_reg_neon): New predicate.


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

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

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 84dd8fa..3fa19e8 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -8026,6 +8026,51 @@ 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. */
+
+int
+neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
+            rtx *modconst, int *elementwidth)
+{
+  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;
+
+  /* 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 */
+  if (last_elt > innersize * 8)
+    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.  */
 
@@ -8048,6 +8093,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)
+{
+    int width, is_valid;
+    static char templ[40];
+
+    is_valid = neon_immediate_valid_for_shift (*op2, mode, op2, &width);
+
+    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
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 43b3805..43c282d 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -1135,11 +1135,53 @@
 ; 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_shift_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", 's', &operands[2],
+                         <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));
+        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_shift_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));
+  }
+
+  [(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_shift_operand" "Dn")))]
+  "TARGET_NEON"
+  {
+    return neon_output_shift_immediate ("vshr", 'u', &operands[2],
+             <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));
+  }              
+
   [(set (attr "neon_type")
       (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
                     (const_string "neon_vshl_ddd")
@@ -1182,29 +1224,35 @@
 
 (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" "")))]
+  (ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
+           (match_operand:VDQIW 2 "imm_shift_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" "")))]
+  (lshiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
+           (match_operand:VDQIW 2 "imm_shift_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;
 })
 
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index d351f44..02fced4 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -496,6 +496,17 @@
   return neon_immediate_valid_for_move (op, mode, NULL, NULL);
 })
 
+(define_predicate "imm_for_neon_shift_operand"
+  (match_code "const_vector")
+{
+  return neon_immediate_valid_for_shift (op, mode, NULL, NULL);
+})
+
+
+(define_predicate "imm_shift_or_reg_neon"
+    (ior (match_operand 0 "s_register_operand")
+         (match_operand 0 "imm_for_neon_shift_operand")))
+
 (define_predicate "imm_for_neon_logic_operand"
   (match_code "const_vector")
 {
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 555e256..dea1d9c 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6260,6 +6260,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);

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2010-06-22 13:29 [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support Dmitry Plotnikov
@ 2010-11-23 18:13 ` Tejas Belagod
  2010-11-25 16:33   ` Dmitry Plotnikov
  0 siblings, 1 reply; 13+ messages in thread
From: Tejas Belagod @ 2010-11-23 18:13 UTC (permalink / raw)
  To: dplotnikov, gcc-patches; +Cc: rearnsha, dm

Hi,

I can't approve or reject this patch, but I have a few comments inline
below.

On Tue, 2010-06-22 at 16:50 +0400, Dmitry Plotnikov wrote:
> This is repost of our patch ( 
> http://gcc.gnu.org/ml/gcc-patches/2010-02/msg00462.html), which also 
> includes a bugfix to previous patch.
> This patch adds support for immediate shift values for NEON in ARM 
> backend.  We added new predicates for immediate shift value or register 
> operands and used them in new patterns. The only tiny modification in 
> target-independent part is in optabs.c and it has been tested on x86_64 
> without any regressions.
> 



+int
+neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
+            rtx *modconst, int *elementwidth)
+{
+  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;
+
+  /* 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 */
+  if (last_elt > innersize * 8)
+    return 0;
+


VSHL allows (elemsize_in_bits - 1) and VSHR allows elemsize_in_bits as
immediate shifts. This condition here holds good for vshr, but not vshl.
It should be something like:
neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
            rtx *modconst, int *elementwidth, bool is_vshr)
{
  ....
  elemsize_in_bits = innersize * 8;
  return (is_vshr ?  last_elt <= elemsize_in_bits 
  : last_elt < elemsize_in_bits );
}

And correspondingly change neon_immediate_valid_for_shift () prototype,
definition and call points.
  
Or possibly have two predicates - one imm_for_neon_rshift_operand for
VSHR and imm_for_neon_lshift_operand for VSHL.


 (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_shift_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", 's',
&operands[2],
+                         <MODE>mode, VALID_NEON_QREG_MODE
(<MODE>mode));
+        default: gcc_unreachable ();
+      }
+  }

In the second template for immediate, the ideal UAL syntax is 'i',
though 's' is allowed - proabaly a minor issue.

Thanks,
Tejas.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2010-11-23 18:13 ` Tejas Belagod
@ 2010-11-25 16:33   ` Dmitry Plotnikov
  2010-11-26 13:19     ` Tejas Belagod
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Plotnikov @ 2010-11-25 16:33 UTC (permalink / raw)
  To: Tejas Belagod; +Cc: gcc-patches, rearnsha, dm

[-- Attachment #1: Type: text/plain, Size: 1045 bytes --]

Hi,

Thank you for comments!
We missed limitations for vshl immediate.  We have added two predicates 
and fixed templates for immediate.  New patch in attachment.
Ok now?

On 11/23/2010 07:47 PM, Tejas Belagod wrote:
>
> VSHL allows (elemsize_in_bits - 1) and VSHR allows elemsize_in_bits as
> immediate shifts. This condition here holds good for vshr, but not vshl.
> It should be something like:
> neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
>              rtx *modconst, int *elementwidth, bool is_vshr)
> {
>    ....
>    elemsize_in_bits = innersize * 8;
>    return (is_vshr ?  last_elt<= elemsize_in_bits
>    : last_elt<  elemsize_in_bits );
> }
>
> And correspondingly change neon_immediate_valid_for_shift () prototype,
> definition and call points.
>
> Or possibly have two predicates - one imm_for_neon_rshift_operand for
> VSHR and imm_for_neon_lshift_operand for VSHL.
>
> In the second template for immediate, the ideal UAL syntax is 'i',
> though 's' is allowed - proabaly a minor issue.
>
> Thanks,
> Tejas.

[-- Attachment #2: neon-immediates.diff --]
[-- Type: text/x-patch, Size: 9749 bytes --]

2010-11-25  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): New function.


   * config/arm/neon.md (vashl<mode>3): Modified constraint.
   (vashr<mode>3_imm): New insn pattern.
   (vlshr<mode>3_imm): New insn pattern.
   (vashr<mode>3): Modified constraint.
   (vlshr<mode>3): Modified constraint.


   * config/arm/predicates.md (imm_for_neon_shift_operand): New predicate.
   (imm_shift_or_reg_neon): New predicate.


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

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

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 4f6bea1..f27f0f5 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -8412,6 +8412,65 @@ 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 < 0) || (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.  */
 
@@ -8434,6 +8493,30 @@ 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)
+{
+    int width, is_valid;
+    static char templ[40];
+    bool isleftshift;
+
+    isleftshift = strcmp(mnem, "vshl") == 0;
+    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
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 06bbc52..db3cd23 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -929,11 +931,53 @@
 ; 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", 's', &operands[2],
+                         <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));
+        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", 'i', &operands[2],
+             <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));
+  }
+
+  [(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));
+  }              
+
   [(set (attr "neon_type")
       (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
                     (const_string "neon_vshl_ddd")
@@ -976,29 +1020,35 @@
 
 (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" "")))]
+  (ashiftrt:VDQIW (match_operand:VDQIW 1 "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" "")))]
+  (lshiftrt:VDQIW (match_operand:VDQIW 1 "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;
 })
 
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index 54f4861..b143557 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -584,6 +584,27 @@
   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")
 {
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 5d095c1..07d6b0a 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6169,6 +6169,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);
   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
index 0000000..82a3c5c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c
@@ -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;
+}

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2010-11-25 16:33   ` Dmitry Plotnikov
@ 2010-11-26 13:19     ` Tejas Belagod
  2010-12-27 15:35       ` Dmitry Plotnikov
  0 siblings, 1 reply; 13+ messages in thread
From: Tejas Belagod @ 2010-11-26 13:19 UTC (permalink / raw)
  To: Dmitry Plotnikov; +Cc: gcc-patches, rearnsha, dm

Hi,

Some formatting comments.

On Thu, 2010-11-25 at 15:50 +0300, Dmitry Plotnikov wrote:
> 2010-11-25  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): New function.
> 
> 
>    * config/arm/neon.md (vashl<mode>3): Modified constraint.
>    (vashr<mode>3_imm): New insn pattern.
>    (vlshr<mode>3_imm): New insn pattern.
>    (vashr<mode>3): Modified constraint.
>    (vlshr<mode>3): Modified constraint.
> 
> 
>    * config/arm/predicates.md (imm_for_neon_shift_operand): New
> predicate.
>    (imm_shift_or_reg_neon): New predicate.
> 

Please update the predicates Changelog entry with your new predicates.

> 
>    * optabs.c (init_optabs): Init optab codes for vashl, vashr, vlshr.
> 
>    * testsuite/gcc.target/arm/neon-vshr-imm-1.c: New testcase.

Also, the preferred format for the Changelog entry is:

1. A separate Changelog section for every directory that has a
Changelog.
2. Every Changelog entry starts with a tab.

i.e.

gcc/

2010-11-25  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): New function.
	* config/arm/neon.md (vashl<mode>3): Modified constraint.
	(vashr<mode>3_imm): New insn pattern.
	(vlshr<mode>3_imm): New insn pattern.
	(vashr<mode>3): Modified constraint.
	(vlshr<mode>3): Modified constraint.
	* config/arm/predicates.md (imm_for_neon_shift_operand): New 
	predicate.
	(imm_shift_or_reg_neon): New predicate.
	* optabs.c (init_optabs): Init optab codes for vashl, vashr, 
	vlshr.

gcc/testsuite/

2010-11-25  Dmitry Plotnikov  <dplotnikov@ispras.ru>
            Dmitry Melnik  <dm@ispras.ru>

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

Thanks,
Tejas.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2010-11-26 13:19     ` Tejas Belagod
@ 2010-12-27 15:35       ` Dmitry Plotnikov
  2011-02-27 23:58         ` Ramana Radhakrishnan
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Plotnikov @ 2010-12-27 15:35 UTC (permalink / raw)
  To: Tejas Belagod; +Cc: gcc-patches, rearnsha, dm

[-- Attachment #1: Type: text/plain, Size: 110 bytes --]

On 11/26/2010 01:34 PM, Tejas Belagod wrote:
> Hi,
>
> Some formatting comments.
>
Fixed. New patch attached.

[-- Attachment #2: neon-immediates.diff --]
[-- Type: text/x-patch, Size: 10002 bytes --]

gcc/config/arm/

2010-11-25  Dmitry Plotnikov  <dplotnikov@ispras.ru>
            Dmitry Melnik  <dm@ispras.ru>

	* arm.c (neon_immediate_valid_for_shift): New function.
	(neon_output_shift_immediate): New function.

	* neon.md (vashl<mode>3): Modified constraint.
	(vashr<mode>3_imm): New insn pattern.
	(vlshr<mode>3_imm): New insn pattern.
	(vashr<mode>3): Modified constraint.
	(vlshr<mode>3): Modified constraint.

	* predicates.md (imm_for_neon_lshift_operand): New predicate.
	(imm_for_neon_rshift_operand): New predicate.
	(imm_lshift_or_reg_neon): New predicate.
	(imm_rshift_or_reg_neon): New predicate.

gcc/

2010-11-25  Dmitry Plotnikov  <dplotnikov@ispras.ru>
            Dmitry Melnik  <dm@ispras.ru>

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

gcc/testsuite/

2010-11-25  Dmitry Plotnikov  <dplotnikov@ispras.ru>
            Dmitry Melnik  <dm@ispras.ru>

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

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 4f6bea1..f27f0f5 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -8412,6 +8412,65 @@ 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 < 0) || (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.  */
 
@@ -8434,6 +8493,30 @@ 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)
+{
+    int width, is_valid;
+    static char templ[40];
+    bool isleftshift;
+
+    isleftshift = strcmp(mnem, "vshl") == 0;
+    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
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 06bbc52..db3cd23 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -929,11 +931,53 @@
 ; 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", 's', &operands[2],
+                         <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));
+        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", 'i', &operands[2],
+             <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));
+  }
+
+  [(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));
+  }              
+
   [(set (attr "neon_type")
       (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
                     (const_string "neon_vshl_ddd")
@@ -976,29 +1020,35 @@
 
 (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" "")))]
+  (ashiftrt:VDQIW (match_operand:VDQIW 1 "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" "")))]
+  (lshiftrt:VDQIW (match_operand:VDQIW 1 "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;
 })
 
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index 54f4861..b143557 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -584,6 +584,27 @@
   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")
 {
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 5d095c1..07d6b0a 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6169,6 +6169,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);
   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
index 0000000..82a3c5c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c
@@ -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;
+}

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2010-12-27 15:35       ` Dmitry Plotnikov
@ 2011-02-27 23:58         ` Ramana Radhakrishnan
  2011-03-02 14:27           ` Dmitry Plotnikov
  0 siblings, 1 reply; 13+ messages in thread
From: Ramana Radhakrishnan @ 2011-02-27 23:58 UTC (permalink / raw)
  To: Dmitry Plotnikov; +Cc: Tejas Belagod, gcc-patches, rearnsha, dm

Hi Dmitry,

		Sorry about the delayed review of this patch. Can you please correct 
the formatting according to a few comments inline below ?

Can you add some tests to check for the generation of vshl and vlshr 
please ? Thanks in advance.

cheers
Ramana


> 2010-11-25  Dmitry Plotnikov  <dplotnikov@ispras.ru>
>             Dmitry Melnik  <dm@ispras.ru>
>
>         * arm.c (neon_immediate_valid_for_shift): New function.
>         (neon_output_shift_immediate): New function.
>
>         * neon.md (vashl<mode>3): Modified constraint.
>         (vashr<mode>3_imm): New insn pattern.
>         (vlshr<mode>3_imm): New insn pattern.
>         (vashr<mode>3): Modified constraint.
>         (vlshr<mode>3): Modified constraint.
>
>         * predicates.md (imm_for_neon_lshift_operand): New predicate.
>         (imm_for_neon_rshift_operand): New predicate.
>         (imm_lshift_or_reg_neon): New predicate.
>         (imm_rshift_or_reg_neon): New predicate.

> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 4f6bea1..f27f0f5 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -8412,6 +8412,65 @@ 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

Can you please change the return type to bool ?

> +neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
> +            rtx *modconst, int *elementwidth, bool isleftshift)

Please note that the function parameters should be aligned to the start 
of the first parameter.

Something like

neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
				rtx *modconst, int *elementwidth,
				bool isleftshift)

Please correct a similar issue below with neon_output_shift_immediate 
and watch out for 80 character line lengths. I find that using the 
script at $GCC_DIR/contrib/check_GNU_style.sh is useful to catch some of 
the more common errors.

>
> +/* 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)
> +{
> +    int width, is_valid;
> +    static char templ[40];
> +    bool isleftshift;
> +
> +    isleftshift = strcmp(mnem, "vshl") == 0;

Space between function name and opening '(' . So "strcmp (" rather than 
the above.

Is it possible to extend neon_output_shift_immediate to have a flag to 
indicate that this is a vshl rather than detecting this in this form ?


> +    is_valid = neon_immediate_valid_for_shift (*op2, mode, op2,&width, isleftshift);
> +

Unnecessary new line here.

> +    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
> diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
> index 06bbc52..db3cd23 100644
> --- a/gcc/config/arm/neon.md
> +++ b/gcc/config/arm/neon.md
> @@ -929,11 +931,53 @@
>   ; 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", 's',&operands[2],
> +<MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));

Again parameters to the function calls should be formatted properly. 
Please also use 'i' instead of 's' since that's the preferred UAL syntax 
for vshl with a constant. Yes, there's a minor bug in the disassembler 
because it shows this up as vshl.s32.

> +        default: gcc_unreachable ();
> +      }
> +  }
> +

Unnecessary new line.

> +  [(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")))]
> +)
> +
> +

Extra new line not needed here.

> +(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", 'i',&operands[2],
> +<MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));

Align <MODE>mode to be at the same position as "vshr" and in a number of 
places below.


> +  }
> +

Extra new line here.

> +  [(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));
> +  }
> +
>     [(set (attr "neon_type")
>         (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
>                       (const_string "neon_vshl_ddd")
> @@ -976,29 +1020,35 @@
>
>   (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" "")))]
> +  (ashiftrt:VDQIW (match_operand:VDQIW 1 "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" "")))]
> +  (lshiftrt:VDQIW (match_operand:VDQIW 1 "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;
>   })
>
> diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
> index 54f4861..b143557 100644
> --- a/gcc/config/arm/predicates.md
> +++ b/gcc/config/arm/predicates.md
> @@ -584,6 +584,27 @@
>     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);
> +})
> +
> +

Unnecessary extra new line which can be removed here.

> +(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")
>   {

> 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
> index 0000000..82a3c5c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c
> @@ -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;
> +}

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2011-02-27 23:58         ` Ramana Radhakrishnan
@ 2011-03-02 14:27           ` Dmitry Plotnikov
  2011-03-04 13:15             ` Dmitry Plotnikov
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Plotnikov @ 2011-03-02 14:27 UTC (permalink / raw)
  To: ramana.radhakrishnan
  Cc: Ramana Radhakrishnan, Tejas Belagod, gcc-patches, rearnsha, dm

[-- Attachment #1: Type: text/plain, Size: 396 bytes --]

On 02/28/2011 02:49 AM, Ramana Radhakrishnan wrote:
> Hi Dmitry,
>
>         Sorry about the delayed review of this patch. Can you please 
> correct the formatting according to a few comments inline below ?
>
> Can you add some tests to check for the generation of vshl and vlshr 
> please ? Thanks in advance.
>
> cheers
> Ramana
>
>

Thank you for review!
Fixed.  New patch attached.
Ok now ?


[-- Attachment #2: neon-immediates.diff --]
[-- Type: text/x-patch, Size: 11322 bytes --]

gcc/config/arm/

2010-11-25  Dmitry Plotnikov  <dplotnikov@ispras.ru>
            Dmitry Melnik  <dm@ispras.ru>

	* arm.c (neon_immediate_valid_for_shift): New function.
	(neon_output_shift_immediate): New function.

	* neon.md (vashl<mode>3): Modified constraint.
	(vashr<mode>3_imm): New insn pattern.
	(vlshr<mode>3_imm): New insn pattern.
	(vashr<mode>3): Modified constraint.
	(vlshr<mode>3): Modified constraint.

	* predicates.md (imm_for_neon_lshift_operand): New predicate.
	(imm_for_neon_rshift_operand): New predicate.
	(imm_lshift_or_reg_neon): New predicate.
	(imm_rshift_or_reg_neon): New predicate.

gcc/

2010-11-25  Dmitry Plotnikov  <dplotnikov@ispras.ru>
            Dmitry Melnik  <dm@ispras.ru>

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

gcc/testsuite/

2010-11-25  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.

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 88c43e3..8b91c45 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -8508,6 +8508,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.  */
+
+bool
+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 < 0) || (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.  */
 
@@ -8530,6 +8590,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
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 06bbc52..b87d0a6 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -929,11 +929,53 @@
 ; 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", 'i', &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")
@@ -976,29 +1018,35 @@
 
 (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" "")))]
+  (ashiftrt:VDQIW (match_operand:VDQIW 1 "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" "")))]
+  (lshiftrt:VDQIW (match_operand:VDQIW 1 "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;
 })
 
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index e4c6146..26ff1c5 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -585,6 +585,26 @@
   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")
 {
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 26735dd..012dae7 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6171,6 +6171,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);
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
index 0000000..e666371
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c
@@ -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
index 0000000..913d595
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c
@@ -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
index 0000000..8f22a52
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c
@@ -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\.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;
+}

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2011-03-02 14:27           ` Dmitry Plotnikov
@ 2011-03-04 13:15             ` Dmitry Plotnikov
  2011-03-20 16:32               ` Ramana Radhakrishnan
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Plotnikov @ 2011-03-04 13:15 UTC (permalink / raw)
  To: Dmitry Plotnikov
  Cc: ramana.radhakrishnan, Ramana Radhakrishnan, Tejas Belagod,
	gcc-patches, rearnsha, dm

[-- Attachment #1: Type: text/plain, Size: 620 bytes --]

On 03/02/2011 05:27 PM, Dmitry Plotnikov wrote:
> On 02/28/2011 02:49 AM, Ramana Radhakrishnan wrote:
>> Hi Dmitry,
>>
>>         Sorry about the delayed review of this patch. Can you please 
>> correct the formatting according to a few comments inline below ?
>>
>> Can you add some tests to check for the generation of vshl and vlshr 
>> please ? Thanks in advance.
>>
>> cheers
>> Ramana
>>
>>
>
> Thank you for review!
> Fixed.  New patch attached.
> Ok now ?
>
There was a mistake in the patch.  According to documentation vshl 
should have .i suffix, while vshr should have .s or .u .
The fixed patch is attached.

[-- Attachment #2: neon-immediates.diff --]
[-- Type: text/x-patch, Size: 11322 bytes --]

gcc/config/arm/

2010-11-25  Dmitry Plotnikov  <dplotnikov@ispras.ru>
            Dmitry Melnik  <dm@ispras.ru>

	* arm.c (neon_immediate_valid_for_shift): New function.
	(neon_output_shift_immediate): New function.

	* neon.md (vashl<mode>3): Modified constraint.
	(vashr<mode>3_imm): New insn pattern.
	(vlshr<mode>3_imm): New insn pattern.
	(vashr<mode>3): Modified constraint.
	(vlshr<mode>3): Modified constraint.

	* predicates.md (imm_for_neon_lshift_operand): New predicate.
	(imm_for_neon_rshift_operand): New predicate.
	(imm_lshift_or_reg_neon): New predicate.
	(imm_rshift_or_reg_neon): New predicate.

gcc/

2010-11-25  Dmitry Plotnikov  <dplotnikov@ispras.ru>
            Dmitry Melnik  <dm@ispras.ru>

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

gcc/testsuite/

2010-11-25  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.

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 88c43e3..8b91c45 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -8508,6 +8508,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.  */
+
+bool
+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 < 0) || (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.  */
 
@@ -8530,6 +8590,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
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 06bbc52..b87d0a6 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -929,11 +929,53 @@
 ; 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")
@@ -976,29 +1018,35 @@
 
 (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" "")))]
+  (ashiftrt:VDQIW (match_operand:VDQIW 1 "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" "")))]
+  (lshiftrt:VDQIW (match_operand:VDQIW 1 "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;
 })
 
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index e4c6146..26ff1c5 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -585,6 +585,26 @@
   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")
 {
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 26735dd..012dae7 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6171,6 +6171,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);
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
index 0000000..e666371
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c
@@ -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
index 0000000..913d595
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c
@@ -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
index 0000000..8f22a52
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c
@@ -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;
+}

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2011-03-04 13:15             ` Dmitry Plotnikov
@ 2011-03-20 16:32               ` Ramana Radhakrishnan
  2011-06-22  0:18                 ` Ramana Radhakrishnan
  0 siblings, 1 reply; 13+ messages in thread
From: Ramana Radhakrishnan @ 2011-03-20 16:32 UTC (permalink / raw)
  To: Dmitry Plotnikov; +Cc: Tejas Belagod, gcc-patches, rearnsha, dm

On Fri, Mar 4, 2011 at 1:16 PM, Dmitry Plotnikov <dplotnikov@ispras.ru> wrote:
> On 03/02/2011 05:27 PM, Dmitry Plotnikov wrote:
>>
>> On 02/28/2011 02:49 AM, Ramana Radhakrishnan wrote:
>>>
>>
> There was a mistake in the patch.  According to documentation vshl should
> have .i suffix, while vshr should have .s or .u .
> The fixed patch is attached.

The ARM specific part of your patch looks ok.

Please get approval for the target independent parts (changes to
optabs.c) separately from a middle-end maintainer.  I cannot approve
those bits.


cheers
Ramana

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2011-03-20 16:32               ` Ramana Radhakrishnan
@ 2011-06-22  0:18                 ` Ramana Radhakrishnan
  2011-06-22  8:52                   ` Richard Earnshaw
  0 siblings, 1 reply; 13+ messages in thread
From: Ramana Radhakrishnan @ 2011-06-22  0:18 UTC (permalink / raw)
  To: gcc-patches; +Cc: Dmitry Plotnikov, Tejas Belagod, rearnsha, dm

>
> Please get approval for the target independent parts (changes to
> optabs.c) separately from a middle-end maintainer.  I cannot approve
> those bits.


Can a global reviewer take a look at the non-target specific changes

http://gcc.gnu.org/ml/gcc-patches/2011-03/msg00191.html


cheers
Ramana

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2011-06-22  0:18                 ` Ramana Radhakrishnan
@ 2011-06-22  8:52                   ` Richard Earnshaw
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Earnshaw @ 2011-06-22  8:52 UTC (permalink / raw)
  To: Ramana Radhakrishnan; +Cc: gcc-patches, Dmitry Plotnikov, Tejas Belagod, dm

On 22/06/11 00:25, Ramana Radhakrishnan wrote:
>>
>> Please get approval for the target independent parts (changes to
>> optabs.c) separately from a middle-end maintainer.  I cannot approve
>> those bits.
> 
> 
> Can a global reviewer take a look at the non-target specific changes
> 
> http://gcc.gnu.org/ml/gcc-patches/2011-03/msg00191.html
> 
> 
> cheers
> Ramana
> 


optabs.c changes are OK.

R.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
  2010-02-11 14:09 Plotnikov Dmitry
@ 2010-03-29 13:24 ` Dmitry Plotnikov
  0 siblings, 0 replies; 13+ messages in thread
From: Dmitry Plotnikov @ 2010-03-29 13:24 UTC (permalink / raw)
  To: gcc-patches; +Cc: dm, rearnsha

Ping

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support
@ 2010-02-11 14:09 Plotnikov Dmitry
  2010-03-29 13:24 ` Dmitry Plotnikov
  0 siblings, 1 reply; 13+ messages in thread
From: Plotnikov Dmitry @ 2010-02-11 14:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: dm, rearnsha

[-- Attachment #1: Type: text/plain, Size: 1118 bytes --]

This patch adds support for immediate shift values for NEON in ARM 
backend.  We have added the new predicates for immediate shift value or 
register operands and have used them in the new patterns. The only tiny 
modification in target-independent part is in optabs.c and it has been 
tested on x86_64 without any regressions.

OK for 4.6?  For trunk?   We think that the changes should be safe for 4.5.

2010-02-10  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): New function.

    * config/arm/neon.md (vashl<mode>3): Modified constraint.
    (vashr<mode>3_imm): New insn pattern.
    (vlshr<mode>3_imm): New insn pattern.
    (vashr<mode>3): Modified constraint.
    (vlshr<mode>3): Modified constraint.

    * config/arm/predicates.md (imm_for_neon_shift_operand): New predicate.
    (imm_shift_or_reg_neon): New predicate.

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

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

[-- Attachment #2: vshr.patch --]
[-- Type: text/x-patch, Size: 8623 bytes --]

diff -rupd gcc-4.5-20100114/gcc/config/arm/arm.c gcc-4.5-20100114/gcc/config/arm/arm.c
--- gcc-4.5-20100114/gcc/config/arm/arm.c	2009-12-24 13:46:00.000000000 +0300
+++ gcc-4.5-20100114/gcc/config/arm/arm.c	2010-02-10 13:59:50.000000000 +0300
@@ -8053,6 +8053,51 @@ neon_immediate_valid_for_logic (rtx op, 
   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. */
+
+int
+neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
+            rtx *modconst, int *elementwidth)
+{
+  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;
+
+  /* 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 */
+  if (last_elt > innersize * 8)
+    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.  */
 
@@ -8075,6 +8120,28 @@ neon_output_logic_immediate (const char 
   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)
+{
+    int width, is_valid;
+    static char templ[40];
+
+    is_valid = neon_immediate_valid_for_shift (*op2, mode, op2, &width);
+
+    gcc_assert (is_valid != 0);
+
+    if (quad)
+      sprintf (templ, "%s.%c%d\t%%q0, %%2", mnem, sign, width);
+    else
+      sprintf (templ, "%s.%c%d\t%%P0, %%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
diff -rupd gcc-4.5-20100114/gcc/config/arm/neon.md gcc-4.5-20100114/gcc/config/arm/neon.md
--- gcc-4.5-20100114/gcc/config/arm/neon.md	2009-11-11 17:23:03.000000000 +0300
+++ gcc-4.5-20100114/gcc/config/arm/neon.md	2010-02-09 19:04:13.000000000 +0300
@@ -1135,11 +1135,53 @@
 ; 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_shift_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", 's', &operands[2],
+                         <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));
+        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_shift_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));
+  }
+
+  [(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_shift_operand" "Dn")))]
+  "TARGET_NEON"
+  {
+    return neon_output_shift_immediate ("vshr", 'u', &operands[2],
+             <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode));
+  }              
+
   [(set (attr "neon_type")
       (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
                     (const_string "neon_vshl_ddd")
@@ -1182,29 +1224,35 @@
 
 (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" "")))]
+  (ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
+           (match_operand:VDQIW 2 "imm_shift_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" "")))]
+  (lshiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
+           (match_operand:VDQIW 2 "imm_shift_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;
 })
 
diff -rupd gcc-4.5-20100114/gcc/config/arm/predicates.md gcc-4.5-20100114/gcc/config/arm/predicates.md
--- gcc-4.5-20100114/gcc/config/arm/predicates.md	2009-07-15 14:12:22.000000000 +0400
+++ gcc-4.5-20100114/gcc/config/arm/predicates.md	2010-02-08 13:08:02.000000000 +0300
@@ -496,6 +496,17 @@
   return neon_immediate_valid_for_move (op, mode, NULL, NULL);
 })
 
+(define_predicate "imm_for_neon_shift_operand"
+  (match_code "const_vector")
+{
+  return neon_immediate_valid_for_shift (op, mode, NULL, NULL);
+})
+
+
+(define_predicate "imm_shift_or_reg_neon"
+    (ior (match_operand 0 "s_register_operand")
+         (match_operand 0 "imm_for_neon_shift_operand")))
+
 (define_predicate "imm_for_neon_logic_operand"
   (match_code "const_vector")
 {
diff -rupd gcc-4.5-20100114/gcc/optabs.c gcc-4.5-20100114/gcc/optabs.c
--- gcc-4.5-20100114/gcc/optabs.c	2009-11-28 19:21:00.000000000 +0300
+++ gcc-4.5-20100114/gcc/optabs.c	2010-02-09 18:01:11.000000000 +0300
@@ -6259,6 +6259,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);
diff -rupd gcc-4.5-20100114/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c gcc-4.5-20100114/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c
--- gcc-4.5-20100114/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c 2009-11-28 19:21:00.000000000 +0300
+++ gcc-4.5-20100114/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c 2010-02-09 18:01:11.000000000 +0300
@@ -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;
+}

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2011-06-22  8:33 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-22 13:29 [PATCH, ARM] VSHL, VSHR, VLSHR immediate values support Dmitry Plotnikov
2010-11-23 18:13 ` Tejas Belagod
2010-11-25 16:33   ` Dmitry Plotnikov
2010-11-26 13:19     ` Tejas Belagod
2010-12-27 15:35       ` Dmitry Plotnikov
2011-02-27 23:58         ` Ramana Radhakrishnan
2011-03-02 14:27           ` Dmitry Plotnikov
2011-03-04 13:15             ` Dmitry Plotnikov
2011-03-20 16:32               ` Ramana Radhakrishnan
2011-06-22  0:18                 ` Ramana Radhakrishnan
2011-06-22  8:52                   ` Richard Earnshaw
  -- strict thread matches above, loose matches on Subject: below --
2010-02-11 14:09 Plotnikov Dmitry
2010-03-29 13:24 ` Dmitry Plotnikov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).