[Lldb-commits] [lldb] 6d4ab6d - [LLDB][RISCV] Add RV32F instruction support for EmulateInstructionRISCV

via lldb-commits lldb-commits at lists.llvm.org
Wed Nov 23 06:09:24 PST 2022


Author: Emmmer
Date: 2022-11-23T22:09:14+08:00
New Revision: 6d4ab6d921792125969e5f917b84cc810a1ba95c

URL: https://github.com/llvm/llvm-project/commit/6d4ab6d921792125969e5f917b84cc810a1ba95c
DIFF: https://github.com/llvm/llvm-project/commit/6d4ab6d921792125969e5f917b84cc810a1ba95c.diff

LOG: [LLDB][RISCV] Add RV32F instruction support for EmulateInstructionRISCV

Add:

- RV32F instruction set.
- corresponding unittests.

Further work:

- RV32FC, RV64F and RV64FC instructions support.
- update execution exceptions to fcsr register in RVM instructions.

Reviewed By: DavidSpickett

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

Added: 
    

Modified: 
    lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
    lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
    lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
    lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h
    lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
index c05b43f300fda..ca7adff785d99 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -101,6 +101,12 @@ static uint32_t GPREncodingToLLDB(uint32_t reg_encode) {
   return LLDB_INVALID_REGNUM;
 }
 
+static uint32_t FPREncodingToLLDB(uint32_t reg_encode) {
+  if (reg_encode >= 0 && reg_encode <= 31)
+    return fpr_f0_riscv + reg_encode;
+  return LLDB_INVALID_REGNUM;
+}
+
 bool Rd::Write(EmulateInstructionRISCV &emulator, uint64_t value) {
   uint32_t lldb_reg = GPREncodingToLLDB(rd);
   EmulateInstruction::Context ctx;
@@ -112,6 +118,17 @@ bool Rd::Write(EmulateInstructionRISCV &emulator, uint64_t value) {
                                 registerValue);
 }
 
+bool Rd::WriteAPFloat(EmulateInstructionRISCV &emulator, llvm::APFloat value) {
+  uint32_t lldb_reg = FPREncodingToLLDB(rd);
+  EmulateInstruction::Context ctx;
+  ctx.type = EmulateInstruction::eContextRegisterStore;
+  ctx.SetNoArgs();
+  RegisterValue registerValue;
+  registerValue.SetUInt64(value.bitcastToAPInt().getZExtValue());
+  return emulator.WriteRegister(ctx, eRegisterKindLLDB, lldb_reg,
+                                registerValue);
+}
+
 llvm::Optional<uint64_t> Rs::Read(EmulateInstructionRISCV &emulator) {
   uint32_t lldbReg = GPREncodingToLLDB(rs);
   RegisterValue value;
@@ -135,6 +152,18 @@ llvm::Optional<uint32_t> Rs::ReadU32(EmulateInstructionRISCV &emulator) {
       [](uint64_t value) { return uint32_t(value); });
 }
 
+llvm::Optional<llvm::APFloat> Rs::ReadAPFloat(EmulateInstructionRISCV &emulator,
+                                              bool isDouble) {
+  uint32_t lldbReg = FPREncodingToLLDB(rs);
+  RegisterValue value;
+  if (!emulator.ReadRegister(eRegisterKindLLDB, lldbReg, value))
+    return llvm::None;
+  uint64_t bits = value.GetAsUInt64();
+  llvm::APInt api(64, bits, false);
+  return llvm::APFloat(isDouble ? llvm::APFloat(api.bitsToDouble())
+                                : llvm::APFloat(api.bitsToFloat()));
+}
+
 static bool CompareB(uint64_t rs1, uint64_t rs2, uint32_t funct3) {
   switch (funct3) {
   case BEQ:
@@ -356,7 +385,7 @@ template <typename T> static RISCVInst DecodeIType(uint32_t inst) {
 
 template <typename T> static RISCVInst DecodeBType(uint32_t inst) {
   return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeBImm(inst),
-           (inst & 0x7000) >> 12};
+           DecodeFunct3(inst)};
 }
 
 template <typename T> static RISCVInst DecodeSType(uint32_t inst) {
@@ -375,6 +404,11 @@ template <typename T> static RISCVInst DecodeRRS1Type(uint32_t inst) {
   return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}};
 }
 
