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 // check whether the compressed encode could be valid
626 uint16_t mask
= try_rvc
& 0b11;
627 bool is_rvc
= try_rvc
!= 0 && mask
!= 3;
628 uint8_t inst_type
= RV64
;
630 // if we have ArchSpec::eCore_riscv128 in the future,
631 // we also need to check it here
632 if (m_arch
.GetCore() == ArchSpec::eCore_riscv32
)
635 for (const InstrPattern
&pat
: PATTERNS
) {
636 if ((inst
& pat
.type_mask
) == pat
.eigen
&&
637 (inst_type
& pat
.inst_type
) != 0) {
639 log
, "EmulateInstructionRISCV::%s: inst(%x at %" PRIx64
") was decoded to %s",
640 __FUNCTION__
, inst
, m_addr
, pat
.name
);
641 auto decoded
= is_rvc
? pat
.decode(try_rvc
) : pat
.decode(inst
);
642 return DecodeResult
{decoded
, inst
, is_rvc
, pat
};
645 LLDB_LOGF(log
, "EmulateInstructionRISCV::%s: inst(0x%x) was unsupported",
651 EmulateInstructionRISCV
&m_emu
;
656 // also used in EvaluateInstruction()
657 static uint64_t size(bool is_rvc
) { return is_rvc
? 2 : 4; }
660 uint64_t delta() { return size(m_is_rvc
); }
663 Executor(EmulateInstructionRISCV
&emulator
, bool ignoreCond
, bool is_rvc
)
664 : m_emu(emulator
), m_ignore_cond(ignoreCond
), m_is_rvc(is_rvc
) {}
666 bool operator()(LUI inst
) { return inst
.rd
.Write(m_emu
, SignExt(inst
.imm
)); }
667 bool operator()(AUIPC inst
) {
668 return transformOptional(m_emu
.ReadPC(),
670 return inst
.rd
.Write(m_emu
,
671 SignExt(inst
.imm
) + pc
);
675 bool operator()(JAL inst
) {
676 return transformOptional(m_emu
.ReadPC(),
678 return inst
.rd
.Write(m_emu
, pc
+ delta()) &&
679 m_emu
.WritePC(SignExt(inst
.imm
) + pc
);
683 bool operator()(JALR inst
) {
684 return transformOptional(zipOpt(m_emu
.ReadPC(), inst
.rs1
.Read(m_emu
)),
686 auto [pc
, rs1
] = tup
;
687 return inst
.rd
.Write(m_emu
, pc
+ delta()) &&
688 m_emu
.WritePC((SignExt(inst
.imm
) + rs1
) &
693 bool operator()(B inst
) {
694 return transformOptional(zipOpt(m_emu
.ReadPC(), inst
.rs1
.Read(m_emu
),
695 inst
.rs2
.Read(m_emu
)),
697 auto [pc
, rs1
, rs2
] = tup
;
699 CompareB(rs1
, rs2
, inst
.funct3
))
700 return m_emu
.WritePC(SignExt(inst
.imm
) + pc
);
705 bool operator()(LB inst
) {
706 return Load
<LB
, uint8_t, int8_t>(m_emu
, inst
, SextW
);
708 bool operator()(LH inst
) {
709 return Load
<LH
, uint16_t, int16_t>(m_emu
, inst
, SextW
);
711 bool operator()(LW inst
) {
712 return Load
<LW
, uint32_t, int32_t>(m_emu
, inst
, SextW
);
714 bool operator()(LBU inst
) {
715 return Load
<LBU
, uint8_t, uint8_t>(m_emu
, inst
, ZextD
);
717 bool operator()(LHU inst
) {
718 return Load
<LHU
, uint16_t, uint16_t>(m_emu
, inst
, ZextD
);
720 bool operator()(SB inst
) { return Store
<SB
, uint8_t>(m_emu
, inst
); }
721 bool operator()(SH inst
) { return Store
<SH
, uint16_t>(m_emu
, inst
); }
722 bool operator()(SW inst
) { return Store
<SW
, uint32_t>(m_emu
, inst
); }
723 bool operator()(ADDI inst
) {
724 return transformOptional(inst
.rs1
.ReadI64(m_emu
),
726 return inst
.rd
.Write(
727 m_emu
, rs1
+ int64_t(SignExt(inst
.imm
)));
731 bool operator()(SLTI inst
) {
732 return transformOptional(inst
.rs1
.ReadI64(m_emu
),
734 return inst
.rd
.Write(
735 m_emu
, rs1
< int64_t(SignExt(inst
.imm
)));
739 bool operator()(SLTIU inst
) {
740 return transformOptional(inst
.rs1
.Read(m_emu
),
742 return inst
.rd
.Write(
743 m_emu
, rs1
< uint64_t(SignExt(inst
.imm
)));
747 bool operator()(XORI inst
) {
748 return transformOptional(inst
.rs1
.Read(m_emu
),
750 return inst
.rd
.Write(
751 m_emu
, rs1
^ uint64_t(SignExt(inst
.imm
)));
755 bool operator()(ORI inst
) {
756 return transformOptional(inst
.rs1
.Read(m_emu
),
758 return inst
.rd
.Write(
759 m_emu
, rs1
| uint64_t(SignExt(inst
.imm
)));
763 bool operator()(ANDI inst
) {
764 return transformOptional(inst
.rs1
.Read(m_emu
),
766 return inst
.rd
.Write(
767 m_emu
, rs1
& uint64_t(SignExt(inst
.imm
)));
771 bool operator()(ADD inst
) {
772 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
774 auto [rs1
, rs2
] = tup
;
775 return inst
.rd
.Write(m_emu
, rs1
+ rs2
);
779 bool operator()(SUB inst
) {
780 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
782 auto [rs1
, rs2
] = tup
;
783 return inst
.rd
.Write(m_emu
, rs1
- rs2
);
787 bool operator()(SLL inst
) {
788 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
790 auto [rs1
, rs2
] = tup
;
791 return inst
.rd
.Write(m_emu
,
792 rs1
<< (rs2
& 0b111111));
796 bool operator()(SLT inst
) {
797 return transformOptional(
798 zipOpt(inst
.rs1
.ReadI64(m_emu
), inst
.rs2
.ReadI64(m_emu
)),
800 auto [rs1
, rs2
] = tup
;
801 return inst
.rd
.Write(m_emu
, rs1
< rs2
);
805 bool operator()(SLTU inst
) {
806 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
808 auto [rs1
, rs2
] = tup
;
809 return inst
.rd
.Write(m_emu
, rs1
< rs2
);
813 bool operator()(XOR inst
) {
814 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
816 auto [rs1
, rs2
] = tup
;
817 return inst
.rd
.Write(m_emu
, rs1
^ rs2
);
821 bool operator()(SRL inst
) {
822 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
824 auto [rs1
, rs2
] = tup
;
825 return inst
.rd
.Write(m_emu
,
826 rs1
>> (rs2
& 0b111111));
830 bool operator()(SRA inst
) {
831 return transformOptional(
832 zipOpt(inst
.rs1
.ReadI64(m_emu
), inst
.rs2
.Read(m_emu
)),
834 auto [rs1
, rs2
] = tup
;
835 return inst
.rd
.Write(m_emu
, rs1
>> (rs2
& 0b111111));
839 bool operator()(OR inst
) {
840 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
842 auto [rs1
, rs2
] = tup
;
843 return inst
.rd
.Write(m_emu
, rs1
| rs2
);
847 bool operator()(AND inst
) {
848 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
850 auto [rs1
, rs2
] = tup
;
851 return inst
.rd
.Write(m_emu
, rs1
& rs2
);
855 bool operator()(LWU inst
) {
856 return Load
<LWU
, uint32_t, uint32_t>(m_emu
, inst
, ZextD
);
858 bool operator()(LD inst
) {
859 return Load
<LD
, uint64_t, uint64_t>(m_emu
, inst
, ZextD
);
861 bool operator()(SD inst
) { return Store
<SD
, uint64_t>(m_emu
, inst
); }
862 bool operator()(SLLI inst
) {
863 return transformOptional(inst
.rs1
.Read(m_emu
),
865 return inst
.rd
.Write(m_emu
, rs1
<< inst
.shamt
);
869 bool operator()(SRLI inst
) {
870 return transformOptional(inst
.rs1
.Read(m_emu
),
872 return inst
.rd
.Write(m_emu
, rs1
>> inst
.shamt
);
876 bool operator()(SRAI inst
) {
877 return transformOptional(inst
.rs1
.ReadI64(m_emu
),
879 return inst
.rd
.Write(m_emu
, rs1
>> inst
.shamt
);
883 bool operator()(ADDIW inst
) {
884 return transformOptional(inst
.rs1
.ReadI32(m_emu
),
886 return inst
.rd
.Write(
887 m_emu
, SextW(rs1
+ SignExt(inst
.imm
)));
891 bool operator()(SLLIW inst
) {
892 return transformOptional(inst
.rs1
.ReadU32(m_emu
),
894 return inst
.rd
.Write(m_emu
,
895 SextW(rs1
<< inst
.shamt
));
899 bool operator()(SRLIW inst
) {
900 return transformOptional(inst
.rs1
.ReadU32(m_emu
),
902 return inst
.rd
.Write(m_emu
,
903 SextW(rs1
>> inst
.shamt
));
907 bool operator()(SRAIW inst
) {
908 return transformOptional(inst
.rs1
.ReadI32(m_emu
),
910 return inst
.rd
.Write(m_emu
,
911 SextW(rs1
>> inst
.shamt
));
915 bool operator()(ADDW inst
) {
916 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
918 auto [rs1
, rs2
] = tup
;
919 return inst
.rd
.Write(m_emu
,
920 SextW(uint32_t(rs1
+ rs2
)));
924 bool operator()(SUBW inst
) {
925 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
927 auto [rs1
, rs2
] = tup
;
928 return inst
.rd
.Write(m_emu
,
929 SextW(uint32_t(rs1
- rs2
)));
933 bool operator()(SLLW inst
) {
934 return transformOptional(
935 zipOpt(inst
.rs1
.ReadU32(m_emu
), inst
.rs2
.ReadU32(m_emu
)),
937 auto [rs1
, rs2
] = tup
;
938 return inst
.rd
.Write(m_emu
, SextW(rs1
<< (rs2
& 0b11111)));
942 bool operator()(SRLW inst
) {
943 return transformOptional(
944 zipOpt(inst
.rs1
.ReadU32(m_emu
), inst
.rs2
.ReadU32(m_emu
)),
946 auto [rs1
, rs2
] = tup
;
947 return inst
.rd
.Write(m_emu
, SextW(rs1
>> (rs2
& 0b11111)));
951 bool operator()(SRAW inst
) {
952 return transformOptional(
953 zipOpt(inst
.rs1
.ReadI32(m_emu
), inst
.rs2
.Read(m_emu
)),
955 auto [rs1
, rs2
] = tup
;
956 return inst
.rd
.Write(m_emu
, SextW(rs1
>> (rs2
& 0b11111)));
960 // RV32M & RV64M (Integer Multiplication and Division Extension) //
961 bool operator()(MUL inst
) {
962 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
964 auto [rs1
, rs2
] = tup
;
965 return inst
.rd
.Write(m_emu
, rs1
* rs2
);
969 bool operator()(MULH inst
) {
970 return transformOptional(
971 zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
973 auto [rs1
, rs2
] = tup
;
975 auto mul
= APInt(128, rs1
, true) * APInt(128, rs2
, true);
976 return inst
.rd
.Write(m_emu
,
977 mul
.ashr(64).trunc(64).getZExtValue());
981 bool operator()(MULHSU inst
) {
982 return transformOptional(
983 zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
985 auto [rs1
, rs2
] = tup
;
988 APInt(128, rs1
, true).zext(128) * APInt(128, rs2
, false);
989 return inst
.rd
.Write(m_emu
,
990 mul
.lshr(64).trunc(64).getZExtValue());
994 bool operator()(MULHU inst
) {
995 return transformOptional(
996 zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
998 auto [rs1
, rs2
] = tup
;
999 // unsigned * unsigned
1000 auto mul
= APInt(128, rs1
, false) * APInt(128, rs2
, false);
1001 return inst
.rd
.Write(m_emu
,
1002 mul
.lshr(64).trunc(64).getZExtValue());
1006 bool operator()(DIV inst
) {
1007 return transformOptional(
1008 zipOpt(inst
.rs1
.ReadI64(m_emu
), inst
.rs2
.ReadI64(m_emu
)),
1010 auto [dividend
, divisor
] = tup
;
1013 return inst
.rd
.Write(m_emu
, UINT64_MAX
);
1015 if (dividend
== INT64_MIN
&& divisor
== -1)
1016 return inst
.rd
.Write(m_emu
, dividend
);
1018 return inst
.rd
.Write(m_emu
, dividend
/ divisor
);
1022 bool operator()(DIVU inst
) {
1023 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
1025 auto [dividend
, divisor
] = tup
;
1028 return inst
.rd
.Write(m_emu
, UINT64_MAX
);
1030 return inst
.rd
.Write(m_emu
, dividend
/ divisor
);
1034 bool operator()(REM inst
) {
1035 return transformOptional(
1036 zipOpt(inst
.rs1
.ReadI64(m_emu
), inst
.rs2
.ReadI64(m_emu
)),
1038 auto [dividend
, divisor
] = tup
;
1041 return inst
.rd
.Write(m_emu
, dividend
);
1043 if (dividend
== INT64_MIN
&& divisor
== -1)
1044 return inst
.rd
.Write(m_emu
, 0);
1046 return inst
.rd
.Write(m_emu
, dividend
% divisor
);
1050 bool operator()(REMU inst
) {
1051 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
), inst
.rs2
.Read(m_emu
)),
1053 auto [dividend
, divisor
] = tup
;
1056 return inst
.rd
.Write(m_emu
, dividend
);
1058 return inst
.rd
.Write(m_emu
, dividend
% divisor
);
1062 bool operator()(MULW inst
) {
1063 return transformOptional(
1064 zipOpt(inst
.rs1
.ReadI32(m_emu
), inst
.rs2
.ReadI32(m_emu
)),
1066 auto [rs1
, rs2
] = tup
;
1067 return inst
.rd
.Write(m_emu
, SextW(rs1
* rs2
));
1071 bool operator()(DIVW inst
) {
1072 return transformOptional(
1073 zipOpt(inst
.rs1
.ReadI32(m_emu
), inst
.rs2
.ReadI32(m_emu
)),
1075 auto [dividend
, divisor
] = tup
;
1078 return inst
.rd
.Write(m_emu
, UINT64_MAX
);
1080 if (dividend
== INT32_MIN
&& divisor
== -1)
1081 return inst
.rd
.Write(m_emu
, SextW(dividend
));
1083 return inst
.rd
.Write(m_emu
, SextW(dividend
/ divisor
));
1087 bool operator()(DIVUW inst
) {
1088 return transformOptional(
1089 zipOpt(inst
.rs1
.ReadU32(m_emu
), inst
.rs2
.ReadU32(m_emu
)),
1091 auto [dividend
, divisor
] = tup
;
1094 return inst
.rd
.Write(m_emu
, UINT64_MAX
);
1096 return inst
.rd
.Write(m_emu
, SextW(dividend
/ divisor
));
1100 bool operator()(REMW inst
) {
1101 return transformOptional(
1102 zipOpt(inst
.rs1
.ReadI32(m_emu
), inst
.rs2
.ReadI32(m_emu
)),
1104 auto [dividend
, divisor
] = tup
;
1107 return inst
.rd
.Write(m_emu
, SextW(dividend
));
1109 if (dividend
== INT32_MIN
&& divisor
== -1)
1110 return inst
.rd
.Write(m_emu
, 0);
1112 return inst
.rd
.Write(m_emu
, SextW(dividend
% divisor
));
1116 bool operator()(REMUW inst
) {
1117 return transformOptional(
1118 zipOpt(inst
.rs1
.ReadU32(m_emu
), inst
.rs2
.ReadU32(m_emu
)),
1120 auto [dividend
, divisor
] = tup
;
1123 return inst
.rd
.Write(m_emu
, SextW(dividend
));
1125 return inst
.rd
.Write(m_emu
, SextW(dividend
% divisor
));
1129 // RV32A & RV64A (The standard atomic instruction extension) //
1130 bool operator()(LR_W
) { return AtomicSequence(m_emu
); }
1131 bool operator()(LR_D
) { return AtomicSequence(m_emu
); }
1132 bool operator()(SC_W
) {
1133 llvm_unreachable("should be handled in AtomicSequence");
1135 bool operator()(SC_D
) {
1136 llvm_unreachable("should be handled in AtomicSequence");
1138 bool operator()(AMOSWAP_W inst
) {
1139 return AtomicSwap
<AMOSWAP_W
, uint32_t>(m_emu
, inst
, 4, SextW
);
1141 bool operator()(AMOADD_W inst
) {
1142 return AtomicADD
<AMOADD_W
, uint32_t>(m_emu
, inst
, 4, SextW
);
1144 bool operator()(AMOXOR_W inst
) {
1145 return AtomicBitOperate
<AMOXOR_W
, uint32_t>(
1146 m_emu
, inst
, 4, SextW
, [](uint32_t a
, uint32_t b
) { return a
^ b
; });
1148 bool operator()(AMOAND_W inst
) {
1149 return AtomicBitOperate
<AMOAND_W
, uint32_t>(
1150 m_emu
, inst
, 4, SextW
, [](uint32_t a
, uint32_t b
) { return a
& b
; });
1152 bool operator()(AMOOR_W inst
) {
1153 return AtomicBitOperate
<AMOOR_W
, uint32_t>(
1154 m_emu
, inst
, 4, SextW
, [](uint32_t a
, uint32_t b
) { return a
| b
; });
1156 bool operator()(AMOMIN_W inst
) {
1157 return AtomicCmp
<AMOMIN_W
, uint32_t>(
1158 m_emu
, inst
, 4, SextW
, [](uint32_t a
, uint32_t b
) {
1159 return uint32_t(std::min(int32_t(a
), int32_t(b
)));
1162 bool operator()(AMOMAX_W inst
) {
1163 return AtomicCmp
<AMOMAX_W
, uint32_t>(
1164 m_emu
, inst
, 4, SextW
, [](uint32_t a
, uint32_t b
) {
1165 return uint32_t(std::max(int32_t(a
), int32_t(b
)));
1168 bool operator()(AMOMINU_W inst
) {
1169 return AtomicCmp
<AMOMINU_W
, uint32_t>(
1170 m_emu
, inst
, 4, SextW
,
1171 [](uint32_t a
, uint32_t b
) { return std::min(a
, b
); });
1173 bool operator()(AMOMAXU_W inst
) {
1174 return AtomicCmp
<AMOMAXU_W
, uint32_t>(
1175 m_emu
, inst
, 4, SextW
,
1176 [](uint32_t a
, uint32_t b
) { return std::max(a
, b
); });
1178 bool operator()(AMOSWAP_D inst
) {
1179 return AtomicSwap
<AMOSWAP_D
, uint64_t>(m_emu
, inst
, 8, ZextD
);
1181 bool operator()(AMOADD_D inst
) {
1182 return AtomicADD
<AMOADD_D
, uint64_t>(m_emu
, inst
, 8, ZextD
);
1184 bool operator()(AMOXOR_D inst
) {
1185 return AtomicBitOperate
<AMOXOR_D
, uint64_t>(
1186 m_emu
, inst
, 8, ZextD
, [](uint64_t a
, uint64_t b
) { return a
^ b
; });
1188 bool operator()(AMOAND_D inst
) {
1189 return AtomicBitOperate
<AMOAND_D
, uint64_t>(
1190 m_emu
, inst
, 8, ZextD
, [](uint64_t a
, uint64_t b
) { return a
& b
; });
1192 bool operator()(AMOOR_D inst
) {
1193 return AtomicBitOperate
<AMOOR_D
, uint64_t>(
1194 m_emu
, inst
, 8, ZextD
, [](uint64_t a
, uint64_t b
) { return a
| b
; });
1196 bool operator()(AMOMIN_D inst
) {
1197 return AtomicCmp
<AMOMIN_D
, uint64_t>(
1198 m_emu
, inst
, 8, ZextD
, [](uint64_t a
, uint64_t b
) {
1199 return uint64_t(std::min(int64_t(a
), int64_t(b
)));
1202 bool operator()(AMOMAX_D inst
) {
1203 return AtomicCmp
<AMOMAX_D
, uint64_t>(
1204 m_emu
, inst
, 8, ZextD
, [](uint64_t a
, uint64_t b
) {
1205 return uint64_t(std::max(int64_t(a
), int64_t(b
)));
1208 bool operator()(AMOMINU_D inst
) {
1209 return AtomicCmp
<AMOMINU_D
, uint64_t>(
1210 m_emu
, inst
, 8, ZextD
,
1211 [](uint64_t a
, uint64_t b
) { return std::min(a
, b
); });
1213 bool operator()(AMOMAXU_D inst
) {
1214 return AtomicCmp
<AMOMAXU_D
, uint64_t>(
1215 m_emu
, inst
, 8, ZextD
,
1216 [](uint64_t a
, uint64_t b
) { return std::max(a
, b
); });
1218 template <typename T
>
1219 bool F_Load(T inst
, const fltSemantics
&(*semantics
)(),
1220 unsigned int numBits
) {
1221 return transformOptional(inst
.rs1
.Read(m_emu
),
1223 uint64_t addr
= rs1
+ uint64_t(inst
.imm
);
1224 uint64_t bits
= *m_emu
.ReadMem
<uint64_t>(addr
);
1225 APFloat
f(semantics(), APInt(numBits
, bits
));
1226 return inst
.rd
.WriteAPFloat(m_emu
, f
);
1230 bool operator()(FLW inst
) { return F_Load(inst
, &APFloat::IEEEsingle
, 32); }
1231 template <typename T
> bool F_Store(T inst
, bool isDouble
) {
1232 return transformOptional(zipOpt(inst
.rs1
.Read(m_emu
),
1233 inst
.rs2
.ReadAPFloat(m_emu
, isDouble
)),
1235 auto [rs1
, rs2
] = tup
;
1236 uint64_t addr
= rs1
+ uint64_t(inst
.imm
);
1238 rs2
.bitcastToAPInt().getZExtValue();
1239 return m_emu
.WriteMem
<uint64_t>(addr
, bits
);
1243 bool operator()(FSW inst
) { return F_Store(inst
, false); }
1244 std::tuple
<bool, APFloat
> FusedMultiplyAdd(APFloat rs1
, APFloat rs2
,
1246 auto opStatus
= rs1
.fusedMultiplyAdd(rs2
, rs3
, m_emu
.GetRoundingMode());
1247 auto res
= m_emu
.SetAccruedExceptions(opStatus
);
1250 template <typename T
>
1251 bool FMA(T inst
, bool isDouble
, float rs2_sign
, float rs3_sign
) {
1252 return transformOptional(zipOpt(inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1253 inst
.rs2
.ReadAPFloat(m_emu
, isDouble
),
1254 inst
.rs3
.ReadAPFloat(m_emu
, isDouble
)),
1256 auto [rs1
, rs2
, rs3
] = tup
;
1257 rs2
.copySign(APFloat(rs2_sign
));
1258 rs3
.copySign(APFloat(rs3_sign
));
1259 auto [res
, f
] = FusedMultiplyAdd(rs1
, rs2
, rs3
);
1260 return res
&& inst
.rd
.WriteAPFloat(m_emu
, f
);
1264 bool operator()(FMADD_S inst
) { return FMA(inst
, false, 1.0f
, 1.0f
); }
1265 bool operator()(FMSUB_S inst
) { return FMA(inst
, false, 1.0f
, -1.0f
); }
1266 bool operator()(FNMSUB_S inst
) { return FMA(inst
, false, -1.0f
, 1.0f
); }
1267 bool operator()(FNMADD_S inst
) { return FMA(inst
, false, -1.0f
, -1.0f
); }
1268 template <typename T
>
1269 bool F_Op(T inst
, bool isDouble
,
1270 APFloat::opStatus (APFloat::*f
)(const APFloat
&RHS
,
1271 APFloat::roundingMode RM
)) {
1272 return transformOptional(zipOpt(inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1273 inst
.rs2
.ReadAPFloat(m_emu
, isDouble
)),
1275 auto [rs1
, rs2
] = tup
;
1277 ((&rs1
)->*f
)(rs2
, m_emu
.GetRoundingMode());
1278 inst
.rd
.WriteAPFloat(m_emu
, rs1
);
1279 return m_emu
.SetAccruedExceptions(res
);
1283 bool operator()(FADD_S inst
) { return F_Op(inst
, false, &APFloat::add
); }
1284 bool operator()(FSUB_S inst
) { return F_Op(inst
, false, &APFloat::subtract
); }
1285 bool operator()(FMUL_S inst
) { return F_Op(inst
, false, &APFloat::multiply
); }
1286 bool operator()(FDIV_S inst
) { return F_Op(inst
, false, &APFloat::divide
); }
1287 bool operator()(FSQRT_S inst
) {
1288 // TODO: APFloat doesn't have a sqrt function.
1291 template <typename T
> bool F_SignInj(T inst
, bool isDouble
, bool isNegate
) {
1292 return transformOptional(zipOpt(inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1293 inst
.rs2
.ReadAPFloat(m_emu
, isDouble
)),
1295 auto [rs1
, rs2
] = tup
;
1299 return inst
.rd
.WriteAPFloat(m_emu
, rs1
);
1303 bool operator()(FSGNJ_S inst
) { return F_SignInj(inst
, false, false); }
1304 bool operator()(FSGNJN_S inst
) { return F_SignInj(inst
, false, true); }
1305 template <typename T
> bool F_SignInjXor(T inst
, bool isDouble
) {
1306 return transformOptional(zipOpt(inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1307 inst
.rs2
.ReadAPFloat(m_emu
, isDouble
)),
1309 auto [rs1
, rs2
] = tup
;
1310 // spec: the sign bit is the XOR of the sign bits
1311 // of rs1 and rs2. if rs1 and rs2 have the same
1312 // signs set rs1 to positive else set rs1 to
1314 if (rs1
.isNegative() == rs2
.isNegative()) {
1320 return inst
.rd
.WriteAPFloat(m_emu
, rs1
);
1324 bool operator()(FSGNJX_S inst
) { return F_SignInjXor(inst
, false); }
1325 template <typename T
>
1326 bool F_MAX_MIN(T inst
, bool isDouble
,
1327 APFloat (*f
)(const APFloat
&A
, const APFloat
&B
)) {
1328 return transformOptional(
1329 zipOpt(inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1330 inst
.rs2
.ReadAPFloat(m_emu
, isDouble
)),
1332 auto [rs1
, rs2
] = tup
;
1333 // If both inputs are NaNs, the result is the canonical NaN.
1334 // If only one operand is a NaN, the result is the non-NaN
1335 // operand. Signaling NaN inputs set the invalid operation
1336 // exception flag, even when the result is not NaN.
1337 if (rs1
.isNaN() || rs2
.isNaN())
1338 m_emu
.SetAccruedExceptions(APFloat::opInvalidOp
);
1339 if (rs1
.isNaN() && rs2
.isNaN()) {
1340 auto canonicalNaN
= APFloat::getQNaN(rs1
.getSemantics());
1341 return inst
.rd
.WriteAPFloat(m_emu
, canonicalNaN
);
1343 return inst
.rd
.WriteAPFloat(m_emu
, f(rs1
, rs2
));
1347 bool operator()(FMIN_S inst
) { return F_MAX_MIN(inst
, false, minnum
); }
1348 bool operator()(FMAX_S inst
) { return F_MAX_MIN(inst
, false, maxnum
); }
1349 bool operator()(FCVT_W_S inst
) {
1350 return FCVT_i2f
<FCVT_W_S
, int32_t, float>(inst
, false,
1351 &APFloat::convertToFloat
);
1353 bool operator()(FCVT_WU_S inst
) {
1354 return FCVT_i2f
<FCVT_WU_S
, uint32_t, float>(inst
, false,
1355 &APFloat::convertToFloat
);
1357 template <typename T
> bool FMV_f2i(T inst
, bool isDouble
) {
1358 return transformOptional(
1359 inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1363 return inst
.rd
.Write(m_emu
, 0x7ff8'0000'0000'0000);
1365 return inst
.rd
.Write(m_emu
, 0x7fc0'0000);
1367 auto bits
= rs1
.bitcastToAPInt().getZExtValue();
1369 return inst
.rd
.Write(m_emu
, bits
);
1371 return inst
.rd
.Write(m_emu
, uint64_t(bits
& 0xffff'ffff));
1375 bool operator()(FMV_X_W inst
) { return FMV_f2i(inst
, false); }
1381 template <typename T
> bool F_Compare(T inst
, bool isDouble
, F_CMP cmp
) {
1382 return transformOptional(
1383 zipOpt(inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1384 inst
.rs2
.ReadAPFloat(m_emu
, isDouble
)),
1386 auto [rs1
, rs2
] = tup
;
1387 if (rs1
.isNaN() || rs2
.isNaN()) {
1389 if (rs1
.isSignaling() || rs2
.isSignaling()) {
1391 m_emu
.SetAccruedExceptions(APFloat::opInvalidOp
);
1392 return res
&& inst
.rd
.Write(m_emu
, 0);
1395 auto res
= m_emu
.SetAccruedExceptions(APFloat::opInvalidOp
);
1396 return res
&& inst
.rd
.Write(m_emu
, 0);
1400 return inst
.rd
.Write(m_emu
,
1401 rs1
.compare(rs2
) == APFloat::cmpEqual
);
1403 return inst
.rd
.Write(m_emu
, rs1
.compare(rs2
) ==
1404 APFloat::cmpLessThan
);
1406 return inst
.rd
.Write(m_emu
, rs1
.compare(rs2
) !=
1407 APFloat::cmpGreaterThan
);
1409 llvm_unreachable("unsupported F_CMP");
1414 bool operator()(FEQ_S inst
) { return F_Compare(inst
, false, FEQ
); }
1415 bool operator()(FLT_S inst
) { return F_Compare(inst
, false, FLT
); }
1416 bool operator()(FLE_S inst
) { return F_Compare(inst
, false, FLE
); }
1417 template <typename T
> bool FCLASS(T inst
, bool isDouble
) {
1418 return transformOptional(inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1420 uint64_t result
= 0;
1421 if (rs1
.isInfinity() && rs1
.isNegative())
1424 if (rs1
.isNormal() && rs1
.isNegative())
1427 if (rs1
.isDenormal() && rs1
.isNegative())
1429 if (rs1
.isNegZero())
1431 if (rs1
.isPosZero())
1434 if (rs1
.isNormal() && !rs1
.isNegative())
1437 if (rs1
.isDenormal() && !rs1
.isNegative())
1439 if (rs1
.isInfinity() && !rs1
.isNegative())
1442 if (rs1
.isSignaling())
1447 return inst
.rd
.Write(m_emu
, result
);
1451 bool operator()(FCLASS_S inst
) { return FCLASS(inst
, false); }
1452 template <typename T
, typename E
>
1453 bool FCVT_f2i(T inst
, std::optional
<E
> (Rs::*f
)(EmulateInstructionRISCV
&emu
),
1454 const fltSemantics
&semantics
) {
1455 return transformOptional(((&inst
.rs1
)->*f
)(m_emu
),
1457 APFloat
apf(semantics
, rs1
);
1458 return inst
.rd
.WriteAPFloat(m_emu
, apf
);
1462 bool operator()(FCVT_S_W inst
) {
1463 return FCVT_f2i(inst
, &Rs::ReadI32
, APFloat::IEEEsingle());
1465 bool operator()(FCVT_S_WU inst
) {
1466 return FCVT_f2i(inst
, &Rs::ReadU32
, APFloat::IEEEsingle());
1468 template <typename T
, typename E
>
1469 bool FMV_i2f(T inst
, unsigned int numBits
, E (APInt::*f
)() const) {
1470 return transformOptional(inst
.rs1
.Read(m_emu
),
1472 APInt
apInt(numBits
, rs1
);
1473 if (numBits
== 32) // a.k.a. float
1474 apInt
= APInt(numBits
, NanUnBoxing(rs1
));
1475 APFloat
apf((&apInt
->*f
)());
1476 return inst
.rd
.WriteAPFloat(m_emu
, apf
);
1480 bool operator()(FMV_W_X inst
) {
1481 return FMV_i2f(inst
, 32, &APInt::bitsToFloat
);
1483 template <typename I
, typename E
, typename T
>
1484 bool FCVT_i2f(I inst
, bool isDouble
, T (APFloat::*f
)() const) {
1485 return transformOptional(inst
.rs1
.ReadAPFloat(m_emu
, isDouble
),
1487 E res
= E((&rs1
->*f
)());
1488 return inst
.rd
.Write(m_emu
, uint64_t(res
));
1492 bool operator()(FCVT_L_S inst
) {
1493 return FCVT_i2f
<FCVT_L_S
, int64_t, float>(inst
, false,
1494 &APFloat::convertToFloat
);
1496 bool operator()(FCVT_LU_S inst
) {
1497 return FCVT_i2f
<FCVT_LU_S
, uint64_t, float>(inst
, false,
1498 &APFloat::convertToFloat
);
1500 bool operator()(FCVT_S_L inst
) {
1501 return FCVT_f2i(inst
, &Rs::ReadI64
, APFloat::IEEEsingle());
1503 bool operator()(FCVT_S_LU inst
) {
1504 return FCVT_f2i(inst
, &Rs::Read
, APFloat::IEEEsingle());
1506 bool operator()(FLD inst
) { return F_Load(inst
, &APFloat::IEEEdouble
, 64); }
1507 bool operator()(FSD inst
) { return F_Store(inst
, true); }
1508 bool operator()(FMADD_D inst
) { return FMA(inst
, true, 1.0f
, 1.0f
); }
1509 bool operator()(FMSUB_D inst
) { return FMA(inst
, true, 1.0f
, -1.0f
); }
1510 bool operator()(FNMSUB_D inst
) { return FMA(inst
, true, -1.0f
, 1.0f
); }
1511 bool operator()(FNMADD_D inst
) { return FMA(inst
, true, -1.0f
, -1.0f
); }
1512 bool operator()(FADD_D inst
) { return F_Op(inst
, true, &APFloat::add
); }
1513 bool operator()(FSUB_D inst
) { return F_Op(inst
, true, &APFloat::subtract
); }
1514 bool operator()(FMUL_D inst
) { return F_Op(inst
, true, &APFloat::multiply
); }
1515 bool operator()(FDIV_D inst
) { return F_Op(inst
, true, &APFloat::divide
); }
1516 bool operator()(FSQRT_D inst
) {
1517 // TODO: APFloat doesn't have a sqrt function.
1520 bool operator()(FSGNJ_D inst
) { return F_SignInj(inst
, true, false); }
1521 bool operator()(FSGNJN_D inst
) { return F_SignInj(inst
, true, true); }
1522 bool operator()(FSGNJX_D inst
) { return F_SignInjXor(inst
, true); }
1523 bool operator()(FMIN_D inst
) { return F_MAX_MIN(inst
, true, minnum
); }
1524 bool operator()(FMAX_D inst
) { return F_MAX_MIN(inst
, true, maxnum
); }
1525 bool operator()(FCVT_S_D inst
) {
1526 return transformOptional(inst
.rs1
.ReadAPFloat(m_emu
, true),
1528 double d
= rs1
.convertToDouble();
1529 APFloat
apf((float(d
)));
1530 return inst
.rd
.WriteAPFloat(m_emu
, apf
);
1534 bool operator()(FCVT_D_S inst
) {
1535 return transformOptional(inst
.rs1
.ReadAPFloat(m_emu
, false),
1537 float f
= rs1
.convertToFloat();
1538 APFloat
apf((double(f
)));
1539 return inst
.rd
.WriteAPFloat(m_emu
, apf
);
1543 bool operator()(FEQ_D inst
) { return F_Compare(inst
, true, FEQ
); }
1544 bool operator()(FLT_D inst
) { return F_Compare(inst
, true, FLT
); }
1545 bool operator()(FLE_D inst
) { return F_Compare(inst
, true, FLE
); }
1546 bool operator()(FCLASS_D inst
) { return FCLASS(inst
, true); }
1547 bool operator()(FCVT_W_D inst
) {
1548 return FCVT_i2f
<FCVT_W_D
, int32_t, double>(inst
, true,
1549 &APFloat::convertToDouble
);
1551 bool operator()(FCVT_WU_D inst
) {
1552 return FCVT_i2f
<FCVT_WU_D
, uint32_t, double>(inst
, true,
1553 &APFloat::convertToDouble
);
1555 bool operator()(FCVT_D_W inst
) {
1556 return FCVT_f2i(inst
, &Rs::ReadI32
, APFloat::IEEEdouble());
1558 bool operator()(FCVT_D_WU inst
) {
1559 return FCVT_f2i(inst
, &Rs::ReadU32
, APFloat::IEEEdouble());
1561 bool operator()(FCVT_L_D inst
) {
1562 return FCVT_i2f
<FCVT_L_D
, int64_t, double>(inst
, true,
1563 &APFloat::convertToDouble
);
1565 bool operator()(FCVT_LU_D inst
) {
1566 return FCVT_i2f
<FCVT_LU_D
, uint64_t, double>(inst
, true,
1567 &APFloat::convertToDouble
);
1569 bool operator()(FMV_X_D inst
) { return FMV_f2i(inst
, true); }
1570 bool operator()(FCVT_D_L inst
) {
1571 return FCVT_f2i(inst
, &Rs::ReadI64
, APFloat::IEEEdouble());
1573 bool operator()(FCVT_D_LU inst
) {
1574 return FCVT_f2i(inst
, &Rs::Read
, APFloat::IEEEdouble());
1576 bool operator()(FMV_D_X inst
) {
1577 return FMV_i2f(inst
, 64, &APInt::bitsToDouble
);
1579 bool operator()(INVALID inst
) { return false; }
1580 bool operator()(RESERVED inst
) { return false; }
1581 bool operator()(EBREAK inst
) { return false; }
1582 bool operator()(HINT inst
) { return true; }
1583 bool operator()(NOP inst
) { return true; }
1586 bool EmulateInstructionRISCV::Execute(DecodeResult inst
, bool ignore_cond
) {
1587 return std::visit(Executor(*this, ignore_cond
, inst
.is_rvc
), inst
.decoded
);
1590 bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options
) {
1591 bool increase_pc
= options
& eEmulateInstructionOptionAutoAdvancePC
;
1592 bool ignore_cond
= options
& eEmulateInstructionOptionIgnoreConditions
;
1595 return Execute(m_decoded
, ignore_cond
);
1597 auto old_pc
= ReadPC();
1601 bool success
= Execute(m_decoded
, ignore_cond
);
1605 auto new_pc
= ReadPC();
1609 // If the pc is not updated during execution, we do it here.
1610 return new_pc
!= old_pc
||
1611 WritePC(*old_pc
+ Executor::size(m_decoded
.is_rvc
));
1614 std::optional
<DecodeResult
>
1615 EmulateInstructionRISCV::ReadInstructionAt(addr_t addr
) {
1616 return transformOptional(ReadMem
<uint32_t>(addr
),
1617 [&](uint32_t inst
) { return Decode(inst
); })
1618 .value_or(std::nullopt
);
1621 bool EmulateInstructionRISCV::ReadInstruction() {
1622 auto addr
= ReadPC();
1623 m_addr
= addr
.value_or(LLDB_INVALID_ADDRESS
);
1626 auto inst
= ReadInstructionAt(*addr
);
1631 m_opcode
.SetOpcode16(inst
->inst
, GetByteOrder());
1633 m_opcode
.SetOpcode32(inst
->inst
, GetByteOrder());
1637 std::optional
<addr_t
> EmulateInstructionRISCV::ReadPC() {
1638 bool success
= false;
1639 auto addr
= ReadRegisterUnsigned(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_PC
,
1640 LLDB_INVALID_ADDRESS
, &success
);
1641 return success
? std::optional
<addr_t
>(addr
) : std::nullopt
;
1644 bool EmulateInstructionRISCV::WritePC(addr_t pc
) {
1645 EmulateInstruction::Context ctx
;
1646 ctx
.type
= eContextAdvancePC
;
1648 return WriteRegisterUnsigned(ctx
, eRegisterKindGeneric
,
1649 LLDB_REGNUM_GENERIC_PC
, pc
);
1652 RoundingMode
EmulateInstructionRISCV::GetRoundingMode() {
1653 bool success
= false;
1654 auto fcsr
= ReadRegisterUnsigned(eRegisterKindLLDB
, fpr_fcsr_riscv
,
1655 LLDB_INVALID_ADDRESS
, &success
);
1657 return RoundingMode::Invalid
;
1658 auto frm
= (fcsr
>> 5) & 0x7;
1661 return RoundingMode::NearestTiesToEven
;
1663 return RoundingMode::TowardZero
;
1665 return RoundingMode::TowardNegative
;
1667 return RoundingMode::TowardPositive
;
1669 return RoundingMode::Dynamic
;
1671 // Reserved for future use.
1672 return RoundingMode::Invalid
;
1676 bool EmulateInstructionRISCV::SetAccruedExceptions(
1677 APFloatBase::opStatus opStatus
) {
1678 bool success
= false;
1679 auto fcsr
= ReadRegisterUnsigned(eRegisterKindLLDB
, fpr_fcsr_riscv
,
1680 LLDB_INVALID_ADDRESS
, &success
);
1684 case APFloatBase::opInvalidOp
:
1687 case APFloatBase::opDivByZero
:
1690 case APFloatBase::opOverflow
:
1693 case APFloatBase::opUnderflow
:
1696 case APFloatBase::opInexact
:
1699 case APFloatBase::opOK
:
1702 EmulateInstruction::Context ctx
;
1703 ctx
.type
= eContextRegisterStore
;
1705 return WriteRegisterUnsigned(ctx
, eRegisterKindLLDB
, fpr_fcsr_riscv
, fcsr
);
1708 std::optional
<RegisterInfo
>
1709 EmulateInstructionRISCV::GetRegisterInfo(RegisterKind reg_kind
,
1710 uint32_t reg_index
) {
1711 if (reg_kind
== eRegisterKindGeneric
) {
1712 switch (reg_index
) {
1713 case LLDB_REGNUM_GENERIC_PC
:
1714 reg_kind
= eRegisterKindLLDB
;
1715 reg_index
= gpr_pc_riscv
;
1717 case LLDB_REGNUM_GENERIC_SP
:
1718 reg_kind
= eRegisterKindLLDB
;
1719 reg_index
= gpr_sp_riscv
;
1721 case LLDB_REGNUM_GENERIC_FP
:
1722 reg_kind
= eRegisterKindLLDB
;
1723 reg_index
= gpr_fp_riscv
;
1725 case LLDB_REGNUM_GENERIC_RA
:
1726 reg_kind
= eRegisterKindLLDB
;
1727 reg_index
= gpr_ra_riscv
;
1729 // We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are
1732 llvm_unreachable("unsupported register");
1736 const RegisterInfo
*array
=
1737 RegisterInfoPOSIX_riscv64::GetRegisterInfoPtr(m_arch
);
1738 const uint32_t length
=
1739 RegisterInfoPOSIX_riscv64::GetRegisterInfoCount(m_arch
);
1741 if (reg_index
>= length
|| reg_kind
!= eRegisterKindLLDB
)
1744 return array
[reg_index
];
1747 bool EmulateInstructionRISCV::SetTargetTriple(const ArchSpec
&arch
) {
1748 return SupportsThisArch(arch
);
1751 bool EmulateInstructionRISCV::TestEmulation(Stream
&out_stream
, ArchSpec
&arch
,
1752 OptionValueDictionary
*test_data
) {
1756 void EmulateInstructionRISCV::Initialize() {
1757 PluginManager::RegisterPlugin(GetPluginNameStatic(),
1758 GetPluginDescriptionStatic(), CreateInstance
);
1761 void EmulateInstructionRISCV::Terminate() {
1762 PluginManager::UnregisterPlugin(CreateInstance
);
1765 lldb_private::EmulateInstruction
*
1766 EmulateInstructionRISCV::CreateInstance(const ArchSpec
&arch
,
1767 InstructionType inst_type
) {
1768 if (EmulateInstructionRISCV::SupportsThisInstructionType(inst_type
) &&
1769 SupportsThisArch(arch
)) {
1770 return new EmulateInstructionRISCV(arch
);
1776 bool EmulateInstructionRISCV::SupportsThisArch(const ArchSpec
&arch
) {
1777 return arch
.GetTriple().isRISCV();
1780 } // namespace lldb_private