struct OperandInfoTy {
int64_t Id;
bool IsSymbolic = false;
+ bool IsDefined = false;
OperandInfoTy(int64_t Id_) : Id(Id_) {}
};
- bool parseSendMsgConstruct(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId);
+ bool parseSendMsgBody(OperandInfoTy &Msg, OperandInfoTy &Op, OperandInfoTy &Stream);
+ void validateSendMsg(const OperandInfoTy &Msg,
+ const OperandInfoTy &Op,
+ const OperandInfoTy &Stream,
+ const SMLoc Loc);
+
bool parseHwregBody(OperandInfoTy &HwReg, int64_t &Offset, int64_t &Width);
void validateHwreg(const OperandInfoTy &HwReg,
const int64_t Offset,
// sendmsg
//===----------------------------------------------------------------------===//
-bool AMDGPUAsmParser::parseSendMsgConstruct(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId) {
+bool
+AMDGPUAsmParser::parseSendMsgBody(OperandInfoTy &Msg,
+ OperandInfoTy &Op,
+ OperandInfoTy &Stream) {
using namespace llvm::AMDGPU::SendMsg;
- if (Parser.getTok().getString() != "sendmsg")
- return true;
- Parser.Lex();
+ if (isToken(AsmToken::Identifier) && (Msg.Id = getMsgId(getTokenStr())) >= 0) {
+ Msg.IsSymbolic = true;
+ lex(); // skip message name
+ } else if (!parseExpr(Msg.Id)) {
+ return false;
+ }
- if (getLexer().isNot(AsmToken::LParen))
- return true;
- Parser.Lex();
+ if (trySkipToken(AsmToken::Comma)) {
+ Op.IsDefined = true;
+ if (isToken(AsmToken::Identifier) &&
+ (Op.Id = getMsgOpId(Msg.Id, getTokenStr())) >= 0) {
+ lex(); // skip operation name
+ } else if (!parseExpr(Op.Id)) {
+ return false;
+ }
- if (getLexer().is(AsmToken::Identifier)) {
- Msg.IsSymbolic = true;
- Msg.Id = ID_UNKNOWN_;
- const std::string tok = Parser.getTok().getString();
- for (int i = ID_GAPS_FIRST_; i < ID_GAPS_LAST_; ++i) {
- switch(i) {
- default: continue; // Omit gaps.
- case ID_GS_ALLOC_REQ:
- if (isSI() || isCI() || isVI())
- continue;
- break;
- case ID_INTERRUPT: case ID_GS: case ID_GS_DONE:
- case ID_SYSMSG: break;
- }
- if (tok == IdSymbolic[i]) {
- Msg.Id = i;
- break;
- }
+ if (trySkipToken(AsmToken::Comma)) {
+ Stream.IsDefined = true;
+ if (!parseExpr(Stream.Id))
+ return false;
}
- Parser.Lex();
- } else {
- Msg.IsSymbolic = false;
- if (getLexer().isNot(AsmToken::Integer))
- return true;
- if (getParser().parseAbsoluteExpression(Msg.Id))
- return true;
- if (getLexer().is(AsmToken::Integer))
- if (getParser().parseAbsoluteExpression(Msg.Id))
- Msg.Id = ID_UNKNOWN_;
}
- if (Msg.Id == ID_UNKNOWN_) // Don't know how to parse the rest.
- return false;
- if (!(Msg.Id == ID_GS || Msg.Id == ID_GS_DONE || Msg.Id == ID_SYSMSG)) {
- if (getLexer().isNot(AsmToken::RParen))
- return true;
- Parser.Lex();
- return false;
- }
+ return skipToken(AsmToken::RParen, "expected a closing parenthesis");
+}
- if (getLexer().isNot(AsmToken::Comma))
- return true;
- Parser.Lex();
+void
+AMDGPUAsmParser::validateSendMsg(const OperandInfoTy &Msg,
+ const OperandInfoTy &Op,
+ const OperandInfoTy &Stream,
+ const SMLoc S) {
+ using namespace llvm::AMDGPU::SendMsg;
- assert(Msg.Id == ID_GS || Msg.Id == ID_GS_DONE || Msg.Id == ID_SYSMSG);
- Operation.Id = ID_UNKNOWN_;
- if (getLexer().is(AsmToken::Identifier)) {
- Operation.IsSymbolic = true;
- const char* const *S = (Msg.Id == ID_SYSMSG) ? OpSysSymbolic : OpGsSymbolic;
- const int F = (Msg.Id == ID_SYSMSG) ? OP_SYS_FIRST_ : OP_GS_FIRST_;
- const int L = (Msg.Id == ID_SYSMSG) ? OP_SYS_LAST_ : OP_GS_LAST_;
- const StringRef Tok = Parser.getTok().getString();
- for (int i = F; i < L; ++i) {
- if (Tok == S[i]) {
- Operation.Id = i;
- break;
- }
- }
- Parser.Lex();
- } else {
- Operation.IsSymbolic = false;
- if (getLexer().isNot(AsmToken::Integer))
- return true;
- if (getParser().parseAbsoluteExpression(Operation.Id))
- return true;
+ // Validation strictness depends on whether message is specified
+ // in a symbolc or in a numeric form. In the latter case
+ // only encoding possibility is checked.
+ bool Strict = Msg.IsSymbolic;
+
+ if (!isValidMsgId(Msg.Id, getSTI(), Strict)) {
+ Error(S, "invalid message id");
+ } else if (Strict && (msgRequiresOp(Msg.Id) != Op.IsDefined)) {
+ Error(S, Op.IsDefined ?
+ "message does not support operations" :
+ "missing message operation");
+ } else if (!isValidMsgOp(Msg.Id, Op.Id, Strict)) {
+ Error(S, "invalid operation id");
+ } else if (Strict && !msgSupportsStream(Msg.Id, Op.Id) && Stream.IsDefined) {
+ Error(S, "message operation does not support streams");
+ } else if (!isValidMsgStream(Msg.Id, Op.Id, Stream.Id, Strict)) {
+ Error(S, "invalid message stream id");
}
+}
- if ((Msg.Id == ID_GS || Msg.Id == ID_GS_DONE) && Operation.Id != OP_GS_NOP) {
- // Stream id is optional.
- if (getLexer().is(AsmToken::RParen)) {
- Parser.Lex();
- return false;
- }
+OperandMatchResultTy
+AMDGPUAsmParser::parseSendMsgOp(OperandVector &Operands) {
+ using namespace llvm::AMDGPU::SendMsg;
- if (getLexer().isNot(AsmToken::Comma))
- return true;
- Parser.Lex();
+ int64_t ImmVal = 0;
+ SMLoc Loc = getLoc();
- if (getLexer().isNot(AsmToken::Integer))
- return true;
- if (getParser().parseAbsoluteExpression(StreamId))
- return true;
+ // 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);
+ ImmVal = encodeMsg(Msg.Id, Op.Id, Stream.Id);
+ }
+ } else if (parseExpr(ImmVal)) {
+ if (ImmVal < 0 || !isUInt<16>(ImmVal))
+ Error(Loc, "invalid immediate: only 16-bit values are legal");
}
- if (getLexer().isNot(AsmToken::RParen))
- return true;
- Parser.Lex();
- return false;
+ Operands.push_back(AMDGPUOperand::CreateImm(this, ImmVal, Loc, AMDGPUOperand::ImmTySendMsg));
+ return MatchOperand_Success;
}
+bool AMDGPUOperand::isSendMsg() const {
+ return isImmTy(ImmTySendMsg);
+}
+
+//===----------------------------------------------------------------------===//
+// v_interp
+//===----------------------------------------------------------------------===//
+
OperandMatchResultTy AMDGPUAsmParser::parseInterpSlot(OperandVector &Operands) {
if (getLexer().getKind() != AsmToken::Identifier)
return MatchOperand_NoMatch;
return MatchOperand_Success;
}
+//===----------------------------------------------------------------------===//
+// exp
+//===----------------------------------------------------------------------===//
+
void AMDGPUAsmParser::errorExpTgt() {
Error(Parser.getTok().getLoc(), "invalid exp target");
}
return MatchOperand_Success;
}
-OperandMatchResultTy
-AMDGPUAsmParser::parseSendMsgOp(OperandVector &Operands) {
- using namespace llvm::AMDGPU::SendMsg;
-
- int64_t Imm16Val = 0;
- SMLoc S = Parser.getTok().getLoc();
-
- switch(getLexer().getKind()) {
- default:
- return MatchOperand_NoMatch;
- case AsmToken::Integer:
- // The operand can be an integer value.
- if (getParser().parseAbsoluteExpression(Imm16Val))
- return MatchOperand_NoMatch;
- if (Imm16Val < 0 || !isUInt<16>(Imm16Val)) {
- Error(S, "invalid immediate: only 16-bit values are legal");
- // Do not return error code, but create an imm operand anyway and proceed
- // to the next operand, if any. That avoids unneccessary error messages.
- }
- break;
- case AsmToken::Identifier: {
- OperandInfoTy Msg(ID_UNKNOWN_);
- OperandInfoTy Operation(OP_UNKNOWN_);
- int64_t StreamId = STREAM_ID_DEFAULT_;
- if (parseSendMsgConstruct(Msg, Operation, StreamId))
- return MatchOperand_ParseFail;
- do {
- // Validate and encode message ID.
- if (! ((ID_INTERRUPT <= Msg.Id && Msg.Id <= ID_GS_DONE)
- || (Msg.Id == ID_GS_ALLOC_REQ && !isSI() && !isCI() && !isVI())
- || Msg.Id == ID_SYSMSG)) {
- if (Msg.IsSymbolic)
- Error(S, "invalid/unsupported symbolic name of message");
- else
- Error(S, "invalid/unsupported code of message");
- break;
- }
- Imm16Val = (Msg.Id << ID_SHIFT_);
- // Validate and encode operation ID.
- if (Msg.Id == ID_GS || Msg.Id == ID_GS_DONE) {
- if (! (OP_GS_FIRST_ <= Operation.Id && Operation.Id < OP_GS_LAST_)) {
- if (Operation.IsSymbolic)
- Error(S, "invalid symbolic name of GS_OP");
- else
- Error(S, "invalid code of GS_OP: only 2-bit values are legal");
- break;
- }
- if (Operation.Id == OP_GS_NOP
- && Msg.Id != ID_GS_DONE) {
- Error(S, "invalid GS_OP: NOP is for GS_DONE only");
- break;
- }
- Imm16Val |= (Operation.Id << OP_SHIFT_);
- }
- if (Msg.Id == ID_SYSMSG) {
- if (! (OP_SYS_FIRST_ <= Operation.Id && Operation.Id < OP_SYS_LAST_)) {
- if (Operation.IsSymbolic)
- Error(S, "invalid/unsupported symbolic name of SYSMSG_OP");
- else
- Error(S, "invalid/unsupported code of SYSMSG_OP");
- break;
- }
- Imm16Val |= (Operation.Id << OP_SHIFT_);
- }
- // Validate and encode stream ID.
- if ((Msg.Id == ID_GS || Msg.Id == ID_GS_DONE) && Operation.Id != OP_GS_NOP) {
- if (! (STREAM_ID_FIRST_ <= StreamId && StreamId < STREAM_ID_LAST_)) {
- Error(S, "invalid stream id: only 2-bit values are legal");
- break;
- }
- Imm16Val |= (StreamId << STREAM_ID_SHIFT_);
- }
- } while (false);
- }
- break;
- }
- Operands.push_back(AMDGPUOperand::CreateImm(this, Imm16Val, S, AMDGPUOperand::ImmTySendMsg));
- return MatchOperand_Success;
-}
-
-bool AMDGPUOperand::isSendMsg() const {
- return isImmTy(ImmTySendMsg);
-}
-
//===----------------------------------------------------------------------===//
// parser helpers
//===----------------------------------------------------------------------===//
raw_ostream &O) {
using namespace llvm::AMDGPU::SendMsg;
- const unsigned SImm16 = MI->getOperand(OpNo).getImm();
- const unsigned Id = SImm16 & ID_MASK_;
- do {
- if (Id == ID_INTERRUPT ||
- (Id == ID_GS_ALLOC_REQ && !AMDGPU::isSI(STI) && !AMDGPU::isCI(STI) &&
- !AMDGPU::isVI(STI))) {
- if ((SImm16 & ~ID_MASK_) != 0) // Unused/unknown bits must be 0.
- break;
- O << "sendmsg(" << IdSymbolic[Id] << ')';
- return;
- }
- if (Id == ID_GS || Id == ID_GS_DONE) {
- if ((SImm16 & ~(ID_MASK_|OP_GS_MASK_|STREAM_ID_MASK_)) != 0) // Unused/unknown bits must be 0.
- break;
- const unsigned OpGs = (SImm16 & OP_GS_MASK_) >> OP_SHIFT_;
- const unsigned StreamId = (SImm16 & STREAM_ID_MASK_) >> STREAM_ID_SHIFT_;
- if (OpGs == OP_GS_NOP && Id != ID_GS_DONE) // NOP to be used for GS_DONE only.
- break;
- if (OpGs == OP_GS_NOP && StreamId != 0) // NOP does not use/define stream id bits.
- break;
- O << "sendmsg(" << IdSymbolic[Id] << ", " << OpGsSymbolic[OpGs];
- if (OpGs != OP_GS_NOP) { O << ", " << StreamId; }
- O << ')';
- return;
- }
- if (Id == ID_SYSMSG) {
- if ((SImm16 & ~(ID_MASK_|OP_SYS_MASK_)) != 0) // Unused/unknown bits must be 0.
- break;
- const unsigned OpSys = (SImm16 & OP_SYS_MASK_) >> OP_SHIFT_;
- if (! (OP_SYS_FIRST_ <= OpSys && OpSys < OP_SYS_LAST_)) // Unused/unknown.
- break;
- O << "sendmsg(" << IdSymbolic[Id] << ", " << OpSysSymbolic[OpSys] << ')';
- return;
+ const unsigned Imm16 = MI->getOperand(OpNo).getImm();
+
+ uint16_t MsgId;
+ uint16_t OpId;
+ uint16_t StreamId;
+ decodeMsg(Imm16, MsgId, OpId, StreamId);
+
+ if (isValidMsgId(MsgId, STI) &&
+ isValidMsgOp(MsgId, OpId) &&
+ isValidMsgStream(MsgId, OpId, StreamId)) {
+ O << "sendmsg(" << getMsgName(MsgId);
+ if (msgRequiresOp(MsgId)) {
+ O << ", " << getMsgOpName(MsgId, OpId);
+ if (msgSupportsStream(MsgId, OpId)) {
+ O << ", " << StreamId;
+ }
}
- } while (false);
- O << SImm16; // Unknown simm16 code.
+ O << ')';
+ } else if (encodeMsg(MsgId, OpId, StreamId) == Imm16) {
+ O << "sendmsg(" << MsgId << ", " << OpId << ", " << StreamId << ')';
+ } else {
+ O << Imm16; // Unknown imm16 code.
+ }
}
static void printSwizzleBitmask(const uint16_t AndMask,
enum Op { // Both GS and SYS operation IDs.
OP_UNKNOWN_ = -1,
OP_SHIFT_ = 4,
- // width(2) [5:4]
+ OP_NONE_ = 0,
+ // Bits used for operation encoding
+ OP_WIDTH_ = 3,
+ OP_MASK_ = (((1 << OP_WIDTH_) - 1) << OP_SHIFT_),
+ // GS operations are encoded in bits 5:4
OP_GS_NOP = 0,
OP_GS_CUT,
OP_GS_EMIT,
OP_GS_EMIT_CUT,
OP_GS_LAST_,
OP_GS_FIRST_ = OP_GS_NOP,
- OP_GS_WIDTH_ = 2,
- OP_GS_MASK_ = (((1 << OP_GS_WIDTH_) - 1) << OP_SHIFT_),
- // width(3) [6:4]
+ // SYS operations are encoded in bits 6:4
OP_SYS_ECC_ERR_INTERRUPT = 1,
OP_SYS_REG_RD,
OP_SYS_HOST_TRAP_ACK,
OP_SYS_TTRACE_PC,
OP_SYS_LAST_,
OP_SYS_FIRST_ = OP_SYS_ECC_ERR_INTERRUPT,
- OP_SYS_WIDTH_ = 3,
- OP_SYS_MASK_ = (((1 << OP_SYS_WIDTH_) - 1) << OP_SHIFT_)
};
enum StreamId : unsigned { // Stream ID, (2) [9:8].
+ STREAM_ID_NONE_ = 0,
STREAM_ID_DEFAULT_ = 0,
STREAM_ID_LAST_ = 4,
STREAM_ID_FIRST_ = STREAM_ID_DEFAULT_,
} // namespace Hwreg
//===----------------------------------------------------------------------===//
+// SendMsg
+//===----------------------------------------------------------------------===//
+
+namespace SendMsg {
+
+int64_t getMsgId(const StringRef Name) {
+ for (int i = ID_GAPS_FIRST_; i < ID_GAPS_LAST_; ++i) {
+ if (IdSymbolic[i] && Name == IdSymbolic[i])
+ return i;
+ }
+ return ID_UNKNOWN_;
+}
+
+static bool isValidMsgId(int64_t MsgId) {
+ return (ID_GAPS_FIRST_ <= MsgId && MsgId < ID_GAPS_LAST_) && IdSymbolic[MsgId];
+}
+
+bool isValidMsgId(int64_t MsgId, const MCSubtargetInfo &STI, bool Strict) {
+ return Strict ?
+ isValidMsgId(MsgId) && (MsgId != ID_GS_ALLOC_REQ || isGFX9(STI) || isGFX10(STI)) :
+ 0 <= MsgId && isUInt<ID_WIDTH_>(MsgId);
+}
+
+StringRef getMsgName(int64_t MsgId) {
+ return isValidMsgId(MsgId)? IdSymbolic[MsgId] : "";
+}
+
+int64_t getMsgOpId(int64_t MsgId, const StringRef Name) {
+ const char* const *S = (MsgId == ID_SYSMSG) ? OpSysSymbolic : OpGsSymbolic;
+ const int F = (MsgId == ID_SYSMSG) ? OP_SYS_FIRST_ : OP_GS_FIRST_;
+ const int L = (MsgId == ID_SYSMSG) ? OP_SYS_LAST_ : OP_GS_LAST_;
+ for (int i = F; i < L; ++i) {
+ if (Name == S[i]) {
+ return i;
+ }
+ }
+ return OP_UNKNOWN_;
+}
+
+bool isValidMsgOp(int64_t MsgId, int64_t OpId, bool Strict) {
+
+ if (!Strict)
+ return 0 <= OpId && isUInt<OP_WIDTH_>(OpId);
+
+ switch(MsgId)
+ {
+ case ID_GS:
+ return (OP_GS_FIRST_ <= OpId && OpId < OP_GS_LAST_) && OpId != OP_GS_NOP;
+ case ID_GS_DONE:
+ return OP_GS_FIRST_ <= OpId && OpId < OP_GS_LAST_;
+ case ID_SYSMSG:
+ return OP_SYS_FIRST_ <= OpId && OpId < OP_SYS_LAST_;
+ default:
+ return OpId == OP_NONE_;
+ }
+}
+
+StringRef getMsgOpName(int64_t MsgId, int64_t OpId) {
+ assert(msgRequiresOp(MsgId));
+ return (MsgId == ID_SYSMSG)? OpSysSymbolic[OpId] : OpGsSymbolic[OpId];
+}
+
+bool isValidMsgStream(int64_t MsgId, int64_t OpId, int64_t StreamId, bool Strict) {
+
+ if (!Strict)
+ return 0 <= StreamId && isUInt<STREAM_ID_WIDTH_>(StreamId);
+
+ switch(MsgId)
+ {
+ case ID_GS:
+ return STREAM_ID_FIRST_ <= StreamId && StreamId < STREAM_ID_LAST_;
+ case ID_GS_DONE:
+ return (OpId == OP_GS_NOP)?
+ (StreamId == STREAM_ID_NONE_) :
+ (STREAM_ID_FIRST_ <= StreamId && StreamId < STREAM_ID_LAST_);
+ default:
+ return StreamId == STREAM_ID_NONE_;
+ }
+}
+
+bool msgRequiresOp(int64_t MsgId) {
+ return MsgId == ID_GS || MsgId == ID_GS_DONE || MsgId == ID_SYSMSG;
+}
+
+bool msgSupportsStream(int64_t MsgId, int64_t OpId) {
+ return (MsgId == ID_GS || MsgId == ID_GS_DONE) && OpId != OP_GS_NOP;
+}
+
+void decodeMsg(unsigned Val,
+ uint16_t &MsgId,
+ uint16_t &OpId,
+ uint16_t &StreamId) {
+ MsgId = Val & ID_MASK_;
+ OpId = (Val & OP_MASK_) >> OP_SHIFT_;
+ StreamId = (Val & STREAM_ID_MASK_) >> STREAM_ID_SHIFT_;
+}
+
+int64_t encodeMsg(int64_t MsgId,
+ int64_t OpId,
+ int64_t StreamId) {
+ return (MsgId << ID_SHIFT_) |
+ (OpId << OP_SHIFT_) |
+ (StreamId << STREAM_ID_SHIFT_);
+}
+
+} // namespace SendMsg
+
+//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
} // namespace Hwreg
+namespace SendMsg {
+
+LLVM_READONLY
+int64_t getMsgId(const StringRef Name);
+
+LLVM_READONLY
+int64_t getMsgOpId(int64_t MsgId, const StringRef Name);
+
+LLVM_READNONE
+StringRef getMsgName(int64_t MsgId);
+
+LLVM_READNONE
+StringRef getMsgOpName(int64_t MsgId, int64_t OpId);
+
+LLVM_READNONE
+bool isValidMsgId(int64_t MsgId, const MCSubtargetInfo &STI, bool Strict = true);
+
+LLVM_READNONE
+bool isValidMsgOp(int64_t MsgId, int64_t OpId, bool Strict = true);
+
+LLVM_READNONE
+bool isValidMsgStream(int64_t MsgId, int64_t OpId, int64_t StreamId, bool Strict = true);
+
+LLVM_READNONE
+bool msgRequiresOp(int64_t MsgId);
+
+LLVM_READNONE
+bool msgSupportsStream(int64_t MsgId, int64_t OpId);
+
+void decodeMsg(unsigned Val,
+ uint16_t &MsgId,
+ uint16_t &OpId,
+ uint16_t &StreamId);
+
+LLVM_READNONE
+int64_t encodeMsg(int64_t MsgId,
+ int64_t OpId,
+ int64_t StreamId);
+
+} // namespace SendMsg
+
+
unsigned getInitialPSInputAddr(const Function &F);
LLVM_READNONE
; GCN: s_mov_b32 m0, s0
; GCN-NOT: s_mov_b32 m0
; VIPLUS-NEXT: s_nop 0
-; SIVI: s_sendmsg 9
+; SIVI: s_sendmsg sendmsg(9, 0, 0)
; GFX9: s_sendmsg sendmsg(MSG_GS_ALLOC_REQ)
define amdgpu_kernel void @test_gs_alloc_req(i32 inreg %a) {
body:
// RUN: not llvm-mc -arch=amdgcn -mcpu=fiji -show-encoding %s 2>&1 | FileCheck --check-prefix=GCN --check-prefix=VI --check-prefix=SICIVI %s
// RUN: not llvm-mc -arch=amdgcn -mcpu=gfx1010 -show-encoding %s 2>&1 | FileCheck --check-prefix=GCN %s
-s_sendmsg sendmsg(11)
-// GCN: error: invalid/unsupported code of message
+//===----------------------------------------------------------------------===//
+// sendmsg
+//===----------------------------------------------------------------------===//
s_sendmsg sendmsg(MSG_INTERRUPTX)
-// GCN: error: invalid/unsupported symbolic name of message
+// GCN: error: expected absolute expression
+
+s_sendmsg sendmsg(1 -)
+// GCN: error: unknown token in expression
s_sendmsg sendmsg(MSG_INTERRUPT, 0)
-// GCN: error: failed parsing operand
+// GCN: error: message does not support operations
+
+s_sendmsg sendmsg(MSG_INTERRUPT, 0, 0)
+// GCN: error: message does not support operations
s_sendmsg sendmsg(MSG_GS)
-// GCN: error: failed parsing operand
+// GCN: error: missing message operation
s_sendmsg sendmsg(MSG_GS, GS_OP_NOP)
-// GCN: error: invalid GS_OP: NOP is for GS_DONE only
+// GCN: error: invalid operation id
+
+s_sendmsg sendmsg(MSG_GS, SYSMSG_OP_ECC_ERR_INTERRUPT)
+// GCN: error: expected absolute expression
+
+s_sendmsg sendmsg(MSG_GS, 0)
+// GCN: error: invalid operation id
+
+s_sendmsg sendmsg(MSG_GS, -1)
+// GCN: error: invalid operation id
+
+s_sendmsg sendmsg(MSG_GS, 4)
+// GCN: error: invalid operation id
+
+s_sendmsg sendmsg(MSG_GS, 8)
+// GCN: error: invalid operation id
+
+s_sendmsg sendmsg(15, -1)
+// GCN: error: invalid operation id
+
+s_sendmsg sendmsg(15, 8)
+// GCN: error: invalid operation id
s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0, 0)
-// GCN: error: failed parsing operand
+// GCN: error: expected a closing parenthesis
s_sendmsg sendmsg(MSG_GSX, GS_OP_CUT, 0)
-// GCN: error: invalid/unsupported symbolic name of message
+// GCN: error: expected absolute expression
s_sendmsg sendmsg(MSG_GS, GS_OP_CUTX, 0)
-// GCN: error: invalid symbolic name of GS_OP
+// GCN: error: expected absolute expression
-s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 4)
-// GCN: error: invalid stream id: only 2-bit values are legal
+s_sendmsg sendmsg(MSG_GS, 1 -)
+// GCN: error: unknown token in expression
-s_sendmsg sendmsg(2)
-// GCN: error: failed parsing operand
+s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 4)
+// GCN: error: invalid message stream id
-s_sendmsg sendmsg(2, 0)
-// GCN: error: invalid GS_OP: NOP is for GS_DONE only
+s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 1 -)
+// GCN: error: unknown token in expression
s_sendmsg sendmsg(2, 3, 0, 0)
-// GCN: error: failed parsing operand
+// GCN: error: expected a closing parenthesis
-s_sendmsg sendmsg(2, 4, 1)
-// GCN: error: invalid code of GS_OP: only 2-bit values are legal
+s_sendmsg sendmsg(2, 2, -1)
+// GCN: error: invalid message stream id
s_sendmsg sendmsg(2, 2, 4)
-// GCN: error: invalid stream id: only 2-bit values are legal
+// GCN: error: invalid message stream id
s_sendmsg sendmsg(2, 2, 0, 0)
-// GCN: error: failed parsing operand
+// GCN: error: expected a closing parenthesis
s_sendmsg sendmsg(MSG_GS_DONE, GS_OP_NOP, 0)
-// GCN: error: failed parsing operand
+// GCN: error: message operation does not support streams
+
+s_sendmsg sendmsg(MSG_GS_DONE, 0, 0)
+// GCN: error: message operation does not support streams
s_sendmsg sendmsg(MSG_GS_ALLOC_REQ)
-// SICIVI: error: invalid/unsupported symbolic name of message
+// SICIVI: error: invalid message id
s_sendmsg sendmsg(MSG_GS_ALLOC_REQ, 0)
-// SICIVI: error: invalid/unsupported symbolic name of message
-
-s_sendmsg sendmsg(15)
-// GCN: error: failed parsing operand
+// SICIVI: error: invalid message id
-s_sendmsg sendmsg(15, 1, 0)
-// GCN: error: failed parsing operand
+s_sendmsg sendmsg(-1)
+// SICIVI: error: invalid message id
-s_sendmsg sendmsg(15, 0)
-// GCN: error: invalid/unsupported code of SYSMSG_OP
-
-s_sendmsg sendmsg(15, 5)
-// GCN: error: invalid/unsupported code of SYSMSG_OP
+s_sendmsg sendmsg(16)
+// SICIVI: error: invalid message id
s_sendmsg sendmsg(MSG_SYSMSG)
-// GCN: error: failed parsing operand
+// GCN: error: missing message operation
s_sendmsg sendmsg(MSG_SYSMSG, SYSMSG_OP_ECC_ERR_INTERRUPT, 0)
-// GCN: error: failed parsing operand
+// GCN: error: message operation does not support streams
s_sendmsg sendmsg(MSG_SYSMSG, 0)
-// GCN: error: invalid/unsupported code of SYSMSG_OP
+// GCN: error: invalid operation id
s_sendmsg sendmsg(MSG_SYSMSG, 5)
-// GCN: error: invalid/unsupported code of SYSMSG_OP
+// GCN: error: invalid operation id
+
+//===----------------------------------------------------------------------===//
+// waitcnt
+//===----------------------------------------------------------------------===//
s_waitcnt lgkmcnt(16)
// SICIVI: error: too large value for lgkmcnt
s_setprio 1
// GCN: s_setprio 1 ; encoding: [0x01,0x00,0x8f,0xbf]
-s_sendmsg 2
-// GCN: s_sendmsg 2 ; encoding: [0x02,0x00,0x90,0xbf]
+//===----------------------------------------------------------------------===//
+// s_sendmsg
+//===----------------------------------------------------------------------===//
s_sendmsg 0x1
// GCN: s_sendmsg sendmsg(MSG_INTERRUPT) ; encoding: [0x01,0x00,0x90,0xbf]
s_sendmsg sendmsg(2, 1)
// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0) ; encoding: [0x12,0x00,0x90,0xbf]
+s_sendmsg sendmsg(2, GS_OP_CUT)
+// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0) ; encoding: [0x12,0x00,0x90,0xbf]
+
+s_sendmsg sendmsg(MSG_GS, GS_OP_CUT)
+// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0) ; encoding: [0x12,0x00,0x90,0xbf]
+
s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0)
// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0) ; encoding: [0x12,0x00,0x90,0xbf]
+s_sendmsg sendmsg(MSG_GS, 1)
+// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0) ; encoding: [0x12,0x00,0x90,0xbf]
+
+s_sendmsg sendmsg(MSG_GS, 1, 1)
+// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 1) ; encoding: [0x12,0x01,0x90,0xbf]
+
s_sendmsg 0x122
// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_EMIT, 1) ; encoding: [0x22,0x01,0x90,0xbf]
s_sendmsg sendmsg(MSG_GS_DONE, GS_OP_NOP)
// GCN: s_sendmsg sendmsg(MSG_GS_DONE, GS_OP_NOP) ; encoding: [0x03,0x00,0x90,0xbf]
-s_sendmsg 0x4
-// GCN: s_sendmsg 4 ; encoding: [0x04,0x00,0x90,0xbf]
-
-s_sendmsg 9
-// GCN: s_sendmsg 9 ; encoding: [0x09,0x00,0x90,0xbf]
-
-s_sendmsg 11
-// GCN: s_sendmsg 11 ; encoding: [0x0b,0x00,0x90,0xbf]
-
s_sendmsg 0x1f
// GCN: s_sendmsg sendmsg(MSG_SYSMSG, SYSMSG_OP_ECC_ERR_INTERRUPT) ; encoding: [0x1f,0x00,0x90,0xbf]
s_sendmsg sendmsg(MSG_SYSMSG, SYSMSG_OP_ECC_ERR_INTERRUPT)
// GCN: s_sendmsg sendmsg(MSG_SYSMSG, SYSMSG_OP_ECC_ERR_INTERRUPT) ; encoding: [0x1f,0x00,0x90,0xbf]
-s_sendmsg 0x6f
-// GCN: s_sendmsg 111 ; encoding: [0x6f,0x00,0x90,0xbf]
-
s_sendmsghalt 3
// GCN: s_sendmsghalt sendmsg(MSG_GS_DONE, GS_OP_NOP) ; encoding: [0x03,0x00,0x91,0xbf]
s_sendmsghalt sendmsg(MSG_GS, GS_OP_EMIT, 1)
// GCN: s_sendmsghalt sendmsg(MSG_GS, GS_OP_EMIT, 1) ; encoding: [0x22,0x01,0x91,0xbf]
+//===----------------------------------------------------------------------===//
+// s_sendmsg with a numeric message id (no validation)
+//===----------------------------------------------------------------------===//
+
+s_sendmsg 2
+// GCN: s_sendmsg sendmsg(2, 0, 0) ; encoding: [0x02,0x00,0x90,0xbf]
+
+s_sendmsg 0x4
+// GCN: s_sendmsg sendmsg(4, 0, 0) ; encoding: [0x04,0x00,0x90,0xbf]
+
+s_sendmsg 9
+// GCN: s_sendmsg sendmsg(9, 0, 0) ; encoding: [0x09,0x00,0x90,0xbf]
+
+s_sendmsg 11
+// GCN: s_sendmsg sendmsg(11, 0, 0) ; encoding: [0x0b,0x00,0x90,0xbf]
+
+s_sendmsg 0x6f
+// GCN: s_sendmsg sendmsg(15, 6, 0) ; encoding: [0x6f,0x00,0x90,0xbf]
+
+s_sendmsg sendmsg(1, 3)
+// GCN: s_sendmsg sendmsg(1, 3, 0) ; encoding: [0x31,0x00,0x90,0xbf]
+
+s_sendmsg sendmsg(1, 3, 2)
+// GCN: s_sendmsg sendmsg(1, 3, 2) ; encoding: [0x31,0x02,0x90,0xbf]
+
+s_sendmsg sendmsg(2, 0, 1)
+// GCN: s_sendmsg sendmsg(2, 0, 1) ; encoding: [0x02,0x01,0x90,0xbf]
+
+s_sendmsg sendmsg(15, 7, 3)
+// GCN: s_sendmsg sendmsg(15, 7, 3) ; encoding: [0x7f,0x03,0x90,0xbf]
+
+s_sendmsg 4567
+// GCN: s_sendmsg 4567 ; encoding: [0xd7,0x11,0x90,0xbf]
+
+//===----------------------------------------------------------------------===//
+// s_sendmsg with expressions
+//===----------------------------------------------------------------------===//
+
+sendmsg=2
+s_sendmsg sendmsg
+// GCN: s_sendmsg sendmsg(2, 0, 0) ; encoding: [0x02,0x00,0x90,0xbf]
+
+sendmsg=1
+s_sendmsg sendmsg+1
+// GCN: s_sendmsg sendmsg(2, 0, 0) ; encoding: [0x02,0x00,0x90,0xbf]
+
+s_sendmsg 1+sendmsg
+// GCN: s_sendmsg sendmsg(2, 0, 0) ; encoding: [0x02,0x00,0x90,0xbf]
+
+msg=1
+s_sendmsg sendmsg(msg)
+// GCN: s_sendmsg sendmsg(MSG_INTERRUPT) ; encoding: [0x01,0x00,0x90,0xbf]
+
+msg=0
+s_sendmsg sendmsg(msg+1)
+// GCN: s_sendmsg sendmsg(MSG_INTERRUPT) ; encoding: [0x01,0x00,0x90,0xbf]
+
+msg=0
+s_sendmsg sendmsg(1+msg)
+// GCN: s_sendmsg sendmsg(MSG_INTERRUPT) ; encoding: [0x01,0x00,0x90,0xbf]
+
+msg=2
+op=1
+s_sendmsg sendmsg(msg, op)
+// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0) ; encoding: [0x12,0x00,0x90,0xbf]
+
+msg=1
+op=0
+s_sendmsg sendmsg(msg+1, op+1)
+// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0) ; encoding: [0x12,0x00,0x90,0xbf]
+
+msg=1
+op=0
+s_sendmsg sendmsg(1+msg, 1+op)
+// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0) ; encoding: [0x12,0x00,0x90,0xbf]
+
+msg=1
+op=2
+stream=1
+s_sendmsg sendmsg(msg+1, op+1, stream+1)
+// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_EMIT_CUT, 2) ; encoding: [0x32,0x02,0x90,0xbf]
+
+msg=1
+op=2
+stream=1
+s_sendmsg sendmsg(1+msg, 1+op, 1+stream)
+// GCN: s_sendmsg sendmsg(MSG_GS, GS_OP_EMIT_CUT, 2) ; encoding: [0x32,0x02,0x90,0xbf]
+
+MSG_GS=-1
+GS_OP_EMIT=-1
+s_sendmsghalt sendmsg(MSG_GS, GS_OP_EMIT, 1)
+// GCN: s_sendmsghalt sendmsg(MSG_GS, GS_OP_EMIT, 1) ; encoding: [0x22,0x01,0x91,0xbf]
+
+//===----------------------------------------------------------------------===//
+// misc sopp instructions
+//===----------------------------------------------------------------------===//
+
s_trap 4
// GCN: s_trap 4 ; encoding: [0x04,0x00,0x92,0xbf]
# GFX10: s_scratch_store_dwordx4 s[4:7], s[4:5], s0 glc ; encoding: [0x02,0x01,0x5d,0xf4,0x00,0x00,0x00,0x00]
0x02,0x01,0x5d,0xf4,0x00,0x00,0x00,0x00
-# GFX10: s_sendmsg 0 ; encoding: [0x00,0x00,0x90,0xbf]
+# GFX10: s_sendmsg sendmsg(0, 0, 0) ; encoding: [0x00,0x00,0x90,0xbf]
0x00,0x00,0x90,0xbf
# GFX10: s_sendmsg 4660 ; encoding: [0x34,0x12,0x90,0xbf]
# GFX10: s_sendmsg 49617 ; encoding: [0xd1,0xc1,0x90,0xbf]
0xd1,0xc1,0x90,0xbf
-# GFX10: s_sendmsghalt 0 ; encoding: [0x00,0x00,0x91,0xbf]
+# GFX10: s_sendmsghalt sendmsg(0, 0, 0) ; encoding: [0x00,0x00,0x91,0xbf]
0x00,0x00,0x91,0xbf
# GFX10: s_sendmsghalt 4660 ; encoding: [0x34,0x12,0x91,0xbf]
# GCN: s_setprio 1 ; encoding: [0x01,0x00,0x8f,0xbf]
0x01 0x00 0x8f 0xbf
-# GCN: s_sendmsg 2 ; encoding: [0x02,0x00,0x90,0xbf]
+# GCN: s_sendmsg sendmsg(2, 0, 0) ; encoding: [0x02,0x00,0x90,0xbf]
0x02 0x00 0x90 0xbf
# GCN: s_sendmsg sendmsg(MSG_INTERRUPT) ; encoding: [0x01,0x00,0x90,0xbf]
# GCN: s_sendmsg sendmsg(MSG_GS_DONE, GS_OP_NOP) ; encoding: [0x03,0x00,0x90,0xbf]
0x03 0x00 0x90 0xbf
-# GCN: s_sendmsg 11 ; encoding: [0x0b,0x00,0x90,0xbf]
+# GCN: s_sendmsg sendmsg(11, 0, 0) ; encoding: [0x0b,0x00,0x90,0xbf]
0x0b 0x00 0x90 0xbf
# GCN: s_sendmsg sendmsg(MSG_SYSMSG, SYSMSG_OP_ECC_ERR_INTERRUPT) ; encoding: [0x1f,0x00,0x90,0xbf]
0x1f 0x00 0x90 0xbf
-# GCN: s_sendmsg 111 ; encoding: [0x6f,0x00,0x90,0xbf]
+# GCN: s_sendmsg sendmsg(15, 6, 0) ; encoding: [0x6f,0x00,0x90,0xbf]
0x6f 0x00 0x90 0xbf
# GCN: s_sendmsghalt sendmsg(MSG_GS_DONE, GS_OP_NOP) ; encoding: [0x03,0x00,0x91,0xbf]
# GCN: s_sendmsghalt sendmsg(MSG_GS, GS_OP_EMIT, 1) ; encoding: [0x22,0x01,0x91,0xbf]
0x22 0x01 0x91 0xbf
-# GCN: s_sendmsghalt 111 ; encoding: [0x6f,0x00,0x91,0xbf]
+# GCN: s_sendmsghalt sendmsg(15, 6, 0) ; encoding: [0x6f,0x00,0x91,0xbf]
0x6f 0x00 0x91 0xbf
+# GCN: s_sendmsg sendmsg(1, 3, 0) ; encoding: [0x31,0x00,0x90,0xbf]
+0x31 0x00 0x90 0xbf
+
+# GCN: s_sendmsg sendmsg(1, 3, 2) ; encoding: [0x31,0x02,0x90,0xbf]
+0x31 0x02 0x90 0xbf
+
+# GCN: s_sendmsg sendmsg(2, 0, 1) ; encoding: [0x02,0x01,0x90,0xbf]
+0x02 0x01 0x90 0xbf
+
+# GCN: s_sendmsg sendmsg(15, 7, 3) ; encoding: [0x7f,0x03,0x90,0xbf]
+0x7f 0x03 0x90 0xbf
+
+# GCN: s_sendmsg 4567 ; encoding: [0xd7,0x11,0x90,0xbf]
+0xd7 0x11 0x90 0xbf
+
# GCN: s_trap 4 ; encoding: [0x04,0x00,0x92,0xbf]
0x04 0x00 0x92 0xbf