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