From: Tom Stellard Date: Tue, 23 Sep 2014 21:26:25 +0000 (+0000) Subject: R600/SI: Clean up checks for legality of immediate operands X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=33aca6d4a090b1305873735dfdc8c8a00e65482e;p=oota-llvm.git R600/SI: Clean up checks for legality of immediate operands There are new register classes VCSrc_* which represent operands that can take an SGPR, VGPR or inline constant. The VSrc_* class is now used to represent operands that can take an SGPR, VGPR, or a 32-bit immediate. This allows us to have more accurate checks for legality of immediates, since before we had no way to distinguish between operands that supported any 32-bit immediate and operands which could only support inline constants. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218334 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/R600/MCTargetDesc/SIMCCodeEmitter.cpp b/lib/Target/R600/MCTargetDesc/SIMCCodeEmitter.cpp index 65f3eb5d99a..999fd0dbc9a 100644 --- a/lib/Target/R600/MCTargetDesc/SIMCCodeEmitter.cpp +++ b/lib/Target/R600/MCTargetDesc/SIMCCodeEmitter.cpp @@ -85,21 +85,13 @@ MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII, bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const { - // FIXME: We need a better way to figure out which operands can be immediate - // values - // - // Some VOP* instructions like ADDC use VReg32 as the register class - // for source 0, because they read VCC and can't take an SGPR as an - // argument due to constant bus restrictions. - if (OpNo == 1 && (Desc.TSFlags & (SIInstrFlags::VOP1 | SIInstrFlags::VOP2 | - SIInstrFlags::VOPC))) - return true; - unsigned RegClass = Desc.OpInfo[OpNo].RegClass; return (AMDGPU::SSrc_32RegClassID == RegClass) || (AMDGPU::SSrc_64RegClassID == RegClass) || (AMDGPU::VSrc_32RegClassID == RegClass) || - (AMDGPU::VSrc_64RegClassID == RegClass); + (AMDGPU::VSrc_64RegClassID == RegClass) || + (AMDGPU::VCSrc_32RegClassID == RegClass) || + (AMDGPU::VCSrc_64RegClassID == RegClass); } uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const { diff --git a/lib/Target/R600/SIISelLowering.cpp b/lib/Target/R600/SIISelLowering.cpp index cb7385d66fa..10b42750c13 100644 --- a/lib/Target/R600/SIISelLowering.cpp +++ b/lib/Target/R600/SIISelLowering.cpp @@ -1498,8 +1498,14 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N, /// \brief Test if RegClass is one of the VSrc classes static bool isVSrc(unsigned RegClass) { - return AMDGPU::VSrc_32RegClassID == RegClass || - AMDGPU::VSrc_64RegClassID == RegClass; + switch(RegClass) { + default: return false; + case AMDGPU::VSrc_32RegClassID: + case AMDGPU::VCSrc_32RegClassID: + case AMDGPU::VSrc_64RegClassID: + case AMDGPU::VCSrc_64RegClassID: + return true; + } } /// \brief Test if RegClass is one of the SSrc classes @@ -1611,10 +1617,9 @@ const TargetRegisterClass *SITargetLowering::getRegClassForNode( // If the COPY_TO_REGCLASS instruction is copying to a VSrc register // class, then the register class for the value could be either a // VReg or and SReg. In order to get a more accurate - if (OpClassID == AMDGPU::VSrc_32RegClassID || - OpClassID == AMDGPU::VSrc_64RegClassID) { + if (isVSrc(OpClassID)) return getRegClassForNode(DAG, Op.getOperand(0)); - } + return TRI.getRegClass(OpClassID); case AMDGPU::EXTRACT_SUBREG: { int SubIdx = cast(Op.getOperand(1))->getZExtValue(); @@ -1648,14 +1653,23 @@ void SITargetLowering::ensureSRegLimit(SelectionDAG &DAG, SDValue &Operand, unsigned RegClass, bool &ScalarSlotUsed) const { - // First map the operands register class to a destination class - if (RegClass == AMDGPU::VSrc_32RegClassID) - RegClass = AMDGPU::VReg_32RegClassID; - else if (RegClass == AMDGPU::VSrc_64RegClassID) - RegClass = AMDGPU::VReg_64RegClassID; - else + if (!isVSrc(RegClass)) return; + // First map the operands register class to a destination class + switch (RegClass) { + case AMDGPU::VSrc_32RegClassID: + case AMDGPU::VCSrc_32RegClassID: + RegClass = AMDGPU::VReg_32RegClassID; + break; + case AMDGPU::VSrc_64RegClassID: + case AMDGPU::VCSrc_64RegClassID: + RegClass = AMDGPU::VReg_64RegClassID; + break; + default: + llvm_unreachable("Unknown vsrc reg class"); + } + // Nothing to do if they fit naturally if (fitsRegClass(DAG, Operand, RegClass)) return; @@ -1745,6 +1759,15 @@ SDNode *SITargetLowering::legalizeOperands(MachineSDNode *Node, // No scalar allowed when we have both VSrc and SSrc bool ScalarSlotUsed = HaveVSrc && HaveSSrc; + // If this instruction has an implicit use of VCC, then it can't use the + // constant bus. + for (unsigned i = 0, e = Desc->getNumImplicitUses(); i != e; ++i) { + if (Desc->ImplicitUses[i] == AMDGPU::VCC) { + ScalarSlotUsed = true; + break; + } + } + // Second go over the operands and try to fold them std::vector Ops; for (unsigned i = 0, e = Node->getNumOperands(), Op = NumDefs; diff --git a/lib/Target/R600/SIInstrInfo.cpp b/lib/Target/R600/SIInstrInfo.cpp index 14d04ff9b1f..eb3faa20487 100644 --- a/lib/Target/R600/SIInstrInfo.cpp +++ b/lib/Target/R600/SIInstrInfo.cpp @@ -747,7 +747,7 @@ bool SIInstrInfo::isImmOperandLegal(const MachineInstr *MI, unsigned OpNo, const MachineOperand &MO) const { const MCOperandInfo &OpInfo = get(MI->getOpcode()).OpInfo[OpNo]; - assert(MO.isImm() || MO.isFPImm()); + assert(MO.isImm() || MO.isFPImm() || MO.isTargetIndex() || MO.isFI()); if (OpInfo.OperandType == MCOI::OPERAND_IMMEDIATE) return true; @@ -755,7 +755,10 @@ bool SIInstrInfo::isImmOperandLegal(const MachineInstr *MI, unsigned OpNo, if (OpInfo.RegClass < 0) return false; - return RI.regClassCanUseImmediate(OpInfo.RegClass); + if (isLiteralConstant(MO)) + return RI.regClassCanUseLiteralConstant(OpInfo.RegClass); + + return RI.regClassCanUseInlineConstant(OpInfo.RegClass); } bool SIInstrInfo::canFoldOffset(unsigned OffsetSize, unsigned AS) { @@ -792,9 +795,41 @@ bool SIInstrInfo::hasModifiers(unsigned Opcode) const { AMDGPU::OpName::src0_modifiers) != -1; } +bool SIInstrInfo::usesConstantBus(const MachineRegisterInfo &MRI, + const MachineOperand &MO) const { + // Literal constants use the constant bus. + if (isLiteralConstant(MO)) + return true; + + if (!MO.isReg() || !MO.isUse()) + return false; + + if (TargetRegisterInfo::isVirtualRegister(MO.getReg())) + return RI.isSGPRClass(MRI.getRegClass(MO.getReg())); + + // FLAT_SCR is just an SGPR pair. + if (!MO.isImplicit() && (MO.getReg() == AMDGPU::FLAT_SCR)) + return true; + + // EXEC register uses the constant bus. + if (!MO.isImplicit() && MO.getReg() == AMDGPU::EXEC) + return true; + + // SGPRs use the constant bus + if (MO.getReg() == AMDGPU::M0 || MO.getReg() == AMDGPU::VCC || + (!MO.isImplicit() && + (AMDGPU::SGPR_32RegClass.contains(MO.getReg()) || + AMDGPU::SGPR_64RegClass.contains(MO.getReg())))) { + return true; + } + + return false; +} + bool SIInstrInfo::verifyInstruction(const MachineInstr *MI, StringRef &ErrInfo) const { uint16_t Opcode = MI->getOpcode(); + const MachineRegisterInfo &MRI = MI->getParent()->getParent()->getRegInfo(); int Src0Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0); int Src1Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1); int Src2Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2); @@ -811,19 +846,12 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr *MI, for (int i = 0, e = Desc.getNumOperands(); i != e; ++i) { switch (Desc.OpInfo[i].OperandType) { case MCOI::OPERAND_REGISTER: { - int RegClass = Desc.OpInfo[i].RegClass; - if (!RI.regClassCanUseImmediate(RegClass) && - (MI->getOperand(i).isImm() || MI->getOperand(i).isFPImm())) { - // Handle some special cases: - // Src0 can of VOP1, VOP2, VOPC can be an immediate no matter what - // the register class. - if (i != Src0Idx || (!isVOP1(Opcode) && !isVOP2(Opcode) && - !isVOPC(Opcode))) { - ErrInfo = "Expected register, but got immediate"; + if ((MI->getOperand(i).isImm() || MI->getOperand(i).isFPImm()) && + !isImmOperandLegal(MI, i, MI->getOperand(i))) { + ErrInfo = "Illegal immediate value for operand."; return false; } } - } break; case MCOI::OPERAND_IMMEDIATE: // Check if this operand is an immediate. @@ -863,31 +891,15 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr *MI, unsigned SGPRUsed = AMDGPU::NoRegister; for (int i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); - if (MO.isReg() && MO.isUse() && - !TargetRegisterInfo::isVirtualRegister(MO.getReg())) { - - // EXEC register uses the constant bus. - if (!MO.isImplicit() && MO.getReg() == AMDGPU::EXEC) - ++ConstantBusCount; - - // FLAT_SCR is just an SGPR pair. - if (!MO.isImplicit() && (MO.getReg() == AMDGPU::FLAT_SCR)) - ++ConstantBusCount; - - // SGPRs use the constant bus - if (MO.getReg() == AMDGPU::M0 || MO.getReg() == AMDGPU::VCC || - (!MO.isImplicit() && - (AMDGPU::SGPR_32RegClass.contains(MO.getReg()) || - AMDGPU::SGPR_64RegClass.contains(MO.getReg())))) { - if (SGPRUsed != MO.getReg()) { + if (usesConstantBus(MRI, MO)) { + if (MO.isReg()) { + if (MO.getReg() != SGPRUsed) ++ConstantBusCount; - SGPRUsed = MO.getReg(); - } + SGPRUsed = MO.getReg(); + } else { + ++ConstantBusCount; } } - // Literal constants use the constant bus. - if (isLiteralConstant(MO)) - ++ConstantBusCount; } if (ConstantBusCount > 1) { ErrInfo = "VOP* instruction uses the constant bus more than once"; @@ -1136,6 +1148,18 @@ bool SIInstrInfo::isOperandLegal(const MachineInstr *MI, unsigned OpIdx, if (!MO) MO = &MI->getOperand(OpIdx); + if (usesConstantBus(MRI, *MO)) { + unsigned SGPRUsed = MO->isReg() ? MO->getReg() : AMDGPU::NoRegister; + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + if (i == OpIdx) + continue; + if (usesConstantBus(MRI, MI->getOperand(i)) && + MI->getOperand(i).isReg() && MI->getOperand(i).getReg() != SGPRUsed) { + return false; + } + } + } + if (MO->isReg()) { assert(DefinedRC); const TargetRegisterClass *RC = MRI.getRegClass(MO->getReg()); @@ -1151,7 +1175,7 @@ bool SIInstrInfo::isOperandLegal(const MachineInstr *MI, unsigned OpIdx, return true; } - return RI.regClassCanUseImmediate(DefinedRC); + return isImmOperandLegal(MI, OpIdx, *MO); } void SIInstrInfo::legalizeOperands(MachineInstr *MI) const { diff --git a/lib/Target/R600/SIInstrInfo.h b/lib/Target/R600/SIInstrInfo.h index 2ccab03c11a..bb9031f8aba 100644 --- a/lib/Target/R600/SIInstrInfo.h +++ b/lib/Target/R600/SIInstrInfo.h @@ -132,6 +132,10 @@ public: /// This function will return false if you pass it a 32-bit instruction. bool hasVALU32BitEncoding(unsigned Opcode) const; + /// \brief Returns true if this operand uses the constant bus. + bool usesConstantBus(const MachineRegisterInfo &MRI, + const MachineOperand &MO) const; + /// \brief Return true if this instruction has any modifiers. /// e.g. src[012]_mod, omod, clamp. bool hasModifiers(unsigned Opcode) const; diff --git a/lib/Target/R600/SIInstrInfo.td b/lib/Target/R600/SIInstrInfo.td index 2d91d496c28..bde90d8ceaa 100644 --- a/lib/Target/R600/SIInstrInfo.td +++ b/lib/Target/R600/SIInstrInfo.td @@ -361,7 +361,7 @@ class getInRC32 SrcVT> { // Returns the register class to use for sources of VOP3 instructions for the // given VT. class getVOP3SrcForVT { - RegisterClass ret = !if(!eq(VT.Size, 32), VSrc_32, VSrc_64); + RegisterClass ret = !if(!eq(VT.Size, 32), VCSrc_32, VCSrc_64); } // Returns the register classes for the source arguments of a VOP3 @@ -494,7 +494,7 @@ def VOP_F64_F64_I32 : VOPProfile <[f64, f64, i32, untyped]>; def VOP_I32_F32_F32 : VOPProfile <[i32, f32, f32, untyped]>; def VOP_I32_I32_I32 : VOPProfile <[i32, i32, i32, untyped]>; def VOP_I32_I32_I32_VCC : VOPProfile <[i32, i32, i32, untyped]> { - let Src0RC32 = VReg_32; + let Src0RC32 = VCSrc_32; } def VOP_I64_I64_I32 : VOPProfile <[i64, i64, i32, untyped]>; def VOP_I64_I64_I64 : VOPProfile <[i64, i64, i64, untyped]>; diff --git a/lib/Target/R600/SIRegisterInfo.cpp b/lib/Target/R600/SIRegisterInfo.cpp index d1666fdd1f6..3924e21003c 100644 --- a/lib/Target/R600/SIRegisterInfo.cpp +++ b/lib/Target/R600/SIRegisterInfo.cpp @@ -275,7 +275,7 @@ unsigned SIRegisterInfo::getPhysRegSubReg(unsigned Reg, return SubRC->getRegister(Index + Channel); } -bool SIRegisterInfo::regClassCanUseImmediate(int RCID) const { +bool SIRegisterInfo::regClassCanUseLiteralConstant(int RCID) const { switch (RCID) { default: return false; case AMDGPU::SSrc_32RegClassID: @@ -286,11 +286,29 @@ bool SIRegisterInfo::regClassCanUseImmediate(int RCID) const { } } -bool SIRegisterInfo::regClassCanUseImmediate( +bool SIRegisterInfo::regClassCanUseLiteralConstant( const TargetRegisterClass *RC) const { - return regClassCanUseImmediate(RC->getID()); + return regClassCanUseLiteralConstant(RC->getID()); } +bool SIRegisterInfo::regClassCanUseInlineConstant(int RCID) const { + if (regClassCanUseLiteralConstant(RCID)) + return true; + + switch (RCID) { + default: return false; + case AMDGPU::VCSrc_32RegClassID: + case AMDGPU::VCSrc_64RegClassID: + return true; + } +} + +bool SIRegisterInfo::regClassCanUseInlineConstant( + const TargetRegisterClass *RC) const { + return regClassCanUseInlineConstant(RC->getID()); +} + + unsigned SIRegisterInfo::getPreloadedValue(const MachineFunction &MF, enum PreloadedValue Value) const { diff --git a/lib/Target/R600/SIRegisterInfo.h b/lib/Target/R600/SIRegisterInfo.h index 112b267fc8a..29b5d0c6d2a 100644 --- a/lib/Target/R600/SIRegisterInfo.h +++ b/lib/Target/R600/SIRegisterInfo.h @@ -68,12 +68,21 @@ struct SIRegisterInfo : public AMDGPURegisterInfo { unsigned Channel) const; /// \returns True if operands defined with this register class can accept - /// inline immediates. - bool regClassCanUseImmediate(int RCID) const; + /// a literal constant (i.e. any 32-bit immediate). + bool regClassCanUseLiteralConstant(int RCID) const; /// \returns True if operands defined with this register class can accept - /// inline immediates. - bool regClassCanUseImmediate(const TargetRegisterClass *RC) const; + /// a literal constant (i.e. any 32-bit immediate). + bool regClassCanUseLiteralConstant(const TargetRegisterClass *RC) const; + + /// \returns True if operands defined with this register class can accept + /// an inline constant. i.e. An integer value in the range (-16, 64) or + /// -4.0f, -2.0f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 2.0f, 4.0f. + bool regClassCanUseInlineConstant(int RCID) const; + + /// \returns True if operands defined with this register class can accept + /// a literal constant. i.e. A value in the range (-16, 64). + bool regClassCanUseInlineConstant(const TargetRegisterClass *RC) const; enum PreloadedValue { TGID_X, diff --git a/lib/Target/R600/SIRegisterInfo.td b/lib/Target/R600/SIRegisterInfo.td index 64f9ca41187..7e00a73ba13 100644 --- a/lib/Target/R600/SIRegisterInfo.td +++ b/lib/Target/R600/SIRegisterInfo.td @@ -210,17 +210,29 @@ def VReg_512 : RegisterClass<"AMDGPU", [v16i32, v16f32], 512, (add VGPR_512)>; def VReg_1 : RegisterClass<"AMDGPU", [i1], 32, (add VGPR_32)>; //===----------------------------------------------------------------------===// -// [SV]Src_(32|64) register classes, can have either an immediate or an register +// SSrc_* Operands with an SGPR or a 32-bit immediate //===----------------------------------------------------------------------===// def SSrc_32 : RegisterClass<"AMDGPU", [i32, f32], 32, (add SReg_32)>; def SSrc_64 : RegisterClass<"AMDGPU", [i64, f64, i1], 64, (add SReg_64)>; +//===----------------------------------------------------------------------===// +// VSrc_* Operands with an SGPR, VGPR or a 32-bit immediate +//===----------------------------------------------------------------------===// + def VSrc_32 : RegisterClass<"AMDGPU", [i32, f32], 32, (add VReg_32, SReg_32)>; def VSrc_64 : RegisterClass<"AMDGPU", [i64, f64], 64, (add VReg_64, SReg_64)>; +//===----------------------------------------------------------------------===// +// VCSrc_* Operands with an SGPR, VGPR or an inline constant +//===----------------------------------------------------------------------===// + +def VCSrc_32 : RegisterClass<"AMDGPU", [i32, f32], 32, (add VReg_32, SReg_32)>; + +def VCSrc_64 : RegisterClass<"AMDGPU", [i64, f64], 64, (add VReg_64, SReg_64)>; + //===----------------------------------------------------------------------===// // SGPR and VGPR register classes //===----------------------------------------------------------------------===//