diff options
Diffstat (limited to 'gnu/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp')
| -rw-r--r-- | gnu/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp | 463 |
1 files changed, 357 insertions, 106 deletions
diff --git a/gnu/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/gnu/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp index b37c274102b..2e3a453f9c7 100644 --- a/gnu/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/gnu/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -1,4 +1,4 @@ -//===-- AMDGPUAsmParser.cpp - Parse SI asm to MCInst instructions ---------===// +//===- AMDGPUAsmParser.cpp - Parse SI asm to MCInst instructions ----------===// // // The LLVM Compiler Infrastructure // @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "AMDGPU.h" #include "AMDKernelCodeT.h" #include "MCTargetDesc/AMDGPUMCTargetDesc.h" #include "MCTargetDesc/AMDGPUTargetStreamer.h" @@ -40,7 +41,9 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/AMDGPUMetadata.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" @@ -83,7 +86,7 @@ public: AMDGPUOperand(KindTy Kind_, const AMDGPUAsmParser *AsmParser_) : MCParsedAsmOperand(), Kind(Kind_), AsmParser(AsmParser_) {} - typedef std::unique_ptr<AMDGPUOperand> Ptr; + using Ptr = std::unique_ptr<AMDGPUOperand>; struct Modifiers { bool Abs = false; @@ -129,6 +132,7 @@ public: ImmTyIdxen, ImmTyAddr64, ImmTyOffset, + ImmTyInstOffset, ImmTyOffset0, ImmTyOffset1, ImmTyGLC, @@ -164,7 +168,8 @@ public: ImmTyOpSelHi, ImmTyNegLo, ImmTyNegHi, - ImmTySwizzle + ImmTySwizzle, + ImmTyHigh }; struct TokOp { @@ -290,8 +295,8 @@ public: bool isOffset0() const { return isImmTy(ImmTyOffset0) && isUInt<16>(getImm()); } bool isOffset1() const { return isImmTy(ImmTyOffset1) && isUInt<8>(getImm()); } - bool isOffsetU12() const { return isImmTy(ImmTyOffset) && isUInt<12>(getImm()); } - bool isOffsetS13() const { return isImmTy(ImmTyOffset) && isInt<13>(getImm()); } + bool isOffsetU12() const { return (isImmTy(ImmTyOffset) || isImmTy(ImmTyInstOffset)) && isUInt<12>(getImm()); } + bool isOffsetS13() const { return (isImmTy(ImmTyOffset) || isImmTy(ImmTyInstOffset)) && isInt<13>(getImm()); } bool isGDS() const { return isImmTy(ImmTyGDS); } bool isGLC() const { return isImmTy(ImmTyGLC); } bool isSLC() const { return isImmTy(ImmTySLC); } @@ -312,6 +317,7 @@ public: bool isOpSelHi() const { return isImmTy(ImmTyOpSelHi); } bool isNegLo() const { return isImmTy(ImmTyNegLo); } bool isNegHi() const { return isImmTy(ImmTyNegHi); } + bool isHigh() const { return isImmTy(ImmTyHigh); } bool isMod() const { return isClampSI() || isOModSI(); @@ -530,6 +536,10 @@ public: return EndLoc; } + SMRange getLocRange() const { + return SMRange(StartLoc, EndLoc); + } + Modifiers getModifiers() const { assert(isRegKind() || isImmTy(ImmTyNone)); return isRegKind() ? Reg.Mods : Imm.Mods; @@ -637,6 +647,7 @@ public: case ImmTyIdxen: OS << "Idxen"; break; case ImmTyAddr64: OS << "Addr64"; break; case ImmTyOffset: OS << "Offset"; break; + case ImmTyInstOffset: OS << "InstOffset"; break; case ImmTyOffset0: OS << "Offset0"; break; case ImmTyOffset1: OS << "Offset1"; break; case ImmTyGLC: OS << "GLC"; break; @@ -673,6 +684,7 @@ public: case ImmTyNegLo: OS << "NegLo"; break; case ImmTyNegHi: OS << "NegHi"; break; case ImmTySwizzle: OS << "Swizzle"; break; + case ImmTyHigh: OS << "High"; break; } } @@ -801,9 +813,12 @@ public: }; class AMDGPUAsmParser : public MCTargetAsmParser { - const MCInstrInfo &MII; MCAsmParser &Parser; + // Number of extra operands parsed after the first optional operand. + // This may be necessary to skip hardcoded mandatory operands. + static const unsigned MAX_OPR_LOOKAHEAD = 1; + unsigned ForcedEncodingSize = 0; bool ForcedDPP = false; bool ForcedSDWA = false; @@ -822,11 +837,15 @@ private: bool ParseDirectiveMajorMinor(uint32_t &Major, uint32_t &Minor); bool ParseDirectiveHSACodeObjectVersion(); bool ParseDirectiveHSACodeObjectISA(); - bool ParseDirectiveCodeObjectMetadata(); bool ParseAMDKernelCodeTValue(StringRef ID, amd_kernel_code_t &Header); bool ParseDirectiveAMDKernelCodeT(); bool subtargetHasRegister(const MCRegisterInfo &MRI, unsigned RegNo) const; bool ParseDirectiveAMDGPUHsaKernel(); + + bool ParseDirectiveISAVersion(); + bool ParseDirectiveHSAMetadata(); + bool ParseDirectivePALMetadata(); + bool AddNextRegisterToList(unsigned& Reg, unsigned& RegWidth, RegisterKind RegKind, unsigned Reg1, unsigned RegNum); @@ -843,12 +862,12 @@ public: Match_PreferE32 = FIRST_TARGET_MATCH_RESULT_TY }; - typedef std::map<AMDGPUOperand::ImmTy, unsigned> OptionalImmIndexMap; + using OptionalImmIndexMap = std::map<AMDGPUOperand::ImmTy, unsigned>; AMDGPUAsmParser(const MCSubtargetInfo &STI, MCAsmParser &_Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) - : MCTargetAsmParser(Options, STI), MII(MII), Parser(_Parser) { + : MCTargetAsmParser(Options, STI, MII), Parser(_Parser) { MCAsmParserExtension::Initialize(Parser); if (getFeatureBits().none()) { @@ -905,6 +924,10 @@ public: return !isVI(); } + bool hasIntClamp() const { + return getFeatureBits()[AMDGPU::FeatureIntClamp]; + } + AMDGPUTargetStreamer &getTargetStreamer() { MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); return static_cast<AMDGPUTargetStreamer &>(TS); @@ -991,8 +1014,9 @@ public: private: struct OperandInfoTy { int64_t Id; - bool IsSymbolic; - OperandInfoTy(int64_t Id_) : Id(Id_), IsSymbolic(false) { } + bool IsSymbolic = false; + + OperandInfoTy(int64_t Id_) : Id(Id_) {} }; bool parseSendMsgConstruct(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId); @@ -1004,6 +1028,7 @@ private: bool validateInstruction(const MCInst &Inst, const SMLoc &IDLoc); bool validateConstantBusLimitations(const MCInst &Inst); bool validateEarlyClobberLimitations(const MCInst &Inst); + bool validateIntClampSupported(const MCInst &Inst); bool usesConstantBus(const MCInst &Inst, unsigned OpIdx); bool isInlineConstant(const MCInst &Inst, unsigned OpIdx) const; unsigned findImplicitSGPRReadInVOP(const MCInst &Inst) const; @@ -1016,6 +1041,7 @@ private: public: OperandMatchResultTy parseOptionalOperand(OperandVector &Operands); + OperandMatchResultTy parseOptionalOpr(OperandVector &Operands); OperandMatchResultTy parseExpTgt(OperandVector &Operands); OperandMatchResultTy parseSendMsgOp(OperandVector &Operands); @@ -1060,9 +1086,12 @@ public: void cvtVOP3(MCInst &Inst, const OperandVector &Operands, OptionalImmIndexMap &OptionalIdx); + void cvtVOP3OpSel(MCInst &Inst, const OperandVector &Operands); void cvtVOP3(MCInst &Inst, const OperandVector &Operands); void cvtVOP3P(MCInst &Inst, const OperandVector &Operands); + void cvtVOP3Interp(MCInst &Inst, const OperandVector &Operands); + void cvtMIMG(MCInst &Inst, const OperandVector &Operands, bool IsAtomic = false); void cvtMIMGAtomic(MCInst &Inst, const OperandVector &Operands); @@ -1279,7 +1308,6 @@ uint64_t AMDGPUOperand::applyInputFPModifiers(uint64_t Val, unsigned Size) const } void AMDGPUOperand::addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers) const { - if (AMDGPU::isSISrcOperand(AsmParser->getMII()->get(Inst.getOpcode()), Inst.getNumOperands())) { addLiteralImmOperand(Inst, Imm.Val, @@ -1311,7 +1339,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo case AMDGPU::OPERAND_REG_IMM_INT64: case AMDGPU::OPERAND_REG_IMM_FP64: case AMDGPU::OPERAND_REG_INLINE_C_INT64: - case AMDGPU::OPERAND_REG_INLINE_C_FP64: { + case AMDGPU::OPERAND_REG_INLINE_C_FP64: if (AMDGPU::isInlinableLiteral64(Literal.getZExtValue(), AsmParser->hasInv2PiInlineImm())) { Inst.addOperand(MCOperand::createImm(Literal.getZExtValue())); @@ -1335,7 +1363,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo // unclear how we should encode them. This case should be checked earlier // in predicate methods (isLiteralImm()) llvm_unreachable("fp literal in 64-bit integer instruction."); - } + case AMDGPU::OPERAND_REG_IMM_INT32: case AMDGPU::OPERAND_REG_IMM_FP32: case AMDGPU::OPERAND_REG_INLINE_C_INT32: @@ -1377,7 +1405,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo case AMDGPU::OPERAND_REG_IMM_INT32: case AMDGPU::OPERAND_REG_IMM_FP32: case AMDGPU::OPERAND_REG_INLINE_C_INT32: - case AMDGPU::OPERAND_REG_INLINE_C_FP32: { + case AMDGPU::OPERAND_REG_INLINE_C_FP32: if (isInt<32>(Val) && AMDGPU::isInlinableLiteral32(static_cast<int32_t>(Val), AsmParser->hasInv2PiInlineImm())) { @@ -1387,11 +1415,11 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo Inst.addOperand(MCOperand::createImm(Val & 0xffffffff)); return; - } + case AMDGPU::OPERAND_REG_IMM_INT64: case AMDGPU::OPERAND_REG_IMM_FP64: case AMDGPU::OPERAND_REG_INLINE_C_INT64: - case AMDGPU::OPERAND_REG_INLINE_C_FP64: { + case AMDGPU::OPERAND_REG_INLINE_C_FP64: if (AMDGPU::isInlinableLiteral64(Val, AsmParser->hasInv2PiInlineImm())) { Inst.addOperand(MCOperand::createImm(Val)); return; @@ -1399,11 +1427,11 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo Inst.addOperand(MCOperand::createImm(Lo_32(Val))); return; - } + case AMDGPU::OPERAND_REG_IMM_INT16: case AMDGPU::OPERAND_REG_IMM_FP16: case AMDGPU::OPERAND_REG_INLINE_C_INT16: - case AMDGPU::OPERAND_REG_INLINE_C_FP16: { + case AMDGPU::OPERAND_REG_INLINE_C_FP16: if (isInt<16>(Val) && AMDGPU::isInlinableLiteral16(static_cast<int16_t>(Val), AsmParser->hasInv2PiInlineImm())) { @@ -1413,7 +1441,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo Inst.addOperand(MCOperand::createImm(Val & 0xffff)); return; - } + case AMDGPU::OPERAND_REG_INLINE_C_V2INT16: case AMDGPU::OPERAND_REG_INLINE_C_V2FP16: { auto LiteralVal = static_cast<uint16_t>(Literal.getLoBits(16).getZExtValue()); @@ -1472,6 +1500,8 @@ static int getRegClass(RegisterKind Is, unsigned RegWidth) { case 1: return AMDGPU::TTMP_32RegClassID; case 2: return AMDGPU::TTMP_64RegClassID; case 4: return AMDGPU::TTMP_128RegClassID; + case 8: return AMDGPU::TTMP_256RegClassID; + case 16: return AMDGPU::TTMP_512RegClassID; } } else if (Is == IS_SGPR) { switch (RegWidth) { @@ -1479,8 +1509,8 @@ static int getRegClass(RegisterKind Is, unsigned RegWidth) { case 1: return AMDGPU::SGPR_32RegClassID; case 2: return AMDGPU::SGPR_64RegClassID; case 4: return AMDGPU::SGPR_128RegClassID; - case 8: return AMDGPU::SReg_256RegClassID; - case 16: return AMDGPU::SReg_512RegClassID; + case 8: return AMDGPU::SGPR_256RegClassID; + case 16: return AMDGPU::SGPR_512RegClassID; } } return -1; @@ -1711,7 +1741,6 @@ AMDGPUAsmParser::parseAbsoluteExpr(int64_t &Val, bool AbsMod) { if (AbsMod && getLexer().peekTok().is(AsmToken::Pipe) && (getLexer().getKind() == AsmToken::Integer || getLexer().getKind() == AsmToken::Real)) { - // This is a workaround for handling operands like these: // |1.0| // |-1| @@ -1736,6 +1765,11 @@ AMDGPUAsmParser::parseImm(OperandVector &Operands, bool AbsMod) { // TODO: add syntactic sugar for 1/(2*PI) bool Minus = false; if (getLexer().getKind() == AsmToken::Minus) { + const AsmToken NextToken = getLexer().peekTok(); + if (!NextToken.is(AsmToken::Integer) && + !NextToken.is(AsmToken::Real)) { + return MatchOperand_NoMatch; + } Minus = true; Parser.Lex(); } @@ -1765,7 +1799,7 @@ AMDGPUAsmParser::parseImm(OperandVector &Operands, bool AbsMod) { return MatchOperand_Success; } default: - return Minus ? MatchOperand_ParseFail : MatchOperand_NoMatch; + return MatchOperand_NoMatch; } } @@ -2111,7 +2145,6 @@ bool AMDGPUAsmParser::validateConstantBusLimitations(const MCInst &Inst) { SIInstrFlags::VOP1 | SIInstrFlags::VOP2 | SIInstrFlags::VOP3 | SIInstrFlags::VOP3P | SIInstrFlags::SDWA)) { - // Check special imm operands (used by madmk, etc) if (AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::imm) != -1) { ++ConstantBusUseCount; @@ -2156,7 +2189,6 @@ bool AMDGPUAsmParser::validateConstantBusLimitations(const MCInst &Inst) { } bool AMDGPUAsmParser::validateEarlyClobberLimitations(const MCInst &Inst) { - const unsigned Opcode = Inst.getOpcode(); const MCInstrDesc &Desc = MII.get(Opcode); @@ -2193,6 +2225,20 @@ bool AMDGPUAsmParser::validateEarlyClobberLimitations(const MCInst &Inst) { return true; } +bool AMDGPUAsmParser::validateIntClampSupported(const MCInst &Inst) { + + const unsigned Opc = Inst.getOpcode(); + const MCInstrDesc &Desc = MII.get(Opc); + + if ((Desc.TSFlags & SIInstrFlags::IntClamp) != 0 && !hasIntClamp()) { + int ClampIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::clamp); + assert(ClampIdx != -1); + return Inst.getOperand(ClampIdx).getImm() == 0; + } + + return true; +} + bool AMDGPUAsmParser::validateInstruction(const MCInst &Inst, const SMLoc &IDLoc) { if (!validateConstantBusLimitations(Inst)) { @@ -2205,10 +2251,18 @@ bool AMDGPUAsmParser::validateInstruction(const MCInst &Inst, "destination must be different than all sources"); return false; } + if (!validateIntClampSupported(Inst)) { + Error(IDLoc, + "integer clamping is not supported on this GPU"); + return false; + } return true; } +static std::string AMDGPUMnemonicSpellCheck(StringRef S, uint64_t FBS, + unsigned VariantID = 0); + bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -2251,8 +2305,13 @@ bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_MissingFeature: return Error(IDLoc, "instruction not supported on this GPU"); - case Match_MnemonicFail: - return Error(IDLoc, "unrecognized instruction mnemonic"); + case Match_MnemonicFail: { + uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); + std::string Suggestion = AMDGPUMnemonicSpellCheck( + ((AMDGPUOperand &)*Operands[0]).getToken(), FBS); + return Error(IDLoc, "invalid instruction" + Suggestion, + ((AMDGPUOperand &)*Operands[0]).getLocRange()); + } case Match_InvalidOperand: { SMLoc ErrorLoc = IDLoc; @@ -2365,49 +2424,6 @@ bool AMDGPUAsmParser::ParseDirectiveHSACodeObjectISA() { return false; } -bool AMDGPUAsmParser::ParseDirectiveCodeObjectMetadata() { - std::string YamlString; - raw_string_ostream YamlStream(YamlString); - - getLexer().setSkipSpace(false); - - bool FoundEnd = false; - while (!getLexer().is(AsmToken::Eof)) { - while (getLexer().is(AsmToken::Space)) { - YamlStream << getLexer().getTok().getString(); - Lex(); - } - - if (getLexer().is(AsmToken::Identifier)) { - StringRef ID = getLexer().getTok().getIdentifier(); - if (ID == AMDGPU::CodeObject::MetadataAssemblerDirectiveEnd) { - Lex(); - FoundEnd = true; - break; - } - } - - YamlStream << Parser.parseStringToEndOfStatement() - << getContext().getAsmInfo()->getSeparatorString(); - - Parser.eatToEndOfStatement(); - } - - getLexer().setSkipSpace(true); - - if (getLexer().is(AsmToken::Eof) && !FoundEnd) { - return TokError( - "expected directive .end_amdgpu_code_object_metadata not found"); - } - - YamlStream.flush(); - - if (!getTargetStreamer().EmitCodeObjectMetadata(YamlString)) - return Error(getParser().getTok().getLoc(), "invalid code object metadata"); - - return false; -} - bool AMDGPUAsmParser::ParseAMDKernelCodeTValue(StringRef ID, amd_kernel_code_t &Header) { SmallString<40> ErrStr; @@ -2460,6 +2476,103 @@ bool AMDGPUAsmParser::ParseDirectiveAMDGPUHsaKernel() { return false; } +bool AMDGPUAsmParser::ParseDirectiveISAVersion() { + if (getSTI().getTargetTriple().getArch() != Triple::amdgcn) { + return Error(getParser().getTok().getLoc(), + ".amd_amdgpu_isa directive is not available on non-amdgcn " + "architectures"); + } + + auto ISAVersionStringFromASM = getLexer().getTok().getStringContents(); + + std::string ISAVersionStringFromSTI; + raw_string_ostream ISAVersionStreamFromSTI(ISAVersionStringFromSTI); + IsaInfo::streamIsaVersion(&getSTI(), ISAVersionStreamFromSTI); + + if (ISAVersionStringFromASM != ISAVersionStreamFromSTI.str()) { + return Error(getParser().getTok().getLoc(), + ".amd_amdgpu_isa directive does not match triple and/or mcpu " + "arguments specified through the command line"); + } + + getTargetStreamer().EmitISAVersion(ISAVersionStreamFromSTI.str()); + Lex(); + + return false; +} + +bool AMDGPUAsmParser::ParseDirectiveHSAMetadata() { + if (getSTI().getTargetTriple().getOS() != Triple::AMDHSA) { + return Error(getParser().getTok().getLoc(), + (Twine(HSAMD::AssemblerDirectiveBegin) + Twine(" directive is " + "not available on non-amdhsa OSes")).str()); + } + + std::string HSAMetadataString; + raw_string_ostream YamlStream(HSAMetadataString); + + getLexer().setSkipSpace(false); + + bool FoundEnd = false; + while (!getLexer().is(AsmToken::Eof)) { + while (getLexer().is(AsmToken::Space)) { + YamlStream << getLexer().getTok().getString(); + Lex(); + } + + if (getLexer().is(AsmToken::Identifier)) { + StringRef ID = getLexer().getTok().getIdentifier(); + if (ID == AMDGPU::HSAMD::AssemblerDirectiveEnd) { + Lex(); + FoundEnd = true; + break; + } + } + + YamlStream << Parser.parseStringToEndOfStatement() + << getContext().getAsmInfo()->getSeparatorString(); + + Parser.eatToEndOfStatement(); + } + + getLexer().setSkipSpace(true); + + if (getLexer().is(AsmToken::Eof) && !FoundEnd) { + return TokError(Twine("expected directive ") + + Twine(HSAMD::AssemblerDirectiveEnd) + Twine(" not found")); + } + + YamlStream.flush(); + + if (!getTargetStreamer().EmitHSAMetadata(HSAMetadataString)) + return Error(getParser().getTok().getLoc(), "invalid HSA metadata"); + + return false; +} + +bool AMDGPUAsmParser::ParseDirectivePALMetadata() { + if (getSTI().getTargetTriple().getOS() != Triple::AMDPAL) { + return Error(getParser().getTok().getLoc(), + (Twine(PALMD::AssemblerDirective) + Twine(" directive is " + "not available on non-amdpal OSes")).str()); + } + + PALMD::Metadata PALMetadata; + for (;;) { + uint32_t Value; + if (ParseAsAbsoluteExpression(Value)) { + return TokError(Twine("invalid value in ") + + Twine(PALMD::AssemblerDirective)); + } + PALMetadata.push_back(Value); + if (getLexer().isNot(AsmToken::Comma)) + break; + Lex(); + } + getTargetStreamer().EmitPALMetadata(PALMetadata); + return false; +} + bool AMDGPUAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); @@ -2469,20 +2582,45 @@ bool AMDGPUAsmParser::ParseDirective(AsmToken DirectiveID) { if (IDVal == ".hsa_code_object_isa") return ParseDirectiveHSACodeObjectISA(); - if (IDVal == AMDGPU::CodeObject::MetadataAssemblerDirectiveBegin) - return ParseDirectiveCodeObjectMetadata(); - if (IDVal == ".amd_kernel_code_t") return ParseDirectiveAMDKernelCodeT(); if (IDVal == ".amdgpu_hsa_kernel") return ParseDirectiveAMDGPUHsaKernel(); + if (IDVal == ".amd_amdgpu_isa") + return ParseDirectiveISAVersion(); + + if (IDVal == AMDGPU::HSAMD::AssemblerDirectiveBegin) + return ParseDirectiveHSAMetadata(); + + if (IDVal == PALMD::AssemblerDirective) + return ParseDirectivePALMetadata(); + return true; } bool AMDGPUAsmParser::subtargetHasRegister(const MCRegisterInfo &MRI, unsigned RegNo) const { + + for (MCRegAliasIterator R(AMDGPU::TTMP12_TTMP13_TTMP14_TTMP15, &MRI, true); + R.isValid(); ++R) { + if (*R == RegNo) + return isGFX9(); + } + + switch (RegNo) { + case AMDGPU::TBA: + case AMDGPU::TBA_LO: + case AMDGPU::TBA_HI: + case AMDGPU::TMA: + case AMDGPU::TMA_LO: + case AMDGPU::TMA_HI: + return !isGFX9(); + default: + break; + } + if (isCI()) return true; @@ -2529,24 +2667,22 @@ AMDGPUAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { if (ResTy == MatchOperand_Success) return ResTy; - if (getLexer().getKind() == AsmToken::Identifier) { - // If this identifier is a symbol, we want to create an expression for it. - // It is a little difficult to distinguish between a symbol name, and - // an instruction flag like 'gds'. In order to do this, we parse - // all tokens as expressions and then treate the symbol name as the token - // string when we want to interpret the operand as a token. - const auto &Tok = Parser.getTok(); - SMLoc S = Tok.getLoc(); - const MCExpr *Expr = nullptr; - if (!Parser.parseExpression(Expr)) { - Operands.push_back(AMDGPUOperand::CreateExpr(this, Expr, S)); - return MatchOperand_Success; - } + const auto &Tok = Parser.getTok(); + SMLoc S = Tok.getLoc(); - Operands.push_back(AMDGPUOperand::CreateToken(this, Tok.getString(), Tok.getLoc())); + const MCExpr *Expr = nullptr; + if (!Parser.parseExpression(Expr)) { + Operands.push_back(AMDGPUOperand::CreateExpr(this, Expr, S)); + return MatchOperand_Success; + } + + // Possibly this is an instruction flag like 'gds'. + if (Tok.getKind() == AsmToken::Identifier) { + Operands.push_back(AMDGPUOperand::CreateToken(this, Tok.getString(), S)); Parser.Lex(); return MatchOperand_Success; } + return MatchOperand_NoMatch; } @@ -2688,7 +2824,7 @@ OperandMatchResultTy AMDGPUAsmParser::parseOperandArrayWithPrefix( // FIXME: How to verify the number of elements matches the number of src // operands? - for (int I = 0; I < 3; ++I) { + for (int I = 0; I < 4; ++I) { if (I != 0) { if (getLexer().is(AsmToken::RBrac)) break; @@ -3726,7 +3862,9 @@ AMDGPUAsmParser::parseSwizzleOp(OperandVector &Operands) { return Ok? MatchOperand_Success : MatchOperand_ParseFail; } else { - return MatchOperand_NoMatch; + // Swizzle "offset" operand is optional. + // If it is omitted, try parsing other optional operands. + return parseOptionalOpr(Operands); } } @@ -4016,11 +4154,13 @@ static const OptionalOperand AMDGPUOptionalOperandTable[] = { {"offset1", AMDGPUOperand::ImmTyOffset1, false, nullptr}, {"gds", AMDGPUOperand::ImmTyGDS, true, nullptr}, {"offset", AMDGPUOperand::ImmTyOffset, false, nullptr}, + {"inst_offset", AMDGPUOperand::ImmTyInstOffset, false, nullptr}, {"dfmt", AMDGPUOperand::ImmTyDFMT, false, nullptr}, {"nfmt", AMDGPUOperand::ImmTyNFMT, false, nullptr}, {"glc", AMDGPUOperand::ImmTyGLC, true, nullptr}, {"slc", AMDGPUOperand::ImmTySLC, true, nullptr}, {"tfe", AMDGPUOperand::ImmTyTFE, true, nullptr}, + {"high", AMDGPUOperand::ImmTyHigh, true, nullptr}, {"clamp", AMDGPUOperand::ImmTyClampSI, true, nullptr}, {"omod", AMDGPUOperand::ImmTyOModSI, false, ConvertOmodMul}, {"unorm", AMDGPUOperand::ImmTyUNorm, true, nullptr}, @@ -4044,6 +4184,39 @@ static const OptionalOperand AMDGPUOptionalOperandTable[] = { }; OperandMatchResultTy AMDGPUAsmParser::parseOptionalOperand(OperandVector &Operands) { + unsigned size = Operands.size(); + assert(size > 0); + + OperandMatchResultTy res = parseOptionalOpr(Operands); + + // This is a hack to enable hardcoded mandatory operands which follow + // optional operands. + // + // Current design assumes that all operands after the first optional operand + // are also optional. However implementation of some instructions violates + // this rule (see e.g. flat/global atomic which have hardcoded 'glc' operands). + // + // To alleviate this problem, we have to (implicitly) parse extra operands + // to make sure autogenerated parser of custom operands never hit hardcoded + // mandatory operands. + + if (size == 1 || ((AMDGPUOperand &)*Operands[size - 1]).isRegKind()) { + + // We have parsed the first optional operand. + // Parse as many operands as necessary to skip all mandatory operands. + + for (unsigned i = 0; i < MAX_OPR_LOOKAHEAD; ++i) { + if (res != MatchOperand_Success || + getLexer().is(AsmToken::EndOfStatement)) break; + if (getLexer().is(AsmToken::Comma)) Parser.Lex(); + res = parseOptionalOpr(Operands); + } + } + + return res; +} + +OperandMatchResultTy AMDGPUAsmParser::parseOptionalOpr(OperandVector &Operands) { OperandMatchResultTy res; for (const OptionalOperand &Op : AMDGPUOptionalOperandTable) { // try to parse any optional operand here @@ -4088,6 +4261,30 @@ OperandMatchResultTy AMDGPUAsmParser::parseOModOperand(OperandVector &Operands) return MatchOperand_NoMatch; } +void AMDGPUAsmParser::cvtVOP3OpSel(MCInst &Inst, const OperandVector &Operands) { + cvtVOP3P(Inst, Operands); + + int Opc = Inst.getOpcode(); + + int SrcNum; + const int Ops[] = { AMDGPU::OpName::src0, + AMDGPU::OpName::src1, + AMDGPU::OpName::src2 }; + for (SrcNum = 0; + SrcNum < 3 && AMDGPU::getNamedOperandIdx(Opc, Ops[SrcNum]) != -1; + ++SrcNum); + assert(SrcNum > 0); + + int OpSelIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::op_sel); + unsigned OpSel = Inst.getOperand(OpSelIdx).getImm(); + + if ((OpSel & (1 << SrcNum)) != 0) { + int ModIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0_modifiers); + uint32_t ModVal = Inst.getOperand(ModIdx).getImm(); + Inst.getOperand(ModIdx).setImm(ModVal | SISrcMods::DST_OP_SEL); + } +} + static bool isRegOrImmWithInputMods(const MCInstrDesc &Desc, unsigned OpNum) { // 1. This operand is input modifiers return Desc.OpInfo[OpNum].OperandType == AMDGPU::OPERAND_INPUT_MODS @@ -4099,6 +4296,45 @@ static bool isRegOrImmWithInputMods(const MCInstrDesc &Desc, unsigned OpNum) { && Desc.getOperandConstraint(OpNum + 1, MCOI::OperandConstraint::TIED_TO) == -1; } +void AMDGPUAsmParser::cvtVOP3Interp(MCInst &Inst, const OperandVector &Operands) +{ + OptionalImmIndexMap OptionalIdx; + unsigned Opc = Inst.getOpcode(); + + unsigned I = 1; + const MCInstrDesc &Desc = MII.get(Inst.getOpcode()); + for (unsigned J = 0; J < Desc.getNumDefs(); ++J) { + ((AMDGPUOperand &)*Operands[I++]).addRegOperands(Inst, 1); + } + + for (unsigned E = Operands.size(); I != E; ++I) { + AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[I]); + if (isRegOrImmWithInputMods(Desc, Inst.getNumOperands())) { + Op.addRegOrImmWithFPInputModsOperands(Inst, 2); + } else if (Op.isInterpSlot() || + Op.isInterpAttr() || + Op.isAttrChan()) { + Inst.addOperand(MCOperand::createImm(Op.Imm.Val)); + } else if (Op.isImmModifier()) { + OptionalIdx[Op.getImmTy()] = I; + } else { + llvm_unreachable("unhandled operand type"); + } + } + + if (AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::high) != -1) { + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyHigh); + } + + if (AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::clamp) != -1) { + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyClampSI); + } + + if (AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::omod) != -1) { + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyOModSI); + } +} + void AMDGPUAsmParser::cvtVOP3(MCInst &Inst, const OperandVector &Operands, OptionalImmIndexMap &OptionalIdx) { unsigned Opc = Inst.getOpcode(); @@ -4162,20 +4398,36 @@ void AMDGPUAsmParser::cvtVOP3(MCInst &Inst, const OperandVector &Operands) { cvtVOP3(Inst, Operands, OptionalIdx); } -void AMDGPUAsmParser::cvtVOP3P(MCInst &Inst, const OperandVector &Operands) { +void AMDGPUAsmParser::cvtVOP3P(MCInst &Inst, + const OperandVector &Operands) { OptionalImmIndexMap OptIdx; + const int Opc = Inst.getOpcode(); + const MCInstrDesc &Desc = MII.get(Opc); + + const bool IsPacked = (Desc.TSFlags & SIInstrFlags::IsPacked) != 0; cvtVOP3(Inst, Operands, OptIdx); + if (AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vdst_in) != -1) { + assert(!IsPacked); + Inst.addOperand(Inst.getOperand(0)); + } + // FIXME: This is messy. Parse the modifiers as if it was a normal VOP3 // instruction, and then figure out where to actually put the modifiers - int Opc = Inst.getOpcode(); addOptionalImmOperand(Inst, Operands, OptIdx, AMDGPUOperand::ImmTyOpSel); - addOptionalImmOperand(Inst, Operands, OptIdx, AMDGPUOperand::ImmTyOpSelHi, -1); + + int OpSelHiIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::op_sel_hi); + if (OpSelHiIdx != -1) { + int DefaultVal = IsPacked ? -1 : 0; + addOptionalImmOperand(Inst, Operands, OptIdx, AMDGPUOperand::ImmTyOpSelHi, + DefaultVal); + } int NegLoIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::neg_lo); if (NegLoIdx != -1) { + assert(IsPacked); addOptionalImmOperand(Inst, Operands, OptIdx, AMDGPUOperand::ImmTyNegLo); addOptionalImmOperand(Inst, Operands, OptIdx, AMDGPUOperand::ImmTyNegHi); } @@ -4188,13 +4440,16 @@ void AMDGPUAsmParser::cvtVOP3P(MCInst &Inst, const OperandVector &Operands) { AMDGPU::OpName::src2_modifiers }; int OpSelIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::op_sel); - int OpSelHiIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::op_sel_hi); unsigned OpSel = Inst.getOperand(OpSelIdx).getImm(); - unsigned OpSelHi = Inst.getOperand(OpSelHiIdx).getImm(); + unsigned OpSelHi = 0; unsigned NegLo = 0; unsigned NegHi = 0; + if (OpSelHiIdx != -1) { + OpSelHi = Inst.getOperand(OpSelHiIdx).getImm(); + } + if (NegLoIdx != -1) { int NegHiIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::neg_hi); NegLo = Inst.getOperand(NegLoIdx).getImm(); @@ -4323,7 +4578,6 @@ AMDGPUAsmParser::parseDPPCtrl(OperandVector &Operands) { if (getLexer().isNot(AsmToken::RBrac)) return MatchOperand_ParseFail; Parser.Lex(); - } else { // sel:%d Parser.Lex(); @@ -4383,6 +4637,11 @@ void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands) { ((AMDGPUOperand &)*Operands[I++]).addRegOperands(Inst, 1); } + // All DPP instructions with at least one source operand have a fake "old" + // source at the beginning that's tied to the dst operand. Handle it here. + if (Desc.getNumOperands() >= 2) + Inst.addOperand(Inst.getOperand(0)); + for (unsigned E = Operands.size(); I != E; ++I) { AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[I]); // Add the register arguments @@ -4405,16 +4664,6 @@ void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands) { addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDppRowMask, 0xf); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDppBankMask, 0xf); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDppBoundCtrl); - - // special case v_mac_{f16, f32}: - // it has src2 register operand that is tied to dst operand - if (Inst.getOpcode() == AMDGPU::V_MAC_F32_dpp || - Inst.getOpcode() == AMDGPU::V_MAC_F16_dpp) { - auto it = Inst.begin(); - std::advance( - it, AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::src2)); - Inst.insert(it, Inst.getOperand(0)); // src2 = dst - } } //===----------------------------------------------------------------------===// @@ -4503,6 +4752,7 @@ void AMDGPUAsmParser::cvtSdwaVOPC(MCInst &Inst, const OperandVector &Operands) { void AMDGPUAsmParser::cvtSDWA(MCInst &Inst, const OperandVector &Operands, uint64_t BasicInstType, bool skipVcc) { using namespace llvm::AMDGPU::SDWA; + OptionalImmIndexMap OptionalIdx; bool skippedVcc = false; @@ -4595,6 +4845,7 @@ extern "C" void LLVMInitializeAMDGPUAsmParser() { #define GET_REGISTER_MATCHER #define GET_MATCHER_IMPLEMENTATION +#define GET_MNEMONIC_SPELL_CHECKER #include "AMDGPUGenAsmMatcher.inc" // This fuction should be defined after auto-generated include so that we have |
