aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/lib/Target/AArch64/AsmParser
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:44:49 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:49 +0300
commit718c552901d703c502ccbefdfc3c9028d608b947 (patch)
tree46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/libs/llvm12/lib/Target/AArch64/AsmParser
parente9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff)
downloadydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Target/AArch64/AsmParser')
-rw-r--r--contrib/libs/llvm12/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp11578
-rw-r--r--contrib/libs/llvm12/lib/Target/AArch64/AsmParser/ya.make40
2 files changed, 5809 insertions, 5809 deletions
diff --git a/contrib/libs/llvm12/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/contrib/libs/llvm12/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 96c50ff3f8..84276b9e5f 100644
--- a/contrib/libs/llvm12/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/contrib/libs/llvm12/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1,192 +1,192 @@
-//==- AArch64AsmParser.cpp - Parse AArch64 assembly to MCInst instructions -==//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "MCTargetDesc/AArch64AddressingModes.h"
+//==- AArch64AsmParser.cpp - Parse AArch64 assembly to MCInst instructions -==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/AArch64AddressingModes.h"
#include "MCTargetDesc/AArch64InstPrinter.h"
-#include "MCTargetDesc/AArch64MCExpr.h"
-#include "MCTargetDesc/AArch64MCTargetDesc.h"
-#include "MCTargetDesc/AArch64TargetStreamer.h"
-#include "TargetInfo/AArch64TargetInfo.h"
-#include "AArch64InstrInfo.h"
-#include "Utils/AArch64BaseInfo.h"
-#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCExpr.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCLinkerOptimizationHint.h"
-#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCParser/MCAsmLexer.h"
-#include "llvm/MC/MCParser/MCAsmParser.h"
-#include "llvm/MC/MCParser/MCAsmParserExtension.h"
-#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
-#include "llvm/MC/MCParser/MCTargetAsmParser.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCSymbol.h"
-#include "llvm/MC/MCTargetOptions.h"
-#include "llvm/MC/SubtargetFeature.h"
-#include "llvm/MC/MCValue.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/SMLoc.h"
-#include "llvm/Support/TargetParser.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cassert>
-#include <cctype>
-#include <cstdint>
-#include <cstdio>
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-using namespace llvm;
-
-namespace {
-
-enum class RegKind {
- Scalar,
- NeonVector,
- SVEDataVector,
- SVEPredicateVector
-};
-
-enum RegConstraintEqualityTy {
- EqualsReg,
- EqualsSuperReg,
- EqualsSubReg
-};
-
-class AArch64AsmParser : public MCTargetAsmParser {
-private:
- StringRef Mnemonic; ///< Instruction mnemonic.
-
- // Map of register aliases registers via the .req directive.
- StringMap<std::pair<RegKind, unsigned>> RegisterReqs;
-
- class PrefixInfo {
- public:
- static PrefixInfo CreateFromInst(const MCInst &Inst, uint64_t TSFlags) {
- PrefixInfo Prefix;
- switch (Inst.getOpcode()) {
- case AArch64::MOVPRFX_ZZ:
- Prefix.Active = true;
- Prefix.Dst = Inst.getOperand(0).getReg();
- break;
- case AArch64::MOVPRFX_ZPmZ_B:
- case AArch64::MOVPRFX_ZPmZ_H:
- case AArch64::MOVPRFX_ZPmZ_S:
- case AArch64::MOVPRFX_ZPmZ_D:
- Prefix.Active = true;
- Prefix.Predicated = true;
- Prefix.ElementSize = TSFlags & AArch64::ElementSizeMask;
- assert(Prefix.ElementSize != AArch64::ElementSizeNone &&
- "No destructive element size set for movprfx");
- Prefix.Dst = Inst.getOperand(0).getReg();
- Prefix.Pg = Inst.getOperand(2).getReg();
- break;
- case AArch64::MOVPRFX_ZPzZ_B:
- case AArch64::MOVPRFX_ZPzZ_H:
- case AArch64::MOVPRFX_ZPzZ_S:
- case AArch64::MOVPRFX_ZPzZ_D:
- Prefix.Active = true;
- Prefix.Predicated = true;
- Prefix.ElementSize = TSFlags & AArch64::ElementSizeMask;
- assert(Prefix.ElementSize != AArch64::ElementSizeNone &&
- "No destructive element size set for movprfx");
- Prefix.Dst = Inst.getOperand(0).getReg();
- Prefix.Pg = Inst.getOperand(1).getReg();
- break;
- default:
- break;
- }
-
- return Prefix;
- }
-
- PrefixInfo() : Active(false), Predicated(false) {}
- bool isActive() const { return Active; }
- bool isPredicated() const { return Predicated; }
- unsigned getElementSize() const {
- assert(Predicated);
- return ElementSize;
- }
- unsigned getDstReg() const { return Dst; }
- unsigned getPgReg() const {
- assert(Predicated);
- return Pg;
- }
-
- private:
- bool Active;
- bool Predicated;
- unsigned ElementSize;
- unsigned Dst;
- unsigned Pg;
- } NextPrefix;
-
- AArch64TargetStreamer &getTargetStreamer() {
- MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
- return static_cast<AArch64TargetStreamer &>(TS);
- }
-
- SMLoc getLoc() const { return getParser().getTok().getLoc(); }
-
- bool parseSysAlias(StringRef Name, SMLoc NameLoc, OperandVector &Operands);
- void createSysAlias(uint16_t Encoding, OperandVector &Operands, SMLoc S);
- AArch64CC::CondCode parseCondCodeString(StringRef Cond);
- bool parseCondCode(OperandVector &Operands, bool invertCondCode);
- unsigned matchRegisterNameAlias(StringRef Name, RegKind Kind);
- bool parseRegister(OperandVector &Operands);
- bool parseSymbolicImmVal(const MCExpr *&ImmVal);
- bool parseNeonVectorList(OperandVector &Operands);
- bool parseOptionalMulOperand(OperandVector &Operands);
+#include "MCTargetDesc/AArch64MCExpr.h"
+#include "MCTargetDesc/AArch64MCTargetDesc.h"
+#include "MCTargetDesc/AArch64TargetStreamer.h"
+#include "TargetInfo/AArch64TargetInfo.h"
+#include "AArch64InstrInfo.h"
+#include "Utils/AArch64BaseInfo.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCLinkerOptimizationHint.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.h"
+#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cctype>
+#include <cstdint>
+#include <cstdio>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+enum class RegKind {
+ Scalar,
+ NeonVector,
+ SVEDataVector,
+ SVEPredicateVector
+};
+
+enum RegConstraintEqualityTy {
+ EqualsReg,
+ EqualsSuperReg,
+ EqualsSubReg
+};
+
+class AArch64AsmParser : public MCTargetAsmParser {
+private:
+ StringRef Mnemonic; ///< Instruction mnemonic.
+
+ // Map of register aliases registers via the .req directive.
+ StringMap<std::pair<RegKind, unsigned>> RegisterReqs;
+
+ class PrefixInfo {
+ public:
+ static PrefixInfo CreateFromInst(const MCInst &Inst, uint64_t TSFlags) {
+ PrefixInfo Prefix;
+ switch (Inst.getOpcode()) {
+ case AArch64::MOVPRFX_ZZ:
+ Prefix.Active = true;
+ Prefix.Dst = Inst.getOperand(0).getReg();
+ break;
+ case AArch64::MOVPRFX_ZPmZ_B:
+ case AArch64::MOVPRFX_ZPmZ_H:
+ case AArch64::MOVPRFX_ZPmZ_S:
+ case AArch64::MOVPRFX_ZPmZ_D:
+ Prefix.Active = true;
+ Prefix.Predicated = true;
+ Prefix.ElementSize = TSFlags & AArch64::ElementSizeMask;
+ assert(Prefix.ElementSize != AArch64::ElementSizeNone &&
+ "No destructive element size set for movprfx");
+ Prefix.Dst = Inst.getOperand(0).getReg();
+ Prefix.Pg = Inst.getOperand(2).getReg();
+ break;
+ case AArch64::MOVPRFX_ZPzZ_B:
+ case AArch64::MOVPRFX_ZPzZ_H:
+ case AArch64::MOVPRFX_ZPzZ_S:
+ case AArch64::MOVPRFX_ZPzZ_D:
+ Prefix.Active = true;
+ Prefix.Predicated = true;
+ Prefix.ElementSize = TSFlags & AArch64::ElementSizeMask;
+ assert(Prefix.ElementSize != AArch64::ElementSizeNone &&
+ "No destructive element size set for movprfx");
+ Prefix.Dst = Inst.getOperand(0).getReg();
+ Prefix.Pg = Inst.getOperand(1).getReg();
+ break;
+ default:
+ break;
+ }
+
+ return Prefix;
+ }
+
+ PrefixInfo() : Active(false), Predicated(false) {}
+ bool isActive() const { return Active; }
+ bool isPredicated() const { return Predicated; }
+ unsigned getElementSize() const {
+ assert(Predicated);
+ return ElementSize;
+ }
+ unsigned getDstReg() const { return Dst; }
+ unsigned getPgReg() const {
+ assert(Predicated);
+ return Pg;
+ }
+
+ private:
+ bool Active;
+ bool Predicated;
+ unsigned ElementSize;
+ unsigned Dst;
+ unsigned Pg;
+ } NextPrefix;
+
+ AArch64TargetStreamer &getTargetStreamer() {
+ MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
+ return static_cast<AArch64TargetStreamer &>(TS);
+ }
+
+ SMLoc getLoc() const { return getParser().getTok().getLoc(); }
+
+ bool parseSysAlias(StringRef Name, SMLoc NameLoc, OperandVector &Operands);
+ void createSysAlias(uint16_t Encoding, OperandVector &Operands, SMLoc S);
+ AArch64CC::CondCode parseCondCodeString(StringRef Cond);
+ bool parseCondCode(OperandVector &Operands, bool invertCondCode);
+ unsigned matchRegisterNameAlias(StringRef Name, RegKind Kind);
+ bool parseRegister(OperandVector &Operands);
+ 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 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);
-
- bool parseDirectiveArch(SMLoc L);
- bool parseDirectiveArchExtension(SMLoc L);
- bool parseDirectiveCPU(SMLoc L);
- bool parseDirectiveInst(SMLoc L);
-
- bool parseDirectiveTLSDescCall(SMLoc L);
-
- bool parseDirectiveLOH(StringRef LOH, SMLoc L);
- bool parseDirectiveLtorg(SMLoc L);
-
- bool parseDirectiveReq(StringRef Name, SMLoc L);
- bool parseDirectiveUnreq(SMLoc L);
- bool parseDirectiveCFINegateRAState();
- bool parseDirectiveCFIBKeyFrame();
-
- bool parseDirectiveVariantPCS(SMLoc L);
-
+
+ bool showMatchError(SMLoc Loc, unsigned ErrCode, uint64_t ErrorInfo,
+ OperandVector &Operands);
+
+ bool parseDirectiveArch(SMLoc L);
+ bool parseDirectiveArchExtension(SMLoc L);
+ bool parseDirectiveCPU(SMLoc L);
+ bool parseDirectiveInst(SMLoc L);
+
+ bool parseDirectiveTLSDescCall(SMLoc L);
+
+ bool parseDirectiveLOH(StringRef LOH, SMLoc L);
+ bool parseDirectiveLtorg(SMLoc L);
+
+ bool parseDirectiveReq(StringRef Name, SMLoc L);
+ bool parseDirectiveUnreq(SMLoc L);
+ bool parseDirectiveCFINegateRAState();
+ bool parseDirectiveCFIBKeyFrame();
+
+ bool parseDirectiveVariantPCS(SMLoc L);
+
bool parseDirectiveSEHAllocStack(SMLoc L);
bool parseDirectiveSEHPrologEnd(SMLoc L);
bool parseDirectiveSEHSaveR19R20X(SMLoc L);
@@ -212,2884 +212,2884 @@ private:
bool parseDirectiveSEHContext(SMLoc L);
bool parseDirectiveSEHClearUnwoundToCall(SMLoc L);
- bool validateInstruction(MCInst &Inst, SMLoc &IDLoc,
- SmallVectorImpl<SMLoc> &Loc);
- bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
- OperandVector &Operands, MCStreamer &Out,
- uint64_t &ErrorInfo,
- bool MatchingInlineAsm) override;
-/// @name Auto-generated Match Functions
-/// {
-
-#define GET_ASSEMBLER_HEADER
-#include "AArch64GenAsmMatcher.inc"
-
- /// }
-
- OperandMatchResultTy tryParseScalarRegister(unsigned &Reg);
- OperandMatchResultTy tryParseVectorRegister(unsigned &Reg, StringRef &Kind,
- RegKind MatchKind);
- OperandMatchResultTy tryParseOptionalShiftExtend(OperandVector &Operands);
- OperandMatchResultTy tryParseBarrierOperand(OperandVector &Operands);
+ bool validateInstruction(MCInst &Inst, SMLoc &IDLoc,
+ SmallVectorImpl<SMLoc> &Loc);
+ bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+ OperandVector &Operands, MCStreamer &Out,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) override;
+/// @name Auto-generated Match Functions
+/// {
+
+#define GET_ASSEMBLER_HEADER
+#include "AArch64GenAsmMatcher.inc"
+
+ /// }
+
+ OperandMatchResultTy tryParseScalarRegister(unsigned &Reg);
+ OperandMatchResultTy tryParseVectorRegister(unsigned &Reg, StringRef &Kind,
+ 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);
- template <bool IsSVEPrefetch = false>
- OperandMatchResultTy tryParsePrefetch(OperandVector &Operands);
- OperandMatchResultTy tryParsePSBHint(OperandVector &Operands);
- OperandMatchResultTy tryParseBTIHint(OperandVector &Operands);
- OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands);
- OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands);
- template<bool AddFPZeroAsLiteral>
- OperandMatchResultTy tryParseFPImm(OperandVector &Operands);
- OperandMatchResultTy tryParseImmWithOptionalShift(OperandVector &Operands);
- OperandMatchResultTy tryParseGPR64sp0Operand(OperandVector &Operands);
- bool tryParseNeonVectorRegister(OperandVector &Operands);
- OperandMatchResultTy tryParseVectorIndex(OperandVector &Operands);
- OperandMatchResultTy tryParseGPRSeqPair(OperandVector &Operands);
- template <bool ParseShiftExtend,
- RegConstraintEqualityTy EqTy = RegConstraintEqualityTy::EqualsReg>
- OperandMatchResultTy tryParseGPROperand(OperandVector &Operands);
- template <bool ParseShiftExtend, bool ParseSuffix>
- OperandMatchResultTy tryParseSVEDataVector(OperandVector &Operands);
- OperandMatchResultTy tryParseSVEPredicateVector(OperandVector &Operands);
- template <RegKind VectorKind>
- OperandMatchResultTy tryParseVectorList(OperandVector &Operands,
- bool ExpectMatch = false);
- OperandMatchResultTy tryParseSVEPattern(OperandVector &Operands);
+ OperandMatchResultTy tryParseMRSSystemRegister(OperandVector &Operands);
+ OperandMatchResultTy tryParseSysReg(OperandVector &Operands);
+ OperandMatchResultTy tryParseSysCROperand(OperandVector &Operands);
+ template <bool IsSVEPrefetch = false>
+ OperandMatchResultTy tryParsePrefetch(OperandVector &Operands);
+ OperandMatchResultTy tryParsePSBHint(OperandVector &Operands);
+ OperandMatchResultTy tryParseBTIHint(OperandVector &Operands);
+ OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands);
+ OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands);
+ template<bool AddFPZeroAsLiteral>
+ OperandMatchResultTy tryParseFPImm(OperandVector &Operands);
+ OperandMatchResultTy tryParseImmWithOptionalShift(OperandVector &Operands);
+ OperandMatchResultTy tryParseGPR64sp0Operand(OperandVector &Operands);
+ bool tryParseNeonVectorRegister(OperandVector &Operands);
+ OperandMatchResultTy tryParseVectorIndex(OperandVector &Operands);
+ OperandMatchResultTy tryParseGPRSeqPair(OperandVector &Operands);
+ template <bool ParseShiftExtend,
+ RegConstraintEqualityTy EqTy = RegConstraintEqualityTy::EqualsReg>
+ OperandMatchResultTy tryParseGPROperand(OperandVector &Operands);
+ template <bool ParseShiftExtend, bool ParseSuffix>
+ OperandMatchResultTy tryParseSVEDataVector(OperandVector &Operands);
+ OperandMatchResultTy tryParseSVEPredicateVector(OperandVector &Operands);
+ template <RegKind VectorKind>
+ OperandMatchResultTy tryParseVectorList(OperandVector &Operands,
+ bool ExpectMatch = false);
+ OperandMatchResultTy tryParseSVEPattern(OperandVector &Operands);
OperandMatchResultTy tryParseGPR64x8(OperandVector &Operands);
-
-public:
- enum AArch64MatchResultTy {
- Match_InvalidSuffix = FIRST_TARGET_MATCH_RESULT_TY,
-#define GET_OPERAND_DIAGNOSTIC_TYPES
-#include "AArch64GenAsmMatcher.inc"
- };
- bool IsILP32;
-
- AArch64AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
- const MCInstrInfo &MII, const MCTargetOptions &Options)
- : MCTargetAsmParser(Options, STI, MII) {
+
+public:
+ enum AArch64MatchResultTy {
+ Match_InvalidSuffix = FIRST_TARGET_MATCH_RESULT_TY,
+#define GET_OPERAND_DIAGNOSTIC_TYPES
+#include "AArch64GenAsmMatcher.inc"
+ };
+ bool IsILP32;
+
+ AArch64AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
+ const MCInstrInfo &MII, const MCTargetOptions &Options)
+ : MCTargetAsmParser(Options, STI, MII) {
IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
- MCAsmParserExtension::Initialize(Parser);
- MCStreamer &S = getParser().getStreamer();
- if (S.getTargetStreamer() == nullptr)
- new AArch64TargetStreamer(S);
-
- // Alias .hword/.word/.[dx]word to the target-independent
- // .2byte/.4byte/.8byte directives as they have the same form and
- // semantics:
- /// ::= (.hword | .word | .dword | .xword ) [ expression (, expression)* ]
- Parser.addAliasForDirective(".hword", ".2byte");
- Parser.addAliasForDirective(".word", ".4byte");
- Parser.addAliasForDirective(".dword", ".8byte");
- Parser.addAliasForDirective(".xword", ".8byte");
-
- // Initialize the set of available features.
- setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits()));
- }
-
- bool regsEqual(const MCParsedAsmOperand &Op1,
- const MCParsedAsmOperand &Op2) const override;
- bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
- SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
- OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc,
- SMLoc &EndLoc) override;
- bool ParseDirective(AsmToken DirectiveID) override;
- unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
- unsigned Kind) override;
-
- static bool classifySymbolRef(const MCExpr *Expr,
- AArch64MCExpr::VariantKind &ELFRefKind,
- MCSymbolRefExpr::VariantKind &DarwinRefKind,
- int64_t &Addend);
-};
-
-/// AArch64Operand - Instances of this class represent a parsed AArch64 machine
-/// instruction.
-class AArch64Operand : public MCParsedAsmOperand {
-private:
- enum KindTy {
- k_Immediate,
- k_ShiftedImm,
- k_CondCode,
- k_Register,
- k_VectorList,
- k_VectorIndex,
- k_Token,
- k_SysReg,
- k_SysCR,
- k_Prefetch,
- k_ShiftExtend,
- k_FPImm,
- k_Barrier,
- k_PSBHint,
- k_BTIHint,
- } Kind;
-
- SMLoc StartLoc, EndLoc;
-
- struct TokOp {
- const char *Data;
- unsigned Length;
- bool IsSuffix; // Is the operand actually a suffix on the mnemonic.
- };
-
- // Separate shift/extend operand.
- struct ShiftExtendOp {
- AArch64_AM::ShiftExtendType Type;
- unsigned Amount;
- bool HasExplicitAmount;
- };
-
- struct RegOp {
- unsigned RegNum;
- RegKind Kind;
- int ElementWidth;
-
- // The register may be allowed as a different register class,
- // e.g. for GPR64as32 or GPR32as64.
- RegConstraintEqualityTy EqualityTy;
-
- // In some cases the shift/extend needs to be explicitly parsed together
- // with the register, rather than as a separate operand. This is needed
- // for addressing modes where the instruction as a whole dictates the
- // scaling/extend, rather than specific bits in the instruction.
- // By parsing them as a single operand, we avoid the need to pass an
- // extra operand in all CodeGen patterns (because all operands need to
- // have an associated value), and we avoid the need to update TableGen to
- // accept operands that have no associated bits in the instruction.
- //
- // An added benefit of parsing them together is that the assembler
- // can give a sensible diagnostic if the scaling is not correct.
- //
- // The default is 'lsl #0' (HasExplicitAmount = false) if no
- // ShiftExtend is specified.
- ShiftExtendOp ShiftExtend;
- };
-
- struct VectorListOp {
- unsigned RegNum;
- unsigned Count;
- unsigned NumElements;
- unsigned ElementWidth;
- RegKind RegisterKind;
- };
-
- struct VectorIndexOp {
- unsigned Val;
- };
-
- struct ImmOp {
- const MCExpr *Val;
- };
-
- struct ShiftedImmOp {
- const MCExpr *Val;
- unsigned ShiftAmount;
- };
-
- struct CondCodeOp {
- AArch64CC::CondCode Code;
- };
-
- struct FPImmOp {
- uint64_t Val; // APFloat value bitcasted to uint64_t.
- bool IsExact; // describes whether parsed value was exact.
- };
-
- struct BarrierOp {
- const char *Data;
- unsigned Length;
- unsigned Val; // Not the enum since not all values have names.
+ MCAsmParserExtension::Initialize(Parser);
+ MCStreamer &S = getParser().getStreamer();
+ if (S.getTargetStreamer() == nullptr)
+ new AArch64TargetStreamer(S);
+
+ // Alias .hword/.word/.[dx]word to the target-independent
+ // .2byte/.4byte/.8byte directives as they have the same form and
+ // semantics:
+ /// ::= (.hword | .word | .dword | .xword ) [ expression (, expression)* ]
+ Parser.addAliasForDirective(".hword", ".2byte");
+ Parser.addAliasForDirective(".word", ".4byte");
+ Parser.addAliasForDirective(".dword", ".8byte");
+ Parser.addAliasForDirective(".xword", ".8byte");
+
+ // Initialize the set of available features.
+ setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits()));
+ }
+
+ bool regsEqual(const MCParsedAsmOperand &Op1,
+ const MCParsedAsmOperand &Op2) const override;
+ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+ SMLoc NameLoc, OperandVector &Operands) override;
+ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
+ OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc,
+ SMLoc &EndLoc) override;
+ bool ParseDirective(AsmToken DirectiveID) override;
+ unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
+ unsigned Kind) override;
+
+ static bool classifySymbolRef(const MCExpr *Expr,
+ AArch64MCExpr::VariantKind &ELFRefKind,
+ MCSymbolRefExpr::VariantKind &DarwinRefKind,
+ int64_t &Addend);
+};
+
+/// AArch64Operand - Instances of this class represent a parsed AArch64 machine
+/// instruction.
+class AArch64Operand : public MCParsedAsmOperand {
+private:
+ enum KindTy {
+ k_Immediate,
+ k_ShiftedImm,
+ k_CondCode,
+ k_Register,
+ k_VectorList,
+ k_VectorIndex,
+ k_Token,
+ k_SysReg,
+ k_SysCR,
+ k_Prefetch,
+ k_ShiftExtend,
+ k_FPImm,
+ k_Barrier,
+ k_PSBHint,
+ k_BTIHint,
+ } Kind;
+
+ SMLoc StartLoc, EndLoc;
+
+ struct TokOp {
+ const char *Data;
+ unsigned Length;
+ bool IsSuffix; // Is the operand actually a suffix on the mnemonic.
+ };
+
+ // Separate shift/extend operand.
+ struct ShiftExtendOp {
+ AArch64_AM::ShiftExtendType Type;
+ unsigned Amount;
+ bool HasExplicitAmount;
+ };
+
+ struct RegOp {
+ unsigned RegNum;
+ RegKind Kind;
+ int ElementWidth;
+
+ // The register may be allowed as a different register class,
+ // e.g. for GPR64as32 or GPR32as64.
+ RegConstraintEqualityTy EqualityTy;
+
+ // In some cases the shift/extend needs to be explicitly parsed together
+ // with the register, rather than as a separate operand. This is needed
+ // for addressing modes where the instruction as a whole dictates the
+ // scaling/extend, rather than specific bits in the instruction.
+ // By parsing them as a single operand, we avoid the need to pass an
+ // extra operand in all CodeGen patterns (because all operands need to
+ // have an associated value), and we avoid the need to update TableGen to
+ // accept operands that have no associated bits in the instruction.
+ //
+ // An added benefit of parsing them together is that the assembler
+ // can give a sensible diagnostic if the scaling is not correct.
+ //
+ // The default is 'lsl #0' (HasExplicitAmount = false) if no
+ // ShiftExtend is specified.
+ ShiftExtendOp ShiftExtend;
+ };
+
+ struct VectorListOp {
+ unsigned RegNum;
+ unsigned Count;
+ unsigned NumElements;
+ unsigned ElementWidth;
+ RegKind RegisterKind;
+ };
+
+ struct VectorIndexOp {
+ unsigned Val;
+ };
+
+ struct ImmOp {
+ const MCExpr *Val;
+ };
+
+ struct ShiftedImmOp {
+ const MCExpr *Val;
+ unsigned ShiftAmount;
+ };
+
+ struct CondCodeOp {
+ AArch64CC::CondCode Code;
+ };
+
+ struct FPImmOp {
+ uint64_t Val; // APFloat value bitcasted to uint64_t.
+ bool IsExact; // describes whether parsed value was exact.
+ };
+
+ struct BarrierOp {
+ const char *Data;
+ unsigned Length;
+ unsigned Val; // Not the enum since not all values have names.
bool HasnXSModifier;
- };
-
- struct SysRegOp {
- const char *Data;
- unsigned Length;
- uint32_t MRSReg;
- uint32_t MSRReg;
- uint32_t PStateField;
- };
-
- struct SysCRImmOp {
- unsigned Val;
- };
-
- struct PrefetchOp {
- const char *Data;
- unsigned Length;
- unsigned Val;
- };
-
- struct PSBHintOp {
- const char *Data;
- unsigned Length;
- unsigned Val;
- };
-
- struct BTIHintOp {
- const char *Data;
- unsigned Length;
- unsigned Val;
- };
-
- struct ExtendOp {
- unsigned Val;
- };
-
- union {
- struct TokOp Tok;
- struct RegOp Reg;
- struct VectorListOp VectorList;
- struct VectorIndexOp VectorIndex;
- struct ImmOp Imm;
- struct ShiftedImmOp ShiftedImm;
- struct CondCodeOp CondCode;
- struct FPImmOp FPImm;
- struct BarrierOp Barrier;
- struct SysRegOp SysReg;
- struct SysCRImmOp SysCRImm;
- struct PrefetchOp Prefetch;
- struct PSBHintOp PSBHint;
- struct BTIHintOp BTIHint;
- struct ShiftExtendOp ShiftExtend;
- };
-
- // Keep the MCContext around as the MCExprs may need manipulated during
- // the add<>Operands() calls.
- MCContext &Ctx;
-
-public:
- AArch64Operand(KindTy K, MCContext &Ctx) : Kind(K), Ctx(Ctx) {}
-
- AArch64Operand(const AArch64Operand &o) : MCParsedAsmOperand(), Ctx(o.Ctx) {
- Kind = o.Kind;
- StartLoc = o.StartLoc;
- EndLoc = o.EndLoc;
- switch (Kind) {
- case k_Token:
- Tok = o.Tok;
- break;
- case k_Immediate:
- Imm = o.Imm;
- break;
- case k_ShiftedImm:
- ShiftedImm = o.ShiftedImm;
- break;
- case k_CondCode:
- CondCode = o.CondCode;
- break;
- case k_FPImm:
- FPImm = o.FPImm;
- break;
- case k_Barrier:
- Barrier = o.Barrier;
- break;
- case k_Register:
- Reg = o.Reg;
- break;
- case k_VectorList:
- VectorList = o.VectorList;
- break;
- case k_VectorIndex:
- VectorIndex = o.VectorIndex;
- break;
- case k_SysReg:
- SysReg = o.SysReg;
- break;
- case k_SysCR:
- SysCRImm = o.SysCRImm;
- break;
- case k_Prefetch:
- Prefetch = o.Prefetch;
- break;
- case k_PSBHint:
- PSBHint = o.PSBHint;
- break;
- case k_BTIHint:
- BTIHint = o.BTIHint;
- break;
- case k_ShiftExtend:
- ShiftExtend = o.ShiftExtend;
- break;
- }
- }
-
- /// getStartLoc - Get the location of the first token of this operand.
- SMLoc getStartLoc() const override { return StartLoc; }
- /// getEndLoc - Get the location of the last token of this operand.
- SMLoc getEndLoc() const override { return EndLoc; }
-
- StringRef getToken() const {
- assert(Kind == k_Token && "Invalid access!");
- return StringRef(Tok.Data, Tok.Length);
- }
-
- bool isTokenSuffix() const {
- assert(Kind == k_Token && "Invalid access!");
- return Tok.IsSuffix;
- }
-
- const MCExpr *getImm() const {
- assert(Kind == k_Immediate && "Invalid access!");
- return Imm.Val;
- }
-
- const MCExpr *getShiftedImmVal() const {
- assert(Kind == k_ShiftedImm && "Invalid access!");
- return ShiftedImm.Val;
- }
-
- unsigned getShiftedImmShift() const {
- assert(Kind == k_ShiftedImm && "Invalid access!");
- return ShiftedImm.ShiftAmount;
- }
-
- AArch64CC::CondCode getCondCode() const {
- assert(Kind == k_CondCode && "Invalid access!");
- return CondCode.Code;
- }
-
- APFloat getFPImm() const {
- assert (Kind == k_FPImm && "Invalid access!");
- return APFloat(APFloat::IEEEdouble(), APInt(64, FPImm.Val, true));
- }
-
- bool getFPImmIsExact() const {
- assert (Kind == k_FPImm && "Invalid access!");
- return FPImm.IsExact;
- }
-
- unsigned getBarrier() const {
- assert(Kind == k_Barrier && "Invalid access!");
- return Barrier.Val;
- }
-
- StringRef getBarrierName() const {
- assert(Kind == k_Barrier && "Invalid access!");
- return StringRef(Barrier.Data, Barrier.Length);
- }
-
+ };
+
+ struct SysRegOp {
+ const char *Data;
+ unsigned Length;
+ uint32_t MRSReg;
+ uint32_t MSRReg;
+ uint32_t PStateField;
+ };
+
+ struct SysCRImmOp {
+ unsigned Val;
+ };
+
+ struct PrefetchOp {
+ const char *Data;
+ unsigned Length;
+ unsigned Val;
+ };
+
+ struct PSBHintOp {
+ const char *Data;
+ unsigned Length;
+ unsigned Val;
+ };
+
+ struct BTIHintOp {
+ const char *Data;
+ unsigned Length;
+ unsigned Val;
+ };
+
+ struct ExtendOp {
+ unsigned Val;
+ };
+
+ union {
+ struct TokOp Tok;
+ struct RegOp Reg;
+ struct VectorListOp VectorList;
+ struct VectorIndexOp VectorIndex;
+ struct ImmOp Imm;
+ struct ShiftedImmOp ShiftedImm;
+ struct CondCodeOp CondCode;
+ struct FPImmOp FPImm;
+ struct BarrierOp Barrier;
+ struct SysRegOp SysReg;
+ struct SysCRImmOp SysCRImm;
+ struct PrefetchOp Prefetch;
+ struct PSBHintOp PSBHint;
+ struct BTIHintOp BTIHint;
+ struct ShiftExtendOp ShiftExtend;
+ };
+
+ // Keep the MCContext around as the MCExprs may need manipulated during
+ // the add<>Operands() calls.
+ MCContext &Ctx;
+
+public:
+ AArch64Operand(KindTy K, MCContext &Ctx) : Kind(K), Ctx(Ctx) {}
+
+ AArch64Operand(const AArch64Operand &o) : MCParsedAsmOperand(), Ctx(o.Ctx) {
+ Kind = o.Kind;
+ StartLoc = o.StartLoc;
+ EndLoc = o.EndLoc;
+ switch (Kind) {
+ case k_Token:
+ Tok = o.Tok;
+ break;
+ case k_Immediate:
+ Imm = o.Imm;
+ break;
+ case k_ShiftedImm:
+ ShiftedImm = o.ShiftedImm;
+ break;
+ case k_CondCode:
+ CondCode = o.CondCode;
+ break;
+ case k_FPImm:
+ FPImm = o.FPImm;
+ break;
+ case k_Barrier:
+ Barrier = o.Barrier;
+ break;
+ case k_Register:
+ Reg = o.Reg;
+ break;
+ case k_VectorList:
+ VectorList = o.VectorList;
+ break;
+ case k_VectorIndex:
+ VectorIndex = o.VectorIndex;
+ break;
+ case k_SysReg:
+ SysReg = o.SysReg;
+ break;
+ case k_SysCR:
+ SysCRImm = o.SysCRImm;
+ break;
+ case k_Prefetch:
+ Prefetch = o.Prefetch;
+ break;
+ case k_PSBHint:
+ PSBHint = o.PSBHint;
+ break;
+ case k_BTIHint:
+ BTIHint = o.BTIHint;
+ break;
+ case k_ShiftExtend:
+ ShiftExtend = o.ShiftExtend;
+ break;
+ }
+ }
+
+ /// getStartLoc - Get the location of the first token of this operand.
+ SMLoc getStartLoc() const override { return StartLoc; }
+ /// getEndLoc - Get the location of the last token of this operand.
+ SMLoc getEndLoc() const override { return EndLoc; }
+
+ StringRef getToken() const {
+ assert(Kind == k_Token && "Invalid access!");
+ return StringRef(Tok.Data, Tok.Length);
+ }
+
+ bool isTokenSuffix() const {
+ assert(Kind == k_Token && "Invalid access!");
+ return Tok.IsSuffix;
+ }
+
+ const MCExpr *getImm() const {
+ assert(Kind == k_Immediate && "Invalid access!");
+ return Imm.Val;
+ }
+
+ const MCExpr *getShiftedImmVal() const {
+ assert(Kind == k_ShiftedImm && "Invalid access!");
+ return ShiftedImm.Val;
+ }
+
+ unsigned getShiftedImmShift() const {
+ assert(Kind == k_ShiftedImm && "Invalid access!");
+ return ShiftedImm.ShiftAmount;
+ }
+
+ AArch64CC::CondCode getCondCode() const {
+ assert(Kind == k_CondCode && "Invalid access!");
+ return CondCode.Code;
+ }
+
+ APFloat getFPImm() const {
+ assert (Kind == k_FPImm && "Invalid access!");
+ return APFloat(APFloat::IEEEdouble(), APInt(64, FPImm.Val, true));
+ }
+
+ bool getFPImmIsExact() const {
+ assert (Kind == k_FPImm && "Invalid access!");
+ return FPImm.IsExact;
+ }
+
+ unsigned getBarrier() const {
+ assert(Kind == k_Barrier && "Invalid access!");
+ return Barrier.Val;
+ }
+
+ StringRef getBarrierName() const {
+ assert(Kind == k_Barrier && "Invalid access!");
+ 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;
- }
-
- RegConstraintEqualityTy getRegEqualityTy() const {
- assert(Kind == k_Register && "Invalid access!");
- return Reg.EqualityTy;
- }
-
- unsigned getVectorListStart() const {
- assert(Kind == k_VectorList && "Invalid access!");
- return VectorList.RegNum;
- }
-
- unsigned getVectorListCount() const {
- assert(Kind == k_VectorList && "Invalid access!");
- return VectorList.Count;
- }
-
- unsigned getVectorIndex() const {
- assert(Kind == k_VectorIndex && "Invalid access!");
- return VectorIndex.Val;
- }
-
- StringRef getSysReg() const {
- assert(Kind == k_SysReg && "Invalid access!");
- return StringRef(SysReg.Data, SysReg.Length);
- }
-
- unsigned getSysCR() const {
- assert(Kind == k_SysCR && "Invalid access!");
- return SysCRImm.Val;
- }
-
- unsigned getPrefetch() const {
- assert(Kind == k_Prefetch && "Invalid access!");
- return Prefetch.Val;
- }
-
- unsigned getPSBHint() const {
- assert(Kind == k_PSBHint && "Invalid access!");
- return PSBHint.Val;
- }
-
- StringRef getPSBHintName() const {
- assert(Kind == k_PSBHint && "Invalid access!");
- return StringRef(PSBHint.Data, PSBHint.Length);
- }
-
- unsigned getBTIHint() const {
- assert(Kind == k_BTIHint && "Invalid access!");
- return BTIHint.Val;
- }
-
- StringRef getBTIHintName() const {
- assert(Kind == k_BTIHint && "Invalid access!");
- return StringRef(BTIHint.Data, BTIHint.Length);
- }
-
- StringRef getPrefetchName() const {
- assert(Kind == k_Prefetch && "Invalid access!");
- return StringRef(Prefetch.Data, Prefetch.Length);
- }
-
- AArch64_AM::ShiftExtendType getShiftExtendType() const {
- if (Kind == k_ShiftExtend)
- return ShiftExtend.Type;
- if (Kind == k_Register)
- return Reg.ShiftExtend.Type;
- llvm_unreachable("Invalid access!");
- }
-
- unsigned getShiftExtendAmount() const {
- if (Kind == k_ShiftExtend)
- return ShiftExtend.Amount;
- if (Kind == k_Register)
- return Reg.ShiftExtend.Amount;
- llvm_unreachable("Invalid access!");
- }
-
- bool hasShiftExtendAmount() const {
- if (Kind == k_ShiftExtend)
- return ShiftExtend.HasExplicitAmount;
- if (Kind == k_Register)
- return Reg.ShiftExtend.HasExplicitAmount;
- llvm_unreachable("Invalid access!");
- }
-
- bool isImm() const override { return Kind == k_Immediate; }
- bool isMem() const override { return false; }
-
- bool isUImm6() const {
- if (!isImm())
- return false;
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE)
- return false;
- int64_t Val = MCE->getValue();
- return (Val >= 0 && Val < 64);
- }
-
- template <int Width> bool isSImm() const { return isSImmScaled<Width, 1>(); }
-
- template <int Bits, int Scale> DiagnosticPredicate isSImmScaled() const {
- return isImmScaled<Bits, Scale>(true);
- }
-
- template <int Bits, int Scale> DiagnosticPredicate isUImmScaled() const {
- return isImmScaled<Bits, Scale>(false);
- }
-
- template <int Bits, int Scale>
- DiagnosticPredicate isImmScaled(bool Signed) const {
- if (!isImm())
- return DiagnosticPredicateTy::NoMatch;
-
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE)
- return DiagnosticPredicateTy::NoMatch;
-
- int64_t MinVal, MaxVal;
- if (Signed) {
- int64_t Shift = Bits - 1;
- MinVal = (int64_t(1) << Shift) * -Scale;
- MaxVal = ((int64_t(1) << Shift) - 1) * Scale;
- } else {
- MinVal = 0;
- MaxVal = ((int64_t(1) << Bits) - 1) * Scale;
- }
-
- int64_t Val = MCE->getValue();
- if (Val >= MinVal && Val <= MaxVal && (Val % Scale) == 0)
- return DiagnosticPredicateTy::Match;
-
- return DiagnosticPredicateTy::NearMatch;
- }
-
- DiagnosticPredicate isSVEPattern() const {
- if (!isImm())
- return DiagnosticPredicateTy::NoMatch;
- auto *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE)
- return DiagnosticPredicateTy::NoMatch;
- int64_t Val = MCE->getValue();
- if (Val >= 0 && Val < 32)
- return DiagnosticPredicateTy::Match;
- return DiagnosticPredicateTy::NearMatch;
- }
-
- bool isSymbolicUImm12Offset(const MCExpr *Expr) const {
- AArch64MCExpr::VariantKind ELFRefKind;
- MCSymbolRefExpr::VariantKind DarwinRefKind;
- int64_t Addend;
- if (!AArch64AsmParser::classifySymbolRef(Expr, ELFRefKind, DarwinRefKind,
- Addend)) {
- // If we don't understand the expression, assume the best and
- // let the fixup and relocation code deal with it.
- return true;
- }
-
- if (DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF ||
- ELFRefKind == AArch64MCExpr::VK_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_GOT_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC ||
- ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC ||
- ELFRefKind == AArch64MCExpr::VK_GOTTPREL_LO12_NC ||
- ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_SECREL_LO12 ||
+ unsigned getReg() const override {
+ assert(Kind == k_Register && "Invalid access!");
+ return Reg.RegNum;
+ }
+
+ RegConstraintEqualityTy getRegEqualityTy() const {
+ assert(Kind == k_Register && "Invalid access!");
+ return Reg.EqualityTy;
+ }
+
+ unsigned getVectorListStart() const {
+ assert(Kind == k_VectorList && "Invalid access!");
+ return VectorList.RegNum;
+ }
+
+ unsigned getVectorListCount() const {
+ assert(Kind == k_VectorList && "Invalid access!");
+ return VectorList.Count;
+ }
+
+ unsigned getVectorIndex() const {
+ assert(Kind == k_VectorIndex && "Invalid access!");
+ return VectorIndex.Val;
+ }
+
+ StringRef getSysReg() const {
+ assert(Kind == k_SysReg && "Invalid access!");
+ return StringRef(SysReg.Data, SysReg.Length);
+ }
+
+ unsigned getSysCR() const {
+ assert(Kind == k_SysCR && "Invalid access!");
+ return SysCRImm.Val;
+ }
+
+ unsigned getPrefetch() const {
+ assert(Kind == k_Prefetch && "Invalid access!");
+ return Prefetch.Val;
+ }
+
+ unsigned getPSBHint() const {
+ assert(Kind == k_PSBHint && "Invalid access!");
+ return PSBHint.Val;
+ }
+
+ StringRef getPSBHintName() const {
+ assert(Kind == k_PSBHint && "Invalid access!");
+ return StringRef(PSBHint.Data, PSBHint.Length);
+ }
+
+ unsigned getBTIHint() const {
+ assert(Kind == k_BTIHint && "Invalid access!");
+ return BTIHint.Val;
+ }
+
+ StringRef getBTIHintName() const {
+ assert(Kind == k_BTIHint && "Invalid access!");
+ return StringRef(BTIHint.Data, BTIHint.Length);
+ }
+
+ StringRef getPrefetchName() const {
+ assert(Kind == k_Prefetch && "Invalid access!");
+ return StringRef(Prefetch.Data, Prefetch.Length);
+ }
+
+ AArch64_AM::ShiftExtendType getShiftExtendType() const {
+ if (Kind == k_ShiftExtend)
+ return ShiftExtend.Type;
+ if (Kind == k_Register)
+ return Reg.ShiftExtend.Type;
+ llvm_unreachable("Invalid access!");
+ }
+
+ unsigned getShiftExtendAmount() const {
+ if (Kind == k_ShiftExtend)
+ return ShiftExtend.Amount;
+ if (Kind == k_Register)
+ return Reg.ShiftExtend.Amount;
+ llvm_unreachable("Invalid access!");
+ }
+
+ bool hasShiftExtendAmount() const {
+ if (Kind == k_ShiftExtend)
+ return ShiftExtend.HasExplicitAmount;
+ if (Kind == k_Register)
+ return Reg.ShiftExtend.HasExplicitAmount;
+ llvm_unreachable("Invalid access!");
+ }
+
+ bool isImm() const override { return Kind == k_Immediate; }
+ bool isMem() const override { return false; }
+
+ bool isUImm6() const {
+ if (!isImm())
+ return false;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ return false;
+ int64_t Val = MCE->getValue();
+ return (Val >= 0 && Val < 64);
+ }
+
+ template <int Width> bool isSImm() const { return isSImmScaled<Width, 1>(); }
+
+ template <int Bits, int Scale> DiagnosticPredicate isSImmScaled() const {
+ return isImmScaled<Bits, Scale>(true);
+ }
+
+ template <int Bits, int Scale> DiagnosticPredicate isUImmScaled() const {
+ return isImmScaled<Bits, Scale>(false);
+ }
+
+ template <int Bits, int Scale>
+ DiagnosticPredicate isImmScaled(bool Signed) const {
+ if (!isImm())
+ return DiagnosticPredicateTy::NoMatch;
+
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ return DiagnosticPredicateTy::NoMatch;
+
+ int64_t MinVal, MaxVal;
+ if (Signed) {
+ int64_t Shift = Bits - 1;
+ MinVal = (int64_t(1) << Shift) * -Scale;
+ MaxVal = ((int64_t(1) << Shift) - 1) * Scale;
+ } else {
+ MinVal = 0;
+ MaxVal = ((int64_t(1) << Bits) - 1) * Scale;
+ }
+
+ int64_t Val = MCE->getValue();
+ if (Val >= MinVal && Val <= MaxVal && (Val % Scale) == 0)
+ return DiagnosticPredicateTy::Match;
+
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ DiagnosticPredicate isSVEPattern() const {
+ if (!isImm())
+ return DiagnosticPredicateTy::NoMatch;
+ auto *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ return DiagnosticPredicateTy::NoMatch;
+ int64_t Val = MCE->getValue();
+ if (Val >= 0 && Val < 32)
+ return DiagnosticPredicateTy::Match;
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ bool isSymbolicUImm12Offset(const MCExpr *Expr) const {
+ AArch64MCExpr::VariantKind ELFRefKind;
+ MCSymbolRefExpr::VariantKind DarwinRefKind;
+ int64_t Addend;
+ if (!AArch64AsmParser::classifySymbolRef(Expr, ELFRefKind, DarwinRefKind,
+ Addend)) {
+ // If we don't understand the expression, assume the best and
+ // let the fixup and relocation code deal with it.
+ return true;
+ }
+
+ if (DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF ||
+ ELFRefKind == AArch64MCExpr::VK_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_GOT_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC ||
+ ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC ||
+ ELFRefKind == AArch64MCExpr::VK_GOTTPREL_LO12_NC ||
+ ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_SECREL_LO12 ||
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.
- return true;
- } else if (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF ||
- DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) {
- // @gotpageoff/@tlvppageoff can only be used directly, not with an addend.
- return Addend == 0;
- }
-
- return false;
- }
-
- template <int Scale> bool isUImm12Offset() const {
- if (!isImm())
- return false;
-
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE)
- return isSymbolicUImm12Offset(getImm());
-
- int64_t Val = MCE->getValue();
- return (Val % Scale) == 0 && Val >= 0 && (Val / Scale) < 0x1000;
- }
-
- template <int N, int M>
- bool isImmInRange() const {
- if (!isImm())
- return false;
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE)
- return false;
- int64_t Val = MCE->getValue();
- return (Val >= N && Val <= M);
- }
-
- // NOTE: Also used for isLogicalImmNot as anything that can be represented as
- // a logical immediate can always be represented when inverted.
- template <typename T>
- bool isLogicalImm() const {
- if (!isImm())
- return false;
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE)
- return false;
-
- int64_t Val = MCE->getValue();
- // Avoid left shift by 64 directly.
- uint64_t Upper = UINT64_C(-1) << (sizeof(T) * 4) << (sizeof(T) * 4);
- // Allow all-0 or all-1 in top bits to permit bitwise NOT.
- if ((Val & Upper) && (Val & Upper) != Upper)
- return false;
-
- return AArch64_AM::isLogicalImmediate(Val & ~Upper, sizeof(T) * 8);
- }
-
- bool isShiftedImm() const { return Kind == k_ShiftedImm; }
-
- /// Returns the immediate value as a pair of (imm, shift) if the immediate is
- /// a shifted immediate by value 'Shift' or '0', or if it is an unshifted
- /// immediate that can be shifted by 'Shift'.
- template <unsigned Width>
- Optional<std::pair<int64_t, unsigned> > getShiftedVal() const {
- if (isShiftedImm() && Width == getShiftedImmShift())
- if (auto *CE = dyn_cast<MCConstantExpr>(getShiftedImmVal()))
- return std::make_pair(CE->getValue(), Width);
-
- if (isImm())
- if (auto *CE = dyn_cast<MCConstantExpr>(getImm())) {
- int64_t Val = CE->getValue();
- if ((Val != 0) && (uint64_t(Val >> Width) << Width) == uint64_t(Val))
- return std::make_pair(Val >> Width, Width);
- else
- return std::make_pair(Val, 0u);
- }
-
- return {};
- }
-
- bool isAddSubImm() const {
- if (!isShiftedImm() && !isImm())
- return false;
-
- const MCExpr *Expr;
-
- // An ADD/SUB shifter is either 'lsl #0' or 'lsl #12'.
- if (isShiftedImm()) {
- unsigned Shift = ShiftedImm.ShiftAmount;
- Expr = ShiftedImm.Val;
- if (Shift != 0 && Shift != 12)
- return false;
- } else {
- Expr = getImm();
- }
-
- AArch64MCExpr::VariantKind ELFRefKind;
- MCSymbolRefExpr::VariantKind DarwinRefKind;
- int64_t Addend;
- if (AArch64AsmParser::classifySymbolRef(Expr, ELFRefKind,
- DarwinRefKind, Addend)) {
- return DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF
- || DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF
- || (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF && Addend == 0)
- || ELFRefKind == AArch64MCExpr::VK_LO12
- || ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12
- || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12
- || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC
- || ELFRefKind == AArch64MCExpr::VK_TPREL_HI12
- || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12
- || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC
- || ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12
- || ELFRefKind == AArch64MCExpr::VK_SECREL_HI12
- || ELFRefKind == AArch64MCExpr::VK_SECREL_LO12;
- }
-
- // If it's a constant, it should be a real immediate in range.
- if (auto ShiftedVal = getShiftedVal<12>())
- return ShiftedVal->first >= 0 && ShiftedVal->first <= 0xfff;
-
- // If it's an expression, we hope for the best and let the fixup/relocation
- // code deal with it.
- return true;
- }
-
- bool isAddSubImmNeg() const {
- if (!isShiftedImm() && !isImm())
- return false;
-
- // Otherwise it should be a real negative immediate in range.
- if (auto ShiftedVal = getShiftedVal<12>())
- return ShiftedVal->first < 0 && -ShiftedVal->first <= 0xfff;
-
- return false;
- }
-
- // Signed value in the range -128 to +127. For element widths of
- // 16 bits or higher it may also be a signed multiple of 256 in the
- // range -32768 to +32512.
- // For element-width of 8 bits a range of -128 to 255 is accepted,
- // since a copy of a byte can be either signed/unsigned.
- template <typename T>
- DiagnosticPredicate isSVECpyImm() const {
- if (!isShiftedImm() && (!isImm() || !isa<MCConstantExpr>(getImm())))
- return DiagnosticPredicateTy::NoMatch;
-
+ // 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.
+ return true;
+ } else if (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF ||
+ DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) {
+ // @gotpageoff/@tlvppageoff can only be used directly, not with an addend.
+ return Addend == 0;
+ }
+
+ return false;
+ }
+
+ template <int Scale> bool isUImm12Offset() const {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ return isSymbolicUImm12Offset(getImm());
+
+ int64_t Val = MCE->getValue();
+ return (Val % Scale) == 0 && Val >= 0 && (Val / Scale) < 0x1000;
+ }
+
+ template <int N, int M>
+ bool isImmInRange() const {
+ if (!isImm())
+ return false;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ return false;
+ int64_t Val = MCE->getValue();
+ return (Val >= N && Val <= M);
+ }
+
+ // NOTE: Also used for isLogicalImmNot as anything that can be represented as
+ // a logical immediate can always be represented when inverted.
+ template <typename T>
+ bool isLogicalImm() const {
+ if (!isImm())
+ return false;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ return false;
+
+ int64_t Val = MCE->getValue();
+ // Avoid left shift by 64 directly.
+ uint64_t Upper = UINT64_C(-1) << (sizeof(T) * 4) << (sizeof(T) * 4);
+ // Allow all-0 or all-1 in top bits to permit bitwise NOT.
+ if ((Val & Upper) && (Val & Upper) != Upper)
+ return false;
+
+ return AArch64_AM::isLogicalImmediate(Val & ~Upper, sizeof(T) * 8);
+ }
+
+ bool isShiftedImm() const { return Kind == k_ShiftedImm; }
+
+ /// Returns the immediate value as a pair of (imm, shift) if the immediate is
+ /// a shifted immediate by value 'Shift' or '0', or if it is an unshifted
+ /// immediate that can be shifted by 'Shift'.
+ template <unsigned Width>
+ Optional<std::pair<int64_t, unsigned> > getShiftedVal() const {
+ if (isShiftedImm() && Width == getShiftedImmShift())
+ if (auto *CE = dyn_cast<MCConstantExpr>(getShiftedImmVal()))
+ return std::make_pair(CE->getValue(), Width);
+
+ if (isImm())
+ if (auto *CE = dyn_cast<MCConstantExpr>(getImm())) {
+ int64_t Val = CE->getValue();
+ if ((Val != 0) && (uint64_t(Val >> Width) << Width) == uint64_t(Val))
+ return std::make_pair(Val >> Width, Width);
+ else
+ return std::make_pair(Val, 0u);
+ }
+
+ return {};
+ }
+
+ bool isAddSubImm() const {
+ if (!isShiftedImm() && !isImm())
+ return false;
+
+ const MCExpr *Expr;
+
+ // An ADD/SUB shifter is either 'lsl #0' or 'lsl #12'.
+ if (isShiftedImm()) {
+ unsigned Shift = ShiftedImm.ShiftAmount;
+ Expr = ShiftedImm.Val;
+ if (Shift != 0 && Shift != 12)
+ return false;
+ } else {
+ Expr = getImm();
+ }
+
+ AArch64MCExpr::VariantKind ELFRefKind;
+ MCSymbolRefExpr::VariantKind DarwinRefKind;
+ int64_t Addend;
+ if (AArch64AsmParser::classifySymbolRef(Expr, ELFRefKind,
+ DarwinRefKind, Addend)) {
+ return DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF
+ || DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF
+ || (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF && Addend == 0)
+ || ELFRefKind == AArch64MCExpr::VK_LO12
+ || ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12
+ || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12
+ || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC
+ || ELFRefKind == AArch64MCExpr::VK_TPREL_HI12
+ || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12
+ || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC
+ || ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12
+ || ELFRefKind == AArch64MCExpr::VK_SECREL_HI12
+ || ELFRefKind == AArch64MCExpr::VK_SECREL_LO12;
+ }
+
+ // If it's a constant, it should be a real immediate in range.
+ if (auto ShiftedVal = getShiftedVal<12>())
+ return ShiftedVal->first >= 0 && ShiftedVal->first <= 0xfff;
+
+ // If it's an expression, we hope for the best and let the fixup/relocation
+ // code deal with it.
+ return true;
+ }
+
+ bool isAddSubImmNeg() const {
+ if (!isShiftedImm() && !isImm())
+ return false;
+
+ // Otherwise it should be a real negative immediate in range.
+ if (auto ShiftedVal = getShiftedVal<12>())
+ return ShiftedVal->first < 0 && -ShiftedVal->first <= 0xfff;
+
+ return false;
+ }
+
+ // Signed value in the range -128 to +127. For element widths of
+ // 16 bits or higher it may also be a signed multiple of 256 in the
+ // range -32768 to +32512.
+ // For element-width of 8 bits a range of -128 to 255 is accepted,
+ // since a copy of a byte can be either signed/unsigned.
+ template <typename T>
+ DiagnosticPredicate isSVECpyImm() const {
+ if (!isShiftedImm() && (!isImm() || !isa<MCConstantExpr>(getImm())))
+ return DiagnosticPredicateTy::NoMatch;
+
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)
- << ShiftedImm->second))
- return DiagnosticPredicateTy::Match;
-
- return DiagnosticPredicateTy::NearMatch;
- }
-
- // Unsigned value in the range 0 to 255. For element widths of
- // 16 bits or higher it may also be a signed multiple of 256 in the
- // range 0 to 65280.
- template <typename T> DiagnosticPredicate isSVEAddSubImm() const {
- if (!isShiftedImm() && (!isImm() || !isa<MCConstantExpr>(getImm())))
- return DiagnosticPredicateTy::NoMatch;
-
+ if (auto ShiftedImm = getShiftedVal<8>())
+ if (!(IsByte && ShiftedImm->second) &&
+ AArch64_AM::isSVECpyImm<T>(uint64_t(ShiftedImm->first)
+ << ShiftedImm->second))
+ return DiagnosticPredicateTy::Match;
+
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ // Unsigned value in the range 0 to 255. For element widths of
+ // 16 bits or higher it may also be a signed multiple of 256 in the
+ // range 0 to 65280.
+ template <typename T> DiagnosticPredicate isSVEAddSubImm() const {
+ if (!isShiftedImm() && (!isImm() || !isa<MCConstantExpr>(getImm())))
+ return DiagnosticPredicateTy::NoMatch;
+
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
- << ShiftedImm->second))
- return DiagnosticPredicateTy::Match;
-
- return DiagnosticPredicateTy::NearMatch;
- }
-
- template <typename T> DiagnosticPredicate isSVEPreferredLogicalImm() const {
- if (isLogicalImm<T>() && !isSVECpyImm<T>())
- return DiagnosticPredicateTy::Match;
- return DiagnosticPredicateTy::NoMatch;
- }
-
- bool isCondCode() const { return Kind == k_CondCode; }
-
- bool isSIMDImmType10() const {
- if (!isImm())
- return false;
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE)
- return false;
- return AArch64_AM::isAdvSIMDModImmType10(MCE->getValue());
- }
-
- template<int N>
- bool isBranchTarget() const {
- if (!isImm())
- return false;
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE)
- return true;
- int64_t Val = MCE->getValue();
- if (Val & 0x3)
- return false;
- assert(N > 0 && "Branch target immediate cannot be 0 bits!");
- return (Val >= -((1<<(N-1)) << 2) && Val <= (((1<<(N-1))-1) << 2));
- }
-
- bool
- isMovWSymbol(ArrayRef<AArch64MCExpr::VariantKind> AllowedModifiers) const {
- if (!isImm())
- return false;
-
- AArch64MCExpr::VariantKind ELFRefKind;
- MCSymbolRefExpr::VariantKind DarwinRefKind;
- int64_t Addend;
- if (!AArch64AsmParser::classifySymbolRef(getImm(), ELFRefKind,
- DarwinRefKind, Addend)) {
- return false;
- }
- if (DarwinRefKind != MCSymbolRefExpr::VK_None)
- return false;
-
- for (unsigned i = 0; i != AllowedModifiers.size(); ++i) {
- if (ELFRefKind == AllowedModifiers[i])
- return true;
- }
-
- return false;
- }
-
- bool isMovWSymbolG3() const {
- return isMovWSymbol({AArch64MCExpr::VK_ABS_G3, AArch64MCExpr::VK_PREL_G3});
- }
-
- bool isMovWSymbolG2() const {
- return isMovWSymbol(
- {AArch64MCExpr::VK_ABS_G2, AArch64MCExpr::VK_ABS_G2_S,
- AArch64MCExpr::VK_ABS_G2_NC, AArch64MCExpr::VK_PREL_G2,
- AArch64MCExpr::VK_PREL_G2_NC, AArch64MCExpr::VK_TPREL_G2,
- AArch64MCExpr::VK_DTPREL_G2});
- }
-
- bool isMovWSymbolG1() const {
- return isMovWSymbol(
- {AArch64MCExpr::VK_ABS_G1, AArch64MCExpr::VK_ABS_G1_S,
- AArch64MCExpr::VK_ABS_G1_NC, AArch64MCExpr::VK_PREL_G1,
- AArch64MCExpr::VK_PREL_G1_NC, AArch64MCExpr::VK_GOTTPREL_G1,
- AArch64MCExpr::VK_TPREL_G1, AArch64MCExpr::VK_TPREL_G1_NC,
- AArch64MCExpr::VK_DTPREL_G1, AArch64MCExpr::VK_DTPREL_G1_NC});
- }
-
- bool isMovWSymbolG0() const {
- return isMovWSymbol(
- {AArch64MCExpr::VK_ABS_G0, AArch64MCExpr::VK_ABS_G0_S,
- AArch64MCExpr::VK_ABS_G0_NC, AArch64MCExpr::VK_PREL_G0,
- AArch64MCExpr::VK_PREL_G0_NC, AArch64MCExpr::VK_GOTTPREL_G0_NC,
- AArch64MCExpr::VK_TPREL_G0, AArch64MCExpr::VK_TPREL_G0_NC,
- AArch64MCExpr::VK_DTPREL_G0, AArch64MCExpr::VK_DTPREL_G0_NC});
- }
-
- template<int RegWidth, int Shift>
- bool isMOVZMovAlias() const {
- if (!isImm()) return false;
-
- const MCExpr *E = getImm();
- if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(E)) {
- uint64_t Value = CE->getValue();
-
- return AArch64_AM::isMOVZMovAlias(Value, Shift, RegWidth);
- }
- // Only supports the case of Shift being 0 if an expression is used as an
- // operand
- return !Shift && E;
- }
-
- template<int RegWidth, int Shift>
- bool isMOVNMovAlias() const {
- if (!isImm()) return false;
-
- const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- if (!CE) return false;
- uint64_t Value = CE->getValue();
-
- return AArch64_AM::isMOVNMovAlias(Value, Shift, RegWidth);
- }
-
- bool isFPImm() const {
- return Kind == k_FPImm &&
- AArch64_AM::getFP64Imm(getFPImm().bitcastToAPInt()) != -1;
- }
-
+ if (auto ShiftedImm = getShiftedVal<8>())
+ if (!(IsByte && ShiftedImm->second) &&
+ AArch64_AM::isSVEAddSubImm<T>(ShiftedImm->first
+ << ShiftedImm->second))
+ return DiagnosticPredicateTy::Match;
+
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ template <typename T> DiagnosticPredicate isSVEPreferredLogicalImm() const {
+ if (isLogicalImm<T>() && !isSVECpyImm<T>())
+ return DiagnosticPredicateTy::Match;
+ return DiagnosticPredicateTy::NoMatch;
+ }
+
+ bool isCondCode() const { return Kind == k_CondCode; }
+
+ bool isSIMDImmType10() const {
+ if (!isImm())
+ return false;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ return false;
+ return AArch64_AM::isAdvSIMDModImmType10(MCE->getValue());
+ }
+
+ template<int N>
+ bool isBranchTarget() const {
+ if (!isImm())
+ return false;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ return true;
+ int64_t Val = MCE->getValue();
+ if (Val & 0x3)
+ return false;
+ assert(N > 0 && "Branch target immediate cannot be 0 bits!");
+ return (Val >= -((1<<(N-1)) << 2) && Val <= (((1<<(N-1))-1) << 2));
+ }
+
+ bool
+ isMovWSymbol(ArrayRef<AArch64MCExpr::VariantKind> AllowedModifiers) const {
+ if (!isImm())
+ return false;
+
+ AArch64MCExpr::VariantKind ELFRefKind;
+ MCSymbolRefExpr::VariantKind DarwinRefKind;
+ int64_t Addend;
+ if (!AArch64AsmParser::classifySymbolRef(getImm(), ELFRefKind,
+ DarwinRefKind, Addend)) {
+ return false;
+ }
+ if (DarwinRefKind != MCSymbolRefExpr::VK_None)
+ return false;
+
+ for (unsigned i = 0; i != AllowedModifiers.size(); ++i) {
+ if (ELFRefKind == AllowedModifiers[i])
+ return true;
+ }
+
+ return false;
+ }
+
+ bool isMovWSymbolG3() const {
+ return isMovWSymbol({AArch64MCExpr::VK_ABS_G3, AArch64MCExpr::VK_PREL_G3});
+ }
+
+ bool isMovWSymbolG2() const {
+ return isMovWSymbol(
+ {AArch64MCExpr::VK_ABS_G2, AArch64MCExpr::VK_ABS_G2_S,
+ AArch64MCExpr::VK_ABS_G2_NC, AArch64MCExpr::VK_PREL_G2,
+ AArch64MCExpr::VK_PREL_G2_NC, AArch64MCExpr::VK_TPREL_G2,
+ AArch64MCExpr::VK_DTPREL_G2});
+ }
+
+ bool isMovWSymbolG1() const {
+ return isMovWSymbol(
+ {AArch64MCExpr::VK_ABS_G1, AArch64MCExpr::VK_ABS_G1_S,
+ AArch64MCExpr::VK_ABS_G1_NC, AArch64MCExpr::VK_PREL_G1,
+ AArch64MCExpr::VK_PREL_G1_NC, AArch64MCExpr::VK_GOTTPREL_G1,
+ AArch64MCExpr::VK_TPREL_G1, AArch64MCExpr::VK_TPREL_G1_NC,
+ AArch64MCExpr::VK_DTPREL_G1, AArch64MCExpr::VK_DTPREL_G1_NC});
+ }
+
+ bool isMovWSymbolG0() const {
+ return isMovWSymbol(
+ {AArch64MCExpr::VK_ABS_G0, AArch64MCExpr::VK_ABS_G0_S,
+ AArch64MCExpr::VK_ABS_G0_NC, AArch64MCExpr::VK_PREL_G0,
+ AArch64MCExpr::VK_PREL_G0_NC, AArch64MCExpr::VK_GOTTPREL_G0_NC,
+ AArch64MCExpr::VK_TPREL_G0, AArch64MCExpr::VK_TPREL_G0_NC,
+ AArch64MCExpr::VK_DTPREL_G0, AArch64MCExpr::VK_DTPREL_G0_NC});
+ }
+
+ template<int RegWidth, int Shift>
+ bool isMOVZMovAlias() const {
+ if (!isImm()) return false;
+
+ const MCExpr *E = getImm();
+ if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(E)) {
+ uint64_t Value = CE->getValue();
+
+ return AArch64_AM::isMOVZMovAlias(Value, Shift, RegWidth);
+ }
+ // Only supports the case of Shift being 0 if an expression is used as an
+ // operand
+ return !Shift && E;
+ }
+
+ template<int RegWidth, int Shift>
+ bool isMOVNMovAlias() const {
+ if (!isImm()) return false;
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ if (!CE) return false;
+ uint64_t Value = CE->getValue();
+
+ return AArch64_AM::isMOVNMovAlias(Value, Shift, RegWidth);
+ }
+
+ bool isFPImm() const {
+ return Kind == k_FPImm &&
+ AArch64_AM::getFP64Imm(getFPImm().bitcastToAPInt()) != -1;
+ }
+
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 {
- if (!isSysReg()) return false;
-
- return SysReg.MRSReg != -1U;
- }
-
- bool isMSRSystemRegister() const {
- if (!isSysReg()) return false;
- return SysReg.MSRReg != -1U;
- }
-
- bool isSystemPStateFieldWithImm0_1() const {
- if (!isSysReg()) return false;
- return (SysReg.PStateField == AArch64PState::PAN ||
- SysReg.PStateField == AArch64PState::DIT ||
- SysReg.PStateField == AArch64PState::UAO ||
- SysReg.PStateField == AArch64PState::SSBS);
- }
-
- bool isSystemPStateFieldWithImm0_15() const {
- if (!isSysReg() || isSystemPStateFieldWithImm0_1()) return false;
- return SysReg.PStateField != -1U;
- }
-
- bool isReg() const override {
- return Kind == k_Register;
- }
-
- bool isScalarReg() const {
- return Kind == k_Register && Reg.Kind == RegKind::Scalar;
- }
-
- bool isNeonVectorReg() const {
- return Kind == k_Register && Reg.Kind == RegKind::NeonVector;
- }
-
- bool isNeonVectorRegLo() const {
- return Kind == k_Register && Reg.Kind == RegKind::NeonVector &&
- (AArch64MCRegisterClasses[AArch64::FPR128_loRegClassID].contains(
- Reg.RegNum) ||
- AArch64MCRegisterClasses[AArch64::FPR64_loRegClassID].contains(
- Reg.RegNum));
- }
-
- template <unsigned Class> bool isSVEVectorReg() const {
- RegKind RK;
- switch (Class) {
- case AArch64::ZPRRegClassID:
- case AArch64::ZPR_3bRegClassID:
- case AArch64::ZPR_4bRegClassID:
- RK = RegKind::SVEDataVector;
- break;
- case AArch64::PPRRegClassID:
- case AArch64::PPR_3bRegClassID:
- RK = RegKind::SVEPredicateVector;
- break;
- default:
- llvm_unreachable("Unsupport register class");
- }
-
- return (Kind == k_Register && Reg.Kind == RK) &&
- AArch64MCRegisterClasses[Class].contains(getReg());
- }
-
- template <unsigned Class> bool isFPRasZPR() const {
- return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
- AArch64MCRegisterClasses[Class].contains(getReg());
- }
-
- template <int ElementWidth, unsigned Class>
- DiagnosticPredicate isSVEPredicateVectorRegOfWidth() const {
- if (Kind != k_Register || Reg.Kind != RegKind::SVEPredicateVector)
- return DiagnosticPredicateTy::NoMatch;
-
- if (isSVEVectorReg<Class>() && (Reg.ElementWidth == ElementWidth))
- return DiagnosticPredicateTy::Match;
-
- return DiagnosticPredicateTy::NearMatch;
- }
-
- template <int ElementWidth, unsigned Class>
- DiagnosticPredicate isSVEDataVectorRegOfWidth() const {
- if (Kind != k_Register || Reg.Kind != RegKind::SVEDataVector)
- return DiagnosticPredicateTy::NoMatch;
-
- if (isSVEVectorReg<Class>() && Reg.ElementWidth == ElementWidth)
- return DiagnosticPredicateTy::Match;
-
- return DiagnosticPredicateTy::NearMatch;
- }
-
- template <int ElementWidth, unsigned Class,
- AArch64_AM::ShiftExtendType ShiftExtendTy, int ShiftWidth,
- bool ShiftWidthAlwaysSame>
- DiagnosticPredicate isSVEDataVectorRegWithShiftExtend() const {
- auto VectorMatch = isSVEDataVectorRegOfWidth<ElementWidth, Class>();
- if (!VectorMatch.isMatch())
- return DiagnosticPredicateTy::NoMatch;
-
- // Give a more specific diagnostic when the user has explicitly typed in
- // a shift-amount that does not match what is expected, but for which
- // there is also an unscaled addressing mode (e.g. sxtw/uxtw).
- bool MatchShift = getShiftExtendAmount() == Log2_32(ShiftWidth / 8);
- if (!MatchShift && (ShiftExtendTy == AArch64_AM::UXTW ||
- ShiftExtendTy == AArch64_AM::SXTW) &&
- !ShiftWidthAlwaysSame && hasShiftExtendAmount() && ShiftWidth == 8)
- return DiagnosticPredicateTy::NoMatch;
-
- if (MatchShift && ShiftExtendTy == getShiftExtendType())
- return DiagnosticPredicateTy::Match;
-
- return DiagnosticPredicateTy::NearMatch;
- }
-
- bool isGPR32as64() const {
- return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
- AArch64MCRegisterClasses[AArch64::GPR64RegClassID].contains(Reg.RegNum);
- }
-
- bool isGPR64as32() const {
- return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
- AArch64MCRegisterClasses[AArch64::GPR32RegClassID].contains(Reg.RegNum);
- }
-
+ bool isSysReg() const { return Kind == k_SysReg; }
+
+ bool isMRSSystemRegister() const {
+ if (!isSysReg()) return false;
+
+ return SysReg.MRSReg != -1U;
+ }
+
+ bool isMSRSystemRegister() const {
+ if (!isSysReg()) return false;
+ return SysReg.MSRReg != -1U;
+ }
+
+ bool isSystemPStateFieldWithImm0_1() const {
+ if (!isSysReg()) return false;
+ return (SysReg.PStateField == AArch64PState::PAN ||
+ SysReg.PStateField == AArch64PState::DIT ||
+ SysReg.PStateField == AArch64PState::UAO ||
+ SysReg.PStateField == AArch64PState::SSBS);
+ }
+
+ bool isSystemPStateFieldWithImm0_15() const {
+ if (!isSysReg() || isSystemPStateFieldWithImm0_1()) return false;
+ return SysReg.PStateField != -1U;
+ }
+
+ bool isReg() const override {
+ return Kind == k_Register;
+ }
+
+ bool isScalarReg() const {
+ return Kind == k_Register && Reg.Kind == RegKind::Scalar;
+ }
+
+ bool isNeonVectorReg() const {
+ return Kind == k_Register && Reg.Kind == RegKind::NeonVector;
+ }
+
+ bool isNeonVectorRegLo() const {
+ return Kind == k_Register && Reg.Kind == RegKind::NeonVector &&
+ (AArch64MCRegisterClasses[AArch64::FPR128_loRegClassID].contains(
+ Reg.RegNum) ||
+ AArch64MCRegisterClasses[AArch64::FPR64_loRegClassID].contains(
+ Reg.RegNum));
+ }
+
+ template <unsigned Class> bool isSVEVectorReg() const {
+ RegKind RK;
+ switch (Class) {
+ case AArch64::ZPRRegClassID:
+ case AArch64::ZPR_3bRegClassID:
+ case AArch64::ZPR_4bRegClassID:
+ RK = RegKind::SVEDataVector;
+ break;
+ case AArch64::PPRRegClassID:
+ case AArch64::PPR_3bRegClassID:
+ RK = RegKind::SVEPredicateVector;
+ break;
+ default:
+ llvm_unreachable("Unsupport register class");
+ }
+
+ return (Kind == k_Register && Reg.Kind == RK) &&
+ AArch64MCRegisterClasses[Class].contains(getReg());
+ }
+
+ template <unsigned Class> bool isFPRasZPR() const {
+ return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
+ AArch64MCRegisterClasses[Class].contains(getReg());
+ }
+
+ template <int ElementWidth, unsigned Class>
+ DiagnosticPredicate isSVEPredicateVectorRegOfWidth() const {
+ if (Kind != k_Register || Reg.Kind != RegKind::SVEPredicateVector)
+ return DiagnosticPredicateTy::NoMatch;
+
+ if (isSVEVectorReg<Class>() && (Reg.ElementWidth == ElementWidth))
+ return DiagnosticPredicateTy::Match;
+
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ template <int ElementWidth, unsigned Class>
+ DiagnosticPredicate isSVEDataVectorRegOfWidth() const {
+ if (Kind != k_Register || Reg.Kind != RegKind::SVEDataVector)
+ return DiagnosticPredicateTy::NoMatch;
+
+ if (isSVEVectorReg<Class>() && Reg.ElementWidth == ElementWidth)
+ return DiagnosticPredicateTy::Match;
+
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ template <int ElementWidth, unsigned Class,
+ AArch64_AM::ShiftExtendType ShiftExtendTy, int ShiftWidth,
+ bool ShiftWidthAlwaysSame>
+ DiagnosticPredicate isSVEDataVectorRegWithShiftExtend() const {
+ auto VectorMatch = isSVEDataVectorRegOfWidth<ElementWidth, Class>();
+ if (!VectorMatch.isMatch())
+ return DiagnosticPredicateTy::NoMatch;
+
+ // Give a more specific diagnostic when the user has explicitly typed in
+ // a shift-amount that does not match what is expected, but for which
+ // there is also an unscaled addressing mode (e.g. sxtw/uxtw).
+ bool MatchShift = getShiftExtendAmount() == Log2_32(ShiftWidth / 8);
+ if (!MatchShift && (ShiftExtendTy == AArch64_AM::UXTW ||
+ ShiftExtendTy == AArch64_AM::SXTW) &&
+ !ShiftWidthAlwaysSame && hasShiftExtendAmount() && ShiftWidth == 8)
+ return DiagnosticPredicateTy::NoMatch;
+
+ if (MatchShift && ShiftExtendTy == getShiftExtendType())
+ return DiagnosticPredicateTy::Match;
+
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ bool isGPR32as64() const {
+ return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
+ AArch64MCRegisterClasses[AArch64::GPR64RegClassID].contains(Reg.RegNum);
+ }
+
+ bool isGPR64as32() const {
+ return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
+ 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(
- Reg.RegNum);
- }
-
- bool isXSeqPair() const {
- return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
- AArch64MCRegisterClasses[AArch64::XSeqPairsClassRegClassID].contains(
- Reg.RegNum);
- }
-
- template<int64_t Angle, int64_t Remainder>
- DiagnosticPredicate isComplexRotation() const {
- if (!isImm()) return DiagnosticPredicateTy::NoMatch;
-
- const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- if (!CE) return DiagnosticPredicateTy::NoMatch;
- uint64_t Value = CE->getValue();
-
- if (Value % Angle == Remainder && Value <= 270)
- return DiagnosticPredicateTy::Match;
- return DiagnosticPredicateTy::NearMatch;
- }
-
- template <unsigned RegClassID> bool isGPR64() const {
- return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
- AArch64MCRegisterClasses[RegClassID].contains(getReg());
- }
-
- template <unsigned RegClassID, int ExtWidth>
- DiagnosticPredicate isGPR64WithShiftExtend() const {
- if (Kind != k_Register || Reg.Kind != RegKind::Scalar)
- return DiagnosticPredicateTy::NoMatch;
-
- if (isGPR64<RegClassID>() && getShiftExtendType() == AArch64_AM::LSL &&
- getShiftExtendAmount() == Log2_32(ExtWidth / 8))
- return DiagnosticPredicateTy::Match;
- return DiagnosticPredicateTy::NearMatch;
- }
-
- /// Is this a vector list with the type implicit (presumably attached to the
- /// instruction itself)?
- template <RegKind VectorKind, unsigned NumRegs>
- bool isImplicitlyTypedVectorList() const {
- return Kind == k_VectorList && VectorList.Count == NumRegs &&
- VectorList.NumElements == 0 &&
- VectorList.RegisterKind == VectorKind;
- }
-
- template <RegKind VectorKind, unsigned NumRegs, unsigned NumElements,
- unsigned ElementWidth>
- bool isTypedVectorList() const {
- if (Kind != k_VectorList)
- return false;
- if (VectorList.Count != NumRegs)
- return false;
- if (VectorList.RegisterKind != VectorKind)
- return false;
- if (VectorList.ElementWidth != ElementWidth)
- return false;
- return VectorList.NumElements == NumElements;
- }
-
- template <int Min, int Max>
- DiagnosticPredicate isVectorIndex() const {
- if (Kind != k_VectorIndex)
- return DiagnosticPredicateTy::NoMatch;
- if (VectorIndex.Val >= Min && VectorIndex.Val <= Max)
- return DiagnosticPredicateTy::Match;
- return DiagnosticPredicateTy::NearMatch;
- }
-
- bool isToken() const override { return Kind == k_Token; }
-
- bool isTokenEqual(StringRef Str) const {
- return Kind == k_Token && getToken() == Str;
- }
- bool isSysCR() const { return Kind == k_SysCR; }
- bool isPrefetch() const { return Kind == k_Prefetch; }
- bool isPSBHint() const { return Kind == k_PSBHint; }
- bool isBTIHint() const { return Kind == k_BTIHint; }
- bool isShiftExtend() const { return Kind == k_ShiftExtend; }
- bool isShifter() const {
- if (!isShiftExtend())
- return false;
-
- AArch64_AM::ShiftExtendType ST = getShiftExtendType();
- return (ST == AArch64_AM::LSL || ST == AArch64_AM::LSR ||
- ST == AArch64_AM::ASR || ST == AArch64_AM::ROR ||
- ST == AArch64_AM::MSL);
- }
-
- template <unsigned ImmEnum> DiagnosticPredicate isExactFPImm() const {
- if (Kind != k_FPImm)
- return DiagnosticPredicateTy::NoMatch;
-
- if (getFPImmIsExact()) {
- // Lookup the immediate from table of supported immediates.
- auto *Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmEnum);
- assert(Desc && "Unknown enum value");
-
- // Calculate its FP value.
- APFloat RealVal(APFloat::IEEEdouble());
- auto StatusOrErr =
- RealVal.convertFromString(Desc->Repr, APFloat::rmTowardZero);
- if (errorToBool(StatusOrErr.takeError()) || *StatusOrErr != APFloat::opOK)
- llvm_unreachable("FP immediate is not exact");
-
- if (getFPImm().bitwiseIsEqual(RealVal))
- return DiagnosticPredicateTy::Match;
- }
-
- return DiagnosticPredicateTy::NearMatch;
- }
-
- template <unsigned ImmA, unsigned ImmB>
- DiagnosticPredicate isExactFPImm() const {
- DiagnosticPredicate Res = DiagnosticPredicateTy::NoMatch;
- if ((Res = isExactFPImm<ImmA>()))
- return DiagnosticPredicateTy::Match;
- if ((Res = isExactFPImm<ImmB>()))
- return DiagnosticPredicateTy::Match;
- return Res;
- }
-
- bool isExtend() const {
- if (!isShiftExtend())
- return false;
-
- AArch64_AM::ShiftExtendType ET = getShiftExtendType();
- return (ET == AArch64_AM::UXTB || ET == AArch64_AM::SXTB ||
- ET == AArch64_AM::UXTH || ET == AArch64_AM::SXTH ||
- ET == AArch64_AM::UXTW || ET == AArch64_AM::SXTW ||
- ET == AArch64_AM::UXTX || ET == AArch64_AM::SXTX ||
- ET == AArch64_AM::LSL) &&
- getShiftExtendAmount() <= 4;
- }
-
- bool isExtend64() const {
- if (!isExtend())
- return false;
- // Make sure the extend expects a 32-bit source register.
- AArch64_AM::ShiftExtendType ET = getShiftExtendType();
- return ET == AArch64_AM::UXTB || ET == AArch64_AM::SXTB ||
- ET == AArch64_AM::UXTH || ET == AArch64_AM::SXTH ||
- ET == AArch64_AM::UXTW || ET == AArch64_AM::SXTW;
- }
-
- bool isExtendLSL64() const {
- if (!isExtend())
- return false;
- AArch64_AM::ShiftExtendType ET = getShiftExtendType();
- return (ET == AArch64_AM::UXTX || ET == AArch64_AM::SXTX ||
- ET == AArch64_AM::LSL) &&
- getShiftExtendAmount() <= 4;
- }
-
- template<int Width> bool isMemXExtend() const {
- if (!isExtend())
- return false;
- AArch64_AM::ShiftExtendType ET = getShiftExtendType();
- return (ET == AArch64_AM::LSL || ET == AArch64_AM::SXTX) &&
- (getShiftExtendAmount() == Log2_32(Width / 8) ||
- getShiftExtendAmount() == 0);
- }
-
- template<int Width> bool isMemWExtend() const {
- if (!isExtend())
- return false;
- AArch64_AM::ShiftExtendType ET = getShiftExtendType();
- return (ET == AArch64_AM::UXTW || ET == AArch64_AM::SXTW) &&
- (getShiftExtendAmount() == Log2_32(Width / 8) ||
- getShiftExtendAmount() == 0);
- }
-
- template <unsigned width>
- bool isArithmeticShifter() const {
- if (!isShifter())
- return false;
-
- // An arithmetic shifter is LSL, LSR, or ASR.
- AArch64_AM::ShiftExtendType ST = getShiftExtendType();
- return (ST == AArch64_AM::LSL || ST == AArch64_AM::LSR ||
- ST == AArch64_AM::ASR) && getShiftExtendAmount() < width;
- }
-
- template <unsigned width>
- bool isLogicalShifter() const {
- if (!isShifter())
- return false;
-
- // A logical shifter is LSL, LSR, ASR or ROR.
- AArch64_AM::ShiftExtendType ST = getShiftExtendType();
- return (ST == AArch64_AM::LSL || ST == AArch64_AM::LSR ||
- ST == AArch64_AM::ASR || ST == AArch64_AM::ROR) &&
- getShiftExtendAmount() < width;
- }
-
- bool isMovImm32Shifter() const {
- if (!isShifter())
- return false;
-
- // A MOVi shifter is LSL of 0, 16, 32, or 48.
- AArch64_AM::ShiftExtendType ST = getShiftExtendType();
- if (ST != AArch64_AM::LSL)
- return false;
- uint64_t Val = getShiftExtendAmount();
- return (Val == 0 || Val == 16);
- }
-
- bool isMovImm64Shifter() const {
- if (!isShifter())
- return false;
-
- // A MOVi shifter is LSL of 0 or 16.
- AArch64_AM::ShiftExtendType ST = getShiftExtendType();
- if (ST != AArch64_AM::LSL)
- return false;
- uint64_t Val = getShiftExtendAmount();
- return (Val == 0 || Val == 16 || Val == 32 || Val == 48);
- }
-
- bool isLogicalVecShifter() const {
- if (!isShifter())
- return false;
-
- // A logical vector shifter is a left shift by 0, 8, 16, or 24.
- unsigned Shift = getShiftExtendAmount();
- return getShiftExtendType() == AArch64_AM::LSL &&
- (Shift == 0 || Shift == 8 || Shift == 16 || Shift == 24);
- }
-
- bool isLogicalVecHalfWordShifter() const {
- if (!isLogicalVecShifter())
- return false;
-
- // A logical vector shifter is a left shift by 0 or 8.
- unsigned Shift = getShiftExtendAmount();
- return getShiftExtendType() == AArch64_AM::LSL &&
- (Shift == 0 || Shift == 8);
- }
-
- bool isMoveVecShifter() const {
- if (!isShiftExtend())
- return false;
-
- // A logical vector shifter is a left shift by 8 or 16.
- unsigned Shift = getShiftExtendAmount();
- return getShiftExtendType() == AArch64_AM::MSL &&
- (Shift == 8 || Shift == 16);
- }
-
- // Fallback unscaled operands are for aliases of LDR/STR that fall back
- // to LDUR/STUR when the offset is not legal for the former but is for
- // the latter. As such, in addition to checking for being a legal unscaled
- // address, also check that it is not a legal scaled address. This avoids
- // ambiguity in the matcher.
- template<int Width>
- bool isSImm9OffsetFB() const {
- return isSImm<9>() && !isUImm12Offset<Width / 8>();
- }
-
- bool isAdrpLabel() const {
- // Validation was handled during parsing, so we just sanity check that
- // something didn't go haywire.
- if (!isImm())
- return false;
-
- if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) {
- int64_t Val = CE->getValue();
- int64_t Min = - (4096 * (1LL << (21 - 1)));
- int64_t Max = 4096 * ((1LL << (21 - 1)) - 1);
- return (Val % 4096) == 0 && Val >= Min && Val <= Max;
- }
-
- return true;
- }
-
- bool isAdrLabel() const {
- // Validation was handled during parsing, so we just sanity check that
- // something didn't go haywire.
- if (!isImm())
- return false;
-
- if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) {
- int64_t Val = CE->getValue();
- int64_t Min = - (1LL << (21 - 1));
- int64_t Max = ((1LL << (21 - 1)) - 1);
- return Val >= Min && Val <= Max;
- }
-
- return true;
- }
-
- void addExpr(MCInst &Inst, const MCExpr *Expr) const {
- // Add as immediates when possible. Null MCExpr = 0.
- if (!Expr)
- Inst.addOperand(MCOperand::createImm(0));
- else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
- Inst.addOperand(MCOperand::createImm(CE->getValue()));
- else
- Inst.addOperand(MCOperand::createExpr(Expr));
- }
-
- void addRegOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createReg(getReg()));
- }
-
- void addGPR32as64Operands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- assert(
- AArch64MCRegisterClasses[AArch64::GPR64RegClassID].contains(getReg()));
-
- const MCRegisterInfo *RI = Ctx.getRegisterInfo();
- uint32_t Reg = RI->getRegClass(AArch64::GPR32RegClassID).getRegister(
- RI->getEncodingValue(getReg()));
-
- Inst.addOperand(MCOperand::createReg(Reg));
- }
-
- void addGPR64as32Operands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- assert(
- AArch64MCRegisterClasses[AArch64::GPR32RegClassID].contains(getReg()));
-
- const MCRegisterInfo *RI = Ctx.getRegisterInfo();
- uint32_t Reg = RI->getRegClass(AArch64::GPR64RegClassID).getRegister(
- RI->getEncodingValue(getReg()));
-
- Inst.addOperand(MCOperand::createReg(Reg));
- }
-
- template <int Width>
- void addFPRasZPRRegOperands(MCInst &Inst, unsigned N) const {
- unsigned Base;
- switch (Width) {
- case 8: Base = AArch64::B0; break;
- case 16: Base = AArch64::H0; break;
- case 32: Base = AArch64::S0; break;
- case 64: Base = AArch64::D0; break;
- case 128: Base = AArch64::Q0; break;
- default:
- llvm_unreachable("Unsupported width");
- }
- Inst.addOperand(MCOperand::createReg(AArch64::Z0 + getReg() - Base));
- }
-
- void addVectorReg64Operands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- assert(
- AArch64MCRegisterClasses[AArch64::FPR128RegClassID].contains(getReg()));
- Inst.addOperand(MCOperand::createReg(AArch64::D0 + getReg() - AArch64::Q0));
- }
-
- void addVectorReg128Operands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- assert(
- AArch64MCRegisterClasses[AArch64::FPR128RegClassID].contains(getReg()));
- Inst.addOperand(MCOperand::createReg(getReg()));
- }
-
- void addVectorRegLoOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createReg(getReg()));
- }
-
- enum VecListIndexType {
- VecListIdx_DReg = 0,
- VecListIdx_QReg = 1,
- VecListIdx_ZReg = 2,
- };
-
- template <VecListIndexType RegTy, unsigned NumRegs>
- void addVectorListOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- static const unsigned FirstRegs[][5] = {
- /* DReg */ { AArch64::Q0,
- AArch64::D0, AArch64::D0_D1,
- AArch64::D0_D1_D2, AArch64::D0_D1_D2_D3 },
- /* QReg */ { AArch64::Q0,
- AArch64::Q0, AArch64::Q0_Q1,
- AArch64::Q0_Q1_Q2, AArch64::Q0_Q1_Q2_Q3 },
- /* ZReg */ { AArch64::Z0,
- AArch64::Z0, AArch64::Z0_Z1,
- AArch64::Z0_Z1_Z2, AArch64::Z0_Z1_Z2_Z3 }
- };
-
- assert((RegTy != VecListIdx_ZReg || NumRegs <= 4) &&
- " NumRegs must be <= 4 for ZRegs");
-
- unsigned FirstReg = FirstRegs[(unsigned)RegTy][NumRegs];
- Inst.addOperand(MCOperand::createReg(FirstReg + getVectorListStart() -
- FirstRegs[(unsigned)RegTy][0]));
- }
-
- void addVectorIndexOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createImm(getVectorIndex()));
- }
-
- template <unsigned ImmIs0, unsigned ImmIs1>
- void addExactFPImmOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- assert(bool(isExactFPImm<ImmIs0, ImmIs1>()) && "Invalid operand");
- Inst.addOperand(MCOperand::createImm(bool(isExactFPImm<ImmIs1>())));
- }
-
- void addImmOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- // If this is a pageoff symrefexpr with an addend, adjust the addend
- // to be only the page-offset portion. Otherwise, just add the expr
- // as-is.
- addExpr(Inst, getImm());
- }
-
- template <int Shift>
- void addImmWithOptionalShiftOperands(MCInst &Inst, unsigned N) const {
- assert(N == 2 && "Invalid number of operands!");
- if (auto ShiftedVal = getShiftedVal<Shift>()) {
- Inst.addOperand(MCOperand::createImm(ShiftedVal->first));
- Inst.addOperand(MCOperand::createImm(ShiftedVal->second));
- } else if (isShiftedImm()) {
- addExpr(Inst, getShiftedImmVal());
- Inst.addOperand(MCOperand::createImm(getShiftedImmShift()));
- } else {
- addExpr(Inst, getImm());
- Inst.addOperand(MCOperand::createImm(0));
- }
- }
-
- template <int Shift>
- void addImmNegWithOptionalShiftOperands(MCInst &Inst, unsigned N) const {
- assert(N == 2 && "Invalid number of operands!");
- if (auto ShiftedVal = getShiftedVal<Shift>()) {
- Inst.addOperand(MCOperand::createImm(-ShiftedVal->first));
- Inst.addOperand(MCOperand::createImm(ShiftedVal->second));
- } else
- llvm_unreachable("Not a shifted negative immediate");
- }
-
- void addCondCodeOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createImm(getCondCode()));
- }
-
- void addAdrpLabelOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE)
- addExpr(Inst, getImm());
- else
- Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 12));
- }
-
- void addAdrLabelOperands(MCInst &Inst, unsigned N) const {
- addImmOperands(Inst, N);
- }
-
- template<int Scale>
- void addUImm12OffsetOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
-
- if (!MCE) {
- Inst.addOperand(MCOperand::createExpr(getImm()));
- return;
- }
- Inst.addOperand(MCOperand::createImm(MCE->getValue() / Scale));
- }
-
- void addUImm6Operands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
- Inst.addOperand(MCOperand::createImm(MCE->getValue()));
- }
-
- template <int Scale>
- void addImmScaledOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
- Inst.addOperand(MCOperand::createImm(MCE->getValue() / Scale));
- }
-
- template <typename T>
- void addLogicalImmOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
- std::make_unsigned_t<T> Val = MCE->getValue();
- uint64_t encoding = AArch64_AM::encodeLogicalImmediate(Val, sizeof(T) * 8);
- Inst.addOperand(MCOperand::createImm(encoding));
- }
-
- template <typename T>
- void addLogicalImmNotOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
- std::make_unsigned_t<T> Val = ~MCE->getValue();
- uint64_t encoding = AArch64_AM::encodeLogicalImmediate(Val, sizeof(T) * 8);
- Inst.addOperand(MCOperand::createImm(encoding));
- }
-
- void addSIMDImmType10Operands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
- uint64_t encoding = AArch64_AM::encodeAdvSIMDModImmType10(MCE->getValue());
- Inst.addOperand(MCOperand::createImm(encoding));
- }
-
- void addBranchTarget26Operands(MCInst &Inst, unsigned N) const {
- // Branch operands don't encode the low bits, so shift them off
- // here. If it's a label, however, just put it on directly as there's
- // not enough information now to do anything.
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE) {
- addExpr(Inst, getImm());
- return;
- }
- assert(MCE && "Invalid constant immediate operand!");
- Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
- }
-
- void addPCRelLabel19Operands(MCInst &Inst, unsigned N) const {
- // Branch operands don't encode the low bits, so shift them off
- // here. If it's a label, however, just put it on directly as there's
- // not enough information now to do anything.
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE) {
- addExpr(Inst, getImm());
- return;
- }
- assert(MCE && "Invalid constant immediate operand!");
- Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
- }
-
- void addBranchTarget14Operands(MCInst &Inst, unsigned N) const {
- // Branch operands don't encode the low bits, so shift them off
- // here. If it's a label, however, just put it on directly as there's
- // not enough information now to do anything.
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
- if (!MCE) {
- addExpr(Inst, getImm());
- return;
- }
- assert(MCE && "Invalid constant immediate operand!");
- Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
- }
-
- void addFPImmOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createImm(
- AArch64_AM::getFP64Imm(getFPImm().bitcastToAPInt())));
- }
-
- void addBarrierOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createImm(getBarrier()));
- }
-
+ bool isWSeqPair() const {
+ return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
+ AArch64MCRegisterClasses[AArch64::WSeqPairsClassRegClassID].contains(
+ Reg.RegNum);
+ }
+
+ bool isXSeqPair() const {
+ return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
+ AArch64MCRegisterClasses[AArch64::XSeqPairsClassRegClassID].contains(
+ Reg.RegNum);
+ }
+
+ template<int64_t Angle, int64_t Remainder>
+ DiagnosticPredicate isComplexRotation() const {
+ if (!isImm()) return DiagnosticPredicateTy::NoMatch;
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ if (!CE) return DiagnosticPredicateTy::NoMatch;
+ uint64_t Value = CE->getValue();
+
+ if (Value % Angle == Remainder && Value <= 270)
+ return DiagnosticPredicateTy::Match;
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ template <unsigned RegClassID> bool isGPR64() const {
+ return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
+ AArch64MCRegisterClasses[RegClassID].contains(getReg());
+ }
+
+ template <unsigned RegClassID, int ExtWidth>
+ DiagnosticPredicate isGPR64WithShiftExtend() const {
+ if (Kind != k_Register || Reg.Kind != RegKind::Scalar)
+ return DiagnosticPredicateTy::NoMatch;
+
+ if (isGPR64<RegClassID>() && getShiftExtendType() == AArch64_AM::LSL &&
+ getShiftExtendAmount() == Log2_32(ExtWidth / 8))
+ return DiagnosticPredicateTy::Match;
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ /// Is this a vector list with the type implicit (presumably attached to the
+ /// instruction itself)?
+ template <RegKind VectorKind, unsigned NumRegs>
+ bool isImplicitlyTypedVectorList() const {
+ return Kind == k_VectorList && VectorList.Count == NumRegs &&
+ VectorList.NumElements == 0 &&
+ VectorList.RegisterKind == VectorKind;
+ }
+
+ template <RegKind VectorKind, unsigned NumRegs, unsigned NumElements,
+ unsigned ElementWidth>
+ bool isTypedVectorList() const {
+ if (Kind != k_VectorList)
+ return false;
+ if (VectorList.Count != NumRegs)
+ return false;
+ if (VectorList.RegisterKind != VectorKind)
+ return false;
+ if (VectorList.ElementWidth != ElementWidth)
+ return false;
+ return VectorList.NumElements == NumElements;
+ }
+
+ template <int Min, int Max>
+ DiagnosticPredicate isVectorIndex() const {
+ if (Kind != k_VectorIndex)
+ return DiagnosticPredicateTy::NoMatch;
+ if (VectorIndex.Val >= Min && VectorIndex.Val <= Max)
+ return DiagnosticPredicateTy::Match;
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ bool isToken() const override { return Kind == k_Token; }
+
+ bool isTokenEqual(StringRef Str) const {
+ return Kind == k_Token && getToken() == Str;
+ }
+ bool isSysCR() const { return Kind == k_SysCR; }
+ bool isPrefetch() const { return Kind == k_Prefetch; }
+ bool isPSBHint() const { return Kind == k_PSBHint; }
+ bool isBTIHint() const { return Kind == k_BTIHint; }
+ bool isShiftExtend() const { return Kind == k_ShiftExtend; }
+ bool isShifter() const {
+ if (!isShiftExtend())
+ return false;
+
+ AArch64_AM::ShiftExtendType ST = getShiftExtendType();
+ return (ST == AArch64_AM::LSL || ST == AArch64_AM::LSR ||
+ ST == AArch64_AM::ASR || ST == AArch64_AM::ROR ||
+ ST == AArch64_AM::MSL);
+ }
+
+ template <unsigned ImmEnum> DiagnosticPredicate isExactFPImm() const {
+ if (Kind != k_FPImm)
+ return DiagnosticPredicateTy::NoMatch;
+
+ if (getFPImmIsExact()) {
+ // Lookup the immediate from table of supported immediates.
+ auto *Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmEnum);
+ assert(Desc && "Unknown enum value");
+
+ // Calculate its FP value.
+ APFloat RealVal(APFloat::IEEEdouble());
+ auto StatusOrErr =
+ RealVal.convertFromString(Desc->Repr, APFloat::rmTowardZero);
+ if (errorToBool(StatusOrErr.takeError()) || *StatusOrErr != APFloat::opOK)
+ llvm_unreachable("FP immediate is not exact");
+
+ if (getFPImm().bitwiseIsEqual(RealVal))
+ return DiagnosticPredicateTy::Match;
+ }
+
+ return DiagnosticPredicateTy::NearMatch;
+ }
+
+ template <unsigned ImmA, unsigned ImmB>
+ DiagnosticPredicate isExactFPImm() const {
+ DiagnosticPredicate Res = DiagnosticPredicateTy::NoMatch;
+ if ((Res = isExactFPImm<ImmA>()))
+ return DiagnosticPredicateTy::Match;
+ if ((Res = isExactFPImm<ImmB>()))
+ return DiagnosticPredicateTy::Match;
+ return Res;
+ }
+
+ bool isExtend() const {
+ if (!isShiftExtend())
+ return false;
+
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ return (ET == AArch64_AM::UXTB || ET == AArch64_AM::SXTB ||
+ ET == AArch64_AM::UXTH || ET == AArch64_AM::SXTH ||
+ ET == AArch64_AM::UXTW || ET == AArch64_AM::SXTW ||
+ ET == AArch64_AM::UXTX || ET == AArch64_AM::SXTX ||
+ ET == AArch64_AM::LSL) &&
+ getShiftExtendAmount() <= 4;
+ }
+
+ bool isExtend64() const {
+ if (!isExtend())
+ return false;
+ // Make sure the extend expects a 32-bit source register.
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ return ET == AArch64_AM::UXTB || ET == AArch64_AM::SXTB ||
+ ET == AArch64_AM::UXTH || ET == AArch64_AM::SXTH ||
+ ET == AArch64_AM::UXTW || ET == AArch64_AM::SXTW;
+ }
+
+ bool isExtendLSL64() const {
+ if (!isExtend())
+ return false;
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ return (ET == AArch64_AM::UXTX || ET == AArch64_AM::SXTX ||
+ ET == AArch64_AM::LSL) &&
+ getShiftExtendAmount() <= 4;
+ }
+
+ template<int Width> bool isMemXExtend() const {
+ if (!isExtend())
+ return false;
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ return (ET == AArch64_AM::LSL || ET == AArch64_AM::SXTX) &&
+ (getShiftExtendAmount() == Log2_32(Width / 8) ||
+ getShiftExtendAmount() == 0);
+ }
+
+ template<int Width> bool isMemWExtend() const {
+ if (!isExtend())
+ return false;
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ return (ET == AArch64_AM::UXTW || ET == AArch64_AM::SXTW) &&
+ (getShiftExtendAmount() == Log2_32(Width / 8) ||
+ getShiftExtendAmount() == 0);
+ }
+
+ template <unsigned width>
+ bool isArithmeticShifter() const {
+ if (!isShifter())
+ return false;
+
+ // An arithmetic shifter is LSL, LSR, or ASR.
+ AArch64_AM::ShiftExtendType ST = getShiftExtendType();
+ return (ST == AArch64_AM::LSL || ST == AArch64_AM::LSR ||
+ ST == AArch64_AM::ASR) && getShiftExtendAmount() < width;
+ }
+
+ template <unsigned width>
+ bool isLogicalShifter() const {
+ if (!isShifter())
+ return false;
+
+ // A logical shifter is LSL, LSR, ASR or ROR.
+ AArch64_AM::ShiftExtendType ST = getShiftExtendType();
+ return (ST == AArch64_AM::LSL || ST == AArch64_AM::LSR ||
+ ST == AArch64_AM::ASR || ST == AArch64_AM::ROR) &&
+ getShiftExtendAmount() < width;
+ }
+
+ bool isMovImm32Shifter() const {
+ if (!isShifter())
+ return false;
+
+ // A MOVi shifter is LSL of 0, 16, 32, or 48.
+ AArch64_AM::ShiftExtendType ST = getShiftExtendType();
+ if (ST != AArch64_AM::LSL)
+ return false;
+ uint64_t Val = getShiftExtendAmount();
+ return (Val == 0 || Val == 16);
+ }
+
+ bool isMovImm64Shifter() const {
+ if (!isShifter())
+ return false;
+
+ // A MOVi shifter is LSL of 0 or 16.
+ AArch64_AM::ShiftExtendType ST = getShiftExtendType();
+ if (ST != AArch64_AM::LSL)
+ return false;
+ uint64_t Val = getShiftExtendAmount();
+ return (Val == 0 || Val == 16 || Val == 32 || Val == 48);
+ }
+
+ bool isLogicalVecShifter() const {
+ if (!isShifter())
+ return false;
+
+ // A logical vector shifter is a left shift by 0, 8, 16, or 24.
+ unsigned Shift = getShiftExtendAmount();
+ return getShiftExtendType() == AArch64_AM::LSL &&
+ (Shift == 0 || Shift == 8 || Shift == 16 || Shift == 24);
+ }
+
+ bool isLogicalVecHalfWordShifter() const {
+ if (!isLogicalVecShifter())
+ return false;
+
+ // A logical vector shifter is a left shift by 0 or 8.
+ unsigned Shift = getShiftExtendAmount();
+ return getShiftExtendType() == AArch64_AM::LSL &&
+ (Shift == 0 || Shift == 8);
+ }
+
+ bool isMoveVecShifter() const {
+ if (!isShiftExtend())
+ return false;
+
+ // A logical vector shifter is a left shift by 8 or 16.
+ unsigned Shift = getShiftExtendAmount();
+ return getShiftExtendType() == AArch64_AM::MSL &&
+ (Shift == 8 || Shift == 16);
+ }
+
+ // Fallback unscaled operands are for aliases of LDR/STR that fall back
+ // to LDUR/STUR when the offset is not legal for the former but is for
+ // the latter. As such, in addition to checking for being a legal unscaled
+ // address, also check that it is not a legal scaled address. This avoids
+ // ambiguity in the matcher.
+ template<int Width>
+ bool isSImm9OffsetFB() const {
+ return isSImm<9>() && !isUImm12Offset<Width / 8>();
+ }
+
+ bool isAdrpLabel() const {
+ // Validation was handled during parsing, so we just sanity check that
+ // something didn't go haywire.
+ if (!isImm())
+ return false;
+
+ if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) {
+ int64_t Val = CE->getValue();
+ int64_t Min = - (4096 * (1LL << (21 - 1)));
+ int64_t Max = 4096 * ((1LL << (21 - 1)) - 1);
+ return (Val % 4096) == 0 && Val >= Min && Val <= Max;
+ }
+
+ return true;
+ }
+
+ bool isAdrLabel() const {
+ // Validation was handled during parsing, so we just sanity check that
+ // something didn't go haywire.
+ if (!isImm())
+ return false;
+
+ if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) {
+ int64_t Val = CE->getValue();
+ int64_t Min = - (1LL << (21 - 1));
+ int64_t Max = ((1LL << (21 - 1)) - 1);
+ return Val >= Min && Val <= Max;
+ }
+
+ return true;
+ }
+
+ void addExpr(MCInst &Inst, const MCExpr *Expr) const {
+ // Add as immediates when possible. Null MCExpr = 0.
+ if (!Expr)
+ Inst.addOperand(MCOperand::createImm(0));
+ else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
+ Inst.addOperand(MCOperand::createImm(CE->getValue()));
+ else
+ Inst.addOperand(MCOperand::createExpr(Expr));
+ }
+
+ void addRegOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(getReg()));
+ }
+
+ void addGPR32as64Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ assert(
+ AArch64MCRegisterClasses[AArch64::GPR64RegClassID].contains(getReg()));
+
+ const MCRegisterInfo *RI = Ctx.getRegisterInfo();
+ uint32_t Reg = RI->getRegClass(AArch64::GPR32RegClassID).getRegister(
+ RI->getEncodingValue(getReg()));
+
+ Inst.addOperand(MCOperand::createReg(Reg));
+ }
+
+ void addGPR64as32Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ assert(
+ AArch64MCRegisterClasses[AArch64::GPR32RegClassID].contains(getReg()));
+
+ const MCRegisterInfo *RI = Ctx.getRegisterInfo();
+ uint32_t Reg = RI->getRegClass(AArch64::GPR64RegClassID).getRegister(
+ RI->getEncodingValue(getReg()));
+
+ Inst.addOperand(MCOperand::createReg(Reg));
+ }
+
+ template <int Width>
+ void addFPRasZPRRegOperands(MCInst &Inst, unsigned N) const {
+ unsigned Base;
+ switch (Width) {
+ case 8: Base = AArch64::B0; break;
+ case 16: Base = AArch64::H0; break;
+ case 32: Base = AArch64::S0; break;
+ case 64: Base = AArch64::D0; break;
+ case 128: Base = AArch64::Q0; break;
+ default:
+ llvm_unreachable("Unsupported width");
+ }
+ Inst.addOperand(MCOperand::createReg(AArch64::Z0 + getReg() - Base));
+ }
+
+ void addVectorReg64Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ assert(
+ AArch64MCRegisterClasses[AArch64::FPR128RegClassID].contains(getReg()));
+ Inst.addOperand(MCOperand::createReg(AArch64::D0 + getReg() - AArch64::Q0));
+ }
+
+ void addVectorReg128Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ assert(
+ AArch64MCRegisterClasses[AArch64::FPR128RegClassID].contains(getReg()));
+ Inst.addOperand(MCOperand::createReg(getReg()));
+ }
+
+ void addVectorRegLoOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(getReg()));
+ }
+
+ enum VecListIndexType {
+ VecListIdx_DReg = 0,
+ VecListIdx_QReg = 1,
+ VecListIdx_ZReg = 2,
+ };
+
+ template <VecListIndexType RegTy, unsigned NumRegs>
+ void addVectorListOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ static const unsigned FirstRegs[][5] = {
+ /* DReg */ { AArch64::Q0,
+ AArch64::D0, AArch64::D0_D1,
+ AArch64::D0_D1_D2, AArch64::D0_D1_D2_D3 },
+ /* QReg */ { AArch64::Q0,
+ AArch64::Q0, AArch64::Q0_Q1,
+ AArch64::Q0_Q1_Q2, AArch64::Q0_Q1_Q2_Q3 },
+ /* ZReg */ { AArch64::Z0,
+ AArch64::Z0, AArch64::Z0_Z1,
+ AArch64::Z0_Z1_Z2, AArch64::Z0_Z1_Z2_Z3 }
+ };
+
+ assert((RegTy != VecListIdx_ZReg || NumRegs <= 4) &&
+ " NumRegs must be <= 4 for ZRegs");
+
+ unsigned FirstReg = FirstRegs[(unsigned)RegTy][NumRegs];
+ Inst.addOperand(MCOperand::createReg(FirstReg + getVectorListStart() -
+ FirstRegs[(unsigned)RegTy][0]));
+ }
+
+ void addVectorIndexOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createImm(getVectorIndex()));
+ }
+
+ template <unsigned ImmIs0, unsigned ImmIs1>
+ void addExactFPImmOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ assert(bool(isExactFPImm<ImmIs0, ImmIs1>()) && "Invalid operand");
+ Inst.addOperand(MCOperand::createImm(bool(isExactFPImm<ImmIs1>())));
+ }
+
+ void addImmOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ // If this is a pageoff symrefexpr with an addend, adjust the addend
+ // to be only the page-offset portion. Otherwise, just add the expr
+ // as-is.
+ addExpr(Inst, getImm());
+ }
+
+ template <int Shift>
+ void addImmWithOptionalShiftOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+ if (auto ShiftedVal = getShiftedVal<Shift>()) {
+ Inst.addOperand(MCOperand::createImm(ShiftedVal->first));
+ Inst.addOperand(MCOperand::createImm(ShiftedVal->second));
+ } else if (isShiftedImm()) {
+ addExpr(Inst, getShiftedImmVal());
+ Inst.addOperand(MCOperand::createImm(getShiftedImmShift()));
+ } else {
+ addExpr(Inst, getImm());
+ Inst.addOperand(MCOperand::createImm(0));
+ }
+ }
+
+ template <int Shift>
+ void addImmNegWithOptionalShiftOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+ if (auto ShiftedVal = getShiftedVal<Shift>()) {
+ Inst.addOperand(MCOperand::createImm(-ShiftedVal->first));
+ Inst.addOperand(MCOperand::createImm(ShiftedVal->second));
+ } else
+ llvm_unreachable("Not a shifted negative immediate");
+ }
+
+ void addCondCodeOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createImm(getCondCode()));
+ }
+
+ void addAdrpLabelOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ addExpr(Inst, getImm());
+ else
+ Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 12));
+ }
+
+ void addAdrLabelOperands(MCInst &Inst, unsigned N) const {
+ addImmOperands(Inst, N);
+ }
+
+ template<int Scale>
+ void addUImm12OffsetOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+
+ if (!MCE) {
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ return;
+ }
+ Inst.addOperand(MCOperand::createImm(MCE->getValue() / Scale));
+ }
+
+ void addUImm6Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
+ Inst.addOperand(MCOperand::createImm(MCE->getValue()));
+ }
+
+ template <int Scale>
+ void addImmScaledOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
+ Inst.addOperand(MCOperand::createImm(MCE->getValue() / Scale));
+ }
+
+ template <typename T>
+ void addLogicalImmOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
+ std::make_unsigned_t<T> Val = MCE->getValue();
+ uint64_t encoding = AArch64_AM::encodeLogicalImmediate(Val, sizeof(T) * 8);
+ Inst.addOperand(MCOperand::createImm(encoding));
+ }
+
+ template <typename T>
+ void addLogicalImmNotOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
+ std::make_unsigned_t<T> Val = ~MCE->getValue();
+ uint64_t encoding = AArch64_AM::encodeLogicalImmediate(Val, sizeof(T) * 8);
+ Inst.addOperand(MCOperand::createImm(encoding));
+ }
+
+ void addSIMDImmType10Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
+ uint64_t encoding = AArch64_AM::encodeAdvSIMDModImmType10(MCE->getValue());
+ Inst.addOperand(MCOperand::createImm(encoding));
+ }
+
+ void addBranchTarget26Operands(MCInst &Inst, unsigned N) const {
+ // Branch operands don't encode the low bits, so shift them off
+ // here. If it's a label, however, just put it on directly as there's
+ // not enough information now to do anything.
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE) {
+ addExpr(Inst, getImm());
+ return;
+ }
+ assert(MCE && "Invalid constant immediate operand!");
+ Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
+ }
+
+ void addPCRelLabel19Operands(MCInst &Inst, unsigned N) const {
+ // Branch operands don't encode the low bits, so shift them off
+ // here. If it's a label, however, just put it on directly as there's
+ // not enough information now to do anything.
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE) {
+ addExpr(Inst, getImm());
+ return;
+ }
+ assert(MCE && "Invalid constant immediate operand!");
+ Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
+ }
+
+ void addBranchTarget14Operands(MCInst &Inst, unsigned N) const {
+ // Branch operands don't encode the low bits, so shift them off
+ // here. If it's a label, however, just put it on directly as there's
+ // not enough information now to do anything.
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE) {
+ addExpr(Inst, getImm());
+ return;
+ }
+ assert(MCE && "Invalid constant immediate operand!");
+ Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
+ }
+
+ void addFPImmOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createImm(
+ AArch64_AM::getFP64Imm(getFPImm().bitcastToAPInt())));
+ }
+
+ void addBarrierOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ 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!");
-
- Inst.addOperand(MCOperand::createImm(SysReg.MRSReg));
- }
-
- void addMSRSystemRegisterOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
-
- Inst.addOperand(MCOperand::createImm(SysReg.MSRReg));
- }
-
- void addSystemPStateFieldWithImm0_1Operands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
-
- Inst.addOperand(MCOperand::createImm(SysReg.PStateField));
- }
-
- void addSystemPStateFieldWithImm0_15Operands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
-
- Inst.addOperand(MCOperand::createImm(SysReg.PStateField));
- }
-
- void addSysCROperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createImm(getSysCR()));
- }
-
- void addPrefetchOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createImm(getPrefetch()));
- }
-
- void addPSBHintOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createImm(getPSBHint()));
- }
-
- void addBTIHintOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createImm(getBTIHint()));
- }
-
- void addShifterOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- unsigned Imm =
- AArch64_AM::getShifterImm(getShiftExtendType(), getShiftExtendAmount());
- Inst.addOperand(MCOperand::createImm(Imm));
- }
-
- void addExtendOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- AArch64_AM::ShiftExtendType ET = getShiftExtendType();
- if (ET == AArch64_AM::LSL) ET = AArch64_AM::UXTW;
- unsigned Imm = AArch64_AM::getArithExtendImm(ET, getShiftExtendAmount());
- Inst.addOperand(MCOperand::createImm(Imm));
- }
-
- void addExtend64Operands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- AArch64_AM::ShiftExtendType ET = getShiftExtendType();
- if (ET == AArch64_AM::LSL) ET = AArch64_AM::UXTX;
- unsigned Imm = AArch64_AM::getArithExtendImm(ET, getShiftExtendAmount());
- Inst.addOperand(MCOperand::createImm(Imm));
- }
-
- void addMemExtendOperands(MCInst &Inst, unsigned N) const {
- assert(N == 2 && "Invalid number of operands!");
- AArch64_AM::ShiftExtendType ET = getShiftExtendType();
- bool IsSigned = ET == AArch64_AM::SXTW || ET == AArch64_AM::SXTX;
- Inst.addOperand(MCOperand::createImm(IsSigned));
- Inst.addOperand(MCOperand::createImm(getShiftExtendAmount() != 0));
- }
-
- // For 8-bit load/store instructions with a register offset, both the
- // "DoShift" and "NoShift" variants have a shift of 0. Because of this,
- // they're disambiguated by whether the shift was explicit or implicit rather
- // than its size.
- void addMemExtend8Operands(MCInst &Inst, unsigned N) const {
- assert(N == 2 && "Invalid number of operands!");
- AArch64_AM::ShiftExtendType ET = getShiftExtendType();
- bool IsSigned = ET == AArch64_AM::SXTW || ET == AArch64_AM::SXTX;
- Inst.addOperand(MCOperand::createImm(IsSigned));
- Inst.addOperand(MCOperand::createImm(hasShiftExtendAmount()));
- }
-
- template<int Shift>
- void addMOVZMovAliasOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
-
- const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- if (CE) {
- uint64_t Value = CE->getValue();
- Inst.addOperand(MCOperand::createImm((Value >> Shift) & 0xffff));
- } else {
- addExpr(Inst, getImm());
- }
- }
-
- template<int Shift>
- void addMOVNMovAliasOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
-
- const MCConstantExpr *CE = cast<MCConstantExpr>(getImm());
- uint64_t Value = CE->getValue();
- Inst.addOperand(MCOperand::createImm((~Value >> Shift) & 0xffff));
- }
-
- void addComplexRotationEvenOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
- Inst.addOperand(MCOperand::createImm(MCE->getValue() / 90));
- }
-
- void addComplexRotationOddOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
- Inst.addOperand(MCOperand::createImm((MCE->getValue() - 90) / 180));
- }
-
- void print(raw_ostream &OS) const override;
-
- static std::unique_ptr<AArch64Operand>
- CreateToken(StringRef Str, bool IsSuffix, SMLoc S, MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_Token, Ctx);
- Op->Tok.Data = Str.data();
- Op->Tok.Length = Str.size();
- Op->Tok.IsSuffix = IsSuffix;
- Op->StartLoc = S;
- Op->EndLoc = S;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand>
- CreateReg(unsigned RegNum, RegKind Kind, SMLoc S, SMLoc E, MCContext &Ctx,
- RegConstraintEqualityTy EqTy = RegConstraintEqualityTy::EqualsReg,
- AArch64_AM::ShiftExtendType ExtTy = AArch64_AM::LSL,
- unsigned ShiftAmount = 0,
- unsigned HasExplicitAmount = false) {
- auto Op = std::make_unique<AArch64Operand>(k_Register, Ctx);
- Op->Reg.RegNum = RegNum;
- Op->Reg.Kind = Kind;
- Op->Reg.ElementWidth = 0;
- Op->Reg.EqualityTy = EqTy;
- Op->Reg.ShiftExtend.Type = ExtTy;
- Op->Reg.ShiftExtend.Amount = ShiftAmount;
- Op->Reg.ShiftExtend.HasExplicitAmount = HasExplicitAmount;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand>
- CreateVectorReg(unsigned RegNum, RegKind Kind, unsigned ElementWidth,
- SMLoc S, SMLoc E, MCContext &Ctx,
- AArch64_AM::ShiftExtendType ExtTy = AArch64_AM::LSL,
- unsigned ShiftAmount = 0,
- unsigned HasExplicitAmount = false) {
- assert((Kind == RegKind::NeonVector || Kind == RegKind::SVEDataVector ||
- Kind == RegKind::SVEPredicateVector) &&
- "Invalid vector kind");
- auto Op = CreateReg(RegNum, Kind, S, E, Ctx, EqualsReg, ExtTy, ShiftAmount,
- HasExplicitAmount);
- Op->Reg.ElementWidth = ElementWidth;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand>
- CreateVectorList(unsigned RegNum, unsigned Count, unsigned NumElements,
- unsigned ElementWidth, RegKind RegisterKind, SMLoc S, SMLoc E,
- MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_VectorList, Ctx);
- Op->VectorList.RegNum = RegNum;
- Op->VectorList.Count = Count;
- Op->VectorList.NumElements = NumElements;
- Op->VectorList.ElementWidth = ElementWidth;
- Op->VectorList.RegisterKind = RegisterKind;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand>
- CreateVectorIndex(unsigned Idx, SMLoc S, SMLoc E, MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_VectorIndex, Ctx);
- Op->VectorIndex.Val = Idx;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand> CreateImm(const MCExpr *Val, SMLoc S,
- SMLoc E, MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_Immediate, Ctx);
- Op->Imm.Val = Val;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand> CreateShiftedImm(const MCExpr *Val,
- unsigned ShiftAmount,
- SMLoc S, SMLoc E,
- MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_ShiftedImm, Ctx);
- Op->ShiftedImm .Val = Val;
- Op->ShiftedImm.ShiftAmount = ShiftAmount;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand>
- CreateCondCode(AArch64CC::CondCode Code, SMLoc S, SMLoc E, MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_CondCode, Ctx);
- Op->CondCode.Code = Code;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand>
- CreateFPImm(APFloat Val, bool IsExact, SMLoc S, MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_FPImm, Ctx);
- Op->FPImm.Val = Val.bitcastToAPInt().getSExtValue();
- Op->FPImm.IsExact = IsExact;
- Op->StartLoc = S;
- Op->EndLoc = S;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand> CreateBarrier(unsigned Val,
- StringRef Str,
- SMLoc S,
+ void addMRSSystemRegisterOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::createImm(SysReg.MRSReg));
+ }
+
+ void addMSRSystemRegisterOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::createImm(SysReg.MSRReg));
+ }
+
+ void addSystemPStateFieldWithImm0_1Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::createImm(SysReg.PStateField));
+ }
+
+ void addSystemPStateFieldWithImm0_15Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::createImm(SysReg.PStateField));
+ }
+
+ void addSysCROperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createImm(getSysCR()));
+ }
+
+ void addPrefetchOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createImm(getPrefetch()));
+ }
+
+ void addPSBHintOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createImm(getPSBHint()));
+ }
+
+ void addBTIHintOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createImm(getBTIHint()));
+ }
+
+ void addShifterOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ unsigned Imm =
+ AArch64_AM::getShifterImm(getShiftExtendType(), getShiftExtendAmount());
+ Inst.addOperand(MCOperand::createImm(Imm));
+ }
+
+ void addExtendOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ if (ET == AArch64_AM::LSL) ET = AArch64_AM::UXTW;
+ unsigned Imm = AArch64_AM::getArithExtendImm(ET, getShiftExtendAmount());
+ Inst.addOperand(MCOperand::createImm(Imm));
+ }
+
+ void addExtend64Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ if (ET == AArch64_AM::LSL) ET = AArch64_AM::UXTX;
+ unsigned Imm = AArch64_AM::getArithExtendImm(ET, getShiftExtendAmount());
+ Inst.addOperand(MCOperand::createImm(Imm));
+ }
+
+ void addMemExtendOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ bool IsSigned = ET == AArch64_AM::SXTW || ET == AArch64_AM::SXTX;
+ Inst.addOperand(MCOperand::createImm(IsSigned));
+ Inst.addOperand(MCOperand::createImm(getShiftExtendAmount() != 0));
+ }
+
+ // For 8-bit load/store instructions with a register offset, both the
+ // "DoShift" and "NoShift" variants have a shift of 0. Because of this,
+ // they're disambiguated by whether the shift was explicit or implicit rather
+ // than its size.
+ void addMemExtend8Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ bool IsSigned = ET == AArch64_AM::SXTW || ET == AArch64_AM::SXTX;
+ Inst.addOperand(MCOperand::createImm(IsSigned));
+ Inst.addOperand(MCOperand::createImm(hasShiftExtendAmount()));
+ }
+
+ template<int Shift>
+ void addMOVZMovAliasOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ if (CE) {
+ uint64_t Value = CE->getValue();
+ Inst.addOperand(MCOperand::createImm((Value >> Shift) & 0xffff));
+ } else {
+ addExpr(Inst, getImm());
+ }
+ }
+
+ template<int Shift>
+ void addMOVNMovAliasOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+
+ const MCConstantExpr *CE = cast<MCConstantExpr>(getImm());
+ uint64_t Value = CE->getValue();
+ Inst.addOperand(MCOperand::createImm((~Value >> Shift) & 0xffff));
+ }
+
+ void addComplexRotationEvenOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
+ Inst.addOperand(MCOperand::createImm(MCE->getValue() / 90));
+ }
+
+ void addComplexRotationOddOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = cast<MCConstantExpr>(getImm());
+ Inst.addOperand(MCOperand::createImm((MCE->getValue() - 90) / 180));
+ }
+
+ void print(raw_ostream &OS) const override;
+
+ static std::unique_ptr<AArch64Operand>
+ CreateToken(StringRef Str, bool IsSuffix, SMLoc S, MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_Token, Ctx);
+ Op->Tok.Data = Str.data();
+ Op->Tok.Length = Str.size();
+ Op->Tok.IsSuffix = IsSuffix;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand>
+ CreateReg(unsigned RegNum, RegKind Kind, SMLoc S, SMLoc E, MCContext &Ctx,
+ RegConstraintEqualityTy EqTy = RegConstraintEqualityTy::EqualsReg,
+ AArch64_AM::ShiftExtendType ExtTy = AArch64_AM::LSL,
+ unsigned ShiftAmount = 0,
+ unsigned HasExplicitAmount = false) {
+ auto Op = std::make_unique<AArch64Operand>(k_Register, Ctx);
+ Op->Reg.RegNum = RegNum;
+ Op->Reg.Kind = Kind;
+ Op->Reg.ElementWidth = 0;
+ Op->Reg.EqualityTy = EqTy;
+ Op->Reg.ShiftExtend.Type = ExtTy;
+ Op->Reg.ShiftExtend.Amount = ShiftAmount;
+ Op->Reg.ShiftExtend.HasExplicitAmount = HasExplicitAmount;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand>
+ CreateVectorReg(unsigned RegNum, RegKind Kind, unsigned ElementWidth,
+ SMLoc S, SMLoc E, MCContext &Ctx,
+ AArch64_AM::ShiftExtendType ExtTy = AArch64_AM::LSL,
+ unsigned ShiftAmount = 0,
+ unsigned HasExplicitAmount = false) {
+ assert((Kind == RegKind::NeonVector || Kind == RegKind::SVEDataVector ||
+ Kind == RegKind::SVEPredicateVector) &&
+ "Invalid vector kind");
+ auto Op = CreateReg(RegNum, Kind, S, E, Ctx, EqualsReg, ExtTy, ShiftAmount,
+ HasExplicitAmount);
+ Op->Reg.ElementWidth = ElementWidth;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand>
+ CreateVectorList(unsigned RegNum, unsigned Count, unsigned NumElements,
+ unsigned ElementWidth, RegKind RegisterKind, SMLoc S, SMLoc E,
+ MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_VectorList, Ctx);
+ Op->VectorList.RegNum = RegNum;
+ Op->VectorList.Count = Count;
+ Op->VectorList.NumElements = NumElements;
+ Op->VectorList.ElementWidth = ElementWidth;
+ Op->VectorList.RegisterKind = RegisterKind;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand>
+ CreateVectorIndex(unsigned Idx, SMLoc S, SMLoc E, MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_VectorIndex, Ctx);
+ Op->VectorIndex.Val = Idx;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand> CreateImm(const MCExpr *Val, SMLoc S,
+ SMLoc E, MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_Immediate, Ctx);
+ Op->Imm.Val = Val;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand> CreateShiftedImm(const MCExpr *Val,
+ unsigned ShiftAmount,
+ SMLoc S, SMLoc E,
+ MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_ShiftedImm, Ctx);
+ Op->ShiftedImm .Val = Val;
+ Op->ShiftedImm.ShiftAmount = ShiftAmount;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand>
+ CreateCondCode(AArch64CC::CondCode Code, SMLoc S, SMLoc E, MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_CondCode, Ctx);
+ Op->CondCode.Code = Code;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand>
+ CreateFPImm(APFloat Val, bool IsExact, SMLoc S, MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_FPImm, Ctx);
+ Op->FPImm.Val = Val.bitcastToAPInt().getSExtValue();
+ Op->FPImm.IsExact = IsExact;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand> CreateBarrier(unsigned Val,
+ StringRef Str,
+ SMLoc S,
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();
+ 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;
- }
-
- static std::unique_ptr<AArch64Operand> CreateSysReg(StringRef Str, SMLoc S,
- uint32_t MRSReg,
- uint32_t MSRReg,
- uint32_t PStateField,
- MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_SysReg, Ctx);
- Op->SysReg.Data = Str.data();
- Op->SysReg.Length = Str.size();
- Op->SysReg.MRSReg = MRSReg;
- Op->SysReg.MSRReg = MSRReg;
- Op->SysReg.PStateField = PStateField;
- Op->StartLoc = S;
- Op->EndLoc = S;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand> CreateSysCR(unsigned Val, SMLoc S,
- SMLoc E, MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_SysCR, Ctx);
- Op->SysCRImm.Val = Val;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand> CreatePrefetch(unsigned Val,
- StringRef Str,
- SMLoc S,
- MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_Prefetch, Ctx);
- Op->Prefetch.Val = Val;
- Op->Barrier.Data = Str.data();
- Op->Barrier.Length = Str.size();
- Op->StartLoc = S;
- Op->EndLoc = S;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand> CreatePSBHint(unsigned Val,
- StringRef Str,
- SMLoc S,
- MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_PSBHint, Ctx);
- Op->PSBHint.Val = Val;
- Op->PSBHint.Data = Str.data();
- Op->PSBHint.Length = Str.size();
- Op->StartLoc = S;
- Op->EndLoc = S;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand> CreateBTIHint(unsigned Val,
- StringRef Str,
- SMLoc S,
- MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_BTIHint, Ctx);
- Op->BTIHint.Val = Val << 1 | 32;
- Op->BTIHint.Data = Str.data();
- Op->BTIHint.Length = Str.size();
- Op->StartLoc = S;
- Op->EndLoc = S;
- return Op;
- }
-
- static std::unique_ptr<AArch64Operand>
- CreateShiftExtend(AArch64_AM::ShiftExtendType ShOp, unsigned Val,
- bool HasExplicitAmount, SMLoc S, SMLoc E, MCContext &Ctx) {
- auto Op = std::make_unique<AArch64Operand>(k_ShiftExtend, Ctx);
- Op->ShiftExtend.Type = ShOp;
- Op->ShiftExtend.Amount = Val;
- Op->ShiftExtend.HasExplicitAmount = HasExplicitAmount;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
-};
-
-} // end anonymous namespace.
-
-void AArch64Operand::print(raw_ostream &OS) const {
- switch (Kind) {
- case k_FPImm:
- OS << "<fpimm " << getFPImm().bitcastToAPInt().getZExtValue();
- if (!getFPImmIsExact())
- OS << " (inexact)";
- OS << ">";
- break;
- case k_Barrier: {
- StringRef Name = getBarrierName();
- if (!Name.empty())
- OS << "<barrier " << Name << ">";
- else
- OS << "<barrier invalid #" << getBarrier() << ">";
- break;
- }
- case k_Immediate:
- OS << *getImm();
- break;
- case k_ShiftedImm: {
- unsigned Shift = getShiftedImmShift();
- OS << "<shiftedimm ";
- OS << *getShiftedImmVal();
- OS << ", lsl #" << AArch64_AM::getShiftValue(Shift) << ">";
- break;
- }
- case k_CondCode:
- OS << "<condcode " << getCondCode() << ">";
- break;
- case k_VectorList: {
- OS << "<vectorlist ";
- unsigned Reg = getVectorListStart();
- for (unsigned i = 0, e = getVectorListCount(); i != e; ++i)
- OS << Reg + i << " ";
- OS << ">";
- break;
- }
- case k_VectorIndex:
- OS << "<vectorindex " << getVectorIndex() << ">";
- break;
- case k_SysReg:
- OS << "<sysreg: " << getSysReg() << '>';
- break;
- case k_Token:
- OS << "'" << getToken() << "'";
- break;
- case k_SysCR:
- OS << "c" << getSysCR();
- break;
- case k_Prefetch: {
- StringRef Name = getPrefetchName();
- if (!Name.empty())
- OS << "<prfop " << Name << ">";
- else
- OS << "<prfop invalid #" << getPrefetch() << ">";
- break;
- }
- case k_PSBHint:
- OS << getPSBHintName();
- break;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand> CreateSysReg(StringRef Str, SMLoc S,
+ uint32_t MRSReg,
+ uint32_t MSRReg,
+ uint32_t PStateField,
+ MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_SysReg, Ctx);
+ Op->SysReg.Data = Str.data();
+ Op->SysReg.Length = Str.size();
+ Op->SysReg.MRSReg = MRSReg;
+ Op->SysReg.MSRReg = MSRReg;
+ Op->SysReg.PStateField = PStateField;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand> CreateSysCR(unsigned Val, SMLoc S,
+ SMLoc E, MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_SysCR, Ctx);
+ Op->SysCRImm.Val = Val;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand> CreatePrefetch(unsigned Val,
+ StringRef Str,
+ SMLoc S,
+ MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_Prefetch, Ctx);
+ Op->Prefetch.Val = Val;
+ Op->Barrier.Data = Str.data();
+ Op->Barrier.Length = Str.size();
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand> CreatePSBHint(unsigned Val,
+ StringRef Str,
+ SMLoc S,
+ MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_PSBHint, Ctx);
+ Op->PSBHint.Val = Val;
+ Op->PSBHint.Data = Str.data();
+ Op->PSBHint.Length = Str.size();
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand> CreateBTIHint(unsigned Val,
+ StringRef Str,
+ SMLoc S,
+ MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_BTIHint, Ctx);
+ Op->BTIHint.Val = Val << 1 | 32;
+ Op->BTIHint.Data = Str.data();
+ Op->BTIHint.Length = Str.size();
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static std::unique_ptr<AArch64Operand>
+ CreateShiftExtend(AArch64_AM::ShiftExtendType ShOp, unsigned Val,
+ bool HasExplicitAmount, SMLoc S, SMLoc E, MCContext &Ctx) {
+ auto Op = std::make_unique<AArch64Operand>(k_ShiftExtend, Ctx);
+ Op->ShiftExtend.Type = ShOp;
+ Op->ShiftExtend.Amount = Val;
+ Op->ShiftExtend.HasExplicitAmount = HasExplicitAmount;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+};
+
+} // end anonymous namespace.
+
+void AArch64Operand::print(raw_ostream &OS) const {
+ switch (Kind) {
+ case k_FPImm:
+ OS << "<fpimm " << getFPImm().bitcastToAPInt().getZExtValue();
+ if (!getFPImmIsExact())
+ OS << " (inexact)";
+ OS << ">";
+ break;
+ case k_Barrier: {
+ StringRef Name = getBarrierName();
+ if (!Name.empty())
+ OS << "<barrier " << Name << ">";
+ else
+ OS << "<barrier invalid #" << getBarrier() << ">";
+ break;
+ }
+ case k_Immediate:
+ OS << *getImm();
+ break;
+ case k_ShiftedImm: {
+ unsigned Shift = getShiftedImmShift();
+ OS << "<shiftedimm ";
+ OS << *getShiftedImmVal();
+ OS << ", lsl #" << AArch64_AM::getShiftValue(Shift) << ">";
+ break;
+ }
+ case k_CondCode:
+ OS << "<condcode " << getCondCode() << ">";
+ break;
+ case k_VectorList: {
+ OS << "<vectorlist ";
+ unsigned Reg = getVectorListStart();
+ for (unsigned i = 0, e = getVectorListCount(); i != e; ++i)
+ OS << Reg + i << " ";
+ OS << ">";
+ break;
+ }
+ case k_VectorIndex:
+ OS << "<vectorindex " << getVectorIndex() << ">";
+ break;
+ case k_SysReg:
+ OS << "<sysreg: " << getSysReg() << '>';
+ break;
+ case k_Token:
+ OS << "'" << getToken() << "'";
+ break;
+ case k_SysCR:
+ OS << "c" << getSysCR();
+ break;
+ case k_Prefetch: {
+ StringRef Name = getPrefetchName();
+ if (!Name.empty())
+ OS << "<prfop " << Name << ">";
+ else
+ OS << "<prfop invalid #" << getPrefetch() << ">";
+ break;
+ }
+ 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_ShiftExtend:
- OS << "<" << AArch64_AM::getShiftExtendName(getShiftExtendType()) << " #"
- << getShiftExtendAmount();
- if (!hasShiftExtendAmount())
- OS << "<imp>";
- OS << '>';
- break;
- }
-}
-
-/// @name Auto-generated Match Functions
-/// {
-
-static unsigned MatchRegisterName(StringRef Name);
-
-/// }
-
-static unsigned MatchNeonVectorRegName(StringRef Name) {
- return StringSwitch<unsigned>(Name.lower())
- .Case("v0", AArch64::Q0)
- .Case("v1", AArch64::Q1)
- .Case("v2", AArch64::Q2)
- .Case("v3", AArch64::Q3)
- .Case("v4", AArch64::Q4)
- .Case("v5", AArch64::Q5)
- .Case("v6", AArch64::Q6)
- .Case("v7", AArch64::Q7)
- .Case("v8", AArch64::Q8)
- .Case("v9", AArch64::Q9)
- .Case("v10", AArch64::Q10)
- .Case("v11", AArch64::Q11)
- .Case("v12", AArch64::Q12)
- .Case("v13", AArch64::Q13)
- .Case("v14", AArch64::Q14)
- .Case("v15", AArch64::Q15)
- .Case("v16", AArch64::Q16)
- .Case("v17", AArch64::Q17)
- .Case("v18", AArch64::Q18)
- .Case("v19", AArch64::Q19)
- .Case("v20", AArch64::Q20)
- .Case("v21", AArch64::Q21)
- .Case("v22", AArch64::Q22)
- .Case("v23", AArch64::Q23)
- .Case("v24", AArch64::Q24)
- .Case("v25", AArch64::Q25)
- .Case("v26", AArch64::Q26)
- .Case("v27", AArch64::Q27)
- .Case("v28", AArch64::Q28)
- .Case("v29", AArch64::Q29)
- .Case("v30", AArch64::Q30)
- .Case("v31", AArch64::Q31)
- .Default(0);
-}
-
-/// Returns an optional pair of (#elements, element-width) if Suffix
-/// is a valid vector kind. Where the number of elements in a vector
-/// or the vector width is implicit or explicitly unknown (but still a
-/// valid suffix kind), 0 is used.
-static Optional<std::pair<int, int>> parseVectorKind(StringRef Suffix,
- RegKind VectorKind) {
- std::pair<int, int> Res = {-1, -1};
-
- switch (VectorKind) {
- case RegKind::NeonVector:
- Res =
- StringSwitch<std::pair<int, int>>(Suffix.lower())
- .Case("", {0, 0})
- .Case(".1d", {1, 64})
- .Case(".1q", {1, 128})
- // '.2h' needed for fp16 scalar pairwise reductions
- .Case(".2h", {2, 16})
- .Case(".2s", {2, 32})
- .Case(".2d", {2, 64})
- // '.4b' is another special case for the ARMv8.2a dot product
- // operand
- .Case(".4b", {4, 8})
- .Case(".4h", {4, 16})
- .Case(".4s", {4, 32})
- .Case(".8b", {8, 8})
- .Case(".8h", {8, 16})
- .Case(".16b", {16, 8})
- // Accept the width neutral ones, too, for verbose syntax. If those
- // aren't used in the right places, the token operand won't match so
- // all will work out.
- .Case(".b", {0, 8})
- .Case(".h", {0, 16})
- .Case(".s", {0, 32})
- .Case(".d", {0, 64})
- .Default({-1, -1});
- break;
- case RegKind::SVEPredicateVector:
- case RegKind::SVEDataVector:
- Res = StringSwitch<std::pair<int, int>>(Suffix.lower())
- .Case("", {0, 0})
- .Case(".b", {0, 8})
- .Case(".h", {0, 16})
- .Case(".s", {0, 32})
- .Case(".d", {0, 64})
- .Case(".q", {0, 128})
- .Default({-1, -1});
- break;
- default:
- llvm_unreachable("Unsupported RegKind");
- }
-
- if (Res == std::make_pair(-1, -1))
- return Optional<std::pair<int, int>>();
-
- return Optional<std::pair<int, int>>(Res);
-}
-
-static bool isValidVectorKind(StringRef Suffix, RegKind VectorKind) {
- return parseVectorKind(Suffix, VectorKind).hasValue();
-}
-
-static unsigned matchSVEDataVectorRegName(StringRef Name) {
- return StringSwitch<unsigned>(Name.lower())
- .Case("z0", AArch64::Z0)
- .Case("z1", AArch64::Z1)
- .Case("z2", AArch64::Z2)
- .Case("z3", AArch64::Z3)
- .Case("z4", AArch64::Z4)
- .Case("z5", AArch64::Z5)
- .Case("z6", AArch64::Z6)
- .Case("z7", AArch64::Z7)
- .Case("z8", AArch64::Z8)
- .Case("z9", AArch64::Z9)
- .Case("z10", AArch64::Z10)
- .Case("z11", AArch64::Z11)
- .Case("z12", AArch64::Z12)
- .Case("z13", AArch64::Z13)
- .Case("z14", AArch64::Z14)
- .Case("z15", AArch64::Z15)
- .Case("z16", AArch64::Z16)
- .Case("z17", AArch64::Z17)
- .Case("z18", AArch64::Z18)
- .Case("z19", AArch64::Z19)
- .Case("z20", AArch64::Z20)
- .Case("z21", AArch64::Z21)
- .Case("z22", AArch64::Z22)
- .Case("z23", AArch64::Z23)
- .Case("z24", AArch64::Z24)
- .Case("z25", AArch64::Z25)
- .Case("z26", AArch64::Z26)
- .Case("z27", AArch64::Z27)
- .Case("z28", AArch64::Z28)
- .Case("z29", AArch64::Z29)
- .Case("z30", AArch64::Z30)
- .Case("z31", AArch64::Z31)
- .Default(0);
-}
-
-static unsigned matchSVEPredicateVectorRegName(StringRef Name) {
- return StringSwitch<unsigned>(Name.lower())
- .Case("p0", AArch64::P0)
- .Case("p1", AArch64::P1)
- .Case("p2", AArch64::P2)
- .Case("p3", AArch64::P3)
- .Case("p4", AArch64::P4)
- .Case("p5", AArch64::P5)
- .Case("p6", AArch64::P6)
- .Case("p7", AArch64::P7)
- .Case("p8", AArch64::P8)
- .Case("p9", AArch64::P9)
- .Case("p10", AArch64::P10)
- .Case("p11", AArch64::P11)
- .Case("p12", AArch64::P12)
- .Case("p13", AArch64::P13)
- .Case("p14", AArch64::P14)
- .Case("p15", AArch64::P15)
- .Default(0);
-}
-
-bool AArch64AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
- SMLoc &EndLoc) {
- return tryParseRegister(RegNo, StartLoc, EndLoc) != MatchOperand_Success;
-}
-
-OperandMatchResultTy AArch64AsmParser::tryParseRegister(unsigned &RegNo,
- SMLoc &StartLoc,
- SMLoc &EndLoc) {
- StartLoc = getLoc();
- auto Res = tryParseScalarRegister(RegNo);
- EndLoc = SMLoc::getFromPointer(getLoc().getPointer() - 1);
- return Res;
-}
-
-// Matches a register name or register alias previously defined by '.req'
-unsigned AArch64AsmParser::matchRegisterNameAlias(StringRef Name,
- RegKind Kind) {
- unsigned RegNum = 0;
- if ((RegNum = matchSVEDataVectorRegName(Name)))
- return Kind == RegKind::SVEDataVector ? RegNum : 0;
-
- if ((RegNum = matchSVEPredicateVectorRegName(Name)))
- return Kind == RegKind::SVEPredicateVector ? RegNum : 0;
-
- if ((RegNum = MatchNeonVectorRegName(Name)))
- return Kind == RegKind::NeonVector ? RegNum : 0;
-
- // The parsed register must be of RegKind Scalar
- if ((RegNum = MatchRegisterName(Name)))
- return Kind == RegKind::Scalar ? RegNum : 0;
-
- if (!RegNum) {
- // Handle a few common aliases of registers.
- if (auto RegNum = StringSwitch<unsigned>(Name.lower())
- .Case("fp", AArch64::FP)
- .Case("lr", AArch64::LR)
- .Case("x31", AArch64::XZR)
- .Case("w31", AArch64::WZR)
- .Default(0))
- return Kind == RegKind::Scalar ? RegNum : 0;
-
- // Check for aliases registered via .req. Canonicalize to lower case.
- // That's more consistent since register names are case insensitive, and
- // it's how the original entry was passed in from MC/MCParser/AsmParser.
- auto Entry = RegisterReqs.find(Name.lower());
- if (Entry == RegisterReqs.end())
- return 0;
-
- // set RegNum if the match is the right kind of register
- if (Kind == Entry->getValue().first)
- RegNum = Entry->getValue().second;
- }
- return RegNum;
-}
-
-/// tryParseScalarRegister - Try to parse a register name. The token must be an
-/// Identifier when called, and if it is a register name the token is eaten and
-/// the register is added to the operand list.
-OperandMatchResultTy
-AArch64AsmParser::tryParseScalarRegister(unsigned &RegNum) {
- MCAsmParser &Parser = getParser();
- const AsmToken &Tok = Parser.getTok();
- if (Tok.isNot(AsmToken::Identifier))
- return MatchOperand_NoMatch;
-
- std::string lowerCase = Tok.getString().lower();
- unsigned Reg = matchRegisterNameAlias(lowerCase, RegKind::Scalar);
- if (Reg == 0)
- return MatchOperand_NoMatch;
-
- RegNum = Reg;
- Parser.Lex(); // Eat identifier token.
- return MatchOperand_Success;
-}
-
-/// tryParseSysCROperand - Try to parse a system instruction CR operand name.
-OperandMatchResultTy
-AArch64AsmParser::tryParseSysCROperand(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- SMLoc S = getLoc();
-
- if (Parser.getTok().isNot(AsmToken::Identifier)) {
- Error(S, "Expected cN operand where 0 <= N <= 15");
- return MatchOperand_ParseFail;
- }
-
- StringRef Tok = Parser.getTok().getIdentifier();
- if (Tok[0] != 'c' && Tok[0] != 'C') {
- Error(S, "Expected cN operand where 0 <= N <= 15");
- return MatchOperand_ParseFail;
- }
-
- uint32_t CRNum;
- bool BadNum = Tok.drop_front().getAsInteger(10, CRNum);
- if (BadNum || CRNum > 15) {
- Error(S, "Expected cN operand where 0 <= N <= 15");
- return MatchOperand_ParseFail;
- }
-
- Parser.Lex(); // Eat identifier token.
- Operands.push_back(
- AArch64Operand::CreateSysCR(CRNum, S, getLoc(), getContext()));
- return MatchOperand_Success;
-}
-
-/// tryParsePrefetch - Try to parse a prefetch operand.
-template <bool IsSVEPrefetch>
-OperandMatchResultTy
-AArch64AsmParser::tryParsePrefetch(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- SMLoc S = getLoc();
- const AsmToken &Tok = Parser.getTok();
-
- auto LookupByName = [](StringRef N) {
- if (IsSVEPrefetch) {
- if (auto Res = AArch64SVEPRFM::lookupSVEPRFMByName(N))
- return Optional<unsigned>(Res->Encoding);
- } else if (auto Res = AArch64PRFM::lookupPRFMByName(N))
- return Optional<unsigned>(Res->Encoding);
- return Optional<unsigned>();
- };
-
- auto LookupByEncoding = [](unsigned E) {
- if (IsSVEPrefetch) {
- if (auto Res = AArch64SVEPRFM::lookupSVEPRFMByEncoding(E))
- return Optional<StringRef>(Res->Name);
- } else if (auto Res = AArch64PRFM::lookupPRFMByEncoding(E))
- return Optional<StringRef>(Res->Name);
- return Optional<StringRef>();
- };
- unsigned MaxVal = IsSVEPrefetch ? 15 : 31;
-
- // Either an identifier for named values or a 5-bit immediate.
- // Eat optional hash.
- if (parseOptionalToken(AsmToken::Hash) ||
- Tok.is(AsmToken::Integer)) {
- const MCExpr *ImmVal;
- if (getParser().parseExpression(ImmVal))
- return MatchOperand_ParseFail;
-
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
- if (!MCE) {
- TokError("immediate value expected for prefetch operand");
- return MatchOperand_ParseFail;
- }
- unsigned prfop = MCE->getValue();
- if (prfop > MaxVal) {
- TokError("prefetch operand out of range, [0," + utostr(MaxVal) +
- "] expected");
- return MatchOperand_ParseFail;
- }
-
- auto PRFM = LookupByEncoding(MCE->getValue());
- Operands.push_back(AArch64Operand::CreatePrefetch(
- prfop, PRFM.getValueOr(""), S, getContext()));
- return MatchOperand_Success;
- }
-
- if (Tok.isNot(AsmToken::Identifier)) {
- TokError("prefetch hint expected");
- return MatchOperand_ParseFail;
- }
-
- auto PRFM = LookupByName(Tok.getString());
- if (!PRFM) {
- TokError("prefetch hint expected");
- return MatchOperand_ParseFail;
- }
-
- Operands.push_back(AArch64Operand::CreatePrefetch(
- *PRFM, Tok.getString(), S, getContext()));
- Parser.Lex(); // Eat identifier token.
- return MatchOperand_Success;
-}
-
-/// tryParsePSBHint - Try to parse a PSB operand, mapped to Hint command
-OperandMatchResultTy
-AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- SMLoc S = getLoc();
- const AsmToken &Tok = Parser.getTok();
- if (Tok.isNot(AsmToken::Identifier)) {
- TokError("invalid operand for instruction");
- return MatchOperand_ParseFail;
- }
-
- auto PSB = AArch64PSBHint::lookupPSBByName(Tok.getString());
- if (!PSB) {
- TokError("invalid operand for instruction");
- return MatchOperand_ParseFail;
- }
-
- Operands.push_back(AArch64Operand::CreatePSBHint(
- PSB->Encoding, Tok.getString(), S, getContext()));
- Parser.Lex(); // Eat identifier token.
- return MatchOperand_Success;
-}
-
-/// tryParseBTIHint - Try to parse a BTI operand, mapped to Hint command
-OperandMatchResultTy
-AArch64AsmParser::tryParseBTIHint(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- SMLoc S = getLoc();
- const AsmToken &Tok = Parser.getTok();
- if (Tok.isNot(AsmToken::Identifier)) {
- TokError("invalid operand for instruction");
- return MatchOperand_ParseFail;
- }
-
- auto BTI = AArch64BTIHint::lookupBTIByName(Tok.getString());
- if (!BTI) {
- TokError("invalid operand for instruction");
- return MatchOperand_ParseFail;
- }
-
- Operands.push_back(AArch64Operand::CreateBTIHint(
- BTI->Encoding, Tok.getString(), S, getContext()));
- Parser.Lex(); // Eat identifier token.
- return MatchOperand_Success;
-}
-
-/// tryParseAdrpLabel - Parse and validate a source label for the ADRP
-/// instruction.
-OperandMatchResultTy
-AArch64AsmParser::tryParseAdrpLabel(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- SMLoc S = getLoc();
- const MCExpr *Expr = nullptr;
-
- if (Parser.getTok().is(AsmToken::Hash)) {
- Parser.Lex(); // Eat hash token.
- }
-
- if (parseSymbolicImmVal(Expr))
- return MatchOperand_ParseFail;
-
- AArch64MCExpr::VariantKind ELFRefKind;
- MCSymbolRefExpr::VariantKind DarwinRefKind;
- int64_t Addend;
- if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
- if (DarwinRefKind == MCSymbolRefExpr::VK_None &&
- ELFRefKind == AArch64MCExpr::VK_INVALID) {
- // No modifier was specified at all; this is the syntax for an ELF basic
- // ADRP relocation (unfortunately).
- Expr =
- AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_PAGE, getContext());
- } else if ((DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGE ||
- DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGE) &&
- Addend != 0) {
- Error(S, "gotpage label reference not allowed an addend");
- return MatchOperand_ParseFail;
- } else if (DarwinRefKind != MCSymbolRefExpr::VK_PAGE &&
- DarwinRefKind != MCSymbolRefExpr::VK_GOTPAGE &&
- DarwinRefKind != MCSymbolRefExpr::VK_TLVPPAGE &&
- ELFRefKind != AArch64MCExpr::VK_ABS_PAGE_NC &&
- ELFRefKind != AArch64MCExpr::VK_GOT_PAGE &&
+ case k_Register:
+ OS << "<register " << getReg() << ">";
+ if (!getShiftExtendAmount() && !hasShiftExtendAmount())
+ break;
+ LLVM_FALLTHROUGH;
+ case k_ShiftExtend:
+ OS << "<" << AArch64_AM::getShiftExtendName(getShiftExtendType()) << " #"
+ << getShiftExtendAmount();
+ if (!hasShiftExtendAmount())
+ OS << "<imp>";
+ OS << '>';
+ break;
+ }
+}
+
+/// @name Auto-generated Match Functions
+/// {
+
+static unsigned MatchRegisterName(StringRef Name);
+
+/// }
+
+static unsigned MatchNeonVectorRegName(StringRef Name) {
+ return StringSwitch<unsigned>(Name.lower())
+ .Case("v0", AArch64::Q0)
+ .Case("v1", AArch64::Q1)
+ .Case("v2", AArch64::Q2)
+ .Case("v3", AArch64::Q3)
+ .Case("v4", AArch64::Q4)
+ .Case("v5", AArch64::Q5)
+ .Case("v6", AArch64::Q6)
+ .Case("v7", AArch64::Q7)
+ .Case("v8", AArch64::Q8)
+ .Case("v9", AArch64::Q9)
+ .Case("v10", AArch64::Q10)
+ .Case("v11", AArch64::Q11)
+ .Case("v12", AArch64::Q12)
+ .Case("v13", AArch64::Q13)
+ .Case("v14", AArch64::Q14)
+ .Case("v15", AArch64::Q15)
+ .Case("v16", AArch64::Q16)
+ .Case("v17", AArch64::Q17)
+ .Case("v18", AArch64::Q18)
+ .Case("v19", AArch64::Q19)
+ .Case("v20", AArch64::Q20)
+ .Case("v21", AArch64::Q21)
+ .Case("v22", AArch64::Q22)
+ .Case("v23", AArch64::Q23)
+ .Case("v24", AArch64::Q24)
+ .Case("v25", AArch64::Q25)
+ .Case("v26", AArch64::Q26)
+ .Case("v27", AArch64::Q27)
+ .Case("v28", AArch64::Q28)
+ .Case("v29", AArch64::Q29)
+ .Case("v30", AArch64::Q30)
+ .Case("v31", AArch64::Q31)
+ .Default(0);
+}
+
+/// Returns an optional pair of (#elements, element-width) if Suffix
+/// is a valid vector kind. Where the number of elements in a vector
+/// or the vector width is implicit or explicitly unknown (but still a
+/// valid suffix kind), 0 is used.
+static Optional<std::pair<int, int>> parseVectorKind(StringRef Suffix,
+ RegKind VectorKind) {
+ std::pair<int, int> Res = {-1, -1};
+
+ switch (VectorKind) {
+ case RegKind::NeonVector:
+ Res =
+ StringSwitch<std::pair<int, int>>(Suffix.lower())
+ .Case("", {0, 0})
+ .Case(".1d", {1, 64})
+ .Case(".1q", {1, 128})
+ // '.2h' needed for fp16 scalar pairwise reductions
+ .Case(".2h", {2, 16})
+ .Case(".2s", {2, 32})
+ .Case(".2d", {2, 64})
+ // '.4b' is another special case for the ARMv8.2a dot product
+ // operand
+ .Case(".4b", {4, 8})
+ .Case(".4h", {4, 16})
+ .Case(".4s", {4, 32})
+ .Case(".8b", {8, 8})
+ .Case(".8h", {8, 16})
+ .Case(".16b", {16, 8})
+ // Accept the width neutral ones, too, for verbose syntax. If those
+ // aren't used in the right places, the token operand won't match so
+ // all will work out.
+ .Case(".b", {0, 8})
+ .Case(".h", {0, 16})
+ .Case(".s", {0, 32})
+ .Case(".d", {0, 64})
+ .Default({-1, -1});
+ break;
+ case RegKind::SVEPredicateVector:
+ case RegKind::SVEDataVector:
+ Res = StringSwitch<std::pair<int, int>>(Suffix.lower())
+ .Case("", {0, 0})
+ .Case(".b", {0, 8})
+ .Case(".h", {0, 16})
+ .Case(".s", {0, 32})
+ .Case(".d", {0, 64})
+ .Case(".q", {0, 128})
+ .Default({-1, -1});
+ break;
+ default:
+ llvm_unreachable("Unsupported RegKind");
+ }
+
+ if (Res == std::make_pair(-1, -1))
+ return Optional<std::pair<int, int>>();
+
+ return Optional<std::pair<int, int>>(Res);
+}
+
+static bool isValidVectorKind(StringRef Suffix, RegKind VectorKind) {
+ return parseVectorKind(Suffix, VectorKind).hasValue();
+}
+
+static unsigned matchSVEDataVectorRegName(StringRef Name) {
+ return StringSwitch<unsigned>(Name.lower())
+ .Case("z0", AArch64::Z0)
+ .Case("z1", AArch64::Z1)
+ .Case("z2", AArch64::Z2)
+ .Case("z3", AArch64::Z3)
+ .Case("z4", AArch64::Z4)
+ .Case("z5", AArch64::Z5)
+ .Case("z6", AArch64::Z6)
+ .Case("z7", AArch64::Z7)
+ .Case("z8", AArch64::Z8)
+ .Case("z9", AArch64::Z9)
+ .Case("z10", AArch64::Z10)
+ .Case("z11", AArch64::Z11)
+ .Case("z12", AArch64::Z12)
+ .Case("z13", AArch64::Z13)
+ .Case("z14", AArch64::Z14)
+ .Case("z15", AArch64::Z15)
+ .Case("z16", AArch64::Z16)
+ .Case("z17", AArch64::Z17)
+ .Case("z18", AArch64::Z18)
+ .Case("z19", AArch64::Z19)
+ .Case("z20", AArch64::Z20)
+ .Case("z21", AArch64::Z21)
+ .Case("z22", AArch64::Z22)
+ .Case("z23", AArch64::Z23)
+ .Case("z24", AArch64::Z24)
+ .Case("z25", AArch64::Z25)
+ .Case("z26", AArch64::Z26)
+ .Case("z27", AArch64::Z27)
+ .Case("z28", AArch64::Z28)
+ .Case("z29", AArch64::Z29)
+ .Case("z30", AArch64::Z30)
+ .Case("z31", AArch64::Z31)
+ .Default(0);
+}
+
+static unsigned matchSVEPredicateVectorRegName(StringRef Name) {
+ return StringSwitch<unsigned>(Name.lower())
+ .Case("p0", AArch64::P0)
+ .Case("p1", AArch64::P1)
+ .Case("p2", AArch64::P2)
+ .Case("p3", AArch64::P3)
+ .Case("p4", AArch64::P4)
+ .Case("p5", AArch64::P5)
+ .Case("p6", AArch64::P6)
+ .Case("p7", AArch64::P7)
+ .Case("p8", AArch64::P8)
+ .Case("p9", AArch64::P9)
+ .Case("p10", AArch64::P10)
+ .Case("p11", AArch64::P11)
+ .Case("p12", AArch64::P12)
+ .Case("p13", AArch64::P13)
+ .Case("p14", AArch64::P14)
+ .Case("p15", AArch64::P15)
+ .Default(0);
+}
+
+bool AArch64AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
+ SMLoc &EndLoc) {
+ return tryParseRegister(RegNo, StartLoc, EndLoc) != MatchOperand_Success;
+}
+
+OperandMatchResultTy AArch64AsmParser::tryParseRegister(unsigned &RegNo,
+ SMLoc &StartLoc,
+ SMLoc &EndLoc) {
+ StartLoc = getLoc();
+ auto Res = tryParseScalarRegister(RegNo);
+ EndLoc = SMLoc::getFromPointer(getLoc().getPointer() - 1);
+ return Res;
+}
+
+// Matches a register name or register alias previously defined by '.req'
+unsigned AArch64AsmParser::matchRegisterNameAlias(StringRef Name,
+ RegKind Kind) {
+ unsigned RegNum = 0;
+ if ((RegNum = matchSVEDataVectorRegName(Name)))
+ return Kind == RegKind::SVEDataVector ? RegNum : 0;
+
+ if ((RegNum = matchSVEPredicateVectorRegName(Name)))
+ return Kind == RegKind::SVEPredicateVector ? RegNum : 0;
+
+ if ((RegNum = MatchNeonVectorRegName(Name)))
+ return Kind == RegKind::NeonVector ? RegNum : 0;
+
+ // The parsed register must be of RegKind Scalar
+ if ((RegNum = MatchRegisterName(Name)))
+ return Kind == RegKind::Scalar ? RegNum : 0;
+
+ if (!RegNum) {
+ // Handle a few common aliases of registers.
+ if (auto RegNum = StringSwitch<unsigned>(Name.lower())
+ .Case("fp", AArch64::FP)
+ .Case("lr", AArch64::LR)
+ .Case("x31", AArch64::XZR)
+ .Case("w31", AArch64::WZR)
+ .Default(0))
+ return Kind == RegKind::Scalar ? RegNum : 0;
+
+ // Check for aliases registered via .req. Canonicalize to lower case.
+ // That's more consistent since register names are case insensitive, and
+ // it's how the original entry was passed in from MC/MCParser/AsmParser.
+ auto Entry = RegisterReqs.find(Name.lower());
+ if (Entry == RegisterReqs.end())
+ return 0;
+
+ // set RegNum if the match is the right kind of register
+ if (Kind == Entry->getValue().first)
+ RegNum = Entry->getValue().second;
+ }
+ return RegNum;
+}
+
+/// tryParseScalarRegister - Try to parse a register name. The token must be an
+/// Identifier when called, and if it is a register name the token is eaten and
+/// the register is added to the operand list.
+OperandMatchResultTy
+AArch64AsmParser::tryParseScalarRegister(unsigned &RegNum) {
+ MCAsmParser &Parser = getParser();
+ const AsmToken &Tok = Parser.getTok();
+ if (Tok.isNot(AsmToken::Identifier))
+ return MatchOperand_NoMatch;
+
+ std::string lowerCase = Tok.getString().lower();
+ unsigned Reg = matchRegisterNameAlias(lowerCase, RegKind::Scalar);
+ if (Reg == 0)
+ return MatchOperand_NoMatch;
+
+ RegNum = Reg;
+ Parser.Lex(); // Eat identifier token.
+ return MatchOperand_Success;
+}
+
+/// tryParseSysCROperand - Try to parse a system instruction CR operand name.
+OperandMatchResultTy
+AArch64AsmParser::tryParseSysCROperand(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ SMLoc S = getLoc();
+
+ if (Parser.getTok().isNot(AsmToken::Identifier)) {
+ Error(S, "Expected cN operand where 0 <= N <= 15");
+ return MatchOperand_ParseFail;
+ }
+
+ StringRef Tok = Parser.getTok().getIdentifier();
+ if (Tok[0] != 'c' && Tok[0] != 'C') {
+ Error(S, "Expected cN operand where 0 <= N <= 15");
+ return MatchOperand_ParseFail;
+ }
+
+ uint32_t CRNum;
+ bool BadNum = Tok.drop_front().getAsInteger(10, CRNum);
+ if (BadNum || CRNum > 15) {
+ Error(S, "Expected cN operand where 0 <= N <= 15");
+ return MatchOperand_ParseFail;
+ }
+
+ Parser.Lex(); // Eat identifier token.
+ Operands.push_back(
+ AArch64Operand::CreateSysCR(CRNum, S, getLoc(), getContext()));
+ return MatchOperand_Success;
+}
+
+/// tryParsePrefetch - Try to parse a prefetch operand.
+template <bool IsSVEPrefetch>
+OperandMatchResultTy
+AArch64AsmParser::tryParsePrefetch(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ SMLoc S = getLoc();
+ const AsmToken &Tok = Parser.getTok();
+
+ auto LookupByName = [](StringRef N) {
+ if (IsSVEPrefetch) {
+ if (auto Res = AArch64SVEPRFM::lookupSVEPRFMByName(N))
+ return Optional<unsigned>(Res->Encoding);
+ } else if (auto Res = AArch64PRFM::lookupPRFMByName(N))
+ return Optional<unsigned>(Res->Encoding);
+ return Optional<unsigned>();
+ };
+
+ auto LookupByEncoding = [](unsigned E) {
+ if (IsSVEPrefetch) {
+ if (auto Res = AArch64SVEPRFM::lookupSVEPRFMByEncoding(E))
+ return Optional<StringRef>(Res->Name);
+ } else if (auto Res = AArch64PRFM::lookupPRFMByEncoding(E))
+ return Optional<StringRef>(Res->Name);
+ return Optional<StringRef>();
+ };
+ unsigned MaxVal = IsSVEPrefetch ? 15 : 31;
+
+ // Either an identifier for named values or a 5-bit immediate.
+ // Eat optional hash.
+ if (parseOptionalToken(AsmToken::Hash) ||
+ Tok.is(AsmToken::Integer)) {
+ const MCExpr *ImmVal;
+ if (getParser().parseExpression(ImmVal))
+ return MatchOperand_ParseFail;
+
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
+ if (!MCE) {
+ TokError("immediate value expected for prefetch operand");
+ return MatchOperand_ParseFail;
+ }
+ unsigned prfop = MCE->getValue();
+ if (prfop > MaxVal) {
+ TokError("prefetch operand out of range, [0," + utostr(MaxVal) +
+ "] expected");
+ return MatchOperand_ParseFail;
+ }
+
+ auto PRFM = LookupByEncoding(MCE->getValue());
+ Operands.push_back(AArch64Operand::CreatePrefetch(
+ prfop, PRFM.getValueOr(""), S, getContext()));
+ return MatchOperand_Success;
+ }
+
+ if (Tok.isNot(AsmToken::Identifier)) {
+ TokError("prefetch hint expected");
+ return MatchOperand_ParseFail;
+ }
+
+ auto PRFM = LookupByName(Tok.getString());
+ if (!PRFM) {
+ TokError("prefetch hint expected");
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(AArch64Operand::CreatePrefetch(
+ *PRFM, Tok.getString(), S, getContext()));
+ Parser.Lex(); // Eat identifier token.
+ return MatchOperand_Success;
+}
+
+/// tryParsePSBHint - Try to parse a PSB operand, mapped to Hint command
+OperandMatchResultTy
+AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ SMLoc S = getLoc();
+ const AsmToken &Tok = Parser.getTok();
+ if (Tok.isNot(AsmToken::Identifier)) {
+ TokError("invalid operand for instruction");
+ return MatchOperand_ParseFail;
+ }
+
+ auto PSB = AArch64PSBHint::lookupPSBByName(Tok.getString());
+ if (!PSB) {
+ TokError("invalid operand for instruction");
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(AArch64Operand::CreatePSBHint(
+ PSB->Encoding, Tok.getString(), S, getContext()));
+ Parser.Lex(); // Eat identifier token.
+ return MatchOperand_Success;
+}
+
+/// tryParseBTIHint - Try to parse a BTI operand, mapped to Hint command
+OperandMatchResultTy
+AArch64AsmParser::tryParseBTIHint(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ SMLoc S = getLoc();
+ const AsmToken &Tok = Parser.getTok();
+ if (Tok.isNot(AsmToken::Identifier)) {
+ TokError("invalid operand for instruction");
+ return MatchOperand_ParseFail;
+ }
+
+ auto BTI = AArch64BTIHint::lookupBTIByName(Tok.getString());
+ if (!BTI) {
+ TokError("invalid operand for instruction");
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(AArch64Operand::CreateBTIHint(
+ BTI->Encoding, Tok.getString(), S, getContext()));
+ Parser.Lex(); // Eat identifier token.
+ return MatchOperand_Success;
+}
+
+/// tryParseAdrpLabel - Parse and validate a source label for the ADRP
+/// instruction.
+OperandMatchResultTy
+AArch64AsmParser::tryParseAdrpLabel(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ SMLoc S = getLoc();
+ const MCExpr *Expr = nullptr;
+
+ if (Parser.getTok().is(AsmToken::Hash)) {
+ Parser.Lex(); // Eat hash token.
+ }
+
+ if (parseSymbolicImmVal(Expr))
+ return MatchOperand_ParseFail;
+
+ AArch64MCExpr::VariantKind ELFRefKind;
+ MCSymbolRefExpr::VariantKind DarwinRefKind;
+ int64_t Addend;
+ if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
+ if (DarwinRefKind == MCSymbolRefExpr::VK_None &&
+ ELFRefKind == AArch64MCExpr::VK_INVALID) {
+ // No modifier was specified at all; this is the syntax for an ELF basic
+ // ADRP relocation (unfortunately).
+ Expr =
+ AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_PAGE, getContext());
+ } else if ((DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGE ||
+ DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGE) &&
+ Addend != 0) {
+ Error(S, "gotpage label reference not allowed an addend");
+ return MatchOperand_ParseFail;
+ } else if (DarwinRefKind != MCSymbolRefExpr::VK_PAGE &&
+ DarwinRefKind != MCSymbolRefExpr::VK_GOTPAGE &&
+ 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.
- Error(S, "page or gotpage label reference expected");
- return MatchOperand_ParseFail;
- }
- }
-
- // We have either a label reference possibly with addend or an immediate. The
- // addend is a raw value here. The linker will adjust it to only reference the
- // page.
- SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
- Operands.push_back(AArch64Operand::CreateImm(Expr, S, E, getContext()));
-
- return MatchOperand_Success;
-}
-
-/// tryParseAdrLabel - Parse and validate a source label for the ADR
-/// instruction.
-OperandMatchResultTy
-AArch64AsmParser::tryParseAdrLabel(OperandVector &Operands) {
- SMLoc S = getLoc();
- const MCExpr *Expr = nullptr;
-
- // Leave anything with a bracket to the default for SVE
- if (getParser().getTok().is(AsmToken::LBrac))
- return MatchOperand_NoMatch;
-
- if (getParser().getTok().is(AsmToken::Hash))
- getParser().Lex(); // Eat hash token.
-
- if (parseSymbolicImmVal(Expr))
- return MatchOperand_ParseFail;
-
- AArch64MCExpr::VariantKind ELFRefKind;
- MCSymbolRefExpr::VariantKind DarwinRefKind;
- int64_t Addend;
- if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
- if (DarwinRefKind == MCSymbolRefExpr::VK_None &&
- ELFRefKind == AArch64MCExpr::VK_INVALID) {
- // No modifier was specified at all; this is the syntax for an ELF basic
- // ADR relocation (unfortunately).
- Expr = AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS, getContext());
- } else {
- Error(S, "unexpected adr label");
- return MatchOperand_ParseFail;
- }
- }
-
- SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
- Operands.push_back(AArch64Operand::CreateImm(Expr, S, E, getContext()));
- return MatchOperand_Success;
-}
-
-/// tryParseFPImm - A floating point immediate expression operand.
-template<bool AddFPZeroAsLiteral>
-OperandMatchResultTy
-AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- SMLoc S = getLoc();
-
- bool Hash = parseOptionalToken(AsmToken::Hash);
-
- // Handle negation, as that still comes through as a separate token.
- bool isNegative = parseOptionalToken(AsmToken::Minus);
-
- const AsmToken &Tok = Parser.getTok();
- if (!Tok.is(AsmToken::Real) && !Tok.is(AsmToken::Integer)) {
- if (!Hash)
- return MatchOperand_NoMatch;
- TokError("invalid floating point immediate");
- return MatchOperand_ParseFail;
- }
-
- // Parse hexadecimal representation.
- if (Tok.is(AsmToken::Integer) && Tok.getString().startswith("0x")) {
- if (Tok.getIntVal() > 255 || isNegative) {
- TokError("encoded floating point value out of range");
- return MatchOperand_ParseFail;
- }
-
- APFloat F((double)AArch64_AM::getFPImmFloat(Tok.getIntVal()));
- Operands.push_back(
- AArch64Operand::CreateFPImm(F, true, S, getContext()));
- } else {
- // Parse FP representation.
- APFloat RealVal(APFloat::IEEEdouble());
- auto StatusOrErr =
- RealVal.convertFromString(Tok.getString(), APFloat::rmTowardZero);
- if (errorToBool(StatusOrErr.takeError())) {
- TokError("invalid floating point representation");
- return MatchOperand_ParseFail;
- }
-
- if (isNegative)
- RealVal.changeSign();
-
- if (AddFPZeroAsLiteral && RealVal.isPosZero()) {
- Operands.push_back(
- AArch64Operand::CreateToken("#0", false, S, getContext()));
- Operands.push_back(
- AArch64Operand::CreateToken(".0", false, S, getContext()));
- } else
- Operands.push_back(AArch64Operand::CreateFPImm(
- RealVal, *StatusOrErr == APFloat::opOK, S, getContext()));
- }
-
- Parser.Lex(); // Eat the token.
-
- return MatchOperand_Success;
-}
-
-/// tryParseImmWithOptionalShift - Parse immediate operand, optionally with
-/// a shift suffix, for example '#1, lsl #12'.
-OperandMatchResultTy
-AArch64AsmParser::tryParseImmWithOptionalShift(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- SMLoc S = getLoc();
-
- if (Parser.getTok().is(AsmToken::Hash))
- Parser.Lex(); // Eat '#'
- else if (Parser.getTok().isNot(AsmToken::Integer))
- // Operand should start from # or should be integer, emit error otherwise.
- return MatchOperand_NoMatch;
-
- const MCExpr *Imm = nullptr;
- if (parseSymbolicImmVal(Imm))
- return MatchOperand_ParseFail;
- else if (Parser.getTok().isNot(AsmToken::Comma)) {
- SMLoc E = Parser.getTok().getLoc();
- Operands.push_back(
- AArch64Operand::CreateImm(Imm, S, E, getContext()));
- return MatchOperand_Success;
- }
-
- // Eat ','
- Parser.Lex();
-
- // The optional operand must be "lsl #N" where N is non-negative.
- if (!Parser.getTok().is(AsmToken::Identifier) ||
- !Parser.getTok().getIdentifier().equals_lower("lsl")) {
- Error(Parser.getTok().getLoc(), "only 'lsl #+N' valid after immediate");
- return MatchOperand_ParseFail;
- }
-
- // Eat 'lsl'
- Parser.Lex();
-
- parseOptionalToken(AsmToken::Hash);
-
- if (Parser.getTok().isNot(AsmToken::Integer)) {
- Error(Parser.getTok().getLoc(), "only 'lsl #+N' valid after immediate");
- return MatchOperand_ParseFail;
- }
-
- int64_t ShiftAmount = Parser.getTok().getIntVal();
-
- if (ShiftAmount < 0) {
- Error(Parser.getTok().getLoc(), "positive shift amount required");
- return MatchOperand_ParseFail;
- }
- Parser.Lex(); // Eat the number
-
- // Just in case the optional lsl #0 is used for immediates other than zero.
- if (ShiftAmount == 0 && Imm != nullptr) {
- SMLoc E = Parser.getTok().getLoc();
- Operands.push_back(AArch64Operand::CreateImm(Imm, S, E, getContext()));
- return MatchOperand_Success;
- }
-
- SMLoc E = Parser.getTok().getLoc();
- Operands.push_back(AArch64Operand::CreateShiftedImm(Imm, ShiftAmount,
- S, E, getContext()));
- return MatchOperand_Success;
-}
-
-/// parseCondCodeString - Parse a Condition Code string.
-AArch64CC::CondCode AArch64AsmParser::parseCondCodeString(StringRef Cond) {
- AArch64CC::CondCode CC = StringSwitch<AArch64CC::CondCode>(Cond.lower())
- .Case("eq", AArch64CC::EQ)
- .Case("ne", AArch64CC::NE)
- .Case("cs", AArch64CC::HS)
- .Case("hs", AArch64CC::HS)
- .Case("cc", AArch64CC::LO)
- .Case("lo", AArch64CC::LO)
- .Case("mi", AArch64CC::MI)
- .Case("pl", AArch64CC::PL)
- .Case("vs", AArch64CC::VS)
- .Case("vc", AArch64CC::VC)
- .Case("hi", AArch64CC::HI)
- .Case("ls", AArch64CC::LS)
- .Case("ge", AArch64CC::GE)
- .Case("lt", AArch64CC::LT)
- .Case("gt", AArch64CC::GT)
- .Case("le", AArch64CC::LE)
- .Case("al", AArch64CC::AL)
- .Case("nv", AArch64CC::NV)
- .Default(AArch64CC::Invalid);
-
- if (CC == AArch64CC::Invalid &&
- getSTI().getFeatureBits()[AArch64::FeatureSVE])
- CC = StringSwitch<AArch64CC::CondCode>(Cond.lower())
- .Case("none", AArch64CC::EQ)
- .Case("any", AArch64CC::NE)
- .Case("nlast", AArch64CC::HS)
- .Case("last", AArch64CC::LO)
- .Case("first", AArch64CC::MI)
- .Case("nfrst", AArch64CC::PL)
- .Case("pmore", AArch64CC::HI)
- .Case("plast", AArch64CC::LS)
- .Case("tcont", AArch64CC::GE)
- .Case("tstop", AArch64CC::LT)
- .Default(AArch64CC::Invalid);
-
- return CC;
-}
-
-/// parseCondCode - Parse a Condition Code operand.
-bool AArch64AsmParser::parseCondCode(OperandVector &Operands,
- bool invertCondCode) {
- MCAsmParser &Parser = getParser();
- SMLoc S = getLoc();
- const AsmToken &Tok = Parser.getTok();
- assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
-
- StringRef Cond = Tok.getString();
- AArch64CC::CondCode CC = parseCondCodeString(Cond);
- if (CC == AArch64CC::Invalid)
- return TokError("invalid condition code");
- Parser.Lex(); // Eat identifier token.
-
- if (invertCondCode) {
- if (CC == AArch64CC::AL || CC == AArch64CC::NV)
- return TokError("condition codes AL and NV are invalid for this instruction");
- CC = AArch64CC::getInvertedCondCode(AArch64CC::CondCode(CC));
- }
-
- Operands.push_back(
- AArch64Operand::CreateCondCode(CC, S, getLoc(), getContext()));
- return false;
-}
-
-/// tryParseOptionalShift - Some operands take an optional shift argument. Parse
-/// them if present.
-OperandMatchResultTy
-AArch64AsmParser::tryParseOptionalShiftExtend(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- const AsmToken &Tok = Parser.getTok();
- std::string LowerID = Tok.getString().lower();
- AArch64_AM::ShiftExtendType ShOp =
- StringSwitch<AArch64_AM::ShiftExtendType>(LowerID)
- .Case("lsl", AArch64_AM::LSL)
- .Case("lsr", AArch64_AM::LSR)
- .Case("asr", AArch64_AM::ASR)
- .Case("ror", AArch64_AM::ROR)
- .Case("msl", AArch64_AM::MSL)
- .Case("uxtb", AArch64_AM::UXTB)
- .Case("uxth", AArch64_AM::UXTH)
- .Case("uxtw", AArch64_AM::UXTW)
- .Case("uxtx", AArch64_AM::UXTX)
- .Case("sxtb", AArch64_AM::SXTB)
- .Case("sxth", AArch64_AM::SXTH)
- .Case("sxtw", AArch64_AM::SXTW)
- .Case("sxtx", AArch64_AM::SXTX)
- .Default(AArch64_AM::InvalidShiftExtend);
-
- if (ShOp == AArch64_AM::InvalidShiftExtend)
- return MatchOperand_NoMatch;
-
- SMLoc S = Tok.getLoc();
- Parser.Lex();
-
- bool Hash = parseOptionalToken(AsmToken::Hash);
-
- if (!Hash && getLexer().isNot(AsmToken::Integer)) {
- if (ShOp == AArch64_AM::LSL || ShOp == AArch64_AM::LSR ||
- ShOp == AArch64_AM::ASR || ShOp == AArch64_AM::ROR ||
- ShOp == AArch64_AM::MSL) {
- // We expect a number here.
- TokError("expected #imm after shift specifier");
- return MatchOperand_ParseFail;
- }
-
- // "extend" type operations don't need an immediate, #0 is implicit.
- SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
- Operands.push_back(
- AArch64Operand::CreateShiftExtend(ShOp, 0, false, S, E, getContext()));
- return MatchOperand_Success;
- }
-
- // Make sure we do actually have a number, identifier or a parenthesized
- // expression.
- SMLoc E = Parser.getTok().getLoc();
- if (!Parser.getTok().is(AsmToken::Integer) &&
- !Parser.getTok().is(AsmToken::LParen) &&
- !Parser.getTok().is(AsmToken::Identifier)) {
- Error(E, "expected integer shift amount");
- return MatchOperand_ParseFail;
- }
-
- const MCExpr *ImmVal;
- if (getParser().parseExpression(ImmVal))
- return MatchOperand_ParseFail;
-
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
- if (!MCE) {
- Error(E, "expected constant '#imm' after shift specifier");
- return MatchOperand_ParseFail;
- }
-
- E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
- Operands.push_back(AArch64Operand::CreateShiftExtend(
- ShOp, MCE->getValue(), true, S, E, getContext()));
- return MatchOperand_Success;
-}
-
-static const struct Extension {
- const char *Name;
- const FeatureBitset Features;
-} ExtensionMap[] = {
- {"crc", {AArch64::FeatureCRC}},
- {"sm4", {AArch64::FeatureSM4}},
- {"sha3", {AArch64::FeatureSHA3}},
- {"sha2", {AArch64::FeatureSHA2}},
- {"aes", {AArch64::FeatureAES}},
- {"crypto", {AArch64::FeatureCrypto}},
- {"fp", {AArch64::FeatureFPARMv8}},
- {"simd", {AArch64::FeatureNEON}},
- {"ras", {AArch64::FeatureRAS}},
- {"lse", {AArch64::FeatureLSE}},
- {"predres", {AArch64::FeaturePredRes}},
- {"ccdp", {AArch64::FeatureCacheDeepPersist}},
- {"mte", {AArch64::FeatureMTE}},
+ ELFRefKind != AArch64MCExpr::VK_GOTTPREL_PAGE &&
+ ELFRefKind != AArch64MCExpr::VK_TLSDESC_PAGE) {
+ // The operand must be an @page or @gotpage qualified symbolref.
+ Error(S, "page or gotpage label reference expected");
+ return MatchOperand_ParseFail;
+ }
+ }
+
+ // We have either a label reference possibly with addend or an immediate. The
+ // addend is a raw value here. The linker will adjust it to only reference the
+ // page.
+ SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
+ Operands.push_back(AArch64Operand::CreateImm(Expr, S, E, getContext()));
+
+ return MatchOperand_Success;
+}
+
+/// tryParseAdrLabel - Parse and validate a source label for the ADR
+/// instruction.
+OperandMatchResultTy
+AArch64AsmParser::tryParseAdrLabel(OperandVector &Operands) {
+ SMLoc S = getLoc();
+ const MCExpr *Expr = nullptr;
+
+ // Leave anything with a bracket to the default for SVE
+ if (getParser().getTok().is(AsmToken::LBrac))
+ return MatchOperand_NoMatch;
+
+ if (getParser().getTok().is(AsmToken::Hash))
+ getParser().Lex(); // Eat hash token.
+
+ if (parseSymbolicImmVal(Expr))
+ return MatchOperand_ParseFail;
+
+ AArch64MCExpr::VariantKind ELFRefKind;
+ MCSymbolRefExpr::VariantKind DarwinRefKind;
+ int64_t Addend;
+ if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
+ if (DarwinRefKind == MCSymbolRefExpr::VK_None &&
+ ELFRefKind == AArch64MCExpr::VK_INVALID) {
+ // No modifier was specified at all; this is the syntax for an ELF basic
+ // ADR relocation (unfortunately).
+ Expr = AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS, getContext());
+ } else {
+ Error(S, "unexpected adr label");
+ return MatchOperand_ParseFail;
+ }
+ }
+
+ SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
+ Operands.push_back(AArch64Operand::CreateImm(Expr, S, E, getContext()));
+ return MatchOperand_Success;
+}
+
+/// tryParseFPImm - A floating point immediate expression operand.
+template<bool AddFPZeroAsLiteral>
+OperandMatchResultTy
+AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ SMLoc S = getLoc();
+
+ bool Hash = parseOptionalToken(AsmToken::Hash);
+
+ // Handle negation, as that still comes through as a separate token.
+ bool isNegative = parseOptionalToken(AsmToken::Minus);
+
+ const AsmToken &Tok = Parser.getTok();
+ if (!Tok.is(AsmToken::Real) && !Tok.is(AsmToken::Integer)) {
+ if (!Hash)
+ return MatchOperand_NoMatch;
+ TokError("invalid floating point immediate");
+ return MatchOperand_ParseFail;
+ }
+
+ // Parse hexadecimal representation.
+ if (Tok.is(AsmToken::Integer) && Tok.getString().startswith("0x")) {
+ if (Tok.getIntVal() > 255 || isNegative) {
+ TokError("encoded floating point value out of range");
+ return MatchOperand_ParseFail;
+ }
+
+ APFloat F((double)AArch64_AM::getFPImmFloat(Tok.getIntVal()));
+ Operands.push_back(
+ AArch64Operand::CreateFPImm(F, true, S, getContext()));
+ } else {
+ // Parse FP representation.
+ APFloat RealVal(APFloat::IEEEdouble());
+ auto StatusOrErr =
+ RealVal.convertFromString(Tok.getString(), APFloat::rmTowardZero);
+ if (errorToBool(StatusOrErr.takeError())) {
+ TokError("invalid floating point representation");
+ return MatchOperand_ParseFail;
+ }
+
+ if (isNegative)
+ RealVal.changeSign();
+
+ if (AddFPZeroAsLiteral && RealVal.isPosZero()) {
+ Operands.push_back(
+ AArch64Operand::CreateToken("#0", false, S, getContext()));
+ Operands.push_back(
+ AArch64Operand::CreateToken(".0", false, S, getContext()));
+ } else
+ Operands.push_back(AArch64Operand::CreateFPImm(
+ RealVal, *StatusOrErr == APFloat::opOK, S, getContext()));
+ }
+
+ Parser.Lex(); // Eat the token.
+
+ return MatchOperand_Success;
+}
+
+/// tryParseImmWithOptionalShift - Parse immediate operand, optionally with
+/// a shift suffix, for example '#1, lsl #12'.
+OperandMatchResultTy
+AArch64AsmParser::tryParseImmWithOptionalShift(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ SMLoc S = getLoc();
+
+ if (Parser.getTok().is(AsmToken::Hash))
+ Parser.Lex(); // Eat '#'
+ else if (Parser.getTok().isNot(AsmToken::Integer))
+ // Operand should start from # or should be integer, emit error otherwise.
+ return MatchOperand_NoMatch;
+
+ const MCExpr *Imm = nullptr;
+ if (parseSymbolicImmVal(Imm))
+ return MatchOperand_ParseFail;
+ else if (Parser.getTok().isNot(AsmToken::Comma)) {
+ SMLoc E = Parser.getTok().getLoc();
+ Operands.push_back(
+ AArch64Operand::CreateImm(Imm, S, E, getContext()));
+ return MatchOperand_Success;
+ }
+
+ // Eat ','
+ Parser.Lex();
+
+ // The optional operand must be "lsl #N" where N is non-negative.
+ if (!Parser.getTok().is(AsmToken::Identifier) ||
+ !Parser.getTok().getIdentifier().equals_lower("lsl")) {
+ Error(Parser.getTok().getLoc(), "only 'lsl #+N' valid after immediate");
+ return MatchOperand_ParseFail;
+ }
+
+ // Eat 'lsl'
+ Parser.Lex();
+
+ parseOptionalToken(AsmToken::Hash);
+
+ if (Parser.getTok().isNot(AsmToken::Integer)) {
+ Error(Parser.getTok().getLoc(), "only 'lsl #+N' valid after immediate");
+ return MatchOperand_ParseFail;
+ }
+
+ int64_t ShiftAmount = Parser.getTok().getIntVal();
+
+ if (ShiftAmount < 0) {
+ Error(Parser.getTok().getLoc(), "positive shift amount required");
+ return MatchOperand_ParseFail;
+ }
+ Parser.Lex(); // Eat the number
+
+ // Just in case the optional lsl #0 is used for immediates other than zero.
+ if (ShiftAmount == 0 && Imm != nullptr) {
+ SMLoc E = Parser.getTok().getLoc();
+ Operands.push_back(AArch64Operand::CreateImm(Imm, S, E, getContext()));
+ return MatchOperand_Success;
+ }
+
+ SMLoc E = Parser.getTok().getLoc();
+ Operands.push_back(AArch64Operand::CreateShiftedImm(Imm, ShiftAmount,
+ S, E, getContext()));
+ return MatchOperand_Success;
+}
+
+/// parseCondCodeString - Parse a Condition Code string.
+AArch64CC::CondCode AArch64AsmParser::parseCondCodeString(StringRef Cond) {
+ AArch64CC::CondCode CC = StringSwitch<AArch64CC::CondCode>(Cond.lower())
+ .Case("eq", AArch64CC::EQ)
+ .Case("ne", AArch64CC::NE)
+ .Case("cs", AArch64CC::HS)
+ .Case("hs", AArch64CC::HS)
+ .Case("cc", AArch64CC::LO)
+ .Case("lo", AArch64CC::LO)
+ .Case("mi", AArch64CC::MI)
+ .Case("pl", AArch64CC::PL)
+ .Case("vs", AArch64CC::VS)
+ .Case("vc", AArch64CC::VC)
+ .Case("hi", AArch64CC::HI)
+ .Case("ls", AArch64CC::LS)
+ .Case("ge", AArch64CC::GE)
+ .Case("lt", AArch64CC::LT)
+ .Case("gt", AArch64CC::GT)
+ .Case("le", AArch64CC::LE)
+ .Case("al", AArch64CC::AL)
+ .Case("nv", AArch64CC::NV)
+ .Default(AArch64CC::Invalid);
+
+ if (CC == AArch64CC::Invalid &&
+ getSTI().getFeatureBits()[AArch64::FeatureSVE])
+ CC = StringSwitch<AArch64CC::CondCode>(Cond.lower())
+ .Case("none", AArch64CC::EQ)
+ .Case("any", AArch64CC::NE)
+ .Case("nlast", AArch64CC::HS)
+ .Case("last", AArch64CC::LO)
+ .Case("first", AArch64CC::MI)
+ .Case("nfrst", AArch64CC::PL)
+ .Case("pmore", AArch64CC::HI)
+ .Case("plast", AArch64CC::LS)
+ .Case("tcont", AArch64CC::GE)
+ .Case("tstop", AArch64CC::LT)
+ .Default(AArch64CC::Invalid);
+
+ return CC;
+}
+
+/// parseCondCode - Parse a Condition Code operand.
+bool AArch64AsmParser::parseCondCode(OperandVector &Operands,
+ bool invertCondCode) {
+ MCAsmParser &Parser = getParser();
+ SMLoc S = getLoc();
+ const AsmToken &Tok = Parser.getTok();
+ assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
+
+ StringRef Cond = Tok.getString();
+ AArch64CC::CondCode CC = parseCondCodeString(Cond);
+ if (CC == AArch64CC::Invalid)
+ return TokError("invalid condition code");
+ Parser.Lex(); // Eat identifier token.
+
+ if (invertCondCode) {
+ if (CC == AArch64CC::AL || CC == AArch64CC::NV)
+ return TokError("condition codes AL and NV are invalid for this instruction");
+ CC = AArch64CC::getInvertedCondCode(AArch64CC::CondCode(CC));
+ }
+
+ Operands.push_back(
+ AArch64Operand::CreateCondCode(CC, S, getLoc(), getContext()));
+ return false;
+}
+
+/// tryParseOptionalShift - Some operands take an optional shift argument. Parse
+/// them if present.
+OperandMatchResultTy
+AArch64AsmParser::tryParseOptionalShiftExtend(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ const AsmToken &Tok = Parser.getTok();
+ std::string LowerID = Tok.getString().lower();
+ AArch64_AM::ShiftExtendType ShOp =
+ StringSwitch<AArch64_AM::ShiftExtendType>(LowerID)
+ .Case("lsl", AArch64_AM::LSL)
+ .Case("lsr", AArch64_AM::LSR)
+ .Case("asr", AArch64_AM::ASR)
+ .Case("ror", AArch64_AM::ROR)
+ .Case("msl", AArch64_AM::MSL)
+ .Case("uxtb", AArch64_AM::UXTB)
+ .Case("uxth", AArch64_AM::UXTH)
+ .Case("uxtw", AArch64_AM::UXTW)
+ .Case("uxtx", AArch64_AM::UXTX)
+ .Case("sxtb", AArch64_AM::SXTB)
+ .Case("sxth", AArch64_AM::SXTH)
+ .Case("sxtw", AArch64_AM::SXTW)
+ .Case("sxtx", AArch64_AM::SXTX)
+ .Default(AArch64_AM::InvalidShiftExtend);
+
+ if (ShOp == AArch64_AM::InvalidShiftExtend)
+ return MatchOperand_NoMatch;
+
+ SMLoc S = Tok.getLoc();
+ Parser.Lex();
+
+ bool Hash = parseOptionalToken(AsmToken::Hash);
+
+ if (!Hash && getLexer().isNot(AsmToken::Integer)) {
+ if (ShOp == AArch64_AM::LSL || ShOp == AArch64_AM::LSR ||
+ ShOp == AArch64_AM::ASR || ShOp == AArch64_AM::ROR ||
+ ShOp == AArch64_AM::MSL) {
+ // We expect a number here.
+ TokError("expected #imm after shift specifier");
+ return MatchOperand_ParseFail;
+ }
+
+ // "extend" type operations don't need an immediate, #0 is implicit.
+ SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
+ Operands.push_back(
+ AArch64Operand::CreateShiftExtend(ShOp, 0, false, S, E, getContext()));
+ return MatchOperand_Success;
+ }
+
+ // Make sure we do actually have a number, identifier or a parenthesized
+ // expression.
+ SMLoc E = Parser.getTok().getLoc();
+ if (!Parser.getTok().is(AsmToken::Integer) &&
+ !Parser.getTok().is(AsmToken::LParen) &&
+ !Parser.getTok().is(AsmToken::Identifier)) {
+ Error(E, "expected integer shift amount");
+ return MatchOperand_ParseFail;
+ }
+
+ const MCExpr *ImmVal;
+ if (getParser().parseExpression(ImmVal))
+ return MatchOperand_ParseFail;
+
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
+ if (!MCE) {
+ Error(E, "expected constant '#imm' after shift specifier");
+ return MatchOperand_ParseFail;
+ }
+
+ E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
+ Operands.push_back(AArch64Operand::CreateShiftExtend(
+ ShOp, MCE->getValue(), true, S, E, getContext()));
+ return MatchOperand_Success;
+}
+
+static const struct Extension {
+ const char *Name;
+ const FeatureBitset Features;
+} ExtensionMap[] = {
+ {"crc", {AArch64::FeatureCRC}},
+ {"sm4", {AArch64::FeatureSM4}},
+ {"sha3", {AArch64::FeatureSHA3}},
+ {"sha2", {AArch64::FeatureSHA2}},
+ {"aes", {AArch64::FeatureAES}},
+ {"crypto", {AArch64::FeatureCrypto}},
+ {"fp", {AArch64::FeatureFPARMv8}},
+ {"simd", {AArch64::FeatureNEON}},
+ {"ras", {AArch64::FeatureRAS}},
+ {"lse", {AArch64::FeatureLSE}},
+ {"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}},
- {"rcpc", {AArch64::FeatureRCPC}},
- {"sve", {AArch64::FeatureSVE}},
- {"sve2", {AArch64::FeatureSVE2}},
- {"sve2-aes", {AArch64::FeatureSVE2AES}},
- {"sve2-sm4", {AArch64::FeatureSVE2SM4}},
- {"sve2-sha3", {AArch64::FeatureSVE2SHA3}},
- {"sve2-bitperm", {AArch64::FeatureSVE2BitPerm}},
+ {"tlb-rmi", {AArch64::FeatureTLB_RMI}},
+ {"pan-rwv", {AArch64::FeaturePAN_RWV}},
+ {"ccpp", {AArch64::FeatureCCPP}},
+ {"rcpc", {AArch64::FeatureRCPC}},
+ {"sve", {AArch64::FeatureSVE}},
+ {"sve2", {AArch64::FeatureSVE2}},
+ {"sve2-aes", {AArch64::FeatureSVE2AES}},
+ {"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", {}},
- {"rdma", {}},
- {"profile", {}},
-};
-
-static void setRequiredFeatureString(FeatureBitset FBS, std::string &Str) {
- if (FBS[AArch64::HasV8_1aOps])
- Str += "ARMv8.1a";
- else if (FBS[AArch64::HasV8_2aOps])
- Str += "ARMv8.2a";
- else if (FBS[AArch64::HasV8_3aOps])
- Str += "ARMv8.3a";
- else if (FBS[AArch64::HasV8_4aOps])
- Str += "ARMv8.4a";
- else if (FBS[AArch64::HasV8_5aOps])
- Str += "ARMv8.5a";
- else if (FBS[AArch64::HasV8_6aOps])
- Str += "ARMv8.6a";
+ // FIXME: Unsupported extensions
+ {"pan", {}},
+ {"lor", {}},
+ {"rdma", {}},
+ {"profile", {}},
+};
+
+static void setRequiredFeatureString(FeatureBitset FBS, std::string &Str) {
+ if (FBS[AArch64::HasV8_1aOps])
+ Str += "ARMv8.1a";
+ else if (FBS[AArch64::HasV8_2aOps])
+ Str += "ARMv8.2a";
+ else if (FBS[AArch64::HasV8_3aOps])
+ Str += "ARMv8.3a";
+ else if (FBS[AArch64::HasV8_4aOps])
+ Str += "ARMv8.4a";
+ else if (FBS[AArch64::HasV8_5aOps])
+ Str += "ARMv8.5a";
+ else if (FBS[AArch64::HasV8_6aOps])
+ Str += "ARMv8.6a";
else if (FBS[AArch64::HasV8_7aOps])
Str += "ARMv8.7a";
- else {
+ else {
SmallVector<std::string, 2> ExtMatches;
for (const auto& Ext : ExtensionMap) {
- // Use & in case multiple features are enabled
+ // Use & in case multiple features are enabled
if ((FBS & Ext.Features) != FeatureBitset())
ExtMatches.push_back(Ext.Name);
}
Str += !ExtMatches.empty() ? llvm::join(ExtMatches, ", ") : "(unknown)";
- }
-}
-
-void AArch64AsmParser::createSysAlias(uint16_t Encoding, OperandVector &Operands,
- SMLoc S) {
- const uint16_t Op2 = Encoding & 7;
- const uint16_t Cm = (Encoding & 0x78) >> 3;
- const uint16_t Cn = (Encoding & 0x780) >> 7;
- const uint16_t Op1 = (Encoding & 0x3800) >> 11;
-
- const MCExpr *Expr = MCConstantExpr::create(Op1, getContext());
-
- Operands.push_back(
- AArch64Operand::CreateImm(Expr, S, getLoc(), getContext()));
- Operands.push_back(
- AArch64Operand::CreateSysCR(Cn, S, getLoc(), getContext()));
- Operands.push_back(
- AArch64Operand::CreateSysCR(Cm, S, getLoc(), getContext()));
- Expr = MCConstantExpr::create(Op2, getContext());
- Operands.push_back(
- AArch64Operand::CreateImm(Expr, S, getLoc(), getContext()));
-}
-
-/// parseSysAlias - The IC, DC, AT, and TLBI instructions are simple aliases for
-/// the SYS instruction. Parse them specially so that we create a SYS MCInst.
-bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
- OperandVector &Operands) {
- if (Name.find('.') != StringRef::npos)
- return TokError("invalid operand");
-
- Mnemonic = Name;
- Operands.push_back(
- AArch64Operand::CreateToken("sys", false, NameLoc, getContext()));
-
- MCAsmParser &Parser = getParser();
- const AsmToken &Tok = Parser.getTok();
- StringRef Op = Tok.getString();
- SMLoc S = Tok.getLoc();
-
- if (Mnemonic == "ic") {
- const AArch64IC::IC *IC = AArch64IC::lookupICByName(Op);
- if (!IC)
- return TokError("invalid operand for IC instruction");
- else if (!IC->haveFeatures(getSTI().getFeatureBits())) {
+ }
+}
+
+void AArch64AsmParser::createSysAlias(uint16_t Encoding, OperandVector &Operands,
+ SMLoc S) {
+ const uint16_t Op2 = Encoding & 7;
+ const uint16_t Cm = (Encoding & 0x78) >> 3;
+ const uint16_t Cn = (Encoding & 0x780) >> 7;
+ const uint16_t Op1 = (Encoding & 0x3800) >> 11;
+
+ const MCExpr *Expr = MCConstantExpr::create(Op1, getContext());
+
+ Operands.push_back(
+ AArch64Operand::CreateImm(Expr, S, getLoc(), getContext()));
+ Operands.push_back(
+ AArch64Operand::CreateSysCR(Cn, S, getLoc(), getContext()));
+ Operands.push_back(
+ AArch64Operand::CreateSysCR(Cm, S, getLoc(), getContext()));
+ Expr = MCConstantExpr::create(Op2, getContext());
+ Operands.push_back(
+ AArch64Operand::CreateImm(Expr, S, getLoc(), getContext()));
+}
+
+/// parseSysAlias - The IC, DC, AT, and TLBI instructions are simple aliases for
+/// the SYS instruction. Parse them specially so that we create a SYS MCInst.
+bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
+ OperandVector &Operands) {
+ if (Name.find('.') != StringRef::npos)
+ return TokError("invalid operand");
+
+ Mnemonic = Name;
+ Operands.push_back(
+ AArch64Operand::CreateToken("sys", false, NameLoc, getContext()));
+
+ MCAsmParser &Parser = getParser();
+ const AsmToken &Tok = Parser.getTok();
+ StringRef Op = Tok.getString();
+ SMLoc S = Tok.getLoc();
+
+ if (Mnemonic == "ic") {
+ const AArch64IC::IC *IC = AArch64IC::lookupICByName(Op);
+ if (!IC)
+ return TokError("invalid operand for IC instruction");
+ else if (!IC->haveFeatures(getSTI().getFeatureBits())) {
std::string Str("IC " + std::string(IC->Name) + " requires: ");
- setRequiredFeatureString(IC->getRequiredFeatures(), Str);
- return TokError(Str.c_str());
- }
- createSysAlias(IC->Encoding, Operands, S);
- } else if (Mnemonic == "dc") {
- const AArch64DC::DC *DC = AArch64DC::lookupDCByName(Op);
- if (!DC)
- return TokError("invalid operand for DC instruction");
- else if (!DC->haveFeatures(getSTI().getFeatureBits())) {
+ setRequiredFeatureString(IC->getRequiredFeatures(), Str);
+ return TokError(Str.c_str());
+ }
+ createSysAlias(IC->Encoding, Operands, S);
+ } else if (Mnemonic == "dc") {
+ const AArch64DC::DC *DC = AArch64DC::lookupDCByName(Op);
+ if (!DC)
+ return TokError("invalid operand for DC instruction");
+ else if (!DC->haveFeatures(getSTI().getFeatureBits())) {
std::string Str("DC " + std::string(DC->Name) + " requires: ");
- setRequiredFeatureString(DC->getRequiredFeatures(), Str);
- return TokError(Str.c_str());
- }
- createSysAlias(DC->Encoding, Operands, S);
- } else if (Mnemonic == "at") {
- const AArch64AT::AT *AT = AArch64AT::lookupATByName(Op);
- if (!AT)
- return TokError("invalid operand for AT instruction");
- else if (!AT->haveFeatures(getSTI().getFeatureBits())) {
+ setRequiredFeatureString(DC->getRequiredFeatures(), Str);
+ return TokError(Str.c_str());
+ }
+ createSysAlias(DC->Encoding, Operands, S);
+ } else if (Mnemonic == "at") {
+ const AArch64AT::AT *AT = AArch64AT::lookupATByName(Op);
+ if (!AT)
+ return TokError("invalid operand for AT instruction");
+ else if (!AT->haveFeatures(getSTI().getFeatureBits())) {
std::string Str("AT " + std::string(AT->Name) + " requires: ");
- setRequiredFeatureString(AT->getRequiredFeatures(), Str);
- return TokError(Str.c_str());
- }
- createSysAlias(AT->Encoding, Operands, S);
- } else if (Mnemonic == "tlbi") {
- const AArch64TLBI::TLBI *TLBI = AArch64TLBI::lookupTLBIByName(Op);
- if (!TLBI)
- return TokError("invalid operand for TLBI instruction");
- else if (!TLBI->haveFeatures(getSTI().getFeatureBits())) {
+ setRequiredFeatureString(AT->getRequiredFeatures(), Str);
+ return TokError(Str.c_str());
+ }
+ createSysAlias(AT->Encoding, Operands, S);
+ } else if (Mnemonic == "tlbi") {
+ const AArch64TLBI::TLBI *TLBI = AArch64TLBI::lookupTLBIByName(Op);
+ if (!TLBI)
+ return TokError("invalid operand for TLBI instruction");
+ else if (!TLBI->haveFeatures(getSTI().getFeatureBits())) {
std::string Str("TLBI " + std::string(TLBI->Name) + " requires: ");
- setRequiredFeatureString(TLBI->getRequiredFeatures(), Str);
- return TokError(Str.c_str());
- }
- createSysAlias(TLBI->Encoding, Operands, S);
- } else if (Mnemonic == "cfp" || Mnemonic == "dvp" || Mnemonic == "cpp") {
- const AArch64PRCTX::PRCTX *PRCTX = AArch64PRCTX::lookupPRCTXByName(Op);
- if (!PRCTX)
- return TokError("invalid operand for prediction restriction instruction");
- else if (!PRCTX->haveFeatures(getSTI().getFeatureBits())) {
- std::string Str(
+ setRequiredFeatureString(TLBI->getRequiredFeatures(), Str);
+ return TokError(Str.c_str());
+ }
+ createSysAlias(TLBI->Encoding, Operands, S);
+ } else if (Mnemonic == "cfp" || Mnemonic == "dvp" || Mnemonic == "cpp") {
+ const AArch64PRCTX::PRCTX *PRCTX = AArch64PRCTX::lookupPRCTXByName(Op);
+ if (!PRCTX)
+ return TokError("invalid operand for prediction restriction instruction");
+ else if (!PRCTX->haveFeatures(getSTI().getFeatureBits())) {
+ std::string Str(
Mnemonic.upper() + std::string(PRCTX->Name) + " requires: ");
- setRequiredFeatureString(PRCTX->getRequiredFeatures(), Str);
- return TokError(Str.c_str());
- }
- uint16_t PRCTX_Op2 =
- Mnemonic == "cfp" ? 4 :
- Mnemonic == "dvp" ? 5 :
- Mnemonic == "cpp" ? 7 :
- 0;
- assert(PRCTX_Op2 && "Invalid mnemonic for prediction restriction instruction");
- createSysAlias(PRCTX->Encoding << 3 | PRCTX_Op2 , Operands, S);
- }
-
- Parser.Lex(); // Eat operand.
-
- bool ExpectRegister = (Op.lower().find("all") == StringRef::npos);
- bool HasRegister = false;
-
- // Check for the optional register operand.
- if (parseOptionalToken(AsmToken::Comma)) {
- if (Tok.isNot(AsmToken::Identifier) || parseRegister(Operands))
- return TokError("expected register operand");
- HasRegister = true;
- }
-
- if (ExpectRegister && !HasRegister)
- return TokError("specified " + Mnemonic + " op requires a register");
- else if (!ExpectRegister && HasRegister)
- return TokError("specified " + Mnemonic + " op does not use a register");
-
- if (parseToken(AsmToken::EndOfStatement, "unexpected token in argument list"))
- return true;
-
- return false;
-}
-
-OperandMatchResultTy
-AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- const AsmToken &Tok = Parser.getTok();
-
- if (Mnemonic == "tsb" && Tok.isNot(AsmToken::Identifier)) {
- TokError("'csync' operand expected");
- return MatchOperand_ParseFail;
- } else if (parseOptionalToken(AsmToken::Hash) || Tok.is(AsmToken::Integer)) {
- // Immediate operand.
- const MCExpr *ImmVal;
- SMLoc ExprLoc = getLoc();
+ setRequiredFeatureString(PRCTX->getRequiredFeatures(), Str);
+ return TokError(Str.c_str());
+ }
+ uint16_t PRCTX_Op2 =
+ Mnemonic == "cfp" ? 4 :
+ Mnemonic == "dvp" ? 5 :
+ Mnemonic == "cpp" ? 7 :
+ 0;
+ assert(PRCTX_Op2 && "Invalid mnemonic for prediction restriction instruction");
+ createSysAlias(PRCTX->Encoding << 3 | PRCTX_Op2 , Operands, S);
+ }
+
+ Parser.Lex(); // Eat operand.
+
+ bool ExpectRegister = (Op.lower().find("all") == StringRef::npos);
+ bool HasRegister = false;
+
+ // Check for the optional register operand.
+ if (parseOptionalToken(AsmToken::Comma)) {
+ if (Tok.isNot(AsmToken::Identifier) || parseRegister(Operands))
+ return TokError("expected register operand");
+ HasRegister = true;
+ }
+
+ if (ExpectRegister && !HasRegister)
+ return TokError("specified " + Mnemonic + " op requires a register");
+ else if (!ExpectRegister && HasRegister)
+ return TokError("specified " + Mnemonic + " op does not use a register");
+
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in argument list"))
+ return true;
+
+ return false;
+}
+
+OperandMatchResultTy
+AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ const AsmToken &Tok = Parser.getTok();
+
+ if (Mnemonic == "tsb" && Tok.isNot(AsmToken::Identifier)) {
+ TokError("'csync' operand expected");
+ return MatchOperand_ParseFail;
+ } 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);
- if (!MCE) {
- Error(ExprLoc, "immediate value expected for barrier operand");
- return MatchOperand_ParseFail;
- }
+ 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();
if (Mnemonic == "dsb" && Value > 15) {
// This case is a no match here, but it might be matched by the nXS
@@ -3099,51 +3099,51 @@ AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) {
return MatchOperand_NoMatch;
}
if (Value < 0 || Value > 15) {
- Error(ExprLoc, "barrier operand out of range");
- return MatchOperand_ParseFail;
- }
+ Error(ExprLoc, "barrier operand out of range");
+ return MatchOperand_ParseFail;
+ }
auto DB = AArch64DB::lookupDBByEncoding(Value);
Operands.push_back(AArch64Operand::CreateBarrier(Value, DB ? DB->Name : "",
ExprLoc, getContext(),
false /*hasnXSModifier*/));
- return MatchOperand_Success;
- }
-
- if (Tok.isNot(AsmToken::Identifier)) {
- TokError("invalid operand for instruction");
- return MatchOperand_ParseFail;
- }
-
+ return MatchOperand_Success;
+ }
+
+ if (Tok.isNot(AsmToken::Identifier)) {
+ TokError("invalid operand for instruction");
+ return MatchOperand_ParseFail;
+ }
+
StringRef Operand = Tok.getString();
auto TSB = AArch64TSB::lookupTSBByName(Operand);
auto DB = AArch64DB::lookupDBByName(Operand);
- // The only valid named option for ISB is 'sy'
- if (Mnemonic == "isb" && (!DB || DB->Encoding != AArch64DB::sy)) {
- TokError("'sy' or #imm operand expected");
- return MatchOperand_ParseFail;
- // The only valid named option for TSB is 'csync'
- } else if (Mnemonic == "tsb" && (!TSB || TSB->Encoding != AArch64TSB::csync)) {
- TokError("'csync' operand expected");
- return MatchOperand_ParseFail;
- } else if (!DB && !TSB) {
+ // The only valid named option for ISB is 'sy'
+ if (Mnemonic == "isb" && (!DB || DB->Encoding != AArch64DB::sy)) {
+ TokError("'sy' or #imm operand expected");
+ return MatchOperand_ParseFail;
+ // The only valid named option for TSB is 'csync'
+ } else if (Mnemonic == "tsb" && (!TSB || TSB->Encoding != AArch64TSB::csync)) {
+ 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(
+ TokError("invalid barrier option name");
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(AArch64Operand::CreateBarrier(
DB ? DB->Encoding : TSB->Encoding, Tok.getString(), getLoc(),
getContext(), false /*hasnXSModifier*/));
- Parser.Lex(); // Consume the option
-
- return MatchOperand_Success;
-}
-
-OperandMatchResultTy
+ Parser.Lex(); // Consume the option
+
+ return MatchOperand_Success;
+}
+
+OperandMatchResultTy
AArch64AsmParser::tryParseBarriernXSOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
@@ -3199,514 +3199,514 @@ AArch64AsmParser::tryParseBarriernXSOperand(OperandVector &Operands) {
}
OperandMatchResultTy
-AArch64AsmParser::tryParseSysReg(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- const AsmToken &Tok = Parser.getTok();
-
- if (Tok.isNot(AsmToken::Identifier))
- return MatchOperand_NoMatch;
-
- int MRSReg, MSRReg;
- auto SysReg = AArch64SysReg::lookupSysRegByName(Tok.getString());
- if (SysReg && SysReg->haveFeatures(getSTI().getFeatureBits())) {
- MRSReg = SysReg->Readable ? SysReg->Encoding : -1;
- MSRReg = SysReg->Writeable ? SysReg->Encoding : -1;
- } else
- MRSReg = MSRReg = AArch64SysReg::parseGenericRegister(Tok.getString());
-
- auto PState = AArch64PState::lookupPStateByName(Tok.getString());
- unsigned PStateImm = -1;
- if (PState && PState->haveFeatures(getSTI().getFeatureBits()))
- PStateImm = PState->Encoding;
-
- Operands.push_back(
- AArch64Operand::CreateSysReg(Tok.getString(), getLoc(), MRSReg, MSRReg,
- PStateImm, getContext()));
- Parser.Lex(); // Eat identifier
-
- return MatchOperand_Success;
-}
-
-/// tryParseNeonVectorRegister - Parse a vector register operand.
-bool AArch64AsmParser::tryParseNeonVectorRegister(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- if (Parser.getTok().isNot(AsmToken::Identifier))
- return true;
-
- SMLoc S = getLoc();
- // Check for a vector register specifier first.
- StringRef Kind;
- unsigned Reg;
- OperandMatchResultTy Res =
- tryParseVectorRegister(Reg, Kind, RegKind::NeonVector);
- if (Res != MatchOperand_Success)
- return true;
-
- const auto &KindRes = parseVectorKind(Kind, RegKind::NeonVector);
- if (!KindRes)
- return true;
-
- unsigned ElementWidth = KindRes->second;
- Operands.push_back(
- AArch64Operand::CreateVectorReg(Reg, RegKind::NeonVector, ElementWidth,
- S, getLoc(), getContext()));
-
- // If there was an explicit qualifier, that goes on as a literal text
- // operand.
- if (!Kind.empty())
- Operands.push_back(
- AArch64Operand::CreateToken(Kind, false, S, getContext()));
-
- return tryParseVectorIndex(Operands) == MatchOperand_ParseFail;
-}
-
-OperandMatchResultTy
-AArch64AsmParser::tryParseVectorIndex(OperandVector &Operands) {
- SMLoc SIdx = getLoc();
- if (parseOptionalToken(AsmToken::LBrac)) {
- const MCExpr *ImmVal;
- if (getParser().parseExpression(ImmVal))
- return MatchOperand_NoMatch;
- const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
- if (!MCE) {
- TokError("immediate value expected for vector index");
- return MatchOperand_ParseFail;;
- }
-
- SMLoc E = getLoc();
-
- if (parseToken(AsmToken::RBrac, "']' expected"))
- return MatchOperand_ParseFail;;
-
- Operands.push_back(AArch64Operand::CreateVectorIndex(MCE->getValue(), SIdx,
- E, getContext()));
- return MatchOperand_Success;
- }
-
- return MatchOperand_NoMatch;
-}
-
-// tryParseVectorRegister - Try to parse a vector register name with
-// optional kind specifier. If it is a register specifier, eat the token
-// and return it.
-OperandMatchResultTy
-AArch64AsmParser::tryParseVectorRegister(unsigned &Reg, StringRef &Kind,
- RegKind MatchKind) {
- MCAsmParser &Parser = getParser();
- const AsmToken &Tok = Parser.getTok();
-
- if (Tok.isNot(AsmToken::Identifier))
- return MatchOperand_NoMatch;
-
- StringRef Name = Tok.getString();
- // If there is a kind specifier, it's separated from the register name by
- // a '.'.
- size_t Start = 0, Next = Name.find('.');
- StringRef Head = Name.slice(Start, Next);
- unsigned RegNum = matchRegisterNameAlias(Head, MatchKind);
-
- if (RegNum) {
- if (Next != StringRef::npos) {
- Kind = Name.slice(Next, StringRef::npos);
- if (!isValidVectorKind(Kind, MatchKind)) {
- TokError("invalid vector kind qualifier");
- return MatchOperand_ParseFail;
- }
- }
- Parser.Lex(); // Eat the register token.
-
- Reg = RegNum;
- return MatchOperand_Success;
- }
-
- return MatchOperand_NoMatch;
-}
-
-/// tryParseSVEPredicateVector - Parse a SVE predicate register operand.
-OperandMatchResultTy
-AArch64AsmParser::tryParseSVEPredicateVector(OperandVector &Operands) {
- // Check for a SVE predicate register specifier first.
- const SMLoc S = getLoc();
- StringRef Kind;
- unsigned RegNum;
- auto Res = tryParseVectorRegister(RegNum, Kind, RegKind::SVEPredicateVector);
- if (Res != MatchOperand_Success)
- return Res;
-
- const auto &KindRes = parseVectorKind(Kind, RegKind::SVEPredicateVector);
- if (!KindRes)
- return MatchOperand_NoMatch;
-
- unsigned ElementWidth = KindRes->second;
- Operands.push_back(AArch64Operand::CreateVectorReg(
- RegNum, RegKind::SVEPredicateVector, ElementWidth, S,
- getLoc(), getContext()));
-
- // Not all predicates are followed by a '/m' or '/z'.
- MCAsmParser &Parser = getParser();
- if (Parser.getTok().isNot(AsmToken::Slash))
- return MatchOperand_Success;
-
- // But when they do they shouldn't have an element type suffix.
- if (!Kind.empty()) {
- Error(S, "not expecting size suffix");
- return MatchOperand_ParseFail;
- }
-
- // Add a literal slash as operand
- Operands.push_back(
- AArch64Operand::CreateToken("/" , false, getLoc(), getContext()));
-
- Parser.Lex(); // Eat the slash.
-
- // Zeroing or merging?
- auto Pred = Parser.getTok().getString().lower();
- if (Pred != "z" && Pred != "m") {
- Error(getLoc(), "expecting 'm' or 'z' predication");
- return MatchOperand_ParseFail;
- }
-
- // Add zero/merge token.
- const char *ZM = Pred == "z" ? "z" : "m";
- Operands.push_back(
- AArch64Operand::CreateToken(ZM, false, getLoc(), getContext()));
-
- Parser.Lex(); // Eat zero/merge token.
- return MatchOperand_Success;
-}
-
-/// parseRegister - Parse a register operand.
-bool AArch64AsmParser::parseRegister(OperandVector &Operands) {
- // Try for a Neon vector register.
- if (!tryParseNeonVectorRegister(Operands))
- return false;
-
- // Otherwise try for a scalar register.
- if (tryParseGPROperand<false>(Operands) == MatchOperand_Success)
- return false;
-
- return true;
-}
-
-bool AArch64AsmParser::parseSymbolicImmVal(const MCExpr *&ImmVal) {
- MCAsmParser &Parser = getParser();
- bool HasELFModifier = false;
- AArch64MCExpr::VariantKind RefKind;
-
- if (parseOptionalToken(AsmToken::Colon)) {
- HasELFModifier = true;
-
- if (Parser.getTok().isNot(AsmToken::Identifier))
- return TokError("expect relocation specifier in operand after ':'");
-
- std::string LowerCase = Parser.getTok().getIdentifier().lower();
- RefKind = StringSwitch<AArch64MCExpr::VariantKind>(LowerCase)
- .Case("lo12", AArch64MCExpr::VK_LO12)
- .Case("abs_g3", AArch64MCExpr::VK_ABS_G3)
- .Case("abs_g2", AArch64MCExpr::VK_ABS_G2)
- .Case("abs_g2_s", AArch64MCExpr::VK_ABS_G2_S)
- .Case("abs_g2_nc", AArch64MCExpr::VK_ABS_G2_NC)
- .Case("abs_g1", AArch64MCExpr::VK_ABS_G1)
- .Case("abs_g1_s", AArch64MCExpr::VK_ABS_G1_S)
- .Case("abs_g1_nc", AArch64MCExpr::VK_ABS_G1_NC)
- .Case("abs_g0", AArch64MCExpr::VK_ABS_G0)
- .Case("abs_g0_s", AArch64MCExpr::VK_ABS_G0_S)
- .Case("abs_g0_nc", AArch64MCExpr::VK_ABS_G0_NC)
- .Case("prel_g3", AArch64MCExpr::VK_PREL_G3)
- .Case("prel_g2", AArch64MCExpr::VK_PREL_G2)
- .Case("prel_g2_nc", AArch64MCExpr::VK_PREL_G2_NC)
- .Case("prel_g1", AArch64MCExpr::VK_PREL_G1)
- .Case("prel_g1_nc", AArch64MCExpr::VK_PREL_G1_NC)
- .Case("prel_g0", AArch64MCExpr::VK_PREL_G0)
- .Case("prel_g0_nc", AArch64MCExpr::VK_PREL_G0_NC)
- .Case("dtprel_g2", AArch64MCExpr::VK_DTPREL_G2)
- .Case("dtprel_g1", AArch64MCExpr::VK_DTPREL_G1)
- .Case("dtprel_g1_nc", AArch64MCExpr::VK_DTPREL_G1_NC)
- .Case("dtprel_g0", AArch64MCExpr::VK_DTPREL_G0)
- .Case("dtprel_g0_nc", AArch64MCExpr::VK_DTPREL_G0_NC)
- .Case("dtprel_hi12", AArch64MCExpr::VK_DTPREL_HI12)
- .Case("dtprel_lo12", AArch64MCExpr::VK_DTPREL_LO12)
- .Case("dtprel_lo12_nc", AArch64MCExpr::VK_DTPREL_LO12_NC)
- .Case("pg_hi21_nc", AArch64MCExpr::VK_ABS_PAGE_NC)
- .Case("tprel_g2", AArch64MCExpr::VK_TPREL_G2)
- .Case("tprel_g1", AArch64MCExpr::VK_TPREL_G1)
- .Case("tprel_g1_nc", AArch64MCExpr::VK_TPREL_G1_NC)
- .Case("tprel_g0", AArch64MCExpr::VK_TPREL_G0)
- .Case("tprel_g0_nc", AArch64MCExpr::VK_TPREL_G0_NC)
- .Case("tprel_hi12", AArch64MCExpr::VK_TPREL_HI12)
- .Case("tprel_lo12", AArch64MCExpr::VK_TPREL_LO12)
- .Case("tprel_lo12_nc", AArch64MCExpr::VK_TPREL_LO12_NC)
- .Case("tlsdesc_lo12", AArch64MCExpr::VK_TLSDESC_LO12)
- .Case("got", AArch64MCExpr::VK_GOT_PAGE)
+AArch64AsmParser::tryParseSysReg(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ const AsmToken &Tok = Parser.getTok();
+
+ if (Tok.isNot(AsmToken::Identifier))
+ return MatchOperand_NoMatch;
+
+ int MRSReg, MSRReg;
+ auto SysReg = AArch64SysReg::lookupSysRegByName(Tok.getString());
+ if (SysReg && SysReg->haveFeatures(getSTI().getFeatureBits())) {
+ MRSReg = SysReg->Readable ? SysReg->Encoding : -1;
+ MSRReg = SysReg->Writeable ? SysReg->Encoding : -1;
+ } else
+ MRSReg = MSRReg = AArch64SysReg::parseGenericRegister(Tok.getString());
+
+ auto PState = AArch64PState::lookupPStateByName(Tok.getString());
+ unsigned PStateImm = -1;
+ if (PState && PState->haveFeatures(getSTI().getFeatureBits()))
+ PStateImm = PState->Encoding;
+
+ Operands.push_back(
+ AArch64Operand::CreateSysReg(Tok.getString(), getLoc(), MRSReg, MSRReg,
+ PStateImm, getContext()));
+ Parser.Lex(); // Eat identifier
+
+ return MatchOperand_Success;
+}
+
+/// tryParseNeonVectorRegister - Parse a vector register operand.
+bool AArch64AsmParser::tryParseNeonVectorRegister(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ if (Parser.getTok().isNot(AsmToken::Identifier))
+ return true;
+
+ SMLoc S = getLoc();
+ // Check for a vector register specifier first.
+ StringRef Kind;
+ unsigned Reg;
+ OperandMatchResultTy Res =
+ tryParseVectorRegister(Reg, Kind, RegKind::NeonVector);
+ if (Res != MatchOperand_Success)
+ return true;
+
+ const auto &KindRes = parseVectorKind(Kind, RegKind::NeonVector);
+ if (!KindRes)
+ return true;
+
+ unsigned ElementWidth = KindRes->second;
+ Operands.push_back(
+ AArch64Operand::CreateVectorReg(Reg, RegKind::NeonVector, ElementWidth,
+ S, getLoc(), getContext()));
+
+ // If there was an explicit qualifier, that goes on as a literal text
+ // operand.
+ if (!Kind.empty())
+ Operands.push_back(
+ AArch64Operand::CreateToken(Kind, false, S, getContext()));
+
+ return tryParseVectorIndex(Operands) == MatchOperand_ParseFail;
+}
+
+OperandMatchResultTy
+AArch64AsmParser::tryParseVectorIndex(OperandVector &Operands) {
+ SMLoc SIdx = getLoc();
+ if (parseOptionalToken(AsmToken::LBrac)) {
+ const MCExpr *ImmVal;
+ if (getParser().parseExpression(ImmVal))
+ return MatchOperand_NoMatch;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
+ if (!MCE) {
+ TokError("immediate value expected for vector index");
+ return MatchOperand_ParseFail;;
+ }
+
+ SMLoc E = getLoc();
+
+ if (parseToken(AsmToken::RBrac, "']' expected"))
+ return MatchOperand_ParseFail;;
+
+ Operands.push_back(AArch64Operand::CreateVectorIndex(MCE->getValue(), SIdx,
+ E, getContext()));
+ return MatchOperand_Success;
+ }
+
+ return MatchOperand_NoMatch;
+}
+
+// tryParseVectorRegister - Try to parse a vector register name with
+// optional kind specifier. If it is a register specifier, eat the token
+// and return it.
+OperandMatchResultTy
+AArch64AsmParser::tryParseVectorRegister(unsigned &Reg, StringRef &Kind,
+ RegKind MatchKind) {
+ MCAsmParser &Parser = getParser();
+ const AsmToken &Tok = Parser.getTok();
+
+ if (Tok.isNot(AsmToken::Identifier))
+ return MatchOperand_NoMatch;
+
+ StringRef Name = Tok.getString();
+ // If there is a kind specifier, it's separated from the register name by
+ // a '.'.
+ size_t Start = 0, Next = Name.find('.');
+ StringRef Head = Name.slice(Start, Next);
+ unsigned RegNum = matchRegisterNameAlias(Head, MatchKind);
+
+ if (RegNum) {
+ if (Next != StringRef::npos) {
+ Kind = Name.slice(Next, StringRef::npos);
+ if (!isValidVectorKind(Kind, MatchKind)) {
+ TokError("invalid vector kind qualifier");
+ return MatchOperand_ParseFail;
+ }
+ }
+ Parser.Lex(); // Eat the register token.
+
+ Reg = RegNum;
+ return MatchOperand_Success;
+ }
+
+ return MatchOperand_NoMatch;
+}
+
+/// tryParseSVEPredicateVector - Parse a SVE predicate register operand.
+OperandMatchResultTy
+AArch64AsmParser::tryParseSVEPredicateVector(OperandVector &Operands) {
+ // Check for a SVE predicate register specifier first.
+ const SMLoc S = getLoc();
+ StringRef Kind;
+ unsigned RegNum;
+ auto Res = tryParseVectorRegister(RegNum, Kind, RegKind::SVEPredicateVector);
+ if (Res != MatchOperand_Success)
+ return Res;
+
+ const auto &KindRes = parseVectorKind(Kind, RegKind::SVEPredicateVector);
+ if (!KindRes)
+ return MatchOperand_NoMatch;
+
+ unsigned ElementWidth = KindRes->second;
+ Operands.push_back(AArch64Operand::CreateVectorReg(
+ RegNum, RegKind::SVEPredicateVector, ElementWidth, S,
+ getLoc(), getContext()));
+
+ // Not all predicates are followed by a '/m' or '/z'.
+ MCAsmParser &Parser = getParser();
+ if (Parser.getTok().isNot(AsmToken::Slash))
+ return MatchOperand_Success;
+
+ // But when they do they shouldn't have an element type suffix.
+ if (!Kind.empty()) {
+ Error(S, "not expecting size suffix");
+ return MatchOperand_ParseFail;
+ }
+
+ // Add a literal slash as operand
+ Operands.push_back(
+ AArch64Operand::CreateToken("/" , false, getLoc(), getContext()));
+
+ Parser.Lex(); // Eat the slash.
+
+ // Zeroing or merging?
+ auto Pred = Parser.getTok().getString().lower();
+ if (Pred != "z" && Pred != "m") {
+ Error(getLoc(), "expecting 'm' or 'z' predication");
+ return MatchOperand_ParseFail;
+ }
+
+ // Add zero/merge token.
+ const char *ZM = Pred == "z" ? "z" : "m";
+ Operands.push_back(
+ AArch64Operand::CreateToken(ZM, false, getLoc(), getContext()));
+
+ Parser.Lex(); // Eat zero/merge token.
+ return MatchOperand_Success;
+}
+
+/// parseRegister - Parse a register operand.
+bool AArch64AsmParser::parseRegister(OperandVector &Operands) {
+ // Try for a Neon vector register.
+ if (!tryParseNeonVectorRegister(Operands))
+ return false;
+
+ // Otherwise try for a scalar register.
+ if (tryParseGPROperand<false>(Operands) == MatchOperand_Success)
+ return false;
+
+ return true;
+}
+
+bool AArch64AsmParser::parseSymbolicImmVal(const MCExpr *&ImmVal) {
+ MCAsmParser &Parser = getParser();
+ bool HasELFModifier = false;
+ AArch64MCExpr::VariantKind RefKind;
+
+ if (parseOptionalToken(AsmToken::Colon)) {
+ HasELFModifier = true;
+
+ if (Parser.getTok().isNot(AsmToken::Identifier))
+ return TokError("expect relocation specifier in operand after ':'");
+
+ std::string LowerCase = Parser.getTok().getIdentifier().lower();
+ RefKind = StringSwitch<AArch64MCExpr::VariantKind>(LowerCase)
+ .Case("lo12", AArch64MCExpr::VK_LO12)
+ .Case("abs_g3", AArch64MCExpr::VK_ABS_G3)
+ .Case("abs_g2", AArch64MCExpr::VK_ABS_G2)
+ .Case("abs_g2_s", AArch64MCExpr::VK_ABS_G2_S)
+ .Case("abs_g2_nc", AArch64MCExpr::VK_ABS_G2_NC)
+ .Case("abs_g1", AArch64MCExpr::VK_ABS_G1)
+ .Case("abs_g1_s", AArch64MCExpr::VK_ABS_G1_S)
+ .Case("abs_g1_nc", AArch64MCExpr::VK_ABS_G1_NC)
+ .Case("abs_g0", AArch64MCExpr::VK_ABS_G0)
+ .Case("abs_g0_s", AArch64MCExpr::VK_ABS_G0_S)
+ .Case("abs_g0_nc", AArch64MCExpr::VK_ABS_G0_NC)
+ .Case("prel_g3", AArch64MCExpr::VK_PREL_G3)
+ .Case("prel_g2", AArch64MCExpr::VK_PREL_G2)
+ .Case("prel_g2_nc", AArch64MCExpr::VK_PREL_G2_NC)
+ .Case("prel_g1", AArch64MCExpr::VK_PREL_G1)
+ .Case("prel_g1_nc", AArch64MCExpr::VK_PREL_G1_NC)
+ .Case("prel_g0", AArch64MCExpr::VK_PREL_G0)
+ .Case("prel_g0_nc", AArch64MCExpr::VK_PREL_G0_NC)
+ .Case("dtprel_g2", AArch64MCExpr::VK_DTPREL_G2)
+ .Case("dtprel_g1", AArch64MCExpr::VK_DTPREL_G1)
+ .Case("dtprel_g1_nc", AArch64MCExpr::VK_DTPREL_G1_NC)
+ .Case("dtprel_g0", AArch64MCExpr::VK_DTPREL_G0)
+ .Case("dtprel_g0_nc", AArch64MCExpr::VK_DTPREL_G0_NC)
+ .Case("dtprel_hi12", AArch64MCExpr::VK_DTPREL_HI12)
+ .Case("dtprel_lo12", AArch64MCExpr::VK_DTPREL_LO12)
+ .Case("dtprel_lo12_nc", AArch64MCExpr::VK_DTPREL_LO12_NC)
+ .Case("pg_hi21_nc", AArch64MCExpr::VK_ABS_PAGE_NC)
+ .Case("tprel_g2", AArch64MCExpr::VK_TPREL_G2)
+ .Case("tprel_g1", AArch64MCExpr::VK_TPREL_G1)
+ .Case("tprel_g1_nc", AArch64MCExpr::VK_TPREL_G1_NC)
+ .Case("tprel_g0", AArch64MCExpr::VK_TPREL_G0)
+ .Case("tprel_g0_nc", AArch64MCExpr::VK_TPREL_G0_NC)
+ .Case("tprel_hi12", AArch64MCExpr::VK_TPREL_HI12)
+ .Case("tprel_lo12", AArch64MCExpr::VK_TPREL_LO12)
+ .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)
- .Case("gottprel_g1", AArch64MCExpr::VK_GOTTPREL_G1)
- .Case("gottprel_g0_nc", AArch64MCExpr::VK_GOTTPREL_G0_NC)
- .Case("tlsdesc", AArch64MCExpr::VK_TLSDESC_PAGE)
- .Case("secrel_lo12", AArch64MCExpr::VK_SECREL_LO12)
- .Case("secrel_hi12", AArch64MCExpr::VK_SECREL_HI12)
- .Default(AArch64MCExpr::VK_INVALID);
-
- if (RefKind == AArch64MCExpr::VK_INVALID)
- return TokError("expect relocation specifier in operand after ':'");
-
- Parser.Lex(); // Eat identifier
-
- if (parseToken(AsmToken::Colon, "expect ':' after relocation specifier"))
- return true;
- }
-
- if (getParser().parseExpression(ImmVal))
- return true;
-
- if (HasELFModifier)
- ImmVal = AArch64MCExpr::create(ImmVal, RefKind, getContext());
-
- return false;
-}
-
-template <RegKind VectorKind>
-OperandMatchResultTy
-AArch64AsmParser::tryParseVectorList(OperandVector &Operands,
- bool ExpectMatch) {
- MCAsmParser &Parser = getParser();
- if (!Parser.getTok().is(AsmToken::LCurly))
- return MatchOperand_NoMatch;
-
- // Wrapper around parse function
- auto ParseVector = [this, &Parser](unsigned &Reg, StringRef &Kind, SMLoc Loc,
- bool NoMatchIsError) {
- auto RegTok = Parser.getTok();
- auto ParseRes = tryParseVectorRegister(Reg, Kind, VectorKind);
- if (ParseRes == MatchOperand_Success) {
- if (parseVectorKind(Kind, VectorKind))
- return ParseRes;
- llvm_unreachable("Expected a valid vector kind");
- }
-
- if (RegTok.isNot(AsmToken::Identifier) ||
- ParseRes == MatchOperand_ParseFail ||
- (ParseRes == MatchOperand_NoMatch && NoMatchIsError)) {
- Error(Loc, "vector register expected");
- return MatchOperand_ParseFail;
- }
-
- return MatchOperand_NoMatch;
- };
-
- SMLoc S = getLoc();
- auto LCurly = Parser.getTok();
- Parser.Lex(); // Eat left bracket token.
-
- StringRef Kind;
- unsigned FirstReg;
- auto ParseRes = ParseVector(FirstReg, Kind, getLoc(), ExpectMatch);
-
- // Put back the original left bracket if there was no match, so that
- // different types of list-operands can be matched (e.g. SVE, Neon).
- if (ParseRes == MatchOperand_NoMatch)
- Parser.getLexer().UnLex(LCurly);
-
- if (ParseRes != MatchOperand_Success)
- return ParseRes;
-
- int64_t PrevReg = FirstReg;
- unsigned Count = 1;
-
- if (parseOptionalToken(AsmToken::Minus)) {
- SMLoc Loc = getLoc();
- StringRef NextKind;
-
- unsigned Reg;
- ParseRes = ParseVector(Reg, NextKind, getLoc(), true);
- if (ParseRes != MatchOperand_Success)
- return ParseRes;
-
- // Any Kind suffices must match on all regs in the list.
- if (Kind != NextKind) {
- Error(Loc, "mismatched register size suffix");
- return MatchOperand_ParseFail;
- }
-
- unsigned Space = (PrevReg < Reg) ? (Reg - PrevReg) : (Reg + 32 - PrevReg);
-
- if (Space == 0 || Space > 3) {
- Error(Loc, "invalid number of vectors");
- return MatchOperand_ParseFail;
- }
-
- Count += Space;
- }
- else {
- while (parseOptionalToken(AsmToken::Comma)) {
- SMLoc Loc = getLoc();
- StringRef NextKind;
- unsigned Reg;
- ParseRes = ParseVector(Reg, NextKind, getLoc(), true);
- if (ParseRes != MatchOperand_Success)
- return ParseRes;
-
- // Any Kind suffices must match on all regs in the list.
- if (Kind != NextKind) {
- Error(Loc, "mismatched register size suffix");
- return MatchOperand_ParseFail;
- }
-
- // Registers must be incremental (with wraparound at 31)
- if (getContext().getRegisterInfo()->getEncodingValue(Reg) !=
- (getContext().getRegisterInfo()->getEncodingValue(PrevReg) + 1) % 32) {
- Error(Loc, "registers must be sequential");
- return MatchOperand_ParseFail;
- }
-
- PrevReg = Reg;
- ++Count;
- }
- }
-
- if (parseToken(AsmToken::RCurly, "'}' expected"))
- return MatchOperand_ParseFail;
-
- if (Count > 4) {
- Error(S, "invalid number of vectors");
- return MatchOperand_ParseFail;
- }
-
- unsigned NumElements = 0;
- unsigned ElementWidth = 0;
- if (!Kind.empty()) {
- if (const auto &VK = parseVectorKind(Kind, VectorKind))
- std::tie(NumElements, ElementWidth) = *VK;
- }
-
- Operands.push_back(AArch64Operand::CreateVectorList(
- FirstReg, Count, NumElements, ElementWidth, VectorKind, S, getLoc(),
- getContext()));
-
- return MatchOperand_Success;
-}
-
-/// parseNeonVectorList - Parse a vector list operand for AdvSIMD instructions.
-bool AArch64AsmParser::parseNeonVectorList(OperandVector &Operands) {
- auto ParseRes = tryParseVectorList<RegKind::NeonVector>(Operands, true);
- if (ParseRes != MatchOperand_Success)
- return true;
-
- return tryParseVectorIndex(Operands) == MatchOperand_ParseFail;
-}
-
-OperandMatchResultTy
-AArch64AsmParser::tryParseGPR64sp0Operand(OperandVector &Operands) {
- SMLoc StartLoc = getLoc();
-
- unsigned RegNum;
- OperandMatchResultTy Res = tryParseScalarRegister(RegNum);
- if (Res != MatchOperand_Success)
- return Res;
-
- if (!parseOptionalToken(AsmToken::Comma)) {
- Operands.push_back(AArch64Operand::CreateReg(
- RegNum, RegKind::Scalar, StartLoc, getLoc(), getContext()));
- return MatchOperand_Success;
- }
-
- parseOptionalToken(AsmToken::Hash);
-
- if (getParser().getTok().isNot(AsmToken::Integer)) {
- Error(getLoc(), "index must be absent or #0");
- return MatchOperand_ParseFail;
- }
-
- const MCExpr *ImmVal;
- if (getParser().parseExpression(ImmVal) || !isa<MCConstantExpr>(ImmVal) ||
- cast<MCConstantExpr>(ImmVal)->getValue() != 0) {
- Error(getLoc(), "index must be absent or #0");
- return MatchOperand_ParseFail;
- }
-
- Operands.push_back(AArch64Operand::CreateReg(
- RegNum, RegKind::Scalar, StartLoc, getLoc(), getContext()));
- return MatchOperand_Success;
-}
-
-template <bool ParseShiftExtend, RegConstraintEqualityTy EqTy>
-OperandMatchResultTy
-AArch64AsmParser::tryParseGPROperand(OperandVector &Operands) {
- SMLoc StartLoc = getLoc();
-
- unsigned RegNum;
- OperandMatchResultTy Res = tryParseScalarRegister(RegNum);
- if (Res != MatchOperand_Success)
- return Res;
-
- // No shift/extend is the default.
- if (!ParseShiftExtend || getParser().getTok().isNot(AsmToken::Comma)) {
- Operands.push_back(AArch64Operand::CreateReg(
- RegNum, RegKind::Scalar, StartLoc, getLoc(), getContext(), EqTy));
- return MatchOperand_Success;
- }
-
- // Eat the comma
- getParser().Lex();
-
- // Match the shift
- SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> ExtOpnd;
- Res = tryParseOptionalShiftExtend(ExtOpnd);
- if (Res != MatchOperand_Success)
- return Res;
-
- auto Ext = static_cast<AArch64Operand*>(ExtOpnd.back().get());
- Operands.push_back(AArch64Operand::CreateReg(
- RegNum, RegKind::Scalar, StartLoc, Ext->getEndLoc(), getContext(), EqTy,
- Ext->getShiftExtendType(), Ext->getShiftExtendAmount(),
- Ext->hasShiftExtendAmount()));
-
- return MatchOperand_Success;
-}
-
-bool AArch64AsmParser::parseOptionalMulOperand(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
-
- // Some SVE instructions have a decoration after the immediate, i.e.
- // "mul vl". We parse them here and add tokens, which must be present in the
- // asm string in the tablegen instruction.
- bool NextIsVL = Parser.getLexer().peekTok().getString().equals_lower("vl");
- bool NextIsHash = Parser.getLexer().peekTok().is(AsmToken::Hash);
- if (!Parser.getTok().getString().equals_lower("mul") ||
- !(NextIsVL || NextIsHash))
- return true;
-
- Operands.push_back(
- AArch64Operand::CreateToken("mul", false, getLoc(), getContext()));
- Parser.Lex(); // Eat the "mul"
-
- if (NextIsVL) {
- Operands.push_back(
- AArch64Operand::CreateToken("vl", false, getLoc(), getContext()));
- Parser.Lex(); // Eat the "vl"
- return false;
- }
-
- if (NextIsHash) {
- Parser.Lex(); // Eat the #
- SMLoc S = getLoc();
-
- // Parse immediate operand.
- const MCExpr *ImmVal;
- if (!Parser.parseExpression(ImmVal))
- if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal)) {
- Operands.push_back(AArch64Operand::CreateImm(
- MCConstantExpr::create(MCE->getValue(), getContext()), S, getLoc(),
- getContext()));
- return MatchOperand_Success;
- }
- }
-
- return Error(getLoc(), "expected 'vl' or '#<imm>'");
-}
-
+ .Case("got_lo12", AArch64MCExpr::VK_GOT_LO12)
+ .Case("gottprel", AArch64MCExpr::VK_GOTTPREL_PAGE)
+ .Case("gottprel_lo12", AArch64MCExpr::VK_GOTTPREL_LO12_NC)
+ .Case("gottprel_g1", AArch64MCExpr::VK_GOTTPREL_G1)
+ .Case("gottprel_g0_nc", AArch64MCExpr::VK_GOTTPREL_G0_NC)
+ .Case("tlsdesc", AArch64MCExpr::VK_TLSDESC_PAGE)
+ .Case("secrel_lo12", AArch64MCExpr::VK_SECREL_LO12)
+ .Case("secrel_hi12", AArch64MCExpr::VK_SECREL_HI12)
+ .Default(AArch64MCExpr::VK_INVALID);
+
+ if (RefKind == AArch64MCExpr::VK_INVALID)
+ return TokError("expect relocation specifier in operand after ':'");
+
+ Parser.Lex(); // Eat identifier
+
+ if (parseToken(AsmToken::Colon, "expect ':' after relocation specifier"))
+ return true;
+ }
+
+ if (getParser().parseExpression(ImmVal))
+ return true;
+
+ if (HasELFModifier)
+ ImmVal = AArch64MCExpr::create(ImmVal, RefKind, getContext());
+
+ return false;
+}
+
+template <RegKind VectorKind>
+OperandMatchResultTy
+AArch64AsmParser::tryParseVectorList(OperandVector &Operands,
+ bool ExpectMatch) {
+ MCAsmParser &Parser = getParser();
+ if (!Parser.getTok().is(AsmToken::LCurly))
+ return MatchOperand_NoMatch;
+
+ // Wrapper around parse function
+ auto ParseVector = [this, &Parser](unsigned &Reg, StringRef &Kind, SMLoc Loc,
+ bool NoMatchIsError) {
+ auto RegTok = Parser.getTok();
+ auto ParseRes = tryParseVectorRegister(Reg, Kind, VectorKind);
+ if (ParseRes == MatchOperand_Success) {
+ if (parseVectorKind(Kind, VectorKind))
+ return ParseRes;
+ llvm_unreachable("Expected a valid vector kind");
+ }
+
+ if (RegTok.isNot(AsmToken::Identifier) ||
+ ParseRes == MatchOperand_ParseFail ||
+ (ParseRes == MatchOperand_NoMatch && NoMatchIsError)) {
+ Error(Loc, "vector register expected");
+ return MatchOperand_ParseFail;
+ }
+
+ return MatchOperand_NoMatch;
+ };
+
+ SMLoc S = getLoc();
+ auto LCurly = Parser.getTok();
+ Parser.Lex(); // Eat left bracket token.
+
+ StringRef Kind;
+ unsigned FirstReg;
+ auto ParseRes = ParseVector(FirstReg, Kind, getLoc(), ExpectMatch);
+
+ // Put back the original left bracket if there was no match, so that
+ // different types of list-operands can be matched (e.g. SVE, Neon).
+ if (ParseRes == MatchOperand_NoMatch)
+ Parser.getLexer().UnLex(LCurly);
+
+ if (ParseRes != MatchOperand_Success)
+ return ParseRes;
+
+ int64_t PrevReg = FirstReg;
+ unsigned Count = 1;
+
+ if (parseOptionalToken(AsmToken::Minus)) {
+ SMLoc Loc = getLoc();
+ StringRef NextKind;
+
+ unsigned Reg;
+ ParseRes = ParseVector(Reg, NextKind, getLoc(), true);
+ if (ParseRes != MatchOperand_Success)
+ return ParseRes;
+
+ // Any Kind suffices must match on all regs in the list.
+ if (Kind != NextKind) {
+ Error(Loc, "mismatched register size suffix");
+ return MatchOperand_ParseFail;
+ }
+
+ unsigned Space = (PrevReg < Reg) ? (Reg - PrevReg) : (Reg + 32 - PrevReg);
+
+ if (Space == 0 || Space > 3) {
+ Error(Loc, "invalid number of vectors");
+ return MatchOperand_ParseFail;
+ }
+
+ Count += Space;
+ }
+ else {
+ while (parseOptionalToken(AsmToken::Comma)) {
+ SMLoc Loc = getLoc();
+ StringRef NextKind;
+ unsigned Reg;
+ ParseRes = ParseVector(Reg, NextKind, getLoc(), true);
+ if (ParseRes != MatchOperand_Success)
+ return ParseRes;
+
+ // Any Kind suffices must match on all regs in the list.
+ if (Kind != NextKind) {
+ Error(Loc, "mismatched register size suffix");
+ return MatchOperand_ParseFail;
+ }
+
+ // Registers must be incremental (with wraparound at 31)
+ if (getContext().getRegisterInfo()->getEncodingValue(Reg) !=
+ (getContext().getRegisterInfo()->getEncodingValue(PrevReg) + 1) % 32) {
+ Error(Loc, "registers must be sequential");
+ return MatchOperand_ParseFail;
+ }
+
+ PrevReg = Reg;
+ ++Count;
+ }
+ }
+
+ if (parseToken(AsmToken::RCurly, "'}' expected"))
+ return MatchOperand_ParseFail;
+
+ if (Count > 4) {
+ Error(S, "invalid number of vectors");
+ return MatchOperand_ParseFail;
+ }
+
+ unsigned NumElements = 0;
+ unsigned ElementWidth = 0;
+ if (!Kind.empty()) {
+ if (const auto &VK = parseVectorKind(Kind, VectorKind))
+ std::tie(NumElements, ElementWidth) = *VK;
+ }
+
+ Operands.push_back(AArch64Operand::CreateVectorList(
+ FirstReg, Count, NumElements, ElementWidth, VectorKind, S, getLoc(),
+ getContext()));
+
+ return MatchOperand_Success;
+}
+
+/// parseNeonVectorList - Parse a vector list operand for AdvSIMD instructions.
+bool AArch64AsmParser::parseNeonVectorList(OperandVector &Operands) {
+ auto ParseRes = tryParseVectorList<RegKind::NeonVector>(Operands, true);
+ if (ParseRes != MatchOperand_Success)
+ return true;
+
+ return tryParseVectorIndex(Operands) == MatchOperand_ParseFail;
+}
+
+OperandMatchResultTy
+AArch64AsmParser::tryParseGPR64sp0Operand(OperandVector &Operands) {
+ SMLoc StartLoc = getLoc();
+
+ unsigned RegNum;
+ OperandMatchResultTy Res = tryParseScalarRegister(RegNum);
+ if (Res != MatchOperand_Success)
+ return Res;
+
+ if (!parseOptionalToken(AsmToken::Comma)) {
+ Operands.push_back(AArch64Operand::CreateReg(
+ RegNum, RegKind::Scalar, StartLoc, getLoc(), getContext()));
+ return MatchOperand_Success;
+ }
+
+ parseOptionalToken(AsmToken::Hash);
+
+ if (getParser().getTok().isNot(AsmToken::Integer)) {
+ Error(getLoc(), "index must be absent or #0");
+ return MatchOperand_ParseFail;
+ }
+
+ const MCExpr *ImmVal;
+ if (getParser().parseExpression(ImmVal) || !isa<MCConstantExpr>(ImmVal) ||
+ cast<MCConstantExpr>(ImmVal)->getValue() != 0) {
+ Error(getLoc(), "index must be absent or #0");
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(AArch64Operand::CreateReg(
+ RegNum, RegKind::Scalar, StartLoc, getLoc(), getContext()));
+ return MatchOperand_Success;
+}
+
+template <bool ParseShiftExtend, RegConstraintEqualityTy EqTy>
+OperandMatchResultTy
+AArch64AsmParser::tryParseGPROperand(OperandVector &Operands) {
+ SMLoc StartLoc = getLoc();
+
+ unsigned RegNum;
+ OperandMatchResultTy Res = tryParseScalarRegister(RegNum);
+ if (Res != MatchOperand_Success)
+ return Res;
+
+ // No shift/extend is the default.
+ if (!ParseShiftExtend || getParser().getTok().isNot(AsmToken::Comma)) {
+ Operands.push_back(AArch64Operand::CreateReg(
+ RegNum, RegKind::Scalar, StartLoc, getLoc(), getContext(), EqTy));
+ return MatchOperand_Success;
+ }
+
+ // Eat the comma
+ getParser().Lex();
+
+ // Match the shift
+ SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> ExtOpnd;
+ Res = tryParseOptionalShiftExtend(ExtOpnd);
+ if (Res != MatchOperand_Success)
+ return Res;
+
+ auto Ext = static_cast<AArch64Operand*>(ExtOpnd.back().get());
+ Operands.push_back(AArch64Operand::CreateReg(
+ RegNum, RegKind::Scalar, StartLoc, Ext->getEndLoc(), getContext(), EqTy,
+ Ext->getShiftExtendType(), Ext->getShiftExtendAmount(),
+ Ext->hasShiftExtendAmount()));
+
+ return MatchOperand_Success;
+}
+
+bool AArch64AsmParser::parseOptionalMulOperand(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+
+ // Some SVE instructions have a decoration after the immediate, i.e.
+ // "mul vl". We parse them here and add tokens, which must be present in the
+ // asm string in the tablegen instruction.
+ bool NextIsVL = Parser.getLexer().peekTok().getString().equals_lower("vl");
+ bool NextIsHash = Parser.getLexer().peekTok().is(AsmToken::Hash);
+ if (!Parser.getTok().getString().equals_lower("mul") ||
+ !(NextIsVL || NextIsHash))
+ return true;
+
+ Operands.push_back(
+ AArch64Operand::CreateToken("mul", false, getLoc(), getContext()));
+ Parser.Lex(); // Eat the "mul"
+
+ if (NextIsVL) {
+ Operands.push_back(
+ AArch64Operand::CreateToken("vl", false, getLoc(), getContext()));
+ Parser.Lex(); // Eat the "vl"
+ return false;
+ }
+
+ if (NextIsHash) {
+ Parser.Lex(); // Eat the #
+ SMLoc S = getLoc();
+
+ // Parse immediate operand.
+ const MCExpr *ImmVal;
+ if (!Parser.parseExpression(ImmVal))
+ if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal)) {
+ Operands.push_back(AArch64Operand::CreateImm(
+ MCConstantExpr::create(MCE->getValue(), getContext()), S, getLoc(),
+ getContext()));
+ return MatchOperand_Success;
+ }
+ }
+
+ return Error(getLoc(), "expected 'vl' or '#<imm>'");
+}
+
bool AArch64AsmParser::parseKeywordOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
auto Tok = Parser.getTok();
@@ -3718,183 +3718,183 @@ bool AArch64AsmParser::parseKeywordOperand(OperandVector &Operands) {
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,
- bool invertCondCode) {
- MCAsmParser &Parser = getParser();
-
- OperandMatchResultTy ResTy =
- MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/ true);
-
- // Check if the current operand has a custom associated parser, if so, try to
- // custom parse the operand, or fallback to the general approach.
- if (ResTy == MatchOperand_Success)
- return false;
- // If there wasn't a custom match, try the generic matcher below. Otherwise,
- // there was a match, but an error occurred, in which case, just return that
- // the operand parsing failed.
- if (ResTy == MatchOperand_ParseFail)
- return true;
-
- // Nothing custom, so do general case parsing.
- SMLoc S, E;
- switch (getLexer().getKind()) {
- default: {
- SMLoc S = getLoc();
- const MCExpr *Expr;
- if (parseSymbolicImmVal(Expr))
- return Error(S, "invalid operand");
-
- SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
- Operands.push_back(AArch64Operand::CreateImm(Expr, S, E, getContext()));
- return false;
- }
- case AsmToken::LBrac: {
- SMLoc Loc = Parser.getTok().getLoc();
- Operands.push_back(AArch64Operand::CreateToken("[", false, Loc,
- getContext()));
- Parser.Lex(); // Eat '['
-
- // There's no comma after a '[', so we can parse the next operand
- // immediately.
- return parseOperand(Operands, false, false);
- }
- case AsmToken::LCurly:
- return parseNeonVectorList(Operands);
- case AsmToken::Identifier: {
- // If we're expecting a Condition Code operand, then just parse that.
- if (isCondCode)
- return parseCondCode(Operands, invertCondCode);
-
- // If it's a register name, parse it.
- if (!parseRegister(Operands))
- return false;
-
- // See if this is a "mul vl" decoration or "mul #<int>" operand used
- // by SVE instructions.
- if (!parseOptionalMulOperand(Operands))
- return false;
-
- // This could be an optional "shift" or "extend" operand.
- OperandMatchResultTy GotShift = tryParseOptionalShiftExtend(Operands);
- // We can only continue if no tokens were eaten.
- if (GotShift != MatchOperand_NoMatch)
- return GotShift;
-
+/// parseOperand - Parse a arm instruction operand. For now this parses the
+/// operand regardless of the mnemonic.
+bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
+ bool invertCondCode) {
+ MCAsmParser &Parser = getParser();
+
+ OperandMatchResultTy ResTy =
+ MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/ true);
+
+ // Check if the current operand has a custom associated parser, if so, try to
+ // custom parse the operand, or fallback to the general approach.
+ if (ResTy == MatchOperand_Success)
+ return false;
+ // If there wasn't a custom match, try the generic matcher below. Otherwise,
+ // there was a match, but an error occurred, in which case, just return that
+ // the operand parsing failed.
+ if (ResTy == MatchOperand_ParseFail)
+ return true;
+
+ // Nothing custom, so do general case parsing.
+ SMLoc S, E;
+ switch (getLexer().getKind()) {
+ default: {
+ SMLoc S = getLoc();
+ const MCExpr *Expr;
+ if (parseSymbolicImmVal(Expr))
+ return Error(S, "invalid operand");
+
+ SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
+ Operands.push_back(AArch64Operand::CreateImm(Expr, S, E, getContext()));
+ return false;
+ }
+ case AsmToken::LBrac: {
+ SMLoc Loc = Parser.getTok().getLoc();
+ Operands.push_back(AArch64Operand::CreateToken("[", false, Loc,
+ getContext()));
+ Parser.Lex(); // Eat '['
+
+ // There's no comma after a '[', so we can parse the next operand
+ // immediately.
+ return parseOperand(Operands, false, false);
+ }
+ case AsmToken::LCurly:
+ return parseNeonVectorList(Operands);
+ case AsmToken::Identifier: {
+ // If we're expecting a Condition Code operand, then just parse that.
+ if (isCondCode)
+ return parseCondCode(Operands, invertCondCode);
+
+ // If it's a register name, parse it.
+ if (!parseRegister(Operands))
+ return false;
+
+ // See if this is a "mul vl" decoration or "mul #<int>" operand used
+ // by SVE instructions.
+ if (!parseOptionalMulOperand(Operands))
+ return false;
+
+ // This could be an optional "shift" or "extend" operand.
+ OperandMatchResultTy GotShift = tryParseOptionalShiftExtend(Operands);
+ // We can only continue if no tokens were eaten.
+ 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;
- S = getLoc();
- if (getParser().parseExpression(IdVal))
- return true;
- E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
- Operands.push_back(AArch64Operand::CreateImm(IdVal, S, E, getContext()));
- return false;
- }
- case AsmToken::Integer:
- case AsmToken::Real:
- case AsmToken::Hash: {
- // #42 -> immediate.
- S = getLoc();
-
- parseOptionalToken(AsmToken::Hash);
-
- // Parse a negative sign
- bool isNegative = false;
- if (Parser.getTok().is(AsmToken::Minus)) {
- isNegative = true;
- // We need to consume this token only when we have a Real, otherwise
- // we let parseSymbolicImmVal take care of it
- if (Parser.getLexer().peekTok().is(AsmToken::Real))
- Parser.Lex();
- }
-
- // The only Real that should come through here is a literal #0.0 for
- // the fcmp[e] r, #0.0 instructions. They expect raw token operands,
- // so convert the value.
- const AsmToken &Tok = Parser.getTok();
- if (Tok.is(AsmToken::Real)) {
- APFloat RealVal(APFloat::IEEEdouble(), Tok.getString());
- uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
- if (Mnemonic != "fcmp" && Mnemonic != "fcmpe" && Mnemonic != "fcmeq" &&
- Mnemonic != "fcmge" && Mnemonic != "fcmgt" && Mnemonic != "fcmle" &&
- Mnemonic != "fcmlt" && Mnemonic != "fcmne")
- return TokError("unexpected floating point literal");
- else if (IntVal != 0 || isNegative)
- return TokError("expected floating-point constant #0.0");
- Parser.Lex(); // Eat the token.
-
- Operands.push_back(
- AArch64Operand::CreateToken("#0", false, S, getContext()));
- Operands.push_back(
- AArch64Operand::CreateToken(".0", false, S, getContext()));
- return false;
- }
-
- const MCExpr *ImmVal;
- if (parseSymbolicImmVal(ImmVal))
- return true;
-
- E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
- Operands.push_back(AArch64Operand::CreateImm(ImmVal, S, E, getContext()));
- return false;
- }
- case AsmToken::Equal: {
- SMLoc Loc = getLoc();
- if (Mnemonic != "ldr") // only parse for ldr pseudo (e.g. ldr r0, =val)
- return TokError("unexpected token in operand");
- Parser.Lex(); // Eat '='
- const MCExpr *SubExprVal;
- if (getParser().parseExpression(SubExprVal))
- return true;
-
- if (Operands.size() < 2 ||
- !static_cast<AArch64Operand &>(*Operands[1]).isScalarReg())
- return Error(Loc, "Only valid when first operand is register");
-
- bool IsXReg =
- AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
- Operands[1]->getReg());
-
- MCContext& Ctx = getContext();
- E = SMLoc::getFromPointer(Loc.getPointer() - 1);
- // If the op is an imm and can be fit into a mov, then replace ldr with mov.
- if (isa<MCConstantExpr>(SubExprVal)) {
- uint64_t Imm = (cast<MCConstantExpr>(SubExprVal))->getValue();
- uint32_t ShiftAmt = 0, MaxShiftAmt = IsXReg ? 48 : 16;
- while(Imm > 0xFFFF && countTrailingZeros(Imm) >= 16) {
- ShiftAmt += 16;
- Imm >>= 16;
- }
- if (ShiftAmt <= MaxShiftAmt && Imm <= 0xFFFF) {
- Operands[0] = AArch64Operand::CreateToken("movz", false, Loc, Ctx);
- Operands.push_back(AArch64Operand::CreateImm(
- MCConstantExpr::create(Imm, Ctx), S, E, Ctx));
- if (ShiftAmt)
- Operands.push_back(AArch64Operand::CreateShiftExtend(AArch64_AM::LSL,
- ShiftAmt, true, S, E, Ctx));
- return false;
- }
- APInt Simm = APInt(64, Imm << ShiftAmt);
- // check if the immediate is an unsigned or signed 32-bit int for W regs
- if (!IsXReg && !(Simm.isIntN(32) || Simm.isSignedIntN(32)))
- return Error(Loc, "Immediate too large for register");
- }
- // If it is a label or an imm that cannot fit in a movz, put it into CP.
- const MCExpr *CPLoc =
- getTargetStreamer().addConstantPoolEntry(SubExprVal, IsXReg ? 8 : 4, Loc);
- Operands.push_back(AArch64Operand::CreateImm(CPLoc, S, E, Ctx));
- return false;
- }
- }
-}
-
+ // 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;
+ S = getLoc();
+ if (getParser().parseExpression(IdVal))
+ return true;
+ E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
+ Operands.push_back(AArch64Operand::CreateImm(IdVal, S, E, getContext()));
+ return false;
+ }
+ case AsmToken::Integer:
+ case AsmToken::Real:
+ case AsmToken::Hash: {
+ // #42 -> immediate.
+ S = getLoc();
+
+ parseOptionalToken(AsmToken::Hash);
+
+ // Parse a negative sign
+ bool isNegative = false;
+ if (Parser.getTok().is(AsmToken::Minus)) {
+ isNegative = true;
+ // We need to consume this token only when we have a Real, otherwise
+ // we let parseSymbolicImmVal take care of it
+ if (Parser.getLexer().peekTok().is(AsmToken::Real))
+ Parser.Lex();
+ }
+
+ // The only Real that should come through here is a literal #0.0 for
+ // the fcmp[e] r, #0.0 instructions. They expect raw token operands,
+ // so convert the value.
+ const AsmToken &Tok = Parser.getTok();
+ if (Tok.is(AsmToken::Real)) {
+ APFloat RealVal(APFloat::IEEEdouble(), Tok.getString());
+ uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
+ if (Mnemonic != "fcmp" && Mnemonic != "fcmpe" && Mnemonic != "fcmeq" &&
+ Mnemonic != "fcmge" && Mnemonic != "fcmgt" && Mnemonic != "fcmle" &&
+ Mnemonic != "fcmlt" && Mnemonic != "fcmne")
+ return TokError("unexpected floating point literal");
+ else if (IntVal != 0 || isNegative)
+ return TokError("expected floating-point constant #0.0");
+ Parser.Lex(); // Eat the token.
+
+ Operands.push_back(
+ AArch64Operand::CreateToken("#0", false, S, getContext()));
+ Operands.push_back(
+ AArch64Operand::CreateToken(".0", false, S, getContext()));
+ return false;
+ }
+
+ const MCExpr *ImmVal;
+ if (parseSymbolicImmVal(ImmVal))
+ return true;
+
+ E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
+ Operands.push_back(AArch64Operand::CreateImm(ImmVal, S, E, getContext()));
+ return false;
+ }
+ case AsmToken::Equal: {
+ SMLoc Loc = getLoc();
+ if (Mnemonic != "ldr") // only parse for ldr pseudo (e.g. ldr r0, =val)
+ return TokError("unexpected token in operand");
+ Parser.Lex(); // Eat '='
+ const MCExpr *SubExprVal;
+ if (getParser().parseExpression(SubExprVal))
+ return true;
+
+ if (Operands.size() < 2 ||
+ !static_cast<AArch64Operand &>(*Operands[1]).isScalarReg())
+ return Error(Loc, "Only valid when first operand is register");
+
+ bool IsXReg =
+ AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
+ Operands[1]->getReg());
+
+ MCContext& Ctx = getContext();
+ E = SMLoc::getFromPointer(Loc.getPointer() - 1);
+ // If the op is an imm and can be fit into a mov, then replace ldr with mov.
+ if (isa<MCConstantExpr>(SubExprVal)) {
+ uint64_t Imm = (cast<MCConstantExpr>(SubExprVal))->getValue();
+ uint32_t ShiftAmt = 0, MaxShiftAmt = IsXReg ? 48 : 16;
+ while(Imm > 0xFFFF && countTrailingZeros(Imm) >= 16) {
+ ShiftAmt += 16;
+ Imm >>= 16;
+ }
+ if (ShiftAmt <= MaxShiftAmt && Imm <= 0xFFFF) {
+ Operands[0] = AArch64Operand::CreateToken("movz", false, Loc, Ctx);
+ Operands.push_back(AArch64Operand::CreateImm(
+ MCConstantExpr::create(Imm, Ctx), S, E, Ctx));
+ if (ShiftAmt)
+ Operands.push_back(AArch64Operand::CreateShiftExtend(AArch64_AM::LSL,
+ ShiftAmt, true, S, E, Ctx));
+ return false;
+ }
+ APInt Simm = APInt(64, Imm << ShiftAmt);
+ // check if the immediate is an unsigned or signed 32-bit int for W regs
+ if (!IsXReg && !(Simm.isIntN(32) || Simm.isSignedIntN(32)))
+ return Error(Loc, "Immediate too large for register");
+ }
+ // If it is a label or an imm that cannot fit in a movz, put it into CP.
+ const MCExpr *CPLoc =
+ getTargetStreamer().addConstantPoolEntry(SubExprVal, IsXReg ? 8 : 4, Loc);
+ Operands.push_back(AArch64Operand::CreateImm(CPLoc, S, E, Ctx));
+ return false;
+ }
+ }
+}
+
bool AArch64AsmParser::parseImmExpr(int64_t &Out) {
const MCExpr *Expr = nullptr;
SMLoc L = getLoc();
@@ -3955,1353 +3955,1353 @@ bool AArch64AsmParser::parseRegisterInRange(unsigned &Out, unsigned Base,
return false;
}
-bool AArch64AsmParser::regsEqual(const MCParsedAsmOperand &Op1,
- const MCParsedAsmOperand &Op2) const {
- auto &AOp1 = static_cast<const AArch64Operand&>(Op1);
- auto &AOp2 = static_cast<const AArch64Operand&>(Op2);
- if (AOp1.getRegEqualityTy() == RegConstraintEqualityTy::EqualsReg &&
- AOp2.getRegEqualityTy() == RegConstraintEqualityTy::EqualsReg)
- return MCTargetAsmParser::regsEqual(Op1, Op2);
-
- assert(AOp1.isScalarReg() && AOp2.isScalarReg() &&
- "Testing equality of non-scalar registers not supported");
-
- // Check if a registers match their sub/super register classes.
- if (AOp1.getRegEqualityTy() == EqualsSuperReg)
- return getXRegFromWReg(Op1.getReg()) == Op2.getReg();
- if (AOp1.getRegEqualityTy() == EqualsSubReg)
- return getWRegFromXReg(Op1.getReg()) == Op2.getReg();
- if (AOp2.getRegEqualityTy() == EqualsSuperReg)
- return getXRegFromWReg(Op2.getReg()) == Op1.getReg();
- if (AOp2.getRegEqualityTy() == EqualsSubReg)
- return getWRegFromXReg(Op2.getReg()) == Op1.getReg();
-
- return false;
-}
-
-/// ParseInstruction - Parse an AArch64 instruction mnemonic followed by its
-/// operands.
-bool AArch64AsmParser::ParseInstruction(ParseInstructionInfo &Info,
- StringRef Name, SMLoc NameLoc,
- OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- Name = StringSwitch<StringRef>(Name.lower())
- .Case("beq", "b.eq")
- .Case("bne", "b.ne")
- .Case("bhs", "b.hs")
- .Case("bcs", "b.cs")
- .Case("blo", "b.lo")
- .Case("bcc", "b.cc")
- .Case("bmi", "b.mi")
- .Case("bpl", "b.pl")
- .Case("bvs", "b.vs")
- .Case("bvc", "b.vc")
- .Case("bhi", "b.hi")
- .Case("bls", "b.ls")
- .Case("bge", "b.ge")
- .Case("blt", "b.lt")
- .Case("bgt", "b.gt")
- .Case("ble", "b.le")
- .Case("bal", "b.al")
- .Case("bnv", "b.nv")
- .Default(Name);
-
- // First check for the AArch64-specific .req directive.
- if (Parser.getTok().is(AsmToken::Identifier) &&
- Parser.getTok().getIdentifier().lower() == ".req") {
- parseDirectiveReq(Name, NameLoc);
- // We always return 'error' for this, as we're done with this
- // statement and don't need to match the 'instruction."
- return true;
- }
-
- // Create the leading tokens for the mnemonic, split by '.' characters.
- size_t Start = 0, Next = Name.find('.');
- StringRef Head = Name.slice(Start, Next);
-
- // IC, DC, AT, TLBI and Prediction invalidation instructions are aliases for
- // the SYS instruction.
- if (Head == "ic" || Head == "dc" || Head == "at" || Head == "tlbi" ||
- Head == "cfp" || Head == "dvp" || Head == "cpp")
- return parseSysAlias(Head, NameLoc, Operands);
-
- Operands.push_back(
- AArch64Operand::CreateToken(Head, false, NameLoc, getContext()));
- Mnemonic = Head;
-
- // Handle condition codes for a branch mnemonic
- if (Head == "b" && Next != StringRef::npos) {
- Start = Next;
- Next = Name.find('.', Start + 1);
- Head = Name.slice(Start + 1, Next);
-
- SMLoc SuffixLoc = SMLoc::getFromPointer(NameLoc.getPointer() +
- (Head.data() - Name.data()));
- AArch64CC::CondCode CC = parseCondCodeString(Head);
- if (CC == AArch64CC::Invalid)
- return Error(SuffixLoc, "invalid condition code");
- Operands.push_back(
- AArch64Operand::CreateToken(".", true, SuffixLoc, getContext()));
- Operands.push_back(
- AArch64Operand::CreateCondCode(CC, NameLoc, NameLoc, getContext()));
- }
-
- // Add the remaining tokens in the mnemonic.
- while (Next != StringRef::npos) {
- Start = Next;
- Next = Name.find('.', Start + 1);
- Head = Name.slice(Start, Next);
- SMLoc SuffixLoc = SMLoc::getFromPointer(NameLoc.getPointer() +
- (Head.data() - Name.data()) + 1);
- Operands.push_back(
- AArch64Operand::CreateToken(Head, true, SuffixLoc, getContext()));
- }
-
- // Conditional compare instructions have a Condition Code operand, which needs
- // to be parsed and an immediate operand created.
- bool condCodeFourthOperand =
- (Head == "ccmp" || Head == "ccmn" || Head == "fccmp" ||
- Head == "fccmpe" || Head == "fcsel" || Head == "csel" ||
- Head == "csinc" || Head == "csinv" || Head == "csneg");
-
- // These instructions are aliases to some of the conditional select
- // instructions. However, the condition code is inverted in the aliased
- // instruction.
- //
- // FIXME: Is this the correct way to handle these? Or should the parser
- // generate the aliased instructions directly?
- bool condCodeSecondOperand = (Head == "cset" || Head == "csetm");
- bool condCodeThirdOperand =
- (Head == "cinc" || Head == "cinv" || Head == "cneg");
-
- // Read the remaining operands.
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
-
- unsigned N = 1;
- do {
- // Parse and remember the operand.
- if (parseOperand(Operands, (N == 4 && condCodeFourthOperand) ||
- (N == 3 && condCodeThirdOperand) ||
- (N == 2 && condCodeSecondOperand),
- condCodeSecondOperand || condCodeThirdOperand)) {
- return true;
- }
-
- // After successfully parsing some operands there are two special cases to
- // consider (i.e. notional operands not separated by commas). Both are due
- // to memory specifiers:
- // + An RBrac will end an address for load/store/prefetch
- // + An '!' will indicate a pre-indexed operation.
- //
- // It's someone else's responsibility to make sure these tokens are sane
- // in the given context!
-
- SMLoc RLoc = Parser.getTok().getLoc();
- if (parseOptionalToken(AsmToken::RBrac))
- Operands.push_back(
- AArch64Operand::CreateToken("]", false, RLoc, getContext()));
- SMLoc ELoc = Parser.getTok().getLoc();
- if (parseOptionalToken(AsmToken::Exclaim))
- Operands.push_back(
- AArch64Operand::CreateToken("!", false, ELoc, getContext()));
-
- ++N;
- } while (parseOptionalToken(AsmToken::Comma));
- }
-
- if (parseToken(AsmToken::EndOfStatement, "unexpected token in argument list"))
- return true;
-
- return false;
-}
-
-static inline bool isMatchingOrAlias(unsigned ZReg, unsigned Reg) {
- assert((ZReg >= AArch64::Z0) && (ZReg <= AArch64::Z31));
- return (ZReg == ((Reg - AArch64::B0) + AArch64::Z0)) ||
- (ZReg == ((Reg - AArch64::H0) + AArch64::Z0)) ||
- (ZReg == ((Reg - AArch64::S0) + AArch64::Z0)) ||
- (ZReg == ((Reg - AArch64::D0) + AArch64::Z0)) ||
- (ZReg == ((Reg - AArch64::Q0) + AArch64::Z0)) ||
- (ZReg == ((Reg - AArch64::Z0) + AArch64::Z0));
-}
-
-// FIXME: This entire function is a giant hack to provide us with decent
-// operand range validation/diagnostics until TableGen/MC can be extended
-// to support autogeneration of this kind of validation.
-bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc,
- SmallVectorImpl<SMLoc> &Loc) {
- const MCRegisterInfo *RI = getContext().getRegisterInfo();
- const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
-
- // A prefix only applies to the instruction following it. Here we extract
- // prefix information for the next instruction before validating the current
- // one so that in the case of failure we don't erronously continue using the
- // current prefix.
- PrefixInfo Prefix = NextPrefix;
- NextPrefix = PrefixInfo::CreateFromInst(Inst, MCID.TSFlags);
-
- // Before validating the instruction in isolation we run through the rules
- // applicable when it follows a prefix instruction.
- // NOTE: brk & hlt can be prefixed but require no additional validation.
- if (Prefix.isActive() &&
- (Inst.getOpcode() != AArch64::BRK) &&
- (Inst.getOpcode() != AArch64::HLT)) {
-
- // Prefixed intructions must have a destructive operand.
- if ((MCID.TSFlags & AArch64::DestructiveInstTypeMask) ==
- AArch64::NotDestructive)
- return Error(IDLoc, "instruction is unpredictable when following a"
- " movprfx, suggest replacing movprfx with mov");
-
- // Destination operands must match.
- if (Inst.getOperand(0).getReg() != Prefix.getDstReg())
- return Error(Loc[0], "instruction is unpredictable when following a"
- " movprfx writing to a different destination");
-
- // Destination operand must not be used in any other location.
- for (unsigned i = 1; i < Inst.getNumOperands(); ++i) {
- if (Inst.getOperand(i).isReg() &&
- (MCID.getOperandConstraint(i, MCOI::TIED_TO) == -1) &&
- isMatchingOrAlias(Prefix.getDstReg(), Inst.getOperand(i).getReg()))
- return Error(Loc[0], "instruction is unpredictable when following a"
- " movprfx and destination also used as non-destructive"
- " source");
- }
-
- auto PPRRegClass = AArch64MCRegisterClasses[AArch64::PPRRegClassID];
- if (Prefix.isPredicated()) {
- int PgIdx = -1;
-
- // Find the instructions general predicate.
- for (unsigned i = 1; i < Inst.getNumOperands(); ++i)
- if (Inst.getOperand(i).isReg() &&
- PPRRegClass.contains(Inst.getOperand(i).getReg())) {
- PgIdx = i;
- break;
- }
-
- // Instruction must be predicated if the movprfx is predicated.
- if (PgIdx == -1 ||
- (MCID.TSFlags & AArch64::ElementSizeMask) == AArch64::ElementSizeNone)
- return Error(IDLoc, "instruction is unpredictable when following a"
- " predicated movprfx, suggest using unpredicated movprfx");
-
- // Instruction must use same general predicate as the movprfx.
- if (Inst.getOperand(PgIdx).getReg() != Prefix.getPgReg())
- return Error(IDLoc, "instruction is unpredictable when following a"
- " predicated movprfx using a different general predicate");
-
- // Instruction element type must match the movprfx.
- if ((MCID.TSFlags & AArch64::ElementSizeMask) != Prefix.getElementSize())
- return Error(IDLoc, "instruction is unpredictable when following a"
- " predicated movprfx with a different element size");
- }
- }
-
- // Check for indexed addressing modes w/ the base register being the
- // same as a destination/source register or pair load where
- // the Rt == Rt2. All of those are undefined behaviour.
- switch (Inst.getOpcode()) {
- case AArch64::LDPSWpre:
- case AArch64::LDPWpost:
- case AArch64::LDPWpre:
- case AArch64::LDPXpost:
- case AArch64::LDPXpre: {
- unsigned Rt = Inst.getOperand(1).getReg();
- unsigned Rt2 = Inst.getOperand(2).getReg();
- unsigned Rn = Inst.getOperand(3).getReg();
- if (RI->isSubRegisterEq(Rn, Rt))
- return Error(Loc[0], "unpredictable LDP instruction, writeback base "
- "is also a destination");
- if (RI->isSubRegisterEq(Rn, Rt2))
- return Error(Loc[1], "unpredictable LDP instruction, writeback base "
- "is also a destination");
- LLVM_FALLTHROUGH;
- }
- case AArch64::LDPDi:
- case AArch64::LDPQi:
- case AArch64::LDPSi:
- case AArch64::LDPSWi:
- case AArch64::LDPWi:
- case AArch64::LDPXi: {
- unsigned Rt = Inst.getOperand(0).getReg();
- unsigned Rt2 = Inst.getOperand(1).getReg();
- if (Rt == Rt2)
- return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt");
- break;
- }
- case AArch64::LDPDpost:
- case AArch64::LDPDpre:
- case AArch64::LDPQpost:
- case AArch64::LDPQpre:
- case AArch64::LDPSpost:
- case AArch64::LDPSpre:
- case AArch64::LDPSWpost: {
- unsigned Rt = Inst.getOperand(1).getReg();
- unsigned Rt2 = Inst.getOperand(2).getReg();
- if (Rt == Rt2)
- return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt");
- break;
- }
- case AArch64::STPDpost:
- case AArch64::STPDpre:
- case AArch64::STPQpost:
- case AArch64::STPQpre:
- case AArch64::STPSpost:
- case AArch64::STPSpre:
- case AArch64::STPWpost:
- case AArch64::STPWpre:
- case AArch64::STPXpost:
- case AArch64::STPXpre: {
- unsigned Rt = Inst.getOperand(1).getReg();
- unsigned Rt2 = Inst.getOperand(2).getReg();
- unsigned Rn = Inst.getOperand(3).getReg();
- if (RI->isSubRegisterEq(Rn, Rt))
- return Error(Loc[0], "unpredictable STP instruction, writeback base "
- "is also a source");
- if (RI->isSubRegisterEq(Rn, Rt2))
- return Error(Loc[1], "unpredictable STP instruction, writeback base "
- "is also a source");
- break;
- }
- case AArch64::LDRBBpre:
- case AArch64::LDRBpre:
- case AArch64::LDRHHpre:
- case AArch64::LDRHpre:
- case AArch64::LDRSBWpre:
- case AArch64::LDRSBXpre:
- case AArch64::LDRSHWpre:
- case AArch64::LDRSHXpre:
- case AArch64::LDRSWpre:
- case AArch64::LDRWpre:
- case AArch64::LDRXpre:
- case AArch64::LDRBBpost:
- case AArch64::LDRBpost:
- case AArch64::LDRHHpost:
- case AArch64::LDRHpost:
- case AArch64::LDRSBWpost:
- case AArch64::LDRSBXpost:
- case AArch64::LDRSHWpost:
- case AArch64::LDRSHXpost:
- case AArch64::LDRSWpost:
- case AArch64::LDRWpost:
- case AArch64::LDRXpost: {
- unsigned Rt = Inst.getOperand(1).getReg();
- unsigned Rn = Inst.getOperand(2).getReg();
- if (RI->isSubRegisterEq(Rn, Rt))
- return Error(Loc[0], "unpredictable LDR instruction, writeback base "
- "is also a source");
- break;
- }
- case AArch64::STRBBpost:
- case AArch64::STRBpost:
- case AArch64::STRHHpost:
- case AArch64::STRHpost:
- case AArch64::STRWpost:
- case AArch64::STRXpost:
- case AArch64::STRBBpre:
- case AArch64::STRBpre:
- case AArch64::STRHHpre:
- case AArch64::STRHpre:
- case AArch64::STRWpre:
- case AArch64::STRXpre: {
- unsigned Rt = Inst.getOperand(1).getReg();
- unsigned Rn = Inst.getOperand(2).getReg();
- if (RI->isSubRegisterEq(Rn, Rt))
- return Error(Loc[0], "unpredictable STR instruction, writeback base "
- "is also a source");
- break;
- }
- case AArch64::STXRB:
- case AArch64::STXRH:
- case AArch64::STXRW:
- case AArch64::STXRX:
- case AArch64::STLXRB:
- case AArch64::STLXRH:
- case AArch64::STLXRW:
- case AArch64::STLXRX: {
- unsigned Rs = Inst.getOperand(0).getReg();
- unsigned Rt = Inst.getOperand(1).getReg();
- unsigned Rn = Inst.getOperand(2).getReg();
- if (RI->isSubRegisterEq(Rt, Rs) ||
- (RI->isSubRegisterEq(Rn, Rs) && Rn != AArch64::SP))
- return Error(Loc[0],
- "unpredictable STXR instruction, status is also a source");
- break;
- }
- case AArch64::STXPW:
- case AArch64::STXPX:
- case AArch64::STLXPW:
- case AArch64::STLXPX: {
- unsigned Rs = Inst.getOperand(0).getReg();
- unsigned Rt1 = Inst.getOperand(1).getReg();
- unsigned Rt2 = Inst.getOperand(2).getReg();
- unsigned Rn = Inst.getOperand(3).getReg();
- if (RI->isSubRegisterEq(Rt1, Rs) || RI->isSubRegisterEq(Rt2, Rs) ||
- (RI->isSubRegisterEq(Rn, Rs) && Rn != AArch64::SP))
- return Error(Loc[0],
- "unpredictable STXP instruction, status is also a source");
- break;
- }
- case AArch64::LDRABwriteback:
- case AArch64::LDRAAwriteback: {
- unsigned Xt = Inst.getOperand(0).getReg();
- unsigned Xn = Inst.getOperand(1).getReg();
- if (Xt == Xn)
- return Error(Loc[0],
- "unpredictable LDRA instruction, writeback base"
- " is also a destination");
- break;
- }
- }
-
-
- // Now check immediate ranges. Separate from the above as there is overlap
- // in the instructions being checked and this keeps the nested conditionals
- // to a minimum.
- switch (Inst.getOpcode()) {
- case AArch64::ADDSWri:
- case AArch64::ADDSXri:
- case AArch64::ADDWri:
- case AArch64::ADDXri:
- case AArch64::SUBSWri:
- case AArch64::SUBSXri:
- case AArch64::SUBWri:
- case AArch64::SUBXri: {
- // Annoyingly we can't do this in the isAddSubImm predicate, so there is
- // some slight duplication here.
- if (Inst.getOperand(2).isExpr()) {
- const MCExpr *Expr = Inst.getOperand(2).getExpr();
- AArch64MCExpr::VariantKind ELFRefKind;
- MCSymbolRefExpr::VariantKind DarwinRefKind;
- int64_t Addend;
- if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
-
- // Only allow these with ADDXri.
- if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF ||
- DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) &&
- Inst.getOpcode() == AArch64::ADDXri)
- return false;
-
- // Only allow these with ADDXri/ADDWri
- if ((ELFRefKind == AArch64MCExpr::VK_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 ||
- ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC ||
- ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 ||
- ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC ||
- ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_SECREL_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_SECREL_HI12) &&
- (Inst.getOpcode() == AArch64::ADDXri ||
- Inst.getOpcode() == AArch64::ADDWri))
- return false;
-
- // Don't allow symbol refs in the immediate field otherwise
- // Note: Loc.back() may be Loc[1] or Loc[2] depending on the number of
- // operands of the original instruction (i.e. 'add w0, w1, borked' vs
- // 'cmp w0, 'borked')
- return Error(Loc.back(), "invalid immediate expression");
- }
- // We don't validate more complex expressions here
- }
- return false;
- }
- default:
- return false;
- }
-}
-
-static std::string AArch64MnemonicSpellCheck(StringRef S,
- const FeatureBitset &FBS,
- unsigned VariantID = 0);
-
-bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
- uint64_t ErrorInfo,
- OperandVector &Operands) {
- switch (ErrCode) {
- case Match_InvalidTiedOperand: {
- RegConstraintEqualityTy EqTy =
- static_cast<const AArch64Operand &>(*Operands[ErrorInfo])
- .getRegEqualityTy();
- switch (EqTy) {
- case RegConstraintEqualityTy::EqualsSubReg:
- return Error(Loc, "operand must be 64-bit form of destination register");
- case RegConstraintEqualityTy::EqualsSuperReg:
- return Error(Loc, "operand must be 32-bit form of destination register");
- case RegConstraintEqualityTy::EqualsReg:
- return Error(Loc, "operand must match destination register");
- }
- llvm_unreachable("Unknown RegConstraintEqualityTy");
- }
- case Match_MissingFeature:
- return Error(Loc,
- "instruction requires a CPU feature not currently enabled");
- case Match_InvalidOperand:
- return Error(Loc, "invalid operand for instruction");
- case Match_InvalidSuffix:
- return Error(Loc, "invalid type suffix for instruction");
- case Match_InvalidCondCode:
- return Error(Loc, "expected AArch64 condition code");
- case Match_AddSubRegExtendSmall:
- return Error(Loc,
- "expected '[su]xt[bhw]' with optional integer in range [0, 4]");
- case Match_AddSubRegExtendLarge:
- return Error(Loc,
- "expected 'sxtx' 'uxtx' or 'lsl' with optional integer in range [0, 4]");
- case Match_AddSubSecondSource:
- return Error(Loc,
- "expected compatible register, symbol or integer in range [0, 4095]");
- case Match_LogicalSecondSource:
- return Error(Loc, "expected compatible register or logical immediate");
- case Match_InvalidMovImm32Shift:
- return Error(Loc, "expected 'lsl' with optional integer 0 or 16");
- case Match_InvalidMovImm64Shift:
- return Error(Loc, "expected 'lsl' with optional integer 0, 16, 32 or 48");
- case Match_AddSubRegShift32:
- return Error(Loc,
- "expected 'lsl', 'lsr' or 'asr' with optional integer in range [0, 31]");
- case Match_AddSubRegShift64:
- return Error(Loc,
- "expected 'lsl', 'lsr' or 'asr' with optional integer in range [0, 63]");
- case Match_InvalidFPImm:
- return Error(Loc,
- "expected compatible register or floating-point constant");
- case Match_InvalidMemoryIndexedSImm6:
- return Error(Loc, "index must be an integer in range [-32, 31].");
- case Match_InvalidMemoryIndexedSImm5:
- return Error(Loc, "index must be an integer in range [-16, 15].");
- case Match_InvalidMemoryIndexed1SImm4:
- return Error(Loc, "index must be an integer in range [-8, 7].");
- case Match_InvalidMemoryIndexed2SImm4:
- return Error(Loc, "index must be a multiple of 2 in range [-16, 14].");
- case Match_InvalidMemoryIndexed3SImm4:
- return Error(Loc, "index must be a multiple of 3 in range [-24, 21].");
- case Match_InvalidMemoryIndexed4SImm4:
- return Error(Loc, "index must be a multiple of 4 in range [-32, 28].");
- case Match_InvalidMemoryIndexed16SImm4:
- return Error(Loc, "index must be a multiple of 16 in range [-128, 112].");
- case Match_InvalidMemoryIndexed32SImm4:
- return Error(Loc, "index must be a multiple of 32 in range [-256, 224].");
- case Match_InvalidMemoryIndexed1SImm6:
- return Error(Loc, "index must be an integer in range [-32, 31].");
- case Match_InvalidMemoryIndexedSImm8:
- return Error(Loc, "index must be an integer in range [-128, 127].");
- case Match_InvalidMemoryIndexedSImm9:
- return Error(Loc, "index must be an integer in range [-256, 255].");
- case Match_InvalidMemoryIndexed16SImm9:
- return Error(Loc, "index must be a multiple of 16 in range [-4096, 4080].");
- case Match_InvalidMemoryIndexed8SImm10:
- return Error(Loc, "index must be a multiple of 8 in range [-4096, 4088].");
- case Match_InvalidMemoryIndexed4SImm7:
- return Error(Loc, "index must be a multiple of 4 in range [-256, 252].");
- case Match_InvalidMemoryIndexed8SImm7:
- return Error(Loc, "index must be a multiple of 8 in range [-512, 504].");
- case Match_InvalidMemoryIndexed16SImm7:
- return Error(Loc, "index must be a multiple of 16 in range [-1024, 1008].");
- case Match_InvalidMemoryIndexed8UImm5:
- return Error(Loc, "index must be a multiple of 8 in range [0, 248].");
- case Match_InvalidMemoryIndexed4UImm5:
- return Error(Loc, "index must be a multiple of 4 in range [0, 124].");
- case Match_InvalidMemoryIndexed2UImm5:
- return Error(Loc, "index must be a multiple of 2 in range [0, 62].");
- case Match_InvalidMemoryIndexed8UImm6:
- return Error(Loc, "index must be a multiple of 8 in range [0, 504].");
- case Match_InvalidMemoryIndexed16UImm6:
- return Error(Loc, "index must be a multiple of 16 in range [0, 1008].");
- case Match_InvalidMemoryIndexed4UImm6:
- return Error(Loc, "index must be a multiple of 4 in range [0, 252].");
- case Match_InvalidMemoryIndexed2UImm6:
- return Error(Loc, "index must be a multiple of 2 in range [0, 126].");
- case Match_InvalidMemoryIndexed1UImm6:
- return Error(Loc, "index must be in range [0, 63].");
- case Match_InvalidMemoryWExtend8:
- return Error(Loc,
- "expected 'uxtw' or 'sxtw' with optional shift of #0");
- case Match_InvalidMemoryWExtend16:
- return Error(Loc,
- "expected 'uxtw' or 'sxtw' with optional shift of #0 or #1");
- case Match_InvalidMemoryWExtend32:
- return Error(Loc,
- "expected 'uxtw' or 'sxtw' with optional shift of #0 or #2");
- case Match_InvalidMemoryWExtend64:
- return Error(Loc,
- "expected 'uxtw' or 'sxtw' with optional shift of #0 or #3");
- case Match_InvalidMemoryWExtend128:
- return Error(Loc,
- "expected 'uxtw' or 'sxtw' with optional shift of #0 or #4");
- case Match_InvalidMemoryXExtend8:
- return Error(Loc,
- "expected 'lsl' or 'sxtx' with optional shift of #0");
- case Match_InvalidMemoryXExtend16:
- return Error(Loc,
- "expected 'lsl' or 'sxtx' with optional shift of #0 or #1");
- case Match_InvalidMemoryXExtend32:
- return Error(Loc,
- "expected 'lsl' or 'sxtx' with optional shift of #0 or #2");
- case Match_InvalidMemoryXExtend64:
- return Error(Loc,
- "expected 'lsl' or 'sxtx' with optional shift of #0 or #3");
- case Match_InvalidMemoryXExtend128:
- return Error(Loc,
- "expected 'lsl' or 'sxtx' with optional shift of #0 or #4");
- case Match_InvalidMemoryIndexed1:
- return Error(Loc, "index must be an integer in range [0, 4095].");
- case Match_InvalidMemoryIndexed2:
- return Error(Loc, "index must be a multiple of 2 in range [0, 8190].");
- case Match_InvalidMemoryIndexed4:
- return Error(Loc, "index must be a multiple of 4 in range [0, 16380].");
- case Match_InvalidMemoryIndexed8:
- return Error(Loc, "index must be a multiple of 8 in range [0, 32760].");
- case Match_InvalidMemoryIndexed16:
- return Error(Loc, "index must be a multiple of 16 in range [0, 65520].");
- case Match_InvalidImm0_1:
- return Error(Loc, "immediate must be an integer in range [0, 1].");
- case Match_InvalidImm0_7:
- return Error(Loc, "immediate must be an integer in range [0, 7].");
- case Match_InvalidImm0_15:
- return Error(Loc, "immediate must be an integer in range [0, 15].");
- case Match_InvalidImm0_31:
- return Error(Loc, "immediate must be an integer in range [0, 31].");
- case Match_InvalidImm0_63:
- return Error(Loc, "immediate must be an integer in range [0, 63].");
- case Match_InvalidImm0_127:
- return Error(Loc, "immediate must be an integer in range [0, 127].");
- case Match_InvalidImm0_255:
- return Error(Loc, "immediate must be an integer in range [0, 255].");
- case Match_InvalidImm0_65535:
- return Error(Loc, "immediate must be an integer in range [0, 65535].");
- case Match_InvalidImm1_8:
- return Error(Loc, "immediate must be an integer in range [1, 8].");
- case Match_InvalidImm1_16:
- return Error(Loc, "immediate must be an integer in range [1, 16].");
- case Match_InvalidImm1_32:
- return Error(Loc, "immediate must be an integer in range [1, 32].");
- case Match_InvalidImm1_64:
- return Error(Loc, "immediate must be an integer in range [1, 64].");
- case Match_InvalidSVEAddSubImm8:
- return Error(Loc, "immediate must be an integer in range [0, 255]"
- " with a shift amount of 0");
- case Match_InvalidSVEAddSubImm16:
- case Match_InvalidSVEAddSubImm32:
- case Match_InvalidSVEAddSubImm64:
- return Error(Loc, "immediate must be an integer in range [0, 255] or a "
- "multiple of 256 in range [256, 65280]");
- case Match_InvalidSVECpyImm8:
- return Error(Loc, "immediate must be an integer in range [-128, 255]"
- " with a shift amount of 0");
- case Match_InvalidSVECpyImm16:
- return Error(Loc, "immediate must be an integer in range [-128, 127] or a "
- "multiple of 256 in range [-32768, 65280]");
- case Match_InvalidSVECpyImm32:
- case Match_InvalidSVECpyImm64:
- return Error(Loc, "immediate must be an integer in range [-128, 127] or a "
- "multiple of 256 in range [-32768, 32512]");
- case Match_InvalidIndexRange1_1:
- return Error(Loc, "expected lane specifier '[1]'");
- case Match_InvalidIndexRange0_15:
- return Error(Loc, "vector lane must be an integer in range [0, 15].");
- case Match_InvalidIndexRange0_7:
- return Error(Loc, "vector lane must be an integer in range [0, 7].");
- case Match_InvalidIndexRange0_3:
- return Error(Loc, "vector lane must be an integer in range [0, 3].");
- case Match_InvalidIndexRange0_1:
- return Error(Loc, "vector lane must be an integer in range [0, 1].");
- case Match_InvalidSVEIndexRange0_63:
- return Error(Loc, "vector lane must be an integer in range [0, 63].");
- case Match_InvalidSVEIndexRange0_31:
- return Error(Loc, "vector lane must be an integer in range [0, 31].");
- case Match_InvalidSVEIndexRange0_15:
- return Error(Loc, "vector lane must be an integer in range [0, 15].");
- case Match_InvalidSVEIndexRange0_7:
- return Error(Loc, "vector lane must be an integer in range [0, 7].");
- case Match_InvalidSVEIndexRange0_3:
- return Error(Loc, "vector lane must be an integer in range [0, 3].");
- case Match_InvalidLabel:
- return Error(Loc, "expected label or encodable integer pc offset");
- case Match_MRS:
- return Error(Loc, "expected readable system register");
- case Match_MSR:
- return Error(Loc, "expected writable system register or pstate");
- case Match_InvalidComplexRotationEven:
- return Error(Loc, "complex rotation must be 0, 90, 180 or 270.");
- case Match_InvalidComplexRotationOdd:
- return Error(Loc, "complex rotation must be 90 or 270.");
- case Match_MnemonicFail: {
- std::string Suggestion = AArch64MnemonicSpellCheck(
- ((AArch64Operand &)*Operands[0]).getToken(),
- ComputeAvailableFeatures(STI->getFeatureBits()));
- return Error(Loc, "unrecognized instruction mnemonic" + Suggestion);
- }
- case Match_InvalidGPR64shifted8:
- return Error(Loc, "register must be x0..x30 or xzr, without shift");
- case Match_InvalidGPR64shifted16:
- return Error(Loc, "register must be x0..x30 or xzr, with required shift 'lsl #1'");
- case Match_InvalidGPR64shifted32:
- return Error(Loc, "register must be x0..x30 or xzr, with required shift 'lsl #2'");
- case Match_InvalidGPR64shifted64:
- return Error(Loc, "register must be x0..x30 or xzr, with required shift 'lsl #3'");
- case Match_InvalidGPR64NoXZRshifted8:
- return Error(Loc, "register must be x0..x30 without shift");
- case Match_InvalidGPR64NoXZRshifted16:
- return Error(Loc, "register must be x0..x30 with required shift 'lsl #1'");
- case Match_InvalidGPR64NoXZRshifted32:
- return Error(Loc, "register must be x0..x30 with required shift 'lsl #2'");
- case Match_InvalidGPR64NoXZRshifted64:
- return Error(Loc, "register must be x0..x30 with required shift 'lsl #3'");
- case Match_InvalidZPR32UXTW8:
- case Match_InvalidZPR32SXTW8:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, (uxtw|sxtw)'");
- case Match_InvalidZPR32UXTW16:
- case Match_InvalidZPR32SXTW16:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, (uxtw|sxtw) #1'");
- case Match_InvalidZPR32UXTW32:
- case Match_InvalidZPR32SXTW32:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, (uxtw|sxtw) #2'");
- case Match_InvalidZPR32UXTW64:
- case Match_InvalidZPR32SXTW64:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, (uxtw|sxtw) #3'");
- case Match_InvalidZPR64UXTW8:
- case Match_InvalidZPR64SXTW8:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, (uxtw|sxtw)'");
- case Match_InvalidZPR64UXTW16:
- case Match_InvalidZPR64SXTW16:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, (lsl|uxtw|sxtw) #1'");
- case Match_InvalidZPR64UXTW32:
- case Match_InvalidZPR64SXTW32:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, (lsl|uxtw|sxtw) #2'");
- case Match_InvalidZPR64UXTW64:
- case Match_InvalidZPR64SXTW64:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, (lsl|uxtw|sxtw) #3'");
- case Match_InvalidZPR32LSL8:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s'");
- case Match_InvalidZPR32LSL16:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, lsl #1'");
- case Match_InvalidZPR32LSL32:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, lsl #2'");
- case Match_InvalidZPR32LSL64:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, lsl #3'");
- case Match_InvalidZPR64LSL8:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d'");
- case Match_InvalidZPR64LSL16:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, lsl #1'");
- case Match_InvalidZPR64LSL32:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, lsl #2'");
- case Match_InvalidZPR64LSL64:
- return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, lsl #3'");
- case Match_InvalidZPR0:
- return Error(Loc, "expected register without element width suffix");
- case Match_InvalidZPR8:
- case Match_InvalidZPR16:
- case Match_InvalidZPR32:
- case Match_InvalidZPR64:
- case Match_InvalidZPR128:
- return Error(Loc, "invalid element width");
- case Match_InvalidZPR_3b8:
- return Error(Loc, "Invalid restricted vector register, expected z0.b..z7.b");
- case Match_InvalidZPR_3b16:
- return Error(Loc, "Invalid restricted vector register, expected z0.h..z7.h");
- case Match_InvalidZPR_3b32:
- return Error(Loc, "Invalid restricted vector register, expected z0.s..z7.s");
- case Match_InvalidZPR_4b16:
- return Error(Loc, "Invalid restricted vector register, expected z0.h..z15.h");
- case Match_InvalidZPR_4b32:
- return Error(Loc, "Invalid restricted vector register, expected z0.s..z15.s");
- case Match_InvalidZPR_4b64:
- return Error(Loc, "Invalid restricted vector register, expected z0.d..z15.d");
- case Match_InvalidSVEPattern:
- return Error(Loc, "invalid predicate pattern");
- case Match_InvalidSVEPredicateAnyReg:
- case Match_InvalidSVEPredicateBReg:
- case Match_InvalidSVEPredicateHReg:
- case Match_InvalidSVEPredicateSReg:
- case Match_InvalidSVEPredicateDReg:
- return Error(Loc, "invalid predicate register.");
- case Match_InvalidSVEPredicate3bAnyReg:
- return Error(Loc, "invalid restricted predicate register, expected p0..p7 (without element suffix)");
- case Match_InvalidSVEPredicate3bBReg:
- return Error(Loc, "invalid restricted predicate register, expected p0.b..p7.b");
- case Match_InvalidSVEPredicate3bHReg:
- return Error(Loc, "invalid restricted predicate register, expected p0.h..p7.h");
- case Match_InvalidSVEPredicate3bSReg:
- return Error(Loc, "invalid restricted predicate register, expected p0.s..p7.s");
- case Match_InvalidSVEPredicate3bDReg:
- return Error(Loc, "invalid restricted predicate register, expected p0.d..p7.d");
- case Match_InvalidSVEExactFPImmOperandHalfOne:
- return Error(Loc, "Invalid floating point constant, expected 0.5 or 1.0.");
- case Match_InvalidSVEExactFPImmOperandHalfTwo:
- return Error(Loc, "Invalid floating point constant, expected 0.5 or 2.0.");
- case Match_InvalidSVEExactFPImmOperandZeroOne:
- return Error(Loc, "Invalid floating point constant, expected 0.0 or 1.0.");
- default:
- llvm_unreachable("unexpected error code!");
- }
-}
-
-static const char *getSubtargetFeatureName(uint64_t Val);
-
-bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
- OperandVector &Operands,
- MCStreamer &Out,
- uint64_t &ErrorInfo,
- bool MatchingInlineAsm) {
- assert(!Operands.empty() && "Unexpect empty operand list!");
- AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[0]);
- assert(Op.isToken() && "Leading operand should always be a mnemonic!");
-
- StringRef Tok = Op.getToken();
- unsigned NumOperands = Operands.size();
-
- if (NumOperands == 4 && Tok == "lsl") {
- AArch64Operand &Op2 = static_cast<AArch64Operand &>(*Operands[2]);
- AArch64Operand &Op3 = static_cast<AArch64Operand &>(*Operands[3]);
- if (Op2.isScalarReg() && Op3.isImm()) {
- const MCConstantExpr *Op3CE = dyn_cast<MCConstantExpr>(Op3.getImm());
- if (Op3CE) {
- uint64_t Op3Val = Op3CE->getValue();
- uint64_t NewOp3Val = 0;
- uint64_t NewOp4Val = 0;
- if (AArch64MCRegisterClasses[AArch64::GPR32allRegClassID].contains(
- Op2.getReg())) {
- NewOp3Val = (32 - Op3Val) & 0x1f;
- NewOp4Val = 31 - Op3Val;
- } else {
- NewOp3Val = (64 - Op3Val) & 0x3f;
- NewOp4Val = 63 - Op3Val;
- }
-
- const MCExpr *NewOp3 = MCConstantExpr::create(NewOp3Val, getContext());
- const MCExpr *NewOp4 = MCConstantExpr::create(NewOp4Val, getContext());
-
- Operands[0] = AArch64Operand::CreateToken(
- "ubfm", false, Op.getStartLoc(), getContext());
- Operands.push_back(AArch64Operand::CreateImm(
- NewOp4, Op3.getStartLoc(), Op3.getEndLoc(), getContext()));
- Operands[3] = AArch64Operand::CreateImm(NewOp3, Op3.getStartLoc(),
- Op3.getEndLoc(), getContext());
- }
- }
- } else if (NumOperands == 4 && Tok == "bfc") {
- // FIXME: Horrible hack to handle BFC->BFM alias.
- AArch64Operand &Op1 = static_cast<AArch64Operand &>(*Operands[1]);
- AArch64Operand LSBOp = static_cast<AArch64Operand &>(*Operands[2]);
- AArch64Operand WidthOp = static_cast<AArch64Operand &>(*Operands[3]);
-
- if (Op1.isScalarReg() && LSBOp.isImm() && WidthOp.isImm()) {
- const MCConstantExpr *LSBCE = dyn_cast<MCConstantExpr>(LSBOp.getImm());
- const MCConstantExpr *WidthCE = dyn_cast<MCConstantExpr>(WidthOp.getImm());
-
- if (LSBCE && WidthCE) {
- uint64_t LSB = LSBCE->getValue();
- uint64_t Width = WidthCE->getValue();
-
- uint64_t RegWidth = 0;
- if (AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
- Op1.getReg()))
- RegWidth = 64;
- else
- RegWidth = 32;
-
- if (LSB >= RegWidth)
- return Error(LSBOp.getStartLoc(),
- "expected integer in range [0, 31]");
- if (Width < 1 || Width > RegWidth)
- return Error(WidthOp.getStartLoc(),
- "expected integer in range [1, 32]");
-
- uint64_t ImmR = 0;
- if (RegWidth == 32)
- ImmR = (32 - LSB) & 0x1f;
- else
- ImmR = (64 - LSB) & 0x3f;
-
- uint64_t ImmS = Width - 1;
-
- if (ImmR != 0 && ImmS >= ImmR)
- return Error(WidthOp.getStartLoc(),
- "requested insert overflows register");
-
- const MCExpr *ImmRExpr = MCConstantExpr::create(ImmR, getContext());
- const MCExpr *ImmSExpr = MCConstantExpr::create(ImmS, getContext());
- Operands[0] = AArch64Operand::CreateToken(
- "bfm", false, Op.getStartLoc(), getContext());
- Operands[2] = AArch64Operand::CreateReg(
- RegWidth == 32 ? AArch64::WZR : AArch64::XZR, RegKind::Scalar,
- SMLoc(), SMLoc(), getContext());
- Operands[3] = AArch64Operand::CreateImm(
- ImmRExpr, LSBOp.getStartLoc(), LSBOp.getEndLoc(), getContext());
- Operands.emplace_back(
- AArch64Operand::CreateImm(ImmSExpr, WidthOp.getStartLoc(),
- WidthOp.getEndLoc(), getContext()));
- }
- }
- } else if (NumOperands == 5) {
- // FIXME: Horrible hack to handle the BFI -> BFM, SBFIZ->SBFM, and
- // UBFIZ -> UBFM aliases.
- if (Tok == "bfi" || Tok == "sbfiz" || Tok == "ubfiz") {
- AArch64Operand &Op1 = static_cast<AArch64Operand &>(*Operands[1]);
- AArch64Operand &Op3 = static_cast<AArch64Operand &>(*Operands[3]);
- AArch64Operand &Op4 = static_cast<AArch64Operand &>(*Operands[4]);
-
- if (Op1.isScalarReg() && Op3.isImm() && Op4.isImm()) {
- const MCConstantExpr *Op3CE = dyn_cast<MCConstantExpr>(Op3.getImm());
- const MCConstantExpr *Op4CE = dyn_cast<MCConstantExpr>(Op4.getImm());
-
- if (Op3CE && Op4CE) {
- uint64_t Op3Val = Op3CE->getValue();
- uint64_t Op4Val = Op4CE->getValue();
-
- uint64_t RegWidth = 0;
- if (AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
- Op1.getReg()))
- RegWidth = 64;
- else
- RegWidth = 32;
-
- if (Op3Val >= RegWidth)
- return Error(Op3.getStartLoc(),
- "expected integer in range [0, 31]");
- if (Op4Val < 1 || Op4Val > RegWidth)
- return Error(Op4.getStartLoc(),
- "expected integer in range [1, 32]");
-
- uint64_t NewOp3Val = 0;
- if (RegWidth == 32)
- NewOp3Val = (32 - Op3Val) & 0x1f;
- else
- NewOp3Val = (64 - Op3Val) & 0x3f;
-
- uint64_t NewOp4Val = Op4Val - 1;
-
- if (NewOp3Val != 0 && NewOp4Val >= NewOp3Val)
- return Error(Op4.getStartLoc(),
- "requested insert overflows register");
-
- const MCExpr *NewOp3 =
- MCConstantExpr::create(NewOp3Val, getContext());
- const MCExpr *NewOp4 =
- MCConstantExpr::create(NewOp4Val, getContext());
- Operands[3] = AArch64Operand::CreateImm(
- NewOp3, Op3.getStartLoc(), Op3.getEndLoc(), getContext());
- Operands[4] = AArch64Operand::CreateImm(
- NewOp4, Op4.getStartLoc(), Op4.getEndLoc(), getContext());
- if (Tok == "bfi")
- Operands[0] = AArch64Operand::CreateToken(
- "bfm", false, Op.getStartLoc(), getContext());
- else if (Tok == "sbfiz")
- Operands[0] = AArch64Operand::CreateToken(
- "sbfm", false, Op.getStartLoc(), getContext());
- else if (Tok == "ubfiz")
- Operands[0] = AArch64Operand::CreateToken(
- "ubfm", false, Op.getStartLoc(), getContext());
- else
- llvm_unreachable("No valid mnemonic for alias?");
- }
- }
-
- // FIXME: Horrible hack to handle the BFXIL->BFM, SBFX->SBFM, and
- // UBFX -> UBFM aliases.
- } else if (NumOperands == 5 &&
- (Tok == "bfxil" || Tok == "sbfx" || Tok == "ubfx")) {
- AArch64Operand &Op1 = static_cast<AArch64Operand &>(*Operands[1]);
- AArch64Operand &Op3 = static_cast<AArch64Operand &>(*Operands[3]);
- AArch64Operand &Op4 = static_cast<AArch64Operand &>(*Operands[4]);
-
- if (Op1.isScalarReg() && Op3.isImm() && Op4.isImm()) {
- const MCConstantExpr *Op3CE = dyn_cast<MCConstantExpr>(Op3.getImm());
- const MCConstantExpr *Op4CE = dyn_cast<MCConstantExpr>(Op4.getImm());
-
- if (Op3CE && Op4CE) {
- uint64_t Op3Val = Op3CE->getValue();
- uint64_t Op4Val = Op4CE->getValue();
-
- uint64_t RegWidth = 0;
- if (AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
- Op1.getReg()))
- RegWidth = 64;
- else
- RegWidth = 32;
-
- if (Op3Val >= RegWidth)
- return Error(Op3.getStartLoc(),
- "expected integer in range [0, 31]");
- if (Op4Val < 1 || Op4Val > RegWidth)
- return Error(Op4.getStartLoc(),
- "expected integer in range [1, 32]");
-
- uint64_t NewOp4Val = Op3Val + Op4Val - 1;
-
- if (NewOp4Val >= RegWidth || NewOp4Val < Op3Val)
- return Error(Op4.getStartLoc(),
- "requested extract overflows register");
-
- const MCExpr *NewOp4 =
- MCConstantExpr::create(NewOp4Val, getContext());
- Operands[4] = AArch64Operand::CreateImm(
- NewOp4, Op4.getStartLoc(), Op4.getEndLoc(), getContext());
- if (Tok == "bfxil")
- Operands[0] = AArch64Operand::CreateToken(
- "bfm", false, Op.getStartLoc(), getContext());
- else if (Tok == "sbfx")
- Operands[0] = AArch64Operand::CreateToken(
- "sbfm", false, Op.getStartLoc(), getContext());
- else if (Tok == "ubfx")
- Operands[0] = AArch64Operand::CreateToken(
- "ubfm", false, Op.getStartLoc(), getContext());
- else
- llvm_unreachable("No valid mnemonic for alias?");
- }
- }
- }
- }
-
- // The Cyclone CPU and early successors didn't execute the zero-cycle zeroing
- // instruction for FP registers correctly in some rare circumstances. Convert
- // it to a safe instruction and warn (because silently changing someone's
- // assembly is rude).
- if (getSTI().getFeatureBits()[AArch64::FeatureZCZeroingFPWorkaround] &&
- NumOperands == 4 && Tok == "movi") {
- AArch64Operand &Op1 = static_cast<AArch64Operand &>(*Operands[1]);
- AArch64Operand &Op2 = static_cast<AArch64Operand &>(*Operands[2]);
- AArch64Operand &Op3 = static_cast<AArch64Operand &>(*Operands[3]);
- if ((Op1.isToken() && Op2.isNeonVectorReg() && Op3.isImm()) ||
- (Op1.isNeonVectorReg() && Op2.isToken() && Op3.isImm())) {
- StringRef Suffix = Op1.isToken() ? Op1.getToken() : Op2.getToken();
- if (Suffix.lower() == ".2d" &&
- cast<MCConstantExpr>(Op3.getImm())->getValue() == 0) {
- Warning(IDLoc, "instruction movi.2d with immediate #0 may not function"
- " correctly on this CPU, converting to equivalent movi.16b");
- // Switch the suffix to .16b.
- unsigned Idx = Op1.isToken() ? 1 : 2;
- Operands[Idx] = AArch64Operand::CreateToken(".16b", false, IDLoc,
- getContext());
- }
- }
- }
-
- // FIXME: Horrible hack for sxtw and uxtw with Wn src and Xd dst operands.
- // InstAlias can't quite handle this since the reg classes aren't
- // subclasses.
- if (NumOperands == 3 && (Tok == "sxtw" || Tok == "uxtw")) {
- // The source register can be Wn here, but the matcher expects a
- // GPR64. Twiddle it here if necessary.
- AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[2]);
- if (Op.isScalarReg()) {
- unsigned Reg = getXRegFromWReg(Op.getReg());
- Operands[2] = AArch64Operand::CreateReg(Reg, RegKind::Scalar,
- Op.getStartLoc(), Op.getEndLoc(),
- getContext());
- }
- }
- // FIXME: Likewise for sxt[bh] with a Xd dst operand
- else if (NumOperands == 3 && (Tok == "sxtb" || Tok == "sxth")) {
- AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[1]);
- if (Op.isScalarReg() &&
- AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
- Op.getReg())) {
- // The source register can be Wn here, but the matcher expects a
- // GPR64. Twiddle it here if necessary.
- AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[2]);
- if (Op.isScalarReg()) {
- unsigned Reg = getXRegFromWReg(Op.getReg());
- Operands[2] = AArch64Operand::CreateReg(Reg, RegKind::Scalar,
- Op.getStartLoc(),
- Op.getEndLoc(), getContext());
- }
- }
- }
- // FIXME: Likewise for uxt[bh] with a Xd dst operand
- else if (NumOperands == 3 && (Tok == "uxtb" || Tok == "uxth")) {
- AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[1]);
- if (Op.isScalarReg() &&
- AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
- Op.getReg())) {
- // The source register can be Wn here, but the matcher expects a
- // GPR32. Twiddle it here if necessary.
- AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[1]);
- if (Op.isScalarReg()) {
- unsigned Reg = getWRegFromXReg(Op.getReg());
- Operands[1] = AArch64Operand::CreateReg(Reg, RegKind::Scalar,
- Op.getStartLoc(),
- Op.getEndLoc(), getContext());
- }
- }
- }
-
- MCInst Inst;
- FeatureBitset MissingFeatures;
- // First try to match against the secondary set of tables containing the
- // short-form NEON instructions (e.g. "fadd.2s v0, v1, v2").
- unsigned MatchResult =
- MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
- MatchingInlineAsm, 1);
-
- // If that fails, try against the alternate table containing long-form NEON:
- // "fadd v0.2s, v1.2s, v2.2s"
- if (MatchResult != Match_Success) {
- // But first, save the short-form match result: we can use it in case the
- // long-form match also fails.
- auto ShortFormNEONErrorInfo = ErrorInfo;
- auto ShortFormNEONMatchResult = MatchResult;
- auto ShortFormNEONMissingFeatures = MissingFeatures;
-
- MatchResult =
- MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
- MatchingInlineAsm, 0);
-
- // Now, both matches failed, and the long-form match failed on the mnemonic
- // suffix token operand. The short-form match failure is probably more
- // relevant: use it instead.
- if (MatchResult == Match_InvalidOperand && ErrorInfo == 1 &&
- Operands.size() > 1 && ((AArch64Operand &)*Operands[1]).isToken() &&
- ((AArch64Operand &)*Operands[1]).isTokenSuffix()) {
- MatchResult = ShortFormNEONMatchResult;
- ErrorInfo = ShortFormNEONErrorInfo;
- MissingFeatures = ShortFormNEONMissingFeatures;
- }
- }
-
- switch (MatchResult) {
- case Match_Success: {
- // Perform range checking and other semantic validations
- SmallVector<SMLoc, 8> OperandLocs;
- NumOperands = Operands.size();
- for (unsigned i = 1; i < NumOperands; ++i)
- OperandLocs.push_back(Operands[i]->getStartLoc());
- if (validateInstruction(Inst, IDLoc, OperandLocs))
- return true;
-
- Inst.setLoc(IDLoc);
- Out.emitInstruction(Inst, getSTI());
- return false;
- }
- case Match_MissingFeature: {
- assert(MissingFeatures.any() && "Unknown missing feature!");
- // Special case the error message for the very common case where only
- // a single subtarget feature is missing (neon, e.g.).
- std::string Msg = "instruction requires:";
- for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
- if (MissingFeatures[i]) {
- Msg += " ";
- Msg += getSubtargetFeatureName(i);
- }
- }
- return Error(IDLoc, Msg);
- }
- case Match_MnemonicFail:
- return showMatchError(IDLoc, MatchResult, ErrorInfo, Operands);
- case Match_InvalidOperand: {
- SMLoc ErrorLoc = IDLoc;
-
- if (ErrorInfo != ~0ULL) {
- if (ErrorInfo >= Operands.size())
- return Error(IDLoc, "too few operands for instruction",
- SMRange(IDLoc, getTok().getLoc()));
-
- ErrorLoc = ((AArch64Operand &)*Operands[ErrorInfo]).getStartLoc();
- if (ErrorLoc == SMLoc())
- ErrorLoc = IDLoc;
- }
- // If the match failed on a suffix token operand, tweak the diagnostic
- // accordingly.
- if (((AArch64Operand &)*Operands[ErrorInfo]).isToken() &&
- ((AArch64Operand &)*Operands[ErrorInfo]).isTokenSuffix())
- MatchResult = Match_InvalidSuffix;
-
- return showMatchError(ErrorLoc, MatchResult, ErrorInfo, Operands);
- }
- case Match_InvalidTiedOperand:
- case Match_InvalidMemoryIndexed1:
- case Match_InvalidMemoryIndexed2:
- case Match_InvalidMemoryIndexed4:
- case Match_InvalidMemoryIndexed8:
- case Match_InvalidMemoryIndexed16:
- case Match_InvalidCondCode:
- case Match_AddSubRegExtendSmall:
- case Match_AddSubRegExtendLarge:
- case Match_AddSubSecondSource:
- case Match_LogicalSecondSource:
- case Match_AddSubRegShift32:
- case Match_AddSubRegShift64:
- case Match_InvalidMovImm32Shift:
- case Match_InvalidMovImm64Shift:
- case Match_InvalidFPImm:
- case Match_InvalidMemoryWExtend8:
- case Match_InvalidMemoryWExtend16:
- case Match_InvalidMemoryWExtend32:
- case Match_InvalidMemoryWExtend64:
- case Match_InvalidMemoryWExtend128:
- case Match_InvalidMemoryXExtend8:
- case Match_InvalidMemoryXExtend16:
- case Match_InvalidMemoryXExtend32:
- case Match_InvalidMemoryXExtend64:
- case Match_InvalidMemoryXExtend128:
- case Match_InvalidMemoryIndexed1SImm4:
- case Match_InvalidMemoryIndexed2SImm4:
- case Match_InvalidMemoryIndexed3SImm4:
- case Match_InvalidMemoryIndexed4SImm4:
- case Match_InvalidMemoryIndexed1SImm6:
- case Match_InvalidMemoryIndexed16SImm4:
- case Match_InvalidMemoryIndexed32SImm4:
- case Match_InvalidMemoryIndexed4SImm7:
- case Match_InvalidMemoryIndexed8SImm7:
- case Match_InvalidMemoryIndexed16SImm7:
- case Match_InvalidMemoryIndexed8UImm5:
- case Match_InvalidMemoryIndexed4UImm5:
- case Match_InvalidMemoryIndexed2UImm5:
- case Match_InvalidMemoryIndexed1UImm6:
- case Match_InvalidMemoryIndexed2UImm6:
- case Match_InvalidMemoryIndexed4UImm6:
- case Match_InvalidMemoryIndexed8UImm6:
- case Match_InvalidMemoryIndexed16UImm6:
- case Match_InvalidMemoryIndexedSImm6:
- case Match_InvalidMemoryIndexedSImm5:
- case Match_InvalidMemoryIndexedSImm8:
- case Match_InvalidMemoryIndexedSImm9:
- case Match_InvalidMemoryIndexed16SImm9:
- case Match_InvalidMemoryIndexed8SImm10:
- case Match_InvalidImm0_1:
- case Match_InvalidImm0_7:
- case Match_InvalidImm0_15:
- case Match_InvalidImm0_31:
- case Match_InvalidImm0_63:
- case Match_InvalidImm0_127:
- case Match_InvalidImm0_255:
- case Match_InvalidImm0_65535:
- case Match_InvalidImm1_8:
- case Match_InvalidImm1_16:
- case Match_InvalidImm1_32:
- case Match_InvalidImm1_64:
- case Match_InvalidSVEAddSubImm8:
- case Match_InvalidSVEAddSubImm16:
- case Match_InvalidSVEAddSubImm32:
- case Match_InvalidSVEAddSubImm64:
- case Match_InvalidSVECpyImm8:
- case Match_InvalidSVECpyImm16:
- case Match_InvalidSVECpyImm32:
- case Match_InvalidSVECpyImm64:
- case Match_InvalidIndexRange1_1:
- case Match_InvalidIndexRange0_15:
- case Match_InvalidIndexRange0_7:
- case Match_InvalidIndexRange0_3:
- case Match_InvalidIndexRange0_1:
- case Match_InvalidSVEIndexRange0_63:
- case Match_InvalidSVEIndexRange0_31:
- case Match_InvalidSVEIndexRange0_15:
- case Match_InvalidSVEIndexRange0_7:
- case Match_InvalidSVEIndexRange0_3:
- case Match_InvalidLabel:
- case Match_InvalidComplexRotationEven:
- case Match_InvalidComplexRotationOdd:
- case Match_InvalidGPR64shifted8:
- case Match_InvalidGPR64shifted16:
- case Match_InvalidGPR64shifted32:
- case Match_InvalidGPR64shifted64:
- case Match_InvalidGPR64NoXZRshifted8:
- case Match_InvalidGPR64NoXZRshifted16:
- case Match_InvalidGPR64NoXZRshifted32:
- case Match_InvalidGPR64NoXZRshifted64:
- case Match_InvalidZPR32UXTW8:
- case Match_InvalidZPR32UXTW16:
- case Match_InvalidZPR32UXTW32:
- case Match_InvalidZPR32UXTW64:
- case Match_InvalidZPR32SXTW8:
- case Match_InvalidZPR32SXTW16:
- case Match_InvalidZPR32SXTW32:
- case Match_InvalidZPR32SXTW64:
- case Match_InvalidZPR64UXTW8:
- case Match_InvalidZPR64SXTW8:
- case Match_InvalidZPR64UXTW16:
- case Match_InvalidZPR64SXTW16:
- case Match_InvalidZPR64UXTW32:
- case Match_InvalidZPR64SXTW32:
- case Match_InvalidZPR64UXTW64:
- case Match_InvalidZPR64SXTW64:
- case Match_InvalidZPR32LSL8:
- case Match_InvalidZPR32LSL16:
- case Match_InvalidZPR32LSL32:
- case Match_InvalidZPR32LSL64:
- case Match_InvalidZPR64LSL8:
- case Match_InvalidZPR64LSL16:
- case Match_InvalidZPR64LSL32:
- case Match_InvalidZPR64LSL64:
- case Match_InvalidZPR0:
- case Match_InvalidZPR8:
- case Match_InvalidZPR16:
- case Match_InvalidZPR32:
- case Match_InvalidZPR64:
- case Match_InvalidZPR128:
- case Match_InvalidZPR_3b8:
- case Match_InvalidZPR_3b16:
- case Match_InvalidZPR_3b32:
- case Match_InvalidZPR_4b16:
- case Match_InvalidZPR_4b32:
- case Match_InvalidZPR_4b64:
- case Match_InvalidSVEPredicateAnyReg:
- case Match_InvalidSVEPattern:
- case Match_InvalidSVEPredicateBReg:
- case Match_InvalidSVEPredicateHReg:
- case Match_InvalidSVEPredicateSReg:
- case Match_InvalidSVEPredicateDReg:
- case Match_InvalidSVEPredicate3bAnyReg:
- case Match_InvalidSVEPredicate3bBReg:
- case Match_InvalidSVEPredicate3bHReg:
- case Match_InvalidSVEPredicate3bSReg:
- case Match_InvalidSVEPredicate3bDReg:
- case Match_InvalidSVEExactFPImmOperandHalfOne:
- case Match_InvalidSVEExactFPImmOperandHalfTwo:
- case Match_InvalidSVEExactFPImmOperandZeroOne:
- case Match_MSR:
- case Match_MRS: {
- if (ErrorInfo >= Operands.size())
- return Error(IDLoc, "too few operands for instruction", SMRange(IDLoc, (*Operands.back()).getEndLoc()));
- // Any time we get here, there's nothing fancy to do. Just get the
- // operand SMLoc and display the diagnostic.
- SMLoc ErrorLoc = ((AArch64Operand &)*Operands[ErrorInfo]).getStartLoc();
- if (ErrorLoc == SMLoc())
- ErrorLoc = IDLoc;
- return showMatchError(ErrorLoc, MatchResult, ErrorInfo, Operands);
- }
- }
-
- llvm_unreachable("Implement any new match types added!");
-}
-
-/// ParseDirective parses the arm specific directives
-bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
- const MCObjectFileInfo::Environment Format =
- getContext().getObjectFileInfo()->getObjectFileType();
- bool IsMachO = Format == MCObjectFileInfo::IsMachO;
+bool AArch64AsmParser::regsEqual(const MCParsedAsmOperand &Op1,
+ const MCParsedAsmOperand &Op2) const {
+ auto &AOp1 = static_cast<const AArch64Operand&>(Op1);
+ auto &AOp2 = static_cast<const AArch64Operand&>(Op2);
+ if (AOp1.getRegEqualityTy() == RegConstraintEqualityTy::EqualsReg &&
+ AOp2.getRegEqualityTy() == RegConstraintEqualityTy::EqualsReg)
+ return MCTargetAsmParser::regsEqual(Op1, Op2);
+
+ assert(AOp1.isScalarReg() && AOp2.isScalarReg() &&
+ "Testing equality of non-scalar registers not supported");
+
+ // Check if a registers match their sub/super register classes.
+ if (AOp1.getRegEqualityTy() == EqualsSuperReg)
+ return getXRegFromWReg(Op1.getReg()) == Op2.getReg();
+ if (AOp1.getRegEqualityTy() == EqualsSubReg)
+ return getWRegFromXReg(Op1.getReg()) == Op2.getReg();
+ if (AOp2.getRegEqualityTy() == EqualsSuperReg)
+ return getXRegFromWReg(Op2.getReg()) == Op1.getReg();
+ if (AOp2.getRegEqualityTy() == EqualsSubReg)
+ return getWRegFromXReg(Op2.getReg()) == Op1.getReg();
+
+ return false;
+}
+
+/// ParseInstruction - Parse an AArch64 instruction mnemonic followed by its
+/// operands.
+bool AArch64AsmParser::ParseInstruction(ParseInstructionInfo &Info,
+ StringRef Name, SMLoc NameLoc,
+ OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ Name = StringSwitch<StringRef>(Name.lower())
+ .Case("beq", "b.eq")
+ .Case("bne", "b.ne")
+ .Case("bhs", "b.hs")
+ .Case("bcs", "b.cs")
+ .Case("blo", "b.lo")
+ .Case("bcc", "b.cc")
+ .Case("bmi", "b.mi")
+ .Case("bpl", "b.pl")
+ .Case("bvs", "b.vs")
+ .Case("bvc", "b.vc")
+ .Case("bhi", "b.hi")
+ .Case("bls", "b.ls")
+ .Case("bge", "b.ge")
+ .Case("blt", "b.lt")
+ .Case("bgt", "b.gt")
+ .Case("ble", "b.le")
+ .Case("bal", "b.al")
+ .Case("bnv", "b.nv")
+ .Default(Name);
+
+ // First check for the AArch64-specific .req directive.
+ if (Parser.getTok().is(AsmToken::Identifier) &&
+ Parser.getTok().getIdentifier().lower() == ".req") {
+ parseDirectiveReq(Name, NameLoc);
+ // We always return 'error' for this, as we're done with this
+ // statement and don't need to match the 'instruction."
+ return true;
+ }
+
+ // Create the leading tokens for the mnemonic, split by '.' characters.
+ size_t Start = 0, Next = Name.find('.');
+ StringRef Head = Name.slice(Start, Next);
+
+ // IC, DC, AT, TLBI and Prediction invalidation instructions are aliases for
+ // the SYS instruction.
+ if (Head == "ic" || Head == "dc" || Head == "at" || Head == "tlbi" ||
+ Head == "cfp" || Head == "dvp" || Head == "cpp")
+ return parseSysAlias(Head, NameLoc, Operands);
+
+ Operands.push_back(
+ AArch64Operand::CreateToken(Head, false, NameLoc, getContext()));
+ Mnemonic = Head;
+
+ // Handle condition codes for a branch mnemonic
+ if (Head == "b" && Next != StringRef::npos) {
+ Start = Next;
+ Next = Name.find('.', Start + 1);
+ Head = Name.slice(Start + 1, Next);
+
+ SMLoc SuffixLoc = SMLoc::getFromPointer(NameLoc.getPointer() +
+ (Head.data() - Name.data()));
+ AArch64CC::CondCode CC = parseCondCodeString(Head);
+ if (CC == AArch64CC::Invalid)
+ return Error(SuffixLoc, "invalid condition code");
+ Operands.push_back(
+ AArch64Operand::CreateToken(".", true, SuffixLoc, getContext()));
+ Operands.push_back(
+ AArch64Operand::CreateCondCode(CC, NameLoc, NameLoc, getContext()));
+ }
+
+ // Add the remaining tokens in the mnemonic.
+ while (Next != StringRef::npos) {
+ Start = Next;
+ Next = Name.find('.', Start + 1);
+ Head = Name.slice(Start, Next);
+ SMLoc SuffixLoc = SMLoc::getFromPointer(NameLoc.getPointer() +
+ (Head.data() - Name.data()) + 1);
+ Operands.push_back(
+ AArch64Operand::CreateToken(Head, true, SuffixLoc, getContext()));
+ }
+
+ // Conditional compare instructions have a Condition Code operand, which needs
+ // to be parsed and an immediate operand created.
+ bool condCodeFourthOperand =
+ (Head == "ccmp" || Head == "ccmn" || Head == "fccmp" ||
+ Head == "fccmpe" || Head == "fcsel" || Head == "csel" ||
+ Head == "csinc" || Head == "csinv" || Head == "csneg");
+
+ // These instructions are aliases to some of the conditional select
+ // instructions. However, the condition code is inverted in the aliased
+ // instruction.
+ //
+ // FIXME: Is this the correct way to handle these? Or should the parser
+ // generate the aliased instructions directly?
+ bool condCodeSecondOperand = (Head == "cset" || Head == "csetm");
+ bool condCodeThirdOperand =
+ (Head == "cinc" || Head == "cinv" || Head == "cneg");
+
+ // Read the remaining operands.
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+
+ unsigned N = 1;
+ do {
+ // Parse and remember the operand.
+ if (parseOperand(Operands, (N == 4 && condCodeFourthOperand) ||
+ (N == 3 && condCodeThirdOperand) ||
+ (N == 2 && condCodeSecondOperand),
+ condCodeSecondOperand || condCodeThirdOperand)) {
+ return true;
+ }
+
+ // After successfully parsing some operands there are two special cases to
+ // consider (i.e. notional operands not separated by commas). Both are due
+ // to memory specifiers:
+ // + An RBrac will end an address for load/store/prefetch
+ // + An '!' will indicate a pre-indexed operation.
+ //
+ // It's someone else's responsibility to make sure these tokens are sane
+ // in the given context!
+
+ SMLoc RLoc = Parser.getTok().getLoc();
+ if (parseOptionalToken(AsmToken::RBrac))
+ Operands.push_back(
+ AArch64Operand::CreateToken("]", false, RLoc, getContext()));
+ SMLoc ELoc = Parser.getTok().getLoc();
+ if (parseOptionalToken(AsmToken::Exclaim))
+ Operands.push_back(
+ AArch64Operand::CreateToken("!", false, ELoc, getContext()));
+
+ ++N;
+ } while (parseOptionalToken(AsmToken::Comma));
+ }
+
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in argument list"))
+ return true;
+
+ return false;
+}
+
+static inline bool isMatchingOrAlias(unsigned ZReg, unsigned Reg) {
+ assert((ZReg >= AArch64::Z0) && (ZReg <= AArch64::Z31));
+ return (ZReg == ((Reg - AArch64::B0) + AArch64::Z0)) ||
+ (ZReg == ((Reg - AArch64::H0) + AArch64::Z0)) ||
+ (ZReg == ((Reg - AArch64::S0) + AArch64::Z0)) ||
+ (ZReg == ((Reg - AArch64::D0) + AArch64::Z0)) ||
+ (ZReg == ((Reg - AArch64::Q0) + AArch64::Z0)) ||
+ (ZReg == ((Reg - AArch64::Z0) + AArch64::Z0));
+}
+
+// FIXME: This entire function is a giant hack to provide us with decent
+// operand range validation/diagnostics until TableGen/MC can be extended
+// to support autogeneration of this kind of validation.
+bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc,
+ SmallVectorImpl<SMLoc> &Loc) {
+ const MCRegisterInfo *RI = getContext().getRegisterInfo();
+ const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+
+ // A prefix only applies to the instruction following it. Here we extract
+ // prefix information for the next instruction before validating the current
+ // one so that in the case of failure we don't erronously continue using the
+ // current prefix.
+ PrefixInfo Prefix = NextPrefix;
+ NextPrefix = PrefixInfo::CreateFromInst(Inst, MCID.TSFlags);
+
+ // Before validating the instruction in isolation we run through the rules
+ // applicable when it follows a prefix instruction.
+ // NOTE: brk & hlt can be prefixed but require no additional validation.
+ if (Prefix.isActive() &&
+ (Inst.getOpcode() != AArch64::BRK) &&
+ (Inst.getOpcode() != AArch64::HLT)) {
+
+ // Prefixed intructions must have a destructive operand.
+ if ((MCID.TSFlags & AArch64::DestructiveInstTypeMask) ==
+ AArch64::NotDestructive)
+ return Error(IDLoc, "instruction is unpredictable when following a"
+ " movprfx, suggest replacing movprfx with mov");
+
+ // Destination operands must match.
+ if (Inst.getOperand(0).getReg() != Prefix.getDstReg())
+ return Error(Loc[0], "instruction is unpredictable when following a"
+ " movprfx writing to a different destination");
+
+ // Destination operand must not be used in any other location.
+ for (unsigned i = 1; i < Inst.getNumOperands(); ++i) {
+ if (Inst.getOperand(i).isReg() &&
+ (MCID.getOperandConstraint(i, MCOI::TIED_TO) == -1) &&
+ isMatchingOrAlias(Prefix.getDstReg(), Inst.getOperand(i).getReg()))
+ return Error(Loc[0], "instruction is unpredictable when following a"
+ " movprfx and destination also used as non-destructive"
+ " source");
+ }
+
+ auto PPRRegClass = AArch64MCRegisterClasses[AArch64::PPRRegClassID];
+ if (Prefix.isPredicated()) {
+ int PgIdx = -1;
+
+ // Find the instructions general predicate.
+ for (unsigned i = 1; i < Inst.getNumOperands(); ++i)
+ if (Inst.getOperand(i).isReg() &&
+ PPRRegClass.contains(Inst.getOperand(i).getReg())) {
+ PgIdx = i;
+ break;
+ }
+
+ // Instruction must be predicated if the movprfx is predicated.
+ if (PgIdx == -1 ||
+ (MCID.TSFlags & AArch64::ElementSizeMask) == AArch64::ElementSizeNone)
+ return Error(IDLoc, "instruction is unpredictable when following a"
+ " predicated movprfx, suggest using unpredicated movprfx");
+
+ // Instruction must use same general predicate as the movprfx.
+ if (Inst.getOperand(PgIdx).getReg() != Prefix.getPgReg())
+ return Error(IDLoc, "instruction is unpredictable when following a"
+ " predicated movprfx using a different general predicate");
+
+ // Instruction element type must match the movprfx.
+ if ((MCID.TSFlags & AArch64::ElementSizeMask) != Prefix.getElementSize())
+ return Error(IDLoc, "instruction is unpredictable when following a"
+ " predicated movprfx with a different element size");
+ }
+ }
+
+ // Check for indexed addressing modes w/ the base register being the
+ // same as a destination/source register or pair load where
+ // the Rt == Rt2. All of those are undefined behaviour.
+ switch (Inst.getOpcode()) {
+ case AArch64::LDPSWpre:
+ case AArch64::LDPWpost:
+ case AArch64::LDPWpre:
+ case AArch64::LDPXpost:
+ case AArch64::LDPXpre: {
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rt2 = Inst.getOperand(2).getReg();
+ unsigned Rn = Inst.getOperand(3).getReg();
+ if (RI->isSubRegisterEq(Rn, Rt))
+ return Error(Loc[0], "unpredictable LDP instruction, writeback base "
+ "is also a destination");
+ if (RI->isSubRegisterEq(Rn, Rt2))
+ return Error(Loc[1], "unpredictable LDP instruction, writeback base "
+ "is also a destination");
+ LLVM_FALLTHROUGH;
+ }
+ case AArch64::LDPDi:
+ case AArch64::LDPQi:
+ case AArch64::LDPSi:
+ case AArch64::LDPSWi:
+ case AArch64::LDPWi:
+ case AArch64::LDPXi: {
+ unsigned Rt = Inst.getOperand(0).getReg();
+ unsigned Rt2 = Inst.getOperand(1).getReg();
+ if (Rt == Rt2)
+ return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt");
+ break;
+ }
+ case AArch64::LDPDpost:
+ case AArch64::LDPDpre:
+ case AArch64::LDPQpost:
+ case AArch64::LDPQpre:
+ case AArch64::LDPSpost:
+ case AArch64::LDPSpre:
+ case AArch64::LDPSWpost: {
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rt2 = Inst.getOperand(2).getReg();
+ if (Rt == Rt2)
+ return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt");
+ break;
+ }
+ case AArch64::STPDpost:
+ case AArch64::STPDpre:
+ case AArch64::STPQpost:
+ case AArch64::STPQpre:
+ case AArch64::STPSpost:
+ case AArch64::STPSpre:
+ case AArch64::STPWpost:
+ case AArch64::STPWpre:
+ case AArch64::STPXpost:
+ case AArch64::STPXpre: {
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rt2 = Inst.getOperand(2).getReg();
+ unsigned Rn = Inst.getOperand(3).getReg();
+ if (RI->isSubRegisterEq(Rn, Rt))
+ return Error(Loc[0], "unpredictable STP instruction, writeback base "
+ "is also a source");
+ if (RI->isSubRegisterEq(Rn, Rt2))
+ return Error(Loc[1], "unpredictable STP instruction, writeback base "
+ "is also a source");
+ break;
+ }
+ case AArch64::LDRBBpre:
+ case AArch64::LDRBpre:
+ case AArch64::LDRHHpre:
+ case AArch64::LDRHpre:
+ case AArch64::LDRSBWpre:
+ case AArch64::LDRSBXpre:
+ case AArch64::LDRSHWpre:
+ case AArch64::LDRSHXpre:
+ case AArch64::LDRSWpre:
+ case AArch64::LDRWpre:
+ case AArch64::LDRXpre:
+ case AArch64::LDRBBpost:
+ case AArch64::LDRBpost:
+ case AArch64::LDRHHpost:
+ case AArch64::LDRHpost:
+ case AArch64::LDRSBWpost:
+ case AArch64::LDRSBXpost:
+ case AArch64::LDRSHWpost:
+ case AArch64::LDRSHXpost:
+ case AArch64::LDRSWpost:
+ case AArch64::LDRWpost:
+ case AArch64::LDRXpost: {
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rn = Inst.getOperand(2).getReg();
+ if (RI->isSubRegisterEq(Rn, Rt))
+ return Error(Loc[0], "unpredictable LDR instruction, writeback base "
+ "is also a source");
+ break;
+ }
+ case AArch64::STRBBpost:
+ case AArch64::STRBpost:
+ case AArch64::STRHHpost:
+ case AArch64::STRHpost:
+ case AArch64::STRWpost:
+ case AArch64::STRXpost:
+ case AArch64::STRBBpre:
+ case AArch64::STRBpre:
+ case AArch64::STRHHpre:
+ case AArch64::STRHpre:
+ case AArch64::STRWpre:
+ case AArch64::STRXpre: {
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rn = Inst.getOperand(2).getReg();
+ if (RI->isSubRegisterEq(Rn, Rt))
+ return Error(Loc[0], "unpredictable STR instruction, writeback base "
+ "is also a source");
+ break;
+ }
+ case AArch64::STXRB:
+ case AArch64::STXRH:
+ case AArch64::STXRW:
+ case AArch64::STXRX:
+ case AArch64::STLXRB:
+ case AArch64::STLXRH:
+ case AArch64::STLXRW:
+ case AArch64::STLXRX: {
+ unsigned Rs = Inst.getOperand(0).getReg();
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rn = Inst.getOperand(2).getReg();
+ if (RI->isSubRegisterEq(Rt, Rs) ||
+ (RI->isSubRegisterEq(Rn, Rs) && Rn != AArch64::SP))
+ return Error(Loc[0],
+ "unpredictable STXR instruction, status is also a source");
+ break;
+ }
+ case AArch64::STXPW:
+ case AArch64::STXPX:
+ case AArch64::STLXPW:
+ case AArch64::STLXPX: {
+ unsigned Rs = Inst.getOperand(0).getReg();
+ unsigned Rt1 = Inst.getOperand(1).getReg();
+ unsigned Rt2 = Inst.getOperand(2).getReg();
+ unsigned Rn = Inst.getOperand(3).getReg();
+ if (RI->isSubRegisterEq(Rt1, Rs) || RI->isSubRegisterEq(Rt2, Rs) ||
+ (RI->isSubRegisterEq(Rn, Rs) && Rn != AArch64::SP))
+ return Error(Loc[0],
+ "unpredictable STXP instruction, status is also a source");
+ break;
+ }
+ case AArch64::LDRABwriteback:
+ case AArch64::LDRAAwriteback: {
+ unsigned Xt = Inst.getOperand(0).getReg();
+ unsigned Xn = Inst.getOperand(1).getReg();
+ if (Xt == Xn)
+ return Error(Loc[0],
+ "unpredictable LDRA instruction, writeback base"
+ " is also a destination");
+ break;
+ }
+ }
+
+
+ // Now check immediate ranges. Separate from the above as there is overlap
+ // in the instructions being checked and this keeps the nested conditionals
+ // to a minimum.
+ switch (Inst.getOpcode()) {
+ case AArch64::ADDSWri:
+ case AArch64::ADDSXri:
+ case AArch64::ADDWri:
+ case AArch64::ADDXri:
+ case AArch64::SUBSWri:
+ case AArch64::SUBSXri:
+ case AArch64::SUBWri:
+ case AArch64::SUBXri: {
+ // Annoyingly we can't do this in the isAddSubImm predicate, so there is
+ // some slight duplication here.
+ if (Inst.getOperand(2).isExpr()) {
+ const MCExpr *Expr = Inst.getOperand(2).getExpr();
+ AArch64MCExpr::VariantKind ELFRefKind;
+ MCSymbolRefExpr::VariantKind DarwinRefKind;
+ int64_t Addend;
+ if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
+
+ // Only allow these with ADDXri.
+ if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF ||
+ DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) &&
+ Inst.getOpcode() == AArch64::ADDXri)
+ return false;
+
+ // Only allow these with ADDXri/ADDWri
+ if ((ELFRefKind == AArch64MCExpr::VK_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 ||
+ ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC ||
+ ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 ||
+ ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC ||
+ ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_SECREL_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_SECREL_HI12) &&
+ (Inst.getOpcode() == AArch64::ADDXri ||
+ Inst.getOpcode() == AArch64::ADDWri))
+ return false;
+
+ // Don't allow symbol refs in the immediate field otherwise
+ // Note: Loc.back() may be Loc[1] or Loc[2] depending on the number of
+ // operands of the original instruction (i.e. 'add w0, w1, borked' vs
+ // 'cmp w0, 'borked')
+ return Error(Loc.back(), "invalid immediate expression");
+ }
+ // We don't validate more complex expressions here
+ }
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
+static std::string AArch64MnemonicSpellCheck(StringRef S,
+ const FeatureBitset &FBS,
+ unsigned VariantID = 0);
+
+bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
+ uint64_t ErrorInfo,
+ OperandVector &Operands) {
+ switch (ErrCode) {
+ case Match_InvalidTiedOperand: {
+ RegConstraintEqualityTy EqTy =
+ static_cast<const AArch64Operand &>(*Operands[ErrorInfo])
+ .getRegEqualityTy();
+ switch (EqTy) {
+ case RegConstraintEqualityTy::EqualsSubReg:
+ return Error(Loc, "operand must be 64-bit form of destination register");
+ case RegConstraintEqualityTy::EqualsSuperReg:
+ return Error(Loc, "operand must be 32-bit form of destination register");
+ case RegConstraintEqualityTy::EqualsReg:
+ return Error(Loc, "operand must match destination register");
+ }
+ llvm_unreachable("Unknown RegConstraintEqualityTy");
+ }
+ case Match_MissingFeature:
+ return Error(Loc,
+ "instruction requires a CPU feature not currently enabled");
+ case Match_InvalidOperand:
+ return Error(Loc, "invalid operand for instruction");
+ case Match_InvalidSuffix:
+ return Error(Loc, "invalid type suffix for instruction");
+ case Match_InvalidCondCode:
+ return Error(Loc, "expected AArch64 condition code");
+ case Match_AddSubRegExtendSmall:
+ return Error(Loc,
+ "expected '[su]xt[bhw]' with optional integer in range [0, 4]");
+ case Match_AddSubRegExtendLarge:
+ return Error(Loc,
+ "expected 'sxtx' 'uxtx' or 'lsl' with optional integer in range [0, 4]");
+ case Match_AddSubSecondSource:
+ return Error(Loc,
+ "expected compatible register, symbol or integer in range [0, 4095]");
+ case Match_LogicalSecondSource:
+ return Error(Loc, "expected compatible register or logical immediate");
+ case Match_InvalidMovImm32Shift:
+ return Error(Loc, "expected 'lsl' with optional integer 0 or 16");
+ case Match_InvalidMovImm64Shift:
+ return Error(Loc, "expected 'lsl' with optional integer 0, 16, 32 or 48");
+ case Match_AddSubRegShift32:
+ return Error(Loc,
+ "expected 'lsl', 'lsr' or 'asr' with optional integer in range [0, 31]");
+ case Match_AddSubRegShift64:
+ return Error(Loc,
+ "expected 'lsl', 'lsr' or 'asr' with optional integer in range [0, 63]");
+ case Match_InvalidFPImm:
+ return Error(Loc,
+ "expected compatible register or floating-point constant");
+ case Match_InvalidMemoryIndexedSImm6:
+ return Error(Loc, "index must be an integer in range [-32, 31].");
+ case Match_InvalidMemoryIndexedSImm5:
+ return Error(Loc, "index must be an integer in range [-16, 15].");
+ case Match_InvalidMemoryIndexed1SImm4:
+ return Error(Loc, "index must be an integer in range [-8, 7].");
+ case Match_InvalidMemoryIndexed2SImm4:
+ return Error(Loc, "index must be a multiple of 2 in range [-16, 14].");
+ case Match_InvalidMemoryIndexed3SImm4:
+ return Error(Loc, "index must be a multiple of 3 in range [-24, 21].");
+ case Match_InvalidMemoryIndexed4SImm4:
+ return Error(Loc, "index must be a multiple of 4 in range [-32, 28].");
+ case Match_InvalidMemoryIndexed16SImm4:
+ return Error(Loc, "index must be a multiple of 16 in range [-128, 112].");
+ case Match_InvalidMemoryIndexed32SImm4:
+ return Error(Loc, "index must be a multiple of 32 in range [-256, 224].");
+ case Match_InvalidMemoryIndexed1SImm6:
+ return Error(Loc, "index must be an integer in range [-32, 31].");
+ case Match_InvalidMemoryIndexedSImm8:
+ return Error(Loc, "index must be an integer in range [-128, 127].");
+ case Match_InvalidMemoryIndexedSImm9:
+ return Error(Loc, "index must be an integer in range [-256, 255].");
+ case Match_InvalidMemoryIndexed16SImm9:
+ return Error(Loc, "index must be a multiple of 16 in range [-4096, 4080].");
+ case Match_InvalidMemoryIndexed8SImm10:
+ return Error(Loc, "index must be a multiple of 8 in range [-4096, 4088].");
+ case Match_InvalidMemoryIndexed4SImm7:
+ return Error(Loc, "index must be a multiple of 4 in range [-256, 252].");
+ case Match_InvalidMemoryIndexed8SImm7:
+ return Error(Loc, "index must be a multiple of 8 in range [-512, 504].");
+ case Match_InvalidMemoryIndexed16SImm7:
+ return Error(Loc, "index must be a multiple of 16 in range [-1024, 1008].");
+ case Match_InvalidMemoryIndexed8UImm5:
+ return Error(Loc, "index must be a multiple of 8 in range [0, 248].");
+ case Match_InvalidMemoryIndexed4UImm5:
+ return Error(Loc, "index must be a multiple of 4 in range [0, 124].");
+ case Match_InvalidMemoryIndexed2UImm5:
+ return Error(Loc, "index must be a multiple of 2 in range [0, 62].");
+ case Match_InvalidMemoryIndexed8UImm6:
+ return Error(Loc, "index must be a multiple of 8 in range [0, 504].");
+ case Match_InvalidMemoryIndexed16UImm6:
+ return Error(Loc, "index must be a multiple of 16 in range [0, 1008].");
+ case Match_InvalidMemoryIndexed4UImm6:
+ return Error(Loc, "index must be a multiple of 4 in range [0, 252].");
+ case Match_InvalidMemoryIndexed2UImm6:
+ return Error(Loc, "index must be a multiple of 2 in range [0, 126].");
+ case Match_InvalidMemoryIndexed1UImm6:
+ return Error(Loc, "index must be in range [0, 63].");
+ case Match_InvalidMemoryWExtend8:
+ return Error(Loc,
+ "expected 'uxtw' or 'sxtw' with optional shift of #0");
+ case Match_InvalidMemoryWExtend16:
+ return Error(Loc,
+ "expected 'uxtw' or 'sxtw' with optional shift of #0 or #1");
+ case Match_InvalidMemoryWExtend32:
+ return Error(Loc,
+ "expected 'uxtw' or 'sxtw' with optional shift of #0 or #2");
+ case Match_InvalidMemoryWExtend64:
+ return Error(Loc,
+ "expected 'uxtw' or 'sxtw' with optional shift of #0 or #3");
+ case Match_InvalidMemoryWExtend128:
+ return Error(Loc,
+ "expected 'uxtw' or 'sxtw' with optional shift of #0 or #4");
+ case Match_InvalidMemoryXExtend8:
+ return Error(Loc,
+ "expected 'lsl' or 'sxtx' with optional shift of #0");
+ case Match_InvalidMemoryXExtend16:
+ return Error(Loc,
+ "expected 'lsl' or 'sxtx' with optional shift of #0 or #1");
+ case Match_InvalidMemoryXExtend32:
+ return Error(Loc,
+ "expected 'lsl' or 'sxtx' with optional shift of #0 or #2");
+ case Match_InvalidMemoryXExtend64:
+ return Error(Loc,
+ "expected 'lsl' or 'sxtx' with optional shift of #0 or #3");
+ case Match_InvalidMemoryXExtend128:
+ return Error(Loc,
+ "expected 'lsl' or 'sxtx' with optional shift of #0 or #4");
+ case Match_InvalidMemoryIndexed1:
+ return Error(Loc, "index must be an integer in range [0, 4095].");
+ case Match_InvalidMemoryIndexed2:
+ return Error(Loc, "index must be a multiple of 2 in range [0, 8190].");
+ case Match_InvalidMemoryIndexed4:
+ return Error(Loc, "index must be a multiple of 4 in range [0, 16380].");
+ case Match_InvalidMemoryIndexed8:
+ return Error(Loc, "index must be a multiple of 8 in range [0, 32760].");
+ case Match_InvalidMemoryIndexed16:
+ return Error(Loc, "index must be a multiple of 16 in range [0, 65520].");
+ case Match_InvalidImm0_1:
+ return Error(Loc, "immediate must be an integer in range [0, 1].");
+ case Match_InvalidImm0_7:
+ return Error(Loc, "immediate must be an integer in range [0, 7].");
+ case Match_InvalidImm0_15:
+ return Error(Loc, "immediate must be an integer in range [0, 15].");
+ case Match_InvalidImm0_31:
+ return Error(Loc, "immediate must be an integer in range [0, 31].");
+ case Match_InvalidImm0_63:
+ return Error(Loc, "immediate must be an integer in range [0, 63].");
+ case Match_InvalidImm0_127:
+ return Error(Loc, "immediate must be an integer in range [0, 127].");
+ case Match_InvalidImm0_255:
+ return Error(Loc, "immediate must be an integer in range [0, 255].");
+ case Match_InvalidImm0_65535:
+ return Error(Loc, "immediate must be an integer in range [0, 65535].");
+ case Match_InvalidImm1_8:
+ return Error(Loc, "immediate must be an integer in range [1, 8].");
+ case Match_InvalidImm1_16:
+ return Error(Loc, "immediate must be an integer in range [1, 16].");
+ case Match_InvalidImm1_32:
+ return Error(Loc, "immediate must be an integer in range [1, 32].");
+ case Match_InvalidImm1_64:
+ return Error(Loc, "immediate must be an integer in range [1, 64].");
+ case Match_InvalidSVEAddSubImm8:
+ return Error(Loc, "immediate must be an integer in range [0, 255]"
+ " with a shift amount of 0");
+ case Match_InvalidSVEAddSubImm16:
+ case Match_InvalidSVEAddSubImm32:
+ case Match_InvalidSVEAddSubImm64:
+ return Error(Loc, "immediate must be an integer in range [0, 255] or a "
+ "multiple of 256 in range [256, 65280]");
+ case Match_InvalidSVECpyImm8:
+ return Error(Loc, "immediate must be an integer in range [-128, 255]"
+ " with a shift amount of 0");
+ case Match_InvalidSVECpyImm16:
+ return Error(Loc, "immediate must be an integer in range [-128, 127] or a "
+ "multiple of 256 in range [-32768, 65280]");
+ case Match_InvalidSVECpyImm32:
+ case Match_InvalidSVECpyImm64:
+ return Error(Loc, "immediate must be an integer in range [-128, 127] or a "
+ "multiple of 256 in range [-32768, 32512]");
+ case Match_InvalidIndexRange1_1:
+ return Error(Loc, "expected lane specifier '[1]'");
+ case Match_InvalidIndexRange0_15:
+ return Error(Loc, "vector lane must be an integer in range [0, 15].");
+ case Match_InvalidIndexRange0_7:
+ return Error(Loc, "vector lane must be an integer in range [0, 7].");
+ case Match_InvalidIndexRange0_3:
+ return Error(Loc, "vector lane must be an integer in range [0, 3].");
+ case Match_InvalidIndexRange0_1:
+ return Error(Loc, "vector lane must be an integer in range [0, 1].");
+ case Match_InvalidSVEIndexRange0_63:
+ return Error(Loc, "vector lane must be an integer in range [0, 63].");
+ case Match_InvalidSVEIndexRange0_31:
+ return Error(Loc, "vector lane must be an integer in range [0, 31].");
+ case Match_InvalidSVEIndexRange0_15:
+ return Error(Loc, "vector lane must be an integer in range [0, 15].");
+ case Match_InvalidSVEIndexRange0_7:
+ return Error(Loc, "vector lane must be an integer in range [0, 7].");
+ case Match_InvalidSVEIndexRange0_3:
+ return Error(Loc, "vector lane must be an integer in range [0, 3].");
+ case Match_InvalidLabel:
+ return Error(Loc, "expected label or encodable integer pc offset");
+ case Match_MRS:
+ return Error(Loc, "expected readable system register");
+ case Match_MSR:
+ return Error(Loc, "expected writable system register or pstate");
+ case Match_InvalidComplexRotationEven:
+ return Error(Loc, "complex rotation must be 0, 90, 180 or 270.");
+ case Match_InvalidComplexRotationOdd:
+ return Error(Loc, "complex rotation must be 90 or 270.");
+ case Match_MnemonicFail: {
+ std::string Suggestion = AArch64MnemonicSpellCheck(
+ ((AArch64Operand &)*Operands[0]).getToken(),
+ ComputeAvailableFeatures(STI->getFeatureBits()));
+ return Error(Loc, "unrecognized instruction mnemonic" + Suggestion);
+ }
+ case Match_InvalidGPR64shifted8:
+ return Error(Loc, "register must be x0..x30 or xzr, without shift");
+ case Match_InvalidGPR64shifted16:
+ return Error(Loc, "register must be x0..x30 or xzr, with required shift 'lsl #1'");
+ case Match_InvalidGPR64shifted32:
+ return Error(Loc, "register must be x0..x30 or xzr, with required shift 'lsl #2'");
+ case Match_InvalidGPR64shifted64:
+ return Error(Loc, "register must be x0..x30 or xzr, with required shift 'lsl #3'");
+ case Match_InvalidGPR64NoXZRshifted8:
+ return Error(Loc, "register must be x0..x30 without shift");
+ case Match_InvalidGPR64NoXZRshifted16:
+ return Error(Loc, "register must be x0..x30 with required shift 'lsl #1'");
+ case Match_InvalidGPR64NoXZRshifted32:
+ return Error(Loc, "register must be x0..x30 with required shift 'lsl #2'");
+ case Match_InvalidGPR64NoXZRshifted64:
+ return Error(Loc, "register must be x0..x30 with required shift 'lsl #3'");
+ case Match_InvalidZPR32UXTW8:
+ case Match_InvalidZPR32SXTW8:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, (uxtw|sxtw)'");
+ case Match_InvalidZPR32UXTW16:
+ case Match_InvalidZPR32SXTW16:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, (uxtw|sxtw) #1'");
+ case Match_InvalidZPR32UXTW32:
+ case Match_InvalidZPR32SXTW32:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, (uxtw|sxtw) #2'");
+ case Match_InvalidZPR32UXTW64:
+ case Match_InvalidZPR32SXTW64:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, (uxtw|sxtw) #3'");
+ case Match_InvalidZPR64UXTW8:
+ case Match_InvalidZPR64SXTW8:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, (uxtw|sxtw)'");
+ case Match_InvalidZPR64UXTW16:
+ case Match_InvalidZPR64SXTW16:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, (lsl|uxtw|sxtw) #1'");
+ case Match_InvalidZPR64UXTW32:
+ case Match_InvalidZPR64SXTW32:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, (lsl|uxtw|sxtw) #2'");
+ case Match_InvalidZPR64UXTW64:
+ case Match_InvalidZPR64SXTW64:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, (lsl|uxtw|sxtw) #3'");
+ case Match_InvalidZPR32LSL8:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s'");
+ case Match_InvalidZPR32LSL16:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, lsl #1'");
+ case Match_InvalidZPR32LSL32:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, lsl #2'");
+ case Match_InvalidZPR32LSL64:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].s, lsl #3'");
+ case Match_InvalidZPR64LSL8:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d'");
+ case Match_InvalidZPR64LSL16:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, lsl #1'");
+ case Match_InvalidZPR64LSL32:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, lsl #2'");
+ case Match_InvalidZPR64LSL64:
+ return Error(Loc, "invalid shift/extend specified, expected 'z[0..31].d, lsl #3'");
+ case Match_InvalidZPR0:
+ return Error(Loc, "expected register without element width suffix");
+ case Match_InvalidZPR8:
+ case Match_InvalidZPR16:
+ case Match_InvalidZPR32:
+ case Match_InvalidZPR64:
+ case Match_InvalidZPR128:
+ return Error(Loc, "invalid element width");
+ case Match_InvalidZPR_3b8:
+ return Error(Loc, "Invalid restricted vector register, expected z0.b..z7.b");
+ case Match_InvalidZPR_3b16:
+ return Error(Loc, "Invalid restricted vector register, expected z0.h..z7.h");
+ case Match_InvalidZPR_3b32:
+ return Error(Loc, "Invalid restricted vector register, expected z0.s..z7.s");
+ case Match_InvalidZPR_4b16:
+ return Error(Loc, "Invalid restricted vector register, expected z0.h..z15.h");
+ case Match_InvalidZPR_4b32:
+ return Error(Loc, "Invalid restricted vector register, expected z0.s..z15.s");
+ case Match_InvalidZPR_4b64:
+ return Error(Loc, "Invalid restricted vector register, expected z0.d..z15.d");
+ case Match_InvalidSVEPattern:
+ return Error(Loc, "invalid predicate pattern");
+ case Match_InvalidSVEPredicateAnyReg:
+ case Match_InvalidSVEPredicateBReg:
+ case Match_InvalidSVEPredicateHReg:
+ case Match_InvalidSVEPredicateSReg:
+ case Match_InvalidSVEPredicateDReg:
+ return Error(Loc, "invalid predicate register.");
+ case Match_InvalidSVEPredicate3bAnyReg:
+ return Error(Loc, "invalid restricted predicate register, expected p0..p7 (without element suffix)");
+ case Match_InvalidSVEPredicate3bBReg:
+ return Error(Loc, "invalid restricted predicate register, expected p0.b..p7.b");
+ case Match_InvalidSVEPredicate3bHReg:
+ return Error(Loc, "invalid restricted predicate register, expected p0.h..p7.h");
+ case Match_InvalidSVEPredicate3bSReg:
+ return Error(Loc, "invalid restricted predicate register, expected p0.s..p7.s");
+ case Match_InvalidSVEPredicate3bDReg:
+ return Error(Loc, "invalid restricted predicate register, expected p0.d..p7.d");
+ case Match_InvalidSVEExactFPImmOperandHalfOne:
+ return Error(Loc, "Invalid floating point constant, expected 0.5 or 1.0.");
+ case Match_InvalidSVEExactFPImmOperandHalfTwo:
+ return Error(Loc, "Invalid floating point constant, expected 0.5 or 2.0.");
+ case Match_InvalidSVEExactFPImmOperandZeroOne:
+ return Error(Loc, "Invalid floating point constant, expected 0.0 or 1.0.");
+ default:
+ llvm_unreachable("unexpected error code!");
+ }
+}
+
+static const char *getSubtargetFeatureName(uint64_t Val);
+
+bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+ OperandVector &Operands,
+ MCStreamer &Out,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) {
+ assert(!Operands.empty() && "Unexpect empty operand list!");
+ AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[0]);
+ assert(Op.isToken() && "Leading operand should always be a mnemonic!");
+
+ StringRef Tok = Op.getToken();
+ unsigned NumOperands = Operands.size();
+
+ if (NumOperands == 4 && Tok == "lsl") {
+ AArch64Operand &Op2 = static_cast<AArch64Operand &>(*Operands[2]);
+ AArch64Operand &Op3 = static_cast<AArch64Operand &>(*Operands[3]);
+ if (Op2.isScalarReg() && Op3.isImm()) {
+ const MCConstantExpr *Op3CE = dyn_cast<MCConstantExpr>(Op3.getImm());
+ if (Op3CE) {
+ uint64_t Op3Val = Op3CE->getValue();
+ uint64_t NewOp3Val = 0;
+ uint64_t NewOp4Val = 0;
+ if (AArch64MCRegisterClasses[AArch64::GPR32allRegClassID].contains(
+ Op2.getReg())) {
+ NewOp3Val = (32 - Op3Val) & 0x1f;
+ NewOp4Val = 31 - Op3Val;
+ } else {
+ NewOp3Val = (64 - Op3Val) & 0x3f;
+ NewOp4Val = 63 - Op3Val;
+ }
+
+ const MCExpr *NewOp3 = MCConstantExpr::create(NewOp3Val, getContext());
+ const MCExpr *NewOp4 = MCConstantExpr::create(NewOp4Val, getContext());
+
+ Operands[0] = AArch64Operand::CreateToken(
+ "ubfm", false, Op.getStartLoc(), getContext());
+ Operands.push_back(AArch64Operand::CreateImm(
+ NewOp4, Op3.getStartLoc(), Op3.getEndLoc(), getContext()));
+ Operands[3] = AArch64Operand::CreateImm(NewOp3, Op3.getStartLoc(),
+ Op3.getEndLoc(), getContext());
+ }
+ }
+ } else if (NumOperands == 4 && Tok == "bfc") {
+ // FIXME: Horrible hack to handle BFC->BFM alias.
+ AArch64Operand &Op1 = static_cast<AArch64Operand &>(*Operands[1]);
+ AArch64Operand LSBOp = static_cast<AArch64Operand &>(*Operands[2]);
+ AArch64Operand WidthOp = static_cast<AArch64Operand &>(*Operands[3]);
+
+ if (Op1.isScalarReg() && LSBOp.isImm() && WidthOp.isImm()) {
+ const MCConstantExpr *LSBCE = dyn_cast<MCConstantExpr>(LSBOp.getImm());
+ const MCConstantExpr *WidthCE = dyn_cast<MCConstantExpr>(WidthOp.getImm());
+
+ if (LSBCE && WidthCE) {
+ uint64_t LSB = LSBCE->getValue();
+ uint64_t Width = WidthCE->getValue();
+
+ uint64_t RegWidth = 0;
+ if (AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
+ Op1.getReg()))
+ RegWidth = 64;
+ else
+ RegWidth = 32;
+
+ if (LSB >= RegWidth)
+ return Error(LSBOp.getStartLoc(),
+ "expected integer in range [0, 31]");
+ if (Width < 1 || Width > RegWidth)
+ return Error(WidthOp.getStartLoc(),
+ "expected integer in range [1, 32]");
+
+ uint64_t ImmR = 0;
+ if (RegWidth == 32)
+ ImmR = (32 - LSB) & 0x1f;
+ else
+ ImmR = (64 - LSB) & 0x3f;
+
+ uint64_t ImmS = Width - 1;
+
+ if (ImmR != 0 && ImmS >= ImmR)
+ return Error(WidthOp.getStartLoc(),
+ "requested insert overflows register");
+
+ const MCExpr *ImmRExpr = MCConstantExpr::create(ImmR, getContext());
+ const MCExpr *ImmSExpr = MCConstantExpr::create(ImmS, getContext());
+ Operands[0] = AArch64Operand::CreateToken(
+ "bfm", false, Op.getStartLoc(), getContext());
+ Operands[2] = AArch64Operand::CreateReg(
+ RegWidth == 32 ? AArch64::WZR : AArch64::XZR, RegKind::Scalar,
+ SMLoc(), SMLoc(), getContext());
+ Operands[3] = AArch64Operand::CreateImm(
+ ImmRExpr, LSBOp.getStartLoc(), LSBOp.getEndLoc(), getContext());
+ Operands.emplace_back(
+ AArch64Operand::CreateImm(ImmSExpr, WidthOp.getStartLoc(),
+ WidthOp.getEndLoc(), getContext()));
+ }
+ }
+ } else if (NumOperands == 5) {
+ // FIXME: Horrible hack to handle the BFI -> BFM, SBFIZ->SBFM, and
+ // UBFIZ -> UBFM aliases.
+ if (Tok == "bfi" || Tok == "sbfiz" || Tok == "ubfiz") {
+ AArch64Operand &Op1 = static_cast<AArch64Operand &>(*Operands[1]);
+ AArch64Operand &Op3 = static_cast<AArch64Operand &>(*Operands[3]);
+ AArch64Operand &Op4 = static_cast<AArch64Operand &>(*Operands[4]);
+
+ if (Op1.isScalarReg() && Op3.isImm() && Op4.isImm()) {
+ const MCConstantExpr *Op3CE = dyn_cast<MCConstantExpr>(Op3.getImm());
+ const MCConstantExpr *Op4CE = dyn_cast<MCConstantExpr>(Op4.getImm());
+
+ if (Op3CE && Op4CE) {
+ uint64_t Op3Val = Op3CE->getValue();
+ uint64_t Op4Val = Op4CE->getValue();
+
+ uint64_t RegWidth = 0;
+ if (AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
+ Op1.getReg()))
+ RegWidth = 64;
+ else
+ RegWidth = 32;
+
+ if (Op3Val >= RegWidth)
+ return Error(Op3.getStartLoc(),
+ "expected integer in range [0, 31]");
+ if (Op4Val < 1 || Op4Val > RegWidth)
+ return Error(Op4.getStartLoc(),
+ "expected integer in range [1, 32]");
+
+ uint64_t NewOp3Val = 0;
+ if (RegWidth == 32)
+ NewOp3Val = (32 - Op3Val) & 0x1f;
+ else
+ NewOp3Val = (64 - Op3Val) & 0x3f;
+
+ uint64_t NewOp4Val = Op4Val - 1;
+
+ if (NewOp3Val != 0 && NewOp4Val >= NewOp3Val)
+ return Error(Op4.getStartLoc(),
+ "requested insert overflows register");
+
+ const MCExpr *NewOp3 =
+ MCConstantExpr::create(NewOp3Val, getContext());
+ const MCExpr *NewOp4 =
+ MCConstantExpr::create(NewOp4Val, getContext());
+ Operands[3] = AArch64Operand::CreateImm(
+ NewOp3, Op3.getStartLoc(), Op3.getEndLoc(), getContext());
+ Operands[4] = AArch64Operand::CreateImm(
+ NewOp4, Op4.getStartLoc(), Op4.getEndLoc(), getContext());
+ if (Tok == "bfi")
+ Operands[0] = AArch64Operand::CreateToken(
+ "bfm", false, Op.getStartLoc(), getContext());
+ else if (Tok == "sbfiz")
+ Operands[0] = AArch64Operand::CreateToken(
+ "sbfm", false, Op.getStartLoc(), getContext());
+ else if (Tok == "ubfiz")
+ Operands[0] = AArch64Operand::CreateToken(
+ "ubfm", false, Op.getStartLoc(), getContext());
+ else
+ llvm_unreachable("No valid mnemonic for alias?");
+ }
+ }
+
+ // FIXME: Horrible hack to handle the BFXIL->BFM, SBFX->SBFM, and
+ // UBFX -> UBFM aliases.
+ } else if (NumOperands == 5 &&
+ (Tok == "bfxil" || Tok == "sbfx" || Tok == "ubfx")) {
+ AArch64Operand &Op1 = static_cast<AArch64Operand &>(*Operands[1]);
+ AArch64Operand &Op3 = static_cast<AArch64Operand &>(*Operands[3]);
+ AArch64Operand &Op4 = static_cast<AArch64Operand &>(*Operands[4]);
+
+ if (Op1.isScalarReg() && Op3.isImm() && Op4.isImm()) {
+ const MCConstantExpr *Op3CE = dyn_cast<MCConstantExpr>(Op3.getImm());
+ const MCConstantExpr *Op4CE = dyn_cast<MCConstantExpr>(Op4.getImm());
+
+ if (Op3CE && Op4CE) {
+ uint64_t Op3Val = Op3CE->getValue();
+ uint64_t Op4Val = Op4CE->getValue();
+
+ uint64_t RegWidth = 0;
+ if (AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
+ Op1.getReg()))
+ RegWidth = 64;
+ else
+ RegWidth = 32;
+
+ if (Op3Val >= RegWidth)
+ return Error(Op3.getStartLoc(),
+ "expected integer in range [0, 31]");
+ if (Op4Val < 1 || Op4Val > RegWidth)
+ return Error(Op4.getStartLoc(),
+ "expected integer in range [1, 32]");
+
+ uint64_t NewOp4Val = Op3Val + Op4Val - 1;
+
+ if (NewOp4Val >= RegWidth || NewOp4Val < Op3Val)
+ return Error(Op4.getStartLoc(),
+ "requested extract overflows register");
+
+ const MCExpr *NewOp4 =
+ MCConstantExpr::create(NewOp4Val, getContext());
+ Operands[4] = AArch64Operand::CreateImm(
+ NewOp4, Op4.getStartLoc(), Op4.getEndLoc(), getContext());
+ if (Tok == "bfxil")
+ Operands[0] = AArch64Operand::CreateToken(
+ "bfm", false, Op.getStartLoc(), getContext());
+ else if (Tok == "sbfx")
+ Operands[0] = AArch64Operand::CreateToken(
+ "sbfm", false, Op.getStartLoc(), getContext());
+ else if (Tok == "ubfx")
+ Operands[0] = AArch64Operand::CreateToken(
+ "ubfm", false, Op.getStartLoc(), getContext());
+ else
+ llvm_unreachable("No valid mnemonic for alias?");
+ }
+ }
+ }
+ }
+
+ // The Cyclone CPU and early successors didn't execute the zero-cycle zeroing
+ // instruction for FP registers correctly in some rare circumstances. Convert
+ // it to a safe instruction and warn (because silently changing someone's
+ // assembly is rude).
+ if (getSTI().getFeatureBits()[AArch64::FeatureZCZeroingFPWorkaround] &&
+ NumOperands == 4 && Tok == "movi") {
+ AArch64Operand &Op1 = static_cast<AArch64Operand &>(*Operands[1]);
+ AArch64Operand &Op2 = static_cast<AArch64Operand &>(*Operands[2]);
+ AArch64Operand &Op3 = static_cast<AArch64Operand &>(*Operands[3]);
+ if ((Op1.isToken() && Op2.isNeonVectorReg() && Op3.isImm()) ||
+ (Op1.isNeonVectorReg() && Op2.isToken() && Op3.isImm())) {
+ StringRef Suffix = Op1.isToken() ? Op1.getToken() : Op2.getToken();
+ if (Suffix.lower() == ".2d" &&
+ cast<MCConstantExpr>(Op3.getImm())->getValue() == 0) {
+ Warning(IDLoc, "instruction movi.2d with immediate #0 may not function"
+ " correctly on this CPU, converting to equivalent movi.16b");
+ // Switch the suffix to .16b.
+ unsigned Idx = Op1.isToken() ? 1 : 2;
+ Operands[Idx] = AArch64Operand::CreateToken(".16b", false, IDLoc,
+ getContext());
+ }
+ }
+ }
+
+ // FIXME: Horrible hack for sxtw and uxtw with Wn src and Xd dst operands.
+ // InstAlias can't quite handle this since the reg classes aren't
+ // subclasses.
+ if (NumOperands == 3 && (Tok == "sxtw" || Tok == "uxtw")) {
+ // The source register can be Wn here, but the matcher expects a
+ // GPR64. Twiddle it here if necessary.
+ AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[2]);
+ if (Op.isScalarReg()) {
+ unsigned Reg = getXRegFromWReg(Op.getReg());
+ Operands[2] = AArch64Operand::CreateReg(Reg, RegKind::Scalar,
+ Op.getStartLoc(), Op.getEndLoc(),
+ getContext());
+ }
+ }
+ // FIXME: Likewise for sxt[bh] with a Xd dst operand
+ else if (NumOperands == 3 && (Tok == "sxtb" || Tok == "sxth")) {
+ AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[1]);
+ if (Op.isScalarReg() &&
+ AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
+ Op.getReg())) {
+ // The source register can be Wn here, but the matcher expects a
+ // GPR64. Twiddle it here if necessary.
+ AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[2]);
+ if (Op.isScalarReg()) {
+ unsigned Reg = getXRegFromWReg(Op.getReg());
+ Operands[2] = AArch64Operand::CreateReg(Reg, RegKind::Scalar,
+ Op.getStartLoc(),
+ Op.getEndLoc(), getContext());
+ }
+ }
+ }
+ // FIXME: Likewise for uxt[bh] with a Xd dst operand
+ else if (NumOperands == 3 && (Tok == "uxtb" || Tok == "uxth")) {
+ AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[1]);
+ if (Op.isScalarReg() &&
+ AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
+ Op.getReg())) {
+ // The source register can be Wn here, but the matcher expects a
+ // GPR32. Twiddle it here if necessary.
+ AArch64Operand &Op = static_cast<AArch64Operand &>(*Operands[1]);
+ if (Op.isScalarReg()) {
+ unsigned Reg = getWRegFromXReg(Op.getReg());
+ Operands[1] = AArch64Operand::CreateReg(Reg, RegKind::Scalar,
+ Op.getStartLoc(),
+ Op.getEndLoc(), getContext());
+ }
+ }
+ }
+
+ MCInst Inst;
+ FeatureBitset MissingFeatures;
+ // First try to match against the secondary set of tables containing the
+ // short-form NEON instructions (e.g. "fadd.2s v0, v1, v2").
+ unsigned MatchResult =
+ MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
+ MatchingInlineAsm, 1);
+
+ // If that fails, try against the alternate table containing long-form NEON:
+ // "fadd v0.2s, v1.2s, v2.2s"
+ if (MatchResult != Match_Success) {
+ // But first, save the short-form match result: we can use it in case the
+ // long-form match also fails.
+ auto ShortFormNEONErrorInfo = ErrorInfo;
+ auto ShortFormNEONMatchResult = MatchResult;
+ auto ShortFormNEONMissingFeatures = MissingFeatures;
+
+ MatchResult =
+ MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
+ MatchingInlineAsm, 0);
+
+ // Now, both matches failed, and the long-form match failed on the mnemonic
+ // suffix token operand. The short-form match failure is probably more
+ // relevant: use it instead.
+ if (MatchResult == Match_InvalidOperand && ErrorInfo == 1 &&
+ Operands.size() > 1 && ((AArch64Operand &)*Operands[1]).isToken() &&
+ ((AArch64Operand &)*Operands[1]).isTokenSuffix()) {
+ MatchResult = ShortFormNEONMatchResult;
+ ErrorInfo = ShortFormNEONErrorInfo;
+ MissingFeatures = ShortFormNEONMissingFeatures;
+ }
+ }
+
+ switch (MatchResult) {
+ case Match_Success: {
+ // Perform range checking and other semantic validations
+ SmallVector<SMLoc, 8> OperandLocs;
+ NumOperands = Operands.size();
+ for (unsigned i = 1; i < NumOperands; ++i)
+ OperandLocs.push_back(Operands[i]->getStartLoc());
+ if (validateInstruction(Inst, IDLoc, OperandLocs))
+ return true;
+
+ Inst.setLoc(IDLoc);
+ Out.emitInstruction(Inst, getSTI());
+ return false;
+ }
+ case Match_MissingFeature: {
+ assert(MissingFeatures.any() && "Unknown missing feature!");
+ // Special case the error message for the very common case where only
+ // a single subtarget feature is missing (neon, e.g.).
+ std::string Msg = "instruction requires:";
+ for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
+ if (MissingFeatures[i]) {
+ Msg += " ";
+ Msg += getSubtargetFeatureName(i);
+ }
+ }
+ return Error(IDLoc, Msg);
+ }
+ case Match_MnemonicFail:
+ return showMatchError(IDLoc, MatchResult, ErrorInfo, Operands);
+ case Match_InvalidOperand: {
+ SMLoc ErrorLoc = IDLoc;
+
+ if (ErrorInfo != ~0ULL) {
+ if (ErrorInfo >= Operands.size())
+ return Error(IDLoc, "too few operands for instruction",
+ SMRange(IDLoc, getTok().getLoc()));
+
+ ErrorLoc = ((AArch64Operand &)*Operands[ErrorInfo]).getStartLoc();
+ if (ErrorLoc == SMLoc())
+ ErrorLoc = IDLoc;
+ }
+ // If the match failed on a suffix token operand, tweak the diagnostic
+ // accordingly.
+ if (((AArch64Operand &)*Operands[ErrorInfo]).isToken() &&
+ ((AArch64Operand &)*Operands[ErrorInfo]).isTokenSuffix())
+ MatchResult = Match_InvalidSuffix;
+
+ return showMatchError(ErrorLoc, MatchResult, ErrorInfo, Operands);
+ }
+ case Match_InvalidTiedOperand:
+ case Match_InvalidMemoryIndexed1:
+ case Match_InvalidMemoryIndexed2:
+ case Match_InvalidMemoryIndexed4:
+ case Match_InvalidMemoryIndexed8:
+ case Match_InvalidMemoryIndexed16:
+ case Match_InvalidCondCode:
+ case Match_AddSubRegExtendSmall:
+ case Match_AddSubRegExtendLarge:
+ case Match_AddSubSecondSource:
+ case Match_LogicalSecondSource:
+ case Match_AddSubRegShift32:
+ case Match_AddSubRegShift64:
+ case Match_InvalidMovImm32Shift:
+ case Match_InvalidMovImm64Shift:
+ case Match_InvalidFPImm:
+ case Match_InvalidMemoryWExtend8:
+ case Match_InvalidMemoryWExtend16:
+ case Match_InvalidMemoryWExtend32:
+ case Match_InvalidMemoryWExtend64:
+ case Match_InvalidMemoryWExtend128:
+ case Match_InvalidMemoryXExtend8:
+ case Match_InvalidMemoryXExtend16:
+ case Match_InvalidMemoryXExtend32:
+ case Match_InvalidMemoryXExtend64:
+ case Match_InvalidMemoryXExtend128:
+ case Match_InvalidMemoryIndexed1SImm4:
+ case Match_InvalidMemoryIndexed2SImm4:
+ case Match_InvalidMemoryIndexed3SImm4:
+ case Match_InvalidMemoryIndexed4SImm4:
+ case Match_InvalidMemoryIndexed1SImm6:
+ case Match_InvalidMemoryIndexed16SImm4:
+ case Match_InvalidMemoryIndexed32SImm4:
+ case Match_InvalidMemoryIndexed4SImm7:
+ case Match_InvalidMemoryIndexed8SImm7:
+ case Match_InvalidMemoryIndexed16SImm7:
+ case Match_InvalidMemoryIndexed8UImm5:
+ case Match_InvalidMemoryIndexed4UImm5:
+ case Match_InvalidMemoryIndexed2UImm5:
+ case Match_InvalidMemoryIndexed1UImm6:
+ case Match_InvalidMemoryIndexed2UImm6:
+ case Match_InvalidMemoryIndexed4UImm6:
+ case Match_InvalidMemoryIndexed8UImm6:
+ case Match_InvalidMemoryIndexed16UImm6:
+ case Match_InvalidMemoryIndexedSImm6:
+ case Match_InvalidMemoryIndexedSImm5:
+ case Match_InvalidMemoryIndexedSImm8:
+ case Match_InvalidMemoryIndexedSImm9:
+ case Match_InvalidMemoryIndexed16SImm9:
+ case Match_InvalidMemoryIndexed8SImm10:
+ case Match_InvalidImm0_1:
+ case Match_InvalidImm0_7:
+ case Match_InvalidImm0_15:
+ case Match_InvalidImm0_31:
+ case Match_InvalidImm0_63:
+ case Match_InvalidImm0_127:
+ case Match_InvalidImm0_255:
+ case Match_InvalidImm0_65535:
+ case Match_InvalidImm1_8:
+ case Match_InvalidImm1_16:
+ case Match_InvalidImm1_32:
+ case Match_InvalidImm1_64:
+ case Match_InvalidSVEAddSubImm8:
+ case Match_InvalidSVEAddSubImm16:
+ case Match_InvalidSVEAddSubImm32:
+ case Match_InvalidSVEAddSubImm64:
+ case Match_InvalidSVECpyImm8:
+ case Match_InvalidSVECpyImm16:
+ case Match_InvalidSVECpyImm32:
+ case Match_InvalidSVECpyImm64:
+ case Match_InvalidIndexRange1_1:
+ case Match_InvalidIndexRange0_15:
+ case Match_InvalidIndexRange0_7:
+ case Match_InvalidIndexRange0_3:
+ case Match_InvalidIndexRange0_1:
+ case Match_InvalidSVEIndexRange0_63:
+ case Match_InvalidSVEIndexRange0_31:
+ case Match_InvalidSVEIndexRange0_15:
+ case Match_InvalidSVEIndexRange0_7:
+ case Match_InvalidSVEIndexRange0_3:
+ case Match_InvalidLabel:
+ case Match_InvalidComplexRotationEven:
+ case Match_InvalidComplexRotationOdd:
+ case Match_InvalidGPR64shifted8:
+ case Match_InvalidGPR64shifted16:
+ case Match_InvalidGPR64shifted32:
+ case Match_InvalidGPR64shifted64:
+ case Match_InvalidGPR64NoXZRshifted8:
+ case Match_InvalidGPR64NoXZRshifted16:
+ case Match_InvalidGPR64NoXZRshifted32:
+ case Match_InvalidGPR64NoXZRshifted64:
+ case Match_InvalidZPR32UXTW8:
+ case Match_InvalidZPR32UXTW16:
+ case Match_InvalidZPR32UXTW32:
+ case Match_InvalidZPR32UXTW64:
+ case Match_InvalidZPR32SXTW8:
+ case Match_InvalidZPR32SXTW16:
+ case Match_InvalidZPR32SXTW32:
+ case Match_InvalidZPR32SXTW64:
+ case Match_InvalidZPR64UXTW8:
+ case Match_InvalidZPR64SXTW8:
+ case Match_InvalidZPR64UXTW16:
+ case Match_InvalidZPR64SXTW16:
+ case Match_InvalidZPR64UXTW32:
+ case Match_InvalidZPR64SXTW32:
+ case Match_InvalidZPR64UXTW64:
+ case Match_InvalidZPR64SXTW64:
+ case Match_InvalidZPR32LSL8:
+ case Match_InvalidZPR32LSL16:
+ case Match_InvalidZPR32LSL32:
+ case Match_InvalidZPR32LSL64:
+ case Match_InvalidZPR64LSL8:
+ case Match_InvalidZPR64LSL16:
+ case Match_InvalidZPR64LSL32:
+ case Match_InvalidZPR64LSL64:
+ case Match_InvalidZPR0:
+ case Match_InvalidZPR8:
+ case Match_InvalidZPR16:
+ case Match_InvalidZPR32:
+ case Match_InvalidZPR64:
+ case Match_InvalidZPR128:
+ case Match_InvalidZPR_3b8:
+ case Match_InvalidZPR_3b16:
+ case Match_InvalidZPR_3b32:
+ case Match_InvalidZPR_4b16:
+ case Match_InvalidZPR_4b32:
+ case Match_InvalidZPR_4b64:
+ case Match_InvalidSVEPredicateAnyReg:
+ case Match_InvalidSVEPattern:
+ case Match_InvalidSVEPredicateBReg:
+ case Match_InvalidSVEPredicateHReg:
+ case Match_InvalidSVEPredicateSReg:
+ case Match_InvalidSVEPredicateDReg:
+ case Match_InvalidSVEPredicate3bAnyReg:
+ case Match_InvalidSVEPredicate3bBReg:
+ case Match_InvalidSVEPredicate3bHReg:
+ case Match_InvalidSVEPredicate3bSReg:
+ case Match_InvalidSVEPredicate3bDReg:
+ case Match_InvalidSVEExactFPImmOperandHalfOne:
+ case Match_InvalidSVEExactFPImmOperandHalfTwo:
+ case Match_InvalidSVEExactFPImmOperandZeroOne:
+ case Match_MSR:
+ case Match_MRS: {
+ if (ErrorInfo >= Operands.size())
+ return Error(IDLoc, "too few operands for instruction", SMRange(IDLoc, (*Operands.back()).getEndLoc()));
+ // Any time we get here, there's nothing fancy to do. Just get the
+ // operand SMLoc and display the diagnostic.
+ SMLoc ErrorLoc = ((AArch64Operand &)*Operands[ErrorInfo]).getStartLoc();
+ if (ErrorLoc == SMLoc())
+ ErrorLoc = IDLoc;
+ return showMatchError(ErrorLoc, MatchResult, ErrorInfo, Operands);
+ }
+ }
+
+ llvm_unreachable("Implement any new match types added!");
+}
+
+/// ParseDirective parses the arm specific directives
+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();
- if (IDVal == ".arch")
- parseDirectiveArch(Loc);
- else if (IDVal == ".cpu")
- parseDirectiveCPU(Loc);
- else if (IDVal == ".tlsdesccall")
- parseDirectiveTLSDescCall(Loc);
- else if (IDVal == ".ltorg" || IDVal == ".pool")
- parseDirectiveLtorg(Loc);
- else if (IDVal == ".unreq")
- parseDirectiveUnreq(Loc);
- else if (IDVal == ".inst")
- parseDirectiveInst(Loc);
- else if (IDVal == ".cfi_negate_ra_state")
- parseDirectiveCFINegateRAState();
- else if (IDVal == ".cfi_b_key_frame")
- parseDirectiveCFIBKeyFrame();
- else if (IDVal == ".arch_extension")
- parseDirectiveArchExtension(Loc);
- else if (IDVal == ".variant_pcs")
- parseDirectiveVariantPCS(Loc);
- else if (IsMachO) {
- if (IDVal == MCLOHDirectiveName())
- parseDirectiveLOH(IDVal, Loc);
- else
- return true;
+
+ auto IDVal = DirectiveID.getIdentifier().lower();
+ SMLoc Loc = DirectiveID.getLoc();
+ if (IDVal == ".arch")
+ parseDirectiveArch(Loc);
+ else if (IDVal == ".cpu")
+ parseDirectiveCPU(Loc);
+ else if (IDVal == ".tlsdesccall")
+ parseDirectiveTLSDescCall(Loc);
+ else if (IDVal == ".ltorg" || IDVal == ".pool")
+ parseDirectiveLtorg(Loc);
+ else if (IDVal == ".unreq")
+ parseDirectiveUnreq(Loc);
+ else if (IDVal == ".inst")
+ parseDirectiveInst(Loc);
+ else if (IDVal == ".cfi_negate_ra_state")
+ parseDirectiveCFINegateRAState();
+ else if (IDVal == ".cfi_b_key_frame")
+ parseDirectiveCFIBKeyFrame();
+ else if (IDVal == ".arch_extension")
+ parseDirectiveArchExtension(Loc);
+ else if (IDVal == ".variant_pcs")
+ parseDirectiveVariantPCS(Loc);
+ else if (IsMachO) {
+ if (IDVal == MCLOHDirectiveName())
+ parseDirectiveLOH(IDVal, Loc);
+ else
+ return true;
} else if (IsCOFF) {
if (IDVal == ".seh_stackalloc")
parseDirectiveSEHAllocStack(Loc);
@@ -5353,457 +5353,457 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
parseDirectiveSEHClearUnwoundToCall(Loc);
else
return true;
- } else
- return true;
- return false;
-}
-
-static void ExpandCryptoAEK(AArch64::ArchKind ArchKind,
- SmallVector<StringRef, 4> &RequestedExtensions) {
+ } else
+ return true;
+ return false;
+}
+
+static void ExpandCryptoAEK(AArch64::ArchKind ArchKind,
+ SmallVector<StringRef, 4> &RequestedExtensions) {
const bool NoCrypto = llvm::is_contained(RequestedExtensions, "nocrypto");
const bool Crypto = llvm::is_contained(RequestedExtensions, "crypto");
-
- if (!NoCrypto && Crypto) {
- switch (ArchKind) {
- default:
- // Map 'generic' (and others) to sha2 and aes, because
- // that was the traditional meaning of crypto.
- case AArch64::ArchKind::ARMV8_1A:
- case AArch64::ArchKind::ARMV8_2A:
- case AArch64::ArchKind::ARMV8_3A:
- RequestedExtensions.push_back("sha2");
- RequestedExtensions.push_back("aes");
- break;
- case AArch64::ArchKind::ARMV8_4A:
- case AArch64::ArchKind::ARMV8_5A:
- case AArch64::ArchKind::ARMV8_6A:
+
+ if (!NoCrypto && Crypto) {
+ switch (ArchKind) {
+ default:
+ // Map 'generic' (and others) to sha2 and aes, because
+ // that was the traditional meaning of crypto.
+ case AArch64::ArchKind::ARMV8_1A:
+ case AArch64::ArchKind::ARMV8_2A:
+ case AArch64::ArchKind::ARMV8_3A:
+ RequestedExtensions.push_back("sha2");
+ RequestedExtensions.push_back("aes");
+ break;
+ 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");
- RequestedExtensions.push_back("aes");
- break;
- }
- } else if (NoCrypto) {
- switch (ArchKind) {
- default:
- // Map 'generic' (and others) to sha2 and aes, because
- // that was the traditional meaning of crypto.
- case AArch64::ArchKind::ARMV8_1A:
- case AArch64::ArchKind::ARMV8_2A:
- case AArch64::ArchKind::ARMV8_3A:
- RequestedExtensions.push_back("nosha2");
- RequestedExtensions.push_back("noaes");
- break;
- case AArch64::ArchKind::ARMV8_4A:
- case AArch64::ArchKind::ARMV8_5A:
- case AArch64::ArchKind::ARMV8_6A:
+ RequestedExtensions.push_back("sm4");
+ RequestedExtensions.push_back("sha3");
+ RequestedExtensions.push_back("sha2");
+ RequestedExtensions.push_back("aes");
+ break;
+ }
+ } else if (NoCrypto) {
+ switch (ArchKind) {
+ default:
+ // Map 'generic' (and others) to sha2 and aes, because
+ // that was the traditional meaning of crypto.
+ case AArch64::ArchKind::ARMV8_1A:
+ case AArch64::ArchKind::ARMV8_2A:
+ case AArch64::ArchKind::ARMV8_3A:
+ RequestedExtensions.push_back("nosha2");
+ RequestedExtensions.push_back("noaes");
+ break;
+ 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");
- RequestedExtensions.push_back("noaes");
- break;
- }
- }
-}
-
-/// parseDirectiveArch
-/// ::= .arch token
-bool AArch64AsmParser::parseDirectiveArch(SMLoc L) {
- SMLoc ArchLoc = getLoc();
-
- StringRef Arch, ExtensionString;
- std::tie(Arch, ExtensionString) =
- getParser().parseStringToEndOfStatement().trim().split('+');
-
- AArch64::ArchKind ID = AArch64::parseArch(Arch);
- if (ID == AArch64::ArchKind::INVALID)
- return Error(ArchLoc, "unknown arch name");
-
- if (parseToken(AsmToken::EndOfStatement))
- return true;
-
- // Get the architecture and extension features.
- std::vector<StringRef> AArch64Features;
- AArch64::getArchFeatures(ID, AArch64Features);
- AArch64::getExtensionFeatures(AArch64::getDefaultExtensions("generic", ID),
- AArch64Features);
-
- MCSubtargetInfo &STI = copySTI();
- std::vector<std::string> ArchFeatures(AArch64Features.begin(), AArch64Features.end());
+ RequestedExtensions.push_back("nosm4");
+ RequestedExtensions.push_back("nosha3");
+ RequestedExtensions.push_back("nosha2");
+ RequestedExtensions.push_back("noaes");
+ break;
+ }
+ }
+}
+
+/// parseDirectiveArch
+/// ::= .arch token
+bool AArch64AsmParser::parseDirectiveArch(SMLoc L) {
+ SMLoc ArchLoc = getLoc();
+
+ StringRef Arch, ExtensionString;
+ std::tie(Arch, ExtensionString) =
+ getParser().parseStringToEndOfStatement().trim().split('+');
+
+ AArch64::ArchKind ID = AArch64::parseArch(Arch);
+ if (ID == AArch64::ArchKind::INVALID)
+ return Error(ArchLoc, "unknown arch name");
+
+ if (parseToken(AsmToken::EndOfStatement))
+ return true;
+
+ // Get the architecture and extension features.
+ std::vector<StringRef> AArch64Features;
+ AArch64::getArchFeatures(ID, AArch64Features);
+ AArch64::getExtensionFeatures(AArch64::getDefaultExtensions("generic", ID),
+ AArch64Features);
+
+ MCSubtargetInfo &STI = copySTI();
+ std::vector<std::string> ArchFeatures(AArch64Features.begin(), AArch64Features.end());
STI.setDefaultFeatures("generic", /*TuneCPU*/ "generic",
join(ArchFeatures.begin(), ArchFeatures.end(), ","));
-
- SmallVector<StringRef, 4> RequestedExtensions;
- if (!ExtensionString.empty())
- ExtensionString.split(RequestedExtensions, '+');
-
- ExpandCryptoAEK(ID, RequestedExtensions);
-
- FeatureBitset Features = STI.getFeatureBits();
- for (auto Name : RequestedExtensions) {
- bool EnableFeature = true;
-
- if (Name.startswith_lower("no")) {
- EnableFeature = false;
- Name = Name.substr(2);
- }
-
- for (const auto &Extension : ExtensionMap) {
- if (Extension.Name != Name)
- continue;
-
- if (Extension.Features.none())
- report_fatal_error("unsupported architectural extension: " + Name);
-
- FeatureBitset ToggleFeatures = EnableFeature
- ? (~Features & Extension.Features)
- : ( Features & Extension.Features);
- FeatureBitset Features =
- ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
- setAvailableFeatures(Features);
- break;
- }
- }
- return false;
-}
-
-/// parseDirectiveArchExtension
-/// ::= .arch_extension [no]feature
-bool AArch64AsmParser::parseDirectiveArchExtension(SMLoc L) {
- SMLoc ExtLoc = getLoc();
-
- StringRef Name = getParser().parseStringToEndOfStatement().trim();
-
- if (parseToken(AsmToken::EndOfStatement,
- "unexpected token in '.arch_extension' directive"))
- return true;
-
- bool EnableFeature = true;
- if (Name.startswith_lower("no")) {
- EnableFeature = false;
- Name = Name.substr(2);
- }
-
- MCSubtargetInfo &STI = copySTI();
- FeatureBitset Features = STI.getFeatureBits();
- for (const auto &Extension : ExtensionMap) {
- if (Extension.Name != Name)
- continue;
-
- if (Extension.Features.none())
- return Error(ExtLoc, "unsupported architectural extension: " + Name);
-
- FeatureBitset ToggleFeatures = EnableFeature
- ? (~Features & Extension.Features)
- : (Features & Extension.Features);
- FeatureBitset Features =
- ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
- setAvailableFeatures(Features);
- return false;
- }
-
- return Error(ExtLoc, "unknown architectural extension: " + Name);
-}
-
-static SMLoc incrementLoc(SMLoc L, int Offset) {
- return SMLoc::getFromPointer(L.getPointer() + Offset);
-}
-
-/// parseDirectiveCPU
-/// ::= .cpu id
-bool AArch64AsmParser::parseDirectiveCPU(SMLoc L) {
- SMLoc CurLoc = getLoc();
-
- StringRef CPU, ExtensionString;
- std::tie(CPU, ExtensionString) =
- getParser().parseStringToEndOfStatement().trim().split('+');
-
- if (parseToken(AsmToken::EndOfStatement))
- return true;
-
- SmallVector<StringRef, 4> RequestedExtensions;
- if (!ExtensionString.empty())
- ExtensionString.split(RequestedExtensions, '+');
-
- // FIXME This is using tablegen data, but should be moved to ARMTargetParser
- // once that is tablegen'ed
- if (!getSTI().isCPUStringValid(CPU)) {
- Error(CurLoc, "unknown CPU name");
- return false;
- }
-
- MCSubtargetInfo &STI = copySTI();
+
+ SmallVector<StringRef, 4> RequestedExtensions;
+ if (!ExtensionString.empty())
+ ExtensionString.split(RequestedExtensions, '+');
+
+ ExpandCryptoAEK(ID, RequestedExtensions);
+
+ FeatureBitset Features = STI.getFeatureBits();
+ for (auto Name : RequestedExtensions) {
+ bool EnableFeature = true;
+
+ if (Name.startswith_lower("no")) {
+ EnableFeature = false;
+ Name = Name.substr(2);
+ }
+
+ for (const auto &Extension : ExtensionMap) {
+ if (Extension.Name != Name)
+ continue;
+
+ if (Extension.Features.none())
+ report_fatal_error("unsupported architectural extension: " + Name);
+
+ FeatureBitset ToggleFeatures = EnableFeature
+ ? (~Features & Extension.Features)
+ : ( Features & Extension.Features);
+ FeatureBitset Features =
+ ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
+ setAvailableFeatures(Features);
+ break;
+ }
+ }
+ return false;
+}
+
+/// parseDirectiveArchExtension
+/// ::= .arch_extension [no]feature
+bool AArch64AsmParser::parseDirectiveArchExtension(SMLoc L) {
+ SMLoc ExtLoc = getLoc();
+
+ StringRef Name = getParser().parseStringToEndOfStatement().trim();
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.arch_extension' directive"))
+ return true;
+
+ bool EnableFeature = true;
+ if (Name.startswith_lower("no")) {
+ EnableFeature = false;
+ Name = Name.substr(2);
+ }
+
+ MCSubtargetInfo &STI = copySTI();
+ FeatureBitset Features = STI.getFeatureBits();
+ for (const auto &Extension : ExtensionMap) {
+ if (Extension.Name != Name)
+ continue;
+
+ if (Extension.Features.none())
+ return Error(ExtLoc, "unsupported architectural extension: " + Name);
+
+ FeatureBitset ToggleFeatures = EnableFeature
+ ? (~Features & Extension.Features)
+ : (Features & Extension.Features);
+ FeatureBitset Features =
+ ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
+ setAvailableFeatures(Features);
+ return false;
+ }
+
+ return Error(ExtLoc, "unknown architectural extension: " + Name);
+}
+
+static SMLoc incrementLoc(SMLoc L, int Offset) {
+ return SMLoc::getFromPointer(L.getPointer() + Offset);
+}
+
+/// parseDirectiveCPU
+/// ::= .cpu id
+bool AArch64AsmParser::parseDirectiveCPU(SMLoc L) {
+ SMLoc CurLoc = getLoc();
+
+ StringRef CPU, ExtensionString;
+ std::tie(CPU, ExtensionString) =
+ getParser().parseStringToEndOfStatement().trim().split('+');
+
+ if (parseToken(AsmToken::EndOfStatement))
+ return true;
+
+ SmallVector<StringRef, 4> RequestedExtensions;
+ if (!ExtensionString.empty())
+ ExtensionString.split(RequestedExtensions, '+');
+
+ // FIXME This is using tablegen data, but should be moved to ARMTargetParser
+ // once that is tablegen'ed
+ if (!getSTI().isCPUStringValid(CPU)) {
+ Error(CurLoc, "unknown CPU name");
+ return false;
+ }
+
+ MCSubtargetInfo &STI = copySTI();
STI.setDefaultFeatures(CPU, /*TuneCPU*/ CPU, "");
- CurLoc = incrementLoc(CurLoc, CPU.size());
-
- ExpandCryptoAEK(llvm::AArch64::getCPUArchKind(CPU), RequestedExtensions);
-
- FeatureBitset Features = STI.getFeatureBits();
- for (auto Name : RequestedExtensions) {
- // Advance source location past '+'.
- CurLoc = incrementLoc(CurLoc, 1);
-
- bool EnableFeature = true;
-
- if (Name.startswith_lower("no")) {
- EnableFeature = false;
- Name = Name.substr(2);
- }
-
- bool FoundExtension = false;
- for (const auto &Extension : ExtensionMap) {
- if (Extension.Name != Name)
- continue;
-
- if (Extension.Features.none())
- report_fatal_error("unsupported architectural extension: " + Name);
-
- FeatureBitset ToggleFeatures = EnableFeature
- ? (~Features & Extension.Features)
- : ( Features & Extension.Features);
- FeatureBitset Features =
- ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
- setAvailableFeatures(Features);
- FoundExtension = true;
-
- break;
- }
-
- if (!FoundExtension)
- Error(CurLoc, "unsupported architectural extension");
-
- CurLoc = incrementLoc(CurLoc, Name.size());
- }
- return false;
-}
-
-/// parseDirectiveInst
-/// ::= .inst opcode [, ...]
-bool AArch64AsmParser::parseDirectiveInst(SMLoc Loc) {
- if (getLexer().is(AsmToken::EndOfStatement))
- return Error(Loc, "expected expression following '.inst' directive");
-
- auto parseOp = [&]() -> bool {
- SMLoc L = getLoc();
- const MCExpr *Expr = nullptr;
- 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;
- getTargetStreamer().emitInst(Value->getValue());
- return false;
- };
-
- if (parseMany(parseOp))
- return addErrorSuffix(" in '.inst' directive");
- return false;
-}
-
-// parseDirectiveTLSDescCall:
-// ::= .tlsdesccall symbol
-bool AArch64AsmParser::parseDirectiveTLSDescCall(SMLoc L) {
- StringRef Name;
- if (check(getParser().parseIdentifier(Name), L,
- "expected symbol after directive") ||
- parseToken(AsmToken::EndOfStatement))
- return true;
-
- MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
- const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext());
- Expr = AArch64MCExpr::create(Expr, AArch64MCExpr::VK_TLSDESC, getContext());
-
- MCInst Inst;
- Inst.setOpcode(AArch64::TLSDESCCALL);
- Inst.addOperand(MCOperand::createExpr(Expr));
-
- getParser().getStreamer().emitInstruction(Inst, getSTI());
- return false;
-}
-
-/// ::= .loh <lohName | lohId> label1, ..., labelN
-/// The number of arguments depends on the loh identifier.
-bool AArch64AsmParser::parseDirectiveLOH(StringRef IDVal, SMLoc Loc) {
- MCLOHType Kind;
- if (getParser().getTok().isNot(AsmToken::Identifier)) {
- if (getParser().getTok().isNot(AsmToken::Integer))
- return TokError("expected an identifier or a number in directive");
- // We successfully get a numeric value for the identifier.
- // Check if it is valid.
- int64_t Id = getParser().getTok().getIntVal();
- if (Id <= -1U && !isValidMCLOHType(Id))
- return TokError("invalid numeric identifier in directive");
- Kind = (MCLOHType)Id;
- } else {
- StringRef Name = getTok().getIdentifier();
- // We successfully parse an identifier.
- // Check if it is a recognized one.
- int Id = MCLOHNameToId(Name);
-
- if (Id == -1)
- return TokError("invalid identifier in directive");
- Kind = (MCLOHType)Id;
- }
- // Consume the identifier.
- Lex();
- // Get the number of arguments of this LOH.
- int NbArgs = MCLOHIdToNbArgs(Kind);
-
- assert(NbArgs != -1 && "Invalid number of arguments");
-
- SmallVector<MCSymbol *, 3> Args;
- for (int Idx = 0; Idx < NbArgs; ++Idx) {
- StringRef Name;
- if (getParser().parseIdentifier(Name))
- return TokError("expected identifier in directive");
- Args.push_back(getContext().getOrCreateSymbol(Name));
-
- if (Idx + 1 == NbArgs)
- break;
- if (parseToken(AsmToken::Comma,
- "unexpected token in '" + Twine(IDVal) + "' directive"))
- return true;
- }
- if (parseToken(AsmToken::EndOfStatement,
- "unexpected token in '" + Twine(IDVal) + "' directive"))
- return true;
-
- getStreamer().emitLOHDirective((MCLOHType)Kind, Args);
- return false;
-}
-
-/// parseDirectiveLtorg
-/// ::= .ltorg | .pool
-bool AArch64AsmParser::parseDirectiveLtorg(SMLoc L) {
- if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
- return true;
- getTargetStreamer().emitCurrentConstantPool();
- return false;
-}
-
-/// parseDirectiveReq
-/// ::= name .req registername
-bool AArch64AsmParser::parseDirectiveReq(StringRef Name, SMLoc L) {
- MCAsmParser &Parser = getParser();
- Parser.Lex(); // Eat the '.req' token.
- SMLoc SRegLoc = getLoc();
- RegKind RegisterKind = RegKind::Scalar;
- unsigned RegNum;
- OperandMatchResultTy ParseRes = tryParseScalarRegister(RegNum);
-
- if (ParseRes != MatchOperand_Success) {
- StringRef Kind;
- RegisterKind = RegKind::NeonVector;
- ParseRes = tryParseVectorRegister(RegNum, Kind, RegKind::NeonVector);
-
- if (ParseRes == MatchOperand_ParseFail)
- return true;
-
- if (ParseRes == MatchOperand_Success && !Kind.empty())
- return Error(SRegLoc, "vector register without type specifier expected");
- }
-
- if (ParseRes != MatchOperand_Success) {
- StringRef Kind;
- RegisterKind = RegKind::SVEDataVector;
- ParseRes =
- tryParseVectorRegister(RegNum, Kind, RegKind::SVEDataVector);
-
- if (ParseRes == MatchOperand_ParseFail)
- return true;
-
- if (ParseRes == MatchOperand_Success && !Kind.empty())
- return Error(SRegLoc,
- "sve vector register without type specifier expected");
- }
-
- if (ParseRes != MatchOperand_Success) {
- StringRef Kind;
- RegisterKind = RegKind::SVEPredicateVector;
- ParseRes = tryParseVectorRegister(RegNum, Kind, RegKind::SVEPredicateVector);
-
- if (ParseRes == MatchOperand_ParseFail)
- return true;
-
- if (ParseRes == MatchOperand_Success && !Kind.empty())
- return Error(SRegLoc,
- "sve predicate register without type specifier expected");
- }
-
- if (ParseRes != MatchOperand_Success)
- return Error(SRegLoc, "register name or alias expected");
-
- // Shouldn't be anything else.
- if (parseToken(AsmToken::EndOfStatement,
- "unexpected input in .req directive"))
- return true;
-
- auto pair = std::make_pair(RegisterKind, (unsigned) RegNum);
- if (RegisterReqs.insert(std::make_pair(Name, pair)).first->second != pair)
- Warning(L, "ignoring redefinition of register alias '" + Name + "'");
-
- return false;
-}
-
-/// parseDirectiveUneq
-/// ::= .unreq registername
-bool AArch64AsmParser::parseDirectiveUnreq(SMLoc L) {
- MCAsmParser &Parser = getParser();
- if (getTok().isNot(AsmToken::Identifier))
- return TokError("unexpected input in .unreq directive.");
- RegisterReqs.erase(Parser.getTok().getIdentifier().lower());
- Parser.Lex(); // Eat the identifier.
- if (parseToken(AsmToken::EndOfStatement))
- return addErrorSuffix("in '.unreq' directive");
- return false;
-}
-
-bool AArch64AsmParser::parseDirectiveCFINegateRAState() {
- if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
- return true;
- getStreamer().emitCFINegateRAState();
- return false;
-}
-
-/// parseDirectiveCFIBKeyFrame
-/// ::= .cfi_b_key
-bool AArch64AsmParser::parseDirectiveCFIBKeyFrame() {
- if (parseToken(AsmToken::EndOfStatement,
- "unexpected token in '.cfi_b_key_frame'"))
- return true;
- getStreamer().emitCFIBKeyFrame();
- return false;
-}
-
-/// parseDirectiveVariantPCS
-/// ::= .variant_pcs symbolname
-bool AArch64AsmParser::parseDirectiveVariantPCS(SMLoc L) {
- MCAsmParser &Parser = getParser();
-
- const AsmToken &Tok = Parser.getTok();
- if (Tok.isNot(AsmToken::Identifier))
- return TokError("expected symbol name");
-
- StringRef SymbolName = Tok.getIdentifier();
-
- MCSymbol *Sym = getContext().lookupSymbol(SymbolName);
- if (!Sym)
- return TokError("unknown symbol in '.variant_pcs' directive");
-
- Parser.Lex(); // Eat the symbol
-
- // Shouldn't be any more tokens
- if (parseToken(AsmToken::EndOfStatement))
- return addErrorSuffix(" in '.variant_pcs' directive");
-
- getTargetStreamer().emitDirectiveVariantPCS(Sym);
-
- return false;
-}
-
+ CurLoc = incrementLoc(CurLoc, CPU.size());
+
+ ExpandCryptoAEK(llvm::AArch64::getCPUArchKind(CPU), RequestedExtensions);
+
+ FeatureBitset Features = STI.getFeatureBits();
+ for (auto Name : RequestedExtensions) {
+ // Advance source location past '+'.
+ CurLoc = incrementLoc(CurLoc, 1);
+
+ bool EnableFeature = true;
+
+ if (Name.startswith_lower("no")) {
+ EnableFeature = false;
+ Name = Name.substr(2);
+ }
+
+ bool FoundExtension = false;
+ for (const auto &Extension : ExtensionMap) {
+ if (Extension.Name != Name)
+ continue;
+
+ if (Extension.Features.none())
+ report_fatal_error("unsupported architectural extension: " + Name);
+
+ FeatureBitset ToggleFeatures = EnableFeature
+ ? (~Features & Extension.Features)
+ : ( Features & Extension.Features);
+ FeatureBitset Features =
+ ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
+ setAvailableFeatures(Features);
+ FoundExtension = true;
+
+ break;
+ }
+
+ if (!FoundExtension)
+ Error(CurLoc, "unsupported architectural extension");
+
+ CurLoc = incrementLoc(CurLoc, Name.size());
+ }
+ return false;
+}
+
+/// parseDirectiveInst
+/// ::= .inst opcode [, ...]
+bool AArch64AsmParser::parseDirectiveInst(SMLoc Loc) {
+ if (getLexer().is(AsmToken::EndOfStatement))
+ return Error(Loc, "expected expression following '.inst' directive");
+
+ auto parseOp = [&]() -> bool {
+ SMLoc L = getLoc();
+ const MCExpr *Expr = nullptr;
+ 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;
+ getTargetStreamer().emitInst(Value->getValue());
+ return false;
+ };
+
+ if (parseMany(parseOp))
+ return addErrorSuffix(" in '.inst' directive");
+ return false;
+}
+
+// parseDirectiveTLSDescCall:
+// ::= .tlsdesccall symbol
+bool AArch64AsmParser::parseDirectiveTLSDescCall(SMLoc L) {
+ StringRef Name;
+ if (check(getParser().parseIdentifier(Name), L,
+ "expected symbol after directive") ||
+ parseToken(AsmToken::EndOfStatement))
+ return true;
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+ const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext());
+ Expr = AArch64MCExpr::create(Expr, AArch64MCExpr::VK_TLSDESC, getContext());
+
+ MCInst Inst;
+ Inst.setOpcode(AArch64::TLSDESCCALL);
+ Inst.addOperand(MCOperand::createExpr(Expr));
+
+ getParser().getStreamer().emitInstruction(Inst, getSTI());
+ return false;
+}
+
+/// ::= .loh <lohName | lohId> label1, ..., labelN
+/// The number of arguments depends on the loh identifier.
+bool AArch64AsmParser::parseDirectiveLOH(StringRef IDVal, SMLoc Loc) {
+ MCLOHType Kind;
+ if (getParser().getTok().isNot(AsmToken::Identifier)) {
+ if (getParser().getTok().isNot(AsmToken::Integer))
+ return TokError("expected an identifier or a number in directive");
+ // We successfully get a numeric value for the identifier.
+ // Check if it is valid.
+ int64_t Id = getParser().getTok().getIntVal();
+ if (Id <= -1U && !isValidMCLOHType(Id))
+ return TokError("invalid numeric identifier in directive");
+ Kind = (MCLOHType)Id;
+ } else {
+ StringRef Name = getTok().getIdentifier();
+ // We successfully parse an identifier.
+ // Check if it is a recognized one.
+ int Id = MCLOHNameToId(Name);
+
+ if (Id == -1)
+ return TokError("invalid identifier in directive");
+ Kind = (MCLOHType)Id;
+ }
+ // Consume the identifier.
+ Lex();
+ // Get the number of arguments of this LOH.
+ int NbArgs = MCLOHIdToNbArgs(Kind);
+
+ assert(NbArgs != -1 && "Invalid number of arguments");
+
+ SmallVector<MCSymbol *, 3> Args;
+ for (int Idx = 0; Idx < NbArgs; ++Idx) {
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+ Args.push_back(getContext().getOrCreateSymbol(Name));
+
+ if (Idx + 1 == NbArgs)
+ break;
+ if (parseToken(AsmToken::Comma,
+ "unexpected token in '" + Twine(IDVal) + "' directive"))
+ return true;
+ }
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '" + Twine(IDVal) + "' directive"))
+ return true;
+
+ getStreamer().emitLOHDirective((MCLOHType)Kind, Args);
+ return false;
+}
+
+/// parseDirectiveLtorg
+/// ::= .ltorg | .pool
+bool AArch64AsmParser::parseDirectiveLtorg(SMLoc L) {
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
+ return true;
+ getTargetStreamer().emitCurrentConstantPool();
+ return false;
+}
+
+/// parseDirectiveReq
+/// ::= name .req registername
+bool AArch64AsmParser::parseDirectiveReq(StringRef Name, SMLoc L) {
+ MCAsmParser &Parser = getParser();
+ Parser.Lex(); // Eat the '.req' token.
+ SMLoc SRegLoc = getLoc();
+ RegKind RegisterKind = RegKind::Scalar;
+ unsigned RegNum;
+ OperandMatchResultTy ParseRes = tryParseScalarRegister(RegNum);
+
+ if (ParseRes != MatchOperand_Success) {
+ StringRef Kind;
+ RegisterKind = RegKind::NeonVector;
+ ParseRes = tryParseVectorRegister(RegNum, Kind, RegKind::NeonVector);
+
+ if (ParseRes == MatchOperand_ParseFail)
+ return true;
+
+ if (ParseRes == MatchOperand_Success && !Kind.empty())
+ return Error(SRegLoc, "vector register without type specifier expected");
+ }
+
+ if (ParseRes != MatchOperand_Success) {
+ StringRef Kind;
+ RegisterKind = RegKind::SVEDataVector;
+ ParseRes =
+ tryParseVectorRegister(RegNum, Kind, RegKind::SVEDataVector);
+
+ if (ParseRes == MatchOperand_ParseFail)
+ return true;
+
+ if (ParseRes == MatchOperand_Success && !Kind.empty())
+ return Error(SRegLoc,
+ "sve vector register without type specifier expected");
+ }
+
+ if (ParseRes != MatchOperand_Success) {
+ StringRef Kind;
+ RegisterKind = RegKind::SVEPredicateVector;
+ ParseRes = tryParseVectorRegister(RegNum, Kind, RegKind::SVEPredicateVector);
+
+ if (ParseRes == MatchOperand_ParseFail)
+ return true;
+
+ if (ParseRes == MatchOperand_Success && !Kind.empty())
+ return Error(SRegLoc,
+ "sve predicate register without type specifier expected");
+ }
+
+ if (ParseRes != MatchOperand_Success)
+ return Error(SRegLoc, "register name or alias expected");
+
+ // Shouldn't be anything else.
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected input in .req directive"))
+ return true;
+
+ auto pair = std::make_pair(RegisterKind, (unsigned) RegNum);
+ if (RegisterReqs.insert(std::make_pair(Name, pair)).first->second != pair)
+ Warning(L, "ignoring redefinition of register alias '" + Name + "'");
+
+ return false;
+}
+
+/// parseDirectiveUneq
+/// ::= .unreq registername
+bool AArch64AsmParser::parseDirectiveUnreq(SMLoc L) {
+ MCAsmParser &Parser = getParser();
+ if (getTok().isNot(AsmToken::Identifier))
+ return TokError("unexpected input in .unreq directive.");
+ RegisterReqs.erase(Parser.getTok().getIdentifier().lower());
+ Parser.Lex(); // Eat the identifier.
+ if (parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix("in '.unreq' directive");
+ return false;
+}
+
+bool AArch64AsmParser::parseDirectiveCFINegateRAState() {
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
+ return true;
+ getStreamer().emitCFINegateRAState();
+ return false;
+}
+
+/// parseDirectiveCFIBKeyFrame
+/// ::= .cfi_b_key
+bool AArch64AsmParser::parseDirectiveCFIBKeyFrame() {
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.cfi_b_key_frame'"))
+ return true;
+ getStreamer().emitCFIBKeyFrame();
+ return false;
+}
+
+/// parseDirectiveVariantPCS
+/// ::= .variant_pcs symbolname
+bool AArch64AsmParser::parseDirectiveVariantPCS(SMLoc L) {
+ MCAsmParser &Parser = getParser();
+
+ const AsmToken &Tok = Parser.getTok();
+ if (Tok.isNot(AsmToken::Identifier))
+ return TokError("expected symbol name");
+
+ StringRef SymbolName = Tok.getIdentifier();
+
+ MCSymbol *Sym = getContext().lookupSymbol(SymbolName);
+ if (!Sym)
+ return TokError("unknown symbol in '.variant_pcs' directive");
+
+ Parser.Lex(); // Eat the symbol
+
+ // Shouldn't be any more tokens
+ if (parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(" in '.variant_pcs' directive");
+
+ getTargetStreamer().emitDirectiveVariantPCS(Sym);
+
+ return false;
+}
+
/// parseDirectiveSEHAllocStack
/// ::= .seh_stackalloc
bool AArch64AsmParser::parseDirectiveSEHAllocStack(SMLoc L) {
@@ -6036,293 +6036,293 @@ bool AArch64AsmParser::parseDirectiveSEHClearUnwoundToCall(SMLoc L) {
return false;
}
-bool
-AArch64AsmParser::classifySymbolRef(const MCExpr *Expr,
- AArch64MCExpr::VariantKind &ELFRefKind,
- MCSymbolRefExpr::VariantKind &DarwinRefKind,
- int64_t &Addend) {
- ELFRefKind = AArch64MCExpr::VK_INVALID;
- DarwinRefKind = MCSymbolRefExpr::VK_None;
- Addend = 0;
-
- if (const AArch64MCExpr *AE = dyn_cast<AArch64MCExpr>(Expr)) {
- ELFRefKind = AE->getKind();
- Expr = AE->getSubExpr();
- }
-
- const MCSymbolRefExpr *SE = dyn_cast<MCSymbolRefExpr>(Expr);
- if (SE) {
- // It's a simple symbol reference with no addend.
- DarwinRefKind = SE->getKind();
- return true;
- }
-
- // Check that it looks like a symbol + an addend
- MCValue Res;
- bool Relocatable = Expr->evaluateAsRelocatable(Res, nullptr, nullptr);
- if (!Relocatable || Res.getSymB())
- return false;
-
- // Treat expressions with an ELFRefKind (like ":abs_g1:3", or
- // ":abs_g1:x" where x is constant) as symbolic even if there is no symbol.
- if (!Res.getSymA() && ELFRefKind == AArch64MCExpr::VK_INVALID)
- return false;
-
- if (Res.getSymA())
- DarwinRefKind = Res.getSymA()->getKind();
- Addend = Res.getConstant();
-
- // It's some symbol reference + a constant addend, but really
- // shouldn't use both Darwin and ELF syntax.
- return ELFRefKind == AArch64MCExpr::VK_INVALID ||
- DarwinRefKind == MCSymbolRefExpr::VK_None;
-}
-
-/// Force static initialization.
-extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmParser() {
- RegisterMCAsmParser<AArch64AsmParser> X(getTheAArch64leTarget());
- RegisterMCAsmParser<AArch64AsmParser> Y(getTheAArch64beTarget());
- RegisterMCAsmParser<AArch64AsmParser> Z(getTheARM64Target());
- RegisterMCAsmParser<AArch64AsmParser> W(getTheARM64_32Target());
- RegisterMCAsmParser<AArch64AsmParser> V(getTheAArch64_32Target());
-}
-
-#define GET_REGISTER_MATCHER
-#define GET_SUBTARGET_FEATURE_NAME
-#define GET_MATCHER_IMPLEMENTATION
-#define GET_MNEMONIC_SPELL_CHECKER
-#include "AArch64GenAsmMatcher.inc"
-
-// Define this matcher function after the auto-generated include so we
-// have the match class enum definitions.
-unsigned AArch64AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
- unsigned Kind) {
- AArch64Operand &Op = static_cast<AArch64Operand &>(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.
- int64_t ExpectedVal;
- switch (Kind) {
- default:
- return Match_InvalidOperand;
- case MCK__HASH_0:
- ExpectedVal = 0;
- break;
- case MCK__HASH_1:
- ExpectedVal = 1;
- break;
- case MCK__HASH_12:
- ExpectedVal = 12;
- break;
- case MCK__HASH_16:
- ExpectedVal = 16;
- break;
- case MCK__HASH_2:
- ExpectedVal = 2;
- break;
- case MCK__HASH_24:
- ExpectedVal = 24;
- break;
- case MCK__HASH_3:
- ExpectedVal = 3;
- break;
- case MCK__HASH_32:
- ExpectedVal = 32;
- break;
- case MCK__HASH_4:
- ExpectedVal = 4;
- break;
- case MCK__HASH_48:
- ExpectedVal = 48;
- break;
- case MCK__HASH_6:
- ExpectedVal = 6;
- break;
- case MCK__HASH_64:
- ExpectedVal = 64;
- break;
- case MCK__HASH_8:
- ExpectedVal = 8;
- break;
- }
- if (!Op.isImm())
- return Match_InvalidOperand;
- const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op.getImm());
- if (!CE)
- return Match_InvalidOperand;
- if (CE->getValue() == ExpectedVal)
- return Match_Success;
- return Match_InvalidOperand;
-}
-
-OperandMatchResultTy
-AArch64AsmParser::tryParseGPRSeqPair(OperandVector &Operands) {
-
- SMLoc S = getLoc();
-
- if (getParser().getTok().isNot(AsmToken::Identifier)) {
- Error(S, "expected register");
- return MatchOperand_ParseFail;
- }
-
- unsigned FirstReg;
- OperandMatchResultTy Res = tryParseScalarRegister(FirstReg);
- if (Res != MatchOperand_Success)
- return MatchOperand_ParseFail;
-
- const MCRegisterClass &WRegClass =
- AArch64MCRegisterClasses[AArch64::GPR32RegClassID];
- const MCRegisterClass &XRegClass =
- AArch64MCRegisterClasses[AArch64::GPR64RegClassID];
-
- bool isXReg = XRegClass.contains(FirstReg),
- isWReg = WRegClass.contains(FirstReg);
- if (!isXReg && !isWReg) {
- Error(S, "expected first even register of a "
- "consecutive same-size even/odd register pair");
- return MatchOperand_ParseFail;
- }
-
- const MCRegisterInfo *RI = getContext().getRegisterInfo();
- unsigned FirstEncoding = RI->getEncodingValue(FirstReg);
-
- if (FirstEncoding & 0x1) {
- Error(S, "expected first even register of a "
- "consecutive same-size even/odd register pair");
- return MatchOperand_ParseFail;
- }
-
- if (getParser().getTok().isNot(AsmToken::Comma)) {
- Error(getLoc(), "expected comma");
- return MatchOperand_ParseFail;
- }
- // Eat the comma
- getParser().Lex();
-
- SMLoc E = getLoc();
- unsigned SecondReg;
- Res = tryParseScalarRegister(SecondReg);
- if (Res != MatchOperand_Success)
- return MatchOperand_ParseFail;
-
- if (RI->getEncodingValue(SecondReg) != FirstEncoding + 1 ||
- (isXReg && !XRegClass.contains(SecondReg)) ||
- (isWReg && !WRegClass.contains(SecondReg))) {
- Error(E,"expected second odd register of a "
- "consecutive same-size even/odd register pair");
- return MatchOperand_ParseFail;
- }
-
- unsigned Pair = 0;
- if (isXReg) {
- Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube64,
- &AArch64MCRegisterClasses[AArch64::XSeqPairsClassRegClassID]);
- } else {
- Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube32,
- &AArch64MCRegisterClasses[AArch64::WSeqPairsClassRegClassID]);
- }
-
- Operands.push_back(AArch64Operand::CreateReg(Pair, RegKind::Scalar, S,
- getLoc(), getContext()));
-
- return MatchOperand_Success;
-}
-
-template <bool ParseShiftExtend, bool ParseSuffix>
-OperandMatchResultTy
-AArch64AsmParser::tryParseSVEDataVector(OperandVector &Operands) {
- const SMLoc S = getLoc();
- // Check for a SVE vector register specifier first.
- unsigned RegNum;
- StringRef Kind;
-
- OperandMatchResultTy Res =
- tryParseVectorRegister(RegNum, Kind, RegKind::SVEDataVector);
-
- if (Res != MatchOperand_Success)
- return Res;
-
- if (ParseSuffix && Kind.empty())
- return MatchOperand_NoMatch;
-
- const auto &KindRes = parseVectorKind(Kind, RegKind::SVEDataVector);
- if (!KindRes)
- return MatchOperand_NoMatch;
-
- unsigned ElementWidth = KindRes->second;
-
- // No shift/extend is the default.
- if (!ParseShiftExtend || getParser().getTok().isNot(AsmToken::Comma)) {
- Operands.push_back(AArch64Operand::CreateVectorReg(
- RegNum, RegKind::SVEDataVector, ElementWidth, S, S, getContext()));
-
- OperandMatchResultTy Res = tryParseVectorIndex(Operands);
- if (Res == MatchOperand_ParseFail)
- return MatchOperand_ParseFail;
- return MatchOperand_Success;
- }
-
- // Eat the comma
- getParser().Lex();
-
- // Match the shift
- SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> ExtOpnd;
- Res = tryParseOptionalShiftExtend(ExtOpnd);
- if (Res != MatchOperand_Success)
- return Res;
-
- auto Ext = static_cast<AArch64Operand *>(ExtOpnd.back().get());
- Operands.push_back(AArch64Operand::CreateVectorReg(
- RegNum, RegKind::SVEDataVector, ElementWidth, S, Ext->getEndLoc(),
- getContext(), Ext->getShiftExtendType(), Ext->getShiftExtendAmount(),
- Ext->hasShiftExtendAmount()));
-
- return MatchOperand_Success;
-}
-
-OperandMatchResultTy
-AArch64AsmParser::tryParseSVEPattern(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
-
- SMLoc SS = getLoc();
- const AsmToken &TokE = Parser.getTok();
- bool IsHash = TokE.is(AsmToken::Hash);
-
- if (!IsHash && TokE.isNot(AsmToken::Identifier))
- return MatchOperand_NoMatch;
-
- int64_t Pattern;
- if (IsHash) {
- Parser.Lex(); // Eat hash
-
- // Parse the immediate operand.
- const MCExpr *ImmVal;
- SS = getLoc();
- if (Parser.parseExpression(ImmVal))
- return MatchOperand_ParseFail;
-
- auto *MCE = dyn_cast<MCConstantExpr>(ImmVal);
- if (!MCE)
- return MatchOperand_ParseFail;
-
- Pattern = MCE->getValue();
- } else {
- // Parse the pattern
- auto Pat = AArch64SVEPredPattern::lookupSVEPREDPATByName(TokE.getString());
- if (!Pat)
- return MatchOperand_NoMatch;
-
- Parser.Lex();
- Pattern = Pat->Encoding;
- assert(Pattern >= 0 && Pattern < 32);
- }
-
- Operands.push_back(
- AArch64Operand::CreateImm(MCConstantExpr::create(Pattern, getContext()),
- SS, getLoc(), getContext()));
-
- return MatchOperand_Success;
-}
+bool
+AArch64AsmParser::classifySymbolRef(const MCExpr *Expr,
+ AArch64MCExpr::VariantKind &ELFRefKind,
+ MCSymbolRefExpr::VariantKind &DarwinRefKind,
+ int64_t &Addend) {
+ ELFRefKind = AArch64MCExpr::VK_INVALID;
+ DarwinRefKind = MCSymbolRefExpr::VK_None;
+ Addend = 0;
+
+ if (const AArch64MCExpr *AE = dyn_cast<AArch64MCExpr>(Expr)) {
+ ELFRefKind = AE->getKind();
+ Expr = AE->getSubExpr();
+ }
+
+ const MCSymbolRefExpr *SE = dyn_cast<MCSymbolRefExpr>(Expr);
+ if (SE) {
+ // It's a simple symbol reference with no addend.
+ DarwinRefKind = SE->getKind();
+ return true;
+ }
+
+ // Check that it looks like a symbol + an addend
+ MCValue Res;
+ bool Relocatable = Expr->evaluateAsRelocatable(Res, nullptr, nullptr);
+ if (!Relocatable || Res.getSymB())
+ return false;
+
+ // Treat expressions with an ELFRefKind (like ":abs_g1:3", or
+ // ":abs_g1:x" where x is constant) as symbolic even if there is no symbol.
+ if (!Res.getSymA() && ELFRefKind == AArch64MCExpr::VK_INVALID)
+ return false;
+
+ if (Res.getSymA())
+ DarwinRefKind = Res.getSymA()->getKind();
+ Addend = Res.getConstant();
+
+ // It's some symbol reference + a constant addend, but really
+ // shouldn't use both Darwin and ELF syntax.
+ return ELFRefKind == AArch64MCExpr::VK_INVALID ||
+ DarwinRefKind == MCSymbolRefExpr::VK_None;
+}
+
+/// Force static initialization.
+extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmParser() {
+ RegisterMCAsmParser<AArch64AsmParser> X(getTheAArch64leTarget());
+ RegisterMCAsmParser<AArch64AsmParser> Y(getTheAArch64beTarget());
+ RegisterMCAsmParser<AArch64AsmParser> Z(getTheARM64Target());
+ RegisterMCAsmParser<AArch64AsmParser> W(getTheARM64_32Target());
+ RegisterMCAsmParser<AArch64AsmParser> V(getTheAArch64_32Target());
+}
+
+#define GET_REGISTER_MATCHER
+#define GET_SUBTARGET_FEATURE_NAME
+#define GET_MATCHER_IMPLEMENTATION
+#define GET_MNEMONIC_SPELL_CHECKER
+#include "AArch64GenAsmMatcher.inc"
+
+// Define this matcher function after the auto-generated include so we
+// have the match class enum definitions.
+unsigned AArch64AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
+ unsigned Kind) {
+ AArch64Operand &Op = static_cast<AArch64Operand &>(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.
+ int64_t ExpectedVal;
+ switch (Kind) {
+ default:
+ return Match_InvalidOperand;
+ case MCK__HASH_0:
+ ExpectedVal = 0;
+ break;
+ case MCK__HASH_1:
+ ExpectedVal = 1;
+ break;
+ case MCK__HASH_12:
+ ExpectedVal = 12;
+ break;
+ case MCK__HASH_16:
+ ExpectedVal = 16;
+ break;
+ case MCK__HASH_2:
+ ExpectedVal = 2;
+ break;
+ case MCK__HASH_24:
+ ExpectedVal = 24;
+ break;
+ case MCK__HASH_3:
+ ExpectedVal = 3;
+ break;
+ case MCK__HASH_32:
+ ExpectedVal = 32;
+ break;
+ case MCK__HASH_4:
+ ExpectedVal = 4;
+ break;
+ case MCK__HASH_48:
+ ExpectedVal = 48;
+ break;
+ case MCK__HASH_6:
+ ExpectedVal = 6;
+ break;
+ case MCK__HASH_64:
+ ExpectedVal = 64;
+ break;
+ case MCK__HASH_8:
+ ExpectedVal = 8;
+ break;
+ }
+ if (!Op.isImm())
+ return Match_InvalidOperand;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op.getImm());
+ if (!CE)
+ return Match_InvalidOperand;
+ if (CE->getValue() == ExpectedVal)
+ return Match_Success;
+ return Match_InvalidOperand;
+}
+
+OperandMatchResultTy
+AArch64AsmParser::tryParseGPRSeqPair(OperandVector &Operands) {
+
+ SMLoc S = getLoc();
+
+ if (getParser().getTok().isNot(AsmToken::Identifier)) {
+ Error(S, "expected register");
+ return MatchOperand_ParseFail;
+ }
+
+ unsigned FirstReg;
+ OperandMatchResultTy Res = tryParseScalarRegister(FirstReg);
+ if (Res != MatchOperand_Success)
+ return MatchOperand_ParseFail;
+
+ const MCRegisterClass &WRegClass =
+ AArch64MCRegisterClasses[AArch64::GPR32RegClassID];
+ const MCRegisterClass &XRegClass =
+ AArch64MCRegisterClasses[AArch64::GPR64RegClassID];
+
+ bool isXReg = XRegClass.contains(FirstReg),
+ isWReg = WRegClass.contains(FirstReg);
+ if (!isXReg && !isWReg) {
+ Error(S, "expected first even register of a "
+ "consecutive same-size even/odd register pair");
+ return MatchOperand_ParseFail;
+ }
+
+ const MCRegisterInfo *RI = getContext().getRegisterInfo();
+ unsigned FirstEncoding = RI->getEncodingValue(FirstReg);
+
+ if (FirstEncoding & 0x1) {
+ Error(S, "expected first even register of a "
+ "consecutive same-size even/odd register pair");
+ return MatchOperand_ParseFail;
+ }
+
+ if (getParser().getTok().isNot(AsmToken::Comma)) {
+ Error(getLoc(), "expected comma");
+ return MatchOperand_ParseFail;
+ }
+ // Eat the comma
+ getParser().Lex();
+
+ SMLoc E = getLoc();
+ unsigned SecondReg;
+ Res = tryParseScalarRegister(SecondReg);
+ if (Res != MatchOperand_Success)
+ return MatchOperand_ParseFail;
+
+ if (RI->getEncodingValue(SecondReg) != FirstEncoding + 1 ||
+ (isXReg && !XRegClass.contains(SecondReg)) ||
+ (isWReg && !WRegClass.contains(SecondReg))) {
+ Error(E,"expected second odd register of a "
+ "consecutive same-size even/odd register pair");
+ return MatchOperand_ParseFail;
+ }
+
+ unsigned Pair = 0;
+ if (isXReg) {
+ Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube64,
+ &AArch64MCRegisterClasses[AArch64::XSeqPairsClassRegClassID]);
+ } else {
+ Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube32,
+ &AArch64MCRegisterClasses[AArch64::WSeqPairsClassRegClassID]);
+ }
+
+ Operands.push_back(AArch64Operand::CreateReg(Pair, RegKind::Scalar, S,
+ getLoc(), getContext()));
+
+ return MatchOperand_Success;
+}
+
+template <bool ParseShiftExtend, bool ParseSuffix>
+OperandMatchResultTy
+AArch64AsmParser::tryParseSVEDataVector(OperandVector &Operands) {
+ const SMLoc S = getLoc();
+ // Check for a SVE vector register specifier first.
+ unsigned RegNum;
+ StringRef Kind;
+
+ OperandMatchResultTy Res =
+ tryParseVectorRegister(RegNum, Kind, RegKind::SVEDataVector);
+
+ if (Res != MatchOperand_Success)
+ return Res;
+
+ if (ParseSuffix && Kind.empty())
+ return MatchOperand_NoMatch;
+
+ const auto &KindRes = parseVectorKind(Kind, RegKind::SVEDataVector);
+ if (!KindRes)
+ return MatchOperand_NoMatch;
+
+ unsigned ElementWidth = KindRes->second;
+
+ // No shift/extend is the default.
+ if (!ParseShiftExtend || getParser().getTok().isNot(AsmToken::Comma)) {
+ Operands.push_back(AArch64Operand::CreateVectorReg(
+ RegNum, RegKind::SVEDataVector, ElementWidth, S, S, getContext()));
+
+ OperandMatchResultTy Res = tryParseVectorIndex(Operands);
+ if (Res == MatchOperand_ParseFail)
+ return MatchOperand_ParseFail;
+ return MatchOperand_Success;
+ }
+
+ // Eat the comma
+ getParser().Lex();
+
+ // Match the shift
+ SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> ExtOpnd;
+ Res = tryParseOptionalShiftExtend(ExtOpnd);
+ if (Res != MatchOperand_Success)
+ return Res;
+
+ auto Ext = static_cast<AArch64Operand *>(ExtOpnd.back().get());
+ Operands.push_back(AArch64Operand::CreateVectorReg(
+ RegNum, RegKind::SVEDataVector, ElementWidth, S, Ext->getEndLoc(),
+ getContext(), Ext->getShiftExtendType(), Ext->getShiftExtendAmount(),
+ Ext->hasShiftExtendAmount()));
+
+ return MatchOperand_Success;
+}
+
+OperandMatchResultTy
+AArch64AsmParser::tryParseSVEPattern(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+
+ SMLoc SS = getLoc();
+ const AsmToken &TokE = Parser.getTok();
+ bool IsHash = TokE.is(AsmToken::Hash);
+
+ if (!IsHash && TokE.isNot(AsmToken::Identifier))
+ return MatchOperand_NoMatch;
+
+ int64_t Pattern;
+ if (IsHash) {
+ Parser.Lex(); // Eat hash
+
+ // Parse the immediate operand.
+ const MCExpr *ImmVal;
+ SS = getLoc();
+ if (Parser.parseExpression(ImmVal))
+ return MatchOperand_ParseFail;
+
+ auto *MCE = dyn_cast<MCConstantExpr>(ImmVal);
+ if (!MCE)
+ return MatchOperand_ParseFail;
+
+ Pattern = MCE->getValue();
+ } else {
+ // Parse the pattern
+ auto Pat = AArch64SVEPredPattern::lookupSVEPREDPATByName(TokE.getString());
+ if (!Pat)
+ return MatchOperand_NoMatch;
+
+ Parser.Lex();
+ Pattern = Pat->Encoding;
+ assert(Pattern >= 0 && Pattern < 32);
+ }
+
+ Operands.push_back(
+ AArch64Operand::CreateImm(MCConstantExpr::create(Pattern, getContext()),
+ SS, getLoc(), getContext()));
+
+ return MatchOperand_Success;
+}
OperandMatchResultTy
AArch64AsmParser::tryParseGPR64x8(OperandVector &Operands) {
diff --git a/contrib/libs/llvm12/lib/Target/AArch64/AsmParser/ya.make b/contrib/libs/llvm12/lib/Target/AArch64/AsmParser/ya.make
index 512f510d85..827aff1e42 100644
--- a/contrib/libs/llvm12/lib/Target/AArch64/AsmParser/ya.make
+++ b/contrib/libs/llvm12/lib/Target/AArch64/AsmParser/ya.make
@@ -1,17 +1,17 @@
-# Generated by devtools/yamaker.
-
-LIBRARY()
-
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/MC
@@ -20,20 +20,20 @@ PEERDIR(
contrib/libs/llvm12/lib/Target/AArch64/MCTargetDesc
contrib/libs/llvm12/lib/Target/AArch64/TargetInfo
contrib/libs/llvm12/lib/Target/AArch64/Utils
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/lib/Target/AArch64
contrib/libs/llvm12/lib/Target/AArch64
contrib/libs/llvm12/lib/Target/AArch64/AsmParser
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- AArch64AsmParser.cpp
-)
-
-END()
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ AArch64AsmParser.cpp
+)
+
+END()