diff options
Diffstat (limited to 'lib/Target/ARM/Disassembler/ARMDisassemblerCore.h')
-rw-r--r-- | lib/Target/ARM/Disassembler/ARMDisassemblerCore.h | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h new file mode 100644 index 0000000000..23b309cd4f --- /dev/null +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h @@ -0,0 +1,301 @@ +//===- ARMDisassemblerCore.h - ARM disassembler helpers ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the ARM Disassembler. +// +// The first part defines the enumeration type of ARM instruction format, which +// specifies the encoding used by the instruction, as well as a helper function +// to convert the enums to printable char strings. +// +// It also contains code to represent the concepts of Builder, Builder Factory, +// as well as the Algorithm to solve the problem of disassembling an ARM instr. +// +//===----------------------------------------------------------------------===// + +#ifndef ARMDISASSEMBLERCORE_H +#define ARMDISASSEMBLERCORE_H + +#include "llvm/MC/MCInst.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "ARMInstrInfo.h" + +namespace llvm { + +class ARMUtils { +public: + static const char *OpcodeName(unsigned Opcode); +}; + +#define ARM_FORMATS \ + ENTRY(ARM_FORMAT_PSEUDO, 0) \ + ENTRY(ARM_FORMAT_MULFRM, 1) \ + ENTRY(ARM_FORMAT_BRFRM, 2) \ + ENTRY(ARM_FORMAT_BRMISCFRM, 3) \ + ENTRY(ARM_FORMAT_DPFRM, 4) \ + ENTRY(ARM_FORMAT_DPSOREGFRM, 5) \ + ENTRY(ARM_FORMAT_LDFRM, 6) \ + ENTRY(ARM_FORMAT_STFRM, 7) \ + ENTRY(ARM_FORMAT_LDMISCFRM, 8) \ + ENTRY(ARM_FORMAT_STMISCFRM, 9) \ + ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \ + ENTRY(ARM_FORMAT_ARITHMISCFRM, 11) \ + ENTRY(ARM_FORMAT_EXTFRM, 12) \ + ENTRY(ARM_FORMAT_VFPUNARYFRM, 13) \ + ENTRY(ARM_FORMAT_VFPBINARYFRM, 14) \ + ENTRY(ARM_FORMAT_VFPCONV1FRM, 15) \ + ENTRY(ARM_FORMAT_VFPCONV2FRM, 16) \ + ENTRY(ARM_FORMAT_VFPCONV3FRM, 17) \ + ENTRY(ARM_FORMAT_VFPCONV4FRM, 18) \ + ENTRY(ARM_FORMAT_VFPCONV5FRM, 19) \ + ENTRY(ARM_FORMAT_VFPLDSTFRM, 20) \ + ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 21) \ + ENTRY(ARM_FORMAT_VFPMISCFRM, 22) \ + ENTRY(ARM_FORMAT_THUMBFRM, 23) \ + ENTRY(ARM_FORMAT_NEONFRM, 24) \ + ENTRY(ARM_FORMAT_NEONGETLNFRM, 25) \ + ENTRY(ARM_FORMAT_NEONSETLNFRM, 26) \ + ENTRY(ARM_FORMAT_NEONDUPFRM, 27) \ + ENTRY(ARM_FORMAT_LDSTEXFRM, 28) \ + ENTRY(ARM_FORMAT_MISCFRM, 29) \ + ENTRY(ARM_FORMAT_THUMBMISCFRM, 30) + +// ARM instruction format specifies the encoding used by the instruction. +#define ENTRY(n, v) n = v, +typedef enum { + ARM_FORMATS + ARM_FORMAT_NA +} ARMFormat; +#undef ENTRY + +// Converts enum to const char*. +static const inline char *stringForARMFormat(ARMFormat form) { +#define ENTRY(n, v) case n: return #n; + switch(form) { + ARM_FORMATS + case ARM_FORMAT_NA: + default: + return ""; + } +#undef ENTRY +} + +#define NS_FORMATS \ + ENTRY(NS_FORMAT_NONE, 0) \ + ENTRY(NS_FORMAT_VLDSTLane, 1) \ + ENTRY(NS_FORMAT_VLDSTLaneDbl, 2) \ + ENTRY(NS_FORMAT_VLDSTRQ, 3) \ + ENTRY(NS_FORMAT_NVdImm, 4) \ + ENTRY(NS_FORMAT_NVdVmImm, 5) \ + ENTRY(NS_FORMAT_NVdVmImmVCVT, 6) \ + ENTRY(NS_FORMAT_NVdVmImmVDupLane, 7) \ + ENTRY(NS_FORMAT_NVdVmImmVSHLL, 8) \ + ENTRY(NS_FORMAT_NVectorShuffle, 9) \ + ENTRY(NS_FORMAT_NVectorShift, 10) \ + ENTRY(NS_FORMAT_NVectorShift2, 11) \ + ENTRY(NS_FORMAT_NVdVnVmImm, 12) \ + ENTRY(NS_FORMAT_NVdVnVmImmVectorShift, 13) \ + ENTRY(NS_FORMAT_NVdVnVmImmVectorExtract, 14) \ + ENTRY(NS_FORMAT_NVdVnVmImmMulScalar, 15) \ + ENTRY(NS_FORMAT_VTBL, 16) + +// NEON instruction sub-format further classify the NEONFrm instruction. +#define ENTRY(n, v) n = v, +typedef enum { + NS_FORMATS + NS_FORMAT_NA +} NSFormat; +#undef ENTRY + +// Converts enum to const char*. +static const inline char *stringForNSFormat(NSFormat form) { +#define ENTRY(n, v) case n: return #n; + switch(form) { + NS_FORMATS + case NS_FORMAT_NA: + return "NA"; + default: + return ""; + } +#undef ENTRY +} + +/// Expands on the enum definitions from ARMBaseInstrInfo.h. +/// They are being used by the disassembler implementation. +namespace ARMII { + enum { + NEONRegMask = 15, + GPRRegMask = 15, + NEON_RegRdShift = 12, + NEON_D_BitShift = 22, + NEON_RegRnShift = 16, + NEON_N_BitShift = 7, + NEON_RegRmShift = 0, + NEON_M_BitShift = 5 + }; +} + +/// Utility function for extracting [From, To] bits from a uint32_t. +static inline unsigned slice(uint32_t Bits, unsigned From, unsigned To) { + assert(From < 32 && To < 32 && From >= To); + return (Bits >> To) & ((1 << (From - To + 1)) - 1); +} + +/// Utility function for setting [From, To] bits to Val for a uint32_t. +static inline void setSlice(uint32_t &Bits, unsigned From, unsigned To, + uint32_t Val) { + assert(From < 32 && To < 32 && From >= To); + uint32_t Mask = ((1 << (From - To + 1)) - 1); + Bits &= ~(Mask << To); + Bits |= (Val & Mask) << To; +} + +/// Various utilities for checking the target specific flags. + +/// A unary data processing instruction doesn't have an Rn operand. +static inline bool isUnaryDP(unsigned TSFlags) { + return (TSFlags & ARMII::UnaryDP); +} + +/// This four-bit field describes the addressing mode used. +/// See also ARMBaseInstrInfo.h. +static inline unsigned getAddrMode(unsigned TSFlags) { + return (TSFlags & ARMII::AddrModeMask); +} + +/// {IndexModePre, IndexModePost} +/// Only valid for load and store ops. +/// See also ARMBaseInstrInfo.h. +static inline unsigned getIndexMode(unsigned TSFlags) { + return (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift; +} + +/// Pre-/post-indexed operations define an extra $base_wb in the OutOperandList. +static inline bool isPrePostLdSt(unsigned TSFlags) { + return (TSFlags & ARMII::IndexModeMask) != 0; +} + +/// AbstractARMMCBuilder - AbstractARMMCBuilder represents an interface of ARM +/// MCInst builder that knows how to build up the MCOperand list. +class AbstractARMMCBuilder { +public: + /// Build - Build the MCInst fully and return true. Return false if any + /// failure occurs. + virtual bool Build(MCInst &MI, uint32_t insn) { return false; } +}; + +/// ARMDisassemblyAlgorithm - ARMDisassemblyAlgorithm represents an interface of +/// ARM disassembly algorithm that relies on the entries of target operand info, +/// among other things, to solve the problem of disassembling an ARM machine +/// instruction. +class ARMDisassemblyAlgorithm { +public: + /// Return true if this algorithm successfully disassembles the instruction. + /// NumOpsAdded is updated to reflect the number of operands added by the + /// algorithm. NumOpsAdded may be less than NumOps, in which case, there are + /// operands unaccounted for which need to be dealt with by the API client. + virtual bool Solve(MCInst& MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) const + = 0; +}; + +/// ARMBasicMCBuilder - ARMBasicMCBuilder represents a concrete subclass of +/// ARMAbstractMCBuilder. +class ARMBasicMCBuilder : public AbstractARMMCBuilder { + unsigned Opcode; + ARMFormat Format; + NSFormat NSF; + unsigned short NumOps; + const ARMDisassemblyAlgorithm &Algo; + static unsigned ITCounter; // Possible values: 0, 1, 2, 3, 4. + static unsigned ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially. + +public: + ARMBasicMCBuilder(ARMBasicMCBuilder &MCB) : AbstractARMMCBuilder(), + Opcode(MCB.Opcode), Format(MCB.Format), NSF(MCB.NSF), NumOps(MCB.NumOps), + Algo(MCB.Algo) {} + + /// Opcode, Format, NSF, NumOperands, and Algo make an ARM Basic MCBuilder. + ARMBasicMCBuilder(unsigned opc, ARMFormat format, NSFormat NSF, + unsigned short num, const ARMDisassemblyAlgorithm &algo) + : AbstractARMMCBuilder(), Opcode(opc), Format(format), NumOps(num), + Algo(algo) {} + + /// TryPredicateAndSBitModifier - TryPredicateAndSBitModifier tries to process + /// the possible Predicate and SBitModifier, to build the remaining MCOperand + /// constituents. + static bool TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode, + uint32_t insn, unsigned short NumOpsRemaning); + + /// InITBlock - InITBlock returns true if we are inside an IT block. + static bool InITBlock() { + return ITCounter > 0; + } + + /// Build - Build delegates to BuildIt to perform the heavy liftling. After + /// that, it invokes RunBuildAfterHook where some housekeepings can be done. + virtual bool Build(MCInst &MI, uint32_t insn) { + bool Status = BuildIt(MI, insn); + return RunBuildAfterHook(Status, MI, insn); + } + + /// BuildIt - BuildIt performs the build step for this ARM Basic MC Builder. + /// The general idea is to set the Opcode for the MCInst, followed by adding + /// the appropriate MCOperands to the MCInst. ARM Basic MC Builder delegates + /// to the Algo (ARM Disassemble Algorithm) object to perform Format-specific + /// disassembly, followed by class method TryPredicateAndSBitModifier() to do + /// PredicateOperand and OptionalDefOperand which follow the Dst/Src Operands. + virtual bool BuildIt(MCInst &MI, uint32_t insn); + + /// RunBuildAfterHook - RunBuildAfterHook performs operations deemed necessary + /// after BuildIt is finished. + virtual bool RunBuildAfterHook(bool Status, MCInst &MI, uint32_t insn); + +private: + /// Get condition of the current IT instruction. + static unsigned GetITCond() { + return slice(ITState, 7, 4); + } + + /// Init ITState. + static void InitITState(unsigned short bits7_0) { + ITState = bits7_0; + } + + /// Update ITState if necessary. + static void UpdateITState() { + assert(ITCounter); + --ITCounter; + if (ITCounter == 0) + ITState = 0; + else { + unsigned short NewITState4_0 = slice(ITState, 4, 0) << 1; + setSlice(ITState, 4, 0, NewITState4_0); + } + } +}; + +/// ARMMCBuilderFactory - ARMMCBuilderFactory represents the factory class that +/// vends out ARMAbstractMCBuilder instances through its class method. +class ARMMCBuilderFactory { +private: + ARMMCBuilderFactory(); // DO NOT IMPLEMENT. + +public: + /// CreateMCBuilder - Return an AbstractARMMCBuilder that can build up the MC + /// infrastructure of an MCInst given the Opcode and Format of the instr. + /// Return NULL if it fails to create/return a proper builder. API clients + /// are responsible for freeing up of the allocated memory. Cacheing can be + /// performed by the API clients to improve performance. + static AbstractARMMCBuilder *CreateMCBuilder(unsigned Opcode, + ARMFormat Format, NSFormat NSF); +}; + +} // namespace llvm + +#endif |