X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTarget%2FARM%2FAsmParser%2FARMAsmParser.cpp;h=68188b131375b68b3345bfcc330ada1bcff3d76e;hp=30c7d62e84b8eb080b9d6c63cb98bb465ccdd983;hb=d84fffe1de546b956429595d652f54f0529dbe07;hpb=eac1f66427c81ae368ca5557505197b4844462da diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 30c7d62e84b..68188b13137 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -28,6 +28,7 @@ #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCAsmParserUtils.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSection.h" @@ -188,9 +189,9 @@ class ARMAsmParser : public MCTargetAsmParser { return getParser().Error(L, Msg, Ranges); } - bool validatetLDMRegList(MCInst Inst, const OperandVector &Operands, + bool validatetLDMRegList(const MCInst &Inst, const OperandVector &Operands, unsigned ListNo, bool IsARPop = false); - bool validatetSTMRegList(MCInst Inst, const OperandVector &Operands, + bool validatetSTMRegList(const MCInst &Inst, const OperandVector &Operands, unsigned ListNo); int tryParseRegister(); @@ -241,6 +242,8 @@ class ARMAsmParser : public MCTargetAsmParser { bool &CanAcceptCarrySet, bool &CanAcceptPredicationCode); + void tryConvertingToTwoOperandForm(StringRef Mnemonic, bool CarrySetting, + OperandVector &Operands); bool isThumb() const { // FIXME: Can tablegen auto-generate this? return STI.getFeatureBits()[ARM::ModeThumb]; @@ -269,8 +272,8 @@ class ARMAsmParser : public MCTargetAsmParser { bool hasARM() const { return !STI.getFeatureBits()[ARM::FeatureNoARM]; } - bool hasThumb2DSP() const { - return STI.getFeatureBits()[ARM::FeatureDSPThumb2]; + bool hasDSP() const { + return STI.getFeatureBits()[ARM::FeatureDSP]; } bool hasD16() const { return STI.getFeatureBits()[ARM::FeatureD16]; @@ -346,7 +349,7 @@ public: ARMAsmParser(MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) - : STI(STI), MII(MII), UC(Parser) { + : MCTargetAsmParser(Options), STI(STI), MII(MII), UC(Parser) { MCAsmParserExtension::Initialize(Parser); // Cache the MCRegisterInfo. @@ -560,87 +563,6 @@ class ARMOperand : public MCParsedAsmOperand { public: ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} - ARMOperand(const ARMOperand &o) : MCParsedAsmOperand() { - Kind = o.Kind; - StartLoc = o.StartLoc; - EndLoc = o.EndLoc; - switch (Kind) { - case k_CondCode: - CC = o.CC; - break; - case k_ITCondMask: - ITMask = o.ITMask; - break; - case k_Token: - Tok = o.Tok; - break; - case k_CCOut: - case k_Register: - Reg = o.Reg; - break; - case k_RegisterList: - case k_DPRRegisterList: - case k_SPRRegisterList: - Registers = o.Registers; - break; - case k_VectorList: - case k_VectorListAllLanes: - case k_VectorListIndexed: - VectorList = o.VectorList; - break; - case k_CoprocNum: - case k_CoprocReg: - Cop = o.Cop; - break; - case k_CoprocOption: - CoprocOption = o.CoprocOption; - break; - case k_Immediate: - Imm = o.Imm; - break; - case k_MemBarrierOpt: - MBOpt = o.MBOpt; - break; - case k_InstSyncBarrierOpt: - ISBOpt = o.ISBOpt; - case k_Memory: - Memory = o.Memory; - break; - case k_PostIndexRegister: - PostIdxReg = o.PostIdxReg; - break; - case k_MSRMask: - MMask = o.MMask; - break; - case k_BankedReg: - BankedReg = o.BankedReg; - break; - case k_ProcIFlags: - IFlags = o.IFlags; - break; - case k_ShifterImmediate: - ShifterImm = o.ShifterImm; - break; - case k_ShiftedRegister: - RegShiftedReg = o.RegShiftedReg; - break; - case k_ShiftedImmediate: - RegShiftedImm = o.RegShiftedImm; - break; - case k_RotateImmediate: - RotImm = o.RotImm; - break; - case k_ModifiedImmediate: - ModImm = o.ModImm; - break; - case k_BitfieldDescriptor: - Bitfield = o.Bitfield; - break; - case k_VectorIndex: - VectorIndex = o.VectorIndex; - break; - } - } /// getStartLoc - Get the location of the first token of this operand. SMLoc getStartLoc() const override { return StartLoc; } @@ -1051,7 +973,7 @@ public: if (!CE) return false; int64_t Value = CE->getValue(); return (ARM_AM::getSOImmVal(Value) != -1 || - ARM_AM::getSOImmVal(-Value) != -1);; + ARM_AM::getSOImmVal(-Value) != -1); } bool isT2SOImm() const { if (!isImm()) return false; @@ -4050,7 +3972,7 @@ ARMAsmParser::parseMSRMaskOperand(OperandVector &Operands) { if (FlagsVal == ~0U) return MatchOperand_NoMatch; - if (!hasThumb2DSP() && (FlagsVal & 0x400)) + if (!hasDSP() && (FlagsVal & 0x400)) // The _g and _nzcvqg versions are only valid if the DSP extension is // available. return MatchOperand_NoMatch; @@ -4252,7 +4174,7 @@ ARMAsmParser::parseSetEndImm(OperandVector &Operands) { Error(S, "'be' or 'le' operand expected"); return MatchOperand_ParseFail; } - Operands.push_back(ARMOperand::CreateImm(MCConstantExpr::Create(Val, + Operands.push_back(ARMOperand::CreateImm(MCConstantExpr::create(Val, getContext()), S, Tok.getEndLoc())); return MatchOperand_Success; @@ -4656,7 +4578,7 @@ ARMAsmParser::parseAM3Offset(OperandVector &Operands) { Val = INT32_MIN; Operands.push_back( - ARMOperand::CreateImm(MCConstantExpr::Create(Val, getContext()), S, E)); + ARMOperand::CreateImm(MCConstantExpr::create(Val, getContext()), S, E)); return MatchOperand_Success; } @@ -4886,7 +4808,7 @@ bool ARMAsmParser::parseMemory(OperandVector &Operands) { // If the constant was #-0, represent it as INT32_MIN. int32_t Val = CE->getValue(); if (isNegative && Val == 0) - CE = MCConstantExpr::Create(INT32_MIN, getContext()); + CE = MCConstantExpr::create(INT32_MIN, getContext()); // Now we should have the closing ']' if (Parser.getTok().isNot(AsmToken::RBrac)) @@ -5073,7 +4995,7 @@ ARMAsmParser::parseFPImm(OperandVector &Operands) { IntVal ^= (uint64_t)isNegative << 31; Parser.Lex(); // Eat the token. Operands.push_back(ARMOperand::CreateImm( - MCConstantExpr::Create(IntVal, getContext()), + MCConstantExpr::create(IntVal, getContext()), S, Parser.getTok().getLoc())); return MatchOperand_Success; } @@ -5090,7 +5012,7 @@ ARMAsmParser::parseFPImm(OperandVector &Operands) { Val = APFloat(RealVal).bitcastToAPInt().getZExtValue(); Operands.push_back(ARMOperand::CreateImm( - MCConstantExpr::Create(Val, getContext()), S, + MCConstantExpr::create(Val, getContext()), S, Parser.getTok().getLoc())); return MatchOperand_Success; } @@ -5179,7 +5101,7 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { if (CE) { int32_t Val = CE->getValue(); if (isNegative && Val == 0) - ImmVal = MCConstantExpr::Create(INT32_MIN, getContext()); + ImmVal = MCConstantExpr::create(INT32_MIN, getContext()); } E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(ARMOperand::CreateImm(ImmVal, S, E)); @@ -5209,7 +5131,7 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { if (getParser().parseExpression(SubExprVal)) return true; - const MCExpr *ExprVal = ARMMCExpr::Create(RefKind, SubExprVal, + const MCExpr *ExprVal = ARMMCExpr::create(RefKind, SubExprVal, getContext()); E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(ARMOperand::CreateImm(ExprVal, S, E)); @@ -5464,6 +5386,92 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic, StringRef FullInst, CanAcceptPredicationCode = true; } +// \brief Some Thumb instructions have two operand forms that are not +// available as three operand, convert to two operand form if possible. +// +// FIXME: We would really like to be able to tablegen'erate this. +void ARMAsmParser::tryConvertingToTwoOperandForm(StringRef Mnemonic, + bool CarrySetting, + OperandVector &Operands) { + if (Operands.size() != 6) + return; + + const auto &Op3 = static_cast(*Operands[3]); + auto &Op4 = static_cast(*Operands[4]); + if (!Op3.isReg() || !Op4.isReg()) + return; + + auto Op3Reg = Op3.getReg(); + auto Op4Reg = Op4.getReg(); + + // For most Thumb2 cases we just generate the 3 operand form and reduce + // it in processInstruction(), but the 3 operand form of ADD (t2ADDrr) + // won't accept SP or PC so we do the transformation here taking care + // with immediate range in the 'add sp, sp #imm' case. + auto &Op5 = static_cast(*Operands[5]); + if (isThumbTwo()) { + if (Mnemonic != "add") + return; + bool TryTransform = Op3Reg == ARM::PC || Op4Reg == ARM::PC || + (Op5.isReg() && Op5.getReg() == ARM::PC); + if (!TryTransform) { + TryTransform = (Op3Reg == ARM::SP || Op4Reg == ARM::SP || + (Op5.isReg() && Op5.getReg() == ARM::SP)) && + !(Op3Reg == ARM::SP && Op4Reg == ARM::SP && + Op5.isImm() && !Op5.isImm0_508s4()); + } + if (!TryTransform) + return; + } else if (!isThumbOne()) + return; + + if (!(Mnemonic == "add" || Mnemonic == "sub" || Mnemonic == "and" || + Mnemonic == "eor" || Mnemonic == "lsl" || Mnemonic == "lsr" || + Mnemonic == "asr" || Mnemonic == "adc" || Mnemonic == "sbc" || + Mnemonic == "ror" || Mnemonic == "orr" || Mnemonic == "bic")) + return; + + // 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' + bool Transform = Op3Reg == Op4Reg; + + // For communtative operations, we might be able to transform if we swap + // Op4 and Op5. The 'ADD Rdm, SP, Rdm' form is already handled specially + // as tADDrsp. + const ARMOperand *LastOp = &Op5; + bool Swap = false; + if (!Transform && Op5.isReg() && Op3Reg == Op5.getReg() && + ((Mnemonic == "add" && Op4Reg != ARM::SP) || + Mnemonic == "and" || Mnemonic == "eor" || + Mnemonic == "adc" || Mnemonic == "orr")) { + Swap = true; + LastOp = &Op4; + Transform = true; + } + + // If both registers are the same then remove one of them from + // the operand list, with certain exceptions. + if (Transform) { + // Don't transform 'adds Rd, Rd, Rm' or 'sub{s} Rd, Rd, Rm' because the + // 2 operand forms don't exist. + if (((Mnemonic == "add" && CarrySetting) || Mnemonic == "sub") && + LastOp->isReg()) + Transform = false; + + // Don't transform 'add/sub{s} Rd, Rd, #imm' if the immediate fits into + // 3-bits because the ARMARM says not to. + if ((Mnemonic == "add" || Mnemonic == "sub") && LastOp->isImm0_7()) + Transform = false; + } + + if (Transform) { + if (Swap) + std::swap(Op4, Op5); + Operands.erase(Operands.begin() + 3); + } +} + bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic, OperandVector &Operands) { // FIXME: This is all horribly hacky. We really need a better way to deal @@ -5765,7 +5773,7 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, // Add the processor imod operand, if necessary. if (ProcessorIMod) { Operands.push_back(ARMOperand::CreateImm( - MCConstantExpr::Create(ProcessorIMod, getContext()), + MCConstantExpr::create(ProcessorIMod, getContext()), NameLoc, NameLoc)); } else if (Mnemonic == "cps" && isMClass()) { return Error(NameLoc, "instruction 'cps' requires effect for M-class"); @@ -5837,11 +5845,13 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, "VFP/Neon double precision register expected"); } + tryConvertingToTwoOperandForm(Mnemonic, CarrySetting, Operands); + // 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 // parse and adjust accordingly before actually matching. We shouldn't ever - // try to remove a cc_out operand that was explicitly set on the the + // try to remove a cc_out operand that was explicitly set on the // mnemonic, of course (CarrySetting == true). Reason number #317 the // table driven matcher doesn't fit well with the ARM instruction set. if (!CarrySetting && shouldOmitCCOutOperand(Mnemonic, Operands)) @@ -5900,48 +5910,6 @@ 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]); @@ -5984,8 +5952,9 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, // return 'true' if register list contains non-low GPR registers, // 'false' otherwise. If Reg is in the register list or is HiReg, set // 'containsReg' to true. -static bool checkLowRegisterList(MCInst Inst, unsigned OpNo, unsigned Reg, - unsigned HiReg, bool &containsReg) { +static bool checkLowRegisterList(const MCInst &Inst, unsigned OpNo, + unsigned Reg, unsigned HiReg, + bool &containsReg) { containsReg = false; for (unsigned i = OpNo; i < Inst.getNumOperands(); ++i) { unsigned OpReg = Inst.getOperand(i).getReg(); @@ -6000,8 +5969,8 @@ static bool checkLowRegisterList(MCInst Inst, unsigned OpNo, unsigned Reg, // Check if the specified regisgter is in the register list of the inst, // starting at the indicated operand number. -static bool listContainsReg(MCInst &Inst, unsigned OpNo, unsigned Reg) { - for (unsigned i = OpNo; i < Inst.getNumOperands(); ++i) { +static bool listContainsReg(const MCInst &Inst, unsigned OpNo, unsigned Reg) { + for (unsigned i = OpNo, e = Inst.getNumOperands(); i < e; ++i) { unsigned OpReg = Inst.getOperand(i).getReg(); if (OpReg == Reg) return true; @@ -6019,7 +5988,7 @@ static bool instIsBreakpoint(const MCInst &Inst) { } -bool ARMAsmParser::validatetLDMRegList(MCInst Inst, +bool ARMAsmParser::validatetLDMRegList(const MCInst &Inst, const OperandVector &Operands, unsigned ListNo, bool IsARPop) { const ARMOperand &Op = static_cast(*Operands[ListNo]); @@ -6042,7 +6011,7 @@ bool ARMAsmParser::validatetLDMRegList(MCInst Inst, return false; } -bool ARMAsmParser::validatetSTMRegList(MCInst Inst, +bool ARMAsmParser::validatetSTMRegList(const MCInst &Inst, const OperandVector &Operands, unsigned ListNo) { const ARMOperand &Op = static_cast(*Operands[ListNo]); @@ -6752,13 +6721,13 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, MCSymbol *Dot = getContext().createTempSymbol(); Out.EmitLabel(Dot); const MCExpr *OpExpr = Inst.getOperand(2).getExpr(); - const MCExpr *InstPC = MCSymbolRefExpr::Create(Dot, + const MCExpr *InstPC = MCSymbolRefExpr::create(Dot, MCSymbolRefExpr::VK_None, getContext()); - const MCExpr *Const8 = MCConstantExpr::Create(8, getContext()); - const MCExpr *ReadPC = MCBinaryExpr::CreateAdd(InstPC, Const8, + const MCExpr *Const8 = MCConstantExpr::create(8, getContext()); + const MCExpr *ReadPC = MCBinaryExpr::createAdd(InstPC, Const8, getContext()); - const MCExpr *FixupAddr = MCBinaryExpr::CreateAdd(ReadPC, OpExpr, + const MCExpr *FixupAddr = MCBinaryExpr::createAdd(ReadPC, OpExpr, getContext()); TmpInst.addOperand(MCOperand::createExpr(FixupAddr)); } @@ -8166,8 +8135,16 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, // If the destination and first source operand are the same, and // there's no setting of the flags, use encoding T2 instead of T3. // Note that this is only for ADD, not SUB. This mirrors the system - // 'as' behaviour. Make sure the wide encoding wasn't explicit. - if (Inst.getOperand(0).getReg() != Inst.getOperand(1).getReg() || + // 'as' behaviour. Also take advantage of ADD being commutative. + // Make sure the wide encoding wasn't explicit. + bool Swap = false; + auto DestReg = Inst.getOperand(0).getReg(); + bool Transform = DestReg == Inst.getOperand(1).getReg(); + if (!Transform && DestReg == Inst.getOperand(2).getReg()) { + Transform = true; + Swap = true; + } + if (!Transform || Inst.getOperand(5).getReg() != 0 || (static_cast(*Operands[3]).isToken() && static_cast(*Operands[3]).getToken() == ".w")) @@ -8176,7 +8153,7 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, TmpInst.setOpcode(ARM::tADDhirr); TmpInst.addOperand(Inst.getOperand(0)); TmpInst.addOperand(Inst.getOperand(0)); - TmpInst.addOperand(Inst.getOperand(2)); + TmpInst.addOperand(Inst.getOperand(Swap ? 1 : 2)); TmpInst.addOperand(Inst.getOperand(3)); TmpInst.addOperand(Inst.getOperand(4)); Inst = TmpInst; @@ -9039,7 +9016,7 @@ bool ARMAsmParser::parseDirectiveUnreq(SMLoc L) { bool ARMAsmParser::parseDirectiveArch(SMLoc L) { StringRef Arch = getParser().parseStringToEndOfStatement().trim(); - unsigned ID = ARMTargetParser::parseArch(Arch); + unsigned ID = ARM::parseArch(Arch); if (ID == ARM::AK_INVALID) { Error(L, "Unknown arch name"); @@ -9168,98 +9145,34 @@ bool ARMAsmParser::parseDirectiveCPU(SMLoc L) { StringRef CPU = getParser().parseStringToEndOfStatement().trim(); getTargetStreamer().emitTextAttribute(ARMBuildAttrs::CPU_name, CPU); + // FIXME: This is using table-gen data, but should be moved to + // ARMTargetParser once that is table-gen'd. 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); + STI.setDefaultFeatures(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 ID; - const FeatureBitset Enabled; - const FeatureBitset Disabled; -} FPUs[] = { - {/* ID */ ARM::FK_VFP, - /* Enabled */ {ARM::FeatureVFP2}, - /* Disabled */ {ARM::FeatureNEON}}, - {/* ID */ ARM::FK_VFPV2, - /* Enabled */ {ARM::FeatureVFP2}, - /* Disabled */ {ARM::FeatureNEON}}, - {/* ID */ ARM::FK_VFPV3, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3}, - /* Disabled */ {ARM::FeatureNEON, ARM::FeatureD16}}, - {/* ID */ ARM::FK_VFPV3_D16, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureD16}, - /* Disabled */ {ARM::FeatureNEON}}, - {/* ID */ ARM::FK_VFPV4, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4}, - /* Disabled */ {ARM::FeatureNEON, ARM::FeatureD16}}, - {/* ID */ ARM::FK_VFPV4_D16, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureD16}, - /* Disabled */ {ARM::FeatureNEON}}, - {/* ID */ ARM::FK_FPV5_D16, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureFPARMv8, ARM::FeatureD16}, - /* Disabled */ {ARM::FeatureNEON, ARM::FeatureCrypto}}, - {/* ID */ ARM::FK_FP_ARMV8, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureFPARMv8}, - /* Disabled */ {ARM::FeatureNEON, ARM::FeatureCrypto, ARM::FeatureD16}}, - {/* ID */ ARM::FK_NEON, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureNEON}, - /* Disabled */ {ARM::FeatureD16}}, - {/* ID */ ARM::FK_NEON_VFPV4, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureNEON}, - /* Disabled */ {ARM::FeatureD16}}, - {/* ID */ ARM::FK_NEON_FP_ARMV8, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureFPARMv8, ARM::FeatureNEON}, - /* Disabled */ {ARM::FeatureCrypto, ARM::FeatureD16}}, - {/* ID */ ARM::FK_CRYPTO_NEON_FP_ARMV8, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureFPARMv8, ARM::FeatureNEON, - ARM::FeatureCrypto}, - /* Disabled */ {ARM::FeatureD16}}, - {ARM::FK_SOFTVFP, {}, {}}, -}; - /// parseDirectiveFPU /// ::= .fpu str bool ARMAsmParser::parseDirectiveFPU(SMLoc L) { SMLoc FPUNameLoc = getTok().getLoc(); StringRef FPU = getParser().parseStringToEndOfStatement().trim(); - unsigned ID = ARMTargetParser::parseFPU(FPU); - - if (ID == ARM::FK_INVALID) { + unsigned ID = ARM::parseFPU(FPU); + std::vector Features; + if (!ARM::getFPUFeatures(ID, Features)) { Error(FPUNameLoc, "Unknown FPU name"); return false; } - 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. - FeatureBitset Toggle = (Entry.Enabled & ~STI.getFeatureBits()) | - (Entry.Disabled & STI.getFeatureBits()); - setAvailableFeatures(ComputeAvailableFeatures(STI.ToggleFeature(Toggle))); - break; - } + for (auto Feature : Features) + STI.ApplyFeatureFlag(Feature); + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); getTargetStreamer().emitFPU(ID); return false; @@ -9804,7 +9717,7 @@ bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) { } const MCSymbolRefExpr *SRE = - MCSymbolRefExpr::Create(Parser.getTok().getIdentifier(), + MCSymbolRefExpr::create(Parser.getTok().getIdentifier(), MCSymbolRefExpr::VK_ARM_TLSDESCSEQ, getContext()); Lex(); @@ -9896,7 +9809,7 @@ bool ARMAsmParser::parseDirectiveObjectArch(SMLoc L) { SMLoc ArchLoc = Parser.getTok().getLoc(); getLexer().Lex(); - unsigned ID = ARMTargetParser::parseArch(Arch); + unsigned ID = ARM::parseArch(Arch); if (ID == ARM::AK_INVALID) { Error(ArchLoc, "unknown architecture '" + Arch + "'"); @@ -9950,22 +9863,13 @@ bool ARMAsmParser::parseDirectiveThumbSet(SMLoc L) { } Lex(); + MCSymbol *Sym; 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(); + if (MCParserUtils::parseAssignmentExpression(Name, /* allow_redef */ true, + Parser, Sym, Value)) + return true; - MCSymbol *Alias = getContext().getOrCreateSymbol(Name); - getTargetStreamer().emitThumbSet(Alias, Value); + getTargetStreamer().emitThumbSet(Sym, Value); return false; } @@ -9982,33 +9886,31 @@ extern "C" void LLVMInitializeARMAsmParser() { #define GET_MATCHER_IMPLEMENTATION #include "ARMGenAsmMatcher.inc" +// FIXME: This structure should be moved inside ARMTargetParser +// when we start to table-generate them, and we can use the ARM +// flags below, that were generated by table-gen. static const struct { - const char *Name; + const unsigned Kind; const unsigned ArchCheck; const FeatureBitset Features; } Extensions[] = { - { "crc", Feature_HasV8, {ARM::FeatureCRC} }, - { "crypto", Feature_HasV8, + { ARM::AEK_CRC, Feature_HasV8, {ARM::FeatureCRC} }, + { ARM::AEK_CRYPTO, Feature_HasV8, {ARM::FeatureCrypto, ARM::FeatureNEON, ARM::FeatureFPARMv8} }, - { "fp", Feature_HasV8, {ARM::FeatureFPARMv8} }, - { "idiv", Feature_HasV7 | Feature_IsNotMClass, + { ARM::AEK_FP, Feature_HasV8, {ARM::FeatureFPARMv8} }, + { (ARM::AEK_HWDIV | ARM::AEK_HWDIVARM), Feature_HasV7 | Feature_IsNotMClass, {ARM::FeatureHWDiv, ARM::FeatureHWDivARM} }, - // FIXME: iWMMXT not supported - { "iwmmxt", Feature_None, {} }, - // FIXME: iWMMXT2 not supported - { "iwmmxt2", Feature_None, {} }, - // FIXME: Maverick not supported - { "maverick", Feature_None, {} }, - { "mp", Feature_HasV7 | Feature_IsNotMClass, {ARM::FeatureMP} }, - // FIXME: ARMv6-m OS Extensions feature not checked - { "os", Feature_None, {} }, - // FIXME: Also available in ARMv6-K - { "sec", Feature_HasV7, {ARM::FeatureTrustZone} }, - { "simd", Feature_HasV8, {ARM::FeatureNEON, ARM::FeatureFPARMv8} }, + { ARM::AEK_MP, Feature_HasV7 | Feature_IsNotMClass, {ARM::FeatureMP} }, + { ARM::AEK_SIMD, Feature_HasV8, {ARM::FeatureNEON, ARM::FeatureFPARMv8} }, + { ARM::AEK_SEC, Feature_HasV6K, {ARM::FeatureTrustZone} }, // FIXME: Only available in A-class, isel not predicated - { "virt", Feature_HasV7, {ARM::FeatureVirtualization} }, - // FIXME: xscale not supported - { "xscale", Feature_None, {} }, + { ARM::AEK_VIRT, Feature_HasV7, {ARM::FeatureVirtualization} }, + // FIXME: Unsupported extensions. + { ARM::AEK_OS, Feature_None, {} }, + { ARM::AEK_IWMMXT, Feature_None, {} }, + { ARM::AEK_IWMMXT2, Feature_None, {} }, + { ARM::AEK_MAVERICK, Feature_None, {} }, + { ARM::AEK_XSCALE, Feature_None, {} }, }; /// parseDirectiveArchExtension @@ -10031,9 +9933,12 @@ bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) { EnableFeature = false; Name = Name.substr(2); } + unsigned FeatureKind = ARM::parseArchExt(Name); + if (FeatureKind == ARM::AEK_INVALID) + Error(ExtLoc, "unknown architectural extension: " + Name); for (const auto &Extension : Extensions) { - if (Extension.Name != Name) + if (Extension.Kind != FeatureKind) continue; if (Extension.Features.none()) @@ -10080,7 +9985,7 @@ unsigned ARMAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, if (Op.isImm()) { const MCExpr *SOExpr = Op.getImm(); int64_t Value; - if (!SOExpr->EvaluateAsAbsolute(Value)) + if (!SOExpr->evaluateAsAbsolute(Value)) return Match_Success; assert((Value >= INT32_MIN && Value <= UINT32_MAX) && "expression value must be representable in 32 bits");