Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
39648 views
//===-- EmulateInstructionRISCV.cpp ---------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "EmulateInstructionRISCV.h"9#include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h"10#include "Plugins/Process/Utility/lldb-riscv-register-enums.h"11#include "RISCVCInstructions.h"12#include "RISCVInstructions.h"1314#include "lldb/Core/Address.h"15#include "lldb/Core/PluginManager.h"16#include "lldb/Interpreter/OptionValueArray.h"17#include "lldb/Interpreter/OptionValueDictionary.h"18#include "lldb/Symbol/UnwindPlan.h"19#include "lldb/Utility/ArchSpec.h"20#include "lldb/Utility/LLDBLog.h"21#include "lldb/Utility/Stream.h"2223#include "llvm/ADT/STLExtras.h"24#include "llvm/Support/MathExtras.h"25#include <optional>2627using namespace llvm;28using namespace lldb;29using namespace lldb_private;3031LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionRISCV, InstructionRISCV)3233namespace lldb_private {3435/// Returns all values wrapped in Optional, or std::nullopt if any of the values36/// is std::nullopt.37template <typename... Ts>38static std::optional<std::tuple<Ts...>> zipOpt(std::optional<Ts> &&...ts) {39if ((ts.has_value() && ...))40return std::optional<std::tuple<Ts...>>(std::make_tuple(std::move(*ts)...));41else42return std::nullopt;43}4445// The funct3 is the type of compare in B<CMP> instructions.46// funct3 means "3-bits function selector", which RISC-V ISA uses as minor47// opcode. It reuses the major opcode encoding space.48constexpr uint32_t BEQ = 0b000;49constexpr uint32_t BNE = 0b001;50constexpr uint32_t BLT = 0b100;51constexpr uint32_t BGE = 0b101;52constexpr uint32_t BLTU = 0b110;53constexpr uint32_t BGEU = 0b111;5455// used in decoder56constexpr int32_t SignExt(uint32_t imm) { return int32_t(imm); }5758// used in executor59template <typename T>60constexpr std::enable_if_t<sizeof(T) <= 4, uint64_t> SextW(T value) {61return uint64_t(int64_t(int32_t(value)));62}6364// used in executor65template <typename T> constexpr uint64_t ZextD(T value) {66return uint64_t(value);67}6869constexpr uint32_t DecodeJImm(uint32_t inst) {70return (uint64_t(int64_t(int32_t(inst & 0x80000000)) >> 11)) // imm[20]71| (inst & 0xff000) // imm[19:12]72| ((inst >> 9) & 0x800) // imm[11]73| ((inst >> 20) & 0x7fe); // imm[10:1]74}7576constexpr uint32_t DecodeIImm(uint32_t inst) {77return int64_t(int32_t(inst)) >> 20; // imm[11:0]78}7980constexpr uint32_t DecodeBImm(uint32_t inst) {81return (uint64_t(int64_t(int32_t(inst & 0x80000000)) >> 19)) // imm[12]82| ((inst & 0x80) << 4) // imm[11]83| ((inst >> 20) & 0x7e0) // imm[10:5]84| ((inst >> 7) & 0x1e); // imm[4:1]85}8687constexpr uint32_t DecodeSImm(uint32_t inst) {88return (uint64_t(int64_t(int32_t(inst & 0xFE000000)) >> 20)) // imm[11:5]89| ((inst & 0xF80) >> 7); // imm[4:0]90}9192constexpr uint32_t DecodeUImm(uint32_t inst) {93return SextW(inst & 0xFFFFF000); // imm[31:12]94}9596static uint32_t GPREncodingToLLDB(uint32_t reg_encode) {97if (reg_encode == 0)98return gpr_x0_riscv;99if (reg_encode >= 1 && reg_encode <= 31)100return gpr_x1_riscv + reg_encode - 1;101return LLDB_INVALID_REGNUM;102}103104static uint32_t FPREncodingToLLDB(uint32_t reg_encode) {105if (reg_encode <= 31)106return fpr_f0_riscv + reg_encode;107return LLDB_INVALID_REGNUM;108}109110bool Rd::Write(EmulateInstructionRISCV &emulator, uint64_t value) {111uint32_t lldb_reg = GPREncodingToLLDB(rd);112EmulateInstruction::Context ctx;113ctx.type = EmulateInstruction::eContextRegisterStore;114ctx.SetNoArgs();115RegisterValue registerValue;116registerValue.SetUInt64(value);117return emulator.WriteRegister(ctx, eRegisterKindLLDB, lldb_reg,118registerValue);119}120121bool Rd::WriteAPFloat(EmulateInstructionRISCV &emulator, APFloat value) {122uint32_t lldb_reg = FPREncodingToLLDB(rd);123EmulateInstruction::Context ctx;124ctx.type = EmulateInstruction::eContextRegisterStore;125ctx.SetNoArgs();126RegisterValue registerValue;127registerValue.SetUInt64(value.bitcastToAPInt().getZExtValue());128return emulator.WriteRegister(ctx, eRegisterKindLLDB, lldb_reg,129registerValue);130}131132std::optional<uint64_t> Rs::Read(EmulateInstructionRISCV &emulator) {133uint32_t lldbReg = GPREncodingToLLDB(rs);134RegisterValue value;135return emulator.ReadRegister(eRegisterKindLLDB, lldbReg, value)136? std::optional<uint64_t>(value.GetAsUInt64())137: std::nullopt;138}139140std::optional<int32_t> Rs::ReadI32(EmulateInstructionRISCV &emulator) {141return transformOptional(142Read(emulator), [](uint64_t value) { return int32_t(uint32_t(value)); });143}144145std::optional<int64_t> Rs::ReadI64(EmulateInstructionRISCV &emulator) {146return transformOptional(Read(emulator),147[](uint64_t value) { return int64_t(value); });148}149150std::optional<uint32_t> Rs::ReadU32(EmulateInstructionRISCV &emulator) {151return transformOptional(Read(emulator),152[](uint64_t value) { return uint32_t(value); });153}154155std::optional<APFloat> Rs::ReadAPFloat(EmulateInstructionRISCV &emulator,156bool isDouble) {157uint32_t lldbReg = FPREncodingToLLDB(rs);158RegisterValue value;159if (!emulator.ReadRegister(eRegisterKindLLDB, lldbReg, value))160return std::nullopt;161uint64_t bits = value.GetAsUInt64();162APInt api(64, bits, false);163return APFloat(isDouble ? APFloat(api.bitsToDouble())164: APFloat(api.bitsToFloat()));165}166167static bool CompareB(uint64_t rs1, uint64_t rs2, uint32_t funct3) {168switch (funct3) {169case BEQ:170return rs1 == rs2;171case BNE:172return rs1 != rs2;173case BLT:174return int64_t(rs1) < int64_t(rs2);175case BGE:176return int64_t(rs1) >= int64_t(rs2);177case BLTU:178return rs1 < rs2;179case BGEU:180return rs1 >= rs2;181default:182llvm_unreachable("unexpected funct3");183}184}185186template <typename T>187constexpr bool is_load =188std::is_same_v<T, LB> || std::is_same_v<T, LH> || std::is_same_v<T, LW> ||189std::is_same_v<T, LD> || std::is_same_v<T, LBU> || std::is_same_v<T, LHU> ||190std::is_same_v<T, LWU>;191192template <typename T>193constexpr bool is_store = std::is_same_v<T, SB> || std::is_same_v<T, SH> ||194std::is_same_v<T, SW> || std::is_same_v<T, SD>;195196template <typename T>197constexpr bool is_amo_add =198std::is_same_v<T, AMOADD_W> || std::is_same_v<T, AMOADD_D>;199200template <typename T>201constexpr bool is_amo_bit_op =202std::is_same_v<T, AMOXOR_W> || std::is_same_v<T, AMOXOR_D> ||203std::is_same_v<T, AMOAND_W> || std::is_same_v<T, AMOAND_D> ||204std::is_same_v<T, AMOOR_W> || std::is_same_v<T, AMOOR_D>;205206template <typename T>207constexpr bool is_amo_swap =208std::is_same_v<T, AMOSWAP_W> || std::is_same_v<T, AMOSWAP_D>;209210template <typename T>211constexpr bool is_amo_cmp =212std::is_same_v<T, AMOMIN_W> || std::is_same_v<T, AMOMIN_D> ||213std::is_same_v<T, AMOMAX_W> || std::is_same_v<T, AMOMAX_D> ||214std::is_same_v<T, AMOMINU_W> || std::is_same_v<T, AMOMINU_D> ||215std::is_same_v<T, AMOMAXU_W> || std::is_same_v<T, AMOMAXU_D>;216217template <typename I>218static std::enable_if_t<is_load<I> || is_store<I>, std::optional<uint64_t>>219LoadStoreAddr(EmulateInstructionRISCV &emulator, I inst) {220return transformOptional(inst.rs1.Read(emulator), [&](uint64_t rs1) {221return rs1 + uint64_t(SignExt(inst.imm));222});223}224225// Read T from memory, then load its sign-extended value m_emu to register.226template <typename I, typename T, typename E>227static std::enable_if_t<is_load<I>, bool>228Load(EmulateInstructionRISCV &emulator, I inst, uint64_t (*extend)(E)) {229auto addr = LoadStoreAddr(emulator, inst);230if (!addr)231return false;232return transformOptional(233emulator.ReadMem<T>(*addr),234[&](T t) { return inst.rd.Write(emulator, extend(E(t))); })235.value_or(false);236}237238template <typename I, typename T>239static std::enable_if_t<is_store<I>, bool>240Store(EmulateInstructionRISCV &emulator, I inst) {241auto addr = LoadStoreAddr(emulator, inst);242if (!addr)243return false;244return transformOptional(245inst.rs2.Read(emulator),246[&](uint64_t rs2) { return emulator.WriteMem<T>(*addr, rs2); })247.value_or(false);248}249250template <typename I>251static std::enable_if_t<is_amo_add<I> || is_amo_bit_op<I> || is_amo_swap<I> ||252is_amo_cmp<I>,253std::optional<uint64_t>>254AtomicAddr(EmulateInstructionRISCV &emulator, I inst, unsigned int align) {255return transformOptional(inst.rs1.Read(emulator),256[&](uint64_t rs1) {257return rs1 % align == 0258? std::optional<uint64_t>(rs1)259: std::nullopt;260})261.value_or(std::nullopt);262}263264template <typename I, typename T>265static std::enable_if_t<is_amo_swap<I>, bool>266AtomicSwap(EmulateInstructionRISCV &emulator, I inst, int align,267uint64_t (*extend)(T)) {268auto addr = AtomicAddr(emulator, inst, align);269if (!addr)270return false;271return transformOptional(272zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)),273[&](auto &&tup) {274auto [tmp, rs2] = tup;275return emulator.WriteMem<T>(*addr, T(rs2)) &&276inst.rd.Write(emulator, extend(tmp));277})278.value_or(false);279}280281template <typename I, typename T>282static std::enable_if_t<is_amo_add<I>, bool>283AtomicADD(EmulateInstructionRISCV &emulator, I inst, int align,284uint64_t (*extend)(T)) {285auto addr = AtomicAddr(emulator, inst, align);286if (!addr)287return false;288return transformOptional(289zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)),290[&](auto &&tup) {291auto [tmp, rs2] = tup;292return emulator.WriteMem<T>(*addr, T(tmp + rs2)) &&293inst.rd.Write(emulator, extend(tmp));294})295.value_or(false);296}297298template <typename I, typename T>299static std::enable_if_t<is_amo_bit_op<I>, bool>300AtomicBitOperate(EmulateInstructionRISCV &emulator, I inst, int align,301uint64_t (*extend)(T), T (*operate)(T, T)) {302auto addr = AtomicAddr(emulator, inst, align);303if (!addr)304return false;305return transformOptional(306zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)),307[&](auto &&tup) {308auto [value, rs2] = tup;309return emulator.WriteMem<T>(*addr, operate(value, T(rs2))) &&310inst.rd.Write(emulator, extend(value));311})312.value_or(false);313}314315template <typename I, typename T>316static std::enable_if_t<is_amo_cmp<I>, bool>317AtomicCmp(EmulateInstructionRISCV &emulator, I inst, int align,318uint64_t (*extend)(T), T (*cmp)(T, T)) {319auto addr = AtomicAddr(emulator, inst, align);320if (!addr)321return false;322return transformOptional(323zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)),324[&](auto &&tup) {325auto [value, rs2] = tup;326return emulator.WriteMem<T>(*addr, cmp(value, T(rs2))) &&327inst.rd.Write(emulator, extend(value));328})329.value_or(false);330}331332bool AtomicSequence(EmulateInstructionRISCV &emulator) {333// The atomic sequence is always 4 instructions long:334// example:335// 110cc: 100427af lr.w a5,(s0)336// 110d0: 00079663 bnez a5,110dc337// 110d4: 1ce426af sc.w.aq a3,a4,(s0)338// 110d8: fe069ae3 bnez a3,110cc339// 110dc: ........ <next instruction>340const auto pc = emulator.ReadPC();341if (!pc)342return false;343auto current_pc = *pc;344const auto entry_pc = current_pc;345346// The first instruction should be LR.W or LR.D347auto inst = emulator.ReadInstructionAt(current_pc);348if (!inst || (!std::holds_alternative<LR_W>(inst->decoded) &&349!std::holds_alternative<LR_D>(inst->decoded)))350return false;351352// The second instruction should be BNE to exit address353inst = emulator.ReadInstructionAt(current_pc += 4);354if (!inst || !std::holds_alternative<B>(inst->decoded))355return false;356auto bne_exit = std::get<B>(inst->decoded);357if (bne_exit.funct3 != BNE)358return false;359// save the exit address to check later360const auto exit_pc = current_pc + SextW(bne_exit.imm);361362// The third instruction should be SC.W or SC.D363inst = emulator.ReadInstructionAt(current_pc += 4);364if (!inst || (!std::holds_alternative<SC_W>(inst->decoded) &&365!std::holds_alternative<SC_D>(inst->decoded)))366return false;367368// The fourth instruction should be BNE to entry address369inst = emulator.ReadInstructionAt(current_pc += 4);370if (!inst || !std::holds_alternative<B>(inst->decoded))371return false;372auto bne_start = std::get<B>(inst->decoded);373if (bne_start.funct3 != BNE)374return false;375if (entry_pc != current_pc + SextW(bne_start.imm))376return false;377378current_pc += 4;379// check the exit address and jump to it380return exit_pc == current_pc && emulator.WritePC(current_pc);381}382383template <typename T> static RISCVInst DecodeUType(uint32_t inst) {384return T{Rd{DecodeRD(inst)}, DecodeUImm(inst)};385}386387template <typename T> static RISCVInst DecodeJType(uint32_t inst) {388return T{Rd{DecodeRD(inst)}, DecodeJImm(inst)};389}390391template <typename T> static RISCVInst DecodeIType(uint32_t inst) {392return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeIImm(inst)};393}394395template <typename T> static RISCVInst DecodeBType(uint32_t inst) {396return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeBImm(inst),397DecodeFunct3(inst)};398}399400template <typename T> static RISCVInst DecodeSType(uint32_t inst) {401return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeSImm(inst)};402}403404template <typename T> static RISCVInst DecodeRType(uint32_t inst) {405return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}};406}407408template <typename T> static RISCVInst DecodeRShamtType(uint32_t inst) {409return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeRS2(inst)};410}411412template <typename T> static RISCVInst DecodeRRS1Type(uint32_t inst) {413return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}};414}415416template <typename T> static RISCVInst DecodeR4Type(uint32_t inst) {417return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)},418Rs{DecodeRS3(inst)}, DecodeRM(inst)};419}420421static const InstrPattern PATTERNS[] = {422// RV32I & RV64I (The base integer ISA) //423{"LUI", 0x7F, 0x37, DecodeUType<LUI>},424{"AUIPC", 0x7F, 0x17, DecodeUType<AUIPC>},425{"JAL", 0x7F, 0x6F, DecodeJType<JAL>},426{"JALR", 0x707F, 0x67, DecodeIType<JALR>},427{"B", 0x7F, 0x63, DecodeBType<B>},428{"LB", 0x707F, 0x3, DecodeIType<LB>},429{"LH", 0x707F, 0x1003, DecodeIType<LH>},430{"LW", 0x707F, 0x2003, DecodeIType<LW>},431{"LBU", 0x707F, 0x4003, DecodeIType<LBU>},432{"LHU", 0x707F, 0x5003, DecodeIType<LHU>},433{"SB", 0x707F, 0x23, DecodeSType<SB>},434{"SH", 0x707F, 0x1023, DecodeSType<SH>},435{"SW", 0x707F, 0x2023, DecodeSType<SW>},436{"ADDI", 0x707F, 0x13, DecodeIType<ADDI>},437{"SLTI", 0x707F, 0x2013, DecodeIType<SLTI>},438{"SLTIU", 0x707F, 0x3013, DecodeIType<SLTIU>},439{"XORI", 0x707F, 0x4013, DecodeIType<XORI>},440{"ORI", 0x707F, 0x6013, DecodeIType<ORI>},441{"ANDI", 0x707F, 0x7013, DecodeIType<ANDI>},442{"SLLI", 0xF800707F, 0x1013, DecodeRShamtType<SLLI>},443{"SRLI", 0xF800707F, 0x5013, DecodeRShamtType<SRLI>},444{"SRAI", 0xF800707F, 0x40005013, DecodeRShamtType<SRAI>},445{"ADD", 0xFE00707F, 0x33, DecodeRType<ADD>},446{"SUB", 0xFE00707F, 0x40000033, DecodeRType<SUB>},447{"SLL", 0xFE00707F, 0x1033, DecodeRType<SLL>},448{"SLT", 0xFE00707F, 0x2033, DecodeRType<SLT>},449{"SLTU", 0xFE00707F, 0x3033, DecodeRType<SLTU>},450{"XOR", 0xFE00707F, 0x4033, DecodeRType<XOR>},451{"SRL", 0xFE00707F, 0x5033, DecodeRType<SRL>},452{"SRA", 0xFE00707F, 0x40005033, DecodeRType<SRA>},453{"OR", 0xFE00707F, 0x6033, DecodeRType<OR>},454{"AND", 0xFE00707F, 0x7033, DecodeRType<AND>},455{"LWU", 0x707F, 0x6003, DecodeIType<LWU>},456{"LD", 0x707F, 0x3003, DecodeIType<LD>},457{"SD", 0x707F, 0x3023, DecodeSType<SD>},458{"ADDIW", 0x707F, 0x1B, DecodeIType<ADDIW>},459{"SLLIW", 0xFE00707F, 0x101B, DecodeRShamtType<SLLIW>},460{"SRLIW", 0xFE00707F, 0x501B, DecodeRShamtType<SRLIW>},461{"SRAIW", 0xFE00707F, 0x4000501B, DecodeRShamtType<SRAIW>},462{"ADDW", 0xFE00707F, 0x3B, DecodeRType<ADDW>},463{"SUBW", 0xFE00707F, 0x4000003B, DecodeRType<SUBW>},464{"SLLW", 0xFE00707F, 0x103B, DecodeRType<SLLW>},465{"SRLW", 0xFE00707F, 0x503B, DecodeRType<SRLW>},466{"SRAW", 0xFE00707F, 0x4000503B, DecodeRType<SRAW>},467468// RV32M & RV64M (The integer multiplication and division extension) //469{"MUL", 0xFE00707F, 0x2000033, DecodeRType<MUL>},470{"MULH", 0xFE00707F, 0x2001033, DecodeRType<MULH>},471{"MULHSU", 0xFE00707F, 0x2002033, DecodeRType<MULHSU>},472{"MULHU", 0xFE00707F, 0x2003033, DecodeRType<MULHU>},473{"DIV", 0xFE00707F, 0x2004033, DecodeRType<DIV>},474{"DIVU", 0xFE00707F, 0x2005033, DecodeRType<DIVU>},475{"REM", 0xFE00707F, 0x2006033, DecodeRType<REM>},476{"REMU", 0xFE00707F, 0x2007033, DecodeRType<REMU>},477{"MULW", 0xFE00707F, 0x200003B, DecodeRType<MULW>},478{"DIVW", 0xFE00707F, 0x200403B, DecodeRType<DIVW>},479{"DIVUW", 0xFE00707F, 0x200503B, DecodeRType<DIVUW>},480{"REMW", 0xFE00707F, 0x200603B, DecodeRType<REMW>},481{"REMUW", 0xFE00707F, 0x200703B, DecodeRType<REMUW>},482483// RV32A & RV64A (The standard atomic instruction extension) //484{"LR_W", 0xF9F0707F, 0x1000202F, DecodeRRS1Type<LR_W>},485{"LR_D", 0xF9F0707F, 0x1000302F, DecodeRRS1Type<LR_D>},486{"SC_W", 0xF800707F, 0x1800202F, DecodeRType<SC_W>},487{"SC_D", 0xF800707F, 0x1800302F, DecodeRType<SC_D>},488{"AMOSWAP_W", 0xF800707F, 0x800202F, DecodeRType<AMOSWAP_W>},489{"AMOADD_W", 0xF800707F, 0x202F, DecodeRType<AMOADD_W>},490{"AMOXOR_W", 0xF800707F, 0x2000202F, DecodeRType<AMOXOR_W>},491{"AMOAND_W", 0xF800707F, 0x6000202F, DecodeRType<AMOAND_W>},492{"AMOOR_W", 0xF800707F, 0x4000202F, DecodeRType<AMOOR_W>},493{"AMOMIN_W", 0xF800707F, 0x8000202F, DecodeRType<AMOMIN_W>},494{"AMOMAX_W", 0xF800707F, 0xA000202F, DecodeRType<AMOMAX_W>},495{"AMOMINU_W", 0xF800707F, 0xC000202F, DecodeRType<AMOMINU_W>},496{"AMOMAXU_W", 0xF800707F, 0xE000202F, DecodeRType<AMOMAXU_W>},497{"AMOSWAP_D", 0xF800707F, 0x800302F, DecodeRType<AMOSWAP_D>},498{"AMOADD_D", 0xF800707F, 0x302F, DecodeRType<AMOADD_D>},499{"AMOXOR_D", 0xF800707F, 0x2000302F, DecodeRType<AMOXOR_D>},500{"AMOAND_D", 0xF800707F, 0x6000302F, DecodeRType<AMOAND_D>},501{"AMOOR_D", 0xF800707F, 0x4000302F, DecodeRType<AMOOR_D>},502{"AMOMIN_D", 0xF800707F, 0x8000302F, DecodeRType<AMOMIN_D>},503{"AMOMAX_D", 0xF800707F, 0xA000302F, DecodeRType<AMOMAX_D>},504{"AMOMINU_D", 0xF800707F, 0xC000302F, DecodeRType<AMOMINU_D>},505{"AMOMAXU_D", 0xF800707F, 0xE000302F, DecodeRType<AMOMAXU_D>},506507// RVC (Compressed Instructions) //508{"C_LWSP", 0xE003, 0x4002, DecodeC_LWSP},509{"C_LDSP", 0xE003, 0x6002, DecodeC_LDSP, RV64 | RV128},510{"C_SWSP", 0xE003, 0xC002, DecodeC_SWSP},511{"C_SDSP", 0xE003, 0xE002, DecodeC_SDSP, RV64 | RV128},512{"C_LW", 0xE003, 0x4000, DecodeC_LW},513{"C_LD", 0xE003, 0x6000, DecodeC_LD, RV64 | RV128},514{"C_SW", 0xE003, 0xC000, DecodeC_SW},515{"C_SD", 0xE003, 0xE000, DecodeC_SD, RV64 | RV128},516{"C_J", 0xE003, 0xA001, DecodeC_J},517{"C_JR", 0xF07F, 0x8002, DecodeC_JR},518{"C_JALR", 0xF07F, 0x9002, DecodeC_JALR},519{"C_BNEZ", 0xE003, 0xE001, DecodeC_BNEZ},520{"C_BEQZ", 0xE003, 0xC001, DecodeC_BEQZ},521{"C_LI", 0xE003, 0x4001, DecodeC_LI},522{"C_LUI_ADDI16SP", 0xE003, 0x6001, DecodeC_LUI_ADDI16SP},523{"C_ADDI", 0xE003, 0x1, DecodeC_ADDI},524{"C_ADDIW", 0xE003, 0x2001, DecodeC_ADDIW, RV64 | RV128},525{"C_ADDI4SPN", 0xE003, 0x0, DecodeC_ADDI4SPN},526{"C_SLLI", 0xE003, 0x2, DecodeC_SLLI, RV64 | RV128},527{"C_SRLI", 0xEC03, 0x8001, DecodeC_SRLI, RV64 | RV128},528{"C_SRAI", 0xEC03, 0x8401, DecodeC_SRAI, RV64 | RV128},529{"C_ANDI", 0xEC03, 0x8801, DecodeC_ANDI},530{"C_MV", 0xF003, 0x8002, DecodeC_MV},531{"C_ADD", 0xF003, 0x9002, DecodeC_ADD},532{"C_AND", 0xFC63, 0x8C61, DecodeC_AND},533{"C_OR", 0xFC63, 0x8C41, DecodeC_OR},534{"C_XOR", 0xFC63, 0x8C21, DecodeC_XOR},535{"C_SUB", 0xFC63, 0x8C01, DecodeC_SUB},536{"C_SUBW", 0xFC63, 0x9C01, DecodeC_SUBW, RV64 | RV128},537{"C_ADDW", 0xFC63, 0x9C21, DecodeC_ADDW, RV64 | RV128},538// RV32FC //539{"FLW", 0xE003, 0x6000, DecodeC_FLW, RV32},540{"FSW", 0xE003, 0xE000, DecodeC_FSW, RV32},541{"FLWSP", 0xE003, 0x6002, DecodeC_FLWSP, RV32},542{"FSWSP", 0xE003, 0xE002, DecodeC_FSWSP, RV32},543// RVDC //544{"FLDSP", 0xE003, 0x2002, DecodeC_FLDSP, RV32 | RV64},545{"FSDSP", 0xE003, 0xA002, DecodeC_FSDSP, RV32 | RV64},546{"FLD", 0xE003, 0x2000, DecodeC_FLD, RV32 | RV64},547{"FSD", 0xE003, 0xA000, DecodeC_FSD, RV32 | RV64},548549// RV32F (Extension for Single-Precision Floating-Point) //550{"FLW", 0x707F, 0x2007, DecodeIType<FLW>},551{"FSW", 0x707F, 0x2027, DecodeSType<FSW>},552{"FMADD_S", 0x600007F, 0x43, DecodeR4Type<FMADD_S>},553{"FMSUB_S", 0x600007F, 0x47, DecodeR4Type<FMSUB_S>},554{"FNMSUB_S", 0x600007F, 0x4B, DecodeR4Type<FNMSUB_S>},555{"FNMADD_S", 0x600007F, 0x4F, DecodeR4Type<FNMADD_S>},556{"FADD_S", 0xFE00007F, 0x53, DecodeRType<FADD_S>},557{"FSUB_S", 0xFE00007F, 0x8000053, DecodeRType<FSUB_S>},558{"FMUL_S", 0xFE00007F, 0x10000053, DecodeRType<FMUL_S>},559{"FDIV_S", 0xFE00007F, 0x18000053, DecodeRType<FDIV_S>},560{"FSQRT_S", 0xFFF0007F, 0x58000053, DecodeIType<FSQRT_S>},561{"FSGNJ_S", 0xFE00707F, 0x20000053, DecodeRType<FSGNJ_S>},562{"FSGNJN_S", 0xFE00707F, 0x20001053, DecodeRType<FSGNJN_S>},563{"FSGNJX_S", 0xFE00707F, 0x20002053, DecodeRType<FSGNJX_S>},564{"FMIN_S", 0xFE00707F, 0x28000053, DecodeRType<FMIN_S>},565{"FMAX_S", 0xFE00707F, 0x28001053, DecodeRType<FMAX_S>},566{"FCVT_W_S", 0xFFF0007F, 0xC0000053, DecodeIType<FCVT_W_S>},567{"FCVT_WU_S", 0xFFF0007F, 0xC0100053, DecodeIType<FCVT_WU_S>},568{"FMV_X_W", 0xFFF0707F, 0xE0000053, DecodeIType<FMV_X_W>},569{"FEQ_S", 0xFE00707F, 0xA0002053, DecodeRType<FEQ_S>},570{"FLT_S", 0xFE00707F, 0xA0001053, DecodeRType<FLT_S>},571{"FLE_S", 0xFE00707F, 0xA0000053, DecodeRType<FLE_S>},572{"FCLASS_S", 0xFFF0707F, 0xE0001053, DecodeIType<FCLASS_S>},573{"FCVT_S_W", 0xFFF0007F, 0xD0000053, DecodeIType<FCVT_S_W>},574{"FCVT_S_WU", 0xFFF0007F, 0xD0100053, DecodeIType<FCVT_S_WU>},575{"FMV_W_X", 0xFFF0707F, 0xF0000053, DecodeIType<FMV_W_X>},576577// RV64F (Extension for Single-Precision Floating-Point) //578{"FCVT_L_S", 0xFFF0007F, 0xC0200053, DecodeIType<FCVT_L_S>},579{"FCVT_LU_S", 0xFFF0007F, 0xC0300053, DecodeIType<FCVT_LU_S>},580{"FCVT_S_L", 0xFFF0007F, 0xD0200053, DecodeIType<FCVT_S_L>},581{"FCVT_S_LU", 0xFFF0007F, 0xD0300053, DecodeIType<FCVT_S_LU>},582583// RV32D (Extension for Double-Precision Floating-Point) //584{"FLD", 0x707F, 0x3007, DecodeIType<FLD>},585{"FSD", 0x707F, 0x3027, DecodeSType<FSD>},586{"FMADD_D", 0x600007F, 0x2000043, DecodeR4Type<FMADD_D>},587{"FMSUB_D", 0x600007F, 0x2000047, DecodeR4Type<FMSUB_D>},588{"FNMSUB_D", 0x600007F, 0x200004B, DecodeR4Type<FNMSUB_D>},589{"FNMADD_D", 0x600007F, 0x200004F, DecodeR4Type<FNMADD_D>},590{"FADD_D", 0xFE00007F, 0x2000053, DecodeRType<FADD_D>},591{"FSUB_D", 0xFE00007F, 0xA000053, DecodeRType<FSUB_D>},592{"FMUL_D", 0xFE00007F, 0x12000053, DecodeRType<FMUL_D>},593{"FDIV_D", 0xFE00007F, 0x1A000053, DecodeRType<FDIV_D>},594{"FSQRT_D", 0xFFF0007F, 0x5A000053, DecodeIType<FSQRT_D>},595{"FSGNJ_D", 0xFE00707F, 0x22000053, DecodeRType<FSGNJ_D>},596{"FSGNJN_D", 0xFE00707F, 0x22001053, DecodeRType<FSGNJN_D>},597{"FSGNJX_D", 0xFE00707F, 0x22002053, DecodeRType<FSGNJX_D>},598{"FMIN_D", 0xFE00707F, 0x2A000053, DecodeRType<FMIN_D>},599{"FMAX_D", 0xFE00707F, 0x2A001053, DecodeRType<FMAX_D>},600{"FCVT_S_D", 0xFFF0007F, 0x40100053, DecodeIType<FCVT_S_D>},601{"FCVT_D_S", 0xFFF0007F, 0x42000053, DecodeIType<FCVT_D_S>},602{"FEQ_D", 0xFE00707F, 0xA2002053, DecodeRType<FEQ_D>},603{"FLT_D", 0xFE00707F, 0xA2001053, DecodeRType<FLT_D>},604{"FLE_D", 0xFE00707F, 0xA2000053, DecodeRType<FLE_D>},605{"FCLASS_D", 0xFFF0707F, 0xE2001053, DecodeIType<FCLASS_D>},606{"FCVT_W_D", 0xFFF0007F, 0xC2000053, DecodeIType<FCVT_W_D>},607{"FCVT_WU_D", 0xFFF0007F, 0xC2100053, DecodeIType<FCVT_WU_D>},608{"FCVT_D_W", 0xFFF0007F, 0xD2000053, DecodeIType<FCVT_D_W>},609{"FCVT_D_WU", 0xFFF0007F, 0xD2100053, DecodeIType<FCVT_D_WU>},610611// RV64D (Extension for Double-Precision Floating-Point) //612{"FCVT_L_D", 0xFFF0007F, 0xC2200053, DecodeIType<FCVT_L_D>},613{"FCVT_LU_D", 0xFFF0007F, 0xC2300053, DecodeIType<FCVT_LU_D>},614{"FMV_X_D", 0xFFF0707F, 0xE2000053, DecodeIType<FMV_X_D>},615{"FCVT_D_L", 0xFFF0007F, 0xD2200053, DecodeIType<FCVT_D_L>},616{"FCVT_D_LU", 0xFFF0007F, 0xD2300053, DecodeIType<FCVT_D_LU>},617{"FMV_D_X", 0xFFF0707F, 0xF2000053, DecodeIType<FMV_D_X>},618};619620std::optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {621Log *log = GetLog(LLDBLog::Unwind);622623uint16_t try_rvc = uint16_t(inst & 0x0000ffff);624uint8_t inst_type = RV64;625626// Try to get size of RISCV instruction.627// 1.2 Instruction Length Encoding628bool is_16b = (inst & 0b11) != 0b11;629bool is_32b = (inst & 0x1f) != 0x1f;630bool is_48b = (inst & 0x3f) != 0x1f;631bool is_64b = (inst & 0x7f) != 0x3f;632if (is_16b)633m_last_size = 2;634else if (is_32b)635m_last_size = 4;636else if (is_48b)637m_last_size = 6;638else if (is_64b)639m_last_size = 8;640else641// Not Valid642m_last_size = std::nullopt;643644// if we have ArchSpec::eCore_riscv128 in the future,645// we also need to check it here646if (m_arch.GetCore() == ArchSpec::eCore_riscv32)647inst_type = RV32;648649for (const InstrPattern &pat : PATTERNS) {650if ((inst & pat.type_mask) == pat.eigen &&651(inst_type & pat.inst_type) != 0) {652LLDB_LOGF(653log, "EmulateInstructionRISCV::%s: inst(%x at %" PRIx64 ") was decoded to %s",654__FUNCTION__, inst, m_addr, pat.name);655auto decoded = is_16b ? pat.decode(try_rvc) : pat.decode(inst);656return DecodeResult{decoded, inst, is_16b, pat};657}658}659LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(0x%x) was unsupported",660__FUNCTION__, inst);661return std::nullopt;662}663664class Executor {665EmulateInstructionRISCV &m_emu;666bool m_ignore_cond;667bool m_is_rvc;668669public:670// also used in EvaluateInstruction()671static uint64_t size(bool is_rvc) { return is_rvc ? 2 : 4; }672673private:674uint64_t delta() { return size(m_is_rvc); }675676public:677Executor(EmulateInstructionRISCV &emulator, bool ignoreCond, bool is_rvc)678: m_emu(emulator), m_ignore_cond(ignoreCond), m_is_rvc(is_rvc) {}679680bool operator()(LUI inst) { return inst.rd.Write(m_emu, SignExt(inst.imm)); }681bool operator()(AUIPC inst) {682return transformOptional(m_emu.ReadPC(),683[&](uint64_t pc) {684return inst.rd.Write(m_emu,685SignExt(inst.imm) + pc);686})687.value_or(false);688}689bool operator()(JAL inst) {690return transformOptional(m_emu.ReadPC(),691[&](uint64_t pc) {692return inst.rd.Write(m_emu, pc + delta()) &&693m_emu.WritePC(SignExt(inst.imm) + pc);694})695.value_or(false);696}697bool operator()(JALR inst) {698return transformOptional(zipOpt(m_emu.ReadPC(), inst.rs1.Read(m_emu)),699[&](auto &&tup) {700auto [pc, rs1] = tup;701return inst.rd.Write(m_emu, pc + delta()) &&702m_emu.WritePC((SignExt(inst.imm) + rs1) &703~1);704})705.value_or(false);706}707bool operator()(B inst) {708return transformOptional(zipOpt(m_emu.ReadPC(), inst.rs1.Read(m_emu),709inst.rs2.Read(m_emu)),710[&](auto &&tup) {711auto [pc, rs1, rs2] = tup;712if (m_ignore_cond ||713CompareB(rs1, rs2, inst.funct3))714return m_emu.WritePC(SignExt(inst.imm) + pc);715return true;716})717.value_or(false);718}719bool operator()(LB inst) {720return Load<LB, uint8_t, int8_t>(m_emu, inst, SextW);721}722bool operator()(LH inst) {723return Load<LH, uint16_t, int16_t>(m_emu, inst, SextW);724}725bool operator()(LW inst) {726return Load<LW, uint32_t, int32_t>(m_emu, inst, SextW);727}728bool operator()(LBU inst) {729return Load<LBU, uint8_t, uint8_t>(m_emu, inst, ZextD);730}731bool operator()(LHU inst) {732return Load<LHU, uint16_t, uint16_t>(m_emu, inst, ZextD);733}734bool operator()(SB inst) { return Store<SB, uint8_t>(m_emu, inst); }735bool operator()(SH inst) { return Store<SH, uint16_t>(m_emu, inst); }736bool operator()(SW inst) { return Store<SW, uint32_t>(m_emu, inst); }737bool operator()(ADDI inst) {738return transformOptional(inst.rs1.ReadI64(m_emu),739[&](int64_t rs1) {740return inst.rd.Write(741m_emu, rs1 + int64_t(SignExt(inst.imm)));742})743.value_or(false);744}745bool operator()(SLTI inst) {746return transformOptional(inst.rs1.ReadI64(m_emu),747[&](int64_t rs1) {748return inst.rd.Write(749m_emu, rs1 < int64_t(SignExt(inst.imm)));750})751.value_or(false);752}753bool operator()(SLTIU inst) {754return transformOptional(inst.rs1.Read(m_emu),755[&](uint64_t rs1) {756return inst.rd.Write(757m_emu, rs1 < uint64_t(SignExt(inst.imm)));758})759.value_or(false);760}761bool operator()(XORI inst) {762return transformOptional(inst.rs1.Read(m_emu),763[&](uint64_t rs1) {764return inst.rd.Write(765m_emu, rs1 ^ uint64_t(SignExt(inst.imm)));766})767.value_or(false);768}769bool operator()(ORI inst) {770return transformOptional(inst.rs1.Read(m_emu),771[&](uint64_t rs1) {772return inst.rd.Write(773m_emu, rs1 | uint64_t(SignExt(inst.imm)));774})775.value_or(false);776}777bool operator()(ANDI inst) {778return transformOptional(inst.rs1.Read(m_emu),779[&](uint64_t rs1) {780return inst.rd.Write(781m_emu, rs1 & uint64_t(SignExt(inst.imm)));782})783.value_or(false);784}785bool operator()(ADD inst) {786return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),787[&](auto &&tup) {788auto [rs1, rs2] = tup;789return inst.rd.Write(m_emu, rs1 + rs2);790})791.value_or(false);792}793bool operator()(SUB inst) {794return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),795[&](auto &&tup) {796auto [rs1, rs2] = tup;797return inst.rd.Write(m_emu, rs1 - rs2);798})799.value_or(false);800}801bool operator()(SLL inst) {802return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),803[&](auto &&tup) {804auto [rs1, rs2] = tup;805return inst.rd.Write(m_emu,806rs1 << (rs2 & 0b111111));807})808.value_or(false);809}810bool operator()(SLT inst) {811return transformOptional(812zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)),813[&](auto &&tup) {814auto [rs1, rs2] = tup;815return inst.rd.Write(m_emu, rs1 < rs2);816})817.value_or(false);818}819bool operator()(SLTU inst) {820return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),821[&](auto &&tup) {822auto [rs1, rs2] = tup;823return inst.rd.Write(m_emu, rs1 < rs2);824})825.value_or(false);826}827bool operator()(XOR inst) {828return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),829[&](auto &&tup) {830auto [rs1, rs2] = tup;831return inst.rd.Write(m_emu, rs1 ^ rs2);832})833.value_or(false);834}835bool operator()(SRL inst) {836return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),837[&](auto &&tup) {838auto [rs1, rs2] = tup;839return inst.rd.Write(m_emu,840rs1 >> (rs2 & 0b111111));841})842.value_or(false);843}844bool operator()(SRA inst) {845return transformOptional(846zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.Read(m_emu)),847[&](auto &&tup) {848auto [rs1, rs2] = tup;849return inst.rd.Write(m_emu, rs1 >> (rs2 & 0b111111));850})851.value_or(false);852}853bool operator()(OR inst) {854return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),855[&](auto &&tup) {856auto [rs1, rs2] = tup;857return inst.rd.Write(m_emu, rs1 | rs2);858})859.value_or(false);860}861bool operator()(AND inst) {862return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),863[&](auto &&tup) {864auto [rs1, rs2] = tup;865return inst.rd.Write(m_emu, rs1 & rs2);866})867.value_or(false);868}869bool operator()(LWU inst) {870return Load<LWU, uint32_t, uint32_t>(m_emu, inst, ZextD);871}872bool operator()(LD inst) {873return Load<LD, uint64_t, uint64_t>(m_emu, inst, ZextD);874}875bool operator()(SD inst) { return Store<SD, uint64_t>(m_emu, inst); }876bool operator()(SLLI inst) {877return transformOptional(inst.rs1.Read(m_emu),878[&](uint64_t rs1) {879return inst.rd.Write(m_emu, rs1 << inst.shamt);880})881.value_or(false);882}883bool operator()(SRLI inst) {884return transformOptional(inst.rs1.Read(m_emu),885[&](uint64_t rs1) {886return inst.rd.Write(m_emu, rs1 >> inst.shamt);887})888.value_or(false);889}890bool operator()(SRAI inst) {891return transformOptional(inst.rs1.ReadI64(m_emu),892[&](int64_t rs1) {893return inst.rd.Write(m_emu, rs1 >> inst.shamt);894})895.value_or(false);896}897bool operator()(ADDIW inst) {898return transformOptional(inst.rs1.ReadI32(m_emu),899[&](int32_t rs1) {900return inst.rd.Write(901m_emu, SextW(rs1 + SignExt(inst.imm)));902})903.value_or(false);904}905bool operator()(SLLIW inst) {906return transformOptional(inst.rs1.ReadU32(m_emu),907[&](uint32_t rs1) {908return inst.rd.Write(m_emu,909SextW(rs1 << inst.shamt));910})911.value_or(false);912}913bool operator()(SRLIW inst) {914return transformOptional(inst.rs1.ReadU32(m_emu),915[&](uint32_t rs1) {916return inst.rd.Write(m_emu,917SextW(rs1 >> inst.shamt));918})919.value_or(false);920}921bool operator()(SRAIW inst) {922return transformOptional(inst.rs1.ReadI32(m_emu),923[&](int32_t rs1) {924return inst.rd.Write(m_emu,925SextW(rs1 >> inst.shamt));926})927.value_or(false);928}929bool operator()(ADDW inst) {930return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),931[&](auto &&tup) {932auto [rs1, rs2] = tup;933return inst.rd.Write(m_emu,934SextW(uint32_t(rs1 + rs2)));935})936.value_or(false);937}938bool operator()(SUBW inst) {939return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),940[&](auto &&tup) {941auto [rs1, rs2] = tup;942return inst.rd.Write(m_emu,943SextW(uint32_t(rs1 - rs2)));944})945.value_or(false);946}947bool operator()(SLLW inst) {948return transformOptional(949zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),950[&](auto &&tup) {951auto [rs1, rs2] = tup;952return inst.rd.Write(m_emu, SextW(rs1 << (rs2 & 0b11111)));953})954.value_or(false);955}956bool operator()(SRLW inst) {957return transformOptional(958zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),959[&](auto &&tup) {960auto [rs1, rs2] = tup;961return inst.rd.Write(m_emu, SextW(rs1 >> (rs2 & 0b11111)));962})963.value_or(false);964}965bool operator()(SRAW inst) {966return transformOptional(967zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.Read(m_emu)),968[&](auto &&tup) {969auto [rs1, rs2] = tup;970return inst.rd.Write(m_emu, SextW(rs1 >> (rs2 & 0b11111)));971})972.value_or(false);973}974// RV32M & RV64M (Integer Multiplication and Division Extension) //975bool operator()(MUL inst) {976return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),977[&](auto &&tup) {978auto [rs1, rs2] = tup;979return inst.rd.Write(m_emu, rs1 * rs2);980})981.value_or(false);982}983bool operator()(MULH inst) {984return transformOptional(985zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),986[&](auto &&tup) {987auto [rs1, rs2] = tup;988// signed * signed989auto mul = APInt(128, rs1, true) * APInt(128, rs2, true);990return inst.rd.Write(m_emu,991mul.ashr(64).trunc(64).getZExtValue());992})993.value_or(false);994}995bool operator()(MULHSU inst) {996return transformOptional(997zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),998[&](auto &&tup) {999auto [rs1, rs2] = tup;1000// signed * unsigned1001auto mul =1002APInt(128, rs1, true).zext(128) * APInt(128, rs2, false);1003return inst.rd.Write(m_emu,1004mul.lshr(64).trunc(64).getZExtValue());1005})1006.value_or(false);1007}1008bool operator()(MULHU inst) {1009return transformOptional(1010zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1011[&](auto &&tup) {1012auto [rs1, rs2] = tup;1013// unsigned * unsigned1014auto mul = APInt(128, rs1, false) * APInt(128, rs2, false);1015return inst.rd.Write(m_emu,1016mul.lshr(64).trunc(64).getZExtValue());1017})1018.value_or(false);1019}1020bool operator()(DIV inst) {1021return transformOptional(1022zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)),1023[&](auto &&tup) {1024auto [dividend, divisor] = tup;10251026if (divisor == 0)1027return inst.rd.Write(m_emu, UINT64_MAX);10281029if (dividend == INT64_MIN && divisor == -1)1030return inst.rd.Write(m_emu, dividend);10311032return inst.rd.Write(m_emu, dividend / divisor);1033})1034.value_or(false);1035}1036bool operator()(DIVU inst) {1037return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1038[&](auto &&tup) {1039auto [dividend, divisor] = tup;10401041if (divisor == 0)1042return inst.rd.Write(m_emu, UINT64_MAX);10431044return inst.rd.Write(m_emu, dividend / divisor);1045})1046.value_or(false);1047}1048bool operator()(REM inst) {1049return transformOptional(1050zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)),1051[&](auto &&tup) {1052auto [dividend, divisor] = tup;10531054if (divisor == 0)1055return inst.rd.Write(m_emu, dividend);10561057if (dividend == INT64_MIN && divisor == -1)1058return inst.rd.Write(m_emu, 0);10591060return inst.rd.Write(m_emu, dividend % divisor);1061})1062.value_or(false);1063}1064bool operator()(REMU inst) {1065return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),1066[&](auto &&tup) {1067auto [dividend, divisor] = tup;10681069if (divisor == 0)1070return inst.rd.Write(m_emu, dividend);10711072return inst.rd.Write(m_emu, dividend % divisor);1073})1074.value_or(false);1075}1076bool operator()(MULW inst) {1077return transformOptional(1078zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)),1079[&](auto &&tup) {1080auto [rs1, rs2] = tup;1081return inst.rd.Write(m_emu, SextW(rs1 * rs2));1082})1083.value_or(false);1084}1085bool operator()(DIVW inst) {1086return transformOptional(1087zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)),1088[&](auto &&tup) {1089auto [dividend, divisor] = tup;10901091if (divisor == 0)1092return inst.rd.Write(m_emu, UINT64_MAX);10931094if (dividend == INT32_MIN && divisor == -1)1095return inst.rd.Write(m_emu, SextW(dividend));10961097return inst.rd.Write(m_emu, SextW(dividend / divisor));1098})1099.value_or(false);1100}1101bool operator()(DIVUW inst) {1102return transformOptional(1103zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),1104[&](auto &&tup) {1105auto [dividend, divisor] = tup;11061107if (divisor == 0)1108return inst.rd.Write(m_emu, UINT64_MAX);11091110return inst.rd.Write(m_emu, SextW(dividend / divisor));1111})1112.value_or(false);1113}1114bool operator()(REMW inst) {1115return transformOptional(1116zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)),1117[&](auto &&tup) {1118auto [dividend, divisor] = tup;11191120if (divisor == 0)1121return inst.rd.Write(m_emu, SextW(dividend));11221123if (dividend == INT32_MIN && divisor == -1)1124return inst.rd.Write(m_emu, 0);11251126return inst.rd.Write(m_emu, SextW(dividend % divisor));1127})1128.value_or(false);1129}1130bool operator()(REMUW inst) {1131return transformOptional(1132zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),1133[&](auto &&tup) {1134auto [dividend, divisor] = tup;11351136if (divisor == 0)1137return inst.rd.Write(m_emu, SextW(dividend));11381139return inst.rd.Write(m_emu, SextW(dividend % divisor));1140})1141.value_or(false);1142}1143// RV32A & RV64A (The standard atomic instruction extension) //1144bool operator()(LR_W) { return AtomicSequence(m_emu); }1145bool operator()(LR_D) { return AtomicSequence(m_emu); }1146bool operator()(SC_W) {1147llvm_unreachable("should be handled in AtomicSequence");1148}1149bool operator()(SC_D) {1150llvm_unreachable("should be handled in AtomicSequence");1151}1152bool operator()(AMOSWAP_W inst) {1153return AtomicSwap<AMOSWAP_W, uint32_t>(m_emu, inst, 4, SextW);1154}1155bool operator()(AMOADD_W inst) {1156return AtomicADD<AMOADD_W, uint32_t>(m_emu, inst, 4, SextW);1157}1158bool operator()(AMOXOR_W inst) {1159return AtomicBitOperate<AMOXOR_W, uint32_t>(1160m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a ^ b; });1161}1162bool operator()(AMOAND_W inst) {1163return AtomicBitOperate<AMOAND_W, uint32_t>(1164m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a & b; });1165}1166bool operator()(AMOOR_W inst) {1167return AtomicBitOperate<AMOOR_W, uint32_t>(1168m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a | b; });1169}1170bool operator()(AMOMIN_W inst) {1171return AtomicCmp<AMOMIN_W, uint32_t>(1172m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) {1173return uint32_t(std::min(int32_t(a), int32_t(b)));1174});1175}1176bool operator()(AMOMAX_W inst) {1177return AtomicCmp<AMOMAX_W, uint32_t>(1178m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) {1179return uint32_t(std::max(int32_t(a), int32_t(b)));1180});1181}1182bool operator()(AMOMINU_W inst) {1183return AtomicCmp<AMOMINU_W, uint32_t>(1184m_emu, inst, 4, SextW,1185[](uint32_t a, uint32_t b) { return std::min(a, b); });1186}1187bool operator()(AMOMAXU_W inst) {1188return AtomicCmp<AMOMAXU_W, uint32_t>(1189m_emu, inst, 4, SextW,1190[](uint32_t a, uint32_t b) { return std::max(a, b); });1191}1192bool operator()(AMOSWAP_D inst) {1193return AtomicSwap<AMOSWAP_D, uint64_t>(m_emu, inst, 8, ZextD);1194}1195bool operator()(AMOADD_D inst) {1196return AtomicADD<AMOADD_D, uint64_t>(m_emu, inst, 8, ZextD);1197}1198bool operator()(AMOXOR_D inst) {1199return AtomicBitOperate<AMOXOR_D, uint64_t>(1200m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a ^ b; });1201}1202bool operator()(AMOAND_D inst) {1203return AtomicBitOperate<AMOAND_D, uint64_t>(1204m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a & b; });1205}1206bool operator()(AMOOR_D inst) {1207return AtomicBitOperate<AMOOR_D, uint64_t>(1208m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a | b; });1209}1210bool operator()(AMOMIN_D inst) {1211return AtomicCmp<AMOMIN_D, uint64_t>(1212m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) {1213return uint64_t(std::min(int64_t(a), int64_t(b)));1214});1215}1216bool operator()(AMOMAX_D inst) {1217return AtomicCmp<AMOMAX_D, uint64_t>(1218m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) {1219return uint64_t(std::max(int64_t(a), int64_t(b)));1220});1221}1222bool operator()(AMOMINU_D inst) {1223return AtomicCmp<AMOMINU_D, uint64_t>(1224m_emu, inst, 8, ZextD,1225[](uint64_t a, uint64_t b) { return std::min(a, b); });1226}1227bool operator()(AMOMAXU_D inst) {1228return AtomicCmp<AMOMAXU_D, uint64_t>(1229m_emu, inst, 8, ZextD,1230[](uint64_t a, uint64_t b) { return std::max(a, b); });1231}1232template <typename T>1233bool F_Load(T inst, const fltSemantics &(*semantics)(),1234unsigned int numBits) {1235return transformOptional(inst.rs1.Read(m_emu),1236[&](auto &&rs1) {1237uint64_t addr = rs1 + uint64_t(inst.imm);1238uint64_t bits = *m_emu.ReadMem<uint64_t>(addr);1239APFloat f(semantics(), APInt(numBits, bits));1240return inst.rd.WriteAPFloat(m_emu, f);1241})1242.value_or(false);1243}1244bool operator()(FLW inst) { return F_Load(inst, &APFloat::IEEEsingle, 32); }1245template <typename T> bool F_Store(T inst, bool isDouble) {1246return transformOptional(zipOpt(inst.rs1.Read(m_emu),1247inst.rs2.ReadAPFloat(m_emu, isDouble)),1248[&](auto &&tup) {1249auto [rs1, rs2] = tup;1250uint64_t addr = rs1 + uint64_t(inst.imm);1251uint64_t bits =1252rs2.bitcastToAPInt().getZExtValue();1253return m_emu.WriteMem<uint64_t>(addr, bits);1254})1255.value_or(false);1256}1257bool operator()(FSW inst) { return F_Store(inst, false); }1258std::tuple<bool, APFloat> FusedMultiplyAdd(APFloat rs1, APFloat rs2,1259APFloat rs3) {1260auto opStatus = rs1.fusedMultiplyAdd(rs2, rs3, m_emu.GetRoundingMode());1261auto res = m_emu.SetAccruedExceptions(opStatus);1262return {res, rs1};1263}1264template <typename T>1265bool FMA(T inst, bool isDouble, float rs2_sign, float rs3_sign) {1266return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1267inst.rs2.ReadAPFloat(m_emu, isDouble),1268inst.rs3.ReadAPFloat(m_emu, isDouble)),1269[&](auto &&tup) {1270auto [rs1, rs2, rs3] = tup;1271rs2.copySign(APFloat(rs2_sign));1272rs3.copySign(APFloat(rs3_sign));1273auto [res, f] = FusedMultiplyAdd(rs1, rs2, rs3);1274return res && inst.rd.WriteAPFloat(m_emu, f);1275})1276.value_or(false);1277}1278bool operator()(FMADD_S inst) { return FMA(inst, false, 1.0f, 1.0f); }1279bool operator()(FMSUB_S inst) { return FMA(inst, false, 1.0f, -1.0f); }1280bool operator()(FNMSUB_S inst) { return FMA(inst, false, -1.0f, 1.0f); }1281bool operator()(FNMADD_S inst) { return FMA(inst, false, -1.0f, -1.0f); }1282template <typename T>1283bool F_Op(T inst, bool isDouble,1284APFloat::opStatus (APFloat::*f)(const APFloat &RHS,1285APFloat::roundingMode RM)) {1286return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1287inst.rs2.ReadAPFloat(m_emu, isDouble)),1288[&](auto &&tup) {1289auto [rs1, rs2] = tup;1290auto res =1291((&rs1)->*f)(rs2, m_emu.GetRoundingMode());1292inst.rd.WriteAPFloat(m_emu, rs1);1293return m_emu.SetAccruedExceptions(res);1294})1295.value_or(false);1296}1297bool operator()(FADD_S inst) { return F_Op(inst, false, &APFloat::add); }1298bool operator()(FSUB_S inst) { return F_Op(inst, false, &APFloat::subtract); }1299bool operator()(FMUL_S inst) { return F_Op(inst, false, &APFloat::multiply); }1300bool operator()(FDIV_S inst) { return F_Op(inst, false, &APFloat::divide); }1301bool operator()(FSQRT_S inst) {1302// TODO: APFloat doesn't have a sqrt function.1303return false;1304}1305template <typename T> bool F_SignInj(T inst, bool isDouble, bool isNegate) {1306return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1307inst.rs2.ReadAPFloat(m_emu, isDouble)),1308[&](auto &&tup) {1309auto [rs1, rs2] = tup;1310if (isNegate)1311rs2.changeSign();1312rs1.copySign(rs2);1313return inst.rd.WriteAPFloat(m_emu, rs1);1314})1315.value_or(false);1316}1317bool operator()(FSGNJ_S inst) { return F_SignInj(inst, false, false); }1318bool operator()(FSGNJN_S inst) { return F_SignInj(inst, false, true); }1319template <typename T> bool F_SignInjXor(T inst, bool isDouble) {1320return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1321inst.rs2.ReadAPFloat(m_emu, isDouble)),1322[&](auto &&tup) {1323auto [rs1, rs2] = tup;1324// spec: the sign bit is the XOR of the sign bits1325// of rs1 and rs2. if rs1 and rs2 have the same1326// signs set rs1 to positive else set rs1 to1327// negative1328if (rs1.isNegative() == rs2.isNegative()) {1329rs1.clearSign();1330} else {1331rs1.clearSign();1332rs1.changeSign();1333}1334return inst.rd.WriteAPFloat(m_emu, rs1);1335})1336.value_or(false);1337}1338bool operator()(FSGNJX_S inst) { return F_SignInjXor(inst, false); }1339template <typename T>1340bool F_MAX_MIN(T inst, bool isDouble,1341APFloat (*f)(const APFloat &A, const APFloat &B)) {1342return transformOptional(1343zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1344inst.rs2.ReadAPFloat(m_emu, isDouble)),1345[&](auto &&tup) {1346auto [rs1, rs2] = tup;1347// If both inputs are NaNs, the result is the canonical NaN.1348// If only one operand is a NaN, the result is the non-NaN1349// operand. Signaling NaN inputs set the invalid operation1350// exception flag, even when the result is not NaN.1351if (rs1.isNaN() || rs2.isNaN())1352m_emu.SetAccruedExceptions(APFloat::opInvalidOp);1353if (rs1.isNaN() && rs2.isNaN()) {1354auto canonicalNaN = APFloat::getQNaN(rs1.getSemantics());1355return inst.rd.WriteAPFloat(m_emu, canonicalNaN);1356}1357return inst.rd.WriteAPFloat(m_emu, f(rs1, rs2));1358})1359.value_or(false);1360}1361bool operator()(FMIN_S inst) { return F_MAX_MIN(inst, false, minnum); }1362bool operator()(FMAX_S inst) { return F_MAX_MIN(inst, false, maxnum); }1363bool operator()(FCVT_W_S inst) {1364return FCVT_i2f<FCVT_W_S, int32_t, float>(inst, false,1365&APFloat::convertToFloat);1366}1367bool operator()(FCVT_WU_S inst) {1368return FCVT_i2f<FCVT_WU_S, uint32_t, float>(inst, false,1369&APFloat::convertToFloat);1370}1371template <typename T> bool FMV_f2i(T inst, bool isDouble) {1372return transformOptional(1373inst.rs1.ReadAPFloat(m_emu, isDouble),1374[&](auto &&rs1) {1375if (rs1.isNaN()) {1376if (isDouble)1377return inst.rd.Write(m_emu, 0x7ff8'0000'0000'0000);1378else1379return inst.rd.Write(m_emu, 0x7fc0'0000);1380}1381auto bits = rs1.bitcastToAPInt().getZExtValue();1382if (isDouble)1383return inst.rd.Write(m_emu, bits);1384else1385return inst.rd.Write(m_emu, uint64_t(bits & 0xffff'ffff));1386})1387.value_or(false);1388}1389bool operator()(FMV_X_W inst) { return FMV_f2i(inst, false); }1390enum F_CMP {1391FEQ,1392FLT,1393FLE,1394};1395template <typename T> bool F_Compare(T inst, bool isDouble, F_CMP cmp) {1396return transformOptional(1397zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),1398inst.rs2.ReadAPFloat(m_emu, isDouble)),1399[&](auto &&tup) {1400auto [rs1, rs2] = tup;1401if (rs1.isNaN() || rs2.isNaN()) {1402if (cmp == FEQ) {1403if (rs1.isSignaling() || rs2.isSignaling()) {1404auto res =1405m_emu.SetAccruedExceptions(APFloat::opInvalidOp);1406return res && inst.rd.Write(m_emu, 0);1407}1408}1409auto res = m_emu.SetAccruedExceptions(APFloat::opInvalidOp);1410return res && inst.rd.Write(m_emu, 0);1411}1412switch (cmp) {1413case FEQ:1414return inst.rd.Write(m_emu,1415rs1.compare(rs2) == APFloat::cmpEqual);1416case FLT:1417return inst.rd.Write(m_emu, rs1.compare(rs2) ==1418APFloat::cmpLessThan);1419case FLE:1420return inst.rd.Write(m_emu, rs1.compare(rs2) !=1421APFloat::cmpGreaterThan);1422}1423llvm_unreachable("unsupported F_CMP");1424})1425.value_or(false);1426}14271428bool operator()(FEQ_S inst) { return F_Compare(inst, false, FEQ); }1429bool operator()(FLT_S inst) { return F_Compare(inst, false, FLT); }1430bool operator()(FLE_S inst) { return F_Compare(inst, false, FLE); }1431template <typename T> bool FCLASS(T inst, bool isDouble) {1432return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble),1433[&](auto &&rs1) {1434uint64_t result = 0;1435if (rs1.isInfinity() && rs1.isNegative())1436result |= 1 << 0;1437// neg normal1438if (rs1.isNormal() && rs1.isNegative())1439result |= 1 << 1;1440// neg subnormal1441if (rs1.isDenormal() && rs1.isNegative())1442result |= 1 << 2;1443if (rs1.isNegZero())1444result |= 1 << 3;1445if (rs1.isPosZero())1446result |= 1 << 4;1447// pos normal1448if (rs1.isNormal() && !rs1.isNegative())1449result |= 1 << 5;1450// pos subnormal1451if (rs1.isDenormal() && !rs1.isNegative())1452result |= 1 << 6;1453if (rs1.isInfinity() && !rs1.isNegative())1454result |= 1 << 7;1455if (rs1.isNaN()) {1456if (rs1.isSignaling())1457result |= 1 << 8;1458else1459result |= 1 << 9;1460}1461return inst.rd.Write(m_emu, result);1462})1463.value_or(false);1464}1465bool operator()(FCLASS_S inst) { return FCLASS(inst, false); }1466template <typename T, typename E>1467bool FCVT_f2i(T inst, std::optional<E> (Rs::*f)(EmulateInstructionRISCV &emu),1468const fltSemantics &semantics) {1469return transformOptional(((&inst.rs1)->*f)(m_emu),1470[&](auto &&rs1) {1471APFloat apf(semantics, rs1);1472return inst.rd.WriteAPFloat(m_emu, apf);1473})1474.value_or(false);1475}1476bool operator()(FCVT_S_W inst) {1477return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEsingle());1478}1479bool operator()(FCVT_S_WU inst) {1480return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEsingle());1481}1482template <typename T, typename E>1483bool FMV_i2f(T inst, unsigned int numBits, E (APInt::*f)() const) {1484return transformOptional(inst.rs1.Read(m_emu),1485[&](auto &&rs1) {1486APInt apInt(numBits, rs1);1487if (numBits == 32) // a.k.a. float1488apInt = APInt(numBits, NanUnBoxing(rs1));1489APFloat apf((&apInt->*f)());1490return inst.rd.WriteAPFloat(m_emu, apf);1491})1492.value_or(false);1493}1494bool operator()(FMV_W_X inst) {1495return FMV_i2f(inst, 32, &APInt::bitsToFloat);1496}1497template <typename I, typename E, typename T>1498bool FCVT_i2f(I inst, bool isDouble, T (APFloat::*f)() const) {1499return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble),1500[&](auto &&rs1) {1501E res = E((&rs1->*f)());1502return inst.rd.Write(m_emu, uint64_t(res));1503})1504.value_or(false);1505}1506bool operator()(FCVT_L_S inst) {1507return FCVT_i2f<FCVT_L_S, int64_t, float>(inst, false,1508&APFloat::convertToFloat);1509}1510bool operator()(FCVT_LU_S inst) {1511return FCVT_i2f<FCVT_LU_S, uint64_t, float>(inst, false,1512&APFloat::convertToFloat);1513}1514bool operator()(FCVT_S_L inst) {1515return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEsingle());1516}1517bool operator()(FCVT_S_LU inst) {1518return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEsingle());1519}1520bool operator()(FLD inst) { return F_Load(inst, &APFloat::IEEEdouble, 64); }1521bool operator()(FSD inst) { return F_Store(inst, true); }1522bool operator()(FMADD_D inst) { return FMA(inst, true, 1.0f, 1.0f); }1523bool operator()(FMSUB_D inst) { return FMA(inst, true, 1.0f, -1.0f); }1524bool operator()(FNMSUB_D inst) { return FMA(inst, true, -1.0f, 1.0f); }1525bool operator()(FNMADD_D inst) { return FMA(inst, true, -1.0f, -1.0f); }1526bool operator()(FADD_D inst) { return F_Op(inst, true, &APFloat::add); }1527bool operator()(FSUB_D inst) { return F_Op(inst, true, &APFloat::subtract); }1528bool operator()(FMUL_D inst) { return F_Op(inst, true, &APFloat::multiply); }1529bool operator()(FDIV_D inst) { return F_Op(inst, true, &APFloat::divide); }1530bool operator()(FSQRT_D inst) {1531// TODO: APFloat doesn't have a sqrt function.1532return false;1533}1534bool operator()(FSGNJ_D inst) { return F_SignInj(inst, true, false); }1535bool operator()(FSGNJN_D inst) { return F_SignInj(inst, true, true); }1536bool operator()(FSGNJX_D inst) { return F_SignInjXor(inst, true); }1537bool operator()(FMIN_D inst) { return F_MAX_MIN(inst, true, minnum); }1538bool operator()(FMAX_D inst) { return F_MAX_MIN(inst, true, maxnum); }1539bool operator()(FCVT_S_D inst) {1540return transformOptional(inst.rs1.ReadAPFloat(m_emu, true),1541[&](auto &&rs1) {1542double d = rs1.convertToDouble();1543APFloat apf((float(d)));1544return inst.rd.WriteAPFloat(m_emu, apf);1545})1546.value_or(false);1547}1548bool operator()(FCVT_D_S inst) {1549return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),1550[&](auto &&rs1) {1551float f = rs1.convertToFloat();1552APFloat apf((double(f)));1553return inst.rd.WriteAPFloat(m_emu, apf);1554})1555.value_or(false);1556}1557bool operator()(FEQ_D inst) { return F_Compare(inst, true, FEQ); }1558bool operator()(FLT_D inst) { return F_Compare(inst, true, FLT); }1559bool operator()(FLE_D inst) { return F_Compare(inst, true, FLE); }1560bool operator()(FCLASS_D inst) { return FCLASS(inst, true); }1561bool operator()(FCVT_W_D inst) {1562return FCVT_i2f<FCVT_W_D, int32_t, double>(inst, true,1563&APFloat::convertToDouble);1564}1565bool operator()(FCVT_WU_D inst) {1566return FCVT_i2f<FCVT_WU_D, uint32_t, double>(inst, true,1567&APFloat::convertToDouble);1568}1569bool operator()(FCVT_D_W inst) {1570return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEdouble());1571}1572bool operator()(FCVT_D_WU inst) {1573return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEdouble());1574}1575bool operator()(FCVT_L_D inst) {1576return FCVT_i2f<FCVT_L_D, int64_t, double>(inst, true,1577&APFloat::convertToDouble);1578}1579bool operator()(FCVT_LU_D inst) {1580return FCVT_i2f<FCVT_LU_D, uint64_t, double>(inst, true,1581&APFloat::convertToDouble);1582}1583bool operator()(FMV_X_D inst) { return FMV_f2i(inst, true); }1584bool operator()(FCVT_D_L inst) {1585return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEdouble());1586}1587bool operator()(FCVT_D_LU inst) {1588return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEdouble());1589}1590bool operator()(FMV_D_X inst) {1591return FMV_i2f(inst, 64, &APInt::bitsToDouble);1592}1593bool operator()(INVALID inst) { return false; }1594bool operator()(RESERVED inst) { return false; }1595bool operator()(EBREAK inst) { return false; }1596bool operator()(HINT inst) { return true; }1597bool operator()(NOP inst) { return true; }1598};15991600bool EmulateInstructionRISCV::Execute(DecodeResult inst, bool ignore_cond) {1601return std::visit(Executor(*this, ignore_cond, inst.is_rvc), inst.decoded);1602}16031604bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) {1605bool increase_pc = options & eEmulateInstructionOptionAutoAdvancePC;1606bool ignore_cond = options & eEmulateInstructionOptionIgnoreConditions;16071608if (!increase_pc)1609return Execute(m_decoded, ignore_cond);16101611auto old_pc = ReadPC();1612if (!old_pc)1613return false;16141615bool success = Execute(m_decoded, ignore_cond);1616if (!success)1617return false;16181619auto new_pc = ReadPC();1620if (!new_pc)1621return false;16221623// If the pc is not updated during execution, we do it here.1624return new_pc != old_pc ||1625WritePC(*old_pc + Executor::size(m_decoded.is_rvc));1626}16271628std::optional<DecodeResult>1629EmulateInstructionRISCV::ReadInstructionAt(addr_t addr) {1630return transformOptional(ReadMem<uint32_t>(addr),1631[&](uint32_t inst) { return Decode(inst); })1632.value_or(std::nullopt);1633}16341635bool EmulateInstructionRISCV::ReadInstruction() {1636auto addr = ReadPC();1637m_addr = addr.value_or(LLDB_INVALID_ADDRESS);1638if (!addr)1639return false;1640auto inst = ReadInstructionAt(*addr);1641if (!inst)1642return false;1643m_decoded = *inst;1644if (inst->is_rvc)1645m_opcode.SetOpcode16(inst->inst, GetByteOrder());1646else1647m_opcode.SetOpcode32(inst->inst, GetByteOrder());1648return true;1649}16501651std::optional<addr_t> EmulateInstructionRISCV::ReadPC() {1652bool success = false;1653auto addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,1654LLDB_INVALID_ADDRESS, &success);1655return success ? std::optional<addr_t>(addr) : std::nullopt;1656}16571658bool EmulateInstructionRISCV::WritePC(addr_t pc) {1659EmulateInstruction::Context ctx;1660ctx.type = eContextAdvancePC;1661ctx.SetNoArgs();1662return WriteRegisterUnsigned(ctx, eRegisterKindGeneric,1663LLDB_REGNUM_GENERIC_PC, pc);1664}16651666RoundingMode EmulateInstructionRISCV::GetRoundingMode() {1667bool success = false;1668auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,1669LLDB_INVALID_ADDRESS, &success);1670if (!success)1671return RoundingMode::Invalid;1672auto frm = (fcsr >> 5) & 0x7;1673switch (frm) {1674case 0b000:1675return RoundingMode::NearestTiesToEven;1676case 0b001:1677return RoundingMode::TowardZero;1678case 0b010:1679return RoundingMode::TowardNegative;1680case 0b011:1681return RoundingMode::TowardPositive;1682case 0b111:1683return RoundingMode::Dynamic;1684default:1685// Reserved for future use.1686return RoundingMode::Invalid;1687}1688}16891690bool EmulateInstructionRISCV::SetAccruedExceptions(1691APFloatBase::opStatus opStatus) {1692bool success = false;1693auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,1694LLDB_INVALID_ADDRESS, &success);1695if (!success)1696return false;1697switch (opStatus) {1698case APFloatBase::opInvalidOp:1699fcsr |= 1 << 4;1700break;1701case APFloatBase::opDivByZero:1702fcsr |= 1 << 3;1703break;1704case APFloatBase::opOverflow:1705fcsr |= 1 << 2;1706break;1707case APFloatBase::opUnderflow:1708fcsr |= 1 << 1;1709break;1710case APFloatBase::opInexact:1711fcsr |= 1 << 0;1712break;1713case APFloatBase::opOK:1714break;1715}1716EmulateInstruction::Context ctx;1717ctx.type = eContextRegisterStore;1718ctx.SetNoArgs();1719return WriteRegisterUnsigned(ctx, eRegisterKindLLDB, fpr_fcsr_riscv, fcsr);1720}17211722std::optional<RegisterInfo>1723EmulateInstructionRISCV::GetRegisterInfo(RegisterKind reg_kind,1724uint32_t reg_index) {1725if (reg_kind == eRegisterKindGeneric) {1726switch (reg_index) {1727case LLDB_REGNUM_GENERIC_PC:1728reg_kind = eRegisterKindLLDB;1729reg_index = gpr_pc_riscv;1730break;1731case LLDB_REGNUM_GENERIC_SP:1732reg_kind = eRegisterKindLLDB;1733reg_index = gpr_sp_riscv;1734break;1735case LLDB_REGNUM_GENERIC_FP:1736reg_kind = eRegisterKindLLDB;1737reg_index = gpr_fp_riscv;1738break;1739case LLDB_REGNUM_GENERIC_RA:1740reg_kind = eRegisterKindLLDB;1741reg_index = gpr_ra_riscv;1742break;1743// We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are1744// supported.1745default:1746llvm_unreachable("unsupported register");1747}1748}17491750const RegisterInfo *array =1751RegisterInfoPOSIX_riscv64::GetRegisterInfoPtr(m_arch);1752const uint32_t length =1753RegisterInfoPOSIX_riscv64::GetRegisterInfoCount(m_arch);17541755if (reg_index >= length || reg_kind != eRegisterKindLLDB)1756return {};17571758return array[reg_index];1759}17601761bool EmulateInstructionRISCV::SetTargetTriple(const ArchSpec &arch) {1762return SupportsThisArch(arch);1763}17641765bool EmulateInstructionRISCV::TestEmulation(Stream &out_stream, ArchSpec &arch,1766OptionValueDictionary *test_data) {1767return false;1768}17691770void EmulateInstructionRISCV::Initialize() {1771PluginManager::RegisterPlugin(GetPluginNameStatic(),1772GetPluginDescriptionStatic(), CreateInstance);1773}17741775void EmulateInstructionRISCV::Terminate() {1776PluginManager::UnregisterPlugin(CreateInstance);1777}17781779lldb_private::EmulateInstruction *1780EmulateInstructionRISCV::CreateInstance(const ArchSpec &arch,1781InstructionType inst_type) {1782if (EmulateInstructionRISCV::SupportsThisInstructionType(inst_type) &&1783SupportsThisArch(arch)) {1784return new EmulateInstructionRISCV(arch);1785}17861787return nullptr;1788}17891790bool EmulateInstructionRISCV::SupportsThisArch(const ArchSpec &arch) {1791return arch.GetTriple().isRISCV();1792}17931794} // namespace lldb_private179517961797