LLVM 24.0.0git
AMDGPUAttributor.cpp
Go to the documentation of this file.
1//===- AMDGPUAttributor.cpp -----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file This pass uses Attributor framework to deduce AMDGPU attributes.
10//
11//===----------------------------------------------------------------------===//
12
13#include "AMDGPU.h"
14#include "AMDGPUTargetMachine.h"
15#include "GCNSubtarget.h"
17#include "llvm/IR/IntrinsicsAMDGPU.h"
18#include "llvm/IR/IntrinsicsR600.h"
21#include <cstdint>
22
23#define DEBUG_TYPE "amdgpu-attributor"
24
25using namespace llvm;
26
27#define AMDGPU_ATTRIBUTE(Name, Str) Name##_POS,
28
30#include "AMDGPUAttributes.def"
32};
33
34#define AMDGPU_ATTRIBUTE(Name, Str) Name = 1 << Name##_POS,
35
38#include "AMDGPUAttributes.def"
41};
42
43#define AMDGPU_ATTRIBUTE(Name, Str) {Name, Str},
44static constexpr std::pair<ImplicitArgumentMask, StringLiteral>
46#include "AMDGPUAttributes.def"
47};
48
49// We do not need to note the x workitem or workgroup id because they are always
50// initialized.
51//
52// TODO: We should not add the attributes if the known compile time workgroup
53// size is 1 for y/z.
55intrinsicToAttrMask(Intrinsic::ID ID, bool &NonKernelOnly, bool &NeedsImplicit,
56 bool HasApertureRegs, bool SupportsGetDoorBellID,
57 unsigned CodeObjectVersion) {
58 switch (ID) {
59 case Intrinsic::amdgcn_workitem_id_x:
60 NonKernelOnly = true;
61 return WORKITEM_ID_X;
62 case Intrinsic::amdgcn_workgroup_id_x:
63 NonKernelOnly = true;
64 return WORKGROUP_ID_X;
65 case Intrinsic::amdgcn_workitem_id_y:
66 case Intrinsic::r600_read_tidig_y:
67 return WORKITEM_ID_Y;
68 case Intrinsic::amdgcn_workitem_id_z:
69 case Intrinsic::r600_read_tidig_z:
70 return WORKITEM_ID_Z;
71 case Intrinsic::amdgcn_workgroup_id_y:
72 case Intrinsic::r600_read_tgid_y:
73 return WORKGROUP_ID_Y;
74 case Intrinsic::amdgcn_workgroup_id_z:
75 case Intrinsic::r600_read_tgid_z:
76 return WORKGROUP_ID_Z;
77 case Intrinsic::amdgcn_cluster_id_x:
78 NonKernelOnly = true;
79 return CLUSTER_ID_X;
80 case Intrinsic::amdgcn_cluster_id_y:
81 return CLUSTER_ID_Y;
82 case Intrinsic::amdgcn_cluster_id_z:
83 return CLUSTER_ID_Z;
84 case Intrinsic::amdgcn_lds_kernel_id:
85 return LDS_KERNEL_ID;
86 case Intrinsic::amdgcn_dispatch_ptr:
87 return DISPATCH_PTR;
88 case Intrinsic::amdgcn_dispatch_id:
89 return DISPATCH_ID;
90 case Intrinsic::amdgcn_implicitarg_ptr:
91 return IMPLICIT_ARG_PTR;
92 // Need queue_ptr anyway. But under V5, we also need implicitarg_ptr to access
93 // queue_ptr.
94 case Intrinsic::amdgcn_queue_ptr:
95 NeedsImplicit = (CodeObjectVersion >= AMDGPU::AMDHSA_COV5);
96 return QUEUE_PTR;
97 case Intrinsic::amdgcn_is_shared:
98 case Intrinsic::amdgcn_is_private:
99 if (HasApertureRegs)
100 return NOT_IMPLICIT_INPUT;
101 // Under V5, we need implicitarg_ptr + offsets to access private_base or
102 // shared_base. For pre-V5, however, need to access them through queue_ptr +
103 // offsets.
104 return CodeObjectVersion >= AMDGPU::AMDHSA_COV5 ? IMPLICIT_ARG_PTR
105 : QUEUE_PTR;
106 case Intrinsic::amdgcn_wwm:
107 case Intrinsic::amdgcn_strict_wwm:
108 return WHOLE_WAVE_MODE;
109 case Intrinsic::trap:
110 case Intrinsic::debugtrap:
111 case Intrinsic::ubsantrap:
112 if (SupportsGetDoorBellID) // GetDoorbellID support implemented since V4.
113 return CodeObjectVersion >= AMDGPU::AMDHSA_COV4 ? NOT_IMPLICIT_INPUT
114 : QUEUE_PTR;
115 NeedsImplicit = (CodeObjectVersion >= AMDGPU::AMDHSA_COV5);
116 return QUEUE_PTR;
117 default:
118 return UNKNOWN_INTRINSIC;
119 }
120}
121
122static bool castRequiresQueuePtr(unsigned SrcAS) {
123 return SrcAS == AMDGPUAS::LOCAL_ADDRESS || SrcAS == AMDGPUAS::PRIVATE_ADDRESS;
124}
125
126static bool isDSAddress(const Constant *C) {
128 if (!GV)
129 return false;
130 unsigned AS = GV->getAddressSpace();
132}
133
134/// Returns true if sanitizer attributes are present on a function.
135static bool hasSanitizerAttributes(const Function &F) {
136 return F.hasFnAttribute(Attribute::SanitizeAddress) ||
137 F.hasFnAttribute(Attribute::SanitizeThread) ||
138 F.hasFnAttribute(Attribute::SanitizeConcurrency) ||
139 F.hasFnAttribute(Attribute::SanitizeMemory) ||
140 F.hasFnAttribute(Attribute::SanitizeHWAddress) ||
141 F.hasFnAttribute(Attribute::SanitizeMemTag);
142}
143
144namespace {
145class AMDGPUInformationCache : public InformationCache {
146public:
147 AMDGPUInformationCache(const Module &M, AnalysisGetter &AG,
149 SetVector<Function *> *CGSCC, TargetMachine &TM)
150 : InformationCache(M, AG, Allocator, CGSCC), TM(TM),
151 SubArch(M.getTargetTriple().getSubArch()),
152 Features(
153 AMDGPU::getFeatureBitset(AMDGPU::getGPUKindFromSubArch(SubArch))),
154 CodeObjectVersion(AMDGPU::getAMDHSACodeObjectVersion(M)) {
155 LLVMContext &Ctx = M.getContext();
156 for (auto [Mask, Name] : ImplicitAttrs)
157 ImplicitAttrList.push_back({Mask, Attribute::get(Ctx, Name)});
158 // Sorted by name, the order of attributes in an attribute set.
159 llvm::sort(ImplicitAttrList, [](const auto &A, const auto &B) {
160 return A.second.getKindAsString() < B.second.getKindAsString();
161 });
162
163 unsigned COV = CodeObjectVersion;
164 ImplicitArgRanges = {
165 {MULTIGRID_SYNC_ARG,
166 {AMDGPU::getMultigridSyncArgImplicitArgPosition(COV), 8}},
167 {HOSTCALL_PTR, {AMDGPU::getHostcallImplicitArgPosition(COV), 8}},
168 {DEFAULT_QUEUE, {AMDGPU::getDefaultQueueImplicitArgPosition(COV), 8}},
169 {COMPLETION_ACTION,
171 if (COV >= 5) {
172 ImplicitArgRanges.push_back(
173 {HEAP_PTR, {AMDGPU::ImplicitArg::HEAP_PTR_OFFSET, 8}});
174 ImplicitArgRanges.push_back(
175 {QUEUE_PTR, {AMDGPU::ImplicitArg::QUEUE_PTR_OFFSET, 8}});
176 }
177
178 int64_t Begin = INT64_MAX, End = 0;
179 for (auto [Mask, Range] : ImplicitArgRanges) {
180 ImplicitArgsMask |= Mask;
181 Begin = std::min(Begin, Range.Offset);
182 End = std::max(End, Range.Offset + Range.Size);
183 }
184
185 ImplicitArgsRange = AA::RangeTy(Begin, End - Begin);
186 }
187
188 TargetMachine &TM;
189
190 /// The attributes for the implicit arguments that are not needed, sorted by
191 /// name.
193 getImplicitAttrList() const {
194 return ImplicitAttrList;
195 }
196
197 enum ConstantStatus : uint8_t {
198 NONE = 0,
199 DS_GLOBAL = 1 << 0,
200 ADDR_SPACE_CAST_PRIVATE_TO_FLAT = 1 << 1,
201 ADDR_SPACE_CAST_LOCAL_TO_FLAT = 1 << 2,
202 ADDR_SPACE_CAST_BOTH_TO_FLAT =
203 ADDR_SPACE_CAST_PRIVATE_TO_FLAT | ADDR_SPACE_CAST_LOCAL_TO_FLAT,
204 CS_WORST = DS_GLOBAL | ADDR_SPACE_CAST_BOTH_TO_FLAT,
205 };
206
207 std::optional<std::pair<unsigned, unsigned>>
208 getFlatWorkGroupSizeAttr(const Function &F) const {
209 auto R = AMDGPU::getIntegerPairAttribute(F, "amdgpu-flat-work-group-size");
210 if (!R)
211 return std::nullopt;
212 return std::make_pair(R->first, *(R->second));
213 }
214
215 std::pair<unsigned, unsigned>
216 getDefaultFlatWorkGroupSize(const Function &F) const {
218 return ST.getDefaultFlatWorkGroupSize(F.getCallingConv());
219 }
220
221 std::pair<unsigned, unsigned> getMaximumFlatWorkGroupRange() const {
224 }
225
226 /// Get code object version.
227 unsigned getCodeObjectVersion() const { return CodeObjectVersion; }
228
229 /// The implicit kernel arguments at a fixed offset from implicitarg_ptr,
230 /// with their ranges.
232 getImplicitArgRanges() const {
233 return ImplicitArgRanges;
234 }
235
236 /// The mask of the implicit arguments in getImplicitArgRanges().
237 uint32_t getImplicitArgsMask() const { return ImplicitArgsMask; }
238
239 /// The range covering all the implicit arguments in getImplicitArgRanges().
240 AA::RangeTy getImplicitArgsRange() const { return ImplicitArgsRange; }
241
242 /// Get the features of the module target.
243 const AMDGPU::AMDGPUFeatureBitset &getFeatures() const { return Features; }
244
245 std::optional<std::pair<unsigned, unsigned>>
246 getWavesPerEUAttr(const Function &F) {
247 auto Val = AMDGPU::getIntegerPairAttribute(F, "amdgpu-waves-per-eu",
248 /*OnlyFirstRequired=*/true);
249 if (!Val)
250 return std::nullopt;
251 if (!Val->second)
252 Val->second = AMDGPU::getMaxWavesPerEU(SubArch);
253 return std::make_pair(Val->first, *(Val->second));
254 }
255
256 unsigned getMaxWavesPerEU() const {
257 return AMDGPU::getMaxWavesPerEU(SubArch);
258 }
259
260 unsigned getMaxAddrSpace() const override {
262 }
263
264private:
265 /// Check if the ConstantExpr \p CE uses an addrspacecast from private or
266 /// local to flat. These casts may require the queue pointer.
267 static uint8_t visitConstExpr(const ConstantExpr *CE) {
269
270 if (CE->getOpcode() == Instruction::AddrSpaceCast) {
271 unsigned SrcAS = CE->getOperand(0)->getType()->getPointerAddressSpace();
272 if (SrcAS == AMDGPUAS::PRIVATE_ADDRESS)
273 Status |= ADDR_SPACE_CAST_PRIVATE_TO_FLAT;
274 else if (SrcAS == AMDGPUAS::LOCAL_ADDRESS)
275 Status |= ADDR_SPACE_CAST_LOCAL_TO_FLAT;
276 }
277
278 return Status;
279 }
280
281 /// Get the constant access bitmap for \p C.
282 uint8_t getConstantAccess(const Constant *C) {
283 if (isa<ConstantData>(C))
284 return NONE;
285
286 const auto &It = ConstantStatus.find(C);
287 if (It != ConstantStatus.end())
288 return It->second.value();
289
292 Worklist.push_back(C);
293 Visited.insert(C);
294
295 uint8_t Result = 0;
296 while (Result != CS_WORST && !Worklist.empty()) {
297 const Constant *CurC = Worklist.pop_back_val();
298
299 std::optional<uint8_t> &CurCResultOrNone = ConstantStatus[CurC];
300 if (CurCResultOrNone) {
301 Result |= CurCResultOrNone.value();
302 continue;
303 }
304 uint8_t CurCResult = 0;
305
306 if (isDSAddress(CurC))
307 CurCResult |= DS_GLOBAL;
308
309 if (const auto *CE = dyn_cast<ConstantExpr>(CurC))
310 CurCResult |= visitConstExpr(CE);
311
312 for (const Use &U : CurC->operands()) {
313 if (const auto *OpC = dyn_cast<Constant>(U)) {
314 if (Visited.insert(OpC).second)
315 Worklist.push_back(OpC);
316 }
317 }
318
319 CurCResultOrNone = CurCResult;
320 Result |= CurCResult;
321 }
322
323 ConstantStatus[C] = Result;
324 return Result;
325 }
326
327public:
328 /// Returns true if \p Fn needs the queue pointer because of \p C.
329 bool needsQueuePtr(const Constant *C, Function &Fn) {
330 bool IsNonEntryFunc = !AMDGPU::isEntryFunctionCC(Fn.getCallingConv());
331 bool HasAperture = Features.test(AMDGPU::FEAT_APERTURE_REGS);
332
333 // No need to explore the constants.
334 if (!IsNonEntryFunc && HasAperture)
335 return false;
336
337 uint8_t Access = getConstantAccess(C);
338
339 // We need to trap on DS globals in non-entry functions.
340 if (IsNonEntryFunc && (Access & DS_GLOBAL))
341 return true;
342
343 return !HasAperture && (Access & ADDR_SPACE_CAST_BOTH_TO_FLAT);
344 }
345
346 bool checkConstForAddrSpaceCastFromPrivate(const Constant *C) {
347 uint8_t Access = getConstantAccess(C);
348 return Access & ADDR_SPACE_CAST_PRIVATE_TO_FLAT;
349 }
350
351private:
352 /// Used to determine if the Constant needs the queue pointer.
355 ImplicitAttrList;
356 const Triple::SubArchType SubArch;
357 const AMDGPU::AMDGPUFeatureBitset Features;
358 const unsigned CodeObjectVersion;
360 ImplicitArgRanges;
361 uint32_t ImplicitArgsMask = 0;
362 AA::RangeTy ImplicitArgsRange;
363};
364
365struct AAAMDAttributes
366 : public StateWrapper<BitIntegerState<uint32_t, ALL_ARGUMENT_MASK, 0>,
367 AbstractAttribute> {
368 using Base = StateWrapper<BitIntegerState<uint32_t, ALL_ARGUMENT_MASK, 0>,
369 AbstractAttribute>;
370
371 AAAMDAttributes(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
372
373 /// Create an abstract attribute view for the position \p IRP.
374 static AAAMDAttributes &createForPosition(const IRPosition &IRP,
375 Attributor &A);
376
377 StringRef getName() const override { return "AAAMDAttributes"; }
378
379 const char *getIdAddr() const override { return &ID; }
380
381 /// This function should return true if the type of the \p AA is
382 /// AAAMDAttributes.
383 static bool classof(const AbstractAttribute *AA) {
384 return (AA->getIdAddr() == &ID);
385 }
386
387 /// Unique ID (due to the unique address)
388 static const char ID;
389};
390const char AAAMDAttributes::ID = 0;
391
392struct AAUniformWorkGroupSize
393 : public StateWrapper<BooleanState, AbstractAttribute> {
394 using Base = StateWrapper<BooleanState, AbstractAttribute>;
395 AAUniformWorkGroupSize(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
396
397 /// Create an abstract attribute view for the position \p IRP.
398 static AAUniformWorkGroupSize &createForPosition(const IRPosition &IRP,
399 Attributor &A);
400
401 StringRef getName() const override { return "AAUniformWorkGroupSize"; }
402
403 const char *getIdAddr() const override { return &ID; }
404
405 /// This function should return true if the type of the \p AA is
406 /// AAAMDAttributes.
407 static bool classof(const AbstractAttribute *AA) {
408 return (AA->getIdAddr() == &ID);
409 }
410
411 /// Unique ID (due to the unique address)
412 static const char ID;
413};
414const char AAUniformWorkGroupSize::ID = 0;
415
416struct AAUniformWorkGroupSizeFunction : public AAUniformWorkGroupSize {
417 AAUniformWorkGroupSizeFunction(const IRPosition &IRP, Attributor &A)
418 : AAUniformWorkGroupSize(IRP, A) {}
419
420 void initialize(Attributor &A) override {
421 Function *F = getAssociatedFunction();
422 CallingConv::ID CC = F->getCallingConv();
423
424 if (CC != CallingConv::AMDGPU_KERNEL)
425 return;
426
427 bool InitialValue = F->hasFnAttribute("uniform-work-group-size");
428
429 if (InitialValue)
430 indicateOptimisticFixpoint();
431 else
432 indicatePessimisticFixpoint();
433 }
434
435 ChangeStatus updateImpl(Attributor &A) override {
436 ChangeStatus Change = ChangeStatus::UNCHANGED;
437
438 auto CheckCallSite = [&](AbstractCallSite CS) {
439 Function *Caller = CS.getInstruction()->getFunction();
440 LLVM_DEBUG(dbgs() << "[AAUniformWorkGroupSize] Call " << Caller->getName()
441 << "->" << getAssociatedFunction()->getName() << "\n");
442
443 const auto *CallerInfo = A.getAAFor<AAUniformWorkGroupSize>(
444 *this, IRPosition::function(*Caller), DepClassTy::REQUIRED);
445 if (!CallerInfo || !CallerInfo->isValidState())
446 return false;
447
448 Change = Change | clampStateAndIndicateChange(this->getState(),
449 CallerInfo->getState());
450
451 return true;
452 };
453
454 bool AllCallSitesKnown = true;
455 if (!A.checkForAllCallSites(CheckCallSite, *this, true, AllCallSitesKnown))
456 return indicatePessimisticFixpoint();
457
458 return Change;
459 }
460
461 ChangeStatus manifest(Attributor &A) override {
462 if (!getAssumed())
463 return ChangeStatus::UNCHANGED;
464
465 LLVMContext &Ctx = getAssociatedFunction()->getContext();
466 return A.manifestAttrs(getIRPosition(),
467 {Attribute::get(Ctx, "uniform-work-group-size")},
468 /*ForceReplace=*/true);
469 }
470
471 bool isValidState() const override {
472 // This state is always valid, even when the state is false.
473 return true;
474 }
475
476 const std::string getAsStr(Attributor *) const override {
477 return "AMDWorkGroupSize[" + std::to_string(getAssumed()) + "]";
478 }
479
480 void trackStatistics() const override {}
481};
482
483AAUniformWorkGroupSize &
484AAUniformWorkGroupSize::createForPosition(const IRPosition &IRP,
485 Attributor &A) {
487 return *new (A.Allocator) AAUniformWorkGroupSizeFunction(IRP, A);
489 "AAUniformWorkGroupSize is only valid for function position");
490}
491
492struct AAAMDAttributesFunction : public AAAMDAttributes {
493 AAAMDAttributesFunction(const IRPosition &IRP, Attributor &A)
494 : AAAMDAttributes(IRP, A) {}
495
496 void initialize(Attributor &A) override {
497 Function *F = getAssociatedFunction();
498
499 // If the function requires the implicit arg pointer due to sanitizers,
500 // assume it's needed even if explicitly marked as not requiring it.
501 // Flat scratch initialization is needed because `asan_malloc_impl`
502 // calls introduced later in pipeline will have flat scratch accesses.
503 // FIXME: FLAT_SCRATCH_INIT will not be required here if device-libs
504 // implementation for `asan_malloc_impl` is updated.
505 const bool HasSanitizerAttrs = hasSanitizerAttributes(*F);
506 if (HasSanitizerAttrs) {
507 removeAssumedBits(IMPLICIT_ARG_PTR);
508 removeAssumedBits(HOSTCALL_PTR);
509 removeAssumedBits(FLAT_SCRATCH_INIT);
510 }
511
512 for (auto Attr : ImplicitAttrs) {
513 if (HasSanitizerAttrs &&
514 (Attr.first == IMPLICIT_ARG_PTR || Attr.first == HOSTCALL_PTR ||
515 Attr.first == FLAT_SCRATCH_INIT))
516 continue;
517
518 if (F->hasFnAttribute(Attr.second))
519 addKnownBits(Attr.first);
520 }
521
522 if (F->isDeclaration())
523 return;
524
525 // Ignore functions with graphics calling conventions, these are currently
526 // not allowed to have kernel arguments.
527 if (AMDGPU::isGraphics(F->getCallingConv())) {
528 indicatePessimisticFixpoint();
529 return;
530 }
531 }
532
533 ChangeStatus updateImpl(Attributor &A) override {
534 Function *F = getAssociatedFunction();
535 // The current assumed state used to determine a change.
536 auto OrigAssumed = getAssumed();
537
538 // Check for Intrinsics and propagate attributes.
539 const AACallEdges *AAEdges = A.getAAFor<AACallEdges>(
540 *this, this->getIRPosition(), DepClassTy::REQUIRED);
541 if (!AAEdges || !AAEdges->isValidState() ||
542 AAEdges->hasNonAsmUnknownCallee())
543 return indicatePessimisticFixpoint();
544
545 bool IsNonEntryFunc = !AMDGPU::isEntryFunctionCC(F->getCallingConv());
546
547 bool NeedsImplicit = false;
548 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
549 const AMDGPU::AMDGPUFeatureBitset &Features = InfoCache.getFeatures();
550 bool HasApertureRegs = Features.test(AMDGPU::FEAT_APERTURE_REGS);
551 bool SupportsGetDoorbellID = Features.test(AMDGPU::FEAT_GET_DOORBELL_ID);
552 unsigned COV = InfoCache.getCodeObjectVersion();
553
554 for (Function *Callee : AAEdges->getOptimisticEdges()) {
555 Intrinsic::ID IID = Callee->getIntrinsicID();
556 if (IID == Intrinsic::not_intrinsic) {
557 const AAAMDAttributes *AAAMD = A.getAAFor<AAAMDAttributes>(
558 *this, IRPosition::function(*Callee), DepClassTy::REQUIRED);
559 if (!AAAMD || !AAAMD->isValidState())
560 return indicatePessimisticFixpoint();
561 *this &= *AAAMD;
562 continue;
563 }
564
565 bool NonKernelOnly = false;
566 ImplicitArgumentMask AttrMask =
567 intrinsicToAttrMask(IID, NonKernelOnly, NeedsImplicit,
568 HasApertureRegs, SupportsGetDoorbellID, COV);
569
570 if (AttrMask == UNKNOWN_INTRINSIC) {
571 // Assume not-nocallback intrinsics may invoke a function which accesses
572 // implicit arguments.
573 //
574 // FIXME: This isn't really the correct check. We want to ensure it
575 // isn't calling any function that may use implicit arguments regardless
576 // of whether it's internal to the module or not.
577 //
578 // TODO: Ignoring callsite attributes.
579 if (!Callee->hasFnAttribute(Attribute::NoCallback))
580 return indicatePessimisticFixpoint();
581 continue;
582 }
583
584 if (AttrMask != NOT_IMPLICIT_INPUT) {
585 if ((IsNonEntryFunc || !NonKernelOnly))
586 removeAssumedBits(AttrMask);
587 }
588 }
589
590 // Need implicitarg_ptr to acess queue_ptr, private_base, and shared_base.
591 if (NeedsImplicit)
592 removeAssumedBits(IMPLICIT_ARG_PTR);
593
594 if (isAssumed(QUEUE_PTR) && checkForQueuePtr(A)) {
595 // Under V5, we need implicitarg_ptr + offsets to access private_base or
596 // shared_base. We do not actually need queue_ptr.
597 if (COV >= 5)
598 removeAssumedBits(IMPLICIT_ARG_PTR);
599 else
600 removeAssumedBits(QUEUE_PTR);
601 }
602
603 uint32_t Retrieved = getRetrievedImplicitArgs(A);
604
605 if (Retrieved & MULTIGRID_SYNC_ARG) {
606 assert(!isAssumed(IMPLICIT_ARG_PTR) &&
607 "multigrid_sync_arg needs implicitarg_ptr");
608 removeAssumedBits(MULTIGRID_SYNC_ARG);
609 }
610
611 if (Retrieved & HOSTCALL_PTR) {
612 assert(!isAssumed(IMPLICIT_ARG_PTR) && "hostcall needs implicitarg_ptr");
613 removeAssumedBits(HOSTCALL_PTR);
614 }
615
616 if (Retrieved & HEAP_PTR) {
617 assert(!isAssumed(IMPLICIT_ARG_PTR) && "heap_ptr needs implicitarg_ptr");
618 removeAssumedBits(HEAP_PTR);
619 }
620
621 if (isAssumed(QUEUE_PTR) && (Retrieved & QUEUE_PTR)) {
622 assert(!isAssumed(IMPLICIT_ARG_PTR) && "queue_ptr needs implicitarg_ptr");
623 removeAssumedBits(QUEUE_PTR);
624 }
625
626 if (isAssumed(LDS_KERNEL_ID) && (Retrieved & LDS_KERNEL_ID)) {
627 removeAssumedBits(LDS_KERNEL_ID);
628 }
629
630 if (isAssumed(DEFAULT_QUEUE) && (Retrieved & DEFAULT_QUEUE))
631 removeAssumedBits(DEFAULT_QUEUE);
632
633 if (isAssumed(COMPLETION_ACTION) && (Retrieved & COMPLETION_ACTION))
634 removeAssumedBits(COMPLETION_ACTION);
635
636 if (isAssumed(FLAT_SCRATCH_INIT) && needFlatScratchInit(A))
637 removeAssumedBits(FLAT_SCRATCH_INIT);
638
639 return getAssumed() != OrigAssumed ? ChangeStatus::CHANGED
640 : ChangeStatus::UNCHANGED;
641 }
642
643 ChangeStatus manifest(Attributor &A) override {
645 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
646 for (auto [Mask, Attr] : InfoCache.getImplicitAttrList()) {
647 if (isKnown(Mask))
648 AttrList.push_back(Attr);
649 }
650
651 return A.manifestAttrs(getIRPosition(), AttrList,
652 /* ForceReplace */ true);
653 }
654
655 const std::string getAsStr(Attributor *) const override {
656 std::string Str;
657 raw_string_ostream OS(Str);
658 OS << "AMDInfo[";
659 for (auto Attr : ImplicitAttrs)
660 if (isAssumed(Attr.first))
661 OS << ' ' << Attr.second;
662 OS << " ]";
663 return OS.str();
664 }
665
666 void trackStatistics() const override {}
667
668private:
669 bool checkForQueuePtr(Attributor &A) {
670 Function *F = getAssociatedFunction();
671 bool IsNonEntryFunc = !AMDGPU::isEntryFunctionCC(F->getCallingConv());
672
673 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
674
675 bool NeedsQueuePtr = false;
676
677 auto CheckAddrSpaceCasts = [&](Instruction &I) {
678 unsigned SrcAS = static_cast<AddrSpaceCastInst &>(I).getSrcAddressSpace();
679 if (castRequiresQueuePtr(SrcAS)) {
680 NeedsQueuePtr = true;
681 return false;
682 }
683 return true;
684 };
685
686 bool HasApertureRegs =
687 InfoCache.getFeatures().test(AMDGPU::FEAT_APERTURE_REGS);
688
689 // `checkForAllInstructions` is much more cheaper than going through all
690 // instructions, try it first.
691
692 // The queue pointer is not needed if aperture regs is present.
693 if (!HasApertureRegs) {
694 bool UsedAssumedInformation = false;
695 A.checkForAllInstructions(CheckAddrSpaceCasts, *this,
696 {Instruction::AddrSpaceCast},
697 UsedAssumedInformation);
698 }
699
700 // If we found that we need the queue pointer, nothing else to do.
701 if (NeedsQueuePtr)
702 return true;
703
704 if (!IsNonEntryFunc && HasApertureRegs)
705 return false;
706
707 for (BasicBlock &BB : *F) {
708 for (Instruction &I : BB) {
709 for (const Use &U : I.operands()) {
710 if (const auto *C = dyn_cast<Constant>(U)) {
711 if (InfoCache.needsQueuePtr(C, *F))
712 return true;
713 }
714 }
715 }
716 }
717
718 return false;
719 }
720
721 /// Returns the implicit kernel arguments that may be read through the
722 /// pointer returned by the implicitarg_ptr call \p Call.
723 uint32_t getImplicitArgsReadThrough(Attributor &A, const CallBase &Call) {
724 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
725 uint32_t ArgsMask = InfoCache.getImplicitArgsMask();
726 const auto *PointerInfoAA = A.getAAFor<AAPointerInfo>(
727 *this, IRPosition::callsite_returned(Call), DepClassTy::REQUIRED);
728 if (!PointerInfoAA || !PointerInfoAA->getState().isValidState())
729 return ArgsMask;
730
731 // An implicit argument is not read if every access that may read any byte
732 // of it is droppable. Check the accesses once for all the implicit
733 // arguments, and stop once all of them may be read.
734 uint32_t Read = 0;
735 auto CheckAccess = [&](const AAPointerInfo::Access &Acc, bool) {
736 if (Acc.getRemoteInst()->isDroppable())
737 return true;
738 for (const AA::RangeTy &AccRange : Acc.getRanges()) {
739 for (auto [Mask, Range] : InfoCache.getImplicitArgRanges()) {
740 if (AccRange.mayOverlap(Range))
741 Read |= Mask;
742 }
743 }
744
745 return Read != ArgsMask;
746 };
747
748 if (!PointerInfoAA->forallInterferingAccesses(
749 InfoCache.getImplicitArgsRange(), CheckAccess))
750 return ArgsMask;
751 return Read;
752 }
753
754 /// Returns the implicit kernel arguments that may be retrieved by the
755 /// function.
756 uint32_t getRetrievedImplicitArgs(Attributor &A) {
757 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
758 uint32_t All = InfoCache.getImplicitArgsMask() | LDS_KERNEL_ID;
759 uint32_t Retrieved = 0;
760 auto CheckCall = [&](Instruction &I) {
761 auto &Call = cast<CallBase>(I);
762 switch (Call.getIntrinsicID()) {
763 case Intrinsic::amdgcn_implicitarg_ptr:
764 Retrieved |= getImplicitArgsReadThrough(A, Call);
765 break;
766 case Intrinsic::amdgcn_lds_kernel_id:
767 Retrieved |= LDS_KERNEL_ID;
768 break;
769 default:
770 // Other calls do not retrieve anything.
771 return true;
772 }
773
774 // Stop once everything may be retrieved.
775 return Retrieved != All;
776 };
777
778 bool UsedAssumedInformation = false;
779 if (!A.checkForAllCallLikeInstructions(CheckCall, *this,
780 UsedAssumedInformation))
781 return All;
782 return Retrieved;
783 }
784
785 // Returns true if FlatScratchInit is needed, i.e., no-flat-scratch-init is
786 // not to be set.
787 bool needFlatScratchInit(Attributor &A) {
788 assert(isAssumed(FLAT_SCRATCH_INIT)); // only called if the bit is still set
789
790 // Check all AddrSpaceCast instructions. FlatScratchInit is needed if
791 // there is a cast from PRIVATE_ADDRESS.
792 auto AddrSpaceCastNotFromPrivate = [](Instruction &I) {
793 return cast<AddrSpaceCastInst>(I).getSrcAddressSpace() !=
795 };
796
797 bool UsedAssumedInformation = false;
798 if (!A.checkForAllInstructions(AddrSpaceCastNotFromPrivate, *this,
799 {Instruction::AddrSpaceCast},
800 UsedAssumedInformation))
801 return true;
802
803 // Check for addrSpaceCast from PRIVATE_ADDRESS in constant expressions
804 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
805
806 Function *F = getAssociatedFunction();
807 for (Instruction &I : instructions(F)) {
808 for (const Use &U : I.operands()) {
809 if (const auto *C = dyn_cast<Constant>(U)) {
810 if (InfoCache.checkConstForAddrSpaceCastFromPrivate(C))
811 return true;
812 }
813 }
814 }
815
816 return false;
817 }
818};
819
820AAAMDAttributes &AAAMDAttributes::createForPosition(const IRPosition &IRP,
821 Attributor &A) {
823 return *new (A.Allocator) AAAMDAttributesFunction(IRP, A);
824 llvm_unreachable("AAAMDAttributes is only valid for function position");
825}
826
827/// Base class to derive different size ranges.
828struct AAAMDSizeRangeAttribute
829 : public StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t> {
830 using Base = StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t>;
831
832 StringRef AttrName;
833
834 AAAMDSizeRangeAttribute(const IRPosition &IRP, Attributor &A,
835 StringRef AttrName)
836 : Base(IRP, 32), AttrName(AttrName) {}
837
838 void trackStatistics() const override {}
839
840 template <class AttributeImpl> ChangeStatus updateImplImpl(Attributor &A) {
841 ChangeStatus Change = ChangeStatus::UNCHANGED;
842
843 auto CheckCallSite = [&](AbstractCallSite CS) {
844 Function *Caller = CS.getInstruction()->getFunction();
845 LLVM_DEBUG(dbgs() << '[' << getName() << "] Call " << Caller->getName()
846 << "->" << getAssociatedFunction()->getName() << '\n');
847
848 const auto *CallerInfo = A.getAAFor<AttributeImpl>(
849 *this, IRPosition::function(*Caller), DepClassTy::REQUIRED);
850 if (!CallerInfo || !CallerInfo->isValidState())
851 return false;
852
853 Change |=
854 clampStateAndIndicateChange(this->getState(), CallerInfo->getState());
855
856 return true;
857 };
858
859 bool AllCallSitesKnown = true;
860 if (!A.checkForAllCallSites(CheckCallSite, *this,
861 /*RequireAllCallSites=*/true,
862 AllCallSitesKnown))
863 return indicatePessimisticFixpoint();
864
865 return Change;
866 }
867
868 /// Clamp the assumed range to the default value ([Min, Max]) and emit the
869 /// attribute if it is not same as default.
871 emitAttributeIfNotDefaultAfterClamp(Attributor &A,
872 std::pair<unsigned, unsigned> Default) {
873 auto [Min, Max] = Default;
874 unsigned Lower = getAssumed().getLower().getZExtValue();
875 unsigned Upper = getAssumed().getUpper().getZExtValue();
876
877 // Clamp the range to the default value.
878 if (Lower < Min)
879 Lower = Min;
880 if (Upper > Max + 1)
881 Upper = Max + 1;
882
883 // No manifest if the value is invalid or same as default after clamp.
884 if ((Lower == Min && Upper == Max + 1) || (Upper < Lower))
885 return ChangeStatus::UNCHANGED;
886
887 Function *F = getAssociatedFunction();
888 LLVMContext &Ctx = F->getContext();
889 SmallString<10> Buffer;
890 raw_svector_ostream OS(Buffer);
891 OS << Lower << ',' << Upper - 1;
892 return A.manifestAttrs(getIRPosition(),
893 {Attribute::get(Ctx, AttrName, OS.str())},
894 /*ForceReplace=*/true);
895 }
896
897 const std::string getAsStr(Attributor *) const override {
898 std::string Str;
899 raw_string_ostream OS(Str);
900 OS << getName() << '[';
901 OS << getAssumed().getLower() << ',' << getAssumed().getUpper() - 1;
902 OS << ']';
903 return OS.str();
904 }
905};
906
907/// Propagate amdgpu-flat-work-group-size attribute.
908struct AAAMDFlatWorkGroupSize : public AAAMDSizeRangeAttribute {
909 AAAMDFlatWorkGroupSize(const IRPosition &IRP, Attributor &A)
910 : AAAMDSizeRangeAttribute(IRP, A, "amdgpu-flat-work-group-size") {}
911
912 void initialize(Attributor &A) override {
913 Function *F = getAssociatedFunction();
914 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
915
916 bool HasAttr = false;
917 auto Range = InfoCache.getDefaultFlatWorkGroupSize(*F);
918 auto MaxRange = InfoCache.getMaximumFlatWorkGroupRange();
919
920 if (auto Attr = InfoCache.getFlatWorkGroupSizeAttr(*F)) {
921 // We only consider an attribute that is not max range because the front
922 // end always emits the attribute, unfortunately, and sometimes it emits
923 // the max range.
924 if (*Attr != MaxRange) {
925 Range = *Attr;
926 HasAttr = true;
927 }
928 }
929
930 // We don't want to directly clamp the state if it's the max range because
931 // that is basically the worst state.
932 if (Range == MaxRange)
933 return;
934
935 auto [Min, Max] = Range;
936 ConstantRange CR(APInt(32, Min), APInt(32, Max + 1));
937 IntegerRangeState IRS(CR);
938 clampStateAndIndicateChange(this->getState(), IRS);
939
940 if (HasAttr || AMDGPU::isEntryFunctionCC(F->getCallingConv()))
941 indicateOptimisticFixpoint();
942 }
943
944 ChangeStatus updateImpl(Attributor &A) override {
945 return updateImplImpl<AAAMDFlatWorkGroupSize>(A);
946 }
947
948 /// Create an abstract attribute view for the position \p IRP.
949 static AAAMDFlatWorkGroupSize &createForPosition(const IRPosition &IRP,
950 Attributor &A);
951
952 ChangeStatus manifest(Attributor &A) override {
953 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
954 return emitAttributeIfNotDefaultAfterClamp(
955 A, InfoCache.getMaximumFlatWorkGroupRange());
956 }
957
958 StringRef getName() const override { return "AAAMDFlatWorkGroupSize"; }
959
960 const char *getIdAddr() const override { return &ID; }
961
962 /// This function should return true if the type of the \p AA is
963 /// AAAMDFlatWorkGroupSize
964 static bool classof(const AbstractAttribute *AA) {
965 return (AA->getIdAddr() == &ID);
966 }
967
968 /// Unique ID (due to the unique address)
969 static const char ID;
970};
971
972const char AAAMDFlatWorkGroupSize::ID = 0;
973
974AAAMDFlatWorkGroupSize &
975AAAMDFlatWorkGroupSize::createForPosition(const IRPosition &IRP,
976 Attributor &A) {
978 return *new (A.Allocator) AAAMDFlatWorkGroupSize(IRP, A);
980 "AAAMDFlatWorkGroupSize is only valid for function position");
981}
982
983struct TupleDecIntegerRangeState : public AbstractState {
984 DecIntegerState<uint32_t> X, Y, Z;
985
986 bool isValidState() const override {
987 return X.isValidState() && Y.isValidState() && Z.isValidState();
988 }
989
990 bool isAtFixpoint() const override {
991 return X.isAtFixpoint() && Y.isAtFixpoint() && Z.isAtFixpoint();
992 }
993
994 ChangeStatus indicateOptimisticFixpoint() override {
995 return X.indicateOptimisticFixpoint() | Y.indicateOptimisticFixpoint() |
996 Z.indicateOptimisticFixpoint();
997 }
998
999 ChangeStatus indicatePessimisticFixpoint() override {
1000 return X.indicatePessimisticFixpoint() | Y.indicatePessimisticFixpoint() |
1001 Z.indicatePessimisticFixpoint();
1002 }
1003
1004 TupleDecIntegerRangeState operator^=(const TupleDecIntegerRangeState &Other) {
1005 X ^= Other.X;
1006 Y ^= Other.Y;
1007 Z ^= Other.Z;
1008 return *this;
1009 }
1010
1011 bool operator==(const TupleDecIntegerRangeState &Other) const {
1012 return X == Other.X && Y == Other.Y && Z == Other.Z;
1013 }
1014
1015 TupleDecIntegerRangeState &getAssumed() { return *this; }
1016 const TupleDecIntegerRangeState &getAssumed() const { return *this; }
1017};
1018
1019using AAAMDMaxNumWorkgroupsState =
1020 StateWrapper<TupleDecIntegerRangeState, AbstractAttribute, uint32_t>;
1021
1022/// Propagate amdgpu-max-num-workgroups attribute.
1023struct AAAMDMaxNumWorkgroups
1024 : public StateWrapper<TupleDecIntegerRangeState, AbstractAttribute> {
1025 using Base = StateWrapper<TupleDecIntegerRangeState, AbstractAttribute>;
1026
1027 AAAMDMaxNumWorkgroups(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
1028
1029 void initialize(Attributor &A) override {
1030 Function *F = getAssociatedFunction();
1031
1032 SmallVector<unsigned> MaxNumWorkgroups = AMDGPU::getMaxNumWorkGroups(*F);
1033
1034 X.takeKnownMinimum(MaxNumWorkgroups[0]);
1035 Y.takeKnownMinimum(MaxNumWorkgroups[1]);
1036 Z.takeKnownMinimum(MaxNumWorkgroups[2]);
1037
1038 if (AMDGPU::isEntryFunctionCC(F->getCallingConv()))
1039 indicatePessimisticFixpoint();
1040 }
1041
1042 ChangeStatus updateImpl(Attributor &A) override {
1043 ChangeStatus Change = ChangeStatus::UNCHANGED;
1044
1045 auto CheckCallSite = [&](AbstractCallSite CS) {
1046 Function *Caller = CS.getInstruction()->getFunction();
1047 LLVM_DEBUG(dbgs() << "[AAAMDMaxNumWorkgroups] Call " << Caller->getName()
1048 << "->" << getAssociatedFunction()->getName() << '\n');
1049
1050 const auto *CallerInfo = A.getAAFor<AAAMDMaxNumWorkgroups>(
1051 *this, IRPosition::function(*Caller), DepClassTy::REQUIRED);
1052 if (!CallerInfo || !CallerInfo->isValidState())
1053 return false;
1054
1055 Change |=
1056 clampStateAndIndicateChange(this->getState(), CallerInfo->getState());
1057 return true;
1058 };
1059
1060 bool AllCallSitesKnown = true;
1061 if (!A.checkForAllCallSites(CheckCallSite, *this,
1062 /*RequireAllCallSites=*/true,
1063 AllCallSitesKnown))
1064 return indicatePessimisticFixpoint();
1065
1066 return Change;
1067 }
1068
1069 /// Create an abstract attribute view for the position \p IRP.
1070 static AAAMDMaxNumWorkgroups &createForPosition(const IRPosition &IRP,
1071 Attributor &A);
1072
1073 ChangeStatus manifest(Attributor &A) override {
1074 Function *F = getAssociatedFunction();
1075 LLVMContext &Ctx = F->getContext();
1076 SmallString<32> Buffer;
1077 raw_svector_ostream OS(Buffer);
1078 OS << X.getAssumed() << ',' << Y.getAssumed() << ',' << Z.getAssumed();
1079
1080 // TODO: Should annotate loads of the group size for this to do anything
1081 // useful.
1082 return A.manifestAttrs(
1083 getIRPosition(),
1084 {Attribute::get(Ctx, "amdgpu-max-num-workgroups", OS.str())},
1085 /* ForceReplace= */ true);
1086 }
1087
1088 StringRef getName() const override { return "AAAMDMaxNumWorkgroups"; }
1089
1090 const std::string getAsStr(Attributor *) const override {
1091 std::string Buffer = "AAAMDMaxNumWorkgroupsState[";
1092 raw_string_ostream OS(Buffer);
1093 OS << X.getAssumed() << ',' << Y.getAssumed() << ',' << Z.getAssumed()
1094 << ']';
1095 return OS.str();
1096 }
1097
1098 const char *getIdAddr() const override { return &ID; }
1099
1100 /// This function should return true if the type of the \p AA is
1101 /// AAAMDMaxNumWorkgroups
1102 static bool classof(const AbstractAttribute *AA) {
1103 return (AA->getIdAddr() == &ID);
1104 }
1105
1106 void trackStatistics() const override {}
1107
1108 /// Unique ID (due to the unique address)
1109 static const char ID;
1110};
1111
1112const char AAAMDMaxNumWorkgroups::ID = 0;
1113
1114AAAMDMaxNumWorkgroups &
1115AAAMDMaxNumWorkgroups::createForPosition(const IRPosition &IRP, Attributor &A) {
1117 return *new (A.Allocator) AAAMDMaxNumWorkgroups(IRP, A);
1118 llvm_unreachable("AAAMDMaxNumWorkgroups is only valid for function position");
1119}
1120
1121/// Propagate amdgpu-waves-per-eu attribute.
1122struct AAAMDWavesPerEU : public AAAMDSizeRangeAttribute {
1123 AAAMDWavesPerEU(const IRPosition &IRP, Attributor &A)
1124 : AAAMDSizeRangeAttribute(IRP, A, "amdgpu-waves-per-eu") {}
1125
1126 void initialize(Attributor &A) override {
1127 Function *F = getAssociatedFunction();
1128 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
1129
1130 // If the attribute exists, we will honor it if it is not the default.
1131 if (auto Attr = InfoCache.getWavesPerEUAttr(*F)) {
1132 std::pair<unsigned, unsigned> MaxWavesPerEURange{
1133 1U, InfoCache.getMaxWavesPerEU()};
1134 if (*Attr != MaxWavesPerEURange) {
1135 auto [Min, Max] = *Attr;
1136 ConstantRange Range(APInt(32, Min), APInt(32, Max + 1));
1137 IntegerRangeState RangeState(Range);
1138 this->getState() = RangeState;
1139 indicateOptimisticFixpoint();
1140 return;
1141 }
1142 }
1143
1144 if (AMDGPU::isEntryFunctionCC(F->getCallingConv()))
1145 indicatePessimisticFixpoint();
1146 }
1147
1148 ChangeStatus updateImpl(Attributor &A) override {
1149 ChangeStatus Change = ChangeStatus::UNCHANGED;
1150
1151 auto CheckCallSite = [&](AbstractCallSite CS) {
1152 Function *Caller = CS.getInstruction()->getFunction();
1153 Function *Func = getAssociatedFunction();
1154 LLVM_DEBUG(dbgs() << '[' << getName() << "] Call " << Caller->getName()
1155 << "->" << Func->getName() << '\n');
1156 (void)Func;
1157
1158 const auto *CallerAA = A.getAAFor<AAAMDWavesPerEU>(
1159 *this, IRPosition::function(*Caller), DepClassTy::REQUIRED);
1160 if (!CallerAA || !CallerAA->isValidState())
1161 return false;
1162
1163 ConstantRange Assumed = getAssumed();
1164 unsigned Min = std::max(Assumed.getLower().getZExtValue(),
1165 CallerAA->getAssumed().getLower().getZExtValue());
1166 unsigned Max = std::max(Assumed.getUpper().getZExtValue(),
1167 CallerAA->getAssumed().getUpper().getZExtValue());
1168 ConstantRange Range(APInt(32, Min), APInt(32, Max));
1169 IntegerRangeState RangeState(Range);
1170 getState() = RangeState;
1171 Change |= getState() == Assumed ? ChangeStatus::UNCHANGED
1172 : ChangeStatus::CHANGED;
1173
1174 return true;
1175 };
1176
1177 bool AllCallSitesKnown = true;
1178 if (!A.checkForAllCallSites(CheckCallSite, *this, true, AllCallSitesKnown))
1179 return indicatePessimisticFixpoint();
1180
1181 return Change;
1182 }
1183
1184 /// Create an abstract attribute view for the position \p IRP.
1185 static AAAMDWavesPerEU &createForPosition(const IRPosition &IRP,
1186 Attributor &A);
1187
1188 ChangeStatus manifest(Attributor &A) override {
1189 auto &InfoCache = static_cast<AMDGPUInformationCache &>(A.getInfoCache());
1190 return emitAttributeIfNotDefaultAfterClamp(
1191 A, {1U, InfoCache.getMaxWavesPerEU()});
1192 }
1193
1194 StringRef getName() const override { return "AAAMDWavesPerEU"; }
1195
1196 const char *getIdAddr() const override { return &ID; }
1197
1198 /// This function should return true if the type of the \p AA is
1199 /// AAAMDWavesPerEU
1200 static bool classof(const AbstractAttribute *AA) {
1201 return (AA->getIdAddr() == &ID);
1202 }
1203
1204 /// Unique ID (due to the unique address)
1205 static const char ID;
1206};
1207
1208const char AAAMDWavesPerEU::ID = 0;
1209
1210AAAMDWavesPerEU &AAAMDWavesPerEU::createForPosition(const IRPosition &IRP,
1211 Attributor &A) {
1213 return *new (A.Allocator) AAAMDWavesPerEU(IRP, A);
1214 llvm_unreachable("AAAMDWavesPerEU is only valid for function position");
1215}
1216
1217/// Compute the minimum number of AGPRs required to allocate the inline asm.
1218static unsigned inlineAsmGetNumRequiredAGPRs(const InlineAsm *IA,
1219 const CallBase &Call) {
1220 unsigned ArgNo = 0;
1221 unsigned ResNo = 0;
1222 unsigned AGPRDefCount = 0;
1223 unsigned AGPRUseCount = 0;
1224 unsigned MaxPhysReg = 0;
1225 const DataLayout &DL = Call.getFunction()->getDataLayout();
1226
1227 // TODO: Overestimates due to not accounting for tied operands
1228 for (const InlineAsm::ConstraintInfo &CI : IA->ParseConstraints()) {
1229 Type *Ty = nullptr;
1230 switch (CI.Type) {
1231 case InlineAsm::isOutput: {
1232 Ty = Call.getType();
1233 if (auto *STy = dyn_cast<StructType>(Ty))
1234 Ty = STy->getElementType(ResNo);
1235 ++ResNo;
1236 break;
1237 }
1238 case InlineAsm::isInput: {
1239 Ty = Call.getArgOperand(ArgNo++)->getType();
1240 break;
1241 }
1242 case InlineAsm::isLabel:
1243 continue;
1245 // Parse the physical register reference.
1246 break;
1247 }
1248
1249 for (StringRef Code : CI.Codes) {
1250 unsigned RegCount = 0;
1251 if (Code.starts_with("a")) {
1252 // Virtual register, compute number of registers based on the type.
1253 //
1254 // We ought to be going through TargetLowering to get the number of
1255 // registers, but we should avoid the dependence on CodeGen here.
1256 RegCount = divideCeil(DL.getTypeSizeInBits(Ty), 32);
1257 } else {
1258 // Physical register reference
1259 auto [Kind, RegIdx, NumRegs] = AMDGPU::parseAsmConstraintPhysReg(Code);
1260 if (Kind == 'a') {
1261 RegCount = NumRegs;
1262 MaxPhysReg = std::max(MaxPhysReg, std::min(RegIdx + NumRegs, 256u));
1263 }
1264
1265 continue;
1266 }
1267
1268 if (CI.Type == InlineAsm::isOutput) {
1269 // Apply tuple alignment requirement
1270 //
1271 // TODO: This is more conservative than necessary.
1272 AGPRDefCount = alignTo(AGPRDefCount, RegCount);
1273
1274 AGPRDefCount += RegCount;
1275 if (CI.isEarlyClobber) {
1276 AGPRUseCount = alignTo(AGPRUseCount, RegCount);
1277 AGPRUseCount += RegCount;
1278 }
1279 } else {
1280 AGPRUseCount = alignTo(AGPRUseCount, RegCount);
1281 AGPRUseCount += RegCount;
1282 }
1283 }
1284 }
1285
1286 unsigned MaxVirtReg = std::max(AGPRUseCount, AGPRDefCount);
1287
1288 // TODO: This is overly conservative. If there are any physical registers,
1289 // allocate any virtual registers after them so we don't have to solve optimal
1290 // packing.
1291 return std::min(MaxVirtReg + MaxPhysReg, 256u);
1292}
1293
1294/// Call \p Pred on each function that \p CB may call. Return false if a callee
1295/// is unknown, or if \p Pred returns false for a callee.
1296static bool
1297checkForAllPossibleCallees(Attributor &A, const AbstractAttribute &QueryingAA,
1298 const CallBase &CB,
1299 function_ref<bool(const Function &)> Pred) {
1300 // A direct call without callbacks only calls its callee, so it does not need
1301 // a call site AACallEdges.
1303 if (Callee && !Callee->hasMetadata(LLVMContext::MD_callback))
1304 return Pred(*Callee);
1305
1306 const AACallEdges *CBEdges = A.getAAFor<AACallEdges>(
1307 QueryingAA, IRPosition::callsite_function(CB), DepClassTy::REQUIRED);
1308 if (!CBEdges || CBEdges->hasUnknownCallee())
1309 return false;
1310 return all_of(CBEdges->getOptimisticEdges(),
1311 [&](const Function *Fn) { return Pred(*Fn); });
1312}
1313
1314struct AAAMDGPUMinAGPRAlloc
1315 : public StateWrapper<DecIntegerState<>, AbstractAttribute> {
1316 using Base = StateWrapper<DecIntegerState<>, AbstractAttribute>;
1317 AAAMDGPUMinAGPRAlloc(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
1318
1319 static AAAMDGPUMinAGPRAlloc &createForPosition(const IRPosition &IRP,
1320 Attributor &A) {
1322 return *new (A.Allocator) AAAMDGPUMinAGPRAlloc(IRP, A);
1324 "AAAMDGPUMinAGPRAlloc is only valid for function position");
1325 }
1326
1327 void initialize(Attributor &A) override {
1328 Function *F = getAssociatedFunction();
1329 auto [MinNumAGPR, MaxNumAGPR] =
1330 AMDGPU::getIntegerPairAttribute(*F, "amdgpu-agpr-alloc", {~0u, ~0u},
1331 /*OnlyFirstRequired=*/true);
1332 if (MinNumAGPR == 0) {
1333 indicateOptimisticFixpoint();
1334 return;
1335 }
1336
1338 indicatePessimisticFixpoint();
1339 }
1340
1341 const std::string getAsStr(Attributor *A) const override {
1342 std::string Str = "amdgpu-agpr-alloc=";
1343 raw_string_ostream OS(Str);
1344 OS << getAssumed();
1345 return OS.str();
1346 }
1347
1348 void trackStatistics() const override {}
1349
1350 ChangeStatus updateImpl(Attributor &A) override {
1351 DecIntegerState<> Maximum;
1352
1353 // Check for cases which require allocation of AGPRs. The only cases where
1354 // AGPRs are required are if there are direct references to AGPRs, so inline
1355 // assembly and special intrinsics.
1356 auto CheckForMinAGPRAllocs = [&](Instruction &I) {
1357 const auto &CB = cast<CallBase>(I);
1358 const Value *CalleeOp = CB.getCalledOperand();
1359
1360 if (const InlineAsm *IA = dyn_cast<InlineAsm>(CalleeOp)) {
1361 // Technically, the inline asm could be invoking a call to an unknown
1362 // external function that requires AGPRs, but ignore that.
1363 unsigned NumRegs = inlineAsmGetNumRequiredAGPRs(IA, CB);
1364 Maximum.takeAssumedMaximum(NumRegs);
1365 return true;
1366 }
1367 switch (CB.getIntrinsicID()) {
1369 break;
1370 case Intrinsic::write_register:
1371 case Intrinsic::read_register:
1372 case Intrinsic::read_volatile_register: {
1373 const MDString *RegName = cast<MDString>(
1375 cast<MetadataAsValue>(CB.getArgOperand(0))->getMetadata())
1376 ->getOperand(0));
1377 auto [Kind, RegIdx, NumRegs] =
1379 if (Kind == 'a')
1380 Maximum.takeAssumedMaximum(std::min(RegIdx + NumRegs, 256u));
1381
1382 return true;
1383 }
1384 // Trap-like intrinsics such as llvm.trap and llvm.debugtrap do not have
1385 // the nocallback attribute, so the AMDGPU attributor can conservatively
1386 // drop all implicitly-known inputs and AGPR allocation information. Make
1387 // sure we still infer that no implicit inputs are required and that the
1388 // AGPR allocation stays at zero. Trap-like intrinsics may invoke a
1389 // function which requires AGPRs, so we need to check if the called
1390 // function has the "trap-func-name" attribute.
1391 case Intrinsic::trap:
1392 case Intrinsic::debugtrap:
1393 case Intrinsic::ubsantrap:
1394 return CB.hasFnAttr(Attribute::NoCallback) ||
1395 !CB.hasFnAttr("trap-func-name");
1396 default:
1397 // Some intrinsics may use AGPRs, but if we have a choice, we are not
1398 // required to use AGPRs.
1399 // Assume !nocallback intrinsics may call a function which requires
1400 // AGPRs.
1401 return CB.hasFnAttr(Attribute::NoCallback);
1402 }
1403
1404 // TODO: Handle callsite attributes
1405 auto CheckCallee = [&](const Function &Callee) {
1406 const AAAMDGPUMinAGPRAlloc *CalleeInfo =
1407 A.getAAFor<AAAMDGPUMinAGPRAlloc>(
1408 *this, IRPosition::function(Callee), DepClassTy::REQUIRED);
1409 if (!CalleeInfo || !CalleeInfo->isValidState())
1410 return false;
1411 Maximum.takeAssumedMaximum(CalleeInfo->getAssumed());
1412 return true;
1413 };
1414 if (!checkForAllPossibleCallees(A, *this, CB, CheckCallee)) {
1416 return false;
1417 }
1418
1419 return true;
1420 };
1421
1422 bool UsedAssumedInformation = false;
1423 if (!A.checkForAllCallLikeInstructions(CheckForMinAGPRAllocs, *this,
1424 UsedAssumedInformation))
1425 return indicatePessimisticFixpoint();
1426
1427 return clampStateAndIndicateChange(getState(), Maximum);
1428 }
1429
1430 ChangeStatus manifest(Attributor &A) override {
1431 LLVMContext &Ctx = getAssociatedFunction()->getContext();
1432 SmallString<4> Buffer;
1433 raw_svector_ostream OS(Buffer);
1434 OS << getAssumed();
1435
1436 return A.manifestAttrs(
1437 getIRPosition(), {Attribute::get(Ctx, "amdgpu-agpr-alloc", OS.str())});
1438 }
1439
1440 StringRef getName() const override { return "AAAMDGPUMinAGPRAlloc"; }
1441 const char *getIdAddr() const override { return &ID; }
1442
1443 /// This function should return true if the type of the \p AA is
1444 /// AAAMDGPUMinAGPRAllocs
1445 static bool classof(const AbstractAttribute *AA) {
1446 return (AA->getIdAddr() == &ID);
1447 }
1448
1449 static const char ID;
1450};
1451
1452const char AAAMDGPUMinAGPRAlloc::ID = 0;
1453
1454/// Deduce the function attribute "amdgpu-no-lds-dma"
1455struct AAAMDGPUNoLDSDMA : public StateWrapper<BooleanState, AbstractAttribute> {
1456 using Base = StateWrapper<BooleanState, AbstractAttribute>;
1457 AAAMDGPUNoLDSDMA(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
1458
1459 /// Create an abstract attribute view for the position \p IRP.
1460 static AAAMDGPUNoLDSDMA &createForPosition(const IRPosition &IRP,
1461 Attributor &A) {
1463 "AAAMDGPUNoLDSDMA is only valid for function position");
1464 return *new (A.Allocator) AAAMDGPUNoLDSDMA(IRP, A);
1465 }
1466
1467 void initialize(Attributor &A) override {
1468 const Function *F = getAssociatedFunction();
1469 if (F->hasFnAttribute("amdgpu-no-lds-dma")) {
1470 indicateOptimisticFixpoint();
1471 return;
1472 }
1473
1474 if (F->isDeclaration())
1475 indicatePessimisticFixpoint();
1476 }
1477
1478 ChangeStatus updateImpl(Attributor &A) override {
1479 auto CheckNoLDSDMA = [&](Instruction &I) {
1480 const auto &CB = cast<CallBase>(I);
1481
1482 // Inline assembly may hold any instruction, including an LDSDMA
1483 // operation.
1485 return false;
1486
1487 Intrinsic::ID IID = CB.getIntrinsicID();
1488 if (IID != Intrinsic::not_intrinsic) {
1489 // Assume !nocallback intrinsics may call a function which issues an
1490 // LDSDMA operation.
1491 return !AMDGPU::isLDSDMAIntrinsic(IID) &&
1492 CB.hasFnAttr(Attribute::NoCallback);
1493 }
1494
1495 return checkForAllPossibleCallees(
1496 A, *this, CB, [&](const Function &Callee) {
1497 const AAAMDGPUNoLDSDMA *CalleeInfo = A.getAAFor<AAAMDGPUNoLDSDMA>(
1498 *this, IRPosition::function(Callee), DepClassTy::REQUIRED);
1499 return CalleeInfo && CalleeInfo->getAssumed();
1500 });
1501 };
1502
1503 bool UsedAssumedInformation = false;
1504 if (!A.checkForAllCallLikeInstructions(CheckNoLDSDMA, *this,
1505 UsedAssumedInformation))
1506 return indicatePessimisticFixpoint();
1507
1508 return ChangeStatus::UNCHANGED;
1509 }
1510
1511 ChangeStatus manifest(Attributor &A) override {
1512 if (!getAssumed())
1513 return ChangeStatus::UNCHANGED;
1514
1515 LLVMContext &Ctx = getAssociatedFunction()->getContext();
1516 return A.manifestAttrs(getIRPosition(),
1517 {Attribute::get(Ctx, "amdgpu-no-lds-dma")});
1518 }
1519
1520 bool isValidState() const override { return true; }
1521
1522 const std::string getAsStr(Attributor *A) const override {
1523 return "AMDGPUNoLDSDMA[" + std::to_string(getAssumed()) + "]";
1524 }
1525
1526 void trackStatistics() const override {}
1527
1528 StringRef getName() const override { return "AAAMDGPUNoLDSDMA"; }
1529 const char *getIdAddr() const override { return &ID; }
1530
1531 /// This function should return true if the type of the \p AA is
1532 /// AAAMDGPUNoLDSDMA
1533 static bool classof(const AbstractAttribute *AA) {
1534 return (AA->getIdAddr() == &ID);
1535 }
1536
1537 static const char ID;
1538};
1539
1540const char AAAMDGPUNoLDSDMA::ID = 0;
1541
1542/// An abstract attribute to propagate the function attribute
1543/// "amdgpu-cluster-dims" from kernel entry functions to device functions.
1544struct AAAMDGPUClusterDims
1545 : public StateWrapper<BooleanState, AbstractAttribute> {
1546 using Base = StateWrapper<BooleanState, AbstractAttribute>;
1547 AAAMDGPUClusterDims(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
1548
1549 /// Create an abstract attribute view for the position \p IRP.
1550 static AAAMDGPUClusterDims &createForPosition(const IRPosition &IRP,
1551 Attributor &A);
1552
1553 StringRef getName() const override { return "AAAMDGPUClusterDims"; }
1554
1555 const char *getIdAddr() const override { return &ID; }
1556
1557 /// This function should return true if the type of the \p AA is
1558 /// AAAMDGPUClusterDims.
1559 static bool classof(const AbstractAttribute *AA) {
1560 return AA->getIdAddr() == &ID;
1561 }
1562
1563 virtual const AMDGPU::ClusterDimsAttr &getClusterDims() const = 0;
1564
1565 /// Unique ID (due to the unique address)
1566 static const char ID;
1567};
1568
1569const char AAAMDGPUClusterDims::ID = 0;
1570
1571struct AAAMDGPUClusterDimsFunction : public AAAMDGPUClusterDims {
1572 AAAMDGPUClusterDimsFunction(const IRPosition &IRP, Attributor &A)
1573 : AAAMDGPUClusterDims(IRP, A) {}
1574
1575 void initialize(Attributor &A) override {
1576 Function *F = getAssociatedFunction();
1577 assert(F && "empty associated function");
1578
1580
1581 // No matter what a kernel function has, it is final.
1582 if (AMDGPU::isEntryFunctionCC(F->getCallingConv())) {
1583 if (Attr.isUnknown())
1584 indicatePessimisticFixpoint();
1585 else
1586 indicateOptimisticFixpoint();
1587 }
1588 }
1589
1590 const std::string getAsStr(Attributor *A) const override {
1591 if (!getAssumed() || Attr.isUnknown())
1592 return "unknown";
1593 if (Attr.isNoCluster())
1594 return "no";
1595 if (Attr.isVariableDims())
1596 return "variable";
1597 return Attr.to_string();
1598 }
1599
1600 void trackStatistics() const override {}
1601
1602 ChangeStatus updateImpl(Attributor &A) override {
1603 auto OldState = Attr;
1604
1605 auto CheckCallSite = [&](AbstractCallSite CS) {
1606 const auto *CallerAA = A.getAAFor<AAAMDGPUClusterDims>(
1607 *this, IRPosition::function(*CS.getInstruction()->getFunction()),
1608 DepClassTy::REQUIRED);
1609 if (!CallerAA || !CallerAA->isValidState())
1610 return false;
1611
1612 return merge(CallerAA->getClusterDims());
1613 };
1614
1615 bool UsedAssumedInformation = false;
1616 if (!A.checkForAllCallSites(CheckCallSite, *this,
1617 /*RequireAllCallSites=*/true,
1618 UsedAssumedInformation))
1619 return indicatePessimisticFixpoint();
1620
1621 return OldState == Attr ? ChangeStatus::UNCHANGED : ChangeStatus::CHANGED;
1622 }
1623
1624 ChangeStatus manifest(Attributor &A) override {
1625 if (Attr.isUnknown())
1626 return ChangeStatus::UNCHANGED;
1627 return A.manifestAttrs(
1628 getIRPosition(),
1629 {Attribute::get(getAssociatedFunction()->getContext(), AttrName,
1630 Attr.to_string())},
1631 /*ForceReplace=*/true);
1632 }
1633
1634 const AMDGPU::ClusterDimsAttr &getClusterDims() const override {
1635 return Attr;
1636 }
1637
1638private:
1639 bool merge(const AMDGPU::ClusterDimsAttr &Other) {
1640 // Case 1: Both of them are unknown yet, we do nothing and continue wait for
1641 // propagation.
1642 if (Attr.isUnknown() && Other.isUnknown())
1643 return true;
1644
1645 // Case 2: The other is determined, but we are unknown yet, we simply take
1646 // the other's value.
1647 if (Attr.isUnknown()) {
1648 Attr = Other;
1649 return true;
1650 }
1651
1652 // Case 3: We are determined but the other is unknown yet, we simply keep
1653 // everything unchanged.
1654 if (Other.isUnknown())
1655 return true;
1656
1657 // After this point, both are determined.
1658
1659 // Case 4: If they are same, we do nothing.
1660 if (Attr == Other)
1661 return true;
1662
1663 // Now they are not same.
1664
1665 // Case 5: If either of us uses cluster (but not both; otherwise case 4
1666 // would hold), then it is unknown whether cluster will be used, and the
1667 // state is final, unlike case 1.
1668 if (Attr.isNoCluster() || Other.isNoCluster()) {
1669 Attr.setUnknown();
1670 return false;
1671 }
1672
1673 // Case 6: Both of us use cluster, but the dims are different, so the result
1674 // is, cluster is used, but we just don't have a fixed dims.
1675 Attr.setVariableDims();
1676 return true;
1677 }
1678
1679 AMDGPU::ClusterDimsAttr Attr;
1680
1681 static constexpr char AttrName[] = "amdgpu-cluster-dims";
1682};
1683
1684AAAMDGPUClusterDims &
1685AAAMDGPUClusterDims::createForPosition(const IRPosition &IRP, Attributor &A) {
1687 return *new (A.Allocator) AAAMDGPUClusterDimsFunction(IRP, A);
1688 llvm_unreachable("AAAMDGPUClusterDims is only valid for function position");
1689}
1690
1691static bool runImpl(SetVector<Function *> &Functions, bool IsModulePass,
1692 bool DeleteFns, Module &M, AnalysisGetter &AG,
1693 TargetMachine &TM, AMDGPUAttributorOptions Options,
1694 ThinOrFullLTOPhase LTOPhase) {
1695
1696 CallGraphUpdater CGUpdater;
1698 AMDGPUInformationCache InfoCache(M, AG, Allocator, nullptr, TM);
1699 static constexpr AAKindSet Allowed = AAKindSet::get<
1700 &AAAMDAttributes::ID, &AAUniformWorkGroupSize::ID, &AAPotentialValues::ID,
1701 &AAAMDFlatWorkGroupSize::ID, &AAAMDMaxNumWorkgroups::ID,
1702 &AAAMDWavesPerEU::ID, &AAAMDGPUMinAGPRAlloc::ID, &AACallEdges::ID,
1705 &AAIndirectCallInfo::ID, &AAAMDGPUClusterDims::ID, &AAAMDGPUNoLDSDMA::ID,
1706 &AAAlign::ID>();
1707
1708 AttributorConfig AC(CGUpdater);
1709 AC.IsClosedWorldModule = Options.IsClosedWorld;
1710 AC.Allowed = Allowed;
1711 AC.IsModulePass = IsModulePass;
1712 AC.DeleteFns = DeleteFns;
1713 AC.DefaultInitializeLiveInternals = false;
1714 // AAIsDead is not allowed, so nothing is ever assumed dead.
1715 AC.UseLiveness = false;
1716 unsigned IndirectCallSpecializationThreshold =
1717 static_cast<const AMDGPUTargetMachine &>(TM)
1718 .getCLOpts()
1719 .indirect_call_specialization_threshold;
1720 AC.IndirectCalleeSpecializationCallback =
1721 [IndirectCallSpecializationThreshold](
1722 Attributor &A, const AbstractAttribute &AA, CallBase &CB,
1723 Function &Callee, unsigned NumAssumedCallees) {
1724 return !AMDGPU::isEntryFunctionCC(Callee.getCallingConv()) &&
1725 (NumAssumedCallees <= IndirectCallSpecializationThreshold);
1726 };
1727 AC.IPOAmendableCB = [](const Function &F) {
1728 return F.getCallingConv() == CallingConv::AMDGPU_KERNEL;
1729 };
1730
1731 Attributor A(Functions, InfoCache, AC);
1732
1733 LLVM_DEBUG({
1734 StringRef LTOPhaseStr = to_string(LTOPhase);
1735 dbgs() << "[AMDGPUAttributor] Running at phase " << LTOPhaseStr << '\n'
1736 << "[AMDGPUAttributor] Module " << M.getName() << " is "
1737 << (AC.IsClosedWorldModule ? "" : "not ")
1738 << "assumed to be a closed world.\n";
1739 });
1740
1741 for (auto *F : Functions) {
1742 A.getOrCreateAAFor<AAAMDAttributes>(IRPosition::function(*F));
1743 A.getOrCreateAAFor<AAUniformWorkGroupSize>(IRPosition::function(*F));
1744 A.getOrCreateAAFor<AAAMDMaxNumWorkgroups>(IRPosition::function(*F));
1745 A.getOrCreateAAFor<AAAMDGPUNoLDSDMA>(IRPosition::function(*F));
1746 CallingConv::ID CC = F->getCallingConv();
1748 A.getOrCreateAAFor<AAAMDFlatWorkGroupSize>(IRPosition::function(*F));
1749 A.getOrCreateAAFor<AAAMDWavesPerEU>(IRPosition::function(*F));
1750 }
1751
1752 const AMDGPU::AMDGPUFeatureBitset &Features = InfoCache.getFeatures();
1753 if (!F->isDeclaration() && Features.test(AMDGPU::FEAT_CLUSTERS))
1754 A.getOrCreateAAFor<AAAMDGPUClusterDims>(IRPosition::function(*F));
1755
1756 if (Features.test(AMDGPU::FEAT_AGPR_ALLOC))
1757 A.getOrCreateAAFor<AAAMDGPUMinAGPRAlloc>(IRPosition::function(*F));
1758
1759 for (auto &I : instructions(F)) {
1760 Value *Ptr = nullptr;
1761 if (auto *LI = dyn_cast<LoadInst>(&I))
1762 Ptr = LI->getPointerOperand();
1763 else if (auto *SI = dyn_cast<StoreInst>(&I))
1764 Ptr = SI->getPointerOperand();
1765 else if (auto *RMW = dyn_cast<AtomicRMWInst>(&I))
1766 Ptr = RMW->getPointerOperand();
1767 else if (auto *CmpX = dyn_cast<AtomicCmpXchgInst>(&I))
1768 Ptr = CmpX->getPointerOperand();
1769
1770 if (Ptr) {
1771 // Only flat pointers can be refined to a specific address space.
1772 if (Ptr->getType()->getPointerAddressSpace() ==
1774 A.getOrCreateAAFor<AAAddressSpace>(IRPosition::value(*Ptr));
1775 A.getOrCreateAAFor<AANoAliasAddrSpace>(IRPosition::value(*Ptr));
1776 }
1777 if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(Ptr)) {
1778 if (II->getIntrinsicID() == Intrinsic::amdgcn_make_buffer_rsrc)
1779 A.getOrCreateAAFor<AAAlign>(IRPosition::value(*Ptr));
1780 }
1781 }
1782 }
1783 }
1784
1785 return A.run() == ChangeStatus::CHANGED;
1786}
1787} // namespace
1788
1791
1794 AnalysisGetter AG(FAM);
1795
1796 SetVector<Function *> Functions;
1797 for (Function &F : M) {
1798 if (!F.isDeclaration())
1799 Functions.insert(&F);
1800 }
1801
1802 // TODO: Probably preserves CFG
1803 return runImpl(Functions, /*IsModulePass=*/true, /*DeleteFns=*/true, M, AG,
1804 TM, Options, LTOPhase)
1807}
1808
1811 LazyCallGraph &CG,
1812 CGSCCUpdateResult &UR) {
1813
1815 AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
1816 AnalysisGetter AG(FAM);
1817
1818 SetVector<Function *> Functions;
1819 for (LazyCallGraph::Node &N : C) {
1820 Function *F = &N.getFunction();
1821 if (!F->isIntrinsic())
1822 Functions.insert(F);
1823 }
1824
1826 Module *M = C.begin()->getFunction().getParent();
1827 // In the CGSCC pipeline, avoid untracked call graph modifications by
1828 // disabling function deletion, mirroring the generic AttributorCGSCCPass.
1829 return runImpl(Functions, /*IsModulePass=*/false, /*DeleteFns=*/false, *M, AG,
1833}
SDValue Pred
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool isDSAddress(const Constant *C)
static constexpr std::pair< ImplicitArgumentMask, StringLiteral > ImplicitAttrs[]
static ImplicitArgumentMask intrinsicToAttrMask(Intrinsic::ID ID, bool &NonKernelOnly, bool &NeedsImplicit, bool HasApertureRegs, bool SupportsGetDoorBellID, unsigned CodeObjectVersion)
static bool hasSanitizerAttributes(const Function &F)
Returns true if sanitizer attributes are present on a function.
ImplicitArgumentMask
@ UNKNOWN_INTRINSIC
@ NOT_IMPLICIT_INPUT
@ ALL_ARGUMENT_MASK
ImplicitArgumentPositions
@ LAST_ARG_POS
static bool castRequiresQueuePtr(unsigned SrcAS)
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
bpf unwind BPF Unwind Lower
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool runImpl(MachineFunction &MF)
Definition CFIFixup.cpp:304
DXIL Resource Access
@ Default
AMD GCN specific subclass of TargetSubtarget.
#define RegName(no)
static LVOptions Options
Definition LVOptions.cpp:25
static LoopDeletionResult merge(LoopDeletionResult A, LoopDeletionResult B)
static FeatureBitset getFeatures(MCSubtargetInfo &STI, StringRef CPU, StringRef TuneCPU, StringRef FS, StringTable ProcNames, ArrayRef< SubtargetSubTypeKV > ProcDesc, ArrayRef< SubtargetFeatureKV > ProcFeatures)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
static StringRef getName(Value *V)
RISCVCC::CondCode CC
Basic Register Allocator
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
#define LLVM_DEBUG(...)
Definition Debug.h:119
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static constexpr AAKindSet get()
Return the set of the kinds with the IDs KindIDs.
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR)
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
static ClusterDimsAttr get(const Function &F)
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
constexpr bool test(unsigned I) const
Definition Bitset.h:109
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
A constant value that is initialized with an expression using other constant values.
Definition Constants.h:1316
const APInt & getLower() const
Return the lower value for this range.
const APInt & getUpper() const
Return the upper value for this range.
This is an important base class in LLVM.
Definition Constant.h:44
A proxy from a FunctionAnalysisManager to an SCC.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
Definition Function.cpp:356
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:273
unsigned getAddressSpace() const
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
A node in the call graph.
An SCC of the call graph.
A lazily constructed view of the call graph of a module.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
A vector that has set insertion semantics.
Definition SetVector.h:57
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
Primary interface to the complete machine description for the target machine.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
op_range operands()
Definition User.h:267
LLVM_ABI bool isDroppable() const
A droppable user is a user for which uses can be dropped without affecting correctness and should be ...
Definition User.cpp:113
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
CallInst * Call
#define INT64_MAX
Definition DataTypes.h:71
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const AArch64MCOptions & getCLOpts(const MCTargetOptions &Options)
@ REGION_ADDRESS
Address space for region memory. (GDS)
@ LOCAL_ADDRESS
Address space for local memory.
@ FLAT_ADDRESS
Address space for flat memory.
@ PRIVATE_ADDRESS
Address space for private memory.
LLVM_ABI unsigned getMaxWavesPerEU(GPUKind AK)
constexpr unsigned getMaxFlatWorkGroupSize()
constexpr unsigned getMinFlatWorkGroupSize()
unsigned getAMDHSACodeObjectVersion(const Module &M)
unsigned getDefaultQueueImplicitArgPosition(unsigned CodeObjectVersion)
std::tuple< char, unsigned, unsigned > parseAsmPhysRegName(StringRef RegName)
Returns a valid charcode or 0 in the first entry if this is a valid physical register name.
bool isLDSDMAIntrinsic(unsigned IntrID)
Bitset< NUM_FEATURES > AMDGPUFeatureBitset
LLVM_READNONE constexpr bool isEntryFunctionCC(CallingConv::ID CC)
LLVM_ABI Triple::SubArchType getSubArch(GPUKind AK)
std::tuple< char, unsigned, unsigned > parseAsmConstraintPhysReg(StringRef Constraint)
Returns a valid charcode or 0 in the first entry if this is a valid physical register constraint.
LLVM_ABI GPUKind getGPUKindFromSubArch(Triple::SubArchType SubArch)
SmallVector< unsigned > getMaxNumWorkGroups(const Function &F)
LLVM_ABI const AMDGPUFeatureBitset & getFeatureBitset(GPUKind AK)
Returns AK's feature bitset, or an empty bitset if unknown.
unsigned getCompletionActionImplicitArgPosition(unsigned CodeObjectVersion)
std::pair< unsigned, unsigned > getIntegerPairAttribute(const Function &F, StringRef Name, std::pair< unsigned, unsigned > Default, bool OnlyFirstRequired)
LLVM_READNONE constexpr bool isGraphics(CallingConv::ID CC)
constexpr E & operator^=(E &LHS, E RHS)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ CE
Windows NT (Windows on ARM)
Definition MCAsmInfo.h:51
NodeAddr< CodeNode * > Code
Definition RDFGraph.h:388
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
AnalysisManager< LazyCallGraph::SCC, LazyCallGraph & > CGSCCAnalysisManager
The CGSCC analysis manager.
ThinOrFullLTOPhase
This enumerates the LLVM full LTO or ThinLTO optimization phases.
Definition Pass.h:75
@ None
No LTO/ThinLTO behavior needed.
Definition Pass.h:77
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:149
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
const char * to_string(ThinOrFullLTOPhase Phase)
Definition Pass.cpp:311
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
@ Other
Any other memory.
Definition ModRef.h:68
ChangeStatus clampStateAndIndicateChange(StateType &S, const StateType &R)
Helper function to clamp a state S of type StateType with the information in R and indicate/return if...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
ChangeStatus
{
Definition Attributor.h:477
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:391
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
#define N
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
virtual const SetVector< Function * > & getOptimisticEdges() const =0
Get the optimistic edges.
virtual bool hasUnknownCallee() const =0
Is there any call with a unknown callee.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
virtual bool hasNonAsmUnknownCallee() const =0
Is there any call with a unknown callee, excluding any inline asm.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
const RangeList & getRanges() const
Instruction * getRemoteInst() const
Return the actual instruction that causes the access.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Helper to represent an access offset and size, with logic to deal with uncertainty and check for over...
Definition Attributor.h:245
virtual const char * getIdAddr() const =0
This function should return the address of the ID of the AbstractAttribute.
Wrapper for FunctionAnalysisManager.
The fixpoint analysis framework that orchestrates the attribute deduction.
Support structure for SCC passes to communicate updates the call graph back to the CGSCC pass manager...
DecIntegerState & takeAssumedMaximum(base_t Value)
Take maximum of assumed and Value.
Helper to describe and deal with positions in the LLVM-IR.
Definition Attributor.h:573
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
Definition Attributor.h:641
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
Definition Attributor.h:597
@ IRP_FUNCTION
An attribute for a function (scope).
Definition Attributor.h:585
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
Definition Attributor.h:616
Kind getPositionKind() const
Return the associated position kind.
Definition Attributor.h:846
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
Definition Attributor.h:636
Data structure to hold cached (LLVM-IR) information.
bool isValidState() const override
NOTE: For now we simply pretend that the worst possible state is invalid.
ChangeStatus indicatePessimisticFixpoint() override
Indicate that the abstract state should converge to the pessimistic state.
Helper to tie a abstract state implementation to an abstract attribute.