Skip to content

Commit 680c780

Browse files
authored
[AMDGPU][AsmParser] Support structured HWREG operands. (#82805)
Symbolic values are to be supported separately.
1 parent c89d511 commit 680c780

File tree

10 files changed

+343
-149
lines changed

10 files changed

+343
-149
lines changed

llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp

Lines changed: 135 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,24 +1685,48 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
16851685
private:
16861686
struct OperandInfoTy {
16871687
SMLoc Loc;
1688-
int64_t Id;
1688+
int64_t Val;
16891689
bool IsSymbolic = false;
16901690
bool IsDefined = false;
16911691

1692-
OperandInfoTy(int64_t Id_) : Id(Id_) {}
1692+
OperandInfoTy(int64_t Val) : Val(Val) {}
16931693
};
16941694

1695+
struct StructuredOpField : OperandInfoTy {
1696+
StringLiteral Id;
1697+
StringLiteral Desc;
1698+
unsigned Width;
1699+
bool IsDefined = false;
1700+
1701+
StructuredOpField(StringLiteral Id, StringLiteral Desc, unsigned Width,
1702+
int64_t Default)
1703+
: OperandInfoTy(Default), Id(Id), Desc(Desc), Width(Width) {}
1704+
virtual ~StructuredOpField() = default;
1705+
1706+
bool Error(AMDGPUAsmParser &Parser, const Twine &Err) const {
1707+
Parser.Error(Loc, "invalid " + Desc + ": " + Err);
1708+
return false;
1709+
}
1710+
1711+
virtual bool validate(AMDGPUAsmParser &Parser) const {
1712+
if (IsSymbolic && Val == OPR_ID_UNSUPPORTED)
1713+
return Error(Parser, "not supported on this GPU");
1714+
if (!isUIntN(Width, Val))
1715+
return Error(Parser, "only " + Twine(Width) + "-bit values are legal");
1716+
return true;
1717+
}
1718+
};
1719+
1720+
ParseStatus parseStructuredOpFields(ArrayRef<StructuredOpField *> Fields);
1721+
bool validateStructuredOpFields(ArrayRef<const StructuredOpField *> Fields);
1722+
16951723
bool parseSendMsgBody(OperandInfoTy &Msg, OperandInfoTy &Op, OperandInfoTy &Stream);
16961724
bool validateSendMsg(const OperandInfoTy &Msg,
16971725
const OperandInfoTy &Op,
16981726
const OperandInfoTy &Stream);
16991727

1700-
bool parseHwregBody(OperandInfoTy &HwReg,
1701-
OperandInfoTy &Offset,
1702-
OperandInfoTy &Width);
1703-
bool validateHwreg(const OperandInfoTy &HwReg,
1704-
const OperandInfoTy &Offset,
1705-
const OperandInfoTy &Width);
1728+
ParseStatus parseHwregFunc(OperandInfoTy &HwReg, OperandInfoTy &Offset,
1729+
OperandInfoTy &Width);
17061730

17071731
SMLoc getFlatOffsetLoc(const OperandVector &Operands) const;
17081732
SMLoc getSMEMOffsetLoc(const OperandVector &Operands) const;
@@ -7197,71 +7221,44 @@ bool AMDGPUOperand::isDepCtr() const { return isS16Imm(); }
71977221
// hwreg
71987222
//===----------------------------------------------------------------------===//
71997223

7200-
bool
7201-
AMDGPUAsmParser::parseHwregBody(OperandInfoTy &HwReg,
7202-
OperandInfoTy &Offset,
7203-
OperandInfoTy &Width) {
7224+
ParseStatus AMDGPUAsmParser::parseHwregFunc(OperandInfoTy &HwReg,
7225+
OperandInfoTy &Offset,
7226+
OperandInfoTy &Width) {
72047227
using namespace llvm::AMDGPU::Hwreg;
72057228

7229+
if (!trySkipId("hwreg", AsmToken::LParen))
7230+
return ParseStatus::NoMatch;
7231+
72067232
// The register may be specified by name or using a numeric code
72077233
HwReg.Loc = getLoc();
72087234
if (isToken(AsmToken::Identifier) &&
7209-
(HwReg.Id = getHwregId(getTokenStr(), getSTI())) != OPR_ID_UNKNOWN) {
7235+
(HwReg.Val = getHwregId(getTokenStr(), getSTI())) != OPR_ID_UNKNOWN) {
72107236
HwReg.IsSymbolic = true;
72117237
lex(); // skip register name
7212-
} else if (!parseExpr(HwReg.Id, "a register name")) {
7213-
return false;
7238+
} else if (!parseExpr(HwReg.Val, "a register name")) {
7239+
return ParseStatus::Failure;
72147240
}
72157241

72167242
if (trySkipToken(AsmToken::RParen))
7217-
return true;
7243+
return ParseStatus::Success;
72187244

72197245
// parse optional params
72207246
if (!skipToken(AsmToken::Comma, "expected a comma or a closing parenthesis"))
7221-
return false;
7247+
return ParseStatus::Failure;
72227248

72237249
Offset.Loc = getLoc();
7224-
if (!parseExpr(Offset.Id))
7225-
return false;
7250+
if (!parseExpr(Offset.Val))
7251+
return ParseStatus::Failure;
72267252

72277253
if (!skipToken(AsmToken::Comma, "expected a comma"))
7228-
return false;
7254+
return ParseStatus::Failure;
72297255

72307256
Width.Loc = getLoc();
7231-
return parseExpr(Width.Id) &&
7232-
skipToken(AsmToken::RParen, "expected a closing parenthesis");
7233-
}
7234-
7235-
bool
7236-
AMDGPUAsmParser::validateHwreg(const OperandInfoTy &HwReg,
7237-
const OperandInfoTy &Offset,
7238-
const OperandInfoTy &Width) {
7239-
7240-
using namespace llvm::AMDGPU::Hwreg;
7257+
if (!parseExpr(Width.Val) ||
7258+
!skipToken(AsmToken::RParen, "expected a closing parenthesis"))
7259+
return ParseStatus::Failure;
72417260

7242-
if (HwReg.IsSymbolic) {
7243-
if (HwReg.Id == OPR_ID_UNSUPPORTED) {
7244-
Error(HwReg.Loc,
7245-
"specified hardware register is not supported on this GPU");
7246-
return false;
7247-
}
7248-
} else {
7249-
if (!isValidHwreg(HwReg.Id)) {
7250-
Error(HwReg.Loc,
7251-
"invalid code of hardware register: only 6-bit values are legal");
7252-
return false;
7253-
}
7254-
}
7255-
if (!isValidHwregOffset(Offset.Id)) {
7256-
Error(Offset.Loc, "invalid bit offset: only 5-bit values are legal");
7257-
return false;
7258-
}
7259-
if (!isValidHwregWidth(Width.Id)) {
7260-
Error(Width.Loc,
7261-
"invalid bitfield width: only values from 1 to 32 are legal");
7262-
return false;
7263-
}
7264-
return true;
7261+
return ParseStatus::Success;
72657262
}
72667263

72677264
ParseStatus AMDGPUAsmParser::parseHwreg(OperandVector &Operands) {
@@ -7270,24 +7267,40 @@ ParseStatus AMDGPUAsmParser::parseHwreg(OperandVector &Operands) {
72707267
int64_t ImmVal = 0;
72717268
SMLoc Loc = getLoc();
72727269

7273-
if (trySkipId("hwreg", AsmToken::LParen)) {
7274-
OperandInfoTy HwReg(OPR_ID_UNKNOWN);
7275-
OperandInfoTy Offset(HwregOffset::Default);
7276-
OperandInfoTy Width(HwregSize::Default);
7277-
if (parseHwregBody(HwReg, Offset, Width) &&
7278-
validateHwreg(HwReg, Offset, Width)) {
7279-
ImmVal = HwregEncoding::encode(HwReg.Id, Offset.Id, Width.Id);
7280-
} else {
7281-
return ParseStatus::Failure;
7270+
StructuredOpField HwReg("id", "hardware register", HwregId::Width,
7271+
HwregId::Default);
7272+
StructuredOpField Offset("offset", "bit offset", HwregOffset::Width,
7273+
HwregOffset::Default);
7274+
struct : StructuredOpField {
7275+
using StructuredOpField::StructuredOpField;
7276+
bool validate(AMDGPUAsmParser &Parser) const override {
7277+
if (!isUIntN(Width, Val - 1))
7278+
return Error(Parser, "only values from 1 to 32 are legal");
7279+
return true;
72827280
}
7283-
} else if (parseExpr(ImmVal, "a hwreg macro")) {
7284-
if (ImmVal < 0 || !isUInt<16>(ImmVal))
7285-
return Error(Loc, "invalid immediate: only 16-bit values are legal");
7286-
} else {
7287-
return ParseStatus::Failure;
7281+
} Width("size", "bitfield width", HwregSize::Width, HwregSize::Default);
7282+
ParseStatus Res = parseStructuredOpFields({&HwReg, &Offset, &Width});
7283+
7284+
if (Res.isNoMatch())
7285+
Res = parseHwregFunc(HwReg, Offset, Width);
7286+
7287+
if (Res.isSuccess()) {
7288+
if (!validateStructuredOpFields({&HwReg, &Offset, &Width}))
7289+
return ParseStatus::Failure;
7290+
ImmVal = HwregEncoding::encode(HwReg.Val, Offset.Val, Width.Val);
72887291
}
72897292

7290-
Operands.push_back(AMDGPUOperand::CreateImm(this, ImmVal, Loc, AMDGPUOperand::ImmTyHwreg));
7293+
if (Res.isNoMatch() &&
7294+
parseExpr(ImmVal, "a hwreg macro, structured immediate"))
7295+
Res = ParseStatus::Success;
7296+
7297+
if (!Res.isSuccess())
7298+
return ParseStatus::Failure;
7299+
7300+
if (!isUInt<16>(ImmVal))
7301+
return Error(Loc, "invalid immediate: only 16-bit values are legal");
7302+
Operands.push_back(
7303+
AMDGPUOperand::CreateImm(this, ImmVal, Loc, AMDGPUOperand::ImmTyHwreg));
72917304
return ParseStatus::Success;
72927305
}
72937306

@@ -7307,27 +7320,27 @@ AMDGPUAsmParser::parseSendMsgBody(OperandInfoTy &Msg,
73077320

73087321
Msg.Loc = getLoc();
73097322
if (isToken(AsmToken::Identifier) &&
7310-
(Msg.Id = getMsgId(getTokenStr(), getSTI())) != OPR_ID_UNKNOWN) {
7323+
(Msg.Val = getMsgId(getTokenStr(), getSTI())) != OPR_ID_UNKNOWN) {
73117324
Msg.IsSymbolic = true;
73127325
lex(); // skip message name
7313-
} else if (!parseExpr(Msg.Id, "a message name")) {
7326+
} else if (!parseExpr(Msg.Val, "a message name")) {
73147327
return false;
73157328
}
73167329

73177330
if (trySkipToken(AsmToken::Comma)) {
73187331
Op.IsDefined = true;
73197332
Op.Loc = getLoc();
73207333
if (isToken(AsmToken::Identifier) &&
7321-
(Op.Id = getMsgOpId(Msg.Id, getTokenStr())) >= 0) {
7334+
(Op.Val = getMsgOpId(Msg.Val, getTokenStr())) >= 0) {
73227335
lex(); // skip operation name
7323-
} else if (!parseExpr(Op.Id, "an operation name")) {
7336+
} else if (!parseExpr(Op.Val, "an operation name")) {
73247337
return false;
73257338
}
73267339

73277340
if (trySkipToken(AsmToken::Comma)) {
73287341
Stream.IsDefined = true;
73297342
Stream.Loc = getLoc();
7330-
if (!parseExpr(Stream.Id))
7343+
if (!parseExpr(Stream.Val))
73317344
return false;
73327345
}
73337346
}
@@ -7347,34 +7360,34 @@ AMDGPUAsmParser::validateSendMsg(const OperandInfoTy &Msg,
73477360
bool Strict = Msg.IsSymbolic;
73487361

73497362
if (Strict) {
7350-
if (Msg.Id == OPR_ID_UNSUPPORTED) {
7363+
if (Msg.Val == OPR_ID_UNSUPPORTED) {
73517364
Error(Msg.Loc, "specified message id is not supported on this GPU");
73527365
return false;
73537366
}
73547367
} else {
7355-
if (!isValidMsgId(Msg.Id, getSTI())) {
7368+
if (!isValidMsgId(Msg.Val, getSTI())) {
73567369
Error(Msg.Loc, "invalid message id");
73577370
return false;
73587371
}
73597372
}
7360-
if (Strict && (msgRequiresOp(Msg.Id, getSTI()) != Op.IsDefined)) {
7373+
if (Strict && (msgRequiresOp(Msg.Val, getSTI()) != Op.IsDefined)) {
73617374
if (Op.IsDefined) {
73627375
Error(Op.Loc, "message does not support operations");
73637376
} else {
73647377
Error(Msg.Loc, "missing message operation");
73657378
}
73667379
return false;
73677380
}
7368-
if (!isValidMsgOp(Msg.Id, Op.Id, getSTI(), Strict)) {
7381+
if (!isValidMsgOp(Msg.Val, Op.Val, getSTI(), Strict)) {
73697382
Error(Op.Loc, "invalid operation id");
73707383
return false;
73717384
}
7372-
if (Strict && !msgSupportsStream(Msg.Id, Op.Id, getSTI()) &&
7385+
if (Strict && !msgSupportsStream(Msg.Val, Op.Val, getSTI()) &&
73737386
Stream.IsDefined) {
73747387
Error(Stream.Loc, "message operation does not support streams");
73757388
return false;
73767389
}
7377-
if (!isValidMsgStream(Msg.Id, Op.Id, Stream.Id, getSTI(), Strict)) {
7390+
if (!isValidMsgStream(Msg.Val, Op.Val, Stream.Val, getSTI(), Strict)) {
73787391
Error(Stream.Loc, "invalid message stream id");
73797392
return false;
73807393
}
@@ -7393,7 +7406,7 @@ ParseStatus AMDGPUAsmParser::parseSendMsg(OperandVector &Operands) {
73937406
OperandInfoTy Stream(STREAM_ID_NONE_);
73947407
if (parseSendMsgBody(Msg, Op, Stream) &&
73957408
validateSendMsg(Msg, Op, Stream)) {
7396-
ImmVal = encodeMsg(Msg.Id, Op.Id, Stream.Id);
7409+
ImmVal = encodeMsg(Msg.Val, Op.Val, Stream.Val);
73977410
} else {
73987411
return ParseStatus::Failure;
73997412
}
@@ -7730,6 +7743,48 @@ AMDGPUAsmParser::getConstLoc(const OperandVector &Operands) const {
77307743
return getOperandLoc(Test, Operands);
77317744
}
77327745

7746+
ParseStatus
7747+
AMDGPUAsmParser::parseStructuredOpFields(ArrayRef<StructuredOpField *> Fields) {
7748+
if (!trySkipToken(AsmToken::LCurly))
7749+
return ParseStatus::NoMatch;
7750+
7751+
bool First = true;
7752+
while (!trySkipToken(AsmToken::RCurly)) {
7753+
if (!First &&
7754+
!skipToken(AsmToken::Comma, "comma or closing brace expected"))
7755+
return ParseStatus::Failure;
7756+
7757+
StringRef Id = getTokenStr();
7758+
SMLoc IdLoc = getLoc();
7759+
if (!skipToken(AsmToken::Identifier, "field name expected") ||
7760+
!skipToken(AsmToken::Colon, "colon expected"))
7761+
return ParseStatus::Failure;
7762+
7763+
auto I =
7764+
find_if(Fields, [Id](StructuredOpField *F) { return F->Id == Id; });
7765+
if (I == Fields.end())
7766+
return Error(IdLoc, "unknown field");
7767+
if ((*I)->IsDefined)
7768+
return Error(IdLoc, "duplicate field");
7769+
7770+
// TODO: Support symbolic values.
7771+
(*I)->Loc = getLoc();
7772+
if (!parseExpr((*I)->Val))
7773+
return ParseStatus::Failure;
7774+
(*I)->IsDefined = true;
7775+
7776+
First = false;
7777+
}
7778+
return ParseStatus::Success;
7779+
}
7780+
7781+
bool AMDGPUAsmParser::validateStructuredOpFields(
7782+
ArrayRef<const StructuredOpField *> Fields) {
7783+
return all_of(Fields, [this](const StructuredOpField *F) {
7784+
return F->validate(*this);
7785+
});
7786+
}
7787+
77337788
//===----------------------------------------------------------------------===//
77347789
// swizzle
77357790
//===----------------------------------------------------------------------===//

llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,16 +1700,6 @@ int64_t getHwregId(const StringRef Name, const MCSubtargetInfo &STI) {
17001700
return (Idx < 0) ? Idx : Opr[Idx].Encoding;
17011701
}
17021702

1703-
bool isValidHwreg(int64_t Id) { return 0 <= Id && isUInt<HwregId::Width>(Id); }
1704-
1705-
bool isValidHwregOffset(int64_t Offset) {
1706-
return 0 <= Offset && isUInt<HwregOffset::Width>(Offset);
1707-
}
1708-
1709-
bool isValidHwregWidth(int64_t Width) {
1710-
return 0 <= (Width - 1) && isUInt<HwregSize::Width>(Width - 1);
1711-
}
1712-
17131703
StringRef getHwreg(unsigned Id, const MCSubtargetInfo &STI) {
17141704
int Idx = getOprIdx<const MCSubtargetInfo &>(Id, Opr, OPR_SIZE, STI);
17151705
return (Idx < 0) ? "" : Opr[Idx].Name;

llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,15 +1068,6 @@ using HwregEncoding = EncodingFields<HwregId, HwregOffset, HwregSize>;
10681068
LLVM_READONLY
10691069
int64_t getHwregId(const StringRef Name, const MCSubtargetInfo &STI);
10701070

1071-
LLVM_READNONE
1072-
bool isValidHwreg(int64_t Id);
1073-
1074-
LLVM_READNONE
1075-
bool isValidHwregOffset(int64_t Offset);
1076-
1077-
LLVM_READNONE
1078-
bool isValidHwregWidth(int64_t Width);
1079-
10801071
LLVM_READNONE
10811072
StringRef getHwreg(unsigned Id, const MCSubtargetInfo &STI);
10821073

llvm/test/MC/AMDGPU/gfx1011_err.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ v_dot8c_i32_i4 v5, v1, v2 dpp8:[7,6,5,4,3,2,1,0] fi:1
1717
// GFX10: :[[@LINE-1]]:{{[0-9]+}}: error: instruction not supported on this GPU
1818

1919
s_getreg_b32 s2, hwreg(HW_REG_SHADER_CYCLES)
20-
// GFX10: :[[@LINE-1]]:{{[0-9]+}}: error: specified hardware register is not supported on this GPU
20+
// GFX10: :[[@LINE-1]]:{{[0-9]+}}: error: invalid hardware register: not supported on this GPU
2121

2222
v_fma_legacy_f32 v0, v1, v2, v3
2323
// GFX10: :[[@LINE-1]]:{{[0-9]+}}: error: instruction not supported on this GPU

llvm/test/MC/AMDGPU/gfx1030_err.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ s_get_waveid_in_workgroup s0
2525
// GFX10: :[[@LINE-1]]:{{[0-9]+}}: error: instruction not supported on this GPU
2626

2727
s_getreg_b32 s2, hwreg(HW_REG_XNACK_MASK)
28-
// GFX10: :[[@LINE-1]]:{{[0-9]+}}: error: specified hardware register is not supported on this GPU
28+
// GFX10: :[[@LINE-1]]:{{[0-9]+}}: error: invalid hardware register: not supported on this GPU
2929

3030
v_mac_f32 v0, v1, v2
3131
// GFX10: :[[@LINE-1]]:{{[0-9]+}}: error: instruction not supported on this GPU

0 commit comments

Comments
 (0)