https://gcc.gnu.org/g:26bb981f58efbeccf52d9e8a0b33a6ae1b5c67e4
commit r17-1771-g26bb981f58efbeccf52d9e8a0b33a6ae1b5c67e4 Author: Zhongyao Chen <[email protected]> Date: Tue Sep 2 17:31:00 2025 +0800 RISC-V: Add support for Zvabd extension This patch adds support for the RISC-V Zvabd (Vector Absolute Difference) extension, based on the current draft specification: 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 - vwabda/vwabdau gcc/ChangeLog: * config/riscv/autovec.md: Add auto-vectorization patterns for Zvabd instructions. * config/riscv/autovec-opt.md: Add widening absolute-difference accumulate combine patterns. * 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]> Diff: --- gcc/config/riscv/autovec-opt.md | 43 ++++++++++++ gcc/config/riscv/autovec.md | 62 ++++++++++-------- gcc/config/riscv/riscv-ext.def | 14 ++++ gcc/config/riscv/riscv-ext.opt | 5 ++ gcc/config/riscv/vector-iterators.md | 25 +++++++ gcc/config/riscv/vector.md | 76 ++++++++++++++++++++++ gcc/doc/riscv-ext.texi | 4 ++ .../gcc.target/riscv/rvv/autovec/zvabd-1.c | 61 +++++++++++++++++ 8 files changed, 262 insertions(+), 28 deletions(-) diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md index f44813df3bf2..cc84f6336c51 100644 --- a/gcc/config/riscv/autovec-opt.md +++ b/gcc/config/riscv/autovec-opt.md @@ -684,6 +684,49 @@ } [(set_attr "type" "viwalu")]) +(define_insn_and_split "*vwabda<su><mode>" + [(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_ZVABD && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + rtx ops[] = {operands[0], operands[1], operands[2]}; + riscv_vector::emit_vlmax_insn (CODE_FOR_pred_widen_abd_plus<su><mode>, + riscv_vector::BINARY_OP, ops); + DONE; +} +[(set_attr "type" "viwalu")]) + +;; have this since we don't canonicalize the plus in the presence of an unspec. +(define_insn_and_split "*vwabda_right<su><mode>" + [(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_ZVABD && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + rtx ops[] = {operands[0], operands[2], operands[3]}; + riscv_vector::emit_vlmax_insn (CODE_FOR_pred_widen_abd_plus<su><mode>, + riscv_vector::BINARY_OP, ops); + DONE; +} +[(set_attr "type" "viwalu")]) + ;; This combine pattern does not correspond to a single instruction, ;; i.e. there is no vwmul.wv instruction. This is a temporary pattern ;; produced by a combine pass and if there is no further combine into diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md index c6b823d04a27..31584f4918c4 100644 --- a/gcc/config/riscv/autovec.md +++ b/gcc/config/riscv/autovec.md @@ -1115,17 +1115,30 @@ [(set_attr "type" "vialu")]) ;; ------------------------------------------------------------------------------- -;; - [INT] ABS expansion to vneg and vmax. +;; - [INT] ABS expansion ;; ------------------------------------------------------------------------------- (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; }) @@ -3066,26 +3079,19 @@ ; ======== ; == 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); - - DONE; - }); +(define_insn_and_split "<su>abd<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_ZVABD && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + riscv_vector::emit_vlmax_insn (CODE_FOR_pred_vabd<su><mode>, + riscv_vector::BINARY_OP, operands); + DONE; +} +[(set_attr "type" "vialu")]) diff --git a/gcc/config/riscv/riscv-ext.def b/gcc/config/riscv/riscv-ext.def index b9ef0c5ea057..25f7f29d470e 100644 --- a/gcc/config/riscv/riscv-ext.def +++ b/gcc/config/riscv/riscv-ext.def @@ -1585,6 +1585,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, 7}}), + /* 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, @@ -2108,6 +2121,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 802c9eb41706..875a8626a648 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) @@ -330,6 +333,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) diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md index 62a1eb3fbc04..3de384093428 100644 --- a/gcc/config/riscv/vector-iterators.md +++ b/gcc/config/riscv/vector-iterators.md @@ -122,6 +122,13 @@ UNSPEC_SF_VFNRCLIP UNSPEC_SF_VFNRCLIPU UNSPEC_SF_CV + + ;; abd + UNSPEC_VSABD + UNSPEC_VUABD + ;; abda + UNSPEC_VSABDA + UNSPEC_VUABDA ]) (define_c_enum "unspecv" [ @@ -6520,3 +6527,21 @@ (V32DI "V32HI") (V64DI "V64HI") (V128DI "V128HI") (V256DI "V256HI") (V512DI "V512HI") ]) + +(define_int_iterator UNSPEC_VABD[ + UNSPEC_VSABD UNSPEC_VUABD +]) + +(define_int_iterator UNSPEC_VABDA[ + UNSPEC_VSABDA UNSPEC_VUABDA +]) + +(define_int_attr su[ + (UNSPEC_VSABD "s") (UNSPEC_VUABD "u") + (UNSPEC_VSABDA "s") (UNSPEC_VUABDA "u") +]) + +(define_int_attr u[ + (UNSPEC_VSABD "") (UNSPEC_VUABD "u") + (UNSPEC_VSABDA "") (UNSPEC_VUABDA "u") +]) diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md index 4f523f7c7229..00e64a854552 100644 --- a/gcc/config/riscv/vector.md +++ b/gcc/config/riscv/vector.md @@ -9230,6 +9230,82 @@ 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 +;; - vwabda/vwabdau: 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_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_ZVABD" + "vabd<u>.vv\t%0,%3,%4%p1" + [(set_attr "type" "vialu") + (set_attr "mode" "<MODE>")]) + +(define_insn "@pred_widen_abd_plus<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_VABDA) + (match_operand:VWEXTI 2 "vector_merge_operand" "vu,0,vu,0")))] + "TARGET_ZVABD" + "vwabda<u>.vv\t%0,%3,%4%p1" + [(set_attr "type" "viwalu") + (set_attr "mode" "<V_DOUBLE_TRUNC>")]) + (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 728cde737a7c..43c836fa77bd 100644 --- a/gcc/doc/riscv-ext.texi +++ b/gcc/doc/riscv-ext.texi @@ -466,6 +466,10 @@ @tab 1.0 @tab Minimal half-precision floating-point in integer registers extension +@item @samp{zvabd} +@tab 0.7 +@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 000000000000..466522705b52 --- /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_VWABDA(TYPE1, TYPE2) \ + __attribute__((noipa)) void \ + vwabda_##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_VWABDA (int16_t, int8_t) \ + TEST_VWABDA (uint16_t, uint8_t) \ + TEST_VWABDA (int32_t, int16_t) \ + TEST_VWABDA (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 {\tvwabda\.vv} 2 } } */ +/* { dg-final { scan-assembler-times {\tvwabdau\.vv} 2 } } */
