Emmmer updated this revision to Diff 482900.
Emmmer added a comment.
Herald added a subscriber: lldb-commits.

Updating D140032 <https://reviews.llvm.org/D140032>: [LLDB][RISCV] Add RVD 
instruction support for EmulateInstructionRISCV


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140032/new/

https://reviews.llvm.org/D140032

Files:
  lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
  lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
  lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp

Index: lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
===================================================================
--- lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
+++ lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
@@ -19,6 +19,7 @@
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h"
 #include "Plugins/Process/Utility/lldb-riscv-register-enums.h"
 
+using namespace llvm;
 using namespace lldb;
 using namespace lldb_private;
 
@@ -485,49 +486,68 @@
   TestAtomic<uint64_t>(this, 0xE0F7382F, 0x1, 0x2, 0x1, 0x2);
 }
 
-struct FloatCalInst {
+template <typename T> struct F_D_CalInst {
   uint32_t inst;
   std::string name;
-  float rs1_val;
-  float rs2_val;
-  float rd_val;
+  T rs1_val;
+  T rs2_val;
+  T rd_val;
 };
 
-static void TestFloatCalInst(RISCVEmulatorTester *tester, DecodeResult inst,
-                             float rs1_val, float rs2_val, float rd_exp) {
-  std::vector<std::string> FloatCMP = {"FEQ_S", "FLT_S", "FLE_S"};
-  std::vector<std::string> FloatCal3 = {"FMADD_S", "FMSUB_S", "FNMSUB_S",
-                                        "FNMADD_S"};
+using FloatCalInst = F_D_CalInst<float>;
+using DoubleCalInst = F_D_CalInst<double>;
+
+template <typename T>
+static void TestF_D_CalInst(RISCVEmulatorTester *tester, DecodeResult inst,
+                            T rs1_val, T rs2_val, T rd_exp) {
+  std::vector<std::string> CMPs = {"FEQ_S", "FLT_S", "FLE_S",
+                                   "FEQ_D", "FLT_D", "FLE_D"};
+  std::vector<std::string> FMAs = {"FMADD_S",  "FMSUB_S", "FNMSUB_S",
+                                   "FNMADD_S", "FMADD_D", "FMSUB_D",
+                                   "FNMSUB_D", "FNMADD_D"};
 
   uint32_t rd = DecodeRD(inst.inst);
   uint32_t rs1 = DecodeRS1(inst.inst);
   uint32_t rs2 = DecodeRS2(inst.inst);
 
-  llvm::APFloat ap_rs1_val(rs1_val);
-  llvm::APFloat ap_rs2_val(rs2_val);
-  llvm::APFloat ap_rs3_val(0.5f);
+  APFloat ap_rs1_val(rs1_val);
+  APFloat ap_rs2_val(rs2_val);
+  APFloat ap_rs3_val(0.0f);
+  static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
+                "T should be float or double");
+  if constexpr (std::is_same_v<T, float>)
+    ap_rs3_val = APFloat(0.5f);
+  if constexpr (std::is_same_v<T, double>)
+    ap_rs3_val = APFloat(0.5);
 
   if (rs1)
     tester->fpr.fpr[rs1] = ap_rs1_val.bitcastToAPInt().getZExtValue();
   if (rs2)
     tester->fpr.fpr[rs2] = ap_rs2_val.bitcastToAPInt().getZExtValue();
-  for (auto i : FloatCal3) {
+  for (auto i : FMAs) {
     if (inst.pattern.name == i) {
       uint32_t rs3 = DecodeRS3(inst.inst);
       tester->fpr.fpr[rs3] = ap_rs3_val.bitcastToAPInt().getZExtValue();
     }
   }
   ASSERT_TRUE(tester->Execute(inst, false));
-  for (auto i : FloatCMP) {
+  for (auto i : CMPs) {
     if (inst.pattern.name == i) {
       ASSERT_EQ(tester->gpr.gpr[rd], rd_exp);
       return;
     }
   }
 
-  llvm::APInt apInt(32, tester->fpr.fpr[rd]);
-  llvm::APFloat rd_val(apInt.bitsToFloat());
-  ASSERT_EQ(rd_val.convertToFloat(), rd_exp);
+  if constexpr (std::is_same_v<T, float>) {
+    APInt apInt(32, tester->fpr.fpr[rd]);
+    APFloat rd_val(apInt.bitsToFloat());
+    ASSERT_EQ(rd_val.convertToFloat(), rd_exp);
+  }
+  if constexpr (std::is_same_v<T, double>) {
+    APInt apInt(64, tester->fpr.fpr[rd]);
+    APFloat rd_val(apInt.bitsToDouble());
+    ASSERT_EQ(rd_val.convertToDouble(), rd_exp);
+  }
 }
 
 TEST_F(RISCVEmulatorTester, TestFloatInst) {
@@ -546,14 +566,14 @@
       {0x28219253, "FMAX_S", -0.5f, -0.6f, -0.5f},
       {0x28219253, "FMAX_S", 0.5f, 0.6f, 0.6f},
       {0x28219253, "FMAX_S", 0.5f, -0.6f, 0.5f},
-      {0xA221A253, "FEQ_S", 0.5f, 0.5f, 1},
-      {0xA221A253, "FEQ_S", 0.5f, -0.5f, 0},
-      {0xA221A253, "FEQ_S", -0.5f, 0.5f, 0},
-      {0xA221A253, "FEQ_S", 0.4f, 0.5f, 0},
-      {0xA2219253, "FLT_S", 0.4f, 0.5f, 1},
-      {0xA2219253, "FLT_S", 0.5f, 0.5f, 0},
-      {0xA2218253, "FLE_S", 0.4f, 0.5f, 1},
-      {0xA2218253, "FLE_S", 0.5f, 0.5f, 1},
+      {0xA021A253, "FEQ_S", 0.5f, 0.5f, 1},
+      {0xA021A253, "FEQ_S", 0.5f, -0.5f, 0},
+      {0xA021A253, "FEQ_S", -0.5f, 0.5f, 0},
+      {0xA021A253, "FEQ_S", 0.4f, 0.5f, 0},
+      {0xA0219253, "FLT_S", 0.4f, 0.5f, 1},
+      {0xA0219253, "FLT_S", 0.5f, 0.5f, 0},
+      {0xA0218253, "FLE_S", 0.4f, 0.5f, 1},
+      {0xA0218253, "FLE_S", 0.5f, 0.5f, 1},
       {0x4021F243, "FMADD_S", 0.5f, 0.5f, 0.75f},
       {0x4021F247, "FMSUB_S", 0.5f, 0.5f, -0.25f},
       {0x4021F24B, "FNMSUB_S", 0.5f, 0.5f, 0.25f},
@@ -564,65 +584,137 @@
     ASSERT_TRUE(decode.has_value());
     std::string name = decode->pattern.name;
     ASSERT_EQ(name, i.name);
-    TestFloatCalInst(this, decode.value(), i.rs1_val, i.rs2_val, i.rd_val);
+    TestF_D_CalInst(this, decode.value(), i.rs1_val, i.rs2_val, i.rd_val);
   }
 }
 
-static void TestFCVT(RISCVEmulatorTester *tester, DecodeResult inst) {
-  std::vector<std::string> FloatToInt = {"FCVT_W_S", "FCVT_WU_S"};
-  std::vector<std::string> IntToFloat = {"FCVT_S_W", "FCVT_S_WU"};
-
-  uint32_t rd = DecodeRD(inst.inst);
-  uint32_t rs1 = DecodeRS1(inst.inst);
-
-  for (auto i : FloatToInt) {
-    if (inst.pattern.name == i) {
-      llvm::APFloat apf_rs1_val(12.0f);
-      tester->fpr.fpr[rs1] = apf_rs1_val.bitcastToAPInt().getZExtValue();
-      ASSERT_TRUE(tester->Execute(inst, false));
-      ASSERT_EQ(tester->gpr.gpr[rd], uint64_t(12));
-      return;
-    }
+TEST_F(RISCVEmulatorTester, TestDoubleInst) {
+  std::vector<DoubleCalInst> tests = {
+      {0x221F253, "FADD_D", 0.5, 0.5, 1.0},
+      {0xA21F253, "FSUB_D", 1.0, 0.5, 0.5},
+      {0x1221F253, "FMUL_D", 0.5, 0.5, 0.25},
+      {0x1A21F253, "FDIV_D", 0.1, 0.1, 1.0},
+      {0x22218253, "FSGNJ_D", 0.5, 0.2, 0.5},
+      {0x22219253, "FSGNJN_D", 0.5, -1.0, 0.5},
+      {0x2221A253, "FSGNJX_D", -0.5, -0.5, 0.5},
+      {0x2221A253, "FSGNJX_D", -0.5, 0.5, -0.5},
+      {0x2A218253, "FMIN_D", -0.5, 0.5, -0.5},
+      {0x2A218253, "FMIN_D", -0.5, -0.6, -0.6},
+      {0x2A218253, "FMIN_D", 0.5, 0.6, 0.5},
+      {0x2A219253, "FMAX_D", -0.5, -0.6, -0.5},
+      {0x2A219253, "FMAX_D", 0.5, 0.6, 0.6},
+      {0x2A219253, "FMAX_D", 0.5, -0.6, 0.5},
+      {0xA221A253, "FEQ_D", 0.5, 0.5, 1},
+      {0xA221A253, "FEQ_D", 0.5, -0.5, 0},
+      {0xA221A253, "FEQ_D", -0.5, 0.5, 0},
+      {0xA221A253, "FEQ_D", 0.4, 0.5, 0},
+      {0xA2219253, "FLT_D", 0.4, 0.5, 1},
+      {0xA2219253, "FLT_D", 0.5, 0.5, 0},
+      {0xA2218253, "FLE_D", 0.4, 0.5, 1},
+      {0xA2218253, "FLE_D", 0.5, 0.5, 1},
+      {0x4221F243, "FMADD_D", 0.5, 0.5, 0.75},
+      {0x4221F247, "FMSUB_D", 0.5, 0.5, -0.25},
+      {0x4221F24B, "FNMSUB_D", 0.5, 0.5, 0.25},
+      {0x4221F24F, "FNMADD_D", 0.5, 0.5, -0.75},
+  };
+  for (auto i : tests) {
+    auto decode = this->Decode(i.inst);
+    ASSERT_TRUE(decode.has_value());
+    std::string name = decode->pattern.name;
+    ASSERT_EQ(name, i.name);
+    TestF_D_CalInst(this, decode.value(), i.rs1_val, i.rs2_val, i.rd_val);
   }
+}
 
-  for (auto i : IntToFloat) {
-    if (inst.pattern.name == i) {
-      tester->gpr.gpr[rs1] = 12;
-      ASSERT_TRUE(tester->Execute(inst, false));
-      llvm::APInt apInt(32, tester->fpr.fpr[rd]);
-      llvm::APFloat rd_val(apInt.bitsToFloat());
-      ASSERT_EQ(rd_val.convertToFloat(), 12.0f);
-      return;
-    }
-  }
+template <typename T>
+static void TestInverse(RISCVEmulatorTester *tester, uint32_t f_reg,
+                        uint32_t x_reg, DecodeResult f2i, DecodeResult i2f,
+                        APFloat apf_val) {
+  uint64_t exp_x;
+  if constexpr (std::is_same_v<T, float>)
+    exp_x = uint64_t(apf_val.convertToFloat());
+  if constexpr (std::is_same_v<T, double>)
+    exp_x = uint64_t(apf_val.convertToDouble());
+  T exp_f = T(exp_x);
+
+  // convert float/double to int.
+  tester->fpr.fpr[f_reg] = apf_val.bitcastToAPInt().getZExtValue();
+  ASSERT_TRUE(tester->Execute(f2i, false));
+  ASSERT_EQ(tester->gpr.gpr[x_reg], exp_x);
+
+  // then convert int to float/double back.
+  ASSERT_TRUE(tester->Execute(i2f, false));
+  ASSERT_EQ(tester->fpr.fpr[f_reg],
+            APFloat(exp_f).bitcastToAPInt().getZExtValue());
 }
 
 struct FCVTInst {
-  uint32_t inst;
-  std::string name;
+  uint32_t f2i;
+  uint32_t i2f;
+  APFloat data;
+  bool isDouble;
 };
 
-TEST_F(RISCVEmulatorTester, TestFCVTInst) {
-  std::vector<FCVTInst> tests = {
-      {0xC001F253, "FCVT_W_S"}, {0xC011F253, "FCVT_WU_S"},
-      {0xD001F253, "FCVT_S_W"}, {0xD011F253, "FCVT_S_WU"},
-      {0xC021F253, "FCVT_L_S"}, {0xC031F253, "FCVT_LU_S"},
-      {0xD021F253, "FCVT_S_L"}, {0xD031F253, "FCVT_S_LU"},
+TEST_F(RISCVEmulatorTester, TestFCVT) {
+  std::vector<FCVTInst> tests{
+      // FCVT_W_S and FCVT_S_W
+      {0xC000F0D3, 0xD000F0D3, APFloat(12.0f), false},
+      // FCVT_WU_S and FCVT_S_WU
+      {0xC010F0D3, 0xD010F0D3, APFloat(12.0f), false},
+      // FCVT_L_S and FCVT_S_L
+      {0xC020F0D3, 0xD020F0D3, APFloat(12.0f), false},
+      // FCVT_LU_S and FCVT_S_LU
+      {0xC030F0D3, 0xD030F0D3, APFloat(12.0f), false},
+      // FCVT_W_D and FCVT_D_W
+      {0xC200F0D3, 0xD200F0D3, APFloat(12.0), true},
+      // FCVT_WU_D and FCVT_D_WU
+      {0xC210F0D3, 0xD210F0D3, APFloat(12.0), true},
+      // FCVT_L_D and FCVT_D_L
+      {0xC220F0D3, 0xD220F0D3, APFloat(12.0), true},
+      // FCVT_LU_D and FCVT_D_LU
+      {0xC230F0D3, 0xD230F0D3, APFloat(12.0), true},
   };
   for (auto i : tests) {
-    auto decode = this->Decode(i.inst);
-    ASSERT_TRUE(decode.has_value());
-    std::string name = decode->pattern.name;
-    ASSERT_EQ(name, i.name);
-    TestFCVT(this, decode.value());
+    auto f2i = this->Decode(i.f2i);
+    auto i2f = this->Decode(i.i2f);
+    ASSERT_TRUE(f2i.has_value());
+    ASSERT_TRUE(i2f.has_value());
+    uint32_t f_reg = DecodeRS1((*f2i).inst);
+    uint32_t x_reg = DecodeRS1((*i2f).inst);
+    if (i.isDouble)
+      TestInverse<double>(this, f_reg, x_reg, *f2i, *i2f, i.data);
+    else
+      TestInverse<float>(this, f_reg, x_reg, *f2i, *i2f, i.data);
   }
 }
 
+TEST_F(RISCVEmulatorTester, TestFDInverse) {
+  // FCVT_S_D
+  auto d2f = this->Decode(0x4010F0D3);
+  // FCVT_S_D
+  auto f2d = this->Decode(0x4200F0D3);
+  ASSERT_TRUE(d2f.has_value());
+  ASSERT_TRUE(f2d.has_value());
+  auto data = APFloat(12.0);
+  uint32_t reg = DecodeRS1((*d2f).inst);
+  float exp_f = 12.0f;
+  double exp_d = 12.0;
+
+  // double to float
+  this->fpr.fpr[reg] = data.bitcastToAPInt().getZExtValue();
+  ASSERT_TRUE(this->Execute(*d2f, false));
+  ASSERT_EQ(this->fpr.fpr[reg], APFloat(exp_f).bitcastToAPInt().getZExtValue());
+
+  // float to double
+  ASSERT_TRUE(this->Execute(*f2d, false));
+  ASSERT_EQ(this->fpr.fpr[reg], APFloat(exp_d).bitcastToAPInt().getZExtValue());
+}
+
 TEST_F(RISCVEmulatorTester, TestFloatLSInst) {
   uint32_t FLWInst = 0x1A207;  // imm = 0
   uint32_t FSWInst = 0x21A827; // imm = 16
 
-  llvm::APFloat apf(12.0f);
+  APFloat apf(12.0f);
   uint64_t bits = apf.bitcastToAPInt().getZExtValue();
 
   *(uint64_t *)this->memory = bits;
@@ -642,30 +734,82 @@
   ASSERT_EQ(*(uint32_t *)(this->memory + 16), bits);
 }
 
+TEST_F(RISCVEmulatorTester, TestDoubleLSInst) {
+  uint32_t FLDInst = 0x1B207;  // imm = 0
+  uint32_t FSDInst = 0x21B827; // imm = 16
+
+  APFloat apf(12.0);
+  uint64_t bits = apf.bitcastToAPInt().getZExtValue();
+
+  *(uint64_t *)this->memory = bits;
+  auto decode = this->Decode(FLDInst);
+  ASSERT_TRUE(decode.has_value());
+  std::string name = decode->pattern.name;
+  ASSERT_EQ(name, "FLD");
+  ASSERT_TRUE(this->Execute(decode.value(), false));
+  ASSERT_EQ(this->fpr.fpr[DecodeRD(FLDInst)], bits);
+
+  this->fpr.fpr[DecodeRS2(FSDInst)] = bits;
+  decode = this->Decode(FSDInst);
+  ASSERT_TRUE(decode.has_value());
+  name = decode->pattern.name;
+  ASSERT_EQ(name, "FSD");
+  ASSERT_TRUE(this->Execute(decode.value(), false));
+  ASSERT_EQ(*(uint64_t *)(this->memory + 16), bits);
+}
+
 TEST_F(RISCVEmulatorTester, TestFMV_X_WInst) {
   auto FMV_X_WInst = 0xE0018253;
 
-  llvm::APFloat apf(12.0f);
-  auto bits = NanBoxing(apf.bitcastToAPInt().getZExtValue());
-  this->fpr.fpr[DecodeRS1(FMV_X_WInst)] = bits;
+  APFloat apf(12.0f);
+  auto exp_bits = apf.bitcastToAPInt().getZExtValue();
+  this->fpr.fpr[DecodeRS1(FMV_X_WInst)] = NanBoxing(exp_bits);
   auto decode = this->Decode(FMV_X_WInst);
   ASSERT_TRUE(decode.has_value());
   std::string name = decode->pattern.name;
   ASSERT_EQ(name, "FMV_X_W");
   ASSERT_TRUE(this->Execute(decode.value(), false));
-  ASSERT_EQ(this->gpr.gpr[DecodeRD(FMV_X_WInst)], bits);
+  ASSERT_EQ(this->gpr.gpr[DecodeRD(FMV_X_WInst)], exp_bits);
+}
+
+TEST_F(RISCVEmulatorTester, TestFMV_X_DInst) {
+  auto FMV_X_DInst = 0xE2018253;
+
+  APFloat apf(12.0);
+  auto exp_bits = apf.bitcastToAPInt().getZExtValue();
+  this->fpr.fpr[DecodeRS1(FMV_X_DInst)] = exp_bits;
+  auto decode = this->Decode(FMV_X_DInst);
+  ASSERT_TRUE(decode.has_value());
+  std::string name = decode->pattern.name;
+  ASSERT_EQ(name, "FMV_X_D");
+  ASSERT_TRUE(this->Execute(decode.value(), false));
+  ASSERT_EQ(this->gpr.gpr[DecodeRD(FMV_X_DInst)], exp_bits);
 }
 
 TEST_F(RISCVEmulatorTester, TestFMV_W_XInst) {
   auto FMV_W_XInst = 0xF0018253;
 
-  llvm::APFloat apf(12.0f);
-  uint64_t bits = NanUnBoxing(apf.bitcastToAPInt().getZExtValue());
-  this->gpr.gpr[DecodeRS1(FMV_W_XInst)] = bits;
+  APFloat apf(12.0f);
+  uint64_t exp_bits = NanUnBoxing(apf.bitcastToAPInt().getZExtValue());
+  this->gpr.gpr[DecodeRS1(FMV_W_XInst)] = exp_bits;
   auto decode = this->Decode(FMV_W_XInst);
   ASSERT_TRUE(decode.has_value());
   std::string name = decode->pattern.name;
   ASSERT_EQ(name, "FMV_W_X");
   ASSERT_TRUE(this->Execute(decode.value(), false));
-  ASSERT_EQ(this->fpr.fpr[DecodeRD(FMV_W_XInst)], bits);
+  ASSERT_EQ(this->fpr.fpr[DecodeRD(FMV_W_XInst)], exp_bits);
+}
+
+TEST_F(RISCVEmulatorTester, TestFMV_D_XInst) {
+  auto FMV_D_XInst = 0xF2018253;
+
+  APFloat apf(12.0);
+  uint64_t bits = apf.bitcastToAPInt().getZExtValue();
+  this->gpr.gpr[DecodeRS1(FMV_D_XInst)] = bits;
+  auto decode = this->Decode(FMV_D_XInst);
+  ASSERT_TRUE(decode.has_value());
+  std::string name = decode->pattern.name;
+  ASSERT_EQ(name, "FMV_D_X");
+  ASSERT_TRUE(this->Execute(decode.value(), false));
+  ASSERT_EQ(this->fpr.fpr[DecodeRD(FMV_D_XInst)], bits);
 }
Index: lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
===================================================================
--- lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
+++ lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
@@ -215,6 +215,42 @@
 I_TYPE_INST(FCVT_S_L);
 I_TYPE_INST(FCVT_S_LU);
 
+// RV32D inst (Extension for Double-Precision Floating-Point)
+I_TYPE_INST(FLD);
+S_TYPE_INST(FSD);
+R4_TYPE_INST(FMADD_D);
+R4_TYPE_INST(FMSUB_D);
+R4_TYPE_INST(FNMSUB_D);
+R4_TYPE_INST(FNMADD_D);
+R_TYPE_INST(FADD_D);
+R_TYPE_INST(FSUB_D);
+R_TYPE_INST(FMUL_D);
+R_TYPE_INST(FDIV_D);
+I_TYPE_INST(FSQRT_D);
+R_TYPE_INST(FSGNJ_D);
+R_TYPE_INST(FSGNJN_D);
+R_TYPE_INST(FSGNJX_D);
+R_TYPE_INST(FMIN_D);
+R_TYPE_INST(FMAX_D);
+I_TYPE_INST(FCVT_S_D);
+I_TYPE_INST(FCVT_D_S);
+R_TYPE_INST(FEQ_D);
+R_TYPE_INST(FLT_D);
+R_TYPE_INST(FLE_D);
+I_TYPE_INST(FCLASS_D);
+I_TYPE_INST(FCVT_W_D);
+I_TYPE_INST(FCVT_WU_D);
+I_TYPE_INST(FCVT_D_W);
+I_TYPE_INST(FCVT_D_WU);
+
+// RV64D inst (Extension for Double-Precision Floating-Point)
+I_TYPE_INST(FCVT_L_D);
+I_TYPE_INST(FCVT_LU_D);
+I_TYPE_INST(FMV_X_D);
+I_TYPE_INST(FCVT_D_L);
+I_TYPE_INST(FCVT_D_LU);
+I_TYPE_INST(FMV_D_X);
+
 /// Invalid and reserved instructions, the `inst` fields are used for debugging.
 INVALID_INST(INVALID);
 INVALID_INST(RESERVED);
@@ -233,8 +269,12 @@
     AMOMAXU_D, FLW, FSW, FMADD_S, FMSUB_S, FNMADD_S, FNMSUB_S, FADD_S, FSUB_S,
     FMUL_S, FDIV_S, FSQRT_S, FSGNJ_S, FSGNJN_S, FSGNJX_S, FMIN_S, FMAX_S,
     FCVT_W_S, FCVT_WU_S, FMV_X_W, FEQ_S, FLT_S, FLE_S, FCLASS_S, FCVT_S_W,
-    FCVT_S_WU, FMV_W_X, FCVT_L_S, FCVT_LU_S, FCVT_S_L, FCVT_S_LU, INVALID,
-    EBREAK, RESERVED, HINT, NOP>;
+    FCVT_S_WU, FMV_W_X, FCVT_L_S, FCVT_LU_S, FCVT_S_L, FCVT_S_LU, FLD, FSD,
+    FMADD_D, FMSUB_D, FNMSUB_D, FNMADD_D, FADD_D, FSUB_D, FMUL_D, FDIV_D,
+    FSQRT_D, FSGNJ_D, FSGNJN_D, FSGNJX_D, FMIN_D, FMAX_D, FCVT_S_D, FCVT_D_S,
+    FEQ_D, FLT_D, FLE_D, FCLASS_D, FCVT_W_D, FCVT_WU_D, FCVT_D_W, FCVT_D_WU,
+    FCVT_L_D, FCVT_LU_D, FMV_X_D, FCVT_D_L, FCVT_D_LU, FMV_D_X, INVALID, EBREAK,
+    RESERVED, HINT, NOP>;
 
 constexpr uint8_t RV32 = 1;
 constexpr uint8_t RV64 = 2;
Index: lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
===================================================================
--- lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -24,6 +24,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/MathExtras.h"
 
+using namespace llvm;
 using namespace lldb;
 using namespace lldb_private;
 
@@ -34,10 +35,9 @@
 /// Returns all values wrapped in Optional, or std::nullopt if any of the values
 /// is std::nullopt.
 template <typename... Ts>
-static llvm::Optional<std::tuple<Ts...>> zipOpt(llvm::Optional<Ts> &&...ts) {
+static Optional<std::tuple<Ts...>> zipOpt(Optional<Ts> &&...ts) {
   if ((ts.has_value() && ...))
-    return llvm::Optional<std::tuple<Ts...>>(
-        std::make_tuple(std::move(*ts)...));
+    return Optional<std::tuple<Ts...>>(std::make_tuple(std::move(*ts)...));
   else
     return std::nullopt;
 }
@@ -118,7 +118,7 @@
                                 registerValue);
 }
 
-bool Rd::WriteAPFloat(EmulateInstructionRISCV &emulator, llvm::APFloat value) {
+bool Rd::WriteAPFloat(EmulateInstructionRISCV &emulator, APFloat value) {
   uint32_t lldb_reg = FPREncodingToLLDB(rd);
   EmulateInstruction::Context ctx;
   ctx.type = EmulateInstruction::eContextRegisterStore;
@@ -129,39 +129,39 @@
                                 registerValue);
 }
 
-llvm::Optional<uint64_t> Rs::Read(EmulateInstructionRISCV &emulator) {
+Optional<uint64_t> Rs::Read(EmulateInstructionRISCV &emulator) {
   uint32_t lldbReg = GPREncodingToLLDB(rs);
   RegisterValue value;
   return emulator.ReadRegister(eRegisterKindLLDB, lldbReg, value)
-             ? llvm::Optional<uint64_t>(value.GetAsUInt64())
+             ? Optional<uint64_t>(value.GetAsUInt64())
              : std::nullopt;
 }
 
-llvm::Optional<int32_t> Rs::ReadI32(EmulateInstructionRISCV &emulator) {
+Optional<int32_t> Rs::ReadI32(EmulateInstructionRISCV &emulator) {
   return Read(emulator).transform(
       [](uint64_t value) { return int32_t(uint32_t(value)); });
 }
 
-llvm::Optional<int64_t> Rs::ReadI64(EmulateInstructionRISCV &emulator) {
+Optional<int64_t> Rs::ReadI64(EmulateInstructionRISCV &emulator) {
   return Read(emulator).transform(
       [](uint64_t value) { return int64_t(value); });
 }
 
-llvm::Optional<uint32_t> Rs::ReadU32(EmulateInstructionRISCV &emulator) {
+Optional<uint32_t> Rs::ReadU32(EmulateInstructionRISCV &emulator) {
   return Read(emulator).transform(
       [](uint64_t value) { return uint32_t(value); });
 }
 
-llvm::Optional<llvm::APFloat> Rs::ReadAPFloat(EmulateInstructionRISCV &emulator,
-                                              bool isDouble) {
+Optional<APFloat> Rs::ReadAPFloat(EmulateInstructionRISCV &emulator,
+                                  bool isDouble) {
   uint32_t lldbReg = FPREncodingToLLDB(rs);
   RegisterValue value;
   if (!emulator.ReadRegister(eRegisterKindLLDB, lldbReg, value))
     return std::nullopt;
   uint64_t bits = value.GetAsUInt64();
-  llvm::APInt api(64, bits, false);
-  return llvm::APFloat(isDouble ? llvm::APFloat(api.bitsToDouble())
-                                : llvm::APFloat(api.bitsToFloat()));
+  APInt api(64, bits, false);
+  return APFloat(isDouble ? APFloat(api.bitsToDouble())
+                          : APFloat(api.bitsToFloat()));
 }
 
 static bool CompareB(uint64_t rs1, uint64_t rs2, uint32_t funct3) {
@@ -215,7 +215,7 @@
     std::is_same_v<T, AMOMAXU_W> || std::is_same_v<T, AMOMAXU_D>;
 
 template <typename I>
-static std::enable_if_t<is_load<I> || is_store<I>, llvm::Optional<uint64_t>>
+static std::enable_if_t<is_load<I> || is_store<I>, Optional<uint64_t>>
 LoadStoreAddr(EmulateInstructionRISCV &emulator, I inst) {
   return inst.rs1.Read(emulator).transform(
       [&](uint64_t rs1) { return rs1 + uint64_t(SignExt(inst.imm)); });
@@ -247,11 +247,11 @@
 template <typename I>
 static std::enable_if_t<is_amo_add<I> || is_amo_bit_op<I> || is_amo_swap<I> ||
                             is_amo_cmp<I>,
-                        llvm::Optional<uint64_t>>
+                        Optional<uint64_t>>
 AtomicAddr(EmulateInstructionRISCV &emulator, I inst, unsigned int align) {
   return inst.rs1.Read(emulator)
       .transform([&](uint64_t rs1) {
-        return rs1 % align == 0 ? llvm::Optional<uint64_t>(rs1) : std::nullopt;
+        return rs1 % align == 0 ? Optional<uint64_t>(rs1) : std::nullopt;
       })
       .value_or(std::nullopt);
 }
@@ -552,9 +552,9 @@
     {"FCVT_W_S", 0xFFF0007F, 0xC0000053, DecodeIType<FCVT_W_S>},
     {"FCVT_WU_S", 0xFFF0007F, 0xC0100053, DecodeIType<FCVT_WU_S>},
     {"FMV_X_W", 0xFFF0707F, 0xE0000053, DecodeIType<FMV_X_W>},
-    {"FEQ_S", 0xFE00707F, 0xA2002053, DecodeRType<FEQ_S>},
-    {"FLT_S", 0xFE00707F, 0xA2001053, DecodeRType<FLT_S>},
-    {"FLE_S", 0xFE00707F, 0xA2000053, DecodeRType<FLE_S>},
+    {"FEQ_S", 0xFE00707F, 0xA0002053, DecodeRType<FEQ_S>},
+    {"FLT_S", 0xFE00707F, 0xA0001053, DecodeRType<FLT_S>},
+    {"FLE_S", 0xFE00707F, 0xA0000053, DecodeRType<FLE_S>},
     {"FCLASS_S", 0xFFF0707F, 0xE0001053, DecodeIType<FCLASS_S>},
     {"FCVT_S_W", 0xFFF0007F, 0xD0000053, DecodeIType<FCVT_S_W>},
     {"FCVT_S_WU", 0xFFF0007F, 0xD0100053, DecodeIType<FCVT_S_WU>},
@@ -565,9 +565,45 @@
     {"FCVT_LU_S", 0xFFF0007F, 0xC0300053, DecodeIType<FCVT_LU_S>},
     {"FCVT_S_L", 0xFFF0007F, 0xD0200053, DecodeIType<FCVT_S_L>},
     {"FCVT_S_LU", 0xFFF0007F, 0xD0300053, DecodeIType<FCVT_S_LU>},
+
+    // RV32D (Extension for Double-Precision Floating-Point) //
+    {"FLD", 0x707F, 0x3007, DecodeIType<FLD>},
+    {"FSD", 0x707F, 0x3027, DecodeSType<FSD>},
+    {"FMADD_D", 0x600007F, 0x2000043, DecodeR4Type<FMADD_D>},
+    {"FMSUB_D", 0x600007F, 0x2000047, DecodeR4Type<FMSUB_D>},
+    {"FNMSUB_D", 0x600007F, 0x200004B, DecodeR4Type<FNMSUB_D>},
+    {"FNMADD_D", 0x600007F, 0x200004F, DecodeR4Type<FNMADD_D>},
+    {"FADD_D", 0xFE00007F, 0x2000053, DecodeRType<FADD_D>},
+    {"FSUB_D", 0xFE00007F, 0xA000053, DecodeRType<FSUB_D>},
+    {"FMUL_D", 0xFE00007F, 0x12000053, DecodeRType<FMUL_D>},
+    {"FDIV_D", 0xFE00007F, 0x1A000053, DecodeRType<FDIV_D>},
+    {"FSQRT_D", 0xFFF0007F, 0x5A000053, DecodeIType<FSQRT_D>},
+    {"FSGNJ_D", 0xFE00707F, 0x22000053, DecodeRType<FSGNJ_D>},
+    {"FSGNJN_D", 0xFE00707F, 0x22001053, DecodeRType<FSGNJN_D>},
+    {"FSGNJX_D", 0xFE00707F, 0x22002053, DecodeRType<FSGNJX_D>},
+    {"FMIN_D", 0xFE00707F, 0x2A000053, DecodeRType<FMIN_D>},
+    {"FMAX_D", 0xFE00707F, 0x2A001053, DecodeRType<FMAX_D>},
+    {"FCVT_S_D", 0xFFF0007F, 0x40100053, DecodeIType<FCVT_S_D>},
+    {"FCVT_D_S", 0xFFF0007F, 0x42000053, DecodeIType<FCVT_D_S>},
+    {"FEQ_D", 0xFE00707F, 0xA2002053, DecodeRType<FEQ_D>},
+    {"FLT_D", 0xFE00707F, 0xA2001053, DecodeRType<FLT_D>},
+    {"FLE_D", 0xFE00707F, 0xA2000053, DecodeRType<FLE_D>},
+    {"FCLASS_D", 0xFFF0707F, 0xE2001053, DecodeIType<FCLASS_D>},
+    {"FCVT_W_D", 0xFFF0007F, 0xC2000053, DecodeIType<FCVT_W_D>},
+    {"FCVT_WU_D", 0xFFF0007F, 0xC2100053, DecodeIType<FCVT_WU_D>},
+    {"FCVT_D_W", 0xFFF0007F, 0xD2000053, DecodeIType<FCVT_D_W>},
+    {"FCVT_D_WU", 0xFFF0007F, 0xD2100053, DecodeIType<FCVT_D_WU>},
+
+    // RV64D (Extension for Double-Precision Floating-Point) //
+    {"FCVT_L_D", 0xFFF0007F, 0xC2200053, DecodeIType<FCVT_L_D>},
+    {"FCVT_LU_D", 0xFFF0007F, 0xC2300053, DecodeIType<FCVT_LU_D>},
+    {"FMV_X_D", 0xFFF0707F, 0xE2000053, DecodeIType<FMV_X_D>},
+    {"FCVT_D_L", 0xFFF0007F, 0xD2200053, DecodeIType<FCVT_D_L>},
+    {"FCVT_D_LU", 0xFFF0007F, 0xD2300053, DecodeIType<FCVT_D_LU>},
+    {"FMV_D_X", 0xFFF0707F, 0xF2000053, DecodeIType<FMV_D_X>},
 };
 
-llvm::Optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
+Optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
   Log *log = GetLog(LLDBLog::Unwind);
 
   uint16_t try_rvc = uint16_t(inst & 0x0000ffff);
@@ -897,7 +933,7 @@
         .transform([&](auto &&tup) {
           auto [rs1, rs2] = tup;
           // signed * signed
-          auto mul = llvm::APInt(128, rs1, true) * llvm::APInt(128, rs2, true);
+          auto mul = APInt(128, rs1, true) * APInt(128, rs2, true);
           return inst.rd.Write(m_emu, mul.ashr(64).trunc(64).getZExtValue());
         })
         .value_or(false);
@@ -907,8 +943,7 @@
         .transform([&](auto &&tup) {
           auto [rs1, rs2] = tup;
           // signed * unsigned
-          auto mul = llvm::APInt(128, rs1, true).zext(128) *
-                     llvm::APInt(128, rs2, false);
+          auto mul = APInt(128, rs1, true).zext(128) * APInt(128, rs2, false);
           return inst.rd.Write(m_emu, mul.lshr(64).trunc(64).getZExtValue());
         })
         .value_or(false);
@@ -918,8 +953,7 @@
         .transform([&](auto &&tup) {
           auto [rs1, rs2] = tup;
           // unsigned * unsigned
-          auto mul =
-              llvm::APInt(128, rs1, false) * llvm::APInt(128, rs2, false);
+          auto mul = APInt(128, rs1, false) * APInt(128, rs2, false);
           return inst.rd.Write(m_emu, mul.lshr(64).trunc(64).getZExtValue());
         })
         .value_or(false);
@@ -1129,18 +1163,21 @@
         m_emu, inst, 8, ZextD,
         [](uint64_t a, uint64_t b) { return std::max(a, b); });
   }
-  bool operator()(FLW inst) {
+  template <typename T>
+  bool F_Load(T inst, const fltSemantics &(*semantics)(),
+              unsigned int numBits) {
     return inst.rs1.Read(m_emu)
         .transform([&](auto &&rs1) {
           uint64_t addr = rs1 + uint64_t(inst.imm);
           uint64_t bits = m_emu.ReadMem<uint64_t>(addr).value();
-          llvm::APFloat f(llvm::APFloat::IEEEsingle(), llvm::APInt(32, bits));
+          APFloat f(semantics(), APInt(numBits, bits));
           return inst.rd.WriteAPFloat(m_emu, f);
         })
         .value_or(false);
   }
-  bool operator()(FSW inst) {
-    return zipOpt(inst.rs1.Read(m_emu), inst.rs2.ReadAPFloat(m_emu, false))
+  bool operator()(FLW inst) { return F_Load(inst, &APFloat::IEEEsingle, 32); }
+  template <typename T> bool F_Store(T inst, bool isDouble) {
+    return zipOpt(inst.rs1.Read(m_emu), inst.rs2.ReadAPFloat(m_emu, isDouble))
         .transform([&](auto &&tup) {
           auto [rs1, rs2] = tup;
           uint64_t addr = rs1 + uint64_t(inst.imm);
@@ -1149,125 +1186,70 @@
         })
         .value_or(false);
   }
-  bool operator()(FMADD_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false),
-                  inst.rs3.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2, rs3] = tup;
-          auto res = rs1.fusedMultiplyAdd(rs2, rs3, m_emu.GetRoundingMode());
-          inst.rd.WriteAPFloat(m_emu, rs1);
-          return m_emu.SetAccruedExceptions(res);
-        })
-        .value_or(false);
-  }
-  bool operator()(FMSUB_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false),
-                  inst.rs3.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2, rs3] = tup;
-          auto res = rs1.fusedMultiplyAdd(rs2, -rs3, m_emu.GetRoundingMode());
-          inst.rd.WriteAPFloat(m_emu, rs1);
-          return m_emu.SetAccruedExceptions(res);
-        })
-        .value_or(false);
-  }
-  bool operator()(FNMSUB_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false),
-                  inst.rs3.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2, rs3] = tup;
-          auto res = rs1.fusedMultiplyAdd(-rs2, rs3, m_emu.GetRoundingMode());
-          inst.rd.WriteAPFloat(m_emu, rs1);
-          return m_emu.SetAccruedExceptions(res);
-        })
-        .value_or(false);
+  bool operator()(FSW inst) { return F_Store(inst, false); }
+  std::tuple<bool, APFloat> FusedMultiplyAdd(APFloat rs1, APFloat rs2,
+                                             APFloat rs3) {
+    auto opStatus = rs1.fusedMultiplyAdd(rs2, rs3, m_emu.GetRoundingMode());
+    auto res = m_emu.SetAccruedExceptions(opStatus);
+    return {res, rs1};
   }
