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);
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,
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;
--- /dev/null
+// 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)