The vector FMA patterns currently match multiply/add trees, which lets
combine fuse operations into FMA instructions even with -ffp-contract=off.
Rewrite these patterns using fma rtxes:
- fma/fnma/fms/fnms in autovec.md.
- *dual_widen_*, *single_widen_* in autovec-opt.md.
- .vf patterns in autovec-opt.md:
*vfmacc_vf, *vfmsac_vf,
*vfwmacc_vf_v_f, *vfwmsac_vf_v_f,
*vfwnmacc_vf_neg_v_f, *vfwnmsac_vf_neg_v_f.
Unlike the old (plus (mult ...)) form, fma folds neg and sub into its operands.
Operands with or without neg create different RTL shapes for vector-scalar
pairs. Cover these by adding:
- *vfnmsac_vf_neg_f_v, *vfnmsac_vf_neg_v_f.
- *vfnmacc_vf_neg_f_v, *vfnmacc_vf_neg_v_f.
- *vfwmacc_vf_f_v, *vfwmsac_vf_f_v.
- *vfwnmacc_vf_neg_f_v, *vfwnmsac_vf_neg_f_v.
Also, testing showed vf-3-f32.c regressed. That's because a scalar is
reused across multiple loop statements and shares a single widening broadcast.
Combine failed to match the inlined broadcast and fell back to vfnmsac.vv.
Add to fix it:
- *vfnmsac_vf_extend_f.
And add the remaining three extend_f variants as well:
- *vfnmacc_vf_extend_f, *vfmacc_vf_extend_f, *vfmsac_vf_extend_f.
PR target/126932
gcc/ChangeLog:
* config/riscv/autovec.md: Rewrite vector FMA patterns.
* config/riscv/autovec-opt.md: Likewise and add new patterns.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/rvv/autovec/ternop/pr126932.c: New test.
Signed-off-by: Zhongyao Chen <[email protected]>
---
gcc/config/riscv/autovec-opt.md | 531 ++++++++++++++----
gcc/config/riscv/autovec.md | 35 +-
.../riscv/rvv/autovec/ternop/pr126932.c | 55 ++
3 files changed, 492 insertions(+), 129 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/pr126932.c
diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md
index 094ad6fd6c94..e6cd23e83998 100644
--- a/gcc/config/riscv/autovec-opt.md
+++ b/gcc/config/riscv/autovec-opt.md
@@ -1091,12 +1091,11 @@
;; Combine extend + fma to widen_fma (vfwmacc)
(define_insn_and_split "*dual_widen_fma<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (plus:VWEXTF
- (mult:VWEXTF
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))
+ (fma:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
(match_operand:VWEXTF 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
@@ -1116,11 +1115,10 @@
;; pattern and non-widen fma pattern.
(define_insn_and_split "*single_widen_fma<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (plus:VWEXTF
- (mult:VWEXTF
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
- (match_operand:VWEXTF 3 "register_operand"))
+ (fma:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
+ (match_operand:VWEXTF 3 "register_operand")
(match_operand:VWEXTF 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
@@ -1143,13 +1141,13 @@
;; Combine extend + fnma to widen_fnma (vfwnmsac)
(define_insn_and_split "*dual_widen_fnma<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (minus:VWEXTF
- (match_operand:VWEXTF 1 "register_operand")
- (mult:VWEXTF
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))))]
+ (fma:VWEXTF
+ (neg:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand")))
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (match_operand:VWEXTF 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
@@ -1168,12 +1166,12 @@
;; pattern and non-widen fnma pattern.
(define_insn_and_split "*single_widen_fnma<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (minus:VWEXTF
- (match_operand:VWEXTF 1 "register_operand")
- (mult:VWEXTF
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
- (match_operand:VWEXTF 3 "register_operand"))))]
+ (fma:VWEXTF
+ (neg:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand")))
+ (match_operand:VWEXTF 3 "register_operand")
+ (match_operand:VWEXTF 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
@@ -1195,13 +1193,12 @@
;; Combine extend + fms to widen_fms (vfwmsac)
(define_insn_and_split "*dual_widen_fms<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (minus:VWEXTF
- (mult:VWEXTF
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))
- (match_operand:VWEXTF 1 "register_operand")))]
+ (fma:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
@@ -1220,12 +1217,11 @@
;; pattern and non-widen fms pattern.
(define_insn_and_split "*single_widen_fms<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (minus:VWEXTF
- (mult:VWEXTF
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
- (match_operand:VWEXTF 3 "register_operand"))
- (match_operand:VWEXTF 1 "register_operand")))]
+ (fma:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
+ (match_operand:VWEXTF 3 "register_operand")
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
@@ -1247,14 +1243,13 @@
;; Combine extend + fnms to widen_fnms (vfwnmacc)
(define_insn_and_split "*dual_widen_fnms<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (minus:VWEXTF
- (mult:VWEXTF
- (neg:VWEXTF
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand")))
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))
- (match_operand:VWEXTF 1 "register_operand")))]
+ (fma:VWEXTF
+ (neg:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand")))
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
@@ -1273,13 +1268,12 @@
;; pattern and non-widen fnms pattern.
(define_insn_and_split "*single_widen_fnms<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (minus:VWEXTF
- (mult:VWEXTF
- (neg:VWEXTF
- (match_operand:VWEXTF 3 "register_operand"))
- (float_extend:VWEXTF
+ (fma:VWEXTF
+ (neg:VWEXTF
+ (float_extend:VWEXTF
(match_operand:<V_DOUBLE_TRUNC> 2 "register_operand")))
- (match_operand:VWEXTF 1 "register_operand")))]
+ (match_operand:VWEXTF 3 "register_operand")
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
@@ -2064,23 +2058,46 @@
;; - vfwmsac.vf
;;
=============================================================================
-;; vfmadd.vf, vfmsub.vf, vfmacc.vf, vfmsac.vf
-(define_insn_and_split "*<optab>_vf_<mode>"
+;; vfmadd.vf, vfmacc.vf
+;; f * v + v
+(define_insn_and_split "*vfmacc_vf_<mode>"
[(set (match_operand:V_VLSF 0 "register_operand")
- (plus_minus:V_VLSF
- (mult:V_VLSF
- (vec_duplicate:V_VLSF
- (match_operand:<VEL> 1 "register_operand"))
- (match_operand:V_VLSF 2 "register_operand"))
- (match_operand:V_VLSF 3 "register_operand")))]
+ (fma:V_VLSF
+ (vec_duplicate:V_VLSF
+ (match_operand:<VEL> 1 "register_operand"))
+ (match_operand:V_VLSF 2 "register_operand")
+ (match_operand:V_VLSF 3 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
- RVV_VUNDEF(<MODE>mode)};
- riscv_vector::emit_vlmax_insn (code_for_pred_mul_scalar (<CODE>,
<MODE>mode),
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn (code_for_pred_mul_scalar (PLUS, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfmuladd")]
+)
+
+;; vfmsub.vf, vfmsac.vf
+;; f * v - v
+(define_insn_and_split "*vfmsac_vf_<mode>"
+ [(set (match_operand:V_VLSF 0 "register_operand")
+ (fma:V_VLSF
+ (vec_duplicate:V_VLSF
+ (match_operand:<VEL> 1 "register_operand"))
+ (match_operand:V_VLSF 2 "register_operand")
+ (neg:V_VLSF (match_operand:V_VLSF 3 "register_operand"))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn (code_for_pred_mul_scalar (MINUS,
<MODE>mode),
riscv_vector::TERNARY_OP_FRM_DYN, ops);
DONE;
}
@@ -2088,71 +2105,200 @@
)
;; vfnmsub.vf, vfnmsac.vf
-(define_insn_and_split "*vfnmsub_<mode>"
+;; -f * v + v
+(define_insn_and_split "*vfnmsac_vf_neg_f_v_<mode>"
[(set (match_operand:V_VLSF 0 "register_operand")
- (minus:V_VLSF
- (match_operand:V_VLSF 3 "register_operand")
- (mult:V_VLSF
+ (fma:V_VLSF
+ (neg:V_VLSF
(vec_duplicate:V_VLSF
- (match_operand:<VEL> 1 "register_operand"))
- (match_operand:V_VLSF 2 "register_operand"))))]
+ (match_operand:<VEL> 1 "register_operand")))
+ (match_operand:V_VLSF 2 "register_operand")
+ (match_operand:V_VLSF 3 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
- RVV_VUNDEF(<MODE>mode)};
- riscv_vector::emit_vlmax_insn (code_for_pred_mul_neg_scalar (PLUS,
<MODE>mode),
- riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_mul_neg_scalar (PLUS, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfmuladd")]
+)
+
+;; vfnmsub.vf, vfnmsac.vf
+;; -v * f + v
+(define_insn_and_split "*vfnmsac_vf_neg_v_f_<mode>"
+ [(set (match_operand:V_VLSF 0 "register_operand")
+ (fma:V_VLSF
+ (neg:V_VLSF
+ (match_operand:V_VLSF 2 "register_operand"))
+ (vec_duplicate:V_VLSF
+ (match_operand:<VEL> 1 "register_operand"))
+ (match_operand:V_VLSF 3 "register_operand")))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_mul_neg_scalar (PLUS, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
DONE;
}
[(set_attr "type" "vfmuladd")]
)
;; vfnmadd.vf, vfnmacc.vf
-(define_insn_and_split "*vfnmadd_<mode>"
+;; -f * v - v
+(define_insn_and_split "*vfnmacc_vf_neg_f_v_<mode>"
[(set (match_operand:V_VLSF 0 "register_operand")
- (minus:V_VLSF
- (mult:V_VLSF
- (neg:V_VLSF
- (match_operand:V_VLSF 2 "register_operand"))
+ (fma:V_VLSF
+ (neg:V_VLSF
(vec_duplicate:V_VLSF
(match_operand:<VEL> 1 "register_operand")))
- (match_operand:V_VLSF 3 "register_operand")))]
+ (match_operand:V_VLSF 2 "register_operand")
+ (neg:V_VLSF (match_operand:V_VLSF 3 "register_operand"))))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
- RVV_VUNDEF(<MODE>mode)};
- riscv_vector::emit_vlmax_insn (code_for_pred_mul_neg_scalar (MINUS,
<MODE>mode),
- riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_mul_neg_scalar (MINUS, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfmuladd")]
+)
+
+;; vfnmadd.vf, vfnmacc.vf
+;; -v * f - v
+(define_insn_and_split "*vfnmacc_vf_neg_v_f_<mode>"
+ [(set (match_operand:V_VLSF 0 "register_operand")
+ (fma:V_VLSF
+ (neg:V_VLSF
+ (match_operand:V_VLSF 2 "register_operand"))
+ (vec_duplicate:V_VLSF
+ (match_operand:<VEL> 1 "register_operand"))
+ (neg:V_VLSF (match_operand:V_VLSF 3 "register_operand"))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_mul_neg_scalar (MINUS, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
DONE;
}
[(set_attr "type" "vfmuladd")]
)
-;; vfwmacc.vf, vfwmsac.vf
-(define_insn_and_split "*vfwmacc_vf_<mode>"
+;; vfwmacc.vf
+;; v * f + v
+(define_insn_and_split "*vfwmacc_vf_v_f_<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (plus_minus:VWEXTF
- (mult:VWEXTF
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
- (vec_duplicate:VWEXTF
- (float_extend:<VEL>
- (match_operand:<VSUBEL> 2 "register_operand"))))
- (match_operand:VWEXTF 1 "register_operand")))]
+ (fma:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand")))
+ (match_operand:VWEXTF 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
- riscv_vector::emit_vlmax_insn (code_for_pred_widen_mul_scalar (<CODE>,
<MODE>mode),
- riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_widen_mul_scalar (PLUS, <MODE>mode),
+ riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfwmuladd")]
+)
+
+;; vfwmsac.vf
+;; v * f - v
+(define_insn_and_split "*vfwmsac_vf_v_f_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (fma:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand")))
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_widen_mul_scalar (MINUS, <MODE>mode),
+ riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfwmuladd")]
+)
+
+;; vfwmacc.vf
+;; f * v + v
+(define_insn_and_split "*vfwmacc_vf_f_v_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (fma:VWEXTF
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand")))
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (match_operand:VWEXTF 1 "register_operand")))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_widen_mul_scalar (PLUS, <MODE>mode),
+ riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfwmuladd")]
+)
+
+;; vfwmsac.vf
+;; f * v - v
+(define_insn_and_split "*vfwmsac_vf_f_v_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (fma:VWEXTF
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand")))
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_widen_mul_scalar (MINUS, <MODE>mode),
+ riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
DONE;
}
[(set_attr "type" "vfwmuladd")]
@@ -2180,16 +2326,42 @@
)
;; vfwnmacc.vf
-(define_insn_and_split "*vfwnmacc_vf_<mode>"
+;; -v * f - v
+(define_insn_and_split "*vfwnmacc_vf_neg_v_f_<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (minus:VWEXTF
- (mult:VWEXTF
- (neg:VWEXTF
- (vec_duplicate:VWEXTF
- (float_extend:<VEL>
- (match_operand:<VSUBEL> 2 "register_operand"))))
+ (fma:VWEXTF
+ (neg:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand")))
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_widen_mul_neg_scalar (MINUS, <MODE>mode),
+ riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfwmuladd")]
+)
+
+;; vfwnmsac.vf
+;; -v * f + v
+(define_insn_and_split "*vfwnmsac_vf_neg_v_f_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (fma:VWEXTF
+ (neg:VWEXTF
(float_extend:VWEXTF
(match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand")))
(match_operand:VWEXTF 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
@@ -2198,38 +2370,179 @@
{
rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
riscv_vector::emit_vlmax_insn(
- code_for_pred_widen_mul_neg_scalar(MINUS, <MODE>mode),
+ code_for_pred_widen_mul_neg_scalar (PLUS, <MODE>mode),
riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
DONE;
}
[(set_attr "type" "vfwmuladd")]
)
+;; vfwnmacc.vf
+;; -f * v - v
+(define_insn_and_split "*vfwnmacc_vf_neg_f_v_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (fma:VWEXTF
+ (neg:VWEXTF
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand"))))
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_widen_mul_neg_scalar (MINUS, <MODE>mode),
+ riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfwmuladd")]
+)
+
;; vfwnmsac.vf
-(define_insn_and_split "*vfwnmsac_vf_<mode>"
+;; -f * v + v
+(define_insn_and_split "*vfwnmsac_vf_neg_f_v_<mode>"
[(set (match_operand:VWEXTF 0 "register_operand")
- (minus:VWEXTF
- (match_operand:VWEXTF 1 "register_operand")
- (mult:VWEXTF
- (float_extend:VWEXTF
- (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (fma:VWEXTF
+ (neg:VWEXTF
(vec_duplicate:VWEXTF
(float_extend:<VEL>
- (match_operand:<VSUBEL> 2 "register_operand"))))))]
+ (match_operand:<VSUBEL> 2 "register_operand"))))
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (match_operand:VWEXTF 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
- riscv_vector::emit_vlmax_insn(
- code_for_pred_widen_mul_neg_scalar (PLUS, <MODE>mode),
- riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_widen_mul_neg_scalar (PLUS, <MODE>mode),
+ riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
DONE;
}
[(set_attr "type" "vfwmuladd")]
)
+;; vfnmsub.vf, vfnmsac.vf
+;; -(extend)f * v + v
+(define_insn_and_split "*vfnmsac_vf_extend_f_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (fma:VWEXTF
+ (neg:VWEXTF
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand"))))
+ (match_operand:VWEXTF 3 "register_operand")
+ (match_operand:VWEXTF 1 "register_operand")))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx wide_scalar = gen_reg_rtx (<VEL>mode);
+ emit_insn (gen_extend<vsubel><vel>2 (wide_scalar, operands[2]));
+
+ rtx ops[] = {operands[0], wide_scalar, operands[3], operands[1],
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_mul_neg_scalar (PLUS, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfmuladd")]
+)
+
+;; vfnmadd.vf, vfnmacc.vf
+;; -(extend)f * v - v
+(define_insn_and_split "*vfnmacc_vf_extend_f_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (fma:VWEXTF
+ (neg:VWEXTF
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand"))))
+ (match_operand:VWEXTF 3 "register_operand")
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx wide_scalar = gen_reg_rtx (<VEL>mode);
+ emit_insn (gen_extend<vsubel><vel>2 (wide_scalar, operands[2]));
+
+ rtx ops[] = {operands[0], wide_scalar, operands[3], operands[1],
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_mul_neg_scalar (MINUS, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfmuladd")]
+)
+
+;; vfmadd.vf, vfmacc.vf
+;; (extend)f * v + v
+(define_insn_and_split "*vfmacc_vf_extend_f_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (fma:VWEXTF
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand")))
+ (match_operand:VWEXTF 3 "register_operand")
+ (match_operand:VWEXTF 1 "register_operand")))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx wide_scalar = gen_reg_rtx (<VEL>mode);
+ emit_insn (gen_extend<vsubel><vel>2 (wide_scalar, operands[2]));
+
+ rtx ops[] = {operands[0], wide_scalar, operands[3], operands[1],
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_mul_scalar (PLUS, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfmuladd")]
+)
+
+;; vfmsub.vf, vfmsac.vf
+;; (extend)f * v - v
+(define_insn_and_split "*vfmsac_vf_extend_f_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (fma:VWEXTF
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand")))
+ (match_operand:VWEXTF 3 "register_operand")
+ (neg:VWEXTF (match_operand:VWEXTF 1 "register_operand"))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx wide_scalar = gen_reg_rtx (<VEL>mode);
+ emit_insn (gen_extend<vsubel><vel>2 (wide_scalar, operands[2]));
+
+ rtx ops[] = {operands[0], wide_scalar, operands[3], operands[1],
+ RVV_VUNDEF (<MODE>mode)};
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_mul_scalar (MINUS, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfmuladd")]
+)
+
;; vfmul.vf
(define_insn_and_split "*vfmul_vf_<mode>"
[(set (match_operand:V_VLSF 0 "register_operand")
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 16d08cae30be..12538c8f162a 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -1254,10 +1254,9 @@
(define_insn_and_split "fma<mode>4"
[(set (match_operand:V_VLSF 0 "register_operand")
- (plus:V_VLSF
- (mult:V_VLSF
- (match_operand:V_VLSF 1 "register_operand")
- (match_operand:V_VLSF 2 "register_operand"))
+ (fma:V_VLSF
+ (match_operand:V_VLSF 1 "register_operand")
+ (match_operand:V_VLSF 2 "register_operand")
(match_operand:V_VLSF 3 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
@@ -1282,11 +1281,10 @@
(define_insn_and_split "fnma<mode>4"
[(set (match_operand:V_VLSF 0 "register_operand")
- (minus:V_VLSF
- (match_operand:V_VLSF 3 "register_operand")
- (mult:V_VLSF
- (match_operand:V_VLSF 1 "register_operand")
- (match_operand:V_VLSF 2 "register_operand"))))]
+ (fma:V_VLSF
+ (neg:V_VLSF (match_operand:V_VLSF 1 "register_operand"))
+ (match_operand:V_VLSF 2 "register_operand")
+ (match_operand:V_VLSF 3 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
@@ -1310,11 +1308,10 @@
(define_insn_and_split "fms<mode>4"
[(set (match_operand:V_VLSF 0 "register_operand")
- (minus:V_VLSF
- (mult:V_VLSF
- (match_operand:V_VLSF 1 "register_operand")
- (match_operand:V_VLSF 2 "register_operand"))
- (match_operand:V_VLSF 3 "register_operand")))]
+ (fma:V_VLSF
+ (match_operand:V_VLSF 1 "register_operand")
+ (match_operand:V_VLSF 2 "register_operand")
+ (neg:V_VLSF (match_operand:V_VLSF 3 "register_operand"))))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
@@ -1338,12 +1335,10 @@
(define_insn_and_split "fnms<mode>4"
[(set (match_operand:V_VLSF 0 "register_operand")
- (minus:V_VLSF
- (neg:V_VLSF
- (mult:V_VLSF
- (match_operand:V_VLSF 1 "register_operand")
- (match_operand:V_VLSF 2 "register_operand")))
- (match_operand:V_VLSF 3 "register_operand")))]
+ (fma:V_VLSF
+ (neg:V_VLSF (match_operand:V_VLSF 1 "register_operand"))
+ (match_operand:V_VLSF 2 "register_operand")
+ (neg:V_VLSF (match_operand:V_VLSF 3 "register_operand"))))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/pr126932.c
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/pr126932.c
new file mode 100644
index 000000000000..3b8a9c749ae8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/pr126932.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -ffp-contract=off" } */
+/* { dg-require-effective-target rv64 } */
+
+typedef struct { float x, y, z, w; } vec4;
+
+vec4 mul_add(vec4 a, vec4 b, vec4 c)
+{
+ vec4 v;
+ v.x = a.x + b.x * c.x;
+ v.y = a.y + b.y * c.y;
+ v.z = a.z + b.z * c.z;
+ v.w = a.w + b.w * c.w;
+ return v;
+}
+
+vec4 neg_mul_add(vec4 a, vec4 b, vec4 c)
+{
+ vec4 v;
+ v.x = c.x - a.x * b.x;
+ v.y = c.y - a.y * b.y;
+ v.z = c.z - a.z * b.z;
+ v.w = c.w - a.w * b.w;
+ return v;
+}
+
+vec4 mul_sub(vec4 a, vec4 b, vec4 c)
+{
+ vec4 v;
+ v.x = a.x * b.x - c.x;
+ v.y = a.y * b.y - c.y;
+ v.z = a.z * b.z - c.z;
+ v.w = a.w * b.w - c.w;
+ return v;
+}
+
+vec4 neg_mul_sub(vec4 a, vec4 b, vec4 c)
+{
+ vec4 v;
+ v.x = -(a.x * b.x) - c.x;
+ v.y = -(a.y * b.y) - c.y;
+ v.z = -(a.z * b.z) - c.z;
+ v.w = -(a.w * b.w) - c.w;
+ return v;
+}
+
+/* No FMA variants should be emitted with -ffp-contract=off. */
+/* { dg-final { scan-assembler-not {\tvfmadd\.vv} } } */
+/* { dg-final { scan-assembler-not {\tvfmsub\.vv} } } */
+/* { dg-final { scan-assembler-not {\tvfnmadd\.vv} } } */
+/* { dg-final { scan-assembler-not {\tvfnmsub\.vv} } } */
+/* { dg-final { scan-assembler-not {\tvfmacc\.vv} } } */
+/* { dg-final { scan-assembler-not {\tvfmsac\.vv} } } */
+/* { dg-final { scan-assembler-not {\tvfnmacc\.vv} } } */
+/* { dg-final { scan-assembler-not {\tvfnmsac\.vv} } } */
--
2.43.0