xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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