Index: lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp =================================================================== --- lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -79,6 +79,7 @@ ImmTyDA, ImmTyR128, ImmTyLWE, + ImmTyHwreg, }; struct TokOp { @@ -406,6 +407,7 @@ bool isDSOffset() const; bool isDSOffset01() const; bool isSWaitCnt() const; + bool isHwreg() const; bool isMubufOffset() const; bool isSMRDOffset() const; bool isSMRDLiteralOffset() const; @@ -530,6 +532,8 @@ bool parseCnt(int64_t &IntVal); OperandMatchResultTy parseSWaitCntOps(OperandVector &Operands); + bool parseHwreg(int64_t &HwRegCode, int64_t &Offset, int64_t &Width); + OperandMatchResultTy parseHwregOp(OperandVector &Operands); OperandMatchResultTy parseSOppBrTarget(OperandVector &Operands); OperandMatchResultTy parseFlatOptionalOps(OperandVector &Operands); @@ -1570,10 +1574,100 @@ return MatchOperand_Success; } +bool AMDGPUAsmParser::parseHwreg(int64_t &HwRegCode, int64_t &Offset, int64_t &Width) { + if (Parser.getTok().getString() != "hwreg") + return true; + Parser.Lex(); + + if (getLexer().isNot(AsmToken::LParen)) + return true; + Parser.Lex(); + + if (getLexer().isNot(AsmToken::Integer)) + return true; + if (getParser().parseAbsoluteExpression(HwRegCode)) + return true; + + if (getLexer().is(AsmToken::RParen)) { + Parser.Lex(); + return false; + } + + // optional params + if (getLexer().isNot(AsmToken::Comma)) + return true; + Parser.Lex(); + + if (getLexer().isNot(AsmToken::Integer)) + return true; + if (getParser().parseAbsoluteExpression(Offset)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return true; + Parser.Lex(); + + if (getLexer().isNot(AsmToken::Integer)) + return true; + if (getParser().parseAbsoluteExpression(Width)) + return true; + + if (getLexer().isNot(AsmToken::RParen)) + return true; + Parser.Lex(); + + return false; +} + +AMDGPUAsmParser::OperandMatchResultTy +AMDGPUAsmParser::parseHwregOp(OperandVector &Operands) { + int64_t Imm16Val = 0; + SMLoc S = Parser.getTok().getLoc(); + + switch(getLexer().getKind()) { + default: return MatchOperand_ParseFail; + case AsmToken::Integer: + // The operand can be an integer value. + if (getParser().parseAbsoluteExpression(Imm16Val)) + return MatchOperand_ParseFail; + 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 + // to the next operand, if any. That avoids unneccessary error messages. + } + break; + + case AsmToken::Identifier: { + int64_t HwRegCode = 0; + int64_t Offset = 0; // default + int64_t Width = 32; // default + if (parseHwreg(HwRegCode, Offset, Width)) + return MatchOperand_ParseFail; + // HwRegCode (6) [5:0] + // Offset (5) [10:6] + // WidthMinusOne (5) [15:11] + if (HwRegCode < 0 || HwRegCode > 63) + Error(S, "invalid code of hardware register: only 6-bit values are legal"); + if (Offset < 0 || Offset > 31) + Error(S, "invalid bit offset: only 5-bit values are legal"); + if (Width < 1 || Width > 32) + Error(S, "invalid bitfield width: only values from 1 to 32 are legal"); + Imm16Val = HwRegCode | (Offset << 6) | ((Width-1) << 11); + } + break; + } + Operands.push_back(AMDGPUOperand::CreateImm(Imm16Val, S, AMDGPUOperand::ImmTyHwreg)); + return MatchOperand_Success; +} + bool AMDGPUOperand::isSWaitCnt() const { return isImm(); } +bool AMDGPUOperand::isHwreg() const { + return isImmTy(ImmTyHwreg); +} + //===----------------------------------------------------------------------===// // sopp branch targets //===----------------------------------------------------------------------===// Index: lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h =================================================================== --- lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h +++ lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h @@ -91,6 +91,7 @@ static void printKCache(const MCInst *MI, unsigned OpNo, raw_ostream &O); static void printSendMsg(const MCInst *MI, unsigned OpNo, raw_ostream &O); static void printWaitFlag(const MCInst *MI, unsigned OpNo, raw_ostream &O); + static void printHwreg(const MCInst *MI, unsigned OpNo, raw_ostream &O); }; } // End namespace llvm Index: lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp =================================================================== --- lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp +++ lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp @@ -760,4 +760,18 @@ } } +void AMDGPUInstPrinter::printHwreg(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + unsigned SImm16 = MI->getOperand(OpNo).getImm(); + const unsigned HwRegCode = SImm16 & 0x3F; + const unsigned Offset = (SImm16 >> 6) & 0x1f; + const unsigned Width = ((SImm16 >> 11) & 0x1F) + 1; + + if (Width == 32 && Offset == 0) { + O << "hwreg(" << HwRegCode << ')'; + } else { + O << "hwreg(" << HwRegCode << ", " << Offset << ", " << Width << ')'; + } +} + #include "AMDGPUGenAsmWriter.inc" Index: lib/Target/AMDGPU/SIInstrInfo.td =================================================================== --- lib/Target/AMDGPU/SIInstrInfo.td +++ lib/Target/AMDGPU/SIInstrInfo.td @@ -603,6 +603,13 @@ let PrintMethod = "print"#BitName; } +def HwregMatchClass : AsmOperandClass { + let Name = "Hwreg"; + let PredicateMethod = "isHwreg"; + let ParserMethod = "parseHwregOp"; + let RenderMethod = "addImmOperands"; +} + let OperandType = "OPERAND_IMMEDIATE" in { def offen : Operand { @@ -730,6 +737,11 @@ let ParserMatchClass = DPPOptionalMatchClass<"BoundCtrl">; } +def hwreg : Operand { + let PrintMethod = "printHwreg"; + let ParserMatchClass = HwregMatchClass; +} + } // End OperandType = "OPERAND_IMMEDIATE" Index: lib/Target/AMDGPU/SIInstructions.td =================================================================== --- lib/Target/AMDGPU/SIInstructions.td +++ lib/Target/AMDGPU/SIInstructions.td @@ -418,18 +418,21 @@ >; let mayLoad = 1 in { -defm S_GETREG_B32 : SOPK_32 , "s_getreg_b32", []>; +defm S_GETREG_B32 : SOPK_m < + sopk<0x12, 0x11>, "s_getreg_b32", (outs SReg_32:$sdst), + (ins hwreg:$simm16), " $sdst, $simm16" +>; } defm S_SETREG_B32 : SOPK_m < sopk<0x13, 0x12>, "s_setreg_b32", (outs), - (ins SReg_32:$sdst, u16imm:$simm16), " $simm16, $sdst" + (ins SReg_32:$sdst, hwreg:$simm16), " $simm16, $sdst" >; // FIXME: Not on SI? //defm S_GETREG_REGRD_B32 : SOPK_32 , "s_getreg_regrd_b32", []>; defm S_SETREG_IMM32_B32 : SOPK_IMM32 < sopk<0x15, 0x14>, "s_setreg_imm32_b32", (outs), - (ins i32imm:$imm, u16imm:$simm16), " $simm16, $imm" + (ins i32imm:$imm, hwreg:$simm16), " $simm16, $imm" >; //===----------------------------------------------------------------------===// Index: test/MC/AMDGPU/sopk-err.s =================================================================== --- /dev/null +++ test/MC/AMDGPU/sopk-err.s @@ -0,0 +1,24 @@ +// RUN: not llvm-mc -arch=amdgcn %s 2>&1 | FileCheck -check-prefix=GCN %s +// RUN: not llvm-mc -arch=amdgcn -mcpu=tahiti %s 2>&1 | FileCheck -check-prefix=GCN -check-prefix=SI %s +// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga %s 2>&1 | FileCheck -check-prefix=GCN -check-prefix=VI %s + +s_setreg_b32 0x1f803, s2 +// GCN: error: invalid immediate: only 16-bit values are legal + +s_setreg_b32 hwreg(0x40), s2 +// GCN: error: invalid code of hardware register: only 6-bit values are legal + +s_setreg_b32 hwreg(3,32,32), s2 +// GCN: error: invalid bit offset: only 5-bit values are legal + +s_setreg_b32 hwreg(3,0,33), s2 +// GCN: error: invalid bitfield width: only values from 1 to 32 are legal + +s_setreg_imm32_b32 0x1f803, 0xff +// GCN: error: invalid immediate: only 16-bit values are legal + +s_setreg_imm32_b32 hwreg(3,0,33), 0xff +// GCN: error: invalid bitfield width: only values from 1 to 32 are legal + +s_getreg_b32 s2, hwreg(3,32,32) +// GCN: error: invalid bit offset: only 5-bit values are legal Index: test/MC/AMDGPU/sopk.s =================================================================== --- test/MC/AMDGPU/sopk.s +++ test/MC/AMDGPU/sopk.s @@ -74,13 +74,33 @@ // VI: s_cbranch_i_fork s[2:3], 0x6 ; encoding: [0x06,0x00,0x02,0xb8] s_getreg_b32 s2, 0x6 -// SICI: s_getreg_b32 s2, 0x6 ; encoding: [0x06,0x00,0x02,0xb9] -// VI: s_getreg_b32 s2, 0x6 ; encoding: [0x06,0x00,0x82,0xb8] +// SICI: s_getreg_b32 s2, hwreg(6, 0, 1) ; encoding: [0x06,0x00,0x02,0xb9] +// VI: s_getreg_b32 s2, hwreg(6, 0, 1) ; encoding: [0x06,0x00,0x82,0xb8] + +s_getreg_b32 s2, hwreg(5, 1, 31) +// SICI: s_getreg_b32 s2, hwreg(5, 1, 31) ; encoding: [0x45,0xf0,0x02,0xb9] +// VI: s_getreg_b32 s2, hwreg(5, 1, 31) ; encoding: [0x45,0xf0,0x82,0xb8] s_setreg_b32 0x6, s2 -// SICI: s_setreg_b32 0x6, s2 ; encoding: [0x06,0x00,0x82,0xb9] -// VI: s_setreg_b32 0x6, s2 ; encoding: [0x06,0x00,0x02,0xb9] +// SICI: s_setreg_b32 hwreg(6, 0, 1), s2 ; encoding: [0x06,0x00,0x82,0xb9] +// VI: s_setreg_b32 hwreg(6, 0, 1), s2 ; encoding: [0x06,0x00,0x02,0xb9] + +s_setreg_b32 0xf803, s2 +// SICI: s_setreg_b32 hwreg(3), s2 ; encoding: [0x03,0xf8,0x82,0xb9] +// VI: s_setreg_b32 hwreg(3), s2 ; encoding: [0x03,0xf8,0x02,0xb9] + +s_setreg_b32 hwreg(4), s2 +// SICI: s_setreg_b32 hwreg(4), s2 ; encoding: [0x04,0xf8,0x82,0xb9] +// VI: s_setreg_b32 hwreg(4), s2 ; encoding: [0x04,0xf8,0x02,0xb9] + +s_setreg_b32 hwreg(5, 1, 31), s2 +// SICI: s_setreg_b32 hwreg(5, 1, 31), s2 ; encoding: [0x45,0xf0,0x82,0xb9] +// VI: s_setreg_b32 hwreg(5, 1, 31), s2 ; encoding: [0x45,0xf0,0x02,0xb9] s_setreg_imm32_b32 0x6, 0xff -// SICI: s_setreg_imm32_b32 0x6, 0xff ; encoding: [0x06,0x00,0x80,0xba,0xff,0x00,0x00,0x00] -// VI: s_setreg_imm32_b32 0x6, 0xff ; encoding: [0x06,0x00,0x00,0xba,0xff,0x00,0x00,0x00] +// SICI: s_setreg_imm32_b32 hwreg(6, 0, 1), 0xff ; encoding: [0x06,0x00,0x80,0xba,0xff,0x00,0x00,0x00] +// VI: s_setreg_imm32_b32 hwreg(6, 0, 1), 0xff ; encoding: [0x06,0x00,0x00,0xba,0xff,0x00,0x00,0x00] + +s_setreg_imm32_b32 hwreg(5, 1, 31), 0xff +// SICI: s_setreg_imm32_b32 hwreg(5, 1, 31), 0xff ; encoding: [0x45,0xf0,0x80,0xba,0xff,0x00,0x00,0x00] +// VI: s_setreg_imm32_b32 hwreg(5, 1, 31), 0xff ; encoding: [0x45,0xf0,0x00,0xba,0xff,0x00,0x00,0x00] Index: test/MC/Disassembler/AMDGPU/sopk_vi.txt =================================================================== --- test/MC/Disassembler/AMDGPU/sopk_vi.txt +++ test/MC/Disassembler/AMDGPU/sopk_vi.txt @@ -48,11 +48,11 @@ # VI: s_cbranch_i_fork s[2:3], 0x6 ; encoding: [0x06,0x00,0x02,0xb8] 0x06 0x00 0x02 0xb8 -# VI: s_getreg_b32 s2, 0x6 ; encoding: [0x06,0x00,0x82,0xb8] -0x06 0x00 0x82 0xb8 +# VI: s_getreg_b32 s2, hwreg(6) ; encoding: [0x06,0xf8,0x82,0xb8] +0x06 0xf8 0x82 0xb8 -# VI: s_setreg_b32 0x6, s2 ; encoding: [0x06,0x00,0x02,0xb9] +# VI: s_setreg_b32 hwreg(6, 0, 1), s2 ; encoding: [0x06,0x00,0x02,0xb9] 0x06 0x00 0x02 0xb9 -# VI: s_setreg_imm32_b32 0x6, 0xff ; encoding: [0x06,0x00,0x00,0xba,0xff,0x00,0x00,0x00] -0x06 0x00 0x00 0xba 0xff 0x00 0x00 0x00 +# VI: s_setreg_imm32_b32 hwreg(5, 1, 31), 0xff ; encoding: [0x45,0xf0,0x00,0xba,0xff,0x00,0x00,0x00] +0x45 0xf0 0x00 0xba 0xff 0x00 0x00 0x00