1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[AMDGPU][llvm-mc] s_getreg/setreg* - hwreg - factor out strings/literals etc.

Hwreg(...) syntax implementation unified with sendmsg(...).
Common strings moved to Utils
MathExtras.h functionality utilized.
Added missing build dependency in Disassembler.

Differential Revision: http://reviews.llvm.org/D20381

llvm-svn: 270871
This commit is contained in:
Artem Tamazov 2016-05-26 17:00:33 +00:00
parent ca3f24eddb
commit c4881d7a78
10 changed files with 206 additions and 169 deletions

View File

@ -13,6 +13,7 @@
#include "SIDefines.h"
#include "Utils/AMDGPUBaseInfo.h"
#include "Utils/AMDKernelCodeTUtils.h"
#include "Utils/AMDGPUAsmUtils.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
@ -36,54 +37,7 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
// FIXME ODR: Move this to some common place for AsmParser and InstPrinter
namespace llvm {
namespace AMDGPU {
namespace SendMsg {
// This must be in sync with llvm::AMDGPU::SendMsg::Id enum members.
static
const char* const IdSymbolic[] = {
nullptr,
"MSG_INTERRUPT",
"MSG_GS",
"MSG_GS_DONE",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"MSG_SYSMSG"
};
// These two must be in sync with llvm::AMDGPU::SendMsg::Op enum members.
static
const char* const OpSysSymbolic[] = {
nullptr,
"SYSMSG_OP_ECC_ERR_INTERRUPT",
"SYSMSG_OP_REG_RD",
"SYSMSG_OP_HOST_TRAP_ACK",
"SYSMSG_OP_TTRACE_PC"
};
static
const char* const OpGsSymbolic[] = {
"GS_OP_NOP",
"GS_OP_CUT",
"GS_OP_EMIT",
"GS_OP_EMIT_CUT"
};
} // namespace SendMsg
} // namespace AMDGPU
} // namespace llvm
#include "llvm/Support/MathExtras.h"
using namespace llvm;
@ -637,7 +591,6 @@ public:
bool parseCnt(int64_t &IntVal);
OperandMatchResultTy parseSWaitCntOps(OperandVector &Operands);
bool parseHwregOperand(int64_t &HwRegCode, int64_t &Offset, int64_t &Width, bool &IsIdentifier);
OperandMatchResultTy parseHwreg(OperandVector &Operands);
private:
@ -647,8 +600,8 @@ private:
OperandInfoTy(int64_t Id_) : Id(Id_), IsSymbolic(false) { }
};
bool parseSendMsg(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId);
bool parseSendMsgConstruct(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId);
bool parseHwregConstruct(OperandInfoTy &HwReg, int64_t &Offset, int64_t &Width);
public:
OperandMatchResultTy parseOptionalOperand(OperandVector &Operands);
@ -1669,7 +1622,9 @@ AMDGPUAsmParser::parseSWaitCntOps(OperandVector &Operands) {
return MatchOperand_Success;
}
bool AMDGPUAsmParser::parseHwregOperand(int64_t &HwRegCode, int64_t &Offset, int64_t &Width, bool &IsIdentifier) {
bool AMDGPUAsmParser::parseHwregConstruct(OperandInfoTy &HwReg, int64_t &Offset, int64_t &Width) {
using namespace llvm::AMDGPU::Hwreg;
if (Parser.getTok().getString() != "hwreg")
return true;
Parser.Lex();
@ -1679,22 +1634,21 @@ bool AMDGPUAsmParser::parseHwregOperand(int64_t &HwRegCode, int64_t &Offset, int
Parser.Lex();
if (getLexer().is(AsmToken::Identifier)) {
IsIdentifier = true;
HwRegCode = StringSwitch<unsigned>(Parser.getTok().getString())
.Case("HW_REG_MODE" , 1)
.Case("HW_REG_STATUS" , 2)
.Case("HW_REG_TRAPSTS" , 3)
.Case("HW_REG_HW_ID" , 4)
.Case("HW_REG_GPR_ALLOC", 5)
.Case("HW_REG_LDS_ALLOC", 6)
.Case("HW_REG_IB_STS" , 7)
.Default(-1);
HwReg.IsSymbolic = true;
HwReg.Id = ID_UNKNOWN_;
const StringRef tok = Parser.getTok().getString();
for (int i = ID_SYMBOLIC_FIRST_; i < ID_SYMBOLIC_LAST_; ++i) {
if (tok == IdSymbolic[i]) {
HwReg.Id = i;
break;
}
}
Parser.Lex();
} else {
IsIdentifier = false;
HwReg.IsSymbolic = false;
if (getLexer().isNot(AsmToken::Integer))
return true;
if (getParser().parseAbsoluteExpression(HwRegCode))
if (getParser().parseAbsoluteExpression(HwReg.Id))
return true;
}
@ -1731,6 +1685,8 @@ bool AMDGPUAsmParser::parseHwregOperand(int64_t &HwRegCode, int64_t &Offset, int
AMDGPUAsmParser::OperandMatchResultTy
AMDGPUAsmParser::parseHwreg(OperandVector &Operands) {
using namespace llvm::AMDGPU::Hwreg;
int64_t Imm16Val = 0;
SMLoc S = Parser.getTok().getLoc();
@ -1739,8 +1695,8 @@ AMDGPUAsmParser::parseHwreg(OperandVector &Operands) {
case AsmToken::Integer:
// The operand can be an integer value.
if (getParser().parseAbsoluteExpression(Imm16Val))
return MatchOperand_ParseFail;
if (!isInt<16>(Imm16Val) && !isUInt<16>(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.
@ -1748,26 +1704,22 @@ AMDGPUAsmParser::parseHwreg(OperandVector &Operands) {
break;
case AsmToken::Identifier: {
bool IsIdentifier = false;
int64_t HwRegCode = -1;
int64_t Offset = 0; // default
int64_t Width = 32; // default
if (parseHwregOperand(HwRegCode, Offset, Width, IsIdentifier))
OperandInfoTy HwReg(ID_UNKNOWN_);
int64_t Offset = OFFSET_DEFAULT_;
int64_t Width = WIDTH_M1_DEFAULT_ + 1;
if (parseHwregConstruct(HwReg, Offset, Width))
return MatchOperand_ParseFail;
// HwRegCode (6) [5:0]
// Offset (5) [10:6]
// WidthMinusOne (5) [15:11]
if (HwRegCode < 0 || HwRegCode > 63) {
if (IsIdentifier)
if (HwReg.Id < 0 || !isUInt<ID_WIDTH_>(HwReg.Id)) {
if (HwReg.IsSymbolic)
Error(S, "invalid symbolic name of hardware register");
else
Error(S, "invalid code of hardware register: only 6-bit values are legal");
}
if (Offset < 0 || Offset > 31)
if (Offset < 0 || !isUInt<OFFSET_WIDTH_>(Offset))
Error(S, "invalid bit offset: only 5-bit values are legal");
if (Width < 1 || Width > 32)
if ((Width-1) < 0 || !isUInt<WIDTH_M1_WIDTH_>(Width-1))
Error(S, "invalid bitfield width: only values from 1 to 32 are legal");
Imm16Val = HwRegCode | (Offset << 6) | ((Width-1) << 11);
Imm16Val = (HwReg.Id << ID_SHIFT_) | (Offset << OFFSET_SHIFT_) | ((Width-1) << WIDTH_M1_SHIFT_);
}
break;
}
@ -1787,7 +1739,7 @@ AMDGPUOperand::Ptr AMDGPUAsmParser::defaultHwreg() const {
return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyHwreg);
}
bool AMDGPUAsmParser::parseSendMsg(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId) {
bool AMDGPUAsmParser::parseSendMsgConstruct(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId) {
using namespace llvm::AMDGPU::SendMsg;
if (Parser.getTok().getString() != "sendmsg")
@ -1844,7 +1796,7 @@ bool AMDGPUAsmParser::parseSendMsg(OperandInfoTy &Msg, OperandInfoTy &Operation,
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 std::string Tok = Parser.getTok().getString();
const StringRef Tok = Parser.getTok().getString();
for (int i = F; i < L; ++i) {
if (Tok == S[i]) {
Operation.Id = i;
@ -1897,7 +1849,7 @@ AMDGPUAsmParser::parseSendMsgOp(OperandVector &Operands) {
// The operand can be an integer value.
if (getParser().parseAbsoluteExpression(Imm16Val))
return MatchOperand_NoMatch;
if (!isInt<16>(Imm16Val) && !isUInt<16>(Imm16Val)) {
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.
@ -1906,9 +1858,9 @@ AMDGPUAsmParser::parseSendMsgOp(OperandVector &Operands) {
case AsmToken::Identifier: {
OperandInfoTy Msg(ID_UNKNOWN_);
OperandInfoTy Operation(OP_UNKNOWN_);
int64_t StreamId = STREAM_ID_DEFAULT;
if (parseSendMsg(Msg, Operation, StreamId))
return MatchOperand_NoMatch;
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)
@ -1919,7 +1871,7 @@ AMDGPUAsmParser::parseSendMsgOp(OperandVector &Operands) {
Error(S, "invalid/unsupported code of message");
break;
}
Imm16Val = Msg.Id;
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_)) {

View File

@ -4,4 +4,4 @@ add_llvm_library(LLVMAMDGPUDisassembler
AMDGPUDisassembler.cpp
)
add_dependencies(LLVMAMDGPUDisassembler AMDGPUCommonTableGen)
add_dependencies(LLVMAMDGPUDisassembler AMDGPUCommonTableGen LLVMAMDGPUUtils)

View File

@ -11,6 +11,7 @@
#include "AMDGPUInstPrinter.h"
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "SIDefines.h"
#include "Utils/AMDGPUAsmUtils.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
@ -20,54 +21,6 @@
#include <string>
// FIXME ODR: Move this to some common place for AsmParser and InstPrinter
namespace llvm {
namespace AMDGPU {
namespace SendMsg {
// This must be in sync with llvm::AMDGPU::SendMsg::Id enum members.
static
const char* const IdSymbolic[] = {
nullptr,
"MSG_INTERRUPT",
"MSG_GS",
"MSG_GS_DONE",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"MSG_SYSMSG"
};
// These two must be in sync with llvm::AMDGPU::SendMsg::Op enum members.
static
const char* const OpSysSymbolic[] = {
nullptr,
"SYSMSG_OP_ECC_ERR_INTERRUPT",
"SYSMSG_OP_REG_RD",
"SYSMSG_OP_HOST_TRAP_ACK",
"SYSMSG_OP_TTRACE_PC"
};
static
const char* const OpGsSymbolic[] = {
"GS_OP_NOP",
"GS_OP_CUT",
"GS_OP_EMIT",
"GS_OP_EMIT_CUT"
};
} // namespace SendMsg
} // namespace AMDGPU
} // namespace llvm
using namespace llvm;
void AMDGPUInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
@ -886,23 +839,20 @@ void AMDGPUInstPrinter::printWaitFlag(const MCInst *MI, unsigned OpNo,
void AMDGPUInstPrinter::printHwreg(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
using namespace llvm::AMDGPU::Hwreg;
unsigned SImm16 = MI->getOperand(OpNo).getImm();
const unsigned HwRegCode = SImm16 & 0x3F;
const unsigned Offset = (SImm16 >> 6) & 0x1f;
const unsigned Width = ((SImm16 >> 11) & 0x1F) + 1;
const unsigned Id = (SImm16 & ID_MASK_) >> ID_SHIFT_;
const unsigned Offset = (SImm16 & OFFSET_MASK_) >> OFFSET_SHIFT_;
const unsigned Width = ((SImm16 & WIDTH_M1_MASK_) >> WIDTH_M1_SHIFT_) + 1;
O << "hwreg(";
switch(HwRegCode) {
case 1: O << "HW_REG_MODE" ; break;
case 2: O << "HW_REG_STATUS" ; break;
case 3: O << "HW_REG_TRAPSTS" ; break;
case 4: O << "HW_REG_HW_ID" ; break;
case 5: O << "HW_REG_GPR_ALLOC" ; break;
case 6: O << "HW_REG_LDS_ALLOC" ; break;
case 7: O << "HW_REG_IB_STS" ; break;
default: O << HwRegCode; break;
if (ID_SYMBOLIC_FIRST_ <= Id && Id < ID_SYMBOLIC_LAST_) {
O << IdSymbolic[Id];
} else {
O << Id;
}
if (! (Width == 32 && Offset == 0)) {
if (Width != WIDTH_M1_DEFAULT_ + 1 || Offset != OFFSET_DEFAULT_) {
O << ", " << Offset << ", " << Width;
}
O << ')';

View File

@ -1,3 +1,5 @@
add_llvm_library(LLVMAMDGPUAsmPrinter
AMDGPUInstPrinter.cpp
)
add_dependencies(LLVMAMDGPUAsmPrinter LLVMAMDGPUUtils)

View File

@ -19,6 +19,6 @@
type = Library
name = AMDGPUAsmPrinter
parent = AMDGPU
required_libraries = MC Support
required_libraries = MC Support AMDGPUUtils
add_to_library_groups = AMDGPU

View File

@ -122,7 +122,7 @@ namespace llvm {
namespace AMDGPU {
namespace SendMsg { // Encoding of SIMM16 used in s_sendmsg* insns.
enum Id { // Message ID, width(3) [3:0].
enum Id { // Message ID, width(4) [3:0].
ID_UNKNOWN_ = -1,
ID_INTERRUPT = 1,
ID_GS,
@ -130,11 +130,14 @@ enum Id { // Message ID, width(3) [3:0].
ID_SYSMSG = 15,
ID_GAPS_LAST_, // Indicate that sequence has gaps.
ID_GAPS_FIRST_ = ID_INTERRUPT,
ID_MASK_ = 0xf
ID_SHIFT_ = 0,
ID_WIDTH_ = 4,
ID_MASK_ = (((1 << ID_WIDTH_) - 1) << ID_SHIFT_)
};
enum Op { // Both GS and SYS operation IDs.
OP_UNKNOWN_ = -1,
OP_SHIFT_ = 4,
// width(2) [5:4]
OP_GS_NOP = 0,
OP_GS_CUT,
@ -142,7 +145,8 @@ enum Op { // Both GS and SYS operation IDs.
OP_GS_EMIT_CUT,
OP_GS_LAST_,
OP_GS_FIRST_ = OP_GS_NOP,
OP_GS_MASK_ = (0x3 << 4),
OP_GS_WIDTH_ = 2,
OP_GS_MASK_ = (((1 << OP_GS_WIDTH_) - 1) << OP_SHIFT_),
// width(3) [6:4]
OP_SYS_ECC_ERR_INTERRUPT = 1,
OP_SYS_REG_RD,
@ -150,19 +154,47 @@ enum Op { // Both GS and SYS operation IDs.
OP_SYS_TTRACE_PC,
OP_SYS_LAST_,
OP_SYS_FIRST_ = OP_SYS_ECC_ERR_INTERRUPT,
OP_SYS_MASK_ = (0x7 << 4),
OP_SHIFT_ = 4
OP_SYS_WIDTH_ = 3,
OP_SYS_MASK_ = (((1 << OP_SYS_WIDTH_) - 1) << OP_SHIFT_)
};
enum StreamId { // Stream ID, (2) [9:8].
STREAM_ID_DEFAULT = 0,
STREAM_ID_DEFAULT_ = 0,
STREAM_ID_LAST_ = 4,
STREAM_ID_FIRST_ = STREAM_ID_DEFAULT,
STREAM_ID_MASK_ = (0x3 << 8),
STREAM_ID_SHIFT_ = 8
STREAM_ID_FIRST_ = STREAM_ID_DEFAULT_,
STREAM_ID_SHIFT_ = 8,
STREAM_ID_WIDTH_= 2,
STREAM_ID_MASK_ = (((1 << STREAM_ID_WIDTH_) - 1) << STREAM_ID_SHIFT_)
};
} // namespace SendMsg
namespace Hwreg { // Encoding of SIMM16 used in s_setreg/getreg* insns.
enum Id { // HwRegCode, (6) [5:0]
ID_UNKNOWN_ = -1,
ID_SYMBOLIC_FIRST_ = 1, // There are corresponding symbolic names defined.
ID_SYMBOLIC_LAST_ = 8,
ID_SHIFT_ = 0,
ID_WIDTH_ = 6,
ID_MASK_ = (((1 << ID_WIDTH_) - 1) << ID_SHIFT_)
};
enum Offset { // Offset, (5) [10:6]
OFFSET_DEFAULT_ = 0,
OFFSET_SHIFT_ = 6,
OFFSET_WIDTH_ = 5,
OFFSET_MASK_ = (((1 << OFFSET_WIDTH_) - 1) << OFFSET_SHIFT_)
};
enum WidthMinusOne { // WidthMinusOne, (5) [15:11]
WIDTH_M1_DEFAULT_ = 31,
WIDTH_M1_SHIFT_ = 11,
WIDTH_M1_WIDTH_ = 5,
WIDTH_M1_MASK_ = (((1 << WIDTH_M1_WIDTH_) - 1) << WIDTH_M1_SHIFT_)
};
} // namespace Hwreg
} // namespace AMDGPU
} // namespace llvm

View File

@ -0,0 +1,69 @@
//===-- AMDGPUAsmUtils.cpp - AsmParser/InstPrinter common -----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AMDGPUAsmUtils.h"
namespace llvm {
namespace AMDGPU {
namespace SendMsg {
// This must be in sync with llvm::AMDGPU::SendMsg::Id enum members, see SIDefines.h.
const char* const IdSymbolic[] = {
nullptr,
"MSG_INTERRUPT",
"MSG_GS",
"MSG_GS_DONE",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"MSG_SYSMSG"
};
// These two must be in sync with llvm::AMDGPU::SendMsg::Op enum members, see SIDefines.h.
const char* const OpSysSymbolic[] = {
nullptr,
"SYSMSG_OP_ECC_ERR_INTERRUPT",
"SYSMSG_OP_REG_RD",
"SYSMSG_OP_HOST_TRAP_ACK",
"SYSMSG_OP_TTRACE_PC"
};
const char* const OpGsSymbolic[] = {
"GS_OP_NOP",
"GS_OP_CUT",
"GS_OP_EMIT",
"GS_OP_EMIT_CUT"
};
} // namespace SendMsg
namespace Hwreg {
// This must be in sync with llvm::AMDGPU::Hwreg::ID_SYMBOLIC_FIRST_/LAST_, see SIDefines.h.
const char* const IdSymbolic[] = {
nullptr,
"HW_REG_MODE",
"HW_REG_STATUS",
"HW_REG_TRAPSTS",
"HW_REG_HW_ID",
"HW_REG_GPR_ALLOC",
"HW_REG_LDS_ALLOC",
"HW_REG_IB_STS"
};
} // namespace Hwreg
} // namespace AMDGPU
} // namespace llvm

View File

@ -0,0 +1,31 @@
//===-- AMDGPUAsmUtils.h - AsmParser/InstPrinter common ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_AMDGPU_UTILS_AMDGPUASMUTILS_H
#define LLVM_LIB_TARGET_AMDGPU_UTILS_AMDGPUASMUTILS_H
namespace llvm {
namespace AMDGPU {
namespace SendMsg { // Symbolic names for the sendmsg(...) syntax.
extern const char* const IdSymbolic[];
extern const char* const OpSysSymbolic[];
extern const char* const OpGsSymbolic[];
} // namespace SendMsg
namespace Hwreg { // Symbolic names for the hwreg(...) syntax.
extern const char* const IdSymbolic[];
} // namespace Hwreg
} // namespace AMDGPU
} // namespace llvm
#endif

View File

@ -1,4 +1,5 @@
add_llvm_library(LLVMAMDGPUUtils
AMDGPUBaseInfo.cpp
AMDKernelCodeTUtils.cpp
AMDGPUAsmUtils.cpp
)

View File

@ -9,16 +9,16 @@ s_sendmsg sendmsg(MSG_INTERRUPTX)
// GCN: error: invalid/unsupported symbolic name of message
s_sendmsg sendmsg(MSG_INTERRUPT, 0)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(MSG_GS)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(MSG_GS, GS_OP_NOP)
// GCN: error: invalid GS_OP: NOP is for GS_DONE only
s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 0, 0)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(MSG_GSX, GS_OP_CUT, 0)
// GCN: error: invalid/unsupported symbolic name of message
@ -30,13 +30,13 @@ s_sendmsg sendmsg(MSG_GS, GS_OP_CUT, 4)
// GCN: error: invalid stream id: only 2-bit values are legal
s_sendmsg sendmsg(2)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(2, 0)
// GCN: error: invalid GS_OP: NOP is for GS_DONE only
s_sendmsg sendmsg(2, 3, 0, 0)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(2, 4, 1)
// GCN: error: invalid code of GS_OP: only 2-bit values are legal
@ -45,16 +45,16 @@ s_sendmsg sendmsg(2, 2, 4)
// GCN: error: invalid stream id: only 2-bit values are legal
s_sendmsg sendmsg(2, 2, 0, 0)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(MSG_GS_DONE, GS_OP_NOP, 0)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(15)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(15, 1, 0)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(15, 0)
// GCN: error: invalid/unsupported code of SYSMSG_OP
@ -63,10 +63,10 @@ s_sendmsg sendmsg(15, 5)
// GCN: error: invalid/unsupported code of SYSMSG_OP
s_sendmsg sendmsg(MSG_SYSMSG)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(MSG_SYSMSG, SYSMSG_OP_ECC_ERR_INTERRUPT, 0)
// GCN: error: not a valid operand
// GCN: error: failed parsing operand
s_sendmsg sendmsg(MSG_SYSMSG, 0)
// GCN: error: invalid/unsupported code of SYSMSG_OP