-  bool operator()(FNMADD_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false),
-                  inst.rs3.ReadAPFloat(m_emu, false))
+  template <typename T>
+  bool FMA(T inst, bool isDouble, float rs2_sign, float rs3_sign) {
+    return zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+                  inst.rs2.ReadAPFloat(m_emu, isDouble),
+                  inst.rs3.ReadAPFloat(m_emu, isDouble))
         .transform([&](auto &&tup) {
           auto [rs1, rs2, rs3] = tup;
-          auto res = rs1.fusedMultiplyAdd(-rs2, -rs3, m_emu.GetRoundingMode());
-          inst.rd.WriteAPFloat(m_emu, rs1);
-          return m_emu.SetAccruedExceptions(res);
-        })
-        .value_or(false);
-  }
-  bool operator()(FADD_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
+          rs2.copySign(APFloat(rs2_sign));
+          rs3.copySign(APFloat(rs3_sign));
+          auto [res, f] = FusedMultiplyAdd(rs1, rs2, rs3);
+          return res && inst.rd.WriteAPFloat(m_emu, f);
+        })
+        .value_or(false);
+  }
+  bool operator()(FMADD_S inst) { return FMA(inst, false, 1.0f, 1.0f); }
+  bool operator()(FMSUB_S inst) { return FMA(inst, false, 1.0f, -1.0f); }
+  bool operator()(FNMSUB_S inst) { return FMA(inst, false, -1.0f, 1.0f); }
+  bool operator()(FNMADD_S inst) { return FMA(inst, false, -1.0f, -1.0f); }
+  template <typename T>
+  bool F_Op(T inst, bool isDouble,
+            APFloat::opStatus (APFloat::*f)(const APFloat &RHS,
+                                            APFloat::roundingMode RM)) {
+    return zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+                  inst.rs2.ReadAPFloat(m_emu, isDouble))
         .transform([&](auto &&tup) {
           auto [rs1, rs2] = tup;
-          auto res = rs1.add(rs2, m_emu.GetRoundingMode());
-          inst.rd.WriteAPFloat(m_emu, rs1);
-          return m_emu.SetAccruedExceptions(res);
-        })
-        .value_or(false);
-  }
-  bool operator()(FSUB_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2] = tup;
-          auto res = rs1.subtract(rs2, m_emu.GetRoundingMode());
-          inst.rd.WriteAPFloat(m_emu, rs1);
-          return m_emu.SetAccruedExceptions(res);
-        })
-        .value_or(false);
-  }
-  bool operator()(FMUL_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2] = tup;
-          auto res = rs1.multiply(rs2, m_emu.GetRoundingMode());
-          inst.rd.WriteAPFloat(m_emu, rs1);
-          return m_emu.SetAccruedExceptions(res);
-        })
-        .value_or(false);
-  }
-  bool operator()(FDIV_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2] = tup;
-          auto res = rs1.divide(rs2, m_emu.GetRoundingMode());
+          auto res = ((&rs1)->*f)(rs2, m_emu.GetRoundingMode());
           inst.rd.WriteAPFloat(m_emu, rs1);
           return m_emu.SetAccruedExceptions(res);
         })
         .value_or(false);
   }
