[llvm] 0676c6d - [RISCV] Support vector type strict_fma.

Yeting Kuo via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 27 18:01:55 PDT 2023


Author: Yeting Kuo
Date: 2023-03-28T09:01:46+08:00
New Revision: 0676c6d91fef302e0ae17f1a4571f28b1be1b27c

URL: https://github.com/llvm/llvm-project/commit/0676c6d91fef302e0ae17f1a4571f28b1be1b27c
DIFF: https://github.com/llvm/llvm-project/commit/0676c6d91fef302e0ae17f1a4571f28b1be1b27c.diff

LOG: [RISCV] Support vector type strict_fma.

Like D145900, the patch also supports fixed vector strict_fma nodes in RISC-V by
customized lowering them to riscv_strict_vfmadd_vl nodes. riscv_strict_vfmadd_vl
is created to avoid some riscv_vfmadd_vl optimizations happening to original
strict_fma nodes. The patch also adds combine patterns for riscv_strict_fmadd_vl
nodes with negation operands.

Reviewed By: craig.topper

Differential Revision: https://reviews.llvm.org/D146939

Added: 
    llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmadd-constrained-sdnode.ll
    llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmsub-constrained-sdnode.ll
    llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfnmadd-constrained-sdnode.ll
    llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfnmsub-constrained-sdnode.ll
    llvm/test/CodeGen/RISCV/rvv/vfmadd-constrained-sdnode.ll
    llvm/test/CodeGen/RISCV/rvv/vfmsub-constrained-sdnode.ll
    llvm/test/CodeGen/RISCV/rvv/vfnmadd-constrained-sdnode.ll
    llvm/test/CodeGen/RISCV/rvv/vfnmsub-constrained-sdnode.ll

Modified: 
    llvm/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/lib/Target/RISCV/RISCVISelLowering.h
    llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td
    llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 59744a204977..91ef4e8d06f1 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -806,7 +806,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
 
       setOperationAction(ISD::STRICT_FP_EXTEND, VT, Custom);
       setOperationAction({ISD::STRICT_FADD, ISD::STRICT_FSUB, ISD::STRICT_FMUL,
-                          ISD::STRICT_FDIV, ISD::STRICT_FSQRT},
+                          ISD::STRICT_FDIV, ISD::STRICT_FSQRT, ISD::STRICT_FMA},
                          VT, Legal);
     };
 
@@ -1024,7 +1024,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
         setOperationAction(ISD::STRICT_FP_EXTEND, VT, Custom);
         setOperationAction({ISD::STRICT_FADD, ISD::STRICT_FSUB,
                             ISD::STRICT_FMUL, ISD::STRICT_FDIV,
-                            ISD::STRICT_FSQRT},
+                            ISD::STRICT_FSQRT, ISD::STRICT_FMA},
                            VT, Custom);
       }
 
@@ -4506,6 +4506,8 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
                              /*HasMergeOp*/ true);
   case ISD::STRICT_FSQRT:
     return lowerToScalableOp(Op, DAG, RISCVISD::STRICT_FSQRT_VL);
+  case ISD::STRICT_FMA:
+    return lowerToScalableOp(Op, DAG, RISCVISD::STRICT_VFMADD_VL);
   case ISD::MGATHER:
   case ISD::VP_GATHER:
     return lowerMaskedGather(Op, DAG);
@@ -10386,6 +10388,10 @@ static unsigned negateFMAOpcode(unsigned Opcode, bool NegMul, bool NegAcc) {
     case RISCVISD::VFNMSUB_VL: Opcode = RISCVISD::VFMADD_VL;  break;
     case RISCVISD::VFNMADD_VL: Opcode = RISCVISD::VFMSUB_VL;  break;
     case RISCVISD::VFMSUB_VL:  Opcode = RISCVISD::VFNMADD_VL; break;
+    case RISCVISD::STRICT_VFMADD_VL:  Opcode = RISCVISD::STRICT_VFNMSUB_VL; break;
+    case RISCVISD::STRICT_VFNMSUB_VL: Opcode = RISCVISD::STRICT_VFMADD_VL;  break;
+    case RISCVISD::STRICT_VFNMADD_VL: Opcode = RISCVISD::STRICT_VFMSUB_VL;  break;
+    case RISCVISD::STRICT_VFMSUB_VL:  Opcode = RISCVISD::STRICT_VFNMADD_VL; break;
     }
     // clang-format on
   }
@@ -10399,6 +10405,10 @@ static unsigned negateFMAOpcode(unsigned Opcode, bool NegMul, bool NegAcc) {
     case RISCVISD::VFMSUB_VL:  Opcode = RISCVISD::VFMADD_VL;  break;
     case RISCVISD::VFNMADD_VL: Opcode = RISCVISD::VFNMSUB_VL; break;
     case RISCVISD::VFNMSUB_VL: Opcode = RISCVISD::VFNMADD_VL; break;
+    case RISCVISD::STRICT_VFMADD_VL:  Opcode = RISCVISD::STRICT_VFMSUB_VL;  break;
+    case RISCVISD::STRICT_VFMSUB_VL:  Opcode = RISCVISD::STRICT_VFMADD_VL;  break;
+    case RISCVISD::STRICT_VFNMADD_VL: Opcode = RISCVISD::STRICT_VFNMSUB_VL; break;
+    case RISCVISD::STRICT_VFNMSUB_VL: Opcode = RISCVISD::STRICT_VFNMADD_VL; break;
     }
     // clang-format on
   }
@@ -11146,13 +11156,19 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
   case RISCVISD::VFMADD_VL:
   case RISCVISD::VFNMADD_VL:
   case RISCVISD::VFMSUB_VL:
