On 07/05/2025 12:29, Robin Dapp wrote:
Yes, we need it in order to be able to test both paths, i.e. combining and not combining.  Also make sure to test with multiple types and situations as in Pan's patch.

Please find attached a revised version of the patch.

Compared to the previous iteration, I have:
* Rebased on top of Pan's work;
* Updated the cost model;
* Added a second pattern to handle the case where PLUS_MINUS operands are swapped;
* Added compile and run tests.

I bootstrapped and regtested against rv64gcv.

Is it OK for mainline?

Thanks,
--
PA
commit b17bd6b3fc8e0f3f1e839bc292f239b28192c607
Author: Paul-Antoine Arras <par...@baylibre.com>
Date:   Mon May 12 14:42:24 2025 +0200

    RISC-V: Add pattern for vector-scalar multiply-add/sub [PR119100]
    
    This pattern enables the combine pass to merge a vec_duplicate into a plus-mult
    or minus-mult RTL instruction.
    
    Before this patch, we have two instructions, e.g.:
      vfmv.v.f        v6,fa0
      vfmadd.vv       v9,v6,v7
    
    After, we get only one:
      vfmadd.vf       v9,fa0,v7
    
    On SPEC2017's 503.bwaves_r, depending on the workload, the reduction in dynamic
    instruction count varies from -4.66% to -4.75%.
    
            PR target/119100
    
    gcc/ChangeLog:
    
            * config/riscv/autovec-opt.md (*<optab>_vf_<mode>): Add new pattern to
            combine vec_duplicate + vfm{add,sub}.vv into vfm{add,sub}.vf.
            * config/riscv/riscv-opts.h (FPR2VR_COST_UNPROVIDED): Define.
            * config/riscv/riscv-protos.h (get_fr2vr_cost): Declare function.
            * config/riscv/riscv-vector-costs.cc (costs::adjust_stmt_cost): Call it.
            * config/riscv/riscv.cc (riscv_rtx_costs): Add cost model for MULT with
            VEC_DUPLICATE.
            (get_fr2vr_cost): New function.
            * config/riscv/riscv.opt: Add new option --param=fpr2vr-cost.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c: New test.
            * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c: New test.

diff --git gcc/config/riscv/autovec-opt.md gcc/config/riscv/autovec-opt.md
index a972eda8de4..be08b659df1 100644
--- gcc/config/riscv/autovec-opt.md
+++ gcc/config/riscv/autovec-opt.md
@@ -1713,3 +1713,55 @@ (define_insn_and_split "*<optab>_vx_<mode>"
 						<MODE>mode);
   }
   [(set_attr "type" "vialu")])
