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,111 @@ +//===-- RISCVMCCodeEmitter.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 + +namespace llvm { +extern Target TheRISCV32Target, TheRISCV64Target; +} + +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(TheRISCV32Target, + createRISCVDisassembler); + TargetRegistry::RegisterMCDisassembler(TheRISCV64Target, + createRISCVDisassembler); +} + +static unsigned getReg(const void *D, unsigned RC, unsigned RegNo) { + const RISCVDisassembler *Dis = static_cast(D); + const MCRegisterInfo *RegInfo = Dis->getContext().getRegisterInfo(); + return *(RegInfo->getRegClass(RC).begin() + RegNo); +} + +static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, RISCV::GPRRegClassID, 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"); + Inst.addOperand(MCOperand::createImm(SignExtend64(Imm))); + 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 { + // Get the four bytes of the instruction. + Size = 4; + if (Bytes.size() < 4) { + Size = 0; + return MCDisassembler::Fail; + } + + 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 @@ -55,6 +55,10 @@ unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + + unsigned getImm20OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; } // end anonymous namespace @@ -87,4 +91,21 @@ return 0; } +unsigned RISCVMCCodeEmitter::getImm20OpValue(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(); + + assert(MO.isExpr() && + "getImm20OpValue expects only expressions or immediates"); + 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 @@ -10,6 +10,7 @@ class RISCVInst pattern> : Instruction { field bits<32> Inst; + 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 @@ -22,26 +22,33 @@ def imm4 : Operand { let ParserMatchClass = ImmediateAsmOperand<"imm4">; + let DecoderMethod = "decodeUImmOperand<4>"; } def imm5 : Operand { let ParserMatchClass = ImmediateAsmOperand<"imm5">; + let DecoderMethod = "decodeUImmOperand<5>"; } def simm12 : Operand { let ParserMatchClass = ImmediateAsmOperand<"simm12">; + let DecoderMethod = "decodeSImmOperand<12>"; } def imm20 : Operand { let ParserMatchClass = ImmediateAsmOperand<"imm20">; + let EncoderMethod = "getImm20OpValue"; + let DecoderMethod = "decodeUImmOperand<20>"; } def simm21maskb0 : Operand { let ParserMatchClass = ImmediateAsmOperand<"simm21maskb0">; + let DecoderMethod = "decodeSImmOperand<21>"; } def simm13maskb0 : Operand { let ParserMatchClass = ImmediateAsmOperand<"simm13maskb0">; + let DecoderMethod = "decodeSImmOperand<13>"; } def LUI : FU<0b0110111, (outs GPR:$rd), (ins imm20:$imm20), Index: test/MC/RISCV/rv32i-valid.s =================================================================== --- test/MC/RISCV/rv32i-valid.s +++ test/MC/RISCV/rv32i-valid.s @@ -1,80 +1,147 @@ # RUN: llvm-mc %s -triple=riscv32 -show-encoding | FileCheck %s # RUN: llvm-mc %s -triple=riscv64 -show-encoding | FileCheck %s +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-DIS %s +# RUN: llvm-mc -filetype=obj -triple riscv64 < %s \ +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-DIS %s lui a0, 2 # CHECK: encoding: [0x37,0x25,0x00,0x00] +# CHECK-DIS: lui a0, 2 lui s11, (0x87000000>>12) # CHECK: encoding: [0xb7,0x0d,0x00,0x87] +# CHECK-DIS: lui s11, 552960 lui t0, 1048575 # CHECK: encoding: [0xb7,0xf2,0xff,0xff] +# CHECK-DIS: lui t0, 1048575 lui gp, 0 # CHECK: encoding: [0xb7,0x01,0x00,0x00] +# CHECK-DIS: lui gp, 0 auipc a0, 2 # CHECK: encoding: [0x17,0x25,0x00,0x00] +# CHECK-DIS: auipc a0, 2 auipc s11, (0x87000000>>12) # CHECK: encoding: [0x97,0x0d,0x00,0x87] +# CHECK-DIS: auipc s11, 552960 auipc t0, 1048575 # CHECK: encoding: [0x97,0xf2,0xff,0xff] +# CHECK-DIS: auipc t0, 1048575 auipc gp, 0 # CHECK: encoding: [0x97,0x01,0x00,0x00] +# CHECK-DIS: auipc gp, 0 jal a2, 1048574 # CHECK: encoding: [0x6f,0xf6,0xff,0x7f] +# CHECK-DIS: jal a2, 1048574 jal a3, 256 # CHECK: encoding: [0xef,0x06,0x00,0x10] +# CHECK-DIS: jal a3, 256 jalr a0, a1, -2048 # CHECK: encoding: [0x67,0x85,0x05,0x80] +# CHECK-DIS: jalr a0, a1, -2048 jalr t2, t1, 2047 # CHECK: encoding: [0xe7,0x03,0xf3,0x7f] +# CHECK-DIS: jalr t2, t1, 2047 jalr sp, zero, 256 # CHECK: encoding: [0x67,0x01,0x00,0x10] +# CHECK-DIS: jalr sp, zero, 256 beq s1, s1, 102 # CHECK: encoding: [0x63,0x83,0x94,0x06] +# CHECK-DIS: beq s1, s1, 102 bne a4, a5, -4096 # CHECK: encoding: [0x63,0x10,0xf7,0x80] +# CHECK-DIS: bne a4, a5, -4096 blt sp, gp, 4094 # CHECK: encoding: [0xe3,0x4f,0x31,0x7e] +# CHECK-DIS: blt sp, gp, 4094 bge s2, ra, -224 # CHECK: encoding: [0xe3,0x50,0x19,0xf2] +# CHECK-DIS: bge s2, ra, -224 bltu zero, zero, 0 # CHECK: encoding: [0x63,0x60,0x00,0x00] +# CHECK-DIS: bltu zero, zero, 0 bgeu s8, sp, 512 # CHECK: encoding: [0x63,0x70,0x2c,0x20] +# CHECK-DIS: bgeu s8, sp, 512 lb s3, 4(ra) # CHECK: encoding: [0x83,0x89,0x40,0x00] +# CHECK-DIS: lb s3, 4(ra) lb s3, +4(ra) # CHECK: encoding: [0x83,0x89,0x40,0x00] +# CHECK-DIS: lb s3, 4(ra) lh t1, -2048(zero) # CHECK: encoding: [0x03,0x13,0x00,0x80] +# CHECK-DIS: lh t1, -2048(zero) lh sp, 2047(a0) # CHECK: encoding: [0x03,0x11,0xf5,0x7f] +# CHECK-DIS: lh sp, 2047(a0) lw a0, 97(a2) # CHECK: encoding: [0x03,0x25,0x16,0x06] +# CHECK-DIS: lw a0, 97(a2) lbu s5, 0(s6) # CHECK: encoding: [0x83,0x4a,0x0b,0x00] +# CHECK-DIS: lbu s5, 0(s6) lhu t3, 255(t3) # CHECK: encoding: [0x03,0x5e,0xfe,0x0f] +# CHECK-DIS: lhu t3, 255(t3) sb a0, 2047(a2) # CHECK: encoding: [0xa3,0x0f,0xa6,0x7e] +# CHECK-DIS: sb a0, 2047(a2) sh t3, -2048(t5) # CHECK: encoding: [0x23,0x10,0xcf,0x81] +# CHECK-DIS: sh t3, -2048(t5) sw ra, 999(zero) # CHECK: encoding: [0xa3,0x23,0x10,0x3e] +# CHECK-DIS: sw ra, 999(zero) addi ra, sp, 2 # CHECK: encoding: [0x93,0x00,0x21,0x00] +# CHECK-DIS: addi ra, sp, 2 slti a0, a2, -20 # CHECK: encoding: [0x13,0x25,0xc6,0xfe] +# CHECK-DIS: slti a0, a2, -20 sltiu s2, s3, 0x50 # CHECK: encoding: [0x13,0xb9,0x09,0x05] +# CHECK-DIS: sltiu s2, s3, 80 xori tp, t1, -99 # CHECK: encoding: [0x13,0x42,0xd3,0xf9] +# CHECK-DIS: xori tp, t1, -99 ori a0, a1, -2048 # CHECK: encoding: [0x13,0xe5,0x05,0x80] +# CHECK-DIS: ori a0, a1, -2048 andi ra, sp, 2047 # CHECK: encoding: [0x93,0x70,0xf1,0x7f] +# CHECK-DIS: andi ra, sp, 2047 andi x1, x2, 2047 # CHECK: encoding: [0x93,0x70,0xf1,0x7f] +# CHECK-DIS: andi ra, sp, 2047 slli t3, t3, 31 # CHECK: encoding: [0x13,0x1e,0xfe,0x01] +# CHECK-DIS: slli t3, t3, 31 srli a0, a4, 0 # CHECK: encoding: [0x13,0x55,0x07,0x00] +# CHECK-DIS: srli a0, a4, 0 srai a2, sp, 15 # CHECK: encoding: [0x13,0x56,0xf1,0x40] +# CHECK-DIS: srai a2, sp, 15 add ra, zero, zero # CHECK: encoding: [0xb3,0x00,0x00,0x00] +# CHECK-DIS: add ra, zero, zero add x1, x0, x0 # CHECK: encoding: [0xb3,0x00,0x00,0x00] +# CHECK-DIS: add ra, zero, zero sub t0, t2, t1 # CHECK: encoding: [0xb3,0x82,0x63,0x40] +# CHECK-DIS: sub t0, t2, t1 sll a5, a4, a3 # CHECK: encoding: [0xb3,0x17,0xd7,0x00] +# CHECK-DIS: sll a5, a4, a3 slt s0, s0, s0 # CHECK: encoding: [0x33,0x24,0x84,0x00] +# CHECK-DIS: slt s0, s0, s0 sltu gp, a0, a1 # CHECK: encoding: [0xb3,0x31,0xb5,0x00] +# CHECK-DIS: sltu gp, a0, a1 xor s2, s2, s8 # CHECK: encoding: [0x33,0x49,0x89,0x01] +# CHECK-DIS: xor s2, s2, s8 xor x18, x18, x24 # CHECK: encoding: [0x33,0x49,0x89,0x01] +# CHECK-DIS: xor s2, s2, s8 srl a0, s0, t0 # CHECK: encoding: [0x33,0x55,0x54,0x00] +# CHECK-DIS: srl a0, s0, t0 sra t0, s2, zero # CHECK: encoding: [0xb3,0x52,0x09,0x40] +# CHECK-DIS: sra t0, s2, zero or s10, t1, ra # CHECK: encoding: [0x33,0x6d,0x13,0x00] +# CHECK-DIS: or s10, t1, ra and a0, s2, s3 # CHECK: encoding: [0x33,0x75,0x39,0x01] +# CHECK-DIS: a0, s2, s3 # TODO: gnu assembler supports fence with no arguments fence 0, 15 # CHECK: encoding: [0x0f,0x00,0xf0,0x00] +# CHECK-DIS: fence 0, 15 fence 15, 0 # CHECK: encoding: [0x0f,0x00,0x00,0x0f] +# CHECK-DIS: fence 15, 0 fence 4, 9 # CHECK: encoding: [0x0f,0x00,0x90,0x04] +# CHECK-DIS: fence 4, 9 fence.i # CHECK: encoding: [0x0f,0x10,0x00,0x00] +# CHECK-DIS: fence.i scall # CHECK: encoding: [0x73,0x00,0x00,0x00] +# CHECK-DIS: scall sbreak # CHECK: encoding: [0x73,0x00,0x10,0x00] +# CHECK-DIS: sbreak rdcycle s0 # CHECK: encoding: [0x73,0x24,0x00,0xc0] +# CHECK-DIS: rdcycle s0 rdcycleh s1 # CHECK: encoding: [0xf3,0x24,0x00,0xc8] +# CHECK-DIS: rdcycleh s1 rdtime s2 # CHECK: encoding: [0x73,0x29,0x10,0xc0] +# CHECK-DIS: rdtime s2 rdtimeh s3 # CHECK: encoding: [0xf3,0x29,0x10,0xc8] +# CHECK-DIS: rdtimeh s3 rdinstret s4 # CHECK: encoding: [0x73,0x2a,0x20,0xc0] +# CHECK-DIS: rdinstret s4 rdinstreth s5 # CHECK: encoding: [0xf3,0x2a,0x20,0xc8] +# CHECK-DIS: rdinstreth s5