-  case RISCVISD::VFNMSUB_VL: {
+  case RISCVISD::VFNMSUB_VL:
+  case RISCVISD::STRICT_VFMADD_VL:
+  case RISCVISD::STRICT_VFNMADD_VL:
+  case RISCVISD::STRICT_VFMSUB_VL:
+  case RISCVISD::STRICT_VFNMSUB_VL: {
     // Fold FNEG_VL into FMA opcodes.
-    SDValue A = N->getOperand(0);
-    SDValue B = N->getOperand(1);
-    SDValue C = N->getOperand(2);
-    SDValue Mask = N->getOperand(3);
-    SDValue VL = N->getOperand(4);
+    // The first operand of strict-fp is chain.
+    unsigned Offset = N->isTargetStrictFPOpcode();
+    SDValue A = N->getOperand(0 + Offset);
+    SDValue B = N->getOperand(1 + Offset);
+    SDValue C = N->getOperand(2 + Offset);
+    SDValue Mask = N->getOperand(3 + Offset);
+    SDValue VL = N->getOperand(4 + Offset);
 
     auto invertIfNegative = [&Mask, &VL](SDValue &V) {
       if (V.getOpcode() == RISCVISD::FNEG_VL && V.getOperand(1) == Mask &&
@@ -11174,6 +11190,9 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
       return SDValue();
 
     unsigned NewOpcode = negateFMAOpcode(N->getOpcode(), NegA != NegB, NegC);
+    if (Offset > 0)
+      return DAG.getNode(NewOpcode, SDLoc(N), N->getVTList(),
+                         {N->getOperand(0), A, B, C, Mask, VL});
     return DAG.getNode(NewOpcode, SDLoc(N), N->getValueType(0), A, B, C, Mask,
                        VL);
   }
@@ -14102,6 +14121,10 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
   NODE_NAME_CASE(STRICT_FMUL_VL)
   NODE_NAME_CASE(STRICT_FDIV_VL)
   NODE_NAME_CASE(STRICT_FSQRT_VL)
+  NODE_NAME_CASE(STRICT_VFMADD_VL)
+  NODE_NAME_CASE(STRICT_VFNMADD_VL)
+  NODE_NAME_CASE(STRICT_VFMSUB_VL)
+  NODE_NAME_CASE(STRICT_VFNMSUB_VL)
   NODE_NAME_CASE(STRICT_FP_EXTEND_VL)
   NODE_NAME_CASE(VWMUL_VL)
   NODE_NAME_CASE(VWMULU_VL)

diff  --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index 8182ef729825..41d71fca13a6 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -335,6 +335,10 @@ enum NodeType : unsigned {
   STRICT_FMUL_VL,
   STRICT_FDIV_VL,
   STRICT_FSQRT_VL,
+  STRICT_VFMADD_VL,
+  STRICT_VFNMADD_VL,
+  STRICT_VFMSUB_VL,
+  STRICT_VFNMSUB_VL,
   STRICT_FP_EXTEND_VL,
 
   // WARNING: Do not add anything in the end unless you want the node to

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td
index ed76f8182789..816a3dce5fb7 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td
@@ -939,59 +939,59 @@ foreach fvti = AllFloatVectors in {
   // NOTE: We choose VFMADD because it has the most commuting freedom. So it
   // works best with how TwoAddressInstructionPass tries commuting.
   defvar suffix = fvti.LMul.MX;
-  def : Pat<(fvti.Vector (fma fvti.RegClass:$rs1, fvti.RegClass:$rd,
-                              fvti.RegClass:$rs2)),
+  def : Pat<(fvti.Vector (any_fma fvti.RegClass:$rs1, fvti.RegClass:$rd,
+                                  fvti.RegClass:$rs2)),
             (!cast<Instruction>("PseudoVFMADD_VV_"# suffix)
                  fvti.RegClass:$rd, fvti.RegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;
-  def : Pat<(fvti.Vector (fma fvti.RegClass:$rs1, fvti.RegClass:$rd,
-                              (fneg fvti.RegClass:$rs2))),
+  def : Pat<(fvti.Vector (any_fma fvti.RegClass:$rs1, fvti.RegClass:$rd,
+                                  (fneg fvti.RegClass:$rs2))),
             (!cast<Instruction>("PseudoVFMSUB_VV_"# suffix)
                  fvti.RegClass:$rd, fvti.RegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;
-  def : Pat<(fvti.Vector (fma (fneg fvti.RegClass:$rs1), fvti.RegClass:$rd,
-                              (fneg fvti.RegClass:$rs2))),
+  def : Pat<(fvti.Vector (any_fma (fneg fvti.RegClass:$rs1), fvti.RegClass:$rd,
+                                  (fneg fvti.RegClass:$rs2))),
             (!cast<Instruction>("PseudoVFNMADD_VV_"# suffix)
                  fvti.RegClass:$rd, fvti.RegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;
-  def : Pat<(fvti.Vector (fma (fneg fvti.RegClass:$rs1), fvti.RegClass:$rd,
-                              fvti.RegClass:$rs2)),
+  def : Pat<(fvti.Vector (any_fma (fneg fvti.RegClass:$rs1), fvti.RegClass:$rd,
+                                  fvti.RegClass:$rs2)),
             (!cast<Instruction>("PseudoVFNMSUB_VV_"# suffix)
                  fvti.RegClass:$rd, fvti.RegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;
 
   // The choice of VFMADD here is arbitrary, vfmadd.vf and vfmacc.vf are equally
   // commutable.
-  def : Pat<(fvti.Vector (fma (SplatFPOp fvti.ScalarRegClass:$rs1),
-                              fvti.RegClass:$rd, fvti.RegClass:$rs2)),
+  def : Pat<(fvti.Vector (any_fma (SplatFPOp fvti.ScalarRegClass:$rs1),
+                                  fvti.RegClass:$rd, fvti.RegClass:$rs2)),
             (!cast<Instruction>("PseudoVFMADD_V" # fvti.ScalarSuffix # "_" # suffix)
                  fvti.RegClass:$rd, fvti.ScalarRegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;
-  def : Pat<(fvti.Vector (fma (SplatFPOp fvti.ScalarRegClass:$rs1),
-                              fvti.RegClass:$rd, (fneg fvti.RegClass:$rs2))),
+  def : Pat<(fvti.Vector (any_fma (SplatFPOp fvti.ScalarRegClass:$rs1),
+                                  fvti.RegClass:$rd, (fneg fvti.RegClass:$rs2))),
             (!cast<Instruction>("PseudoVFMSUB_V" # fvti.ScalarSuffix # "_" # suffix)
                  fvti.RegClass:$rd, fvti.ScalarRegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;
 
-  def : Pat<(fvti.Vector (fma (SplatFPOp fvti.ScalarRegClass:$rs1),
-                              (fneg fvti.RegClass:$rd), (fneg fvti.RegClass:$rs2))),
+  def : Pat<(fvti.Vector (any_fma (SplatFPOp fvti.ScalarRegClass:$rs1),
+                                  (fneg fvti.RegClass:$rd), (fneg fvti.RegClass:$rs2))),
             (!cast<Instruction>("PseudoVFNMADD_V" # fvti.ScalarSuffix # "_" # suffix)
                  fvti.RegClass:$rd, fvti.ScalarRegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;
-  def : Pat<(fvti.Vector (fma (SplatFPOp fvti.ScalarRegClass:$rs1),
-                              (fneg fvti.RegClass:$rd), fvti.RegClass:$rs2)),
+  def : Pat<(fvti.Vector (any_fma (SplatFPOp fvti.ScalarRegClass:$rs1),
+                                  (fneg fvti.RegClass:$rd), fvti.RegClass:$rs2)),
             (!cast<Instruction>("PseudoVFNMSUB_V" # fvti.ScalarSuffix # "_" # suffix)
                  fvti.RegClass:$rd, fvti.ScalarRegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;
 
   // The splat might be negated.
-  def : Pat<(fvti.Vector (fma (fneg (SplatFPOp fvti.ScalarRegClass:$rs1)),
-                              fvti.RegClass:$rd, (fneg fvti.RegClass:$rs2))),
+  def : Pat<(fvti.Vector (any_fma (fneg (SplatFPOp fvti.ScalarRegClass:$rs1)),
+                                  fvti.RegClass:$rd, (fneg fvti.RegClass:$rs2))),
             (!cast<Instruction>("PseudoVFNMADD_V" # fvti.ScalarSuffix # "_" # suffix)
                  fvti.RegClass:$rd, fvti.ScalarRegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;
-  def : Pat<(fvti.Vector (fma (fneg (SplatFPOp fvti.ScalarRegClass:$rs1)),
-                              fvti.RegClass:$rd, fvti.RegClass:$rs2)),
+  def : Pat<(fvti.Vector (any_fma (fneg (SplatFPOp fvti.ScalarRegClass:$rs1)),
+                                  fvti.RegClass:$rd, fvti.RegClass:$rs2)),
             (!cast<Instruction>("PseudoVFNMSUB_V" # fvti.ScalarSuffix # "_" # suffix)
                  fvti.RegClass:$rd, fvti.ScalarRegClass:$rs1, fvti.RegClass:$rs2,
                  fvti.AVL, fvti.Log2SEW, TAIL_AGNOSTIC)>;

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td
index 0dabf8d10782..5d6567ffff1d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td
@@ -141,6 +141,24 @@ def riscv_vfnmadd_vl : SDNode<"RISCVISD::VFNMADD_VL", SDT_RISCVVecFMA_VL, [SDNPC
 def riscv_vfmsub_vl : SDNode<"RISCVISD::VFMSUB_VL", SDT_RISCVVecFMA_VL, [SDNPCommutative]>;
 def riscv_vfnmsub_vl : SDNode<"RISCVISD::VFNMSUB_VL", SDT_RISCVVecFMA_VL, [SDNPCommutative]>;
 
+def riscv_strict_vfmadd_vl : SDNode<"RISCVISD::STRICT_VFMADD_VL", SDT_RISCVVecFMA_VL, [SDNPCommutative, SDNPHasChain]>;
+def riscv_strict_vfnmadd_vl : SDNode<"RISCVISD::STRICT_VFNMADD_VL", SDT_RISCVVecFMA_VL, [SDNPCommutative, SDNPHasChain]>;
+def riscv_strict_vfmsub_vl : SDNode<"RISCVISD::STRICT_VFMSUB_VL", SDT_RISCVVecFMA_VL, [SDNPCommutative, SDNPHasChain]>;
+def riscv_strict_vfnmsub_vl : SDNode<"RISCVISD::STRICT_VFNMSUB_VL", SDT_RISCVVecFMA_VL, [SDNPCommutative, SDNPHasChain]>;
+
+def any_riscv_vfmadd_vl : PatFrags<(ops node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl),
+                        [(riscv_vfmadd_vl node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl),
+                         (riscv_strict_vfmadd_vl node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl)]>;
+def any_riscv_vfnmadd_vl : PatFrags<(ops node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl),
+                        [(riscv_vfnmadd_vl node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl),
+                         (riscv_strict_vfnmadd_vl node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl)]>;
+def any_riscv_vfmsub_vl : PatFrags<(ops node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl),
+                        [(riscv_vfmsub_vl node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl),
+                         (riscv_strict_vfmsub_vl node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl)]>;
+def any_riscv_vfnmsub_vl : PatFrags<(ops node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl),
+                        [(riscv_vfnmsub_vl node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl),
+                         (riscv_strict_vfnmsub_vl node:$rs1, node:$rs2, node:$rs3, node:$mask, node:$vl)]>;
+
 def SDT_RISCVFPRoundOp_VL  : SDTypeProfile<1, 3, [
   SDTCisFP<0>, SDTCisFP<1>, SDTCisOpSmallerThanOp<0, 1>, SDTCisSameNumEltsAs<0, 1>,
   SDTCVecEltisVT<2, i1>, SDTCisSameNumEltsAs<1, 2>, SDTCisVT<3, XLenVT>
@@ -1395,7 +1413,7 @@ multiclass VPatNarrowShiftSplat_WX_WI<SDNode op, string instruction_name> {
   }
 }
 
-multiclass VPatFPMulAddVL_VV_VF<SDNode vop, string instruction_name> {
+multiclass VPatFPMulAddVL_VV_VF<SDPatternOperator vop, string instruction_name> {
   foreach vti = AllFloatVectors in {
   defvar suffix = vti.LMul.MX;
   def : Pat<(vti.Vector (vop vti.RegClass:$rs1, vti.RegClass:$rd,
@@ -1783,10 +1801,10 @@ defm : VPatBinaryFPVL_R_VF_E<any_riscv_fdiv_vl, "PseudoVFRDIV">;
 defm : VPatWidenBinaryFPVL_VV_VF<riscv_fmul_vl, riscv_fpextend_vl_oneuse, "PseudoVFWMUL">;
 
 // 13.6 Vector Single-Width Floating-Point Fused Multiply-Add Instructions.
-defm : VPatFPMulAddVL_VV_VF<riscv_vfmadd_vl,  "PseudoVFMADD">;
-defm : VPatFPMulAddVL_VV_VF<riscv_vfmsub_vl,  "PseudoVFMSUB">;
-defm : VPatFPMulAddVL_VV_VF<riscv_vfnmadd_vl, "PseudoVFNMADD">;
-defm : VPatFPMulAddVL_VV_VF<riscv_vfnmsub_vl, "PseudoVFNMSUB">;
+defm : VPatFPMulAddVL_VV_VF<any_riscv_vfmadd_vl,  "PseudoVFMADD">;
+defm : VPatFPMulAddVL_VV_VF<any_riscv_vfmsub_vl,  "PseudoVFMSUB">;
+defm : VPatFPMulAddVL_VV_VF<any_riscv_vfnmadd_vl, "PseudoVFNMADD">;
+defm : VPatFPMulAddVL_VV_VF<any_riscv_vfnmsub_vl, "PseudoVFNMSUB">;
 defm : VPatFPMulAccVL_VV_VF<riscv_vfmadd_vl_oneuse,  "PseudoVFMACC">;
 defm : VPatFPMulAccVL_VV_VF<riscv_vfmsub_vl_oneuse,  "PseudoVFMSAC">;
 defm : VPatFPMulAccVL_VV_VF<riscv_vfnmadd_vl_oneuse, "PseudoVFNMACC">;

diff  --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmadd-constrained-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmadd-constrained-sdnode.ll
new file mode 100644
index 000000000000..b7d81e59c234
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmadd-constrained-sdnode.ll
@@ -0,0 +1,298 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=ilp32d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=lp64d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+
+; This tests a mix of vfmacc and vfmadd by using 
diff erent operand orders to
+; trigger commuting in TwoAddressInstructionPass.
+
+declare <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half>, <2 x half>, <2 x half>, metadata, metadata)
+
+define <2 x half> @vfmadd_vv_v2f16(<2 x half> %va, <2 x half> %vb, <2 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_v2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e16, mf4, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %vd = call <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half> %va, <2 x half> %vc, <2 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x half> %vd
+}
+
+define <2 x half> @vfmadd_vf_v2f16(<2 x half> %va, <2 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_v2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e16, mf4, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x half> poison, half %c, i32 0
+  %splat = shufflevector <2 x half> %head, <2 x half> poison, <2 x i32> zeroinitializer
+  %vd = call <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half> %vb, <2 x half> %splat, <2 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x half> %vd
+}
+
+declare <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half>, <4 x half>, <4 x half>, metadata, metadata)
+
+define <4 x half> @vfmadd_vv_v4f16(<4 x half> %va, <4 x half> %vb, <4 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_v4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e16, mf2, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %vd = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> %vb, <4 x half> %va, <4 x half> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x half> %vd
+}
+
+define <4 x half> @vfmadd_vf_v4f16(<4 x half> %va, <4 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_v4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e16, mf2, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x half> poison, half %c, i32 0
+  %splat = shufflevector <4 x half> %head, <4 x half> poison, <4 x i32> zeroinitializer
+  %vd = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> %va, <4 x half> %splat, <4 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x half> %vd
+}
+
+declare <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half>, <8 x half>, <8 x half>, metadata, metadata)
+
+define <8 x half> @vfmadd_vv_v8f16(<8 x half> %va, <8 x half> %vb, <8 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_v8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT:    vfmacc.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %vd = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> %vb, <8 x half> %vc, <8 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x half> %vd
+}
+
+define <8 x half> @vfmadd_vf_v8f16(<8 x half> %va, <8 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_v8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x half> poison, half %c, i32 0
+  %splat = shufflevector <8 x half> %head, <8 x half> poison, <8 x i32> zeroinitializer
+  %vd = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> %vb, <8 x half> %splat, <8 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x half> %vd
+}
+
+declare <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half>, <16 x half>, <16 x half>, metadata, metadata)
+
+define <16 x half> @vfmadd_vv_v16f16(<16 x half> %va, <16 x half> %vb, <16 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_v16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e16, m2, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %vd = call <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half> %vc, <16 x half> %va, <16 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x half> %vd
+}
+
+define <16 x half> @vfmadd_vf_v16f16(<16 x half> %va, <16 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_v16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e16, m2, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <16 x half> poison, half %c, i32 0
+  %splat = shufflevector <16 x half> %head, <16 x half> poison, <16 x i32> zeroinitializer
+  %vd = call <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half> %va, <16 x half> %splat, <16 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x half> %vd
+}
+
+declare <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half>, <32 x half>, <32 x half>, metadata, metadata)
+
+define <32 x half> @vfmadd_vv_v32f16(<32 x half> %va, <32 x half> %vb, <32 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_v32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 32
+; CHECK-NEXT:    vsetvli zero, a0, e16, m4, ta, ma
+; CHECK-NEXT:    vfmacc.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %vd = call <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half> %vc, <32 x half> %vb, <32 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <32 x half> %vd
+}
+
+define <32 x half> @vfmadd_vf_v32f16(<32 x half> %va, <32 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_v32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 32
+; CHECK-NEXT:    vsetvli zero, a0, e16, m4, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <32 x half> poison, half %c, i32 0
+  %splat = shufflevector <32 x half> %head, <32 x half> poison, <32 x i32> zeroinitializer
+  %vd = call <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half> %vb, <32 x half> %splat, <32 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <32 x half> %vd
+}
+
+declare <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float>, <2 x float>, <2 x float>, metadata, metadata)
+
+define <2 x float> @vfmadd_vv_v2f32(<2 x float> %va, <2 x float> %vb, <2 x float> %vc) {
+; CHECK-LABEL: vfmadd_vv_v2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e32, mf2, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %vd = call <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float> %va, <2 x float> %vc, <2 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x float> %vd
+}
+
+define <2 x float> @vfmadd_vf_v2f32(<2 x float> %va, <2 x float> %vb, float %c) {
+; CHECK-LABEL: vfmadd_vf_v2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e32, mf2, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x float> poison, float %c, i32 0
+  %splat = shufflevector <2 x float> %head, <2 x float> poison, <2 x i32> zeroinitializer
+  %vd = call <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float> %vb, <2 x float> %splat, <2 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x float> %vd
+}
+
+declare <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float>, <4 x float>, <4 x float>, metadata, metadata)
+
+define <4 x float> @vfmadd_vv_v4f32(<4 x float> %va, <4 x float> %vb, <4 x float> %vc) {
+; CHECK-LABEL: vfmadd_vv_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %vd = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %vb, <4 x float> %va, <4 x float> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x float> %vd
+}
+
+define <4 x float> @vfmadd_vf_v4f32(<4 x float> %va, <4 x float> %vb, float %c) {
+; CHECK-LABEL: vfmadd_vf_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x float> poison, float %c, i32 0
+  %splat = shufflevector <4 x float> %head, <4 x float> poison, <4 x i32> zeroinitializer
+  %vd = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %va, <4 x float> %splat, <4 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x float> %vd
+}
+
+declare <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float>, <8 x float>, <8 x float>, metadata, metadata)
+
+define <8 x float> @vfmadd_vv_v8f32(<8 x float> %va, <8 x float> %vb, <8 x float> %vc) {
+; CHECK-LABEL: vfmadd_vv_v8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT:    vfmacc.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %vd = call <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float> %vb, <8 x float> %vc, <8 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x float> %vd
+}
+
+define <8 x float> @vfmadd_vf_v8f32(<8 x float> %va, <8 x float> %vb, float %c) {
+; CHECK-LABEL: vfmadd_vf_v8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x float> poison, float %c, i32 0
+  %splat = shufflevector <8 x float> %head, <8 x float> poison, <8 x i32> zeroinitializer
+  %vd = call <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float> %vb, <8 x float> %splat, <8 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x float> %vd
+}
+
+declare <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float>, <16 x float>, <16 x float>, metadata, metadata)
+
+define <16 x float> @vfmadd_vv_v16f32(<16 x float> %va, <16 x float> %vb, <16 x float> %vc) {
+; CHECK-LABEL: vfmadd_vv_v16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e32, m4, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %vd = call <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float> %vc, <16 x float> %va, <16 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x float> %vd
+}
+
+define <16 x float> @vfmadd_vf_v16f32(<16 x float> %va, <16 x float> %vb, float %c) {
+; CHECK-LABEL: vfmadd_vf_v16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e32, m4, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <16 x float> poison, float %c, i32 0
+  %splat = shufflevector <16 x float> %head, <16 x float> poison, <16 x i32> zeroinitializer
+  %vd = call <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float> %va, <16 x float> %splat, <16 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x float> %vd
+}
+
+declare <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double>, <2 x double>, <2 x double>, metadata, metadata)
+
+define <2 x double> @vfmadd_vv_v2f64(<2 x double> %va, <2 x double> %vb, <2 x double> %vc) {
+; CHECK-LABEL: vfmadd_vv_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %vd = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %va, <2 x double> %vc, <2 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x double> %vd
+}
+
+define <2 x double> @vfmadd_vf_v2f64(<2 x double> %va, <2 x double> %vb, double %c) {
+; CHECK-LABEL: vfmadd_vf_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x double> poison, double %c, i32 0
+  %splat = shufflevector <2 x double> %head, <2 x double> poison, <2 x i32> zeroinitializer
+  %vd = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %vb, <2 x double> %splat, <2 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x double> %vd
+}
+
+declare <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double>, <4 x double>, <4 x double>, metadata, metadata)
+
+define <4 x double> @vfmadd_vv_v4f64(<4 x double> %va, <4 x double> %vb, <4 x double> %vc) {
+; CHECK-LABEL: vfmadd_vv_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e64, m2, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v10, v12
+; CHECK-NEXT:    ret
+  %vd = call <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double> %vb, <4 x double> %va, <4 x double> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x double> %vd
+}
+
+define <4 x double> @vfmadd_vf_v4f64(<4 x double> %va, <4 x double> %vb, double %c) {
+; CHECK-LABEL: vfmadd_vf_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e64, m2, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x double> poison, double %c, i32 0
+  %splat = shufflevector <4 x double> %head, <4 x double> poison, <4 x i32> zeroinitializer
+  %vd = call <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double> %va, <4 x double> %splat, <4 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x double> %vd
+}
+
+declare <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double>, <8 x double>, <8 x double>, metadata, metadata)
+
+define <8 x double> @vfmadd_vv_v8f64(<8 x double> %va, <8 x double> %vb, <8 x double> %vc) {
+; CHECK-LABEL: vfmadd_vv_v8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e64, m4, ta, ma
+; CHECK-NEXT:    vfmacc.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %vd = call <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double> %vb, <8 x double> %vc, <8 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x double> %vd
+}
+
+define <8 x double> @vfmadd_vf_v8f64(<8 x double> %va, <8 x double> %vb, double %c) {
+; CHECK-LABEL: vfmadd_vf_v8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e64, m4, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x double> poison, double %c, i32 0
+  %splat = shufflevector <8 x double> %head, <8 x double> poison, <8 x i32> zeroinitializer
+  %vd = call <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double> %vb, <8 x double> %splat, <8 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x double> %vd
+}

diff  --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmsub-constrained-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmsub-constrained-sdnode.ll
new file mode 100644
index 000000000000..4dd695477371
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmsub-constrained-sdnode.ll
@@ -0,0 +1,322 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=ilp32d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=lp64d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+
+; This tests a mix of vfmsac and vfmsub by using 
diff erent operand orders to
+; trigger commuting in TwoAddressInstructionPass.
+
+declare <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half>, <2 x half>, <2 x half>, metadata, metadata)
+
+define <2 x half> @vfmsub_vv_v2f16(<2 x half> %va, <2 x half> %vb, <2 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_v2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e16, mf4, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <2 x half> %vb
+  %vd = call <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half> %va, <2 x half> %vc, <2 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x half> %vd
+}
+
+define <2 x half> @vfmsub_vf_v2f16(<2 x half> %va, <2 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_v2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e16, mf4, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x half> poison, half %c, i32 0
+  %splat = shufflevector <2 x half> %head, <2 x half> poison, <2 x i32> zeroinitializer
+  %neg = fneg <2 x half> %va
+  %vd = call <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half> %vb, <2 x half> %splat, <2 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x half> %vd
+}
+
+declare <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half>, <4 x half>, <4 x half>, metadata, metadata)
+
+define <4 x half> @vfmsub_vv_v4f16(<4 x half> %va, <4 x half> %vb, <4 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_v4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e16, mf2, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <4 x half> %vc
+  %vd = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> %vb, <4 x half> %va, <4 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x half> %vd
+}
+
+define <4 x half> @vfmsub_vf_v4f16(<4 x half> %va, <4 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_v4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e16, mf2, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x half> poison, half %c, i32 0
+  %splat = shufflevector <4 x half> %head, <4 x half> poison, <4 x i32> zeroinitializer
+  %neg = fneg <4 x half> %vb
+  %vd = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> %va, <4 x half> %splat, <4 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x half> %vd
+}
+
+declare <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half>, <8 x half>, <8 x half>, metadata, metadata)
+
+define <8 x half> @vfmsub_vv_v8f16(<8 x half> %va, <8 x half> %vb, <8 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_v8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT:    vfmsac.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <8 x half> %va
+  %vd = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> %vb, <8 x half> %vc, <8 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x half> %vd
+}
+
+define <8 x half> @vfmsub_vf_v8f16(<8 x half> %va, <8 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_v8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x half> poison, half %c, i32 0
+  %splat = shufflevector <8 x half> %head, <8 x half> poison, <8 x i32> zeroinitializer
+  %neg = fneg <8 x half> %va
+  %vd = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> %vb, <8 x half> %splat, <8 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x half> %vd
+}
+
+declare <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half>, <16 x half>, <16 x half>, metadata, metadata)
+
+define <16 x half> @vfmsub_vv_v16f16(<16 x half> %va, <16 x half> %vb, <16 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_v16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e16, m2, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <16 x half> %vb
+  %vd = call <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half> %vc, <16 x half> %va, <16 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x half> %vd
+}
+
+define <16 x half> @vfmsub_vf_v16f16(<16 x half> %va, <16 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_v16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e16, m2, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <16 x half> poison, half %c, i32 0
+  %splat = shufflevector <16 x half> %head, <16 x half> poison, <16 x i32> zeroinitializer
+  %neg = fneg <16 x half> %vb
+  %vd = call <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half> %va, <16 x half> %splat, <16 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x half> %vd
+}
+
+declare <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half>, <32 x half>, <32 x half>, metadata, metadata)
+
+define <32 x half> @vfmsub_vv_v32f16(<32 x half> %va, <32 x half> %vb, <32 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_v32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 32
+; CHECK-NEXT:    vsetvli zero, a0, e16, m4, ta, ma
+; CHECK-NEXT:    vfmsac.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <32 x half> %va
+  %vd = call <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half> %vc, <32 x half> %vb, <32 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <32 x half> %vd
+}
+
+define <32 x half> @vfmsub_vf_v32f16(<32 x half> %va, <32 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_v32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 32
+; CHECK-NEXT:    vsetvli zero, a0, e16, m4, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <32 x half> poison, half %c, i32 0
+  %splat = shufflevector <32 x half> %head, <32 x half> poison, <32 x i32> zeroinitializer
+  %neg = fneg <32 x half> %va
+  %vd = call <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half> %vb, <32 x half> %splat, <32 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <32 x half> %vd
+}
+
+declare <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float>, <2 x float>, <2 x float>, metadata, metadata)
+
+define <2 x float> @vfmsub_vv_v2f32(<2 x float> %va, <2 x float> %vb, <2 x float> %vc) {
+; CHECK-LABEL: vfmsub_vv_v2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e32, mf2, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <2 x float> %vb
+  %vd = call <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float> %va, <2 x float> %vc, <2 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x float> %vd
+}
+
+define <2 x float> @vfmsub_vf_v2f32(<2 x float> %va, <2 x float> %vb, float %c) {
+; CHECK-LABEL: vfmsub_vf_v2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e32, mf2, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x float> poison, float %c, i32 0
+  %splat = shufflevector <2 x float> %head, <2 x float> poison, <2 x i32> zeroinitializer
+  %neg = fneg <2 x float> %va
+  %vd = call <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float> %vb, <2 x float> %splat, <2 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x float> %vd
+}
+
+declare <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float>, <4 x float>, <4 x float>, metadata, metadata)
+
+define <4 x float> @vfmsub_vv_v4f32(<4 x float> %va, <4 x float> %vb, <4 x float> %vc) {
+; CHECK-LABEL: vfmsub_vv_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <4 x float> %vc
+  %vd = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %vb, <4 x float> %va, <4 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x float> %vd
+}
+
+define <4 x float> @vfmsub_vf_v4f32(<4 x float> %va, <4 x float> %vb, float %c) {
+; CHECK-LABEL: vfmsub_vf_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x float> poison, float %c, i32 0
+  %splat = shufflevector <4 x float> %head, <4 x float> poison, <4 x i32> zeroinitializer
+  %neg = fneg <4 x float> %vb
+  %vd = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %va, <4 x float> %splat, <4 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x float> %vd
+}
+
+declare <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float>, <8 x float>, <8 x float>, metadata, metadata)
+
+define <8 x float> @vfmsub_vv_v8f32(<8 x float> %va, <8 x float> %vb, <8 x float> %vc) {
+; CHECK-LABEL: vfmsub_vv_v8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT:    vfmsac.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <8 x float> %va
+  %vd = call <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float> %vb, <8 x float> %vc, <8 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x float> %vd
+}
+
+define <8 x float> @vfmsub_vf_v8f32(<8 x float> %va, <8 x float> %vb, float %c) {
+; CHECK-LABEL: vfmsub_vf_v8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x float> poison, float %c, i32 0
+  %splat = shufflevector <8 x float> %head, <8 x float> poison, <8 x i32> zeroinitializer
+  %neg = fneg <8 x float> %va
+  %vd = call <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float> %vb, <8 x float> %splat, <8 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x float> %vd
+}
+
+declare <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float>, <16 x float>, <16 x float>, metadata, metadata)
+
+define <16 x float> @vfmsub_vv_v16f32(<16 x float> %va, <16 x float> %vb, <16 x float> %vc) {
+; CHECK-LABEL: vfmsub_vv_v16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e32, m4, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <16 x float> %vb
+  %vd = call <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float> %vc, <16 x float> %va, <16 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x float> %vd
+}
+
+define <16 x float> @vfmsub_vf_v16f32(<16 x float> %va, <16 x float> %vb, float %c) {
+; CHECK-LABEL: vfmsub_vf_v16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e32, m4, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <16 x float> poison, float %c, i32 0
+  %splat = shufflevector <16 x float> %head, <16 x float> poison, <16 x i32> zeroinitializer
+  %neg = fneg <16 x float> %vb
+  %vd = call <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float> %va, <16 x float> %splat, <16 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x float> %vd
+}
+
+declare <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double>, <2 x double>, <2 x double>, metadata, metadata)
+
+define <2 x double> @vfmsub_vv_v2f64(<2 x double> %va, <2 x double> %vb, <2 x double> %vc) {
+; CHECK-LABEL: vfmsub_vv_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <2 x double> %vb
+  %vd = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %va, <2 x double> %vc, <2 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x double> %vd
+}
+
+define <2 x double> @vfmsub_vf_v2f64(<2 x double> %va, <2 x double> %vb, double %c) {
+; CHECK-LABEL: vfmsub_vf_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x double> poison, double %c, i32 0
+  %splat = shufflevector <2 x double> %head, <2 x double> poison, <2 x i32> zeroinitializer
+  %neg = fneg <2 x double> %va
+  %vd = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %vb, <2 x double> %splat, <2 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x double> %vd
+}
+
+declare <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double>, <4 x double>, <4 x double>, metadata, metadata)
+
+define <4 x double> @vfmsub_vv_v4f64(<4 x double> %va, <4 x double> %vb, <4 x double> %vc) {
+; CHECK-LABEL: vfmsub_vv_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e64, m2, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v10, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <4 x double> %vc
+  %vd = call <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double> %vb, <4 x double> %va, <4 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x double> %vd
+}
+
+define <4 x double> @vfmsub_vf_v4f64(<4 x double> %va, <4 x double> %vb, double %c) {
+; CHECK-LABEL: vfmsub_vf_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e64, m2, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x double> poison, double %c, i32 0
+  %splat = shufflevector <4 x double> %head, <4 x double> poison, <4 x i32> zeroinitializer
+  %neg = fneg <4 x double> %vb
+  %vd = call <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double> %va, <4 x double> %splat, <4 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x double> %vd
+}
+
+declare <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double>, <8 x double>, <8 x double>, metadata, metadata)
+
+define <8 x double> @vfmsub_vv_v8f64(<8 x double> %va, <8 x double> %vb, <8 x double> %vc) {
+; CHECK-LABEL: vfmsub_vv_v8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e64, m4, ta, ma
+; CHECK-NEXT:    vfmsac.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <8 x double> %va
+  %vd = call <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double> %vb, <8 x double> %vc, <8 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x double> %vd
+}
+
+define <8 x double> @vfmsub_vf_v8f64(<8 x double> %va, <8 x double> %vb, double %c) {
+; CHECK-LABEL: vfmsub_vf_v8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e64, m4, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x double> poison, double %c, i32 0
+  %splat = shufflevector <8 x double> %head, <8 x double> poison, <8 x i32> zeroinitializer
+  %neg = fneg <8 x double> %va
+  %vd = call <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double> %vb, <8 x double> %splat, <8 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x double> %vd
+}

diff  --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfnmadd-constrained-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfnmadd-constrained-sdnode.ll
new file mode 100644
index 000000000000..4293ce970f8c
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfnmadd-constrained-sdnode.ll
@@ -0,0 +1,346 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=ilp32d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=lp64d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+
+; This tests a mix of vfnmacc and vfnmadd by using 
diff erent operand orders to
+; trigger commuting in TwoAddressInstructionPass.
+
+declare <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half>, <2 x half>, <2 x half>, metadata, metadata)
+
+define <2 x half> @vfnmsub_vv_v2f16(<2 x half> %va, <2 x half> %vb, <2 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e16, mf4, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <2 x half> %va
+  %neg2 = fneg <2 x half> %vb
+  %vd = call <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half> %neg, <2 x half> %vc, <2 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x half> %vd
+}
+
+define <2 x half> @vfnmsub_vf_v2f16(<2 x half> %va, <2 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e16, mf4, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x half> poison, half %c, i32 0
+  %splat = shufflevector <2 x half> %head, <2 x half> poison, <2 x i32> zeroinitializer
+  %neg = fneg <2 x half> %va
+  %neg2 = fneg <2 x half> %vb
+  %vd = call <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half> %splat, <2 x half> %neg, <2 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x half> %vd
+}
+
+declare <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half>, <4 x half>, <4 x half>, metadata, metadata)
+
+define <4 x half> @vfnmsub_vv_v4f16(<4 x half> %va, <4 x half> %vb, <4 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e16, mf2, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <4 x half> %vb
+  %neg2 = fneg <4 x half> %vc
+  %vd = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> %neg, <4 x half> %va, <4 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x half> %vd
+}
+
+define <4 x half> @vfnmsub_vf_v4f16(<4 x half> %va, <4 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e16, mf2, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x half> poison, half %c, i32 0
+  %splat = shufflevector <4 x half> %head, <4 x half> poison, <4 x i32> zeroinitializer
+  %neg = fneg <4 x half> %splat
+  %neg2 = fneg <4 x half> %vb
+  %vd = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> %va, <4 x half> %neg, <4 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x half> %vd
+}
+
+declare <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half>, <8 x half>, <8 x half>, metadata, metadata)
+
+define <8 x half> @vfnmsub_vv_v8f16(<8 x half> %va, <8 x half> %vb, <8 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT:    vfnmacc.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <8 x half> %vb
+  %neg2 = fneg <8 x half> %va
+  %vd = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> %neg, <8 x half> %vc, <8 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x half> %vd
+}
+
+define <8 x half> @vfnmsub_vf_v8f16(<8 x half> %va, <8 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT:    vfnmacc.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x half> poison, half %c, i32 0
+  %splat = shufflevector <8 x half> %head, <8 x half> poison, <8 x i32> zeroinitializer
+  %neg = fneg <8 x half> %splat
+  %neg2 = fneg <8 x half> %va
+  %vd = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> %vb, <8 x half> %neg, <8 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x half> %vd
+}
+
+declare <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half>, <16 x half>, <16 x half>, metadata, metadata)
+
+define <16 x half> @vfnmsub_vv_v16f16(<16 x half> %va, <16 x half> %vb, <16 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e16, m2, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <16 x half> %vc
+  %neg2 = fneg <16 x half> %vb
+  %vd = call <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half> %neg, <16 x half> %va, <16 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x half> %vd
+}
+
+define <16 x half> @vfnmsub_vf_v16f16(<16 x half> %va, <16 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e16, m2, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <16 x half> poison, half %c, i32 0
+  %splat = shufflevector <16 x half> %head, <16 x half> poison, <16 x i32> zeroinitializer
+  %neg = fneg <16 x half> %splat
+  %neg2 = fneg <16 x half> %vb
+  %vd = call <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half> %neg, <16 x half> %va, <16 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x half> %vd
+}
+
+declare <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half>, <32 x half>, <32 x half>, metadata, metadata)
+
+define <32 x half> @vfnmsub_vv_v32f16(<32 x half> %va, <32 x half> %vb, <32 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 32
+; CHECK-NEXT:    vsetvli zero, a0, e16, m4, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <32 x half> %vc
+  %neg2 = fneg <32 x half> %vb
+  %vd = call <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half> %neg, <32 x half> %va, <32 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <32 x half> %vd
+}
+
+define <32 x half> @vfnmsub_vf_v32f16(<32 x half> %va, <32 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 32
+; CHECK-NEXT:    vsetvli zero, a0, e16, m4, ta, ma
+; CHECK-NEXT:    vfnmacc.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <32 x half> poison, half %c, i32 0
+  %splat = shufflevector <32 x half> %head, <32 x half> poison, <32 x i32> zeroinitializer
+  %neg = fneg <32 x half> %splat
+  %neg2 = fneg <32 x half> %va
+  %vd = call <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half> %neg, <32 x half> %vb, <32 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <32 x half> %vd
+}
+
+declare <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float>, <2 x float>, <2 x float>, metadata, metadata)
+
+define <2 x float> @vfnmsub_vv_v2f32(<2 x float> %va, <2 x float> %vb, <2 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e32, mf2, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <2 x float> %vc
+  %neg2 = fneg <2 x float> %vb
+  %vd = call <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float> %va, <2 x float> %neg, <2 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x float> %vd
+}
+
+define <2 x float> @vfnmsub_vf_v2f32(<2 x float> %va, <2 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_v2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e32, mf2, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x float> poison, float %c, i32 0
+  %splat = shufflevector <2 x float> %head, <2 x float> poison, <2 x i32> zeroinitializer
+  %neg = fneg <2 x float> %va
+  %neg2 = fneg <2 x float> %vb
+  %vd = call <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float> %splat, <2 x float> %neg, <2 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x float> %vd
+}
+
+declare <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float>, <4 x float>, <4 x float>, metadata, metadata)
+
+define <4 x float> @vfnmsub_vv_v4f32(<4 x float> %va, <4 x float> %vb, <4 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <4 x float> %va
+  %neg2 = fneg <4 x float> %vc
+  %vd = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %vb, <4 x float> %neg, <4 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x float> %vd
+}
+
+define <4 x float> @vfnmsub_vf_v4f32(<4 x float> %va, <4 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x float> poison, float %c, i32 0
+  %splat = shufflevector <4 x float> %head, <4 x float> poison, <4 x i32> zeroinitializer
+  %neg = fneg <4 x float> %splat
+  %neg2 = fneg <4 x float> %vb
+  %vd = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %va, <4 x float> %neg, <4 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x float> %vd
+}
+
+declare <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float>, <8 x float>, <8 x float>, metadata, metadata)
+
+define <8 x float> @vfnmsub_vv_v8f32(<8 x float> %va, <8 x float> %vb, <8 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT:    vfnmacc.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <8 x float> %vc
+  %neg2 = fneg <8 x float> %va
+  %vd = call <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float> %vb, <8 x float> %neg, <8 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x float> %vd
+}
+
+define <8 x float> @vfnmsub_vf_v8f32(<8 x float> %va, <8 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_v8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT:    vfnmacc.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x float> poison, float %c, i32 0
+  %splat = shufflevector <8 x float> %head, <8 x float> poison, <8 x i32> zeroinitializer
+  %neg = fneg <8 x float> %splat
+  %neg2 = fneg <8 x float> %va
+  %vd = call <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float> %vb, <8 x float> %neg, <8 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x float> %vd
+}
+
+declare <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float>, <16 x float>, <16 x float>, metadata, metadata)
+
+define <16 x float> @vfnmsub_vv_v16f32(<16 x float> %va, <16 x float> %vb, <16 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e32, m4, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <16 x float> %va
+  %neg2 = fneg <16 x float> %vb
+  %vd = call <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float> %vc, <16 x float> %neg, <16 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x float> %vd
+}
+
+define <16 x float> @vfnmsub_vf_v16f32(<16 x float> %va, <16 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_v16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e32, m4, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <16 x float> poison, float %c, i32 0
+  %splat = shufflevector <16 x float> %head, <16 x float> poison, <16 x i32> zeroinitializer
+  %neg = fneg <16 x float> %splat
+  %neg2 = fneg <16 x float> %vb
+  %vd = call <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float> %neg, <16 x float> %va, <16 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x float> %vd
+}
+
+declare <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double>, <2 x double>, <2 x double>, metadata, metadata)
+
+define <2 x double> @vfnmsub_vv_v2f64(<2 x double> %va, <2 x double> %vb, <2 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <2 x double> %va
+  %neg2 = fneg <2 x double> %vb
+  %vd = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %neg, <2 x double> %vc, <2 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x double> %vd
+}
+
+define <2 x double> @vfnmsub_vf_v2f64(<2 x double> %va, <2 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x double> poison, double %c, i32 0
+  %splat = shufflevector <2 x double> %head, <2 x double> poison, <2 x i32> zeroinitializer
+  %neg = fneg <2 x double> %va
+  %neg2 = fneg <2 x double> %vb
+  %vd = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %splat, <2 x double> %neg, <2 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x double> %vd
+}
+
+declare <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double>, <4 x double>, <4 x double>, metadata, metadata)
+
+define <4 x double> @vfnmsub_vv_v4f64(<4 x double> %va, <4 x double> %vb, <4 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e64, m2, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v10, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <4 x double> %vb
+  %neg2 = fneg <4 x double> %vc
+  %vd = call <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double> %neg, <4 x double> %va, <4 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x double> %vd
+}
+
+define <4 x double> @vfnmsub_vf_v4f64(<4 x double> %va, <4 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e64, m2, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x double> poison, double %c, i32 0
+  %splat = shufflevector <4 x double> %head, <4 x double> poison, <4 x i32> zeroinitializer
+  %neg = fneg <4 x double> %splat
+  %neg2 = fneg <4 x double> %vb
+  %vd = call <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double> %va, <4 x double> %neg, <4 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x double> %vd
+}
+
+declare <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double>, <8 x double>, <8 x double>, metadata, metadata)
+
+define <8 x double> @vfnmsub_vv_v8f64(<8 x double> %va, <8 x double> %vb, <8 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e64, m4, ta, ma
+; CHECK-NEXT:    vfnmacc.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <8 x double> %vb
+  %neg2 = fneg <8 x double> %va
+  %vd = call <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double> %neg, <8 x double> %vc, <8 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x double> %vd
+}
+
+define <8 x double> @vfnmsub_vf_v8f64(<8 x double> %va, <8 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_v8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e64, m4, ta, ma
+; CHECK-NEXT:    vfnmacc.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x double> poison, double %c, i32 0
+  %splat = shufflevector <8 x double> %head, <8 x double> poison, <8 x i32> zeroinitializer
+  %neg = fneg <8 x double> %splat
+  %neg2 = fneg <8 x double> %va
+  %vd = call <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double> %vb, <8 x double> %neg, <8 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x double> %vd
+}

