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