[Lldb-commits] [lldb] ff7b876 - [LLDB][RISCV] Add more instruction decode and execute for EmulateInstructionRISCV

via lldb-commits lldb-commits at lists.llvm.org
Thu Sep 1 19:17:23 PDT 2022


Author: Emmmer
Date: 2022-09-02T10:17:09+08:00
New Revision: ff7b876aa75d1d4df581ada78befb707dfdbb129

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

LOG: [LLDB][RISCV] Add more instruction decode and execute for EmulateInstructionRISCV

Add:
- most of instructions from RVI base instructions set.
- some instruction decode tests from objdump.

Further work:
- implement riscv imac extension.

Reviewed By: DavidSpickett

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

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 10aefc6d9dc08..4ca017dd98bbe 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -32,12 +32,6 @@ LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionRISCV, InstructionRISCV)
 
 namespace lldb_private {
 
-// Masks for detecting instructions types. According to riscv-spec Chap 26.
-constexpr uint32_t I_MASK = 0b111000001111111;
-constexpr uint32_t J_MASK = 0b000000001111111;
-// no funct3 in the b-mask because the logic executing B<CMP> is quite similar.
-constexpr uint32_t B_MASK = 0b000000001111111;
-
 // The funct3 is the type of compare in B<CMP> instructions.
 // funct3 means "3-bits function selector", which RISC-V ISA uses as minor
 // opcode. It reuses the major opcode encoding space.
@@ -48,13 +42,26 @@ constexpr uint32_t BGE = 0b101;
 constexpr uint32_t BLTU = 0b110;
 constexpr uint32_t BGEU = 0b111;
 
-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 DecodeSHAMT5(uint32_t inst) { return DecodeRS2(inst); }
+constexpr uint32_t DecodeSHAMT7(uint32_t inst) {
+  return (inst & 0x7F00000) >> 20;
+}
 constexpr uint32_t DecodeFunct3(uint32_t inst) { return (inst & 0x7000) >> 12; }
 
+// used in decoder
 constexpr int32_t SignExt(uint32_t imm) { return int32_t(imm); }
 
+// used in executor
+template <typename T>
+constexpr std::enable_if_t<sizeof(T) <= 4, uint64_t> SextW(T value) {
+  return uint64_t(int64_t(int32_t(value)));
+}
+
+// used in executor
+template <typename T> constexpr uint64_t ZextD(T value) {
+  return uint64_t(value);
+}
+
 constexpr uint32_t DecodeJImm(uint32_t inst) {
   return (uint64_t(int64_t(int32_t(inst & 0x80000000)) >> 11)) // imm[20]
          | (inst & 0xff000)                                    // imm[19:12]
@@ -73,6 +80,15 @@ constexpr uint32_t DecodeBImm(uint32_t inst) {
          | ((inst >> 7) & 0x1e);                               // imm[4:1]
 }
 
+constexpr uint32_t DecodeSImm(uint32_t inst) {
+  return (uint64_t(int64_t(int32_t(inst & 0xFE00000)) >> 20)) // imm[11:5]
+         | ((inst & 0xF80) >> 7);                             // imm[4:0]
+}
+
+constexpr uint32_t DecodeUImm(uint32_t inst) {
+  return SextW(inst & 0xFFFFF000); // imm[31:12]
+}
+
 static uint32_t GPREncodingToLLDB(uint32_t reg_encode) {
   if (reg_encode == 0)
     return gpr_x0_riscv;
@@ -81,43 +97,43 @@ static uint32_t GPREncodingToLLDB(uint32_t reg_encode) {
   return LLDB_INVALID_REGNUM;
 }
 
-static bool ReadRegister(EmulateInstructionRISCV *emulator, uint32_t reg_encode,
+static bool ReadRegister(EmulateInstructionRISCV &emulator, uint32_t reg_encode,
                          RegisterValue &value) {
   uint32_t lldb_reg = GPREncodingToLLDB(reg_encode);
-  return emulator->ReadRegister(eRegisterKindLLDB, lldb_reg, value);
+  return emulator.ReadRegister(eRegisterKindLLDB, lldb_reg, value);
 }
 
-static bool WriteRegister(EmulateInstructionRISCV *emulator,
+static bool WriteRegister(EmulateInstructionRISCV &emulator,
                           uint32_t reg_encode, const RegisterValue &value) {
   uint32_t lldb_reg = GPREncodingToLLDB(reg_encode);
   EmulateInstruction::Context ctx;
   ctx.type = EmulateInstruction::eContextRegisterStore;
   ctx.SetNoArgs();
-  return emulator->WriteRegister(ctx, eRegisterKindLLDB, lldb_reg, value);
+  return emulator.WriteRegister(ctx, eRegisterKindLLDB, lldb_reg, value);
 }
 
-static bool ExecJAL(EmulateInstructionRISCV *emulator, uint32_t inst, bool) {
+static bool ExecJAL(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
   bool success = false;
   int64_t offset = SignExt(DecodeJImm(inst));
-  int64_t pc = emulator->ReadPC(&success);
-  return success && emulator->WritePC(pc + offset) &&
+  int64_t pc = emulator.ReadPC(&success);
+  return success && emulator.WritePC(pc + offset) &&
          WriteRegister(emulator, DecodeRD(inst),
                        RegisterValue(uint64_t(pc + 4)));
 }
 
-static bool ExecJALR(EmulateInstructionRISCV *emulator, uint32_t inst, bool) {
+static bool ExecJALR(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
   int64_t offset = SignExt(DecodeIImm(inst));
   RegisterValue value;
   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
   // address, to simplify hardware and to allow auxiliary information to be
   // stored in function pointers."
-  return emulator->WritePC((rs1 + offset) & ~1) &&
+  return emulator.WritePC((rs1 + offset) & ~1) &&
          WriteRegister(emulator, DecodeRD(inst),
                        RegisterValue(uint64_t(pc + 4)));
 }
@@ -141,17 +157,17 @@ static bool CompareB(uint64_t rs1, uint64_t rs2, uint32_t funct3) {
   }
 }
 
-static bool ExecB(EmulateInstructionRISCV *emulator, uint32_t inst,
+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;
 
   uint64_t offset = SignExt(DecodeBImm(inst));
   uint64_t target = pc + offset;
   if (ignore_cond)
-    return emulator->WritePC(target);
+    return emulator.WritePC(target);
 
   RegisterValue value1;
   RegisterValue value2;
@@ -161,43 +177,563 @@ static bool ExecB(EmulateInstructionRISCV *emulator, uint32_t inst,
 
   uint32_t funct3 = DecodeFunct3(inst);
   if (CompareB(value1.GetAsUInt64(), value2.GetAsUInt64(), funct3))
-    return emulator->WritePC(target);
+    return emulator.WritePC(target);
 
   return true;
 }
 
-struct InstrPattern {
-  const char *name;
-  /// Bit mask to check the type of a instruction (B-Type, I-Type, J-Type, etc.)
-  uint32_t type_mask;
-  /// Characteristic value after bitwise-and with type_mask.
-  uint32_t eigen;
-  bool (*exec)(EmulateInstructionRISCV *emulator, uint32_t inst,
-               bool ignore_cond);
-};
+static bool ExecLUI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  uint32_t imm = DecodeUImm(inst);
+  RegisterValue value;
+  value.SetUInt64(SignExt(imm));
+  return WriteRegister(emulator, DecodeRD(inst), value);
+}
+
+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));
+  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) {
+
+  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));
+}
+
+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))
+    return LLDB_INVALID_ADDRESS;
+  uint64_t addr = value.GetAsUInt64() + uint64_t(imm);
+  return addr;
+}
+
+// Read T from memory, then load its sign-extended value E to register.
+template <typename T, typename E>
+static bool Load(EmulateInstructionRISCV &emulator, uint32_t inst,
+                 uint64_t (*extend)(E)) {
+  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)
+    return false;
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(extend(value)));
+}
+
+template <typename T>
+static bool Store(EmulateInstructionRISCV &emulator, uint32_t inst) {
+  uint64_t addr = LoadStoreAddr(emulator, inst);
+  if (addr == LLDB_INVALID_ADDRESS)
+    return false;
+  RegisterValue value;
+  if (!ReadRegister(emulator, DecodeRS2(inst), value))
+    return false;
+  return WriteMem<T>(emulator, addr, value);
+}
+
+static bool ExecLB(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Load<uint8_t, int8_t>(emulator, inst, SextW);
+}
+
+static bool ExecLH(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Load<uint16_t, int16_t>(emulator, inst, SextW);
+}
+
+static bool ExecLW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Load<uint32_t, int32_t>(emulator, inst, SextW);
+}
+
+static bool ExecLD(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Load<uint64_t, uint64_t>(emulator, inst, ZextD);
+}
+
+static bool ExecLBU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Load<uint8_t, uint8_t>(emulator, inst, ZextD);
+}
+
+static bool ExecLHU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Load<uint16_t, uint16_t>(emulator, inst, ZextD);
+}
+
+static bool ExecLWU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Load<uint32_t, uint32_t>(emulator, inst, ZextD);
+}
+
+static bool ExecSB(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Store<uint8_t>(emulator, inst);
+}
+
+static bool ExecSH(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Store<uint16_t>(emulator, inst);
+}
+
+static bool ExecSW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Store<uint32_t>(emulator, inst);
+}
+
+static bool ExecSD(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+  return Store<uint64_t>(emulator, inst);
+}
+
+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))
+    return false;
+
+  uint64_t result = int64_t(value.GetAsUInt64()) + 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))
+    return false;
+
+  uint64_t result = int64_t(value.GetAsUInt64()) < 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))
+    return false;
+
+  uint64_t result = value.GetAsUInt64() < 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))
+    return false;
+
+  uint64_t result = value.GetAsUInt64() ^ 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))
+    return false;
+
+  uint64_t result = value.GetAsUInt64() | 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))
+    return false;
+
+  uint64_t result = value.GetAsUInt64() & 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))
+    return false;
+
+  uint64_t result = value.GetAsUInt64() << shamt;
+  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))
+    return false;
+
+  uint64_t result = value.GetAsUInt64() >> shamt;
+  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))
+    return false;
+
+  uint64_t result = int64_t(value.GetAsUInt64()) >> shamt;
+  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))
+    return false;
 
