diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-12-02 21:02:54 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-12-02 21:02:54 +0000 |
| commit | f65dcba83ce5035ab88a85fe17628b447eb56e1b (patch) | |
| tree | 35f37bb72b3cfc6060193e66c76ee7c9478969b0 /llvm/lib/Target/AMDGPU | |
| parent | 846a2208a8ab099f595fe7e8b2e6d54a7b5e67fb (diff) | |
Diffstat (limited to 'llvm/lib/Target/AMDGPU')
46 files changed, 828 insertions, 316 deletions
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCombine.td b/llvm/lib/Target/AMDGPU/AMDGPUCombine.td index df2f9a0fa3a9..c7c5ff7bcbe7 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUCombine.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUCombine.td @@ -26,6 +26,14 @@ def uchar_to_float : GICombineRule< [{ return PostLegalizerHelper.matchUCharToFloat(*${itofp}); }]), (apply [{ PostLegalizerHelper.applyUCharToFloat(*${itofp}); }])>; + +def rcp_sqrt_to_rsq : GICombineRule< + (defs root:$rcp, build_fn_matchinfo:$matchinfo), + (match (wip_match_opcode G_INTRINSIC, G_FSQRT):$rcp, + [{ return PostLegalizerHelper.matchRcpSqrtToRsq(*${rcp}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFn(*${rcp}, ${matchinfo}); }])>; + + def cvt_f32_ubyteN_matchdata : GIDefMatchData<"AMDGPUPostLegalizerCombinerHelper::CvtF32UByteMatchInfo">; def cvt_f32_ubyteN : GICombineRule< @@ -86,7 +94,8 @@ def AMDGPUPreLegalizerCombinerHelper: GICombinerHelper< def AMDGPUPostLegalizerCombinerHelper: GICombinerHelper< "AMDGPUGenPostLegalizerCombinerHelper", [all_combines, gfx6gfx7_combines, - uchar_to_float, cvt_f32_ubyteN, remove_fcanonicalize, foldable_fneg]> { + uchar_to_float, cvt_f32_ubyteN, remove_fcanonicalize, foldable_fneg, + rcp_sqrt_to_rsq]> { let DisableRuleOption = "amdgpupostlegalizercombiner-disable-rule"; let StateClass = "AMDGPUPostLegalizerCombinerHelperState"; let AdditionalArguments = []; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp index cee56ee97294..8236e6672247 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp @@ -654,6 +654,9 @@ void AMDGPUDAGToDAGISel::Select(SDNode *N) { SelectMAD_64_32(N); return; } + case ISD::SMUL_LOHI: + case ISD::UMUL_LOHI: + return SelectMUL_LOHI(N); case ISD::CopyToReg: { const SITargetLowering& Lowering = *static_cast<const SITargetLowering*>(getTargetLowering()); @@ -719,6 +722,18 @@ bool AMDGPUDAGToDAGISel::isUniformBr(const SDNode *N) const { Term->getMetadata("structurizecfg.uniform"); } +bool AMDGPUDAGToDAGISel::isUnneededShiftMask(const SDNode *N, + unsigned ShAmtBits) const { + assert(N->getOpcode() == ISD::AND); + + const APInt &RHS = cast<ConstantSDNode>(N->getOperand(1))->getAPIntValue(); + if (RHS.countTrailingOnes() >= ShAmtBits) + return true; + + const APInt &LHSKnownZeros = CurDAG->computeKnownBits(N->getOperand(0)).Zero; + return (LHSKnownZeros | RHS).countTrailingOnes() >= ShAmtBits; +} + static bool getBaseWithOffsetUsingSplitOR(SelectionDAG &DAG, SDValue Addr, SDValue &N0, SDValue &N1) { if (Addr.getValueType() == MVT::i64 && Addr.getOpcode() == ISD::BITCAST && @@ -1001,6 +1016,32 @@ void AMDGPUDAGToDAGISel::SelectMAD_64_32(SDNode *N) { CurDAG->SelectNodeTo(N, Opc, N->getVTList(), Ops); } +// We need to handle this here because tablegen doesn't support matching +// instructions with multiple outputs. +void AMDGPUDAGToDAGISel::SelectMUL_LOHI(SDNode *N) { + SDLoc SL(N); + bool Signed = N->getOpcode() == ISD::SMUL_LOHI; + unsigned Opc = Signed ? AMDGPU::V_MAD_I64_I32_e64 : AMDGPU::V_MAD_U64_U32_e64; + + SDValue Zero = CurDAG->getTargetConstant(0, SL, MVT::i64); + SDValue Clamp = CurDAG->getTargetConstant(0, SL, MVT::i1); + SDValue Ops[] = {N->getOperand(0), N->getOperand(1), Zero, Clamp}; + SDNode *Mad = CurDAG->getMachineNode(Opc, SL, N->getVTList(), Ops); + if (!SDValue(N, 0).use_empty()) { + SDValue Sub0 = CurDAG->getTargetConstant(AMDGPU::sub0, SL, MVT::i32); + SDNode *Lo = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, SL, + MVT::i32, SDValue(Mad, 0), Sub0); + ReplaceUses(SDValue(N, 0), SDValue(Lo, 0)); + } + if (!SDValue(N, 1).use_empty()) { + SDValue Sub1 = CurDAG->getTargetConstant(AMDGPU::sub1, SL, MVT::i32); + SDNode *Hi = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, SL, + MVT::i32, SDValue(Mad, 0), Sub1); + ReplaceUses(SDValue(N, 1), SDValue(Hi, 0)); + } + CurDAG->RemoveDeadNode(N); +} + bool AMDGPUDAGToDAGISel::isDSOffsetLegal(SDValue Base, unsigned Offset) const { if (!isUInt<16>(Offset)) return false; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h index c1d9673f067e..d638d9877a9b 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h @@ -136,6 +136,10 @@ private: bool isUniformLoad(const SDNode *N) const; bool isUniformBr(const SDNode *N) const; + // Returns true if ISD::AND SDNode `N`'s masking of the shift amount operand's + // `ShAmtBits` bits is unneeded. + bool isUnneededShiftMask(const SDNode *N, unsigned ShAmtBits) const; + bool isBaseWithConstantOffset64(SDValue Addr, SDValue &LHS, SDValue &RHS) const; @@ -231,6 +235,7 @@ private: void SelectUADDO_USUBO(SDNode *N); void SelectDIV_SCALE(SDNode *N); void SelectMAD_64_32(SDNode *N); + void SelectMUL_LOHI(SDNode *N); void SelectFMA_W_CHAIN(SDNode *N); void SelectFMUL_W_CHAIN(SDNode *N); SDNode *getBFE32(bool IsSigned, const SDLoc &DL, SDValue Val, uint32_t Offset, diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index 523fa2d3724b..54177564afbc 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -594,6 +594,8 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM, setTargetDAGCombine(ISD::SRL); setTargetDAGCombine(ISD::TRUNCATE); setTargetDAGCombine(ISD::MUL); + setTargetDAGCombine(ISD::SMUL_LOHI); + setTargetDAGCombine(ISD::UMUL_LOHI); setTargetDAGCombine(ISD::MULHU); setTargetDAGCombine(ISD::MULHS); setTargetDAGCombine(ISD::SELECT); @@ -3462,6 +3464,50 @@ SDValue AMDGPUTargetLowering::performMulCombine(SDNode *N, return DAG.getSExtOrTrunc(Mul, DL, VT); } +SDValue +AMDGPUTargetLowering::performMulLoHiCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + if (N->getValueType(0) != MVT::i32) + return SDValue(); + + SelectionDAG &DAG = DCI.DAG; + SDLoc DL(N); + + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + + // SimplifyDemandedBits has the annoying habit of turning useful zero_extends + // in the source into any_extends if the result of the mul is truncated. Since + // we can assume the high bits are whatever we want, use the underlying value + // to avoid the unknown high bits from interfering. + if (N0.getOpcode() == ISD::ANY_EXTEND) + N0 = N0.getOperand(0); + if (N1.getOpcode() == ISD::ANY_EXTEND) + N1 = N1.getOperand(0); + + // Try to use two fast 24-bit multiplies (one for each half of the result) + // instead of one slow extending multiply. + unsigned LoOpcode, HiOpcode; + if (Subtarget->hasMulU24() && isU24(N0, DAG) && isU24(N1, DAG)) { + N0 = DAG.getZExtOrTrunc(N0, DL, MVT::i32); + N1 = DAG.getZExtOrTrunc(N1, DL, MVT::i32); + LoOpcode = AMDGPUISD::MUL_U24; + HiOpcode = AMDGPUISD::MULHI_U24; + } else if (Subtarget->hasMulI24() && isI24(N0, DAG) && isI24(N1, DAG)) { + N0 = DAG.getSExtOrTrunc(N0, DL, MVT::i32); + N1 = DAG.getSExtOrTrunc(N1, DL, MVT::i32); + LoOpcode = AMDGPUISD::MUL_I24; + HiOpcode = AMDGPUISD::MULHI_I24; + } else { + return SDValue(); + } + + SDValue Lo = DAG.getNode(LoOpcode, DL, MVT::i32, N0, N1); + SDValue Hi = DAG.getNode(HiOpcode, DL, MVT::i32, N0, N1); + DCI.CombineTo(N, Lo, Hi); + return SDValue(N, 0); +} + SDValue AMDGPUTargetLowering::performMulhsCombine(SDNode *N, DAGCombinerInfo &DCI) const { EVT VT = N->getValueType(0); @@ -4103,6 +4149,9 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N, return performTruncateCombine(N, DCI); case ISD::MUL: return performMulCombine(N, DCI); + case ISD::SMUL_LOHI: + case ISD::UMUL_LOHI: + return performMulLoHiCombine(N, DCI); case ISD::MULHS: return performMulhsCombine(N, DCI); case ISD::MULHU: diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h index 03632ac18598..daaca8737c5d 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -91,6 +91,7 @@ protected: SDValue performSrlCombine(SDNode *N, DAGCombinerInfo &DCI) const; SDValue performTruncateCombine(SDNode *N, DAGCombinerInfo &DCI) const; SDValue performMulCombine(SDNode *N, DAGCombinerInfo &DCI) const; + SDValue performMulLoHiCombine(SDNode *N, DAGCombinerInfo &DCI) const; SDValue performMulhsCombine(SDNode *N, DAGCombinerInfo &DCI) const; SDValue performMulhuCombine(SDNode *N, DAGCombinerInfo &DCI) const; SDValue performCtlz_CttzCombine(const SDLoc &SL, SDValue Cond, SDValue LHS, diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp index 28cb2fc57ac7..e16bead81b65 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp @@ -3880,6 +3880,22 @@ bool AMDGPUInstructionSelector::isDSOffset2Legal(Register Base, int64_t Offset0, return KnownBits->signBitIsZero(Base); } +bool AMDGPUInstructionSelector::isUnneededShiftMask(const MachineInstr &MI, + unsigned ShAmtBits) const { + assert(MI.getOpcode() == TargetOpcode::G_AND); + + Optional<APInt> RHS = getIConstantVRegVal(MI.getOperand(2).getReg(), *MRI); + if (!RHS) + return false; + + if (RHS->countTrailingOnes() >= ShAmtBits) + return true; + + const APInt &LHSKnownZeros = + KnownBits->getKnownZeroes(MI.getOperand(1).getReg()); + return (LHSKnownZeros | *RHS).countTrailingOnes() >= ShAmtBits; +} + InstructionSelector::ComplexRendererFns AMDGPUInstructionSelector::selectMUBUFScratchOffset( MachineOperand &Root) const { diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h index b70e6883bae2..26996e42af53 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h @@ -300,6 +300,10 @@ private: bool isInlineImmediate64(int64_t Imm) const; bool isInlineImmediate(const APFloat &Imm) const; + // Returns true if TargetOpcode::G_AND MachineInstr `MI`'s masking of the + // shift amount operand's `ShAmtBits` bits is unneeded. + bool isUnneededShiftMask(const MachineInstr &MI, unsigned ShAmtBits) const; + const SIInstrInfo &TII; const SIRegisterInfo &TRI; const AMDGPURegisterBankInfo &RBI; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td b/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td index bad9f6265b36..0528b552f475 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td @@ -242,25 +242,41 @@ def AMDGPUmul_i24_oneuse : HasOneUseBinOp<AMDGPUmul_i24>; //===----------------------------------------------------------------------===// // Constrained shift PatFrags. + +def csh_mask_16 : PatFrag<(ops node:$src0), (and node:$src0, imm), + [{ return isUnneededShiftMask(N, 4); }]> { + let GISelPredicateCode = [{ return isUnneededShiftMask(MI, 4); }]; + } + +def csh_mask_32 : PatFrag<(ops node:$src0), (and node:$src0, imm), + [{ return isUnneededShiftMask(N, 5); }]> { + let GISelPredicateCode = [{ return isUnneededShiftMask(MI, 5); }]; + } + +def csh_mask_64 : PatFrag<(ops node:$src0), (and node:$src0, imm), + [{ return isUnneededShiftMask(N, 6); }]> { + let GISelPredicateCode = [{ return isUnneededShiftMask(MI, 6); }]; + } + foreach width = [16, 32, 64] in { -defvar mask = !sub(width, 1); +defvar csh_mask = !cast<SDPatternOperator>("csh_mask_"#width); def cshl_#width : PatFrags<(ops node:$src0, node:$src1), - [(shl node:$src0, node:$src1), (shl node:$src0, (and node:$src1, mask))]>; + [(shl node:$src0, node:$src1), (shl node:$src0, (csh_mask node:$src1))]>; defvar cshl = !cast<SDPatternOperator>("cshl_"#width); def cshl_#width#_oneuse : HasOneUseBinOp<cshl>; def clshl_rev_#width : PatFrag <(ops node:$src0, node:$src1), (cshl $src1, $src0)>; def csrl_#width : PatFrags<(ops node:$src0, node:$src1), - [(srl node:$src0, node:$src1), (srl node:$src0, (and node:$src1, mask))]>; + [(srl node:$src0, node:$src1), (srl node:$src0, (csh_mask node:$src1))]>; defvar csrl = !cast<SDPatternOperator>("csrl_"#width); def csrl_#width#_oneuse : HasOneUseBinOp<csrl>; def clshr_rev_#width : PatFrag <(ops node:$src0, node:$src1), (csrl $src1, $src0)>; def csra_#width : PatFrags<(ops node:$src0, node:$src1), - [(sra node:$src0, node:$src1), (sra node:$src0, (and node:$src1, mask))]>; + [(sra node:$src0, node:$src1), (sra node:$src0, (csh_mask node:$src1))]>; defvar csra = !cast<SDPatternOperator>("csra_"#width); def csra_#width#_oneuse : HasOneUseBinOp<csra>; def cashr_rev_#width : PatFrag <(ops node:$src0, node:$src1), @@ -696,11 +712,6 @@ class RcpPat<Instruction RcpInst, ValueType vt> : AMDGPUPat < (RcpInst $src) >; -class RsqPat<Instruction RsqInst, ValueType vt> : AMDGPUPat < - (AMDGPUrcp (fsqrt vt:$src)), - (RsqInst $src) ->; - // Instructions which select to the same v_min_f* def fminnum_like : PatFrags<(ops node:$src0, node:$src1), [(fminnum_ieee node:$src0, node:$src1), diff --git a/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp b/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp index fc984d2dda64..1479933a2850 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp @@ -23,6 +23,7 @@ #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/IntrinsicsAMDGPU.h" #include "llvm/Target/TargetMachine.h" #define DEBUG_TYPE "amdgpu-postlegalizer-combiner" @@ -58,6 +59,9 @@ public: bool matchUCharToFloat(MachineInstr &MI); void applyUCharToFloat(MachineInstr &MI); + bool matchRcpSqrtToRsq(MachineInstr &MI, + std::function<void(MachineIRBuilder &)> &MatchInfo); + // FIXME: Should be able to have 2 separate matchdatas rather than custom // struct boilerplate. struct CvtF32UByteMatchInfo { @@ -203,6 +207,48 @@ void AMDGPUPostLegalizerCombinerHelper::applyUCharToFloat(MachineInstr &MI) { MI.eraseFromParent(); } +bool AMDGPUPostLegalizerCombinerHelper::matchRcpSqrtToRsq( + MachineInstr &MI, std::function<void(MachineIRBuilder &)> &MatchInfo) { + + auto getRcpSrc = [=](const MachineInstr &MI) { + MachineInstr *ResMI = nullptr; + if (MI.getOpcode() == TargetOpcode::G_INTRINSIC && + MI.getIntrinsicID() == Intrinsic::amdgcn_rcp) + ResMI = MRI.getVRegDef(MI.getOperand(2).getReg()); + + return ResMI; + }; + + auto getSqrtSrc = [=](const MachineInstr &MI) { + MachineInstr *SqrtSrcMI = nullptr; + mi_match(MI.getOperand(0).getReg(), MRI, m_GFSqrt(m_MInstr(SqrtSrcMI))); + return SqrtSrcMI; + }; + + MachineInstr *RcpSrcMI = nullptr, *SqrtSrcMI = nullptr; + // rcp(sqrt(x)) + if ((RcpSrcMI = getRcpSrc(MI)) && (SqrtSrcMI = getSqrtSrc(*RcpSrcMI))) { + MatchInfo = [SqrtSrcMI, &MI](MachineIRBuilder &B) { + B.buildIntrinsic(Intrinsic::amdgcn_rsq, {MI.getOperand(0)}, false) + .addUse(SqrtSrcMI->getOperand(0).getReg()) + .setMIFlags(MI.getFlags()); + }; + return true; + } + + // sqrt(rcp(x)) + if ((SqrtSrcMI = getSqrtSrc(MI)) && (RcpSrcMI = getRcpSrc(*SqrtSrcMI))) { + MatchInfo = [RcpSrcMI, &MI](MachineIRBuilder &B) { + B.buildIntrinsic(Intrinsic::amdgcn_rsq, {MI.getOperand(0)}, false) + .addUse(RcpSrcMI->getOperand(0).getReg()) + .setMIFlags(MI.getFlags()); + }; + return true; + } + + return false; +} + bool AMDGPUPostLegalizerCombinerHelper::matchCvtF32UByteN( MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo) { Register SrcReg = MI.getOperand(1).getReg(); diff --git a/llvm/lib/Target/AMDGPU/AMDGPUPrintfRuntimeBinding.cpp b/llvm/lib/Target/AMDGPU/AMDGPUPrintfRuntimeBinding.cpp index d560d2043f42..7c4eb71882c7 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUPrintfRuntimeBinding.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUPrintfRuntimeBinding.cpp @@ -280,10 +280,10 @@ bool AMDGPUPrintfRuntimeBindingImpl::lowerPrintfForGpu(Module &M) { } LLVM_DEBUG(dbgs() << "Printf format string in source = " << Str.str() << '\n'); - for (size_t I = 0; I < Str.size(); ++I) { + for (char C : Str) { // Rest of the C escape sequences (e.g. \') are handled correctly // by the MDParser - switch (Str[I]) { + switch (C) { case '\a': Sizes << "\\a"; break; @@ -308,7 +308,7 @@ bool AMDGPUPrintfRuntimeBindingImpl::lowerPrintfForGpu(Module &M) { Sizes << "\\72"; break; default: - Sizes << Str[I]; + Sizes << C; break; } } diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp index d7dc9ee4117b..12b5830ef930 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp @@ -45,6 +45,7 @@ public: TRI(*MF.getSubtarget().getRegisterInfo()), Helper(Helper){}; bool isVgprRegBank(Register Reg); + Register getAsVgpr(Register Reg); struct MinMaxMedOpc { unsigned Min, Max, Med; @@ -69,6 +70,23 @@ bool AMDGPURegBankCombinerHelper::isVgprRegBank(Register Reg) { return RBI.getRegBank(Reg, MRI, TRI)->getID() == AMDGPU::VGPRRegBankID; } +Register AMDGPURegBankCombinerHelper::getAsVgpr(Register Reg) { + if (isVgprRegBank(Reg)) + return Reg; + + // Search for existing copy of Reg to vgpr. + for (MachineInstr &Use : MRI.use_instructions(Reg)) { + Register Def = Use.getOperand(0).getReg(); + if (Use.getOpcode() == AMDGPU::COPY && isVgprRegBank(Def)) + return Def; + } + + // Copy Reg to vgpr. + Register VgprReg = B.buildCopy(MRI.getType(Reg), Reg).getReg(0); + MRI.setRegBank(VgprReg, RBI.getRegBank(AMDGPU::VGPRRegBankID)); + return VgprReg; +} + AMDGPURegBankCombinerHelper::MinMaxMedOpc AMDGPURegBankCombinerHelper::getMinMaxPair(unsigned Opc) { switch (Opc) { @@ -134,7 +152,9 @@ void AMDGPURegBankCombinerHelper::applyMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) { B.setInstrAndDebugLoc(MI); B.buildInstr(MatchInfo.Opc, {MI.getOperand(0)}, - {MatchInfo.Val0, MatchInfo.Val1, MatchInfo.Val2}, MI.getFlags()); + {getAsVgpr(MatchInfo.Val0), getAsVgpr(MatchInfo.Val1), + getAsVgpr(MatchInfo.Val2)}, + MI.getFlags()); MI.eraseFromParent(); } diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp index ab3ce980c3f6..5988403c0a29 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp @@ -3189,10 +3189,10 @@ unsigned AMDGPURegisterBankInfo::getMappingType(const MachineRegisterInfo &MRI, const MachineInstr &MI) const { unsigned RegBank = AMDGPU::InvalidRegBankID; - for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { - if (!MI.getOperand(i).isReg()) + for (const MachineOperand &MO : MI.operands()) { + if (!MO.isReg()) continue; - Register Reg = MI.getOperand(i).getReg(); + Register Reg = MO.getReg(); if (const RegisterBank *Bank = getRegBank(Reg, MRI, *TRI)) { RegBank = regBankUnion(RegBank, Bank->getID()); if (RegBank == AMDGPU::VGPRRegBankID) @@ -3206,10 +3206,10 @@ unsigned AMDGPURegisterBankInfo::getMappingType(const MachineRegisterInfo &MRI, bool AMDGPURegisterBankInfo::isSALUMapping(const MachineInstr &MI) const { const MachineFunction &MF = *MI.getParent()->getParent(); const MachineRegisterInfo &MRI = MF.getRegInfo(); - for (unsigned i = 0, e = MI.getNumOperands();i != e; ++i) { - if (!MI.getOperand(i).isReg()) + for (const MachineOperand &MO : MI.operands()) { + if (!MO.isReg()) continue; - Register Reg = MI.getOperand(i).getReg(); + Register Reg = MO.getReg(); if (const RegisterBank *Bank = getRegBank(Reg, MRI, *TRI)) { if (Bank->getID() != AMDGPU::SGPRRegBankID) return false; diff --git a/llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp b/llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp index 1a9255f3240f..712f6dece911 100644 --- a/llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp +++ b/llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp @@ -706,9 +706,7 @@ bool AMDGPUCFGStructurizer::prepare() { // Remove unconditional branch instr. // Add dummy exit block iff there are multiple returns. - for (SmallVectorImpl<MachineBasicBlock *>::const_iterator - It = OrderedBlks.begin(), E = OrderedBlks.end(); It != E; ++It) { - MachineBasicBlock *MBB = *It; + for (MachineBasicBlock *MBB : OrderedBlks) { removeUnconditionalBranch(MBB); removeRedundantConditionalBranch(MBB); if (isReturnBlock(MBB)) { @@ -851,14 +849,10 @@ bool AMDGPUCFGStructurizer::run() { void AMDGPUCFGStructurizer::orderBlocks(MachineFunction *MF) { int SccNum = 0; - MachineBasicBlock *MBB; for (scc_iterator<MachineFunction *> It = scc_begin(MF); !It.isAtEnd(); ++It, ++SccNum) { const std::vector<MachineBasicBlock *> &SccNext = *It; - for (std::vector<MachineBasicBlock *>::const_iterator - blockIter = SccNext.begin(), blockEnd = SccNext.end(); - blockIter != blockEnd; ++blockIter) { - MBB = *blockIter; + for (MachineBasicBlock *MBB : SccNext) { OrderedBlks.push_back(MBB); recordSccnum(MBB, SccNum); } @@ -1601,11 +1595,8 @@ void AMDGPUCFGStructurizer::addDummyExitBlock( FuncRep->push_back(DummyExitBlk); //insert to function insertInstrEnd(DummyExitBlk, R600::RETURN); - for (SmallVectorImpl<MachineBasicBlock *>::iterator It = RetMBB.begin(), - E = RetMBB.end(); It != E; ++It) { - MachineBasicBlock *MBB = *It; - MachineInstr *MI = getReturnInstr(MBB); - if (MI) + for (MachineBasicBlock *MBB : RetMBB) { + if (MachineInstr *MI = getReturnInstr(MBB)) MI->eraseFromParent(); MBB->addSuccessor(DummyExitBlk); LLVM_DEBUG(dbgs() << "Add dummyExitBlock to BB" << MBB->getNumber() diff --git a/llvm/lib/Target/AMDGPU/CaymanInstructions.td b/llvm/lib/Target/AMDGPU/CaymanInstructions.td index f4ddbf1131c3..d18dab0554bd 100644 --- a/llvm/lib/Target/AMDGPU/CaymanInstructions.td +++ b/llvm/lib/Target/AMDGPU/CaymanInstructions.td @@ -48,8 +48,6 @@ def SIN_cm : SIN_Common<0x8D>; def COS_cm : COS_Common<0x8E>; } // End isVector = 1 -def : RsqPat<RECIPSQRT_IEEE_cm, f32>; - def : SqrtPat<RECIPSQRT_IEEE_cm, RECIP_IEEE_cm>; def : POW_Common <LOG_IEEE_cm, EXP_IEEE_cm, MUL>; diff --git a/llvm/lib/Target/AMDGPU/EvergreenInstructions.td b/llvm/lib/Target/AMDGPU/EvergreenInstructions.td index 12224cb3f797..a9a3421e8192 100644 --- a/llvm/lib/Target/AMDGPU/EvergreenInstructions.td +++ b/llvm/lib/Target/AMDGPU/EvergreenInstructions.td @@ -126,7 +126,6 @@ def EXP_IEEE_eg : EXP_IEEE_Common<0x81>; def LOG_IEEE_eg : LOG_IEEE_Common<0x83>; def RECIP_CLAMPED_eg : RECIP_CLAMPED_Common<0x84>; def RECIPSQRT_IEEE_eg : RECIPSQRT_IEEE_Common<0x89>; -def : RsqPat<RECIPSQRT_IEEE_eg, f32>; def : SqrtPat<RECIPSQRT_IEEE_eg, RECIP_IEEE_eg>; def SIN_eg : SIN_Common<0x8D>; diff --git a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp index ff5d0b0af6a4..0f8dd0b3bf58 100644 --- a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp +++ b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp @@ -1442,12 +1442,10 @@ int GCNHazardRecognizer::checkMAIHazards90A(MachineInstr *MI) { bool FullReg; const MachineInstr *MI1; - auto IsOverlappedDGEMMorXDLFn = [Reg, &IsMFMAFn, &FullReg, &MI1, - this](const MachineInstr &MI) { + auto IsOverlappedMFMAFn = [Reg, &IsMFMAFn, &FullReg, &MI1, + this](const MachineInstr &MI) { if (!IsMFMAFn(MI)) return false; - if (!isDGEMM(MI.getOpcode()) && !isXDL(ST, MI)) - return false; Register DstReg = MI.getOperand(0).getReg(); FullReg = (DstReg == Reg); MI1 = &MI; @@ -1458,8 +1456,8 @@ int GCNHazardRecognizer::checkMAIHazards90A(MachineInstr *MI) { getWaitStatesSinceDef(Reg, IsLegacyVALUNotDotFn, MaxWaitStates); WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); - int NumWaitStates = getWaitStatesSinceDef(Reg, IsOverlappedDGEMMorXDLFn, - MaxWaitStates); + int NumWaitStates = + getWaitStatesSinceDef(Reg, IsOverlappedMFMAFn, MaxWaitStates); if (NumWaitStates == std::numeric_limits<int>::max()) continue; @@ -1619,12 +1617,9 @@ int GCNHazardRecognizer::checkMAIVALUHazards(MachineInstr *MI) { const MachineInstr *MFMA = nullptr; unsigned Reg; - auto IsDGEMMorXDLWriteFn = [&Reg, &IsMFMAFn, &MFMA, - this](const MachineInstr &MI) { + auto IsMFMAWriteFn = [&Reg, &IsMFMAFn, &MFMA, this](const MachineInstr &MI) { if (!IsMFMAFn(MI) || !TRI.regsOverlap(MI.getOperand(0).getReg(), Reg)) return false; - if (!isDGEMM(MI.getOpcode()) && !isXDL(ST, MI)) - return false; MFMA = &MI; return true; }; @@ -1675,8 +1670,8 @@ int GCNHazardRecognizer::checkMAIVALUHazards(MachineInstr *MI) { } MFMA = nullptr; - WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDGEMMorXDLWriteFn, - MaxWaitStates); + WaitStatesSinceDef = + getWaitStatesSinceDef(Reg, IsMFMAWriteFn, MaxWaitStates); if (!MFMA) continue; @@ -1750,8 +1745,8 @@ int GCNHazardRecognizer::checkMAIVALUHazards(MachineInstr *MI) { WaitStatesSinceDef); MFMA = nullptr; - WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDGEMMorXDLWriteFn, - MaxWaitStates); + WaitStatesSinceDef = + getWaitStatesSinceDef(Reg, IsMFMAWriteFn, MaxWaitStates); if (MFMA) { int NeedWaitStates = MaxWaitStates; switch (TSchedModel.computeInstrLatency(MFMA)) { diff --git a/llvm/lib/Target/AMDGPU/GCNRegPressure.cpp b/llvm/lib/Target/AMDGPU/GCNRegPressure.cpp index 3456f9a6156c..82c09378acac 100644 --- a/llvm/lib/Target/AMDGPU/GCNRegPressure.cpp +++ b/llvm/lib/Target/AMDGPU/GCNRegPressure.cpp @@ -74,11 +74,11 @@ unsigned GCNRegPressure::getRegKind(Register Reg, assert(Reg.isVirtual()); const auto RC = MRI.getRegClass(Reg); auto STI = static_cast<const SIRegisterInfo*>(MRI.getTargetRegisterInfo()); - return STI->isSGPRClass(RC) ? - (STI->getRegSizeInBits(*RC) == 32 ? SGPR32 : SGPR_TUPLE) : - STI->hasAGPRs(RC) ? - (STI->getRegSizeInBits(*RC) == 32 ? AGPR32 : AGPR_TUPLE) : - (STI->getRegSizeInBits(*RC) == 32 ? VGPR32 : VGPR_TUPLE); + return STI->isSGPRClass(RC) + ? (STI->getRegSizeInBits(*RC) == 32 ? SGPR32 : SGPR_TUPLE) + : STI->isAGPRClass(RC) + ? (STI->getRegSizeInBits(*RC) == 32 ? AGPR32 : AGPR_TUPLE) + : (STI->getRegSizeInBits(*RC) == 32 ? VGPR32 : VGPR_TUPLE); } void GCNRegPressure::inc(unsigned Reg, diff --git a/llvm/lib/Target/AMDGPU/R600ClauseMergePass.cpp b/llvm/lib/Target/AMDGPU/R600ClauseMergePass.cpp index 1d93165f9eec..715fd69fc7ae 100644 --- a/llvm/lib/Target/AMDGPU/R600ClauseMergePass.cpp +++ b/llvm/lib/Target/AMDGPU/R600ClauseMergePass.cpp @@ -177,9 +177,7 @@ bool R600ClauseMergePass::runOnMachineFunction(MachineFunction &MF) { const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>(); TII = ST.getInstrInfo(); - for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end(); - BB != BB_E; ++BB) { - MachineBasicBlock &MBB = *BB; + for (MachineBasicBlock &MBB : MF) { MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); MachineBasicBlock::iterator LatestCFAlu = E; while (I != E) { diff --git a/llvm/lib/Target/AMDGPU/R600EmitClauseMarkers.cpp b/llvm/lib/Target/AMDGPU/R600EmitClauseMarkers.cpp index d5eaa33ef964..b9ca7f928d56 100644 --- a/llvm/lib/Target/AMDGPU/R600EmitClauseMarkers.cpp +++ b/llvm/lib/Target/AMDGPU/R600EmitClauseMarkers.cpp @@ -301,9 +301,7 @@ public: const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>(); TII = ST.getInstrInfo(); - for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end(); - BB != BB_E; ++BB) { - MachineBasicBlock &MBB = *BB; + for (MachineBasicBlock &MBB : MF) { MachineBasicBlock::iterator I = MBB.begin(); if (I != MBB.end() && I->getOpcode() == R600::CF_ALU) continue; // BB was already parsed diff --git a/llvm/lib/Target/AMDGPU/R600ExpandSpecialInstrs.cpp b/llvm/lib/Target/AMDGPU/R600ExpandSpecialInstrs.cpp index 838a497b4df1..194879fef53c 100644 --- a/llvm/lib/Target/AMDGPU/R600ExpandSpecialInstrs.cpp +++ b/llvm/lib/Target/AMDGPU/R600ExpandSpecialInstrs.cpp @@ -73,9 +73,7 @@ bool R600ExpandSpecialInstrsPass::runOnMachineFunction(MachineFunction &MF) { const R600RegisterInfo &TRI = TII->getRegisterInfo(); - for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end(); - BB != BB_E; ++BB) { - MachineBasicBlock &MBB = *BB; + for (MachineBasicBlock &MBB : MF) { MachineBasicBlock::iterator I = MBB.begin(); while (I != MBB.end()) { MachineInstr &MI = *I; diff --git a/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp b/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp index 0215eb9f9fea..bd757e9e3d70 100644 --- a/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp @@ -285,9 +285,8 @@ R600TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, NewMI = BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(R600::getLDSNoRetOp(MI.getOpcode()))); - for (unsigned i = 1, e = MI.getNumOperands(); i < e; ++i) { - NewMI.add(MI.getOperand(i)); - } + for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) + NewMI.add(MO); } else { return AMDGPUTargetLowering::EmitInstrWithCustomInserter(MI, BB); } diff --git a/llvm/lib/Target/AMDGPU/R600Instructions.td b/llvm/lib/Target/AMDGPU/R600Instructions.td index 4487864888b6..b3da2fdefacc 100644 --- a/llvm/lib/Target/AMDGPU/R600Instructions.td +++ b/llvm/lib/Target/AMDGPU/R600Instructions.td @@ -1265,7 +1265,6 @@ let Predicates = [isR600] in { defm DIV_r600 : DIV_Common<RECIP_IEEE_r600>; def : POW_Common <LOG_IEEE_r600, EXP_IEEE_r600, MUL>; - def : RsqPat<RECIPSQRT_IEEE_r600, f32>; def : SqrtPat<RECIPSQRT_IEEE_r600, RECIP_IEEE_r600>; def R600_ExportSwz : ExportSwzInst { diff --git a/llvm/lib/Target/AMDGPU/R600MachineScheduler.cpp b/llvm/lib/Target/AMDGPU/R600MachineScheduler.cpp index 36acfafa72aa..6aee2f591b56 100644 --- a/llvm/lib/Target/AMDGPU/R600MachineScheduler.cpp +++ b/llvm/lib/Target/AMDGPU/R600MachineScheduler.cpp @@ -124,11 +124,9 @@ SUnit* R600SchedStrategy::pickNode(bool &IsTopNode) { DAG->dumpNode(*SU); } else { dbgs() << "NO NODE \n"; - for (unsigned i = 0; i < DAG->SUnits.size(); i++) { - const SUnit &S = DAG->SUnits[i]; + for (const SUnit &S : DAG->SUnits) if (!S.isScheduled) DAG->dumpNode(S); - } }); return SU; diff --git a/llvm/lib/Target/AMDGPU/R600OptimizeVectorRegisters.cpp b/llvm/lib/Target/AMDGPU/R600OptimizeVectorRegisters.cpp index 1a723279dc9f..72cf48c04e7f 100644 --- a/llvm/lib/Target/AMDGPU/R600OptimizeVectorRegisters.cpp +++ b/llvm/lib/Target/AMDGPU/R600OptimizeVectorRegisters.cpp @@ -323,14 +323,12 @@ bool R600VectorRegMerger::runOnMachineFunction(MachineFunction &Fn) { TII = ST.getInstrInfo(); MRI = &Fn.getRegInfo(); - for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); - MBB != MBBe; ++MBB) { - MachineBasicBlock *MB = &*MBB; + for (MachineBasicBlock &MB : Fn) { PreviousRegSeq.clear(); PreviousRegSeqByReg.clear(); PreviousRegSeqByUndefCount.clear(); - for (MachineBasicBlock::iterator MII = MB->begin(), MIIE = MB->end(); + for (MachineBasicBlock::iterator MII = MB.begin(), MIIE = MB.end(); MII != MIIE; ++MII) { MachineInstr &MI = *MII; if (MI.getOpcode() != R600::REG_SEQUENCE) { diff --git a/llvm/lib/Target/AMDGPU/R600Packetizer.cpp b/llvm/lib/Target/AMDGPU/R600Packetizer.cpp index e858bba2983c..beb0aad86e89 100644 --- a/llvm/lib/Target/AMDGPU/R600Packetizer.cpp +++ b/llvm/lib/Target/AMDGPU/R600Packetizer.cpp @@ -343,20 +343,11 @@ bool R600Packetizer::runOnMachineFunction(MachineFunction &Fn) { // dependence between Insn 0 and Insn 2. This can lead to incorrect // packetization // - for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); - MBB != MBBe; ++MBB) { - MachineBasicBlock::iterator End = MBB->end(); - MachineBasicBlock::iterator MI = MBB->begin(); - while (MI != End) { - if (MI->isKill() || MI->getOpcode() == R600::IMPLICIT_DEF || - (MI->getOpcode() == R600::CF_ALU && !MI->getOperand(8).getImm())) { - MachineBasicBlock::iterator DeleteMI = MI; - ++MI; - MBB->erase(DeleteMI); - End = MBB->end(); - continue; - } - ++MI; + for (MachineBasicBlock &MBB : Fn) { + for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) { + if (MI.isKill() || MI.getOpcode() == R600::IMPLICIT_DEF || + (MI.getOpcode() == R600::CF_ALU && !MI.getOperand(8).getImm())) + MBB.erase(MI); } } diff --git a/llvm/lib/Target/AMDGPU/SIDefines.h b/llvm/lib/Target/AMDGPU/SIDefines.h index 777744f08cde..580e4bc417a4 100644 --- a/llvm/lib/Target/AMDGPU/SIDefines.h +++ b/llvm/lib/Target/AMDGPU/SIDefines.h @@ -18,7 +18,8 @@ namespace llvm { enum SIRCFlags : uint8_t { // For vector registers. HasVGPR = 1 << 0, - HasAGPR = 1 << 1 + HasAGPR = 1 << 1, + HasSGPR = 1 << 2 }; // enum SIRCFlags namespace SIInstrFlags { diff --git a/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp b/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp index cf93a63f26a0..f54778535b7c 100644 --- a/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp +++ b/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp @@ -127,11 +127,11 @@ FunctionPass *llvm::createSIFixSGPRCopiesPass() { static bool hasVectorOperands(const MachineInstr &MI, const SIRegisterInfo *TRI) { const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); - for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { - if (!MI.getOperand(i).isReg() || !MI.getOperand(i).getReg().isVirtual()) + for (const MachineOperand &MO : MI.operands()) { + if (!MO.isReg() || !MO.getReg().isVirtual()) continue; - if (TRI->hasVectorRegisters(MRI.getRegClass(MI.getOperand(i).getReg()))) + if (TRI->hasVectorRegisters(MRI.getRegClass(MO.getReg()))) return true; } return false; @@ -259,7 +259,7 @@ static bool foldVGPRCopyIntoRegSequence(MachineInstr &MI, // VGPRz = REG_SEQUENCE VGPRx, sub0 MI.getOperand(0).setReg(CopyUse.getOperand(0).getReg()); - bool IsAGPR = TRI->hasAGPRs(DstRC); + bool IsAGPR = TRI->isAGPRClass(DstRC); for (unsigned I = 1, N = MI.getNumOperands(); I != N; I += 2) { Register SrcReg = MI.getOperand(I).getReg(); @@ -853,7 +853,7 @@ MachineBasicBlock *SIFixSGPRCopies::processPHINode(MachineInstr &MI) { Register PHIRes = MI.getOperand(0).getReg(); const TargetRegisterClass *RC0 = MRI->getRegClass(PHIRes); - if (AllAGPRUses && numVGPRUses && !TRI->hasAGPRs(RC0)) { + if (AllAGPRUses && numVGPRUses && !TRI->isAGPRClass(RC0)) { LLVM_DEBUG(dbgs() << "Moving PHI to AGPR: " << MI); MRI->setRegClass(PHIRes, TRI->getEquivalentAGPRClass(RC0)); for (unsigned I = 1, N = MI.getNumOperands(); I != N; I += 2) { diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index a3a0e9c9b9ac..200e00ee5521 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -1586,17 +1586,9 @@ bool SIFoldOperands::tryFoldRegSequence(MachineInstr &MI) { unsigned OpIdx = Op - &UseMI->getOperand(0); const MCInstrDesc &InstDesc = UseMI->getDesc(); - const MCOperandInfo &OpInfo = InstDesc.OpInfo[OpIdx]; - switch (OpInfo.RegClass) { - case AMDGPU::AV_32RegClassID: LLVM_FALLTHROUGH; - case AMDGPU::AV_64RegClassID: LLVM_FALLTHROUGH; - case AMDGPU::AV_96RegClassID: LLVM_FALLTHROUGH; - case AMDGPU::AV_128RegClassID: LLVM_FALLTHROUGH; - case AMDGPU::AV_160RegClassID: - break; - default: + if (!TRI->isVectorSuperClass( + TRI->getRegClass(InstDesc.OpInfo[OpIdx].RegClass))) return false; - } const auto *NewDstRC = TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg)); auto Dst = MRI->createVirtualRegister(NewDstRC); diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp index 882b9a203755..4706c74be721 100644 --- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp @@ -1364,6 +1364,34 @@ bool SIFrameLowering::assignCalleeSavedSpillSlots( return false; } +bool SIFrameLowering::allocateScavengingFrameIndexesNearIncomingSP( + const MachineFunction &MF) const { + + const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); + uint64_t EstStackSize = MFI.estimateStackSize(MF); + uint64_t MaxOffset = EstStackSize - 1; + + // We need the emergency stack slots to be allocated in range of the + // MUBUF/flat scratch immediate offset from the base register, so assign these + // first at the incoming SP position. + // + // TODO: We could try sorting the objects to find a hole in the first bytes + // rather than allocating as close to possible. This could save a lot of space + // on frames with alignment requirements. + if (ST.enableFlatScratch()) { + const SIInstrInfo *TII = ST.getInstrInfo(); + if (TII->isLegalFLATOffset(MaxOffset, AMDGPUAS::PRIVATE_ADDRESS, + SIInstrFlags::FlatScratch)) + return false; + } else { + if (SIInstrInfo::isLegalMUBUFImmOffset(MaxOffset)) + return false; + } + + return true; +} + MachineBasicBlock::iterator SIFrameLowering::eliminateCallFramePseudoInstr( MachineFunction &MF, MachineBasicBlock &MBB, diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/llvm/lib/Target/AMDGPU/SIFrameLowering.h index 951ea79b2809..56fbb875ffd9 100644 --- a/llvm/lib/Target/AMDGPU/SIFrameLowering.h +++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.h @@ -43,6 +43,9 @@ public: const TargetRegisterInfo *TRI, std::vector<CalleeSavedInfo> &CSI) const override; + bool allocateScavengingFrameIndexesNearIncomingSP( + const MachineFunction &MF) const override; + bool isSupportedStackID(TargetStackID::Value ID) const override; void processFunctionBeforeFrameFinalized( diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index 519c5b936536..35b72f5d201b 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -809,6 +809,11 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction(ISD::SMULO, MVT::i64, Custom); setOperationAction(ISD::UMULO, MVT::i64, Custom); + if (Subtarget->hasMad64_32()) { + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Custom); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Custom); + } + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::f32, Custom); setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::v4f32, Custom); @@ -919,6 +924,16 @@ bool SITargetLowering::isFPExtFoldable(const SelectionDAG &DAG, unsigned Opcode, !hasFP32Denormals(DAG.getMachineFunction()); } +bool SITargetLowering::isFPExtFoldable(const MachineInstr &MI, unsigned Opcode, + LLT DestTy, LLT SrcTy) const { + return ((Opcode == TargetOpcode::G_FMAD && Subtarget->hasMadMixInsts()) || + (Opcode == TargetOpcode::G_FMA && Subtarget->hasFmaMixInsts())) && + DestTy.getScalarSizeInBits() == 32 && + SrcTy.getScalarSizeInBits() == 16 && + // TODO: This probably only requires no input flushing? + !hasFP32Denormals(*MI.getMF()); +} + bool SITargetLowering::isShuffleMaskLegal(ArrayRef<int>, EVT) const { // SI has some legal vector types, but no legal vector operations. Say no // shuffles are legal in order to prefer scalarizing some vector operations. @@ -4290,8 +4305,8 @@ MachineBasicBlock *SITargetLowering::EmitInstrWithCustomInserter( MachineInstrBuilder MIB; MIB = BuildMI(*BB, MI, DL, TII->get(AMDGPU::SI_CALL), ReturnAddrReg); - for (unsigned I = 0, E = MI.getNumOperands(); I != E; ++I) - MIB.add(MI.getOperand(I)); + for (const MachineOperand &MO : MI.operands()) + MIB.add(MO); MIB.cloneMemRefs(MI); MI.eraseFromParent(); @@ -4457,6 +4472,8 @@ bool SITargetLowering::enableAggressiveFMAFusion(EVT VT) const { return true; } +bool SITargetLowering::enableAggressiveFMAFusion(LLT Ty) const { return true; } + EVT SITargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &Ctx, EVT VT) const { if (!VT.isVector()) { @@ -4522,6 +4539,34 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, return false; } +bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, + LLT Ty) const { + switch (Ty.getScalarSizeInBits()) { + case 16: + return isFMAFasterThanFMulAndFAdd(MF, MVT::f16); + case 32: + return isFMAFasterThanFMulAndFAdd(MF, MVT::f32); + case 64: + return isFMAFasterThanFMulAndFAdd(MF, MVT::f64); + default: + break; + } + + return false; +} + +bool SITargetLowering::isFMADLegal(const MachineInstr &MI, LLT Ty) const { + if (!Ty.isScalar()) + return false; + + if (Ty.getScalarSizeInBits() == 16) + return Subtarget->hasMadF16() && !hasFP64FP16Denormals(*MI.getMF()); + if (Ty.getScalarSizeInBits() == 32) + return Subtarget->hasMadMacF32Insts() && !hasFP32Denormals(*MI.getMF()); + + return false; +} + bool SITargetLowering::isFMADLegal(const SelectionDAG &DAG, const SDNode *N) const { // TODO: Check future ftz flag @@ -4691,6 +4736,9 @@ SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::SMULO: case ISD::UMULO: return lowerXMULO(Op, DAG); + case ISD::SMUL_LOHI: + case ISD::UMUL_LOHI: + return lowerXMUL_LOHI(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); } @@ -5304,6 +5352,21 @@ SDValue SITargetLowering::lowerXMULO(SDValue Op, SelectionDAG &DAG) const { return DAG.getMergeValues({ Result, Overflow }, SL); } +SDValue SITargetLowering::lowerXMUL_LOHI(SDValue Op, SelectionDAG &DAG) const { + if (Op->isDivergent()) { + // Select to V_MAD_[IU]64_[IU]32. + return Op; + } + if (Subtarget->hasSMulHi()) { + // Expand to S_MUL_I32 + S_MUL_HI_[IU]32. + return SDValue(); + } + // The multiply is uniform but we would have to use V_MUL_HI_[IU]32 to + // calculate the high part, so we might as well do the whole thing with + // V_MAD_[IU]64_[IU]32. + return Op; +} + SDValue SITargetLowering::lowerTRAP(SDValue Op, SelectionDAG &DAG) const { if (!Subtarget->isTrapHandlerEnabled() || Subtarget->getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA) @@ -9790,10 +9853,9 @@ bool SITargetLowering::isCanonicalized(Register Reg, MachineFunction &MF, if (Subtarget->supportsMinMaxDenormModes() || denormalsEnabledForType(MRI.getType(Reg), MF)) return true; - for (unsigned I = 1, E = MI->getNumOperands(); I != E; ++I) { - if (!isCanonicalized(MI->getOperand(I).getReg(), MF, MaxDepth - 1)) + for (const MachineOperand &MO : llvm::drop_begin(MI->operands())) + if (!isCanonicalized(MO.getReg(), MF, MaxDepth - 1)) return false; - } return true; } default: @@ -11460,15 +11522,15 @@ void SITargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI, if (I == -1) break; MachineOperand &Op = MI.getOperand(I); - if ((OpInfo[I].RegClass != llvm::AMDGPU::AV_64RegClassID && - OpInfo[I].RegClass != llvm::AMDGPU::AV_32RegClassID) || - !Op.getReg().isVirtual() || !TRI->isAGPR(MRI, Op.getReg())) + if (!Op.isReg() || !Op.getReg().isVirtual()) + continue; + auto *RC = TRI->getRegClassForReg(MRI, Op.getReg()); + if (!TRI->hasAGPRs(RC)) continue; auto *Src = MRI.getUniqueVRegDef(Op.getReg()); if (!Src || !Src->isCopy() || !TRI->isSGPRReg(MRI, Src->getOperand(1).getReg())) continue; - auto *RC = TRI->getRegClassForReg(MRI, Op.getReg()); auto *NewRC = TRI->getEquivalentVGPRClass(RC); // All uses of agpr64 and agpr32 can also accept vgpr except for // v_accvgpr_read, but we do not produce agpr reads during selection, diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h index 1e48c96ad3c8..1315cc15dd02 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.h +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h @@ -135,6 +135,7 @@ private: SDValue lowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFMINNUM_FMAXNUM(SDValue Op, SelectionDAG &DAG) const; SDValue lowerXMULO(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerXMUL_LOHI(SDValue Op, SelectionDAG &DAG) const; SDValue getSegmentAperture(unsigned AS, const SDLoc &DL, SelectionDAG &DAG) const; @@ -252,6 +253,9 @@ public: bool isFPExtFoldable(const SelectionDAG &DAG, unsigned Opcode, EVT DestVT, EVT SrcVT) const override; + bool isFPExtFoldable(const MachineInstr &MI, unsigned Opcode, LLT DestTy, + LLT SrcTy) const override; + bool isShuffleMaskLegal(ArrayRef<int> /*Mask*/, EVT /*VT*/) const override; bool getTgtMemIntrinsic(IntrinsicInfo &, const CallInst &, @@ -377,6 +381,7 @@ public: bool hasBitPreservingFPLogic(EVT VT) const override; bool enableAggressiveFMAFusion(EVT VT) const override; + bool enableAggressiveFMAFusion(LLT Ty) const override; EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override; MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override; @@ -384,7 +389,10 @@ public: bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, EVT VT) const override; + bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, + const LLT Ty) const override; bool isFMADLegal(const SelectionDAG &DAG, const SDNode *N) const override; + bool isFMADLegal(const MachineInstr &MI, const LLT Ty) const override; SDValue splitUnaryVectorOp(SDValue Op, SelectionDAG &DAG) const; SDValue splitBinaryVectorOp(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp index f4e5771d2a2a..c9d9dd1fb82c 100644 --- a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp +++ b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp @@ -150,6 +150,8 @@ enum VmemType { VMEM_NOSAMPLER, // MIMG instructions with a sampler. VMEM_SAMPLER, + // BVH instructions + VMEM_BVH }; VmemType getVmemType(const MachineInstr &Inst) { @@ -157,9 +159,10 @@ VmemType getVmemType(const MachineInstr &Inst) { if (!SIInstrInfo::isMIMG(Inst)) return VMEM_NOSAMPLER; const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(Inst.getOpcode()); - return AMDGPU::getMIMGBaseOpcodeInfo(Info->BaseOpcode)->Sampler - ? VMEM_SAMPLER - : VMEM_NOSAMPLER; + const AMDGPU::MIMGBaseOpcodeInfo *BaseInfo = + AMDGPU::getMIMGBaseOpcodeInfo(Info->BaseOpcode); + return BaseInfo->BVH ? VMEM_BVH + : BaseInfo->Sampler ? VMEM_SAMPLER : VMEM_NOSAMPLER; } void addWait(AMDGPU::Waitcnt &Wait, InstCounterType T, unsigned Count) { diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp index 4a928123b68f..92f5322b8ad2 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp +++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp @@ -898,10 +898,10 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB, unsigned EltSize = 4; unsigned Opcode = AMDGPU::V_MOV_B32_e32; - if (RI.hasAGPRs(RC)) { + if (RI.isAGPRClass(RC)) { Opcode = (RI.hasVGPRs(SrcRC)) ? AMDGPU::V_ACCVGPR_WRITE_B32_e64 : AMDGPU::INSTRUCTION_LIST_END; - } else if (RI.hasVGPRs(RC) && RI.hasAGPRs(SrcRC)) { + } else if (RI.hasVGPRs(RC) && RI.isAGPRClass(SrcRC)) { Opcode = AMDGPU::V_ACCVGPR_READ_B32_e64; } else if ((Size % 64 == 0) && RI.hasVGPRs(RC) && (RI.isProperlyAlignedRC(*RC) && @@ -1205,7 +1205,7 @@ Register SIInstrInfo::insertNE(MachineBasicBlock *MBB, unsigned SIInstrInfo::getMovOpcode(const TargetRegisterClass *DstRC) const { - if (RI.hasAGPRs(DstRC)) + if (RI.isAGPRClass(DstRC)) return AMDGPU::COPY; if (RI.getRegSizeInBits(*DstRC) == 32) { return RI.isSGPRClass(DstRC) ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32; @@ -1435,6 +1435,7 @@ void SIInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, FrameInfo.getObjectAlign(FrameIndex)); unsigned SpillSize = TRI->getSpillSize(*RC); + MachineRegisterInfo &MRI = MF->getRegInfo(); if (RI.isSGPRClass(RC)) { MFI->setHasSpilledSGPRs(); assert(SrcReg != AMDGPU::M0 && "m0 should not be spilled"); @@ -1448,7 +1449,6 @@ void SIInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, // The SGPR spill/restore instructions only work on number sgprs, so we need // to make sure we are using the correct register class. if (SrcReg.isVirtual() && SpillSize == 4) { - MachineRegisterInfo &MRI = MF->getRegInfo(); MRI.constrainRegClass(SrcReg, &AMDGPU::SReg_32_XM0_XEXECRegClass); } @@ -1463,10 +1463,21 @@ void SIInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, return; } - unsigned Opcode = RI.hasAGPRs(RC) ? getAGPRSpillSaveOpcode(SpillSize) - : getVGPRSpillSaveOpcode(SpillSize); + unsigned Opcode = RI.isAGPRClass(RC) ? getAGPRSpillSaveOpcode(SpillSize) + : getVGPRSpillSaveOpcode(SpillSize); MFI->setHasSpilledVGPRs(); + if (RI.isVectorSuperClass(RC)) { + // Convert an AV spill into a VGPR spill. Introduce a copy from AV to an + // equivalent VGPR register beforehand. Regalloc might want to introduce + // AV spills only to be relevant until rewriter at which they become + // either spills of VGPRs or AGPRs. + Register TmpVReg = MRI.createVirtualRegister(RI.getEquivalentVGPRClass(RC)); + BuildMI(MBB, MI, DL, get(TargetOpcode::COPY), TmpVReg) + .addReg(SrcReg, RegState::Kill); + SrcReg = TmpVReg; + } + BuildMI(MBB, MI, DL, get(Opcode)) .addReg(SrcReg, getKillRegState(isKill)) // data .addFrameIndex(FrameIndex) // addr @@ -1598,13 +1609,26 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, return; } - unsigned Opcode = RI.hasAGPRs(RC) ? getAGPRSpillRestoreOpcode(SpillSize) - : getVGPRSpillRestoreOpcode(SpillSize); + unsigned Opcode = RI.isAGPRClass(RC) ? getAGPRSpillRestoreOpcode(SpillSize) + : getVGPRSpillRestoreOpcode(SpillSize); + + bool IsVectorSuperClass = RI.isVectorSuperClass(RC); + Register TmpReg = DestReg; + if (IsVectorSuperClass) { + // For AV classes, insert the spill restore to a VGPR followed by a copy + // into an equivalent AV register. + MachineRegisterInfo &MRI = MF->getRegInfo(); + DestReg = MRI.createVirtualRegister(RI.getEquivalentVGPRClass(RC)); + } BuildMI(MBB, MI, DL, get(Opcode), DestReg) .addFrameIndex(FrameIndex) // vaddr .addReg(MFI->getStackPtrOffsetReg()) // scratch_offset .addImm(0) // offset .addMemOperand(MMO); + + if (IsVectorSuperClass) + BuildMI(MBB, MI, DL, get(TargetOpcode::COPY), TmpReg) + .addReg(DestReg, RegState::Kill); } void SIInstrInfo::insertNoop(MachineBasicBlock &MBB, @@ -2802,12 +2826,11 @@ bool SIInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI, } if (Is16Bit) { - if (isVGPRCopy) - return false; // Do not clobber vgpr_hi16 + if (isVGPRCopy) + return false; // Do not clobber vgpr_hi16 - if (DstReg.isVirtual() && - UseMI.getOperand(0).getSubReg() != AMDGPU::lo16) - return false; + if (DstReg.isVirtual() && UseMI.getOperand(0).getSubReg() != AMDGPU::lo16) + return false; UseMI.getOperand(0).setSubReg(0); if (DstReg.isPhysical()) { @@ -3896,9 +3919,7 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI, // verification is broken anyway if (ST.needsAlignedVGPRs()) { const TargetRegisterClass *RC = RI.getRegClassForReg(MRI, Reg); - const bool IsVGPR = RI.hasVGPRs(RC); - const bool IsAGPR = !IsVGPR && RI.hasAGPRs(RC); - if ((IsVGPR || IsAGPR) && MO.getSubReg()) { + if (RI.hasVectorRegisters(RC) && MO.getSubReg()) { const TargetRegisterClass *SubRC = RI.getSubRegClass(RC, MO.getSubReg()); RC = RI.getCompatibleSubRegClass(RC, SubRC, MO.getSubReg()); @@ -5522,13 +5543,13 @@ SIInstrInfo::legalizeOperands(MachineInstr &MI, if (getOpRegClass(MI, 0) == &AMDGPU::VReg_1RegClass) { VRC = &AMDGPU::VReg_1RegClass; } else - VRC = RI.hasAGPRs(getOpRegClass(MI, 0)) + VRC = RI.isAGPRClass(getOpRegClass(MI, 0)) ? RI.getEquivalentAGPRClass(SRC) : RI.getEquivalentVGPRClass(SRC); } else { - VRC = RI.hasAGPRs(getOpRegClass(MI, 0)) - ? RI.getEquivalentAGPRClass(VRC) - : RI.getEquivalentVGPRClass(VRC); + VRC = RI.isAGPRClass(getOpRegClass(MI, 0)) + ? RI.getEquivalentAGPRClass(VRC) + : RI.getEquivalentVGPRClass(VRC); } RC = VRC; } else { @@ -7065,8 +7086,8 @@ const TargetRegisterClass *SIInstrInfo::getDestEquivalentVGPRClass( case AMDGPU::STRICT_WWM: case AMDGPU::STRICT_WQM: { const TargetRegisterClass *SrcRC = getOpRegClass(Inst, 1); - if (RI.hasAGPRs(SrcRC)) { - if (RI.hasAGPRs(NewDstRC)) + if (RI.isAGPRClass(SrcRC)) { + if (RI.isAGPRClass(NewDstRC)) return nullptr; switch (Inst.getOpcode()) { @@ -7082,7 +7103,7 @@ const TargetRegisterClass *SIInstrInfo::getDestEquivalentVGPRClass( if (!NewDstRC) return nullptr; } else { - if (RI.hasVGPRs(NewDstRC) || NewDstRC == &AMDGPU::VReg_1RegClass) + if (RI.isVGPRClass(NewDstRC) || NewDstRC == &AMDGPU::VReg_1RegClass) return nullptr; NewDstRC = RI.getEquivalentVGPRClass(NewDstRC); diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td index 8c24268e379e..47ee83eb9351 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td +++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td @@ -2246,7 +2246,7 @@ class VOP_NO_EXT <VOPProfile p> : VOPProfile <p.ArgVT> { let HasExtSDWA9 = 0; } -class VOP_PAT_GEN <VOPProfile p, int mode=PatGenMode.Pattern> : VOPProfile <p.ArgVT> { +class VOP_PAT_GEN <VOPProfile p, int mode=PatGenMode.NoPattern> : VOPProfile <p.ArgVT> { let NeedPatGen = mode; } diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td index d5f9cb8ba493..d55d8da8699a 100644 --- a/llvm/lib/Target/AMDGPU/SIInstructions.td +++ b/llvm/lib/Target/AMDGPU/SIInstructions.td @@ -827,10 +827,6 @@ def : Pat < let OtherPredicates = [UnsafeFPMath] in { -//defm : RsqPat<V_RSQ_F32_e32, f32>; - -def : RsqPat<V_RSQ_F32_e32, f32>; - // Convert (x - floor(x)) to fract(x) def : GCNPat < (f32 (fsub (f32 (VOP3Mods f32:$x, i32:$mods)), @@ -1372,61 +1368,48 @@ def : GCNPat < >; } + /********** ================================ **********/ /********** Floating point absolute/negative **********/ /********** ================================ **********/ -// Prevent expanding both fneg and fabs. -// TODO: Add IgnoredBySelectionDAG bit? -let AddedComplexity = 1 in { // Prefer SALU to VALU patterns for DAG - def : GCNPat < - (fneg (fabs (f32 SReg_32:$src))), + (UniformUnaryFrag<fneg> (fabs (f32 SReg_32:$src))), (S_OR_B32 SReg_32:$src, (S_MOV_B32 (i32 0x80000000))) // Set sign bit >; def : GCNPat < - (fabs (f32 SReg_32:$src)), + (UniformUnaryFrag<fabs> (f32 SReg_32:$src)), (S_AND_B32 SReg_32:$src, (S_MOV_B32 (i32 0x7fffffff))) >; def : GCNPat < - (fneg (f32 SReg_32:$src)), + (UniformUnaryFrag<fneg> (f32 SReg_32:$src)), (S_XOR_B32 SReg_32:$src, (S_MOV_B32 (i32 0x80000000))) >; def : GCNPat < - (fneg (f16 SReg_32:$src)), + (UniformUnaryFrag<fneg> (f16 SReg_32:$src)), (S_XOR_B32 SReg_32:$src, (S_MOV_B32 (i32 0x00008000))) >; def : GCNPat < - (fneg (f16 VGPR_32:$src)), - (V_XOR_B32_e32 (S_MOV_B32 (i32 0x00008000)), VGPR_32:$src) ->; - -def : GCNPat < - (fabs (f16 SReg_32:$src)), + (UniformUnaryFrag<fabs> (f16 SReg_32:$src)), (S_AND_B32 SReg_32:$src, (S_MOV_B32 (i32 0x00007fff))) >; def : GCNPat < - (fneg (fabs (f16 SReg_32:$src))), + (UniformUnaryFrag<fneg> (fabs (f16 SReg_32:$src))), (S_OR_B32 SReg_32:$src, (S_MOV_B32 (i32 0x00008000))) // Set sign bit >; def : GCNPat < - (fneg (fabs (f16 VGPR_32:$src))), - (V_OR_B32_e32 (S_MOV_B32 (i32 0x00008000)), VGPR_32:$src) // Set sign bit ->; - -def : GCNPat < - (fneg (v2f16 SReg_32:$src)), + (UniformUnaryFrag<fneg> (v2f16 SReg_32:$src)), (S_XOR_B32 SReg_32:$src, (S_MOV_B32 (i32 0x80008000))) >; def : GCNPat < - (fabs (v2f16 SReg_32:$src)), + (UniformUnaryFrag<fabs> (v2f16 SReg_32:$src)), (S_AND_B32 SReg_32:$src, (S_MOV_B32 (i32 0x7fff7fff))) >; @@ -1435,51 +1418,20 @@ def : GCNPat < // fabs is not reported as free because there is modifier for it in // VOP3P instructions, so it is turned into the bit op. def : GCNPat < - (fneg (v2f16 (bitconvert (and_oneuse (i32 SReg_32:$src), 0x7fff7fff)))), + (UniformUnaryFrag<fneg> (v2f16 (bitconvert (and_oneuse (i32 SReg_32:$src), 0x7fff7fff)))), (S_OR_B32 SReg_32:$src, (S_MOV_B32 (i32 0x80008000))) // Set sign bit >; def : GCNPat < - (fneg (v2f16 (fabs SReg_32:$src))), + (UniformUnaryFrag<fneg> (v2f16 (fabs SReg_32:$src))), (S_OR_B32 SReg_32:$src, (S_MOV_B32 (i32 0x80008000))) // Set sign bit >; -// FIXME: The implicit-def of scc from S_[X]OR/AND_B32 is mishandled - // def : GCNPat < -// (fneg (f64 SReg_64:$src)), -// (REG_SEQUENCE SReg_64, -// (i32 (EXTRACT_SUBREG SReg_64:$src, sub0)), -// sub0, -// (S_XOR_B32 (i32 (EXTRACT_SUBREG SReg_64:$src, sub1)), -// (i32 (S_MOV_B32 (i32 0x80000000)))), -// sub1) -// >; - -// def : GCNPat < -// (fneg (fabs (f64 SReg_64:$src))), -// (REG_SEQUENCE SReg_64, -// (i32 (EXTRACT_SUBREG SReg_64:$src, sub0)), -// sub0, -// (S_OR_B32 (i32 (EXTRACT_SUBREG SReg_64:$src, sub1)), -// (S_MOV_B32 (i32 0x80000000))), // Set sign bit. -// sub1) -// >; - -// FIXME: Use S_BITSET0_B32/B64? -// def : GCNPat < -// (fabs (f64 SReg_64:$src)), -// (REG_SEQUENCE SReg_64, -// (i32 (EXTRACT_SUBREG SReg_64:$src, sub0)), -// sub0, -// (S_AND_B32 (i32 (EXTRACT_SUBREG SReg_64:$src, sub1)), -// (i32 (S_MOV_B32 (i32 0x7fffffff)))), -// sub1) -// >; // COPY_TO_REGCLASS is needed to avoid using SCC from S_XOR_B32 instead // of the real value. def : GCNPat < - (fneg (v2f32 SReg_64:$src)), + (UniformUnaryFrag<fneg> (v2f32 SReg_64:$src)), (v2f32 (REG_SEQUENCE SReg_64, (f32 (COPY_TO_REGCLASS (S_XOR_B32 (i32 (EXTRACT_SUBREG $src, sub0)), (i32 (S_MOV_B32 (i32 0x80000000)))), @@ -1489,36 +1441,103 @@ def : GCNPat < SReg_32)), sub1)) >; -} // End let AddedComplexity = 1 +def : GCNPat < + (UniformUnaryFrag<fabs> (v2f32 SReg_64:$src)), + (v2f32 (REG_SEQUENCE SReg_64, + (f32 (COPY_TO_REGCLASS (S_AND_B32 (i32 (EXTRACT_SUBREG $src, sub0)), + (i32 (S_MOV_B32 (i32 0x7fffffff)))), + SReg_32)), sub0, + (f32 (COPY_TO_REGCLASS (S_AND_B32 (i32 (EXTRACT_SUBREG $src, sub1)), + (i32 (S_MOV_B32 (i32 0x7fffffff)))), + SReg_32)), sub1)) +>; + +def : GCNPat < + (UniformUnaryFrag<fneg> (fabs (v2f32 SReg_64:$src))), + (v2f32 (REG_SEQUENCE SReg_64, + (f32 (COPY_TO_REGCLASS (S_OR_B32 (i32 (EXTRACT_SUBREG $src, sub0)), + (i32 (S_MOV_B32 (i32 0x80000000)))), + SReg_32)), sub0, + (f32 (COPY_TO_REGCLASS (S_OR_B32 (i32 (EXTRACT_SUBREG $src, sub1)), + (i32 (S_MOV_B32 (i32 0x80000000)))), + SReg_32)), sub1)) +>; + +// FIXME: Use S_BITSET0_B32/B64? +def : GCNPat < + (UniformUnaryFrag<fabs> (f64 SReg_64:$src)), + (REG_SEQUENCE SReg_64, + (i32 (EXTRACT_SUBREG SReg_64:$src, sub0)), + sub0, + (i32 (COPY_TO_REGCLASS (S_AND_B32 (i32 (EXTRACT_SUBREG SReg_64:$src, sub1)), + (S_MOV_B32 (i32 0x7fffffff))), SReg_32)), // Set sign bit. + sub1) +>; + +def : GCNPat < + (UniformUnaryFrag<fneg> (f64 SReg_64:$src)), + (REG_SEQUENCE SReg_64, + (i32 (EXTRACT_SUBREG SReg_64:$src, sub0)), + sub0, + (i32 (COPY_TO_REGCLASS (S_XOR_B32 (i32 (EXTRACT_SUBREG SReg_64:$src, sub1)), + (i32 (S_MOV_B32 (i32 0x80000000)))), SReg_32)), + sub1) +>; + +def : GCNPat < + (UniformUnaryFrag<fneg> (fabs (f64 SReg_64:$src))), + (REG_SEQUENCE SReg_64, + (i32 (EXTRACT_SUBREG SReg_64:$src, sub0)), + sub0, + (i32 (COPY_TO_REGCLASS (S_OR_B32 (i32 (EXTRACT_SUBREG SReg_64:$src, sub1)), + (S_MOV_B32 (i32 0x80000000))), SReg_32)),// Set sign bit. + sub1) +>; + + +def : GCNPat < + (fneg (fabs (f32 VGPR_32:$src))), + (V_OR_B32_e64 (S_MOV_B32 (i32 0x80000000)), VGPR_32:$src) // Set sign bit +>; def : GCNPat < (fabs (f32 VGPR_32:$src)), - (V_AND_B32_e32 (S_MOV_B32 (i32 0x7fffffff)), VGPR_32:$src) + (V_AND_B32_e64 (S_MOV_B32 (i32 0x7fffffff)), VGPR_32:$src) >; def : GCNPat < (fneg (f32 VGPR_32:$src)), - (V_XOR_B32_e32 (S_MOV_B32 (i32 0x80000000)), VGPR_32:$src) + (V_XOR_B32_e64 (S_MOV_B32 (i32 0x80000000)), VGPR_32:$src) >; def : GCNPat < (fabs (f16 VGPR_32:$src)), - (V_AND_B32_e32 (S_MOV_B32 (i32 0x00007fff)), VGPR_32:$src) + (V_AND_B32_e64 (S_MOV_B32 (i32 0x00007fff)), VGPR_32:$src) +>; + +def : GCNPat < + (fneg (f16 VGPR_32:$src)), + (V_XOR_B32_e64 (S_MOV_B32 (i32 0x00008000)), VGPR_32:$src) +>; + +def : GCNPat < + (fneg (fabs (f16 VGPR_32:$src))), + (V_OR_B32_e64 (S_MOV_B32 (i32 0x00008000)), VGPR_32:$src) // Set sign bit >; def : GCNPat < (fneg (v2f16 VGPR_32:$src)), - (V_XOR_B32_e32 (S_MOV_B32 (i32 0x80008000)), VGPR_32:$src) + (V_XOR_B32_e64 (S_MOV_B32 (i32 0x80008000)), VGPR_32:$src) >; def : GCNPat < (fabs (v2f16 VGPR_32:$src)), - (V_AND_B32_e32 (S_MOV_B32 (i32 0x7fff7fff)), VGPR_32:$src) + (V_AND_B32_e64 (S_MOV_B32 (i32 0x7fff7fff)), VGPR_32:$src) >; def : GCNPat < (fneg (v2f16 (fabs VGPR_32:$src))), - (V_OR_B32_e32 (S_MOV_B32 (i32 0x80008000)), VGPR_32:$src) // Set sign bit + (V_OR_B32_e64 (S_MOV_B32 (i32 0x80008000)), VGPR_32:$src) >; def : GCNPat < @@ -1526,30 +1545,28 @@ def : GCNPat < (REG_SEQUENCE VReg_64, (i32 (EXTRACT_SUBREG VReg_64:$src, sub0)), sub0, - (V_AND_B32_e64 (i32 (EXTRACT_SUBREG VReg_64:$src, sub1)), - (V_MOV_B32_e32 (i32 0x7fffffff))), // Set sign bit. + (V_AND_B32_e64 (i32 (S_MOV_B32 (i32 0x7fffffff))), + (i32 (EXTRACT_SUBREG VReg_64:$src, sub1))), sub1) >; -// TODO: Use SGPR for constant def : GCNPat < (fneg (f64 VReg_64:$src)), (REG_SEQUENCE VReg_64, (i32 (EXTRACT_SUBREG VReg_64:$src, sub0)), sub0, - (V_XOR_B32_e32 (i32 (EXTRACT_SUBREG VReg_64:$src, sub1)), - (i32 (V_MOV_B32_e32 (i32 0x80000000)))), + (V_XOR_B32_e64 (i32 (S_MOV_B32 (i32 0x80000000))), + (i32 (EXTRACT_SUBREG VReg_64:$src, sub1))), sub1) >; -// TODO: Use SGPR for constant def : GCNPat < (fneg (fabs (f64 VReg_64:$src))), (REG_SEQUENCE VReg_64, (i32 (EXTRACT_SUBREG VReg_64:$src, sub0)), sub0, - (V_OR_B32_e32 (i32 (EXTRACT_SUBREG VReg_64:$src, sub1)), - (V_MOV_B32_e32 (i32 0x80000000))), // Set sign bit. + (V_OR_B32_e64 (i32 (S_MOV_B32 (i32 0x80000000))), + (i32 (EXTRACT_SUBREG VReg_64:$src, sub1))), sub1) >; @@ -1681,14 +1698,9 @@ def : GCNPat < /********** Intrinsic Patterns **********/ /********** ================== **********/ -let OtherPredicates = [isNotGFX90APlus] in -// FIXME: Should use _e64 and select source modifiers. -def : POW_Common <V_LOG_F32_e32, V_EXP_F32_e32, V_MUL_LEGACY_F32_e32>; - -let OtherPredicates = [isGFX90APlus] in def : GCNPat < - (fpow f32:$src0, f32:$src1), - (V_EXP_F32_e32 (V_MUL_LEGACY_F32_e64 0, f32:$src1, SRCMODS.NONE, (V_LOG_F32_e32 f32:$src0), 0, 0)) + (f32 (fpow (VOP3Mods f32:$src0, i32:$src0_mods), (VOP3Mods f32:$src1, i32:$src1_mods))), + (V_EXP_F32_e64 SRCMODS.NONE, (V_MUL_LEGACY_F32_e64 $src1_mods, $src1, SRCMODS.NONE, (V_LOG_F32_e64 $src0_mods, $src0), 0, 0)) >; def : GCNPat < diff --git a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp index 34cbb49dcd16..f4d9002e930e 100644 --- a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp +++ b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp @@ -1609,7 +1609,7 @@ SILoadStoreOptimizer::getTargetRegisterClass(const CombineInfo &CI, } unsigned BitWidth = 32 * (CI.Width + Paired.Width); - return TRI->hasAGPRs(getDataRegClass(*CI.I)) + return TRI->isAGPRClass(getDataRegClass(*CI.I)) ? TRI->getAGPRClassForBitWidth(BitWidth) : TRI->getVGPRClassForBitWidth(BitWidth); } diff --git a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp index 29f072ca1e6c..fff4f6729c99 100644 --- a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp +++ b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp @@ -795,6 +795,8 @@ bool SIGfx6CacheControl::enableLoadCacheBypass( switch (Scope) { case SIAtomicScope::SYSTEM: case SIAtomicScope::AGENT: + // Set L1 cache policy to MISS_EVICT. + // Note: there is no L2 cache bypass policy at the ISA level. Changed |= enableGLCBit(MI); break; case SIAtomicScope::WORKGROUP: @@ -837,8 +839,10 @@ bool SIGfx6CacheControl::enableRMWCacheBypass( assert(MI->mayLoad() && MI->mayStore()); bool Changed = false; - /// The L1 cache is write through so does not need to be bypassed. There is no - /// bypass control for the L2 cache at the isa level. + /// Do not set GLC for RMW atomic operations as L0/L1 cache is automatically + /// bypassed, and the GLC bit is instead used to indicate if they are + /// return or no-return. + /// Note: there is no L2 cache coherent bypass control at the ISA level. return Changed; } @@ -860,6 +864,9 @@ bool SIGfx6CacheControl::enableVolatileAndOrNonTemporal( bool Changed = false; if (IsVolatile) { + // Set L1 cache policy to be MISS_EVICT for load instructions + // and MISS_LRU for store instructions. + // Note: there is no L2 cache bypass policy at the ISA level. if (Op == SIMemOp::LOAD) Changed |= enableGLCBit(MI); @@ -875,7 +882,8 @@ bool SIGfx6CacheControl::enableVolatileAndOrNonTemporal( } if (IsNonTemporal) { - // Request L1 MISS_EVICT and L2 STREAM for load and store instructions. + // Setting both GLC and SLC configures L1 cache policy to MISS_EVICT + // for both loads and stores, and the L2 cache policy to STREAM. Changed |= enableGLCBit(MI); Changed |= enableSLCBit(MI); return Changed; @@ -1097,6 +1105,8 @@ bool SIGfx90ACacheControl::enableLoadCacheBypass( switch (Scope) { case SIAtomicScope::SYSTEM: case SIAtomicScope::AGENT: + // Set the L1 cache policy to MISS_LRU. + // Note: there is no L2 cache bypass policy at the ISA level. Changed |= enableGLCBit(MI); break; case SIAtomicScope::WORKGROUP: @@ -1206,6 +1216,9 @@ bool SIGfx90ACacheControl::enableVolatileAndOrNonTemporal( bool Changed = false; if (IsVolatile) { + // Set L1 cache policy to be MISS_EVICT for load instructions + // and MISS_LRU for store instructions. + // Note: there is no L2 cache bypass policy at the ISA level. if (Op == SIMemOp::LOAD) Changed |= enableGLCBit(MI); @@ -1221,7 +1234,8 @@ bool SIGfx90ACacheControl::enableVolatileAndOrNonTemporal( } if (IsNonTemporal) { - // Request L1 MISS_EVICT and L2 STREAM for load and store instructions. + // Setting both GLC and SLC configures L1 cache policy to MISS_EVICT + // for both loads and stores, and the L2 cache policy to STREAM. Changed |= enableGLCBit(MI); Changed |= enableSLCBit(MI); return Changed; @@ -1380,12 +1394,11 @@ bool SIGfx10CacheControl::enableLoadCacheBypass( bool Changed = false; if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) { - /// TODO Do not set glc for rmw atomic operations as they - /// implicitly bypass the L0/L1 caches. - switch (Scope) { case SIAtomicScope::SYSTEM: case SIAtomicScope::AGENT: + // Set the L0 and L1 cache policies to MISS_EVICT. + // Note: there is no L2 cache coherent bypass control at the ISA level. Changed |= enableGLCBit(MI); Changed |= enableDLCBit(MI); break; @@ -1434,6 +1447,9 @@ bool SIGfx10CacheControl::enableVolatileAndOrNonTemporal( bool Changed = false; if (IsVolatile) { + // Set L0 and L1 cache policy to be MISS_EVICT for load instructions + // and MISS_LRU for store instructions. + // Note: there is no L2 cache coherent bypass control at the ISA level. if (Op == SIMemOp::LOAD) { Changed |= enableGLCBit(MI); Changed |= enableDLCBit(MI); @@ -1450,8 +1466,14 @@ bool SIGfx10CacheControl::enableVolatileAndOrNonTemporal( } if (IsNonTemporal) { - // Request L0/L1 HIT_EVICT and L2 STREAM for load and store instructions. + // For loads setting SLC configures L0 and L1 cache policy to HIT_EVICT + // and L2 cache policy to STREAM. + // For stores setting both GLC and SLC configures L0 and L1 cache policy + // to MISS_EVICT and the L2 cache policy to STREAM. + if (Op == SIMemOp::STORE) + Changed |= enableGLCBit(MI); Changed |= enableSLCBit(MI); + return Changed; } diff --git a/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp b/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp index 6a698348d389..da41a5e2478a 100644 --- a/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp +++ b/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp @@ -1170,7 +1170,7 @@ void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &MI, unsigned I = MI.getOperandNo(&Op); if (Desc.OpInfo[I].RegClass == -1 || - !TRI->hasVGPRs(TRI->getRegClass(Desc.OpInfo[I].RegClass))) + !TRI->isVSSuperClass(TRI->getRegClass(Desc.OpInfo[I].RegClass))) continue; if (ST.hasSDWAScalar() && ConstantBusCount == 0 && Op.isReg() && diff --git a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp index d1b8e217471e..b0e45dd3e3e3 100644 --- a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp +++ b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp @@ -291,20 +291,19 @@ bool SIPreEmitPeephole::mustRetainExeczBranch( MBBI != End && MBBI != ToI; ++MBBI) { const MachineBasicBlock &MBB = *MBBI; - for (MachineBasicBlock::const_iterator I = MBB.begin(), E = MBB.end(); - I != E; ++I) { + for (const MachineInstr &MI : MBB) { // When a uniform loop is inside non-uniform control flow, the branch // leaving the loop might never be taken when EXEC = 0. // Hence we should retain cbranch out of the loop lest it become infinite. - if (I->isConditionalBranch()) + if (MI.isConditionalBranch()) return true; - if (TII->hasUnwantedEffectsWhenEXECEmpty(*I)) + if (TII->hasUnwantedEffectsWhenEXECEmpty(MI)) return true; // These instructions are potentially expensive even if EXEC = 0. - if (TII->isSMRD(*I) || TII->isVMEM(*I) || TII->isFLAT(*I) || - TII->isDS(*I) || I->getOpcode() == AMDGPU::S_WAITCNT) + if (TII->isSMRD(MI) || TII->isVMEM(MI) || TII->isFLAT(MI) || + TII->isDS(MI) || MI.getOpcode() == AMDGPU::S_WAITCNT) return true; ++NumInstr; diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp index bfbe84f696f8..a1d9a23a5084 100644 --- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp +++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp @@ -402,6 +402,62 @@ const uint32_t *SIRegisterInfo::getNoPreservedMask() const { return CSR_AMDGPU_NoRegs_RegMask; } +const TargetRegisterClass * +SIRegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC, + const MachineFunction &MF) const { + // FIXME: Should have a helper function like getEquivalentVGPRClass to get the + // equivalent AV class. If used one, the verifier will crash after + // RegBankSelect in the GISel flow. The aligned regclasses are not fully given + // until Instruction selection. + if (MF.getSubtarget<GCNSubtarget>().hasMAIInsts() && + (isVGPRClass(RC) || isAGPRClass(RC))) { + if (RC == &AMDGPU::VGPR_32RegClass || RC == &AMDGPU::AGPR_32RegClass) + return &AMDGPU::AV_32RegClass; + if (RC == &AMDGPU::VReg_64RegClass || RC == &AMDGPU::AReg_64RegClass) + return &AMDGPU::AV_64RegClass; + if (RC == &AMDGPU::VReg_64_Align2RegClass || + RC == &AMDGPU::AReg_64_Align2RegClass) + return &AMDGPU::AV_64_Align2RegClass; + if (RC == &AMDGPU::VReg_96RegClass || RC == &AMDGPU::AReg_96RegClass) + return &AMDGPU::AV_96RegClass; + if (RC == &AMDGPU::VReg_96_Align2RegClass || + RC == &AMDGPU::AReg_96_Align2RegClass) + return &AMDGPU::AV_96_Align2RegClass; + if (RC == &AMDGPU::VReg_128RegClass || RC == &AMDGPU::AReg_128RegClass) + return &AMDGPU::AV_128RegClass; + if (RC == &AMDGPU::VReg_128_Align2RegClass || + RC == &AMDGPU::AReg_128_Align2RegClass) + return &AMDGPU::AV_128_Align2RegClass; + if (RC == &AMDGPU::VReg_160RegClass || RC == &AMDGPU::AReg_160RegClass) + return &AMDGPU::AV_160RegClass; + if (RC == &AMDGPU::VReg_160_Align2RegClass || + RC == &AMDGPU::AReg_160_Align2RegClass) + return &AMDGPU::AV_160_Align2RegClass; + if (RC == &AMDGPU::VReg_192RegClass || RC == &AMDGPU::AReg_192RegClass) + return &AMDGPU::AV_192RegClass; + if (RC == &AMDGPU::VReg_192_Align2RegClass || + RC == &AMDGPU::AReg_192_Align2RegClass) + return &AMDGPU::AV_192_Align2RegClass; + if (RC == &AMDGPU::VReg_256RegClass || RC == &AMDGPU::AReg_256RegClass) + return &AMDGPU::AV_256RegClass; + if (RC == &AMDGPU::VReg_256_Align2RegClass || + RC == &AMDGPU::AReg_256_Align2RegClass) + return &AMDGPU::AV_256_Align2RegClass; + if (RC == &AMDGPU::VReg_512RegClass || RC == &AMDGPU::AReg_512RegClass) + return &AMDGPU::AV_512RegClass; + if (RC == &AMDGPU::VReg_512_Align2RegClass || + RC == &AMDGPU::AReg_512_Align2RegClass) + return &AMDGPU::AV_512_Align2RegClass; + if (RC == &AMDGPU::VReg_1024RegClass || RC == &AMDGPU::AReg_1024RegClass) + return &AMDGPU::AV_1024RegClass; + if (RC == &AMDGPU::VReg_1024_Align2RegClass || + RC == &AMDGPU::AReg_1024_Align2RegClass) + return &AMDGPU::AV_1024_Align2RegClass; + } + + return TargetRegisterInfo::getLargestLegalSuperClass(RC, MF); +} + Register SIRegisterInfo::getFrameRegister(const MachineFunction &MF) const { const SIFrameLowering *TFI = MF.getSubtarget<GCNSubtarget>().getFrameLowering(); @@ -994,10 +1050,22 @@ static MachineInstrBuilder spillVGPRtoAGPR(const GCNSubtarget &ST, unsigned Dst = IsStore ? Reg : ValueReg; unsigned Src = IsStore ? ValueReg : Reg; - unsigned Opc = (IsStore ^ TRI->isVGPR(MRI, Reg)) ? AMDGPU::V_ACCVGPR_WRITE_B32_e64 - : AMDGPU::V_ACCVGPR_READ_B32_e64; + bool IsVGPR = TRI->isVGPR(MRI, Reg); + DebugLoc DL = MI->getDebugLoc(); + if (IsVGPR == TRI->isVGPR(MRI, ValueReg)) { + // Spiller during regalloc may restore a spilled register to its superclass. + // It could result in AGPR spills restored to VGPRs or the other way around, + // making the src and dst with identical regclasses at this point. It just + // needs a copy in such cases. + auto CopyMIB = BuildMI(MBB, MI, DL, TII->get(AMDGPU::COPY), Dst) + .addReg(Src, getKillRegState(IsKill)); + CopyMIB->setAsmPrinterFlag(MachineInstr::ReloadReuse); + return CopyMIB; + } + unsigned Opc = (IsStore ^ IsVGPR) ? AMDGPU::V_ACCVGPR_WRITE_B32_e64 + : AMDGPU::V_ACCVGPR_READ_B32_e64; - auto MIB = BuildMI(MBB, MI, MI->getDebugLoc(), TII->get(Opc), Dst) + auto MIB = BuildMI(MBB, MI, DL, TII->get(Opc), Dst) .addReg(Src, getKillRegState(IsKill)); MIB->setAsmPrinterFlag(MachineInstr::ReloadReuse); return MIB; @@ -1099,7 +1167,7 @@ void SIRegisterInfo::buildSpillLoadStore( const TargetRegisterClass *RC = getRegClassForReg(MF->getRegInfo(), ValueReg); // On gfx90a+ AGPR is a regular VGPR acceptable for loads and stores. - const bool IsAGPR = !ST.hasGFX90AInsts() && hasAGPRs(RC); + const bool IsAGPR = !ST.hasGFX90AInsts() && isAGPRClass(RC); const unsigned RegWidth = AMDGPU::getRegBitWidth(RC->getID()) / 8; // Always use 4 byte operations for AGPRs because we need to scavenge @@ -2163,6 +2231,65 @@ SIRegisterInfo::getAGPRClassForBitWidth(unsigned BitWidth) const { : getAnyAGPRClassForBitWidth(BitWidth); } +static const TargetRegisterClass * +getAnyVectorSuperClassForBitWidth(unsigned BitWidth) { + if (BitWidth <= 64) + return &AMDGPU::AV_64RegClass; + if (BitWidth <= 96) + return &AMDGPU::AV_96RegClass; + if (BitWidth <= 128) + return &AMDGPU::AV_128RegClass; + if (BitWidth <= 160) + return &AMDGPU::AV_160RegClass; + if (BitWidth <= 192) + return &AMDGPU::AV_192RegClass; + if (BitWidth <= 224) + return &AMDGPU::AV_224RegClass; + if (BitWidth <= 256) + return &AMDGPU::AV_256RegClass; + if (BitWidth <= 512) + return &AMDGPU::AV_512RegClass; + if (BitWidth <= 1024) + return &AMDGPU::AV_1024RegClass; + + return nullptr; +} + +static const TargetRegisterClass * +getAlignedVectorSuperClassForBitWidth(unsigned BitWidth) { + if (BitWidth <= 64) + return &AMDGPU::AV_64_Align2RegClass; + if (BitWidth <= 96) + return &AMDGPU::AV_96_Align2RegClass; + if (BitWidth <= 128) + return &AMDGPU::AV_128_Align2RegClass; + if (BitWidth <= 160) + return &AMDGPU::AV_160_Align2RegClass; + if (BitWidth <= 192) + return &AMDGPU::AV_192_Align2RegClass; + if (BitWidth <= 224) + return &AMDGPU::AV_224_Align2RegClass; + if (BitWidth <= 256) + return &AMDGPU::AV_256_Align2RegClass; + if (BitWidth <= 512) + return &AMDGPU::AV_512_Align2RegClass; + if (BitWidth <= 1024) + return &AMDGPU::AV_1024_Align2RegClass; + + return nullptr; +} + +const TargetRegisterClass * +SIRegisterInfo::getVectorSuperClassForBitWidth(unsigned BitWidth) const { + if (BitWidth <= 16) + return &AMDGPU::VGPR_LO16RegClass; + if (BitWidth <= 32) + return &AMDGPU::AV_32RegClass; + return ST.needsAlignedVGPRs() + ? getAlignedVectorSuperClassForBitWidth(BitWidth) + : getAnyVectorSuperClassForBitWidth(BitWidth); +} + const TargetRegisterClass * SIRegisterInfo::getSGPRClassForBitWidth(unsigned BitWidth) { if (BitWidth <= 16) @@ -2305,15 +2432,14 @@ const TargetRegisterClass *SIRegisterInfo::getSubRegClass( // We can assume that each lane corresponds to one 32-bit register. unsigned Size = getNumChannelsFromSubReg(SubIdx) * 32; - if (isSGPRClass(RC)) { - if (Size == 32) - RC = &AMDGPU::SGPR_32RegClass; - else - RC = getSGPRClassForBitWidth(Size); - } else if (hasAGPRs(RC)) { + if (isAGPRClass(RC)) { RC = getAGPRClassForBitWidth(Size); - } else { + } else if (isVGPRClass(RC)) { RC = getVGPRClassForBitWidth(Size); + } else if (isVectorSuperClass(RC)) { + RC = getVectorSuperClassForBitWidth(Size); + } else { + RC = getSGPRClassForBitWidth(Size); } assert(RC && "Invalid sub-register class size"); return RC; @@ -2626,10 +2752,13 @@ bool SIRegisterInfo::isProperlyAlignedRC(const TargetRegisterClass &RC) const { if (!ST.needsAlignedVGPRs()) return true; - if (hasVGPRs(&RC)) + if (isVGPRClass(&RC)) return RC.hasSuperClassEq(getVGPRClassForBitWidth(getRegSizeInBits(RC))); - if (hasAGPRs(&RC)) + if (isAGPRClass(&RC)) return RC.hasSuperClassEq(getAGPRClassForBitWidth(getRegSizeInBits(RC))); + if (isVectorSuperClass(&RC)) + return RC.hasSuperClassEq( + getVectorSuperClassForBitWidth(getRegSizeInBits(RC))); return true; } diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h index 8d90ddb1cf4c..f1fe0a1d9329 100644 --- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h +++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h @@ -77,6 +77,10 @@ public: return 100; } + const TargetRegisterClass * + getLargestLegalSuperClass(const TargetRegisterClass *RC, + const MachineFunction &MF) const override; + Register getFrameRegister(const MachineFunction &MF) const override; bool hasBasePointer(const MachineFunction &MF) const; @@ -156,6 +160,10 @@ public: const TargetRegisterClass *getAGPRClassForBitWidth(unsigned BitWidth) const; LLVM_READONLY + const TargetRegisterClass * + getVectorSuperClassForBitWidth(unsigned BitWidth) const; + + LLVM_READONLY static const TargetRegisterClass *getSGPRClassForBitWidth(unsigned BitWidth); /// Return the 'base' register class for this register. @@ -164,7 +172,7 @@ public: /// \returns true if this class contains only SGPR registers static bool isSGPRClass(const TargetRegisterClass *RC) { - return !hasVGPRs(RC) && !hasAGPRs(RC); + return hasSGPRs(RC) && !hasVGPRs(RC) && !hasAGPRs(RC); } /// \returns true if this class ID contains only SGPR registers @@ -176,12 +184,22 @@ public: /// \returns true if this class contains only VGPR registers static bool isVGPRClass(const TargetRegisterClass *RC) { - return hasVGPRs(RC) && !hasAGPRs(RC); + return hasVGPRs(RC) && !hasAGPRs(RC) && !hasSGPRs(RC); } /// \returns true if this class contains only AGPR registers static bool isAGPRClass(const TargetRegisterClass *RC) { - return hasAGPRs(RC) && !hasVGPRs(RC); + return hasAGPRs(RC) && !hasVGPRs(RC) && !hasSGPRs(RC); + } + + /// \returns true only if this class contains both VGPR and AGPR registers + bool isVectorSuperClass(const TargetRegisterClass *RC) const { + return hasVGPRs(RC) && hasAGPRs(RC) && !hasSGPRs(RC); + } + + /// \returns true only if this class contains both VGPR and SGPR registers + bool isVSSuperClass(const TargetRegisterClass *RC) const { + return hasVGPRs(RC) && hasSGPRs(RC) && !hasAGPRs(RC); } /// \returns true if this class contains VGPR registers. @@ -194,6 +212,11 @@ public: return RC->TSFlags & SIRCFlags::HasAGPR; } + /// \returns true if this class contains SGPR registers. + static bool hasSGPRs(const TargetRegisterClass *RC) { + return RC->TSFlags & SIRCFlags::HasSGPR; + } + /// \returns true if this class contains any vector registers. static bool hasVectorRegisters(const TargetRegisterClass *RC) { return hasVGPRs(RC) || hasAGPRs(RC); diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td index cf1d90484228..340e2b48e5cd 100644 --- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td +++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td @@ -133,9 +133,13 @@ class SIRegisterClass <string n, list<ValueType> rTypes, int Align, dag rList> field bit HasVGPR = 0; field bit HasAGPR = 0; + // For scalar register classes. + field bit HasSGPR = 0; + // These need to be kept in sync with the enum SIRCFlags. let TSFlags{0} = HasVGPR; let TSFlags{1} = HasAGPR; + let TSFlags{2} = HasSGPR; } multiclass SIRegLoHi16 <string n, bits<16> regIdx, bit ArtificialHigh = 1, @@ -307,45 +311,51 @@ foreach Index = 0...255 in { // Groupings using register classes and tuples //===----------------------------------------------------------------------===// -def SCC_CLASS : RegisterClass<"AMDGPU", [i1], 1, (add SCC)> { +def SCC_CLASS : SIRegisterClass<"AMDGPU", [i1], 1, (add SCC)> { let CopyCost = -1; let isAllocatable = 0; + let HasSGPR = 1; } -def M0_CLASS : RegisterClass<"AMDGPU", [i32], 32, (add M0)> { +def M0_CLASS : SIRegisterClass<"AMDGPU", [i32], 32, (add M0)> { let CopyCost = 1; let isAllocatable = 0; + let HasSGPR = 1; } -def M0_CLASS_LO16 : RegisterClass<"AMDGPU", [i16, f16], 16, (add M0_LO16)> { +def M0_CLASS_LO16 : SIRegisterClass<"AMDGPU", [i16, f16], 16, (add M0_LO16)> { let CopyCost = 1; let Size = 16; let isAllocatable = 0; + let HasSGPR = 1; } // TODO: Do we need to set DwarfRegAlias on register tuples? -def SGPR_LO16 : RegisterClass<"AMDGPU", [i16, f16], 16, +def SGPR_LO16 : SIRegisterClass<"AMDGPU", [i16, f16], 16, (add (sequence "SGPR%u_LO16", 0, 105))> { let AllocationPriority = 9; let Size = 16; let GeneratePressureSet = 0; + let HasSGPR = 1; } -def SGPR_HI16 : RegisterClass<"AMDGPU", [i16, f16], 16, +def SGPR_HI16 : SIRegisterClass<"AMDGPU", [i16, f16], 16, (add (sequence "SGPR%u_HI16", 0, 105))> { let isAllocatable = 0; let Size = 16; let GeneratePressureSet = 0; + let HasSGPR = 1; } // SGPR 32-bit registers -def SGPR_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, +def SGPR_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, (add (sequence "SGPR%u", 0, 105))> { // Give all SGPR classes higher priority than VGPR classes, because // we want to spill SGPRs to VGPRs. let AllocationPriority = 9; let GeneratePressureSet = 0; + let HasSGPR = 1; } // SGPR 64-bit registers @@ -376,16 +386,18 @@ def SGPR_512Regs : SIRegisterTuples<getSubRegs<16>.ret, SGPR_32, 105, 4, 16, "s" def SGPR_1024Regs : SIRegisterTuples<getSubRegs<32>.ret, SGPR_32, 105, 4, 32, "s">; // Trap handler TMP 32-bit registers -def TTMP_32 : RegisterClass<"AMDGPU", [i32, f32, v2i16, v2f16], 32, +def TTMP_32 : SIRegisterClass<"AMDGPU", [i32, f32, v2i16, v2f16], 32, (add (sequence "TTMP%u", 0, 15))> { let isAllocatable = 0; + let HasSGPR = 1; } // Trap handler TMP 16-bit registers -def TTMP_LO16 : RegisterClass<"AMDGPU", [i16, f16], 16, +def TTMP_LO16 : SIRegisterClass<"AMDGPU", [i16, f16], 16, (add (sequence "TTMP%u_LO16", 0, 15))> { let Size = 16; let isAllocatable = 0; + let HasSGPR = 1; } // Trap handler TMP 64-bit registers @@ -598,16 +610,18 @@ def AGPR_1024 : SIRegisterTuples<getSubRegs<32>.ret, AGPR_32, 255, 1, 32, "a">; // Register classes used as source and destination //===----------------------------------------------------------------------===// -def Pseudo_SReg_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, +def Pseudo_SReg_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, (add FP_REG, SP_REG)> { let isAllocatable = 0; let CopyCost = -1; + let HasSGPR = 1; } -def Pseudo_SReg_128 : RegisterClass<"AMDGPU", [v4i32, v2i64, v2f64], 32, +def Pseudo_SReg_128 : SIRegisterClass<"AMDGPU", [v4i32, v2i64, v2f64], 32, (add PRIVATE_RSRC_REG)> { let isAllocatable = 0; let CopyCost = -1; + let HasSGPR = 1; } def LDS_DIRECT_CLASS : RegisterClass<"AMDGPU", [i32], 32, @@ -616,10 +630,10 @@ def LDS_DIRECT_CLASS : RegisterClass<"AMDGPU", [i32], 32, let CopyCost = -1; } -let GeneratePressureSet = 0 in { +let GeneratePressureSet = 0, HasSGPR = 1 in { // Subset of SReg_32 without M0 for SMRD instructions and alike. // See comments in SIInstructions.td for more info. -def SReg_32_XM0_XEXEC : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32, +def SReg_32_XM0_XEXEC : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32, (add SGPR_32, VCC_LO, VCC_HI, FLAT_SCR_LO, FLAT_SCR_HI, XNACK_MASK_LO, XNACK_MASK_HI, SGPR_NULL, TTMP_32, TMA_LO, TMA_HI, TBA_LO, TBA_HI, SRC_SHARED_BASE, SRC_SHARED_LIMIT, SRC_PRIVATE_BASE, SRC_PRIVATE_LIMIT, SRC_POPS_EXITING_WAVE_ID, @@ -627,7 +641,7 @@ def SReg_32_XM0_XEXEC : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f1 let AllocationPriority = 10; } -def SReg_LO16_XM0_XEXEC : RegisterClass<"AMDGPU", [i16, f16], 16, +def SReg_LO16_XM0_XEXEC : SIRegisterClass<"AMDGPU", [i16, f16], 16, (add SGPR_LO16, VCC_LO_LO16, VCC_HI_LO16, FLAT_SCR_LO_LO16, FLAT_SCR_HI_LO16, XNACK_MASK_LO_LO16, XNACK_MASK_HI_LO16, SGPR_NULL_LO16, TTMP_LO16, TMA_LO_LO16, TMA_HI_LO16, TBA_LO_LO16, TBA_HI_LO16, SRC_SHARED_BASE_LO16, @@ -637,29 +651,29 @@ def SReg_LO16_XM0_XEXEC : RegisterClass<"AMDGPU", [i16, f16], 16, let AllocationPriority = 10; } -def SReg_32_XEXEC_HI : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32, +def SReg_32_XEXEC_HI : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32, (add SReg_32_XM0_XEXEC, EXEC_LO, M0_CLASS)> { let AllocationPriority = 10; } -def SReg_LO16_XEXEC_HI : RegisterClass<"AMDGPU", [i16, f16], 16, +def SReg_LO16_XEXEC_HI : SIRegisterClass<"AMDGPU", [i16, f16], 16, (add SReg_LO16_XM0_XEXEC, EXEC_LO_LO16, M0_CLASS_LO16)> { let Size = 16; let AllocationPriority = 10; } -def SReg_32_XM0 : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32, +def SReg_32_XM0 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32, (add SReg_32_XM0_XEXEC, EXEC_LO, EXEC_HI)> { let AllocationPriority = 10; } -def SReg_LO16_XM0 : RegisterClass<"AMDGPU", [i16, f16], 16, +def SReg_LO16_XM0 : SIRegisterClass<"AMDGPU", [i16, f16], 16, (add SReg_LO16_XM0_XEXEC, EXEC_LO_LO16, EXEC_HI_LO16)> { let Size = 16; let AllocationPriority = 10; } -def SReg_LO16 : RegisterClass<"AMDGPU", [i16, f16], 16, +def SReg_LO16 : SIRegisterClass<"AMDGPU", [i16, f16], 16, (add SGPR_LO16, SReg_LO16_XM0, M0_CLASS_LO16, EXEC_LO_LO16, EXEC_HI_LO16, SReg_LO16_XEXEC_HI)> { let Size = 16; let AllocationPriority = 10; @@ -667,65 +681,75 @@ def SReg_LO16 : RegisterClass<"AMDGPU", [i16, f16], 16, } // End GeneratePressureSet = 0 // Register class for all scalar registers (SGPRs + Special Registers) -def SReg_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32, +def SReg_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16, i1], 32, (add SReg_32_XM0, M0_CLASS, EXEC_LO, EXEC_HI, SReg_32_XEXEC_HI)> { let AllocationPriority = 10; + let HasSGPR = 1; } let GeneratePressureSet = 0 in { -def SRegOrLds_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, +def SRegOrLds_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, (add SReg_32, LDS_DIRECT_CLASS)> { let isAllocatable = 0; + let HasSGPR = 1; } -def SGPR_64 : RegisterClass<"AMDGPU", [v2i32, i64, v2f32, f64, v4i16, v4f16], 32, +def SGPR_64 : SIRegisterClass<"AMDGPU", [v2i32, i64, v2f32, f64, v4i16, v4f16], 32, (add SGPR_64Regs)> { let CopyCost = 1; let AllocationPriority = 11; + let HasSGPR = 1; } // CCR (call clobbered registers) SGPR 64-bit registers -def CCR_SGPR_64 : RegisterClass<"AMDGPU", SGPR_64.RegTypes, 32, +def CCR_SGPR_64 : SIRegisterClass<"AMDGPU", SGPR_64.RegTypes, 32, (add (trunc SGPR_64, 16))> { let CopyCost = SGPR_64.CopyCost; let AllocationPriority = SGPR_64.AllocationPriority; + let HasSGPR = 1; } // Call clobbered 64-bit SGPRs for AMDGPU_Gfx CC -def Gfx_CCR_SGPR_64 : RegisterClass<"AMDGPU", SGPR_64.RegTypes, 32, +def Gfx_CCR_SGPR_64 : SIRegisterClass<"AMDGPU", SGPR_64.RegTypes, 32, (add (trunc (shl SGPR_64, 15), 1), // s[30:31] (trunc (shl SGPR_64, 18), 14))> { // s[36:37]-s[s62:63] let CopyCost = SGPR_64.CopyCost; let AllocationPriority = SGPR_64.AllocationPriority; + let HasSGPR = 1; } -def TTMP_64 : RegisterClass<"AMDGPU", [v2i32, i64, f64, v4i16, v4f16], 32, +def TTMP_64 : SIRegisterClass<"AMDGPU", [v2i32, i64, f64, v4i16, v4f16], 32, (add TTMP_64Regs)> { let isAllocatable = 0; + let HasSGPR = 1; } -def SReg_64_XEXEC : RegisterClass<"AMDGPU", [v2i32, i64, v2f32, f64, i1, v4i16, v4f16], 32, +def SReg_64_XEXEC : SIRegisterClass<"AMDGPU", [v2i32, i64, v2f32, f64, i1, v4i16, v4f16], 32, (add SGPR_64, VCC, FLAT_SCR, XNACK_MASK, TTMP_64, TBA, TMA)> { let CopyCost = 1; let AllocationPriority = 13; + let HasSGPR = 1; } -def SReg_64 : RegisterClass<"AMDGPU", [v2i32, i64, v2f32, f64, i1, v4i16, v4f16], 32, +def SReg_64 : SIRegisterClass<"AMDGPU", [v2i32, i64, v2f32, f64, i1, v4i16, v4f16], 32, (add SReg_64_XEXEC, EXEC)> { let CopyCost = 1; let AllocationPriority = 13; + let HasSGPR = 1; } -def SReg_1_XEXEC : RegisterClass<"AMDGPU", [i1], 32, +def SReg_1_XEXEC : SIRegisterClass<"AMDGPU", [i1], 32, (add SReg_64_XEXEC, SReg_32_XM0_XEXEC)> { let CopyCost = 1; let isAllocatable = 0; + let HasSGPR = 1; } -def SReg_1 : RegisterClass<"AMDGPU", [i1], 32, +def SReg_1 : SIRegisterClass<"AMDGPU", [i1], 32, (add SReg_1_XEXEC, EXEC, EXEC_LO)> { let CopyCost = 1; let isAllocatable = 0; + let HasSGPR = 1; } multiclass SRegClass<int numRegs, int priority, @@ -738,18 +762,18 @@ multiclass SRegClass<int numRegs, int priority, defvar sgprName = !strconcat("SGPR_", suffix); defvar ttmpName = !strconcat("TTMP_", suffix); - let AllocationPriority = priority, CopyCost = copyCost in { - def "" # sgprName : RegisterClass<"AMDGPU", regTypes, 32, (add regList)> { + let AllocationPriority = priority, CopyCost = copyCost, HasSGPR = 1 in { + def "" # sgprName : SIRegisterClass<"AMDGPU", regTypes, 32, (add regList)> { } if hasTTMP then { - def "" # ttmpName : RegisterClass<"AMDGPU", regTypes, 32, (add ttmpList)> { + def "" # ttmpName : SIRegisterClass<"AMDGPU", regTypes, 32, (add ttmpList)> { let isAllocatable = 0; } } def SReg_ # suffix : - RegisterClass<"AMDGPU", regTypes, 32, + SIRegisterClass<"AMDGPU", regTypes, 32, !con(!dag(add, [!cast<RegisterClass>(sgprName)], ["sgpr"]), !if(hasTTMP, !dag(add, [!cast<RegisterClass>(ttmpName)], ["ttmp"]), @@ -855,44 +879,45 @@ def VS_32 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, (add VGPR_32, SReg_32, LDS_DIRECT_CLASS)> { let isAllocatable = 0; let HasVGPR = 1; + let HasSGPR = 1; } def VS_64 : SIRegisterClass<"AMDGPU", [i64, f64, v2f32], 32, (add VReg_64, SReg_64)> { let isAllocatable = 0; let HasVGPR = 1; + let HasSGPR = 1; } -def AV_32 : SIRegisterClass<"AMDGPU", VGPR_32.RegTypes, 32, - (add AGPR_32, VGPR_32)> { - let isAllocatable = 0; - let HasVGPR = 1; - let HasAGPR = 1; -} - -def AV_64 : SIRegisterClass<"AMDGPU", VReg_64.RegTypes, 32, - (add AReg_64, VReg_64)> { - let isAllocatable = 0; +def AV_32 : SIRegisterClass<"AMDGPU", VGPR_32.RegTypes, 32, (add VGPR_32, AGPR_32)> { let HasVGPR = 1; let HasAGPR = 1; } } // End GeneratePressureSet = 0 -let HasVGPR = 1, HasAGPR = 1 in { -def AV_96 : SIRegisterClass<"AMDGPU", VReg_96.RegTypes, 32, - (add AReg_96, VReg_96)> { - let isAllocatable = 0; -} +// Define a register tuple class, along with one requiring an even +// aligned base register. +multiclass AVRegClass<int numRegs, list<ValueType> regTypes, + dag vregList, dag aregList> { + let HasVGPR = 1, HasAGPR = 1 in { + // Define the regular class. + def "" : VRegClassBase<numRegs, regTypes, (add vregList, aregList)>; -def AV_128 : SIRegisterClass<"AMDGPU", VReg_128.RegTypes, 32, - (add AReg_128, VReg_128)> { - let isAllocatable = 0; + // Define 2-aligned variant + def _Align2 : VRegClassBase<numRegs, regTypes, + (add (decimate vregList, 2), + (decimate aregList, 2))>; + } } -def AV_160 : SIRegisterClass<"AMDGPU", VReg_160.RegTypes, 32, - (add AReg_160, VReg_160)> { - let isAllocatable = 0; -} -} // End HasVGPR = 1, HasAGPR = 1 +defm AV_64 : AVRegClass<2, VReg_64.RegTypes, (add VGPR_64), (add AGPR_64)>; +defm AV_96 : AVRegClass<3, VReg_96.RegTypes, (add VGPR_96), (add AGPR_96)>; +defm AV_128 : AVRegClass<4, VReg_128.RegTypes, (add VGPR_128), (add AGPR_128)>; +defm AV_160 : AVRegClass<5, VReg_160.RegTypes, (add VGPR_160), (add AGPR_160)>; +defm AV_192 : AVRegClass<6, VReg_160.RegTypes, (add VGPR_192), (add AGPR_192)>; +defm AV_224 : AVRegClass<7, VReg_160.RegTypes, (add VGPR_224), (add AGPR_224)>; +defm AV_256 : AVRegClass<8, VReg_160.RegTypes, (add VGPR_256), (add AGPR_256)>; +defm AV_512 : AVRegClass<16, VReg_160.RegTypes, (add VGPR_512), (add AGPR_512)>; +defm AV_1024 : AVRegClass<32, VReg_160.RegTypes, (add VGPR_1024), (add AGPR_1024)>; //===----------------------------------------------------------------------===// // Register operands diff --git a/llvm/lib/Target/AMDGPU/SISchedule.td b/llvm/lib/Target/AMDGPU/SISchedule.td index 0792b303b830..18d424a3bc9f 100644 --- a/llvm/lib/Target/AMDGPU/SISchedule.td +++ b/llvm/lib/Target/AMDGPU/SISchedule.td @@ -93,16 +93,16 @@ def HWBranch : ProcResource<1> { let BufferSize = 1; } def HWExport : ProcResource<1> { - let BufferSize = 7; // Taken from S_WAITCNT + let BufferSize = 1; } def HWLGKM : ProcResource<1> { - let BufferSize = 31; // Taken from S_WAITCNT + let BufferSize = 1; } def HWSALU : ProcResource<1> { let BufferSize = 1; } def HWVMEM : ProcResource<1> { - let BufferSize = 15; // Taken from S_WAITCNT + let BufferSize = 1; } def HWVALU : ProcResource<1> { let BufferSize = 1; diff --git a/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp b/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp index 6f63f686635a..46012e5d7d97 100644 --- a/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp +++ b/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp @@ -487,6 +487,8 @@ char SIWholeQuadMode::scanInstructions(MachineFunction &MF, bool WQMOutputs = MF.getFunction().hasFnAttribute("amdgpu-ps-wqm-outputs"); SmallVector<MachineInstr *, 4> SetInactiveInstrs; SmallVector<MachineInstr *, 4> SoftWQMInstrs; + bool HasImplicitDerivatives = + MF.getFunction().getCallingConv() == CallingConv::AMDGPU_PS; // We need to visit the basic blocks in reverse post-order so that we visit // defs before uses, in particular so that we don't accidentally mark an @@ -497,8 +499,7 @@ char SIWholeQuadMode::scanInstructions(MachineFunction &MF, MachineBasicBlock &MBB = **BI; BlockInfo &BBI = Blocks[&MBB]; - for (auto II = MBB.begin(), IE = MBB.end(); II != IE; ++II) { - MachineInstr &MI = *II; + for (MachineInstr &MI : MBB) { InstrInfo &III = Instructions[&MI]; unsigned Opcode = MI.getOpcode(); char Flags = 0; @@ -507,6 +508,11 @@ char SIWholeQuadMode::scanInstructions(MachineFunction &MF, // If LOD is not supported WQM is not needed. if (!ST->hasExtendedImageInsts()) continue; + // Only generate implicit WQM if implicit derivatives are required. + // This avoids inserting unintended WQM if a shader type without + // implicit derivatives uses an image sampling instruction. + if (!HasImplicitDerivatives) + continue; // Sampling instructions don't need to produce results for all pixels // in a quad, they just require all inputs of a quad to have been // computed for derivatives. diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp index 9da7b9f5145d..d20eaaaa65e8 100644 --- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp +++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp @@ -1626,13 +1626,14 @@ unsigned getRegBitWidth(unsigned RCID) { return 32; case AMDGPU::SGPR_64RegClassID: case AMDGPU::VS_64RegClassID: - case AMDGPU::AV_64RegClassID: case AMDGPU::SReg_64RegClassID: case AMDGPU::VReg_64RegClassID: case AMDGPU::AReg_64RegClassID: case AMDGPU::SReg_64_XEXECRegClassID: case AMDGPU::VReg_64_Align2RegClassID: case AMDGPU::AReg_64_Align2RegClassID: + case AMDGPU::AV_64RegClassID: + case AMDGPU::AV_64_Align2RegClassID: return 64; case AMDGPU::SGPR_96RegClassID: case AMDGPU::SReg_96RegClassID: @@ -1641,6 +1642,7 @@ unsigned getRegBitWidth(unsigned RCID) { case AMDGPU::VReg_96_Align2RegClassID: case AMDGPU::AReg_96_Align2RegClassID: case AMDGPU::AV_96RegClassID: + case AMDGPU::AV_96_Align2RegClassID: return 96; case AMDGPU::SGPR_128RegClassID: case AMDGPU::SReg_128RegClassID: @@ -1649,6 +1651,7 @@ unsigned getRegBitWidth(unsigned RCID) { case AMDGPU::VReg_128_Align2RegClassID: case AMDGPU::AReg_128_Align2RegClassID: case AMDGPU::AV_128RegClassID: + case AMDGPU::AV_128_Align2RegClassID: return 128; case AMDGPU::SGPR_160RegClassID: case AMDGPU::SReg_160RegClassID: @@ -1657,6 +1660,7 @@ unsigned getRegBitWidth(unsigned RCID) { case AMDGPU::VReg_160_Align2RegClassID: case AMDGPU::AReg_160_Align2RegClassID: case AMDGPU::AV_160RegClassID: + case AMDGPU::AV_160_Align2RegClassID: return 160; case AMDGPU::SGPR_192RegClassID: case AMDGPU::SReg_192RegClassID: @@ -1664,6 +1668,8 @@ unsigned getRegBitWidth(unsigned RCID) { case AMDGPU::AReg_192RegClassID: case AMDGPU::VReg_192_Align2RegClassID: case AMDGPU::AReg_192_Align2RegClassID: + case AMDGPU::AV_192RegClassID: + case AMDGPU::AV_192_Align2RegClassID: return 192; case AMDGPU::SGPR_224RegClassID: case AMDGPU::SReg_224RegClassID: @@ -1671,6 +1677,8 @@ unsigned getRegBitWidth(unsigned RCID) { case AMDGPU::AReg_224RegClassID: case AMDGPU::VReg_224_Align2RegClassID: case AMDGPU::AReg_224_Align2RegClassID: + case AMDGPU::AV_224RegClassID: + case AMDGPU::AV_224_Align2RegClassID: return 224; case AMDGPU::SGPR_256RegClassID: case AMDGPU::SReg_256RegClassID: @@ -1678,6 +1686,8 @@ unsigned getRegBitWidth(unsigned RCID) { case AMDGPU::AReg_256RegClassID: case AMDGPU::VReg_256_Align2RegClassID: case AMDGPU::AReg_256_Align2RegClassID: + case AMDGPU::AV_256RegClassID: + case AMDGPU::AV_256_Align2RegClassID: return 256; case AMDGPU::SGPR_512RegClassID: case AMDGPU::SReg_512RegClassID: @@ -1685,6 +1695,8 @@ unsigned getRegBitWidth(unsigned RCID) { case AMDGPU::AReg_512RegClassID: case AMDGPU::VReg_512_Align2RegClassID: case AMDGPU::AReg_512_Align2RegClassID: + case AMDGPU::AV_512RegClassID: + case AMDGPU::AV_512_Align2RegClassID: return 512; case AMDGPU::SGPR_1024RegClassID: case AMDGPU::SReg_1024RegClassID: @@ -1692,6 +1704,8 @@ unsigned getRegBitWidth(unsigned RCID) { case AMDGPU::AReg_1024RegClassID: case AMDGPU::VReg_1024_Align2RegClassID: case AMDGPU::AReg_1024_Align2RegClassID: + case AMDGPU::AV_1024RegClassID: + case AMDGPU::AV_1024_Align2RegClassID: return 1024; default: llvm_unreachable("Unexpected register class"); |
