summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorDmitry Preobrazhensky <dmitry.preobrazhensky@amd.com>2017-03-03 14:31:06 +0000
committerDmitry Preobrazhensky <dmitry.preobrazhensky@amd.com>2017-03-03 14:31:06 +0000
commit03880f8d247052c6efdf16d3808d294dc726af33 (patch)
tree436e813408871006d5487597f432156be7c39f2a /llvm/lib
parent9528f8c2fb4b0440914fa9ea93419753551c1870 (diff)
downloadbcm5719-llvm-03880f8d247052c6efdf16d3808d294dc726af33.tar.gz
bcm5719-llvm-03880f8d247052c6efdf16d3808d294dc726af33.zip
[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. llvm-svn: 296873
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp132
-rw-r--r--llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp19
-rw-r--r--llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h4
-rw-r--r--llvm/lib/Target/AMDGPU/VOP1Instructions.td2
-rw-r--r--llvm/lib/Target/AMDGPU/VOP2Instructions.td2
-rw-r--r--llvm/lib/Target/AMDGPU/VOPCInstructions.td2
-rw-r--r--llvm/lib/Target/AMDGPU/VOPInstructions.td2
7 files changed, 163 insertions, 0 deletions
diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
index 77bf0a618bb..ea76043eb5f 100644
--- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
+++ b/llvm/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<unsigned> 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/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
index cdcc0f08177..de0fda4be6f 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
+++ b/llvm/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/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
index c20a2093755..96171562ebe 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
+++ b/llvm/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/llvm/lib/Target/AMDGPU/VOP1Instructions.td b/llvm/lib/Target/AMDGPU/VOP1Instructions.td
index ff2f9338407..dcef11ee7bf 100644
--- a/llvm/lib/Target/AMDGPU/VOP1Instructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP1Instructions.td
@@ -75,6 +75,8 @@ class VOP1_Real <VOP1_Pseudo ps, int EncodingFamily> :
let Constraints = ps.Constraints;
let DisableEncoding = ps.DisableEncoding;
let TSFlags = ps.TSFlags;
+ let UseNamedOperandTable = ps.UseNamedOperandTable;
+ let Uses = ps.Uses;
}
class VOP1_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
diff --git a/llvm/lib/Target/AMDGPU/VOP2Instructions.td b/llvm/lib/Target/AMDGPU/VOP2Instructions.td
index bfd73d44b42..4476fd56763 100644
--- a/llvm/lib/Target/AMDGPU/VOP2Instructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP2Instructions.td
@@ -93,6 +93,8 @@ class VOP2_Real <VOP2_Pseudo ps, int EncodingFamily> :
let Constraints = ps.Constraints;
let DisableEncoding = ps.DisableEncoding;
let TSFlags = ps.TSFlags;
+ let UseNamedOperandTable = ps.UseNamedOperandTable;
+ let Uses = ps.Uses;
}
class VOP2_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
diff --git a/llvm/lib/Target/AMDGPU/VOPCInstructions.td b/llvm/lib/Target/AMDGPU/VOPCInstructions.td
index bb05fb7bae7..c64a18aaee0 100644
--- a/llvm/lib/Target/AMDGPU/VOPCInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPCInstructions.td
@@ -93,6 +93,8 @@ class VOPC_Real <VOPC_Pseudo ps, int EncodingFamily> :
let Constraints = ps.Constraints;
let DisableEncoding = ps.DisableEncoding;
let TSFlags = ps.TSFlags;
+ let UseNamedOperandTable = ps.UseNamedOperandTable;
+ let Uses = ps.Uses;
}
class VOPC_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
diff --git a/llvm/lib/Target/AMDGPU/VOPInstructions.td b/llvm/lib/Target/AMDGPU/VOPInstructions.td
index acb5b066896..cc4ad934465 100644
--- a/llvm/lib/Target/AMDGPU/VOPInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPInstructions.td
@@ -136,6 +136,8 @@ class VOP3_Real <VOP3_Pseudo ps, int EncodingFamily> :
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
OpenPOWER on IntegriCloud