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