diff options
author | Alex Bradbury <asb@lowrisc.org> | 2017-09-17 14:36:28 +0000 |
---|---|---|
committer | Alex Bradbury <asb@lowrisc.org> | 2017-09-17 14:36:28 +0000 |
commit | 8ab4a9696a7753c546caff4fd21826ea72370648 (patch) | |
tree | 7e51c89b9e72b3376bb4b34e300f45c789f55505 /llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp | |
parent | 6758ecb98cf6a1e2d99f6a53cffe7d4848371cbc (diff) | |
download | bcm5719-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.cpp | 135 |
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); +} |