+  bool operator()(FADD_S inst) { return F_Op(inst, false, &APFloat::add); }
+  bool operator()(FSUB_S inst) { return F_Op(inst, false, &APFloat::subtract); }
+  bool operator()(FMUL_S inst) { return F_Op(inst, false, &APFloat::multiply); }
+  bool operator()(FDIV_S inst) { return F_Op(inst, false, &APFloat::divide); }
   bool operator()(FSQRT_S inst) {
     // TODO: APFloat doesn't have a sqrt function.
     return false;
   }
-  bool operator()(FSGNJ_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
+  template <typename T> bool F_SignInj(T inst, bool isDouble, bool isNegate) {
+    return zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+                  inst.rs2.ReadAPFloat(m_emu, isDouble))
         .transform([&](auto &&tup) {
           auto [rs1, rs2] = tup;
+          if (isNegate)
+            rs2.changeSign();
           rs1.copySign(rs2);
           return inst.rd.WriteAPFloat(m_emu, rs1);
         })
         .value_or(false);
   }
-  bool operator()(FSGNJN_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2] = tup;
-          rs1.copySign(-rs2);
-          return inst.rd.WriteAPFloat(m_emu, rs1);
-        })
-        .value_or(false);
-  }
-  bool operator()(FSGNJX_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
+  bool operator()(FSGNJ_S inst) { return F_SignInj(inst, false, false); }
+  bool operator()(FSGNJN_S inst) { return F_SignInj(inst, false, true); }
+  template <typename T> bool F_SignInjXor(T inst, bool isDouble) {
+    return zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+                  inst.rs2.ReadAPFloat(m_emu, isDouble))
         .transform([&](auto &&tup) {
           auto [rs1, rs2] = tup;
           // spec: the sign bit is the XOR of the sign bits of rs1 and rs2.
@@ -1284,9 +1266,12 @@
         })
         .value_or(false);
   }
