diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td
@@ -29,15 +29,13 @@
 // Instruction Class Templates
 //===----------------------------------------------------------------------===//
 
-let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
-class FPFMAD_rrr_frm<RISCVOpcode opcode, string opcodestr>
-    : RVInstR4<0b01, opcode, (outs FPR64:$rd),
-               (ins FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, frmarg:$funct3),
-                opcodestr, "$rd, $rs1, $rs2, $rs3, $funct3">;
-
-class FPFMADDynFrmAlias<FPFMAD_rrr_frm Inst, string OpcodeStr>
-    : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3",
-                (Inst FPR64:$rd, FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>;
+multiclass FPFMAD_mc<RISCVOpcode opcode, string OpcodeStr> {
+  def _gen : FPFMA_gen<opcode, OpcodeStr, 0b01, FPR64>;
+  def _def : FPFMA_def<opcode, OpcodeStr, 0b01, FPR64>;
+  def      : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3",
+                       (!cast<Instruction>(NAME # "_gen")
+                        FPR64:$rd, FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>;
+}
 
 let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
 class FPALUD_rr<bits<7> funct7, bits<3> funct3, string opcodestr>
@@ -81,18 +79,14 @@
                    "fsd", "$rs2, ${imm12}(${rs1})">,
           Sched<[WriteFST64, ReadStoreData, ReadFMemBase]>;
 
-def FMADD_D  : FPFMAD_rrr_frm<OPC_MADD, "fmadd.d">,
-               Sched<[WriteFMulAdd64, ReadFMulAdd64, ReadFMulAdd64, ReadFMulAdd64]>;
-def          : FPFMADDynFrmAlias<FMADD_D, "fmadd.d">;
-def FMSUB_D  : FPFMAD_rrr_frm<OPC_MSUB, "fmsub.d">,
-               Sched<[WriteFMulSub64, ReadFMulSub64, ReadFMulSub64, ReadFMulSub64]>;
-def          : FPFMADDynFrmAlias<FMSUB_D, "fmsub.d">;
-def FNMSUB_D : FPFMAD_rrr_frm<OPC_NMSUB, "fnmsub.d">,
-               Sched<[WriteFMulSub64, ReadFMulSub64, ReadFMulSub64, ReadFMulSub64]>;
-def          : FPFMADDynFrmAlias<FNMSUB_D, "fnmsub.d">;
-def FNMADD_D : FPFMAD_rrr_frm<OPC_NMADD, "fnmadd.d">,
-               Sched<[WriteFMulAdd64, ReadFMulAdd64, ReadFMulAdd64, ReadFMulAdd64]>;
-def          : FPFMADDynFrmAlias<FNMADD_D, "fnmadd.d">;
+defm FMADD_D  : FPFMAD_mc<OPC_MADD, "fmadd.d">,
+                Sched<[WriteFMulAdd64, ReadFMulAdd64, ReadFMulAdd64, ReadFMulAdd64]>;
+defm FMSUB_D  : FPFMAD_mc<OPC_MSUB, "fmsub.d">,
+                Sched<[WriteFMulSub64, ReadFMulSub64, ReadFMulSub64, ReadFMulSub64]>;
+defm FNMSUB_D : FPFMAD_mc<OPC_NMSUB, "fnmsub.d">,
+                Sched<[WriteFMulSub64, ReadFMulSub64, ReadFMulSub64, ReadFMulSub64]>;
+defm FNMADD_D : FPFMAD_mc<OPC_NMADD, "fnmadd.d">,
+                Sched<[WriteFMulAdd64, ReadFMulAdd64, ReadFMulAdd64, ReadFMulAdd64]>;
 
 def FADD_D : FPALUD_rr_frm<0b0000001, "fadd.d">,
              Sched<[WriteFALU64, ReadFALU64, ReadFALU64]>;
@@ -267,19 +261,19 @@
 
 // fmadd: rs1 * rs2 + rs3
 def : Pat<(fma FPR64:$rs1, FPR64:$rs2, FPR64:$rs3),
-          (FMADD_D $rs1, $rs2, $rs3, 0b111)>;
+          (FMADD_D_def $rs1, $rs2, $rs3)>;
 
 // fmsub: rs1 * rs2 - rs3
 def : Pat<(fma FPR64:$rs1, FPR64:$rs2, (fneg FPR64:$rs3)),
-          (FMSUB_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>;
+          (FMSUB_D_def FPR64:$rs1, FPR64:$rs2, FPR64:$rs3)>;
 
 // fnmsub: -rs1 * rs2 + rs3
 def : Pat<(fma (fneg FPR64:$rs1), FPR64:$rs2, FPR64:$rs3),
-          (FNMSUB_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>;
+          (FNMSUB_D_def FPR64:$rs1, FPR64:$rs2, FPR64:$rs3)>;
 
 // fnmadd: -rs1 * rs2 - rs3
 def : Pat<(fma (fneg FPR64:$rs1), FPR64:$rs2, (fneg FPR64:$rs3)),
-          (FNMADD_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>;
+          (FNMADD_D_def FPR64:$rs1, FPR64:$rs2, FPR64:$rs3)>;
 
 // The RISC-V 2.2 user-level ISA spec defines fmin and fmax as returning the
 // canonical NaN when giving a signaling NaN. This doesn't match the LLVM
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
@@ -47,15 +47,42 @@
 // Instruction class templates
 //===----------------------------------------------------------------------===//
 
-let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
-class FPFMAS_rrr_frm<RISCVOpcode opcode, string opcodestr>
-    : RVInstR4<0b00, opcode, (outs FPR32:$rd),
-               (ins FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, frmarg:$funct3),
-                opcodestr, "$rd, $rs1, $rs2, $rs3, $funct3">;
+// Instructions that may depend on dynamic rounding mode in FRM or set accrued
+// flags in FFLAGs exist in two forms:
+// - generic, which depends on FRM and defined FFLAGS. Constrained intrinsics
+//   are lowered to this form.
+// - default, which ignores dependency on FRM and influence on FFLAGS. It is
+//   used to lower regular IR FP operations.
+
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+  class FPFMA_gen<RISCVOpcode opcode, string opcodestr,
+                  bits<2> kind, RegisterClass rty>
+      : RVInstR4<kind, opcode, (outs rty:$rd),
+                 (ins rty:$rs1, rty:$rs2, rty:$rs3, frmarg:$funct3),
+                  opcodestr, "$rd, $rs1, $rs2, $rs3, $funct3"> {
+    let Defs = [FFLAGS];
+    let Uses = [FRM];
+  }
+
+  class FPFMA_def<RISCVOpcode opcode, string opcodestr,
+                  bits<2> kind, RegisterClass rty>
+      : RVInstR4<kind, opcode, (outs rty:$rd),
+                 (ins rty:$rs1, rty:$rs2, rty:$rs3),
+                  opcodestr, "$rd, $rs1, $rs2, $rs3, dyn"> {
+    let isCodeGenOnly = 1;
+    // FIXME: Until constrained intrinsics are supported by RISCV codegen, use
+    // dynamic rounding mode.
+    let funct3 = 0b111;
+  }
+}
 
-class FPFMASDynFrmAlias<FPFMAS_rrr_frm Inst, string OpcodeStr>
-    : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3",
-                (Inst FPR32:$rd, FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>;
+multiclass FPFMAS_mc<RISCVOpcode opcode, string OpcodeStr> {
+  def _gen : FPFMA_gen<opcode, OpcodeStr, 0b00, FPR32>;
+  def _def : FPFMA_def<opcode, OpcodeStr, 0b00, FPR32>;
+  def      : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3",
+                       (!cast<Instruction>(NAME # "_gen")
+                        FPR32:$rd, FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>;
+}
 
 let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
 class FPALUS_rr<bits<7> funct7, bits<3> funct3, string opcodestr>
@@ -116,18 +143,14 @@
                    "fsw", "$rs2, ${imm12}(${rs1})">,
           Sched<[WriteFST32, ReadStoreData, ReadFMemBase]>;
 
-def FMADD_S  : FPFMAS_rrr_frm<OPC_MADD, "fmadd.s">,
-               Sched<[WriteFMulAdd32, ReadFMulAdd32, ReadFMulAdd32, ReadFMulAdd32]>;
-def          : FPFMASDynFrmAlias<FMADD_S, "fmadd.s">;
-def FMSUB_S  : FPFMAS_rrr_frm<OPC_MSUB, "fmsub.s">,
-               Sched<[WriteFMulSub32, ReadFMulSub32, ReadFMulSub32, ReadFMulSub32]>;
-def          : FPFMASDynFrmAlias<FMSUB_S, "fmsub.s">;
-def FNMSUB_S : FPFMAS_rrr_frm<OPC_NMSUB, "fnmsub.s">,
-               Sched<[WriteFMulSub32, ReadFMulSub32, ReadFMulSub32, ReadFMulSub32]>;
-def          : FPFMASDynFrmAlias<FNMSUB_S, "fnmsub.s">;
-def FNMADD_S : FPFMAS_rrr_frm<OPC_NMADD, "fnmadd.s">,
-               Sched<[WriteFMulAdd32, ReadFMulAdd32, ReadFMulAdd32, ReadFMulAdd32]>;
-def          : FPFMASDynFrmAlias<FNMADD_S, "fnmadd.s">;
+defm FMADD_S  : FPFMAS_mc<OPC_MADD, "fmadd.s">,
+                Sched<[WriteFMulAdd32, ReadFMulAdd32, ReadFMulAdd32, ReadFMulAdd32]>;
+defm FMSUB_S  : FPFMAS_mc<OPC_MSUB, "fmsub.s">,
+                Sched<[WriteFMulSub32, ReadFMulSub32, ReadFMulSub32, ReadFMulSub32]>;
+defm FNMSUB_S : FPFMAS_mc<OPC_NMSUB, "fnmsub.s">,
+                Sched<[WriteFMulSub32, ReadFMulSub32, ReadFMulSub32, ReadFMulSub32]>;
+defm FNMADD_S : FPFMAS_mc<OPC_NMADD, "fnmadd.s">,
+                Sched<[WriteFMulAdd32, ReadFMulAdd32, ReadFMulAdd32, ReadFMulAdd32]>;
 
 def FADD_S : FPALUS_rr_frm<0b0000000, "fadd.s">,
              Sched<[WriteFALU32, ReadFALU32, ReadFALU32]>;
@@ -323,19 +346,19 @@
 
 // fmadd: rs1 * rs2 + rs3
 def : Pat<(fma FPR32:$rs1, FPR32:$rs2, FPR32:$rs3),
-          (FMADD_S $rs1, $rs2, $rs3, 0b111)>;
+          (FMADD_S_def $rs1, $rs2, $rs3)>;
 
 // fmsub: rs1 * rs2 - rs3
 def : Pat<(fma FPR32:$rs1, FPR32:$rs2, (fneg FPR32:$rs3)),
-          (FMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>;
+          (FMSUB_S_def FPR32:$rs1, FPR32:$rs2, FPR32:$rs3)>;
 
 // fnmsub: -rs1 * rs2 + rs3
 def : Pat<(fma (fneg FPR32:$rs1), FPR32:$rs2, FPR32:$rs3),
-          (FNMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>;
+          (FNMSUB_S_def FPR32:$rs1, FPR32:$rs2, FPR32:$rs3)>;
 
 // fnmadd: -rs1 * rs2 - rs3
 def : Pat<(fma (fneg FPR32:$rs1), FPR32:$rs2, (fneg FPR32:$rs3)),
-          (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>;
+          (FNMADD_S_def FPR32:$rs1, FPR32:$rs2, FPR32:$rs3)>;
 
 // The RISC-V 2.2 user-level ISA spec defines fmin and fmax as returning the
 // canonical NaN when given a signaling NaN. This doesn't match the LLVM
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
@@ -31,15 +31,13 @@
 // Instruction class templates
 //===----------------------------------------------------------------------===//
 
-let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
-class FPFMAH_rrr_frm<RISCVOpcode opcode, string opcodestr>
-    : RVInstR4<0b10, opcode, (outs FPR16:$rd),
-               (ins FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, frmarg:$funct3),
-                opcodestr, "$rd, $rs1, $rs2, $rs3, $funct3">;
-
-class FPFMAHDynFrmAlias<FPFMAH_rrr_frm Inst, string OpcodeStr>
-    : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3",
-                (Inst FPR16:$rd, FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, 0b111)>;
+multiclass FPFMAH_mc<RISCVOpcode opcode, string OpcodeStr> {
+  def _gen : FPFMA_gen<opcode, OpcodeStr, 0b10, FPR16>;
+  def _def : FPFMA_def<opcode, OpcodeStr, 0b10, FPR16>;
+  def      : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3",
+                       (!cast<Instruction>(NAME # "_gen")
+                        FPR16:$rd, FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, 0b111)>;
+}
 
 let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
 class FPALUH_rr<bits<7> funct7, bits<3> funct3, string opcodestr>
@@ -82,18 +80,14 @@
                    "fsh", "$rs2, ${imm12}(${rs1})">,
           Sched<[WriteFST16, ReadStoreData, ReadFMemBase]>;
 
-def FMADD_H  : FPFMAH_rrr_frm<OPC_MADD, "fmadd.h">,
-               Sched<[WriteFMulAdd16, ReadFMulAdd16, ReadFMulAdd16, ReadFMulAdd16]>;
-def          : FPFMAHDynFrmAlias<FMADD_H, "fmadd.h">;
-def FMSUB_H  : FPFMAH_rrr_frm<OPC_MSUB, "fmsub.h">,
-               Sched<[WriteFMulSub16, ReadFMulSub16, ReadFMulSub16, ReadFMulSub16]>;
-def          : FPFMAHDynFrmAlias<FMSUB_H, "fmsub.h">;
-def FNMSUB_H : FPFMAH_rrr_frm<OPC_NMSUB, "fnmsub.h">,
-               Sched<[WriteFMulSub16, ReadFMulSub16, ReadFMulSub16, ReadFMulSub16]>;
-def          : FPFMAHDynFrmAlias<FNMSUB_H, "fnmsub.h">;
-def FNMADD_H : FPFMAH_rrr_frm<OPC_NMADD, "fnmadd.h">,
-               Sched<[WriteFMulAdd16, ReadFMulAdd16, ReadFMulAdd16, ReadFMulAdd16]>;
-def          : FPFMAHDynFrmAlias<FNMADD_H, "fnmadd.h">;
+defm FMADD_H  : FPFMAH_mc<OPC_MADD, "fmadd.h">,
+                Sched<[WriteFMulAdd16, ReadFMulAdd16, ReadFMulAdd16, ReadFMulAdd16]>;
+defm FMSUB_H  : FPFMAH_mc<OPC_MSUB, "fmsub.h">,
+                Sched<[WriteFMulSub16, ReadFMulSub16, ReadFMulSub16, ReadFMulSub16]>;
+defm FNMSUB_H : FPFMAH_mc<OPC_NMSUB, "fnmsub.h">,
+                Sched<[WriteFMulSub16, ReadFMulSub16, ReadFMulSub16, ReadFMulSub16]>;
+defm FNMADD_H : FPFMAH_mc<OPC_NMADD, "fnmadd.h">,
+                Sched<[WriteFMulAdd16, ReadFMulAdd16, ReadFMulAdd16, ReadFMulAdd16]>;
 
 def FADD_H : FPALUH_rr_frm<0b0000010, "fadd.h">,
              Sched<[WriteFALU16, ReadFALU16, ReadFALU16]>;
@@ -283,19 +277,19 @@
 
 // fmadd: rs1 * rs2 + rs3
 def : Pat<(fma FPR16:$rs1, FPR16:$rs2, FPR16:$rs3),
-          (FMADD_H $rs1, $rs2, $rs3, 0b111)>;
+          (FMADD_H_def $rs1, $rs2, $rs3)>;
 
 // fmsub: rs1 * rs2 - rs3
 def : Pat<(fma FPR16:$rs1, FPR16:$rs2, (fneg FPR16:$rs3)),
-          (FMSUB_H FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, 0b111)>;
+          (FMSUB_H_def FPR16:$rs1, FPR16:$rs2, FPR16:$rs3)>;
 
 // fnmsub: -rs1 * rs2 + rs3
 def : Pat<(fma (fneg FPR16:$rs1), FPR16:$rs2, FPR16:$rs3),
-          (FNMSUB_H FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, 0b111)>;
+          (FNMSUB_H_def FPR16:$rs1, FPR16:$rs2, FPR16:$rs3)>;
 
 // fnmadd: -rs1 * rs2 - rs3
 def : Pat<(fma (fneg FPR16:$rs1), FPR16:$rs2, (fneg FPR16:$rs3)),
-          (FNMADD_H FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, 0b111)>;
+          (FNMADD_H_def FPR16:$rs1, FPR16:$rs2, FPR16:$rs3)>;
 
 def : PatFpr16Fpr16<fminnum, FMIN_H>;
 def : PatFpr16Fpr16<fmaxnum, FMAX_H>;