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