X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FAsmParser%2FARMAsmParser.cpp;h=dec92512e061a172eeb36bdf23cb07455f773d18;hb=83ec87755ed4d07f6650d6727fb762052bd0041c;hp=bbeec1cac4381d0793f84c09f099f62f0c77898f;hpb=5de728cfe1a922ac9b13546dca94526b2fa693b6;p=oota-llvm.git diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index bbeec1cac43..dec92512e06 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -18,16 +18,18 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetAsmParser.h" -#include "llvm/Target/TargetRegistry.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" @@ -41,6 +43,36 @@ class ARMAsmParser : public MCTargetAsmParser { MCSubtargetInfo &STI; MCAsmParser &Parser; + struct { + ARMCC::CondCodes Cond; // Condition for IT block. + unsigned Mask:4; // Condition mask for instructions. + // Starting at first 1 (from lsb). + // '1' condition as indicated in IT. + // '0' inverse of condition (else). + // Count of instructions in IT block is + // 4 - trailingzeroes(mask) + + bool FirstCond; // Explicit flag for when we're parsing the + // First instruction in the IT block. It's + // implied in the mask, so needs special + // handling. + + unsigned CurPosition; // Current position in parsing of IT + // block. In range [0,3]. Initialized + // according to count of instructions in block. + // ~0U if no active IT block. + } ITState; + bool inITBlock() { return ITState.CurPosition != ~0U;} + void forwardITPosition() { + if (!inITBlock()) return; + // Move to the next instruction in the IT block, if there is one. If not, + // mark the block as done. + unsigned TZ = CountTrailingZeros_32(ITState.Mask); + if (++ITState.CurPosition == 5 - TZ) + ITState.CurPosition = ~0U; // Done with the IT block after this. + } + + MCAsmParser &getParser() const { return Parser; } MCAsmLexer &getLexer() const { return Parser.getLexer(); } @@ -51,24 +83,11 @@ class ARMAsmParser : public MCTargetAsmParser { bool tryParseRegisterWithWriteBack(SmallVectorImpl &); int tryParseShiftRegister(SmallVectorImpl &); bool parseRegisterList(SmallVectorImpl &); - bool parseMemory(SmallVectorImpl &, - ARMII::AddrMode AddrMode); + bool parseMemory(SmallVectorImpl &); bool parseOperand(SmallVectorImpl &, StringRef Mnemonic); bool parsePrefix(ARMMCExpr::VariantKind &RefKind); - const MCExpr *applyPrefixToExpr(const MCExpr *E, - MCSymbolRefExpr::VariantKind Variant); - - - bool parseMemoryOffsetReg(bool &Negative, - bool &OffsetRegShifted, - enum ARM_AM::ShiftOpc &ShiftType, - const MCExpr *&ShiftAmount, - const MCExpr *&Offset, - bool &OffsetIsReg, - int &OffsetRegNum, - SMLoc &E); - bool parseShift(enum ARM_AM::ShiftOpc &St, - const MCExpr *&ShiftAmount, SMLoc &E); + bool parseMemRegOffsetShift(ARM_AM::ShiftOpc &ShiftType, + unsigned &ShiftAmount); bool parseDirectiveWord(unsigned Size, SMLoc L); bool parseDirectiveThumb(SMLoc L); bool parseDirectiveThumbFunc(SMLoc L); @@ -76,7 +95,8 @@ class ARMAsmParser : public MCTargetAsmParser { bool parseDirectiveSyntax(SMLoc L); StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, - bool &CarrySetting, unsigned &ProcessorIMod); + bool &CarrySetting, unsigned &ProcessorIMod, + StringRef &ITMask); void getMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet, bool &CanAcceptPredicationCode); @@ -87,10 +107,22 @@ class ARMAsmParser : public MCTargetAsmParser { bool isThumbOne() const { return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2) == 0; } + bool isThumbTwo() const { + return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2); + } + bool hasV6Ops() const { + return STI.getFeatureBits() & ARM::HasV6Ops; + } + bool hasV7Ops() const { + return STI.getFeatureBits() & ARM::HasV7Ops; + } void SwitchMode() { unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb)); setAvailableFeatures(FB); } + bool isMClass() const { + return STI.getFeatureBits() & ARM::FeatureMClass; + } /// @name Auto-generated Match Functions /// { @@ -100,20 +132,19 @@ class ARMAsmParser : public MCTargetAsmParser { /// } + OperandMatchResultTy parseITCondCode(SmallVectorImpl&); OperandMatchResultTy parseCoprocNumOperand( SmallVectorImpl&); OperandMatchResultTy parseCoprocRegOperand( SmallVectorImpl&); + OperandMatchResultTy parseCoprocOptionOperand( + SmallVectorImpl&); OperandMatchResultTy parseMemBarrierOptOperand( SmallVectorImpl&); OperandMatchResultTy parseProcIFlagsOperand( SmallVectorImpl&); OperandMatchResultTy parseMSRMaskOperand( SmallVectorImpl&); - OperandMatchResultTy parseMemMode2Operand( - SmallVectorImpl&); - OperandMatchResultTy parseMemMode3Operand( - SmallVectorImpl&); OperandMatchResultTy parsePKHImm(SmallVectorImpl &O, StringRef Op, int Low, int High); OperandMatchResultTy parsePKHLSLImm(SmallVectorImpl &O) { @@ -125,28 +156,80 @@ class ARMAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseSetEndImm(SmallVectorImpl&); OperandMatchResultTy parseShifterImm(SmallVectorImpl&); OperandMatchResultTy parseRotImm(SmallVectorImpl&); + OperandMatchResultTy parseBitfield(SmallVectorImpl&); + OperandMatchResultTy parsePostIdxReg(SmallVectorImpl&); + OperandMatchResultTy parseAM3Offset(SmallVectorImpl&); + OperandMatchResultTy parseFPImm(SmallVectorImpl&); + OperandMatchResultTy parseVectorList(SmallVectorImpl&); // Asm Match Converter Methods + bool cvtT2LdrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtT2StrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtLdWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtStWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); bool cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, const SmallVectorImpl &); - bool cvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, + bool cvtLdWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode, const SmallVectorImpl &); - bool cvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode, + bool cvtStWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, const SmallVectorImpl &); bool cvtStWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode, const SmallVectorImpl &); - + bool cvtLdExtTWriteBackImm(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtLdExtTWriteBackReg(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtStExtTWriteBackImm(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtStExtTWriteBackReg(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtLdrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtStrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtThumbMultiply(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtVLDwbFixed(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtVLDwbRegister(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtVSTwbFixed(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); + bool cvtVSTwbRegister(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); bool validateInstruction(MCInst &Inst, const SmallVectorImpl &Ops); + bool processInstruction(MCInst &Inst, + const SmallVectorImpl &Ops); + bool shouldOmitCCOutOperand(StringRef Mnemonic, + SmallVectorImpl &Operands); public: + enum ARMMatchResultTy { + Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY, + Match_RequiresNotITBlock, + Match_RequiresV6, + Match_RequiresThumb2 + }; + ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser) : MCTargetAsmParser(), STI(_STI), Parser(_Parser) { MCAsmParserExtension::Initialize(_Parser); // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + + // Not in an ITBlock to start with. + ITState.CurPosition = ~0U; } // Implementation of the MCTargetAsmParser interface: @@ -155,6 +238,8 @@ public: SmallVectorImpl &Operands); bool ParseDirective(AsmToken DirectiveID); + unsigned checkTargetMatchPredicate(MCInst &Inst); + bool MatchAndEmitInstruction(SMLoc IDLoc, SmallVectorImpl &Operands, MCStreamer &Out); @@ -167,24 +252,31 @@ namespace { /// instruction. class ARMOperand : public MCParsedAsmOperand { enum KindTy { - CondCode, - CCOut, - CoprocNum, - CoprocReg, - Immediate, - MemBarrierOpt, - Memory, - MSRMask, - ProcIFlags, - Register, - RegisterList, - DPRRegisterList, - SPRRegisterList, - ShiftedRegister, - ShiftedImmediate, - ShifterImmediate, - RotateImmediate, - Token + k_CondCode, + k_CCOut, + k_ITCondMask, + k_CoprocNum, + k_CoprocReg, + k_CoprocOption, + k_Immediate, + k_FPImmediate, + k_MemBarrierOpt, + k_Memory, + k_PostIndexRegister, + k_MSRMask, + k_ProcIFlags, + k_VectorIndex, + k_Register, + k_RegisterList, + k_DPRRegisterList, + k_SPRRegisterList, + k_VectorList, + k_ShiftedRegister, + k_ShiftedImmediate, + k_ShifterImmediate, + k_RotateImmediate, + k_BitfieldDescriptor, + k_Token } Kind; SMLoc StartLoc, EndLoc; @@ -196,12 +288,20 @@ class ARMOperand : public MCParsedAsmOperand { } CC; struct { - ARM_MB::MemBOpt Val; - } MBOpt; + unsigned Val; + } Cop; struct { unsigned Val; - } Cop; + } CoprocOption; + + struct { + unsigned Mask:4; + } ITMask; + + struct { + ARM_MB::MemBOpt Val; + } MBOpt; struct { ARM_PROC::IFlags Val; @@ -220,27 +320,44 @@ class ARMOperand : public MCParsedAsmOperand { unsigned RegNum; } Reg; + // A vector register list is a sequential list of 1 to 4 registers. + struct { + unsigned RegNum; + unsigned Count; + } VectorList; + + struct { + unsigned Val; + } VectorIndex; + struct { const MCExpr *Val; } Imm; + struct { + unsigned Val; // encoded 8-bit representation + } FPImm; + /// Combined record for all forms of ARM address expressions. struct { - ARMII::AddrMode AddrMode; unsigned BaseRegNum; - union { - unsigned RegNum; ///< Offset register num, when OffsetIsReg. - const MCExpr *Value; ///< Offset value, when !OffsetIsReg. - } Offset; - const MCExpr *ShiftAmount; // used when OffsetRegShifted is true - enum ARM_AM::ShiftOpc ShiftType; // used when OffsetRegShifted is true - unsigned OffsetRegShifted : 1; // only used when OffsetIsReg is true - unsigned Preindexed : 1; - unsigned Postindexed : 1; - unsigned OffsetIsReg : 1; - unsigned Negative : 1; // only used when OffsetIsReg is true - unsigned Writeback : 1; - } Mem; + // Offset is in OffsetReg or OffsetImm. If both are zero, no offset + // was specified. + const MCConstantExpr *OffsetImm; // Offset immediate value + unsigned OffsetRegNum; // Offset register num, when OffsetImm == NULL + ARM_AM::ShiftOpc ShiftType; // Shift type for OffsetReg + unsigned ShiftImm; // shift for OffsetReg. + unsigned Alignment; // 0 = no alignment specified + // n = alignment in bytes (8, 16, or 32) + unsigned isNegative : 1; // Negated OffsetReg? (~'U' bit) + } Memory; + + struct { + unsigned RegNum; + bool isAdd; + ARM_AM::ShiftOpc ShiftTy; + unsigned ShiftImm; + } PostIdxReg; struct { bool isASR; @@ -260,6 +377,10 @@ class ARMOperand : public MCParsedAsmOperand { struct { unsigned Imm; } RotImm; + struct { + unsigned LSB; + unsigned Width; + } Bitfield; }; ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} @@ -269,52 +390,73 @@ public: StartLoc = o.StartLoc; EndLoc = o.EndLoc; switch (Kind) { - case CondCode: + case k_CondCode: CC = o.CC; break; - case Token: + case k_ITCondMask: + ITMask = o.ITMask; + break; + case k_Token: Tok = o.Tok; break; - case CCOut: - case Register: + case k_CCOut: + case k_Register: Reg = o.Reg; break; - case RegisterList: - case DPRRegisterList: - case SPRRegisterList: + case k_RegisterList: + case k_DPRRegisterList: + case k_SPRRegisterList: Registers = o.Registers; break; - case CoprocNum: - case CoprocReg: + case k_VectorList: + VectorList = o.VectorList; + break; + case k_CoprocNum: + case k_CoprocReg: Cop = o.Cop; break; - case Immediate: + case k_CoprocOption: + CoprocOption = o.CoprocOption; + break; + case k_Immediate: Imm = o.Imm; break; - case MemBarrierOpt: + case k_FPImmediate: + FPImm = o.FPImm; + break; + case k_MemBarrierOpt: MBOpt = o.MBOpt; break; - case Memory: - Mem = o.Mem; + case k_Memory: + Memory = o.Memory; break; - case MSRMask: + case k_PostIndexRegister: + PostIdxReg = o.PostIdxReg; + break; + case k_MSRMask: MMask = o.MMask; break; - case ProcIFlags: + case k_ProcIFlags: IFlags = o.IFlags; break; - case ShifterImmediate: + case k_ShifterImmediate: ShifterImm = o.ShifterImm; break; - case ShiftedRegister: + case k_ShiftedRegister: RegShiftedReg = o.RegShiftedReg; break; - case ShiftedImmediate: + case k_ShiftedImmediate: RegShiftedImm = o.RegShiftedImm; break; - case RotateImmediate: + case k_RotateImmediate: RotImm = o.RotImm; break; + case k_BitfieldDescriptor: + Bitfield = o.Bitfield; + break; + case k_VectorIndex: + VectorIndex = o.VectorIndex; + break; } } @@ -324,94 +466,96 @@ public: SMLoc getEndLoc() const { return EndLoc; } ARMCC::CondCodes getCondCode() const { - assert(Kind == CondCode && "Invalid access!"); + assert(Kind == k_CondCode && "Invalid access!"); return CC.Val; } unsigned getCoproc() const { - assert((Kind == CoprocNum || Kind == CoprocReg) && "Invalid access!"); + assert((Kind == k_CoprocNum || Kind == k_CoprocReg) && "Invalid access!"); return Cop.Val; } StringRef getToken() const { - assert(Kind == Token && "Invalid access!"); + assert(Kind == k_Token && "Invalid access!"); return StringRef(Tok.Data, Tok.Length); } unsigned getReg() const { - assert((Kind == Register || Kind == CCOut) && "Invalid access!"); + assert((Kind == k_Register || Kind == k_CCOut) && "Invalid access!"); return Reg.RegNum; } const SmallVectorImpl &getRegList() const { - assert((Kind == RegisterList || Kind == DPRRegisterList || - Kind == SPRRegisterList) && "Invalid access!"); + assert((Kind == k_RegisterList || Kind == k_DPRRegisterList || + Kind == k_SPRRegisterList) && "Invalid access!"); return Registers; } const MCExpr *getImm() const { - assert(Kind == Immediate && "Invalid access!"); + assert(Kind == k_Immediate && "Invalid access!"); return Imm.Val; } + unsigned getFPImm() const { + assert(Kind == k_FPImmediate && "Invalid access!"); + return FPImm.Val; + } + + unsigned getVectorIndex() const { + assert(Kind == k_VectorIndex && "Invalid access!"); + return VectorIndex.Val; + } + ARM_MB::MemBOpt getMemBarrierOpt() const { - assert(Kind == MemBarrierOpt && "Invalid access!"); + assert(Kind == k_MemBarrierOpt && "Invalid access!"); return MBOpt.Val; } ARM_PROC::IFlags getProcIFlags() const { - assert(Kind == ProcIFlags && "Invalid access!"); + assert(Kind == k_ProcIFlags && "Invalid access!"); return IFlags.Val; } unsigned getMSRMask() const { - assert(Kind == MSRMask && "Invalid access!"); + assert(Kind == k_MSRMask && "Invalid access!"); return MMask.Val; } - /// @name Memory Operand Accessors - /// @{ - ARMII::AddrMode getMemAddrMode() const { - return Mem.AddrMode; - } - unsigned getMemBaseRegNum() const { - return Mem.BaseRegNum; - } - unsigned getMemOffsetRegNum() const { - assert(Mem.OffsetIsReg && "Invalid access!"); - return Mem.Offset.RegNum; - } - const MCExpr *getMemOffset() const { - assert(!Mem.OffsetIsReg && "Invalid access!"); - return Mem.Offset.Value; - } - unsigned getMemOffsetRegShifted() const { - assert(Mem.OffsetIsReg && "Invalid access!"); - return Mem.OffsetRegShifted; + bool isCoprocNum() const { return Kind == k_CoprocNum; } + bool isCoprocReg() const { return Kind == k_CoprocReg; } + bool isCoprocOption() const { return Kind == k_CoprocOption; } + bool isCondCode() const { return Kind == k_CondCode; } + bool isCCOut() const { return Kind == k_CCOut; } + bool isITMask() const { return Kind == k_ITCondMask; } + bool isITCondCode() const { return Kind == k_CondCode; } + bool isImm() const { return Kind == k_Immediate; } + bool isFPImm() const { return Kind == k_FPImmediate; } + bool isImm8s4() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ((Value & 3) == 0) && Value >= -1020 && Value <= 1020; } - const MCExpr *getMemShiftAmount() const { - assert(Mem.OffsetIsReg && Mem.OffsetRegShifted && "Invalid access!"); - return Mem.ShiftAmount; + bool isImm0_1020s4() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ((Value & 3) == 0) && Value >= 0 && Value <= 1020; } - enum ARM_AM::ShiftOpc getMemShiftType() const { - assert(Mem.OffsetIsReg && Mem.OffsetRegShifted && "Invalid access!"); - return Mem.ShiftType; + bool isImm0_508s4() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ((Value & 3) == 0) && Value >= 0 && Value <= 508; } - bool getMemPreindexed() const { return Mem.Preindexed; } - bool getMemPostindexed() const { return Mem.Postindexed; } - bool getMemOffsetIsReg() const { return Mem.OffsetIsReg; } - bool getMemNegative() const { return Mem.Negative; } - bool getMemWriteback() const { return Mem.Writeback; } - - /// @} - - bool isCoprocNum() const { return Kind == CoprocNum; } - bool isCoprocReg() const { return Kind == CoprocReg; } - bool isCondCode() const { return Kind == CondCode; } - bool isCCOut() const { return Kind == CCOut; } - bool isImm() const { return Kind == Immediate; } bool isImm0_255() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; @@ -419,7 +563,7 @@ public: return Value >= 0 && Value < 256; } bool isImm0_7() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; @@ -427,7 +571,7 @@ public: return Value >= 0 && Value < 8; } bool isImm0_15() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; @@ -435,7 +579,7 @@ public: return Value >= 0 && Value < 16; } bool isImm0_31() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; @@ -443,7 +587,7 @@ public: return Value >= 0 && Value < 32; } bool isImm1_16() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; @@ -451,15 +595,23 @@ public: return Value > 0 && Value < 17; } bool isImm1_32() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value < 33; } + bool isImm0_32() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return Value >= 0 && Value < 33; + } bool isImm0_65535() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; @@ -467,7 +619,7 @@ public: return Value >= 0 && Value < 65536; } bool isImm0_65535Expr() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // If it's not a constant expression, it'll generate a fixup and be @@ -477,15 +629,23 @@ public: return Value >= 0 && Value < 65536; } bool isImm24bit() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value <= 0xffffff; } + bool isImmThumbSR() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return Value > 0 && Value < 33; + } bool isPKHLSLImm() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; @@ -493,7 +653,7 @@ public: return Value >= 0 && Value < 32; } bool isPKHASRImm() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; @@ -501,132 +661,391 @@ public: return Value > 0 && Value <= 32; } bool isARMSOImm() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return ARM_AM::getSOImmVal(Value) != -1; } + bool isARMSOImmNot() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ARM_AM::getSOImmVal(~Value) != -1; + } bool isT2SOImm() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return ARM_AM::getT2SOImmVal(Value) != -1; } + bool isT2SOImmNot() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ARM_AM::getT2SOImmVal(~Value) != -1; + } bool isSetEndImm() const { - if (Kind != Immediate) + if (Kind != k_Immediate) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value == 1 || Value == 0; } - bool isReg() const { return Kind == Register; } - bool isRegList() const { return Kind == RegisterList; } - bool isDPRRegList() const { return Kind == DPRRegisterList; } - bool isSPRRegList() const { return Kind == SPRRegisterList; } - bool isToken() const { return Kind == Token; } - bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; } - bool isMemory() const { return Kind == Memory; } - bool isShifterImm() const { return Kind == ShifterImmediate; } - bool isRegShiftedReg() const { return Kind == ShiftedRegister; } - bool isRegShiftedImm() const { return Kind == ShiftedImmediate; } - bool isRotImm() const { return Kind == RotateImmediate; } - bool isMemMode2() const { - if (getMemAddrMode() != ARMII::AddrMode2) + bool isReg() const { return Kind == k_Register; } + bool isRegList() const { return Kind == k_RegisterList; } + bool isDPRRegList() const { return Kind == k_DPRRegisterList; } + bool isSPRRegList() const { return Kind == k_SPRRegisterList; } + bool isToken() const { return Kind == k_Token; } + bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; } + bool isMemory() const { return Kind == k_Memory; } + bool isShifterImm() const { return Kind == k_ShifterImmediate; } + bool isRegShiftedReg() const { return Kind == k_ShiftedRegister; } + bool isRegShiftedImm() const { return Kind == k_ShiftedImmediate; } + bool isRotImm() const { return Kind == k_RotateImmediate; } + bool isBitfield() const { return Kind == k_BitfieldDescriptor; } + bool isPostIdxRegShifted() const { return Kind == k_PostIndexRegister; } + bool isPostIdxReg() const { + return Kind == k_PostIndexRegister && PostIdxReg.ShiftTy == ARM_AM::no_shift; + } + bool isMemNoOffset(bool alignOK = false) const { + if (!isMemory()) return false; - - if (getMemOffsetIsReg()) - return true; - - if (getMemNegative() && - !(getMemPostindexed() || getMemPreindexed())) + // No offset of any kind. + return Memory.OffsetRegNum == 0 && Memory.OffsetImm == 0 && + (alignOK || Memory.Alignment == 0); + } + bool isAlignedMemory() const { + return isMemNoOffset(true); + } + bool isAddrMode2() const { + if (!isMemory() || Memory.Alignment != 0) return false; + // Check for register offset. + if (Memory.OffsetRegNum) return true; + // Immediate offset in range [-4095, 4095]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val > -4096 && Val < 4096; + } + bool isAM2OffsetImm() const { + if (Kind != k_Immediate) return false; - - const MCConstantExpr *CE = dyn_cast(getMemOffset()); + // Immediate offset in range [-4095, 4095]. + const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; - int64_t Value = CE->getValue(); - - // The offset must be in the range 0-4095 (imm12). - if (Value > 4095 || Value < -4095) + int64_t Val = CE->getValue(); + return Val > -4096 && Val < 4096; + } + bool isAddrMode3() const { + if (!isMemory() || Memory.Alignment != 0) return false; + // No shifts are legal for AM3. + if (Memory.ShiftType != ARM_AM::no_shift) return false; + // Check for register offset. + if (Memory.OffsetRegNum) return true; + // Immediate offset in range [-255, 255]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val > -256 && Val < 256; + } + bool isAM3Offset() const { + if (Kind != k_Immediate && Kind != k_PostIndexRegister) + return false; + if (Kind == k_PostIndexRegister) + return PostIdxReg.ShiftTy == ARM_AM::no_shift; + // Immediate offset in range [-255, 255]. + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Val = CE->getValue(); + // Special case, #-0 is INT32_MIN. + return (Val > -256 && Val < 256) || Val == INT32_MIN; + } + bool isAddrMode5() const { + // If we have an immediate that's not a constant, treat it as a label + // reference needing a fixup. If it is a constant, it's something else + // and we reject it. + if (Kind == k_Immediate && !isa(getImm())) + return true; + if (!isMemory() || Memory.Alignment != 0) return false; + // Check for register offset. + if (Memory.OffsetRegNum) return false; + // Immediate offset in range [-1020, 1020] and a multiple of 4. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return (Val >= -1020 && Val <= 1020 && ((Val & 3) == 0)) || + Val == INT32_MIN; + } + bool isMemTBB() const { + if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative || + Memory.ShiftType != ARM_AM::no_shift || Memory.Alignment != 0) return false; - return true; } - bool isMemMode3() const { - if (getMemAddrMode() != ARMII::AddrMode3) + bool isMemTBH() const { + if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative || + Memory.ShiftType != ARM_AM::lsl || Memory.ShiftImm != 1 || + Memory.Alignment != 0 ) return false; - - if (getMemOffsetIsReg()) { - if (getMemOffsetRegShifted()) - return false; // No shift with offset reg allowed + return true; + } + bool isMemRegOffset() const { + if (!isMemory() || !Memory.OffsetRegNum || Memory.Alignment != 0) + return false; + return true; + } + bool isT2MemRegOffset() const { + if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative || + Memory.Alignment != 0) + return false; + // Only lsl #{0, 1, 2, 3} allowed. + if (Memory.ShiftType == ARM_AM::no_shift) return true; - } - - if (getMemNegative() && - !(getMemPostindexed() || getMemPreindexed())) + if (Memory.ShiftType != ARM_AM::lsl || Memory.ShiftImm > 3) + return false; + return true; + } + bool isMemThumbRR() const { + // Thumb reg+reg addressing is simple. Just two registers, a base and + // an offset. No shifts, negations or any other complicating factors. + if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative || + Memory.ShiftType != ARM_AM::no_shift || Memory.Alignment != 0) + return false; + return isARMLowRegister(Memory.BaseRegNum) && + (!Memory.OffsetRegNum || isARMLowRegister(Memory.OffsetRegNum)); + } + bool isMemThumbRIs4() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || + !isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0) + return false; + // Immediate offset, multiple of 4 in range [0, 124]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val >= 0 && Val <= 124 && (Val % 4) == 0; + } + bool isMemThumbRIs2() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || + !isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0) + return false; + // Immediate offset, multiple of 4 in range [0, 62]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val >= 0 && Val <= 62 && (Val % 2) == 0; + } + bool isMemThumbRIs1() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || + !isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0) + return false; + // Immediate offset in range [0, 31]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val >= 0 && Val <= 31; + } + bool isMemThumbSPI() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || + Memory.BaseRegNum != ARM::SP || Memory.Alignment != 0) + return false; + // Immediate offset, multiple of 4 in range [0, 1020]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val >= 0 && Val <= 1020 && (Val % 4) == 0; + } + bool isMemImm8s4Offset() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) + return false; + // Immediate offset a multiple of 4 in range [-1020, 1020]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val >= -1020 && Val <= 1020 && (Val & 3) == 0; + } + bool isMemImm0_1020s4Offset() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) + return false; + // Immediate offset a multiple of 4 in range [0, 1020]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val >= 0 && Val <= 1020 && (Val & 3) == 0; + } + bool isMemImm8Offset() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) + return false; + // Immediate offset in range [-255, 255]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return (Val == INT32_MIN) || (Val > -256 && Val < 256); + } + bool isMemPosImm8Offset() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) + return false; + // Immediate offset in range [0, 255]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val >= 0 && Val < 256; + } + bool isMemNegImm8Offset() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) + return false; + // Immediate offset in range [-255, -1]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return Val > -256 && Val < 0; + } + bool isMemUImm12Offset() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; + // Immediate offset in range [0, 4095]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return (Val >= 0 && Val < 4096); + } + bool isMemImm12Offset() const { + // If we have an immediate that's not a constant, treat it as a label + // reference needing a fixup. If it is a constant, it's something else + // and we reject it. + if (Kind == k_Immediate && !isa(getImm())) + return true; - const MCConstantExpr *CE = dyn_cast(getMemOffset()); + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) + return false; + // Immediate offset in range [-4095, 4095]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return (Val > -4096 && Val < 4096) || (Val == INT32_MIN); + } + bool isPostIdxImm8() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; - int64_t Value = CE->getValue(); - - // The offset must be in the range 0-255 (imm8). - if (Value > 255 || Value < -255) + int64_t Val = CE->getValue(); + return (Val > -256 && Val < 256) || (Val == INT32_MIN); + } + bool isPostIdxImm8s4() const { + if (Kind != k_Immediate) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Val = CE->getValue(); + return ((Val & 3) == 0 && Val >= -1020 && Val <= 1020) || + (Val == INT32_MIN); + } - return true; + bool isMSRMask() const { return Kind == k_MSRMask; } + bool isProcIFlags() const { return Kind == k_ProcIFlags; } + + // NEON operands. + bool isVecListOneD() const { + if (Kind != k_VectorList) return false; + return VectorList.Count == 1; } - bool isMemMode5() const { - if (!isMemory() || getMemOffsetIsReg() || getMemWriteback() || - getMemNegative()) - return false; - const MCConstantExpr *CE = dyn_cast(getMemOffset()); - if (!CE) return false; + bool isVecListTwoD() const { + if (Kind != k_VectorList) return false; + return VectorList.Count == 2; + } - // The offset must be a multiple of 4 in the range 0-1020. - int64_t Value = CE->getValue(); - return ((Value & 0x3) == 0 && Value <= 1020 && Value >= -1020); - } - bool isMemMode7() const { - if (!isMemory() || - getMemPreindexed() || - getMemPostindexed() || - getMemOffsetIsReg() || - getMemNegative() || - getMemWriteback()) - return false; + bool isVecListThreeD() const { + if (Kind != k_VectorList) return false; + return VectorList.Count == 3; + } - const MCConstantExpr *CE = dyn_cast(getMemOffset()); - if (!CE) return false; + bool isVecListFourD() const { + if (Kind != k_VectorList) return false; + return VectorList.Count == 4; + } - if (CE->getValue()) - return false; + bool isVecListTwoQ() const { + if (Kind != k_VectorList) return false; + //FIXME: We haven't taught the parser to handle by-two register lists + // yet, so don't pretend to know one. + return VectorList.Count == 2 && false; + } - return true; + bool isVectorIndex8() const { + if (Kind != k_VectorIndex) return false; + return VectorIndex.Val < 8; + } + bool isVectorIndex16() const { + if (Kind != k_VectorIndex) return false; + return VectorIndex.Val < 4; } - bool isMemModeRegThumb() const { - if (!isMemory() || !getMemOffsetIsReg() || getMemWriteback()) + bool isVectorIndex32() const { + if (Kind != k_VectorIndex) return false; + return VectorIndex.Val < 2; + } + + bool isNEONi8splat() const { + if (Kind != k_Immediate) return false; - return true; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. + if (!CE) return false; + int64_t Value = CE->getValue(); + // i8 value splatted across 8 bytes. The immediate is just the 8 byte + // value. + return Value >= 0 && Value < 256; } - bool isMemModeImmThumb() const { - if (!isMemory() || getMemOffsetIsReg() || getMemWriteback()) + + bool isNEONi16splat() const { + if (Kind != k_Immediate) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. + if (!CE) return false; + int64_t Value = CE->getValue(); + // i16 value in the range [0,255] or [0x0100, 0xff00] + return (Value >= 0 && Value < 256) || (Value >= 0x0100 && Value <= 0xff00); + } - const MCConstantExpr *CE = dyn_cast(getMemOffset()); + bool isNEONi32splat() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. if (!CE) return false; + int64_t Value = CE->getValue(); + // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X. + return (Value >= 0 && Value < 256) || + (Value >= 0x0100 && Value <= 0xff00) || + (Value >= 0x010000 && Value <= 0xff0000) || + (Value >= 0x01000000 && Value <= 0xff000000); + } - // The offset must be a multiple of 4 in the range 0-124. + bool isNEONi32vmov() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. + if (!CE) return false; + int64_t Value = CE->getValue(); + // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X, + // for VMOV/VMVN only, 00Xf or 0Xff are also accepted. + return (Value >= 0 && Value < 256) || + (Value >= 0x0100 && Value <= 0xff00) || + (Value >= 0x010000 && Value <= 0xff0000) || + (Value >= 0x01000000 && Value <= 0xff000000) || + (Value >= 0x01ff && Value <= 0xffff && (Value & 0xff) == 0xff) || + (Value >= 0x01ffff && Value <= 0xffffff && (Value & 0xffff) == 0xffff); + } + + bool isNEONi64splat() const { + if (Kind != k_Immediate) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. + if (!CE) return false; uint64_t Value = CE->getValue(); - return ((Value & 0x3) == 0 && Value <= 124); + // i64 value with each byte being either 0 or 0xff. + for (unsigned i = 0; i < 8; ++i) + if ((Value & 0xff) != 0 && (Value & 0xff) != 0xff) return false; + return true; } - bool isMSRMask() const { return Kind == MSRMask; } - bool isProcIFlags() const { return Kind == ProcIFlags; } void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediates when possible. Null MCExpr = 0. @@ -655,6 +1074,21 @@ public: Inst.addOperand(MCOperand::CreateImm(getCoproc())); } + void addCoprocOptionOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(CoprocOption.Val)); + } + + void addITMaskOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(ITMask.Mask)); + } + + void addITCondCodeOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode()))); + } + void addCCOutOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(getReg())); @@ -682,7 +1116,6 @@ public: ARM_AM::getSORegOpc(RegShiftedImm.ShiftTy, RegShiftedImm.ShiftImm))); } - void addShifterImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateImm((ShifterImm.isASR << 5) | @@ -711,11 +1144,51 @@ public: Inst.addOperand(MCOperand::CreateImm(RotImm.Imm >> 3)); } + void addBitfieldOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // Munge the lsb/width into a bitfield mask. + unsigned lsb = Bitfield.LSB; + unsigned width = Bitfield.Width; + // Make a 32-bit mask w/ the referenced bits clear and all other bits set. + uint32_t Mask = ~(((uint32_t)0xffffffff >> lsb) << (32 - width) >> + (32 - (lsb + width))); + Inst.addOperand(MCOperand::CreateImm(Mask)); + } + void addImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); } + void addFPImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(getFPImm())); + } + + void addImm8s4Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // FIXME: We really want to scale the value here, but the LDRD/STRD + // instruction don't encode operands that way yet. + const MCConstantExpr *CE = dyn_cast(getImm()); + Inst.addOperand(MCOperand::CreateImm(CE->getValue())); + } + + void addImm0_1020s4Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The immediate is scaled by four in the encoding and is stored + // in the MCInst as such. Lop off the low two bits here. + const MCConstantExpr *CE = dyn_cast(getImm()); + Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4)); + } + + void addImm0_508s4Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The immediate is scaled by four in the encoding and is stored + // in the MCInst as such. Lop off the low two bits here. + const MCConstantExpr *CE = dyn_cast(getImm()); + Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4)); + } + void addImm0_255Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); @@ -752,6 +1225,11 @@ public: Inst.addOperand(MCOperand::CreateImm(CE->getValue() - 1)); } + void addImm0_32Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + void addImm0_65535Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); @@ -767,6 +1245,15 @@ public: addExpr(Inst, getImm()); } + void addImmThumbSROperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The constant encodes as the immediate, except for 32, which encodes as + // zero. + const MCConstantExpr *CE = dyn_cast(getImm()); + unsigned Imm = CE->getValue(); + Inst.addOperand(MCOperand::CreateImm((Imm == 32 ? 0 : Imm))); + } + void addPKHLSLImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); @@ -791,6 +1278,22 @@ public: addExpr(Inst, getImm()); } + void addT2SOImmNotOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The operand is actually a t2_so_imm, but we have its bitwise + // negation in the assembly source, so twiddle it here. + const MCConstantExpr *CE = dyn_cast(getImm()); + Inst.addOperand(MCOperand::CreateImm(~CE->getValue())); + } + + void addARMSOImmNotOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The operand is actually a so_imm, but we have its bitwise + // negation in the assembly source, so twiddle it here. + const MCConstantExpr *CE = dyn_cast(getImm()); + Inst.addOperand(MCOperand::CreateImm(~CE->getValue())); + } + void addSetEndImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); @@ -801,122 +1304,274 @@ public: Inst.addOperand(MCOperand::CreateImm(unsigned(getMemBarrierOpt()))); } - void addMemMode7Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && isMemMode7() && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBaseRegNum())); - - const MCConstantExpr *CE = dyn_cast(getMemOffset()); - (void)CE; - assert((CE || CE->getValue() == 0) && - "No offset operand support in mode 7"); + void addMemNoOffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); } - void addMemMode2Operands(MCInst &Inst, unsigned N) const { - assert(isMemMode2() && "Invalid mode or number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBaseRegNum())); - unsigned IdxMode = (getMemPreindexed() | getMemPostindexed() << 1); + void addAlignedMemoryOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Memory.Alignment)); + } - if (getMemOffsetIsReg()) { - Inst.addOperand(MCOperand::CreateReg(getMemOffsetRegNum())); + void addAddrMode2Operands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + if (!Memory.OffsetRegNum) { + ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; + // Special case for #-0 + if (Val == INT32_MIN) Val = 0; + if (Val < 0) Val = -Val; + Val = ARM_AM::getAM2Opc(AddSub, Val, ARM_AM::no_shift); + } else { + // For register offset, we encode the shift type and negation flag + // here. + Val = ARM_AM::getAM2Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add, + Memory.ShiftImm, Memory.ShiftType); + } + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } - ARM_AM::AddrOpc AMOpc = getMemNegative() ? ARM_AM::sub : ARM_AM::add; - ARM_AM::ShiftOpc ShOpc = ARM_AM::no_shift; - int64_t ShiftAmount = 0; + void addAM2OffsetImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + const MCConstantExpr *CE = dyn_cast(getImm()); + assert(CE && "non-constant AM2OffsetImm operand!"); + int32_t Val = CE->getValue(); + ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; + // Special case for #-0 + if (Val == INT32_MIN) Val = 0; + if (Val < 0) Val = -Val; + Val = ARM_AM::getAM2Opc(AddSub, Val, ARM_AM::no_shift); + Inst.addOperand(MCOperand::CreateReg(0)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } - if (getMemOffsetRegShifted()) { - ShOpc = getMemShiftType(); - const MCConstantExpr *CE = - dyn_cast(getMemShiftAmount()); - ShiftAmount = CE->getValue(); - } + void addAddrMode3Operands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + if (!Memory.OffsetRegNum) { + ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; + // Special case for #-0 + if (Val == INT32_MIN) Val = 0; + if (Val < 0) Val = -Val; + Val = ARM_AM::getAM3Opc(AddSub, Val); + } else { + // For register offset, we encode the shift type and negation flag + // here. + Val = ARM_AM::getAM3Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add, 0); + } + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } - Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM2Opc(AMOpc, ShiftAmount, - ShOpc, IdxMode))); + void addAM3OffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + if (Kind == k_PostIndexRegister) { + int32_t Val = + ARM_AM::getAM3Opc(PostIdxReg.isAdd ? ARM_AM::add : ARM_AM::sub, 0); + Inst.addOperand(MCOperand::CreateReg(PostIdxReg.RegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); return; } - // Create a operand placeholder to always yield the same number of operands. + // Constant offset. + const MCConstantExpr *CE = static_cast(getImm()); + int32_t Val = CE->getValue(); + ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; + // Special case for #-0 + if (Val == INT32_MIN) Val = 0; + if (Val < 0) Val = -Val; + Val = ARM_AM::getAM3Opc(AddSub, Val); Inst.addOperand(MCOperand::CreateReg(0)); - - // FIXME: #-0 is encoded differently than #0. Does the parser preserve - // the difference? - const MCConstantExpr *CE = dyn_cast(getMemOffset()); - assert(CE && "Non-constant mode 2 offset operand!"); - int64_t Offset = CE->getValue(); - - if (Offset >= 0) - Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM2Opc(ARM_AM::add, - Offset, ARM_AM::no_shift, IdxMode))); - else - Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM2Opc(ARM_AM::sub, - -Offset, ARM_AM::no_shift, IdxMode))); + Inst.addOperand(MCOperand::CreateImm(Val)); } - void addMemMode3Operands(MCInst &Inst, unsigned N) const { - assert(isMemMode3() && "Invalid mode or number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBaseRegNum())); - unsigned IdxMode = (getMemPreindexed() | getMemPostindexed() << 1); - - if (getMemOffsetIsReg()) { - Inst.addOperand(MCOperand::CreateReg(getMemOffsetRegNum())); + void addAddrMode5Operands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + // If we have an immediate that's not a constant, treat it as a label + // reference needing a fixup. If it is a constant, it's something else + // and we reject it. + if (isImm()) { + Inst.addOperand(MCOperand::CreateExpr(getImm())); + Inst.addOperand(MCOperand::CreateImm(0)); + return; + } + + // The lower two bits are always zero and as such are not encoded. + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() / 4 : 0; + ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; + // Special case for #-0 + if (Val == INT32_MIN) Val = 0; + if (Val < 0) Val = -Val; + Val = ARM_AM::getAM5Opc(AddSub, Val); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } + + void addMemImm8s4OffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } + + void addMemImm0_1020s4OffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + // The lower two bits are always zero and as such are not encoded. + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() / 4 : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } + + void addMemImm8OffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } + + void addMemPosImm8OffsetOperands(MCInst &Inst, unsigned N) const { + addMemImm8OffsetOperands(Inst, N); + } + + void addMemNegImm8OffsetOperands(MCInst &Inst, unsigned N) const { + addMemImm8OffsetOperands(Inst, N); + } - ARM_AM::AddrOpc AMOpc = getMemNegative() ? ARM_AM::sub : ARM_AM::add; - Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM3Opc(AMOpc, 0, - IdxMode))); + void addMemUImm12OffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + // If this is an immediate, it's a label reference. + if (Kind == k_Immediate) { + addExpr(Inst, getImm()); + Inst.addOperand(MCOperand::CreateImm(0)); return; } - // Create a operand placeholder to always yield the same number of operands. - Inst.addOperand(MCOperand::CreateReg(0)); + // Otherwise, it's a normal memory reg+offset. + int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } + + void addMemImm12OffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + // If this is an immediate, it's a label reference. + if (Kind == k_Immediate) { + addExpr(Inst, getImm()); + Inst.addOperand(MCOperand::CreateImm(0)); + return; + } - // FIXME: #-0 is encoded differently than #0. Does the parser preserve - // the difference? - const MCConstantExpr *CE = dyn_cast(getMemOffset()); - assert(CE && "Non-constant mode 3 offset operand!"); - int64_t Offset = CE->getValue(); + // Otherwise, it's a normal memory reg+offset. + int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } - if (Offset >= 0) - Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM3Opc(ARM_AM::add, - Offset, IdxMode))); - else - Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM3Opc(ARM_AM::sub, - -Offset, IdxMode))); + void addMemTBBOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); + } + + void addMemTBHOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); + } + + void addMemRegOffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + unsigned Val = ARM_AM::getAM2Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add, + Memory.ShiftImm, Memory.ShiftType); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); } - void addMemMode5Operands(MCInst &Inst, unsigned N) const { - assert(N == 2 && isMemMode5() && "Invalid number of operands!"); + void addT2MemRegOffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); + Inst.addOperand(MCOperand::CreateImm(Memory.ShiftImm)); + } - Inst.addOperand(MCOperand::CreateReg(getMemBaseRegNum())); - assert(!getMemOffsetIsReg() && "Invalid mode 5 operand"); + void addMemThumbRROperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); + } - // FIXME: #-0 is encoded differently than #0. Does the parser preserve - // the difference? - const MCConstantExpr *CE = dyn_cast(getMemOffset()); - assert(CE && "Non-constant mode 5 offset operand!"); + void addMemThumbRIs4Operands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 4) : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } - // The MCInst offset operand doesn't include the low two bits (like - // the instruction encoding). - int64_t Offset = CE->getValue() / 4; - if (Offset >= 0) - Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::add, - Offset))); - else - Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::sub, - -Offset))); + void addMemThumbRIs2Operands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 2) : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); } - void addMemModeRegThumbOperands(MCInst &Inst, unsigned N) const { - assert(N == 2 && isMemModeRegThumb() && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBaseRegNum())); - Inst.addOperand(MCOperand::CreateReg(getMemOffsetRegNum())); + void addMemThumbRIs1Operands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue()) : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); } - void addMemModeImmThumbOperands(MCInst &Inst, unsigned N) const { - assert(N == 2 && isMemModeImmThumb() && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBaseRegNum())); - const MCConstantExpr *CE = dyn_cast(getMemOffset()); - assert(CE && "Non-constant mode offset operand!"); - Inst.addOperand(MCOperand::CreateImm(CE->getValue())); + void addMemThumbSPIOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 4) : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } + + void addPostIdxImm8Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *CE = dyn_cast(getImm()); + assert(CE && "non-constant post-idx-imm8 operand!"); + int Imm = CE->getValue(); + bool isAdd = Imm >= 0; + if (Imm == INT32_MIN) Imm = 0; + Imm = (Imm < 0 ? -Imm : Imm) | (int)isAdd << 8; + Inst.addOperand(MCOperand::CreateImm(Imm)); + } + + void addPostIdxImm8s4Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *CE = dyn_cast(getImm()); + assert(CE && "non-constant post-idx-imm8s4 operand!"); + int Imm = CE->getValue(); + bool isAdd = Imm >= 0; + if (Imm == INT32_MIN) Imm = 0; + // Immediate is scaled by 4. + Imm = ((Imm < 0 ? -Imm : Imm) / 4) | (int)isAdd << 8; + Inst.addOperand(MCOperand::CreateImm(Imm)); + } + + void addPostIdxRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(PostIdxReg.RegNum)); + Inst.addOperand(MCOperand::CreateImm(PostIdxReg.isAdd)); + } + + void addPostIdxRegShiftedOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(PostIdxReg.RegNum)); + // The sign, shift type, and shift amount are encoded in a single operand + // using the AM2 encoding helpers. + ARM_AM::AddrOpc opc = PostIdxReg.isAdd ? ARM_AM::add : ARM_AM::sub; + unsigned Imm = ARM_AM::getAM2Opc(opc, PostIdxReg.ShiftImm, + PostIdxReg.ShiftTy); + Inst.addOperand(MCOperand::CreateImm(Imm)); } void addMSRMaskOperands(MCInst &Inst, unsigned N) const { @@ -929,10 +1584,126 @@ public: Inst.addOperand(MCOperand::CreateImm(unsigned(getProcIFlags()))); } + void addVecListOneDOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(VectorList.RegNum)); + } + + void addVecListTwoDOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // Only the first register actually goes on the instruction. The rest + // are implied by the opcode. + Inst.addOperand(MCOperand::CreateReg(VectorList.RegNum)); + } + + void addVecListThreeDOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // Only the first register actually goes on the instruction. The rest + // are implied by the opcode. + Inst.addOperand(MCOperand::CreateReg(VectorList.RegNum)); + } + + void addVecListFourDOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // Only the first register actually goes on the instruction. The rest + // are implied by the opcode. + Inst.addOperand(MCOperand::CreateReg(VectorList.RegNum)); + } + + void addVecListTwoQOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // Only the first register actually goes on the instruction. The rest + // are implied by the opcode. + Inst.addOperand(MCOperand::CreateReg(VectorList.RegNum)); + } + + void addVectorIndex8Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(getVectorIndex())); + } + + void addVectorIndex16Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(getVectorIndex())); + } + + void addVectorIndex32Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(getVectorIndex())); + } + + void addNEONi8splatOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The immediate encodes the type of constant as well as the value. + // Mask in that this is an i8 splat. + const MCConstantExpr *CE = dyn_cast(getImm()); + Inst.addOperand(MCOperand::CreateImm(CE->getValue() | 0xe00)); + } + + void addNEONi16splatOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The immediate encodes the type of constant as well as the value. + const MCConstantExpr *CE = dyn_cast(getImm()); + unsigned Value = CE->getValue(); + if (Value >= 256) + Value = (Value >> 8) | 0xa00; + else + Value |= 0x800; + Inst.addOperand(MCOperand::CreateImm(Value)); + } + + void addNEONi32splatOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The immediate encodes the type of constant as well as the value. + const MCConstantExpr *CE = dyn_cast(getImm()); + unsigned Value = CE->getValue(); + if (Value >= 256 && Value <= 0xff00) + Value = (Value >> 8) | 0x200; + else if (Value > 0xffff && Value <= 0xff0000) + Value = (Value >> 16) | 0x400; + else if (Value > 0xffffff) + Value = (Value >> 24) | 0x600; + Inst.addOperand(MCOperand::CreateImm(Value)); + } + + void addNEONi32vmovOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The immediate encodes the type of constant as well as the value. + const MCConstantExpr *CE = dyn_cast(getImm()); + unsigned Value = CE->getValue(); + if (Value >= 256 && Value <= 0xffff) + Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200); + else if (Value > 0xffff && Value <= 0xffffff) + Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400); + else if (Value > 0xffffff) + Value = (Value >> 24) | 0x600; + Inst.addOperand(MCOperand::CreateImm(Value)); + } + + void addNEONi64splatOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // The immediate encodes the type of constant as well as the value. + const MCConstantExpr *CE = dyn_cast(getImm()); + uint64_t Value = CE->getValue(); + unsigned Imm = 0; + for (unsigned i = 0; i < 8; ++i, Value >>= 8) { + Imm |= (Value & 1) << i; + } + Inst.addOperand(MCOperand::CreateImm(Imm | 0x1e00)); + } + virtual void print(raw_ostream &OS) const; + static ARMOperand *CreateITMask(unsigned Mask, SMLoc S) { + ARMOperand *Op = new ARMOperand(k_ITCondMask); + Op->ITMask.Mask = Mask; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + static ARMOperand *CreateCondCode(ARMCC::CondCodes CC, SMLoc S) { - ARMOperand *Op = new ARMOperand(CondCode); + ARMOperand *Op = new ARMOperand(k_CondCode); Op->CC.Val = CC; Op->StartLoc = S; Op->EndLoc = S; @@ -940,7 +1711,7 @@ public: } static ARMOperand *CreateCoprocNum(unsigned CopVal, SMLoc S) { - ARMOperand *Op = new ARMOperand(CoprocNum); + ARMOperand *Op = new ARMOperand(k_CoprocNum); Op->Cop.Val = CopVal; Op->StartLoc = S; Op->EndLoc = S; @@ -948,15 +1719,23 @@ public: } static ARMOperand *CreateCoprocReg(unsigned CopVal, SMLoc S) { - ARMOperand *Op = new ARMOperand(CoprocReg); + ARMOperand *Op = new ARMOperand(k_CoprocReg); Op->Cop.Val = CopVal; Op->StartLoc = S; Op->EndLoc = S; return Op; } + static ARMOperand *CreateCoprocOption(unsigned Val, SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(k_CoprocOption); + Op->Cop.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + static ARMOperand *CreateCCOut(unsigned RegNum, SMLoc S) { - ARMOperand *Op = new ARMOperand(CCOut); + ARMOperand *Op = new ARMOperand(k_CCOut); Op->Reg.RegNum = RegNum; Op->StartLoc = S; Op->EndLoc = S; @@ -964,7 +1743,7 @@ public: } static ARMOperand *CreateToken(StringRef Str, SMLoc S) { - ARMOperand *Op = new ARMOperand(Token); + ARMOperand *Op = new ARMOperand(k_Token); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; @@ -973,7 +1752,7 @@ public: } static ARMOperand *CreateReg(unsigned RegNum, SMLoc S, SMLoc E) { - ARMOperand *Op = new ARMOperand(Register); + ARMOperand *Op = new ARMOperand(k_Register); Op->Reg.RegNum = RegNum; Op->StartLoc = S; Op->EndLoc = E; @@ -985,7 +1764,7 @@ public: unsigned ShiftReg, unsigned ShiftImm, SMLoc S, SMLoc E) { - ARMOperand *Op = new ARMOperand(ShiftedRegister); + ARMOperand *Op = new ARMOperand(k_ShiftedRegister); Op->RegShiftedReg.ShiftTy = ShTy; Op->RegShiftedReg.SrcReg = SrcReg; Op->RegShiftedReg.ShiftReg = ShiftReg; @@ -999,7 +1778,7 @@ public: unsigned SrcReg, unsigned ShiftImm, SMLoc S, SMLoc E) { - ARMOperand *Op = new ARMOperand(ShiftedImmediate); + ARMOperand *Op = new ARMOperand(k_ShiftedImmediate); Op->RegShiftedImm.ShiftTy = ShTy; Op->RegShiftedImm.SrcReg = SrcReg; Op->RegShiftedImm.ShiftImm = ShiftImm; @@ -1010,7 +1789,7 @@ public: static ARMOperand *CreateShifterImm(bool isASR, unsigned Imm, SMLoc S, SMLoc E) { - ARMOperand *Op = new ARMOperand(ShifterImmediate); + ARMOperand *Op = new ARMOperand(k_ShifterImmediate); Op->ShifterImm.isASR = isASR; Op->ShifterImm.Imm = Imm; Op->StartLoc = S; @@ -1019,24 +1798,33 @@ public: } static ARMOperand *CreateRotImm(unsigned Imm, SMLoc S, SMLoc E) { - ARMOperand *Op = new ARMOperand(RotateImmediate); + ARMOperand *Op = new ARMOperand(k_RotateImmediate); Op->RotImm.Imm = Imm; Op->StartLoc = S; Op->EndLoc = E; return Op; } + static ARMOperand *CreateBitfield(unsigned LSB, unsigned Width, + SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(k_BitfieldDescriptor); + Op->Bitfield.LSB = LSB; + Op->Bitfield.Width = Width; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + static ARMOperand * CreateRegList(const SmallVectorImpl > &Regs, SMLoc StartLoc, SMLoc EndLoc) { - KindTy Kind = RegisterList; + KindTy Kind = k_RegisterList; - if (llvm::ARMMCRegisterClasses[ARM::DPRRegClassID]. - contains(Regs.front().first)) - Kind = DPRRegisterList; - else if (llvm::ARMMCRegisterClasses[ARM::SPRRegClassID]. + if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Regs.front().first)) + Kind = k_DPRRegisterList; + else if (ARMMCRegisterClasses[ARM::SPRRegClassID]. contains(Regs.front().first)) - Kind = SPRRegisterList; + Kind = k_SPRRegisterList; ARMOperand *Op = new ARMOperand(Kind); for (SmallVectorImpl >::const_iterator @@ -1048,55 +1836,78 @@ public: return Op; } + static ARMOperand *CreateVectorList(unsigned RegNum, unsigned Count, + SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(k_VectorList); + Op->VectorList.RegNum = RegNum; + Op->VectorList.Count = Count; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static ARMOperand *CreateVectorIndex(unsigned Idx, SMLoc S, SMLoc E, + MCContext &Ctx) { + ARMOperand *Op = new ARMOperand(k_VectorIndex); + Op->VectorIndex.Val = Idx; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + static ARMOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { - ARMOperand *Op = new ARMOperand(Immediate); + ARMOperand *Op = new ARMOperand(k_Immediate); Op->Imm.Val = Val; Op->StartLoc = S; Op->EndLoc = E; return Op; } - static ARMOperand *CreateMem(ARMII::AddrMode AddrMode, unsigned BaseRegNum, - bool OffsetIsReg, const MCExpr *Offset, - int OffsetRegNum, bool OffsetRegShifted, - enum ARM_AM::ShiftOpc ShiftType, - const MCExpr *ShiftAmount, bool Preindexed, - bool Postindexed, bool Negative, bool Writeback, + static ARMOperand *CreateFPImm(unsigned Val, SMLoc S, MCContext &Ctx) { + ARMOperand *Op = new ARMOperand(k_FPImmediate); + Op->FPImm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static ARMOperand *CreateMem(unsigned BaseRegNum, + const MCConstantExpr *OffsetImm, + unsigned OffsetRegNum, + ARM_AM::ShiftOpc ShiftType, + unsigned ShiftImm, + unsigned Alignment, + bool isNegative, SMLoc S, SMLoc E) { - assert((OffsetRegNum == -1 || OffsetIsReg) && - "OffsetRegNum must imply OffsetIsReg!"); - assert((!OffsetRegShifted || OffsetIsReg) && - "OffsetRegShifted must imply OffsetIsReg!"); - assert((Offset || OffsetIsReg) && - "Offset must exists unless register offset is used!"); - assert((!ShiftAmount || (OffsetIsReg && OffsetRegShifted)) && - "Cannot have shift amount without shifted register offset!"); - assert((!Offset || !OffsetIsReg) && - "Cannot have expression offset and register offset!"); - - ARMOperand *Op = new ARMOperand(Memory); - Op->Mem.AddrMode = AddrMode; - Op->Mem.BaseRegNum = BaseRegNum; - Op->Mem.OffsetIsReg = OffsetIsReg; - if (OffsetIsReg) - Op->Mem.Offset.RegNum = OffsetRegNum; - else - Op->Mem.Offset.Value = Offset; - Op->Mem.OffsetRegShifted = OffsetRegShifted; - Op->Mem.ShiftType = ShiftType; - Op->Mem.ShiftAmount = ShiftAmount; - Op->Mem.Preindexed = Preindexed; - Op->Mem.Postindexed = Postindexed; - Op->Mem.Negative = Negative; - Op->Mem.Writeback = Writeback; + ARMOperand *Op = new ARMOperand(k_Memory); + Op->Memory.BaseRegNum = BaseRegNum; + Op->Memory.OffsetImm = OffsetImm; + Op->Memory.OffsetRegNum = OffsetRegNum; + Op->Memory.ShiftType = ShiftType; + Op->Memory.ShiftImm = ShiftImm; + Op->Memory.Alignment = Alignment; + Op->Memory.isNegative = isNegative; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + static ARMOperand *CreatePostIdxReg(unsigned RegNum, bool isAdd, + ARM_AM::ShiftOpc ShiftTy, + unsigned ShiftImm, + SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(k_PostIndexRegister); + Op->PostIdxReg.RegNum = RegNum; + Op->PostIdxReg.isAdd = isAdd; + Op->PostIdxReg.ShiftTy = ShiftTy; + Op->PostIdxReg.ShiftImm = ShiftImm; Op->StartLoc = S; Op->EndLoc = E; return Op; } static ARMOperand *CreateMemBarrierOpt(ARM_MB::MemBOpt Opt, SMLoc S) { - ARMOperand *Op = new ARMOperand(MemBarrierOpt); + ARMOperand *Op = new ARMOperand(k_MemBarrierOpt); Op->MBOpt.Val = Opt; Op->StartLoc = S; Op->EndLoc = S; @@ -1104,7 +1915,7 @@ public: } static ARMOperand *CreateProcIFlags(ARM_PROC::IFlags IFlags, SMLoc S) { - ARMOperand *Op = new ARMOperand(ProcIFlags); + ARMOperand *Op = new ARMOperand(k_ProcIFlags); Op->IFlags.Val = IFlags; Op->StartLoc = S; Op->EndLoc = S; @@ -1112,7 +1923,7 @@ public: } static ARMOperand *CreateMSRMask(unsigned MMask, SMLoc S) { - ARMOperand *Op = new ARMOperand(MSRMask); + ARMOperand *Op = new ARMOperand(k_MSRMask); Op->MMask.Val = MMask; Op->StartLoc = S; Op->EndLoc = S; @@ -1124,53 +1935,57 @@ public: void ARMOperand::print(raw_ostream &OS) const { switch (Kind) { - case CondCode: + case k_FPImmediate: + OS << ""; + break; + case k_CondCode: OS << ""; break; - case CCOut: + case k_CCOut: OS << ""; break; - case CoprocNum: + case k_ITCondMask: { + static const char *MaskStr[] = { + "()", "(t)", "(e)", "(tt)", "(et)", "(te)", "(ee)", "(ttt)", "(ett)", + "(tet)", "(eet)", "(tte)", "(ete)", "(tee)", "(eee)" + }; + assert((ITMask.Mask & 0xf) == ITMask.Mask); + OS << ""; + break; + } + case k_CoprocNum: OS << ""; break; - case CoprocReg: + case k_CoprocReg: OS << ""; break; - case MSRMask: + case k_CoprocOption: + OS << ""; + break; + case k_MSRMask: OS << ""; break; - case Immediate: + case k_Immediate: getImm()->print(OS); break; - case MemBarrierOpt: + case k_MemBarrierOpt: OS << ""; break; - case Memory: + case k_Memory: OS << ""; + break; + case k_PostIndexRegister: + OS << "post-idx register " << (PostIdxReg.isAdd ? "" : "-") + << PostIdxReg.RegNum; + if (PostIdxReg.ShiftTy != ARM_AM::no_shift) + OS << ARM_AM::getShiftOpcStr(PostIdxReg.ShiftTy) << " " + << PostIdxReg.ShiftImm; OS << ">"; break; - case ProcIFlags: { + case k_ProcIFlags: { OS << "= 0; --i) @@ -1179,14 +1994,14 @@ void ARMOperand::print(raw_ostream &OS) const { OS << ">"; break; } - case Register: + case k_Register: OS << ""; break; - case ShifterImmediate: + case k_ShifterImmediate: OS << ""; break; - case ShiftedRegister: + case k_ShiftedRegister: OS << ""; break; - case ShiftedImmediate: + case k_ShiftedImmediate: OS << ""; break; - case RotateImmediate: + case k_RotateImmediate: OS << ""; break; - case RegisterList: - case DPRRegisterList: - case SPRRegisterList: { + case k_BitfieldDescriptor: + OS << ""; + break; + case k_RegisterList: + case k_DPRRegisterList: + case k_SPRRegisterList: { OS << " &RegList = getRegList(); @@ -1219,9 +2038,16 @@ void ARMOperand::print(raw_ostream &OS) const { OS << ">"; break; } - case Token: + case k_VectorList: + OS << ""; + break; + case k_Token: OS << "'" << getToken() << "'"; break; + case k_VectorIndex: + OS << ""; + break; } } @@ -1245,12 +2071,11 @@ bool ARMAsmParser::ParseRegister(unsigned &RegNo, /// int ARMAsmParser::tryParseRegister() { const AsmToken &Tok = Parser.getTok(); - assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); + if (Tok.isNot(AsmToken::Identifier)) return -1; // FIXME: Validate register for the current architecture; we have to do // validation later, so maybe there is no need for this here. - std::string upperCase = Tok.getString().str(); - std::string lowerCase = LowercaseString(upperCase); + std::string lowerCase = Tok.getString().lower(); unsigned RegNum = MatchRegisterName(lowerCase); if (!RegNum) { RegNum = StringSwitch(lowerCase) @@ -1263,6 +2088,7 @@ int ARMAsmParser::tryParseRegister() { if (!RegNum) return -1; Parser.Lex(); // Eat identifier token. + return RegNum; } @@ -1277,8 +2103,7 @@ int ARMAsmParser::tryParseShiftRegister( const AsmToken &Tok = Parser.getTok(); assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); - std::string upperCase = Tok.getString().str(); - std::string lowerCase = LowercaseString(upperCase); + std::string lowerCase = Tok.getString().lower(); ARM_AM::ShiftOpc ShiftTy = StringSwitch(lowerCase) .Case("lsl", ARM_AM::lsl) .Case("lsr", ARM_AM::lsr) @@ -1378,6 +2203,36 @@ tryParseRegisterWithWriteBack(SmallVectorImpl &Operands) { Operands.push_back(ARMOperand::CreateToken(ExclaimTok.getString(), ExclaimTok.getLoc())); Parser.Lex(); // Eat exclaim token + return false; + } + + // Also check for an index operand. This is only legal for vector registers, + // but that'll get caught OK in operand matching, so we don't need to + // explicitly filter everything else out here. + if (Parser.getTok().is(AsmToken::LBrac)) { + SMLoc SIdx = Parser.getTok().getLoc(); + Parser.Lex(); // Eat left bracket token. + + const MCExpr *ImmVal; + if (getParser().ParseExpression(ImmVal)) + return MatchOperand_ParseFail; + const MCConstantExpr *MCE = dyn_cast(ImmVal); + if (!MCE) { + TokError("immediate value expected for vector index"); + return MatchOperand_ParseFail; + } + + SMLoc E = Parser.getTok().getLoc(); + if (Parser.getTok().isNot(AsmToken::RBrac)) { + Error(E, "']' expected"); + return MatchOperand_ParseFail; + } + + Parser.Lex(); // Eat right bracket token. + + Operands.push_back(ARMOperand::CreateVectorIndex(MCE->getValue(), + SIdx, E, + getContext())); } return false; @@ -1426,6 +2281,41 @@ static int MatchCoprocessorOperandName(StringRef Name, char CoprocOp) { return -1; } +/// parseITCondCode - Try to parse a condition code for an IT instruction. +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseITCondCode(SmallVectorImpl &Operands) { + SMLoc S = Parser.getTok().getLoc(); + const AsmToken &Tok = Parser.getTok(); + if (!Tok.is(AsmToken::Identifier)) + return MatchOperand_NoMatch; + unsigned CC = StringSwitch(Tok.getString()) + .Case("eq", ARMCC::EQ) + .Case("ne", ARMCC::NE) + .Case("hs", ARMCC::HS) + .Case("cs", ARMCC::HS) + .Case("lo", ARMCC::LO) + .Case("cc", ARMCC::LO) + .Case("mi", ARMCC::MI) + .Case("pl", ARMCC::PL) + .Case("vs", ARMCC::VS) + .Case("vc", ARMCC::VC) + .Case("hi", ARMCC::HI) + .Case("ls", ARMCC::LS) + .Case("ge", ARMCC::GE) + .Case("lt", ARMCC::LT) + .Case("gt", ARMCC::GT) + .Case("le", ARMCC::LE) + .Case("al", ARMCC::AL) + .Default(~0U); + if (CC == ~0U) + return MatchOperand_NoMatch; + Parser.Lex(); // Eat the token. + + Operands.push_back(ARMOperand::CreateCondCode(ARMCC::CondCodes(CC), S)); + + return MatchOperand_Success; +} + /// parseCoprocNumOperand - Try to parse an coprocessor number operand. The /// token must be an Identifier when called, and if it is a coprocessor /// number, the token is eaten and the operand is added to the operand list. @@ -1433,7 +2323,8 @@ ARMAsmParser::OperandMatchResultTy ARMAsmParser:: parseCoprocNumOperand(SmallVectorImpl &Operands) { SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); - assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); + if (Tok.isNot(AsmToken::Identifier)) + return MatchOperand_NoMatch; int Num = MatchCoprocessorOperandName(Tok.getString(), 'p'); if (Num == -1) @@ -1451,7 +2342,8 @@ ARMAsmParser::OperandMatchResultTy ARMAsmParser:: parseCoprocRegOperand(SmallVectorImpl &Operands) { SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); - assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); + if (Tok.isNot(AsmToken::Identifier)) + return MatchOperand_NoMatch; int Reg = MatchCoprocessorOperandName(Tok.getString(), 'c'); if (Reg == -1) @@ -1462,88 +2354,242 @@ parseCoprocRegOperand(SmallVectorImpl &Operands) { return MatchOperand_Success; } -/// Parse a register list, return it if successful else return null. The first -/// token must be a '{' when called. -bool ARMAsmParser:: -parseRegisterList(SmallVectorImpl &Operands) { - assert(Parser.getTok().is(AsmToken::LCurly) && - "Token is not a Left Curly Brace"); +/// parseCoprocOptionOperand - Try to parse an coprocessor option operand. +/// coproc_option : '{' imm0_255 '}' +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseCoprocOptionOperand(SmallVectorImpl &Operands) { SMLoc S = Parser.getTok().getLoc(); - // Read the rest of the registers in the list. - unsigned PrevRegNum = 0; - SmallVector, 32> Registers; + // If this isn't a '{', this isn't a coprocessor immediate operand. + if (Parser.getTok().isNot(AsmToken::LCurly)) + return MatchOperand_NoMatch; + Parser.Lex(); // Eat the '{' - do { - bool IsRange = Parser.getTok().is(AsmToken::Minus); - Parser.Lex(); // Eat non-identifier token. + const MCExpr *Expr; + SMLoc Loc = Parser.getTok().getLoc(); + if (getParser().ParseExpression(Expr)) { + Error(Loc, "illegal expression"); + return MatchOperand_ParseFail; + } + const MCConstantExpr *CE = dyn_cast(Expr); + if (!CE || CE->getValue() < 0 || CE->getValue() > 255) { + Error(Loc, "coprocessor option must be an immediate in range [0, 255]"); + return MatchOperand_ParseFail; + } + int Val = CE->getValue(); - const AsmToken &RegTok = Parser.getTok(); - SMLoc RegLoc = RegTok.getLoc(); - if (RegTok.isNot(AsmToken::Identifier)) { - Error(RegLoc, "register expected"); - return true; - } + // Check for and consume the closing '}' + if (Parser.getTok().isNot(AsmToken::RCurly)) + return MatchOperand_ParseFail; + SMLoc E = Parser.getTok().getLoc(); + Parser.Lex(); // Eat the '}' - int RegNum = tryParseRegister(); - if (RegNum == -1) { - Error(RegLoc, "register expected"); - return true; - } + Operands.push_back(ARMOperand::CreateCoprocOption(Val, S, E)); + return MatchOperand_Success; +} - if (IsRange) { - int Reg = PrevRegNum; - do { - ++Reg; - Registers.push_back(std::make_pair(Reg, RegLoc)); - } while (Reg != RegNum); - } else { - Registers.push_back(std::make_pair(RegNum, RegLoc)); - } +// For register list parsing, we need to map from raw GPR register numbering +// to the enumeration values. The enumeration values aren't sorted by +// register number due to our using "sp", "lr" and "pc" as canonical names. +static unsigned getNextRegister(unsigned Reg) { + // If this is a GPR, we need to do it manually, otherwise we can rely + // on the sort ordering of the enumeration since the other reg-classes + // are sane. + if (!ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg)) + return Reg + 1; + switch(Reg) { + default: assert(0 && "Invalid GPR number!"); + case ARM::R0: return ARM::R1; case ARM::R1: return ARM::R2; + case ARM::R2: return ARM::R3; case ARM::R3: return ARM::R4; + case ARM::R4: return ARM::R5; case ARM::R5: return ARM::R6; + case ARM::R6: return ARM::R7; case ARM::R7: return ARM::R8; + case ARM::R8: return ARM::R9; case ARM::R9: return ARM::R10; + case ARM::R10: return ARM::R11; case ARM::R11: return ARM::R12; + case ARM::R12: return ARM::SP; case ARM::SP: return ARM::LR; + case ARM::LR: return ARM::PC; case ARM::PC: return ARM::R0; + } +} - PrevRegNum = RegNum; - } while (Parser.getTok().is(AsmToken::Comma) || - Parser.getTok().is(AsmToken::Minus)); +/// Parse a register list. +bool ARMAsmParser:: +parseRegisterList(SmallVectorImpl &Operands) { + assert(Parser.getTok().is(AsmToken::LCurly) && + "Token is not a Left Curly Brace"); + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); // Eat '{' token. + SMLoc RegLoc = Parser.getTok().getLoc(); - // Process the right curly brace of the list. - const AsmToken &RCurlyTok = Parser.getTok(); - if (RCurlyTok.isNot(AsmToken::RCurly)) { - Error(RCurlyTok.getLoc(), "'}' expected"); - return true; + // Check the first register in the list to see what register class + // this is a list of. + int Reg = tryParseRegister(); + if (Reg == -1) + return Error(RegLoc, "register expected"); + + const MCRegisterClass *RC; + if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg)) + RC = &ARMMCRegisterClasses[ARM::GPRRegClassID]; + else if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg)) + RC = &ARMMCRegisterClasses[ARM::DPRRegClassID]; + else if (ARMMCRegisterClasses[ARM::SPRRegClassID].contains(Reg)) + RC = &ARMMCRegisterClasses[ARM::SPRRegClassID]; + else + return Error(RegLoc, "invalid register in register list"); + + // The reglist instructions have at most 16 registers, so reserve + // space for that many. + SmallVector, 16> Registers; + // Store the first register. + Registers.push_back(std::pair(Reg, RegLoc)); + + // This starts immediately after the first register token in the list, + // so we can see either a comma or a minus (range separator) as a legal + // next token. + while (Parser.getTok().is(AsmToken::Comma) || + Parser.getTok().is(AsmToken::Minus)) { + if (Parser.getTok().is(AsmToken::Minus)) { + Parser.Lex(); // Eat the comma. + SMLoc EndLoc = Parser.getTok().getLoc(); + int EndReg = tryParseRegister(); + if (EndReg == -1) + return Error(EndLoc, "register expected"); + // If the register is the same as the start reg, there's nothing + // more to do. + if (Reg == EndReg) + continue; + // The register must be in the same register class as the first. + if (!RC->contains(EndReg)) + return Error(EndLoc, "invalid register in register list"); + // Ranges must go from low to high. + if (getARMRegisterNumbering(Reg) > getARMRegisterNumbering(EndReg)) + return Error(EndLoc, "bad range in register list"); + + // Add all the registers in the range to the register list. + while (Reg != EndReg) { + Reg = getNextRegister(Reg); + Registers.push_back(std::pair(Reg, RegLoc)); + } + continue; + } + Parser.Lex(); // Eat the comma. + RegLoc = Parser.getTok().getLoc(); + int OldReg = Reg; + Reg = tryParseRegister(); + if (Reg == -1) + return Error(RegLoc, "register expected"); + // The register must be in the same register class as the first. + if (!RC->contains(Reg)) + return Error(RegLoc, "invalid register in register list"); + // List must be monotonically increasing. + if (getARMRegisterNumbering(Reg) <= getARMRegisterNumbering(OldReg)) + return Error(RegLoc, "register list not in ascending order"); + // VFP register lists must also be contiguous. + // It's OK to use the enumeration values directly here rather, as the + // VFP register classes have the enum sorted properly. + if (RC != &ARMMCRegisterClasses[ARM::GPRRegClassID] && + Reg != OldReg + 1) + return Error(RegLoc, "non-contiguous register range"); + Registers.push_back(std::pair(Reg, RegLoc)); } - SMLoc E = RCurlyTok.getLoc(); - Parser.Lex(); // Eat right curly brace token. + SMLoc E = Parser.getTok().getLoc(); + if (Parser.getTok().isNot(AsmToken::RCurly)) + return Error(E, "'}' expected"); + Parser.Lex(); // Eat '}' token. - // Verify the register list. - SmallVectorImpl >::const_iterator - RI = Registers.begin(), RE = Registers.end(); + Operands.push_back(ARMOperand::CreateRegList(Registers, S, E)); + return false; +} - unsigned HighRegNum = getARMRegisterNumbering(RI->first); - bool EmittedWarning = false; +// Return the low-subreg of a given Q register. +static unsigned getDRegFromQReg(unsigned QReg) { + switch (QReg) { + default: llvm_unreachable("expected a Q register!"); + case ARM::Q0: return ARM::D0; + case ARM::Q1: return ARM::D2; + case ARM::Q2: return ARM::D4; + case ARM::Q3: return ARM::D6; + case ARM::Q4: return ARM::D8; + case ARM::Q5: return ARM::D10; + case ARM::Q6: return ARM::D12; + case ARM::Q7: return ARM::D14; + case ARM::Q8: return ARM::D16; + case ARM::Q9: return ARM::D19; + case ARM::Q10: return ARM::D20; + case ARM::Q11: return ARM::D22; + case ARM::Q12: return ARM::D24; + case ARM::Q13: return ARM::D26; + case ARM::Q14: return ARM::D28; + case ARM::Q15: return ARM::D30; + } +} - DenseMap RegMap; - RegMap[HighRegNum] = true; +// parse a vector register list +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseVectorList(SmallVectorImpl &Operands) { + if(Parser.getTok().isNot(AsmToken::LCurly)) + return MatchOperand_NoMatch; - for (++RI; RI != RE; ++RI) { - const std::pair &RegInfo = *RI; - unsigned Reg = getARMRegisterNumbering(RegInfo.first); + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); // Eat '{' token. + SMLoc RegLoc = Parser.getTok().getLoc(); - if (RegMap[Reg]) { - Error(RegInfo.second, "register duplicated in register list"); - return true; + int Reg = tryParseRegister(); + if (Reg == -1) { + Error(RegLoc, "register expected"); + return MatchOperand_ParseFail; + } + unsigned Count = 1; + unsigned FirstReg = Reg; + // The list is of D registers, but we also allow Q regs and just interpret + // them as the two D sub-registers. + if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) { + FirstReg = Reg = getDRegFromQReg(Reg); + ++Reg; + ++Count; + } + + while (Parser.getTok().is(AsmToken::Comma)) { + Parser.Lex(); // Eat the comma. + RegLoc = Parser.getTok().getLoc(); + int OldReg = Reg; + Reg = tryParseRegister(); + if (Reg == -1) { + Error(RegLoc, "register expected"); + return MatchOperand_ParseFail; } + // vector register lists must be contiguous. + // It's OK to use the enumeration values directly here rather, as the + // VFP register classes have the enum sorted properly. + // + // The list is of D registers, but we also allow Q regs and just interpret + // them as the two D sub-registers. + if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) { + Reg = getDRegFromQReg(Reg); + if (Reg != OldReg + 1) { + Error(RegLoc, "non-contiguous register range"); + return MatchOperand_ParseFail; + } + ++Reg; + Count += 2; + continue; + } + // Normal D register. Just check that it's contiguous and keep going. + if (Reg != OldReg + 1) { + Error(RegLoc, "non-contiguous register range"); + return MatchOperand_ParseFail; + } + ++Count; + } - if (!EmittedWarning && Reg < HighRegNum) - Warning(RegInfo.second, - "register not in ascending order in register list"); - - RegMap[Reg] = true; - HighRegNum = std::max(Reg, HighRegNum); + SMLoc E = Parser.getTok().getLoc(); + if (Parser.getTok().isNot(AsmToken::RCurly)) { + Error(E, "'}' expected"); + return MatchOperand_ParseFail; } + Parser.Lex(); // Eat '}' token. - Operands.push_back(ARMOperand::CreateRegList(Registers, S, E)); - return false; + Operands.push_back(ARMOperand::CreateVectorList(FirstReg, Count, S, E)); + return MatchOperand_Success; } /// parseMemBarrierOptOperand - Try to parse DSB/DMB data barrier options. @@ -1585,20 +2631,24 @@ parseProcIFlagsOperand(SmallVectorImpl &Operands) { assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); StringRef IFlagsStr = Tok.getString(); + // An iflags string of "none" is interpreted to mean that none of the AIF + // bits are set. Not a terribly useful instruction, but a valid encoding. unsigned IFlags = 0; - for (int i = 0, e = IFlagsStr.size(); i != e; ++i) { - unsigned Flag = StringSwitch(IFlagsStr.substr(i, 1)) - .Case("a", ARM_PROC::A) - .Case("i", ARM_PROC::I) - .Case("f", ARM_PROC::F) - .Default(~0U); + if (IFlagsStr != "none") { + for (int i = 0, e = IFlagsStr.size(); i != e; ++i) { + unsigned Flag = StringSwitch(IFlagsStr.substr(i, 1)) + .Case("a", ARM_PROC::A) + .Case("i", ARM_PROC::I) + .Case("f", ARM_PROC::F) + .Default(~0U); + + // If some specific iflag is already set, it means that some letter is + // present more than once, this is not acceptable. + if (Flag == ~0U || (IFlags & Flag)) + return MatchOperand_NoMatch; - // If some specific iflag is already set, it means that some letter is - // present more than once, this is not acceptable. - if (Flag == ~0U || (IFlags & Flag)) - return MatchOperand_NoMatch; - - IFlags |= Flag; + IFlags |= Flag; + } } Parser.Lex(); // Eat identifier token. @@ -1614,10 +2664,41 @@ parseMSRMaskOperand(SmallVectorImpl &Operands) { assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); StringRef Mask = Tok.getString(); + if (isMClass()) { + // See ARMv6-M 10.1.1 + unsigned FlagsVal = StringSwitch(Mask) + .Case("apsr", 0) + .Case("iapsr", 1) + .Case("eapsr", 2) + .Case("xpsr", 3) + .Case("ipsr", 5) + .Case("epsr", 6) + .Case("iepsr", 7) + .Case("msp", 8) + .Case("psp", 9) + .Case("primask", 16) + .Case("basepri", 17) + .Case("basepri_max", 18) + .Case("faultmask", 19) + .Case("control", 20) + .Default(~0U); + + if (FlagsVal == ~0U) + return MatchOperand_NoMatch; + + if (!hasV7Ops() && FlagsVal >= 17 && FlagsVal <= 19) + // basepri, basepri_max and faultmask only valid for V7m. + return MatchOperand_NoMatch; + + Parser.Lex(); // Eat identifier token. + Operands.push_back(ARMOperand::CreateMSRMask(FlagsVal, S)); + return MatchOperand_Success; + } + // Split spec_reg from flag, example: CPSR_sxf => "CPSR" and "sxf" size_t Start = 0, Next = Mask.find('_'); StringRef Flags = ""; - std::string SpecReg = LowercaseString(Mask.slice(Start, Next)); + std::string SpecReg = Mask.slice(Start, Next).lower(); if (Next != StringRef::npos) Flags = Mask.slice(Next+1, Mask.size()); @@ -1637,7 +2718,7 @@ parseMSRMaskOperand(SmallVectorImpl &Operands) { if (!Flags.empty()) return MatchOperand_NoMatch; else - FlagsVal = 0; // No flag + FlagsVal = 8; // No flag } } else if (SpecReg == "cpsr" || SpecReg == "spsr") { if (Flags == "all") // cpsr_all is an alias for cpsr_fc @@ -1659,9 +2740,13 @@ parseMSRMaskOperand(SmallVectorImpl &Operands) { } else // No match for special register. return MatchOperand_NoMatch; - // Special register without flags are equivalent to "fc" flags. - if (!FlagsVal) - FlagsVal = 0x9; + // Special register without flags is NOT equivalent to "fc" flags. + // NOTE: This is a divergence from gas' behavior. Uncommenting the following + // two lines would enable gas compatibility at the expense of breaking + // round-tripping. + // + // if (!FlagsVal) + // FlagsVal = 0x9; // Bit 4: Special Reg (cpsr, apsr => 0; spsr => 1) if (SpecReg == "spsr") @@ -1672,28 +2757,6 @@ parseMSRMaskOperand(SmallVectorImpl &Operands) { return MatchOperand_Success; } -/// parseMemMode2Operand - Try to parse memory addressing mode 2 operand. -ARMAsmParser::OperandMatchResultTy ARMAsmParser:: -parseMemMode2Operand(SmallVectorImpl &Operands) { - assert(Parser.getTok().is(AsmToken::LBrac) && "Token is not a \"[\""); - - if (parseMemory(Operands, ARMII::AddrMode2)) - return MatchOperand_NoMatch; - - return MatchOperand_Success; -} - -/// parseMemMode3Operand - Try to parse memory addressing mode 3 operand. -ARMAsmParser::OperandMatchResultTy ARMAsmParser:: -parseMemMode3Operand(SmallVectorImpl &Operands) { - assert(Parser.getTok().is(AsmToken::LBrac) && "Token is not a \"[\""); - - if (parseMemory(Operands, ARMII::AddrMode3)) - return MatchOperand_NoMatch; - - return MatchOperand_Success; -} - ARMAsmParser::OperandMatchResultTy ARMAsmParser:: parsePKHImm(SmallVectorImpl &Operands, StringRef Op, int Low, int High) { @@ -1703,8 +2766,8 @@ parsePKHImm(SmallVectorImpl &Operands, StringRef Op, return MatchOperand_ParseFail; } StringRef ShiftName = Tok.getString(); - std::string LowerOp = LowercaseString(Op); - std::string UpperOp = UppercaseString(Op); + std::string LowerOp = Op.lower(); + std::string UpperOp = Op.upper(); if (ShiftName != LowerOp && ShiftName != UpperOp) { Error(Parser.getTok().getLoc(), Op + " operand expected."); return MatchOperand_ParseFail; @@ -1815,7 +2878,11 @@ parseShifterImm(SmallVectorImpl &Operands) { Error(E, "'asr' shift amount must be in range [1,32]"); return MatchOperand_ParseFail; } - // asr #32 encoded as asr #0. + // asr #32 encoded as asr #0, but is not allowed in Thumb2 mode. + if (isThumb() && Val == 32) { + Error(E, "'asr #32' shift amount not allowed in Thumb mode"); + return MatchOperand_ParseFail; + } if (Val == 32) Val = 0; } else { // Shift amount must be in [1,32] @@ -1838,15 +2905,11 @@ ARMAsmParser::OperandMatchResultTy ARMAsmParser:: parseRotImm(SmallVectorImpl &Operands) { const AsmToken &Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); - if (Tok.isNot(AsmToken::Identifier)) { - Error(S, "rotate operator 'ror' expected"); - return MatchOperand_ParseFail; - } + if (Tok.isNot(AsmToken::Identifier)) + return MatchOperand_NoMatch; StringRef ShiftName = Tok.getString(); - if (ShiftName != "ror" && ShiftName != "ROR") { - Error(S, "rotate operator 'ror' expected"); - return MatchOperand_ParseFail; - } + if (ShiftName != "ror" && ShiftName != "ROR") + return MatchOperand_NoMatch; Parser.Lex(); // Eat the operator. // A '#' and a rotate amount. @@ -1883,6 +2946,255 @@ parseRotImm(SmallVectorImpl &Operands) { return MatchOperand_Success; } +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseBitfield(SmallVectorImpl &Operands) { + SMLoc S = Parser.getTok().getLoc(); + // The bitfield descriptor is really two operands, the LSB and the width. + if (Parser.getTok().isNot(AsmToken::Hash)) { + Error(Parser.getTok().getLoc(), "'#' expected"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat hash token. + + const MCExpr *LSBExpr; + SMLoc E = Parser.getTok().getLoc(); + if (getParser().ParseExpression(LSBExpr)) { + Error(E, "malformed immediate expression"); + return MatchOperand_ParseFail; + } + const MCConstantExpr *CE = dyn_cast(LSBExpr); + if (!CE) { + Error(E, "'lsb' operand must be an immediate"); + return MatchOperand_ParseFail; + } + + int64_t LSB = CE->getValue(); + // The LSB must be in the range [0,31] + if (LSB < 0 || LSB > 31) { + Error(E, "'lsb' operand must be in the range [0,31]"); + return MatchOperand_ParseFail; + } + E = Parser.getTok().getLoc(); + + // Expect another immediate operand. + if (Parser.getTok().isNot(AsmToken::Comma)) { + Error(Parser.getTok().getLoc(), "too few operands"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat hash token. + if (Parser.getTok().isNot(AsmToken::Hash)) { + Error(Parser.getTok().getLoc(), "'#' expected"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat hash token. + + const MCExpr *WidthExpr; + if (getParser().ParseExpression(WidthExpr)) { + Error(E, "malformed immediate expression"); + return MatchOperand_ParseFail; + } + CE = dyn_cast(WidthExpr); + if (!CE) { + Error(E, "'width' operand must be an immediate"); + return MatchOperand_ParseFail; + } + + int64_t Width = CE->getValue(); + // The LSB must be in the range [1,32-lsb] + if (Width < 1 || Width > 32 - LSB) { + Error(E, "'width' operand must be in the range [1,32-lsb]"); + return MatchOperand_ParseFail; + } + E = Parser.getTok().getLoc(); + + Operands.push_back(ARMOperand::CreateBitfield(LSB, Width, S, E)); + + return MatchOperand_Success; +} + +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parsePostIdxReg(SmallVectorImpl &Operands) { + // Check for a post-index addressing register operand. Specifically: + // postidx_reg := '+' register {, shift} + // | '-' register {, shift} + // | register {, shift} + + // This method must return MatchOperand_NoMatch without consuming any tokens + // in the case where there is no match, as other alternatives take other + // parse methods. + AsmToken Tok = Parser.getTok(); + SMLoc S = Tok.getLoc(); + bool haveEaten = false; + bool isAdd = true; + int Reg = -1; + if (Tok.is(AsmToken::Plus)) { + Parser.Lex(); // Eat the '+' token. + haveEaten = true; + } else if (Tok.is(AsmToken::Minus)) { + Parser.Lex(); // Eat the '-' token. + isAdd = false; + haveEaten = true; + } + if (Parser.getTok().is(AsmToken::Identifier)) + Reg = tryParseRegister(); + if (Reg == -1) { + if (!haveEaten) + return MatchOperand_NoMatch; + Error(Parser.getTok().getLoc(), "register expected"); + return MatchOperand_ParseFail; + } + SMLoc E = Parser.getTok().getLoc(); + + ARM_AM::ShiftOpc ShiftTy = ARM_AM::no_shift; + unsigned ShiftImm = 0; + if (Parser.getTok().is(AsmToken::Comma)) { + Parser.Lex(); // Eat the ','. + if (parseMemRegOffsetShift(ShiftTy, ShiftImm)) + return MatchOperand_ParseFail; + } + + Operands.push_back(ARMOperand::CreatePostIdxReg(Reg, isAdd, ShiftTy, + ShiftImm, S, E)); + + return MatchOperand_Success; +} + +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseAM3Offset(SmallVectorImpl &Operands) { + // Check for a post-index addressing register operand. Specifically: + // am3offset := '+' register + // | '-' register + // | register + // | # imm + // | # + imm + // | # - imm + + // This method must return MatchOperand_NoMatch without consuming any tokens + // in the case where there is no match, as other alternatives take other + // parse methods. + AsmToken Tok = Parser.getTok(); + SMLoc S = Tok.getLoc(); + + // Do immediates first, as we always parse those if we have a '#'. + if (Parser.getTok().is(AsmToken::Hash)) { + Parser.Lex(); // Eat the '#'. + // Explicitly look for a '-', as we need to encode negative zero + // differently. + bool isNegative = Parser.getTok().is(AsmToken::Minus); + const MCExpr *Offset; + if (getParser().ParseExpression(Offset)) + return MatchOperand_ParseFail; + const MCConstantExpr *CE = dyn_cast(Offset); + if (!CE) { + Error(S, "constant expression expected"); + return MatchOperand_ParseFail; + } + SMLoc E = Tok.getLoc(); + // Negative zero is encoded as the flag value INT32_MIN. + int32_t Val = CE->getValue(); + if (isNegative && Val == 0) + Val = INT32_MIN; + + Operands.push_back( + ARMOperand::CreateImm(MCConstantExpr::Create(Val, getContext()), S, E)); + + return MatchOperand_Success; + } + + + bool haveEaten = false; + bool isAdd = true; + int Reg = -1; + if (Tok.is(AsmToken::Plus)) { + Parser.Lex(); // Eat the '+' token. + haveEaten = true; + } else if (Tok.is(AsmToken::Minus)) { + Parser.Lex(); // Eat the '-' token. + isAdd = false; + haveEaten = true; + } + if (Parser.getTok().is(AsmToken::Identifier)) + Reg = tryParseRegister(); + if (Reg == -1) { + if (!haveEaten) + return MatchOperand_NoMatch; + Error(Parser.getTok().getLoc(), "register expected"); + return MatchOperand_ParseFail; + } + SMLoc E = Parser.getTok().getLoc(); + + Operands.push_back(ARMOperand::CreatePostIdxReg(Reg, isAdd, ARM_AM::no_shift, + 0, S, E)); + + return MatchOperand_Success; +} + +/// cvtT2LdrdPre - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtT2LdrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Rt, Rt2 + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1); + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateReg(0)); + // addr + ((ARMOperand*)Operands[4])->addMemImm8s4OffsetOperands(Inst, 2); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtT2StrdPre - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtT2StrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateReg(0)); + // Rt, Rt2 + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1); + // addr + ((ARMOperand*)Operands[4])->addMemImm8s4OffsetOperands(Inst, 2); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtLdWriteBackRegT2AddrModeImm8 - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtLdWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + + ((ARMOperand*)Operands[3])->addMemImm8OffsetOperands(Inst, 2); + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtStWriteBackRegT2AddrModeImm8 - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtStWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[3])->addMemImm8OffsetOperands(Inst, 2); + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + /// cvtLdWriteBackRegAddrMode2 - Convert parsed operands to MCInst. /// Needed here because the Asm Gen Matcher can't handle properly tied operands /// when they refer multiple MIOperands inside a single one. @@ -1894,7 +3206,38 @@ cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, // Create a writeback register dummy placeholder. Inst.addOperand(MCOperand::CreateImm(0)); - ((ARMOperand*)Operands[3])->addMemMode2Operands(Inst, 3); + ((ARMOperand*)Operands[3])->addAddrMode2Operands(Inst, 3); + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtLdWriteBackRegAddrModeImm12 - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtLdWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + + ((ARMOperand*)Operands[3])->addMemImm12OffsetOperands(Inst, 2); + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + + +/// cvtStWriteBackRegAddrModeImm12 - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtStWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[3])->addMemImm12OffsetOperands(Inst, 2); ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); return true; } @@ -1908,49 +3251,248 @@ cvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, // Create a writeback register dummy placeholder. Inst.addOperand(MCOperand::CreateImm(0)); ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); - ((ARMOperand*)Operands[3])->addMemMode2Operands(Inst, 3); + ((ARMOperand*)Operands[3])->addAddrMode2Operands(Inst, 3); ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); return true; } -/// cvtLdWriteBackRegAddrMode3 - Convert parsed operands to MCInst. +/// cvtStWriteBackRegAddrMode3 - Convert parsed operands to MCInst. /// Needed here because the Asm Gen Matcher can't handle properly tied operands /// when they refer multiple MIOperands inside a single one. bool ARMAsmParser:: -cvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode, +cvtStWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode, const SmallVectorImpl &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[3])->addAddrMode3Operands(Inst, 3); + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} +/// cvtLdExtTWriteBackImm - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtLdExtTWriteBackImm(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Rt + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); // Create a writeback register dummy placeholder. Inst.addOperand(MCOperand::CreateImm(0)); + // addr + ((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1); + // offset + ((ARMOperand*)Operands[4])->addPostIdxImm8Operands(Inst, 1); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} - ((ARMOperand*)Operands[3])->addMemMode3Operands(Inst, 3); +/// cvtLdExtTWriteBackReg - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtLdExtTWriteBackReg(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Rt + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + // addr + ((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1); + // offset + ((ARMOperand*)Operands[4])->addPostIdxRegOperands(Inst, 2); + // pred ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); return true; } -/// cvtStWriteBackRegAddrMode3 - Convert parsed operands to MCInst. +/// cvtStExtTWriteBackImm - Convert parsed operands to MCInst. /// Needed here because the Asm Gen Matcher can't handle properly tied operands /// when they refer multiple MIOperands inside a single one. bool ARMAsmParser:: -cvtStWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode, - const SmallVectorImpl &Operands) { +cvtStExtTWriteBackImm(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + // Rt + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + // addr + ((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1); + // offset + ((ARMOperand*)Operands[4])->addPostIdxImm8Operands(Inst, 1); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtStExtTWriteBackReg - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtStExtTWriteBackReg(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + // Rt + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + // addr + ((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1); + // offset + ((ARMOperand*)Operands[4])->addPostIdxRegOperands(Inst, 2); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtLdrdPre - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtLdrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Rt, Rt2 + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1); // Create a writeback register dummy placeholder. Inst.addOperand(MCOperand::CreateImm(0)); + // addr + ((ARMOperand*)Operands[4])->addAddrMode3Operands(Inst, 3); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtStrdPre - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtStrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + // Rt, Rt2 + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1); + // addr + ((ARMOperand*)Operands[4])->addAddrMode3Operands(Inst, 3); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtLdWriteBackRegAddrMode3 - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); - ((ARMOperand*)Operands[3])->addMemMode3Operands(Inst, 3); + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + ((ARMOperand*)Operands[3])->addAddrMode3Operands(Inst, 3); + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtThumbMultiple- Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtThumbMultiply(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // The second source operand must be the same register as the destination + // operand. + if (Operands.size() == 6 && + (((ARMOperand*)Operands[3])->getReg() != + ((ARMOperand*)Operands[5])->getReg()) && + (((ARMOperand*)Operands[3])->getReg() != + ((ARMOperand*)Operands[4])->getReg())) { + Error(Operands[3]->getStartLoc(), + "destination register must match source register"); + return false; + } + ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[1])->addCCOutOperands(Inst, 1); + // If we have a three-operand form, make sure to set Rn to be the operand + // that isn't the same as Rd. + unsigned RegOp = 4; + if (Operands.size() == 6 && + ((ARMOperand*)Operands[4])->getReg() == + ((ARMOperand*)Operands[3])->getReg()) + RegOp = 5; + ((ARMOperand*)Operands[RegOp])->addRegOperands(Inst, 1); + Inst.addOperand(Inst.getOperand(0)); + ((ARMOperand*)Operands[2])->addCondCodeOperands(Inst, 2); + + return true; +} + +bool ARMAsmParser:: +cvtVLDwbFixed(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Vd + ((ARMOperand*)Operands[3])->addVecListTwoDOperands(Inst, 1); + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + // Vn + ((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +bool ARMAsmParser:: +cvtVLDwbRegister(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Vd + ((ARMOperand*)Operands[3])->addVecListTwoDOperands(Inst, 1); + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + // Vn + ((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2); + // Vm + ((ARMOperand*)Operands[5])->addRegOperands(Inst, 1); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +bool ARMAsmParser:: +cvtVSTwbFixed(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + // Vn + ((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2); + // Vt + ((ARMOperand*)Operands[3])->addVecListTwoDOperands(Inst, 1); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +bool ARMAsmParser:: +cvtVSTwbRegister(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + // Vn + ((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2); + // Vm + ((ARMOperand*)Operands[5])->addRegOperands(Inst, 1); + // Vt + ((ARMOperand*)Operands[3])->addVecListTwoDOperands(Inst, 1); + // pred ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); return true; } /// Parse an ARM memory expression, return false if successful else return true /// or an error. The first token must be a '[' when called. -/// -/// TODO Only preindexing and postindexing addressing are started, unindexed -/// with option, etc are still to do. bool ARMAsmParser:: -parseMemory(SmallVectorImpl &Operands, - ARMII::AddrMode AddrMode = ARMII::AddrModeNone) { +parseMemory(SmallVectorImpl &Operands) { SMLoc S, E; assert(Parser.getTok().is(AsmToken::LBrac) && "Token is not a Left Bracket"); @@ -1958,185 +3500,178 @@ parseMemory(SmallVectorImpl &Operands, Parser.Lex(); // Eat left bracket token. const AsmToken &BaseRegTok = Parser.getTok(); - if (BaseRegTok.isNot(AsmToken::Identifier)) { - Error(BaseRegTok.getLoc(), "register expected"); - return true; - } int BaseRegNum = tryParseRegister(); - if (BaseRegNum == -1) { - Error(BaseRegTok.getLoc(), "register expected"); - return true; - } + if (BaseRegNum == -1) + return Error(BaseRegTok.getLoc(), "register expected"); // The next token must either be a comma or a closing bracket. const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Comma) && !Tok.is(AsmToken::RBrac)) - return true; + return Error(Tok.getLoc(), "malformed memory operand"); - bool Preindexed = false; - bool Postindexed = false; - bool OffsetIsReg = false; - bool Negative = false; - bool Writeback = false; - ARMOperand *WBOp = 0; - int OffsetRegNum = -1; - bool OffsetRegShifted = false; - enum ARM_AM::ShiftOpc ShiftType = ARM_AM::lsl; - const MCExpr *ShiftAmount = 0; - const MCExpr *Offset = 0; - - // First look for preindexed address forms, that is after the "[Rn" we now - // have to see if the next token is a comma. - if (Tok.is(AsmToken::Comma)) { - Preindexed = true; - Parser.Lex(); // Eat comma token. - - if (parseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, ShiftAmount, - Offset, OffsetIsReg, OffsetRegNum, E)) - return true; - const AsmToken &RBracTok = Parser.getTok(); - if (RBracTok.isNot(AsmToken::RBrac)) { - Error(RBracTok.getLoc(), "']' expected"); - return true; - } - E = RBracTok.getLoc(); + if (Tok.is(AsmToken::RBrac)) { + E = Tok.getLoc(); Parser.Lex(); // Eat right bracket token. - const AsmToken &ExclaimTok = Parser.getTok(); - if (ExclaimTok.is(AsmToken::Exclaim)) { - // None of addrmode3 instruction uses "!" - if (AddrMode == ARMII::AddrMode3) - return true; + Operands.push_back(ARMOperand::CreateMem(BaseRegNum, 0, 0, ARM_AM::no_shift, + 0, 0, false, S, E)); - WBOp = ARMOperand::CreateToken(ExclaimTok.getString(), - ExclaimTok.getLoc()); - Writeback = true; - Parser.Lex(); // Eat exclaim token - } else { // In addressing mode 2, pre-indexed mode always end with "!" - if (AddrMode == ARMII::AddrMode2) - Preindexed = false; + // If there's a pre-indexing writeback marker, '!', just add it as a token + // operand. It's rather odd, but syntactically valid. + if (Parser.getTok().is(AsmToken::Exclaim)) { + Operands.push_back(ARMOperand::CreateToken("!",Parser.getTok().getLoc())); + Parser.Lex(); // Eat the '!'. } - } else { - // The "[Rn" we have so far was not followed by a comma. - // If there's anything other than the right brace, this is a post indexing - // addressing form. - E = Tok.getLoc(); - Parser.Lex(); // Eat right bracket token. - - const AsmToken &NextTok = Parser.getTok(); + return false; + } - if (NextTok.isNot(AsmToken::EndOfStatement)) { - Postindexed = true; - Writeback = true; + assert(Tok.is(AsmToken::Comma) && "Lost comma in memory operand?!"); + Parser.Lex(); // Eat the comma. - if (NextTok.isNot(AsmToken::Comma)) { - Error(NextTok.getLoc(), "',' expected"); - return true; - } + // If we have a ':', it's an alignment specifier. + if (Parser.getTok().is(AsmToken::Colon)) { + Parser.Lex(); // Eat the ':'. + E = Parser.getTok().getLoc(); - Parser.Lex(); // Eat comma token. + const MCExpr *Expr; + if (getParser().ParseExpression(Expr)) + return true; - if (parseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, - ShiftAmount, Offset, OffsetIsReg, OffsetRegNum, - E)) - return true; + // The expression has to be a constant. Memory references with relocations + // don't come through here, as they use the