[Lldb-commits] [lldb] 05ae747 - [LLDB][RISCV] Add RV64C instruction support for EmulateInstructionRISCV
via lldb-commits
lldb-commits at lists.llvm.org
Tue Oct 25 04:12:53 PDT 2022
Author: Emmmer
Date: 2022-10-25T19:12:45+08:00
New Revision: 05ae747a5353811f93f5814f24d2335e6229d78a
URL: https://github.com/llvm/llvm-project/commit/05ae747a5353811f93f5814f24d2335e6229d78a
DIFF: https://github.com/llvm/llvm-project/commit/05ae747a5353811f93f5814f24d2335e6229d78a.diff
LOG: [LLDB][RISCV] Add RV64C instruction support for EmulateInstructionRISCV
Add:
- RV64C instructions sets.
- corresponding unittests.
- `c.break` code for lldb and lldb-server
Fix:
- wrong decoding of imm in `DecodeSType`
Reviewed By: DavidSpickett
Differential Revision: https://reviews.llvm.org/D136362
Added:
lldb/source/Plugins/Instruction/RISCV/RISCVCInstructions.h
Modified:
lldb/source/Host/common/NativeProcessProtocol.cpp
lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
lldb/source/Target/Platform.cpp
lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
Removed:
################################################################################
diff --git a/lldb/source/Host/common/NativeProcessProtocol.cpp b/lldb/source/Host/common/NativeProcessProtocol.cpp
index 363699344146f..cdb59842e658b 100644
--- a/lldb/source/Host/common/NativeProcessProtocol.cpp
+++ b/lldb/source/Host/common/NativeProcessProtocol.cpp
@@ -503,9 +503,10 @@ NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
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 @@ NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
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
index 8d1a4c999e8f8..1d8f3a2750277 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -6,11 +6,10 @@
//
//===----------------------------------------------------------------------===//
-#include <cstdlib>
-
#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 DecodeBImm(uint32_t inst) {
}
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 @@ LoadStoreAddr(EmulateInstructionRISCV &emulator, I inst) {
}
// Read T from memory, then load its sign-extended value m_emu to register.
-template <typename I, typename T, typename m_emu>
+template <typename I, typename T, typename E>
static std::enable_if_t<is_load<I>, 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<T>(*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 @@ static const InstrPattern PATTERNS[] = {
{"AMOMAX_D", 0xF800707F, 0xA000302F, DecodeRType<AMOMAX_D>},
{"AMOMINU_D", 0xF800707F, 0xC000302F, DecodeRType<AMOMINU_D>},
{"AMOMAXU_D", 0xF800707F, 0xE000302F, DecodeRType<AMOMAXU_D>},
+
+ // 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<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
@@ -473,9 +504,9 @@ llvm::Optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
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 @@ class Executor {
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
index 0000000000000..1f113167311ad
--- /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 <cstdint>
+#include <variant>
+
+#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
index 380dcefeecfd2..5b29fce4ec5bf 100644
--- a/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
+++ b/lldb/source/Plugins/Instruction/RISCV/RISCVInstructions.h
@@ -68,6 +68,11 @@ struct Rs {
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(AMOMAX_D);
R_TYPE_INST(AMOMINU_D);
R_TYPE_INST(AMOMAXU_D);
-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 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 DecodeRD(uint32_t inst) { return (inst & 0xF80) >> 7; }
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
index 4e09a6cf35627..306ee99be5952 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -1929,8 +1929,14 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,
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
index 5645bae8016bb..9d58983b6532b 100644
--- a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
+++ b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
@@ -256,6 +256,88 @@ TEST_F(RISCVEmulatorTester, TestAtomicSequence) {
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<TestDecode> 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 @@ struct TestData {
};
TEST_F(RISCVEmulatorTester, TestDecodeAndExcute) {
-
std::vector<TestData> tests = {
// RV32I & RV64I Tests
{0x00010113, "ADDI", false, [](RS1 rs1, RS2, PC) { return rs1 + 0; }},
More information about the lldb-commits
mailing list