[Lldb-commits] [lldb] edc1c9f - [LLDB][RISCV] Add RVM and RVA instruction support for EmulateInstructionRISCV

via lldb-commits lldb-commits at lists.llvm.org
Fri Sep 16 21:19:20 PDT 2022


Author: Emmmer
Date: 2022-09-17T12:19:09+08:00
New Revision: edc1c9f6108a4eae24990928f914fe5a39f57ca6

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

LOG: [LLDB][RISCV] Add RVM and RVA instruction support for EmulateInstructionRISCV

Add:
- RVM and RVA instructions sets.
- corresponding unittests.

Further work:
- implement RVC, RVF, RVD, and RVV extension.

Reviewed By: DavidSpickett

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

Added: 
    

Modified: 
    lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
    lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.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 4ca017dd98bbe..bcd18ff63d11b 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -19,7 +19,6 @@
 #include "lldb/Symbol/UnwindPlan.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/LLDBLog.h"
-#include "lldb/Utility/RegisterValue.h"
 #include "lldb/Utility/Stream.h"
 
 #include "llvm/ADT/STLExtras.h"
@@ -115,7 +114,7 @@ static bool WriteRegister(EmulateInstructionRISCV &emulator,
 static bool ExecJAL(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
   bool success = false;
   int64_t offset = SignExt(DecodeJImm(inst));
-  int64_t pc = emulator.ReadPC(&success);
+  int64_t pc = emulator.ReadPC(success);
   return success && emulator.WritePC(pc + offset) &&
          WriteRegister(emulator, DecodeRD(inst),
                        RegisterValue(uint64_t(pc + 4)));
@@ -127,7 +126,7 @@ static bool ExecJALR(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
   if (!ReadRegister(emulator, DecodeRS1(inst), value))
     return false;
   bool success = false;
-  int64_t pc = emulator.ReadPC(&success);
+  int64_t pc = emulator.ReadPC(success);
   int64_t rs1 = int64_t(value.GetAsUInt64());
   // JALR clears the bottom bit. According to riscv-spec:
   // "The JALR instruction now clears the lowest bit of the calculated target
@@ -157,10 +156,60 @@ static bool CompareB(uint64_t rs1, uint64_t rs2, uint32_t funct3) {
   }
 }
 
+struct Wrapped {
+  RegisterValue value;
+
+  template <typename T>
+  [[nodiscard]] std::enable_if_t<std::is_unsigned_v<T>, T> trunc() const {
+    return T(value.GetAsUInt64());
+  }
+
+  template <typename T> T sext() const = delete;
+};
+
+template <> int32_t Wrapped::sext<int32_t>() const {
+  return int32_t(trunc<uint32_t>());
+}
+
+template <> int64_t Wrapped::sext<int64_t>() const {
+  return int64_t(trunc<uint64_t>());
+}
+
+template <bool hasRS2> struct RSRegs {
+private:
+  Wrapped rs1_value;
+
+public:
+  bool valid;
+
+  Wrapped &rs1() { return rs1_value; }
+};
+
+template <> struct RSRegs<true> : RSRegs<false> {
+private:
+  Wrapped rs2_value;
+
+public:
+  Wrapped &rs2() { return rs2_value; }
+};
+
+RSRegs<true> readRS1RS2(EmulateInstructionRISCV &emulator, uint32_t inst) {
+  RSRegs<true> value{};
+  value.valid = ReadRegister(emulator, DecodeRS1(inst), value.rs1().value) &&
+                ReadRegister(emulator, DecodeRS2(inst), value.rs2().value);
+  return value;
+}
+
+RSRegs<false> readRS1(EmulateInstructionRISCV &emulator, uint32_t inst) {
+  RSRegs<false> value{};
+  value.valid = ReadRegister(emulator, DecodeRS1(inst), value.rs1().value);
+  return value;
+}
+
 static bool ExecB(EmulateInstructionRISCV &emulator, uint32_t inst,
                   bool ignore_cond) {
   bool success = false;
-  uint64_t pc = emulator.ReadPC(&success);
+  uint64_t pc = emulator.ReadPC(success);
   if (!success)
     return false;
 
@@ -169,14 +218,12 @@ static bool ExecB(EmulateInstructionRISCV &emulator, uint32_t inst,
   if (ignore_cond)
     return emulator.WritePC(target);
 
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, DecodeRS1(inst), value1) ||
-      !ReadRegister(emulator, DecodeRS2(inst), value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
   uint32_t funct3 = DecodeFunct3(inst);
-  if (CompareB(value1.GetAsUInt64(), value2.GetAsUInt64(), funct3))
+  if (CompareB(rs.rs1().trunc<uint64_t>(), rs.rs2().trunc<uint64_t>(), funct3))
     return emulator.WritePC(target);
 
   return true;
@@ -193,18 +240,21 @@ static bool ExecAUIPC(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
   uint32_t imm = DecodeUImm(inst);
   RegisterValue value;
   bool success = false;
-  value.SetUInt64(SignExt(imm) + emulator.ReadPC(&success));
+  value.SetUInt64(SignExt(imm) + emulator.ReadPC(success));
   return success && WriteRegister(emulator, DecodeRD(inst), value);
 }
 
 template <typename T>
-static std::enable_if_t<std::is_integral_v<T>, T>
-ReadMem(EmulateInstructionRISCV &emulator, uint64_t addr, bool *success) {
-
+static std::enable_if_t<std::is_integral_v<T>, llvm::Optional<T>>
+ReadMem(EmulateInstructionRISCV &emulator, uint64_t addr) {
   EmulateInstructionRISCV::Context ctx;
   ctx.type = EmulateInstruction::eContextRegisterLoad;
   ctx.SetNoArgs();
-  return T(emulator.ReadMemoryUnsigned(ctx, addr, sizeof(T), T(), success));
+  bool success = false;
+  T result = emulator.ReadMemoryUnsigned(ctx, addr, sizeof(T), T(), &success);
+  if (!success)
+    return {}; // aka return false
+  return result;
 }
 
 template <typename T>
@@ -219,12 +269,11 @@ static bool WriteMem(EmulateInstructionRISCV &emulator, uint64_t addr,
 
 static uint64_t LoadStoreAddr(EmulateInstructionRISCV &emulator,
                               uint32_t inst) {
-  auto rs1 = DecodeRS1(inst);
   int32_t imm = SignExt(DecodeSImm(inst));
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return LLDB_INVALID_ADDRESS;
-  uint64_t addr = value.GetAsUInt64() + uint64_t(imm);
+  uint64_t addr = rs.rs1().trunc<uint64_t>() + uint64_t(imm);
   return addr;
 }
 
@@ -235,9 +284,8 @@ static bool Load(EmulateInstructionRISCV &emulator, uint32_t inst,
   uint64_t addr = LoadStoreAddr(emulator, inst);
   if (addr == LLDB_INVALID_ADDRESS)
     return false;
-  bool success = false;
-  E value = E(ReadMem<T>(emulator, addr, &success));
-  if (!success)
+  E value = E(ReadMem<T>(emulator, addr).value());
+  if (!value)
     return false;
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(extend(value)));
 }
@@ -253,6 +301,7 @@ static bool Store(EmulateInstructionRISCV &emulator, uint32_t inst) {
   return WriteMem<T>(emulator, addr, value);
 }
 
+// RV32I & RV64I (The base integer ISA) //
 static bool ExecLB(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
   return Load<uint8_t, int8_t>(emulator, inst, SextW);
 }
@@ -298,376 +347,765 @@ static bool ExecSD(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
 }
 
 static bool ExecADDI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
   int32_t imm = SignExt(DecodeIImm(inst));
 
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = int64_t(value.GetAsUInt64()) + int64_t(imm);
+  uint64_t result = rs.rs1().sext<int64_t>() + int64_t(imm);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSLTI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
   int32_t imm = SignExt(DecodeIImm(inst));
 
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = int64_t(value.GetAsUInt64()) < int64_t(imm);
+  uint64_t result = rs.rs1().sext<int64_t>() < int64_t(imm);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSLTIU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
   int32_t imm = SignExt(DecodeIImm(inst));
 
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value.GetAsUInt64() < uint64_t(imm);
+  uint64_t result = rs.rs1().trunc<uint64_t>() < uint64_t(imm);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecXORI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
   int32_t imm = SignExt(DecodeIImm(inst));
 
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value.GetAsUInt64() ^ uint64_t(imm);
+  uint64_t result = rs.rs1().trunc<uint64_t>() ^ uint64_t(imm);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecORI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
   int32_t imm = SignExt(DecodeIImm(inst));
 
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value.GetAsUInt64() | uint64_t(imm);
+  uint64_t result = rs.rs1().trunc<uint64_t>() | uint64_t(imm);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecANDI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
   int32_t imm = SignExt(DecodeIImm(inst));
 
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value.GetAsUInt64() & uint64_t(imm);
+  uint64_t result = rs.rs1().trunc<uint64_t>() & uint64_t(imm);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSLLI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto shamt = DecodeSHAMT7(inst);
-
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value.GetAsUInt64() << shamt;
+  uint64_t result = rs.rs1().trunc<uint64_t>() << DecodeSHAMT7(inst);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSRLI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto shamt = DecodeSHAMT7(inst);
-
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value.GetAsUInt64() >> shamt;
+  uint64_t result = rs.rs1().trunc<uint64_t>() >> DecodeSHAMT7(inst);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSRAI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto shamt = DecodeSHAMT7(inst);
-
-  RegisterValue value;
-  if (!ReadRegister(emulator, rs1, value))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = int64_t(value.GetAsUInt64()) >> shamt;
+  uint64_t result = rs.rs1().sext<int64_t>() >> DecodeSHAMT7(inst);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecADD(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value1.GetAsUInt64() + value2.GetAsUInt64();
+  uint64_t result = rs.rs1().trunc<uint64_t>() + rs.rs2().trunc<uint64_t>();
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSUB(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value1.GetAsUInt64() - value2.GetAsUInt64();
+  uint64_t result = rs.rs1().trunc<uint64_t>() - rs.rs2().trunc<uint64_t>();
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSLL(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value1.GetAsUInt64() << (value2.GetAsUInt64() & 0b111111);
+  uint64_t result = rs.rs1().trunc<uint64_t>()
+                    << (rs.rs2().trunc<uint64_t>() & 0b111111);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSLT(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = int64_t(value1.GetAsUInt64()) < int64_t(value2.GetAsUInt64());
+  uint64_t result = rs.rs1().sext<int64_t>() < rs.rs2().sext<int64_t>();
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSLTU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value1.GetAsUInt64() < value2.GetAsUInt64();
+  uint64_t result = rs.rs1().trunc<uint64_t>() < rs.rs2().trunc<uint64_t>();
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecXOR(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value1.GetAsUInt64() ^ value2.GetAsUInt64();
+  uint64_t result = rs.rs1().trunc<uint64_t>() ^ rs.rs2().trunc<uint64_t>();
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSRL(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value1.GetAsUInt64() >> (value2.GetAsUInt64() & 0b111111);
+  uint64_t result =
+      rs.rs1().trunc<uint64_t>() >> (rs.rs2().trunc<uint64_t>() & 0b111111);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSRA(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
   uint64_t result =
-      int64_t(value1.GetAsUInt64()) >> (value2.GetAsUInt64() & 0b111111);
+      rs.rs1().sext<int64_t>() >> (rs.rs2().trunc<uint64_t>() & 0b111111);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecOR(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value1.GetAsUInt64() | value2.GetAsUInt64();
+  uint64_t result = rs.rs1().trunc<uint64_t>() | rs.rs2().trunc<uint64_t>();
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecAND(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = value1.GetAsUInt64() & value2.GetAsUInt64();
+  uint64_t result = rs.rs1().trunc<uint64_t>() & rs.rs2().trunc<uint64_t>();
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecADDIW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
   int32_t imm = SignExt(DecodeIImm(inst));
 
-  RegisterValue value1;
-  if (!ReadRegister(emulator, rs1, value1))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = SextW(int32_t(value1.GetAsUInt64()) + imm);
+  uint64_t result = SextW(rs.rs1().sext<int32_t>() + imm);
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSLLIW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto shamt = DecodeSHAMT5(inst);
-
-  RegisterValue value1;
-  if (!ReadRegister(emulator, rs1, value1))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) << shamt);
+  uint64_t result = SextW(rs.rs1().trunc<uint32_t>() << DecodeSHAMT5(inst));
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSRLIW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto shamt = DecodeSHAMT5(inst);
-
-  RegisterValue value1;
-  if (!ReadRegister(emulator, rs1, value1))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) >> shamt);
+  uint64_t result = SextW(rs.rs1().trunc<uint32_t>() >> DecodeSHAMT5(inst));
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSRAIW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto shamt = DecodeSHAMT5(inst);
-
-  RegisterValue value1;
-  if (!ReadRegister(emulator, rs1, value1))
+  auto rs = readRS1(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = SextW(int32_t(value1.GetAsUInt64()) >> shamt);
+  uint64_t result = SextW(rs.rs1().sext<int32_t>() >> DecodeSHAMT5(inst));
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecADDW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = SextW(value1.GetAsUInt32() + value2.GetAsUInt32());
+  uint64_t result =
+      SextW(uint32_t(rs.rs1().trunc<uint64_t>() + rs.rs2().trunc<uint64_t>()));
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSUBW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = SextW(value1.GetAsUInt32() - value2.GetAsUInt32());
+  uint64_t result =
+      SextW(uint32_t(rs.rs1().trunc<uint64_t>() - rs.rs2().trunc<uint64_t>()));
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSLLW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = SextW(uint32_t(value1.GetAsUInt64())
-                          << (value2.GetAsUInt64() & 0b111111));
+  uint64_t result = SextW(rs.rs1().trunc<uint32_t>()
+                          << (rs.rs2().trunc<uint32_t>() & 0b11111));
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSRLW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
-
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) >>
-                          (value2.GetAsUInt64() & 0b111111));
+  uint64_t result = SextW(rs.rs1().trunc<uint32_t>() >>
+                          (rs.rs2().trunc<uint32_t>() & 0b11111));
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
 static bool ExecSRAW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = DecodeRS2(inst);
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  uint64_t result = SextW(rs.rs1().sext<int32_t>() >>
+                          (rs.rs2().trunc<uint64_t>() & 0b111111));
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
 
-  RegisterValue value1;
-  RegisterValue value2;
-  if (!ReadRegister(emulator, rs1, value1) ||
-      !ReadRegister(emulator, rs2, value2))
+// RV32M & RV64M (The standard integer multiplication and division extension) //
+static bool ExecMUL(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
     return false;
 
-  uint64_t result =
-      SextW(int32_t(value1.GetAsUInt64()) >> (value2.GetAsUInt64() & 0b111111));
+  uint64_t result = rs.rs1().trunc<uint64_t>() * rs.rs2().trunc<uint64_t>();
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecMULH(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  llvm::APInt mul = llvm::APInt(128, rs.rs1().trunc<uint64_t>(), true) *
+                    llvm::APInt(128, rs.rs2().trunc<uint64_t>(), true);
+
+  // signed * signed
+  auto result = mul.ashr(64).trunc(64).getZExtValue();
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecMULHSU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  // signed * unsigned
+  llvm::APInt mul =
+      llvm::APInt(128, rs.rs1().trunc<uint64_t>(), true).zext(128) *
+      llvm::APInt(128, rs.rs2().trunc<uint64_t>(), false);
+
+  auto result = mul.lshr(64).trunc(64).getZExtValue();
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecMULHU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  // unsigned * unsigned
+  llvm::APInt mul = llvm::APInt(128, rs.rs1().trunc<uint64_t>(), false) *
+                    llvm::APInt(128, rs.rs2().trunc<uint64_t>(), false);
+  auto result = mul.lshr(64).trunc(64).getZExtValue();
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecDIV(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  int64_t dividend = rs.rs1().sext<int64_t>();
+  int64_t divisor = rs.rs2().sext<int64_t>();
+
+  if (divisor == 0)
+    return WriteRegister(emulator, DecodeRD(inst), RegisterValue(UINT64_MAX));
+
+  if (dividend == INT64_MIN && divisor == -1)
+    return WriteRegister(emulator, DecodeRD(inst),
+                         RegisterValue(uint64_t(dividend)));
+
+  return WriteRegister(emulator, DecodeRD(inst),
+                       RegisterValue(uint64_t(dividend / divisor)));
+}
+
+static bool ExecDIVU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  uint64_t dividend = rs.rs1().trunc<uint64_t>();
+  uint64_t divisor = rs.rs2().trunc<uint64_t>();
+
+  if (divisor == 0)
+    return WriteRegister(emulator, DecodeRD(inst), RegisterValue(UINT64_MAX));
+
+  return WriteRegister(emulator, DecodeRD(inst),
+                       RegisterValue(dividend / divisor));
+}
+
+static bool ExecREM(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  int64_t dividend = rs.rs1().sext<int64_t>();
+  int64_t divisor = rs.rs2().sext<int64_t>();
+
+  if (divisor == 0)
+    return WriteRegister(emulator, DecodeRD(inst),
+                         RegisterValue(uint64_t(dividend)));
+
+  if (dividend == INT64_MIN && divisor == -1)
+    return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(0)));
+
+  return WriteRegister(emulator, DecodeRD(inst),
+                       RegisterValue(uint64_t(dividend % divisor)));
+}
+
+static bool ExecREMU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  uint64_t dividend = rs.rs1().trunc<uint64_t>();
+  uint64_t divisor = rs.rs2().trunc<uint64_t>();
+
+  if (divisor == 0)
+    return WriteRegister(emulator, DecodeRD(inst), RegisterValue(dividend));
+
+  return WriteRegister(emulator, DecodeRD(inst),
+                       RegisterValue(dividend % divisor));
+}
+
+static bool ExecMULW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  uint64_t result = SextW(rs.rs1().sext<int32_t>() * rs.rs2().sext<int32_t>());
   return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
 }
 
+static bool ExecDIVW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  int32_t dividend = rs.rs1().sext<int32_t>();
+  int32_t divisor = rs.rs2().sext<int32_t>();
+
+  if (divisor == 0)
+    return WriteRegister(emulator, DecodeRD(inst), RegisterValue(UINT64_MAX));
+
+  if (dividend == INT32_MIN && divisor == -1)
+    return WriteRegister(emulator, DecodeRD(inst),
+                         RegisterValue(SextW(dividend)));
+
+  return WriteRegister(emulator, DecodeRD(inst),
+                       RegisterValue(SextW(dividend / divisor)));
+}
+
+static bool ExecDIVUW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  uint32_t dividend = rs.rs1().trunc<uint32_t>();
+  uint32_t divisor = rs.rs2().trunc<uint32_t>();
+
+  if (divisor == 0)
+    return WriteRegister(emulator, DecodeRD(inst), RegisterValue(UINT64_MAX));
+
+  return WriteRegister(emulator, DecodeRD(inst),
+                       RegisterValue(SextW(dividend / divisor)));
+}
+
+static bool ExecREMW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  int32_t dividend = rs.rs1().sext<int32_t>();
+  int32_t divisor = rs.rs2().sext<int32_t>();
+
+  if (divisor == 0)
+    return WriteRegister(emulator, DecodeRD(inst),
+                         RegisterValue(SextW(dividend)));
+
+  if (dividend == INT32_MIN && divisor == -1)
+    return WriteRegister(emulator, DecodeRD(inst), RegisterValue(uint64_t(0)));
+
+  return WriteRegister(emulator, DecodeRD(inst),
+                       RegisterValue(SextW(dividend % divisor)));
+}
+
+static bool ExecREMUW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  auto rs = readRS1RS2(emulator, inst);
+  if (!rs.valid)
+    return false;
+
+  uint32_t dividend = rs.rs1().trunc<uint32_t>();
+  uint32_t divisor = rs.rs2().trunc<uint32_t>();
+
+  if (divisor == 0)
+    return WriteRegister(emulator, DecodeRD(inst),
+                         RegisterValue(SextW(dividend)));
+
+  return WriteRegister(emulator, DecodeRD(inst),
+                       RegisterValue(SextW(dividend % divisor)));
+}
+
+// RV32A & RV64A (The standard atomic instruction extension) //
+static uint64_t AtomicAddr(EmulateInstructionRISCV &emulator, uint32_t reg,
+                           unsigned int align) {
+  RegisterValue value;
+  if (!ReadRegister(emulator, reg, value))
+    return LLDB_INVALID_ADDRESS;
+
+  uint64_t addr = value.GetAsUInt64();
+  return addr % align == 0 ? addr : LLDB_INVALID_ADDRESS;
+}
+
+template <typename T>
+static bool AtomicSwap(EmulateInstructionRISCV &emulator, uint32_t inst,
+                       int align, uint64_t (*extend)(T)) {
+  RegisterValue rs2;
+  if (!ReadRegister(emulator, DecodeRS2(inst), rs2))
+    return false;
+
+  uint64_t addr = AtomicAddr(emulator, DecodeRS1(inst), align);
+  if (addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+  T tmp = ReadMem<T>(emulator, addr).value();
+  if (!tmp)
+    return false;
+
+  bool success =
+      WriteMem<T>(emulator, addr, RegisterValue(T(rs2.GetAsUInt64())));
+  if (!success)
+    return false;
+
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(extend(tmp)));
+}
+
+template <typename T>
+static bool AtomicADD(EmulateInstructionRISCV &emulator, uint32_t inst,
+                      int align, uint64_t (*extend)(T)) {
+  RegisterValue rs2;
+  if (!ReadRegister(emulator, DecodeRS2(inst), rs2))
+    return false;
+
+  uint64_t addr = AtomicAddr(emulator, DecodeRS1(inst), align);
+  if (addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+  T value = ReadMem<T>(emulator, addr).value();
+  if (!value)
+    return false;
+
+  bool success =
+      WriteMem<T>(emulator, addr, RegisterValue(value + T(rs2.GetAsUInt64())));
+  if (!success)
+    return false;
+
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(extend(value)));
+}
+
+template <typename T>
+static bool AtomicBitOperate(EmulateInstructionRISCV &emulator, uint32_t inst,
+                             int align, uint64_t (*extend)(T),
+                             T (*operate)(T, T)) {
+  RegisterValue rs2;
+  if (!ReadRegister(emulator, DecodeRS2(inst), rs2))
+    return false;
+
+  uint64_t addr = AtomicAddr(emulator, DecodeRS1(inst), align);
+  if (addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+  T value = ReadMem<T>(emulator, addr).value();
+  if (!value)
+    return false;
+
+  bool success = WriteMem<T>(
+      emulator, addr, RegisterValue(operate(value, T(rs2.GetAsUInt64()))));
+  if (!success)
+    return false;
+
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(extend(value)));
+}
+
+template <typename T>
+static bool AtomicCmp(EmulateInstructionRISCV &emulator, uint32_t inst,
+                      int align, uint64_t (*extend)(T), T (*cmp)(T, T)) {
+  RegisterValue rs2;
+  if (!ReadRegister(emulator, DecodeRS2(inst), rs2))
+    return false;
+
+  uint64_t addr = AtomicAddr(emulator, DecodeRS1(inst), align);
+  if (addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+  T value = ReadMem<T>(emulator, addr).value();
+  if (!value)
+    return false;
+
+  bool success = WriteMem<T>(emulator, addr,
+                             RegisterValue(cmp(value, T(rs2.GetAsUInt64()))));
+  if (!success)
+    return false;
+
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(extend(value)));
+}
+
+// 00010 aq[1] rl[1] 00000 rs1[5] 010 rd[5] 0101111 LR.D
+// 00010 aq[1] rl[1] 00000 rs1[5] 011 rd[5] 0101111 LR.W
+static bool IsLR(uint32_t inst) {
+  return (inst & 0xF9F0707F) == 0x1000202F || (inst & 0xF9F0707F) == 0x1000302F;
+}
+
+// 00011 aq[1] rl[1] rs2[5] rs1[5] 010 rd[5] 0101111 SC.W
+// 00011 aq[1] rl[1] rs2[5] rs1[5] 011 rd[5] 0101111 SC.D
+static bool IsSC(uint32_t inst) {
+  return (inst & 0xF800707F) == 0x1800202F || (inst & 0xF800707F) == 0x1800302F;
+}
+
+// imm[7] rs2[5] rs1[5] 001 imm[5] 1100011 BNE
+static bool IsBNE(uint32_t inst) { return (inst & 0x707F) == 0x1063; }
+
+static bool ExecAtomicSequence(EmulateInstructionRISCV &emulator, uint32_t inst,
+                               bool) {
+  // The atomic sequence is always 4 instructions long:
+  // example:
+  //   110cc:	100427af          	lr.w	a5,(s0)
+  //   110d0:	00079663          	bnez	a5,110dc
+  //   110d4:	1ce426af          	sc.w.aq	a3,a4,(s0)
+  //   110d8:	fe069ae3          	bnez	a3,110cc
+  //   110dc:   ........          	<next instruction>
+  bool success = false;
+  llvm::Optional<lldb::addr_t> pc = emulator.ReadPC(success);
+  if (!success || !pc)
+    return false;
+  lldb::addr_t current_pc = pc.value();
+  lldb::addr_t start_pc = current_pc;
+  llvm::Optional<uint32_t> value = inst;
+
+  // inst must be LR
+  if (!value || !IsLR(value.value()))
+    return false;
+  value = ReadMem<uint32_t>(emulator, current_pc += 4).value();
+
+  // inst must be BNE to exit
+  if (!value || !IsBNE(value.value()))
+    return false;
+  auto exit_pc = current_pc + SextW(DecodeBImm(value.value()));
+  value = ReadMem<uint32_t>(emulator, current_pc += 4).value();
+
+  // inst must be SC
+  if (!value || !IsSC(value.value()))
+    return false;
+  value = ReadMem<uint32_t>(emulator, current_pc += 4).value();
+
+  // inst must be BNE to restart
+  if (!value || !IsBNE(value.value()))
+    return false;
+  if (current_pc + SextW(DecodeBImm(value.value())) != start_pc)
+    return false;
+  current_pc += 4;
+
+  if (exit_pc != current_pc)
+    return false;
+
+  return emulator.WritePC(current_pc);
+}
+
+static bool ExecLR_W(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return ExecAtomicSequence(emulator, inst, false);
+}
+
+static bool ExecAMOSWAP_W(EmulateInstructionRISCV &emulator, uint32_t inst,
+                          bool) {
+  return AtomicSwap<uint32_t>(emulator, inst, 4, SextW);
+}
+
+static bool ExecAMOADD_W(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicADD<uint32_t>(emulator, inst, 4, SextW);
+}
+
+static bool ExecAMOXOR_W(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicBitOperate<uint32_t>(
+      emulator, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a ^ b; });
+}
+
+static bool ExecAMOAND_W(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicBitOperate<uint32_t>(
+      emulator, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a & b; });
+}
+
+static bool ExecAMOOR_W(EmulateInstructionRISCV &emulator, uint32_t inst,
+                        bool) {
+  return AtomicBitOperate<uint32_t>(
+      emulator, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a | b; });
+}
+
+static bool ExecAMOMIN_W(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicCmp<uint32_t>(
+      emulator, inst, 4, SextW, [](uint32_t a, uint32_t b) {
+        return uint32_t(std::min(int32_t(a), int32_t(b)));
+      });
+}
+
+static bool ExecAMOMAX_W(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicCmp<uint32_t>(
+      emulator, inst, 4, SextW, [](uint32_t a, uint32_t b) {
+        return uint32_t(std::max(int32_t(a), int32_t(b)));
+      });
+}
+
+static bool ExecAMOMINU_W(EmulateInstructionRISCV &emulator, uint32_t inst,
+                          bool) {
+  return AtomicCmp<uint32_t>(
+      emulator, inst, 4, SextW,
+      [](uint32_t a, uint32_t b) { return std::min(a, b); });
+}
+
+static bool ExecAMOMAXU_W(EmulateInstructionRISCV &emulator, uint32_t inst,
+                          bool) {
+  return AtomicCmp<uint32_t>(
+      emulator, inst, 4, SextW,
+      [](uint32_t a, uint32_t b) { return std::max(a, b); });
+}
+
+static bool ExecLR_D(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return ExecAtomicSequence(emulator, inst, false);
+}
+
+static bool ExecAMOSWAP_D(EmulateInstructionRISCV &emulator, uint32_t inst,
+                          bool) {
+  return AtomicSwap<uint64_t>(emulator, inst, 8, ZextD);
+}
+
+static bool ExecAMOADD_D(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicADD<uint64_t>(emulator, inst, 8, ZextD);
+}
+
+static bool ExecAMOXOR_D(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicBitOperate<uint64_t>(
+      emulator, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a ^ b; });
+}
+
+static bool ExecAMOAND_D(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicBitOperate<uint64_t>(
+      emulator, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a & b; });
+}
+
+static bool ExecAMOOR_D(EmulateInstructionRISCV &emulator, uint32_t inst,
+                        bool) {
+  return AtomicBitOperate<uint64_t>(
+      emulator, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a | b; });
+}
+
+static bool ExecAMOMIN_D(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicCmp<uint64_t>(
+      emulator, inst, 8, ZextD, [](uint64_t a, uint64_t b) {
+        return uint64_t(std::min(int64_t(a), int64_t(b)));
+      });
+}
+
+static bool ExecAMOMAX_D(EmulateInstructionRISCV &emulator, uint32_t inst,
+                         bool) {
+  return AtomicCmp<uint64_t>(
+      emulator, inst, 8, ZextD, [](uint64_t a, uint64_t b) {
+        return uint64_t(std::max(int64_t(a), int64_t(b)));
+      });
+}
+
+static bool ExecAMOMINU_D(EmulateInstructionRISCV &emulator, uint32_t inst,
+                          bool) {
+  return AtomicCmp<uint64_t>(
+      emulator, inst, 8, ZextD,
+      [](uint64_t a, uint64_t b) { return std::min(a, b); });
+}
+
+static bool ExecAMOMAXU_D(EmulateInstructionRISCV &emulator, uint32_t inst,
+                          bool) {
+  return AtomicCmp<uint64_t>(
+      emulator, inst, 8, ZextD,
+      [](uint64_t a, uint64_t b) { return std::max(a, b); });
+}
+
 static const InstrPattern PATTERNS[] = {
+    // RV32I & RV64I (The base integer ISA) //
     {"LUI", 0x7F, 0x37, ExecLUI},
     {"AUIPC", 0x7F, 0x17, ExecAUIPC},
     {"JAL", 0x7F, 0x6F, ExecJAL},
@@ -712,19 +1150,55 @@ static const InstrPattern PATTERNS[] = {
     {"SLLW", 0xFE00707F, 0x103B, ExecSLLW},
     {"SRLW", 0xFE00707F, 0x503B, ExecSRLW},
     {"SRAW", 0xFE00707F, 0x4000503B, ExecSRAW},
+
+    // RV32M & RV64M (The integer multiplication and division extension) //
+    {"MUL", 0xFE00707F, 0x2000033, ExecMUL},
+    {"MULH", 0xFE00707F, 0x2001033, ExecMULH},
+    {"MULHSU", 0xFE00707F, 0x2002033, ExecMULHSU},
+    {"MULHU", 0xFE00707F, 0x2003033, ExecMULHU},
+    {"DIV", 0xFE00707F, 0x2004033, ExecDIV},
+    {"DIVU", 0xFE00707F, 0x2005033, ExecDIVU},
+    {"REM", 0xFE00707F, 0x2006033, ExecREM},
+    {"REMU", 0xFE00707F, 0x2007033, ExecREMU},
+    {"MULW", 0xFE00707F, 0x200003B, ExecMULW},
+    {"DIVW", 0xFE00707F, 0x200403B, ExecDIVW},
+    {"DIVUW", 0xFE00707F, 0x200503B, ExecDIVUW},
+    {"REMW", 0xFE00707F, 0x200603B, ExecREMW},
+    {"REMUW", 0xFE00707F, 0x200703B, ExecREMUW},
+
+    // RV32A & RV64A (The standard atomic instruction extension) //
+    {"LR_W", 0xF9F0707F, 0x1000202F, ExecLR_W},
+    {"AMOSWAP_W", 0xF800707F, 0x800202F, ExecAMOSWAP_W},
+    {"AMOADD_W", 0xF800707F, 0x202F, ExecAMOADD_W},
+    {"AMOXOR_W", 0xF800707F, 0x2000202F, ExecAMOXOR_W},
+    {"AMOAND_W", 0xF800707F, 0x6000202F, ExecAMOAND_W},
+    {"AMOOR_W", 0xF800707F, 0x4000202F, ExecAMOOR_W},
+    {"AMOMIN_W", 0xF800707F, 0x8000202F, ExecAMOMIN_W},
+    {"AMOMAX_W", 0xF800707F, 0xA000202F, ExecAMOMAX_W},
+    {"AMOMINU_W", 0xF800707F, 0xC000202F, ExecAMOMINU_W},
+    {"AMOMAXU_W", 0xF800707F, 0xE000202F, ExecAMOMAXU_W},
+    {"LR_D", 0xF9F0707F, 0x1000302F, ExecLR_D},
+    {"AMOSWAP_D", 0xF800707F, 0x800302F, ExecAMOSWAP_D},
+    {"AMOADD_D", 0xF800707F, 0x302F, ExecAMOADD_D},
+    {"AMOXOR_D", 0xF800707F, 0x2000302F, ExecAMOXOR_D},
+    {"AMOAND_D", 0xF800707F, 0x6000302F, ExecAMOAND_D},
+    {"AMOOR_D", 0xF800707F, 0x4000302F, ExecAMOOR_D},
+    {"AMOMIN_D", 0xF800707F, 0x8000302F, ExecAMOMIN_D},
+    {"AMOMAX_D", 0xF800707F, 0xA000302F, ExecAMOMAX_D},
+    {"AMOMINU_D", 0xF800707F, 0xC000302F, ExecAMOMINU_D},
+    {"AMOMAXU_D", 0xF800707F, 0xE000302F, ExecAMOMAXU_D},
 };
 
 const InstrPattern *EmulateInstructionRISCV::Decode(uint32_t inst) {
   for (const InstrPattern &pat : PATTERNS) {
-    if ((inst & pat.type_mask) == pat.eigen) {
+    if ((inst & pat.type_mask) == pat.eigen)
       return &pat;
-    }
   }
   return nullptr;
 }
 
 /// This function only determines the next instruction address for software
-/// sigle stepping by emulating instructions
+/// single stepping by emulating instructions
 bool EmulateInstructionRISCV::DecodeAndExecute(uint32_t inst,
                                                bool ignore_cond) {
   Log *log = GetLog(LLDBLog::Unwind);
@@ -735,11 +1209,9 @@ bool EmulateInstructionRISCV::DecodeAndExecute(uint32_t inst,
     return pattern->exec(*this, inst, ignore_cond);
   }
 
-  LLDB_LOGF(log,
-            "EmulateInstructionRISCV::%s: inst(0x%x) does not branch: "
-            "no need to calculate the next pc address which is trivial.",
+  LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(0x%x) was unsupported",
             __FUNCTION__, inst);
-  return true;
+  return false;
 }
 
 bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) {
@@ -751,7 +1223,7 @@ bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) {
 
   lldb::addr_t old_pc = LLDB_INVALID_ADDRESS;
   if (increase_pc) {
-    old_pc = ReadPC(&success);
+    old_pc = ReadPC(success);
     if (!success)
       return false;
   }
@@ -766,7 +1238,7 @@ bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) {
     return false;
 
   if (increase_pc) {
-    lldb::addr_t new_pc = ReadPC(&success);
+    lldb::addr_t new_pc = ReadPC(success);
     if (!success)
       return false;
 
@@ -780,7 +1252,7 @@ bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) {
 
 bool EmulateInstructionRISCV::ReadInstruction() {
   bool success = false;
-  m_addr = ReadPC(&success);
+  m_addr = ReadPC(success);
   if (!success) {
     m_addr = LLDB_INVALID_ADDRESS;
     return false;
@@ -801,9 +1273,9 @@ bool EmulateInstructionRISCV::ReadInstruction() {
   return true;
 }
 
-lldb::addr_t EmulateInstructionRISCV::ReadPC(bool *success) {
+lldb::addr_t EmulateInstructionRISCV::ReadPC(bool &success) {
   return ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
-                              LLDB_INVALID_ADDRESS, success);
+                              LLDB_INVALID_ADDRESS, &success);
 }
 
 bool EmulateInstructionRISCV::WritePC(lldb::addr_t pc) {

diff  --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
index 07dfcf692fca8..1c7cf6cb08d66 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
@@ -12,6 +12,7 @@
 #include "lldb/Core/EmulateInstruction.h"
 #include "lldb/Interpreter/OptionValue.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
 #include "lldb/Utility/Status.h"
 
 namespace lldb_private {
@@ -78,11 +79,31 @@ class EmulateInstructionRISCV : public EmulateInstruction {
   bool GetRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num,
                        RegisterInfo &reg_info) override;
 
-  lldb::addr_t ReadPC(bool *success);
+  lldb::addr_t ReadPC(bool &success);
   bool WritePC(lldb::addr_t pc);
 
   const InstrPattern *Decode(uint32_t inst);
   bool DecodeAndExecute(uint32_t inst, bool ignore_cond);
+
+  template <typename T>
+  static std::enable_if_t<std::is_integral_v<T>, T>
+  ReadMem(EmulateInstructionRISCV &emulator, uint64_t addr, bool *success) {
+
+    EmulateInstructionRISCV::Context ctx;
+    ctx.type = EmulateInstruction::eContextRegisterLoad;
+    ctx.SetNoArgs();
+    return T(emulator.ReadMemoryUnsigned(ctx, addr, sizeof(T), T(), success));
+  }
+
+  template <typename T>
+  static bool WriteMem(EmulateInstructionRISCV &emulator, uint64_t addr,
+                       RegisterValue value) {
+    EmulateInstructionRISCV::Context ctx;
+    ctx.type = EmulateInstruction::eContextRegisterStore;
+    ctx.SetNoArgs();
+    return emulator.WriteMemoryUnsigned(ctx, addr, value.GetAsUInt64(),
+                                        sizeof(T));
+  }
 };
 
 } // namespace lldb_private

diff  --git a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
index 2ae8b4eb7149c..2df2d08711a8a 100644
--- a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
+++ b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
@@ -24,11 +24,14 @@ using namespace lldb_private;
 
 struct RISCVEmulatorTester : public EmulateInstructionRISCV, testing::Test {
   RegisterInfoPOSIX_riscv64::GPR gpr;
+  uint8_t memory[1024] = {0};
 
   RISCVEmulatorTester()
       : EmulateInstructionRISCV(ArchSpec("riscv64-unknown-linux-gnu")) {
     EmulateInstruction::SetReadRegCallback(ReadRegisterCallback);
     EmulateInstruction::SetWriteRegCallback(WriteRegisterCallback);
+    EmulateInstruction::SetReadMemCallback(ReadMemoryCallback);
+    EmulateInstruction::SetWriteMemCallback(WriteMemoryCallback);
   }
 
   static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
@@ -53,6 +56,25 @@ struct RISCVEmulatorTester : public EmulateInstructionRISCV, testing::Test {
       tester->gpr.gpr[reg] = reg_value.GetAsUInt64();
     return true;
   }
+
+  static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
+                                   const Context &context, lldb::addr_t addr,
+                                   void *dst, size_t length) {
+    RISCVEmulatorTester *tester = (RISCVEmulatorTester *)instruction;
+    assert(addr + length < sizeof(tester->memory));
+    memcpy(dst, tester->memory + addr, length);
+    return length;
+  };
+
+  static size_t WriteMemoryCallback(EmulateInstruction *instruction,
+                                    void *baton, const Context &context,
+                                    lldb::addr_t addr, const void *dst,
+                                    size_t length) {
+    RISCVEmulatorTester *tester = (RISCVEmulatorTester *)instruction;
+    assert(addr + length < sizeof(tester->memory));
+    memcpy(tester->memory + addr, dst, length);
+    return length;
+  };
 };
 
 TEST_F(RISCVEmulatorTester, testJAL) {
@@ -64,7 +86,7 @@ TEST_F(RISCVEmulatorTester, testJAL) {
   auto x1 = gpr.gpr[1];
 
   bool success = false;
-  auto pc = ReadPC(&success);
+  auto pc = ReadPC(success);
 
   ASSERT_TRUE(success);
   ASSERT_EQ(x1, old_pc + 4);
@@ -91,7 +113,7 @@ TEST_F(RISCVEmulatorTester, testJALR) {
   auto x1 = gpr.gpr[1];
 
   bool success = false;
-  auto pc = ReadPC(&success);
+  auto pc = ReadPC(success);
 
   ASSERT_TRUE(success);
   ASSERT_EQ(x1, old_pc + 4);
@@ -144,7 +166,7 @@ void testBranch(RISCVEmulatorTester *tester, EncoderB encoder, bool branched,
   uint32_t inst = encoder(1, 2, -256);
   ASSERT_TRUE(tester->DecodeAndExecute(inst, false));
   bool success = false;
-  auto pc = tester->ReadPC(&success);
+  auto pc = tester->ReadPC(success);
   ASSERT_TRUE(success);
   ASSERT_EQ(pc, old_pc + (branched ? (-256) : 0));
 }
@@ -161,6 +183,13 @@ 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) {
+  bool success = false;
+  ASSERT_EQ(tester->ReadMem<T>(*tester, addr, &success), value);
+  ASSERT_TRUE(success);
+}
+
 using RS1 = uint64_t;
 using RS2 = uint64_t;
 using PC = uint64_t;
@@ -171,21 +200,62 @@ void TestInst(RISCVEmulatorTester *tester, uint64_t inst, bool has_rs2,
 
   lldb::addr_t old_pc = 0x114514;
   tester->WritePC(old_pc);
-  auto rd = DecodeRD(inst);
-  auto rs1 = DecodeRS1(inst);
-  auto rs2 = 0;
+  uint32_t rd = DecodeRD(inst);
+  uint32_t rs1 = DecodeRS1(inst);
+  uint32_t rs2 = 0;
+
+  uint64_t rs1_val = 0x19;
+  uint64_t rs2_val = 0x81;
+
   if (rs1)
-    tester->gpr.gpr[rs1] = 0x1919;
+    tester->gpr.gpr[rs1] = rs1_val;
 
   if (has_rs2) {
     rs2 = DecodeRS2(inst);
-    if (rs2)
-      tester->gpr.gpr[rs2] = 0x8181;
+    if (rs2) {
+      if (rs1 == rs2)
+        rs2_val = rs1_val;
+      tester->gpr.gpr[rs2] = rs2_val;
+    }
   }
 
   ASSERT_TRUE(tester->DecodeAndExecute(inst, false));
-  CheckRD(tester, rd,
-          rd_val(tester->gpr.gpr[rs1], rs2 ? tester->gpr.gpr[rs2] : 0, old_pc));
+  CheckRD(tester, rd, rd_val(rs1_val, rs2 ? rs2_val : 0, old_pc));
+}
+
+template <typename T>
+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);
+  uint32_t rs1 = DecodeRS1(inst);
+  uint32_t rs2 = DecodeRS2(inst);
+
+  // addr was stored in rs1
+  uint64_t atomic_addr = 0x100;
+
+  tester->gpr.gpr[rs1] = atomic_addr;
+  tester->gpr.gpr[rs2] = rs2_val;
+
+  // Write and check rs1_val in atomic_addr
+  ASSERT_TRUE(
+      tester->WriteMem<T>(*tester, atomic_addr, RegisterValue(rs1_val)));
+  CheckMem<T>(tester, atomic_addr, rs1_val);
+
+  ASSERT_TRUE(tester->DecodeAndExecute(inst, false));
+  CheckRD(tester, rd, rd_expected);
+  CheckMem<T>(tester, atomic_addr, mem_expected);
+}
+
+TEST_F(RISCVEmulatorTester, TestAtomicSequence) {
+  this->WritePC(0x0);
+  *(uint64_t *)this->memory = 0x100427af;        // lr.w	a5,(s0)
+  *(uint64_t *)(this->memory + 4) = 0x00079663;  // bnez	a5,12
+  *(uint64_t *)(this->memory + 8) = 0x1ce426af;  // sc.w.aq	a3,a4,(s0)
+  *(uint64_t *)(this->memory + 12) = 0xfe069ae3; // bnez	a3,-12
+  ASSERT_TRUE(this->DecodeAndExecute(*(uint32_t *)this->memory, false));
+  ASSERT_EQ(this->gpr.gpr[0], uint64_t(16));
 }
 
 // GEN_BRANCH_TEST(opcode, imm1, imm2, imm3):
@@ -208,18 +278,43 @@ struct TestData {
 TEST_F(RISCVEmulatorTester, TestDecodeAndExcute) {
 
   std::vector<TestData> tests = {
+      // RV32I & RV64I Tests
       {0x00010113, "ADDI", false, [](RS1 rs1, RS2, PC) { return rs1 + 0; }},
       {0x00023517, "AUIPC", false, [](RS1, RS2, PC pc) { return pc + 143360; }},
       {0x0006079b, "ADDIW", false, [](RS1 rs1, RS2, PC) { return rs1 + 0; }},
       {0x00110837, "LUI", false, [](RS1, RS2, PC pc) { return 1114112; }},
       {0x00147513, "ANDI", false, [](RS1 rs1, RS2, PC) { return rs1 & 1; }},
-      {0x00153513, "SLTIU", false, [](RS1 rs1, RS2, PC) { return rs1 != 0; }},
-      {0x00256513, "ORI", false, [](RS1 rs1, RS2, PC) { return rs1 | 1; }},
+      {0x00153513, "SLTIU", false, [](RS1 rs1, RS2, PC) { return 0; }},
+      {0x00256513, "ORI", false, [](RS1 rs1, RS2, PC) { return rs1 | 2; }},
       {0x00451a13, "SLLI", false, [](RS1 rs1, RS2, PC) { return rs1 << 4; }},
       {0x00455693, "SRLI", false, [](RS1 rs1, RS2, PC) { return rs1 >> 4; }},
       {0x00a035b3, "SLTU", true, [](RS1 rs1, RS2 rs2, PC) { return rs2 != 0; }},
       {0x00b50633, "ADD", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 + rs2; }},
       {0x40d507b3, "SUB", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 - rs2; }},
+
+      // RV32M & RV64M Tests
+      {0x02f787b3, "MUL", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 * rs2; }},
+      {0x2F797B3, "MULH", true, [](RS1 rs1, RS2 rs2, PC) { return 0; }},
+      {0x2F7A7B3, "MULHSU", true,
+       [](RS1 rs1, RS2 rs2, PC) { return 0; }},
+      {0x2F7B7B3, "MULHU", true,
+       [](RS1 rs1, RS2 rs2, PC) { return 0; }},
+      {0x02f747b3, "DIV", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
+      {0x02f757b3, "DIVU", true,
+       [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
+      {0x02f767b3, "REM", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
+      {0x02f777b3, "REMU", true,
+       [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
+      {0x02f787bb, "MULW", true,
+       [](RS1 rs1, RS2 rs2, PC) { return rs1 * rs2; }},
+      {0x02f747bb, "DIVW", true,
+       [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
+      {0x02f757bb, "DIVUW", true,
+       [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
+      {0x02f767bb, "REMW", true,
+       [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
+      {0x02f777bb, "REMUW", true,
+       [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
   };
   for (auto i : tests) {
     const InstrPattern *pattern = this->Decode(i.inst);
@@ -229,3 +324,48 @@ TEST_F(RISCVEmulatorTester, TestDecodeAndExcute) {
     TestInst(this, i.inst, i.has_rs2, i.rd_val);
   }
 }
+
+TEST_F(RISCVEmulatorTester, TestAMOSWAP) {
+  TestAtomic<uint32_t>(this, 0x8F7282F, 0x1, 0x2, 0x1, 0x2);
+  TestAtomic<uint64_t>(this, 0x8F7382F, 0x1, 0x2, 0x1, 0x2);
+}
+
+TEST_F(RISCVEmulatorTester, TestAMOADD) {
+  TestAtomic<uint32_t>(this, 0xF7282F, 0x1, 0x2, 0x1, 0x3);
+  TestAtomic<uint64_t>(this, 0xF7382F, 0x1, 0x2, 0x1, 0x3);
+}
+
+TEST_F(RISCVEmulatorTester, TestAMOXOR) {
+  TestAtomic<uint32_t>(this, 0x20F7282F, 0x1, 0x2, 0x1, 0x3);
+  TestAtomic<uint32_t>(this, 0x20F7382F, 0x1, 0x2, 0x1, 0x3);
+}
+
+TEST_F(RISCVEmulatorTester, TestAMOAND) {
+  TestAtomic<uint32_t>(this, 0x60F7282F, 0x1, 0x2, 0x1, 0x0);
+  TestAtomic<uint64_t>(this, 0x60F7382F, 0x1, 0x2, 0x1, 0x0);
+}
+
+TEST_F(RISCVEmulatorTester, TestAMOOR) {
+  TestAtomic<uint32_t>(this, 0x40F7282F, 0x1, 0x2, 0x1, 0x3);
+  TestAtomic<uint32_t>(this, 0x40F7382F, 0x1, 0x2, 0x1, 0x3);
+}
+
+TEST_F(RISCVEmulatorTester, TestAMOMIN) {
+  TestAtomic<uint32_t>(this, 0x80F7282F, 0x1, 0x2, 0x1, 0x1);
+  TestAtomic<uint64_t>(this, 0x80F7382F, 0x1, 0x2, 0x1, 0x1);
+}
+
+TEST_F(RISCVEmulatorTester, TestAMOMAX) {
+  TestAtomic<uint32_t>(this, 0xA0F7282F, 0x1, 0x2, 0x1, 0x2);
+  TestAtomic<uint64_t>(this, 0xA0F7382F, 0x1, 0x2, 0x1, 0x2);
+}
+
+TEST_F(RISCVEmulatorTester, TestAMOMINU) {
+  TestAtomic<uint32_t>(this, 0xC0F7282F, 0x1, 0x2, 0x1, 0x1);
+  TestAtomic<uint64_t>(this, 0xC0F7382F, 0x1, 0x2, 0x1, 0x1);
+}
+
+TEST_F(RISCVEmulatorTester, TestAMOMAXU) {
+  TestAtomic<uint32_t>(this, 0xE0F7282F, 0x1, 0x2, 0x1, 0x2);
+  TestAtomic<uint64_t>(this, 0xE0F7382F, 0x1, 0x2, 0x1, 0x2);
+}


        


More information about the lldb-commits mailing list