diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp | 596 |
1 files changed, 559 insertions, 37 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/contrib/llvm-project/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index e72ae0e62cb7..96c50ff3f8d0 100644 --- a/contrib/llvm-project/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/contrib/llvm-project/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/AArch64AddressingModes.h" +#include "MCTargetDesc/AArch64InstPrinter.h" #include "MCTargetDesc/AArch64MCExpr.h" #include "MCTargetDesc/AArch64MCTargetDesc.h" #include "MCTargetDesc/AArch64TargetStreamer.h" @@ -158,8 +159,13 @@ private: bool parseSymbolicImmVal(const MCExpr *&ImmVal); bool parseNeonVectorList(OperandVector &Operands); bool parseOptionalMulOperand(OperandVector &Operands); + bool parseKeywordOperand(OperandVector &Operands); bool parseOperand(OperandVector &Operands, bool isCondCode, bool invertCondCode); + bool parseImmExpr(int64_t &Out); + bool parseComma(); + bool parseRegisterInRange(unsigned &Out, unsigned Base, unsigned First, + unsigned Last); bool showMatchError(SMLoc Loc, unsigned ErrCode, uint64_t ErrorInfo, OperandVector &Operands); @@ -181,6 +187,31 @@ private: bool parseDirectiveVariantPCS(SMLoc L); + bool parseDirectiveSEHAllocStack(SMLoc L); + bool parseDirectiveSEHPrologEnd(SMLoc L); + bool parseDirectiveSEHSaveR19R20X(SMLoc L); + bool parseDirectiveSEHSaveFPLR(SMLoc L); + bool parseDirectiveSEHSaveFPLRX(SMLoc L); + bool parseDirectiveSEHSaveReg(SMLoc L); + bool parseDirectiveSEHSaveRegX(SMLoc L); + bool parseDirectiveSEHSaveRegP(SMLoc L); + bool parseDirectiveSEHSaveRegPX(SMLoc L); + bool parseDirectiveSEHSaveLRPair(SMLoc L); + bool parseDirectiveSEHSaveFReg(SMLoc L); + bool parseDirectiveSEHSaveFRegX(SMLoc L); + bool parseDirectiveSEHSaveFRegP(SMLoc L); + bool parseDirectiveSEHSaveFRegPX(SMLoc L); + bool parseDirectiveSEHSetFP(SMLoc L); + bool parseDirectiveSEHAddFP(SMLoc L); + bool parseDirectiveSEHNop(SMLoc L); + bool parseDirectiveSEHSaveNext(SMLoc L); + bool parseDirectiveSEHEpilogStart(SMLoc L); + bool parseDirectiveSEHEpilogEnd(SMLoc L); + bool parseDirectiveSEHTrapFrame(SMLoc L); + bool parseDirectiveSEHMachineFrame(SMLoc L); + bool parseDirectiveSEHContext(SMLoc L); + bool parseDirectiveSEHClearUnwoundToCall(SMLoc L); + bool validateInstruction(MCInst &Inst, SMLoc &IDLoc, SmallVectorImpl<SMLoc> &Loc); bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, @@ -200,6 +231,7 @@ private: RegKind MatchKind); OperandMatchResultTy tryParseOptionalShiftExtend(OperandVector &Operands); OperandMatchResultTy tryParseBarrierOperand(OperandVector &Operands); + OperandMatchResultTy tryParseBarriernXSOperand(OperandVector &Operands); OperandMatchResultTy tryParseMRSSystemRegister(OperandVector &Operands); OperandMatchResultTy tryParseSysReg(OperandVector &Operands); OperandMatchResultTy tryParseSysCROperand(OperandVector &Operands); @@ -226,6 +258,7 @@ private: OperandMatchResultTy tryParseVectorList(OperandVector &Operands, bool ExpectMatch = false); OperandMatchResultTy tryParseSVEPattern(OperandVector &Operands); + OperandMatchResultTy tryParseGPR64x8(OperandVector &Operands); public: enum AArch64MatchResultTy { @@ -238,7 +271,7 @@ public: AArch64AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) : MCTargetAsmParser(Options, STI, MII) { - IsILP32 = Options.getABIName() == "ilp32"; + IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32; MCAsmParserExtension::Initialize(Parser); MCStreamer &S = getParser().getStreamer(); if (S.getTargetStreamer() == nullptr) @@ -371,6 +404,7 @@ private: const char *Data; unsigned Length; unsigned Val; // Not the enum since not all values have names. + bool HasnXSModifier; }; struct SysRegOp { @@ -540,6 +574,11 @@ public: return StringRef(Barrier.Data, Barrier.Length); } + bool getBarriernXSModifier() const { + assert(Kind == k_Barrier && "Invalid access!"); + return Barrier.HasnXSModifier; + } + unsigned getReg() const override { assert(Kind == k_Register && "Invalid access!"); return Reg.RegNum; @@ -711,7 +750,8 @@ public: ELFRefKind == AArch64MCExpr::VK_GOTTPREL_LO12_NC || ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 || ELFRefKind == AArch64MCExpr::VK_SECREL_LO12 || - ELFRefKind == AArch64MCExpr::VK_SECREL_HI12) { + ELFRefKind == AArch64MCExpr::VK_SECREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_GOT_PAGE_LO15) { // Note that we don't range-check the addend. It's adjusted modulo page // size when converted, so there is no "out of range" condition when using // @pageoff. @@ -857,7 +897,8 @@ public: if (!isShiftedImm() && (!isImm() || !isa<MCConstantExpr>(getImm()))) return DiagnosticPredicateTy::NoMatch; - bool IsByte = std::is_same<int8_t, std::make_signed_t<T>>::value; + bool IsByte = std::is_same<int8_t, std::make_signed_t<T>>::value || + std::is_same<int8_t, T>::value; if (auto ShiftedImm = getShiftedVal<8>()) if (!(IsByte && ShiftedImm->second) && AArch64_AM::isSVECpyImm<T>(uint64_t(ShiftedImm->first) @@ -874,7 +915,8 @@ public: if (!isShiftedImm() && (!isImm() || !isa<MCConstantExpr>(getImm()))) return DiagnosticPredicateTy::NoMatch; - bool IsByte = std::is_same<int8_t, std::make_signed_t<T>>::value; + bool IsByte = std::is_same<int8_t, std::make_signed_t<T>>::value || + std::is_same<int8_t, T>::value; if (auto ShiftedImm = getShiftedVal<8>()) if (!(IsByte && ShiftedImm->second) && AArch64_AM::isSVEAddSubImm<T>(ShiftedImm->first @@ -999,7 +1041,12 @@ public: AArch64_AM::getFP64Imm(getFPImm().bitcastToAPInt()) != -1; } - bool isBarrier() const { return Kind == k_Barrier; } + bool isBarrier() const { + return Kind == k_Barrier && !getBarriernXSModifier(); + } + bool isBarriernXS() const { + return Kind == k_Barrier && getBarriernXSModifier(); + } bool isSysReg() const { return Kind == k_SysReg; } bool isMRSSystemRegister() const { @@ -1126,6 +1173,12 @@ public: AArch64MCRegisterClasses[AArch64::GPR32RegClassID].contains(Reg.RegNum); } + bool isGPR64x8() const { + return Kind == k_Register && Reg.Kind == RegKind::Scalar && + AArch64MCRegisterClasses[AArch64::GPR64x8ClassRegClassID].contains( + Reg.RegNum); + } + bool isWSeqPair() const { return Kind == k_Register && Reg.Kind == RegKind::Scalar && AArch64MCRegisterClasses[AArch64::WSeqPairsClassRegClassID].contains( @@ -1689,6 +1742,11 @@ public: Inst.addOperand(MCOperand::createImm(getBarrier())); } + void addBarriernXSOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(getBarrier())); + } + void addMRSSystemRegisterOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); @@ -1924,11 +1982,13 @@ public: static std::unique_ptr<AArch64Operand> CreateBarrier(unsigned Val, StringRef Str, SMLoc S, - MCContext &Ctx) { + MCContext &Ctx, + bool HasnXSModifier) { auto Op = std::make_unique<AArch64Operand>(k_Barrier, Ctx); Op->Barrier.Val = Val; Op->Barrier.Data = Str.data(); Op->Barrier.Length = Str.size(); + Op->Barrier.HasnXSModifier = HasnXSModifier; Op->StartLoc = S; Op->EndLoc = S; return Op; @@ -2073,14 +2133,14 @@ void AArch64Operand::print(raw_ostream &OS) const { case k_PSBHint: OS << getPSBHintName(); break; + case k_BTIHint: + OS << getBTIHintName(); + break; case k_Register: OS << "<register " << getReg() << ">"; if (!getShiftExtendAmount() && !hasShiftExtendAmount()) break; LLVM_FALLTHROUGH; - case k_BTIHint: - OS << getBTIHintName(); - break; case k_ShiftExtend: OS << "<" << AArch64_AM::getShiftExtendName(getShiftExtendType()) << " #" << getShiftExtendAmount(); @@ -2510,6 +2570,7 @@ AArch64AsmParser::tryParseAdrpLabel(OperandVector &Operands) { DarwinRefKind != MCSymbolRefExpr::VK_TLVPPAGE && ELFRefKind != AArch64MCExpr::VK_ABS_PAGE_NC && ELFRefKind != AArch64MCExpr::VK_GOT_PAGE && + ELFRefKind != AArch64MCExpr::VK_GOT_PAGE_LO15 && ELFRefKind != AArch64MCExpr::VK_GOTTPREL_PAGE && ELFRefKind != AArch64MCExpr::VK_TLSDESC_PAGE) { // The operand must be an @page or @gotpage qualified symbolref. @@ -2843,6 +2904,7 @@ static const struct Extension { {"predres", {AArch64::FeaturePredRes}}, {"ccdp", {AArch64::FeatureCacheDeepPersist}}, {"mte", {AArch64::FeatureMTE}}, + {"memtag", {AArch64::FeatureMTE}}, {"tlb-rmi", {AArch64::FeatureTLB_RMI}}, {"pan-rwv", {AArch64::FeaturePAN_RWV}}, {"ccpp", {AArch64::FeatureCCPP}}, @@ -2853,6 +2915,10 @@ static const struct Extension { {"sve2-sm4", {AArch64::FeatureSVE2SM4}}, {"sve2-sha3", {AArch64::FeatureSVE2SHA3}}, {"sve2-bitperm", {AArch64::FeatureSVE2BitPerm}}, + {"ls64", {AArch64::FeatureLS64}}, + {"xs", {AArch64::FeatureXS}}, + {"pauth", {AArch64::FeaturePAuth}}, + {"flagm", {AArch64::FeatureFlagM}}, // FIXME: Unsupported extensions {"pan", {}}, {"lor", {}}, @@ -2873,15 +2939,16 @@ static void setRequiredFeatureString(FeatureBitset FBS, std::string &Str) { Str += "ARMv8.5a"; else if (FBS[AArch64::HasV8_6aOps]) Str += "ARMv8.6a"; + else if (FBS[AArch64::HasV8_7aOps]) + Str += "ARMv8.7a"; else { - auto ext = std::find_if(std::begin(ExtensionMap), - std::end(ExtensionMap), - [&](const Extension& e) + SmallVector<std::string, 2> ExtMatches; + for (const auto& Ext : ExtensionMap) { // Use & in case multiple features are enabled - { return (FBS & e.Features) != FeatureBitset(); } - ); - - Str += ext != std::end(ExtensionMap) ? ext->Name : "(unknown)"; + if ((FBS & Ext.Features) != FeatureBitset()) + ExtMatches.push_back(Ext.Name); + } + Str += !ExtMatches.empty() ? llvm::join(ExtMatches, ", ") : "(unknown)"; } } @@ -2926,7 +2993,7 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc, if (!IC) return TokError("invalid operand for IC instruction"); else if (!IC->haveFeatures(getSTI().getFeatureBits())) { - std::string Str("IC " + std::string(IC->Name) + " requires "); + std::string Str("IC " + std::string(IC->Name) + " requires: "); setRequiredFeatureString(IC->getRequiredFeatures(), Str); return TokError(Str.c_str()); } @@ -2936,7 +3003,7 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc, if (!DC) return TokError("invalid operand for DC instruction"); else if (!DC->haveFeatures(getSTI().getFeatureBits())) { - std::string Str("DC " + std::string(DC->Name) + " requires "); + std::string Str("DC " + std::string(DC->Name) + " requires: "); setRequiredFeatureString(DC->getRequiredFeatures(), Str); return TokError(Str.c_str()); } @@ -2946,7 +3013,7 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc, if (!AT) return TokError("invalid operand for AT instruction"); else if (!AT->haveFeatures(getSTI().getFeatureBits())) { - std::string Str("AT " + std::string(AT->Name) + " requires "); + std::string Str("AT " + std::string(AT->Name) + " requires: "); setRequiredFeatureString(AT->getRequiredFeatures(), Str); return TokError(Str.c_str()); } @@ -2956,7 +3023,7 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc, if (!TLBI) return TokError("invalid operand for TLBI instruction"); else if (!TLBI->haveFeatures(getSTI().getFeatureBits())) { - std::string Str("TLBI " + std::string(TLBI->Name) + " requires "); + std::string Str("TLBI " + std::string(TLBI->Name) + " requires: "); setRequiredFeatureString(TLBI->getRequiredFeatures(), Str); return TokError(Str.c_str()); } @@ -2967,7 +3034,7 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc, return TokError("invalid operand for prediction restriction instruction"); else if (!PRCTX->haveFeatures(getSTI().getFeatureBits())) { std::string Str( - Mnemonic.upper() + std::string(PRCTX->Name) + " requires "); + Mnemonic.upper() + std::string(PRCTX->Name) + " requires: "); setRequiredFeatureString(PRCTX->getRequiredFeatures(), Str); return TokError(Str.c_str()); } @@ -3011,11 +3078,11 @@ AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) { if (Mnemonic == "tsb" && Tok.isNot(AsmToken::Identifier)) { TokError("'csync' operand expected"); return MatchOperand_ParseFail; - // Can be either a #imm style literal or an option name } else if (parseOptionalToken(AsmToken::Hash) || Tok.is(AsmToken::Integer)) { // Immediate operand. const MCExpr *ImmVal; SMLoc ExprLoc = getLoc(); + AsmToken IntTok = Tok; if (getParser().parseExpression(ImmVal)) return MatchOperand_ParseFail; const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal); @@ -3023,13 +3090,22 @@ AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) { Error(ExprLoc, "immediate value expected for barrier operand"); return MatchOperand_ParseFail; } - if (MCE->getValue() < 0 || MCE->getValue() > 15) { + int64_t Value = MCE->getValue(); + if (Mnemonic == "dsb" && Value > 15) { + // This case is a no match here, but it might be matched by the nXS + // variant. Deliberately not unlex the optional '#' as it is not necessary + // to characterize an integer immediate. + Parser.getLexer().UnLex(IntTok); + return MatchOperand_NoMatch; + } + if (Value < 0 || Value > 15) { Error(ExprLoc, "barrier operand out of range"); return MatchOperand_ParseFail; } - auto DB = AArch64DB::lookupDBByEncoding(MCE->getValue()); - Operands.push_back(AArch64Operand::CreateBarrier( - MCE->getValue(), DB ? DB->Name : "", ExprLoc, getContext())); + auto DB = AArch64DB::lookupDBByEncoding(Value); + Operands.push_back(AArch64Operand::CreateBarrier(Value, DB ? DB->Name : "", + ExprLoc, getContext(), + false /*hasnXSModifier*/)); return MatchOperand_Success; } @@ -3038,9 +3114,10 @@ AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) { return MatchOperand_ParseFail; } - auto TSB = AArch64TSB::lookupTSBByName(Tok.getString()); + StringRef Operand = Tok.getString(); + auto TSB = AArch64TSB::lookupTSBByName(Operand); + auto DB = AArch64DB::lookupDBByName(Operand); // The only valid named option for ISB is 'sy' - auto DB = AArch64DB::lookupDBByName(Tok.getString()); if (Mnemonic == "isb" && (!DB || DB->Encoding != AArch64DB::sy)) { TokError("'sy' or #imm operand expected"); return MatchOperand_ParseFail; @@ -3049,12 +3126,73 @@ AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) { TokError("'csync' operand expected"); return MatchOperand_ParseFail; } else if (!DB && !TSB) { + if (Mnemonic == "dsb") { + // This case is a no match here, but it might be matched by the nXS + // variant. + return MatchOperand_NoMatch; + } TokError("invalid barrier option name"); return MatchOperand_ParseFail; } Operands.push_back(AArch64Operand::CreateBarrier( - DB ? DB->Encoding : TSB->Encoding, Tok.getString(), getLoc(), getContext())); + DB ? DB->Encoding : TSB->Encoding, Tok.getString(), getLoc(), + getContext(), false /*hasnXSModifier*/)); + Parser.Lex(); // Consume the option + + return MatchOperand_Success; +} + +OperandMatchResultTy +AArch64AsmParser::tryParseBarriernXSOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + const AsmToken &Tok = Parser.getTok(); + + assert(Mnemonic == "dsb" && "Instruction does not accept nXS operands"); + if (Mnemonic != "dsb") + return MatchOperand_ParseFail; + + if (parseOptionalToken(AsmToken::Hash) || Tok.is(AsmToken::Integer)) { + // Immediate operand. + const MCExpr *ImmVal; + SMLoc ExprLoc = getLoc(); + if (getParser().parseExpression(ImmVal)) + return MatchOperand_ParseFail; + const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal); + if (!MCE) { + Error(ExprLoc, "immediate value expected for barrier operand"); + return MatchOperand_ParseFail; + } + int64_t Value = MCE->getValue(); + // v8.7-A DSB in the nXS variant accepts only the following immediate + // values: 16, 20, 24, 28. + if (Value != 16 && Value != 20 && Value != 24 && Value != 28) { + Error(ExprLoc, "barrier operand out of range"); + return MatchOperand_ParseFail; + } + auto DB = AArch64DBnXS::lookupDBnXSByImmValue(Value); + Operands.push_back(AArch64Operand::CreateBarrier(DB->Encoding, DB->Name, + ExprLoc, getContext(), + true /*hasnXSModifier*/)); + return MatchOperand_Success; + } + + if (Tok.isNot(AsmToken::Identifier)) { + TokError("invalid operand for instruction"); + return MatchOperand_ParseFail; + } + + StringRef Operand = Tok.getString(); + auto DB = AArch64DBnXS::lookupDBnXSByName(Operand); + + if (!DB) { + TokError("invalid barrier option name"); + return MatchOperand_ParseFail; + } + + Operands.push_back( + AArch64Operand::CreateBarrier(DB->Encoding, Tok.getString(), getLoc(), + getContext(), true /*hasnXSModifier*/)); Parser.Lex(); // Consume the option return MatchOperand_Success; @@ -3300,6 +3438,7 @@ bool AArch64AsmParser::parseSymbolicImmVal(const MCExpr *&ImmVal) { .Case("tprel_lo12_nc", AArch64MCExpr::VK_TPREL_LO12_NC) .Case("tlsdesc_lo12", AArch64MCExpr::VK_TLSDESC_LO12) .Case("got", AArch64MCExpr::VK_GOT_PAGE) + .Case("gotpage_lo15", AArch64MCExpr::VK_GOT_PAGE_LO15) .Case("got_lo12", AArch64MCExpr::VK_GOT_LO12) .Case("gottprel", AArch64MCExpr::VK_GOTTPREL_PAGE) .Case("gottprel_lo12", AArch64MCExpr::VK_GOTTPREL_LO12_NC) @@ -3568,6 +3707,17 @@ bool AArch64AsmParser::parseOptionalMulOperand(OperandVector &Operands) { return Error(getLoc(), "expected 'vl' or '#<imm>'"); } +bool AArch64AsmParser::parseKeywordOperand(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + auto Tok = Parser.getTok(); + if (Tok.isNot(AsmToken::Identifier)) + return true; + Operands.push_back(AArch64Operand::CreateToken(Tok.getString(), false, + Tok.getLoc(), getContext())); + Parser.Lex(); + return false; +} + /// parseOperand - Parse a arm instruction operand. For now this parses the /// operand regardless of the mnemonic. bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode, @@ -3632,6 +3782,11 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode, if (GotShift != MatchOperand_NoMatch) return GotShift; + // If this is a two-word mnemonic, parse its special keyword + // operand as an identifier. + if (Mnemonic == "brb") + return parseKeywordOperand(Operands); + // This was not a register so parse other operands that start with an // identifier (like labels) as expressions and create them as immediates. const MCExpr *IdVal; @@ -3740,6 +3895,66 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode, } } +bool AArch64AsmParser::parseImmExpr(int64_t &Out) { + const MCExpr *Expr = nullptr; + SMLoc L = getLoc(); + if (check(getParser().parseExpression(Expr), L, "expected expression")) + return true; + const MCConstantExpr *Value = dyn_cast_or_null<MCConstantExpr>(Expr); + if (check(!Value, L, "expected constant expression")) + return true; + Out = Value->getValue(); + return false; +} + +bool AArch64AsmParser::parseComma() { + if (check(getParser().getTok().isNot(AsmToken::Comma), getLoc(), + "expected comma")) + return true; + // Eat the comma + getParser().Lex(); + return false; +} + +bool AArch64AsmParser::parseRegisterInRange(unsigned &Out, unsigned Base, + unsigned First, unsigned Last) { + unsigned Reg; + SMLoc Start, End; + if (check(ParseRegister(Reg, Start, End), getLoc(), "expected register")) + return true; + + // Special handling for FP and LR; they aren't linearly after x28 in + // the registers enum. + unsigned RangeEnd = Last; + if (Base == AArch64::X0) { + if (Last == AArch64::FP) { + RangeEnd = AArch64::X28; + if (Reg == AArch64::FP) { + Out = 29; + return false; + } + } + if (Last == AArch64::LR) { + RangeEnd = AArch64::X28; + if (Reg == AArch64::FP) { + Out = 29; + return false; + } else if (Reg == AArch64::LR) { + Out = 30; + return false; + } + } + } + + if (check(Reg < First || Reg > RangeEnd, Start, + Twine("expected register in range ") + + AArch64InstPrinter::getRegisterName(First) + " to " + + AArch64InstPrinter::getRegisterName(Last))) + return true; + Out = Reg - Base; + return false; +} + bool AArch64AsmParser::regsEqual(const MCParsedAsmOperand &Op1, const MCParsedAsmOperand &Op2) const { auto &AOp1 = static_cast<const AArch64Operand&>(Op1); @@ -5058,6 +5273,7 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) { const MCObjectFileInfo::Environment Format = getContext().getObjectFileInfo()->getObjectFileType(); bool IsMachO = Format == MCObjectFileInfo::IsMachO; + bool IsCOFF = Format == MCObjectFileInfo::IsCOFF; auto IDVal = DirectiveID.getIdentifier().lower(); SMLoc Loc = DirectiveID.getLoc(); @@ -5086,6 +5302,57 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) { parseDirectiveLOH(IDVal, Loc); else return true; + } else if (IsCOFF) { + if (IDVal == ".seh_stackalloc") + parseDirectiveSEHAllocStack(Loc); + else if (IDVal == ".seh_endprologue") + parseDirectiveSEHPrologEnd(Loc); + else if (IDVal == ".seh_save_r19r20_x") + parseDirectiveSEHSaveR19R20X(Loc); + else if (IDVal == ".seh_save_fplr") + parseDirectiveSEHSaveFPLR(Loc); + else if (IDVal == ".seh_save_fplr_x") + parseDirectiveSEHSaveFPLRX(Loc); + else if (IDVal == ".seh_save_reg") + parseDirectiveSEHSaveReg(Loc); + else if (IDVal == ".seh_save_reg_x") + parseDirectiveSEHSaveRegX(Loc); + else if (IDVal == ".seh_save_regp") + parseDirectiveSEHSaveRegP(Loc); + else if (IDVal == ".seh_save_regp_x") + parseDirectiveSEHSaveRegPX(Loc); + else if (IDVal == ".seh_save_lrpair") + parseDirectiveSEHSaveLRPair(Loc); + else if (IDVal == ".seh_save_freg") + parseDirectiveSEHSaveFReg(Loc); + else if (IDVal == ".seh_save_freg_x") + parseDirectiveSEHSaveFRegX(Loc); + else if (IDVal == ".seh_save_fregp") + parseDirectiveSEHSaveFRegP(Loc); + else if (IDVal == ".seh_save_fregp_x") + parseDirectiveSEHSaveFRegPX(Loc); + else if (IDVal == ".seh_set_fp") + parseDirectiveSEHSetFP(Loc); + else if (IDVal == ".seh_add_fp") + parseDirectiveSEHAddFP(Loc); + else if (IDVal == ".seh_nop") + parseDirectiveSEHNop(Loc); + else if (IDVal == ".seh_save_next") + parseDirectiveSEHSaveNext(Loc); + else if (IDVal == ".seh_startepilogue") + parseDirectiveSEHEpilogStart(Loc); + else if (IDVal == ".seh_endepilogue") + parseDirectiveSEHEpilogEnd(Loc); + else if (IDVal == ".seh_trap_frame") + parseDirectiveSEHTrapFrame(Loc); + else if (IDVal == ".seh_pushframe") + parseDirectiveSEHMachineFrame(Loc); + else if (IDVal == ".seh_context") + parseDirectiveSEHContext(Loc); + else if (IDVal == ".seh_clear_unwound_to_call") + parseDirectiveSEHClearUnwoundToCall(Loc); + else + return true; } else return true; return false; @@ -5093,12 +5360,8 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) { static void ExpandCryptoAEK(AArch64::ArchKind ArchKind, SmallVector<StringRef, 4> &RequestedExtensions) { - const bool NoCrypto = - (std::find(RequestedExtensions.begin(), RequestedExtensions.end(), - "nocrypto") != std::end(RequestedExtensions)); - const bool Crypto = - (std::find(RequestedExtensions.begin(), RequestedExtensions.end(), - "crypto") != std::end(RequestedExtensions)); + const bool NoCrypto = llvm::is_contained(RequestedExtensions, "nocrypto"); + const bool Crypto = llvm::is_contained(RequestedExtensions, "crypto"); if (!NoCrypto && Crypto) { switch (ArchKind) { @@ -5114,6 +5377,8 @@ static void ExpandCryptoAEK(AArch64::ArchKind ArchKind, case AArch64::ArchKind::ARMV8_4A: case AArch64::ArchKind::ARMV8_5A: case AArch64::ArchKind::ARMV8_6A: + case AArch64::ArchKind::ARMV8_7A: + case AArch64::ArchKind::ARMV8R: RequestedExtensions.push_back("sm4"); RequestedExtensions.push_back("sha3"); RequestedExtensions.push_back("sha2"); @@ -5134,6 +5399,7 @@ static void ExpandCryptoAEK(AArch64::ArchKind ArchKind, case AArch64::ArchKind::ARMV8_4A: case AArch64::ArchKind::ARMV8_5A: case AArch64::ArchKind::ARMV8_6A: + case AArch64::ArchKind::ARMV8_7A: RequestedExtensions.push_back("nosm4"); RequestedExtensions.push_back("nosha3"); RequestedExtensions.push_back("nosha2"); @@ -5167,7 +5433,8 @@ bool AArch64AsmParser::parseDirectiveArch(SMLoc L) { MCSubtargetInfo &STI = copySTI(); std::vector<std::string> ArchFeatures(AArch64Features.begin(), AArch64Features.end()); - STI.setDefaultFeatures("generic", join(ArchFeatures.begin(), ArchFeatures.end(), ",")); + STI.setDefaultFeatures("generic", /*TuneCPU*/ "generic", + join(ArchFeatures.begin(), ArchFeatures.end(), ",")); SmallVector<StringRef, 4> RequestedExtensions; if (!ExtensionString.empty()) @@ -5269,7 +5536,7 @@ bool AArch64AsmParser::parseDirectiveCPU(SMLoc L) { } MCSubtargetInfo &STI = copySTI(); - STI.setDefaultFeatures(CPU, ""); + STI.setDefaultFeatures(CPU, /*TuneCPU*/ CPU, ""); CurLoc = incrementLoc(CurLoc, CPU.size()); ExpandCryptoAEK(llvm::AArch64::getCPUArchKind(CPU), RequestedExtensions); @@ -5537,6 +5804,238 @@ bool AArch64AsmParser::parseDirectiveVariantPCS(SMLoc L) { return false; } +/// parseDirectiveSEHAllocStack +/// ::= .seh_stackalloc +bool AArch64AsmParser::parseDirectiveSEHAllocStack(SMLoc L) { + int64_t Size; + if (parseImmExpr(Size)) + return true; + getTargetStreamer().EmitARM64WinCFIAllocStack(Size); + return false; +} + +/// parseDirectiveSEHPrologEnd +/// ::= .seh_endprologue +bool AArch64AsmParser::parseDirectiveSEHPrologEnd(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIPrologEnd(); + return false; +} + +/// parseDirectiveSEHSaveR19R20X +/// ::= .seh_save_r19r20_x +bool AArch64AsmParser::parseDirectiveSEHSaveR19R20X(SMLoc L) { + int64_t Offset; + if (parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveR19R20X(Offset); + return false; +} + +/// parseDirectiveSEHSaveFPLR +/// ::= .seh_save_fplr +bool AArch64AsmParser::parseDirectiveSEHSaveFPLR(SMLoc L) { + int64_t Offset; + if (parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFPLR(Offset); + return false; +} + +/// parseDirectiveSEHSaveFPLRX +/// ::= .seh_save_fplr_x +bool AArch64AsmParser::parseDirectiveSEHSaveFPLRX(SMLoc L) { + int64_t Offset; + if (parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFPLRX(Offset); + return false; +} + +/// parseDirectiveSEHSaveReg +/// ::= .seh_save_reg +bool AArch64AsmParser::parseDirectiveSEHSaveReg(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::LR) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveReg(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveRegX +/// ::= .seh_save_reg_x +bool AArch64AsmParser::parseDirectiveSEHSaveRegX(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::LR) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveRegX(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveRegP +/// ::= .seh_save_regp +bool AArch64AsmParser::parseDirectiveSEHSaveRegP(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::FP) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveRegP(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveRegPX +/// ::= .seh_save_regp_x +bool AArch64AsmParser::parseDirectiveSEHSaveRegPX(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::FP) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveRegPX(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveLRPair +/// ::= .seh_save_lrpair +bool AArch64AsmParser::parseDirectiveSEHSaveLRPair(SMLoc L) { + unsigned Reg; + int64_t Offset; + L = getLoc(); + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::LR) || + parseComma() || parseImmExpr(Offset)) + return true; + if (check(((Reg - 19) % 2 != 0), L, + "expected register with even offset from x19")) + return true; + getTargetStreamer().EmitARM64WinCFISaveLRPair(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveFReg +/// ::= .seh_save_freg +bool AArch64AsmParser::parseDirectiveSEHSaveFReg(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::D0, AArch64::D8, AArch64::D15) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFReg(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveFRegX +/// ::= .seh_save_freg_x +bool AArch64AsmParser::parseDirectiveSEHSaveFRegX(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::D0, AArch64::D8, AArch64::D15) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFRegX(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveFRegP +/// ::= .seh_save_fregp +bool AArch64AsmParser::parseDirectiveSEHSaveFRegP(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::D0, AArch64::D8, AArch64::D14) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFRegP(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveFRegPX +/// ::= .seh_save_fregp_x +bool AArch64AsmParser::parseDirectiveSEHSaveFRegPX(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::D0, AArch64::D8, AArch64::D14) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFRegPX(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSetFP +/// ::= .seh_set_fp +bool AArch64AsmParser::parseDirectiveSEHSetFP(SMLoc L) { + getTargetStreamer().EmitARM64WinCFISetFP(); + return false; +} + +/// parseDirectiveSEHAddFP +/// ::= .seh_add_fp +bool AArch64AsmParser::parseDirectiveSEHAddFP(SMLoc L) { + int64_t Size; + if (parseImmExpr(Size)) + return true; + getTargetStreamer().EmitARM64WinCFIAddFP(Size); + return false; +} + +/// parseDirectiveSEHNop +/// ::= .seh_nop +bool AArch64AsmParser::parseDirectiveSEHNop(SMLoc L) { + getTargetStreamer().EmitARM64WinCFINop(); + return false; +} + +/// parseDirectiveSEHSaveNext +/// ::= .seh_save_next +bool AArch64AsmParser::parseDirectiveSEHSaveNext(SMLoc L) { + getTargetStreamer().EmitARM64WinCFISaveNext(); + return false; +} + +/// parseDirectiveSEHEpilogStart +/// ::= .seh_startepilogue +bool AArch64AsmParser::parseDirectiveSEHEpilogStart(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIEpilogStart(); + return false; +} + +/// parseDirectiveSEHEpilogEnd +/// ::= .seh_endepilogue +bool AArch64AsmParser::parseDirectiveSEHEpilogEnd(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIEpilogEnd(); + return false; +} + +/// parseDirectiveSEHTrapFrame +/// ::= .seh_trap_frame +bool AArch64AsmParser::parseDirectiveSEHTrapFrame(SMLoc L) { + getTargetStreamer().EmitARM64WinCFITrapFrame(); + return false; +} + +/// parseDirectiveSEHMachineFrame +/// ::= .seh_pushframe +bool AArch64AsmParser::parseDirectiveSEHMachineFrame(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIMachineFrame(); + return false; +} + +/// parseDirectiveSEHContext +/// ::= .seh_context +bool AArch64AsmParser::parseDirectiveSEHContext(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIContext(); + return false; +} + +/// parseDirectiveSEHClearUnwoundToCall +/// ::= .seh_clear_unwound_to_call +bool AArch64AsmParser::parseDirectiveSEHClearUnwoundToCall(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIClearUnwoundToCall(); + return false; +} + bool AArch64AsmParser::classifySymbolRef(const MCExpr *Expr, AArch64MCExpr::VariantKind &ELFRefKind, @@ -5824,3 +6323,26 @@ AArch64AsmParser::tryParseSVEPattern(OperandVector &Operands) { return MatchOperand_Success; } + +OperandMatchResultTy +AArch64AsmParser::tryParseGPR64x8(OperandVector &Operands) { + SMLoc SS = getLoc(); + + unsigned XReg; + if (tryParseScalarRegister(XReg) != MatchOperand_Success) + return MatchOperand_NoMatch; + + MCContext &ctx = getContext(); + const MCRegisterInfo *RI = ctx.getRegisterInfo(); + int X8Reg = RI->getMatchingSuperReg( + XReg, AArch64::x8sub_0, + &AArch64MCRegisterClasses[AArch64::GPR64x8ClassRegClassID]); + if (!X8Reg) { + Error(SS, "expected an even-numbered x-register in the range [x0,x22]"); + return MatchOperand_ParseFail; + } + + Operands.push_back( + AArch64Operand::CreateReg(X8Reg, RegKind::Scalar, SS, getLoc(), ctx)); + return MatchOperand_Success; +} |