Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
39648 views
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>
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
57
constexpr int32_t SignExt(uint32_t imm) { return int32_t(imm); }
58
59
// used in executor
60
template <typename T>
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
66
template <typename T> constexpr uint64_t ZextD(T value) {
67
return uint64_t(value);
68
}
69
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
77
constexpr uint32_t DecodeIImm(uint32_t inst) {
78
return int64_t(int32_t(inst)) >> 20; // imm[11:0]
79
}
80
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
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
93
constexpr uint32_t DecodeUImm(uint32_t inst) {
94
return SextW(inst & 0xFFFFF000); // imm[31:12]
95
}
96
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
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
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
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
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
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
146
std::optional<int64_t> Rs::ReadI64(EmulateInstructionRISCV &emulator) {
147
return transformOptional(Read(emulator),
148
[](uint64_t value) { return int64_t(value); });
149
}
150
151
std::optional<uint32_t> Rs::ReadU32(EmulateInstructionRISCV &emulator) {
152
return transformOptional(Read(emulator),
153
[](uint64_t value) { return uint32_t(value); });
154
}
155
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
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>>
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>
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>
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>>
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>
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>
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>
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>
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
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
384
template <typename T> static RISCVInst DecodeUType(uint32_t inst) {
385
return T{Rd{DecodeRD(inst)}, DecodeUImm(inst)};
386
}
387
388
template <typename T> static RISCVInst DecodeJType(uint32_t inst) {
389
return T{Rd{DecodeRD(inst)}, DecodeJImm(inst)};
390
}
391
392
template <typename T> static RISCVInst DecodeIType(uint32_t inst) {
393
return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeIImm(inst)};
394
}
395
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
401
template <typename T> static RISCVInst DecodeSType(uint32_t inst) {
402
return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeSImm(inst)};
403
}
404
405
template <typename T> static RISCVInst DecodeRType(uint32_t inst) {
406
return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}};
407
}
408
409
template <typename T> static RISCVInst DecodeRShamtType(uint32_t inst) {
410
return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeRS2(inst)};
411
}
412
413
template <typename T> static RISCVInst DecodeRRS1Type(uint32_t inst) {
414
return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}};
415
}
416
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
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
uint8_t inst_type = RV64;
626
627
// Try to get size of RISCV instruction.
628
// 1.2 Instruction Length Encoding
629
bool is_16b = (inst & 0b11) != 0b11;
630
bool is_32b = (inst & 0x1f) != 0x1f;
631
bool is_48b = (inst & 0x3f) != 0x1f;
632
bool is_64b = (inst & 0x7f) != 0x3f;
633
if (is_16b)
634
m_last_size = 2;
635
else if (is_32b)
636
m_last_size = 4;
637
else if (is_48b)
638
m_last_size = 6;
639
else if (is_64b)
640
m_last_size = 8;
641
else
642
// Not Valid
643
m_last_size = std::nullopt;
644
645
// if we have ArchSpec::eCore_riscv128 in the future,
646
// we also need to check it here
647
if (m_arch.GetCore() == ArchSpec::eCore_riscv32)
648
inst_type = RV32;
649
650
for (const InstrPattern &pat : PATTERNS) {
651
if ((inst & pat.type_mask) == pat.eigen &&
652
(inst_type & pat.inst_type) != 0) {
653
LLDB_LOGF(
654
log, "EmulateInstructionRISCV::%s: inst(%x at %" PRIx64 ") was decoded to %s",
655
__FUNCTION__, inst, m_addr, pat.name);
656
auto decoded = is_16b ? pat.decode(try_rvc) : pat.decode(inst);
657
return DecodeResult{decoded, inst, is_16b, pat};
658
}
659
}
660
LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(0x%x) was unsupported",
661
__FUNCTION__, inst);
662
return std::nullopt;
663
}
664
665
class Executor {
666
EmulateInstructionRISCV &m_emu;
667
bool m_ignore_cond;
668
bool m_is_rvc;
669
670
public:
671
// also used in EvaluateInstruction()
672
static uint64_t size(bool is_rvc) { return is_rvc ? 2 : 4; }
673
674
private:
675
uint64_t delta() { return size(m_is_rvc); }
676
677
public:
678
Executor(EmulateInstructionRISCV &emulator, bool ignoreCond, bool is_rvc)
679
: m_emu(emulator), m_ignore_cond(ignoreCond), m_is_rvc(is_rvc) {}
680
681
bool operator()(LUI inst) { return inst.rd.Write(m_emu, SignExt(inst.imm)); }
682
bool operator()(AUIPC inst) {
683
return transformOptional(m_emu.ReadPC(),
684
[&](uint64_t pc) {
685
return inst.rd.Write(m_emu,
686
SignExt(inst.imm) + pc);
687
})
688
.value_or(false);
689
}
690
bool operator()(JAL inst) {
691
return transformOptional(m_emu.ReadPC(),
692
[&](uint64_t pc) {
693
return inst.rd.Write(m_emu, pc + delta()) &&
694
m_emu.WritePC(SignExt(inst.imm) + pc);
695
})
696
.value_or(false);
697
}
698
bool operator()(JALR inst) {
699
return transformOptional(zipOpt(m_emu.ReadPC(), inst.rs1.Read(m_emu)),
700
[&](auto &&tup) {
701
auto [pc, rs1] = tup;
702
return inst.rd.Write(m_emu, pc + delta()) &&
703
m_emu.WritePC((SignExt(inst.imm) + rs1) &
704
~1);
705
})
706
.value_or(false);
707
}
708
bool operator()(B inst) {
709
return transformOptional(zipOpt(m_emu.ReadPC(), inst.rs1.Read(m_emu),
710
inst.rs2.Read(m_emu)),
711
[&](auto &&tup) {
712
auto [pc, rs1, rs2] = tup;
713
if (m_ignore_cond ||
714
CompareB(rs1, rs2, inst.funct3))
715
return m_emu.WritePC(SignExt(inst.imm) + pc);
716
return true;
717
})
718
.value_or(false);
719
}
720
bool operator()(LB inst) {
721
return Load<LB, uint8_t, int8_t>(m_emu, inst, SextW);
722
}
723
bool operator()(LH inst) {
724
return Load<LH, uint16_t, int16_t>(m_emu, inst, SextW);
725
}
726
bool operator()(LW inst) {
727
return Load<LW, uint32_t, int32_t>(m_emu, inst, SextW);
728
}
729
bool operator()(LBU inst) {
730
return Load<LBU, uint8_t, uint8_t>(m_emu, inst, ZextD);
731
}
732
bool operator()(LHU inst) {
733
return Load<LHU, uint16_t, uint16_t>(m_emu, inst, ZextD);
734
}
735
bool operator()(SB inst) { return Store<SB, uint8_t>(m_emu, inst); }
736
bool operator()(SH inst) { return Store<SH, uint16_t>(m_emu, inst); }
737
bool operator()(SW inst) { return Store<SW, uint32_t>(m_emu, inst); }
738
bool operator()(ADDI inst) {
739
return transformOptional(inst.rs1.ReadI64(m_emu),
740
[&](int64_t rs1) {
741
return inst.rd.Write(
742
m_emu, rs1 + int64_t(SignExt(inst.imm)));
743
})
744
.value_or(false);
745
}
746
bool operator()(SLTI inst) {
747
return transformOptional(inst.rs1.ReadI64(m_emu),
748
[&](int64_t rs1) {
749
return inst.rd.Write(
750
m_emu, rs1 < int64_t(SignExt(inst.imm)));
751
})
752
.value_or(false);
753
}
754
bool operator()(SLTIU inst) {
755
return transformOptional(inst.rs1.Read(m_emu),
756
[&](uint64_t rs1) {
757
return inst.rd.Write(
758
m_emu, rs1 < uint64_t(SignExt(inst.imm)));
759
})
760
.value_or(false);
761
}
762
bool operator()(XORI inst) {
763
return transformOptional(inst.rs1.Read(m_emu),
764
[&](uint64_t rs1) {
765
return inst.rd.Write(
766
m_emu, rs1 ^ uint64_t(SignExt(inst.imm)));
767
})
768
.value_or(false);
769
}
770
bool operator()(ORI inst) {
771
return transformOptional(inst.rs1.Read(m_emu),
772
[&](uint64_t rs1) {
773
return inst.rd.Write(
774
m_emu, rs1 | uint64_t(SignExt(inst.imm)));
775
})
776
.value_or(false);
777
}
778
bool operator()(ANDI inst) {
779
return transformOptional(inst.rs1.Read(m_emu),
780
[&](uint64_t rs1) {
781
return inst.rd.Write(
782
m_emu, rs1 & uint64_t(SignExt(inst.imm)));
783
})
784
.value_or(false);
785
}
786
bool operator()(ADD inst) {
787
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
788
[&](auto &&tup) {
789
auto [rs1, rs2] = tup;
790
return inst.rd.Write(m_emu, rs1 + rs2);
791
})
792
.value_or(false);
793
}
794
bool operator()(SUB inst) {
795
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
796
[&](auto &&tup) {
797
auto [rs1, rs2] = tup;
798
return inst.rd.Write(m_emu, rs1 - rs2);
799
})
800
.value_or(false);
801
}
802
bool operator()(SLL inst) {
803
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
804
[&](auto &&tup) {
805
auto [rs1, rs2] = tup;
806
return inst.rd.Write(m_emu,
807
rs1 << (rs2 & 0b111111));
808
})
809
.value_or(false);
810
}
811
bool operator()(SLT inst) {
812
return transformOptional(
813
zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)),
814
[&](auto &&tup) {
815
auto [rs1, rs2] = tup;
816
return inst.rd.Write(m_emu, rs1 < rs2);
817
})
818
.value_or(false);
819
}
820
bool operator()(SLTU inst) {
821
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
822
[&](auto &&tup) {
823
auto [rs1, rs2] = tup;
824
return inst.rd.Write(m_emu, rs1 < rs2);
825
})
826
.value_or(false);
827
}
828
bool operator()(XOR inst) {
829
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
830
[&](auto &&tup) {
831
auto [rs1, rs2] = tup;
832
return inst.rd.Write(m_emu, rs1 ^ rs2);
833
})
834
.value_or(false);
835
}
836
bool operator()(SRL inst) {
837
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
838
[&](auto &&tup) {
839
auto [rs1, rs2] = tup;
840
return inst.rd.Write(m_emu,
841
rs1 >> (rs2 & 0b111111));
842
})
843
.value_or(false);
844
}
845
bool operator()(SRA inst) {
846
return transformOptional(
847
zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.Read(m_emu)),
848
[&](auto &&tup) {
849
auto [rs1, rs2] = tup;
850
return inst.rd.Write(m_emu, rs1 >> (rs2 & 0b111111));
851
})
852
.value_or(false);
853
}
854
bool operator()(OR inst) {
855
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
856
[&](auto &&tup) {
857
auto [rs1, rs2] = tup;
858
return inst.rd.Write(m_emu, rs1 | rs2);
859
})
860
.value_or(false);
861
}
862
bool operator()(AND inst) {
863
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
864
[&](auto &&tup) {
865
auto [rs1, rs2] = tup;
866
return inst.rd.Write(m_emu, rs1 & rs2);
867
})
868
.value_or(false);
869
}
870
bool operator()(LWU inst) {
871
return Load<LWU, uint32_t, uint32_t>(m_emu, inst, ZextD);
872
}
873
bool operator()(LD inst) {
874
return Load<LD, uint64_t, uint64_t>(m_emu, inst, ZextD);
875
}
876
bool operator()(SD inst) { return Store<SD, uint64_t>(m_emu, inst); }
877
bool operator()(SLLI inst) {
878
return transformOptional(inst.rs1.Read(m_emu),
879
[&](uint64_t rs1) {
880
return inst.rd.Write(m_emu, rs1 << inst.shamt);
881
})
882
.value_or(false);
883
}
884
bool operator()(SRLI inst) {
885
return transformOptional(inst.rs1.Read(m_emu),
886
[&](uint64_t rs1) {
887
return inst.rd.Write(m_emu, rs1 >> inst.shamt);
888
})
889
.value_or(false);
890
}
891
bool operator()(SRAI inst) {
892
return transformOptional(inst.rs1.ReadI64(m_emu),
893
[&](int64_t rs1) {
894
return inst.rd.Write(m_emu, rs1 >> inst.shamt);
895
})
896
.value_or(false);
897
}
898
bool operator()(ADDIW inst) {
899
return transformOptional(inst.rs1.ReadI32(m_emu),
900
[&](int32_t rs1) {
901
return inst.rd.Write(
902
m_emu, SextW(rs1 + SignExt(inst.imm)));
903
})
904
.value_or(false);
905
}
906
bool operator()(SLLIW inst) {
907
return transformOptional(inst.rs1.ReadU32(m_emu),
908
[&](uint32_t rs1) {
909
return inst.rd.Write(m_emu,
910
SextW(rs1 << inst.shamt));
911
})
912
.value_or(false);
913
}
914
bool operator()(SRLIW inst) {
915
return transformOptional(inst.rs1.ReadU32(m_emu),
916
[&](uint32_t rs1) {
917
return inst.rd.Write(m_emu,
918
SextW(rs1 >> inst.shamt));
919
})
920
.value_or(false);
921
}
922
bool operator()(SRAIW inst) {
923
return transformOptional(inst.rs1.ReadI32(m_emu),
924
[&](int32_t rs1) {
925
return inst.rd.Write(m_emu,
926
SextW(rs1 >> inst.shamt));
927
})
928
.value_or(false);
929
}
930
bool operator()(ADDW inst) {
931
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
932
[&](auto &&tup) {
933
auto [rs1, rs2] = tup;
934
return inst.rd.Write(m_emu,
935
SextW(uint32_t(rs1 + rs2)));
936
})
937
.value_or(false);
938
}
939
bool operator()(SUBW inst) {
940
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
941
[&](auto &&tup) {
942
auto [rs1, rs2] = tup;
943
return inst.rd.Write(m_emu,
944
SextW(uint32_t(rs1 - rs2)));
945
})
946
.value_or(false);
947
}
948
bool operator()(SLLW inst) {
949
return transformOptional(
950
zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),
951
[&](auto &&tup) {
952
auto [rs1, rs2] = tup;
953
return inst.rd.Write(m_emu, SextW(rs1 << (rs2 & 0b11111)));
954
})
955
.value_or(false);
956
}
957
bool operator()(SRLW inst) {
958
return transformOptional(
959
zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),
960
[&](auto &&tup) {
961
auto [rs1, rs2] = tup;
962
return inst.rd.Write(m_emu, SextW(rs1 >> (rs2 & 0b11111)));
963
})
964
.value_or(false);
965
}
966
bool operator()(SRAW inst) {
967
return transformOptional(
968
zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.Read(m_emu)),
969
[&](auto &&tup) {
970
auto [rs1, rs2] = tup;
971
return inst.rd.Write(m_emu, SextW(rs1 >> (rs2 & 0b11111)));
972
})
973
.value_or(false);
974
}
975
// RV32M & RV64M (Integer Multiplication and Division Extension) //
976
bool operator()(MUL inst) {
977
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
978
[&](auto &&tup) {
979
auto [rs1, rs2] = tup;
980
return inst.rd.Write(m_emu, rs1 * rs2);
981
})
982
.value_or(false);
983
}
984
bool operator()(MULH inst) {
985
return transformOptional(
986
zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
987
[&](auto &&tup) {
988
auto [rs1, rs2] = tup;
989
// signed * signed
990
auto mul = APInt(128, rs1, true) * APInt(128, rs2, true);
991
return inst.rd.Write(m_emu,
992
mul.ashr(64).trunc(64).getZExtValue());
993
})
994
.value_or(false);
995
}
996
bool operator()(MULHSU inst) {
997
return transformOptional(
998
zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
999
[&](auto &&tup) {
1000
auto [rs1, rs2] = tup;
1001
// signed * unsigned
1002
auto mul =
1003
APInt(128, rs1, true).zext(128) * APInt(128, rs2, false);
1004
return inst.rd.Write(m_emu,
1005
mul.lshr(64).trunc(64).getZExtValue());
1006
})
1007
.value_or(false);
1008
}
1009
bool operator()(MULHU inst) {
1010
return transformOptional(
1011
zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
1012
[&](auto &&tup) {
1013
auto [rs1, rs2] = tup;
1014
// unsigned * unsigned
1015
auto mul = APInt(128, rs1, false) * APInt(128, rs2, false);
1016
return inst.rd.Write(m_emu,
1017
mul.lshr(64).trunc(64).getZExtValue());
1018
})
1019
.value_or(false);
1020
}
1021
bool operator()(DIV inst) {
1022
return transformOptional(
1023
zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)),
1024
[&](auto &&tup) {
1025
auto [dividend, divisor] = tup;
1026
1027
if (divisor == 0)
1028
return inst.rd.Write(m_emu, UINT64_MAX);
1029
1030
if (dividend == INT64_MIN && divisor == -1)
1031
return inst.rd.Write(m_emu, dividend);
1032
1033
return inst.rd.Write(m_emu, dividend / divisor);
1034
})
1035
.value_or(false);
1036
}
1037
bool operator()(DIVU inst) {
1038
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
1039
[&](auto &&tup) {
1040
auto [dividend, divisor] = tup;
1041
1042
if (divisor == 0)
1043
return inst.rd.Write(m_emu, UINT64_MAX);
1044
1045
return inst.rd.Write(m_emu, dividend / divisor);
1046
})
1047
.value_or(false);
1048
}
1049
bool operator()(REM inst) {
1050
return transformOptional(
1051
zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)),
1052
[&](auto &&tup) {
1053
auto [dividend, divisor] = tup;
1054
1055
if (divisor == 0)
1056
return inst.rd.Write(m_emu, dividend);
1057
1058
if (dividend == INT64_MIN && divisor == -1)
1059
return inst.rd.Write(m_emu, 0);
1060
1061
return inst.rd.Write(m_emu, dividend % divisor);
1062
})
1063
.value_or(false);
1064
}
1065
bool operator()(REMU inst) {
1066
return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)),
1067
[&](auto &&tup) {
1068
auto [dividend, divisor] = tup;
1069
1070
if (divisor == 0)
1071
return inst.rd.Write(m_emu, dividend);
1072
1073
return inst.rd.Write(m_emu, dividend % divisor);
1074
})
1075
.value_or(false);
1076
}
1077
bool operator()(MULW inst) {
1078
return transformOptional(
1079
zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)),
1080
[&](auto &&tup) {
1081
auto [rs1, rs2] = tup;
1082
return inst.rd.Write(m_emu, SextW(rs1 * rs2));
1083
})
1084
.value_or(false);
1085
}
1086
bool operator()(DIVW inst) {
1087
return transformOptional(
1088
zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)),
1089
[&](auto &&tup) {
1090
auto [dividend, divisor] = tup;
1091
1092
if (divisor == 0)
1093
return inst.rd.Write(m_emu, UINT64_MAX);
1094
1095
if (dividend == INT32_MIN && divisor == -1)
1096
return inst.rd.Write(m_emu, SextW(dividend));
1097
1098
return inst.rd.Write(m_emu, SextW(dividend / divisor));
1099
})
1100
.value_or(false);
1101
}
1102
bool operator()(DIVUW inst) {
1103
return transformOptional(
1104
zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),
1105
[&](auto &&tup) {
1106
auto [dividend, divisor] = tup;
1107
1108
if (divisor == 0)
1109
return inst.rd.Write(m_emu, UINT64_MAX);
1110
1111
return inst.rd.Write(m_emu, SextW(dividend / divisor));
1112
})
1113
.value_or(false);
1114
}
1115
bool operator()(REMW inst) {
1116
return transformOptional(
1117
zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)),
1118
[&](auto &&tup) {
1119
auto [dividend, divisor] = tup;
1120
1121
if (divisor == 0)
1122
return inst.rd.Write(m_emu, SextW(dividend));
1123
1124
if (dividend == INT32_MIN && divisor == -1)
1125
return inst.rd.Write(m_emu, 0);
1126
1127
return inst.rd.Write(m_emu, SextW(dividend % divisor));
1128
})
1129
.value_or(false);
1130
}
1131
bool operator()(REMUW inst) {
1132
return transformOptional(
1133
zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)),
1134
[&](auto &&tup) {
1135
auto [dividend, divisor] = tup;
1136
1137
if (divisor == 0)
1138
return inst.rd.Write(m_emu, SextW(dividend));
1139
1140
return inst.rd.Write(m_emu, SextW(dividend % divisor));
1141
})
1142
.value_or(false);
1143
}
1144
// RV32A & RV64A (The standard atomic instruction extension) //
1145
bool operator()(LR_W) { return AtomicSequence(m_emu); }
1146
bool operator()(LR_D) { return AtomicSequence(m_emu); }
1147
bool operator()(SC_W) {
1148
llvm_unreachable("should be handled in AtomicSequence");
1149
}
1150
bool operator()(SC_D) {
1151
llvm_unreachable("should be handled in AtomicSequence");
1152
}
1153
bool operator()(AMOSWAP_W inst) {
1154
return AtomicSwap<AMOSWAP_W, uint32_t>(m_emu, inst, 4, SextW);
1155
}
1156
bool operator()(AMOADD_W inst) {
1157
return AtomicADD<AMOADD_W, uint32_t>(m_emu, inst, 4, SextW);
1158
}
1159
bool operator()(AMOXOR_W inst) {
1160
return AtomicBitOperate<AMOXOR_W, uint32_t>(
1161
m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a ^ b; });
1162
}
1163
bool operator()(AMOAND_W inst) {
1164
return AtomicBitOperate<AMOAND_W, uint32_t>(
1165
m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a & b; });
1166
}
1167
bool operator()(AMOOR_W inst) {
1168
return AtomicBitOperate<AMOOR_W, uint32_t>(
1169
m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a | b; });
1170
}
1171
bool operator()(AMOMIN_W inst) {
1172
return AtomicCmp<AMOMIN_W, uint32_t>(
1173
m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) {
1174
return uint32_t(std::min(int32_t(a), int32_t(b)));
1175
});
1176
}
1177
bool operator()(AMOMAX_W inst) {
1178
return AtomicCmp<AMOMAX_W, uint32_t>(
1179
m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) {
1180
return uint32_t(std::max(int32_t(a), int32_t(b)));
1181
});
1182
}
1183
bool operator()(AMOMINU_W inst) {
1184
return AtomicCmp<AMOMINU_W, uint32_t>(
1185
m_emu, inst, 4, SextW,
1186
[](uint32_t a, uint32_t b) { return std::min(a, b); });
1187
}
1188
bool operator()(AMOMAXU_W inst) {
1189
return AtomicCmp<AMOMAXU_W, uint32_t>(
1190
m_emu, inst, 4, SextW,
1191
[](uint32_t a, uint32_t b) { return std::max(a, b); });
1192
}
1193
bool operator()(AMOSWAP_D inst) {
1194
return AtomicSwap<AMOSWAP_D, uint64_t>(m_emu, inst, 8, ZextD);
1195
}
1196
bool operator()(AMOADD_D inst) {
1197
return AtomicADD<AMOADD_D, uint64_t>(m_emu, inst, 8, ZextD);
1198
}
1199
bool operator()(AMOXOR_D inst) {
1200
return AtomicBitOperate<AMOXOR_D, uint64_t>(
1201
m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a ^ b; });
1202
}
1203
bool operator()(AMOAND_D inst) {
1204
return AtomicBitOperate<AMOAND_D, uint64_t>(
1205
m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a & b; });
1206
}
1207
bool operator()(AMOOR_D inst) {
1208
return AtomicBitOperate<AMOOR_D, uint64_t>(
1209
m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a | b; });
1210
}
1211
bool operator()(AMOMIN_D inst) {
1212
return AtomicCmp<AMOMIN_D, uint64_t>(
1213
m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) {
1214
return uint64_t(std::min(int64_t(a), int64_t(b)));
1215
});
1216
}
1217
bool operator()(AMOMAX_D inst) {
1218
return AtomicCmp<AMOMAX_D, uint64_t>(
1219
m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) {
1220
return uint64_t(std::max(int64_t(a), int64_t(b)));
1221
});
1222
}
1223
bool operator()(AMOMINU_D inst) {
1224
return AtomicCmp<AMOMINU_D, uint64_t>(
1225
m_emu, inst, 8, ZextD,
1226
[](uint64_t a, uint64_t b) { return std::min(a, b); });
1227
}
1228
bool operator()(AMOMAXU_D inst) {
1229
return AtomicCmp<AMOMAXU_D, uint64_t>(
1230
m_emu, inst, 8, ZextD,
1231
[](uint64_t a, uint64_t b) { return std::max(a, b); });
1232
}
1233
template <typename T>
1234
bool F_Load(T inst, const fltSemantics &(*semantics)(),
1235
unsigned int numBits) {
1236
return transformOptional(inst.rs1.Read(m_emu),
1237
[&](auto &&rs1) {
1238
uint64_t addr = rs1 + uint64_t(inst.imm);
1239
uint64_t bits = *m_emu.ReadMem<uint64_t>(addr);
1240
APFloat f(semantics(), APInt(numBits, bits));
1241
return inst.rd.WriteAPFloat(m_emu, f);
1242
})
1243
.value_or(false);
1244
}
1245
bool operator()(FLW inst) { return F_Load(inst, &APFloat::IEEEsingle, 32); }
1246
template <typename T> bool F_Store(T inst, bool isDouble) {
1247
return transformOptional(zipOpt(inst.rs1.Read(m_emu),
1248
inst.rs2.ReadAPFloat(m_emu, isDouble)),
1249
[&](auto &&tup) {
1250
auto [rs1, rs2] = tup;
1251
uint64_t addr = rs1 + uint64_t(inst.imm);
1252
uint64_t bits =
1253
rs2.bitcastToAPInt().getZExtValue();
1254
return m_emu.WriteMem<uint64_t>(addr, bits);
1255
})
1256
.value_or(false);
1257
}
1258
bool operator()(FSW inst) { return F_Store(inst, false); }
1259
std::tuple<bool, APFloat> FusedMultiplyAdd(APFloat rs1, APFloat rs2,
1260
APFloat rs3) {
1261
auto opStatus = rs1.fusedMultiplyAdd(rs2, rs3, m_emu.GetRoundingMode());
1262
auto res = m_emu.SetAccruedExceptions(opStatus);
1263
return {res, rs1};
1264
}
1265
template <typename T>
1266
bool FMA(T inst, bool isDouble, float rs2_sign, float rs3_sign) {
1267
return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
1268
inst.rs2.ReadAPFloat(m_emu, isDouble),
1269
inst.rs3.ReadAPFloat(m_emu, isDouble)),
1270
[&](auto &&tup) {
1271
auto [rs1, rs2, rs3] = tup;
1272
rs2.copySign(APFloat(rs2_sign));
1273
rs3.copySign(APFloat(rs3_sign));
1274
auto [res, f] = FusedMultiplyAdd(rs1, rs2, rs3);
1275
return res && inst.rd.WriteAPFloat(m_emu, f);
1276
})
1277
.value_or(false);
1278
}
1279
bool operator()(FMADD_S inst) { return FMA(inst, false, 1.0f, 1.0f); }
1280
bool operator()(FMSUB_S inst) { return FMA(inst, false, 1.0f, -1.0f); }
1281
bool operator()(FNMSUB_S inst) { return FMA(inst, false, -1.0f, 1.0f); }
1282
bool operator()(FNMADD_S inst) { return FMA(inst, false, -1.0f, -1.0f); }
1283
template <typename T>
1284
bool F_Op(T inst, bool isDouble,
1285
APFloat::opStatus (APFloat::*f)(const APFloat &RHS,
1286
APFloat::roundingMode RM)) {
1287
return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
1288
inst.rs2.ReadAPFloat(m_emu, isDouble)),
1289
[&](auto &&tup) {
1290
auto [rs1, rs2] = tup;
1291
auto res =
1292
((&rs1)->*f)(rs2, m_emu.GetRoundingMode());
1293
inst.rd.WriteAPFloat(m_emu, rs1);
1294
return m_emu.SetAccruedExceptions(res);
1295
})
1296
.value_or(false);
1297
}
1298
bool operator()(FADD_S inst) { return F_Op(inst, false, &APFloat::add); }
1299
bool operator()(FSUB_S inst) { return F_Op(inst, false, &APFloat::subtract); }
1300
bool operator()(FMUL_S inst) { return F_Op(inst, false, &APFloat::multiply); }
1301
bool operator()(FDIV_S inst) { return F_Op(inst, false, &APFloat::divide); }
1302
bool operator()(FSQRT_S inst) {
1303
// TODO: APFloat doesn't have a sqrt function.
1304
return false;
1305
}
1306
template <typename T> bool F_SignInj(T inst, bool isDouble, bool isNegate) {
1307
return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
1308
inst.rs2.ReadAPFloat(m_emu, isDouble)),
1309
[&](auto &&tup) {
1310
auto [rs1, rs2] = tup;
1311
if (isNegate)
1312
rs2.changeSign();
1313
rs1.copySign(rs2);
1314
return inst.rd.WriteAPFloat(m_emu, rs1);
1315
})
1316
.value_or(false);
1317
}
1318
bool operator()(FSGNJ_S inst) { return F_SignInj(inst, false, false); }
1319
bool operator()(FSGNJN_S inst) { return F_SignInj(inst, false, true); }
1320
template <typename T> bool F_SignInjXor(T inst, bool isDouble) {
1321
return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
1322
inst.rs2.ReadAPFloat(m_emu, isDouble)),
1323
[&](auto &&tup) {
1324
auto [rs1, rs2] = tup;
1325
// spec: the sign bit is the XOR of the sign bits
1326
// of rs1 and rs2. if rs1 and rs2 have the same
1327
// signs set rs1 to positive else set rs1 to
1328
// negative
1329
if (rs1.isNegative() == rs2.isNegative()) {
1330
rs1.clearSign();
1331
} else {
1332
rs1.clearSign();
1333
rs1.changeSign();
1334
}
1335
return inst.rd.WriteAPFloat(m_emu, rs1);
1336
})
1337
.value_or(false);
1338
}
1339
bool operator()(FSGNJX_S inst) { return F_SignInjXor(inst, false); }
1340
template <typename T>
1341
bool F_MAX_MIN(T inst, bool isDouble,
1342
APFloat (*f)(const APFloat &A, const APFloat &B)) {
1343
return transformOptional(
1344
zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
1345
inst.rs2.ReadAPFloat(m_emu, isDouble)),
1346
[&](auto &&tup) {
1347
auto [rs1, rs2] = tup;
1348
// If both inputs are NaNs, the result is the canonical NaN.
1349
// If only one operand is a NaN, the result is the non-NaN
1350
// operand. Signaling NaN inputs set the invalid operation
1351
// exception flag, even when the result is not NaN.
1352
if (rs1.isNaN() || rs2.isNaN())
1353
m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
1354
if (rs1.isNaN() && rs2.isNaN()) {
1355
auto canonicalNaN = APFloat::getQNaN(rs1.getSemantics());
1356
return inst.rd.WriteAPFloat(m_emu, canonicalNaN);
1357
}
1358
return inst.rd.WriteAPFloat(m_emu, f(rs1, rs2));
1359
})
1360
.value_or(false);
1361
}
1362
bool operator()(FMIN_S inst) { return F_MAX_MIN(inst, false, minnum); }
1363
bool operator()(FMAX_S inst) { return F_MAX_MIN(inst, false, maxnum); }
1364
bool operator()(FCVT_W_S inst) {
1365
return FCVT_i2f<FCVT_W_S, int32_t, float>(inst, false,
1366
&APFloat::convertToFloat);
1367
}
1368
bool operator()(FCVT_WU_S inst) {
1369
return FCVT_i2f<FCVT_WU_S, uint32_t, float>(inst, false,
1370
&APFloat::convertToFloat);
1371
}
1372
template <typename T> bool FMV_f2i(T inst, bool isDouble) {
1373
return transformOptional(
1374
inst.rs1.ReadAPFloat(m_emu, isDouble),
1375
[&](auto &&rs1) {
1376
if (rs1.isNaN()) {
1377
if (isDouble)
1378
return inst.rd.Write(m_emu, 0x7ff8'0000'0000'0000);
1379
else
1380
return inst.rd.Write(m_emu, 0x7fc0'0000);
1381
}
1382
auto bits = rs1.bitcastToAPInt().getZExtValue();
1383
if (isDouble)
1384
return inst.rd.Write(m_emu, bits);
1385
else
1386
return inst.rd.Write(m_emu, uint64_t(bits & 0xffff'ffff));
1387
})
1388
.value_or(false);
1389
}
1390
bool operator()(FMV_X_W inst) { return FMV_f2i(inst, false); }
1391
enum F_CMP {
1392
FEQ,
1393
FLT,
1394
FLE,
1395
};
1396
template <typename T> bool F_Compare(T inst, bool isDouble, F_CMP cmp) {
1397
return transformOptional(
1398
zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble),
1399
inst.rs2.ReadAPFloat(m_emu, isDouble)),
1400
[&](auto &&tup) {
1401
auto [rs1, rs2] = tup;
1402
if (rs1.isNaN() || rs2.isNaN()) {
1403
if (cmp == FEQ) {
1404
if (rs1.isSignaling() || rs2.isSignaling()) {
1405
auto res =
1406
m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
1407
return res && inst.rd.Write(m_emu, 0);
1408
}
1409
}
1410
auto res = m_emu.SetAccruedExceptions(APFloat::opInvalidOp);
1411
return res && inst.rd.Write(m_emu, 0);
1412
}
1413
switch (cmp) {
1414
case FEQ:
1415
return inst.rd.Write(m_emu,
1416
rs1.compare(rs2) == APFloat::cmpEqual);
1417
case FLT:
1418
return inst.rd.Write(m_emu, rs1.compare(rs2) ==
1419
APFloat::cmpLessThan);
1420
case FLE:
1421
return inst.rd.Write(m_emu, rs1.compare(rs2) !=
1422
APFloat::cmpGreaterThan);
1423
}
1424
llvm_unreachable("unsupported F_CMP");
1425
})
1426
.value_or(false);
1427
}
1428
1429
bool operator()(FEQ_S inst) { return F_Compare(inst, false, FEQ); }
1430
bool operator()(FLT_S inst) { return F_Compare(inst, false, FLT); }
1431
bool operator()(FLE_S inst) { return F_Compare(inst, false, FLE); }
1432
template <typename T> bool FCLASS(T inst, bool isDouble) {
1433
return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble),
1434
[&](auto &&rs1) {
1435
uint64_t result = 0;
1436
if (rs1.isInfinity() && rs1.isNegative())
1437
result |= 1 << 0;
1438
// neg normal
1439
if (rs1.isNormal() && rs1.isNegative())
1440
result |= 1 << 1;
1441
// neg subnormal
1442
if (rs1.isDenormal() && rs1.isNegative())
1443
result |= 1 << 2;
1444
if (rs1.isNegZero())
1445
result |= 1 << 3;
1446
if (rs1.isPosZero())
1447
result |= 1 << 4;
1448
// pos normal
1449
if (rs1.isNormal() && !rs1.isNegative())
1450
result |= 1 << 5;
1451
// pos subnormal
1452
if (rs1.isDenormal() && !rs1.isNegative())
1453
result |= 1 << 6;
1454
if (rs1.isInfinity() && !rs1.isNegative())
1455
result |= 1 << 7;
1456
if (rs1.isNaN()) {
1457
if (rs1.isSignaling())
1458
result |= 1 << 8;
1459
else
1460
result |= 1 << 9;
1461
}
1462
return inst.rd.Write(m_emu, result);
1463
})
1464
.value_or(false);
1465
}
1466
bool operator()(FCLASS_S inst) { return FCLASS(inst, false); }
1467
template <typename T, typename E>
1468
bool FCVT_f2i(T inst, std::optional<E> (Rs::*f)(EmulateInstructionRISCV &emu),
1469
const fltSemantics &semantics) {
1470
return transformOptional(((&inst.rs1)->*f)(m_emu),
1471
[&](auto &&rs1) {
1472
APFloat apf(semantics, rs1);
1473
return inst.rd.WriteAPFloat(m_emu, apf);
1474
})
1475
.value_or(false);
1476
}
1477
bool operator()(FCVT_S_W inst) {
1478
return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEsingle());
1479
}
1480
bool operator()(FCVT_S_WU inst) {
1481
return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEsingle());
1482
}
1483
template <typename T, typename E>
1484
bool FMV_i2f(T inst, unsigned int numBits, E (APInt::*f)() const) {
1485
return transformOptional(inst.rs1.Read(m_emu),
1486
[&](auto &&rs1) {
1487
APInt apInt(numBits, rs1);
1488
if (numBits == 32) // a.k.a. float
1489
apInt = APInt(numBits, NanUnBoxing(rs1));
1490
APFloat apf((&apInt->*f)());
1491
return inst.rd.WriteAPFloat(m_emu, apf);
1492
})
1493
.value_or(false);
1494
}
1495
bool operator()(FMV_W_X inst) {
1496
return FMV_i2f(inst, 32, &APInt::bitsToFloat);
1497
}
1498
template <typename I, typename E, typename T>
1499
bool FCVT_i2f(I inst, bool isDouble, T (APFloat::*f)() const) {
1500
return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble),
1501
[&](auto &&rs1) {
1502
E res = E((&rs1->*f)());
1503
return inst.rd.Write(m_emu, uint64_t(res));
1504
})
1505
.value_or(false);
1506
}
1507
bool operator()(FCVT_L_S inst) {
1508
return FCVT_i2f<FCVT_L_S, int64_t, float>(inst, false,
1509
&APFloat::convertToFloat);
1510
}
1511
bool operator()(FCVT_LU_S inst) {
1512
return FCVT_i2f<FCVT_LU_S, uint64_t, float>(inst, false,
1513
&APFloat::convertToFloat);
1514
}
1515
bool operator()(FCVT_S_L inst) {
1516
return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEsingle());
1517
}
1518
bool operator()(FCVT_S_LU inst) {
1519
return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEsingle());
1520
}
1521
bool operator()(FLD inst) { return F_Load(inst, &APFloat::IEEEdouble, 64); }
1522
bool operator()(FSD inst) { return F_Store(inst, true); }
1523
bool operator()(FMADD_D inst) { return FMA(inst, true, 1.0f, 1.0f); }
1524
bool operator()(FMSUB_D inst) { return FMA(inst, true, 1.0f, -1.0f); }
1525
bool operator()(FNMSUB_D inst) { return FMA(inst, true, -1.0f, 1.0f); }
1526
bool operator()(FNMADD_D inst) { return FMA(inst, true, -1.0f, -1.0f); }
1527
bool operator()(FADD_D inst) { return F_Op(inst, true, &APFloat::add); }
1528
bool operator()(FSUB_D inst) { return F_Op(inst, true, &APFloat::subtract); }
1529
bool operator()(FMUL_D inst) { return F_Op(inst, true, &APFloat::multiply); }
1530
bool operator()(FDIV_D inst) { return F_Op(inst, true, &APFloat::divide); }
1531
bool operator()(FSQRT_D inst) {
1532
// TODO: APFloat doesn't have a sqrt function.
1533
return false;
1534
}
1535
bool operator()(FSGNJ_D inst) { return F_SignInj(inst, true, false); }
1536
bool operator()(FSGNJN_D inst) { return F_SignInj(inst, true, true); }
1537
bool operator()(FSGNJX_D inst) { return F_SignInjXor(inst, true); }
1538
bool operator()(FMIN_D inst) { return F_MAX_MIN(inst, true, minnum); }
1539
bool operator()(FMAX_D inst) { return F_MAX_MIN(inst, true, maxnum); }
1540
bool operator()(FCVT_S_D inst) {
1541
return transformOptional(inst.rs1.ReadAPFloat(m_emu, true),
1542
[&](auto &&rs1) {
1543
double d = rs1.convertToDouble();
1544
APFloat apf((float(d)));
1545
return inst.rd.WriteAPFloat(m_emu, apf);
1546
})
1547
.value_or(false);
1548
}
1549
bool operator()(FCVT_D_S inst) {
1550
return transformOptional(inst.rs1.ReadAPFloat(m_emu, false),
1551
[&](auto &&rs1) {
1552
float f = rs1.convertToFloat();
1553
APFloat apf((double(f)));
1554
return inst.rd.WriteAPFloat(m_emu, apf);
1555
})
1556
.value_or(false);
1557
}
1558
bool operator()(FEQ_D inst) { return F_Compare(inst, true, FEQ); }
1559
bool operator()(FLT_D inst) { return F_Compare(inst, true, FLT); }
1560
bool operator()(FLE_D inst) { return F_Compare(inst, true, FLE); }
1561
bool operator()(FCLASS_D inst) { return FCLASS(inst, true); }
1562
bool operator()(FCVT_W_D inst) {
1563
return FCVT_i2f<FCVT_W_D, int32_t, double>(inst, true,
1564
&APFloat::convertToDouble);
1565
}
1566
bool operator()(FCVT_WU_D inst) {
1567
return FCVT_i2f<FCVT_WU_D, uint32_t, double>(inst, true,
1568
&APFloat::convertToDouble);
1569
}
1570
bool operator()(FCVT_D_W inst) {
1571
return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEdouble());
1572
}
1573
bool operator()(FCVT_D_WU inst) {
1574
return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEdouble());
1575
}
1576
bool operator()(FCVT_L_D inst) {
1577
return FCVT_i2f<FCVT_L_D, int64_t, double>(inst, true,
1578
&APFloat::convertToDouble);
1579
}
1580
bool operator()(FCVT_LU_D inst) {
1581
return FCVT_i2f<FCVT_LU_D, uint64_t, double>(inst, true,
1582
&APFloat::convertToDouble);
1583
}
1584
bool operator()(FMV_X_D inst) { return FMV_f2i(inst, true); }
1585
bool operator()(FCVT_D_L inst) {
1586
return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEdouble());
1587
}
1588
bool operator()(FCVT_D_LU inst) {
1589
return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEdouble());
1590
}
1591
bool operator()(FMV_D_X inst) {
1592
return FMV_i2f(inst, 64, &APInt::bitsToDouble);
1593
}
1594
bool operator()(INVALID inst) { return false; }
1595
bool operator()(RESERVED inst) { return false; }
1596
bool operator()(EBREAK inst) { return false; }
1597
bool operator()(HINT inst) { return true; }
1598
bool operator()(NOP inst) { return true; }
1599
};
1600
1601
bool EmulateInstructionRISCV::Execute(DecodeResult inst, bool ignore_cond) {
1602
return std::visit(Executor(*this, ignore_cond, inst.is_rvc), inst.decoded);
1603
}
1604
1605
bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) {
1606
bool increase_pc = options & eEmulateInstructionOptionAutoAdvancePC;
1607
bool ignore_cond = options & eEmulateInstructionOptionIgnoreConditions;
1608
1609
if (!increase_pc)
1610
return Execute(m_decoded, ignore_cond);
1611
1612
auto old_pc = ReadPC();
1613
if (!old_pc)
1614
return false;
1615
1616
bool success = Execute(m_decoded, ignore_cond);
1617
if (!success)
1618
return false;
1619
1620
auto new_pc = ReadPC();
1621
if (!new_pc)
1622
return false;
1623
1624
// If the pc is not updated during execution, we do it here.
1625
return new_pc != old_pc ||
1626
WritePC(*old_pc + Executor::size(m_decoded.is_rvc));
1627
}
1628
1629
std::optional<DecodeResult>
1630
EmulateInstructionRISCV::ReadInstructionAt(addr_t addr) {
1631
return transformOptional(ReadMem<uint32_t>(addr),
1632
[&](uint32_t inst) { return Decode(inst); })
1633
.value_or(std::nullopt);
1634
}
1635
1636
bool EmulateInstructionRISCV::ReadInstruction() {
1637
auto addr = ReadPC();
1638
m_addr = addr.value_or(LLDB_INVALID_ADDRESS);
1639
if (!addr)
1640
return false;
1641
auto inst = ReadInstructionAt(*addr);
1642
if (!inst)
1643
return false;
1644
m_decoded = *inst;
1645
if (inst->is_rvc)
1646
m_opcode.SetOpcode16(inst->inst, GetByteOrder());
1647
else
1648
m_opcode.SetOpcode32(inst->inst, GetByteOrder());
1649
return true;
1650
}
1651
1652
std::optional<addr_t> EmulateInstructionRISCV::ReadPC() {
1653
bool success = false;
1654
auto addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
1655
LLDB_INVALID_ADDRESS, &success);
1656
return success ? std::optional<addr_t>(addr) : std::nullopt;
1657
}
1658
1659
bool EmulateInstructionRISCV::WritePC(addr_t pc) {
1660
EmulateInstruction::Context ctx;
1661
ctx.type = eContextAdvancePC;
1662
ctx.SetNoArgs();
1663
return WriteRegisterUnsigned(ctx, eRegisterKindGeneric,
1664
LLDB_REGNUM_GENERIC_PC, pc);
1665
}
1666
1667
RoundingMode EmulateInstructionRISCV::GetRoundingMode() {
1668
bool success = false;
1669
auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,
1670
LLDB_INVALID_ADDRESS, &success);
1671
if (!success)
1672
return RoundingMode::Invalid;
1673
auto frm = (fcsr >> 5) & 0x7;
1674
switch (frm) {
1675
case 0b000:
1676
return RoundingMode::NearestTiesToEven;
1677
case 0b001:
1678
return RoundingMode::TowardZero;
1679
case 0b010:
1680
return RoundingMode::TowardNegative;
1681
case 0b011:
1682
return RoundingMode::TowardPositive;
1683
case 0b111:
1684
return RoundingMode::Dynamic;
1685
default:
1686
// Reserved for future use.
1687
return RoundingMode::Invalid;
1688
}
1689
}
1690
1691
bool EmulateInstructionRISCV::SetAccruedExceptions(
1692
APFloatBase::opStatus opStatus) {
1693
bool success = false;
1694
auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,
1695
LLDB_INVALID_ADDRESS, &success);
1696
if (!success)
1697
return false;
1698
switch (opStatus) {
1699
case APFloatBase::opInvalidOp:
1700
fcsr |= 1 << 4;
1701
break;
1702
case APFloatBase::opDivByZero:
1703
fcsr |= 1 << 3;
1704
break;
1705
case APFloatBase::opOverflow:
1706
fcsr |= 1 << 2;
1707
break;
1708
case APFloatBase::opUnderflow:
1709
fcsr |= 1 << 1;
1710
break;
1711
case APFloatBase::opInexact:
1712
fcsr |= 1 << 0;
1713
break;
1714
case APFloatBase::opOK:
1715
break;
1716
}
1717
EmulateInstruction::Context ctx;
1718
ctx.type = eContextRegisterStore;
1719
ctx.SetNoArgs();
1720
return WriteRegisterUnsigned(ctx, eRegisterKindLLDB, fpr_fcsr_riscv, fcsr);
1721
}
1722
1723
std::optional<RegisterInfo>
1724
EmulateInstructionRISCV::GetRegisterInfo(RegisterKind reg_kind,
1725
uint32_t reg_index) {
1726
if (reg_kind == eRegisterKindGeneric) {
1727
switch (reg_index) {
1728
case LLDB_REGNUM_GENERIC_PC:
1729
reg_kind = eRegisterKindLLDB;
1730
reg_index = gpr_pc_riscv;
1731
break;
1732
case LLDB_REGNUM_GENERIC_SP:
1733
reg_kind = eRegisterKindLLDB;
1734
reg_index = gpr_sp_riscv;
1735
break;
1736
case LLDB_REGNUM_GENERIC_FP:
1737
reg_kind = eRegisterKindLLDB;
1738
reg_index = gpr_fp_riscv;
1739
break;
1740
case LLDB_REGNUM_GENERIC_RA:
1741
reg_kind = eRegisterKindLLDB;
1742
reg_index = gpr_ra_riscv;
1743
break;
1744
// We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are
1745
// supported.
1746
default:
1747
llvm_unreachable("unsupported register");
1748
}
1749
}
1750
1751
const RegisterInfo *array =
1752
RegisterInfoPOSIX_riscv64::GetRegisterInfoPtr(m_arch);
1753
const uint32_t length =
1754
RegisterInfoPOSIX_riscv64::GetRegisterInfoCount(m_arch);
1755
1756
if (reg_index >= length || reg_kind != eRegisterKindLLDB)
1757
return {};
1758
1759
return array[reg_index];
1760
}
1761
1762
bool EmulateInstructionRISCV::SetTargetTriple(const ArchSpec &arch) {
1763
return SupportsThisArch(arch);
1764
}
1765
1766
bool EmulateInstructionRISCV::TestEmulation(Stream &out_stream, ArchSpec &arch,
1767
OptionValueDictionary *test_data) {
1768
return false;
1769
}
1770
1771
void EmulateInstructionRISCV::Initialize() {
1772
PluginManager::RegisterPlugin(GetPluginNameStatic(),
1773
GetPluginDescriptionStatic(), CreateInstance);
1774
}
1775
1776
void EmulateInstructionRISCV::Terminate() {
1777
PluginManager::UnregisterPlugin(CreateInstance);
1778
}
1779
1780
lldb_private::EmulateInstruction *
1781
EmulateInstructionRISCV::CreateInstance(const ArchSpec &arch,
1782
InstructionType inst_type) {
1783
if (EmulateInstructionRISCV::SupportsThisInstructionType(inst_type) &&
1784
SupportsThisArch(arch)) {
1785
return new EmulateInstructionRISCV(arch);
1786
}
1787
1788
return nullptr;
1789
}
1790
1791
bool EmulateInstructionRISCV::SupportsThisArch(const ArchSpec &arch) {
1792
return arch.GetTriple().isRISCV();
1793
}
1794
1795
} // namespace lldb_private
1796
1797