17#include "llvm/IR/IntrinsicsAMDGPU.h"
18#include "llvm/IR/IntrinsicsR600.h"
23#define DEBUG_TYPE "amdgpu-attributor"
28 "amdgpu-indirect-call-specialization-threshold",
30 "A threshold controls whether an indirect call will be specialized"),
33#define AMDGPU_ATTRIBUTE(Name, Str) Name##_POS,
36#include "AMDGPUAttributes.def"
40#define AMDGPU_ATTRIBUTE(Name, Str) Name = 1 << Name##_POS,
44#include "AMDGPUAttributes.def"
49#define AMDGPU_ATTRIBUTE(Name, Str) {Name, Str},
50static constexpr std::pair<ImplicitArgumentMask, StringLiteral>
52#include "AMDGPUAttributes.def"
62 bool HasApertureRegs,
bool SupportsGetDoorBellID,
63 unsigned CodeObjectVersion) {
65 case Intrinsic::amdgcn_workitem_id_x:
68 case Intrinsic::amdgcn_workgroup_id_x:
70 return WORKGROUP_ID_X;
71 case Intrinsic::amdgcn_workitem_id_y:
72 case Intrinsic::r600_read_tidig_y:
74 case Intrinsic::amdgcn_workitem_id_z:
75 case Intrinsic::r600_read_tidig_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:
86 case Intrinsic::amdgcn_cluster_id_y:
88 case Intrinsic::amdgcn_cluster_id_z:
90 case Intrinsic::amdgcn_lds_kernel_id:
92 case Intrinsic::amdgcn_dispatch_ptr:
94 case Intrinsic::amdgcn_dispatch_id:
96 case Intrinsic::amdgcn_implicitarg_ptr:
97 return IMPLICIT_ARG_PTR;
100 case Intrinsic::amdgcn_queue_ptr:
103 case Intrinsic::amdgcn_is_shared:
104 case Intrinsic::amdgcn_is_private:
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)
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);
152 AMDGPUInformationCache(
const Module &M, AnalysisGetter &AG,
154 SetVector<Function *> *
CGSCC, TargetMachine &TM)
163 enum ConstantStatus : uint8_t {
166 ADDR_SPACE_CAST_PRIVATE_TO_FLAT = 1 << 1,
167 ADDR_SPACE_CAST_LOCAL_TO_FLAT = 1 << 2,
168 ADDR_SPACE_CAST_BOTH_TO_FLAT =
169 ADDR_SPACE_CAST_PRIVATE_TO_FLAT | ADDR_SPACE_CAST_LOCAL_TO_FLAT,
170 CS_WORST = DS_GLOBAL | ADDR_SPACE_CAST_BOTH_TO_FLAT,
173 std::optional<std::pair<unsigned, unsigned>>
174 getFlatWorkGroupSizeAttr(
const Function &
F)
const {
178 return std::make_pair(
R->first, *(
R->second));
181 std::pair<unsigned, unsigned>
182 getDefaultFlatWorkGroupSize(
const Function &
F)
const {
183 const GCNSubtarget &
ST = TM.getSubtarget<GCNSubtarget>(
F);
184 return ST.getDefaultFlatWorkGroupSize(
F.getCallingConv());
187 std::pair<unsigned, unsigned> getMaximumFlatWorkGroupRange()
const {
193 unsigned getCodeObjectVersion()
const {
return CodeObjectVersion; }
198 std::optional<std::pair<unsigned, unsigned>>
206 return std::make_pair(Val->first, *(Val->second));
213 unsigned getMaxAddrSpace()
const override {
220 static uint8_t visitConstExpr(
const ConstantExpr *CE) {
221 uint8_t Status = NONE;
223 if (
CE->getOpcode() == Instruction::AddrSpaceCast) {
224 unsigned SrcAS =
CE->getOperand(0)->getType()->getPointerAddressSpace();
226 Status |= ADDR_SPACE_CAST_PRIVATE_TO_FLAT;
228 Status |= ADDR_SPACE_CAST_LOCAL_TO_FLAT;
235 uint8_t getConstantAccess(
const Constant *
C) {
236 const auto &It = ConstantStatus.find(
C);
237 if (It != ConstantStatus.end())
238 return It->second.value();
240 SmallPtrSet<const Constant *, 8> Visited;
246 while (Result != CS_WORST && !Worklist.
empty()) {
249 std::optional<uint8_t> &CurCResultOrNone = ConstantStatus[CurC];
250 if (CurCResultOrNone) {
251 Result |= CurCResultOrNone.value();
254 uint8_t CurCResult = 0;
257 CurCResult |= DS_GLOBAL;
260 CurCResult |= visitConstExpr(CE);
262 for (
const Use &U : CurC->
operands()) {
264 if (Visited.
insert(OpC).second)
269 CurCResultOrNone = CurCResult;
279 bool needsQueuePtr(
const Constant *
C,
Function &Fn) {
281 bool HasAperture = Features.test(AMDGPU::FEAT_APERTURE_REGS);
284 if (!IsNonEntryFunc && HasAperture)
287 uint8_t
Access = getConstantAccess(
C);
290 if (IsNonEntryFunc && (
Access & DS_GLOBAL))
293 return !HasAperture && (
Access & ADDR_SPACE_CAST_BOTH_TO_FLAT);
296 bool checkConstForAddrSpaceCastFromPrivate(
const Constant *
C) {
297 uint8_t
Access = getConstantAccess(
C);
298 return Access & ADDR_SPACE_CAST_PRIVATE_TO_FLAT;
303 DenseMap<const Constant *, std::optional<uint8_t>> ConstantStatus;
306 const unsigned CodeObjectVersion;
309struct AAAMDAttributes
310 :
public StateWrapper<BitIntegerState<uint32_t, ALL_ARGUMENT_MASK, 0>,
312 using Base = StateWrapper<BitIntegerState<uint32_t, ALL_ARGUMENT_MASK, 0>,
315 AAAMDAttributes(
const IRPosition &IRP, Attributor &
A) : Base(IRP) {}
318 static AAAMDAttributes &createForPosition(
const IRPosition &IRP,
322 StringRef
getName()
const override {
return "AAAMDAttributes"; }
325 const char *getIdAddr()
const override {
return &ID; }
329 static bool classof(
const AbstractAttribute *AA) {
334 static const char ID;
336const char AAAMDAttributes::ID = 0;
338struct AAUniformWorkGroupSize
339 :
public StateWrapper<BooleanState, AbstractAttribute> {
340 using Base = StateWrapper<BooleanState, AbstractAttribute>;
341 AAUniformWorkGroupSize(
const IRPosition &IRP, Attributor &
A) : Base(IRP) {}
344 static AAUniformWorkGroupSize &createForPosition(
const IRPosition &IRP,
348 StringRef
getName()
const override {
return "AAUniformWorkGroupSize"; }
351 const char *getIdAddr()
const override {
return &ID; }
355 static bool classof(
const AbstractAttribute *AA) {
360 static const char ID;
362const char AAUniformWorkGroupSize::ID = 0;
364struct AAUniformWorkGroupSizeFunction :
public AAUniformWorkGroupSize {
365 AAUniformWorkGroupSizeFunction(
const IRPosition &IRP, Attributor &
A)
366 : AAUniformWorkGroupSize(IRP,
A) {}
370 CallingConv::ID CC =
F->getCallingConv();
372 if (CC != CallingConv::AMDGPU_KERNEL)
375 bool InitialValue =
F->hasFnAttribute(
"uniform-work-group-size");
378 indicateOptimisticFixpoint();
380 indicatePessimisticFixpoint();
386 auto CheckCallSite = [&](AbstractCallSite CS) {
389 <<
"->" << getAssociatedFunction()->
getName() <<
"\n");
391 const auto *CallerInfo =
A.getAAFor<AAUniformWorkGroupSize>(
393 if (!CallerInfo || !CallerInfo->isValidState())
397 CallerInfo->getState());
402 bool AllCallSitesKnown =
true;
403 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
404 return indicatePessimisticFixpoint();
411 return ChangeStatus::UNCHANGED;
413 LLVMContext &Ctx = getAssociatedFunction()->getContext();
414 return A.manifestAttrs(getIRPosition(),
415 {Attribute::get(Ctx,
"uniform-work-group-size")},
419 bool isValidState()
const override {
424 const std::string getAsStr(Attributor *)
const override {
425 return "AMDWorkGroupSize[" + std::to_string(getAssumed()) +
"]";
429 void trackStatistics()
const override {}
432AAUniformWorkGroupSize &
433AAUniformWorkGroupSize::createForPosition(
const IRPosition &IRP,
436 return *
new (
A.Allocator) AAUniformWorkGroupSizeFunction(IRP,
A);
438 "AAUniformWorkGroupSize is only valid for function position");
441struct AAAMDAttributesFunction :
public AAAMDAttributes {
442 AAAMDAttributesFunction(
const IRPosition &IRP, Attributor &
A)
443 : AAAMDAttributes(IRP,
A) {}
455 if (HasSanitizerAttrs) {
456 removeAssumedBits(IMPLICIT_ARG_PTR);
457 removeAssumedBits(HOSTCALL_PTR);
458 removeAssumedBits(FLAT_SCRATCH_INIT);
462 if (HasSanitizerAttrs &&
463 (Attr.first == IMPLICIT_ARG_PTR || Attr.first == HOSTCALL_PTR ||
464 Attr.first == FLAT_SCRATCH_INIT))
467 if (
F->hasFnAttribute(Attr.second))
468 addKnownBits(Attr.first);
471 if (
F->isDeclaration())
477 indicatePessimisticFixpoint();
485 auto OrigAssumed = getAssumed();
488 const AACallEdges *AAEdges =
A.getAAFor<AACallEdges>(
489 *
this, this->getIRPosition(), DepClassTy::REQUIRED);
492 return indicatePessimisticFixpoint();
496 bool NeedsImplicit =
false;
497 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
499 bool HasApertureRegs = Features.
test(AMDGPU::FEAT_APERTURE_REGS);
500 bool SupportsGetDoorbellID = Features.
test(AMDGPU::FEAT_GET_DOORBELL_ID);
501 unsigned COV = InfoCache.getCodeObjectVersion();
506 const AAAMDAttributes *AAAMD =
A.getAAFor<AAAMDAttributes>(
508 if (!AAAMD || !AAAMD->isValidState())
509 return indicatePessimisticFixpoint();
514 bool NonKernelOnly =
false;
517 HasApertureRegs, SupportsGetDoorbellID, COV);
528 if (!
Callee->hasFnAttribute(Attribute::NoCallback))
529 return indicatePessimisticFixpoint();
534 if ((IsNonEntryFunc || !NonKernelOnly))
535 removeAssumedBits(AttrMask);
541 removeAssumedBits(IMPLICIT_ARG_PTR);
543 if (isAssumed(QUEUE_PTR) && checkForQueuePtr(
A)) {
547 removeAssumedBits(IMPLICIT_ARG_PTR);
549 removeAssumedBits(QUEUE_PTR);
552 if (funcRetrievesMultigridSyncArg(
A, COV)) {
553 assert(!isAssumed(IMPLICIT_ARG_PTR) &&
554 "multigrid_sync_arg needs implicitarg_ptr");
555 removeAssumedBits(MULTIGRID_SYNC_ARG);
558 if (funcRetrievesHostcallPtr(
A, COV)) {
559 assert(!isAssumed(IMPLICIT_ARG_PTR) &&
"hostcall needs implicitarg_ptr");
560 removeAssumedBits(HOSTCALL_PTR);
563 if (funcRetrievesHeapPtr(
A, COV)) {
564 assert(!isAssumed(IMPLICIT_ARG_PTR) &&
"heap_ptr needs implicitarg_ptr");
565 removeAssumedBits(HEAP_PTR);
568 if (isAssumed(QUEUE_PTR) && funcRetrievesQueuePtr(
A, COV)) {
569 assert(!isAssumed(IMPLICIT_ARG_PTR) &&
"queue_ptr needs implicitarg_ptr");
570 removeAssumedBits(QUEUE_PTR);
573 if (isAssumed(LDS_KERNEL_ID) && funcRetrievesLDSKernelId(
A)) {
574 removeAssumedBits(LDS_KERNEL_ID);
577 if (isAssumed(DEFAULT_QUEUE) && funcRetrievesDefaultQueue(
A, COV))
578 removeAssumedBits(DEFAULT_QUEUE);
580 if (isAssumed(COMPLETION_ACTION) && funcRetrievesCompletionAction(
A, COV))
581 removeAssumedBits(COMPLETION_ACTION);
583 if (isAssumed(FLAT_SCRATCH_INIT) && needFlatScratchInit(
A))
584 removeAssumedBits(FLAT_SCRATCH_INIT);
586 return getAssumed() != OrigAssumed ? ChangeStatus::CHANGED
587 : ChangeStatus::UNCHANGED;
592 LLVMContext &Ctx = getAssociatedFunction()->getContext();
595 if (isKnown(Attr.first))
596 AttrList.
push_back(Attribute::get(Ctx, Attr.second));
599 return A.manifestAttrs(getIRPosition(), AttrList,
603 const std::string getAsStr(Attributor *)
const override {
605 raw_string_ostream OS(Str);
608 if (isAssumed(Attr.first))
609 OS <<
' ' << Attr.second;
615 void trackStatistics()
const override {}
618 bool checkForQueuePtr(Attributor &
A) {
622 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
624 bool NeedsQueuePtr =
false;
627 unsigned SrcAS =
static_cast<AddrSpaceCastInst &
>(
I).getSrcAddressSpace();
629 NeedsQueuePtr =
true;
635 bool HasApertureRegs =
636 InfoCache.getFeatures().test(AMDGPU::FEAT_APERTURE_REGS);
642 if (!HasApertureRegs) {
643 bool UsedAssumedInformation =
false;
644 A.checkForAllInstructions(CheckAddrSpaceCasts, *
this,
645 {Instruction::AddrSpaceCast},
646 UsedAssumedInformation);
653 if (!IsNonEntryFunc && HasApertureRegs)
656 for (BasicBlock &BB : *
F) {
657 for (Instruction &
I : BB) {
658 for (
const Use &U :
I.operands()) {
660 if (InfoCache.needsQueuePtr(
C, *
F))
670 bool funcRetrievesMultigridSyncArg(Attributor &
A,
unsigned COV) {
672 AA::RangeTy
Range(Pos, 8);
673 return funcRetrievesImplicitKernelArg(
A,
Range);
676 bool funcRetrievesHostcallPtr(Attributor &
A,
unsigned COV) {
678 AA::RangeTy
Range(Pos, 8);
679 return funcRetrievesImplicitKernelArg(
A,
Range);
682 bool funcRetrievesDefaultQueue(Attributor &
A,
unsigned COV) {
684 AA::RangeTy
Range(Pos, 8);
685 return funcRetrievesImplicitKernelArg(
A,
Range);
688 bool funcRetrievesCompletionAction(Attributor &
A,
unsigned COV) {
690 AA::RangeTy
Range(Pos, 8);
691 return funcRetrievesImplicitKernelArg(
A,
Range);
694 bool funcRetrievesHeapPtr(Attributor &
A,
unsigned COV) {
698 return funcRetrievesImplicitKernelArg(
A,
Range);
701 bool funcRetrievesQueuePtr(Attributor &
A,
unsigned COV) {
705 return funcRetrievesImplicitKernelArg(
A,
Range);
708 bool funcRetrievesImplicitKernelArg(Attributor &
A, AA::RangeTy
Range) {
720 const auto *PointerInfoAA =
A.getAAFor<AAPointerInfo>(
722 if (!PointerInfoAA || !PointerInfoAA->getState().isValidState())
725 return PointerInfoAA->forallInterferingAccesses(
726 Range, [](
const AAPointerInfo::Access &Acc,
bool IsExact) {
731 bool UsedAssumedInformation =
false;
732 return !
A.checkForAllCallLikeInstructions(DoesNotLeadToKernelArgLoc, *
this,
733 UsedAssumedInformation);
736 bool funcRetrievesLDSKernelId(Attributor &
A) {
741 bool UsedAssumedInformation =
false;
742 return !
A.checkForAllCallLikeInstructions(DoesNotRetrieve, *
this,
743 UsedAssumedInformation);
748 bool needFlatScratchInit(Attributor &
A) {
749 assert(isAssumed(FLAT_SCRATCH_INIT));
758 bool UsedAssumedInformation =
false;
759 if (!
A.checkForAllInstructions(AddrSpaceCastNotFromPrivate, *
this,
760 {Instruction::AddrSpaceCast},
761 UsedAssumedInformation))
765 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
769 for (
const Use &U :
I.operands()) {
771 if (InfoCache.checkConstForAddrSpaceCastFromPrivate(
C))
781AAAMDAttributes &AAAMDAttributes::createForPosition(
const IRPosition &IRP,
784 return *
new (
A.Allocator) AAAMDAttributesFunction(IRP,
A);
789struct AAAMDSizeRangeAttribute
790 :
public StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t> {
791 using Base = StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t>;
795 AAAMDSizeRangeAttribute(
const IRPosition &IRP, Attributor &
A,
797 :
Base(IRP, 32), AttrName(AttrName) {}
800 void trackStatistics()
const override {}
802 template <
class AttributeImpl>
ChangeStatus updateImplImpl(Attributor &
A) {
805 auto CheckCallSite = [&](AbstractCallSite CS) {
808 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
810 const auto *CallerInfo =
A.getAAFor<AttributeImpl>(
812 if (!CallerInfo || !CallerInfo->isValidState())
821 bool AllCallSitesKnown =
true;
822 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
825 return indicatePessimisticFixpoint();
833 emitAttributeIfNotDefaultAfterClamp(Attributor &
A,
834 std::pair<unsigned, unsigned>
Default) {
836 unsigned Lower = getAssumed().getLower().getZExtValue();
837 unsigned Upper = getAssumed().getUpper().getZExtValue();
847 return ChangeStatus::UNCHANGED;
850 LLVMContext &Ctx =
F->getContext();
851 SmallString<10> Buffer;
852 raw_svector_ostream OS(Buffer);
854 return A.manifestAttrs(getIRPosition(),
855 {Attribute::get(Ctx, AttrName, OS.str())},
859 const std::string getAsStr(Attributor *)
const override {
861 raw_string_ostream OS(Str);
863 OS << getAssumed().getLower() <<
',' << getAssumed().getUpper() - 1;
870struct AAAMDFlatWorkGroupSize :
public AAAMDSizeRangeAttribute {
871 AAAMDFlatWorkGroupSize(
const IRPosition &IRP, Attributor &
A)
872 : AAAMDSizeRangeAttribute(IRP,
A,
"amdgpu-flat-work-group-size") {}
876 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
878 bool HasAttr =
false;
879 auto Range = InfoCache.getDefaultFlatWorkGroupSize(*
F);
880 auto MaxRange = InfoCache.getMaximumFlatWorkGroupRange();
882 if (
auto Attr = InfoCache.getFlatWorkGroupSizeAttr(*
F)) {
886 if (*Attr != MaxRange) {
894 if (
Range == MaxRange)
898 ConstantRange CR(APInt(32, Min), APInt(32, Max + 1));
899 IntegerRangeState IRS(CR);
903 indicateOptimisticFixpoint();
907 return updateImplImpl<AAAMDFlatWorkGroupSize>(
A);
911 static AAAMDFlatWorkGroupSize &createForPosition(
const IRPosition &IRP,
915 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
916 return emitAttributeIfNotDefaultAfterClamp(
917 A, InfoCache.getMaximumFlatWorkGroupRange());
921 StringRef
getName()
const override {
return "AAAMDFlatWorkGroupSize"; }
924 const char *getIdAddr()
const override {
return &
ID; }
928 static bool classof(
const AbstractAttribute *AA) {
933 static const char ID;
936const char AAAMDFlatWorkGroupSize::ID = 0;
938AAAMDFlatWorkGroupSize &
939AAAMDFlatWorkGroupSize::createForPosition(
const IRPosition &IRP,
942 return *
new (
A.Allocator) AAAMDFlatWorkGroupSize(IRP,
A);
944 "AAAMDFlatWorkGroupSize is only valid for function position");
947struct TupleDecIntegerRangeState :
public AbstractState {
948 DecIntegerState<uint32_t>
X,
Y, Z;
950 bool isValidState()
const override {
951 return X.isValidState() &&
Y.isValidState() &&
Z.isValidState();
954 bool isAtFixpoint()
const override {
955 return X.isAtFixpoint() &&
Y.isAtFixpoint() &&
Z.isAtFixpoint();
959 return X.indicateOptimisticFixpoint() |
Y.indicateOptimisticFixpoint() |
960 Z.indicateOptimisticFixpoint();
964 return X.indicatePessimisticFixpoint() |
Y.indicatePessimisticFixpoint() |
965 Z.indicatePessimisticFixpoint();
968 TupleDecIntegerRangeState
operator^=(
const TupleDecIntegerRangeState &
Other) {
979 TupleDecIntegerRangeState &getAssumed() {
return *
this; }
980 const TupleDecIntegerRangeState &getAssumed()
const {
return *
this; }
983using AAAMDMaxNumWorkgroupsState =
984 StateWrapper<TupleDecIntegerRangeState, AbstractAttribute, uint32_t>;
987struct AAAMDMaxNumWorkgroups
988 :
public StateWrapper<TupleDecIntegerRangeState, AbstractAttribute> {
989 using Base = StateWrapper<TupleDecIntegerRangeState, AbstractAttribute>;
991 AAAMDMaxNumWorkgroups(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
998 X.takeKnownMinimum(MaxNumWorkgroups[0]);
999 Y.takeKnownMinimum(MaxNumWorkgroups[1]);
1000 Z.takeKnownMinimum(MaxNumWorkgroups[2]);
1003 indicatePessimisticFixpoint();
1009 auto CheckCallSite = [&](AbstractCallSite CS) {
1012 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
1014 const auto *CallerInfo =
A.getAAFor<AAAMDMaxNumWorkgroups>(
1016 if (!CallerInfo || !CallerInfo->isValidState())
1024 bool AllCallSitesKnown =
true;
1025 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
1028 return indicatePessimisticFixpoint();
1034 static AAAMDMaxNumWorkgroups &createForPosition(
const IRPosition &IRP,
1039 LLVMContext &Ctx =
F->getContext();
1040 SmallString<32> Buffer;
1041 raw_svector_ostream OS(Buffer);
1042 OS <<
X.getAssumed() <<
',' <<
Y.getAssumed() <<
',' <<
Z.getAssumed();
1046 return A.manifestAttrs(
1048 {Attribute::get(Ctx,
"amdgpu-max-num-workgroups", OS.str())},
1052 StringRef
getName()
const override {
return "AAAMDMaxNumWorkgroups"; }
1054 const std::string getAsStr(Attributor *)
const override {
1055 std::string Buffer =
"AAAMDMaxNumWorkgroupsState[";
1056 raw_string_ostream OS(Buffer);
1057 OS <<
X.getAssumed() <<
',' <<
Y.getAssumed() <<
',' <<
Z.getAssumed()
1062 const char *getIdAddr()
const override {
return &
ID; }
1066 static bool classof(
const AbstractAttribute *AA) {
1070 void trackStatistics()
const override {}
1073 static const char ID;
1076const char AAAMDMaxNumWorkgroups::ID = 0;
1078AAAMDMaxNumWorkgroups &
1079AAAMDMaxNumWorkgroups::createForPosition(
const IRPosition &IRP, Attributor &
A) {
1081 return *
new (
A.Allocator) AAAMDMaxNumWorkgroups(IRP,
A);
1082 llvm_unreachable(
"AAAMDMaxNumWorkgroups is only valid for function position");
1086struct AAAMDWavesPerEU :
public AAAMDSizeRangeAttribute {
1087 AAAMDWavesPerEU(
const IRPosition &IRP, Attributor &
A)
1088 : AAAMDSizeRangeAttribute(IRP,
A,
"amdgpu-waves-per-eu") {}
1092 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
1095 if (
auto Attr = InfoCache.getWavesPerEUAttr(*
F)) {
1096 std::pair<unsigned, unsigned> MaxWavesPerEURange{
1097 1U, InfoCache.getMaxWavesPerEU()};
1098 if (*Attr != MaxWavesPerEURange) {
1099 auto [Min,
Max] = *Attr;
1100 ConstantRange
Range(APInt(32, Min), APInt(32, Max + 1));
1101 IntegerRangeState RangeState(
Range);
1102 this->getState() = RangeState;
1103 indicateOptimisticFixpoint();
1109 indicatePessimisticFixpoint();
1115 auto CheckCallSite = [&](AbstractCallSite CS) {
1119 <<
"->" <<
Func->getName() <<
'\n');
1122 const auto *CallerAA =
A.getAAFor<AAAMDWavesPerEU>(
1124 if (!CallerAA || !CallerAA->isValidState())
1127 ConstantRange Assumed = getAssumed();
1129 CallerAA->getAssumed().getLower().getZExtValue());
1131 CallerAA->getAssumed().getUpper().getZExtValue());
1132 ConstantRange
Range(APInt(32, Min), APInt(32, Max));
1133 IntegerRangeState RangeState(
Range);
1134 getState() = RangeState;
1135 Change |= getState() == Assumed ? ChangeStatus::UNCHANGED
1136 : ChangeStatus::CHANGED;
1141 bool AllCallSitesKnown =
true;
1142 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
1143 return indicatePessimisticFixpoint();
1149 static AAAMDWavesPerEU &createForPosition(
const IRPosition &IRP,
1153 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
1154 return emitAttributeIfNotDefaultAfterClamp(
1155 A, {1U, InfoCache.getMaxWavesPerEU()});
1159 StringRef
getName()
const override {
return "AAAMDWavesPerEU"; }
1162 const char *getIdAddr()
const override {
return &
ID; }
1166 static bool classof(
const AbstractAttribute *AA) {
1171 static const char ID;
1174const char AAAMDWavesPerEU::ID = 0;
1176AAAMDWavesPerEU &AAAMDWavesPerEU::createForPosition(
const IRPosition &IRP,
1179 return *
new (
A.Allocator) AAAMDWavesPerEU(IRP,
A);
1184static unsigned inlineAsmGetNumRequiredAGPRs(
const InlineAsm *IA,
1185 const CallBase &
Call) {
1188 unsigned AGPRDefCount = 0;
1189 unsigned AGPRUseCount = 0;
1190 unsigned MaxPhysReg = 0;
1194 for (
const InlineAsm::ConstraintInfo &CI :
IA->ParseConstraints()) {
1200 Ty = STy->getElementType(ResNo);
1215 for (StringRef Code : CI.Codes) {
1216 unsigned RegCount = 0;
1217 if (
Code.starts_with(
"a")) {
1228 MaxPhysReg = std::max(MaxPhysReg, std::min(RegIdx + NumRegs, 256u));
1238 AGPRDefCount =
alignTo(AGPRDefCount, RegCount);
1240 AGPRDefCount += RegCount;
1241 if (CI.isEarlyClobber) {
1242 AGPRUseCount =
alignTo(AGPRUseCount, RegCount);
1243 AGPRUseCount += RegCount;
1246 AGPRUseCount =
alignTo(AGPRUseCount, RegCount);
1247 AGPRUseCount += RegCount;
1252 unsigned MaxVirtReg = std::max(AGPRUseCount, AGPRDefCount);
1257 return std::min(MaxVirtReg + MaxPhysReg, 256u);
1260struct AAAMDGPUMinAGPRAlloc
1261 :
public StateWrapper<DecIntegerState<>, AbstractAttribute> {
1262 using Base = StateWrapper<DecIntegerState<>, AbstractAttribute>;
1263 AAAMDGPUMinAGPRAlloc(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
1265 static AAAMDGPUMinAGPRAlloc &createForPosition(
const IRPosition &IRP,
1268 return *
new (
A.Allocator) AAAMDGPUMinAGPRAlloc(IRP,
A);
1270 "AAAMDGPUMinAGPRAlloc is only valid for function position");
1275 auto [MinNumAGPR, MaxNumAGPR] =
1278 if (MinNumAGPR == 0) {
1279 indicateOptimisticFixpoint();
1284 indicatePessimisticFixpoint();
1287 const std::string getAsStr(Attributor *
A)
const override {
1288 std::string Str =
"amdgpu-agpr-alloc=";
1289 raw_string_ostream OS(Str);
1294 void trackStatistics()
const override {}
1297 DecIntegerState<> Maximum;
1304 const Value *CalleeOp = CB.getCalledOperand();
1309 unsigned NumRegs = inlineAsmGetNumRequiredAGPRs(IA, CB);
1313 switch (CB.getIntrinsicID()) {
1316 case Intrinsic::write_register:
1317 case Intrinsic::read_register:
1318 case Intrinsic::read_volatile_register: {
1323 auto [
Kind, RegIdx, NumRegs] =
1337 case Intrinsic::trap:
1338 case Intrinsic::debugtrap:
1339 case Intrinsic::ubsantrap:
1340 return CB.hasFnAttr(Attribute::NoCallback) ||
1341 !CB.hasFnAttr(
"trap-func-name");
1347 return CB.hasFnAttr(Attribute::NoCallback);
1351 auto *CBEdges =
A.getAAFor<AACallEdges>(
1353 if (!CBEdges || CBEdges->hasUnknownCallee()) {
1358 for (
const Function *PossibleCallee : CBEdges->getOptimisticEdges()) {
1359 const auto *CalleeInfo =
A.getAAFor<AAAMDGPUMinAGPRAlloc>(
1361 if (!CalleeInfo || !CalleeInfo->isValidState()) {
1372 bool UsedAssumedInformation =
false;
1373 if (!
A.checkForAllCallLikeInstructions(CheckForMinAGPRAllocs, *
this,
1374 UsedAssumedInformation))
1375 return indicatePessimisticFixpoint();
1381 LLVMContext &Ctx = getAssociatedFunction()->getContext();
1382 SmallString<4> Buffer;
1383 raw_svector_ostream OS(Buffer);
1386 return A.manifestAttrs(
1387 getIRPosition(), {Attribute::get(Ctx,
"amdgpu-agpr-alloc", OS.str())});
1390 StringRef
getName()
const override {
return "AAAMDGPUMinAGPRAlloc"; }
1391 const char *getIdAddr()
const override {
return &
ID; }
1395 static bool classof(
const AbstractAttribute *AA) {
1399 static const char ID;
1402const char AAAMDGPUMinAGPRAlloc::ID = 0;
1406struct AAAMDGPUClusterDims
1407 :
public StateWrapper<BooleanState, AbstractAttribute> {
1408 using Base = StateWrapper<BooleanState, AbstractAttribute>;
1409 AAAMDGPUClusterDims(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
1412 static AAAMDGPUClusterDims &createForPosition(
const IRPosition &IRP,
1416 StringRef
getName()
const override {
return "AAAMDGPUClusterDims"; }
1419 const char *getIdAddr()
const override {
return &
ID; }
1423 static bool classof(
const AbstractAttribute *AA) {
1427 virtual const AMDGPU::ClusterDimsAttr &getClusterDims()
const = 0;
1430 static const char ID;
1433const char AAAMDGPUClusterDims::ID = 0;
1435struct AAAMDGPUClusterDimsFunction :
public AAAMDGPUClusterDims {
1436 AAAMDGPUClusterDimsFunction(
const IRPosition &IRP, Attributor &
A)
1437 : AAAMDGPUClusterDims(IRP,
A) {}
1441 assert(
F &&
"empty associated function");
1448 indicatePessimisticFixpoint();
1450 indicateOptimisticFixpoint();
1454 const std::string getAsStr(Attributor *
A)
const override {
1464 void trackStatistics()
const override {}
1467 auto OldState = Attr;
1469 auto CheckCallSite = [&](AbstractCallSite CS) {
1470 const auto *CallerAA =
A.getAAFor<AAAMDGPUClusterDims>(
1472 DepClassTy::REQUIRED);
1473 if (!CallerAA || !CallerAA->isValidState())
1476 return merge(CallerAA->getClusterDims());
1479 bool UsedAssumedInformation =
false;
1480 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
1482 UsedAssumedInformation))
1483 return indicatePessimisticFixpoint();
1485 return OldState == Attr ? ChangeStatus::UNCHANGED : ChangeStatus::CHANGED;
1490 return ChangeStatus::UNCHANGED;
1491 return A.manifestAttrs(
1493 {Attribute::get(getAssociatedFunction()->
getContext(), AttrName,
1498 const AMDGPU::ClusterDimsAttr &getClusterDims()
const override {
1503 bool merge(
const AMDGPU::ClusterDimsAttr &
Other) {
1518 if (
Other.isUnknown())
1543 AMDGPU::ClusterDimsAttr Attr;
1545 static constexpr char AttrName[] =
"amdgpu-cluster-dims";
1548AAAMDGPUClusterDims &
1549AAAMDGPUClusterDims::createForPosition(
const IRPosition &IRP, Attributor &
A) {
1551 return *
new (
A.Allocator) AAAMDGPUClusterDimsFunction(IRP,
A);
1552 llvm_unreachable(
"AAAMDGPUClusterDims is only valid for function position");
1555static bool runImpl(SetVector<Function *> &Functions,
bool IsModulePass,
1556 bool DeleteFns,
Module &M, AnalysisGetter &AG,
1557 TargetMachine &TM, AMDGPUAttributorOptions
Options,
1560 CallGraphUpdater CGUpdater;
1562 AMDGPUInformationCache InfoCache(M, AG,
Allocator,
nullptr, TM);
1563 DenseSet<const char *>
Allowed(
1564 {&AAAMDAttributes::ID, &AAUniformWorkGroupSize::ID,
1566 &AAAMDMaxNumWorkgroups::ID, &AAAMDWavesPerEU::ID,
1572 AttributorConfig AC(CGUpdater);
1573 AC.IsClosedWorldModule =
Options.IsClosedWorld;
1575 AC.IsModulePass = IsModulePass;
1576 AC.DeleteFns = DeleteFns;
1577 AC.DefaultInitializeLiveInternals =
false;
1578 AC.IndirectCalleeSpecializationCallback =
1579 [](Attributor &
A,
const AbstractAttribute &AA, CallBase &CB,
1584 AC.IPOAmendableCB = [](
const Function &
F) {
1585 return F.getCallingConv() == CallingConv::AMDGPU_KERNEL;
1588 Attributor
A(Functions, InfoCache, AC);
1591 StringRef LTOPhaseStr =
to_string(LTOPhase);
1592 dbgs() <<
"[AMDGPUAttributor] Running at phase " << LTOPhaseStr <<
'\n'
1593 <<
"[AMDGPUAttributor] Module " <<
M.getName() <<
" is "
1594 << (AC.IsClosedWorldModule ?
"" :
"not ")
1595 <<
"assumed to be a closed world.\n";
1598 for (
auto *
F : Functions) {
1602 CallingConv::ID CC =
F->getCallingConv();
1609 if (!
F->isDeclaration() && Features.
test(AMDGPU::FEAT_CLUSTERS))
1612 if (Features.
test(AMDGPU::FEAT_AGPR_ALLOC))
1616 Value *Ptr =
nullptr;
1618 Ptr = LI->getPointerOperand();
1620 Ptr =
SI->getPointerOperand();
1622 Ptr = RMW->getPointerOperand();
1624 Ptr = CmpX->getPointerOperand();
1630 if (
II->getIntrinsicID() == Intrinsic::amdgcn_make_buffer_rsrc)
1637 return A.run() == ChangeStatus::CHANGED;
1650 if (!
F.isDeclaration())
1651 Functions.insert(&
F);
1655 return runImpl(Functions,
true,
true, M, AG,
1656 TM, Options, LTOPhase)
1673 if (!
F->isIntrinsic())
1674 Functions.insert(
F);
1678 Module *M =
C.begin()->getFunction().getParent();
1681 return runImpl(Functions,
false,
false, *M, AG,
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.
ImplicitArgumentPositions
static bool castRequiresQueuePtr(unsigned SrcAS)
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
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)
AMD GCN specific subclass of TargetSubtarget.
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)
Machine Check Debug Module
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
static StringRef getName(Value *V)
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
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)
std::string to_string() const
bool isVariableDims() const
uint64_t getZExtValue() const
Get zero extended value.
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
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.
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...
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.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
A vector that has set insertion semantics.
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.
LLVM_ABI bool isDroppable() const
A droppable user is a user for which uses can be dropped without affecting correctness and should be ...
Type * getType() const
All values are typed, get the type of this value.
#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.
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)
E & operator^=(E &LHS, E RHS)
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
NodeAddr< CodeNode * > Code
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
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.
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
AnalysisManager< LazyCallGraph::SCC, LazyCallGraph & > CGSCCAnalysisManager
The CGSCC analysis manager.
ThinOrFullLTOPhase
This enumerates the LLVM full LTO or ThinLTO optimization phases.
@ None
No LTO/ThinLTO behavior needed.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
const char * to_string(ThinOrFullLTOPhase Phase)
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
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.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
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.
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
@ IRP_FUNCTION
An attribute for a function (scope).
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
Kind getPositionKind() const
Return the associated position kind.
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
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.