-  bool operator()(FMIN_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
+  bool operator()(FSGNJX_S inst) { return F_SignInjXor(inst, false); }
+  template <typename T>
+  bool F_MAX_MIN(T inst, bool isDouble,
+                 APFloat (*f)(const APFloat &A, const APFloat &B)) {
+    return zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+                  inst.rs2.ReadAPFloat(m_emu, isDouble))
         .transform([&](auto &&tup) {
           auto [rs1, rs2] = tup;
           // If both inputs are NaNs, the result is the canonical NaN.
@@ -1294,101 +1279,84 @@
           // Signaling NaN inputs set the invalid operation exception flag, even
           // when the result is not NaN.
           if (rs1.isNaN() || rs2.isNaN())
-            m_emu.SetAccruedExceptions(llvm::APFloat::opInvalidOp);
-          if (rs1.isNaN() && rs2.isNaN()) {
-            auto canonicalNaN = llvm::APFloat::getQNaN(rs1.getSemantics());
-            return inst.rd.WriteAPFloat(m_emu, canonicalNaN);
-          }
-          return inst.rd.WriteAPFloat(m_emu, minnum(rs1, rs2));
-        })
-        .value_or(false);
-  }
-  bool operator()(FMAX_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2] = tup;
-          if (rs1.isNaN() || rs2.isNaN())
-            m_emu.SetAccruedExceptions(llvm::APFloat::opInvalidOp);
+            m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
           if (rs1.isNaN() && rs2.isNaN()) {
-            auto canonicalNaN = llvm::APFloat::getQNaN(rs1.getSemantics());
+            auto canonicalNaN = APFloat::getQNaN(rs1.getSemantics());
             return inst.rd.WriteAPFloat(m_emu, canonicalNaN);
           }
