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,120 @@ +//===-- 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(TheRISCV32Target, + createRISCVDisassembler); + TargetRegistry::RegisterMCDisassembler(TheRISCV64Target, + 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 { + 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 @@ -104,6 +107,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,18 +29,22 @@ 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 with a mask of !0x1 applied (i.e. the LSB must be @@ -48,10 +52,13 @@ def simm13_mask1 : Operand { let ParserMatchClass = SImmAsmOperand<13, "Mask1">; 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 with a mask of !0x1 applied (i.e. the LSB must be @@ -59,6 +66,7 @@ def simm21_mask1 : Operand { let ParserMatchClass = SImmAsmOperand<21, "Mask1">; let EncoderMethod = "getImmOpValueAsr1"; + let DecoderMethod = "decodeSImmOperandAndLsl1<21>"; } def LUI : FU<0b0110111, (outs GPR:$rd), (ins uimm20:$imm20), Index: test/MC/RISCV/rv32i-valid.s =================================================================== --- test/MC/RISCV/rv32i-valid.s +++ test/MC/RISCV/rv32i-valid.s @@ -1,81 +1,149 @@ # 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 ecall # CHECK: encoding: [0x73,0x00,0x00,0x00] +# CHECK-DIS: ecall ebreak # CHECK: encoding: [0x73,0x00,0x10,0x00] +# CHECK-DIS: ebreak csrrw t0, 0xfff, t1 # CHECK: encoding: [0xf3,0x12,0xf3,0xff] +# CHECK-DIS: csrrw t0, 4095, t1 csrrs s0, 0xc00, x0 # CHECK: encoding: [0x73,0x24,0x00,0xc0] +# CHECK-DIS: csrrs s0, 3072, zero csrrs s3, 0x001, s5 # CHECK: encoding: [0xf3,0xa9,0x1a,0x00] +# CHECK-DIS: csrrs s3, 1, s5 csrrc sp, 0x000, ra # CHECK: encoding: [0x73,0xb1,0x00,0x00] +# CHECK-DIS: csrrc sp, 0, ra csrrwi a5, 0x000, 0 # CHECK: encoding: [0xf3,0x57,0x00,0x00] +# CHECK-DIS: csrrwi a5, 0, 0 csrrsi t2, 0xfff, 31 # CHECK: encoding: [0xf3,0xe3,0xff,0xff] +# CHECK-DIS: csrrsi t2, 4095, 31 csrrci t1, 0x140, 5 # CHECK: encoding: [0x73,0xf3,0x02,0x14] +# CHECK-DIS: csrrci t1, 320, 5