]> granicus.if.org Git - llvm/commitdiff
[RISCV] Add support for disassembly
authorAlex Bradbury <asb@lowrisc.org>
Sun, 17 Sep 2017 14:36:28 +0000 (14:36 +0000)
committerAlex Bradbury <asb@lowrisc.org>
Sun, 17 Sep 2017 14:36:28 +0000 (14:36 +0000)
This Disassembly support allows for 'round-trip' testing, and rv32i-valid.s
has been updated appropriately.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@313486 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/RISCV/CMakeLists.txt
lib/Target/RISCV/Disassembler/CMakeLists.txt [new file with mode: 0644]
lib/Target/RISCV/Disassembler/LLVMBuild.txt [new file with mode: 0644]
lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp [new file with mode: 0644]
lib/Target/RISCV/LLVMBuild.txt
lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
lib/Target/RISCV/RISCVInstrFormats.td
lib/Target/RISCV/RISCVInstrInfo.td
test/MC/RISCV/rv32i-valid.s

index 6cc55fd3a17531b64d43879c7d25cf9fc4b1a2d5..b9f3fc110c7468a960873d19935573dcd44aaf22 100644 (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)
diff --git a/lib/Target/RISCV/Disassembler/CMakeLists.txt b/lib/Target/RISCV/Disassembler/CMakeLists.txt
new file mode 100644 (file)
index 0000000..39bd2b7
--- /dev/null
@@ -0,0 +1,3 @@
+add_llvm_library(LLVMRISCVDisassembler
+  RISCVDisassembler.cpp
+  )
diff --git a/lib/Target/RISCV/Disassembler/LLVMBuild.txt b/lib/Target/RISCV/Disassembler/LLVMBuild.txt
new file mode 100644 (file)
index 0000000..340e89d
--- /dev/null
@@ -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
+
diff --git a/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
new file mode 100644 (file)
index 0000000..e64d875
--- /dev/null
@@ -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);
+}
index 933fed1856b4972c99297372c90bb9cba97fb69c..e15963b5bd7b4925c5dd50c2e2e131ffd2ace05f 100644 (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
index eb0beb028ad2068ee2ecefd9668f19332d919bb4..f4eaf06f622d9287b3fcf85faff17b03f02a8605 100644 (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"
index 0f68dd7aa055e1bdbac8d6b0d6510fe12ebb1aba..2b35eab577bfaf8c37fe35210c5db9e033695106 100644 (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);
   }
 }
index 7c98b1c8f321335c345167e3ac8e2a0f949eb16a..9891fd52b2f4ef80056d72e921edd69191cd48c5 100644 (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
index 3fab7122f6f1a51a8c2089d2e8aead9eb3f0a18e..d77f3874c7df00a979f24ebafb6a62e316a8bb32 100644 (file)
 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;
index 78b1c907f339a6d7912242871681acf793d87ffb..e84e4dabb9428adc1ea3bc5d1850753826a7d7c9 100644 (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
index 4c883e9a0ae17f40e40be7c46ab88eb8408d510f..95d9da4bb51d5e17349639d6fc6ab14d4b2cf211 100644 (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]