-static InstrPattern PATTERNS[] = {
-    {"JAL", J_MASK, 0b1101111, ExecJAL},
-    {"JALR", I_MASK, 0b000000001100111, ExecJALR},
-    {"B<CMP>", B_MASK, 0b1100011, ExecB},
-    // TODO: {LR/SC}.{W/D} and ECALL
+  uint64_t result = value1.GetAsUInt64() + value2.GetAsUInt64();
+  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))
+    return false;
+
+  uint64_t result = value1.GetAsUInt64() - value2.GetAsUInt64();
+  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))
+    return false;
+
+  uint64_t result = value1.GetAsUInt64() << (value2.GetAsUInt64() & 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))
+    return false;
+
+  uint64_t result = int64_t(value1.GetAsUInt64()) < int64_t(value2.GetAsUInt64());
+  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))
+    return false;
+
+  uint64_t result = value1.GetAsUInt64() < value2.GetAsUInt64();
+  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))
+    return false;
+
+  uint64_t result = value1.GetAsUInt64() ^ value2.GetAsUInt64();
+  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))
+    return false;
+
+  uint64_t result = value1.GetAsUInt64() >> (value2.GetAsUInt64() & 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))
+    return false;
+
+  uint64_t result =
+      int64_t(value1.GetAsUInt64()) >> (value2.GetAsUInt64() & 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))
+    return false;
+
+  uint64_t result = value1.GetAsUInt64() | value2.GetAsUInt64();
+  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))
+    return false;
+
+  uint64_t result = value1.GetAsUInt64() & value2.GetAsUInt64();
+  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))
+    return false;
+
+  uint64_t result = SextW(int32_t(value1.GetAsUInt64()) + 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))
+    return false;
+
+  uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) << shamt);
+  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))
+    return false;
+
+  uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) >> shamt);
+  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))
+    return false;
+
+  uint64_t result = SextW(int32_t(value1.GetAsUInt64()) >> shamt);
+  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))
+    return false;
+
+  uint64_t result = SextW(value1.GetAsUInt32() + value2.GetAsUInt32());
+  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))
+    return false;
+
+  uint64_t result = SextW(value1.GetAsUInt32() - value2.GetAsUInt32());
+  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))
+    return false;
+
+  uint64_t result = SextW(uint32_t(value1.GetAsUInt64())
+                          << (value2.GetAsUInt64() & 0b111111));
+  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))
+    return false;
+
+  uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) >>
+                          (value2.GetAsUInt64() & 0b111111));
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSRAW(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))
+    return false;
+
+  uint64_t result =
+      SextW(int32_t(value1.GetAsUInt64()) >> (value2.GetAsUInt64() & 0b111111));
+  return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static const InstrPattern PATTERNS[] = {
+    {"LUI", 0x7F, 0x37, ExecLUI},
+    {"AUIPC", 0x7F, 0x17, ExecAUIPC},
+    {"JAL", 0x7F, 0x6F, ExecJAL},
+    {"JALR", 0x707F, 0x67, ExecJALR},
+    {"B<CMP>", 0x7F, 0x63, ExecB},
+    {"LB", 0x707F, 0x3, ExecLB},
+    {"LH", 0x707F, 0x1003, ExecLH},
+    {"LW", 0x707F, 0x2003, ExecLW},
+    {"LBU", 0x707F, 0x4003, ExecLBU},
+    {"LHU", 0x707F, 0x5003, ExecLHU},
+    {"SB", 0x707F, 0x23, ExecSB},
+    {"SH", 0x707F, 0x1023, ExecSH},
+    {"SW", 0x707F, 0x2023, ExecSW},
+    {"ADDI", 0x707F, 0x13, ExecADDI},
+    {"SLTI", 0x707F, 0x2013, ExecSLTI},
+    {"SLTIU", 0x707F, 0x3013, ExecSLTIU},
+    {"XORI", 0x707F, 0x4013, ExecXORI},
+    {"ORI", 0x707F, 0x6013, ExecORI},
+    {"ANDI", 0x707F, 0x7013, ExecANDI},
+    {"SLLI", 0xF800707F, 0x1013, ExecSLLI},
+    {"SRLI", 0xF800707F, 0x5013, ExecSRLI},
+    {"SRAI", 0xF800707F, 0x40005013, ExecSRAI},
+    {"ADD", 0xFE00707F, 0x33, ExecADD},
+    {"SUB", 0xFE00707F, 0x40000033, ExecSUB},
+    {"SLL", 0xFE00707F, 0x1033, ExecSLL},
+    {"SLT", 0xFE00707F, 0x2033, ExecSLT},
+    {"SLTU", 0xFE00707F, 0x3033, ExecSLTU},
+    {"XOR", 0xFE00707F, 0x4033, ExecXOR},
+    {"SRL", 0xFE00707F, 0x5033, ExecSRL},
+    {"SRA", 0xFE00707F, 0x40005033, ExecSRA},
+    {"OR", 0xFE00707F, 0x6033, ExecOR},
+    {"AND", 0xFE00707F, 0x7033, ExecAND},
+    {"LWU", 0x707F, 0x6003, ExecLWU},
+    {"LD", 0x707F, 0x3003, ExecLD},
+    {"SD", 0x707F, 0x3023, ExecSD},
+    {"ADDIW", 0x707F, 0x1B, ExecADDIW},
+    {"SLLIW", 0xFE00707F, 0x101B, ExecSLLIW},
+    {"SRLIW", 0xFE00707F, 0x501B, ExecSRLIW},
+    {"SRAIW", 0xFE00707F, 0x4000501B, ExecSRAIW},
+    {"ADDW", 0xFE00707F, 0x3B, ExecADDW},
+    {"SUBW", 0xFE00707F, 0x4000003B, ExecSUBW},
+    {"SLLW", 0xFE00707F, 0x103B, ExecSLLW},
+    {"SRLW", 0xFE00707F, 0x503B, ExecSRLW},
+    {"SRAW", 0xFE00707F, 0x4000503B, ExecSRAW},
 };
 
