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