diff options
author | Stephen Hines <srhines@google.com> | 2014-04-23 16:57:46 -0700 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-04-24 15:53:16 -0700 |
commit | 36b56886974eae4f9c5ebc96befd3e7bfe5de338 (patch) | |
tree | e6cfb69fbbd937f450eeb83bfb83b9da3b01275a /lib/Target/ARM/AsmParser | |
parent | 69a8640022b04415ae9fac62f8ab090601d8f889 (diff) | |
download | external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.zip external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.gz external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.bz2 |
Update to LLVM 3.5a.
Change-Id: Ifadecab779f128e62e430c2b4f6ddd84953ed617
Diffstat (limited to 'lib/Target/ARM/AsmParser')
-rw-r--r-- | lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 1490 | ||||
-rw-r--r-- | lib/Target/ARM/AsmParser/Android.mk | 2 | ||||
-rw-r--r-- | lib/Target/ARM/AsmParser/CMakeLists.txt | 4 |
3 files changed, 1284 insertions, 212 deletions
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index e3f9e0d..9c57a24 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -7,33 +7,43 @@ // //===----------------------------------------------------------------------===// -#include "ARMBuildAttrs.h" #include "ARMFPUName.h" #include "ARMFeatures.h" -#include "llvm/MC/MCTargetAsmParser.h" #include "MCTargetDesc/ARMAddressingModes.h" +#include "MCTargetDesc/ARMArchName.h" #include "MCTargetDesc/ARMBaseInfo.h" #include "MCTargetDesc/ARMMCExpr.h" -#include "llvm/ADT/BitVector.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCELF.h" #include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCELFSymbolFlags.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/ARMEHABI.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SourceMgr.h" @@ -48,31 +58,90 @@ class ARMOperand; enum VectorLaneTy { NoLanes, AllLanes, IndexedLane }; +class UnwindContext { + MCAsmParser &Parser; + + typedef SmallVector<SMLoc, 4> Locs; + + Locs FnStartLocs; + Locs CantUnwindLocs; + Locs PersonalityLocs; + Locs PersonalityIndexLocs; + Locs HandlerDataLocs; + int FPReg; + +public: + UnwindContext(MCAsmParser &P) : Parser(P), FPReg(ARM::SP) {} + + bool hasFnStart() const { return !FnStartLocs.empty(); } + bool cantUnwind() const { return !CantUnwindLocs.empty(); } + bool hasHandlerData() const { return !HandlerDataLocs.empty(); } + bool hasPersonality() const { + return !(PersonalityLocs.empty() && PersonalityIndexLocs.empty()); + } + + void recordFnStart(SMLoc L) { FnStartLocs.push_back(L); } + void recordCantUnwind(SMLoc L) { CantUnwindLocs.push_back(L); } + void recordPersonality(SMLoc L) { PersonalityLocs.push_back(L); } + void recordHandlerData(SMLoc L) { HandlerDataLocs.push_back(L); } + void recordPersonalityIndex(SMLoc L) { PersonalityIndexLocs.push_back(L); } + + void saveFPReg(int Reg) { FPReg = Reg; } + int getFPReg() const { return FPReg; } + + void emitFnStartLocNotes() const { + for (Locs::const_iterator FI = FnStartLocs.begin(), FE = FnStartLocs.end(); + FI != FE; ++FI) + Parser.Note(*FI, ".fnstart was specified here"); + } + void emitCantUnwindLocNotes() const { + for (Locs::const_iterator UI = CantUnwindLocs.begin(), + UE = CantUnwindLocs.end(); UI != UE; ++UI) + Parser.Note(*UI, ".cantunwind was specified here"); + } + void emitHandlerDataLocNotes() const { + for (Locs::const_iterator HI = HandlerDataLocs.begin(), + HE = HandlerDataLocs.end(); HI != HE; ++HI) + Parser.Note(*HI, ".handlerdata was specified here"); + } + void emitPersonalityLocNotes() const { + for (Locs::const_iterator PI = PersonalityLocs.begin(), + PE = PersonalityLocs.end(), + PII = PersonalityIndexLocs.begin(), + PIE = PersonalityIndexLocs.end(); + PI != PE || PII != PIE;) { + if (PI != PE && (PII == PIE || PI->getPointer() < PII->getPointer())) + Parser.Note(*PI++, ".personality was specified here"); + else if (PII != PIE && (PI == PE || PII->getPointer() < PI->getPointer())) + Parser.Note(*PII++, ".personalityindex was specified here"); + else + llvm_unreachable(".personality and .personalityindex cannot be " + "at the same location"); + } + } + + void reset() { + FnStartLocs = Locs(); + CantUnwindLocs = Locs(); + PersonalityLocs = Locs(); + HandlerDataLocs = Locs(); + PersonalityIndexLocs = Locs(); + FPReg = ARM::SP; + } +}; + class ARMAsmParser : public MCTargetAsmParser { MCSubtargetInfo &STI; MCAsmParser &Parser; const MCInstrInfo &MII; const MCRegisterInfo *MRI; + UnwindContext UC; ARMTargetStreamer &getTargetStreamer() { - MCTargetStreamer &TS = getParser().getStreamer().getTargetStreamer(); + MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); return static_cast<ARMTargetStreamer &>(TS); } - // Unwind directives state - SMLoc FnStartLoc; - SMLoc CantUnwindLoc; - SMLoc PersonalityLoc; - SMLoc HandlerDataLoc; - int FPReg; - void resetUnwindDirectiveParserState() { - FnStartLoc = SMLoc(); - CantUnwindLoc = SMLoc(); - PersonalityLoc = SMLoc(); - HandlerDataLoc = SMLoc(); - FPReg = -1; - } - // Map of register aliases registers via the .req directive. StringMap<unsigned> RegisterReqs; @@ -111,6 +180,9 @@ class ARMAsmParser : public MCTargetAsmParser { MCAsmParser &getParser() const { return Parser; } MCAsmLexer &getLexer() const { return Parser.getLexer(); } + void Note(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges = None) { + return Parser.Note(L, Msg, Ranges); + } bool Warning(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges = None) { return Parser.Warning(L, Msg, Ranges); @@ -129,7 +201,7 @@ class ARMAsmParser : public MCTargetAsmParser { bool parsePrefix(ARMMCExpr::VariantKind &RefKind); bool parseMemRegOffsetShift(ARM_AM::ShiftOpc &ShiftType, unsigned &ShiftAmount); - bool parseDirectiveWord(unsigned Size, SMLoc L); + bool parseLiteralValues(unsigned Size, SMLoc L); bool parseDirectiveThumb(SMLoc L); bool parseDirectiveARM(SMLoc L); bool parseDirectiveThumbFunc(SMLoc L); @@ -149,6 +221,17 @@ class ARMAsmParser : public MCTargetAsmParser { bool parseDirectiveSetFP(SMLoc L); bool parseDirectivePad(SMLoc L); bool parseDirectiveRegSave(SMLoc L, bool IsVector); + bool parseDirectiveInst(SMLoc L, char Suffix = '\0'); + bool parseDirectiveLtorg(SMLoc L); + bool parseDirectiveEven(SMLoc L); + bool parseDirectivePersonalityIndex(SMLoc L); + bool parseDirectiveUnwindRaw(SMLoc L); + bool parseDirectiveTLSDescSeq(SMLoc L); + bool parseDirectiveMovSP(SMLoc L); + bool parseDirectiveObjectArch(SMLoc L); + bool parseDirectiveArchExtension(SMLoc L); + bool parseDirectiveAlign(SMLoc L); + bool parseDirectiveThumbSet(SMLoc L); StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, bool &CarrySetting, unsigned &ProcessorIMod, @@ -241,7 +324,7 @@ class ARMAsmParser : public MCTargetAsmParser { const SmallVectorImpl<MCParsedAsmOperand*> &); void cvtThumbBranches(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &); - + bool validateInstruction(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &Ops); bool processInstruction(MCInst &Inst, @@ -263,7 +346,7 @@ public: ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser, const MCInstrInfo &MII) - : MCTargetAsmParser(), STI(_STI), Parser(_Parser), MII(MII), FPReg(-1) { + : MCTargetAsmParser(), STI(_STI), Parser(_Parser), MII(MII), UC(_Parser) { MCAsmParserExtension::Initialize(_Parser); // Cache the MCRegisterInfo. @@ -279,21 +362,22 @@ public: } // Implementation of the MCTargetAsmParser interface: - bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); - bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, - SMLoc NameLoc, - SmallVectorImpl<MCParsedAsmOperand*> &Operands); - bool ParseDirective(AsmToken DirectiveID); + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + bool + ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands) override; + bool ParseDirective(AsmToken DirectiveID) override; - unsigned validateTargetOperandClass(MCParsedAsmOperand *Op, unsigned Kind); - unsigned checkTargetMatchPredicate(MCInst &Inst); + unsigned validateTargetOperandClass(MCParsedAsmOperand *Op, + unsigned Kind) override; + unsigned checkTargetMatchPredicate(MCInst &Inst) override; bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, SmallVectorImpl<MCParsedAsmOperand*> &Operands, MCStreamer &Out, unsigned &ErrorInfo, - bool MatchingInlineAsm); - void onLabelParsed(MCSymbol *Symbol); - + bool MatchingInlineAsm) override; + void onLabelParsed(MCSymbol *Symbol) override; }; } // end anonymous namespace @@ -542,9 +626,9 @@ public: } /// getStartLoc - Get the location of the first token of this operand. - SMLoc getStartLoc() const { return StartLoc; } + SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Get the location of the last token of this operand. - SMLoc getEndLoc() const { return EndLoc; } + SMLoc getEndLoc() const override { return EndLoc; } /// getLocRange - Get the range between the first and last token of this /// operand. SMRange getLocRange() const { return SMRange(StartLoc, EndLoc); } @@ -564,7 +648,7 @@ public: return StringRef(Tok.Data, Tok.Length); } - unsigned getReg() const { + unsigned getReg() const override { assert((Kind == k_Register || Kind == k_CCOut) && "Invalid access!"); return Reg.RegNum; } @@ -612,7 +696,7 @@ public: bool isCCOut() const { return Kind == k_CCOut; } bool isITMask() const { return Kind == k_ITCondMask; } bool isITCondCode() const { return Kind == k_CondCode; } - bool isImm() const { return Kind == k_Immediate; } + bool isImm() const override { return Kind == k_Immediate; } // checks whether this operand is an unsigned offset which fits is a field // of specified width and scaled by a specific number of bits template<unsigned width, unsigned scale> @@ -988,14 +1072,14 @@ public: int64_t Value = CE->getValue(); return Value == 1 || Value == 0; } - bool isReg() const { return Kind == k_Register; } + bool isReg() const override { return Kind == k_Register; } bool isRegList() const { return Kind == k_RegisterList; } bool isDPRRegList() const { return Kind == k_DPRRegisterList; } bool isSPRRegList() const { return Kind == k_SPRRegisterList; } - bool isToken() const { return Kind == k_Token; } + bool isToken() const override { return Kind == k_Token; } bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; } bool isInstSyncBarrierOpt() const { return Kind == k_InstSyncBarrierOpt; } - bool isMem() const { return Kind == k_Memory; } + bool isMem() const override { return Kind == k_Memory; } bool isShifterImm() const { return Kind == k_ShifterImmediate; } bool isRegShiftedReg() const { return Kind == k_ShiftedRegister; } bool isRegShiftedImm() const { return Kind == k_ShiftedImmediate; } @@ -1282,6 +1366,7 @@ public: } bool isVecListDPairSpaced() const { + if (Kind != k_VectorList) return false; if (isSingleSpacedVectorList()) return false; return (ARMMCRegisterClasses[ARM::DPairSpcRegClassID] .contains(VectorList.RegNum)); @@ -1580,7 +1665,7 @@ public: void addRegShiftedRegOperands(MCInst &Inst, unsigned N) const { assert(N == 3 && "Invalid number of operands!"); assert(isRegShiftedReg() && - "addRegShiftedRegOperands() on non RegShiftedReg!"); + "addRegShiftedRegOperands() on non-RegShiftedReg!"); Inst.addOperand(MCOperand::CreateReg(RegShiftedReg.SrcReg)); Inst.addOperand(MCOperand::CreateReg(RegShiftedReg.ShiftReg)); Inst.addOperand(MCOperand::CreateImm( @@ -1590,7 +1675,7 @@ public: void addRegShiftedImmOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); assert(isRegShiftedImm() && - "addRegShiftedImmOperands() on non RegShiftedImm!"); + "addRegShiftedImmOperands() on non-RegShiftedImm!"); Inst.addOperand(MCOperand::CreateReg(RegShiftedImm.SrcReg)); // Shift of #32 is encoded as 0 where permitted unsigned Imm = (RegShiftedImm.ShiftImm == 32 ? 0 : RegShiftedImm.ShiftImm); @@ -2230,7 +2315,7 @@ public: Inst.addOperand(MCOperand::CreateImm(Imm | 0x1e00)); } - virtual void print(raw_ostream &OS) const; + void print(raw_ostream &OS) const override; static ARMOperand *CreateITMask(unsigned Mask, SMLoc S) { ARMOperand *Op = new ARMOperand(k_ITCondMask); @@ -2700,7 +2785,8 @@ int ARMAsmParser::tryParseShiftRegister( SmallVectorImpl<MCParsedAsmOperand*> &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 -1; std::string lowerCase = Tok.getString().lower(); ARM_AM::ShiftOpc ShiftTy = StringSwitch<ARM_AM::ShiftOpc>(lowerCase) @@ -3518,7 +3604,7 @@ parseMemBarrierOptOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { Error(Loc, "illegal expression"); return MatchOperand_ParseFail; } - + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(MemBarrierID); if (!CE) { Error(Loc, "constant expression expected"); @@ -4117,7 +4203,7 @@ parseAM3Offset(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { isAdd = false; haveEaten = true; } - + Tok = Parser.getTok(); int Reg = tryParseRegister(); if (Reg == -1) { @@ -4190,7 +4276,7 @@ cvtThumbBranches(MCInst &Inst, break; } } - + // now decide on encoding size based on branch target range switch(Inst.getOpcode()) { // classify tB as either t2B or t1B based on range of immediate operand @@ -4491,8 +4577,12 @@ parseFPImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { // for these: // vmov.i{8|16|32|64} <dreg|qreg>, #imm ARMOperand *TyOp = static_cast<ARMOperand*>(Operands[2]); - if (!TyOp->isToken() || (TyOp->getToken() != ".f32" && - TyOp->getToken() != ".f64")) + bool isVmovf = TyOp->isToken() && (TyOp->getToken() == ".f32" || + TyOp->getToken() == ".f64"); + ARMOperand *Mnemonic = static_cast<ARMOperand*>(Operands[0]); + bool isFconst = Mnemonic->isToken() && (Mnemonic->getToken() == "fconstd" || + Mnemonic->getToken() == "fconsts"); + if (!(isVmovf || isFconst)) return MatchOperand_NoMatch; Parser.Lex(); // Eat '#' or '$'. @@ -4505,7 +4595,7 @@ parseFPImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { } const AsmToken &Tok = Parser.getTok(); SMLoc Loc = Tok.getLoc(); - if (Tok.is(AsmToken::Real)) { + if (Tok.is(AsmToken::Real) && isVmovf) { APFloat RealVal(APFloat::IEEEsingle, Tok.getString()); uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); // If we had a '-' in front, toggle the sign bit. @@ -4518,15 +4608,16 @@ parseFPImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { } // Also handle plain integers. Instructions which allow floating point // immediates also allow a raw encoded 8-bit value. - if (Tok.is(AsmToken::Integer)) { + if (Tok.is(AsmToken::Integer) && isFconst) { int64_t Val = Tok.getIntVal(); Parser.Lex(); // Eat the token. if (Val > 255 || Val < 0) { Error(Loc, "encoded floating point value out of range"); return MatchOperand_ParseFail; } - double RealVal = ARM_AM::getFPImmFloat(Val); - Val = APFloat(APFloat::IEEEdouble, RealVal).bitcastToAPInt().getZExtValue(); + float RealVal = ARM_AM::getFPImmFloat(Val); + Val = APFloat(RealVal).bitcastToAPInt().getZExtValue(); + Operands.push_back(ARMOperand::CreateImm( MCConstantExpr::Create(Val, getContext()), S, Parser.getTok().getLoc())); @@ -4623,7 +4714,7 @@ bool ARMAsmParser::parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, Operands.push_back(ARMOperand::CreateImm(ImmVal, S, E)); // There can be a trailing '!' on operands that we want as a separate - // '!' Token operand. Handle that here. For example, the compatibilty + // '!' Token operand. Handle that here. For example, the compatibility // alias for 'srsdb sp!, #imm' is 'srsdb #imm!'. if (Parser.getTok().is(AsmToken::Exclaim)) { Operands.push_back(ARMOperand::CreateToken(Parser.getTok().getString(), @@ -4653,6 +4744,20 @@ bool ARMAsmParser::parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, Operands.push_back(ARMOperand::CreateImm(ExprVal, S, E)); return false; } + case AsmToken::Equal: { + if (Mnemonic != "ldr") // only parse for ldr pseudo (e.g. ldr r0, =val) + return Error(Parser.getTok().getLoc(), "unexpected token in operand"); + + Parser.Lex(); // Eat '=' + const MCExpr *SubExprVal; + if (getParser().parseExpression(SubExprVal)) + return true; + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + const MCExpr *CPLoc = getTargetStreamer().addConstantPoolEntry(SubExprVal); + Operands.push_back(ARMOperand::CreateImm(CPLoc, S, E)); + return false; + } } } @@ -4661,6 +4766,10 @@ bool ARMAsmParser::parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) { RefKind = ARMMCExpr::VK_ARM_None; + // consume an optional '#' (GNU compatibility) + if (getLexer().is(AsmToken::Hash)) + Parser.Lex(); + // :lower16: and :upper16: modifiers assert(getLexer().is(AsmToken::Colon) && "expected a :"); Parser.Lex(); // Eat ':' @@ -4763,7 +4872,7 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic, Mnemonic == "fmrs" || Mnemonic == "fsqrts" || Mnemonic == "fsubs" || Mnemonic == "fsts" || Mnemonic == "fcpys" || Mnemonic == "fdivs" || Mnemonic == "fmuls" || Mnemonic == "fcmps" || Mnemonic == "fcmpzs" || - Mnemonic == "vfms" || Mnemonic == "vfnms" || + Mnemonic == "vfms" || Mnemonic == "vfnms" || Mnemonic == "fconsts" || (Mnemonic == "movs" && isThumb()))) { Mnemonic = Mnemonic.slice(0, Mnemonic.size() - 1); CarrySetting = true; @@ -5009,12 +5118,40 @@ static bool doesIgnoreDataTypeSuffix(StringRef Mnemonic, StringRef DT) { } static void applyMnemonicAliases(StringRef &Mnemonic, unsigned Features, unsigned VariantID); + +static bool RequiresVFPRegListValidation(StringRef Inst, + bool &AcceptSinglePrecisionOnly, + bool &AcceptDoublePrecisionOnly) { + if (Inst.size() < 7) + return false; + + if (Inst.startswith("fldm") || Inst.startswith("fstm")) { + StringRef AddressingMode = Inst.substr(4, 2); + if (AddressingMode == "ia" || AddressingMode == "db" || + AddressingMode == "ea" || AddressingMode == "fd") { + AcceptSinglePrecisionOnly = Inst[6] == 's'; + AcceptDoublePrecisionOnly = Inst[6] == 'd' || Inst[6] == 'x'; + return true; + } + } + + return false; +} + /// Parse an arm instruction mnemonic followed by its operands. bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + // FIXME: Can this be done via tablegen in some fashion? + bool RequireVFPRegisterListCheck; + bool AcceptSinglePrecisionOnly; + bool AcceptDoublePrecisionOnly; + RequireVFPRegisterListCheck = + RequiresVFPRegListValidation(Name, AcceptSinglePrecisionOnly, + AcceptDoublePrecisionOnly); + // Apply mnemonic aliases before doing anything else, as the destination - // mnemnonic may include suffices and we want to handle them normally. + // mnemonic may include suffices and we want to handle them normally. // The generic tblgen'erated code does this later, at the start of // MatchInstructionImpl(), but that's too late for aliases that include // any sort of suffix. @@ -5141,6 +5278,7 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, // For for ARM mode generate an error if the .n qualifier is used. if (ExtraToken == ".n" && !isThumb()) { SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Start); + Parser.eatToEndOfStatement(); return Error(Loc, "instruction with .n (narrow) qualifier not allowed in " "arm mode"); } @@ -5181,6 +5319,16 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, Parser.Lex(); // Consume the EndOfStatement + if (RequireVFPRegisterListCheck) { + ARMOperand *Op = static_cast<ARMOperand*>(Operands.back()); + if (AcceptSinglePrecisionOnly && !Op->isSPRRegList()) + return Error(Op->getStartLoc(), + "VFP/Neon single precision register expected"); + if (AcceptDoublePrecisionOnly && !Op->isDPRRegList()) + return Error(Op->getStartLoc(), + "VFP/Neon double precision register expected"); + } + // Some instructions, mostly Thumb, have forms for the same mnemonic that // do and don't have a cc_out optional-def operand. With some spot-checks // of the operand list, we can figure out which variant we're trying to @@ -5255,6 +5403,24 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, } } + // GNU Assembler extension (compatibility) + if ((Mnemonic == "ldrd" || Mnemonic == "strd") && !isThumb() && + Operands.size() == 4) { + ARMOperand *Op = static_cast<ARMOperand *>(Operands[2]); + assert(Op->isReg() && "expected register argument"); + + unsigned SuperReg = MRI->getMatchingSuperReg( + Op->getReg(), ARM::gsub_0, &MRI->getRegClass(ARM::GPRPairRegClassID)); + + assert(SuperReg && "expected register pair"); + + unsigned PairedReg = MRI->getSubReg(SuperReg, ARM::gsub_1); + + Operands.insert(Operands.begin() + 3, + ARMOperand::CreateReg(PairedReg, Op->getStartLoc(), + Op->getEndLoc())); + } + // FIXME: As said above, this is all a pretty gross hack. This instruction // does not fit with other "subs" and tblgen. // Adjust operands of B9.3.19 SUBS PC, LR, #imm (Thumb2) system instruction @@ -5496,7 +5662,6 @@ validateInstruction(MCInst &Inst, case ARM::sysSTMIB_UPD: return Error(Operands[2]->getStartLoc(), "system STM cannot have writeback register"); - break; case ARM::tMUL: { // The second source operand must be the same register as the destination // operand. @@ -5789,7 +5954,7 @@ static unsigned getRealVLDOpcode(unsigned Opc, unsigned &Spacing) { case ARM::VLD4LNdWB_fixed_Asm_8: Spacing = 1; return ARM::VLD4LNd8_UPD; case ARM::VLD4LNdWB_fixed_Asm_16: Spacing = 1; return ARM::VLD4LNd16_UPD; case ARM::VLD4LNdWB_fixed_Asm_32: Spacing = 1; return ARM::VLD4LNd32_UPD; - case ARM::VLD4LNqWB_fixed_Asm_16: Spacing = 1; return ARM::VLD4LNq16_UPD; + case ARM::VLD4LNqWB_fixed_Asm_16: Spacing = 2; return ARM::VLD4LNq16_UPD; case ARM::VLD4LNqWB_fixed_Asm_32: Spacing = 2; return ARM::VLD4LNq32_UPD; case ARM::VLD4LNdWB_register_Asm_8: Spacing = 1; return ARM::VLD4LNd8_UPD; case ARM::VLD4LNdWB_register_Asm_16: Spacing = 1; return ARM::VLD4LNd16_UPD; @@ -5848,6 +6013,42 @@ bool ARMAsmParser:: processInstruction(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &Operands) { switch (Inst.getOpcode()) { + // Alias for alternate form of 'ldr{,b}t Rt, [Rn], #imm' instruction. + case ARM::LDRT_POST: + case ARM::LDRBT_POST: { + const unsigned Opcode = + (Inst.getOpcode() == ARM::LDRT_POST) ? ARM::LDRT_POST_IMM + : ARM::LDRBT_POST_IMM; + MCInst TmpInst; + TmpInst.setOpcode(Opcode); + TmpInst.addOperand(Inst.getOperand(0)); + TmpInst.addOperand(Inst.getOperand(1)); + TmpInst.addOperand(Inst.getOperand(1)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + TmpInst.addOperand(Inst.getOperand(2)); + TmpInst.addOperand(Inst.getOperand(3)); + Inst = TmpInst; + return true; + } + // Alias for alternate form of 'str{,b}t Rt, [Rn], #imm' instruction. + case ARM::STRT_POST: + case ARM::STRBT_POST: { + const unsigned Opcode = + (Inst.getOpcode() == ARM::STRT_POST) ? ARM::STRT_POST_IMM + : ARM::STRBT_POST_IMM; + MCInst TmpInst; + TmpInst.setOpcode(Opcode); + TmpInst.addOperand(Inst.getOperand(1)); + TmpInst.addOperand(Inst.getOperand(0)); + TmpInst.addOperand(Inst.getOperand(1)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + TmpInst.addOperand(Inst.getOperand(2)); + TmpInst.addOperand(Inst.getOperand(3)); + Inst = TmpInst; + return true; + } // Alias for alternate form of 'ADR Rd, #imm' instruction. case ARM::ADDri: { if (Inst.getOperand(1).getReg() != ARM::PC || @@ -7659,6 +7860,10 @@ unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) { return Match_Success; } +template<> inline bool IsCPSRDead<MCInst>(MCInst* Instr) { + return true; // In an assembly source, no need to second-guess +} + static const char *getSubtargetFeatureName(unsigned Val); bool ARMAsmParser:: MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, @@ -7694,7 +7899,7 @@ MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, // Only after the instruction is fully processed, we can validate it if (wasInITBlock && hasV8Ops() && isThumb() && - !isV8EligibleForIT(&Inst, 2)) { + !isV8EligibleForIT(&Inst)) { Warning(IDLoc, "deprecated instruction in IT block"); } } @@ -7710,7 +7915,7 @@ MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return false; Inst.setLoc(IDLoc); - Out.EmitInstruction(Inst); + Out.EmitInstruction(Inst, STI); return false; case Match_MissingFeature: { assert(ErrorInfo && "Unknown missing feature!"); @@ -7769,7 +7974,9 @@ MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getIdentifier(); if (IDVal == ".word") - return parseDirectiveWord(4, DirectiveID.getLoc()); + return parseLiteralValues(4, DirectiveID.getLoc()); + else if (IDVal == ".short" || IDVal == ".hword") + return parseLiteralValues(2, DirectiveID.getLoc()); else if (IDVal == ".thumb") return parseDirectiveThumb(DirectiveID.getLoc()); else if (IDVal == ".arm") @@ -7808,17 +8015,47 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { return parseDirectiveRegSave(DirectiveID.getLoc(), false); else if (IDVal == ".vsave") return parseDirectiveRegSave(DirectiveID.getLoc(), true); + else if (IDVal == ".inst") + return parseDirectiveInst(DirectiveID.getLoc()); + else if (IDVal == ".inst.n") + return parseDirectiveInst(DirectiveID.getLoc(), 'n'); + else if (IDVal == ".inst.w") + return parseDirectiveInst(DirectiveID.getLoc(), 'w'); + else if (IDVal == ".ltorg" || IDVal == ".pool") + return parseDirectiveLtorg(DirectiveID.getLoc()); + else if (IDVal == ".even") + return parseDirectiveEven(DirectiveID.getLoc()); + else if (IDVal == ".personalityindex") + return parseDirectivePersonalityIndex(DirectiveID.getLoc()); + else if (IDVal == ".unwind_raw") + return parseDirectiveUnwindRaw(DirectiveID.getLoc()); + else if (IDVal == ".tlsdescseq") + return parseDirectiveTLSDescSeq(DirectiveID.getLoc()); + else if (IDVal == ".movsp") + return parseDirectiveMovSP(DirectiveID.getLoc()); + else if (IDVal == ".object_arch") + return parseDirectiveObjectArch(DirectiveID.getLoc()); + else if (IDVal == ".arch_extension") + return parseDirectiveArchExtension(DirectiveID.getLoc()); + else if (IDVal == ".align") + return parseDirectiveAlign(DirectiveID.getLoc()); + else if (IDVal == ".thumb_set") + return parseDirectiveThumbSet(DirectiveID.getLoc()); return true; } -/// parseDirectiveWord -/// ::= .word [ expression (, expression)* ] -bool ARMAsmParser::parseDirectiveWord(unsigned Size, SMLoc L) { +/// parseLiteralValues +/// ::= .hword expression [, expression]* +/// ::= .short expression [, expression]* +/// ::= .word expression [, expression]* +bool ARMAsmParser::parseLiteralValues(unsigned Size, SMLoc L) { if (getLexer().isNot(AsmToken::EndOfStatement)) { for (;;) { const MCExpr *Value; - if (getParser().parseExpression(Value)) - return true; + if (getParser().parseExpression(Value)) { + Parser.eatToEndOfStatement(); + return false; + } getParser().getStreamer().EmitValue(Value, Size); @@ -7826,8 +8063,10 @@ bool ARMAsmParser::parseDirectiveWord(unsigned Size, SMLoc L) { break; // FIXME: Improve diagnostic. - if (getLexer().isNot(AsmToken::Comma)) - return Error(L, "unexpected token in directive"); + if (getLexer().isNot(AsmToken::Comma)) { + Error(L, "unexpected token in directive"); + return false; + } Parser.Lex(); } } @@ -7839,15 +8078,20 @@ bool ARMAsmParser::parseDirectiveWord(unsigned Size, SMLoc L) { /// parseDirectiveThumb /// ::= .thumb bool ARMAsmParser::parseDirectiveThumb(SMLoc L) { - if (getLexer().isNot(AsmToken::EndOfStatement)) - return Error(L, "unexpected token in directive"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(L, "unexpected token in directive"); + return false; + } Parser.Lex(); - if (!hasThumb()) - return Error(L, "target does not support Thumb mode"); + if (!hasThumb()) { + Error(L, "target does not support Thumb mode"); + return false; + } if (!isThumb()) SwitchMode(); + getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); return false; } @@ -7855,15 +8099,20 @@ bool ARMAsmParser::parseDirectiveThumb(SMLoc L) { /// parseDirectiveARM /// ::= .arm bool ARMAsmParser::parseDirectiveARM(SMLoc L) { - if (getLexer().isNot(AsmToken::EndOfStatement)) - return Error(L, "unexpected token in directive"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(L, "unexpected token in directive"); + return false; + } Parser.Lex(); - if (!hasARM()) - return Error(L, "target does not support ARM mode"); + if (!hasARM()) { + Error(L, "target does not support ARM mode"); + return false; + } if (isThumb()) SwitchMode(); + getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32); return false; } @@ -7872,6 +8121,32 @@ void ARMAsmParser::onLabelParsed(MCSymbol *Symbol) { if (NextSymbolIsThumb) { getParser().getStreamer().EmitThumbFunc(Symbol); NextSymbolIsThumb = false; + return; + } + + if (!isThumb()) + return; + + const MCObjectFileInfo::Environment Format = + getContext().getObjectFileInfo()->getObjectFileType(); + switch (Format) { + case MCObjectFileInfo::IsCOFF: { + const MCSymbolData &SD = + getParser().getStreamer().getOrCreateSymbolData(Symbol); + char Type = COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT; + if (SD.getFlags() & (Type << COFF::SF_TypeShift)) + getParser().getStreamer().EmitThumbFunc(Symbol); + break; + } + case MCObjectFileInfo::IsELF: { + const MCSymbolData &SD = + getParser().getStreamer().getOrCreateSymbolData(Symbol); + if (MCELF::GetType(SD) & (ELF::STT_FUNC << ELF_STT_Shift)) + getParser().getStreamer().EmitThumbFunc(Symbol); + break; + } + case MCObjectFileInfo::IsMachO: + break; } } @@ -7886,8 +8161,11 @@ bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) { if (isMachO) { const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::EndOfStatement)) { - if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) - return Error(L, "unexpected token in .thumb_func directive"); + if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) { + Error(L, "unexpected token in .thumb_func directive"); + return false; + } + MCSymbol *Func = getParser().getContext().GetOrCreateSymbol(Tok.getIdentifier()); getParser().getStreamer().EmitThumbFunc(Func); @@ -7896,11 +8174,12 @@ bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) { } } - if (getLexer().isNot(AsmToken::EndOfStatement)) - return Error(L, "unexpected token in directive"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(L, "unexpected token in directive"); + return false; + } NextSymbolIsThumb = true; - return false; } @@ -7908,18 +8187,26 @@ bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) { /// ::= .syntax unified | divided bool ARMAsmParser::parseDirectiveSyntax(SMLoc L) { const AsmToken &Tok = Parser.getTok(); - if (Tok.isNot(AsmToken::Identifier)) - return Error(L, "unexpected token in .syntax directive"); + if (Tok.isNot(AsmToken::Identifier)) { + Error(L, "unexpected token in .syntax directive"); + return false; + } + StringRef Mode = Tok.getString(); - if (Mode == "unified" || Mode == "UNIFIED") + if (Mode == "unified" || Mode == "UNIFIED") { Parser.Lex(); - else if (Mode == "divided" || Mode == "DIVIDED") - return Error(L, "'.syntax divided' arm asssembly not supported"); - else - return Error(L, "unrecognized syntax mode in .syntax directive"); + } else if (Mode == "divided" || Mode == "DIVIDED") { + Error(L, "'.syntax divided' arm asssembly not supported"); + return false; + } else { + Error(L, "unrecognized syntax mode in .syntax directive"); + return false; + } - if (getLexer().isNot(AsmToken::EndOfStatement)) - return Error(Parser.getTok().getLoc(), "unexpected token in directive"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), "unexpected token in directive"); + return false; + } Parser.Lex(); // TODO tell the MC streamer the mode @@ -7931,30 +8218,37 @@ bool ARMAsmParser::parseDirectiveSyntax(SMLoc L) { /// ::= .code 16 | 32 bool ARMAsmParser::parseDirectiveCode(SMLoc L) { const AsmToken &Tok = Parser.getTok(); - if (Tok.isNot(AsmToken::Integer)) - return Error(L, "unexpected token in .code directive"); + if (Tok.isNot(AsmToken::Integer)) { + Error(L, "unexpected token in .code directive"); + return false; + } int64_t Val = Parser.getTok().getIntVal(); - if (Val == 16) - Parser.Lex(); - else if (Val == 32) - Parser.Lex(); - else - return Error(L, "invalid operand to .code directive"); + if (Val != 16 && Val != 32) { + Error(L, "invalid operand to .code directive"); + return false; + } + Parser.Lex(); - if (getLexer().isNot(AsmToken::EndOfStatement)) - return Error(Parser.getTok().getLoc(), "unexpected token in directive"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), "unexpected token in directive"); + return false; + } Parser.Lex(); if (Val == 16) { - if (!hasThumb()) - return Error(L, "target does not support Thumb mode"); + if (!hasThumb()) { + Error(L, "target does not support Thumb mode"); + return false; + } if (!isThumb()) SwitchMode(); getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); } else { - if (!hasARM()) - return Error(L, "target does not support ARM mode"); + if (!hasARM()) { + Error(L, "target does not support ARM mode"); + return false; + } if (isThumb()) SwitchMode(); @@ -7972,21 +8266,23 @@ bool ARMAsmParser::parseDirectiveReq(StringRef Name, SMLoc L) { SMLoc SRegLoc, ERegLoc; if (ParseRegister(Reg, SRegLoc, ERegLoc)) { Parser.eatToEndOfStatement(); - return Error(SRegLoc, "register name expected"); + Error(SRegLoc, "register name expected"); + return false; } // Shouldn't be anything else. if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { Parser.eatToEndOfStatement(); - return Error(Parser.getTok().getLoc(), - "unexpected input in .req directive."); + Error(Parser.getTok().getLoc(), "unexpected input in .req directive."); + return false; } Parser.Lex(); // Consume the EndOfStatement - if (RegisterReqs.GetOrCreateValue(Name, Reg).getValue() != Reg) - return Error(SRegLoc, "redefinition of '" + Name + - "' does not match original."); + if (RegisterReqs.GetOrCreateValue(Name, Reg).getValue() != Reg) { + Error(SRegLoc, "redefinition of '" + Name + "' does not match original."); + return false; + } return false; } @@ -7996,9 +8292,10 @@ bool ARMAsmParser::parseDirectiveReq(StringRef Name, SMLoc L) { bool ARMAsmParser::parseDirectiveUnreq(SMLoc L) { if (Parser.getTok().isNot(AsmToken::Identifier)) { Parser.eatToEndOfStatement(); - return Error(L, "unexpected input in .unreq directive."); + Error(L, "unexpected input in .unreq directive."); + return false; } - RegisterReqs.erase(Parser.getTok().getIdentifier()); + RegisterReqs.erase(Parser.getTok().getIdentifier().lower()); Parser.Lex(); // Eat the identifier. return false; } @@ -8006,34 +8303,158 @@ bool ARMAsmParser::parseDirectiveUnreq(SMLoc L) { /// parseDirectiveArch /// ::= .arch token bool ARMAsmParser::parseDirectiveArch(SMLoc L) { - return true; + const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo(); + bool isMachO = MAI->hasSubsectionsViaSymbols(); + if (isMachO) { + Error(L, ".arch directive not valid for Mach-O"); + Parser.eatToEndOfStatement(); + return false; + } + + StringRef Arch = getParser().parseStringToEndOfStatement().trim(); + + unsigned ID = StringSwitch<unsigned>(Arch) +#define ARM_ARCH_NAME(NAME, ID, DEFAULT_CPU_NAME, DEFAULT_CPU_ARCH) \ + .Case(NAME, ARM::ID) +#define ARM_ARCH_ALIAS(NAME, ID) \ + .Case(NAME, ARM::ID) +#include "MCTargetDesc/ARMArchName.def" + .Default(ARM::INVALID_ARCH); + + if (ID == ARM::INVALID_ARCH) { + Error(L, "Unknown arch name"); + return false; + } + + getTargetStreamer().emitArch(ID); + return false; } /// parseDirectiveEabiAttr -/// ::= .eabi_attribute int, int +/// ::= .eabi_attribute int, int [, "str"] +/// ::= .eabi_attribute Tag_name, int [, "str"] bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) { - if (Parser.getTok().isNot(AsmToken::Integer)) - return Error(L, "integer expected"); - int64_t Tag = Parser.getTok().getIntVal(); - Parser.Lex(); // eat tag integer + const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo(); + bool isMachO = MAI->hasSubsectionsViaSymbols(); + if (isMachO) { + Error(L, ".eabi_attribute directive not valid for Mach-O"); + Parser.eatToEndOfStatement(); + return false; + } - if (Parser.getTok().isNot(AsmToken::Comma)) - return Error(L, "comma expected"); + int64_t Tag; + SMLoc TagLoc; + TagLoc = Parser.getTok().getLoc(); + if (Parser.getTok().is(AsmToken::Identifier)) { + StringRef Name = Parser.getTok().getIdentifier(); + Tag = ARMBuildAttrs::AttrTypeFromString(Name); + if (Tag == -1) { + Error(TagLoc, "attribute name not recognised: " + Name); + Parser.eatToEndOfStatement(); + return false; + } + Parser.Lex(); + } else { + const MCExpr *AttrExpr; + + TagLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(AttrExpr)) { + Parser.eatToEndOfStatement(); + return false; + } + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr); + if (!CE) { + Error(TagLoc, "expected numeric constant"); + Parser.eatToEndOfStatement(); + return false; + } + + Tag = CE->getValue(); + } + + if (Parser.getTok().isNot(AsmToken::Comma)) { + Error(Parser.getTok().getLoc(), "comma expected"); + Parser.eatToEndOfStatement(); + return false; + } Parser.Lex(); // skip comma - L = Parser.getTok().getLoc(); - if (Parser.getTok().isNot(AsmToken::Integer)) - return Error(L, "integer expected"); - int64_t Value = Parser.getTok().getIntVal(); - Parser.Lex(); // eat value integer + StringRef StringValue = ""; + bool IsStringValue = false; + + int64_t IntegerValue = 0; + bool IsIntegerValue = false; + + if (Tag == ARMBuildAttrs::CPU_raw_name || Tag == ARMBuildAttrs::CPU_name) + IsStringValue = true; + else if (Tag == ARMBuildAttrs::compatibility) { + IsStringValue = true; + IsIntegerValue = true; + } else if (Tag < 32 || Tag % 2 == 0) + IsIntegerValue = true; + else if (Tag % 2 == 1) + IsStringValue = true; + else + llvm_unreachable("invalid tag type"); - getTargetStreamer().emitAttribute(Tag, Value); + if (IsIntegerValue) { + const MCExpr *ValueExpr; + SMLoc ValueExprLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(ValueExpr)) { + Parser.eatToEndOfStatement(); + return false; + } + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr); + if (!CE) { + Error(ValueExprLoc, "expected numeric constant"); + Parser.eatToEndOfStatement(); + return false; + } + + IntegerValue = CE->getValue(); + } + + if (Tag == ARMBuildAttrs::compatibility) { + if (Parser.getTok().isNot(AsmToken::Comma)) + IsStringValue = false; + else + Parser.Lex(); + } + + if (IsStringValue) { + if (Parser.getTok().isNot(AsmToken::String)) { + Error(Parser.getTok().getLoc(), "bad string constant"); + Parser.eatToEndOfStatement(); + return false; + } + + StringValue = Parser.getTok().getStringContents(); + Parser.Lex(); + } + + if (IsIntegerValue && IsStringValue) { + assert(Tag == ARMBuildAttrs::compatibility); + getTargetStreamer().emitIntTextAttribute(Tag, IntegerValue, StringValue); + } else if (IsIntegerValue) + getTargetStreamer().emitAttribute(Tag, IntegerValue); + else if (IsStringValue) + getTargetStreamer().emitTextAttribute(Tag, StringValue); return false; } /// parseDirectiveCPU /// ::= .cpu str bool ARMAsmParser::parseDirectiveCPU(SMLoc L) { + const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo(); + bool isMachO = MAI->hasSubsectionsViaSymbols(); + if (isMachO) { + Error(L, ".cpu directive not valid for Mach-O"); + Parser.eatToEndOfStatement(); + return false; + } + StringRef CPU = getParser().parseStringToEndOfStatement().trim(); getTargetStreamer().emitTextAttribute(ARMBuildAttrs::CPU_name, CPU); return false; @@ -8042,6 +8463,14 @@ bool ARMAsmParser::parseDirectiveCPU(SMLoc L) { /// parseDirectiveFPU /// ::= .fpu str bool ARMAsmParser::parseDirectiveFPU(SMLoc L) { + const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo(); + bool isMachO = MAI->hasSubsectionsViaSymbols(); + if (isMachO) { + Error(L, ".fpu directive not valid for Mach-O"); + Parser.eatToEndOfStatement(); + return false; + } + StringRef FPU = getParser().parseStringToEndOfStatement().trim(); unsigned ID = StringSwitch<unsigned>(FPU) @@ -8049,8 +8478,10 @@ bool ARMAsmParser::parseDirectiveFPU(SMLoc L) { #include "ARMFPUName.def" .Default(ARM::INVALID_FPU); - if (ID == ARM::INVALID_FPU) - return Error(L, "Unknown FPU name"); + if (ID == ARM::INVALID_FPU) { + Error(L, "Unknown FPU name"); + return false; + } getTargetStreamer().emitFPU(ID); return false; @@ -8059,14 +8490,26 @@ bool ARMAsmParser::parseDirectiveFPU(SMLoc L) { /// parseDirectiveFnStart /// ::= .fnstart bool ARMAsmParser::parseDirectiveFnStart(SMLoc L) { - if (FnStartLoc.isValid()) { + const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo(); + bool isMachO = MAI->hasSubsectionsViaSymbols(); + if (isMachO) { + Error(L, ".fnstart directive not valid for Mach-O"); + Parser.eatToEndOfStatement(); + return false; + } + + if (UC.hasFnStart()) { Error(L, ".fnstart starts before the end of previous one"); - Error(FnStartLoc, "previous .fnstart starts here"); - return true; + UC.emitFnStartLocNotes(); + return false; } - FnStartLoc = L; + // Reset the unwind directives parser state + UC.reset(); + getTargetStreamer().emitFnStart(); + + UC.recordFnStart(L); return false; } @@ -8074,31 +8517,37 @@ bool ARMAsmParser::parseDirectiveFnStart(SMLoc L) { /// ::= .fnend bool ARMAsmParser::parseDirectiveFnEnd(SMLoc L) { // Check the ordering of unwind directives - if (!FnStartLoc.isValid()) - return Error(L, ".fnstart must precede .fnend directive"); + if (!UC.hasFnStart()) { + Error(L, ".fnstart must precede .fnend directive"); + return false; + } // Reset the unwind directives parser state - resetUnwindDirectiveParserState(); getTargetStreamer().emitFnEnd(); + + UC.reset(); return false; } /// parseDirectiveCantUnwind /// ::= .cantunwind bool ARMAsmParser::parseDirectiveCantUnwind(SMLoc L) { + UC.recordCantUnwind(L); + // Check the ordering of unwind directives - CantUnwindLoc = L; - if (!FnStartLoc.isValid()) - return Error(L, ".fnstart must precede .cantunwind directive"); - if (HandlerDataLoc.isValid()) { + if (!UC.hasFnStart()) { + Error(L, ".fnstart must precede .cantunwind directive"); + return false; + } + if (UC.hasHandlerData()) { Error(L, ".cantunwind can't be used with .handlerdata directive"); - Error(HandlerDataLoc, ".handlerdata was specified here"); - return true; + UC.emitHandlerDataLocNotes(); + return false; } - if (PersonalityLoc.isValid()) { + if (UC.hasPersonality()) { Error(L, ".cantunwind can't be used with .personality directive"); - Error(PersonalityLoc, ".personality was specified here"); - return true; + UC.emitPersonalityLocNotes(); + return false; } getTargetStreamer().emitCantUnwind(); @@ -8108,25 +8557,37 @@ bool ARMAsmParser::parseDirectiveCantUnwind(SMLoc L) { /// parseDirectivePersonality /// ::= .personality name bool ARMAsmParser::parseDirectivePersonality(SMLoc L) { + bool HasExistingPersonality = UC.hasPersonality(); + + UC.recordPersonality(L); + // Check the ordering of unwind directives - PersonalityLoc = L; - if (!FnStartLoc.isValid()) - return Error(L, ".fnstart must precede .personality directive"); - if (CantUnwindLoc.isValid()) { + if (!UC.hasFnStart()) { + Error(L, ".fnstart must precede .personality directive"); + return false; + } + if (UC.cantUnwind()) { Error(L, ".personality can't be used with .cantunwind directive"); - Error(CantUnwindLoc, ".cantunwind was specified here"); - return true; + UC.emitCantUnwindLocNotes(); + return false; } - if (HandlerDataLoc.isValid()) { + if (UC.hasHandlerData()) { Error(L, ".personality must precede .handlerdata directive"); - Error(HandlerDataLoc, ".handlerdata was specified here"); - return true; + UC.emitHandlerDataLocNotes(); + return false; + } + if (HasExistingPersonality) { + Parser.eatToEndOfStatement(); + Error(L, "multiple personality directives"); + UC.emitPersonalityLocNotes(); + return false; } // Parse the name of the personality routine if (Parser.getTok().isNot(AsmToken::Identifier)) { Parser.eatToEndOfStatement(); - return Error(L, "unexpected input in .personality directive."); + Error(L, "unexpected input in .personality directive."); + return false; } StringRef Name(Parser.getTok().getIdentifier()); Parser.Lex(); @@ -8139,14 +8600,17 @@ bool ARMAsmParser::parseDirectivePersonality(SMLoc L) { /// parseDirectiveHandlerData /// ::= .handlerdata bool ARMAsmParser::parseDirectiveHandlerData(SMLoc L) { + UC.recordHandlerData(L); + // Check the ordering of unwind directives - HandlerDataLoc = L; - if (!FnStartLoc.isValid()) - return Error(L, ".fnstart must precede .personality directive"); - if (CantUnwindLoc.isValid()) { + if (!UC.hasFnStart()) { + Error(L, ".fnstart must precede .personality directive"); + return false; + } + if (UC.cantUnwind()) { Error(L, ".handlerdata can't be used with .cantunwind directive"); - Error(CantUnwindLoc, ".cantunwind was specified here"); - return true; + UC.emitCantUnwindLocNotes(); + return false; } getTargetStreamer().emitHandlerData(); @@ -8157,34 +8621,45 @@ bool ARMAsmParser::parseDirectiveHandlerData(SMLoc L) { /// ::= .setfp fpreg, spreg [, offset] bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) { // Check the ordering of unwind directives - if (!FnStartLoc.isValid()) - return Error(L, ".fnstart must precede .setfp directive"); - if (HandlerDataLoc.isValid()) - return Error(L, ".setfp must precede .handlerdata directive"); + if (!UC.hasFnStart()) { + Error(L, ".fnstart must precede .setfp directive"); + return false; + } + if (UC.hasHandlerData()) { + Error(L, ".setfp must precede .handlerdata directive"); + return false; + } // Parse fpreg - SMLoc NewFPRegLoc = Parser.getTok().getLoc(); - int NewFPReg = tryParseRegister(); - if (NewFPReg == -1) - return Error(NewFPRegLoc, "frame pointer register expected"); + SMLoc FPRegLoc = Parser.getTok().getLoc(); + int FPReg = tryParseRegister(); + if (FPReg == -1) { + Error(FPRegLoc, "frame pointer register expected"); + return false; + } // Consume comma - if (!Parser.getTok().is(AsmToken::Comma)) - return Error(Parser.getTok().getLoc(), "comma expected"); + if (Parser.getTok().isNot(AsmToken::Comma)) { + Error(Parser.getTok().getLoc(), "comma expected"); + return false; + } Parser.Lex(); // skip comma // Parse spreg - SMLoc NewSPRegLoc = Parser.getTok().getLoc(); - int NewSPReg = tryParseRegister(); - if (NewSPReg == -1) - return Error(NewSPRegLoc, "stack pointer register expected"); + SMLoc SPRegLoc = Parser.getTok().getLoc(); + int SPReg = tryParseRegister(); + if (SPReg == -1) { + Error(SPRegLoc, "stack pointer register expected"); + return false; + } - if (NewSPReg != ARM::SP && NewSPReg != FPReg) - return Error(NewSPRegLoc, - "register should be either $sp or the latest fp register"); + if (SPReg != ARM::SP && SPReg != UC.getFPReg()) { + Error(SPRegLoc, "register should be either $sp or the latest fp register"); + return false; + } // Update the frame pointer register - FPReg = NewFPReg; + UC.saveFPReg(FPReg); // Parse offset int64_t Offset = 0; @@ -8193,24 +8668,29 @@ bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) { if (Parser.getTok().isNot(AsmToken::Hash) && Parser.getTok().isNot(AsmToken::Dollar)) { - return Error(Parser.getTok().getLoc(), "'#' expected"); + Error(Parser.getTok().getLoc(), "'#' expected"); + return false; } Parser.Lex(); // skip hash token. const MCExpr *OffsetExpr; SMLoc ExLoc = Parser.getTok().getLoc(); SMLoc EndLoc; - if (getParser().parseExpression(OffsetExpr, EndLoc)) - return Error(ExLoc, "malformed setfp offset"); + if (getParser().parseExpression(OffsetExpr, EndLoc)) { + Error(ExLoc, "malformed setfp offset"); + return false; + } const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr); - if (!CE) - return Error(ExLoc, "setfp offset must be an immediate"); + if (!CE) { + Error(ExLoc, "setfp offset must be an immediate"); + return false; + } Offset = CE->getValue(); } - getTargetStreamer().emitSetFP(static_cast<unsigned>(NewFPReg), - static_cast<unsigned>(NewSPReg), Offset); + getTargetStreamer().emitSetFP(static_cast<unsigned>(FPReg), + static_cast<unsigned>(SPReg), Offset); return false; } @@ -8218,26 +8698,35 @@ bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) { /// ::= .pad offset bool ARMAsmParser::parseDirectivePad(SMLoc L) { // Check the ordering of unwind directives - if (!FnStartLoc.isValid()) - return Error(L, ".fnstart must precede .pad directive"); - if (HandlerDataLoc.isValid()) - return Error(L, ".pad must precede .handlerdata directive"); + if (!UC.hasFnStart()) { + Error(L, ".fnstart must precede .pad directive"); + return false; + } + if (UC.hasHandlerData()) { + Error(L, ".pad must precede .handlerdata directive"); + return false; + } // Parse the offset if (Parser.getTok().isNot(AsmToken::Hash) && Parser.getTok().isNot(AsmToken::Dollar)) { - return Error(Parser.getTok().getLoc(), "'#' expected"); + Error(Parser.getTok().getLoc(), "'#' expected"); + return false; } Parser.Lex(); // skip hash token. const MCExpr *OffsetExpr; SMLoc ExLoc = Parser.getTok().getLoc(); SMLoc EndLoc; - if (getParser().parseExpression(OffsetExpr, EndLoc)) - return Error(ExLoc, "malformed pad offset"); + if (getParser().parseExpression(OffsetExpr, EndLoc)) { + Error(ExLoc, "malformed pad offset"); + return false; + } const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr); - if (!CE) - return Error(ExLoc, "pad offset must be an immediate"); + if (!CE) { + Error(ExLoc, "pad offset must be an immediate"); + return false; + } getTargetStreamer().emitPad(CE->getValue()); return false; @@ -8248,10 +8737,14 @@ bool ARMAsmParser::parseDirectivePad(SMLoc L) { /// ::= .vsave { registers } bool ARMAsmParser::parseDirectiveRegSave(SMLoc L, bool IsVector) { // Check the ordering of unwind directives - if (!FnStartLoc.isValid()) - return Error(L, ".fnstart must precede .save or .vsave directives"); - if (HandlerDataLoc.isValid()) - return Error(L, ".save or .vsave must precede .handlerdata directive"); + if (!UC.hasFnStart()) { + Error(L, ".fnstart must precede .save or .vsave directives"); + return false; + } + if (UC.hasHandlerData()) { + Error(L, ".save or .vsave must precede .handlerdata directive"); + return false; + } // RAII object to make sure parsed operands are deleted. struct CleanupObject { @@ -8264,21 +8757,509 @@ bool ARMAsmParser::parseDirectiveRegSave(SMLoc L, bool IsVector) { // Parse the register list if (parseRegisterList(CO.Operands)) - return true; + return false; ARMOperand *Op = (ARMOperand*)CO.Operands[0]; - if (!IsVector && !Op->isRegList()) - return Error(L, ".save expects GPR registers"); - if (IsVector && !Op->isDPRRegList()) - return Error(L, ".vsave expects DPR registers"); + if (!IsVector && !Op->isRegList()) { + Error(L, ".save expects GPR registers"); + return false; + } + if (IsVector && !Op->isDPRRegList()) { + Error(L, ".vsave expects DPR registers"); + return false; + } getTargetStreamer().emitRegSave(Op->getRegList(), IsVector); return false; } +/// parseDirectiveInst +/// ::= .inst opcode [, ...] +/// ::= .inst.n opcode [, ...] +/// ::= .inst.w opcode [, ...] +bool ARMAsmParser::parseDirectiveInst(SMLoc Loc, char Suffix) { + const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo(); + bool isMachO = MAI->hasSubsectionsViaSymbols(); + if (isMachO) { + Error(Loc, ".inst directive not valid for Mach-O"); + Parser.eatToEndOfStatement(); + return false; + } + + int Width; + + if (isThumb()) { + switch (Suffix) { + case 'n': + Width = 2; + break; + case 'w': + Width = 4; + break; + default: + Parser.eatToEndOfStatement(); + Error(Loc, "cannot determine Thumb instruction size, " + "use inst.n/inst.w instead"); + return false; + } + } else { + if (Suffix) { + Parser.eatToEndOfStatement(); + Error(Loc, "width suffixes are invalid in ARM mode"); + return false; + } + Width = 4; + } + + if (getLexer().is(AsmToken::EndOfStatement)) { + Parser.eatToEndOfStatement(); + Error(Loc, "expected expression following directive"); + return false; + } + + for (;;) { + const MCExpr *Expr; + + if (getParser().parseExpression(Expr)) { + Error(Loc, "expected expression"); + return false; + } + + const MCConstantExpr *Value = dyn_cast_or_null<MCConstantExpr>(Expr); + if (!Value) { + Error(Loc, "expected constant expression"); + return false; + } + + switch (Width) { + case 2: + if (Value->getValue() > 0xffff) { + Error(Loc, "inst.n operand is too big, use inst.w instead"); + return false; + } + break; + case 4: + if (Value->getValue() > 0xffffffff) { + Error(Loc, + StringRef(Suffix ? "inst.w" : "inst") + " operand is too big"); + return false; + } + break; + default: + llvm_unreachable("only supported widths are 2 and 4"); + } + + getTargetStreamer().emitInst(Value->getValue(), Suffix); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) { + Error(Loc, "unexpected token in directive"); + return false; + } + + Parser.Lex(); + } + + Parser.Lex(); + return false; +} + +/// parseDirectiveLtorg +/// ::= .ltorg | .pool +bool ARMAsmParser::parseDirectiveLtorg(SMLoc L) { + getTargetStreamer().emitCurrentConstantPool(); + return false; +} + +bool ARMAsmParser::parseDirectiveEven(SMLoc L) { + const MCSection *Section = getStreamer().getCurrentSection().first; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + TokError("unexpected token in directive"); + return false; + } + + if (!Section) { + getStreamer().InitSections(); + Section = getStreamer().getCurrentSection().first; + } + + assert(Section && "must have section to emit alignment"); + if (Section->UseCodeAlign()) + getStreamer().EmitCodeAlignment(2); + else + getStreamer().EmitValueToAlignment(2); + + return false; +} + +/// parseDirectivePersonalityIndex +/// ::= .personalityindex index +bool ARMAsmParser::parseDirectivePersonalityIndex(SMLoc L) { + bool HasExistingPersonality = UC.hasPersonality(); + + UC.recordPersonalityIndex(L); + + if (!UC.hasFnStart()) { + Parser.eatToEndOfStatement(); + Error(L, ".fnstart must precede .personalityindex directive"); + return false; + } + if (UC.cantUnwind()) { + Parser.eatToEndOfStatement(); + Error(L, ".personalityindex cannot be used with .cantunwind"); + UC.emitCantUnwindLocNotes(); + return false; + } + if (UC.hasHandlerData()) { + Parser.eatToEndOfStatement(); + Error(L, ".personalityindex must precede .handlerdata directive"); + UC.emitHandlerDataLocNotes(); + return false; + } + if (HasExistingPersonality) { + Parser.eatToEndOfStatement(); + Error(L, "multiple personality directives"); + UC.emitPersonalityLocNotes(); + return false; + } + + const MCExpr *IndexExpression; + SMLoc IndexLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(IndexExpression)) { + Parser.eatToEndOfStatement(); + return false; + } + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(IndexExpression); + if (!CE) { + Parser.eatToEndOfStatement(); + Error(IndexLoc, "index must be a constant number"); + return false; + } + if (CE->getValue() < 0 || + CE->getValue() >= ARM::EHABI::NUM_PERSONALITY_INDEX) { + Parser.eatToEndOfStatement(); + Error(IndexLoc, "personality routine index should be in range [0-3]"); + return false; + } + + getTargetStreamer().emitPersonalityIndex(CE->getValue()); + return false; +} + +/// parseDirectiveUnwindRaw +/// ::= .unwind_raw offset, opcode [, opcode...] +bool ARMAsmParser::parseDirectiveUnwindRaw(SMLoc L) { + if (!UC.hasFnStart()) { + Parser.eatToEndOfStatement(); + Error(L, ".fnstart must precede .unwind_raw directives"); + return false; + } + + int64_t StackOffset; + + const MCExpr *OffsetExpr; + SMLoc OffsetLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::EndOfStatement) || + getParser().parseExpression(OffsetExpr)) { + Error(OffsetLoc, "expected expression"); + Parser.eatToEndOfStatement(); + return false; + } + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr); + if (!CE) { + Error(OffsetLoc, "offset must be a constant"); + Parser.eatToEndOfStatement(); + return false; + } + + StackOffset = CE->getValue(); + + if (getLexer().isNot(AsmToken::Comma)) { + Error(getLexer().getLoc(), "expected comma"); + Parser.eatToEndOfStatement(); + return false; + } + Parser.Lex(); + + SmallVector<uint8_t, 16> Opcodes; + for (;;) { + const MCExpr *OE; + + SMLoc OpcodeLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::EndOfStatement) || Parser.parseExpression(OE)) { + Error(OpcodeLoc, "expected opcode expression"); + Parser.eatToEndOfStatement(); + return false; + } + + const MCConstantExpr *OC = dyn_cast<MCConstantExpr>(OE); + if (!OC) { + Error(OpcodeLoc, "opcode value must be a constant"); + Parser.eatToEndOfStatement(); + return false; + } + + const int64_t Opcode = OC->getValue(); + if (Opcode & ~0xff) { + Error(OpcodeLoc, "invalid opcode"); + Parser.eatToEndOfStatement(); + return false; + } + + Opcodes.push_back(uint8_t(Opcode)); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) { + Error(getLexer().getLoc(), "unexpected token in directive"); + Parser.eatToEndOfStatement(); + return false; + } + + Parser.Lex(); + } + + getTargetStreamer().emitUnwindRaw(StackOffset, Opcodes); + + Parser.Lex(); + return false; +} + +/// parseDirectiveTLSDescSeq +/// ::= .tlsdescseq tls-variable +bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) { + const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo(); + bool isMachO = MAI->hasSubsectionsViaSymbols(); + if (isMachO) { + Error(L, ".tlsdescseq directive not valid for Mach-O"); + Parser.eatToEndOfStatement(); + return false; + } + + if (getLexer().isNot(AsmToken::Identifier)) { + TokError("expected variable after '.tlsdescseq' directive"); + Parser.eatToEndOfStatement(); + return false; + } + + const MCSymbolRefExpr *SRE = + MCSymbolRefExpr::Create(Parser.getTok().getIdentifier(), + MCSymbolRefExpr::VK_ARM_TLSDESCSEQ, getContext()); + Lex(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), "unexpected token"); + Parser.eatToEndOfStatement(); + return false; + } + + getTargetStreamer().AnnotateTLSDescriptorSequence(SRE); + return false; +} + +/// parseDirectiveMovSP +/// ::= .movsp reg [, #offset] +bool ARMAsmParser::parseDirectiveMovSP(SMLoc L) { + if (!UC.hasFnStart()) { + Parser.eatToEndOfStatement(); + Error(L, ".fnstart must precede .movsp directives"); + return false; + } + if (UC.getFPReg() != ARM::SP) { + Parser.eatToEndOfStatement(); + Error(L, "unexpected .movsp directive"); + return false; + } + + SMLoc SPRegLoc = Parser.getTok().getLoc(); + int SPReg = tryParseRegister(); + if (SPReg == -1) { + Parser.eatToEndOfStatement(); + Error(SPRegLoc, "register expected"); + return false; + } + + if (SPReg == ARM::SP || SPReg == ARM::PC) { + Parser.eatToEndOfStatement(); + Error(SPRegLoc, "sp and pc are not permitted in .movsp directive"); + return false; + } + + int64_t Offset = 0; + if (Parser.getTok().is(AsmToken::Comma)) { + Parser.Lex(); + + if (Parser.getTok().isNot(AsmToken::Hash)) { + Error(Parser.getTok().getLoc(), "expected #constant"); + Parser.eatToEndOfStatement(); + return false; + } + Parser.Lex(); + + const MCExpr *OffsetExpr; + SMLoc OffsetLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(OffsetExpr)) { + Parser.eatToEndOfStatement(); + Error(OffsetLoc, "malformed offset expression"); + return false; + } + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr); + if (!CE) { + Parser.eatToEndOfStatement(); + Error(OffsetLoc, "offset must be an immediate constant"); + return false; + } + + Offset = CE->getValue(); + } + + getTargetStreamer().emitMovSP(SPReg, Offset); + UC.saveFPReg(SPReg); + + return false; +} + +/// parseDirectiveObjectArch +/// ::= .object_arch name +bool ARMAsmParser::parseDirectiveObjectArch(SMLoc L) { + const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo(); + bool isMachO = MAI->hasSubsectionsViaSymbols(); + if (isMachO) { + Error(L, ".object_arch directive not valid for Mach-O"); + Parser.eatToEndOfStatement(); + return false; + } + + if (getLexer().isNot(AsmToken::Identifier)) { + Error(getLexer().getLoc(), "unexpected token"); + Parser.eatToEndOfStatement(); + return false; + } + + StringRef Arch = Parser.getTok().getString(); + SMLoc ArchLoc = Parser.getTok().getLoc(); + getLexer().Lex(); + + unsigned ID = StringSwitch<unsigned>(Arch) +#define ARM_ARCH_NAME(NAME, ID, DEFAULT_CPU_NAME, DEFAULT_CPU_ARCH) \ + .Case(NAME, ARM::ID) +#define ARM_ARCH_ALIAS(NAME, ID) \ + .Case(NAME, ARM::ID) +#include "MCTargetDesc/ARMArchName.def" +#undef ARM_ARCH_NAME +#undef ARM_ARCH_ALIAS + .Default(ARM::INVALID_ARCH); + + if (ID == ARM::INVALID_ARCH) { + Error(ArchLoc, "unknown architecture '" + Arch + "'"); + Parser.eatToEndOfStatement(); + return false; + } + + getTargetStreamer().emitObjectArch(ID); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(getLexer().getLoc(), "unexpected token"); + Parser.eatToEndOfStatement(); + } + + return false; +} + +/// parseDirectiveAlign +/// ::= .align +bool ARMAsmParser::parseDirectiveAlign(SMLoc L) { + // NOTE: if this is not the end of the statement, fall back to the target + // agnostic handling for this directive which will correctly handle this. + if (getLexer().isNot(AsmToken::EndOfStatement)) + return true; + + // '.align' is target specifically handled to mean 2**2 byte alignment. + if (getStreamer().getCurrentSection().first->UseCodeAlign()) + getStreamer().EmitCodeAlignment(4, 0); + else + getStreamer().EmitValueToAlignment(4, 0, 1, 0); + + return false; +} + +/// parseDirectiveThumbSet +/// ::= .thumb_set name, value +bool ARMAsmParser::parseDirectiveThumbSet(SMLoc L) { + StringRef Name; + if (Parser.parseIdentifier(Name)) { + TokError("expected identifier after '.thumb_set'"); + Parser.eatToEndOfStatement(); + return false; + } + + if (getLexer().isNot(AsmToken::Comma)) { + TokError("expected comma after name '" + Name + "'"); + Parser.eatToEndOfStatement(); + return false; + } + Lex(); + + const MCExpr *Value; + if (Parser.parseExpression(Value)) { + TokError("missing expression"); + Parser.eatToEndOfStatement(); + return false; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + TokError("unexpected token"); + Parser.eatToEndOfStatement(); + return false; + } + Lex(); + + MCSymbol *Alias = getContext().GetOrCreateSymbol(Name); + if (const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(Value)) { + MCSymbol *Sym = getContext().LookupSymbol(SRE->getSymbol().getName()); + if (!Sym->isDefined()) { + getStreamer().EmitSymbolAttribute(Sym, MCSA_Global); + getStreamer().EmitAssignment(Alias, Value); + return false; + } + + const MCObjectFileInfo::Environment Format = + getContext().getObjectFileInfo()->getObjectFileType(); + switch (Format) { + case MCObjectFileInfo::IsCOFF: { + char Type = COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT; + getStreamer().EmitCOFFSymbolType(Type); + // .set values are always local in COFF + getStreamer().EmitSymbolAttribute(Alias, MCSA_Local); + break; + } + case MCObjectFileInfo::IsELF: + getStreamer().EmitSymbolAttribute(Alias, MCSA_ELF_TypeFunction); + break; + case MCObjectFileInfo::IsMachO: + break; + } + } + + // FIXME: set the function as being a thumb function via the assembler + getStreamer().EmitThumbFunc(Alias); + getStreamer().EmitAssignment(Alias, Value); + + return false; +} + /// Force static initialization. extern "C" void LLVMInitializeARMAsmParser() { - RegisterMCAsmParser<ARMAsmParser> X(TheARMTarget); - RegisterMCAsmParser<ARMAsmParser> Y(TheThumbTarget); + RegisterMCAsmParser<ARMAsmParser> X(TheARMLETarget); + RegisterMCAsmParser<ARMAsmParser> Y(TheARMBETarget); + RegisterMCAsmParser<ARMAsmParser> A(TheThumbLETarget); + RegisterMCAsmParser<ARMAsmParser> B(TheThumbBETarget); } #define GET_REGISTER_MATCHER @@ -8286,6 +9267,82 @@ extern "C" void LLVMInitializeARMAsmParser() { #define GET_MATCHER_IMPLEMENTATION #include "ARMGenAsmMatcher.inc" +static const struct ExtMapEntry { + const char *Extension; + const unsigned ArchCheck; + const uint64_t Features; +} Extensions[] = { + { "crc", Feature_HasV8, ARM::FeatureCRC }, + { "crypto", Feature_HasV8, + ARM::FeatureCrypto | ARM::FeatureNEON | ARM::FeatureFPARMv8 }, + { "fp", Feature_HasV8, ARM::FeatureFPARMv8 }, + { "idiv", Feature_HasV7 | Feature_IsNotMClass, + ARM::FeatureHWDiv | ARM::FeatureHWDivARM }, + // FIXME: iWMMXT not supported + { "iwmmxt", Feature_None, 0 }, + // FIXME: iWMMXT2 not supported + { "iwmmxt2", Feature_None, 0 }, + // FIXME: Maverick not supported + { "maverick", Feature_None, 0 }, + { "mp", Feature_HasV7 | Feature_IsNotMClass, ARM::FeatureMP }, + // FIXME: ARMv6-m OS Extensions feature not checked + { "os", Feature_None, 0 }, + // FIXME: Also available in ARMv6-K + { "sec", Feature_HasV7, ARM::FeatureTrustZone }, + { "simd", Feature_HasV8, ARM::FeatureNEON | ARM::FeatureFPARMv8 }, + // FIXME: Only available in A-class, isel not predicated + { "virt", Feature_HasV7, ARM::FeatureVirtualization }, + // FIXME: xscale not supported + { "xscale", Feature_None, 0 }, +}; + +/// parseDirectiveArchExtension +/// ::= .arch_extension [no]feature +bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) { + if (getLexer().isNot(AsmToken::Identifier)) { + Error(getLexer().getLoc(), "unexpected token"); + Parser.eatToEndOfStatement(); + return false; + } + + StringRef Extension = Parser.getTok().getString(); + SMLoc ExtLoc = Parser.getTok().getLoc(); + getLexer().Lex(); + + bool EnableFeature = true; + if (Extension.startswith_lower("no")) { + EnableFeature = false; + Extension = Extension.substr(2); + } + + for (unsigned EI = 0, EE = array_lengthof(Extensions); EI != EE; ++EI) { + if (Extensions[EI].Extension != Extension) + continue; + + unsigned FB = getAvailableFeatures(); + if ((FB & Extensions[EI].ArchCheck) != Extensions[EI].ArchCheck) { + Error(ExtLoc, "architectural extension '" + Extension + "' is not " + "allowed for the current base architecture"); + return false; + } + + if (!Extensions[EI].Features) + report_fatal_error("unsupported architectural extension: " + Extension); + + if (EnableFeature) + FB |= ComputeAvailableFeatures(Extensions[EI].Features); + else + FB &= ~ComputeAvailableFeatures(Extensions[EI].Features); + + setAvailableFeatures(FB); + return false; + } + + Error(ExtLoc, "unknown architectural extension: " + Extension); + Parser.eatToEndOfStatement(); + return false; +} + // Define this matcher function after the auto-generated include so we // have the match class enum definitions. unsigned ARMAsmParser::validateTargetOperandClass(MCParsedAsmOperand *AsmOp, @@ -8294,12 +9351,29 @@ unsigned ARMAsmParser::validateTargetOperandClass(MCParsedAsmOperand *AsmOp, // If the kind is a token for a literal immediate, check if our asm // operand matches. This is for InstAliases which have a fixed-value // immediate in the syntax. - if (Kind == MCK__35_0 && Op->isImm()) { - const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm()); - if (!CE) - return Match_InvalidOperand; - if (CE->getValue() == 0) + switch (Kind) { + default: break; + case MCK__35_0: + if (Op->isImm()) + if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm())) + if (CE->getValue() == 0) + return Match_Success; + break; + case MCK_ARMSOImm: + if (Op->isImm()) { + const MCExpr *SOExpr = Op->getImm(); + int64_t Value; + if (!SOExpr->EvaluateAsAbsolute(Value)) + return Match_Success; + assert((Value >= INT32_MIN && Value <= INT32_MAX) && + "expression value must be representiable in 32 bits"); + } + break; + case MCK_GPRPair: + if (Op->isReg() && + MRI->getRegClass(ARM::GPRRegClassID).contains(Op->getReg())) return Match_Success; + break; } return Match_InvalidOperand; } diff --git a/lib/Target/ARM/AsmParser/Android.mk b/lib/Target/ARM/AsmParser/Android.mk index e17a274..5f88cc3 100644 --- a/lib/Target/ARM/AsmParser/Android.mk +++ b/lib/Target/ARM/AsmParser/Android.mk @@ -46,6 +46,7 @@ include $(BUILD_HOST_STATIC_LIBRARY) #===---------------------------------------------------------------=== # libARMAsmParser (target) #===---------------------------------------------------------------=== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) include $(CLEAR_VARS) include $(CLEAR_TBLGEN_VARS) @@ -59,3 +60,4 @@ TBLGEN_TD_DIR := $(arm_asm_parser_TBLGEN_TD_DIR) include $(LLVM_DEVICE_BUILD_MK) include $(LLVM_TBLGEN_RULES_MK) include $(BUILD_STATIC_LIBRARY) +endif diff --git a/lib/Target/ARM/AsmParser/CMakeLists.txt b/lib/Target/ARM/AsmParser/CMakeLists.txt index d2012c3..66ed1df 100644 --- a/lib/Target/ARM/AsmParser/CMakeLists.txt +++ b/lib/Target/ARM/AsmParser/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) - add_llvm_library(LLVMARMAsmParser ARMAsmParser.cpp ) - -add_dependencies(LLVMARMAsmParser ARMCommonTableGen) |