zfh: fused multiply add encodings

PiperOrigin-RevId: 759314983
Change-Id: I7ab0cd8e20807e7af70bdcaa2944b4af7ffddc13
diff --git a/riscv/riscv_zfh.bin_fmt b/riscv/riscv_zfh.bin_fmt
index 92c7c9a..7ed55d4 100644
--- a/riscv/riscv_zfh.bin_fmt
+++ b/riscv/riscv_zfh.bin_fmt
@@ -50,4 +50,8 @@
   fcmplt_h  : RType : func7 == 0b1010010, func3 == 0b001, opcode == 0b1010011;
   fcmple_h  : RType : func7 == 0b1010010, func3 == 0b000, opcode == 0b1010011;
   fclass_h  : RType : func7 == 0b1110010, rs2 == 0b00000, func3 == 0b001, opcode == 0b1010011;
+  fmadd_h   : R4Type : func2 == 0b10, opcode == 0b1000011;
+  fmsub_h   : R4Type : func2 == 0b10, opcode == 0b1000111;
+  fnmsub_h  : R4Type : func2 == 0b10, opcode == 0b1001011;
+  fnmadd_h  : R4Type : func2 == 0b10, opcode == 0b1001111;
 };
diff --git a/riscv/riscv_zfh.isa b/riscv/riscv_zfh.isa
index c4514e7..33d15cc 100644
--- a/riscv/riscv_zfh.isa
+++ b/riscv/riscv_zfh.isa
@@ -192,5 +192,21 @@
       resources: { next_pc, frs1 : rd[0..]},
       semfunc: "&RV32::RiscVZfhFclass",
       disasm: "fclass.h", "%rd, %frs1";
+    fmadd_h{: frs1, frs2, frs3, rm : frd, fflags},
+      resources: {next_pc, frs1, frs2, frs3 : frd[0..]},
+      semfunc: "&RiscVZfhFmadd",
+      disasm: "fmadd.h", "%frd, %frs1, %frs2, %frs3";
+    fmsub_h{: frs1, frs2, frs3, rm : frd, fflags},
+      resources: {next_pc, frs1, frs2, frs3 : frd[0..]},
+      semfunc: "&RiscVZfhFmsub",
+      disasm: "fmsub.h", "%frd, %frs1, %frs2, %frs3";
+    fnmadd_h{: frs1, frs2, frs3, rm : frd, fflags},
+      resources: {next_pc, frs1, frs2, frs3 : frd[0..]},
+      semfunc: "&RiscVZfhFnmadd",
+      disasm: "fnmadd.h", "%frd, %frs1, %frs2, %frs3";
+    fnmsub_h{: frs1, frs2, frs3, rm : frd, fflags},
+      resources: {next_pc, frs1, frs2, frs3 : frd[0..]},
+      semfunc: "&RiscVZfhFnmsub",
+      disasm: "fnmsub.h", "%frd, %frs1, %frs2, %frs3";
   }
 }
diff --git a/riscv/test/riscv_getters_zfh.h b/riscv/test/riscv_getters_zfh.h
index bdb926c..0722c3e 100644
--- a/riscv/test/riscv_getters_zfh.h
+++ b/riscv/test/riscv_getters_zfh.h
@@ -78,6 +78,12 @@
         common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
         kFRegisterAliases[num]);
   });
+  Insert(getter_map, *Enum::kFrs3, [common]() -> SourceOperandInterface * {
+    int num = Extractors::Inst32Format::ExtractRs3(common->inst_word());
+    return GetRegisterSourceOp<FloatRegister>(
+        common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
+        kFRegisterAliases[num]);
+  });
 }
 
 template <typename Enum, typename Extractors, typename IntegerRegister>
diff --git a/riscv/test/zfh_encoding_test.cc b/riscv/test/zfh_encoding_test.cc
index a376c21..f767556 100644
--- a/riscv/test/zfh_encoding_test.cc
+++ b/riscv/test/zfh_encoding_test.cc
@@ -111,6 +111,14 @@
 constexpr uint32_t kFcmpleH = 0b1010010'00000'00000'000'00000'1010011;
 //                              func7  |     | rs1 |fn3| rd  | opcode
 constexpr uint32_t kFclassH = 0b1110010'00000'00000'001'00000'1010011;
