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