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)
160 enum ConstantStatus : uint8_t {
163 ADDR_SPACE_CAST_PRIVATE_TO_FLAT = 1 << 1,
164 ADDR_SPACE_CAST_LOCAL_TO_FLAT = 1 << 2,
165 ADDR_SPACE_CAST_BOTH_TO_FLAT =
166 ADDR_SPACE_CAST_PRIVATE_TO_FLAT | ADDR_SPACE_CAST_LOCAL_TO_FLAT,
167 CS_WORST = DS_GLOBAL | ADDR_SPACE_CAST_BOTH_TO_FLAT,
171 bool hasApertureRegs(Function &
F) {
172 const GCNSubtarget &
ST = TM.getSubtarget<GCNSubtarget>(
F);
173 return ST.hasApertureRegs();
177 bool supportsGetDoorbellID(Function &
F) {
178 const GCNSubtarget &
ST = TM.getSubtarget<GCNSubtarget>(
F);
179 return ST.supportsGetDoorbellID();
182 std::optional<std::pair<unsigned, unsigned>>
183 getFlatWorkGroupSizeAttr(
const Function &
F)
const {
187 return std::make_pair(
R->first, *(
R->second));
190 std::pair<unsigned, unsigned>
191 getDefaultFlatWorkGroupSize(
const Function &
F)
const {
192 const GCNSubtarget &
ST = TM.getSubtarget<GCNSubtarget>(
F);
193 return ST.getDefaultFlatWorkGroupSize(
F.getCallingConv());
196 std::pair<unsigned, unsigned>
197 getMaximumFlatWorkGroupRange(
const Function &
F) {
198 const GCNSubtarget &
ST = TM.getSubtarget<GCNSubtarget>(
F);
199 return {
ST.getMinFlatWorkGroupSize(),
ST.getMaxFlatWorkGroupSize()};
202 SmallVector<unsigned> getMaxNumWorkGroups(
const Function &
F) {
203 const GCNSubtarget &
ST = TM.getSubtarget<GCNSubtarget>(
F);
204 return ST.getMaxNumWorkGroups(
F);
208 unsigned getCodeObjectVersion()
const {
return CodeObjectVersion; }
210 std::optional<std::pair<unsigned, unsigned>>
211 getWavesPerEUAttr(
const Function &
F) {
217 const GCNSubtarget &
ST = TM.getSubtarget<GCNSubtarget>(
F);
218 Val->second =
ST.getMaxWavesPerEU();
220 return std::make_pair(Val->first, *(Val->second));
224 const GCNSubtarget &
ST = TM.getSubtarget<GCNSubtarget>(
F);
225 return ST.getMaxWavesPerEU();
228 unsigned getMaxAddrSpace()
const override {
235 static uint8_t visitConstExpr(
const ConstantExpr *CE) {
236 uint8_t Status = NONE;
238 if (
CE->getOpcode() == Instruction::AddrSpaceCast) {
239 unsigned SrcAS =
CE->getOperand(0)->getType()->getPointerAddressSpace();
241 Status |= ADDR_SPACE_CAST_PRIVATE_TO_FLAT;
243 Status |= ADDR_SPACE_CAST_LOCAL_TO_FLAT;
250 uint8_t getConstantAccess(
const Constant *
C) {
251 const auto &It = ConstantStatus.find(
C);
252 if (It != ConstantStatus.end())
253 return It->second.value();
255 SmallPtrSet<const Constant *, 8> Visited;
261 while (Result != CS_WORST && !Worklist.
empty()) {
264 std::optional<uint8_t> &CurCResultOrNone = ConstantStatus[CurC];
265 if (CurCResultOrNone) {
266 Result |= CurCResultOrNone.value();
269 uint8_t CurCResult = 0;
272 CurCResult |= DS_GLOBAL;
275 CurCResult |= visitConstExpr(CE);
277 for (
const Use &U : CurC->
operands()) {
279 if (Visited.
insert(OpC).second)
284 CurCResultOrNone = CurCResult;
294 bool needsQueuePtr(
const Constant *
C, Function &Fn) {
296 bool HasAperture = hasApertureRegs(Fn);
299 if (!IsNonEntryFunc && HasAperture)
302 uint8_t
Access = getConstantAccess(
C);
305 if (IsNonEntryFunc && (
Access & DS_GLOBAL))
308 return !HasAperture && (
Access & ADDR_SPACE_CAST_BOTH_TO_FLAT);
311 bool checkConstForAddrSpaceCastFromPrivate(
const Constant *
C) {
312 uint8_t
Access = getConstantAccess(
C);
313 return Access & ADDR_SPACE_CAST_PRIVATE_TO_FLAT;
318 DenseMap<const Constant *, std::optional<uint8_t>> ConstantStatus;
319 const unsigned CodeObjectVersion;
322struct AAAMDAttributes
323 :
public StateWrapper<BitIntegerState<uint32_t, ALL_ARGUMENT_MASK, 0>,
325 using Base = StateWrapper<BitIntegerState<uint32_t, ALL_ARGUMENT_MASK, 0>,
328 AAAMDAttributes(
const IRPosition &IRP, Attributor &
A) : Base(IRP) {}
331 static AAAMDAttributes &createForPosition(
const IRPosition &IRP,
335 StringRef
getName()
const override {
return "AAAMDAttributes"; }
338 const char *getIdAddr()
const override {
return &ID; }
342 static bool classof(
const AbstractAttribute *AA) {
347 static const char ID;
349const char AAAMDAttributes::ID = 0;
351struct AAUniformWorkGroupSize
352 :
public StateWrapper<BooleanState, AbstractAttribute> {
353 using Base = StateWrapper<BooleanState, AbstractAttribute>;
354 AAUniformWorkGroupSize(
const IRPosition &IRP, Attributor &
A) : Base(IRP) {}
357 static AAUniformWorkGroupSize &createForPosition(
const IRPosition &IRP,
361 StringRef
getName()
const override {
return "AAUniformWorkGroupSize"; }
364 const char *getIdAddr()
const override {
return &ID; }
368 static bool classof(
const AbstractAttribute *AA) {
373 static const char ID;
375const char AAUniformWorkGroupSize::ID = 0;
377struct AAUniformWorkGroupSizeFunction :
public AAUniformWorkGroupSize {
378 AAUniformWorkGroupSizeFunction(
const IRPosition &IRP, Attributor &
A)
379 : AAUniformWorkGroupSize(IRP,
A) {}
383 CallingConv::ID CC =
F->getCallingConv();
385 if (CC != CallingConv::AMDGPU_KERNEL)
388 bool InitialValue =
F->hasFnAttribute(
"uniform-work-group-size");
391 indicateOptimisticFixpoint();
393 indicatePessimisticFixpoint();
399 auto CheckCallSite = [&](AbstractCallSite CS) {
402 <<
"->" << getAssociatedFunction()->
getName() <<
"\n");
404 const auto *CallerInfo =
A.getAAFor<AAUniformWorkGroupSize>(
406 if (!CallerInfo || !CallerInfo->isValidState())
410 CallerInfo->getState());
415 bool AllCallSitesKnown =
true;
416 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
417 return indicatePessimisticFixpoint();
424 return ChangeStatus::UNCHANGED;
426 LLVMContext &Ctx = getAssociatedFunction()->getContext();
427 return A.manifestAttrs(getIRPosition(),
428 {Attribute::get(Ctx,
"uniform-work-group-size")},
432 bool isValidState()
const override {
437 const std::string getAsStr(Attributor *)
const override {
438 return "AMDWorkGroupSize[" + std::to_string(getAssumed()) +
"]";
442 void trackStatistics()
const override {}
445AAUniformWorkGroupSize &
446AAUniformWorkGroupSize::createForPosition(
const IRPosition &IRP,
449 return *
new (
A.Allocator) AAUniformWorkGroupSizeFunction(IRP,
A);
451 "AAUniformWorkGroupSize is only valid for function position");
454struct AAAMDAttributesFunction :
public AAAMDAttributes {
455 AAAMDAttributesFunction(
const IRPosition &IRP, Attributor &
A)
456 : AAAMDAttributes(IRP,
A) {}
468 if (HasSanitizerAttrs) {
469 removeAssumedBits(IMPLICIT_ARG_PTR);
470 removeAssumedBits(HOSTCALL_PTR);
471 removeAssumedBits(FLAT_SCRATCH_INIT);
475 if (HasSanitizerAttrs &&
476 (Attr.first == IMPLICIT_ARG_PTR || Attr.first == HOSTCALL_PTR ||
477 Attr.first == FLAT_SCRATCH_INIT))
480 if (
F->hasFnAttribute(Attr.second))
481 addKnownBits(Attr.first);
484 if (
F->isDeclaration())
490 indicatePessimisticFixpoint();
498 auto OrigAssumed = getAssumed();
501 const AACallEdges *AAEdges =
A.getAAFor<AACallEdges>(
502 *
this, this->getIRPosition(), DepClassTy::REQUIRED);
505 return indicatePessimisticFixpoint();
509 bool NeedsImplicit =
false;
510 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
511 bool HasApertureRegs = InfoCache.hasApertureRegs(*
F);
512 bool SupportsGetDoorbellID = InfoCache.supportsGetDoorbellID(*
F);
513 unsigned COV = InfoCache.getCodeObjectVersion();
518 const AAAMDAttributes *AAAMD =
A.getAAFor<AAAMDAttributes>(
520 if (!AAAMD || !AAAMD->isValidState())
521 return indicatePessimisticFixpoint();
526 bool NonKernelOnly =
false;
529 HasApertureRegs, SupportsGetDoorbellID, COV);
540 if (!
Callee->hasFnAttribute(Attribute::NoCallback))
541 return indicatePessimisticFixpoint();
546 if ((IsNonEntryFunc || !NonKernelOnly))
547 removeAssumedBits(AttrMask);
553 removeAssumedBits(IMPLICIT_ARG_PTR);
555 if (isAssumed(QUEUE_PTR) && checkForQueuePtr(
A)) {
559 removeAssumedBits(IMPLICIT_ARG_PTR);
561 removeAssumedBits(QUEUE_PTR);
564 if (funcRetrievesMultigridSyncArg(
A, COV)) {
565 assert(!isAssumed(IMPLICIT_ARG_PTR) &&
566 "multigrid_sync_arg needs implicitarg_ptr");
567 removeAssumedBits(MULTIGRID_SYNC_ARG);
570 if (funcRetrievesHostcallPtr(
A, COV)) {
571 assert(!isAssumed(IMPLICIT_ARG_PTR) &&
"hostcall needs implicitarg_ptr");
572 removeAssumedBits(HOSTCALL_PTR);
575 if (funcRetrievesHeapPtr(
A, COV)) {
576 assert(!isAssumed(IMPLICIT_ARG_PTR) &&
"heap_ptr needs implicitarg_ptr");
577 removeAssumedBits(HEAP_PTR);
580 if (isAssumed(QUEUE_PTR) && funcRetrievesQueuePtr(
A, COV)) {
581 assert(!isAssumed(IMPLICIT_ARG_PTR) &&
"queue_ptr needs implicitarg_ptr");
582 removeAssumedBits(QUEUE_PTR);
585 if (isAssumed(LDS_KERNEL_ID) && funcRetrievesLDSKernelId(
A)) {
586 removeAssumedBits(LDS_KERNEL_ID);
589 if (isAssumed(DEFAULT_QUEUE) && funcRetrievesDefaultQueue(
A, COV))
590 removeAssumedBits(DEFAULT_QUEUE);
592 if (isAssumed(COMPLETION_ACTION) && funcRetrievesCompletionAction(
A, COV))
593 removeAssumedBits(COMPLETION_ACTION);
595 if (isAssumed(FLAT_SCRATCH_INIT) && needFlatScratchInit(
A))
596 removeAssumedBits(FLAT_SCRATCH_INIT);
598 return getAssumed() != OrigAssumed ? ChangeStatus::CHANGED
599 : ChangeStatus::UNCHANGED;
604 LLVMContext &Ctx = getAssociatedFunction()->getContext();
607 if (isKnown(Attr.first))
608 AttrList.
push_back(Attribute::get(Ctx, Attr.second));
611 return A.manifestAttrs(getIRPosition(), AttrList,
615 const std::string getAsStr(Attributor *)
const override {
617 raw_string_ostream OS(Str);
620 if (isAssumed(Attr.first))
621 OS <<
' ' << Attr.second;
627 void trackStatistics()
const override {}
630 bool checkForQueuePtr(Attributor &
A) {
634 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
636 bool NeedsQueuePtr =
false;
639 unsigned SrcAS =
static_cast<AddrSpaceCastInst &
>(
I).getSrcAddressSpace();
641 NeedsQueuePtr =
true;
647 bool HasApertureRegs = InfoCache.hasApertureRegs(*
F);
653 if (!HasApertureRegs) {
654 bool UsedAssumedInformation =
false;
655 A.checkForAllInstructions(CheckAddrSpaceCasts, *
this,
656 {Instruction::AddrSpaceCast},
657 UsedAssumedInformation);
664 if (!IsNonEntryFunc && HasApertureRegs)
667 for (BasicBlock &BB : *
F) {
668 for (Instruction &
I : BB) {
669 for (
const Use &U :
I.operands()) {
671 if (InfoCache.needsQueuePtr(
C, *
F))
681 bool funcRetrievesMultigridSyncArg(Attributor &
A,
unsigned COV) {
683 AA::RangeTy
Range(Pos, 8);
684 return funcRetrievesImplicitKernelArg(
A,
Range);
687 bool funcRetrievesHostcallPtr(Attributor &
A,
unsigned COV) {
689 AA::RangeTy
Range(Pos, 8);
690 return funcRetrievesImplicitKernelArg(
A,
Range);
693 bool funcRetrievesDefaultQueue(Attributor &
A,
unsigned COV) {
695 AA::RangeTy
Range(Pos, 8);
696 return funcRetrievesImplicitKernelArg(
A,
Range);
699 bool funcRetrievesCompletionAction(Attributor &
A,
unsigned COV) {
701 AA::RangeTy
Range(Pos, 8);
702 return funcRetrievesImplicitKernelArg(
A,
Range);
705 bool funcRetrievesHeapPtr(Attributor &
A,
unsigned COV) {
709 return funcRetrievesImplicitKernelArg(
A,
Range);
712 bool funcRetrievesQueuePtr(Attributor &
A,
unsigned COV) {
716 return funcRetrievesImplicitKernelArg(
A,
Range);
719 bool funcRetrievesImplicitKernelArg(Attributor &
A, AA::RangeTy
Range) {
731 const auto *PointerInfoAA =
A.getAAFor<AAPointerInfo>(
733 if (!PointerInfoAA || !PointerInfoAA->getState().isValidState())
736 return PointerInfoAA->forallInterferingAccesses(
737 Range, [](
const AAPointerInfo::Access &Acc,
bool IsExact) {
742 bool UsedAssumedInformation =
false;
743 return !
A.checkForAllCallLikeInstructions(DoesNotLeadToKernelArgLoc, *
this,
744 UsedAssumedInformation);
747 bool funcRetrievesLDSKernelId(Attributor &
A) {
752 bool UsedAssumedInformation =
false;
753 return !
A.checkForAllCallLikeInstructions(DoesNotRetrieve, *
this,
754 UsedAssumedInformation);
759 bool needFlatScratchInit(Attributor &
A) {
760 assert(isAssumed(FLAT_SCRATCH_INIT));
769 bool UsedAssumedInformation =
false;
770 if (!
A.checkForAllInstructions(AddrSpaceCastNotFromPrivate, *
this,
771 {Instruction::AddrSpaceCast},
772 UsedAssumedInformation))
776 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
780 for (
const Use &U :
I.operands()) {
782 if (InfoCache.checkConstForAddrSpaceCastFromPrivate(
C))
804 return Callee->getIntrinsicID() !=
805 Intrinsic::amdgcn_addrspacecast_nonnull;
808 UsedAssumedInformation =
false;
812 return !
A.checkForAllCallLikeInstructions(CheckForNoFlatScratchInit, *
this,
813 UsedAssumedInformation);
817AAAMDAttributes &AAAMDAttributes::createForPosition(
const IRPosition &IRP,
820 return *
new (
A.Allocator) AAAMDAttributesFunction(IRP,
A);
825struct AAAMDSizeRangeAttribute
826 :
public StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t> {
827 using Base = StateWrapper<IntegerRangeState, AbstractAttribute, uint32_t>;
831 AAAMDSizeRangeAttribute(
const IRPosition &IRP, Attributor &
A,
833 :
Base(IRP, 32), AttrName(AttrName) {}
836 void trackStatistics()
const override {}
838 template <
class AttributeImpl>
ChangeStatus updateImplImpl(Attributor &
A) {
841 auto CheckCallSite = [&](AbstractCallSite CS) {
844 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
846 const auto *CallerInfo =
A.getAAFor<AttributeImpl>(
848 if (!CallerInfo || !CallerInfo->isValidState())
857 bool AllCallSitesKnown =
true;
858 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
861 return indicatePessimisticFixpoint();
869 emitAttributeIfNotDefaultAfterClamp(Attributor &
A,
870 std::pair<unsigned, unsigned>
Default) {
872 unsigned Lower = getAssumed().getLower().getZExtValue();
873 unsigned Upper = getAssumed().getUpper().getZExtValue();
883 return ChangeStatus::UNCHANGED;
886 LLVMContext &Ctx =
F->getContext();
887 SmallString<10> Buffer;
888 raw_svector_ostream OS(Buffer);
890 return A.manifestAttrs(getIRPosition(),
891 {Attribute::get(Ctx, AttrName, OS.str())},
895 const std::string getAsStr(Attributor *)
const override {
897 raw_string_ostream OS(Str);
899 OS << getAssumed().getLower() <<
',' << getAssumed().getUpper() - 1;
906struct AAAMDFlatWorkGroupSize :
public AAAMDSizeRangeAttribute {
907 AAAMDFlatWorkGroupSize(
const IRPosition &IRP, Attributor &
A)
908 : AAAMDSizeRangeAttribute(IRP,
A,
"amdgpu-flat-work-group-size") {}
912 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
914 bool HasAttr =
false;
915 auto Range = InfoCache.getDefaultFlatWorkGroupSize(*
F);
916 auto MaxRange = InfoCache.getMaximumFlatWorkGroupRange(*
F);
918 if (
auto Attr = InfoCache.getFlatWorkGroupSizeAttr(*
F)) {
922 if (*Attr != MaxRange) {
930 if (
Range == MaxRange)
934 ConstantRange CR(APInt(32, Min), APInt(32, Max + 1));
935 IntegerRangeState IRS(CR);
939 indicateOptimisticFixpoint();
943 return updateImplImpl<AAAMDFlatWorkGroupSize>(
A);
947 static AAAMDFlatWorkGroupSize &createForPosition(
const IRPosition &IRP,
952 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
953 return emitAttributeIfNotDefaultAfterClamp(
954 A, InfoCache.getMaximumFlatWorkGroupRange(*
F));
958 StringRef
getName()
const override {
return "AAAMDFlatWorkGroupSize"; }
961 const char *getIdAddr()
const override {
return &
ID; }
965 static bool classof(
const AbstractAttribute *AA) {
970 static const char ID;
973const char AAAMDFlatWorkGroupSize::ID = 0;
975AAAMDFlatWorkGroupSize &
976AAAMDFlatWorkGroupSize::createForPosition(
const IRPosition &IRP,
979 return *
new (
A.Allocator) AAAMDFlatWorkGroupSize(IRP,
A);
981 "AAAMDFlatWorkGroupSize is only valid for function position");
984struct TupleDecIntegerRangeState :
public AbstractState {
985 DecIntegerState<uint32_t>
X,
Y, Z;
987 bool isValidState()
const override {
988 return X.isValidState() &&
Y.isValidState() &&
Z.isValidState();
991 bool isAtFixpoint()
const override {
992 return X.isAtFixpoint() &&
Y.isAtFixpoint() &&
Z.isAtFixpoint();
996 return X.indicateOptimisticFixpoint() |
Y.indicateOptimisticFixpoint() |
997 Z.indicateOptimisticFixpoint();
1001 return X.indicatePessimisticFixpoint() |
Y.indicatePessimisticFixpoint() |
1002 Z.indicatePessimisticFixpoint();
1005 TupleDecIntegerRangeState
operator^=(
const TupleDecIntegerRangeState &
Other) {
1016 TupleDecIntegerRangeState &getAssumed() {
return *
this; }
1017 const TupleDecIntegerRangeState &getAssumed()
const {
return *
this; }
1020using AAAMDMaxNumWorkgroupsState =
1021 StateWrapper<TupleDecIntegerRangeState, AbstractAttribute, uint32_t>;
1024struct AAAMDMaxNumWorkgroups
1025 :
public StateWrapper<TupleDecIntegerRangeState, AbstractAttribute> {
1026 using Base = StateWrapper<TupleDecIntegerRangeState, AbstractAttribute>;
1028 AAAMDMaxNumWorkgroups(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
1032 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
1034 SmallVector<unsigned> MaxNumWorkgroups = InfoCache.getMaxNumWorkGroups(*
F);
1036 X.takeKnownMinimum(MaxNumWorkgroups[0]);
1037 Y.takeKnownMinimum(MaxNumWorkgroups[1]);
1038 Z.takeKnownMinimum(MaxNumWorkgroups[2]);
1041 indicatePessimisticFixpoint();
1047 auto CheckCallSite = [&](AbstractCallSite CS) {
1050 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
1052 const auto *CallerInfo =
A.getAAFor<AAAMDMaxNumWorkgroups>(
1054 if (!CallerInfo || !CallerInfo->isValidState())
1062 bool AllCallSitesKnown =
true;
1063 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
1066 return indicatePessimisticFixpoint();
1072 static AAAMDMaxNumWorkgroups &createForPosition(
const IRPosition &IRP,
1077 LLVMContext &Ctx =
F->getContext();
1078 SmallString<32> Buffer;
1079 raw_svector_ostream OS(Buffer);
1080 OS <<
X.getAssumed() <<
',' <<
Y.getAssumed() <<
',' <<
Z.getAssumed();
1084 return A.manifestAttrs(
1086 {Attribute::get(Ctx,
"amdgpu-max-num-workgroups", OS.str())},
1090 StringRef
getName()
const override {
return "AAAMDMaxNumWorkgroups"; }
1092 const std::string getAsStr(Attributor *)
const override {
1093 std::string Buffer =
"AAAMDMaxNumWorkgroupsState[";
1094 raw_string_ostream OS(Buffer);
1095 OS <<
X.getAssumed() <<
',' <<
Y.getAssumed() <<
',' <<
Z.getAssumed()
1100 const char *getIdAddr()
const override {
return &
ID; }
1104 static bool classof(
const AbstractAttribute *AA) {
1108 void trackStatistics()
const override {}
1111 static const char ID;
1114const char AAAMDMaxNumWorkgroups::ID = 0;
1116AAAMDMaxNumWorkgroups &
1117AAAMDMaxNumWorkgroups::createForPosition(
const IRPosition &IRP, Attributor &
A) {
1119 return *
new (
A.Allocator) AAAMDMaxNumWorkgroups(IRP,
A);
1120 llvm_unreachable(
"AAAMDMaxNumWorkgroups is only valid for function position");
1124struct AAAMDWavesPerEU :
public AAAMDSizeRangeAttribute {
1125 AAAMDWavesPerEU(
const IRPosition &IRP, Attributor &
A)
1126 : AAAMDSizeRangeAttribute(IRP,
A,
"amdgpu-waves-per-eu") {}
1130 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
1133 if (
auto Attr = InfoCache.getWavesPerEUAttr(*
F)) {
1134 std::pair<unsigned, unsigned> MaxWavesPerEURange{
1135 1U, InfoCache.getMaxWavesPerEU(*
F)};
1136 if (*Attr != MaxWavesPerEURange) {
1137 auto [Min,
Max] = *Attr;
1138 ConstantRange
Range(APInt(32, Min), APInt(32, Max + 1));
1139 IntegerRangeState RangeState(
Range);
1140 this->getState() = RangeState;
1141 indicateOptimisticFixpoint();
1147 indicatePessimisticFixpoint();
1153 auto CheckCallSite = [&](AbstractCallSite CS) {
1157 <<
"->" <<
Func->getName() <<
'\n');
1160 const auto *CallerAA =
A.getAAFor<AAAMDWavesPerEU>(
1162 if (!CallerAA || !CallerAA->isValidState())
1165 ConstantRange Assumed = getAssumed();
1167 CallerAA->getAssumed().getLower().getZExtValue());
1169 CallerAA->getAssumed().getUpper().getZExtValue());
1170 ConstantRange
Range(APInt(32, Min), APInt(32, Max));
1171 IntegerRangeState RangeState(
Range);
1172 getState() = RangeState;
1173 Change |= getState() == Assumed ? ChangeStatus::UNCHANGED
1174 : ChangeStatus::CHANGED;
1179 bool AllCallSitesKnown =
true;
1180 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
1181 return indicatePessimisticFixpoint();
1187 static AAAMDWavesPerEU &createForPosition(
const IRPosition &IRP,
1192 auto &InfoCache =
static_cast<AMDGPUInformationCache &
>(
A.getInfoCache());
1193 return emitAttributeIfNotDefaultAfterClamp(
1194 A, {1U, InfoCache.getMaxWavesPerEU(*
F)});
1198 StringRef
getName()
const override {
return "AAAMDWavesPerEU"; }
1201 const char *getIdAddr()
const override {
return &
ID; }
1205 static bool classof(
const AbstractAttribute *AA) {
1210 static const char ID;
1213const char AAAMDWavesPerEU::ID = 0;
1215AAAMDWavesPerEU &AAAMDWavesPerEU::createForPosition(
const IRPosition &IRP,
1218 return *
new (
A.Allocator) AAAMDWavesPerEU(IRP,
A);
1223static unsigned inlineAsmGetNumRequiredAGPRs(
const InlineAsm *IA,
1224 const CallBase &
Call) {
1227 unsigned AGPRDefCount = 0;
1228 unsigned AGPRUseCount = 0;
1229 unsigned MaxPhysReg = 0;
1233 for (
const InlineAsm::ConstraintInfo &CI :
IA->ParseConstraints()) {
1239 Ty = STy->getElementType(ResNo);
1254 for (StringRef Code : CI.Codes) {
1255 unsigned RegCount = 0;
1256 if (
Code.starts_with(
"a")) {
1267 MaxPhysReg = std::max(MaxPhysReg, std::min(RegIdx + NumRegs, 256u));
1277 AGPRDefCount =
alignTo(AGPRDefCount, RegCount);
1279 AGPRDefCount += RegCount;
1280 if (CI.isEarlyClobber) {
1281 AGPRUseCount =
alignTo(AGPRUseCount, RegCount);
1282 AGPRUseCount += RegCount;
1285 AGPRUseCount =
alignTo(AGPRUseCount, RegCount);
1286 AGPRUseCount += RegCount;
1291 unsigned MaxVirtReg = std::max(AGPRUseCount, AGPRDefCount);
1296 return std::min(MaxVirtReg + MaxPhysReg, 256u);
1299struct AAAMDGPUMinAGPRAlloc
1300 :
public StateWrapper<DecIntegerState<>, AbstractAttribute> {
1301 using Base = StateWrapper<DecIntegerState<>, AbstractAttribute>;
1302 AAAMDGPUMinAGPRAlloc(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
1304 static AAAMDGPUMinAGPRAlloc &createForPosition(
const IRPosition &IRP,
1307 return *
new (
A.Allocator) AAAMDGPUMinAGPRAlloc(IRP,
A);
1309 "AAAMDGPUMinAGPRAlloc is only valid for function position");
1314 auto [MinNumAGPR, MaxNumAGPR] =
1317 if (MinNumAGPR == 0)
1318 indicateOptimisticFixpoint();
1321 const std::string getAsStr(Attributor *
A)
const override {
1322 std::string Str =
"amdgpu-agpr-alloc=";
1323 raw_string_ostream OS(Str);
1328 void trackStatistics()
const override {}
1331 DecIntegerState<> Maximum;
1338 const Value *CalleeOp = CB.getCalledOperand();
1343 unsigned NumRegs = inlineAsmGetNumRequiredAGPRs(IA, CB);
1347 switch (CB.getIntrinsicID()) {
1350 case Intrinsic::write_register:
1351 case Intrinsic::read_register:
1352 case Intrinsic::read_volatile_register: {
1357 auto [
Kind, RegIdx, NumRegs] =
1371 case Intrinsic::trap:
1372 case Intrinsic::debugtrap:
1373 case Intrinsic::ubsantrap:
1374 return CB.hasFnAttr(Attribute::NoCallback) ||
1375 !CB.hasFnAttr(
"trap-func-name");
1381 return CB.hasFnAttr(Attribute::NoCallback);
1385 auto *CBEdges =
A.getAAFor<AACallEdges>(
1387 if (!CBEdges || CBEdges->hasUnknownCallee()) {
1392 for (
const Function *PossibleCallee : CBEdges->getOptimisticEdges()) {
1393 const auto *CalleeInfo =
A.getAAFor<AAAMDGPUMinAGPRAlloc>(
1395 if (!CalleeInfo || !CalleeInfo->isValidState()) {
1406 bool UsedAssumedInformation =
false;
1407 if (!
A.checkForAllCallLikeInstructions(CheckForMinAGPRAllocs, *
this,
1408 UsedAssumedInformation))
1409 return indicatePessimisticFixpoint();
1415 LLVMContext &Ctx = getAssociatedFunction()->getContext();
1416 SmallString<4> Buffer;
1417 raw_svector_ostream OS(Buffer);
1420 return A.manifestAttrs(
1421 getIRPosition(), {Attribute::get(Ctx,
"amdgpu-agpr-alloc", OS.str())});
1424 StringRef
getName()
const override {
return "AAAMDGPUMinAGPRAlloc"; }
1425 const char *getIdAddr()
const override {
return &
ID; }
1429 static bool classof(
const AbstractAttribute *AA) {
1433 static const char ID;
1436const char AAAMDGPUMinAGPRAlloc::ID = 0;
1440struct AAAMDGPUClusterDims
1441 :
public StateWrapper<BooleanState, AbstractAttribute> {
1442 using Base = StateWrapper<BooleanState, AbstractAttribute>;
1443 AAAMDGPUClusterDims(
const IRPosition &IRP, Attributor &
A) :
Base(IRP) {}
1446 static AAAMDGPUClusterDims &createForPosition(
const IRPosition &IRP,
1450 StringRef
getName()
const override {
return "AAAMDGPUClusterDims"; }
1453 const char *getIdAddr()
const override {
return &
ID; }
1457 static bool classof(
const AbstractAttribute *AA) {
1461 virtual const AMDGPU::ClusterDimsAttr &getClusterDims()
const = 0;
1464 static const char ID;
1467const char AAAMDGPUClusterDims::ID = 0;
1469struct AAAMDGPUClusterDimsFunction :
public AAAMDGPUClusterDims {
1470 AAAMDGPUClusterDimsFunction(
const IRPosition &IRP, Attributor &
A)
1471 : AAAMDGPUClusterDims(IRP,
A) {}
1475 assert(
F &&
"empty associated function");
1482 indicatePessimisticFixpoint();
1484 indicateOptimisticFixpoint();
1488 const std::string getAsStr(Attributor *
A)
const override {
1498 void trackStatistics()
const override {}
1501 auto OldState = Attr;
1503 auto CheckCallSite = [&](AbstractCallSite CS) {
1504 const auto *CallerAA =
A.getAAFor<AAAMDGPUClusterDims>(
1506 DepClassTy::REQUIRED);
1507 if (!CallerAA || !CallerAA->isValidState())
1510 return merge(CallerAA->getClusterDims());
1513 bool UsedAssumedInformation =
false;
1514 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
1516 UsedAssumedInformation))
1517 return indicatePessimisticFixpoint();
1519 return OldState == Attr ? ChangeStatus::UNCHANGED : ChangeStatus::CHANGED;
1524 return ChangeStatus::UNCHANGED;
1525 return A.manifestAttrs(
1527 {Attribute::get(getAssociatedFunction()->
getContext(), AttrName,
1532 const AMDGPU::ClusterDimsAttr &getClusterDims()
const override {
1537 bool merge(
const AMDGPU::ClusterDimsAttr &
Other) {
1552 if (
Other.isUnknown())
1577 AMDGPU::ClusterDimsAttr Attr;
1579 static constexpr char AttrName[] =
"amdgpu-cluster-dims";
1582AAAMDGPUClusterDims &
1583AAAMDGPUClusterDims::createForPosition(
const IRPosition &IRP, Attributor &
A) {
1585 return *
new (
A.Allocator) AAAMDGPUClusterDimsFunction(IRP,
A);
1586 llvm_unreachable(
"AAAMDGPUClusterDims is only valid for function position");
1589static bool runImpl(SetVector<Function *> &Functions,
bool IsModulePass,
1590 bool DeleteFns,
Module &M, AnalysisGetter &AG,
1591 TargetMachine &TM, AMDGPUAttributorOptions
Options,
1594 CallGraphUpdater CGUpdater;
1596 AMDGPUInformationCache InfoCache(M, AG,
Allocator,
nullptr, TM);
1597 DenseSet<const char *>
Allowed(
1598 {&AAAMDAttributes::ID, &AAUniformWorkGroupSize::ID,
1600 &AAAMDMaxNumWorkgroups::ID, &AAAMDWavesPerEU::ID,
1606 AttributorConfig AC(CGUpdater);
1607 AC.IsClosedWorldModule =
Options.IsClosedWorld;
1609 AC.IsModulePass = IsModulePass;
1610 AC.DeleteFns = DeleteFns;
1611 AC.DefaultInitializeLiveInternals =
false;
1612 AC.IndirectCalleeSpecializationCallback =
1613 [](Attributor &
A,
const AbstractAttribute &AA, CallBase &CB,
1618 AC.IPOAmendableCB = [](
const Function &
F) {
1619 return F.getCallingConv() == CallingConv::AMDGPU_KERNEL;
1622 Attributor
A(Functions, InfoCache, AC);
1625 StringRef LTOPhaseStr =
to_string(LTOPhase);
1626 dbgs() <<
"[AMDGPUAttributor] Running at phase " << LTOPhaseStr <<
'\n'
1627 <<
"[AMDGPUAttributor] Module " <<
M.getName() <<
" is "
1628 << (AC.IsClosedWorldModule ?
"" :
"not ")
1629 <<
"assumed to be a closed world.\n";
1632 for (
auto *
F : Functions) {
1636 CallingConv::ID CC =
F->getCallingConv();
1643 if (!
F->isDeclaration() &&
ST.hasClusters())
1646 if (
ST.hasGFX90AInsts())
1650 Value *Ptr =
nullptr;
1652 Ptr = LI->getPointerOperand();
1654 Ptr =
SI->getPointerOperand();
1656 Ptr = RMW->getPointerOperand();
1658 Ptr = CmpX->getPointerOperand();
1664 if (
II->getIntrinsicID() == Intrinsic::amdgcn_make_buffer_rsrc)
1671 return A.run() == ChangeStatus::CHANGED;
1684 if (!
F.isDeclaration())
1685 Functions.insert(&
F);
1689 return runImpl(Functions,
true,
true, M, AG,
1690 TM, Options, LTOPhase)
1707 if (!
F->isIntrinsic())
1708 Functions.insert(
F);
1712 Module *M =
C.begin()->getFunction().getParent();
1715 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< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static bool runImpl(Function &F, const TargetLowering &TLI, const LibcallLoweringInfo &Libcalls, AssumptionCache *AC)
AMD GCN specific subclass of TargetSubtarget.
static LoopDeletionResult merge(LoopDeletionResult A, LoopDeletionResult B)
Machine Check Debug Module
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
static StringRef getName(Value *V)
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.
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.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
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.
unsigned getMaxWavesPerEU(const MCSubtargetInfo *STI)
unsigned getAMDHSACodeObjectVersion(const Module &M)
unsigned getDefaultQueueImplicitArgPosition(unsigned CodeObjectVersion)
std::tuple< char, unsigned, unsigned > parseAsmPhysRegName(StringRef RegName)
Returns a valid charcode or 0 in the first entry if this is a valid physical register name.
LLVM_READNONE constexpr bool isEntryFunctionCC(CallingConv::ID CC)
std::tuple< char, unsigned, unsigned > parseAsmConstraintPhysReg(StringRef Constraint)
Returns a valid charcode or 0 in the first entry if this is a valid physical register constraint.
unsigned getHostcallImplicitArgPosition(unsigned CodeObjectVersion)
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)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
NodeAddr< CodeNode * > Code
NodeAddr< FuncNode * > Func
Context & getContext() const
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
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)
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.