summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
diff options
context:
space:
mode:
authorAlex Bradbury <asb@lowrisc.org>2017-09-17 14:36:28 +0000
committerAlex Bradbury <asb@lowrisc.org>2017-09-17 14:36:28 +0000
commit8ab4a9696a7753c546caff4fd21826ea72370648 (patch)
tree7e51c89b9e72b3376bb4b34e300f45c789f55505 /llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
parent6758ecb98cf6a1e2d99f6a53cffe7d4848371cbc (diff)
downloadbcm5719-llvm-8ab4a9696a7753c546caff4fd21826ea72370648.tar.gz
bcm5719-llvm-8ab4a9696a7753c546caff4fd21826ea72370648.zip
[RISCV] Add support for disassembly
This Disassembly support allows for 'round-trip' testing, and rv32i-valid.s has been updated appropriately. Differential Revision: https://reviews.llvm.org/D23567 llvm-svn: 313486
Diffstat (limited to 'llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp')
-rw-r--r--llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp135
1 files changed, 135 insertions, 0 deletions
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
new file mode 100644
index 00000000000..e64d875a567
--- /dev/null
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -0,0 +1,135 @@
+//===-- RISCVDisassembler.cpp - Disassembler for RISCV --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the RISCVDisassembler class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCFixedLenDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "riscv-disassembler"
+
+typedef MCDisassembler::DecodeStatus DecodeStatus;
+
+namespace {
+class RISCVDisassembler : public MCDisassembler {
+
+public:
+ RISCVDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
+ : MCDisassembler(STI, Ctx) {}
+
+ DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const override;
+};
+} // end anonymous namespace
+
+static MCDisassembler *createRISCVDisassembler(const Target &T,
+ const MCSubtargetInfo &STI,
+ MCContext &Ctx) {
+ return new RISCVDisassembler(STI, Ctx);
+}
+
+extern "C" void LLVMInitializeRISCVDisassembler() {
+ // Register the disassembler for each target.
+ TargetRegistry::RegisterMCDisassembler(getTheRISCV32Target(),
+ createRISCVDisassembler);
+ TargetRegistry::RegisterMCDisassembler(getTheRISCV64Target(),
+ createRISCVDisassembler);
+}
+
+static const unsigned GPRDecoderTable[] = {
+ RISCV::X0_32, RISCV::X1_32, RISCV::X2_32, RISCV::X3_32,
+ RISCV::X4_32, RISCV::X5_32, RISCV::X6_32, RISCV::X7_32,
+ RISCV::X8_32, RISCV::X9_32, RISCV::X10_32, RISCV::X11_32,
+ RISCV::X12_32, RISCV::X13_32, RISCV::X14_32, RISCV::X15_32,
+ RISCV::X16_32, RISCV::X17_32, RISCV::X18_32, RISCV::X19_32,
+ RISCV::X20_32, RISCV::X21_32, RISCV::X22_32, RISCV::X23_32,
+ RISCV::X24_32, RISCV::X25_32, RISCV::X26_32, RISCV::X27_32,
+ RISCV::X28_32, RISCV::X29_32, RISCV::X30_32, RISCV::X31_32
+};
+
+static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > sizeof(GPRDecoderTable)) {
+ return MCDisassembler::Fail;
+ }
+
+ // We must define our own mapping from RegNo to register identifier.
+ // Accessing index RegNo in the register class will work in the case that
+ // registers were added in ascending order, but not in general.
+ unsigned Reg = GPRDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+template <unsigned N>
+static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm,
+ int64_t Address, const void *Decoder) {
+ assert(isUInt<N>(Imm) && "Invalid immediate");
+ Inst.addOperand(MCOperand::createImm(Imm));
+ return MCDisassembler::Success;
+}
+
+template <unsigned N>
+static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm,
+ int64_t Address, const void *Decoder) {
+ assert(isUInt<N>(Imm) && "Invalid immediate");
+ // Sign-extend the number in the bottom N bits of Imm
+ Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm)));
+ return MCDisassembler::Success;
+}
+
+template <unsigned N>
+static DecodeStatus decodeSImmOperandAndLsl1(MCInst &Inst, uint64_t Imm,
+ int64_t Address,
+ const void *Decoder) {
+ assert(isUInt<N>(Imm) && "Invalid immediate");
+ // Sign-extend the number in the bottom N bits of Imm after accounting for
+ // the fact that the N bit immediate is stored in N-1 bits (the LSB is
+ // always zero)
+ Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm << 1)));
+ return MCDisassembler::Success;
+}
+
+#include "RISCVGenDisassemblerTables.inc"
+
+DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &OS,
+ raw_ostream &CS) const {
+ // TODO: although assuming 4-byte instructions is sufficient for RV32 and
+ // RV64, this will need modification when supporting the compressed
+ // instruction set extension (RVC) which uses 16-bit instructions. Other
+ // instruction set extensions have the option of defining instructions up to
+ // 176 bits wide.
+ Size = 4;
+ if (Bytes.size() < 4) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ // Get the four bytes of the instruction.
+ uint32_t Inst = support::endian::read32le(Bytes.data());
+
+ return decodeInstruction(DecoderTable32, MI, Inst, Address, this, STI);
+}
OpenPOWER on IntegriCloud