-/// This function only determines the next instruction address for software
-/// sigle stepping by emulating branching instructions including:
-/// - from Base Instruction Set  : JAL, JALR, B<CMP>, ECALL
-/// - from Atomic Instruction Set: LR -> BNE -> SC -> BNE
-/// We will get rid of this tedious code when the riscv debug spec is ratified.
-bool EmulateInstructionRISCV::DecodeAndExecute(uint32_t inst,
-                                               bool ignore_cond) {
-  Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
+const InstrPattern *EmulateInstructionRISCV::Decode(uint32_t inst) {
   for (const InstrPattern &pat : PATTERNS) {
     if ((inst & pat.type_mask) == pat.eigen) {
-      LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(%x) was decoded to %s",
-                __FUNCTION__, inst, pat.name);
-      return pat.exec(this, inst, ignore_cond);
+      return &pat;
     }
   }
+  return nullptr;
+}
+
+/// This function only determines the next instruction address for software
+/// sigle stepping by emulating instructions
+bool EmulateInstructionRISCV::DecodeAndExecute(uint32_t inst,
+                                               bool ignore_cond) {
+  Log *log = GetLog(LLDBLog::Unwind);
+  const InstrPattern *pattern = this->Decode(inst);
+  if (pattern) {
+    LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(%x) was decoded to %s",
+              __FUNCTION__, inst, pattern->name);
+    return pattern->exec(*this, inst, ignore_cond);
+  }
 
   LLDB_LOGF(log,
             "EmulateInstructionRISCV::%s: inst(0x%x) does not branch: "
@@ -213,7 +749,7 @@ bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) {
   bool ignore_cond = options & eEmulateInstructionOptionIgnoreConditions;
   bool success = false;
 
-  lldb::addr_t old_pc = 0;
+  lldb::addr_t old_pc = LLDB_INVALID_ADDRESS;
   if (increase_pc) {
     old_pc = ReadPC(&success);
     if (!success)
@@ -253,15 +789,14 @@ bool EmulateInstructionRISCV::ReadInstruction() {
   Context ctx;
   ctx.type = eContextReadOpcode;
   ctx.SetNoArgs();
-  uint32_t inst = (uint32_t)ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success);
-  uint16_t try_rvc = (uint16_t)(inst & 0x0000ffff);
+  uint32_t inst = uint32_t(ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success));
+  uint16_t try_rvc = uint16_t(inst & 0x0000ffff);
   // check whether the compressed encode could be valid
   uint16_t mask = try_rvc & 0b11;
-  if (try_rvc != 0 && mask != 3) {
+  if (try_rvc != 0 && mask != 3)
     m_opcode.SetOpcode16(try_rvc, GetByteOrder());
-  } else {
+  else
     m_opcode.SetOpcode32(inst, GetByteOrder());
-  }
 
   return true;
 }