+//                             rs3  |f2| rs2 | rs1 |rm | rd  | opcode
+constexpr uint32_t kFmaddH = 0b00000'10'00000'00000'000'00000'1000011;
+//                             rs3  |f2| rs2 | rs1 |rm | rd  | opcode
+constexpr uint32_t kFmsubH = 0b00001'10'00000'00000'000'00000'1000111;
+//                              rs3  |f2| rs2 | rs1 |rm | rd  | opcode
+constexpr uint32_t kFnmaddH = 0b00000'10'00000'00000'000'00000'1001111;
+//                              rs3  |f2| rs2 | rs1 |rm | rd  | opcode
+constexpr uint32_t kFnmsubH = 0b00000'10'00000'00000'000'00000'1001011;
 
 class ZfhEncodingTest : public testing::Test {
  protected:
@@ -130,6 +138,7 @@
   void FloatSourceHelper(uint32_t, OpcodeEnum, SourceOpEnum, int);
   void FloatFrs1Helper(uint32_t, OpcodeEnum);
   void FloatFrs2Helper(uint32_t, OpcodeEnum);
+  void FloatFrs3Helper(uint32_t, OpcodeEnum);
   void FloatRmHelper(uint32_t, OpcodeEnum);
 
   FlatDemandMemory memory_;
@@ -236,6 +245,11 @@
   FloatSourceHelper(binary_instruction, opcode_enum, SourceOpEnum::kFrs2, 20);
 }
 
+void ZfhEncodingTest::FloatFrs3Helper(uint32_t binary_instruction,
+                                      OpcodeEnum opcode_enum) {
+  FloatSourceHelper(binary_instruction, opcode_enum, SourceOpEnum::kFrs3, 27);
+}
+
 void ZfhEncodingTest::FloatRmHelper(uint32_t binary_instruction,
                                     OpcodeEnum opcode_enum) {
   for (int rm = 0; rm <= 6; ++rm) {
@@ -754,4 +768,104 @@
   FloatFrdHelper(kFclassH, OpcodeEnum::kFclassH);
 }
 
+TEST_F(ZfhEncodingTest, FmaddH) {
+  enc_->ParseInstruction(kFmaddH);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FmaddH_frs1) {
+  FloatFrs1Helper(kFmaddH, OpcodeEnum::kFmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FmaddH_frs2) {
+  FloatFrs2Helper(kFmaddH, OpcodeEnum::kFmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FmaddH_frs3) {
+  FloatFrs3Helper(kFmaddH, OpcodeEnum::kFmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FmaddH_rm) {
+  FloatRmHelper(kFmaddH, OpcodeEnum::kFmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FmaddH_frd) {
+  FloatFrdHelper(kFmaddH, OpcodeEnum::kFmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FmsubH) {
+  enc_->ParseInstruction(kFmsubH);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FmsubH_frs1) {
+  FloatFrs1Helper(kFmsubH, OpcodeEnum::kFmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FmsubH_frs2) {
+  FloatFrs2Helper(kFmsubH, OpcodeEnum::kFmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FmsubH_frs3) {
+  FloatFrs3Helper(kFmsubH, OpcodeEnum::kFmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FmsubH_rm) {
+  FloatRmHelper(kFmsubH, OpcodeEnum::kFmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FmsubH_frd) {
+  FloatFrdHelper(kFmsubH, OpcodeEnum::kFmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FnmaddH) {
+  enc_->ParseInstruction(kFnmaddH);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFnmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FnmaddH_frs1) {
+  FloatFrs1Helper(kFnmaddH, OpcodeEnum::kFnmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FnmaddH_frs2) {
+  FloatFrs2Helper(kFnmaddH, OpcodeEnum::kFnmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FnmaddH_frs3) {
+  FloatFrs3Helper(kFnmaddH, OpcodeEnum::kFnmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FnmaddH_rm) {
+  FloatRmHelper(kFnmaddH, OpcodeEnum::kFnmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FnmaddH_frd) {
+  FloatFrdHelper(kFnmaddH, OpcodeEnum::kFnmaddH);
+}
+
+TEST_F(ZfhEncodingTest, FnmsubH) {
+  enc_->ParseInstruction(kFnmsubH);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFnmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FnmsubH_frs1) {
+  FloatFrs1Helper(kFnmsubH, OpcodeEnum::kFnmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FnmsubH_frs2) {
+  FloatFrs2Helper(kFnmsubH, OpcodeEnum::kFnmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FnmsubH_frs3) {
+  FloatFrs3Helper(kFnmsubH, OpcodeEnum::kFnmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FnmsubH_rm) {
+  FloatRmHelper(kFnmsubH, OpcodeEnum::kFnmsubH);
+}
+
+TEST_F(ZfhEncodingTest, FnmsubH_frd) {
+  FloatFrdHelper(kFnmsubH, OpcodeEnum::kFnmsubH);
+}
+
 }  // namespace