This patch adds support for the RISC-V Zvabd (Vector Absolute Difference)
extension, based on Zvabd Draft Spec.
https://github.com/riscv/integer-vector-absolute-difference/pull/1

Zvabd is now in the 'Specification in Freeze' state.
https://riscv.atlassian.net/browse/RVS-3896

It adds patterns for:
- vabs
- vabd/vabdu
- vwabdacc/vwabdaccu

Note:
- The abd expand condition remains gated because PR119224 is still open.
- check_GNU_style.sh false positive on riscv-ext.opt,

gcc/ChangeLog:

        * config/riscv/autovec.md: Add auto-vectorization patterns for Zvabd 
instructions.
        * config/riscv/riscv-ext.def: Add Zvabd extension entry.
        * config/riscv/riscv-ext.opt: Add Zvabd option.
        * config/riscv/vector-iterators.md: Update for Zvabd.
        * config/riscv/vector.md: Add Zvabd patterns.
        * doc/riscv-ext.texi: Document zvabd extension.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/rvv/autovec/zvabd-1.c: New tests for Zvabd.

Co-authored-by: Yuke Tang <[email protected]>
Signed-off-by: Zhongyao Chen <[email protected]>
---
 gcc/config/riscv/autovec.md                   | 129 ++++++++++++++----
 gcc/config/riscv/riscv-ext.def                |  14 ++
 gcc/config/riscv/riscv-ext.opt                |   6 +-
 gcc/config/riscv/vector-iterators.md          |  33 +++++
 gcc/config/riscv/vector.md                    |  84 ++++++++++++
 gcc/doc/riscv-ext.texi                        |   4 +
 .../gcc.target/riscv/rvv/autovec/zvabd-1.c    |  61 +++++++++
 7 files changed, 304 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/zvabd-1.c

diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index fc5a31c9396..3cdf03fd9b5 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -1120,12 +1120,25 @@
 
 (define_expand "abs<mode>2"
   [(set (match_operand:V_VLSI 0 "register_operand")
-    (smax:V_VLSI
-     (match_dup 0)
-     (neg:V_VLSI
-       (match_operand:V_VLSI 1 "register_operand"))))]
+       (abs:V_VLSI
+         (match_operand:V_VLSI 1 "register_operand")))]
   "TARGET_VECTOR"
 {
+  if (TARGET_ZVABD)
+    {
+      riscv_vector::emit_vlmax_insn (CODE_FOR_pred_abs<mode>,
+                                    riscv_vector::UNARY_OP, operands);
+      DONE;
+    }
+
+  rtx neg = gen_reg_rtx (<MODE>mode);
+  rtx ops1[] = {neg, operands[1]};
+  riscv_vector::emit_vlmax_insn (CODE_FOR_pred_neg<mode>,
+                                riscv_vector::UNARY_OP, ops1);
+
+  rtx ops2[] = {operands[0], operands[1], neg};
+  riscv_vector::emit_vlmax_insn (CODE_FOR_pred_smax<mode>,
+                                riscv_vector::BINARY_OP, ops2);
   DONE;
 })
 
@@ -3143,26 +3156,90 @@
 ; ========
 ; == Absolute difference (not including sum)
 ; ========
