diff options
Diffstat (limited to 'lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp')
-rw-r--r-- | lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp | 3351 |
1 files changed, 3351 insertions, 0 deletions
diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp new file mode 100644 index 0000000000..c38a606c0a --- /dev/null +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp @@ -0,0 +1,3351 @@ +//===- 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; + retu |