Index: lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp =================================================================== --- lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -82,6 +82,23 @@ }; } // namespace SendMsg + +namespace Hwreg { + +// This must be in sync with llvm::AMDGPU::Hwreg::ID_SYMBOLIC_FIRST_/LAST_. +static +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 @@ -654,16 +671,16 @@ 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: struct OperandInfoTy { int64_t Id; bool IsSymbolic; OperandInfoTy(int64_t Id_) : Id(Id_), IsSymbolic(false) { } }; + bool parseHwregOperand(OperandInfoTy &HwReg, int64_t &Offset, int64_t &Width); bool parseSendMsg(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId); public: + OperandMatchResultTy parseHwreg(OperandVector &Operands); OperandMatchResultTy parseSendMsgOp(OperandVector &Operands); OperandMatchResultTy parseSOppBrTarget(OperandVector &Operands); AMDGPUOperand::Ptr defaultHwreg() const; @@ -1761,7 +1778,9 @@ return MatchOperand_Success; } -bool AMDGPUAsmParser::parseHwregOperand(int64_t &HwRegCode, int64_t &Offset, int64_t &Width, bool &IsIdentifier) { +bool AMDGPUAsmParser::parseHwregOperand(OperandInfoTy &HwReg, int64_t &Offset, int64_t &Width) { + using namespace llvm::AMDGPU::Hwreg; + if (Parser.getTok().getString() != "hwreg") return true; Parser.Lex(); @@ -1771,22 +1790,21 @@ Parser.Lex(); if (getLexer().is(AsmToken::Identifier)) { - IsIdentifier = true; - HwRegCode = StringSwitch(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; } @@ -1823,6 +1841,8 @@ AMDGPUAsmParser::OperandMatchResultTy AMDGPUAsmParser::parseHwreg(OperandVector &Operands) { + using namespace llvm::AMDGPU::Hwreg; + int64_t Imm16Val = 0; SMLoc S = Parser.getTok().getLoc(); @@ -1831,7 +1851,7 @@ case AsmToken::Integer: // The operand can be an integer value. if (getParser().parseAbsoluteExpression(Imm16Val)) - return MatchOperand_ParseFail; + return MatchOperand_NoMatch; if (!isInt<16>(Imm16Val) && !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 @@ -1840,26 +1860,22 @@ 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_DEFAULT_; + if (parseHwregOperand(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 & ~(ID_MASK_ >> ID_SHIFT_)) != 0) { + 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 & ~(OFFSET_MASK_ >> OFFSET_SHIFT_)) != 0) Error(S, "invalid bit offset: only 5-bit values are legal"); - if (Width < 1 || Width > 32) + if (((Width-1) & ~(WIDTH_MINUS_ONE_MASK_ >> WIDTH_MINUS_ONE_SHIFT_)) != 0) 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_MINUS_ONE_SHIFT_); } break; } @@ -1936,7 +1952,7 @@ 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; @@ -1998,9 +2014,9 @@ case AsmToken::Identifier: { OperandInfoTy Msg(ID_UNKNOWN_); OperandInfoTy Operation(OP_UNKNOWN_); - int64_t StreamId = STREAM_ID_DEFAULT; + int64_t StreamId = STREAM_ID_DEFAULT_; if (parseSendMsg(Msg, Operation, StreamId)) - return MatchOperand_NoMatch; + return MatchOperand_ParseFail; do { // Validate and encode message ID. if (! ((ID_INTERRUPT <= Msg.Id && Msg.Id <= ID_GS_DONE) @@ -2011,7 +2027,7 @@ 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_)) { Index: lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp =================================================================== --- lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp +++ lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp @@ -65,6 +65,23 @@ }; } // namespace SendMsg + +namespace Hwreg { + +// This must be in sync with llvm::AMDGPU::Hwreg::ID_SYMBOLIC_FIRST_/LAST_. +static +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 @@ -886,23 +903,20 @@ 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_MINUS_ONE_MASK_) >> WIDTH_MINUS_ONE_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 (! (Width == 32 && Offset == 0)) { + if (ID_SYMBOLIC_FIRST_ <= Id && Id < ID_SYMBOLIC_LAST_) { + O << IdSymbolic[Id]; + } else { + O << Id; + } + if (Width != WIDTH_DEFAULT_ || Offset != OFFSET_DEFAULT_) { O << ", " << Offset << ", " << Width; } O << ')'; Index: lib/Target/AMDGPU/SIDefines.h =================================================================== --- lib/Target/AMDGPU/SIDefines.h +++ lib/Target/AMDGPU/SIDefines.h @@ -107,11 +107,13 @@ ID_SYSMSG = 15, ID_GAPS_LAST_, // Indicate that sequence has gaps. ID_GAPS_FIRST_ = ID_INTERRUPT, - ID_MASK_ = 0xf + ID_SHIFT_ = 0, + ID_MASK_ = (0xf << 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, @@ -119,7 +121,7 @@ OP_GS_EMIT_CUT, OP_GS_LAST_, OP_GS_FIRST_ = OP_GS_NOP, - OP_GS_MASK_ = (0x3 << 4), + OP_GS_MASK_ = (0x3 << OP_SHIFT_), // width(3) [6:4] OP_SYS_ECC_ERR_INTERRUPT = 1, OP_SYS_REG_RD, @@ -127,19 +129,42 @@ 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_MASK_ = (0x7 << 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_MASK_ = (0x3 << 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_MASK_ = (0x3f << ID_SHIFT_) +}; + +enum Offset { // Offset, (5) [10:6] + OFFSET_DEFAULT_ = 0, + OFFSET_SHIFT_ = 6, + OFFSET_MASK_ = (0x1f << OFFSET_SHIFT_) +}; + +enum Width { // WidthMinusOne, (5) [15:11] + WIDTH_DEFAULT_ = 32, + WIDTH_MINUS_ONE_SHIFT_ = 11, + WIDTH_MINUS_ONE_MASK_ = (0x1f << WIDTH_MINUS_ONE_SHIFT_) +}; + +} // namespace Hwreg } // namespace AMDGPU } // namespace llvm Index: test/MC/AMDGPU/sopp-err.s =================================================================== --- test/MC/AMDGPU/sopp-err.s +++ test/MC/AMDGPU/sopp-err.s @@ -9,16 +9,16 @@ // 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 @@ // 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 @@ // 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 @@ // 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