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