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