diff  --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfnmsub-constrained-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfnmsub-constrained-sdnode.ll
new file mode 100644
index 000000000000..db75aee24e8b
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfnmsub-constrained-sdnode.ll
@@ -0,0 +1,322 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=ilp32d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=lp64d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+
+; This tests a mix of vfnmsac and vfnmsub by using 
diff erent operand orders to
+; trigger commuting in TwoAddressInstructionPass.
+
+declare <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half>, <2 x half>, <2 x half>, metadata, metadata)
+
+define <2 x half> @vfnmsub_vv_v2f16(<2 x half> %va, <2 x half> %vb, <2 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e16, mf4, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <2 x half> %va
+  %vd = call <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half> %neg, <2 x half> %vc, <2 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x half> %vd
+}
+
+define <2 x half> @vfnmsub_vf_v2f16(<2 x half> %va, <2 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e16, mf4, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x half> poison, half %c, i32 0
+  %splat = shufflevector <2 x half> %head, <2 x half> poison, <2 x i32> zeroinitializer
+  %neg = fneg <2 x half> %va
+  %vd = call <2 x half> @llvm.experimental.constrained.fma.v2f16(<2 x half> %splat, <2 x half> %neg, <2 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x half> %vd
+}
+
+declare <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half>, <4 x half>, <4 x half>, metadata, metadata)
+
+define <4 x half> @vfnmsub_vv_v4f16(<4 x half> %va, <4 x half> %vb, <4 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e16, mf2, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <4 x half> %vb
+  %vd = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> %neg, <4 x half> %va, <4 x half> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x half> %vd
+}
+
+define <4 x half> @vfnmsub_vf_v4f16(<4 x half> %va, <4 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e16, mf2, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x half> poison, half %c, i32 0
+  %splat = shufflevector <4 x half> %head, <4 x half> poison, <4 x i32> zeroinitializer
+  %neg = fneg <4 x half> %splat
+  %vd = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> %va, <4 x half> %neg, <4 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x half> %vd
+}
+
+declare <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half>, <8 x half>, <8 x half>, metadata, metadata)
+
+define <8 x half> @vfnmsub_vv_v8f16(<8 x half> %va, <8 x half> %vb, <8 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT:    vfnmsac.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <8 x half> %vb
+  %vd = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> %neg, <8 x half> %vc, <8 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x half> %vd
+}
+
+define <8 x half> @vfnmsub_vf_v8f16(<8 x half> %va, <8 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT:    vfnmsac.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x half> poison, half %c, i32 0
+  %splat = shufflevector <8 x half> %head, <8 x half> poison, <8 x i32> zeroinitializer
+  %neg = fneg <8 x half> %splat
+  %vd = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> %vb, <8 x half> %neg, <8 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x half> %vd
+}
+
+declare <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half>, <16 x half>, <16 x half>, metadata, metadata)
+
+define <16 x half> @vfnmsub_vv_v16f16(<16 x half> %va, <16 x half> %vb, <16 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e16, m2, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <16 x half> %vc
+  %vd = call <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half> %neg, <16 x half> %va, <16 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x half> %vd
+}
+
+define <16 x half> @vfnmsub_vf_v16f16(<16 x half> %va, <16 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e16, m2, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <16 x half> poison, half %c, i32 0
+  %splat = shufflevector <16 x half> %head, <16 x half> poison, <16 x i32> zeroinitializer
+  %neg = fneg <16 x half> %splat
+  %vd = call <16 x half> @llvm.experimental.constrained.fma.v16f16(<16 x half> %neg, <16 x half> %va, <16 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x half> %vd
+}
+
+declare <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half>, <32 x half>, <32 x half>, metadata, metadata)
+
+define <32 x half> @vfnmsub_vv_v32f16(<32 x half> %va, <32 x half> %vb, <32 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 32
+; CHECK-NEXT:    vsetvli zero, a0, e16, m4, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <32 x half> %vc
+  %vd = call <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half> %neg, <32 x half> %va, <32 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <32 x half> %vd
+}
+
+define <32 x half> @vfnmsub_vf_v32f16(<32 x half> %va, <32 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_v32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 32
+; CHECK-NEXT:    vsetvli zero, a0, e16, m4, ta, ma
+; CHECK-NEXT:    vfnmsac.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <32 x half> poison, half %c, i32 0
+  %splat = shufflevector <32 x half> %head, <32 x half> poison, <32 x i32> zeroinitializer
+  %neg = fneg <32 x half> %splat
+  %vd = call <32 x half> @llvm.experimental.constrained.fma.v32f16(<32 x half> %neg, <32 x half> %vb, <32 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <32 x half> %vd
+}
+
+declare <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float>, <2 x float>, <2 x float>, metadata, metadata)
+
+define <2 x float> @vfnmsub_vv_v2f32(<2 x float> %va, <2 x float> %vb, <2 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e32, mf2, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <2 x float> %vc
+  %vd = call <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float> %va, <2 x float> %neg, <2 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x float> %vd
+}
+
+define <2 x float> @vfnmsub_vf_v2f32(<2 x float> %va, <2 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_v2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e32, mf2, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x float> poison, float %c, i32 0
+  %splat = shufflevector <2 x float> %head, <2 x float> poison, <2 x i32> zeroinitializer
+  %neg = fneg <2 x float> %va
+  %vd = call <2 x float> @llvm.experimental.constrained.fma.v2f32(<2 x float> %splat, <2 x float> %neg, <2 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x float> %vd
+}
+
+declare <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float>, <4 x float>, <4 x float>, metadata, metadata)
+
+define <4 x float> @vfnmsub_vv_v4f32(<4 x float> %va, <4 x float> %vb, <4 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <4 x float> %va
+  %vd = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %vb, <4 x float> %neg, <4 x float> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x float> %vd
+}
+
+define <4 x float> @vfnmsub_vf_v4f32(<4 x float> %va, <4 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_v4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x float> poison, float %c, i32 0
+  %splat = shufflevector <4 x float> %head, <4 x float> poison, <4 x i32> zeroinitializer
+  %neg = fneg <4 x float> %splat
+  %vd = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %va, <4 x float> %neg, <4 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x float> %vd
+}
+
+declare <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float>, <8 x float>, <8 x float>, metadata, metadata)
+
+define <8 x float> @vfnmsub_vv_v8f32(<8 x float> %va, <8 x float> %vb, <8 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT:    vfnmsac.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <8 x float> %vc
+  %vd = call <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float> %vb, <8 x float> %neg, <8 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x float> %vd
+}
+
+define <8 x float> @vfnmsub_vf_v8f32(<8 x float> %va, <8 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_v8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT:    vfnmsac.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x float> poison, float %c, i32 0
+  %splat = shufflevector <8 x float> %head, <8 x float> poison, <8 x i32> zeroinitializer
+  %neg = fneg <8 x float> %splat
+  %vd = call <8 x float> @llvm.experimental.constrained.fma.v8f32(<8 x float> %vb, <8 x float> %neg, <8 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x float> %vd
+}
+
+declare <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float>, <16 x float>, <16 x float>, metadata, metadata)
+
+define <16 x float> @vfnmsub_vv_v16f32(<16 x float> %va, <16 x float> %vb, <16 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e32, m4, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <16 x float> %va
+  %vd = call <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float> %vc, <16 x float> %neg, <16 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x float> %vd
+}
+
+define <16 x float> @vfnmsub_vf_v16f32(<16 x float> %va, <16 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_v16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 16, e32, m4, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <16 x float> poison, float %c, i32 0
+  %splat = shufflevector <16 x float> %head, <16 x float> poison, <16 x i32> zeroinitializer
+  %neg = fneg <16 x float> %splat
+  %vd = call <16 x float> @llvm.experimental.constrained.fma.v16f32(<16 x float> %neg, <16 x float> %va, <16 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <16 x float> %vd
+}
+
+declare <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double>, <2 x double>, <2 x double>, metadata, metadata)
+
+define <2 x double> @vfnmsub_vv_v2f64(<2 x double> %va, <2 x double> %vb, <2 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <2 x double> %va
+  %vd = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %neg, <2 x double> %vc, <2 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x double> %vd
+}
+
+define <2 x double> @vfnmsub_vf_v2f64(<2 x double> %va, <2 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_v2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 2, e64, m1, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <2 x double> poison, double %c, i32 0
+  %splat = shufflevector <2 x double> %head, <2 x double> poison, <2 x i32> zeroinitializer
+  %neg = fneg <2 x double> %va
+  %vd = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %splat, <2 x double> %neg, <2 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <2 x double> %vd
+}
+
+declare <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double>, <4 x double>, <4 x double>, metadata, metadata)
+
+define <4 x double> @vfnmsub_vv_v4f64(<4 x double> %va, <4 x double> %vb, <4 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e64, m2, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v10, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <4 x double> %vb
+  %vd = call <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double> %neg, <4 x double> %va, <4 x double> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x double> %vd
+}
+
+define <4 x double> @vfnmsub_vf_v4f64(<4 x double> %va, <4 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_v4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e64, m2, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <4 x double> poison, double %c, i32 0
+  %splat = shufflevector <4 x double> %head, <4 x double> poison, <4 x i32> zeroinitializer
+  %neg = fneg <4 x double> %splat
+  %vd = call <4 x double> @llvm.experimental.constrained.fma.v4f64(<4 x double> %va, <4 x double> %neg, <4 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <4 x double> %vd
+}
+
+declare <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double>, <8 x double>, <8 x double>, metadata, metadata)
+
+define <8 x double> @vfnmsub_vv_v8f64(<8 x double> %va, <8 x double> %vb, <8 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_v8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e64, m4, ta, ma
+; CHECK-NEXT:    vfnmsac.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <8 x double> %vb
+  %vd = call <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double> %neg, <8 x double> %vc, <8 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x double> %vd
+}
+
+define <8 x double> @vfnmsub_vf_v8f64(<8 x double> %va, <8 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_v8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 8, e64, m4, ta, ma
+; CHECK-NEXT:    vfnmsac.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <8 x double> poison, double %c, i32 0
+  %splat = shufflevector <8 x double> %head, <8 x double> poison, <8 x i32> zeroinitializer
+  %neg = fneg <8 x double> %splat
+  %vd = call <8 x double> @llvm.experimental.constrained.fma.v8f64(<8 x double> %vb, <8 x double> %neg, <8 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <8 x double> %vd
+}

diff  --git a/llvm/test/CodeGen/RISCV/rvv/vfmadd-constrained-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/vfmadd-constrained-sdnode.ll
new file mode 100644
index 000000000000..352b379703a5
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/vfmadd-constrained-sdnode.ll
@@ -0,0 +1,371 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=ilp32d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=lp64d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+
+; This tests a mix of vfmacc and vfmadd by using 
diff erent operand orders to
+; trigger commuting in TwoAddressInstructionPass.
+
+declare <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half>, <vscale x 1 x half>, <vscale x 1 x half>, metadata, metadata)
+
+define <vscale x 1 x half> @vfmadd_vv_nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, <vscale x 1 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv1f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf4, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, <vscale x 1 x half> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x half> %vd
+}
+
+define <vscale x 1 x half> @vfmadd_vf_nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_nxv1f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf4, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 1 x half> %head, <vscale x 1 x half> poison, <vscale x 1 x i32> zeroinitializer
+  %vd = call <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %splat, <vscale x 1 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x half> %vd
+}
+
+declare <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half>, <vscale x 2 x half>, <vscale x 2 x half>, metadata, metadata)
+
+define <vscale x 2 x half> @vfmadd_vv_nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vb, <vscale x 2 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf2, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vc, <vscale x 2 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x half> %vd
+}
+
+define <vscale x 2 x half> @vfmadd_vf_nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_nxv2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf2, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 2 x half> %head, <vscale x 2 x half> poison, <vscale x 2 x i32> zeroinitializer
+  %vd = call <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half> %vb, <vscale x 2 x half> %splat, <vscale x 2 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x half> %vd
+}
+
+declare <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half>, <vscale x 4 x half>, <vscale x 4 x half>, metadata, metadata)
+
+define <vscale x 4 x half> @vfmadd_vv_nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %vb, <vscale x 4 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m1, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half> %vb, <vscale x 4 x half> %va, <vscale x 4 x half> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x half> %vd
+}
+
+define <vscale x 4 x half> @vfmadd_vf_nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_nxv4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m1, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 4 x half> %head, <vscale x 4 x half> poison, <vscale x 4 x i32> zeroinitializer
+  %vd = call <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %splat, <vscale x 4 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x half> %vd
+}
+
+declare <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half>, <vscale x 8 x half>, <vscale x 8 x half>, metadata, metadata)
+
+define <vscale x 8 x half> @vfmadd_vv_nxv8f16(<vscale x 8 x half> %va, <vscale x 8 x half> %vb, <vscale x 8 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m2, ta, ma
+; CHECK-NEXT:    vfmacc.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half> %vb, <vscale x 8 x half> %vc, <vscale x 8 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x half> %vd
+}
+
+define <vscale x 8 x half> @vfmadd_vf_nxv8f16(<vscale x 8 x half> %va, <vscale x 8 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_nxv8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m2, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 8 x half> %head, <vscale x 8 x half> poison, <vscale x 8 x i32> zeroinitializer
+  %vd = call <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half> %vb, <vscale x 8 x half> %splat, <vscale x 8 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x half> %vd
+}
+
+declare <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half>, <vscale x 16 x half>, <vscale x 16 x half>, metadata, metadata)
+
+define <vscale x 16 x half> @vfmadd_vv_nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %vb, <vscale x 16 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m4, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half> %vc, <vscale x 16 x half> %va, <vscale x 16 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x half> %vd
+}
+
+define <vscale x 16 x half> @vfmadd_vf_nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_nxv16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m4, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 16 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 16 x half> %head, <vscale x 16 x half> poison, <vscale x 16 x i32> zeroinitializer
+  %vd = call <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %splat, <vscale x 16 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x half> %vd
+}
+
+declare <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half>, <vscale x 32 x half>, <vscale x 32 x half>, metadata, metadata)
+
+define <vscale x 32 x half> @vfmadd_vv_nxv32f16(<vscale x 32 x half> %va, <vscale x 32 x half> %vb, <vscale x 32 x half> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re16.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e16, m8, ta, ma
+; CHECK-NEXT:    vfmacc.vv v8, v16, v24
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half> %vc, <vscale x 32 x half> %vb, <vscale x 32 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 32 x half> %vd
+}
+
+define <vscale x 32 x half> @vfmadd_vf_nxv32f16(<vscale x 32 x half> %va, <vscale x 32 x half> %vb, half %c) {
+; CHECK-LABEL: vfmadd_vf_nxv32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m8, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 32 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 32 x half> %head, <vscale x 32 x half> poison, <vscale x 32 x i32> zeroinitializer
+  %vd = call <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half> %vb, <vscale x 32 x half> %splat, <vscale x 32 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 32 x half> %vd
+}
+
+declare <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float>, <vscale x 1 x float>, <vscale x 1 x float>, metadata, metadata)
+
+define <vscale x 1 x float> @vfmadd_vv_nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, <vscale x 1 x float> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv1f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, mf2, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, <vscale x 1 x float> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x float> %vd
+}
+
+define <vscale x 1 x float> @vfmadd_vf_nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, float %c) {
+; CHECK-LABEL: vfmadd_vf_nxv1f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, mf2, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 1 x float> %head, <vscale x 1 x float> poison, <vscale x 1 x i32> zeroinitializer
+  %vd = call <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %splat, <vscale x 1 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x float> %vd
+}
+
+declare <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float>, <vscale x 2 x float>, <vscale x 2 x float>, metadata, metadata)
+
+define <vscale x 2 x float> @vfmadd_vv_nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vb, <vscale x 2 x float> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vc, <vscale x 2 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x float> %vd
+}
+
+define <vscale x 2 x float> @vfmadd_vf_nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vb, float %c) {
+; CHECK-LABEL: vfmadd_vf_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 2 x float> %head, <vscale x 2 x float> poison, <vscale x 2 x i32> zeroinitializer
+  %vd = call <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float> %vb, <vscale x 2 x float> %splat, <vscale x 2 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x float> %vd
+}
+
+declare <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float>, metadata, metadata)
+
+define <vscale x 4 x float> @vfmadd_vv_nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %vb, <vscale x 4 x float> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m2, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v10, v12
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float> %vb, <vscale x 4 x float> %va, <vscale x 4 x float> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x float> %vd
+}
+
+define <vscale x 4 x float> @vfmadd_vf_nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %vb, float %c) {
+; CHECK-LABEL: vfmadd_vf_nxv4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m2, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 4 x float> %head, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
+  %vd = call <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %splat, <vscale x 4 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x float> %vd
+}
+
+declare <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float>, <vscale x 8 x float>, <vscale x 8 x float>, metadata, metadata)
+
+define <vscale x 8 x float> @vfmadd_vv_nxv8f32(<vscale x 8 x float> %va, <vscale x 8 x float> %vb, <vscale x 8 x float> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m4, ta, ma
+; CHECK-NEXT:    vfmacc.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float> %vb, <vscale x 8 x float> %vc, <vscale x 8 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x float> %vd
+}
+
+define <vscale x 8 x float> @vfmadd_vf_nxv8f32(<vscale x 8 x float> %va, <vscale x 8 x float> %vb, float %c) {
+; CHECK-LABEL: vfmadd_vf_nxv8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m4, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 8 x float> %head, <vscale x 8 x float> poison, <vscale x 8 x i32> zeroinitializer
+  %vd = call <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float> %vb, <vscale x 8 x float> %splat, <vscale x 8 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x float> %vd
+}
+
+declare <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float>, <vscale x 16 x float>, <vscale x 16 x float>, metadata, metadata)
+
+define <vscale x 16 x float> @vfmadd_vv_nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %vb, <vscale x 16 x float> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re32.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e32, m8, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v24, v16
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float> %vc, <vscale x 16 x float> %va, <vscale x 16 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x float> %vd
+}
+
+define <vscale x 16 x float> @vfmadd_vf_nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %vb, float %c) {
+; CHECK-LABEL: vfmadd_vf_nxv16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m8, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 16 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 16 x float> %head, <vscale x 16 x float> poison, <vscale x 16 x i32> zeroinitializer
+  %vd = call <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %splat, <vscale x 16 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x float> %vd
+}
+
+declare <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double>, <vscale x 1 x double>, <vscale x 1 x double>, metadata, metadata)
+
+define <vscale x 1 x double> @vfmadd_vv_nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, <vscale x 1 x double> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv1f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m1, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, <vscale x 1 x double> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x double> %vd
+}
+
+define <vscale x 1 x double> @vfmadd_vf_nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, double %c) {
+; CHECK-LABEL: vfmadd_vf_nxv1f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m1, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 1 x double> %head, <vscale x 1 x double> poison, <vscale x 1 x i32> zeroinitializer
+  %vd = call <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %splat, <vscale x 1 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x double> %vd
+}
+
+declare <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double>, <vscale x 2 x double>, <vscale x 2 x double>, metadata, metadata)
+
+define <vscale x 2 x double> @vfmadd_vv_nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vb, <vscale x 2 x double> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m2, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vc, <vscale x 2 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x double> %vd
+}
+
+define <vscale x 2 x double> @vfmadd_vf_nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vb, double %c) {
+; CHECK-LABEL: vfmadd_vf_nxv2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m2, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 2 x double> %head, <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer
+  %vd = call <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double> %vb, <vscale x 2 x double> %splat, <vscale x 2 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x double> %vd
+}
+
+declare <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double>, <vscale x 4 x double>, <vscale x 4 x double>, metadata, metadata)
+
+define <vscale x 4 x double> @vfmadd_vv_nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %vb, <vscale x 4 x double> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m4, ta, ma
+; CHECK-NEXT:    vfmadd.vv v8, v12, v16
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double> %vb, <vscale x 4 x double> %va, <vscale x 4 x double> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x double> %vd
+}
+
+define <vscale x 4 x double> @vfmadd_vf_nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %vb, double %c) {
+; CHECK-LABEL: vfmadd_vf_nxv4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m4, ta, ma
+; CHECK-NEXT:    vfmadd.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 4 x double> %head, <vscale x 4 x double> poison, <vscale x 4 x i32> zeroinitializer
+  %vd = call <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %splat, <vscale x 4 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x double> %vd
+}
+
+declare <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double>, <vscale x 8 x double>, <vscale x 8 x double>, metadata, metadata)
+
+define <vscale x 8 x double> @vfmadd_vv_nxv8f64(<vscale x 8 x double> %va, <vscale x 8 x double> %vb, <vscale x 8 x double> %vc) {
+; CHECK-LABEL: vfmadd_vv_nxv8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re64.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e64, m8, ta, ma
+; CHECK-NEXT:    vfmacc.vv v8, v16, v24
+; CHECK-NEXT:    ret
+  %vd = call <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double> %vb, <vscale x 8 x double> %vc, <vscale x 8 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x double> %vd
+}
+
+define <vscale x 8 x double> @vfmadd_vf_nxv8f64(<vscale x 8 x double> %va, <vscale x 8 x double> %vb, double %c) {
+; CHECK-LABEL: vfmadd_vf_nxv8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m8, ta, ma
+; CHECK-NEXT:    vfmacc.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 8 x double> %head, <vscale x 8 x double> poison, <vscale x 8 x i32> zeroinitializer
+  %vd = call <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double> %vb, <vscale x 8 x double> %splat, <vscale x 8 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x double> %vd
+}

