1 //===-- EmulateInstructionRISCV.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
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"
24 #include "llvm/ADT/STLExtras.h"
25 #include "llvm/Support/MathExtras.h"
30 using namespace lldb_private
;
32 LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionRISCV
, InstructionRISCV
)
34 namespace lldb_private
{
36 /// Returns all values wrapped in Optional, or std::nullopt if any of the values
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
)...));
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;
57 constexpr int32_t SignExt(uint32_t imm
) { return int32_t(imm
); }
61 constexpr std::enable_if_t
<sizeof(T
) <= 4, uint64_t> SextW(T value
) {
62 return uint64_t(int64_t(int32_t(value
)));
66 template <typename T
> constexpr uint64_t ZextD(T value
) {
67 return uint64_t(value
);
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]
77 constexpr uint32_t DecodeIImm(uint32_t inst
) {
78 return int64_t(int32_t(inst
)) >> 20; // imm[11:0]
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]
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]
93 constexpr uint32_t DecodeUImm(uint32_t inst
) {
94 return SextW(inst
& 0xFFFFF000); // imm[31:12]
97 static uint32_t GPREncodingToLLDB(uint32_t reg_encode
) {
100 if (reg_encode
>= 1 && reg_encode
<= 31)
101 return gpr_x1_riscv
+ reg_encode
- 1;
102 return LLDB_INVALID_REGNUM
;
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
;
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
;
116 RegisterValue registerValue
;
117 registerValue
.SetUInt64(value
);
118 return emulator
.WriteRegister(ctx
, eRegisterKindLLDB
, lldb_reg
,
122 bool Rd::WriteAPFloat(EmulateInstructionRISCV
&emulator
, APFloat value
) {
123 uint32_t lldb_reg
= FPREncodingToLLDB(rd
);
124 EmulateInstruction::Context ctx
;
125 ctx
.type
= EmulateInstruction::eContextRegisterStore
;
127 RegisterValue registerValue
;
128 registerValue
.SetUInt64(value
.bitcastToAPInt().getZExtValue());
129 return emulator
.WriteRegister(ctx
, eRegisterKindLLDB
, lldb_reg
,
133 std::optional
<uint64_t> Rs::Read(EmulateInstructionRISCV
&emulator
) {
134 uint32_t lldbReg
= GPREncodingToLLDB(rs
);
136 return emulator
.ReadRegister(eRegisterKindLLDB
, lldbReg
, value
)
137 ? std::optional
<uint64_t>(value
.GetAsUInt64())
141 std::optional
<int32_t> Rs::ReadI32(EmulateInstructionRISCV
&emulator
) {
142 return transformOptional(
143 Read(emulator
), [](uint64_t value
) { return int32_t(uint32_t(value
)); });
146 std::optional
<int64_t> Rs::ReadI64(EmulateInstructionRISCV
&emulator
) {
147 return transformOptional(Read(emulator
),
148 [](uint64_t value
) { return int64_t(value
); });
151 std::optional
<uint32_t> Rs::ReadU32(EmulateInstructionRISCV
&emulator
) {
152 return transformOptional(Read(emulator
),
153 [](uint64_t value
) { return uint32_t(value
); });
156 std::optional
<APFloat
> Rs::ReadAPFloat(EmulateInstructionRISCV
&emulator
,
158 uint32_t lldbReg
= FPREncodingToLLDB(rs
);
160 if (!emulator
.ReadRegister(eRegisterKindLLDB
, lldbReg
, value
))
162 uint64_t bits
= value
.GetAsUInt64();
163 APInt
api(64, bits
, false);
164 return APFloat(isDouble
? APFloat(api
.bitsToDouble())
165 : APFloat(api
.bitsToFloat()));
168 static bool CompareB(uint64_t rs1
, uint64_t rs2
, uint32_t funct3
) {
175 return int64_t(rs1
) < int64_t(rs2
);
177 return int64_t(rs1
) >= int64_t(rs2
);
183 llvm_unreachable("unexpected funct3");
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
>;
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
>;
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
>;
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
>;
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
>;
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
>;
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
));
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
);
233 return transformOptional(
234 emulator
.ReadMem
<T
>(*addr
),
235 [&](T t
) { return inst
.rd
.Write(emulator
, extend(E(t
))); })
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
);
245 return transformOptional(
246 inst
.rs2
.Read(emulator
),
247 [&](uint64_t rs2
) { return emulator
.WriteMem
<T
>(*addr
, rs2
); })
251 template <typename I
>
252 static std::enable_if_t
<is_amo_add
<I
> || is_amo_bit_op
<I
> || is_amo_swap
<I
> ||
254 std::optional
<uint64_t>>
255 AtomicAddr(EmulateInstructionRISCV
&emulator
, I inst
, unsigned int align
) {
256 return transformOptional(inst
.rs1
.Read(emulator
),
258 return rs1
% align
== 0
259 ? std::optional
<uint64_t>(rs1
)
262 .value_or(std::nullopt
);
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
);
272 return transformOptional(
273 zipOpt(emulator
.ReadMem
<T
>(*addr
), inst
.rs2
.Read(emulator
)),
275 auto [tmp
, rs2
] = tup
;
276 return emulator
.WriteMem
<T
>(*addr
, T(rs2
)) &&
277 inst
.rd
.Write(emulator
, extend(tmp
));
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
);
289 return transformOptional(
290 zipOpt(emulator
.ReadMem
<T
>(*addr
), inst
.rs2
.Read(emulator
)),
292 auto [tmp
, rs2
] = tup
;
293 return emulator
.WriteMem
<T
>(*addr
, T(tmp
+ rs2
)) &&
294 inst
.rd
.Write(emulator
, extend(tmp
));
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
);
306 return transformOptional(
307 zipOpt(emulator
.ReadMem
<T
>(*addr
), inst
.rs2
.Read(emulator
)),
309 auto [value
, rs2
] = tup
;
310 return emulator
.WriteMem
<T
>(*addr
, operate(value
, T(rs2
))) &&
311 inst
.rd
.Write(emulator
, extend(value
));
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
);
323 return transformOptional(
324 zipOpt(emulator
.ReadMem
<T
>(*addr
), inst
.rs2
.Read(emulator
)),
326 auto [value
, rs2
] = tup
;
327 return emulator
.WriteMem
<T
>(*addr
, cmp(value
, T(rs2
))) &&
328 inst
.rd
.Write(emulator
, extend(value
));
333 bool AtomicSequence(EmulateInstructionRISCV
&emulator
) {
334 // The atomic sequence is always 4 instructions long:
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();
344 auto current_pc
= *pc
;
345 const auto entry_pc
= current_pc
;
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
)))
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
))
357 auto bne_exit
= std::get
<B
>(inst
->decoded
);
358 if (bne_exit
.funct3
!= BNE
)
360 // save the exit address to check later
361 const auto exit_pc
= current_pc
+ SextW(bne_exit
.imm
);
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
)))
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
))
373 auto bne_start
= std::get
<B
>(inst
->decoded
);
374 if (bne_start
.funct3
!= BNE
)
376 if (entry_pc
!= current_pc
+ SextW(bne_start
.imm
))
380 // check the exit address and jump to it
381 return exit_pc
== current_pc
&& emulator
.WritePC(current_pc
);
384 template <typename T
> static RISCVInst
DecodeUType(uint32_t inst
) {
385 return T
{Rd
{DecodeRD(inst
)}, DecodeUImm(inst
)};
388 template <typename T
> static RISCVInst
DecodeJType(uint32_t inst
) {
389 return T
{Rd
{DecodeRD(inst
)}, DecodeJImm(inst
)};
392 template <typename T
> static RISCVInst
DecodeIType(uint32_t inst
) {
393 return T
{Rd
{DecodeRD(inst
)}, Rs
{DecodeRS1(inst
)}, DecodeIImm(inst
)};
396 template <typename T
> static RISCVInst
DecodeBType(uint32_t inst
) {
397 return T
{Rs
{DecodeRS1(inst
)}, Rs
{DecodeRS2(inst
)}, DecodeBImm(inst
),
401 template <typename T
> static RISCVInst
DecodeSType(uint32_t inst
) {
402 return T
{Rs
{DecodeRS1(inst
)}, Rs
{DecodeRS2(inst
)}, DecodeSImm(inst
)};
405 template <typename T
> static RISCVInst
DecodeRType(uint32_t inst
) {
406 return T
{Rd
{DecodeRD(inst
)}, Rs
{DecodeRS1(inst
)}, Rs
{DecodeRS2(inst
)}};
409 template <typename T
> static RISCVInst
DecodeRShamtType(uint32_t inst
) {
410 return T
{Rd
{DecodeRD(inst
)}, Rs
{DecodeRS1(inst
)}, DecodeRS2(inst
)};
413 template <typename T
> static RISCVInst
DecodeRRS1Type(uint32_t inst
) {
414 return T
{Rd
{DecodeRD(inst
)}, Rs
{DecodeRS1(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
)};
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
>},
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
>},
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
>},
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
},
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
},
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
},
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
>},
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
>},
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
>},
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
>},
621 std::optional
<DecodeResult
> EmulateInstructionRISCV::Decode(uint32_t inst
) {
622 Log
*log
= GetLog(LLDBLog::Unwind
);
624 uint16_t try_rvc
= uint16_t(inst
& 0x0000ffff);
625 uint8_t inst_type
= RV64
;
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;
643 m_last_size
= std::nullopt
;
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
)
650 for (const InstrPattern
&pat
: PATTERNS
) {
651 if ((inst
& pat
.type_mask
) == pat
.eigen
&&
652 (inst_type
& pat
.inst_type
) != 0) {
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
};
660 LLDB_LOGF(log
, "EmulateInstructionRISCV::%s: inst(0x%x) was unsupported",
666 EmulateInstructionRISCV
&m_emu
;
671 // also used in EvaluateInstruction()
672 static uint64_t size(bool is_rvc
) { return is_rvc
? 2 : 4; }
675 uint64_t delta() { return size(m_is_rvc
); }
678 Executor(EmulateInstructionRISCV
&emulator
, bool ignoreCond
, bool is_rvc
)
679 : m_emu(emulator
), m_ignore_cond(ignoreCond
), m_is_rvc(is_rvc
) {}
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(),
685 return inst
.rd
.Write(m_emu
,
686 SignExt(inst
.imm
) + pc
);
690 bool operator()(JAL inst
) {
691 return transformOptional(m_emu
.ReadPC(),
693 return inst
.rd
.Write(m_emu
, pc
+ delta()) &&
694 m_emu
.WritePC(SignExt(inst
.imm
) + pc
);
698 bool operator()(JALR inst
) {
699 return transformOptional(zipOpt(m_emu
.ReadPC(), inst
.rs1
.Read(m_emu
)),
701 auto [pc
, rs1
] = tup
;
702 return inst
.rd
.Write(m_emu
, pc
+ delta()) &&
703 m_emu
.WritePC((SignExt(inst
.imm
) + rs1
) &
708 bool operator()(B inst
) {
709 return transformOptional(zipOpt(m_emu
.ReadPC(), inst
.rs1
.Read(m_emu
),
710 inst
.rs2
.Read(m_emu
)),
712 auto [pc
, rs1
, rs2
] = tup
;
714 CompareB(rs1
, rs2
, inst
.funct3
))
715 return m_emu
.WritePC(SignExt(inst
.imm
) + pc
);
720 bool operator()(LB inst
) {
721 return Load
<LB
, uint8_t, int8_t>(m_emu
, inst
, SextW
);
723 bool operator()(LH inst
) {
724 return Load
<LH
, uint16_t, int16_t>(m_emu
, inst
, SextW
);
726 bool operator()(LW inst
) {
727 return Load
<LW
, uint32_t, int32_t>(m_emu
, inst
, SextW
);
729 bool operator()(LBU inst
) {
730 return Load
<LBU
, uint8_t, uint8_t>(m_emu
, inst
, ZextD
);
732 bool operator()(LHU inst
) {
733 return Load
<LHU
, uint16_t, uint16_t>(m_emu
, inst
, ZextD
);
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
),
741 return inst
.rd
.Write(
742 m_emu
, rs1
+ int64_t(SignExt(inst
.imm
)));
746 bool operator()(SLTI inst
) {
747 return transformOptional(inst
.rs1
.ReadI64(m_emu
),
749 return inst
.rd
.Write(
750 m_emu
, rs1
< int64_t(SignExt(inst
.imm
)));
754 bool operator()(SLTIU inst
) {
755 return transformOptional(inst
.rs1
.Read(m_emu
),
757 return inst
.rd
.Write(
758 m_emu
, rs1
< uint64_t(SignExt(inst
.imm
)));
762 bool operator()(XORI inst
) {
763 return transformOptional(inst
.rs1
.Read(m_emu
),
765 return inst
.rd
.Write(
766 m_emu
, rs1
^ uint64_t(SignExt(inst
.imm
)));
770 bool operator()(ORI inst
) {
771 return transformOptional(inst
.rs1
.Read(m_emu
),
773 return inst
.rd
.Write(
774 m_emu
, rs1
| uint64_t(SignExt(inst
.imm
)));
778 bool operator()(ANDI inst
) {
779 return transformOptional(inst
.rs1
.Read(m_emu
),
781 return inst
.rd
.Write(
782 m_emu
, rs1
& uint64_t(SignExt(inst
.imm
)));
786 bool operator()(ADD inst
) {
787 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
789 auto [rs1
, rs2
] = tup
;
790 return inst
.rd
.Write(m_emu
, rs1
+ rs2
);
794 bool operator()(SUB inst
) {
795 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
797 auto [rs1
, rs2
] = tup
;
798 return inst
.rd
.Write(m_emu
, rs1
- rs2
);
802 bool operator()(SLL inst
) {
803 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
805 auto [rs1
, rs2
] = tup
;
806 return inst
.rd
.Write(m_emu
,
807 rs1
<< (rs2
& 0b111111));
811 bool operator()(SLT inst
) {
812 return transformOptional(
813 zipOpt(inst
.rs1
.ReadI64(m_emu
), inst
.rs2
.ReadI64(m_emu
)),
815 auto [rs1
, rs2
] = tup
;
816 return inst
.rd
.Write(m_emu
, rs1
< rs2
);
820 bool operator()(SLTU inst
) {
821 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
823 auto [rs1
, rs2
] = tup
;
824 return inst
.rd
.Write(m_emu
, rs1
< rs2
);
828 bool operator()(XOR inst
) {
829 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
831 auto [rs1
, rs2
] = tup
;
832 return inst
.rd
.Write(m_emu
, rs1
^ rs2
);
836 bool operator()(SRL inst
) {
837 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
839 auto [rs1
, rs2
] = tup
;
840 return inst
.rd
.Write(m_emu
,
841 rs1
>> (rs2
& 0b111111));
845 bool operator()(SRA inst
) {
846 return transformOptional(
847 zipOpt(inst
.rs1
.ReadI64(m_emu
), inst
.rs2
.Read(m_emu
)),
849 auto [rs1
, rs2
] = tup
;
850 return inst
.rd
.Write(m_emu
, rs1
>> (rs2
& 0b111111));
854 bool operator()(OR inst
) {
855 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
857 auto [rs1
, rs2
] = tup
;
858 return inst
.rd
.Write(m_emu
, rs1
| rs2
);
862 bool operator()(AND inst
) {
863 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
865 auto [rs1
, rs2
] = tup
;
866 return inst
.rd
.Write(m_emu
, rs1
& rs2
);
870 bool operator()(LWU inst
) {
871 return Load
<LWU
, uint32_t, uint32_t>(m_emu
, inst
, ZextD
);
873 bool operator()(LD inst
) {
874 return Load
<LD
, uint64_t, uint64_t>(m_emu
, inst
, ZextD
);
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
),
880 return inst
.rd
.Write(m_emu
, rs1
<< inst
.shamt
);
884 bool operator()(SRLI inst
) {
885 return transformOptional(inst
.rs1
.Read(m_emu
),
887 return inst
.rd
.Write(m_emu
, rs1
>> inst
.shamt
);
891 bool operator()(SRAI inst
) {
892 return transformOptional(inst
.rs1
.ReadI64(m_emu
),
894 return inst
.rd
.Write(m_emu
, rs1
>> inst
.shamt
);
898 bool operator()(ADDIW inst
) {
899 return transformOptional(inst
.rs1
.ReadI32(m_emu
),
901 return inst
.rd
.Write(
902 m_emu
, SextW(rs1
+ SignExt(inst
.imm
)));
906 bool operator()(SLLIW inst
) {
907 return transformOptional(inst
.rs1
.ReadU32(m_emu
),
909 return inst
.rd
.Write(m_emu
,
910 SextW(rs1
<< inst
.shamt
));
914 bool operator()(SRLIW inst
) {
915 return transformOptional(inst
.rs1
.ReadU32(m_emu
),
917 return inst
.rd
.Write(m_emu
,
918 SextW(rs1
>> inst
.shamt
));
922 bool operator()(SRAIW inst
) {
923 return transformOptional(inst
.rs1
.ReadI32(m_emu
),
925 return inst
.rd
.Write(m_emu
,
926 SextW(rs1
>> inst
.shamt
));
930 bool operator()(ADDW inst
) {
931 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
933 auto [rs1
, rs2
] = tup
;
934 return inst
.rd
.Write(m_emu
,
935 SextW(uint32_t(rs1
+ rs2
)));
939 bool operator()(SUBW inst
) {
940 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
942 auto [rs1
, rs2
] = tup
;
943 return inst
.rd
.Write(m_emu
,
944 SextW(uint32_t(rs1
- rs2
)));
948 bool operator()(SLLW inst
) {
949 return transformOptional(
950 zipOpt(inst
.rs1
.ReadU32(m_emu
), inst
.rs2
.ReadU32(m_emu
)),
952 auto [rs1
, rs2
] = tup
;
953 return inst
.rd
.Write(m_emu
, SextW(rs1
<< (rs2
& 0b11111)));
957 bool operator()(SRLW inst
) {
958 return transformOptional(
959 zipOpt(inst
.rs1
.ReadU32(m_emu
), inst
.rs2
.ReadU32(m_emu
)),
961 auto [rs1
, rs2
] = tup
;
962 return inst
.rd
.Write(m_emu
, SextW(rs1
>> (rs2
& 0b11111)));
966 bool operator()(SRAW inst
) {
967 return transformOptional(
968 zipOpt(inst
.rs1
.ReadI32(m_emu
), inst
.rs2
.Read(m_emu
)),
970 auto [rs1
, rs2
] = tup
;
971 return inst
.rd
.Write(m_emu
, SextW(rs1
>> (rs2
& 0b11111)));
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
)),
979 auto [rs1
, rs2
] = tup
;
980 return inst
.rd
.Write(m_emu
, rs1
* rs2
);
984 bool operator()(MULH inst
) {
985 return transformOptional(
986 zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
988 auto [rs1
, rs2
] = tup
;
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());
996 bool operator()(MULHSU inst
) {
997 return transformOptional(
998 zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
1000 auto [rs1
, rs2
] = tup
;
1001 // signed * unsigned
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());
1009 bool operator()(MULHU inst
) {
1010 return transformOptional(
1011 zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
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());
1021 bool operator()(DIV inst
) {
1022 return transformOptional(
1023 zipOpt(inst
.rs1
.ReadI64(m_emu
), inst
.rs2
.ReadI64(m_emu
)),
1025 auto [dividend
, divisor
] = tup
;
1028 return inst
.rd
.Write(m_emu
, UINT64_MAX
);
1030 if (dividend
== INT64_MIN
&& divisor
== -1)
1031 return inst
.rd
.Write(m_emu
, dividend
);
1033 return inst
.rd
.Write(m_emu
, dividend
/ divisor
);
1037 bool operator()(DIVU inst
) {
1038 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
1040 auto [dividend
, divisor
] = tup
;
1043 return inst
.rd
.Write(m_emu
, UINT64_MAX
);
1045 return inst
.rd
.Write(m_emu
, dividend
/ divisor
);
1049 bool operator()(REM inst
) {
1050 return transformOptional(
1051 zipOpt(inst
.rs1
.ReadI64(m_emu
), inst
.rs2
.ReadI64(m_emu
)),
1053 auto [dividend
, divisor
] = tup
;
1056 return inst
.rd
.Write(m_emu
, dividend
);
1058 if (dividend
== INT64_MIN
&& divisor
== -1)
1059 return inst
.rd
.Write(m_emu
, 0);
1061 return inst
.rd
.Write(m_emu
, dividend
% divisor
);
1065 bool operator()(REMU inst
) {
1066 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
1068 auto [dividend
, divisor
] = tup
;
1071 return inst
.rd
.Write(m_emu
, dividend
);
1073 return inst
.rd
.Write(m_emu
, dividend
% divisor
);
1077 bool operator()(MULW inst
) {
1078 return transformOptional(
1079 zipOpt(inst
.rs1
.ReadI32(m_emu
), inst
.rs2
.ReadI32(m_emu
)),
1081 auto [rs1
, rs2
] = tup
;
1082 return inst
.rd
.Write(m_emu
, SextW(rs1
* rs2
));
1086 bool operator()(DIVW inst
) {
1087 return transformOptional(
1088 zipOpt(inst
.rs1
.ReadI32(m_emu
), inst
.rs2
.ReadI32(m_emu
)),
1090 auto [dividend
, divisor
] = tup
;
1093 return inst
.rd
.Write(m_emu
, UINT64_MAX
);
1095 if (dividend
== INT32_MIN
&& divisor
== -1)
1096 return inst
.rd
.Write(m_emu
, SextW(dividend
));
1098 return inst
.rd
.Write(m_emu
, SextW(dividend
/ divisor
));
1102 bool operator()(DIVUW inst
) {
1103 return transformOptional(
1104 zipOpt(inst
.rs1
.ReadU32(m_emu
), inst
.rs2
.ReadU32(m_emu
)),
1106 auto [dividend
, divisor
] = tup
;
1109 return inst
.rd
.Write(m_emu
, UINT64_MAX
);
1111 return inst
.rd
.Write(m_emu
, SextW(dividend
/ divisor
));
1115 bool operator()(REMW inst
) {
1116 return transformOptional(
1117 zipOpt(inst
.rs1
.ReadI32(m_emu
), inst
.rs2
.ReadI32(m_emu
)),
1119 auto [dividend
, divisor
] = tup
;
1122 return inst
.rd
.Write(m_emu
, SextW(dividend
));
1124 if (dividend
== INT32_MIN
&& divisor
== -1)
1125 return inst
.rd
.Write(m_emu
, 0);
1127 return inst
.rd
.Write(m_emu
, SextW(dividend
% divisor
));
1131 bool operator()(REMUW inst
) {
1132 return transformOptional(
1133 zipOpt(inst
.rs1
.ReadU32(m_emu
), inst
.rs2
.ReadU32(m_emu
)),
1135 auto [dividend
, divisor
] = tup
;
1138 return inst
.rd
.Write(m_emu
, SextW(dividend
));
1140 return inst
.rd
.Write(m_emu
, SextW(dividend
% divisor
));
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");
1150 bool operator()(SC_D
) {
1151 llvm_unreachable("should be handled in AtomicSequence");
1153 bool operator()(AMOSWAP_W inst
) {
1154 return AtomicSwap
<AMOSWAP_W
, uint32_t>(m_emu
, inst
, 4, SextW
);
1156 bool operator()(AMOADD_W inst
) {
1157 return AtomicADD
<AMOADD_W
, uint32_t>(m_emu
, inst
, 4, SextW
);
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
; });
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
; });
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
; });
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
)));
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
)));
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
); });
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
); });
1193 bool operator()(AMOSWAP_D inst
) {
1194 return AtomicSwap
<AMOSWAP_D
, uint64_t>(m_emu
, inst
, 8, ZextD
);
1196 bool operator()(AMOADD_D inst
) {
1197 return AtomicADD
<AMOADD_D
, uint64_t>(m_emu
, inst
, 8, ZextD
);
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
; });
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
; });
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
; });
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
)));
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
)));
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
); });
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
); });
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
),
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
);
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
)),
1250 auto [rs1
, rs2
] = tup
;
1251 uint64_t addr
= rs1
+ uint64_t(inst
.imm
);
1253 rs2
.bitcastToAPInt().getZExtValue();
1254 return m_emu
.WriteMem
<uint64_t>(addr
, bits
);
1258 bool operator()(FSW inst
) { return F_Store(inst
, false); }
1259 std::tuple
<bool, APFloat
> FusedMultiplyAdd(APFloat rs1
, APFloat rs2
,
1261 auto opStatus
= rs1
.fusedMultiplyAdd(rs2
, rs3
, m_emu
.GetRoundingMode());
1262 auto res
= m_emu
.SetAccruedExceptions(opStatus
);
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
)),
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
);
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
)),
1290 auto [rs1
, rs2
] = tup
;
1292 ((&rs1
)->*f
)(rs2
, m_emu
.GetRoundingMode());
1293 inst
.rd
.WriteAPFloat(m_emu
, rs1
);
1294 return m_emu
.SetAccruedExceptions(res
);
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.
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
)),
1310 auto [rs1
, rs2
] = tup
;
1314 return inst
.rd
.WriteAPFloat(m_emu
, rs1
);
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
)),
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
1329 if (rs1
.isNegative() == rs2
.isNegative()) {
1335 return inst
.rd
.WriteAPFloat(m_emu
, rs1
);
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
)),
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
);
1358 return inst
.rd
.WriteAPFloat(m_emu
, f(rs1
, rs2
));
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
);
1368 bool operator()(FCVT_WU_S inst
) {
1369 return FCVT_i2f
<FCVT_WU_S
, uint32_t, float>(inst
, false,
1370 &APFloat::convertToFloat
);
1372 template <typename T
> bool FMV_f2i(T inst
, bool isDouble
) {
1373 return transformOptional(
1374 inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1378 return inst
.rd
.Write(m_emu
, 0x7ff8'0000'0000'0000);
1380 return inst
.rd
.Write(m_emu
, 0x7fc0'0000);
1382 auto bits
= rs1
.bitcastToAPInt().getZExtValue();
1384 return inst
.rd
.Write(m_emu
, bits
);
1386 return inst
.rd
.Write(m_emu
, uint64_t(bits
& 0xffff'ffff));
1390 bool operator()(FMV_X_W inst
) { return FMV_f2i(inst
, false); }
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
)),
1401 auto [rs1
, rs2
] = tup
;
1402 if (rs1
.isNaN() || rs2
.isNaN()) {
1404 if (rs1
.isSignaling() || rs2
.isSignaling()) {
1406 m_emu
.SetAccruedExceptions(APFloat::opInvalidOp
);
1407 return res
&& inst
.rd
.Write(m_emu
, 0);
1410 auto res
= m_emu
.SetAccruedExceptions(APFloat::opInvalidOp
);
1411 return res
&& inst
.rd
.Write(m_emu
, 0);
1415 return inst
.rd
.Write(m_emu
,
1416 rs1
.compare(rs2
) == APFloat::cmpEqual
);
1418 return inst
.rd
.Write(m_emu
, rs1
.compare(rs2
) ==
1419 APFloat::cmpLessThan
);
1421 return inst
.rd
.Write(m_emu
, rs1
.compare(rs2
) !=
1422 APFloat::cmpGreaterThan
);
1424 llvm_unreachable("unsupported F_CMP");
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
),
1435 uint64_t result
= 0;
1436 if (rs1
.isInfinity() && rs1
.isNegative())
1439 if (rs1
.isNormal() && rs1
.isNegative())
1442 if (rs1
.isDenormal() && rs1
.isNegative())
1444 if (rs1
.isNegZero())
1446 if (rs1
.isPosZero())
1449 if (rs1
.isNormal() && !rs1
.isNegative())
1452 if (rs1
.isDenormal() && !rs1
.isNegative())
1454 if (rs1
.isInfinity() && !rs1
.isNegative())
1457 if (rs1
.isSignaling())
1462 return inst
.rd
.Write(m_emu
, result
);
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
),
1472 APFloat
apf(semantics
, rs1
);
1473 return inst
.rd
.WriteAPFloat(m_emu
, apf
);
1477 bool operator()(FCVT_S_W inst
) {
1478 return FCVT_f2i(inst
, &Rs::ReadI32
, APFloat::IEEEsingle());
1480 bool operator()(FCVT_S_WU inst
) {
1481 return FCVT_f2i(inst
, &Rs::ReadU32
, APFloat::IEEEsingle());
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
),
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
);
1495 bool operator()(FMV_W_X inst
) {
1496 return FMV_i2f(inst
, 32, &APInt::bitsToFloat
);
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
),
1502 E res
= E((&rs1
->*f
)());
1503 return inst
.rd
.Write(m_emu
, uint64_t(res
));
1507 bool operator()(FCVT_L_S inst
) {
1508 return FCVT_i2f
<FCVT_L_S
, int64_t, float>(inst
, false,
1509 &APFloat::convertToFloat
);
1511 bool operator()(FCVT_LU_S inst
) {
1512 return FCVT_i2f
<FCVT_LU_S
, uint64_t, float>(inst
, false,
1513 &APFloat::convertToFloat
);
1515 bool operator()(FCVT_S_L inst
) {
1516 return FCVT_f2i(inst
, &Rs::ReadI64
, APFloat::IEEEsingle());
1518 bool operator()(FCVT_S_LU inst
) {
1519 return FCVT_f2i(inst
, &Rs::Read
, APFloat::IEEEsingle());
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.
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),
1543 double d
= rs1
.convertToDouble();
1544 APFloat
apf((float(d
)));
1545 return inst
.rd
.WriteAPFloat(m_emu
, apf
);
1549 bool operator()(FCVT_D_S inst
) {
1550 return transformOptional(inst
.rs1
.ReadAPFloat(m_emu
, false),
1552 float f
= rs1
.convertToFloat();
1553 APFloat
apf((double(f
)));
1554 return inst
.rd
.WriteAPFloat(m_emu
, apf
);
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
);
1566 bool operator()(FCVT_WU_D inst
) {
1567 return FCVT_i2f
<FCVT_WU_D
, uint32_t, double>(inst
, true,
1568 &APFloat::convertToDouble
);
1570 bool operator()(FCVT_D_W inst
) {
1571 return FCVT_f2i(inst
, &Rs::ReadI32
, APFloat::IEEEdouble());
1573 bool operator()(FCVT_D_WU inst
) {
1574 return FCVT_f2i(inst
, &Rs::ReadU32
, APFloat::IEEEdouble());
1576 bool operator()(FCVT_L_D inst
) {
1577 return FCVT_i2f
<FCVT_L_D
, int64_t, double>(inst
, true,
1578 &APFloat::convertToDouble
);
1580 bool operator()(FCVT_LU_D inst
) {
1581 return FCVT_i2f
<FCVT_LU_D
, uint64_t, double>(inst
, true,
1582 &APFloat::convertToDouble
);
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());
1588 bool operator()(FCVT_D_LU inst
) {
1589 return FCVT_f2i(inst
, &Rs::Read
, APFloat::IEEEdouble());
1591 bool operator()(FMV_D_X inst
) {
1592 return FMV_i2f(inst
, 64, &APInt::bitsToDouble
);
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; }
1601 bool EmulateInstructionRISCV::Execute(DecodeResult inst
, bool ignore_cond
) {
1602 return std::visit(Executor(*this, ignore_cond
, inst
.is_rvc
), inst
.decoded
);
1605 bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options
) {
1606 bool increase_pc
= options
& eEmulateInstructionOptionAutoAdvancePC
;
1607 bool ignore_cond
= options
& eEmulateInstructionOptionIgnoreConditions
;
1610 return Execute(m_decoded
, ignore_cond
);
1612 auto old_pc
= ReadPC();
1616 bool success
= Execute(m_decoded
, ignore_cond
);
1620 auto new_pc
= ReadPC();
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
));
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
);
1636 bool EmulateInstructionRISCV::ReadInstruction() {
1637 auto addr
= ReadPC();
1638 m_addr
= addr
.value_or(LLDB_INVALID_ADDRESS
);
1641 auto inst
= ReadInstructionAt(*addr
);
1646 m_opcode
.SetOpcode16(inst
->inst
, GetByteOrder());
1648 m_opcode
.SetOpcode32(inst
->inst
, GetByteOrder());
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
;
1659 bool EmulateInstructionRISCV::WritePC(addr_t pc
) {
1660 EmulateInstruction::Context ctx
;
1661 ctx
.type
= eContextAdvancePC
;
1663 return WriteRegisterUnsigned(ctx
, eRegisterKindGeneric
,
1664 LLDB_REGNUM_GENERIC_PC
, pc
);
1667 RoundingMode
EmulateInstructionRISCV::GetRoundingMode() {
1668 bool success
= false;
1669 auto fcsr
= ReadRegisterUnsigned(eRegisterKindLLDB
, fpr_fcsr_riscv
,
1670 LLDB_INVALID_ADDRESS
, &success
);
1672 return RoundingMode::Invalid
;
1673 auto frm
= (fcsr
>> 5) & 0x7;
1676 return RoundingMode::NearestTiesToEven
;
1678 return RoundingMode::TowardZero
;
1680 return RoundingMode::TowardNegative
;
1682 return RoundingMode::TowardPositive
;
1684 return RoundingMode::Dynamic
;
1686 // Reserved for future use.
1687 return RoundingMode::Invalid
;
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
);
1699 case APFloatBase::opInvalidOp
:
1702 case APFloatBase::opDivByZero
:
1705 case APFloatBase::opOverflow
:
1708 case APFloatBase::opUnderflow
:
1711 case APFloatBase::opInexact
:
1714 case APFloatBase::opOK
:
1717 EmulateInstruction::Context ctx
;
1718 ctx
.type
= eContextRegisterStore
;
1720 return WriteRegisterUnsigned(ctx
, eRegisterKindLLDB
, fpr_fcsr_riscv
, fcsr
);
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
;
1732 case LLDB_REGNUM_GENERIC_SP
:
1733 reg_kind
= eRegisterKindLLDB
;
1734 reg_index
= gpr_sp_riscv
;
1736 case LLDB_REGNUM_GENERIC_FP
:
1737 reg_kind
= eRegisterKindLLDB
;
1738 reg_index
= gpr_fp_riscv
;
1740 case LLDB_REGNUM_GENERIC_RA
:
1741 reg_kind
= eRegisterKindLLDB
;
1742 reg_index
= gpr_ra_riscv
;
1744 // We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are
1747 llvm_unreachable("unsupported register");
1751 RegisterInfoPOSIX_riscv64
reg_info(m_arch
,
1752 RegisterInfoPOSIX_riscv64::eRegsetMaskAll
);
1753 const RegisterInfo
*array
= reg_info
.GetRegisterInfo();
1754 const uint32_t length
= reg_info
.GetRegisterCount();
1756 if (reg_index
>= length
|| reg_kind
!= eRegisterKindLLDB
)
1759 return array
[reg_index
];
1762 bool EmulateInstructionRISCV::SetTargetTriple(const ArchSpec
&arch
) {
1763 return SupportsThisArch(arch
);
1766 bool EmulateInstructionRISCV::TestEmulation(Stream
&out_stream
, ArchSpec
&arch
,
1767 OptionValueDictionary
*test_data
) {
1771 void EmulateInstructionRISCV::Initialize() {
1772 PluginManager::RegisterPlugin(GetPluginNameStatic(),
1773 GetPluginDescriptionStatic(), CreateInstance
);
1776 void EmulateInstructionRISCV::Terminate() {
1777 PluginManager::UnregisterPlugin(CreateInstance
);
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
);
1791 bool EmulateInstructionRISCV::SupportsThisArch(const ArchSpec
&arch
) {
1792 return arch
.GetTriple().isRISCV();
1795 } // namespace lldb_private