diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp --- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -4784,6 +4784,17 @@ return Error(IDLoc, "invalid instruction" + Suggestion); } +static bool isInvalidVOPDY(const OperandVector &Operands, + uint64_t InvalidOprIdx) { + assert(InvalidOprIdx < Operands.size()); + const auto &Op = ((AMDGPUOperand &)*Operands[InvalidOprIdx]); + if (Op.isToken() && InvalidOprIdx > 1) { + const auto &PrevOp = ((AMDGPUOperand &)*Operands[InvalidOprIdx - 1]); + return PrevOp.isToken() && PrevOp.getToken() == "::"; + } + return false; +} + bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -4844,6 +4855,9 @@ ErrorLoc = ((AMDGPUOperand &)*Operands[ErrorInfo]).getStartLoc(); if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; + + if (isInvalidVOPDY(Operands, ErrorInfo)) + return Error(ErrorLoc, "invalid VOPDY instruction"); } return Error(ErrorLoc, "invalid operand for instruction"); } @@ -8460,12 +8474,13 @@ lex(); lex(); Operands.push_back(AMDGPUOperand::CreateToken(this, "::", S)); + SMLoc OpYLoc = getLoc(); StringRef OpYName; if (isToken(AsmToken::Identifier) && !Parser.parseIdentifier(OpYName)) { - Operands.push_back(AMDGPUOperand::CreateToken(this, OpYName, S)); + Operands.push_back(AMDGPUOperand::CreateToken(this, OpYName, OpYLoc)); return MatchOperand_Success; } - Error(S, "invalid VOPD :: usage"); + Error(OpYLoc, "expected a VOPDY instruction after ::"); return MatchOperand_ParseFail; } return MatchOperand_NoMatch; diff --git a/llvm/test/MC/AMDGPU/gfx11_asm_vopd_errs.s b/llvm/test/MC/AMDGPU/gfx11_asm_vopd_err.s rename from llvm/test/MC/AMDGPU/gfx11_asm_vopd_errs.s rename to llvm/test/MC/AMDGPU/gfx11_asm_vopd_err.s --- a/llvm/test/MC/AMDGPU/gfx11_asm_vopd_errs.s +++ b/llvm/test/MC/AMDGPU/gfx11_asm_vopd_err.s @@ -267,3 +267,47 @@ // GFX11: error: src2 operands must use different VGPR banks // GFX11-NEXT:{{^}}v_dual_fmamk_f32 v6, v1, 0xaf123456, v3 :: v_dual_fmac_f32 v5, v2, v3 // GFX11-NEXT:{{^}} ^ + +//===----------------------------------------------------------------------===// +// Check invalid VOPD syntax. +//===----------------------------------------------------------------------===// + +v_dual_fmamk_f32 v6, v1, 0xaf123456, v2 : : v_dual_fmac_f32 v5, v2, v3 +// GFX11: error: unknown token in expression +// GFX11-NEXT:{{^}}v_dual_fmamk_f32 v6, v1, 0xaf123456, v2 : : v_dual_fmac_f32 v5, v2, v3 +// GFX11-NEXT:{{^}} ^ + +v_dual_fmamk_f32 v6, v1, 0xaf123456, v3 +// GFX11: error: too few operands for instruction +// GFX11-NEXT:{{^}}v_dual_fmamk_f32 v6, v1, 0xaf123456, v3 +// GFX11-NEXT:{{^}}^ + +v_dual_fmamk_f32 v6, v1, 0xaf123456, v2 :: v_dual_fmac_f32 +// GFX11: error: too few operands for instruction +// GFX11-NEXT:{{^}}v_dual_fmamk_f32 v6, v1, 0xaf123456, v2 :: v_dual_fmac_f32 +// GFX11-NEXT:{{^}}^ + +v_dual_add_f32 v255, v4 :: v_add_f32 v6, v1, v3 +// GFX11: error: invalid operand for instruction +// GFX11-NEXT:{{^}}v_dual_add_f32 v255, v4 :: v_add_f32 v6, v1, v3 +// GFX11-NEXT:{{^}} ^ + +v_dual_fmamk_f32 v6, v1, 0xaf123456, v3 :: +// GFX11: error: expected a VOPDY instruction after :: +// GFX11-NEXT:{{^}}v_dual_fmamk_f32 v6, v1, 0xaf123456, v3 :: +// GFX11-NEXT:{{^}} ^ + +v_add_f32 v6, v1, v3 :: +// GFX11: error: expected a VOPDY instruction after :: +// GFX11-NEXT:{{^}}v_add_f32 v6, v1, v3 :: +// GFX11-NEXT:{{^}} ^ + +v_dual_add_f32 v255:: +// GFX11: error: expected a VOPDY instruction after :: +// GFX11-NEXT:{{^}}v_dual_add_f32 v255:: +// GFX11-NEXT:{{^}} ^ + +v_dual_add_f32 v255, v4, v2 :: v_add_f32 v6, v1, v3 +// GFX11: error: invalid VOPDY instruction +// GFX11-NEXT:{{^}}v_dual_add_f32 v255, v4, v2 :: v_add_f32 v6, v1, v3 +// GFX11-NEXT:{{^}} ^