-          return inst.rd.WriteAPFloat(m_emu, maxnum(rs1, rs2));
+          return inst.rd.WriteAPFloat(m_emu, f(rs1, rs2));
         })
         .value_or(false);
   }
+  bool operator()(FMIN_S inst) { return F_MAX_MIN(inst, false, minnum); }
+  bool operator()(FMAX_S inst) { return F_MAX_MIN(inst, false, maxnum); }
   bool operator()(FCVT_W_S inst) {
-    return inst.rs1.ReadAPFloat(m_emu, false)
-        .transform([&](auto &&rs1) {
-          int32_t res = rs1.convertToFloat();
-          return inst.rd.Write(m_emu, uint64_t(res));
-        })
-        .value_or(false);
+    return FCVT_i2f<FCVT_W_S, int32_t, float>(inst, false,
+                                              &APFloat::convertToFloat);
   }
   bool operator()(FCVT_WU_S inst) {
-    return inst.rs1.ReadAPFloat(m_emu, false)
-        .transform([&](auto &&rs1) {
-          uint32_t res = rs1.convertToFloat();
-          return inst.rd.Write(m_emu, uint64_t(res));
-        })
-        .value_or(false);
+    return FCVT_i2f<FCVT_WU_S, uint32_t, float>(inst, false,
+                                                &APFloat::convertToFloat);
   }