diff  --git a/llvm/test/CodeGen/RISCV/rvv/vfmsub-constrained-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/vfmsub-constrained-sdnode.ll
new file mode 100644
index 000000000000..7252ddbf98ea
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/vfmsub-constrained-sdnode.ll
@@ -0,0 +1,401 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=ilp32d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=lp64d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+
+; This tests a mix of vfmsac and vfmsub by using 
diff erent operand orders to
+; trigger commuting in TwoAddressInstructionPass.
+
+declare <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half>, <vscale x 1 x half>, <vscale x 1 x half>, metadata, metadata)
+
+define <vscale x 1 x half> @vfmsub_vv_nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, <vscale x 1 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv1f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf4, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 1 x half> %vc
+  %vd = call <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, <vscale x 1 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x half> %vd
+}
+
+define <vscale x 1 x half> @vfmsub_vf_nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_nxv1f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf4, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 1 x half> %head, <vscale x 1 x half> poison, <vscale x 1 x i32> zeroinitializer
+  %neg = fneg <vscale x 1 x half> %vb
+  %vd = call <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %splat, <vscale x 1 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x half> %vd
+}
+
+declare <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half>, <vscale x 2 x half>, <vscale x 2 x half>, metadata, metadata)
+
+define <vscale x 2 x half> @vfmsub_vv_nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vb, <vscale x 2 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf2, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 2 x half> %vb
+  %vd = call <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vc, <vscale x 2 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x half> %vd
+}
+
+define <vscale x 2 x half> @vfmsub_vf_nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_nxv2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf2, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 2 x half> %head, <vscale x 2 x half> poison, <vscale x 2 x i32> zeroinitializer
+  %neg = fneg <vscale x 2 x half> %va
+  %vd = call <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half> %vb, <vscale x 2 x half> %splat, <vscale x 2 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x half> %vd
+}
+
+declare <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half>, <vscale x 4 x half>, <vscale x 4 x half>, metadata, metadata)
+
+define <vscale x 4 x half> @vfmsub_vv_nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %vb, <vscale x 4 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m1, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 4 x half> %vc
+  %vd = call <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half> %vb, <vscale x 4 x half> %va, <vscale x 4 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x half> %vd
+}
+
+define <vscale x 4 x half> @vfmsub_vf_nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_nxv4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m1, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 4 x half> %head, <vscale x 4 x half> poison, <vscale x 4 x i32> zeroinitializer
+  %neg = fneg <vscale x 4 x half> %vb
+  %vd = call <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %splat, <vscale x 4 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x half> %vd
+}
+
+declare <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half>, <vscale x 8 x half>, <vscale x 8 x half>, metadata, metadata)
+
+define <vscale x 8 x half> @vfmsub_vv_nxv8f16(<vscale x 8 x half> %va, <vscale x 8 x half> %vb, <vscale x 8 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m2, ta, ma
+; CHECK-NEXT:    vfmsac.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 8 x half> %va
+  %vd = call <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half> %vb, <vscale x 8 x half> %vc, <vscale x 8 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x half> %vd
+}
+
+define <vscale x 8 x half> @vfmsub_vf_nxv8f16(<vscale x 8 x half> %va, <vscale x 8 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_nxv8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m2, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 8 x half> %head, <vscale x 8 x half> poison, <vscale x 8 x i32> zeroinitializer
+  %neg = fneg <vscale x 8 x half> %va
+  %vd = call <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half> %vb, <vscale x 8 x half> %splat, <vscale x 8 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x half> %vd
+}
+
+declare <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half>, <vscale x 16 x half>, <vscale x 16 x half>, metadata, metadata)
+
+define <vscale x 16 x half> @vfmsub_vv_nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %vb, <vscale x 16 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m4, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 16 x half> %vb
+  %vd = call <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half> %vc, <vscale x 16 x half> %va, <vscale x 16 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x half> %vd
+}
+
+define <vscale x 16 x half> @vfmsub_vf_nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_nxv16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m4, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 16 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 16 x half> %head, <vscale x 16 x half> poison, <vscale x 16 x i32> zeroinitializer
+  %neg = fneg <vscale x 16 x half> %vb
+  %vd = call <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %splat, <vscale x 16 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x half> %vd
+}
+
+declare <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half>, <vscale x 32 x half>, <vscale x 32 x half>, metadata, metadata)
+
+define <vscale x 32 x half> @vfmsub_vv_nxv32f16(<vscale x 32 x half> %va, <vscale x 32 x half> %vb, <vscale x 32 x half> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re16.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e16, m8, ta, ma
+; CHECK-NEXT:    vfmsac.vv v8, v16, v24
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 32 x half> %va
+  %vd = call <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half> %vc, <vscale x 32 x half> %vb, <vscale x 32 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 32 x half> %vd
+}
+
+define <vscale x 32 x half> @vfmsub_vf_nxv32f16(<vscale x 32 x half> %va, <vscale x 32 x half> %vb, half %c) {
+; CHECK-LABEL: vfmsub_vf_nxv32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m8, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 32 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 32 x half> %head, <vscale x 32 x half> poison, <vscale x 32 x i32> zeroinitializer
+  %neg = fneg <vscale x 32 x half> %va
+  %vd = call <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half> %vb, <vscale x 32 x half> %splat, <vscale x 32 x half> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 32 x half> %vd
+}
+
+declare <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float>, <vscale x 1 x float>, <vscale x 1 x float>, metadata, metadata)
+
+define <vscale x 1 x float> @vfmsub_vv_nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, <vscale x 1 x float> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv1f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, mf2, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 1 x float> %vc
+  %vd = call <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, <vscale x 1 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x float> %vd
+}
+
+define <vscale x 1 x float> @vfmsub_vf_nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, float %c) {
+; CHECK-LABEL: vfmsub_vf_nxv1f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, mf2, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 1 x float> %head, <vscale x 1 x float> poison, <vscale x 1 x i32> zeroinitializer
+  %neg = fneg <vscale x 1 x float> %vb
+  %vd = call <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %splat, <vscale x 1 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x float> %vd
+}
+
+declare <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float>, <vscale x 2 x float>, <vscale x 2 x float>, metadata, metadata)
+
+define <vscale x 2 x float> @vfmsub_vv_nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vb, <vscale x 2 x float> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 2 x float> %vb
+  %vd = call <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vc, <vscale x 2 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x float> %vd
+}
+
+define <vscale x 2 x float> @vfmsub_vf_nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vb, float %c) {
+; CHECK-LABEL: vfmsub_vf_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 2 x float> %head, <vscale x 2 x float> poison, <vscale x 2 x i32> zeroinitializer
+  %neg = fneg <vscale x 2 x float> %va
+  %vd = call <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float> %vb, <vscale x 2 x float> %splat, <vscale x 2 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x float> %vd
+}
+
+declare <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float>, metadata, metadata)
+
+define <vscale x 4 x float> @vfmsub_vv_nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %vb, <vscale x 4 x float> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m2, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v10, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 4 x float> %vc
+  %vd = call <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float> %vb, <vscale x 4 x float> %va, <vscale x 4 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x float> %vd
+}
+
+define <vscale x 4 x float> @vfmsub_vf_nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %vb, float %c) {
+; CHECK-LABEL: vfmsub_vf_nxv4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m2, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 4 x float> %head, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
+  %neg = fneg <vscale x 4 x float> %vb
+  %vd = call <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %splat, <vscale x 4 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x float> %vd
+}
+
+declare <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float>, <vscale x 8 x float>, <vscale x 8 x float>, metadata, metadata)
+
+define <vscale x 8 x float> @vfmsub_vv_nxv8f32(<vscale x 8 x float> %va, <vscale x 8 x float> %vb, <vscale x 8 x float> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m4, ta, ma
+; CHECK-NEXT:    vfmsac.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 8 x float> %va
+  %vd = call <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float> %vb, <vscale x 8 x float> %vc, <vscale x 8 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x float> %vd
+}
+
+define <vscale x 8 x float> @vfmsub_vf_nxv8f32(<vscale x 8 x float> %va, <vscale x 8 x float> %vb, float %c) {
+; CHECK-LABEL: vfmsub_vf_nxv8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m4, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 8 x float> %head, <vscale x 8 x float> poison, <vscale x 8 x i32> zeroinitializer
+  %neg = fneg <vscale x 8 x float> %va
+  %vd = call <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float> %vb, <vscale x 8 x float> %splat, <vscale x 8 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x float> %vd
+}
+
+declare <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float>, <vscale x 16 x float>, <vscale x 16 x float>, metadata, metadata)
+
+define <vscale x 16 x float> @vfmsub_vv_nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %vb, <vscale x 16 x float> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re32.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e32, m8, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v24, v16
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 16 x float> %vb
+  %vd = call <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float> %vc, <vscale x 16 x float> %va, <vscale x 16 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x float> %vd
+}
+
+define <vscale x 16 x float> @vfmsub_vf_nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %vb, float %c) {
+; CHECK-LABEL: vfmsub_vf_nxv16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m8, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 16 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 16 x float> %head, <vscale x 16 x float> poison, <vscale x 16 x i32> zeroinitializer
+  %neg = fneg <vscale x 16 x float> %vb
+  %vd = call <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %splat, <vscale x 16 x float> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x float> %vd
+}
+
+declare <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double>, <vscale x 1 x double>, <vscale x 1 x double>, metadata, metadata)
+
+define <vscale x 1 x double> @vfmsub_vv_nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, <vscale x 1 x double> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv1f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m1, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 1 x double> %vc
+  %vd = call <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, <vscale x 1 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x double> %vd
+}
+
+define <vscale x 1 x double> @vfmsub_vf_nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, double %c) {
+; CHECK-LABEL: vfmsub_vf_nxv1f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m1, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 1 x double> %head, <vscale x 1 x double> poison, <vscale x 1 x i32> zeroinitializer
+  %neg = fneg <vscale x 1 x double> %vb
+  %vd = call <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %splat, <vscale x 1 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x double> %vd
+}
+
+declare <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double>, <vscale x 2 x double>, <vscale x 2 x double>, metadata, metadata)
+
+define <vscale x 2 x double> @vfmsub_vv_nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vb, <vscale x 2 x double> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m2, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 2 x double> %vb
+  %vd = call <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vc, <vscale x 2 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x double> %vd
+}
+
+define <vscale x 2 x double> @vfmsub_vf_nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vb, double %c) {
+; CHECK-LABEL: vfmsub_vf_nxv2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m2, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 2 x double> %head, <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer
+  %neg = fneg <vscale x 2 x double> %va
+  %vd = call <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double> %vb, <vscale x 2 x double> %splat, <vscale x 2 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x double> %vd
+}
+
+declare <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double>, <vscale x 4 x double>, <vscale x 4 x double>, metadata, metadata)
+
+define <vscale x 4 x double> @vfmsub_vv_nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %vb, <vscale x 4 x double> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m4, ta, ma
+; CHECK-NEXT:    vfmsub.vv v8, v12, v16
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 4 x double> %vc
+  %vd = call <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double> %vb, <vscale x 4 x double> %va, <vscale x 4 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x double> %vd
+}
+
+define <vscale x 4 x double> @vfmsub_vf_nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %vb, double %c) {
+; CHECK-LABEL: vfmsub_vf_nxv4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m4, ta, ma
+; CHECK-NEXT:    vfmsub.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 4 x double> %head, <vscale x 4 x double> poison, <vscale x 4 x i32> zeroinitializer
+  %neg = fneg <vscale x 4 x double> %vb
+  %vd = call <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %splat, <vscale x 4 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x double> %vd
+}
+
+declare <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double>, <vscale x 8 x double>, <vscale x 8 x double>, metadata, metadata)
+
+define <vscale x 8 x double> @vfmsub_vv_nxv8f64(<vscale x 8 x double> %va, <vscale x 8 x double> %vb, <vscale x 8 x double> %vc) {
+; CHECK-LABEL: vfmsub_vv_nxv8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re64.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e64, m8, ta, ma
+; CHECK-NEXT:    vfmsac.vv v8, v16, v24
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 8 x double> %va
+  %vd = call <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double> %vb, <vscale x 8 x double> %vc, <vscale x 8 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x double> %vd
+}
+
+define <vscale x 8 x double> @vfmsub_vf_nxv8f64(<vscale x 8 x double> %va, <vscale x 8 x double> %vb, double %c) {
+; CHECK-LABEL: vfmsub_vf_nxv8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m8, ta, ma
+; CHECK-NEXT:    vfmsac.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 8 x double> %head, <vscale x 8 x double> poison, <vscale x 8 x i32> zeroinitializer
+  %neg = fneg <vscale x 8 x double> %va
+  %vd = call <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double> %vb, <vscale x 8 x double> %splat, <vscale x 8 x double> %neg, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x double> %vd
+}

