1fe6060f1SDimitry Andric //===- AMDGPUAttributor.cpp -----------------------------------------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric /// \file This pass uses Attributor framework to deduce AMDGPU attributes. 10fe6060f1SDimitry Andric // 11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 12fe6060f1SDimitry Andric 13fe6060f1SDimitry Andric #include "AMDGPU.h" 14fe6060f1SDimitry Andric #include "GCNSubtarget.h" 1581ad6265SDimitry Andric #include "Utils/AMDGPUBaseInfo.h" 16bdd1243dSDimitry Andric #include "llvm/Analysis/CycleAnalysis.h" 17fe6060f1SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 18fe6060f1SDimitry Andric #include "llvm/IR/IntrinsicsAMDGPU.h" 19fe6060f1SDimitry Andric #include "llvm/IR/IntrinsicsR600.h" 20fe6060f1SDimitry Andric #include "llvm/Target/TargetMachine.h" 21fe6060f1SDimitry Andric #include "llvm/Transforms/IPO/Attributor.h" 22fe6060f1SDimitry Andric 23fe6060f1SDimitry Andric #define DEBUG_TYPE "amdgpu-attributor" 24fe6060f1SDimitry Andric 25bdd1243dSDimitry Andric namespace llvm { 26bdd1243dSDimitry Andric void initializeCycleInfoWrapperPassPass(PassRegistry &); 27bdd1243dSDimitry Andric } 28bdd1243dSDimitry Andric 29fe6060f1SDimitry Andric using namespace llvm; 30fe6060f1SDimitry Andric 3181ad6265SDimitry Andric #define AMDGPU_ATTRIBUTE(Name, Str) Name##_POS, 32349cc55cSDimitry Andric 3381ad6265SDimitry Andric enum ImplicitArgumentPositions { 3481ad6265SDimitry Andric #include "AMDGPUAttributes.def" 3581ad6265SDimitry Andric LAST_ARG_POS 36349cc55cSDimitry Andric }; 37349cc55cSDimitry Andric 3881ad6265SDimitry Andric #define AMDGPU_ATTRIBUTE(Name, Str) Name = 1 << Name##_POS, 3981ad6265SDimitry Andric 4081ad6265SDimitry Andric enum ImplicitArgumentMask { 4181ad6265SDimitry Andric NOT_IMPLICIT_INPUT = 0, 4281ad6265SDimitry Andric #include "AMDGPUAttributes.def" 4381ad6265SDimitry Andric ALL_ARGUMENT_MASK = (1 << LAST_ARG_POS) - 1 4481ad6265SDimitry Andric }; 4581ad6265SDimitry Andric 4681ad6265SDimitry Andric #define AMDGPU_ATTRIBUTE(Name, Str) {Name, Str}, 47349cc55cSDimitry Andric static constexpr std::pair<ImplicitArgumentMask, 48349cc55cSDimitry Andric StringLiteral> ImplicitAttrs[] = { 4981ad6265SDimitry Andric #include "AMDGPUAttributes.def" 50349cc55cSDimitry Andric }; 51fe6060f1SDimitry Andric 52fe6060f1SDimitry Andric // We do not need to note the x workitem or workgroup id because they are always 53fe6060f1SDimitry Andric // initialized. 54fe6060f1SDimitry Andric // 55fe6060f1SDimitry Andric // TODO: We should not add the attributes if the known compile time workgroup 56fe6060f1SDimitry Andric // size is 1 for y/z. 57349cc55cSDimitry Andric static ImplicitArgumentMask 5881ad6265SDimitry Andric intrinsicToAttrMask(Intrinsic::ID ID, bool &NonKernelOnly, bool &NeedsImplicit, 59*06c3fb27SDimitry Andric bool HasApertureRegs, bool SupportsGetDoorBellID, 60*06c3fb27SDimitry Andric unsigned CodeObjectVersion) { 61fe6060f1SDimitry Andric switch (ID) { 62fe6060f1SDimitry Andric case Intrinsic::amdgcn_workitem_id_x: 63fe6060f1SDimitry Andric NonKernelOnly = true; 64349cc55cSDimitry Andric return WORKITEM_ID_X; 65fe6060f1SDimitry Andric case Intrinsic::amdgcn_workgroup_id_x: 66fe6060f1SDimitry Andric NonKernelOnly = true; 67349cc55cSDimitry Andric return WORKGROUP_ID_X; 68fe6060f1SDimitry Andric case Intrinsic::amdgcn_workitem_id_y: 69fe6060f1SDimitry Andric case Intrinsic::r600_read_tidig_y: 70349cc55cSDimitry Andric return WORKITEM_ID_Y; 71fe6060f1SDimitry Andric case Intrinsic::amdgcn_workitem_id_z: 72fe6060f1SDimitry Andric case Intrinsic::r600_read_tidig_z: 73349cc55cSDimitry Andric return WORKITEM_ID_Z; 74fe6060f1SDimitry Andric case Intrinsic::amdgcn_workgroup_id_y: 75fe6060f1SDimitry Andric case Intrinsic::r600_read_tgid_y: 76349cc55cSDimitry Andric return WORKGROUP_ID_Y; 77fe6060f1SDimitry Andric case Intrinsic::amdgcn_workgroup_id_z: 78fe6060f1SDimitry Andric case Intrinsic::r600_read_tgid_z: 79349cc55cSDimitry Andric return WORKGROUP_ID_Z; 80fcaf7f86SDimitry Andric case Intrinsic::amdgcn_lds_kernel_id: 81fcaf7f86SDimitry Andric return LDS_KERNEL_ID; 82fe6060f1SDimitry Andric case Intrinsic::amdgcn_dispatch_ptr: 83349cc55cSDimitry Andric return DISPATCH_PTR; 84fe6060f1SDimitry Andric case Intrinsic::amdgcn_dispatch_id: 85349cc55cSDimitry Andric return DISPATCH_ID; 86fe6060f1SDimitry Andric case Intrinsic::amdgcn_implicitarg_ptr: 87349cc55cSDimitry Andric return IMPLICIT_ARG_PTR; 8881ad6265SDimitry Andric // Need queue_ptr anyway. But under V5, we also need implicitarg_ptr to access 8981ad6265SDimitry Andric // queue_ptr. 90fe6060f1SDimitry Andric case Intrinsic::amdgcn_queue_ptr: 91*06c3fb27SDimitry Andric NeedsImplicit = (CodeObjectVersion >= AMDGPU::AMDHSA_COV5); 9281ad6265SDimitry Andric return QUEUE_PTR; 93fe6060f1SDimitry Andric case Intrinsic::amdgcn_is_shared: 94fe6060f1SDimitry Andric case Intrinsic::amdgcn_is_private: 9581ad6265SDimitry Andric if (HasApertureRegs) 9681ad6265SDimitry Andric return NOT_IMPLICIT_INPUT; 9781ad6265SDimitry Andric // Under V5, we need implicitarg_ptr + offsets to access private_base or 9881ad6265SDimitry Andric // shared_base. For pre-V5, however, need to access them through queue_ptr + 9981ad6265SDimitry Andric // offsets. 100*06c3fb27SDimitry Andric return CodeObjectVersion >= AMDGPU::AMDHSA_COV5 ? IMPLICIT_ARG_PTR : 101*06c3fb27SDimitry Andric QUEUE_PTR; 102fe6060f1SDimitry Andric case Intrinsic::trap: 10381ad6265SDimitry Andric if (SupportsGetDoorBellID) // GetDoorbellID support implemented since V4. 104*06c3fb27SDimitry Andric return CodeObjectVersion >= AMDGPU::AMDHSA_COV4 ? NOT_IMPLICIT_INPUT : 105*06c3fb27SDimitry Andric QUEUE_PTR; 106*06c3fb27SDimitry Andric NeedsImplicit = (CodeObjectVersion >= AMDGPU::AMDHSA_COV5); 107349cc55cSDimitry Andric return QUEUE_PTR; 108fe6060f1SDimitry Andric default: 109349cc55cSDimitry Andric return NOT_IMPLICIT_INPUT; 110fe6060f1SDimitry Andric } 111fe6060f1SDimitry Andric } 112fe6060f1SDimitry Andric 113fe6060f1SDimitry Andric static bool castRequiresQueuePtr(unsigned SrcAS) { 114fe6060f1SDimitry Andric return SrcAS == AMDGPUAS::LOCAL_ADDRESS || SrcAS == AMDGPUAS::PRIVATE_ADDRESS; 115fe6060f1SDimitry Andric } 116fe6060f1SDimitry Andric 117fe6060f1SDimitry Andric static bool isDSAddress(const Constant *C) { 118fe6060f1SDimitry Andric const GlobalValue *GV = dyn_cast<GlobalValue>(C); 119fe6060f1SDimitry Andric if (!GV) 120fe6060f1SDimitry Andric return false; 121fe6060f1SDimitry Andric unsigned AS = GV->getAddressSpace(); 122fe6060f1SDimitry Andric return AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::REGION_ADDRESS; 123fe6060f1SDimitry Andric } 124fe6060f1SDimitry Andric 1250eae32dcSDimitry Andric /// Returns true if the function requires the implicit argument be passed 1260eae32dcSDimitry Andric /// regardless of the function contents. 12781ad6265SDimitry Andric static bool funcRequiresHostcallPtr(const Function &F) { 1280eae32dcSDimitry Andric // Sanitizers require the hostcall buffer passed in the implicit arguments. 1290eae32dcSDimitry Andric return F.hasFnAttribute(Attribute::SanitizeAddress) || 1300eae32dcSDimitry Andric F.hasFnAttribute(Attribute::SanitizeThread) || 1310eae32dcSDimitry Andric F.hasFnAttribute(Attribute::SanitizeMemory) || 1320eae32dcSDimitry Andric F.hasFnAttribute(Attribute::SanitizeHWAddress) || 1330eae32dcSDimitry Andric F.hasFnAttribute(Attribute::SanitizeMemTag); 1340eae32dcSDimitry Andric } 1350eae32dcSDimitry Andric 136349cc55cSDimitry Andric namespace { 137fe6060f1SDimitry Andric class AMDGPUInformationCache : public InformationCache { 138fe6060f1SDimitry Andric public: 139fe6060f1SDimitry Andric AMDGPUInformationCache(const Module &M, AnalysisGetter &AG, 140fe6060f1SDimitry Andric BumpPtrAllocator &Allocator, 141fe6060f1SDimitry Andric SetVector<Function *> *CGSCC, TargetMachine &TM) 142*06c3fb27SDimitry Andric : InformationCache(M, AG, Allocator, CGSCC), TM(TM), 143*06c3fb27SDimitry Andric CodeObjectVersion(AMDGPU::getCodeObjectVersion(M)) {} 144*06c3fb27SDimitry Andric 145fe6060f1SDimitry Andric TargetMachine &TM; 146fe6060f1SDimitry Andric 147fe6060f1SDimitry Andric enum ConstantStatus { DS_GLOBAL = 1 << 0, ADDR_SPACE_CAST = 1 << 1 }; 148fe6060f1SDimitry Andric 149fe6060f1SDimitry Andric /// Check if the subtarget has aperture regs. 150fe6060f1SDimitry Andric bool hasApertureRegs(Function &F) { 151fe6060f1SDimitry Andric const GCNSubtarget &ST = TM.getSubtarget<GCNSubtarget>(F); 152fe6060f1SDimitry Andric return ST.hasApertureRegs(); 153fe6060f1SDimitry Andric } 154fe6060f1SDimitry Andric 15581ad6265SDimitry Andric /// Check if the subtarget supports GetDoorbellID. 15681ad6265SDimitry Andric bool supportsGetDoorbellID(Function &F) { 15781ad6265SDimitry Andric const GCNSubtarget &ST = TM.getSubtarget<GCNSubtarget>(F); 15881ad6265SDimitry Andric return ST.supportsGetDoorbellID(); 15981ad6265SDimitry Andric } 16081ad6265SDimitry Andric 161349cc55cSDimitry Andric std::pair<unsigned, unsigned> getFlatWorkGroupSizes(const Function &F) { 162349cc55cSDimitry Andric const GCNSubtarget &ST = TM.getSubtarget<GCNSubtarget>(F); 163349cc55cSDimitry Andric return ST.getFlatWorkGroupSizes(F); 164349cc55cSDimitry Andric } 165349cc55cSDimitry Andric 166349cc55cSDimitry Andric std::pair<unsigned, unsigned> 167349cc55cSDimitry Andric getMaximumFlatWorkGroupRange(const Function &F) { 168349cc55cSDimitry Andric const GCNSubtarget &ST = TM.getSubtarget<GCNSubtarget>(F); 169349cc55cSDimitry Andric return {ST.getMinFlatWorkGroupSize(), ST.getMaxFlatWorkGroupSize()}; 170349cc55cSDimitry Andric } 171349cc55cSDimitry Andric 172*06c3fb27SDimitry Andric /// Get code object version. 173*06c3fb27SDimitry Andric unsigned getCodeObjectVersion() const { 174*06c3fb27SDimitry Andric return CodeObjectVersion; 175*06c3fb27SDimitry Andric } 176*06c3fb27SDimitry Andric 177*06c3fb27SDimitry Andric /// Get the effective value of "amdgpu-waves-per-eu" for the function, 178*06c3fb27SDimitry Andric /// accounting for the interaction with the passed value to use for 179*06c3fb27SDimitry Andric /// "amdgpu-flat-work-group-size". 180*06c3fb27SDimitry Andric std::pair<unsigned, unsigned> 181*06c3fb27SDimitry Andric getWavesPerEU(const Function &F, 182*06c3fb27SDimitry Andric std::pair<unsigned, unsigned> FlatWorkGroupSize) { 183*06c3fb27SDimitry Andric const GCNSubtarget &ST = TM.getSubtarget<GCNSubtarget>(F); 184*06c3fb27SDimitry Andric return ST.getWavesPerEU(F, FlatWorkGroupSize); 185*06c3fb27SDimitry Andric } 186*06c3fb27SDimitry Andric 187*06c3fb27SDimitry Andric std::pair<unsigned, unsigned> 188*06c3fb27SDimitry Andric getEffectiveWavesPerEU(const Function &F, 189*06c3fb27SDimitry Andric std::pair<unsigned, unsigned> WavesPerEU, 190*06c3fb27SDimitry Andric std::pair<unsigned, unsigned> FlatWorkGroupSize) { 191*06c3fb27SDimitry Andric const GCNSubtarget &ST = TM.getSubtarget<GCNSubtarget>(F); 192*06c3fb27SDimitry Andric return ST.getEffectiveWavesPerEU(WavesPerEU, FlatWorkGroupSize); 193*06c3fb27SDimitry Andric } 194*06c3fb27SDimitry Andric 195*06c3fb27SDimitry Andric unsigned getMaxWavesPerEU(const Function &F) { 196*06c3fb27SDimitry Andric const GCNSubtarget &ST = TM.getSubtarget<GCNSubtarget>(F); 197*06c3fb27SDimitry Andric return ST.getMaxWavesPerEU(); 198*06c3fb27SDimitry Andric } 199*06c3fb27SDimitry Andric 200fe6060f1SDimitry Andric private: 20181ad6265SDimitry Andric /// Check if the ConstantExpr \p CE requires the queue pointer. 202fe6060f1SDimitry Andric static bool visitConstExpr(const ConstantExpr *CE) { 203fe6060f1SDimitry Andric if (CE->getOpcode() == Instruction::AddrSpaceCast) { 204fe6060f1SDimitry Andric unsigned SrcAS = CE->getOperand(0)->getType()->getPointerAddressSpace(); 205fe6060f1SDimitry Andric return castRequiresQueuePtr(SrcAS); 206fe6060f1SDimitry Andric } 207fe6060f1SDimitry Andric return false; 208fe6060f1SDimitry Andric } 209fe6060f1SDimitry Andric 210fe6060f1SDimitry Andric /// Get the constant access bitmap for \p C. 211*06c3fb27SDimitry Andric uint8_t getConstantAccess(const Constant *C, 212*06c3fb27SDimitry Andric SmallPtrSetImpl<const Constant *> &Visited) { 213fe6060f1SDimitry Andric auto It = ConstantStatus.find(C); 214fe6060f1SDimitry Andric if (It != ConstantStatus.end()) 215fe6060f1SDimitry Andric return It->second; 216fe6060f1SDimitry Andric 217fe6060f1SDimitry Andric uint8_t Result = 0; 218fe6060f1SDimitry Andric if (isDSAddress(C)) 219fe6060f1SDimitry Andric Result = DS_GLOBAL; 220fe6060f1SDimitry Andric 221fe6060f1SDimitry Andric if (const auto *CE = dyn_cast<ConstantExpr>(C)) 222fe6060f1SDimitry Andric if (visitConstExpr(CE)) 223fe6060f1SDimitry Andric Result |= ADDR_SPACE_CAST; 224fe6060f1SDimitry Andric 225fe6060f1SDimitry Andric for (const Use &U : C->operands()) { 226fe6060f1SDimitry Andric const auto *OpC = dyn_cast<Constant>(U); 227*06c3fb27SDimitry Andric if (!OpC || !Visited.insert(OpC).second) 228fe6060f1SDimitry Andric continue; 229fe6060f1SDimitry Andric 230*06c3fb27SDimitry Andric Result |= getConstantAccess(OpC, Visited); 231fe6060f1SDimitry Andric } 232fe6060f1SDimitry Andric return Result; 233fe6060f1SDimitry Andric } 234fe6060f1SDimitry Andric 235fe6060f1SDimitry Andric public: 23681ad6265SDimitry Andric /// Returns true if \p Fn needs the queue pointer because of \p C. 237fe6060f1SDimitry Andric bool needsQueuePtr(const Constant *C, Function &Fn) { 238fe6060f1SDimitry Andric bool IsNonEntryFunc = !AMDGPU::isEntryFunctionCC(Fn.getCallingConv()); 239fe6060f1SDimitry Andric bool HasAperture = hasApertureRegs(Fn); 240fe6060f1SDimitry Andric 241fe6060f1SDimitry Andric // No need to explore the constants. 242fe6060f1SDimitry Andric if (!IsNonEntryFunc && HasAperture) 243fe6060f1SDimitry Andric return false; 244fe6060f1SDimitry Andric 245*06c3fb27SDimitry Andric SmallPtrSet<const Constant *, 8> Visited; 246*06c3fb27SDimitry Andric uint8_t Access = getConstantAccess(C, Visited); 247fe6060f1SDimitry Andric 248fe6060f1SDimitry Andric // We need to trap on DS globals in non-entry functions. 249fe6060f1SDimitry Andric if (IsNonEntryFunc && (Access & DS_GLOBAL)) 250fe6060f1SDimitry Andric return true; 251fe6060f1SDimitry Andric 252fe6060f1SDimitry Andric return !HasAperture && (Access & ADDR_SPACE_CAST); 253fe6060f1SDimitry Andric } 254fe6060f1SDimitry Andric 255fe6060f1SDimitry Andric private: 25681ad6265SDimitry Andric /// Used to determine if the Constant needs the queue pointer. 257fe6060f1SDimitry Andric DenseMap<const Constant *, uint8_t> ConstantStatus; 258*06c3fb27SDimitry Andric const unsigned CodeObjectVersion; 259fe6060f1SDimitry Andric }; 260fe6060f1SDimitry Andric 261bdd1243dSDimitry Andric struct AAAMDAttributes 262bdd1243dSDimitry Andric : public StateWrapper<BitIntegerState<uint32_t, ALL_ARGUMENT_MASK, 0>, 263bdd1243dSDimitry Andric AbstractAttribute> { 264bdd1243dSDimitry Andric using Base = StateWrapper<BitIntegerState<uint32_t, ALL_ARGUMENT_MASK, 0>, 265349cc55cSDimitry Andric AbstractAttribute>; 266349cc55cSDimitry Andric 267fe6060f1SDimitry Andric AAAMDAttributes(const IRPosition &IRP, Attributor &A) : Base(IRP) {} 268fe6060f1SDimitry Andric 269fe6060f1SDimitry Andric /// Create an abstract attribute view for the position \p IRP. 270fe6060f1SDimitry Andric static AAAMDAttributes &createForPosition(const IRPosition &IRP, 271fe6060f1SDimitry Andric Attributor &A); 272fe6060f1SDimitry Andric 273fe6060f1SDimitry Andric /// See AbstractAttribute::getName(). 274fe6060f1SDimitry Andric const std::string getName() const override { return "AAAMDAttributes"; } 275fe6060f1SDimitry Andric 276fe6060f1SDimitry Andric /// See AbstractAttribute::getIdAddr(). 277fe6060f1SDimitry Andric const char *getIdAddr() const override { return &ID; } 278fe6060f1SDimitry Andric 279fe6060f1SDimitry Andric /// This function should return true if the type of the \p AA is 280fe6060f1SDimitry Andric /// AAAMDAttributes. 281fe6060f1SDimitry Andric static bool classof(const AbstractAttribute *AA) { 282fe6060f1SDimitry Andric return (AA->getIdAddr() == &ID); 283fe6060f1SDimitry Andric } 284fe6060f1SDimitry Andric 285fe6060f1SDimitry Andric /// Unique ID (due to the unique address) 286fe6060f1SDimitry Andric static const char ID; 287fe6060f1SDimitry Andric }; 288fe6060f1SDimitry Andric const char AAAMDAttributes::ID = 0; 289fe6060f1SDimitry Andric 290349cc55cSDimitry Andric struct AAUniformWorkGroupSize 291fe6060f1SDimitry Andric : public StateWrapper<BooleanState, AbstractAttribute> { 292fe6060f1SDimitry Andric using Base = StateWrapper<BooleanState, AbstractAttribute>; 293349cc55cSDimitry Andric AAUniformWorkGroupSize(const IRPosition &IRP, Attributor &A) : Base(IRP) {} 294fe6060f1SDimitry Andric 295fe6060f1SDimitry Andric /// Create an abstract attribute view for the position \p IRP. 296349cc55cSDimitry Andric static AAUniformWorkGroupSize &createForPosition(const IRPosition &IRP, 297fe6060f1SDimitry Andric Attributor &A); 298fe6060f1SDimitry Andric 299fe6060f1SDimitry Andric /// See AbstractAttribute::getName(). 300349cc55cSDimitry Andric const std::string getName() const override { 301349cc55cSDimitry Andric return "AAUniformWorkGroupSize"; 302349cc55cSDimitry Andric } 303fe6060f1SDimitry Andric 304fe6060f1SDimitry Andric /// See AbstractAttribute::getIdAddr(). 305fe6060f1SDimitry Andric const char *getIdAddr() const override { return &ID; } 306fe6060f1SDimitry Andric 307fe6060f1SDimitry Andric /// This function should return true if the type of the \p AA is 308fe6060f1SDimitry Andric /// AAAMDAttributes. 309fe6060f1SDimitry Andric static bool classof(const AbstractAttribute *AA) { 310fe6060f1SDimitry Andric return (AA->getIdAddr() == &ID); 311fe6060f1SDimitry Andric } 312fe6060f1SDimitry Andric 313fe6060f1SDimitry Andric /// Unique ID (due to the unique address) 314fe6060f1SDimitry Andric static const char ID; 315fe6060f1SDimitry Andric }; 316349cc55cSDimitry Andric const char AAUniformWorkGroupSize::ID = 0; 317fe6060f1SDimitry Andric 318349cc55cSDimitry Andric struct AAUniformWorkGroupSizeFunction : public AAUniformWorkGroupSize { 319349cc55cSDimitry Andric AAUniformWorkGroupSizeFunction(const IRPosition &IRP, Attributor &A) 320349cc55cSDimitry Andric : AAUniformWorkGroupSize(IRP, A) {} 321fe6060f1SDimitry Andric 322fe6060f1SDimitry Andric void initialize(Attributor &A) override { 323fe6060f1SDimitry Andric Function *F = getAssociatedFunction(); 324fe6060f1SDimitry Andric CallingConv::ID CC = F->getCallingConv(); 325fe6060f1SDimitry Andric 326fe6060f1SDimitry Andric if (CC != CallingConv::AMDGPU_KERNEL) 327fe6060f1SDimitry Andric return; 328fe6060f1SDimitry Andric 329fe6060f1SDimitry Andric bool InitialValue = false; 330fe6060f1SDimitry Andric if (F->hasFnAttribute("uniform-work-group-size")) 331fe6060f1SDimitry Andric InitialValue = F->getFnAttribute("uniform-work-group-size") 332fe6060f1SDimitry Andric .getValueAsString() 333fe6060f1SDimitry Andric .equals("true"); 334fe6060f1SDimitry Andric 335fe6060f1SDimitry Andric if (InitialValue) 336fe6060f1SDimitry Andric indicateOptimisticFixpoint(); 337fe6060f1SDimitry Andric else 338fe6060f1SDimitry Andric indicatePessimisticFixpoint(); 339fe6060f1SDimitry Andric } 340fe6060f1SDimitry Andric 341fe6060f1SDimitry Andric ChangeStatus updateImpl(Attributor &A) override { 342fe6060f1SDimitry Andric ChangeStatus Change = ChangeStatus::UNCHANGED; 343fe6060f1SDimitry Andric 344fe6060f1SDimitry Andric auto CheckCallSite = [&](AbstractCallSite CS) { 345fe6060f1SDimitry Andric Function *Caller = CS.getInstruction()->getFunction(); 346349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "[AAUniformWorkGroupSize] Call " << Caller->getName() 347fe6060f1SDimitry Andric << "->" << getAssociatedFunction()->getName() << "\n"); 348fe6060f1SDimitry Andric 349*06c3fb27SDimitry Andric const auto *CallerInfo = A.getAAFor<AAUniformWorkGroupSize>( 350fe6060f1SDimitry Andric *this, IRPosition::function(*Caller), DepClassTy::REQUIRED); 351*06c3fb27SDimitry Andric if (!CallerInfo) 352*06c3fb27SDimitry Andric return false; 353fe6060f1SDimitry Andric 354fe6060f1SDimitry Andric Change = Change | clampStateAndIndicateChange(this->getState(), 355*06c3fb27SDimitry Andric CallerInfo->getState()); 356fe6060f1SDimitry Andric 357fe6060f1SDimitry Andric return true; 358fe6060f1SDimitry Andric }; 359fe6060f1SDimitry Andric 360fe6060f1SDimitry Andric bool AllCallSitesKnown = true; 361fe6060f1SDimitry Andric if (!A.checkForAllCallSites(CheckCallSite, *this, true, AllCallSitesKnown)) 3620eae32dcSDimitry Andric return indicatePessimisticFixpoint(); 363fe6060f1SDimitry Andric 364fe6060f1SDimitry Andric return Change; 365fe6060f1SDimitry Andric } 366fe6060f1SDimitry Andric 367fe6060f1SDimitry Andric ChangeStatus manifest(Attributor &A) override { 368fe6060f1SDimitry Andric SmallVector<Attribute, 8> AttrList; 369fe6060f1SDimitry Andric LLVMContext &Ctx = getAssociatedFunction()->getContext(); 370fe6060f1SDimitry Andric 371fe6060f1SDimitry Andric AttrList.push_back(Attribute::get(Ctx, "uniform-work-group-size", 372fe6060f1SDimitry Andric getAssumed() ? "true" : "false")); 373*06c3fb27SDimitry Andric return A.manifestAttrs(getIRPosition(), AttrList, 374fe6060f1SDimitry Andric /* ForceReplace */ true); 375fe6060f1SDimitry Andric } 376fe6060f1SDimitry Andric 377fe6060f1SDimitry Andric bool isValidState() const override { 378fe6060f1SDimitry Andric // This state is always valid, even when the state is false. 379fe6060f1SDimitry Andric return true; 380fe6060f1SDimitry Andric } 381fe6060f1SDimitry Andric 382*06c3fb27SDimitry Andric const std::string getAsStr(Attributor *) const override { 383fe6060f1SDimitry Andric return "AMDWorkGroupSize[" + std::to_string(getAssumed()) + "]"; 384fe6060f1SDimitry Andric } 385fe6060f1SDimitry Andric 386fe6060f1SDimitry Andric /// See AbstractAttribute::trackStatistics() 387fe6060f1SDimitry Andric void trackStatistics() const override {} 388fe6060f1SDimitry Andric }; 389fe6060f1SDimitry Andric 390349cc55cSDimitry Andric AAUniformWorkGroupSize & 391349cc55cSDimitry Andric AAUniformWorkGroupSize::createForPosition(const IRPosition &IRP, 392fe6060f1SDimitry Andric Attributor &A) { 393fe6060f1SDimitry Andric if (IRP.getPositionKind() == IRPosition::IRP_FUNCTION) 394349cc55cSDimitry Andric return *new (A.Allocator) AAUniformWorkGroupSizeFunction(IRP, A); 395349cc55cSDimitry Andric llvm_unreachable( 396349cc55cSDimitry Andric "AAUniformWorkGroupSize is only valid for function position"); 397fe6060f1SDimitry Andric } 398fe6060f1SDimitry Andric 399fe6060f1SDimitry Andric struct AAAMDAttributesFunction : public AAAMDAttributes { 400fe6060f1SDimitry Andric AAAMDAttributesFunction(const IRPosition &IRP, Attributor &A) 401fe6060f1SDimitry Andric : AAAMDAttributes(IRP, A) {} 402fe6060f1SDimitry Andric 403fe6060f1SDimitry Andric void initialize(Attributor &A) override { 404fe6060f1SDimitry Andric Function *F = getAssociatedFunction(); 4050eae32dcSDimitry Andric 4060eae32dcSDimitry Andric // If the function requires the implicit arg pointer due to sanitizers, 4070eae32dcSDimitry Andric // assume it's needed even if explicitly marked as not requiring it. 40881ad6265SDimitry Andric const bool NeedsHostcall = funcRequiresHostcallPtr(*F); 40981ad6265SDimitry Andric if (NeedsHostcall) { 4100eae32dcSDimitry Andric removeAssumedBits(IMPLICIT_ARG_PTR); 41181ad6265SDimitry Andric removeAssumedBits(HOSTCALL_PTR); 41281ad6265SDimitry Andric } 4130eae32dcSDimitry Andric 414349cc55cSDimitry Andric for (auto Attr : ImplicitAttrs) { 41581ad6265SDimitry Andric if (NeedsHostcall && 41681ad6265SDimitry Andric (Attr.first == IMPLICIT_ARG_PTR || Attr.first == HOSTCALL_PTR)) 4170eae32dcSDimitry Andric continue; 4180eae32dcSDimitry Andric 419349cc55cSDimitry Andric if (F->hasFnAttribute(Attr.second)) 420349cc55cSDimitry Andric addKnownBits(Attr.first); 421fe6060f1SDimitry Andric } 422fe6060f1SDimitry Andric 423349cc55cSDimitry Andric if (F->isDeclaration()) 424349cc55cSDimitry Andric return; 425349cc55cSDimitry Andric 426fe6060f1SDimitry Andric // Ignore functions with graphics calling conventions, these are currently 427fe6060f1SDimitry Andric // not allowed to have kernel arguments. 428fe6060f1SDimitry Andric if (AMDGPU::isGraphics(F->getCallingConv())) { 429fe6060f1SDimitry Andric indicatePessimisticFixpoint(); 430fe6060f1SDimitry Andric return; 431fe6060f1SDimitry Andric } 432fe6060f1SDimitry Andric } 433fe6060f1SDimitry Andric 434fe6060f1SDimitry Andric ChangeStatus updateImpl(Attributor &A) override { 435fe6060f1SDimitry Andric Function *F = getAssociatedFunction(); 436349cc55cSDimitry Andric // The current assumed state used to determine a change. 437349cc55cSDimitry Andric auto OrigAssumed = getAssumed(); 438fe6060f1SDimitry Andric 439fe6060f1SDimitry Andric // Check for Intrinsics and propagate attributes. 440*06c3fb27SDimitry Andric const AACallEdges *AAEdges = A.getAAFor<AACallEdges>( 441fe6060f1SDimitry Andric *this, this->getIRPosition(), DepClassTy::REQUIRED); 442*06c3fb27SDimitry Andric if (!AAEdges || AAEdges->hasNonAsmUnknownCallee()) 443349cc55cSDimitry Andric return indicatePessimisticFixpoint(); 444fe6060f1SDimitry Andric 445349cc55cSDimitry Andric bool IsNonEntryFunc = !AMDGPU::isEntryFunctionCC(F->getCallingConv()); 446fe6060f1SDimitry Andric 44781ad6265SDimitry Andric bool NeedsImplicit = false; 44881ad6265SDimitry Andric auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache()); 44981ad6265SDimitry Andric bool HasApertureRegs = InfoCache.hasApertureRegs(*F); 45081ad6265SDimitry Andric bool SupportsGetDoorbellID = InfoCache.supportsGetDoorbellID(*F); 451*06c3fb27SDimitry Andric unsigned COV = InfoCache.getCodeObjectVersion(); 452349cc55cSDimitry Andric 453*06c3fb27SDimitry Andric for (Function *Callee : AAEdges->getOptimisticEdges()) { 454fe6060f1SDimitry Andric Intrinsic::ID IID = Callee->getIntrinsicID(); 455349cc55cSDimitry Andric if (IID == Intrinsic::not_intrinsic) { 456*06c3fb27SDimitry Andric const AAAMDAttributes *AAAMD = A.getAAFor<AAAMDAttributes>( 457349cc55cSDimitry Andric *this, IRPosition::function(*Callee), DepClassTy::REQUIRED); 458*06c3fb27SDimitry Andric if (!AAAMD) 459*06c3fb27SDimitry Andric return indicatePessimisticFixpoint(); 460*06c3fb27SDimitry Andric *this &= *AAAMD; 461fe6060f1SDimitry Andric continue; 462fe6060f1SDimitry Andric } 463fe6060f1SDimitry Andric 464fe6060f1SDimitry Andric bool NonKernelOnly = false; 465349cc55cSDimitry Andric ImplicitArgumentMask AttrMask = 46681ad6265SDimitry Andric intrinsicToAttrMask(IID, NonKernelOnly, NeedsImplicit, 467*06c3fb27SDimitry Andric HasApertureRegs, SupportsGetDoorbellID, COV); 468349cc55cSDimitry Andric if (AttrMask != NOT_IMPLICIT_INPUT) { 469349cc55cSDimitry Andric if ((IsNonEntryFunc || !NonKernelOnly)) 470349cc55cSDimitry Andric removeAssumedBits(AttrMask); 471fe6060f1SDimitry Andric } 472fe6060f1SDimitry Andric } 473fe6060f1SDimitry Andric 47481ad6265SDimitry Andric // Need implicitarg_ptr to acess queue_ptr, private_base, and shared_base. 47581ad6265SDimitry Andric if (NeedsImplicit) 47681ad6265SDimitry Andric removeAssumedBits(IMPLICIT_ARG_PTR); 47781ad6265SDimitry Andric 47881ad6265SDimitry Andric if (isAssumed(QUEUE_PTR) && checkForQueuePtr(A)) { 47981ad6265SDimitry Andric // Under V5, we need implicitarg_ptr + offsets to access private_base or 48081ad6265SDimitry Andric // shared_base. We do not actually need queue_ptr. 481*06c3fb27SDimitry Andric if (COV >= 5) 48281ad6265SDimitry Andric removeAssumedBits(IMPLICIT_ARG_PTR); 48381ad6265SDimitry Andric else 484349cc55cSDimitry Andric removeAssumedBits(QUEUE_PTR); 485fe6060f1SDimitry Andric } 486fe6060f1SDimitry Andric 487*06c3fb27SDimitry Andric if (funcRetrievesMultigridSyncArg(A, COV)) { 48881ad6265SDimitry Andric assert(!isAssumed(IMPLICIT_ARG_PTR) && 48981ad6265SDimitry Andric "multigrid_sync_arg needs implicitarg_ptr"); 49081ad6265SDimitry Andric removeAssumedBits(MULTIGRID_SYNC_ARG); 491349cc55cSDimitry Andric } 492fe6060f1SDimitry Andric 493*06c3fb27SDimitry Andric if (funcRetrievesHostcallPtr(A, COV)) { 49481ad6265SDimitry Andric assert(!isAssumed(IMPLICIT_ARG_PTR) && "hostcall needs implicitarg_ptr"); 49581ad6265SDimitry Andric removeAssumedBits(HOSTCALL_PTR); 49681ad6265SDimitry Andric } 49781ad6265SDimitry Andric 498*06c3fb27SDimitry Andric if (funcRetrievesHeapPtr(A, COV)) { 49981ad6265SDimitry Andric assert(!isAssumed(IMPLICIT_ARG_PTR) && "heap_ptr needs implicitarg_ptr"); 50081ad6265SDimitry Andric removeAssumedBits(HEAP_PTR); 50181ad6265SDimitry Andric } 50281ad6265SDimitry Andric 503*06c3fb27SDimitry Andric if (isAssumed(QUEUE_PTR) && funcRetrievesQueuePtr(A, COV)) { 50481ad6265SDimitry Andric assert(!isAssumed(IMPLICIT_ARG_PTR) && "queue_ptr needs implicitarg_ptr"); 505349cc55cSDimitry Andric removeAssumedBits(QUEUE_PTR); 506fe6060f1SDimitry Andric } 507fe6060f1SDimitry Andric 508fcaf7f86SDimitry Andric if (isAssumed(LDS_KERNEL_ID) && funcRetrievesLDSKernelId(A)) { 509fcaf7f86SDimitry Andric removeAssumedBits(LDS_KERNEL_ID); 510fcaf7f86SDimitry Andric } 511fcaf7f86SDimitry Andric 512*06c3fb27SDimitry Andric if (isAssumed(DEFAULT_QUEUE) && funcRetrievesDefaultQueue(A, COV)) 513bdd1243dSDimitry Andric removeAssumedBits(DEFAULT_QUEUE); 514bdd1243dSDimitry Andric 515*06c3fb27SDimitry Andric if (isAssumed(COMPLETION_ACTION) && funcRetrievesCompletionAction(A, COV)) 516bdd1243dSDimitry Andric removeAssumedBits(COMPLETION_ACTION); 517bdd1243dSDimitry Andric 51881ad6265SDimitry Andric return getAssumed() != OrigAssumed ? ChangeStatus::CHANGED 51981ad6265SDimitry Andric : ChangeStatus::UNCHANGED; 520fe6060f1SDimitry Andric } 521fe6060f1SDimitry Andric 522fe6060f1SDimitry Andric ChangeStatus manifest(Attributor &A) override { 523fe6060f1SDimitry Andric SmallVector<Attribute, 8> AttrList; 524fe6060f1SDimitry Andric LLVMContext &Ctx = getAssociatedFunction()->getContext(); 525fe6060f1SDimitry Andric 526349cc55cSDimitry Andric for (auto Attr : ImplicitAttrs) { 527349cc55cSDimitry Andric if (isKnown(Attr.first)) 528349cc55cSDimitry Andric AttrList.push_back(Attribute::get(Ctx, Attr.second)); 529349cc55cSDimitry Andric } 530fe6060f1SDimitry Andric 531*06c3fb27SDimitry Andric return A.manifestAttrs(getIRPosition(), AttrList, 532fe6060f1SDimitry Andric /* ForceReplace */ true); 533fe6060f1SDimitry Andric } 534fe6060f1SDimitry Andric 535*06c3fb27SDimitry Andric const std::string getAsStr(Attributor *) const override { 536349cc55cSDimitry Andric std::string Str; 537349cc55cSDimitry Andric raw_string_ostream OS(Str); 538349cc55cSDimitry Andric OS << "AMDInfo["; 539349cc55cSDimitry Andric for (auto Attr : ImplicitAttrs) 540*06c3fb27SDimitry Andric if (isAssumed(Attr.first)) 541349cc55cSDimitry Andric OS << ' ' << Attr.second; 542349cc55cSDimitry Andric OS << " ]"; 543349cc55cSDimitry Andric return OS.str(); 544fe6060f1SDimitry Andric } 545fe6060f1SDimitry Andric 546fe6060f1SDimitry Andric /// See AbstractAttribute::trackStatistics() 547fe6060f1SDimitry Andric void trackStatistics() const override {} 54881ad6265SDimitry Andric 54981ad6265SDimitry Andric private: 55081ad6265SDimitry Andric bool checkForQueuePtr(Attributor &A) { 55181ad6265SDimitry Andric Function *F = getAssociatedFunction(); 55281ad6265SDimitry Andric bool IsNonEntryFunc = !AMDGPU::isEntryFunctionCC(F->getCallingConv()); 55381ad6265SDimitry Andric 55481ad6265SDimitry Andric auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache()); 55581ad6265SDimitry Andric 55681ad6265SDimitry Andric bool NeedsQueuePtr = false; 55781ad6265SDimitry Andric 55881ad6265SDimitry Andric auto CheckAddrSpaceCasts = [&](Instruction &I) { 55981ad6265SDimitry Andric unsigned SrcAS = static_cast<AddrSpaceCastInst &>(I).getSrcAddressSpace(); 56081ad6265SDimitry Andric if (castRequiresQueuePtr(SrcAS)) { 56181ad6265SDimitry Andric NeedsQueuePtr = true; 56281ad6265SDimitry Andric return false; 56381ad6265SDimitry Andric } 56481ad6265SDimitry Andric return true; 56581ad6265SDimitry Andric }; 56681ad6265SDimitry Andric 56781ad6265SDimitry Andric bool HasApertureRegs = InfoCache.hasApertureRegs(*F); 56881ad6265SDimitry Andric 56981ad6265SDimitry Andric // `checkForAllInstructions` is much more cheaper than going through all 57081ad6265SDimitry Andric // instructions, try it first. 57181ad6265SDimitry Andric 57281ad6265SDimitry Andric // The queue pointer is not needed if aperture regs is present. 57381ad6265SDimitry Andric if (!HasApertureRegs) { 57481ad6265SDimitry Andric bool UsedAssumedInformation = false; 57581ad6265SDimitry Andric A.checkForAllInstructions(CheckAddrSpaceCasts, *this, 57681ad6265SDimitry Andric {Instruction::AddrSpaceCast}, 57781ad6265SDimitry Andric UsedAssumedInformation); 57881ad6265SDimitry Andric } 57981ad6265SDimitry Andric 58081ad6265SDimitry Andric // If we found that we need the queue pointer, nothing else to do. 58181ad6265SDimitry Andric if (NeedsQueuePtr) 58281ad6265SDimitry Andric return true; 58381ad6265SDimitry Andric 58481ad6265SDimitry Andric if (!IsNonEntryFunc && HasApertureRegs) 58581ad6265SDimitry Andric return false; 58681ad6265SDimitry Andric 58781ad6265SDimitry Andric for (BasicBlock &BB : *F) { 58881ad6265SDimitry Andric for (Instruction &I : BB) { 58981ad6265SDimitry Andric for (const Use &U : I.operands()) { 59081ad6265SDimitry Andric if (const auto *C = dyn_cast<Constant>(U)) { 59181ad6265SDimitry Andric if (InfoCache.needsQueuePtr(C, *F)) 59281ad6265SDimitry Andric return true; 59381ad6265SDimitry Andric } 59481ad6265SDimitry Andric } 59581ad6265SDimitry Andric } 59681ad6265SDimitry Andric } 59781ad6265SDimitry Andric 59881ad6265SDimitry Andric return false; 59981ad6265SDimitry Andric } 60081ad6265SDimitry Andric 601*06c3fb27SDimitry Andric bool funcRetrievesMultigridSyncArg(Attributor &A, unsigned COV) { 602*06c3fb27SDimitry Andric auto Pos = llvm::AMDGPU::getMultigridSyncArgImplicitArgPosition(COV); 603bdd1243dSDimitry Andric AA::RangeTy Range(Pos, 8); 604bdd1243dSDimitry Andric return funcRetrievesImplicitKernelArg(A, Range); 60581ad6265SDimitry Andric } 60681ad6265SDimitry Andric 607*06c3fb27SDimitry Andric bool funcRetrievesHostcallPtr(Attributor &A, unsigned COV) { 608*06c3fb27SDimitry Andric auto Pos = llvm::AMDGPU::getHostcallImplicitArgPosition(COV); 609bdd1243dSDimitry Andric AA::RangeTy Range(Pos, 8); 610bdd1243dSDimitry Andric return funcRetrievesImplicitKernelArg(A, Range); 611bdd1243dSDimitry Andric } 612bdd1243dSDimitry Andric 613*06c3fb27SDimitry Andric bool funcRetrievesDefaultQueue(Attributor &A, unsigned COV) { 614*06c3fb27SDimitry Andric auto Pos = llvm::AMDGPU::getDefaultQueueImplicitArgPosition(COV); 615bdd1243dSDimitry Andric AA::RangeTy Range(Pos, 8); 616bdd1243dSDimitry Andric return funcRetrievesImplicitKernelArg(A, Range); 617bdd1243dSDimitry Andric } 618bdd1243dSDimitry Andric 619*06c3fb27SDimitry Andric bool funcRetrievesCompletionAction(Attributor &A, unsigned COV) { 620*06c3fb27SDimitry Andric auto Pos = llvm::AMDGPU::getCompletionActionImplicitArgPosition(COV); 621bdd1243dSDimitry Andric AA::RangeTy Range(Pos, 8); 622bdd1243dSDimitry Andric return funcRetrievesImplicitKernelArg(A, Range); 62381ad6265SDimitry Andric } 62481ad6265SDimitry Andric 625*06c3fb27SDimitry Andric bool funcRetrievesHeapPtr(Attributor &A, unsigned COV) { 626*06c3fb27SDimitry Andric if (COV < 5) 62781ad6265SDimitry Andric return false; 628bdd1243dSDimitry Andric AA::RangeTy Range(AMDGPU::ImplicitArg::HEAP_PTR_OFFSET, 8); 629bdd1243dSDimitry Andric return funcRetrievesImplicitKernelArg(A, Range); 63081ad6265SDimitry Andric } 63181ad6265SDimitry Andric 632*06c3fb27SDimitry Andric bool funcRetrievesQueuePtr(Attributor &A, unsigned COV) { 633*06c3fb27SDimitry Andric if (COV < 5) 63481ad6265SDimitry Andric return false; 635bdd1243dSDimitry Andric AA::RangeTy Range(AMDGPU::ImplicitArg::QUEUE_PTR_OFFSET, 8); 636bdd1243dSDimitry Andric return funcRetrievesImplicitKernelArg(A, Range); 63781ad6265SDimitry Andric } 63881ad6265SDimitry Andric 639bdd1243dSDimitry Andric bool funcRetrievesImplicitKernelArg(Attributor &A, AA::RangeTy Range) { 64081ad6265SDimitry Andric // Check if this is a call to the implicitarg_ptr builtin and it 64181ad6265SDimitry Andric // is used to retrieve the hostcall pointer. The implicit arg for 64281ad6265SDimitry Andric // hostcall is not used only if every use of the implicitarg_ptr 64381ad6265SDimitry Andric // is a load that clearly does not retrieve any byte of the 64481ad6265SDimitry Andric // hostcall pointer. We check this by tracing all the uses of the 64581ad6265SDimitry Andric // initial call to the implicitarg_ptr intrinsic. 64681ad6265SDimitry Andric auto DoesNotLeadToKernelArgLoc = [&](Instruction &I) { 64781ad6265SDimitry Andric auto &Call = cast<CallBase>(I); 64881ad6265SDimitry Andric if (Call.getIntrinsicID() != Intrinsic::amdgcn_implicitarg_ptr) 64981ad6265SDimitry Andric return true; 65081ad6265SDimitry Andric 651*06c3fb27SDimitry Andric const auto *PointerInfoAA = A.getAAFor<AAPointerInfo>( 65281ad6265SDimitry Andric *this, IRPosition::callsite_returned(Call), DepClassTy::REQUIRED); 653*06c3fb27SDimitry Andric if (!PointerInfoAA) 654*06c3fb27SDimitry Andric return false; 65581ad6265SDimitry Andric 656*06c3fb27SDimitry Andric return PointerInfoAA->forallInterferingAccesses( 657bdd1243dSDimitry Andric Range, [](const AAPointerInfo::Access &Acc, bool IsExact) { 65881ad6265SDimitry Andric return Acc.getRemoteInst()->isDroppable(); 65981ad6265SDimitry Andric }); 66081ad6265SDimitry Andric }; 66181ad6265SDimitry Andric 66281ad6265SDimitry Andric bool UsedAssumedInformation = false; 66381ad6265SDimitry Andric return !A.checkForAllCallLikeInstructions(DoesNotLeadToKernelArgLoc, *this, 66481ad6265SDimitry Andric UsedAssumedInformation); 66581ad6265SDimitry Andric } 666fcaf7f86SDimitry Andric 667fcaf7f86SDimitry Andric bool funcRetrievesLDSKernelId(Attributor &A) { 668fcaf7f86SDimitry Andric auto DoesNotRetrieve = [&](Instruction &I) { 669fcaf7f86SDimitry Andric auto &Call = cast<CallBase>(I); 670fcaf7f86SDimitry Andric return Call.getIntrinsicID() != Intrinsic::amdgcn_lds_kernel_id; 671fcaf7f86SDimitry Andric }; 672fcaf7f86SDimitry Andric bool UsedAssumedInformation = false; 673fcaf7f86SDimitry Andric return !A.checkForAllCallLikeInstructions(DoesNotRetrieve, *this, 674fcaf7f86SDimitry Andric UsedAssumedInformation); 675fcaf7f86SDimitry Andric } 676fe6060f1SDimitry Andric }; 677fe6060f1SDimitry Andric 678fe6060f1SDimitry Andric AAAMDAttributes &AAAMDAttributes::createForPosition(const IRPosition &IRP, 679fe6060f1SDimitry Andric Attributor &A) { 680fe6060f1SDimitry Andric if (IRP.getPositionKind() == IRPosition::IRP_FUNCTION) 681fe6060f1SDimitry Andric return *new (A.Allocator) AAAMDAttributesFunction(IRP, A); 682fe6060f1SDimitry Andric llvm_unreachable("AAAMDAttributes is only valid for function position"); 683fe6060f1SDimitry Andric } 684fe6060f1SDimitry Andric 685*06c3fb27SDimitry Andric /// Base class to derive different size ranges. 686*06c3fb27SDimitry Andric struct AAAMDSizeRangeAttribute 687349cc55cSDimitry Andric : public StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t> { 688349cc55cSDimitry Andric using Base = StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t>; 689349cc55cSDimitry Andric 690*06c3fb27SDimitry Andric StringRef AttrName; 691*06c3fb27SDimitry Andric 692*06c3fb27SDimitry Andric AAAMDSizeRangeAttribute(const IRPosition &IRP, Attributor &A, 693*06c3fb27SDimitry Andric StringRef AttrName) 694*06c3fb27SDimitry Andric : Base(IRP, 32), AttrName(AttrName) {} 695*06c3fb27SDimitry Andric 696*06c3fb27SDimitry Andric /// See AbstractAttribute::trackStatistics() 697*06c3fb27SDimitry Andric void trackStatistics() const override {} 698*06c3fb27SDimitry Andric 699*06c3fb27SDimitry Andric template <class AttributeImpl> 700*06c3fb27SDimitry Andric ChangeStatus updateImplImpl(Attributor &A) { 701*06c3fb27SDimitry Andric ChangeStatus Change = ChangeStatus::UNCHANGED; 702*06c3fb27SDimitry Andric 703*06c3fb27SDimitry Andric auto CheckCallSite = [&](AbstractCallSite CS) { 704*06c3fb27SDimitry Andric Function *Caller = CS.getInstruction()->getFunction(); 705*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << '[' << getName() << "] Call " << Caller->getName() 706*06c3fb27SDimitry Andric << "->" << getAssociatedFunction()->getName() << '\n'); 707*06c3fb27SDimitry Andric 708*06c3fb27SDimitry Andric const auto *CallerInfo = A.getAAFor<AttributeImpl>( 709*06c3fb27SDimitry Andric *this, IRPosition::function(*Caller), DepClassTy::REQUIRED); 710*06c3fb27SDimitry Andric if (!CallerInfo) 711*06c3fb27SDimitry Andric return false; 712*06c3fb27SDimitry Andric 713*06c3fb27SDimitry Andric Change |= 714*06c3fb27SDimitry Andric clampStateAndIndicateChange(this->getState(), CallerInfo->getState()); 715*06c3fb27SDimitry Andric 716*06c3fb27SDimitry Andric return true; 717*06c3fb27SDimitry Andric }; 718*06c3fb27SDimitry Andric 719*06c3fb27SDimitry Andric bool AllCallSitesKnown = true; 720*06c3fb27SDimitry Andric if (!A.checkForAllCallSites(CheckCallSite, *this, true, AllCallSitesKnown)) 721*06c3fb27SDimitry Andric return indicatePessimisticFixpoint(); 722*06c3fb27SDimitry Andric 723*06c3fb27SDimitry Andric return Change; 724*06c3fb27SDimitry Andric } 725*06c3fb27SDimitry Andric 726*06c3fb27SDimitry Andric ChangeStatus emitAttributeIfNotDefault(Attributor &A, unsigned Min, 727*06c3fb27SDimitry Andric unsigned Max) { 728*06c3fb27SDimitry Andric // Don't add the attribute if it's the implied default. 729*06c3fb27SDimitry Andric if (getAssumed().getLower() == Min && getAssumed().getUpper() - 1 == Max) 730*06c3fb27SDimitry Andric return ChangeStatus::UNCHANGED; 731*06c3fb27SDimitry Andric 732*06c3fb27SDimitry Andric Function *F = getAssociatedFunction(); 733*06c3fb27SDimitry Andric LLVMContext &Ctx = F->getContext(); 734*06c3fb27SDimitry Andric SmallString<10> Buffer; 735*06c3fb27SDimitry Andric raw_svector_ostream OS(Buffer); 736*06c3fb27SDimitry Andric OS << getAssumed().getLower() << ',' << getAssumed().getUpper() - 1; 737*06c3fb27SDimitry Andric return A.manifestAttrs(getIRPosition(), 738*06c3fb27SDimitry Andric {Attribute::get(Ctx, AttrName, OS.str())}, 739*06c3fb27SDimitry Andric /* ForceReplace */ true); 740*06c3fb27SDimitry Andric } 741*06c3fb27SDimitry Andric 742*06c3fb27SDimitry Andric const std::string getAsStr(Attributor *) const override { 743*06c3fb27SDimitry Andric std::string Str; 744*06c3fb27SDimitry Andric raw_string_ostream OS(Str); 745*06c3fb27SDimitry Andric OS << getName() << '['; 746*06c3fb27SDimitry Andric OS << getAssumed().getLower() << ',' << getAssumed().getUpper() - 1; 747*06c3fb27SDimitry Andric OS << ']'; 748*06c3fb27SDimitry Andric return OS.str(); 749*06c3fb27SDimitry Andric } 750*06c3fb27SDimitry Andric }; 751*06c3fb27SDimitry Andric 752*06c3fb27SDimitry Andric /// Propagate amdgpu-flat-work-group-size attribute. 753*06c3fb27SDimitry Andric struct AAAMDFlatWorkGroupSize : public AAAMDSizeRangeAttribute { 754*06c3fb27SDimitry Andric AAAMDFlatWorkGroupSize(const IRPosition &IRP, Attributor &A) 755*06c3fb27SDimitry Andric : AAAMDSizeRangeAttribute(IRP, A, "amdgpu-flat-work-group-size") {} 756349cc55cSDimitry Andric 757349cc55cSDimitry Andric void initialize(Attributor &A) override { 758349cc55cSDimitry Andric Function *F = getAssociatedFunction(); 759349cc55cSDimitry Andric auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache()); 760349cc55cSDimitry Andric unsigned MinGroupSize, MaxGroupSize; 761349cc55cSDimitry Andric std::tie(MinGroupSize, MaxGroupSize) = InfoCache.getFlatWorkGroupSizes(*F); 762349cc55cSDimitry Andric intersectKnown( 763349cc55cSDimitry Andric ConstantRange(APInt(32, MinGroupSize), APInt(32, MaxGroupSize + 1))); 7640eae32dcSDimitry Andric 7650eae32dcSDimitry Andric if (AMDGPU::isEntryFunctionCC(F->getCallingConv())) 7660eae32dcSDimitry Andric indicatePessimisticFixpoint(); 767349cc55cSDimitry Andric } 768349cc55cSDimitry Andric 769349cc55cSDimitry Andric ChangeStatus updateImpl(Attributor &A) override { 770*06c3fb27SDimitry Andric return updateImplImpl<AAAMDFlatWorkGroupSize>(A); 771349cc55cSDimitry Andric } 772349cc55cSDimitry Andric 773349cc55cSDimitry Andric /// Create an abstract attribute view for the position \p IRP. 774349cc55cSDimitry Andric static AAAMDFlatWorkGroupSize &createForPosition(const IRPosition &IRP, 775349cc55cSDimitry Andric Attributor &A); 776349cc55cSDimitry Andric 777*06c3fb27SDimitry Andric ChangeStatus manifest(Attributor &A) override { 778*06c3fb27SDimitry Andric Function *F = getAssociatedFunction(); 779*06c3fb27SDimitry Andric auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache()); 780*06c3fb27SDimitry Andric unsigned Min, Max; 781*06c3fb27SDimitry Andric std::tie(Min, Max) = InfoCache.getMaximumFlatWorkGroupRange(*F); 782*06c3fb27SDimitry Andric return emitAttributeIfNotDefault(A, Min, Max); 783*06c3fb27SDimitry Andric } 784*06c3fb27SDimitry Andric 785349cc55cSDimitry Andric /// See AbstractAttribute::getName() 786349cc55cSDimitry Andric const std::string getName() const override { 787349cc55cSDimitry Andric return "AAAMDFlatWorkGroupSize"; 788349cc55cSDimitry Andric } 789349cc55cSDimitry Andric 790349cc55cSDimitry Andric /// See AbstractAttribute::getIdAddr() 791349cc55cSDimitry Andric const char *getIdAddr() const override { return &ID; } 792349cc55cSDimitry Andric 793349cc55cSDimitry Andric /// This function should return true if the type of the \p AA is 794349cc55cSDimitry Andric /// AAAMDFlatWorkGroupSize 795349cc55cSDimitry Andric static bool classof(const AbstractAttribute *AA) { 796349cc55cSDimitry Andric return (AA->getIdAddr() == &ID); 797349cc55cSDimitry Andric } 798349cc55cSDimitry Andric 799349cc55cSDimitry Andric /// Unique ID (due to the unique address) 800349cc55cSDimitry Andric static const char ID; 801349cc55cSDimitry Andric }; 802349cc55cSDimitry Andric 803349cc55cSDimitry Andric const char AAAMDFlatWorkGroupSize::ID = 0; 804349cc55cSDimitry Andric 805349cc55cSDimitry Andric AAAMDFlatWorkGroupSize & 806349cc55cSDimitry Andric AAAMDFlatWorkGroupSize::createForPosition(const IRPosition &IRP, 807349cc55cSDimitry Andric Attributor &A) { 808349cc55cSDimitry Andric if (IRP.getPositionKind() == IRPosition::IRP_FUNCTION) 809349cc55cSDimitry Andric return *new (A.Allocator) AAAMDFlatWorkGroupSize(IRP, A); 810349cc55cSDimitry Andric llvm_unreachable( 811349cc55cSDimitry Andric "AAAMDFlatWorkGroupSize is only valid for function position"); 812349cc55cSDimitry Andric } 813349cc55cSDimitry Andric 814*06c3fb27SDimitry Andric /// Propagate amdgpu-waves-per-eu attribute. 815*06c3fb27SDimitry Andric struct AAAMDWavesPerEU : public AAAMDSizeRangeAttribute { 816*06c3fb27SDimitry Andric AAAMDWavesPerEU(const IRPosition &IRP, Attributor &A) 817*06c3fb27SDimitry Andric : AAAMDSizeRangeAttribute(IRP, A, "amdgpu-waves-per-eu") {} 818*06c3fb27SDimitry Andric 819*06c3fb27SDimitry Andric bool isValidState() const override { 820*06c3fb27SDimitry Andric return !Assumed.isEmptySet() && IntegerRangeState::isValidState(); 821*06c3fb27SDimitry Andric } 822*06c3fb27SDimitry Andric 823*06c3fb27SDimitry Andric void initialize(Attributor &A) override { 824*06c3fb27SDimitry Andric Function *F = getAssociatedFunction(); 825*06c3fb27SDimitry Andric auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache()); 826*06c3fb27SDimitry Andric 827*06c3fb27SDimitry Andric if (const auto *AssumedGroupSize = A.getAAFor<AAAMDFlatWorkGroupSize>( 828*06c3fb27SDimitry Andric *this, IRPosition::function(*F), DepClassTy::REQUIRED)) { 829*06c3fb27SDimitry Andric 830*06c3fb27SDimitry Andric unsigned Min, Max; 831*06c3fb27SDimitry Andric std::tie(Min, Max) = InfoCache.getWavesPerEU( 832*06c3fb27SDimitry Andric *F, {AssumedGroupSize->getAssumed().getLower().getZExtValue(), 833*06c3fb27SDimitry Andric AssumedGroupSize->getAssumed().getUpper().getZExtValue() - 1}); 834*06c3fb27SDimitry Andric 835*06c3fb27SDimitry Andric ConstantRange Range(APInt(32, Min), APInt(32, Max + 1)); 836*06c3fb27SDimitry Andric intersectKnown(Range); 837*06c3fb27SDimitry Andric } 838*06c3fb27SDimitry Andric 839*06c3fb27SDimitry Andric if (AMDGPU::isEntryFunctionCC(F->getCallingConv())) 840*06c3fb27SDimitry Andric indicatePessimisticFixpoint(); 841*06c3fb27SDimitry Andric } 842*06c3fb27SDimitry Andric 843*06c3fb27SDimitry Andric ChangeStatus updateImpl(Attributor &A) override { 844*06c3fb27SDimitry Andric auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache()); 845*06c3fb27SDimitry Andric ChangeStatus Change = ChangeStatus::UNCHANGED; 846*06c3fb27SDimitry Andric 847*06c3fb27SDimitry Andric auto CheckCallSite = [&](AbstractCallSite CS) { 848*06c3fb27SDimitry Andric Function *Caller = CS.getInstruction()->getFunction(); 849*06c3fb27SDimitry Andric Function *Func = getAssociatedFunction(); 850*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << '[' << getName() << "] Call " << Caller->getName() 851*06c3fb27SDimitry Andric << "->" << Func->getName() << '\n'); 852*06c3fb27SDimitry Andric 853*06c3fb27SDimitry Andric const auto *CallerInfo = A.getAAFor<AAAMDWavesPerEU>( 854*06c3fb27SDimitry Andric *this, IRPosition::function(*Caller), DepClassTy::REQUIRED); 855*06c3fb27SDimitry Andric const auto *AssumedGroupSize = A.getAAFor<AAAMDFlatWorkGroupSize>( 856*06c3fb27SDimitry Andric *this, IRPosition::function(*Func), DepClassTy::REQUIRED); 857*06c3fb27SDimitry Andric if (!CallerInfo || !AssumedGroupSize) 858*06c3fb27SDimitry Andric return false; 859*06c3fb27SDimitry Andric 860*06c3fb27SDimitry Andric unsigned Min, Max; 861*06c3fb27SDimitry Andric std::tie(Min, Max) = InfoCache.getEffectiveWavesPerEU( 862*06c3fb27SDimitry Andric *Caller, 863*06c3fb27SDimitry Andric {CallerInfo->getAssumed().getLower().getZExtValue(), 864*06c3fb27SDimitry Andric CallerInfo->getAssumed().getUpper().getZExtValue() - 1}, 865*06c3fb27SDimitry Andric {AssumedGroupSize->getAssumed().getLower().getZExtValue(), 866*06c3fb27SDimitry Andric AssumedGroupSize->getAssumed().getUpper().getZExtValue() - 1}); 867*06c3fb27SDimitry Andric ConstantRange CallerRange(APInt(32, Min), APInt(32, Max + 1)); 868*06c3fb27SDimitry Andric IntegerRangeState CallerRangeState(CallerRange); 869*06c3fb27SDimitry Andric Change |= clampStateAndIndicateChange(this->getState(), CallerRangeState); 870*06c3fb27SDimitry Andric 871*06c3fb27SDimitry Andric return true; 872*06c3fb27SDimitry Andric }; 873*06c3fb27SDimitry Andric 874*06c3fb27SDimitry Andric bool AllCallSitesKnown = true; 875*06c3fb27SDimitry Andric if (!A.checkForAllCallSites(CheckCallSite, *this, true, AllCallSitesKnown)) 876*06c3fb27SDimitry Andric return indicatePessimisticFixpoint(); 877*06c3fb27SDimitry Andric 878*06c3fb27SDimitry Andric return Change; 879*06c3fb27SDimitry Andric } 880*06c3fb27SDimitry Andric 881*06c3fb27SDimitry Andric /// Create an abstract attribute view for the position \p IRP. 882*06c3fb27SDimitry Andric static AAAMDWavesPerEU &createForPosition(const IRPosition &IRP, 883*06c3fb27SDimitry Andric Attributor &A); 884*06c3fb27SDimitry Andric 885*06c3fb27SDimitry Andric ChangeStatus manifest(Attributor &A) override { 886*06c3fb27SDimitry Andric Function *F = getAssociatedFunction(); 887*06c3fb27SDimitry Andric auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache()); 888*06c3fb27SDimitry Andric unsigned Max = InfoCache.getMaxWavesPerEU(*F); 889*06c3fb27SDimitry Andric return emitAttributeIfNotDefault(A, 1, Max); 890*06c3fb27SDimitry Andric } 891*06c3fb27SDimitry Andric 892*06c3fb27SDimitry Andric /// See AbstractAttribute::getName() 893*06c3fb27SDimitry Andric const std::string getName() const override { return "AAAMDWavesPerEU"; } 894*06c3fb27SDimitry Andric 895*06c3fb27SDimitry Andric /// See AbstractAttribute::getIdAddr() 896*06c3fb27SDimitry Andric const char *getIdAddr() const override { return &ID; } 897*06c3fb27SDimitry Andric 898*06c3fb27SDimitry Andric /// This function should return true if the type of the \p AA is 899*06c3fb27SDimitry Andric /// AAAMDWavesPerEU 900*06c3fb27SDimitry Andric static bool classof(const AbstractAttribute *AA) { 901*06c3fb27SDimitry Andric return (AA->getIdAddr() == &ID); 902*06c3fb27SDimitry Andric } 903*06c3fb27SDimitry Andric 904*06c3fb27SDimitry Andric /// Unique ID (due to the unique address) 905*06c3fb27SDimitry Andric static const char ID; 906*06c3fb27SDimitry Andric }; 907*06c3fb27SDimitry Andric 908*06c3fb27SDimitry Andric const char AAAMDWavesPerEU::ID = 0; 909*06c3fb27SDimitry Andric 910*06c3fb27SDimitry Andric AAAMDWavesPerEU &AAAMDWavesPerEU::createForPosition(const IRPosition &IRP, 911*06c3fb27SDimitry Andric Attributor &A) { 912*06c3fb27SDimitry Andric if (IRP.getPositionKind() == IRPosition::IRP_FUNCTION) 913*06c3fb27SDimitry Andric return *new (A.Allocator) AAAMDWavesPerEU(IRP, A); 914*06c3fb27SDimitry Andric llvm_unreachable("AAAMDWavesPerEU is only valid for function position"); 915*06c3fb27SDimitry Andric } 916*06c3fb27SDimitry Andric 917fe6060f1SDimitry Andric class AMDGPUAttributor : public ModulePass { 918fe6060f1SDimitry Andric public: 919fe6060f1SDimitry Andric AMDGPUAttributor() : ModulePass(ID) {} 920fe6060f1SDimitry Andric 921fe6060f1SDimitry Andric /// doInitialization - Virtual method overridden by subclasses to do 922fe6060f1SDimitry Andric /// any necessary initialization before any pass is run. 923fe6060f1SDimitry Andric bool doInitialization(Module &) override { 924fe6060f1SDimitry Andric auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 925fe6060f1SDimitry Andric if (!TPC) 926fe6060f1SDimitry Andric report_fatal_error("TargetMachine is required"); 927fe6060f1SDimitry Andric 928fe6060f1SDimitry Andric TM = &TPC->getTM<TargetMachine>(); 929fe6060f1SDimitry Andric return false; 930fe6060f1SDimitry Andric } 931fe6060f1SDimitry Andric 932fe6060f1SDimitry Andric bool runOnModule(Module &M) override { 933fe6060f1SDimitry Andric SetVector<Function *> Functions; 934bdd1243dSDimitry Andric AnalysisGetter AG(this); 935349cc55cSDimitry Andric for (Function &F : M) { 936349cc55cSDimitry Andric if (!F.isIntrinsic()) 937fe6060f1SDimitry Andric Functions.insert(&F); 938349cc55cSDimitry Andric } 939fe6060f1SDimitry Andric 940fe6060f1SDimitry Andric CallGraphUpdater CGUpdater; 941fe6060f1SDimitry Andric BumpPtrAllocator Allocator; 942fe6060f1SDimitry Andric AMDGPUInformationCache InfoCache(M, AG, Allocator, nullptr, *TM); 943349cc55cSDimitry Andric DenseSet<const char *> Allowed( 944349cc55cSDimitry Andric {&AAAMDAttributes::ID, &AAUniformWorkGroupSize::ID, 945*06c3fb27SDimitry Andric &AAPotentialValues::ID, &AAAMDFlatWorkGroupSize::ID, 946*06c3fb27SDimitry Andric &AAAMDWavesPerEU::ID, &AACallEdges::ID, &AAPointerInfo::ID, 947*06c3fb27SDimitry Andric &AAPotentialConstantValues::ID, &AAUnderlyingObjects::ID}); 948349cc55cSDimitry Andric 94981ad6265SDimitry Andric AttributorConfig AC(CGUpdater); 95081ad6265SDimitry Andric AC.Allowed = &Allowed; 95181ad6265SDimitry Andric AC.IsModulePass = true; 95281ad6265SDimitry Andric AC.DefaultInitializeLiveInternals = false; 953*06c3fb27SDimitry Andric AC.IPOAmendableCB = [](const Function &F) { 954*06c3fb27SDimitry Andric return F.getCallingConv() == CallingConv::AMDGPU_KERNEL; 955*06c3fb27SDimitry Andric }; 95681ad6265SDimitry Andric 95781ad6265SDimitry Andric Attributor A(Functions, InfoCache, AC); 958fe6060f1SDimitry Andric 959fe6060f1SDimitry Andric for (Function &F : M) { 960349cc55cSDimitry Andric if (!F.isIntrinsic()) { 961fe6060f1SDimitry Andric A.getOrCreateAAFor<AAAMDAttributes>(IRPosition::function(F)); 962349cc55cSDimitry Andric A.getOrCreateAAFor<AAUniformWorkGroupSize>(IRPosition::function(F)); 963349cc55cSDimitry Andric if (!AMDGPU::isEntryFunctionCC(F.getCallingConv())) { 964349cc55cSDimitry Andric A.getOrCreateAAFor<AAAMDFlatWorkGroupSize>(IRPosition::function(F)); 965*06c3fb27SDimitry Andric A.getOrCreateAAFor<AAAMDWavesPerEU>(IRPosition::function(F)); 966349cc55cSDimitry Andric } 967349cc55cSDimitry Andric } 968fe6060f1SDimitry Andric } 969fe6060f1SDimitry Andric 970fe6060f1SDimitry Andric ChangeStatus Change = A.run(); 971fe6060f1SDimitry Andric return Change == ChangeStatus::CHANGED; 972fe6060f1SDimitry Andric } 973fe6060f1SDimitry Andric 974bdd1243dSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 975bdd1243dSDimitry Andric AU.addRequired<CycleInfoWrapperPass>(); 976bdd1243dSDimitry Andric } 977bdd1243dSDimitry Andric 978fe6060f1SDimitry Andric StringRef getPassName() const override { return "AMDGPU Attributor"; } 979fe6060f1SDimitry Andric TargetMachine *TM; 980fe6060f1SDimitry Andric static char ID; 981fe6060f1SDimitry Andric }; 982349cc55cSDimitry Andric } // namespace 983fe6060f1SDimitry Andric 984fe6060f1SDimitry Andric char AMDGPUAttributor::ID = 0; 985fe6060f1SDimitry Andric 986fe6060f1SDimitry Andric Pass *llvm::createAMDGPUAttributorPass() { return new AMDGPUAttributor(); } 987bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(AMDGPUAttributor, DEBUG_TYPE, "AMDGPU Attributor", false, 988bdd1243dSDimitry Andric false) 989bdd1243dSDimitry Andric INITIALIZE_PASS_DEPENDENCY(CycleInfoWrapperPass); 990bdd1243dSDimitry Andric INITIALIZE_PASS_END(AMDGPUAttributor, DEBUG_TYPE, "AMDGPU Attributor", false, 991bdd1243dSDimitry Andric false) 992