diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp | 1973 |
1 files changed, 1250 insertions, 723 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/contrib/llvm-project/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp index 013b7a0cf25d..af4a47935e3f 100644 --- a/contrib/llvm-project/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/contrib/llvm-project/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "AMDGPU.h" #include "AMDKernelCodeT.h" #include "MCTargetDesc/AMDGPUMCTargetDesc.h" #include "MCTargetDesc/AMDGPUTargetStreamer.h" @@ -17,49 +16,23 @@ #include "Utils/AMDGPUBaseInfo.h" #include "Utils/AMDKernelCodeTUtils.h" #include "llvm/ADT/APFloat.h" -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstrDesc.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCParser/MCAsmParserExtension.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/AMDGPUMetadata.h" #include "llvm/Support/AMDHSAKernelDescriptor.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Error.h" #include "llvm/Support/MachineValueType.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/SMLoc.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <cstring> -#include <iterator> -#include <map> -#include <memory> -#include <string> using namespace llvm; using namespace llvm::AMDGPU; @@ -188,6 +161,12 @@ public: ImmTyEndpgm, }; + enum ImmKindTy { + ImmKindTyNone, + ImmKindTyLiteral, + ImmKindTyConst, + }; + private: struct TokOp { const char *Data; @@ -198,6 +177,7 @@ private: int64_t Val; ImmTy Type; bool IsFPImm; + mutable ImmKindTy Kind; Modifiers Mods; }; @@ -233,6 +213,29 @@ public: return Kind == Immediate; } + void setImmKindNone() const { + assert(isImm()); + Imm.Kind = ImmKindTyNone; + } + + void setImmKindLiteral() const { + assert(isImm()); + Imm.Kind = ImmKindTyLiteral; + } + + void setImmKindConst() const { + assert(isImm()); + Imm.Kind = ImmKindTyConst; + } + + bool IsImmKindLiteral() const { + return isImm() && Imm.Kind == ImmKindTyLiteral; + } + + bool isImmKindConst() const { + return isImm() && Imm.Kind == ImmKindTyConst; + } + bool isInlinableImm(MVT type) const; bool isLiteralImm(MVT type) const; @@ -335,11 +338,14 @@ public: bool isLDS() const { return isImmTy(ImmTyLDS); } bool isDLC() const { return isImmTy(ImmTyDLC); } bool isGLC() const { return isImmTy(ImmTyGLC); } + // "GLC_1" is a MatchClass of the GLC_1 operand with the default and forced + // value of the GLC operand. + bool isGLC_1() const { return isImmTy(ImmTyGLC); } bool isSLC() const { return isImmTy(ImmTySLC); } bool isSWZ() const { return isImmTy(ImmTySWZ); } bool isTFE() const { return isImmTy(ImmTyTFE); } bool isD16() const { return isImmTy(ImmTyD16); } - bool isFORMAT() const { return isImmTy(ImmTyFORMAT) && isUInt<8>(getImm()); } + bool isFORMAT() const { return isImmTy(ImmTyFORMAT) && isUInt<7>(getImm()); } bool isBankMask() const { return isImmTy(ImmTyDppBankMask); } bool isRowMask() const { return isImmTy(ImmTyDppRowMask); } bool isBoundCtrl() const { return isImmTy(ImmTyDppBoundCtrl); } @@ -689,6 +695,11 @@ public: return Imm.Val; } + void setImm(int64_t Val) { + assert(isImm()); + Imm.Val = Val; + } + ImmTy getImmTy() const { assert(isImm()); return Imm.Type; @@ -903,6 +914,7 @@ public: auto Op = std::make_unique<AMDGPUOperand>(Immediate, AsmParser); Op->Imm.Val = Val; Op->Imm.IsFPImm = IsFPImm; + Op->Imm.Kind = ImmKindTyNone; Op->Imm.Type = Type; Op->Imm.Mods = Modifiers(); Op->StartLoc = Loc; @@ -1065,7 +1077,7 @@ private: std::string &CollectString); bool AddNextRegisterToList(unsigned& Reg, unsigned& RegWidth, - RegisterKind RegKind, unsigned Reg1); + RegisterKind RegKind, unsigned Reg1, SMLoc Loc); bool ParseAMDGPURegister(RegisterKind &RegKind, unsigned &Reg, unsigned &RegNum, unsigned &RegWidth, bool RestoreOnFailure = false); @@ -1083,7 +1095,8 @@ private: bool ParseRegRange(unsigned& Num, unsigned& Width); unsigned getRegularReg(RegisterKind RegKind, unsigned RegNum, - unsigned RegWidth); + unsigned RegWidth, + SMLoc Loc); bool isRegister(); bool isRegister(const AsmToken &Token, const AsmToken &NextToken) const; @@ -1127,7 +1140,7 @@ public: // AsmParser::parseDirectiveSet() cannot be specialized for specific target. AMDGPU::IsaVersion ISA = AMDGPU::getIsaVersion(getSTI().getCPU()); MCContext &Ctx = getContext(); - if (ISA.Major >= 6 && AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI())) { + if (ISA.Major >= 6 && isHsaAbiVersion3(&getSTI())) { MCSymbol *Sym = Ctx.getOrCreateSymbol(Twine(".amdgcn.gfx_generation_number")); Sym->setVariableValue(MCConstantExpr::create(ISA.Major, Ctx)); @@ -1144,7 +1157,7 @@ public: Sym = Ctx.getOrCreateSymbol(Twine(".option.machine_version_stepping")); Sym->setVariableValue(MCConstantExpr::create(ISA.Stepping, Ctx)); } - if (ISA.Major >= 6 && AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI())) { + if (ISA.Major >= 6 && isHsaAbiVersion3(&getSTI())) { initializeGprCountSymbol(IS_VGPR); initializeGprCountSymbol(IS_SGPR); } else @@ -1184,10 +1197,16 @@ public: return AMDGPU::isGFX9(getSTI()); } + bool isGFX9Plus() const { + return AMDGPU::isGFX9Plus(getSTI()); + } + bool isGFX10() const { return AMDGPU::isGFX10(getSTI()); } + bool isGFX10Plus() const { return AMDGPU::isGFX10Plus(getSTI()); } + bool isGFX10_BEncoding() const { return AMDGPU::isGFX10_BEncoding(getSTI()); } @@ -1204,9 +1223,7 @@ public: return !isVI() && !isGFX9(); } - bool hasSGPR104_SGPR105() const { - return isGFX10(); - } + bool hasSGPR104_SGPR105() const { return isGFX10Plus(); } bool hasIntClamp() const { return getFeatureBits()[AMDGPU::FeatureIntClamp]; @@ -1240,6 +1257,7 @@ public: bool isForcedDPP() const { return ForcedDPP; } bool isForcedSDWA() const { return ForcedSDWA; } ArrayRef<unsigned> getMatchedVariants() const; + StringRef getMatchedVariantName() const; std::unique_ptr<AMDGPUOperand> parseRegister(bool RestoreOnFailure = false); bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc, @@ -1279,7 +1297,8 @@ public: parseNamedBit(const char *Name, OperandVector &Operands, AMDGPUOperand::ImmTy ImmTy = AMDGPUOperand::ImmTyNone); OperandMatchResultTy parseStringWithPrefix(StringRef Prefix, - StringRef &Value); + StringRef &Value, + SMLoc &StringLoc); bool isModifier(); bool isOperandModifier(const AsmToken &Token, const AsmToken &NextToken) const; @@ -1295,7 +1314,15 @@ public: OperandMatchResultTy parseRegWithFPInputMods(OperandVector &Operands); OperandMatchResultTy parseRegWithIntInputMods(OperandVector &Operands); OperandMatchResultTy parseVReg32OrOff(OperandVector &Operands); - OperandMatchResultTy parseDfmtNfmt(OperandVector &Operands); + OperandMatchResultTy parseDfmtNfmt(int64_t &Format); + OperandMatchResultTy parseUfmt(int64_t &Format); + OperandMatchResultTy parseSymbolicSplitFormat(StringRef FormatStr, SMLoc Loc, int64_t &Format); + OperandMatchResultTy parseSymbolicUnifiedFormat(StringRef FormatStr, SMLoc Loc, int64_t &Format); + OperandMatchResultTy parseFORMAT(OperandVector &Operands); + OperandMatchResultTy parseSymbolicOrNumericFormat(int64_t &Format); + OperandMatchResultTy parseNumericFormat(int64_t &Format); + bool tryParseFmt(const char *Pref, int64_t MaxVal, int64_t &Val); + bool matchDfmtNfmt(int64_t &Dfmt, int64_t &Nfmt, StringRef FormatStr, SMLoc Loc); void cvtDSOffset01(MCInst &Inst, const OperandVector &Operands); void cvtDS(MCInst &Inst, const OperandVector &Operands) { cvtDSImpl(Inst, Operands, false); } @@ -1308,6 +1335,7 @@ public: private: struct OperandInfoTy { + SMLoc Loc; int64_t Id; bool IsSymbolic = false; bool IsDefined = false; @@ -1318,30 +1346,35 @@ private: bool parseSendMsgBody(OperandInfoTy &Msg, OperandInfoTy &Op, OperandInfoTy &Stream); bool validateSendMsg(const OperandInfoTy &Msg, const OperandInfoTy &Op, - const OperandInfoTy &Stream, - const SMLoc Loc); + const OperandInfoTy &Stream); - bool parseHwregBody(OperandInfoTy &HwReg, int64_t &Offset, int64_t &Width); + bool parseHwregBody(OperandInfoTy &HwReg, + OperandInfoTy &Offset, + OperandInfoTy &Width); bool validateHwreg(const OperandInfoTy &HwReg, - const int64_t Offset, - const int64_t Width, - const SMLoc Loc); + const OperandInfoTy &Offset, + const OperandInfoTy &Width); - void errorExpTgt(); - OperandMatchResultTy parseExpTgtImpl(StringRef Str, uint8_t &Val); SMLoc getFlatOffsetLoc(const OperandVector &Operands) const; SMLoc getSMEMOffsetLoc(const OperandVector &Operands) const; + SMLoc getOperandLoc(std::function<bool(const AMDGPUOperand&)> Test, + const OperandVector &Operands) const; + SMLoc getImmLoc(AMDGPUOperand::ImmTy Type, const OperandVector &Operands) const; + SMLoc getRegLoc(unsigned Reg, const OperandVector &Operands) const; + SMLoc getLitLoc(const OperandVector &Operands) const; + SMLoc getConstLoc(const OperandVector &Operands) const; + bool validateInstruction(const MCInst &Inst, const SMLoc &IDLoc, const OperandVector &Operands); bool validateFlatOffset(const MCInst &Inst, const OperandVector &Operands); bool validateSMEMOffset(const MCInst &Inst, const OperandVector &Operands); bool validateSOPLiteral(const MCInst &Inst) const; - bool validateConstantBusLimitations(const MCInst &Inst); - bool validateEarlyClobberLimitations(const MCInst &Inst); + bool validateConstantBusLimitations(const MCInst &Inst, const OperandVector &Operands); + bool validateEarlyClobberLimitations(const MCInst &Inst, const OperandVector &Operands); bool validateIntClampSupported(const MCInst &Inst); bool validateMIMGAtomicDMask(const MCInst &Inst); bool validateMIMGGatherDMask(const MCInst &Inst); - bool validateMovrels(const MCInst &Inst); + bool validateMovrels(const MCInst &Inst, const OperandVector &Operands); bool validateMIMGDataSize(const MCInst &Inst); bool validateMIMGAddrSize(const MCInst &Inst); bool validateMIMGD16(const MCInst &Inst); @@ -1349,13 +1382,23 @@ private: bool validateLdsDirect(const MCInst &Inst); bool validateOpSel(const MCInst &Inst); bool validateVccOperand(unsigned Reg) const; - bool validateVOP3Literal(const MCInst &Inst) const; - bool validateMAIAccWrite(const MCInst &Inst); + bool validateVOP3Literal(const MCInst &Inst, const OperandVector &Operands); + bool validateMAIAccWrite(const MCInst &Inst, const OperandVector &Operands); + bool validateDivScale(const MCInst &Inst); + bool validateCoherencyBits(const MCInst &Inst, const OperandVector &Operands, + const SMLoc &IDLoc); unsigned getConstantBusLimit(unsigned Opcode) const; bool usesConstantBus(const MCInst &Inst, unsigned OpIdx); bool isInlineConstant(const MCInst &Inst, unsigned OpIdx) const; unsigned findImplicitSGPRReadInVOP(const MCInst &Inst) const; + bool isSupportedMnemo(StringRef Mnemo, + const FeatureBitset &FBS); + bool isSupportedMnemo(StringRef Mnemo, + const FeatureBitset &FBS, + ArrayRef<unsigned> Variants); + bool checkUnsupportedInstruction(StringRef Name, const SMLoc &IDLoc); + bool isId(const StringRef Id) const; bool isId(const AsmToken &Token, const StringRef Id) const; bool isToken(const AsmToken::TokenKind Kind) const; @@ -1364,9 +1407,11 @@ private: bool trySkipToken(const AsmToken::TokenKind Kind); bool skipToken(const AsmToken::TokenKind Kind, const StringRef ErrMsg); bool parseString(StringRef &Val, const StringRef ErrMsg = "expected a string"); + bool parseId(StringRef &Val, const StringRef ErrMsg = ""); + void peekTokens(MutableArrayRef<AsmToken> Tokens); AsmToken::TokenKind getTokenKind() const; - bool parseExpr(int64_t &Imm); + bool parseExpr(int64_t &Imm, StringRef Expected = ""); bool parseExpr(OperandVector &Operands); StringRef getTokenStr() const; AsmToken peekToken(); @@ -1385,6 +1430,11 @@ public: OperandMatchResultTy parseSOppBrTarget(OperandVector &Operands); OperandMatchResultTy parseBoolReg(OperandVector &Operands); + bool parseSwizzleOperand(int64_t &Op, + const unsigned MinVal, + const unsigned MaxVal, + const StringRef ErrMsg, + SMLoc &Loc); bool parseSwizzleOperands(const unsigned OpNum, int64_t* Op, const unsigned MinVal, const unsigned MaxVal, @@ -1409,6 +1459,7 @@ public: AMDGPUOperand::Ptr defaultDLC() const; AMDGPUOperand::Ptr defaultGLC() const; + AMDGPUOperand::Ptr defaultGLC_1() const; AMDGPUOperand::Ptr defaultSLC() const; AMDGPUOperand::Ptr defaultSMRDOffset8() const; @@ -1429,10 +1480,14 @@ public: void cvtMIMG(MCInst &Inst, const OperandVector &Operands, bool IsAtomic = false); void cvtMIMGAtomic(MCInst &Inst, const OperandVector &Operands); + void cvtIntersectRay(MCInst &Inst, const OperandVector &Operands); OperandMatchResultTy parseDim(OperandVector &Operands); OperandMatchResultTy parseDPP8(OperandVector &Operands); OperandMatchResultTy parseDPPCtrl(OperandVector &Operands); + bool isSupportedDPPCtrl(StringRef Ctrl, const OperandVector &Operands); + int64_t parseDPPCtrlSel(StringRef Ctrl); + int64_t parseDPPCtrlPerm(); AMDGPUOperand::Ptr defaultRowMask() const; AMDGPUOperand::Ptr defaultBankMask() const; AMDGPUOperand::Ptr defaultBoundCtrl() const; @@ -1673,7 +1728,7 @@ bool AMDGPUOperand::isRegClass(unsigned RCID) const { bool AMDGPUOperand::isSDWAOperand(MVT type) const { if (AsmParser->isVI()) return isVReg32(); - else if (AsmParser->isGFX9() || AsmParser->isGFX10()) + else if (AsmParser->isGFX9Plus()) return isRegClass(AMDGPU::VS_32RegClassID) || isInlinableImm(type); else return false; @@ -1726,6 +1781,7 @@ void AMDGPUOperand::addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers } else { assert(!isImmTy(ImmTyNone) || !hasModifiers()); Inst.addOperand(MCOperand::createImm(Imm.Val)); + setImmKindNone(); } } @@ -1753,6 +1809,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo if (AMDGPU::isInlinableLiteral64(Literal.getZExtValue(), AsmParser->hasInv2PiInlineImm())) { Inst.addOperand(MCOperand::createImm(Literal.getZExtValue())); + setImmKindConst(); return; } @@ -1766,6 +1823,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo } Inst.addOperand(MCOperand::createImm(Literal.lshr(32).getZExtValue())); + setImmKindLiteral(); return; } @@ -1802,6 +1860,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo uint64_t ImmVal = FPLiteral.bitcastToAPInt().getZExtValue(); Inst.addOperand(MCOperand::createImm(ImmVal)); + setImmKindLiteral(); return; } default: @@ -1826,10 +1885,12 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo AMDGPU::isInlinableLiteral32(static_cast<int32_t>(Val), AsmParser->hasInv2PiInlineImm())) { Inst.addOperand(MCOperand::createImm(Val)); + setImmKindConst(); return; } Inst.addOperand(MCOperand::createImm(Val & 0xffffffff)); + setImmKindLiteral(); return; case AMDGPU::OPERAND_REG_IMM_INT64: @@ -1838,10 +1899,12 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo case AMDGPU::OPERAND_REG_INLINE_C_FP64: if (AMDGPU::isInlinableLiteral64(Val, AsmParser->hasInv2PiInlineImm())) { Inst.addOperand(MCOperand::createImm(Val)); + setImmKindConst(); return; } Inst.addOperand(MCOperand::createImm(Lo_32(Val))); + setImmKindLiteral(); return; case AMDGPU::OPERAND_REG_IMM_INT16: @@ -1854,10 +1917,12 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo AMDGPU::isInlinableLiteral16(static_cast<int16_t>(Val), AsmParser->hasInv2PiInlineImm())) { Inst.addOperand(MCOperand::createImm(Val)); + setImmKindConst(); return; } Inst.addOperand(MCOperand::createImm(Val & 0xffff)); + setImmKindLiteral(); return; case AMDGPU::OPERAND_REG_INLINE_C_V2INT16: @@ -1879,6 +1944,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo template <unsigned Bitwidth> void AMDGPUOperand::addKImmFPOperands(MCInst &Inst, unsigned N) const { APInt Literal(64, Imm.Val); + setImmKindNone(); if (!Imm.IsFPImm) { // We got int literal token. @@ -2051,7 +2117,8 @@ OperandMatchResultTy AMDGPUAsmParser::tryParseRegister(unsigned &RegNo, } bool AMDGPUAsmParser::AddNextRegisterToList(unsigned &Reg, unsigned &RegWidth, - RegisterKind RegKind, unsigned Reg1) { + RegisterKind RegKind, unsigned Reg1, + SMLoc Loc) { switch (RegKind) { case IS_SPECIAL: if (Reg == AMDGPU::EXEC_LO && Reg1 == AMDGPU::EXEC_HI) { @@ -2084,12 +2151,14 @@ bool AMDGPUAsmParser::AddNextRegisterToList(unsigned &Reg, unsigned &RegWidth, RegWidth = 2; return true; } + Error(Loc, "register does not fit in the list"); return false; case IS_VGPR: case IS_SGPR: case IS_AGPR: case IS_TTMP: if (Reg1 != Reg + RegWidth) { + Error(Loc, "registers in a list must have consecutive indices"); return false; } RegWidth++; @@ -2172,7 +2241,8 @@ AMDGPUAsmParser::isRegister() unsigned AMDGPUAsmParser::getRegularReg(RegisterKind RegKind, unsigned RegNum, - unsigned RegWidth) { + unsigned RegWidth, + SMLoc Loc) { assert(isRegularReg(RegKind)); @@ -2183,18 +2253,24 @@ AMDGPUAsmParser::getRegularReg(RegisterKind RegKind, AlignSize = std::min(RegWidth, 4u); } - if (RegNum % AlignSize != 0) + if (RegNum % AlignSize != 0) { + Error(Loc, "invalid register alignment"); return AMDGPU::NoRegister; + } unsigned RegIdx = RegNum / AlignSize; int RCID = getRegClass(RegKind, RegWidth); - if (RCID == -1) + if (RCID == -1) { + Error(Loc, "invalid or unsupported register size"); return AMDGPU::NoRegister; + } const MCRegisterInfo *TRI = getContext().getRegisterInfo(); const MCRegisterClass RC = TRI->getRegClass(RCID); - if (RegIdx >= RC.getNumRegs()) + if (RegIdx >= RC.getNumRegs()) { + Error(Loc, "register index is out of range"); return AMDGPU::NoRegister; + } return RC.getRegister(RegIdx); } @@ -2202,24 +2278,40 @@ AMDGPUAsmParser::getRegularReg(RegisterKind RegKind, bool AMDGPUAsmParser::ParseRegRange(unsigned& Num, unsigned& Width) { int64_t RegLo, RegHi; - if (!trySkipToken(AsmToken::LBrac)) + if (!skipToken(AsmToken::LBrac, "missing register index")) return false; + SMLoc FirstIdxLoc = getLoc(); + SMLoc SecondIdxLoc; + if (!parseExpr(RegLo)) return false; if (trySkipToken(AsmToken::Colon)) { + SecondIdxLoc = getLoc(); if (!parseExpr(RegHi)) return false; } else { RegHi = RegLo; } - if (!trySkipToken(AsmToken::RBrac)) + if (!skipToken(AsmToken::RBrac, "expected a closing square bracket")) return false; - if (!isUInt<32>(RegLo) || !isUInt<32>(RegHi) || RegLo > RegHi) + if (!isUInt<32>(RegLo)) { + Error(FirstIdxLoc, "invalid register index"); return false; + } + + if (!isUInt<32>(RegHi)) { + Error(SecondIdxLoc, "invalid register index"); + return false; + } + + if (RegLo > RegHi) { + Error(FirstIdxLoc, "first register index should not exceed second index"); + return false; + } Num = static_cast<unsigned>(RegLo); Width = (RegHi - RegLo) + 1; @@ -2246,10 +2338,14 @@ unsigned AMDGPUAsmParser::ParseRegularReg(RegisterKind &RegKind, SmallVectorImpl<AsmToken> &Tokens) { assert(isToken(AsmToken::Identifier)); StringRef RegName = getTokenStr(); + auto Loc = getLoc(); const RegInfo *RI = getRegularRegInfo(RegName); - if (!RI) + if (!RI) { + Error(Loc, "invalid register name"); return AMDGPU::NoRegister; + } + Tokens.push_back(getToken()); lex(); // skip register name @@ -2257,8 +2353,10 @@ unsigned AMDGPUAsmParser::ParseRegularReg(RegisterKind &RegKind, StringRef RegSuffix = RegName.substr(RI->Name.size()); if (!RegSuffix.empty()) { // Single 32-bit register: vXX. - if (!getRegNum(RegSuffix, RegNum)) + if (!getRegNum(RegSuffix, RegNum)) { + Error(Loc, "invalid register index"); return AMDGPU::NoRegister; + } RegWidth = 1; } else { // Range of registers: v[XX:YY]. ":YY" is optional. @@ -2266,44 +2364,59 @@ unsigned AMDGPUAsmParser::ParseRegularReg(RegisterKind &RegKind, return AMDGPU::NoRegister; } - return getRegularReg(RegKind, RegNum, RegWidth); + return getRegularReg(RegKind, RegNum, RegWidth, Loc); } unsigned AMDGPUAsmParser::ParseRegList(RegisterKind &RegKind, unsigned &RegNum, unsigned &RegWidth, SmallVectorImpl<AsmToken> &Tokens) { unsigned Reg = AMDGPU::NoRegister; + auto ListLoc = getLoc(); - if (!trySkipToken(AsmToken::LBrac)) + if (!skipToken(AsmToken::LBrac, + "expected a register or a list of registers")) { return AMDGPU::NoRegister; + } // List of consecutive registers, e.g.: [s0,s1,s2,s3] + auto Loc = getLoc(); if (!ParseAMDGPURegister(RegKind, Reg, RegNum, RegWidth)) return AMDGPU::NoRegister; - if (RegWidth != 1) + if (RegWidth != 1) { + Error(Loc, "expected a single 32-bit register"); return AMDGPU::NoRegister; + } for (; trySkipToken(AsmToken::Comma); ) { RegisterKind NextRegKind; unsigned NextReg, NextRegNum, NextRegWidth; + Loc = getLoc(); - if (!ParseAMDGPURegister(NextRegKind, NextReg, NextRegNum, NextRegWidth, - Tokens)) + if (!ParseAMDGPURegister(NextRegKind, NextReg, + NextRegNum, NextRegWidth, + Tokens)) { return AMDGPU::NoRegister; - if (NextRegWidth != 1) + } + if (NextRegWidth != 1) { + Error(Loc, "expected a single 32-bit register"); return AMDGPU::NoRegister; - if (NextRegKind != RegKind) + } + if (NextRegKind != RegKind) { + Error(Loc, "registers in a list must be of the same kind"); return AMDGPU::NoRegister; - if (!AddNextRegisterToList(Reg, RegWidth, RegKind, NextReg)) + } + if (!AddNextRegisterToList(Reg, RegWidth, RegKind, NextReg, Loc)) return AMDGPU::NoRegister; } - if (!trySkipToken(AsmToken::RBrac)) + if (!skipToken(AsmToken::RBrac, + "expected a comma or a closing square bracket")) { return AMDGPU::NoRegister; + } if (isRegularReg(RegKind)) - Reg = getRegularReg(RegKind, RegNum, RegWidth); + Reg = getRegularReg(RegKind, RegNum, RegWidth, ListLoc); return Reg; } @@ -2311,6 +2424,7 @@ unsigned AMDGPUAsmParser::ParseRegList(RegisterKind &RegKind, unsigned &RegNum, bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind &RegKind, unsigned &Reg, unsigned &RegNum, unsigned &RegWidth, SmallVectorImpl<AsmToken> &Tokens) { + auto Loc = getLoc(); Reg = AMDGPU::NoRegister; if (isToken(AsmToken::Identifier)) { @@ -2322,12 +2436,26 @@ bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind &RegKind, unsigned &Reg, } const MCRegisterInfo *TRI = getContext().getRegisterInfo(); - return Reg != AMDGPU::NoRegister && subtargetHasRegister(*TRI, Reg); + if (Reg == AMDGPU::NoRegister) { + assert(Parser.hasPendingError()); + return false; + } + + if (!subtargetHasRegister(*TRI, Reg)) { + if (Reg == AMDGPU::SGPR_NULL) { + Error(Loc, "'null' operand is not supported on this GPU"); + } else { + Error(Loc, "register not available on this GPU"); + } + return false; + } + + return true; } bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind &RegKind, unsigned &Reg, unsigned &RegNum, unsigned &RegWidth, - bool RestoreOnFailure) { + bool RestoreOnFailure /*=false*/) { Reg = AMDGPU::NoRegister; SmallVector<AsmToken, 1> Tokens; @@ -2377,11 +2505,11 @@ bool AMDGPUAsmParser::updateGprCountSymbols(RegisterKind RegKind, int64_t OldCount; if (!Sym->isVariable()) - return !Error(getParser().getTok().getLoc(), + return !Error(getLoc(), ".amdgcn.next_free_{v,s}gpr symbols must be variable"); if (!Sym->getVariableValue(false)->evaluateAsAbsolute(OldCount)) return !Error( - getParser().getTok().getLoc(), + getLoc(), ".amdgcn.next_free_{v,s}gpr symbols must be absolute expressions"); if (OldCount <= NewMax) @@ -2392,18 +2520,16 @@ bool AMDGPUAsmParser::updateGprCountSymbols(RegisterKind RegKind, std::unique_ptr<AMDGPUOperand> AMDGPUAsmParser::parseRegister(bool RestoreOnFailure) { - const auto &Tok = Parser.getTok(); + const auto &Tok = getToken(); SMLoc StartLoc = Tok.getLoc(); SMLoc EndLoc = Tok.getEndLoc(); RegisterKind RegKind; unsigned Reg, RegNum, RegWidth; if (!ParseAMDGPURegister(RegKind, Reg, RegNum, RegWidth)) { - //FIXME: improve error messages (bug 41303). - Error(StartLoc, "not a valid operand."); return nullptr; } - if (AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI())) { + if (isHsaAbiVersion3(&getSTI())) { if (!updateGprCountSymbols(RegKind, RegNum, RegWidth)) return nullptr; } else @@ -2466,7 +2592,7 @@ AMDGPUAsmParser::parseImm(OperandVector &Operands, bool HasSP3AbsModifier) { // This syntax is not compatible with syntax of standard // MC expressions (due to the trailing '|'). SMLoc EndLoc; - if (getParser().parsePrimaryExpr(Expr, EndLoc)) + if (getParser().parsePrimaryExpr(Expr, EndLoc, nullptr)) return MatchOperand_ParseFail; } else { if (Parser.parseExpression(Expr)) @@ -2761,6 +2887,15 @@ unsigned AMDGPUAsmParser::checkTargetMatchPredicate(MCInst &Inst) { return Match_Success; } +static ArrayRef<unsigned> getAllVariants() { + static const unsigned Variants[] = { + AMDGPUAsmVariants::DEFAULT, AMDGPUAsmVariants::VOP3, + AMDGPUAsmVariants::SDWA, AMDGPUAsmVariants::SDWA9, AMDGPUAsmVariants::DPP + }; + + return makeArrayRef(Variants); +} + // What asm variants we should check ArrayRef<unsigned> AMDGPUAsmParser::getMatchedVariants() const { if (getForcedEncodingSize() == 32) { @@ -2784,12 +2919,23 @@ ArrayRef<unsigned> AMDGPUAsmParser::getMatchedVariants() const { return makeArrayRef(Variants); } - static const unsigned Variants[] = { - AMDGPUAsmVariants::DEFAULT, AMDGPUAsmVariants::VOP3, - AMDGPUAsmVariants::SDWA, AMDGPUAsmVariants::SDWA9, AMDGPUAsmVariants::DPP - }; + return getAllVariants(); +} - return makeArrayRef(Variants); +StringRef AMDGPUAsmParser::getMatchedVariantName() const { + if (getForcedEncodingSize() == 32) + return "e32"; + + if (isForcedVOP3()) + return "e64"; + + if (isForcedSDWA()) + return "sdwa"; + + if (isForcedDPP()) + return "dpp"; + + return ""; } unsigned AMDGPUAsmParser::findImplicitSGPRReadInVOP(const MCInst &Inst) const { @@ -2858,20 +3004,20 @@ bool AMDGPUAsmParser::isInlineConstant(const MCInst &Inst, } unsigned AMDGPUAsmParser::getConstantBusLimit(unsigned Opcode) const { - if (!isGFX10()) + if (!isGFX10Plus()) return 1; switch (Opcode) { // 64-bit shift instructions can use only one scalar value input - case AMDGPU::V_LSHLREV_B64: + case AMDGPU::V_LSHLREV_B64_e64: case AMDGPU::V_LSHLREV_B64_gfx10: - case AMDGPU::V_LSHL_B64: - case AMDGPU::V_LSHRREV_B64: + case AMDGPU::V_LSHRREV_B64_e64: case AMDGPU::V_LSHRREV_B64_gfx10: - case AMDGPU::V_LSHR_B64: - case AMDGPU::V_ASHRREV_I64: + case AMDGPU::V_ASHRREV_I64_e64: case AMDGPU::V_ASHRREV_I64_gfx10: - case AMDGPU::V_ASHR_I64: + case AMDGPU::V_LSHL_B64_e64: + case AMDGPU::V_LSHR_B64_e64: + case AMDGPU::V_ASHR_I64_e64: return 1; default: return 2; @@ -2885,15 +3031,19 @@ bool AMDGPUAsmParser::usesConstantBus(const MCInst &Inst, unsigned OpIdx) { } else if (MO.isReg()) { auto Reg = MO.getReg(); const MCRegisterInfo *TRI = getContext().getRegisterInfo(); - return isSGPR(mc2PseudoReg(Reg), TRI) && Reg != SGPR_NULL; + auto PReg = mc2PseudoReg(Reg); + return isSGPR(PReg, TRI) && PReg != SGPR_NULL; } else { return true; } } -bool AMDGPUAsmParser::validateConstantBusLimitations(const MCInst &Inst) { +bool +AMDGPUAsmParser::validateConstantBusLimitations(const MCInst &Inst, + const OperandVector &Operands) { const unsigned Opcode = Inst.getOpcode(); const MCInstrDesc &Desc = MII.get(Opcode); + unsigned LastSGPR = AMDGPU::NoRegister; unsigned ConstantBusUseCount = 0; unsigned NumLiterals = 0; unsigned LiteralSize; @@ -2927,15 +3077,15 @@ bool AMDGPUAsmParser::validateConstantBusLimitations(const MCInst &Inst) { const MCOperand &MO = Inst.getOperand(OpIdx); if (usesConstantBus(Inst, OpIdx)) { if (MO.isReg()) { - const unsigned Reg = mc2PseudoReg(MO.getReg()); + LastSGPR = mc2PseudoReg(MO.getReg()); // Pairs of registers with a partial intersections like these // s0, s[0:1] // flat_scratch_lo, flat_scratch // flat_scratch_lo, flat_scratch_hi // are theoretically valid but they are disabled anyway. // Note that this code mimics SIInstrInfo::verifyInstruction - if (!SGPRsUsed.count(Reg)) { - SGPRsUsed.insert(Reg); + if (!SGPRsUsed.count(LastSGPR)) { + SGPRsUsed.insert(LastSGPR); ++ConstantBusUseCount; } } else { // Expression or a literal @@ -2967,10 +3117,19 @@ bool AMDGPUAsmParser::validateConstantBusLimitations(const MCInst &Inst) { } ConstantBusUseCount += NumLiterals; - return ConstantBusUseCount <= getConstantBusLimit(Opcode); + if (ConstantBusUseCount <= getConstantBusLimit(Opcode)) + return true; + + SMLoc LitLoc = getLitLoc(Operands); + SMLoc RegLoc = getRegLoc(LastSGPR, Operands); + SMLoc Loc = (LitLoc.getPointer() < RegLoc.getPointer()) ? RegLoc : LitLoc; + Error(Loc, "invalid operand (violates constant bus restrictions)"); + return false; } -bool AMDGPUAsmParser::validateEarlyClobberLimitations(const MCInst &Inst) { +bool +AMDGPUAsmParser::validateEarlyClobberLimitations(const MCInst &Inst, + const OperandVector &Operands) { const unsigned Opcode = Inst.getOpcode(); const MCInstrDesc &Desc = MII.get(Opcode); @@ -2999,6 +3158,8 @@ bool AMDGPUAsmParser::validateEarlyClobberLimitations(const MCInst &Inst) { if (Src.isReg()) { const unsigned SrcReg = mc2PseudoReg(Src.getReg()); if (isRegIntersect(DstReg, SrcReg, TRI)) { + Error(getRegLoc(SrcReg, Operands), + "destination must be different than all sources"); return false; } } @@ -3034,8 +3195,9 @@ bool AMDGPUAsmParser::validateMIMGDataSize(const MCInst &Inst) { int TFEIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::tfe); assert(VDataIdx != -1); - assert(DMaskIdx != -1); - assert(TFEIdx != -1); + + if (DMaskIdx == -1 || TFEIdx == -1) // intersect_ray + return true; unsigned VDataSize = AMDGPU::getRegOperandSize(getMRI(), Desc, VDataIdx); unsigned TFESize = Inst.getOperand(TFEIdx).getImm()? 1 : 0; @@ -3058,10 +3220,11 @@ bool AMDGPUAsmParser::validateMIMGAddrSize(const MCInst &Inst) { const unsigned Opc = Inst.getOpcode(); const MCInstrDesc &Desc = MII.get(Opc); - if ((Desc.TSFlags & SIInstrFlags::MIMG) == 0 || !isGFX10()) + if ((Desc.TSFlags & SIInstrFlags::MIMG) == 0 || !isGFX10Plus()) return true; const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(Opc); + const AMDGPU::MIMGBaseOpcodeInfo *BaseOpcode = AMDGPU::getMIMGBaseOpcodeInfo(Info->BaseOpcode); int VAddr0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vaddr0); @@ -3070,9 +3233,11 @@ bool AMDGPUAsmParser::validateMIMGAddrSize(const MCInst &Inst) { assert(VAddr0Idx != -1); assert(SrsrcIdx != -1); - assert(DimIdx != -1); assert(SrsrcIdx > VAddr0Idx); + if (DimIdx == -1) + return true; // intersect_ray + unsigned Dim = Inst.getOperand(DimIdx).getImm(); const AMDGPU::MIMGDimInfo *DimInfo = AMDGPU::getMIMGDimInfoByEncoding(Dim); bool IsNSA = SrsrcIdx - VAddr0Idx > 1; @@ -3148,7 +3313,8 @@ static bool IsMovrelsSDWAOpcode(const unsigned Opcode) // movrels* opcodes should only allow VGPRS as src0. // This is specified in .td description for vop1/vop3, // but sdwa is handled differently. See isSDWAOperand. -bool AMDGPUAsmParser::validateMovrels(const MCInst &Inst) { +bool AMDGPUAsmParser::validateMovrels(const MCInst &Inst, + const OperandVector &Operands) { const unsigned Opc = Inst.getOpcode(); const MCInstrDesc &Desc = MII.get(Opc); @@ -3159,16 +3325,24 @@ bool AMDGPUAsmParser::validateMovrels(const MCInst &Inst) { const int Src0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0); assert(Src0Idx != -1); + SMLoc ErrLoc; const MCOperand &Src0 = Inst.getOperand(Src0Idx); - if (!Src0.isReg()) - return false; + if (Src0.isReg()) { + auto Reg = mc2PseudoReg(Src0.getReg()); + const MCRegisterInfo *TRI = getContext().getRegisterInfo(); + if (!isSGPR(Reg, TRI)) + return true; + ErrLoc = getRegLoc(Reg, Operands); + } else { + ErrLoc = getConstLoc(Operands); + } - auto Reg = Src0.getReg(); - const MCRegisterInfo *TRI = getContext().getRegisterInfo(); - return !isSGPR(mc2PseudoReg(Reg), TRI); + Error(ErrLoc, "source operand must be a VGPR"); + return false; } -bool AMDGPUAsmParser::validateMAIAccWrite(const MCInst &Inst) { +bool AMDGPUAsmParser::validateMAIAccWrite(const MCInst &Inst, + const OperandVector &Operands) { const unsigned Opc = Inst.getOpcode(); @@ -3182,16 +3356,45 @@ bool AMDGPUAsmParser::validateMAIAccWrite(const MCInst &Inst) { if (!Src0.isReg()) return true; - auto Reg = Src0.getReg(); + auto Reg = mc2PseudoReg(Src0.getReg()); const MCRegisterInfo *TRI = getContext().getRegisterInfo(); - if (isSGPR(mc2PseudoReg(Reg), TRI)) { - Error(getLoc(), "source operand must be either a VGPR or an inline constant"); + if (isSGPR(Reg, TRI)) { + Error(getRegLoc(Reg, Operands), + "source operand must be either a VGPR or an inline constant"); return false; } return true; } +bool AMDGPUAsmParser::validateDivScale(const MCInst &Inst) { + switch (Inst.getOpcode()) { + default: + return true; + case V_DIV_SCALE_F32_gfx6_gfx7: + case V_DIV_SCALE_F32_vi: + case V_DIV_SCALE_F32_gfx10: + case V_DIV_SCALE_F64_gfx6_gfx7: + case V_DIV_SCALE_F64_vi: + case V_DIV_SCALE_F64_gfx10: + break; + } + + // TODO: Check that src0 = src1 or src2. + + for (auto Name : {AMDGPU::OpName::src0_modifiers, + AMDGPU::OpName::src2_modifiers, + AMDGPU::OpName::src2_modifiers}) { + if (Inst.getOperand(AMDGPU::getNamedOperandIdx(Inst.getOpcode(), Name)) + .getImm() & + SISrcMods::ABS) { + return false; + } + } + + return true; +} + bool AMDGPUAsmParser::validateMIMGD16(const MCInst &Inst) { const unsigned Opc = Inst.getOpcode(); @@ -3239,8 +3442,8 @@ static bool IsRevOpcode(const unsigned Opcode) case AMDGPU::V_SUBREV_F32_e64_gfx6_gfx7: case AMDGPU::V_SUBREV_F32_e64_vi: - case AMDGPU::V_SUBREV_I32_e32: - case AMDGPU::V_SUBREV_I32_e64: + case AMDGPU::V_SUBREV_CO_U32_e32: + case AMDGPU::V_SUBREV_CO_U32_e64: case AMDGPU::V_SUBREV_I32_e32_gfx6_gfx7: case AMDGPU::V_SUBREV_I32_e64_gfx6_gfx7: @@ -3328,15 +3531,15 @@ static bool IsRevOpcode(const unsigned Opcode) case AMDGPU::V_ASHRREV_I16_e64_vi: case AMDGPU::V_ASHRREV_I16_gfx10: - case AMDGPU::V_LSHLREV_B64: + case AMDGPU::V_LSHLREV_B64_e64: case AMDGPU::V_LSHLREV_B64_gfx10: case AMDGPU::V_LSHLREV_B64_vi: - case AMDGPU::V_LSHRREV_B64: + case AMDGPU::V_LSHRREV_B64_e64: case AMDGPU::V_LSHRREV_B64_gfx10: case AMDGPU::V_LSHRREV_B64_vi: - case AMDGPU::V_ASHRREV_I64: + case AMDGPU::V_ASHRREV_I64_e64: case AMDGPU::V_ASHRREV_I64_gfx10: case AMDGPU::V_ASHRREV_I64_vi: @@ -3419,22 +3622,20 @@ bool AMDGPUAsmParser::validateFlatOffset(const MCInst &Inst, return false; } - // Address offset is 12-bit signed for GFX10, 13-bit for GFX9. // For FLAT segment the offset must be positive; // MSB is ignored and forced to zero. - unsigned OffsetSize = isGFX9() ? 13 : 12; - if (TSFlags & SIInstrFlags::IsNonFlatSeg) { + if (TSFlags & (SIInstrFlags::IsFlatGlobal | SIInstrFlags::IsFlatScratch)) { + unsigned OffsetSize = AMDGPU::getNumFlatOffsetBits(getSTI(), true); if (!isIntN(OffsetSize, Op.getImm())) { Error(getFlatOffsetLoc(Operands), - isGFX9() ? "expected a 13-bit signed offset" : - "expected a 12-bit signed offset"); + Twine("expected a ") + Twine(OffsetSize) + "-bit signed offset"); return false; } } else { - if (!isUIntN(OffsetSize - 1, Op.getImm())) { + unsigned OffsetSize = AMDGPU::getNumFlatOffsetBits(getSTI(), false); + if (!isUIntN(OffsetSize, Op.getImm())) { Error(getFlatOffsetLoc(Operands), - isGFX9() ? "expected a 12-bit unsigned offset" : - "expected an 11-bit unsigned offset"); + Twine("expected a ") + Twine(OffsetSize) + "-bit unsigned offset"); return false; } } @@ -3443,7 +3644,8 @@ bool AMDGPUAsmParser::validateFlatOffset(const MCInst &Inst, } SMLoc AMDGPUAsmParser::getSMEMOffsetLoc(const OperandVector &Operands) const { - for (unsigned i = 1, e = Operands.size(); i != e; ++i) { + // Start with second operand because SMEM Offset cannot be dst or src0. + for (unsigned i = 2, e = Operands.size(); i != e; ++i) { AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[i]); if (Op.isSMEMOffset()) return Op.getStartLoc(); @@ -3539,7 +3741,8 @@ bool AMDGPUAsmParser::validateVccOperand(unsigned Reg) const { } // VOP3 literal is only allowed in GFX10+ and only one can be used -bool AMDGPUAsmParser::validateVOP3Literal(const MCInst &Inst) const { +bool AMDGPUAsmParser::validateVOP3Literal(const MCInst &Inst, + const OperandVector &Operands) { unsigned Opcode = Inst.getOpcode(); const MCInstrDesc &Desc = MII.get(Opcode); if (!(Desc.TSFlags & (SIInstrFlags::VOP3 | SIInstrFlags::VOP3P))) @@ -3565,8 +3768,11 @@ bool AMDGPUAsmParser::validateVOP3Literal(const MCInst &Inst) const { continue; if (OpIdx == Src2Idx && (Desc.TSFlags & SIInstrFlags::IsMAI) && - getFeatureBits()[AMDGPU::FeatureMFMAInlineLiteralBug]) + getFeatureBits()[AMDGPU::FeatureMFMAInlineLiteralBug]) { + Error(getConstLoc(Operands), + "inline constants are not allowed for this operand"); return false; + } if (MO.isImm() && !isInlineConstant(Inst, OpIdx)) { uint32_t Value = static_cast<uint32_t>(MO.getImm()); @@ -3580,51 +3786,74 @@ bool AMDGPUAsmParser::validateVOP3Literal(const MCInst &Inst) const { } NumLiterals += NumExprs; - return !NumLiterals || - (NumLiterals == 1 && getFeatureBits()[AMDGPU::FeatureVOP3Literal]); + if (!NumLiterals) + return true; + + if (!getFeatureBits()[AMDGPU::FeatureVOP3Literal]) { + Error(getLitLoc(Operands), "literal operands are not supported"); + return false; + } + + if (NumLiterals > 1) { + Error(getLitLoc(Operands), "only one literal operand is allowed"); + return false; + } + + return true; +} + +bool AMDGPUAsmParser::validateCoherencyBits(const MCInst &Inst, + const OperandVector &Operands, + const SMLoc &IDLoc) { + int GLCPos = AMDGPU::getNamedOperandIdx(Inst.getOpcode(), + AMDGPU::OpName::glc1); + if (GLCPos != -1) { + // -1 is set by GLC_1 default operand. In all cases "glc" must be present + // in the asm string, and the default value means it is not present. + if (Inst.getOperand(GLCPos).getImm() == -1) { + Error(IDLoc, "instruction must use glc"); + return false; + } + } + + return true; } bool AMDGPUAsmParser::validateInstruction(const MCInst &Inst, const SMLoc &IDLoc, const OperandVector &Operands) { if (!validateLdsDirect(Inst)) { - Error(IDLoc, + Error(getRegLoc(AMDGPU::LDS_DIRECT, Operands), "invalid use of lds_direct"); return false; } if (!validateSOPLiteral(Inst)) { - Error(IDLoc, + Error(getLitLoc(Operands), "only one literal operand is allowed"); return false; } - if (!validateVOP3Literal(Inst)) { - Error(IDLoc, - "invalid literal operand"); + if (!validateVOP3Literal(Inst, Operands)) { return false; } - if (!validateConstantBusLimitations(Inst)) { - Error(IDLoc, - "invalid operand (violates constant bus restrictions)"); + if (!validateConstantBusLimitations(Inst, Operands)) { return false; } - if (!validateEarlyClobberLimitations(Inst)) { - Error(IDLoc, - "destination must be different than all sources"); + if (!validateEarlyClobberLimitations(Inst, Operands)) { return false; } if (!validateIntClampSupported(Inst)) { - Error(IDLoc, + Error(getImmLoc(AMDGPUOperand::ImmTyClampSI, Operands), "integer clamping is not supported on this GPU"); return false; } if (!validateOpSel(Inst)) { - Error(IDLoc, + Error(getImmLoc(AMDGPUOperand::ImmTyOpSel, Operands), "invalid op_sel operand"); return false; } // For MUBUF/MTBUF d16 is a part of opcode, so there is nothing to validate. if (!validateMIMGD16(Inst)) { - Error(IDLoc, + Error(getImmLoc(AMDGPUOperand::ImmTyD16, Operands), "d16 modifier is not supported on this GPU"); return false; } @@ -3643,17 +3872,16 @@ bool AMDGPUAsmParser::validateInstruction(const MCInst &Inst, return false; } if (!validateMIMGAtomicDMask(Inst)) { - Error(IDLoc, + Error(getImmLoc(AMDGPUOperand::ImmTyDMask, Operands), "invalid atomic image dmask"); return false; } if (!validateMIMGGatherDMask(Inst)) { - Error(IDLoc, + Error(getImmLoc(AMDGPUOperand::ImmTyDMask, Operands), "invalid image_gather dmask: only one bit must be set"); return false; } - if (!validateMovrels(Inst)) { - Error(IDLoc, "source operand must be a VGPR"); + if (!validateMovrels(Inst, Operands)) { return false; } if (!validateFlatOffset(Inst, Operands)) { @@ -3662,7 +3890,14 @@ bool AMDGPUAsmParser::validateInstruction(const MCInst &Inst, if (!validateSMEMOffset(Inst, Operands)) { return false; } - if (!validateMAIAccWrite(Inst)) { + if (!validateMAIAccWrite(Inst, Operands)) { + return false; + } + if (!validateDivScale(Inst)) { + Error(IDLoc, "ABS not allowed in VOP3B instructions"); + return false; + } + if (!validateCoherencyBits(Inst, Operands, IDLoc)) { return false; } @@ -3673,6 +3908,57 @@ static std::string AMDGPUMnemonicSpellCheck(StringRef S, const FeatureBitset &FBS, unsigned VariantID = 0); +static bool AMDGPUCheckMnemonic(StringRef Mnemonic, + const FeatureBitset &AvailableFeatures, + unsigned VariantID); + +bool AMDGPUAsmParser::isSupportedMnemo(StringRef Mnemo, + const FeatureBitset &FBS) { + return isSupportedMnemo(Mnemo, FBS, getAllVariants()); +} + +bool AMDGPUAsmParser::isSupportedMnemo(StringRef Mnemo, + const FeatureBitset &FBS, + ArrayRef<unsigned> Variants) { + for (auto Variant : Variants) { + if (AMDGPUCheckMnemonic(Mnemo, FBS, Variant)) + return true; + } + + return false; +} + +bool AMDGPUAsmParser::checkUnsupportedInstruction(StringRef Mnemo, + const SMLoc &IDLoc) { + FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); + + // Check if requested instruction variant is supported. + if (isSupportedMnemo(Mnemo, FBS, getMatchedVariants())) + return false; + + // This instruction is not supported. + // Clear any other pending errors because they are no longer relevant. + getParser().clearPendingErrors(); + + // Requested instruction variant is not supported. + // Check if any other variants are supported. + StringRef VariantName = getMatchedVariantName(); + if (!VariantName.empty() && isSupportedMnemo(Mnemo, FBS)) { + return Error(IDLoc, + Twine(VariantName, + " variant of this instruction is not supported")); + } + + // Finally check if this instruction is supported on any other GPU. + if (isSupportedMnemo(Mnemo, FeatureBitset().set())) { + return Error(IDLoc, "instruction not supported on this GPU"); + } + + // Instruction not supported on any GPU. Probably a typo. + std::string Suggestion = AMDGPUMnemonicSpellCheck(Mnemo, FBS); + return Error(IDLoc, "invalid instruction" + Suggestion); +} + bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -3702,27 +3988,28 @@ bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, break; } - switch (Result) { - default: break; - case Match_Success: + if (Result == Match_Success) { if (!validateInstruction(Inst, IDLoc, Operands)) { return true; } Inst.setLoc(IDLoc); Out.emitInstruction(Inst, getSTI()); return false; + } - case Match_MissingFeature: - return Error(IDLoc, "instruction not supported on this GPU"); - - case Match_MnemonicFail: { - FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); - std::string Suggestion = AMDGPUMnemonicSpellCheck( - ((AMDGPUOperand &)*Operands[0]).getToken(), FBS); - return Error(IDLoc, "invalid instruction" + Suggestion, - ((AMDGPUOperand &)*Operands[0]).getLocRange()); + StringRef Mnemo = ((AMDGPUOperand &)*Operands[0]).getToken(); + if (checkUnsupportedInstruction(Mnemo, IDLoc)) { + return true; } + switch (Result) { + default: break; + case Match_MissingFeature: + // It has been verified that the specified instruction + // mnemonic is valid. A match was found but it requires + // features which are not supported on this GPU. + return Error(IDLoc, "operands are not valid for this GPU or mode"); + case Match_InvalidOperand: { SMLoc ErrorLoc = IDLoc; if (ErrorInfo != ~0ULL) { @@ -3739,13 +4026,15 @@ bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_PreferE32: return Error(IDLoc, "internal error: instruction without _e64 suffix " "should be encoded as e32"); + case Match_MnemonicFail: + llvm_unreachable("Invalid instructions should have been handled already"); } llvm_unreachable("Implement any new match types added!"); } bool AMDGPUAsmParser::ParseAsAbsoluteExpression(uint32_t &Ret) { int64_t Tmp = -1; - if (getLexer().isNot(AsmToken::Integer) && getLexer().isNot(AsmToken::Identifier)) { + if (!isToken(AsmToken::Integer) && !isToken(AsmToken::Identifier)) { return true; } if (getParser().parseAbsoluteExpression(Tmp)) { @@ -3760,9 +4049,8 @@ bool AMDGPUAsmParser::ParseDirectiveMajorMinor(uint32_t &Major, if (ParseAsAbsoluteExpression(Major)) return TokError("invalid major version"); - if (getLexer().isNot(AsmToken::Comma)) + if (!trySkipToken(AsmToken::Comma)) return TokError("minor version number required, comma expected"); - Lex(); if (ParseAsAbsoluteExpression(Minor)) return TokError("invalid minor version"); @@ -3776,25 +4064,24 @@ bool AMDGPUAsmParser::ParseDirectiveAMDGCNTarget() { std::string Target; - SMLoc TargetStart = getTok().getLoc(); + SMLoc TargetStart = getLoc(); if (getParser().parseEscapedString(Target)) return true; - SMRange TargetRange = SMRange(TargetStart, getTok().getLoc()); + SMRange TargetRange = SMRange(TargetStart, getLoc()); std::string ExpectedTarget; raw_string_ostream ExpectedTargetOS(ExpectedTarget); IsaInfo::streamIsaVersion(&getSTI(), ExpectedTargetOS); if (Target != ExpectedTargetOS.str()) - return getParser().Error(TargetRange.Start, "target must match options", - TargetRange); + return Error(TargetRange.Start, "target must match options", TargetRange); getTargetStreamer().EmitDirectiveAMDGCNTarget(Target); return false; } bool AMDGPUAsmParser::OutOfRangeError(SMRange Range) { - return getParser().Error(Range.Start, "value out of range", Range); + return Error(Range.Start, "value out of range", Range); } bool AMDGPUAsmParser::calculateGPRBlocks( @@ -3865,15 +4152,12 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { Optional<bool> EnableWavefrontSize32; while (true) { - while (getLexer().is(AsmToken::EndOfStatement)) - Lex(); - - if (getLexer().isNot(AsmToken::Identifier)) - return TokError("expected .amdhsa_ directive or .end_amdhsa_kernel"); + while (trySkipToken(AsmToken::EndOfStatement)); - StringRef ID = getTok().getIdentifier(); + StringRef ID; SMRange IDRange = getTok().getLocRange(); - Lex(); + if (!parseId(ID, "expected .amdhsa_ directive or .end_amdhsa_kernel")) + return true; if (ID == ".end_amdhsa_kernel") break; @@ -3882,11 +4166,11 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { return TokError(".amdhsa_ directives cannot be repeated"); Seen.insert(ID); - SMLoc ValStart = getTok().getLoc(); + SMLoc ValStart = getLoc(); int64_t IVal; if (getParser().parseAbsoluteExpression(IVal)) return true; - SMLoc ValEnd = getTok().getLoc(); + SMLoc ValEnd = getLoc(); SMRange ValRange = SMRange(ValStart, ValEnd); if (IVal < 0) @@ -3951,8 +4235,7 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { UserSGPRCount += 1; } else if (ID == ".amdhsa_wavefront_size32") { if (IVersion.Major < 10) - return getParser().Error(IDRange.Start, "directive requires gfx10+", - IDRange); + return Error(IDRange.Start, "directive requires gfx10+", IDRange); EnableWavefrontSize32 = Val; PARSE_BITS_ENTRY(KD.kernel_code_properties, KERNEL_CODE_PROPERTY_ENABLE_WAVEFRONT_SIZE32, @@ -3960,7 +4243,7 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { } else if (ID == ".amdhsa_system_sgpr_private_segment_wavefront_offset") { PARSE_BITS_ENTRY( KD.compute_pgm_rsrc2, - COMPUTE_PGM_RSRC2_ENABLE_SGPR_PRIVATE_SEGMENT_WAVEFRONT_OFFSET, Val, + COMPUTE_PGM_RSRC2_ENABLE_PRIVATE_SEGMENT, Val, ValRange); } else if (ID == ".amdhsa_system_sgpr_workgroup_id_x") { PARSE_BITS_ENTRY(KD.compute_pgm_rsrc2, @@ -3994,15 +4277,13 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { ReserveVCC = Val; } else if (ID == ".amdhsa_reserve_flat_scratch") { if (IVersion.Major < 7) - return getParser().Error(IDRange.Start, "directive requires gfx7+", - IDRange); + return Error(IDRange.Start, "directive requires gfx7+", IDRange); if (!isUInt<1>(Val)) return OutOfRangeError(ValRange); ReserveFlatScr = Val; } else if (ID == ".amdhsa_reserve_xnack_mask") { if (IVersion.Major < 8) - return getParser().Error(IDRange.Start, "directive requires gfx8+", - IDRange); + return Error(IDRange.Start, "directive requires gfx8+", IDRange); if (!isUInt<1>(Val)) return OutOfRangeError(ValRange); ReserveXNACK = Val; @@ -4027,26 +4308,22 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { Val, ValRange); } else if (ID == ".amdhsa_fp16_overflow") { if (IVersion.Major < 9) - return getParser().Error(IDRange.Start, "directive requires gfx9+", - IDRange); + return Error(IDRange.Start, "directive requires gfx9+", IDRange); PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_FP16_OVFL, Val, ValRange); } else if (ID == ".amdhsa_workgroup_processor_mode") { if (IVersion.Major < 10) - return getParser().Error(IDRange.Start, "directive requires gfx10+", - IDRange); + return Error(IDRange.Start, "directive requires gfx10+", IDRange); PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_WGP_MODE, Val, ValRange); } else if (ID == ".amdhsa_memory_ordered") { if (IVersion.Major < 10) - return getParser().Error(IDRange.Start, "directive requires gfx10+", - IDRange); + return Error(IDRange.Start, "directive requires gfx10+", IDRange); PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_MEM_ORDERED, Val, ValRange); } else if (ID == ".amdhsa_forward_progress") { if (IVersion.Major < 10) - return getParser().Error(IDRange.Start, "directive requires gfx10+", - IDRange); + return Error(IDRange.Start, "directive requires gfx10+", IDRange); PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_FWD_PROGRESS, Val, ValRange); } else if (ID == ".amdhsa_exception_fp_ieee_invalid_op") { @@ -4080,8 +4357,7 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { COMPUTE_PGM_RSRC2_ENABLE_EXCEPTION_INT_DIVIDE_BY_ZERO, Val, ValRange); } else { - return getParser().Error(IDRange.Start, - "unknown .amdhsa_kernel directive", IDRange); + return Error(IDRange.Start, "unknown .amdhsa_kernel directive", IDRange); } #undef PARSE_BITS_ENTRY @@ -4145,7 +4421,7 @@ bool AMDGPUAsmParser::ParseDirectiveHSACodeObjectISA() { // If this directive has no arguments, then use the ISA version for the // targeted GPU. - if (getLexer().is(AsmToken::EndOfStatement)) { + if (isToken(AsmToken::EndOfStatement)) { AMDGPU::IsaVersion ISA = AMDGPU::getIsaVersion(getSTI().getCPU()); getTargetStreamer().EmitDirectiveHSACodeObjectISA(ISA.Major, ISA.Minor, ISA.Stepping, @@ -4156,32 +4432,23 @@ bool AMDGPUAsmParser::ParseDirectiveHSACodeObjectISA() { if (ParseDirectiveMajorMinor(Major, Minor)) return true; - if (getLexer().isNot(AsmToken::Comma)) + if (!trySkipToken(AsmToken::Comma)) return TokError("stepping version number required, comma expected"); - Lex(); if (ParseAsAbsoluteExpression(Stepping)) return TokError("invalid stepping version"); - if (getLexer().isNot(AsmToken::Comma)) + if (!trySkipToken(AsmToken::Comma)) return TokError("vendor name required, comma expected"); - Lex(); - - if (getLexer().isNot(AsmToken::String)) - return TokError("invalid vendor name"); - VendorName = getLexer().getTok().getStringContents(); - Lex(); + if (!parseString(VendorName, "invalid vendor name")) + return true; - if (getLexer().isNot(AsmToken::Comma)) + if (!trySkipToken(AsmToken::Comma)) return TokError("arch name required, comma expected"); - Lex(); - if (getLexer().isNot(AsmToken::String)) - return TokError("invalid arch name"); - - ArchName = getLexer().getTok().getStringContents(); - Lex(); + if (!parseString(ArchName, "invalid arch name")) + return true; getTargetStreamer().EmitDirectiveHSACodeObjectISA(Major, Minor, Stepping, VendorName, ArchName); @@ -4206,7 +4473,7 @@ bool AMDGPUAsmParser::ParseAMDKernelCodeTValue(StringRef ID, if (ID == "enable_wavefront_size32") { if (Header.code_properties & AMD_CODE_PROPERTY_ENABLE_WAVEFRONT_SIZE32) { - if (!isGFX10()) + if (!isGFX10Plus()) return TokError("enable_wavefront_size32=1 is only allowed on GFX10+"); if (!getFeatureBits()[AMDGPU::FeatureWavefrontSize32]) return TokError("enable_wavefront_size32=1 requires +WavefrontSize32"); @@ -4218,7 +4485,7 @@ bool AMDGPUAsmParser::ParseAMDKernelCodeTValue(StringRef ID, if (ID == "wavefront_size") { if (Header.wavefront_size == 5) { - if (!isGFX10()) + if (!isGFX10Plus()) return TokError("wavefront_size=5 is only allowed on GFX10+"); if (!getFeatureBits()[AMDGPU::FeatureWavefrontSize32]) return TokError("wavefront_size=5 requires +WavefrontSize32"); @@ -4229,17 +4496,20 @@ bool AMDGPUAsmParser::ParseAMDKernelCodeTValue(StringRef ID, } if (ID == "enable_wgp_mode") { - if (G_00B848_WGP_MODE(Header.compute_pgm_resource_registers) && !isGFX10()) + if (G_00B848_WGP_MODE(Header.compute_pgm_resource_registers) && + !isGFX10Plus()) return TokError("enable_wgp_mode=1 is only allowed on GFX10+"); } if (ID == "enable_mem_ordered") { - if (G_00B848_MEM_ORDERED(Header.compute_pgm_resource_registers) && !isGFX10()) + if (G_00B848_MEM_ORDERED(Header.compute_pgm_resource_registers) && + !isGFX10Plus()) return TokError("enable_mem_ordered=1 is only allowed on GFX10+"); } if (ID == "enable_fwd_progress") { - if (G_00B848_FWD_PROGRESS(Header.compute_pgm_resource_registers) && !isGFX10()) + if (G_00B848_FWD_PROGRESS(Header.compute_pgm_resource_registers) && + !isGFX10Plus()) return TokError("enable_fwd_progress=1 is only allowed on GFX10+"); } @@ -4253,14 +4523,11 @@ bool AMDGPUAsmParser::ParseDirectiveAMDKernelCodeT() { while (true) { // Lex EndOfStatement. This is in a while loop, because lexing a comment // will set the current token to EndOfStatement. - while(getLexer().is(AsmToken::EndOfStatement)) - Lex(); + while(trySkipToken(AsmToken::EndOfStatement)); - if (getLexer().isNot(AsmToken::Identifier)) - return TokError("expected value identifier or .end_amd_kernel_code_t"); - - StringRef ID = getLexer().getTok().getIdentifier(); - Lex(); + StringRef ID; + if (!parseId(ID, "expected value identifier or .end_amd_kernel_code_t")) + return true; if (ID == ".end_amd_kernel_code_t") break; @@ -4275,34 +4542,32 @@ bool AMDGPUAsmParser::ParseDirectiveAMDKernelCodeT() { } bool AMDGPUAsmParser::ParseDirectiveAMDGPUHsaKernel() { - if (getLexer().isNot(AsmToken::Identifier)) - return TokError("expected symbol name"); - - StringRef KernelName = Parser.getTok().getString(); + StringRef KernelName; + if (!parseId(KernelName, "expected symbol name")) + return true; getTargetStreamer().EmitAMDGPUSymbolType(KernelName, ELF::STT_AMDGPU_HSA_KERNEL); - Lex(); - if (!AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI())) - KernelScope.initialize(getContext()); + + KernelScope.initialize(getContext()); return false; } bool AMDGPUAsmParser::ParseDirectiveISAVersion() { if (getSTI().getTargetTriple().getArch() != Triple::amdgcn) { - return Error(getParser().getTok().getLoc(), + return Error(getLoc(), ".amd_amdgpu_isa directive is not available on non-amdgcn " "architectures"); } - auto ISAVersionStringFromASM = getLexer().getTok().getStringContents(); + auto ISAVersionStringFromASM = getToken().getStringContents(); std::string ISAVersionStringFromSTI; raw_string_ostream ISAVersionStreamFromSTI(ISAVersionStringFromSTI); IsaInfo::streamIsaVersion(&getSTI(), ISAVersionStreamFromSTI); if (ISAVersionStringFromASM != ISAVersionStreamFromSTI.str()) { - return Error(getParser().getTok().getLoc(), + return Error(getLoc(), ".amd_amdgpu_isa directive does not match triple and/or mcpu " "arguments specified through the command line"); } @@ -4317,14 +4582,14 @@ bool AMDGPUAsmParser::ParseDirectiveHSAMetadata() { const char *AssemblerDirectiveBegin; const char *AssemblerDirectiveEnd; std::tie(AssemblerDirectiveBegin, AssemblerDirectiveEnd) = - AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI()) + isHsaAbiVersion3(&getSTI()) ? std::make_tuple(HSAMD::V3::AssemblerDirectiveBegin, HSAMD::V3::AssemblerDirectiveEnd) : std::make_tuple(HSAMD::AssemblerDirectiveBegin, HSAMD::AssemblerDirectiveEnd); if (getSTI().getTargetTriple().getOS() != Triple::AMDHSA) { - return Error(getParser().getTok().getLoc(), + return Error(getLoc(), (Twine(AssemblerDirectiveBegin) + Twine(" directive is " "not available on non-amdhsa OSes")).str()); } @@ -4334,12 +4599,12 @@ bool AMDGPUAsmParser::ParseDirectiveHSAMetadata() { HSAMetadataString)) return true; - if (IsaInfo::hasCodeObjectV3(&getSTI())) { + if (isHsaAbiVersion3(&getSTI())) { if (!getTargetStreamer().EmitHSAMetadataV3(HSAMetadataString)) - return Error(getParser().getTok().getLoc(), "invalid HSA metadata"); + return Error(getLoc(), "invalid HSA metadata"); } else { if (!getTargetStreamer().EmitHSAMetadataV2(HSAMetadataString)) - return Error(getParser().getTok().getLoc(), "invalid HSA metadata"); + return Error(getLoc(), "invalid HSA metadata"); } return false; @@ -4356,19 +4621,15 @@ bool AMDGPUAsmParser::ParseToEndDirective(const char *AssemblerDirectiveBegin, getLexer().setSkipSpace(false); bool FoundEnd = false; - while (!getLexer().is(AsmToken::Eof)) { - while (getLexer().is(AsmToken::Space)) { - CollectStream << getLexer().getTok().getString(); + while (!isToken(AsmToken::Eof)) { + while (isToken(AsmToken::Space)) { + CollectStream << getTokenStr(); Lex(); } - if (getLexer().is(AsmToken::Identifier)) { - StringRef ID = getLexer().getTok().getIdentifier(); - if (ID == AssemblerDirectiveEnd) { - Lex(); - FoundEnd = true; - break; - } + if (trySkipId(AssemblerDirectiveEnd)) { + FoundEnd = true; + break; } CollectStream << Parser.parseStringToEndOfStatement() @@ -4379,7 +4640,7 @@ bool AMDGPUAsmParser::ParseToEndDirective(const char *AssemblerDirectiveBegin, getLexer().setSkipSpace(true); - if (getLexer().is(AsmToken::Eof) && !FoundEnd) { + if (isToken(AsmToken::Eof) && !FoundEnd) { return TokError(Twine("expected directive ") + Twine(AssemblerDirectiveEnd) + Twine(" not found")); } @@ -4397,14 +4658,14 @@ bool AMDGPUAsmParser::ParseDirectivePALMetadataBegin() { auto PALMetadata = getTargetStreamer().getPALMetadata(); if (!PALMetadata->setFromString(String)) - return Error(getParser().getTok().getLoc(), "invalid PAL metadata"); + return Error(getLoc(), "invalid PAL metadata"); return false; } /// Parse the assembler directive for old linear-format PAL metadata. bool AMDGPUAsmParser::ParseDirectivePALMetadata() { if (getSTI().getTargetTriple().getOS() != Triple::AMDPAL) { - return Error(getParser().getTok().getLoc(), + return Error(getLoc(), (Twine(PALMD::AssemblerDirective) + Twine(" directive is " "not available on non-amdpal OSes")).str()); } @@ -4417,19 +4678,17 @@ bool AMDGPUAsmParser::ParseDirectivePALMetadata() { return TokError(Twine("invalid value in ") + Twine(PALMD::AssemblerDirective)); } - if (getLexer().isNot(AsmToken::Comma)) { + if (!trySkipToken(AsmToken::Comma)) { return TokError(Twine("expected an even number of values in ") + Twine(PALMD::AssemblerDirective)); } - Lex(); if (ParseAsAbsoluteExpression(Value)) { return TokError(Twine("invalid value in ") + Twine(PALMD::AssemblerDirective)); } PALMetadata->setRegister(Key, Value); - if (getLexer().isNot(AsmToken::Comma)) + if (!trySkipToken(AsmToken::Comma)) break; - Lex(); } return false; } @@ -4441,7 +4700,7 @@ bool AMDGPUAsmParser::ParseDirectiveAMDGPULDS() { return true; StringRef Name; - SMLoc NameLoc = getLexer().getLoc(); + SMLoc NameLoc = getLoc(); if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); @@ -4452,7 +4711,7 @@ bool AMDGPUAsmParser::ParseDirectiveAMDGPULDS() { unsigned LocalMemorySize = AMDGPU::IsaInfo::getLocalMemorySize(&getSTI()); int64_t Size; - SMLoc SizeLoc = getLexer().getLoc(); + SMLoc SizeLoc = getLoc(); if (getParser().parseAbsoluteExpression(Size)) return true; if (Size < 0) @@ -4461,9 +4720,8 @@ bool AMDGPUAsmParser::ParseDirectiveAMDGPULDS() { return Error(SizeLoc, "size is too large"); int64_t Alignment = 4; - if (getLexer().is(AsmToken::Comma)) { - Lex(); - SMLoc AlignLoc = getLexer().getLoc(); + if (trySkipToken(AsmToken::Comma)) { + SMLoc AlignLoc = getLoc(); if (getParser().parseAbsoluteExpression(Alignment)) return true; if (Alignment < 0 || !isPowerOf2_64(Alignment)) @@ -4491,7 +4749,7 @@ bool AMDGPUAsmParser::ParseDirectiveAMDGPULDS() { bool AMDGPUAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); - if (AMDGPU::IsaInfo::hasCodeObjectV3(&getSTI())) { + if (isHsaAbiVersion3(&getSTI())) { if (IDVal == ".amdgcn_target") return ParseDirectiveAMDGCNTarget(); @@ -4539,7 +4797,7 @@ bool AMDGPUAsmParser::subtargetHasRegister(const MCRegisterInfo &MRI, for (MCRegAliasIterator R(AMDGPU::TTMP12_TTMP13_TTMP14_TTMP15, &MRI, true); R.isValid(); ++R) { if (*R == RegNo) - return isGFX9() || isGFX10(); + return isGFX9Plus(); } // GFX10 has 2 more SGPRs 104 and 105. @@ -4555,20 +4813,20 @@ bool AMDGPUAsmParser::subtargetHasRegister(const MCRegisterInfo &MRI, case AMDGPU::SRC_PRIVATE_BASE: case AMDGPU::SRC_PRIVATE_LIMIT: case AMDGPU::SRC_POPS_EXITING_WAVE_ID: - return !isCI() && !isSI() && !isVI(); + return isGFX9Plus(); case AMDGPU::TBA: case AMDGPU::TBA_LO: case AMDGPU::TBA_HI: case AMDGPU::TMA: case AMDGPU::TMA_LO: case AMDGPU::TMA_HI: - return !isGFX9() && !isGFX10(); + return !isGFX9Plus(); case AMDGPU::XNACK_MASK: case AMDGPU::XNACK_MASK_LO: case AMDGPU::XNACK_MASK_HI: - return !isCI() && !isSI() && !isGFX10() && hasXNACK(); + return (isVI() || isGFX9()) && hasXNACK(); case AMDGPU::SGPR_NULL: - return isGFX10(); + return isGFX10Plus(); default: break; } @@ -4576,7 +4834,7 @@ bool AMDGPUAsmParser::subtargetHasRegister(const MCRegisterInfo &MRI, if (isCI()) return true; - if (isSI() || isGFX10()) { + if (isSI() || isGFX10Plus()) { // No flat_scr on SI. // On GFX10 flat scratch is not a valid register operand and can only be // accessed with s_setreg/s_getreg. @@ -4614,35 +4872,33 @@ AMDGPUAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic, // are appending default values to the Operands list. This is only done // by custom parser, so we shouldn't continue on to the generic parsing. if (ResTy == MatchOperand_Success || ResTy == MatchOperand_ParseFail || - getLexer().is(AsmToken::EndOfStatement)) + isToken(AsmToken::EndOfStatement)) return ResTy; - if (Mode == OperandMode_NSA && getLexer().is(AsmToken::LBrac)) { + SMLoc RBraceLoc; + SMLoc LBraceLoc = getLoc(); + if (Mode == OperandMode_NSA && trySkipToken(AsmToken::LBrac)) { unsigned Prefix = Operands.size(); - SMLoc LBraceLoc = getTok().getLoc(); - Parser.Lex(); // eat the '[' for (;;) { ResTy = parseReg(Operands); if (ResTy != MatchOperand_Success) return ResTy; - if (getLexer().is(AsmToken::RBrac)) + RBraceLoc = getLoc(); + if (trySkipToken(AsmToken::RBrac)) break; - if (getLexer().isNot(AsmToken::Comma)) + if (!trySkipToken(AsmToken::Comma)) return MatchOperand_ParseFail; - Parser.Lex(); } if (Operands.size() - Prefix > 1) { Operands.insert(Operands.begin() + Prefix, AMDGPUOperand::CreateToken(this, "[", LBraceLoc)); - Operands.push_back(AMDGPUOperand::CreateToken(this, "]", - getTok().getLoc())); + Operands.push_back(AMDGPUOperand::CreateToken(this, "]", RBraceLoc)); } - Parser.Lex(); // eat the ']' return MatchOperand_Success; } @@ -4680,32 +4936,28 @@ bool AMDGPUAsmParser::ParseInstruction(ParseInstructionInfo &Info, bool IsMIMG = Name.startswith("image_"); - while (!getLexer().is(AsmToken::EndOfStatement)) { + while (!trySkipToken(AsmToken::EndOfStatement)) { OperandMode Mode = OperandMode_Default; - if (IsMIMG && isGFX10() && Operands.size() == 2) + if (IsMIMG && isGFX10Plus() && Operands.size() == 2) Mode = OperandMode_NSA; OperandMatchResultTy Res = parseOperand(Operands, Name, Mode); // Eat the comma or space if there is one. - if (getLexer().is(AsmToken::Comma)) - Parser.Lex(); + trySkipToken(AsmToken::Comma); - switch (Res) { - case MatchOperand_Success: break; - case MatchOperand_ParseFail: + if (Res != MatchOperand_Success) { + checkUnsupportedInstruction(Name, NameLoc); + if (!Parser.hasPendingError()) { // FIXME: use real operand location rather than the current location. - Error(getLexer().getLoc(), "failed parsing operand."); - while (!getLexer().is(AsmToken::EndOfStatement)) { - Parser.Lex(); - } - return true; - case MatchOperand_NoMatch: - // FIXME: use real operand location rather than the current location. - Error(getLexer().getLoc(), "not a valid operand."); - while (!getLexer().is(AsmToken::EndOfStatement)) { - Parser.Lex(); - } - return true; + StringRef Msg = + (Res == MatchOperand_ParseFail) ? "failed parsing operand." : + "not a valid operand."; + Error(getLoc(), Msg); + } + while (!trySkipToken(AsmToken::EndOfStatement)) { + lex(); + } + return true; } } @@ -4794,14 +5046,14 @@ OperandMatchResultTy AMDGPUAsmParser::parseNamedBit(const char *Name, OperandVector &Operands, AMDGPUOperand::ImmTy ImmTy) { int64_t Bit = 0; - SMLoc S = Parser.getTok().getLoc(); + SMLoc S = getLoc(); // We are at the end of the statement, and this is a default argument, so // use a default value. - if (getLexer().isNot(AsmToken::EndOfStatement)) { - switch(getLexer().getKind()) { + if (!isToken(AsmToken::EndOfStatement)) { + switch(getTokenKind()) { case AsmToken::Identifier: { - StringRef Tok = Parser.getTok().getString(); + StringRef Tok = getTokenStr(); if (Tok == Name) { if (Tok == "r128" && !hasMIMG_R128()) Error(S, "r128 modifier is not supported on this GPU"); @@ -4822,7 +5074,7 @@ AMDGPUAsmParser::parseNamedBit(const char *Name, OperandVector &Operands, } } - if (!isGFX10() && ImmTy == AMDGPUOperand::ImmTyDLC) + if (!isGFX10Plus() && ImmTy == AMDGPUOperand::ImmTyDLC) return MatchOperand_ParseFail; if (isGFX9() && ImmTy == AMDGPUOperand::ImmTyA16) @@ -4847,73 +5099,273 @@ static void addOptionalImmOperand( } OperandMatchResultTy -AMDGPUAsmParser::parseStringWithPrefix(StringRef Prefix, StringRef &Value) { - if (getLexer().isNot(AsmToken::Identifier)) { +AMDGPUAsmParser::parseStringWithPrefix(StringRef Prefix, + StringRef &Value, + SMLoc &StringLoc) { + if (!trySkipId(Prefix, AsmToken::Colon)) return MatchOperand_NoMatch; + + StringLoc = getLoc(); + return parseId(Value, "expected an identifier") ? MatchOperand_Success + : MatchOperand_ParseFail; +} + +//===----------------------------------------------------------------------===// +// MTBUF format +//===----------------------------------------------------------------------===// + +bool AMDGPUAsmParser::tryParseFmt(const char *Pref, + int64_t MaxVal, + int64_t &Fmt) { + int64_t Val; + SMLoc Loc = getLoc(); + + auto Res = parseIntWithPrefix(Pref, Val); + if (Res == MatchOperand_ParseFail) + return false; + if (Res == MatchOperand_NoMatch) + return true; + + if (Val < 0 || Val > MaxVal) { + Error(Loc, Twine("out of range ", StringRef(Pref))); + return false; } - StringRef Tok = Parser.getTok().getString(); - if (Tok != Prefix) { + + Fmt = Val; + return true; +} + +// dfmt and nfmt (in a tbuffer instruction) are parsed as one to allow their +// values to live in a joint format operand in the MCInst encoding. +OperandMatchResultTy +AMDGPUAsmParser::parseDfmtNfmt(int64_t &Format) { + using namespace llvm::AMDGPU::MTBUFFormat; + + int64_t Dfmt = DFMT_UNDEF; + int64_t Nfmt = NFMT_UNDEF; + + // dfmt and nfmt can appear in either order, and each is optional. + for (int I = 0; I < 2; ++I) { + if (Dfmt == DFMT_UNDEF && !tryParseFmt("dfmt", DFMT_MAX, Dfmt)) + return MatchOperand_ParseFail; + + if (Nfmt == NFMT_UNDEF && !tryParseFmt("nfmt", NFMT_MAX, Nfmt)) { + return MatchOperand_ParseFail; + } + // Skip optional comma between dfmt/nfmt + // but guard against 2 commas following each other. + if ((Dfmt == DFMT_UNDEF) != (Nfmt == NFMT_UNDEF) && + !peekToken().is(AsmToken::Comma)) { + trySkipToken(AsmToken::Comma); + } + } + + if (Dfmt == DFMT_UNDEF && Nfmt == NFMT_UNDEF) return MatchOperand_NoMatch; + + Dfmt = (Dfmt == DFMT_UNDEF) ? DFMT_DEFAULT : Dfmt; + Nfmt = (Nfmt == NFMT_UNDEF) ? NFMT_DEFAULT : Nfmt; + + Format = encodeDfmtNfmt(Dfmt, Nfmt); + return MatchOperand_Success; +} + +OperandMatchResultTy +AMDGPUAsmParser::parseUfmt(int64_t &Format) { + using namespace llvm::AMDGPU::MTBUFFormat; + + int64_t Fmt = UFMT_UNDEF; + + if (!tryParseFmt("format", UFMT_MAX, Fmt)) + return MatchOperand_ParseFail; + + if (Fmt == UFMT_UNDEF) + return MatchOperand_NoMatch; + + Format = Fmt; + return MatchOperand_Success; +} + +bool AMDGPUAsmParser::matchDfmtNfmt(int64_t &Dfmt, + int64_t &Nfmt, + StringRef FormatStr, + SMLoc Loc) { + using namespace llvm::AMDGPU::MTBUFFormat; + int64_t Format; + + Format = getDfmt(FormatStr); + if (Format != DFMT_UNDEF) { + Dfmt = Format; + return true; } - Parser.Lex(); - if (getLexer().isNot(AsmToken::Colon)) { + Format = getNfmt(FormatStr, getSTI()); + if (Format != NFMT_UNDEF) { + Nfmt = Format; + return true; + } + + Error(Loc, "unsupported format"); + return false; +} + +OperandMatchResultTy +AMDGPUAsmParser::parseSymbolicSplitFormat(StringRef FormatStr, + SMLoc FormatLoc, + int64_t &Format) { + using namespace llvm::AMDGPU::MTBUFFormat; + + int64_t Dfmt = DFMT_UNDEF; + int64_t Nfmt = NFMT_UNDEF; + if (!matchDfmtNfmt(Dfmt, Nfmt, FormatStr, FormatLoc)) return MatchOperand_ParseFail; + + if (trySkipToken(AsmToken::Comma)) { + StringRef Str; + SMLoc Loc = getLoc(); + if (!parseId(Str, "expected a format string") || + !matchDfmtNfmt(Dfmt, Nfmt, Str, Loc)) { + return MatchOperand_ParseFail; + } + if (Dfmt == DFMT_UNDEF) { + Error(Loc, "duplicate numeric format"); + return MatchOperand_ParseFail; + } else if (Nfmt == NFMT_UNDEF) { + Error(Loc, "duplicate data format"); + return MatchOperand_ParseFail; + } } - Parser.Lex(); - if (getLexer().isNot(AsmToken::Identifier)) { + Dfmt = (Dfmt == DFMT_UNDEF) ? DFMT_DEFAULT : Dfmt; + Nfmt = (Nfmt == NFMT_UNDEF) ? NFMT_DEFAULT : Nfmt; + + if (isGFX10Plus()) { + auto Ufmt = convertDfmtNfmt2Ufmt(Dfmt, Nfmt); + if (Ufmt == UFMT_UNDEF) { + Error(FormatLoc, "unsupported format"); + return MatchOperand_ParseFail; + } + Format = Ufmt; + } else { + Format = encodeDfmtNfmt(Dfmt, Nfmt); + } + + return MatchOperand_Success; +} + +OperandMatchResultTy +AMDGPUAsmParser::parseSymbolicUnifiedFormat(StringRef FormatStr, + SMLoc Loc, + int64_t &Format) { + using namespace llvm::AMDGPU::MTBUFFormat; + + auto Id = getUnifiedFormat(FormatStr); + if (Id == UFMT_UNDEF) + return MatchOperand_NoMatch; + + if (!isGFX10Plus()) { + Error(Loc, "unified format is not supported on this GPU"); return MatchOperand_ParseFail; } - Value = Parser.getTok().getString(); + Format = Id; return MatchOperand_Success; } -// dfmt and nfmt (in a tbuffer instruction) are parsed as one to allow their -// values to live in a joint format operand in the MCInst encoding. OperandMatchResultTy -AMDGPUAsmParser::parseDfmtNfmt(OperandVector &Operands) { - SMLoc S = Parser.getTok().getLoc(); - int64_t Dfmt = 0, Nfmt = 0; - // dfmt and nfmt can appear in either order, and each is optional. - bool GotDfmt = false, GotNfmt = false; - while (!GotDfmt || !GotNfmt) { - if (!GotDfmt) { - auto Res = parseIntWithPrefix("dfmt", Dfmt); - if (Res != MatchOperand_NoMatch) { - if (Res != MatchOperand_Success) - return Res; - if (Dfmt >= 16) { - Error(Parser.getTok().getLoc(), "out of range dfmt"); - return MatchOperand_ParseFail; - } - GotDfmt = true; - Parser.Lex(); - continue; - } - } - if (!GotNfmt) { - auto Res = parseIntWithPrefix("nfmt", Nfmt); - if (Res != MatchOperand_NoMatch) { - if (Res != MatchOperand_Success) - return Res; - if (Nfmt >= 8) { - Error(Parser.getTok().getLoc(), "out of range nfmt"); - return MatchOperand_ParseFail; - } - GotNfmt = true; - Parser.Lex(); - continue; - } - } - break; +AMDGPUAsmParser::parseNumericFormat(int64_t &Format) { + using namespace llvm::AMDGPU::MTBUFFormat; + SMLoc Loc = getLoc(); + + if (!parseExpr(Format)) + return MatchOperand_ParseFail; + if (!isValidFormatEncoding(Format, getSTI())) { + Error(Loc, "out of range format"); + return MatchOperand_ParseFail; } - if (!GotDfmt && !GotNfmt) + + return MatchOperand_Success; +} + +OperandMatchResultTy +AMDGPUAsmParser::parseSymbolicOrNumericFormat(int64_t &Format) { + using namespace llvm::AMDGPU::MTBUFFormat; + + if (!trySkipId("format", AsmToken::Colon)) return MatchOperand_NoMatch; - auto Format = Dfmt | Nfmt << 4; + + if (trySkipToken(AsmToken::LBrac)) { + StringRef FormatStr; + SMLoc Loc = getLoc(); + if (!parseId(FormatStr, "expected a format string")) + return MatchOperand_ParseFail; + + auto Res = parseSymbolicUnifiedFormat(FormatStr, Loc, Format); + if (Res == MatchOperand_NoMatch) + Res = parseSymbolicSplitFormat(FormatStr, Loc, Format); + if (Res != MatchOperand_Success) + return Res; + + if (!skipToken(AsmToken::RBrac, "expected a closing square bracket")) + return MatchOperand_ParseFail; + + return MatchOperand_Success; + } + + return parseNumericFormat(Format); +} + +OperandMatchResultTy +AMDGPUAsmParser::parseFORMAT(OperandVector &Operands) { + using namespace llvm::AMDGPU::MTBUFFormat; + + int64_t Format = getDefaultFormatEncoding(getSTI()); + OperandMatchResultTy Res; + SMLoc Loc = getLoc(); + + // Parse legacy format syntax. + Res = isGFX10Plus() ? parseUfmt(Format) : parseDfmtNfmt(Format); + if (Res == MatchOperand_ParseFail) + return Res; + + bool FormatFound = (Res == MatchOperand_Success); + Operands.push_back( - AMDGPUOperand::CreateImm(this, Format, S, AMDGPUOperand::ImmTyFORMAT)); + AMDGPUOperand::CreateImm(this, Format, Loc, AMDGPUOperand::ImmTyFORMAT)); + + if (FormatFound) + trySkipToken(AsmToken::Comma); + + if (isToken(AsmToken::EndOfStatement)) { + // We are expecting an soffset operand, + // but let matcher handle the error. + return MatchOperand_Success; + } + + // Parse soffset. + Res = parseRegOrImm(Operands); + if (Res != MatchOperand_Success) + return Res; + + trySkipToken(AsmToken::Comma); + + if (!FormatFound) { + Res = parseSymbolicOrNumericFormat(Format); + if (Res == MatchOperand_ParseFail) + return Res; + if (Res == MatchOperand_Success) { + auto Size = Operands.size(); + AMDGPUOperand &Op = static_cast<AMDGPUOperand &>(*Operands[Size - 2]); + assert(Op.isImm() && Op.getImmTy() == AMDGPUOperand::ImmTyFORMAT); + Op.setImm(Format); + } + return MatchOperand_Success; + } + + if (isId("format") && peekToken().is(AsmToken::Colon)) { + Error(getLoc(), "duplicate format"); + return MatchOperand_ParseFail; + } return MatchOperand_Success; } @@ -5122,12 +5574,14 @@ AMDGPUAsmParser::parseSWaitCntOps(OperandVector &Operands) { int64_t Waitcnt = getWaitcntBitMask(ISA); SMLoc S = getLoc(); - // If parse failed, do not return error code - // to avoid excessive error messages. if (isToken(AsmToken::Identifier) && peekToken().is(AsmToken::LParen)) { - while (parseCnt(Waitcnt) && !isToken(AsmToken::EndOfStatement)); + while (!isToken(AsmToken::EndOfStatement)) { + if (!parseCnt(Waitcnt)) + return MatchOperand_ParseFail; + } } else { - parseExpr(Waitcnt); + if (!parseExpr(Waitcnt)) + return MatchOperand_ParseFail; } Operands.push_back(AMDGPUOperand::CreateImm(this, Waitcnt, S)); @@ -5145,16 +5599,17 @@ AMDGPUOperand::isSWaitCnt() const { bool AMDGPUAsmParser::parseHwregBody(OperandInfoTy &HwReg, - int64_t &Offset, - int64_t &Width) { + OperandInfoTy &Offset, + OperandInfoTy &Width) { using namespace llvm::AMDGPU::Hwreg; // The register may be specified by name or using a numeric code + HwReg.Loc = getLoc(); if (isToken(AsmToken::Identifier) && (HwReg.Id = getHwregId(getTokenStr())) >= 0) { HwReg.IsSymbolic = true; - lex(); // skip message name - } else if (!parseExpr(HwReg.Id)) { + lex(); // skip register name + } else if (!parseExpr(HwReg.Id, "a register name")) { return false; } @@ -5162,33 +5617,45 @@ AMDGPUAsmParser::parseHwregBody(OperandInfoTy &HwReg, return true; // parse optional params - return - skipToken(AsmToken::Comma, "expected a comma or a closing parenthesis") && - parseExpr(Offset) && - skipToken(AsmToken::Comma, "expected a comma") && - parseExpr(Width) && - skipToken(AsmToken::RParen, "expected a closing parenthesis"); + if (!skipToken(AsmToken::Comma, "expected a comma or a closing parenthesis")) + return false; + + Offset.Loc = getLoc(); + if (!parseExpr(Offset.Id)) + return false; + + if (!skipToken(AsmToken::Comma, "expected a comma")) + return false; + + Width.Loc = getLoc(); + return parseExpr(Width.Id) && + skipToken(AsmToken::RParen, "expected a closing parenthesis"); } bool AMDGPUAsmParser::validateHwreg(const OperandInfoTy &HwReg, - const int64_t Offset, - const int64_t Width, - const SMLoc Loc) { + const OperandInfoTy &Offset, + const OperandInfoTy &Width) { using namespace llvm::AMDGPU::Hwreg; if (HwReg.IsSymbolic && !isValidHwreg(HwReg.Id, getSTI())) { - Error(Loc, "specified hardware register is not supported on this GPU"); + Error(HwReg.Loc, + "specified hardware register is not supported on this GPU"); return false; - } else if (!isValidHwreg(HwReg.Id)) { - Error(Loc, "invalid code of hardware register: only 6-bit values are legal"); + } + if (!isValidHwreg(HwReg.Id)) { + Error(HwReg.Loc, + "invalid code of hardware register: only 6-bit values are legal"); return false; - } else if (!isValidHwregOffset(Offset)) { - Error(Loc, "invalid bit offset: only 5-bit values are legal"); + } + if (!isValidHwregOffset(Offset.Id)) { + Error(Offset.Loc, "invalid bit offset: only 5-bit values are legal"); return false; - } else if (!isValidHwregWidth(Width)) { - Error(Loc, "invalid bitfield width: only values from 1 to 32 are legal"); + } + if (!isValidHwregWidth(Width.Id)) { + Error(Width.Loc, + "invalid bitfield width: only values from 1 to 32 are legal"); return false; } return true; @@ -5201,19 +5668,23 @@ AMDGPUAsmParser::parseHwreg(OperandVector &Operands) { int64_t ImmVal = 0; SMLoc Loc = getLoc(); - // If parse failed, do not return error code - // to avoid excessive error messages. if (trySkipId("hwreg", AsmToken::LParen)) { OperandInfoTy HwReg(ID_UNKNOWN_); - int64_t Offset = OFFSET_DEFAULT_; - int64_t Width = WIDTH_DEFAULT_; + OperandInfoTy Offset(OFFSET_DEFAULT_); + OperandInfoTy Width(WIDTH_DEFAULT_); if (parseHwregBody(HwReg, Offset, Width) && - validateHwreg(HwReg, Offset, Width, Loc)) { - ImmVal = encodeHwreg(HwReg.Id, Offset, Width); + validateHwreg(HwReg, Offset, Width)) { + ImmVal = encodeHwreg(HwReg.Id, Offset.Id, Width.Id); + } else { + return MatchOperand_ParseFail; } - } else if (parseExpr(ImmVal)) { - if (ImmVal < 0 || !isUInt<16>(ImmVal)) + } else if (parseExpr(ImmVal, "a hwreg macro")) { + if (ImmVal < 0 || !isUInt<16>(ImmVal)) { Error(Loc, "invalid immediate: only 16-bit values are legal"); + return MatchOperand_ParseFail; + } + } else { + return MatchOperand_ParseFail; } Operands.push_back(AMDGPUOperand::CreateImm(this, ImmVal, Loc, AMDGPUOperand::ImmTyHwreg)); @@ -5234,24 +5705,27 @@ AMDGPUAsmParser::parseSendMsgBody(OperandInfoTy &Msg, OperandInfoTy &Stream) { using namespace llvm::AMDGPU::SendMsg; + Msg.Loc = getLoc(); if (isToken(AsmToken::Identifier) && (Msg.Id = getMsgId(getTokenStr())) >= 0) { Msg.IsSymbolic = true; lex(); // skip message name - } else if (!parseExpr(Msg.Id)) { + } else if (!parseExpr(Msg.Id, "a message name")) { return false; } if (trySkipToken(AsmToken::Comma)) { Op.IsDefined = true; + Op.Loc = getLoc(); if (isToken(AsmToken::Identifier) && (Op.Id = getMsgOpId(Msg.Id, getTokenStr())) >= 0) { lex(); // skip operation name - } else if (!parseExpr(Op.Id)) { + } else if (!parseExpr(Op.Id, "an operation name")) { return false; } if (trySkipToken(AsmToken::Comma)) { Stream.IsDefined = true; + Stream.Loc = getLoc(); if (!parseExpr(Stream.Id)) return false; } @@ -5263,8 +5737,7 @@ AMDGPUAsmParser::parseSendMsgBody(OperandInfoTy &Msg, bool AMDGPUAsmParser::validateSendMsg(const OperandInfoTy &Msg, const OperandInfoTy &Op, - const OperandInfoTy &Stream, - const SMLoc S) { + const OperandInfoTy &Stream) { using namespace llvm::AMDGPU::SendMsg; // Validation strictness depends on whether message is specified @@ -5273,21 +5746,27 @@ AMDGPUAsmParser::validateSendMsg(const OperandInfoTy &Msg, bool Strict = Msg.IsSymbolic; if (!isValidMsgId(Msg.Id, getSTI(), Strict)) { - Error(S, "invalid message id"); + Error(Msg.Loc, "invalid message id"); return false; - } else if (Strict && (msgRequiresOp(Msg.Id) != Op.IsDefined)) { - Error(S, Op.IsDefined ? - "message does not support operations" : - "missing message operation"); + } + if (Strict && (msgRequiresOp(Msg.Id) != Op.IsDefined)) { + if (Op.IsDefined) { + Error(Op.Loc, "message does not support operations"); + } else { + Error(Msg.Loc, "missing message operation"); + } return false; - } else if (!isValidMsgOp(Msg.Id, Op.Id, Strict)) { - Error(S, "invalid operation id"); + } + if (!isValidMsgOp(Msg.Id, Op.Id, Strict)) { + Error(Op.Loc, "invalid operation id"); return false; - } else if (Strict && !msgSupportsStream(Msg.Id, Op.Id) && Stream.IsDefined) { - Error(S, "message operation does not support streams"); + } + if (Strict && !msgSupportsStream(Msg.Id, Op.Id) && Stream.IsDefined) { + Error(Stream.Loc, "message operation does not support streams"); return false; - } else if (!isValidMsgStream(Msg.Id, Op.Id, Stream.Id, Strict)) { - Error(S, "invalid message stream id"); + } + if (!isValidMsgStream(Msg.Id, Op.Id, Stream.Id, Strict)) { + Error(Stream.Loc, "invalid message stream id"); return false; } return true; @@ -5300,19 +5779,23 @@ AMDGPUAsmParser::parseSendMsgOp(OperandVector &Operands) { int64_t ImmVal = 0; SMLoc Loc = getLoc(); - // If parse failed, do not return error code - // to avoid excessive error messages. if (trySkipId("sendmsg", AsmToken::LParen)) { OperandInfoTy Msg(ID_UNKNOWN_); OperandInfoTy Op(OP_NONE_); OperandInfoTy Stream(STREAM_ID_NONE_); if (parseSendMsgBody(Msg, Op, Stream) && - validateSendMsg(Msg, Op, Stream, Loc)) { + validateSendMsg(Msg, Op, Stream)) { ImmVal = encodeMsg(Msg.Id, Op.Id, Stream.Id); + } else { + return MatchOperand_ParseFail; } - } else if (parseExpr(ImmVal)) { - if (ImmVal < 0 || !isUInt<16>(ImmVal)) + } else if (parseExpr(ImmVal, "a sendmsg macro")) { + if (ImmVal < 0 || !isUInt<16>(ImmVal)) { Error(Loc, "invalid immediate: only 16-bit values are legal"); + return MatchOperand_ParseFail; + } + } else { + return MatchOperand_ParseFail; } Operands.push_back(AMDGPUOperand::CreateImm(this, ImmVal, Loc, AMDGPUOperand::ImmTySendMsg)); @@ -5328,34 +5811,40 @@ bool AMDGPUOperand::isSendMsg() const { //===----------------------------------------------------------------------===// OperandMatchResultTy AMDGPUAsmParser::parseInterpSlot(OperandVector &Operands) { - if (getLexer().getKind() != AsmToken::Identifier) + StringRef Str; + SMLoc S = getLoc(); + + if (!parseId(Str)) return MatchOperand_NoMatch; - StringRef Str = Parser.getTok().getString(); int Slot = StringSwitch<int>(Str) .Case("p10", 0) .Case("p20", 1) .Case("p0", 2) .Default(-1); - SMLoc S = Parser.getTok().getLoc(); - if (Slot == -1) + if (Slot == -1) { + Error(S, "invalid interpolation slot"); return MatchOperand_ParseFail; + } - Parser.Lex(); Operands.push_back(AMDGPUOperand::CreateImm(this, Slot, S, AMDGPUOperand::ImmTyInterpSlot)); return MatchOperand_Success; } OperandMatchResultTy AMDGPUAsmParser::parseInterpAttr(OperandVector &Operands) { - if (getLexer().getKind() != AsmToken::Identifier) - return MatchOperand_NoMatch; + StringRef Str; + SMLoc S = getLoc(); - StringRef Str = Parser.getTok().getString(); - if (!Str.startswith("attr")) + if (!parseId(Str)) return MatchOperand_NoMatch; + if (!Str.startswith("attr")) { + Error(S, "invalid interpolation attribute"); + return MatchOperand_ParseFail; + } + StringRef Chan = Str.take_back(2); int AttrChan = StringSwitch<int>(Chan) .Case(".x", 0) @@ -5363,20 +5852,22 @@ OperandMatchResultTy AMDGPUAsmParser::parseInterpAttr(OperandVector &Operands) { .Case(".z", 2) .Case(".w", 3) .Default(-1); - if (AttrChan == -1) + if (AttrChan == -1) { + Error(S, "invalid or missing interpolation attribute channel"); return MatchOperand_ParseFail; + } Str = Str.drop_back(2).drop_front(4); uint8_t Attr; - if (Str.getAsInteger(10, Attr)) + if (Str.getAsInteger(10, Attr)) { + Error(S, "invalid or missing interpolation attribute number"); return MatchOperand_ParseFail; + } - SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); if (Attr > 63) { - Error(S, "out of bounds attr"); - return MatchOperand_Success; + Error(S, "out of bounds interpolation attribute number"); + return MatchOperand_ParseFail; } SMLoc SChan = SMLoc::getFromPointer(Chan.data()); @@ -5392,86 +5883,24 @@ OperandMatchResultTy AMDGPUAsmParser::parseInterpAttr(OperandVector &Operands) { // exp //===----------------------------------------------------------------------===// -void AMDGPUAsmParser::errorExpTgt() { - Error(Parser.getTok().getLoc(), "invalid exp target"); -} - -OperandMatchResultTy AMDGPUAsmParser::parseExpTgtImpl(StringRef Str, - uint8_t &Val) { - if (Str == "null") { - Val = 9; - return MatchOperand_Success; - } - - if (Str.startswith("mrt")) { - Str = Str.drop_front(3); - if (Str == "z") { // == mrtz - Val = 8; - return MatchOperand_Success; - } - - if (Str.getAsInteger(10, Val)) - return MatchOperand_ParseFail; - - if (Val > 7) - errorExpTgt(); - - return MatchOperand_Success; - } - - if (Str.startswith("pos")) { - Str = Str.drop_front(3); - if (Str.getAsInteger(10, Val)) - return MatchOperand_ParseFail; - - if (Val > 4 || (Val == 4 && !isGFX10())) - errorExpTgt(); - - Val += 12; - return MatchOperand_Success; - } - - if (isGFX10() && Str == "prim") { - Val = 20; - return MatchOperand_Success; - } - - if (Str.startswith("param")) { - Str = Str.drop_front(5); - if (Str.getAsInteger(10, Val)) - return MatchOperand_ParseFail; - - if (Val >= 32) - errorExpTgt(); +OperandMatchResultTy AMDGPUAsmParser::parseExpTgt(OperandVector &Operands) { + using namespace llvm::AMDGPU::Exp; - Val += 32; - return MatchOperand_Success; - } + StringRef Str; + SMLoc S = getLoc(); - if (Str.startswith("invalid_target_")) { - Str = Str.drop_front(15); - if (Str.getAsInteger(10, Val)) - return MatchOperand_ParseFail; + if (!parseId(Str)) + return MatchOperand_NoMatch; - errorExpTgt(); - return MatchOperand_Success; + unsigned Id = getTgtId(Str); + if (Id == ET_INVALID || !isSupportedTgtId(Id, getSTI())) { + Error(S, (Id == ET_INVALID) ? + "invalid exp target" : + "exp target is not supported on this GPU"); + return MatchOperand_ParseFail; } - return MatchOperand_NoMatch; -} - -OperandMatchResultTy AMDGPUAsmParser::parseExpTgt(OperandVector &Operands) { - uint8_t Val; - StringRef Str = Parser.getTok().getString(); - - auto Res = parseExpTgtImpl(Str, Val); - if (Res != MatchOperand_Success) - return Res; - - SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); - - Operands.push_back(AMDGPUOperand::CreateImm(this, Val, S, + Operands.push_back(AMDGPUOperand::CreateImm(this, Id, S, AMDGPUOperand::ImmTyExpTgt)); return MatchOperand_Success; } @@ -5534,8 +5963,23 @@ AMDGPUAsmParser::skipToken(const AsmToken::TokenKind Kind, } bool -AMDGPUAsmParser::parseExpr(int64_t &Imm) { - return !getParser().parseAbsoluteExpression(Imm); +AMDGPUAsmParser::parseExpr(int64_t &Imm, StringRef Expected) { + SMLoc S = getLoc(); + + const MCExpr *Expr; + if (Parser.parseExpression(Expr)) + return false; + + if (Expr->evaluateAsAbsolute(Imm)) + return true; + + if (Expected.empty()) { + Error(S, "expected absolute expression"); + } else { + Error(S, Twine("expected ", Expected) + + Twine(" or an absolute expression")); + } + return false; } bool @@ -5567,6 +6011,19 @@ AMDGPUAsmParser::parseString(StringRef &Val, const StringRef ErrMsg) { } } +bool +AMDGPUAsmParser::parseId(StringRef &Val, const StringRef ErrMsg) { + if (isToken(AsmToken::Identifier)) { + Val = getTokenStr(); + lex(); + return true; + } else { + if (!ErrMsg.empty()) + Error(getLoc(), ErrMsg); + return false; + } +} + AsmToken AMDGPUAsmParser::getToken() const { return Parser.getTok(); @@ -5574,7 +6031,7 @@ AMDGPUAsmParser::getToken() const { AsmToken AMDGPUAsmParser::peekToken() { - return getLexer().peekTok(); + return isToken(AsmToken::EndOfStatement) ? getToken() : getLexer().peekTok(); } void @@ -5605,6 +6062,49 @@ AMDGPUAsmParser::lex() { Parser.Lex(); } +SMLoc +AMDGPUAsmParser::getOperandLoc(std::function<bool(const AMDGPUOperand&)> Test, + const OperandVector &Operands) const { + for (unsigned i = Operands.size() - 1; i > 0; --i) { + AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[i]); + if (Test(Op)) + return Op.getStartLoc(); + } + return ((AMDGPUOperand &)*Operands[0]).getStartLoc(); +} + +SMLoc +AMDGPUAsmParser::getImmLoc(AMDGPUOperand::ImmTy Type, + const OperandVector &Operands) const { + auto Test = [=](const AMDGPUOperand& Op) { return Op.isImmTy(Type); }; + return getOperandLoc(Test, Operands); +} + +SMLoc +AMDGPUAsmParser::getRegLoc(unsigned Reg, + const OperandVector &Operands) const { + auto Test = [=](const AMDGPUOperand& Op) { + return Op.isRegKind() && Op.getReg() == Reg; + }; + return getOperandLoc(Test, Operands); +} + +SMLoc +AMDGPUAsmParser::getLitLoc(const OperandVector &Operands) const { + auto Test = [](const AMDGPUOperand& Op) { + return Op.IsImmKindLiteral() || Op.isExpr(); + }; + return getOperandLoc(Test, Operands); +} + +SMLoc +AMDGPUAsmParser::getConstLoc(const OperandVector &Operands) const { + auto Test = [](const AMDGPUOperand& Op) { + return Op.isImmKindConst(); + }; + return getOperandLoc(Test, Operands); +} + //===----------------------------------------------------------------------===// // swizzle //===----------------------------------------------------------------------===// @@ -5623,22 +6123,35 @@ encodeBitmaskPerm(const unsigned AndMask, } bool +AMDGPUAsmParser::parseSwizzleOperand(int64_t &Op, + const unsigned MinVal, + const unsigned MaxVal, + const StringRef ErrMsg, + SMLoc &Loc) { + if (!skipToken(AsmToken::Comma, "expected a comma")) { + return false; + } + Loc = getLoc(); + if (!parseExpr(Op)) { + return false; + } + if (Op < MinVal || Op > MaxVal) { + Error(Loc, ErrMsg); + return false; + } + + return true; +} + +bool AMDGPUAsmParser::parseSwizzleOperands(const unsigned OpNum, int64_t* Op, const unsigned MinVal, const unsigned MaxVal, const StringRef ErrMsg) { + SMLoc Loc; for (unsigned i = 0; i < OpNum; ++i) { - if (!skipToken(AsmToken::Comma, "expected a comma")){ + if (!parseSwizzleOperand(Op[i], MinVal, MaxVal, ErrMsg, Loc)) return false; - } - SMLoc ExprLoc = Parser.getTok().getLoc(); - if (!parseExpr(Op[i])) { - return false; - } - if (Op[i] < MinVal || Op[i] > MaxVal) { - Error(ExprLoc, ErrMsg); - return false; - } } return true; @@ -5664,22 +6177,24 @@ bool AMDGPUAsmParser::parseSwizzleBroadcast(int64_t &Imm) { using namespace llvm::AMDGPU::Swizzle; - SMLoc S = Parser.getTok().getLoc(); + SMLoc Loc; int64_t GroupSize; int64_t LaneIdx; - if (!parseSwizzleOperands(1, &GroupSize, - 2, 32, - "group size must be in the interval [2,32]")) { + if (!parseSwizzleOperand(GroupSize, + 2, 32, + "group size must be in the interval [2,32]", + Loc)) { return false; } if (!isPowerOf2_64(GroupSize)) { - Error(S, "group size must be a power of two"); + Error(Loc, "group size must be a power of two"); return false; } - if (parseSwizzleOperands(1, &LaneIdx, - 0, GroupSize - 1, - "lane id must be in the interval [0,group size - 1]")) { + if (parseSwizzleOperand(LaneIdx, + 0, GroupSize - 1, + "lane id must be in the interval [0,group size - 1]", + Loc)) { Imm = encodeBitmaskPerm(BITMASK_MAX - GroupSize + 1, LaneIdx, 0); return true; } @@ -5690,15 +6205,17 @@ bool AMDGPUAsmParser::parseSwizzleReverse(int64_t &Imm) { using namespace llvm::AMDGPU::Swizzle; - SMLoc S = Parser.getTok().getLoc(); + SMLoc Loc; int64_t GroupSize; - if (!parseSwizzleOperands(1, &GroupSize, - 2, 32, "group size must be in the interval [2,32]")) { + if (!parseSwizzleOperand(GroupSize, + 2, 32, + "group size must be in the interval [2,32]", + Loc)) { return false; } if (!isPowerOf2_64(GroupSize)) { - Error(S, "group size must be a power of two"); + Error(Loc, "group size must be a power of two"); return false; } @@ -5710,15 +6227,17 @@ bool AMDGPUAsmParser::parseSwizzleSwap(int64_t &Imm) { using namespace llvm::AMDGPU::Swizzle; - SMLoc S = Parser.getTok().getLoc(); + SMLoc Loc; int64_t GroupSize; - if (!parseSwizzleOperands(1, &GroupSize, - 1, 16, "group size must be in the interval [1,16]")) { + if (!parseSwizzleOperand(GroupSize, + 1, 16, + "group size must be in the interval [1,16]", + Loc)) { return false; } if (!isPowerOf2_64(GroupSize)) { - Error(S, "group size must be a power of two"); + Error(Loc, "group size must be a power of two"); return false; } @@ -5735,7 +6254,7 @@ AMDGPUAsmParser::parseSwizzleBitmaskPerm(int64_t &Imm) { } StringRef Ctl; - SMLoc StrLoc = Parser.getTok().getLoc(); + SMLoc StrLoc = getLoc(); if (!parseString(Ctl)) { return false; } @@ -5776,9 +6295,9 @@ AMDGPUAsmParser::parseSwizzleBitmaskPerm(int64_t &Imm) { bool AMDGPUAsmParser::parseSwizzleOffset(int64_t &Imm) { - SMLoc OffsetLoc = Parser.getTok().getLoc(); + SMLoc OffsetLoc = getLoc(); - if (!parseExpr(Imm)) { + if (!parseExpr(Imm, "a swizzle macro")) { return false; } if (!isUInt<16>(Imm)) { @@ -5794,7 +6313,7 @@ AMDGPUAsmParser::parseSwizzleMacro(int64_t &Imm) { if (skipToken(AsmToken::LParen, "expected a left parentheses")) { - SMLoc ModeLoc = Parser.getTok().getLoc(); + SMLoc ModeLoc = getLoc(); bool Ok = false; if (trySkipId(IdSymbolic[ID_QUAD_PERM])) { @@ -5819,7 +6338,7 @@ AMDGPUAsmParser::parseSwizzleMacro(int64_t &Imm) { OperandMatchResultTy AMDGPUAsmParser::parseSwizzleOp(OperandVector &Operands) { - SMLoc S = Parser.getTok().getLoc(); + SMLoc S = getLoc(); int64_t Imm = 0; if (trySkipId("offset")) { @@ -5864,7 +6383,7 @@ int64_t AMDGPUAsmParser::parseGPRIdxMacro() { while (true) { unsigned Mode = 0; - SMLoc S = Parser.getTok().getLoc(); + SMLoc S = getLoc(); for (unsigned ModeId = ID_MIN; ModeId <= ID_MAX; ++ModeId) { if (trySkipId(IdSymbolic[ModeId])) { @@ -5877,12 +6396,12 @@ int64_t AMDGPUAsmParser::parseGPRIdxMacro() { Error(S, (Imm == 0)? "expected a VGPR index mode or a closing parenthesis" : "expected a VGPR index mode"); - break; + return UNDEF; } if (Imm & Mode) { Error(S, "duplicate VGPR index mode"); - break; + return UNDEF; } Imm |= Mode; @@ -5890,7 +6409,7 @@ int64_t AMDGPUAsmParser::parseGPRIdxMacro() { break; if (!skipToken(AsmToken::Comma, "expected a comma or a closing parenthesis")) - break; + return UNDEF; } return Imm; @@ -5899,25 +6418,21 @@ int64_t AMDGPUAsmParser::parseGPRIdxMacro() { OperandMatchResultTy AMDGPUAsmParser::parseGPRIdxMode(OperandVector &Operands) { - int64_t Imm = 0; - SMLoc S = Parser.getTok().getLoc(); - - if (getLexer().getKind() == AsmToken::Identifier && - Parser.getTok().getString() == "gpr_idx" && - getLexer().peekTok().is(AsmToken::LParen)) { + using namespace llvm::AMDGPU::VGPRIndexMode; - Parser.Lex(); - Parser.Lex(); + int64_t Imm = 0; + SMLoc S = getLoc(); - // If parse failed, trigger an error but do not return error code - // to avoid excessive error messages. + if (trySkipId("gpr_idx", AsmToken::LParen)) { Imm = parseGPRIdxMacro(); - + if (Imm == UNDEF) + return MatchOperand_ParseFail; } else { if (getParser().parseAbsoluteExpression(Imm)) - return MatchOperand_NoMatch; + return MatchOperand_ParseFail; if (Imm < 0 || !isUInt<4>(Imm)) { Error(S, "invalid immediate: only 4-bit values are legal"); + return MatchOperand_ParseFail; } } @@ -5943,22 +6458,22 @@ AMDGPUAsmParser::parseSOppBrTarget(OperandVector &Operands) { if (isRegister() || isModifier()) return MatchOperand_NoMatch; - if (parseExpr(Operands)) { + if (!parseExpr(Operands)) + return MatchOperand_ParseFail; - AMDGPUOperand &Opr = ((AMDGPUOperand &)*Operands[Operands.size() - 1]); - assert(Opr.isImm() || Opr.isExpr()); - SMLoc Loc = Opr.getStartLoc(); + AMDGPUOperand &Opr = ((AMDGPUOperand &)*Operands[Operands.size() - 1]); + assert(Opr.isImm() || Opr.isExpr()); + SMLoc Loc = Opr.getStartLoc(); - // Currently we do not support arbitrary expressions as branch targets. - // Only labels and absolute expressions are accepted. - if (Opr.isExpr() && !Opr.isSymbolRefExpr()) { - Error(Loc, "expected an absolute expression or a label"); - } else if (Opr.isImm() && !Opr.isS16Imm()) { - Error(Loc, "expected a 16-bit signed jump offset"); - } + // Currently we do not support arbitrary expressions as branch targets. + // Only labels and absolute expressions are accepted. + if (Opr.isExpr() && !Opr.isSymbolRefExpr()) { + Error(Loc, "expected an absolute expression or a label"); + } else if (Opr.isImm() && !Opr.isS16Imm()) { + Error(Loc, "expected a 16-bit signed jump offset"); } - return MatchOperand_Success; // avoid excessive error messages + return MatchOperand_Success; } //===----------------------------------------------------------------------===// @@ -5982,6 +6497,10 @@ AMDGPUOperand::Ptr AMDGPUAsmParser::defaultGLC() const { return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyGLC); } +AMDGPUOperand::Ptr AMDGPUAsmParser::defaultGLC_1() const { + return AMDGPUOperand::CreateImm(this, -1, SMLoc(), AMDGPUOperand::ImmTyGLC); +} + AMDGPUOperand::Ptr AMDGPUAsmParser::defaultSLC() const { return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTySLC); } @@ -6046,8 +6565,9 @@ void AMDGPUAsmParser::cvtMubufImpl(MCInst &Inst, } addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyOffset); - if (!IsAtomic) { // glc is hard-coded. - addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyGLC); + if (!IsAtomic || IsAtomicReturn) { + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyGLC, + IsAtomicReturn ? -1 : 0); } addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySLC); @@ -6055,7 +6575,7 @@ void AMDGPUAsmParser::cvtMubufImpl(MCInst &Inst, addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyTFE); } - if (isGFX10()) + if (isGFX10Plus()) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDLC); } @@ -6095,7 +6615,7 @@ void AMDGPUAsmParser::cvtMtbuf(MCInst &Inst, const OperandVector &Operands) { addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySLC); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyTFE); - if (isGFX10()) + if (isGFX10Plus()) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDLC); } @@ -6132,22 +6652,22 @@ void AMDGPUAsmParser::cvtMIMG(MCInst &Inst, const OperandVector &Operands, } } - bool IsGFX10 = isGFX10(); + bool IsGFX10Plus = isGFX10Plus(); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDMask); - if (IsGFX10) + if (IsGFX10Plus) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDim, -1); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyUNorm); - if (IsGFX10) + if (IsGFX10Plus) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDLC); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyGLC); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySLC); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyR128A16); - if (IsGFX10) + if (IsGFX10Plus) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyA16); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyTFE); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyLWE); - if (!IsGFX10) + if (!IsGFX10Plus) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDA); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyD16); } @@ -6156,6 +6676,17 @@ void AMDGPUAsmParser::cvtMIMGAtomic(MCInst &Inst, const OperandVector &Operands) cvtMIMG(Inst, Operands, true); } +void AMDGPUAsmParser::cvtIntersectRay(MCInst &Inst, + const OperandVector &Operands) { + for (unsigned I = 1; I < Operands.size(); ++I) { + auto &Operand = (AMDGPUOperand &)*Operands[I]; + if (Operand.isReg()) + Operand.addRegOperands(Inst, 1); + } + + Inst.addOperand(MCOperand::createImm(1)); // a16 +} + //===----------------------------------------------------------------------===// // smrd //===----------------------------------------------------------------------===// @@ -6242,7 +6773,6 @@ static const OptionalOperand AMDGPUOptionalOperandTable[] = { {"offset", AMDGPUOperand::ImmTyOffset, false, nullptr}, {"inst_offset", AMDGPUOperand::ImmTyInstOffset, false, nullptr}, {"dlc", AMDGPUOperand::ImmTyDLC, true, nullptr}, - {"format", AMDGPUOperand::ImmTyFORMAT, false, nullptr}, {"glc", AMDGPUOperand::ImmTyGLC, true, nullptr}, {"slc", AMDGPUOperand::ImmTySLC, true, nullptr}, {"swz", AMDGPUOperand::ImmTySWZ, true, nullptr}, @@ -6327,8 +6857,6 @@ OperandMatchResultTy AMDGPUAsmParser::parseOptionalOpr(OperandVector &Operands) Op.ConvertResult); } else if (Op.Type == AMDGPUOperand::ImmTyDim) { res = parseDim(Operands); - } else if (Op.Type == AMDGPUOperand::ImmTyFORMAT && !isGFX10()) { - res = parseDfmtNfmt(Operands); } else { res = parseIntWithPrefix(Op.Name, Operands, Op.Type, Op.ConvertResult); } @@ -6340,7 +6868,7 @@ OperandMatchResultTy AMDGPUAsmParser::parseOptionalOpr(OperandVector &Operands) } OperandMatchResultTy AMDGPUAsmParser::parseOModOperand(OperandVector &Operands) { - StringRef Name = Parser.getTok().getString(); + StringRef Name = getTokenStr(); if (Name == "mul") { return parseIntWithPrefix("mul", Operands, AMDGPUOperand::ImmTyOModSI, ConvertOmodMul); @@ -6479,15 +7007,19 @@ void AMDGPUAsmParser::cvtVOP3(MCInst &Inst, const OperandVector &Operands, if (Opc == AMDGPU::V_MAC_F32_e64_gfx6_gfx7 || Opc == AMDGPU::V_MAC_F32_e64_gfx10 || Opc == AMDGPU::V_MAC_F32_e64_vi || + Opc == AMDGPU::V_MAC_LEGACY_F32_e64_gfx6_gfx7 || + Opc == AMDGPU::V_MAC_LEGACY_F32_e64_gfx10 || Opc == AMDGPU::V_MAC_F16_e64_vi || Opc == AMDGPU::V_FMAC_F32_e64_gfx10 || Opc == AMDGPU::V_FMAC_F32_e64_vi || + Opc == AMDGPU::V_FMAC_LEGACY_F32_e64_gfx10 || Opc == AMDGPU::V_FMAC_F16_e64_gfx10) { auto it = Inst.begin(); std::advance(it, AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2_modifiers)); it = Inst.insert(it, MCOperand::createImm(0)); // no modifiers for src2 ++it; - Inst.insert(it, Inst.getOperand(0)); // src2 = dst + // Copy the operand to ensure it's not invalidated when Inst grows. + Inst.insert(it, MCOperand(Inst.getOperand(0))); // src2 = dst } } @@ -6636,35 +7168,27 @@ bool AMDGPUOperand::isU16Imm() const { } OperandMatchResultTy AMDGPUAsmParser::parseDim(OperandVector &Operands) { - if (!isGFX10()) + if (!isGFX10Plus()) return MatchOperand_NoMatch; - SMLoc S = Parser.getTok().getLoc(); + SMLoc S = getLoc(); - if (getLexer().isNot(AsmToken::Identifier)) - return MatchOperand_NoMatch; - if (getLexer().getTok().getString() != "dim") + if (!trySkipId("dim", AsmToken::Colon)) return MatchOperand_NoMatch; - Parser.Lex(); - if (getLexer().isNot(AsmToken::Colon)) - return MatchOperand_ParseFail; - - Parser.Lex(); - // We want to allow "dim:1D" etc., but the initial 1 is tokenized as an // integer. std::string Token; - if (getLexer().is(AsmToken::Integer)) { - SMLoc Loc = getLexer().getTok().getEndLoc(); - Token = std::string(getLexer().getTok().getString()); - Parser.Lex(); - if (getLexer().getTok().getLoc() != Loc) + if (isToken(AsmToken::Integer)) { + SMLoc Loc = getToken().getEndLoc(); + Token = std::string(getTokenStr()); + lex(); + if (getLoc() != Loc) return MatchOperand_ParseFail; } - if (getLexer().isNot(AsmToken::Identifier)) + if (!isToken(AsmToken::Identifier)) return MatchOperand_ParseFail; - Token += getLexer().getTok().getString(); + Token += getTokenStr(); StringRef DimId = Token; if (DimId.startswith("SQ_RSRC_IMG_")) @@ -6674,7 +7198,7 @@ OperandMatchResultTy AMDGPUAsmParser::parseDim(OperandVector &Operands) { if (!DimInfo) return MatchOperand_ParseFail; - Parser.Lex(); + lex(); Operands.push_back(AMDGPUOperand::CreateImm(this, DimInfo->Encoding, S, AMDGPUOperand::ImmTyDim)); @@ -6682,52 +7206,33 @@ OperandMatchResultTy AMDGPUAsmParser::parseDim(OperandVector &Operands) { } OperandMatchResultTy AMDGPUAsmParser::parseDPP8(OperandVector &Operands) { - SMLoc S = Parser.getTok().getLoc(); - StringRef Prefix; - - if (getLexer().getKind() == AsmToken::Identifier) { - Prefix = Parser.getTok().getString(); - } else { - return MatchOperand_NoMatch; - } + SMLoc S = getLoc(); - if (Prefix != "dpp8") - return parseDPPCtrl(Operands); - if (!isGFX10()) + if (!isGFX10Plus() || !trySkipId("dpp8", AsmToken::Colon)) return MatchOperand_NoMatch; // dpp8:[%d,%d,%d,%d,%d,%d,%d,%d] int64_t Sels[8]; - Parser.Lex(); - if (getLexer().isNot(AsmToken::Colon)) - return MatchOperand_ParseFail; - - Parser.Lex(); - if (getLexer().isNot(AsmToken::LBrac)) + if (!skipToken(AsmToken::LBrac, "expected an opening square bracket")) return MatchOperand_ParseFail; - Parser.Lex(); - if (getParser().parseAbsoluteExpression(Sels[0])) - return MatchOperand_ParseFail; - if (0 > Sels[0] || 7 < Sels[0]) - return MatchOperand_ParseFail; - - for (size_t i = 1; i < 8; ++i) { - if (getLexer().isNot(AsmToken::Comma)) + for (size_t i = 0; i < 8; ++i) { + if (i > 0 && !skipToken(AsmToken::Comma, "expected a comma")) return MatchOperand_ParseFail; - Parser.Lex(); + SMLoc Loc = getLoc(); if (getParser().parseAbsoluteExpression(Sels[i])) return MatchOperand_ParseFail; - if (0 > Sels[i] || 7 < Sels[i]) + if (0 > Sels[i] || 7 < Sels[i]) { + Error(Loc, "expected a 3-bit value"); return MatchOperand_ParseFail; + } } - if (getLexer().isNot(AsmToken::RBrac)) + if (!skipToken(AsmToken::RBrac, "expected a closing square bracket")) return MatchOperand_ParseFail; - Parser.Lex(); unsigned DPP8 = 0; for (size_t i = 0; i < 8; ++i) @@ -6737,119 +7242,138 @@ OperandMatchResultTy AMDGPUAsmParser::parseDPP8(OperandVector &Operands) { return MatchOperand_Success; } -OperandMatchResultTy -AMDGPUAsmParser::parseDPPCtrl(OperandVector &Operands) { +bool +AMDGPUAsmParser::isSupportedDPPCtrl(StringRef Ctrl, + const OperandVector &Operands) { + if (Ctrl == "row_share" || + Ctrl == "row_xmask") + return isGFX10Plus(); + + if (Ctrl == "wave_shl" || + Ctrl == "wave_shr" || + Ctrl == "wave_rol" || + Ctrl == "wave_ror" || + Ctrl == "row_bcast") + return isVI() || isGFX9(); + + return Ctrl == "row_mirror" || + Ctrl == "row_half_mirror" || + Ctrl == "quad_perm" || + Ctrl == "row_shl" || + Ctrl == "row_shr" || + Ctrl == "row_ror"; +} + +int64_t +AMDGPUAsmParser::parseDPPCtrlPerm() { + // quad_perm:[%d,%d,%d,%d] + + if (!skipToken(AsmToken::LBrac, "expected an opening square bracket")) + return -1; + + int64_t Val = 0; + for (int i = 0; i < 4; ++i) { + if (i > 0 && !skipToken(AsmToken::Comma, "expected a comma")) + return -1; + + int64_t Temp; + SMLoc Loc = getLoc(); + if (getParser().parseAbsoluteExpression(Temp)) + return -1; + if (Temp < 0 || Temp > 3) { + Error(Loc, "expected a 2-bit value"); + return -1; + } + + Val += (Temp << i * 2); + } + + if (!skipToken(AsmToken::RBrac, "expected a closing square bracket")) + return -1; + + return Val; +} + +int64_t +AMDGPUAsmParser::parseDPPCtrlSel(StringRef Ctrl) { using namespace AMDGPU::DPP; - SMLoc S = Parser.getTok().getLoc(); - StringRef Prefix; - int64_t Int; + // sel:%d + + int64_t Val; + SMLoc Loc = getLoc(); - if (getLexer().getKind() == AsmToken::Identifier) { - Prefix = Parser.getTok().getString(); + if (getParser().parseAbsoluteExpression(Val)) + return -1; + + struct DppCtrlCheck { + int64_t Ctrl; + int Lo; + int Hi; + }; + + DppCtrlCheck Check = StringSwitch<DppCtrlCheck>(Ctrl) + .Case("wave_shl", {DppCtrl::WAVE_SHL1, 1, 1}) + .Case("wave_rol", {DppCtrl::WAVE_ROL1, 1, 1}) + .Case("wave_shr", {DppCtrl::WAVE_SHR1, 1, 1}) + .Case("wave_ror", {DppCtrl::WAVE_ROR1, 1, 1}) + .Case("row_shl", {DppCtrl::ROW_SHL0, 1, 15}) + .Case("row_shr", {DppCtrl::ROW_SHR0, 1, 15}) + .Case("row_ror", {DppCtrl::ROW_ROR0, 1, 15}) + .Case("row_share", {DppCtrl::ROW_SHARE_FIRST, 0, 15}) + .Case("row_xmask", {DppCtrl::ROW_XMASK_FIRST, 0, 15}) + .Default({-1, 0, 0}); + + bool Valid; + if (Check.Ctrl == -1) { + Valid = (Ctrl == "row_bcast" && (Val == 15 || Val == 31)); + Val = (Val == 15)? DppCtrl::BCAST15 : DppCtrl::BCAST31; } else { - return MatchOperand_NoMatch; + Valid = Check.Lo <= Val && Val <= Check.Hi; + Val = (Check.Lo == Check.Hi) ? Check.Ctrl : (Check.Ctrl | Val); } - if (Prefix == "row_mirror") { - Int = DppCtrl::ROW_MIRROR; - Parser.Lex(); - } else if (Prefix == "row_half_mirror") { - Int = DppCtrl::ROW_HALF_MIRROR; - Parser.Lex(); - } else { - // Check to prevent parseDPPCtrlOps from eating invalid tokens - if (Prefix != "quad_perm" - && Prefix != "row_shl" - && Prefix != "row_shr" - && Prefix != "row_ror" - && Prefix != "wave_shl" - && Prefix != "wave_rol" - && Prefix != "wave_shr" - && Prefix != "wave_ror" - && Prefix != "row_bcast" - && Prefix != "row_share" - && Prefix != "row_xmask") { - return MatchOperand_NoMatch; - } - - if (!isGFX10() && (Prefix == "row_share" || Prefix == "row_xmask")) - return MatchOperand_NoMatch; - - if (!isVI() && !isGFX9() && - (Prefix == "wave_shl" || Prefix == "wave_shr" || - Prefix == "wave_rol" || Prefix == "wave_ror" || - Prefix == "row_bcast")) - return MatchOperand_NoMatch; - - Parser.Lex(); - if (getLexer().isNot(AsmToken::Colon)) - return MatchOperand_ParseFail; + if (!Valid) { + Error(Loc, Twine("invalid ", Ctrl) + Twine(" value")); + return -1; + } - if (Prefix == "quad_perm") { - // quad_perm:[%d,%d,%d,%d] - Parser.Lex(); - if (getLexer().isNot(AsmToken::LBrac)) - return MatchOperand_ParseFail; - Parser.Lex(); + return Val; +} - if (getParser().parseAbsoluteExpression(Int) || !(0 <= Int && Int <=3)) - return MatchOperand_ParseFail; +OperandMatchResultTy +AMDGPUAsmParser::parseDPPCtrl(OperandVector &Operands) { + using namespace AMDGPU::DPP; - for (int i = 0; i < 3; ++i) { - if (getLexer().isNot(AsmToken::Comma)) - return MatchOperand_ParseFail; - Parser.Lex(); + if (!isToken(AsmToken::Identifier) || + !isSupportedDPPCtrl(getTokenStr(), Operands)) + return MatchOperand_NoMatch; - int64_t Temp; - if (getParser().parseAbsoluteExpression(Temp) || !(0 <= Temp && Temp <=3)) - return MatchOperand_ParseFail; - const int shift = i*2 + 2; - Int += (Temp << shift); - } + SMLoc S = getLoc(); + int64_t Val = -1; + StringRef Ctrl; - if (getLexer().isNot(AsmToken::RBrac)) - return MatchOperand_ParseFail; - Parser.Lex(); - } else { - // sel:%d - Parser.Lex(); - if (getParser().parseAbsoluteExpression(Int)) - return MatchOperand_ParseFail; + parseId(Ctrl); - if (Prefix == "row_shl" && 1 <= Int && Int <= 15) { - Int |= DppCtrl::ROW_SHL0; - } else if (Prefix == "row_shr" && 1 <= Int && Int <= 15) { - Int |= DppCtrl::ROW_SHR0; - } else if (Prefix == "row_ror" && 1 <= Int && Int <= 15) { - Int |= DppCtrl::ROW_ROR0; - } else if (Prefix == "wave_shl" && 1 == Int) { - Int = DppCtrl::WAVE_SHL1; - } else if (Prefix == "wave_rol" && 1 == Int) { - Int = DppCtrl::WAVE_ROL1; - } else if (Prefix == "wave_shr" && 1 == Int) { - Int = DppCtrl::WAVE_SHR1; - } else if (Prefix == "wave_ror" && 1 == Int) { - Int = DppCtrl::WAVE_ROR1; - } else if (Prefix == "row_bcast") { - if (Int == 15) { - Int = DppCtrl::BCAST15; - } else if (Int == 31) { - Int = DppCtrl::BCAST31; - } else { - return MatchOperand_ParseFail; - } - } else if (Prefix == "row_share" && 0 <= Int && Int <= 15) { - Int |= DppCtrl::ROW_SHARE_FIRST; - } else if (Prefix == "row_xmask" && 0 <= Int && Int <= 15) { - Int |= DppCtrl::ROW_XMASK_FIRST; + if (Ctrl == "row_mirror") { + Val = DppCtrl::ROW_MIRROR; + } else if (Ctrl == "row_half_mirror") { + Val = DppCtrl::ROW_HALF_MIRROR; + } else { + if (skipToken(AsmToken::Colon, "expected a colon")) { + if (Ctrl == "quad_perm") { + Val = parseDPPCtrlPerm(); } else { - return MatchOperand_ParseFail; + Val = parseDPPCtrlSel(Ctrl); } } } - Operands.push_back(AMDGPUOperand::CreateImm(this, Int, S, AMDGPUOperand::ImmTyDppCtrl)); + if (Val == -1) + return MatchOperand_ParseFail; + + Operands.push_back( + AMDGPUOperand::CreateImm(this, Val, S, AMDGPUOperand::ImmTyDppCtrl)); return MatchOperand_Success; } @@ -6947,11 +7471,12 @@ AMDGPUAsmParser::parseSDWASel(OperandVector &Operands, StringRef Prefix, AMDGPUOperand::ImmTy Type) { using namespace llvm::AMDGPU::SDWA; - SMLoc S = Parser.getTok().getLoc(); + SMLoc S = getLoc(); StringRef Value; OperandMatchResultTy res; - res = parseStringWithPrefix(Prefix, Value); + SMLoc StringLoc; + res = parseStringWithPrefix(Prefix, Value, StringLoc); if (res != MatchOperand_Success) { return res; } @@ -6966,9 +7491,9 @@ AMDGPUAsmParser::parseSDWASel(OperandVector &Operands, StringRef Prefix, .Case("WORD_1", SdwaSel::WORD_1) .Case("DWORD", SdwaSel::DWORD) .Default(0xffffffff); - Parser.Lex(); // eat last token if (Int == 0xffffffff) { + Error(StringLoc, "invalid " + Twine(Prefix) + " value"); return MatchOperand_ParseFail; } @@ -6980,11 +7505,12 @@ OperandMatchResultTy AMDGPUAsmParser::parseSDWADstUnused(OperandVector &Operands) { using namespace llvm::AMDGPU::SDWA; - SMLoc S = Parser.getTok().getLoc(); + SMLoc S = getLoc(); StringRef Value; OperandMatchResultTy res; - res = parseStringWithPrefix("dst_unused", Value); + SMLoc StringLoc; + res = parseStringWithPrefix("dst_unused", Value, StringLoc); if (res != MatchOperand_Success) { return res; } @@ -6995,9 +7521,9 @@ AMDGPUAsmParser::parseSDWADstUnused(OperandVector &Operands) { .Case("UNUSED_SEXT", DstUnused::UNUSED_SEXT) .Case("UNUSED_PRESERVE", DstUnused::UNUSED_PRESERVE) .Default(0xffffffff); - Parser.Lex(); // eat last token if (Int == 0xffffffff) { + Error(StringLoc, "invalid dst_unused value"); return MatchOperand_ParseFail; } @@ -7146,6 +7672,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAMDGPUAsmParser() { #define GET_REGISTER_MATCHER #define GET_MATCHER_IMPLEMENTATION #define GET_MNEMONIC_SPELL_CHECKER +#define GET_MNEMONIC_CHECKER #include "AMDGPUGenAsmMatcher.inc" // This fuction should be defined after auto-generated include so that we have @@ -7210,7 +7737,7 @@ unsigned AMDGPUAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op, //===----------------------------------------------------------------------===// OperandMatchResultTy AMDGPUAsmParser::parseEndpgmOp(OperandVector &Operands) { - SMLoc S = Parser.getTok().getLoc(); + SMLoc S = getLoc(); int64_t Imm = 0; if (!parseExpr(Imm)) { |