[llvm] dcc7ef3 - [AMDGPU][MC] Disable sendmsg SYSMSG_OP_HOST_TRAP_ACK on gfx9+ (#90203)
via llvm-commits
llvm-commits at lists.llvm.org
Tue May 7 04:39:02 PDT 2024
Author: Emma Pilkington
Date: 2024-05-07T07:38:58-04:00
New Revision: dcc7ef3ce87d7ea1ed9e64bb91e3bb2026df9644
URL: https://github.com/llvm/llvm-project/commit/dcc7ef3ce87d7ea1ed9e64bb91e3bb2026df9644
DIFF: https://github.com/llvm/llvm-project/commit/dcc7ef3ce87d7ea1ed9e64bb91e3bb2026df9644.diff
LOG: [AMDGPU][MC] Disable sendmsg SYSMSG_OP_HOST_TRAP_ACK on gfx9+ (#90203)
This is no longer supported as of gfx9. Fixes #52903
This commit also includes some refactoring of sendmsg operand parsing:
- Use CustomOperand for sendmsg operations, this allows them to be
conditionally available based on a STI check (and automatically in
sync with SIDefines.h).
- Move CustomOperand table lookups from AMDGPUBaseInfo to
AMDGPUAsmUtils. This cleans up an awkward interface where
AMDGPUAsmUtils defined a table/size as globals that AMDGPUBaseInfo
had to loop over.
- Clean up a few of the operand lookup functions while moving them.
Added:
Modified:
llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
llvm/lib/Target/AMDGPU/SIDefines.h
llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp
llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h
llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
llvm/test/MC/AMDGPU/gfx9-asm-err.s
llvm/test/MC/AMDGPU/sopp-err.s
llvm/test/MC/AMDGPU/sopp-gfx9.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
index e7930b68972e7..5ac245ac3b63d 100644
--- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
+++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
@@ -7436,7 +7436,8 @@ AMDGPUAsmParser::parseSendMsgBody(OperandInfoTy &Msg,
Op.IsDefined = true;
Op.Loc = getLoc();
if (isToken(AsmToken::Identifier) &&
- (Op.Val = getMsgOpId(Msg.Val, getTokenStr())) >= 0) {
+ (Op.Val = getMsgOpId(Msg.Val, getTokenStr(), getSTI())) !=
+ OPR_ID_UNKNOWN) {
lex(); // skip operation name
} else if (!parseExpr(Op.Val, "an operation name")) {
return false;
@@ -7484,7 +7485,10 @@ AMDGPUAsmParser::validateSendMsg(const OperandInfoTy &Msg,
return false;
}
if (!isValidMsgOp(Msg.Val, Op.Val, getSTI(), Strict)) {
- Error(Op.Loc, "invalid operation id");
+ if (Op.Val == OPR_ID_UNSUPPORTED)
+ Error(Op.Loc, "specified operation id is not supported on this GPU");
+ else
+ Error(Op.Loc, "invalid operation id");
return false;
}
if (Strict && !msgSupportsStream(Msg.Val, Op.Val, getSTI()) &&
diff --git a/llvm/lib/Target/AMDGPU/SIDefines.h b/llvm/lib/Target/AMDGPU/SIDefines.h
index 1f0207ddb0ebd..6d0e0b3f4de2c 100644
--- a/llvm/lib/Target/AMDGPU/SIDefines.h
+++ b/llvm/lib/Target/AMDGPU/SIDefines.h
@@ -468,7 +468,6 @@ enum Id { // Message ID, width(4) [3:0].
};
enum Op { // Both GS and SYS operation IDs.
- OP_UNKNOWN_ = -1,
OP_SHIFT_ = 4,
OP_NONE_ = 0,
// Bits used for operation encoding
@@ -479,14 +478,12 @@ enum Op { // Both GS and SYS operation IDs.
OP_GS_CUT = 1,
OP_GS_EMIT = 2,
OP_GS_EMIT_CUT = 3,
- OP_GS_LAST_,
OP_GS_FIRST_ = OP_GS_NOP,
// SYS operations are encoded in bits 6:4
OP_SYS_ECC_ERR_INTERRUPT = 1,
OP_SYS_REG_RD = 2,
OP_SYS_HOST_TRAP_ACK = 3,
OP_SYS_TTRACE_PC = 4,
- OP_SYS_LAST_,
OP_SYS_FIRST_ = OP_SYS_ECC_ERR_INTERRUPT,
};
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp
index d468b14d54d3f..2e1db1665b9c1 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp
@@ -12,6 +12,60 @@
namespace llvm {
namespace AMDGPU {
+//===----------------------------------------------------------------------===//
+// Custom Operands.
+//
+// A table of custom operands shall describe "primary" operand names first
+// followed by aliases if any. It is not required but recommended to arrange
+// operands so that operand encoding match operand position in the table. This
+// will make getNameFromOperandTable() a bit more efficient. Unused slots in the
+// table shall have an empty name.
+//
+//===----------------------------------------------------------------------===//
+
+/// Map from the encoding of a sendmsg/hwreg asm operand to it's name.
+template <size_t N>
+static StringRef getNameFromOperandTable(const CustomOperand (&Table)[N],
+ unsigned Encoding,
+ const MCSubtargetInfo &STI) {
+ auto isValidIndexForEncoding = [&](size_t Idx) {
+ return Idx < N && Table[Idx].Encoding == Encoding &&
+ !Table[Idx].Name.empty() &&
+ (!Table[Idx].Cond || Table[Idx].Cond(STI));
+ };
+
+ // This is an optimization that should work in most cases. As a side effect,
+ // it may cause selection of an alias instead of a primary operand name in
+ // case of sparse tables.
+ if (isValidIndexForEncoding(Encoding))
+ return Table[Encoding].Name;
+
+ for (size_t Idx = 0; Idx != N; ++Idx)
+ if (isValidIndexForEncoding(Idx))
+ return Table[Idx].Name;
+
+ return "";
+}
+
+/// Map from a symbolic name for a sendmsg/hwreg asm operand to it's encoding.
+template <size_t N>
+static int64_t getEncodingFromOperandTable(const CustomOperand (&Table)[N],
+ StringRef Name,
+ const MCSubtargetInfo &STI) {
+ int64_t InvalidEncoding = OPR_ID_UNKNOWN;
+ for (const CustomOperand &Entry : Table) {
+ if (Entry.Name != Name)
+ continue;
+
+ if (!Entry.Cond || Entry.Cond(STI))
+ return Entry.Encoding;
+
+ InvalidEncoding = OPR_ID_UNSUPPORTED;
+ }
+
+ return InvalidEncoding;
+}
+
namespace DepCtr {
// NOLINTBEGIN
@@ -34,10 +88,11 @@ const int DEP_CTR_SIZE =
namespace SendMsg {
-// Disable lint checking for this block since it makes the table unreadable.
+// Disable lint checking here since it makes these tables unreadable.
// NOLINTBEGIN
// clang-format off
-const CustomOperand<const MCSubtargetInfo &> Msg[] = {
+
+static constexpr CustomOperand MsgOperands[] = {
{{""}},
{{"MSG_INTERRUPT"}, ID_INTERRUPT},
{{"MSG_GS"}, ID_GS_PreGFX11, isNotGFX11Plus},
@@ -63,27 +118,47 @@ const CustomOperand<const MCSubtargetInfo &> Msg[] = {
{{"MSG_RTN_GET_TBA_TO_PC"}, ID_RTN_GET_TBA_TO_PC, isGFX11Plus},
{{"MSG_RTN_GET_SE_AID_ID"}, ID_RTN_GET_SE_AID_ID, isGFX12Plus},
};
+
+static constexpr CustomOperand SysMsgOperands[] = {
+ {{""}},
+ {{"SYSMSG_OP_ECC_ERR_INTERRUPT"}, OP_SYS_ECC_ERR_INTERRUPT},
+ {{"SYSMSG_OP_REG_RD"}, OP_SYS_REG_RD},
+ {{"SYSMSG_OP_HOST_TRAP_ACK"}, OP_SYS_HOST_TRAP_ACK, isNotGFX9Plus},
+ {{"SYSMSG_OP_TTRACE_PC"}, OP_SYS_TTRACE_PC},
+};
+
+static constexpr CustomOperand StreamMsgOperands[] = {
+ {{"GS_OP_NOP"}, OP_GS_NOP},
+ {{"GS_OP_CUT"}, OP_GS_CUT},
+ {{"GS_OP_EMIT"}, OP_GS_EMIT},
+ {{"GS_OP_EMIT_CUT"}, OP_GS_EMIT_CUT},
+};
+
// clang-format on
// NOLINTEND
-const int MSG_SIZE = static_cast<int>(
- sizeof(Msg) / sizeof(CustomOperand<const MCSubtargetInfo &>));
+int64_t getMsgId(StringRef Name, const MCSubtargetInfo &STI) {
+ return getEncodingFromOperandTable(MsgOperands, Name, STI);
+}
-// These two must be in sync with llvm::AMDGPU::SendMsg::Op enum members, see SIDefines.h.
-const char *const OpSysSymbolic[OP_SYS_LAST_] = {
- nullptr,
- "SYSMSG_OP_ECC_ERR_INTERRUPT",
- "SYSMSG_OP_REG_RD",
- "SYSMSG_OP_HOST_TRAP_ACK",
- "SYSMSG_OP_TTRACE_PC"
-};
+StringRef getMsgName(uint64_t Encoding, const MCSubtargetInfo &STI) {
+ return getNameFromOperandTable(MsgOperands, Encoding, STI);
+}
-const char *const OpGsSymbolic[OP_GS_LAST_] = {
- "GS_OP_NOP",
- "GS_OP_CUT",
- "GS_OP_EMIT",
- "GS_OP_EMIT_CUT"
-};
+int64_t getMsgOpId(int64_t MsgId, StringRef Name, const MCSubtargetInfo &STI) {
+ if (MsgId == ID_SYSMSG)
+ return getEncodingFromOperandTable(SysMsgOperands, Name, STI);
+ return getEncodingFromOperandTable(StreamMsgOperands, Name, STI);
+}
+
+StringRef getMsgOpName(int64_t MsgId, uint64_t Encoding,
+ const MCSubtargetInfo &STI) {
+ assert(msgRequiresOp(MsgId, STI) && "must have an operand");
+
+ if (MsgId == ID_SYSMSG)
+ return getNameFromOperandTable(SysMsgOperands, Encoding, STI);
+ return getNameFromOperandTable(StreamMsgOperands, Encoding, STI);
+}
} // namespace SendMsg
@@ -92,7 +167,7 @@ namespace Hwreg {
// Disable lint checking for this block since it makes the table unreadable.
// NOLINTBEGIN
// clang-format off
-const CustomOperand<const MCSubtargetInfo &> Opr[] = {
+static constexpr CustomOperand Operands[] = {
{{""}},
{{"HW_REG_MODE"}, ID_MODE},
{{"HW_REG_STATUS"}, ID_STATUS},
@@ -155,8 +230,13 @@ const CustomOperand<const MCSubtargetInfo &> Opr[] = {
// clang-format on
// NOLINTEND
-const int OPR_SIZE = static_cast<int>(
- sizeof(Opr) / sizeof(CustomOperand<const MCSubtargetInfo &>));
+int64_t getHwregId(StringRef Name, const MCSubtargetInfo &STI) {
+ return getEncodingFromOperandTable(Operands, Name, STI);
+}
+
+StringRef getHwreg(uint64_t Encoding, const MCSubtargetInfo &STI) {
+ return getNameFromOperandTable(Operands, Encoding, STI);
+}
} // namespace Hwreg
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h
index 054e35e90f2fa..069134a7ae7f6 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h
@@ -25,10 +25,10 @@ const int OPR_ID_UNSUPPORTED = -2;
const int OPR_ID_DUPLICATE = -3;
const int OPR_VAL_INVALID = -4;
-template <class T> struct CustomOperand {
+struct CustomOperand {
StringLiteral Name;
- int Encoding = 0;
- bool (*Cond)(T Context) = nullptr;
+ unsigned Encoding = 0;
+ bool (*Cond)(const MCSubtargetInfo &STI) = nullptr;
};
struct CustomOperandVal {
@@ -60,20 +60,34 @@ extern const int DEP_CTR_SIZE;
} // namespace DepCtr
-namespace SendMsg { // Symbolic names for the sendmsg(...) syntax.
+// Symbolic names for the sendmsg(msg_id, operation, stream) syntax.
+namespace SendMsg {
+
+/// Map from a symbolic name for a msg_id to the message portion of the
+/// immediate encoding. A negative return value indicates that the Name was
+/// unknown or unsupported on this target.
+int64_t getMsgId(StringRef Name, const MCSubtargetInfo &STI);
+
+/// Map from an encoding to the symbolic name for a msg_id immediate. This is
+/// doing opposite of getMsgId().
+StringRef getMsgName(uint64_t Encoding, const MCSubtargetInfo &STI);
-extern const CustomOperand<const MCSubtargetInfo &> Msg[];
-extern const int MSG_SIZE;
+/// Map from a symbolic name for a sendmsg operation to the operation portion of
+/// the immediate encoding. A negative return value indicates that the Name was
+/// unknown or unsupported on this target.
+int64_t getMsgOpId(int64_t MsgId, StringRef Name, const MCSubtargetInfo &STI);
-extern const char *const OpSysSymbolic[OP_SYS_LAST_];
-extern const char *const OpGsSymbolic[OP_GS_LAST_];
+/// Map from an encoding to the symbolic name for a sendmsg operation. This is
+/// doing opposite of getMsgOpId().
+StringRef getMsgOpName(int64_t MsgId, uint64_t Encoding,
+ const MCSubtargetInfo &STI);
} // namespace SendMsg
namespace Hwreg { // Symbolic names for the hwreg(...) syntax.
-extern const CustomOperand<const MCSubtargetInfo &> Opr[];
-extern const int OPR_SIZE;
+int64_t getHwregId(StringRef Name, const MCSubtargetInfo &STI);
+StringRef getHwreg(uint64_t Encoding, const MCSubtargetInfo &STI);
} // namespace Hwreg
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
index 4e0074451aa58..2fae7a31d70bf 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
@@ -1495,62 +1495,6 @@ unsigned encodeStorecntDscnt(const IsaVersion &Version,
return encodeStorecntDscnt(Version, Decoded.StoreCnt, Decoded.DsCnt);
}
-//===----------------------------------------------------------------------===//
-// Custom Operands.
-//
-// A table of custom operands shall describe "primary" operand names
-// first followed by aliases if any. It is not required but recommended
-// to arrange operands so that operand encoding match operand position
-// in the table. This will make disassembly a bit more efficient.
-// Unused slots in the table shall have an empty name.
-//
-//===----------------------------------------------------------------------===//
-
-template <class T>
-static bool isValidOpr(int Idx, const CustomOperand<T> OpInfo[], int OpInfoSize,
- T Context) {
- return 0 <= Idx && Idx < OpInfoSize && !OpInfo[Idx].Name.empty() &&
- (!OpInfo[Idx].Cond || OpInfo[Idx].Cond(Context));
-}
-
-template <class T>
-static int getOprIdx(std::function<bool(const CustomOperand<T> &)> Test,
- const CustomOperand<T> OpInfo[], int OpInfoSize,
- T Context) {
- int InvalidIdx = OPR_ID_UNKNOWN;
- for (int Idx = 0; Idx < OpInfoSize; ++Idx) {
- if (Test(OpInfo[Idx])) {
- if (!OpInfo[Idx].Cond || OpInfo[Idx].Cond(Context))
- return Idx;
- InvalidIdx = OPR_ID_UNSUPPORTED;
- }
- }
- return InvalidIdx;
-}
-
-template <class T>
-static int getOprIdx(const StringRef Name, const CustomOperand<T> OpInfo[],
- int OpInfoSize, T Context) {
- auto Test = [=](const CustomOperand<T> &Op) { return Op.Name == Name; };
- return getOprIdx<T>(Test, OpInfo, OpInfoSize, Context);
-}
-
-template <class T>
-static int getOprIdx(int Id, const CustomOperand<T> OpInfo[], int OpInfoSize,
- T Context, bool QuickCheck = true) {
- auto Test = [=](const CustomOperand<T> &Op) {
- return Op.Encoding == Id && !Op.Name.empty();
- };
- // This is an optimization that should work in most cases.
- // As a side effect, it may cause selection of an alias
- // instead of a primary operand name in case of sparse tables.
- if (QuickCheck && isValidOpr<T>(Id, OpInfo, OpInfoSize, Context) &&
- OpInfo[Id].Encoding == Id) {
- return Id;
- }
- return getOprIdx<T>(Test, OpInfo, OpInfoSize, Context);
-}
-
//===----------------------------------------------------------------------===//
// Custom Operand Values
//===----------------------------------------------------------------------===//
@@ -1701,24 +1645,6 @@ unsigned encodeFieldSaSdst(unsigned SaSdst) {
} // namespace DepCtr
-//===----------------------------------------------------------------------===//
-// hwreg
-//===----------------------------------------------------------------------===//
-
-namespace Hwreg {
-
-int64_t getHwregId(const StringRef Name, const MCSubtargetInfo &STI) {
- int Idx = getOprIdx<const MCSubtargetInfo &>(Name, Opr, OPR_SIZE, STI);
- return (Idx < 0) ? Idx : Opr[Idx].Encoding;
-}
-
-StringRef getHwreg(unsigned Id, const MCSubtargetInfo &STI) {
- int Idx = getOprIdx<const MCSubtargetInfo &>(Id, Opr, OPR_SIZE, STI);
- return (Idx < 0) ? "" : Opr[Idx].Name;
-}
-
-} // namespace Hwreg
-
//===----------------------------------------------------------------------===//
// exp tgt
//===----------------------------------------------------------------------===//
@@ -1919,32 +1845,10 @@ static uint64_t getMsgIdMask(const MCSubtargetInfo &STI) {
return isGFX11Plus(STI) ? ID_MASK_GFX11Plus_ : ID_MASK_PreGFX11_;
}
-int64_t getMsgId(const StringRef Name, const MCSubtargetInfo &STI) {
- int Idx = getOprIdx<const MCSubtargetInfo &>(Name, Msg, MSG_SIZE, STI);
- return (Idx < 0) ? Idx : Msg[Idx].Encoding;
-}
-
bool isValidMsgId(int64_t MsgId, const MCSubtargetInfo &STI) {
return (MsgId & ~(getMsgIdMask(STI))) == 0;
}
-StringRef getMsgName(int64_t MsgId, const MCSubtargetInfo &STI) {
- int Idx = getOprIdx<const MCSubtargetInfo &>(MsgId, Msg, MSG_SIZE, STI);
- return (Idx < 0) ? "" : Msg[Idx].Name;
-}
-
-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, const MCSubtargetInfo &STI,
bool Strict) {
assert(isValidMsgId(MsgId, STI));
@@ -1952,23 +1856,14 @@ bool isValidMsgOp(int64_t MsgId, int64_t OpId, const MCSubtargetInfo &STI,
if (!Strict)
return 0 <= OpId && isUInt<OP_WIDTH_>(OpId);
- if (MsgId == ID_SYSMSG)
- return OP_SYS_FIRST_ <= OpId && OpId < OP_SYS_LAST_;
- if (!isGFX11Plus(STI)) {
- switch (MsgId) {
- case ID_GS_PreGFX11:
- return (OP_GS_FIRST_ <= OpId && OpId < OP_GS_LAST_) && OpId != OP_GS_NOP;
- case ID_GS_DONE_PreGFX11:
- return OP_GS_FIRST_ <= OpId && OpId < OP_GS_LAST_;
- }
+ if (msgRequiresOp(MsgId, STI)) {
+ if (MsgId == ID_GS_PreGFX11 && OpId == OP_GS_NOP)
+ return false;
+
+ return !getMsgOpName(MsgId, OpId, STI).empty();
}
- return OpId == OP_NONE_;
-}
-StringRef getMsgOpName(int64_t MsgId, int64_t OpId,
- const MCSubtargetInfo &STI) {
- assert(msgRequiresOp(MsgId, STI));
- return (MsgId == ID_SYSMSG)? OpSysSymbolic[OpId] : OpGsSymbolic[OpId];
+ return OpId == OP_NONE_;
}
bool isValidMsgStream(int64_t MsgId, int64_t OpId, int64_t StreamId,
@@ -2186,6 +2081,8 @@ bool isGFX9Plus(const MCSubtargetInfo &STI) {
return isGFX9(STI) || isGFX10Plus(STI);
}
+bool isNotGFX9Plus(const MCSubtargetInfo &STI) { return !isGFX9Plus(STI); }
+
bool isGFX10(const MCSubtargetInfo &STI) {
return STI.hasFeature(AMDGPU::FeatureGFX10);
}
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
index 943588fe701cc..12d1b3a55cccb 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
@@ -1078,12 +1078,6 @@ struct HwregSize : EncodingField<15, 11, 32> {
using HwregEncoding = EncodingFields<HwregId, HwregOffset, HwregSize>;
-LLVM_READONLY
-int64_t getHwregId(const StringRef Name, const MCSubtargetInfo &STI);
-
-LLVM_READNONE
-StringRef getHwreg(unsigned Id, const MCSubtargetInfo &STI);
-
} // namespace Hwreg
namespace DepCtr {
@@ -1173,18 +1167,6 @@ unsigned getDefaultFormatEncoding(const MCSubtargetInfo &STI);
namespace SendMsg {
-LLVM_READONLY
-int64_t getMsgId(const StringRef Name, const MCSubtargetInfo &STI);
-
-LLVM_READONLY
-int64_t getMsgOpId(int64_t MsgId, const StringRef Name);
-
-LLVM_READNONE
-StringRef getMsgName(int64_t MsgId, const MCSubtargetInfo &STI);
-
-LLVM_READNONE
-StringRef getMsgOpName(int64_t MsgId, int64_t OpId, const MCSubtargetInfo &STI);
-
LLVM_READNONE
bool isValidMsgId(int64_t MsgId, const MCSubtargetInfo &STI);
@@ -1276,6 +1258,7 @@ bool isGFX9_GFX10_GFX11(const MCSubtargetInfo &STI);
bool isGFX8_GFX9_GFX10(const MCSubtargetInfo &STI);
bool isGFX8Plus(const MCSubtargetInfo &STI);
bool isGFX9Plus(const MCSubtargetInfo &STI);
+bool isNotGFX9Plus(const MCSubtargetInfo &STI);
bool isGFX10(const MCSubtargetInfo &STI);
bool isGFX10_GFX11(const MCSubtargetInfo &STI);
bool isGFX10Plus(const MCSubtargetInfo &STI);
diff --git a/llvm/test/MC/AMDGPU/gfx9-asm-err.s b/llvm/test/MC/AMDGPU/gfx9-asm-err.s
index 93138a8291850..31e0d953b5bd8 100644
--- a/llvm/test/MC/AMDGPU/gfx9-asm-err.s
+++ b/llvm/test/MC/AMDGPU/gfx9-asm-err.s
@@ -41,3 +41,6 @@ global_load_dword v[2:3], off
scratch_load_dword v2, off, offset:256
// GFX9ERR: :[[@LINE-1]]:{{[0-9]+}}: error: too few operands for instruction
+
+s_sendmsg sendmsg(MSG_SYSMSG, SYSMSG_OP_HOST_TRAP_ACK)
+// GFX9ERR: :[[@LINE-1]]:{{[0-9]+}}: error: specified operation id is not supported on this GPU
diff --git a/llvm/test/MC/AMDGPU/sopp-err.s b/llvm/test/MC/AMDGPU/sopp-err.s
index bd044cb743402..8b7ff74b21051 100644
--- a/llvm/test/MC/AMDGPU/sopp-err.s
+++ b/llvm/test/MC/AMDGPU/sopp-err.s
@@ -199,6 +199,10 @@ s_sendmsg sendmsg(MSG_SYSMSG, 0)
s_sendmsg sendmsg(MSG_SYSMSG, 5)
// GCN: :[[@LINE-1]]:{{[0-9]+}}: error: invalid operation id
+s_sendmsg sendmsg(MSG_SYSMSG, SYSMSG_OP_HOST_TRAP_ACK)
+// GFX10: :[[@LINE-1]]:{{[0-9]+}}: error: specified operation id is not supported on this GPU
+// GFX11PLUS: :[[@LINE-2]]:{{[0-9]+}}: error: specified operation id is not supported on this GPU
+
//===----------------------------------------------------------------------===//
// waitcnt
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/MC/AMDGPU/sopp-gfx9.s b/llvm/test/MC/AMDGPU/sopp-gfx9.s
index e760d497896fa..2ba6d0043f35e 100644
--- a/llvm/test/MC/AMDGPU/sopp-gfx9.s
+++ b/llvm/test/MC/AMDGPU/sopp-gfx9.s
@@ -109,3 +109,6 @@ s_sendmsg 10
s_sendmsg sendmsg(MSG_GET_DOORBELL)
// GFX9: s_sendmsg sendmsg(MSG_GET_DOORBELL) ; encoding: [0x0a,0x00,0x90,0xbf]
+
+s_sendmsg sendmsg(15, 3, 0)
+// GFX9: s_sendmsg sendmsg(15, 3, 0) ; encoding: [0x3f,0x00,0x90,0xbf]
More information about the llvm-commits
mailing list