diff --git a/lldb/source/Host/common/NativeProcessProtocol.cpp b/lldb/source/Host/common/NativeProcessProtocol.cpp --- a/lldb/source/Host/common/NativeProcessProtocol.cpp +++ b/lldb/source/Host/common/NativeProcessProtocol.cpp @@ -503,9 +503,10 @@ static const uint8_t g_mips64_opcode[] = {0x00, 0x00, 0x00, 0x0d}; static const uint8_t g_mips64el_opcode[] = {0x0d, 0x00, 0x00, 0x00}; static const uint8_t g_s390x_opcode[] = {0x00, 0x01}; - static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08}; // trap + static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08}; // trap static const uint8_t g_ppcle_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap static const uint8_t g_riscv_opcode[] = {0x73, 0x00, 0x10, 0x00}; // ebreak + static const uint8_t g_riscv_opcode_c[] = {0x02, 0x90}; // c.ebreak switch (GetArchitecture().GetMachine()) { case llvm::Triple::aarch64: @@ -535,8 +536,10 @@ return llvm::makeArrayRef(g_ppcle_opcode); case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - return llvm::makeArrayRef(g_riscv_opcode); + case llvm::Triple::riscv64: { + return size_hint == 2 ? llvm::makeArrayRef(g_riscv_opcode_c) + : llvm::makeArrayRef(g_riscv_opcode); + } default: return llvm::createStringError(llvm::inconvertibleErrorCode(), diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp --- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp +++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp @@ -6,11 +6,10 @@ // //===----------------------------------------------------------------------===// -#include - #include "EmulateInstructionRISCV.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h" #include "Plugins/Process/Utility/lldb-riscv-register-enums.h" +#include "RISCVCInstructions.h" #include "RISCVInstructions.h" #include "lldb/Core/Address.h" @@ -86,8 +85,8 @@ } constexpr uint32_t DecodeSImm(uint32_t inst) { - return (uint64_t(int64_t(int32_t(inst & 0xFE00000)) >> 20)) // imm[11:5] - | ((inst & 0xF80) >> 7); // imm[4:0] + return (uint64_t(int64_t(int32_t(inst & 0xFE000000)) >> 20)) // imm[11:5] + | ((inst & 0xF80) >> 7); // imm[4:0] } constexpr uint32_t DecodeUImm(uint32_t inst) { @@ -194,14 +193,14 @@ } // Read T from memory, then load its sign-extended value m_emu to register. -template +template static std::enable_if_t, bool> -Load(EmulateInstructionRISCV &emulator, I inst, uint64_t (*extend)(m_emu)) { +Load(EmulateInstructionRISCV &emulator, I inst, uint64_t (*extend)(E)) { auto addr = LoadStoreAddr(emulator, inst); if (!addr) return false; return emulator.ReadMem(*addr) - .transform([&](T t) { return inst.rd.Write(emulator, extend(m_emu(t))); }) + .transform([&](T t) { return inst.rd.Write(emulator, extend(E(t))); }) .value_or(false); } @@ -461,6 +460,38 @@ {"AMOMAX_D", 0xF800707F, 0xA000302F, DecodeRType}, {"AMOMINU_D", 0xF800707F, 0xC000302F, DecodeRType}, {"AMOMAXU_D", 0xF800707F, 0xE000302F, DecodeRType}, + + // RVC (Compressed Instructions) // + {"C_LWSP", 0xE003, 0x4002, DecodeC_LWSP}, + {"C_LDSP", 0xE003, 0x6002, DecodeC_LDSP}, + {"C_SWSP", 0xE003, 0xC002, DecodeC_SWSP}, + {"C_SDSP", 0xE003, 0xE002, DecodeC_SDSP}, + {"C_LW", 0xE003, 0x4000, DecodeC_LW}, + {"C_LD", 0xE003, 0x6000, DecodeC_LD}, + {"C_SW", 0xE003, 0xC000, DecodeC_SW}, + {"C_SD", 0xE003, 0xE000, DecodeC_SD}, + {"C_J", 0xE003, 0xA001, DecodeC_J}, + {"C_JR", 0xF07F, 0x8002, DecodeC_JR}, + {"C_JALR", 0xF07F, 0x9002, DecodeC_JALR}, + {"C_BNEZ", 0xE003, 0xE001, DecodeC_BNEZ}, + {"C_BEQZ", 0xE003, 0xC001, DecodeC_BEQZ}, + {"C_LI", 0xE003, 0x4001, DecodeC_LI}, + {"C_LUI_ADDI16SP", 0xE003, 0x6001, DecodeC_LUI_ADDI16SP}, + {"C_ADDI", 0xE003, 0x1, DecodeC_ADDI}, + {"C_ADDIW", 0xE003, 0x2001, DecodeC_ADDIW}, + {"C_ADDI4SPN", 0xE003, 0x0, DecodeC_ADDI4SPN}, + {"C_SLLI", 0xE003, 0x2, DecodeC_SLLI}, + {"C_SRLI", 0xEC03, 0x8001, DecodeC_SRLI}, + {"C_SRAI", 0xEC03, 0x8401, DecodeC_SRAI}, + {"C_ANDI", 0xEC03, 0x8801, DecodeC_ANDI}, + {"C_MV", 0xF003, 0x8002, DecodeC_MV}, + {"C_ADD", 0xF003, 0x9002, DecodeC_ADD}, + {"C_AND", 0xFC63, 0x8C61, DecodeC_AND}, + {"C_OR", 0xFC63, 0x8C41, DecodeC_OR}, + {"C_XOR", 0xFC63, 0x8C21, DecodeC_XOR}, + {"C_SUB", 0xFC63, 0x8C01, DecodeC_SUB}, + {"C_SUBW", 0xFC63, 0x9C01, DecodeC_SUBW}, + {"C_ADDW", 0xFC63, 0x9C21, DecodeC_ADDW}, }; llvm::Optional EmulateInstructionRISCV::Decode(uint32_t inst) { @@ -473,9 +504,9 @@ for (const InstrPattern &pat : PATTERNS) { if ((inst & pat.type_mask) == pat.eigen) { - LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(%x) was decoded to %s", - __FUNCTION__, inst, pat.name); - auto decoded = pat.decode(inst); + LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(%x at %lx) was decoded to %s", + __FUNCTION__, inst, m_addr, pat.name); + auto decoded = is_rvc ? pat.decode(try_rvc) : pat.decode(inst); return DecodeResult{decoded, inst, is_rvc, pat}; } } @@ -1017,6 +1048,11 @@ m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return std::max(a, b); }); } + bool operator()(INVALID inst) { return false; } + bool operator()(RESERVED inst) { return false; } + bool operator()(EBREAK inst) { return false; } + bool operator()(HINT inst) { return true; } + bool operator()(NOP inst) { return true; } }; bool EmulateInstructionRISCV::Execute(DecodeResult inst, bool ignore_cond) { diff --git a/lldb/source/Plugins/Instruction/RISCV/RISCVCInstructions.h b/lldb/source/Plugins/Instruction/RISCV/RISCVCInstructions.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Instruction/RISCV/RISCVCInstructions.h @@ -0,0 +1,304 @@ +//===-- RISCVCInstructions.h ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVCINSTRUCTION_H +#define LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVCINSTRUCTION_H + +#include +#include + +#include "RISCVInstructions.h" +#include "llvm/ADT/Optional.h" + +namespace lldb_private { + +/// Unified RISC-V C register encoding. +struct RxC { + uint32_t rd; + bool shift = true; + operator int() { return rd; } + operator Rd() { return Rd{rd + (shift ? 8 : 0)}; } + operator Rs() { return Rs{rd + (shift ? 8 : 0)}; } +}; + +// decode register for RVC +constexpr RxC DecodeCR_RD(uint32_t inst) { return RxC{DecodeRD(inst), false}; } +constexpr RxC DecodeCI_RD(uint32_t inst) { return RxC{DecodeRD(inst), false}; } +constexpr RxC DecodeCR_RS1(uint32_t inst) { return RxC{DecodeRD(inst), false}; } +constexpr RxC DecodeCI_RS1(uint32_t inst) { return RxC{DecodeRD(inst), false}; } +constexpr RxC DecodeCR_RS2(uint32_t inst) { + return RxC{(inst & 0x7C) >> 2, false}; +} + +constexpr RxC DecodeCIW_RD(uint32_t inst) { return RxC{(inst & 0x1C) >> 2}; } +constexpr RxC DecodeCL_RD(uint32_t inst) { return RxC{DecodeCIW_RD(inst)}; } +constexpr RxC DecodeCA_RD(uint32_t inst) { return RxC{(inst & 0x380) >> 7}; } +constexpr RxC DecodeCB_RD(uint32_t inst) { return RxC{DecodeCA_RD(inst)}; } + +constexpr RxC DecodeCL_RS1(uint32_t inst) { return RxC{DecodeCA_RD(inst)}; } +constexpr RxC DecodeCS_RS1(uint32_t inst) { return RxC{DecodeCA_RD(inst)}; } +constexpr RxC DecodeCA_RS1(uint32_t inst) { return RxC{DecodeCA_RD(inst)}; } +constexpr RxC DecodeCB_RS1(uint32_t inst) { return RxC{DecodeCA_RD(inst)}; } + +constexpr RxC DecodeCSS_RS2(uint32_t inst) { return DecodeCR_RS2(inst); } +constexpr RxC DecodeCS_RS2(uint32_t inst) { return RxC{DecodeCIW_RD(inst)}; } +constexpr RxC DecodeCA_RS2(uint32_t inst) { return RxC{DecodeCIW_RD(inst)}; } + +RISCVInst DecodeC_LWSP(uint32_t inst) { + auto rd = DecodeCI_RD(inst); + uint16_t offset = ((inst << 4) & 0xc0) // offset[7:6] + | ((inst >> 7) & 0x20) // offset[5] + | ((inst >> 2) & 0x1c); // offset[4:2] + if (rd == 0) + return RESERVED{inst}; + return LW{rd, Rs{gpr_sp_riscv}, uint32_t(offset)}; +} + +RISCVInst DecodeC_LDSP(uint32_t inst) { + auto rd = DecodeCI_RD(inst); + uint16_t offset = ((inst << 4) & 0x1c0) // offset[8:6] + | ((inst >> 7) & 0x20) // offset[5] + | ((inst >> 2) & 0x18); // offset[4:3] + if (rd == 0) + return RESERVED{inst}; + return LD{rd, Rs{gpr_sp_riscv}, uint32_t(offset)}; +} + +RISCVInst DecodeC_SWSP(uint32_t inst) { + uint16_t offset = ((inst >> 1) & 0xc0) // offset[7:6] + | ((inst >> 7) & 0x3c); // offset[5:2] + return SW{Rs{gpr_sp_riscv}, DecodeCSS_RS2(inst), uint32_t(offset)}; +} + +RISCVInst DecodeC_SDSP(uint32_t inst) { + uint16_t offset = ((inst >> 1) & 0x1c0) // offset[8:6] + | ((inst >> 7) & 0x38); // offset[5:3] + return SD{Rs{gpr_sp_riscv}, DecodeCSS_RS2(inst), uint32_t(offset)}; +} + +RISCVInst DecodeC_LW(uint32_t inst) { + uint16_t offset = ((inst << 1) & 0x40) // imm[6] + | ((inst >> 7) & 0x38) // imm[5:3] + | ((inst >> 4) & 0x4); // imm[2] + return LW{DecodeCL_RD(inst), DecodeCL_RS1(inst), uint32_t(offset)}; +} + +RISCVInst DecodeC_LD(uint32_t inst) { + uint16_t offset = ((inst << 1) & 0xc0) // imm[7:6] + | ((inst >> 7) & 0x38); // imm[5:3] + return LD{DecodeCL_RD(inst), DecodeCL_RS1(inst), uint32_t(offset)}; +} + +RISCVInst DecodeC_SW(uint32_t inst) { + uint16_t offset = ((inst << 1) & 0x40) // imm[6] + | ((inst >> 7) & 0x38) // imm[5:3] + | ((inst >> 4) & 0x4); // imm[2] + return SW{DecodeCS_RS1(inst), DecodeCS_RS2(inst), uint32_t(offset)}; +} + +RISCVInst DecodeC_SD(uint32_t inst) { + uint16_t offset = ((inst << 1) & 0xc0) // imm[7:6] + | ((inst >> 7) & 0x38); // imm[5:3] + return SD{DecodeCS_RS1(inst), DecodeCS_RS2(inst), uint32_t(offset)}; +} + +RISCVInst DecodeC_J(uint32_t inst) { + uint16_t offset = ((inst >> 1) & 0x800) // offset[11] + | ((inst << 2) & 0x400) // offset[10] + | ((inst >> 1) & 0x300) // offset[9:8] + | ((inst << 1) & 0x80) // offset[7] + | ((inst >> 1) & 0x40) // offset[6] + | ((inst << 3) & 0x20) // offset[5] + | ((inst >> 7) & 0x10) // offset[4] + | ((inst >> 2) & 0xe); // offset[3:1] + if ((offset & 0x800) == 0) + return JAL{Rd{0}, uint32_t(offset)}; + return JAL{Rd{0}, uint32_t(int32_t(int16_t(offset | 0xf000)))}; +} + +RISCVInst DecodeC_JR(uint32_t inst) { + auto rs1 = DecodeCR_RS1(inst); + if (rs1 == 0) + return RESERVED{inst}; + return JALR{Rd{0}, rs1, 0}; +} + +RISCVInst DecodeC_JALR(uint32_t inst) { + auto rs1 = DecodeCR_RS1(inst); + if (rs1 == 0) + return EBREAK{inst}; + return JALR{Rd{1}, rs1, 0}; +} + +constexpr uint16_t BOffset(uint32_t inst) { + return ((inst >> 4) & 0x100) // offset[8] + | ((inst << 1) & 0xc0) // offset[7:6] + | ((inst << 3) & 0x20) // offset[5] + | ((inst >> 7) & 0x18) // offset[4:3] + | ((inst >> 2) & 0x6); // offset[2:1] +} + +RISCVInst DecodeC_BNEZ(uint32_t inst) { + auto rs1 = DecodeCB_RS1(inst); + uint16_t offset = BOffset(inst); + if ((offset & 0x100) == 0) + return B{rs1, Rs{0}, uint32_t(offset), 0b001}; + return B{rs1, Rs{0}, uint32_t(int32_t(int16_t(offset | 0xfe00))), 0b001}; +} + +RISCVInst DecodeC_BEQZ(uint32_t inst) { + auto rs1 = DecodeCB_RS1(inst); + uint16_t offset = BOffset(inst); + if ((offset & 0x100) == 0) + return B{rs1, Rs{0}, uint32_t(offset), 0b000}; + return B{rs1, Rs{0}, uint32_t(int32_t(int16_t(offset | 0xfe00))), 0b000}; +} + +RISCVInst DecodeC_LI(uint32_t inst) { + auto rd = DecodeCI_RD(inst); + uint16_t imm = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f); + if ((imm & 0x20) == 0) + return ADDI{rd, Rs{0}, uint32_t(imm)}; + return ADDI{rd, Rs{0}, uint32_t(int32_t(int8_t(imm | 0xc0)))}; +} + +RISCVInst DecodeC_LUI_ADDI16SP(uint32_t inst) { + auto rd = DecodeCI_RD(inst); + if (rd == 0) + return HINT{inst}; + if (rd == 2) { + uint16_t nzimm = ((inst >> 3) & 0x200) // nzimm[9] + | ((inst >> 2) & 0x10) // nzimm[4] + | ((inst << 1) & 0x40) // nzimm[6] + | ((inst << 4) & 0x180) // nzimm[8:7] + | ((inst << 3) & 0x20); // nzimm[5] + if (nzimm == 0) + return RESERVED{inst}; + if ((nzimm & 0x200) == 0) + return ADDI{Rd{gpr_sp_riscv}, Rs{gpr_sp_riscv}, uint32_t(nzimm)}; + return ADDI{Rd{gpr_sp_riscv}, Rs{gpr_sp_riscv}, + uint32_t(int32_t(int16_t(nzimm | 0xfc00)))}; + } + uint32_t imm = + ((uint32_t(inst) << 5) & 0x20000) | ((uint32_t(inst) << 10) & 0x1f000); + if ((imm & 0x20000) == 0) + return LUI{rd, imm}; + return LUI{rd, uint32_t(int32_t(imm | 0xfffc0000))}; +} + +RISCVInst DecodeC_ADDI(uint32_t inst) { + auto rd = DecodeCI_RD(inst); + if (rd == 0) + return NOP{inst}; + uint16_t imm = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f); + if ((imm & 0x20) == 0) + return ADDI{rd, rd, uint32_t(imm)}; + return ADDI{rd, rd, uint32_t(int32_t(int8_t(imm | 0xc0)))}; +} + +RISCVInst DecodeC_ADDIW(uint32_t inst) { + auto rd = DecodeCI_RD(inst); + if (rd == 0) + return RESERVED{inst}; + uint16_t imm = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f); + if ((imm & 0x20) == 0) + return ADDIW{rd, rd, uint32_t(imm)}; + return ADDIW{rd, rd, uint32_t(int32_t(int8_t(imm | 0xc0)))}; +} + +RISCVInst DecodeC_ADDI4SPN(uint32_t inst) { + auto rd = DecodeCIW_RD(inst); + uint16_t nzuimm = ((inst >> 1) & 0x3c0) // nzuimm[9:6] + | ((inst >> 7) & 0x30) // nzuimm[5:4] + | ((inst >> 2) & 0x8) // nzuimm[3] + | ((inst >> 4) & 0x4); // nzuimm[2] + + if (rd == 0 && nzuimm == 0) + return INVALID{inst}; + if (nzuimm == 0) + return RESERVED{inst}; + return ADDI{rd, Rs{gpr_sp_riscv}, uint32_t(nzuimm)}; +} + +RISCVInst DecodeC_SLLI(uint32_t inst) { + auto rd = DecodeCI_RD(inst); + uint16_t shamt = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f); + if (rd == 0 || shamt == 0) + return HINT{inst}; + return SLLI{rd, rd, uint8_t(shamt)}; +} + +RISCVInst DecodeC_SRLI(uint32_t inst) { + auto rd = DecodeCB_RD(inst); + uint16_t shamt = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f); + if (shamt == 0) + return HINT{inst}; + return SRLI{rd, rd, uint8_t(shamt)}; +} + +RISCVInst DecodeC_SRAI(uint32_t inst) { + auto rd = DecodeCB_RD(inst); + uint16_t shamt = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f); + if (shamt == 0) + return HINT{inst}; + return SRAI{rd, rd, uint8_t(shamt)}; +} + +RISCVInst DecodeC_ANDI(uint32_t inst) { + auto rd = DecodeCB_RD(inst); + uint16_t imm = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f); + if ((imm & 0x20) == 0) + return ANDI{rd, rd, uint32_t(imm)}; + return ANDI{rd, rd, uint32_t(int32_t(int8_t(imm | 0xc0)))}; +} + +RISCVInst DecodeC_MV(uint32_t inst) { + auto rd = DecodeCR_RD(inst); + auto rs2 = DecodeCR_RS2(inst); + if (rd == 0) + return HINT{inst}; + return ADD{rd, Rs{0}, rs2}; +} + +RISCVInst DecodeC_ADD(uint32_t inst) { + auto rd = DecodeCR_RD(inst); + return ADD{rd, rd, DecodeCR_RS2(inst)}; +} + +RISCVInst DecodeC_AND(uint32_t inst) { + auto rd = DecodeCA_RD(inst); + return AND{rd, rd, DecodeCA_RS2(inst)}; +} + +RISCVInst DecodeC_OR(uint32_t inst) { + auto rd = DecodeCA_RD(inst); + return OR{rd, rd, DecodeCA_RS2(inst)}; +} + +RISCVInst DecodeC_XOR(uint32_t inst) { + auto rd = DecodeCA_RD(inst); + return XOR{rd, rd, DecodeCA_RS2(inst)}; +} + +RISCVInst DecodeC_SUB(uint32_t inst) { + auto rd = DecodeCA_RD(inst); + return SUB{rd, rd, DecodeCA_RS2(inst)}; +} + +RISCVInst DecodeC_SUBW(uint32_t inst) { + auto rd = DecodeCA_RD(inst); + return SUBW{rd, rd, DecodeCA_RS2(inst)}; +} + +RISCVInst DecodeC_ADDW(uint32_t inst) { + auto rd = DecodeCA_RD(inst); + return ADDW{rd, rd, DecodeCA_RS2(inst)}; +} + +} // namespace lldb_private +#endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVCINSTRUCTION_H diff --git a/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h b/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h --- a/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h +++ b/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h @@ -68,6 +68,11 @@ Rd rd; \ Rs rs1; \ } +/// The `inst` fields are used for debugging. +#define INVALID_INST(NAME) \ + struct NAME { \ + uint32_t inst; \ + } // RV32I instructions (The base integer ISA) struct B { @@ -165,16 +170,22 @@ R_TYPE_INST(AMOMINU_D); R_TYPE_INST(AMOMAXU_D); -using RISCVInst = - std::variant; +/// Invalid and reserved instructions, the `inst` fields are used for debugging. +INVALID_INST(INVALID); +INVALID_INST(RESERVED); +INVALID_INST(EBREAK); +INVALID_INST(HINT); +INVALID_INST(NOP); + +using RISCVInst = 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, INVALID, EBREAK, RESERVED, HINT, NOP>; struct InstrPattern { const char *name; @@ -196,25 +207,5 @@ constexpr uint32_t DecodeRS1(uint32_t inst) { return (inst & 0xF8000) >> 15; } constexpr uint32_t DecodeRS2(uint32_t inst) { return (inst & 0x1F00000) >> 20; } -// decode register for RVC -constexpr uint16_t DecodeCR_RD(uint16_t inst) { return DecodeRD(inst); } -constexpr uint16_t DecodeCI_RD(uint16_t inst) { return DecodeRD(inst); } -constexpr uint16_t DecodeCIW_RD(uint16_t inst) { return (inst & 0x1C) >> 2; } -constexpr uint16_t DecodeCL_RD(uint16_t inst) { return DecodeCIW_RD(inst); } -constexpr uint16_t DecodeCA_RD(uint16_t inst) { return (inst & 0x380) >> 7; } -constexpr uint16_t DecodeCB_RD(uint16_t inst) { return DecodeCA_RD(inst); } - -constexpr uint16_t DecodeCR_RS1(uint16_t inst) { return DecodeRD(inst); } -constexpr uint16_t DecodeCI_RS1(uint16_t inst) { return DecodeRD(inst); } -constexpr uint16_t DecodeCL_RS1(uint16_t inst) { return DecodeCA_RD(inst); } -constexpr uint16_t DecodeCS_RS1(uint16_t inst) { return DecodeCA_RD(inst); } -constexpr uint16_t DecodeCA_RS1(uint16_t inst) { return DecodeCA_RD(inst); } -constexpr uint16_t DecodeCB_RS1(uint16_t inst) { return DecodeCA_RD(inst); } - -constexpr uint16_t DecodeCR_RS2(uint16_t inst) { return (inst & 0x7C) >> 2; } -constexpr uint16_t DecodeCSS_RS2(uint16_t inst) { return DecodeCR_RS2(inst); } -constexpr uint16_t DecodeCS_RS2(uint16_t inst) { return DecodeCIW_RD(inst); } -constexpr uint16_t DecodeCA_RS2(uint16_t inst) { return DecodeCIW_RD(inst); } - } // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_RISCVINSTRUCTION_H diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -1929,8 +1929,14 @@ case llvm::Triple::riscv32: case llvm::Triple::riscv64: { static const uint8_t g_riscv_opcode[] = {0x73, 0x00, 0x10, 0x00}; // ebreak - trap_opcode = g_riscv_opcode; - trap_opcode_size = sizeof(g_riscv_opcode); + static const uint8_t g_riscv_opcode_c[] = {0x02, 0x90}; // c.ebreak + if (arch.GetFlags() & ArchSpec::eRISCV_rvc) { + trap_opcode = g_riscv_opcode_c; + trap_opcode_size = sizeof(g_riscv_opcode_c); + } else { + trap_opcode = g_riscv_opcode; + trap_opcode_size = sizeof(g_riscv_opcode); + } } break; default: diff --git a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp --- a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp +++ b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp @@ -256,6 +256,88 @@ ASSERT_EQ(this->gpr.gpr[0], uint64_t(16)); } +struct TestDecode { + uint32_t inst; + RISCVInst inst_type; +}; + +bool compareInst(const RISCVInst &lhs, const RISCVInst &rhs) { + if (lhs.index() != rhs.index()) + return false; + return std::visit( + [&](auto &&L) { + return std::visit( + [&](auto &&R) { + // guaranteed by + // 1. lhs.index() == rhs.index() + // (they are the same instruction type) + // 2. all instruction representations are plain data objects + // consisting of primitive types. + return std::memcmp(&L, &R, sizeof(L)) == 0; + }, + rhs); + }, + lhs); +} + +TEST_F(RISCVEmulatorTester, TestCDecode) { + std::vector tests = { + {0x0000, INVALID{0x0000}}, + {0x0010, RESERVED{0x0010}}, + // ADDI4SPN here, decode as ADDI + {0x0024, ADDI{Rd{9}, Rs{2}, 8}}, + {0x4488, LW{Rd{10}, Rs{9}, 8}}, + {0x6488, LD{Rd{10}, Rs{9}, 8}}, + {0xC488, SW{Rs{9}, Rs{10}, 8}}, + {0xE488, SD{Rs{9}, Rs{10}, 8}}, + {0x1001, NOP{0x1001}}, + {0x1085, ADDI{Rd{1}, Rs{1}, uint32_t(-31)}}, + {0x2081, ADDIW{Rd{1}, Rs{1}, 0}}, + // ADDI16SP here, decode as ADDI + {0x7101, ADDI{Rd{2}, Rs{2}, uint32_t(-512)}}, + {0x4081, ADDI{Rd{1}, Rs{0}, 0}}, + {0x7081, LUI{Rd{1}, uint32_t(-131072)}}, + {0x8085, SRLI{Rd{9}, Rs{9}, 1}}, + {0x8485, SRAI{Rd{9}, Rs{9}, 1}}, + {0x8881, ANDI{Rd{9}, Rs{9}, 0}}, + {0x8C85, SUB{Rd{9}, Rs{9}, Rs{9}}}, + {0x8CA5, XOR{Rd{9}, Rs{9}, Rs{9}}}, + {0x8CC5, OR{Rd{9}, Rs{9}, Rs{9}}}, + {0x8CE5, AND{Rd{9}, Rs{9}, Rs{9}}}, + {0x9C85, SUBW{Rd{9}, Rs{9}, Rs{9}}}, + {0x9CA5, ADDW{Rd{9}, Rs{9}, Rs{9}}}, + // C.J here, decoded as JAL + {0xA001, JAL{Rd{0}, 0}}, + {0xC081, B{Rs{9}, Rs{0}, 0, 0b000}}, + {0xE081, B{Rs{9}, Rs{0}, 0, 0b001}}, + {0x1082, SLLI{Rd{1}, Rs{1}, 32}}, + {0x1002, HINT{0x1002}}, + // SLLI64 here, decoded as HINT if not in RV128 + {0x0082, HINT{0x0082}}, + // LWSP here, decoded as LW + {0x4082, LW{Rd{1}, Rs{2}, 0}}, + // LDSP here, decoded as LD + {0x6082, LD{Rd{1}, Rs{2}, 0}}, + // C.JR here, decoded as JALR + {0x8082, JALR{Rd{0}, Rs{1}, 0}}, + // C.MV here, decoded as ADD + {0x8086, ADD{Rd{1}, Rs{0}, Rs{1}}}, + {0x9002, EBREAK{0x9002}}, + {0x9082, JALR{Rd{1}, Rs{1}, 0}}, + {0x9086, ADD{Rd{1}, Rs{1}, Rs{1}}}, + // C.SWSP here, decoded as SW + {0xC006, SW{Rs{2}, Rs{1}, 0}}, + // C.SDSP here, decoded as SD + {0xE006, SD{Rs{2}, Rs{1}, 0}}, + }; + + for (auto i : tests) { + auto decode = this->Decode(i.inst); + ASSERT_TRUE(decode.has_value()); + ASSERT_TRUE(compareInst(decode->decoded, i.inst_type)); + } +} + // GEN_BRANCH_TEST(opcode, imm1, imm2, imm3): // It should branch for instruction `opcode imm1, imm2` // It should do nothing for instruction `opcode imm1, imm3` @@ -274,7 +356,6 @@ }; TEST_F(RISCVEmulatorTester, TestDecodeAndExcute) { - std::vector tests = { // RV32I & RV64I Tests {0x00010113, "ADDI", false, [](RS1 rs1, RS2, PC) { return rs1 + 0; }},