diff options
Diffstat (limited to 'lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp')
-rw-r--r-- | lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp | 4832 |
1 files changed, 0 insertions, 4832 deletions
diff --git a/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp b/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp deleted file mode 100644 index 38a61d809d..0000000000 --- a/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp +++ /dev/null @@ -1,4832 +0,0 @@ -//===-- ARM64AsmParser.cpp - Parse ARM64 assembly to MCInst instructions --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MCTargetDesc/ARM64AddressingModes.h" -#include "MCTargetDesc/ARM64BaseInfo.h" -#include "MCTargetDesc/ARM64MCExpr.h" -#include "llvm/MC/MCParser/MCAsmLexer.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCParser/MCParsedAsmOperand.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCTargetAsmParser.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Twine.h" -#include <cstdio> -using namespace llvm; - -namespace { - -class ARM64Operand; - -class ARM64AsmParser : public MCTargetAsmParser { -public: - typedef SmallVectorImpl<MCParsedAsmOperand *> OperandVector; - -private: - StringRef Mnemonic; ///< Instruction mnemonic. - MCSubtargetInfo &STI; - MCAsmParser &Parser; - - MCAsmParser &getParser() const { return Parser; } - MCAsmLexer &getLexer() const { return Parser.getLexer(); } - - SMLoc getLoc() const { return Parser.getTok().getLoc(); } - - bool parseSysAlias(StringRef Name, SMLoc NameLoc, OperandVector &Operands); - unsigned parseCondCodeString(StringRef Cond); - bool parseCondCode(OperandVector &Operands, bool invertCondCode); - int tryParseRegister(); - int tryMatchVectorRegister(StringRef &Kind); - bool parseOptionalShift(OperandVector &Operands); - bool parseOptionalExtend(OperandVector &Operands); - bool parseRegister(OperandVector &Operands); - bool parseMemory(OperandVector &Operands); - bool parseSymbolicImmVal(const MCExpr *&ImmVal); - bool parseVectorList(OperandVector &Operands); - bool parseOperand(OperandVector &Operands, bool isCondCode, - bool invertCondCode); - - void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); } - bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } - bool showMatchError(SMLoc Loc, unsigned ErrCode); - - bool parseDirectiveWord(unsigned Size, SMLoc L); - bool parseDirectiveTLSDescCall(SMLoc L); - - bool parseDirectiveLOH(StringRef LOH, SMLoc L); - - bool validateInstruction(MCInst &Inst, SmallVectorImpl<SMLoc> &Loc); - bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, - OperandVector &Operands, MCStreamer &Out, - unsigned &ErrorInfo, bool MatchingInlineAsm); -/// @name Auto-generated Match Functions -/// { - -#define GET_ASSEMBLER_HEADER -#include "ARM64GenAsmMatcher.inc" - - /// } - - OperandMatchResultTy tryParseNoIndexMemory(OperandVector &Operands); - OperandMatchResultTy tryParseBarrierOperand(OperandVector &Operands); - OperandMatchResultTy tryParseSystemRegister(OperandVector &Operands); - OperandMatchResultTy tryParseCPSRField(OperandVector &Operands); - OperandMatchResultTy tryParseSysCROperand(OperandVector &Operands); - OperandMatchResultTy tryParsePrefetch(OperandVector &Operands); - OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands); - OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands); - OperandMatchResultTy tryParseFPImm(OperandVector &Operands); - bool tryParseVectorRegister(OperandVector &Operands); - -public: - enum ARM64MatchResultTy { - Match_InvalidSuffix = FIRST_TARGET_MATCH_RESULT_TY, -#define GET_OPERAND_DIAGNOSTIC_TYPES -#include "ARM64GenAsmMatcher.inc" - }; - ARM64AsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser, - const MCInstrInfo &MII) - : MCTargetAsmParser(), STI(_STI), Parser(_Parser) { - MCAsmParserExtension::Initialize(_Parser); - } - - virtual bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, - SMLoc NameLoc, OperandVector &Operands); - virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); - virtual bool ParseDirective(AsmToken DirectiveID); - unsigned validateTargetOperandClass(MCParsedAsmOperand *Op, unsigned Kind); - - static bool classifySymbolRef(const MCExpr *Expr, - ARM64MCExpr::VariantKind &ELFRefKind, - MCSymbolRefExpr::VariantKind &DarwinRefKind, - const MCConstantExpr *&Addend); -}; -} // end anonymous namespace - -namespace { - -/// ARM64Operand - Instances of this class represent a parsed ARM64 machine -/// instruction. -class ARM64Operand : public MCParsedAsmOperand { -public: - enum MemIdxKindTy { - ImmediateOffset, // pre-indexed, no writeback - RegisterOffset // register offset, with optional extend - }; - -private: - enum KindTy { - k_Immediate, - k_Memory, - k_Register, - k_VectorList, - k_VectorIndex, - k_Token, - k_SysCR, - k_Prefetch, - k_Shifter, - k_Extend, - k_FPImm, - k_Barrier, - k_SystemRegister, - k_CPSRField - } Kind; - - SMLoc StartLoc, EndLoc, OffsetLoc; - - struct TokOp { - const char *Data; - unsigned Length; - bool IsSuffix; // Is the operand actually a suffix on the mnemonic. - }; - - struct RegOp { - unsigned RegNum; - bool isVector; - }; - - struct VectorListOp { - unsigned RegNum; - unsigned Count; - unsigned NumElements; - unsigned ElementKind; - }; - - struct VectorIndexOp { - unsigned Val; - }; - - struct ImmOp { - const MCExpr *Val; - }; - - struct FPImmOp { - unsigned Val; // Encoded 8-bit representation. - }; - - struct BarrierOp { - unsigned Val; // Not the enum since not all values have names. - }; - - struct SystemRegisterOp { - // 16-bit immediate, usually from the ARM64SYS::SystermRegister enum, - // but not limited to those values. - uint16_t Val; - }; - - struct CPSRFieldOp { - ARM64SYS::CPSRField Field; - }; - - struct SysCRImmOp { - unsigned Val; - }; - - struct PrefetchOp { - unsigned Val; - }; - - struct ShifterOp { - unsigned Val; - }; - - struct ExtendOp { - unsigned Val; - }; - - // This is for all forms of ARM64 address expressions - struct MemOp { - unsigned BaseRegNum, OffsetRegNum; - ARM64_AM::ExtendType ExtType; - unsigned ShiftVal; - bool ExplicitShift; - const MCExpr *OffsetImm; - MemIdxKindTy Mode; - }; - - union { - struct TokOp Tok; - struct RegOp Reg; - struct VectorListOp VectorList; - struct VectorIndexOp VectorIndex; - struct ImmOp Imm; - struct FPImmOp FPImm; - struct BarrierOp Barrier; - struct SystemRegisterOp SystemRegister; - struct CPSRFieldOp CPSRField; - struct SysCRImmOp SysCRImm; - struct PrefetchOp Prefetch; - struct ShifterOp Shifter; - struct ExtendOp Extend; - struct MemOp Mem; - }; - - // Keep the MCContext around as the MCExprs may need manipulated during - // the add<>Operands() calls. - MCContext &Ctx; - - ARM64Operand(KindTy K, MCContext &_Ctx) - : MCParsedAsmOperand(), Kind(K), Ctx(_Ctx) {} - -public: - ARM64Operand(const ARM64Operand &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_FPImm: - FPImm = o.FPImm; - break; - case k_Barrier: - Barrier = o.Barrier; - break; - case k_SystemRegister: - SystemRegister = o.SystemRegister; - break; - case k_CPSRField: - CPSRField = o.CPSRField; - break; - case k_Register: - Reg = o.Reg; - break; - case k_VectorList: - VectorList = o.VectorList; - break; - case k_VectorIndex: - VectorIndex = o.VectorIndex; - break; - case k_SysCR: - SysCRImm = o.SysCRImm; - break; - case k_Prefetch: - Prefetch = o.Prefetch; - break; - case k_Memory: - Mem = o.Mem; - break; - case k_Shifter: - Shifter = o.Shifter; - break; - case k_Extend: - Extend = o.Extend; - break; - } - } - - /// getStartLoc - Get the location of the first token of this operand. - SMLoc getStartLoc() const { return StartLoc; } - /// getEndLoc - Get the location of the last token of this operand. - SMLoc getEndLoc() const { return EndLoc; } - /// getOffsetLoc - Get the location of the offset of this memory operand. - SMLoc getOffsetLoc() const { return OffsetLoc; } - - 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; - } - - unsigned getFPImm() const { - assert(Kind == k_FPImm && "Invalid access!"); - return FPImm.Val; - } - - unsigned getBarrier() const { - assert(Kind == k_Barrier && "Invalid access!"); - return Barrier.Val; - } - - uint16_t getSystemRegister() const { - assert(Kind == k_SystemRegister && "Invalid access!"); - return SystemRegister.Val; - } - - ARM64SYS::CPSRField getCPSRField() const { - assert(Kind == k_CPSRField && "Invalid access!"); - return CPSRField.Field; - } - - unsigned getReg() const { - assert(Kind == k_Register && "Invalid access!"); - return Reg.RegNum; - } - - 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; - } - - 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 getShifter() const { - assert(Kind == k_Shifter && "Invalid access!"); - return Shifter.Val; - } - - unsigned getExtend() const { - assert(Kind == k_Extend && "Invalid access!"); - return Extend.Val; - } - - bool isImm() const { return Kind == k_Immediate; } - bool isSImm9() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - int64_t Val = MCE->getValue(); - return (Val >= -256 && Val < 256); - } - bool isSImm7s4() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - int64_t Val = MCE->getValue(); - return (Val >= -256 && Val <= 252 && (Val & 3) == 0); - } - bool isSImm7s8() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - int64_t Val = MCE->getValue(); - return (Val >= -512 && Val <= 504 && (Val & 7) == 0); - } - bool isSImm7s16() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - int64_t Val = MCE->getValue(); - return (Val >= -1024 && Val <= 1008 && (Val & 15) == 0); - } - bool isImm0_7() 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 < 8); - } - bool isImm1_8() 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 < 9); - } - bool isImm0_15() 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 < 16); - } - bool isImm1_16() 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 < 17); - } - bool isImm0_31() 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 < 32); - } - bool isImm1_31() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - int64_t Val = MCE->getValue(); - return (Val >= 1 && Val < 32); - } - bool isImm1_32() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - int64_t Val = MCE->getValue(); - return (Val >= 1 && Val < 33); - } - bool isImm0_63() 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); - } - bool isImm1_63() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - int64_t Val = MCE->getValue(); - return (Val >= 1 && Val < 64); - } - bool isImm1_64() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - int64_t Val = MCE->getValue(); - return (Val >= 1 && Val < 65); - } - bool isImm0_127() 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 < 128); - } - bool isImm0_255() 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 < 256); - } - bool isImm0_65535() 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 < 65536); - } - bool isLogicalImm32() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - return ARM64_AM::isLogicalImmediate(MCE->getValue(), 32); - } - bool isLogicalImm64() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - return ARM64_AM::isLogicalImmediate(MCE->getValue(), 64); - } - bool isSIMDImmType10() const { - if (!isImm()) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - if (!MCE) - return false; - return ARM64_AM::isAdvSIMDModImmType10(MCE->getValue()); - } - bool isBranchTarget26() 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; - return (Val >= -(0x2000000 << 2) && Val <= (0x1ffffff << 2)); - } - bool isBranchTarget19() 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; - return (Val >= -(0x40000 << 2) && Val <= (0x3ffff << 2)); - } - bool isBranchTarget14() 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; - return (Val >= -(0x2000 << 2) && Val <= (0x1fff << 2)); - } - - bool isMovWSymbol(ArrayRef<ARM64MCExpr::VariantKind> AllowedModifiers) const { - if (!isImm()) - return false; - - ARM64MCExpr::VariantKind ELFRefKind; - MCSymbolRefExpr::VariantKind DarwinRefKind; - const MCConstantExpr *Addend; - if (!ARM64AsmParser::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 Addend == 0; - } - - return false; - } - - bool isMovZSymbolG3() const { - static ARM64MCExpr::VariantKind Variants[] = { ARM64MCExpr::VK_ABS_G3 }; - return isMovWSymbol(Variants); - } - - bool isMovZSymbolG2() const { - static ARM64MCExpr::VariantKind Variants[] = { ARM64MCExpr::VK_ABS_G2, - ARM64MCExpr::VK_TPREL_G2, - ARM64MCExpr::VK_DTPREL_G2 }; - return isMovWSymbol(Variants); - } - - bool isMovZSymbolG1() const { - static ARM64MCExpr::VariantKind Variants[] = { ARM64MCExpr::VK_ABS_G1, - ARM64MCExpr::VK_GOTTPREL_G1, - ARM64MCExpr::VK_TPREL_G1, - ARM64MCExpr::VK_DTPREL_G1, }; - return isMovWSymbol(Variants); - } - - bool isMovZSymbolG0() const { - static ARM64MCExpr::VariantKind Variants[] = { ARM64MCExpr::VK_ABS_G0, - ARM64MCExpr::VK_TPREL_G0, - ARM64MCExpr::VK_DTPREL_G0 }; - return isMovWSymbol(Variants); - } - - bool isMovKSymbolG2() const { - static ARM64MCExpr::VariantKind Variants[] = { ARM64MCExpr::VK_ABS_G2_NC }; - return isMovWSymbol(Variants); - } - - bool isMovKSymbolG1() const { - static ARM64MCExpr::VariantKind Variants[] = { - ARM64MCExpr::VK_ABS_G1_NC, ARM64MCExpr::VK_TPREL_G1_NC, - ARM64MCExpr::VK_DTPREL_G1_NC - }; - return isMovWSymbol(Variants); - } - - bool isMovKSymbolG0() const { - static ARM64MCExpr::VariantKind Variants[] = { - ARM64MCExpr::VK_ABS_G0_NC, ARM64MCExpr::VK_GOTTPREL_G0_NC, - ARM64MCExpr::VK_TPREL_G0_NC, ARM64MCExpr::VK_DTPREL_G0_NC - }; - return isMovWSymbol(Variants); - } - - bool isFPImm() const { return Kind == k_FPImm; } - bool isBarrier() const { return Kind == k_Barrier; } - bool isSystemRegister() const { - if (Kind == k_SystemRegister) - return true; - // SPSel is legal for both the system register and the CPSR-field - // variants of MSR, so special case that. Fugly. - return (Kind == k_CPSRField && getCPSRField() == ARM64SYS::cpsr_SPSel); - } - bool isSystemCPSRField() const { return Kind == k_CPSRField; } - bool isReg() const { return Kind == k_Register && !Reg.isVector; } - bool isVectorReg() const { return Kind == k_Register && Reg.isVector; } - - /// Is this a vector list with the type implicit (presumably attached to the - /// instruction itself)? - template <unsigned NumRegs> bool isImplicitlyTypedVectorList() const { - return Kind == k_VectorList && VectorList.Count == NumRegs && - !VectorList.ElementKind; - } - - template <unsigned NumRegs, unsigned NumElements, char ElementKind> - bool isTypedVectorList() const { - if (Kind != k_VectorList) - return false; - if (VectorList.Count != NumRegs) - return false; - if (VectorList.ElementKind != ElementKind) - return false; - return VectorList.NumElements == NumElements; - } - - bool isVectorIndexB() const { - return Kind == k_VectorIndex && VectorIndex.Val < 16; - } - bool isVectorIndexH() const { - return Kind == k_VectorIndex && VectorIndex.Val < 8; - } - bool isVectorIndexS() const { - return Kind == k_VectorIndex && VectorIndex.Val < 4; - } - bool isVectorIndexD() const { - return Kind == k_VectorIndex && VectorIndex.Val < 2; - } - bool isToken() const { return Kind == k_Token; } - bool isTokenEqual(StringRef Str) const { - return Kind == k_Token && getToken() == Str; - } - bool isMem() const { return Kind == k_Memory; } - bool isSysCR() const { return Kind == k_SysCR; } - bool isPrefetch() const { return Kind == k_Prefetch; } - bool isShifter() const { return Kind == k_Shifter; } - bool isExtend() const { - // lsl is an alias for UXTX but will be a parsed as a k_Shifter operand. - if (isShifter()) { - ARM64_AM::ShiftType ST = ARM64_AM::getShiftType(Shifter.Val); - return ST == ARM64_AM::LSL; - } - return Kind == k_Extend; - } - bool isExtend64() const { - if (Kind != k_Extend) - return false; - // UXTX and SXTX require a 64-bit source register (the ExtendLSL64 class). - ARM64_AM::ExtendType ET = ARM64_AM::getArithExtendType(Extend.Val); - return ET != ARM64_AM::UXTX && ET != ARM64_AM::SXTX; - } - bool isExtendLSL64() const { - // lsl is an alias for UXTX but will be a parsed as a k_Shifter operand. - if (isShifter()) { - ARM64_AM::ShiftType ST = ARM64_AM::getShiftType(Shifter.Val); - return ST == ARM64_AM::LSL; - } - if (Kind != k_Extend) - return false; - ARM64_AM::ExtendType ET = ARM64_AM::getArithExtendType(Extend.Val); - return ET == ARM64_AM::UXTX || ET == ARM64_AM::SXTX; - } - - bool isArithmeticShifter() const { - if (!isShifter()) - return false; - - // An arithmetic shifter is LSL, LSR, or ASR. - ARM64_AM::ShiftType ST = ARM64_AM::getShiftType(Shifter.Val); - return ST == ARM64_AM::LSL || ST == ARM64_AM::LSR || ST == ARM64_AM::ASR; - } - - bool isMovImm32Shifter() const { - if (!isShifter()) - return false; - - // A MOVi shifter is LSL of 0, 16, 32, or 48. - ARM64_AM::ShiftType ST = ARM64_AM::getShiftType(Shifter.Val); - if (ST != ARM64_AM::LSL) - return false; - uint64_t Val = ARM64_AM::getShiftValue(Shifter.Val); - return (Val == 0 || Val == 16); - } - - bool isMovImm64Shifter() const { - if (!isShifter()) - return false; - - // A MOVi shifter is LSL of 0 or 16. - ARM64_AM::ShiftType ST = ARM64_AM::getShiftType(Shifter.Val); - if (ST != ARM64_AM::LSL) - return false; - uint64_t Val = ARM64_AM::getShiftValue(Shifter.Val); - return (Val == 0 || Val == 16 || Val == 32 || Val == 48); - } - - bool isAddSubShifter() const { - if (!isShifter()) - return false; - - // An ADD/SUB shifter is either 'lsl #0' or 'lsl #12'. - unsigned Val = Shifter.Val; - return ARM64_AM::getShiftType(Val) == ARM64_AM::LSL && - (ARM64_AM::getShiftValue(Val) == 0 || - ARM64_AM::getShiftValue(Val) == 12); - } - - bool isLogicalVecShifter() const { - if (!isShifter()) - return false; - - // A logical vector shifter is a left shift by 0, 8, 16, or 24. - unsigned Val = Shifter.Val; - unsigned Shift = ARM64_AM::getShiftValue(Val); - return ARM64_AM::getShiftType(Val) == ARM64_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 Val = Shifter.Val; - unsigned Shift = ARM64_AM::getShiftValue(Val); - return ARM64_AM::getShiftType(Val) == ARM64_AM::LSL && - (Shift == 0 || Shift == 8); - } - - bool isMoveVecShifter() const { - if (!isShifter()) - return false; - - // A logical vector shifter is a left shift by 8 or 16. - unsigned Val = Shifter.Val; - unsigned Shift = ARM64_AM::getShiftValue(Val); - return ARM64_AM::getShiftType(Val) == ARM64_AM::MSL && - (Shift == 8 || Shift == 16); - } - - bool isMemoryRegisterOffset8() const { - return isMem() && Mem.Mode == RegisterOffset && Mem.ShiftVal == 0; - } - - bool isMemoryRegisterOffset16() const { - return isMem() && Mem.Mode == RegisterOffset && - (Mem.ShiftVal == 0 || Mem.ShiftVal == 1); - } - - bool isMemoryRegisterOffset32() const { - return isMem() && Mem.Mode == RegisterOffset && - (Mem.ShiftVal == 0 || Mem.ShiftVal == 2); - } - - bool isMemoryRegisterOffset64() const { - return isMem() && Mem.Mode == RegisterOffset && - (Mem.ShiftVal == 0 || Mem.ShiftVal == 3); - } - - bool isMemoryRegisterOffset128() const { - return isMem() && Mem.Mode == RegisterOffset && - (Mem.ShiftVal == 0 || Mem.ShiftVal == 4); - } - - bool isMemoryUnscaled() const { - if (!isMem()) - return false; - if (Mem.Mode != ImmediateOffset) - return false; - if (!Mem.OffsetImm) - return true; - // Make sure the immediate value is valid. - const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.OffsetImm); - if (!CE) - return false; - // The offset must fit in a signed 9-bit unscaled immediate. - int64_t Value = CE->getValue(); - return (Value >= -256 && Value < 256); - } - // 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. - bool isMemoryUnscaledFB8() const { - return isMemoryUnscaled() && !isMemoryIndexed8(); - } - bool isMemoryUnscaledFB16() const { - return isMemoryUnscaled() && !isMemoryIndexed16(); - } - bool isMemoryUnscaledFB32() const { - return isMemoryUnscaled() && !isMemoryIndexed32(); - } - bool isMemoryUnscaledFB64() const { - return isMemoryUnscaled() && !isMemoryIndexed64(); - } - bool isMemoryUnscaledFB128() const { - return isMemoryUnscaled() && !isMemoryIndexed128(); - } - bool isMemoryIndexed(unsigned Scale) const { - if (!isMem()) - return false; - if (Mem.Mode != ImmediateOffset) - return false; - if (!Mem.OffsetImm) - return true; - // Make sure the immediate value is valid. - const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.OffsetImm); - - if (CE) { - // The offset must be a positive multiple of the scale and in range of - // encoding with a 12-bit immediate. - int64_t Value = CE->getValue(); - return (Value >= 0 && (Value % Scale) == 0 && Value <= (4095 * Scale)); - } - - // If it's not a constant, check for some expressions we know. - const MCExpr *Expr = Mem.OffsetImm; - ARM64MCExpr::VariantKind ELFRefKind; - MCSymbolRefExpr::VariantKind DarwinRefKind; - const MCConstantExpr *Addend; - if (!ARM64AsmParser::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 == ARM64MCExpr::VK_LO12 || - ELFRefKind == ARM64MCExpr::VK_GOT_LO12 || - ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12 || - ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12_NC || - ELFRefKind == ARM64MCExpr::VK_TPREL_LO12 || - ELFRefKind == ARM64MCExpr::VK_TPREL_LO12_NC || - ELFRefKind == ARM64MCExpr::VK_GOTTPREL_LO12_NC || - ELFRefKind == ARM64MCExpr::VK_TLSDESC_LO12) { - // 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. - int64_t Value = Addend ? Addend->getValue() : 0; - return Value >= 0 && (Value % Scale) == 0; - } 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; - } - bool isMemoryIndexed128() const { return isMemoryIndexed(16); } - bool isMemoryIndexed64() const { return isMemoryIndexed(8); } - bool isMemoryIndexed32() const { return isMemoryIndexed(4); } - bool isMemoryIndexed16() const { return isMemoryIndexed(2); } - bool isMemoryIndexed8() const { return isMemoryIndexed(1); } - bool isMemoryNoIndex() const { - if (!isMem()) - return false; - if (Mem.Mode != ImmediateOffset) - return false; - if (!Mem.OffsetImm) - return true; - - // Make sure the immediate value is valid. Only zero is allowed. - const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.OffsetImm); - if (!CE || CE->getValue() != 0) - return false; - return true; - } - bool isMemorySIMDNoIndex() const { - if (!isMem()) - return false; - if (Mem.Mode != ImmediateOffset) - return false; - return Mem.OffsetImm == 0; - } - bool isMemoryIndexedSImm9() const { - if (!isMem() || Mem.Mode != ImmediateOffset) - return false; - if (!Mem.OffsetImm) - return true; - const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.OffsetImm); - assert(CE && "Non-constant pre-indexed offset!"); - int64_t Value = CE->getValue(); - return Value >= -256 && Value <= 255; - } - bool isMemoryIndexed32SImm7() const { - if (!isMem() || Mem.Mode != ImmediateOffset) - return false; - if (!Mem.OffsetImm) - return true; - const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.OffsetImm); - assert(CE && "Non-constant pre-indexed offset!"); - int64_t Value = CE->getValue(); - return ((Value % 4) == 0) && Value >= -256 && Value <= 252; - } - bool isMemoryIndexed64SImm7() const { - if (!isMem() || Mem.Mode != ImmediateOffset) - return false; - if (!Mem.OffsetImm) - return true; - const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.OffsetImm); - assert(CE && "Non-constant pre-indexed offset!"); - int64_t Value = CE->getValue(); - return ((Value % 8) == 0) && Value >= -512 && Value <= 504; - } - bool isMemoryIndexed128SImm7() const { - if (!isMem() || Mem.Mode != ImmediateOffset) - return false; - if (!Mem.OffsetImm) - return true; - const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.OffsetImm); - assert(CE && "Non-constant pre-indexed offset!"); - int64_t Value = CE->getValue(); - return ((Value % 16) == 0) && Value >= -1024 && Value <= 1008; - } - - bool isAdrpLabel() const { - // Validation was handled during parsing, so we just sanity check that - // something didn't go haywire. - return isImm(); - } - - bool isAdrLabel() const { - // Validation was handled during parsing, so we just sanity check that - // something didn't go haywire. - return isImm(); - } - - void addExpr(MCInst &Inst, const MCExpr *Expr) const { - // Add as immediates when possible. Null MCExpr = 0. - if (Expr == 0) - 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 addVectorRegOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getReg())); - } - - template <unsigned NumRegs> - void addVectorList64Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - static unsigned FirstRegs[] = { ARM64::D0, ARM64::D0_D1, - ARM64::D0_D1_D2, ARM64::D0_D1_D2_D3 }; - unsigned FirstReg = FirstRegs[NumRegs - 1]; - - Inst.addOperand( - MCOperand::CreateReg(FirstReg + getVectorListStart() - ARM64::Q0)); - } - - template <unsigned NumRegs> - void addVectorList128Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - static unsigned FirstRegs[] = { ARM64::Q0, ARM64::Q0_Q1, - ARM64::Q0_Q1_Q2, ARM64::Q0_Q1_Q2_Q3 }; - unsigned FirstReg = FirstRegs[NumRegs - 1]; - - Inst.addOperand( - MCOperand::CreateReg(FirstReg + getVectorListStart() - ARM64::Q0)); - } - - void addVectorIndexBOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getVectorIndex())); - } - - void addVectorIndexHOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getVectorIndex())); - } - - void addVectorIndexSOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getVectorIndex())); - } - - void addVectorIndexDOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getVectorIndex())); - } - - 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()); - } - - void addAdrpLabelOperands(MCInst &Inst, unsigned N) const { - addImmOperands(Inst, N); - } - - void addAdrLabelOperands(MCInst &Inst, unsigned N) const { - addImmOperands(Inst, N); - } - - void addSImm9Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addSImm7s4Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue() / 4)); - } - - void addSImm7s8Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue() / 8)); - } - - void addSImm7s16Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue() / 16)); - } - - void addImm0_7Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm1_8Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm0_15Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm1_16Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm0_31Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm1_31Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm1_32Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm0_63Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm1_63Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm1_64Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm0_127Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm0_255Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addImm0_65535Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid constant immediate operand!"); - Inst.addOperand(MCOperand::CreateImm(MCE->getValue())); - } - - void addLogicalImm32Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid logical immediate operand!"); - uint64_t encoding = ARM64_AM::encodeLogicalImmediate(MCE->getValue(), 32); - Inst.addOperand(MCOperand::CreateImm(encoding)); - } - - void addLogicalImm64Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid logical immediate operand!"); - uint64_t encoding = ARM64_AM::encodeLogicalImmediate(MCE->getValue(), 64); - Inst.addOperand(MCOperand::CreateImm(encoding)); - } - - void addSIMDImmType10Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm()); - assert(MCE && "Invalid immediate operand!"); - uint64_t encoding = ARM64_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 addBranchTarget19Operands(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(getFPImm())); - } - - void addBarrierOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getBarrier())); - } - - void addSystemRegisterOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - if (Kind == k_SystemRegister) - Inst.addOperand(MCOperand::CreateImm(getSystemRegister())); - else { - assert(Kind == k_CPSRField && getCPSRField() == ARM64SYS::cpsr_SPSel); - Inst.addOperand(MCOperand::CreateImm(ARM64SYS::SPSel)); - } - } - - void addSystemCPSRFieldOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getCPSRField())); - } - - 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 addShifterOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getShifter())); - } - - void addArithmeticShifterOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getShifter())); - } - - void addMovImm32ShifterOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getShifter())); - } - - void addMovImm64ShifterOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getShifter())); - } - - void addAddSubShifterOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getShifter())); - } - - void addLogicalVecShifterOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getShifter())); - } - - void addLogicalVecHalfWordShifterOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getShifter())); - } - - void addMoveVecShifterOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getShifter())); - } - - void addExtendOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - // lsl is an alias for UXTX but will be a parsed as a k_Shifter operand. - if (isShifter()) { - assert(ARM64_AM::getShiftType(getShifter()) == ARM64_AM::LSL); - unsigned imm = getArithExtendImm(ARM64_AM::UXTX, - ARM64_AM::getShiftValue(getShifter())); - Inst.addOperand(MCOperand::CreateImm(imm)); - } else - Inst.addOperand(MCOperand::CreateImm(getExtend())); - } - - void addExtend64Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm(getExtend())); - } - - void addExtendLSL64Operands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - // lsl is an alias for UXTX but will be a parsed as a k_Shifter operand. - if (isShifter()) { - assert(ARM64_AM::getShiftType(getShifter()) == ARM64_AM::LSL); - unsigned imm = getArithExtendImm(ARM64_AM::UXTX, - ARM64_AM::getShiftValue(getShifter())); - Inst.addOperand(MCOperand::CreateImm(imm)); - } else - Inst.addOperand(MCOperand::CreateImm(getExtend())); - } - - void addMemoryRegisterOffsetOperands(MCInst &Inst, unsigned N, bool DoShift) { - assert(N == 3 && "Invalid number of operands!"); - - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); - unsigned ExtendImm = ARM64_AM::getMemExtendImm(Mem.ExtType, DoShift); - Inst.addOperand(MCOperand::CreateImm(ExtendImm)); - } - - void addMemoryRegisterOffset8Operands(MCInst &Inst, unsigned N) { - addMemoryRegisterOffsetOperands(Inst, N, Mem.ExplicitShift); - } - - void addMemoryRegisterOffset16Operands(MCInst &Inst, unsigned N) { - addMemoryRegisterOffsetOperands(Inst, N, Mem.ShiftVal == 1); - } - - void addMemoryRegisterOffset32Operands(MCInst &Inst, unsigned N) { - addMemoryRegisterOffsetOperands(Inst, N, Mem.ShiftVal == 2); - } - - void addMemoryRegisterOffset64Operands(MCInst &Inst, unsigned N) { - addMemoryRegisterOffsetOperands(Inst, N, Mem.ShiftVal == 3); - } - - void addMemoryRegisterOffset128Operands(MCInst &Inst, unsigned N) { - addMemoryRegisterOffsetOperands(Inst, N, Mem.ShiftVal == 4); - } - - void addMemoryIndexedOperands(MCInst &Inst, unsigned N, - unsigned Scale) const { - // Add the base register operand. - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - - if (!Mem.OffsetImm) { - // There isn't an offset. - Inst.addOperand(MCOperand::CreateImm(0)); - return; - } - - // Add the offset operand. - if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.OffsetImm)) { - assert(CE->getValue() % Scale == 0 && - "Offset operand must be multiple of the scale!"); - - // The MCInst offset operand doesn't include the low bits (like the - // instruction encoding). - Inst.addOperand(MCOperand::CreateImm(CE->getValue() / Scale)); - } - - // If this is a pageoff symrefexpr with an addend, the linker will - // do the scaling of the addend. - // - // Otherwise we don't know what this is, so just add the scaling divide to - // the expression and let the MC fixup evaluation code deal with it. - const MCExpr *Expr = Mem.OffsetImm; - ARM64MCExpr::VariantKind ELFRefKind; - MCSymbolRefExpr::VariantKind DarwinRefKind; - const MCConstantExpr *Addend; - if (Scale > 1 && - (!ARM64AsmParser::classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, - Addend) || - (Addend != 0 && DarwinRefKind != MCSymbolRefExpr::VK_PAGEOFF))) { - Expr = MCBinaryExpr::CreateDiv(Expr, MCConstantExpr::Create(Scale, Ctx), - Ctx); - } - - Inst.addOperand(MCOperand::CreateExpr(Expr)); - } - - void addMemoryUnscaledOperands(MCInst &Inst, unsigned N) const { - assert(N == 2 && isMemoryUnscaled() && "Invalid number of operands!"); - // Add the base register operand. - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - - // Add the offset operand. - if (!Mem.OffsetImm) - Inst.addOperand(MCOperand::CreateImm(0)); - else { - // Only constant offsets supported. - const MCConstantExpr *CE = cast<MCConstantExpr>(Mem.OffsetImm); - Inst.addOperand(MCOperand::CreateImm(CE->getValue())); - } - } - - void addMemoryIndexed128Operands(MCInst &Inst, unsigned N) const { - assert(N == 2 && isMemoryIndexed128() && "Invalid number of operands!"); - addMemoryIndexedOperands(Inst, N, 16); - } - - void addMemoryIndexed64Operands(MCInst &Inst, unsigned N) const { - assert(N == 2 && isMemoryIndexed64() && "Invalid number of operands!"); - addMemoryIndexedOperands(Inst, N, 8); - } - - void addMemoryIndexed32Operands(MCInst &Inst, unsigned N) const { - assert(N == 2 && isMemoryIndexed32() && "Invalid number of operands!"); - addMemoryIndexedOperands(Inst, N, 4); - } - - void addMemoryIndexed16Operands(MCInst &Inst, unsigned N) const { - assert(N == 2 && isMemoryIndexed16() && "Invalid number of operands!"); - addMemoryIndexedOperands(Inst, N, 2); - } - - void addMemoryIndexed8Operands(MCInst &Inst, unsigned N) const { - assert(N == 2 && isMemoryIndexed8() && "Invalid number of operands!"); - addMemoryIndexedOperands(Inst, N, 1); - } - - void addMemoryNoIndexOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && isMemoryNoIndex() && "Invalid number of operands!"); - // Add the base register operand (the offset is always zero, so ignore it). - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - } - - void addMemorySIMDNoIndexOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && isMemorySIMDNoIndex() && "Invalid number of operands!"); - // Add the base register operand (the offset is always zero, so ignore it). - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - } - - void addMemoryWritebackIndexedOperands(MCInst &Inst, unsigned N, - unsigned Scale) const { - assert(N == 2 && "Invalid number of operands!"); - - // Add the base register operand. - Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); - - // Add the offset operand. - int64_t Offset = 0; - if (Mem.OffsetImm) { - const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.OffsetImm); - assert(CE && "Non-constant indexed offset operand!"); - Offset = CE->getValue(); - } - - if (Scale != 1) { - assert(Offset % Scale == 0 && - "Offset operand must be a multiple of the scale!"); - Offset /= Scale; - } - - Inst.addOperand(MCOperand::CreateImm(Offset)); - } - - void addMemoryIndexedSImm9Operands(MCInst &Inst, unsigned N) const { - addMemoryWritebackIndexedOperands(Inst, N, 1); - } - - void addMemoryIndexed32SImm7Operands(MCInst &Inst, unsigned N) const { - addMemoryWritebackIndexedOperands(Inst, N, 4); - } - - void addMemoryIndexed64SImm7Operands(MCInst &Inst, unsigned N) const { - addMemoryWritebackIndexedOperands(Inst, N, 8); - } - - void addMemoryIndexed128SImm7Operands(MCInst &Inst, unsigned N) const { - addMemoryWritebackIndexedOperands(Inst, N, 16); - } - - virtual void print(raw_ostream &OS) const; - - static ARM64Operand *CreateToken(StringRef Str, bool IsSuffix, SMLoc S, - MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(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 ARM64Operand *CreateReg(unsigned RegNum, bool isVector, SMLoc S, - SMLoc E, MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_Register, Ctx); - Op->Reg.RegNum = RegNum; - Op->Reg.isVector = isVector; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static ARM64Operand *CreateVectorList(unsigned RegNum, unsigned Count, - unsigned NumElements, char ElementKind, - SMLoc S, SMLoc E, MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_VectorList, Ctx); - Op->VectorList.RegNum = RegNum; - Op->VectorList.Count = Count; - Op->VectorList.NumElements = NumElements; - Op->VectorList.ElementKind = ElementKind; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static ARM64Operand *CreateVectorIndex(unsigned Idx, SMLoc S, SMLoc E, - MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_VectorIndex, Ctx); - Op->VectorIndex.Val = Idx; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static ARM64Operand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, - MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_Immediate, Ctx); - Op->Imm.Val = Val; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static ARM64Operand *CreateFPImm(unsigned Val, SMLoc S, MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_FPImm, Ctx); - Op->FPImm.Val = Val; - Op->StartLoc = S; - Op->EndLoc = S; - return Op; - } - - static ARM64Operand *CreateBarrier(unsigned Val, SMLoc S, MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_Barrier, Ctx); - Op->Barrier.Val = Val; - Op->StartLoc = S; - Op->EndLoc = S; - return Op; - } - - static ARM64Operand *CreateSystemRegister(uint16_t Val, SMLoc S, - MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_SystemRegister, Ctx); - Op->SystemRegister.Val = Val; - Op->StartLoc = S; - Op->EndLoc = S; - return Op; - } - - static ARM64Operand *CreateCPSRField(ARM64SYS::CPSRField Field, SMLoc S, - MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_CPSRField, Ctx); - Op->CPSRField.Field = Field; - Op->StartLoc = S; - Op->EndLoc = S; - return Op; - } - - static ARM64Operand *CreateMem(unsigned BaseRegNum, const MCExpr *Off, - SMLoc S, SMLoc E, SMLoc OffsetLoc, - MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_Memory, Ctx); - Op->Mem.BaseRegNum = BaseRegNum; - Op->Mem.OffsetRegNum = 0; - Op->Mem.OffsetImm = Off; - Op->Mem.ExtType = ARM64_AM::UXTX; - Op->Mem.ShiftVal = 0; - Op->Mem.ExplicitShift = false; - Op->Mem.Mode = ImmediateOffset; - Op->OffsetLoc = OffsetLoc; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static ARM64Operand *CreateRegOffsetMem(unsigned BaseReg, unsigned OffsetReg, - ARM64_AM::ExtendType ExtType, - unsigned ShiftVal, bool ExplicitShift, - SMLoc S, SMLoc E, MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_Memory, Ctx); - Op->Mem.BaseRegNum = BaseReg; - Op->Mem.OffsetRegNum = OffsetReg; - Op->Mem.OffsetImm = 0; - Op->Mem.ExtType = ExtType; - Op->Mem.ShiftVal = ShiftVal; - Op->Mem.ExplicitShift = ExplicitShift; - Op->Mem.Mode = RegisterOffset; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static ARM64Operand *CreateSysCR(unsigned Val, SMLoc S, SMLoc E, - MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_SysCR, Ctx); - Op->SysCRImm.Val = Val; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static ARM64Operand *CreatePrefetch(unsigned Val, SMLoc S, MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_Prefetch, Ctx); - Op->Prefetch.Val = Val; - Op->StartLoc = S; - Op->EndLoc = S; - return Op; - } - - static ARM64Operand *CreateShifter(ARM64_AM::ShiftType ShOp, unsigned Val, - SMLoc S, SMLoc E, MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_Shifter, Ctx); - Op->Shifter.Val = ARM64_AM::getShifterImm(ShOp, Val); - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static ARM64Operand *CreateExtend(ARM64_AM::ExtendType ExtOp, unsigned Val, - SMLoc S, SMLoc E, MCContext &Ctx) { - ARM64Operand *Op = new ARM64Operand(k_Extend, Ctx); - Op->Extend.Val = ARM64_AM::getArithExtendImm(ExtOp, Val); - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } -}; - -} // end anonymous namespace. - -void ARM64Operand::print(raw_ostream &OS) const { - switch (Kind) { - case k_FPImm: - OS << "<fpimm " << getFPImm() << "(" << ARM64_AM::getFPImmFloat(getFPImm()) - << ") >"; - break; - case k_Barrier: { - const char *Name = - ARM64SYS::getBarrierOptName((ARM64SYS::BarrierOption)getBarrier()); - OS << "<barrier "; - if (Name) - OS << Name; - else - OS << getBarrier(); - OS << ">"; - break; - } - case k_SystemRegister: { - const char *Name = ARM64SYS::getSystemRegisterName( - (ARM64SYS::SystemRegister)getSystemRegister()); - OS << "<systemreg "; - if (Name) - OS << Name; - else - OS << "#" << getSystemRegister(); - OS << ">"; - break; - } - case k_CPSRField: { - const char *Name = ARM64SYS::getCPSRFieldName(getCPSRField()); - OS << "<cpsrfield " << Name << ">"; - break; - } - case k_Immediate: - getImm()->print(OS); - break; - case k_Memory: - OS << "<memory>"; - break; - case k_Register: - OS << "<register " << getReg() << ">"; - 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_Token: - OS << "'" << getToken() << "'"; - break; - case k_SysCR: - OS << "c" << getSysCR(); - break; - case k_Prefetch: - OS << "<prfop "; - if (ARM64_AM::isNamedPrefetchOp(getPrefetch())) - OS << ARM64_AM::getPrefetchOpName((ARM64_AM::PrefetchOp)getPrefetch()); - else - OS << "#" << getPrefetch(); - OS << ">"; - break; - case k_Shifter: { - unsigned Val = getShifter(); - OS << "<" << ARM64_AM::getShiftName(ARM64_AM::getShiftType(Val)) << " #" - << ARM64_AM::getShiftValue(Val) << ">"; - break; - } - case k_Extend: { - unsigned Val = getExtend(); - OS << "<" << ARM64_AM::getExtendName(ARM64_AM::getArithExtendType(Val)) - << " #" << ARM64_AM::getArithShiftValue(Val) << ">"; - break; - } - } -} - -/// @name Auto-generated Match Functions -/// { - -static unsigned MatchRegisterName(StringRef Name); - -/// } - -static unsigned matchVectorRegName(StringRef Name) { - return StringSwitch<unsigned>(Name) - .Case("v0", ARM64::Q0) - .Case("v1", ARM64::Q1) - .Case("v2", ARM64::Q2) - .Case("v3", ARM64::Q3) - .Case("v4", ARM64::Q4) - .Case("v5", ARM64::Q5) - .Case("v6", ARM64::Q6) - .Case("v7", ARM64::Q7) - .Case("v8", ARM64::Q8) - .Case("v9", ARM64::Q9) - .Case("v10", ARM64::Q10) - .Case("v11", ARM64::Q11) - .Case("v12", ARM64::Q12) - .Case("v13", ARM64::Q13) - .Case("v14", ARM64::Q14) - .Case("v15", ARM64::Q15) - .Case("v16", ARM64::Q16) - .Case("v17", ARM64::Q17) - .Case("v18", ARM64::Q18) - .Case("v19", ARM64::Q19) - .Case("v20", ARM64::Q20) - .Case("v21", ARM64::Q21) - .Case("v22", ARM64::Q22) - .Case("v23", ARM64::Q23) - .Case("v24", ARM64::Q24) - .Case("v25", ARM64::Q25) - .Case("v26", ARM64::Q26) - .Case("v27", ARM64::Q27) - .Case("v28", ARM64::Q28) - .Case("v29", ARM64::Q29) - .Case("v30", ARM64::Q30) - .Case("v31", ARM64::Q31) - .Default(0); -} - -static bool isValidVectorKind(StringRef Name) { - return StringSwitch<bool>(Name.lower()) - .Case(".8b", true) - .Case(".16b", true) - .Case(".4h", true) - .Case(".8h", true) - .Case(".2s", true) - .Case(".4s", true) - .Case(".1d", true) - .Case(".2d", true) - .Case(".1q", true) - // 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", true) - .Case(".h", true) - .Case(".s", true) - .Case(".d", true) - .Default(false); -} - -static void parseValidVectorKind(StringRef Name, unsigned &NumElements, - char &ElementKind) { - assert(isValidVectorKind(Name)); - - ElementKind = Name.lower()[Name.size() - 1]; - NumElements = 0; - - if (Name.size() == 2) - return; - - // Parse the lane count - Name = Name.drop_front(); - while (isdigit(Name.front())) { - NumElements = 10 * NumElements + (Name.front() - '0'); - Name = Name.drop_front(); - } -} - -bool ARM64AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, - SMLoc &EndLoc) { - StartLoc = getLoc(); - RegNo = tryParseRegister(); - EndLoc = SMLoc::getFromPointer(getLoc().getPointer() - 1); - return (RegNo == (unsigned)-1); -} - -/// tryParseRegister - 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. -int ARM64AsmParser::tryParseRegister() { - const AsmToken &Tok = Parser.getTok(); - assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); - - std::string lowerCase = Tok.getString().lower(); - unsigned RegNum = MatchRegisterName(lowerCase); - // Also handle a few aliases of registers. - if (RegNum == 0) - RegNum = StringSwitch<unsigned>(lowerCase) - .Case("x29", ARM64::FP) - .Case("x30", ARM64::LR) - .Case("x31", ARM64::XZR) - .Case("w31", ARM64::WZR) - .Default(0); - - if (RegNum == 0) - return -1; - - Parser.Lex(); // Eat identifier token. - return RegNum; -} - -/// tryMatchVectorRegister - Try to parse a vector register name with optional -/// kind specifier. If it is a register specifier, eat the token and return it. -int ARM64AsmParser::tryMatchVectorRegister(StringRef &Kind) { - if (Parser.getTok().isNot(AsmToken::Identifier)) { - TokError("vector register expected"); - return -1; - } - - StringRef Name = Parser.getTok().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 = matchVectorRegName(Head); - if (RegNum) { - if (Next != StringRef::npos) { - Kind = Name.slice(Next, StringRef::npos); - if (!isValidVectorKind(Kind)) { - TokError("invalid vector kind qualifier"); - return -1; - } - } - Parser.Lex(); // Eat the register token. - return RegNum; - } - return -1; -} - -static int MatchSysCRName(StringRef Name) { - // Use the same layout as the tablegen'erated register name matcher. Ugly, - // but efficient. - switch (Name.size()) { - default: - break; - case 2: - if (Name[0] != 'c' && Name[0] != 'C') - return -1; - switch (Name[1]) { - default: - return -1; - case '0': - return 0; - case '1': - return 1; - case '2': - return 2; - case '3': - return 3; - case '4': - return 4; - case '5': - return 5; - case '6': - return 6; - case '7': - return 7; - case '8': - return 8; - case '9': - return 9; - } - break; - case 3: - if ((Name[0] != 'c' && Name[0] != 'C') || Name[1] != '1') - return -1; - switch (Name[2]) { - default: - return -1; - case '0': - return 10; - case '1': - return 11; - case '2': - return 12; - case '3': - return 13; - case '4': - return 14; - case '5': - return 15; - } - break; - } - - llvm_unreachable("Unhandled SysCR operand string!"); - return -1; -} - -/// tryParseSysCROperand - Try to parse a system instruction CR operand name. -ARM64AsmParser::OperandMatchResultTy -ARM64AsmParser::tryParseSysCROperand(OperandVector &Operands) { - SMLoc S = getLoc(); - const AsmToken &Tok = Parser.getTok(); - if (Tok.isNot(AsmToken::Identifier)) - return MatchOperand_NoMatch; - - int Num = MatchSysCRName(Tok.getString()); - if (Num == -1) - return MatchOperand_NoMatch; - - Parser.Lex(); // Eat identifier token. - Operands.push_back(ARM64Operand::CreateSysCR(Num, S, getLoc(), getContext())); - return MatchOperand_Success; -} - -/// tryParsePrefetch - Try to parse a prefetch operand. -ARM64AsmParser::OperandMatchResultTy -ARM64AsmParser::tryParsePrefetch(OperandVector &Operands) { - SMLoc S = getLoc(); - const AsmToken &Tok = Parser.getTok(); - // Either an identifier for named values or a 5-bit immediate. - if (Tok.is(AsmToken::Hash)) { - Parser.Lex(); // Eat hash token. - 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 > 31) { - TokError("prefetch operand out of range, [0,31] expected"); - return MatchOperand_ParseFail; - } - - Operands.push_back(ARM64Operand::CreatePrefetch(prfop, S, getContext())); - return MatchOperand_Success; - } - - if (Tok.isNot(AsmToken::Identifier)) { - TokError("pre-fetch hint expected"); - return MatchOperand_ParseFail; - } - - unsigned prfop = StringSwitch<unsigned>(Tok.getString()) - .Case("pldl1keep", ARM64_AM::PLDL1KEEP) - .Case("pldl1strm", ARM64_AM::PLDL1STRM) - .Case("pldl2keep", ARM64_AM::PLDL2KEEP) - .Case("pldl2strm", ARM64_AM::PLDL2STRM) - .Case("pldl3keep", ARM64_AM::PLDL3KEEP) - .Case("pldl3strm", ARM64_AM::PLDL3STRM) - .Case("pstl1keep", ARM64_AM::PSTL1KEEP) - .Case("pstl1strm", ARM64_AM::PSTL1STRM) - .Case("pstl2keep", ARM64_AM::PSTL2KEEP) - .Case("pstl2strm", ARM64_AM::PSTL2STRM) - .Case("pstl3keep", ARM64_AM::PSTL3KEEP) - .Case("pstl3strm", ARM64_AM::PSTL3STRM) - .Default(0xff); - if (prfop == 0xff) { - TokError("pre-fetch hint expected"); - return MatchOperand_ParseFail; - } - - Parser.Lex(); // Eat identifier token. - Operands.push_back(ARM64Operand::CreatePrefetch(prfop, S, getContext())); - return MatchOperand_Success; -} - -/// tryParseAdrpLabel - Parse and validate a source label for the ADRP -/// instruction. -ARM64AsmParser::OperandMatchResultTy -ARM64AsmParser::tryParseAdrpLabel(OperandVector &Operands) { - SMLoc S = getLoc(); - const MCExpr *Expr; - if (parseSymbolicImmVal(Expr)) - return MatchOperand_ParseFail; - - ARM64MCExpr::VariantKind ELFRefKind; - MCSymbolRefExpr::VariantKind DarwinRefKind; - const MCConstantExpr *Addend; - if (!classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { - Error(S, "modified label reference + constant expected"); - return MatchOperand_ParseFail; - } - - if (DarwinRefKind == MCSymbolRefExpr::VK_None && - ELFRefKind == ARM64MCExpr::VK_INVALID) { - // No modifier was specified at all; this is the syntax for an ELF basic - // ADRP relocation (unfortunately). - Expr = ARM64MCExpr::Create(Expr, ARM64MCExpr::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 != ARM64MCExpr::VK_GOT_PAGE && - ELFRefKind != ARM64MCExpr::VK_GOTTPREL_PAGE && - ELFRefKind != ARM64MCExpr::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 a label reference possibly with addend. 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(ARM64Operand::CreateImm(Expr, S, E, getContext())); - - return MatchOperand_Success; -} - -/// tryParseAdrLabel - Parse and validate a source label for the ADR -/// instruction. -ARM64AsmParser::OperandMatchResultTy -ARM64AsmParser::tryParseAdrLabel(OperandVector &Operands) { - SMLoc S = getLoc(); - const MCExpr *Expr; - if (getParser().parseExpression(Expr)) - return MatchOperand_ParseFail; - - // The operand must be an un-qualified assembler local symbolref. - // FIXME: wrong for ELF. - if (const MCSymbolRefExpr *SRE = dyn_cast<const MCSymbolRefExpr>(Expr)) { - // FIXME: Should reference the MachineAsmInfo to get the private prefix. - bool isTemporary = SRE->getSymbol().getName().startswith("L"); - if (!isTemporary || SRE->getKind() != MCSymbolRefExpr::VK_None) { - Error(S, "unqualified, assembler-local label name expected"); - return MatchOperand_ParseFail; - } - } - - SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1); - Operands.push_back(ARM64Operand::CreateImm(Expr, S, E, getContext())); - - return MatchOperand_Success; -} - -/// tryParseFPImm - A floating point immediate expression operand. -ARM64AsmParser::OperandMatchResultTy -ARM64AsmParser::tryParseFPImm(OperandVector &Operands) { - SMLoc S = getLoc(); - - if (Parser.getTok().isNot(AsmToken::Hash)) - return MatchOperand_NoMatch; - Parser.Lex(); // Eat the '#'. - - // Handle negation, as that still comes through as a separate token. - bool isNegative = false; - if (Parser.getTok().is(AsmToken::Minus)) { - isNegative = true; - Parser.Lex(); - } - const AsmToken &Tok = Parser.getTok(); - if (Tok.is(AsmToken::Real)) { - APFloat RealVal(APFloat::IEEEdouble, Tok.getString()); - uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); - // If we had a '-' in front, toggle the sign bit. - IntVal ^= (uint64_t)isNegative << 63; - int Val = ARM64_AM::getFP64Imm(APInt(64, IntVal)); - Parser.Lex(); // Eat the token. - // Check for out of range values. As an exception, we let Zero through, - // as we handle that special case in post-processing before matching in - // order to use the zero register for it. - if (Val == -1 && !RealVal.isZero()) { - TokError("floating point value out of range"); - return MatchOperand_ParseFail; - } - Operands.push_back(ARM64Operand::CreateFPImm(Val, S, getContext())); - return MatchOperand_Success; - } - if (Tok.is(AsmToken::Integer)) { - int64_t Val; - if (!isNegative && Tok.getString().startswith("0x")) { - Val = Tok.getIntVal(); - if (Val > 255 || Val < 0) { - TokError("encoded floating point value out of range"); - return MatchOperand_ParseFail; - } - } else { - APFloat RealVal(APFloat::IEEEdouble, Tok.getString()); - uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); - // If we had a '-' in front, toggle the sign bit. - IntVal ^= (uint64_t)isNegative << 63; - Val = ARM64_AM::getFP64Imm(APInt(64, IntVal)); - } - Parser.Lex(); // Eat the token. - Operands.push_back(ARM64Operand::CreateFPImm(Val, S, getContext())); - return MatchOperand_Success; - } - - TokError("invalid floating point immediate"); - return MatchOperand_ParseFail; -} - -/// parseCondCodeString - Parse a Condition Code string. -unsigned ARM64AsmParser::parseCondCodeString(StringRef Cond) { - unsigned CC = StringSwitch<unsigned>(Cond) - .Case("eq", ARM64CC::EQ) - .Case("ne", ARM64CC::NE) - .Case("cs", ARM64CC::CS) - .Case("hs", ARM64CC::CS) - .Case("cc", ARM64CC::CC) - .Case("lo", ARM64CC::CC) - .Case("mi", ARM64CC::MI) - .Case("pl", ARM64CC::PL) - .Case("vs", ARM64CC::VS) - .Case("vc", ARM64CC::VC) - .Case("hi", ARM64CC::HI) - .Case("ls", ARM64CC::LS) - .Case("ge", ARM64CC::GE) - .Case("lt", ARM64CC::LT) - .Case("gt", ARM64CC::GT) - .Case("le", ARM64CC::LE) - .Case("al", ARM64CC::AL) - // Upper case works too. Not mixed case, though. - .Case("EQ", ARM64CC::EQ) - .Case("NE", ARM64CC::NE) - .Case("CS", ARM64CC::CS) - .Case("HS", ARM64CC::CS) - .Case("CC", ARM64CC::CC) - .Case("LO", ARM64CC::CC) - .Case("MI", ARM64CC::MI) - .Case("PL", ARM64CC::PL) - .Case("VS", ARM64CC::VS) - .Case("VC", ARM64CC::VC) - .Case("HI", ARM64CC::HI) - .Case("LS", ARM64CC::LS) - .Case("GE", ARM64CC::GE) - .Case("LT", ARM64CC::LT) - .Case("GT", ARM64CC::GT) - .Case("LE", ARM64CC::LE) - .Case("AL", ARM64CC::AL) - .Default(~0U); - return CC; -} - -/// parseCondCode - Parse a Condition Code operand. -bool ARM64AsmParser::parseCondCode(OperandVector &Operands, - bool invertCondCode) { - SMLoc S = getLoc(); - const AsmToken &Tok = Parser.getTok(); - assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); - - StringRef Cond = Tok.getString(); - unsigned CC = parseCondCodeString(Cond); - if (CC == ~0U) - return TokError("invalid condition code"); - Parser.Lex(); // Eat identifier token. - - if (invertCondCode) - CC = ARM64CC::getInvertedCondCode(ARM64CC::CondCode(CC)); - - const MCExpr *CCExpr = MCConstantExpr::Create(CC, getContext()); - Operands.push_back( - ARM64Operand::CreateImm(CCExpr, S, getLoc(), getContext())); - return false; -} - -/// ParseOptionalShift - Some operands take an optional shift argument. Parse -/// them if present. -bool ARM64AsmParser::parseOptionalShift(OperandVector &Operands) { - const AsmToken &Tok = Parser.getTok(); - ARM64_AM::ShiftType ShOp = StringSwitch<ARM64_AM::ShiftType>(Tok.getString()) - .Case("lsl", ARM64_AM::LSL) - .Case("lsr", ARM64_AM::LSR) - .Case("asr", ARM64_AM::ASR) - .Case("ror", ARM64_AM::ROR) - .Case("msl", ARM64_AM::MSL) - .Case("LSL", ARM64_AM::LSL) - .Case("LSR", ARM64_AM::LSR) - .Case("ASR", ARM64_AM::ASR) - .Case("ROR", ARM64_AM::ROR) - .Case("MSL", ARM64_AM::MSL) - .Default(ARM64_AM::InvalidShift); - if (ShOp == ARM64_AM::InvalidShift) - return true; - - SMLoc S = Tok.getLoc(); - Parser.Lex(); - - // We expect a number here. - if (getLexer().isNot(AsmToken::Hash)) - return TokError("immediate value expected for shifter operand"); - Parser.Lex(); // Eat the '#'. - - SMLoc ExprLoc = getLoc(); - const MCExpr *ImmVal; - if (getParser().parseExpression(ImmVal)) - return true; - - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal); - if (!MCE) - return TokError("immediate value expected for shifter operand"); - - if ((MCE->getValue() & 0x3f) != MCE->getValue()) - return Error(ExprLoc, "immediate value too large for shifter operand"); - - SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1); - Operands.push_back( - ARM64Operand::CreateShifter(ShOp, MCE->getValue(), S, E, getContext())); - return false; -} - -/// parseOptionalExtend - Some operands take an optional extend argument. Parse -/// them if present. -bool ARM64AsmParser::parseOptionalExtend(OperandVector &Operands) { - const AsmToken &Tok = Parser.getTok(); - ARM64_AM::ExtendType ExtOp = - StringSwitch<ARM64_AM::ExtendType>(Tok.getString()) - .Case("uxtb", ARM64_AM::UXTB) - .Case("uxth", ARM64_AM::UXTH) - .Case("uxtw", ARM64_AM::UXTW) - .Case("uxtx", ARM64_AM::UXTX) - .Case("lsl", ARM64_AM::UXTX) // Alias for UXTX - .Case("sxtb", ARM64_AM::SXTB) - .Case("sxth", ARM64_AM::SXTH) - .Case("sxtw", ARM64_AM::SXTW) - .Case("sxtx", ARM64_AM::SXTX) - .Case("UXTB", ARM64_AM::UXTB) - .Case("UXTH", ARM64_AM::UXTH) - .Case("UXTW", ARM64_AM::UXTW) - .Case("UXTX", ARM64_AM::UXTX) - .Case("LSL", ARM64_AM::UXTX) // Alias for UXTX - .Case("SXTB", ARM64_AM::SXTB) - .Case("SXTH", ARM64_AM::SXTH) - .Case("SXTW", ARM64_AM::SXTW) - .Case("SXTX", ARM64_AM::SXTX) - .Default(ARM64_AM::InvalidExtend); - if (ExtOp == ARM64_AM::InvalidExtend) - return true; - - SMLoc S = Tok.getLoc(); - Parser.Lex(); - - if (getLexer().is(AsmToken::EndOfStatement) || - getLexer().is(AsmToken::Comma)) { - SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1); - Operands.push_back( - ARM64Operand::CreateExtend(ExtOp, 0, S, E, getContext())); - return false; - } - - if (getLexer().isNot(AsmToken::Hash)) { - SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1); - Operands.push_back( - ARM64Operand::CreateExtend(ExtOp, 0, S, E, getContext())); - return false; - } - - Parser.Lex(); // Eat the '#'. - - const MCExpr *ImmVal; - if (getParser().parseExpression(ImmVal)) - return true; - - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal); - if (!MCE) - return TokError("immediate value expected for extend operand"); - - SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1); - Operands.push_back( - ARM64Operand::CreateExtend(ExtOp, MCE->getValue(), S, E, getContext())); - return false; -} - -/// 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 ARM64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc, - OperandVector &Operands) { - if (Name.find('.') != StringRef::npos) - return TokError("invalid operand"); - - Mnemonic = Name; - Operands.push_back( - ARM64Operand::CreateToken("sys", false, NameLoc, getContext())); - - const AsmToken &Tok = Parser.getTok(); - StringRef Op = Tok.getString(); - SMLoc S = Tok.getLoc(); - - const MCExpr *Expr = 0; - -#define SYS_ALIAS(op1, Cn, Cm, op2) \ - do { \ - Expr = MCConstantExpr::Create(op1, getContext()); \ - Operands.push_back( \ - ARM64Operand::CreateImm(Expr, S, getLoc(), getContext())); \ - Operands.push_back( \ - ARM64Operand::CreateSysCR(Cn, S, getLoc(), getContext())); \ - Operands.push_back( \ - ARM64Operand::CreateSysCR(Cm, S, getLoc(), getContext())); \ - Expr = MCConstantExpr::Create(op2, getContext()); \ - Operands.push_back( \ - ARM64Operand::CreateImm(Expr, S, getLoc(), getContext())); \ - } while (0) - - if (Mnemonic == "ic") { - if (!Op.compare_lower("ialluis")) { - // SYS #0, C7, C1, #0 - SYS_ALIAS(0, 7, 1, 0); - } else if (!Op.compare_lower("iallu")) { - // SYS #0, C7, C5, #0 - SYS_ALIAS(0, 7, 5, 0); - } else if (!Op.compare_lower("ivau")) { - // SYS #3, C7, C5, #1 - SYS_ALIAS(3, 7, 5, 1); - } else { - return TokError("invalid operand for IC instruction"); - } - } else if (Mnemonic == "dc") { - if (!Op.compare_lower("zva")) { - // SYS #3, C7, C4, #1 - SYS_ALIAS(3, 7, 4, 1); - } else if (!Op.compare_lower("ivac")) { - // SYS #3, C7, C6, #1 - SYS_ALIAS(0, 7, 6, 1); - } else if (!Op.compare_lower("isw")) { - // SYS #0, C7, C6, #2 - SYS_ALIAS(0, 7, 6, 2); - } else if (!Op.compare_lower("cvac")) { - // SYS #3, C7, C10, #1 - SYS_ALIAS(3, 7, 10, 1); - } else if (!Op.compare_lower("csw")) { - // SYS #0, C7, C10, #2 - SYS_ALIAS(0, 7, 10, 2); - } else if (!Op.compare_lower("cvau")) { - // SYS #3, C7, C11, #1 - SYS_ALIAS(3, 7, 11, 1); - } else if (!Op.compare_lower("civac")) { - // SYS #3, C7, C14, #1 - SYS_ALIAS(3, 7, 14, 1); - } else if (!Op.compare_lower("cisw")) { - // SYS #0, C7, C14, #2 - SYS_ALIAS(0, 7, 14, 2); - } else { - return TokError("invalid operand for DC instruction"); - } - } else if (Mnemonic == "at") { - if (!Op.compare_lower("s1e1r")) { - // SYS #0, C7, C8, #0 - SYS_ALIAS(0, 7, 8, 0); - } else if (!Op.compare_lower("s1e2r")) { - // SYS #4, C7, C8, #0 - SYS_ALIAS(4, 7, 8, 0); - } else if (!Op.compare_lower("s1e3r")) { - // SYS #6, C7, C8, #0 - SYS_ALIAS(6, 7, 8, 0); - } else if (!Op.compare_lower("s1e1w")) { - // SYS #0, C7, C8, #1 - SYS_ALIAS(0, 7, 8, 1); - } else if (!Op.compare_lower("s1e2w")) { - // SYS #4, C7, C8, #1 - SYS_ALIAS(4, 7, 8, 1); - } else if (!Op.compare_lower("s1e3w")) { - // SYS #6, C7, C8, #1 - SYS_ALIAS(6, 7, 8, 1); - } else if (!Op.compare_lower("s1e0r")) { - // SYS #0, C7, C8, #3 - SYS_ALIAS(0, 7, 8, 2); - } else if (!Op.compare_lower("s1e0w")) { - // SYS #0, C7, C8, #3 - SYS_ALIAS(0, 7, 8, 3); - } else if (!Op.compare_lower("s12e1r")) { - // SYS #4, C7, C8, #4 - SYS_ALIAS(4, 7, 8, 4); - } else if (!Op.compare_lower("s12e1w")) { - // SYS #4, C7, C8, #5 - SYS_ALIAS(4, 7, 8, 5); - } else if (!Op.compare_lower("s12e0r")) { - // SYS #4, C7, C8, #6 - SYS_ALIAS(4, 7, 8, 6); - } else if (!Op.compare_lower("s12e0w")) { - // SYS #4, C7, C8, #7 - SYS_ALIAS(4, 7, 8, 7); - } else { - return TokError("invalid operand for AT instruction"); - } - } else if (Mnemonic == "tlbi") { - if (!Op.compare_lower("vmalle1is")) { - // SYS #0, C8, C3, #0 - SYS_ALIAS(0, 8, 3, 0); - } else if (!Op.compare_lower("alle2is")) { - // SYS #4, C8, C3, #0 - SYS_ALIAS(4, 8, 3, 0); - } else if (!Op.compare_lower("alle3is")) { - // SYS #6, C8, C3, #0 - SYS_ALIAS(6, 8, 3, 0); - } else if (!Op.compare_lower("vae1is")) { - // SYS #0, C8, C3, #1 - SYS_ALIAS(0, 8, 3, 1); - } else if (!Op.compare_lower("vae2is")) { - // SYS #4, C8, C3, #1 - SYS_ALIAS(4, 8, 3, 1); - } else if (!Op.compare_lower("vae3is")) { - // SYS #6, C8, C3, #1 - SYS_ALIAS(6, 8, 3, 1); - } else if (!Op.compare_lower("aside1is")) { - // SYS #0, C8, C3, #2 - SYS_ALIAS(0, 8, 3, 2); - } else if (!Op.compare_lower("vaae1is")) { - // SYS #0, C8, C3, #3 - SYS_ALIAS(0, 8, 3, 3); - } else if (!Op.compare_lower("alle1is")) { - // SYS #4, C8, C3, #4 - SYS_ALIAS(4, 8, 3, 4); - } else if (!Op.compare_lower("vale1is")) { - // SYS #0, C8, C3, #5 - SYS_ALIAS(0, 8, 3, 5); - } else if (!Op.compare_lower("vaale1is")) { - // SYS #0, C8, C3, #7 - SYS_ALIAS(0, 8, 3, 7); - } else if (!Op.compare_lower("vmalle1")) { - // SYS #0, C8, C7, #0 - SYS_ALIAS(0, 8, 7, 0); - } else if (!Op.compare_lower("alle2")) { - // SYS #4, C8, C7, #0 - SYS_ALIAS(4, 8, 7, 0); - } else if (!Op.compare_lower("vale2is")) { - // SYS #4, C8, C3, #5 - SYS_ALIAS(4, 8, 3, 5); - } else if (!Op.compare_lower("vale3is")) { - // SYS #6, C8, C3, #5 - SYS_ALIAS(6, 8, 3, 5); - } else if (!Op.compare_lower("alle3")) { - // SYS #6, C8, C7, #0 - SYS_ALIAS(6, 8, 7, 0); - } else if (!Op.compare_lower("vae1")) { - // SYS #0, C8, C7, #1 - SYS_ALIAS(0, 8, 7, 1); - } else if (!Op.compare_lower("vae2")) { - // SYS #4, C8, C7, #1 - SYS_ALIAS(4, 8, 7, 1); - } else if (!Op.compare_lower("vae3")) { - // SYS #6, C8, C7, #1 - SYS_ALIAS(6, 8, 7, 1); - } else if (!Op.compare_lower("aside1")) { - // SYS #0, C8, C7, #2 - SYS_ALIAS(0, 8, 7, 2); - } else if (!Op.compare_lower("vaae1")) { - // SYS #0, C8, C7, #3 - SYS_ALIAS(0, 8, 7, 3); - } else if (!Op.compare_lower("alle1")) { - // SYS #4, C8, C7, #4 - SYS_ALIAS(4, 8, 7, 4); - } else if (!Op.compare_lower("vale1")) { - // SYS #0, C8, C7, #5 - SYS_ALIAS(0, 8, 7, 5); - } else if (!Op.compare_lower("vale2")) { - // SYS #4, C8, C7, #5 - SYS_ALIAS(4, 8, 7, 5); - } else if (!Op.compare_lower("vale3")) { - // SYS #6, C8, C7, #5 - SYS_ALIAS(6, 8, 7, 5); - } else if (!Op.compare_lower("vaale1")) { - // SYS #0, C8, C7, #7 - SYS_ALIAS(0, 8, 7, 7); - } else if (!Op.compare_lower("ipas2e1")) { - // SYS #4, C8, C4, #1 - SYS_ALIAS(4, 8, 4, 1); - } else if (!Op.compare_lower("ipas2le1")) { - // SYS #4, C8, C4, #5 - SYS_ALIAS(4, 8, 4, 5); - } else if (!Op.compare_lower("vmalls12e1")) { - // SYS #4, C8, C7, #6 - SYS_ALIAS(4, 8, 7, 6); - } else if (!Op.compare_lower("vmalls12e1is")) { - // SYS #4, C8, C3, #6 - SYS_ALIAS(4, 8, 3, 6); - } else { - return TokError("invalid operand for TLBI instruction"); - } - } - -#undef SYS_ALIAS - - Parser.Lex(); // Eat operand. - - // Check for the optional register operand. - if (getLexer().is(AsmToken::Comma)) { - Parser.Lex(); // Eat comma. - - if (Tok.isNot(AsmToken::Identifier) || parseRegister(Operands)) - return TokError("expected register operand"); - } - - if (getLexer().isNot(AsmToken::EndOfStatement)) { - Parser.eatToEndOfStatement(); - return TokError("unexpected token in argument list"); - } - - Parser.Lex(); // Consume the EndOfStatement - return false; -} - -ARM64AsmParser::OperandMatchResultTy -ARM64AsmParser::tryParseBarrierOperand(OperandVector &Operands) { - const AsmToken &Tok = Parser.getTok(); - - // Can be either a #imm style literal or an option name - if (Tok.is(AsmToken::Hash)) { - // Immediate operand. - Parser.Lex(); // Eat the '#' - const MCExpr *ImmVal; - SMLoc ExprLoc = getLoc(); - if (getParser().parseExpression(ImmVal)) - return MatchOperand_ParseFail; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal); - if (!MCE) { - Error(ExprLoc, "immediate value expected for barrier operand"); - return MatchOperand_ParseFail; - } - if (MCE->getValue() < 0 || MCE->getValue() > 15) { - Error(ExprLoc, "barrier operand out of range"); - return MatchOperand_ParseFail; - } - Operands.push_back( - ARM64Operand::CreateBarrier(MCE->getValue(), ExprLoc, getContext())); - return MatchOperand_Success; - } - - if (Tok.isNot(AsmToken::Identifier)) { - TokError("invalid operand for instruction"); - return MatchOperand_ParseFail; - } - - unsigned Opt = StringSwitch<unsigned>(Tok.getString()) - .Case("oshld", ARM64SYS::OSHLD) - .Case("oshst", ARM64SYS::OSHST) - .Case("osh", ARM64SYS::OSH) - .Case("nshld", ARM64SYS::NSHLD) - .Case("nshst", ARM64SYS::NSHST) - .Case("nsh", ARM64SYS::NSH) - .Case("ishld", ARM64SYS::ISHLD) - .Case("ishst", ARM64SYS::ISHST) - .Case("ish", ARM64SYS::ISH) - .Case("ld", ARM64SYS::LD) - .Case("st", ARM64SYS::ST) - .Case("sy", ARM64SYS::SY) - .Default(ARM64SYS::InvalidBarrier); - if (Opt == ARM64SYS::InvalidBarrier) { - TokError("invalid barrier option name"); - return MatchOperand_ParseFail; - } - - // The only valid named option for ISB is 'sy' - if (Mnemonic == "isb" && Opt != ARM64SYS::SY) { - TokError("'sy' or #imm operand expected"); - return MatchOperand_ParseFail; - } - - Operands.push_back(ARM64Operand::CreateBarrier(Opt, getLoc(), getContext())); - Parser.Lex(); // Consume the option - - return MatchOperand_Success; -} - -ARM64AsmParser::OperandMatchResultTy -ARM64AsmParser::tryParseSystemRegister(OperandVector &Operands) { - const AsmToken &Tok = Parser.getTok(); - - // It can be specified as a symbolic name. - if (Tok.isNot(AsmToken::Identifier)) - return MatchOperand_NoMatch; - - auto ID = Tok.getString().lower(); - ARM64SYS::SystemRegister Reg = - StringSwitch<ARM64SYS::SystemRegister>(ID) - .Case("spsr_el1", ARM64SYS::SPSR_svc) - .Case("spsr_svc", ARM64SYS::SPSR_svc) - .Case("elr_el1", ARM64SYS::ELR_EL1) - .Case("sp_el0", ARM64SYS::SP_EL0) - .Case("spsel", ARM64SYS::SPSel) - .Case("daif", ARM64SYS::DAIF) - .Case("currentel", ARM64SYS::CurrentEL) - .Case("nzcv", ARM64SYS::NZCV) - .Case("fpcr", ARM64SYS::FPCR) - .Case("fpsr", ARM64SYS::FPSR) - .Case("dspsr", ARM64SYS::DSPSR) - .Case("dlr", ARM64SYS::DLR) - .Case("spsr_el2", ARM64SYS::SPSR_hyp) - .Case("spsr_hyp", ARM64SYS::SPSR_hyp) - .Case("elr_el2", ARM64SYS::ELR_EL2) - .Case("sp_el1", ARM64SYS::SP_EL1) - .Case("spsr_irq", ARM64SYS::SPSR_irq) - .Case("spsr_abt", ARM64SYS::SPSR_abt) - .Case("spsr_und", ARM64SYS::SPSR_und) - .Case("spsr_fiq", ARM64SYS::SPSR_fiq) - .Case("spsr_el3", ARM64SYS::SPSR_EL3) - .Case("elr_el3", ARM64SYS::ELR_EL3) - .Case("sp_el2", ARM64SYS::SP_EL2) - .Case("midr_el1", ARM64SYS::MIDR_EL1) - .Case("ctr_el0", ARM64SYS::CTR_EL0) - .Case("mpidr_el1", ARM64SYS::MPIDR_EL1) - .Case("ecoidr_el1", ARM64SYS::ECOIDR_EL1) - .Case("dczid_el0", ARM64SYS::DCZID_EL0) - .Case("mvfr0_el1", ARM64SYS::MVFR0_EL1) - .Case("mvfr1_el1", ARM64SYS::MVFR1_EL1) - .Case("id_aa64pfr0_el1", ARM64SYS::ID_AA64PFR0_EL1) - .Case("id_aa64pfr1_el1", ARM64SYS::ID_AA64PFR1_EL1) - .Case("id_aa64dfr0_el1", ARM64SYS::ID_AA64DFR0_EL1) - .Case("id_aa64dfr1_el1", ARM64SYS::ID_AA64DFR1_EL1) - .Case("id_aa64isar0_el1", ARM64SYS::ID_AA64ISAR0_EL1) - .Case("id_aa64isar1_el1", ARM64SYS::ID_AA64ISAR1_EL1) - .Case("id_aa64mmfr0_el1", ARM64SYS::ID_AA64MMFR0_EL1) - .Case("id_aa64mmfr1_el1", ARM64SYS::ID_AA64MMFR1_EL1) - .Case("ccsidr_el1", ARM64SYS::CCSIDR_EL1) - .Case("clidr_el1", ARM64SYS::CLIDR_EL1) - .Case("aidr_el1", ARM64SYS::AIDR_EL1) - .Case("csselr_el1", ARM64SYS::CSSELR_EL1) - .Case("vpidr_el2", ARM64SYS::VPIDR_EL2) - .Case("vmpidr_el2", ARM64SYS::VMPIDR_EL2) - .Case("sctlr_el1", ARM64SYS::SCTLR_EL1) - .Case("sctlr_el2", ARM64SYS::SCTLR_EL2) - .Case("sctlr_el3", ARM64SYS::SCTLR_EL3) - .Case("actlr_el1", ARM64SYS::ACTLR_EL1) - .Case("actlr_el2", ARM64SYS::ACTLR_EL2) - .Case("actlr_el3", ARM64SYS::ACTLR_EL3) - .Case("cpacr_el1", ARM64SYS::CPACR_EL1) - .Case("cptr_el2", ARM64SYS::CPTR_EL2) - .Case("cptr_el3", ARM64SYS::CPTR_EL3) - .Case("scr_el3", ARM64SYS::SCR_EL3) - .Case("hcr_el2", ARM64SYS::HCR_EL2) - .Case("mdcr_el2", ARM64SYS::MDCR_EL2) - .Case("mdcr_el3", ARM64SYS::MDCR_EL3) - .Case("hstr_el2", ARM64SYS::HSTR_EL2) - .Case("hacr_el2", ARM64SYS::HACR_EL2) - .Case("ttbr0_el1", ARM64SYS::TTBR0_EL1) - .Case("ttbr1_el1", ARM64SYS::TTBR1_EL1) - .Case("ttbr0_el2", ARM64SYS::TTBR0_EL2) - .Case("ttbr0_el3", ARM64SYS::TTBR0_EL3) - .Case("vttbr_el2", ARM64SYS::VTTBR_EL2) - .Case("tcr_el1", ARM64SYS::TCR_EL1) - .Case("tcr_el2", ARM64SYS::TCR_EL2) - .Case("tcr_el3", ARM64SYS::TCR_EL3) - .Case("vtcr_el2", ARM64SYS::VTCR_EL2) - .Case("adfsr_el1", ARM64SYS::ADFSR_EL1) - .Case("aifsr_el1", ARM64SYS::AIFSR_EL1) - .Case("adfsr_el2", ARM64SYS::ADFSR_EL2) - .Case("aifsr_el2", ARM64SYS::AIFSR_EL2) - .Case("adfsr_el3", ARM64SYS::ADFSR_EL3) - .Case("aifsr_el3", ARM64SYS::AIFSR_EL3) - .Case("esr_el1", ARM64SYS::ESR_EL1) - .Case("esr_el2", ARM64SYS::ESR_EL2) - .Case("esr_el3", ARM64SYS::ESR_EL3) - .Case("far_el1", ARM64SYS::FAR_EL1) - .Case("far_el2", ARM64SYS::FAR_EL2) - .Case("far_el3", ARM64SYS::FAR_EL3) - .Case("hpfar_el2", ARM64SYS::HPFAR_EL2) - .Case("par_el1", ARM64SYS::PAR_EL1) - .Case("mair_el1", ARM64SYS::MAIR_EL1) - .Case("mair_el2", ARM64SYS::MAIR_EL2) - .Case("mair_el3", ARM64SYS::MAIR_EL3) - .Case("amair_el1", ARM64SYS::AMAIR_EL1) - .Case("amair_el2", ARM64SYS::AMAIR_EL2) - .Case("amair_el3", ARM64SYS::AMAIR_EL3) - .Case("vbar_el1", ARM64SYS::VBAR_EL1) - .Case("vbar_el2", ARM64SYS::VBAR_EL2) - .Case("vbar_el3", ARM64SYS::VBAR_EL3) - .Case("rvbar_el1", ARM64SYS::RVBAR_EL1) - .Case("rvbar_el2", ARM64SYS::RVBAR_EL2) - .Case("rvbar_el3", ARM64SYS::RVBAR_EL3) - .Case("isr_el1", ARM64SYS::ISR_EL1) - .Case("contextidr_el1", ARM64SYS::CONTEXTIDR_EL1) - .Case("tpidr_el0", ARM64SYS::TPIDR_EL0) - .Case("tpidrro_el0", ARM64SYS::TPIDRRO_EL0) - .Case("tpidr_el1", ARM64SYS::TPIDR_EL1) - .Case("tpidr_el2", ARM64SYS::TPIDR_EL2) - .Case("tpidr_el3", ARM64SYS::TPIDR_EL3) - .Case("teecr32_el1", ARM64SYS::TEECR32_EL1) - .Case("cntfrq_el0", ARM64SYS::CNTFRQ_EL0) - .Case("cntpct_el0", ARM64SYS::CNTPCT_EL0) - .Case("cntvct_el0", ARM64SYS::CNTVCT_EL0) - .Case("cntvoff_el2", ARM64SYS::CNTVOFF_EL2) - .Case("cntkctl_el1", ARM64SYS::CNTKCTL_EL1) - .Case("cnthctl_el2", ARM64SYS::CNTHCTL_EL2) - .Case("cntp_tval_el0", ARM64SYS::CNTP_TVAL_EL0) - .Case("cntp_ctl_el0", ARM64SYS::CNTP_CTL_EL0) - .Case("cntp_cval_el0", ARM64SYS::CNTP_CVAL_EL0) - .Case("cntv_tval_el0", ARM64SYS::CNTV_TVAL_EL0) - .Case("cntv_ctl_el0", ARM64SYS::CNTV_CTL_EL0) - .Case("cntv_cval_el0", ARM64SYS::CNTV_CVAL_EL0) - .Case("cnthp_tval_el2", ARM64SYS::CNTHP_TVAL_EL2) - .Case("cnthp_ctl_el2", ARM64SYS::CNTHP_CTL_EL2) - .Case("cnthp_cval_el2", ARM64SYS::CNTHP_CVAL_EL2) - .Case("cntps_tval_el1", ARM64SYS::CNTPS_TVAL_EL1) - .Case("cntps_ctl_el1", ARM64SYS::CNTPS_CTL_EL1) - .Case("cntps_cval_el1", ARM64SYS::CNTPS_CVAL_EL1) - .Case("dacr32_el2", ARM64SYS::DACR32_EL2) - .Case("ifsr32_el2", ARM64SYS::IFSR32_EL2) - .Case("teehbr32_el1", ARM64SYS::TEEHBR32_EL1) - .Case("sder32_el3", ARM64SYS::SDER32_EL3) - .Case("fpexc32_el2", ARM64SYS::FPEXC32_EL2) - .Case("current_el", ARM64SYS::CurrentEL) - .Case("pmevcntr0_el0", ARM64SYS::PMEVCNTR0_EL0) - .Case("pmevcntr1_el0", ARM64SYS::PMEVCNTR1_EL0) - .Case("pmevcntr2_el0", ARM64SYS::PMEVCNTR2_EL0) - .Case("pmevcntr3_el0", ARM64SYS::PMEVCNTR3_EL0) - .Case("pmevcntr4_el0", ARM64SYS::PMEVCNTR4_EL0) - .Case("pmevcntr5_el0", ARM64SYS::PMEVCNTR5_EL0) - .Case("pmevcntr6_el0", ARM64SYS::PMEVCNTR6_EL0) - .Case("pmevcntr7_el0", ARM64SYS::PMEVCNTR7_EL0) - .Case("pmevcntr8_el0", ARM64SYS::PMEVCNTR8_EL0) - .Case("pmevcntr9_el0", ARM64SYS::PMEVCNTR9_EL0) - .Case("pmevcntr10_el0", ARM64SYS::PMEVCNTR10_EL0) - .Case("pmevcntr11_el0", ARM64SYS::PMEVCNTR11_EL0) - .Case("pmevcntr12_el0", ARM64SYS::PMEVCNTR12_EL0) - .Case("pmevcntr13_el0", ARM64SYS::PMEVCNTR13_EL0) - .Case("pmevcntr14_el0", ARM64SYS::PMEVCNTR14_EL0) - .Case("pmevcntr15_el0", ARM64SYS::PMEVCNTR15_EL0) - .Case("pmevcntr16_el0", ARM64SYS::PMEVCNTR16_EL0) - .Case("pmevcntr17_el0", ARM64SYS::PMEVCNTR17_EL0) - .Case("pmevcntr18_el0", ARM64SYS::PMEVCNTR18_EL0) - .Case("pmevcntr19_el0", ARM64SYS::PMEVCNTR19_EL0) - .Case("pmevcntr20_el0", ARM64SYS::PMEVCNTR20_EL0) - .Case("pmevcntr21_el0", ARM64SYS::PMEVCNTR21_EL0) - .Case("pmevcntr22_el0", ARM64SYS::PMEVCNTR22_EL0) - .Case("pmevcntr23_el0", ARM64SYS::PMEVCNTR23_EL0) - .Case("pmevcntr24_el0", ARM64SYS::PMEVCNTR24_EL0) - .Case("pmevcntr25_el0", ARM64SYS::PMEVCNTR25_EL0) - .Case("pmevcntr26_el0", ARM64SYS::PMEVCNTR26_EL0) - .Case("pmevcntr27_el0", ARM64SYS::PMEVCNTR27_EL0) - .Case("pmevcntr28_el0", ARM64SYS::PMEVCNTR28_EL0) - .Case("pmevcntr29_el0", ARM64SYS::PMEVCNTR29_EL0) - .Case("pmevcntr30_el0", ARM64SYS::PMEVCNTR30_EL0) - .Case("pmevtyper0_el0", ARM64SYS::PMEVTYPER0_EL0) - .Case("pmevtyper1_el0", ARM64SYS::PMEVTYPER1_EL0) - .Case("pmevtyper2_el0", ARM64SYS::PMEVTYPER2_EL0) - .Case("pmevtyper3_el0", ARM64SYS::PMEVTYPER3_EL0) - .Case("pmevtyper4_el0", ARM64SYS::PMEVTYPER4_EL0) - .Case("pmevtyper5_el0", ARM64SYS::PMEVTYPER5_EL0) - .Case("pmevtyper6_el0", ARM64SYS::PMEVTYPER6_EL0) - .Case("pmevtyper7_el0", ARM64SYS::PMEVTYPER7_EL0) - .Case("pmevtyper8_el0", ARM64SYS::PMEVTYPER8_EL0) - .Case("pmevtyper9_el0", ARM64SYS::PMEVTYPER9_EL0) - .Case("pmevtyper10_el0", ARM64SYS::PMEVTYPER10_EL0) - .Case("pmevtyper11_el0", ARM64SYS::PMEVTYPER11_EL0) - .Case("pmevtyper12_el0", ARM64SYS::PMEVTYPER12_EL0) - .Case("pmevtyper13_el0", ARM64SYS::PMEVTYPER13_EL0) - .Case("pmevtyper14_el0", ARM64SYS::PMEVTYPER14_EL0) - .Case("pmevtyper15_el0", ARM64SYS::PMEVTYPER15_EL0) - .Case("pmevtyper16_el0", ARM64SYS::PMEVTYPER16_EL0) - .Case("pmevtyper17_el0", ARM64SYS::PMEVTYPER17_EL0) - .Case("pmevtyper18_el0", ARM64SYS::PMEVTYPER18_EL0) - .Case("pmevtyper19_el0", ARM64SYS::PMEVTYPER19_EL0) - .Case("pmevtyper20_el0", ARM64SYS::PMEVTYPER20_EL0) - .Case("pmevtyper21_el0", ARM64SYS::PMEVTYPER21_EL0) - .Case("pmevtyper22_el0", ARM64SYS::PMEVTYPER22_EL0) - .Case("pmevtyper23_el0", ARM64SYS::PMEVTYPER23_EL0) - .Case("pmevtyper24_el0", ARM64SYS::PMEVTYPER24_EL0) - .Case("pmevtyper25_el0", ARM64SYS::PMEVTYPER25_EL0) - .Case("pmevtyper26_el0", ARM64SYS::PMEVTYPER26_EL0) - .Case("pmevtyper27_el0", ARM64SYS::PMEVTYPER27_EL0) - .Case("pmevtyper28_el0", ARM64SYS::PMEVTYPER28_EL0) - .Case("pmevtyper29_el0", ARM64SYS::PMEVTYPER29_EL0) - .Case("pmevtyper30_el0", ARM64SYS::PMEVTYPER30_EL0) - .Case("pmccfiltr_el0", ARM64SYS::PMCCFILTR_EL0) - .Case("rmr_el3", ARM64SYS::RMR_EL3) - .Case("rmr_el2", ARM64SYS::RMR_EL2) - .Case("rmr_el1", ARM64SYS::RMR_EL1) - .Case("cpm_ioacc_ctl_el3", ARM64SYS::CPM_IOACC_CTL_EL3) - .Case("mdccsr_el0", ARM64SYS::MDCCSR_EL0) - .Case("mdccint_el1", ARM64SYS::MDCCINT_EL1) - .Case("dbgdtr_el0", ARM64SYS::DBGDTR_EL0) - .Case("dbgdtrrx_el0", ARM64SYS::DBGDTRRX_EL0) - .Case("dbgdtrtx_el0", ARM64SYS::DBGDTRTX_EL0) - .Case("dbgvcr32_el2", ARM64SYS::DBGVCR32_EL2) - .Case("osdtrrx_el1", ARM64SYS::OSDTRRX_EL1) - .Case("mdscr_el1", ARM64SYS::MDSCR_EL1) - .Case("osdtrtx_el1", ARM64SYS::OSDTRTX_EL1) - .Case("oseccr_el11", ARM64SYS::OSECCR_EL11) - .Case("dbgbvr0_el1", ARM64SYS::DBGBVR0_EL1) - .Case("dbgbvr1_el1", ARM64SYS::DBGBVR1_EL1) - .Case("dbgbvr2_el1", ARM64SYS::DBGBVR2_EL1) - .Case("dbgbvr3_el1", ARM64SYS::DBGBVR3_EL1) - .Case("dbgbvr4_el1", ARM64SYS::DBGBVR4_EL1) - .Case("dbgbvr5_el1", ARM64SYS::DBGBVR5_EL1) - .Case("dbgbvr6_el1", ARM64SYS::DBGBVR6_EL1) - .Case("dbgbvr7_el1", ARM64SYS::DBGBVR7_EL1) - .Case("dbgbvr8_el1", ARM64SYS::DBGBVR8_EL1) - .Case("dbgbvr9_el1", ARM64SYS::DBGBVR9_EL1) - .Case("dbgbvr10_el1", ARM64SYS::DBGBVR10_EL1) - .Case("dbgbvr11_el1", ARM64SYS::DBGBVR11_EL1) - .Case("dbgbvr12_el1", ARM64SYS::DBGBVR12_EL1) - .Case("dbgbvr13_el1", ARM64SYS::DBGBVR13_EL1) - .Case("dbgbvr14_el1", ARM64SYS::DBGBVR14_EL1) - .Case("dbgbvr15_el1", ARM64SYS::DBGBVR15_EL1) - .Case("dbgbcr0_el1", ARM64SYS::DBGBCR0_EL1) - .Case("dbgbcr1_el1", ARM64SYS::DBGBCR1_EL1) - .Case("dbgbcr2_el1", ARM64SYS::DBGBCR2_EL1) - .Case("dbgbcr3_el1", ARM64SYS::DBGBCR3_EL1) - .Case("dbgbcr4_el1", ARM64SYS::DBGBCR4_EL1) - .Case("dbgbcr5_el1", ARM64SYS::DBGBCR5_EL1) - .Case("dbgbcr6_el1", ARM64SYS::DBGBCR6_EL1) - .Case("dbgbcr7_el1", ARM64SYS::DBGBCR7_EL1) - .Case("dbgbcr8_el1", ARM64SYS::DBGBCR8_EL1) - .Case("dbgbcr9_el1", ARM64SYS::DBGBCR9_EL1) - .Case("dbgbcr10_el1", ARM64SYS::DBGBCR10_EL1) - .Case("dbgbcr11_el1", ARM64SYS::DBGBCR11_EL1) - .Case("dbgbcr12_el1", ARM64SYS::DBGBCR12_EL1) - .Case("dbgbcr13_el1", ARM64SYS::DBGBCR13_EL1) - .Case("dbgbcr14_el1", ARM64SYS::DBGBCR14_EL1) - .Case("dbgbcr15_el1", ARM64SYS::DBGBCR15_EL1) - .Case("dbgwvr0_el1", ARM64SYS::DBGWVR0_EL1) - .Case("dbgwvr1_el1", ARM64SYS::DBGWVR1_EL1) - .Case("dbgwvr2_el1", ARM64SYS::DBGWVR2_EL1) - .Case("dbgwvr3_el1", ARM64SYS::DBGWVR3_EL1) - .Case("dbgwvr4_el1", ARM64SYS::DBGWVR4_EL1) - .Case("dbgwvr5_el1", ARM64SYS::DBGWVR5_EL1) - .Case("dbgwvr6_el1", ARM64SYS::DBGWVR6_EL1) - .Case("dbgwvr7_el1", ARM64SYS::DBGWVR7_EL1) - .Case("dbgwvr8_el1", ARM64SYS::DBGWVR8_EL1) - .Case("dbgwvr9_el1", ARM64SYS::DBGWVR9_EL1) - .Case("dbgwvr10_el1", ARM64SYS::DBGWVR10_EL1) - .Case("dbgwvr11_el1", ARM64SYS::DBGWVR11_EL1) - .Case("dbgwvr12_el1", ARM64SYS::DBGWVR12_EL1) - .Case("dbgwvr13_el1", ARM64SYS::DBGWVR13_EL1) - .Case("dbgwvr14_el1", ARM64SYS::DBGWVR14_EL1) - .Case("dbgwvr15_el1", ARM64SYS::DBGWVR15_EL1) - .Case("dbgwcr0_el1", ARM64SYS::DBGWCR0_EL1) - .Case("dbgwcr1_el1", ARM64SYS::DBGWCR1_EL1) - .Case("dbgwcr2_el1", ARM64SYS::DBGWCR2_EL1) - .Case("dbgwcr3_el1", ARM64SYS::DBGWCR3_EL1) - .Case("dbgwcr4_el1", ARM64SYS::DBGWCR4_EL1) - .Case("dbgwcr5_el1", ARM64SYS::DBGWCR5_EL1) - .Case("dbgwcr6_el1", ARM64SYS::DBGWCR6_EL1) - .Case("dbgwcr7_el1", ARM64SYS::DBGWCR7_EL1) - .Case("dbgwcr8_el1", ARM64SYS::DBGWCR8_EL1) - .Case("dbgwcr9_el1", ARM64SYS::DBGWCR9_EL1) - .Case("dbgwcr10_el1", ARM64SYS::DBGWCR10_EL1) - .Case("dbgwcr11_el1", ARM64SYS::DBGWCR11_EL1) - .Case("dbgwcr12_el1", ARM64SYS::DBGWCR12_EL1) - .Case("dbgwcr13_el1", ARM64SYS::DBGWCR13_EL1) - .Case("dbgwcr14_el1", ARM64SYS::DBGWCR14_EL1) - .Case("dbgwcr15_el1", ARM64SYS::DBGWCR15_EL1) - .Case("mdrar_el1", ARM64SYS::MDRAR_EL1) - .Case("oslar_el1", ARM64SYS::OSLAR_EL1) - .Case("oslsr_el1", ARM64SYS::OSLSR_EL1) - .Case("osdlr_el1", ARM64SYS::OSDLR_EL1) - .Case("dbgprcr_el1", ARM64SYS::DBGPRCR_EL1) - .Case("dbgclaimset_el1", ARM64SYS::DBGCLAIMSET_EL1) - .Case("dbgclaimclr_el1", ARM64SYS::DBGCLAIMCLR_EL1) - .Case("dbgauthstatus_el1", ARM64SYS::DBGAUTHSTATUS_EL1) - .Case("dbgdevid2", ARM64SYS::DBGDEVID2) - .Case("dbgdevid1", ARM64SYS::DBGDEVID1) - .Case("dbgdevid0", ARM64SYS::DBGDEVID0) - .Case("id_pfr0_el1", ARM64SYS::ID_PFR0_EL1) - .Case("id_pfr1_el1", ARM64SYS::ID_PFR1_EL1) - .Case("id_dfr0_el1", ARM64SYS::ID_DFR0_EL1) - .Case("id_afr0_el1", ARM64SYS::ID_AFR0_EL1) - .Case("id_isar0_el1", ARM64SYS::ID_ISAR0_EL1) - .Case("id_isar1_el1", ARM64SYS::ID_ISAR1_EL1) - .Case("id_isar2_el1", ARM64SYS::ID_ISAR2_EL1) - .Case("id_isar3_el1", ARM64SYS::ID_ISAR3_EL1) - .Case("id_isar4_el1", ARM64SYS::ID_ISAR4_EL1) - .Case("id_isar5_el1", ARM64SYS::ID_ISAR5_EL1) - .Case("afsr1_el1", ARM64SYS::AFSR1_EL1) - .Case("afsr0_el1", ARM64SYS::AFSR0_EL1) - .Case("revidr_el1", ARM64SYS::REVIDR_EL1) - .Default(ARM64SYS::InvalidSystemReg); - if (Reg != ARM64SYS::InvalidSystemReg) { - // We matched a reg name, so create the operand. - Operands.push_back( - ARM64Operand::CreateSystemRegister(Reg, getLoc(), getContext())); - Parser.Lex(); // Consume the register name. - return MatchOperand_Success; - } - - // Or we may have an identifier that encodes the sub-operands. - // For example, s3_2_c15_c0_0. - unsigned op0, op1, CRn, CRm, op2; - std::string Desc = ID; - if (std::sscanf(Desc.c_str(), "s%u_%u_c%u_c%u_%u", &op0, &op1, &CRn, &CRm, - &op2) != 5) - return MatchOperand_NoMatch; - if ((op0 != 2 && op0 != 3) || op1 > 7 || CRn > 15 || CRm > 15 || op2 > 7) - return MatchOperand_NoMatch; - - unsigned Val = op0 << 14 | op1 << 11 | CRn << 7 | CRm << 3 | op2; - Operands.push_back( - ARM64Operand::CreateSystemRegister(Val, getLoc(), getContext())); - Parser.Lex(); // Consume the register name. - - return MatchOperand_Success; -} - -ARM64AsmParser::OperandMatchResultTy -ARM64AsmParser::tryParseCPSRField(OperandVector &Operands) { - const AsmToken &Tok = Parser.getTok(); - - if (Tok.isNot(AsmToken::Identifier)) - return MatchOperand_NoMatch; - - ARM64SYS::CPSRField Field = - StringSwitch<ARM64SYS::CPSRField>(Tok.getString().lower()) - .Case("spsel", ARM64SYS::cpsr_SPSel) - .Case("daifset", ARM64SYS::cpsr_DAIFSet) - .Case("daifclr", ARM64SYS::cpsr_DAIFClr) - .Default(ARM64SYS::InvalidCPSRField); - if (Field == ARM64SYS::InvalidCPSRField) - return MatchOperand_NoMatch; - Operands.push_back( - ARM64Operand::CreateCPSRField(Field, getLoc(), getContext())); - Parser.Lex(); // Consume the register name. - - return MatchOperand_Success; -} - -/// tryParseVectorRegister - Parse a vector register operand. -bool ARM64AsmParser::tryParseVectorRegister(OperandVector &Operands) { - if (Parser.getTok().isNot(AsmToken::Identifier)) - return true; - - SMLoc S = getLoc(); - // Check for a vector register specifier first. - StringRef Kind; - int64_t Reg = tryMatchVectorRegister(Kind); - if (Reg == -1) - return true; - Operands.push_back( - ARM64Operand::CreateReg(Reg, true, S, getLoc(), getContext())); - // If there was an explicit qualifier, that goes on as a literal text - // operand. - if (!Kind.empty()) - Operands.push_back(ARM64Operand::CreateToken(Kind, false, S, getContext())); - - // If there is an index specifier following the register, parse that too. - if (Parser.getTok().is(AsmToken::LBrac)) { - SMLoc SIdx = getLoc(); - Parser.Lex(); // Eat left bracket token. - - const MCExpr *ImmVal; - if (getParser().parseExpression(ImmVal)) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal); - if (!MCE) { - TokError("immediate value expected for vector index"); - return false; - } - - SMLoc E = getLoc(); - if (Parser.getTok().isNot(AsmToken::RBrac)) { - Error(E, "']' expected"); - return false; - } - - Parser.Lex(); // Eat right bracket token. - - Operands.push_back(ARM64Operand::CreateVectorIndex(MCE->getValue(), SIdx, E, - getContext())); - } - - return false; -} - -/// parseRegister - Parse a non-vector register operand. -bool ARM64AsmParser::parseRegister(OperandVector &Operands) { - SMLoc S = getLoc(); - // Try for a vector register. - if (!tryParseVectorRegister(Operands)) - return false; - - // Try for a scalar register. - int64_t Reg = tryParseRegister(); - if (Reg == -1) - return true; - Operands.push_back( - ARM64Operand::CreateReg(Reg, false, S, getLoc(), getContext())); - - // A small number of instructions (FMOVXDhighr, for example) have "[1]" - // as a string token in the instruction itself. - if (getLexer().getKind() == AsmToken::LBrac) { - SMLoc LBracS = getLoc(); - Parser.Lex(); - const AsmToken &Tok = Parser.getTok(); - if (Tok.is(AsmToken::Integer)) { - SMLoc IntS = getLoc(); - int64_t Val = Tok.getIntVal(); - if (Val == 1) { - Parser.Lex(); - if (getLexer().getKind() == AsmToken::RBrac) { - SMLoc RBracS = getLoc(); - Parser.Lex(); - Operands.push_back( - ARM64Operand::CreateToken("[", false, LBracS, getContext())); - Operands.push_back( - ARM64Operand::CreateToken("1", false, IntS, getContext())); - Operands.push_back( - ARM64Operand::CreateToken("]", false, RBracS, getContext())); - return false; - } - } - } - } - - return false; -} - -/// tryParseNoIndexMemory - Custom parser method for memory operands that -/// do not allow base regisrer writeback modes, -/// or those that handle writeback separately from -/// the memory operand (like the AdvSIMD ldX/stX -/// instructions. -ARM64AsmParser::OperandMatchResultTy -ARM64AsmParser::tryParseNoIndexMemory(OperandVector &Operands) { - if (Parser.getTok().isNot(AsmToken::LBrac)) - return MatchOperand_NoMatch; - SMLoc S = getLoc(); - Parser.Lex(); // Eat left bracket token. - - const AsmToken &BaseRegTok = Parser.getTok(); - if (BaseRegTok.isNot(AsmToken::Identifier)) { - Error(BaseRegTok.getLoc(), "register expected"); - return MatchOperand_ParseFail; - } - - int64_t Reg = tryParseRegister(); - if (Reg == -1) { - Error(BaseRegTok.getLoc(), "register expected"); - return MatchOperand_ParseFail; - } - - SMLoc E = getLoc(); - if (Parser.getTok().isNot(AsmToken::RBrac)) { - Error(E, "']' expected"); - return MatchOperand_ParseFail; - } - - Parser.Lex(); // Eat right bracket token. - - Operands.push_back(ARM64Operand::CreateMem(Reg, 0, S, E, E, getContext())); - return MatchOperand_Success; -} - -/// parseMemory - Parse a memory operand for a basic load/store instruction. -bool ARM64AsmParser::parseMemory(OperandVector &Operands) { - assert(Parser.getTok().is(AsmToken::LBrac) && "Token is not a Left Bracket"); - SMLoc S = getLoc(); - Parser.Lex(); // Eat left bracket token. - - const AsmToken &BaseRegTok = Parser.getTok(); - if (BaseRegTok.isNot(AsmToken::Identifier)) - return Error(BaseRegTok.getLoc(), "register expected"); - - int64_t Reg = tryParseRegister(); - if (Reg == -1) - return Error(BaseRegTok.getLoc(), "register expected"); - - // If there is an offset expression, parse it. - const MCExpr *OffsetExpr = 0; - SMLoc OffsetLoc; - if (Parser.getTok().is(AsmToken::Comma)) { - Parser.Lex(); // Eat the comma. - OffsetLoc = getLoc(); - - // Register offset - const AsmToken &OffsetRegTok = Parser.getTok(); - int Reg2 = OffsetRegTok.is(AsmToken::Identifier) ? tryParseRegister() : -1; - if (Reg2 != -1) { - // Default shift is LSL, with an omitted shift. We use the third bit of - // the extend value to indicate presence/omission of the immediate offset. - ARM64_AM::ExtendType ExtOp = ARM64_AM::UXTX; - int64_t ShiftVal = 0; - bool ExplicitShift = false; - - if (Parser.getTok().is(AsmToken::Comma)) { - // Embedded extend operand. - Parser.Lex(); // Eat the comma - - SMLoc ExtLoc = getLoc(); - const AsmToken &Tok = Parser.getTok(); - ExtOp = StringSwitch<ARM64_AM::ExtendType>(Tok.getString()) - .Case("uxtw", ARM64_AM::UXTW) - .Case("lsl", ARM64_AM::UXTX) // Alias for UXTX - .Case("sxtw", ARM64_AM::SXTW) - .Case("sxtx", ARM64_AM::SXTX) - .Case("UXTW", ARM64_AM::UXTW) - .Case("LSL", ARM64_AM::UXTX) // Alias for UXTX - .Case("SXTW", ARM64_AM::SXTW) - .Case("SXTX", ARM64_AM::SXTX) - .Default(ARM64_AM::InvalidExtend); - if (ExtOp == ARM64_AM::InvalidExtend) - return Error(ExtLoc, "expected valid extend operation"); - - Parser.Lex(); // Eat the extend op. - - if (getLexer().is(AsmToken::RBrac)) { - // No immediate operand. - if (ExtOp == ARM64_AM::UXTX) - return Error(ExtLoc, "LSL extend requires immediate operand"); - } else if (getLexer().is(AsmToken::Hash)) { - // Immediate operand. - Parser.Lex(); // Eat the '#' - const MCExpr *ImmVal; - SMLoc ExprLoc = getLoc(); - if (getParser().parseExpression(ImmVal)) - return true; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal); - if (!MCE) - return TokError("immediate value expected for extend operand"); - - ExplicitShift = true; - ShiftVal = MCE->getValue(); - if (ShiftVal < 0 || ShiftVal > 4) - return Error(ExprLoc, "immediate operand out of range"); - } else - return Error(getLoc(), "expected immediate operand"); - } - - if (Parser.getTok().isNot(AsmToken::RBrac)) - return Error(getLoc(), "']' expected"); - - Parser.Lex(); // Eat right bracket token. - - SMLoc E = getLoc(); - Operands.push_back(ARM64Operand::CreateRegOffsetMem( - Reg, Reg2, ExtOp, ShiftVal, ExplicitShift, S, E, getContext())); - return false; - - // Immediate expressions. - } else if (Parser.getTok().is(AsmToken::Hash)) { - Parser.Lex(); // Eat hash token. - - if (parseSymbolicImmVal(OffsetExpr)) - return true; - } else { - // FIXME: We really should make sure that we're dealing with a LDR/STR - // instruction that can legally have a symbolic expression here. - // Symbol reference. - if (Parser.getTok().isNot(AsmToken::Identifier) && - Parser.getTok().isNot(AsmToken::String)) - return Error(getLoc(), "identifier or immediate expression expected"); - if (getParser().parseExpression(OffsetExpr)) - return true; - // If this is a plain ref, Make sure a legal variant kind was specified. - // Otherwise, it's a more complicated expression and we have to just - // assume it's OK and let the relocation stuff puke if it's not. - ARM64MCExpr::VariantKind ELFRefKind; - MCSymbolRefExpr::VariantKind DarwinRefKind; - const MCConstantExpr *Addend; - if (classifySymbolRef(OffsetExpr, ELFRefKind, DarwinRefKind, Addend) && - Addend == 0) { - assert(ELFRefKind == ARM64MCExpr::VK_INVALID && - "ELF symbol modifiers not supported here yet"); - - switch (DarwinRefKind) { - default: - return Error(getLoc(), "expected @pageoff or @gotpageoff modifier"); - case MCSymbolRefExpr::VK_GOTPAGEOFF: - case MCSymbolRefExpr::VK_PAGEOFF: - case MCSymbolRefExpr::VK_TLVPPAGEOFF: - // These are what we're expecting. - break; - } - } - } - } - - SMLoc E = getLoc(); - if (Parser.getTok().isNot(AsmToken::RBrac)) - return Error(E, "']' expected"); - - Parser.Lex(); // Eat right bracket token. - - // Create the memory operand. - Operands.push_back( - ARM64Operand::CreateMem(Reg, OffsetExpr, S, E, OffsetLoc, getContext())); - - // Check for a '!', indicating pre-indexed addressing with writeback. - if (Parser.getTok().is(AsmToken::Exclaim)) { - // There needs to have been an immediate or wback doesn't make sense. - if (!OffsetExpr) - return Error(E, "missing offset for pre-indexed addressing"); - // Pre-indexed with writeback must have a constant expression for the - // offset. FIXME: Theoretically, we'd like to allow fixups so long - // as they don't require a relocation. - if (!isa<MCConstantExpr>(OffsetExpr)) - return Error(OffsetLoc, "constant immediate expression expected"); - - // Create the Token operand for the '!'. - Operands.push_back(ARM64Operand::CreateToken( - "!", false, Parser.getTok().getLoc(), getContext())); - Parser.Lex(); // Eat the '!' token. - } - - return false; -} - -bool ARM64AsmParser::parseSymbolicImmVal(const MCExpr *&ImmVal) { - bool HasELFModifier = false; - ARM64MCExpr::VariantKind RefKind; - - if (Parser.getTok().is(AsmToken::Colon)) { - Parser.Lex(); // Eat ':" - HasELFModifier = true; - - if (Parser.getTok().isNot(AsmToken::Identifier)) { - Error(Parser.getTok().getLoc(), - "expect relocation specifier in operand after ':'"); - return true; - } - - std::string LowerCase = Parser.getTok().getIdentifier().lower(); - RefKind = StringSwitch<ARM64MCExpr::VariantKind>(LowerCase) - .Case("lo12", ARM64MCExpr::VK_LO12) - .Case("abs_g3", ARM64MCExpr::VK_ABS_G3) - .Case("abs_g2", ARM64MCExpr::VK_ABS_G2) - .Case("abs_g2_nc", ARM64MCExpr::VK_ABS_G2_NC) - .Case("abs_g1", ARM64MCExpr::VK_ABS_G1) - .Case("abs_g1_nc", ARM64MCExpr::VK_ABS_G1_NC) - .Case("abs_g0", ARM64MCExpr::VK_ABS_G0) - .Case("abs_g0_nc", ARM64MCExpr::VK_ABS_G0_NC) - .Case("dtprel_g2", ARM64MCExpr::VK_DTPREL_G2) - .Case("dtprel_g1", ARM64MCExpr::VK_DTPREL_G1) - .Case("dtprel_g1_nc", ARM64MCExpr::VK_DTPREL_G1_NC) - .Case("dtprel_g0", ARM64MCExpr::VK_DTPREL_G0) - .Case("dtprel_g0_nc", ARM64MCExpr::VK_DTPREL_G0_NC) - .Case("dtprel_lo12", ARM64MCExpr::VK_DTPREL_LO12) - .Case("dtprel_lo12_nc", ARM64MCExpr::VK_DTPREL_LO12_NC) - .Case("tprel_g2", ARM64MCExpr::VK_TPREL_G2) - .Case("tprel_g1", ARM64MCExpr::VK_TPREL_G1) - .Case("tprel_g1_nc", ARM64MCExpr::VK_TPREL_G1_NC) - .Case("tprel_g0", ARM64MCExpr::VK_TPREL_G0) - .Case("tprel_g0_nc", ARM64MCExpr::VK_TPREL_G0_NC) - .Case("tprel_lo12", ARM64MCExpr::VK_TPREL_LO12) - .Case("tprel_lo12_nc", ARM64MCExpr::VK_TPREL_LO12_NC) - .Case("tlsdesc_lo12", ARM64MCExpr::VK_TLSDESC_LO12) - .Case("got", ARM64MCExpr::VK_GOT_PAGE) - .Case("got_lo12", ARM64MCExpr::VK_GOT_LO12) - .Case("gottprel", ARM64MCExpr::VK_GOTTPREL_PAGE) - .Case("gottprel_lo12", ARM64MCExpr::VK_GOTTPREL_LO12_NC) - .Case("gottprel_g1", ARM64MCExpr::VK_GOTTPREL_G1) - .Case("gottprel_g0_nc", ARM64MCExpr::VK_GOTTPREL_G0_NC) - .Case("tlsdesc", ARM64MCExpr::VK_TLSDESC_PAGE) - .Default(ARM64MCExpr::VK_INVALID); - - if (RefKind == ARM64MCExpr::VK_INVALID) { - Error(Parser.getTok().getLoc(), - "expect relocation specifier in operand after ':'"); - return true; - } - - Parser.Lex(); // Eat identifier - - if (Parser.getTok().isNot(AsmToken::Colon)) { - Error(Parser.getTok().getLoc(), "expect ':' after relocation specifier"); - return true; - } - Parser.Lex(); // Eat ':' - } - - if (getParser().parseExpression(ImmVal)) - return true; - - if (HasELFModifier) - ImmVal = ARM64MCExpr::Create(ImmVal, RefKind, getContext()); - - return false; -} - -/// parseVectorList - Parse a vector list operand for AdvSIMD instructions. -bool ARM64AsmParser::parseVectorList(OperandVector &Operands) { - assert(Parser.getTok().is(AsmToken::LCurly) && "Token is not a Left Bracket"); - SMLoc S = getLoc(); - Parser.Lex(); // Eat left bracket token. - StringRef Kind; - int64_t FirstReg = tryMatchVectorRegister(Kind); - if (FirstReg == -1) - return Error(getLoc(), "vector register expected"); - int64_t PrevReg = FirstReg; - unsigned Count = 1; - while (Parser.getTok().isNot(AsmToken::RCurly)) { - if (Parser.getTok().is(AsmToken::EndOfStatement)) - Error(getLoc(), "'}' expected"); - - if (Parser.getTok().isNot(AsmToken::Comma)) - return Error(getLoc(), "',' expected"); - Parser.Lex(); // Eat the comma token. - - SMLoc Loc = getLoc(); - StringRef NextKind; - int64_t Reg = tryMatchVectorRegister(NextKind); - if (Reg == -1) - return Error(Loc, "vector register expected"); - // Any Kind suffices must match on all regs in the list. - if (Kind != NextKind) - return Error(Loc, "mismatched register size suffix"); - - // Registers must be incremental (with wraparound at 31) - if (getContext().getRegisterInfo()->getEncodingValue(Reg) != - (getContext().getRegisterInfo()->getEncodingValue(PrevReg) + 1) % 32) - return Error(Loc, "registers must be sequential"); - - PrevReg = Reg; - ++Count; - } - Parser.Lex(); // Eat the '}' token. - - unsigned NumElements = 0; - char ElementKind = 0; - if (!Kind.empty()) - parseValidVectorKind(Kind, NumElements, ElementKind); - - Operands.push_back(ARM64Operand::CreateVectorList( - FirstReg, Count, NumElements, ElementKind, S, getLoc(), getContext())); - - // If there is an index specifier following the list, parse that too. - if (Parser.getTok().is(AsmToken::LBrac)) { - SMLoc SIdx = getLoc(); - Parser.Lex(); // Eat left bracket token. - - const MCExpr *ImmVal; - if (getParser().parseExpression(ImmVal)) - return false; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal); - if (!MCE) { - TokError("immediate value expected for vector index"); - return false; - } - - SMLoc E = getLoc(); - if (Parser.getTok().isNot(AsmToken::RBrac)) { - Error(E, "']' expected"); - return false; - } - - Parser.Lex(); // Eat right bracket token. - - Operands.push_back(ARM64Operand::CreateVectorIndex(MCE->getValue(), SIdx, E, - getContext())); - } - return false; -} - -/// parseOperand - Parse a arm instruction operand. For now this parses the -/// operand regardless of the mnemonic. -bool ARM64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode, - bool invertCondCode) { - // Check if the current operand has a custom associated parser, if so, try to - // custom parse the operand, or fallback to the general approach. - OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); - 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(ARM64Operand::CreateImm(Expr, S, E, getContext())); - return false; - } - case AsmToken::LBrac: - return parseMemory(Operands); - case AsmToken::LCurly: - return parseVectorList(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; - - // This could be an optional "shift" operand. - if (!parseOptionalShift(Operands)) - return false; - - // Or maybe it could be an optional "extend" operand. - if (!parseOptionalExtend(Operands)) - 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(ARM64Operand::CreateImm(IdVal, S, E, getContext())); - return false; - } - case AsmToken::Hash: { - // #42 -> immediate. - S = getLoc(); - 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 (IntVal != 0 || (Mnemonic != "fcmp" && Mnemonic != "fcmpe")) - return TokError("unexpected floating point literal"); - Parser.Lex(); // Eat the token. - - Operands.push_back( - ARM64Operand::CreateToken("#0", false, S, getContext())); - Operands.push_back( - ARM64Operand::CreateToken(".0", false, S, getContext())); - return false; - } - - const MCExpr *ImmVal; - if (parseSymbolicImmVal(ImmVal)) - return true; - - E = SMLoc::getFromPointer(getLoc().getPointer() - 1); - Operands.push_back(ARM64Operand::CreateImm(ImmVal, S, E, getContext())); - return false; - } - } -} - -/// ParseInstruction - Parse an ARM64 instruction mnemonic followed by its -/// operands. -bool ARM64AsmParser::ParseInstruction(ParseInstructionInfo &Info, - StringRef Name, SMLoc NameLoc, - OperandVector &Operands) { - // 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, and TLBI instructions are aliases for the SYS instruction. - if (Head == "ic" || Head == "dc" || Head == "at" || Head == "tlbi") - return parseSysAlias(Head, NameLoc, Operands); - - Operands.push_back( - ARM64Operand::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())); - unsigned CC = parseCondCodeString(Head); - if (CC == ~0U) - return Error(SuffixLoc, "invalid condition code"); - const MCExpr *CCExpr = MCConstantExpr::Create(CC, getContext()); - Operands.push_back( - ARM64Operand::CreateImm(CCExpr, 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( - ARM64Operand::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)) { - // Read the first operand. - if (parseOperand(Operands, false, false)) { - Parser.eatToEndOfStatement(); - return true; - } - - unsigned N = 2; - while (getLexer().is(AsmToken::Comma)) { - Parser.Lex(); // Eat the comma. - - // Parse and remember the operand. - if (parseOperand(Operands, (N == 4 && condCodeFourthOperand) || - (N == 3 && condCodeThirdOperand) || - (N == 2 && condCodeSecondOperand), - condCodeSecondOperand || condCodeThirdOperand)) { - Parser.eatToEndOfStatement(); - return true; - } - - ++N; - } - } - - if (getLexer().isNot(AsmToken::EndOfStatement)) { - SMLoc Loc = Parser.getTok().getLoc(); - Parser.eatToEndOfStatement(); - return Error(Loc, "unexpected token in argument list"); - } - - Parser.Lex(); // Consume the EndOfStatement - return false; -} - -/// isFPR32Register - Check if a register is in the FPR32 register class. -/// (The parser does not have the target register info to check the register -/// class directly.) -static bool isFPR32Register(unsigned Reg) { - using namespace ARM64; - switch (Reg) { - default: - break; - case S0: case S1: case S2: case S3: case S4: case S5: case S6: - case S7: case S8: case S9: case S10: case S11: case S12: case S13: - case S14: case S15: case S16: case S17: case S18: case S19: case S20: - case S21: case S22: case S23: case S24: case S25: case S26: case S27: - case S28: case S29: case S30: case S31: - return true; - } - return false; -} - -/// isGPR32Register - Check if a register is in the GPR32sp register class. -/// (The parser does not have the target register info to check the register -/// class directly.) -static bool isGPR32Register(unsigned Reg) { - using namespace ARM64; - switch (Reg) { - default: - break; - case W0: case W1: case W2: case W3: case W4: case W5: case W6: - case W7: case W8: case W9: case W10: case W11: case W12: case W13: - case W14: case W15: case W16: case W17: case W18: case W19: case W20: - case W21: case W22: case W23: case W24: case W25: case W26: case W27: - case W28: case W29: case W30: case WSP: - return true; - } - return false; -} - -static bool isGPR64Reg(unsigned Reg) { - using namespace ARM64; - switch (Reg) { - case X0: case X1: case X2: case X3: case X4: case X5: case X6: - case X7: case X8: case X9: case X10: case X11: case X12: case X13: - case X14: case X15: case X16: case X17: case X18: case X19: case X20: - case X21: case X22: case X23: case X24: case X25: case X26: case X27: - case X28: case FP: case LR: case SP: case XZR: - return true; - default: - return false; - } -} - - -// 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 ARM64AsmParser::validateInstruction(MCInst &Inst, - SmallVectorImpl<SMLoc> &Loc) { - const MCRegisterInfo *RI = getContext().getRegisterInfo(); - // 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 ARM64::LDPSWpre: - case ARM64::LDPWpost: - case ARM64::LDPWpre: - case ARM64::LDPXpost: - case ARM64::LDPXpre: { - unsigned Rt = Inst.getOperand(0).getReg(); - unsigned Rt2 = Inst.getOperand(1).getReg(); - unsigned Rn = Inst.getOperand(2).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"); - // FALLTHROUGH - } - case ARM64::LDPDpost: - case ARM64::LDPDpre: - case ARM64::LDPQpost: - case ARM64::LDPQpre: - case ARM64::LDPSpost: - case ARM64::LDPSpre: - case ARM64::LDPSWpost: - case ARM64::LDPDi: - case ARM64::LDPQi: - case ARM64::LDPSi: - case ARM64::LDPSWi: - case ARM64::LDPWi: - case ARM64::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 ARM64::STPDpost: - case ARM64::STPDpre: - case ARM64::STPQpost: - case ARM64::STPQpre: - case ARM64::STPSpost: - case ARM64::STPSpre: - case ARM64::STPWpost: - case ARM64::STPWpre: - case ARM64::STPXpost: - case ARM64::STPXpre: { - unsigned Rt = Inst.getOperand(0).getReg(); - unsigned Rt2 = Inst.getOperand(1).getReg(); - unsigned Rn = Inst.getOperand(2).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 ARM64::LDRBBpre: - case ARM64::LDRBpre: - case ARM64::LDRHHpre: - case ARM64::LDRHpre: - case ARM64::LDRSBWpre: - case ARM64::LDRSBXpre: - case ARM64::LDRSHWpre: - case ARM64::LDRSHXpre: - case ARM64::LDRSWpre: - case ARM64::LDRWpre: - case ARM64::LDRXpre: - case ARM64::LDRBBpost: - case ARM64::LDRBpost: - case ARM64::LDRHHpost: - case ARM64::LDRHpost: - case ARM64::LDRSBWpost: - case ARM64::LDRSBXpost: - case ARM64::LDRSHWpost: - case ARM64::LDRSHXpost: - case ARM64::LDRSWpost: - case ARM64::LDRWpost: - case ARM64::LDRXpost: { - unsigned Rt = Inst.getOperand(0).getReg(); - unsigned Rn = Inst.getOperand(1).getReg(); - if (RI->isSubRegisterEq(Rn, Rt)) - return Error(Loc[0], "unpredictable LDR instruction, writeback base " - "is also a source"); - break; - } - case ARM64::STRBBpost: - case ARM64::STRBpost: - case ARM64::STRHHpost: - case ARM64::STRHpost: - case ARM64::STRWpost: - case ARM64::STRXpost: - case ARM64::STRBBpre: - case ARM64::STRBpre: - case ARM64::STRHHpre: - case ARM64::STRHpre: - case ARM64::STRWpre: - case ARM64::STRXpre: { - unsigned Rt = Inst.getOperand(0).getReg(); - unsigned Rn = Inst.getOperand(1).getReg(); - if (RI->isSubRegisterEq(Rn, Rt)) - return Error(Loc[0], "unpredictable STR instruction, writeback base " - "is also a source"); - 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 ARM64::ANDWrs: - case ARM64::ANDSWrs: - case ARM64::EORWrs: - case ARM64::ORRWrs: { - if (!Inst.getOperand(3).isImm()) - return Error(Loc[3], "immediate value expected"); - int64_t shifter = Inst.getOperand(3).getImm(); - ARM64_AM::ShiftType ST = ARM64_AM::getShiftType(shifter); - if (ST == ARM64_AM::LSL && shifter > 31) - return Error(Loc[3], "shift value out of range"); - return false; - } - case ARM64::ADDSWri: - case ARM64::ADDSXri: - case ARM64::ADDWri: - case ARM64::ADDXri: - case ARM64::SUBSWri: - case ARM64::SUBSXri: - case ARM64::SUBWri: - case ARM64::SUBXri: { - if (!Inst.getOperand(3).isImm()) - return Error(Loc[3], "immediate value expected"); - int64_t shifter = Inst.getOperand(3).getImm(); - if (shifter != 0 && shifter != 12) - return Error(Loc[3], "shift value out of range"); - // The imm12 operand can be an expression. Validate that it's legit. - // FIXME: We really, really want to allow arbitrary expressions here - // and resolve the value and validate the result at fixup time, but - // that's hard as we have long since lost any source information we - // need to generate good diagnostics by that point. - if (Inst.getOpcode() == ARM64::ADDXri && Inst.getOperand(2).isExpr()) { - const MCExpr *Expr = Inst.getOperand(2).getExpr(); - ARM64MCExpr::VariantKind ELFRefKind; - MCSymbolRefExpr::VariantKind DarwinRefKind; - const MCConstantExpr *Addend; - if (!classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { - return Error(Loc[2], "invalid immediate expression"); - } - - if (DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF || - DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF || - ELFRefKind == ARM64MCExpr::VK_LO12 || - ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12 || - ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12_NC || - ELFRefKind == ARM64MCExpr::VK_TPREL_LO12 || - ELFRefKind == ARM64MCExpr::VK_TPREL_LO12_NC || - ELFRefKind == ARM64MCExpr::VK_TLSDESC_LO12) { - // 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. Any validity checking for the value - // was done in the is*() predicate function. - return false; - } else if (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF) { - // @gotpageoff can only be used directly, not with an addend. - return Addend != 0; - } - - // Otherwise, we're not sure, so don't allow it for now. - return Error(Loc[2], "invalid immediate expression"); - } - - // If it's anything but an immediate, it's not legit. - if (!Inst.getOperand(2).isImm()) - return Error(Loc[2], "invalid immediate expression"); - int64_t imm = Inst.getOperand(2).getImm(); - if (imm > 4095 || imm < 0) - return Error(Loc[2], "immediate value out of range"); - return false; - } - case ARM64::LDRBpre: - case ARM64::LDRHpre: - case ARM64::LDRSBWpre: - case ARM64::LDRSBXpre: - case ARM64::LDRSHWpre: - case ARM64::LDRSHXpre: - case ARM64::LDRWpre: - case ARM64::LDRXpre: - case ARM64::LDRSpre: - case ARM64::LDRDpre: - case ARM64::LDRQpre: - case ARM64::STRBpre: - case ARM64::STRHpre: - case ARM64::STRWpre: - case ARM64::STRXpre: - case ARM64::STRSpre: - case ARM64::STRDpre: - case ARM64::STRQpre: - case ARM64::LDRBpost: - case ARM64::LDRHpost: - case ARM64::LDRSBWpost: - case ARM64::LDRSBXpost: - case ARM64::LDRSHWpost: - case ARM64::LDRSHXpost: - case ARM64::LDRWpost: - case ARM64::LDRXpost: - case ARM64::LDRSpost: - case ARM64::LDRDpost: - case ARM64::LDRQpost: - case ARM64::STRBpost: - case ARM64::STRHpost: - case ARM64::STRWpost: - case ARM64::STRXpost: - case ARM64::STRSpost: - case ARM64::STRDpost: - case ARM64::STRQpost: - case ARM64::LDTRXi: - case ARM64::LDTRWi: - case ARM64::LDTRHi: - case ARM64::LDTRBi: - case ARM64::LDTRSHWi: - case ARM64::LDTRSHXi: - case ARM64::LDTRSBWi: - case ARM64::LDTRSBXi: - case ARM64::LDTRSWi: - case ARM64::STTRWi: - case ARM64::STTRXi: - case ARM64::STTRHi: - case ARM64::STTRBi: - case ARM64::LDURWi: - case ARM64::LDURXi: - case ARM64::LDURSi: - case ARM64::LDURDi: - case ARM64::LDURQi: - case ARM64::LDURHi: - case ARM64::LDURBi: - case ARM64::LDURSHWi: - case ARM64::LDURSHXi: - case ARM64::LDURSBWi: - case ARM64::LDURSBXi: - case ARM64::LDURSWi: - case ARM64::PRFUMi: - case ARM64::STURWi: - case ARM64::STURXi: - case ARM64::STURSi: - case ARM64::STURDi: - case ARM64::STURQi: - case ARM64::STURHi: - case ARM64::STURBi: { - // FIXME: Should accept expressions and error in fixup evaluation - // if out of range. - if (!Inst.getOperand(2).isImm()) - return Error(Loc[1], "immediate value expected"); - int64_t offset = Inst.getOperand(2).getImm(); - if (offset > 255 || offset < -256) - return Error(Loc[1], "offset value out of range"); - return false; - } - case ARM64::LDRSro: - case ARM64::LDRWro: - case ARM64::LDRSWro: - case ARM64::STRWro: - case ARM64::STRSro: { - // FIXME: Should accept expressions and error in fixup evaluation - // if out of range. - if (!Inst.getOperand(3).isImm()) - return Error(Loc[1], "immediate value expected"); - int64_t shift = Inst.getOperand(3).getImm(); - ARM64_AM::ExtendType type = ARM64_AM::getMemExtendType(shift); - if (type != ARM64_AM::UXTW && type != ARM64_AM::UXTX && - type != ARM64_AM::SXTW && type != ARM64_AM::SXTX) - return Error(Loc[1], "shift type invalid"); - return false; - } - case ARM64::LDRDro: - case ARM64::LDRQro: - case ARM64::LDRXro: - case ARM64::PRFMro: - case ARM64::STRXro: - case ARM64::STRDro: - case ARM64::STRQro: { - // FIXME: Should accept expressions and error in fixup evaluation - // if out of range. - if (!Inst.getOperand(3).isImm()) - return Error(Loc[1], "immediate value expected"); - int64_t shift = Inst.getOperand(3).getImm(); - ARM64_AM::ExtendType type = ARM64_AM::getMemExtendType(shift); - if (type != ARM64_AM::UXTW && type != ARM64_AM::UXTX && - type != ARM64_AM::SXTW && type != ARM64_AM::SXTX) - return Error(Loc[1], "shift type invalid"); - return false; - } - case ARM64::LDRHro: - case ARM64::LDRHHro: - case ARM64::LDRSHWro: - case ARM64::LDRSHXro: - case ARM64::STRHro: - case ARM64::STRHHro: { - // FIXME: Should accept expressions and error in fixup evaluation - // if out of range. - if (!Inst.getOperand(3).isImm()) - return Error(Loc[1], "immediate value expected"); - int64_t shift = Inst.getOperand(3).getImm(); - ARM64_AM::ExtendType type = ARM64_AM::getMemExtendType(shift); - if (type != ARM64_AM::UXTW && type != ARM64_AM::UXTX && - type != ARM64_AM::SXTW && type != ARM64_AM::SXTX) - return Error(Loc[1], "shift type invalid"); - return false; - } - case ARM64::LDRBro: - case ARM64::LDRBBro: - case ARM64::LDRSBWro: - case ARM64::LDRSBXro: - case ARM64::STRBro: - case ARM64::STRBBro: { - // FIXME: Should accept expressions and error in fixup evaluation - // if out of range. - if (!Inst.getOperand(3).isImm()) - return Error(Loc[1], "immediate value expected"); - int64_t shift = Inst.getOperand(3).getImm(); - ARM64_AM::ExtendType type = ARM64_AM::getMemExtendType(shift); - if (type != ARM64_AM::UXTW && type != ARM64_AM::UXTX && - type != ARM64_AM::SXTW && type != ARM64_AM::SXTX) - return Error(Loc[1], "shift type invalid"); - return false; - } - case ARM64::LDPWi: - case ARM64::LDPXi: - case ARM64::LDPSi: - case ARM64::LDPDi: - case ARM64::LDPQi: - case ARM64::LDPSWi: - case ARM64::STPWi: - case ARM64::STPXi: - case ARM64::STPSi: - case ARM64::STPDi: - case ARM64::STPQi: - case ARM64::LDPWpre: - case ARM64::LDPXpre: - case ARM64::LDPSpre: - case ARM64::LDPDpre: - case ARM64::LDPQpre: - case ARM64::LDPSWpre: - case ARM64::STPWpre: - case ARM64::STPXpre: - case ARM64::STPSpre: - case ARM64::STPDpre: - case ARM64::STPQpre: - case ARM64::LDPWpost: - case ARM64::LDPXpost: - case ARM64::LDPSpost: - case ARM64::LDPDpost: - case ARM64::LDPQpost: - case ARM64::LDPSWpost: - case ARM64::STPWpost: - case ARM64::STPXpost: - case ARM64::STPSpost: - case ARM64::STPDpost: - case ARM64::STPQpost: - case ARM64::LDNPWi: - case ARM64::LDNPXi: - case ARM64::LDNPSi: - case ARM64::LDNPDi: - case ARM64::LDNPQi: - case ARM64::STNPWi: - case ARM64::STNPXi: - case ARM64::STNPSi: - case ARM64::STNPDi: - case ARM64::STNPQi: { - // FIXME: Should accept expressions and error in fixup evaluation - // if out of range. - if (!Inst.getOperand(3).isImm()) - return Error(Loc[2], "immediate value expected"); - int64_t offset = Inst.getOperand(3).getImm(); - if (offset > 63 || offset < -64) - return Error(Loc[2], "offset value out of range"); - return false; - } - default: - return false; - } -} - -static void rewriteMOV(ARM64AsmParser::OperandVector &Operands, - StringRef mnemonic, uint64_t imm, unsigned shift, - MCContext &Context) { - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[0]); - ARM64Operand *Op2 = static_cast<ARM64Operand *>(Operands[2]); - Operands[0] = - ARM64Operand::CreateToken(mnemonic, false, Op->getStartLoc(), Context); - - const MCExpr *NewImm = MCConstantExpr::Create(imm >> shift, Context); - Operands[2] = ARM64Operand::CreateImm(NewImm, Op2->getStartLoc(), - Op2->getEndLoc(), Context); - - Operands.push_back(ARM64Operand::CreateShifter( - ARM64_AM::LSL, shift, Op2->getStartLoc(), Op2->getEndLoc(), Context)); - delete Op2; - delete Op; -} - -bool ARM64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode) { - switch (ErrCode) { - 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_InvalidMemoryIndexedSImm9: - return Error(Loc, "index must be an integer in range [-256,255]."); - case Match_InvalidMemoryIndexed32SImm7: - return Error(Loc, "index must be a multiple of 4 in range [-256,252]."); - case Match_InvalidMemoryIndexed64SImm7: - return Error(Loc, "index must be a multiple of 8 in range [-512,504]."); - case Match_InvalidMemoryIndexed128SImm7: - return Error(Loc, "index must be a multiple of 16 in range [-1024,1008]."); - case Match_InvalidMemoryIndexed8: - return Error(Loc, "index must be an integer in range [0,4095]."); - case Match_InvalidMemoryIndexed16: - return Error(Loc, "index must be a multiple of 2 in range [0,8190]."); - case Match_InvalidMemoryIndexed32: - return Error(Loc, "index must be a multiple of 4 in range [0,16380]."); - case Match_InvalidMemoryIndexed64: - return Error(Loc, "index must be a multiple of 8 in range [0,32760]."); - case Match_InvalidMemoryIndexed128: - return Error(Loc, "index must be a multiple of 16 in range [0,65520]."); - 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_MnemonicFail: - return Error(Loc, "unrecognized instruction mnemonic"); - default: - assert(0 && "unexpected error code!"); - return Error(Loc, "invalid instruction format"); - } -} - -bool ARM64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, - OperandVector &Operands, - MCStreamer &Out, - unsigned &ErrorInfo, - bool MatchingInlineAsm) { - assert(!Operands.empty() && "Unexpect empty operand list!"); - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[0]); - assert(Op->isToken() && "Leading operand should always be a mnemonic!"); - - StringRef Tok = Op->getToken(); - // Translate CMN/CMP pseudos to ADDS/SUBS with zero register destination. - // This needs to be done before the special handling of ADD/SUB immediates. - if (Tok == "cmp" || Tok == "cmn") { - // Replace the opcode with either ADDS or SUBS. - const char *Repl = StringSwitch<const char *>(Tok) - .Case("cmp", "subs") - .Case("cmn", "adds") - .Default(0); - assert(Repl && "Unknown compare instruction"); - delete Operands[0]; - Operands[0] = ARM64Operand::CreateToken(Repl, false, IDLoc, getContext()); - - // Insert WZR or XZR as destination operand. - ARM64Operand *RegOp = static_cast<ARM64Operand *>(Operands[1]); - unsigned ZeroReg; - if (RegOp->isReg() && - (isGPR32Register(RegOp->getReg()) || RegOp->getReg() == ARM64::WZR)) - ZeroReg = ARM64::WZR; - else - ZeroReg = ARM64::XZR; - Operands.insert( - Operands.begin() + 1, - ARM64Operand::CreateReg(ZeroReg, false, IDLoc, IDLoc, getContext())); - // Update since we modified it above. - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[0]); - Tok = Op->getToken(); - } - - unsigned NumOperands = Operands.size(); - - if (Tok == "mov" && NumOperands == 3) { - // The MOV mnemomic is aliased to movn/movz, depending on the value of - // the immediate being instantiated. - // FIXME: Catching this here is a total hack, and we should use tblgen - // support to implement this instead as soon as it is available. - - ARM64Operand *Op2 = static_cast<ARM64Operand *>(Operands[2]); - if (Op2->isImm()) { - if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op2->getImm())) { - uint64_t Val = CE->getValue(); - uint64_t NVal = ~Val; - - // If this is a 32-bit register and the value has none of the upper - // set, clear the complemented upper 32-bits so the logic below works - // for 32-bit registers too. - ARM64Operand *Op1 = static_cast<ARM64Operand *>(Operands[1]); - if (Op1->isReg() && isGPR32Register(Op1->getReg()) && - (Val & 0xFFFFFFFFULL) == Val) - NVal &= 0x00000000FFFFFFFFULL; - - // MOVK Rd, imm << 0 - if ((Val & 0xFFFF) == Val) - rewriteMOV(Operands, "movz", Val, 0, getContext()); - - // MOVK Rd, imm << 16 - else if ((Val & 0xFFFF0000ULL) == Val) - rewriteMOV(Operands, "movz", Val, 16, getContext()); - - // MOVK Rd, imm << 32 - else if ((Val & 0xFFFF00000000ULL) == Val) - rewriteMOV(Operands, "movz", Val, 32, getContext()); - - // MOVK Rd, imm << 48 - else if ((Val & 0xFFFF000000000000ULL) == Val) - rewriteMOV(Operands, "movz", Val, 48, getContext()); - - // MOVN Rd, (~imm << 0) - else if ((NVal & 0xFFFFULL) == NVal) - rewriteMOV(Operands, "movn", NVal, 0, getContext()); - - // MOVN Rd, ~(imm << 16) - else if ((NVal & 0xFFFF0000ULL) == NVal) - rewriteMOV(Operands, "movn", NVal, 16, getContext()); - - // MOVN Rd, ~(imm << 32) - else if ((NVal & 0xFFFF00000000ULL) == NVal) - rewriteMOV(Operands, "movn", NVal, 32, getContext()); - - // MOVN Rd, ~(imm << 48) - else if ((NVal & 0xFFFF000000000000ULL) == NVal) - rewriteMOV(Operands, "movn", NVal, 48, getContext()); - } - } - } else if (NumOperands == 4) { - if (Tok == "add" || Tok == "adds" || Tok == "sub" || Tok == "subs") { - // Handle the uimm24 immediate form, where the shift is not specified. - ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]); - if (Op3->isImm()) { - if (const MCConstantExpr *CE = - dyn_cast<MCConstantExpr>(Op3->getImm())) { - uint64_t Val = CE->getValue(); - if (Val >= (1 << 24)) { - Error(IDLoc, "immediate value is too large"); - return true; - } - if (Val < (1 << 12)) { - Operands.push_back(ARM64Operand::CreateShifter( - ARM64_AM::LSL, 0, IDLoc, IDLoc, getContext())); - } else if ((Val & 0xfff) == 0) { - delete Operands[3]; - CE = MCConstantExpr::Create(Val >> 12, getContext()); - Operands[3] = - ARM64Operand::CreateImm(CE, IDLoc, IDLoc, getContext()); - Operands.push_back(ARM64Operand::CreateShifter( - ARM64_AM::LSL, 12, IDLoc, IDLoc, getContext())); - } else { - Error(IDLoc, "immediate value is too large"); - return true; - } - } else { - Operands.push_back(ARM64Operand::CreateShifter( - ARM64_AM::LSL, 0, IDLoc, IDLoc, getContext())); - } - } - - // FIXME: Horible hack to handle the LSL -> UBFM alias. - } else if (NumOperands == 4 && Tok == "lsl") { - ARM64Operand *Op2 = static_cast<ARM64Operand *>(Operands[2]); - ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]); - if (Op2->isReg() && 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 (isGPR32Register(Op2->getReg()) || Op2->getReg() == ARM64::WZR) { - 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] = ARM64Operand::CreateToken( - "ubfm", false, Op->getStartLoc(), getContext()); - Operands[3] = ARM64Operand::CreateImm(NewOp3, Op3->getStartLoc(), - Op3->getEndLoc(), getContext()); - Operands.push_back(ARM64Operand::CreateImm( - NewOp4, Op3->getStartLoc(), Op3->getEndLoc(), getContext())); - delete Op3; - delete Op; - } - } - - // FIXME: Horrible hack to handle the optional LSL shift for vector - // instructions. - } else if (NumOperands == 4 && (Tok == "bic" || Tok == "orr")) { - ARM64Operand *Op1 = static_cast<ARM64Operand *>(Operands[1]); - ARM64Operand *Op2 = static_cast<ARM64Operand *>(Operands[2]); - ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]); - if ((Op1->isToken() && Op2->isVectorReg() && Op3->isImm()) || - (Op1->isVectorReg() && Op2->isToken() && Op3->isImm())) - Operands.push_back(ARM64Operand::CreateShifter(ARM64_AM::LSL, 0, IDLoc, - IDLoc, getContext())); - } else if (NumOperands == 4 && (Tok == "movi" || Tok == "mvni")) { - ARM64Operand *Op1 = static_cast<ARM64Operand *>(Operands[1]); - ARM64Operand *Op2 = static_cast<ARM64Operand *>(Operands[2]); - ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]); - if ((Op1->isToken() && Op2->isVectorReg() && Op3->isImm()) || - (Op1->isVectorReg() && Op2->isToken() && Op3->isImm())) { - StringRef Suffix = Op1->isToken() ? Op1->getToken() : Op2->getToken(); - // Canonicalize on lower-case for ease of comparison. - std::string CanonicalSuffix = Suffix.lower(); - if (Tok != "movi" || - (CanonicalSuffix != ".1d" && CanonicalSuffix != ".2d" && - CanonicalSuffix != ".8b" && CanonicalSuffix != ".16b")) - Operands.push_back(ARM64Operand::CreateShifter( - ARM64_AM::LSL, 0, IDLoc, IDLoc, 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") { - ARM64Operand *Op1 = static_cast<ARM64Operand *>(Operands[1]); - ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]); - ARM64Operand *Op4 = static_cast<ARM64Operand *>(Operands[4]); - - if (Op1->isReg() && 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 NewOp3Val = 0; - if (isGPR32Register(Op1->getReg())) - NewOp3Val = (32 - Op3Val) & 0x1f; - else - NewOp3Val = (64 - Op3Val) & 0x3f; - - uint64_t NewOp4Val = Op4Val - 1; - - const MCExpr *NewOp3 = - MCConstantExpr::Create(NewOp3Val, getContext()); - const MCExpr *NewOp4 = - MCConstantExpr::Create(NewOp4Val, getContext()); - Operands[3] = ARM64Operand::CreateImm(NewOp3, Op3->getStartLoc(), - Op3->getEndLoc(), getContext()); - Operands[4] = ARM64Operand::CreateImm(NewOp4, Op4->getStartLoc(), - Op4->getEndLoc(), getContext()); - if (Tok == "bfi") - Operands[0] = ARM64Operand::CreateToken( - "bfm", false, Op->getStartLoc(), getContext()); - else if (Tok == "sbfiz") - Operands[0] = ARM64Operand::CreateToken( - "sbfm", false, Op->getStartLoc(), getContext()); - else if (Tok == "ubfiz") - Operands[0] = ARM64Operand::CreateToken( - "ubfm", false, Op->getStartLoc(), getContext()); - else - llvm_unreachable("No valid mnemonic for alias?"); - - delete Op; - delete Op3; - delete Op4; - } - } - - // FIXME: Horrible hack to handle the BFXIL->BFM, SBFX->SBFM, and - // UBFX -> UBFM aliases. - } else if (NumOperands == 5 && - (Tok == "bfxil" || Tok == "sbfx" || Tok == "ubfx")) { - ARM64Operand *Op1 = static_cast<ARM64Operand *>(Operands[1]); - ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]); - ARM64Operand *Op4 = static_cast<ARM64Operand *>(Operands[4]); - - if (Op1->isReg() && 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 NewOp4Val = Op3Val + Op4Val - 1; - - if (NewOp4Val >= Op3Val) { - const MCExpr *NewOp4 = - MCConstantExpr::Create(NewOp4Val, getContext()); - Operands[4] = ARM64Operand::CreateImm( - NewOp4, Op4->getStartLoc(), Op4->getEndLoc(), getContext()); - if (Tok == "bfxil") - Operands[0] = ARM64Operand::CreateToken( - "bfm", false, Op->getStartLoc(), getContext()); - else if (Tok == "sbfx") - Operands[0] = ARM64Operand::CreateToken( - "sbfm", false, Op->getStartLoc(), getContext()); - else if (Tok == "ubfx") - Operands[0] = ARM64Operand::CreateToken( - "ubfm", false, Op->getStartLoc(), getContext()); - else - llvm_unreachable("No valid mnemonic for alias?"); - - delete Op; - delete Op4; - } - } - } - } - } - // FIXME: Horrible hack for tbz and tbnz with Wn register operand. - // InstAlias can't quite handle this since the reg classes aren't - // subclasses. - if (NumOperands == 4 && (Tok == "tbz" || Tok == "tbnz")) { - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[2]); - if (Op->isImm()) { - if (const MCConstantExpr *OpCE = dyn_cast<MCConstantExpr>(Op->getImm())) { - if (OpCE->getValue() < 32) { - // The source register can be Wn here, but the matcher expects a - // GPR64. Twiddle it here if necessary. - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[1]); - if (Op->isReg()) { - unsigned Reg = getXRegFromWReg(Op->getReg()); - Operands[1] = ARM64Operand::CreateReg( - Reg, false, Op->getStartLoc(), Op->getEndLoc(), getContext()); - delete Op; - } - } - } - } - } - // 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. - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[2]); - if (Op->isReg()) { - unsigned Reg = getXRegFromWReg(Op->getReg()); - Operands[2] = ARM64Operand::CreateReg(Reg, false, Op->getStartLoc(), - Op->getEndLoc(), getContext()); - delete Op; - } - } - // FIXME: Likewise for [su]xt[bh] with a Xd dst operand - else if (NumOperands == 3 && - (Tok == "sxtb" || Tok == "uxtb" || Tok == "sxth" || Tok == "uxth")) { - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[1]); - if (Op->isReg() && isGPR64Reg(Op->getReg())) { - // The source register can be Wn here, but the matcher expects a - // GPR64. Twiddle it here if necessary. - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[2]); - if (Op->isReg()) { - unsigned Reg = getXRegFromWReg(Op->getReg()); - Operands[2] = ARM64Operand::CreateReg(Reg, false, Op->getStartLoc(), - Op->getEndLoc(), getContext()); - delete Op; - } - } - } - - // Yet another horrible hack to handle FMOV Rd, #0.0 using [WX]ZR. - if (NumOperands == 3 && Tok == "fmov") { - ARM64Operand *RegOp = static_cast<ARM64Operand *>(Operands[1]); - ARM64Operand *ImmOp = static_cast<ARM64Operand *>(Operands[2]); - if (RegOp->isReg() && ImmOp->isFPImm() && - ImmOp->getFPImm() == (unsigned)-1) { - unsigned zreg = - isFPR32Register(RegOp->getReg()) ? ARM64::WZR : ARM64::XZR; - Operands[2] = ARM64Operand::CreateReg(zreg, false, Op->getStartLoc(), - Op->getEndLoc(), getContext()); - delete ImmOp; - } - } - - // FIXME: Horrible hack to handle the literal .d[1] vector index on - // FMOV instructions. The index isn't an actual instruction operand - // but rather syntactic sugar. It really should be part of the mnemonic, - // not the operand, but whatever. - if ((NumOperands == 5) && Tok == "fmov") { - // If the last operand is a vectorindex of '1', then replace it with - // a '[' '1' ']' token sequence, which is what the matcher - // (annoyingly) expects for a literal vector index operand. - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[NumOperands - 1]); - if (Op->isVectorIndexD() && Op->getVectorIndex() == 1) { - SMLoc Loc = Op->getStartLoc(); - Operands.pop_back(); - Operands.push_back( - ARM64Operand::CreateToken("[", false, Loc, getContext())); - Operands.push_back( - ARM64Operand::CreateToken("1", false, Loc, getContext())); - Operands.push_back( - ARM64Operand::CreateToken("]", false, Loc, getContext())); - } else if (Op->isReg()) { - // Similarly, check the destination operand for the GPR->High-lane - // variant. - unsigned OpNo = NumOperands - 2; - ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[OpNo]); - if (Op->isVectorIndexD() && Op->getVectorIndex() == 1) { - SMLoc Loc = Op->getStartLoc(); - Operands[OpNo] = - ARM64Operand::CreateToken("[", false, Loc, getContext()); - Operands.insert( - Operands.begin() + OpNo + 1, - ARM64Operand::CreateToken("1", false, Loc, getContext())); - Operands.insert( - Operands.begin() + OpNo + 2, - ARM64Operand::CreateToken("]", false, Loc, getContext())); - } - } - } - - MCInst Inst; - // 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, 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) - MatchResult = - MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm, 0); - - 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, OperandLocs)) - return true; - - Inst.setLoc(IDLoc); - Out.EmitInstruction(Inst, STI); - return false; - } - case Match_MissingFeature: - case Match_MnemonicFail: - return showMatchError(IDLoc, MatchResult); - case Match_InvalidOperand: { - SMLoc ErrorLoc = IDLoc; - if (ErrorInfo != ~0U) { - if (ErrorInfo >= Operands.size()) - return Error(IDLoc, "too few operands for instruction"); - - ErrorLoc = ((ARM64Operand *)Operands[ErrorInfo])->getStartLoc(); - if (ErrorLoc == SMLoc()) - ErrorLoc = IDLoc; - } - // If the match failed on a suffix token operand, tweak the diagnostic - // accordingly. - if (((ARM64Operand *)Operands[ErrorInfo])->isToken() && - ((ARM64Operand *)Operands[ErrorInfo])->isTokenSuffix()) - MatchResult = Match_InvalidSuffix; - - return showMatchError(ErrorLoc, MatchResult); - } - case Match_InvalidMemoryIndexedSImm9: { - // If there is not a '!' after the memory operand that failed, we really - // want the diagnostic for the non-pre-indexed instruction variant instead. - // Be careful to check for the post-indexed variant as well, which also - // uses this match diagnostic. Also exclude the explicitly unscaled - // mnemonics, as they want the unscaled diagnostic as well. - if (Operands.size() == ErrorInfo + 1 && - !((ARM64Operand *)Operands[ErrorInfo])->isImm() && - !Tok.startswith("stur") && !Tok.startswith("ldur")) { - // whether we want an Indexed64 or Indexed32 diagnostic depends on - // the register class of the previous operand. Default to 64 in case - // we see something unexpected. - MatchResult = Match_InvalidMemoryIndexed64; - if (ErrorInfo) { - ARM64Operand *PrevOp = (ARM64Operand *)Operands[ErrorInfo - 1]; - if (PrevOp->isReg() && ARM64MCRegisterClasses[ARM64::GPR32RegClassID] - .contains(PrevOp->getReg())) - MatchResult = Match_InvalidMemoryIndexed32; - } - } - SMLoc ErrorLoc = ((ARM64Operand *)Operands[ErrorInfo])->getStartLoc(); - if (ErrorLoc == SMLoc()) - ErrorLoc = IDLoc; - return showMatchError(ErrorLoc, MatchResult); - } - case Match_InvalidMemoryIndexed32: - case Match_InvalidMemoryIndexed64: - case Match_InvalidMemoryIndexed128: - // If there is a '!' after the memory operand that failed, we really - // want the diagnostic for the pre-indexed instruction variant instead. - if (Operands.size() > ErrorInfo + 1 && - ((ARM64Operand *)Operands[ErrorInfo + 1])->isTokenEqual("!")) - MatchResult = Match_InvalidMemoryIndexedSImm9; - // FALL THROUGH - case Match_InvalidMemoryIndexed8: - case Match_InvalidMemoryIndexed16: - case Match_InvalidMemoryIndexed32SImm7: - case Match_InvalidMemoryIndexed64SImm7: - case Match_InvalidMemoryIndexed128SImm7: - case Match_InvalidImm1_8: - case Match_InvalidImm1_16: - case Match_InvalidImm1_32: - case Match_InvalidImm1_64: { - // Any time we get here, there's nothing fancy to do. Just get the - // operand SMLoc and display the diagnostic. - SMLoc ErrorLoc = ((ARM64Operand *)Operands[ErrorInfo])->getStartLoc(); - // If it's a memory operand, the error is with the offset immediate, - // so get that location instead. - if (((ARM64Operand *)Operands[ErrorInfo])->isMem()) - ErrorLoc = ((ARM64Operand *)Operands[ErrorInfo])->getOffsetLoc(); - if (ErrorLoc == SMLoc()) - ErrorLoc = IDLoc; - return showMatchError(ErrorLoc, MatchResult); - } - } - - llvm_unreachable("Implement any new match types added!"); - return true; -} - -/// ParseDirective parses the arm specific directives -bool ARM64AsmParser::ParseDirective(AsmToken DirectiveID) { - StringRef IDVal = DirectiveID.getIdentifier(); - SMLoc Loc = DirectiveID.getLoc(); - if (IDVal == ".hword") - return parseDirectiveWord(2, Loc); - if (IDVal == ".word") - return parseDirectiveWord(4, Loc); - if (IDVal == ".xword") - return parseDirectiveWord(8, Loc); - if (IDVal == ".tlsdesccall") - return parseDirectiveTLSDescCall(Loc); - - return parseDirectiveLOH(IDVal, Loc); -} - -/// parseDirectiveWord -/// ::= .word [ expression (, expression)* ] -bool ARM64AsmParser::parseDirectiveWord(unsigned Size, SMLoc L) { - if (getLexer().isNot(AsmToken::EndOfStatement)) { - for (;;) { - const MCExpr *Value; - if (getParser().parseExpression(Value)) - return true; - - getParser().getStreamer().EmitValue(Value, Size); - - if (getLexer().is(AsmToken::EndOfStatement)) - break; - - // FIXME: Improve diagnostic. - if (getLexer().isNot(AsmToken::Comma)) - return Error(L, "unexpected token in directive"); - Parser.Lex(); - } - } - - Parser.Lex(); - return false; -} - -// parseDirectiveTLSDescCall: -// ::= .tlsdesccall symbol -bool ARM64AsmParser::parseDirectiveTLSDescCall(SMLoc L) { - StringRef Name; - if (getParser().parseIdentifier(Name)) - return Error(L, "expected symbol after directive"); - - MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); - const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, getContext()); - Expr = ARM64MCExpr::Create(Expr, ARM64MCExpr::VK_TLSDESC, getContext()); - - MCInst Inst; - Inst.setOpcode(ARM64::TLSDESCCALL); - Inst.addOperand(MCOperand::CreateExpr(Expr)); - - getParser().getStreamer().EmitInstruction(Inst, STI); - return false; -} - -/// ::= .loh <lohName | lohId> label1, ..., labelN -/// The number of arguments depends on the loh identifier. -bool ARM64AsmParser::parseDirectiveLOH(StringRef IDVal, SMLoc Loc) { - if (IDVal != MCLOHDirectiveName()) - return true; - 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(); - Kind = (MCLOHType)Id; - // Check that Id does not overflow MCLOHType. - if (!isValidMCLOHType(Kind) || Id != Kind) - return TokError("invalid numeric identifier in directive"); - } 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 (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); - Lex(); - } - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); - - getStreamer().EmitLOHDirective((MCLOHType)Kind, Args); - return false; -} - -bool -ARM64AsmParser::classifySymbolRef(const MCExpr *Expr, - ARM64MCExpr::VariantKind &ELFRefKind, - MCSymbolRefExpr::VariantKind &DarwinRefKind, - const MCConstantExpr *&Addend) { - ELFRefKind = ARM64MCExpr::VK_INVALID; - DarwinRefKind = MCSymbolRefExpr::VK_None; - - if (const ARM64MCExpr *AE = dyn_cast<ARM64MCExpr>(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(); - Addend = 0; - return true; - } - - const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr); - if (!BE) - return false; - - SE = dyn_cast<MCSymbolRefExpr>(BE->getLHS()); - if (!SE) - return false; - DarwinRefKind = SE->getKind(); - - if (BE->getOpcode() != MCBinaryExpr::Add) - return false; - - // See if the addend is is a constant, otherwise there's more going - // on here than we can deal with. - Addend = dyn_cast<MCConstantExpr>(BE->getRHS()); - if (!Addend) - return false; - - // It's some symbol reference + a constant addend, but really - // shouldn't use both Darwin and ELF syntax. - return ELFRefKind == ARM64MCExpr::VK_INVALID || - DarwinRefKind == MCSymbolRefExpr::VK_None; -} - -/// Force static initialization. -extern "C" void LLVMInitializeARM64AsmParser() { - RegisterMCAsmParser<ARM64AsmParser> X(TheARM64Target); -} - -#define GET_REGISTER_MATCHER -#define GET_MATCHER_IMPLEMENTATION -#include "ARM64GenAsmMatcher.inc" - -// Define this matcher function after the auto-generated include so we -// have the match class enum definitions. -unsigned ARM64AsmParser::validateTargetOperandClass(MCParsedAsmOperand *AsmOp, - unsigned Kind) { - ARM64Operand *Op = static_cast<ARM64Operand *>(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__35_0: - ExpectedVal = 0; - break; - case MCK__35_1: - ExpectedVal = 1; - break; - case MCK__35_12: - ExpectedVal = 12; - break; - case MCK__35_16: - ExpectedVal = 16; - break; - case MCK__35_2: - ExpectedVal = 2; - break; - case MCK__35_24: - ExpectedVal = 24; - break; - case MCK__35_3: - ExpectedVal = 3; - break; - case MCK__35_32: - ExpectedVal = 32; - break; - case MCK__35_4: - ExpectedVal = 4; - break; - case MCK__35_48: - ExpectedVal = 48; - break; - case MCK__35_6: - ExpectedVal = 6; - break; - case MCK__35_64: - ExpectedVal = 64; - break; - case MCK__35_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; -} |