Index: lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp =================================================================== --- lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -155,6 +155,9 @@ ImmTyHwreg, ImmTyOff, ImmTySendMsg, + ImmTyInterpSlot, + ImmTyInterpAttr, + ImmTyAttrChan }; struct TokOp { @@ -279,6 +282,9 @@ bool isSDWASrc0Sel() const { return isImmTy(ImmTySdwaSrc0Sel); } bool isSDWASrc1Sel() const { return isImmTy(ImmTySdwaSrc1Sel); } bool isSDWADstUnused() const { return isImmTy(ImmTySdwaDstUnused); } + bool isInterpSlot() const { return isImmTy(ImmTyInterpSlot); } + bool isInterpAttr() const { return isImmTy(ImmTyInterpAttr); } + bool isAttrChan() const { return isImmTy(ImmTyAttrChan); } bool isMod() const { return isClampSI() || isOModSI(); @@ -568,6 +574,9 @@ case ImmTyExpVM: OS << "ExpVM"; break; case ImmTyHwreg: OS << "Hwreg"; break; case ImmTySendMsg: OS << "SendMsg"; break; + case ImmTyInterpSlot: OS << "InterpSlot"; break; + case ImmTyInterpAttr: OS << "InterpAttr"; break; + case ImmTyAttrChan: OS << "AttrChan"; break; } } @@ -824,6 +833,8 @@ OperandMatchResultTy parseExpTgt(OperandVector &Operands); OperandMatchResultTy parseSendMsgOp(OperandVector &Operands); + OperandMatchResultTy parseInterpSlot(OperandVector &Operands); + OperandMatchResultTy parseInterpAttr(OperandVector &Operands); OperandMatchResultTy parseSOppBrTarget(OperandVector &Operands); void cvtMubuf(MCInst &Inst, const OperandVector &Operands) { cvtMubufImpl(Inst, Operands, false, false); } @@ -2491,6 +2502,67 @@ return false; } +OperandMatchResultTy AMDGPUAsmParser::parseInterpSlot(OperandVector &Operands) { + if (getLexer().getKind() != AsmToken::Identifier) + return MatchOperand_NoMatch; + + StringRef Str = Parser.getTok().getString(); + int Slot = StringSwitch(Str) + .Case("p10", 0) + .Case("p20", 1) + .Case("p0", 2) + .Default(-1); + + SMLoc S = Parser.getTok().getLoc(); + if (Slot == -1) + return MatchOperand_ParseFail; + + Parser.Lex(); + Operands.push_back(AMDGPUOperand::CreateImm(this, Slot, S, + AMDGPUOperand::ImmTyInterpSlot)); + return MatchOperand_Success; +} + +OperandMatchResultTy AMDGPUAsmParser::parseInterpAttr(OperandVector &Operands) { + if (getLexer().getKind() != AsmToken::Identifier) + return MatchOperand_NoMatch; + + StringRef Str = Parser.getTok().getString(); + if (!Str.startswith("attr")) + return MatchOperand_NoMatch; + + StringRef Chan = Str.take_back(2); + int AttrChan = StringSwitch(Chan) + .Case(".x", 0) + .Case(".y", 1) + .Case(".z", 2) + .Case(".w", 3) + .Default(-1); + if (AttrChan == -1) + return MatchOperand_ParseFail; + + Str = Str.drop_back(2).drop_front(4); + + uint8_t Attr; + if (Str.getAsInteger(10, Attr)) + return MatchOperand_ParseFail; + + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); + if (Attr > 63) { + Error(S, "out of bounds attr"); + return MatchOperand_Success; + } + + SMLoc SChan = SMLoc::getFromPointer(Chan.data()); + + Operands.push_back(AMDGPUOperand::CreateImm(this, Attr, S, + AMDGPUOperand::ImmTyInterpAttr)); + Operands.push_back(AMDGPUOperand::CreateImm(this, AttrChan, SChan, + AMDGPUOperand::ImmTyAttrChan)); + return MatchOperand_Success; +} + void AMDGPUAsmParser::errorExpTgt() { Error(Parser.getTok().getLoc(), "invalid exp target"); } @@ -3427,6 +3499,12 @@ return Operand.isSoppBrTarget() ? Match_Success : Match_InvalidOperand; case MCK_VReg32OrOff: return Operand.isVReg32OrOff() ? Match_Success : Match_InvalidOperand; + case MCK_InterpSlot: + return Operand.isInterpSlot() ? Match_Success : Match_InvalidOperand; + case MCK_Attr: + return Operand.isInterpAttr() ? Match_Success : Match_InvalidOperand; + case MCK_AttrChan: + return Operand.isAttrChan() ? Match_Success : Match_InvalidOperand; default: return Match_InvalidOperand; } Index: lib/Target/AMDGPU/SIInstrInfo.td =================================================================== --- lib/Target/AMDGPU/SIInstrInfo.td +++ lib/Target/AMDGPU/SIInstrInfo.td @@ -304,19 +304,43 @@ def si_ga : Operand; +def InterpSlotMatchClass : AsmOperandClass { + let Name = "InterpSlot"; + let PredicateMethod = "isInterpSlot"; + let ParserMethod = "parseInterpSlot"; + let RenderMethod = "addImmOperands"; +} + def InterpSlot : Operand { let PrintMethod = "printInterpSlot"; + let ParserMatchClass = InterpSlotMatchClass; + let OperandType = "OPERAND_IMMEDIATE"; +} + +def AttrMatchClass : AsmOperandClass { + let Name = "Attr"; + let PredicateMethod = "isInterpAttr"; + let ParserMethod = "parseInterpAttr"; + let RenderMethod = "addImmOperands"; } // It appears to be necessary to create a separate operand for this to // be able to parse attr with no space. def Attr : Operand { let PrintMethod = "printInterpAttr"; + let ParserMatchClass = AttrMatchClass; let OperandType = "OPERAND_IMMEDIATE"; } +def AttrChanMatchClass : AsmOperandClass { + let Name = "AttrChan"; + let PredicateMethod = "isAttrChan"; + let RenderMethod = "addImmOperands"; +} + def AttrChan : Operand { let PrintMethod = "printInterpAttrChan"; + let ParserMatchClass = AttrChanMatchClass; let OperandType = "OPERAND_IMMEDIATE"; } Index: lib/Target/AMDGPU/SIInstructions.td =================================================================== --- lib/Target/AMDGPU/SIInstructions.td +++ lib/Target/AMDGPU/SIInstructions.td @@ -51,7 +51,7 @@ multiclass V_INTERP_P1_F32_m : VINTRP_m < 0x00000000, (outs VGPR_32:$vdst), - (ins VGPR_32:$vsrc, AttrChan:$attrchan, Attr:$attr), + (ins VGPR_32:$vsrc, Attr:$attr, AttrChan:$attrchan), "v_interp_p1_f32 $vdst, $vsrc, $attr$attrchan", [(set f32:$vdst, (AMDGPUinterp_p1 f32:$vsrc, (i32 imm:$attrchan), (i32 imm:$attr)))] @@ -74,8 +74,8 @@ defm V_INTERP_P2_F32 : VINTRP_m < 0x00000001, (outs VGPR_32:$vdst), - (ins VGPR_32:$src0, VGPR_32:$vsrc, AttrChan:$attrchan, Attr:$attr), - "v_interp_p2_f32 $vdst, $vsrc, attr${attr}$attrchan", + (ins VGPR_32:$src0, VGPR_32:$vsrc, Attr:$attr, AttrChan:$attrchan), + "v_interp_p2_f32 $vdst, $vsrc, $attr$attrchan", [(set f32:$vdst, (AMDGPUinterp_p2 f32:$src0, f32:$vsrc, (i32 imm:$attrchan), (i32 imm:$attr)))]>; @@ -84,7 +84,7 @@ defm V_INTERP_MOV_F32 : VINTRP_m < 0x00000002, (outs VGPR_32:$vdst), - (ins InterpSlot:$vsrc, AttrChan:$attrchan, Attr:$attr), + (ins InterpSlot:$vsrc, Attr:$attr, AttrChan:$attrchan), "v_interp_mov_f32 $vdst, $vsrc, $attr$attrchan", [(set f32:$vdst, (AMDGPUinterp_mov (i32 imm:$vsrc), (i32 imm:$attrchan), (i32 imm:$attr)))]>; Index: test/MC/AMDGPU/vintrp-err.s =================================================================== --- /dev/null +++ test/MC/AMDGPU/vintrp-err.s @@ -0,0 +1,45 @@ +// RUN: not llvm-mc -arch=amdgcn -show-encoding %s 2>&1 | FileCheck -check-prefix=GCN -check-prefix=SI %s +// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s 2>&1 | FileCheck -check-prefix=GCN -check-prefix=VI %s + +v_interp_p1_f32 v0, v1, attr64.w +// GCN: :25: error: out of bounds attr + +v_interp_p1_f32 v0, v1, attr64.x +// GCN: :25: error: out of bounds attr + +v_interp_p2_f32 v9, v1, attr64.x +// GCN: :25: error: out of bounds attr + +v_interp_p2_f32 v0, v1, attr64.x +// GCN: :25: error: out of bounds attr + +v_interp_p2_f32 v0, v1, attr0.q +// GCN: :25: error: failed parsing operand. + +v_interp_p2_f32 v0, v1, attr0. +// GCN: :25: error: failed parsing operand. + +v_interp_p2_f32 v0, v1, attr +// GCN: :25: error: failed parsing operand. + +// XXX - Why does this one parse? +v_interp_p2_f32 v0, v1, att +// GCN: :25: error: invalid operand for instruction + +v_interp_p2_f32 v0, v1, attrq +// GCN: :25: error: failed parsing operand. + +v_interp_mov_f32 v11, invalid_param_3, attr0.y +// GCN: :23: error: failed parsing operand. + +v_interp_mov_f32 v12, invalid_param_10, attr0.x +// GCN: :23: error: failed parsing operand. + +v_interp_mov_f32 v3, invalid_param_3, attr0.x +// GCN: :22: error: failed parsing operand. + +v_interp_mov_f32 v8, invalid_param_8, attr0.x +// GCN: :22: error: failed parsing operand. + +v_interp_mov_f32 v8, foo, attr0.x +// GCN: :22: error: failed parsing operand. Index: test/MC/AMDGPU/vintrp.s =================================================================== --- /dev/null +++ test/MC/AMDGPU/vintrp.s @@ -0,0 +1,105 @@ +// 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=VI %s + +v_interp_p1_f32 v1, v0, attr0.x +// SI: v_interp_p1_f32 v1, v0, attr0.x ; encoding: [0x00,0x00,0x04,0xc8] +// VI: v_interp_p1_f32 v1, v0, attr0.x ; encoding: [0x00,0x00,0x04,0xd4] + +v_interp_p1_f32 v2, v0, attr0.y +// SI: v_interp_p1_f32 v2, v0, attr0.y ; encoding: [0x00,0x01,0x08,0xc8] +// VI: v_interp_p1_f32 v2, v0, attr0.y ; encoding: [0x00,0x01,0x08,0xd4] + +v_interp_p1_f32 v3, v0, attr0.z +// SI: v_interp_p1_f32 v3, v0, attr0.z ; encoding: [0x00,0x02,0x0c,0xc8] +// VI: v_interp_p1_f32 v3, v0, attr0.z ; encoding: [0x00,0x02,0x0c,0xd4] + +v_interp_p1_f32 v4, v0, attr0.w +// SI: v_interp_p1_f32 v4, v0, attr0.w ; encoding: [0x00,0x03,0x10,0xc8] +// VI: v_interp_p1_f32 v4, v0, attr0.w ; encoding: [0x00,0x03,0x10,0xd4] + +v_interp_p1_f32 v5, v0, attr0.x +// SI: v_interp_p1_f32 v5, v0, attr0.x ; encoding: [0x00,0x00,0x14,0xc8] +// VI: v_interp_p1_f32 v5, v0, attr0.x ; encoding: [0x00,0x00,0x14,0xd4] + +v_interp_p1_f32 v6, v0, attr1.x +// SI: v_interp_p1_f32 v6, v0, attr1.x ; encoding: [0x00,0x04,0x18,0xc8] +// VI: v_interp_p1_f32 v6, v0, attr1.x ; encoding: [0x00,0x04,0x18,0xd4] + +v_interp_p1_f32 v7, v0, attr2.y +// SI: v_interp_p1_f32 v7, v0, attr2.y ; encoding: [0x00,0x09,0x1c,0xc8] +// VI: v_interp_p1_f32 v7, v0, attr2.y ; encoding: [0x00,0x09,0x1c,0xd4] + +v_interp_p1_f32 v8, v0, attr3.z +// SI: v_interp_p1_f32 v8, v0, attr3.z ; encoding: [0x00,0x0e,0x20,0xc8] +// VI: v_interp_p1_f32 v8, v0, attr3.z ; encoding: [0x00,0x0e,0x20,0xd4] + +v_interp_p1_f32 v9, v0, attr4.w +// SI: v_interp_p1_f32 v9, v0, attr4.w ; encoding: [0x00,0x13,0x24,0xc8] +// VI: v_interp_p1_f32 v9, v0, attr4.w ; encoding: [0x00,0x13,0x24,0xd4] + +v_interp_p1_f32 v10, v0, attr63.w +// SI: v_interp_p1_f32 v10, v0, attr63.w ; encoding: [0x00,0xff,0x28,0xc8] +// VI: v_interp_p1_f32 v10, v0, attr63.w ; encoding: [0x00,0xff,0x28,0xd4] + + +v_interp_p2_f32 v2, v1, attr0.x +// SI: v_interp_p2_f32 v2, v1, attr0.x ; encoding: [0x01,0x00,0x09,0xc8] +// VI: v_interp_p2_f32 v2, v1, attr0.x ; encoding: [0x01,0x00,0x09,0xd4] + +v_interp_p2_f32 v3, v1, attr0.y +// SI: v_interp_p2_f32 v3, v1, attr0.y ; encoding: [0x01,0x01,0x0d,0xc8] +// VI: v_interp_p2_f32 v3, v1, attr0.y ; encoding: [0x01,0x01,0x0d,0xd4] + +v_interp_p2_f32 v4, v1, attr0.z +// SI: v_interp_p2_f32 v4, v1, attr0.z ; encoding: [0x01,0x02,0x11,0xc8] +// VI: v_interp_p2_f32 v4, v1, attr0.z ; encoding: [0x01,0x02,0x11,0xd4] + +v_interp_p2_f32 v5, v1, attr0.w +// SI: v_interp_p2_f32 v5, v1, attr0.w ; encoding: [0x01,0x03,0x15,0xc8] +// VI: v_interp_p2_f32 v5, v1, attr0.w ; encoding: [0x01,0x03,0x15,0xd4] + +v_interp_p2_f32 v6, v1, attr0.x +// SI: v_interp_p2_f32 v6, v1, attr0.x ; encoding: [0x01,0x00,0x19,0xc8] +// VI: v_interp_p2_f32 v6, v1, attr0.x ; encoding: [0x01,0x00,0x19,0xd4] + +v_interp_p2_f32 v7, v1, attr1.x +// SI: v_interp_p2_f32 v7, v1, attr1.x ; encoding: [0x01,0x04,0x1d,0xc8] +// VI: v_interp_p2_f32 v7, v1, attr1.x ; encoding: [0x01,0x04,0x1d,0xd4] + +v_interp_p2_f32 v8, v1, attr63.x +// SI: v_interp_p2_f32 v8, v1, attr63.x ; encoding: [0x01,0xfc,0x21,0xc8] +// VI: v_interp_p2_f32 v8, v1, attr63.x ; encoding: [0x01,0xfc,0x21,0xd4] + + +v_interp_mov_f32 v0, p10, attr0.x +// SI: v_interp_mov_f32 v0, p10, attr0.x ; encoding: [0x00,0x00,0x02,0xc8] +// VI: v_interp_mov_f32 v0, p10, attr0.x ; encoding: [0x00,0x00,0x02,0xd4] + +v_interp_mov_f32 v1, p20, attr0.x +// SI: v_interp_mov_f32 v1, p20, attr0.x ; encoding: [0x01,0x00,0x06,0xc8] +// VI: v_interp_mov_f32 v1, p20, attr0.x ; encoding: [0x01,0x00,0x06,0xd4] + +v_interp_mov_f32 v2, p0, attr0.x +// SI: v_interp_mov_f32 v2, p0, attr0.x ; encoding: [0x02,0x00,0x0a,0xc8] +// VI: v_interp_mov_f32 v2, p0, attr0.x ; encoding: [0x02,0x00,0x0a,0xd4] + +v_interp_mov_f32 v4, p10, attr0.y +// SI: v_interp_mov_f32 v4, p10, attr0.y ; encoding: [0x00,0x01,0x12,0xc8] +// VI: v_interp_mov_f32 v4, p10, attr0.y ; encoding: [0x00,0x01,0x12,0xd4] + +v_interp_mov_f32 v5, p10, attr0.z +// SI: v_interp_mov_f32 v5, p10, attr0.z ; encoding: [0x00,0x02,0x16,0xc8] +// VI: v_interp_mov_f32 v5, p10, attr0.z ; encoding: [0x00,0x02,0x16,0xd4] + +v_interp_mov_f32 v6, p10, attr0.w +// SI: v_interp_mov_f32 v6, p10, attr0.w ; encoding: [0x00,0x03,0x1a,0xc8] +// VI: v_interp_mov_f32 v6, p10, attr0.w ; encoding: [0x00,0x03,0x1a,0xd4] + +v_interp_mov_f32 v7, p10, attr0.x +// SI: v_interp_mov_f32 v7, p10, attr0.x ; encoding: [0x00,0x00,0x1e,0xc8] +// VI: v_interp_mov_f32 v7, p10, attr0.x ; encoding: [0x00,0x00,0x1e,0xd4] + +v_interp_mov_f32 v9, p10, attr63.y +// SI: v_interp_mov_f32 v9, p10, attr63.y ; encoding: [0x00,0xfd,0x26,0xc8] +// VI: v_interp_mov_f32 v9, p10, attr63.y ; encoding: [0x00,0xfd,0x26,0xd4] +