diff options
Diffstat (limited to 'llvm/lib/Target/ARM/Disassembler')
-rw-r--r-- | llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp | 513 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/Disassembler/ARMDisassembler.h | 71 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp | 3351 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h | 301 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/Disassembler/Makefile | 17 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc | 2158 |
6 files changed, 0 insertions, 6411 deletions
diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp deleted file mode 100644 index 52010cd057f..00000000000 --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ /dev/null @@ -1,513 +0,0 @@ -//===- ARMDisassembler.cpp - Disassembler for ARM/Thumb ISA ----*- 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. -// It contains code to translate the data produced by the decoder into MCInsts. -// Documentation for the disassembler can be found in ARMDisassembler.h. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "arm-disassembler" - -#include "ARMDisassembler.h" -#include "ARMDisassemblerCore.h" - -#include "llvm/MC/MCInst.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/MemoryObject.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" - -/// ARMDisassemblerTables.inc - ARMDisassemblerTables.inc is tblgen'ed from -/// RISCDisassemblerEmitter.cpp TableGen backend. It contains: -/// -/// o Mappings from opcode to ARM/Thumb instruction format -/// -/// o static uint16_t decodeInstruction(uint32_t insn) - the decoding function -/// for an ARM instruction. -/// -/// o static uint16_t decodeThumbInstruction(field_t insn) - the decoding -/// function for a Thumb instruction. -/// -#include "../ARMGenDisassemblerTables.inc" - -namespace llvm { - -namespace ARMDisassembler { - -/// showBitVector - Use the raw_ostream to log a diagnostic message describing -/// the inidividual bits of the instruction. This is a sample output: -/// -/// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -/// ------------------------------------------------------------------------------------------------- -/// | 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| -/// ------------------------------------------------------------------------------------------------- -/// -static inline void showBitVector(raw_ostream &os, const uint32_t &insn) { - os << " 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 \n"; - os << "-------------------------------------------------------------------------------------------------\n"; - os << '|'; - for (unsigned i = 32; i != 0; --i) { - if (insn >> (i - 1) & 0x01) - os << " 1"; - else - os << " 0"; - os << (i%4 == 1 ? '|' : ':'); - } - os << '\n'; - os << "-------------------------------------------------------------------------------------------------\n"; - os << '\n'; -} - -/// decodeARMInstruction is a decorator function which tries special cases of -/// instruction matching before calling the auto-generated decoder function. -static unsigned decodeARMInstruction(uint32_t &insn) { - if (slice(insn, 31, 28) == 15) - goto AutoGenedDecoder; - - // Special case processing, if any, goes here.... - - // LLVM combines the offset mode of A8.6.197 & A8.6.198 into STRB. - // The insufficient encoding information of the combined instruction confuses - // the decoder wrt BFC/BFI. Therefore, we try to recover here. - // For BFC, Inst{27-21} = 0b0111110 & Inst{6-0} = 0b0011111. - // For BFI, Inst{27-21} = 0b0111110 & Inst{6-4} = 0b001 & Inst{3-0} =! 0b1111. - if (slice(insn, 27, 21) == 0x3e && slice(insn, 6, 4) == 1) { - if (slice(insn, 3, 0) == 15) - return ARM::BFC; - else - return ARM::BFI; - } - - // Ditto for ADDSrs, which is a super-instruction for A8.6.7 & A8.6.8. - // As a result, the decoder fails to decode UMULL properly. - if (slice(insn, 27, 21) == 0x04 && slice(insn, 7, 4) == 9) { - return ARM::UMULL; - } - - // Ditto for STR_PRE, which is a super-instruction for A8.6.194 & A8.6.195. - // As a result, the decoder fails to decode SBFX properly. - if (slice(insn, 27, 21) == 0x3d && slice(insn, 6, 4) == 5) - return ARM::SBFX; - - // And STRB_PRE, which is a super-instruction for A8.6.197 & A8.6.198. - // As a result, the decoder fails to decode UBFX properly. - if (slice(insn, 27, 21) == 0x3f && slice(insn, 6, 4) == 5) - return ARM::UBFX; - - // Ditto for STRT, which is a super-instruction for A8.6.210 Encoding A1 & A2. - // As a result, the decoder fails to deocode SSAT properly. - if (slice(insn, 27, 21) == 0x35 && slice(insn, 5, 4) == 1) - return slice(insn, 6, 6) == 0 ? ARM::SSATlsl : ARM::SSATasr; - - // Ditto for RSCrs, which is a super-instruction for A8.6.146 & A8.6.147. - // As a result, the decoder fails to decode STRHT/LDRHT/LDRSHT/LDRSBT. - if (slice(insn, 27, 24) == 0) { - switch (slice(insn, 21, 20)) { - case 2: - switch (slice(insn, 7, 4)) { - case 11: - return ARM::STRHT; - default: - break; // fallthrough - } - break; - case 3: - switch (slice(insn, 7, 4)) { - case 11: - return ARM::LDRHT; - case 13: - return ARM::LDRSBT; - case 15: - return ARM::LDRSHT; - default: - break; // fallthrough - } - break; - default: - break; // fallthrough - } - } - - // Ditto for SBCrs, which is a super-instruction for A8.6.152 & A8.6.153. - // As a result, the decoder fails to decode STRH_Post/LDRD_POST/STRD_POST - // properly. - if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 0) { - unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21); - switch (slice(insn, 7, 4)) { - case 11: - switch (PW) { - case 2: // Offset - return ARM::STRH; - case 3: // Pre-indexed - return ARM::STRH_PRE; - case 0: // Post-indexed - return ARM::STRH_POST; - default: - break; // fallthrough - } - break; - case 13: - switch (PW) { - case 2: // Offset - return ARM::LDRD; - case 3: // Pre-indexed - return ARM::LDRD_PRE; - case 0: // Post-indexed - return ARM::LDRD_POST; - default: - break; // fallthrough - } - break; - case 15: - switch (PW) { - case 2: // Offset - return ARM::STRD; - case 3: // Pre-indexed - return ARM::STRD_PRE; - case 0: // Post-indexed - return ARM::STRD_POST; - default: - break; // fallthrough - } - break; - default: - break; // fallthrough - } - } - - // Ditto for SBCSSrs, which is a super-instruction for A8.6.152 & A8.6.153. - // As a result, the decoder fails to decode LDRH_POST/LDRSB_POST/LDRSH_POST - // properly. - if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 1) { - unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21); - switch (slice(insn, 7, 4)) { - case 11: - switch (PW) { - case 2: // Offset - return ARM::LDRH; - case 3: // Pre-indexed - return ARM::LDRH_PRE; - case 0: // Post-indexed - return ARM::LDRH_POST; - default: - break; // fallthrough - } - break; - case 13: - switch (PW) { - case 2: // Offset - return ARM::LDRSB; - case 3: // Pre-indexed - return ARM::LDRSB_PRE; - case 0: // Post-indexed - return ARM::LDRSB_POST; - default: - break; // fallthrough - } - break; - case 15: - switch (PW) { - case 2: // Offset - return ARM::LDRSH; - case 3: // Pre-indexed - return ARM::LDRSH_PRE; - case 0: // Post-indexed - return ARM::LDRSH_POST; - default: - break; // fallthrough - } - break; - default: - break; // fallthrough - } - } - -AutoGenedDecoder: - // Calling the auto-generated decoder function. - return decodeInstruction(insn); -} - -// Helper function for special case handling of LDR (literal) and friends. -// See, for example, A6.3.7 Load word: Table A6-18 Load word. -// See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode -// before passing it on. -static unsigned T2Morph2LoadLiteral(unsigned Opcode) { - switch (Opcode) { - default: - return Opcode; // Return unmorphed opcode. - - case ARM::t2LDRDi8: - return ARM::t2LDRDpci; - - case ARM::t2LDR_POST: case ARM::t2LDR_PRE: - case ARM::t2LDRi12: case ARM::t2LDRi8: - case ARM::t2LDRs: - return ARM::t2LDRpci; - - case ARM::t2LDRB_POST: case ARM::t2LDRB_PRE: - case ARM::t2LDRBi12: case ARM::t2LDRBi8: - case ARM::t2LDRBs: - return ARM::t2LDRBpci; - - case ARM::t2LDRH_POST: case ARM::t2LDRH_PRE: - case ARM::t2LDRHi12: case ARM::t2LDRHi8: - case ARM::t2LDRHs: - return ARM::t2LDRHpci; - - case ARM::t2LDRSB_POST: case ARM::t2LDRSB_PRE: - case ARM::t2LDRSBi12: case ARM::t2LDRSBi8: - case ARM::t2LDRSBs: - return ARM::t2LDRSBpci; - - case ARM::t2LDRSH_POST: case ARM::t2LDRSH_PRE: - case ARM::t2LDRSHi12: case ARM::t2LDRSHi8: - case ARM::t2LDRSHs: - return ARM::t2LDRSHpci; - } -} - -/// decodeThumbSideEffect is a decorator function which can potentially twiddle -/// the instruction or morph the returned opcode under Thumb2. -/// -/// First it checks whether the insn is a NEON or VFP instr; if true, bit -/// twiddling could be performed on insn to turn it into an ARM NEON/VFP -/// equivalent instruction and decodeInstruction is called with the transformed -/// insn. -/// -/// Next, there is special handling for Load byte/halfword/word instruction by -/// checking whether Rn=0b1111 and call T2Morph2LoadLiteral() on the decoded -/// Thumb2 instruction. See comments below for further details. -/// -/// Finally, one last check is made to see whether the insn is a NEON/VFP and -/// decodeInstruction(insn) is invoked on the original insn. -/// -/// Otherwise, decodeThumbInstruction is called with the original insn. -static unsigned decodeThumbSideEffect(bool IsThumb2, uint32_t &insn) { - if (IsThumb2) { - uint16_t op1 = slice(insn, 28, 27); - uint16_t op2 = slice(insn, 26, 20); - - // A6.3 32-bit Thumb instruction encoding - // Table A6-9 32-bit Thumb instruction encoding - - // The coprocessor instructions of interest are transformed to their ARM - // equivalents. - - // --------- Transform Begin Marker --------- - if ((op1 == 1 || op1 == 3) && slice(op2, 6, 4) == 7) { - // A7.4 Advanced SIMD data-processing instructions - // U bit of Thumb corresponds to Inst{24} of ARM. - uint16_t U = slice(op1, 1, 1); - - // Inst{28-24} of ARM = {1,0,0,1,U}; - uint16_t bits28_24 = 9 << 1 | U; - DEBUG(showBitVector(errs(), insn)); - setSlice(insn, 28, 24, bits28_24); - return decodeInstruction(insn); - } - - if (op1 == 3 && slice(op2, 6, 4) == 1 && slice(op2, 0, 0) == 0) { - // A7.7 Advanced SIMD element or structure load/store instructions - // Inst{27-24} of Thumb = 0b1001 - // Inst{27-24} of ARM = 0b0100 - DEBUG(showBitVector(errs(), insn)); - setSlice(insn, 27, 24, 4); - return decodeInstruction(insn); - } - // --------- Transform End Marker --------- - - // See, for example, A6.3.7 Load word: Table A6-18 Load word. - // See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode - // before passing it on to our delegate. - if (op1 == 3 && slice(op2, 6, 5) == 0 && slice(op2, 0, 0) == 1 - && slice(insn, 19, 16) == 15) - return T2Morph2LoadLiteral(decodeThumbInstruction(insn)); - - // One last check for NEON/VFP instructions. - if ((op1 == 1 || op1 == 3) && slice(op2, 6, 6) == 1) - return decodeInstruction(insn); - - // Fall through. - } - - return decodeThumbInstruction(insn); -} - -static inline bool Thumb2PreloadOpcodeNoPCI(unsigned Opcode) { - switch (Opcode) { - default: - return false; - case ARM::t2PLDi12: case ARM::t2PLDi8: - case ARM::t2PLDr: case ARM::t2PLDs: - case ARM::t2PLDWi12: case ARM::t2PLDWi8: - case ARM::t2PLDWr: case ARM::t2PLDWs: - case ARM::t2PLIi12: case ARM::t2PLIi8: - case ARM::t2PLIr: case ARM::t2PLIs: - return true; - } -} - -static inline unsigned T2Morph2Preload2PCI(unsigned Opcode) { - switch (Opcode) { - default: - return 0; - case ARM::t2PLDi12: case ARM::t2PLDi8: - case ARM::t2PLDr: case ARM::t2PLDs: - return ARM::t2PLDpci; - case ARM::t2PLDWi12: case ARM::t2PLDWi8: - case ARM::t2PLDWr: case ARM::t2PLDWs: - return ARM::t2PLDWpci; - case ARM::t2PLIi12: case ARM::t2PLIi8: - case ARM::t2PLIr: case ARM::t2PLIs: - return ARM::t2PLIpci; - } -} - -// -// Public interface for the disassembler -// - -bool ARMDisassembler::getInstruction(MCInst &MI, - uint64_t &Size, - const MemoryObject &Region, - uint64_t Address, - raw_ostream &os) const { - // The machine instruction. - uint32_t insn; - - // We want to read exactly 4 bytes of data. - if (Region.readBytes(Address, 4, (uint8_t*)&insn, NULL) == -1) - return false; - - unsigned Opcode = decodeARMInstruction(insn); - ARMFormat Format = ARMFormats[Opcode]; - NSFormat NSF = NSFormats[Opcode]; - Size = 4; - - DEBUG({ - errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode) - << " Format=" << stringForARMFormat(Format) << " NSFormat=" - << stringForNSFormat(NSF) << '\n'; - showBitVector(errs(), insn); - }); - - AbstractARMMCBuilder *Builder = - ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF); - - if (!Builder) - return false; - - if (!Builder->Build(MI, insn)) - return false; - - delete Builder; - - return true; -} - -bool ThumbDisassembler::getInstruction(MCInst &MI, - uint64_t &Size, - const MemoryObject &Region, - uint64_t Address, - raw_ostream &os) const { - // The machine instruction. - uint32_t insn = 0; - uint32_t insn1 = 0; - - // A6.1 Thumb instruction set encoding - // - // If bits [15:11] of the halfword being decoded take any of the following - // values, the halfword is the first halfword of a 32-bit instruction: - // o 0b11101 - // o 0b11110 - // o 0b11111. - // - // Otherwise, the halfword is a 16-bit instruction. - - // Read 2 bytes of data first. - if (Region.readBytes(Address, 2, (uint8_t*)&insn, NULL) == -1) - return false; - - unsigned bits15_11 = slice(insn, 15, 11); - bool IsThumb2 = false; - - // 32-bit instructions if the bits [15:11] of the halfword matches - // { 0b11101 /* 0x1D */, 0b11110 /* 0x1E */, ob11111 /* 0x1F */ }. - if (bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F) { - IsThumb2 = true; - if (Region.readBytes(Address + 2, 2, (uint8_t*)&insn1, NULL) == -1) - return false; - insn = (insn << 16 | insn1); - } - - // The insn could potentially be bit-twiddled in order to be decoded as an ARM - // NEON/VFP opcode. In such case, the modified insn is later disassembled as - // an ARM NEON/VFP instruction. - // - // This is a short term solution for lack of encoding bits specified for the - // Thumb2 NEON/VFP instructions. The long term solution could be adding some - // infrastructure to have each instruction support more than one encodings. - // Which encoding is used would be based on which subtarget the compiler/ - // disassembler is working with at the time. This would allow the sharing of - // the NEON patterns between ARM and Thumb2, as well as potential greater - // sharing between the regular ARM instructions and the 32-bit wide Thumb2 - // instructions as well. - unsigned Opcode = decodeThumbSideEffect(IsThumb2, insn); - - // A8.6.117/119/120/121. - // PLD/PLDW/PLI instructions with Rn==15 is transformed to the pci variant. - if (Thumb2PreloadOpcodeNoPCI(Opcode) && slice(insn, 19, 16) == 15) - Opcode = T2Morph2Preload2PCI(Opcode); - - ARMFormat Format = ARMFormats[Opcode]; - NSFormat NSF = NSFormats[Opcode]; - Size = IsThumb2 ? 4 : 2; - - DEBUG({ - errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode) - << " Format=" << stringForARMFormat(Format) << " NSFormat=" - << stringForNSFormat(NSF) << '\n'; - showBitVector(errs(), insn); - }); - - AbstractARMMCBuilder *Builder = - ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF); - - if (!Builder) - return false; - - if (!Builder->Build(MI, insn)) - return false; - - delete Builder; - - return true; -} - -} // namespace ARM Disassembler - -static const MCDisassembler *createARMDisassembler(const Target &T) { - return new ARMDisassembler::ARMDisassembler; -} - -static const MCDisassembler *createThumbDisassembler(const Target &T) { - return new ARMDisassembler::ThumbDisassembler; -} - -extern "C" void LLVMInitializeARMDisassembler() { - // Register the disassembler. - TargetRegistry::RegisterMCDisassembler(TheARMTarget, - createARMDisassembler); - TargetRegistry::RegisterMCDisassembler(TheThumbTarget, - createThumbDisassembler); -} - -} // namespace llvm diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.h b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.h deleted file mode 100644 index 85bc8b3d2c0..00000000000 --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.h +++ /dev/null @@ -1,71 +0,0 @@ -//===- X86Disassembler.h - Disassembler for x86 and x86_64 ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -//===----------------------------------------------------------------------===// - -#ifndef ARMDISASSEMBLER_H -#define ARMDISASSEMBLER_H - -#include "llvm/MC/MCDisassembler.h" - -namespace llvm { - -class MCInst; -class MemoryObject; -class raw_ostream; - -namespace ARMDisassembler { - -/// ARMDisassembler - ARM disassembler for all ARM platforms. -class ARMDisassembler : public MCDisassembler { -public: - /// Constructor - Initializes the disassembler. - /// - ARMDisassembler() : - MCDisassembler() { - } - - ~ARMDisassembler() { - } - - /// getInstruction - See MCDisassembler. - bool getInstruction(MCInst &instr, - uint64_t &size, - const MemoryObject ®ion, - uint64_t address, - raw_ostream &vStream) const; -private: -}; - -/// ThumbDisassembler - Thumb disassembler for all ARM platforms. -class ThumbDisassembler : public MCDisassembler { -public: - /// Constructor - Initializes the disassembler. - /// - ThumbDisassembler() : - MCDisassembler() { - } - - ~ThumbDisassembler() { - } - - /// getInstruction - See MCDisassembler. - bool getInstruction(MCInst &instr, - uint64_t &size, - const MemoryObject ®ion, - uint64_t address, - raw_ostream &vStream) const; -private: -}; - -} // namespace ARMDisassembler - -} // namespace llvm - -#endif diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp deleted file mode 100644 index c38a606c0a9..00000000000 --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp +++ /dev/null @@ -1,3351 +0,0 @@ -//===- ARMDisassemblerCore.cpp - 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. -// It contains code to represent the core concepts of Builder, Builder Factory, -// as well as the Algorithm to solve the problem of disassembling an ARM instr. -// -//===----------------------------------------------------------------------===// - -#include "ARMAddressingModes.h" -#include "ARMDisassemblerCore.h" -#include <map> - -/// ARMGenInstrInfo.inc - ARMGenInstrInfo.inc contains the static const -/// TargetInstrDesc ARMInsts[] definition and the TargetOperandInfo[]'s -/// describing the operand info for each ARMInsts[i]. -/// -/// Together with an instruction's encoding format, we can take advantage of the -/// NumOperands and the OpInfo fields of the target instruction description in -/// the quest to build out the MCOperand list for an MCInst. -/// -/// The general guideline is that with a known format, the number of dst and src -/// operands are well-known. The dst is built first, followed by the src -/// operand(s). The operands not yet used at this point are for the Implicit -/// Uses and Defs by this instr. For the Uses part, the pred:$p operand is -/// defined with two components: -/// -/// def pred { // Operand PredicateOperand -/// ValueType Type = OtherVT; -/// string PrintMethod = "printPredicateOperand"; -/// string AsmOperandLowerMethod = ?; -/// dag MIOperandInfo = (ops i32imm, CCR); -/// AsmOperandClass ParserMatchClass = ImmAsmOperand; -/// dag DefaultOps = (ops (i32 14), (i32 zero_reg)); -/// } -/// -/// which is manifested by the TargetOperandInfo[] of: -/// -/// { 0, 0|(1<<TOI::Predicate), 0 }, -/// { ARM::CCRRegClassID, 0|(1<<TOI::Predicate), 0 } -/// -/// So the first predicate MCOperand corresponds to the immediate part of the -/// ARM condition field (Inst{31-28}), and the second predicate MCOperand -/// corresponds to a register kind of ARM::CPSR. -/// -/// For the Defs part, in the simple case of only cc_out:$s, we have: -/// -/// def cc_out { // Operand OptionalDefOperand -/// ValueType Type = OtherVT; -/// string PrintMethod = "printSBitModifierOperand"; -/// string AsmOperandLowerMethod = ?; -/// dag MIOperandInfo = (ops CCR); -/// AsmOperandClass ParserMatchClass = ImmAsmOperand; -/// dag DefaultOps = (ops (i32 zero_reg)); -/// } -/// -/// which is manifested by the one TargetOperandInfo of: -/// -/// { ARM::CCRRegClassID, 0|(1<<TOI::OptionalDef), 0 } -/// -/// And this maps to one MCOperand with the regsiter kind of ARM::CPSR. -#include "ARMGenInstrInfo.inc" - -using namespace llvm; - -const char *ARMUtils::OpcodeName(unsigned Opcode) { - return ARMInsts[Opcode].Name; -} - -// There is a more efficient way than the following. It is fragile, though. -// See the code snippet after this function. -static unsigned getRegisterEnum(unsigned RegClassID, unsigned RawRegister, - bool DRegPair = false) { - - if (DRegPair && RegClassID == ARM::QPRRegClassID) { - // LLVM expects { Dd, Dd+1 } to form a super register; this is not specified - // in the ARM Architecture Manual as far as I understand it (A8.6.307). - // Therefore, we morph the RegClassID to be the sub register class and don't - // subsequently transform the RawRegister encoding when calculating RegNum. - // - // See also ARMinstPrinter::printOperand() wrt "dregpair" modifier part - // where this workaround is meant for. - RegClassID = ARM::DPRRegClassID; - } - - // See also decodeNEONRd(), decodeNEONRn(), decodeNEONRm(). - unsigned RegNum = - RegClassID == ARM::QPRRegClassID ? RawRegister >> 1 : RawRegister; - - switch (RegNum) { - default: - break; - case 0: - switch (RegClassID) { - case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R0; - case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: - case ARM::DPR_VFP2RegClassID: - return ARM::D0; - case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: - case ARM::QPR_VFP2RegClassID: - return ARM::Q0; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S0; - } - break; - case 1: - switch (RegClassID) { - case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R1; - case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: - case ARM::DPR_VFP2RegClassID: - return ARM::D1; - case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: - case ARM::QPR_VFP2RegClassID: - return ARM::Q1; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S1; - } - break; - case 2: - switch (RegClassID) { - case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R2; - case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: - case ARM::DPR_VFP2RegClassID: - return ARM::D2; - case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: - case ARM::QPR_VFP2RegClassID: - return ARM::Q2; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S2; - } - break; - case 3: - switch (RegClassID) { - case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R3; - case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: - case ARM::DPR_VFP2RegClassID: - return ARM::D3; - case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: - case ARM::QPR_VFP2RegClassID: - return ARM::Q3; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S3; - } - break; - case 4: - switch (RegClassID) { - case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R4; - case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: - case ARM::DPR_VFP2RegClassID: - return ARM::D4; - case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q4; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S4; - } - break; - case 5: - switch (RegClassID) { - case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R5; - case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: - case ARM::DPR_VFP2RegClassID: - return ARM::D5; - case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q5; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S5; - } - break; - case 6: - switch (RegClassID) { - case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R6; - case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: - case ARM::DPR_VFP2RegClassID: - return ARM::D6; - case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q6; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S6; - } - break; - case 7: - switch (RegClassID) { - case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R7; - case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: - case ARM::DPR_VFP2RegClassID: - return ARM::D7; - case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q7; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S7; - } - break; - case 8: - switch (RegClassID) { - case ARM::GPRRegClassID: return ARM::R8; - case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D8; - case ARM::QPRRegClassID: return ARM::Q8; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S8; - } - break; - case 9: - switch (RegClassID) { - case ARM::GPRRegClassID: return ARM::R9; - case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D9; - case ARM::QPRRegClassID: return ARM::Q9; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S9; - } - break; - case 10: - switch (RegClassID) { - case ARM::GPRRegClassID: return ARM::R10; - case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D10; - case ARM::QPRRegClassID: return ARM::Q10; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S10; - } - break; - case 11: - switch (RegClassID) { - case ARM::GPRRegClassID: return ARM::R11; - case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D11; - case ARM::QPRRegClassID: return ARM::Q11; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S11; - } - break; - case 12: - switch (RegClassID) { - case ARM::GPRRegClassID: return ARM::R12; - case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D12; - case ARM::QPRRegClassID: return ARM::Q12; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S12; - } - break; - case 13: - switch (RegClassID) { - case ARM::GPRRegClassID: return ARM::SP; - case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D13; - case ARM::QPRRegClassID: return ARM::Q13; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S13; - } - break; - case 14: - switch (RegClassID) { - case ARM::GPRRegClassID: return ARM::LR; - case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D14; - case ARM::QPRRegClassID: return ARM::Q14; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S14; - } - break; - case 15: - switch (RegClassID) { - case ARM::GPRRegClassID: return ARM::PC; - case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D15; - case ARM::QPRRegClassID: return ARM::Q15; - case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S15; - } - break; - case 16: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D16; - case ARM::SPRRegClassID: return ARM::S16; - } - break; - case 17: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D17; - case ARM::SPRRegClassID: return ARM::S17; - } - break; - case 18: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D18; - case ARM::SPRRegClassID: return ARM::S18; - } - break; - case 19: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D19; - case ARM::SPRRegClassID: return ARM::S19; - } - break; - case 20: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D20; - case ARM::SPRRegClassID: return ARM::S20; - } - break; - case 21: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D21; - case ARM::SPRRegClassID: return ARM::S21; - } - break; - case 22: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D22; - case ARM::SPRRegClassID: return ARM::S22; - } - break; - case 23: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D23; - case ARM::SPRRegClassID: return ARM::S23; - } - break; - case 24: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D24; - case ARM::SPRRegClassID: return ARM::S24; - } - break; - case 25: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D25; - case ARM::SPRRegClassID: return ARM::S25; - } - break; - case 26: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D26; - case ARM::SPRRegClassID: return ARM::S26; - } - break; - case 27: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D27; - case ARM::SPRRegClassID: return ARM::S27; - } - break; - case 28: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D28; - case ARM::SPRRegClassID: return ARM::S28; - } - break; - case 29: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D29; - case ARM::SPRRegClassID: return ARM::S29; - } - break; - case 30: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D30; - case ARM::SPRRegClassID: return ARM::S30; - } - break; - case 31: - switch (RegClassID) { - case ARM::DPRRegClassID: return ARM::D31; - case ARM::SPRRegClassID: return ARM::S31; - } - break; - } - llvm_unreachable("Invalid (RegClassID, RawRegister) combination"); -} - -// This is efficient but fragile. -/* -// See ARMGenRegisterInfo.h.inc for more info. -static const TargetRegisterClass* const ARMRegisterClasses[] = { - NULL, - &ARM::CCRRegClass, // CCRRegClassID = 1, - &ARM::DPRRegClass, // DPRRegClassID = 2, - &ARM::DPR_8RegClass, // DPR_8RegClassID = 3, - &ARM::DPR_VFP2RegClass, // DPR_VFP2RegClassID = 4, - &ARM::GPRRegClass, // GPRRegClassID = 5, - &ARM::QPRRegClass, // QPRRegClassID = 6, - &ARM::QPR_8RegClass, // QPR_8RegClassID = 7, - &ARM::QPR_VFP2RegClass, // QPR_VFP2RegClassID = 8, - &ARM::SPRRegClass, // SPRRegClassID = 9, - &ARM::SPR_8RegClass, // SPR_8RegClassID = 10, - &ARM::SPR_INVALIDRegClass, // SPR_INVALIDRegClassID = 11, - &ARM::tGPRRegClass, // tGPRRegClassID = 12 -}; - -// Return the register enum given register class id and raw register value. -static unsigned getRegisterEnum(unsigned RegClassID, unsigned RawRegister) { - assert(RegClassID < array_lengthof(ARMRegisterClasses) && - "Register Class ID out of range"); - return ARMRegisterClasses[RegClassID]->getRegister(RawRegister); -} -*/ - -/// DisassembleFP - DisassembleFP points to a function that disassembles an insn -/// and builds the MCOperand list upon disassembly. It returns false on failure -/// or true on success. The number of operands added is updated upon success. -typedef bool (*DisassembleFP)(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded); - -/////////////////////////////// -// // -// Utility Functions // -// // -/////////////////////////////// - -// Extract/Decode Rd: Inst{15-12}. -static inline unsigned decodeRd(uint32_t insn) { - return (insn >> ARMII::RegRdShift) & ARMII::GPRRegMask; -} - -// Extract/Decode Rn: Inst{19-16}. -static inline unsigned decodeRn(uint32_t insn) { - return (insn >> ARMII::RegRnShift) & ARMII::GPRRegMask; -} - -// Extract/Decode Rm: Inst{3-0}. -static inline unsigned decodeRm(uint32_t insn) { - return (insn & ARMII::GPRRegMask); -} - -// Extract/Decode Rs: Inst{11-8}. -static inline unsigned decodeRs(uint32_t insn) { - return (insn >> ARMII::RegRsShift) & ARMII::GPRRegMask; -} - -static inline unsigned getCondField(uint32_t insn) { - return (insn >> ARMII::CondShift); -} - -static inline unsigned getIBit(uint32_t insn) { - return (insn >> ARMII::I_BitShift) & 1; -} - -static inline unsigned getAM3IBit(uint32_t insn) { - return (insn >> ARMII::AM3_I_BitShift) & 1; -} - -static inline unsigned getPBit(uint32_t insn) { - return (insn >> ARMII::P_BitShift) & 1; -} - -static inline unsigned getUBit(uint32_t insn) { - return (insn >> ARMII::U_BitShift) & 1; -} - -static inline unsigned getPUBits(uint32_t insn) { - return (insn >> ARMII::U_BitShift) & 3; -} - -static inline unsigned getSBit(uint32_t insn) { - return (insn >> ARMII::S_BitShift) & 1; -} - -static inline unsigned getWBit(uint32_t insn) { - return (insn >> ARMII::W_BitShift) & 1; -} - -static inline unsigned getDBit(uint32_t insn) { - return (insn >> ARMII::D_BitShift) & 1; -} - -static inline unsigned getNBit(uint32_t insn) { - return (insn >> ARMII::N_BitShift) & 1; -} - -static inline unsigned getMBit(uint32_t insn) { - return (insn >> ARMII::M_BitShift) & 1; -} - -namespace { -// Sign extend 5 bit number x to r. -// Usage: int r = signextend<signed int, 5>(x); -template <typename T, unsigned B> inline T signextend(const T x) { - struct {T x:B;} s; - return s.x = x; -} -} - -// See A8.4 Shifts applied to a register. -// A8.4.2 Register controlled shifts. -// -// getShiftOpcForBits - getShiftOpcForBits translates from the ARM encoding bits -// into llvm enums for shift opcode. -// -// A8-12: DecodeRegShift() -static inline ARM_AM::ShiftOpc getShiftOpcForBits(unsigned bits) { - switch (bits) { - default: assert(0 && "No such value"); - case 0: return ARM_AM::lsl; - case 1: return ARM_AM::lsr; - case 2: return ARM_AM::asr; - case 3: return ARM_AM::ror; - } -} - -// See A8.4 Shifts applied to a register. -// A8.4.1 Constant shifts. -// -// getImmShiftSE - getImmShiftSE translates from the raw ShiftOpc and raw Imm5 -// encodings into the intended ShiftOpc and shift amount. -// -// A8-11: DecodeImmShift() -static inline void getImmShiftSE(ARM_AM::ShiftOpc &ShOp, unsigned &ShImm) { - // If type == 0b11 and imm5 == 0, we have an rrx, instead. - if (ShOp == ARM_AM::ror && ShImm == 0) - ShOp = ARM_AM::rrx; - // If (lsr or asr) and imm5 == 0, shift amount is 32. - if ((ShOp == ARM_AM::lsr || ShOp == ARM_AM::asr) && ShImm == 0) - ShImm = 32; -} - -// getAMSubModeForBits - getAMSubModeForBits translates from the ARM encoding -// bits Inst{24-23} (P(24) and U(23)) into llvm enums for AMSubMode. -static inline ARM_AM::AMSubMode getAMSubModeForBits(unsigned bits) { - switch (bits) { - default: assert(0 && "No such value"); - case 1: return ARM_AM::ia; // P=0 U=1 - case 3: return ARM_AM::ib; // P=1 U=1 - case 0: return ARM_AM::da; // P=0 U=0 - case 2: return ARM_AM::db; // P=1 U=0 - } -} - -//////////////////////////////////////////// -// // -// Disassemble function definitions // -// // -//////////////////////////////////////////// - -/// There is a separate Disassemble*Frm function entry for disassembly of an ARM -/// instr into a list of MCOperands in the appropriate order, with possible dst, -/// followed by possible src(s). -/// -/// The processing of the predicate, and the 'S' modifier bit, if MI modifies -/// the CPSR, is factored into ARMBasicMCBuilder's class method named -/// TryPredicateAndSBitModifier. - -static bool DisassemblePseudo(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - if (Opcode == ARM::Int_MemBarrierV7 || Opcode == ARM::Int_SyncBarrierV7) - return true; - - assert(0 && "Unexpected pseudo instruction!"); - return false; -} - -// Multiply Instructions. -// MLA, MLS, SMLABB, SMLABT, SMLATB, SMLATT, SMLAWB, SMLAWT, SMMLA, SMMLS: -// Rd{19-16} Rn{3-0} Rm{11-8} Ra{15-12} -// -// MUL, SMMUL, SMULBB, SMULBT, SMULTB, SMULTT, SMULWB, SMULWT: -// Rd{19-16} Rn{3-0} Rm{11-8} -// -// SMLAL, SMULL, UMAAL, UMLAL, UMULL, SMLALBB, SMLALBT, SMLALTB, SMLALTT: -// RdLo{15-12} RdHi{19-16} Rn{3-0} Rm{11-8} -// -// The mapping of the multiply registers to the "regular" ARM registers, where -// there are convenience decoder functions, is: -// -// Inst{15-12} => Rd -// Inst{19-16} => Rn -// Inst{3-0} => Rm -// Inst{11-8} => Rs -static bool DisassembleMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - unsigned short NumDefs = TID.getNumDefs(); - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumDefs > 0 && "NumDefs should be greater than 0 for MulFrm"); - assert(NumOps >= 3 - && OpInfo[0].RegClass == ARM::GPRRegClassID - && OpInfo[1].RegClass == ARM::GPRRegClassID - && OpInfo[2].RegClass == ARM::GPRRegClassID); - - // Instructions with two destination registers have RdLo{15-12} first. - if (NumDefs == 2) { - assert(NumOps >= 4 && OpInfo[3].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - } - - // The destination register: RdHi{19-16} or Rd{19-16}. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - - // The two src regsiters: Rn{3-0}, then Rm{11-8}. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRs(insn)))); - OpIdx += 3; - - // Many multiply instructions (e.g., MLA) have three src registers. - // The third register operand is Ra{15-12}. - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - } - - return true; -} - -// Helper routines for disassembly of coprocessor instructions. - -static bool LdStCopOpcode(unsigned Opcode) { - if ((Opcode >= ARM::LDC2L_OFFSET && Opcode <= ARM::LDC_PRE) || - (Opcode >= ARM::STC2L_OFFSET && Opcode <= ARM::STC_PRE)) - return true; - return false; -} -static bool CoprocessorOpcode(unsigned Opcode) { - if (LdStCopOpcode(Opcode)) - return true; - - switch (Opcode) { - default: - return false; - case ARM::CDP: case ARM::CDP2: - case ARM::MCR: case ARM::MCR2: case ARM::MRC: case ARM::MRC2: - case ARM::MCRR: case ARM::MCRR2: case ARM::MRRC: case ARM::MRRC2: - return true; - } -} -static inline unsigned GetCoprocessor(uint32_t insn) { - return slice(insn, 11, 8); -} -static inline unsigned GetCopOpc1(uint32_t insn, bool CDP) { - return CDP ? slice(insn, 23, 20) : slice(insn, 23, 21); -} -static inline unsigned GetCopOpc2(uint32_t insn) { - return slice(insn, 7, 5); -} -static inline unsigned GetCopOpc(uint32_t insn) { - return slice(insn, 7, 4); -} -// Most of the operands are in immediate forms, except Rd and Rn, which are ARM -// core registers. -// -// CDP, CDP2: cop opc1 CRd CRn CRm opc2 -// -// MCR, MCR2, MRC, MRC2: cop opc1 Rd CRn CRm opc2 -// -// MCRR, MCRR2, MRRC, MRRc2: cop opc Rd Rn CRm -// -// LDC_OFFSET, LDC_PRE, LDC_POST: cop CRd Rn R0 [+/-]imm8:00 -// and friends -// STC_OFFSET, STC_PRE, STC_POST: cop CRd Rn R0 [+/-]imm8:00 -// and friends -// <-- addrmode2 --> -// -// LDC_OPTION: cop CRd Rn imm8 -// and friends -// STC_OPTION: cop CRd Rn imm8 -// and friends -// -static bool DisassembleCoprocessor(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 5); - - unsigned &OpIdx = NumOpsAdded; - bool OneCopOpc = (Opcode == ARM::MCRR || Opcode == ARM::MCRR2 || - Opcode == ARM::MRRC || Opcode == ARM::MRRC2); - // CDP/CDP2 has no GPR operand; the opc1 operand is also wider (Inst{23-20}). - bool NoGPR = (Opcode == ARM::CDP || Opcode == ARM::CDP2); - bool LdStCop = LdStCopOpcode(Opcode); - - OpIdx = 0; - - MI.addOperand(MCOperand::CreateImm(GetCoprocessor(insn))); - - if (LdStCop) { - // Unindex if P:W = 0b00 --> _OPTION variant - unsigned PW = getPBit(insn) << 1 | getWBit(insn); - - MI.addOperand(MCOperand::CreateImm(decodeRd(insn))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - - if (PW) { - MI.addOperand(MCOperand::CreateReg(0)); - ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; - unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, slice(insn, 7, 0) << 2, - ARM_AM::no_shift); - MI.addOperand(MCOperand::CreateImm(Offset)); - OpIdx = 5; - } else { - MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 0))); - OpIdx = 4; - } - } else { - MI.addOperand(MCOperand::CreateImm(OneCopOpc ? GetCopOpc(insn) - : GetCopOpc1(insn, NoGPR))); - - MI.addOperand(NoGPR ? MCOperand::CreateImm(decodeRd(insn)) - : MCOperand::CreateReg( - getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - - MI.addOperand(OneCopOpc ? MCOperand::CreateReg( - getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn))) - : MCOperand::CreateImm(decodeRn(insn))); - - MI.addOperand(MCOperand::CreateImm(decodeRm(insn))); - - OpIdx = 5; - - if (!OneCopOpc) { - MI.addOperand(MCOperand::CreateImm(GetCopOpc2(insn))); - ++OpIdx; - } - } - - return true; -} - -// Branch Instructions. -// BLr9: SignExtend(Imm24:'00', 32) -// Bcc, BLr9_pred: SignExtend(Imm24:'00', 32) Pred0 Pred1 -// SMC: ZeroExtend(imm4, 32) -// SVC: ZeroExtend(Imm24, 32) -// -// Various coprocessor instructions are assigned BrFrm arbitrarily. -// Delegates to DisassembleCoprocessor() helper function. -// -// MRS/MRSsys: Rd -// MSR/MSRsys: Rm mask=Inst{19-16} -// BXJ: Rm -// MSRi/MSRsysi: so_imm -// SRSW/SRS: addrmode4:$addr mode_imm -// RFEW/RFE: addrmode4:$addr Rn -static bool DisassembleBrFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - if (CoprocessorOpcode(Opcode)) - return DisassembleCoprocessor(MI, Opcode, insn, NumOps, NumOpsAdded); - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - // MRS and MRSsys take one GPR reg Rd. - if (Opcode == ARM::MRS || Opcode == ARM::MRSsys) { - assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - NumOpsAdded = 1; - return true; - } - // BXJ takes one GPR reg Rm. - if (Opcode == ARM::BXJ) { - assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - NumOpsAdded = 1; - return true; - } - // MSR and MSRsys take one GPR reg Rm, followed by the mask. - if (Opcode == ARM::MSR || Opcode == ARM::MSRsys) { - assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); - NumOpsAdded = 2; - return true; - } - // MSRi and MSRsysi take one so_imm operand, followed by the mask. - if (Opcode == ARM::MSRi || Opcode == ARM::MSRsysi) { - // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0. - // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}. - // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot(). - unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF; - unsigned Imm = insn & 0xFF; - MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); - NumOpsAdded = 2; - return true; - } - // SRSW and SRS requires addrmode4:$addr for ${addr:submode}, followed by the - // mode immediate (Inst{4-0}). - if (Opcode == ARM::SRSW || Opcode == ARM::SRS || - Opcode == ARM::RFEW || Opcode == ARM::RFE) { - // ARMInstPrinter::printAddrMode4Operand() prints special mode string - // if the base register is SP; so don't set ARM::SP. - MI.addOperand(MCOperand::CreateReg(0)); - bool WB = (Opcode == ARM::SRSW); - ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); - - if (Opcode == ARM::SRSW || Opcode == ARM::SRS) - MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); - else - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - NumOpsAdded = 3; - return true; - } - - assert(Opcode == ARM::Bcc || Opcode == ARM::BLr9 || Opcode == ARM::BLr9_pred - || Opcode == ARM::SMC || Opcode == ARM::SVC); - - assert(NumOps >= 1 && OpInfo[0].RegClass == 0); - - int Imm32 = 0; - if (Opcode == ARM::SMC) { - // ZeroExtend(imm4, 32) where imm24 = Inst{3-0}. - Imm32 = slice(insn, 3, 0); - } else if (Opcode == ARM::SVC) { - // ZeroExtend(imm24, 32) where imm24 = Inst{23-0}. - Imm32 = slice(insn, 23, 0); - } else { - // SignExtend(imm24:'00', 32) where imm24 = Inst{23-0}. - unsigned Imm26 = slice(insn, 23, 0) << 2; - Imm32 = signextend<signed int, 26>(Imm26); - - // When executing an ARM instruction, PC reads as the address of the current - // instruction plus 8. The assembler subtracts 8 from the difference - // between the branch instruction and the target address, disassembler has - // to add 8 to compensate. - Imm32 += 8; - } - - MI.addOperand(MCOperand::CreateImm(Imm32)); - NumOpsAdded = 1; - - return true; -} - -// Misc. Branch Instructions. -// BR_JTadd, BR_JTr, BR_JTm -// BLXr9, BXr9 -// BRIND, BX_RET -static bool DisassembleBrMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - // BX_RET has only two predicate operands, do an early return. - if (Opcode == ARM::BX_RET) - return true; - - // BLXr9 and BRIND take one GPR reg. - if (Opcode == ARM::BLXr9 || Opcode == ARM::BRIND) { - assert(NumOps >= 1 && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - OpIdx = 1; - return true; - } - - // BR_JTadd is an ADD with Rd = PC, (Rn, Rm) as the target and index regs. - if (Opcode == ARM::BR_JTadd) { - // InOperandList with GPR:$target and GPR:$idx regs. - - assert(NumOps == 4); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - - // Fill in the two remaining imm operands to signify build completion. - MI.addOperand(MCOperand::CreateImm(0)); - MI.addOperand(MCOperand::CreateImm(0)); - - OpIdx = 4; - return true; - } - - // BR_JTr is a MOV with Rd = PC, and Rm as the source register. - if (Opcode == ARM::BR_JTr) { - // InOperandList with GPR::$target reg. - - assert(NumOps == 3); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - - // Fill in the two remaining imm operands to signify build completion. - MI.addOperand(MCOperand::CreateImm(0)); - MI.addOperand(MCOperand::CreateImm(0)); - - OpIdx = 3; - return true; - } - - // BR_JTm is an LDR with Rt = PC. - if (Opcode == ARM::BR_JTm) { - // This is the reg/reg form, with base reg followed by +/- reg shop imm. - // See also ARMAddressingModes.h (Addressing Mode #2). - - assert(NumOps == 5 && getIBit(insn) == 1); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - - ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; - - // Disassemble the offset reg (Rm), shift type, and immediate shift length. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - // Inst{6-5} encodes the shift opcode. - ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); - // Inst{11-7} encodes the imm5 shift amount. - unsigned ShImm = slice(insn, 11, 7); - - // A8.4.1. Possible rrx or shift amount of 32... - getImmShiftSE(ShOp, ShImm); - MI.addOperand(MCOperand::CreateImm( - ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); - - // Fill in the two remaining imm operands to signify build completion. - MI.addOperand(MCOperand::CreateImm(0)); - MI.addOperand(MCOperand::CreateImm(0)); - - OpIdx = 5; - return true; - } - - assert(0 && "Unexpected BrMiscFrm Opcode"); - return false; -} - -static inline uint32_t getBFCInvMask(uint32_t insn) { - uint32_t lsb = slice(insn, 11, 7); - uint32_t msb = slice(insn, 20, 16); - uint32_t Val = 0; - assert(lsb <= msb && "Encoding error: lsb > msb"); - for (uint32_t i = lsb; i <= msb; ++i) - Val |= (1 << i); - return ~Val; -} - -static inline bool SaturateOpcode(unsigned Opcode) { - switch (Opcode) { - case ARM::SSATlsl: case ARM::SSATasr: case ARM::SSAT16: - case ARM::USATlsl: case ARM::USATasr: case ARM::USAT16: - return true; - default: - return false; - } -} - -static inline unsigned decodeSaturatePos(unsigned Opcode, uint32_t insn) { - switch (Opcode) { - case ARM::SSATlsl: - case ARM::SSATasr: - return slice(insn, 20, 16) + 1; - case ARM::SSAT16: - return slice(insn, 19, 16) + 1; - case ARM::USATlsl: - case ARM::USATasr: - return slice(insn, 20, 16); - case ARM::USAT16: - return slice(insn, 19, 16); - default: - llvm_unreachable("Invalid opcode passed in"); - return 0; - } -} - -// A major complication is the fact that some of the saturating add/subtract -// operations have Rd Rm Rn, instead of the "normal" Rd Rn Rm. -// They are QADD, QDADD, QDSUB, and QSUB. -static bool DisassembleDPFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - unsigned short NumDefs = TID.getNumDefs(); - bool isUnary = isUnaryDP(TID.TSFlags); - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - // Disassemble register def if there is one. - if (NumDefs && (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID)) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - } - - // Now disassemble the src operands. - if (OpIdx >= NumOps) - return false; - - // SSAT/SSAT16/USAT/USAT16 has imm operand after Rd. - if (SaturateOpcode(Opcode)) { - MI.addOperand(MCOperand::CreateImm(decodeSaturatePos(Opcode, insn))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - - if (Opcode == ARM::SSAT16 || Opcode == ARM::USAT16) { - OpIdx += 2; - return true; - } - - // For SSAT operand reg (Rm) has been disassembled above. - // Now disassemble the shift amount. - - // Inst{11-7} encodes the imm5 shift amount. - unsigned ShAmt = slice(insn, 11, 7); - - // A8.6.183. Possible ASR shift amount of 32... - if (Opcode == ARM::SSATasr && ShAmt == 0) - ShAmt = 32; - - MI.addOperand(MCOperand::CreateImm(ShAmt)); - - OpIdx += 3; - return true; - } - - // Special-case handling of BFC/BFI/SBFX/UBFX. - if (Opcode == ARM::BFC || Opcode == ARM::BFI) { - // TIED_TO operand skipped for BFC and Inst{3-0} (Reg) for BFI. - MI.addOperand(MCOperand::CreateReg(Opcode == ARM::BFC ? 0 - : getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - MI.addOperand(MCOperand::CreateImm(getBFCInvMask(insn))); - OpIdx += 2; - return true; - } - if (Opcode == ARM::SBFX || Opcode == ARM::UBFX) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 7))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 20, 16) + 1)); - OpIdx += 3; - return true; - } - - bool RmRn = (Opcode == ARM::QADD || Opcode == ARM::QDADD || - Opcode == ARM::QDSUB || Opcode == ARM::QSUB); - - // BinaryDP has an Rn operand. - if (!isUnary) { - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::GPRRegClassID, - RmRn ? decodeRm(insn) : decodeRn(insn)))); - ++OpIdx; - } - - // If this is a two-address operand, skip it, e.g., MOVCCr operand 1. - if (isUnary && (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)) { - MI.addOperand(MCOperand::CreateReg(0)); - ++OpIdx; - } - - // Now disassemble operand 2. - if (OpIdx >= NumOps) - return false; - - if (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) { - // We have a reg/reg form. - // Assert disabled because saturating operations, e.g., A8.6.127 QASX, are - // routed here as well. - // assert(getIBit(insn) == 0 && "I_Bit != '0' reg/reg form"); - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::GPRRegClassID, - RmRn? decodeRn(insn) : decodeRm(insn)))); - ++OpIdx; - } else if (Opcode == ARM::MOVi16 || Opcode == ARM::MOVTi16) { - // We have an imm16 = imm4:imm12 (imm4=Inst{19:16}, imm12 = Inst{11:0}). - assert(getIBit(insn) == 1 && "I_Bit != '1' reg/imm form"); - unsigned Imm16 = slice(insn, 19, 16) << 12 | slice(insn, 11, 0); - MI.addOperand(MCOperand::CreateImm(Imm16)); - ++OpIdx; - } else { - // We have a reg/imm form. - // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0. - // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}. - // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot(). - assert(getIBit(insn) == 1 && "I_Bit != '1' reg/imm form"); - unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF; - unsigned Imm = insn & 0xFF; - MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot))); - ++OpIdx; - } - - return true; -} - -static bool DisassembleDPSoRegFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - unsigned short NumDefs = TID.getNumDefs(); - bool isUnary = isUnaryDP(TID.TSFlags); - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - // Disassemble register def if there is one. - if (NumDefs && (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID)) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - } - - // Disassemble the src operands. - if (OpIdx >= NumOps) - return false; - - // BinaryDP has an Rn operand. - if (!isUnary) { - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - } - - // If this is a two-address operand, skip it, e.g., MOVCCs operand 1. - if (isUnary && (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)) { - MI.addOperand(MCOperand::CreateReg(0)); - ++OpIdx; - } - - // Disassemble operand 2, which consists of three components. - if (OpIdx + 2 >= NumOps) - return false; - - assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) && - (OpInfo[OpIdx+1].RegClass == ARM::GPRRegClassID) && - (OpInfo[OpIdx+2].RegClass == 0)); - - // Register-controlled shifts have Inst{7} = 0 and Inst{4} = 1. - unsigned Rs = slice(insn, 4, 4); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - if (Rs) { - // Register-controlled shifts: [Rm, Rs, shift]. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRs(insn)))); - // Inst{6-5} encodes the shift opcode. - ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); - MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, 0))); - } else { - // Constant shifts: [Rm, reg0, shift_imm]. - MI.addOperand(MCOperand::CreateReg(0)); // NoRegister - // Inst{6-5} encodes the shift opcode. - ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); - // Inst{11-7} encodes the imm5 shift amount. - unsigned ShImm = slice(insn, 11, 7); - - // A8.4.1. Possible rrx or shift amount of 32... - getImmShiftSE(ShOp, ShImm); - MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShImm))); - } - OpIdx += 3; - - return true; -} - -static bool DisassembleLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded, bool isStore) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - unsigned short NumDefs = TID.getNumDefs(); - bool isPrePost = isPrePostLdSt(TID.TSFlags); - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert((!isStore && NumDefs > 0) || (isStore && (NumDefs == 0 || isPrePost))); - - // Operand 0 of a pre- and post-indexed store is the address base writeback. - if (isPrePost && isStore) { - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - } - - // Disassemble the dst/src operand. - if (OpIdx >= NumOps) - return false; - - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - - // After dst of a pre- and post-indexed load is the address base writeback. - if (isPrePost && !isStore) { - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - } - - // Disassemble the base operand. - if (OpIdx >= NumOps) - return false; - - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - assert(!isPrePost || (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - - // For reg/reg form, base reg is followed by +/- reg shop imm. - // For immediate form, it is followed by +/- imm12. - // See also ARMAddressingModes.h (Addressing Mode #2). - if (OpIdx + 1 >= NumOps) - return false; - - assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) && - (OpInfo[OpIdx+1].RegClass == 0)); - - ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; - if (getIBit(insn) == 0) { - MI.addOperand(MCOperand::CreateReg(0)); - - // Disassemble the 12-bit immediate offset. - unsigned Imm12 = slice(insn, 11, 0); - unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, Imm12, ARM_AM::no_shift); - MI.addOperand(MCOperand::CreateImm(Offset)); - } else { - // Disassemble the offset reg (Rm), shift type, and immediate shift length. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - // Inst{6-5} encodes the shift opcode. - ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); - // Inst{11-7} encodes the imm5 shift amount. - unsigned ShImm = slice(insn, 11, 7); - - // A8.4.1. Possible rrx or shift amount of 32... - getImmShiftSE(ShOp, ShImm); - MI.addOperand(MCOperand::CreateImm( - ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); - } - OpIdx += 2; - - return true; -} - -static bool DisassembleLdFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false); -} - -static bool DisassembleStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true); -} - -static bool HasDualReg(unsigned Opcode) { - switch (Opcode) { - default: - return false; - case ARM::LDRD: case ARM::LDRD_PRE: case ARM::LDRD_POST: - case ARM::STRD: case ARM::STRD_PRE: case ARM::STRD_POST: - return true; - } -} - -static bool DisassembleLdStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded, bool isStore) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - unsigned short NumDefs = TID.getNumDefs(); - bool isPrePost = isPrePostLdSt(TID.TSFlags); - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert((!isStore && NumDefs > 0) || (isStore && (NumDefs == 0 || isPrePost))); - - // Operand 0 of a pre- and post-indexed store is the address base writeback. - if (isPrePost && isStore) { - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - } - - bool DualReg = HasDualReg(Opcode); - - // Disassemble the dst/src operand. - if (OpIdx >= NumOps) - return false; - - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - - // Fill in LDRD and STRD's second operand. - if (DualReg) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn) + 1))); - ++OpIdx; - } - - // After dst of a pre- and post-indexed load is the address base writeback. - if (isPrePost && !isStore) { - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - } - - // Disassemble the base operand. - if (OpIdx >= NumOps) - return false; - - assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - assert(!isPrePost || (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - - // For reg/reg form, base reg is followed by +/- reg. - // For immediate form, it is followed by +/- imm8. - // See also ARMAddressingModes.h (Addressing Mode #3). - if (OpIdx + 1 >= NumOps) - return false; - - assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) && - (OpInfo[OpIdx+1].RegClass == 0)); - - ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; - if (getAM3IBit(insn) == 1) { - MI.addOperand(MCOperand::CreateReg(0)); - - // Disassemble the 8-bit immediate offset. - unsigned Imm4H = (insn >> ARMII::ImmHiShift) & 0xF; - unsigned Imm4L = insn & 0xF; - unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, (Imm4H << 4) | Imm4L); - MI.addOperand(MCOperand::CreateImm(Offset)); - } else { - // Disassemble the offset reg (Rm). - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, 0); - MI.addOperand(MCOperand::CreateImm(Offset)); - } - OpIdx += 2; - - return true; -} - -static bool DisassembleLdMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false); -} - -static bool DisassembleStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true); -} - -// The algorithm for disassembly of LdStMulFrm is different from others because -// it explicitly populates the two predicate operands after operand 0 (the base) -// and operand 1 (the AM4 mode imm). After operand 3, we need to populate the -// reglist with each affected register encoded as an MCOperand. -static bool DisassembleLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps == 5 && "LdStMulFrm expects NumOps of 5"); - - unsigned &OpIdx = NumOpsAdded; - - unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); - MI.addOperand(MCOperand::CreateReg(Base)); - - ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); - bool WB = getWBit(insn) == 1; - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); - - // Handling the two predicate operands before the reglist. - int64_t CondVal = insn >> ARMII::CondShift; - MI.addOperand(MCOperand::CreateImm(CondVal == 0xF ? 0xE : CondVal)); - MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - - OpIdx = 4; - - // Fill the variadic part of reglist. - unsigned RegListBits = insn & ((1 << 16) - 1); - for (unsigned i = 0; i < 16; ++i) { - if ((RegListBits >> i) & 1) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - i))); - ++OpIdx; - } - } - - return true; -} - -// LDREX, LDREXB, LDREXH: Rd Rn -// LDREXD: Rd Rd+1 Rn -// STREX, STREXB, STREXH: Rd Rm Rn -// STREXD: Rd Rm Rm+1 Rn -// -// SWP, SWPB: Rd Rm Rn -static bool DisassembleLdStExFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 - && OpInfo[0].RegClass == ARM::GPRRegClassID - && OpInfo[1].RegClass == ARM::GPRRegClassID); - - bool isStore = slice(insn, 20, 20) == 0; - bool isDW = (Opcode == ARM::LDREXD || Opcode == ARM::STREXD); - - // Add the destination operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - - // Store register Exclusive needs a source operand. - if (isStore) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - ++OpIdx; - - if (isDW) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)+1))); - ++OpIdx; - } - } else if (isDW) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)+1))); - ++OpIdx; - } - - // Finally add the pointer operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - - return true; -} - -// Misc. Arithmetic Instructions. -// CLZ: Rd Rm -// PKHBT, PKHTB: Rd Rn Rm , LSL/ASR #imm5 -// RBIT, REV, REV16, REVSH: Rd Rm -static bool DisassembleArithMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 - && OpInfo[0].RegClass == ARM::GPRRegClassID - && OpInfo[1].RegClass == ARM::GPRRegClassID); - - bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - - if (ThreeReg) { - assert(NumOps >= 4); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - } - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - ++OpIdx; - - // If there is still an operand info left which is an immediate operand, add - // an additional imm5 LSL/ASR operand. - if (ThreeReg && OpInfo[OpIdx].RegClass == 0 - && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { - // Extract the 5-bit immediate field Inst{11-7}. - unsigned ShiftAmt = (insn >> ARMII::ShiftShift) & 0x1F; - MI.addOperand(MCOperand::CreateImm(ShiftAmt)); - ++OpIdx; - } - - return true; -} - -// Extend instructions. -// SXT* and UXT*: Rd [Rn] Rm [rot_imm]. -// The 2nd operand register is Rn and the 3rd operand regsiter is Rm for the -// three register operand form. Otherwise, Rn=0b1111 and only Rm is used. -static bool DisassembleExtFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 - && OpInfo[0].RegClass == ARM::GPRRegClassID - && OpInfo[1].RegClass == ARM::GPRRegClassID); - - bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - - if (ThreeReg) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - } - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - ++OpIdx; - - // If there is still an operand info left which is an immediate operand, add - // an additional rotate immediate operand. - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 - && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { - // Extract the 2-bit rotate field Inst{11-10}. - unsigned rot = (insn >> ARMII::ExtRotImmShift) & 3; - // Rotation by 8, 16, or 24 bits. - MI.addOperand(MCOperand::CreateImm(rot << 3)); - ++OpIdx; - } - - return true; -} - -///////////////////////////////////// -// // -// Utility Functions For VFP // -// // -///////////////////////////////////// - -// Extract/Decode Dd/Sd: -// -// SP => d = UInt(Vd:D) -// DP => d = UInt(D:Vd) -static unsigned decodeVFPRd(uint32_t insn, bool isSPVFP) { - return isSPVFP ? (decodeRd(insn) << 1 | getDBit(insn)) - : (decodeRd(insn) | getDBit(insn) << 4); -} - -// Extract/Decode Dn/Sn: -// -// SP => n = UInt(Vn:N) -// DP => n = UInt(N:Vn) -static unsigned decodeVFPRn(uint32_t insn, bool isSPVFP) { - return isSPVFP ? (decodeRn(insn) << 1 | getNBit(insn)) - : (decodeRn(insn) | getNBit(insn) << 4); -} - -// Extract/Decode Dm/Sm: -// -// SP => m = UInt(Vm:M) -// DP => m = UInt(M:Vm) -static unsigned decodeVFPRm(uint32_t insn, bool isSPVFP) { - return isSPVFP ? (decodeRm(insn) << 1 | getMBit(insn)) - : (decodeRm(insn) | getMBit(insn) << 4); -} - -// A7.5.1 -#if 0 -static uint64_t VFPExpandImm(unsigned char byte, unsigned N) { - assert(N == 32 || N == 64); - - uint64_t Result; - unsigned bit6 = slice(byte, 6, 6); - if (N == 32) { - Result = slice(byte, 7, 7) << 31 | slice(byte, 5, 0) << 19; - if (bit6) - Result |= 0x1f << 25; - else - Result |= 0x1 << 30; - } else { - Result = (uint64_t)slice(byte, 7, 7) << 63 | - (uint64_t)slice(byte, 5, 0) << 48; - if (bit6) - Result |= 0xffL << 54; - else - Result |= 0x1L << 62; - } - return Result; -} -#endif - -// VFP Unary Format Instructions: -// -// VCMP[E]ZD, VCMP[E]ZS: compares one floating-point register with zero -// VCVTDS, VCVTSD: converts between double-precision and single-precision -// The rest of the instructions have homogeneous [VFP]Rd and [VFP]Rm registers. -static bool DisassembleVFPUnaryFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 1 && "VFPUnaryFrm expects NumOps >= 1"); - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - unsigned RegClass = OpInfo[OpIdx].RegClass; - assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID); - bool isSP = (RegClass == ARM::SPRRegClassID); - - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(RegClass, decodeVFPRd(insn, isSP)))); - ++OpIdx; - - // Early return for compare with zero instructions. - if (Opcode == ARM::VCMPEZD || Opcode == ARM::VCMPEZS - || Opcode == ARM::VCMPZD || Opcode == ARM::VCMPZS) - return true; - - RegClass = OpInfo[OpIdx].RegClass; - assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID); - isSP = (RegClass == ARM::SPRRegClassID); - - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(RegClass, decodeVFPRm(insn, isSP)))); - ++OpIdx; - - return true; -} - -// All the instructions have homogeneous [VFP]Rd, [VFP]Rn, and [VFP]Rm regs. -// Some of them have operand constraints which tie the first operand in the -// InOperandList to that of the dst. As far as asm printing is concerned, this -// tied_to operand is simply skipped. -static bool DisassembleVFPBinaryFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 3 && "VFPBinaryFrm expects NumOps >= 3"); - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - unsigned RegClass = OpInfo[OpIdx].RegClass; - assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID); - bool isSP = (RegClass == ARM::SPRRegClassID); - - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(RegClass, decodeVFPRd(insn, isSP)))); - ++OpIdx; - - // Skip tied_to operand constraint. - if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { - assert(NumOps >= 4); - MI.addOperand(MCOperand::CreateReg(0)); - ++OpIdx; - } - - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(RegClass, decodeVFPRn(insn, isSP)))); - ++OpIdx; - - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(RegClass, decodeVFPRm(insn, isSP)))); - ++OpIdx; - - return true; -} - -// A8.6.295 vcvt (floating-point <-> integer) -// Int to FP: VSITOD, VSITOS, VUITOD, VUITOS -// FP to Int: VTOSI[Z|R]D, VTOSI[Z|R]S, VTOUI[Z|R]D, VTOUI[Z|R]S -// -// A8.6.297 vcvt (floating-point and fixed-point) -// Dd|Sd Dd|Sd(TIED_TO) #fbits(= 16|32 - UInt(imm4:i)) -static bool DisassembleVFPConv1Frm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 2 && "VFPConv1Frm expects NumOps >= 2"); - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - - bool SP = slice(insn, 8, 8) == 0; // A8.6.295 & A8.6.297 - bool fixed_point = slice(insn, 17, 17) == 1; // A8.6.297 - unsigned RegClassID = SP ? ARM::SPRRegClassID : ARM::DPRRegClassID; - - if (fixed_point) { - // A8.6.297 - assert(NumOps >= 3); - int size = slice(insn, 7, 7) == 0 ? 16 : 32; - int fbits = size - (slice(insn,3,0) << 1 | slice(insn,5,5)); - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(RegClassID, - decodeVFPRd(insn, SP)))); - - assert(TID.getOperandConstraint(1, TOI::TIED_TO) != -1); - MI.addOperand(MI.getOperand(0)); - - assert(OpInfo[2].RegClass == 0 && !OpInfo[2].isPredicate() && - !OpInfo[2].isOptionalDef()); - MI.addOperand(MCOperand::CreateImm(fbits)); - - NumOpsAdded = 3; - } else { - // A8.6.295 - // The Rd (destination) and Rm (source) bits have different interpretations - // depending on their single-precisonness. - unsigned d, m; - if (slice(insn, 18, 18) == 1) { // to_integer operation - d = decodeVFPRd(insn, true /* Is Single Precision */); - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::SPRRegClassID, d))); - m = decodeVFPRm(insn, SP); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, m))); - } else { - d = decodeVFPRd(insn, SP); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, d))); - m = decodeVFPRm(insn, true /* Is Single Precision */); - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::SPRRegClassID, m))); - } - NumOpsAdded = 2; - } - - return true; -} - -// VMOVRS - A8.6.330 -// Rt => Rd; Sn => UInt(Vn:N) -static bool DisassembleVFPConv2Frm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 2 && "VFPConv2Frm expects NumOps >= 2"); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, - decodeVFPRn(insn, true)))); - NumOpsAdded = 2; - return true; -} - -// VMOVRRD - A8.6.332 -// Rt => Rd; Rt2 => Rn; Dm => UInt(M:Vm) -// -// VMOVRRS - A8.6.331 -// Rt => Rd; Rt2 => Rn; Sm => UInt(Vm:M); Sm1 = Sm+1 -static bool DisassembleVFPConv3Frm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 3 && "VFPConv3Frm expects NumOps >= 3"); - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - OpIdx = 2; - - if (OpInfo[OpIdx].RegClass == ARM::SPRRegClassID) { - unsigned Sm = decodeVFPRm(insn, true); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, - Sm))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, - Sm+1))); - OpIdx += 2; - } else { - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::DPRRegClassID, - decodeVFPRm(insn, false)))); - ++OpIdx; - } - return true; -} - -// VMOVSR - A8.6.330 -// Rt => Rd; Sn => UInt(Vn:N) -static bool DisassembleVFPConv4Frm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 2 && "VFPConv4Frm expects NumOps >= 2"); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, - decodeVFPRn(insn, true)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - NumOpsAdded = 2; - return true; -} - -// VMOVDRR - A8.6.332 -// Rt => Rd; Rt2 => Rn; Dm => UInt(M:Vm) -// -// VMOVRRS - A8.6.331 -// Rt => Rd; Rt2 => Rn; Sm => UInt(Vm:M); Sm1 = Sm+1 -static bool DisassembleVFPConv5Frm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 3 && "VFPConv5Frm expects NumOps >= 3"); - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - if (OpInfo[OpIdx].RegClass == ARM::SPRRegClassID) { - unsigned Sm = decodeVFPRm(insn, true); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, - Sm))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, - Sm+1))); - OpIdx += 2; - } else { - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::DPRRegClassID, - decodeVFPRm(insn, false)))); - ++OpIdx; - } - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - OpIdx += 2; - return true; -} - -// VFP Load/Store Instructions. -// VLDRD, VLDRS, VSTRD, VSTRS -static bool DisassembleVFPLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 3 && "VFPLdStFrm expects NumOps >= 3"); - - bool isSPVFP = (Opcode == ARM::VLDRS || Opcode == ARM::VSTRS) ? true : false; - unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID; - - // Extract Dd/Sd for operand 0. - unsigned RegD = decodeVFPRd(insn, isSPVFP); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, RegD))); - - unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); - MI.addOperand(MCOperand::CreateReg(Base)); - - // Next comes the AM5 Opcode. - ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; - unsigned char Imm8 = insn & 0xFF; - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(AddrOpcode, Imm8))); - - NumOpsAdded = 3; - - return true; -} - -// VFP Load/Store Multiple Instructions. -// This is similar to the algorithm for LDM/STM in that operand 0 (the base) and -// operand 1 (the AM5 mode imm) is followed by two predicate operands. It is -// followed by a reglist of either DPR(s) or SPR(s). -// -// VLDMD, VLDMS, VSTMD, VSTMS -static bool DisassembleVFPLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps == 5 && "VFPLdStMulFrm expects NumOps of 5"); - - unsigned &OpIdx = NumOpsAdded; - - unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); - MI.addOperand(MCOperand::CreateReg(Base)); - - // Next comes the AM5 Opcode. - ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); - bool WB = getWBit(insn) == 1; - unsigned char Imm8 = insn & 0xFF; - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(SubMode, WB, Imm8))); - - // Handling the two predicate operands before the reglist. - int64_t CondVal = insn >> ARMII::CondShift; - MI.addOperand(MCOperand::CreateImm(CondVal == 0xF ? 0xE : CondVal)); - MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - - OpIdx = 4; - - bool isSPVFP = (Opcode == ARM::VLDMS || Opcode == ARM::VSTMS) ? true : false; - unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID; - - // Extract Dd/Sd. - unsigned RegD = decodeVFPRd(insn, isSPVFP); - - // Fill the variadic part of reglist. - unsigned Regs = isSPVFP ? Imm8 : Imm8/2; - for (unsigned i = 0; i < Regs; ++i) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, - RegD + i))); - ++OpIdx; - } - - return true; -} - -// Misc. VFP Instructions. -// FMSTAT (vmrs with Rt=0b1111, i.e., to apsr_nzcv and no register operand) -// FCONSTD (DPR and a VFPf64Imm operand) -// FCONSTS (SPR and a VFPf32Imm operand) -// VMRS/VMSR (GPR operand) -static bool DisassembleVFPMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - if (Opcode == ARM::FMSTAT) - return true; - - assert(NumOps >= 2); - - unsigned RegEnum = 0; - switch (OpInfo[0].RegClass) { - case ARM::DPRRegClassID: - RegEnum = getRegisterEnum(ARM::DPRRegClassID, decodeVFPRd(insn, false)); - break; - case ARM::SPRRegClassID: - RegEnum = getRegisterEnum(ARM::SPRRegClassID, decodeVFPRd(insn, true)); - break; - case ARM::GPRRegClassID: - RegEnum = getRegisterEnum(ARM::GPRRegClassID, decodeRd(insn)); - break; - default: - llvm_unreachable("Invalid reg class id"); - } - - MI.addOperand(MCOperand::CreateReg(RegEnum)); - ++OpIdx; - - // Extract/decode the f64/f32 immediate. - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 - && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { - // The asm syntax specifies the before-expanded <imm>. - // Not VFPExpandImm(slice(insn,19,16) << 4 | slice(insn, 3, 0), - // Opcode == ARM::FCONSTD ? 64 : 32) - MI.addOperand(MCOperand::CreateImm(slice(insn,19,16)<<4 | slice(insn,3,0))); - ++OpIdx; - } - - return true; -} - -// DisassembleThumbFrm() is defined in ThumbDisassemblerCore.cpp.inc file. -#include "ThumbDisassemblerCore.cpp.inc" - -///////////////////////////////////////////////////// -// // -// Utility Functions For ARM Advanced SIMD // -// // -///////////////////////////////////////////////////// - -// The following NEON namings are based on A8.6.266 VABA, VABAL. Notice that -// A8.6.303 VDUP (ARM core register)'s D/Vd pair is the N/Vn pair of VABA/VABAL. - -// A7.3 Register encoding - -// Extract/Decode NEON D/Vd: -// -// Note that for quadword, Qd = UInt(D:Vd<3:1>) = Inst{22:15-13}, whereas for -// doubleword, Dd = UInt(D:Vd). We compensate for this difference by -// handling it in the getRegisterEnum() utility function. -// D = Inst{22}, Vd = Inst{15-12} -static unsigned decodeNEONRd(uint32_t insn) { - return ((insn >> ARMII::NEON_D_BitShift) & 1) << 4 - | (insn >> ARMII::NEON_RegRdShift) & ARMII::NEONRegMask; -} - -// Extract/Decode NEON N/Vn: -// -// Note that for quadword, Qn = UInt(N:Vn<3:1>) = Inst{7:19-17}, whereas for -// doubleword, Dn = UInt(N:Vn). We compensate for this difference by -// handling it in the getRegisterEnum() utility function. -// N = Inst{7}, Vn = Inst{19-16} -static unsigned decodeNEONRn(uint32_t insn) { - return ((insn >> ARMII::NEON_N_BitShift) & 1) << 4 - | (insn >> ARMII::NEON_RegRnShift) & ARMII::NEONRegMask; -} - -// Extract/Decode NEON M/Vm: -// -// Note that for quadword, Qm = UInt(M:Vm<3:1>) = Inst{5:3-1}, whereas for -// doubleword, Dm = UInt(M:Vm). We compensate for this difference by -// handling it in the getRegisterEnum() utility function. -// M = Inst{5}, Vm = Inst{3-0} -static unsigned decodeNEONRm(uint32_t insn) { - return ((insn >> ARMII::NEON_M_BitShift) & 1) << 4 - | (insn >> ARMII::NEON_RegRmShift) & ARMII::NEONRegMask; -} - -namespace { -enum ElemSize { - ESizeNA = 0, - ESize8 = 8, - ESize16 = 16, - ESize32 = 32, - ESize64 = 64 -}; -} // End of unnamed namespace - -// size field -> Inst{11-10} -// index_align field -> Inst{7-4} -// -// The Lane Index interpretation depends on the Data Size: -// 8 (encoded as size = 0b00) -> Index = index_align[3:1] -// 16 (encoded as size = 0b01) -> Index = index_align[3:2] -// 32 (encoded as size = 0b10) -> Index = index_align[3] -// -// Ref: A8.6.317 VLD4 (single 4-element structure to one lane). -static unsigned decodeLaneIndex(uint32_t insn) { - unsigned size = insn >> 10 & 3; - assert(size == 0 || size == 1 || size == 2); - - unsigned index_align = insn >> 4 & 0xF; - return (index_align >> 1) >> size; -} - -// imm64 = AdvSIMDExpandImm(op, cmode, i:imm3:imm4) -// op = Inst{5}, cmode = Inst{11-8} -// i = Inst{24} (ARM architecture) -// imm3 = Inst{18-16}, imm4 = Inst{3-0} -// Ref: Table A7-15 Modified immediate values for Advanced SIMD instructions. -static uint64_t decodeN1VImm(uint32_t insn, ElemSize esize) { - unsigned char cmode = (insn >> 8) & 0xF; - unsigned char Imm8 = ((insn >> 24) & 1) << 7 | - ((insn >> 16) & 7) << 4 | - (insn & 0xF); - uint64_t Imm64 = 0; - - switch (esize) { - case ESize8: - Imm64 = Imm8; - break; - case ESize16: - Imm64 = Imm8 << 8*(cmode >> 1 & 1); - break; - case ESize32: { - if (cmode == 12) - Imm64 = (Imm8 << 8) | 0xFF; - else if (cmode == 13) - Imm64 = (Imm8 << 16) | 0xFFFF; - else { - // Imm8 to be shifted left by how many bytes... - Imm64 = Imm8 << 8*(cmode >> 1 & 3); - } - break; - } - case ESize64: { - for (unsigned i = 0; i < 8; ++i) - if ((Imm8 >> i) & 1) - Imm64 |= 0xFF << 8*i; - break; - } - default: - assert(0 && "Unreachable code!"); - return 0; - } - - return Imm64; -} - -// A8.6.339 VMUL, VMULL (by scalar) -// ESize16 => m = Inst{2-0} (Vm<2:0>) D0-D7 -// ESize32 => m = Inst{3-0} (Vm<3:0>) D0-D15 -static unsigned decodeRestrictedDm(uint32_t insn, ElemSize esize) { - switch (esize) { - case ESize16: - return insn & 7; - case ESize32: - return insn & 0xF; - default: - assert(0 && "Unreachable code!"); - return 0; - } -} - -// A8.6.339 VMUL, VMULL (by scalar) -// ESize16 => index = Inst{5:3} (M:Vm<3>) D0-D7 -// ESize32 => index = Inst{5} (M) D0-D15 -static unsigned decodeRestrictedDmIndex(uint32_t insn, ElemSize esize) { - switch (esize) { - case ESize16: - return (((insn >> 5) & 1) << 1) | ((insn >> 3) & 1); - case ESize32: - return (insn >> 5) & 1; - default: - assert(0 && "Unreachable code!"); - return 0; - } -} - -// A8.6.296 VCVT (between floating-point and fixed-point, Advanced SIMD) -// (64 - <fbits>) is encoded as imm6, i.e., Inst{21-16}. -static unsigned decodeVCVTFractionBits(uint32_t insn) { - return 64 - ((insn >> 16) & 0x3F); -} - -// A8.6.302 VDUP (scalar) -// ESize8 => index = Inst{19-17} -// ESize16 => index = Inst{19-18} -// ESize32 => index = Inst{19} -static unsigned decodeNVLaneDupIndex(uint32_t insn, ElemSize esize) { - switch (esize) { - case ESize8: - return (insn >> 17) & 7; - case ESize16: - return (insn >> 18) & 3; - case ESize32: - return (insn >> 19) & 1; - default: - assert(0 && "Unspecified element size!"); - return 0; - } -} - -// A8.6.328 VMOV (ARM core register to scalar) -// A8.6.329 VMOV (scalar to ARM core register) -// ESize8 => index = Inst{21:6-5} -// ESize16 => index = Inst{21:6} -// ESize32 => index = Inst{21} -static unsigned decodeNVLaneOpIndex(uint32_t insn, ElemSize esize) { - switch (esize) { - case ESize8: - return ((insn >> 21) & 1) << 2 | ((insn >> 5) & 3); - case ESize16: - return ((insn >> 21) & 1) << 1 | ((insn >> 6) & 1); - case ESize32: - return ((insn >> 21) & 1); - default: - assert(0 && "Unspecified element size!"); - return 0; - } -} - -// Imm6 = Inst{21-16}, L = Inst{7} -// -// NormalShift == true (A8.6.376 VRSHR, A8.6.368 VQSHRN): -// case L:imm6 of -// '0001xxx' => esize = 8; shift_amount = 16 - imm6 -// '001xxxx' => esize = 16; shift_amount = 32 - imm6 -// '01xxxxx' => esize = 32; shift_amount = 64 - imm6 -// '1xxxxxx' => esize = 64; shift_amount = 64 - imm6 -// -// NormalShift == false (A8.6.367 VQSHL, A8.6.387 VSLI): -// case L:imm6 of -// '0001xxx' => esize = 8; shift_amount = imm6 - 8 -// '001xxxx' => esize = 16; shift_amount = imm6 - 16 -// '01xxxxx' => esize = 32; shift_amount = imm6 - 32 -// '1xxxxxx' => esize = 64; shift_amount = imm6 -// -static unsigned decodeNVSAmt(uint32_t insn, bool NormalShift) { - ElemSize esize = ESizeNA; - unsigned L = (insn >> 7) & 1; - unsigned imm6 = (insn >> 16) & 0x3F; - if (L == 0) { - if (imm6 >> 3 == 1) - esize = ESize8; - else if (imm6 >> 4 == 1) - esize = ESize16; - else if (imm6 >> 5 == 1) - esize = ESize32; - else - assert(0 && "Wrong encoding of Inst{7:21-16}!"); - } else - esize = ESize64; - - if (NormalShift) - return esize == ESize64 ? (esize - imm6) : (2*esize - imm6); - else - return esize == ESize64 ? imm6 : (imm6 - esize); -} - -// A8.6.305 VEXT -// Imm4 = Inst{11-8} -static unsigned decodeN3VImm(uint32_t insn) { - return (insn >> 8) & 0xF; -} - -static bool DisassembleNSFormatNone(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - assert(0 && "Unexpected NEON Sub-Format of NSFormatNone"); - return false; -} - -// VLD* -// D[d] D[d2] ... R[addr] [TIED_TO] R[update] AM6 align(ignored) -// VLD*LN* -// D[d] D[d2] ... R[addr] R[update] AM6 align(ignored) TIED_TO ... imm(idx) -// VST* -// R[addr] [TIED_TO] R[update] AM6 align(ignored) D[d] D[d2] ... -// VST*LN* -// R[addr] R[update] AM6 align(ignored) D[d] D[d2] ... [imm(idx)] -// -// Correctly set VLD*/VST*'s TIED_TO GPR, as the asm printer needs it. -static bool DisassembleVLDSTLane0(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded, bool Store, bool DblSpaced) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - - // At least one DPR register plus addressing mode #6. - assert(NumOps >= 5); - - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - // We have homogeneous NEON registers for Load/Store. - unsigned RegClass = 0; - - // Double-spaced registers have increments of 2. - unsigned Inc = DblSpaced ? 2 : 1; - - unsigned Rn = decodeRn(insn); - unsigned Rm = decodeRm(insn); - unsigned Rd = decodeNEONRd(insn); - - // A7.7.1 Advanced SIMD addressing mode. - bool WB = Rm != 15; - - // LLVM Addressing Mode #6. - unsigned RmEnum = 0; - if (WB && Rm != 13) - RmEnum = getRegisterEnum(ARM::GPRRegClassID, Rm); - - if (Store) { - // Consume AddrMode6 (possible TIED_TO Rn), the DPR/QPR's, then possible - // lane index. - assert(OpIdx < NumOps && OpInfo[0].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - Rn))); - ++OpIdx; - if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { - // TIED_TO operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - Rn))); - ++OpIdx; - } - - assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(RmEnum)); - ++OpIdx; - assert(OpIdx < NumOps && - OpInfo[OpIdx].RegClass == 0 && OpInfo[OpIdx+1].RegClass == 0); - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM6Opc(WB))); - MI.addOperand(MCOperand::CreateImm(0)); // Alignment ignored? - OpIdx += 2; - - assert(OpIdx < NumOps && - (OpInfo[OpIdx].RegClass == ARM::DPRRegClassID || - OpInfo[OpIdx].RegClass == ARM::QPRRegClassID)); - - RegClass = OpInfo[OpIdx].RegClass; - while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) { - if (Opcode >= ARM::VST1q16 && Opcode <= ARM::VST1q8) - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd,true))); - else - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd))); - Rd += Inc; - ++OpIdx; - } - - // Handle possible lane index. - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 - && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { - MI.addOperand(MCOperand::CreateImm(decodeLaneIndex(insn))); - ++OpIdx; - } - - } else { - // Consume the DPR/QPR's, AddrMode6 (possible TIED_TO Rn), possible TIED_TO - // DPR/QPR's (ignored), then possible lane index. - RegClass = OpInfo[0].RegClass; - - while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) { - if (Opcode >= ARM::VLD1q16 && Opcode <= ARM::VLD1q8) - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd,true))); - else - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd))); - Rd += Inc; - ++OpIdx; - } - - assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - Rn))); - ++OpIdx; - if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { - // TIED_TO operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - Rn))); - ++OpIdx; - } - - assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); - MI.addOperand(MCOperand::CreateReg(RmEnum)); - ++OpIdx; - assert(OpIdx < NumOps && - OpInfo[OpIdx].RegClass == 0 && OpInfo[OpIdx+1].RegClass == 0); - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM6Opc(WB))); - MI.addOperand(MCOperand::CreateImm(0)); // Alignment ignored? - OpIdx += 2; - - while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) { - assert(TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1); - MI.addOperand(MCOperand::CreateReg(0)); - ++OpIdx; - } - - // Handle possible lane index. - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 - && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { - MI.addOperand(MCOperand::CreateImm(decodeLaneIndex(insn))); - ++OpIdx; - } - } - - return true; -} - -// A7.7 -// If L (Inst{21}) == 0, store instructions. -// DblSpaced = false. -static bool DisassembleVLDSTLane(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleVLDSTLane0(MI, Opcode, insn, NumOps, NumOpsAdded, - slice(insn, 21, 21) == 0, false); -} -// A7.7 -// If L (Inst{21}) == 0, store instructions. -// DblSpaced = true. -static bool DisassembleVLDSTLaneDbl(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleVLDSTLane0(MI, Opcode, insn, NumOps, NumOpsAdded, - slice(insn, 21, 21) == 0, true); -} - -// VLDRQ (vldmia), VSTRQ (vstmia) -// Qd Rn imm (AM4) -static bool DisassembleVLDSTRQ(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 3 && - OpInfo[0].RegClass == ARM::QPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID && - OpInfo[2].RegClass == 0); - - // Qd = Inst{22:15-12} => NEON Rd - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::QPRRegClassID, - decodeNEONRd(insn), true))); - - // Rn = Inst{19-16} => ARM Rn - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - - // Next comes the AM4 Opcode. - assert(Opcode == ARM::VLDRQ || Opcode == ARM::VSTRQ); - ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); - bool WB = getWBit(insn) == 1; - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); - - NumOpsAdded = 3; - return true; -} - -// VMOV (immediate) -// Qd/Dd imm -static bool DisassembleNVdImm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - - assert(NumOps >= 2 && - (OpInfo[0].RegClass == ARM::DPRRegClassID || - OpInfo[0].RegClass == ARM::QPRRegClassID) && - (OpInfo[1].RegClass == 0)); - - // Qd/Dd = Inst{22:15-12} => NEON Rd - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[0].RegClass, - decodeNEONRd(insn)))); - - ElemSize esize = ESizeNA; - switch (Opcode) { - case ARM::VMOVv8i8: - case ARM::VMOVv16i8: - esize = ESize8; - break; - case ARM::VMOVv4i16: - case ARM::VMOVv8i16: - esize = ESize16; - break; - case ARM::VMOVv2i32: - case ARM::VMOVv4i32: - esize = ESize32; - break; - case ARM::VMOVv1i64: - case ARM::VMOVv2i64: - esize = ESize64; - default: - assert(0 && "Unreachable code!"); - return false; - } - - // One register and a modified immediate value. - // Add the imm operand. - MI.addOperand(MCOperand::CreateImm(decodeN1VImm(insn, esize))); - - NumOpsAdded = 2; - return true; -} - -namespace { -enum N2VFlag { - N2V_None, - N2V_VectorDupLane, - N2V_VectorShiftLeftLong, - N2V_VectorConvert_Between_Float_Fixed -}; -} // End of unnamed namespace - -// Vector Convert [between floating-point and fixed-point] -// Qd/Dd Qm/Dm [fbits] -// -// Vector Duplicate Lane (from scalar to all elements) Instructions. -// VDUPLN16d, VDUPLN16q, VDUPLN32d, VDUPLN32q, VDUPLN8d, VDUPLN8q: -// Qd/Dd Dm index -// -// Vector Shift Left Long (with maximum shift count) Instructions. -// VSHLLi16, VSHLLi32, VSHLLi8: Qd Dm imm (== size) -// -// Vector Move Long: -// Qd Dm -// -// Vector Move Narrow: -// Dd Qm -// -// Others -static bool DisassembleNVdVmImm0(MCInst &MI, unsigned Opc, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded, N2VFlag Flag = N2V_None) { - - const TargetInstrDesc &TID = ARMInsts[Opc]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - - assert(NumOps >= 2 && - (OpInfo[0].RegClass == ARM::DPRRegClassID || - OpInfo[0].RegClass == ARM::QPRRegClassID) && - (OpInfo[1].RegClass == ARM::DPRRegClassID || - OpInfo[1].RegClass == ARM::QPRRegClassID)); - - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - ElemSize esize = ESizeNA; - if (Flag == N2V_VectorShiftLeftLong) { - // VSHLL has maximum shift count as the imm, inferred from its size. - assert(Opc == ARM::VSHLLi16 || Opc == ARM::VSHLLi32 || Opc == ARM::VSHLLi8); - esize = Opc == ARM::VSHLLi8 ? ESize8 - : (Opc == ARM::VSHLLi16 ? ESize16 - : ESize32); - } - if (Flag == N2V_VectorDupLane) { - // VDUPLN has its index embedded. Its size can be inferred from the Opcode. - assert(Opc >= ARM::VDUPLN16d && Opc <= ARM::VDUPLN8q); - esize = (Opc == ARM::VDUPLN8d || Opc == ARM::VDUPLN8q) ? ESize8 - : ((Opc == ARM::VDUPLN16d || Opc == ARM::VDUPLN16q) ? ESize16 - : ESize32); - } - - // Qd/Dd = Inst{22:15-12} => NEON Rd - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, - decodeNEONRd(insn)))); - ++OpIdx; - - // VPADAL... - if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { - // TIED_TO operand. - MI.addOperand(MCOperand::CreateReg(0)); - ++OpIdx; - } - - // Dm = Inst{5:3-0} => NEON Rm - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, - decodeNEONRm(insn)))); - ++OpIdx; - - // Add the imm operand, if required. - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 - && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { - - unsigned imm = 0xFFFFFFFF; - - if (Flag == N2V_VectorShiftLeftLong) - imm = static_cast<unsigned>(esize); - if (Flag == N2V_VectorDupLane) - imm = decodeNVLaneDupIndex(insn, esize); - if (Flag == N2V_VectorConvert_Between_Float_Fixed) - imm = decodeVCVTFractionBits(insn); - - assert(imm != 0xFFFFFFFF); - MI.addOperand(MCOperand::CreateImm(imm)); - ++OpIdx; - } - - return true; -} - -static bool DisassembleNVdVmImm(MCInst &MI, unsigned Opc, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded); -} -static bool DisassembleNVdVmImmVCVT(MCInst &MI, unsigned Opc, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded, - N2V_VectorConvert_Between_Float_Fixed); -} -static bool DisassembleNVdVmImmVDupLane(MCInst &MI, unsigned Opc, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded, - N2V_VectorDupLane); -} -static bool DisassembleNVdVmImmVSHLL(MCInst &MI, unsigned Opc, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded, - N2V_VectorShiftLeftLong); -} - -// Vector Transpose/Unzip/Zip Instructions -// Qd/Dd Qm/Dm [Qd/Dd (TIED_TO)] [Qm/Dm (TIED_TO)] -static bool DisassembleNVectorShuffle(MCInst &MI,unsigned Opcode,uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - - assert(NumOps >= 4 && - (OpInfo[0].RegClass == ARM::DPRRegClassID || - OpInfo[0].RegClass == ARM::QPRRegClassID) && - (OpInfo[1].RegClass == ARM::DPRRegClassID || - OpInfo[1].RegClass == ARM::QPRRegClassID) && - (OpInfo[2].RegClass == ARM::DPRRegClassID || - OpInfo[2].RegClass == ARM::QPRRegClassID) && - (OpInfo[3].RegClass == ARM::DPRRegClassID || - OpInfo[3].RegClass == ARM::QPRRegClassID)); - - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - // Qd/Dd = Inst{22:15-12} => NEON Rd - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, - decodeNEONRd(insn)))); - ++OpIdx; - - // Dm = Inst{5:3-0} => NEON Rm - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, - decodeNEONRm(insn)))); - ++OpIdx; - - assert(TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1 && - TID.getOperandConstraint(OpIdx+1, TOI::TIED_TO) != -1); - - MI.addOperand(MCOperand::CreateReg(0)); ++OpIdx; - MI.addOperand(MCOperand::CreateReg(0)); ++OpIdx; - - return true; -} - -// Vector Shift [Accumulate] Instructions. -// Qd/Dd [Qd/Dd (TIED_TO)] Qm/Dm ShiftAmt -static bool DisassembleNVectorShift0(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded, bool NormalShift = true) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - - assert(NumOps >= 3 && - (OpInfo[0].RegClass == ARM::DPRRegClassID || - OpInfo[0].RegClass == ARM::QPRRegClassID) && - (OpInfo[1].RegClass == ARM::DPRRegClassID || - OpInfo[1].RegClass == ARM::QPRRegClassID)); - - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - // Qd/Dd = Inst{22:15-12} => NEON Rd - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, - decodeNEONRd(insn)))); - ++OpIdx; - - if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { - // TIED_TO operand. - MI.addOperand(MCOperand::CreateReg(0)); - ++OpIdx; - } - - assert(OpInfo[OpIdx].RegClass == ARM::DPRRegClassID || - OpInfo[OpIdx].RegClass == ARM::QPRRegClassID); - - // Qm/Dm = Inst{5:3-0} => NEON Rm - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, - decodeNEONRm(insn)))); - ++OpIdx; - - assert(OpInfo[OpIdx].RegClass == 0); - - // Add the imm operand. - MI.addOperand(MCOperand::CreateImm(decodeNVSAmt(insn, NormalShift))); - ++OpIdx; - - return true; -} - -// Normal shift amount interpretation. -static bool DisassembleNVectorShift(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVectorShift0(MI, Opcode, insn, NumOps, NumOpsAdded, true); -} -// Different shift amount interpretation. -static bool DisassembleNVectorShift2(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVectorShift0(MI, Opcode, insn, NumOps, NumOpsAdded, false); -} - -namespace { -enum N3VFlag { - N3V_None, - N3V_VectorExtract, - N3V_VectorShift, - N3V_Multiply_By_Scalar -}; -} // End of unnamed namespace - -// NEON Three Register Instructions with Optional Immediate Operand -// -// Vector Extract Instructions. -// Qd/Dd Qn/Dn Qm/Dm imm4 -// -// Vector Shift (Register) Instructions. -// Qd/Dd Qm/Dm Qn/Dn (notice the order of m, n) -// -// Vector Multiply [Accumulate/Subtract] [Long] By Scalar Instructions. -// Qd/Dd Qn/Dn RestrictedDm index -// -// Others -static bool DisassembleNVdVnVmImm0(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded, N3VFlag Flag = N3V_None) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - - assert(NumOps >= 3 && - (OpInfo[0].RegClass == ARM::DPRRegClassID || - OpInfo[0].RegClass == ARM::QPRRegClassID) && - (OpInfo[1].RegClass == ARM::DPRRegClassID || - OpInfo[1].RegClass == ARM::QPRRegClassID) && - (OpInfo[2].RegClass != 0)); - - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - bool VdVnVm = Flag == N3V_VectorShift ? false : true; - bool IsImm4 = Flag == N3V_VectorExtract ? true : false; - bool IsDmRestricted = Flag == N3V_Multiply_By_Scalar ? true : false; - ElemSize esize = ESizeNA; - if (Flag == N3V_Multiply_By_Scalar) { - unsigned size = (insn >> 20) & 3; - if (size == 1) esize = ESize16; - if (size == 2) esize = ESize32; - assert (esize == ESize16 || esize == ESize32); - } - - // Qd/Dd = Inst{22:15-12} => NEON Rd - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, - decodeNEONRd(insn)))); - ++OpIdx; - - // VABA, VABAL, VBSLd, VBSLq, ... - if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { - // TIED_TO operand. - MI.addOperand(MCOperand::CreateReg(0)); - ++OpIdx; - } - - // Dn = Inst{7:19-16} => NEON Rn - // or - // Dm = Inst{5:3-0} => NEON Rm - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(OpInfo[OpIdx].RegClass, - VdVnVm ? decodeNEONRn(insn) - : decodeNEONRm(insn)))); - ++OpIdx; - - // Dm = Inst{5:3-0} => NEON Rm - // or - // Dm is restricted to D0-D7 if size is 16, D0-D15 otherwise - // or - // Dn = Inst{7:19-16} => NEON Rn - unsigned m = VdVnVm ? (IsDmRestricted ? decodeRestrictedDm(insn, esize) - : decodeNEONRm(insn)) - : decodeNEONRn(insn); - - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(OpInfo[OpIdx].RegClass, m))); - ++OpIdx; - - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 - && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { - // Add the imm operand. - unsigned Imm = 0; - if (IsImm4) - Imm = decodeN3VImm(insn); - else if (IsDmRestricted) - Imm = decodeRestrictedDmIndex(insn, esize); - else - assert(0 && "Internal error: unreachable code!"); - - MI.addOperand(MCOperand::CreateImm(Imm)); - ++OpIdx; - } - - return true; -} - -static bool DisassembleNVdVnVmImm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded); -} -static bool DisassembleNVdVnVmImmVectorShift(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded, - N3V_VectorShift); -} -static bool DisassembleNVdVnVmImmVectorExtract(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded, - N3V_VectorExtract); -} -static bool DisassembleNVdVnVmImmMulScalar(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded, - N3V_Multiply_By_Scalar); -} - -// Vector Table Lookup -// -// VTBL1, VTBX1: Dd [Dd(TIED_TO)] Dn Dm -// VTBL2, VTBX2: Dd [Dd(TIED_TO)] Dn Dn+1 Dm -// VTBL3, VTBX3: Dd [Dd(TIED_TO)] Dn Dn+1 Dn+2 Dm -// VTBL4, VTBX4: Dd [Dd(TIED_TO)] Dn Dn+1 Dn+2 Dn+3 Dm -static bool DisassembleVTBL(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - - assert(NumOps >= 3 && - OpInfo[0].RegClass == ARM::DPRRegClassID && - OpInfo[1].RegClass == ARM::DPRRegClassID && - OpInfo[2].RegClass == ARM::DPRRegClassID); - - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - unsigned Rn = decodeNEONRn(insn); - - // {Dn} encoded as len = 0b00 - // {Dn Dn+1} encoded as len = 0b01 - // {Dn Dn+1 Dn+2 } encoded as len = 0b10 - // {Dn Dn+1 Dn+2 Dn+3} encoded as len = 0b11 - unsigned Len = slice(insn, 9, 8) + 1; - - // Dd (the destination vector) - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, - decodeNEONRd(insn)))); - ++OpIdx; - - // Process tied_to operand constraint. - int Idx; - if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { - MI.addOperand(MI.getOperand(Idx)); - ++OpIdx; - } - - // Do the <list> now. - for (unsigned i = 0; i < Len; ++i) { - assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::DPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, - Rn + i))); - ++OpIdx; - } - - // Dm (the index vector) - assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::DPRRegClassID); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, - decodeNEONRm(insn)))); - ++OpIdx; - - return true; -} - -/// NEONFuncPtrs - NEONFuncPtrs maps NSFormat to corresponding DisassembleFP. -/// We divide the disassembly task into different categories, with each one -/// corresponding to a specific instruction encoding format. There could be -/// exceptions when handling a specific format, and that is why the Opcode is -/// also present in the function prototype. -static const DisassembleFP NEONFuncPtrs[] = { - // This will assert(). - &DisassembleNSFormatNone, - - // VLD and VST (including one lane) Instructions. - &DisassembleVLDSTLane, - - // VLD and VST (including one lane) Double-Spaced Instructions. - &DisassembleVLDSTLaneDbl, - - // A8.6.319 VLDM & A8.6.399 VSTM - // LLVM defines VLDRQ/VSTRQ to load/store a Q register as a D register pair. - &DisassembleVLDSTRQ, - - // A7.4.6 One register and a modified immediate value - // 1-Register Instructions with imm. - // LLVM only defines VMOVv instructions. - &DisassembleNVdImm, - - // 2-Register Instructions with no imm. - &DisassembleNVdVmImm, - - // 2-Register Instructions with imm (vector convert float/fixed point). - &DisassembleNVdVmImmVCVT, - - // 2-Register Instructions with imm (vector dup lane). - &DisassembleNVdVmImmVDupLane, - - // 2-Register Instructions with imm (vector shift left long). - &DisassembleNVdVmImmVSHLL, - - // Vector Transpose/Unzip/Zip Instructions. - &DisassembleNVectorShuffle, - - // Vector Shift [Narrow Accumulate] Instructions. - &DisassembleNVectorShift, - - // Vector Shift Instructions with different interpretation of shift amount. - &DisassembleNVectorShift2, - - // 3-Register Data-Processing Instructions. - &DisassembleNVdVnVmImm, - - // Vector Shift (Register) Instructions. - // D:Vd M:Vm N:Vn (notice that M:Vm is the first operand) - &DisassembleNVdVnVmImmVectorShift, - - // Vector Extract Instructions. - &DisassembleNVdVnVmImmVectorExtract, - - // Vector [Saturating Rounding Doubling] Multiply [Accumulate/Subtract] [Long] - // By Scalar Instructions. - &DisassembleNVdVnVmImmMulScalar, - - // Vector Table Lookup uses byte indexes in a control vector to look up byte - // values in a table and generate a new vector. - &DisassembleVTBL, - NULL, -}; - -static bool DisassembleNEONFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - assert(0 && "Code is not reachable"); - return false; -} - -// Vector Get Lane (move scalar to ARM core register) Instructions. -// VGETLNi32, VGETLNs16, VGETLNs8, VGETLNu16, VGETLNu8: Rt Dn index -static bool DisassembleNEONGetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - unsigned short NumDefs = TID.getNumDefs(); - const TargetOperandInfo *OpInfo = TID.OpInfo; - - assert(NumDefs == 1 && NumOps >= 3 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass == ARM::DPRRegClassID && - OpInfo[2].RegClass == 0); - - ElemSize esize = - Opcode == ARM::VGETLNi32 ? ESize32 - : ((Opcode == ARM::VGETLNs16 || Opcode == ARM::VGETLNu16) ? ESize16 - : ESize32); - - // Rt = Inst{15-12} => ARM Rd - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - - // Dn = Inst{7:19-16} => NEON Rn - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, - decodeNEONRn(insn)))); - - MI.addOperand(MCOperand::CreateImm(decodeNVLaneOpIndex(insn, esize))); - - NumOpsAdded = 3; - return true; -} - -// Vector Set Lane (move ARM core register to scalar) Instructions. -// VSETLNi16, VSETLNi32, VSETLNi8: Dd Dd (TIED_TO) Rt index -static bool DisassembleNEONSetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - unsigned short NumDefs = TID.getNumDefs(); - const TargetOperandInfo *OpInfo = TID.OpInfo; - - assert(NumDefs == 1 && NumOps >= 3 && - OpInfo[0].RegClass == ARM::DPRRegClassID && - OpInfo[1].RegClass == ARM::DPRRegClassID && - TID.getOperandConstraint(1, TOI::TIED_TO) != -1 && - OpInfo[2].RegClass == ARM::GPRRegClassID && - OpInfo[3].RegClass == 0); - - ElemSize esize = - Opcode == ARM::VSETLNi8 ? ESize8 - : (Opcode == ARM::VSETLNi16 ? ESize16 - : ESize32); - - // Dd = Inst{7:19-16} => NEON Rn - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, - decodeNEONRn(insn)))); - - // TIED_TO operand. - MI.addOperand(MCOperand::CreateReg(0)); - - // Rt = Inst{15-12} => ARM Rd - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - - MI.addOperand(MCOperand::CreateImm(decodeNVLaneOpIndex(insn, esize))); - - NumOpsAdded = 4; - return true; -} - -// Vector Duplicate Instructions (from ARM core register to all elements). -// VDUP8d, VDUP16d, VDUP32d, VDUP8q, VDUP16q, VDUP32q: Qd/Dd Rt -static bool DisassembleNEONDupFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 2 && - (OpInfo[0].RegClass == ARM::DPRRegClassID || - OpInfo[0].RegClass == ARM::QPRRegClassID) && - OpInfo[1].RegClass == ARM::GPRRegClassID); - - unsigned RegClass = OpInfo[0].RegClass; - - // Qd/Dd = Inst{7:19-16} => NEON Rn - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass, - decodeNEONRn(insn)))); - - // Rt = Inst{15-12} => ARM Rd - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - - NumOpsAdded = 2; - return true; -} - -// A8.6.41 DMB -// A8.6.42 DSB -// A8.6.49 ISB -static inline bool MemBarrierInstr(uint32_t insn) { - unsigned op7_4 = slice(insn, 7, 4); - if (slice(insn, 31, 20) == 0xf57 && (op7_4 >= 4 && op7_4 <= 6)) - return true; - - return false; -} - -static inline bool PreLoadOpcode(unsigned Opcode) { - switch(Opcode) { - case ARM::PLDi: case ARM::PLDr: - case ARM::PLDWi: case ARM::PLDWr: - case ARM::PLIi: case ARM::PLIr: - return true; - default: - return false; - } -} - -static bool DisassemblePreLoadFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - // Preload Data/Instruction requires either 2 or 4 operands. - // PLDi, PLDWi, PLIi: Rn [+/-]imm12 add = (U == '1') - // PLDr[a|m], PLDWr[a|m], PLIr[a|m]: Rn Rm addrmode2_opc - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - - if (Opcode == ARM::PLDi || Opcode == ARM::PLDWi || Opcode == ARM::PLIi) { - unsigned Imm12 = slice(insn, 11, 0); - bool Negative = getUBit(insn) == 0; - int Offset = Negative ? -1 - Imm12 : 1 * Imm12; - MI.addOperand(MCOperand::CreateImm(Offset)); - NumOpsAdded = 2; - } else { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - - ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; - - // Inst{6-5} encodes the shift opcode. - ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); - // Inst{11-7} encodes the imm5 shift amount. - unsigned ShImm = slice(insn, 11, 7); - - // A8.4.1. Possible rrx or shift amount of 32... - getImmShiftSE(ShOp, ShImm); - MI.addOperand(MCOperand::CreateImm( - ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); - NumOpsAdded = 3; - } - - return true; -} - -static bool DisassembleMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - if (MemBarrierInstr(insn)) - return true; - - switch (Opcode) { - case ARM::CLREX: - case ARM::NOP: - case ARM::TRAP: - case ARM::YIELD: - case ARM::WFE: - case ARM::WFI: - case ARM::SEV: - case ARM::SETENDBE: - case ARM::SETENDLE: - return true; - default: - break; - } - - // CPS has a singleton $opt operand that contains the following information: - // opt{4-0} = mode from Inst{4-0} - // opt{5} = changemode from Inst{17} - // opt{8-6} = AIF from Inst{8-6} - // opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable - if (Opcode == ARM::CPS) { - unsigned Option = slice(insn, 4, 0) | slice(insn, 17, 17) << 5 | - slice(insn, 8, 6) << 6 | slice(insn, 19, 18) << 9; - MI.addOperand(MCOperand::CreateImm(Option)); - NumOpsAdded = 1; - return true; - } - - // DBG has its option specified in Inst{3-0}. - if (Opcode == ARM::DBG) { - MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 0))); - NumOpsAdded = 1; - return true; - } - - // BKPT takes an imm32 val equal to ZeroExtend(Inst{19-8:3-0}). - if (Opcode == ARM::BKPT) { - MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 8) << 4 | - slice(insn, 3, 0))); - NumOpsAdded = 1; - return true; - } - - if (PreLoadOpcode(Opcode)) - return DisassemblePreLoadFrm(MI, Opcode, insn, NumOps, NumOpsAdded); - - assert(0 && "Unexpected misc instruction!"); - return false; -} - -static bool DisassembleThumbMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(0 && "Unexpected thumb misc. instruction!"); - return false; -} - -/// FuncPtrs - FuncPtrs maps ARMFormat to its corresponding DisassembleFP. -/// We divide the disassembly task into different categories, with each one -/// corresponding to a specific instruction encoding format. There could be -/// exceptions when handling a specific format, and that is why the Opcode is -/// also present in the function prototype. -static const DisassembleFP FuncPtrs[] = { - &DisassemblePseudo, - &DisassembleMulFrm, - &DisassembleBrFrm, - &DisassembleBrMiscFrm, - &DisassembleDPFrm, - &DisassembleDPSoRegFrm, - &DisassembleLdFrm, - &DisassembleStFrm, - &DisassembleLdMiscFrm, - &DisassembleStMiscFrm, - &DisassembleLdStMulFrm, - &DisassembleArithMiscFrm, - &DisassembleExtFrm, - &DisassembleVFPUnaryFrm, - &DisassembleVFPBinaryFrm, - &DisassembleVFPConv1Frm, - &DisassembleVFPConv2Frm, - &DisassembleVFPConv3Frm, - &DisassembleVFPConv4Frm, - &DisassembleVFPConv5Frm, - &DisassembleVFPLdStFrm, - &DisassembleVFPLdStMulFrm, - &DisassembleVFPMiscFrm, - &DisassembleThumbFrm, - &DisassembleNEONFrm, - &DisassembleNEONGetLnFrm, - &DisassembleNEONSetLnFrm, - &DisassembleNEONDupFrm, - &DisassembleLdStExFrm, - &DisassembleMiscFrm, - &DisassembleThumbMiscFrm, - NULL, -}; - -/// ARMAlgorithm - ARMAlgorithm implements ARMDisassemblyAlgorithm for solving -/// the problem of building the MCOperands of an MCInst. Construction of -/// ARMAlgorithm requires passing in a function pointer with the DisassembleFP -/// data type. -class ARMAlgorithm : public ARMDisassemblyAlgorithm { - /// Algorithms - Algorithms stores a map from Format to ARMAlgorithm*. - static std::vector<ARMAlgorithm*> Algorithms; - /// NSAlgorithms - NSAlgorithms stores a map from NSFormat to ARMAlgorithm*. - static std::vector<ARMAlgorithm*> NSAlgorithms; - - DisassembleFP Disassemble; - -public: - /// GetInstance - GetInstance returns an instance of ARMAlgorithm given the - /// encoding Format. API clients should not free up the returned instance. - static ARMAlgorithm *GetInstance(ARMFormat Format, NSFormat NSF) { - /// Init the first time. - if (Algorithms.size() == 0) { - Algorithms.resize(array_lengthof(FuncPtrs)); - for (unsigned i = 0, num = array_lengthof(FuncPtrs); i < num; ++i) - if (FuncPtrs[i]) - Algorithms[i] = new ARMAlgorithm(FuncPtrs[i]); - else - Algorithms[i] = NULL; - } - if (NSAlgorithms.size() == 0) { - NSAlgorithms.resize(array_lengthof(NEONFuncPtrs)); - for (unsigned i = 0, num = array_lengthof(NEONFuncPtrs); i < num; ++i) - if (NEONFuncPtrs[i]) - NSAlgorithms[i] = new ARMAlgorithm(NEONFuncPtrs[i]); - else - NSAlgorithms[i] = NULL; - } - - if (Format != ARM_FORMAT_NEONFRM) - return Algorithms[Format]; - else - return NSAlgorithms[NSF]; - } - - virtual bool Solve(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) const { - if (Disassemble == NULL) - return false; - - return (*Disassemble)(MI, Opcode, insn, NumOps, NumOpsAdded); - } - -private: - ARMAlgorithm(DisassembleFP fp) : - ARMDisassemblyAlgorithm(), Disassemble(fp) {} - - ARMAlgorithm(ARMAlgorithm &AA) : - ARMDisassemblyAlgorithm(), Disassemble(AA.Disassemble) {} - - virtual ~ARMAlgorithm() {} -}; - -// Define the symbol here. -std::vector<ARMAlgorithm*> ARMAlgorithm::Algorithms; - -// Define the symbol here. -std::vector<ARMAlgorithm*> ARMAlgorithm::NSAlgorithms; - -// Define the symbol here. -unsigned ARMBasicMCBuilder::ITCounter = 0; - -// Define the symbol here. -unsigned ARMBasicMCBuilder::ITState = 0; - -// A8.6.50 -static unsigned short CountITSize(unsigned ITMask) { - // First count the trailing zeros of the IT mask. - unsigned TZ = CountTrailingZeros_32(ITMask); - assert(TZ <= 3); - return (4 - TZ); -} - -/// 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. -bool ARMBasicMCBuilder::BuildIt(MCInst &MI, uint32_t insn) { - // Stage 1 sets the Opcode. - MI.setOpcode(Opcode); - // If the number of operands is zero, we're done! - if (NumOps == 0) - return true; - - // Stage 2 calls the ARM Disassembly Algorithm to build the operand list. - unsigned NumOpsAdded = 0; - bool OK = Algo.Solve(MI, Opcode, insn, NumOps, NumOpsAdded); - - if (!OK) return false; - if (NumOpsAdded >= NumOps) - return true; - - // Stage 3 deals with operands unaccounted for after stage 2 is finished. - // FIXME: Should this be done selectively? - return TryPredicateAndSBitModifier(MI, Opcode, insn, NumOps - NumOpsAdded); -} - -bool ARMBasicMCBuilder::TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode, - uint32_t insn, unsigned short NumOpsRemaining) { - - assert(NumOpsRemaining > 0); - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - const std::string &Name = ARMInsts[Opcode].Name; - unsigned Idx = MI.getNumOperands(); - - // First, we check whether this instr specifies the PredicateOperand through - // a pair of TargetOperandInfos with isPredicate() property. - if (NumOpsRemaining >= 2 && - OpInfo[Idx].isPredicate() && OpInfo[Idx+1].isPredicate() && - OpInfo[Idx].RegClass == 0 && OpInfo[Idx+1].RegClass == ARM::CCRRegClassID) - { - // If we are inside an IT block, get the IT condition bits maintained via - // ARMBasicMCBuilder::ITState[7:0], through ARMBasicMCBuilder::GetITCond(). - // See also A2.5.2. - if (InITBlock()) - MI.addOperand(MCOperand::CreateImm(GetITCond())); - else { - if (Name.length() > 1 && Name[0] == 't') { - // Thumb conditional branch instructions have their cond field embedded, - // like ARM. - // - // A8.6.16 B - if (Name == "t2Bcc") - MI.addOperand(MCOperand::CreateImm(slice(insn, 25, 22))); - else if (Name == "tBcc") - MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8))); - else - MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); - } else { - // ARM Instructions. Check condition field. - int64_t CondVal = getCondField(insn); - if (CondVal == 0xF) - MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); - else - MI.addOperand(MCOperand::CreateImm(CondVal)); - } - } - MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - Idx += 2; - NumOpsRemaining -= 2; - if (NumOpsRemaining == 0) - return true; - } - - assert(NumOpsRemaining > 0); - - // Next, if OptionalDefOperand exists, we check whether the 'S' bit is set. - if (OpInfo[Idx].isOptionalDef() && OpInfo[Idx].RegClass==ARM::CCRRegClassID) { - MI.addOperand(MCOperand::CreateReg(getSBit(insn) == 1 ? ARM::CPSR : 0)); - --NumOpsRemaining; - } - - if (NumOpsRemaining == 0) - return true; - else - return false; -} - -/// RunBuildAfterHook - RunBuildAfterHook performs operations deemed necessary -/// after BuildIt is finished. -bool ARMBasicMCBuilder::RunBuildAfterHook(bool Status, MCInst &MI, - uint32_t insn) { - - if (Opcode == ARM::t2IT) { - ARMBasicMCBuilder::ITCounter = CountITSize(slice(insn, 3, 0)); - ARMBasicMCBuilder::InitITState(slice(insn, 7, 0)); - } else if (InITBlock()) - ARMBasicMCBuilder::UpdateITState(); - - return Status; -} - -AbstractARMMCBuilder *ARMMCBuilderFactory::CreateMCBuilder(unsigned Opcode, - ARMFormat Format, NSFormat NSF) { - - ARMAlgorithm *Algo = ARMAlgorithm::GetInstance(Format, NSF); - if (!Algo) - return NULL; - - return new ARMBasicMCBuilder(Opcode, Format, NSF, - ARMInsts[Opcode].getNumOperands(), *Algo); -} diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h b/llvm/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h deleted file mode 100644 index 23b309cd4f4..00000000000 --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h +++ /dev/null @@ -1,301 +0,0 @@ -//===- 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 diff --git a/llvm/lib/Target/ARM/Disassembler/Makefile b/llvm/lib/Target/ARM/Disassembler/Makefile deleted file mode 100644 index 3eab8325a44..00000000000 --- a/llvm/lib/Target/ARM/Disassembler/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -##===- lib/Target/ARM/Disassembler/Makefile ----------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -LIBRARYNAME = LLVMARMDisassembler -CXXFLAGS = -fno-rtti - -# Hack: we need to include 'main' arm target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. - -include $(LEVEL)/Makefile.common diff --git a/llvm/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc b/llvm/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc deleted file mode 100644 index 928c403b7ef..00000000000 --- a/llvm/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc +++ /dev/null @@ -1,2158 +0,0 @@ -//===- ThumbDisassemblerCore.cpp - 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. -// It contains code for disassembling a Thumb instr. -// -//===----------------------------------------------------------------------===// - -/////////////////////////////// -// // -// Utility Functions // -// // -/////////////////////////////// - -// Utilities for 16-bit Thumb instructions. -/* -15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - [ tRt ] - [ tRm ] [ tRn ] [ tRd ] - D [ Rm ] [ Rd ] - - [ imm3] - [ imm5 ] - i [ imm5 ] - [ imm7 ] - [ imm8 ] - [ imm11 ] - - [ cond ] -*/ - -static bool InITBlock() { - return ARMBasicMCBuilder::InITBlock(); -} - -// Extract tRt: Inst{10-8}. -static inline unsigned getT1tRt(uint32_t insn) { - return slice(insn, 10, 8); -} - -// Extract tRm: Inst{8-6}. -static inline unsigned getT1tRm(uint32_t insn) { - return slice(insn, 8, 6); -} - -// Extract tRn: Inst{5-3}. -static inline unsigned getT1tRn(uint32_t insn) { - return slice(insn, 5, 3); -} - -// Extract tRd: Inst{2-0}. -static inline unsigned getT1tRd(uint32_t insn) { - return slice(insn, 2, 0); -} - -// Extract [D:Rd]: Inst{7:2-0}. -static inline unsigned getT1Rd(uint32_t insn) { - return slice(insn, 7, 7) << 3 | slice(insn, 2, 0); -} - -// Extract Rm: Inst{6-3}. -static inline unsigned getT1Rm(uint32_t insn) { - return slice(insn, 6, 3); -} - -// Extract imm3: Inst{8-6}. -static inline unsigned getT1Imm3(uint32_t insn) { - return slice(insn, 8, 6); -} - -// Extract imm5: Inst{10-6}. -static inline unsigned getT1Imm5(uint32_t insn) { - return slice(insn, 10, 6); -} - -// Extract i:imm5: Inst{9:7-3}. -static inline unsigned getT1Imm6(uint32_t insn) { - return slice(insn, 9, 9) << 5 | slice(insn, 7, 3); -} - -// Extract imm7: Inst{6-0}. -static inline unsigned getT1Imm7(uint32_t insn) { - return slice(insn, 6, 0); -} - -// Extract imm8: Inst{7-0}. -static inline unsigned getT1Imm8(uint32_t insn) { - return slice(insn, 7, 0); -} - -// Extract imm11: Inst{10-0}. -static inline unsigned getT1Imm11(uint32_t insn) { - return slice(insn, 10, 0); -} - -// Extract cond: Inst{11-8}. -static inline unsigned getT1Cond(uint32_t insn) { - return slice(insn, 11, 8); -} - -static inline bool IsGPR(unsigned RegClass) { - return RegClass == ARM::GPRRegClassID; -} - -// Utilities for 32-bit Thumb instructions. - -// Extract imm4: Inst{19-16}. -static inline unsigned getImm4(uint32_t insn) { - return slice(insn, 19, 16); -} - -// Extract imm3: Inst{14-12}. -static inline unsigned getImm3(uint32_t insn) { - return slice(insn, 14, 12); -} - -// Extract imm8: Inst{7-0}. -static inline unsigned getImm8(uint32_t insn) { - return slice(insn, 7, 0); -} - -// A8.6.61 LDRB (immediate, Thumb) and friends -// +/-: Inst{9} -// imm8: Inst{7-0} -static inline int decodeImm8(uint32_t insn) { - int Offset = getImm8(insn); - return slice(insn, 9, 9) ? Offset : -Offset; -} - -// Extract imm12: Inst{11-0}. -static inline unsigned getImm12(uint32_t insn) { - return slice(insn, 11, 0); -} - -// A8.6.63 LDRB (literal) and friends -// +/-: Inst{23} -// imm12: Inst{11-0} -static inline int decodeImm12(uint32_t insn) { - int Offset = getImm12(insn); - return slice(insn, 23, 23) ? Offset : -Offset; -} - -// Extract imm2: Inst{7-6}. -static inline unsigned getImm2(uint32_t insn) { - return slice(insn, 7, 6); -} - -// For BFI, BFC, t2SBFX, and t2UBFX. -// Extract lsb: Inst{14-12:7-6}. -static inline unsigned getLsb(uint32_t insn) { - return getImm3(insn) << 2 | getImm2(insn); -} - -// For BFI and BFC. -// Extract msb: Inst{4-0}. -static inline unsigned getMsb(uint32_t insn) { - return slice(insn, 4, 0); -} - -// For t2SBFX and t2UBFX. -// Extract widthminus1: Inst{4-0}. -static inline unsigned getWidthMinus1(uint32_t insn) { - return slice(insn, 4, 0); -} - -// For t2ADDri12 and t2SUBri12. -// imm12 = i:imm3:imm8; -static inline unsigned getIImm3Imm8(uint32_t insn) { - return slice(insn, 26, 26) << 11 | getImm3(insn) << 8 | getImm8(insn); -} - -// For t2MOVi16 and t2MOVTi16. -// imm16 = imm4:i:imm3:imm8; -static inline unsigned getImm16(uint32_t insn) { - return getImm4(insn) << 12 | slice(insn, 26, 26) << 11 | - getImm3(insn) << 8 | getImm8(insn); -} - -// Inst{5-4} encodes the shift type. -static inline unsigned getShiftTypeBits(uint32_t insn) { - return slice(insn, 5, 4); -} - -// Inst{14-12}:Inst{7-6} encodes the imm5 shift amount. -static inline unsigned getShiftAmtBits(uint32_t insn) { - return getImm3(insn) << 2 | getImm2(insn); -} - -// A8.6.17 BFC -// Encoding T1 ARMv6T2, ARMv7 -// LLVM-specific encoding for #<lsb> and #<width> -static inline uint32_t getBitfieldInvMask(uint32_t insn) { - uint32_t lsb = getImm3(insn) << 2 | getImm2(insn); - uint32_t msb = getMsb(insn); - uint32_t Val = 0; - assert(lsb <= msb && "Encoding error: lsb > msb"); - for (uint32_t i = lsb; i <= msb; ++i) - Val |= (1 << i); - return ~Val; -} - -// A8.4 Shifts applied to a register -// A8.4.1 Constant shifts -// A8.4.3 Pseudocode details of instruction-specified shifts and rotates -// -// decodeImmShift() returns the shift amount and the the shift opcode. -// Note that, as of Jan-06-2010, LLVM does not support rrx shifted operands yet. -static inline unsigned decodeImmShift(unsigned bits2, unsigned imm5, - ARM_AM::ShiftOpc &ShOp) { - - assert(imm5 < 32); - switch (bits2) { - default: assert(0 && "No such value"); - case 0: - ShOp = ARM_AM::lsl; - return imm5; - case 1: - ShOp = ARM_AM::lsr; - return (imm5 == 0 ? 32 : imm5); - case 2: - ShOp = ARM_AM::asr; - return (imm5 == 0 ? 32 : imm5); - case 3: - ShOp = (imm5 == 0 ? ARM_AM::rrx : ARM_AM::ror); - return (imm5 == 0 ? 1 : imm5); - } -} - -// A6.3.2 Modified immediate constants in Thumb instructions -// -// ThumbExpandImm() returns the modified immediate constant given an imm12 for -// Thumb data-processing instructions with modified immediate. -// See also A6.3.1 Data-processing (modified immediate). -static inline unsigned ThumbExpandImm(unsigned imm12) { - assert(imm12 <= 0xFFF); - - // If the leading two bits is 0b00, the modified immediate constant is - // obtained by splatting the low 8 bits into the first byte, every other byte, - // or every byte of a 32-bit value. - // - // Otherwise, a rotate right of '1':imm12<6:0> by the amount imm12<11:7> is - // performed. - - if (slice(imm12, 11, 10) == 0) { - unsigned short control = slice(imm12, 9, 8); - unsigned imm8 = slice(imm12, 7, 0); - switch (control) { - default: - assert(0 && "No such value"); - return 0; - case 0: - return imm8; - case 1: - return imm8 << 16 | imm8; - case 2: - return imm8 << 24 | imm8 << 8; - case 3: - return imm8 << 24 | imm8 << 16 | imm8 << 8 | imm8; - } - } else { - // A rotate is required. - unsigned Val = 1 << 7 | slice(imm12, 6, 0); - unsigned Amt = slice(imm12, 11, 7); - return ARM_AM::rotr32(Val, Amt); - } -} - -static inline int decodeImm32_B_EncodingT3(uint32_t insn) { - bool S = slice(insn, 26, 26); - bool J1 = slice(insn, 13, 13); - bool J2 = slice(insn, 11, 11); - unsigned Imm21 = slice(insn, 21, 16) << 12 | slice(insn, 10, 0) << 1; - if (S) Imm21 |= 1 << 20; - if (J2) Imm21 |= 1 << 19; - if (J1) Imm21 |= 1 << 18; - - return signextend<signed int, 21>(Imm21); -} - -static inline int decodeImm32_B_EncodingT4(uint32_t insn) { - unsigned S = slice(insn, 26, 26); - bool I1 = slice(insn, 13, 13) == S; - bool I2 = slice(insn, 11, 11) == S; - unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 0) << 1; - if (S) Imm25 |= 1 << 24; - if (I1) Imm25 |= 1 << 23; - if (I2) Imm25 |= 1 << 22; - - return signextend<signed int, 25>(Imm25); -} - -static inline int decodeImm32_BL(uint32_t insn) { - unsigned S = slice(insn, 26, 26); - bool I1 = slice(insn, 13, 13) == S; - bool I2 = slice(insn, 11, 11) == S; - unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 0) << 1; - if (S) Imm25 |= 1 << 24; - if (I1) Imm25 |= 1 << 23; - if (I2) Imm25 |= 1 << 22; - - return signextend<signed int, 25>(Imm25); -} - -static inline int decodeImm32_BLX(uint32_t insn) { - unsigned S = slice(insn, 26, 26); - bool I1 = slice(insn, 13, 13) == S; - bool I2 = slice(insn, 11, 11) == S; - unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 1) << 2; - if (S) Imm25 |= 1 << 24; - if (I1) Imm25 |= 1 << 23; - if (I2) Imm25 |= 1 << 22; - - return signextend<signed int, 25>(Imm25); -} - -// See, for example, A8.6.221 SXTAB16. -static inline unsigned decodeRotate(uint32_t insn) { - unsigned rotate = slice(insn, 5, 4); - return rotate << 3; -} - -/////////////////////////////////////////////// -// // -// Thumb1 instruction disassembly functions. // -// // -/////////////////////////////////////////////// - -// See "Utilities for 16-bit Thumb instructions" for register naming convention. - -// A6.2.1 Shift (immediate), add, subtract, move, and compare -// -// shift immediate: tRd CPSR tRn imm5 -// add/sub register: tRd CPSR tRn tRm -// add/sub 3-bit immediate: tRd CPSR tRn imm3 -// add/sub 8-bit immediate: tRt CPSR tRt(TIED_TO) imm8 -// mov/cmp immediate: tRt [CPSR] imm8 (CPSR present for mov) -// -// Special case: -// tMOVSr: tRd tRn -static bool DisassembleThumb1General(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID); - - bool Imm3 = (Opcode == ARM::tADDi3 || Opcode == ARM::tSUBi3); - - // Use Rt implies use imm8. - bool UseRt = (Opcode == ARM::tADDi8 || Opcode == ARM::tSUBi8 || - Opcode == ARM::tMOVi8 || Opcode == ARM::tCMPi8); - - // Add the destination operand. - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::tGPRRegClassID, - UseRt ? getT1tRt(insn) : getT1tRd(insn)))); - ++OpIdx; - - // Check whether the next operand to be added is a CCR Register. - if (OpInfo[OpIdx].RegClass == ARM::CCRRegClassID) { - assert(OpInfo[OpIdx].isOptionalDef()); - MI.addOperand(MCOperand::CreateReg(InITBlock() ? 0 : ARM::CPSR)); - ++OpIdx; - } - - // Check whether the next operand to be added is a Thumb1 Register. - assert(OpIdx < NumOps); - if (OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) { - // For UseRt, the reg operand is tied to the first reg operand. - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::tGPRRegClassID, - UseRt ? getT1tRt(insn) : getT1tRn(insn)))); - ++OpIdx; - } - - // Special case for tMOVSr. - if (OpIdx == NumOps) - return true; - - // The next available operand is either a reg operand or an imm operand. - if (OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) { - // Three register operand instructions. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRm(insn)))); - } else { - assert(OpInfo[OpIdx].RegClass == 0 && - !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()); - MI.addOperand(MCOperand::CreateImm(UseRt ? getT1Imm8(insn) - : (Imm3 ? getT1Imm3(insn) - : getT1Imm5(insn)))); - } - ++OpIdx; - - return true; -} - -// A6.2.2 Data-processing -// -// tCMPr, tTST, tCMN: tRd tRn -// tMVN, tRSB: tRd CPSR tRn -// Others: tRd CPSR tRd(TIED_TO) tRn -static bool DisassembleThumb1DP(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && - (OpInfo[1].RegClass == ARM::CCRRegClassID - || OpInfo[1].RegClass == ARM::tGPRRegClassID)); - - // Add the destination operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRd(insn)))); - ++OpIdx; - - // Check whether the next operand to be added is a CCR Register. - if (OpInfo[OpIdx].RegClass == ARM::CCRRegClassID) { - assert(OpInfo[OpIdx].isOptionalDef()); - MI.addOperand(MCOperand::CreateReg(InITBlock() ? 0 : ARM::CPSR)); - ++OpIdx; - } - - // We have either { tRd(TIED_TO), tRn } or { tRn } remaining. - // Process the TIED_TO operand first. - - assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID); - int Idx; - if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { - // The reg operand is tied to the first reg operand. - MI.addOperand(MI.getOperand(Idx)); - ++OpIdx; - } - - // Process possible next reg operand. - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) { - // Add tRn operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRn(insn)))); - ++OpIdx; - } - - return true; -} - -// A6.2.3 Special data instructions and branch and exchange -// -// tADDhirr: Rd Rd(TIED_TO) Rm -// tCMPhir: Rd Rm -// tMOVr, tMOVgpr2gpr, tMOVgpr2tgpr, tMOVtgpr2gpr: Rd|tRd Rm|tRn -// tBX_RET: 0 operand -// tBX_RET_vararg: Rm -// tBLXr_r9: Rm -static bool DisassembleThumb1Special(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - // tBX_RET has 0 operand. - if (NumOps == 0) - return true; - - // BX/BLX has 1 reg operand: Rm. - if (NumOps == 1) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - getT1Rm(insn)))); - NumOpsAdded = 1; - return true; - } - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - // Add the destination operand. - unsigned RegClass = OpInfo[OpIdx].RegClass; - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(RegClass, - IsGPR(RegClass) ? getT1Rd(insn) - : getT1tRd(insn)))); - ++OpIdx; - - // We have either { Rd(TIED_TO), Rm } or { Rm|tRn } remaining. - // Process the TIED_TO operand first. - - assert(OpIdx < NumOps); - int Idx; - if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { - // The reg operand is tied to the first reg operand. - MI.addOperand(MI.getOperand(Idx)); - ++OpIdx; - } - - // The next reg operand is either Rm or tRn. - assert(OpIdx < NumOps); - RegClass = OpInfo[OpIdx].RegClass; - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(RegClass, - IsGPR(RegClass) ? getT1Rm(insn) - : getT1tRn(insn)))); - ++OpIdx; - - return true; -} - -// A8.6.59 LDR (literal) -// -// tLDRpci: tRt imm8*4 -static bool DisassembleThumb1LdPC(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && - (OpInfo[1].RegClass == 0 && - !OpInfo[1].isPredicate() && - !OpInfo[1].isOptionalDef())); - - // Add the destination operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRt(insn)))); - - // And the (imm8 << 2) operand. - MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn) << 2)); - - NumOpsAdded = 2; - - return true; -} - -// Thumb specific addressing modes (see ARMInstrThumb.td): -// -// t_addrmode_rr := reg + reg -// -// t_addrmode_s4 := reg + reg -// reg + imm5 * 4 -// -// t_addrmode_s2 := reg + reg -// reg + imm5 * 2 -// -// t_addrmode_s1 := reg + reg -// reg + imm5 -// -// t_addrmode_sp := sp + imm8 * 4 -// - -// A6.2.4 Load/store single data item -// -// Load/Store Register (reg|imm): tRd tRn imm5 tRm -// Load Register Signed Byte|Halfword: tRd tRn tRm -static bool DisassembleThumb1LdSt(unsigned opA, MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - // Table A6-5 16-bit Thumb Load/store instructions - // opA = 0b0101 for STR/LDR (register) and friends. - // Otherwise, we have STR/LDR (immediate) and friends. - bool Imm5 = (opA != 5); - - assert(NumOps >= 2 - && OpInfo[0].RegClass == ARM::tGPRRegClassID - && OpInfo[1].RegClass == ARM::tGPRRegClassID); - - // Add the destination reg and the base reg. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRd(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRn(insn)))); - OpIdx = 2; - - // We have either { imm5, tRm } or { tRm } remaining. - // Process the imm5 first. Note that STR/LDR (register) should skip the imm5 - // offset operand for t_addrmode_s[1|2|4]. - - assert(OpIdx < NumOps); - - if (OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() && - !OpInfo[OpIdx].isOptionalDef()) { - - MI.addOperand(MCOperand::CreateImm(Imm5 ? getT1Imm5(insn) : 0)); - ++OpIdx; - } - - // The next reg operand is tRm, the offset. - assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID); - MI.addOperand(MCOperand::CreateReg(Imm5 ? 0 - : getRegisterEnum(ARM::tGPRRegClassID, - getT1tRm(insn)))); - ++OpIdx; - - return true; -} - -// A6.2.4 Load/store single data item -// -// Load/Store Register SP relative: tRt ARM::SP imm8 -static bool DisassembleThumb1LdStSP(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(Opcode == ARM::tLDRspi || Opcode == ARM::tSTRspi); - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 3 && - OpInfo[0].RegClass == ARM::tGPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID && - (OpInfo[2].RegClass == 0 && - !OpInfo[2].isPredicate() && - !OpInfo[2].isOptionalDef())); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRt(insn)))); - MI.addOperand(MCOperand::CreateReg(ARM::SP)); - MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); - NumOpsAdded = 3; - return true; -} - -// Table A6-1 16-bit Thumb instruction encoding -// A8.6.10 ADR -// -// tADDrPCi: tRt imm8 -static bool DisassembleThumb1AddPCi(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(Opcode == ARM::tADDrPCi); - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && - (OpInfo[1].RegClass == 0 && - !OpInfo[1].isPredicate() && - !OpInfo[1].isOptionalDef())); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRt(insn)))); - MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); - NumOpsAdded = 2; - return true; -} - -// Table A6-1 16-bit Thumb instruction encoding -// A8.6.8 ADD (SP plus immediate) -// -// tADDrSPi: tRt ARM::SP imm8 -static bool DisassembleThumb1AddSPi(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(Opcode == ARM::tADDrSPi); - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 3 && - OpInfo[0].RegClass == ARM::tGPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID && - (OpInfo[2].RegClass == 0 && - !OpInfo[2].isPredicate() && - !OpInfo[2].isOptionalDef())); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRt(insn)))); - MI.addOperand(MCOperand::CreateReg(ARM::SP)); - MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); - NumOpsAdded = 3; - return true; -} - -// tPUSH, tPOP: Pred-Imm Pred-CCR register_list -// -// where register_list = low registers + [lr] for PUSH or -// low registers + [pc] for POP -// -// "low registers" is specified by Inst{7-0} -// lr|pc is specified by Inst{8} -static bool DisassembleThumb1PushPop(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(Opcode == ARM::tPUSH || Opcode == ARM::tPOP); - - unsigned &OpIdx = NumOpsAdded; - - // Handling the two predicate operands before the reglist. - MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); - MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - OpIdx = 2; - - // Fill the variadic part of reglist. - unsigned RegListBits = slice(insn, 8, 8) << (Opcode == ARM::tPUSH ? 14 : 15) - | slice(insn, 7, 0); - for (unsigned i = 0; i < 16; ++i) { - if ((RegListBits >> i) & 1) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - i))); - ++OpIdx; - } - } - - return true; -} - -// A6.2.5 Miscellaneous 16-bit instructions -// Delegate to DisassembleThumb1PushPop() for tPUSH & tPOP. -// -// tADDspi, tSUBspi: ARM::SP ARM::SP(TIED_TO) imm7 -// t2IT: firstcond=Inst{7-4} mask=Inst{3-0} -// tCBNZ, tCBZ: tRd imm6*2 -// tBKPT: imm8 -// tNOP, tSEV, tYIELD, tWFE, tWFI: -// no operand (except predicate pair) -// tSETENDBE, tSETENDLE, : -// no operand -// Others: tRd tRn -static bool DisassembleThumb1Misc(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - if (NumOps == 0) - return true; - - if (Opcode == ARM::tPUSH || Opcode == ARM::tPOP) - return DisassembleThumb1PushPop(MI, Opcode, insn, NumOps, NumOpsAdded); - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - // Predicate operands are handled elsewhere. - if (NumOps == 2 && - OpInfo[0].isPredicate() && OpInfo[1].isPredicate() && - OpInfo[0].RegClass == 0 && OpInfo[1].RegClass == ARM::CCRRegClassID) { - return true; - } - - if (Opcode == ARM::tADDspi || Opcode == ARM::tSUBspi) { - // Special case handling for tADDspi and tSUBspi. - // A8.6.8 ADD (SP plus immediate) & A8.6.215 SUB (SP minus immediate) - MI.addOperand(MCOperand::CreateReg(ARM::SP)); - MI.addOperand(MCOperand::CreateReg(ARM::SP)); - MI.addOperand(MCOperand::CreateImm(getT1Imm7(insn))); - NumOpsAdded = 3; - return true; - } - - if (Opcode == ARM::t2IT) { - // Special case handling for If-Then. - // A8.6.50 IT - // Tag the (firstcond[0] bit << 4) along with mask. - - // firstcond - MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 4))); - - // firstcond[0] and mask - MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); - NumOpsAdded = 2; - return true; - } - - if (Opcode == ARM::tBKPT) { - MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); // breakpoint value - NumOpsAdded = 1; - return true; - } - - // CPS has a singleton $opt operand that contains the following information: - // opt{4-0} = don't care - // opt{5} = 0 (false) - // opt{8-6} = AIF from Inst{2-0} - // opt{10-9} = 1:imod from Inst{4} with 0b10 as enable and 0b11 as disable - if (Opcode == ARM::tCPS) { - unsigned Option = slice(insn, 2, 0) << 6 | slice(insn, 4, 4) << 9 | 1 << 10; - MI.addOperand(MCOperand::CreateImm(Option)); - NumOpsAdded = 1; - return true; - } - - assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && - (OpInfo[1].RegClass==0 || OpInfo[1].RegClass==ARM::tGPRRegClassID)); - - // Add the destination operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRd(insn)))); - - if (OpInfo[1].RegClass == ARM::tGPRRegClassID) { - // Two register instructions. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - getT1tRn(insn)))); - } else { - // CBNZ, CBZ - assert(Opcode == ARM::tCBNZ || Opcode == ARM::tCBZ); - MI.addOperand(MCOperand::CreateImm(getT1Imm6(insn) * 2)); - } - - NumOpsAdded = 2; - - return true; -} - -// A8.6.53 LDM / LDMIA -// A8.6.189 STM / STMIA -// -// tRt AM4ModeImm Pred-Imm Pred-CCR register_list -static bool DisassembleThumb1LdStMul(bool Ld, MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(Opcode == ARM::tLDM || Opcode == ARM::tSTM_UPD); - - unsigned &OpIdx = NumOpsAdded; - - unsigned tRt = getT1tRt(insn); - unsigned RegListBits = slice(insn, 7, 0); - - OpIdx = 0; - - // For STM, WB is always true. - if (Opcode == ARM::tSTM_UPD) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - tRt))); - ++OpIdx; - } - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - tRt))); - ++OpIdx; - - // A8.6.53 LDM / LDMIA / LDMFD - Encoding T1 - // WB is true if tRt is not specified as a member of the register list. - // For STM, WB is always true. - bool WB = Ld ? ((RegListBits >> tRt) & 1) == 0 : true; - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(ARM_AM::ia, WB))); - ++OpIdx; - - // Handling the two predicate operands before the reglist. - MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); - MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - OpIdx += 2; - - // Fill the variadic part of reglist. - for (unsigned i = 0; i < 8; ++i) { - if ((RegListBits >> i) & 1) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, - i))); - ++OpIdx; - } - } - - return true; -} - -static bool DisassembleThumb1LdMul(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - return DisassembleThumb1LdStMul(true, MI, Opcode, insn, NumOps, NumOpsAdded); -} - -static bool DisassembleThumb1StMul(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - return DisassembleThumb1LdStMul(false, MI, Opcode, insn, NumOps, NumOpsAdded); -} - -// A8.6.16 B Encoding T1 -// cond = Inst{11-8} & imm8 = Inst{7-0} -// imm32 = SignExtend(imm8:'0', 32) -// -// tBcc: offset Pred-Imm Pred-CCR -// tSVC: imm8 Pred-Imm Pred-CCR -// tTRAP: 0 operand (early return) -static bool DisassembleThumb1CondBr(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - if (Opcode == ARM::tTRAP) - return true; - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - assert(NumOps == 3 && OpInfo[0].RegClass == 0 && - OpInfo[1].isPredicate() && OpInfo[2].RegClass == ARM::CCRRegClassID); - - unsigned Imm8 = getT1Imm8(insn); - MI.addOperand(MCOperand::CreateImm( - Opcode == ARM::tBcc ? signextend<signed int, 9>(Imm8 << 1) + 4 - : (int)Imm8)); - - // Predicate operands by ARMBasicMCBuilder::TryPredicateAndSBitModifier(). - NumOpsAdded = 1; - - return true; -} - -// A8.6.16 B Encoding T2 -// imm11 = Inst{10-0} -// imm32 = SignExtend(imm11:'0', 32) -// -// tB: offset -static bool DisassembleThumb1Br(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - assert(NumOps == 1 && OpInfo[0].RegClass == 0); - - unsigned Imm11 = getT1Imm11(insn); - - // When executing a Thumb instruction, PC reads as the address of the current - // instruction plus 4. The assembler subtracts 4 from the difference between - // the branch instruction and the target address, disassembler has to add 4 to - // to compensate. - MI.addOperand(MCOperand::CreateImm( - signextend<signed int, 12>(Imm11 << 1) + 4)); - - NumOpsAdded = 1; - - return true; - -} - -// See A6.2 16-bit Thumb instruction encoding for instruction classes -// corresponding to op. -// -// Table A6-1 16-bit Thumb instruction encoding (abridged) -// op Instruction or instruction class -// ------ -------------------------------------------------------------------- -// 00xxxx Shift (immediate), add, subtract, move, and compare on page A6-7 -// 010000 Data-processing on page A6-8 -// 010001 Special data instructions and branch and exchange on page A6-9 -// 01001x Load from Literal Pool, see LDR (literal) on page A8-122 -// 0101xx Load/store single data item on page A6-10 -// 011xxx -// 100xxx -// 10100x Generate PC-relative address, see ADR on page A8-32 -// 10101x Generate SP-relative address, see ADD (SP plus immediate) on page A8-28 -// 1011xx Miscellaneous 16-bit instructions on page A6-11 -// 11000x Store multiple registers, see STM / STMIA / STMEA on page A8-374 -// 11001x Load multiple registers, see LDM / LDMIA / LDMFD on page A8-110 a -// 1101xx Conditional branch, and Supervisor Call on page A6-13 -// 11100x Unconditional Branch, see B on page A8-44 -// -static bool DisassembleThumb1(uint16_t op, - MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - unsigned op1 = slice(op, 5, 4); - unsigned op2 = slice(op, 3, 2); - unsigned op3 = slice(op, 1, 0); - unsigned opA = slice(op, 5, 2); - switch (op1) { - case 0: - // A6.2.1 Shift (immediate), add, subtract, move, and compare - return DisassembleThumb1General(MI, Opcode, insn, NumOps, NumOpsAdded); - case 1: - switch (op2) { - case 0: - switch (op3) { - case 0: - // A6.2.2 Data-processing - return DisassembleThumb1DP(MI, Opcode, insn, NumOps, NumOpsAdded); - case 1: - // A6.2.3 Special data instructions and branch and exchange - return DisassembleThumb1Special(MI, Opcode, insn, NumOps, NumOpsAdded); - default: - // A8.6.59 LDR (literal) - return DisassembleThumb1LdPC(MI, Opcode, insn, NumOps, NumOpsAdded); - } - break; - default: - // A6.2.4 Load/store single data item - return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded); - break; - } - break; - case 2: - switch (op2) { - case 0: - // A6.2.4 Load/store single data item - return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded); - case 1: - // A6.2.4 Load/store single data item - return DisassembleThumb1LdStSP(MI, Opcode, insn, NumOps, NumOpsAdded); - case 2: - if (op3 <= 1) { - // A8.6.10 ADR - return DisassembleThumb1AddPCi(MI, Opcode, insn, NumOps, NumOpsAdded); - } else { - // A8.6.8 ADD (SP plus immediate) - return DisassembleThumb1AddSPi(MI, Opcode, insn, NumOps, NumOpsAdded); - } - default: - // A6.2.5 Miscellaneous 16-bit instructions - return DisassembleThumb1Misc(MI, Opcode, insn, NumOps, NumOpsAdded); - } - break; - case 3: - switch (op2) { - case 0: - if (op3 <= 1) { - // A8.6.189 STM / STMIA / STMEA - return DisassembleThumb1StMul(MI, Opcode, insn, NumOps, NumOpsAdded); - } else { - // A8.6.53 LDM / LDMIA / LDMFD - return DisassembleThumb1LdMul(MI, Opcode, insn, NumOps, NumOpsAdded); - } - case 1: - // A6.2.6 Conditional branch, and Supervisor Call - return DisassembleThumb1CondBr(MI, Opcode, insn, NumOps, NumOpsAdded); - case 2: - // Unconditional Branch, see B on page A8-44 - return DisassembleThumb1Br(MI, Opcode, insn, NumOps, NumOpsAdded); - default: - assert(0 && "Unreachable code"); - break; - } - break; - default: - assert(0 && "Unreachable code"); - break; - } - - return false; -} - -/////////////////////////////////////////////// -// // -// Thumb2 instruction disassembly functions. // -// // -/////////////////////////////////////////////// - -/////////////////////////////////////////////////////////// -// // -// Note: the register naming follows the ARM convention! // -// // -/////////////////////////////////////////////////////////// - -static inline bool Thumb2SRSOpcode(unsigned Opcode) { - switch (Opcode) { - default: - return false; - case ARM::t2SRSDBW: case ARM::t2SRSDB: - case ARM::t2SRSIAW: case ARM::t2SRSIA: - return true; - } -} - -static inline bool Thumb2RFEOpcode(unsigned Opcode) { - switch (Opcode) { - default: - return false; - case ARM::t2RFEDBW: case ARM::t2RFEDB: - case ARM::t2RFEIAW: case ARM::t2RFEIA: - return true; - } -} - -// t2SRS[IA|DB]W/t2SRS[IA|DB]: mode_imm = Inst{4-0} -static bool DisassembleThumb2SRS(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); - NumOpsAdded = 1; - return true; -} - -// t2RFE[IA|DB]W/t2RFE[IA|DB]: Rn -static bool DisassembleThumb2RFE(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - NumOpsAdded = 1; - return true; -} - -static bool DisassembleThumb2LdStMul(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - if (Thumb2SRSOpcode(Opcode)) - return DisassembleThumb2SRS(MI, Opcode, insn, NumOps, NumOpsAdded); - - if (Thumb2RFEOpcode(Opcode)) - return DisassembleThumb2RFE(MI, Opcode, insn, NumOps, NumOpsAdded); - - assert(Opcode == ARM::t2LDM || Opcode == ARM::t2LDM_UPD || - Opcode == ARM::t2STM || Opcode == ARM::t2STM_UPD); - assert(NumOps >= 5 && "Thumb2 LdStMul expects NumOps of 5"); - - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); - - // Writeback to base. - if (Opcode == ARM::t2LDM_UPD || Opcode == ARM::t2STM_UPD) { - MI.addOperand(MCOperand::CreateReg(Base)); - ++OpIdx; - } - - MI.addOperand(MCOperand::CreateReg(Base)); - ++OpIdx; - - ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); - bool WB = getWBit(insn) == 1; - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); - ++OpIdx; - - // Handling the two predicate operands before the reglist. - MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); - MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - OpIdx += 2; - - // Fill the variadic part of reglist. - unsigned RegListBits = insn & ((1 << 16) - 1); - for (unsigned i = 0; i < 16; ++i) { - if ((RegListBits >> i) & 1) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - i))); - ++OpIdx; - } - } - - return true; -} - -// t2LDREX: Rd Rn -// t2LDREXD: Rd Rs Rn -// t2LDREXB, t2LDREXH: Rd Rn -// t2STREX: Rs Rd Rn -// t2STREXD: Rm Rd Rs Rn -// t2STREXB, t2STREXH: Rm Rd Rn -static bool DisassembleThumb2LdStEx(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 - && OpInfo[0].RegClass == ARM::GPRRegClassID - && OpInfo[1].RegClass == ARM::GPRRegClassID); - - bool isStore = (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH); - bool isSW = (Opcode == ARM::t2LDREX || Opcode == ARM::t2STREX); - bool isDW = (Opcode == ARM::t2LDREXD || Opcode == ARM::t2STREXD); - - // Add the destination operand for store. - if (isStore) { - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::GPRRegClassID, - isSW ? decodeRs(insn) : decodeRm(insn)))); - ++OpIdx; - } - - // Source operand for store and destination operand for load. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - ++OpIdx; - - // Thumb2 doubleword complication: with an extra source/destination operand. - if (isDW) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRs(insn)))); - ++OpIdx; - } - - // Finally add the pointer operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - - return true; -} - -// LLVM, as of Jan-05-2010, does not output <Rt2>, i.e., Rs, in the asm. -// Whereas the ARM Arch. Manual does not require that t2 = t+1 like in ARM ISA. -// -// t2LDRDi8: Rd Rs Rn imm8s4 (offset mode) -// t2LDRDpci: Rd Rs imm8s4 (Not decoded, prefer the generic t2LDRDi8 version) -// t2STRDi8: Rd Rs Rn imm8s4 (offset mode) -// -// Ditto for t2LDRD_PRE, t2LDRD_POST, t2STRD_PRE, t2STRD_POST, which are for -// disassembly only and do not have a tied_to writeback base register operand. -static bool DisassembleThumb2LdStDual(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 4 - && OpInfo[0].RegClass == ARM::GPRRegClassID - && OpInfo[1].RegClass == ARM::GPRRegClassID - && OpInfo[2].RegClass == ARM::GPRRegClassID - && OpInfo[3].RegClass == 0); - - // Add the <Rt> <Rt2> operands. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRs(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - - // Finally add (+/-)imm8*4, depending on the U bit. - int Offset = getImm8(insn) * 4; - if (getUBit(insn) == 0) - Offset = -Offset; - MI.addOperand(MCOperand::CreateImm(Offset)); - NumOpsAdded = 4; - - return true; -} - -// PC-based defined for Codegen, which do not get decoded by design: -// -// t2TBB, t2TBH: Rm immDontCare immDontCare -// -// Generic version defined for disassembly: -// -// t2TBBgen, t2TBHgen: Rn Rm Pred-Imm Pred-CCR -static bool DisassembleThumb2TB(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - assert(NumOps >= 2); - - // The generic version of TBB/TBH needs a base register. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - // Add the index register. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - NumOpsAdded = 2; - - return true; -} - -static inline bool Thumb2ShiftOpcode(unsigned Opcode) { - switch (Opcode) { - default: - return false; - case ARM::t2MOVCClsl: case ARM::t2MOVCClsr: - case ARM::t2MOVCCasr: case ARM::t2MOVCCror: - case ARM::t2LSLri: case ARM::t2LSRri: - case ARM::t2ASRri: case ARM::t2RORri: - return true; - } -} - -// A6.3.11 Data-processing (shifted register) -// -// Two register operands (Rn=0b1111 no 1st operand reg): Rs Rm -// Two register operands (Rs=0b1111 no dst operand reg): Rn Rm -// Three register operands: Rs Rn Rm -// Three register operands: (Rn=0b1111 Conditional Move) Rs Ro(TIED_TO) Rm -// -// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 -// register with shift forms: (Rm, ConstantShiftSpecifier). -// Constant shift specifier: Imm = (ShOp | ShAmt<<3). -// -// There are special instructions, like t2MOVsra_flag and t2MOVsrl_flag, which -// only require two register operands: Rd, Rm in ARM Reference Manual terms, and -// nothing else, because the shift amount is already specified. -// Similar case holds for t2MOVrx, t2ADDrr, ..., etc. -static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - // Special case handling. - if (Opcode == ARM::t2BR_JT) { - assert(NumOps == 4 - && OpInfo[0].RegClass == ARM::GPRRegClassID - && OpInfo[1].RegClass == ARM::GPRRegClassID - && OpInfo[2].RegClass == 0 - && OpInfo[3].RegClass == 0); - // Only need to populate the src reg operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - MI.addOperand(MCOperand::CreateReg(0)); - MI.addOperand(MCOperand::CreateImm(0)); - MI.addOperand(MCOperand::CreateImm(0)); - NumOpsAdded = 4; - return true; - } - - OpIdx = 0; - - assert(NumOps >= 2 - && OpInfo[0].RegClass == ARM::GPRRegClassID - && OpInfo[1].RegClass == ARM::GPRRegClassID); - - bool ThreeReg = (NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID); - bool NoDstReg = (decodeRs(insn) == 0xF); - - // Build the register operands, followed by the constant shift specifier. - - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::GPRRegClassID, - NoDstReg ? decodeRn(insn) : decodeRs(insn)))); - ++OpIdx; - - if (ThreeReg) { - int Idx; - if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { - // Process tied_to operand constraint. - MI.addOperand(MI.getOperand(Idx)); - } else { - assert(!NoDstReg); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - } - ++OpIdx; - } - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - ++OpIdx; - - if (NumOps == OpIdx) - return true; - - if (OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() - && !OpInfo[OpIdx].isOptionalDef()) { - - if (Thumb2ShiftOpcode(Opcode)) - MI.addOperand(MCOperand::CreateImm(getShiftAmtBits(insn))); - else { - // Build the constant shift specifier operand. - unsigned bits2 = getShiftTypeBits(insn); - unsigned imm5 = getShiftAmtBits(insn); - ARM_AM::ShiftOpc ShOp = ARM_AM::no_shift; - unsigned ShAmt = decodeImmShift(bits2, imm5, ShOp); - - // PKHBT/PKHTB are special in that we need the decodeImmShift() call to - // decode the shift amount from raw imm5 and bits2, but we DO NOT need - // to encode the ShOp, as it's in the asm string already. - if (Opcode == ARM::t2PKHBT || Opcode == ARM::t2PKHTB) - MI.addOperand(MCOperand::CreateImm(ShAmt)); - else - MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShAmt))); - } - ++OpIdx; - } - - return true; -} - -// A6.3.1 Data-processing (modified immediate) -// -// Two register operands: Rs Rn ModImm -// One register operands (Rs=0b1111 no explicit dest reg): Rn ModImm -// One register operands (Rn=0b1111 no explicit src reg): Rs ModImm - {t2MOVi, t2MVNi} -// -// ModImm = ThumbExpandImm(i:imm3:imm8) -static bool DisassembleThumb2DPModImm(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID); - - bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID); - bool NoDstReg = (decodeRs(insn) == 0xF); - - // Build the register operands, followed by the modified immediate. - - MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(ARM::GPRRegClassID, - NoDstReg ? decodeRn(insn) : decodeRs(insn)))); - ++OpIdx; - - if (TwoReg) { - assert(!NoDstReg); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - } - - // The modified immediate operand should come next. - assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 && - !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()); - - // i:imm3:imm8 - // A6.3.2 Modified immediate constants in Thumb instructions - unsigned imm12 = getIImm3Imm8(insn); - MI.addOperand(MCOperand::CreateImm(ThumbExpandImm(imm12))); - ++OpIdx; - - return true; -} - -static inline bool Thumb2SaturateOpcode(unsigned Opcode) { - switch (Opcode) { - case ARM::t2SSATlsl: case ARM::t2SSATasr: case ARM::t2SSAT16: - case ARM::t2USATlsl: case ARM::t2USATasr: case ARM::t2USAT16: - return true; - default: - return false; - } -} - -static inline unsigned decodeThumb2SaturatePos(unsigned Opcode, uint32_t insn) { - switch (Opcode) { - case ARM::t2SSATlsl: - case ARM::t2SSATasr: - return slice(insn, 4, 0) + 1; - case ARM::t2SSAT16: - return slice(insn, 3, 0) + 1; - case ARM::t2USATlsl: - case ARM::t2USATasr: - return slice(insn, 4, 0); - case ARM::t2USAT16: - return slice(insn, 3, 0); - default: - llvm_unreachable("Invalid opcode passed in"); - return 0; - } -} - -// A6.3.3 Data-processing (plain binary immediate) -// -// o t2ADDri12, t2SUBri12: Rs Rn imm12 -// o t2LEApcrel (ADR): Rs imm12 -// o t2BFC (BFC): Rs Ro(TIED_TO) bf_inv_mask_imm -// o t2BFI (BFI) (Currently not defined in LLVM as of Jan-07-2010) -// o t2MOVi16: Rs imm16 -// o t2MOVTi16: Rs imm16 -// o t2SBFX (SBFX): Rs Rn lsb width -// o t2UBFX (UBFX): Rs Rn lsb width -// o t2BFI (BFI): Rs Rn lsb width -// -// [Signed|Unsigned] Saturate [16] -// -// o t2SSAT[lsl|asr], t2USAT[lsl|asr]: Rs sat_pos Rn shamt -// o t2SSAT16, t2USAT16: Rs sat_pos Rn -static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID); - - bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID); - - // Build the register operand(s), followed by the immediate(s). - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRs(insn)))); - ++OpIdx; - - // t2SSAT/t2SSAT16/t2USAT/t2USAT16 has imm operand after Rd. - if (Thumb2SaturateOpcode(Opcode)) { - MI.addOperand(MCOperand::CreateImm(decodeThumb2SaturatePos(Opcode, insn))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - - if (Opcode == ARM::t2SSAT16 || Opcode == ARM::t2USAT16) { - OpIdx += 2; - return true; - } - - // For SSAT operand reg (Rn) has been disassembled above. - // Now disassemble the shift amount. - - // Inst{14-12:7-6} encodes the imm5 shift amount. - unsigned ShAmt = slice(insn, 14, 12) << 2 | slice(insn, 7, 6); - - MI.addOperand(MCOperand::CreateImm(ShAmt)); - - OpIdx += 3; - return true; - } - - if (TwoReg) { - assert(NumOps >= 3); - int Idx; - if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { - // Process tied_to operand constraint. - MI.addOperand(MI.getOperand(Idx)); - } else { - // Add src reg operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - } - ++OpIdx; - } - - assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() - && !OpInfo[OpIdx].isOptionalDef()); - - // Pre-increment OpIdx. - ++OpIdx; - - if (Opcode == ARM::t2ADDri12 || Opcode == ARM::t2SUBri12 - || Opcode == ARM::t2LEApcrel) - MI.addOperand(MCOperand::CreateImm(getIImm3Imm8(insn))); - else if (Opcode == ARM::t2MOVi16 || Opcode == ARM::t2MOVTi16) - MI.addOperand(MCOperand::CreateImm(getImm16(insn))); - else if (Opcode == ARM::t2BFC) - MI.addOperand(MCOperand::CreateImm(getBitfieldInvMask(insn))); - else { - // Handle the case of: lsb width - assert(Opcode == ARM::t2SBFX || Opcode == ARM::t2UBFX || - Opcode == ARM::t2BFI); - MI.addOperand(MCOperand::CreateImm(getLsb(insn))); - if (Opcode == ARM::t2BFI) { - assert(getMsb(insn) >= getLsb(insn)); - MI.addOperand(MCOperand::CreateImm(getMsb(insn) - getLsb(insn) + 1)); - } else - MI.addOperand(MCOperand::CreateImm(getWidthMinus1(insn) + 1)); - - ++OpIdx; - } - - return true; -} - -// A6.3.4 Table A6-15 Miscellaneous control instructions -// A8.6.41 DMB -// A8.6.42 DSB -// A8.6.49 ISB -static inline bool t2MiscCtrlInstr(uint32_t insn) { - if (slice(insn, 31, 20) == 0xf3b && slice(insn, 15, 14) == 2 && - slice(insn, 12, 12) == 0) - return true; - - return false; -} - -// A6.3.4 Branches and miscellaneous control -// -// A8.6.16 B -// Branches: t2B, t2Bcc -> imm operand -// -// Branches: t2TPsoft -> no operand -// -// A8.6.23 BL, BLX (immediate) -// Branches (defined in ARMInstrThumb.td): tBLr9, tBLXi_r9 -> imm operand -// -// A8.6.26 -// t2BXJ -> Rn -// -// Miscellaneous control: t2Int_MemBarrierV7 (and its t2DMB variants), -// t2Int_SyncBarrierV7 (and its t2DSB varianst), t2ISBsy, t2CLREX -// -> no operand (except pred-imm pred-ccr for CLREX, memory barrier variants) -// -// Hint: t2NOP, t2YIELD, t2WFE, t2WFI, t2SEV -// -> no operand (except pred-imm pred-ccr) -// -// t2DBG -> imm4 = Inst{3-0} -// -// t2MRS/t2MRSsys -> Rs -// t2MSR/t2MSRsys -> Rn mask=Inst{11-8} -// t2SMC -> imm4 = Inst{19-16} -static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - if (NumOps == 0) - return true; - - if (t2MiscCtrlInstr(insn)) - return true; - - switch (Opcode) { - case ARM::t2CLREX: - case ARM::t2NOP: - case ARM::t2YIELD: - case ARM::t2WFE: - case ARM::t2WFI: - case ARM::t2SEV: - return true; - default: - break; - } - - // CPS has a singleton $opt operand that contains the following information: - // opt{4-0} = mode from Inst{4-0} - // opt{5} = changemode from Inst{8} - // opt{8-6} = AIF from Inst{7-5} - // opt{10-9} = imod from Inst{10-9} with 0b10 as enable and 0b11 as disable - if (Opcode == ARM::t2CPS) { - unsigned Option = slice(insn, 4, 0) | slice(insn, 8, 8) << 5 | - slice(insn, 7, 5) << 6 | slice(insn, 10, 9) << 9; - MI.addOperand(MCOperand::CreateImm(Option)); - NumOpsAdded = 1; - return true; - } - - // DBG has its option specified in Inst{3-0}. - if (Opcode == ARM::t2DBG) { - MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 0))); - NumOpsAdded = 1; - return true; - } - - // MRS and MRSsys take one GPR reg Rs. - if (Opcode == ARM::t2MRS || Opcode == ARM::t2MRSsys) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRs(insn)))); - NumOpsAdded = 1; - return true; - } - // BXJ takes one GPR reg Rn. - if (Opcode == ARM::t2BXJ) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - NumOpsAdded = 1; - return true; - } - // MSR and MSRsys take one GPR reg Rn, followed by the mask. - if (Opcode == ARM::t2MSR || Opcode == ARM::t2MSRsys || Opcode == ARM::t2BXJ) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8))); - NumOpsAdded = 2; - return true; - } - // SMC take imm4. - if (Opcode == ARM::t2SMC) { - MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); - NumOpsAdded = 1; - return true; - } - - // Add the imm operand. - int Offset = 0; - - switch (Opcode) { - default: - assert(0 && "Unreachable code"); - case ARM::t2B: - Offset = decodeImm32_B_EncodingT4(insn); - break; - case ARM::t2Bcc: - Offset = decodeImm32_B_EncodingT3(insn); - break; - case ARM::tBLr9: - Offset = decodeImm32_BL(insn); - break; - case ARM::tBLXi_r9: - Offset = decodeImm32_BLX(insn); - break; - } - // When executing a Thumb instruction, PC reads as the address of the current - // instruction plus 4. The assembler subtracts 4 from the difference between - // the branch instruction and the target address, disassembler has to add 4 to - // to compensate. - MI.addOperand(MCOperand::CreateImm(Offset + 4)); - - NumOpsAdded = 1; - - return true; -} - -static inline bool Thumb2PreloadOpcode(unsigned Opcode) { - switch (Opcode) { - default: - return false; - case ARM::t2PLDi12: case ARM::t2PLDi8: case ARM::t2PLDpci: - case ARM::t2PLDr: case ARM::t2PLDs: - case ARM::t2PLDWi12: case ARM::t2PLDWi8: case ARM::t2PLDWpci: - case ARM::t2PLDWr: case ARM::t2PLDWs: - case ARM::t2PLIi12: case ARM::t2PLIi8: case ARM::t2PLIpci: - case ARM::t2PLIr: case ARM::t2PLIs: - return true; - } -} - -static bool DisassembleThumb2PreLoad(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - // Preload Data/Instruction requires either 2 or 3 operands. - // t2PLDi12, t2PLDi8, t2PLDpci: Rn [+/-]imm12/imm8 - // t2PLDr: Rn Rm - // t2PLDs: Rn Rm imm2=Inst{5-4} - // Same pattern applies for t2PLDW* and t2PLI*. - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 && - OpInfo[0].RegClass == ARM::GPRRegClassID); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - - if (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - } else { - assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() - && !OpInfo[OpIdx].isOptionalDef()); - int Offset = 0; - if (Opcode == ARM::t2PLDpci || Opcode == ARM::t2PLDWpci || - Opcode == ARM::t2PLIpci) { - bool Negative = slice(insn, 23, 23) == 0; - unsigned Imm12 = getImm12(insn); - Offset = Negative ? -1 - Imm12 : 1 * Imm12; - } else if (Opcode == ARM::t2PLDi8 || Opcode == ARM::t2PLDWi8 || - Opcode == ARM::t2PLIi8) { - // A8.6.117 Encoding T2: add = FALSE - unsigned Imm8 = getImm8(insn); - Offset = -1 - Imm8; - } else // The i12 forms. See, for example, A8.6.117 Encoding T1. - Offset = decodeImm12(insn); - MI.addOperand(MCOperand::CreateImm(Offset)); - } - ++OpIdx; - - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 && - !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { - // Fills in the shift amount for t2PLDs, t2PLDWs, t2PLIs. - MI.addOperand(MCOperand::CreateImm(slice(insn, 5, 4))); - ++OpIdx; - } - - return true; -} - -// A8.6.63 LDRB (literal) -// A8.6.79 LDRSB (literal) -// A8.6.75 LDRH (literal) -// A8.6.83 LDRSH (literal) -// A8.6.59 LDR (literal) -// -// These instrs calculate an address from the PC value and an immediate offset. -// Rd Rn=PC (+/-)imm12 (+ if Inst{23} == 0b1) -static bool DisassembleThumb2Ldpci(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 2 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass == 0); - - // Build the register operand, followed by the (+/-)imm12 immediate. - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - - MI.addOperand(MCOperand::CreateImm(decodeImm12(insn))); - - NumOpsAdded = 2; - - return true; -} - -// A6.3.10 Store single data item -// A6.3.9 Load byte, memory hints -// A6.3.8 Load halfword, memory hints -// A6.3.7 Load word -// -// For example, -// -// t2LDRi12: Rd Rn (+)imm12 -// t2LDRi8: Rd Rn (+/-)imm8 (+ if Inst{9} == 0b1) -// t2LDRs: Rd Rn Rm ConstantShiftSpecifier (see also DisassembleThumb2DPSoReg) -// t2LDR_POST: Rd Rn Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) -// t2LDR_PRE: Rd Rn Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) -// -// t2STRi12: Rd Rn (+)imm12 -// t2STRi8: Rd Rn (+/-)imm8 (+ if Inst{9} == 0b1) -// t2STRs: Rd Rn Rm ConstantShiftSpecifier (see also DisassembleThumb2DPSoReg) -// t2STR_POST: Rn Rd Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) -// t2STR_PRE: Rn Rd Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) -// -// Note that for indexed modes, the Rn(TIED_TO) operand needs to be populated -// correctly, as LLVM AsmPrinter depends on it. For indexed stores, the first -// operand is Rn; for all the other instructions, Rd is the first operand. -// -// Delegates to DisassembleThumb2PreLoad() for preload data/instruction. -// Delegates to DisassembleThumb2Ldpci() for load * literal operations. -static bool DisassembleThumb2LdSt(bool Load, MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { - - unsigned Rn = decodeRn(insn); - - if (Thumb2PreloadOpcode(Opcode)) - return DisassembleThumb2PreLoad(MI, Opcode, insn, NumOps, NumOpsAdded); - - // See, for example, A6.3.7 Load word: Table A6-18 Load word. - if (Load && Rn == 15) - return DisassembleThumb2Ldpci(MI, Opcode, insn, NumOps, NumOpsAdded); - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 3 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID); - - bool ThreeReg = (OpInfo[2].RegClass == ARM::GPRRegClassID); - bool TIED_TO = ThreeReg && TID.getOperandConstraint(2, TOI::TIED_TO) != -1; - bool Imm12 = !ThreeReg && slice(insn, 23, 23) == 1; // ARMInstrThumb2.td - - // Build the register operands, followed by the immediate. - unsigned R0, R1, R2 = 0; - unsigned Rd = decodeRd(insn); - int Imm = 0; - - if (!Load && TIED_TO) { - R0 = Rn; - R1 = Rd; - } else { - R0 = Rd; - R1 = Rn; - } - if (ThreeReg) { - if (TIED_TO) { - R2 = Rn; - Imm = decodeImm8(insn); - } else { - R2 = decodeRm(insn); - // See, for example, A8.6.64 LDRB (register). - // And ARMAsmPrinter::printT2AddrModeSoRegOperand(). - // LSL is the default shift opc, and LLVM does not expect it to be encoded - // as part of the immediate operand. - // Imm = ARM_AM::getSORegOpc(ARM_AM::lsl, slice(insn, 5, 4)); - Imm = slice(insn, 5, 4); - } - } else { - if (Imm12) - Imm = getImm12(insn); - else - Imm = decodeImm8(insn); - } - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, R0))); - ++OpIdx; - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, R1))); - ++OpIdx; - - if (ThreeReg) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,R2))); - ++OpIdx; - } - - assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() - && !OpInfo[OpIdx].isOptionalDef()); - - MI.addOperand(MCOperand::CreateImm(Imm)); - ++OpIdx; - - return true; -} - -// A6.3.12 Data-processing (register) -// -// Two register operands [rotate]: Rs Rm [rotation(= (rotate:'000'))] -// Three register operands only: Rs Rn Rm -// Three register operands [rotate]: Rs Rn Rm [rotation(= (rotate:'000'))] -// -// Parallel addition and subtraction 32-bit Thumb instructions: Rs Rn Rm -// -// Miscellaneous operations: Rs [Rn] Rm -static bool DisassembleThumb2DPReg(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetInstrDesc &TID = ARMInsts[Opcode]; - const TargetOperandInfo *OpInfo = TID.OpInfo; - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; - - assert(NumOps >= 2 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID); - - // Build the register operands, followed by the optional rotation amount. - - bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRs(insn)))); - ++OpIdx; - - if (ThreeReg) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - ++OpIdx; - } - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - ++OpIdx; - - if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 - && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { - // Add the rotation amount immediate. - MI.addOperand(MCOperand::CreateImm(decodeRotate(insn))); - ++OpIdx; - } - - return true; -} - -// A6.3.16 Multiply, multiply accumulate, and absolute difference -// -// t2MLA, t2MLS, t2SMMLA, t2SMMLS: Rs Rn Rm Ra=Inst{15-12} -// t2MUL, t2SMMUL: Rs Rn Rm -// t2SMLA[BB|BT|TB|TT|WB|WT]: Rs Rn Rm Ra=Inst{15-12} -// t2SMUL[BB|BT|TB|TT|WB|WT]: Rs Rn Rm -// -// Dual halfword multiply: t2SMUAD[X], t2SMUSD[X], t2SMLAD[X], t2SMLSD[X]: -// Rs Rn Rm Ra=Inst{15-12} -// -// Unsigned Sum of Absolute Differences [and Accumulate] -// Rs Rn Rm [Ra=Inst{15-12}] -static bool DisassembleThumb2Mul(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 3 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID && - OpInfo[2].RegClass == ARM::GPRRegClassID); - - // Build the register operands. - - bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID; - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRs(insn)))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - - if (FourReg) - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - - NumOpsAdded = FourReg ? 4 : 3; - - return true; -} - -// A6.3.17 Long multiply, long multiply accumulate, and divide -// -// t2SMULL, t2UMULL, t2SMLAL, t2UMLAL, t2UMAAL: RdLo RdHi Rn Rm -// where RdLo = Inst{15-12} and RdHi = Inst{11-8} -// -// Halfword multiple accumulate long: t2SMLAL<x><y>: RdLo RdHi Rn Rm -// where RdLo = Inst{15-12} and RdHi = Inst{11-8} -// -// Dual halfword multiple: t2SMLALD[X], t2SMLSLD[X]: RdLo RdHi Rn Rm -// where RdLo = Inst{15-12} and RdHi = Inst{11-8} -// -// Signed/Unsigned divide: t2SDIV, t2UDIV: Rs Rn Rm -static bool DisassembleThumb2LongMul(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - - assert(NumOps >= 3 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID && - OpInfo[2].RegClass == ARM::GPRRegClassID); - - bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID; - - // Build the register operands. - - if (FourReg) - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRd(insn)))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRs(insn)))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRn(insn)))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, - decodeRm(insn)))); - - if (FourReg) - NumOpsAdded = 4; - else - NumOpsAdded = 3; - - return true; -} - -// See A6.3 32-bit Thumb instruction encoding for instruction classes -// corresponding to (op1, op2, op). -// -// Table A6-9 32-bit Thumb instruction encoding -// op1 op2 op Instruction class, see -// --- ------- -- ------------------------------------------------------------ -// 01 00xx0xx - Load/store multiple on page A6-23 -// 00xx1xx - Load/store dual, load/store exclusive, table branch on page A6-24 -// 01xxxxx - Data-processing (shifted register) on page A6-31 -// 1xxxxxx - Coprocessor instructions on page A6-40 -// 10 x0xxxxx 0 Data-processing (modified immediate) on page A6-15 -// x1xxxxx 0 Data-processing (plain binary immediate) on page A6-19 -// - 1 Branches and miscellaneous control on page A6-20 -// 11 000xxx0 - Store single data item on page A6-30 -// 001xxx0 - Advanced SIMD element or structure load/store instructions on page A7-27 -// 00xx001 - Load byte, memory hints on page A6-28 -// 00xx011 - Load halfword, memory hints on page A6-26 -// 00xx101 - Load word on page A6-25 -// 00xx111 - UNDEFINED -// 010xxxx - Data-processing (register) on page A6-33 -// 0110xxx - Multiply, multiply accumulate, and absolute difference on page A6-38 -// 0111xxx - Long multiply, long multiply accumulate, and divide on page A6-39 -// 1xxxxxx - Coprocessor instructions on page A6-40 -// -static bool DisassembleThumb2(uint16_t op1, uint16_t op2, uint16_t op, - MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - switch (op1) { - case 1: - if (slice(op2, 6, 5) == 0) { - if (slice(op2, 2, 2) == 0) { - // Load/store multiple. - return DisassembleThumb2LdStMul(MI, Opcode, insn, NumOps, NumOpsAdded); - } - - // Load/store dual, load/store exclusive, table branch, otherwise. - assert(slice(op2, 2, 2) == 1); - if ((ARM::t2LDREX <= Opcode && Opcode <= ARM::t2LDREXH) || - (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH)) { - // Load/store exclusive. - return DisassembleThumb2LdStEx(MI, Opcode, insn, NumOps, NumOpsAdded); - } - if (Opcode == ARM::t2LDRDi8 || - Opcode == ARM::t2LDRD_PRE || Opcode == ARM::t2LDRD_POST || - Opcode == ARM::t2STRDi8 || - Opcode == ARM::t2STRD_PRE || Opcode == ARM::t2STRD_POST) { - // Load/store dual. - return DisassembleThumb2LdStDual(MI, Opcode, insn, NumOps, NumOpsAdded); - } - if (Opcode == ARM::t2TBBgen || Opcode == ARM::t2TBHgen) { - // Table branch. - return DisassembleThumb2TB(MI, Opcode, insn, NumOps, NumOpsAdded); - } - } else if (slice(op2, 6, 5) == 1) { - // Data-processing (shifted register). - return DisassembleThumb2DPSoReg(MI, Opcode, insn, NumOps, NumOpsAdded); - } - - // FIXME: A6.3.18 Coprocessor instructions - // But see ThumbDisassembler::getInstruction(). - - break; - case 2: - if (op == 0) { - if (slice(op2, 5, 5) == 0) { - // Data-processing (modified immediate) - return DisassembleThumb2DPModImm(MI, Opcode, insn, NumOps, NumOpsAdded); - } else { - // Data-processing (plain binary immediate) - return DisassembleThumb2DPBinImm(MI, Opcode, insn, NumOps, NumOpsAdded); - } - } else { - // Branches and miscellaneous control on page A6-20. - return DisassembleThumb2BrMiscCtrl(MI, Opcode, insn, NumOps, NumOpsAdded); - } - - break; - case 3: - switch (slice(op2, 6, 5)) { - case 0: - // Load/store instructions... - if (slice(op2, 0, 0) == 0) { - if (slice(op2, 4, 4) == 0) { - // Store single data item on page A6-30 - return DisassembleThumb2LdSt(false, MI,Opcode,insn,NumOps,NumOpsAdded); - } else { - // FIXME: Advanced SIMD element or structure load/store instructions. - // But see ThumbDisassembler::getInstruction(). - ; - } - } else { - // Table A6-9 32-bit Thumb instruction encoding: Load byte|halfword|word - return DisassembleThumb2LdSt(true, MI,Opcode,insn,NumOps,NumOpsAdded); - } - break; - case 1: - if (slice(op2, 4, 4) == 0) { - // A6.3.12 Data-processing (register) - return DisassembleThumb2DPReg(MI, Opcode, insn, NumOps, NumOpsAdded); - } else if (slice(op2, 3, 3) == 0) { - // A6.3.16 Multiply, multiply accumulate, and absolute difference - return DisassembleThumb2Mul(MI, Opcode, insn, NumOps, NumOpsAdded); - } else { - // A6.3.17 Long multiply, long multiply accumulate, and divide - return DisassembleThumb2LongMul(MI, Opcode, insn, NumOps, NumOpsAdded); - } - break; - default: - // FIXME: A6.3.18 Coprocessor instructions - // But see ThumbDisassembler::getInstruction(). - ; - break; - } - - break; - default: - assert(0 && "Encoding error for Thumb2 instruction!"); - break; - } - - return false; -} - -static bool DisassembleThumbFrm(MCInst &MI, unsigned Opcode, uint32_t insn, - unsigned short NumOps, unsigned &NumOpsAdded) { - - uint16_t HalfWord = slice(insn, 31, 16); - - if (HalfWord == 0) { - // A6.2 16-bit Thumb instruction encoding - // op = bits[15:10] - uint16_t op = slice(insn, 15, 10); - return DisassembleThumb1(op, MI, Opcode, insn, NumOps, NumOpsAdded); - } - - unsigned bits15_11 = slice(HalfWord, 15, 11); - - // A6.1 Thumb instruction set encoding - assert((bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F) && - "Bits [15:11] of first halfword of a Thumb2 instruction out of range"); - - // A6.3 32-bit Thumb instruction encoding - - uint16_t op1 = slice(HalfWord, 12, 11); - uint16_t op2 = slice(HalfWord, 10, 4); - uint16_t op = slice(insn, 15, 15); - - return DisassembleThumb2(op1, op2, op, MI, Opcode, insn, NumOps, NumOpsAdded); -} |