X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FAsmParser%2FARMAsmParser.cpp;h=46ea29f19276d20b24a4d91b64749d24852470a3;hb=681460f954e9c13ffd2f02f27bba048ccf90abaf;hp=3e8f98d2621fb8f9fe3225b4c09277a56236294d;hpb=f6c35c59f515505fa2e9b74b3d0f4ab06f8266d8;p=oota-llvm.git diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 3e8f98d2621..46ea29f1927 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -138,6 +138,8 @@ class ARMAsmParser : public MCTargetAsmParser { SmallVectorImpl&); OperandMatchResultTy parseCoprocRegOperand( SmallVectorImpl&); + OperandMatchResultTy parseCoprocOptionOperand( + SmallVectorImpl&); OperandMatchResultTy parseMemBarrierOptOperand( SmallVectorImpl&); OperandMatchResultTy parseProcIFlagsOperand( @@ -159,6 +161,7 @@ class ARMAsmParser : public MCTargetAsmParser { OperandMatchResultTy parsePostIdxReg(SmallVectorImpl&); OperandMatchResultTy parseAM3Offset(SmallVectorImpl&); OperandMatchResultTy parseFPImm(SmallVectorImpl&); + OperandMatchResultTy parseVectorList(SmallVectorImpl&); // Asm Match Converter Methods bool cvtT2LdrdPre(MCInst &Inst, unsigned Opcode, @@ -195,6 +198,14 @@ class ARMAsmParser : public MCTargetAsmParser { 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); @@ -247,6 +258,7 @@ class ARMOperand : public MCParsedAsmOperand { k_ITCondMask, k_CoprocNum, k_CoprocReg, + k_CoprocOption, k_Immediate, k_FPImmediate, k_MemBarrierOpt, @@ -259,6 +271,7 @@ class ARMOperand : public MCParsedAsmOperand { k_RegisterList, k_DPRRegisterList, k_SPRRegisterList, + k_VectorList, k_ShiftedRegister, k_ShiftedImmediate, k_ShifterImmediate, @@ -279,6 +292,10 @@ class ARMOperand : public MCParsedAsmOperand { unsigned Val; } Cop; + struct { + unsigned Val; + } CoprocOption; + struct { unsigned Mask:4; } ITMask; @@ -304,6 +321,12 @@ 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; @@ -324,9 +347,11 @@ class ARMOperand : public MCParsedAsmOperand { 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 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) - } Mem; + } Memory; struct { unsigned RegNum; @@ -384,10 +409,16 @@ public: case k_SPRRegisterList: Registers = o.Registers; break; + case k_VectorList: + VectorList = o.VectorList; + break; case k_CoprocNum: case k_CoprocReg: Cop = o.Cop; break; + case k_CoprocOption: + CoprocOption = o.CoprocOption; + break; case k_Immediate: Imm = o.Imm; break; @@ -398,7 +429,7 @@ public: MBOpt = o.MBOpt; break; case k_Memory: - Mem = o.Mem; + Memory = o.Memory; break; case k_PostIndexRegister: PostIdxReg = o.PostIdxReg; @@ -493,6 +524,7 @@ public: 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; } @@ -629,6 +661,14 @@ public: 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 != k_Immediate) return false; @@ -637,6 +677,14 @@ public: 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 != k_Immediate) return false; @@ -661,20 +709,23 @@ public: bool isPostIdxReg() const { return Kind == k_PostIndexRegister && PostIdxReg.ShiftTy == ARM_AM::no_shift; } - bool isMemNoOffset() const { + bool isMemNoOffset(bool alignOK = false) const { if (!isMemory()) return false; // No offset of any kind. - return Mem.OffsetRegNum == 0 && Mem.OffsetImm == 0; + return Memory.OffsetRegNum == 0 && Memory.OffsetImm == 0 && + (alignOK || Memory.Alignment == 0); + } + bool isAlignedMemory() const { + return isMemNoOffset(true); } bool isAddrMode2() const { - if (!isMemory()) - return false; + if (!isMemory() || Memory.Alignment != 0) return false; // Check for register offset. - if (Mem.OffsetRegNum) return true; + if (Memory.OffsetRegNum) return true; // Immediate offset in range [-4095, 4095]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return Val > -4096 && Val < 4096; } bool isAM2OffsetImm() const { @@ -687,15 +738,14 @@ public: return Val > -4096 && Val < 4096; } bool isAddrMode3() const { - if (!isMemory()) - return false; + if (!isMemory() || Memory.Alignment != 0) return false; // No shifts are legal for AM3. - if (Mem.ShiftType != ARM_AM::no_shift) return false; + if (Memory.ShiftType != ARM_AM::no_shift) return false; // Check for register offset. - if (Mem.OffsetRegNum) return true; + if (Memory.OffsetRegNum) return true; // Immediate offset in range [-255, 255]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return Val > -256 && Val < 256; } bool isAM3Offset() const { @@ -711,139 +761,140 @@ public: return (Val > -256 && Val < 256) || Val == INT32_MIN; } bool isAddrMode5() const { - if (!isMemory()) - return false; + // 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 (Mem.OffsetRegNum) return false; + if (Memory.OffsetRegNum) return false; // Immediate offset in range [-1020, 1020] and a multiple of 4. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return (Val >= -1020 && Val <= 1020 && ((Val & 3) == 0)) || - Val == INT32_MIN; + Val == INT32_MIN; } bool isMemTBB() const { - if (!isMemory() || !Mem.OffsetRegNum || Mem.isNegative || - Mem.ShiftType != ARM_AM::no_shift) + if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative || + Memory.ShiftType != ARM_AM::no_shift || Memory.Alignment != 0) return false; return true; } bool isMemTBH() const { - if (!isMemory() || !Mem.OffsetRegNum || Mem.isNegative || - Mem.ShiftType != ARM_AM::lsl || Mem.ShiftImm != 1) + if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative || + Memory.ShiftType != ARM_AM::lsl || Memory.ShiftImm != 1 || + Memory.Alignment != 0 ) return false; return true; } bool isMemRegOffset() const { - if (!isMemory() || !Mem.OffsetRegNum) + if (!isMemory() || !Memory.OffsetRegNum || Memory.Alignment != 0) return false; return true; } bool isT2MemRegOffset() const { - if (!isMemory() || !Mem.OffsetRegNum || Mem.isNegative) + if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative || + Memory.Alignment != 0) return false; // Only lsl #{0, 1, 2, 3} allowed. - if (Mem.ShiftType == ARM_AM::no_shift) + if (Memory.ShiftType == ARM_AM::no_shift) return true; - if (Mem.ShiftType != ARM_AM::lsl || Mem.ShiftImm > 3) + 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() || !Mem.OffsetRegNum || Mem.isNegative || - Mem.ShiftType != ARM_AM::no_shift) + if (!isMemory() || !Memory.OffsetRegNum || Memory.isNegative || + Memory.ShiftType != ARM_AM::no_shift || Memory.Alignment != 0) return false; - return isARMLowRegister(Mem.BaseRegNum) && - (!Mem.OffsetRegNum || isARMLowRegister(Mem.OffsetRegNum)); + return isARMLowRegister(Memory.BaseRegNum) && + (!Memory.OffsetRegNum || isARMLowRegister(Memory.OffsetRegNum)); } bool isMemThumbRIs4() const { - if (!isMemory() || Mem.OffsetRegNum != 0 || - !isARMLowRegister(Mem.BaseRegNum)) + if (!isMemory() || Memory.OffsetRegNum != 0 || + !isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0) return false; // Immediate offset, multiple of 4 in range [0, 124]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 124 && (Val % 4) == 0; } bool isMemThumbRIs2() const { - if (!isMemory() || Mem.OffsetRegNum != 0 || - !isARMLowRegister(Mem.BaseRegNum)) + if (!isMemory() || Memory.OffsetRegNum != 0 || + !isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0) return false; // Immediate offset, multiple of 4 in range [0, 62]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 62 && (Val % 2) == 0; } bool isMemThumbRIs1() const { - if (!isMemory() || Mem.OffsetRegNum != 0 || - !isARMLowRegister(Mem.BaseRegNum)) + if (!isMemory() || Memory.OffsetRegNum != 0 || + !isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0) return false; // Immediate offset in range [0, 31]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 31; } bool isMemThumbSPI() const { - if (!isMemory() || Mem.OffsetRegNum != 0 || Mem.BaseRegNum != ARM::SP) + if (!isMemory() || Memory.OffsetRegNum != 0 || + Memory.BaseRegNum != ARM::SP || Memory.Alignment != 0) return false; // Immediate offset, multiple of 4 in range [0, 1020]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 1020 && (Val % 4) == 0; } bool isMemImm8s4Offset() const { - if (!isMemory() || Mem.OffsetRegNum != 0) + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset a multiple of 4 in range [-1020, 1020]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + 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() || Mem.OffsetRegNum != 0) + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset a multiple of 4 in range [0, 1020]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 1020 && (Val & 3) == 0; } bool isMemImm8Offset() const { - if (!isMemory() || Mem.OffsetRegNum != 0) + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset in range [-255, 255]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return (Val == INT32_MIN) || (Val > -256 && Val < 256); } bool isMemPosImm8Offset() const { - if (!isMemory() || Mem.OffsetRegNum != 0) + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset in range [0, 255]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val < 256; } bool isMemNegImm8Offset() const { - if (!isMemory() || Mem.OffsetRegNum != 0) + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset in range [-255, -1]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return Val > -256 && Val < 0; } bool isMemUImm12Offset() 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() || Mem.OffsetRegNum != 0) + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset in range [0, 4095]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return (Val >= 0 && Val < 4096); } bool isMemImm12Offset() const { @@ -853,11 +904,11 @@ public: if (Kind == k_Immediate && !isa(getImm())) return true; - if (!isMemory() || Mem.OffsetRegNum != 0) + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset in range [-4095, 4095]. - if (!Mem.OffsetImm) return true; - int64_t Val = Mem.OffsetImm->getValue(); + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); return (Val > -4096 && Val < 4096) || (Val == INT32_MIN); } bool isPostIdxImm8() const { @@ -868,10 +919,47 @@ public: 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); + } 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 isVecListTwoD() const { + if (Kind != k_VectorList) return false; + return VectorList.Count == 2; + } + + bool isVecListThreeD() const { + if (Kind != k_VectorList) return false; + return VectorList.Count == 3; + } + + bool isVecListFourD() const { + if (Kind != k_VectorList) return false; + return VectorList.Count == 4; + } + + 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; + } + bool isVectorIndex8() const { if (Kind != k_VectorIndex) return false; return VectorIndex.Val < 8; @@ -885,7 +973,72 @@ public: return VectorIndex.Val < 2; } + bool isNEONi8splat() 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(); + // i8 value splatted across 8 bytes. The immediate is just the 8 byte + // value. + return Value >= 0 && Value < 256; + } + 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); + } + + 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); + } + + 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(); + // 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; + } void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediates when possible. Null MCExpr = 0. @@ -909,6 +1062,16 @@ public: Inst.addOperand(MCOperand::CreateImm(getCoproc())); } + void addCoprocRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + 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)); @@ -919,11 +1082,6 @@ public: Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode()))); } - void addCoprocRegOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getCoproc())); - } - void addCCOutOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(getReg())); @@ -1108,6 +1266,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()); @@ -1120,13 +1294,19 @@ public: void addMemNoOffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + } + + 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)); } void addAddrMode2Operands(MCInst &Inst, unsigned N) const { assert(N == 3 && "Invalid number of operands!"); - int32_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0; - if (!Mem.OffsetRegNum) { + 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; @@ -1135,11 +1315,11 @@ public: } else { // For register offset, we encode the shift type and negation flag // here. - Val = ARM_AM::getAM2Opc(Mem.isNegative ? ARM_AM::sub : ARM_AM::add, - Mem.ShiftImm, Mem.ShiftType); + Val = ARM_AM::getAM2Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add, + Memory.ShiftImm, Memory.ShiftType); } - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); Inst.addOperand(MCOperand::CreateImm(Val)); } @@ -1159,8 +1339,8 @@ public: void addAddrMode3Operands(MCInst &Inst, unsigned N) const { assert(N == 3 && "Invalid number of operands!"); - int32_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0; - if (!Mem.OffsetRegNum) { + 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; @@ -1169,10 +1349,10 @@ public: } else { // For register offset, we encode the shift type and negation flag // here. - Val = ARM_AM::getAM3Opc(Mem.isNegative ? ARM_AM::sub : ARM_AM::add, 0); + Val = ARM_AM::getAM3Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add, 0); } - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); Inst.addOperand(MCOperand::CreateImm(Val)); } @@ -1200,36 +1380,45 @@ public: 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 = Mem.OffsetImm ? Mem.OffsetImm->getValue() / 4 : 0; + 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(Mem.BaseRegNum)); + 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 = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0; - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + 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 = Mem.OffsetImm ? Mem.OffsetImm->getValue() / 4 : 0; - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + 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 = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0; - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::CreateImm(Val)); } @@ -1251,8 +1440,8 @@ public: } // Otherwise, it's a normal memory reg+offset. - int64_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0; - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::CreateImm(Val)); } @@ -1266,70 +1455,70 @@ public: } // Otherwise, it's a normal memory reg+offset. - int64_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0; - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::CreateImm(Val)); } void addMemTBBOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); + 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(Mem.BaseRegNum)); - Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); + 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(Mem.isNegative ? ARM_AM::sub : ARM_AM::add, - Mem.ShiftImm, Mem.ShiftType); - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); + 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 addT2MemRegOffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 3 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); - Inst.addOperand(MCOperand::CreateImm(Mem.ShiftImm)); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); + Inst.addOperand(MCOperand::CreateImm(Memory.ShiftImm)); } void addMemThumbRROperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Memory.OffsetRegNum)); } void addMemThumbRIs4Operands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - int64_t Val = Mem.OffsetImm ? (Mem.OffsetImm->getValue() / 4) : 0; - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 4) : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::CreateImm(Val)); } void addMemThumbRIs2Operands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - int64_t Val = Mem.OffsetImm ? (Mem.OffsetImm->getValue() / 2) : 0; - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 2) : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::CreateImm(Val)); } void addMemThumbRIs1Operands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - int64_t Val = Mem.OffsetImm ? (Mem.OffsetImm->getValue()) : 0; - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue()) : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::CreateImm(Val)); } void addMemThumbSPIOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - int64_t Val = Mem.OffsetImm ? (Mem.OffsetImm->getValue() / 4) : 0; - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 4) : 0; + Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::CreateImm(Val)); } @@ -1344,6 +1533,18 @@ public: 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)); @@ -1371,6 +1572,39 @@ 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())); @@ -1386,6 +1620,66 @@ public: 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) { @@ -1420,6 +1714,14 @@ public: 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(k_CCOut); Op->Reg.RegNum = RegNum; @@ -1522,6 +1824,16 @@ 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); @@ -1552,15 +1864,17 @@ public: unsigned OffsetRegNum, ARM_AM::ShiftOpc ShiftType, unsigned ShiftImm, + unsigned Alignment, bool isNegative, SMLoc S, SMLoc E) { ARMOperand *Op = new ARMOperand(k_Memory); - Op->Mem.BaseRegNum = BaseRegNum; - Op->Mem.OffsetImm = OffsetImm; - Op->Mem.OffsetRegNum = OffsetRegNum; - Op->Mem.ShiftType = ShiftType; - Op->Mem.ShiftImm = ShiftImm; - Op->Mem.isNegative = isNegative; + 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; @@ -1620,9 +1934,10 @@ void ARMOperand::print(raw_ostream &OS) const { OS << ""; break; case k_ITCondMask: { - static char MaskStr[][6] = { "()", "(t)", "(e)", "(tt)", "(et)", "(te)", - "(ee)", "(ttt)", "(ett)", "(tet)", "(eet)", "(tte)", "(ete)", - "(tee)", "(eee)" }; + 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; @@ -1633,6 +1948,9 @@ void ARMOperand::print(raw_ostream &OS) const { case k_CoprocReg: OS << ""; break; + case k_CoprocOption: + OS << ""; + break; case k_MSRMask: OS << ""; break; @@ -1644,7 +1962,7 @@ void ARMOperand::print(raw_ostream &OS) const { break; case k_Memory: OS << ""; break; case k_PostIndexRegister: @@ -1708,6 +2026,10 @@ void ARMOperand::print(raw_ostream &OS) const { OS << ">"; break; } + case k_VectorList: + OS << ""; + break; case k_Token: OS << "'" << getToken() << "'"; break; @@ -1756,38 +2078,6 @@ int ARMAsmParser::tryParseRegister() { Parser.Lex(); // Eat identifier token. -#if 0 - // 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; - SMLoc ExprLoc = Parser.getTok().getLoc(); - 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())); - } -#endif - return RegNum; } @@ -1914,7 +2204,6 @@ tryParseRegisterWithWriteBack(SmallVectorImpl &Operands) { Parser.Lex(); // Eat left bracket token. const MCExpr *ImmVal; - SMLoc ExprLoc = Parser.getTok().getLoc(); if (getParser().ParseExpression(ImmVal)) return MatchOperand_ParseFail; const MCConstantExpr *MCE = dyn_cast(ImmVal); @@ -2024,7 +2313,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) @@ -2042,7 +2332,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) @@ -2053,6 +2344,40 @@ parseCoprocRegOperand(SmallVectorImpl &Operands) { return MatchOperand_Success; } +/// parseCoprocOptionOperand - Try to parse an coprocessor option operand. +/// coproc_option : '{' imm0_255 '}' +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseCoprocOptionOperand(SmallVectorImpl &Operands) { + SMLoc S = Parser.getTok().getLoc(); + + // 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 '{' + + 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(); + + // Check for and consume the closing '}' + if (Parser.getTok().isNot(AsmToken::RCurly)) + return MatchOperand_ParseFail; + SMLoc E = Parser.getTok().getLoc(); + Parser.Lex(); // Eat the '}' + + Operands.push_back(ARMOperand::CreateCoprocOption(Val, S, E)); + return MatchOperand_Success; +} + // 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. @@ -2090,7 +2415,7 @@ parseRegisterList(SmallVectorImpl &Operands) { if (Reg == -1) return Error(RegLoc, "register expected"); - MCRegisterClass *RC; + const MCRegisterClass *RC; if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg)) RC = &ARMMCRegisterClasses[ARM::GPRRegClassID]; else if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg)) @@ -2165,6 +2490,98 @@ parseRegisterList(SmallVectorImpl &Operands) { return 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; + } +} + +// parse a vector register list +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseVectorList(SmallVectorImpl &Operands) { + if(Parser.getTok().isNot(AsmToken::LCurly)) + return MatchOperand_NoMatch; + + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); // Eat '{' token. + SMLoc RegLoc = Parser.getTok().getLoc(); + + 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; + } + + 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::CreateVectorList(FirstReg, Count, S, E)); + return MatchOperand_Success; +} + /// parseMemBarrierOptOperand - Try to parse DSB/DMB data barrier options. ARMAsmParser::OperandMatchResultTy ARMAsmParser:: parseMemBarrierOptOperand(SmallVectorImpl &Operands) { @@ -2313,9 +2730,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") @@ -2996,6 +3417,66 @@ cvtThumbMultiply(MCInst &Inst, unsigned Opcode, 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. bool ARMAsmParser:: @@ -3021,7 +3502,7 @@ parseMemory(SmallVectorImpl &Operands) { Parser.Lex(); // Eat right bracket token. Operands.push_back(ARMOperand::CreateMem(BaseRegNum, 0, 0, ARM_AM::no_shift, - 0, false, S, E)); + 0, 0, false, S, E)); // If there's a pre-indexing writeback marker, '!', just add it as a token // operand. It's rather odd, but syntactically valid. @@ -3036,7 +3517,54 @@ parseMemory(SmallVectorImpl &Operands) { assert(Tok.is(AsmToken::Comma) && "Lost comma in memory operand?!"); Parser.Lex(); // Eat the comma. - // If we have a '#' it's an immediate offset, else assume it's a register + // If we have a ':', it's an alignment specifier. + if (Parser.getTok().is(AsmToken::Colon)) { + Parser.Lex(); // Eat the ':'. + E = Parser.getTok().getLoc(); + + const MCExpr *Expr; + if (getParser().ParseExpression(Expr)) + return true; + + // The expression has to be a constant. Memory references with relocations + // don't come through here, as they use the