From: Robin Dapp Date: Tue, 20 Jun 2023 11:07:23 +0000 (+0200) Subject: RISC-V: Add autovec FP widening/narrowing. X-Git-Tag: basepoints/gcc-15~8000 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a9b40612baf2f936ac1d211fbc0b3e46404cefa7;p=thirdparty%2Fgcc.git RISC-V: Add autovec FP widening/narrowing. This patch adds FP widening and narrowing expanders as well as tests. Conceptually similar to integer extension/truncation, we emulate _Float16 -> double by two vfwcvts and double -> _Float16 by two vfncvts. gcc/ChangeLog: * config/riscv/autovec.md (extend2): New expander. (extend2): Ditto. (trunc2): Ditto. (trunc2): Ditto. * config/riscv/vector-iterators.md: Add VQEXTF and HF to V_QUAD_TRUNC and v_quad_trunc. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/conversions/vfncvt-run.c: New test. * gcc.target/riscv/rvv/autovec/conversions/vfncvt-rv32gcv.c: New test. * gcc.target/riscv/rvv/autovec/conversions/vfncvt-rv64gcv.c: New test. * gcc.target/riscv/rvv/autovec/conversions/vfncvt-template.h: New test. * gcc.target/riscv/rvv/autovec/conversions/vfncvt-zvfh-run.c: New test. * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-run.c: New test. * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-rv32gcv.c: New test. * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-rv64gcv.c: New test. * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-template.h: New test. * gcc.target/riscv/rvv/autovec/conversions/vfwcvt-zvfh-run.c: New test. --- diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md index b0e5950fb561..a7c8056a7743 100644 --- a/gcc/config/riscv/autovec.md +++ b/gcc/config/riscv/autovec.md @@ -162,12 +162,12 @@ riscv_vector::emit_vlmax_insn (code_for_pred_scalar (, mode), riscv_vector::RVV_BINOP, operands); DONE; -} +} [(set_attr "type" "vshift") (set_attr "mode" "")]) ;; ------------------------------------------------------------------------- -;; ---- [INT] Binary shifts by scalar. +;; ---- [INT] Binary shifts by vector. ;; ------------------------------------------------------------------------- ;; Includes: ;; - vsll.vv/vsra.vv/vsrl.vv @@ -428,6 +428,90 @@ DONE; }) +;; ------------------------------------------------------------------------- +;; ---- [FP] Widening. +;; ------------------------------------------------------------------------- +;; - vfwcvt.f.f.v +;; ------------------------------------------------------------------------- +(define_insn_and_split "extend2" + [(set (match_operand:VWEXTF_ZVFHMIN 0 "register_operand" "=&vr") + (float_extend:VWEXTF_ZVFHMIN + (match_operand: 1 "register_operand" " vr")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_extend (mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands); + DONE; +} + [(set_attr "type" "vfwcvtftof") + (set_attr "mode" "")]) + +(define_expand "extend2" + [(set (match_operand:VQEXTF 0 "register_operand") + (float_extend:VQEXTF + (match_operand: 1 "register_operand")))] + "TARGET_VECTOR && (TARGET_ZVFHMIN || TARGET_ZVFH)" +{ + rtx dblw = gen_reg_rtx (mode); + insn_code icode = code_for_pred_extend (mode); + rtx ops1[] = {dblw, operands[1]}; + riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops1); + + icode = code_for_pred_extend (mode); + rtx ops2[] = {operands[0], dblw}; + riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops2); + DONE; +}) + +;; ------------------------------------------------------------------------- +;; ---- [FP] Narrowing. +;; ------------------------------------------------------------------------- +;; - vfncvt.f.f.w +;; ------------------------------------------------------------------------- +(define_insn_and_split "trunc2" + [(set (match_operand: 0 "register_operand" "=vr") + (truncate: + (match_operand:VWEXTF_ZVFHMIN 1 "register_operand" " vr")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_trunc (mode); + riscv_vector::emit_vlmax_fp_insn (icode, riscv_vector::RVV_UNOP, operands); + DONE; +} + [(set_attr "type" "vfncvtftof") + (set_attr "mode" "")]) + +;; ------------------------------------------------------------------------- +;; Narrowing to a mode whose inner mode size is a quarter of mode's. +;; We emulate this with two consecutive vfncvts. +;; ------------------------------------------------------------------------- +(define_expand "trunc2" + [(set (match_operand: 0 "register_operand") + (truncate: + (match_operand:VQEXTF 1 "register_operand")))] + "TARGET_VECTOR && (TARGET_ZVFHMIN || TARGET_ZVFH)" +{ + rtx half = gen_reg_rtx (mode); + rtx opshalf[] = {half, operands[1]}; + + /* According to the RISC-V V Spec 13.19. we need to use + vfncvt.rod.f.f.w for all steps but the last. */ + insn_code icode = code_for_pred_rod_trunc (mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, opshalf); + + rtx ops[] = {operands[0], half}; + icode = code_for_pred_trunc (mode); + riscv_vector::emit_vlmax_fp_insn (icode, riscv_vector::RVV_UNOP, ops); + DONE; +}) + + ;; ========================================================================= ;; == Conversions ;; ========================================================================= diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md index 7893aa66a2b0..8134bc0ddd6f 100644 --- a/gcc/config/riscv/vector-iterators.md +++ b/gcc/config/riscv/vector-iterators.md @@ -547,6 +547,14 @@ (VNx16DI "TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN >= 128") ]) +(define_mode_iterator VQEXTF [ + (VNx1DF "TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN < 128") + (VNx2DF "TARGET_VECTOR_ELEN_FP_64") + (VNx4DF "TARGET_VECTOR_ELEN_FP_64") + (VNx8DF "TARGET_VECTOR_ELEN_FP_64") + (VNx16DF "TARGET_VECTOR_ELEN_FP_64 && TARGET_MIN_VLEN >= 128") +]) + (define_mode_iterator VOEXTI [ (VNx1DI "TARGET_VECTOR_ELEN_64 && TARGET_MIN_VLEN < 128") (VNx2DI "TARGET_VECTOR_ELEN_64") (VNx4DI "TARGET_VECTOR_ELEN_64") (VNx8DI "TARGET_VECTOR_ELEN_64") @@ -1305,6 +1313,9 @@ (VNx16SI "VNx16QI") (VNx32SI "VNx32QI") (VNx1DI "VNx1HI") (VNx2DI "VNx2HI") (VNx4DI "VNx4HI") (VNx8DI "VNx8HI") (VNx16DI "VNx16HI") + + (VNx1DF "VNx1HF") (VNx2DF "VNx2HF") (VNx4DF "VNx4HF") (VNx8DF "VNx8HF") + (VNx16DF "VNx16HF") ]) (define_mode_attr V_OCT_TRUNC [ @@ -1330,6 +1341,9 @@ (VNx16SI "vnx16qi") (VNx32SI "vnx32qi") (VNx1DI "vnx1hi") (VNx2DI "vnx2hi") (VNx4DI "vnx4hi") (VNx8DI "vnx8hi") (VNx16DI "vnx16hi") + + (VNx1DF "vnx1hf") (VNx2DF "vnx2hf") (VNx4DF "vnx4hf") (VNx8DF "vnx8hf") + (VNx16DF "vnx16hf") ]) (define_mode_attr v_oct_trunc [ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-run.c new file mode 100644 index 000000000000..65d2826c8a1c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-run.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */ + +#include "vfncvt-template.h" + +#include + +#define SZ 512 +#define EPS 1e-4 + +#define RUN(TYPE1,TYPE2) \ + TYPE1 src##TYPE1##TYPE2[SZ]; \ + TYPE2 dst##TYPE1##TYPE2[SZ]; \ + for (int i = 0; i < SZ; i++) \ + { \ + src##TYPE1##TYPE2[i] = (i & 1) ? -i : i; \ + src##TYPE1##TYPE2[i] *= 3.141592; \ + dst##TYPE1##TYPE2[i] = -1; \ + } \ + vfncvt_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \ + src##TYPE1##TYPE2, SZ); \ + for (int i = 0; i < SZ; i++) \ + assert (__builtin_fabs (dst##TYPE1##TYPE2[i] \ + - ((i & 1) ? -i : i) * 3.141592) < EPS); \ + + +#define RUN_ALL() \ + RUN(double, float) \ + +int main () +{ + RUN_ALL() +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-rv32gcv.c new file mode 100644 index 000000000000..10fe75d27541 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-rv32gcv.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */ + +#include "vfncvt-template.h" + +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.f\.w} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rod\.f\.f\.w} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-rv64gcv.c new file mode 100644 index 000000000000..fd40fa242e4f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-rv64gcv.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */ + +#include "vfncvt-template.h" + +/* { dg-final { scan-assembler-times {\tvfncvt\.f\.f\.w} 3 } } */ +/* { dg-final { scan-assembler-times {\tvfncvt\.rod\.f\.f\.w} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-template.h new file mode 100644 index 000000000000..221e8838d36a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-template.h @@ -0,0 +1,16 @@ +#include + +#define TEST(TYPE1, TYPE2) \ + __attribute__((noipa)) \ + void vfncvt_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n) \ + { \ + for (int i = 0; i < n; i++) \ + dst[i] = (TYPE2)a[i]; \ + } + +#define TEST_ALL() \ + TEST(float, _Float16) \ + TEST(double, _Float16) \ + TEST(double, float) \ + +TEST_ALL() diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-zvfh-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-zvfh-run.c new file mode 100644 index 000000000000..38e0d84b4e21 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfncvt-zvfh-run.c @@ -0,0 +1,34 @@ +/* { dg-do run { target { riscv_vector && riscv_zvfh_hw } } } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +#include "vfncvt-template.h" + +#include + +#define SZ 512 +#define EPS 1e-4 + +#define RUN(TYPE1,TYPE2) \ + TYPE1 src##TYPE1##TYPE2[SZ]; \ + TYPE2 dst##TYPE1##TYPE2[SZ]; \ + for (int i = 0; i < SZ; i++) \ + { \ + src##TYPE1##TYPE2[i] = (i & 1) ? -i : i; \ + src##TYPE1##TYPE2[i] *= 0.0003141592; \ + dst##TYPE1##TYPE2[i] = -1; \ + } \ + vfncvt_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \ + src##TYPE1##TYPE2, SZ); \ + for (int i = 0; i < SZ; i++) \ + assert (__builtin_fabs (dst##TYPE1##TYPE2[i] \ + - ((i & 1) ? -i : i) * 0.0003141592) < EPS); \ + + +#define RUN_ALL() \ + RUN(float, _Float16) \ + RUN(double, _Float16) \ + +int main () +{ + RUN_ALL() +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-run.c new file mode 100644 index 000000000000..9594909c4eed --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-run.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */ + +#include "vfwcvt-template.h" + +#include + +#define SZ 512 +#define EPS 1e-4 + +#define RUN(TYPE1,TYPE2) \ + TYPE1 src##TYPE1##TYPE2[SZ]; \ + TYPE2 dst##TYPE1##TYPE2[SZ]; \ + for (int i = 0; i < SZ; i++) \ + { \ + src##TYPE1##TYPE2[i] = (i & 1) ? -i : i; \ + src##TYPE1##TYPE2[i] *= 3.141592; \ + dst##TYPE1##TYPE2[i] = -1; \ + } \ + vfwcvt_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \ + src##TYPE1##TYPE2, SZ); \ + for (int i = 0; i < SZ; i++) \ + assert (__builtin_fabs (dst##TYPE1##TYPE2[i] \ + - ((i & 1) ? -i : i) * 3.141592) < EPS); \ + + +#define RUN_ALL() \ + RUN(float, double) \ + +int main () +{ + RUN_ALL() +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-rv32gcv.c new file mode 100644 index 000000000000..006bdb24c41a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-rv32gcv.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv_zvfh -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */ + +#include "vfwcvt-template.h" + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-rv64gcv.c new file mode 100644 index 000000000000..7ec710702c9b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-rv64gcv.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv_zvfh -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */ + +#include "vfwcvt-template.h" + +/* { dg-final { scan-assembler-times {\tvfwcvt\.f\.f\.v} 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-template.h new file mode 100644 index 000000000000..b6ccf3ba2f53 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-template.h @@ -0,0 +1,16 @@ +#include + +#define TEST(TYPE1, TYPE2) \ + __attribute__((noipa)) \ + void vfwcvt_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n) \ + { \ + for (int i = 0; i < n; i++) \ + dst[i] = (TYPE2)a[i]; \ + } + +#define TEST_ALL() \ + TEST(_Float16, float) \ + TEST(_Float16, double) \ + TEST(float, double) \ + +TEST_ALL() diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-zvfh-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-zvfh-run.c new file mode 100644 index 000000000000..77d653e256df --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vfwcvt-zvfh-run.c @@ -0,0 +1,34 @@ +/* { dg-do run { target { riscv_vector && riscv_zvfh_hw } } } */ +/* { dg-additional-options "-std=c99 -march=rv64gcv_zvfh -mabi=lp64d -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +#include "vfwcvt-template.h" + +#include + +#define SZ 512 +#define EPS 1e-4 + +#define RUN(TYPE1,TYPE2) \ + TYPE1 src##TYPE1##TYPE2[SZ]; \ + TYPE2 dst##TYPE1##TYPE2[SZ]; \ + for (int i = 0; i < SZ; i++) \ + { \ + src##TYPE1##TYPE2[i] = (i & 1) ? -i : i; \ + src##TYPE1##TYPE2[i] *= 0.0003141592; \ + dst##TYPE1##TYPE2[i] = -1; \ + } \ + vfwcvt_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \ + src##TYPE1##TYPE2, SZ); \ + for (int i = 0; i < SZ; i++) \ + assert (__builtin_fabs (dst##TYPE1##TYPE2[i] \ + - ((i & 1) ? -i : i) * 0.0003141592) < EPS); \ + + +#define RUN_ALL() \ + RUN(_Float16, float) \ + RUN(_Float16, double) \ + +int main () +{ + RUN_ALL() +}