-(define_expand "uabd<mode>3"
-  [(match_operand:V_VLSI 0 "register_operand")
-   (match_operand:V_VLSI 1 "register_operand")
-   (match_operand:V_VLSI 2 "register_operand")]
-  ;; Disabled until PR119224 is resolved
-  "TARGET_VECTOR && 0"
-  {
-    rtx max = gen_reg_rtx (<MODE>mode);
-    insn_code icode = code_for_pred (UMAX, <MODE>mode);
-    rtx ops1[] = {max, operands[1], operands[2]};
-    riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops1);
-
-    rtx min = gen_reg_rtx (<MODE>mode);
-    icode = code_for_pred (UMIN, <MODE>mode);
-    rtx ops2[] = {min, operands[1], operands[2]};
-    riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops2);
-
-    icode = code_for_pred (MINUS, <MODE>mode);
-    rtx ops3[] = {operands[0], max, min};
-    riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops3);
+(define_expand "<su>abd<mode>3"
+  [(set (match_operand:V_VLSI 0 "register_operand")
+       (unspec:V_VLSI
+         [(match_operand:V_VLSI 1 "register_operand")
+          (match_operand:V_VLSI 2 "register_operand")]
+         UNSPEC_VABD))]
+;; Disabled when zvabd not enabled until PR119224 is resolved.
+  "TARGET_VECTOR && TARGET_ZVABD")
+
+(define_insn_and_split "*abd<su><mode>3"
+  [(set (match_operand:V_VLSI 0 "register_operand" "=vr")
+       (unspec:V_VLSI
+         [(match_operand:V_VLSI 1 "register_operand" "vr")
+          (match_operand:V_VLSI 2 "register_operand" "vr")]
+         UNSPEC_VABD))]
+  "TARGET_VECTOR && (TARGET_ZVABD || can_create_pseudo_p ())"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  if (TARGET_ZVABD)
+    riscv_vector::emit_vlmax_insn (CODE_FOR_pred_vabd<su><mode>,
+                                 riscv_vector::BINARY_OP, operands);
+  else
+    {
+      rtx max = gen_reg_rtx (<MODE>mode);
+      insn_code icode = code_for_pred (<ABD_MAX>, <MODE>mode);
+      rtx ops1[] = {max, operands[1], operands[2]};
+      riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops1);
+
+      rtx min = gen_reg_rtx (<MODE>mode);
+      icode = code_for_pred (<ABD_MIN>, <MODE>mode);
+      rtx ops2[] = {min, operands[1], operands[2]};
+      riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops2);
+
+      icode = code_for_pred (MINUS, <MODE>mode);
+      rtx ops3[] = {operands[0], max, min};
+      riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops3);
+    }
+  DONE;
+}
+[(set_attr "type" "vialu")])
 
