Index: lib/Target/AMDGPU/AMDGPUAsmPrinter.h =================================================================== --- lib/Target/AMDGPU/AMDGPUAsmPrinter.h +++ lib/Target/AMDGPU/AMDGPUAsmPrinter.h @@ -40,6 +40,8 @@ NumVGPR(0), NumSGPR(0), FlatUsed(false), + NumSGPRsForWavesPerEU(0), + NumVGPRsForWavesPerEU(0), ReservedVGPRFirst(0), ReservedVGPRCount(0), DebuggerWavefrontPrivateSegmentOffsetSGPR((uint16_t)-1), @@ -71,15 +73,23 @@ uint32_t LDSSize; bool FlatUsed; + // Number of SGPRs that meets number of waves per execution unit request. + uint32_t NumSGPRsForWavesPerEU; + + // Number of VGPRs that meets number of waves per execution unit request. + uint32_t NumVGPRsForWavesPerEU; + // If ReservedVGPRCount is 0 then must be 0. Otherwise, this is the first // fixed VGPR number reserved. uint16_t ReservedVGPRFirst; + // The number of consecutive VGPRs reserved. uint16_t ReservedVGPRCount; // Fixed SGPR number used to hold wave scratch offset for entire kernel // execution, or uint16_t(-1) if the register is not used or not known. uint16_t DebuggerWavefrontPrivateSegmentOffsetSGPR; + // Fixed SGPR number of the first 4 SGPRs used to hold scratch V# for entire // kernel execution, or uint16_t(-1) if the register is not used or not // known. Index: lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp =================================================================== --- lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp +++ lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp @@ -202,6 +202,16 @@ OutStreamer->emitRawComment(" LDSByteSize: " + Twine(KernelInfo.LDSSize) + " bytes/workgroup (compile time only)", false); + OutStreamer->emitRawComment(" SGPRBlocks: " + + Twine(KernelInfo.SGPRBlocks), false); + OutStreamer->emitRawComment(" VGPRBlocks: " + + Twine(KernelInfo.VGPRBlocks), false); + + OutStreamer->emitRawComment(" NumSGPRsForWavesPerEU: " + + Twine(KernelInfo.NumSGPRsForWavesPerEU), false); + OutStreamer->emitRawComment(" NumVGPRsForWavesPerEU: " + + Twine(KernelInfo.NumVGPRsForWavesPerEU), false); + OutStreamer->emitRawComment(" ReservedVGPRFirst: " + Twine(KernelInfo.ReservedVGPRFirst), false); OutStreamer->emitRawComment(" ReservedVGPRCount: " + Twine(KernelInfo.ReservedVGPRCount), @@ -446,20 +456,15 @@ ExtraSGPRs = 6; } - MaxSGPR += ExtraSGPRs; - // Record first reserved register and reserved register count fields, and // update max register counts if "amdgpu-debugger-reserve-regs" attribute was - // specified. - if (STM.debuggerReserveRegs()) { - ProgInfo.ReservedVGPRFirst = MaxVGPR + 1; - ProgInfo.ReservedVGPRCount = MFI->getDebuggerReservedVGPRCount(); - MaxVGPR += MFI->getDebuggerReservedVGPRCount(); - } + // requested. + ProgInfo.ReservedVGPRFirst = STM.debuggerReserveRegs() ? MaxVGPR + 1 : 0; + ProgInfo.ReservedVGPRCount = RI->getNumDebuggerReservedVGPRs(STM); // Update DebuggerWavefrontPrivateSegmentOffsetSGPR and // DebuggerPrivateSegmentBufferSGPR fields if "amdgpu-debugger-emit-prologue" - // attribute was specified. + // attribute was requested. if (STM.debuggerEmitPrologue()) { ProgInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR = RI->getHWRegIndex(MFI->getScratchWaveOffsetReg()); @@ -467,11 +472,22 @@ RI->getHWRegIndex(MFI->getScratchRSrcReg()); } + // Account for extra SGPRs and VGPRs reserved for debugger use. + MaxSGPR += ExtraSGPRs; + MaxVGPR += RI->getNumDebuggerReservedVGPRs(STM); + // We found the maximum register index. They start at 0, so add one to get the // number of registers. ProgInfo.NumVGPR = MaxVGPR + 1; ProgInfo.NumSGPR = MaxSGPR + 1; + // Adjust number of registers used to meet default/requested minimum/maximum + // number of waves per execution unit request. + ProgInfo.NumSGPRsForWavesPerEU = std::max( + ProgInfo.NumSGPR, RI->getMinNumSGPRs(STM, MFI->getMaxWavesPerEU())); + ProgInfo.NumVGPRsForWavesPerEU = std::max( + ProgInfo.NumVGPR, RI->getMinNumVGPRs(MFI->getMaxWavesPerEU())); + if (STM.hasSGPRInitBug()) { if (ProgInfo.NumSGPR > SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG) { LLVMContext &Ctx = MF.getFunction()->getContext(); @@ -482,6 +498,7 @@ } ProgInfo.NumSGPR = SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG; + ProgInfo.NumSGPRsForWavesPerEU = SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG; } if (MFI->NumUserSGPRs > STM.getMaxNumUserSGPRs()) { @@ -498,8 +515,16 @@ Ctx.diagnose(Diag); } - ProgInfo.VGPRBlocks = (ProgInfo.NumVGPR - 1) / 4; - ProgInfo.SGPRBlocks = (ProgInfo.NumSGPR - 1) / 8; + // SGPRBlocks is actual number of SGPR blocks minus 1. + ProgInfo.SGPRBlocks = alignTo(ProgInfo.NumSGPRsForWavesPerEU, + RI->getSGPRAllocGranule()); + ProgInfo.SGPRBlocks = ProgInfo.SGPRBlocks / RI->getSGPRAllocGranule() - 1; + + // VGPRBlocks is actual number of VGPR blocks minus 1. + ProgInfo.VGPRBlocks = alignTo(ProgInfo.NumVGPRsForWavesPerEU, + RI->getVGPRAllocGranule()); + ProgInfo.VGPRBlocks = ProgInfo.VGPRBlocks / RI->getVGPRAllocGranule() - 1; + // Set the value to initialize FP_ROUND and FP_DENORM parts of the mode // register. ProgInfo.FloatMode = getFPMode(MF); @@ -525,8 +550,8 @@ LDSAlignShift = 9; } - unsigned LDSSpillSize = MFI->LDSWaveSpillSize * - MFI->getMaximumWorkGroupSize(MF); + unsigned LDSSpillSize = + MFI->LDSWaveSpillSize * MFI->getMaxFlatWorkGroupSize(); ProgInfo.LDSSize = MFI->getLDSSize() + LDSSpillSize; ProgInfo.LDSBlocks = Index: lib/Target/AMDGPU/AMDGPUPromoteAlloca.cpp =================================================================== --- lib/Target/AMDGPU/AMDGPUPromoteAlloca.cpp +++ lib/Target/AMDGPU/AMDGPUPromoteAlloca.cpp @@ -184,13 +184,12 @@ // TODO: Have some sort of hint or other heuristics to guess occupancy based // on other factors.. - unsigned OccupancyHint - = AMDGPU::getIntegerAttribute(F, "amdgpu-max-waves-per-eu", 0); + unsigned OccupancyHint = ST.getWavesPerEU(F).second; if (OccupancyHint == 0) OccupancyHint = 7; // Clamp to max value. - OccupancyHint = std::min(OccupancyHint, ST.getMaxWavesPerCU()); + OccupancyHint = std::min(OccupancyHint, ST.getMaxWavesPerEU()); // Check the hint but ignore it if it's obviously wrong from the existing LDS // usage. @@ -650,9 +649,11 @@ if (AMDGPU::isShader(ContainingFunction.getCallingConv())) return; + const AMDGPUSubtarget &ST = + TM->getSubtarget(ContainingFunction); // FIXME: We should also try to get this value from the reqd_work_group_size // function attribute if it is available. - unsigned WorkGroupSize = AMDGPU::getMaximumWorkGroupSize(ContainingFunction); + unsigned WorkGroupSize = ST.getFlatWorkGroupSizes(ContainingFunction).second; const DataLayout &DL = Mod->getDataLayout(); Index: lib/Target/AMDGPU/AMDGPUSubtarget.h =================================================================== --- lib/Target/AMDGPU/AMDGPUSubtarget.h +++ lib/Target/AMDGPU/AMDGPUSubtarget.h @@ -270,14 +270,6 @@ return EnableXNACK; } - unsigned getMaxWavesPerCU() const { - if (getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS) - return 10; - - // FIXME: Not sure what this is for other subtagets. - return 8; - } - /// \brief Returns the offset in bytes from the start of the input buffer /// of the first explicit kernel argument. unsigned getExplicitKernelArgOffset() const { @@ -296,6 +288,98 @@ bool enableSubRegLiveness() const override { return true; } + + /// \returns Number of execution units per compute unit supported by the + /// subtarget. + unsigned getEUsPerCU() const { + return 4; + } + + /// \returns Maximum number of work groups per compute unit supported by the + /// subtarget and limited by given flat work group size. + unsigned getMaxWorkGroupsPerCU(unsigned FlatWorkGroupSize) const { + if (getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS) + return 8; + return getWavesPerWorkGroup(FlatWorkGroupSize) == 1 ? 40 : 16; + } + + /// \returns Maximum number of waves per compute unit supported by the + /// subtarget without any kind of limitation. + unsigned getMaxWavesPerCU() const { + return getMaxWavesPerEU() * getEUsPerCU(); + } + + /// \returns Maximum number of waves per compute unit supported by the + /// subtarget and limited by given flat work group size. + unsigned getMaxWavesPerCU(unsigned FlatWorkGroupSize) const { + unsigned WavesPerWorkGroup = getWavesPerWorkGroup(FlatWorkGroupSize); + unsigned MaxWorkGroupsPerCU = getMaxWorkGroupsPerCU(FlatWorkGroupSize); + unsigned MaxWavesPerCU = WavesPerWorkGroup * MaxWorkGroupsPerCU; + MaxWavesPerCU = std::min(MaxWavesPerCU, getMaxWavesPerCU()); + MaxWavesPerCU = alignDown(MaxWavesPerCU, WavesPerWorkGroup); + MaxWavesPerCU = MaxWavesPerCU / WavesPerWorkGroup; + MaxWavesPerCU = MaxWavesPerCU * WavesPerWorkGroup; + return MaxWavesPerCU; + } + + /// \returns Minimum number of waves per execution unit supported by the + /// subtarget. + unsigned getMinWavesPerEU() const { + return 1; + } + + /// \returns Maximum number of waves per execution unit supported by the + /// subtarget without any kind of limitation. + unsigned getMaxWavesPerEU() const { + if (getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS) + return 8; + // FIXME: Need to take scratch memory into account. + return 10; + } + + /// \returns Maximum number of waves per execution unit supported by the + /// subtarget and limited by given flat work group size. + unsigned getMaxWavesPerEU(unsigned FlatWorkGroupSize) const { + unsigned MaxWavesPerCU = getMaxWavesPerCU(FlatWorkGroupSize); + unsigned MaxWavesPerEU = alignDown(MaxWavesPerCU, getEUsPerCU()); + MaxWavesPerEU = MaxWavesPerEU / getEUsPerCU(); + return MaxWavesPerEU; + } + + /// \returns Minimum flat work group size supported by the subtarget. + unsigned getMinFlatWorkGroupSize() const { + return 1; + } + + /// \returns Maximum flat work group size supported by the subtarget. + unsigned getMaxFlatWorkGroupSize() const { + return 2048; + } + + /// \returns Number of waves per work group given the flat work group size. + unsigned getWavesPerWorkGroup(unsigned FlatWorkGroupSize) const { + return alignTo(FlatWorkGroupSize, getWavefrontSize()) / getWavefrontSize(); + } + + /// \returns Subtarget's default pair of minimum/maximum flat work group sizes + /// for function \p F, or minimum/maximum flat work group sizes explicitly + /// requested using "amdgpu-flat-work-group-size" attribute attached to + /// function \p F. + /// + /// \returns Subtarget's default values if explicitly requested values cannot + /// be converted to integer, or violate subtarget's specifications. + std::pair getFlatWorkGroupSizes(const Function &F) const; + + /// \returns Subtarget's default pair of minimum/maximum number of waves per + /// execution unit for function \p F, or minimum/maximum number of waves per + /// execution unit explicitly requested using "amdgpu-waves-per-eu" attribute + /// attached to function \p F. + /// + /// \returns Subtarget's default values if explicitly requested values cannot + /// be converted to integer, violate subtarget's specifications, or are not + /// compatible with minimum/maximum number of waves limited by flat work group + /// size, register usage, and/or lds usage. + std::pair getWavesPerEU(const Function &F) const; }; class R600Subtarget final : public AMDGPUSubtarget { Index: lib/Target/AMDGPU/AMDGPUSubtarget.cpp =================================================================== --- lib/Target/AMDGPU/AMDGPUSubtarget.cpp +++ lib/Target/AMDGPU/AMDGPUSubtarget.cpp @@ -179,6 +179,93 @@ return 1; } +std::pair AMDGPUSubtarget::getFlatWorkGroupSizes( + const Function &F) const { + + // Default minimum/maximum flat work group sizes. + std::pair Default = + AMDGPU::isCompute(F.getCallingConv()) ? + std::pair(getWavefrontSize() * 2, + getWavefrontSize() * 4) : + std::pair(1, getWavefrontSize()); + + // TODO: Do not process "amdgpu-max-work-group-size" attribute once mesa + // starts using "amdgpu-flat-work-group-size" attribute. + Default.second = AMDGPU::getIntegerAttribute( + F, "amdgpu-max-work-group-size", Default.second); + Default.first = std::min(Default.first, Default.second); + + // Requested minimum/maximum flat work group sizes. + std::pair Requested = AMDGPU::getIntegerPairAttribute( + F, "amdgpu-flat-work-group-size", Default); + + // Make sure requested minimum is less than requested maximum. + if (Requested.first > Requested.second) + return Default; + + // Make sure requested values do not violate subtarget's specifications. + if (Requested.first < getMinFlatWorkGroupSize()) + return Default; + if (Requested.second > getMaxFlatWorkGroupSize()) + return Default; + + return Requested; +} + +std::pair AMDGPUSubtarget::getWavesPerEU( + const Function &F) const { + + // Default minimum/maximum number of waves per execution unit. + std::pair Default(1, 0); + + // Default/requested minimum/maximum flat work group sizes. + std::pair FlatWorkGroupSizes = getFlatWorkGroupSizes(F); + + // If minimum/maximum flat work group sizes were explicitly requested using + // "amdgpu-flat-work-group-size" attribute, then set default minimum/maximum + // number of waves per execution unit to values implied by requested + // minimum/maximum flat work group sizes. + unsigned ImpliedByMinFlatWorkGroupSize = + getMaxWavesPerEU(FlatWorkGroupSizes.first); + unsigned ImpliedByMaxFlatWorkGroupSize = + getMaxWavesPerEU(FlatWorkGroupSizes.second); + unsigned MinImpliedByFlatWorkGroupSize = + std::min(ImpliedByMinFlatWorkGroupSize, ImpliedByMaxFlatWorkGroupSize); + unsigned MaxImpliedByFlatWorkGroupSize = + std::max(ImpliedByMinFlatWorkGroupSize, ImpliedByMaxFlatWorkGroupSize); + + // TODO: Do not process "amdgpu-max-work-group-size" attribute once mesa + // starts using "amdgpu-flat-work-group-size" attribute. + if (F.hasFnAttribute("amdgpu-max-work-group-size") || + F.hasFnAttribute("amdgpu-flat-work-group-size")) { + Default.first = MinImpliedByFlatWorkGroupSize; + Default.second = MaxImpliedByFlatWorkGroupSize; + } + + // Requested minimum/maximum number of waves per execution unit. + std::pair Requested = AMDGPU::getIntegerPairAttribute( + F, "amdgpu-waves-per-eu", Default, true); + + // Make sure requested minimum is less than requested maximum. + if (Requested.second && Requested.first > Requested.second) + return Default; + + // Make sure requested values do not violate subtarget's specifications. + if (Requested.first < getMinWavesPerEU() || + Requested.first > getMaxWavesPerEU()) + return Default; + if (Requested.second > getMaxWavesPerEU()) + return Default; + + // Make sure requested values are compatible with values implied by requested + // minimum/maximum flat work group sizes. + if (Requested.first > MinImpliedByFlatWorkGroupSize || + Requested.second > MaxImpliedByFlatWorkGroupSize) + return Default; + + return Requested; +} + R600Subtarget::R600Subtarget(const Triple &TT, StringRef GPU, StringRef FS, const TargetMachine &TM) : AMDGPUSubtarget(TT, GPU, FS, TM), Index: lib/Target/AMDGPU/SIInstrInfo.cpp =================================================================== --- lib/Target/AMDGPU/SIInstrInfo.cpp +++ lib/Target/AMDGPU/SIInstrInfo.cpp @@ -729,7 +729,7 @@ const SISubtarget &ST = MF->getSubtarget(); const SIRegisterInfo *TRI = ST.getRegisterInfo(); DebugLoc DL = MBB.findDebugLoc(MI); - unsigned WorkGroupSize = MFI->getMaximumWorkGroupSize(*MF); + unsigned WorkGroupSize = MFI->getMaxFlatWorkGroupSize(); unsigned WavefrontSize = ST.getWavefrontSize(); unsigned TIDReg = MFI->getTIDReg(); Index: lib/Target/AMDGPU/SIMachineFunctionInfo.h =================================================================== --- lib/Target/AMDGPU/SIMachineFunctionInfo.h +++ lib/Target/AMDGPU/SIMachineFunctionInfo.h @@ -60,10 +60,18 @@ unsigned PSInputAddr; bool ReturnsVoid; - unsigned MaximumWorkGroupSize; + // A pair of default/requested minimum/maximum flat work group sizes. + // Minimum - first, maximum - second. + std::pair FlatWorkGroupSizes; + + // A pair of default/requested minimum/maximum number of waves per execution + // unit. Minimum - first, maximum - second. + std::pair WavesPerEU; + + // Boolean value that indicates whether number of registers is controlled by + /// the user through one of the attributes, or not. + bool UserControlledRegisters; - // Number of reserved VGPRs for debugger usage. - unsigned DebuggerReservedVGPRCount; // Stack object indices for work group IDs. std::array DebuggerWorkGroupIDStackObjectIndices; // Stack object indices for work item IDs. @@ -343,9 +351,42 @@ ReturnsVoid = Value; } - /// \returns Number of reserved VGPRs for debugger usage. - unsigned getDebuggerReservedVGPRCount() const { - return DebuggerReservedVGPRCount; + /// \returns A pair of default/requested minimum/maximum flat work group sizes + /// for this function. + std::pair getFlatWorkGroupSizes() const { + return FlatWorkGroupSizes; + } + + /// \returns Default/requested minimum flat work group size for this function. + unsigned getMinFlatWorkGroupSize() const { + return FlatWorkGroupSizes.first; + } + + /// \returns Default/requested maximum flat work group size for this function. + unsigned getMaxFlatWorkGroupSize() const { + return FlatWorkGroupSizes.second; + } + + /// \returns A pair of default/requested minimum/maximum number of waves per + /// execution unit. + std::pair getWavesPerEU() const { + return WavesPerEU; + } + + /// \returns Default/requested minimum number of waves per execution unit. + unsigned getMinWavesPerEU() const { + return WavesPerEU.first; + } + + /// \returns Default/requested maximum number of waves per execution unit. + unsigned getMaxWavesPerEU() const { + return WavesPerEU.second; + } + + /// \returns True if number of registers is controlled by the user through one + /// of the attributes, false otherwise. + bool isUserControlledRegisters() const { + return UserControlledRegisters; } /// \returns Stack object index for \p Dim's work group ID. @@ -403,8 +444,6 @@ } llvm_unreachable("unexpected dimension"); } - - unsigned getMaximumWorkGroupSize(const MachineFunction &MF) const; }; } // End namespace llvm Index: lib/Target/AMDGPU/SIMachineFunctionInfo.cpp =================================================================== --- lib/Target/AMDGPU/SIMachineFunctionInfo.cpp +++ lib/Target/AMDGPU/SIMachineFunctionInfo.cpp @@ -48,8 +48,9 @@ PrivateSegmentWaveByteOffsetSystemSGPR(AMDGPU::NoRegister), PSInputAddr(0), ReturnsVoid(true), - MaximumWorkGroupSize(0), - DebuggerReservedVGPRCount(0), + FlatWorkGroupSizes(0, 0), + WavesPerEU(0, 0), + UserControlledRegisters(false), DebuggerWorkGroupIDStackObjectIndices({{0, 0, 0}}), DebuggerWorkItemIDStackObjectIndices({{0, 0, 0}}), LDSWaveSpillSize(0), @@ -135,13 +136,13 @@ ST.isAmdHsaOS()) FlatScratchInit = true; - if (AMDGPU::isCompute(F->getCallingConv())) - MaximumWorkGroupSize = AMDGPU::getMaximumWorkGroupSize(*F); - else - MaximumWorkGroupSize = ST.getWavefrontSize(); - - if (ST.debuggerReserveRegs()) - DebuggerReservedVGPRCount = 4; + FlatWorkGroupSizes = ST.getFlatWorkGroupSizes(*F); + WavesPerEU = ST.getWavesPerEU(*F); + UserControlledRegisters = F->hasFnAttribute("amdgpu-max-work-group-size") || + F->hasFnAttribute("amdgpu-max-work-group-size") || + F->hasFnAttribute("amdgpu-waves-per-eu") || + F->hasFnAttribute("amdgpu-num-sgpr") || + F->hasFnAttribute("amdgpu-num-vgpr"); } unsigned SIMachineFunctionInfo::addPrivateSegmentBuffer( @@ -229,8 +230,3 @@ Spill.VGPR = LaneVGPRs[LaneVGPRIdx]; return Spill; } - -unsigned SIMachineFunctionInfo::getMaximumWorkGroupSize( - const MachineFunction &MF) const { - return MaximumWorkGroupSize; -} Index: lib/Target/AMDGPU/SIRegisterInfo.h =================================================================== --- lib/Target/AMDGPU/SIRegisterInfo.h +++ lib/Target/AMDGPU/SIRegisterInfo.h @@ -170,14 +170,6 @@ unsigned getPreloadedValue(const MachineFunction &MF, enum PreloadedValue Value) const; - /// \brief Give the maximum number of VGPRs that can be used by \p WaveCount - /// concurrent waves. - unsigned getNumVGPRsAllowed(unsigned WaveCount) const; - - /// \brief Give the maximum number of SGPRs that can be used by \p WaveCount - /// concurrent waves. - unsigned getNumSGPRsAllowed(const SISubtarget &ST, unsigned WaveCount) const; - unsigned findUnusedRegister(const MachineRegisterInfo &MRI, const TargetRegisterClass *RC, const MachineFunction &MF) const; @@ -187,6 +179,70 @@ bool isVGPR(const MachineRegisterInfo &MRI, unsigned Reg) const; + /// \returns SGPR allocation granularity supported by the subtarget. + unsigned getSGPRAllocGranule() const { + return 8; + } + + /// \returns Total number of SGPRs supported by the subtarget. + unsigned getTotalNumSGPRs(const SISubtarget &ST) const; + + /// \returns Number of addressable SGPRs supported by the subtarget. + unsigned getNumAddressableSGPRs(const SISubtarget &ST) const; + + /// \returns Number of reserved SGPRs supported by the subtarget. + unsigned getNumReservedSGPRs(const SISubtarget &ST) const; + + /// \returns Minimum number of SGPRs that meets given number of waves per + /// execution unit requirement for given subtarget. + unsigned getMinNumSGPRs(const SISubtarget &ST, unsigned WavesPerEU) const; + + /// \returns Maximum number of SGPRs that meets given number of waves per + /// execution unit requirement for given subtarget. + unsigned getMaxNumSGPRs(const SISubtarget &ST, unsigned WavesPerEU) const; + + /// \returns Maximum number of SGPRs that meets number of waves per execution + /// unit requirement for function \p MF, or number of SGPRs explicitly + /// requested using "amdgpu-num-sgpr" attribute attached to function \p MF. + /// + /// \returns Value that meets number of waves per execution unit requirement + /// if explicitly requested value cannot be converted to integer, violates + /// subtarget's specifications, or does not meet number of waves per execution + /// unit requirement. + unsigned getMaxNumSGPRs(const MachineFunction &MF) const; + + /// \returns VGPR allocation granularity supported by the subtarget. + unsigned getVGPRAllocGranule() const { + return 4; + } + + /// \returns Total number of VGPRs supported by the subtarget. + unsigned getTotalNumVGPRs() const { + return 256; + } + + /// \returns Number of reserved VGPRs for debugger use supported by the + /// subtarget. + unsigned getNumDebuggerReservedVGPRs(const SISubtarget &ST) const; + + /// \returns Minimum number of SGPRs that meets given number of waves per + /// execution unit requirement. + unsigned getMinNumVGPRs(unsigned WavesPerEU) const; + + /// \returns Maximum number of VGPRs that meets given number of waves per + /// execution unit requirement. + unsigned getMaxNumVGPRs(unsigned WavesPerEU) const; + + /// \returns Maximum number of VGPRs that meets number of waves per execution + /// unit requirement for function \p MF, or number of VGPRs explicitly + /// requested using "amdgpu-num-vgpr" attribute attached to function \p MF. + /// + /// \returns Value that meets number of waves per execution unit requirement + /// if explicitly requested value cannot be converted to integer, violates + /// subtarget's specifications, or does not meet number of waves per execution + /// unit requirement. + unsigned getMaxNumVGPRs(const MachineFunction &MF) const; + private: void buildScratchLoadStore(MachineBasicBlock::iterator MI, unsigned LoadStoreOp, const MachineOperand *SrcDst, Index: lib/Target/AMDGPU/SIRegisterInfo.cpp =================================================================== --- lib/Target/AMDGPU/SIRegisterInfo.cpp +++ lib/Target/AMDGPU/SIRegisterInfo.cpp @@ -24,53 +24,6 @@ using namespace llvm; -static unsigned getMaxWaveCountPerSIMD(const MachineFunction &MF) { - const SIMachineFunctionInfo &MFI = *MF.getInfo(); - const SISubtarget &ST = MF.getSubtarget(); - unsigned SIMDPerCU = 4; - - unsigned MaxInvocationsPerWave = SIMDPerCU * ST.getWavefrontSize(); - return alignTo(MFI.getMaximumWorkGroupSize(MF), MaxInvocationsPerWave) / - MaxInvocationsPerWave; -} - -static unsigned getMaxWorkGroupSGPRCount(const MachineFunction &MF) { - const SISubtarget &ST = MF.getSubtarget(); - unsigned MaxWaveCountPerSIMD = getMaxWaveCountPerSIMD(MF); - - unsigned TotalSGPRCountPerSIMD, AddressableSGPRCount, SGPRUsageAlignment; - unsigned ReservedSGPRCount; - - if (ST.getGeneration() >= SISubtarget::VOLCANIC_ISLANDS) { - TotalSGPRCountPerSIMD = 800; - AddressableSGPRCount = 102; - SGPRUsageAlignment = 16; - ReservedSGPRCount = 6; // VCC, FLAT_SCRATCH, XNACK - } else { - TotalSGPRCountPerSIMD = 512; - AddressableSGPRCount = 104; - SGPRUsageAlignment = 8; - ReservedSGPRCount = 2; // VCC - } - - unsigned MaxSGPRCount = (TotalSGPRCountPerSIMD / MaxWaveCountPerSIMD); - MaxSGPRCount = alignDown(MaxSGPRCount, SGPRUsageAlignment); - - if (ST.hasSGPRInitBug()) - MaxSGPRCount = SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG; - - return std::min(MaxSGPRCount - ReservedSGPRCount, AddressableSGPRCount); -} - -static unsigned getMaxWorkGroupVGPRCount(const MachineFunction &MF) { - unsigned MaxWaveCountPerSIMD = getMaxWaveCountPerSIMD(MF); - unsigned TotalVGPRCountPerSIMD = 256; - unsigned VGPRUsageAlignment = 4; - - return alignDown(TotalVGPRCountPerSIMD / MaxWaveCountPerSIMD, - VGPRUsageAlignment); -} - static bool hasPressureSet(const int *PSets, unsigned PSetID) { for (unsigned i = 0; PSets[i] != -1; ++i) { if (PSets[i] == (int)PSetID) @@ -119,14 +72,14 @@ unsigned SIRegisterInfo::reservedPrivateSegmentBufferReg( const MachineFunction &MF) const { - unsigned BaseIdx = alignDown(getMaxWorkGroupSGPRCount(MF), 4) - 4; + unsigned BaseIdx = alignDown(getMaxNumSGPRs(MF), 4) - 4; unsigned BaseReg(AMDGPU::SGPR_32RegClass.getRegister(BaseIdx)); return getMatchingSuperReg(BaseReg, AMDGPU::sub0, &AMDGPU::SReg_128RegClass); } unsigned SIRegisterInfo::reservedPrivateSegmentWaveByteOffsetReg( const MachineFunction &MF) const { - unsigned RegCount = getMaxWorkGroupSGPRCount(MF); + unsigned RegCount = getMaxNumSGPRs(MF); unsigned Reg; // Try to place it in a hole after PrivateSegmentbufferReg. @@ -161,18 +114,16 @@ reserveRegisterTuples(Reserved, AMDGPU::TTMP8_TTMP9); reserveRegisterTuples(Reserved, AMDGPU::TTMP10_TTMP11); - unsigned MaxWorkGroupSGPRCount = getMaxWorkGroupSGPRCount(MF); - unsigned MaxWorkGroupVGPRCount = getMaxWorkGroupVGPRCount(MF); - - unsigned NumSGPRs = AMDGPU::SGPR_32RegClass.getNumRegs(); - unsigned NumVGPRs = AMDGPU::VGPR_32RegClass.getNumRegs(); - for (unsigned i = MaxWorkGroupSGPRCount; i < NumSGPRs; ++i) { + unsigned MaxNumSGPRs = getMaxNumSGPRs(MF); + unsigned TotalNumSGPRs = AMDGPU::SGPR_32RegClass.getNumRegs(); + for (unsigned i = MaxNumSGPRs; i < TotalNumSGPRs; ++i) { unsigned Reg = AMDGPU::SGPR_32RegClass.getRegister(i); reserveRegisterTuples(Reserved, Reg); } - - for (unsigned i = MaxWorkGroupVGPRCount; i < NumVGPRs; ++i) { + unsigned MaxNumVGPRs = getMaxNumVGPRs(MF); + unsigned TotalNumVGPRs = AMDGPU::VGPR_32RegClass.getNumRegs(); + for (unsigned i = MaxNumVGPRs; i < TotalNumVGPRs; ++i) { unsigned Reg = AMDGPU::VGPR_32RegClass.getRegister(i); reserveRegisterTuples(Reserved, Reg); } @@ -194,28 +145,18 @@ assert(!isSubRegister(ScratchRSrcReg, ScratchWaveOffsetReg)); } - // Reserve registers for debugger usage if "amdgpu-debugger-reserve-trap-regs" - // attribute was specified. - const SISubtarget &ST = MF.getSubtarget(); - if (ST.debuggerReserveRegs()) { - unsigned ReservedVGPRFirst = - MaxWorkGroupVGPRCount - MFI->getDebuggerReservedVGPRCount(); - for (unsigned i = ReservedVGPRFirst; i < MaxWorkGroupVGPRCount; ++i) { - unsigned Reg = AMDGPU::VGPR_32RegClass.getRegister(i); - reserveRegisterTuples(Reserved, Reg); - } - } - return Reserved; } unsigned SIRegisterInfo::getRegPressureSetLimit(const MachineFunction &MF, unsigned Idx) const { - const SISubtarget &STI = MF.getSubtarget(); - // FIXME: We should adjust the max number of waves based on LDS size. - unsigned SGPRLimit = getNumSGPRsAllowed(STI, STI.getMaxWavesPerCU()); - unsigned VGPRLimit = getNumVGPRsAllowed(STI.getMaxWavesPerCU()); + const SIMachineFunctionInfo &MFI = *MF.getInfo(); + if (MFI.isUserControlledRegisters()) + return AMDGPURegisterInfo::getRegPressureSetLimit(MF, Idx); + const SISubtarget &ST = MF.getSubtarget(); + unsigned SGPRLimit = getMaxNumSGPRs(ST, ST.getMaxWavesPerEU()); + unsigned VGPRLimit = getMaxNumVGPRs(ST.getMaxWavesPerEU()); unsigned VSLimit = SGPRLimit + VGPRLimit; if (SGPRPressureSets.test(Idx) && VGPRPressureSets.test(Idx)) { @@ -907,50 +848,193 @@ return AMDGPU::NoRegister; } -unsigned SIRegisterInfo::getNumVGPRsAllowed(unsigned WaveCount) const { - switch(WaveCount) { - case 10: return 24; - case 9: return 28; - case 8: return 32; - case 7: return 36; - case 6: return 40; - case 5: return 48; - case 4: return 64; - case 3: return 84; - case 2: return 128; - default: return 256; +bool SIRegisterInfo::isVGPR(const MachineRegisterInfo &MRI, + unsigned Reg) const { + const TargetRegisterClass *RC; + if (TargetRegisterInfo::isVirtualRegister(Reg)) + RC = MRI.getRegClass(Reg); + else + RC = getPhysRegClass(Reg); + + return hasVGPRs(RC); +} + +unsigned SIRegisterInfo::getTotalNumSGPRs(const SISubtarget &ST) const { + if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) + return 800; + return 512; +} + +unsigned SIRegisterInfo::getNumAddressableSGPRs(const SISubtarget &ST) const { + if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) + return 102; + return 104; +} + +unsigned SIRegisterInfo::getNumReservedSGPRs(const SISubtarget &ST) const { + if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) + return 6; // VCC, FLAT_SCRATCH, XNACK. + return 2; // VCC. +} + +unsigned SIRegisterInfo::getMinNumSGPRs(const SISubtarget &ST, + unsigned WavesPerEU) const { + if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) { + switch (WavesPerEU) { + case 0: return 0; + case 10: return 0; + case 9: return 0; + case 8: return 81; + default: return 97; + } + } else { + switch (WavesPerEU) { + case 0: return 0; + case 10: return 0; + case 9: return 49; + case 8: return 57; + case 7: return 65; + case 6: return 73; + case 5: return 81; + default: return 97; + } } } -unsigned SIRegisterInfo::getNumSGPRsAllowed(const SISubtarget &ST, - unsigned WaveCount) const { - if (ST.getGeneration() >= SISubtarget::VOLCANIC_ISLANDS) { - switch (WaveCount) { +unsigned SIRegisterInfo::getMaxNumSGPRs(const SISubtarget &ST, + unsigned WavesPerEU) const { + if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) { + switch (WavesPerEU) { + case 0: return 80; case 10: return 80; case 9: return 80; case 8: return 96; - default: return 102; + default: return getNumAddressableSGPRs(ST); } } else { - switch(WaveCount) { + switch (WavesPerEU) { + case 0: return 48; case 10: return 48; case 9: return 56; case 8: return 64; case 7: return 72; case 6: return 80; case 5: return 96; - default: return 103; + default: return getNumAddressableSGPRs(ST); } } } -bool SIRegisterInfo::isVGPR(const MachineRegisterInfo &MRI, - unsigned Reg) const { - const TargetRegisterClass *RC; - if (TargetRegisterInfo::isVirtualRegister(Reg)) - RC = MRI.getRegClass(Reg); - else - RC = getPhysRegClass(Reg); +unsigned SIRegisterInfo::getMaxNumSGPRs(const MachineFunction &MF) const { + const Function &F = *MF.getFunction(); - return hasVGPRs(RC); + const SISubtarget &ST = MF.getSubtarget(); + const SIMachineFunctionInfo &MFI = *MF.getInfo(); + + // Compute maximum number of SGPRs function can use using default/requested + // minimum number of waves per execution unit. + std::pair WavesPerEU = MFI.getWavesPerEU(); + unsigned MaxNumSGPRs = getMaxNumSGPRs(ST, WavesPerEU.first); + + // Check if maximum number of SGPRs was explicitly requested using + // "amdgpu-num-sgpr" attribute. + if (F.hasFnAttribute("amdgpu-num-sgpr")) { + unsigned Requested = AMDGPU::getIntegerAttribute( + F, "amdgpu-num-sgpr", MaxNumSGPRs); + + // Make sure requested value does not violate subtarget's specifications. + if (Requested && Requested <= getNumReservedSGPRs(ST)) + Requested = 0; + + // Make sure requested value is compatible with values implied by + // default/requested minimum/maximum number of waves per execution unit. + if (Requested && Requested > getMaxNumSGPRs(ST, WavesPerEU.first)) + Requested = 0; + if (WavesPerEU.second && + Requested && Requested < getMinNumSGPRs(ST, WavesPerEU.second)) + Requested = 0; + + if (Requested) + MaxNumSGPRs = Requested; + } + + if (ST.hasSGPRInitBug()) + MaxNumSGPRs = SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG; + + return MaxNumSGPRs - getNumReservedSGPRs(ST); +} + +unsigned SIRegisterInfo::getNumDebuggerReservedVGPRs( + const SISubtarget &ST) const { + if (ST.debuggerReserveRegs()) + return 4; + return 0; +} + +unsigned SIRegisterInfo::getMinNumVGPRs(unsigned WavesPerEU) const { + switch (WavesPerEU) { + case 0: return 0; + case 10: return 0; + case 9: return 25; + case 8: return 29; + case 7: return 33; + case 6: return 37; + case 5: return 41; + case 4: return 49; + case 3: return 65; + case 2: return 85; + default: return 129; + } +} + +unsigned SIRegisterInfo::getMaxNumVGPRs(unsigned WavesPerEU) const { + switch (WavesPerEU) { + case 0: return 24; + case 10: return 24; + case 9: return 28; + case 8: return 32; + case 7: return 36; + case 6: return 40; + case 5: return 48; + case 4: return 64; + case 3: return 84; + case 2: return 128; + default: return getTotalNumVGPRs(); + } +} + +unsigned SIRegisterInfo::getMaxNumVGPRs(const MachineFunction &MF) const { + const Function &F = *MF.getFunction(); + + const SISubtarget &ST = MF.getSubtarget(); + const SIMachineFunctionInfo &MFI = *MF.getInfo(); + + // Compute maximum number of VGPRs function can use using default/requested + // minimum number of waves per execution unit. + std::pair WavesPerEU = MFI.getWavesPerEU(); + unsigned MaxNumVGPRs = getMaxNumVGPRs(WavesPerEU.first); + + // Check if maximum number of VGPRs was explicitly requested using + // "amdgpu-num-vgpr" attribute. + if (F.hasFnAttribute("amdgpu-num-vgpr")) { + unsigned Requested = AMDGPU::getIntegerAttribute( + F, "amdgpu-num-vgpr", MaxNumVGPRs); + + // Make sure requested value does not violate subtarget's specifications. + if (Requested && Requested <= getNumDebuggerReservedVGPRs(ST)) + Requested = 0; + + // Make sure requested value is compatible with values implied by + // default/requested minimum/maximum number of waves per execution unit. + if (Requested && Requested > getMaxNumVGPRs(WavesPerEU.first)) + Requested = 0; + if (WavesPerEU.second && + Requested && Requested < getMinNumVGPRs(WavesPerEU.second)) + Requested = 0; + + if (Requested) + MaxNumVGPRs = Requested; + } + + return MaxNumVGPRs - getNumDebuggerReservedVGPRs(ST); } Index: lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h =================================================================== --- lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h +++ lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h @@ -45,9 +45,28 @@ bool isGlobalSegment(const GlobalValue *GV); bool isReadOnlySegment(const GlobalValue *GV); +/// \returns Integer value requested using \p F's \p Name attribute. +/// +/// \returns \p Default if attribute is not present. +/// +/// \returns \p Default and emits error if requested value cannot be converted +/// to integer. int getIntegerAttribute(const Function &F, StringRef Name, int Default); -unsigned getMaximumWorkGroupSize(const Function &F); +/// \returns A pair of integer values requested using \p F's \p Name attribute +/// in "first[,second]" format ("second" is optional unless \p OnlyFirstRequired +/// is false). +/// +/// \returns \p Default if attribute is not present. +/// +/// \returns \p Default and emits error if one of the requested values cannot be +/// converted to integer, or \p OnlyFirstRequired is false and "second" value is +/// not present. +std::pair getIntegerPairAttribute(const Function &F, + StringRef Name, + std::pair Default, + bool OnlyFirstRequired = false); + unsigned getInitialPSInputAddr(const Function &F); bool isShader(CallingConv::ID cc); Index: lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp =================================================================== --- lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp +++ lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp @@ -124,8 +124,29 @@ return Result; } -unsigned getMaximumWorkGroupSize(const Function &F) { - return getIntegerAttribute(F, "amdgpu-max-work-group-size", 256); +std::pair getIntegerPairAttribute(const Function &F, + StringRef Name, + std::pair Default, + bool OnlyFirstRequired) { + Attribute A = F.getFnAttribute(Name); + if (!A.isStringAttribute()) + return Default; + + LLVMContext &Ctx = F.getContext(); + std::pair Ints = Default; + std::pair Strs = A.getValueAsString().split(','); + if (Strs.first.trim().getAsInteger(0, Ints.first)) { + Ctx.emitError("can't parse first integer attribute " + Name); + return Default; + } + if (Strs.second.trim().getAsInteger(0, Ints.second)) { + if (!OnlyFirstRequired || Strs.second.trim().size()) { + Ctx.emitError("can't parse second integer attribute " + Name); + return Default; + } + } + + return Ints; } unsigned getInitialPSInputAddr(const Function &F) { Index: test/CodeGen/AMDGPU/amdgpu.private-memory.ll =================================================================== --- test/CodeGen/AMDGPU/amdgpu.private-memory.ll +++ test/CodeGen/AMDGPU/amdgpu.private-memory.ll @@ -545,7 +545,7 @@ ret void } -attributes #0 = { nounwind "amdgpu-max-waves-per-eu"="2" } +attributes #0 = { nounwind "amdgpu-waves-per-eu"="1,2" } ; HSAOPT: !0 = !{} ; HSAOPT: !1 = !{i32 0, i32 2048} Index: test/CodeGen/AMDGPU/array-ptr-calc-i32.ll =================================================================== --- test/CodeGen/AMDGPU/array-ptr-calc-i32.ll +++ test/CodeGen/AMDGPU/array-ptr-calc-i32.ll @@ -47,6 +47,6 @@ ret void } -attributes #0 = { nounwind "amdgpu-max-waves-per-eu"="1" } +attributes #0 = { nounwind "amdgpu-waves-per-eu"="1,1" } attributes #1 = { nounwind readnone } attributes #2 = { nounwind convergent } Index: test/CodeGen/AMDGPU/attr-amdgpu-flat-work-group-size.ll =================================================================== --- test/CodeGen/AMDGPU/attr-amdgpu-flat-work-group-size.ll +++ test/CodeGen/AMDGPU/attr-amdgpu-flat-work-group-size.ll @@ -0,0 +1,110 @@ +; RUN: llc -mtriple=amdgcn--amdhsa -mcpu=fiji -verify-machineinstrs < %s | FileCheck %s + +; CHECK-LABEL: {{^}}empty_64_64: +; CHECK: SGPRBlocks: 0 +; CHECK: VGPRBlocks: 0 +; CHECK: NumSGPRsForWavesPerEU: 1 +; CHECK: NumVGPRsForWavesPerEU: 1 +define void @empty_64_64() #0 { +entry: + ret void +} +attributes #0 = {"amdgpu-flat-work-group-size"="64,64"} + +; CHECK-LABEL: {{^}}empty_64_128: +; CHECK: SGPRBlocks: 0 +; CHECK: VGPRBlocks: 0 +; CHECK: NumSGPRsForWavesPerEU: 1 +; CHECK: NumVGPRsForWavesPerEU: 1 +define void @empty_64_128() #1 { +entry: + ret void +} +attributes #1 = {"amdgpu-flat-work-group-size"="64,128"} + +; CHECK-LABEL: {{^}}empty_128_128: +; CHECK: SGPRBlocks: 10 +; CHECK: VGPRBlocks: 7 +; CHECK: NumSGPRsForWavesPerEU: 81 +; CHECK: NumVGPRsForWavesPerEU: 29 +define void @empty_128_128() #2 { +entry: + ret void +} +attributes #2 = {"amdgpu-flat-work-group-size"="128,128"} + +@var = addrspace(1) global float 0.0 + +; CHECK-LABEL: {{^}}exactly_256_256: +; CHECK: SGPRBlocks: 2 +; CHECK: VGPRBlocks: 5 +; CHECK: NumSGPRsForWavesPerEU: 19 +; CHECK: NumVGPRsForWavesPerEU: 24 +define void @exactly_256_256() #3 { + %val0 = load volatile float, float addrspace(1)* @var + %val1 = load volatile float, float addrspace(1)* @var + %val2 = load volatile float, float addrspace(1)* @var + %val3 = load volatile float, float addrspace(1)* @var + %val4 = load volatile float, float addrspace(1)* @var + %val5 = load volatile float, float addrspace(1)* @var + %val6 = load volatile float, float addrspace(1)* @var + %val7 = load volatile float, float addrspace(1)* @var + %val8 = load volatile float, float addrspace(1)* @var + %val9 = load volatile float, float addrspace(1)* @var + %val10 = load volatile float, float addrspace(1)* @var + %val11 = load volatile float, float addrspace(1)* @var + %val12 = load volatile float, float addrspace(1)* @var + %val13 = load volatile float, float addrspace(1)* @var + %val14 = load volatile float, float addrspace(1)* @var + %val15 = load volatile float, float addrspace(1)* @var + %val16 = load volatile float, float addrspace(1)* @var + %val17 = load volatile float, float addrspace(1)* @var + %val18 = load volatile float, float addrspace(1)* @var + %val19 = load volatile float, float addrspace(1)* @var + %val20 = load volatile float, float addrspace(1)* @var + %val21 = load volatile float, float addrspace(1)* @var + %val22 = load volatile float, float addrspace(1)* @var + %val23 = load volatile float, float addrspace(1)* @var + %val24 = load volatile float, float addrspace(1)* @var + %val25 = load volatile float, float addrspace(1)* @var + %val26 = load volatile float, float addrspace(1)* @var + %val27 = load volatile float, float addrspace(1)* @var + %val28 = load volatile float, float addrspace(1)* @var + %val29 = load volatile float, float addrspace(1)* @var + %val30 = load volatile float, float addrspace(1)* @var + + store volatile float %val0, float addrspace(1)* @var + store volatile float %val1, float addrspace(1)* @var + store volatile float %val2, float addrspace(1)* @var + store volatile float %val3, float addrspace(1)* @var + store volatile float %val4, float addrspace(1)* @var + store volatile float %val5, float addrspace(1)* @var + store volatile float %val6, float addrspace(1)* @var + store volatile float %val7, float addrspace(1)* @var + store volatile float %val8, float addrspace(1)* @var + store volatile float %val9, float addrspace(1)* @var + store volatile float %val10, float addrspace(1)* @var + store volatile float %val11, float addrspace(1)* @var + store volatile float %val12, float addrspace(1)* @var + store volatile float %val13, float addrspace(1)* @var + store volatile float %val14, float addrspace(1)* @var + store volatile float %val15, float addrspace(1)* @var + store volatile float %val16, float addrspace(1)* @var + store volatile float %val17, float addrspace(1)* @var + store volatile float %val18, float addrspace(1)* @var + store volatile float %val19, float addrspace(1)* @var + store volatile float %val20, float addrspace(1)* @var + store volatile float %val21, float addrspace(1)* @var + store volatile float %val22, float addrspace(1)* @var + store volatile float %val23, float addrspace(1)* @var + store volatile float %val24, float addrspace(1)* @var + store volatile float %val25, float addrspace(1)* @var + store volatile float %val26, float addrspace(1)* @var + store volatile float %val27, float addrspace(1)* @var + store volatile float %val28, float addrspace(1)* @var + store volatile float %val29, float addrspace(1)* @var + store volatile float %val30, float addrspace(1)* @var + + ret void +} +attributes #3 = { "amdgpu-flat-work-group-size"="256,256" } Index: test/CodeGen/AMDGPU/attr-amdgpu-num-active-waves-per-eu.ll =================================================================== --- test/CodeGen/AMDGPU/attr-amdgpu-num-active-waves-per-eu.ll +++ test/CodeGen/AMDGPU/attr-amdgpu-num-active-waves-per-eu.ll @@ -0,0 +1,190 @@ +; RUN: llc -mtriple=amdgcn--amdhsa -mcpu=fiji -verify-machineinstrs < %s | FileCheck %s + +; Exactly 1 active wave per execution unit. +; CHECK-LABEL: {{^}}empty_exactly_1: +; CHECK: SGPRBlocks: 12 +; CHECK: VGPRBlocks: 32 +; CHECK: NumSGPRsForWavesPerEU: 97 +; CHECK: NumVGPRsForWavesPerEU: 129 +define void @empty_exactly_1() #0 { +entry: + ret void +} +attributes #0 = {"amdgpu-waves-per-eu"="1,1"} + +; Exactly 5 active waves per execution unit. +; CHECK-LABEL: {{^}}empty_exactly_5: +; CHECK: SGPRBlocks: 12 +; CHECK: VGPRBlocks: 10 +; CHECK: NumSGPRsForWavesPerEU: 97 +; CHECK: NumVGPRsForWavesPerEU: 41 +define void @empty_exactly_5() #1 { +entry: + ret void +} +attributes #1 = {"amdgpu-waves-per-eu"="5,5"} + +; Exactly 10 active waves per execution unit. +; CHECK-LABEL: {{^}}empty_exactly_10: +; CHECK: SGPRBlocks: 0 +; CHECK: VGPRBlocks: 0 +; CHECK: NumSGPRsForWavesPerEU: 1 +; CHECK: NumVGPRsForWavesPerEU: 1 +define void @empty_exactly_10() #2 { +entry: + ret void +} +attributes #2 = {"amdgpu-waves-per-eu"="10,10" "amdgpu-flat-work-group-size"="256,256"} + +; At least 1 active wave per execution unit. +; CHECK-LABEL: {{^}}empty_at_least_1: +; CHECK: SGPRBlocks: 0 +; CHECK: VGPRBlocks: 0 +; CHECK: NumSGPRsForWavesPerEU: 1 +; CHECK: NumVGPRsForWavesPerEU: 1 +define void @empty_at_least_1() #3 { +entry: + ret void +} +attributes #3 = {"amdgpu-waves-per-eu"="1"} + +; At least 5 active waves per execution unit. +; CHECK-LABEL: {{^}}empty_at_least_5: +; CHECK: SGPRBlocks: 0 +; CHECK: VGPRBlocks: 0 +; CHECK: NumSGPRsForWavesPerEU: 1 +; CHECK: NumVGPRsForWavesPerEU: 1 +define void @empty_at_least_5() #4 { +entry: + ret void +} +attributes #4 = {"amdgpu-waves-per-eu"="5"} + +; At least 10 active waves per execution unit. +; CHECK-LABEL: {{^}}empty_at_least_10: +; CHECK: SGPRBlocks: 0 +; CHECK: VGPRBlocks: 0 +; CHECK: NumSGPRsForWavesPerEU: 1 +; CHECK: NumVGPRsForWavesPerEU: 1 +define void @empty_at_least_10() #5 { +entry: + ret void +} +attributes #5 = {"amdgpu-waves-per-eu"="10" "amdgpu-flat-work-group-size"="256,256"} + +; At most 1 active wave per execution unit (same as @empty_exactly_1). + +; At most 5 active waves per execution unit. +; CHECK-LABEL: {{^}}empty_at_most_5: +; CHECK: SGPRBlocks: 12 +; CHECK: VGPRBlocks: 10 +; CHECK: NumSGPRsForWavesPerEU: 97 +; CHECK: NumVGPRsForWavesPerEU: 41 +define void @empty_at_most_5() #6 { +entry: + ret void +} +attributes #6 = {"amdgpu-waves-per-eu"="1,5"} + +; At most 10 active waves per execution unit. +; CHECK-LABEL: {{^}}empty_at_most_10: +; CHECK: SGPRBlocks: 0 +; CHECK: VGPRBlocks: 0 +; CHECK: NumSGPRsForWavesPerEU: 1 +; CHECK: NumVGPRsForWavesPerEU: 1 +define void @empty_at_most_10() #7 { +entry: + ret void +} +attributes #7 = {"amdgpu-waves-per-eu"="1,10"} + +; Between 1 and 5 active waves per execution unit (same as @empty_at_most_5). + +; Between 5 and 10 active waves per execution unit. +; CHECK-LABEL: {{^}}empty_between_5_and_10: +; CHECK: SGPRBlocks: 0 +; CHECK: VGPRBlocks: 0 +; CHECK: NumSGPRsForWavesPerEU: 1 +; CHECK: NumVGPRsForWavesPerEU: 1 +define void @empty_between_5_and_10() #8 { +entry: + ret void +} +attributes #8 = {"amdgpu-waves-per-eu"="5,10"} + +@var = addrspace(1) global float 0.0 + +; Exactly 10 active waves per execution unit. +; CHECK-LABEL: {{^}}exactly_10: +; CHECK: SGPRBlocks: 2 +; CHECK: VGPRBlocks: 5 +; CHECK: NumSGPRsForWavesPerEU: 19 +; CHECK: NumVGPRsForWavesPerEU: 24 +define void @exactly_10() #9 { + %val0 = load volatile float, float addrspace(1)* @var + %val1 = load volatile float, float addrspace(1)* @var + %val2 = load volatile float, float addrspace(1)* @var + %val3 = load volatile float, float addrspace(1)* @var + %val4 = load volatile float, float addrspace(1)* @var + %val5 = load volatile float, float addrspace(1)* @var + %val6 = load volatile float, float addrspace(1)* @var + %val7 = load volatile float, float addrspace(1)* @var + %val8 = load volatile float, float addrspace(1)* @var + %val9 = load volatile float, float addrspace(1)* @var + %val10 = load volatile float, float addrspace(1)* @var + %val11 = load volatile float, float addrspace(1)* @var + %val12 = load volatile float, float addrspace(1)* @var + %val13 = load volatile float, float addrspace(1)* @var + %val14 = load volatile float, float addrspace(1)* @var + %val15 = load volatile float, float addrspace(1)* @var + %val16 = load volatile float, float addrspace(1)* @var + %val17 = load volatile float, float addrspace(1)* @var + %val18 = load volatile float, float addrspace(1)* @var + %val19 = load volatile float, float addrspace(1)* @var + %val20 = load volatile float, float addrspace(1)* @var + %val21 = load volatile float, float addrspace(1)* @var + %val22 = load volatile float, float addrspace(1)* @var + %val23 = load volatile float, float addrspace(1)* @var + %val24 = load volatile float, float addrspace(1)* @var + %val25 = load volatile float, float addrspace(1)* @var + %val26 = load volatile float, float addrspace(1)* @var + %val27 = load volatile float, float addrspace(1)* @var + %val28 = load volatile float, float addrspace(1)* @var + %val29 = load volatile float, float addrspace(1)* @var + %val30 = load volatile float, float addrspace(1)* @var + + store volatile float %val0, float addrspace(1)* @var + store volatile float %val1, float addrspace(1)* @var + store volatile float %val2, float addrspace(1)* @var + store volatile float %val3, float addrspace(1)* @var + store volatile float %val4, float addrspace(1)* @var + store volatile float %val5, float addrspace(1)* @var + store volatile float %val6, float addrspace(1)* @var + store volatile float %val7, float addrspace(1)* @var + store volatile float %val8, float addrspace(1)* @var + store volatile float %val9, float addrspace(1)* @var + store volatile float %val10, float addrspace(1)* @var + store volatile float %val11, float addrspace(1)* @var + store volatile float %val12, float addrspace(1)* @var + store volatile float %val13, float addrspace(1)* @var + store volatile float %val14, float addrspace(1)* @var + store volatile float %val15, float addrspace(1)* @var + store volatile float %val16, float addrspace(1)* @var + store volatile float %val17, float addrspace(1)* @var + store volatile float %val18, float addrspace(1)* @var + store volatile float %val19, float addrspace(1)* @var + store volatile float %val20, float addrspace(1)* @var + store volatile float %val21, float addrspace(1)* @var + store volatile float %val22, float addrspace(1)* @var + store volatile float %val23, float addrspace(1)* @var + store volatile float %val24, float addrspace(1)* @var + store volatile float %val25, float addrspace(1)* @var + store volatile float %val26, float addrspace(1)* @var + store volatile float %val27, float addrspace(1)* @var + store volatile float %val28, float addrspace(1)* @var + store volatile float %val29, float addrspace(1)* @var + store volatile float %val30, float addrspace(1)* @var + + ret void +} +attributes #9 = { "amdgpu-waves-per-eu"="10,10" "amdgpu-flat-work-group-size"="256,256" } Index: test/CodeGen/AMDGPU/attr-amdgpu-num-gpr.ll =================================================================== --- test/CodeGen/AMDGPU/attr-amdgpu-num-gpr.ll +++ test/CodeGen/AMDGPU/attr-amdgpu-num-gpr.ll @@ -0,0 +1,91 @@ +; RUN: llc -mtriple=amdgcn--amdhsa -mcpu=fiji -verify-machineinstrs < %s | FileCheck %s + +; CHECK-LABEL: {{^}}num_sgpr: +; CHECK: SGPRBlocks: 1 +; CHECK: NumSGPRsForWavesPerEU: 13 +define void @num_sgpr(i32 addrspace(1)* %out1, + i32 addrspace(1)* %out2, + i32 addrspace(1)* %out3, + i32 addrspace(1)* %out4, + i32 %one, i32 %two, i32 %three, i32 %four) #0 { + store i32 %one, i32 addrspace(1)* %out1 + store i32 %two, i32 addrspace(1)* %out2 + store i32 %three, i32 addrspace(1)* %out3 + store i32 %four, i32 addrspace(1)* %out4 + ret void +} +attributes #0 = { "amdgpu-num-sgpr"="18" } + +@var = addrspace(1) global float 0.0 + +; CHECK-LABEL: {{^}}num_vgpr: +; CHECK: VGPRBlocks: 4 +; CHECK: NumVGPRsForWavesPerEU: 20 +define void @num_vgpr() #1 { + %val0 = load volatile float, float addrspace(1)* @var + %val1 = load volatile float, float addrspace(1)* @var + %val2 = load volatile float, float addrspace(1)* @var + %val3 = load volatile float, float addrspace(1)* @var + %val4 = load volatile float, float addrspace(1)* @var + %val5 = load volatile float, float addrspace(1)* @var + %val6 = load volatile float, float addrspace(1)* @var + %val7 = load volatile float, float addrspace(1)* @var + %val8 = load volatile float, float addrspace(1)* @var + %val9 = load volatile float, float addrspace(1)* @var + %val10 = load volatile float, float addrspace(1)* @var + %val11 = load volatile float, float addrspace(1)* @var + %val12 = load volatile float, float addrspace(1)* @var + %val13 = load volatile float, float addrspace(1)* @var + %val14 = load volatile float, float addrspace(1)* @var + %val15 = load volatile float, float addrspace(1)* @var + %val16 = load volatile float, float addrspace(1)* @var + %val17 = load volatile float, float addrspace(1)* @var + %val18 = load volatile float, float addrspace(1)* @var + %val19 = load volatile float, float addrspace(1)* @var + %val20 = load volatile float, float addrspace(1)* @var + %val21 = load volatile float, float addrspace(1)* @var + %val22 = load volatile float, float addrspace(1)* @var + %val23 = load volatile float, float addrspace(1)* @var + %val24 = load volatile float, float addrspace(1)* @var + %val25 = load volatile float, float addrspace(1)* @var + %val26 = load volatile float, float addrspace(1)* @var + %val27 = load volatile float, float addrspace(1)* @var + %val28 = load volatile float, float addrspace(1)* @var + %val29 = load volatile float, float addrspace(1)* @var + %val30 = load volatile float, float addrspace(1)* @var + + store volatile float %val0, float addrspace(1)* @var + store volatile float %val1, float addrspace(1)* @var + store volatile float %val2, float addrspace(1)* @var + store volatile float %val3, float addrspace(1)* @var + store volatile float %val4, float addrspace(1)* @var + store volatile float %val5, float addrspace(1)* @var + store volatile float %val6, float addrspace(1)* @var + store volatile float %val7, float addrspace(1)* @var + store volatile float %val8, float addrspace(1)* @var + store volatile float %val9, float addrspace(1)* @var + store volatile float %val10, float addrspace(1)* @var + store volatile float %val11, float addrspace(1)* @var + store volatile float %val12, float addrspace(1)* @var + store volatile float %val13, float addrspace(1)* @var + store volatile float %val14, float addrspace(1)* @var + store volatile float %val15, float addrspace(1)* @var + store volatile float %val16, float addrspace(1)* @var + store volatile float %val17, float addrspace(1)* @var + store volatile float %val18, float addrspace(1)* @var + store volatile float %val19, float addrspace(1)* @var + store volatile float %val20, float addrspace(1)* @var + store volatile float %val21, float addrspace(1)* @var + store volatile float %val22, float addrspace(1)* @var + store volatile float %val23, float addrspace(1)* @var + store volatile float %val24, float addrspace(1)* @var + store volatile float %val25, float addrspace(1)* @var + store volatile float %val26, float addrspace(1)* @var + store volatile float %val27, float addrspace(1)* @var + store volatile float %val28, float addrspace(1)* @var + store volatile float %val29, float addrspace(1)* @var + store volatile float %val30, float addrspace(1)* @var + + ret void +} +attributes #1 = { "amdgpu-num-vgpr"="20" } Index: test/CodeGen/AMDGPU/attr-unparseable.ll =================================================================== --- test/CodeGen/AMDGPU/attr-unparseable.ll +++ test/CodeGen/AMDGPU/attr-unparseable.ll @@ -0,0 +1,57 @@ +; RUN: not llc -mtriple=amdgcn--amdhsa -mcpu=fiji -verify-machineinstrs < %s 2>&1 | FileCheck %s + +; CHECK: can't parse integer attribute amdgpu-num-sgpr +define void @unparseable_single_0() #0 { +entry: + ret void +} +attributes #0 = { "amdgpu-num-sgpr" } + +; CHECK: can't parse integer attribute amdgpu-num-sgpr +define void @unparseable_single_1() #1 { +entry: + ret void +} +attributes #1 = { "amdgpu-num-sgpr"="k" } + +; CHECK: can't parse integer attribute amdgpu-num-sgpr +define void @unparseable_single_2() #2 { +entry: + ret void +} +attributes #2 = { "amdgpu-num-sgpr"="1,2" } + +; CHECK: can't parse first integer attribute amdgpu-flat-work-group-size +define void @unparseable_pair_0() #3 { +entry: + ret void +} +attributes #3 = { "amdgpu-flat-work-group-size" } + +; CHECK: can't parse first integer attribute amdgpu-flat-work-group-size +define void @unparseable_pair_1() #4 { +entry: + ret void +} +attributes #4 = { "amdgpu-flat-work-group-size"="k" } + +; CHECK: can't parse second integer attribute amdgpu-flat-work-group-size +define void @unparseable_pair_2() #5 { +entry: + ret void +} +attributes #5 = { "amdgpu-flat-work-group-size"="1" } + +; CHECK: can't parse second integer attribute amdgpu-flat-work-group-size +define void @unparseable_pair_3() #6 { +entry: + ret void +} +attributes #6 = { "amdgpu-flat-work-group-size"="1,k" } + +; CHECK: can't parse second integer attribute amdgpu-flat-work-group-size +define void @unparseable_pair_4() #7 { +entry: + ret void +} +attributes #7 = { "amdgpu-flat-work-group-size"="1,2,3" } Index: test/CodeGen/AMDGPU/indirect-private-64.ll =================================================================== --- test/CodeGen/AMDGPU/indirect-private-64.ll +++ test/CodeGen/AMDGPU/indirect-private-64.ll @@ -121,4 +121,4 @@ } attributes #0 = { convergent nounwind } -attributes #1 = { nounwind "amdgpu-max-waves-per-eu"="2" "amdgpu-max-work-group-size"="64" } +attributes #1 = { nounwind "amdgpu-waves-per-eu"="2,2" "amdgpu-flat-work-group-size"="64,64" } Index: test/CodeGen/AMDGPU/large-work-group-promote-alloca.ll =================================================================== --- test/CodeGen/AMDGPU/large-work-group-promote-alloca.ll +++ test/CodeGen/AMDGPU/large-work-group-promote-alloca.ll @@ -255,10 +255,10 @@ } attributes #0 = { nounwind "amdgpu-max-work-group-size"="63" } -attributes #1 = { nounwind "amdgpu-max-waves-per-eu"="3" "amdgpu-max-work-group-size"="256" } -attributes #2 = { nounwind "amdgpu-max-waves-per-eu"="1" "amdgpu-max-work-group-size"="1600" } -attributes #3 = { nounwind "amdgpu-max-waves-per-eu"="0" } -attributes #4 = { nounwind "amdgpu-max-waves-per-eu"="-1" } -attributes #5 = { nounwind "amdgpu-max-waves-per-eu"="6" "amdgpu-max-work-group-size"="64" } -attributes #6 = { nounwind "amdgpu-max-waves-per-eu"="8" "amdgpu-max-work-group-size"="64" } -attributes #7 = { nounwind "amdgpu-max-waves-per-eu"="9" "amdgpu-max-work-group-size"="64" } +attributes #1 = { nounwind "amdgpu-waves-per-eu"="1,3" "amdgpu-flat-work-group-size"="256,256" } +attributes #2 = { nounwind "amdgpu-waves-per-eu"="1,1" "amdgpu-flat-work-group-size"="1600,1600" } +attributes #3 = { nounwind "amdgpu-waves-per-eu"="1,10" } +attributes #4 = { nounwind "amdgpu-waves-per-eu"="1,10" } +attributes #5 = { nounwind "amdgpu-waves-per-eu"="1,6" "amdgpu-flat-work-group-size"="64,64" } +attributes #6 = { nounwind "amdgpu-waves-per-eu"="1,8" "amdgpu-flat-work-group-size"="64,64" } +attributes #7 = { nounwind "amdgpu-waves-per-eu"="1,9" "amdgpu-flat-work-group-size"="64,64" } Index: test/CodeGen/AMDGPU/large-work-group-registers.ll =================================================================== --- test/CodeGen/AMDGPU/large-work-group-registers.ll +++ test/CodeGen/AMDGPU/large-work-group-registers.ll @@ -1,6 +1,6 @@ ; RUN: llc -march=amdgcn -mcpu=tonga -regalloc=basic -post-RA-scheduler=0 < %s | FileCheck %s -; CHECK: NumVgprs: 64 +; CHECK: NumVgprs: 32 define void @main([9 x <16 x i8>] addrspace(2)* byval, [17 x <16 x i8>] addrspace(2)* byval, [17 x <8 x i32>] addrspace(2)* byval, [16 x <8 x i32>] addrspace(2)* byval, [16 x <4 x i32>] addrspace(2)* byval, <3 x i32> inreg, <3 x i32> inreg, <3 x i32>) #0 { main_body: %8 = getelementptr [16 x <4 x i32>], [16 x <4 x i32>] addrspace(2)* %4, i64 0, i64 8 Index: test/CodeGen/AMDGPU/load-constant-i16.ll =================================================================== --- test/CodeGen/AMDGPU/load-constant-i16.ll +++ test/CodeGen/AMDGPU/load-constant-i16.ll @@ -260,8 +260,8 @@ ; FUNC-LABEL: {{^}}constant_zextload_v32i16_to_v32i32: ; GCN-DAG: s_load_dwordx16 ; GCN-DAG: s_mov_b32 [[K:s[0-9]+]], 0xffff{{$}} -; GCN: s_and_b32 s{{[0-9]+}}, s{{[0-9]+}}, [[K]] -; GCN: s_lshr_b32 s{{[0-9]+}}, s{{[0-9]+}}, 16 +; GCN-DAG: s_lshr_b32 s{{[0-9]+}}, s{{[0-9]+}}, 16 +; GCN-DAG: s_and_b32 s{{[0-9]+}}, s{{[0-9]+}}, [[K]] define void @constant_zextload_v32i16_to_v32i32(<32 x i32> addrspace(1)* %out, <32 x i16> addrspace(2)* %in) #0 { %load = load <32 x i16>, <32 x i16> addrspace(2)* %in %ext = zext <32 x i16> %load to <32 x i32> Index: test/CodeGen/AMDGPU/private-memory-r600.ll =================================================================== --- test/CodeGen/AMDGPU/private-memory-r600.ll +++ test/CodeGen/AMDGPU/private-memory-r600.ll @@ -297,4 +297,4 @@ ; OPT: !0 = !{i32 0, i32 2048} -attributes #0 = { nounwind "amdgpu-max-waves-per-eu"="2" } +attributes #0 = { nounwind "amdgpu-waves-per-eu"="1,2" } Index: test/CodeGen/AMDGPU/promote-alloca-mem-intrinsics.ll =================================================================== --- test/CodeGen/AMDGPU/promote-alloca-mem-intrinsics.ll +++ test/CodeGen/AMDGPU/promote-alloca-mem-intrinsics.ll @@ -61,5 +61,5 @@ ret void } -attributes #0 = { nounwind "amdgpu-max-work-group-size"="64" "amdgpu-max-waves-per-eu"="3" } +attributes #0 = { nounwind "amdgpu-flat-work-group-size"="64,64" "amdgpu-waves-per-eu"="3,3" } attributes #1 = { nounwind readnone } Index: test/CodeGen/AMDGPU/promote-alloca-no-opts.ll =================================================================== --- test/CodeGen/AMDGPU/promote-alloca-no-opts.ll +++ test/CodeGen/AMDGPU/promote-alloca-no-opts.ll @@ -34,5 +34,5 @@ ret void } -attributes #0 = { nounwind "amdgpu-max-work-group-size"="64" } -attributes #1 = { nounwind optnone noinline "amdgpu-max-work-group-size"="64" } +attributes #0 = { nounwind "amdgpu-flat-work-group-size"="64,64" } +attributes #1 = { nounwind optnone noinline "amdgpu-flat-work-group-size"="64,64" } Index: test/CodeGen/AMDGPU/promote-alloca-padding-size-estimate.ll =================================================================== --- test/CodeGen/AMDGPU/promote-alloca-padding-size-estimate.ll +++ test/CodeGen/AMDGPU/promote-alloca-padding-size-estimate.ll @@ -127,4 +127,4 @@ ret void } -attributes #0 = { nounwind "amdgpu-max-work-group-size"="64" } +attributes #0 = { nounwind "amdgpu-flat-work-group-size"="64,64" "amdgpu-waves-per-eu"="1,7" } Index: test/CodeGen/AMDGPU/promote-alloca-to-lds-icmp.ll =================================================================== --- test/CodeGen/AMDGPU/promote-alloca-to-lds-icmp.ll +++ test/CodeGen/AMDGPU/promote-alloca-to-lds-icmp.ll @@ -61,4 +61,4 @@ declare i32* @get_unknown_pointer() #0 -attributes #0 = { nounwind "amdgpu-max-waves-per-eu"="1" } +attributes #0 = { nounwind "amdgpu-waves-per-eu"="1,1" } Index: test/CodeGen/AMDGPU/promote-alloca-to-lds-phi.ll =================================================================== --- test/CodeGen/AMDGPU/promote-alloca-to-lds-phi.ll +++ test/CodeGen/AMDGPU/promote-alloca-to-lds-phi.ll @@ -201,4 +201,4 @@ declare i32* @get_unknown_pointer() #0 -attributes #0 = { nounwind "amdgpu-max-waves-per-eu"="1" } +attributes #0 = { nounwind "amdgpu-waves-per-eu"="1,1" } Index: test/CodeGen/AMDGPU/promote-alloca-to-lds-select.ll =================================================================== --- test/CodeGen/AMDGPU/promote-alloca-to-lds-select.ll +++ test/CodeGen/AMDGPU/promote-alloca-to-lds-select.ll @@ -129,5 +129,5 @@ ret void } -attributes #0 = { norecurse nounwind "amdgpu-max-waves-per-eu"="1" } +attributes #0 = { norecurse nounwind "amdgpu-waves-per-eu"="1,1" } attributes #1 = { norecurse nounwind } \ No newline at end of file Index: test/CodeGen/AMDGPU/target-cpu.ll =================================================================== --- test/CodeGen/AMDGPU/target-cpu.ll +++ test/CodeGen/AMDGPU/target-cpu.ll @@ -108,5 +108,5 @@ attributes #2 = { nounwind "target-cpu"="tahiti" } attributes #3 = { nounwind "target-cpu"="bonaire" } attributes #4 = { nounwind "target-cpu"="fiji" } -attributes #5 = { nounwind "target-features"="+promote-alloca" "amdgpu-max-waves-per-eu"="3" } -attributes #6 = { nounwind "target-features"="-promote-alloca" "amdgpu-max-waves-per-eu"="3" } +attributes #5 = { nounwind "target-features"="+promote-alloca" "amdgpu-waves-per-eu"="1,3" } +attributes #6 = { nounwind "target-features"="-promote-alloca" "amdgpu-waves-per-eu"="1,3" }