LLDB mainline
RISCVInstructions.h
Go to the documentation of this file.
1//===-- RISCVInstructions.h -----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVINSTRUCTION_H
10#define LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVINSTRUCTION_H
11
12#include <cstdint>
13#include <optional>
14#include <variant>
15
16#include "llvm/ADT/APFloat.h"
17
18namespace lldb_private {
19
20class EmulateInstructionRISCV;
21
22struct Rd {
23 uint32_t rd;
24 bool Write(EmulateInstructionRISCV &emulator, uint64_t value);
25 bool WriteAPFloat(EmulateInstructionRISCV &emulator, llvm::APFloat value);
26};
27
28struct Rs {
29 uint32_t rs;
30 std::optional<uint64_t> Read(EmulateInstructionRISCV &emulator);
31 std::optional<int32_t> ReadI32(EmulateInstructionRISCV &emulator);
32 std::optional<int64_t> ReadI64(EmulateInstructionRISCV &emulator);
33 std::optional<uint32_t> ReadU32(EmulateInstructionRISCV &emulator);
34 std::optional<llvm::APFloat> ReadAPFloat(EmulateInstructionRISCV &emulator,
35 bool isDouble);
36};
37
38#define DERIVE_EQ(NAME) \
39 bool operator==(const NAME &r) const { \
40 return std::memcmp(this, &r, sizeof(NAME)) == 0; \
41 }
42
43#define I_TYPE_INST(NAME) \
44 struct NAME { \
45 Rd rd; \
46 Rs rs1; \
47 uint32_t imm; \
48 DERIVE_EQ(NAME); \
49 }
50#define S_TYPE_INST(NAME) \
51 struct NAME { \
52 Rs rs1; \
53 Rs rs2; \
54 uint32_t imm; \
55 DERIVE_EQ(NAME); \
56 }
57#define U_TYPE_INST(NAME) \
58 struct NAME { \
59 Rd rd; \
60 uint32_t imm; \
61 DERIVE_EQ(NAME); \
62 }
63/// The memory layout are the same in our code.
64#define J_TYPE_INST(NAME) U_TYPE_INST(NAME)
65#define R_TYPE_INST(NAME) \
66 struct NAME { \
67 Rd rd; \
68 Rs rs1; \
69 Rs rs2; \
70 DERIVE_EQ(NAME); \
71 }
72#define R_SHAMT_TYPE_INST(NAME) \
73 struct NAME { \
74 Rd rd; \
75 Rs rs1; \
76 uint32_t shamt; \
77 DERIVE_EQ(NAME); \
78 }
79#define R_RS1_TYPE_INST(NAME) \
80 struct NAME { \
81 Rd rd; \
82 Rs rs1; \
83 DERIVE_EQ(NAME); \
84 }
85#define R4_TYPE_INST(NAME) \
86 struct NAME { \
87 Rd rd; \
88 Rs rs1; \
89 Rs rs2; \
90 Rs rs3; \
91 int32_t rm; \
92 DERIVE_EQ(NAME); \
93 }
94/// The `inst` fields are used for debugging.
95#define INVALID_INST(NAME) \
96 struct NAME { \
97 uint32_t inst; \
98 DERIVE_EQ(NAME); \
99 }
100
101// RV32I instructions (The base integer ISA)
102struct B {
105 uint32_t imm;
106 uint32_t funct3;
108};
137
138// RV64I inst (The base integer ISA)
154
155// RV32M inst (The standard integer multiplication and division extension)
164
165// RV64M inst (The standard integer multiplication and division extension)
171
172// RV32A inst (The standard atomic instruction extension)
175R_TYPE_INST(AMOSWAP_W);
176R_TYPE_INST(AMOADD_W);
177R_TYPE_INST(AMOXOR_W);
178R_TYPE_INST(AMOAND_W);
179R_TYPE_INST(AMOOR_W);
180R_TYPE_INST(AMOMIN_W);
181R_TYPE_INST(AMOMAX_W);
182R_TYPE_INST(AMOMINU_W);
183R_TYPE_INST(AMOMAXU_W);
184
185// RV64A inst (The standard atomic instruction extension)
188R_TYPE_INST(AMOSWAP_D);
189R_TYPE_INST(AMOADD_D);
190R_TYPE_INST(AMOXOR_D);
191R_TYPE_INST(AMOAND_D);
192R_TYPE_INST(AMOOR_D);
193R_TYPE_INST(AMOMIN_D);
194R_TYPE_INST(AMOMAX_D);
195R_TYPE_INST(AMOMINU_D);
196R_TYPE_INST(AMOMAXU_D);
197
198// RV32F inst (The standard single-precision floating-point extension)
203R4_TYPE_INST(FNMADD_S);
204R4_TYPE_INST(FNMSUB_S);
209I_TYPE_INST(FSQRT_S);
210R_TYPE_INST(FSGNJ_S);
211R_TYPE_INST(FSGNJN_S);
212R_TYPE_INST(FSGNJX_S);
215I_TYPE_INST(FCVT_W_S);
216I_TYPE_INST(FCVT_WU_S);
217I_TYPE_INST(FMV_X_W);
221I_TYPE_INST(FCLASS_S);
222I_TYPE_INST(FCVT_S_W);
223I_TYPE_INST(FCVT_S_WU);
224I_TYPE_INST(FMV_W_X);
225
226// RV64F inst (The standard single-precision floating-point extension)
227I_TYPE_INST(FCVT_L_S);
228I_TYPE_INST(FCVT_LU_S);
229I_TYPE_INST(FCVT_S_L);
230I_TYPE_INST(FCVT_S_LU);
231
232// RV32D inst (Extension for Double-Precision Floating-Point)
237R4_TYPE_INST(FNMSUB_D);
238R4_TYPE_INST(FNMADD_D);
243I_TYPE_INST(FSQRT_D);
244R_TYPE_INST(FSGNJ_D);
245R_TYPE_INST(FSGNJN_D);
246R_TYPE_INST(FSGNJX_D);
249I_TYPE_INST(FCVT_S_D);
250I_TYPE_INST(FCVT_D_S);
254I_TYPE_INST(FCLASS_D);
255I_TYPE_INST(FCVT_W_D);
256I_TYPE_INST(FCVT_WU_D);
257I_TYPE_INST(FCVT_D_W);
258I_TYPE_INST(FCVT_D_WU);
259
260// RV64D inst (Extension for Double-Precision Floating-Point)
261I_TYPE_INST(FCVT_L_D);
262I_TYPE_INST(FCVT_LU_D);
263I_TYPE_INST(FMV_X_D);
264I_TYPE_INST(FCVT_D_L);
265I_TYPE_INST(FCVT_D_LU);
266I_TYPE_INST(FMV_D_X);
267
268/// Invalid and reserved instructions, the `inst` fields are used for debugging.
270INVALID_INST(RESERVED);
274
275using RISCVInst = std::variant<
276 LUI, AUIPC, JAL, JALR, B, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI,
277 SLTIU, XORI, ORI, ANDI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND,
278 LWU, LD, SD, SLLI, SRLI, SRAI, ADDIW, SLLIW, SRLIW, SRAIW, ADDW, SUBW, SLLW,
279 SRLW, SRAW, MUL, MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU, MULW, DIVW,
280 DIVUW, REMW, REMUW, LR_W, SC_W, AMOSWAP_W, AMOADD_W, AMOXOR_W, AMOAND_W,
281 AMOOR_W, AMOMIN_W, AMOMAX_W, AMOMINU_W, AMOMAXU_W, LR_D, SC_D, AMOSWAP_D,
282 AMOADD_D, AMOXOR_D, AMOAND_D, AMOOR_D, AMOMIN_D, AMOMAX_D, AMOMINU_D,
283 AMOMAXU_D, FLW, FSW, FMADD_S, FMSUB_S, FNMADD_S, FNMSUB_S, FADD_S, FSUB_S,
284 FMUL_S, FDIV_S, FSQRT_S, FSGNJ_S, FSGNJN_S, FSGNJX_S, FMIN_S, FMAX_S,
285 FCVT_W_S, FCVT_WU_S, FMV_X_W, FEQ_S, FLT_S, FLE_S, FCLASS_S, FCVT_S_W,
286 FCVT_S_WU, FMV_W_X, FCVT_L_S, FCVT_LU_S, FCVT_S_L, FCVT_S_LU, FLD, FSD,
287 FMADD_D, FMSUB_D, FNMSUB_D, FNMADD_D, FADD_D, FSUB_D, FMUL_D, FDIV_D,
288 FSQRT_D, FSGNJ_D, FSGNJN_D, FSGNJX_D, FMIN_D, FMAX_D, FCVT_S_D, FCVT_D_S,
289 FEQ_D, FLT_D, FLE_D, FCLASS_D, FCVT_W_D, FCVT_WU_D, FCVT_D_W, FCVT_D_WU,
290 FCVT_L_D, FCVT_LU_D, FMV_X_D, FCVT_D_L, FCVT_D_LU, FMV_D_X, INVALID, EBREAK,
291 RESERVED, HINT, NOP>;
292
293constexpr uint8_t RV32 = 1;
294constexpr uint8_t RV64 = 2;
295constexpr uint8_t RV128 = 4;
296
298 const char *name;
299 /// Bit mask to check the type of a instruction (B-Type, I-Type, J-Type, etc.)
300 uint32_t type_mask;
301 /// Characteristic value after bitwise-and with type_mask.
302 uint32_t eigen;
303 RISCVInst (*decode)(uint32_t inst);
304 /// If not specified, the inst will be supported by all RV versions.
305 uint8_t inst_type = RV32 | RV64 | RV128;
306};
307
310 uint32_t inst;
311 bool is_rvc;
313};
314
315constexpr uint32_t DecodeRD(uint32_t inst) { return (inst & 0xF80) >> 7; }
316constexpr uint32_t DecodeRS1(uint32_t inst) { return (inst & 0xF8000) >> 15; }
317constexpr uint32_t DecodeRS2(uint32_t inst) { return (inst & 0x1F00000) >> 20; }
318constexpr uint32_t DecodeRS3(uint32_t inst) {
319 return (inst & 0xF0000000) >> 27;
320}
321constexpr uint32_t DecodeFunct3(uint32_t inst) { return (inst & 0x7000) >> 12; }
322constexpr uint32_t DecodeFunct2(uint32_t inst) {
323 return (inst & 0xE000000) >> 25;
324}
325constexpr uint32_t DecodeFunct7(uint32_t inst) {
326 return (inst & 0xFE000000) >> 25;
327}
328
329constexpr int32_t DecodeRM(uint32_t inst) { return DecodeFunct3(inst); }
330
331/// RISC-V spec: The upper bits of a valid NaN-boxed value must be all 1s.
332constexpr uint64_t NanBoxing(uint64_t val) {
333 return val | 0xFFFF'FFFF'0000'0000;
334}
335constexpr uint32_t NanUnBoxing(uint64_t val) {
336 return val & (~0xFFFF'FFFF'0000'0000);
337}
338
339#undef R_TYPE_INST
340#undef R_SHAMT_TYPE_INST
341#undef R_RS1_TYPE_INST
342#undef R4_TYPE_INST
343#undef I_TYPE_INST
344#undef S_TYPE_INST
345#undef B_TYPE_INST
346#undef U_TYPE_INST
347#undef J_TYPE_INST
348#undef INVALID_INST
349#undef DERIVE_EQ
350
351} // namespace lldb_private
352#endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVINSTRUCTION_H
#define R4_TYPE_INST(NAME)
#define J_TYPE_INST(NAME)
The memory layout are the same in our code.
#define I_TYPE_INST(NAME)
#define S_TYPE_INST(NAME)
#define R_SHAMT_TYPE_INST(NAME)
#define R_RS1_TYPE_INST(NAME)
#define R_TYPE_INST(NAME)
#define INVALID_INST(NAME)
The inst fields are used for debugging.
#define U_TYPE_INST(NAME)
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
constexpr uint32_t DecodeFunct7(uint32_t inst)
constexpr uint32_t DecodeRS2(uint32_t inst)
constexpr uint8_t RV32
constexpr uint32_t DecodeRS3(uint32_t inst)
constexpr int32_t DecodeRM(uint32_t inst)
std::variant< LUI, AUIPC, JAL, JALR, B, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI, SLTIU, XORI, ORI, ANDI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, LWU, LD, SD, SLLI, SRLI, SRAI, ADDIW, SLLIW, SRLIW, SRAIW, ADDW, SUBW, SLLW, SRLW, SRAW, MUL, MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU, MULW, DIVW, DIVUW, REMW, REMUW, LR_W, SC_W, AMOSWAP_W, AMOADD_W, AMOXOR_W, AMOAND_W, AMOOR_W, AMOMIN_W, AMOMAX_W, AMOMINU_W, AMOMAXU_W, LR_D, SC_D, AMOSWAP_D, AMOADD_D, AMOXOR_D, AMOAND_D, AMOOR_D, AMOMIN_D, AMOMAX_D, AMOMINU_D, AMOMAXU_D, FLW, FSW, FMADD_S, FMSUB_S, FNMADD_S, FNMSUB_S, FADD_S, FSUB_S, FMUL_S, FDIV_S, FSQRT_S, FSGNJ_S, FSGNJN_S, FSGNJX_S, FMIN_S, FMAX_S, FCVT_W_S, FCVT_WU_S, FMV_X_W, FEQ_S, FLT_S, FLE_S, FCLASS_S, FCVT_S_W, FCVT_S_WU, FMV_W_X, FCVT_L_S, FCVT_LU_S, FCVT_S_L, FCVT_S_LU, FLD, FSD, FMADD_D, FMSUB_D, FNMSUB_D, FNMADD_D, FADD_D, FSUB_D, FMUL_D, FDIV_D, FSQRT_D, FSGNJ_D, FSGNJN_D, FSGNJX_D, FMIN_D, FMAX_D, FCVT_S_D, FCVT_D_S, FEQ_D, FLT_D, FLE_D, FCLASS_D, FCVT_W_D, FCVT_WU_D, FCVT_D_W, FCVT_D_WU, FCVT_L_D, FCVT_LU_D, FMV_X_D, FCVT_D_L, FCVT_D_LU, FMV_D_X, INVALID, EBREAK, RESERVED, HINT, NOP > RISCVInst
constexpr uint8_t RV64
constexpr uint32_t NanUnBoxing(uint64_t val)
constexpr uint32_t DecodeRS1(uint32_t inst)
constexpr uint8_t RV128
constexpr uint32_t DecodeRD(uint32_t inst)
constexpr uint32_t DecodeFunct3(uint32_t inst)
constexpr uint64_t NanBoxing(uint64_t val)
RISC-V spec: The upper bits of a valid NaN-boxed value must be all 1s.
constexpr uint32_t DecodeFunct2(uint32_t inst)
uint32_t eigen
Characteristic value after bitwise-and with type_mask.
uint8_t inst_type
If not specified, the inst will be supported by all RV versions.
uint32_t type_mask
Bit mask to check the type of a instruction (B-Type, I-Type, J-Type, etc.)
RISCVInst(* decode)(uint32_t inst)
bool Write(EmulateInstructionRISCV &emulator, uint64_t value)
bool WriteAPFloat(EmulateInstructionRISCV &emulator, llvm::APFloat value)
std::optional< llvm::APFloat > ReadAPFloat(EmulateInstructionRISCV &emulator, bool isDouble)
std::optional< uint64_t > Read(EmulateInstructionRISCV &emulator)
std::optional< int64_t > ReadI64(EmulateInstructionRISCV &emulator)
std::optional< uint32_t > ReadU32(EmulateInstructionRISCV &emulator)
std::optional< int32_t > ReadI32(EmulateInstructionRISCV &emulator)