llvm-mirror/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
Alex Bradbury d744c268f2 [RISCV] MC layer support for the standard RV32F instruction set extension
The most interesting part of this patch is probably the handling of 
rounding mode arguments. Sadly, the RISC-V assembler handles floating point 
rounding modes as a special "argument" when it would be more consistent to 
handle them like the atomics, opcode suffixes. This patch supports parsing 
this optional parameter, using InstAlias to allow parsing these floating point 
instructions when no rounding mode is specified.

Differential Revision: https://reviews.llvm.org/D39893

llvm-svn: 320020
2017-12-07 10:26:05 +00:00

160 lines
6.3 KiB
C++

//===-- 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, RISCV::X1, RISCV::X2, RISCV::X3,
RISCV::X4, RISCV::X5, RISCV::X6, RISCV::X7,
RISCV::X8, RISCV::X9, RISCV::X10, RISCV::X11,
RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15,
RISCV::X16, RISCV::X17, RISCV::X18, RISCV::X19,
RISCV::X20, RISCV::X21, RISCV::X22, RISCV::X23,
RISCV::X24, RISCV::X25, RISCV::X26, RISCV::X27,
RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31
};
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;
}
static const unsigned FPR32DecoderTable[] = {
RISCV::F0_32, RISCV::F1_32, RISCV::F2_32, RISCV::F3_32,
RISCV::F4_32, RISCV::F5_32, RISCV::F6_32, RISCV::F7_32,
RISCV::F8_32, RISCV::F9_32, RISCV::F10_32, RISCV::F11_32,
RISCV::F12_32, RISCV::F13_32, RISCV::F14_32, RISCV::F15_32,
RISCV::F16_32, RISCV::F17_32, RISCV::F18_32, RISCV::F19_32,
RISCV::F20_32, RISCV::F21_32, RISCV::F22_32, RISCV::F23_32,
RISCV::F24_32, RISCV::F25_32, RISCV::F26_32, RISCV::F27_32,
RISCV::F28_32, RISCV::F29_32, RISCV::F30_32, RISCV::F31_32
};
static DecodeStatus DecodeFPR32RegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > sizeof(FPR32DecoderTable))
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 = FPR32DecoderTable[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);
}