54#include "llvm/IR/IntrinsicsAMDGPU.h"
55#include "llvm/IR/IntrinsicsNVPTX.h"
82#define DEBUG_TYPE "attributor"
86 cl::desc(
"Manifest Attributor internal string attributes."),
99 cl::desc(
"Maximum number of potential values to be "
100 "tracked for each position."),
105 "attributor-max-potential-values-iterations",
cl::Hidden,
107 "Maximum number of iterations we keep dismantling potential values."),
110STATISTIC(NumAAs,
"Number of abstract attributes created");
111STATISTIC(NumIndirectCallsPromoted,
"Number of indirect calls promoted");
126#define BUILD_STAT_MSG_IR_ATTR(TYPE, NAME) \
127 ("Number of " #TYPE " marked '" #NAME "'")
128#define BUILD_STAT_NAME(NAME, TYPE) NumIR##TYPE##_##NAME
129#define STATS_DECL_(NAME, MSG) STATISTIC(NAME, MSG);
130#define STATS_DECL(NAME, TYPE, MSG) \
131 STATS_DECL_(BUILD_STAT_NAME(NAME, TYPE), MSG);
132#define STATS_TRACK(NAME, TYPE) ++(BUILD_STAT_NAME(NAME, TYPE));
133#define STATS_DECLTRACK(NAME, TYPE, MSG) \
134 {STATS_DECL(NAME, TYPE, MSG) STATS_TRACK(NAME, TYPE)}
135#define STATS_DECLTRACK_ARG_ATTR(NAME) \
136 STATS_DECLTRACK(NAME, Arguments, BUILD_STAT_MSG_IR_ATTR(arguments, NAME))
137#define STATS_DECLTRACK_CSARG_ATTR(NAME) \
138 STATS_DECLTRACK(NAME, CSArguments, \
139 BUILD_STAT_MSG_IR_ATTR(call site arguments, NAME))
140#define STATS_DECLTRACK_FN_ATTR(NAME) \
141 STATS_DECLTRACK(NAME, Function, BUILD_STAT_MSG_IR_ATTR(functions, NAME))
142#define STATS_DECLTRACK_CS_ATTR(NAME) \
143 STATS_DECLTRACK(NAME, CS, BUILD_STAT_MSG_IR_ATTR(call site, NAME))
144#define STATS_DECLTRACK_FNRET_ATTR(NAME) \
145 STATS_DECLTRACK(NAME, FunctionReturn, \
146 BUILD_STAT_MSG_IR_ATTR(function returns, NAME))
147#define STATS_DECLTRACK_CSRET_ATTR(NAME) \
148 STATS_DECLTRACK(NAME, CSReturn, \
149 BUILD_STAT_MSG_IR_ATTR(call site returns, NAME))
150#define STATS_DECLTRACK_FLOATING_ATTR(NAME) \
151 STATS_DECLTRACK(NAME, Floating, \
152 ("Number of floating values known to be '" #NAME "'"))
157#define PIPE_OPERATOR(CLASS) \
158 raw_ostream &operator<<(raw_ostream &OS, const CLASS &AA) { \
159 return OS << static_cast<const AbstractAttribute &>(AA); \
216 bool HeaderOnly,
Cycle **CPtr =
nullptr) {
219 auto *BB =
I->getParent();
225 return !HeaderOnly || BB ==
C->getHeader();
236 if (
DL.getTypeSizeInBits(Ty) !=
DL.getTypeAllocSizeInBits(Ty))
261 StartPos +=
DL.getTypeAllocSizeInBits(ElTy);
271 bool AllowVolatile) {
272 if (!AllowVolatile &&
I->isVolatile())
276 return LI->getPointerOperand();
280 return SI->getPointerOperand();
284 return CXI->getPointerOperand();
288 return RMWI->getPointerOperand();
310 bool GetMinOffset,
bool AllowNonInbounds,
311 bool UseAssumed =
false) {
313 auto AttributorAnalysis = [&](
Value &V,
APInt &ROffset) ->
bool {
320 if (!ValueConstantRangeAA)
324 if (
Range.isFullSet())
330 ROffset =
Range.getSignedMin();
332 ROffset =
Range.getSignedMax();
343 const Value *Ptr, int64_t &BytesOffset,
348 true, AllowNonInbounds);
356template <
typename AAType,
typename StateType =
typename AAType::StateType,
358 bool RecurseForSelectAndPHI =
true>
360 Attributor &
A,
const AAType &QueryingAA, StateType &S,
362 LLVM_DEBUG(
dbgs() <<
"[Attributor] Clamp return value states for "
363 << QueryingAA <<
" into " << S <<
"\n");
365 assert((QueryingAA.getIRPosition().getPositionKind() ==
367 QueryingAA.getIRPosition().getPositionKind() ==
369 "Can only clamp returned value states for a function returned or call "
370 "site returned position!");
374 std::optional<StateType>
T;
377 auto CheckReturnValue = [&](
Value &RV) ->
bool {
391 <<
" AA: " <<
AA->getAsStr(&
A) <<
" @ " << RVPos <<
"\n");
392 const StateType &AAS =
AA->getState();
394 T = StateType::getBestState(AAS);
396 LLVM_DEBUG(
dbgs() <<
"[Attributor] AA State: " << AAS <<
" RV State: " <<
T
398 return T->isValidState();
401 if (!
A.checkForAllReturnedValues(CheckReturnValue, QueryingAA,
403 RecurseForSelectAndPHI))
404 S.indicatePessimisticFixpoint();
411template <
typename AAType,
typename BaseType,
412 typename StateType =
typename BaseType::StateType,
413 bool PropagateCallBaseContext =
false,
415 bool RecurseForSelectAndPHI =
true>
416struct AAReturnedFromReturnedValues :
public BaseType {
417 AAReturnedFromReturnedValues(
const IRPosition &IRP, Attributor &
A)
422 StateType S(StateType::getBestState(this->getState()));
424 RecurseForSelectAndPHI>(
426 PropagateCallBaseContext ? this->getCallBaseContext() : nullptr);
435template <
typename AAType,
typename StateType =
typename AAType::StateType,
437static void clampCallSiteArgumentStates(
Attributor &
A,
const AAType &QueryingAA,
439 LLVM_DEBUG(
dbgs() <<
"[Attributor] Clamp call site argument states for "
440 << QueryingAA <<
" into " << S <<
"\n");
442 assert(QueryingAA.getIRPosition().getPositionKind() ==
444 "Can only clamp call site argument states for an argument position!");
448 std::optional<StateType>
T;
451 unsigned ArgNo = QueryingAA.getIRPosition().getCallSiteArgNo();
471 LLVM_DEBUG(
dbgs() <<
"[Attributor] ACS: " << *ACS.getInstruction()
472 <<
" AA: " <<
AA->getAsStr(&
A) <<
" @" << ACSArgPos
474 const StateType &AAS =
AA->getState();
476 T = StateType::getBestState(AAS);
478 LLVM_DEBUG(
dbgs() <<
"[Attributor] AA State: " << AAS <<
" CSA State: " <<
T
480 return T->isValidState();
483 bool UsedAssumedInformation =
false;
484 if (!
A.checkForAllCallSites(CallSiteCheck, QueryingAA,
true,
485 UsedAssumedInformation))
486 S.indicatePessimisticFixpoint();
493template <
typename AAType,
typename BaseType,
494 typename StateType =
typename AAType::StateType,
496bool getArgumentStateFromCallBaseContext(
Attributor &
A,
500 "Expected an 'argument' position !");
506 assert(ArgNo >= 0 &&
"Invalid Arg No!");
520 const StateType &CBArgumentState =
521 static_cast<const StateType &
>(
AA->getState());
523 LLVM_DEBUG(
dbgs() <<
"[Attributor] Briding Call site context to argument"
524 <<
"Position:" << Pos <<
"CB Arg state:" << CBArgumentState
528 State ^= CBArgumentState;
533template <
typename AAType,
typename BaseType,
534 typename StateType =
typename AAType::StateType,
535 bool BridgeCallBaseContext =
false,
537struct AAArgumentFromCallSiteArguments :
public BaseType {
538 AAArgumentFromCallSiteArguments(
const IRPosition &IRP, Attributor &
A)
543 StateType S = StateType::getBestState(this->getState());
545 if (BridgeCallBaseContext) {
547 getArgumentStateFromCallBaseContext<AAType,
BaseType, StateType,
549 A, *
this, this->getIRPosition(), S);
553 clampCallSiteArgumentStates<AAType, StateType, IRAttributeKind>(
A, *
this,
563template <
typename AAType,
typename BaseType,
564 typename StateType =
typename BaseType::StateType,
565 bool IntroduceCallBaseContext =
false,
567struct AACalleeToCallSite :
public BaseType {
568 AACalleeToCallSite(
const IRPosition &IRP, Attributor &
A) :
BaseType(IRP,
A) {}
572 auto IRPKind = this->getIRPosition().getPositionKind();
575 "Can only wrap function returned positions for call site "
576 "returned positions!");
577 auto &S = this->getState();
580 if (IntroduceCallBaseContext)
581 LLVM_DEBUG(
dbgs() <<
"[Attributor] Introducing call base context:" << CB
586 for (
const Function *Callee : Callees) {
590 IntroduceCallBaseContext ? &CB :
nullptr)
592 *
Callee, IntroduceCallBaseContext ? &CB : nullptr);
594 if (Attribute::isEnumAttrKind(IRAttributeKind)) {
597 A,
this, FnPos, DepClassTy::REQUIRED, IsKnown))
603 A.getAAFor<AAType>(*
this, FnPos, DepClassTy::REQUIRED);
607 if (S.isAtFixpoint())
608 return S.isValidState();
612 if (!
A.checkForAllCallees(CalleePred, *
this, CB))
613 return S.indicatePessimisticFixpoint();
619template <
class AAType,
typename StateType =
typename AAType::StateType>
625 auto EIt = Explorer.
begin(CtxI), EEnd = Explorer.
end(CtxI);
626 for (
unsigned u = 0;
u <
Uses.size(); ++
u) {
630 if (Found &&
AA.followUseInMBEC(
A, U, UserI, State))
645template <
class AAType,
typename StateType =
typename AAType::StateType>
646static void followUsesInMBEC(AAType &
AA,
Attributor &
A, StateType &S,
648 const Value &Val =
AA.getIRPosition().getAssociatedValue();
653 A.getInfoCache().getMustBeExecutedContextExplorer();
659 for (
const Use &U : Val.
uses())
662 followUsesInContext<AAType>(
AA,
A, *Explorer, &CtxI,
Uses, S);
664 if (S.isAtFixpoint())
708 StateType ParentState;
712 ParentState.indicateOptimisticFixpoint();
714 for (
const BasicBlock *BB : Br->successors()) {
715 StateType ChildState;
717 size_t BeforeSize =
Uses.size();
718 followUsesInContext(
AA,
A, *Explorer, &BB->front(),
Uses, ChildState);
721 for (
auto It =
Uses.begin() + BeforeSize; It !=
Uses.end();)
724 ParentState &= ChildState;
798 R.indicatePessimisticFixpoint();
815 BS.indicateOptimisticFixpoint();
821 BS.indicatePessimisticFixpoint();
891 template <
typename F>
898 if (!
Range.mayOverlap(ItRange))
900 bool IsExact =
Range == ItRange && !
Range.offsetOrSizeAreUnknown();
901 for (
auto Index : It.getSecond()) {
911 template <
typename F>
922 for (
unsigned Index : LocalList->getSecond()) {
925 if (
Range.offsetAndSizeAreUnknown())
941 RemoteI = RemoteI ? RemoteI : &
I;
945 bool AccExists =
false;
947 for (
auto Index : LocalList) {
949 if (
A.getLocalInst() == &
I) {
958 <<
"[AAPointerInfo] Inserting access in new offset bins\n";);
960 for (
auto Key : ToAdd) {
967 AccessList.emplace_back(&
I, RemoteI, Ranges, Content, Kind, Ty);
969 "New Access should have been at AccIndex");
970 LocalList.push_back(AccIndex);
979 auto Before = Current;
981 if (Current == Before)
984 auto &ExistingRanges = Before.getRanges();
985 auto &NewRanges = Current.getRanges();
992 <<
"[AAPointerInfo] Removing access from old offset bins\n";);
999 "Expected bin to actually contain the Access.");
1000 Bin.erase(AccIndex);
1021struct AAPointerInfoImpl
1022 :
public StateWrapper<AA::PointerInfo::State, AAPointerInfo> {
1027 const std::string getAsStr(
Attributor *
A)
const override {
1028 return std::string(
"PointerInfo ") +
1029 (isValidState() ? (std::string(
"#") +
1030 std::to_string(OffsetBins.size()) +
" bins")
1035 [](int64_t O) {
return std::to_string(O); }),
1043 return AAPointerInfo::manifest(
A);
1046 const_bin_iterator
begin()
const override {
return State::begin(); }
1047 const_bin_iterator
end()
const override {
return State::end(); }
1048 int64_t numOffsetBins()
const override {
return State::numOffsetBins(); }
1049 bool reachesReturn()
const override {
1050 return !ReturnedOffsets.isUnassigned();
1052 void addReturnedOffsetsTo(OffsetInfo &OI)
const override {
1053 if (ReturnedOffsets.isUnknown()) {
1058 OffsetInfo MergedOI;
1059 for (
auto Offset : ReturnedOffsets) {
1060 OffsetInfo TmpOI = OI;
1062 MergedOI.merge(TmpOI);
1064 OI = std::move(MergedOI);
1067 ChangeStatus setReachesReturn(
const OffsetInfo &ReachedReturnedOffsets) {
1068 if (ReturnedOffsets.isUnknown())
1069 return ChangeStatus::UNCHANGED;
1070 if (ReachedReturnedOffsets.isUnknown()) {
1071 ReturnedOffsets.setUnknown();
1072 return ChangeStatus::CHANGED;
1074 if (ReturnedOffsets.merge(ReachedReturnedOffsets))
1075 return ChangeStatus::CHANGED;
1076 return ChangeStatus::UNCHANGED;
1079 bool forallInterferingAccesses(
1081 function_ref<
bool(
const AAPointerInfo::Access &,
bool)> CB)
1083 return State::forallInterferingAccesses(
Range, CB);
1086 bool forallInterferingAccesses(
1087 Attributor &
A,
const AbstractAttribute &QueryingAA, Instruction &
I,
1088 bool FindInterferingWrites,
bool FindInterferingReads,
1089 function_ref<
bool(
const Access &,
bool)> UserCB,
bool &HasBeenWrittenTo,
1091 function_ref<
bool(
const Access &)> SkipCB)
const override {
1092 HasBeenWrittenTo =
false;
1094 SmallPtrSet<const Access *, 8> DominatingWrites;
1102 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
1104 bool AllInSameNoSyncFn = IsAssumedNoSync;
1105 bool InstIsExecutedByInitialThreadOnly =
1106 ExecDomainAA && ExecDomainAA->isExecutedByInitialThreadOnly(
I);
1113 bool InstIsExecutedInAlignedRegion =
1114 FindInterferingReads && ExecDomainAA &&
1115 ExecDomainAA->isExecutedInAlignedRegion(
A,
I);
1117 if (InstIsExecutedInAlignedRegion || InstIsExecutedByInitialThreadOnly)
1118 A.recordDependence(*ExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1120 InformationCache &InfoCache =
A.getInfoCache();
1121 bool IsThreadLocalObj =
1130 auto CanIgnoreThreadingForInst = [&](
const Instruction &
I) ->
bool {
1131 if (IsThreadLocalObj || AllInSameNoSyncFn)
1133 const auto *FnExecDomainAA =
1134 I.getFunction() == &
Scope
1136 :
A.lookupAAFor<AAExecutionDomain>(
1139 if (!FnExecDomainAA)
1141 if (InstIsExecutedInAlignedRegion ||
1142 (FindInterferingWrites &&
1143 FnExecDomainAA->isExecutedInAlignedRegion(
A,
I))) {
1144 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1147 if (InstIsExecutedByInitialThreadOnly &&
1148 FnExecDomainAA->isExecutedByInitialThreadOnly(
I)) {
1149 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1158 auto CanIgnoreThreading = [&](
const Access &Acc) ->
bool {
1159 return CanIgnoreThreadingForInst(*Acc.getRemoteInst()) ||
1160 (Acc.getRemoteInst() != Acc.getLocalInst() &&
1161 CanIgnoreThreadingForInst(*Acc.getLocalInst()));
1165 bool IsKnownNoRecurse;
1173 bool InstInKernel =
A.getInfoCache().isKernel(Scope);
1174 bool ObjHasKernelLifetime =
false;
1175 const bool UseDominanceReasoning =
1176 FindInterferingWrites && IsKnownNoRecurse;
1177 const DominatorTree *DT =
1186 unsigned VAS =
V->getType()->getPointerAddressSpace();
1197 std::function<bool(
const Function &)> IsLiveInCalleeCB;
1202 const Function *AIFn = AI->getFunction();
1203 ObjHasKernelLifetime =
A.getInfoCache().isKernel(*AIFn);
1204 bool IsKnownNoRecurse;
1207 IsKnownNoRecurse)) {
1208 IsLiveInCalleeCB = [AIFn](
const Function &Fn) {
return AIFn != &Fn; };
1213 ObjHasKernelLifetime = HasKernelLifetime(GV, *GV->getParent());
1214 if (ObjHasKernelLifetime)
1215 IsLiveInCalleeCB = [&
A](
const Function &Fn) {
1216 return !
A.getInfoCache().isKernel(Fn);
1224 auto AccessCB = [&](
const Access &Acc,
bool Exact) {
1225 Function *AccScope = Acc.getRemoteInst()->getFunction();
1226 bool AccInSameScope = AccScope == &
Scope;
1230 if (InstInKernel && ObjHasKernelLifetime && !AccInSameScope &&
1231 A.getInfoCache().isKernel(*AccScope))
1234 if (Exact && Acc.isMustAccess() && Acc.getRemoteInst() != &
I) {
1235 if (Acc.isWrite() || (
isa<LoadInst>(
I) && Acc.isWriteOrAssumption()))
1236 ExclusionSet.
insert(Acc.getRemoteInst());
1239 if ((!FindInterferingWrites || !Acc.isWriteOrAssumption()) &&
1240 (!FindInterferingReads || !Acc.isRead()))
1243 bool Dominates = FindInterferingWrites && DT && Exact &&
1244 Acc.isMustAccess() && AccInSameScope &&
1247 DominatingWrites.
insert(&Acc);
1251 AllInSameNoSyncFn &= Acc.getRemoteInst()->getFunction() == &
Scope;
1253 InterferingAccesses.
push_back({&Acc, Exact});
1256 if (!State::forallInterferingAccesses(
I, AccessCB,
Range))
1259 HasBeenWrittenTo = !DominatingWrites.
empty();
1263 for (
const Access *Acc : DominatingWrites) {
1264 if (!LeastDominatingWriteInst) {
1265 LeastDominatingWriteInst = Acc->getRemoteInst();
1266 }
else if (DT->
dominates(LeastDominatingWriteInst,
1267 Acc->getRemoteInst())) {
1268 LeastDominatingWriteInst = Acc->getRemoteInst();
1273 auto CanSkipAccess = [&](
const Access &Acc,
bool Exact) {
1274 if (SkipCB && SkipCB(Acc))
1276 if (!CanIgnoreThreading(Acc))
1282 bool ReadChecked = !FindInterferingReads;
1283 bool WriteChecked = !FindInterferingWrites;
1289 &ExclusionSet, IsLiveInCalleeCB))
1294 if (!WriteChecked) {
1296 &ExclusionSet, IsLiveInCalleeCB))
1297 WriteChecked =
true;
1311 if (!WriteChecked && HasBeenWrittenTo &&
1312 Acc.getRemoteInst()->getFunction() != &Scope) {
1314 const auto *FnReachabilityAA =
A.getAAFor<AAInterFnReachability>(
1316 if (FnReachabilityAA) {
1322 if (!FnReachabilityAA->instructionCanReach(
1323 A, *LeastDominatingWriteInst,
1324 *Acc.getRemoteInst()->getFunction(), &ExclusionSet))
1325 WriteChecked =
true;
1332 if (ReadChecked && WriteChecked)
1335 if (!DT || !UseDominanceReasoning)
1337 if (!DominatingWrites.count(&Acc))
1339 return LeastDominatingWriteInst != Acc.getRemoteInst();
1344 for (
auto &It : InterferingAccesses) {
1345 if ((!AllInSameNoSyncFn && !IsThreadLocalObj && !ExecDomainAA) ||
1346 !CanSkipAccess(*It.first, It.second)) {
1347 if (!UserCB(*It.first, It.second))
1355 const AAPointerInfo &OtherAA,
1357 using namespace AA::PointerInfo;
1359 return indicatePessimisticFixpoint();
1362 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1363 bool IsByval = OtherAAImpl.getAssociatedArgument()->hasByValAttr();
1364 Changed |= setReachesReturn(OtherAAImpl.ReturnedOffsets);
1367 const auto &State = OtherAAImpl.getState();
1368 for (
const auto &It : State) {
1369 for (
auto Index : It.getSecond()) {
1370 const auto &RAcc = State.getAccess(Index);
1371 if (IsByval && !RAcc.isRead())
1373 bool UsedAssumedInformation =
false;
1375 auto Content =
A.translateArgumentToCallSiteContent(
1376 RAcc.getContent(), CB, *
this, UsedAssumedInformation);
1377 AK =
AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW));
1378 AK =
AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST));
1380 Changed |= addAccess(
A, RAcc.getRanges(), CB, Content, AK,
1381 RAcc.getType(), RAcc.getRemoteInst());
1387 ChangeStatus translateAndAddState(Attributor &
A,
const AAPointerInfo &OtherAA,
1388 const OffsetInfo &Offsets, CallBase &CB,
1390 using namespace AA::PointerInfo;
1392 return indicatePessimisticFixpoint();
1394 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1398 const auto &State = OtherAAImpl.getState();
1399 for (
const auto &It : State) {
1400 for (
auto Index : It.getSecond()) {
1401 const auto &RAcc = State.getAccess(Index);
1402 if (!IsMustAcc && RAcc.isAssumption())
1404 for (
auto Offset : Offsets) {
1408 if (!NewRanges.isUnknown()) {
1409 NewRanges.addToAllOffsets(Offset);
1414 Changed |= addAccess(
A, NewRanges, CB, RAcc.getContent(), AK,
1415 RAcc.getType(), RAcc.getRemoteInst());
1424 void trackPointerInfoStatistics(
const IRPosition &IRP)
const {}
1427 void dumpState(raw_ostream &O) {
1428 for (
auto &It : OffsetBins) {
1429 O <<
"[" << It.first.Offset <<
"-" << It.first.Offset + It.first.Size
1430 <<
"] : " << It.getSecond().size() <<
"\n";
1431 for (
auto AccIndex : It.getSecond()) {
1432 auto &Acc = AccessList[AccIndex];
1433 O <<
" - " << Acc.getKind() <<
" - " << *Acc.getLocalInst() <<
"\n";
1434 if (Acc.getLocalInst() != Acc.getRemoteInst())
1435 O <<
" --> " << *Acc.getRemoteInst()
1437 if (!Acc.isWrittenValueYetUndetermined()) {
1439 O <<
" - c: func " << Acc.getWrittenValue()->getName()
1441 else if (Acc.getWrittenValue())
1442 O <<
" - c: " << *Acc.getWrittenValue() <<
"\n";
1444 O <<
" - c: <unknown>\n";
1451struct AAPointerInfoFloating :
public AAPointerInfoImpl {
1453 AAPointerInfoFloating(
const IRPosition &IRP, Attributor &
A)
1454 : AAPointerInfoImpl(IRP,
A) {}
1457 bool handleAccess(Attributor &
A, Instruction &
I,
1458 std::optional<Value *> Content,
AccessKind Kind,
1461 using namespace AA::PointerInfo;
1463 const DataLayout &
DL =
A.getDataLayout();
1464 TypeSize AccessSize =
DL.getTypeStoreSize(&Ty);
1473 if (!VT || VT->getElementCount().isScalable() ||
1475 (*Content)->getType() != VT ||
1476 DL.getTypeStoreSize(VT->getElementType()).isScalable()) {
1487 int64_t ElementSize =
DL.getTypeStoreSize(ElementType).getFixedValue();
1492 for (
int i = 0, e = VT->getElementCount().getFixedValue(); i != e; ++i) {
1494 ConstContent, ConstantInt::get(
Int32Ty, i));
1501 for (
auto &ElementOffset : ElementOffsets)
1502 ElementOffset += ElementSize;
1515 bool collectConstantsForGEP(Attributor &
A,
const DataLayout &
DL,
1516 OffsetInfo &UsrOI,
const OffsetInfo &PtrOI,
1517 const GEPOperator *
GEP);
1520 void trackStatistics()
const override {
1521 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1525bool AAPointerInfoFloating::collectConstantsForGEP(Attributor &
A,
1526 const DataLayout &
DL,
1528 const OffsetInfo &PtrOI,
1529 const GEPOperator *
GEP) {
1530 unsigned BitWidth =
DL.getIndexTypeSizeInBits(
GEP->getType());
1531 SmallMapVector<Value *, APInt, 4> VariableOffsets;
1534 assert(!UsrOI.isUnknown() && !PtrOI.isUnknown() &&
1535 "Don't look for constant values if the offset has already been "
1536 "determined to be unknown.");
1538 if (!
GEP->collectOffset(
DL,
BitWidth, VariableOffsets, ConstantOffset)) {
1544 << (VariableOffsets.
empty() ?
"" :
"not") <<
" constant "
1548 Union.addToAll(ConstantOffset.getSExtValue());
1553 for (
const auto &VI : VariableOffsets) {
1554 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
1556 if (!PotentialConstantsAA || !PotentialConstantsAA->isValidState()) {
1562 if (PotentialConstantsAA->undefIsContained())
1569 auto &AssumedSet = PotentialConstantsAA->getAssumedSet();
1570 if (AssumedSet.empty())
1574 for (
const auto &ConstOffset : AssumedSet) {
1575 auto CopyPerOffset =
Union;
1576 CopyPerOffset.addToAll(ConstOffset.getSExtValue() *
1577 VI.second.getZExtValue());
1578 Product.merge(CopyPerOffset);
1583 UsrOI = std::move(Union);
1587ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &
A) {
1588 using namespace AA::PointerInfo;
1590 const DataLayout &
DL =
A.getDataLayout();
1591 Value &AssociatedValue = getAssociatedValue();
1593 DenseMap<Value *, OffsetInfo> OffsetInfoMap;
1594 OffsetInfoMap[&AssociatedValue].
insert(0);
1596 auto HandlePassthroughUser = [&](
Value *Usr,
Value *CurPtr,
bool &Follow) {
1607 "CurPtr does not exist in the map!");
1609 auto &UsrOI = OffsetInfoMap[Usr];
1610 auto &PtrOI = OffsetInfoMap[CurPtr];
1611 assert(!PtrOI.isUnassigned() &&
1612 "Cannot pass through if the input Ptr was not visited!");
1618 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
1620 User *Usr =
U.getUser();
1621 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Analyze " << *CurPtr <<
" in " << *Usr
1624 "The current pointer offset should have been seeded!");
1625 assert(!OffsetInfoMap[CurPtr].isUnassigned() &&
1626 "Current pointer should be assigned");
1630 return HandlePassthroughUser(Usr, CurPtr, Follow);
1632 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled constant user " << *CE
1640 auto &UsrOI = OffsetInfoMap[Usr];
1641 auto &PtrOI = OffsetInfoMap[CurPtr];
1643 if (UsrOI.isUnknown())
1646 if (PtrOI.isUnknown()) {
1652 Follow = collectConstantsForGEP(
A,
DL, UsrOI, PtrOI,
GEP);
1658 return HandlePassthroughUser(Usr, CurPtr, Follow);
1663 if (RI->getFunction() == getAssociatedFunction()) {
1664 auto &PtrOI = OffsetInfoMap[CurPtr];
1665 Changed |= setReachesReturn(PtrOI);
1678 auto &UsrOI = PhiIt->second;
1679 auto &PtrOI = OffsetInfoMap[CurPtr];
1683 if (PtrOI.isUnknown()) {
1684 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand offset unknown "
1685 << *CurPtr <<
" in " << *
PHI <<
"\n");
1686 Follow = !UsrOI.isUnknown();
1692 if (UsrOI == PtrOI) {
1693 assert(!PtrOI.isUnassigned() &&
1694 "Cannot assign if the current Ptr was not visited!");
1695 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant (so far)");
1705 auto It = OffsetInfoMap.
find(CurPtrBase);
1706 if (It == OffsetInfoMap.
end()) {
1707 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand is too complex "
1708 << *CurPtr <<
" in " << *
PHI
1709 <<
" (base: " << *CurPtrBase <<
")\n");
1723 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
1724 *
PHI->getFunction());
1726 auto BaseOI = It->getSecond();
1727 BaseOI.addToAll(
Offset.getZExtValue());
1728 if (IsFirstPHIUser || BaseOI == UsrOI) {
1729 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant " << *CurPtr
1730 <<
" in " << *Usr <<
"\n");
1731 return HandlePassthroughUser(Usr, CurPtr, Follow);
1735 dbgs() <<
"[AAPointerInfo] PHI operand pointer offset mismatch "
1736 << *CurPtr <<
" in " << *
PHI <<
"\n");
1755 if (!handleAccess(
A, *LoadI,
nullptr, AK,
1756 OffsetInfoMap[CurPtr].Offsets,
Changed,
1762 return II->isAssumeLikeIntrinsic();
1773 }
while (FromI && FromI != ToI);
1778 auto IsValidAssume = [&](IntrinsicInst &IntrI) {
1779 if (IntrI.getIntrinsicID() != Intrinsic::assume)
1782 if (IntrI.getParent() == BB) {
1783 if (IsImpactedInRange(LoadI->getNextNode(), &IntrI))
1789 if ((*PredIt) != BB)
1794 if (SuccBB == IntrBB)
1800 if (IsImpactedInRange(LoadI->getNextNode(), BB->
getTerminator()))
1802 if (IsImpactedInRange(&IntrBB->
front(), &IntrI))
1808 std::pair<Value *, IntrinsicInst *> Assumption;
1809 for (
const Use &LoadU : LoadI->uses()) {
1811 if (!CmpI->isEquality() || !CmpI->isTrueWhenEqual())
1813 for (
const Use &CmpU : CmpI->uses()) {
1815 if (!IsValidAssume(*IntrI))
1817 int Idx = CmpI->getOperandUse(0) == LoadU;
1818 Assumption = {CmpI->getOperand(Idx), IntrI};
1823 if (Assumption.first)
1828 if (!Assumption.first || !Assumption.second)
1832 << *Assumption.second <<
": " << *LoadI
1833 <<
" == " << *Assumption.first <<
"\n");
1834 bool UsedAssumedInformation =
false;
1835 std::optional<Value *> Content =
nullptr;
1836 if (Assumption.first)
1838 A.getAssumedSimplified(*Assumption.first, *
this,
1840 return handleAccess(
1841 A, *Assumption.second, Content, AccessKind::AK_ASSUMPTION,
1842 OffsetInfoMap[CurPtr].Offsets,
Changed, *LoadI->getType());
1847 for (
auto *OtherOp : OtherOps) {
1848 if (OtherOp == CurPtr) {
1851 <<
"[AAPointerInfo] Escaping use in store like instruction " <<
I
1863 bool UsedAssumedInformation =
false;
1864 std::optional<Value *> Content =
nullptr;
1866 Content =
A.getAssumedSimplified(
1868 return handleAccess(
A,
I, Content, AK, OffsetInfoMap[CurPtr].Offsets,
1873 return HandleStoreLike(*StoreI, StoreI->getValueOperand(),
1874 *StoreI->getValueOperand()->getType(),
1875 {StoreI->getValueOperand()}, AccessKind::AK_W);
1877 return HandleStoreLike(*RMWI,
nullptr, *RMWI->getValOperand()->getType(),
1878 {RMWI->getValOperand()}, AccessKind::AK_RW);
1880 return HandleStoreLike(
1881 *CXI,
nullptr, *CXI->getNewValOperand()->getType(),
1882 {CXI->getCompareOperand(), CXI->getNewValOperand()},
1889 A.getInfoCache().getTargetLibraryInfoForFunction(*CB->
getFunction());
1894 const auto *CSArgPI =
A.getAAFor<AAPointerInfo>(
1900 Changed = translateAndAddState(
A, *CSArgPI, OffsetInfoMap[CurPtr], *CB,
1903 if (!CSArgPI->reachesReturn())
1904 return isValidState();
1907 if (!Callee ||
Callee->arg_size() <= ArgNo)
1909 bool UsedAssumedInformation =
false;
1910 auto ReturnedValue =
A.getAssumedSimplified(
1915 auto *Arg =
Callee->getArg(ArgNo);
1916 if (ReturnedArg && Arg != ReturnedArg)
1918 bool IsRetMustAcc = IsArgMustAcc && (ReturnedArg == Arg);
1919 const auto *CSRetPI =
A.getAAFor<AAPointerInfo>(
1923 OffsetInfo OI = OffsetInfoMap[CurPtr];
1924 CSArgPI->addReturnedOffsetsTo(OI);
1926 translateAndAddState(
A, *CSRetPI, OI, *CB, IsRetMustAcc) |
Changed;
1927 return isValidState();
1929 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Call user not handled " << *CB
1934 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] User not handled " << *Usr <<
"\n");
1937 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
1938 assert(OffsetInfoMap.
count(OldU) &&
"Old use should be known already!");
1939 assert(!OffsetInfoMap[OldU].isUnassigned() &&
"Old use should be assinged");
1940 if (OffsetInfoMap.
count(NewU)) {
1942 if (!(OffsetInfoMap[NewU] == OffsetInfoMap[OldU])) {
1943 dbgs() <<
"[AAPointerInfo] Equivalent use callback failed: "
1944 << OffsetInfoMap[NewU] <<
" vs " << OffsetInfoMap[OldU]
1948 return OffsetInfoMap[NewU] == OffsetInfoMap[OldU];
1951 return HandlePassthroughUser(NewU.get(), OldU.
get(), Unused);
1953 if (!
A.checkForAllUses(UsePred, *
this, AssociatedValue,
1955 true, EquivalentUseCB)) {
1956 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Check for all uses failed, abort!\n");
1957 return indicatePessimisticFixpoint();
1961 dbgs() <<
"Accesses by bin after update:\n";
1968struct AAPointerInfoReturned final : AAPointerInfoImpl {
1969 AAPointerInfoReturned(
const IRPosition &IRP, Attributor &
A)
1970 : AAPointerInfoImpl(IRP,
A) {}
1974 return indicatePessimisticFixpoint();
1978 void trackStatistics()
const override {
1979 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1983struct AAPointerInfoArgument final : AAPointerInfoFloating {
1984 AAPointerInfoArgument(
const IRPosition &IRP, Attributor &
A)
1985 : AAPointerInfoFloating(IRP,
A) {}
1988 void trackStatistics()
const override {
1989 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1993struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
1994 AAPointerInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
1995 : AAPointerInfoFloating(IRP,
A) {}
1999 using namespace AA::PointerInfo;
2005 if (
auto Length =
MI->getLengthInBytes())
2006 LengthVal =
Length->getSExtValue();
2007 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
2010 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled memory intrinsic "
2012 return indicatePessimisticFixpoint();
2015 ArgNo == 0 ? AccessKind::AK_MUST_WRITE : AccessKind::AK_MUST_READ;
2017 Changed | addAccess(
A, {0, LengthVal}, *
MI,
nullptr,
Kind,
nullptr);
2020 dbgs() <<
"Accesses by bin after update:\n";
2031 Argument *Arg = getAssociatedArgument();
2035 A.getAAFor<AAPointerInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
2036 if (ArgAA && ArgAA->getState().isValidState())
2037 return translateAndAddStateFromCallee(
A, *ArgAA,
2040 return indicatePessimisticFixpoint();
2043 bool IsKnownNoCapture;
2045 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNoCapture))
2046 return indicatePessimisticFixpoint();
2048 bool IsKnown =
false;
2050 return ChangeStatus::UNCHANGED;
2053 ReadOnly ? AccessKind::AK_MAY_READ : AccessKind::AK_MAY_READ_WRITE;
2059 void trackStatistics()
const override {
2060 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2064struct AAPointerInfoCallSiteReturned final : AAPointerInfoFloating {
2065 AAPointerInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2066 : AAPointerInfoFloating(IRP,
A) {}
2069 void trackStatistics()
const override {
2070 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2078struct AANoUnwindImpl : AANoUnwind {
2079 AANoUnwindImpl(
const IRPosition &IRP, Attributor &
A) : AANoUnwind(IRP,
A) {}
2085 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2089 const std::string getAsStr(Attributor *
A)
const override {
2090 return getAssumed() ?
"nounwind" :
"may-unwind";
2096 (unsigned)Instruction::Invoke, (
unsigned)Instruction::CallBr,
2097 (unsigned)Instruction::Call, (
unsigned)Instruction::CleanupRet,
2098 (unsigned)Instruction::CatchSwitch, (
unsigned)Instruction::Resume};
2101 if (!
I.mayThrow(
true))
2105 bool IsKnownNoUnwind;
2113 bool UsedAssumedInformation =
false;
2114 if (!
A.checkForAllInstructions(CheckForNoUnwind, *
this, Opcodes,
2115 UsedAssumedInformation))
2116 return indicatePessimisticFixpoint();
2118 return ChangeStatus::UNCHANGED;
2122struct AANoUnwindFunction final :
public AANoUnwindImpl {
2123 AANoUnwindFunction(
const IRPosition &IRP, Attributor &
A)
2124 : AANoUnwindImpl(IRP,
A) {}
2131struct AANoUnwindCallSite final
2132 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl> {
2133 AANoUnwindCallSite(
const IRPosition &IRP, Attributor &
A)
2134 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl>(IRP,
A) {}
2145 case Intrinsic::nvvm_barrier_cta_sync_aligned_all:
2146 case Intrinsic::nvvm_barrier_cta_sync_aligned_count:
2147 case Intrinsic::nvvm_barrier_cta_red_and_aligned_all:
2148 case Intrinsic::nvvm_barrier_cta_red_and_aligned_count:
2149 case Intrinsic::nvvm_barrier_cta_red_or_aligned_all:
2150 case Intrinsic::nvvm_barrier_cta_red_or_aligned_count:
2151 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_all:
2152 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_count:
2154 case Intrinsic::amdgcn_s_barrier:
2155 if (ExecutedAligned)
2178 switch (
I->getOpcode()) {
2179 case Instruction::AtomicRMW:
2182 case Instruction::Store:
2185 case Instruction::Load:
2190 "New atomic operations need to be known in the attributor.");
2209 const std::string getAsStr(Attributor *
A)
const override {
2210 return getAssumed() ?
"nosync" :
"may-sync";
2226 if (
I.mayReadOrWriteMemory())
2240 bool UsedAssumedInformation =
false;
2241 if (!
A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *
this,
2242 UsedAssumedInformation) ||
2243 !
A.checkForAllCallLikeInstructions(CheckForNoSync, *
this,
2244 UsedAssumedInformation))
2245 return indicatePessimisticFixpoint();
2250struct AANoSyncFunction final :
public AANoSyncImpl {
2251 AANoSyncFunction(
const IRPosition &IRP, Attributor &
A)
2252 : AANoSyncImpl(IRP,
A) {}
2259struct AANoSyncCallSite final : AACalleeToCallSite<AANoSync, AANoSyncImpl> {
2260 AANoSyncCallSite(
const IRPosition &IRP, Attributor &
A)
2261 : AACalleeToCallSite<AANoSync, AANoSyncImpl>(IRP,
A) {}
2271struct AANoFreeImpl :
public AANoFree {
2272 AANoFreeImpl(
const IRPosition &IRP, Attributor &
A) : AANoFree(IRP,
A) {}
2278 DepClassTy::NONE, IsKnown));
2288 DepClassTy::REQUIRED, IsKnown);
2291 bool UsedAssumedInformation =
false;
2292 if (!
A.checkForAllCallLikeInstructions(CheckForNoFree, *
this,
2293 UsedAssumedInformation))
2294 return indicatePessimisticFixpoint();
2295 return ChangeStatus::UNCHANGED;
2299 const std::string getAsStr(Attributor *
A)
const override {
2300 return getAssumed() ?
"nofree" :
"may-free";
2304struct AANoFreeFunction final :
public AANoFreeImpl {
2305 AANoFreeFunction(
const IRPosition &IRP, Attributor &
A)
2306 : AANoFreeImpl(IRP,
A) {}
2313struct AANoFreeCallSite final : AACalleeToCallSite<AANoFree, AANoFreeImpl> {
2314 AANoFreeCallSite(
const IRPosition &IRP, Attributor &
A)
2315 : AACalleeToCallSite<AANoFree, AANoFreeImpl>(IRP,
A) {}
2322struct AANoFreeFloating : AANoFreeImpl {
2323 AANoFreeFloating(
const IRPosition &IRP, Attributor &
A)
2324 : AANoFreeImpl(IRP,
A) {}
2331 const IRPosition &IRP = getIRPosition();
2336 DepClassTy::OPTIONAL, IsKnown))
2337 return ChangeStatus::UNCHANGED;
2339 Value &AssociatedValue = getIRPosition().getAssociatedValue();
2340 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
2352 DepClassTy::REQUIRED, IsKnown);
2372 if (!
A.checkForAllUses(Pred, *
this, AssociatedValue))
2373 return indicatePessimisticFixpoint();
2375 return ChangeStatus::UNCHANGED;
2380struct AANoFreeArgument final : AANoFreeFloating {
2381 AANoFreeArgument(
const IRPosition &IRP, Attributor &
A)
2382 : AANoFreeFloating(IRP,
A) {}
2389struct AANoFreeCallSiteArgument final : AANoFreeFloating {
2390 AANoFreeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2391 : AANoFreeFloating(IRP,
A) {}
2399 Argument *Arg = getAssociatedArgument();
2401 return indicatePessimisticFixpoint();
2405 DepClassTy::REQUIRED, IsKnown))
2406 return ChangeStatus::UNCHANGED;
2407 return indicatePessimisticFixpoint();
2415struct AANoFreeReturned final : AANoFreeFloating {
2416 AANoFreeReturned(
const IRPosition &IRP, Attributor &
A)
2417 : AANoFreeFloating(IRP,
A) {
2432 void trackStatistics()
const override {}
2436struct AANoFreeCallSiteReturned final : AANoFreeFloating {
2437 AANoFreeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2438 : AANoFreeFloating(IRP,
A) {}
2441 return ChangeStatus::UNCHANGED;
2452 bool IgnoreSubsumingPositions) {
2454 AttrKinds.
push_back(Attribute::NonNull);
2457 AttrKinds.
push_back(Attribute::Dereferenceable);
2458 if (
A.hasAttr(IRP, AttrKinds, IgnoreSubsumingPositions, Attribute::NonNull))
2465 if (!Fn->isDeclaration()) {
2475 bool UsedAssumedInformation =
false;
2476 if (!
A.checkForAllInstructions(
2478 Worklist.push_back({*cast<ReturnInst>(I).getReturnValue(), &I});
2482 UsedAssumedInformation,
false,
true))
2494 Attribute::NonNull)});
2499static int64_t getKnownNonNullAndDerefBytesForUse(
2500 Attributor &
A,
const AbstractAttribute &QueryingAA,
Value &AssociatedValue,
2501 const Use *U,
const Instruction *
I,
bool &IsNonNull,
bool &TrackUse) {
2504 const Value *UseV =
U->get();
2525 const DataLayout &
DL =
A.getInfoCache().getDL();
2529 U, {Attribute::NonNull, Attribute::Dereferenceable})) {
2546 bool IsKnownNonNull;
2549 IsNonNull |= IsKnownNonNull;
2552 return DerefAA ? DerefAA->getKnownDereferenceableBytes() : 0;
2556 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
2557 Loc->Size.isScalable() ||
I->isVolatile())
2563 if (
Base &&
Base == &AssociatedValue) {
2564 int64_t DerefBytes = Loc->Size.getValue() +
Offset;
2566 return std::max(int64_t(0), DerefBytes);
2573 int64_t DerefBytes = Loc->Size.getValue();
2575 return std::max(int64_t(0), DerefBytes);
2581struct AANonNullImpl : AANonNull {
2582 AANonNullImpl(
const IRPosition &IRP, Attributor &
A) : AANonNull(IRP,
A) {}
2586 Value &
V = *getAssociatedValue().stripPointerCasts();
2588 indicatePessimisticFixpoint();
2592 if (Instruction *CtxI = getCtxI())
2593 followUsesInMBEC(*
this,
A, getState(), *CtxI);
2597 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
2598 AANonNull::StateType &State) {
2599 bool IsNonNull =
false;
2600 bool TrackUse =
false;
2601 getKnownNonNullAndDerefBytesForUse(
A, *
this, getAssociatedValue(), U,
I,
2602 IsNonNull, TrackUse);
2603 State.setKnown(IsNonNull);
2608 const std::string getAsStr(Attributor *
A)
const override {
2609 return getAssumed() ?
"nonnull" :
"may-null";
2614struct AANonNullFloating :
public AANonNullImpl {
2615 AANonNullFloating(
const IRPosition &IRP, Attributor &
A)
2616 : AANonNullImpl(IRP,
A) {}
2620 auto CheckIRP = [&](
const IRPosition &IRP) {
2621 bool IsKnownNonNull;
2623 A, *
this, IRP, DepClassTy::OPTIONAL, IsKnownNonNull);
2627 bool UsedAssumedInformation =
false;
2628 Value *AssociatedValue = &getAssociatedValue();
2630 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
2635 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
2641 return AA::hasAssumedIRAttr<Attribute::NonNull>(
2642 A, this, IRPosition::value(*Op), DepClassTy::OPTIONAL,
2645 return ChangeStatus::UNCHANGED;
2649 DepClassTy::OPTIONAL, IsKnown) &&
2652 DepClassTy::OPTIONAL, IsKnown))
2653 return ChangeStatus::UNCHANGED;
2660 if (AVIRP == getIRPosition() || !CheckIRP(AVIRP))
2661 return indicatePessimisticFixpoint();
2662 return ChangeStatus::UNCHANGED;
2665 for (
const auto &VAC : Values)
2667 return indicatePessimisticFixpoint();
2669 return ChangeStatus::UNCHANGED;
2677struct AANonNullReturned final
2678 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2679 false, AANonNull::IRAttributeKind, false> {
2680 AANonNullReturned(
const IRPosition &IRP, Attributor &
A)
2681 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2686 const std::string getAsStr(Attributor *
A)
const override {
2687 return getAssumed() ?
"nonnull" :
"may-null";
2695struct AANonNullArgument final
2696 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
2697 AANonNullArgument(
const IRPosition &IRP, Attributor &
A)
2698 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP,
A) {}
2704struct AANonNullCallSiteArgument final : AANonNullFloating {
2705 AANonNullCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2706 : AANonNullFloating(IRP,
A) {}
2713struct AANonNullCallSiteReturned final
2714 : AACalleeToCallSite<AANonNull, AANonNullImpl> {
2715 AANonNullCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2716 : AACalleeToCallSite<AANonNull, AANonNullImpl>(IRP,
A) {}
2725struct AAMustProgressImpl :
public AAMustProgress {
2726 AAMustProgressImpl(
const IRPosition &IRP, Attributor &
A)
2727 : AAMustProgress(IRP,
A) {}
2733 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2738 const std::string getAsStr(Attributor *
A)
const override {
2739 return getAssumed() ?
"mustprogress" :
"may-not-progress";
2743struct AAMustProgressFunction final : AAMustProgressImpl {
2744 AAMustProgressFunction(
const IRPosition &IRP, Attributor &
A)
2745 : AAMustProgressImpl(IRP,
A) {}
2751 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnown)) {
2753 return indicateOptimisticFixpoint();
2754 return ChangeStatus::UNCHANGED;
2757 auto CheckForMustProgress = [&](AbstractCallSite ACS) {
2759 bool IsKnownMustProgress;
2761 A,
this, IPos, DepClassTy::REQUIRED, IsKnownMustProgress,
2765 bool AllCallSitesKnown =
true;
2766 if (!
A.checkForAllCallSites(CheckForMustProgress, *
this,
2769 return indicatePessimisticFixpoint();
2771 return ChangeStatus::UNCHANGED;
2775 void trackStatistics()
const override {
2781struct AAMustProgressCallSite final : AAMustProgressImpl {
2782 AAMustProgressCallSite(
const IRPosition &IRP, Attributor &
A)
2783 : AAMustProgressImpl(IRP,
A) {}
2792 bool IsKnownMustProgress;
2794 A,
this, FnPos, DepClassTy::REQUIRED, IsKnownMustProgress))
2795 return indicatePessimisticFixpoint();
2796 return ChangeStatus::UNCHANGED;
2800 void trackStatistics()
const override {
2809struct AANoRecurseImpl :
public AANoRecurse {
2810 AANoRecurseImpl(
const IRPosition &IRP, Attributor &
A) : AANoRecurse(IRP,
A) {}
2816 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2821 const std::string getAsStr(Attributor *
A)
const override {
2822 return getAssumed() ?
"norecurse" :
"may-recurse";
2826struct AANoRecurseFunction final : AANoRecurseImpl {
2827 AANoRecurseFunction(
const IRPosition &IRP, Attributor &
A)
2828 : AANoRecurseImpl(IRP,
A) {}
2834 auto CallSitePred = [&](AbstractCallSite ACS) {
2835 bool IsKnownNoRecurse;
2839 DepClassTy::NONE, IsKnownNoRecurse))
2841 return IsKnownNoRecurse;
2843 bool UsedAssumedInformation =
false;
2844 if (
A.checkForAllCallSites(CallSitePred, *
this,
true,
2845 UsedAssumedInformation)) {
2851 if (!UsedAssumedInformation)
2852 indicateOptimisticFixpoint();
2853 return ChangeStatus::UNCHANGED;
2856 const AAInterFnReachability *EdgeReachability =
2857 A.getAAFor<AAInterFnReachability>(*
this, getIRPosition(),
2858 DepClassTy::REQUIRED);
2859 if (EdgeReachability && EdgeReachability->
canReach(
A, *getAnchorScope()))
2860 return indicatePessimisticFixpoint();
2861 return ChangeStatus::UNCHANGED;
2868struct AANoRecurseCallSite final
2869 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl> {
2870 AANoRecurseCallSite(
const IRPosition &IRP, Attributor &
A)
2871 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl>(IRP,
A) {}
2881struct AANonConvergentImpl :
public AANonConvergent {
2882 AANonConvergentImpl(
const IRPosition &IRP, Attributor &
A)
2883 : AANonConvergent(IRP,
A) {}
2886 const std::string getAsStr(Attributor *
A)
const override {
2887 return getAssumed() ?
"non-convergent" :
"may-be-convergent";
2891struct AANonConvergentFunction final : AANonConvergentImpl {
2892 AANonConvergentFunction(
const IRPosition &IRP, Attributor &
A)
2893 : AANonConvergentImpl(IRP,
A) {}
2899 auto CalleeIsNotConvergent = [&](
Instruction &Inst) {
2902 if (!Callee ||
Callee->isIntrinsic()) {
2905 if (
Callee->isDeclaration()) {
2906 return !
Callee->hasFnAttribute(Attribute::Convergent);
2908 const auto *ConvergentAA =
A.getAAFor<AANonConvergent>(
2910 return ConvergentAA && ConvergentAA->isAssumedNotConvergent();
2913 bool UsedAssumedInformation =
false;
2914 if (!
A.checkForAllCallLikeInstructions(CalleeIsNotConvergent, *
this,
2915 UsedAssumedInformation)) {
2916 return indicatePessimisticFixpoint();
2918 return ChangeStatus::UNCHANGED;
2922 if (isKnownNotConvergent() &&
2923 A.hasAttr(getIRPosition(), Attribute::Convergent)) {
2924 A.removeAttrs(getIRPosition(), {Attribute::Convergent});
2925 return ChangeStatus::CHANGED;
2927 return ChangeStatus::UNCHANGED;
2937struct AAUndefinedBehaviorImpl :
public AAUndefinedBehavior {
2938 AAUndefinedBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
2939 : AAUndefinedBehavior(IRP,
A) {}
2944 const size_t UBPrevSize = KnownUBInsts.size();
2945 const size_t NoUBPrevSize = AssumedNoUBInsts.size();
2953 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
2962 "Expected pointer operand of memory accessing instruction");
2966 std::optional<Value *> SimplifiedPtrOp =
2967 stopOnUndefOrAssumed(
A, PtrOp, &
I);
2968 if (!SimplifiedPtrOp || !*SimplifiedPtrOp)
2970 const Value *PtrOpVal = *SimplifiedPtrOp;
2976 AssumedNoUBInsts.insert(&
I);
2988 AssumedNoUBInsts.insert(&
I);
2990 KnownUBInsts.insert(&
I);
2999 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3007 std::optional<Value *> SimplifiedCond =
3008 stopOnUndefOrAssumed(
A, BrInst->getCondition(), BrInst);
3009 if (!SimplifiedCond || !*SimplifiedCond)
3011 AssumedNoUBInsts.insert(&
I);
3019 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3028 for (
unsigned idx = 0; idx < CB.
arg_size(); idx++) {
3034 if (idx >=
Callee->arg_size())
3046 bool IsKnownNoUndef;
3048 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNoUndef);
3049 if (!IsKnownNoUndef)
3051 bool UsedAssumedInformation =
false;
3052 std::optional<Value *> SimplifiedVal =
3055 if (UsedAssumedInformation)
3057 if (SimplifiedVal && !*SimplifiedVal)
3060 KnownUBInsts.insert(&
I);
3066 bool IsKnownNonNull;
3068 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNonNull);
3070 KnownUBInsts.insert(&
I);
3079 std::optional<Value *> SimplifiedRetValue =
3080 stopOnUndefOrAssumed(
A, RI.getReturnValue(), &
I);
3081 if (!SimplifiedRetValue || !*SimplifiedRetValue)
3099 bool IsKnownNonNull;
3104 KnownUBInsts.insert(&
I);
3110 bool UsedAssumedInformation =
false;
3111 A.checkForAllInstructions(InspectMemAccessInstForUB, *
this,
3112 {Instruction::Load, Instruction::Store,
3113 Instruction::AtomicCmpXchg,
3114 Instruction::AtomicRMW},
3115 UsedAssumedInformation,
3117 A.checkForAllInstructions(InspectBrInstForUB, *
this, {Instruction::CondBr},
3118 UsedAssumedInformation,
3120 A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *
this,
3121 UsedAssumedInformation);
3125 if (!getAnchorScope()->getReturnType()->isVoidTy()) {
3127 if (!
A.isAssumedDead(ReturnIRP,
this,
nullptr, UsedAssumedInformation)) {
3128 bool IsKnownNoUndef;
3130 A,
this, ReturnIRP, DepClassTy::NONE, IsKnownNoUndef);
3132 A.checkForAllInstructions(InspectReturnInstForUB, *
this,
3133 {Instruction::Ret}, UsedAssumedInformation,
3138 if (NoUBPrevSize != AssumedNoUBInsts.size() ||
3139 UBPrevSize != KnownUBInsts.size())
3140 return ChangeStatus::CHANGED;
3141 return ChangeStatus::UNCHANGED;
3144 bool isKnownToCauseUB(Instruction *
I)
const override {
3145 return KnownUBInsts.count(
I);
3148 bool isAssumedToCauseUB(Instruction *
I)
const override {
3155 switch (
I->getOpcode()) {
3156 case Instruction::Load:
3157 case Instruction::Store:
3158 case Instruction::AtomicCmpXchg:
3159 case Instruction::AtomicRMW:
3160 case Instruction::CondBr:
3161 return !AssumedNoUBInsts.count(
I);
3169 if (KnownUBInsts.empty())
3170 return ChangeStatus::UNCHANGED;
3171 for (Instruction *
I : KnownUBInsts)
3172 A.changeToUnreachableAfterManifest(
I);
3173 return ChangeStatus::CHANGED;
3177 const std::string getAsStr(Attributor *
A)
const override {
3178 return getAssumed() ?
"undefined-behavior" :
"no-ub";
3206 SmallPtrSet<Instruction *, 8> KnownUBInsts;
3210 SmallPtrSet<Instruction *, 8> AssumedNoUBInsts;
3221 std::optional<Value *> stopOnUndefOrAssumed(Attributor &
A,
Value *V,
3223 bool UsedAssumedInformation =
false;
3224 std::optional<Value *> SimplifiedV =
3227 if (!UsedAssumedInformation) {
3232 KnownUBInsts.insert(
I);
3233 return std::nullopt;
3240 KnownUBInsts.insert(
I);
3241 return std::nullopt;
3247struct AAUndefinedBehaviorFunction final : AAUndefinedBehaviorImpl {
3248 AAUndefinedBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
3249 : AAUndefinedBehaviorImpl(IRP,
A) {}
3252 void trackStatistics()
const override {
3253 STATS_DECL(UndefinedBehaviorInstruction, Instruction,
3254 "Number of instructions known to have UB");
3256 KnownUBInsts.size();
3267static bool mayContainUnboundedCycle(Function &
F, Attributor &
A) {
3268 ScalarEvolution *SE =
3269 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
F);
3270 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
F);
3276 for (scc_iterator<Function *> SCCI =
scc_begin(&
F); !SCCI.isAtEnd(); ++SCCI)
3277 if (SCCI.hasCycle())
3287 for (
auto *L : LI->getLoopsInPreorder()) {
3294struct AAWillReturnImpl :
public AAWillReturn {
3295 AAWillReturnImpl(
const IRPosition &IRP, Attributor &
A)
3296 : AAWillReturn(IRP,
A) {}
3302 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
3307 bool isImpliedByMustprogressAndReadonly(Attributor &
A,
bool KnownOnly) {
3308 if (!
A.hasAttr(getIRPosition(), {Attribute::MustProgress}))
3313 return IsKnown || !KnownOnly;
3319 if (isImpliedByMustprogressAndReadonly(
A,
false))
3320 return ChangeStatus::UNCHANGED;
3326 A,
this, IPos, DepClassTy::REQUIRED, IsKnown)) {
3332 bool IsKnownNoRecurse;
3334 A,
this, IPos, DepClassTy::REQUIRED, IsKnownNoRecurse);
3337 bool UsedAssumedInformation =
false;
3338 if (!
A.checkForAllCallLikeInstructions(CheckForWillReturn, *
this,
3339 UsedAssumedInformation))
3340 return indicatePessimisticFixpoint();
3344 return !
I.isVolatile();
3346 if (!
A.checkForAllInstructions(CheckForVolatile, *
this,
3347 {Instruction::Load, Instruction::Store,
3348 Instruction::AtomicCmpXchg,
3349 Instruction::AtomicRMW},
3350 UsedAssumedInformation))
3351 return indicatePessimisticFixpoint();
3353 return ChangeStatus::UNCHANGED;
3357 const std::string getAsStr(Attributor *
A)
const override {
3358 return getAssumed() ?
"willreturn" :
"may-noreturn";
3362struct AAWillReturnFunction final : AAWillReturnImpl {
3363 AAWillReturnFunction(
const IRPosition &IRP, Attributor &
A)
3364 : AAWillReturnImpl(IRP,
A) {}
3368 AAWillReturnImpl::initialize(
A);
3371 assert(
F &&
"Did expect an anchor function");
3372 if (
F->isDeclaration() || mayContainUnboundedCycle(*
F,
A))
3373 indicatePessimisticFixpoint();
3381struct AAWillReturnCallSite final
3382 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl> {
3383 AAWillReturnCallSite(
const IRPosition &IRP, Attributor &
A)
3384 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl>(IRP,
A) {}
3388 if (isImpliedByMustprogressAndReadonly(
A,
false))
3389 return ChangeStatus::UNCHANGED;
3391 return AACalleeToCallSite::updateImpl(
A);
3413 const ToTy *
To =
nullptr;
3440 if (!ES || ES->
empty()) {
3441 ExclusionSet = nullptr;
3442 }
else if (MakeUnique) {
3443 ExclusionSet =
A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ES);
3468 if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))
3470 return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);
3474#define DefineKeys(ToTy) \
3476 ReachabilityQueryInfo<ToTy> \
3477 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::EmptyKey = \
3478 ReachabilityQueryInfo<ToTy>( \
3479 DenseMapInfo<const Instruction *>::getEmptyKey(), \
3480 DenseMapInfo<const ToTy *>::getEmptyKey()); \
3482 ReachabilityQueryInfo<ToTy> \
3483 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::TombstoneKey = \
3484 ReachabilityQueryInfo<ToTy>( \
3485 DenseMapInfo<const Instruction *>::getTombstoneKey(), \
3486 DenseMapInfo<const ToTy *>::getTombstoneKey());
3495template <
typename BaseTy,
typename ToTy>
3496struct CachedReachabilityAA :
public BaseTy {
3497 using RQITy = ReachabilityQueryInfo<ToTy>;
3499 CachedReachabilityAA(
const IRPosition &IRP, Attributor &
A) : BaseTy(IRP,
A) {}
3502 bool isQueryAA()
const override {
return true; }
3507 for (
unsigned u = 0,
e = QueryVector.size();
u <
e; ++
u) {
3508 RQITy *RQI = QueryVector[
u];
3509 if (RQI->Result == RQITy::Reachable::No &&
3511 Changed = ChangeStatus::CHANGED;
3517 bool IsTemporaryRQI) = 0;
3519 bool rememberResult(Attributor &
A,
typename RQITy::Reachable
Result,
3520 RQITy &RQI,
bool UsedExclusionSet,
bool IsTemporaryRQI) {
3525 QueryCache.erase(&RQI);
3531 if (
Result == RQITy::Reachable::Yes || !UsedExclusionSet) {
3532 RQITy PlainRQI(RQI.From, RQI.To);
3533 if (!QueryCache.count(&PlainRQI)) {
3534 RQITy *RQIPtr =
new (
A.Allocator) RQITy(RQI.From, RQI.To);
3536 QueryVector.push_back(RQIPtr);
3537 QueryCache.insert(RQIPtr);
3542 if (IsTemporaryRQI &&
Result != RQITy::Reachable::Yes && UsedExclusionSet) {
3543 assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&
3544 "Did not expect empty set!");
3545 RQITy *RQIPtr =
new (
A.Allocator)
3546 RQITy(
A, *RQI.From, *RQI.To, RQI.ExclusionSet,
true);
3547 assert(RQIPtr->Result == RQITy::Reachable::No &&
"Already reachable?");
3549 assert(!QueryCache.count(RQIPtr));
3550 QueryVector.push_back(RQIPtr);
3551 QueryCache.insert(RQIPtr);
3554 if (
Result == RQITy::Reachable::No && IsTemporaryRQI)
3555 A.registerForUpdate(*
this);
3556 return Result == RQITy::Reachable::Yes;
3559 const std::string getAsStr(Attributor *
A)
const override {
3561 return "#queries(" + std::to_string(QueryVector.size()) +
")";
3564 bool checkQueryCache(Attributor &
A, RQITy &StackRQI,
3565 typename RQITy::Reachable &
Result) {
3566 if (!this->getState().isValidState()) {
3567 Result = RQITy::Reachable::Yes;
3573 if (StackRQI.ExclusionSet) {
3574 RQITy PlainRQI(StackRQI.From, StackRQI.To);
3575 auto It = QueryCache.find(&PlainRQI);
3576 if (It != QueryCache.end() && (*It)->Result == RQITy::Reachable::No) {
3577 Result = RQITy::Reachable::No;
3582 auto It = QueryCache.find(&StackRQI);
3583 if (It != QueryCache.end()) {
3590 QueryCache.insert(&StackRQI);
3596 DenseSet<RQITy *> QueryCache;
3599struct AAIntraFnReachabilityFunction final
3600 :
public CachedReachabilityAA<AAIntraFnReachability, Instruction> {
3601 using Base = CachedReachabilityAA<AAIntraFnReachability, Instruction>;
3602 AAIntraFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
3604 DT =
A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(
3608 bool isAssumedReachable(
3609 Attributor &
A,
const Instruction &From,
const Instruction &To,
3611 auto *NonConstThis =
const_cast<AAIntraFnReachabilityFunction *
>(
this);
3615 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
3617 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
3618 return NonConstThis->isReachableImpl(
A, StackRQI,
3620 return Result == RQITy::Reachable::Yes;
3627 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3630 [&](
const auto &DeadEdge) {
3631 return LivenessAA->isEdgeDead(DeadEdge.first,
3635 return LivenessAA->isAssumedDead(BB);
3637 return ChangeStatus::UNCHANGED;
3641 return Base::updateImpl(
A);
3645 bool IsTemporaryRQI)
override {
3647 bool UsedExclusionSet =
false;
3652 while (IP && IP != &To) {
3653 if (ExclusionSet && IP != Origin && ExclusionSet->
count(IP)) {
3654 UsedExclusionSet =
true;
3662 const BasicBlock *FromBB = RQI.From->getParent();
3663 const BasicBlock *ToBB = RQI.To->getParent();
3665 "Not an intra-procedural query!");
3669 if (FromBB == ToBB &&
3670 WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
3671 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3676 if (!WillReachInBlock(ToBB->
front(), *RQI.To, RQI.ExclusionSet))
3677 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3681 SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
3682 if (RQI.ExclusionSet)
3683 for (
auto *
I : *RQI.ExclusionSet)
3684 if (
I->getFunction() == Fn)
3685 ExclusionBlocks.
insert(
I->getParent());
3688 if (ExclusionBlocks.
count(FromBB) &&
3691 return rememberResult(
A, RQITy::Reachable::No, RQI,
true, IsTemporaryRQI);
3694 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3695 if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {
3696 DeadBlocks.insert(ToBB);
3697 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3701 SmallPtrSet<const BasicBlock *, 16> Visited;
3705 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> LocalDeadEdges;
3706 while (!Worklist.
empty()) {
3708 if (!Visited.
insert(BB).second)
3710 for (
const BasicBlock *SuccBB :
successors(BB)) {
3711 if (LivenessAA && LivenessAA->isEdgeDead(BB, SuccBB)) {
3712 LocalDeadEdges.
insert({BB, SuccBB});
3717 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3720 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3723 if (ExclusionBlocks.
count(SuccBB)) {
3724 UsedExclusionSet =
true;
3731 DeadEdges.insert_range(LocalDeadEdges);
3732 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3737 void trackStatistics()
const override {}
3742 DenseSet<const BasicBlock *> DeadBlocks;
3746 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> DeadEdges;
3749 const DominatorTree *DT =
nullptr;
3757 bool IgnoreSubsumingPositions) {
3758 assert(ImpliedAttributeKind == Attribute::NoAlias &&
3759 "Unexpected attribute kind");
3765 IgnoreSubsumingPositions =
true;
3776 if (
A.hasAttr(IRP, {Attribute::ByVal, Attribute::NoAlias},
3777 IgnoreSubsumingPositions, Attribute::NoAlias))
3787 "Noalias is a pointer attribute");
3790 const std::string getAsStr(
Attributor *
A)
const override {
3791 return getAssumed() ?
"noalias" :
"may-alias";
3796struct AANoAliasFloating final : AANoAliasImpl {
3797 AANoAliasFloating(
const IRPosition &IRP, Attributor &
A)
3798 : AANoAliasImpl(IRP,
A) {}
3803 return indicatePessimisticFixpoint();
3807 void trackStatistics()
const override {
3813struct AANoAliasArgument final
3814 : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> {
3815 using Base = AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>;
3816 AANoAliasArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
3829 DepClassTy::OPTIONAL, IsKnownNoSycn))
3830 return Base::updateImpl(
A);
3835 return Base::updateImpl(
A);
3839 bool UsedAssumedInformation =
false;
3840 if (
A.checkForAllCallSites(
3841 [](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *
this,
3842 true, UsedAssumedInformation))
3843 return Base::updateImpl(
A);
3851 return indicatePessimisticFixpoint();
3858struct AANoAliasCallSiteArgument final : AANoAliasImpl {
3859 AANoAliasCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
3860 : AANoAliasImpl(IRP,
A) {}
3864 bool mayAliasWithArgument(Attributor &
A, AAResults *&AAR,
3865 const AAMemoryBehavior &MemBehaviorAA,
3866 const CallBase &CB,
unsigned OtherArgNo) {
3868 if (this->getCalleeArgNo() == (
int)OtherArgNo)
3876 auto *CBArgMemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
3880 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadNone()) {
3881 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3888 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadOnly() &&
3890 A.recordDependence(MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3891 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3897 AAR =
A.getInfoCache().getAnalysisResultForFunction<AAManager>(
3901 bool IsAliasing = !AAR || !AAR->
isNoAlias(&getAssociatedValue(), ArgOp);
3903 "callsite arguments: "
3904 << getAssociatedValue() <<
" " << *ArgOp <<
" => "
3905 << (IsAliasing ?
"" :
"no-") <<
"alias \n");
3910 bool isKnownNoAliasDueToNoAliasPreservation(
3911 Attributor &
A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA) {
3924 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
3940 bool IsKnownNoCapture;
3943 DepClassTy::OPTIONAL, IsKnownNoCapture))
3949 A, *UserI, *getCtxI(), *
this,
nullptr,
3950 [ScopeFn](
const Function &Fn) {
return &Fn != ScopeFn; }))
3965 LLVM_DEBUG(
dbgs() <<
"[AANoAliasCSArg] Unknown user: " << *UserI <<
"\n");
3969 bool IsKnownNoCapture;
3970 const AANoCapture *NoCaptureAA =
nullptr;
3972 A,
this, VIRP, DepClassTy::NONE, IsKnownNoCapture,
false, &NoCaptureAA);
3973 if (!IsAssumedNoCapture &&
3975 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue())) {
3977 dbgs() <<
"[AANoAliasCSArg] " << getAssociatedValue()
3978 <<
" cannot be noalias as it is potentially captured\n");
3983 A.recordDependence(*NoCaptureAA, *
this, DepClassTy::OPTIONAL);
3989 for (
unsigned OtherArgNo = 0; OtherArgNo < CB.
arg_size(); OtherArgNo++)
3990 if (mayAliasWithArgument(
A, AAR, MemBehaviorAA, CB, OtherArgNo))
4000 auto *MemBehaviorAA =
4001 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
4003 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
4004 return ChangeStatus::UNCHANGED;
4007 bool IsKnownNoAlias;
4010 A,
this, VIRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
4012 <<
" is not no-alias at the definition\n");
4013 return indicatePessimisticFixpoint();
4016 AAResults *AAR =
nullptr;
4017 if (MemBehaviorAA &&
4018 isKnownNoAliasDueToNoAliasPreservation(
A, AAR, *MemBehaviorAA)) {
4020 dbgs() <<
"[AANoAlias] No-Alias deduced via no-alias preservation\n");
4021 return ChangeStatus::UNCHANGED;
4024 return indicatePessimisticFixpoint();
4032struct AANoAliasReturned final : AANoAliasImpl {
4033 AANoAliasReturned(
const IRPosition &IRP, Attributor &
A)
4034 : AANoAliasImpl(IRP,
A) {}
4039 auto CheckReturnValue = [&](
Value &RV) ->
bool {
4050 bool IsKnownNoAlias;
4052 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoAlias))
4055 bool IsKnownNoCapture;
4056 const AANoCapture *NoCaptureAA =
nullptr;
4058 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
4060 return IsAssumedNoCapture ||
4064 if (!
A.checkForAllReturnedValues(CheckReturnValue, *
this))
4065 return indicatePessimisticFixpoint();
4067 return ChangeStatus::UNCHANGED;
4075struct AANoAliasCallSiteReturned final
4076 : AACalleeToCallSite<AANoAlias, AANoAliasImpl> {
4077 AANoAliasCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4078 : AACalleeToCallSite<AANoAlias, AANoAliasImpl>(IRP,
A) {}
4088struct AAIsDeadValueImpl :
public AAIsDead {
4089 AAIsDeadValueImpl(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4092 bool isAssumedDead()
const override {
return isAssumed(IS_DEAD); }
4095 bool isKnownDead()
const override {
return isKnown(IS_DEAD); }
4098 bool isAssumedDead(
const BasicBlock *BB)
const override {
return false; }
4101 bool isKnownDead(
const BasicBlock *BB)
const override {
return false; }
4104 bool isAssumedDead(
const Instruction *
I)
const override {
4105 return I == getCtxI() && isAssumedDead();
4109 bool isKnownDead(
const Instruction *
I)
const override {
4110 return isAssumedDead(
I) && isKnownDead();
4114 const std::string getAsStr(Attributor *
A)
const override {
4115 return isAssumedDead() ?
"assumed-dead" :
"assumed-live";
4119 bool areAllUsesAssumedDead(Attributor &
A,
Value &V) {
4121 if (
V.getType()->isVoidTy() ||
V.use_empty())
4127 if (!
A.isRunOn(*
I->getFunction()))
4129 bool UsedAssumedInformation =
false;
4130 std::optional<Constant *>
C =
4131 A.getAssumedConstant(V, *
this, UsedAssumedInformation);
4136 auto UsePred = [&](
const Use &
U,
bool &Follow) {
return false; };
4141 return A.checkForAllUses(UsePred, *
this, V,
false,
4142 DepClassTy::REQUIRED,
4147 bool isAssumedSideEffectFree(Attributor &
A, Instruction *
I) {
4151 if (!
I->isTerminator() && !
I->mayHaveSideEffects())
4160 bool IsKnownNoUnwind;
4162 A,
this, CallIRP, DepClassTy::OPTIONAL, IsKnownNoUnwind))
4170struct AAIsDeadFloating :
public AAIsDeadValueImpl {
4171 AAIsDeadFloating(
const IRPosition &IRP, Attributor &
A)
4172 : AAIsDeadValueImpl(IRP,
A) {}
4176 AAIsDeadValueImpl::initialize(
A);
4179 indicatePessimisticFixpoint();
4184 if (!isAssumedSideEffectFree(
A,
I)) {
4186 indicatePessimisticFixpoint();
4188 removeAssumedBits(HAS_NO_EFFECT);
4192 bool isDeadFence(Attributor &
A, FenceInst &FI) {
4193 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
4195 if (!ExecDomainAA || !ExecDomainAA->isNoOpFence(FI))
4197 A.recordDependence(*ExecDomainAA, *
this, DepClassTy::OPTIONAL);
4201 bool isDeadStore(Attributor &
A, StoreInst &SI,
4202 SmallSetVector<Instruction *, 8> *AssumeOnlyInst =
nullptr) {
4204 if (
SI.isVolatile())
4210 bool UsedAssumedInformation =
false;
4211 if (!AssumeOnlyInst) {
4212 PotentialCopies.clear();
4214 UsedAssumedInformation)) {
4217 <<
"[AAIsDead] Could not determine potential copies of store!\n");
4221 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Store has " << PotentialCopies.size()
4222 <<
" potential copies.\n");
4224 InformationCache &InfoCache =
A.getInfoCache();
4227 UsedAssumedInformation))
4231 auto &UserI = cast<Instruction>(*U.getUser());
4232 if (InfoCache.isOnlyUsedByAssume(UserI)) {
4234 AssumeOnlyInst->insert(&UserI);
4237 return A.isAssumedDead(U,
this,
nullptr, UsedAssumedInformation);
4243 <<
" is assumed live!\n");
4249 const std::string getAsStr(Attributor *
A)
const override {
4253 return "assumed-dead-store";
4256 return "assumed-dead-fence";
4257 return AAIsDeadValueImpl::getAsStr(
A);
4264 if (!isDeadStore(
A, *SI))
4265 return indicatePessimisticFixpoint();
4267 if (!isDeadFence(
A, *FI))
4268 return indicatePessimisticFixpoint();
4270 if (!isAssumedSideEffectFree(
A,
I))
4271 return indicatePessimisticFixpoint();
4272 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4273 return indicatePessimisticFixpoint();
4278 bool isRemovableStore()
const override {
4279 return isAssumed(IS_REMOVABLE) &&
isa<StoreInst>(&getAssociatedValue());
4284 Value &
V = getAssociatedValue();
4291 SmallSetVector<Instruction *, 8> AssumeOnlyInst;
4292 bool IsDead = isDeadStore(
A, *SI, &AssumeOnlyInst);
4295 A.deleteAfterManifest(*
I);
4296 for (
size_t i = 0; i < AssumeOnlyInst.
size(); ++i) {
4298 for (
auto *Usr : AOI->
users())
4300 A.deleteAfterManifest(*AOI);
4306 A.deleteAfterManifest(*FI);
4310 A.deleteAfterManifest(*
I);
4318 void trackStatistics()
const override {
4324 SmallSetVector<Value *, 4> PotentialCopies;
4327struct AAIsDeadArgument :
public AAIsDeadFloating {
4328 AAIsDeadArgument(
const IRPosition &IRP, Attributor &
A)
4329 : AAIsDeadFloating(IRP,
A) {}
4333 Argument &Arg = *getAssociatedArgument();
4334 if (
A.isValidFunctionSignatureRewrite(Arg, {}))
4335 if (
A.registerFunctionSignatureRewrite(
4339 return ChangeStatus::CHANGED;
4341 return ChangeStatus::UNCHANGED;
4348struct AAIsDeadCallSiteArgument :
public AAIsDeadValueImpl {
4349 AAIsDeadCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
4350 : AAIsDeadValueImpl(IRP,
A) {}
4354 AAIsDeadValueImpl::initialize(
A);
4356 indicatePessimisticFixpoint();
4365 Argument *Arg = getAssociatedArgument();
4367 return indicatePessimisticFixpoint();
4369 auto *ArgAA =
A.getAAFor<AAIsDead>(*
this, ArgPos, DepClassTy::REQUIRED);
4371 return indicatePessimisticFixpoint();
4380 "Expected undef values to be filtered out!");
4382 if (
A.changeUseAfterManifest(U, UV))
4383 return ChangeStatus::CHANGED;
4384 return ChangeStatus::UNCHANGED;
4391struct AAIsDeadCallSiteReturned :
public AAIsDeadFloating {
4392 AAIsDeadCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4393 : AAIsDeadFloating(IRP,
A) {}
4396 bool isAssumedDead()
const override {
4397 return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;
4402 AAIsDeadFloating::initialize(
A);
4404 indicatePessimisticFixpoint();
4409 IsAssumedSideEffectFree = isAssumedSideEffectFree(
A, getCtxI());
4415 if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(
A, getCtxI())) {
4416 IsAssumedSideEffectFree =
false;
4417 Changed = ChangeStatus::CHANGED;
4419 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4420 return indicatePessimisticFixpoint();
4425 void trackStatistics()
const override {
4426 if (IsAssumedSideEffectFree)
4433 const std::string getAsStr(Attributor *
A)
const override {
4434 return isAssumedDead()
4436 : (getAssumed() ?
"assumed-dead-users" :
"assumed-live");
4440 bool IsAssumedSideEffectFree =
true;
4443struct AAIsDeadReturned :
public AAIsDeadValueImpl {
4444 AAIsDeadReturned(
const IRPosition &IRP, Attributor &
A)
4445 : AAIsDeadValueImpl(IRP,
A) {}
4450 bool UsedAssumedInformation =
false;
4451 A.checkForAllInstructions([](Instruction &) {
return true; }, *
this,
4452 {Instruction::Ret}, UsedAssumedInformation);
4454 auto PredForCallSite = [&](AbstractCallSite ACS) {
4455 if (ACS.isCallbackCall() || !ACS.getInstruction())
4457 return areAllUsesAssumedDead(
A, *ACS.getInstruction());
4460 if (!
A.checkForAllCallSites(PredForCallSite, *
this,
true,
4461 UsedAssumedInformation))
4462 return indicatePessimisticFixpoint();
4464 return ChangeStatus::UNCHANGED;
4470 bool AnyChange =
false;
4471 UndefValue &UV = *
UndefValue::get(getAssociatedFunction()->getReturnType());
4478 bool UsedAssumedInformation =
false;
4479 A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
4480 UsedAssumedInformation);
4481 return AnyChange ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
4488struct AAIsDeadFunction :
public AAIsDead {
4489 AAIsDeadFunction(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4494 assert(
F &&
"Did expect an anchor function");
4495 if (!isAssumedDeadInternalFunction(
A)) {
4496 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4497 assumeLive(
A,
F->getEntryBlock());
4501 bool isAssumedDeadInternalFunction(Attributor &
A) {
4502 if (!getAnchorScope()->hasLocalLinkage())
4504 bool UsedAssumedInformation =
false;
4505 return A.checkForAllCallSites([](AbstractCallSite) {
return false; }, *
this,
4506 true, UsedAssumedInformation);
4510 const std::string getAsStr(Attributor *
A)
const override {
4511 return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) +
"/" +
4512 std::to_string(getAnchorScope()->
size()) +
"][#TBEP " +
4513 std::to_string(ToBeExploredFrom.size()) +
"][#KDE " +
4514 std::to_string(KnownDeadEnds.size()) +
"]";
4519 assert(getState().isValidState() &&
4520 "Attempted to manifest an invalid state!");
4525 if (AssumedLiveBlocks.empty()) {
4526 A.deleteAfterManifest(
F);
4527 return ChangeStatus::CHANGED;
4533 bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(
F);
4535 KnownDeadEnds.set_union(ToBeExploredFrom);
4536 for (
const Instruction *DeadEndI : KnownDeadEnds) {
4540 bool IsKnownNoReturn;
4548 A.registerInvokeWithDeadSuccessor(
const_cast<InvokeInst &
>(*
II));
4550 A.changeToUnreachableAfterManifest(
4551 const_cast<Instruction *
>(DeadEndI->getNextNode()));
4552 HasChanged = ChangeStatus::CHANGED;
4555 STATS_DECL(AAIsDead, BasicBlock,
"Number of dead basic blocks deleted.");
4556 for (BasicBlock &BB :
F)
4557 if (!AssumedLiveBlocks.count(&BB)) {
4558 A.deleteAfterManifest(BB);
4560 HasChanged = ChangeStatus::CHANGED;
4569 bool isEdgeDead(
const BasicBlock *From,
const BasicBlock *To)
const override {
4572 "Used AAIsDead of the wrong function");
4573 return isValidState() && !AssumedLiveEdges.count(std::make_pair(From, To));
4577 void trackStatistics()
const override {}
4580 bool isAssumedDead()
const override {
return false; }
4583 bool isKnownDead()
const override {
return false; }
4586 bool isAssumedDead(
const BasicBlock *BB)
const override {
4588 "BB must be in the same anchor scope function.");
4592 return !AssumedLiveBlocks.count(BB);
4596 bool isKnownDead(
const BasicBlock *BB)
const override {
4597 return getKnown() && isAssumedDead(BB);
4601 bool isAssumedDead(
const Instruction *
I)
const override {
4602 assert(
I->getParent()->getParent() == getAnchorScope() &&
4603 "Instruction must be in the same anchor scope function.");
4610 if (!AssumedLiveBlocks.count(
I->getParent()))
4616 if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))
4624 bool isKnownDead(
const Instruction *
I)
const override {
4625 return getKnown() && isAssumedDead(
I);
4630 bool assumeLive(Attributor &
A,
const BasicBlock &BB) {
4631 if (!AssumedLiveBlocks.insert(&BB).second)
4638 for (
const Instruction &
I : BB)
4641 if (
F->hasLocalLinkage())
4642 A.markLiveInternalFunction(*
F);
4648 SmallSetVector<const Instruction *, 8> ToBeExploredFrom;
4651 SmallSetVector<const Instruction *, 8> KnownDeadEnds;
4654 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> AssumedLiveEdges;
4657 DenseSet<const BasicBlock *> AssumedLiveBlocks;
4661identifyAliveSuccessors(Attributor &
A,
const CallBase &CB,
4662 AbstractAttribute &AA,
4663 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4666 bool IsKnownNoReturn;
4669 return !IsKnownNoReturn;
4678identifyAliveSuccessors(Attributor &
A,
const InvokeInst &
II,
4679 AbstractAttribute &AA,
4680 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4681 bool UsedAssumedInformation =
4687 if (AAIsDeadFunction::mayCatchAsynchronousExceptions(*
II.getFunction())) {
4688 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4692 bool IsKnownNoUnwind;
4695 UsedAssumedInformation |= !IsKnownNoUnwind;
4697 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4700 return UsedAssumedInformation;
4704identifyAliveSuccessors(Attributor &,
const UncondBrInst &BI,
4705 AbstractAttribute &,
4706 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4712identifyAliveSuccessors(Attributor &
A,
const CondBrInst &BI,
4713 AbstractAttribute &AA,
4714 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4715 bool UsedAssumedInformation =
false;
4716 std::optional<Constant *>
C =
4717 A.getAssumedConstant(*BI.
getCondition(), AA, UsedAssumedInformation);
4727 UsedAssumedInformation =
false;
4729 return UsedAssumedInformation;
4733identifyAliveSuccessors(Attributor &
A,
const SwitchInst &SI,
4734 AbstractAttribute &AA,
4735 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4736 bool UsedAssumedInformation =
false;
4740 UsedAssumedInformation)) {
4742 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4747 if (Values.
empty() ||
4748 (Values.
size() == 1 &&
4751 return UsedAssumedInformation;
4754 Type &Ty = *
SI.getCondition()->getType();
4755 SmallPtrSet<ConstantInt *, 8>
Constants;
4756 auto CheckForConstantInt = [&](
Value *
V) {
4764 if (!
all_of(Values, [&](AA::ValueAndContext &VAC) {
4765 return CheckForConstantInt(VAC.
getValue());
4767 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4769 return UsedAssumedInformation;
4772 unsigned MatchedCases = 0;
4773 for (
const auto &CaseIt :
SI.cases()) {
4774 if (
Constants.count(CaseIt.getCaseValue())) {
4776 AliveSuccessors.
push_back(&CaseIt.getCaseSuccessor()->front());
4783 AliveSuccessors.
push_back(&
SI.getDefaultDest()->front());
4784 return UsedAssumedInformation;
4790 if (AssumedLiveBlocks.empty()) {
4791 if (isAssumedDeadInternalFunction(
A))
4795 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4796 assumeLive(
A,
F->getEntryBlock());
4800 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Live [" << AssumedLiveBlocks.size() <<
"/"
4801 << getAnchorScope()->
size() <<
"] BBs and "
4802 << ToBeExploredFrom.size() <<
" exploration points and "
4803 << KnownDeadEnds.size() <<
" known dead ends\n");
4808 ToBeExploredFrom.end());
4809 decltype(ToBeExploredFrom) NewToBeExploredFrom;
4812 while (!Worklist.
empty()) {
4819 I =
I->getNextNode();
4821 AliveSuccessors.
clear();
4823 bool UsedAssumedInformation =
false;
4824 switch (
I->getOpcode()) {
4828 "Expected non-terminators to be handled already!");
4829 for (
const BasicBlock *SuccBB :
successors(
I->getParent()))
4832 case Instruction::Call:
4834 *
this, AliveSuccessors);
4836 case Instruction::Invoke:
4838 *
this, AliveSuccessors);
4840 case Instruction::UncondBr:
4841 UsedAssumedInformation = identifyAliveSuccessors(
4844 case Instruction::CondBr:
4846 *
this, AliveSuccessors);
4848 case Instruction::Switch:
4850 *
this, AliveSuccessors);
4854 if (UsedAssumedInformation) {
4855 NewToBeExploredFrom.insert(
I);
4856 }
else if (AliveSuccessors.
empty() ||
4857 (
I->isTerminator() &&
4858 AliveSuccessors.
size() <
I->getNumSuccessors())) {
4859 if (KnownDeadEnds.insert(
I))
4864 << AliveSuccessors.
size() <<
" UsedAssumedInformation: "
4865 << UsedAssumedInformation <<
"\n");
4867 for (
const Instruction *AliveSuccessor : AliveSuccessors) {
4868 if (!
I->isTerminator()) {
4869 assert(AliveSuccessors.size() == 1 &&
4870 "Non-terminator expected to have a single successor!");
4874 auto Edge = std::make_pair(
I->getParent(), AliveSuccessor->getParent());
4875 if (AssumedLiveEdges.insert(
Edge).second)
4877 if (assumeLive(
A, *AliveSuccessor->getParent()))
4884 if (NewToBeExploredFrom.size() != ToBeExploredFrom.size() ||
4885 llvm::any_of(NewToBeExploredFrom, [&](
const Instruction *
I) {
4886 return !ToBeExploredFrom.count(I);
4889 ToBeExploredFrom = std::move(NewToBeExploredFrom);
4898 if (ToBeExploredFrom.empty() &&
4899 getAnchorScope()->
size() == AssumedLiveBlocks.size() &&
4900 llvm::all_of(KnownDeadEnds, [](
const Instruction *DeadEndI) {
4901 return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;
4903 return indicatePessimisticFixpoint();
4908struct AAIsDeadCallSite final : AAIsDeadFunction {
4909 AAIsDeadCallSite(
const IRPosition &IRP, Attributor &
A)
4910 : AAIsDeadFunction(IRP,
A) {}
4919 "supported for call sites yet!");
4924 return indicatePessimisticFixpoint();
4928 void trackStatistics()
const override {}
4935struct AADereferenceableImpl : AADereferenceable {
4936 AADereferenceableImpl(
const IRPosition &IRP, Attributor &
A)
4937 : AADereferenceable(IRP,
A) {}
4938 using StateType = DerefState;
4942 Value &
V = *getAssociatedValue().stripPointerCasts();
4944 A.getAttrs(getIRPosition(),
4945 {Attribute::Dereferenceable, Attribute::DereferenceableOrNull},
4948 takeKnownDerefBytesMaximum(Attr.getValueAsInt());
4951 bool IsKnownNonNull;
4953 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNonNull);
4955 bool CanBeNull, CanBeFreed;
4956 takeKnownDerefBytesMaximum(
V.getPointerDereferenceableBytes(
4957 A.getDataLayout(), CanBeNull, CanBeFreed));
4959 if (Instruction *CtxI = getCtxI())
4960 followUsesInMBEC(*
this,
A, getState(), *CtxI);
4965 StateType &getState()
override {
return *
this; }
4966 const StateType &getState()
const override {
return *
this; }
4970 void addAccessedBytesForUse(Attributor &
A,
const Use *U,
const Instruction *
I,
4971 DerefState &State) {
4972 const Value *UseV =
U->get();
4977 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
I->isVolatile())
4982 Loc->Ptr,
Offset,
A.getDataLayout(),
true);
4983 if (
Base &&
Base == &getAssociatedValue())
4984 State.addAccessedBytes(
Offset, Loc->Size.getValue());
4988 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
4989 AADereferenceable::StateType &State) {
4990 bool IsNonNull =
false;
4991 bool TrackUse =
false;
4992 int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
4993 A, *
this, getAssociatedValue(), U,
I, IsNonNull, TrackUse);
4994 LLVM_DEBUG(
dbgs() <<
"[AADereferenceable] Deref bytes: " << DerefBytes
4995 <<
" for instruction " << *
I <<
"\n");
4997 addAccessedBytesForUse(
A, U,
I, State);
4998 State.takeKnownDerefBytesMaximum(DerefBytes);
5005 bool IsKnownNonNull;
5007 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5008 if (IsAssumedNonNull &&
5009 A.hasAttr(getIRPosition(), Attribute::DereferenceableOrNull)) {
5010 A.removeAttrs(getIRPosition(), {Attribute::DereferenceableOrNull});
5011 return ChangeStatus::CHANGED;
5016 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5017 SmallVectorImpl<Attribute> &Attrs)
const override {
5019 bool IsKnownNonNull;
5021 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5022 if (IsAssumedNonNull)
5023 Attrs.emplace_back(Attribute::getWithDereferenceableBytes(
5024 Ctx, getAssumedDereferenceableBytes()));
5026 Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes(
5027 Ctx, getAssumedDereferenceableBytes()));
5031 const std::string getAsStr(Attributor *
A)
const override {
5032 if (!getAssumedDereferenceableBytes())
5033 return "unknown-dereferenceable";
5034 bool IsKnownNonNull;
5035 bool IsAssumedNonNull =
false;
5038 *
A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5039 return std::string(
"dereferenceable") +
5040 (IsAssumedNonNull ?
"" :
"_or_null") +
5041 (isAssumedGlobal() ?
"_globally" :
"") +
"<" +
5042 std::to_string(getKnownDereferenceableBytes()) +
"-" +
5043 std::to_string(getAssumedDereferenceableBytes()) +
">" +
5044 (!
A ?
" [non-null is unknown]" :
"");
5049struct AADereferenceableFloating : AADereferenceableImpl {
5050 AADereferenceableFloating(
const IRPosition &IRP, Attributor &
A)
5051 : AADereferenceableImpl(IRP,
A) {}
5056 bool UsedAssumedInformation =
false;
5058 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5060 Values.
push_back({getAssociatedValue(), getCtxI()});
5063 Stripped = Values.
size() != 1 ||
5064 Values.
front().getValue() != &getAssociatedValue();
5067 const DataLayout &
DL =
A.getDataLayout();
5070 auto VisitValueCB = [&](
const Value &
V) ->
bool {
5072 DL.getIndexSizeInBits(
V.getType()->getPointerAddressSpace());
5073 APInt
Offset(IdxWidth, 0);
5078 const auto *AA =
A.getAAFor<AADereferenceable>(
5080 int64_t DerefBytes = 0;
5081 if (!AA || (!Stripped &&
this == AA)) {
5084 bool CanBeNull, CanBeFreed;
5086 Base->getPointerDereferenceableBytes(
DL, CanBeNull, CanBeFreed);
5087 T.GlobalState.indicatePessimisticFixpoint();
5090 DerefBytes =
DS.DerefBytesState.getAssumed();
5091 T.GlobalState &=
DS.GlobalState;
5097 int64_t OffsetSExt =
Offset.getSExtValue();
5101 T.takeAssumedDerefBytesMinimum(
5102 std::max(int64_t(0), DerefBytes - OffsetSExt));
5107 T.takeKnownDerefBytesMaximum(
5108 std::max(int64_t(0), DerefBytes - OffsetSExt));
5109 T.indicatePessimisticFixpoint();
5110 }
else if (OffsetSExt > 0) {
5116 T.indicatePessimisticFixpoint();
5120 return T.isValidState();
5123 for (
const auto &VAC : Values)
5124 if (!VisitValueCB(*VAC.
getValue()))
5125 return indicatePessimisticFixpoint();
5131 void trackStatistics()
const override {
5137struct AADereferenceableReturned final
5138 : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl> {
5140 AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl>;
5141 AADereferenceableReturned(
const IRPosition &IRP, Attributor &
A)
5145 void trackStatistics()
const override {
5151struct AADereferenceableArgument final
5152 : AAArgumentFromCallSiteArguments<AADereferenceable,
5153 AADereferenceableImpl> {
5155 AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl>;
5156 AADereferenceableArgument(
const IRPosition &IRP, Attributor &
A)
5160 void trackStatistics()
const override {
5166struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {
5167 AADereferenceableCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5168 : AADereferenceableFloating(IRP,
A) {}
5171 void trackStatistics()
const override {
5177struct AADereferenceableCallSiteReturned final
5178 : AACalleeToCallSite<AADereferenceable, AADereferenceableImpl> {
5179 using Base = AACalleeToCallSite<AADereferenceable, AADereferenceableImpl>;
5180 AADereferenceableCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5184 void trackStatistics()
const override {
5194static unsigned getKnownAlignForUse(Attributor &
A, AAAlign &QueryingAA,
5195 Value &AssociatedValue,
const Use *U,
5196 const Instruction *
I,
bool &TrackUse) {
5205 if (
GEP->hasAllConstantIndices())
5210 switch (
II->getIntrinsicID()) {
5211 case Intrinsic::ptrmask: {
5213 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5215 const auto *AlignAA =
A.getAAFor<AAAlign>(
5217 if (ConstVals && ConstVals->isValidState() && ConstVals->isAtFixpoint()) {
5218 unsigned ShiftValue = std::min(ConstVals->getAssumedMinTrailingZeros(),
5220 Align ConstAlign(UINT64_C(1) << ShiftValue);
5221 if (ConstAlign >= AlignAA->getKnownAlign())
5222 return Align(1).value();
5225 return AlignAA->getKnownAlign().
value();
5228 case Intrinsic::amdgcn_make_buffer_rsrc: {
5229 const auto *AlignAA =
A.getAAFor<AAAlign>(
5232 return AlignAA->getKnownAlign().
value();
5250 MA = MaybeAlign(AlignAA->getKnownAlign());
5253 const DataLayout &
DL =
A.getDataLayout();
5254 const Value *UseV =
U->get();
5256 if (
SI->getPointerOperand() == UseV)
5257 MA =
SI->getAlign();
5259 if (LI->getPointerOperand() == UseV)
5260 MA = LI->getAlign();
5262 if (AI->getPointerOperand() == UseV)
5263 MA = AI->getAlign();
5265 if (AI->getPointerOperand() == UseV)
5266 MA = AI->getAlign();
5272 unsigned Alignment = MA->value();
5276 if (
Base == &AssociatedValue) {
5281 uint32_t
gcd = std::gcd(uint32_t(
abs((int32_t)
Offset)), Alignment);
5289struct AAAlignImpl : AAAlign {
5290 AAAlignImpl(
const IRPosition &IRP, Attributor &
A) : AAAlign(IRP,
A) {}
5295 A.getAttrs(getIRPosition(), {Attribute::Alignment},
Attrs);
5297 takeKnownMaximum(Attr.getValueAsInt());
5299 Value &
V = *getAssociatedValue().stripPointerCasts();
5300 takeKnownMaximum(
V.getPointerAlignment(
A.getDataLayout()).value());
5302 if (Instruction *CtxI = getCtxI())
5303 followUsesInMBEC(*
this,
A, getState(), *CtxI);
5311 Value &AssociatedValue = getAssociatedValue();
5313 return ChangeStatus::UNCHANGED;
5315 for (
const Use &U : AssociatedValue.
uses()) {
5317 if (
SI->getPointerOperand() == &AssociatedValue)
5318 if (
SI->getAlign() < getAssumedAlign()) {
5320 "Number of times alignment added to a store");
5321 SI->setAlignment(getAssumedAlign());
5322 InstrChanged = ChangeStatus::CHANGED;
5325 if (LI->getPointerOperand() == &AssociatedValue)
5326 if (LI->getAlign() < getAssumedAlign()) {
5327 LI->setAlignment(getAssumedAlign());
5329 "Number of times alignment added to a load");
5330 InstrChanged = ChangeStatus::CHANGED;
5333 if (RMW->getPointerOperand() == &AssociatedValue) {
5334 if (RMW->getAlign() < getAssumedAlign()) {
5336 "Number of times alignment added to atomicrmw");
5338 RMW->setAlignment(getAssumedAlign());
5339 InstrChanged = ChangeStatus::CHANGED;
5343 if (CAS->getPointerOperand() == &AssociatedValue) {
5344 if (CAS->getAlign() < getAssumedAlign()) {
5346 "Number of times alignment added to cmpxchg");
5347 CAS->setAlignment(getAssumedAlign());
5348 InstrChanged = ChangeStatus::CHANGED;
5356 Align InheritAlign =
5357 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5358 if (InheritAlign >= getAssumedAlign())
5359 return InstrChanged;
5360 return Changed | InstrChanged;
5368 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5369 SmallVectorImpl<Attribute> &Attrs)
const override {
5370 if (getAssumedAlign() > 1)
5372 Attribute::getWithAlignment(Ctx,
Align(getAssumedAlign())));
5376 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5377 AAAlign::StateType &State) {
5378 bool TrackUse =
false;
5380 unsigned int KnownAlign =
5381 getKnownAlignForUse(
A, *
this, getAssociatedValue(), U,
I, TrackUse);
5382 State.takeKnownMaximum(KnownAlign);
5388 const std::string getAsStr(Attributor *
A)
const override {
5389 return "align<" + std::to_string(getKnownAlign().value()) +
"-" +
5390 std::to_string(getAssumedAlign().value()) +
">";
5395struct AAAlignFloating : AAAlignImpl {
5396 AAAlignFloating(
const IRPosition &IRP, Attributor &
A) : AAAlignImpl(IRP,
A) {}
5400 const DataLayout &
DL =
A.getDataLayout();
5403 bool UsedAssumedInformation =
false;
5405 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5407 Values.
push_back({getAssociatedValue(), getCtxI()});
5410 Stripped = Values.
size() != 1 ||
5411 Values.
front().getValue() != &getAssociatedValue();
5415 auto VisitValueCB = [&](
Value &
V) ->
bool {
5419 DepClassTy::REQUIRED);
5420 if (!AA || (!Stripped &&
this == AA)) {
5422 unsigned Alignment = 1;
5435 Alignment =
V.getPointerAlignment(
DL).value();
5438 T.takeKnownMaximum(Alignment);
5439 T.indicatePessimisticFixpoint();
5442 const AAAlign::StateType &
DS = AA->
getState();
5445 return T.isValidState();
5448 for (
const auto &VAC : Values) {
5449 if (!VisitValueCB(*VAC.
getValue()))
5450 return indicatePessimisticFixpoint();
5463struct AAAlignReturned final
5464 : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {
5465 using Base = AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>;
5466 AAAlignReturned(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5473struct AAAlignArgument final
5474 : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {
5475 using Base = AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>;
5476 AAAlignArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5483 if (
A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))
5484 return ChangeStatus::UNCHANGED;
5485 return Base::manifest(
A);
5492struct AAAlignCallSiteArgument final : AAAlignFloating {
5493 AAAlignCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5494 : AAAlignFloating(IRP,
A) {}
5501 if (Argument *Arg = getAssociatedArgument())
5502 if (
A.getInfoCache().isInvolvedInMustTailCall(*Arg))
5503 return ChangeStatus::UNCHANGED;
5505 Align InheritAlign =
5506 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5507 if (InheritAlign >= getAssumedAlign())
5508 Changed = ChangeStatus::UNCHANGED;
5515 if (Argument *Arg = getAssociatedArgument()) {
5518 const auto *ArgAlignAA =
A.getAAFor<AAAlign>(
5521 takeKnownMaximum(ArgAlignAA->getKnownAlign().value());
5531struct AAAlignCallSiteReturned final
5532 : AACalleeToCallSite<AAAlign, AAAlignImpl> {
5533 using Base = AACalleeToCallSite<AAAlign, AAAlignImpl>;
5534 AAAlignCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5540 switch (
II->getIntrinsicID()) {
5541 case Intrinsic::ptrmask: {
5545 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5547 if (ConstVals && ConstVals->isValidState()) {
5548 unsigned ShiftValue =
5549 std::min(ConstVals->getAssumedMinTrailingZeros(),
5550 Value::MaxAlignmentExponent);
5551 Alignment =
Align(UINT64_C(1) << ShiftValue);
5555 const auto *AlignAA =
5557 DepClassTy::REQUIRED);
5559 Alignment = std::max(AlignAA->getAssumedAlign(), Alignment);
5566 std::min(this->getAssumedAlign(), Alignment).value());
5572 case Intrinsic::amdgcn_make_buffer_rsrc: {
5573 const auto *AlignAA =
5575 DepClassTy::REQUIRED);
5578 this->getState(), AlignAA->getAssumedAlign().
value());
5585 return Base::updateImpl(
A);
5594struct AANoReturnImpl :
public AANoReturn {
5595 AANoReturnImpl(
const IRPosition &IRP, Attributor &
A) : AANoReturn(IRP,
A) {}
5601 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
5606 const std::string getAsStr(Attributor *
A)
const override {
5607 return getAssumed() ?
"noreturn" :
"may-return";
5612 auto CheckForNoReturn = [](
Instruction &) {
return false; };
5613 bool UsedAssumedInformation =
false;
5614 if (!
A.checkForAllInstructions(CheckForNoReturn, *
this,
5615 {(unsigned)Instruction::Ret},
5616 UsedAssumedInformation))
5617 return indicatePessimisticFixpoint();
5618 return ChangeStatus::UNCHANGED;
5622struct AANoReturnFunction final : AANoReturnImpl {
5623 AANoReturnFunction(
const IRPosition &IRP, Attributor &
A)
5624 : AANoReturnImpl(IRP,
A) {}
5631struct AANoReturnCallSite final
5632 : AACalleeToCallSite<AANoReturn, AANoReturnImpl> {
5633 AANoReturnCallSite(
const IRPosition &IRP, Attributor &
A)
5634 : AACalleeToCallSite<AANoReturn, AANoReturnImpl>(IRP,
A) {}
5645struct AAInstanceInfoImpl :
public AAInstanceInfo {
5646 AAInstanceInfoImpl(
const IRPosition &IRP, Attributor &
A)
5647 : AAInstanceInfo(IRP,
A) {}
5651 Value &
V = getAssociatedValue();
5653 if (
C->isThreadDependent())
5654 indicatePessimisticFixpoint();
5656 indicateOptimisticFixpoint();
5662 indicateOptimisticFixpoint();
5667 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
5670 indicatePessimisticFixpoint();
5680 Value &
V = getAssociatedValue();
5683 Scope =
I->getFunction();
5686 if (!
Scope->hasLocalLinkage())
5690 return indicateOptimisticFixpoint();
5692 bool IsKnownNoRecurse;
5698 auto UsePred = [&](
const Use &
U,
bool &Follow) {
5713 if (!Callee || !
Callee->hasLocalLinkage())
5717 const auto *ArgInstanceInfoAA =
A.getAAFor<AAInstanceInfo>(
5719 DepClassTy::OPTIONAL);
5720 if (!ArgInstanceInfoAA ||
5721 !ArgInstanceInfoAA->isAssumedUniqueForAnalysis())
5726 A, *CB, *Scope, *
this,
nullptr,
5727 [Scope](
const Function &Fn) {
return &Fn !=
Scope; }))
5734 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
5736 auto *Ptr =
SI->getPointerOperand()->stripPointerCasts();
5744 if (!
A.checkForAllUses(UsePred, *
this, V,
true,
5745 DepClassTy::OPTIONAL,
5746 true, EquivalentUseCB))
5747 return indicatePessimisticFixpoint();
5753 const std::string getAsStr(Attributor *
A)
const override {
5754 return isAssumedUniqueForAnalysis() ?
"<unique [fAa]>" :
"<unknown>";
5758 void trackStatistics()
const override {}
5762struct AAInstanceInfoFloating : AAInstanceInfoImpl {
5763 AAInstanceInfoFloating(
const IRPosition &IRP, Attributor &
A)
5764 : AAInstanceInfoImpl(IRP,
A) {}
5768struct AAInstanceInfoArgument final : AAInstanceInfoFloating {
5769 AAInstanceInfoArgument(
const IRPosition &IRP, Attributor &
A)
5770 : AAInstanceInfoFloating(IRP,
A) {}
5774struct AAInstanceInfoCallSiteArgument final : AAInstanceInfoImpl {
5775 AAInstanceInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5776 : AAInstanceInfoImpl(IRP,
A) {}
5784 Argument *Arg = getAssociatedArgument();
5786 return indicatePessimisticFixpoint();
5789 A.getAAFor<AAInstanceInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
5791 return indicatePessimisticFixpoint();
5797struct AAInstanceInfoReturned final : AAInstanceInfoImpl {
5798 AAInstanceInfoReturned(
const IRPosition &IRP, Attributor &
A)
5799 : AAInstanceInfoImpl(IRP,
A) {
5815struct AAInstanceInfoCallSiteReturned final : AAInstanceInfoFloating {
5816 AAInstanceInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5817 : AAInstanceInfoFloating(IRP,
A) {}
5824 bool IgnoreSubsumingPositions) {
5825 assert(ImpliedAttributeKind == Attribute::Captures &&
5826 "Unexpected attribute kind");
5836 V.getType()->getPointerAddressSpace() == 0)) {
5841 A.getAttrs(IRP, {Attribute::Captures}, Attrs,
5851 {Attribute::Captures, Attribute::ByVal}, Attrs,
5889 bool NoThrow =
F.doesNotThrow();
5890 bool IsVoidReturn =
F.getReturnType()->isVoidTy();
5891 if (
ReadOnly && NoThrow && IsVoidReturn) {
5904 if (NoThrow && IsVoidReturn)
5909 if (!NoThrow || ArgNo < 0 ||
5910 !
F.getAttributes().hasAttrSomewhere(Attribute::Returned))
5913 for (
unsigned U = 0, E =
F.arg_size(); U < E; ++U)
5914 if (
F.hasParamAttribute(U, Attribute::Returned)) {
5915 if (U ==
unsigned(ArgNo))
5942 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5943 SmallVectorImpl<Attribute> &Attrs)
const override {
5944 if (!isAssumedNoCaptureMaybeReturned())
5947 if (isArgumentPosition()) {
5948 if (isAssumedNoCapture())
5949 Attrs.emplace_back(Attribute::get(Ctx, Attribute::Captures));
5951 Attrs.emplace_back(Attribute::get(Ctx,
"no-capture-maybe-returned"));
5956 const std::string getAsStr(Attributor *
A)
const override {
5957 if (isKnownNoCapture())
5958 return "known not-captured";
5959 if (isAssumedNoCapture())
5960 return "assumed not-captured";
5961 if (isKnownNoCaptureMaybeReturned())
5962 return "known not-captured-maybe-returned";
5963 if (isAssumedNoCaptureMaybeReturned())
5964 return "assumed not-captured-maybe-returned";
5965 return "assumed-captured";
5970 bool checkUse(Attributor &
A, AANoCapture::StateType &State,
const Use &U,
5973 LLVM_DEBUG(
dbgs() <<
"[AANoCapture] Check use: " << *
U.get() <<
" in "
5979 return isCapturedIn(State,
true,
true,
5986 return isCapturedIn(State,
true,
true,
5992 return isCapturedIn(State,
false,
false,
5994 return isCapturedIn(State,
true,
true,
6002 return isCapturedIn(State,
true,
true,
6009 bool IsKnownNoCapture;
6010 const AANoCapture *ArgNoCaptureAA =
nullptr;
6012 A,
this, CSArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6014 if (IsAssumedNoCapture)
6015 return isCapturedIn(State,
false,
false,
6019 return isCapturedIn(State,
false,
false,
6024 return isCapturedIn(State,
true,
true,
6031 static bool isCapturedIn(AANoCapture::StateType &State,
bool CapturedInMem,
6032 bool CapturedInInt,
bool CapturedInRet) {
6033 LLVM_DEBUG(
dbgs() <<
" - captures [Mem " << CapturedInMem <<
"|Int "
6034 << CapturedInInt <<
"|Ret " << CapturedInRet <<
"]\n");
6046 const IRPosition &IRP = getIRPosition();
6050 return indicatePessimisticFixpoint();
6057 return indicatePessimisticFixpoint();
6065 T.addKnownBits(NOT_CAPTURED_IN_MEM);
6067 addKnownBits(NOT_CAPTURED_IN_MEM);
6074 auto CheckReturnedArgs = [&](
bool &UsedAssumedInformation) {
6078 UsedAssumedInformation))
6080 bool SeenConstant =
false;
6081 for (
const AA::ValueAndContext &VAC : Values) {
6085 SeenConstant =
true;
6087 VAC.
getValue() == getAssociatedArgument())
6093 bool IsKnownNoUnwind;
6096 bool IsVoidTy =
F->getReturnType()->isVoidTy();
6097 bool UsedAssumedInformation =
false;
6098 if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {
6099 T.addKnownBits(NOT_CAPTURED_IN_RET);
6100 if (
T.isKnown(NOT_CAPTURED_IN_MEM))
6102 if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {
6103 addKnownBits(NOT_CAPTURED_IN_RET);
6104 if (isKnown(NOT_CAPTURED_IN_MEM))
6105 return indicateOptimisticFixpoint();
6110 auto UseCheck = [&](
const Use &
U,
bool &Follow) ->
bool {
6119 return checkUse(
A,
T, U, Follow);
6122 if (!
A.checkForAllUses(UseCheck, *
this, *V))
6123 return indicatePessimisticFixpoint();
6126 auto Assumed = S.getAssumed();
6127 S.intersectAssumedBits(
T.getAssumed());
6128 if (!isAssumedNoCaptureMaybeReturned())
6129 return indicatePessimisticFixpoint();
6135struct AANoCaptureArgument final : AANoCaptureImpl {
6136 AANoCaptureArgument(
const IRPosition &IRP, Attributor &
A)
6137 : AANoCaptureImpl(IRP,
A) {}
6144struct AANoCaptureCallSiteArgument final : AANoCaptureImpl {
6145 AANoCaptureCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6146 : AANoCaptureImpl(IRP,
A) {}
6154 Argument *Arg = getAssociatedArgument();
6156 return indicatePessimisticFixpoint();
6158 bool IsKnownNoCapture;
6159 const AANoCapture *ArgAA =
nullptr;
6161 A,
this, ArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6163 return ChangeStatus::UNCHANGED;
6165 return indicatePessimisticFixpoint();
6170 void trackStatistics()
const override {
6176struct AANoCaptureFloating final : AANoCaptureImpl {
6177 AANoCaptureFloating(
const IRPosition &IRP, Attributor &
A)
6178 : AANoCaptureImpl(IRP,
A) {}
6181 void trackStatistics()
const override {
6187struct AANoCaptureReturned final : AANoCaptureImpl {
6188 AANoCaptureReturned(
const IRPosition &IRP, Attributor &
A)
6189 : AANoCaptureImpl(IRP,
A) {
6204 void trackStatistics()
const override {}
6208struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {
6209 AANoCaptureCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6210 : AANoCaptureImpl(IRP,
A) {}
6216 determineFunctionCaptureCapabilities(getIRPosition(), *
F, *
this);
6220 void trackStatistics()
const override {
6237 dbgs() <<
"[ValueSimplify] is assumed to be "
6240 dbgs() <<
"[ValueSimplify] is assumed to be <none>\n";
6252 if (getAssociatedValue().
getType()->isVoidTy())
6253 indicatePessimisticFixpoint();
6254 if (
A.hasSimplificationCallback(getIRPosition()))
6255 indicatePessimisticFixpoint();
6259 const std::string getAsStr(Attributor *
A)
const override {
6261 dbgs() <<
"SAV: " << (bool)SimplifiedAssociatedValue <<
" ";
6262 if (SimplifiedAssociatedValue && *SimplifiedAssociatedValue)
6263 dbgs() <<
"SAV: " << **SimplifiedAssociatedValue <<
" ";
6265 return isValidState() ? (isAtFixpoint() ?
"simplified" :
"maybe-simple")
6270 void trackStatistics()
const override {}
6273 std::optional<Value *>
6274 getAssumedSimplifiedValue(Attributor &
A)
const override {
6275 return SimplifiedAssociatedValue;
6282 static Value *ensureType(Attributor &
A,
Value &V,
Type &Ty, Instruction *CtxI,
6286 if (CtxI &&
V.getType()->canLosslesslyBitCastTo(&Ty))
6288 : BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6297 static Value *reproduceInst(Attributor &
A,
6298 const AbstractAttribute &QueryingAA,
6299 Instruction &
I,
Type &Ty, Instruction *CtxI,
6301 assert(CtxI &&
"Cannot reproduce an instruction without context!");
6302 if (
Check && (
I.mayReadFromMemory() ||
6307 Value *NewOp = reproduceValue(
A, QueryingAA, *
Op, Ty, CtxI,
Check, VMap);
6309 assert(
Check &&
"Manifest of new value unexpectedly failed!");
6331 static Value *reproduceValue(Attributor &
A,
6332 const AbstractAttribute &QueryingAA,
Value &V,
6333 Type &Ty, Instruction *CtxI,
bool Check,
6335 if (
const auto &NewV = VMap.
lookup(&V))
6337 bool UsedAssumedInformation =
false;
6338 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
6340 if (!SimpleV.has_value())
6344 EffectiveV = *SimpleV;
6349 return ensureType(
A, *EffectiveV, Ty, CtxI,
Check);
6351 if (
Value *NewV = reproduceInst(
A, QueryingAA, *
I, Ty, CtxI,
Check, VMap))
6352 return ensureType(
A, *NewV, Ty, CtxI,
Check);
6358 Value *manifestReplacementValue(Attributor &
A, Instruction *CtxI)
const {
6359 Value *NewV = SimplifiedAssociatedValue
6360 ? *SimplifiedAssociatedValue
6362 if (NewV && NewV != &getAssociatedValue()) {
6366 if (reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6368 return reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6376 bool checkAndUpdate(Attributor &
A,
const AbstractAttribute &QueryingAA,
6377 const IRPosition &IRP,
bool Simplify =
true) {
6378 bool UsedAssumedInformation =
false;
6381 QueryingValueSimplified =
A.getAssumedSimplified(
6383 return unionAssumed(QueryingValueSimplified);
6387 template <
typename AAType>
bool askSimplifiedValueFor(Attributor &
A) {
6388 if (!getAssociatedValue().
getType()->isIntegerTy())
6393 A.getAAFor<AAType>(*
this, getIRPosition(), DepClassTy::NONE);
6397 std::optional<Constant *> COpt = AA->getAssumedConstant(
A);
6400 SimplifiedAssociatedValue = std::nullopt;
6401 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6404 if (
auto *
C = *COpt) {
6405 SimplifiedAssociatedValue =
C;
6406 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6412 bool askSimplifiedValueForOtherAAs(Attributor &
A) {
6413 if (askSimplifiedValueFor<AAValueConstantRange>(
A))
6415 if (askSimplifiedValueFor<AAPotentialConstantValues>(
A))
6423 for (
auto &U : getAssociatedValue().uses()) {
6428 IP =
PHI->getIncomingBlock(U)->getTerminator();
6429 if (
auto *NewV = manifestReplacementValue(
A, IP)) {
6431 <<
" -> " << *NewV <<
" :: " << *
this <<
"\n");
6432 if (
A.changeUseAfterManifest(U, *NewV))
6433 Changed = ChangeStatus::CHANGED;
6437 return Changed | AAValueSimplify::manifest(
A);
6442 SimplifiedAssociatedValue = &getAssociatedValue();
6443 return AAValueSimplify::indicatePessimisticFixpoint();
6447struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
6448 AAValueSimplifyArgument(
const IRPosition &IRP, Attributor &
A)
6449 : AAValueSimplifyImpl(IRP,
A) {}
6452 AAValueSimplifyImpl::initialize(
A);
6453 if (
A.hasAttr(getIRPosition(),
6454 {Attribute::InAlloca, Attribute::Preallocated,
6455 Attribute::StructRet, Attribute::Nest, Attribute::ByVal},
6457 indicatePessimisticFixpoint();
6464 Argument *Arg = getAssociatedArgument();
6470 return indicatePessimisticFixpoint();
6473 auto Before = SimplifiedAssociatedValue;
6475 auto PredForCallSite = [&](AbstractCallSite ACS) {
6476 const IRPosition &ACSArgPos =
6487 bool UsedAssumedInformation =
false;
6488 std::optional<Constant *> SimpleArgOp =
6489 A.getAssumedConstant(ACSArgPos, *
this, UsedAssumedInformation);
6496 return unionAssumed(*SimpleArgOp);
6501 bool UsedAssumedInformation =
false;
6502 if (hasCallBaseContext() &&
6503 getCallBaseContext()->getCalledOperand() == Arg->
getParent())
6505 AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
6507 Success =
A.checkForAllCallSites(PredForCallSite, *
this,
true,
6508 UsedAssumedInformation);
6511 if (!askSimplifiedValueForOtherAAs(
A))
6512 return indicatePessimisticFixpoint();
6515 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6516 : ChangeStatus ::CHANGED;
6520 void trackStatistics()
const override {
6525struct AAValueSimplifyReturned : AAValueSimplifyImpl {
6526 AAValueSimplifyReturned(
const IRPosition &IRP, Attributor &
A)
6527 : AAValueSimplifyImpl(IRP,
A) {}
6530 std::optional<Value *>
6531 getAssumedSimplifiedValue(Attributor &
A)
const override {
6532 if (!isValidState())
6534 return SimplifiedAssociatedValue;
6539 auto Before = SimplifiedAssociatedValue;
6543 return checkAndUpdate(
6548 bool UsedAssumedInformation =
false;
6549 if (!
A.checkForAllInstructions(ReturnInstCB, *
this, {Instruction::Ret},
6550 UsedAssumedInformation))
6551 if (!askSimplifiedValueForOtherAAs(
A))
6552 return indicatePessimisticFixpoint();
6555 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6556 : ChangeStatus ::CHANGED;
6562 return ChangeStatus::UNCHANGED;
6566 void trackStatistics()
const override {
6571struct AAValueSimplifyFloating : AAValueSimplifyImpl {
6572 AAValueSimplifyFloating(
const IRPosition &IRP, Attributor &
A)
6573 : AAValueSimplifyImpl(IRP,
A) {}
6577 AAValueSimplifyImpl::initialize(
A);
6578 Value &
V = getAnchorValue();
6582 indicatePessimisticFixpoint();
6587 auto Before = SimplifiedAssociatedValue;
6588 if (!askSimplifiedValueForOtherAAs(
A))
6589 return indicatePessimisticFixpoint();
6592 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6593 : ChangeStatus ::CHANGED;
6597 void trackStatistics()
const override {
6602struct AAValueSimplifyFunction : AAValueSimplifyImpl {
6603 AAValueSimplifyFunction(
const IRPosition &IRP, Attributor &
A)
6604 : AAValueSimplifyImpl(IRP,
A) {}
6608 SimplifiedAssociatedValue =
nullptr;
6609 indicateOptimisticFixpoint();
6614 "AAValueSimplify(Function|CallSite)::updateImpl will not be called");
6617 void trackStatistics()
const override {
6622struct AAValueSimplifyCallSite : AAValueSimplifyFunction {
6623 AAValueSimplifyCallSite(
const IRPosition &IRP, Attributor &
A)
6624 : AAValueSimplifyFunction(IRP,
A) {}
6626 void trackStatistics()
const override {
6631struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl {
6632 AAValueSimplifyCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6633 : AAValueSimplifyImpl(IRP,
A) {}
6636 AAValueSimplifyImpl::initialize(
A);
6637 Function *Fn = getAssociatedFunction();
6638 assert(Fn &&
"Did expect an associted function");
6639 for (Argument &Arg : Fn->
args()) {
6644 checkAndUpdate(
A, *
this, IRP))
6645 indicateOptimisticFixpoint();
6647 indicatePessimisticFixpoint();
6655 return indicatePessimisticFixpoint();
6658 void trackStatistics()
const override {
6663struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
6664 AAValueSimplifyCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6665 : AAValueSimplifyFloating(IRP,
A) {}
6671 auto *FloatAA =
A.lookupAAFor<AAValueSimplify>(
6673 if (FloatAA && FloatAA->getState().isValidState())
6676 if (
auto *NewV = manifestReplacementValue(
A, getCtxI())) {
6678 ->getArgOperandUse(getCallSiteArgNo());
6679 if (
A.changeUseAfterManifest(U, *NewV))
6680 Changed = ChangeStatus::CHANGED;
6683 return Changed | AAValueSimplify::manifest(
A);
6686 void trackStatistics()
const override {
6694struct AAHeapToStackFunction final :
public AAHeapToStack {
6696 static bool isGlobalizedLocal(
const CallBase &CB) {
6698 return A.
isValid() &&
A.getValueAsString() ==
"__kmpc_alloc_shared";
6701 struct AllocationInfo {
6706 bool IsGlobalizedLocal =
false;
6713 } Status = STACK_DUE_TO_USE;
6717 bool HasPotentiallyFreeingUnknownUses =
false;
6721 bool MoveAllocaIntoEntry =
true;
6724 SmallSetVector<CallBase *, 1> PotentialFreeCalls{};
6727 struct DeallocationInfo {
6735 bool MightFreeUnknownObjects =
false;
6738 SmallSetVector<CallBase *, 1> PotentialAllocationCalls{};
6741 AAHeapToStackFunction(
const IRPosition &IRP, Attributor &
A)
6742 : AAHeapToStack(IRP,
A) {}
6744 ~AAHeapToStackFunction()
override {
6747 for (
auto &It : AllocationInfos)
6748 It.second->~AllocationInfo();
6749 for (
auto &It : DeallocationInfos)
6750 It.second->~DeallocationInfo();
6754 AAHeapToStack::initialize(
A);
6757 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6764 DeallocationInfos[CB] =
new (
A.Allocator) DeallocationInfo{CB, FreedOp};
6771 auto *I8Ty = Type::getInt8Ty(CB->
getParent()->getContext());
6773 AllocationInfo *AI =
new (
A.Allocator) AllocationInfo{CB};
6774 AllocationInfos[CB] = AI;
6775 AI->IsGlobalizedLocal = isGlobalizedLocal(*CB);
6781 bool UsedAssumedInformation =
false;
6782 bool Success =
A.checkForAllCallLikeInstructions(
6783 AllocationIdentifierCB, *
this, UsedAssumedInformation,
6787 assert(
Success &&
"Did not expect the call base visit callback to fail!");
6790 [](
const IRPosition &,
const AbstractAttribute *,
6791 bool &) -> std::optional<Value *> {
return nullptr; };
6792 for (
const auto &It : AllocationInfos)
6795 for (
const auto &It : DeallocationInfos)
6800 const std::string getAsStr(Attributor *
A)
const override {
6801 unsigned NumH2SMallocs = 0, NumInvalidMallocs = 0;
6802 for (
const auto &It : AllocationInfos) {
6803 if (It.second->Status == AllocationInfo::INVALID)
6804 ++NumInvalidMallocs;
6808 return "[H2S] Mallocs Good/Bad: " + std::to_string(NumH2SMallocs) +
"/" +
6809 std::to_string(NumInvalidMallocs);
6813 void trackStatistics()
const override {
6815 MallocCalls, Function,
6816 "Number of malloc/calloc/aligned_alloc calls converted to allocas");
6817 for (
const auto &It : AllocationInfos)
6818 if (It.second->Status != AllocationInfo::INVALID)
6822 bool isAssumedHeapToStack(
const CallBase &CB)
const override {
6824 if (AllocationInfo *AI =
6825 AllocationInfos.lookup(
const_cast<CallBase *
>(&CB)))
6826 return AI->Status != AllocationInfo::INVALID;
6830 bool isAssumedHeapToStackRemovedFree(CallBase &CB)
const override {
6831 if (!isValidState())
6834 for (
const auto &It : AllocationInfos) {
6835 AllocationInfo &AI = *It.second;
6836 if (AI.Status == AllocationInfo::INVALID)
6839 if (AI.PotentialFreeCalls.count(&CB))
6847 assert(getState().isValidState() &&
6848 "Attempted to manifest an invalid state!");
6852 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6854 for (
auto &It : AllocationInfos) {
6855 AllocationInfo &AI = *It.second;
6856 if (AI.Status == AllocationInfo::INVALID)
6859 for (CallBase *FreeCall : AI.PotentialFreeCalls) {
6860 LLVM_DEBUG(
dbgs() <<
"H2S: Removing free call: " << *FreeCall <<
"\n");
6861 A.deleteAfterManifest(*FreeCall);
6862 HasChanged = ChangeStatus::CHANGED;
6865 LLVM_DEBUG(
dbgs() <<
"H2S: Removing malloc-like call: " << *AI.CB
6868 auto Remark = [&](OptimizationRemark
OR) {
6869 if (AI.IsGlobalizedLocal)
6870 return OR <<
"Moving globalized variable to the stack.";
6871 return OR <<
"Moving memory allocation from the heap to the stack.";
6873 if (AI.IsGlobalizedLocal)
6874 A.emitRemark<OptimizationRemark>(AI.CB,
"OMP110",
Remark);
6876 A.emitRemark<OptimizationRemark>(AI.CB,
"HeapToStack",
Remark);
6878 const DataLayout &
DL =
A.getInfoCache().getDL();
6880 std::optional<APInt> SizeAPI =
getSize(
A, *
this, AI);
6882 Size = ConstantInt::get(AI.CB->getContext(), *SizeAPI);
6884 LLVMContext &Ctx = AI.CB->getContext();
6885 ObjectSizeOpts Opts;
6886 ObjectSizeOffsetEvaluator Eval(
DL, TLI, Ctx, Opts);
6887 SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);
6894 ?
F->getEntryBlock().begin()
6895 : AI.CB->getIterator();
6898 if (MaybeAlign RetAlign = AI.CB->getRetAlign())
6899 Alignment = std::max(Alignment, *RetAlign);
6901 std::optional<APInt> AlignmentAPI = getAPInt(
A, *
this, *Align);
6902 assert(AlignmentAPI && AlignmentAPI->getZExtValue() > 0 &&
6903 "Expected an alignment during manifest!");
6905 std::max(Alignment,
assumeAligned(AlignmentAPI->getZExtValue()));
6909 unsigned AS =
DL.getAllocaAddrSpace();
6911 new AllocaInst(Type::getInt8Ty(
F->getContext()), AS,
Size, Alignment,
6912 AI.CB->getName() +
".h2s", IP);
6914 if (Alloca->
getType() != AI.CB->getType())
6915 Alloca = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6916 Alloca, AI.CB->getType(),
"malloc_cast", AI.CB->getIterator());
6918 auto *I8Ty = Type::getInt8Ty(
F->getContext());
6921 "Must be able to materialize initial memory state of allocation");
6926 auto *NBB =
II->getNormalDest();
6928 A.deleteAfterManifest(*AI.CB);
6930 A.deleteAfterManifest(*AI.CB);
6939 Builder.CreateMemSet(Alloca, InitVal,
Size, std::nullopt);
6941 HasChanged = ChangeStatus::CHANGED;
6947 std::optional<APInt> getAPInt(Attributor &
A,
const AbstractAttribute &AA,
6949 bool UsedAssumedInformation =
false;
6950 std::optional<Constant *> SimpleV =
6951 A.getAssumedConstant(V, AA, UsedAssumedInformation);
6953 return APInt(64, 0);
6955 return CI->getValue();
6956 return std::nullopt;
6959 std::optional<APInt>
getSize(Attributor &
A,
const AbstractAttribute &AA,
6960 AllocationInfo &AI) {
6961 auto Mapper = [&](
const Value *
V) ->
const Value * {
6962 bool UsedAssumedInformation =
false;
6963 if (std::optional<Constant *> SimpleV =
6964 A.getAssumedConstant(*V, AA, UsedAssumedInformation))
6971 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6977 MapVector<CallBase *, AllocationInfo *> AllocationInfos;
6981 MapVector<CallBase *, DeallocationInfo *> DeallocationInfos;
6986ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &
A) {
6989 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6991 const auto *LivenessAA =
6994 MustBeExecutedContextExplorer *Explorer =
6995 A.getInfoCache().getMustBeExecutedContextExplorer();
6997 bool StackIsAccessibleByOtherThreads =
6998 A.getInfoCache().stackIsAccessibleByOtherThreads();
7001 A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(*F);
7002 std::optional<bool> MayContainIrreducibleControl;
7004 if (&
F->getEntryBlock() == &BB)
7006 if (!MayContainIrreducibleControl.has_value())
7008 if (*MayContainIrreducibleControl)
7017 bool HasUpdatedFrees =
false;
7019 auto UpdateFrees = [&]() {
7020 HasUpdatedFrees =
true;
7022 for (
auto &It : DeallocationInfos) {
7023 DeallocationInfo &DI = *It.second;
7026 if (DI.MightFreeUnknownObjects)
7030 bool UsedAssumedInformation =
false;
7031 if (
A.isAssumedDead(*DI.CB,
this, LivenessAA, UsedAssumedInformation,
7038 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown underlying object for free!\n");
7039 DI.MightFreeUnknownObjects =
true;
7052 DI.MightFreeUnknownObjects =
true;
7056 AllocationInfo *AI = AllocationInfos.lookup(ObjCB);
7058 LLVM_DEBUG(
dbgs() <<
"[H2S] Free of a non-allocation object: " << *Obj
7060 DI.MightFreeUnknownObjects =
true;
7064 DI.PotentialAllocationCalls.insert(ObjCB);
7068 auto FreeCheck = [&](AllocationInfo &AI) {
7072 if (!StackIsAccessibleByOtherThreads) {
7077 dbgs() <<
"[H2S] found an escaping use, stack is not accessible by "
7078 "other threads and function is not nosync:\n");
7082 if (!HasUpdatedFrees)
7086 if (AI.PotentialFreeCalls.size() != 1) {
7088 << AI.PotentialFreeCalls.size() <<
"\n");
7091 CallBase *UniqueFree = *AI.PotentialFreeCalls.begin();
7092 DeallocationInfo *DI = DeallocationInfos.lookup(UniqueFree);
7095 dbgs() <<
"[H2S] unique free call was not known as deallocation call "
7096 << *UniqueFree <<
"\n");
7099 if (DI->MightFreeUnknownObjects) {
7101 dbgs() <<
"[H2S] unique free call might free unknown allocations\n");
7104 if (DI->PotentialAllocationCalls.empty())
7106 if (DI->PotentialAllocationCalls.size() > 1) {
7108 << DI->PotentialAllocationCalls.size()
7109 <<
" different allocations\n");
7112 if (*DI->PotentialAllocationCalls.begin() != AI.CB) {
7115 <<
"[H2S] unique free call not known to free this allocation but "
7116 << **DI->PotentialAllocationCalls.begin() <<
"\n");
7121 if (!AI.IsGlobalizedLocal) {
7123 if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
7124 LLVM_DEBUG(
dbgs() <<
"[H2S] unique free call might not be executed "
7125 "with the allocation "
7126 << *UniqueFree <<
"\n");
7133 auto UsesCheck = [&](AllocationInfo &AI) {
7134 bool ValidUsesOnly =
true;
7136 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
7141 if (
SI->getValueOperand() ==
U.get()) {
7143 <<
"[H2S] escaping store to memory: " << *UserI <<
"\n");
7144 ValidUsesOnly =
false;
7153 if (DeallocationInfos.count(CB)) {
7154 AI.PotentialFreeCalls.insert(CB);
7161 bool IsKnownNoCapture;
7170 if (!IsAssumedNoCapture ||
7171 (!AI.IsGlobalizedLocal && !IsAssumedNoFree)) {
7172 AI.HasPotentiallyFreeingUnknownUses |= !IsAssumedNoFree;
7175 auto Remark = [&](OptimizationRemarkMissed ORM) {
7177 <<
"Could not move globalized variable to the stack. "
7178 "Variable is potentially captured in call. Mark "
7179 "parameter as `__attribute__((noescape))` to override.";
7182 if (ValidUsesOnly && AI.IsGlobalizedLocal)
7183 A.emitRemark<OptimizationRemarkMissed>(CB,
"OMP113",
Remark);
7186 ValidUsesOnly =
false;
7199 ValidUsesOnly =
false;
7202 if (!
A.checkForAllUses(Pred, *
this, *AI.CB,
false,
7204 [&](
const Use &OldU,
const Use &NewU) {
7205 auto *SI = dyn_cast<StoreInst>(OldU.getUser());
7206 return !SI || StackIsAccessibleByOtherThreads ||
7207 AA::isAssumedThreadLocalObject(
7208 A, *SI->getPointerOperand(), *this);
7211 return ValidUsesOnly;
7216 for (
auto &It : AllocationInfos) {
7217 AllocationInfo &AI = *It.second;
7218 if (AI.Status == AllocationInfo::INVALID)
7222 std::optional<APInt> APAlign = getAPInt(
A, *
this, *Align);
7226 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown allocation alignment: " << *AI.CB
7228 AI.Status = AllocationInfo::INVALID;
7233 !APAlign->isPowerOf2()) {
7234 LLVM_DEBUG(
dbgs() <<
"[H2S] Invalid allocation alignment: " << APAlign
7236 AI.Status = AllocationInfo::INVALID;
7247 dbgs() <<
"[H2S] Unknown allocation size: " << *AI.CB <<
"\n";
7249 dbgs() <<
"[H2S] Allocation size too large: " << *AI.CB <<
" vs. "
7253 AI.Status = AllocationInfo::INVALID;
7259 switch (AI.Status) {
7260 case AllocationInfo::STACK_DUE_TO_USE:
7263 AI.Status = AllocationInfo::STACK_DUE_TO_FREE;
7265 case AllocationInfo::STACK_DUE_TO_FREE:
7268 AI.Status = AllocationInfo::INVALID;
7271 case AllocationInfo::INVALID:
7278 bool IsGlobalizedLocal = AI.IsGlobalizedLocal;
7279 if (AI.MoveAllocaIntoEntry &&
7280 (!
Size.has_value() ||
7281 (!IsGlobalizedLocal && IsInLoop(*AI.CB->getParent()))))
7282 AI.MoveAllocaIntoEntry =
false;
7291struct AAPrivatizablePtrImpl :
public AAPrivatizablePtr {
7292 AAPrivatizablePtrImpl(
const IRPosition &IRP, Attributor &
A)
7293 : AAPrivatizablePtr(IRP,
A), PrivatizableType(std::nullopt) {}
7296 AAPrivatizablePtr::indicatePessimisticFixpoint();
7297 PrivatizableType =
nullptr;
7298 return ChangeStatus::CHANGED;
7304 virtual std::optional<Type *> identifyPrivatizableType(Attributor &
A) = 0;
7308 std::optional<Type *> combineTypes(std::optional<Type *> T0,
7309 std::optional<Type *>
T1) {
7319 std::optional<Type *> getPrivatizableType()
const override {
7320 return PrivatizableType;
7323 const std::string getAsStr(Attributor *
A)
const override {
7324 return isAssumedPrivatizablePtr() ?
"[priv]" :
"[no-priv]";
7328 std::optional<Type *> PrivatizableType;
7333struct AAPrivatizablePtrArgument final :
public AAPrivatizablePtrImpl {
7334 AAPrivatizablePtrArgument(
const IRPosition &IRP, Attributor &
A)
7335 : AAPrivatizablePtrImpl(IRP,
A) {}
7338 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7341 bool UsedAssumedInformation =
false;
7343 A.getAttrs(getIRPosition(), {Attribute::ByVal},
Attrs,
7345 if (!
Attrs.empty() &&
7346 A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *
this,
7347 true, UsedAssumedInformation))
7348 return Attrs[0].getValueAsType();
7350 std::optional<Type *> Ty;
7351 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
7359 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7368 A.getAAFor<AAPrivatizablePtr>(*
this, ACSArgPos, DepClassTy::REQUIRED);
7371 std::optional<Type *> CSTy = PrivCSArgAA->getPrivatizableType();
7374 dbgs() <<
"[AAPrivatizablePtr] ACSPos: " << ACSArgPos <<
", CSTy: ";
7378 dbgs() <<
"<nullptr>";
7383 Ty = combineTypes(Ty, CSTy);
7386 dbgs() <<
" : New Type: ";
7388 (*Ty)->print(
dbgs());
7390 dbgs() <<
"<nullptr>";
7399 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7400 UsedAssumedInformation))
7407 PrivatizableType = identifyPrivatizableType(
A);
7408 if (!PrivatizableType)
7409 return ChangeStatus::UNCHANGED;
7410 if (!*PrivatizableType)
7411 return indicatePessimisticFixpoint();
7416 DepClassTy::OPTIONAL);
7419 if (!
A.hasAttr(getIRPosition(), Attribute::ByVal) &&
7422 return indicatePessimisticFixpoint();
7428 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7432 Function &Fn = *getIRPosition().getAnchorScope();
7434 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(Fn);
7436 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Missing TTI for function "
7438 return indicatePessimisticFixpoint();
7441 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7448 bool UsedAssumedInformation =
false;
7449 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7450 UsedAssumedInformation)) {
7452 dbgs() <<
"[AAPrivatizablePtr] ABI incompatibility detected for "
7454 return indicatePessimisticFixpoint();
7458 Argument *Arg = getAssociatedArgument();
7459 if (!
A.isValidFunctionSignatureRewrite(*Arg, ReplacementTypes)) {
7461 return indicatePessimisticFixpoint();
7468 auto IsCompatiblePrivArgOfCallback = [&](CallBase &CB) {
7471 for (
const Use *U : CallbackUses) {
7472 AbstractCallSite CBACS(U);
7473 assert(CBACS && CBACS.isCallbackCall());
7474 for (Argument &CBArg : CBACS.getCalledFunction()->args()) {
7475 int CBArgNo = CBACS.getCallArgOperandNo(CBArg);
7479 <<
"[AAPrivatizablePtr] Argument " << *Arg
7480 <<
"check if can be privatized in the context of its parent ("
7482 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7484 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7485 <<
")\n[AAPrivatizablePtr] " << CBArg <<
" : "
7486 << CBACS.getCallArgOperand(CBArg) <<
" vs "
7488 <<
"[AAPrivatizablePtr] " << CBArg <<
" : "
7489 << CBACS.getCallArgOperandNo(CBArg) <<
" vs " << ArgNo <<
"\n";
7492 if (CBArgNo !=
int(ArgNo))
7494 const auto *CBArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7496 if (CBArgPrivAA && CBArgPrivAA->isValidState()) {
7497 auto CBArgPrivTy = CBArgPrivAA->getPrivatizableType();
7500 if (*CBArgPrivTy == PrivatizableType)
7505 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7506 <<
" cannot be privatized in the context of its parent ("
7508 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7510 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7511 <<
").\n[AAPrivatizablePtr] for which the argument "
7512 "privatization is not compatible.\n";
7522 auto IsCompatiblePrivArgOfDirectCS = [&](AbstractCallSite ACS) {
7526 "Expected a direct call operand for callback call operand");
7531 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7532 <<
" check if be privatized in the context of its parent ("
7534 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7536 << DCArgNo <<
"@" << DCCallee->
getName() <<
").\n";
7539 if (
unsigned(DCArgNo) < DCCallee->
arg_size()) {
7540 const auto *DCArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7542 DepClassTy::REQUIRED);
7543 if (DCArgPrivAA && DCArgPrivAA->isValidState()) {
7544 auto DCArgPrivTy = DCArgPrivAA->getPrivatizableType();
7547 if (*DCArgPrivTy == PrivatizableType)
7553 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7554 <<
" cannot be privatized in the context of its parent ("
7556 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7559 <<
").\n[AAPrivatizablePtr] for which the argument "
7560 "privatization is not compatible.\n";
7568 auto IsCompatiblePrivArgOfOtherCallSite = [&](AbstractCallSite ACS) {
7572 return IsCompatiblePrivArgOfDirectCS(ACS);
7576 if (!
A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *
this,
true,
7577 UsedAssumedInformation))
7578 return indicatePessimisticFixpoint();
7580 return ChangeStatus::UNCHANGED;
7586 identifyReplacementTypes(
Type *PrivType,
7587 SmallVectorImpl<Type *> &ReplacementTypes) {
7590 assert(PrivType &&
"Expected privatizable type!");
7594 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++)
7595 ReplacementTypes.
push_back(PrivStructType->getElementType(u));
7597 ReplacementTypes.
append(PrivArrayType->getNumElements(),
7598 PrivArrayType->getElementType());
7607 static void createInitialization(
Type *PrivType,
Value &
Base, Function &
F,
7609 assert(PrivType &&
"Expected privatizable type!");
7612 const DataLayout &
DL =
F.getDataLayout();
7616 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7617 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7620 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7623 Type *PointeeTy = PrivArrayType->getElementType();
7624 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7625 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7627 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7630 new StoreInst(
F.getArg(ArgNo), &
Base, IP);
7636 void createReplacementValues(Align Alignment,
Type *PrivType,
7638 SmallVectorImpl<Value *> &ReplacementValues) {
7640 assert(PrivType &&
"Expected privatizable type!");
7648 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7649 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7650 Type *PointeeTy = PrivStructType->getElementType(u);
7653 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7654 L->setAlignment(Alignment);
7658 Type *PointeeTy = PrivArrayType->getElementType();
7659 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7660 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7662 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7663 L->setAlignment(Alignment);
7668 L->setAlignment(Alignment);
7675 if (!PrivatizableType)
7676 return ChangeStatus::UNCHANGED;
7677 assert(*PrivatizableType &&
"Expected privatizable type!");
7683 bool UsedAssumedInformation =
false;
7684 if (!
A.checkForAllInstructions(
7685 [&](Instruction &
I) {
7686 CallInst &CI = cast<CallInst>(I);
7687 if (CI.isTailCall())
7688 TailCalls.push_back(&CI);
7691 *
this, {Instruction::Call}, UsedAssumedInformation))
7692 return ChangeStatus::UNCHANGED;
7694 Argument *Arg = getAssociatedArgument();
7697 const auto *AlignAA =
7704 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7706 BasicBlock &EntryBB = ReplacementFn.getEntryBlock();
7708 const DataLayout &
DL = IP->getDataLayout();
7709 unsigned AS =
DL.getAllocaAddrSpace();
7710 Instruction *AI =
new AllocaInst(*PrivatizableType, AS,
7711 Arg->
getName() +
".priv", IP);
7712 createInitialization(*PrivatizableType, *AI, ReplacementFn,
7713 ArgIt->getArgNo(), IP);
7716 AI = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
7720 for (CallInst *CI : TailCalls)
7721 CI->setTailCall(
false);
7728 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7729 AbstractCallSite ACS, SmallVectorImpl<Value *> &NewArgOperands) {
7732 createReplacementValues(
7733 AlignAA ? AlignAA->getAssumedAlign() :
Align(0),
7734 *PrivatizableType, ACS,
7742 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7745 if (
A.registerFunctionSignatureRewrite(*Arg, ReplacementTypes,
7746 std::move(FnRepairCB),
7747 std::move(ACSRepairCB)))
7748 return ChangeStatus::CHANGED;
7749 return ChangeStatus::UNCHANGED;
7753 void trackStatistics()
const override {
7758struct AAPrivatizablePtrFloating :
public AAPrivatizablePtrImpl {
7759 AAPrivatizablePtrFloating(
const IRPosition &IRP, Attributor &
A)
7760 : AAPrivatizablePtrImpl(IRP,
A) {}
7765 indicatePessimisticFixpoint();
7770 "updateImpl will not be called");
7774 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7777 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] No underlying object found!\n");
7784 return AI->getAllocatedType();
7786 auto *PrivArgAA =
A.getAAFor<AAPrivatizablePtr>(
7788 if (PrivArgAA && PrivArgAA->isAssumedPrivatizablePtr())
7789 return PrivArgAA->getPrivatizableType();
7792 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Underlying object neither valid "
7793 "alloca nor privatizable argument: "
7799 void trackStatistics()
const override {
7804struct AAPrivatizablePtrCallSiteArgument final
7805 :
public AAPrivatizablePtrFloating {
7806 AAPrivatizablePtrCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
7807 : AAPrivatizablePtrFloating(IRP,
A) {}
7811 if (
A.hasAttr(getIRPosition(), Attribute::ByVal))
7812 indicateOptimisticFixpoint();
7817 PrivatizableType = identifyPrivatizableType(
A);
7818 if (!PrivatizableType)
7819 return ChangeStatus::UNCHANGED;
7820 if (!*PrivatizableType)
7821 return indicatePessimisticFixpoint();
7823 const IRPosition &IRP = getIRPosition();
7824 bool IsKnownNoCapture;
7826 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoCapture);
7827 if (!IsAssumedNoCapture) {
7828 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might be captured!\n");
7829 return indicatePessimisticFixpoint();
7832 bool IsKnownNoAlias;
7834 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
7835 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might alias!\n");
7836 return indicatePessimisticFixpoint();
7841 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer is written!\n");
7842 return indicatePessimisticFixpoint();
7845 return ChangeStatus::UNCHANGED;
7849 void trackStatistics()
const override {
7854struct AAPrivatizablePtrCallSiteReturned final
7855 :
public AAPrivatizablePtrFloating {
7856 AAPrivatizablePtrCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
7857 : AAPrivatizablePtrFloating(IRP,
A) {}
7862 indicatePessimisticFixpoint();
7866 void trackStatistics()
const override {
7871struct AAPrivatizablePtrReturned final :
public AAPrivatizablePtrFloating {
7872 AAPrivatizablePtrReturned(
const IRPosition &IRP, Attributor &
A)
7873 : AAPrivatizablePtrFloating(IRP,
A) {}
7878 indicatePessimisticFixpoint();
7882 void trackStatistics()
const override {
7892struct AAMemoryBehaviorImpl :
public AAMemoryBehavior {
7893 AAMemoryBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
7894 : AAMemoryBehavior(IRP,
A) {}
7898 intersectAssumedBits(BEST_STATE);
7899 getKnownStateFromValue(
A, getIRPosition(), getState());
7900 AAMemoryBehavior::initialize(
A);
7904 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
7905 BitIntegerState &State,
7906 bool IgnoreSubsumingPositions =
false) {
7908 A.getAttrs(IRP, AttrKinds, Attrs, IgnoreSubsumingPositions);
7910 switch (Attr.getKindAsEnum()) {
7911 case Attribute::ReadNone:
7914 case Attribute::ReadOnly:
7917 case Attribute::WriteOnly:
7926 if (!
I->mayReadFromMemory())
7928 if (!
I->mayWriteToMemory())
7934 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
7935 SmallVectorImpl<Attribute> &Attrs)
const override {
7938 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));
7940 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));
7941 else if (isAssumedWriteOnly())
7942 Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));
7948 const IRPosition &IRP = getIRPosition();
7950 if (
A.hasAttr(IRP, Attribute::ReadNone,
7952 return ChangeStatus::UNCHANGED;
7961 return ChangeStatus::UNCHANGED;
7964 A.removeAttrs(IRP, AttrKinds);
7967 A.removeAttrs(IRP, Attribute::Writable);
7974 const std::string getAsStr(Attributor *
A)
const override {
7979 if (isAssumedWriteOnly())
7981 return "may-read/write";
7985 static const Attribute::AttrKind AttrKinds[3];
7989 Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};
7992struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {
7993 AAMemoryBehaviorFloating(
const IRPosition &IRP, Attributor &
A)
7994 : AAMemoryBehaviorImpl(IRP,
A) {}
8000 void trackStatistics()
const override {
8005 else if (isAssumedWriteOnly())
8012 bool followUsersOfUseIn(Attributor &
A,
const Use &U,
8013 const Instruction *UserI);
8016 void analyzeUseIn(Attributor &
A,
const Use &U,
const Instruction *UserI);
8020struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
8021 AAMemoryBehaviorArgument(
const IRPosition &IRP, Attributor &
A)
8022 : AAMemoryBehaviorFloating(IRP,
A) {}
8026 intersectAssumedBits(BEST_STATE);
8027 const IRPosition &IRP = getIRPosition();
8031 bool HasByVal =
A.hasAttr(IRP, {Attribute::ByVal},
8033 getKnownStateFromValue(
A, IRP, getState(),
8040 return ChangeStatus::UNCHANGED;
8044 if (
A.hasAttr(getIRPosition(),
8045 {Attribute::InAlloca, Attribute::Preallocated})) {
8046 removeKnownBits(NO_WRITES);
8047 removeAssumedBits(NO_WRITES);
8049 A.removeAttrs(getIRPosition(), AttrKinds);
8050 return AAMemoryBehaviorFloating::manifest(
A);
8054 void trackStatistics()
const override {
8059 else if (isAssumedWriteOnly())
8064struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {
8065 AAMemoryBehaviorCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
8066 : AAMemoryBehaviorArgument(IRP,
A) {}
8072 Argument *Arg = getAssociatedArgument();
8074 indicatePessimisticFixpoint();
8078 addKnownBits(NO_WRITES);
8079 removeKnownBits(NO_READS);
8080 removeAssumedBits(NO_READS);
8082 AAMemoryBehaviorArgument::initialize(
A);
8083 if (getAssociatedFunction()->isDeclaration())
8084 indicatePessimisticFixpoint();
8093 Argument *Arg = getAssociatedArgument();
8096 A.getAAFor<AAMemoryBehavior>(*
this, ArgPos, DepClassTy::REQUIRED);
8098 return indicatePessimisticFixpoint();
8103 void trackStatistics()
const override {
8108 else if (isAssumedWriteOnly())
8114struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {
8115 AAMemoryBehaviorCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
8116 : AAMemoryBehaviorFloating(IRP,
A) {}
8120 AAMemoryBehaviorImpl::initialize(
A);
8125 return ChangeStatus::UNCHANGED;
8129 void trackStatistics()
const override {}
8133struct AAMemoryBehaviorFunction final :
public AAMemoryBehaviorImpl {
8134 AAMemoryBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
8135 : AAMemoryBehaviorImpl(IRP,
A) {}
8151 else if (isAssumedWriteOnly())
8154 A.removeAttrs(getIRPosition(), AttrKinds);
8157 for (Argument &Arg :
F.args())
8159 return A.manifestAttrs(getIRPosition(),
8160 Attribute::getWithMemoryEffects(
F.getContext(), ME));
8164 void trackStatistics()
const override {
8169 else if (isAssumedWriteOnly())
8175struct AAMemoryBehaviorCallSite final
8176 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl> {
8177 AAMemoryBehaviorCallSite(
const IRPosition &IRP, Attributor &
A)
8178 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl>(IRP,
A) {}
8189 else if (isAssumedWriteOnly())
8192 A.removeAttrs(getIRPosition(), AttrKinds);
8195 for (Use &U : CB.
args())
8197 Attribute::Writable);
8198 return A.manifestAttrs(
8199 getIRPosition(), Attribute::getWithMemoryEffects(CB.
getContext(), ME));
8203 void trackStatistics()
const override {
8208 else if (isAssumedWriteOnly())
8213ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &
A) {
8216 auto AssumedState = getAssumed();
8223 const auto *MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
8225 if (MemBehaviorAA) {
8226 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8227 return !isAtFixpoint();
8232 if (
I.mayReadFromMemory())
8233 removeAssumedBits(NO_READS);
8234 if (
I.mayWriteToMemory())
8235 removeAssumedBits(NO_WRITES);
8236 return !isAtFixpoint();
8239 bool UsedAssumedInformation =
false;
8240 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8241 UsedAssumedInformation))
8242 return indicatePessimisticFixpoint();
8248ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &
A) {
8250 const IRPosition &IRP = getIRPosition();
8261 const auto *FnMemAA =
8264 FnMemAssumedState = FnMemAA->getAssumed();
8265 S.addKnownBits(FnMemAA->getKnown());
8266 if ((S.getAssumed() & FnMemAA->getAssumed()) == S.getAssumed())
8272 auto AssumedState = S.getAssumed();
8278 bool IsKnownNoCapture;
8279 const AANoCapture *ArgNoCaptureAA =
nullptr;
8284 if (!IsAssumedNoCapture &&
8286 S.intersectAssumedBits(FnMemAssumedState);
8292 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
8294 LLVM_DEBUG(
dbgs() <<
"[AAMemoryBehavior] Use: " << *U <<
" in " << *UserI
8302 Follow = followUsersOfUseIn(
A, U, UserI);
8306 analyzeUseIn(
A, U, UserI);
8308 return !isAtFixpoint();
8311 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue()))
8312 return indicatePessimisticFixpoint();
8318bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &
A,
const Use &U,
8319 const Instruction *UserI) {
8337 if (
U.get()->getType()->isPointerTy()) {
8339 bool IsKnownNoCapture;
8348void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &
A,
const Use &U,
8349 const Instruction *UserI) {
8356 case Instruction::Load:
8358 removeAssumedBits(NO_READS);
8361 case Instruction::Store:
8366 removeAssumedBits(NO_WRITES);
8368 indicatePessimisticFixpoint();
8371 case Instruction::Call:
8372 case Instruction::CallBr:
8373 case Instruction::Invoke: {
8380 indicatePessimisticFixpoint();
8387 removeAssumedBits(NO_READS);
8394 if (
U.get()->getType()->isPointerTy())
8398 const auto *MemBehaviorAA =
8404 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8412 removeAssumedBits(NO_READS);
8414 removeAssumedBits(NO_WRITES);
8426 return "all memory";
8429 std::string S =
"memory:";
8435 S +=
"internal global,";
8437 S +=
"external global,";
8441 S +=
"inaccessible,";
8455 AccessKind2Accesses.fill(
nullptr);
8458 ~AAMemoryLocationImpl()
override {
8461 for (AccessSet *AS : AccessKind2Accesses)
8468 intersectAssumedBits(BEST_STATE);
8469 getKnownStateFromValue(
A, getIRPosition(), getState());
8470 AAMemoryLocation::initialize(
A);
8474 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
8475 BitIntegerState &State,
8476 bool IgnoreSubsumingPositions =
false) {
8485 bool UseArgMemOnly =
true;
8487 if (AnchorFn &&
A.isRunOn(*AnchorFn))
8491 A.getAttrs(IRP, {Attribute::Memory},
Attrs, IgnoreSubsumingPositions);
8500 State.
addKnownBits(inverseLocation(NO_INACCESSIBLE_MEM,
true,
true));
8505 State.
addKnownBits(inverseLocation(NO_ARGUMENT_MEM,
true,
true));
8509 A.manifestAttrs(IRP,
8510 Attribute::getWithMemoryEffects(
8519 NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM,
true,
true));
8523 A.manifestAttrs(IRP,
8524 Attribute::getWithMemoryEffects(
8534 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
8535 SmallVectorImpl<Attribute> &Attrs)
const override {
8542 else if (isAssumedInaccessibleMemOnly())
8543 Attrs.push_back(Attribute::getWithMemoryEffects(
8545 else if (isAssumedArgMemOnly())
8548 else if (isAssumedInaccessibleOrArgMemOnly())
8549 Attrs.push_back(Attribute::getWithMemoryEffects(
8559 const IRPosition &IRP = getIRPosition();
8563 if (DeducedAttrs.
size() != 1)
8564 return ChangeStatus::UNCHANGED;
8567 return A.manifestAttrs(IRP, Attribute::getWithMemoryEffects(
8572 bool checkForAllAccessesToMemoryKind(
8574 MemoryLocationsKind)>
8576 MemoryLocationsKind RequestedMLK)
const override {
8577 if (!isValidState())
8580 MemoryLocationsKind AssumedMLK = getAssumedNotAccessedLocation();
8581 if (AssumedMLK == NO_LOCATIONS)
8585 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS;
8586 CurMLK *= 2, ++Idx) {
8587 if (CurMLK & RequestedMLK)
8590 if (
const AccessSet *
Accesses = AccessKind2Accesses[Idx])
8591 for (
const AccessInfo &AI : *
Accesses)
8592 if (!Pred(AI.I, AI.Ptr, AI.Kind, CurMLK))
8605 MemoryLocationsKind KnownMLK = getKnown();
8607 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2)
8608 if (!(CurMLK & KnownMLK))
8609 updateStateAndAccessesMap(getState(), CurMLK,
I,
nullptr,
Changed,
8610 getAccessKindFromInst(
I));
8611 return AAMemoryLocation::indicatePessimisticFixpoint();
8631 bool operator()(
const AccessInfo &
LHS,
const AccessInfo &
RHS)
const {
8635 return LHS.Ptr <
RHS.Ptr;
8636 if (
LHS.Kind !=
RHS.Kind)
8637 return LHS.Kind <
RHS.Kind;
8644 using AccessSet = SmallSet<AccessInfo, 2, AccessInfo>;
8645 std::array<AccessSet *, llvm::ConstantLog2<VALID_STATE>()>
8646 AccessKind2Accesses;
8651 categorizeArgumentPointerLocations(Attributor &
A, CallBase &CB,
8652 AAMemoryLocation::StateType &AccessedLocs,
8657 categorizeAccessedLocations(Attributor &
A, Instruction &
I,
bool &
Changed);
8660 AccessKind getAccessKindFromInst(
const Instruction *
I) {
8663 AK =
I->mayReadFromMemory() ? READ :
NONE;
8672 void updateStateAndAccessesMap(AAMemoryLocation::StateType &State,
8673 MemoryLocationsKind MLK,
const Instruction *
I,
8682 if (MLK == NO_UNKOWN_MEM)
8684 State.removeAssumedBits(MLK);
8689 void categorizePtrValue(Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8690 AAMemoryLocation::StateType &State,
bool &
Changed,
8691 unsigned AccessAS = 0);
8697void AAMemoryLocationImpl::categorizePtrValue(
8698 Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8700 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize pointer locations for "
8705 unsigned ObjectAS =
Obj.getType()->getPointerAddressSpace();
8707 MemoryLocationsKind MLK = NO_LOCATIONS;
8727 MLK = NO_ARGUMENT_MEM;
8733 if (GVar->isConstant())
8736 if (GV->hasLocalLinkage())
8737 MLK = NO_GLOBAL_INTERNAL_MEM;
8739 MLK = NO_GLOBAL_EXTERNAL_MEM;
8747 bool IsKnownNoAlias;
8751 MLK = NO_MALLOCED_MEM;
8753 MLK = NO_UNKOWN_MEM;
8755 MLK = NO_UNKOWN_MEM;
8758 assert(MLK != NO_LOCATIONS &&
"No location specified!");
8759 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Ptr value can be categorized: "
8760 << Obj <<
" -> " << getMemoryLocationsAsStr(MLK) <<
"\n");
8762 getAccessKindFromInst(&
I));
8767 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
8771 dbgs() <<
"[AAMemoryLocation] Pointer locations not categorized\n");
8772 updateStateAndAccessesMap(
State, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8773 getAccessKindFromInst(&
I));
8778 dbgs() <<
"[AAMemoryLocation] Accessed locations with pointer locations: "
8782void AAMemoryLocationImpl::categorizeArgumentPointerLocations(
8785 for (
unsigned ArgNo = 0,
E = CB.
arg_size(); ArgNo <
E; ++ArgNo) {
8794 const auto *ArgOpMemLocationAA =
8797 if (ArgOpMemLocationAA && ArgOpMemLocationAA->isAssumedReadNone())
8802 categorizePtrValue(
A, CB, *ArgOp, AccessedLocs,
Changed);
8807AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &
A, Instruction &
I,
8809 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize accessed locations for "
8813 AccessedLocs.intersectAssumedBits(NO_LOCATIONS);
8818 const auto *CBMemLocationAA =
A.getAAFor<AAMemoryLocation>(
8821 <<
" [" << CBMemLocationAA <<
"]\n");
8822 if (!CBMemLocationAA) {
8823 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
8824 Changed, getAccessKindFromInst(&
I));
8825 return NO_UNKOWN_MEM;
8828 if (CBMemLocationAA->isAssumedReadNone())
8829 return NO_LOCATIONS;
8831 if (CBMemLocationAA->isAssumedInaccessibleMemOnly()) {
8832 updateStateAndAccessesMap(AccessedLocs, NO_INACCESSIBLE_MEM, &
I,
nullptr,
8833 Changed, getAccessKindFromInst(&
I));
8834 return AccessedLocs.getAssumed();
8837 uint32_t CBAssumedNotAccessedLocs =
8838 CBMemLocationAA->getAssumedNotAccessedLocation();
8841 uint32_t CBAssumedNotAccessedLocsNoArgMem =
8842 CBAssumedNotAccessedLocs | NO_ARGUMENT_MEM | NO_GLOBAL_MEM;
8844 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2) {
8845 if (CBAssumedNotAccessedLocsNoArgMem & CurMLK)
8847 updateStateAndAccessesMap(AccessedLocs, CurMLK, &
I,
nullptr,
Changed,
8848 getAccessKindFromInst(&
I));
8853 bool HasGlobalAccesses = ((~CBAssumedNotAccessedLocs) & NO_GLOBAL_MEM);
8854 if (HasGlobalAccesses) {
8857 updateStateAndAccessesMap(AccessedLocs, MLK, &
I, Ptr,
Changed,
8858 getAccessKindFromInst(&
I));
8861 if (!CBMemLocationAA->checkForAllAccessesToMemoryKind(
8862 AccessPred, inverseLocation(NO_GLOBAL_MEM,
false,
false)))
8863 return AccessedLocs.getWorstState();
8867 dbgs() <<
"[AAMemoryLocation] Accessed state before argument handling: "
8868 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8871 bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM);
8873 categorizeArgumentPointerLocations(
A, *CB, AccessedLocs,
Changed);
8876 dbgs() <<
"[AAMemoryLocation] Accessed state after argument handling: "
8877 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8879 return AccessedLocs.getAssumed();
8884 dbgs() <<
"[AAMemoryLocation] Categorize memory access with pointer: "
8885 <<
I <<
" [" << *Ptr <<
"]\n");
8886 categorizePtrValue(
A,
I, *Ptr, AccessedLocs,
Changed,
8887 Ptr->getType()->getPointerAddressSpace());
8888 return AccessedLocs.getAssumed();
8891 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Failed to categorize instruction: "
8893 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8894 getAccessKindFromInst(&
I));
8895 return AccessedLocs.getAssumed();
8899struct AAMemoryLocationFunction final :
public AAMemoryLocationImpl {
8900 AAMemoryLocationFunction(
const IRPosition &IRP, Attributor &
A)
8901 : AAMemoryLocationImpl(IRP,
A) {}
8906 const auto *MemBehaviorAA =
8907 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
8910 return indicateOptimisticFixpoint();
8912 "AAMemoryLocation was not read-none but AAMemoryBehavior was!");
8913 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
8914 return ChangeStatus::UNCHANGED;
8918 auto AssumedState = getAssumed();
8922 MemoryLocationsKind MLK = categorizeAccessedLocations(
A,
I,
Changed);
8923 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Accessed locations for " <<
I
8924 <<
": " << getMemoryLocationsAsStr(MLK) <<
"\n");
8925 removeAssumedBits(inverseLocation(MLK,
false,
false));
8928 return getAssumedNotAccessedLocation() != VALID_STATE;
8931 bool UsedAssumedInformation =
false;
8932 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8933 UsedAssumedInformation))
8934 return indicatePessimisticFixpoint();
8936 Changed |= AssumedState != getAssumed();
8937 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8941 void trackStatistics()
const override {
8944 else if (isAssumedArgMemOnly())
8946 else if (isAssumedInaccessibleMemOnly())
8948 else if (isAssumedInaccessibleOrArgMemOnly())
8954struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {
8955 AAMemoryLocationCallSite(
const IRPosition &IRP, Attributor &
A)
8956 : AAMemoryLocationImpl(IRP,
A) {}
8967 A.getAAFor<AAMemoryLocation>(*
this, FnPos, DepClassTy::REQUIRED);
8969 return indicatePessimisticFixpoint();
8973 updateStateAndAccessesMap(getState(), MLK,
I, Ptr,
Changed,
8974 getAccessKindFromInst(
I));
8977 if (!FnAA->checkForAllAccessesToMemoryKind(AccessPred, ALL_LOCATIONS))
8978 return indicatePessimisticFixpoint();
8979 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8983 void trackStatistics()
const override {
8993struct AADenormalFPMathImpl :
public AADenormalFPMath {
8994 AADenormalFPMathImpl(
const IRPosition &IRP, Attributor &
A)
8995 : AADenormalFPMath(IRP,
A) {}
8997 const std::string getAsStr(Attributor *
A)
const override {
8998 std::string Str(
"AADenormalFPMath[");
8999 raw_string_ostream OS(Str);
9001 DenormalState Known = getKnown();
9002 if (Known.Mode.isValid())
9003 OS <<
"denormal-fp-math=" << Known.Mode;
9007 if (Known.ModeF32.isValid())
9008 OS <<
" denormal-fp-math-f32=" << Known.ModeF32;
9014struct AADenormalFPMathFunction final : AADenormalFPMathImpl {
9015 AADenormalFPMathFunction(
const IRPosition &IRP, Attributor &
A)
9016 : AADenormalFPMathImpl(IRP,
A) {}
9020 DenormalFPEnv DenormEnv =
F->getDenormalFPEnv();
9030 auto CheckCallSite = [=, &Change, &
A](AbstractCallSite CS) {
9033 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
9035 const auto *CallerInfo =
A.getAAFor<AADenormalFPMath>(
9041 CallerInfo->getState());
9045 bool AllCallSitesKnown =
true;
9046 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
9047 return indicatePessimisticFixpoint();
9049 if (Change == ChangeStatus::CHANGED && isModeFixed())
9055 LLVMContext &Ctx = getAssociatedFunction()->getContext();
9061 DenormalFPEnv KnownEnv(Known.Mode, Known.ModeF32);
9064 AttrToRemove.
push_back(Attribute::DenormalFPEnv);
9067 Ctx, Attribute::DenormalFPEnv,
9068 DenormalFPEnv(Known.Mode, Known.ModeF32).toIntValue()));
9071 auto &IRP = getIRPosition();
9074 return A.removeAttrs(IRP, AttrToRemove) |
9075 A.manifestAttrs(IRP, AttrToAdd,
true);
9078 void trackStatistics()
const override {
9087struct AAValueConstantRangeImpl : AAValueConstantRange {
9088 using StateType = IntegerRangeState;
9089 AAValueConstantRangeImpl(
const IRPosition &IRP, Attributor &
A)
9090 : AAValueConstantRange(IRP,
A) {}
9094 if (
A.hasSimplificationCallback(getIRPosition())) {
9095 indicatePessimisticFixpoint();
9100 intersectKnown(getConstantRangeFromSCEV(
A, getCtxI()));
9103 intersectKnown(getConstantRangeFromLVI(
A, getCtxI()));
9107 const std::string getAsStr(Attributor *
A)
const override {
9109 llvm::raw_string_ostream OS(Str);
9111 getKnown().print(OS);
9113 getAssumed().print(OS);
9120 const SCEV *getSCEV(Attributor &
A,
const Instruction *
I =
nullptr)
const {
9121 if (!getAnchorScope())
9124 ScalarEvolution *SE =
9125 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9128 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
9134 const SCEV *S = SE->
getSCEV(&getAssociatedValue());
9143 ConstantRange getConstantRangeFromSCEV(Attributor &
A,
9144 const Instruction *
I =
nullptr)
const {
9145 if (!getAnchorScope())
9148 ScalarEvolution *SE =
9149 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9152 const SCEV *S = getSCEV(
A,
I);
9162 getConstantRangeFromLVI(Attributor &
A,
9163 const Instruction *CtxI =
nullptr)
const {
9164 if (!getAnchorScope())
9167 LazyValueInfo *LVI =
9168 A.getInfoCache().getAnalysisResultForFunction<LazyValueAnalysis>(
9183 bool isValidCtxInstructionForOutsideAnalysis(Attributor &
A,
9184 const Instruction *CtxI,
9185 bool AllowAACtxI)
const {
9186 if (!CtxI || (!AllowAACtxI && CtxI == getCtxI()))
9198 InformationCache &InfoCache =
A.getInfoCache();
9199 const DominatorTree *DT =
9210 getKnownConstantRange(Attributor &
A,
9211 const Instruction *CtxI =
nullptr)
const override {
9212 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9216 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9217 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9218 return getKnown().intersectWith(SCEVR).intersectWith(LVIR);
9223 getAssumedConstantRange(Attributor &
A,
9224 const Instruction *CtxI =
nullptr)
const override {
9229 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9231 return getAssumed();
9233 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9234 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9235 return getAssumed().intersectWith(SCEVR).intersectWith(LVIR);
9240 getMDNodeForConstantRange(
Type *Ty, LLVMContext &Ctx,
9241 const ConstantRange &AssumedConstantRange) {
9243 Ty, AssumedConstantRange.
getLower())),
9245 Ty, AssumedConstantRange.
getUpper()))};
9250 static bool isBetterRange(
const ConstantRange &Assumed,
9251 const Instruction &
I) {
9255 std::optional<ConstantRange> Known;
9259 }
else if (MDNode *KnownRanges =
I.getMetadata(LLVMContext::MD_range)) {
9265 if (KnownRanges->getNumOperands() > 2)
9268 ConstantInt *
Lower =
9270 ConstantInt *
Upper =
9273 Known.emplace(
Lower->getValue(),
Upper->getValue());
9275 return !Known || (*Known != Assumed && Known->contains(Assumed));
9280 setRangeMetadataIfisBetterRange(Instruction *
I,
9281 const ConstantRange &AssumedConstantRange) {
9282 if (isBetterRange(AssumedConstantRange, *
I)) {
9283 I->setMetadata(LLVMContext::MD_range,
9284 getMDNodeForConstantRange(
I->getType(),
I->getContext(),
9285 AssumedConstantRange));
9292 setRangeRetAttrIfisBetterRange(Attributor &
A,
const IRPosition &IRP,
9294 const ConstantRange &AssumedConstantRange) {
9295 if (isBetterRange(AssumedConstantRange, *
I)) {
9296 A.manifestAttrs(IRP,
9297 Attribute::get(
I->getContext(), Attribute::Range,
9298 AssumedConstantRange),
9308 ConstantRange AssumedConstantRange = getAssumedConstantRange(
A);
9311 auto &
V = getAssociatedValue();
9315 assert(
I == getCtxI() &&
"Should not annotate an instruction which is "
9316 "not the context instruction");
9318 if (setRangeMetadataIfisBetterRange(
I, AssumedConstantRange))
9319 Changed = ChangeStatus::CHANGED;
9321 if (setRangeRetAttrIfisBetterRange(
A, getIRPosition(),
I,
9322 AssumedConstantRange))
9323 Changed = ChangeStatus::CHANGED;
9331struct AAValueConstantRangeArgument final
9332 : AAArgumentFromCallSiteArguments<
9333 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9335 using Base = AAArgumentFromCallSiteArguments<
9336 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9338 AAValueConstantRangeArgument(
const IRPosition &IRP, Attributor &
A)
9342 void trackStatistics()
const override {
9347struct AAValueConstantRangeReturned
9348 : AAReturnedFromReturnedValues<AAValueConstantRange,
9349 AAValueConstantRangeImpl,
9350 AAValueConstantRangeImpl::StateType,
9353 AAReturnedFromReturnedValues<AAValueConstantRange,
9354 AAValueConstantRangeImpl,
9355 AAValueConstantRangeImpl::StateType,
9357 AAValueConstantRangeReturned(
const IRPosition &IRP, Attributor &
A)
9362 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9363 indicatePessimisticFixpoint();
9367 void trackStatistics()
const override {
9372struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
9373 AAValueConstantRangeFloating(
const IRPosition &IRP, Attributor &
A)
9374 : AAValueConstantRangeImpl(IRP,
A) {}
9378 AAValueConstantRangeImpl::initialize(
A);
9382 Value &
V = getAssociatedValue();
9385 unionAssumed(ConstantRange(
C->getValue()));
9386 indicateOptimisticFixpoint();
9392 unionAssumed(ConstantRange(APInt(
getBitWidth(), 0)));
9393 indicateOptimisticFixpoint();
9405 if (
auto *RangeMD = LI->getMetadata(LLVMContext::MD_range)) {
9416 indicatePessimisticFixpoint();
9419 << getAssociatedValue() <<
"\n");
9422 bool calculateBinaryOperator(
9423 Attributor &
A, BinaryOperator *BinOp, IntegerRangeState &
T,
9424 const Instruction *CtxI,
9425 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9430 bool UsedAssumedInformation =
false;
9431 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9434 if (!SimplifiedLHS.has_value())
9436 if (!*SimplifiedLHS)
9438 LHS = *SimplifiedLHS;
9440 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9443 if (!SimplifiedRHS.has_value())
9445 if (!*SimplifiedRHS)
9447 RHS = *SimplifiedRHS;
9453 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9455 DepClassTy::REQUIRED);
9459 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9461 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9463 DepClassTy::REQUIRED);
9467 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9469 auto AssumedRange = LHSAARange.binaryOp(BinOp->
getOpcode(), RHSAARange);
9471 T.unionAssumed(AssumedRange);
9475 return T.isValidState();
9478 bool calculateCastInst(
9479 Attributor &
A, CastInst *CastI, IntegerRangeState &
T,
9480 const Instruction *CtxI,
9481 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9487 bool UsedAssumedInformation =
false;
9488 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9491 if (!SimplifiedOpV.has_value())
9493 if (!*SimplifiedOpV)
9495 OpV = *SimplifiedOpV;
9500 auto *OpAA =
A.getAAFor<AAValueConstantRange>(
9502 DepClassTy::REQUIRED);
9506 T.unionAssumed(OpAA->getAssumed().castOp(CastI->
getOpcode(),
9508 return T.isValidState();
9512 calculateCmpInst(Attributor &
A, CmpInst *CmpI, IntegerRangeState &
T,
9513 const Instruction *CtxI,
9514 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9519 bool UsedAssumedInformation =
false;
9520 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9523 if (!SimplifiedLHS.has_value())
9525 if (!*SimplifiedLHS)
9527 LHS = *SimplifiedLHS;
9529 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9532 if (!SimplifiedRHS.has_value())
9534 if (!*SimplifiedRHS)
9536 RHS = *SimplifiedRHS;
9542 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9544 DepClassTy::REQUIRED);
9548 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9550 DepClassTy::REQUIRED);
9554 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9555 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9558 if (LHSAARange.isEmptySet() || RHSAARange.isEmptySet())
9561 bool MustTrue =
false, MustFalse =
false;
9563 auto AllowedRegion =
9566 if (AllowedRegion.intersectWith(LHSAARange).isEmptySet())
9572 assert((!MustTrue || !MustFalse) &&
9573 "Either MustTrue or MustFalse should be false!");
9576 T.unionAssumed(ConstantRange(APInt( 1, 1)));
9578 T.unionAssumed(ConstantRange(APInt( 1, 0)));
9580 T.unionAssumed(ConstantRange( 1,
true));
9582 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] " << *CmpI <<
" after "
9583 << (MustTrue ?
"true" : (MustFalse ?
"false" :
"unknown"))
9584 <<
": " <<
T <<
"\n\t" << *LHSAA <<
"\t<op>\n\t"
9588 return T.isValidState();
9600 bool UsedAssumedInformation =
false;
9601 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9604 if (!SimplifiedOpV.has_value())
9606 if (!*SimplifiedOpV)
9608 Value *VPtr = *SimplifiedOpV;
9611 const auto *AA =
A.getAAFor<AAValueConstantRange>(
9613 DepClassTy::REQUIRED);
9617 T.unionAssumed(AA->getAssumedConstantRange(
A, CtxI));
9621 return T.isValidState();
9626 if (!calculateBinaryOperator(
A, BinOp,
T, CtxI, QuerriedAAs))
9629 if (!calculateCmpInst(
A, CmpI,
T, CtxI, QuerriedAAs))
9632 if (!calculateCastInst(
A, CastI,
T, CtxI, QuerriedAAs))
9638 T.indicatePessimisticFixpoint();
9645 for (
const AAValueConstantRange *QueriedAA : QuerriedAAs) {
9646 if (QueriedAA !=
this)
9649 if (
T.getAssumed() == getState().getAssumed())
9651 T.indicatePessimisticFixpoint();
9654 return T.isValidState();
9657 if (!VisitValueCB(getAssociatedValue(), getCtxI()))
9658 return indicatePessimisticFixpoint();
9663 return ChangeStatus::UNCHANGED;
9664 if (++NumChanges > MaxNumChanges) {
9665 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] performed " << NumChanges
9666 <<
" but only " << MaxNumChanges
9667 <<
" are allowed to avoid cyclic reasoning.");
9668 return indicatePessimisticFixpoint();
9670 return ChangeStatus::CHANGED;
9674 void trackStatistics()
const override {
9683 static constexpr int MaxNumChanges = 5;
9686struct AAValueConstantRangeFunction : AAValueConstantRangeImpl {
9687 AAValueConstantRangeFunction(
const IRPosition &IRP, Attributor &
A)
9688 : AAValueConstantRangeImpl(IRP,
A) {}
9692 llvm_unreachable(
"AAValueConstantRange(Function|CallSite)::updateImpl will "
9700struct AAValueConstantRangeCallSite : AAValueConstantRangeFunction {
9701 AAValueConstantRangeCallSite(
const IRPosition &IRP, Attributor &
A)
9702 : AAValueConstantRangeFunction(IRP,
A) {}
9708struct AAValueConstantRangeCallSiteReturned
9709 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9710 AAValueConstantRangeImpl::StateType,
9712 AAValueConstantRangeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
9713 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9714 AAValueConstantRangeImpl::StateType,
9721 if (std::optional<ConstantRange>
Range = CI->getRange())
9722 intersectKnown(*
Range);
9725 AAValueConstantRangeImpl::initialize(
A);
9729 void trackStatistics()
const override {
9733struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating {
9734 AAValueConstantRangeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
9735 : AAValueConstantRangeFloating(IRP,
A) {}
9739 return ChangeStatus::UNCHANGED;
9743 void trackStatistics()
const override {
9752struct AAPotentialConstantValuesImpl : AAPotentialConstantValues {
9755 AAPotentialConstantValuesImpl(
const IRPosition &IRP, Attributor &
A)
9756 : AAPotentialConstantValues(IRP,
A) {}
9760 if (
A.hasSimplificationCallback(getIRPosition()))
9761 indicatePessimisticFixpoint();
9763 AAPotentialConstantValues::initialize(
A);
9766 bool fillSetWithConstantValues(Attributor &
A,
const IRPosition &IRP, SetTy &S,
9767 bool &ContainsUndef,
bool ForSelf) {
9769 bool UsedAssumedInformation =
false;
9771 UsedAssumedInformation)) {
9778 auto *PotentialValuesAA =
A.getAAFor<AAPotentialConstantValues>(
9779 *
this, IRP, DepClassTy::REQUIRED);
9780 if (!PotentialValuesAA || !PotentialValuesAA->getState().isValidState())
9782 ContainsUndef = PotentialValuesAA->getState().undefIsContained();
9783 S = PotentialValuesAA->getState().getAssumedSet();
9790 ContainsUndef =
false;
9791 for (
auto &It : Values) {
9793 ContainsUndef =
true;
9799 S.insert(CI->getValue());
9801 ContainsUndef &= S.empty();
9807 const std::string getAsStr(Attributor *
A)
const override {
9809 llvm::raw_string_ostream OS(Str);
9816 return indicatePessimisticFixpoint();
9820struct AAPotentialConstantValuesArgument final
9821 : AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9822 AAPotentialConstantValuesImpl,
9823 PotentialConstantIntValuesState> {
9824 using Base = AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9825 AAPotentialConstantValuesImpl,
9827 AAPotentialConstantValuesArgument(
const IRPosition &IRP, Attributor &
A)
9831 void trackStatistics()
const override {
9836struct AAPotentialConstantValuesReturned
9837 : AAReturnedFromReturnedValues<AAPotentialConstantValues,
9838 AAPotentialConstantValuesImpl> {
9839 using Base = AAReturnedFromReturnedValues<AAPotentialConstantValues,
9840 AAPotentialConstantValuesImpl>;
9841 AAPotentialConstantValuesReturned(
const IRPosition &IRP, Attributor &
A)
9845 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9846 indicatePessimisticFixpoint();
9847 Base::initialize(
A);
9851 void trackStatistics()
const override {
9856struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl {
9857 AAPotentialConstantValuesFloating(
const IRPosition &IRP, Attributor &
A)
9858 : AAPotentialConstantValuesImpl(IRP,
A) {}
9862 AAPotentialConstantValuesImpl::initialize(
A);
9866 Value &
V = getAssociatedValue();
9869 unionAssumed(
C->getValue());
9870 indicateOptimisticFixpoint();
9875 unionAssumedWithUndef();
9876 indicateOptimisticFixpoint();
9886 indicatePessimisticFixpoint();
9889 << getAssociatedValue() <<
"\n");
9892 static bool calculateICmpInst(
const ICmpInst *ICI,
const APInt &
LHS,
9897 static APInt calculateCastInst(
const CastInst *CI,
const APInt &Src,
9898 uint32_t ResultBitWidth) {
9903 case Instruction::Trunc:
9904 return Src.trunc(ResultBitWidth);
9905 case Instruction::SExt:
9906 return Src.sext(ResultBitWidth);
9907 case Instruction::ZExt:
9908 return Src.zext(ResultBitWidth);
9909 case Instruction::BitCast:
9914 static APInt calculateBinaryOperator(
const BinaryOperator *BinOp,
9915 const APInt &
LHS,
const APInt &
RHS,
9916 bool &SkipOperation,
bool &Unsupported) {
9923 switch (BinOpcode) {
9927 case Instruction::Add:
9929 case Instruction::Sub:
9931 case Instruction::Mul:
9933 case Instruction::UDiv:
9935 SkipOperation =
true;
9939 case Instruction::SDiv:
9941 SkipOperation =
true;
9945 case Instruction::URem:
9947 SkipOperation =
true;
9951 case Instruction::SRem:
9953 SkipOperation =
true;
9957 case Instruction::Shl:
9959 case Instruction::LShr:
9961 case Instruction::AShr:
9963 case Instruction::And:
9965 case Instruction::Or:
9967 case Instruction::Xor:
9972 bool calculateBinaryOperatorAndTakeUnion(
const BinaryOperator *BinOp,
9973 const APInt &
LHS,
const APInt &
RHS) {
9974 bool SkipOperation =
false;
9977 calculateBinaryOperator(BinOp,
LHS,
RHS, SkipOperation, Unsupported);
9982 unionAssumed(Result);
9983 return isValidState();
9986 ChangeStatus updateWithICmpInst(Attributor &
A, ICmpInst *ICI) {
9987 auto AssumedBefore = getAssumed();
9991 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
9992 SetTy LHSAAPVS, RHSAAPVS;
9994 LHSContainsUndef,
false) ||
9996 RHSContainsUndef,
false))
9997 return indicatePessimisticFixpoint();
10000 bool MaybeTrue =
false, MaybeFalse =
false;
10002 if (LHSContainsUndef && RHSContainsUndef) {
10005 unionAssumedWithUndef();
10006 }
else if (LHSContainsUndef) {
10007 for (
const APInt &R : RHSAAPVS) {
10008 bool CmpResult = calculateICmpInst(ICI, Zero, R);
10009 MaybeTrue |= CmpResult;
10010 MaybeFalse |= !CmpResult;
10011 if (MaybeTrue & MaybeFalse)
10012 return indicatePessimisticFixpoint();
10014 }
else if (RHSContainsUndef) {
10015 for (
const APInt &L : LHSAAPVS) {
10016 bool CmpResult = calculateICmpInst(ICI, L, Zero);
10017 MaybeTrue |= CmpResult;
10018 MaybeFalse |= !CmpResult;
10019 if (MaybeTrue & MaybeFalse)
10020 return indicatePessimisticFixpoint();
10023 for (
const APInt &L : LHSAAPVS) {
10024 for (
const APInt &R : RHSAAPVS) {
10025 bool CmpResult = calculateICmpInst(ICI, L, R);
10026 MaybeTrue |= CmpResult;
10027 MaybeFalse |= !CmpResult;
10028 if (MaybeTrue & MaybeFalse)
10029 return indicatePessimisticFixpoint();
10034 unionAssumed(APInt( 1, 1));
10036 unionAssumed(APInt( 1, 0));
10037 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10038 : ChangeStatus::CHANGED;
10041 ChangeStatus updateWithSelectInst(Attributor &
A, SelectInst *SI) {
10042 auto AssumedBefore = getAssumed();
10046 bool UsedAssumedInformation =
false;
10047 std::optional<Constant *>
C =
A.getAssumedConstant(
10048 *
SI->getCondition(), *
this, UsedAssumedInformation);
10051 bool OnlyLeft =
false, OnlyRight =
false;
10052 if (
C && *
C && (*C)->isOneValue())
10054 else if (
C && *
C && (*C)->isNullValue())
10057 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10058 SetTy LHSAAPVS, RHSAAPVS;
10061 LHSContainsUndef,
false))
10062 return indicatePessimisticFixpoint();
10066 RHSContainsUndef,
false))
10067 return indicatePessimisticFixpoint();
10069 if (OnlyLeft || OnlyRight) {
10071 auto *OpAA = OnlyLeft ? &LHSAAPVS : &RHSAAPVS;
10072 auto Undef = OnlyLeft ? LHSContainsUndef : RHSContainsUndef;
10075 unionAssumedWithUndef();
10077 for (
const auto &It : *OpAA)
10081 }
else if (LHSContainsUndef && RHSContainsUndef) {
10083 unionAssumedWithUndef();
10085 for (
const auto &It : LHSAAPVS)
10087 for (
const auto &It : RHSAAPVS)
10090 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10091 : ChangeStatus::CHANGED;
10094 ChangeStatus updateWithCastInst(Attributor &
A, CastInst *CI) {
10095 auto AssumedBefore = getAssumed();
10097 return indicatePessimisticFixpoint();
10102 bool SrcContainsUndef =
false;
10105 SrcContainsUndef,
false))
10106 return indicatePessimisticFixpoint();
10108 if (SrcContainsUndef)
10109 unionAssumedWithUndef();
10111 for (
const APInt &S : SrcPVS) {
10112 APInt
T = calculateCastInst(CI, S, ResultBitWidth);
10116 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10117 : ChangeStatus::CHANGED;
10120 ChangeStatus updateWithBinaryOperator(Attributor &
A, BinaryOperator *BinOp) {
10121 auto AssumedBefore = getAssumed();
10125 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10126 SetTy LHSAAPVS, RHSAAPVS;
10128 LHSContainsUndef,
false) ||
10130 RHSContainsUndef,
false))
10131 return indicatePessimisticFixpoint();
10136 if (LHSContainsUndef && RHSContainsUndef) {
10137 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))
10138 return indicatePessimisticFixpoint();
10139 }
else if (LHSContainsUndef) {
10140 for (
const APInt &R : RHSAAPVS) {
10141 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))
10142 return indicatePessimisticFixpoint();
10144 }
else if (RHSContainsUndef) {
10145 for (
const APInt &L : LHSAAPVS) {
10146 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
10147 return indicatePessimisticFixpoint();
10150 for (
const APInt &L : LHSAAPVS) {
10151 for (
const APInt &R : RHSAAPVS) {
10152 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
10153 return indicatePessimisticFixpoint();
10157 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10158 : ChangeStatus::CHANGED;
10161 ChangeStatus updateWithInstruction(Attributor &
A, Instruction *Inst) {
10162 auto AssumedBefore = getAssumed();
10164 bool ContainsUndef;
10166 ContainsUndef,
true))
10167 return indicatePessimisticFixpoint();
10168 if (ContainsUndef) {
10169 unionAssumedWithUndef();
10171 for (
const auto &It : Incoming)
10174 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10175 : ChangeStatus::CHANGED;
10180 Value &
V = getAssociatedValue();
10184 return updateWithICmpInst(
A, ICI);
10187 return updateWithSelectInst(
A, SI);
10190 return updateWithCastInst(
A, CI);
10193 return updateWithBinaryOperator(
A, BinOp);
10196 return updateWithInstruction(
A,
I);
10198 return indicatePessimisticFixpoint();
10202 void trackStatistics()
const override {
10207struct AAPotentialConstantValuesFunction : AAPotentialConstantValuesImpl {
10208 AAPotentialConstantValuesFunction(
const IRPosition &IRP, Attributor &
A)
10209 : AAPotentialConstantValuesImpl(IRP,
A) {}
10214 "AAPotentialConstantValues(Function|CallSite)::updateImpl will "
10219 void trackStatistics()
const override {
10224struct AAPotentialConstantValuesCallSite : AAPotentialConstantValuesFunction {
10225 AAPotentialConstantValuesCallSite(
const IRPosition &IRP, Attributor &
A)
10226 : AAPotentialConstantValuesFunction(IRP,
A) {}
10229 void trackStatistics()
const override {
10234struct AAPotentialConstantValuesCallSiteReturned
10235 : AACalleeToCallSite<AAPotentialConstantValues,
10236 AAPotentialConstantValuesImpl> {
10237 AAPotentialConstantValuesCallSiteReturned(
const IRPosition &IRP,
10239 : AACalleeToCallSite<AAPotentialConstantValues,
10240 AAPotentialConstantValuesImpl>(IRP,
A) {}
10243 void trackStatistics()
const override {
10248struct AAPotentialConstantValuesCallSiteArgument
10249 : AAPotentialConstantValuesFloating {
10250 AAPotentialConstantValuesCallSiteArgument(
const IRPosition &IRP,
10252 : AAPotentialConstantValuesFloating(IRP,
A) {}
10256 AAPotentialConstantValuesImpl::initialize(
A);
10257 if (isAtFixpoint())
10260 Value &
V = getAssociatedValue();
10263 unionAssumed(
C->getValue());
10264 indicateOptimisticFixpoint();
10269 unionAssumedWithUndef();
10270 indicateOptimisticFixpoint();
10277 Value &
V = getAssociatedValue();
10278 auto AssumedBefore = getAssumed();
10279 auto *AA =
A.getAAFor<AAPotentialConstantValues>(
10282 return indicatePessimisticFixpoint();
10283 const auto &S = AA->getAssumed();
10285 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10286 : ChangeStatus::CHANGED;
10290 void trackStatistics()
const override {
10299 bool IgnoreSubsumingPositions) {
10300 assert(ImpliedAttributeKind == Attribute::NoUndef &&
10301 "Unexpected attribute kind");
10302 if (
A.hasAttr(IRP, {Attribute::NoUndef}, IgnoreSubsumingPositions,
10303 Attribute::NoUndef))
10323 Value &V = getAssociatedValue();
10325 indicatePessimisticFixpoint();
10326 assert(!isImpliedByIR(
A, getIRPosition(), Attribute::NoUndef));
10330 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10331 AANoUndef::StateType &State) {
10332 const Value *UseV =
U->get();
10333 const DominatorTree *DT =
nullptr;
10334 AssumptionCache *AC =
nullptr;
10335 InformationCache &InfoCache =
A.getInfoCache();
10336 if (Function *
F = getAnchorScope()) {
10341 bool TrackUse =
false;
10350 const std::string getAsStr(Attributor *
A)
const override {
10351 return getAssumed() ?
"noundef" :
"may-undef-or-poison";
10358 bool UsedAssumedInformation =
false;
10359 if (
A.isAssumedDead(getIRPosition(),
nullptr,
nullptr,
10360 UsedAssumedInformation))
10361 return ChangeStatus::UNCHANGED;
10365 if (!
A.getAssumedSimplified(getIRPosition(), *
this, UsedAssumedInformation,
10368 return ChangeStatus::UNCHANGED;
10369 return AANoUndef::manifest(
A);
10373struct AANoUndefFloating :
public AANoUndefImpl {
10374 AANoUndefFloating(
const IRPosition &IRP, Attributor &
A)
10375 : AANoUndefImpl(IRP,
A) {}
10379 AANoUndefImpl::initialize(
A);
10380 if (!getState().isAtFixpoint() && getAnchorScope() &&
10381 !getAnchorScope()->isDeclaration())
10382 if (Instruction *CtxI = getCtxI())
10383 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10388 auto VisitValueCB = [&](
const IRPosition &IRP) ->
bool {
10389 bool IsKnownNoUndef;
10391 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoUndef);
10395 bool UsedAssumedInformation =
false;
10396 Value *AssociatedValue = &getAssociatedValue();
10398 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10403 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
10411 if (AVIRP == getIRPosition() || !VisitValueCB(AVIRP))
10412 return indicatePessimisticFixpoint();
10413 return ChangeStatus::UNCHANGED;
10416 for (
const auto &VAC : Values)
10418 return indicatePessimisticFixpoint();
10420 return ChangeStatus::UNCHANGED;
10427struct AANoUndefReturned final
10428 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl> {
10429 AANoUndefReturned(
const IRPosition &IRP, Attributor &
A)
10430 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10436struct AANoUndefArgument final
10437 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl> {
10438 AANoUndefArgument(
const IRPosition &IRP, Attributor &
A)
10439 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10445struct AANoUndefCallSiteArgument final : AANoUndefFloating {
10446 AANoUndefCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10447 : AANoUndefFloating(IRP,
A) {}
10453struct AANoUndefCallSiteReturned final
10454 : AACalleeToCallSite<AANoUndef, AANoUndefImpl> {
10455 AANoUndefCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10456 : AACalleeToCallSite<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10464struct AANoFPClassImpl : AANoFPClass {
10465 AANoFPClassImpl(
const IRPosition &IRP, Attributor &
A) : AANoFPClass(IRP,
A) {}
10468 const IRPosition &IRP = getIRPosition();
10472 indicateOptimisticFixpoint();
10477 A.getAttrs(getIRPosition(), {Attribute::NoFPClass},
Attrs,
false);
10478 for (
const auto &Attr : Attrs) {
10485 const DataLayout &
DL =
A.getDataLayout();
10486 InformationCache &InfoCache =
A.getInfoCache();
10488 const DominatorTree *DT =
nullptr;
10489 AssumptionCache *AC =
nullptr;
10490 const TargetLibraryInfo *TLI =
nullptr;
10494 if (!
F->isDeclaration()) {
10501 SimplifyQuery Q(
DL, TLI, DT, AC, CtxI);
10508 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10512 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10513 AANoFPClass::StateType &State) {
10524 if (
auto *NoFPAA =
A.getAAFor<AANoFPClass>(*
this, IRP, DepClassTy::NONE))
10525 State.addKnownBits(NoFPAA->getState().getKnown());
10529 const std::string getAsStr(Attributor *
A)
const override {
10530 std::string
Result =
"nofpclass";
10531 raw_string_ostream OS(Result);
10532 OS << getKnownNoFPClass() <<
'/' << getAssumedNoFPClass();
10536 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
10537 SmallVectorImpl<Attribute> &Attrs)
const override {
10538 Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));
10542struct AANoFPClassFloating :
public AANoFPClassImpl {
10543 AANoFPClassFloating(
const IRPosition &IRP, Attributor &
A)
10544 : AANoFPClassImpl(IRP,
A) {}
10549 bool UsedAssumedInformation =
false;
10550 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10552 Values.
push_back({getAssociatedValue(), getCtxI()});
10558 DepClassTy::REQUIRED);
10559 if (!AA ||
this == AA) {
10560 T.indicatePessimisticFixpoint();
10562 const AANoFPClass::StateType &S =
10563 static_cast<const AANoFPClass::StateType &
>(AA->
getState());
10566 return T.isValidState();
10569 for (
const auto &VAC : Values)
10571 return indicatePessimisticFixpoint();
10577 void trackStatistics()
const override {
10582struct AANoFPClassReturned final
10583 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10584 AANoFPClassImpl::StateType, false,
10585 Attribute::None, false> {
10586 AANoFPClassReturned(
const IRPosition &IRP, Attributor &
A)
10587 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10588 AANoFPClassImpl::StateType,
false,
10592 void trackStatistics()
const override {
10597struct AANoFPClassArgument final
10598 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {
10599 AANoFPClassArgument(
const IRPosition &IRP, Attributor &
A)
10600 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10606struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {
10607 AANoFPClassCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10608 : AANoFPClassFloating(IRP,
A) {}
10611 void trackStatistics()
const override {
10616struct AANoFPClassCallSiteReturned final
10617 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl> {
10618 AANoFPClassCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10619 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10622 void trackStatistics()
const override {
10627struct AACallEdgesImpl :
public AACallEdges {
10628 AACallEdgesImpl(
const IRPosition &IRP, Attributor &
A) : AACallEdges(IRP,
A) {}
10630 const SetVector<Function *> &getOptimisticEdges()
const override {
10631 return CalledFunctions;
10634 bool hasUnknownCallee()
const override {
return HasUnknownCallee; }
10636 bool hasNonAsmUnknownCallee()
const override {
10637 return HasUnknownCalleeNonAsm;
10640 const std::string getAsStr(Attributor *
A)
const override {
10641 return "CallEdges[" + std::to_string(HasUnknownCallee) +
"," +
10642 std::to_string(CalledFunctions.size()) +
"]";
10645 void trackStatistics()
const override {}
10648 void addCalledFunction(Function *Fn,
ChangeStatus &Change) {
10649 if (CalledFunctions.insert(Fn)) {
10650 Change = ChangeStatus::CHANGED;
10656 void setHasUnknownCallee(
bool NonAsm,
ChangeStatus &Change) {
10657 if (!HasUnknownCallee)
10658 Change = ChangeStatus::CHANGED;
10659 if (NonAsm && !HasUnknownCalleeNonAsm)
10660 Change = ChangeStatus::CHANGED;
10661 HasUnknownCalleeNonAsm |= NonAsm;
10662 HasUnknownCallee =
true;
10667 SetVector<Function *> CalledFunctions;
10670 bool HasUnknownCallee =
false;
10673 bool HasUnknownCalleeNonAsm =
false;
10676struct AACallEdgesCallSite :
public AACallEdgesImpl {
10677 AACallEdgesCallSite(
const IRPosition &IRP, Attributor &
A)
10678 : AACallEdgesImpl(IRP,
A) {}
10685 addCalledFunction(Fn, Change);
10687 LLVM_DEBUG(
dbgs() <<
"[AACallEdges] Unrecognized value: " << V <<
"\n");
10688 setHasUnknownCallee(
true, Change);
10699 VisitValue(*V, CtxI);
10703 bool UsedAssumedInformation =
false;
10709 for (
auto &VAC : Values)
10716 if (
IA->hasSideEffects() &&
10719 setHasUnknownCallee(
false, Change);
10725 if (
auto *IndirectCallAA =
A.getAAFor<AAIndirectCallInfo>(
10726 *
this, getIRPosition(), DepClassTy::OPTIONAL))
10727 if (IndirectCallAA->foreachCallee(
10728 [&](Function *Fn) { return VisitValue(*Fn, CB); }))
10737 for (
const Use *U : CallbackUses)
10738 ProcessCalledOperand(
U->get(), CB);
10744struct AACallEdgesFunction :
public AACallEdgesImpl {
10745 AACallEdgesFunction(
const IRPosition &IRP, Attributor &
A)
10746 : AACallEdgesImpl(IRP,
A) {}
10755 auto *CBEdges =
A.getAAFor<AACallEdges>(
10759 if (CBEdges->hasNonAsmUnknownCallee())
10760 setHasUnknownCallee(
true, Change);
10761 if (CBEdges->hasUnknownCallee())
10762 setHasUnknownCallee(
false, Change);
10764 for (Function *
F : CBEdges->getOptimisticEdges())
10765 addCalledFunction(
F, Change);
10771 bool UsedAssumedInformation =
false;
10772 if (!
A.checkForAllCallLikeInstructions(ProcessCallInst, *
this,
10773 UsedAssumedInformation,
10777 setHasUnknownCallee(
true, Change);
10786struct AAInterFnReachabilityFunction
10787 :
public CachedReachabilityAA<AAInterFnReachability, Function> {
10788 using Base = CachedReachabilityAA<AAInterFnReachability, Function>;
10789 AAInterFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
10792 bool instructionCanReach(
10793 Attributor &
A,
const Instruction &From,
const Function &To,
10796 auto *NonConstThis =
const_cast<AAInterFnReachabilityFunction *
>(
this);
10798 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
10799 RQITy::Reachable
Result;
10800 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
10801 return NonConstThis->isReachableImpl(
A, StackRQI,
10803 return Result == RQITy::Reachable::Yes;
10807 bool IsTemporaryRQI)
override {
10809 &RQI.From->getFunction()->getEntryBlock().front();
10810 if (EntryI != RQI.From &&
10811 !instructionCanReach(
A, *EntryI, *RQI.To,
nullptr))
10812 return rememberResult(
A, RQITy::Reachable::No, RQI,
false,
10815 auto CheckReachableCallBase = [&](CallBase *CB) {
10816 auto *CBEdges =
A.getAAFor<AACallEdges>(
10818 if (!CBEdges || !CBEdges->getState().isValidState())
10821 if (CBEdges->hasUnknownCallee())
10824 for (Function *Fn : CBEdges->getOptimisticEdges()) {
10835 if (Fn == getAnchorScope()) {
10836 if (EntryI == RQI.From)
10841 const AAInterFnReachability *InterFnReachability =
10843 DepClassTy::OPTIONAL);
10846 if (!InterFnReachability ||
10854 const auto *IntraFnReachability =
A.getAAFor<AAIntraFnReachability>(
10856 DepClassTy::OPTIONAL);
10864 return IntraFnReachability && !IntraFnReachability->isAssumedReachable(
10865 A, *RQI.From, CBInst, RQI.ExclusionSet);
10868 bool UsedExclusionSet =
true;
10869 bool UsedAssumedInformation =
false;
10870 if (!
A.checkForAllCallLikeInstructions(CheckCallBase, *
this,
10871 UsedAssumedInformation,
10873 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
10876 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
10880 void trackStatistics()
const override {}
10884template <
typename AAType>
10885static std::optional<Constant *>
10888 if (!Ty.isIntegerTy())
10896 std::optional<Constant *> COpt =
AA->getAssumedConstant(
A);
10898 if (!COpt.has_value()) {
10900 return std::nullopt;
10902 if (
auto *
C = *COpt) {
10913 std::optional<Value *> V;
10914 for (
auto &It : Values) {
10916 if (V.has_value() && !*V)
10919 if (!V.has_value())
10933 if (
A.hasSimplificationCallback(getIRPosition())) {
10934 indicatePessimisticFixpoint();
10937 Value *Stripped = getAssociatedValue().stripPointerCasts();
10939 addValue(
A, getState(), *Stripped, getCtxI(),
AA::AnyScope,
10941 indicateOptimisticFixpoint();
10944 AAPotentialValues::initialize(
A);
10948 const std::string getAsStr(Attributor *
A)
const override {
10950 llvm::raw_string_ostream OS(Str);
10955 template <
typename AAType>
10956 static std::optional<Value *> askOtherAA(Attributor &
A,
10957 const AbstractAttribute &AA,
10958 const IRPosition &IRP,
Type &Ty) {
10963 return std::nullopt;
10970 virtual void addValue(Attributor &
A, StateType &State,
Value &V,
10972 Function *AnchorScope)
const {
10976 for (
const auto &U : CB->
args()) {
10986 Type &Ty = *getAssociatedType();
10987 std::optional<Value *> SimpleV =
10988 askOtherAA<AAValueConstantRange>(
A, *
this, ValIRP, Ty);
10989 if (SimpleV.has_value() && !*SimpleV) {
10990 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
10991 *
this, ValIRP, DepClassTy::OPTIONAL);
10992 if (PotentialConstantsAA && PotentialConstantsAA->isValidState()) {
10993 for (
const auto &It : PotentialConstantsAA->getAssumedSet())
10994 State.unionAssumed({{*ConstantInt::get(&Ty, It),
nullptr}, S});
10995 if (PotentialConstantsAA->undefIsContained())
11000 if (!SimpleV.has_value())
11012 State.unionAssumed({{*VPtr, CtxI}, S});
11018 AA::ValueAndContext
I;
11022 return II.I ==
I &&
II.S == S;
11025 return std::tie(
I, S) < std::tie(
II.I,
II.S);
11029 bool recurseForValue(Attributor &
A,
const IRPosition &IRP,
AA::ValueScope S) {
11030 SmallMapVector<AA::ValueAndContext, int, 8> ValueScopeMap;
11035 bool UsedAssumedInformation =
false;
11037 if (!
A.getAssumedSimplifiedValues(IRP,
this, Values, CS,
11038 UsedAssumedInformation))
11041 for (
auto &It : Values)
11042 ValueScopeMap[It] += CS;
11044 for (
auto &It : ValueScopeMap)
11045 addValue(
A, getState(), *It.first.getValue(), It.first.getCtxI(),
11051 void giveUpOnIntraprocedural(Attributor &
A) {
11052 auto NewS = StateType::getBestState(getState());
11053 for (
const auto &It : getAssumedSet()) {
11056 addValue(
A, NewS, *It.first.getValue(), It.first.getCtxI(),
11059 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11067 getState() = StateType::getBestState(getState());
11068 getState().unionAssumed({{getAssociatedValue(), getCtxI()},
AA::AnyScope});
11069 AAPotentialValues::indicateOptimisticFixpoint();
11070 return ChangeStatus::CHANGED;
11075 return indicatePessimisticFixpoint();
11083 if (!getAssumedSimplifiedValues(
A, Values, S))
11085 Value &OldV = getAssociatedValue();
11088 Value *NewV = getSingleValue(
A, *
this, getIRPosition(), Values);
11089 if (!NewV || NewV == &OldV)
11094 if (
A.changeAfterManifest(getIRPosition(), *NewV))
11095 return ChangeStatus::CHANGED;
11097 return ChangeStatus::UNCHANGED;
11100 bool getAssumedSimplifiedValues(
11101 Attributor &
A, SmallVectorImpl<AA::ValueAndContext> &Values,
11102 AA::ValueScope S,
bool RecurseForSelectAndPHI =
false)
const override {
11103 if (!isValidState())
11105 bool UsedAssumedInformation =
false;
11106 for (
const auto &It : getAssumedSet())
11107 if (It.second & S) {
11108 if (RecurseForSelectAndPHI && (
isa<PHINode>(It.first.getValue()) ||
11110 if (
A.getAssumedSimplifiedValues(
11112 this, Values, S, UsedAssumedInformation))
11117 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11122struct AAPotentialValuesFloating : AAPotentialValuesImpl {
11123 AAPotentialValuesFloating(
const IRPosition &IRP, Attributor &
A)
11124 : AAPotentialValuesImpl(IRP,
A) {}
11128 auto AssumedBefore = getAssumed();
11130 genericValueTraversal(
A, &getAssociatedValue());
11132 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11133 : ChangeStatus::CHANGED;
11137 struct LivenessInfo {
11138 const AAIsDead *LivenessAA =
nullptr;
11139 bool AnyDead =
false;
11149 SmallVectorImpl<ItemInfo> &Worklist) {
11152 bool UsedAssumedInformation =
false;
11154 auto GetSimplifiedValues = [&](
Value &
V,
11156 if (!
A.getAssumedSimplifiedValues(
11160 Values.
push_back(AA::ValueAndContext{
V,
II.I.getCtxI()});
11162 return Values.
empty();
11164 if (GetSimplifiedValues(*
LHS, LHSValues))
11166 if (GetSimplifiedValues(*
RHS, RHSValues))
11171 InformationCache &InfoCache =
A.getInfoCache();
11178 F ?
A.getInfoCache().getTargetLibraryInfoForFunction(*
F) :
nullptr;
11183 const DataLayout &
DL =
A.getDataLayout();
11184 SimplifyQuery Q(
DL, TLI, DT, AC, CmpI);
11186 auto CheckPair = [&](
Value &LHSV,
Value &RHSV) {
11189 nullptr,
II.S, getAnchorScope());
11195 if (&LHSV == &RHSV &&
11197 Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
11199 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11206 if (TypedLHS && TypedRHS) {
11208 if (NewV && NewV != &Cmp) {
11209 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11221 if (!LHSIsNull && !RHSIsNull)
11227 assert((LHSIsNull || RHSIsNull) &&
11228 "Expected nullptr versus non-nullptr comparison at this point");
11231 unsigned PtrIdx = LHSIsNull;
11232 bool IsKnownNonNull;
11235 DepClassTy::REQUIRED, IsKnownNonNull);
11236 if (!IsAssumedNonNull)
11242 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11247 for (
auto &LHSValue : LHSValues)
11248 for (
auto &RHSValue : RHSValues)
11249 if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))
11254 bool handleSelectInst(Attributor &
A, SelectInst &SI, ItemInfo
II,
11255 SmallVectorImpl<ItemInfo> &Worklist) {
11257 bool UsedAssumedInformation =
false;
11259 std::optional<Constant *>
C =
11260 A.getAssumedConstant(*
SI.getCondition(), *
this, UsedAssumedInformation);
11261 bool NoValueYet = !
C.has_value();
11269 }
else if (&SI == &getAssociatedValue()) {
11274 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11276 if (!SimpleV.has_value())
11279 addValue(
A, getState(), **SimpleV, CtxI,
II.S, getAnchorScope());
11287 bool handleLoadInst(Attributor &
A, LoadInst &LI, ItemInfo
II,
11288 SmallVectorImpl<ItemInfo> &Worklist) {
11289 SmallSetVector<Value *, 4> PotentialCopies;
11290 SmallSetVector<Instruction *, 4> PotentialValueOrigins;
11291 bool UsedAssumedInformation =
false;
11293 PotentialValueOrigins, *
this,
11294 UsedAssumedInformation,
11296 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Failed to get potentially "
11297 "loaded values for load instruction "
11305 InformationCache &InfoCache =
A.getInfoCache();
11307 if (!
llvm::all_of(PotentialValueOrigins, [&](Instruction *
I) {
11311 return A.isAssumedDead(
SI->getOperandUse(0),
this,
11313 UsedAssumedInformation,
11315 return A.isAssumedDead(*
I,
this,
nullptr,
11316 UsedAssumedInformation,
11319 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Load is onl used by assumes "
11320 "and we cannot delete all the stores: "
11331 bool AllLocal = ScopeIsLocal;
11336 if (!DynamicallyUnique) {
11337 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Not all potentially loaded "
11338 "values are dynamically unique: "
11343 for (
auto *PotentialCopy : PotentialCopies) {
11345 Worklist.
push_back({{*PotentialCopy, CtxI},
II.S});
11350 if (!AllLocal && ScopeIsLocal)
11355 bool handlePHINode(
11356 Attributor &
A, PHINode &
PHI, ItemInfo
II,
11357 SmallVectorImpl<ItemInfo> &Worklist,
11358 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11359 auto GetLivenessInfo = [&](
const Function &
F) -> LivenessInfo & {
11360 LivenessInfo &LI = LivenessAAs[&
F];
11361 if (!LI.LivenessAA)
11367 if (&
PHI == &getAssociatedValue()) {
11368 LivenessInfo &LI = GetLivenessInfo(*
PHI.getFunction());
11370 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
11371 *
PHI.getFunction());
11375 for (
unsigned u = 0, e =
PHI.getNumIncomingValues(); u < e; u++) {
11377 if (LI.LivenessAA &&
11378 LI.LivenessAA->isEdgeDead(IncomingBB,
PHI.getParent())) {
11397 bool UsedAssumedInformation =
false;
11398 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11400 if (!SimpleV.has_value())
11404 addValue(
A, getState(), **SimpleV, &
PHI,
II.S, getAnchorScope());
11411 bool handleGenericInst(Attributor &
A, Instruction &
I, ItemInfo
II,
11412 SmallVectorImpl<ItemInfo> &Worklist) {
11413 bool SomeSimplified =
false;
11414 bool UsedAssumedInformation =
false;
11416 SmallVector<Value *, 8> NewOps(
I.getNumOperands());
11419 const auto &SimplifiedOp =
A.getAssumedSimplified(
11424 if (!SimplifiedOp.has_value())
11428 NewOps[Idx] = *SimplifiedOp;
11432 SomeSimplified |= (NewOps[Idx] !=
Op);
11438 if (!SomeSimplified)
11441 InformationCache &InfoCache =
A.getInfoCache();
11445 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
11448 const DataLayout &
DL =
I.getDataLayout();
11449 SimplifyQuery Q(
DL, TLI, DT, AC, &
I);
11451 if (!NewV || NewV == &
I)
11454 LLVM_DEBUG(
dbgs() <<
"Generic inst " <<
I <<
" assumed simplified to "
11461 Attributor &
A, Instruction &
I, ItemInfo
II,
11462 SmallVectorImpl<ItemInfo> &Worklist,
11463 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11466 CI->getPredicate(),
II, Worklist);
11468 switch (
I.getOpcode()) {
11469 case Instruction::Select:
11471 case Instruction::PHI:
11473 case Instruction::Load:
11476 return handleGenericInst(
A,
I,
II, Worklist);
11481 void genericValueTraversal(Attributor &
A,
Value *InitialV) {
11482 SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;
11484 SmallSet<ItemInfo, 16> Visited;
11503 LLVM_DEBUG(
dbgs() <<
"Generic value traversal reached iteration limit: "
11504 << Iteration <<
"!\n");
11505 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11511 Value *NewV =
nullptr;
11512 if (
V->getType()->isPointerTy()) {
11518 for (Argument &Arg :
Callee->args())
11525 if (NewV && NewV != V) {
11526 Worklist.
push_back({{*NewV, CtxI}, S});
11540 if (V == InitialV && CtxI == getCtxI()) {
11541 indicatePessimisticFixpoint();
11545 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11546 }
while (!Worklist.
empty());
11550 for (
auto &It : LivenessAAs)
11551 if (It.second.AnyDead)
11552 A.recordDependence(*It.second.LivenessAA, *
this, DepClassTy::OPTIONAL);
11556 void trackStatistics()
const override {
11561struct AAPotentialValuesArgument final : AAPotentialValuesImpl {
11562 using Base = AAPotentialValuesImpl;
11563 AAPotentialValuesArgument(
const IRPosition &IRP, Attributor &
A)
11570 indicatePessimisticFixpoint();
11575 auto AssumedBefore = getAssumed();
11577 unsigned ArgNo = getCalleeArgNo();
11579 bool UsedAssumedInformation =
false;
11581 auto CallSitePred = [&](AbstractCallSite ACS) {
11583 if (CSArgIRP.getPositionKind() == IRP_INVALID)
11586 if (!
A.getAssumedSimplifiedValues(CSArgIRP,
this, Values,
11588 UsedAssumedInformation))
11591 return isValidState();
11594 if (!
A.checkForAllCallSites(CallSitePred, *
this,
11596 UsedAssumedInformation))
11597 return indicatePessimisticFixpoint();
11599 Function *Fn = getAssociatedFunction();
11600 bool AnyNonLocal =
false;
11601 for (
auto &It : Values) {
11603 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11608 return indicatePessimisticFixpoint();
11612 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11618 AnyNonLocal =
true;
11620 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11622 giveUpOnIntraprocedural(
A);
11624 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11625 : ChangeStatus::CHANGED;
11629 void trackStatistics()
const override {
11634struct AAPotentialValuesReturned :
public AAPotentialValuesFloating {
11635 using Base = AAPotentialValuesFloating;
11636 AAPotentialValuesReturned(
const IRPosition &IRP, Attributor &
A)
11642 if (!
F ||
F->isDeclaration() ||
F->getReturnType()->isVoidTy()) {
11643 indicatePessimisticFixpoint();
11647 for (Argument &Arg :
F->args())
11650 ReturnedArg = &Arg;
11653 if (!
A.isFunctionIPOAmendable(*
F) ||
11654 A.hasSimplificationCallback(getIRPosition())) {
11656 indicatePessimisticFixpoint();
11658 indicateOptimisticFixpoint();
11664 auto AssumedBefore = getAssumed();
11665 bool UsedAssumedInformation =
false;
11668 Function *AnchorScope = getAnchorScope();
11674 UsedAssumedInformation,
11680 bool AllInterAreIntra =
false;
11683 llvm::all_of(Values, [&](
const AA::ValueAndContext &VAC) {
11687 for (
const AA::ValueAndContext &VAC : Values) {
11688 addValue(
A, getState(), *VAC.
getValue(),
11692 if (AllInterAreIntra)
11699 HandleReturnedValue(*ReturnedArg,
nullptr,
true);
11702 bool AddValues =
true;
11705 addValue(
A, getState(), *RetI.getOperand(0), &RetI,
AA::AnyScope,
11709 return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);
11712 if (!
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11713 UsedAssumedInformation,
11715 return indicatePessimisticFixpoint();
11718 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11719 : ChangeStatus::CHANGED;
11724 return ChangeStatus::UNCHANGED;
11726 if (!getAssumedSimplifiedValues(
A, Values, AA::ValueScope::Intraprocedural,
11728 return ChangeStatus::UNCHANGED;
11729 Value *NewVal = getSingleValue(
A, *
this, getIRPosition(), Values);
11731 return ChangeStatus::UNCHANGED;
11736 "Number of function with unique return");
11739 {Attribute::get(Arg->
getContext(), Attribute::Returned)});
11744 Value *RetOp = RetI.getOperand(0);
11748 if (
A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))
11749 Changed = ChangeStatus::CHANGED;
11752 bool UsedAssumedInformation =
false;
11753 (void)
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11754 UsedAssumedInformation,
11760 return AAPotentialValues::indicatePessimisticFixpoint();
11764 void trackStatistics()
const override{
11771struct AAPotentialValuesFunction : AAPotentialValuesImpl {
11772 AAPotentialValuesFunction(
const IRPosition &IRP, Attributor &
A)
11773 : AAPotentialValuesImpl(IRP,
A) {}
11782 void trackStatistics()
const override {
11787struct AAPotentialValuesCallSite : AAPotentialValuesFunction {
11788 AAPotentialValuesCallSite(
const IRPosition &IRP, Attributor &
A)
11789 : AAPotentialValuesFunction(IRP,
A) {}
11792 void trackStatistics()
const override {
11797struct AAPotentialValuesCallSiteReturned : AAPotentialValuesImpl {
11798 AAPotentialValuesCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
11799 : AAPotentialValuesImpl(IRP,
A) {}
11803 auto AssumedBefore = getAssumed();
11807 return indicatePessimisticFixpoint();
11809 bool UsedAssumedInformation =
false;
11813 UsedAssumedInformation))
11814 return indicatePessimisticFixpoint();
11821 Values, S, UsedAssumedInformation))
11824 for (
auto &It : Values) {
11825 Value *
V = It.getValue();
11826 std::optional<Value *> CallerV =
A.translateArgumentToCallSiteContent(
11827 V, *CB, *
this, UsedAssumedInformation);
11828 if (!CallerV.has_value()) {
11832 V = *CallerV ? *CallerV :
V;
11838 giveUpOnIntraprocedural(
A);
11841 addValue(
A, getState(), *V, CB, S, getAnchorScope());
11846 return indicatePessimisticFixpoint();
11848 return indicatePessimisticFixpoint();
11849 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11850 : ChangeStatus::CHANGED;
11854 return AAPotentialValues::indicatePessimisticFixpoint();
11858 void trackStatistics()
const override {
11863struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
11864 AAPotentialValuesCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
11865 : AAPotentialValuesFloating(IRP,
A) {}
11868 void trackStatistics()
const override {
11876struct AAAssumptionInfoImpl :
public AAAssumptionInfo {
11877 AAAssumptionInfoImpl(
const IRPosition &IRP, Attributor &
A,
11878 const DenseSet<StringRef> &Known)
11879 : AAAssumptionInfo(IRP,
A, Known) {}
11884 if (getKnown().isUniversal())
11885 return ChangeStatus::UNCHANGED;
11887 const IRPosition &IRP = getIRPosition();
11889 getAssumed().getSet().
end());
11891 return A.manifestAttrs(IRP,
11898 bool hasAssumption(
const StringRef Assumption)
const override {
11899 return isValidState() && setContains(Assumption);
11903 const std::string getAsStr(Attributor *
A)
const override {
11904 const SetContents &Known = getKnown();
11905 const SetContents &Assumed = getAssumed();
11909 const std::string KnownStr =
llvm::join(Set,
",");
11911 std::string AssumedStr =
"Universal";
11912 if (!Assumed.isUniversal()) {
11913 Set.assign(Assumed.getSet().begin(), Assumed.getSet().end());
11916 return "Known [" + KnownStr +
"]," +
" Assumed [" + AssumedStr +
"]";
11931struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {
11932 AAAssumptionInfoFunction(
const IRPosition &IRP, Attributor &
A)
11933 : AAAssumptionInfoImpl(IRP,
A,
11940 auto CallSitePred = [&](AbstractCallSite ACS) {
11941 const auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
11943 DepClassTy::REQUIRED);
11947 Changed |= getIntersection(AssumptionAA->getAssumed());
11948 return !getAssumed().empty() || !getKnown().empty();
11951 bool UsedAssumedInformation =
false;
11956 if (!
A.checkForAllCallSites(CallSitePred, *
this,
true,
11957 UsedAssumedInformation))
11958 return indicatePessimisticFixpoint();
11960 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11963 void trackStatistics()
const override {}
11967struct AAAssumptionInfoCallSite final : AAAssumptionInfoImpl {
11969 AAAssumptionInfoCallSite(
const IRPosition &IRP, Attributor &
A)
11970 : AAAssumptionInfoImpl(IRP,
A, getInitialAssumptions(IRP)) {}
11975 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11981 auto *AssumptionAA =
11982 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11984 return indicatePessimisticFixpoint();
11985 bool Changed = getIntersection(AssumptionAA->getAssumed());
11986 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11990 void trackStatistics()
const override {}
11995 DenseSet<StringRef> getInitialAssumptions(
const IRPosition &IRP) {
12002 return Assumptions;
12017struct AAUnderlyingObjectsImpl
12023 const std::string getAsStr(
Attributor *
A)
const override {
12024 if (!isValidState())
12025 return "<invalid>";
12028 OS <<
"underlying objects: inter " << InterAssumedUnderlyingObjects.size()
12029 <<
" objects, intra " << IntraAssumedUnderlyingObjects.size()
12031 if (!InterAssumedUnderlyingObjects.empty()) {
12032 OS <<
"inter objects:\n";
12033 for (
auto *Obj : InterAssumedUnderlyingObjects)
12034 OS << *Obj <<
'\n';
12036 if (!IntraAssumedUnderlyingObjects.empty()) {
12037 OS <<
"intra objects:\n";
12038 for (
auto *Obj : IntraAssumedUnderlyingObjects)
12039 OS << *
Obj <<
'\n';
12045 void trackStatistics()
const override {}
12049 auto &Ptr = getAssociatedValue();
12051 bool UsedAssumedInformation =
false;
12052 auto DoUpdate = [&](SmallSetVector<Value *, 8> &UnderlyingObjects,
12054 SmallPtrSet<Value *, 8> SeenObjects;
12058 Scope, UsedAssumedInformation))
12059 return UnderlyingObjects.
insert(&Ptr);
12063 for (
unsigned I = 0;
I < Values.
size(); ++
I) {
12064 auto &VAC = Values[
I];
12067 if (!SeenObjects.
insert(UO ? UO : Obj).second)
12069 if (UO && UO != Obj) {
12075 const auto *OtherAA =
A.getAAFor<AAUnderlyingObjects>(
12077 auto Pred = [&](
Value &
V) {
12085 if (!OtherAA || !OtherAA->forallUnderlyingObjects(Pred, Scope))
12087 "The forall call should not return false at this position");
12093 Changed |= handleIndirect(
A, *Obj, UnderlyingObjects, Scope,
12094 UsedAssumedInformation);
12100 for (
unsigned u = 0, e =
PHI->getNumIncomingValues(); u < e; u++) {
12102 handleIndirect(
A, *
PHI->getIncomingValue(u), UnderlyingObjects,
12103 Scope, UsedAssumedInformation);
12117 if (!UsedAssumedInformation)
12118 indicateOptimisticFixpoint();
12119 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12122 bool forallUnderlyingObjects(
12123 function_ref<
bool(
Value &)> Pred,
12125 if (!isValidState())
12126 return Pred(getAssociatedValue());
12129 ? IntraAssumedUnderlyingObjects
12130 : InterAssumedUnderlyingObjects;
12131 for (
Value *Obj : AssumedUnderlyingObjects)
12141 bool handleIndirect(Attributor &
A,
Value &V,
12142 SmallSetVector<Value *, 8> &UnderlyingObjects,
12145 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
12147 auto Pred = [&](
Value &
V) {
12151 if (!AA || !AA->forallUnderlyingObjects(Pred, Scope))
12153 "The forall call should not return false at this position");
12159 SmallSetVector<Value *, 8> IntraAssumedUnderlyingObjects;
12161 SmallSetVector<Value *, 8> InterAssumedUnderlyingObjects;
12164struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl {
12165 AAUnderlyingObjectsFloating(
const IRPosition &IRP, Attributor &
A)
12166 : AAUnderlyingObjectsImpl(IRP,
A) {}
12169struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl {
12170 AAUnderlyingObjectsArgument(
const IRPosition &IRP, Attributor &
A)
12171 : AAUnderlyingObjectsImpl(IRP,
A) {}
12174struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl {
12175 AAUnderlyingObjectsCallSite(
const IRPosition &IRP, Attributor &
A)
12176 : AAUnderlyingObjectsImpl(IRP,
A) {}
12179struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl {
12180 AAUnderlyingObjectsCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12181 : AAUnderlyingObjectsImpl(IRP,
A) {}
12184struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl {
12185 AAUnderlyingObjectsReturned(
const IRPosition &IRP, Attributor &
A)
12186 : AAUnderlyingObjectsImpl(IRP,
A) {}
12189struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl {
12190 AAUnderlyingObjectsCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12191 : AAUnderlyingObjectsImpl(IRP,
A) {}
12194struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {
12195 AAUnderlyingObjectsFunction(
const IRPosition &IRP, Attributor &
A)
12196 : AAUnderlyingObjectsImpl(IRP,
A) {}
12202struct AAGlobalValueInfoFloating :
public AAGlobalValueInfo {
12203 AAGlobalValueInfoFloating(
const IRPosition &IRP, Attributor &
A)
12204 : AAGlobalValueInfo(IRP,
A) {}
12209 bool checkUse(Attributor &
A,
const Use &U,
bool &Follow,
12210 SmallVectorImpl<const Value *> &Worklist) {
12217 LLVM_DEBUG(
dbgs() <<
"[AAGlobalValueInfo] Check use: " << *
U.get() <<
" in "
12218 << *UInst <<
"\n");
12221 int Idx = &
Cmp->getOperandUse(0) == &
U;
12224 return U == &getAnchorValue();
12229 auto CallSitePred = [&](AbstractCallSite ACS) {
12230 Worklist.
push_back(ACS.getInstruction());
12233 bool UsedAssumedInformation =
false;
12235 if (!
A.checkForAllCallSites(CallSitePred, *UInst->
getFunction(),
12237 UsedAssumedInformation))
12255 if (!Fn || !
A.isFunctionIPOAmendable(*Fn))
12264 unsigned NumUsesBefore =
Uses.size();
12266 SmallPtrSet<const Value *, 8> Visited;
12270 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
12278 return checkUse(
A, U, Follow, Worklist);
12280 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
12281 Uses.insert(&OldU);
12285 while (!Worklist.
empty()) {
12287 if (!Visited.
insert(V).second)
12289 if (!
A.checkForAllUses(UsePred, *
this, *V,
12291 DepClassTy::OPTIONAL,
12292 true, EquivalentUseCB)) {
12293 return indicatePessimisticFixpoint();
12297 return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED
12298 : ChangeStatus::CHANGED;
12301 bool isPotentialUse(
const Use &U)
const override {
12302 return !isValidState() ||
Uses.contains(&U);
12307 return ChangeStatus::UNCHANGED;
12311 const std::string getAsStr(Attributor *
A)
const override {
12312 return "[" + std::to_string(
Uses.size()) +
" uses]";
12315 void trackStatistics()
const override {
12321 SmallPtrSet<const Use *, 8>
Uses;
12327struct AAIndirectCallInfoCallSite :
public AAIndirectCallInfo {
12328 AAIndirectCallInfoCallSite(
const IRPosition &IRP, Attributor &
A)
12329 : AAIndirectCallInfo(IRP,
A) {}
12333 auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);
12334 if (!MD && !
A.isClosedWorldModule())
12338 for (
const auto &
Op : MD->operands())
12340 PotentialCallees.insert(Callee);
12341 }
else if (
A.isClosedWorldModule()) {
12343 A.getInfoCache().getIndirectlyCallableFunctions(
A);
12344 PotentialCallees.insert_range(IndirectlyCallableFunctions);
12347 if (PotentialCallees.empty())
12348 indicateOptimisticFixpoint();
12356 SmallSetVector<Function *, 4> AssumedCalleesNow;
12357 bool AllCalleesKnownNow = AllCalleesKnown;
12359 auto CheckPotentialCalleeUse = [&](
Function &PotentialCallee,
12360 bool &UsedAssumedInformation) {
12361 const auto *GIAA =
A.getAAFor<AAGlobalValueInfo>(
12363 if (!GIAA || GIAA->isPotentialUse(CalleeUse))
12365 UsedAssumedInformation = !GIAA->isAtFixpoint();
12369 auto AddPotentialCallees = [&]() {
12370 for (
auto *PotentialCallee : PotentialCallees) {
12371 bool UsedAssumedInformation =
false;
12372 if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))
12373 AssumedCalleesNow.
insert(PotentialCallee);
12379 bool UsedAssumedInformation =
false;
12382 AA::ValueScope::AnyScope,
12383 UsedAssumedInformation)) {
12384 if (PotentialCallees.empty())
12385 return indicatePessimisticFixpoint();
12386 AddPotentialCallees();
12391 auto CheckPotentialCallee = [&](
Function &Fn) {
12392 if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))
12395 auto &CachedResult = FilterResults[&Fn];
12396 if (CachedResult.has_value())
12397 return CachedResult.value();
12399 bool UsedAssumedInformation =
false;
12400 if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {
12401 if (!UsedAssumedInformation)
12402 CachedResult =
false;
12411 for (
int I = NumCBArgs;
I < NumFnArgs; ++
I) {
12412 bool IsKnown =
false;
12415 DepClassTy::OPTIONAL, IsKnown)) {
12417 CachedResult =
false;
12422 CachedResult =
true;
12428 for (
auto &VAC : Values) {
12436 if (CheckPotentialCallee(*VACFn))
12437 AssumedCalleesNow.
insert(VACFn);
12440 if (!PotentialCallees.empty()) {
12441 AddPotentialCallees();
12444 AllCalleesKnownNow =
false;
12447 if (AssumedCalleesNow == AssumedCallees &&
12448 AllCalleesKnown == AllCalleesKnownNow)
12449 return ChangeStatus::UNCHANGED;
12451 std::swap(AssumedCallees, AssumedCalleesNow);
12452 AllCalleesKnown = AllCalleesKnownNow;
12453 return ChangeStatus::CHANGED;
12459 if (!AllCalleesKnown && AssumedCallees.empty())
12460 return ChangeStatus::UNCHANGED;
12463 bool UsedAssumedInformation =
false;
12464 if (
A.isAssumedDead(*CB,
this,
nullptr,
12465 UsedAssumedInformation))
12466 return ChangeStatus::UNCHANGED;
12470 if (
FP->getType()->getPointerAddressSpace())
12471 FP =
new AddrSpaceCastInst(
FP, PointerType::get(
FP->getContext(), 0),
12481 if (AssumedCallees.empty()) {
12482 assert(AllCalleesKnown &&
12483 "Expected all callees to be known if there are none.");
12484 A.changeToUnreachableAfterManifest(CB);
12485 return ChangeStatus::CHANGED;
12489 if (AllCalleesKnown && AssumedCallees.size() == 1) {
12490 auto *NewCallee = AssumedCallees.front();
12493 NumIndirectCallsPromoted++;
12494 return ChangeStatus::CHANGED;
12501 A.deleteAfterManifest(*CB);
12502 return ChangeStatus::CHANGED;
12512 bool SpecializedForAnyCallees =
false;
12513 bool SpecializedForAllCallees = AllCalleesKnown;
12514 ICmpInst *LastCmp =
nullptr;
12517 for (Function *NewCallee : AssumedCallees) {
12518 if (!
A.shouldSpecializeCallSiteForCallee(*
this, *CB, *NewCallee,
12519 AssumedCallees.size())) {
12520 SkippedAssumedCallees.
push_back(NewCallee);
12521 SpecializedForAllCallees =
false;
12524 SpecializedForAnyCallees =
true;
12530 A.registerManifestAddedBasicBlock(*ThenTI->
getParent());
12531 A.registerManifestAddedBasicBlock(*IP->getParent());
12537 A.registerManifestAddedBasicBlock(*ElseBB);
12539 SplitTI->replaceUsesOfWith(CBBB, ElseBB);
12544 CastInst *RetBC =
nullptr;
12545 CallInst *NewCall =
nullptr;
12550 NumIndirectCallsPromoted++;
12558 auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {
12559 if (!AllCalleesKnown)
12560 return ChangeStatus::UNCHANGED;
12561 MDBuilder MDB(IndirectCB.getContext());
12562 MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);
12563 IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);
12564 return ChangeStatus::CHANGED;
12567 if (!SpecializedForAnyCallees)
12568 return AttachCalleeMetadata(*CB);
12571 if (SpecializedForAllCallees) {
12574 new UnreachableInst(IP->getContext(), IP);
12575 IP->eraseFromParent();
12578 CBClone->setName(CB->
getName());
12579 CBClone->insertBefore(*IP->getParent(), IP);
12580 NewCalls.
push_back({CBClone,
nullptr});
12581 AttachCalleeMetadata(*CBClone);
12588 CB->
getParent()->getFirstInsertionPt());
12589 for (
auto &It : NewCalls) {
12590 CallBase *NewCall = It.first;
12591 Instruction *CallRet = It.second ? It.second : It.first;
12603 A.deleteAfterManifest(*CB);
12604 Changed = ChangeStatus::CHANGED;
12610 const std::string getAsStr(Attributor *
A)
const override {
12611 return std::string(AllCalleesKnown ?
"eliminate" :
"specialize") +
12612 " indirect call site with " + std::to_string(AssumedCallees.size()) +
12616 void trackStatistics()
const override {
12617 if (AllCalleesKnown) {
12619 Eliminated, CallSites,
12620 "Number of indirect call sites eliminated via specialization")
12623 "Number of indirect call sites specialized")
12627 bool foreachCallee(function_ref<
bool(Function *)> CB)
const override {
12628 return isValidState() && AllCalleesKnown &&
all_of(AssumedCallees, CB);
12633 DenseMap<Function *, std::optional<bool>> FilterResults;
12637 SmallSetVector<Function *, 4> PotentialCallees;
12641 SmallSetVector<Function *, 4> AssumedCallees;
12645 bool AllCalleesKnown =
true;
12652struct AAInvariantLoadPointerImpl
12653 :
public StateWrapper<BitIntegerState<uint8_t, 15>,
12654 AAInvariantLoadPointer> {
12658 IS_NOALIAS = 1 << 0,
12661 IS_NOEFFECT = 1 << 1,
12663 IS_LOCALLY_INVARIANT = 1 << 2,
12665 IS_LOCALLY_CONSTRAINED = 1 << 3,
12667 IS_BEST_STATE = IS_NOALIAS | IS_NOEFFECT | IS_LOCALLY_INVARIANT |
12668 IS_LOCALLY_CONSTRAINED,
12670 static_assert(getBestState() == IS_BEST_STATE,
"Unexpected best state");
12673 StateWrapper<BitIntegerState<uint8_t, 15>, AAInvariantLoadPointer>;
12677 AAInvariantLoadPointerImpl(
const IRPosition &IRP, Attributor &
A)
12680 bool isKnownInvariant()
const final {
12681 return isKnownLocallyInvariant() && isKnown(IS_LOCALLY_CONSTRAINED);
12684 bool isKnownLocallyInvariant()
const final {
12685 if (isKnown(IS_LOCALLY_INVARIANT))
12687 return isKnown(IS_NOALIAS | IS_NOEFFECT);
12690 bool isAssumedInvariant()
const final {
12691 return isAssumedLocallyInvariant() && isAssumed(IS_LOCALLY_CONSTRAINED);
12694 bool isAssumedLocallyInvariant()
const final {
12695 if (isAssumed(IS_LOCALLY_INVARIANT))
12697 return isAssumed(IS_NOALIAS | IS_NOEFFECT);
12704 if (requiresNoAlias() && !isAssumed(IS_NOALIAS))
12705 return indicatePessimisticFixpoint();
12709 Changed |= updateLocalInvariance(
A);
12715 if (!isKnownInvariant())
12716 return ChangeStatus::UNCHANGED;
12719 const Value *Ptr = &getAssociatedValue();
12720 const auto TagInvariantLoads = [&](
const Use &
U,
bool &) {
12721 if (
U.get() != Ptr)
12729 if (!
A.isRunOn(
I->getFunction()))
12732 if (
I->hasMetadata(LLVMContext::MD_invariant_load))
12736 LI->setMetadata(LLVMContext::MD_invariant_load,
12738 Changed = ChangeStatus::CHANGED;
12743 (void)
A.checkForAllUses(TagInvariantLoads, *
this, *Ptr);
12748 const std::string getAsStr(Attributor *)
const override {
12749 if (isKnownInvariant())
12750 return "load-invariant pointer";
12751 return "non-invariant pointer";
12755 void trackStatistics()
const override {}
12759 bool requiresNoAlias()
const {
12760 switch (getPositionKind()) {
12766 case IRP_CALL_SITE:
12768 case IRP_CALL_SITE_RETURNED: {
12773 case IRP_ARGUMENT: {
12774 const Function *
F = getAssociatedFunction();
12775 assert(
F &&
"no associated function for argument");
12781 bool isExternal()
const {
12782 const Function *
F = getAssociatedFunction();
12786 getPositionKind() != IRP_CALL_SITE_RETURNED;
12790 if (isKnown(IS_NOALIAS) || !isAssumed(IS_NOALIAS))
12791 return ChangeStatus::UNCHANGED;
12794 if (
const auto *ANoAlias =
A.getOrCreateAAFor<AANoAlias>(
12795 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12796 if (ANoAlias->isKnownNoAlias()) {
12797 addKnownBits(IS_NOALIAS);
12798 return ChangeStatus::CHANGED;
12801 if (!ANoAlias->isAssumedNoAlias()) {
12802 removeAssumedBits(IS_NOALIAS);
12803 return ChangeStatus::CHANGED;
12806 return ChangeStatus::UNCHANGED;
12811 if (
const Argument *Arg = getAssociatedArgument()) {
12813 addKnownBits(IS_NOALIAS);
12814 return ChangeStatus::UNCHANGED;
12819 removeAssumedBits(IS_NOALIAS);
12820 return ChangeStatus::CHANGED;
12823 return ChangeStatus::UNCHANGED;
12827 if (isKnown(IS_NOEFFECT) || !isAssumed(IS_NOEFFECT))
12828 return ChangeStatus::UNCHANGED;
12830 if (!getAssociatedFunction())
12831 return indicatePessimisticFixpoint();
12834 return indicatePessimisticFixpoint();
12836 const auto HasNoEffectLoads = [&](
const Use &
U,
bool &) {
12838 return !LI || !LI->mayHaveSideEffects();
12840 if (!
A.checkForAllUses(HasNoEffectLoads, *
this, getAssociatedValue()))
12841 return indicatePessimisticFixpoint();
12843 if (
const auto *AMemoryBehavior =
A.getOrCreateAAFor<AAMemoryBehavior>(
12844 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12847 if (!AMemoryBehavior->isAssumedReadOnly())
12848 return indicatePessimisticFixpoint();
12850 if (AMemoryBehavior->isKnownReadOnly()) {
12851 addKnownBits(IS_NOEFFECT);
12852 return ChangeStatus::UNCHANGED;
12855 return ChangeStatus::UNCHANGED;
12858 if (
const Argument *Arg = getAssociatedArgument()) {
12860 addKnownBits(IS_NOEFFECT);
12861 return ChangeStatus::UNCHANGED;
12866 return indicatePessimisticFixpoint();
12869 return ChangeStatus::UNCHANGED;
12873 if (isKnown(IS_LOCALLY_INVARIANT) || !isAssumed(IS_LOCALLY_INVARIANT))
12874 return ChangeStatus::UNCHANGED;
12877 const auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
12878 getIRPosition(),
this, DepClassTy::REQUIRED);
12880 return ChangeStatus::UNCHANGED;
12882 bool UsedAssumedInformation =
false;
12883 const auto IsLocallyInvariantLoadIfPointer = [&](
const Value &
V) {
12884 if (!
V.getType()->isPointerTy())
12886 const auto *IsInvariantLoadPointer =
12888 DepClassTy::REQUIRED);
12890 if (!IsInvariantLoadPointer)
12893 if (IsInvariantLoadPointer->isKnownLocallyInvariant())
12895 if (!IsInvariantLoadPointer->isAssumedLocallyInvariant())
12898 UsedAssumedInformation =
true;
12901 if (!AUO->forallUnderlyingObjects(IsLocallyInvariantLoadIfPointer))
12902 return indicatePessimisticFixpoint();
12908 if (!IsLocallyInvariantLoadIfPointer(*Arg))
12909 return indicatePessimisticFixpoint();
12914 if (!UsedAssumedInformation) {
12916 addKnownBits(IS_LOCALLY_INVARIANT);
12917 return ChangeStatus::CHANGED;
12920 return ChangeStatus::UNCHANGED;
12924struct AAInvariantLoadPointerFloating final : AAInvariantLoadPointerImpl {
12925 AAInvariantLoadPointerFloating(
const IRPosition &IRP, Attributor &
A)
12926 : AAInvariantLoadPointerImpl(IRP,
A) {}
12929struct AAInvariantLoadPointerReturned final : AAInvariantLoadPointerImpl {
12930 AAInvariantLoadPointerReturned(
const IRPosition &IRP, Attributor &
A)
12931 : AAInvariantLoadPointerImpl(IRP,
A) {}
12934 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12938struct AAInvariantLoadPointerCallSiteReturned final
12939 : AAInvariantLoadPointerImpl {
12940 AAInvariantLoadPointerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12941 : AAInvariantLoadPointerImpl(IRP,
A) {}
12944 const Function *
F = getAssociatedFunction();
12945 assert(
F &&
"no associated function for return from call");
12947 if (!
F->isDeclaration() && !
F->isIntrinsic())
12948 return AAInvariantLoadPointerImpl::initialize(
A);
12953 return AAInvariantLoadPointerImpl::initialize(
A);
12955 if (
F->onlyReadsMemory() &&
F->hasNoSync())
12956 return AAInvariantLoadPointerImpl::initialize(
A);
12960 indicatePessimisticFixpoint();
12964struct AAInvariantLoadPointerArgument final : AAInvariantLoadPointerImpl {
12965 AAInvariantLoadPointerArgument(
const IRPosition &IRP, Attributor &
A)
12966 : AAInvariantLoadPointerImpl(IRP,
A) {}
12969 const Function *
F = getAssociatedFunction();
12970 assert(
F &&
"no associated function for argument");
12973 addKnownBits(IS_LOCALLY_CONSTRAINED);
12977 if (!
F->hasLocalLinkage())
12978 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12982struct AAInvariantLoadPointerCallSiteArgument final
12983 : AAInvariantLoadPointerImpl {
12984 AAInvariantLoadPointerCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12985 : AAInvariantLoadPointerImpl(IRP,
A) {}
12992template <
typename InstType>
12993static bool makeChange(Attributor &
A, InstType *MemInst,
const Use &U,
12994 Value *OriginalValue, PointerType *NewPtrTy,
12995 bool UseOriginalValue) {
12996 if (
U.getOperandNo() != InstType::getPointerOperandIndex())
12999 if (MemInst->isVolatile()) {
13000 auto *
TTI =
A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(
13001 *MemInst->getFunction());
13002 unsigned NewAS = NewPtrTy->getPointerAddressSpace();
13007 if (UseOriginalValue) {
13008 A.changeUseAfterManifest(
const_cast<Use &
>(U), *OriginalValue);
13012 Instruction *CastInst =
new AddrSpaceCastInst(OriginalValue, NewPtrTy);
13014 A.changeUseAfterManifest(
const_cast<Use &
>(U), *CastInst);
13018struct AAAddressSpaceImpl :
public AAAddressSpace {
13019 AAAddressSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13020 : AAAddressSpace(IRP,
A) {}
13023 assert(isValidState() &&
"the AA is invalid");
13024 return AssumedAddressSpace;
13029 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13030 "Associated value is not a pointer");
13032 if (!
A.getInfoCache().getFlatAddressSpace().has_value()) {
13033 indicatePessimisticFixpoint();
13037 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13038 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13039 if (AS != FlatAS) {
13040 [[maybe_unused]]
bool R = takeAddressSpace(AS);
13041 assert(R &&
"The take should happen");
13042 indicateOptimisticFixpoint();
13047 uint32_t OldAddressSpace = AssumedAddressSpace;
13048 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13050 auto CheckAddressSpace = [&](
Value &
Obj) {
13056 unsigned ObjAS =
Obj.getType()->getPointerAddressSpace();
13057 if (ObjAS != FlatAS)
13058 return takeAddressSpace(ObjAS);
13072 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(*F);
13074 if (AssumedAS != ~0U)
13075 return takeAddressSpace(AssumedAS);
13079 return takeAddressSpace(FlatAS);
13082 auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(getIRPosition(),
this,
13083 DepClassTy::REQUIRED);
13084 if (!AUO->forallUnderlyingObjects(CheckAddressSpace))
13085 return indicatePessimisticFixpoint();
13087 return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED
13088 : ChangeStatus::CHANGED;
13095 if (NewAS == InvalidAddressSpace ||
13097 return ChangeStatus::UNCHANGED;
13099 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13101 Value *AssociatedValue = &getAssociatedValue();
13102 Value *OriginalValue = peelAddrspacecast(AssociatedValue, FlatAS);
13105 PointerType::get(getAssociatedType()->
getContext(), NewAS);
13106 bool UseOriginalValue =
13111 auto Pred = [&](
const Use &
U,
bool &) {
13112 if (
U.get() != AssociatedValue)
13123 makeChange(
A, LI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13126 makeChange(
A, SI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13129 makeChange(
A, RMW, U, OriginalValue, NewPtrTy, UseOriginalValue);
13132 makeChange(
A, CmpX, U, OriginalValue, NewPtrTy, UseOriginalValue);
13139 (void)
A.checkForAllUses(Pred, *
this, getAssociatedValue(),
13142 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13146 const std::string getAsStr(Attributor *
A)
const override {
13147 if (!isValidState())
13148 return "addrspace(<invalid>)";
13149 return "addrspace(" +
13150 (AssumedAddressSpace == InvalidAddressSpace
13152 : std::to_string(AssumedAddressSpace)) +
13157 uint32_t AssumedAddressSpace = InvalidAddressSpace;
13159 bool takeAddressSpace(uint32_t AS) {
13160 if (AssumedAddressSpace == InvalidAddressSpace) {
13161 AssumedAddressSpace = AS;
13164 return AssumedAddressSpace == AS;
13167 static Value *peelAddrspacecast(
Value *V,
unsigned FlatAS) {
13169 assert(
I->getSrcAddressSpace() != FlatAS &&
13170 "there should not be flat AS -> non-flat AS");
13171 return I->getPointerOperand();
13174 if (
C->getOpcode() == Instruction::AddrSpaceCast) {
13175 assert(
C->getOperand(0)->getType()->getPointerAddressSpace() !=
13177 "there should not be flat AS -> non-flat AS X");
13178 return C->getOperand(0);
13184struct AAAddressSpaceFloating final : AAAddressSpaceImpl {
13185 AAAddressSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13186 : AAAddressSpaceImpl(IRP,
A) {}
13188 void trackStatistics()
const override {
13193struct AAAddressSpaceReturned final : AAAddressSpaceImpl {
13194 AAAddressSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13195 : AAAddressSpaceImpl(IRP,
A) {}
13201 (void)indicatePessimisticFixpoint();
13204 void trackStatistics()
const override {
13209struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl {
13210 AAAddressSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13211 : AAAddressSpaceImpl(IRP,
A) {}
13213 void trackStatistics()
const override {
13218struct AAAddressSpaceArgument final : AAAddressSpaceImpl {
13219 AAAddressSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13220 : AAAddressSpaceImpl(IRP,
A) {}
13225struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl {
13226 AAAddressSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13227 : AAAddressSpaceImpl(IRP,
A) {}
13233 (void)indicatePessimisticFixpoint();
13236 void trackStatistics()
const override {
13251struct AANoAliasAddrSpaceImpl :
public AANoAliasAddrSpace {
13252 AANoAliasAddrSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13253 : AANoAliasAddrSpace(IRP,
A) {}
13256 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13257 "Associated value is not a pointer");
13261 std::optional<unsigned> FlatAS =
A.getInfoCache().getFlatAddressSpace();
13262 if (!FlatAS.has_value()) {
13263 indicatePessimisticFixpoint();
13269 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13270 if (AS != *FlatAS) {
13272 indicateOptimisticFixpoint();
13277 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13278 uint32_t OldAssumed = getAssumed();
13280 auto CheckAddressSpace = [&](
Value &
Obj) {
13284 unsigned AS =
Obj.getType()->getPointerAddressSpace();
13288 removeAS(
Obj.getType()->getPointerAddressSpace());
13292 const AAUnderlyingObjects *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
13293 getIRPosition(),
this, DepClassTy::REQUIRED);
13295 return indicatePessimisticFixpoint();
13297 return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
13298 : ChangeStatus::CHANGED;
13303 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13305 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13306 if (AS != FlatAS ||
Map.empty())
13307 return ChangeStatus::UNCHANGED;
13309 LLVMContext &Ctx = getAssociatedValue().getContext();
13310 MDNode *NoAliasASNode =
nullptr;
13311 MDBuilder MDB(Ctx);
13313 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13316 unsigned Upper =
I.stop();
13317 unsigned Lower =
I.start();
13318 if (!NoAliasASNode) {
13319 NoAliasASNode = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13322 MDNode *ASRange = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13326 Value *AssociatedValue = &getAssociatedValue();
13329 auto AddNoAliasAttr = [&](
const Use &
U,
bool &) {
13330 if (
U.get() != AssociatedValue)
13333 if (!Inst || Inst->
hasMetadata(LLVMContext::MD_noalias_addrspace))
13340 Inst->
setMetadata(LLVMContext::MD_noalias_addrspace, NoAliasASNode);
13344 (void)
A.checkForAllUses(AddNoAliasAttr, *
this, *AssociatedValue,
13346 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13350 const std::string getAsStr(Attributor *
A)
const override {
13351 if (!isValidState())
13352 return "<invalid>";
13354 raw_string_ostream OS(Str);
13355 OS <<
"CanNotBeAddrSpace(";
13356 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13357 unsigned Upper =
I.stop();
13358 unsigned Lower =
I.start();
13359 OS <<
' ' <<
'[' <<
Upper <<
',' <<
Lower + 1 <<
')';
13366 void removeAS(
unsigned AS) {
13367 RangeMap::iterator
I =
Map.find(AS);
13369 if (
I !=
Map.end()) {
13370 unsigned Upper =
I.stop();
13371 unsigned Lower =
I.start();
13375 if (AS != ~((
unsigned)0) && AS + 1 <=
Upper)
13377 if (AS != 0 &&
Lower <= AS - 1)
13382 void resetASRanges(Attributor &
A) {
13384 Map.insert(0,
A.getInfoCache().getMaxAddrSpace(),
true);
13388struct AANoAliasAddrSpaceFloating final : AANoAliasAddrSpaceImpl {
13389 AANoAliasAddrSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13390 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13392 void trackStatistics()
const override {
13397struct AANoAliasAddrSpaceReturned final : AANoAliasAddrSpaceImpl {
13398 AANoAliasAddrSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13399 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13401 void trackStatistics()
const override {
13406struct AANoAliasAddrSpaceCallSiteReturned final : AANoAliasAddrSpaceImpl {
13407 AANoAliasAddrSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13408 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13410 void trackStatistics()
const override {
13415struct AANoAliasAddrSpaceArgument final : AANoAliasAddrSpaceImpl {
13416 AANoAliasAddrSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13417 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13419 void trackStatistics()
const override {
13424struct AANoAliasAddrSpaceCallSiteArgument final : AANoAliasAddrSpaceImpl {
13425 AANoAliasAddrSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13426 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13428 void trackStatistics()
const override {
13435struct AAAllocationInfoImpl :
public AAAllocationInfo {
13436 AAAllocationInfoImpl(
const IRPosition &IRP, Attributor &
A)
13437 : AAAllocationInfo(IRP,
A) {}
13439 std::optional<TypeSize> getAllocatedSize()
const override {
13440 assert(isValidState() &&
"the AA is invalid");
13441 return AssumedAllocatedSize;
13444 std::optional<TypeSize> findInitialAllocationSize(Instruction *
I,
13445 const DataLayout &
DL) {
13448 switch (
I->getOpcode()) {
13449 case Instruction::Alloca: {
13454 return std::nullopt;
13460 const IRPosition &IRP = getIRPosition();
13465 return indicatePessimisticFixpoint();
13467 bool IsKnownNoCapture;
13469 A,
this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture))
13470 return indicatePessimisticFixpoint();
13472 const AAPointerInfo *PI =
13473 A.getOrCreateAAFor<AAPointerInfo>(IRP, *
this, DepClassTy::REQUIRED);
13476 return indicatePessimisticFixpoint();
13479 return indicatePessimisticFixpoint();
13481 const DataLayout &
DL =
A.getDataLayout();
13482 const auto AllocationSize = findInitialAllocationSize(
I,
DL);
13485 if (!AllocationSize)
13486 return indicatePessimisticFixpoint();
13490 if (*AllocationSize == 0)
13491 return indicatePessimisticFixpoint();
13497 return indicatePessimisticFixpoint();
13499 if (BinSize == 0) {
13500 auto NewAllocationSize = std::make_optional<TypeSize>(0,
false);
13501 if (!changeAllocationSize(NewAllocationSize))
13502 return ChangeStatus::UNCHANGED;
13503 return ChangeStatus::CHANGED;
13507 const auto &It = PI->
begin();
13510 if (It->first.Offset != 0)
13511 return indicatePessimisticFixpoint();
13513 uint64_t SizeOfBin = It->first.Offset + It->first.Size;
13515 if (SizeOfBin >= *AllocationSize)
13516 return indicatePessimisticFixpoint();
13518 auto NewAllocationSize = std::make_optional<TypeSize>(SizeOfBin * 8,
false);
13520 if (!changeAllocationSize(NewAllocationSize))
13521 return ChangeStatus::UNCHANGED;
13523 return ChangeStatus::CHANGED;
13529 assert(isValidState() &&
13530 "Manifest should only be called if the state is valid.");
13534 auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
13536 unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
13538 switch (
I->getOpcode()) {
13540 case Instruction::Alloca: {
13544 Type *CharType = Type::getInt8Ty(
I->getContext());
13546 auto *NumBytesToValue =
13547 ConstantInt::get(
I->getContext(), APInt(32, NumBytesToAllocate));
13550 insertPt = std::next(insertPt);
13551 AllocaInst *NewAllocaInst =
13556 return ChangeStatus::CHANGED;
13564 return ChangeStatus::UNCHANGED;
13568 const std::string getAsStr(Attributor *
A)
const override {
13569 if (!isValidState())
13570 return "allocationinfo(<invalid>)";
13571 return "allocationinfo(" +
13572 (AssumedAllocatedSize == HasNoAllocationSize
13574 : std::to_string(AssumedAllocatedSize->getFixedValue())) +
13579 std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
13583 bool changeAllocationSize(std::optional<TypeSize>
Size) {
13584 if (AssumedAllocatedSize == HasNoAllocationSize ||
13585 AssumedAllocatedSize !=
Size) {
13586 AssumedAllocatedSize =
Size;
13593struct AAAllocationInfoFloating : AAAllocationInfoImpl {
13594 AAAllocationInfoFloating(
const IRPosition &IRP, Attributor &
A)
13595 : AAAllocationInfoImpl(IRP,
A) {}
13597 void trackStatistics()
const override {
13602struct AAAllocationInfoReturned : AAAllocationInfoImpl {
13603 AAAllocationInfoReturned(
const IRPosition &IRP, Attributor &
A)
13604 : AAAllocationInfoImpl(IRP,
A) {}
13610 (void)indicatePessimisticFixpoint();
13613 void trackStatistics()
const override {
13618struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl {
13619 AAAllocationInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13620 : AAAllocationInfoImpl(IRP,
A) {}
13622 void trackStatistics()
const override {
13627struct AAAllocationInfoArgument : AAAllocationInfoImpl {
13628 AAAllocationInfoArgument(
const IRPosition &IRP, Attributor &
A)
13629 : AAAllocationInfoImpl(IRP,
A) {}
13631 void trackStatistics()
const override {
13636struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl {
13637 AAAllocationInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13638 : AAAllocationInfoImpl(IRP,
A) {}
13643 (void)indicatePessimisticFixpoint();
13646 void trackStatistics()
const override {
13695#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \
13696 case IRPosition::PK: \
13697 llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");
13699#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \
13700 case IRPosition::PK: \
13701 AA = new (A.Allocator) CLASS##SUFFIX(IRP, A); \
13705#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13706 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13707 CLASS *AA = nullptr; \
13708 switch (IRP.getPositionKind()) { \
13709 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13710 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13711 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13712 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13713 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13714 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13715 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13716 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13721#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13722 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13723 CLASS *AA = nullptr; \
13724 switch (IRP.getPositionKind()) { \
13725 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13726 SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \
13727 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13728 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13729 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13730 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13731 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13732 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13737#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS) \
13738 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13739 CLASS *AA = nullptr; \
13740 switch (IRP.getPositionKind()) { \
13741 SWITCH_PK_CREATE(CLASS, IRP, POS, SUFFIX) \
13743 llvm_unreachable("Cannot create " #CLASS " for position otherthan " #POS \
13749#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13750 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13751 CLASS *AA = nullptr; \
13752 switch (IRP.getPositionKind()) { \
13753 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13754 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13755 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13756 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13757 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13758 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13759 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13760 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13765#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13766 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13767 CLASS *AA = nullptr; \
13768 switch (IRP.getPositionKind()) { \
13769 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13770 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13771 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13772 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13773 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13774 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13775 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13776 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13781#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13782 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13783 CLASS *AA = nullptr; \
13784 switch (IRP.getPositionKind()) { \
13785 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13786 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13787 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13788 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13789 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13790 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13791 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13792 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13844#undef CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION
13845#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
13846#undef CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION
13847#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
13848#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
13849#undef CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION
13850#undef SWITCH_PK_CREATE
13851#undef SWITCH_PK_INV
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file implements a class to represent arbitrary precision integral constant values and operations...
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis false
This file contains the simple types necessary to represent the attributes associated with functions a...
#define STATS_DECLTRACK(NAME, TYPE, MSG)
static std::optional< Constant * > askForAssumedConstant(Attributor &A, const AbstractAttribute &QueryingAA, const IRPosition &IRP, Type &Ty)
static cl::opt< unsigned, true > MaxPotentialValues("attributor-max-potential-values", cl::Hidden, cl::desc("Maximum number of potential values to be " "tracked for each position."), cl::location(llvm::PotentialConstantIntValuesState::MaxPotentialValues), cl::init(7))
static void clampReturnedValueStates(Attributor &A, const AAType &QueryingAA, StateType &S, const IRPosition::CallBaseContext *CBContext=nullptr)
Clamp the information known for all returned values of a function (identified by QueryingAA) into S.
#define STATS_DECLTRACK_FN_ATTR(NAME)
#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static cl::opt< int > MaxPotentialValuesIterations("attributor-max-potential-values-iterations", cl::Hidden, cl::desc("Maximum number of iterations we keep dismantling potential values."), cl::init(64))
#define STATS_DECLTRACK_CS_ATTR(NAME)
#define PIPE_OPERATOR(CLASS)
static bool mayBeInCycle(const CycleInfo *CI, const Instruction *I, bool HeaderOnly, Cycle **CPtr=nullptr)
#define STATS_DECLTRACK_ARG_ATTR(NAME)
static const Value * stripAndAccumulateOffsets(Attributor &A, const AbstractAttribute &QueryingAA, const Value *Val, const DataLayout &DL, APInt &Offset, bool GetMinOffset, bool AllowNonInbounds, bool UseAssumed=false)
#define STATS_DECLTRACK_CSRET_ATTR(NAME)
static cl::opt< bool > ManifestInternal("attributor-manifest-internal", cl::Hidden, cl::desc("Manifest Attributor internal string attributes."), cl::init(false))
static Value * constructPointer(Value *Ptr, int64_t Offset, IRBuilder< NoFolder > &IRB)
Helper function to create a pointer based on Ptr, and advanced by Offset bytes.
#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
#define BUILD_STAT_NAME(NAME, TYPE)
static bool isDenselyPacked(Type *Ty, const DataLayout &DL)
Checks if a type could have padding bytes.
#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static const Value * getMinimalBaseOfPointer(Attributor &A, const AbstractAttribute &QueryingAA, const Value *Ptr, int64_t &BytesOffset, const DataLayout &DL, bool AllowNonInbounds=false)
#define STATS_DECLTRACK_FNRET_ATTR(NAME)
#define STATS_DECLTRACK_CSARG_ATTR(NAME)
#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS)
#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static cl::opt< int > MaxHeapToStackSize("max-heap-to-stack-size", cl::init(128), cl::Hidden)
#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
#define STATS_DECLTRACK_FLOATING_ATTR(NAME)
#define STATS_DECL(NAME, TYPE, MSG)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool isReachableImpl(SmallVectorImpl< BasicBlock * > &Worklist, const StopSetT &StopSet, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet, const DominatorTree *DT, const LoopInfo *LI, const CycleInfo *CI)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file declares an analysis pass that computes CycleInfo for LLVM IR, specialized from GenericCycl...
DXIL Forward Handle Accesses
This file defines DenseMapInfo traits for DenseMap.
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
static unsigned getAddressSpace(const Value *V, unsigned MaxLookup)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
static StringRef getName(Value *V)
dot regions Print regions of function to dot true view regions View regions of function(with no function bodies)"
Remove Loads Into Fake Uses
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
std::pair< BasicBlock *, BasicBlock * > Edge
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
This file defines generic set operations that may be used on set's of different types,...
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static SymbolRef::Type getType(const Symbol *Sym)
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.
static unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type.
static unsigned getSize(unsigned Kind)
LLVM_ABI AACallGraphNode * operator*() const
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A trivial helper function to check to see if the specified pointers are no-alias.
Class for arbitrary precision integers.
int64_t getSExtValue() const
Get sign extended value.
CallBase * getInstruction() const
Return the underlying instruction.
bool isCallbackCall() const
Return true if this ACS represents a callback call.
bool isDirectCall() const
Return true if this ACS represents a direct call.
static LLVM_ABI void getCallbackUses(const CallBase &CB, SmallVectorImpl< const Use * > &CallbackUses)
Add operand uses of CB that represent callback uses into CallbackUses.
int getCallArgOperandNo(Argument &Arg) const
Return the operand index of the underlying instruction associated with Arg.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
unsigned getAddressSpace() const
Return the address space for the allocation.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
This class represents an incoming formal argument to a Function.
LLVM_ABI bool hasNoAliasAttr() const
Return true if this argument has the noalias attribute.
LLVM_ABI bool onlyReadsMemory() const
Return true if this argument has the readonly or readnone attribute.
LLVM_ABI bool hasPointeeInMemoryValueAttr() const
Return true if this argument has the byval, sret, inalloca, preallocated, or byref attribute.
LLVM_ABI bool hasReturnedAttr() const
Return true if this argument has the returned attribute.
LLVM_ABI bool hasByValAttr() const
Return true if this argument has the byval attribute.
const Function * getParent() const
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
Functions, function parameters, and return types can have attributes to indicate how they should be t...
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
LLVM_ABI FPClassTest getNoFPClass() const
Return the FPClassTest for nofpclass.
LLVM_ABI Attribute::AttrKind getKindAsEnum() const
Return the attribute's kind as an enum (Attribute::AttrKind).
LLVM_ABI MemoryEffects getMemoryEffects() const
Returns memory effects.
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
static LLVM_ABI Attribute getWithCaptureInfo(LLVMContext &Context, CaptureInfo CI)
static bool isEnumAttrKind(AttrKind Kind)
bool isValid() const
Return true if the attribute is any kind of attribute.
LLVM_ABI CaptureInfo getCaptureInfo() const
Returns information from captures attribute.
LLVM Basic Block Representation.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Instruction & front() const
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
BinaryOps getOpcode() const
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
Value * getCalledOperand() const
const Use & getCalledOperandUse() const
Attribute getFnAttr(StringRef Kind) const
Get the attribute of a given kind for the function.
const Use & getArgOperandUse(unsigned i) const
Wrappers for getting the Use of a call argument.
LLVM_ABI std::optional< ConstantRange > getRange() const
If this return value has a range attribute, return the value range of the argument.
Value * getArgOperand(unsigned i) const
bool isBundleOperand(unsigned Idx) const
Return true if the operand at index Idx is a bundle operand.
bool isConvergent() const
Determine if the invoke is convergent.
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static CaptureInfo none()
Create CaptureInfo that does not capture any components of the pointer.
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
LLVM_ABI bool isIntegerCast() const
There are several places where we need to know if a cast instruction only deals with integer source a...
Type * getDestTy() const
Return the destination type, as a convenience.
bool isEquality() const
Determine if this is an equals/not equals predicate.
bool isFalseWhenEqual() const
This is just a convenience.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
bool isTrueWhenEqual() const
This is just a convenience.
Predicate getPredicate() const
Return the predicate for this instruction.
Conditional Branch instruction.
Value * getCondition() const
BasicBlock * getSuccessor(unsigned i) const
static LLVM_ABI Constant * getExtractElement(Constant *Vec, Constant *Idx, Type *OnlyIfReducedTy=nullptr)
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
This class represents a range of values.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
LLVM_ABI bool isEmptySet() const
Return true if this set contains no members.
bool isSingleElement() const
Return true if this set contains exactly one member.
static LLVM_ABI ConstantRange makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other)
Produce the smallest range such that all values that may satisfy the given predicate with any value c...
const APInt & getUpper() const
Return the upper value for this range.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
const BasicBlock & getEntryBlock() const
iterator_range< arg_iterator > args()
const Function & getFunction() const
Argument * getArg(unsigned i) const
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
CycleT * getCycle(const BlockT *Block) const
Find the innermost cycle containing a given block.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasLocalLinkage() const
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
Value * CreatePtrAdd(Value *Ptr, Value *Offset, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI bool isLifetimeStartOrEnd() const LLVM_READONLY
Return true if the instruction is a llvm.lifetime.start or llvm.lifetime.end marker.
bool mayReadOrWriteMemory() const
Return true if this instruction may read or write memory.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
bool hasMetadata() const
Return true if this instruction has any metadata attached to it.
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI BasicBlock * getSuccessor(unsigned Idx) const LLVM_READONLY
Return the specified successor. This instruction must be a terminator.
LLVM_ABI bool mayHaveSideEffects() const LLVM_READONLY
Return true if the instruction may have side effects.
bool isTerminator() const
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This is an important class for using LLVM in a threaded context.
ConstantRange getConstantRange(Value *V, Instruction *CxtI, bool UndefAllowed)
Return the ConstantRange constraint that is known to hold for the specified value at the specified in...
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static LLVM_ABI MDNode * getMostGenericRange(MDNode *A, MDNode *B)
static MemoryEffectsBase readOnly()
bool doesNotAccessMemory() const
Whether this function accesses no memory.
static MemoryEffectsBase argMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase inaccessibleMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
bool onlyAccessesInaccessibleMem() const
Whether this function only (at most) accesses inaccessible memory.
ModRefInfo getModRef(Location Loc) const
Get ModRefInfo for the given Location.
bool onlyAccessesArgPointees() const
Whether this function only (at most) accesses argument memory.
bool onlyReadsMemory() const
Whether this function only (at most) reads memory.
static MemoryEffectsBase writeOnly()
static MemoryEffectsBase inaccessibleOrArgMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase none()
bool onlyAccessesInaccessibleOrArgMem() const
Whether this function only (at most) accesses argument and inaccessible memory.
static MemoryEffectsBase unknown()
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static SizeOffsetValue unknown()
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Value * getReturnValue() const
Convenience accessor. Returns null if there is no return value.
LLVM_ABI const SCEV * getSCEVAtScope(const SCEV *S, const Loop *L)
Return a SCEV expression for the specified value at the specified scope in the program.
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI unsigned getSmallConstantMaxTripCount(const Loop *L, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Returns the upper bound of the loop trip count as a normal unsigned value.
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static unsigned getPointerOperandIndex()
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
TypeSize getElementOffset(unsigned Idx) const
TypeSize getElementOffsetInBits(unsigned Idx) const
Class to represent struct types.
unsigned getNumElements() const
Random access to the elements.
Type * getElementType(unsigned N) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isPointerTy() const
True if this is an instance of PointerType.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
bool isPtrOrPtrVectorTy() const
Return true if this is a pointer type or a vector of pointer types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
bool isVoidTy() const
Return true if this is 'void'.
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
BasicBlock * getSuccessor(unsigned i=0) const
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
User * getUser() const
Returns the User that contains this Use.
const Use & getOperandUse(unsigned i) const
LLVM_ABI bool isDroppable() const
A droppable user is a user for which uses can be dropped without affecting correctness and should be ...
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
unsigned getNumOperands() const
ValueT lookup(const KeyT &Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
static constexpr uint64_t MaximumAlignment
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
LLVM_ABI const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr, bool LookThroughIntToPtr=false) const
Accumulate the constant offset this value has compared to a base pointer.
static constexpr unsigned MaxAlignmentExponent
The maximum alignment for instructions.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
constexpr ScalarTy getFixedValue() const
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
SetVector< Function * >::iterator I
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
LLVM_ABI bool isAssumedReadNone(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readnone.
LLVM_ABI bool isAssumedReadOnly(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readonly.
raw_ostream & operator<<(raw_ostream &OS, const RangeTy &R)
LLVM_ABI std::optional< Value * > combineOptionalValuesInAAValueLatice(const std::optional< Value * > &A, const std::optional< Value * > &B, Type *Ty)
Return the combination of A and B such that the result is a possible value of both.
LLVM_ABI bool isValidAtPosition(const ValueAndContext &VAC, InformationCache &InfoCache)
Return true if the value of VAC is a valid at the position of VAC, that is a constant,...
LLVM_ABI bool isAssumedThreadLocalObject(Attributor &A, Value &Obj, const AbstractAttribute &QueryingAA)
Return true if Obj is assumed to be a thread local object.
LLVM_ABI bool isGPUConstantAddressSpace(const Module &M, unsigned AS)
Check if the given address space AS corresponds to a GPU constant address space for the target triple...
LLVM_ABI bool isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA, const Value &V, bool ForAnalysisOnly=true)
Return true if V is dynamically unique, that is, there are no two "instances" of V at runtime with di...
LLVM_ABI bool getPotentialCopiesOfStoredValue(Attributor &A, StoreInst &SI, SmallSetVector< Value *, 4 > &PotentialCopies, const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, bool OnlyExact=false)
Collect all potential values of the one stored by SI into PotentialCopies.
LLVM_ABI bool isGPUSharedAddressSpace(const Module &M, unsigned AS)
Check if the given address space AS corresponds to a GPU shared address space for the target triple i...
LLVM_ABI bool isGPULocalAddressSpace(const Module &M, unsigned AS)
Check if the given address space AS corresponds to a GPU local/private address space for the target t...
SmallPtrSet< Instruction *, 4 > InstExclusionSetTy
LLVM_ABI bool isGPU(const Module &M)
Return true iff M target a GPU (and we can use GPU AS reasoning).
ValueScope
Flags to distinguish intra-procedural queries from potentially inter-procedural queries.
LLVM_ABI bool isValidInScope(const Value &V, const Function *Scope)
Return true if V is a valid value in Scope, that is a constant or an instruction/argument of Scope.
LLVM_ABI bool isPotentiallyReachable(Attributor &A, const Instruction &FromI, const Instruction &ToI, const AbstractAttribute &QueryingAA, const AA::InstExclusionSetTy *ExclusionSet=nullptr, std::function< bool(const Function &F)> GoBackwardsCB=nullptr)
Return true if ToI is potentially reachable from FromI without running into any instruction in Exclus...
LLVM_ABI bool isNoSyncInst(Attributor &A, const Instruction &I, const AbstractAttribute &QueryingAA)
Return true if I is a nosync instruction.
bool hasAssumedIRAttr(Attributor &A, const AbstractAttribute *QueryingAA, const IRPosition &IRP, DepClassTy DepClass, bool &IsKnown, bool IgnoreSubsumingPositions=false, const AAType **AAPtr=nullptr)
Helper to avoid creating an AA for IR Attributes that might already be set.
LLVM_ABI bool getPotentiallyLoadedValues(Attributor &A, LoadInst &LI, SmallSetVector< Value *, 4 > &PotentialValues, SmallSetVector< Instruction *, 4 > &PotentialValueOrigins, const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, bool OnlyExact=false)
Collect all potential values LI could read into PotentialValues.
LLVM_ABI Value * getWithType(Value &V, Type &Ty)
Try to convert V to type Ty without introducing new instructions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
@ Unsupported
This operation is completely unsupported on the target.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
@ CE
Windows NT (Windows on ARM)
@ Valid
The data is already valid.
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
unsigned combineHashValue(unsigned a, unsigned b)
Simplistic combination of 32-bit hash values into 32-bit hash values.
ElementType
The element type of an SRV or UAV resource.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
@ User
could "use" a pointer
NodeAddr< UseNode * > Use
Context & getContext() const
friend class Instruction
Iterator for Instructions in a `BasicBlock.
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
bool operator<(int64_t V1, const APSInt &V2)
FunctionAddr VTableAddr Value
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt gcd(const DynamicAPInt &A, const DynamicAPInt &B)
LLVM_ABI KnownFPClass computeKnownFPClass(const Value *V, const APInt &DemandedElts, FPClassTest InterestedClasses, const SimplifyQuery &SQ, unsigned Depth=0)
Determine which floating-point classes are valid for V, and return them in KnownFPClass bit sets.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI bool isLegalToPromote(const CallBase &CB, Function *Callee, const char **FailureReason=nullptr)
Return true if the given indirect call site can be made to call Callee.
LLVM_ABI Constant * getInitialValueOfAllocation(const Value *V, const TargetLibraryInfo *TLI, Type *Ty)
If this is a call to an allocation function that initializes memory to a fixed value,...
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
@ Undef
Value of the register doesn't matter.
auto pred_end(const MachineBasicBlock *BB)
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
auto successors(const MachineBasicBlock *BB)
LLVM_ABI bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI)
Return true if this is a call to an allocation function that does not have side effects that we are r...
APFloat abs(APFloat X)
Returns the absolute value of the argument.
LLVM_ABI raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
LLVM_ABI Value * getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI)
Gets the alignment argument for an aligned_alloc-like function, using either built-in knowledge based...
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
LLVM_ABI Value * simplifyInstructionWithOperands(Instruction *I, ArrayRef< Value * > NewOps, const SimplifyQuery &Q)
Like simplifyInstruction but the operands of I are replaced with NewOps.
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
LLVM_ABI bool isNoAliasCall(const Value *V)
Return true if this pointer is returned by a noalias function.
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
LLVM_ABI bool isSafeToSpeculativelyExecute(const Instruction *I, const Instruction *CtxI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr, bool UseVariableInfo=true, bool IgnoreUBImplyingAttrs=true)
Return true if the instruction does not have any effects besides calculating the result and does not ...
bool isa_and_nonnull(const Y &Val)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI ConstantRange getConstantRangeFromMetadata(const MDNode &RangeMD)
Parse out a conservative ConstantRange from !range metadata.
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
LLVM_ABI Value * simplifyInstruction(Instruction *I, const SimplifyQuery &Q)
See if we can compute a simplified version of this instruction.
auto dyn_cast_or_null(const Y &Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(const CallBase *Call, bool MustPreserveNullness)
{launder,strip}.invariant.group returns pointer that aliases its argument, and it only captures point...
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
PotentialValuesState< std::pair< AA::ValueAndContext, AA::ValueScope > > PotentialLLVMValuesState
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI bool NullPointerIsDefined(const Function *F, unsigned AS=0)
Check whether null pointer dereferencing is considered undefined behavior for a given function or an ...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
LLVM_ABI bool wouldInstructionBeTriviallyDead(const Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction would have no side effects if it was not used.
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI CallBase & promoteCall(CallBase &CB, Function *Callee, CastInst **RetBitCast=nullptr)
Promote the given indirect call site to unconditionally call Callee.
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...
LLVM_ABI bool hasAssumption(const Function &F, const KnownAssumptionString &AssumptionStr)
Return true if F has the assumption AssumptionStr attached.
LLVM_ABI RetainedKnowledge getKnowledgeFromUse(const Use *U, ArrayRef< Attribute::AttrKind > AttrKinds)
Return a valid Knowledge associated to the Use U if its Attribute kind is in AttrKinds.
@ Success
The lock was released successfully.
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth=0)
Return true if the given value is known to be non-zero when defined.
AtomicOrdering
Atomic ordering for LLVM's memory model.
PotentialValuesState< APInt > PotentialConstantIntValuesState
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
InterleavedRange< Range > interleaved_array(const Range &R, StringRef Separator=", ")
Output range R as an array of interleaved elements.
ChangeStatus clampStateAndIndicateChange< DerefState >(DerefState &S, const DerefState &R)
void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, RemapFlags Flags=RF_None, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr, const MetadataPredicate *IdentityMD=nullptr)
Convert the instruction operands from referencing the current values into those specified by VM.
DWARFExpression::Operation Op
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI Value * getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI)
If this if a call to a free function, return the freed operand.
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...
constexpr unsigned BitWidth
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
auto pred_begin(const MachineBasicBlock *BB)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
LLVM_ABI std::optional< APInt > getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, function_ref< const Value *(const Value *)> Mapper=[](const Value *V) { return V;})
Return the size of the requested allocation.
LLVM_ABI DenseSet< StringRef > getAssumptions(const Function &F)
Return the set of all assumptions for the function F.
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
LLVM_ABI Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
@ OPTIONAL
The target may be valid if the source is not.
@ NONE
Do not track a dependence between source and target.
@ REQUIRED
The target cannot be valid if the source is not.
LLVM_ABI UseCaptureInfo DetermineUseCaptureKind(const Use &U, const Value *Base)
Determine what kind of capture behaviour U may exhibit.
LLVM_ABI Value * simplifyCmpInst(CmpPredicate Predicate, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a CmpInst, fold the result or return null.
LLVM_ABI bool mayContainIrreducibleControl(const Function &F, const LoopInfo *LI)
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool capturesNothing(CaptureComponents CC)
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
constexpr StringRef AssumptionAttrKey
The key we use for assumption attributes.
constexpr bool isCallableCC(CallingConv::ID CC)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
A type to track pointer/struct usage and accesses for AAPointerInfo.
bool forallInterferingAccesses(AA::RangeTy Range, F CB) const
See AAPointerInfo::forallInterferingAccesses.
AAPointerInfo::const_bin_iterator end() const
ChangeStatus addAccess(Attributor &A, const AAPointerInfo::RangeList &Ranges, Instruction &I, std::optional< Value * > Content, AAPointerInfo::AccessKind Kind, Type *Ty, Instruction *RemoteI=nullptr)
Add a new Access to the state at offset Offset and with size Size.
DenseMap< const Instruction *, SmallVector< unsigned > > RemoteIMap
AAPointerInfo::const_bin_iterator begin() const
AAPointerInfo::OffsetInfo ReturnedOffsets
Flag to determine if the underlying pointer is reaching a return statement in the associated function...
State & operator=(State &&R)
State(State &&SIS)=default
const AAPointerInfo::Access & getAccess(unsigned Index) const
SmallVector< AAPointerInfo::Access > AccessList
bool isAtFixpoint() const override
See AbstractState::isAtFixpoint().
bool forallInterferingAccesses(Instruction &I, F CB, AA::RangeTy &Range) const
See AAPointerInfo::forallInterferingAccesses.
static State getWorstState(const State &SIS)
Return the worst possible representable state.
int64_t numOffsetBins() const
AAPointerInfo::OffsetBinsTy OffsetBins
ChangeStatus indicateOptimisticFixpoint() override
See AbstractState::indicateOptimisticFixpoint().
State & operator=(const State &R)
ChangeStatus indicatePessimisticFixpoint() override
See AbstractState::indicatePessimisticFixpoint().
const State & getAssumed() const
static State getBestState(const State &SIS)
Return the best possible representable state.
bool isValidState() const override
See AbstractState::isValidState().
----------------—AAIntraFnReachability Attribute-----------------------—
ReachabilityQueryInfo(const ReachabilityQueryInfo &RQI)
unsigned Hash
Precomputed hash for this RQI.
const Instruction * From
Start here,.
Reachable Result
and remember if it worked:
ReachabilityQueryInfo(const Instruction *From, const ToTy *To)
ReachabilityQueryInfo(Attributor &A, const Instruction &From, const ToTy &To, const AA::InstExclusionSetTy *ES, bool MakeUnique)
Constructor replacement to ensure unique and stable sets are used for the cache.
const ToTy * To
reach this place,
const AA::InstExclusionSetTy * ExclusionSet
without going through any of these instructions,
unsigned computeHashValue() const
An abstract interface for address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all align attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Align getKnownAlign() const
Return known alignment.
static LLVM_ABI const char ID
An abstract attribute for getting assumption information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract state for querying live call edges.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for specializing "dynamic" components of denormal_fpenv to a known denormal mod...
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all dereferenceable attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for llvm::GlobalValue information interference.
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)
An abstract interface for indirect call information interference.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface to track if a value leaves it's defining function instance.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for computing reachability between functions.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool canReach(Attributor &A, const Function &Fn) const
If the function represented by this possition can reach Fn.
virtual bool instructionCanReach(Attributor &A, const Instruction &Inst, const Function &Fn, const AA::InstExclusionSetTy *ExclusionSet=nullptr) const =0
Can Inst reach Fn.
An abstract interface to determine reachability of point A to B.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for identifying pointers from which loads can be marked invariant.
static LLVM_ABI const char ID
Unique ID (due to the unique address).
An abstract interface for liveness abstract attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for memory access kind related attributes (readnone/readonly/writeonly).
bool isAssumedReadOnly() const
Return true if we assume that the underlying value is not accessed (=written) in its respective scope...
bool isKnownReadNone() const
Return true if we know that the underlying value is not read or accessed in its respective scope.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool isAssumedReadNone() const
Return true if we assume that the underlying value is not read or accessed in its respective scope.
An abstract interface for all memory location attributes (readnone/argmemonly/inaccessiblememonly/ina...
static LLVM_ABI std::string getMemoryLocationsAsStr(MemoryLocationsKind MLK)
Return the locations encoded by MLK as a readable string.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
StateType::base_t MemoryLocationsKind
An abstract interface for all nonnull attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for potential address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all noalias attributes.
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all nocapture attributes.
@ NO_CAPTURE_MAYBE_RETURNED
If we do not capture the value in memory or through integers we can only communicate it back as a der...
@ NO_CAPTURE
If we do not capture the value in memory, through integers, or as a derived pointer we know it is not...
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool isAssumedNoCaptureMaybeReturned() const
Return true if we assume that the underlying value is not captured in its respective scope but we all...
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI void determineFunctionCaptureCapabilities(const IRPosition &IRP, const Function &F, BitIntegerState &State)
Update State according to the capture capabilities of F for position IRP.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for nofree.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for norecurse.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for noreturn.
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 bool isAlignedBarrier(const CallBase &CB, bool ExecutedAligned)
Helper function to determine if CB is an aligned (GPU) barrier.
static LLVM_ABI bool isNonRelaxedAtomic(const Instruction *I)
Helper function used to determine whether an instruction is non-relaxed atomic.
An abstract interface for all noundef attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for determining the necessity of the convergent attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all nonnull attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See AbstractAttribute::isImpliedByIR(...).
A helper containing a list of offsets computed for a Use.
A container for a list of ranges.
static void set_difference(const RangeList &L, const RangeList &R, RangeList &D)
Copy ranges from L that are not in R, into D.
An abstract interface for struct information.
virtual bool reachesReturn() const =0
OffsetBinsTy::const_iterator const_bin_iterator
virtual const_bin_iterator begin() const =0
DenseMap< AA::RangeTy, SmallSet< unsigned, 4 > > OffsetBinsTy
static LLVM_ABI const char ID
Unique ID (due to the unique address)
virtual int64_t numOffsetBins() const =0
An abstract interface for potential values analysis.
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 Value * getSingleValue(Attributor &A, const AbstractAttribute &AA, const IRPosition &IRP, SmallVectorImpl< AA::ValueAndContext > &Values)
Extract the single value in Values if any.
An abstract interface for privatizability.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for undefined behavior.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for getting all assumption underlying objects.
virtual bool forallUnderlyingObjects(function_ref< bool(Value &)> Pred, AA::ValueScope Scope=AA::Interprocedural) const =0
Check Pred on all underlying objects in Scope collected so far.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for range value analysis.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for value simplify abstract attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for willreturn.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Helper to represent an access offset and size, with logic to deal with uncertainty and check for over...
static constexpr int64_t Unknown
static RangeTy getUnknown()
const Instruction * getCtxI() const
Base struct for all "concrete attribute" deductions.
void print(raw_ostream &OS) const
Helper functions, for debug purposes only.
virtual StateType & getState()=0
Return the internal abstract state for inspection.
An interface to query the internal state of an abstract attribute.
virtual bool isAtFixpoint() const =0
Return if this abstract state is fixed, thus does not need to be updated if information changes as it...
virtual bool isValidState() const =0
Return if this abstract state is in a valid state.
Helper for AA::PointerInfo::Access DenseMap/Set usage ignoring everythign but the instruction.
static unsigned getHashValue(const Access &A)
AAPointerInfo::Access Access
static Access getTombstoneKey()
DenseMapInfo< Instruction * > Base
static bool isEqual(const Access &LHS, const Access &RHS)
static Access getEmptyKey()
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
std::function< void( const ArgumentReplacementInfo &, Function &, Function::arg_iterator)> CalleeRepairCBTy
Callee repair callback type.
const Argument & getReplacedArg() const
std::function< void(const ArgumentReplacementInfo &, AbstractCallSite, SmallVectorImpl< Value * > &)> ACSRepairCBTy
Abstract call site (ACS) repair callback type.
The fixpoint analysis framework that orchestrates the attribute deduction.
std::function< std::optional< Value * >( const IRPosition &, const AbstractAttribute *, bool &)> SimplifictionCallbackTy
Register CB as a simplification callback.
Specialization of the integer state for a bit-wise encoding.
BitIntegerState & addKnownBits(base_t Bits)
Add the bits in BitsEncoding to the "known bits".
Simple wrapper for a single bit (boolean) state.
static constexpr DenormalFPEnv getDefault()
static Access getTombstoneKey()
static unsigned getHashValue(const Access &A)
static Access getEmptyKey()
AAPointerInfo::Access Access
static bool isEqual(const Access &LHS, const Access &RHS)
static bool isEqual(const AA::RangeTy &A, const AA::RangeTy B)
static AA::RangeTy getTombstoneKey()
static unsigned getHashValue(const AA::RangeTy &Range)
static AA::RangeTy getEmptyKey()
static ReachabilityQueryInfo< ToTy > EmptyKey
static ReachabilityQueryInfo< ToTy > TombstoneKey
static ReachabilityQueryInfo< ToTy > * getEmptyKey()
DenseMapInfo< std::pair< const Instruction *, const ToTy * > > PairDMI
static ReachabilityQueryInfo< ToTy > * getTombstoneKey()
static bool isEqual(const ReachabilityQueryInfo< ToTy > *LHS, const ReachabilityQueryInfo< ToTy > *RHS)
DenseMapInfo< const AA::InstExclusionSetTy * > InstSetDMI
static unsigned getHashValue(const ReachabilityQueryInfo< ToTy > *RQI)
An information struct used to provide DenseMap with the various necessary components for a given valu...
State for dereferenceable attribute.
IncIntegerState DerefBytesState
State representing for dereferenceable bytes.
ChangeStatus manifest(Attributor &A) override
See AbstractAttribute::manifest(...).
Helper to describe and deal with positions in the LLVM-IR.
Function * getAssociatedFunction() const
Return the associated function, if any.
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
static const IRPosition returned(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the returned value of F.
LLVM_ABI Argument * getAssociatedArgument() const
Return the associated argument, if any.
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
int getCalleeArgNo() const
Return the callee argument number of the associated value if it is an argument or call site argument,...
static const IRPosition inst(const Instruction &I, const CallBaseContext *CBContext=nullptr)
Create a position describing the instruction I.
static const IRPosition callsite_argument(const CallBase &CB, unsigned ArgNo)
Create a position describing the argument of CB at position ArgNo.
@ IRP_ARGUMENT
An attribute for a function argument.
@ IRP_RETURNED
An attribute for the function return value.
@ IRP_CALL_SITE
An attribute for a call site (function scope).
@ IRP_CALL_SITE_RETURNED
An attribute for a call site return value.
@ IRP_FUNCTION
An attribute for a function (scope).
@ IRP_CALL_SITE_ARGUMENT
An attribute for a call site argument.
@ IRP_INVALID
An invalid position.
Instruction * getCtxI() const
Return the context instruction, if any.
static const IRPosition argument(const Argument &Arg, const CallBaseContext *CBContext=nullptr)
Create a position describing the argument Arg.
Type * getAssociatedType() const
Return the type this abstract attribute is associated with.
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
const CallBaseContext * getCallBaseContext() const
Get the call base context from the position.
Value & getAssociatedValue() const
Return the value this abstract attribute is associated with.
Value & getAnchorValue() const
Return the value this abstract attribute is anchored with.
int getCallSiteArgNo() const
Return the call site argument number of the associated value if it is an argument or call site argume...
static const IRPosition function_scope(const IRPosition &IRP, const CallBaseContext *CBContext=nullptr)
Create a position with function scope matching the "context" of IRP.
Kind getPositionKind() const
Return the associated position kind.
bool isArgumentPosition() const
Return true if the position is an argument or call site argument.
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
Function * getAnchorScope() const
Return the Function surrounding the anchor value.
ConstantRange getKnown() const
Return the known state encoding.
ConstantRange getAssumed() const
Return the assumed state encoding.
base_t getAssumed() const
Return the assumed state encoding.
static constexpr base_t getWorstState()
Helper that allows to insert a new assumption string in the known assumption set by creating a (stati...
FPClassTest KnownFPClasses
Floating-point classes the value could be one of.
A "must be executed context" for a given program point PP is the set of instructions,...
iterator & end()
Return an universal end iterator.
bool findInContextOf(const Instruction *I, const Instruction *PP)
Helper to look for I in the context of PP.
iterator & begin(const Instruction *PP)
Return an iterator to explore the context around PP.
bool checkForAllContext(const Instruction *PP, function_ref< bool(const Instruction *)> Pred)
}
static unsigned MaxPotentialValues
Helper to tie a abstract state implementation to an abstract attribute.
StateType & getState() override
See AbstractAttribute::getState(...).
bool isPassthrough() const
LLVM_ABI bool unionAssumed(std::optional< Value * > Other)
Merge Other into the currently assumed simplified value.
std::optional< Value * > SimplifiedAssociatedValue
An assumed simplified value.
Type * Ty
The type of the original value.