-  bool operator()(FMV_X_W inst) {
-    return inst.rs1.ReadAPFloat(m_emu, false)
+  template <typename T> bool FMV_f2i(T inst, bool isDouble) {
+    return inst.rs1.ReadAPFloat(m_emu, isDouble)
         .transform([&](auto &&rs1) {
-          if (rs1.isNaN())
-            return inst.rd.Write(m_emu, 0x7fc00000);
-          auto bits = rs1.bitcastToAPInt();
-          return inst.rd.Write(m_emu, NanBoxing(uint64_t(bits.getSExtValue())));
-        })
-        .value_or(false);
-  }
-  bool operator()(FEQ_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2] = tup;
-          if (rs1.isNaN() || rs2.isNaN()) {
-            if (rs1.isSignaling() || rs2.isSignaling())
-              m_emu.SetAccruedExceptions(llvm::APFloat::opInvalidOp);
-            return inst.rd.Write(m_emu, 0);
+          if (rs1.isNaN()) {
+            if (isDouble)
+              return inst.rd.Write(m_emu, 0x7ff8'0000'0000'0000);
+            else
+              return inst.rd.Write(m_emu, 0x7fc0'0000);
           }
-          return inst.rd.Write(m_emu,
-                               rs1.compare(rs2) == llvm::APFloat::cmpEqual);
-        })
-        .value_or(false);
-  }
-  bool operator()(FLT_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
+          auto bits = rs1.bitcastToAPInt().getZExtValue();
+          if (isDouble)
+            return inst.rd.Write(m_emu, bits);
+          else
+            return inst.rd.Write(m_emu, uint64_t(bits & 0xffff'ffff));
+        })
+        .value_or(false);
+  }
+  bool operator()(FMV_X_W inst) { return FMV_f2i(inst, false); }
+  enum F_CMP {
+    FEQ,
+    FLT,
+    FLE,
+  };
+  template <typename T> bool F_Compare(T inst, bool isDouble, F_CMP cmp) {
+    return zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
+                  inst.rs2.ReadAPFloat(m_emu, isDouble))
         .transform([&](auto &&tup) {
           auto [rs1, rs2] = tup;
           if (rs1.isNaN() || rs2.isNaN()) {
-            m_emu.SetAccruedExceptions(llvm::APFloat::opInvalidOp);
-            return inst.rd.Write(m_emu, 0);
+            if (cmp == FEQ) {
+              if (rs1.isSignaling() || rs2.isSignaling()) {
+                auto res = m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
+                return res && inst.rd.Write(m_emu, 0);
+              }
+            }
+            auto res = m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
+            return res && inst.rd.Write(m_emu, 0);
           }
-          return inst.rd.Write(m_emu,
-                               rs1.compare(rs2) == llvm::APFloat::cmpLessThan);
-        })
-        .value_or(false);
-  }
-  bool operator()(FLE_S inst) {
-    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
-                  inst.rs2.ReadAPFloat(m_emu, false))
-        .transform([&](auto &&tup) {
-          auto [rs1, rs2] = tup;
-          if (rs1.isNaN() || rs2.isNaN()) {
-            m_emu.SetAccruedExceptions(llvm::APFloat::opInvalidOp);
-            return inst.rd.Write(m_emu, 0);
+          switch (cmp) {
+          case FEQ:
+            return inst.rd.Write(m_emu, rs1.compare(rs2) == APFloat::cmpEqual);
+          case FLT:
+            return inst.rd.Write(m_emu,
+                                 rs1.compare(rs2) == APFloat::cmpLessThan);
+          case FLE:
+            return inst.rd.Write(m_emu,
+                                 rs1.compare(rs2) != APFloat::cmpGreaterThan);
+          default:
+            llvm_unreachable("Invalid F_CMP");
           }
-          return inst.rd.Write(m_emu, rs1.compare(rs2) !=
-                                          llvm::APFloat::cmpGreaterThan);
         })
         .value_or(false);
   }
