Index: lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp =================================================================== --- lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -135,9 +135,11 @@ ImmTyDA, ImmTyR128, ImmTyLWE, + ImmTyExpTgt, ImmTyExpCompr, ImmTyExpVM, ImmTyHwreg, + ImmTyOff, ImmTySendMsg, }; @@ -215,6 +217,10 @@ return isRegOrImmWithInputMods(MVT::f64); } + bool isVReg32OrOff() const { + return isOff() || isRegClass(AMDGPU::VGPR_32RegClassID); + } + bool isImmTy(ImmTy ImmT) const { return isImm() && Imm.Type == ImmT; } @@ -230,6 +236,8 @@ bool isDA() const { return isImmTy(ImmTyDA); } bool isR128() const { return isImmTy(ImmTyUNorm); } bool isLWE() const { return isImmTy(ImmTyLWE); } + bool isOff() const { return isImmTy(ImmTyOff); } + bool isExpTgt() const { return isImmTy(ImmTyExpTgt); } bool isExpVM() const { return isImmTy(ImmTyExpVM); } bool isExpCompr() const { return isImmTy(ImmTyExpCompr); } bool isOffen() const { return isImmTy(ImmTyOffen); } @@ -460,7 +468,7 @@ } } - void printImmTy(raw_ostream& OS, ImmTy Type) const { + static void printImmTy(raw_ostream& OS, ImmTy Type) { switch (Type) { case ImmTyNone: OS << "None"; break; case ImmTyGDS: OS << "GDS"; break; @@ -488,6 +496,8 @@ case ImmTyDA: OS << "DA"; break; case ImmTyR128: OS << "R128"; break; case ImmTyLWE: OS << "LWE"; break; + case ImmTyOff: OS << "Off"; break; + case ImmTyExpTgt: OS << "ExpTgt"; break; case ImmTyExpCompr: OS << "ExpCompr"; break; case ImmTyExpVM: OS << "ExpVM"; break; case ImmTyHwreg: OS << "Hwreg"; break; @@ -713,9 +723,11 @@ OperandMatchResultTy parseRegOrImm(OperandVector &Operands); OperandMatchResultTy parseRegOrImmWithFPInputMods(OperandVector &Operands); OperandMatchResultTy parseRegOrImmWithIntInputMods(OperandVector &Operands); + OperandMatchResultTy parseVReg32OrOff(OperandVector &Operands); void cvtDSOffset01(MCInst &Inst, const OperandVector &Operands); void cvtDS(MCInst &Inst, const OperandVector &Operands); + void cvtExp(MCInst &Inst, const OperandVector &Operands); bool parseCnt(int64_t &IntVal); OperandMatchResultTy parseSWaitCntOps(OperandVector &Operands); @@ -730,9 +742,14 @@ bool parseSendMsgConstruct(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId); bool parseHwregConstruct(OperandInfoTy &HwReg, int64_t &Offset, int64_t &Width); + + void errorExpTgt(); + OperandMatchResultTy parseExpTgtImpl(StringRef Str, uint8_t &Val); + public: OperandMatchResultTy parseOptionalOperand(OperandVector &Operands); + OperandMatchResultTy parseExpTgt(OperandVector &Operands); OperandMatchResultTy parseSendMsgOp(OperandVector &Operands); OperandMatchResultTy parseSOppBrTarget(OperandVector &Operands); @@ -751,6 +768,7 @@ AMDGPUOperand::Ptr defaultSMRDOffset8() const; AMDGPUOperand::Ptr defaultSMRDOffset20() const; AMDGPUOperand::Ptr defaultSMRDLiteralOffset() const; + AMDGPUOperand::Ptr defaultExpTgt() const; AMDGPUOperand::Ptr defaultExpCompr() const; AMDGPUOperand::Ptr defaultExpVM() const; @@ -1358,9 +1376,28 @@ AMDGPUOperand &Op = static_cast(*Operands.back()); Op.setModifiers(Mods); } + return MatchOperand_Success; } +OperandMatchResultTy AMDGPUAsmParser::parseVReg32OrOff(OperandVector &Operands) { + std::unique_ptr Reg = parseRegister(); + if (Reg) { + Operands.push_back(std::move(Reg)); + return MatchOperand_Success; + } + + const AsmToken &Tok = Parser.getTok(); + if (Tok.getString() == "off") { + Operands.push_back(AMDGPUOperand::CreateImm(this, 0, Tok.getLoc(), + AMDGPUOperand::ImmTyOff, false)); + Parser.Lex(); + return MatchOperand_Success; + } + + return MatchOperand_NoMatch; +} + unsigned AMDGPUAsmParser::checkTargetMatchPredicate(MCInst &Inst) { uint64_t TSFlags = MII.get(Inst.getOpcode()).TSFlags; @@ -2001,6 +2038,46 @@ Inst.addOperand(MCOperand::createReg(AMDGPU::M0)); // m0 } +void AMDGPUAsmParser::cvtExp(MCInst &Inst, const OperandVector &Operands) { + OptionalImmIndexMap OptionalIdx; + + unsigned EnMask = 0; + int SrcIdx = 0; + + for (unsigned i = 1, e = Operands.size(); i != e; ++i) { + AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[i]); + + // Add the register arguments + if (Op.isReg()) { + EnMask |= (1 << SrcIdx); + Op.addRegOperands(Inst, 1); + ++SrcIdx; + continue; + } + + if (Op.isOff()) { + ++SrcIdx; + Inst.addOperand(MCOperand::createReg(AMDGPU::NoRegister)); + continue; + } + + if (Op.isImm() && Op.getImmTy() == AMDGPUOperand::ImmTyExpTgt) { + Op.addImmOperands(Inst, 1); + continue; + } + + if (Op.isToken() && Op.getToken() == "done") + continue; + + // Handle optional arguments + OptionalIdx[Op.getImmTy()] = i; + } + + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyExpVM); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyExpCompr); + + Inst.addOperand(MCOperand::createImm(EnMask)); +} //===----------------------------------------------------------------------===// // s_waitcnt @@ -2275,6 +2352,85 @@ return false; } +void AMDGPUAsmParser::errorExpTgt() { + Error(Parser.getTok().getLoc(), "invalid exp target"); +} + +OperandMatchResultTy AMDGPUAsmParser::parseExpTgtImpl(StringRef Str, + uint8_t &Val) { + if (Str == "null") { + Val = 9; + return MatchOperand_Success; + } + + if (Str.startswith("mrt")) { + Str = Str.drop_front(3); + if (Str == "z") { // == mrtz + Val = 8; + return MatchOperand_Success; + } + + if (Str.getAsInteger(10, Val)) + return MatchOperand_ParseFail; + + if (Val > 7) + errorExpTgt(); + + return MatchOperand_Success; + } + + if (Str.startswith("pos")) { + Str = Str.drop_front(3); + if (Str.getAsInteger(10, Val)) + return MatchOperand_ParseFail; + + if (Val > 3) + errorExpTgt(); + + Val += 12; + return MatchOperand_Success; + } + + if (Str.startswith("param")) { + Str = Str.drop_front(5); + if (Str.getAsInteger(10, Val)) + return MatchOperand_ParseFail; + + if (Val >= 32) + errorExpTgt(); + + Val += 32; + return MatchOperand_Success; + } + + if (Str.startswith("invalid_target_")) { + Str = Str.drop_front(15); + if (Str.getAsInteger(10, Val)) + return MatchOperand_ParseFail; + + errorExpTgt(); + return MatchOperand_Success; + } + + return MatchOperand_NoMatch; +} + +OperandMatchResultTy AMDGPUAsmParser::parseExpTgt(OperandVector &Operands) { + uint8_t Val; + StringRef Str = Parser.getTok().getString(); + + auto Res = parseExpTgtImpl(Str, Val); + if (Res != MatchOperand_Success) + return Res; + + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); + + Operands.push_back(AMDGPUOperand::CreateImm(this, Val, S, + AMDGPUOperand::ImmTyExpTgt)); + return MatchOperand_Success; +} + OperandMatchResultTy AMDGPUAsmParser::parseSendMsgOp(OperandVector &Operands) { using namespace llvm::AMDGPU::SendMsg; @@ -2540,6 +2696,10 @@ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyLWE); } +AMDGPUOperand::Ptr AMDGPUAsmParser::defaultExpTgt() const { + return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyExpTgt); +} + AMDGPUOperand::Ptr AMDGPUAsmParser::defaultExpCompr() const { return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyExpCompr); } @@ -2644,6 +2804,7 @@ {"src0_sel", AMDGPUOperand::ImmTySdwaSrc0Sel, false, nullptr}, {"src1_sel", AMDGPUOperand::ImmTySdwaSrc1Sel, false, nullptr}, {"dst_unused", AMDGPUOperand::ImmTySdwaDstUnused, false, nullptr}, + {"vm", AMDGPUOperand::ImmTyExpVM, true, nullptr}, }; OperandMatchResultTy AMDGPUAsmParser::parseOptionalOperand(OperandVector &Operands) { @@ -3126,6 +3287,9 @@ return Operand.isSSrcF32() ? Match_Success : Match_InvalidOperand; case MCK_SoppBrTarget: return Operand.isSoppBrTarget() ? Match_Success : Match_InvalidOperand; - default: return Match_InvalidOperand; + case MCK_VReg32OrOff: + return Operand.isVReg32OrOff() ? Match_Success : Match_InvalidOperand; + default: + return Match_InvalidOperand; } } Index: lib/Target/AMDGPU/SIInstrInfo.td =================================================================== --- lib/Target/AMDGPU/SIInstrInfo.td +++ lib/Target/AMDGPU/SIInstrInfo.td @@ -315,6 +315,13 @@ let RenderMethod = "addImmOperands"; } +def ExpTgtMatchClass : AsmOperandClass { + let Name = "ExpTgt"; + let PredicateMethod = "isExpTgt"; + let ParserMethod = "parseExpTgt"; + let RenderMethod = "printExpTgt"; +} + def SendMsgImm : Operand { let PrintMethod = "printSendMsg"; let ParserMatchClass = SendMsgMatchClass; @@ -326,6 +333,11 @@ let ParserMethod = "parseSWaitCntOps"; } +def VReg32OrOffClass : AsmOperandClass { + let Name = "VReg32OrOff"; + let ParserMethod = "parseVReg32OrOff"; +} + def WAIT_FLAG : Operand { let ParserMatchClass = SWaitMatchClass; let PrintMethod = "printWaitFlag"; @@ -334,6 +346,31 @@ include "SIInstrFormats.td" include "VIInstrFormats.td" +// ===----------------------------------------------------------------------===// +// ExpSrc* Special cases for exp src operands which are printed as +// "off" depending on en operand. +// ===----------------------------------------------------------------------===// + +def ExpSrc0 : RegisterOperand { + let PrintMethod = "printExpSrc0"; + let ParserMatchClass = VReg32OrOffClass; +} + +def ExpSrc1 : RegisterOperand { + let PrintMethod = "printExpSrc1"; + let ParserMatchClass = VReg32OrOffClass; +} + +def ExpSrc2 : RegisterOperand { + let PrintMethod = "printExpSrc2"; + let ParserMatchClass = VReg32OrOffClass; +} + +def ExpSrc3 : RegisterOperand { + let PrintMethod = "printExpSrc3"; + let ParserMatchClass = VReg32OrOffClass; +} + class NamedMatchClass : AsmOperandClass { let Name = "Imm"#CName; let PredicateMethod = "is"#CName; @@ -402,8 +439,8 @@ def hwreg : NamedOperandU16<"Hwreg", NamedMatchClass<"Hwreg", 0>>; -def exp_tgt : Operand { - let PrintMethod = "printExpTgt"; +def exp_tgt : NamedOperandU8<"ExpTgt", NamedMatchClass<"ExpTgt", 0>> { + } } // End OperandType = "OPERAND_IMMEDIATE" @@ -531,8 +568,9 @@ exp_vm:$vm, exp_compr:$compr, i8imm:$en), "exp$tgt $src0, $src1, $src2, $src3"#!if(done, " done", "")#"$compr$vm", [(node (i8 timm:$en), (i1 timm:$vm), (i8 timm:$tgt), (i1 timm:$compr), - f32:$src0, f32:$src1, f32:$src2, f32:$src3)] ->; + f32:$src0, f32:$src1, f32:$src2, f32:$src3)]> { + let AsmMatchConverter = "cvtExp"; +} // Split EXP instruction into EXP and EXP_DONE so we can set // hasSideEffects for done=1. Index: lib/Target/AMDGPU/SIRegisterInfo.td =================================================================== --- lib/Target/AMDGPU/SIRegisterInfo.td +++ lib/Target/AMDGPU/SIRegisterInfo.td @@ -431,24 +431,3 @@ //===----------------------------------------------------------------------===// defm VCSrc : RegInlineOperand<"VS", "VCSrc">; - -// ===----------------------------------------------------------------------===// -// ExpSrc* Special cases for exp src operands which are printed as -// "off" depending on en operand. -// ===----------------------------------------------------------------------===// - -def ExpSrc0 : RegisterOperand { - let PrintMethod = "printExpSrc0"; -} - -def ExpSrc1 : RegisterOperand { - let PrintMethod = "printExpSrc1"; -} - -def ExpSrc2 : RegisterOperand { - let PrintMethod = "printExpSrc2"; -} - -def ExpSrc3 : RegisterOperand { - let PrintMethod = "printExpSrc3"; -} Index: test/MC/AMDGPU/exp-err.s =================================================================== --- /dev/null +++ test/MC/AMDGPU/exp-err.s @@ -0,0 +1,107 @@ +// RUN: not llvm-mc -arch=amdgcn -show-encoding %s 2>&1 | FileCheck -check-prefix=GCN %s +// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s 2>&1 | FileCheck -check-prefix=GCN %s + +exp mrt8 v3, v2, v1, v0 +// GCN: :5: error: invalid exp target + +exp pos4 v3, v2, v1, v0 +// GCN: :5: error: invalid exp target + +exp param32 v3, v2, v1, v0 +// GCN: :5: error: invalid exp target + +exp invalid_target_10 v3, v2, v1, v0 +// GCN: :5: error: invalid exp target + +exp invalid_target_10 v3, v2, v1, v0 done +// GCN: :5: error: invalid exp target + +exp invalid_target_11 v3, v2, v1, v0 +// GCN: :5: error: invalid exp target + +exp invalid_target_11 v3, v2, v1, v0 done +// GCN: :5: error: invalid exp target + +exp mrt-1 v3, v2, v1, v0 +// GCN: :5: error: failed parsing operand + +exp mrtX v3, v2, v1, v0 +// GCN: :5: error: failed parsing operand + +exp pos-1 v3, v2, v1, v0 +// GCN: :5: error: failed parsing operand + +exp posX v3, v2, v1, v0 +// GCN: :5: error: failed parsing operand + +exp param-1 v3, v2, v1, v0 +// GCN: :5: error: failed parsing operand + +exp paramX v3, v2, v1, v0 +// GCN: :5: error: failed parsing operand + +exp invalid_target_-1 v3, v2, v1, v0 +// GCN: :5: error: failed parsing operand + +exp invalid_target_X v3, v2, v1, v0 +// GCN: :5: error: failed parsing operand + +exp mrt0 s0, v0, v0, v0 +// GCN: 10: error: invalid operand for instruction + +exp mrt0 v0, s0, v0, v0 +// GCN: 14: error: invalid operand for instruction + +exp mrt0 v0, v0, s0, v0 +// GCN: 18: error: invalid operand for instruction + +exp mrt0 v0, v0, v0, s0 +// GCN: 22: error: invalid operand for instruction + +exp mrt0 v[0:1], v0, v0, v0 +// GCN: 10: error: invalid operand for instruction + +exp mrt0 v0, v[0:1], v0, v0 +// GCN: 14: error: invalid operand for instruction + +exp mrt0 v0, v0, v[0:1], v0 +// GCN: 18: error: invalid operand for instruction + +exp mrt0 v0, v0, v0, v[0:1] +// GCN: 22: error: invalid operand for instruction + +exp mrt0 1.0, v0, v0, v0 +// GCN: 10: error: invalid operand for instruction + +exp mrt0 v0, 1.0, v0, v0 +// GCN: 14: error: invalid operand for instruction + +exp mrt0 v0, v0, 1.0, v0 +// GCN: 18: error: invalid operand for instruction + +exp mrt0 v0, v0, v0, 1.0 +// GCN: 22: error: invalid operand for instruction + +exp mrt0 7, v0, v0, v0 +// GCN: 10: error: invalid operand for instruction + +exp mrt0 v0, 7, v0, v0 +// GCN: 14: error: invalid operand for instruction + +exp mrt0 v0, v0, 7, v0 +// GCN: 18: error: invalid operand for instruction + +exp mrt0 v0, v0, v0, 7 +// GCN: 22: error: invalid operand for instruction + +exp mrt0 0x12345678, v0, v0, v0 +// GCN: 10: error: invalid operand for instruction + +exp mrt0 v0, 0x12345678, v0, v0 +// GCN: 14: error: invalid operand for instruction + +exp mrt0 v0, v0, 0x12345678, v0 +// GCN: 18: error: invalid operand for instruction + +exp mrt0 v0, v0, v0, 0x12345678 +// GCN: 22: error: invalid operand for instruction Index: test/MC/AMDGPU/exp.s =================================================================== --- /dev/null +++ test/MC/AMDGPU/exp.s @@ -0,0 +1,86 @@ +// RUN: llvm-mc -arch=amdgcn -show-encoding %s | FileCheck -check-prefix=GCN -check-prefix=SI %s +// RUN: llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s | FileCheck -check-prefix=GCN -check-prefix=SI %s + +exp mrt0 off, off, off, off +// GCN: exp mrt0 off, off, off, off ; encoding: [0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00] + +exp mrt0 off, off, off, off done +// GCN: exp mrt0 off, off, off, off done ; encoding: [0x00,0x08,0x00,0xf8,0x00,0x00,0x00,0x00] + +exp mrt0 v4, off, off, off done +// GCN: exp mrt0 v4, off, off, off done ; encoding: [0x01,0x08,0x00,0xf8,0x04,0x00,0x00,0x00] + +exp mrt0 off, v3, off, off done +// GCN: exp mrt0 off, v3, off, off done ; encoding: [0x02,0x08,0x00,0xf8,0x00,0x03,0x00,0x00] + +exp mrt0 off, off, v2, off done +// GCN: exp mrt0 off, off, v2, off done ; encoding: [0x04,0x08,0x00,0xf8,0x00,0x00,0x02,0x00] + +exp mrt0 off, off, off, v1 done +// GCN: exp mrt0 off, off, off, v1 done ; encoding: [0x08,0x08,0x00,0xf8,0x00,0x00,0x00,0x01] + +exp mrt0 v4, v3, off, off done +// GCN: exp mrt0 v4, v3, off, off done ; encoding: [0x03,0x08,0x00,0xf8,0x04,0x03,0x00,0x00] + +exp mrt0 v4, off, v2, off done +// GCN: exp mrt0 v4, off, v2, off done ; encoding: [0x05,0x08,0x00,0xf8,0x04,0x00,0x02,0x00] + +exp mrt0 v4, off, off, v1 +// GCN: exp mrt0 v4, off, off, v1 ; encoding: [0x09,0x00,0x00,0xf8,0x04,0x00,0x00,0x01] + +exp mrt0 v4, off, off, v1 done +// GCN: exp mrt0 v4, off, off, v1 done ; encoding: [0x09,0x08,0x00,0xf8,0x04,0x00,0x00,0x01] + +exp mrt0 v4, v3, v2, v1 +// GCN: exp mrt0 v4, v3, v2, v1 ; encoding: [0x0f,0x00,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp mrt0 v4, v3, v2, v1 done +// GCN: exp mrt0 v4, v3, v2, v1 done ; encoding: [0x0f,0x08,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp mrt7 v1, v1, v1, v1 +// GCN: exp mrt7 v1, v1, v1, v1 ; encoding: [0x7f,0x00,0x00,0xf8,0x01,0x01,0x01,0x01] + +exp mrt7 v1, v1, v1, v1 done +// GCN: exp mrt7 v1, v1, v1, v1 done ; encoding: [0x7f,0x08,0x00,0xf8,0x01,0x01,0x01,0x01] + +exp mrtz v4, v3, v2, v1 +// GCN: exp mrtz v4, v3, v2, v1 ; encoding: [0x8f,0x00,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp mrtz v4, v3, v2, v1 done +// GCN: exp mrtz v4, v3, v2, v1 done ; encoding: [0x8f,0x08,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp null v4, v3, v2, v1 +// GCN: exp null v4, v3, v2, v1 ; encoding: [0x9f,0x00,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp null v4, v3, v2, v1 done +// GCN: exp null v4, v3, v2, v1 done ; encoding: [0x9f,0x08,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp pos0 v4, v3, v2, v1 +// GCN: exp pos0 v4, v3, v2, v1 ; encoding: [0xcf,0x00,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp pos0 v4, v3, v2, v1 done +// GCN: exp pos0 v4, v3, v2, v1 done ; encoding: [0xcf,0x08,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp pos3 v4, v3, v2, v1 +// GCN: exp pos3 v4, v3, v2, v1 ; encoding: [0xff,0x00,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp pos3 v4, v3, v2, v1 done +// GCN: exp pos3 v4, v3, v2, v1 done ; encoding: [0xff,0x08,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp param0 v4, v3, v2, v1 +// GCN: exp param0 v4, v3, v2, v1 ; encoding: [0x0f,0x02,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp param0 v4, v3, v2, v1 done +// GCN: exp param0 v4, v3, v2, v1 done ; encoding: [0x0f,0x0a,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp param31 v4, v3, v2, v1 +// GCN: exp param31 v4, v3, v2, v1 ; encoding: [0xff,0x03,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp param31 v4, v3, v2, v1 done +// GCN: exp param31 v4, v3, v2, v1 done ; encoding: [0xff,0x0b,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp mrt0 v4, v3, v2, v1 vm +// GCN: exp mrt0 v4, v3, v2, v1 vm ; encoding: [0x0f,0x10,0x00,0xf8,0x04,0x03,0x02,0x01] + +exp mrt0 v4, v3, v2, v1 done vm +// GCN: exp mrt0 v4, v3, v2, v1 done vm ; encoding: [0x0f,0x18,0x00,0xf8,0x04,0x03,0x02,0x01]