| 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 | |
| 18 | namespace lldb_private { |
| 19 | |
| 20 | class EmulateInstructionRISCV; |
| 21 | |
| 22 | struct Rd { |
| 23 | uint32_t rd; |
| 24 | bool Write(EmulateInstructionRISCV &emulator, uint64_t value); |
| 25 | bool WriteAPFloat(EmulateInstructionRISCV &emulator, llvm::APFloat value); |
| 26 | }; |
| 27 | |
| 28 | struct 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) |
| 102 | struct B { |
| 103 | Rs rs1; |
| 104 | Rs rs2; |
| 105 | uint32_t imm; |
| 106 | uint32_t funct3; |
| 107 | DERIVE_EQ(B); |
| 108 | }; |
| 109 | U_TYPE_INST(LUI); |
| 110 | U_TYPE_INST(AUIPC); |
| 111 | J_TYPE_INST(JAL); |
| 112 | I_TYPE_INST(JALR); |
| 113 | I_TYPE_INST(LB); |
| 114 | I_TYPE_INST(LH); |
| 115 | I_TYPE_INST(LW); |
| 116 | I_TYPE_INST(LBU); |
| 117 | I_TYPE_INST(LHU); |
| 118 | S_TYPE_INST(SB); |
| 119 | S_TYPE_INST(SH); |
| 120 | S_TYPE_INST(SW); |
| 121 | I_TYPE_INST(ADDI); |
| 122 | I_TYPE_INST(SLTI); |
| 123 | I_TYPE_INST(SLTIU); |
| 124 | I_TYPE_INST(XORI); |
| 125 | I_TYPE_INST(ORI); |
| 126 | I_TYPE_INST(ANDI); |
| 127 | R_TYPE_INST(ADD); |
| 128 | R_TYPE_INST(SUB); |
| 129 | R_TYPE_INST(SLL); |
| 130 | R_TYPE_INST(SLT); |
| 131 | R_TYPE_INST(SLTU); |
| 132 | R_TYPE_INST(XOR); |
| 133 | R_TYPE_INST(SRL); |
| 134 | R_TYPE_INST(SRA); |
| 135 | R_TYPE_INST(OR); |
| 136 | R_TYPE_INST(AND); |
| 137 | |
| 138 | // RV64I inst (The base integer ISA) |
| 139 | I_TYPE_INST(LWU); |
| 140 | I_TYPE_INST(LD); |
| 141 | S_TYPE_INST(SD); |
| 142 | R_SHAMT_TYPE_INST(SLLI); |
| 143 | R_SHAMT_TYPE_INST(SRLI); |
| 144 | R_SHAMT_TYPE_INST(SRAI); |
| 145 | I_TYPE_INST(ADDIW); |
| 146 | R_SHAMT_TYPE_INST(SLLIW); |
| 147 | R_SHAMT_TYPE_INST(SRLIW); |
| 148 | R_SHAMT_TYPE_INST(SRAIW); |
| 149 | R_TYPE_INST(ADDW); |
| 150 | R_TYPE_INST(SUBW); |
| 151 | R_TYPE_INST(SLLW); |
| 152 | R_TYPE_INST(SRLW); |
| 153 | R_TYPE_INST(SRAW); |
| 154 | |
| 155 | // RV32M inst (The standard integer multiplication and division extension) |
| 156 | R_TYPE_INST(MUL); |
| 157 | R_TYPE_INST(MULH); |
| 158 | R_TYPE_INST(MULHSU); |
| 159 | R_TYPE_INST(MULHU); |
| 160 | R_TYPE_INST(DIV); |
| 161 | R_TYPE_INST(DIVU); |
| 162 | R_TYPE_INST(REM); |
| 163 | R_TYPE_INST(REMU); |
| 164 | |
| 165 | // RV64M inst (The standard integer multiplication and division extension) |
| 166 | R_TYPE_INST(MULW); |
| 167 | R_TYPE_INST(DIVW); |
| 168 | R_TYPE_INST(DIVUW); |
| 169 | R_TYPE_INST(REMW); |
| 170 | R_TYPE_INST(REMUW); |
| 171 | |
| 172 | // RV32A inst (The standard atomic instruction extension) |
| 173 | R_RS1_TYPE_INST(LR_W); |
| 174 | R_TYPE_INST(SC_W); |
| 175 | R_TYPE_INST(AMOSWAP_W); |
| 176 | R_TYPE_INST(AMOADD_W); |
| 177 | R_TYPE_INST(AMOXOR_W); |
| 178 | R_TYPE_INST(AMOAND_W); |
| 179 | R_TYPE_INST(AMOOR_W); |
| 180 | R_TYPE_INST(AMOMIN_W); |
| 181 | R_TYPE_INST(AMOMAX_W); |
| 182 | R_TYPE_INST(AMOMINU_W); |
| 183 | R_TYPE_INST(AMOMAXU_W); |
| 184 | |
| 185 | // RV64A inst (The standard atomic instruction extension) |
| 186 | R_RS1_TYPE_INST(LR_D); |
| 187 | R_TYPE_INST(SC_D); |
| 188 | R_TYPE_INST(AMOSWAP_D); |
| 189 | R_TYPE_INST(AMOADD_D); |
| 190 | R_TYPE_INST(AMOXOR_D); |
| 191 | R_TYPE_INST(AMOAND_D); |
| 192 | R_TYPE_INST(AMOOR_D); |
| 193 | R_TYPE_INST(AMOMIN_D); |
| 194 | R_TYPE_INST(AMOMAX_D); |
| 195 | R_TYPE_INST(AMOMINU_D); |
| 196 | R_TYPE_INST(AMOMAXU_D); |
| 197 | |
| 198 | // RV32F inst (The standard single-precision floating-point extension) |
| 199 | I_TYPE_INST(FLW); |
| 200 | S_TYPE_INST(FSW); |
| 201 | R4_TYPE_INST(FMADD_S); |
| 202 | R4_TYPE_INST(FMSUB_S); |
| 203 | R4_TYPE_INST(FNMADD_S); |
| 204 | R4_TYPE_INST(FNMSUB_S); |
| 205 | R_TYPE_INST(FADD_S); |
| 206 | R_TYPE_INST(FSUB_S); |
| 207 | R_TYPE_INST(FMUL_S); |
| 208 | R_TYPE_INST(FDIV_S); |
| 209 | I_TYPE_INST(FSQRT_S); |
| 210 | R_TYPE_INST(FSGNJ_S); |
| 211 | R_TYPE_INST(FSGNJN_S); |
| 212 | R_TYPE_INST(FSGNJX_S); |
| 213 | R_TYPE_INST(FMIN_S); |
| 214 | R_TYPE_INST(FMAX_S); |
| 215 | I_TYPE_INST(FCVT_W_S); |
| 216 | I_TYPE_INST(FCVT_WU_S); |
| 217 | I_TYPE_INST(FMV_X_W); |
| 218 | R_TYPE_INST(FEQ_S); |
| 219 | R_TYPE_INST(FLT_S); |
| 220 | R_TYPE_INST(FLE_S); |
| 221 | I_TYPE_INST(FCLASS_S); |
| 222 | I_TYPE_INST(FCVT_S_W); |
| 223 | I_TYPE_INST(FCVT_S_WU); |
| 224 | I_TYPE_INST(FMV_W_X); |
| 225 | |
| 226 | // RV64F inst (The standard single-precision floating-point extension) |
| 227 | I_TYPE_INST(FCVT_L_S); |
| 228 | I_TYPE_INST(FCVT_LU_S); |
| 229 | I_TYPE_INST(FCVT_S_L); |
| 230 | I_TYPE_INST(FCVT_S_LU); |
| 231 | |
| 232 | // RV32D inst (Extension for Double-Precision Floating-Point) |
| 233 | I_TYPE_INST(FLD); |
| 234 | S_TYPE_INST(FSD); |
| 235 | R4_TYPE_INST(FMADD_D); |
| 236 | R4_TYPE_INST(FMSUB_D); |
| 237 | R4_TYPE_INST(FNMSUB_D); |
| 238 | R4_TYPE_INST(FNMADD_D); |
| 239 | R_TYPE_INST(FADD_D); |
| 240 | R_TYPE_INST(FSUB_D); |
| 241 | R_TYPE_INST(FMUL_D); |
| 242 | R_TYPE_INST(FDIV_D); |
| 243 | I_TYPE_INST(FSQRT_D); |
| 244 | R_TYPE_INST(FSGNJ_D); |
| 245 | R_TYPE_INST(FSGNJN_D); |
| 246 | R_TYPE_INST(FSGNJX_D); |
| 247 | R_TYPE_INST(FMIN_D); |
| 248 | R_TYPE_INST(FMAX_D); |
| 249 | I_TYPE_INST(FCVT_S_D); |
| 250 | I_TYPE_INST(FCVT_D_S); |
| 251 | R_TYPE_INST(FEQ_D); |
| 252 | R_TYPE_INST(FLT_D); |
| 253 | R_TYPE_INST(FLE_D); |
| 254 | I_TYPE_INST(FCLASS_D); |
| 255 | I_TYPE_INST(FCVT_W_D); |
| 256 | I_TYPE_INST(FCVT_WU_D); |
| 257 | I_TYPE_INST(FCVT_D_W); |
| 258 | I_TYPE_INST(FCVT_D_WU); |
| 259 | |
| 260 | // RV64D inst (Extension for Double-Precision Floating-Point) |
| 261 | I_TYPE_INST(FCVT_L_D); |
| 262 | I_TYPE_INST(FCVT_LU_D); |
| 263 | I_TYPE_INST(FMV_X_D); |
| 264 | I_TYPE_INST(FCVT_D_L); |
| 265 | I_TYPE_INST(FCVT_D_LU); |
| 266 | I_TYPE_INST(FMV_D_X); |
| 267 | |
| 268 | /// Invalid and reserved instructions, the `inst` fields are used for debugging. |
| 269 | INVALID_INST(INVALID); |
| 270 | INVALID_INST(RESERVED); |
| 271 | INVALID_INST(EBREAK); |
| 272 | INVALID_INST(HINT); |
| 273 | INVALID_INST(NOP); |
| 274 | |
| 275 | using 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 | |
| 293 | constexpr uint8_t RV32 = 1; |
| 294 | constexpr uint8_t RV64 = 2; |
| 295 | constexpr uint8_t RV128 = 4; |
| 296 | |
| 297 | struct InstrPattern { |
| 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 | |
| 308 | struct DecodeResult { |
| 309 | RISCVInst decoded; |
| 310 | uint32_t inst; |
| 311 | bool is_rvc; |
| 312 | InstrPattern pattern; |
| 313 | }; |
| 314 | |
| 315 | constexpr uint32_t DecodeRD(uint32_t inst) { return (inst & 0xF80) >> 7; } |
| 316 | constexpr uint32_t DecodeRS1(uint32_t inst) { return (inst & 0xF8000) >> 15; } |
| 317 | constexpr uint32_t DecodeRS2(uint32_t inst) { return (inst & 0x1F00000) >> 20; } |
| 318 | constexpr uint32_t DecodeRS3(uint32_t inst) { |
| 319 | return (inst & 0xF0000000) >> 27; |
| 320 | } |
| 321 | constexpr uint32_t DecodeFunct3(uint32_t inst) { return (inst & 0x7000) >> 12; } |
| 322 | constexpr uint32_t DecodeFunct2(uint32_t inst) { |
| 323 | return (inst & 0xE000000) >> 25; |
| 324 | } |
| 325 | constexpr uint32_t DecodeFunct7(uint32_t inst) { |
| 326 | return (inst & 0xFE000000) >> 25; |
| 327 | } |
| 328 | |
| 329 | constexpr 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. |
| 332 | constexpr uint64_t NanBoxing(uint64_t val) { |
| 333 | return val | 0xFFFF'FFFF'0000'0000; |
| 334 | } |
| 335 | constexpr 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 |
| 353 | |