diff  --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
index 65fba83eb14f7..2ed049ffac990 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
@@ -16,6 +16,22 @@
 
 namespace lldb_private {
 
+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; }
+
+class EmulateInstructionRISCV;
+
+struct InstrPattern {
+  const char *name;
+  /// Bit mask to check the type of a instruction (B-Type, I-Type, J-Type, etc.)
+  uint32_t type_mask;
+  /// Characteristic value after bitwise-and with type_mask.
+  uint32_t eigen;
+  bool (*exec)(EmulateInstructionRISCV &emulator, uint32_t inst,
+               bool ignore_cond);
+};
+
 class EmulateInstructionRISCV : public EmulateInstruction {
 public:
   static llvm::StringRef GetPluginNameStatic() { return "riscv"; }
@@ -32,6 +48,8 @@ class EmulateInstructionRISCV : public EmulateInstruction {
     case eInstructionTypePrologueEpilogue:
     case eInstructionTypeAll:
       return false;
+    default:
+      llvm_unreachable("Unhandled instruction type");
     }
     llvm_unreachable("Fully covered switch above!");
   }
@@ -64,6 +82,8 @@ class EmulateInstructionRISCV : public EmulateInstruction {
 
   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);
 };
 

diff  --git a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
index c49f33ddd0d7e..2ae8b4eb7149c 100644
--- a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
+++ b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
@@ -157,6 +157,37 @@ 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) {
+  ASSERT_EQ(tester->gpr.gpr[rd], value);
+}
+
+using RS1 = uint64_t;
+using RS2 = uint64_t;
+using PC = uint64_t;
+using RDComputer = std::function<uint64_t(RS1, RS2, PC)>;
+
+void TestInst(RISCVEmulatorTester *tester, uint64_t inst, bool has_rs2,
+              RDComputer rd_val) {
+
+  lldb::addr_t old_pc = 0x114514;
+  tester->WritePC(old_pc);
+  auto rd = DecodeRD(inst);
+  auto rs1 = DecodeRS1(inst);
+  auto rs2 = 0;
+  if (rs1)
+    tester->gpr.gpr[rs1] = 0x1919;
+
+  if (has_rs2) {
+    rs2 = DecodeRS2(inst);
+    if (rs2)
+      tester->gpr.gpr[rs2] = 0x8181;
+  }
+
+  ASSERT_TRUE(tester->DecodeAndExecute(inst, false));
+  CheckRD(tester, rd,
+          rd_val(tester->gpr.gpr[rs1], rs2 ? tester->gpr.gpr[rs2] : 0, old_pc));
+}
+
 // GEN_BRANCH_TEST(opcode, imm1, imm2, imm3):
 // It should branch for instruction `opcode imm1, imm2`
 // It should do nothing for instruction `opcode imm1, imm3`