diff  --git a/llvm/test/CodeGen/RISCV/rvv/vfnmadd-constrained-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/vfnmadd-constrained-sdnode.ll
new file mode 100644
index 000000000000..07f1b0ae3ed7
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/vfnmadd-constrained-sdnode.ll
@@ -0,0 +1,431 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=ilp32d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=lp64d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+
+; This tests a mix of vfnmacc and vfnmadd by using 
diff erent operand orders to
+; trigger commuting in TwoAddressInstructionPass.
+
+declare <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half>, <vscale x 1 x half>, <vscale x 1 x half>, metadata, metadata)
+
+define <vscale x 1 x half> @vfnmsub_vv_nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, <vscale x 1 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv1f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf4, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 1 x half> %va
+  %neg2 = fneg <vscale x 1 x half> %vc
+  %vd = call <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half> %neg, <vscale x 1 x half> %vb, <vscale x 1 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x half> %vd
+}
+
+define <vscale x 1 x half> @vfnmsub_vf_nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv1f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf4, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 1 x half> %head, <vscale x 1 x half> poison, <vscale x 1 x i32> zeroinitializer
+  %neg = fneg <vscale x 1 x half> %va
+  %neg2 = fneg <vscale x 1 x half> %vb
+  %vd = call <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half> %neg, <vscale x 1 x half> %splat, <vscale x 1 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x half> %vd
+}
+
+declare <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half>, <vscale x 2 x half>, <vscale x 2 x half>, metadata, metadata)
+
+define <vscale x 2 x half> @vfnmsub_vv_nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vb, <vscale x 2 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf2, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 2 x half> %va
+  %neg2 = fneg <vscale x 2 x half> %vb
+  %vd = call <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half> %neg, <vscale x 2 x half> %vc, <vscale x 2 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x half> %vd
+}
+
+define <vscale x 2 x half> @vfnmsub_vf_nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf2, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 2 x half> %head, <vscale x 2 x half> poison, <vscale x 2 x i32> zeroinitializer
+  %neg = fneg <vscale x 2 x half> %va
+  %neg2 = fneg <vscale x 2 x half> %vb
+  %vd = call <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half> %splat, <vscale x 2 x half> %neg, <vscale x 2 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x half> %vd
+}
+
+declare <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half>, <vscale x 4 x half>, <vscale x 4 x half>, metadata, metadata)
+
+define <vscale x 4 x half> @vfnmsub_vv_nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %vb, <vscale x 4 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m1, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 4 x half> %vb
+  %neg2 = fneg <vscale x 4 x half> %vc
+  %vd = call <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half> %neg, <vscale x 4 x half> %va, <vscale x 4 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x half> %vd
+}
+
+define <vscale x 4 x half> @vfnmsub_vf_nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m1, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 4 x half> %head, <vscale x 4 x half> poison, <vscale x 4 x i32> zeroinitializer
+  %neg = fneg <vscale x 4 x half> %splat
+  %neg2 = fneg <vscale x 4 x half> %vb
+  %vd = call <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %neg, <vscale x 4 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x half> %vd
+}
+
+declare <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half>, <vscale x 8 x half>, <vscale x 8 x half>, metadata, metadata)
+
+define <vscale x 8 x half> @vfnmsub_vv_nxv8f16(<vscale x 8 x half> %va, <vscale x 8 x half> %vb, <vscale x 8 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m2, ta, ma
+; CHECK-NEXT:    vfnmacc.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 8 x half> %vb
+  %neg2 = fneg <vscale x 8 x half> %va
+  %vd = call <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half> %neg, <vscale x 8 x half> %vc, <vscale x 8 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x half> %vd
+}
+
+define <vscale x 8 x half> @vfnmsub_vf_nxv8f16(<vscale x 8 x half> %va, <vscale x 8 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m2, ta, ma
+; CHECK-NEXT:    vfnmacc.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 8 x half> %head, <vscale x 8 x half> poison, <vscale x 8 x i32> zeroinitializer
+  %neg = fneg <vscale x 8 x half> %splat
+  %neg2 = fneg <vscale x 8 x half> %va
+  %vd = call <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half> %vb, <vscale x 8 x half> %neg, <vscale x 8 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x half> %vd
+}
+
+declare <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half>, <vscale x 16 x half>, <vscale x 16 x half>, metadata, metadata)
+
+define <vscale x 16 x half> @vfnmsub_vv_nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %vb, <vscale x 16 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m4, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 16 x half> %vc
+  %neg2 = fneg <vscale x 16 x half> %vb
+  %vd = call <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half> %neg, <vscale x 16 x half> %va, <vscale x 16 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x half> %vd
+}
+
+define <vscale x 16 x half> @vfnmsub_vf_nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m4, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 16 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 16 x half> %head, <vscale x 16 x half> poison, <vscale x 16 x i32> zeroinitializer
+  %neg = fneg <vscale x 16 x half> %splat
+  %neg2 = fneg <vscale x 16 x half> %vb
+  %vd = call <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half> %neg, <vscale x 16 x half> %va, <vscale x 16 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x half> %vd
+}
+
+declare <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half>, <vscale x 32 x half>, <vscale x 32 x half>, metadata, metadata)
+
+define <vscale x 32 x half> @vfnmsub_vv_nxv32f16(<vscale x 32 x half> %va, <vscale x 32 x half> %vb, <vscale x 32 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re16.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e16, m8, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v24, v16
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 32 x half> %vc
+  %neg2 = fneg <vscale x 32 x half> %vb
+  %vd = call <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half> %neg, <vscale x 32 x half> %va, <vscale x 32 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 32 x half> %vd
+}
+
+define <vscale x 32 x half> @vfnmsub_vf_nxv32f16(<vscale x 32 x half> %va, <vscale x 32 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m8, ta, ma
+; CHECK-NEXT:    vfnmacc.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 32 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 32 x half> %head, <vscale x 32 x half> poison, <vscale x 32 x i32> zeroinitializer
+  %neg = fneg <vscale x 32 x half> %splat
+  %neg2 = fneg <vscale x 32 x half> %va
+  %vd = call <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half> %neg, <vscale x 32 x half> %vb, <vscale x 32 x half> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 32 x half> %vd
+}
+
+declare <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float>, <vscale x 1 x float>, <vscale x 1 x float>, metadata, metadata)
+
+define <vscale x 1 x float> @vfnmsub_vv_nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, <vscale x 1 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv1f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, mf2, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 1 x float> %vb
+  %neg2 = fneg <vscale x 1 x float> %vc
+  %vd = call <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %neg, <vscale x 1 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x float> %vd
+}
+
+define <vscale x 1 x float> @vfnmsub_vf_nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv1f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, mf2, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 1 x float> %head, <vscale x 1 x float> poison, <vscale x 1 x i32> zeroinitializer
+  %neg = fneg <vscale x 1 x float> %va
+  %neg2 = fneg <vscale x 1 x float> %vb
+  %vd = call <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float> %neg, <vscale x 1 x float> %splat, <vscale x 1 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x float> %vd
+}
+
+declare <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float>, <vscale x 2 x float>, <vscale x 2 x float>, metadata, metadata)
+
+define <vscale x 2 x float> @vfnmsub_vv_nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vb, <vscale x 2 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 2 x float> %vc
+  %neg2 = fneg <vscale x 2 x float> %vb
+  %vd = call <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %neg, <vscale x 2 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x float> %vd
+}
+
+define <vscale x 2 x float> @vfnmsub_vf_nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 2 x float> %head, <vscale x 2 x float> poison, <vscale x 2 x i32> zeroinitializer
+  %neg = fneg <vscale x 2 x float> %va
+  %neg2 = fneg <vscale x 2 x float> %vb
+  %vd = call <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float> %splat, <vscale x 2 x float> %neg, <vscale x 2 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x float> %vd
+}
+
+declare <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float>, metadata, metadata)
+
+define <vscale x 4 x float> @vfnmsub_vv_nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %vb, <vscale x 4 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m2, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v10, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 4 x float> %va
+  %neg2 = fneg <vscale x 4 x float> %vc
+  %vd = call <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float> %vb, <vscale x 4 x float> %neg, <vscale x 4 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x float> %vd
+}
+
+define <vscale x 4 x float> @vfnmsub_vf_nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m2, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 4 x float> %head, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
+  %neg = fneg <vscale x 4 x float> %splat
+  %neg2 = fneg <vscale x 4 x float> %vb
+  %vd = call <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %neg, <vscale x 4 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x float> %vd
+}
+
+declare <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float>, <vscale x 8 x float>, <vscale x 8 x float>, metadata, metadata)
+
+define <vscale x 8 x float> @vfnmsub_vv_nxv8f32(<vscale x 8 x float> %va, <vscale x 8 x float> %vb, <vscale x 8 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m4, ta, ma
+; CHECK-NEXT:    vfnmacc.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 8 x float> %vc
+  %neg2 = fneg <vscale x 8 x float> %va
+  %vd = call <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float> %vb, <vscale x 8 x float> %neg, <vscale x 8 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x float> %vd
+}
+
+define <vscale x 8 x float> @vfnmsub_vf_nxv8f32(<vscale x 8 x float> %va, <vscale x 8 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m4, ta, ma
+; CHECK-NEXT:    vfnmacc.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 8 x float> %head, <vscale x 8 x float> poison, <vscale x 8 x i32> zeroinitializer
+  %neg = fneg <vscale x 8 x float> %splat
+  %neg2 = fneg <vscale x 8 x float> %va
+  %vd = call <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float> %vb, <vscale x 8 x float> %neg, <vscale x 8 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x float> %vd
+}
+
+declare <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float>, <vscale x 16 x float>, <vscale x 16 x float>, metadata, metadata)
+
+define <vscale x 16 x float> @vfnmsub_vv_nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %vb, <vscale x 16 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re32.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e32, m8, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v24, v16
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 16 x float> %va
+  %neg2 = fneg <vscale x 16 x float> %vb
+  %vd = call <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float> %vc, <vscale x 16 x float> %neg, <vscale x 16 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x float> %vd
+}
+
+define <vscale x 16 x float> @vfnmsub_vf_nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m8, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 16 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 16 x float> %head, <vscale x 16 x float> poison, <vscale x 16 x i32> zeroinitializer
+  %neg = fneg <vscale x 16 x float> %splat
+  %neg2 = fneg <vscale x 16 x float> %vb
+  %vd = call <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float> %neg, <vscale x 16 x float> %va, <vscale x 16 x float> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x float> %vd
+}
+
+declare <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double>, <vscale x 1 x double>, <vscale x 1 x double>, metadata, metadata)
+
+define <vscale x 1 x double> @vfnmsub_vv_nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, <vscale x 1 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv1f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m1, ta, ma
+; CHECK-NEXT:    vfnmacc.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 1 x double> %vb
+  %neg2 = fneg <vscale x 1 x double> %va
+  %vd = call <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double> %vc, <vscale x 1 x double> %neg, <vscale x 1 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x double> %vd
+}
+
+define <vscale x 1 x double> @vfnmsub_vf_nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv1f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m1, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 1 x double> %head, <vscale x 1 x double> poison, <vscale x 1 x i32> zeroinitializer
+  %neg = fneg <vscale x 1 x double> %va
+  %neg2 = fneg <vscale x 1 x double> %vb
+  %vd = call <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double> %neg, <vscale x 1 x double> %splat, <vscale x 1 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x double> %vd
+}
+
+declare <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double>, <vscale x 2 x double>, <vscale x 2 x double>, metadata, metadata)
+
+define <vscale x 2 x double> @vfnmsub_vv_nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vb, <vscale x 2 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m2, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 2 x double> %va
+  %neg2 = fneg <vscale x 2 x double> %vb
+  %vd = call <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double> %neg, <vscale x 2 x double> %vc, <vscale x 2 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x double> %vd
+}
+
+define <vscale x 2 x double> @vfnmsub_vf_nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m2, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 2 x double> %head, <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer
+  %neg = fneg <vscale x 2 x double> %va
+  %neg2 = fneg <vscale x 2 x double> %vb
+  %vd = call <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double> %splat, <vscale x 2 x double> %neg, <vscale x 2 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x double> %vd
+}
+
+declare <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double>, <vscale x 4 x double>, <vscale x 4 x double>, metadata, metadata)
+
+define <vscale x 4 x double> @vfnmsub_vv_nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %vb, <vscale x 4 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m4, ta, ma
+; CHECK-NEXT:    vfnmadd.vv v8, v12, v16
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 4 x double> %vb
+  %neg2 = fneg <vscale x 4 x double> %vc
+  %vd = call <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double> %neg, <vscale x 4 x double> %va, <vscale x 4 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x double> %vd
+}
+
+define <vscale x 4 x double> @vfnmsub_vf_nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m4, ta, ma
+; CHECK-NEXT:    vfnmadd.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 4 x double> %head, <vscale x 4 x double> poison, <vscale x 4 x i32> zeroinitializer
+  %neg = fneg <vscale x 4 x double> %splat
+  %neg2 = fneg <vscale x 4 x double> %vb
+  %vd = call <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %neg, <vscale x 4 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x double> %vd
+}
+
+declare <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double>, <vscale x 8 x double>, <vscale x 8 x double>, metadata, metadata)
+
+define <vscale x 8 x double> @vfnmsub_vv_nxv8f64(<vscale x 8 x double> %va, <vscale x 8 x double> %vb, <vscale x 8 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re64.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e64, m8, ta, ma
+; CHECK-NEXT:    vfnmacc.vv v8, v16, v24
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 8 x double> %vb
+  %neg2 = fneg <vscale x 8 x double> %va
+  %vd = call <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double> %neg, <vscale x 8 x double> %vc, <vscale x 8 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x double> %vd
+}
+
+define <vscale x 8 x double> @vfnmsub_vf_nxv8f64(<vscale x 8 x double> %va, <vscale x 8 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m8, ta, ma
+; CHECK-NEXT:    vfnmacc.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 8 x double> %head, <vscale x 8 x double> poison, <vscale x 8 x i32> zeroinitializer
+  %neg = fneg <vscale x 8 x double> %splat
+  %neg2 = fneg <vscale x 8 x double> %va
+  %vd = call <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double> %vb, <vscale x 8 x double> %neg, <vscale x 8 x double> %neg2, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x double> %vd
+}

