forked from OSchip/llvm-project
[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
This commit is contained in:
parent
6758ecb98c
commit
8ab4a9696a
|
@ -5,6 +5,8 @@ tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info)
|
|||
tablegen(LLVM RISCVGenMCCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM RISCVGenAsmMatcher.inc -gen-asm-matcher)
|
||||
tablegen(LLVM RISCVGenAsmWriter.inc -gen-asm-writer)
|
||||
tablegen(LLVM RISCVGenSubtargetInfo.inc -gen-subtarget)
|
||||
tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler)
|
||||
|
||||
add_public_tablegen_target(RISCVCommonTableGen)
|
||||
|
||||
|
@ -13,6 +15,7 @@ add_llvm_target(RISCVCodeGen
|
|||
)
|
||||
|
||||
add_subdirectory(AsmParser)
|
||||
add_subdirectory(Disassembler)
|
||||
add_subdirectory(InstPrinter)
|
||||
add_subdirectory(MCTargetDesc)
|
||||
add_subdirectory(TargetInfo)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
add_llvm_library(LLVMRISCVDisassembler
|
||||
RISCVDisassembler.cpp
|
||||
)
|
|
@ -0,0 +1,24 @@
|
|||
;===- ./lib/Target/RISCV/Disassembler/LLVMBuild.txt ------------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = RISCVDisassembler
|
||||
parent = RISCV
|
||||
required_libraries = MCDisassembler RISCVInfo Support
|
||||
add_to_library_groups = RISCV
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[common]
|
||||
subdirectories = AsmParser InstPrinter TargetInfo MCTargetDesc
|
||||
subdirectories = AsmParser Disassembler InstPrinter TargetInfo MCTargetDesc
|
||||
|
||||
[component_0]
|
||||
type = TargetGroup
|
||||
|
@ -24,6 +24,7 @@ name = RISCV
|
|||
parent = Target
|
||||
has_asmparser = 1
|
||||
has_asmprinter = 1
|
||||
has_disassembler = 1
|
||||
|
||||
[component_1]
|
||||
type = Library
|
||||
|
|
|
@ -59,6 +59,9 @@ public:
|
|||
unsigned getImmOpValueAsr1(const MCInst &MI, unsigned OpNo,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
unsigned getImmOpValue(const MCInst &MI, unsigned OpNo,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
@ -105,6 +108,23 @@ RISCVMCCodeEmitter::getImmOpValueAsr1(const MCInst &MI, unsigned OpNo,
|
|||
}
|
||||
|
||||
llvm_unreachable("Unhandled expression!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
|
||||
const MCOperand &MO = MI.getOperand(OpNo);
|
||||
|
||||
// If the destination is an immediate, there is nothing to do
|
||||
if (MO.isImm())
|
||||
return MO.getImm();
|
||||
|
||||
llvm_unreachable("Unhandled expression!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "RISCVGenMCCodeEmitter.inc"
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#define GET_REGINFO_MC_DESC
|
||||
#include "RISCVGenRegisterInfo.inc"
|
||||
|
||||
#define GET_SUBTARGETINFO_MC_DESC
|
||||
#include "RISCVGenSubtargetInfo.inc"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static MCInstrInfo *createRISCVMCInstrInfo() {
|
||||
|
@ -64,5 +67,6 @@ extern "C" void LLVMInitializeRISCVTargetMC() {
|
|||
TargetRegistry::RegisterMCAsmBackend(*T, createRISCVAsmBackend);
|
||||
TargetRegistry::RegisterMCCodeEmitter(*T, createRISCVMCCodeEmitter);
|
||||
TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter);
|
||||
TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfoImpl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,4 +55,7 @@ MCObjectWriter *createRISCVELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI,
|
|||
#define GET_INSTRINFO_ENUM
|
||||
#include "RISCVGenInstrInfo.inc"
|
||||
|
||||
#define GET_SUBTARGETINFO_ENUM
|
||||
#include "RISCVGenSubtargetInfo.inc"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
class RISCVInst<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: Instruction {
|
||||
field bits<32> Inst;
|
||||
// SoftFail is a field the disassembler can use to provide a way for
|
||||
// instructions to not match without killing the whole decode process. It is
|
||||
// mainly used for ARM, but Tablegen expects this field to exist or it fails
|
||||
// to build the decode table.
|
||||
field bits<32> SoftFail = 0;
|
||||
let Size = 4;
|
||||
|
||||
bits<7> Opcode = 0;
|
||||
|
|
|
@ -36,34 +36,42 @@ def FenceArg : AsmOperandClass {
|
|||
def fencearg : Operand<i32> {
|
||||
let ParserMatchClass = FenceArg;
|
||||
let PrintMethod = "printFenceArg";
|
||||
let DecoderMethod = "decodeUImmOperand<4>";
|
||||
}
|
||||
|
||||
def uimm5 : Operand<i32> {
|
||||
let ParserMatchClass = UImmAsmOperand<5>;
|
||||
let DecoderMethod = "decodeUImmOperand<5>";
|
||||
}
|
||||
|
||||
def simm12 : Operand<i32> {
|
||||
let ParserMatchClass = SImmAsmOperand<12>;
|
||||
let DecoderMethod = "decodeSImmOperand<12>";
|
||||
}
|
||||
|
||||
def uimm12 : Operand<i32> {
|
||||
let ParserMatchClass = UImmAsmOperand<12>;
|
||||
let DecoderMethod = "decodeUImmOperand<12>";
|
||||
}
|
||||
|
||||
// A 13-bit signed immediate where the least significant bit is zero.
|
||||
def simm13_lsb0 : Operand<i32> {
|
||||
let ParserMatchClass = SImmAsmOperand<13, "Lsb0">;
|
||||
let EncoderMethod = "getImmOpValueAsr1";
|
||||
let DecoderMethod = "decodeSImmOperandAndLsl1<13>";
|
||||
}
|
||||
|
||||
def uimm20 : Operand<i32> {
|
||||
let ParserMatchClass = UImmAsmOperand<20>;
|
||||
let EncoderMethod = "getImmOpValue";
|
||||
let DecoderMethod = "decodeUImmOperand<20>";
|
||||
}
|
||||
|
||||
// A 21-bit signed immediate where the least significant bit is zero.
|
||||
def simm21_lsb0 : Operand<i32> {
|
||||
let ParserMatchClass = SImmAsmOperand<21, "Lsb0">;
|
||||
let EncoderMethod = "getImmOpValueAsr1";
|
||||
let DecoderMethod = "decodeSImmOperandAndLsl1<21>";
|
||||
}
|
||||
|
||||
// As noted in RISCVRegisterInfo.td, the hope is that support for
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
|
||||
# RUN: llvm-mc %s -triple=riscv64 -show-encoding \
|
||||
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s
|
||||
# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
|
||||
# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s
|
||||
# RUN: llvm-mc -filetype=obj -triple riscv64 < %s \
|
||||
# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s
|
||||
|
||||
# CHECK-INST: lui a0, 2
|
||||
# CHECK: encoding: [0x37,0x25,0x00,0x00]
|
||||
|
|
Loading…
Reference in New Issue