-  bool operator()(FCLASS_S inst) {
-    return inst.rs1.ReadAPFloat(m_emu, false)
+
+  bool operator()(FEQ_S inst) { return F_Compare(inst, false, FEQ); }
+  bool operator()(FLT_S inst) { return F_Compare(inst, false, FLT); }
+  bool operator()(FLE_S inst) { return F_Compare(inst, false, FLE); }
+  template <typename T> bool FCLASS(T inst, bool isDouble) {
+    return inst.rs1.ReadAPFloat(m_emu, isDouble)
         .transform([&](auto &&rs1) {
           uint64_t result = 0;
           if (rs1.isInfinity() && rs1.isNegative())
@@ -1421,63 +1389,134 @@
         })
         .value_or(false);
   }
-  bool operator()(FCVT_S_W inst) {
-    return inst.rs1.ReadI32(m_emu)
+  bool operator()(FCLASS_S inst) { return FCLASS(inst, false); }
+  template <typename T, typename E>
+  bool FCVT_f2i(T inst, Optional<E> (Rs::*f)(EmulateInstructionRISCV &emu),
+                const fltSemantics &(*semantics)()) {
+    return ((&inst.rs1)->*f)(m_emu)
         .transform([&](auto &&rs1) {
-          llvm::APFloat apf(llvm::APFloat::IEEEsingle(), rs1);
+          APFloat apf(semantics(), rs1);
           return inst.rd.WriteAPFloat(m_emu, apf);
         })
         .value_or(false);
   }
+  bool operator()(FCVT_S_W inst) {
+    return FCVT_f2i(inst, &Rs::ReadI32, &APFloat::IEEEsingle);
+  }
   bool operator()(FCVT_S_WU inst) {
-    return inst.rs1.ReadU32(m_emu)
-        .transform([&](auto &&rs1) {
-          llvm::APFloat apf(llvm::APFloat::IEEEsingle(), rs1);
-          return inst.rd.WriteAPFloat(m_emu, apf);
-        })
-        .value_or(false);
+    return FCVT_f2i(inst, &Rs::ReadU32, &APFloat::IEEEsingle);
   }
-  bool operator()(FMV_W_X inst) {
+  template <typename T, typename E>
+  bool FMV_i2f(T inst, unsigned int numBits, E (APInt::*f)() const) {
     return inst.rs1.Read(m_emu)
         .transform([&](auto &&rs1) {
-          llvm::APInt apInt(32, NanUnBoxing(rs1));
-          llvm::APFloat apf(apInt.bitsToFloat());
+          APInt apInt(numBits, rs1);
+          if (numBits == 32) // a.k.a. float
+            apInt = APInt(numBits, NanUnBoxing(rs1));
+          APFloat apf((&apInt->*f)());
           return inst.rd.WriteAPFloat(m_emu, apf);
         })
         .value_or(false);
   }
-  bool operator()(FCVT_L_S inst) {
-    return inst.rs1.ReadAPFloat(m_emu, false)
+  bool operator()(FMV_W_X inst) {
+    return FMV_i2f(inst, 32, &APInt::bitsToFloat);
+  }
+  template <typename I, typename E, typename T>
+  bool FCVT_i2f(I inst, bool isDouble, T (APFloat::*f)() const) {
+    return inst.rs1.ReadAPFloat(m_emu, isDouble)
         .transform([&](auto &&rs1) {
-          int64_t res = rs1.convertToFloat();
+          E res = E((&rs1->*f)());
           return inst.rd.Write(m_emu, uint64_t(res));
         })
         .value_or(false);
   }
+  bool operator()(FCVT_L_S inst) {
+    return FCVT_i2f<FCVT_L_S, int64_t, float>(inst, false,
+                                              &APFloat::convertToFloat);
+  }
   bool operator()(FCVT_LU_S inst) {
-    return inst.rs1.ReadAPFloat(m_emu, false)
-        .transform([&](auto &&rs1) {
-          uint64_t res = rs1.convertToFloat();
-          return inst.rd.Write(m_emu, res);
-        })
-        .value_or(false);
+    return FCVT_i2f<FCVT_LU_S, uint64_t, float>(inst, false,
+                                                &APFloat::convertToFloat);
   }
   bool operator()(FCVT_S_L inst) {
-    return inst.rs1.ReadI64(m_emu)
+    return FCVT_f2i(inst, &Rs::ReadI64, &APFloat::IEEEsingle);
+  }
+  bool operator()(FCVT_S_LU inst) {
+    return FCVT_f2i(inst, &Rs::Read, &APFloat::IEEEsingle);
+  }
+  bool operator()(FLD inst) { return F_Load(inst, &APFloat::IEEEdouble, 64); }
+  bool operator()(FSD inst) { return F_Store(inst, true); }
+  bool operator()(FMADD_D inst) { return FMA(inst, true, 1.0f, 1.0f); }
+  bool operator()(FMSUB_D inst) { return FMA(inst, true, 1.0f, -1.0f); }
+  bool operator()(FNMSUB_D inst) { return FMA(inst, true, -1.0f, 1.0f); }
+  bool operator()(FNMADD_D inst) { return FMA(inst, true, -1.0f, -1.0f); }
+  bool operator()(FADD_D inst) { return F_Op(inst, true, &APFloat::add); }
+  bool operator()(FSUB_D inst) { return F_Op(inst, true, &APFloat::subtract); }
+  bool operator()(FMUL_D inst) { return F_Op(inst, true, &APFloat::multiply); }
+  bool operator()(FDIV_D inst) { return F_Op(inst, true, &APFloat::divide); }
+  bool operator()(FSQRT_D inst) {
+    // TODO: APFloat doesn't have a sqrt function.
+    return false;
+  }
+  bool operator()(FSGNJ_D inst) { return F_SignInj(inst, true, false); }
+  bool operator()(FSGNJN_D inst) { return F_SignInj(inst, true, true); }
+  bool operator()(FSGNJX_D inst) { return F_SignInjXor(inst, true); }
+  bool operator()(FMIN_D inst) { return F_MAX_MIN(inst, true, minnum); }
+  bool operator()(FMAX_D inst) { return F_MAX_MIN(inst, true, maxnum); }
+  bool operator()(FCVT_S_D inst) {
+    return inst.rs1.ReadAPFloat(m_emu, true)
         .transform([&](auto &&rs1) {
-          llvm::APFloat apf(llvm::APFloat::IEEEsingle(), rs1);
+          double d = rs1.convertToDouble();
+          APFloat apf((float(d)));
           return inst.rd.WriteAPFloat(m_emu, apf);
         })
         .value_or(false);
   }
-  bool operator()(FCVT_S_LU inst) {
-    return inst.rs1.Read(m_emu)
+  bool operator()(FCVT_D_S inst) {
+    return inst.rs1.ReadAPFloat(m_emu, false)
         .transform([&](auto &&rs1) {
-          llvm::APFloat apf(llvm::APFloat::IEEEsingle(), rs1);
+          float f = rs1.convertToFloat();
+          APFloat apf((double(f)));
           return inst.rd.WriteAPFloat(m_emu, apf);
         })
         .value_or(false);
   }
+  bool operator()(FEQ_D inst) { return F_Compare(inst, true, FEQ); }
+  bool operator()(FLT_D inst) { return F_Compare(inst, true, FLT); }
+  bool operator()(FLE_D inst) { return F_Compare(inst, true, FLE); }
+  bool operator()(FCLASS_D inst) { return FCLASS(inst, true); }
+  bool operator()(FCVT_W_D inst) {
+    return FCVT_i2f<FCVT_W_D, int32_t, double>(inst, true,
+                                               &APFloat::convertToDouble);
+  }
+  bool operator()(FCVT_WU_D inst) {
+    return FCVT_i2f<FCVT_WU_D, uint32_t, double>(inst, true,
+                                                 &APFloat::convertToDouble);
+  }
+  bool operator()(FCVT_D_W inst) {
+    return FCVT_f2i(inst, &Rs::ReadI32, &APFloat::IEEEdouble);
+  }
+  bool operator()(FCVT_D_WU inst) {
+    return FCVT_f2i(inst, &Rs::ReadU32, &APFloat::IEEEdouble);
+  }
+  bool operator()(FCVT_L_D inst) {
+    return FCVT_i2f<FCVT_L_D, int64_t, double>(inst, true,
+                                               &APFloat::convertToDouble);
+  }
+  bool operator()(FCVT_LU_D inst) {
+    return FCVT_i2f<FCVT_LU_D, uint64_t, double>(inst, true,
+                                                 &APFloat::convertToDouble);
+  }
+  bool operator()(FMV_X_D inst) { return FMV_f2i(inst, true); }
+  bool operator()(FCVT_D_L inst) {
+    return FCVT_f2i(inst, &Rs::ReadI64, &APFloat::IEEEdouble);
+  }
+  bool operator()(FCVT_D_LU inst) {
+    return FCVT_f2i(inst, &Rs::Read, &APFloat::IEEEdouble);
+  }
+  bool operator()(FMV_D_X inst) {
+    return FMV_i2f(inst, 64, &APInt::bitsToDouble);
+  }
   bool operator()(INVALID inst) { return false; }
   bool operator()(RESERVED inst) { return false; }
   bool operator()(EBREAK inst) { return false; }
@@ -1513,7 +1552,7 @@
          WritePC(*old_pc + Executor::size(m_decoded.is_rvc));
 }
 
-llvm::Optional<DecodeResult>
+Optional<DecodeResult>
 EmulateInstructionRISCV::ReadInstructionAt(lldb::addr_t addr) {
   return ReadMem<uint32_t>(addr)
       .transform([&](uint32_t inst) { return Decode(inst); })
@@ -1536,11 +1575,11 @@
   return true;
 }
 
-llvm::Optional<lldb::addr_t> EmulateInstructionRISCV::ReadPC() {
+Optional<lldb::addr_t> EmulateInstructionRISCV::ReadPC() {
   bool success = false;
   auto addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
                                    LLDB_INVALID_ADDRESS, &success);
-  return success ? llvm::Optional<lldb::addr_t>(addr) : std::nullopt;
+  return success ? Optional<lldb::addr_t>(addr) : std::nullopt;
 }
 
 bool EmulateInstructionRISCV::WritePC(lldb::addr_t pc) {
@@ -1551,54 +1590,54 @@
                                LLDB_REGNUM_GENERIC_PC, pc);
 }
 
-llvm::RoundingMode EmulateInstructionRISCV::GetRoundingMode() {
+RoundingMode EmulateInstructionRISCV::GetRoundingMode() {
   bool success = false;
   auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,
                                    LLDB_INVALID_ADDRESS, &success);
   if (!success)
-    return llvm::RoundingMode::Invalid;
+    return RoundingMode::Invalid;
   auto frm = (fcsr >> 5) & 0x7;
   switch (frm) {
   case 0b000:
-    return llvm::RoundingMode::NearestTiesToEven;
+    return RoundingMode::NearestTiesToEven;
   case 0b001:
-    return llvm::RoundingMode::TowardZero;
+    return RoundingMode::TowardZero;
   case 0b010:
-    return llvm::RoundingMode::TowardNegative;
+    return RoundingMode::TowardNegative;
   case 0b011:
-    return llvm::RoundingMode::TowardPositive;
+    return RoundingMode::TowardPositive;
   case 0b111:
-    return llvm::RoundingMode::Dynamic;
+    return RoundingMode::Dynamic;
   default:
     // Reserved for future use.
-    return llvm::RoundingMode::Invalid;
+    return RoundingMode::Invalid;
   }
 }
 
 bool EmulateInstructionRISCV::SetAccruedExceptions(
-    llvm::APFloatBase::opStatus opStatus) {
+    APFloatBase::opStatus opStatus) {
   bool success = false;
   auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,
                                    LLDB_INVALID_ADDRESS, &success);
   if (!success)
     return false;
   switch (opStatus) {
-  case llvm::APFloatBase::opInvalidOp:
+  case APFloatBase::opInvalidOp:
     fcsr |= 1 << 4;
     break;
-  case llvm::APFloatBase::opDivByZero:
+  case APFloatBase::opDivByZero:
     fcsr |= 1 << 3;
     break;
-  case llvm::APFloatBase::opOverflow:
+  case APFloatBase::opOverflow:
     fcsr |= 1 << 2;
     break;
-  case llvm::APFloatBase::opUnderflow:
+  case APFloatBase::opUnderflow:
     fcsr |= 1 << 1;
     break;
-  case llvm::APFloatBase::opInexact:
+  case APFloatBase::opInexact:
     fcsr |= 1 << 0;
     break;
-  case llvm::APFloatBase::opOK:
+  case APFloatBase::opOK:
     break;
   }
   EmulateInstruction::Context ctx;
@@ -1607,7 +1646,7 @@
   return WriteRegisterUnsigned(ctx, eRegisterKindLLDB, fpr_fcsr_riscv, fcsr);
 }
 
-llvm::Optional<RegisterInfo>
+Optional<RegisterInfo>
 EmulateInstructionRISCV::GetRegisterInfo(lldb::RegisterKind reg_kind,
                                          uint32_t reg_index) {
   if (reg_kind == eRegisterKindGeneric) {
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to