diff  --git a/llvm/test/CodeGen/RISCV/rvv/vfnmsub-constrained-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/vfnmsub-constrained-sdnode.ll
new file mode 100644
index 000000000000..48c14404691e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/vfnmsub-constrained-sdnode.ll
@@ -0,0 +1,401 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=ilp32d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=lp64d \
+; RUN:     -verify-machineinstrs < %s | FileCheck %s
+
+; This tests a mix of vfnmsac and vfnmsub by using 
diff erent operand orders to
+; trigger commuting in TwoAddressInstructionPass.
+
+declare <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half>, <vscale x 1 x half>, <vscale x 1 x half>, metadata, metadata)
+
+define <vscale x 1 x half> @vfnmsub_vv_nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, <vscale x 1 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv1f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf4, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 1 x half> %va
+  %vd = call <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half> %neg, <vscale x 1 x half> %vb, <vscale x 1 x half> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x half> %vd
+}
+
+define <vscale x 1 x half> @vfnmsub_vf_nxv1f16(<vscale x 1 x half> %va, <vscale x 1 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv1f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf4, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 1 x half> %head, <vscale x 1 x half> poison, <vscale x 1 x i32> zeroinitializer
+  %neg = fneg <vscale x 1 x half> %va
+  %vd = call <vscale x 1 x half> @llvm.experimental.constrained.fma.nxv1f16(<vscale x 1 x half> %neg, <vscale x 1 x half> %splat, <vscale x 1 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x half> %vd
+}
+
+declare <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half>, <vscale x 2 x half>, <vscale x 2 x half>, metadata, metadata)
+
+define <vscale x 2 x half> @vfnmsub_vv_nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vb, <vscale x 2 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf2, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 2 x half> %va
+  %vd = call <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half> %neg, <vscale x 2 x half> %vc, <vscale x 2 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x half> %vd
+}
+
+define <vscale x 2 x half> @vfnmsub_vf_nxv2f16(<vscale x 2 x half> %va, <vscale x 2 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, mf2, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 2 x half> %head, <vscale x 2 x half> poison, <vscale x 2 x i32> zeroinitializer
+  %neg = fneg <vscale x 2 x half> %va
+  %vd = call <vscale x 2 x half> @llvm.experimental.constrained.fma.nxv2f16(<vscale x 2 x half> %splat, <vscale x 2 x half> %neg, <vscale x 2 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x half> %vd
+}
+
+declare <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half>, <vscale x 4 x half>, <vscale x 4 x half>, metadata, metadata)
+
+define <vscale x 4 x half> @vfnmsub_vv_nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %vb, <vscale x 4 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m1, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 4 x half> %vb
+  %vd = call <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half> %neg, <vscale x 4 x half> %va, <vscale x 4 x half> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x half> %vd
+}
+
+define <vscale x 4 x half> @vfnmsub_vf_nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv4f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m1, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 4 x half> %head, <vscale x 4 x half> poison, <vscale x 4 x i32> zeroinitializer
+  %neg = fneg <vscale x 4 x half> %splat
+  %vd = call <vscale x 4 x half> @llvm.experimental.constrained.fma.nxv4f16(<vscale x 4 x half> %va, <vscale x 4 x half> %neg, <vscale x 4 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x half> %vd
+}
+
+declare <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half>, <vscale x 8 x half>, <vscale x 8 x half>, metadata, metadata)
+
+define <vscale x 8 x half> @vfnmsub_vv_nxv8f16(<vscale x 8 x half> %va, <vscale x 8 x half> %vb, <vscale x 8 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m2, ta, ma
+; CHECK-NEXT:    vfnmsac.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 8 x half> %vb
+  %vd = call <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half> %neg, <vscale x 8 x half> %vc, <vscale x 8 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x half> %vd
+}
+
+define <vscale x 8 x half> @vfnmsub_vf_nxv8f16(<vscale x 8 x half> %va, <vscale x 8 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv8f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m2, ta, ma
+; CHECK-NEXT:    vfnmsac.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 8 x half> %head, <vscale x 8 x half> poison, <vscale x 8 x i32> zeroinitializer
+  %neg = fneg <vscale x 8 x half> %splat
+  %vd = call <vscale x 8 x half> @llvm.experimental.constrained.fma.nxv8f16(<vscale x 8 x half> %vb, <vscale x 8 x half> %neg, <vscale x 8 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x half> %vd
+}
+
+declare <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half>, <vscale x 16 x half>, <vscale x 16 x half>, metadata, metadata)
+
+define <vscale x 16 x half> @vfnmsub_vv_nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %vb, <vscale x 16 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m4, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 16 x half> %vc
+  %vd = call <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half> %neg, <vscale x 16 x half> %va, <vscale x 16 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x half> %vd
+}
+
+define <vscale x 16 x half> @vfnmsub_vf_nxv16f16(<vscale x 16 x half> %va, <vscale x 16 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv16f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m4, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 16 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 16 x half> %head, <vscale x 16 x half> poison, <vscale x 16 x i32> zeroinitializer
+  %neg = fneg <vscale x 16 x half> %splat
+  %vd = call <vscale x 16 x half> @llvm.experimental.constrained.fma.nxv16f16(<vscale x 16 x half> %neg, <vscale x 16 x half> %va, <vscale x 16 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x half> %vd
+}
+
+declare <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half>, <vscale x 32 x half>, <vscale x 32 x half>, metadata, metadata)
+
+define <vscale x 32 x half> @vfnmsub_vv_nxv32f16(<vscale x 32 x half> %va, <vscale x 32 x half> %vb, <vscale x 32 x half> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re16.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e16, m8, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v24, v16
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 32 x half> %vc
+  %vd = call <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half> %neg, <vscale x 32 x half> %va, <vscale x 32 x half> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 32 x half> %vd
+}
+
+define <vscale x 32 x half> @vfnmsub_vf_nxv32f16(<vscale x 32 x half> %va, <vscale x 32 x half> %vb, half %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv32f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e16, m8, ta, ma
+; CHECK-NEXT:    vfnmsac.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 32 x half> poison, half %c, i32 0
+  %splat = shufflevector <vscale x 32 x half> %head, <vscale x 32 x half> poison, <vscale x 32 x i32> zeroinitializer
+  %neg = fneg <vscale x 32 x half> %splat
+  %vd = call <vscale x 32 x half> @llvm.experimental.constrained.fma.nxv32f16(<vscale x 32 x half> %neg, <vscale x 32 x half> %vb, <vscale x 32 x half> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 32 x half> %vd
+}
+
+declare <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float>, <vscale x 1 x float>, <vscale x 1 x float>, metadata, metadata)
+
+define <vscale x 1 x float> @vfnmsub_vv_nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, <vscale x 1 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv1f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, mf2, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v9, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 1 x float> %vb
+  %vd = call <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %neg, <vscale x 1 x float> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x float> %vd
+}
+
+define <vscale x 1 x float> @vfnmsub_vf_nxv1f32(<vscale x 1 x float> %va, <vscale x 1 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv1f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, mf2, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 1 x float> %head, <vscale x 1 x float> poison, <vscale x 1 x i32> zeroinitializer
+  %neg = fneg <vscale x 1 x float> %va
+  %vd = call <vscale x 1 x float> @llvm.experimental.constrained.fma.nxv1f32(<vscale x 1 x float> %neg, <vscale x 1 x float> %splat, <vscale x 1 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x float> %vd
+}
+
+declare <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float>, <vscale x 2 x float>, <vscale x 2 x float>, metadata, metadata)
+
+define <vscale x 2 x float> @vfnmsub_vv_nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vb, <vscale x 2 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 2 x float> %vc
+  %vd = call <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %neg, <vscale x 2 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x float> %vd
+}
+
+define <vscale x 2 x float> @vfnmsub_vf_nxv2f32(<vscale x 2 x float> %va, <vscale x 2 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 2 x float> %head, <vscale x 2 x float> poison, <vscale x 2 x i32> zeroinitializer
+  %neg = fneg <vscale x 2 x float> %va
+  %vd = call <vscale x 2 x float> @llvm.experimental.constrained.fma.nxv2f32(<vscale x 2 x float> %splat, <vscale x 2 x float> %neg, <vscale x 2 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x float> %vd
+}
+
+declare <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float>, metadata, metadata)
+
+define <vscale x 4 x float> @vfnmsub_vv_nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %vb, <vscale x 4 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m2, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v10, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 4 x float> %va
+  %vd = call <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float> %vb, <vscale x 4 x float> %neg, <vscale x 4 x float> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x float> %vd
+}
+
+define <vscale x 4 x float> @vfnmsub_vf_nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv4f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m2, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 4 x float> %head, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
+  %neg = fneg <vscale x 4 x float> %splat
+  %vd = call <vscale x 4 x float> @llvm.experimental.constrained.fma.nxv4f32(<vscale x 4 x float> %va, <vscale x 4 x float> %neg, <vscale x 4 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x float> %vd
+}
+
+declare <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float>, <vscale x 8 x float>, <vscale x 8 x float>, metadata, metadata)
+
+define <vscale x 8 x float> @vfnmsub_vv_nxv8f32(<vscale x 8 x float> %va, <vscale x 8 x float> %vb, <vscale x 8 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m4, ta, ma
+; CHECK-NEXT:    vfnmsac.vv v8, v16, v12
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 8 x float> %vc
+  %vd = call <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float> %vb, <vscale x 8 x float> %neg, <vscale x 8 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x float> %vd
+}
+
+define <vscale x 8 x float> @vfnmsub_vf_nxv8f32(<vscale x 8 x float> %va, <vscale x 8 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv8f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m4, ta, ma
+; CHECK-NEXT:    vfnmsac.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 8 x float> %head, <vscale x 8 x float> poison, <vscale x 8 x i32> zeroinitializer
+  %neg = fneg <vscale x 8 x float> %splat
+  %vd = call <vscale x 8 x float> @llvm.experimental.constrained.fma.nxv8f32(<vscale x 8 x float> %vb, <vscale x 8 x float> %neg, <vscale x 8 x float> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x float> %vd
+}
+
+declare <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float>, <vscale x 16 x float>, <vscale x 16 x float>, metadata, metadata)
+
+define <vscale x 16 x float> @vfnmsub_vv_nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %vb, <vscale x 16 x float> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re32.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e32, m8, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v24, v16
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 16 x float> %va
+  %vd = call <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float> %vc, <vscale x 16 x float> %neg, <vscale x 16 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x float> %vd
+}
+
+define <vscale x 16 x float> @vfnmsub_vf_nxv16f32(<vscale x 16 x float> %va, <vscale x 16 x float> %vb, float %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv16f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m8, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 16 x float> poison, float %c, i32 0
+  %splat = shufflevector <vscale x 16 x float> %head, <vscale x 16 x float> poison, <vscale x 16 x i32> zeroinitializer
+  %neg = fneg <vscale x 16 x float> %splat
+  %vd = call <vscale x 16 x float> @llvm.experimental.constrained.fma.nxv16f32(<vscale x 16 x float> %neg, <vscale x 16 x float> %va, <vscale x 16 x float> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 16 x float> %vd
+}
+
+declare <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double>, <vscale x 1 x double>, <vscale x 1 x double>, metadata, metadata)
+
+define <vscale x 1 x double> @vfnmsub_vv_nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, <vscale x 1 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv1f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m1, ta, ma
+; CHECK-NEXT:    vfnmsac.vv v8, v10, v9
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 1 x double> %vb
+  %vd = call <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double> %vc, <vscale x 1 x double> %neg, <vscale x 1 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x double> %vd
+}
+
+define <vscale x 1 x double> @vfnmsub_vf_nxv1f64(<vscale x 1 x double> %va, <vscale x 1 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv1f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m1, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v9
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 1 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 1 x double> %head, <vscale x 1 x double> poison, <vscale x 1 x i32> zeroinitializer
+  %neg = fneg <vscale x 1 x double> %va
+  %vd = call <vscale x 1 x double> @llvm.experimental.constrained.fma.nxv1f64(<vscale x 1 x double> %neg, <vscale x 1 x double> %splat, <vscale x 1 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 1 x double> %vd
+}
+
+declare <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double>, <vscale x 2 x double>, <vscale x 2 x double>, metadata, metadata)
+
+define <vscale x 2 x double> @vfnmsub_vv_nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vb, <vscale x 2 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m2, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v12, v10
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 2 x double> %va
+  %vd = call <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double> %neg, <vscale x 2 x double> %vc, <vscale x 2 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x double> %vd
+}
+
+define <vscale x 2 x double> @vfnmsub_vf_nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv2f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m2, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v10
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 2 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 2 x double> %head, <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer
+  %neg = fneg <vscale x 2 x double> %va
+  %vd = call <vscale x 2 x double> @llvm.experimental.constrained.fma.nxv2f64(<vscale x 2 x double> %splat, <vscale x 2 x double> %neg, <vscale x 2 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 2 x double> %vd
+}
+
+declare <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double>, <vscale x 4 x double>, <vscale x 4 x double>, metadata, metadata)
+
+define <vscale x 4 x double> @vfnmsub_vv_nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %vb, <vscale x 4 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m4, ta, ma
+; CHECK-NEXT:    vfnmsub.vv v8, v12, v16
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 4 x double> %vb
+  %vd = call <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double> %neg, <vscale x 4 x double> %va, <vscale x 4 x double> %vc, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x double> %vd
+}
+
+define <vscale x 4 x double> @vfnmsub_vf_nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv4f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m4, ta, ma
+; CHECK-NEXT:    vfnmsub.vf v8, fa0, v12
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 4 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 4 x double> %head, <vscale x 4 x double> poison, <vscale x 4 x i32> zeroinitializer
+  %neg = fneg <vscale x 4 x double> %splat
+  %vd = call <vscale x 4 x double> @llvm.experimental.constrained.fma.nxv4f64(<vscale x 4 x double> %va, <vscale x 4 x double> %neg, <vscale x 4 x double> %vb, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 4 x double> %vd
+}
+
+declare <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double>, <vscale x 8 x double>, <vscale x 8 x double>, metadata, metadata)
+
+define <vscale x 8 x double> @vfnmsub_vv_nxv8f64(<vscale x 8 x double> %va, <vscale x 8 x double> %vb, <vscale x 8 x double> %vc) {
+; CHECK-LABEL: vfnmsub_vv_nxv8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl8re64.v v24, (a0)
+; CHECK-NEXT:    vsetvli a0, zero, e64, m8, ta, ma
+; CHECK-NEXT:    vfnmsac.vv v8, v16, v24
+; CHECK-NEXT:    ret
+  %neg = fneg <vscale x 8 x double> %vb
+  %vd = call <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double> %neg, <vscale x 8 x double> %vc, <vscale x 8 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x double> %vd
+}
+
+define <vscale x 8 x double> @vfnmsub_vf_nxv8f64(<vscale x 8 x double> %va, <vscale x 8 x double> %vb, double %c) {
+; CHECK-LABEL: vfnmsub_vf_nxv8f64:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e64, m8, ta, ma
+; CHECK-NEXT:    vfnmsac.vf v8, fa0, v16
+; CHECK-NEXT:    ret
+  %head = insertelement <vscale x 8 x double> poison, double %c, i32 0
+  %splat = shufflevector <vscale x 8 x double> %head, <vscale x 8 x double> poison, <vscale x 8 x i32> zeroinitializer
+  %neg = fneg <vscale x 8 x double> %splat
+  %vd = call <vscale x 8 x double> @llvm.experimental.constrained.fma.nxv8f64(<vscale x 8 x double> %vb, <vscale x 8 x double> %neg, <vscale x 8 x double> %va, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  ret <vscale x 8 x double> %vd
+}


        


More information about the llvm-commits mailing list