[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:
Alex Bradbury 2017-09-17 14:36:28 +00:00
parent 6758ecb98c
commit 8ab4a9696a
11 changed files with 211 additions and 1 deletions

View File

@ -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)

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMRISCVDisassembler
RISCVDisassembler.cpp
)

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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]