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