From: Dmitry Preobrazhensky Date: Fri, 3 Mar 2017 14:31:06 +0000 (+0000) Subject: [AMDGPU][MC] Fix for Bug 30829 + LIT tests X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=23bacbc32aaa4a596f0a9f9e94b20abca9929b9a;p=llvm [AMDGPU][MC] Fix for Bug 30829 + LIT tests Added code to check constant bus restrictions for VOP formats (only one SGPR value or literal-constant may be used by the instruction). Note that the same checks are performed by SIInstrInfo::verifyInstruction (used by lowering code). Added LIT tests. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296873 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp index 77bf0a618bb..ea76043eb5f 100644 --- a/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -980,6 +980,12 @@ private: void errorExpTgt(); OperandMatchResultTy parseExpTgtImpl(StringRef Str, uint8_t &Val); + bool validateOperandLimitations(const MCInst &Inst); + bool usesConstantBus(const MCInst &Inst, unsigned OpIdx); + bool isInlineConstant(const MCInst &Inst, unsigned OpIdx) const; + unsigned findImplicitSGPRReadInVOP(const MCInst &Inst) const; + bool isSGPR(unsigned Reg); + public: OperandMatchResultTy parseOptionalOperand(OperandVector &Operands); @@ -1886,6 +1892,128 @@ ArrayRef AMDGPUAsmParser::getMatchedVariants() const { return makeArrayRef(Variants); } +unsigned AMDGPUAsmParser::findImplicitSGPRReadInVOP(const MCInst &Inst) const { + const MCInstrDesc &Desc = MII.get(Inst.getOpcode()); + const unsigned Num = Desc.getNumImplicitUses(); + for (unsigned i = 0; i < Num; ++i) { + unsigned Reg = Desc.ImplicitUses[i]; + switch (Reg) { + case AMDGPU::FLAT_SCR: + case AMDGPU::VCC: + case AMDGPU::M0: + return Reg; + default: + break; + } + } + return AMDGPU::NoRegister; +} + +bool AMDGPUAsmParser::isSGPR(unsigned Reg) { + const MCRegisterInfo *TRI = getContext().getRegisterInfo(); + const MCRegisterClass SGPRClass = TRI->getRegClass(AMDGPU::SReg_32RegClassID); + const unsigned FirstSubReg = TRI->getSubReg(Reg, 1); + return SGPRClass.contains(FirstSubReg != 0 ? FirstSubReg : Reg) || + Reg == AMDGPU::SCC; +} + +// NB: This code is correct only when used to check constant +// bus limitations because GFX7 support no f16 inline constants. +// Note that there are no cases when a GFX7 opcode violates +// constant bus limitations due to the use of an f16 constant. +bool AMDGPUAsmParser::isInlineConstant(const MCInst &Inst, + unsigned OpIdx) const { + const MCInstrDesc &Desc = MII.get(Inst.getOpcode()); + + if (!AMDGPU::isSISrcOperand(Desc, OpIdx)) { + return false; + } + + const MCOperand &MO = Inst.getOperand(OpIdx); + + int64_t Val = MO.getImm(); + auto OpSize = AMDGPU::getOperandSize(Desc, OpIdx); + + switch (OpSize) { // expected operand size + case 8: + return AMDGPU::isInlinableLiteral64(Val, hasInv2PiInlineImm()); + case 4: + return AMDGPU::isInlinableLiteral32(Val, hasInv2PiInlineImm()); + case 2: { + const unsigned OperandType = Desc.OpInfo[OpIdx].OperandType; + if (OperandType == AMDGPU::OPERAND_REG_INLINE_C_V2INT16 || + OperandType == AMDGPU::OPERAND_REG_INLINE_C_V2FP16) { + return AMDGPU::isInlinableLiteralV216(Val, hasInv2PiInlineImm()); + } else { + return AMDGPU::isInlinableLiteral16(Val, hasInv2PiInlineImm()); + } + } + default: + llvm_unreachable("invalid operand size"); + } +} + +bool AMDGPUAsmParser::usesConstantBus(const MCInst &Inst, unsigned OpIdx) { + const MCOperand &MO = Inst.getOperand(OpIdx); + if (MO.isImm()) { + return !isInlineConstant(Inst, OpIdx); + } + return !MO.isReg() || isSGPR(mc2PseudoReg(MO.getReg())); +} + +bool AMDGPUAsmParser::validateOperandLimitations(const MCInst &Inst) { + const unsigned Opcode = Inst.getOpcode(); + const MCInstrDesc &Desc = MII.get(Opcode); + unsigned ConstantBusUseCount = 0; + + if (Desc.TSFlags & + (SIInstrFlags::VOPC | + SIInstrFlags::VOP1 | SIInstrFlags::VOP2 | + SIInstrFlags::VOP3 | SIInstrFlags::VOP3P)) { + + // Check special imm operands (used by madmk, etc) + if (AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::imm) != -1) { + ++ConstantBusUseCount; + } + + unsigned SGPRUsed = findImplicitSGPRReadInVOP(Inst); + if (SGPRUsed != AMDGPU::NoRegister) { + ++ConstantBusUseCount; + } + + const int Src0Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0); + const int Src1Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1); + const int Src2Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2); + + const int OpIndices[] = { Src0Idx, Src1Idx, Src2Idx }; + + for (int OpIdx : OpIndices) { + if (OpIdx == -1) break; + + const MCOperand &MO = Inst.getOperand(OpIdx); + if (usesConstantBus(Inst, OpIdx)) { + if (MO.isReg()) { + const unsigned Reg = mc2PseudoReg(MO.getReg()); + // Pairs of registers with a partial intersections like these + // s0, s[0:1] + // flat_scratch_lo, flat_scratch + // flat_scratch_lo, flat_scratch_hi + // are theoretically valid but they are disabled anyway. + // Note that this code mimics SIInstrInfo::verifyInstruction + if (Reg != SGPRUsed) { + ++ConstantBusUseCount; + } + SGPRUsed = Reg; + } else { // Expression or a literal + ++ConstantBusUseCount; + } + } + } + } + + return ConstantBusUseCount <= 1; +} + bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -1918,6 +2046,10 @@ bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, switch (Result) { default: break; case Match_Success: + if (!validateOperandLimitations(Inst)) { + return Error(IDLoc, + "invalid operand (violates constant bus restrictions)"); + } Inst.setLoc(IDLoc); Out.EmitInstruction(Inst, getSTI()); return false; diff --git a/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp index cdcc0f08177..de0fda4be6f 100644 --- a/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp +++ b/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp @@ -547,6 +547,25 @@ unsigned getMCReg(unsigned Reg, const MCSubtargetInfo &STI) { return Reg; } +unsigned mc2PseudoReg(unsigned Reg) { + switch (Reg) { + case AMDGPU::FLAT_SCR_ci: + case AMDGPU::FLAT_SCR_vi: + return FLAT_SCR; + + case AMDGPU::FLAT_SCR_LO_ci: + case AMDGPU::FLAT_SCR_LO_vi: + return AMDGPU::FLAT_SCR_LO; + + case AMDGPU::FLAT_SCR_HI_ci: + case AMDGPU::FLAT_SCR_HI_vi: + return AMDGPU::FLAT_SCR_HI; + + default: + return Reg; + } +} + bool isSISrcOperand(const MCInstrDesc &Desc, unsigned OpNo) { assert(OpNo < Desc.NumOperands); unsigned OpType = Desc.OpInfo[OpNo].OperandType; diff --git a/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h index c20a2093755..96171562ebe 100644 --- a/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h +++ b/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h @@ -263,6 +263,10 @@ bool isVI(const MCSubtargetInfo &STI); /// \p STI otherwise return \p Reg. unsigned getMCReg(unsigned Reg, const MCSubtargetInfo &STI); +/// \brief Convert hardware register \p Reg to a pseudo register +LLVM_READNONE +unsigned mc2PseudoReg(unsigned Reg); + /// \brief Can this operand also contain immediate values? bool isSISrcOperand(const MCInstrDesc &Desc, unsigned OpNo); diff --git a/lib/Target/AMDGPU/VOP1Instructions.td b/lib/Target/AMDGPU/VOP1Instructions.td index ff2f9338407..dcef11ee7bf 100644 --- a/lib/Target/AMDGPU/VOP1Instructions.td +++ b/lib/Target/AMDGPU/VOP1Instructions.td @@ -75,6 +75,8 @@ class VOP1_Real : let Constraints = ps.Constraints; let DisableEncoding = ps.DisableEncoding; let TSFlags = ps.TSFlags; + let UseNamedOperandTable = ps.UseNamedOperandTable; + let Uses = ps.Uses; } class VOP1_SDWA_Pseudo pattern=[]> : diff --git a/lib/Target/AMDGPU/VOP2Instructions.td b/lib/Target/AMDGPU/VOP2Instructions.td index bfd73d44b42..4476fd56763 100644 --- a/lib/Target/AMDGPU/VOP2Instructions.td +++ b/lib/Target/AMDGPU/VOP2Instructions.td @@ -93,6 +93,8 @@ class VOP2_Real : let Constraints = ps.Constraints; let DisableEncoding = ps.DisableEncoding; let TSFlags = ps.TSFlags; + let UseNamedOperandTable = ps.UseNamedOperandTable; + let Uses = ps.Uses; } class VOP2_SDWA_Pseudo pattern=[]> : diff --git a/lib/Target/AMDGPU/VOPCInstructions.td b/lib/Target/AMDGPU/VOPCInstructions.td index bb05fb7bae7..c64a18aaee0 100644 --- a/lib/Target/AMDGPU/VOPCInstructions.td +++ b/lib/Target/AMDGPU/VOPCInstructions.td @@ -93,6 +93,8 @@ class VOPC_Real : let Constraints = ps.Constraints; let DisableEncoding = ps.DisableEncoding; let TSFlags = ps.TSFlags; + let UseNamedOperandTable = ps.UseNamedOperandTable; + let Uses = ps.Uses; } class VOPC_SDWA_Pseudo pattern=[]> : diff --git a/lib/Target/AMDGPU/VOPInstructions.td b/lib/Target/AMDGPU/VOPInstructions.td index acb5b066896..cc4ad934465 100644 --- a/lib/Target/AMDGPU/VOPInstructions.td +++ b/lib/Target/AMDGPU/VOPInstructions.td @@ -136,6 +136,8 @@ class VOP3_Real : let Constraints = ps.Constraints; let DisableEncoding = ps.DisableEncoding; let TSFlags = ps.TSFlags; + let UseNamedOperandTable = ps.UseNamedOperandTable; + let Uses = ps.Uses; } // XXX - Is there any reason to distingusih this from regular VOP3 diff --git a/test/MC/AMDGPU/vop-err.s b/test/MC/AMDGPU/vop-err.s new file mode 100644 index 00000000000..13388263b20 --- /dev/null +++ b/test/MC/AMDGPU/vop-err.s @@ -0,0 +1,290 @@ +// RUN: not llvm-mc -arch=amdgcn -mcpu=bonaire -show-encoding %s 2>&1 | FileCheck %s +// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s 2>&1 | FileCheck %s + +// GENERIC LIMITATIONS ON VOP FORMATS: CONSTANT BUS RESTRICTIONS + +//===================================================== +// v_movreld_b32: implicitly reads m0 (VOP1/VOP3) + +v_movreld_b32 v0, s1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32 v0, flat_scratch_lo +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32 v0, flat_scratch_hi +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32 v0, vcc_lo +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32 v0, vcc_hi +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32 v0, exec_lo +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32 v0, exec_hi +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32 v0, ttmp0 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32 v0, ttmp1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32 v0, 123 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32_e64 v0, s1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32_e64 v0, flat_scratch_lo +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_movreld_b32_e64 v0, flat_scratch_hi +// CHECK: error: invalid operand (violates constant bus restrictions) + +//===================================================== +// v_div_fmas: implicitly read VCC (VOP3) + +v_div_fmas_f32 v0, s1, s1, s1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f32 v0, v2, v3, -s1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f32 v0, v1, s2, |v3| +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f32 v0, v1, -v2, -s3 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f32 v0, v1, flat_scratch_lo, v3 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f32 v0, v1, v2, flat_scratch_hi +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f32 v0, v1, v2, m0 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f32 v0, v1, ttmp2, v2 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f64 v[0:1], s[2:3], v[4:5], v[6:7] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f64 v[0:1], v[2:3], s[4:5], v[6:7] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f64 v[0:1], v[2:3], v[4:5], s[6:7] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f64 v[0:1], v[2:3], v[4:5], ttmp[2:3] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f64 v[0:1], v[2:3], v[4:5], flat_scratch +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_div_fmas_f64 v[0:1], v[2:3], v[4:5], exec +// CHECK: error: invalid operand (violates constant bus restrictions) + +//===================================================== +// v_cndmask_b32: implicitly reads VCC (VOP2) + +v_cndmask_b32 v0, s1, v2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32 v0, flat_scratch_lo, v2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32 v0, flat_scratch_hi, v2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32 v0, exec_lo, v2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32 v0, exec_hi, v2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +//===================================================== +// v_cndmask_b32_e64: VOP3, no implicit reads + +v_cndmask_b32_e64 v0, s1, v2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, flat_scratch_lo, v2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, flat_scratch_hi, v2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, s1, v2, flat_scratch +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, s0, v2, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, v2, s0, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, s0, s0, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, s1, v2, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, v2, s1, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, s1, s1, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, s1, v2, s[2:3] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, v2, s1, s[2:3] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cndmask_b32_e64 v0, s1, s1, s[2:3] +// CHECK: error: invalid operand (violates constant bus restrictions) + +//===================================================== +// v_addc_u32: implicitly reads VCC (VOP2 only!) + +v_addc_u32 v0, vcc, s0, v0, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32 v0, vcc, flat_scratch_lo, v0, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32 v0, vcc, flat_scratch_hi, v0, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32 v0, vcc, exec_lo, v0, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32 v0, vcc, exec_hi, v0, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +//===================================================== +// v_addc_u32_e64: no implicit read in VOP3 + +v_addc_u32_e64 v0, s[0:1], s2, v2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32_e64 v0, s[0:1], v2, s2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32_e64 v0, s[0:1], s2, s2, vcc +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32_e64 v0, s[0:1], s0, v2, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32_e64 v0, s[0:1], v2, s0, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32_e64 v0, s[0:1], s0, s0, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32_e64 v0, s[0:1], s2, v2, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32_e64 v0, s[0:1], v2, s2, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_addc_u32_e64 v0, s[0:1], s2, s2, s[0:1] +// CHECK: error: invalid operand (violates constant bus restrictions) + +//===================================================== +// VOP1 w/o implicit reads have no negative test cases on constant bus use +// VOPC has no negative test cases on constant bus use + +//===================================================== +// madak/madmk: a special case for VOP2 w/o implicit reads + +v_madak_f32 v0, s0, v0, 0x11213141 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_madak_f32 v0, flat_scratch_lo, v0, 0x11213141 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_madak_f32 v0, flat_scratch_hi, v0, 0x11213141 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_madak_f32 v0, exec_lo, v0, 0x11213141 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_madak_f32 v0, exec_hi, v0, 0x11213141 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_madak_f32 v0, vcc_lo, v0, 0x11213141 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_madak_f32 v0, vcc_hi, v0, 0x11213141 +// CHECK: error: invalid operand (violates constant bus restrictions) + +//===================================================== +// VOP3 w/o implicit reads + +v_mad_f32 v0, s0, s1, s0 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_mad_f32 v0, s1, s0, s0 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_mad_f32 v0, s0, s0, s1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_mad_f32 v0, s0, s0, flat_scratch_lo +// CHECK: error: invalid operand (violates constant bus restrictions) + +//===================================================== +// VOP2_e64: + +v_add_f32_e64 v0, s0, s1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_add_f32_e64 v0, s0, flat_scratch_lo +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_add_f32_e64 v0, flat_scratch_hi, s1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_add_f32_e64 v0, flat_scratch_hi, m0 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_add_f64 v[0:1], s[0:1], s[2:3] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_add_f64 v[0:1], s[0:1], flat_scratch +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_add_f64 v[0:1], vcc, s[2:3] +// CHECK: error: invalid operand (violates constant bus restrictions) + +//===================================================== +// VOPC_e64: + +v_cmp_eq_f32_e64 s[0:1], s0, s1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cmp_eq_f32_e64 s[0:1], s0, flat_scratch_lo +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cmp_eq_f32_e64 s[0:1], flat_scratch_hi, s1 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cmp_eq_f32_e64 s[0:1], s0, m0 +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cmp_eq_f64_e64 s[0:1], s[0:1], s[2:3] +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cmp_eq_f64_e64 s[0:1], s[0:1], flat_scratch +// CHECK: error: invalid operand (violates constant bus restrictions) + +v_cmp_eq_f64_e64 s[0:1], vcc, s[2:3] +// CHECK: error: invalid operand (violates constant bus restrictions) diff --git a/test/MC/AMDGPU/vop3p-err.s b/test/MC/AMDGPU/vop3p-err.s index 4cfc21762b0..f4b1a3da714 100644 --- a/test/MC/AMDGPU/vop3p-err.s +++ b/test/MC/AMDGPU/vop3p-err.s @@ -111,3 +111,10 @@ v_mad_mixhi_f16 v1, v2, v3, v4 neg_lo:[0,0,0] // GFX9: invalid operand for instruction v_mad_mixhi_f16 v1, v2, v3, v4 neg_hi:[0,0,0] + +// +// Constant bus restrictions +// + +// GFX9: invalid operand (violates constant bus restrictions) +v_pk_add_f16 v255, s1, s2