+template <typename T> static RISCVInst DecodeR4Type(uint32_t inst) {
+  return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)},
+           Rs{DecodeRS3(inst)}, DecodeRM(inst)};
+}
+
 static const InstrPattern PATTERNS[] = {
     // RV32I & RV64I (The base integer ISA) //
     {"LUI", 0x7F, 0x37, DecodeUType<LUI>},
@@ -492,6 +526,34 @@ static const InstrPattern PATTERNS[] = {
     {"C_SUB", 0xFC63, 0x8C01, DecodeC_SUB},
     {"C_SUBW", 0xFC63, 0x9C01, DecodeC_SUBW},
     {"C_ADDW", 0xFC63, 0x9C21, DecodeC_ADDW},
+
+    // RV32F (Extension for Single-Precision Floating-Point) //
+    {"FLW", 0x707F, 0x2007, DecodeIType<FLW>},
+    {"FSW", 0x707F, 0x2027, DecodeSType<FSW>},
+    {"FMADD_S", 0x600007F, 0x43, DecodeR4Type<FMADD_S>},
+    {"FMSUB_S", 0x600007F, 0x47, DecodeR4Type<FMSUB_S>},
+    {"FNMSUB_S", 0x600007F, 0x4B, DecodeR4Type<FNMSUB_S>},
+    {"FNMADD_S", 0x600007F, 0x4F, DecodeR4Type<FNMADD_S>},
+    {"FADD_S", 0xFE00007F, 0x53, DecodeRType<FADD_S>},
+    {"FSUB_S", 0xFE00007F, 0x8000053, DecodeRType<FSUB_S>},
+    {"FMUL_S", 0xFE00007F, 0x10000053, DecodeRType<FMUL_S>},
+    {"FDIV_S", 0xFE00007F, 0x18000053, DecodeRType<FDIV_S>},
+    {"FSQRT_S", 0xFFF0007F, 0x58000053, DecodeRType<FSQRT_S>},
+    {"FSGNJ_S", 0xFE00707F, 0x20000053, DecodeRType<FSGNJ_S>},
+    {"FSGNJN_S", 0xFE00707F, 0x20001053, DecodeRType<FSGNJN_S>},
+    {"FSGNJX_S", 0xFE00707F, 0x20002053, DecodeRType<FSGNJX_S>},
+    {"FMIN_S", 0xFE00707F, 0x28000053, DecodeRType<FMIN_S>},
+    {"FMAX_S", 0xFE00707F, 0x28001053, DecodeRType<FMAX_S>},
+    {"FCVT_W_S", 0xFFF0007F, 0xC0000053, DecodeRType<FCVT_W_S>},
+    {"FCVT_WU_S", 0xFFF0007F, 0xC0100053, DecodeRType<FCVT_WU_S>},
+    {"FMV_X_W", 0xFFF0707F, 0xE0000053, DecodeRType<FMV_X_W>},
+    {"FEQ_S", 0xFE00707F, 0xA2002053, DecodeRType<FEQ_S>},
+    {"FLT_S", 0xFE00707F, 0xA2001053, DecodeRType<FLT_S>},
+    {"FLE_S", 0xFE00707F, 0xA2000053, DecodeRType<FLE_S>},
+    {"FCLASS_S", 0xFFF0707F, 0xE0001053, DecodeRType<FCLASS_S>},
+    {"FCVT_S_W", 0xFFF0007F, 0xD0000053, DecodeRType<FCVT_S_W>},
+    {"FCVT_S_WU", 0xFFF0007F, 0xD0100053, DecodeRType<FCVT_S_WU>},
+    {"FMV_W_X", 0xFFF0707F, 0xF0000053, DecodeRType<FMV_W_X>},
 };
 
 llvm::Optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
@@ -504,10 +566,9 @@ llvm::Optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
 
   for (const InstrPattern &pat : PATTERNS) {
     if ((inst & pat.type_mask) == pat.eigen) {
-      LLDB_LOGF(log,
-                "EmulateInstructionRISCV::%s: inst(%x at %" PRIx64
-                ") was decoded to %s",
-                __FUNCTION__, inst, m_addr, pat.name);
+      LLDB_LOGF(
+          log, "EmulateInstructionRISCV::%s: inst(%x at %lx) was decoded to %s",
+          __FUNCTION__, inst, m_addr, pat.name);
       auto decoded = is_rvc ? pat.decode(try_rvc) : pat.decode(inst);
       return DecodeResult{decoded, inst, is_rvc, pat};
     }
@@ -1050,6 +1111,323 @@ class Executor {
         m_emu, inst, 8, ZextD,
         [](uint64_t a, uint64_t b) { return std::max(a, b); });
   }
+  bool operator()(FLW inst) {
+    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));
+          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))
+        .transform([&](auto &&tup) {
+          auto [rs1, rs2] = tup;
+          uint64_t addr = rs1 + uint64_t(inst.imm);
+          uint64_t bits = rs2.bitcastToAPInt().getZExtValue();
+          return m_emu.WriteMem<uint64_t>(addr, bits);
+        })
+        .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()(FNMADD_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()(FADD_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.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());
+          inst.rd.WriteAPFloat(m_emu, rs1);
+          return m_emu.SetAccruedExceptions(res);
+        })
+        .value_or(false);
+  }
+  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))
+        .transform([&](auto &&tup) {
+          auto [rs1, rs2] = tup;
+          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))
+        .transform([&](auto &&tup) {
+          auto [rs1, rs2] = tup;
+          // spec: the sign bit is the XOR of the sign bits of rs1 and rs2.
+          // if rs1 and rs2 have the same signs
+          // set rs1 to positive
+          // else set rs1 to negative
+          if (rs1.isNegative() == rs2.isNegative()) {
+            rs1.clearSign();
+          } else {
+            rs1.clearSign();
+            rs1.changeSign();
+          }
+          return inst.rd.WriteAPFloat(m_emu, rs1);
+        })
+        .value_or(false);
+  }
+  bool operator()(FMIN_S inst) {
+    return zipOpt(inst.rs1.ReadAPFloat(m_emu, false),
+                  inst.rs2.ReadAPFloat(m_emu, false))
+        .transform([&](auto &&tup) {
+          auto [rs1, rs2] = tup;
+          // If both inputs are NaNs, the result is the canonical NaN.
+          // If only one operand is a NaN, the result is the non-NaN operand.
+          // 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);
+          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, maxnum(rs1, rs2));
+        })
+        .value_or(false);
+  }
+  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);
+  }
+  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);
+  }
+  bool operator()(FMV_X_W inst) {
+    return inst.rs1.ReadAPFloat(m_emu, false)
+        .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);
+          }
+          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))
+        .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);
+          }
+          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);
+          }
+          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)
+        .transform([&](auto &&rs1) {
+          uint64_t result = 0;
+          if (rs1.isInfinity() && rs1.isNegative())
+            result |= 1 << 0;
+          // neg normal
+          if (rs1.isNormal() && rs1.isNegative())
+            result |= 1 << 1;
+          // neg subnormal
+          if (rs1.isDenormal() && rs1.isNegative())
+            result |= 1 << 2;
+          if (rs1.isNegZero())
+            result |= 1 << 3;
+          if (rs1.isPosZero())
+            result |= 1 << 4;
+          // pos normal
+          if (rs1.isNormal() && !rs1.isNegative())
+            result |= 1 << 5;
+          // pos subnormal
+          if (rs1.isDenormal() && !rs1.isNegative())
+            result |= 1 << 6;
+          if (rs1.isInfinity() && !rs1.isNegative())
+            result |= 1 << 7;
+          if (rs1.isNaN()) {
+            if (rs1.isSignaling())
+              result |= 1 << 8;
+            else
+              result |= 1 << 9;
+          }
+          return inst.rd.Write(m_emu, result);
+        })
+        .value_or(false);
+  }
+  bool operator()(FCVT_S_W inst) {
+    return inst.rs1.ReadI32(m_emu)
+        .transform([&](auto &&rs1) {
+          llvm::APFloat apf(llvm::APFloat::IEEEsingle(), rs1);
+          return inst.rd.WriteAPFloat(m_emu, apf);
+        })
+        .value_or(false);
+  }
+  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);
+  }
+  bool operator()(FMV_W_X inst) {
+    return inst.rs1.Read(m_emu)
+        .transform([&](auto &&rs1) {
+          llvm::APInt apInt(32, NanUnBoxing(rs1));
+          llvm::APFloat apf(apInt.bitsToFloat());
+          return inst.rd.WriteAPFloat(m_emu, apf);
+        })
+        .value_or(false);
+  }
   bool operator()(INVALID inst) { return false; }
   bool operator()(RESERVED inst) { return false; }
   bool operator()(EBREAK inst) { return false; }