+
+;; =============================================================================
+;; Combine vec_duplicate + op.vv to op.vf
+;; Include
+;; - vfmadd.vf
+;; - vfmsub.vf
+;; =============================================================================
+
+
+(define_insn_and_split "*<optab>_vf_<mode>"
+  [(set (match_operand:V_VLSF 0 "register_operand"            "=vd")
+    (plus_minus:V_VLSF
+	    (mult:V_VLSF
+	      (vec_duplicate:V_VLSF
+		(match_operand:<VEL> 1 "register_operand"     "  f"))
+	      (match_operand:V_VLSF 2 "register_operand"      "  0"))
+	    (match_operand:V_VLSF 3 "register_operand"        " vr")))]
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+  {
+    rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
+		 operands[2]};
+    riscv_vector::emit_vlmax_insn (code_for_pred_mul_scalar (<CODE>, <MODE>mode),
+				   riscv_vector::TERNARY_OP_FRM_DYN, ops);
+    DONE;
+  }
+  [(set_attr "type" "vfmuladd")]
+)
+
+(define_insn_and_split "*<optab>_vf_<mode>"
+  [(set (match_operand:V_VLSF 0 "register_operand"            "=vd")
+    (plus_minus:V_VLSF
+	    (match_operand:V_VLSF 3 "register_operand"        " vr")
+	    (mult:V_VLSF
+	      (vec_duplicate:V_VLSF
+		(match_operand:<VEL> 1 "register_operand"     "  f"))
+	      (match_operand:V_VLSF 2 "register_operand"      "  0"))))]
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+  {
+    rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
+		 operands[2]};
+    riscv_vector::emit_vlmax_insn (code_for_pred_mul_scalar (<CODE>, <MODE>mode),
+				   riscv_vector::TERNARY_OP_FRM_DYN, ops);
+    DONE;
+  }
+  [(set_attr "type" "vfmuladd")]
+)
diff --git gcc/config/riscv/riscv-opts.h gcc/config/riscv/riscv-opts.h
index c02c599ed39..e1a820bb50e 100644
--- gcc/config/riscv/riscv-opts.h
+++ gcc/config/riscv/riscv-opts.h
@@ -164,6 +164,7 @@ enum riscv_tls_type {
   (TARGET_VECTOR && riscv_mautovec_segment)
 
 #define GPR2VR_COST_UNPROVIDED -1
+#define FPR2VR_COST_UNPROVIDED -1
 
 /* Extra extension flags, used for carry extra info for a RISC-V extension.  */
 enum
diff --git gcc/config/riscv/riscv-protos.h gcc/config/riscv/riscv-protos.h
index d8c8f6b5079..a0331204479 100644
--- gcc/config/riscv/riscv-protos.h
+++ gcc/config/riscv/riscv-protos.h
@@ -841,6 +841,7 @@ const struct riscv_tune_info *
 riscv_parse_tune (const char *, bool);
 const cpu_vector_cost *get_vector_costs ();
 int get_gr2vr_cost ();
+int get_fr2vr_cost ();
 
 enum
 {
diff --git gcc/config/riscv/riscv-vector-costs.cc gcc/config/riscv/riscv-vector-costs.cc
index c28eecd1110..e710edfb763 100644
--- gcc/config/riscv/riscv-vector-costs.cc
+++ gcc/config/riscv/riscv-vector-costs.cc
@@ -1120,8 +1120,8 @@ costs::adjust_stmt_cost (enum vect_cost_for_stmt kind, loop_vec_info loop,
   switch (kind)
     {
     case scalar_to_vec:
-      stmt_cost += (FLOAT_TYPE_P (vectype) ? costs->regmove->FR2VR
-		    : get_gr2vr_cost ());
+      stmt_cost
+	+= (FLOAT_TYPE_P (vectype) ? get_fr2vr_cost () : get_gr2vr_cost ());
       break;
     case vec_to_scalar:
       stmt_cost += (FLOAT_TYPE_P (vectype) ? costs->regmove->VR2FR
diff --git gcc/config/riscv/riscv.cc gcc/config/riscv/riscv.cc
index 1a88e96d8c6..d6ba9399fd1 100644
--- gcc/config/riscv/riscv.cc
+++ gcc/config/riscv/riscv.cc
@@ -3904,6 +3904,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
   if (riscv_v_ext_mode_p (mode))
     {
       int gr2vr_cost = get_gr2vr_cost ();
+      int fr2vr_cost = get_fr2vr_cost ();
 
       switch (outer_code)
 	{
@@ -3919,14 +3920,29 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 		{
 		  rtx op_0 = XEXP (x, 0);
 		  rtx op_1 = XEXP (x, 1);
+		  rtx op;
 
 		  if (GET_CODE (op_0) == VEC_DUPLICATE
 		      || GET_CODE (op_1) == VEC_DUPLICATE)
-		    *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1);
-		  else
-		    *total = COSTS_N_INSNS (1);
+		    {
+		      *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1);
+		      break;
+		    }
+		  else if (GET_CODE (op = op_0) == MULT
+			   || GET_CODE (op = op_1) == MULT)
+		    {
+		      rtx mult_op0 = XEXP (op, 0);
+		      if (GET_CODE (mult_op0) == VEC_DUPLICATE)
+			{
+			  if (FLOAT_MODE_P (mode))
+			    *total = (fr2vr_cost + 1) * COSTS_N_INSNS (1);
+			  else
+			    *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1);
+			  break;
+			}
+		    }
 		}
-		break;
+		/* Fall through.  */
 	      default:
 		*total = COSTS_N_INSNS (1);
 		break;
@@ -12643,6 +12659,21 @@ get_gr2vr_cost ()
   return cost;
 }
 
+/* Return the cost of moving data from floating-point to vector register.
+   It will take the value of --param=fpr2vr-cost if it is provided.
+   Otherwise the default regmove->FR2VR will be returned.  */
+
+int
+get_fr2vr_cost ()
+{
+  int cost = get_vector_costs ()->regmove->FR2VR;
+
+  if (fpr2vr_cost != FPR2VR_COST_UNPROVIDED)
+    cost = fpr2vr_cost;
+
+  return cost;
+}
+
 /* Implement targetm.vectorize.builtin_vectorization_cost.  */
 
 static int
diff --git gcc/config/riscv/riscv.opt gcc/config/riscv/riscv.opt
index 527e09549a8..55b703d8d82 100644
--- gcc/config/riscv/riscv.opt
+++ gcc/config/riscv/riscv.opt
@@ -286,6 +286,10 @@ Max number of bytes to compare as part of inlined strcmp/strncmp routines (defau
 Target RejectNegative Joined UInteger Var(gpr2vr_cost) Init(GPR2VR_COST_UNPROVIDED)
 Set the cost value of the rvv instruction when operate from GPR to VR.
 
+-param=fpr2vr-cost=
+Target RejectNegative Joined UInteger Var(fpr2vr_cost) Init(FPR2VR_COST_UNPROVIDED)
+Set the cost value of the rvv instruction when operate from FPR to VR.
+
 Enum
 Name(rvv_max_lmul) Type(enum rvv_max_lmul_enum)
 The RVV possible LMUL (-mrvv-max-lmul=):
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c
new file mode 100644
index 00000000000..49b42879a51
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(float, +, add)
+DEF_VF_MULOP_CASE_0(float, -, sub)
+
+/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */
+/* { dg-final { scan-assembler-times {vfmsub.vf} 1 } } */
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c
new file mode 100644
index 00000000000..2bb5d891237
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(double, +, add)
+DEF_VF_MULOP_CASE_0(double, -, sub)
+
+/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */
+/* { dg-final { scan-assembler-times {vfmsub.vf} 1 } } */
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c
new file mode 100644
index 00000000000..66ff9b8c75e
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=1" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(float, +, add)
+DEF_VF_MULOP_CASE_0(float, -, sub)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c
new file mode 100644
index 00000000000..66ff9b8c75e
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=1" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(float, +, add)
+DEF_VF_MULOP_CASE_0(float, -, sub)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c
new file mode 100644
index 00000000000..c853620bb13
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(float, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(float, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler {vfmadd.vf} } } */
+/* { dg-final { scan-assembler {vfmsub.vf} } } */
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c
new file mode 100644
index 00000000000..d38ae8b3220
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(double, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(double, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler {vfmadd.vf} } } */
+/* { dg-final { scan-assembler {vfmsub.vf} } } */
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c
new file mode 100644
index 00000000000..6730d4b154d
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=4" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(float, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(float, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c
new file mode 100644
index 00000000000..bcb6a6e5696
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=4" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(double, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(double, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h
new file mode 100644
index 00000000000..52539788906
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h
@@ -0,0 +1,61 @@
+#ifndef HAVE_DEFINED_VF_MULOP_H
+#define HAVE_DEFINED_VF_MULOP_H
+
+#include <stdint.h>
+
+#define DEF_VF_MULOP_CASE_0(T, OP, NAME)                                       \
+  void test_vf_mulop_##NAME##_##T##_case_0(T *restrict out, T *restrict in,    \
+                                           T x, unsigned n) {                  \
+    for (unsigned i = 0; i < n; i++)                                           \
+      out[i] = in[i] OP out[i] * x;                                            \
+  }
+#define DEF_VF_MULOP_CASE_0_WRAP(T, OP, NAME) DEF_VF_MULOP_CASE_0(T, OP, NAME)
+#define RUN_VF_MULOP_CASE_0(T, NAME, out, in, x, n)                            \
+  test_vf_mulop_##NAME##_##T##_case_0(out, in, x, n)
+#define RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)                       \
+  RUN_VF_MULOP_CASE_0(T, NAME, out, in, x, n)
+
+#define VF_MULOP_BODY(op)                                                      \
+  out[k + 0] = in[k + 0] op tmp * out[k + 0];                                  \
+  out[k + 1] = in[k + 1] op tmp * out[k + 1];                                  \
+  k += 2;
+
+#define VF_MULOP_BODY_X4(op)                                                   \
+  VF_MULOP_BODY(op)                                                            \
+  VF_MULOP_BODY(op)
+
+#define VF_MULOP_BODY_X8(op)                                                   \
+  VF_MULOP_BODY_X4(op)                                                         \
+  VF_MULOP_BODY_X4(op)
+
+#define VF_MULOP_BODY_X16(op)                                                  \
+  VF_MULOP_BODY_X8(op)                                                         \
+  VF_MULOP_BODY_X8(op)
+
+#define VF_MULOP_BODY_X32(op)                                                  \
+  VF_MULOP_BODY_X16(op)                                                        \
+  VF_MULOP_BODY_X16(op)
+
+#define VF_MULOP_BODY_X64(op)                                                  \
+  VF_MULOP_BODY_X32(op)                                                        \
+  VF_MULOP_BODY_X32(op)
+
+#define VF_MULOP_BODY_X128(op)                                                 \
+  VF_MULOP_BODY_X64(op)                                                        \
+  VF_MULOP_BODY_X64(op)
+
+#define DEF_VF_MULOP_CASE_1(T, OP, NAME, BODY)                                       \
+  void test_vf_mulop_##NAME##_##T##_case_1(T *restrict out, T *restrict in,    \
+                                           T x, unsigned n) {                  \
+    unsigned k = 0;                                                            \
+    T tmp = x + 3;                                                             \
+                                                                               \
+    while (k < n) {                                                            \
+      tmp = tmp * 0x3f;                                                        \
+      BODY(OP)                                                                 \
+    }                                                                          \
+  }
+#define DEF_VF_MULOP_CASE_1_WRAP(T, OP, NAME, BODY)                            \
+  DEF_VF_MULOP_CASE_1(T, OP, NAME, BODY)
+
+#endif
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h
new file mode 100644
index 00000000000..d10459b5c47
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h
@@ -0,0 +1,284 @@
+#ifndef HAVE_DEFINED_VF_MULOP_DATA_H
+#define HAVE_DEFINED_VF_MULOP_DATA_H
+
+#define N 16
+
+#define TEST_MULOP_DATA(T, NAME)      test_##T##_##NAME##_data
+#define TEST_MULOP_DATA_WRAP(T, NAME) TEST_MULOP_DATA(T, NAME)
+
+
+float TEST_MULOP_DATA(float, add)[][4][N] =
+{
+  {
+    { 43.71f },
+    {
+      -410.28f,    -410.28f,    -410.28f,    -410.28f,
+      -276.91f,    -276.91f,    -276.91f,    -276.91f,
+      -103.38f,    -103.38f,    -103.38f,    -103.38f,
+      -378.24f,    -378.24f,    -378.24f,    -378.24f,
+   },
+   {
+         9.56f,       9.56f,       9.56f,       9.56f,
+         6.39f,       6.39f,       6.39f,       6.39f,
+         2.40f,       2.40f,       2.40f,       2.40f,
+         8.80f,       8.80f,       8.80f,       8.80f,
+   },
+   {
+         7.59f,       7.59f,       7.59f,       7.59f,
+         2.40f,       2.40f,       2.40f,       2.40f,
+         1.52f,       1.52f,       1.52f,       1.52f,
+         6.41f,       6.41f,       6.41f,       6.41f,
+   }
+  },
+  {
+    { 2.04f },
+    {
+       -110.22f,    -110.22f,    -110.22f,    -110.22f,
+        -25.13f,     -25.13f,     -25.13f,     -25.13f,
+       -108.18f,    -108.18f,    -108.18f,    -108.18f,
+       -107.14f,    -107.14f,    -107.14f,    -107.14f,
+    },
+    {
+         64.82f,      64.82f,      64.82f,      64.82f,
+         31.65f,      31.65f,      31.65f,      31.65f,
+         87.32f,      87.32f,      87.32f,      87.32f,
+         58.70f,      58.70f,      58.70f,      58.70f,
+    },
+    {
+         22.01f,      22.01f,      22.01f,      22.01f,
+         39.44f,      39.44f,      39.44f,      39.44f,
+         69.95f,      69.95f,      69.95f,      69.95f,
+         12.61f,      12.61f,      12.61f,      12.61f,
+    }
+  },
+  {
+    { 20.35f },
+    {
+        881.43f,     881.43f,     881.43f,     881.43f,
+       3300.17f,    3300.17f,    3300.17f,    3300.17f,
+       5217.85f,    5217.85f,    5217.85f,    5217.85f,
+         66.57f,      66.57f,      66.57f,      66.57f,
+    },
+    {
+         64.82f,      64.82f,      64.82f,      64.82f,
+         31.65f,      31.65f,      31.65f,      31.65f,
+         87.32f,      87.32f,      87.32f,      87.32f,
+         58.70f,      58.70f,      58.70f,      58.70f,
+    },
+    {
+       2200.52f,    2200.52f,    2200.52f,    2200.52f,
+       3944.25f,    3944.25f,    3944.25f,    3944.25f,
+       6994.81f,    6994.81f,    6994.81f,    6994.81f,
+       1261.12f,    1261.12f,    1261.12f,    1261.12f,
+    }
+  },
+};
+
+
+double TEST_MULOP_DATA(double, add)[][4][N] =
+{
+  {
+    {   1.16e+12 },
+    {
+    1.8757e+45, 1.8757e+45, 1.8757e+45, 1.8757e+45,
+    7.5140e+45, 7.5140e+45, 7.5140e+45, 7.5140e+45,
+    8.2069e+45, 8.2069e+45, 8.2069e+45, 8.2069e+45,
+    4.9456e+45, 4.9456e+45, 4.9456e+45, 4.9456e+45,
+    },
+    {
+    9.0242e+32, 9.0242e+32, 9.0242e+32, 9.0242e+32,
+    3.6908e+32, 3.6908e+32, 3.6908e+32, 3.6908e+32,
+    3.9202e+32, 3.9202e+32, 3.9202e+32, 3.9202e+32,
+    5.0276e+32, 5.0276e+32, 5.0276e+32, 5.0276e+32,
+    },
+    {
+    2.9201e+45, 2.9201e+45, 2.9201e+45, 2.9201e+45,
+    7.9411e+45, 7.9411e+45, 7.9411e+45, 7.9411e+45,
+    8.6606e+45, 8.6606e+45, 8.6606e+45, 8.6606e+45,
+    5.5275e+45, 5.5275e+45, 5.5275e+45, 5.5275e+45,
+    }
+    
+  },
+  {
+    {  -7.29e+23 },
+    {
+    -6.4993e+65, -6.4993e+65, -6.4993e+65, -6.4993e+65,
+    -4.6760e+65, -4.6760e+65, -4.6760e+65, -4.6760e+65,
+    -8.1564e+65, -8.1564e+65, -8.1564e+65, -8.1564e+65,
+    -8.2899e+65, -8.2899e+65, -8.2899e+65, -8.2899e+65,
+    },
+    {
+    -7.7764e+41, -7.7764e+41, -7.7764e+41, -7.7764e+41,
+    -1.9756e+41, -1.9756e+41, -1.9756e+41, -1.9756e+41,
+    -4.8980e+41, -4.8980e+41, -4.8980e+41, -4.8980e+41,
+    -8.1062e+41, -8.1062e+41, -8.1062e+41, -8.1062e+41,
+    },
+    {
+    -8.2928e+64, -8.2928e+64, -8.2928e+64, -8.2928e+64,
+    -3.2356e+65, -3.2356e+65, -3.2356e+65, -3.2356e+65,
+    -4.5850e+65, -4.5850e+65, -4.5850e+65, -4.5850e+65,
+    -2.3794e+65, -2.3794e+65, -2.3794e+65, -2.3794e+65,
+    }
+    
+  },
+  {
+    {   2.02e-03 },
+    {
+    -1.2191e-35, -1.2191e-35, -1.2191e-35, -1.2191e-35,
+    -1.0471e-36, -1.0471e-36, -1.0471e-36, -1.0471e-36,
+    -9.7582e-36, -9.7582e-36, -9.7582e-36, -9.7582e-36,
+    -2.2097e-36, -2.2097e-36, -2.2097e-36, -2.2097e-36,
+    },
+    {
+    9.7703e-33, 9.7703e-33, 9.7703e-33, 9.7703e-33,
+    4.1632e-33, 4.1632e-33, 4.1632e-33, 4.1632e-33,
+    8.1964e-33, 8.1964e-33, 8.1964e-33, 8.1964e-33,
+    4.7314e-33, 4.7314e-33, 4.7314e-33, 4.7314e-33,
+    },
+    {
+    7.5586e-36, 7.5586e-36, 7.5586e-36, 7.5586e-36,
+    7.3684e-36, 7.3684e-36, 7.3684e-36, 7.3684e-36,
+    6.8101e-36, 6.8101e-36, 6.8101e-36, 6.8101e-36,
+    7.3543e-36, 7.3543e-36, 7.3543e-36, 7.3543e-36,
+    }
+  },
+};
+
+float TEST_MULOP_DATA(float, sub)[][4][N] =
+{
+  {
+  {8.51f },
+  {
+       24.21f,      24.21f,      24.21f,      24.21f,
+       40.31f,      40.31f,      40.31f,      40.31f,
+       59.68f,      59.68f,      59.68f,      59.68f,
+       45.42f,      45.42f,      45.42f,      45.42f,
+  },
+  {
+        1.94f,       1.94f,       1.94f,       1.94f,
+        4.24f,       4.24f,       4.24f,       4.24f,
+        6.48f,       6.48f,       6.48f,       6.48f,
+        4.68f,       4.68f,       4.68f,       4.68f,
+  },
+  {
+        7.70f,       7.70f,       7.70f,       7.70f,
+        4.23f,       4.23f,       4.23f,       4.23f,
+        4.54f,       4.54f,       4.54f,       4.54f,
+        5.59f,       5.59f,       5.59f,       5.59f,
+  },
+},
+  {
+    { 85.14f },
+    {
+       1731.29f,    1731.29f,    1731.29f,    1731.29f,
+       3656.53f,    3656.53f,    3656.53f,    3656.53f,
+       5565.07f,    5565.07f,    5565.07f,    5565.07f,
+       4042.14f,    4042.14f,    4042.14f,    4042.14f,
+    },
+    {
+         19.43f,      19.43f,      19.43f,      19.43f,
+         42.45f,      42.45f,      42.45f,      42.45f,
+         64.83f,      64.83f,      64.83f,      64.83f,
+         46.82f,      46.82f,      46.82f,      46.82f,
+    },
+    {
+         77.02f,      77.02f,      77.02f,      77.02f,
+         42.34f,      42.34f,      42.34f,      42.34f,
+         45.44f,      45.44f,      45.44f,      45.44f,
+         55.89f,      55.89f,      55.89f,      55.89f,
+    }
+  },
+  {
+    { 99.01f },
+    {
+       6240.43f,    6240.43f,    6240.43f,    6240.43f,
+       2179.23f,    2179.23f,    2179.23f,    2179.23f,
+       5346.65f,    5346.65f,    5346.65f,    5346.65f,
+       2649.91f,    2649.91f,    2649.91f,    2649.91f,
+    },
+    {
+         59.46f,      59.46f,      59.46f,      59.46f,
+         16.96f,      16.96f,      16.96f,      16.96f,
+         52.55f,      52.55f,      52.55f,      52.55f,
+         24.70f,      24.70f,      24.70f,      24.70f,
+    },
+    {
+        353.30f,     353.30f,     353.30f,     353.30f,
+        500.02f,     500.02f,     500.02f,     500.02f,
+        143.67f,     143.67f,     143.67f,     143.67f,
+        204.36f,     204.36f,     204.36f,     204.36f,
+    }
+    
+  },
+};
+
+double TEST_MULOP_DATA(double, sub)[][4][N] =
+{
+  {
+    { 80.54 },
+    {
+       5731.60,    5731.60,    5731.60,    5731.60,
+       6682.41,    6682.41,    6682.41,    6682.41,
+       7737.53,    7737.53,    7737.53,    7737.53,
+       4922.68,    4922.68,    4922.68,    4922.68,
+    },
+    {
+         67.14,      67.14,      67.14,      67.14,
+         78.23,      78.23,      78.23,      78.23,
+         94.35,      94.35,      94.35,      94.35,
+         49.68,      49.68,      49.68,      49.68,
+    },
+    {
+        324.14,     324.14,     324.14,     324.14,
+        381.77,     381.77,     381.77,     381.77,
+        138.58,     138.58,     138.58,     138.58,
+        921.45,     921.45,     921.45,     921.45,
+    }
+  },
+  {
+    {   8.05e+01 },
+    {
+      8.65e+27,   8.65e+27,   8.65e+27,   8.65e+27,
+      1.01e+28,   1.01e+28,   1.01e+28,   1.01e+28,
+      8.99e+27,   8.99e+27,   8.99e+27,   8.99e+27,
+      1.32e+28,   1.32e+28,   1.32e+28,   1.32e+28,
+    },
+    {
+      6.71e+25,   6.71e+25,   6.71e+25,   6.71e+25,
+      7.82e+25,   7.82e+25,   7.82e+25,   7.82e+25,
+      9.44e+25,   9.44e+25,   9.44e+25,   9.44e+25,
+      4.97e+25,   4.97e+25,   4.97e+25,   4.97e+25,
+    },
+    {
+      3.24e+27,   3.24e+27,   3.24e+27,   3.24e+27,
+      3.82e+27,   3.82e+27,   3.82e+27,   3.82e+27,
+      1.39e+27,   1.39e+27,   1.39e+27,   1.39e+27,
+      9.21e+27,   9.21e+27,   9.21e+27,   9.21e+27,
+    }
+  },
+  {
+    {   2.02e-03 },
+    {
+    2.7308e-35, 2.7308e-35, 2.7308e-35, 2.7308e-35,
+    1.5784e-35, 1.5784e-35, 1.5784e-35, 1.5784e-35,
+    2.3378e-35, 2.3378e-35, 2.3378e-35, 2.3378e-35,
+    1.6918e-35, 1.6918e-35, 1.6918e-35, 1.6918e-35,
+    },
+    {
+    9.7703e-33, 9.7703e-33, 9.7703e-33, 9.7703e-33,
+    4.1632e-33, 4.1632e-33, 4.1632e-33, 4.1632e-33,
+    8.1964e-33, 8.1964e-33, 8.1964e-33, 8.1964e-33,
+    4.7314e-33, 4.7314e-33, 4.7314e-33, 4.7314e-33,
+    },
+    {
+    7.5586e-36, 7.5586e-36, 7.5586e-36, 7.5586e-36,
+    7.3684e-36, 7.3684e-36, 7.3684e-36, 7.3684e-36,
+    6.8101e-36, 6.8101e-36, 6.8101e-36, 6.8101e-36,
+    7.3543e-36, 7.3543e-36, 7.3543e-36, 7.3543e-36,
+    }
+    
+  },
+};
+
+
+#endif
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h
new file mode 100644
index 00000000000..3eda7c055f7
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h
@@ -0,0 +1,34 @@
+#ifndef HAVE_DEFINED_VF_MULOP_RUN_H
+#define HAVE_DEFINED_VF_MULOP_RUN_H
+
+#include <math.h>
+
+#define TYPE_FABS(x, T)                                                        \
+  (__builtin_types_compatible_p (T, float) ? fabsf (x) : fabs (x))
+
+int
+main ()
+{
+  unsigned i, k;
+
+  for (i = 0; i < sizeof (TEST_DATA) / sizeof (TEST_DATA[0]); i++)
+    {
+      T x = TEST_DATA[i][0][0];
+      T *in = TEST_DATA[i][1];
+      T *out = TEST_DATA[i][2];
+      T *expect = TEST_DATA[i][3];
+
+      TEST_RUN (T, NAME, out, in, x, N);
+
+      for (k = 0; k < N; k++)
+	{
+	  T diff = expect[k] - out[k];
+	  if (TYPE_FABS (diff, T) > .01 * TYPE_FABS (expect[k], T))
+	    __builtin_abort ();
+	}
+    }
+
+  return 0;
+}
+
+#endif
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c
new file mode 100644
index 00000000000..932c377ec5e
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=gpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T    float
+#define NAME add
+
+DEF_VF_MULOP_CASE_0_WRAP(T, +, NAME)
+
+#define TEST_DATA                        TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_run.h"
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c
new file mode 100644
index 00000000000..3fdceb08ff0
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=gpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T    double
+#define NAME add
+
+DEF_VF_MULOP_CASE_0_WRAP(T, +, NAME)
+
+#define TEST_DATA                        TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_run.h"
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c
new file mode 100644
index 00000000000..a22e04f89ce
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=gpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T    float
+#define NAME sub
+
+DEF_VF_MULOP_CASE_0_WRAP(T, -, NAME)
+
+#define TEST_DATA                        TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_run.h"
diff --git gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c
new file mode 100644
index 00000000000..9a8465ff8ee
--- /dev/null
+++ gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=gpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T    double
+#define NAME sub
+
+DEF_VF_MULOP_CASE_0_WRAP(T, -, NAME)
+
+#define TEST_DATA                        TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_run.h"

Reply via email to