brintos

brintos / llvm-project-archived public Read only

0
0
Text · 80.5 KiB · 2957cb7 Raw
2061 lines · cpp
1//===-- EmulateInstructionRISCV.cpp ---------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "EmulateInstructionRISCV.h"10#include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h"11#include "Plugins/Process/Utility/lldb-riscv-register-enums.h"12#include "RISCVCInstructions.h"13#include "RISCVInstructions.h"14 15#include "lldb/Core/Address.h"16#include "lldb/Core/PluginManager.h"17#include "lldb/Interpreter/OptionValueArray.h"18#include "lldb/Interpreter/OptionValueDictionary.h"19#include "lldb/Symbol/UnwindPlan.h"20#include "lldb/Utility/ArchSpec.h"21#include "lldb/Utility/LLDBLog.h"22#include "lldb/Utility/Stream.h"23 24#include "llvm/ADT/STLExtras.h"25#include "llvm/Support/MathExtras.h"26#include <optional>27 28using namespace llvm;29using namespace lldb;30using namespace lldb_private;31 32LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionRISCV, InstructionRISCV)33 34namespace lldb_private {35 36// RISC-V General Purpose Register numbers37static constexpr uint32_t RISCV_GPR_SP = 2; // x2 is the stack pointer38static constexpr uint32_t RISCV_GPR_FP = 8; // x8 is the frame pointer39 40/// Returns all values wrapped in Optional, or std::nullopt if any of the values41/// is std::nullopt.42template <typename... Ts>43static std::optional<std::tuple<Ts...>> zipOpt(std::optional<Ts> &&...ts) {44  if ((ts.has_value() && ...))45    return std::optional<std::tuple<Ts...>>(std::make_tuple(std::move(*ts)...));46  else47    return std::nullopt;48}49 50// The funct3 is the type of compare in B<CMP> instructions.51// funct3 means "3-bits function selector", which RISC-V ISA uses as minor52// opcode. It reuses the major opcode encoding space.53constexpr uint32_t BEQ = 0b000;54constexpr uint32_t BNE = 0b001;55constexpr uint32_t BLT = 0b100;56constexpr uint32_t BGE = 0b101;57constexpr uint32_t BLTU = 0b110;58constexpr uint32_t BGEU = 0b111;59 60// used in decoder61constexpr int32_t SignExt(uint32_t imm) { return int32_t(imm); }62 63// used in executor64template <typename T>65constexpr std::enable_if_t<sizeof(T) <= 4, uint64_t> SextW(T value) {66  return uint64_t(int64_t(int32_t(value)));67}68 69// used in executor70template <typename T> constexpr uint64_t ZextD(T value) {71  return uint64_t(value);72}73 74constexpr uint32_t DecodeJImm(uint32_t inst) {75  return (uint64_t(int64_t(int32_t(inst & 0x80000000)) >> 11)) // imm[20]76         | (inst & 0xff000)                                    // imm[19:12]77         | ((inst >> 9) & 0x800)                               // imm[11]78         | ((inst >> 20) & 0x7fe);                             // imm[10:1]79}80 81constexpr uint32_t DecodeIImm(uint32_t inst) {82  return int64_t(int32_t(inst)) >> 20; // imm[11:0]83}84 85constexpr uint32_t DecodeBImm(uint32_t inst) {86  return (uint64_t(int64_t(int32_t(inst & 0x80000000)) >> 19)) // imm[12]87         | ((inst & 0x80) << 4)                                // imm[11]88         | ((inst >> 20) & 0x7e0)                              // imm[10:5]89         | ((inst >> 7) & 0x1e);                               // imm[4:1]90}91 92constexpr uint32_t DecodeSImm(uint32_t inst) {93  return (uint64_t(int64_t(int32_t(inst & 0xFE000000)) >> 20)) // imm[11:5]94         | ((inst & 0xF80) >> 7);                              // imm[4:0]95}96 97constexpr uint32_t DecodeUImm(uint32_t inst) {98  return SextW(inst & 0xFFFFF000); // imm[31:12]99}100 101static uint32_t GPREncodingToLLDB(uint32_t reg_encode) {102  if (reg_encode == 0)103    return gpr_x0_riscv;104  if (reg_encode >= 1 && reg_encode <= 31)105    return gpr_x1_riscv + reg_encode - 1;106  return LLDB_INVALID_REGNUM;107}108 109static uint32_t FPREncodingToLLDB(uint32_t reg_encode) {110  if (reg_encode <= 31)111    return fpr_f0_riscv + reg_encode;112  return LLDB_INVALID_REGNUM;113}114 115// Helper function to get register info from GPR encoding116static std::optional<RegisterInfo>117GPREncodingToRegisterInfo(EmulateInstructionRISCV &emulator,118                          uint32_t reg_encode) {119  uint32_t lldb_reg = GPREncodingToLLDB(reg_encode);120  if (lldb_reg == LLDB_INVALID_REGNUM)121    return std::nullopt;122  return emulator.GetRegisterInfo(eRegisterKindLLDB, lldb_reg);123}124 125bool Rd::Write(EmulateInstructionRISCV &emulator, uint64_t value) {126  uint32_t lldb_reg = GPREncodingToLLDB(rd);127  EmulateInstruction::Context ctx;128  ctx.type = EmulateInstruction::eContextRegisterStore;129  ctx.SetNoArgs();130  RegisterValue registerValue;131  registerValue.SetUInt64(value);132  return emulator.WriteRegister(ctx, eRegisterKindLLDB, lldb_reg,133                                registerValue);134}135 136bool Rd::WriteAPFloat(EmulateInstructionRISCV &emulator, APFloat value) {137  uint32_t lldb_reg = FPREncodingToLLDB(rd);138  EmulateInstruction::Context ctx;139  ctx.type = EmulateInstruction::eContextRegisterStore;140  ctx.SetNoArgs();141  RegisterValue registerValue;142  registerValue.SetUInt64(value.bitcastToAPInt().getZExtValue());143  return emulator.WriteRegister(ctx, eRegisterKindLLDB, lldb_reg,144                                registerValue);145}146 147std::optional<uint64_t> Rs::Read(EmulateInstructionRISCV &emulator) {148  uint32_t lldbReg = GPREncodingToLLDB(rs);149  RegisterValue value;150  return emulator.ReadRegister(eRegisterKindLLDB, lldbReg, value)151             ? std::optional<uint64_t>(value.GetAsUInt64())152             : std::nullopt;153}154 155std::optional<int32_t> Rs::ReadI32(EmulateInstructionRISCV &emulator) {156  return transformOptional(157      Read(emulator), [](uint64_t value) { return int32_t(uint32_t(value)); });158}159 160std::optional<int64_t> Rs::ReadI64(EmulateInstructionRISCV &emulator) {161  return transformOptional(Read(emulator),162                           [](uint64_t value) { return int64_t(value); });163}164 165std::optional<uint32_t> Rs::ReadU32(EmulateInstructionRISCV &emulator) {166  return transformOptional(Read(emulator),167                           [](uint64_t value) { return uint32_t(value); });168}169 170std::optional<APFloat> Rs::ReadAPFloat(EmulateInstructionRISCV &emulator,171                                       bool isDouble) {172  uint32_t lldbReg = FPREncodingToLLDB(rs);173  RegisterValue value;174  if (!emulator.ReadRegister(eRegisterKindLLDB, lldbReg, value))175    return std::nullopt;176  uint64_t bits = value.GetAsUInt64();177  APInt api(64, bits, false);178  return APFloat(isDouble ? APFloat(api.bitsToDouble())179                          : APFloat(api.bitsToFloat()));180}181 182static bool CompareB(uint64_t rs1, uint64_t rs2, uint32_t funct3) {183  switch (funct3) {184  case BEQ:185    return rs1 == rs2;186  case BNE:187    return rs1 != rs2;188  case BLT:189    return int64_t(rs1) < int64_t(rs2);190  case BGE:191    return int64_t(rs1) >= int64_t(rs2);192  case BLTU:193    return rs1 < rs2;194  case BGEU:195    return rs1 >= rs2;196  default:197    llvm_unreachable("unexpected funct3");198  }199}200 201template <typename T>202constexpr bool is_load =203    std::is_same_v<T, LB> || std::is_same_v<T, LH> || std::is_same_v<T, LW> ||204    std::is_same_v<T, LD> || std::is_same_v<T, LBU> || std::is_same_v<T, LHU> ||205    std::is_same_v<T, LWU>;206 207template <typename T>208constexpr bool is_store = std::is_same_v<T, SB> || std::is_same_v<T, SH> ||209                          std::is_same_v<T, SW> || std::is_same_v<T, SD>;210 211template <typename T>212constexpr bool is_amo_add =213    std::is_same_v<T, AMOADD_W> || std::is_same_v<T, AMOADD_D>;214 215template <typename T>216constexpr bool is_amo_bit_op =217    std::is_same_v<T, AMOXOR_W> || std::is_same_v<T, AMOXOR_D> ||218    std::is_same_v<T, AMOAND_W> || std::is_same_v<T, AMOAND_D> ||219    std::is_same_v<T, AMOOR_W> || std::is_same_v<T, AMOOR_D>;220 221template <typename T>222constexpr bool is_amo_swap =223    std::is_same_v<T, AMOSWAP_W> || std::is_same_v<T, AMOSWAP_D>;224 225template <typename T>226constexpr bool is_amo_cmp =227    std::is_same_v<T, AMOMIN_W> || std::is_same_v<T, AMOMIN_D> ||228    std::is_same_v<T, AMOMAX_W> || std::is_same_v<T, AMOMAX_D> ||229    std::is_same_v<T, AMOMINU_W> || std::is_same_v<T, AMOMINU_D> ||230    std::is_same_v<T, AMOMAXU_W> || std::is_same_v<T, AMOMAXU_D>;231 232template <typename I>233static std::enable_if_t<is_load<I> || is_store<I>, std::optional<uint64_t>>234LoadStoreAddr(EmulateInstructionRISCV &emulator, I inst) {235  return transformOptional(inst.rs1.Read(emulator), [&](uint64_t rs1) {236    return rs1 + uint64_t(SignExt(inst.imm));237  });238}239 240// Read T from memory, then load its sign-extended value m_emu to register.241template <typename I, typename T, typename E>242static std::enable_if_t<is_load<I>, bool>243Load(EmulateInstructionRISCV &emulator, I inst, uint64_t (*extend)(E)) {244  auto addr = LoadStoreAddr(emulator, inst);245  if (!addr)246    return false;247 248  // Set up context for the load operation, similar to ARM64.249  EmulateInstructionRISCV::Context context;250 251  // Get register info for base register252  std::optional<RegisterInfo> reg_info_rs1 =253      GPREncodingToRegisterInfo(emulator, inst.rs1.rs);254 255  if (!reg_info_rs1)256    return false;257 258  // Set context type based on whether this is a stack-based load.259  if (inst.rs1.rs == RISCV_GPR_SP)260    context.type = EmulateInstruction::eContextPopRegisterOffStack;261  else262    context.type = EmulateInstruction::eContextRegisterLoad;263 264  // Set the context address information265  context.SetAddress(*addr);266 267  // Read from memory with context and write to register.268  bool success = false;269  uint64_t value =270      emulator.ReadMemoryUnsigned(context, *addr, sizeof(T), 0, &success);271  if (!success)272    return false;273 274  return inst.rd.Write(emulator, extend(E(T(value))));275}276 277template <typename I, typename T>278static std::enable_if_t<is_store<I>, bool>279Store(EmulateInstructionRISCV &emulator, I inst) {280  auto addr = LoadStoreAddr(emulator, inst);281  if (!addr)282    return false;283 284  // Set up context for the store operation, similar to ARM64.285  EmulateInstructionRISCV::Context context;286 287  // Get register info for source and base registers.288  std::optional<RegisterInfo> reg_info_rs1 =289      GPREncodingToRegisterInfo(emulator, inst.rs1.rs);290  std::optional<RegisterInfo> reg_info_rs2 =291      GPREncodingToRegisterInfo(emulator, inst.rs2.rs);292 293  if (!reg_info_rs1 || !reg_info_rs2)294    return false;295 296  // Set context type based on whether this is a stack-based store.297  if (inst.rs1.rs == RISCV_GPR_SP)298    context.type = EmulateInstruction::eContextPushRegisterOnStack;299  else300    context.type = EmulateInstruction::eContextRegisterStore;301 302  // Set the context to show which register is being stored to which base303  // register + offset.304  context.SetRegisterToRegisterPlusOffset(*reg_info_rs2, *reg_info_rs1,305                                          SignExt(inst.imm));306 307  return transformOptional(inst.rs2.Read(emulator),308                           [&](uint64_t rs2) {309                             return emulator.WriteMemoryUnsigned(310                                 context, *addr, rs2, sizeof(T));311                           })312      .value_or(false);313}314 315template <typename I>316static std::enable_if_t<is_amo_add<I> || is_amo_bit_op<I> || is_amo_swap<I> ||317                            is_amo_cmp<I>,318                        std::optional<uint64_t>>319AtomicAddr(EmulateInstructionRISCV &emulator, I inst, unsigned int align) {320  return transformOptional(inst.rs1.Read(emulator),321                           [&](uint64_t rs1) {322                             return rs1 % align == 0323                                        ? std::optional<uint64_t>(rs1)324                                        : std::nullopt;325                           })326      .value_or(std::nullopt);327}328 329template <typename I, typename T>330static std::enable_if_t<is_amo_swap<I>, bool>331AtomicSwap(EmulateInstructionRISCV &emulator, I inst, int align,332           uint64_t (*extend)(T)) {333  auto addr = AtomicAddr(emulator, inst, align);334  if (!addr)335    return false;336  return transformOptional(337             zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)),338             [&](auto &&tup) {339               auto [tmp, rs2] = tup;340               return emulator.WriteMem<T>(*addr, T(rs2)) &&341                      inst.rd.Write(emulator, extend(tmp));342             })343      .value_or(false);344}345 346template <typename I, typename T>347static std::enable_if_t<is_amo_add<I>, bool>348AtomicADD(EmulateInstructionRISCV &emulator, I inst, int align,349          uint64_t (*extend)(T)) {350  auto addr = AtomicAddr(emulator, inst, align);351  if (!addr)352    return false;353  return transformOptional(354             zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)),355             [&](auto &&tup) {356               auto [tmp, rs2] = tup;357               return emulator.WriteMem<T>(*addr, T(tmp + rs2)) &&358                      inst.rd.Write(emulator, extend(tmp));359             })360      .value_or(false);361}362 363template <typename I, typename T>364static std::enable_if_t<is_amo_bit_op<I>, bool>365AtomicBitOperate(EmulateInstructionRISCV &emulator, I inst, int align,366                 uint64_t (*extend)(T), T (*operate)(T, T)) {367  auto addr = AtomicAddr(emulator, inst, align);368  if (!addr)369    return false;370  return transformOptional(371             zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)),372             [&](auto &&tup) {373               auto [value, rs2] = tup;374               return emulator.WriteMem<T>(*addr, operate(value, T(rs2))) &&375                      inst.rd.Write(emulator, extend(value));376             })377      .value_or(false);378}379 380template <typename I, typename T>381static std::enable_if_t<is_amo_cmp<I>, bool>382AtomicCmp(EmulateInstructionRISCV &emulator, I inst, int align,383          uint64_t (*extend)(T), T (*cmp)(T, T)) {384  auto addr = AtomicAddr(emulator, inst, align);385  if (!addr)386    return false;387  return transformOptional(388             zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)),389             [&](auto &&tup) {390               auto [value, rs2] = tup;391               return emulator.WriteMem<T>(*addr, cmp(value, T(rs2))) &&392                      inst.rd.Write(emulator, extend(value));393             })394      .value_or(false);395}396 397bool AtomicSequence(EmulateInstructionRISCV &emulator) {398  // The atomic sequence is always 4 instructions long:399  // example:400  //   110cc:	100427af          	lr.w	a5,(s0)401  //   110d0:	00079663          	bnez	a5,110dc402  //   110d4:	1ce426af          	sc.w.aq	a3,a4,(s0)403  //   110d8:	fe069ae3          	bnez	a3,110cc404  //   110dc:   ........          	<next instruction>405  const auto pc = emulator.ReadPC();406  if (!pc)407    return false;408  auto current_pc = *pc;409  const auto entry_pc = current_pc;410 411  // The first instruction should be LR.W or LR.D412  auto inst = emulator.ReadInstructionAt(current_pc);413  if (!inst || (!std::holds_alternative<LR_W>(inst->decoded) &&414                !std::holds_alternative<LR_D>(inst->decoded)))415    return false;416 417  // The second instruction should be BNE to exit address418  inst = emulator.ReadInstructionAt(current_pc += 4);419  if (!inst || !std::holds_alternative<B>(inst->decoded))420    return false;421  auto bne_exit = std::get<B>(inst->decoded);422  if (bne_exit.funct3 != BNE)423    return false;424  // save the exit address to check later425  const auto exit_pc = current_pc + SextW(bne_exit.imm);426 427  // The third instruction should be SC.W or SC.D428  inst = emulator.ReadInstructionAt(current_pc += 4);429  if (!inst || (!std::holds_alternative<SC_W>(inst->decoded) &&430                !std::holds_alternative<SC_D>(inst->decoded)))431    return false;432 433  // The fourth instruction should be BNE to entry address434  inst = emulator.ReadInstructionAt(current_pc += 4);435  if (!inst || !std::holds_alternative<B>(inst->decoded))436    return false;437  auto bne_start = std::get<B>(inst->decoded);438  if (bne_start.funct3 != BNE)439    return false;440  if (entry_pc != current_pc + SextW(bne_start.imm))441    return false;442 443  current_pc += 4;444  // check the exit address and jump to it445  return exit_pc == current_pc && emulator.WritePC(current_pc);446}447 448template <typename T> static RISCVInst DecodeUType(uint32_t inst) {449  return T{Rd{DecodeRD(inst)}, DecodeUImm(inst)};450}451 452template <typename T> static RISCVInst DecodeJType(uint32_t inst) {453  return T{Rd{DecodeRD(inst)}, DecodeJImm(inst)};454}455 456template <typename T> static RISCVInst DecodeIType(uint32_t inst) {457  return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeIImm(inst)};458}459 460template <typename T> static RISCVInst DecodeBType(uint32_t inst) {461  return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeBImm(inst),462           DecodeFunct3(inst)};463}464 465template <typename T> static RISCVInst DecodeSType(uint32_t inst) {466  return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeSImm(inst)};467}468 469template <typename T> static RISCVInst DecodeRType(uint32_t inst) {470  return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}};471}472 473template <typename T> static RISCVInst DecodeRShamtType(uint32_t inst) {474  return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeRS2(inst)};475}476 477template <typename T> static RISCVInst DecodeRRS1Type(uint32_t inst) {478  return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}};479}480 481template <typename T> static RISCVInst DecodeR4Type(uint32_t inst) {482  return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)},483           Rs{DecodeRS3(inst)}, DecodeRM(inst)};484}485 486static const InstrPattern PATTERNS[] = {487    // RV32I & RV64I (The base integer ISA) //488    {"LUI", 0x7F, 0x37, DecodeUType<LUI>},489    {"AUIPC", 0x7F, 0x17, DecodeUType<AUIPC>},490    {"JAL", 0x7F, 0x6F, DecodeJType<JAL>},491    {"JALR", 0x707F, 0x67, DecodeIType<JALR>},492    {"B", 0x7F, 0x63, DecodeBType<B>},493    {"LB", 0x707F, 0x3, DecodeIType<LB>},494    {"LH", 0x707F, 0x1003, DecodeIType<LH>},495    {"LW", 0x707F, 0x2003, DecodeIType<LW>},496    {"LBU", 0x707F, 0x4003, DecodeIType<LBU>},497    {"LHU", 0x707F, 0x5003, DecodeIType<LHU>},498    {"SB", 0x707F, 0x23, DecodeSType<SB>},499    {"SH", 0x707F, 0x1023, DecodeSType<SH>},500    {"SW", 0x707F, 0x2023, DecodeSType<SW>},501    {"ADDI", 0x707F, 0x13, DecodeIType<ADDI>},502    {"SLTI", 0x707F, 0x2013, DecodeIType<SLTI>},503    {"SLTIU", 0x707F, 0x3013, DecodeIType<SLTIU>},504    {"XORI", 0x707F, 0x4013, DecodeIType<XORI>},505    {"ORI", 0x707F, 0x6013, DecodeIType<ORI>},506    {"ANDI", 0x707F, 0x7013, DecodeIType<ANDI>},507    {"SLLI", 0xF800707F, 0x1013, DecodeRShamtType<SLLI>},508    {"SRLI", 0xF800707F, 0x5013, DecodeRShamtType<SRLI>},509    {"SRAI", 0xF800707F, 0x40005013, DecodeRShamtType<SRAI>},510    {"ADD", 0xFE00707F, 0x33, DecodeRType<ADD>},511    {"SUB", 0xFE00707F, 0x40000033, DecodeRType<SUB>},512    {"SLL", 0xFE00707F, 0x1033, DecodeRType<SLL>},513    {"SLT", 0xFE00707F, 0x2033, DecodeRType<SLT>},514    {"SLTU", 0xFE00707F, 0x3033, DecodeRType<SLTU>},515    {"XOR", 0xFE00707F, 0x4033, DecodeRType<XOR>},516    {"SRL", 0xFE00707F, 0x5033, DecodeRType<SRL>},517    {"SRA", 0xFE00707F, 0x40005033, DecodeRType<SRA>},518    {"OR", 0xFE00707F, 0x6033, DecodeRType<OR>},519    {"AND", 0xFE00707F, 0x7033, DecodeRType<AND>},520    {"LWU", 0x707F, 0x6003, DecodeIType<LWU>},521    {"LD", 0x707F, 0x3003, DecodeIType<LD>},522    {"SD", 0x707F, 0x3023, DecodeSType<SD>},523    {"ADDIW", 0x707F, 0x1B, DecodeIType<ADDIW>},524    {"SLLIW", 0xFE00707F, 0x101B, DecodeRShamtType<SLLIW>},525    {"SRLIW", 0xFE00707F, 0x501B, DecodeRShamtType<SRLIW>},526    {"SRAIW", 0xFE00707F, 0x4000501B, DecodeRShamtType<SRAIW>},527    {"ADDW", 0xFE00707F, 0x3B, DecodeRType<ADDW>},528    {"SUBW", 0xFE00707F, 0x4000003B, DecodeRType<SUBW>},529    {"SLLW", 0xFE00707F, 0x103B, DecodeRType<SLLW>},530    {"SRLW", 0xFE00707F, 0x503B, DecodeRType<SRLW>},531    {"SRAW", 0xFE00707F, 0x4000503B, DecodeRType<SRAW>},532 533    // RV32M & RV64M (The integer multiplication and division extension) //534    {"MUL", 0xFE00707F, 0x2000033, DecodeRType<MUL>},535    {"MULH", 0xFE00707F, 0x2001033, DecodeRType<MULH>},536    {"MULHSU", 0xFE00707F, 0x2002033, DecodeRType<MULHSU>},537    {"MULHU", 0xFE00707F, 0x2003033, DecodeRType<MULHU>},538    {"DIV", 0xFE00707F, 0x2004033, DecodeRType<DIV>},539    {"DIVU", 0xFE00707F, 0x2005033, DecodeRType<DIVU>},540    {"REM", 0xFE00707F, 0x2006033, DecodeRType<REM>},541    {"REMU", 0xFE00707F, 0x2007033, DecodeRType<REMU>},542    {"MULW", 0xFE00707F, 0x200003B, DecodeRType<MULW>},543    {"DIVW", 0xFE00707F, 0x200403B, DecodeRType<DIVW>},544    {"DIVUW", 0xFE00707F, 0x200503B, DecodeRType<DIVUW>},545    {"REMW", 0xFE00707F, 0x200603B, DecodeRType<REMW>},546    {"REMUW", 0xFE00707F, 0x200703B, DecodeRType<REMUW>},547 548    // RV32A & RV64A (The standard atomic instruction extension) //549    {"LR_W", 0xF9F0707F, 0x1000202F, DecodeRRS1Type<LR_W>},550    {"LR_D", 0xF9F0707F, 0x1000302F, DecodeRRS1Type<LR_D>},551    {"SC_W", 0xF800707F, 0x1800202F, DecodeRType<SC_W>},552    {"SC_D", 0xF800707F, 0x1800302F, DecodeRType<SC_D>},553    {"AMOSWAP_W", 0xF800707F, 0x800202F, DecodeRType<AMOSWAP_W>},554    {"AMOADD_W", 0xF800707F, 0x202F, DecodeRType<AMOADD_W>},555    {"AMOXOR_W", 0xF800707F, 0x2000202F, DecodeRType<AMOXOR_W>},556    {"AMOAND_W", 0xF800707F, 0x6000202F, DecodeRType<AMOAND_W>},557    {"AMOOR_W", 0xF800707F, 0x4000202F, DecodeRType<AMOOR_W>},558    {"AMOMIN_W", 0xF800707F, 0x8000202F, DecodeRType<AMOMIN_W>},559    {"AMOMAX_W", 0xF800707F, 0xA000202F, DecodeRType<AMOMAX_W>},560    {"AMOMINU_W", 0xF800707F, 0xC000202F, DecodeRType<AMOMINU_W>},561    {"AMOMAXU_W", 0xF800707F, 0xE000202F, DecodeRType<AMOMAXU_W>},562    {"AMOSWAP_D", 0xF800707F, 0x800302F, DecodeRType<AMOSWAP_D>},563    {"AMOADD_D", 0xF800707F, 0x302F, DecodeRType<AMOADD_D>},564    {"AMOXOR_D", 0xF800707F, 0x2000302F, DecodeRType<AMOXOR_D>},565    {"AMOAND_D", 0xF800707F, 0x6000302F, DecodeRType<AMOAND_D>},566    {"AMOOR_D", 0xF800707F, 0x4000302F, DecodeRType<AMOOR_D>},567    {"AMOMIN_D", 0xF800707F, 0x8000302F, DecodeRType<AMOMIN_D>},568    {"AMOMAX_D", 0xF800707F, 0xA000302F, DecodeRType<AMOMAX_D>},569    {"AMOMINU_D", 0xF800707F, 0xC000302F, DecodeRType<AMOMINU_D>},570    {"AMOMAXU_D", 0xF800707F, 0xE000302F, DecodeRType<AMOMAXU_D>},571 572    // RVC (Compressed Instructions) //573    {"C_LWSP", 0xE003, 0x4002, DecodeC_LWSP},574    {"C_LDSP", 0xE003, 0x6002, DecodeC_LDSP, RV64 | RV128},575    {"C_SWSP", 0xE003, 0xC002, DecodeC_SWSP},576    {"C_SDSP", 0xE003, 0xE002, DecodeC_SDSP, RV64 | RV128},577    {"C_LW", 0xE003, 0x4000, DecodeC_LW},578    {"C_LD", 0xE003, 0x6000, DecodeC_LD, RV64 | RV128},579    {"C_SW", 0xE003, 0xC000, DecodeC_SW},580    {"C_SD", 0xE003, 0xE000, DecodeC_SD, RV64 | RV128},581    {"C_J", 0xE003, 0xA001, DecodeC_J},582    {"C_JR", 0xF07F, 0x8002, DecodeC_JR},583    {"C_JALR", 0xF07F, 0x9002, DecodeC_JALR},584    {"C_BNEZ", 0xE003, 0xE001, DecodeC_BNEZ},585    {"C_BEQZ", 0xE003, 0xC001, DecodeC_BEQZ},586    {"C_LI", 0xE003, 0x4001, DecodeC_LI},587    {"C_LUI_ADDI16SP", 0xE003, 0x6001, DecodeC_LUI_ADDI16SP},588    {"C_ADDI", 0xE003, 0x1, DecodeC_ADDI},589    {"C_ADDIW", 0xE003, 0x2001, DecodeC_ADDIW, RV64 | RV128},590    {"C_ADDI4SPN", 0xE003, 0x0, DecodeC_ADDI4SPN},591    {"C_SLLI", 0xE003, 0x2, DecodeC_SLLI, RV64 | RV128},592    {"C_SRLI", 0xEC03, 0x8001, DecodeC_SRLI, RV64 | RV128},593    {"C_SRAI", 0xEC03, 0x8401, DecodeC_SRAI, RV64 | RV128},594    {"C_ANDI", 0xEC03, 0x8801, DecodeC_ANDI},595    {"C_MV", 0xF003, 0x8002, DecodeC_MV},596    {"C_ADD", 0xF003, 0x9002, DecodeC_ADD},597    {"C_AND", 0xFC63, 0x8C61, DecodeC_AND},598    {"C_OR", 0xFC63, 0x8C41, DecodeC_OR},599    {"C_XOR", 0xFC63, 0x8C21, DecodeC_XOR},600    {"C_SUB", 0xFC63, 0x8C01, DecodeC_SUB},601    {"C_SUBW", 0xFC63, 0x9C01, DecodeC_SUBW, RV64 | RV128},602    {"C_ADDW", 0xFC63, 0x9C21, DecodeC_ADDW, RV64 | RV128},603    // RV32FC //604    {"FLW", 0xE003, 0x6000, DecodeC_FLW, RV32},605    {"FSW", 0xE003, 0xE000, DecodeC_FSW, RV32},606    {"FLWSP", 0xE003, 0x6002, DecodeC_FLWSP, RV32},607    {"FSWSP", 0xE003, 0xE002, DecodeC_FSWSP, RV32},608    // RVDC //609    {"FLDSP", 0xE003, 0x2002, DecodeC_FLDSP, RV32 | RV64},610    {"FSDSP", 0xE003, 0xA002, DecodeC_FSDSP, RV32 | RV64},611    {"FLD", 0xE003, 0x2000, DecodeC_FLD, RV32 | RV64},612    {"FSD", 0xE003, 0xA000, DecodeC_FSD, RV32 | RV64},613 614    // RV32F (Extension for Single-Precision Floating-Point) //615    {"FLW", 0x707F, 0x2007, DecodeIType<FLW>},616    {"FSW", 0x707F, 0x2027, DecodeSType<FSW>},617    {"FMADD_S", 0x600007F, 0x43, DecodeR4Type<FMADD_S>},618    {"FMSUB_S", 0x600007F, 0x47, DecodeR4Type<FMSUB_S>},619    {"FNMSUB_S", 0x600007F, 0x4B, DecodeR4Type<FNMSUB_S>},620    {"FNMADD_S", 0x600007F, 0x4F, DecodeR4Type<FNMADD_S>},621    {"FADD_S", 0xFE00007F, 0x53, DecodeRType<FADD_S>},622    {"FSUB_S", 0xFE00007F, 0x8000053, DecodeRType<FSUB_S>},623    {"FMUL_S", 0xFE00007F, 0x10000053, DecodeRType<FMUL_S>},624    {"FDIV_S", 0xFE00007F, 0x18000053, DecodeRType<FDIV_S>},625    {"FSQRT_S", 0xFFF0007F, 0x58000053, DecodeIType<FSQRT_S>},626    {"FSGNJ_S", 0xFE00707F, 0x20000053, DecodeRType<FSGNJ_S>},627    {"FSGNJN_S", 0xFE00707F, 0x20001053, DecodeRType<FSGNJN_S>},628    {"FSGNJX_S", 0xFE00707F, 0x20002053, DecodeRType<FSGNJX_S>},629    {"FMIN_S", 0xFE00707F, 0x28000053, DecodeRType<FMIN_S>},630    {"FMAX_S", 0xFE00707F, 0x28001053, DecodeRType<FMAX_S>},631    {"FCVT_W_S", 0xFFF0007F, 0xC0000053, DecodeIType<FCVT_W_S>},632    {"FCVT_WU_S", 0xFFF0007F, 0xC0100053, DecodeIType<FCVT_WU_S>},633    {"FMV_X_W", 0xFFF0707F, 0xE0000053, DecodeIType<FMV_X_W>},634    {"FEQ_S", 0xFE00707F, 0xA0002053, DecodeRType<FEQ_S>},635    {"FLT_S", 0xFE00707F, 0xA0001053, DecodeRType<FLT_S>},636    {"FLE_S", 0xFE00707F, 0xA0000053, DecodeRType<FLE_S>},637    {"FCLASS_S", 0xFFF0707F, 0xE0001053, DecodeIType<FCLASS_S>},638    {"FCVT_S_W", 0xFFF0007F, 0xD0000053, DecodeIType<FCVT_S_W>},639    {"FCVT_S_WU", 0xFFF0007F, 0xD0100053, DecodeIType<FCVT_S_WU>},640    {"FMV_W_X", 0xFFF0707F, 0xF0000053, DecodeIType<FMV_W_X>},641 642    // RV64F (Extension for Single-Precision Floating-Point) //643    {"FCVT_L_S", 0xFFF0007F, 0xC0200053, DecodeIType<FCVT_L_S>},644    {"FCVT_LU_S", 0xFFF0007F, 0xC0300053, DecodeIType<FCVT_LU_S>},645    {"FCVT_S_L", 0xFFF0007F, 0xD0200053, DecodeIType<FCVT_S_L>},646    {"FCVT_S_LU", 0xFFF0007F, 0xD0300053, DecodeIType<FCVT_S_LU>},647 648    // RV32D (Extension for Double-Precision Floating-Point) //649    {"FLD", 0x707F, 0x3007, DecodeIType<FLD>},650    {"FSD", 0x707F, 0x3027, DecodeSType<FSD>},651    {"FMADD_D", 0x600007F, 0x2000043, DecodeR4Type<FMADD_D>},652    {"FMSUB_D", 0x600007F, 0x2000047, DecodeR4Type<FMSUB_D>},653    {"FNMSUB_D", 0x600007F, 0x200004B, DecodeR4Type<FNMSUB_D>},654    {"FNMADD_D", 0x600007F, 0x200004F, DecodeR4Type<FNMADD_D>},655    {"FADD_D", 0xFE00007F, 0x2000053, DecodeRType<FADD_D>},656    {"FSUB_D", 0xFE00007F, 0xA000053, DecodeRType<FSUB_D>},657    {"FMUL_D", 0xFE00007F, 0x12000053, DecodeRType<FMUL_D>},658    {"FDIV_D", 0xFE00007F, 0x1A000053, DecodeRType<FDIV_D>},659    {"FSQRT_D", 0xFFF0007F, 0x5A000053, DecodeIType<FSQRT_D>},660    {"FSGNJ_D", 0xFE00707F, 0x22000053, DecodeRType<FSGNJ_D>},661    {"FSGNJN_D", 0xFE00707F, 0x22001053, DecodeRType<FSGNJN_D>},662    {"FSGNJX_D", 0xFE00707F, 0x22002053, DecodeRType<FSGNJX_D>},663    {"FMIN_D", 0xFE00707F, 0x2A000053, DecodeRType<FMIN_D>},664    {"FMAX_D", 0xFE00707F, 0x2A001053, DecodeRType<FMAX_D>},665    {"FCVT_S_D", 0xFFF0007F, 0x40100053, DecodeIType<FCVT_S_D>},666    {"FCVT_D_S", 0xFFF0007F, 0x42000053, DecodeIType<FCVT_D_S>},667    {"FEQ_D", 0xFE00707F, 0xA2002053, DecodeRType<FEQ_D>},668    {"FLT_D", 0xFE00707F, 0xA2001053, DecodeRType<FLT_D>},669    {"FLE_D", 0xFE00707F, 0xA2000053, DecodeRType<FLE_D>},670    {"FCLASS_D", 0xFFF0707F, 0xE2001053, DecodeIType<FCLASS_D>},671    {"FCVT_W_D", 0xFFF0007F, 0xC2000053, DecodeIType<FCVT_W_D>},672    {"FCVT_WU_D", 0xFFF0007F, 0xC2100053, DecodeIType<FCVT_WU_D>},673    {"FCVT_D_W", 0xFFF0007F, 0xD2000053, DecodeIType<FCVT_D_W>},674    {"FCVT_D_WU", 0xFFF0007F, 0xD2100053, DecodeIType<FCVT_D_WU>},675 676    // RV64D (Extension for Double-Precision Floating-Point) //677    {"FCVT_L_D", 0xFFF0007F, 0xC2200053, DecodeIType<FCVT_L_D>},678    {"FCVT_LU_D", 0xFFF0007F, 0xC2300053, DecodeIType<FCVT_LU_D>},679    {"FMV_X_D", 0xFFF0707F, 0xE2000053, DecodeIType<FMV_X_D>},680    {"FCVT_D_L", 0xFFF0007F, 0xD2200053, DecodeIType<FCVT_D_L>},681    {"FCVT_D_LU", 0xFFF0007F, 0xD2300053, DecodeIType<FCVT_D_LU>},682    {"FMV_D_X", 0xFFF0707F, 0xF2000053, DecodeIType<FMV_D_X>},683};684 685std::optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {686  Log *log = GetLog(LLDBLog::Unwind);687 688  uint16_t try_rvc = uint16_t(inst & 0x0000ffff);689  uint8_t inst_type = RV64;690 691  // Try to get size of RISCV instruction.692  // 1.2 Instruction Length Encoding693  bool is_16b = (inst & 0b11) != 0b11;694  bool is_32b = (inst & 0x1f) != 0x1f;695  bool is_48b = (inst & 0x3f) != 0x1f;696  bool is_64b = (inst & 0x7f) != 0x3f;697  if (is_16b)698    m_last_size = 2;699  else if (is_32b)700    m_last_size = 4;701  else if (is_48b)702    m_last_size = 6;703  else if (is_64b)704    m_last_size = 8;705  else706    // Not Valid707    m_last_size = std::nullopt;708 709  // if we have ArchSpec::eCore_riscv128 in the future,710  // we also need to check it here711  if (m_arch.GetCore() == ArchSpec::eCore_riscv32)712    inst_type = RV32;713 714  for (const InstrPattern &pat : PATTERNS) {715    if ((inst & pat.type_mask) == pat.eigen &&716        (inst_type & pat.inst_type) != 0) {717      LLDB_LOGF(log,718                "EmulateInstructionRISCV::%s: inst(%x at %" PRIx64719                ") was decoded to %s",720                __FUNCTION__, inst, m_addr, pat.name);721      auto decoded = is_16b ? pat.decode(try_rvc) : pat.decode(inst);722      return DecodeResult{decoded, inst, is_16b, pat};723    }724  }725  LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(0x%x) was unsupported",726            __FUNCTION__, inst);727  return std::nullopt;728}729 730class Executor {731  EmulateInstructionRISCV &m_emu;732  bool m_ignore_cond;733  bool m_is_rvc;734 735public:736  // also used in EvaluateInstruction()737  static uint64_t size(bool is_rvc) { return is_rvc ? 2 : 4; }738 739private:740  uint64_t delta() { return size(m_is_rvc); }741 742public:743  Executor(EmulateInstructionRISCV &emulator, bool ignoreCond, bool is_rvc)744      : m_emu(emulator), m_ignore_cond(ignoreCond), m_is_rvc(is_rvc) {}745 746  bool operator()(LUI inst) { return inst.rd.Write(m_emu, SignExt(inst.imm)); }747  bool operator()(AUIPC inst) {748    return transformOptional(m_emu.ReadPC(),749                             [&](uint64_t pc) {750                               return inst.rd.Write(m_emu,751                                                    SignExt(inst.imm) + pc);752                             })753        .value_or(false);754  }755  bool operator()(JAL inst) {756    return transformOptional(m_emu.ReadPC(),757                             [&](uint64_t pc) {758                               return inst.rd.Write(m_emu, pc + delta()) &&759                                      m_emu.WritePC(SignExt(inst.imm) + pc);760                             })761        .value_or(false);762  }763  bool operator()(JALR inst) {764    return transformOptional(zipOpt(m_emu.ReadPC(), inst.rs1.Read(m_emu)),765                             [&](auto &&tup) {766                               auto [pc, rs1] = tup;767                               return inst.rd.Write(m_emu, pc + delta()) &&768                                      m_emu.WritePC((SignExt(inst.imm) + rs1) &769                                                    ~1);770                             })771        .value_or(false);772  }773  bool operator()(B inst) {774    return transformOptional(zipOpt(m_emu.ReadPC(), inst.rs1.Read(m_emu),775                                    inst.rs2.Read(m_emu)),776                             [&](auto &&tup) {777                               auto [pc, rs1, rs2] = tup;778                               if (m_ignore_cond ||779                                   CompareB(rs1, rs2, inst.funct3))780                                 return m_emu.WritePC(SignExt(inst.imm) + pc);781                               return true;782                             })783        .value_or(false);784  }785  bool operator()(LB inst) {786    return Load<LB, uint8_t, int8_t>(m_emu, inst, SextW);787  }788  bool operator()(LH inst) {789    return Load<LH, uint16_t, int16_t>(m_emu, inst, SextW);790  }791  bool operator()(LW inst) {792    return Load<LW, uint32_t, int32_t>(m_emu, inst, SextW);793  }794  bool operator()(LBU inst) {795    return Load<LBU, uint8_t, uint8_t>(m_emu, inst, ZextD);796  }797  bool operator()(LHU inst) {798    return Load<LHU, uint16_t, uint16_t>(m_emu, inst, ZextD);799  }800  bool operator()(SB inst) { return Store<SB, uint8_t>(m_emu, inst); }801  bool operator()(SH inst) { return Store<SH, uint16_t>(m_emu, inst); }802  bool operator()(SW inst) { return Store<SW, uint32_t>(m_emu, inst); }803  bool operator()(ADDI inst) {804    return transformOptional(805               inst.rs1.ReadI64(m_emu),806               [&](int64_t rs1) {807                 uint64_t result = rs1 + uint64_t(SignExt(inst.imm));808                 // Check if this is a stack pointer adjustment.809                 if (inst.rd.rd == RISCV_GPR_SP &&810                     inst.rs1.rs == RISCV_GPR_SP) {811                   EmulateInstruction::Context context;812                   context.type =813                       EmulateInstruction::eContextAdjustStackPointer;814                   context.SetImmediateSigned(SignExt(inst.imm));815                   uint32_t sp_lldb_reg = GPREncodingToLLDB(RISCV_GPR_SP);816                   RegisterValue registerValue;817                   registerValue.SetUInt64(result);818                   return m_emu.WriteRegister(context, eRegisterKindLLDB,819                                              sp_lldb_reg, registerValue);820                 }821                 // Check if this is setting up the frame pointer.822                 // addi fp, sp, imm -> fp = sp + imm (frame pointer setup).823                 if (inst.rd.rd == RISCV_GPR_FP &&824                     inst.rs1.rs == RISCV_GPR_SP) {825                   EmulateInstruction::Context context;826                   context.type = EmulateInstruction::eContextSetFramePointer;827                   auto sp_reg_info = m_emu.GetRegisterInfo(828                       eRegisterKindLLDB, GPREncodingToLLDB(RISCV_GPR_SP));829                   if (sp_reg_info) {830                     context.SetRegisterPlusOffset(*sp_reg_info,831                                                   SignExt(inst.imm));832                   }833                   uint32_t fp_lldb_reg = GPREncodingToLLDB(RISCV_GPR_FP);834                   RegisterValue registerValue;835                   registerValue.SetUInt64(result);836                   return m_emu.WriteRegister(context, eRegisterKindLLDB,837                                              fp_lldb_reg, registerValue);838                 }839                 // Regular ADDI instruction.840                 return inst.rd.Write(m_emu, result);841               })842        .value_or(false);843  }844  bool operator()(SLTI inst) {845    return transformOptional(inst.rs1.ReadI64(m_emu),846                             [&](int64_t rs1) {847                               return inst.rd.Write(848                                   m_emu, rs1 < int64_t(SignExt(inst.imm)));849                             })850        .value_or(false);851  }852  bool operator()(SLTIU inst) {853    return transformOptional(inst.rs1.Read(m_emu),854                             [&](uint64_t rs1) {855                               return inst.rd.Write(856                                   m_emu, rs1 < uint64_t(SignExt(inst.imm)));857                             })858        .value_or(false);859  }860  bool operator()(XORI inst) {861    return transformOptional(inst.rs1.Read(m_emu),862                             [&](uint64_t rs1) {863                               return inst.rd.Write(864                                   m_emu, rs1 ^ uint64_t(SignExt(inst.imm)));865                             })866        .value_or(false);867  }868  bool operator()(ORI inst) {869    return transformOptional(inst.rs1.Read(m_emu),870                             [&](uint64_t rs1) {871                               return inst.rd.Write(872                                   m_emu, rs1 | uint64_t(SignExt(inst.imm)));873                             })874        .value_or(false);875  }876  bool operator()(ANDI inst) {877    return transformOptional(inst.rs1.Read(m_emu),878                             [&](uint64_t rs1) {879                               return inst.rd.Write(880                                   m_emu, rs1 & uint64_t(SignExt(inst.imm)));881                             })882        .value_or(false);883  }884  bool operator()(ADD inst) {885    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),886                             [&](auto &&tup) {887                               auto [rs1, rs2] = tup;888                               return inst.rd.Write(m_emu, rs1 + rs2);889                             })890        .value_or(false);891  }892  bool operator()(SUB inst) {893    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),894                             [&](auto &&tup) {895                               auto [rs1, rs2] = tup;896                               return inst.rd.Write(m_emu, rs1 - rs2);897                             })898        .value_or(false);899  }900  bool operator()(SLL inst) {901    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),902                             [&](auto &&tup) {903                               auto [rs1, rs2] = tup;904                               return inst.rd.Write(m_emu,905                                                    rs1 << (rs2 & 0b111111));906                             })907        .value_or(false);908  }909  bool operator()(SLT inst) {910    return transformOptional(911               zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)),912               [&](auto &&tup) {913                 auto [rs1, rs2] = tup;914                 return inst.rd.Write(m_emu, rs1 < rs2);915               })916        .value_or(false);917  }918  bool operator()(SLTU inst) {919    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),920                             [&](auto &&tup) {921                               auto [rs1, rs2] = tup;922                               return inst.rd.Write(m_emu, rs1 < rs2);923                             })924        .value_or(false);925  }926  bool operator()(XOR inst) {927    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),928                             [&](auto &&tup) {929                               auto [rs1, rs2] = tup;930                               return inst.rd.Write(m_emu, rs1 ^ rs2);931                             })932        .value_or(false);933  }934  bool operator()(SRL inst) {935    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),936                             [&](auto &&tup) {937                               auto [rs1, rs2] = tup;938                               return inst.rd.Write(m_emu,939                                                    rs1 >> (rs2 & 0b111111));940                             })941        .value_or(false);942  }943  bool operator()(SRA inst) {944    return transformOptional(945               zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.Read(m_emu)),946               [&](auto &&tup) {947                 auto [rs1, rs2] = tup;948                 return inst.rd.Write(m_emu, rs1 >> (rs2 & 0b111111));949               })950        .value_or(false);951  }952  bool operator()(OR inst) {953    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),954                             [&](auto &&tup) {955                               auto [rs1, rs2] = tup;956                               return inst.rd.Write(m_emu, rs1 | rs2);957                             })958        .value_or(false);959  }960  bool operator()(AND inst) {961    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),962                             [&](auto &&tup) {963                               auto [rs1, rs2] = tup;964                               return inst.rd.Write(m_emu, rs1 & rs2);965                             })966        .value_or(false);967  }968  bool operator()(LWU inst) {969    return Load<LWU, uint32_t, uint32_t>(m_emu, inst, ZextD);970  }971  bool operator()(LD inst) {972    return Load<LD, uint64_t, uint64_t>(m_emu, inst, ZextD);973  }974  bool operator()(SD inst) { return Store<SD, uint64_t>(m_emu, inst); }975  bool operator()(SLLI inst) {976    return transformOptional(inst.rs1.Read(m_emu),977                             [&](uint64_t rs1) {978                               return inst.rd.Write(m_emu, rs1 << inst.shamt);979                             })980        .value_or(false);981  }982  bool operator()(SRLI inst) {983    return transformOptional(inst.rs1.Read(m_emu),984                             [&](uint64_t rs1) {985                               return inst.rd.Write(m_emu, rs1 >> inst.shamt);986                             })987        .value_or(false);988  }989  bool operator()(SRAI inst) {990    return transformOptional(inst.rs1.ReadI64(m_emu),991                             [&](int64_t rs1) {992                               return inst.rd.Write(m_emu, rs1 >> inst.shamt);993                             })994        .value_or(false);995  }996  bool operator()(ADDIW inst) {997    return transformOptional(inst.rs1.ReadI32(m_emu),998                             [&](int32_t rs1) {999                               return inst.rd.Write(1000                                   m_emu, SextW(rs1 + SignExt(inst.imm)));1001                             })1002        .value_or(false);1003  }1004  bool operator()(SLLIW inst) {1005    return transformOptional(inst.rs1.ReadU32(m_emu),1006                             [&](uint32_t rs1) {1007                               return inst.rd.Write(m_emu,1008                                                    SextW(rs1 << inst.shamt));1009                             })1010        .value_or(false);1011  }1012  bool operator()(SRLIW inst) {1013    return transformOptional(inst.rs1.ReadU32(m_emu),1014                             [&](uint32_t rs1) {1015                               return inst.rd.Write(m_emu,1016                                                    SextW(rs1 >> inst.shamt));1017                             })1018        .value_or(false);1019  }1020  bool operator()(SRAIW inst) {1021    return transformOptional(inst.rs1.ReadI32(m_emu),1022                             [&](int32_t rs1) {1023                               return inst.rd.Write(m_emu,1024                                                    SextW(rs1 >> inst.shamt));1025                             })1026        .value_or(false);1027  }1028  bool operator()(ADDW inst) {1029    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1030                             [&](auto &&tup) {1031                               auto [rs1, rs2] = tup;1032                               return inst.rd.Write(m_emu,1033                                                    SextW(uint32_t(rs1 + rs2)));1034                             })1035        .value_or(false);1036  }1037  bool operator()(SUBW inst) {1038    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1039                             [&](auto &&tup) {1040                               auto [rs1, rs2] = tup;1041                               return inst.rd.Write(m_emu,1042                                                    SextW(uint32_t(rs1 - rs2)));1043                             })1044        .value_or(false);1045  }1046  bool operator()(SLLW inst) {1047    return transformOptional(1048               zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),1049               [&](auto &&tup) {1050                 auto [rs1, rs2] = tup;1051                 return inst.rd.Write(m_emu, SextW(rs1 << (rs2 & 0b11111)));1052               })1053        .value_or(false);1054  }1055  bool operator()(SRLW inst) {1056    return transformOptional(1057               zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),1058               [&](auto &&tup) {1059                 auto [rs1, rs2] = tup;1060                 return inst.rd.Write(m_emu, SextW(rs1 >> (rs2 & 0b11111)));1061               })1062        .value_or(false);1063  }1064  bool operator()(SRAW inst) {1065    return transformOptional(1066               zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.Read(m_emu)),1067               [&](auto &&tup) {1068                 auto [rs1, rs2] = tup;1069                 return inst.rd.Write(m_emu, SextW(rs1 >> (rs2 & 0b11111)));1070               })1071        .value_or(false);1072  }1073  // RV32M & RV64M (Integer Multiplication and Division Extension) //1074  bool operator()(MUL inst) {1075    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1076                             [&](auto &&tup) {1077                               auto [rs1, rs2] = tup;1078                               return inst.rd.Write(m_emu, rs1 * rs2);1079                             })1080        .value_or(false);1081  }1082  bool operator()(MULH inst) {1083    return transformOptional(1084               zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1085               [&](auto &&tup) {1086                 auto [rs1, rs2] = tup;1087                 // signed * signed1088                 auto mul = APInt(128, rs1, true) * APInt(128, rs2, true);1089                 return inst.rd.Write(m_emu,1090                                      mul.ashr(64).trunc(64).getZExtValue());1091               })1092        .value_or(false);1093  }1094  bool operator()(MULHSU inst) {1095    return transformOptional(1096               zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1097               [&](auto &&tup) {1098                 auto [rs1, rs2] = tup;1099                 // signed * unsigned1100                 auto mul =1101                     APInt(128, rs1, true).zext(128) * APInt(128, rs2, false);1102                 return inst.rd.Write(m_emu,1103                                      mul.lshr(64).trunc(64).getZExtValue());1104               })1105        .value_or(false);1106  }1107  bool operator()(MULHU inst) {1108    return transformOptional(1109               zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1110               [&](auto &&tup) {1111                 auto [rs1, rs2] = tup;1112                 // unsigned * unsigned1113                 auto mul = APInt(128, rs1, false) * APInt(128, rs2, false);1114                 return inst.rd.Write(m_emu,1115                                      mul.lshr(64).trunc(64).getZExtValue());1116               })1117        .value_or(false);1118  }1119  bool operator()(DIV inst) {1120    return transformOptional(1121               zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)),1122               [&](auto &&tup) {1123                 auto [dividend, divisor] = tup;1124 1125                 if (divisor == 0)1126                   return inst.rd.Write(m_emu, UINT64_MAX);1127 1128                 if (dividend == INT64_MIN && divisor == -1)1129                   return inst.rd.Write(m_emu, dividend);1130 1131                 return inst.rd.Write(m_emu, dividend / divisor);1132               })1133        .value_or(false);1134  }1135  bool operator()(DIVU inst) {1136    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1137                             [&](auto &&tup) {1138                               auto [dividend, divisor] = tup;1139 1140                               if (divisor == 0)1141                                 return inst.rd.Write(m_emu, UINT64_MAX);1142 1143                               return inst.rd.Write(m_emu, dividend / divisor);1144                             })1145        .value_or(false);1146  }1147  bool operator()(REM inst) {1148    return transformOptional(1149               zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)),1150               [&](auto &&tup) {1151                 auto [dividend, divisor] = tup;1152 1153                 if (divisor == 0)1154                   return inst.rd.Write(m_emu, dividend);1155 1156                 if (dividend == INT64_MIN && divisor == -1)1157                   return inst.rd.Write(m_emu, 0);1158 1159                 return inst.rd.Write(m_emu, dividend % divisor);1160               })1161        .value_or(false);1162  }1163  bool operator()(REMU inst) {1164    return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1165                             [&](auto &&tup) {1166                               auto [dividend, divisor] = tup;1167 1168                               if (divisor == 0)1169                                 return inst.rd.Write(m_emu, dividend);1170 1171                               return inst.rd.Write(m_emu, dividend % divisor);1172                             })1173        .value_or(false);1174  }1175  bool operator()(MULW inst) {1176    return transformOptional(1177               zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)),1178               [&](auto &&tup) {1179                 auto [rs1, rs2] = tup;1180                 return inst.rd.Write(m_emu, SextW(rs1 * rs2));1181               })1182        .value_or(false);1183  }1184  bool operator()(DIVW inst) {1185    return transformOptional(1186               zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)),1187               [&](auto &&tup) {1188                 auto [dividend, divisor] = tup;1189 1190                 if (divisor == 0)1191                   return inst.rd.Write(m_emu, UINT64_MAX);1192 1193                 if (dividend == INT32_MIN && divisor == -1)1194                   return inst.rd.Write(m_emu, SextW(dividend));1195 1196                 return inst.rd.Write(m_emu, SextW(dividend / divisor));1197               })1198        .value_or(false);1199  }1200  bool operator()(DIVUW inst) {1201    return transformOptional(1202               zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),1203               [&](auto &&tup) {1204                 auto [dividend, divisor] = tup;1205 1206                 if (divisor == 0)1207                   return inst.rd.Write(m_emu, UINT64_MAX);1208 1209                 return inst.rd.Write(m_emu, SextW(dividend / divisor));1210               })1211        .value_or(false);1212  }1213  bool operator()(REMW inst) {1214    return transformOptional(1215               zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)),1216               [&](auto &&tup) {1217                 auto [dividend, divisor] = tup;1218 1219                 if (divisor == 0)1220                   return inst.rd.Write(m_emu, SextW(dividend));1221 1222                 if (dividend == INT32_MIN && divisor == -1)1223                   return inst.rd.Write(m_emu, 0);1224 1225                 return inst.rd.Write(m_emu, SextW(dividend % divisor));1226               })1227        .value_or(false);1228  }1229  bool operator()(REMUW inst) {1230    return transformOptional(1231               zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),1232               [&](auto &&tup) {1233                 auto [dividend, divisor] = tup;1234 1235                 if (divisor == 0)1236                   return inst.rd.Write(m_emu, SextW(dividend));1237 1238                 return inst.rd.Write(m_emu, SextW(dividend % divisor));1239               })1240        .value_or(false);1241  }1242  // RV32A & RV64A (The standard atomic instruction extension) //1243  bool operator()(LR_W) { return AtomicSequence(m_emu); }1244  bool operator()(LR_D) { return AtomicSequence(m_emu); }1245  bool operator()(SC_W) {1246    llvm_unreachable("should be handled in AtomicSequence");1247  }1248  bool operator()(SC_D) {1249    llvm_unreachable("should be handled in AtomicSequence");1250  }1251  bool operator()(AMOSWAP_W inst) {1252    return AtomicSwap<AMOSWAP_W, uint32_t>(m_emu, inst, 4, SextW);1253  }1254  bool operator()(AMOADD_W inst) {1255    return AtomicADD<AMOADD_W, uint32_t>(m_emu, inst, 4, SextW);1256  }1257  bool operator()(AMOXOR_W inst) {1258    return AtomicBitOperate<AMOXOR_W, uint32_t>(1259        m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a ^ b; });1260  }1261  bool operator()(AMOAND_W inst) {1262    return AtomicBitOperate<AMOAND_W, uint32_t>(1263        m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a & b; });1264  }1265  bool operator()(AMOOR_W inst) {1266    return AtomicBitOperate<AMOOR_W, uint32_t>(1267        m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a | b; });1268  }1269  bool operator()(AMOMIN_W inst) {1270    return AtomicCmp<AMOMIN_W, uint32_t>(1271        m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) {1272          return uint32_t(std::min(int32_t(a), int32_t(b)));1273        });1274  }1275  bool operator()(AMOMAX_W inst) {1276    return AtomicCmp<AMOMAX_W, uint32_t>(1277        m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) {1278          return uint32_t(std::max(int32_t(a), int32_t(b)));1279        });1280  }1281  bool operator()(AMOMINU_W inst) {1282    return AtomicCmp<AMOMINU_W, uint32_t>(1283        m_emu, inst, 4, SextW,1284        [](uint32_t a, uint32_t b) { return std::min(a, b); });1285  }1286  bool operator()(AMOMAXU_W inst) {1287    return AtomicCmp<AMOMAXU_W, uint32_t>(1288        m_emu, inst, 4, SextW,1289        [](uint32_t a, uint32_t b) { return std::max(a, b); });1290  }1291  bool operator()(AMOSWAP_D inst) {1292    return AtomicSwap<AMOSWAP_D, uint64_t>(m_emu, inst, 8, ZextD);1293  }1294  bool operator()(AMOADD_D inst) {1295    return AtomicADD<AMOADD_D, uint64_t>(m_emu, inst, 8, ZextD);1296  }1297  bool operator()(AMOXOR_D inst) {1298    return AtomicBitOperate<AMOXOR_D, uint64_t>(1299        m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a ^ b; });1300  }1301  bool operator()(AMOAND_D inst) {1302    return AtomicBitOperate<AMOAND_D, uint64_t>(1303        m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a & b; });1304  }1305  bool operator()(AMOOR_D inst) {1306    return AtomicBitOperate<AMOOR_D, uint64_t>(1307        m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a | b; });1308  }1309  bool operator()(AMOMIN_D inst) {1310    return AtomicCmp<AMOMIN_D, uint64_t>(1311        m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) {1312          return uint64_t(std::min(int64_t(a), int64_t(b)));1313        });1314  }1315  bool operator()(AMOMAX_D inst) {1316    return AtomicCmp<AMOMAX_D, uint64_t>(1317        m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) {1318          return uint64_t(std::max(int64_t(a), int64_t(b)));1319        });1320  }1321  bool operator()(AMOMINU_D inst) {1322    return AtomicCmp<AMOMINU_D, uint64_t>(1323        m_emu, inst, 8, ZextD,1324        [](uint64_t a, uint64_t b) { return std::min(a, b); });1325  }1326  bool operator()(AMOMAXU_D inst) {1327    return AtomicCmp<AMOMAXU_D, uint64_t>(1328        m_emu, inst, 8, ZextD,1329        [](uint64_t a, uint64_t b) { return std::max(a, b); });1330  }1331  template <typename I, typename T>1332  bool F_Load(I inst, const fltSemantics &(*semantics)()) {1333    return transformOptional(inst.rs1.Read(m_emu),1334                             [&](auto &&rs1) {1335                               uint64_t addr =1336                                   rs1 + uint64_t(SignExt(inst.imm));1337                               uint64_t bits = *m_emu.ReadMem<T>(addr);1338                               unsigned numBits = sizeof(T) * 8;1339                               APFloat f(semantics(), APInt(numBits, bits));1340                               return inst.rd.WriteAPFloat(m_emu, f);1341                             })1342        .value_or(false);1343  }1344  bool operator()(FLW inst) {1345    return F_Load<FLW, uint32_t>(inst, &APFloat::IEEEsingle);1346  }1347  template <typename I, typename T> bool F_Store(I inst, bool isDouble) {1348    return transformOptional(zipOpt(inst.rs1.Read(m_emu),1349                                    inst.rs2.ReadAPFloat(m_emu, isDouble)),1350                             [&](auto &&tup) {1351                               auto [rs1, rs2] = tup;1352                               uint64_t addr =1353                                   rs1 + uint64_t(SignExt(inst.imm));1354                               uint64_t bits =1355                                   rs2.bitcastToAPInt().getZExtValue();1356                               return m_emu.WriteMem<T>(addr, bits);1357                             })1358        .value_or(false);1359  }1360  bool operator()(FSW inst) { return F_Store<FSW, uint32_t>(inst, false); }1361  std::tuple<bool, APFloat> FusedMultiplyAdd(APFloat rs1, APFloat rs2,1362                                             APFloat rs3) {1363    auto opStatus = rs1.fusedMultiplyAdd(rs2, rs3, m_emu.GetRoundingMode());1364    auto res = m_emu.SetAccruedExceptions(opStatus);1365    return {res, rs1};1366  }1367  template <typename T>1368  bool FMA(T inst, bool isDouble, float rs2_sign, float rs3_sign) {1369    return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1370                                    inst.rs2.ReadAPFloat(m_emu, isDouble),1371                                    inst.rs3.ReadAPFloat(m_emu, isDouble)),1372                             [&](auto &&tup) {1373                               auto [rs1, rs2, rs3] = tup;1374                               rs2.copySign(APFloat(rs2_sign));1375                               rs3.copySign(APFloat(rs3_sign));1376                               auto [res, f] = FusedMultiplyAdd(rs1, rs2, rs3);1377                               return res && inst.rd.WriteAPFloat(m_emu, f);1378                             })1379        .value_or(false);1380  }1381  bool operator()(FMADD_S inst) { return FMA(inst, false, 1.0f, 1.0f); }1382  bool operator()(FMSUB_S inst) { return FMA(inst, false, 1.0f, -1.0f); }1383  bool operator()(FNMSUB_S inst) { return FMA(inst, false, -1.0f, 1.0f); }1384  bool operator()(FNMADD_S inst) { return FMA(inst, false, -1.0f, -1.0f); }1385  template <typename T>1386  bool F_Op(T inst, bool isDouble,1387            APFloat::opStatus (APFloat::*f)(const APFloat &RHS,1388                                            APFloat::roundingMode RM)) {1389    return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1390                                    inst.rs2.ReadAPFloat(m_emu, isDouble)),1391                             [&](auto &&tup) {1392                               auto [rs1, rs2] = tup;1393                               auto res =1394                                   ((&rs1)->*f)(rs2, m_emu.GetRoundingMode());1395                               inst.rd.WriteAPFloat(m_emu, rs1);1396                               return m_emu.SetAccruedExceptions(res);1397                             })1398        .value_or(false);1399  }1400  bool operator()(FADD_S inst) { return F_Op(inst, false, &APFloat::add); }1401  bool operator()(FSUB_S inst) { return F_Op(inst, false, &APFloat::subtract); }1402  bool operator()(FMUL_S inst) { return F_Op(inst, false, &APFloat::multiply); }1403  bool operator()(FDIV_S inst) { return F_Op(inst, false, &APFloat::divide); }1404  bool operator()(FSQRT_S inst) {1405    // TODO: APFloat doesn't have a sqrt function.1406    return false;1407  }1408  template <typename T> bool F_SignInj(T inst, bool isDouble, bool isNegate) {1409    return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1410                                    inst.rs2.ReadAPFloat(m_emu, isDouble)),1411                             [&](auto &&tup) {1412                               auto [rs1, rs2] = tup;1413                               if (isNegate)1414                                 rs2.changeSign();1415                               rs1.copySign(rs2);1416                               return inst.rd.WriteAPFloat(m_emu, rs1);1417                             })1418        .value_or(false);1419  }1420  bool operator()(FSGNJ_S inst) { return F_SignInj(inst, false, false); }1421  bool operator()(FSGNJN_S inst) { return F_SignInj(inst, false, true); }1422  template <typename T> bool F_SignInjXor(T inst, bool isDouble) {1423    return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1424                                    inst.rs2.ReadAPFloat(m_emu, isDouble)),1425                             [&](auto &&tup) {1426                               auto [rs1, rs2] = tup;1427                               // spec: the sign bit is the XOR of the sign bits1428                               // of rs1 and rs2. if rs1 and rs2 have the same1429                               // signs set rs1 to positive else set rs1 to1430                               // negative1431                               if (rs1.isNegative() == rs2.isNegative()) {1432                                 rs1.clearSign();1433                               } else {1434                                 rs1.clearSign();1435                                 rs1.changeSign();1436                               }1437                               return inst.rd.WriteAPFloat(m_emu, rs1);1438                             })1439        .value_or(false);1440  }1441  bool operator()(FSGNJX_S inst) { return F_SignInjXor(inst, false); }1442  template <typename T>1443  bool F_MAX_MIN(T inst, bool isDouble,1444                 APFloat (*f)(const APFloat &A, const APFloat &B)) {1445    return transformOptional(1446               zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1447                      inst.rs2.ReadAPFloat(m_emu, isDouble)),1448               [&](auto &&tup) {1449                 auto [rs1, rs2] = tup;1450                 // If both inputs are NaNs, the result is the canonical NaN.1451                 // If only one operand is a NaN, the result is the non-NaN1452                 // operand. Signaling NaN inputs set the invalid operation1453                 // exception flag, even when the result is not NaN.1454                 if (rs1.isNaN() || rs2.isNaN())1455                   m_emu.SetAccruedExceptions(APFloat::opInvalidOp);1456                 if (rs1.isNaN() && rs2.isNaN()) {1457                   auto canonicalNaN = APFloat::getQNaN(rs1.getSemantics());1458                   return inst.rd.WriteAPFloat(m_emu, canonicalNaN);1459                 }1460                 return inst.rd.WriteAPFloat(m_emu, f(rs1, rs2));1461               })1462        .value_or(false);1463  }1464  bool operator()(FMIN_S inst) { return F_MAX_MIN(inst, false, minnum); }1465  bool operator()(FMAX_S inst) { return F_MAX_MIN(inst, false, maxnum); }1466  bool operator()(FCVT_W_S inst) {1467    return FCVT_i2f<FCVT_W_S, int32_t, float>(inst, false,1468                                              &APFloat::convertToFloat);1469  }1470  bool operator()(FCVT_WU_S inst) {1471    return FCVT_i2f<FCVT_WU_S, uint32_t, float>(inst, false,1472                                                &APFloat::convertToFloat);1473  }1474  template <typename T> bool FMV_f2i(T inst, bool isDouble) {1475    return transformOptional(1476               inst.rs1.ReadAPFloat(m_emu, isDouble),1477               [&](auto &&rs1) {1478                 if (rs1.isNaN()) {1479                   if (isDouble)1480                     return inst.rd.Write(m_emu, 0x7ff8'0000'0000'0000);1481                   else1482                     return inst.rd.Write(m_emu, 0x7fc0'0000);1483                 }1484                 auto bits = rs1.bitcastToAPInt().getZExtValue();1485                 if (isDouble)1486                   return inst.rd.Write(m_emu, bits);1487                 else1488                   return inst.rd.Write(m_emu, uint64_t(bits & 0xffff'ffff));1489               })1490        .value_or(false);1491  }1492  bool operator()(FMV_X_W inst) { return FMV_f2i(inst, false); }1493  enum F_CMP {1494    FEQ,1495    FLT,1496    FLE,1497  };1498  template <typename T> bool F_Compare(T inst, bool isDouble, F_CMP cmp) {1499    return transformOptional(1500               zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1501                      inst.rs2.ReadAPFloat(m_emu, isDouble)),1502               [&](auto &&tup) {1503                 auto [rs1, rs2] = tup;1504                 if (rs1.isNaN() || rs2.isNaN()) {1505                   if (cmp == FEQ) {1506                     if (rs1.isSignaling() || rs2.isSignaling()) {1507                       auto res =1508                           m_emu.SetAccruedExceptions(APFloat::opInvalidOp);1509                       return res && inst.rd.Write(m_emu, 0);1510                     }1511                   }1512                   auto res = m_emu.SetAccruedExceptions(APFloat::opInvalidOp);1513                   return res && inst.rd.Write(m_emu, 0);1514                 }1515                 switch (cmp) {1516                 case FEQ:1517                   return inst.rd.Write(m_emu,1518                                        rs1.compare(rs2) == APFloat::cmpEqual);1519                 case FLT:1520                   return inst.rd.Write(m_emu, rs1.compare(rs2) ==1521                                                   APFloat::cmpLessThan);1522                 case FLE:1523                   return inst.rd.Write(m_emu, rs1.compare(rs2) !=1524                                                   APFloat::cmpGreaterThan);1525                 }1526                 llvm_unreachable("unsupported F_CMP");1527               })1528        .value_or(false);1529  }1530 1531  bool operator()(FEQ_S inst) { return F_Compare(inst, false, FEQ); }1532  bool operator()(FLT_S inst) { return F_Compare(inst, false, FLT); }1533  bool operator()(FLE_S inst) { return F_Compare(inst, false, FLE); }1534  template <typename T> bool FCLASS(T inst, bool isDouble) {1535    return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble),1536                             [&](auto &&rs1) {1537                               uint64_t result = 0;1538                               if (rs1.isInfinity() && rs1.isNegative())1539                                 result |= 1 << 0;1540                               // neg normal1541                               if (rs1.isNormal() && rs1.isNegative())1542                                 result |= 1 << 1;1543                               // neg subnormal1544                               if (rs1.isDenormal() && rs1.isNegative())1545                                 result |= 1 << 2;1546                               if (rs1.isNegZero())1547                                 result |= 1 << 3;1548                               if (rs1.isPosZero())1549                                 result |= 1 << 4;1550                               // pos normal1551                               if (rs1.isNormal() && !rs1.isNegative())1552                                 result |= 1 << 5;1553                               // pos subnormal1554                               if (rs1.isDenormal() && !rs1.isNegative())1555                                 result |= 1 << 6;1556                               if (rs1.isInfinity() && !rs1.isNegative())1557                                 result |= 1 << 7;1558                               if (rs1.isNaN()) {1559                                 if (rs1.isSignaling())1560                                   result |= 1 << 8;1561                                 else1562                                   result |= 1 << 9;1563                               }1564                               return inst.rd.Write(m_emu, result);1565                             })1566        .value_or(false);1567  }1568  bool operator()(FCLASS_S inst) { return FCLASS(inst, false); }1569  template <typename T, typename E>1570  bool FCVT_f2i(T inst, std::optional<E> (Rs::*f)(EmulateInstructionRISCV &emu),1571                const fltSemantics &semantics) {1572    return transformOptional(((&inst.rs1)->*f)(m_emu),1573                             [&](auto &&rs1) {1574                               APFloat apf(semantics, rs1);1575                               return inst.rd.WriteAPFloat(m_emu, apf);1576                             })1577        .value_or(false);1578  }1579  bool operator()(FCVT_S_W inst) {1580    return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEsingle());1581  }1582  bool operator()(FCVT_S_WU inst) {1583    return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEsingle());1584  }1585  template <typename T, typename E>1586  bool FMV_i2f(T inst, unsigned int numBits, E (APInt::*f)() const) {1587    return transformOptional(inst.rs1.Read(m_emu),1588                             [&](auto &&rs1) {1589                               APInt apInt(numBits, rs1);1590                               if (numBits == 32) // a.k.a. float1591                                 apInt = APInt(numBits, NanUnBoxing(rs1));1592                               APFloat apf((&apInt->*f)());1593                               return inst.rd.WriteAPFloat(m_emu, apf);1594                             })1595        .value_or(false);1596  }1597  bool operator()(FMV_W_X inst) {1598    return FMV_i2f(inst, 32, &APInt::bitsToFloat);1599  }1600  template <typename I, typename E, typename T>1601  bool FCVT_i2f(I inst, bool isDouble, T (APFloat::*f)() const) {1602    return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble),1603                             [&](auto &&rs1) {1604                               E res = E((&rs1->*f)());1605                               return inst.rd.Write(m_emu, uint64_t(res));1606                             })1607        .value_or(false);1608  }1609  bool operator()(FCVT_L_S inst) {1610    return FCVT_i2f<FCVT_L_S, int64_t, float>(inst, false,1611                                              &APFloat::convertToFloat);1612  }1613  bool operator()(FCVT_LU_S inst) {1614    return FCVT_i2f<FCVT_LU_S, uint64_t, float>(inst, false,1615                                                &APFloat::convertToFloat);1616  }1617  bool operator()(FCVT_S_L inst) {1618    return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEsingle());1619  }1620  bool operator()(FCVT_S_LU inst) {1621    return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEsingle());1622  }1623  bool operator()(FLD inst) {1624    return F_Load<FLD, uint64_t>(inst, &APFloat::IEEEdouble);1625  }1626  bool operator()(FSD inst) { return F_Store<FSD, uint64_t>(inst, true); }1627  bool operator()(FMADD_D inst) { return FMA(inst, true, 1.0f, 1.0f); }1628  bool operator()(FMSUB_D inst) { return FMA(inst, true, 1.0f, -1.0f); }1629  bool operator()(FNMSUB_D inst) { return FMA(inst, true, -1.0f, 1.0f); }1630  bool operator()(FNMADD_D inst) { return FMA(inst, true, -1.0f, -1.0f); }1631  bool operator()(FADD_D inst) { return F_Op(inst, true, &APFloat::add); }1632  bool operator()(FSUB_D inst) { return F_Op(inst, true, &APFloat::subtract); }1633  bool operator()(FMUL_D inst) { return F_Op(inst, true, &APFloat::multiply); }1634  bool operator()(FDIV_D inst) { return F_Op(inst, true, &APFloat::divide); }1635  bool operator()(FSQRT_D inst) {1636    // TODO: APFloat doesn't have a sqrt function.1637    return false;1638  }1639  bool operator()(FSGNJ_D inst) { return F_SignInj(inst, true, false); }1640  bool operator()(FSGNJN_D inst) { return F_SignInj(inst, true, true); }1641  bool operator()(FSGNJX_D inst) { return F_SignInjXor(inst, true); }1642  bool operator()(FMIN_D inst) { return F_MAX_MIN(inst, true, minnum); }1643  bool operator()(FMAX_D inst) { return F_MAX_MIN(inst, true, maxnum); }1644  bool operator()(FCVT_S_D inst) {1645    return transformOptional(inst.rs1.ReadAPFloat(m_emu, true),1646                             [&](auto &&rs1) {1647                               double d = rs1.convertToDouble();1648                               APFloat apf((float(d)));1649                               return inst.rd.WriteAPFloat(m_emu, apf);1650                             })1651        .value_or(false);1652  }1653  bool operator()(FCVT_D_S inst) {1654    return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),1655                             [&](auto &&rs1) {1656                               float f = rs1.convertToFloat();1657                               APFloat apf((double(f)));1658                               return inst.rd.WriteAPFloat(m_emu, apf);1659                             })1660        .value_or(false);1661  }1662  bool operator()(FEQ_D inst) { return F_Compare(inst, true, FEQ); }1663  bool operator()(FLT_D inst) { return F_Compare(inst, true, FLT); }1664  bool operator()(FLE_D inst) { return F_Compare(inst, true, FLE); }1665  bool operator()(FCLASS_D inst) { return FCLASS(inst, true); }1666  bool operator()(FCVT_W_D inst) {1667    return FCVT_i2f<FCVT_W_D, int32_t, double>(inst, true,1668                                               &APFloat::convertToDouble);1669  }1670  bool operator()(FCVT_WU_D inst) {1671    return FCVT_i2f<FCVT_WU_D, uint32_t, double>(inst, true,1672                                                 &APFloat::convertToDouble);1673  }1674  bool operator()(FCVT_D_W inst) {1675    return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEdouble());1676  }1677  bool operator()(FCVT_D_WU inst) {1678    return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEdouble());1679  }1680  bool operator()(FCVT_L_D inst) {1681    return FCVT_i2f<FCVT_L_D, int64_t, double>(inst, true,1682                                               &APFloat::convertToDouble);1683  }1684  bool operator()(FCVT_LU_D inst) {1685    return FCVT_i2f<FCVT_LU_D, uint64_t, double>(inst, true,1686                                                 &APFloat::convertToDouble);1687  }1688  bool operator()(FMV_X_D inst) { return FMV_f2i(inst, true); }1689  bool operator()(FCVT_D_L inst) {1690    return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEdouble());1691  }1692  bool operator()(FCVT_D_LU inst) {1693    return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEdouble());1694  }1695  bool operator()(FMV_D_X inst) {1696    return FMV_i2f(inst, 64, &APInt::bitsToDouble);1697  }1698  bool operator()(INVALID inst) { return false; }1699  bool operator()(RESERVED inst) { return false; }1700  bool operator()(EBREAK inst) { return false; }1701  bool operator()(HINT inst) { return true; }1702  bool operator()(NOP inst) { return true; }1703};1704 1705bool EmulateInstructionRISCV::Execute(DecodeResult inst, bool ignore_cond) {1706  return std::visit(Executor(*this, ignore_cond, inst.is_rvc), inst.decoded);1707}1708 1709bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) {1710  bool increase_pc = options & eEmulateInstructionOptionAutoAdvancePC;1711  bool ignore_cond = options & eEmulateInstructionOptionIgnoreConditions;1712 1713  if (!increase_pc)1714    return Execute(m_decoded, ignore_cond);1715 1716  auto old_pc = ReadPC();1717  if (!old_pc)1718    return false;1719 1720  bool success = Execute(m_decoded, ignore_cond);1721  if (!success)1722    return false;1723 1724  auto new_pc = ReadPC();1725  if (!new_pc)1726    return false;1727 1728  // If the pc is not updated during execution, we do it here.1729  return new_pc != old_pc ||1730         WritePC(*old_pc + Executor::size(m_decoded.is_rvc));1731}1732 1733std::optional<DecodeResult>1734EmulateInstructionRISCV::ReadInstructionAt(addr_t addr) {1735  return transformOptional(ReadMem<uint32_t>(addr),1736                           [&](uint32_t inst) { return Decode(inst); })1737      .value_or(std::nullopt);1738}1739 1740bool EmulateInstructionRISCV::ReadInstruction() {1741  auto addr = ReadPC();1742  m_addr = addr.value_or(LLDB_INVALID_ADDRESS);1743  if (!addr)1744    return false;1745  auto inst = ReadInstructionAt(*addr);1746  if (!inst)1747    return false;1748  m_decoded = *inst;1749  if (inst->is_rvc)1750    m_opcode.SetOpcode16(inst->inst, GetByteOrder());1751  else1752    m_opcode.SetOpcode32(inst->inst, GetByteOrder());1753  return true;1754}1755 1756RoundingMode EmulateInstructionRISCV::GetRoundingMode() {1757  bool success = false;1758  auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,1759                                   LLDB_INVALID_ADDRESS, &success);1760  if (!success)1761    return RoundingMode::Invalid;1762  auto frm = (fcsr >> 5) & 0x7;1763  switch (frm) {1764  case 0b000:1765    return RoundingMode::NearestTiesToEven;1766  case 0b001:1767    return RoundingMode::TowardZero;1768  case 0b010:1769    return RoundingMode::TowardNegative;1770  case 0b011:1771    return RoundingMode::TowardPositive;1772  case 0b111:1773    return RoundingMode::Dynamic;1774  default:1775    // Reserved for future use.1776    return RoundingMode::Invalid;1777  }1778}1779 1780bool EmulateInstructionRISCV::SetAccruedExceptions(1781    APFloatBase::opStatus opStatus) {1782  bool success = false;1783  auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,1784                                   LLDB_INVALID_ADDRESS, &success);1785  if (!success)1786    return false;1787  switch (opStatus) {1788  case APFloatBase::opInvalidOp:1789    fcsr |= 1 << 4;1790    break;1791  case APFloatBase::opDivByZero:1792    fcsr |= 1 << 3;1793    break;1794  case APFloatBase::opOverflow:1795    fcsr |= 1 << 2;1796    break;1797  case APFloatBase::opUnderflow:1798    fcsr |= 1 << 1;1799    break;1800  case APFloatBase::opInexact:1801    fcsr |= 1 << 0;1802    break;1803  case APFloatBase::opOK:1804    break;1805  }1806  EmulateInstruction::Context ctx;1807  ctx.type = eContextRegisterStore;1808  ctx.SetNoArgs();1809  return WriteRegisterUnsigned(ctx, eRegisterKindLLDB, fpr_fcsr_riscv, fcsr);1810}1811 1812std::optional<RegisterInfo>1813EmulateInstructionRISCV::GetRegisterInfo(RegisterKind reg_kind,1814                                         uint32_t reg_index) {1815  if (reg_kind == eRegisterKindGeneric) {1816    switch (reg_index) {1817    case LLDB_REGNUM_GENERIC_PC:1818      reg_kind = eRegisterKindLLDB;1819      reg_index = gpr_pc_riscv;1820      break;1821    case LLDB_REGNUM_GENERIC_SP:1822      reg_kind = eRegisterKindLLDB;1823      reg_index = gpr_sp_riscv;1824      break;1825    case LLDB_REGNUM_GENERIC_FP:1826      reg_kind = eRegisterKindLLDB;1827      reg_index = gpr_fp_riscv;1828      break;1829    case LLDB_REGNUM_GENERIC_RA:1830      reg_kind = eRegisterKindLLDB;1831      reg_index = gpr_ra_riscv;1832      break;1833    // We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are1834    // supported.1835    default:1836      llvm_unreachable("unsupported register");1837    }1838  }1839 1840  RegisterInfoPOSIX_riscv64 reg_info(m_arch,1841                                     RegisterInfoPOSIX_riscv64::eRegsetMaskAll);1842  const RegisterInfo *array = reg_info.GetRegisterInfo();1843  const uint32_t length = reg_info.GetRegisterCount();1844 1845  if (reg_index >= length || reg_kind != eRegisterKindLLDB)1846    return {};1847 1848  return array[reg_index];1849}1850 1851bool EmulateInstructionRISCV::SetInstruction(const Opcode &opcode,1852                                             const Address &inst_addr,1853                                             Target *target) {1854  // Call the base class implementation.1855  if (!EmulateInstruction::SetInstruction(opcode, inst_addr, target))1856    return false;1857 1858  // Extract instruction data from the opcode.1859  uint32_t inst_data = 0;1860  const void *opcode_data = m_opcode.GetOpcodeBytes();1861  if (!opcode_data)1862    return false;1863 1864  if (m_opcode.GetByteSize() == 2) {1865    // 16-bit compressed instruction.1866    const uint16_t *data = static_cast<const uint16_t *>(opcode_data);1867    inst_data = *data;1868  } else if (m_opcode.GetByteSize() == 4) {1869    // 32-bit instruction.1870    const uint32_t *data = static_cast<const uint32_t *>(opcode_data);1871    inst_data = *data;1872  } else {1873    return false;1874  }1875 1876  // Decode the instruction.1877  auto decoded_inst = Decode(inst_data);1878  if (!decoded_inst)1879    return false;1880 1881  // Store the decoded result.1882  m_decoded = *decoded_inst;1883  return true;1884}1885 1886bool EmulateInstructionRISCV::CreateFunctionEntryUnwind(1887    UnwindPlan &unwind_plan) {1888  unwind_plan.Clear();1889  unwind_plan.SetRegisterKind(eRegisterKindLLDB);1890 1891  UnwindPlan::Row row;1892 1893  row.GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_riscv, 0);1894  row.SetRegisterLocationToSame(gpr_ra_riscv, /*must_replace=*/false);1895  row.SetRegisterLocationToSame(gpr_fp_riscv, /*must_replace=*/false);1896 1897  unwind_plan.AppendRow(std::move(row));1898  unwind_plan.SetSourceName("EmulateInstructionRISCV");1899  unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);1900  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);1901  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);1902  unwind_plan.SetReturnAddressRegister(gpr_ra_riscv);1903  return true;1904}1905 1906bool EmulateInstructionRISCV::SetTargetTriple(const ArchSpec &arch) {1907  return SupportsThisArch(arch);1908}1909 1910bool EmulateInstructionRISCV::TestEmulation(Stream &out_stream, ArchSpec &arch,1911                                            OptionValueDictionary *test_data) {1912  return false;1913}1914 1915void EmulateInstructionRISCV::Initialize() {1916  PluginManager::RegisterPlugin(GetPluginNameStatic(),1917                                GetPluginDescriptionStatic(), CreateInstance);1918}1919 1920void EmulateInstructionRISCV::Terminate() {1921  PluginManager::UnregisterPlugin(CreateInstance);1922}1923 1924lldb_private::EmulateInstruction *1925EmulateInstructionRISCV::CreateInstance(const ArchSpec &arch,1926                                        InstructionType inst_type) {1927  if (EmulateInstructionRISCV::SupportsThisInstructionType(inst_type) &&1928      SupportsThisArch(arch)) {1929    return new EmulateInstructionRISCV(arch);1930  }1931 1932  return nullptr;1933}1934 1935bool EmulateInstructionRISCV::SupportsThisArch(const ArchSpec &arch) {1936  return arch.GetTriple().isRISCV();1937}1938 1939BreakpointLocations1940RISCVSingleStepBreakpointLocationsPredictor::GetBreakpointLocations(1941    Status &status) {1942  EmulateInstructionRISCV *riscv_emulator =1943      static_cast<EmulateInstructionRISCV *>(m_emulator_up.get());1944 1945  auto pc = riscv_emulator->ReadPC();1946  if (!pc) {1947    status = Status("Can't read PC");1948    return {};1949  }1950 1951  auto inst = riscv_emulator->ReadInstructionAt(*pc);1952  if (!inst) {1953    // Can't read instruction. Try default handler.1954    return SingleStepBreakpointLocationsPredictor::GetBreakpointLocations(1955        status);1956  }1957 1958  if (FoundLoadReserve(inst->decoded))1959    return HandleAtomicSequence(*pc, status);1960 1961  if (FoundStoreConditional(inst->decoded)) {1962    // Ill-formed atomic sequence (SC doesn't have corresponding LR1963    // instruction). Consider SC instruction like a non-atomic store and set a1964    // breakpoint at the next instruction.1965    Log *log = GetLog(LLDBLog::Unwind);1966    LLDB_LOGF(log,1967              "RISCVSingleStepBreakpointLocationsPredictor::%s: can't find "1968              "corresponding load reserve instruction",1969              __FUNCTION__);1970    return {*pc + (inst->is_rvc ? 2u : 4u)};1971  }1972 1973  return SingleStepBreakpointLocationsPredictor::GetBreakpointLocations(status);1974}1975 1976llvm::Expected<unsigned>1977RISCVSingleStepBreakpointLocationsPredictor::GetBreakpointSize(1978    lldb::addr_t bp_addr) {1979  EmulateInstructionRISCV *riscv_emulator =1980      static_cast<EmulateInstructionRISCV *>(m_emulator_up.get());1981 1982  if (auto inst = riscv_emulator->ReadInstructionAt(bp_addr); inst)1983    return inst->is_rvc ? 2 : 4;1984 1985  // Try last instruction size.1986  if (auto last_instr_size = riscv_emulator->GetLastInstrSize();1987      last_instr_size)1988    return *last_instr_size;1989 1990  // Just place non-compressed software trap.1991  return 4;1992}1993 1994BreakpointLocations1995RISCVSingleStepBreakpointLocationsPredictor::HandleAtomicSequence(1996    lldb::addr_t pc, Status &error) {1997  EmulateInstructionRISCV *riscv_emulator =1998      static_cast<EmulateInstructionRISCV *>(m_emulator_up.get());1999 2000  // Handle instructions between LR and SC. According to unprivileged2001  // RISC-V ISA there can be at most 16 instructions in the sequence.2002 2003  lldb::addr_t entry_pc = pc; // LR instruction address2004  auto lr_inst = riscv_emulator->ReadInstructionAt(entry_pc);2005  pc += lr_inst->is_rvc ? 2 : 4;2006 2007  size_t atomic_length = 0;2008  std::optional<DecodeResult> inst;2009  std::vector<lldb::addr_t> bp_addrs;2010  do {2011    inst = riscv_emulator->ReadInstructionAt(pc);2012    if (!inst) {2013      error = Status("Can't read instruction");2014      return {};2015    }2016 2017    if (B *branch = std::get_if<B>(&inst->decoded))2018      bp_addrs.push_back(pc + SignExt(branch->imm));2019 2020    unsigned addent = inst->is_rvc ? 2 : 4;2021    pc += addent;2022    atomic_length += addent;2023  } while ((atomic_length < s_max_atomic_sequence_length) &&2024           !FoundStoreConditional(inst->decoded));2025 2026  if (atomic_length >= s_max_atomic_sequence_length) {2027    // Ill-formed atomic sequence (LR doesn't have corresponding SC2028    // instruction). In this case consider LR like a non-atomic load instruction2029    // and set a breakpoint at the next after LR instruction.2030    Log *log = GetLog(LLDBLog::Unwind);2031    LLDB_LOGF(log,2032              "RISCVSingleStepBreakpointLocationsPredictor::%s: can't find "2033              "corresponding store conditional instruction",2034              __FUNCTION__);2035    return {entry_pc + (lr_inst->is_rvc ? 2u : 4u)};2036  }2037 2038  lldb::addr_t exit_pc = pc;2039 2040  // Check if we have a branch to the start of the atomic sequence after SC2041  // instruction. If we have such branch, consider it as a part of the atomic2042  // sequence.2043  inst = riscv_emulator->ReadInstructionAt(exit_pc);2044  if (inst) {2045    B *branch = std::get_if<B>(&inst->decoded);2046    if (branch && (exit_pc + SignExt(branch->imm)) == entry_pc)2047      exit_pc += inst->is_rvc ? 2 : 4;2048  }2049 2050  // Set breakpoints at the jump addresses of the forward branches that points2051  // after the end of the atomic sequence.2052  llvm::erase_if(2053      bp_addrs, [exit_pc](lldb::addr_t bp_addr) { return exit_pc >= bp_addr; });2054 2055  // Set breakpoint at the end of atomic sequence.2056  bp_addrs.push_back(exit_pc);2057  return bp_addrs;2058}2059 2060} // namespace lldb_private2061