-    DONE;
-  });
+; ========
+; == Widening absolute difference and accumulate
+; ========
+(define_insn_and_split "*vwabdacc<su><mode>4"
+  [(set (match_operand:VWEXTI 0 "register_operand" "+&vr")
+       (plus:VWEXTI
+         (zero_extend:VWEXTI
+           (unspec:<V_DOUBLE_TRUNC>
+             [(match_operand:<V_DOUBLE_TRUNC> 1 "register_operand" "vr")
+              (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand" "vr")]
+             UNSPEC_VABD))
+         (match_operand:VWEXTI 3 "register_operand" "0")))]
+  "TARGET_VECTOR && TARGET_ZVABD"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  rtx ops[] = {operands[0], operands[1], operands[2]};
+  riscv_vector::emit_vlmax_insn (CODE_FOR_pred_vwabdacc<su><mode>,
+                               riscv_vector::BINARY_OP, ops);
+  DONE;
+}
+[(set_attr "type" "viwalu")])
+
+(define_insn_and_split "*vwabdacc_right<su><mode>4"
+  [(set (match_operand:VWEXTI 0 "register_operand" "+&vr")
+       (plus:VWEXTI
+         (match_operand:VWEXTI 1 "register_operand" "0")
+         (zero_extend:VWEXTI
+           (unspec:<V_DOUBLE_TRUNC>
+             [(match_operand:<V_DOUBLE_TRUNC> 2 "register_operand" "vr")
+              (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand" "vr")]
+             UNSPEC_VABD))))]
+  "TARGET_VECTOR && TARGET_ZVABD"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  rtx ops[] = {operands[0], operands[2], operands[3]};
+  riscv_vector::emit_vlmax_insn (CODE_FOR_pred_vwabdacc<su><mode>,
+                               riscv_vector::BINARY_OP, ops);
+  DONE;
+}
+[(set_attr "type" "viwalu")])
diff --git a/gcc/config/riscv/riscv-ext.def b/gcc/config/riscv/riscv-ext.def
index 1993e899148..f963f06d0a1 100644
--- a/gcc/config/riscv/riscv-ext.def
+++ b/gcc/config/riscv/riscv-ext.def
@@ -1572,6 +1572,19 @@ DEFINE_RISCV_EXT(
   /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
   /* EXTRA_EXTENSION_FLAGS */ 0)
 
+DEFINE_RISCV_EXT (
+  /* NAME.  */ zvabd,
+  /* UPPERCASE_NAME.  */ ZVABD,
+  /* FULL_NAME.  */ "Vector absolute difference extension.",
+  /* DESC.  */ "",
+  /* URL.  */ ,
+  /* DEP_EXTS.  */ ({"v"}),
+  /* SUPPORTED_VERSIONS.  */ ({{0, 5}}),
+  /* FLAG_GROUP.  */ zvabd,
+  /* BITMASK_GROUP_ID.  */ BITMASK_NOT_YET_ALLOCATED,
+  /* BITMASK_BIT_POSITION.  */ BITMASK_NOT_YET_ALLOCATED,
+  /* EXTRA_EXTENSION_FLAGS.  */ 0)
+
 DEFINE_RISCV_EXT(
   /* NAME */ sdtrig,
   /* UPPERCASE_NAME */ SDTRIG,
@@ -2095,6 +2108,7 @@ DEFINE_RISCV_EXT(
   /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
   /* EXTRA_EXTENSION_FLAGS */ 0)
 
+
 #include "riscv-ext-corev.def"
 #include "riscv-ext-sifive.def"
 #include "riscv-ext-thead.def"
diff --git a/gcc/config/riscv/riscv-ext.opt b/gcc/config/riscv/riscv-ext.opt
index 7bf3d4effc6..00c0953192d 100644
--- a/gcc/config/riscv/riscv-ext.opt
+++ b/gcc/config/riscv/riscv-ext.opt
@@ -106,6 +106,9 @@ int riscv_zvk_subext
 TargetVariable
 int riscv_zvl_subext
 
+TargetVariable
+int riscv_zvabd_subext
+
 Mask(RVE) Var(riscv_base_subext)
 
 Mask(RVI) Var(riscv_base_subext)
@@ -328,6 +331,8 @@ Mask(ZHINX) Var(riscv_zinx_subext)
 
 Mask(ZHINXMIN) Var(riscv_zinx_subext)
 
+Mask(ZVABD) Var(riscv_zvabd_subext)
+
 Mask(SDTRIG) Var(riscv_sd_subext)
 
 Mask(SHA) Var(riscv_sh_subext)
@@ -473,4 +478,3 @@ Mask(XANDESVPACKFPH) Var(riscv_xandes_subext)
 Mask(XANDESVDOT) Var(riscv_xandes_subext)
 
 Mask(XSMTVDOT) Var(riscv_xsmt_subext)
-
diff --git a/gcc/config/riscv/vector-iterators.md 
b/gcc/config/riscv/vector-iterators.md
index b2383de8549..ceebe35f798 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -126,6 +126,13 @@
   ;; Vector conditional branch optabs
   UNSPEC_COND_LEN_CMP_ALL
   UNSPEC_COND_LEN_CMP_ANY
+
+  ;; abd
+  UNSPEC_VSABD
+  UNSPEC_VUABD
+  ;; abdacc
+  UNSPEC_VSABDACC
+  UNSPEC_VUABDACC
 ])
 
 (define_c_enum "unspecv" [
@@ -6538,3 +6545,29 @@
   (UNSPEC_COND_LEN_CMP_ALL "cond_len_vec_cbranch_all")
   (UNSPEC_COND_LEN_CMP_ANY "cond_len_vec_cbranch_any")
 ])
+
+(define_int_iterator UNSPEC_VABD[
+  UNSPEC_VSABD UNSPEC_VUABD
+])
+
+(define_int_iterator UNSPEC_VABDACC[
+  UNSPEC_VSABDACC UNSPEC_VUABDACC
+])
+
+(define_int_attr su[
+  (UNSPEC_VSABD "s") (UNSPEC_VUABD "u")
+  (UNSPEC_VSABDACC "s") (UNSPEC_VUABDACC "u")
+])
+
+(define_int_attr u[
+  (UNSPEC_VSABD "") (UNSPEC_VUABD "u")
+  (UNSPEC_VSABDACC "") (UNSPEC_VUABDACC "u")
+])
+
+(define_int_attr ABD_MAX[
+  (UNSPEC_VSABD "SMAX") (UNSPEC_VUABD "UMAX")
+])
+
+(define_int_attr ABD_MIN[
+  (UNSPEC_VSABD "SMIN") (UNSPEC_VUABD "UMIN")
+])
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 136ecdc787e..086ed87210d 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -9200,6 +9200,90 @@
     riscv_vector::prepare_ternary_operands (operands);
   })
 
