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