X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTarget%2FARM%2FAsmParser%2FARMAsmParser.cpp;h=59461e8f55325fa0a8418149d347b51b84e504cf;hp=7e66af6eaf2de5cba6c33469b3b71342a4d22a92;hb=2b5910a7675ddb005e72b0536499a2b983813dff;hpb=049ffbbdf2a43d5529cb56b6bb696d20d28ff217 diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 7e66af6eaf2..59461e8f553 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -129,12 +129,13 @@ public: class ARMAsmParser : public MCTargetAsmParser { MCSubtargetInfo &STI; - MCAsmParser &Parser; const MCInstrInfo &MII; const MCRegisterInfo *MRI; UnwindContext UC; ARMTargetStreamer &getTargetStreamer() { + assert(getParser().getStreamer().getTargetStreamer() && + "do not have a target streamer"); MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); return static_cast(TS); } @@ -163,7 +164,10 @@ class ARMAsmParser : public MCTargetAsmParser { // according to count of instructions in block. // ~0U if no active IT block. } ITState; - bool inITBlock() { return ITState.CurPosition != ~0U;} + bool inITBlock() { return ITState.CurPosition != ~0U; } + bool lastInITBlock() { + return ITState.CurPosition == 4 - countTrailingZeros(ITState.Mask); + } void forwardITPosition() { if (!inITBlock()) return; // Move to the next instruction in the IT block, if there is one. If not, @@ -173,22 +177,23 @@ class ARMAsmParser : public MCTargetAsmParser { ITState.CurPosition = ~0U; // Done with the IT block after this. } - - MCAsmParser &getParser() const { return Parser; } - MCAsmLexer &getLexer() const { return Parser.getLexer(); } - void Note(SMLoc L, const Twine &Msg, ArrayRef Ranges = None) { - return Parser.Note(L, Msg, Ranges); + return getParser().Note(L, Msg, Ranges); } bool Warning(SMLoc L, const Twine &Msg, ArrayRef Ranges = None) { - return Parser.Warning(L, Msg, Ranges); + return getParser().Warning(L, Msg, Ranges); } bool Error(SMLoc L, const Twine &Msg, ArrayRef Ranges = None) { - return Parser.Error(L, Msg, Ranges); + return getParser().Error(L, Msg, Ranges); } + bool validatetLDMRegList(MCInst Inst, const OperandVector &Operands, + unsigned ListNo, bool IsARPop = false); + bool validatetSTMRegList(MCInst Inst, const OperandVector &Operands, + unsigned ListNo); + int tryParseRegister(); bool tryParseRegisterWithWriteBack(OperandVector &); int tryParseShiftRegister(OperandVector &); @@ -265,6 +270,12 @@ class ARMAsmParser : public MCTargetAsmParser { bool hasARM() const { return !(STI.getFeatureBits() & ARM::FeatureNoARM); } + bool hasThumb2DSP() const { + return STI.getFeatureBits() & ARM::FeatureDSPThumb2; + } + bool hasD16() const { + return STI.getFeatureBits() & ARM::FeatureD16; + } void SwitchMode() { uint64_t FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb)); @@ -302,6 +313,7 @@ class ARMAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseSetEndImm(OperandVector &); OperandMatchResultTy parseShifterImm(OperandVector &); OperandMatchResultTy parseRotImm(OperandVector &); + OperandMatchResultTy parseModImm(OperandVector &); OperandMatchResultTy parseBitfield(OperandVector &); OperandMatchResultTy parsePostIdxReg(OperandVector &); OperandMatchResultTy parseAM3Offset(OperandVector &); @@ -315,7 +327,7 @@ class ARMAsmParser : public MCTargetAsmParser { void cvtThumbBranches(MCInst &Inst, const OperandVector &); bool validateInstruction(MCInst &Inst, const OperandVector &Ops); - bool processInstruction(MCInst &Inst, const OperandVector &Ops); + bool processInstruction(MCInst &Inst, const OperandVector &Ops, MCStreamer &Out); bool shouldOmitCCOutOperand(StringRef Mnemonic, OperandVector &Operands); bool shouldOmitPredicateOperand(StringRef Mnemonic, OperandVector &Operands); @@ -330,10 +342,9 @@ public: }; - ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser, - const MCInstrInfo &MII, - const MCTargetOptions &Options) - : MCTargetAsmParser(), STI(_STI), Parser(_Parser), MII(MII), UC(_Parser) { + ARMAsmParser(MCSubtargetInfo & _STI, MCAsmParser & _Parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(), STI(_STI), MII(MII), UC(_Parser) { MCAsmParserExtension::Initialize(_Parser); // Cache the MCRegisterInfo. @@ -398,6 +409,7 @@ class ARMOperand : public MCParsedAsmOperand { k_ShiftedImmediate, k_ShifterImmediate, k_RotateImmediate, + k_ModifiedImmediate, k_BitfieldDescriptor, k_Token } Kind; @@ -509,6 +521,11 @@ class ARMOperand : public MCParsedAsmOperand { unsigned Imm; }; + struct ModImmOp { + unsigned Bits; + unsigned Rot; + }; + struct BitfieldOp { unsigned LSB; unsigned Width; @@ -535,6 +552,7 @@ class ARMOperand : public MCParsedAsmOperand { struct RegShiftedRegOp RegShiftedReg; struct RegShiftedImmOp RegShiftedImm; struct RotImmOp RotImm; + struct ModImmOp ModImm; struct BitfieldOp Bitfield; }; @@ -610,6 +628,9 @@ public: case k_RotateImmediate: RotImm = o.RotImm; break; + case k_ModifiedImmediate: + ModImm = o.ModImm; + break; case k_BitfieldDescriptor: Bitfield = o.Bitfield; break; @@ -1018,33 +1039,17 @@ public: } bool isAdrLabel() 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, but it can't fit - // into shift immediate encoding, we reject it. - if (isImm() && !isa(getImm())) return true; - else return (isARMSOImm() || isARMSOImmNeg()); - } - bool isARMSOImm() const { - if (!isImm()) 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 (!isImm()) return false; - const MCConstantExpr *CE = dyn_cast(getImm()); - if (!CE) return false; - int64_t Value = CE->getValue(); - return ARM_AM::getSOImmVal(~Value) != -1; - } - bool isARMSOImmNeg() const { + // reference needing a fixup. + if (isImm() && !isa(getImm())) + return true; + + // If it is a constant, it must fit into a modified immediate encoding. if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); - // Only use this when not representable as a plain so_imm. - return ARM_AM::getSOImmVal(Value) == -1 && - ARM_AM::getSOImmVal(-Value) != -1; + return (ARM_AM::getSOImmVal(Value) != -1 || + ARM_AM::getSOImmVal(-Value) != -1);; } bool isT2SOImm() const { if (!isImm()) return false; @@ -1089,6 +1094,22 @@ public: bool isRegShiftedReg() const { return Kind == k_ShiftedRegister; } bool isRegShiftedImm() const { return Kind == k_ShiftedImmediate; } bool isRotImm() const { return Kind == k_RotateImmediate; } + bool isModImm() const { return Kind == k_ModifiedImmediate; } + bool isModImmNot() const { + if (!isImm()) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ARM_AM::getSOImmVal(~Value) != -1; + } + bool isModImmNeg() const { + if (!isImm()) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ARM_AM::getSOImmVal(Value) == -1 && + ARM_AM::getSOImmVal(-Value) != -1; + } bool isBitfield() const { return Kind == k_BitfieldDescriptor; } bool isPostIdxRegShifted() const { return Kind == k_PostIndexRegister; } bool isPostIdxReg() const { @@ -1617,9 +1638,18 @@ public: 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); + unsigned Value = CE->getValue(); + return ARM_AM::isNEONi16splat(Value); + } + + bool isNEONi16splatNot() const { + if (!isImm()) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. + if (!CE) return false; + unsigned Value = CE->getValue(); + return ARM_AM::isNEONi16splat(~Value & 0xffff); } bool isNEONi32splat() const { @@ -1630,12 +1660,18 @@ public: 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); + unsigned Value = CE->getValue(); + return ARM_AM::isNEONi32splat(Value); + } + + bool isNEONi32splatNot() const { + if (!isImm()) + return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // Must be a constant. + if (!CE) return false; + unsigned Value = CE->getValue(); + return ARM_AM::isNEONi32splat(~Value); } bool isNEONByteReplicate(unsigned NumBytes) const { @@ -1671,6 +1707,7 @@ public: 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. + // FIXME: This is probably wrong and a copy and paste from previous example return (Value >= 0 && Value < 256) || (Value >= 0x0100 && Value <= 0xff00) || (Value >= 0x010000 && Value <= 0xff0000) || @@ -1686,6 +1723,7 @@ public: 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. + // FIXME: This is probably wrong and a copy and paste from previous example return (Value >= 0 && Value < 256) || (Value >= 0x0100 && Value <= 0xff00) || (Value >= 0x010000 && Value <= 0xff0000) || @@ -1807,6 +1845,30 @@ public: Inst.addOperand(MCOperand::CreateImm(RotImm.Imm >> 3)); } + void addModImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + + // Support for fixups (MCFixup) + if (isImm()) + return addImmOperands(Inst, N); + + Inst.addOperand(MCOperand::CreateImm(ModImm.Bits | (ModImm.Rot << 7))); + } + + void addModImmNotOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *CE = dyn_cast(getImm()); + uint32_t Enc = ARM_AM::getSOImmVal(~CE->getValue()); + Inst.addOperand(MCOperand::CreateImm(Enc)); + } + + void addModImmNegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *CE = dyn_cast(getImm()); + uint32_t Enc = ARM_AM::getSOImmVal(-CE->getValue()); + Inst.addOperand(MCOperand::CreateImm(Enc)); + } + void addBitfieldOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // Munge the lsb/width into a bitfield mask. @@ -1963,22 +2025,6 @@ public: Inst.addOperand(MCOperand::CreateImm(Memory.OffsetImm->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 addARMSOImmNegOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - // The operand is actually a so_imm, but we have its - // negation in the assembly source, so twiddle it here. - const MCConstantExpr *CE = dyn_cast(getImm()); - Inst.addOperand(MCOperand::CreateImm(-CE->getValue())); - } - void addMemBarrierOptOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateImm(unsigned(getMemBarrierOpt()))); @@ -2399,10 +2445,16 @@ public: // 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; + Value = ARM_AM::encodeNEONi16splat(Value); + Inst.addOperand(MCOperand::CreateImm(Value)); + } + + void addNEONi16splatNotOperands(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(); + Value = ARM_AM::encodeNEONi16splat(~Value & 0xffff); Inst.addOperand(MCOperand::CreateImm(Value)); } @@ -2411,12 +2463,16 @@ public: // 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; + Value = ARM_AM::encodeNEONi32splat(Value); + Inst.addOperand(MCOperand::CreateImm(Value)); + } + + void addNEONi32splatNotOperands(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(); + Value = ARM_AM::encodeNEONi32splat(~Value); Inst.addOperand(MCOperand::CreateImm(Value)); } @@ -2601,6 +2657,16 @@ public: return Op; } + static std::unique_ptr CreateModImm(unsigned Bits, unsigned Rot, + SMLoc S, SMLoc E) { + auto Op = make_unique(k_ModifiedImmediate); + Op->ModImm.Bits = Bits; + Op->ModImm.Rot = Rot; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + static std::unique_ptr CreateBitfield(unsigned LSB, unsigned Width, SMLoc S, SMLoc E) { auto Op = make_unique(k_BitfieldDescriptor); @@ -2854,6 +2920,10 @@ void ARMOperand::print(raw_ostream &OS) const { case k_RotateImmediate: OS << ""; break; + case k_ModifiedImmediate: + OS << ""; + break; case k_BitfieldDescriptor: OS << ""; @@ -2903,8 +2973,9 @@ static unsigned MatchRegisterName(StringRef Name); bool ARMAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { - StartLoc = Parser.getTok().getLoc(); - EndLoc = Parser.getTok().getEndLoc(); + const AsmToken &Tok = getParser().getTok(); + StartLoc = Tok.getLoc(); + EndLoc = Tok.getEndLoc(); RegNo = tryParseRegister(); return (RegNo == (unsigned)-1); @@ -2915,6 +2986,7 @@ bool ARMAsmParser::ParseRegister(unsigned &RegNo, /// returned. Otherwise return -1. /// int ARMAsmParser::tryParseRegister() { + MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) return -1; @@ -2956,6 +3028,10 @@ int ARMAsmParser::tryParseRegister() { return Entry->getValue(); } + // Some FPUs only have 16 D registers, so D16-D31 are invalid + if (hasD16() && RegNum >= ARM::D16 && RegNum <= ARM::D31) + return -1; + Parser.Lex(); // Eat identifier token. return RegNum; @@ -2967,6 +3043,7 @@ int ARMAsmParser::tryParseRegister() { // consumed in the process of trying to parse the shifter (i.e., when it is // indeed a shifter operand, but malformed). int ARMAsmParser::tryParseShiftRegister(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) @@ -3069,6 +3146,7 @@ int ARMAsmParser::tryParseShiftRegister(OperandVector &Operands) { /// TODO this is likely to change to allow different register types and or to /// parse for a specific register type. bool ARMAsmParser::tryParseRegisterWithWriteBack(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); const AsmToken &RegTok = Parser.getTok(); int RegNo = tryParseRegister(); if (RegNo == -1) @@ -3165,6 +3243,7 @@ static int MatchCoprocessorOperandName(StringRef Name, char CoprocOp) { /// parseITCondCode - Try to parse a condition code for an IT instruction. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseITCondCode(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Identifier)) @@ -3202,6 +3281,7 @@ ARMAsmParser::parseITCondCode(OperandVector &Operands) { /// number, the token is eaten and the operand is added to the operand list. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseCoprocNumOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) @@ -3224,6 +3304,7 @@ ARMAsmParser::parseCoprocNumOperand(OperandVector &Operands) { /// number, the token is eaten and the operand is added to the operand list. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseCoprocRegOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) @@ -3242,6 +3323,7 @@ ARMAsmParser::parseCoprocRegOperand(OperandVector &Operands) { /// coproc_option : '{' imm0_255 '}' ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseCoprocOptionOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); // If this isn't a '{', this isn't a coprocessor immediate operand. @@ -3319,6 +3401,7 @@ static unsigned getDRegFromQReg(unsigned QReg) { /// Parse a register list. bool ARMAsmParser::parseRegisterList(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); assert(Parser.getTok().is(AsmToken::LCurly) && "Token is not a Left Curly Brace"); SMLoc S = Parser.getTok().getLoc(); @@ -3450,6 +3533,7 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands) { // Helper function to parse the lane index for vector lists. ARMAsmParser::OperandMatchResultTy ARMAsmParser:: parseVectorLane(VectorLaneTy &LaneKind, unsigned &Index, SMLoc &EndLoc) { + MCAsmParser &Parser = getParser(); Index = 0; // Always return a defined index value. if (Parser.getTok().is(AsmToken::LBrac)) { Parser.Lex(); // Eat the '['. @@ -3501,6 +3585,7 @@ parseVectorLane(VectorLaneTy &LaneKind, unsigned &Index, SMLoc &EndLoc) { // parse a vector register list ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseVectorList(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); VectorLaneTy LaneKind; unsigned LaneIndex; SMLoc S = Parser.getTok().getLoc(); @@ -3752,6 +3837,7 @@ ARMAsmParser::parseVectorList(OperandVector &Operands) { /// parseMemBarrierOptOperand - Try to parse DSB/DMB data barrier options. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseMemBarrierOptOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); unsigned Opt; @@ -3823,6 +3909,7 @@ ARMAsmParser::parseMemBarrierOptOperand(OperandVector &Operands) { /// parseInstSyncBarrierOptOperand - Try to parse ISB inst sync barrier options. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseInstSyncBarrierOptOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); unsigned Opt; @@ -3874,6 +3961,7 @@ ARMAsmParser::parseInstSyncBarrierOptOperand(OperandVector &Operands) { /// parseProcIFlagsOperand - Try to parse iflags from CPS instruction. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseProcIFlagsOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Identifier)) @@ -3908,6 +3996,7 @@ ARMAsmParser::parseProcIFlagsOperand(OperandVector &Operands) { /// parseMSRMaskOperand - Try to parse mask flags from MSR instruction. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseMSRMaskOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Identifier)) @@ -3928,9 +4017,6 @@ ARMAsmParser::parseMSRMaskOperand(OperandVector &Operands) { // should really only be allowed when writing a special register. Note // they get dropped in the MRS instruction reading a special register as // the SYSm field is only 8 bits. - // - // FIXME: the _g and _nzcvqg versions are only allowed if the processor - // includes the DSP extension but that is not checked. .Case("apsr", 0x800) .Case("apsr_nzcvq", 0x800) .Case("apsr_g", 0x400) @@ -3962,6 +4048,11 @@ ARMAsmParser::parseMSRMaskOperand(OperandVector &Operands) { if (FlagsVal == ~0U) return MatchOperand_NoMatch; + if (!hasThumb2DSP() && (FlagsVal & 0x400)) + // The _g and _nzcvqg versions are only valid if the DSP extension is + // available. + return MatchOperand_NoMatch; + if (!hasV7Ops() && FlagsVal >= 0x811 && FlagsVal <= 0x813) // basepri, basepri_max and faultmask only valid for V7m. return MatchOperand_NoMatch; @@ -4038,6 +4129,7 @@ ARMAsmParser::parseMSRMaskOperand(OperandVector &Operands) { /// use in the MRS/MSR instructions added to support virtualization. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseBankedRegOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Identifier)) @@ -4093,6 +4185,7 @@ ARMAsmParser::parseBankedRegOperand(OperandVector &Operands) { ARMAsmParser::OperandMatchResultTy ARMAsmParser::parsePKHImm(OperandVector &Operands, StringRef Op, int Low, int High) { + MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) { Error(Parser.getTok().getLoc(), Op + " operand expected."); @@ -4140,6 +4233,7 @@ ARMAsmParser::parsePKHImm(OperandVector &Operands, StringRef Op, int Low, ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseSetEndImm(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); if (Tok.isNot(AsmToken::Identifier)) { @@ -4169,6 +4263,7 @@ ARMAsmParser::parseSetEndImm(OperandVector &Operands) { /// n == 32 encoded as n == 0. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseShifterImm(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); if (Tok.isNot(AsmToken::Identifier)) { @@ -4239,6 +4334,7 @@ ARMAsmParser::parseShifterImm(OperandVector &Operands) { /// ror #n 'n' in {0, 8, 16, 24} ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseRotImm(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); if (Tok.isNot(AsmToken::Identifier)) @@ -4283,8 +4379,126 @@ ARMAsmParser::parseRotImm(OperandVector &Operands) { return MatchOperand_Success; } +ARMAsmParser::OperandMatchResultTy +ARMAsmParser::parseModImm(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + MCAsmLexer &Lexer = getLexer(); + int64_t Imm1, Imm2; + + SMLoc S = Parser.getTok().getLoc(); + + // 1) A mod_imm operand can appear in the place of a register name: + // add r0, #mod_imm + // add r0, r0, #mod_imm + // to correctly handle the latter, we bail out as soon as we see an + // identifier. + // + // 2) Similarly, we do not want to parse into complex operands: + // mov r0, #mod_imm + // mov r0, :lower16:(_foo) + if (Parser.getTok().is(AsmToken::Identifier) || + Parser.getTok().is(AsmToken::Colon)) + return MatchOperand_NoMatch; + + // Hash (dollar) is optional as per the ARMARM + if (Parser.getTok().is(AsmToken::Hash) || + Parser.getTok().is(AsmToken::Dollar)) { + // Avoid parsing into complex operands (#:) + if (Lexer.peekTok().is(AsmToken::Colon)) + return MatchOperand_NoMatch; + + // Eat the hash (dollar) + Parser.Lex(); + } + + SMLoc Sx1, Ex1; + Sx1 = Parser.getTok().getLoc(); + const MCExpr *Imm1Exp; + if (getParser().parseExpression(Imm1Exp, Ex1)) { + Error(Sx1, "malformed expression"); + return MatchOperand_ParseFail; + } + + const MCConstantExpr *CE = dyn_cast(Imm1Exp); + + if (CE) { + // Immediate must fit within 32-bits + Imm1 = CE->getValue(); + int Enc = ARM_AM::getSOImmVal(Imm1); + if (Enc != -1 && Parser.getTok().is(AsmToken::EndOfStatement)) { + // We have a match! + Operands.push_back(ARMOperand::CreateModImm((Enc & 0xFF), + (Enc & 0xF00) >> 7, + Sx1, Ex1)); + return MatchOperand_Success; + } + + // We have parsed an immediate which is not for us, fallback to a plain + // immediate. This can happen for instruction aliases. For an example, + // ARMInstrInfo.td defines the alias [mov <-> mvn] which can transform + // a mov (mvn) with a mod_imm_neg/mod_imm_not operand into the opposite + // instruction with a mod_imm operand. The alias is defined such that the + // parser method is shared, that's why we have to do this here. + if (Parser.getTok().is(AsmToken::EndOfStatement)) { + Operands.push_back(ARMOperand::CreateImm(Imm1Exp, Sx1, Ex1)); + return MatchOperand_Success; + } + } else { + // Operands like #(l1 - l2) can only be evaluated at a later stage (via an + // MCFixup). Fallback to a plain immediate. + Operands.push_back(ARMOperand::CreateImm(Imm1Exp, Sx1, Ex1)); + return MatchOperand_Success; + } + + // From this point onward, we expect the input to be a (#bits, #rot) pair + if (Parser.getTok().isNot(AsmToken::Comma)) { + Error(Sx1, "expected modified immediate operand: #[0, 255], #even[0-30]"); + return MatchOperand_ParseFail; + } + + if (Imm1 & ~0xFF) { + Error(Sx1, "immediate operand must a number in the range [0, 255]"); + return MatchOperand_ParseFail; + } + + // Eat the comma + Parser.Lex(); + + // Repeat for #rot + SMLoc Sx2, Ex2; + Sx2 = Parser.getTok().getLoc(); + + // Eat the optional hash (dollar) + if (Parser.getTok().is(AsmToken::Hash) || + Parser.getTok().is(AsmToken::Dollar)) + Parser.Lex(); + + const MCExpr *Imm2Exp; + if (getParser().parseExpression(Imm2Exp, Ex2)) { + Error(Sx2, "malformed expression"); + return MatchOperand_ParseFail; + } + + CE = dyn_cast(Imm2Exp); + + if (CE) { + Imm2 = CE->getValue(); + if (!(Imm2 & ~0x1E)) { + // We have a match! + Operands.push_back(ARMOperand::CreateModImm(Imm1, Imm2, S, Ex2)); + return MatchOperand_Success; + } + Error(Sx2, "immediate operand must an even number in the range [0, 30]"); + return MatchOperand_ParseFail; + } else { + Error(Sx2, "constant expression expected"); + return MatchOperand_ParseFail; + } +} + ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseBitfield(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); // The bitfield descriptor is really two operands, the LSB and the width. if (Parser.getTok().isNot(AsmToken::Hash) && @@ -4361,6 +4575,7 @@ ARMAsmParser::parsePostIdxReg(OperandVector &Operands) { // 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. + MCAsmParser &Parser = getParser(); AsmToken Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); bool haveEaten = false; @@ -4413,6 +4628,7 @@ ARMAsmParser::parseAM3Offset(OperandVector &Operands) { // 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. + MCAsmParser &Parser = getParser(); AsmToken Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); @@ -4550,6 +4766,7 @@ void ARMAsmParser::cvtThumbBranches(MCInst &Inst, /// 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::parseMemory(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); SMLoc S, E; assert(Parser.getTok().is(AsmToken::LBrac) && "Token is not a Left Bracket"); @@ -4741,6 +4958,7 @@ bool ARMAsmParser::parseMemory(OperandVector &Operands) { /// return true if it parses a shift otherwise it returns false. bool ARMAsmParser::parseMemRegOffsetShift(ARM_AM::ShiftOpc &St, unsigned &Amount) { + MCAsmParser &Parser = getParser(); SMLoc Loc = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) @@ -4801,6 +5019,7 @@ bool ARMAsmParser::parseMemRegOffsetShift(ARM_AM::ShiftOpc &St, /// parseFPImm - A floating point immediate expression operand. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseFPImm(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); // Anything that can accept a floating point constant as an operand // needs to go through here, as the regular parseExpression is // integer only. @@ -4881,6 +5100,7 @@ ARMAsmParser::parseFPImm(OperandVector &Operands) { /// Parse a arm instruction operand. For now this parses the operand regardless /// of the mnemonic. bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { + MCAsmParser &Parser = getParser(); SMLoc S, E; // Check if the current operand has a custom associated parser, if so, try to @@ -5013,6 +5233,7 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { // parsePrefix - Parse ARM 16-bit relocations expression prefix, i.e. // :lower16: and :upper16:. bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) { + MCAsmParser &Parser = getParser(); RefKind = ARMMCExpr::VK_ARM_None; // consume an optional '#' (GNU compatibility) @@ -5028,15 +5249,52 @@ bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) { return true; } + enum { + COFF = (1 << MCObjectFileInfo::IsCOFF), + ELF = (1 << MCObjectFileInfo::IsELF), + MACHO = (1 << MCObjectFileInfo::IsMachO) + }; + static const struct PrefixEntry { + const char *Spelling; + ARMMCExpr::VariantKind VariantKind; + uint8_t SupportedFormats; + } PrefixEntries[] = { + { "lower16", ARMMCExpr::VK_ARM_LO16, COFF | ELF | MACHO }, + { "upper16", ARMMCExpr::VK_ARM_HI16, COFF | ELF | MACHO }, + }; + StringRef IDVal = Parser.getTok().getIdentifier(); - if (IDVal == "lower16") { - RefKind = ARMMCExpr::VK_ARM_LO16; - } else if (IDVal == "upper16") { - RefKind = ARMMCExpr::VK_ARM_HI16; - } else { + + const auto &Prefix = + std::find_if(std::begin(PrefixEntries), std::end(PrefixEntries), + [&IDVal](const PrefixEntry &PE) { + return PE.Spelling == IDVal; + }); + if (Prefix == std::end(PrefixEntries)) { Error(Parser.getTok().getLoc(), "unexpected prefix in operand"); return true; } + + uint8_t CurrentFormat; + switch (getContext().getObjectFileInfo()->getObjectFileType()) { + case MCObjectFileInfo::IsMachO: + CurrentFormat = MACHO; + break; + case MCObjectFileInfo::IsELF: + CurrentFormat = ELF; + break; + case MCObjectFileInfo::IsCOFF: + CurrentFormat = COFF; + break; + } + + if (~Prefix->SupportedFormats & CurrentFormat) { + Error(Parser.getTok().getLoc(), + "cannot represent relocation in the current file format"); + return true; + } + + RefKind = Prefix->VariantKind; Parser.Lex(); if (getLexer().isNot(AsmToken::Colon)) { @@ -5044,6 +5302,7 @@ bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) { return true; } Parser.Lex(); // Eat the last ':' + return false; } @@ -5076,7 +5335,8 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic, Mnemonic == "fmuls" || Mnemonic == "vmaxnm" || Mnemonic == "vminnm" || Mnemonic == "vcvta" || Mnemonic == "vcvtn" || Mnemonic == "vcvtp" || Mnemonic == "vcvtm" || Mnemonic == "vrinta" || Mnemonic == "vrintn" || - Mnemonic == "vrintp" || Mnemonic == "vrintm" || Mnemonic.startswith("vsel")) + Mnemonic == "vrintp" || Mnemonic == "vrintm" || Mnemonic == "hvc" || + Mnemonic.startswith("vsel")) return Mnemonic; // First, split out any predication code. Ignore mnemonics we know aren't @@ -5181,7 +5441,7 @@ getMnemonicAcceptInfo(StringRef Mnemonic, StringRef FullInst, Mnemonic == "vmaxnm" || Mnemonic == "vminnm" || Mnemonic == "vcvta" || Mnemonic == "vcvtn" || Mnemonic == "vcvtp" || Mnemonic == "vcvtm" || Mnemonic == "vrinta" || Mnemonic == "vrintn" || Mnemonic == "vrintp" || - Mnemonic == "vrintm" || Mnemonic.startswith("aes") || + Mnemonic == "vrintm" || Mnemonic.startswith("aes") || Mnemonic == "hvc" || Mnemonic.startswith("sha1") || Mnemonic.startswith("sha256") || (FullInst.startswith("vmull") && FullInst.endswith(".p64"))) { // These mnemonics are never predicable @@ -5219,7 +5479,7 @@ bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic, // conditionally adding the cc_out in the first place because we need // to check the type of the parsed immediate operand. if (Mnemonic == "mov" && Operands.size() > 4 && !isThumb() && - !static_cast(*Operands[4]).isARMSOImm() && + !static_cast(*Operands[4]).isModImm() && static_cast(*Operands[4]).isImm0_65535Expr() && static_cast(*Operands[1]).getReg() == 0) return true; @@ -5388,6 +5648,7 @@ static bool RequiresVFPRegListValidation(StringRef Inst, /// Parse an arm instruction mnemonic followed by its operands. bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { + MCAsmParser &Parser = getParser(); // FIXME: Can this be done via tablegen in some fashion? bool RequireVFPRegisterListCheck; bool AcceptSinglePrecisionOnly; @@ -5507,6 +5768,8 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, Operands.push_back(ARMOperand::CreateImm( MCConstantExpr::Create(ProcessorIMod, getContext()), NameLoc, NameLoc)); + } else if (Mnemonic == "cps" && isMClass()) { + return Error(NameLoc, "instruction 'cps' requires effect for M-class"); } // Add the remaining tokens in the mnemonic. @@ -5638,6 +5901,48 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, } } + // If first 2 operands of a 3 operand instruction are the same + // then transform to 2 operand version of the same instruction + // e.g. 'adds r0, r0, #1' transforms to 'adds r0, #1' + // FIXME: We would really like to be able to tablegen'erate this. + if (isThumbOne() && Operands.size() == 6 && + (Mnemonic == "add" || Mnemonic == "sub" || Mnemonic == "and" || + Mnemonic == "eor" || Mnemonic == "lsl" || Mnemonic == "lsr" || + Mnemonic == "asr" || Mnemonic == "adc" || Mnemonic == "sbc" || + Mnemonic == "ror" || Mnemonic == "orr" || Mnemonic == "bic")) { + ARMOperand &Op3 = static_cast(*Operands[3]); + ARMOperand &Op4 = static_cast(*Operands[4]); + ARMOperand &Op5 = static_cast(*Operands[5]); + + // If both registers are the same then remove one of them from + // the operand list. + if (Op3.isReg() && Op4.isReg() && Op3.getReg() == Op4.getReg()) { + // If 3rd operand (variable Op5) is a register and the instruction is adds/sub + // then do not transform as the backend already handles this instruction + // correctly. + if (!Op5.isReg() || !((Mnemonic == "add" && CarrySetting) || Mnemonic == "sub")) { + Operands.erase(Operands.begin() + 3); + if (Mnemonic == "add" && !CarrySetting) { + // Special case for 'add' (not 'adds') instruction must + // remove the CCOut operand as well. + Operands.erase(Operands.begin() + 1); + } + } + } + } + + // If instruction is 'add' and first two register operands + // use SP register, then remove one of the SP registers from + // the instruction. + // FIXME: We would really like to be able to tablegen'erate this. + if (isThumbOne() && Operands.size() == 5 && Mnemonic == "add" && !CarrySetting) { + ARMOperand &Op2 = static_cast(*Operands[2]); + ARMOperand &Op3 = static_cast(*Operands[3]); + if (Op2.isReg() && Op3.isReg() && Op2.getReg() == ARM::SP && Op3.getReg() == ARM::SP) { + Operands.erase(Operands.begin() + 2); + } + } + // GNU Assembler extension (compatibility) if ((Mnemonic == "ldrd" || Mnemonic == "strd")) { ARMOperand &Op2 = static_cast(*Operands[2]); @@ -5715,6 +6020,50 @@ static bool instIsBreakpoint(const MCInst &Inst) { } +bool ARMAsmParser::validatetLDMRegList(MCInst Inst, + const OperandVector &Operands, + unsigned ListNo, bool IsARPop) { + const ARMOperand &Op = static_cast(*Operands[ListNo]); + bool HasWritebackToken = Op.isToken() && Op.getToken() == "!"; + + bool ListContainsSP = listContainsReg(Inst, ListNo, ARM::SP); + bool ListContainsLR = listContainsReg(Inst, ListNo, ARM::LR); + bool ListContainsPC = listContainsReg(Inst, ListNo, ARM::PC); + + if (!IsARPop && ListContainsSP) + return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(), + "SP may not be in the register list"); + else if (ListContainsPC && ListContainsLR) + return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(), + "PC and LR may not be in the register list simultaneously"); + else if (inITBlock() && !lastInITBlock() && ListContainsPC) + return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(), + "instruction must be outside of IT block or the last " + "instruction in an IT block"); + return false; +} + +bool ARMAsmParser::validatetSTMRegList(MCInst Inst, + const OperandVector &Operands, + unsigned ListNo) { + const ARMOperand &Op = static_cast(*Operands[ListNo]); + bool HasWritebackToken = Op.isToken() && Op.getToken() == "!"; + + bool ListContainsSP = listContainsReg(Inst, ListNo, ARM::SP); + bool ListContainsPC = listContainsReg(Inst, ListNo, ARM::PC); + + if (ListContainsSP && ListContainsPC) + return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(), + "SP and PC may not be in the register list"); + else if (ListContainsSP) + return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(), + "SP may not be in the register list"); + else if (ListContainsPC) + return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(), + "PC may not be in the register list"); + return false; +} + // FIXME: We would really like to be able to tablegen'erate this. bool ARMAsmParser::validateInstruction(MCInst &Inst, const OperandVector &Operands) { @@ -5899,6 +6248,8 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, "writeback operator '!' not allowed when base register " "in register list"); + if (validatetLDMRegList(Inst, Operands, 3)) + return true; break; } case ARM::LDMIA_UPD: @@ -5909,7 +6260,20 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, // UNPREDICTABLE on v7 upwards. Goodness knows what they did before. if (!hasV7Ops()) break; - // Fallthrough + if (listContainsReg(Inst, 3, Inst.getOperand(0).getReg())) + return Error(Operands.back()->getStartLoc(), + "writeback register not allowed in register list"); + break; + case ARM::t2LDMIA: + case ARM::t2LDMDB: + if (validatetLDMRegList(Inst, Operands, 3)) + return true; + break; + case ARM::t2STMIA: + case ARM::t2STMDB: + if (validatetSTMRegList(Inst, Operands, 3)) + return true; + break; case ARM::t2LDMIA_UPD: case ARM::t2LDMDB_UPD: case ARM::t2STMIA_UPD: @@ -5917,6 +6281,14 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, if (listContainsReg(Inst, 3, Inst.getOperand(0).getReg())) return Error(Operands.back()->getStartLoc(), "writeback register not allowed in register list"); + + if (Opcode == ARM::t2LDMIA_UPD || Opcode == ARM::t2LDMDB_UPD) { + if (validatetLDMRegList(Inst, Operands, 3)) + return true; + } else { + if (validatetSTMRegList(Inst, Operands, 3)) + return true; + } break; } case ARM::sysLDMIA_UPD: @@ -5961,6 +6333,8 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, !isThumbTwo()) return Error(Operands[2]->getStartLoc(), "registers must be in range r0-r7 or pc"); + if (validatetLDMRegList(Inst, Operands, 2, !isMClass())) + return true; break; } case ARM::tPUSH: { @@ -5969,6 +6343,8 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, !isThumbTwo()) return Error(Operands[2]->getStartLoc(), "registers must be in range r0-r7 or lr"); + if (validatetSTMRegList(Inst, Operands, 2)) + return true; break; } case ARM::tSTMIA_UPD: { @@ -5985,6 +6361,9 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, return Error(Operands[4]->getStartLoc(), "writeback operator '!' not allowed when base register " "in register list"); + + if (validatetSTMRegList(Inst, Operands, 4)) + return true; break; } case ARM::tADDrSP: { @@ -6305,7 +6684,8 @@ static unsigned getRealVLDOpcode(unsigned Opc, unsigned &Spacing) { } bool ARMAsmParser::processInstruction(MCInst &Inst, - const OperandVector &Operands) { + const OperandVector &Operands, + MCStreamer &Out) { switch (Inst.getOpcode()) { // Alias for alternate form of 'ldr{,b}t Rt, [Rn], #imm' instruction. case ARM::LDRT_POST: @@ -6346,12 +6726,35 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, // Alias for alternate form of 'ADR Rd, #imm' instruction. case ARM::ADDri: { if (Inst.getOperand(1).getReg() != ARM::PC || - Inst.getOperand(5).getReg() != 0) + Inst.getOperand(5).getReg() != 0 || + !(Inst.getOperand(2).isExpr() || Inst.getOperand(2).isImm())) return false; MCInst TmpInst; TmpInst.setOpcode(ARM::ADR); TmpInst.addOperand(Inst.getOperand(0)); - TmpInst.addOperand(Inst.getOperand(2)); + if (Inst.getOperand(2).isImm()) { + // Immediate (mod_imm) will be in its encoded form, we must unencode it + // before passing it to the ADR instruction. + unsigned Enc = Inst.getOperand(2).getImm(); + TmpInst.addOperand(MCOperand::CreateImm( + ARM_AM::rotr32(Enc & 0xFF, (Enc & 0xF00) >> 7))); + } else { + // Turn PC-relative expression into absolute expression. + // Reading PC provides the start of the current instruction + 8 and + // the transform to adr is biased by that. + MCSymbol *Dot = getContext().CreateTempSymbol(); + Out.EmitLabel(Dot); + const MCExpr *OpExpr = Inst.getOperand(2).getExpr(); + const MCExpr *InstPC = MCSymbolRefExpr::Create(Dot, + MCSymbolRefExpr::VK_None, + getContext()); + const MCExpr *Const8 = MCConstantExpr::Create(8, getContext()); + const MCExpr *ReadPC = MCBinaryExpr::CreateAdd(InstPC, Const8, + getContext()); + const MCExpr *FixupAddr = MCBinaryExpr::CreateAdd(ReadPC, OpExpr, + getContext()); + TmpInst.addOperand(MCOperand::CreateExpr(FixupAddr)); + } TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(4)); Inst = TmpInst; @@ -8144,7 +8547,7 @@ unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) { } // Some high-register supporting Thumb1 encodings only allow both registers // to be from r0-r7 when in Thumb2. - else if (Opc == ARM::tADDhirr && isThumbOne() && + else if (Opc == ARM::tADDhirr && isThumbOne() && !hasV6MOps() && isARMLowRegister(Inst.getOperand(1).getReg()) && isARMLowRegister(Inst.getOperand(2).getReg())) return Match_RequiresThumb2; @@ -8173,7 +8576,6 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); switch (MatchResult) { - default: break; case Match_Success: // Context sensitive operand constraints aren't handled by the matcher, // so check them here. @@ -8191,7 +8593,7 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, // encoding is selected. Loop on it while changes happen so the // individual transformations can chain off each other. E.g., // tPOP(r8)->t2LDMIA_UPD(sp,r8)->t2STR_POST(sp,r8) - while (processInstruction(Inst, Operands)) + while (processInstruction(Inst, Operands, Out)) ; // Only after the instruction is fully processed, we can validate it @@ -8308,6 +8710,7 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { const MCObjectFileInfo::Environment Format = getContext().getObjectFileInfo()->getObjectFileType(); bool IsMachO = Format == MCObjectFileInfo::IsMachO; + bool IsCOFF = Format == MCObjectFileInfo::IsCOFF; StringRef IDVal = DirectiveID.getIdentifier(); if (IDVal == ".word") @@ -8359,7 +8762,7 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { else if (IDVal == ".thumb_set") return parseDirectiveThumbSet(DirectiveID.getLoc()); - if (!IsMachO) { + if (!IsMachO && !IsCOFF) { if (IDVal == ".arch") return parseDirectiveArch(DirectiveID.getLoc()); else if (IDVal == ".cpu") @@ -8390,6 +8793,7 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { /// ::= .short expression [, expression]* /// ::= .word expression [, expression]* bool ARMAsmParser::parseLiteralValues(unsigned Size, SMLoc L) { + MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::EndOfStatement)) { for (;;) { const MCExpr *Value; @@ -8419,6 +8823,7 @@ bool ARMAsmParser::parseLiteralValues(unsigned Size, SMLoc L) { /// parseDirectiveThumb /// ::= .thumb bool ARMAsmParser::parseDirectiveThumb(SMLoc L) { + MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::EndOfStatement)) { Error(L, "unexpected token in directive"); return false; @@ -8440,6 +8845,7 @@ bool ARMAsmParser::parseDirectiveThumb(SMLoc L) { /// parseDirectiveARM /// ::= .arm bool ARMAsmParser::parseDirectiveARM(SMLoc L) { + MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::EndOfStatement)) { Error(L, "unexpected token in directive"); return false; @@ -8468,12 +8874,13 @@ void ARMAsmParser::onLabelParsed(MCSymbol *Symbol) { /// parseDirectiveThumbFunc /// ::= .thumbfunc symbol_name bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) { - const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo(); - bool isMachO = MAI->hasSubsectionsViaSymbols(); + MCAsmParser &Parser = getParser(); + const auto Format = getContext().getObjectFileInfo()->getObjectFileType(); + bool IsMachO = Format == MCObjectFileInfo::IsMachO; // Darwin asm has (optionally) function name after .thumb_func direction // ELF doesn't - if (isMachO) { + if (IsMachO) { const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::EndOfStatement)) { if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) { @@ -8490,7 +8897,8 @@ bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) { } if (getLexer().isNot(AsmToken::EndOfStatement)) { - Error(L, "unexpected token in directive"); + Error(Parser.getTok().getLoc(), "unexpected token in directive"); + Parser.eatToEndOfStatement(); return false; } @@ -8501,6 +8909,7 @@ bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) { /// parseDirectiveSyntax /// ::= .syntax unified | divided bool ARMAsmParser::parseDirectiveSyntax(SMLoc L) { + MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) { Error(L, "unexpected token in .syntax directive"); @@ -8532,6 +8941,7 @@ bool ARMAsmParser::parseDirectiveSyntax(SMLoc L) { /// parseDirectiveCode /// ::= .code 16 | 32 bool ARMAsmParser::parseDirectiveCode(SMLoc L) { + MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Integer)) { Error(L, "unexpected token in .code directive"); @@ -8576,6 +8986,7 @@ bool ARMAsmParser::parseDirectiveCode(SMLoc L) { /// parseDirectiveReq /// ::= name .req registername bool ARMAsmParser::parseDirectiveReq(StringRef Name, SMLoc L) { + MCAsmParser &Parser = getParser(); Parser.Lex(); // Eat the '.req' token. unsigned Reg; SMLoc SRegLoc, ERegLoc; @@ -8594,7 +9005,7 @@ bool ARMAsmParser::parseDirectiveReq(StringRef Name, SMLoc L) { Parser.Lex(); // Consume the EndOfStatement - if (RegisterReqs.GetOrCreateValue(Name, Reg).getValue() != Reg) { + if (RegisterReqs.insert(std::make_pair(Name, Reg)).first->second != Reg) { Error(SRegLoc, "redefinition of '" + Name + "' does not match original."); return false; } @@ -8605,6 +9016,7 @@ bool ARMAsmParser::parseDirectiveReq(StringRef Name, SMLoc L) { /// parseDirectiveUneq /// ::= .unreq registername bool ARMAsmParser::parseDirectiveUnreq(SMLoc L) { + MCAsmParser &Parser = getParser(); if (Parser.getTok().isNot(AsmToken::Identifier)) { Parser.eatToEndOfStatement(); Error(L, "unexpected input in .unreq directive."); @@ -8641,6 +9053,7 @@ bool ARMAsmParser::parseDirectiveArch(SMLoc L) { /// ::= .eabi_attribute int, int [, "str"] /// ::= .eabi_attribute Tag_name, int [, "str"] bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) { + MCAsmParser &Parser = getParser(); int64_t Tag; SMLoc TagLoc; TagLoc = Parser.getTok().getLoc(); @@ -8718,8 +9131,13 @@ bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) { if (Tag == ARMBuildAttrs::compatibility) { if (Parser.getTok().isNot(AsmToken::Comma)) IsStringValue = false; - else - Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::Comma)) { + Error(Parser.getTok().getLoc(), "comma expected"); + Parser.eatToEndOfStatement(); + return false; + } else { + Parser.Lex(); + } } if (IsStringValue) { @@ -8748,36 +9166,78 @@ bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) { bool ARMAsmParser::parseDirectiveCPU(SMLoc L) { StringRef CPU = getParser().parseStringToEndOfStatement().trim(); getTargetStreamer().emitTextAttribute(ARMBuildAttrs::CPU_name, CPU); + + if (!STI.isCPUStringValid(CPU)) { + Error(L, "Unknown CPU name"); + return false; + } + + // FIXME: This switches the CPU features globally, therefore it might + // happen that code you would not expect to assemble will. For details + // see: http://llvm.org/bugs/show_bug.cgi?id=20757 + STI.InitMCProcessorInfo(CPU, ""); + STI.InitCPUSchedModel(CPU); + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + return false; } // FIXME: This is duplicated in getARMFPUFeatures() in // tools/clang/lib/Driver/Tools.cpp static const struct { - const unsigned Fpu; + const unsigned ID; const uint64_t Enabled; const uint64_t Disabled; -} Fpus[] = { - {ARM::VFP, ARM::FeatureVFP2, ARM::FeatureNEON}, - {ARM::VFPV2, ARM::FeatureVFP2, ARM::FeatureNEON}, - {ARM::VFPV3, ARM::FeatureVFP3, ARM::FeatureNEON}, - {ARM::VFPV3_D16, ARM::FeatureVFP3 | ARM::FeatureD16, ARM::FeatureNEON}, - {ARM::VFPV4, ARM::FeatureVFP4, ARM::FeatureNEON}, - {ARM::VFPV4_D16, ARM::FeatureVFP4 | ARM::FeatureD16, ARM::FeatureNEON}, - {ARM::FP_ARMV8, ARM::FeatureFPARMv8, - ARM::FeatureNEON | ARM::FeatureCrypto}, - {ARM::NEON, ARM::FeatureNEON, 0}, - {ARM::NEON_VFPV4, ARM::FeatureVFP4 | ARM::FeatureNEON, 0}, - {ARM::NEON_FP_ARMV8, ARM::FeatureFPARMv8 | ARM::FeatureNEON, - ARM::FeatureCrypto}, - {ARM::CRYPTO_NEON_FP_ARMV8, - ARM::FeatureFPARMv8 | ARM::FeatureNEON | ARM::FeatureCrypto, 0}, - {ARM::SOFTVFP, 0, 0}, +} FPUs[] = { + {/* ID */ ARM::VFP, + /* Enabled */ ARM::FeatureVFP2, + /* Disabled */ ARM::FeatureNEON}, + {/* ID */ ARM::VFPV2, + /* Enabled */ ARM::FeatureVFP2, + /* Disabled */ ARM::FeatureNEON}, + {/* ID */ ARM::VFPV3, + /* Enabled */ ARM::FeatureVFP2 | ARM::FeatureVFP3, + /* Disabled */ ARM::FeatureNEON | ARM::FeatureD16}, + {/* ID */ ARM::VFPV3_D16, + /* Enable */ ARM::FeatureVFP2 | ARM::FeatureVFP3 | ARM::FeatureD16, + /* Disabled */ ARM::FeatureNEON}, + {/* ID */ ARM::VFPV4, + /* Enabled */ ARM::FeatureVFP2 | ARM::FeatureVFP3 | ARM::FeatureVFP4, + /* Disabled */ ARM::FeatureNEON | ARM::FeatureD16}, + {/* ID */ ARM::VFPV4_D16, + /* Enabled */ ARM::FeatureVFP2 | ARM::FeatureVFP3 | ARM::FeatureVFP4 | + ARM::FeatureD16, + /* Disabled */ ARM::FeatureNEON}, + {/* ID */ ARM::FPV5_D16, + /* Enabled */ ARM::FeatureVFP2 | ARM::FeatureVFP3 | ARM::FeatureVFP4 | + ARM::FeatureFPARMv8 | ARM::FeatureD16, + /* Disabled */ ARM::FeatureNEON | ARM::FeatureCrypto}, + {/* ID */ ARM::FP_ARMV8, + /* Enabled */ ARM::FeatureVFP2 | ARM::FeatureVFP3 | ARM::FeatureVFP4 | + ARM::FeatureFPARMv8, + /* Disabled */ ARM::FeatureNEON | ARM::FeatureCrypto | ARM::FeatureD16}, + {/* ID */ ARM::NEON, + /* Enabled */ ARM::FeatureVFP2 | ARM::FeatureVFP3 | ARM::FeatureNEON, + /* Disabled */ ARM::FeatureD16}, + {/* ID */ ARM::NEON_VFPV4, + /* Enabled */ ARM::FeatureVFP2 | ARM::FeatureVFP3 | ARM::FeatureVFP4 | + ARM::FeatureNEON, + /* Disabled */ ARM::FeatureD16}, + {/* ID */ ARM::NEON_FP_ARMV8, + /* Enabled */ ARM::FeatureVFP2 | ARM::FeatureVFP3 | ARM::FeatureVFP4 | + ARM::FeatureFPARMv8 | ARM::FeatureNEON, + /* Disabled */ ARM::FeatureCrypto | ARM::FeatureD16}, + {/* ID */ ARM::CRYPTO_NEON_FP_ARMV8, + /* Enabled */ ARM::FeatureVFP2 | ARM::FeatureVFP3 | ARM::FeatureVFP4 | + ARM::FeatureFPARMv8 | ARM::FeatureNEON | ARM::FeatureCrypto, + /* Disabled */ ARM::FeatureD16}, + {ARM::SOFTVFP, 0, 0}, }; /// parseDirectiveFPU /// ::= .fpu str bool ARMAsmParser::parseDirectiveFPU(SMLoc L) { + SMLoc FPUNameLoc = getTok().getLoc(); StringRef FPU = getParser().parseStringToEndOfStatement().trim(); unsigned ID = StringSwitch(FPU) @@ -8786,18 +9246,18 @@ bool ARMAsmParser::parseDirectiveFPU(SMLoc L) { .Default(ARM::INVALID_FPU); if (ID == ARM::INVALID_FPU) { - Error(L, "Unknown FPU name"); + Error(FPUNameLoc, "Unknown FPU name"); return false; } - for (const auto &Fpu : Fpus) { - if (Fpu.Fpu != ID) + for (const auto &Entry : FPUs) { + if (Entry.ID != ID) continue; // Need to toggle features that should be on but are off and that // should off but are on. - uint64_t Toggle = (Fpu.Enabled & ~STI.getFeatureBits()) | - (Fpu.Disabled & STI.getFeatureBits()); + uint64_t Toggle = (Entry.Enabled & ~STI.getFeatureBits()) | + (Entry.Disabled & STI.getFeatureBits()); setAvailableFeatures(ComputeAvailableFeatures(STI.ToggleFeature(Toggle))); break; } @@ -8868,6 +9328,7 @@ bool ARMAsmParser::parseDirectiveCantUnwind(SMLoc L) { /// parseDirectivePersonality /// ::= .personality name bool ARMAsmParser::parseDirectivePersonality(SMLoc L) { + MCAsmParser &Parser = getParser(); bool HasExistingPersonality = UC.hasPersonality(); UC.recordPersonality(L); @@ -8931,6 +9392,7 @@ bool ARMAsmParser::parseDirectiveHandlerData(SMLoc L) { /// parseDirectiveSetFP /// ::= .setfp fpreg, spreg [, offset] bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) { + MCAsmParser &Parser = getParser(); // Check the ordering of unwind directives if (!UC.hasFnStart()) { Error(L, ".fnstart must precede .setfp directive"); @@ -9008,6 +9470,7 @@ bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) { /// parseDirective /// ::= .pad offset bool ARMAsmParser::parseDirectivePad(SMLoc L) { + MCAsmParser &Parser = getParser(); // Check the ordering of unwind directives if (!UC.hasFnStart()) { Error(L, ".fnstart must precede .pad directive"); @@ -9082,6 +9545,7 @@ bool ARMAsmParser::parseDirectiveRegSave(SMLoc L, bool IsVector) { /// ::= .inst.n opcode [, ...] /// ::= .inst.w opcode [, ...] bool ARMAsmParser::parseDirectiveInst(SMLoc Loc, char Suffix) { + MCAsmParser &Parser = getParser(); int Width; if (isThumb()) { @@ -9178,7 +9642,7 @@ bool ARMAsmParser::parseDirectiveEven(SMLoc L) { } if (!Section) { - getStreamer().InitSections(); + getStreamer().InitSections(false); Section = getStreamer().getCurrentSection().first; } @@ -9194,6 +9658,7 @@ bool ARMAsmParser::parseDirectiveEven(SMLoc L) { /// parseDirectivePersonalityIndex /// ::= .personalityindex index bool ARMAsmParser::parseDirectivePersonalityIndex(SMLoc L) { + MCAsmParser &Parser = getParser(); bool HasExistingPersonality = UC.hasPersonality(); UC.recordPersonalityIndex(L); @@ -9249,6 +9714,7 @@ bool ARMAsmParser::parseDirectivePersonalityIndex(SMLoc L) { /// parseDirectiveUnwindRaw /// ::= .unwind_raw offset, opcode [, opcode...] bool ARMAsmParser::parseDirectiveUnwindRaw(SMLoc L) { + MCAsmParser &Parser = getParser(); if (!UC.hasFnStart()) { Parser.eatToEndOfStatement(); Error(L, ".fnstart must precede .unwind_raw directives"); @@ -9330,6 +9796,8 @@ bool ARMAsmParser::parseDirectiveUnwindRaw(SMLoc L) { /// parseDirectiveTLSDescSeq /// ::= .tlsdescseq tls-variable bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) { + MCAsmParser &Parser = getParser(); + if (getLexer().isNot(AsmToken::Identifier)) { TokError("expected variable after '.tlsdescseq' directive"); Parser.eatToEndOfStatement(); @@ -9354,6 +9822,7 @@ bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) { /// parseDirectiveMovSP /// ::= .movsp reg [, #offset] bool ARMAsmParser::parseDirectiveMovSP(SMLoc L) { + MCAsmParser &Parser = getParser(); if (!UC.hasFnStart()) { Parser.eatToEndOfStatement(); Error(L, ".fnstart must precede .movsp directives"); @@ -9417,6 +9886,7 @@ bool ARMAsmParser::parseDirectiveMovSP(SMLoc L) { /// parseDirectiveObjectArch /// ::= .object_arch name bool ARMAsmParser::parseDirectiveObjectArch(SMLoc L) { + MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::Identifier)) { Error(getLexer().getLoc(), "unexpected token"); Parser.eatToEndOfStatement(); @@ -9473,6 +9943,8 @@ bool ARMAsmParser::parseDirectiveAlign(SMLoc L) { /// parseDirectiveThumbSet /// ::= .thumb_set name, value bool ARMAsmParser::parseDirectiveThumbSet(SMLoc L) { + MCAsmParser &Parser = getParser(); + StringRef Name; if (Parser.parseIdentifier(Name)) { TokError("expected identifier after '.thumb_set'"); @@ -9551,6 +10023,8 @@ static const struct { /// parseDirectiveArchExtension /// ::= .arch_extension [no]feature bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) { + MCAsmParser &Parser = getParser(); + if (getLexer().isNot(AsmToken::Identifier)) { Error(getLexer().getLoc(), "unexpected token"); Parser.eatToEndOfStatement(); @@ -9610,7 +10084,7 @@ unsigned ARMAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, if (CE->getValue() == 0) return Match_Success; break; - case MCK_ARMSOImm: + case MCK_ModImm: if (Op.isImm()) { const MCExpr *SOExpr = Op.getImm(); int64_t Value;