+;; ------------------------------------
+;; ---- Vector absolute difference extension
+;; ----------------------------------------------------------------
+;; Includes:
+;; - vabs: Vector Single-Width Signed Integer Absolute
+;; - vabd/vabdu: Vector Single-Width Signed Integer Absolute Difference
+;; - vwabdacc/vwabdaccu: Vector Widening Signed Integer Absolute
+;;   Difference and Accumulate
+;; ------------------------------------
+
+(define_insn "@pred_abs<mode>"
+  [(set (match_operand:V_VLSI 0 "register_operand"      "=vd, vd, vr, vr")
+       (if_then_else:V_VLSI
+         (unspec:<VM>
+           [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm, Wc1, Wc1")
+            (match_operand 4 "vector_length_operand"    " rK, rK, rK, rK")
+            (match_operand 5 "const_int_operand"        " i, i, i, i")
+            (match_operand 6 "const_int_operand"        " i, i, i, i")
+            (match_operand 7 "const_int_operand"        " i, i, i, i")
+            (reg:SI VL_REGNUM)
+            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+         (abs:V_VLSI
+           (match_operand:V_VLSI 3 "register_operand"    " vr, vr, vr, vr"))
+         (match_operand:V_VLSI 2 "vector_merge_operand"  "vu, 0, vu, 0")))]
+  "TARGET_VECTOR && TARGET_ZVABD"
+  "vabs.v\t%0,%3%p1"
+  [(set_attr "type" "vialu")
+   (set_attr "mode" "<MODE>")
+   (set_attr "vl_op_idx" "4")
+   (set (attr "ta") (symbol_ref "riscv_vector::get_ta (operands[5])"))
+   (set (attr "ma") (symbol_ref "riscv_vector::get_ma (operands[6])"))
+   (set (attr "avl_type_idx") (const_int 7))])
+
+(define_insn "@pred_vabd<su><mode>"
+  [(set (match_operand:V_VLSI 0 "register_operand"         "=vd, vd, vr, vr")
+       (if_then_else:V_VLSI
+         (unspec:<VM>
+           [(match_operand:<VM> 1 "vector_mask_operand" " vm, vm, Wc1, Wc1")
+            (match_operand 5 "vector_length_operand"    " rK, rK, rK, rK")
+            (match_operand 6 "const_int_operand"        " i, i, i, i")
+            (match_operand 7 "const_int_operand"        " i, i, i, i")
+            (match_operand 8 "const_int_operand"        " i, i, i, i")
+            (reg:SI VL_REGNUM)
+            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+         (unspec:V_VLSI
+           [(match_operand:V_VLSI 3 "register_operand"      "vr,vr,vr,vr")
+            (match_operand:V_VLSI 4 "register_operand"    "vr,vr,vr,vr")]
+           UNSPEC_VABD)
+         (match_operand:V_VLSI 2 "vector_merge_operand"     "vu, 0, vu, 0")))]
+  "TARGET_VECTOR && TARGET_ZVABD"
+  "vabd<u>.vv\t%0,%3,%4%p1"
+  [(set_attr "type" "vialu")
+   (set_attr "mode" "<MODE>")
+   (set_attr "vl_op_idx" "5")
+   (set (attr "ta") (symbol_ref "riscv_vector::get_ta (operands[6])"))
+   (set (attr "ma") (symbol_ref "riscv_vector::get_ma (operands[7])"))
+   (set (attr "avl_type_idx") (const_int 8))])
+
+(define_insn "@pred_vwabdacc<su><mode>"
+  [(set (match_operand:VWEXTI 0 "register_operand"      "+&vd,&vd,&vr,&vr")
+       (if_then_else:VWEXTI
+         (unspec:<VM>
+           [(match_operand:<VM> 1 "vector_mask_operand" "vm,vm,Wc1,Wc1")
+            (match_operand 5 "vector_length_operand"    "rK,rK,rK,rK")
+            (match_operand 6 "const_int_operand"      "i,i,i,i")
+            (match_operand 7 "const_int_operand"      "i,i,i,i")
+            (match_operand 8 "const_int_operand"      "i,i,i,i")
+            (reg:SI VL_REGNUM)
+            (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+         (unspec:VWEXTI
+           [(match_operand:<V_DOUBLE_TRUNC> 3 "register_operand" "vr,vr,vr,vr")
+            (match_operand:<V_DOUBLE_TRUNC> 4 "register_operand" "vr,vr,vr,vr")
+            (match_dup 0)]
+           UNSPEC_VABDACC)
+         (match_operand:VWEXTI 2 "vector_merge_operand" "vu,0,vu,0")))]
+  "TARGET_VECTOR && TARGET_ZVABD"
+  "vwabdacc<u>.vv\t%0,%3,%4%p1"
+  [(set_attr "type" "viwalu")
+   (set_attr "mode" "<V_DOUBLE_TRUNC>")
+   (set_attr "vl_op_idx" "5")
+   (set (attr "ta") (symbol_ref "riscv_vector::get_ta (operands[6])"))
+   (set (attr "ma") (symbol_ref "riscv_vector::get_ma (operands[7])"))
+   (set (attr "avl_type_idx") (const_int 8))])
+
 (include "autovec.md")
 (include "autovec-opt.md")
 (include "sifive-vector.md")
diff --git a/gcc/doc/riscv-ext.texi b/gcc/doc/riscv-ext.texi
index bf4f56a6201..92b9514efa9 100644
--- a/gcc/doc/riscv-ext.texi
+++ b/gcc/doc/riscv-ext.texi
@@ -462,6 +462,10 @@
 @tab 1.0
 @tab Minimal half-precision floating-point in integer registers extension
 
+@item @samp{zvabd}
+@tab 0.5
+@tab Vector absolute difference extension
+
 @item @samp{sdtrig}
 @tab 1.0
 @tab Debug triggers extension
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zvabd-1.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zvabd-1.c
new file mode 100644
index 00000000000..d28f18f294e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zvabd-1.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv_zvabd -mabi=lp64d 
-fno-vect-cost-model" } */
+
+#include <stdint-gcc.h>
+
+static int
+abs (int i)
+{
+  return i < 0 ? -i : i;
+}
+
+#define TEST_VABS(TYPE1, TYPE2)                                            \
+  __attribute__((noipa)) void vabs_##TYPE1_##TYPE2 (TYPE1 *__restrict dst, \
+                                                   TYPE2 *__restrict a,   \
+                                                   int n)                 \
+  {                                                                        \
+    int i;                                                                 \
+    for (i = 0; i < n; i++)                                                \
+      dst[i] = abs (a[i]);                                                 \
+  }
+
+#define TEST_VABD(TYPE1, TYPE2)                                            \
+  __attribute__((noipa)) void vabd_##TYPE1_##TYPE2 (TYPE1 *__restrict dst, \
+                                                   TYPE2 *__restrict a,   \
+                                                   TYPE2 *__restrict b,   \
+                                                   int n)                 \
+  {                                                                        \
+    int i;                                                                 \
+    for (i = 0; i < n; i++)                                                \
+      dst[i] = abs (a[i] - b[i]);                                          \
+  }
+
+#define TEST_VWABDACC(TYPE1, TYPE2)                                      \
+  __attribute__((noipa)) void                                             \
+  vwabdacc_##TYPE1_##TYPE2 (TYPE1 *__restrict dst, TYPE2 *__restrict a,  \
+                           TYPE2 *__restrict b, int n)                  \
+  {                                                                      \
+    int i;                                                               \
+    for (i = 0; i < n; i++)                                              \
+      dst[i] += abs (a[i] - b[i]);                                       \
+  }
+
+#define TEST_ALL()                 \
+  TEST_VABS (int8_t, int8_t)       \
+  TEST_VABS (int16_t, int16_t)     \
+  TEST_VABD (int8_t, int8_t)       \
+  TEST_VABD (uint8_t, uint8_t)     \
+  TEST_VABD (int16_t, int16_t)     \
+  TEST_VABD (uint16_t, uint16_t)   \
+  TEST_VWABDACC (int16_t, int8_t)  \
+  TEST_VWABDACC (uint16_t, uint8_t)\
+  TEST_VWABDACC (int32_t, int16_t) \
+  TEST_VWABDACC (uint32_t, uint16_t)
+
+TEST_ALL()
+
+/* { dg-final { scan-assembler-times {\tvabs\.v} 2 } } */
+/* { dg-final { scan-assembler-times {\tvabd\.vv} 2 } } */
+/* { dg-final { scan-assembler-times {\tvabdu\.vv} 2 } } */
+/* { dg-final { scan-assembler-times {\tvwabdacc\.vv} 2 } } */
+/* { dg-final { scan-assembler-times {\tvwabdaccu\.vv} 2 } } */
-- 
2.43.0


Reply via email to