@@ -167,30 +198,34 @@ GEN_BRANCH_TEST(BGE, -2, -3, 1)
 GEN_BRANCH_TEST(BLTU, -2, -1, 1)
 GEN_BRANCH_TEST(BGEU, -2, 1, -1)
 
-void testNothing(RISCVEmulatorTester *tester, uint32_t inst) {
-  lldb::addr_t old_pc = 0x114514;
-  tester->WritePC(old_pc);
-  tester->SetInstruction(Opcode(inst, tester->GetByteOrder()),
-                         LLDB_INVALID_ADDRESS, nullptr);
-  ASSERT_TRUE(tester->EvaluateInstruction(0));
-  bool success = false;
-  auto pc = tester->ReadPC(&success);
-  ASSERT_TRUE(success);
-  ASSERT_EQ(pc, old_pc);
-  ASSERT_TRUE(
-      tester->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC));
-  pc = tester->ReadPC(&success);
-  ASSERT_TRUE(success);
-  ASSERT_EQ(pc, old_pc + 4);
-}
-
-#define GEN_NOTHING_TEST(name, inst)                                           \
-  TEST_F(RISCVEmulatorTester, testDoNothing_##name) { testNothing(this, inst); }
+struct TestData {
+  uint32_t inst;
+  std::string name;
+  bool has_rs2;
+  RDComputer rd_val;
+};
 
-// GEN_NOTHING_TEST(name, inst):
-// It should do nothing (except increasing pc) for instruction `inst`
-GEN_NOTHING_TEST(mv, 0x01813083)   // mv a0, a5
-GEN_NOTHING_TEST(li, 0x00078513)   // li a5, 0
-GEN_NOTHING_TEST(sd, 0x02010413)   // sd s0, sp(16)
-GEN_NOTHING_TEST(lw, 0x0007879b)   // lw a5, s0(-20)
-GEN_NOTHING_TEST(addi, 0x00113423) // addi sp, sp, -16
+TEST_F(RISCVEmulatorTester, TestDecodeAndExcute) {
+
+  std::vector<TestData> 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; }},
+      {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; }},
+  };
+  for (auto i : tests) {
+    const InstrPattern *pattern = this->Decode(i.inst);
+    ASSERT_TRUE(pattern != nullptr);
+    std::string name = pattern->name;
+    ASSERT_EQ(name, i.name);
+    TestInst(this, i.inst, i.has_rs2, i.rd_val);
+  }
+}


        


More information about the lldb-commits mailing list