This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH, ARM] VSHL, VSHR, VLSHR immediate values support


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.
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;
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]