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 
28 using namespace llvm;
29 using namespace lldb;
30 using namespace lldb_private;
31 
32 LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionRISCV, InstructionRISCV)
33 
34 namespace lldb_private {
35 
36 /// Returns all values wrapped in Optional, or std::nullopt if any of the values
37 /// is std::nullopt.
38 template <typename... Ts>
39 static 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.
49 constexpr uint32_t BEQ = 0b000;
50 constexpr uint32_t BNE = 0b001;
51 constexpr uint32_t BLT = 0b100;
52 constexpr uint32_t BGE = 0b101;
53 constexpr uint32_t BLTU = 0b110;
54 constexpr uint32_t BGEU = 0b111;
55 
56 // used in decoder
57 constexpr int32_t SignExt(uint32_t imm) { return int32_t(imm); }
58 
59 // used in executor
60 template <typename T>
61 constexpr 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
66 template <typename T> constexpr uint64_t ZextD(T value) {
67   return uint64_t(value);
68 }
69 
70 constexpr 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 
77 constexpr uint32_t DecodeIImm(uint32_t inst) {
78   return int64_t(int32_t(inst)) >> 20; // imm[11:0]
79 }
80 
81 constexpr 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 
88 constexpr 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 
93 constexpr uint32_t DecodeUImm(uint32_t inst) {
94   return SextW(inst & 0xFFFFF000); // imm[31:12]
95 }
96 
97 static 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 
105 static 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 
111 bool 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 
122 bool 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 
133 std::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 
141 std::optional<int32_t> Rs::ReadI32(EmulateInstructionRISCV &emulator) {
142   return transformOptional(
143       Read(emulator), [](uint64_t value) { return int32_t(uint32_t(value)); });
144 }
145 
146 std::optional<int64_t> Rs::ReadI64(EmulateInstructionRISCV &emulator) {
147   return transformOptional(Read(emulator),
148                            [](uint64_t value) { return int64_t(value); });
149 }
150 
151 std::optional<uint32_t> Rs::ReadU32(EmulateInstructionRISCV &emulator) {
152   return transformOptional(Read(emulator),
153                            [](uint64_t value) { return uint32_t(value); });
154 }
155 
156 std::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 
168 static 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 
187 template <typename T>
188 constexpr 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 
193 template <typename T>
194 constexpr 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 
197 template <typename T>
198 constexpr bool is_amo_add =
199     std::is_same_v<T, AMOADD_W> || std::is_same_v<T, AMOADD_D>;
200 
201 template <typename T>
202 constexpr 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 
207 template <typename T>
208 constexpr bool is_amo_swap =
209     std::is_same_v<T, AMOSWAP_W> || std::is_same_v<T, AMOSWAP_D>;
210 
211 template <typename T>
212 constexpr 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 
218 template <typename I>
219 static std::enable_if_t<is_load<I> || is_store<I>, std::optional<uint64_t>>
220 LoadStoreAddr(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.
227 template <typename I, typename T, typename E>
228 static std::enable_if_t<is_load<I>, bool>
229 Load(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 
239 template <typename I, typename T>
240 static std::enable_if_t<is_store<I>, bool>
241 Store(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 
251 template <typename I>
252 static 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>>
255 AtomicAddr(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 
265 template <typename I, typename T>
266 static std::enable_if_t<is_amo_swap<I>, bool>
267 AtomicSwap(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 
282 template <typename I, typename T>
283 static std::enable_if_t<is_amo_add<I>, bool>
284 AtomicADD(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 
299 template <typename I, typename T>
300 static std::enable_if_t<is_amo_bit_op<I>, bool>
301 AtomicBitOperate(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 
316 template <typename I, typename T>
317 static std::enable_if_t<is_amo_cmp<I>, bool>
318 AtomicCmp(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 
333 bool 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 
384 template <typename T> static RISCVInst DecodeUType(uint32_t inst) {
385   return T{Rd{DecodeRD(inst)}, DecodeUImm(inst)};
386 }
387 
388 template <typename T> static RISCVInst DecodeJType(uint32_t inst) {
389   return T{Rd{DecodeRD(inst)}, DecodeJImm(inst)};
390 }
391 
392 template <typename T> static RISCVInst DecodeIType(uint32_t inst) {
393   return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeIImm(inst)};
394 }
395 
396 template <typename T> static RISCVInst DecodeBType(uint32_t inst) {
397   return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeBImm(inst),
398            DecodeFunct3(inst)};
399 }
400 
401 template <typename T> static RISCVInst DecodeSType(uint32_t inst) {
402   return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeSImm(inst)};
403 }
404 
405 template <typename T> static RISCVInst DecodeRType(uint32_t inst) {
406   return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}};
407 }
408 
409 template <typename T> static RISCVInst DecodeRShamtType(uint32_t inst) {
410   return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeRS2(inst)};
411 }
412 
413 template <typename T> static RISCVInst DecodeRRS1Type(uint32_t inst) {
414   return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}};
415 }
416 
417 template <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 
422 static 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 
621 std::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 %" PRIx64 ") 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 
650 class Executor {
651   EmulateInstructionRISCV &m_emu;
652   bool m_ignore_cond;
653   bool m_is_rvc;
654 
655 public:
656   // also used in EvaluateInstruction()
657   static uint64_t size(bool is_rvc) { return is_rvc ? 2 : 4; }
658 
659 private:
660   uint64_t delta() { return size(m_is_rvc); }
661 
662 public:
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 
1586 bool EmulateInstructionRISCV::Execute(DecodeResult inst, bool ignore_cond) {
1587   return std::visit(Executor(*this, ignore_cond, inst.is_rvc), inst.decoded);
1588 }
1589 
1590 bool 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 
1614 std::optional<DecodeResult>
1615 EmulateInstructionRISCV::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 
1621 bool 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 
1637 std::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 
1644 bool 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 
1652 RoundingMode 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 
1676 bool 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 
1708 std::optional<RegisterInfo>
1709 EmulateInstructionRISCV::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 
1747 bool EmulateInstructionRISCV::SetTargetTriple(const ArchSpec &arch) {
1748   return SupportsThisArch(arch);
1749 }
1750 
1751 bool EmulateInstructionRISCV::TestEmulation(Stream &out_stream, ArchSpec &arch,
1752                                             OptionValueDictionary *test_data) {
1753   return false;
1754 }
1755 
1756 void EmulateInstructionRISCV::Initialize() {
1757   PluginManager::RegisterPlugin(GetPluginNameStatic(),
1758                                 GetPluginDescriptionStatic(), CreateInstance);
1759 }
1760 
1761 void EmulateInstructionRISCV::Terminate() {
1762   PluginManager::UnregisterPlugin(CreateInstance);
1763 }
1764 
1765 lldb_private::EmulateInstruction *
1766 EmulateInstructionRISCV::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 
1776 bool EmulateInstructionRISCV::SupportsThisArch(const ArchSpec &arch) {
1777   return arch.GetTriple().isRISCV();
1778 }
1779 
1780 } // namespace lldb_private
1781