Index: lib/Target/RISCV/CMakeLists.txt =================================================================== --- lib/Target/RISCV/CMakeLists.txt +++ lib/Target/RISCV/CMakeLists.txt @@ -5,6 +5,8 @@ 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_subdirectory(AsmParser) +add_subdirectory(Disassembler) add_subdirectory(InstPrinter) add_subdirectory(MCTargetDesc) add_subdirectory(TargetInfo) Index: lib/Target/RISCV/Disassembler/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/RISCV/Disassembler/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMRISCVDisassembler + RISCVDisassembler.cpp + ) Index: lib/Target/RISCV/Disassembler/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/RISCV/Disassembler/LLVMBuild.txt @@ -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 + Index: lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp =================================================================== --- /dev/null +++ lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -0,0 +1,125 @@ +//===-- 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 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 DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + const RISCVDisassembler *Dis = + static_cast(Decoder); + const MCRegisterInfo *RegInfo = Dis->getContext().getRegisterInfo(); + const MCRegisterClass &RC = RegInfo->getRegClass(RISCV::GPRRegClassID); + + if (RegNo > RC.getNumRegs()) + return MCDisassembler::Fail; + + unsigned Reg = *(RC.begin() + RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +template +static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + +template +static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt(Imm) && "Invalid immediate"); + // Sign-extend the number in the bottom N bits of Imm + Inst.addOperand(MCOperand::createImm(SignExtend64(Imm))); + return MCDisassembler::Success; +} + +template +static DecodeStatus decodeSImmOperandAndLsl1(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt(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(Imm << 1))); + return MCDisassembler::Success; +} + +#include "RISCVGenDisassemblerTables.inc" + +DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size, + ArrayRef 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); +} Index: lib/Target/RISCV/LLVMBuild.txt =================================================================== --- lib/Target/RISCV/LLVMBuild.txt +++ lib/Target/RISCV/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = AsmParser InstPrinter TargetInfo MCTargetDesc +subdirectories = AsmParser Disassembler InstPrinter TargetInfo MCTargetDesc [component_0] type = TargetGroup @@ -24,6 +24,7 @@ parent = Target has_asmparser = 1 has_asmprinter = 1 +has_disassembler = 1 [component_1] type = Library Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -59,6 +59,9 @@ unsigned getImmOpValueAsr1(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + unsigned getImmOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; } // end anonymous namespace @@ -105,6 +108,23 @@ } llvm_unreachable("Unhandled expression!"); + + return 0; +} + +unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &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" Index: lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h +++ lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h @@ -55,4 +55,7 @@ #define GET_INSTRINFO_ENUM #include "RISCVGenInstrInfo.inc" +#define GET_SUBTARGETINFO_ENUM +#include "RISCVGenSubtargetInfo.inc" + #endif Index: lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp @@ -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() { @@ -65,5 +68,6 @@ TargetRegistry::RegisterMCAsmBackend(*T, createRISCVAsmBackend); TargetRegistry::RegisterMCCodeEmitter(*T, createRISCVMCCodeEmitter); TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter); + TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfoImpl); } } Index: lib/Target/RISCV/RISCVInstrFormats.td =================================================================== --- lib/Target/RISCV/RISCVInstrFormats.td +++ lib/Target/RISCV/RISCVInstrFormats.td @@ -28,6 +28,11 @@ class RISCVInst 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; Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -29,34 +29,42 @@ def uimm4 : Operand { let ParserMatchClass = UImmAsmOperand<4>; + let DecoderMethod = "decodeUImmOperand<4>"; } def uimm5 : Operand { let ParserMatchClass = UImmAsmOperand<5>; + let DecoderMethod = "decodeUImmOperand<5>"; } def simm12 : Operand { let ParserMatchClass = SImmAsmOperand<12>; + let DecoderMethod = "decodeSImmOperand<12>"; } def uimm12 : Operand { let ParserMatchClass = UImmAsmOperand<12>; + let DecoderMethod = "decodeUImmOperand<12>"; } // A 13-bit signed immediate where the least significant bit is zero. def simm13_lsb0 : Operand { let ParserMatchClass = SImmAsmOperand<13, "Lsb0">; let EncoderMethod = "getImmOpValueAsr1"; + let DecoderMethod = "decodeSImmOperandAndLsl1<13>"; } def uimm20 : Operand { 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 { let ParserMatchClass = SImmAsmOperand<21, "Lsb0">; let EncoderMethod = "getImmOpValueAsr1"; + let DecoderMethod = "decodeSImmOperandAndLsl1<21>"; } // As noted in RISCVRegisterInfo.td, the hope is that support for Index: test/MC/RISCV/rv32i-valid.s =================================================================== --- test/MC/RISCV/rv32i-valid.s +++ test/MC/RISCV/rv32i-valid.s @@ -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]