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