@@ -1123,6 +1501,62 @@ bool EmulateInstructionRISCV::WritePC(lldb::addr_t pc) {
                                LLDB_REGNUM_GENERIC_PC, pc);
 }
 
+llvm::RoundingMode EmulateInstructionRISCV::GetRoundingMode() {
+  bool success = false;
+  auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,
+                                   LLDB_INVALID_ADDRESS, &success);
+  if (!success)
+    return llvm::RoundingMode::Invalid;
+  auto frm = (fcsr >> 5) & 0x7;
+  switch (frm) {
+  case 0b000:
+    return llvm::RoundingMode::NearestTiesToEven;
+  case 0b001:
+    return llvm::RoundingMode::TowardZero;
+  case 0b010:
+    return llvm::RoundingMode::TowardNegative;
+  case 0b011:
+    return llvm::RoundingMode::TowardPositive;
+  case 0b111:
+    return llvm::RoundingMode::Dynamic;
+  default:
+    // Reserved for future use.
+    return llvm::RoundingMode::Invalid;
+  }
+}
+
+bool EmulateInstructionRISCV::SetAccruedExceptions(
+    llvm::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:
+    fcsr |= 1 << 4;
+    break;
+  case llvm::APFloatBase::opDivByZero:
+    fcsr |= 1 << 3;
+    break;
+  case llvm::APFloatBase::opOverflow:
+    fcsr |= 1 << 2;
+    break;
+  case llvm::APFloatBase::opUnderflow:
+    fcsr |= 1 << 1;
+    break;
+  case llvm::APFloatBase::opInexact:
+    fcsr |= 1 << 0;
+    break;
+  case llvm::APFloatBase::opOK:
+    break;
+  }
+  EmulateInstruction::Context ctx;
+  ctx.type = eContextRegisterStore;
+  ctx.SetNoArgs();
+  return WriteRegisterUnsigned(ctx, eRegisterKindLLDB, fpr_fcsr_riscv, fcsr);
+}
+
 llvm::Optional<RegisterInfo>
 EmulateInstructionRISCV::GetRegisterInfo(lldb::RegisterKind reg_kind,
                                          uint32_t reg_index) {

diff  --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
index 19b4755c2450f..fa921d79d554d 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
@@ -92,6 +92,9 @@ class EmulateInstructionRISCV : public EmulateInstruction {
     return WriteMemoryUnsigned(ctx, addr, value, sizeof(T));
   }
 
+  llvm::RoundingMode GetRoundingMode();
+  bool SetAccruedExceptions(llvm::APFloatBase::opStatus);
+
 private:
   /// Last decoded instruction from m_opcode
   DecodeResult m_decoded;

diff  --git a/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h b/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
index 5b29fce4ec5bf..0b406a1fa10ee 100644
--- a/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
+++ b/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
@@ -13,6 +13,7 @@
 #include <variant>
 
 #include "EmulateInstructionRISCV.h"
+#include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/Optional.h"
 
 namespace lldb_private {
@@ -22,6 +23,7 @@ class EmulateInstructionRISCV;
 struct Rd {
   uint32_t rd;
   bool Write(EmulateInstructionRISCV &emulator, uint64_t value);
+  bool WriteAPFloat(EmulateInstructionRISCV &emulator, llvm::APFloat value);
 };
 
 struct Rs {
@@ -30,6 +32,8 @@ struct Rs {
   llvm::Optional<int32_t> ReadI32(EmulateInstructionRISCV &emulator);
   llvm::Optional<int64_t> ReadI64(EmulateInstructionRISCV &emulator);
   llvm::Optional<uint32_t> ReadU32(EmulateInstructionRISCV &emulator);
+  llvm::Optional<llvm::APFloat> ReadAPFloat(EmulateInstructionRISCV &emulator,
+                                            bool isDouble);
 };
 
 #define I_TYPE_INST(NAME)                                                      \
@@ -68,6 +72,14 @@ struct Rs {
     Rd rd;                                                                     \
     Rs rs1;                                                                    \
   }
+#define R4_TYPE_INST(NAME)                                                     \
+  struct NAME {                                                                \
+    Rd rd;                                                                     \
+    Rs rs1;                                                                    \
+    Rs rs2;                                                                    \
+    Rs rs3;                                                                    \
+    int32_t rm;                                                                \
+  }
 /// The `inst` fields are used for debugging.
 #define INVALID_INST(NAME)                                                     \
   struct NAME {                                                                \
@@ -170,6 +182,34 @@ R_TYPE_INST(AMOMAX_D);
 R_TYPE_INST(AMOMINU_D);
 R_TYPE_INST(AMOMAXU_D);
 
+// RV32F inst (The standard single-precision floating-point extension)
+I_TYPE_INST(FLW);
+S_TYPE_INST(FSW);
+R4_TYPE_INST(FMADD_S);
+R4_TYPE_INST(FMSUB_S);
+R4_TYPE_INST(FNMADD_S);
+R4_TYPE_INST(FNMSUB_S);
+R_TYPE_INST(FADD_S);
+R_TYPE_INST(FSUB_S);
+R_TYPE_INST(FMUL_S);
+R_TYPE_INST(FDIV_S);
+R_TYPE_INST(FSQRT_S);
+R_TYPE_INST(FSGNJ_S);
+R_TYPE_INST(FSGNJN_S);
+R_TYPE_INST(FSGNJX_S);
+R_TYPE_INST(FMIN_S);
+R_TYPE_INST(FMAX_S);
+R_TYPE_INST(FCVT_W_S);
+R_TYPE_INST(FCVT_WU_S);
+R_TYPE_INST(FMV_X_W);
+R_TYPE_INST(FEQ_S);
+R_TYPE_INST(FLT_S);
+R_TYPE_INST(FLE_S);
+R_TYPE_INST(FCLASS_S);
+R_TYPE_INST(FCVT_S_W);
+R_TYPE_INST(FCVT_S_WU);
+R_TYPE_INST(FMV_W_X);
+
 /// Invalid and reserved instructions, the `inst` fields are used for debugging.
 INVALID_INST(INVALID);
 INVALID_INST(RESERVED);
@@ -185,7 +225,10 @@ using RISCVInst = std::variant<
     DIVUW, REMW, REMUW, LR_W, SC_W, AMOSWAP_W, AMOADD_W, AMOXOR_W, AMOAND_W,
     AMOOR_W, AMOMIN_W, AMOMAX_W, AMOMINU_W, AMOMAXU_W, LR_D, SC_D, AMOSWAP_D,
     AMOADD_D, AMOXOR_D, AMOAND_D, AMOOR_D, AMOMIN_D, AMOMAX_D, AMOMINU_D,
-    AMOMAXU_D, INVALID, EBREAK, RESERVED, HINT, NOP>;
+    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, INVALID, EBREAK, RESERVED, HINT, NOP>;
 
 struct InstrPattern {
   const char *name;
@@ -206,6 +249,26 @@ struct DecodeResult {
 constexpr uint32_t DecodeRD(uint32_t inst) { return (inst & 0xF80) >> 7; }
 constexpr uint32_t DecodeRS1(uint32_t inst) { return (inst & 0xF8000) >> 15; }
 constexpr uint32_t DecodeRS2(uint32_t inst) { return (inst & 0x1F00000) >> 20; }
+constexpr uint32_t DecodeRS3(uint32_t inst) {
+  return (inst & 0xF0000000) >> 27;
+}
+constexpr uint32_t DecodeFunct3(uint32_t inst) { return (inst & 0x7000) >> 12; }
+constexpr uint32_t DecodeFunct2(uint32_t inst) {
+  return (inst & 0xE000000) >> 25;
+}
+constexpr uint32_t DecodeFunct7(uint32_t inst) {
+  return (inst & 0xFE000000) >> 25;
+}
+
+constexpr int32_t DecodeRM(uint32_t inst) { return DecodeFunct3(inst); }
+
+/// RISC-V spec: The upper bits of a valid NaN-boxed value must be all 1s.
+constexpr uint64_t NanBoxing(uint64_t val) {
+  return val | 0xFFFF'FFFF'0000'0000;
+}
+constexpr uint32_t NanUnBoxing(uint64_t val) {
+  return val & (~0xFFFF'FFFF'0000'0000);
+}
 
 } // namespace lldb_private
 #endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVINSTRUCTION_H

diff  --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h
index 0e07b910f8559..c5b955f93af63 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h
@@ -31,7 +31,7 @@ class RegisterInfoPOSIX_riscv64
   };
 
   struct FPR {
-    uint64_t f[32];
+    uint64_t fpr[32];
     uint32_t fcsr;
   };
 

diff  --git a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
index 9d58983b6532b..68c2ee6ae7da9 100644
--- a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
+++ b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
@@ -24,6 +24,7 @@ using namespace lldb_private;
 
 struct RISCVEmulatorTester : public EmulateInstructionRISCV, testing::Test {
   RegisterInfoPOSIX_riscv64::GPR gpr;
+  RegisterInfoPOSIX_riscv64::FPR fpr;
   uint8_t memory[1024] = {0};
 
   RISCVEmulatorTester()
@@ -32,6 +33,7 @@ struct RISCVEmulatorTester : public EmulateInstructionRISCV, testing::Test {
     EmulateInstruction::SetWriteRegCallback(WriteRegisterCallback);
     EmulateInstruction::SetReadMemCallback(ReadMemoryCallback);
     EmulateInstruction::SetWriteMemCallback(WriteMemoryCallback);
+    ClearAll();
   }
 
   static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
@@ -41,8 +43,13 @@ struct RISCVEmulatorTester : public EmulateInstructionRISCV, testing::Test {
     uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
     if (reg == gpr_x0_riscv)
       reg_value.SetUInt(0, reg_info->byte_size);
-    else
+    if (reg >= gpr_pc_riscv && reg <= gpr_x31_riscv)
       reg_value.SetUInt(tester->gpr.gpr[reg], reg_info->byte_size);
+    if (reg >= fpr_f0_riscv && reg <= fpr_f31_riscv)
+      reg_value.SetUInt(tester->fpr.fpr[reg - fpr_f0_riscv],
+                        reg_info->byte_size);
+    if (reg == fpr_fcsr_riscv)
+      reg_value.SetUInt(tester->fpr.fcsr, reg_info->byte_size);
     return true;
   }
 
@@ -52,8 +59,12 @@ struct RISCVEmulatorTester : public EmulateInstructionRISCV, testing::Test {
                                     const RegisterValue &reg_value) {
     RISCVEmulatorTester *tester = (RISCVEmulatorTester *)instruction;
     uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
-    if (reg != gpr_x0_riscv)
+    if (reg >= gpr_pc_riscv && reg <= gpr_x31_riscv)
       tester->gpr.gpr[reg] = reg_value.GetAsUInt64();
+    if (reg >= fpr_f0_riscv && reg <= fpr_f31_riscv)
+      tester->fpr.fpr[reg - fpr_f0_riscv] = reg_value.GetAsUInt64();
+    if (reg == fpr_fcsr_riscv)
+      tester->fpr.fcsr = reg_value.GetAsUInt32();
     return true;
   }
 
@@ -81,6 +92,12 @@ struct RISCVEmulatorTester : public EmulateInstructionRISCV, testing::Test {
         .transform([&](DecodeResult res) { return Execute(res, ignore_cond); })
         .value_or(false);
   }
+
+  void ClearAll() {
+    memset(&gpr, 0, sizeof(gpr));
+    memset(&fpr, 0, sizeof(fpr));
+    memset(memory, 0, sizeof(memory));
+  }
 };
 
 TEST_F(RISCVEmulatorTester, testJAL) {
@@ -155,8 +172,8 @@ constexpr uint32_t BGEU(uint32_t rs1, uint32_t rs2, int32_t offset) {
 
 using EncoderB = uint32_t (*)(uint32_t rs1, uint32_t rs2, int32_t offset);
 
-void testBranch(RISCVEmulatorTester *tester, EncoderB encoder, bool branched,
-                uint64_t rs1, uint64_t rs2) {
+static void testBranch(RISCVEmulatorTester *tester, EncoderB encoder,
+                       bool branched, uint64_t rs1, uint64_t rs2) {
   // prepare test registers
   lldb::addr_t old_pc = 0x114514;
   tester->WritePC(old_pc);
@@ -178,12 +195,13 @@ void testBranch(RISCVEmulatorTester *tester, EncoderB encoder, bool branched,
     testBranch(this, name, false, rs1, rs2_continued);                         \
   }
 
-void CheckRD(RISCVEmulatorTester *tester, uint64_t rd, uint64_t value) {
+static void CheckRD(RISCVEmulatorTester *tester, uint64_t rd, uint64_t value) {
   ASSERT_EQ(tester->gpr.gpr[rd], value);
 }
 
 template <typename T>
-void CheckMem(RISCVEmulatorTester *tester, uint64_t addr, uint64_t value) {
+static void CheckMem(RISCVEmulatorTester *tester, uint64_t addr,
+                     uint64_t value) {
   auto mem = tester->ReadMem<T>(addr);
   ASSERT_TRUE(mem.has_value());
   ASSERT_EQ(*mem, value);
@@ -194,8 +212,8 @@ using RS2 = uint64_t;
 using PC = uint64_t;
 using RDComputer = std::function<uint64_t(RS1, RS2, PC)>;
 
-void TestInst(RISCVEmulatorTester *tester, DecodeResult inst, bool has_rs2,
-              RDComputer rd_val) {
+static void TestInst(RISCVEmulatorTester *tester, DecodeResult inst,
+                     bool has_rs2, RDComputer rd_val) {
 
   lldb::addr_t old_pc = 0x114514;
   tester->WritePC(old_pc);
@@ -223,8 +241,8 @@ void TestInst(RISCVEmulatorTester *tester, DecodeResult inst, bool has_rs2,
 }
 
 template <typename T>
-void TestAtomic(RISCVEmulatorTester *tester, uint64_t inst, T rs1_val,
-                T rs2_val, T rd_expected, T mem_expected) {
+static void TestAtomic(RISCVEmulatorTester *tester, uint64_t inst, T rs1_val,
+                       T rs2_val, T rd_expected, T mem_expected) {
   // Atomic inst must have rs1 and rs2
 
   uint32_t rd = DecodeRD(inst);
@@ -261,7 +279,7 @@ struct TestDecode {
   RISCVInst inst_type;
 };
 
-bool compareInst(const RISCVInst &lhs, const RISCVInst &rhs) {
+static bool compareInst(const RISCVInst &lhs, const RISCVInst &rhs) {
   if (lhs.index() != rhs.index())
     return false;
   return std::visit(
@@ -446,3 +464,188 @@ TEST_F(RISCVEmulatorTester, TestAMOMAXU) {
   TestAtomic<uint32_t>(this, 0xE0F7282F, 0x1, 0x2, 0x1, 0x2);
   TestAtomic<uint64_t>(this, 0xE0F7382F, 0x1, 0x2, 0x1, 0x2);
 }
+
+struct FloatCalInst {
+  uint32_t inst;
+  std::string name;
+  float rs1_val;
+  float rs2_val;
+  float 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"};
+
+  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);
+
+  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) {
+    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) {
+    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);
+}
+
+TEST_F(RISCVEmulatorTester, TestFloatInst) {
+  std::vector<FloatCalInst> tests = {
+      {0x21F253, "FADD_S", 0.5f, 0.5f, 1.0f},
+      {0x821F253, "FSUB_S", 1.0f, 0.5f, 0.5f},
+      {0x1021F253, "FMUL_S", 0.5f, 0.5f, 0.25f},
+      {0x1821F253, "FDIV_S", 0.1f, 0.1f, 1.0f},
+      {0x20218253, "FSGNJ_S", 0.5f, 0.2f, 0.5f},
+      {0x20219253, "FSGNJN_S", 0.5f, -1.0f, 0.5f},
+      {0x2021A253, "FSGNJX_S", -0.5f, -0.5f, 0.5f},
+      {0x2021A253, "FSGNJX_S", -0.5f, 0.5f, -0.5f},
+      {0x28218253, "FMIN_S", -0.5f, 0.5f, -0.5f},
+      {0x28218253, "FMIN_S", -0.5f, -0.6f, -0.6f},
+      {0x28218253, "FMIN_S", 0.5f, 0.6f, 0.5f},
+      {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},
+      {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},
+      {0x4021F24F, "FNMADD_S", 0.5f, 0.5f, -0.75f},
+  };
+  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);
+    TestFloatCalInst(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;
+    }
+  }
+
+  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;
+    }
+  }
+}
+
+struct FCVTInst {
+  uint32_t inst;
+  std::string name;
+};
+
+TEST_F(RISCVEmulatorTester, TestFCVTInst) {
+  std::vector<FCVTInst> tests = {
+      {0xC001F253, "FCVT_W_S"},
+      {0xC011F253, "FCVT_WU_S"},
+      {0xD001F253, "FCVT_S_W"},
+      {0xD011F253, "FCVT_S_WU"},
+  };
+  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());
+  }
+}
+
+TEST_F(RISCVEmulatorTester, TestFloatLSInst) {
+  uint32_t FLWInst = 0x1A207;  // imm = 0
+  uint32_t FSWInst = 0x21A827; // imm = 16
+
+  llvm::APFloat apf(12.0f);
+  uint64_t bits = apf.bitcastToAPInt().getZExtValue();
+
+  *(uint64_t *)this->memory = bits;
+  auto decode = this->Decode(FLWInst);
+  ASSERT_TRUE(decode.has_value());
+  std::string name = decode->pattern.name;
+  ASSERT_EQ(name, "FLW");
+  ASSERT_TRUE(this->Execute(decode.value(), false));
+  ASSERT_EQ(this->fpr.fpr[DecodeRD(FLWInst)], bits);
+
+  this->fpr.fpr[DecodeRS2(FSWInst)] = bits;
+  decode = this->Decode(FSWInst);
+  ASSERT_TRUE(decode.has_value());
+  name = decode->pattern.name;
+  ASSERT_EQ(name, "FSW");
+  ASSERT_TRUE(this->Execute(decode.value(), false));
+  ASSERT_EQ(*(uint32_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;
+  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);
+}
+
+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;
+  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);
+}


        


More information about the lldb-commits mailing list