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));
2296 bool UsedAssumedInformation =
false;
2297 if (!
A.checkForAllReadWriteInstructions(CheckForNoFree, *
this,
2298 UsedAssumedInformation) ||
2299 !
A.checkForAllCallLikeInstructions(CheckForNoFree, *
this,
2300 UsedAssumedInformation))
2301 return indicatePessimisticFixpoint();
2303 return ChangeStatus::UNCHANGED;
2307 const std::string getAsStr(Attributor *
A)
const override {
2308 return getAssumed() ?
"nofree" :
"may-free";
2312struct AANoFreeFunction final :
public AANoFreeImpl {
2313 AANoFreeFunction(
const IRPosition &IRP, Attributor &
A)
2314 : AANoFreeImpl(IRP,
A) {}
2321struct AANoFreeCallSite final : AACalleeToCallSite<AANoFree, AANoFreeImpl> {
2322 AANoFreeCallSite(
const IRPosition &IRP, Attributor &
A)
2323 : AACalleeToCallSite<AANoFree, AANoFreeImpl>(IRP,
A) {}
2330struct AANoFreeFloating : AANoFreeImpl {
2331 AANoFreeFloating(
const IRPosition &IRP, Attributor &
A)
2332 : AANoFreeImpl(IRP,
A) {}
2339 const IRPosition &IRP = getIRPosition();
2344 DepClassTy::OPTIONAL, IsKnown))
2345 return ChangeStatus::UNCHANGED;
2347 Value &AssociatedValue = getIRPosition().getAssociatedValue();
2348 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
2363 DepClassTy::REQUIRED, IsKnown))
2366 const AANoCapture *NoCaptureAA =
nullptr;
2369 DepClassTy::REQUIRED, IsKnown,
2370 false, &NoCaptureAA)) {
2395 if (!
A.checkForAllUses(Pred, *
this, AssociatedValue))
2396 return indicatePessimisticFixpoint();
2398 return ChangeStatus::UNCHANGED;
2403struct AANoFreeArgument final : AANoFreeFloating {
2404 AANoFreeArgument(
const IRPosition &IRP, Attributor &
A)
2405 : AANoFreeFloating(IRP,
A) {}
2412struct AANoFreeCallSiteArgument final : AANoFreeFloating {
2413 AANoFreeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2414 : AANoFreeFloating(IRP,
A) {}
2422 Argument *Arg = getAssociatedArgument();
2424 return indicatePessimisticFixpoint();
2428 DepClassTy::REQUIRED, IsKnown))
2429 return ChangeStatus::UNCHANGED;
2430 return indicatePessimisticFixpoint();
2438struct AANoFreeReturned final : AANoFreeFloating {
2439 AANoFreeReturned(
const IRPosition &IRP, Attributor &
A)
2440 : AANoFreeFloating(IRP,
A) {
2455 void trackStatistics()
const override {}
2459struct AANoFreeCallSiteReturned final : AANoFreeFloating {
2460 AANoFreeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2461 : AANoFreeFloating(IRP,
A) {}
2464 return ChangeStatus::UNCHANGED;
2475 bool IgnoreSubsumingPositions) {
2477 AttrKinds.
push_back(Attribute::NonNull);
2480 AttrKinds.
push_back(Attribute::Dereferenceable);
2481 if (
A.hasAttr(IRP, AttrKinds, IgnoreSubsumingPositions, Attribute::NonNull))
2488 if (!Fn->isDeclaration()) {
2498 bool UsedAssumedInformation =
false;
2499 if (!
A.checkForAllInstructions(
2501 Worklist.push_back({*cast<ReturnInst>(I).getReturnValue(), &I});
2505 UsedAssumedInformation,
false,
true))
2517 Attribute::NonNull)});
2522static int64_t getKnownNonNullAndDerefBytesForUse(
2523 Attributor &
A,
const AbstractAttribute &QueryingAA,
Value &AssociatedValue,
2524 const Use *U,
const Instruction *
I,
bool &IsNonNull,
bool &TrackUse) {
2527 const Value *UseV =
U->get();
2548 const DataLayout &
DL =
A.getInfoCache().getDL();
2552 U, {Attribute::NonNull, Attribute::Dereferenceable})) {
2569 bool IsKnownNonNull;
2572 IsNonNull |= IsKnownNonNull;
2575 return DerefAA ? DerefAA->getKnownDereferenceableBytes() : 0;
2579 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
2580 Loc->Size.isScalable() ||
I->isVolatile())
2586 if (
Base &&
Base == &AssociatedValue) {
2587 int64_t DerefBytes = Loc->Size.getValue() +
Offset;
2589 return std::max(int64_t(0), DerefBytes);
2596 int64_t DerefBytes = Loc->Size.getValue();
2598 return std::max(int64_t(0), DerefBytes);
2604struct AANonNullImpl : AANonNull {
2605 AANonNullImpl(
const IRPosition &IRP, Attributor &
A) : AANonNull(IRP,
A) {}
2609 Value &
V = *getAssociatedValue().stripPointerCasts();
2611 indicatePessimisticFixpoint();
2615 if (Instruction *CtxI = getCtxI())
2616 followUsesInMBEC(*
this,
A, getState(), *CtxI);
2620 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
2621 AANonNull::StateType &State) {
2622 bool IsNonNull =
false;
2623 bool TrackUse =
false;
2624 getKnownNonNullAndDerefBytesForUse(
A, *
this, getAssociatedValue(), U,
I,
2625 IsNonNull, TrackUse);
2626 State.setKnown(IsNonNull);
2631 const std::string getAsStr(Attributor *
A)
const override {
2632 return getAssumed() ?
"nonnull" :
"may-null";
2637struct AANonNullFloating :
public AANonNullImpl {
2638 AANonNullFloating(
const IRPosition &IRP, Attributor &
A)
2639 : AANonNullImpl(IRP,
A) {}
2643 auto CheckIRP = [&](
const IRPosition &IRP) {
2644 bool IsKnownNonNull;
2646 A, *
this, IRP, DepClassTy::OPTIONAL, IsKnownNonNull);
2650 bool UsedAssumedInformation =
false;
2651 Value *AssociatedValue = &getAssociatedValue();
2653 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
2658 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
2664 return AA::hasAssumedIRAttr<Attribute::NonNull>(
2665 A, this, IRPosition::value(*Op), DepClassTy::OPTIONAL,
2668 return ChangeStatus::UNCHANGED;
2672 DepClassTy::OPTIONAL, IsKnown) &&
2675 DepClassTy::OPTIONAL, IsKnown))
2676 return ChangeStatus::UNCHANGED;
2683 if (AVIRP == getIRPosition() || !CheckIRP(AVIRP))
2684 return indicatePessimisticFixpoint();
2685 return ChangeStatus::UNCHANGED;
2688 for (
const auto &VAC : Values)
2690 return indicatePessimisticFixpoint();
2692 return ChangeStatus::UNCHANGED;
2700struct AANonNullReturned final
2701 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2702 false, AANonNull::IRAttributeKind, false> {
2703 AANonNullReturned(
const IRPosition &IRP, Attributor &
A)
2704 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2709 const std::string getAsStr(Attributor *
A)
const override {
2710 return getAssumed() ?
"nonnull" :
"may-null";
2718struct AANonNullArgument final
2719 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
2720 AANonNullArgument(
const IRPosition &IRP, Attributor &
A)
2721 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP,
A) {}
2727struct AANonNullCallSiteArgument final : AANonNullFloating {
2728 AANonNullCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2729 : AANonNullFloating(IRP,
A) {}
2736struct AANonNullCallSiteReturned final
2737 : AACalleeToCallSite<AANonNull, AANonNullImpl> {
2738 AANonNullCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2739 : AACalleeToCallSite<AANonNull, AANonNullImpl>(IRP,
A) {}
2748struct AAMustProgressImpl :
public AAMustProgress {
2749 AAMustProgressImpl(
const IRPosition &IRP, Attributor &
A)
2750 : AAMustProgress(IRP,
A) {}
2756 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2761 const std::string getAsStr(Attributor *
A)
const override {
2762 return getAssumed() ?
"mustprogress" :
"may-not-progress";
2766struct AAMustProgressFunction final : AAMustProgressImpl {
2767 AAMustProgressFunction(
const IRPosition &IRP, Attributor &
A)
2768 : AAMustProgressImpl(IRP,
A) {}
2774 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnown)) {
2776 return indicateOptimisticFixpoint();
2777 return ChangeStatus::UNCHANGED;
2780 auto CheckForMustProgress = [&](AbstractCallSite ACS) {
2782 bool IsKnownMustProgress;
2784 A,
this, IPos, DepClassTy::REQUIRED, IsKnownMustProgress,
2788 bool AllCallSitesKnown =
true;
2789 if (!
A.checkForAllCallSites(CheckForMustProgress, *
this,
2792 return indicatePessimisticFixpoint();
2794 return ChangeStatus::UNCHANGED;
2798 void trackStatistics()
const override {
2804struct AAMustProgressCallSite final : AAMustProgressImpl {
2805 AAMustProgressCallSite(
const IRPosition &IRP, Attributor &
A)
2806 : AAMustProgressImpl(IRP,
A) {}
2815 bool IsKnownMustProgress;
2817 A,
this, FnPos, DepClassTy::REQUIRED, IsKnownMustProgress))
2818 return indicatePessimisticFixpoint();
2819 return ChangeStatus::UNCHANGED;
2823 void trackStatistics()
const override {
2832struct AANoRecurseImpl :
public AANoRecurse {
2833 AANoRecurseImpl(
const IRPosition &IRP, Attributor &
A) : AANoRecurse(IRP,
A) {}
2839 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2844 const std::string getAsStr(Attributor *
A)
const override {
2845 return getAssumed() ?
"norecurse" :
"may-recurse";
2849struct AANoRecurseFunction final : AANoRecurseImpl {
2850 AANoRecurseFunction(
const IRPosition &IRP, Attributor &
A)
2851 : AANoRecurseImpl(IRP,
A) {}
2857 auto CallSitePred = [&](AbstractCallSite ACS) {
2858 bool IsKnownNoRecurse;
2862 DepClassTy::NONE, IsKnownNoRecurse))
2864 return IsKnownNoRecurse;
2866 bool UsedAssumedInformation =
false;
2867 if (
A.checkForAllCallSites(CallSitePred, *
this,
true,
2868 UsedAssumedInformation)) {
2874 if (!UsedAssumedInformation)
2875 indicateOptimisticFixpoint();
2876 return ChangeStatus::UNCHANGED;
2879 const AAInterFnReachability *EdgeReachability =
2880 A.getAAFor<AAInterFnReachability>(*
this, getIRPosition(),
2881 DepClassTy::REQUIRED);
2882 if (EdgeReachability && EdgeReachability->
canReach(
A, *getAnchorScope()))
2883 return indicatePessimisticFixpoint();
2884 return ChangeStatus::UNCHANGED;
2891struct AANoRecurseCallSite final
2892 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl> {
2893 AANoRecurseCallSite(
const IRPosition &IRP, Attributor &
A)
2894 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl>(IRP,
A) {}
2904struct AANonConvergentImpl :
public AANonConvergent {
2905 AANonConvergentImpl(
const IRPosition &IRP, Attributor &
A)
2906 : AANonConvergent(IRP,
A) {}
2909 const std::string getAsStr(Attributor *
A)
const override {
2910 return getAssumed() ?
"non-convergent" :
"may-be-convergent";
2914struct AANonConvergentFunction final : AANonConvergentImpl {
2915 AANonConvergentFunction(
const IRPosition &IRP, Attributor &
A)
2916 : AANonConvergentImpl(IRP,
A) {}
2922 auto CalleeIsNotConvergent = [&](
Instruction &Inst) {
2925 if (!Callee ||
Callee->isIntrinsic()) {
2928 if (
Callee->isDeclaration()) {
2929 return !
Callee->hasFnAttribute(Attribute::Convergent);
2931 const auto *ConvergentAA =
A.getAAFor<AANonConvergent>(
2933 return ConvergentAA && ConvergentAA->isAssumedNotConvergent();
2936 bool UsedAssumedInformation =
false;
2937 if (!
A.checkForAllCallLikeInstructions(CalleeIsNotConvergent, *
this,
2938 UsedAssumedInformation)) {
2939 return indicatePessimisticFixpoint();
2941 return ChangeStatus::UNCHANGED;
2945 if (isKnownNotConvergent() &&
2946 A.hasAttr(getIRPosition(), Attribute::Convergent)) {
2947 A.removeAttrs(getIRPosition(), {Attribute::Convergent});
2948 return ChangeStatus::CHANGED;
2950 return ChangeStatus::UNCHANGED;
2960struct AAUndefinedBehaviorImpl :
public AAUndefinedBehavior {
2961 AAUndefinedBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
2962 : AAUndefinedBehavior(IRP,
A) {}
2967 const size_t UBPrevSize = KnownUBInsts.size();
2968 const size_t NoUBPrevSize = AssumedNoUBInsts.size();
2976 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
2985 "Expected pointer operand of memory accessing instruction");
2989 std::optional<Value *> SimplifiedPtrOp =
2990 stopOnUndefOrAssumed(
A, PtrOp, &
I);
2991 if (!SimplifiedPtrOp || !*SimplifiedPtrOp)
2993 const Value *PtrOpVal = *SimplifiedPtrOp;
2999 AssumedNoUBInsts.insert(&
I);
3011 AssumedNoUBInsts.insert(&
I);
3013 KnownUBInsts.insert(&
I);
3022 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3030 std::optional<Value *> SimplifiedCond =
3031 stopOnUndefOrAssumed(
A, BrInst->getCondition(), BrInst);
3032 if (!SimplifiedCond || !*SimplifiedCond)
3034 AssumedNoUBInsts.insert(&
I);
3042 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3051 for (
unsigned idx = 0; idx < CB.
arg_size(); idx++) {
3057 if (idx >=
Callee->arg_size())
3069 bool IsKnownNoUndef;
3071 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNoUndef);
3072 if (!IsKnownNoUndef)
3074 bool UsedAssumedInformation =
false;
3075 std::optional<Value *> SimplifiedVal =
3078 if (UsedAssumedInformation)
3080 if (SimplifiedVal && !*SimplifiedVal)
3083 KnownUBInsts.insert(&
I);
3089 bool IsKnownNonNull;
3091 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNonNull);
3093 KnownUBInsts.insert(&
I);
3102 std::optional<Value *> SimplifiedRetValue =
3103 stopOnUndefOrAssumed(
A, RI.getReturnValue(), &
I);
3104 if (!SimplifiedRetValue || !*SimplifiedRetValue)
3122 bool IsKnownNonNull;
3127 KnownUBInsts.insert(&
I);
3133 bool UsedAssumedInformation =
false;
3134 A.checkForAllInstructions(InspectMemAccessInstForUB, *
this,
3135 {Instruction::Load, Instruction::Store,
3136 Instruction::AtomicCmpXchg,
3137 Instruction::AtomicRMW},
3138 UsedAssumedInformation,
3140 A.checkForAllInstructions(InspectBrInstForUB, *
this, {Instruction::CondBr},
3141 UsedAssumedInformation,
3143 A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *
this,
3144 UsedAssumedInformation);
3148 if (!getAnchorScope()->getReturnType()->isVoidTy()) {
3150 if (!
A.isAssumedDead(ReturnIRP,
this,
nullptr, UsedAssumedInformation)) {
3151 bool IsKnownNoUndef;
3153 A,
this, ReturnIRP, DepClassTy::NONE, IsKnownNoUndef);
3155 A.checkForAllInstructions(InspectReturnInstForUB, *
this,
3156 {Instruction::Ret}, UsedAssumedInformation,
3161 if (NoUBPrevSize != AssumedNoUBInsts.size() ||
3162 UBPrevSize != KnownUBInsts.size())
3163 return ChangeStatus::CHANGED;
3164 return ChangeStatus::UNCHANGED;
3167 bool isKnownToCauseUB(Instruction *
I)
const override {
3168 return KnownUBInsts.count(
I);
3171 bool isAssumedToCauseUB(Instruction *
I)
const override {
3178 switch (
I->getOpcode()) {
3179 case Instruction::Load:
3180 case Instruction::Store:
3181 case Instruction::AtomicCmpXchg:
3182 case Instruction::AtomicRMW:
3183 case Instruction::CondBr:
3184 return !AssumedNoUBInsts.count(
I);
3192 if (KnownUBInsts.empty())
3193 return ChangeStatus::UNCHANGED;
3194 for (Instruction *
I : KnownUBInsts)
3195 A.changeToUnreachableAfterManifest(
I);
3196 return ChangeStatus::CHANGED;
3200 const std::string getAsStr(Attributor *
A)
const override {
3201 return getAssumed() ?
"undefined-behavior" :
"no-ub";
3229 SmallPtrSet<Instruction *, 8> KnownUBInsts;
3233 SmallPtrSet<Instruction *, 8> AssumedNoUBInsts;
3244 std::optional<Value *> stopOnUndefOrAssumed(Attributor &
A,
Value *V,
3246 bool UsedAssumedInformation =
false;
3247 std::optional<Value *> SimplifiedV =
3250 if (!UsedAssumedInformation) {
3255 KnownUBInsts.insert(
I);
3256 return std::nullopt;
3263 KnownUBInsts.insert(
I);
3264 return std::nullopt;
3270struct AAUndefinedBehaviorFunction final : AAUndefinedBehaviorImpl {
3271 AAUndefinedBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
3272 : AAUndefinedBehaviorImpl(IRP,
A) {}
3275 void trackStatistics()
const override {
3276 STATS_DECL(UndefinedBehaviorInstruction, Instruction,
3277 "Number of instructions known to have UB");
3279 KnownUBInsts.size();
3290static bool mayContainUnboundedCycle(Function &
F, Attributor &
A) {
3291 ScalarEvolution *SE =
3292 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
F);
3293 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
F);
3299 for (scc_iterator<Function *> SCCI =
scc_begin(&
F); !SCCI.isAtEnd(); ++SCCI)
3300 if (SCCI.hasCycle())
3310 for (
auto *L : LI->getLoopsInPreorder()) {
3317struct AAWillReturnImpl :
public AAWillReturn {
3318 AAWillReturnImpl(
const IRPosition &IRP, Attributor &
A)
3319 : AAWillReturn(IRP,
A) {}
3325 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
3330 bool isImpliedByMustprogressAndReadonly(Attributor &
A,
bool KnownOnly) {
3331 if (!
A.hasAttr(getIRPosition(), {Attribute::MustProgress}))
3336 return IsKnown || !KnownOnly;
3342 if (isImpliedByMustprogressAndReadonly(
A,
false))
3343 return ChangeStatus::UNCHANGED;
3349 A,
this, IPos, DepClassTy::REQUIRED, IsKnown)) {
3355 bool IsKnownNoRecurse;
3357 A,
this, IPos, DepClassTy::REQUIRED, IsKnownNoRecurse);
3360 bool UsedAssumedInformation =
false;
3361 if (!
A.checkForAllCallLikeInstructions(CheckForWillReturn, *
this,
3362 UsedAssumedInformation))
3363 return indicatePessimisticFixpoint();
3367 return !
I.isVolatile();
3369 if (!
A.checkForAllInstructions(CheckForVolatile, *
this,
3370 {Instruction::Load, Instruction::Store,
3371 Instruction::AtomicCmpXchg,
3372 Instruction::AtomicRMW},
3373 UsedAssumedInformation))
3374 return indicatePessimisticFixpoint();
3376 return ChangeStatus::UNCHANGED;
3380 const std::string getAsStr(Attributor *
A)
const override {
3381 return getAssumed() ?
"willreturn" :
"may-noreturn";
3385struct AAWillReturnFunction final : AAWillReturnImpl {
3386 AAWillReturnFunction(
const IRPosition &IRP, Attributor &
A)
3387 : AAWillReturnImpl(IRP,
A) {}
3391 AAWillReturnImpl::initialize(
A);
3394 assert(
F &&
"Did expect an anchor function");
3395 if (
F->isDeclaration() || mayContainUnboundedCycle(*
F,
A))
3396 indicatePessimisticFixpoint();
3404struct AAWillReturnCallSite final
3405 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl> {
3406 AAWillReturnCallSite(
const IRPosition &IRP, Attributor &
A)
3407 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl>(IRP,
A) {}
3411 if (isImpliedByMustprogressAndReadonly(
A,
false))
3412 return ChangeStatus::UNCHANGED;
3414 return AACalleeToCallSite::updateImpl(
A);
3436 const ToTy *
To =
nullptr;
3463 if (!ES || ES->
empty()) {
3464 ExclusionSet = nullptr;
3465 }
else if (MakeUnique) {
3466 ExclusionSet =
A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ES);
3491 if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))
3493 return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);
3497#define DefineKeys(ToTy) \
3499 ReachabilityQueryInfo<ToTy> \
3500 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::EmptyKey = \
3501 ReachabilityQueryInfo<ToTy>( \
3502 DenseMapInfo<const Instruction *>::getEmptyKey(), \
3503 DenseMapInfo<const ToTy *>::getEmptyKey()); \
3505 ReachabilityQueryInfo<ToTy> \
3506 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::TombstoneKey = \
3507 ReachabilityQueryInfo<ToTy>( \
3508 DenseMapInfo<const Instruction *>::getTombstoneKey(), \
3509 DenseMapInfo<const ToTy *>::getTombstoneKey());
3518template <
typename BaseTy,
typename ToTy>
3519struct CachedReachabilityAA :
public BaseTy {
3520 using RQITy = ReachabilityQueryInfo<ToTy>;
3522 CachedReachabilityAA(
const IRPosition &IRP, Attributor &
A) : BaseTy(IRP,
A) {}
3525 bool isQueryAA()
const override {
return true; }
3530 for (
unsigned u = 0,
e = QueryVector.size();
u <
e; ++
u) {
3531 RQITy *RQI = QueryVector[
u];
3532 if (RQI->Result == RQITy::Reachable::No &&
3534 Changed = ChangeStatus::CHANGED;
3540 bool IsTemporaryRQI) = 0;
3542 bool rememberResult(Attributor &
A,
typename RQITy::Reachable
Result,
3543 RQITy &RQI,
bool UsedExclusionSet,
bool IsTemporaryRQI) {
3548 QueryCache.erase(&RQI);
3554 if (
Result == RQITy::Reachable::Yes || !UsedExclusionSet) {
3555 RQITy PlainRQI(RQI.From, RQI.To);
3556 if (!QueryCache.count(&PlainRQI)) {
3557 RQITy *RQIPtr =
new (
A.Allocator) RQITy(RQI.From, RQI.To);
3559 QueryVector.push_back(RQIPtr);
3560 QueryCache.insert(RQIPtr);
3565 if (IsTemporaryRQI &&
Result != RQITy::Reachable::Yes && UsedExclusionSet) {
3566 assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&
3567 "Did not expect empty set!");
3568 RQITy *RQIPtr =
new (
A.Allocator)
3569 RQITy(
A, *RQI.From, *RQI.To, RQI.ExclusionSet,
true);
3570 assert(RQIPtr->Result == RQITy::Reachable::No &&
"Already reachable?");
3572 assert(!QueryCache.count(RQIPtr));
3573 QueryVector.push_back(RQIPtr);
3574 QueryCache.insert(RQIPtr);
3577 if (
Result == RQITy::Reachable::No && IsTemporaryRQI)
3578 A.registerForUpdate(*
this);
3579 return Result == RQITy::Reachable::Yes;
3582 const std::string getAsStr(Attributor *
A)
const override {
3584 return "#queries(" + std::to_string(QueryVector.size()) +
")";
3587 bool checkQueryCache(Attributor &
A, RQITy &StackRQI,
3588 typename RQITy::Reachable &
Result) {
3589 if (!this->getState().isValidState()) {
3590 Result = RQITy::Reachable::Yes;
3596 if (StackRQI.ExclusionSet) {
3597 RQITy PlainRQI(StackRQI.From, StackRQI.To);
3598 auto It = QueryCache.find(&PlainRQI);
3599 if (It != QueryCache.end() && (*It)->Result == RQITy::Reachable::No) {
3600 Result = RQITy::Reachable::No;
3605 auto It = QueryCache.find(&StackRQI);
3606 if (It != QueryCache.end()) {
3613 QueryCache.insert(&StackRQI);
3619 DenseSet<RQITy *> QueryCache;
3622struct AAIntraFnReachabilityFunction final
3623 :
public CachedReachabilityAA<AAIntraFnReachability, Instruction> {
3624 using Base = CachedReachabilityAA<AAIntraFnReachability, Instruction>;
3625 AAIntraFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
3627 DT =
A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(
3631 bool isAssumedReachable(
3632 Attributor &
A,
const Instruction &From,
const Instruction &To,
3634 auto *NonConstThis =
const_cast<AAIntraFnReachabilityFunction *
>(
this);
3638 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
3640 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
3641 return NonConstThis->isReachableImpl(
A, StackRQI,
3643 return Result == RQITy::Reachable::Yes;
3650 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3653 [&](
const auto &DeadEdge) {
3654 return LivenessAA->isEdgeDead(DeadEdge.first,
3658 return LivenessAA->isAssumedDead(BB);
3660 return ChangeStatus::UNCHANGED;
3664 return Base::updateImpl(
A);
3668 bool IsTemporaryRQI)
override {
3670 bool UsedExclusionSet =
false;
3675 while (IP && IP != &To) {
3676 if (ExclusionSet && IP != Origin && ExclusionSet->
count(IP)) {
3677 UsedExclusionSet =
true;
3685 const BasicBlock *FromBB = RQI.From->getParent();
3686 const BasicBlock *ToBB = RQI.To->getParent();
3688 "Not an intra-procedural query!");
3692 if (FromBB == ToBB &&
3693 WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
3694 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3699 if (!WillReachInBlock(ToBB->
front(), *RQI.To, RQI.ExclusionSet))
3700 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3704 SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
3705 if (RQI.ExclusionSet)
3706 for (
auto *
I : *RQI.ExclusionSet)
3707 if (
I->getFunction() == Fn)
3708 ExclusionBlocks.
insert(
I->getParent());
3711 if (ExclusionBlocks.
count(FromBB) &&
3714 return rememberResult(
A, RQITy::Reachable::No, RQI,
true, IsTemporaryRQI);
3717 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3718 if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {
3719 DeadBlocks.insert(ToBB);
3720 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3724 SmallPtrSet<const BasicBlock *, 16> Visited;
3728 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> LocalDeadEdges;
3729 while (!Worklist.
empty()) {
3731 if (!Visited.
insert(BB).second)
3733 for (
const BasicBlock *SuccBB :
successors(BB)) {
3734 if (LivenessAA && LivenessAA->isEdgeDead(BB, SuccBB)) {
3735 LocalDeadEdges.
insert({BB, SuccBB});
3740 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3743 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3746 if (ExclusionBlocks.
count(SuccBB)) {
3747 UsedExclusionSet =
true;
3754 DeadEdges.insert_range(LocalDeadEdges);
3755 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3760 void trackStatistics()
const override {}
3765 DenseSet<const BasicBlock *> DeadBlocks;
3769 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> DeadEdges;
3772 const DominatorTree *DT =
nullptr;
3780 bool IgnoreSubsumingPositions) {
3781 assert(ImpliedAttributeKind == Attribute::NoAlias &&
3782 "Unexpected attribute kind");
3788 IgnoreSubsumingPositions =
true;
3799 if (
A.hasAttr(IRP, {Attribute::ByVal, Attribute::NoAlias},
3800 IgnoreSubsumingPositions, Attribute::NoAlias))
3810 "Noalias is a pointer attribute");
3813 const std::string getAsStr(
Attributor *
A)
const override {
3814 return getAssumed() ?
"noalias" :
"may-alias";
3819struct AANoAliasFloating final : AANoAliasImpl {
3820 AANoAliasFloating(
const IRPosition &IRP, Attributor &
A)
3821 : AANoAliasImpl(IRP,
A) {}
3826 return indicatePessimisticFixpoint();
3830 void trackStatistics()
const override {
3836struct AANoAliasArgument final
3837 : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> {
3838 using Base = AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>;
3839 AANoAliasArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
3852 DepClassTy::OPTIONAL, IsKnownNoSycn))
3853 return Base::updateImpl(
A);
3858 return Base::updateImpl(
A);
3862 bool UsedAssumedInformation =
false;
3863 if (
A.checkForAllCallSites(
3864 [](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *
this,
3865 true, UsedAssumedInformation))
3866 return Base::updateImpl(
A);
3874 return indicatePessimisticFixpoint();
3881struct AANoAliasCallSiteArgument final : AANoAliasImpl {
3882 AANoAliasCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
3883 : AANoAliasImpl(IRP,
A) {}
3887 bool mayAliasWithArgument(Attributor &
A, AAResults *&AAR,
3888 const AAMemoryBehavior &MemBehaviorAA,
3889 const CallBase &CB,
unsigned OtherArgNo) {
3891 if (this->getCalleeArgNo() == (
int)OtherArgNo)
3899 auto *CBArgMemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
3903 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadNone()) {
3904 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3911 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadOnly() &&
3913 A.recordDependence(MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3914 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3920 AAR =
A.getInfoCache().getAnalysisResultForFunction<AAManager>(
3924 bool IsAliasing = !AAR || !AAR->
isNoAlias(&getAssociatedValue(), ArgOp);
3926 "callsite arguments: "
3927 << getAssociatedValue() <<
" " << *ArgOp <<
" => "
3928 << (IsAliasing ?
"" :
"no-") <<
"alias \n");
3933 bool isKnownNoAliasDueToNoAliasPreservation(
3934 Attributor &
A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA) {
3947 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
3963 bool IsKnownNoCapture;
3966 DepClassTy::OPTIONAL, IsKnownNoCapture))
3972 A, *UserI, *getCtxI(), *
this,
nullptr,
3973 [ScopeFn](
const Function &Fn) {
return &Fn != ScopeFn; }))
3988 LLVM_DEBUG(
dbgs() <<
"[AANoAliasCSArg] Unknown user: " << *UserI <<
"\n");
3992 bool IsKnownNoCapture;
3993 const AANoCapture *NoCaptureAA =
nullptr;
3995 A,
this, VIRP, DepClassTy::NONE, IsKnownNoCapture,
false, &NoCaptureAA);
3996 if (!IsAssumedNoCapture &&
3998 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue())) {
4000 dbgs() <<
"[AANoAliasCSArg] " << getAssociatedValue()
4001 <<
" cannot be noalias as it is potentially captured\n");
4006 A.recordDependence(*NoCaptureAA, *
this, DepClassTy::OPTIONAL);
4012 for (
unsigned OtherArgNo = 0; OtherArgNo < CB.
arg_size(); OtherArgNo++)
4013 if (mayAliasWithArgument(
A, AAR, MemBehaviorAA, CB, OtherArgNo))
4023 auto *MemBehaviorAA =
4024 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
4026 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
4027 return ChangeStatus::UNCHANGED;
4030 bool IsKnownNoAlias;
4033 A,
this, VIRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
4035 <<
" is not no-alias at the definition\n");
4036 return indicatePessimisticFixpoint();
4039 AAResults *AAR =
nullptr;
4040 if (MemBehaviorAA &&
4041 isKnownNoAliasDueToNoAliasPreservation(
A, AAR, *MemBehaviorAA)) {
4043 dbgs() <<
"[AANoAlias] No-Alias deduced via no-alias preservation\n");
4044 return ChangeStatus::UNCHANGED;
4047 return indicatePessimisticFixpoint();
4055struct AANoAliasReturned final : AANoAliasImpl {
4056 AANoAliasReturned(
const IRPosition &IRP, Attributor &
A)
4057 : AANoAliasImpl(IRP,
A) {}
4062 auto CheckReturnValue = [&](
Value &RV) ->
bool {
4073 bool IsKnownNoAlias;
4075 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoAlias))
4078 bool IsKnownNoCapture;
4079 const AANoCapture *NoCaptureAA =
nullptr;
4081 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
4083 return IsAssumedNoCapture ||
4087 if (!
A.checkForAllReturnedValues(CheckReturnValue, *
this))
4088 return indicatePessimisticFixpoint();
4090 return ChangeStatus::UNCHANGED;
4098struct AANoAliasCallSiteReturned final
4099 : AACalleeToCallSite<AANoAlias, AANoAliasImpl> {
4100 AANoAliasCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4101 : AACalleeToCallSite<AANoAlias, AANoAliasImpl>(IRP,
A) {}
4111struct AAIsDeadValueImpl :
public AAIsDead {
4112 AAIsDeadValueImpl(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4115 bool isAssumedDead()
const override {
return isAssumed(IS_DEAD); }
4118 bool isKnownDead()
const override {
return isKnown(IS_DEAD); }
4121 bool isAssumedDead(
const BasicBlock *BB)
const override {
return false; }
4124 bool isKnownDead(
const BasicBlock *BB)
const override {
return false; }
4127 bool isAssumedDead(
const Instruction *
I)
const override {
4128 return I == getCtxI() && isAssumedDead();
4132 bool isKnownDead(
const Instruction *
I)
const override {
4133 return isAssumedDead(
I) && isKnownDead();
4137 const std::string getAsStr(Attributor *
A)
const override {
4138 return isAssumedDead() ?
"assumed-dead" :
"assumed-live";
4142 bool areAllUsesAssumedDead(Attributor &
A,
Value &V) {
4144 if (
V.getType()->isVoidTy() ||
V.use_empty())
4150 if (!
A.isRunOn(*
I->getFunction()))
4152 bool UsedAssumedInformation =
false;
4153 std::optional<Constant *>
C =
4154 A.getAssumedConstant(V, *
this, UsedAssumedInformation);
4159 auto UsePred = [&](
const Use &
U,
bool &Follow) {
return false; };
4164 return A.checkForAllUses(UsePred, *
this, V,
false,
4165 DepClassTy::REQUIRED,
4170 bool isAssumedSideEffectFree(Attributor &
A, Instruction *
I) {
4174 if (!
I->isTerminator() && !
I->mayHaveSideEffects())
4183 bool IsKnownNoUnwind;
4185 A,
this, CallIRP, DepClassTy::OPTIONAL, IsKnownNoUnwind))
4193struct AAIsDeadFloating :
public AAIsDeadValueImpl {
4194 AAIsDeadFloating(
const IRPosition &IRP, Attributor &
A)
4195 : AAIsDeadValueImpl(IRP,
A) {}
4199 AAIsDeadValueImpl::initialize(
A);
4202 indicatePessimisticFixpoint();
4207 if (!isAssumedSideEffectFree(
A,
I)) {
4209 indicatePessimisticFixpoint();
4211 removeAssumedBits(HAS_NO_EFFECT);
4215 bool isDeadFence(Attributor &
A, FenceInst &FI) {
4216 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
4218 if (!ExecDomainAA || !ExecDomainAA->isNoOpFence(FI))
4220 A.recordDependence(*ExecDomainAA, *
this, DepClassTy::OPTIONAL);
4224 bool isDeadStore(Attributor &
A, StoreInst &SI,
4225 SmallSetVector<Instruction *, 8> *AssumeOnlyInst =
nullptr) {
4227 if (
SI.isVolatile())
4233 bool UsedAssumedInformation =
false;
4234 if (!AssumeOnlyInst) {
4235 PotentialCopies.clear();
4237 UsedAssumedInformation)) {
4240 <<
"[AAIsDead] Could not determine potential copies of store!\n");
4244 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Store has " << PotentialCopies.size()
4245 <<
" potential copies.\n");
4247 InformationCache &InfoCache =
A.getInfoCache();
4250 UsedAssumedInformation))
4254 auto &UserI = cast<Instruction>(*U.getUser());
4255 if (InfoCache.isOnlyUsedByAssume(UserI)) {
4257 AssumeOnlyInst->insert(&UserI);
4260 return A.isAssumedDead(U,
this,
nullptr, UsedAssumedInformation);
4266 <<
" is assumed live!\n");
4272 const std::string getAsStr(Attributor *
A)
const override {
4276 return "assumed-dead-store";
4279 return "assumed-dead-fence";
4280 return AAIsDeadValueImpl::getAsStr(
A);
4287 if (!isDeadStore(
A, *SI))
4288 return indicatePessimisticFixpoint();
4290 if (!isDeadFence(
A, *FI))
4291 return indicatePessimisticFixpoint();
4293 if (!isAssumedSideEffectFree(
A,
I))
4294 return indicatePessimisticFixpoint();
4295 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4296 return indicatePessimisticFixpoint();
4301 bool isRemovableStore()
const override {
4302 return isAssumed(IS_REMOVABLE) &&
isa<StoreInst>(&getAssociatedValue());
4307 Value &
V = getAssociatedValue();
4314 SmallSetVector<Instruction *, 8> AssumeOnlyInst;
4315 bool IsDead = isDeadStore(
A, *SI, &AssumeOnlyInst);
4318 A.deleteAfterManifest(*
I);
4319 for (
size_t i = 0; i < AssumeOnlyInst.
size(); ++i) {
4321 for (
auto *Usr : AOI->
users())
4323 A.deleteAfterManifest(*AOI);
4329 A.deleteAfterManifest(*FI);
4333 A.deleteAfterManifest(*
I);
4341 void trackStatistics()
const override {
4347 SmallSetVector<Value *, 4> PotentialCopies;
4350struct AAIsDeadArgument :
public AAIsDeadFloating {
4351 AAIsDeadArgument(
const IRPosition &IRP, Attributor &
A)
4352 : AAIsDeadFloating(IRP,
A) {}
4356 Argument &Arg = *getAssociatedArgument();
4357 if (
A.isValidFunctionSignatureRewrite(Arg, {}))
4358 if (
A.registerFunctionSignatureRewrite(
4362 return ChangeStatus::CHANGED;
4364 return ChangeStatus::UNCHANGED;
4371struct AAIsDeadCallSiteArgument :
public AAIsDeadValueImpl {
4372 AAIsDeadCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
4373 : AAIsDeadValueImpl(IRP,
A) {}
4377 AAIsDeadValueImpl::initialize(
A);
4379 indicatePessimisticFixpoint();
4388 Argument *Arg = getAssociatedArgument();
4390 return indicatePessimisticFixpoint();
4392 auto *ArgAA =
A.getAAFor<AAIsDead>(*
this, ArgPos, DepClassTy::REQUIRED);
4394 return indicatePessimisticFixpoint();
4403 "Expected undef values to be filtered out!");
4405 if (
A.changeUseAfterManifest(U, UV))
4406 return ChangeStatus::CHANGED;
4407 return ChangeStatus::UNCHANGED;
4414struct AAIsDeadCallSiteReturned :
public AAIsDeadFloating {
4415 AAIsDeadCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4416 : AAIsDeadFloating(IRP,
A) {}
4419 bool isAssumedDead()
const override {
4420 return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;
4425 AAIsDeadFloating::initialize(
A);
4427 indicatePessimisticFixpoint();
4432 IsAssumedSideEffectFree = isAssumedSideEffectFree(
A, getCtxI());
4438 if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(
A, getCtxI())) {
4439 IsAssumedSideEffectFree =
false;
4440 Changed = ChangeStatus::CHANGED;
4442 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4443 return indicatePessimisticFixpoint();
4448 void trackStatistics()
const override {
4449 if (IsAssumedSideEffectFree)
4456 const std::string getAsStr(Attributor *
A)
const override {
4457 return isAssumedDead()
4459 : (getAssumed() ?
"assumed-dead-users" :
"assumed-live");
4463 bool IsAssumedSideEffectFree =
true;
4466struct AAIsDeadReturned :
public AAIsDeadValueImpl {
4467 AAIsDeadReturned(
const IRPosition &IRP, Attributor &
A)
4468 : AAIsDeadValueImpl(IRP,
A) {}
4473 bool UsedAssumedInformation =
false;
4474 A.checkForAllInstructions([](Instruction &) {
return true; }, *
this,
4475 {Instruction::Ret}, UsedAssumedInformation);
4477 auto PredForCallSite = [&](AbstractCallSite ACS) {
4478 if (ACS.isCallbackCall() || !ACS.getInstruction())
4480 return areAllUsesAssumedDead(
A, *ACS.getInstruction());
4483 if (!
A.checkForAllCallSites(PredForCallSite, *
this,
true,
4484 UsedAssumedInformation))
4485 return indicatePessimisticFixpoint();
4487 return ChangeStatus::UNCHANGED;
4493 bool AnyChange =
false;
4494 UndefValue &UV = *
UndefValue::get(getAssociatedFunction()->getReturnType());
4501 bool UsedAssumedInformation =
false;
4502 A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
4503 UsedAssumedInformation);
4504 return AnyChange ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
4511struct AAIsDeadFunction :
public AAIsDead {
4512 AAIsDeadFunction(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4517 assert(
F &&
"Did expect an anchor function");
4518 if (!isAssumedDeadInternalFunction(
A)) {
4519 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4520 assumeLive(
A,
F->getEntryBlock());
4524 bool isAssumedDeadInternalFunction(Attributor &
A) {
4525 if (!getAnchorScope()->hasLocalLinkage())
4527 bool UsedAssumedInformation =
false;
4528 return A.checkForAllCallSites([](AbstractCallSite) {
return false; }, *
this,
4529 true, UsedAssumedInformation);
4533 const std::string getAsStr(Attributor *
A)
const override {
4534 return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) +
"/" +
4535 std::to_string(getAnchorScope()->
size()) +
"][#TBEP " +
4536 std::to_string(ToBeExploredFrom.size()) +
"][#KDE " +
4537 std::to_string(KnownDeadEnds.size()) +
"]";
4542 assert(getState().isValidState() &&
4543 "Attempted to manifest an invalid state!");
4548 if (AssumedLiveBlocks.empty()) {
4549 A.deleteAfterManifest(
F);
4550 return ChangeStatus::CHANGED;
4556 bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(
F);
4558 KnownDeadEnds.set_union(ToBeExploredFrom);
4559 for (
const Instruction *DeadEndI : KnownDeadEnds) {
4563 bool IsKnownNoReturn;
4571 A.registerInvokeWithDeadSuccessor(
const_cast<InvokeInst &
>(*
II));
4573 A.changeToUnreachableAfterManifest(
4574 const_cast<Instruction *
>(DeadEndI->getNextNode()));
4575 HasChanged = ChangeStatus::CHANGED;
4578 STATS_DECL(AAIsDead, BasicBlock,
"Number of dead basic blocks deleted.");
4579 for (BasicBlock &BB :
F)
4580 if (!AssumedLiveBlocks.count(&BB)) {
4581 A.deleteAfterManifest(BB);
4583 HasChanged = ChangeStatus::CHANGED;
4592 bool isEdgeDead(
const BasicBlock *From,
const BasicBlock *To)
const override {
4595 "Used AAIsDead of the wrong function");
4596 return isValidState() && !AssumedLiveEdges.count(std::make_pair(From, To));
4600 void trackStatistics()
const override {}
4603 bool isAssumedDead()
const override {
return false; }
4606 bool isKnownDead()
const override {
return false; }
4609 bool isAssumedDead(
const BasicBlock *BB)
const override {
4611 "BB must be in the same anchor scope function.");
4615 return !AssumedLiveBlocks.count(BB);
4619 bool isKnownDead(
const BasicBlock *BB)
const override {
4620 return getKnown() && isAssumedDead(BB);
4624 bool isAssumedDead(
const Instruction *
I)
const override {
4625 assert(
I->getParent()->getParent() == getAnchorScope() &&
4626 "Instruction must be in the same anchor scope function.");
4633 if (!AssumedLiveBlocks.count(
I->getParent()))
4639 if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))
4647 bool isKnownDead(
const Instruction *
I)
const override {
4648 return getKnown() && isAssumedDead(
I);
4653 bool assumeLive(Attributor &
A,
const BasicBlock &BB) {
4654 if (!AssumedLiveBlocks.insert(&BB).second)
4661 for (
const Instruction &
I : BB)
4664 if (
F->hasLocalLinkage())
4665 A.markLiveInternalFunction(*
F);
4671 SmallSetVector<const Instruction *, 8> ToBeExploredFrom;
4674 SmallSetVector<const Instruction *, 8> KnownDeadEnds;
4677 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> AssumedLiveEdges;
4680 DenseSet<const BasicBlock *> AssumedLiveBlocks;
4684identifyAliveSuccessors(Attributor &
A,
const CallBase &CB,
4685 AbstractAttribute &AA,
4686 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4689 bool IsKnownNoReturn;
4692 return !IsKnownNoReturn;
4701identifyAliveSuccessors(Attributor &
A,
const InvokeInst &
II,
4702 AbstractAttribute &AA,
4703 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4704 bool UsedAssumedInformation =
4710 if (AAIsDeadFunction::mayCatchAsynchronousExceptions(*
II.getFunction())) {
4711 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4715 bool IsKnownNoUnwind;
4718 UsedAssumedInformation |= !IsKnownNoUnwind;
4720 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4723 return UsedAssumedInformation;
4727identifyAliveSuccessors(Attributor &,
const UncondBrInst &BI,
4728 AbstractAttribute &,
4729 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4735identifyAliveSuccessors(Attributor &
A,
const CondBrInst &BI,
4736 AbstractAttribute &AA,
4737 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4738 bool UsedAssumedInformation =
false;
4739 std::optional<Constant *>
C =
4740 A.getAssumedConstant(*BI.
getCondition(), AA, UsedAssumedInformation);
4750 UsedAssumedInformation =
false;
4752 return UsedAssumedInformation;
4756identifyAliveSuccessors(Attributor &
A,
const SwitchInst &SI,
4757 AbstractAttribute &AA,
4758 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4759 bool UsedAssumedInformation =
false;
4763 UsedAssumedInformation)) {
4765 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4770 if (Values.
empty() ||
4771 (Values.
size() == 1 &&
4774 return UsedAssumedInformation;
4777 Type &Ty = *
SI.getCondition()->getType();
4778 SmallPtrSet<ConstantInt *, 8>
Constants;
4779 auto CheckForConstantInt = [&](
Value *
V) {
4787 if (!
all_of(Values, [&](AA::ValueAndContext &VAC) {
4788 return CheckForConstantInt(VAC.
getValue());
4790 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4792 return UsedAssumedInformation;
4795 unsigned MatchedCases = 0;
4796 for (
const auto &CaseIt :
SI.cases()) {
4797 if (
Constants.count(CaseIt.getCaseValue())) {
4799 AliveSuccessors.
push_back(&CaseIt.getCaseSuccessor()->front());
4806 AliveSuccessors.
push_back(&
SI.getDefaultDest()->front());
4807 return UsedAssumedInformation;
4813 if (AssumedLiveBlocks.empty()) {
4814 if (isAssumedDeadInternalFunction(
A))
4818 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4819 assumeLive(
A,
F->getEntryBlock());
4823 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Live [" << AssumedLiveBlocks.size() <<
"/"
4824 << getAnchorScope()->
size() <<
"] BBs and "
4825 << ToBeExploredFrom.size() <<
" exploration points and "
4826 << KnownDeadEnds.size() <<
" known dead ends\n");
4831 ToBeExploredFrom.end());
4832 decltype(ToBeExploredFrom) NewToBeExploredFrom;
4835 while (!Worklist.
empty()) {
4842 I =
I->getNextNode();
4844 AliveSuccessors.
clear();
4846 bool UsedAssumedInformation =
false;
4847 switch (
I->getOpcode()) {
4851 "Expected non-terminators to be handled already!");
4852 for (
const BasicBlock *SuccBB :
successors(
I->getParent()))
4855 case Instruction::Call:
4857 *
this, AliveSuccessors);
4859 case Instruction::Invoke:
4861 *
this, AliveSuccessors);
4863 case Instruction::UncondBr:
4864 UsedAssumedInformation = identifyAliveSuccessors(
4867 case Instruction::CondBr:
4869 *
this, AliveSuccessors);
4871 case Instruction::Switch:
4873 *
this, AliveSuccessors);
4877 if (UsedAssumedInformation) {
4878 NewToBeExploredFrom.insert(
I);
4879 }
else if (AliveSuccessors.
empty() ||
4880 (
I->isTerminator() &&
4881 AliveSuccessors.
size() <
I->getNumSuccessors())) {
4882 if (KnownDeadEnds.insert(
I))
4887 << AliveSuccessors.
size() <<
" UsedAssumedInformation: "
4888 << UsedAssumedInformation <<
"\n");
4890 for (
const Instruction *AliveSuccessor : AliveSuccessors) {
4891 if (!
I->isTerminator()) {
4892 assert(AliveSuccessors.size() == 1 &&
4893 "Non-terminator expected to have a single successor!");
4897 auto Edge = std::make_pair(
I->getParent(), AliveSuccessor->getParent());
4898 if (AssumedLiveEdges.insert(
Edge).second)
4900 if (assumeLive(
A, *AliveSuccessor->getParent()))
4907 if (NewToBeExploredFrom.size() != ToBeExploredFrom.size() ||
4908 llvm::any_of(NewToBeExploredFrom, [&](
const Instruction *
I) {
4909 return !ToBeExploredFrom.count(I);
4912 ToBeExploredFrom = std::move(NewToBeExploredFrom);
4921 if (ToBeExploredFrom.empty() &&
4922 getAnchorScope()->
size() == AssumedLiveBlocks.size() &&
4923 llvm::all_of(KnownDeadEnds, [](
const Instruction *DeadEndI) {
4924 return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;
4926 return indicatePessimisticFixpoint();
4931struct AAIsDeadCallSite final : AAIsDeadFunction {
4932 AAIsDeadCallSite(
const IRPosition &IRP, Attributor &
A)
4933 : AAIsDeadFunction(IRP,
A) {}
4942 "supported for call sites yet!");
4947 return indicatePessimisticFixpoint();
4951 void trackStatistics()
const override {}
4958struct AADereferenceableImpl : AADereferenceable {
4959 AADereferenceableImpl(
const IRPosition &IRP, Attributor &
A)
4960 : AADereferenceable(IRP,
A) {}
4961 using StateType = DerefState;
4965 Value &
V = *getAssociatedValue().stripPointerCasts();
4967 A.getAttrs(getIRPosition(),
4968 {Attribute::Dereferenceable, Attribute::DereferenceableOrNull},
4971 takeKnownDerefBytesMaximum(Attr.getValueAsInt());
4974 bool IsKnownNonNull;
4976 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNonNull);
4978 bool CanBeNull, CanBeFreed;
4979 takeKnownDerefBytesMaximum(
V.getPointerDereferenceableBytes(
4980 A.getDataLayout(), CanBeNull, CanBeFreed));
4982 if (Instruction *CtxI = getCtxI())
4983 followUsesInMBEC(*
this,
A, getState(), *CtxI);
4988 StateType &getState()
override {
return *
this; }
4989 const StateType &getState()
const override {
return *
this; }
4993 void addAccessedBytesForUse(Attributor &
A,
const Use *U,
const Instruction *
I,
4994 DerefState &State) {
4995 const Value *UseV =
U->get();
5000 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
I->isVolatile())
5005 Loc->Ptr,
Offset,
A.getDataLayout(),
true);
5006 if (
Base &&
Base == &getAssociatedValue())
5007 State.addAccessedBytes(
Offset, Loc->Size.getValue());
5011 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5012 AADereferenceable::StateType &State) {
5013 bool IsNonNull =
false;
5014 bool TrackUse =
false;
5015 int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
5016 A, *
this, getAssociatedValue(), U,
I, IsNonNull, TrackUse);
5017 LLVM_DEBUG(
dbgs() <<
"[AADereferenceable] Deref bytes: " << DerefBytes
5018 <<
" for instruction " << *
I <<
"\n");
5020 addAccessedBytesForUse(
A, U,
I, State);
5021 State.takeKnownDerefBytesMaximum(DerefBytes);
5028 bool IsKnownNonNull;
5030 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5031 if (IsAssumedNonNull &&
5032 A.hasAttr(getIRPosition(), Attribute::DereferenceableOrNull)) {
5033 A.removeAttrs(getIRPosition(), {Attribute::DereferenceableOrNull});
5034 return ChangeStatus::CHANGED;
5039 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5040 SmallVectorImpl<Attribute> &Attrs)
const override {
5042 bool IsKnownNonNull;
5044 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5045 if (IsAssumedNonNull)
5046 Attrs.emplace_back(Attribute::getWithDereferenceableBytes(
5047 Ctx, getAssumedDereferenceableBytes()));
5049 Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes(
5050 Ctx, getAssumedDereferenceableBytes()));
5054 const std::string getAsStr(Attributor *
A)
const override {
5055 if (!getAssumedDereferenceableBytes())
5056 return "unknown-dereferenceable";
5057 bool IsKnownNonNull;
5058 bool IsAssumedNonNull =
false;
5061 *
A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5062 return std::string(
"dereferenceable") +
5063 (IsAssumedNonNull ?
"" :
"_or_null") +
5064 (isAssumedGlobal() ?
"_globally" :
"") +
"<" +
5065 std::to_string(getKnownDereferenceableBytes()) +
"-" +
5066 std::to_string(getAssumedDereferenceableBytes()) +
">" +
5067 (!
A ?
" [non-null is unknown]" :
"");
5072struct AADereferenceableFloating : AADereferenceableImpl {
5073 AADereferenceableFloating(
const IRPosition &IRP, Attributor &
A)
5074 : AADereferenceableImpl(IRP,
A) {}
5079 bool UsedAssumedInformation =
false;
5081 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5083 Values.
push_back({getAssociatedValue(), getCtxI()});
5086 Stripped = Values.
size() != 1 ||
5087 Values.
front().getValue() != &getAssociatedValue();
5090 const DataLayout &
DL =
A.getDataLayout();
5093 auto VisitValueCB = [&](
const Value &
V) ->
bool {
5095 DL.getIndexSizeInBits(
V.getType()->getPointerAddressSpace());
5096 APInt
Offset(IdxWidth, 0);
5101 const auto *AA =
A.getAAFor<AADereferenceable>(
5103 int64_t DerefBytes = 0;
5104 if (!AA || (!Stripped &&
this == AA)) {
5107 bool CanBeNull, CanBeFreed;
5109 Base->getPointerDereferenceableBytes(
DL, CanBeNull, CanBeFreed);
5110 T.GlobalState.indicatePessimisticFixpoint();
5113 DerefBytes =
DS.DerefBytesState.getAssumed();
5114 T.GlobalState &=
DS.GlobalState;
5120 int64_t OffsetSExt =
Offset.getSExtValue();
5124 T.takeAssumedDerefBytesMinimum(
5125 std::max(int64_t(0), DerefBytes - OffsetSExt));
5130 T.takeKnownDerefBytesMaximum(
5131 std::max(int64_t(0), DerefBytes - OffsetSExt));
5132 T.indicatePessimisticFixpoint();
5133 }
else if (OffsetSExt > 0) {
5139 T.indicatePessimisticFixpoint();
5143 return T.isValidState();
5146 for (
const auto &VAC : Values)
5147 if (!VisitValueCB(*VAC.
getValue()))
5148 return indicatePessimisticFixpoint();
5154 void trackStatistics()
const override {
5160struct AADereferenceableReturned final
5161 : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl> {
5163 AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl>;
5164 AADereferenceableReturned(
const IRPosition &IRP, Attributor &
A)
5168 void trackStatistics()
const override {
5174struct AADereferenceableArgument final
5175 : AAArgumentFromCallSiteArguments<AADereferenceable,
5176 AADereferenceableImpl> {
5178 AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl>;
5179 AADereferenceableArgument(
const IRPosition &IRP, Attributor &
A)
5183 void trackStatistics()
const override {
5189struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {
5190 AADereferenceableCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5191 : AADereferenceableFloating(IRP,
A) {}
5194 void trackStatistics()
const override {
5200struct AADereferenceableCallSiteReturned final
5201 : AACalleeToCallSite<AADereferenceable, AADereferenceableImpl> {
5202 using Base = AACalleeToCallSite<AADereferenceable, AADereferenceableImpl>;
5203 AADereferenceableCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5207 void trackStatistics()
const override {
5217static unsigned getKnownAlignForUse(Attributor &
A, AAAlign &QueryingAA,
5218 Value &AssociatedValue,
const Use *U,
5219 const Instruction *
I,
bool &TrackUse) {
5228 if (
GEP->hasAllConstantIndices())
5233 switch (
II->getIntrinsicID()) {
5234 case Intrinsic::ptrmask: {
5236 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5238 const auto *AlignAA =
A.getAAFor<AAAlign>(
5240 if (ConstVals && ConstVals->isValidState() && ConstVals->isAtFixpoint()) {
5241 unsigned ShiftValue = std::min(ConstVals->getAssumedMinTrailingZeros(),
5243 Align ConstAlign(UINT64_C(1) << ShiftValue);
5244 if (ConstAlign >= AlignAA->getKnownAlign())
5245 return Align(1).value();
5248 return AlignAA->getKnownAlign().
value();
5251 case Intrinsic::amdgcn_make_buffer_rsrc: {
5252 const auto *AlignAA =
A.getAAFor<AAAlign>(
5255 return AlignAA->getKnownAlign().
value();
5273 MA = MaybeAlign(AlignAA->getKnownAlign());
5276 const DataLayout &
DL =
A.getDataLayout();
5277 const Value *UseV =
U->get();
5279 if (
SI->getPointerOperand() == UseV)
5280 MA =
SI->getAlign();
5282 if (LI->getPointerOperand() == UseV)
5283 MA = LI->getAlign();
5285 if (AI->getPointerOperand() == UseV)
5286 MA = AI->getAlign();
5288 if (AI->getPointerOperand() == UseV)
5289 MA = AI->getAlign();
5295 unsigned Alignment = MA->value();
5299 if (
Base == &AssociatedValue) {
5304 uint32_t
gcd = std::gcd(uint32_t(
abs((int32_t)
Offset)), Alignment);
5312struct AAAlignImpl : AAAlign {
5313 AAAlignImpl(
const IRPosition &IRP, Attributor &
A) : AAAlign(IRP,
A) {}
5318 A.getAttrs(getIRPosition(), {Attribute::Alignment},
Attrs);
5320 takeKnownMaximum(Attr.getValueAsInt());
5322 Value &
V = *getAssociatedValue().stripPointerCasts();
5323 takeKnownMaximum(
V.getPointerAlignment(
A.getDataLayout()).value());
5325 if (Instruction *CtxI = getCtxI())
5326 followUsesInMBEC(*
this,
A, getState(), *CtxI);
5334 Value &AssociatedValue = getAssociatedValue();
5336 return ChangeStatus::UNCHANGED;
5338 for (
const Use &U : AssociatedValue.
uses()) {
5340 if (
SI->getPointerOperand() == &AssociatedValue)
5341 if (
SI->getAlign() < getAssumedAlign()) {
5343 "Number of times alignment added to a store");
5344 SI->setAlignment(getAssumedAlign());
5345 InstrChanged = ChangeStatus::CHANGED;
5348 if (LI->getPointerOperand() == &AssociatedValue)
5349 if (LI->getAlign() < getAssumedAlign()) {
5350 LI->setAlignment(getAssumedAlign());
5352 "Number of times alignment added to a load");
5353 InstrChanged = ChangeStatus::CHANGED;
5356 if (RMW->getPointerOperand() == &AssociatedValue) {
5357 if (RMW->getAlign() < getAssumedAlign()) {
5359 "Number of times alignment added to atomicrmw");
5361 RMW->setAlignment(getAssumedAlign());
5362 InstrChanged = ChangeStatus::CHANGED;
5366 if (CAS->getPointerOperand() == &AssociatedValue) {
5367 if (CAS->getAlign() < getAssumedAlign()) {
5369 "Number of times alignment added to cmpxchg");
5370 CAS->setAlignment(getAssumedAlign());
5371 InstrChanged = ChangeStatus::CHANGED;
5379 Align InheritAlign =
5380 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5381 if (InheritAlign >= getAssumedAlign())
5382 return InstrChanged;
5383 return Changed | InstrChanged;
5391 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5392 SmallVectorImpl<Attribute> &Attrs)
const override {
5393 if (getAssumedAlign() > 1)
5395 Attribute::getWithAlignment(Ctx,
Align(getAssumedAlign())));
5399 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5400 AAAlign::StateType &State) {
5401 bool TrackUse =
false;
5403 unsigned int KnownAlign =
5404 getKnownAlignForUse(
A, *
this, getAssociatedValue(), U,
I, TrackUse);
5405 State.takeKnownMaximum(KnownAlign);
5411 const std::string getAsStr(Attributor *
A)
const override {
5412 return "align<" + std::to_string(getKnownAlign().value()) +
"-" +
5413 std::to_string(getAssumedAlign().value()) +
">";
5418struct AAAlignFloating : AAAlignImpl {
5419 AAAlignFloating(
const IRPosition &IRP, Attributor &
A) : AAAlignImpl(IRP,
A) {}
5423 const DataLayout &
DL =
A.getDataLayout();
5426 bool UsedAssumedInformation =
false;
5428 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5430 Values.
push_back({getAssociatedValue(), getCtxI()});
5433 Stripped = Values.
size() != 1 ||
5434 Values.
front().getValue() != &getAssociatedValue();
5438 auto VisitValueCB = [&](
Value &
V) ->
bool {
5442 DepClassTy::REQUIRED);
5443 if (!AA || (!Stripped &&
this == AA)) {
5445 unsigned Alignment = 1;
5458 Alignment =
V.getPointerAlignment(
DL).value();
5461 T.takeKnownMaximum(Alignment);
5462 T.indicatePessimisticFixpoint();
5465 const AAAlign::StateType &
DS = AA->
getState();
5468 return T.isValidState();
5471 for (
const auto &VAC : Values) {
5472 if (!VisitValueCB(*VAC.
getValue()))
5473 return indicatePessimisticFixpoint();
5486struct AAAlignReturned final
5487 : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {
5488 using Base = AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>;
5489 AAAlignReturned(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5496struct AAAlignArgument final
5497 : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {
5498 using Base = AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>;
5499 AAAlignArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5506 if (
A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))
5507 return ChangeStatus::UNCHANGED;
5508 return Base::manifest(
A);
5515struct AAAlignCallSiteArgument final : AAAlignFloating {
5516 AAAlignCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5517 : AAAlignFloating(IRP,
A) {}
5524 if (Argument *Arg = getAssociatedArgument())
5525 if (
A.getInfoCache().isInvolvedInMustTailCall(*Arg))
5526 return ChangeStatus::UNCHANGED;
5528 Align InheritAlign =
5529 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5530 if (InheritAlign >= getAssumedAlign())
5531 Changed = ChangeStatus::UNCHANGED;
5538 if (Argument *Arg = getAssociatedArgument()) {
5541 const auto *ArgAlignAA =
A.getAAFor<AAAlign>(
5544 takeKnownMaximum(ArgAlignAA->getKnownAlign().value());
5554struct AAAlignCallSiteReturned final
5555 : AACalleeToCallSite<AAAlign, AAAlignImpl> {
5556 using Base = AACalleeToCallSite<AAAlign, AAAlignImpl>;
5557 AAAlignCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5563 switch (
II->getIntrinsicID()) {
5564 case Intrinsic::ptrmask: {
5568 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5570 if (ConstVals && ConstVals->isValidState()) {
5571 unsigned ShiftValue =
5572 std::min(ConstVals->getAssumedMinTrailingZeros(),
5573 Value::MaxAlignmentExponent);
5574 Alignment =
Align(UINT64_C(1) << ShiftValue);
5578 const auto *AlignAA =
5580 DepClassTy::REQUIRED);
5582 Alignment = std::max(AlignAA->getAssumedAlign(), Alignment);
5589 std::min(this->getAssumedAlign(), Alignment).value());
5595 case Intrinsic::amdgcn_make_buffer_rsrc: {
5596 const auto *AlignAA =
5598 DepClassTy::REQUIRED);
5601 this->getState(), AlignAA->getAssumedAlign().
value());
5608 return Base::updateImpl(
A);
5617struct AANoReturnImpl :
public AANoReturn {
5618 AANoReturnImpl(
const IRPosition &IRP, Attributor &
A) : AANoReturn(IRP,
A) {}
5624 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
5629 const std::string getAsStr(Attributor *
A)
const override {
5630 return getAssumed() ?
"noreturn" :
"may-return";
5635 auto CheckForNoReturn = [](
Instruction &) {
return false; };
5636 bool UsedAssumedInformation =
false;
5637 if (!
A.checkForAllInstructions(CheckForNoReturn, *
this,
5638 {(unsigned)Instruction::Ret},
5639 UsedAssumedInformation))
5640 return indicatePessimisticFixpoint();
5641 return ChangeStatus::UNCHANGED;
5645struct AANoReturnFunction final : AANoReturnImpl {
5646 AANoReturnFunction(
const IRPosition &IRP, Attributor &
A)
5647 : AANoReturnImpl(IRP,
A) {}
5654struct AANoReturnCallSite final
5655 : AACalleeToCallSite<AANoReturn, AANoReturnImpl> {
5656 AANoReturnCallSite(
const IRPosition &IRP, Attributor &
A)
5657 : AACalleeToCallSite<AANoReturn, AANoReturnImpl>(IRP,
A) {}
5668struct AAInstanceInfoImpl :
public AAInstanceInfo {
5669 AAInstanceInfoImpl(
const IRPosition &IRP, Attributor &
A)
5670 : AAInstanceInfo(IRP,
A) {}
5674 Value &
V = getAssociatedValue();
5676 if (
C->isThreadDependent())
5677 indicatePessimisticFixpoint();
5679 indicateOptimisticFixpoint();
5685 indicateOptimisticFixpoint();
5690 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
5693 indicatePessimisticFixpoint();
5703 Value &
V = getAssociatedValue();
5706 Scope =
I->getFunction();
5709 if (!
Scope->hasLocalLinkage())
5713 return indicateOptimisticFixpoint();
5715 bool IsKnownNoRecurse;
5721 auto UsePred = [&](
const Use &
U,
bool &Follow) {
5736 if (!Callee || !
Callee->hasLocalLinkage())
5740 const auto *ArgInstanceInfoAA =
A.getAAFor<AAInstanceInfo>(
5742 DepClassTy::OPTIONAL);
5743 if (!ArgInstanceInfoAA ||
5744 !ArgInstanceInfoAA->isAssumedUniqueForAnalysis())
5749 A, *CB, *Scope, *
this,
nullptr,
5750 [Scope](
const Function &Fn) {
return &Fn !=
Scope; }))
5757 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
5759 auto *Ptr =
SI->getPointerOperand()->stripPointerCasts();
5767 if (!
A.checkForAllUses(UsePred, *
this, V,
true,
5768 DepClassTy::OPTIONAL,
5769 true, EquivalentUseCB))
5770 return indicatePessimisticFixpoint();
5776 const std::string getAsStr(Attributor *
A)
const override {
5777 return isAssumedUniqueForAnalysis() ?
"<unique [fAa]>" :
"<unknown>";
5781 void trackStatistics()
const override {}
5785struct AAInstanceInfoFloating : AAInstanceInfoImpl {
5786 AAInstanceInfoFloating(
const IRPosition &IRP, Attributor &
A)
5787 : AAInstanceInfoImpl(IRP,
A) {}
5791struct AAInstanceInfoArgument final : AAInstanceInfoFloating {
5792 AAInstanceInfoArgument(
const IRPosition &IRP, Attributor &
A)
5793 : AAInstanceInfoFloating(IRP,
A) {}
5797struct AAInstanceInfoCallSiteArgument final : AAInstanceInfoImpl {
5798 AAInstanceInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5799 : AAInstanceInfoImpl(IRP,
A) {}
5807 Argument *Arg = getAssociatedArgument();
5809 return indicatePessimisticFixpoint();
5812 A.getAAFor<AAInstanceInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
5814 return indicatePessimisticFixpoint();
5820struct AAInstanceInfoReturned final : AAInstanceInfoImpl {
5821 AAInstanceInfoReturned(
const IRPosition &IRP, Attributor &
A)
5822 : AAInstanceInfoImpl(IRP,
A) {
5838struct AAInstanceInfoCallSiteReturned final : AAInstanceInfoFloating {
5839 AAInstanceInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5840 : AAInstanceInfoFloating(IRP,
A) {}
5847 bool IgnoreSubsumingPositions) {
5848 assert(ImpliedAttributeKind == Attribute::Captures &&
5849 "Unexpected attribute kind");
5859 V.getType()->getPointerAddressSpace() == 0)) {
5864 A.getAttrs(IRP, {Attribute::Captures}, Attrs,
5874 {Attribute::Captures, Attribute::ByVal}, Attrs,
5912 bool NoThrow =
F.doesNotThrow();
5913 bool IsVoidReturn =
F.getReturnType()->isVoidTy();
5914 if (
ReadOnly && NoThrow && IsVoidReturn) {
5927 if (NoThrow && IsVoidReturn)
5932 if (!NoThrow || ArgNo < 0 ||
5933 !
F.getAttributes().hasAttrSomewhere(Attribute::Returned))
5936 for (
unsigned U = 0, E =
F.arg_size(); U < E; ++U)
5937 if (
F.hasParamAttribute(U, Attribute::Returned)) {
5938 if (U ==
unsigned(ArgNo))
5965 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5966 SmallVectorImpl<Attribute> &Attrs)
const override {
5967 if (!isAssumedNoCaptureMaybeReturned())
5970 if (isArgumentPosition()) {
5971 if (isAssumedNoCapture())
5972 Attrs.emplace_back(Attribute::get(Ctx, Attribute::Captures));
5974 Attrs.emplace_back(Attribute::get(Ctx,
"no-capture-maybe-returned"));
5979 const std::string getAsStr(Attributor *
A)
const override {
5980 if (isKnownNoCapture())
5981 return "known not-captured";
5982 if (isAssumedNoCapture())
5983 return "assumed not-captured";
5984 if (isKnownNoCaptureMaybeReturned())
5985 return "known not-captured-maybe-returned";
5986 if (isAssumedNoCaptureMaybeReturned())
5987 return "assumed not-captured-maybe-returned";
5988 return "assumed-captured";
5993 bool checkUse(Attributor &
A, AANoCapture::StateType &State,
const Use &U,
5996 LLVM_DEBUG(
dbgs() <<
"[AANoCapture] Check use: " << *
U.get() <<
" in "
6002 return isCapturedIn(State,
true,
true,
6009 return isCapturedIn(State,
true,
true,
6015 return isCapturedIn(State,
false,
false,
6017 return isCapturedIn(State,
true,
true,
6025 return isCapturedIn(State,
true,
true,
6032 bool IsKnownNoCapture;
6033 const AANoCapture *ArgNoCaptureAA =
nullptr;
6035 A,
this, CSArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6037 if (IsAssumedNoCapture)
6038 return isCapturedIn(State,
false,
false,
6042 return isCapturedIn(State,
false,
false,
6047 return isCapturedIn(State,
true,
true,
6054 static bool isCapturedIn(AANoCapture::StateType &State,
bool CapturedInMem,
6055 bool CapturedInInt,
bool CapturedInRet) {
6056 LLVM_DEBUG(
dbgs() <<
" - captures [Mem " << CapturedInMem <<
"|Int "
6057 << CapturedInInt <<
"|Ret " << CapturedInRet <<
"]\n");
6069 const IRPosition &IRP = getIRPosition();
6073 return indicatePessimisticFixpoint();
6080 return indicatePessimisticFixpoint();
6088 T.addKnownBits(NOT_CAPTURED_IN_MEM);
6090 addKnownBits(NOT_CAPTURED_IN_MEM);
6097 auto CheckReturnedArgs = [&](
bool &UsedAssumedInformation) {
6101 UsedAssumedInformation))
6103 bool SeenConstant =
false;
6104 for (
const AA::ValueAndContext &VAC : Values) {
6108 SeenConstant =
true;
6110 VAC.
getValue() == getAssociatedArgument())
6116 bool IsKnownNoUnwind;
6119 bool IsVoidTy =
F->getReturnType()->isVoidTy();
6120 bool UsedAssumedInformation =
false;
6121 if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {
6122 T.addKnownBits(NOT_CAPTURED_IN_RET);
6123 if (
T.isKnown(NOT_CAPTURED_IN_MEM))
6125 if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {
6126 addKnownBits(NOT_CAPTURED_IN_RET);
6127 if (isKnown(NOT_CAPTURED_IN_MEM))
6128 return indicateOptimisticFixpoint();
6133 auto UseCheck = [&](
const Use &
U,
bool &Follow) ->
bool {
6142 return checkUse(
A,
T, U, Follow);
6145 if (!
A.checkForAllUses(UseCheck, *
this, *V))
6146 return indicatePessimisticFixpoint();
6149 auto Assumed = S.getAssumed();
6150 S.intersectAssumedBits(
T.getAssumed());
6151 if (!isAssumedNoCaptureMaybeReturned())
6152 return indicatePessimisticFixpoint();
6158struct AANoCaptureArgument final : AANoCaptureImpl {
6159 AANoCaptureArgument(
const IRPosition &IRP, Attributor &
A)
6160 : AANoCaptureImpl(IRP,
A) {}
6167struct AANoCaptureCallSiteArgument final : AANoCaptureImpl {
6168 AANoCaptureCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6169 : AANoCaptureImpl(IRP,
A) {}
6177 Argument *Arg = getAssociatedArgument();
6179 return indicatePessimisticFixpoint();
6181 bool IsKnownNoCapture;
6182 const AANoCapture *ArgAA =
nullptr;
6184 A,
this, ArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6186 return ChangeStatus::UNCHANGED;
6188 return indicatePessimisticFixpoint();
6193 void trackStatistics()
const override {
6199struct AANoCaptureFloating final : AANoCaptureImpl {
6200 AANoCaptureFloating(
const IRPosition &IRP, Attributor &
A)
6201 : AANoCaptureImpl(IRP,
A) {}
6204 void trackStatistics()
const override {
6210struct AANoCaptureReturned final : AANoCaptureImpl {
6211 AANoCaptureReturned(
const IRPosition &IRP, Attributor &
A)
6212 : AANoCaptureImpl(IRP,
A) {
6227 void trackStatistics()
const override {}
6231struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {
6232 AANoCaptureCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6233 : AANoCaptureImpl(IRP,
A) {}
6239 determineFunctionCaptureCapabilities(getIRPosition(), *
F, *
this);
6243 void trackStatistics()
const override {
6260 dbgs() <<
"[ValueSimplify] is assumed to be "
6263 dbgs() <<
"[ValueSimplify] is assumed to be <none>\n";
6275 if (getAssociatedValue().
getType()->isVoidTy())
6276 indicatePessimisticFixpoint();
6277 if (
A.hasSimplificationCallback(getIRPosition()))
6278 indicatePessimisticFixpoint();
6282 const std::string getAsStr(Attributor *
A)
const override {
6284 dbgs() <<
"SAV: " << (bool)SimplifiedAssociatedValue <<
" ";
6285 if (SimplifiedAssociatedValue && *SimplifiedAssociatedValue)
6286 dbgs() <<
"SAV: " << **SimplifiedAssociatedValue <<
" ";
6288 return isValidState() ? (isAtFixpoint() ?
"simplified" :
"maybe-simple")
6293 void trackStatistics()
const override {}
6296 std::optional<Value *>
6297 getAssumedSimplifiedValue(Attributor &
A)
const override {
6298 return SimplifiedAssociatedValue;
6305 static Value *ensureType(Attributor &
A,
Value &V,
Type &Ty, Instruction *CtxI,
6309 if (CtxI &&
V.getType()->canLosslesslyBitCastTo(&Ty))
6311 : BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6320 static Value *reproduceInst(Attributor &
A,
6321 const AbstractAttribute &QueryingAA,
6322 Instruction &
I,
Type &Ty, Instruction *CtxI,
6324 assert(CtxI &&
"Cannot reproduce an instruction without context!");
6325 if (
Check && (
I.mayReadFromMemory() ||
6330 Value *NewOp = reproduceValue(
A, QueryingAA, *
Op, Ty, CtxI,
Check, VMap);
6332 assert(
Check &&
"Manifest of new value unexpectedly failed!");
6354 static Value *reproduceValue(Attributor &
A,
6355 const AbstractAttribute &QueryingAA,
Value &V,
6356 Type &Ty, Instruction *CtxI,
bool Check,
6358 if (
const auto &NewV = VMap.
lookup(&V))
6360 bool UsedAssumedInformation =
false;
6361 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
6363 if (!SimpleV.has_value())
6367 EffectiveV = *SimpleV;
6372 return ensureType(
A, *EffectiveV, Ty, CtxI,
Check);
6374 if (
Value *NewV = reproduceInst(
A, QueryingAA, *
I, Ty, CtxI,
Check, VMap))
6375 return ensureType(
A, *NewV, Ty, CtxI,
Check);
6381 Value *manifestReplacementValue(Attributor &
A, Instruction *CtxI)
const {
6382 Value *NewV = SimplifiedAssociatedValue
6383 ? *SimplifiedAssociatedValue
6385 if (NewV && NewV != &getAssociatedValue()) {
6389 if (reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6391 return reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6399 bool checkAndUpdate(Attributor &
A,
const AbstractAttribute &QueryingAA,
6400 const IRPosition &IRP,
bool Simplify =
true) {
6401 bool UsedAssumedInformation =
false;
6404 QueryingValueSimplified =
A.getAssumedSimplified(
6406 return unionAssumed(QueryingValueSimplified);
6410 template <
typename AAType>
bool askSimplifiedValueFor(Attributor &
A) {
6411 if (!getAssociatedValue().
getType()->isIntegerTy())
6416 A.getAAFor<AAType>(*
this, getIRPosition(), DepClassTy::NONE);
6420 std::optional<Constant *> COpt = AA->getAssumedConstant(
A);
6423 SimplifiedAssociatedValue = std::nullopt;
6424 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6427 if (
auto *
C = *COpt) {
6428 SimplifiedAssociatedValue =
C;
6429 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6435 bool askSimplifiedValueForOtherAAs(Attributor &
A) {
6436 if (askSimplifiedValueFor<AAValueConstantRange>(
A))
6438 if (askSimplifiedValueFor<AAPotentialConstantValues>(
A))
6446 for (
auto &U : getAssociatedValue().uses()) {
6451 IP =
PHI->getIncomingBlock(U)->getTerminator();
6452 if (
auto *NewV = manifestReplacementValue(
A, IP)) {
6454 <<
" -> " << *NewV <<
" :: " << *
this <<
"\n");
6455 if (
A.changeUseAfterManifest(U, *NewV))
6456 Changed = ChangeStatus::CHANGED;
6460 return Changed | AAValueSimplify::manifest(
A);
6465 SimplifiedAssociatedValue = &getAssociatedValue();
6466 return AAValueSimplify::indicatePessimisticFixpoint();
6470struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
6471 AAValueSimplifyArgument(
const IRPosition &IRP, Attributor &
A)
6472 : AAValueSimplifyImpl(IRP,
A) {}
6475 AAValueSimplifyImpl::initialize(
A);
6476 if (
A.hasAttr(getIRPosition(),
6477 {Attribute::InAlloca, Attribute::Preallocated,
6478 Attribute::StructRet, Attribute::Nest, Attribute::ByVal},
6480 indicatePessimisticFixpoint();
6487 Argument *Arg = getAssociatedArgument();
6493 return indicatePessimisticFixpoint();
6496 auto Before = SimplifiedAssociatedValue;
6498 auto PredForCallSite = [&](AbstractCallSite ACS) {
6499 const IRPosition &ACSArgPos =
6510 bool UsedAssumedInformation =
false;
6511 std::optional<Constant *> SimpleArgOp =
6512 A.getAssumedConstant(ACSArgPos, *
this, UsedAssumedInformation);
6519 return unionAssumed(*SimpleArgOp);
6524 bool UsedAssumedInformation =
false;
6525 if (hasCallBaseContext() &&
6526 getCallBaseContext()->getCalledOperand() == Arg->
getParent())
6528 AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
6530 Success =
A.checkForAllCallSites(PredForCallSite, *
this,
true,
6531 UsedAssumedInformation);
6534 if (!askSimplifiedValueForOtherAAs(
A))
6535 return indicatePessimisticFixpoint();
6538 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6539 : ChangeStatus ::CHANGED;
6543 void trackStatistics()
const override {
6548struct AAValueSimplifyReturned : AAValueSimplifyImpl {
6549 AAValueSimplifyReturned(
const IRPosition &IRP, Attributor &
A)
6550 : AAValueSimplifyImpl(IRP,
A) {}
6553 std::optional<Value *>
6554 getAssumedSimplifiedValue(Attributor &
A)
const override {
6555 if (!isValidState())
6557 return SimplifiedAssociatedValue;
6562 auto Before = SimplifiedAssociatedValue;
6566 return checkAndUpdate(
6571 bool UsedAssumedInformation =
false;
6572 if (!
A.checkForAllInstructions(ReturnInstCB, *
this, {Instruction::Ret},
6573 UsedAssumedInformation))
6574 if (!askSimplifiedValueForOtherAAs(
A))
6575 return indicatePessimisticFixpoint();
6578 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6579 : ChangeStatus ::CHANGED;
6585 return ChangeStatus::UNCHANGED;
6589 void trackStatistics()
const override {
6594struct AAValueSimplifyFloating : AAValueSimplifyImpl {
6595 AAValueSimplifyFloating(
const IRPosition &IRP, Attributor &
A)
6596 : AAValueSimplifyImpl(IRP,
A) {}
6600 AAValueSimplifyImpl::initialize(
A);
6601 Value &
V = getAnchorValue();
6605 indicatePessimisticFixpoint();
6610 auto Before = SimplifiedAssociatedValue;
6611 if (!askSimplifiedValueForOtherAAs(
A))
6612 return indicatePessimisticFixpoint();
6615 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6616 : ChangeStatus ::CHANGED;
6620 void trackStatistics()
const override {
6625struct AAValueSimplifyFunction : AAValueSimplifyImpl {
6626 AAValueSimplifyFunction(
const IRPosition &IRP, Attributor &
A)
6627 : AAValueSimplifyImpl(IRP,
A) {}
6631 SimplifiedAssociatedValue =
nullptr;
6632 indicateOptimisticFixpoint();
6637 "AAValueSimplify(Function|CallSite)::updateImpl will not be called");
6640 void trackStatistics()
const override {
6645struct AAValueSimplifyCallSite : AAValueSimplifyFunction {
6646 AAValueSimplifyCallSite(
const IRPosition &IRP, Attributor &
A)
6647 : AAValueSimplifyFunction(IRP,
A) {}
6649 void trackStatistics()
const override {
6654struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl {
6655 AAValueSimplifyCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6656 : AAValueSimplifyImpl(IRP,
A) {}
6659 AAValueSimplifyImpl::initialize(
A);
6660 Function *Fn = getAssociatedFunction();
6661 assert(Fn &&
"Did expect an associted function");
6662 for (Argument &Arg : Fn->
args()) {
6667 checkAndUpdate(
A, *
this, IRP))
6668 indicateOptimisticFixpoint();
6670 indicatePessimisticFixpoint();
6678 return indicatePessimisticFixpoint();
6681 void trackStatistics()
const override {
6686struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
6687 AAValueSimplifyCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6688 : AAValueSimplifyFloating(IRP,
A) {}
6694 auto *FloatAA =
A.lookupAAFor<AAValueSimplify>(
6696 if (FloatAA && FloatAA->getState().isValidState())
6699 if (
auto *NewV = manifestReplacementValue(
A, getCtxI())) {
6701 ->getArgOperandUse(getCallSiteArgNo());
6702 if (
A.changeUseAfterManifest(U, *NewV))
6703 Changed = ChangeStatus::CHANGED;
6706 return Changed | AAValueSimplify::manifest(
A);
6709 void trackStatistics()
const override {
6717struct AAHeapToStackFunction final :
public AAHeapToStack {
6719 static bool isGlobalizedLocal(
const CallBase &CB) {
6721 return A.
isValid() &&
A.getValueAsString() ==
"__kmpc_alloc_shared";
6724 struct AllocationInfo {
6729 bool IsGlobalizedLocal =
false;
6736 } Status = STACK_DUE_TO_USE;
6740 bool HasPotentiallyFreeingUnknownUses =
false;
6744 bool MoveAllocaIntoEntry =
true;
6747 SmallSetVector<CallBase *, 1> PotentialFreeCalls{};
6750 struct DeallocationInfo {
6758 bool MightFreeUnknownObjects =
false;
6761 SmallSetVector<CallBase *, 1> PotentialAllocationCalls{};
6764 AAHeapToStackFunction(
const IRPosition &IRP, Attributor &
A)
6765 : AAHeapToStack(IRP,
A) {}
6767 ~AAHeapToStackFunction()
override {
6770 for (
auto &It : AllocationInfos)
6771 It.second->~AllocationInfo();
6772 for (
auto &It : DeallocationInfos)
6773 It.second->~DeallocationInfo();
6777 AAHeapToStack::initialize(
A);
6780 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6787 DeallocationInfos[CB] =
new (
A.Allocator) DeallocationInfo{CB, FreedOp};
6794 auto *I8Ty = Type::getInt8Ty(CB->
getParent()->getContext());
6796 AllocationInfo *AI =
new (
A.Allocator) AllocationInfo{CB};
6797 AllocationInfos[CB] = AI;
6798 AI->IsGlobalizedLocal = isGlobalizedLocal(*CB);
6804 bool UsedAssumedInformation =
false;
6805 bool Success =
A.checkForAllCallLikeInstructions(
6806 AllocationIdentifierCB, *
this, UsedAssumedInformation,
6810 assert(
Success &&
"Did not expect the call base visit callback to fail!");
6813 [](
const IRPosition &,
const AbstractAttribute *,
6814 bool &) -> std::optional<Value *> {
return nullptr; };
6815 for (
const auto &It : AllocationInfos)
6818 for (
const auto &It : DeallocationInfos)
6823 const std::string getAsStr(Attributor *
A)
const override {
6824 unsigned NumH2SMallocs = 0, NumInvalidMallocs = 0;
6825 for (
const auto &It : AllocationInfos) {
6826 if (It.second->Status == AllocationInfo::INVALID)
6827 ++NumInvalidMallocs;
6831 return "[H2S] Mallocs Good/Bad: " + std::to_string(NumH2SMallocs) +
"/" +
6832 std::to_string(NumInvalidMallocs);
6836 void trackStatistics()
const override {
6838 MallocCalls, Function,
6839 "Number of malloc/calloc/aligned_alloc calls converted to allocas");
6840 for (
const auto &It : AllocationInfos)
6841 if (It.second->Status != AllocationInfo::INVALID)
6845 bool isAssumedHeapToStack(
const CallBase &CB)
const override {
6847 if (AllocationInfo *AI =
6848 AllocationInfos.lookup(
const_cast<CallBase *
>(&CB)))
6849 return AI->Status != AllocationInfo::INVALID;
6853 bool isAssumedHeapToStackRemovedFree(CallBase &CB)
const override {
6854 if (!isValidState())
6857 for (
const auto &It : AllocationInfos) {
6858 AllocationInfo &AI = *It.second;
6859 if (AI.Status == AllocationInfo::INVALID)
6862 if (AI.PotentialFreeCalls.count(&CB))
6870 assert(getState().isValidState() &&
6871 "Attempted to manifest an invalid state!");
6875 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6877 for (
auto &It : AllocationInfos) {
6878 AllocationInfo &AI = *It.second;
6879 if (AI.Status == AllocationInfo::INVALID)
6882 for (CallBase *FreeCall : AI.PotentialFreeCalls) {
6883 LLVM_DEBUG(
dbgs() <<
"H2S: Removing free call: " << *FreeCall <<
"\n");
6884 A.deleteAfterManifest(*FreeCall);
6885 HasChanged = ChangeStatus::CHANGED;
6888 LLVM_DEBUG(
dbgs() <<
"H2S: Removing malloc-like call: " << *AI.CB
6891 auto Remark = [&](OptimizationRemark
OR) {
6892 if (AI.IsGlobalizedLocal)
6893 return OR <<
"Moving globalized variable to the stack.";
6894 return OR <<
"Moving memory allocation from the heap to the stack.";
6896 if (AI.IsGlobalizedLocal)
6897 A.emitRemark<OptimizationRemark>(AI.CB,
"OMP110",
Remark);
6899 A.emitRemark<OptimizationRemark>(AI.CB,
"HeapToStack",
Remark);
6901 const DataLayout &
DL =
A.getInfoCache().getDL();
6903 std::optional<APInt> SizeAPI =
getSize(
A, *
this, AI);
6905 Size = ConstantInt::get(AI.CB->getContext(), *SizeAPI);
6907 LLVMContext &Ctx = AI.CB->getContext();
6908 ObjectSizeOpts Opts;
6909 ObjectSizeOffsetEvaluator Eval(
DL, TLI, Ctx, Opts);
6910 SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);
6917 ?
F->getEntryBlock().begin()
6918 : AI.CB->getIterator();
6921 if (MaybeAlign RetAlign = AI.CB->getRetAlign())
6922 Alignment = std::max(Alignment, *RetAlign);
6924 std::optional<APInt> AlignmentAPI = getAPInt(
A, *
this, *Align);
6925 assert(AlignmentAPI && AlignmentAPI->getZExtValue() > 0 &&
6926 "Expected an alignment during manifest!");
6928 std::max(Alignment,
assumeAligned(AlignmentAPI->getZExtValue()));
6932 unsigned AS =
DL.getAllocaAddrSpace();
6934 new AllocaInst(Type::getInt8Ty(
F->getContext()), AS,
Size, Alignment,
6935 AI.CB->getName() +
".h2s", IP);
6937 if (Alloca->
getType() != AI.CB->getType())
6938 Alloca = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6939 Alloca, AI.CB->getType(),
"malloc_cast", AI.CB->getIterator());
6941 auto *I8Ty = Type::getInt8Ty(
F->getContext());
6944 "Must be able to materialize initial memory state of allocation");
6949 auto *NBB =
II->getNormalDest();
6951 A.deleteAfterManifest(*AI.CB);
6953 A.deleteAfterManifest(*AI.CB);
6962 Builder.CreateMemSet(Alloca, InitVal,
Size, std::nullopt);
6964 HasChanged = ChangeStatus::CHANGED;
6970 std::optional<APInt> getAPInt(Attributor &
A,
const AbstractAttribute &AA,
6972 bool UsedAssumedInformation =
false;
6973 std::optional<Constant *> SimpleV =
6974 A.getAssumedConstant(V, AA, UsedAssumedInformation);
6976 return APInt(64, 0);
6978 return CI->getValue();
6979 return std::nullopt;
6982 std::optional<APInt>
getSize(Attributor &
A,
const AbstractAttribute &AA,
6983 AllocationInfo &AI) {
6984 auto Mapper = [&](
const Value *
V) ->
const Value * {
6985 bool UsedAssumedInformation =
false;
6986 if (std::optional<Constant *> SimpleV =
6987 A.getAssumedConstant(*V, AA, UsedAssumedInformation))
6994 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
7000 MapVector<CallBase *, AllocationInfo *> AllocationInfos;
7004 MapVector<CallBase *, DeallocationInfo *> DeallocationInfos;
7009ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &
A) {
7012 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
7014 const auto *LivenessAA =
7017 MustBeExecutedContextExplorer *Explorer =
7018 A.getInfoCache().getMustBeExecutedContextExplorer();
7020 bool StackIsAccessibleByOtherThreads =
7021 A.getInfoCache().stackIsAccessibleByOtherThreads();
7024 A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(*F);
7025 std::optional<bool> MayContainIrreducibleControl;
7027 if (&
F->getEntryBlock() == &BB)
7029 if (!MayContainIrreducibleControl.has_value())
7031 if (*MayContainIrreducibleControl)
7040 bool HasUpdatedFrees =
false;
7042 auto UpdateFrees = [&]() {
7043 HasUpdatedFrees =
true;
7045 for (
auto &It : DeallocationInfos) {
7046 DeallocationInfo &DI = *It.second;
7049 if (DI.MightFreeUnknownObjects)
7053 bool UsedAssumedInformation =
false;
7054 if (
A.isAssumedDead(*DI.CB,
this, LivenessAA, UsedAssumedInformation,
7061 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown underlying object for free!\n");
7062 DI.MightFreeUnknownObjects =
true;
7075 DI.MightFreeUnknownObjects =
true;
7079 AllocationInfo *AI = AllocationInfos.lookup(ObjCB);
7081 LLVM_DEBUG(
dbgs() <<
"[H2S] Free of a non-allocation object: " << *Obj
7083 DI.MightFreeUnknownObjects =
true;
7087 DI.PotentialAllocationCalls.insert(ObjCB);
7091 auto FreeCheck = [&](AllocationInfo &AI) {
7095 if (!StackIsAccessibleByOtherThreads) {
7100 dbgs() <<
"[H2S] found an escaping use, stack is not accessible by "
7101 "other threads and function is not nosync:\n");
7105 if (!HasUpdatedFrees)
7109 if (AI.PotentialFreeCalls.size() != 1) {
7111 << AI.PotentialFreeCalls.size() <<
"\n");
7114 CallBase *UniqueFree = *AI.PotentialFreeCalls.begin();
7115 DeallocationInfo *DI = DeallocationInfos.lookup(UniqueFree);
7118 dbgs() <<
"[H2S] unique free call was not known as deallocation call "
7119 << *UniqueFree <<
"\n");
7122 if (DI->MightFreeUnknownObjects) {
7124 dbgs() <<
"[H2S] unique free call might free unknown allocations\n");
7127 if (DI->PotentialAllocationCalls.empty())
7129 if (DI->PotentialAllocationCalls.size() > 1) {
7131 << DI->PotentialAllocationCalls.size()
7132 <<
" different allocations\n");
7135 if (*DI->PotentialAllocationCalls.begin() != AI.CB) {
7138 <<
"[H2S] unique free call not known to free this allocation but "
7139 << **DI->PotentialAllocationCalls.begin() <<
"\n");
7144 if (!AI.IsGlobalizedLocal) {
7146 if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
7147 LLVM_DEBUG(
dbgs() <<
"[H2S] unique free call might not be executed "
7148 "with the allocation "
7149 << *UniqueFree <<
"\n");
7156 auto UsesCheck = [&](AllocationInfo &AI) {
7157 bool ValidUsesOnly =
true;
7159 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
7164 if (
SI->getValueOperand() ==
U.get()) {
7166 <<
"[H2S] escaping store to memory: " << *UserI <<
"\n");
7167 ValidUsesOnly =
false;
7176 if (DeallocationInfos.count(CB)) {
7177 AI.PotentialFreeCalls.insert(CB);
7184 bool IsKnownNoCapture;
7193 if (!IsAssumedNoCapture ||
7194 (!AI.IsGlobalizedLocal && !IsAssumedNoFree)) {
7195 AI.HasPotentiallyFreeingUnknownUses |= !IsAssumedNoFree;
7198 auto Remark = [&](OptimizationRemarkMissed ORM) {
7200 <<
"Could not move globalized variable to the stack. "
7201 "Variable is potentially captured in call. Mark "
7202 "parameter as `__attribute__((noescape))` to override.";
7205 if (ValidUsesOnly && AI.IsGlobalizedLocal)
7206 A.emitRemark<OptimizationRemarkMissed>(CB,
"OMP113",
Remark);
7209 ValidUsesOnly =
false;
7222 ValidUsesOnly =
false;
7225 if (!
A.checkForAllUses(Pred, *
this, *AI.CB,
false,
7227 [&](
const Use &OldU,
const Use &NewU) {
7228 auto *SI = dyn_cast<StoreInst>(OldU.getUser());
7229 return !SI || StackIsAccessibleByOtherThreads ||
7230 AA::isAssumedThreadLocalObject(
7231 A, *SI->getPointerOperand(), *this);
7234 return ValidUsesOnly;
7239 for (
auto &It : AllocationInfos) {
7240 AllocationInfo &AI = *It.second;
7241 if (AI.Status == AllocationInfo::INVALID)
7245 std::optional<APInt> APAlign = getAPInt(
A, *
this, *Align);
7249 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown allocation alignment: " << *AI.CB
7251 AI.Status = AllocationInfo::INVALID;
7256 !APAlign->isPowerOf2()) {
7257 LLVM_DEBUG(
dbgs() <<
"[H2S] Invalid allocation alignment: " << APAlign
7259 AI.Status = AllocationInfo::INVALID;
7270 dbgs() <<
"[H2S] Unknown allocation size: " << *AI.CB <<
"\n";
7272 dbgs() <<
"[H2S] Allocation size too large: " << *AI.CB <<
" vs. "
7276 AI.Status = AllocationInfo::INVALID;
7282 switch (AI.Status) {
7283 case AllocationInfo::STACK_DUE_TO_USE:
7286 AI.Status = AllocationInfo::STACK_DUE_TO_FREE;
7288 case AllocationInfo::STACK_DUE_TO_FREE:
7291 AI.Status = AllocationInfo::INVALID;
7294 case AllocationInfo::INVALID:
7301 bool IsGlobalizedLocal = AI.IsGlobalizedLocal;
7302 if (AI.MoveAllocaIntoEntry &&
7303 (!
Size.has_value() ||
7304 (!IsGlobalizedLocal && IsInLoop(*AI.CB->getParent()))))
7305 AI.MoveAllocaIntoEntry =
false;
7314struct AAPrivatizablePtrImpl :
public AAPrivatizablePtr {
7315 AAPrivatizablePtrImpl(
const IRPosition &IRP, Attributor &
A)
7316 : AAPrivatizablePtr(IRP,
A), PrivatizableType(std::nullopt) {}
7319 AAPrivatizablePtr::indicatePessimisticFixpoint();
7320 PrivatizableType =
nullptr;
7321 return ChangeStatus::CHANGED;
7327 virtual std::optional<Type *> identifyPrivatizableType(Attributor &
A) = 0;
7331 std::optional<Type *> combineTypes(std::optional<Type *> T0,
7332 std::optional<Type *>
T1) {
7342 std::optional<Type *> getPrivatizableType()
const override {
7343 return PrivatizableType;
7346 const std::string getAsStr(Attributor *
A)
const override {
7347 return isAssumedPrivatizablePtr() ?
"[priv]" :
"[no-priv]";
7351 std::optional<Type *> PrivatizableType;
7356struct AAPrivatizablePtrArgument final :
public AAPrivatizablePtrImpl {
7357 AAPrivatizablePtrArgument(
const IRPosition &IRP, Attributor &
A)
7358 : AAPrivatizablePtrImpl(IRP,
A) {}
7361 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7364 bool UsedAssumedInformation =
false;
7366 A.getAttrs(getIRPosition(), {Attribute::ByVal},
Attrs,
7368 if (!
Attrs.empty() &&
7369 A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *
this,
7370 true, UsedAssumedInformation))
7371 return Attrs[0].getValueAsType();
7373 std::optional<Type *> Ty;
7374 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
7382 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7391 A.getAAFor<AAPrivatizablePtr>(*
this, ACSArgPos, DepClassTy::REQUIRED);
7394 std::optional<Type *> CSTy = PrivCSArgAA->getPrivatizableType();
7397 dbgs() <<
"[AAPrivatizablePtr] ACSPos: " << ACSArgPos <<
", CSTy: ";
7401 dbgs() <<
"<nullptr>";
7406 Ty = combineTypes(Ty, CSTy);
7409 dbgs() <<
" : New Type: ";
7411 (*Ty)->print(
dbgs());
7413 dbgs() <<
"<nullptr>";
7422 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7423 UsedAssumedInformation))
7430 PrivatizableType = identifyPrivatizableType(
A);
7431 if (!PrivatizableType)
7432 return ChangeStatus::UNCHANGED;
7433 if (!*PrivatizableType)
7434 return indicatePessimisticFixpoint();
7439 DepClassTy::OPTIONAL);
7442 if (!
A.hasAttr(getIRPosition(), Attribute::ByVal) &&
7445 return indicatePessimisticFixpoint();
7451 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7455 Function &Fn = *getIRPosition().getAnchorScope();
7457 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(Fn);
7459 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Missing TTI for function "
7461 return indicatePessimisticFixpoint();
7464 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7471 bool UsedAssumedInformation =
false;
7472 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7473 UsedAssumedInformation)) {
7475 dbgs() <<
"[AAPrivatizablePtr] ABI incompatibility detected for "
7477 return indicatePessimisticFixpoint();
7481 Argument *Arg = getAssociatedArgument();
7482 if (!
A.isValidFunctionSignatureRewrite(*Arg, ReplacementTypes)) {
7484 return indicatePessimisticFixpoint();
7491 auto IsCompatiblePrivArgOfCallback = [&](CallBase &CB) {
7494 for (
const Use *U : CallbackUses) {
7495 AbstractCallSite CBACS(U);
7496 assert(CBACS && CBACS.isCallbackCall());
7497 for (Argument &CBArg : CBACS.getCalledFunction()->args()) {
7498 int CBArgNo = CBACS.getCallArgOperandNo(CBArg);
7502 <<
"[AAPrivatizablePtr] Argument " << *Arg
7503 <<
"check if can be privatized in the context of its parent ("
7505 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7507 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7508 <<
")\n[AAPrivatizablePtr] " << CBArg <<
" : "
7509 << CBACS.getCallArgOperand(CBArg) <<
" vs "
7511 <<
"[AAPrivatizablePtr] " << CBArg <<
" : "
7512 << CBACS.getCallArgOperandNo(CBArg) <<
" vs " << ArgNo <<
"\n";
7515 if (CBArgNo !=
int(ArgNo))
7517 const auto *CBArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7519 if (CBArgPrivAA && CBArgPrivAA->isValidState()) {
7520 auto CBArgPrivTy = CBArgPrivAA->getPrivatizableType();
7523 if (*CBArgPrivTy == PrivatizableType)
7528 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7529 <<
" cannot be privatized in the context of its parent ("
7531 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7533 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7534 <<
").\n[AAPrivatizablePtr] for which the argument "
7535 "privatization is not compatible.\n";
7545 auto IsCompatiblePrivArgOfDirectCS = [&](AbstractCallSite ACS) {
7549 "Expected a direct call operand for callback call operand");
7554 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7555 <<
" check if be privatized in the context of its parent ("
7557 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7559 << DCArgNo <<
"@" << DCCallee->
getName() <<
").\n";
7562 if (
unsigned(DCArgNo) < DCCallee->
arg_size()) {
7563 const auto *DCArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7565 DepClassTy::REQUIRED);
7566 if (DCArgPrivAA && DCArgPrivAA->isValidState()) {
7567 auto DCArgPrivTy = DCArgPrivAA->getPrivatizableType();
7570 if (*DCArgPrivTy == PrivatizableType)
7576 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7577 <<
" cannot be privatized in the context of its parent ("
7579 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7582 <<
").\n[AAPrivatizablePtr] for which the argument "
7583 "privatization is not compatible.\n";
7591 auto IsCompatiblePrivArgOfOtherCallSite = [&](AbstractCallSite ACS) {
7595 return IsCompatiblePrivArgOfDirectCS(ACS);
7599 if (!
A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *
this,
true,
7600 UsedAssumedInformation))
7601 return indicatePessimisticFixpoint();
7603 return ChangeStatus::UNCHANGED;
7609 identifyReplacementTypes(
Type *PrivType,
7610 SmallVectorImpl<Type *> &ReplacementTypes) {
7613 assert(PrivType &&
"Expected privatizable type!");
7617 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++)
7618 ReplacementTypes.
push_back(PrivStructType->getElementType(u));
7620 ReplacementTypes.
append(PrivArrayType->getNumElements(),
7621 PrivArrayType->getElementType());
7630 static void createInitialization(
Type *PrivType,
Value &
Base, Function &
F,
7632 assert(PrivType &&
"Expected privatizable type!");
7635 const DataLayout &
DL =
F.getDataLayout();
7639 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7640 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7643 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7646 Type *PointeeTy = PrivArrayType->getElementType();
7647 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7648 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7650 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7653 new StoreInst(
F.getArg(ArgNo), &
Base, IP);
7659 void createReplacementValues(Align Alignment,
Type *PrivType,
7661 SmallVectorImpl<Value *> &ReplacementValues) {
7663 assert(PrivType &&
"Expected privatizable type!");
7671 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7672 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7673 Type *PointeeTy = PrivStructType->getElementType(u);
7676 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7677 L->setAlignment(Alignment);
7681 Type *PointeeTy = PrivArrayType->getElementType();
7682 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7683 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7685 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7686 L->setAlignment(Alignment);
7691 L->setAlignment(Alignment);
7698 if (!PrivatizableType)
7699 return ChangeStatus::UNCHANGED;
7700 assert(*PrivatizableType &&
"Expected privatizable type!");
7706 bool UsedAssumedInformation =
false;
7707 if (!
A.checkForAllInstructions(
7708 [&](Instruction &
I) {
7709 CallInst &CI = cast<CallInst>(I);
7710 if (CI.isTailCall())
7711 TailCalls.push_back(&CI);
7714 *
this, {Instruction::Call}, UsedAssumedInformation))
7715 return ChangeStatus::UNCHANGED;
7717 Argument *Arg = getAssociatedArgument();
7720 const auto *AlignAA =
7727 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7729 BasicBlock &EntryBB = ReplacementFn.getEntryBlock();
7731 const DataLayout &
DL = IP->getDataLayout();
7732 unsigned AS =
DL.getAllocaAddrSpace();
7733 Instruction *AI =
new AllocaInst(*PrivatizableType, AS,
7734 Arg->
getName() +
".priv", IP);
7735 createInitialization(*PrivatizableType, *AI, ReplacementFn,
7736 ArgIt->getArgNo(), IP);
7739 AI = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
7743 for (CallInst *CI : TailCalls)
7744 CI->setTailCall(
false);
7751 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7752 AbstractCallSite ACS, SmallVectorImpl<Value *> &NewArgOperands) {
7755 createReplacementValues(
7756 AlignAA ? AlignAA->getAssumedAlign() :
Align(0),
7757 *PrivatizableType, ACS,
7765 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7768 if (
A.registerFunctionSignatureRewrite(*Arg, ReplacementTypes,
7769 std::move(FnRepairCB),
7770 std::move(ACSRepairCB)))
7771 return ChangeStatus::CHANGED;
7772 return ChangeStatus::UNCHANGED;
7776 void trackStatistics()
const override {
7781struct AAPrivatizablePtrFloating :
public AAPrivatizablePtrImpl {
7782 AAPrivatizablePtrFloating(
const IRPosition &IRP, Attributor &
A)
7783 : AAPrivatizablePtrImpl(IRP,
A) {}
7788 indicatePessimisticFixpoint();
7793 "updateImpl will not be called");
7797 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7800 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] No underlying object found!\n");
7807 return AI->getAllocatedType();
7809 auto *PrivArgAA =
A.getAAFor<AAPrivatizablePtr>(
7811 if (PrivArgAA && PrivArgAA->isAssumedPrivatizablePtr())
7812 return PrivArgAA->getPrivatizableType();
7815 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Underlying object neither valid "
7816 "alloca nor privatizable argument: "
7822 void trackStatistics()
const override {
7827struct AAPrivatizablePtrCallSiteArgument final
7828 :
public AAPrivatizablePtrFloating {
7829 AAPrivatizablePtrCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
7830 : AAPrivatizablePtrFloating(IRP,
A) {}
7834 if (
A.hasAttr(getIRPosition(), Attribute::ByVal))
7835 indicateOptimisticFixpoint();
7840 PrivatizableType = identifyPrivatizableType(
A);
7841 if (!PrivatizableType)
7842 return ChangeStatus::UNCHANGED;
7843 if (!*PrivatizableType)
7844 return indicatePessimisticFixpoint();
7846 const IRPosition &IRP = getIRPosition();
7847 bool IsKnownNoCapture;
7849 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoCapture);
7850 if (!IsAssumedNoCapture) {
7851 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might be captured!\n");
7852 return indicatePessimisticFixpoint();
7855 bool IsKnownNoAlias;
7857 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
7858 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might alias!\n");
7859 return indicatePessimisticFixpoint();
7864 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer is written!\n");
7865 return indicatePessimisticFixpoint();
7868 return ChangeStatus::UNCHANGED;
7872 void trackStatistics()
const override {
7877struct AAPrivatizablePtrCallSiteReturned final
7878 :
public AAPrivatizablePtrFloating {
7879 AAPrivatizablePtrCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
7880 : AAPrivatizablePtrFloating(IRP,
A) {}
7885 indicatePessimisticFixpoint();
7889 void trackStatistics()
const override {
7894struct AAPrivatizablePtrReturned final :
public AAPrivatizablePtrFloating {
7895 AAPrivatizablePtrReturned(
const IRPosition &IRP, Attributor &
A)
7896 : AAPrivatizablePtrFloating(IRP,
A) {}
7901 indicatePessimisticFixpoint();
7905 void trackStatistics()
const override {
7915struct AAMemoryBehaviorImpl :
public AAMemoryBehavior {
7916 AAMemoryBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
7917 : AAMemoryBehavior(IRP,
A) {}
7921 intersectAssumedBits(BEST_STATE);
7922 getKnownStateFromValue(
A, getIRPosition(), getState());
7923 AAMemoryBehavior::initialize(
A);
7927 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
7928 BitIntegerState &State,
7929 bool IgnoreSubsumingPositions =
false) {
7931 A.getAttrs(IRP, AttrKinds, Attrs, IgnoreSubsumingPositions);
7933 switch (Attr.getKindAsEnum()) {
7934 case Attribute::ReadNone:
7937 case Attribute::ReadOnly:
7940 case Attribute::WriteOnly:
7949 if (!
I->mayReadFromMemory())
7951 if (!
I->mayWriteToMemory())
7957 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
7958 SmallVectorImpl<Attribute> &Attrs)
const override {
7961 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));
7963 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));
7964 else if (isAssumedWriteOnly())
7965 Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));
7971 const IRPosition &IRP = getIRPosition();
7973 if (
A.hasAttr(IRP, Attribute::ReadNone,
7975 return ChangeStatus::UNCHANGED;
7984 return ChangeStatus::UNCHANGED;
7987 A.removeAttrs(IRP, AttrKinds);
7990 A.removeAttrs(IRP, Attribute::Writable);
7997 const std::string getAsStr(Attributor *
A)
const override {
8002 if (isAssumedWriteOnly())
8004 return "may-read/write";
8008 static const Attribute::AttrKind AttrKinds[3];
8012 Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};
8015struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {
8016 AAMemoryBehaviorFloating(
const IRPosition &IRP, Attributor &
A)
8017 : AAMemoryBehaviorImpl(IRP,
A) {}
8023 void trackStatistics()
const override {
8028 else if (isAssumedWriteOnly())
8035 bool followUsersOfUseIn(Attributor &
A,
const Use &U,
8036 const Instruction *UserI);
8039 void analyzeUseIn(Attributor &
A,
const Use &U,
const Instruction *UserI);
8043struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
8044 AAMemoryBehaviorArgument(
const IRPosition &IRP, Attributor &
A)
8045 : AAMemoryBehaviorFloating(IRP,
A) {}
8049 intersectAssumedBits(BEST_STATE);
8050 const IRPosition &IRP = getIRPosition();
8054 bool HasByVal =
A.hasAttr(IRP, {Attribute::ByVal},
8056 getKnownStateFromValue(
A, IRP, getState(),
8063 return ChangeStatus::UNCHANGED;
8067 if (
A.hasAttr(getIRPosition(),
8068 {Attribute::InAlloca, Attribute::Preallocated})) {
8069 removeKnownBits(NO_WRITES);
8070 removeAssumedBits(NO_WRITES);
8072 A.removeAttrs(getIRPosition(), AttrKinds);
8073 return AAMemoryBehaviorFloating::manifest(
A);
8077 void trackStatistics()
const override {
8082 else if (isAssumedWriteOnly())
8087struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {
8088 AAMemoryBehaviorCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
8089 : AAMemoryBehaviorArgument(IRP,
A) {}
8095 Argument *Arg = getAssociatedArgument();
8097 indicatePessimisticFixpoint();
8101 addKnownBits(NO_WRITES);
8102 removeKnownBits(NO_READS);
8103 removeAssumedBits(NO_READS);
8105 AAMemoryBehaviorArgument::initialize(
A);
8106 if (getAssociatedFunction()->isDeclaration())
8107 indicatePessimisticFixpoint();
8116 Argument *Arg = getAssociatedArgument();
8119 A.getAAFor<AAMemoryBehavior>(*
this, ArgPos, DepClassTy::REQUIRED);
8121 return indicatePessimisticFixpoint();
8126 void trackStatistics()
const override {
8131 else if (isAssumedWriteOnly())
8137struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {
8138 AAMemoryBehaviorCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
8139 : AAMemoryBehaviorFloating(IRP,
A) {}
8143 AAMemoryBehaviorImpl::initialize(
A);
8148 return ChangeStatus::UNCHANGED;
8152 void trackStatistics()
const override {}
8156struct AAMemoryBehaviorFunction final :
public AAMemoryBehaviorImpl {
8157 AAMemoryBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
8158 : AAMemoryBehaviorImpl(IRP,
A) {}
8174 else if (isAssumedWriteOnly())
8177 A.removeAttrs(getIRPosition(), AttrKinds);
8180 for (Argument &Arg :
F.args())
8182 return A.manifestAttrs(getIRPosition(),
8183 Attribute::getWithMemoryEffects(
F.getContext(), ME));
8187 void trackStatistics()
const override {
8192 else if (isAssumedWriteOnly())
8198struct AAMemoryBehaviorCallSite final
8199 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl> {
8200 AAMemoryBehaviorCallSite(
const IRPosition &IRP, Attributor &
A)
8201 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl>(IRP,
A) {}
8212 else if (isAssumedWriteOnly())
8215 A.removeAttrs(getIRPosition(), AttrKinds);
8218 for (Use &U : CB.
args())
8220 Attribute::Writable);
8221 return A.manifestAttrs(
8222 getIRPosition(), Attribute::getWithMemoryEffects(CB.
getContext(), ME));
8226 void trackStatistics()
const override {
8231 else if (isAssumedWriteOnly())
8236ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &
A) {
8239 auto AssumedState = getAssumed();
8246 const auto *MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
8248 if (MemBehaviorAA) {
8249 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8250 return !isAtFixpoint();
8255 if (
I.mayReadFromMemory())
8256 removeAssumedBits(NO_READS);
8257 if (
I.mayWriteToMemory())
8258 removeAssumedBits(NO_WRITES);
8259 return !isAtFixpoint();
8262 bool UsedAssumedInformation =
false;
8263 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8264 UsedAssumedInformation))
8265 return indicatePessimisticFixpoint();
8271ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &
A) {
8273 const IRPosition &IRP = getIRPosition();
8284 const auto *FnMemAA =
8287 FnMemAssumedState = FnMemAA->getAssumed();
8288 S.addKnownBits(FnMemAA->getKnown());
8289 if ((S.getAssumed() & FnMemAA->getAssumed()) == S.getAssumed())
8295 auto AssumedState = S.getAssumed();
8301 bool IsKnownNoCapture;
8302 const AANoCapture *ArgNoCaptureAA =
nullptr;
8307 if (!IsAssumedNoCapture &&
8309 S.intersectAssumedBits(FnMemAssumedState);
8315 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
8317 LLVM_DEBUG(
dbgs() <<
"[AAMemoryBehavior] Use: " << *U <<
" in " << *UserI
8325 Follow = followUsersOfUseIn(
A, U, UserI);
8329 analyzeUseIn(
A, U, UserI);
8331 return !isAtFixpoint();
8334 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue()))
8335 return indicatePessimisticFixpoint();
8341bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &
A,
const Use &U,
8342 const Instruction *UserI) {
8360 if (
U.get()->getType()->isPointerTy()) {
8362 bool IsKnownNoCapture;
8371void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &
A,
const Use &U,
8372 const Instruction *UserI) {
8379 case Instruction::Load:
8381 removeAssumedBits(NO_READS);
8384 case Instruction::Store:
8389 removeAssumedBits(NO_WRITES);
8391 indicatePessimisticFixpoint();
8394 case Instruction::Call:
8395 case Instruction::CallBr:
8396 case Instruction::Invoke: {
8403 indicatePessimisticFixpoint();
8410 removeAssumedBits(NO_READS);
8417 if (
U.get()->getType()->isPointerTy())
8421 const auto *MemBehaviorAA =
8427 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8435 removeAssumedBits(NO_READS);
8437 removeAssumedBits(NO_WRITES);
8449 return "all memory";
8452 std::string S =
"memory:";
8458 S +=
"internal global,";
8460 S +=
"external global,";
8464 S +=
"inaccessible,";
8478 AccessKind2Accesses.fill(
nullptr);
8481 ~AAMemoryLocationImpl()
override {
8484 for (AccessSet *AS : AccessKind2Accesses)
8491 intersectAssumedBits(BEST_STATE);
8492 getKnownStateFromValue(
A, getIRPosition(), getState());
8493 AAMemoryLocation::initialize(
A);
8497 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
8498 BitIntegerState &State,
8499 bool IgnoreSubsumingPositions =
false) {
8508 bool UseArgMemOnly =
true;
8510 if (AnchorFn &&
A.isRunOn(*AnchorFn))
8514 A.getAttrs(IRP, {Attribute::Memory},
Attrs, IgnoreSubsumingPositions);
8523 State.
addKnownBits(inverseLocation(NO_INACCESSIBLE_MEM,
true,
true));
8528 State.
addKnownBits(inverseLocation(NO_ARGUMENT_MEM,
true,
true));
8532 A.manifestAttrs(IRP,
8533 Attribute::getWithMemoryEffects(
8542 NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM,
true,
true));
8546 A.manifestAttrs(IRP,
8547 Attribute::getWithMemoryEffects(
8557 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
8558 SmallVectorImpl<Attribute> &Attrs)
const override {
8565 else if (isAssumedInaccessibleMemOnly())
8566 Attrs.push_back(Attribute::getWithMemoryEffects(
8568 else if (isAssumedArgMemOnly())
8571 else if (isAssumedInaccessibleOrArgMemOnly())
8572 Attrs.push_back(Attribute::getWithMemoryEffects(
8582 const IRPosition &IRP = getIRPosition();
8586 if (DeducedAttrs.
size() != 1)
8587 return ChangeStatus::UNCHANGED;
8590 return A.manifestAttrs(IRP, Attribute::getWithMemoryEffects(
8595 bool checkForAllAccessesToMemoryKind(
8597 MemoryLocationsKind)>
8599 MemoryLocationsKind RequestedMLK)
const override {
8600 if (!isValidState())
8603 MemoryLocationsKind AssumedMLK = getAssumedNotAccessedLocation();
8604 if (AssumedMLK == NO_LOCATIONS)
8608 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS;
8609 CurMLK *= 2, ++Idx) {
8610 if (CurMLK & RequestedMLK)
8613 if (
const AccessSet *
Accesses = AccessKind2Accesses[Idx])
8614 for (
const AccessInfo &AI : *
Accesses)
8615 if (!Pred(AI.I, AI.Ptr, AI.Kind, CurMLK))
8628 MemoryLocationsKind KnownMLK = getKnown();
8630 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2)
8631 if (!(CurMLK & KnownMLK))
8632 updateStateAndAccessesMap(getState(), CurMLK,
I,
nullptr,
Changed,
8633 getAccessKindFromInst(
I));
8634 return AAMemoryLocation::indicatePessimisticFixpoint();
8654 bool operator()(
const AccessInfo &
LHS,
const AccessInfo &
RHS)
const {
8658 return LHS.Ptr <
RHS.Ptr;
8659 if (
LHS.Kind !=
RHS.Kind)
8660 return LHS.Kind <
RHS.Kind;
8667 using AccessSet = SmallSet<AccessInfo, 2, AccessInfo>;
8668 std::array<AccessSet *, llvm::ConstantLog2<VALID_STATE>()>
8669 AccessKind2Accesses;
8674 categorizeArgumentPointerLocations(Attributor &
A, CallBase &CB,
8675 AAMemoryLocation::StateType &AccessedLocs,
8680 categorizeAccessedLocations(Attributor &
A, Instruction &
I,
bool &
Changed);
8683 AccessKind getAccessKindFromInst(
const Instruction *
I) {
8686 AK =
I->mayReadFromMemory() ? READ :
NONE;
8695 void updateStateAndAccessesMap(AAMemoryLocation::StateType &State,
8696 MemoryLocationsKind MLK,
const Instruction *
I,
8705 if (MLK == NO_UNKOWN_MEM)
8707 State.removeAssumedBits(MLK);
8712 void categorizePtrValue(Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8713 AAMemoryLocation::StateType &State,
bool &
Changed,
8714 unsigned AccessAS = 0);
8720void AAMemoryLocationImpl::categorizePtrValue(
8721 Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8723 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize pointer locations for "
8728 unsigned ObjectAS =
Obj.getType()->getPointerAddressSpace();
8730 MemoryLocationsKind MLK = NO_LOCATIONS;
8750 MLK = NO_ARGUMENT_MEM;
8756 if (GVar->isConstant())
8759 if (GV->hasLocalLinkage())
8760 MLK = NO_GLOBAL_INTERNAL_MEM;
8762 MLK = NO_GLOBAL_EXTERNAL_MEM;
8770 bool IsKnownNoAlias;
8774 MLK = NO_MALLOCED_MEM;
8776 MLK = NO_UNKOWN_MEM;
8778 MLK = NO_UNKOWN_MEM;
8781 assert(MLK != NO_LOCATIONS &&
"No location specified!");
8782 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Ptr value can be categorized: "
8783 << Obj <<
" -> " << getMemoryLocationsAsStr(MLK) <<
"\n");
8785 getAccessKindFromInst(&
I));
8790 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
8794 dbgs() <<
"[AAMemoryLocation] Pointer locations not categorized\n");
8795 updateStateAndAccessesMap(
State, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8796 getAccessKindFromInst(&
I));
8801 dbgs() <<
"[AAMemoryLocation] Accessed locations with pointer locations: "
8805void AAMemoryLocationImpl::categorizeArgumentPointerLocations(
8808 for (
unsigned ArgNo = 0,
E = CB.
arg_size(); ArgNo <
E; ++ArgNo) {
8817 const auto *ArgOpMemLocationAA =
8820 if (ArgOpMemLocationAA && ArgOpMemLocationAA->isAssumedReadNone())
8825 categorizePtrValue(
A, CB, *ArgOp, AccessedLocs,
Changed);
8830AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &
A, Instruction &
I,
8832 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize accessed locations for "
8836 AccessedLocs.intersectAssumedBits(NO_LOCATIONS);
8841 const auto *CBMemLocationAA =
A.getAAFor<AAMemoryLocation>(
8844 <<
" [" << CBMemLocationAA <<
"]\n");
8845 if (!CBMemLocationAA) {
8846 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
8847 Changed, getAccessKindFromInst(&
I));
8848 return NO_UNKOWN_MEM;
8851 if (CBMemLocationAA->isAssumedReadNone())
8852 return NO_LOCATIONS;
8854 if (CBMemLocationAA->isAssumedInaccessibleMemOnly()) {
8855 updateStateAndAccessesMap(AccessedLocs, NO_INACCESSIBLE_MEM, &
I,
nullptr,
8856 Changed, getAccessKindFromInst(&
I));
8857 return AccessedLocs.getAssumed();
8860 uint32_t CBAssumedNotAccessedLocs =
8861 CBMemLocationAA->getAssumedNotAccessedLocation();
8864 uint32_t CBAssumedNotAccessedLocsNoArgMem =
8865 CBAssumedNotAccessedLocs | NO_ARGUMENT_MEM | NO_GLOBAL_MEM;
8867 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2) {
8868 if (CBAssumedNotAccessedLocsNoArgMem & CurMLK)
8870 updateStateAndAccessesMap(AccessedLocs, CurMLK, &
I,
nullptr,
Changed,
8871 getAccessKindFromInst(&
I));
8876 bool HasGlobalAccesses = ((~CBAssumedNotAccessedLocs) & NO_GLOBAL_MEM);
8877 if (HasGlobalAccesses) {
8880 updateStateAndAccessesMap(AccessedLocs, MLK, &
I, Ptr,
Changed,
8881 getAccessKindFromInst(&
I));
8884 if (!CBMemLocationAA->checkForAllAccessesToMemoryKind(
8885 AccessPred, inverseLocation(NO_GLOBAL_MEM,
false,
false)))
8886 return AccessedLocs.getWorstState();
8890 dbgs() <<
"[AAMemoryLocation] Accessed state before argument handling: "
8891 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8894 bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM);
8896 categorizeArgumentPointerLocations(
A, *CB, AccessedLocs,
Changed);
8899 dbgs() <<
"[AAMemoryLocation] Accessed state after argument handling: "
8900 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8902 return AccessedLocs.getAssumed();
8907 dbgs() <<
"[AAMemoryLocation] Categorize memory access with pointer: "
8908 <<
I <<
" [" << *Ptr <<
"]\n");
8909 categorizePtrValue(
A,
I, *Ptr, AccessedLocs,
Changed,
8910 Ptr->getType()->getPointerAddressSpace());
8911 return AccessedLocs.getAssumed();
8914 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Failed to categorize instruction: "
8916 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8917 getAccessKindFromInst(&
I));
8918 return AccessedLocs.getAssumed();
8922struct AAMemoryLocationFunction final :
public AAMemoryLocationImpl {
8923 AAMemoryLocationFunction(
const IRPosition &IRP, Attributor &
A)
8924 : AAMemoryLocationImpl(IRP,
A) {}
8929 const auto *MemBehaviorAA =
8930 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
8933 return indicateOptimisticFixpoint();
8935 "AAMemoryLocation was not read-none but AAMemoryBehavior was!");
8936 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
8937 return ChangeStatus::UNCHANGED;
8941 auto AssumedState = getAssumed();
8945 MemoryLocationsKind MLK = categorizeAccessedLocations(
A,
I,
Changed);
8946 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Accessed locations for " <<
I
8947 <<
": " << getMemoryLocationsAsStr(MLK) <<
"\n");
8948 removeAssumedBits(inverseLocation(MLK,
false,
false));
8951 return getAssumedNotAccessedLocation() != VALID_STATE;
8954 bool UsedAssumedInformation =
false;
8955 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8956 UsedAssumedInformation))
8957 return indicatePessimisticFixpoint();
8959 Changed |= AssumedState != getAssumed();
8960 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8964 void trackStatistics()
const override {
8967 else if (isAssumedArgMemOnly())
8969 else if (isAssumedInaccessibleMemOnly())
8971 else if (isAssumedInaccessibleOrArgMemOnly())
8977struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {
8978 AAMemoryLocationCallSite(
const IRPosition &IRP, Attributor &
A)
8979 : AAMemoryLocationImpl(IRP,
A) {}
8990 A.getAAFor<AAMemoryLocation>(*
this, FnPos, DepClassTy::REQUIRED);
8992 return indicatePessimisticFixpoint();
8996 updateStateAndAccessesMap(getState(), MLK,
I, Ptr,
Changed,
8997 getAccessKindFromInst(
I));
9000 if (!FnAA->checkForAllAccessesToMemoryKind(AccessPred, ALL_LOCATIONS))
9001 return indicatePessimisticFixpoint();
9002 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
9006 void trackStatistics()
const override {
9016struct AADenormalFPMathImpl :
public AADenormalFPMath {
9017 AADenormalFPMathImpl(
const IRPosition &IRP, Attributor &
A)
9018 : AADenormalFPMath(IRP,
A) {}
9020 const std::string getAsStr(Attributor *
A)
const override {
9021 std::string Str(
"AADenormalFPMath[");
9022 raw_string_ostream OS(Str);
9024 DenormalState Known = getKnown();
9025 if (Known.Mode.isValid())
9026 OS <<
"denormal-fp-math=" << Known.Mode;
9030 if (Known.ModeF32.isValid())
9031 OS <<
" denormal-fp-math-f32=" << Known.ModeF32;
9037struct AADenormalFPMathFunction final : AADenormalFPMathImpl {
9038 AADenormalFPMathFunction(
const IRPosition &IRP, Attributor &
A)
9039 : AADenormalFPMathImpl(IRP,
A) {}
9043 DenormalFPEnv DenormEnv =
F->getDenormalFPEnv();
9053 auto CheckCallSite = [=, &Change, &
A](AbstractCallSite CS) {
9056 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
9058 const auto *CallerInfo =
A.getAAFor<AADenormalFPMath>(
9064 CallerInfo->getState());
9068 bool AllCallSitesKnown =
true;
9069 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
9070 return indicatePessimisticFixpoint();
9072 if (Change == ChangeStatus::CHANGED && isModeFixed())
9078 LLVMContext &Ctx = getAssociatedFunction()->getContext();
9084 DenormalFPEnv KnownEnv(Known.Mode, Known.ModeF32);
9087 AttrToRemove.
push_back(Attribute::DenormalFPEnv);
9090 Ctx, Attribute::DenormalFPEnv,
9091 DenormalFPEnv(Known.Mode, Known.ModeF32).toIntValue()));
9094 auto &IRP = getIRPosition();
9097 return A.removeAttrs(IRP, AttrToRemove) |
9098 A.manifestAttrs(IRP, AttrToAdd,
true);
9101 void trackStatistics()
const override {
9110struct AAValueConstantRangeImpl : AAValueConstantRange {
9111 using StateType = IntegerRangeState;
9112 AAValueConstantRangeImpl(
const IRPosition &IRP, Attributor &
A)
9113 : AAValueConstantRange(IRP,
A) {}
9117 if (
A.hasSimplificationCallback(getIRPosition())) {
9118 indicatePessimisticFixpoint();
9123 intersectKnown(getConstantRangeFromSCEV(
A, getCtxI()));
9126 intersectKnown(getConstantRangeFromLVI(
A, getCtxI()));
9130 const std::string getAsStr(Attributor *
A)
const override {
9132 llvm::raw_string_ostream OS(Str);
9134 getKnown().print(OS);
9136 getAssumed().print(OS);
9143 const SCEV *getSCEV(Attributor &
A,
const Instruction *
I =
nullptr)
const {
9144 if (!getAnchorScope())
9147 ScalarEvolution *SE =
9148 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9151 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
9157 const SCEV *S = SE->
getSCEV(&getAssociatedValue());
9166 ConstantRange getConstantRangeFromSCEV(Attributor &
A,
9167 const Instruction *
I =
nullptr)
const {
9168 if (!getAnchorScope())
9171 ScalarEvolution *SE =
9172 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9175 const SCEV *S = getSCEV(
A,
I);
9185 getConstantRangeFromLVI(Attributor &
A,
9186 const Instruction *CtxI =
nullptr)
const {
9187 if (!getAnchorScope())
9190 LazyValueInfo *LVI =
9191 A.getInfoCache().getAnalysisResultForFunction<LazyValueAnalysis>(
9206 bool isValidCtxInstructionForOutsideAnalysis(Attributor &
A,
9207 const Instruction *CtxI,
9208 bool AllowAACtxI)
const {
9209 if (!CtxI || (!AllowAACtxI && CtxI == getCtxI()))
9221 InformationCache &InfoCache =
A.getInfoCache();
9222 const DominatorTree *DT =
9233 getKnownConstantRange(Attributor &
A,
9234 const Instruction *CtxI =
nullptr)
const override {
9235 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9239 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9240 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9241 return getKnown().intersectWith(SCEVR).intersectWith(LVIR);
9246 getAssumedConstantRange(Attributor &
A,
9247 const Instruction *CtxI =
nullptr)
const override {
9252 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9254 return getAssumed();
9256 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9257 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9258 return getAssumed().intersectWith(SCEVR).intersectWith(LVIR);
9263 getMDNodeForConstantRange(
Type *Ty, LLVMContext &Ctx,
9264 const ConstantRange &AssumedConstantRange) {
9266 Ty, AssumedConstantRange.
getLower())),
9268 Ty, AssumedConstantRange.
getUpper()))};
9273 static bool isBetterRange(
const ConstantRange &Assumed,
9274 const Instruction &
I) {
9278 std::optional<ConstantRange> Known;
9282 }
else if (MDNode *KnownRanges =
I.getMetadata(LLVMContext::MD_range)) {
9288 if (KnownRanges->getNumOperands() > 2)
9291 ConstantInt *
Lower =
9293 ConstantInt *
Upper =
9296 Known.emplace(
Lower->getValue(),
Upper->getValue());
9298 return !Known || (*Known != Assumed && Known->contains(Assumed));
9303 setRangeMetadataIfisBetterRange(Instruction *
I,
9304 const ConstantRange &AssumedConstantRange) {
9305 if (isBetterRange(AssumedConstantRange, *
I)) {
9306 I->setMetadata(LLVMContext::MD_range,
9307 getMDNodeForConstantRange(
I->getType(),
I->getContext(),
9308 AssumedConstantRange));
9315 setRangeRetAttrIfisBetterRange(Attributor &
A,
const IRPosition &IRP,
9317 const ConstantRange &AssumedConstantRange) {
9318 if (isBetterRange(AssumedConstantRange, *
I)) {
9319 A.manifestAttrs(IRP,
9320 Attribute::get(
I->getContext(), Attribute::Range,
9321 AssumedConstantRange),
9331 ConstantRange AssumedConstantRange = getAssumedConstantRange(
A);
9334 auto &
V = getAssociatedValue();
9338 assert(
I == getCtxI() &&
"Should not annotate an instruction which is "
9339 "not the context instruction");
9341 if (setRangeMetadataIfisBetterRange(
I, AssumedConstantRange))
9342 Changed = ChangeStatus::CHANGED;
9344 if (setRangeRetAttrIfisBetterRange(
A, getIRPosition(),
I,
9345 AssumedConstantRange))
9346 Changed = ChangeStatus::CHANGED;
9354struct AAValueConstantRangeArgument final
9355 : AAArgumentFromCallSiteArguments<
9356 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9358 using Base = AAArgumentFromCallSiteArguments<
9359 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9361 AAValueConstantRangeArgument(
const IRPosition &IRP, Attributor &
A)
9365 void trackStatistics()
const override {
9370struct AAValueConstantRangeReturned
9371 : AAReturnedFromReturnedValues<AAValueConstantRange,
9372 AAValueConstantRangeImpl,
9373 AAValueConstantRangeImpl::StateType,
9376 AAReturnedFromReturnedValues<AAValueConstantRange,
9377 AAValueConstantRangeImpl,
9378 AAValueConstantRangeImpl::StateType,
9380 AAValueConstantRangeReturned(
const IRPosition &IRP, Attributor &
A)
9385 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9386 indicatePessimisticFixpoint();
9390 void trackStatistics()
const override {
9395struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
9396 AAValueConstantRangeFloating(
const IRPosition &IRP, Attributor &
A)
9397 : AAValueConstantRangeImpl(IRP,
A) {}
9401 AAValueConstantRangeImpl::initialize(
A);
9405 Value &
V = getAssociatedValue();
9408 unionAssumed(ConstantRange(
C->getValue()));
9409 indicateOptimisticFixpoint();
9415 unionAssumed(ConstantRange(APInt(
getBitWidth(), 0)));
9416 indicateOptimisticFixpoint();
9428 if (
auto *RangeMD = LI->getMetadata(LLVMContext::MD_range)) {
9439 indicatePessimisticFixpoint();
9442 << getAssociatedValue() <<
"\n");
9445 bool calculateBinaryOperator(
9446 Attributor &
A, BinaryOperator *BinOp, IntegerRangeState &
T,
9447 const Instruction *CtxI,
9448 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9453 bool UsedAssumedInformation =
false;
9454 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9457 if (!SimplifiedLHS.has_value())
9459 if (!*SimplifiedLHS)
9461 LHS = *SimplifiedLHS;
9463 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9466 if (!SimplifiedRHS.has_value())
9468 if (!*SimplifiedRHS)
9470 RHS = *SimplifiedRHS;
9476 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9478 DepClassTy::REQUIRED);
9482 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9484 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9486 DepClassTy::REQUIRED);
9490 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9492 auto AssumedRange = LHSAARange.binaryOp(BinOp->
getOpcode(), RHSAARange);
9494 T.unionAssumed(AssumedRange);
9498 return T.isValidState();
9501 bool calculateCastInst(
9502 Attributor &
A, CastInst *CastI, IntegerRangeState &
T,
9503 const Instruction *CtxI,
9504 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9510 bool UsedAssumedInformation =
false;
9511 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9514 if (!SimplifiedOpV.has_value())
9516 if (!*SimplifiedOpV)
9518 OpV = *SimplifiedOpV;
9523 auto *OpAA =
A.getAAFor<AAValueConstantRange>(
9525 DepClassTy::REQUIRED);
9529 T.unionAssumed(OpAA->getAssumed().castOp(CastI->
getOpcode(),
9531 return T.isValidState();
9535 calculateCmpInst(Attributor &
A, CmpInst *CmpI, IntegerRangeState &
T,
9536 const Instruction *CtxI,
9537 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9542 bool UsedAssumedInformation =
false;
9543 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9546 if (!SimplifiedLHS.has_value())
9548 if (!*SimplifiedLHS)
9550 LHS = *SimplifiedLHS;
9552 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9555 if (!SimplifiedRHS.has_value())
9557 if (!*SimplifiedRHS)
9559 RHS = *SimplifiedRHS;
9565 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9567 DepClassTy::REQUIRED);
9571 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9573 DepClassTy::REQUIRED);
9577 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9578 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9581 if (LHSAARange.isEmptySet() || RHSAARange.isEmptySet())
9584 bool MustTrue =
false, MustFalse =
false;
9586 auto AllowedRegion =
9589 if (AllowedRegion.intersectWith(LHSAARange).isEmptySet())
9595 assert((!MustTrue || !MustFalse) &&
9596 "Either MustTrue or MustFalse should be false!");
9599 T.unionAssumed(ConstantRange(APInt( 1, 1)));
9601 T.unionAssumed(ConstantRange(APInt( 1, 0)));
9603 T.unionAssumed(ConstantRange( 1,
true));
9605 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] " << *CmpI <<
" after "
9606 << (MustTrue ?
"true" : (MustFalse ?
"false" :
"unknown"))
9607 <<
": " <<
T <<
"\n\t" << *LHSAA <<
"\t<op>\n\t"
9611 return T.isValidState();
9623 bool UsedAssumedInformation =
false;
9624 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9627 if (!SimplifiedOpV.has_value())
9629 if (!*SimplifiedOpV)
9631 Value *VPtr = *SimplifiedOpV;
9634 const auto *AA =
A.getAAFor<AAValueConstantRange>(
9636 DepClassTy::REQUIRED);
9640 T.unionAssumed(AA->getAssumedConstantRange(
A, CtxI));
9644 return T.isValidState();
9649 if (!calculateBinaryOperator(
A, BinOp,
T, CtxI, QuerriedAAs))
9652 if (!calculateCmpInst(
A, CmpI,
T, CtxI, QuerriedAAs))
9655 if (!calculateCastInst(
A, CastI,
T, CtxI, QuerriedAAs))
9661 T.indicatePessimisticFixpoint();
9668 for (
const AAValueConstantRange *QueriedAA : QuerriedAAs) {
9669 if (QueriedAA !=
this)
9672 if (
T.getAssumed() == getState().getAssumed())
9674 T.indicatePessimisticFixpoint();
9677 return T.isValidState();
9680 if (!VisitValueCB(getAssociatedValue(), getCtxI()))
9681 return indicatePessimisticFixpoint();
9686 return ChangeStatus::UNCHANGED;
9687 if (++NumChanges > MaxNumChanges) {
9688 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] performed " << NumChanges
9689 <<
" but only " << MaxNumChanges
9690 <<
" are allowed to avoid cyclic reasoning.");
9691 return indicatePessimisticFixpoint();
9693 return ChangeStatus::CHANGED;
9697 void trackStatistics()
const override {
9706 static constexpr int MaxNumChanges = 5;
9709struct AAValueConstantRangeFunction : AAValueConstantRangeImpl {
9710 AAValueConstantRangeFunction(
const IRPosition &IRP, Attributor &
A)
9711 : AAValueConstantRangeImpl(IRP,
A) {}
9715 llvm_unreachable(
"AAValueConstantRange(Function|CallSite)::updateImpl will "
9723struct AAValueConstantRangeCallSite : AAValueConstantRangeFunction {
9724 AAValueConstantRangeCallSite(
const IRPosition &IRP, Attributor &
A)
9725 : AAValueConstantRangeFunction(IRP,
A) {}
9731struct AAValueConstantRangeCallSiteReturned
9732 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9733 AAValueConstantRangeImpl::StateType,
9735 AAValueConstantRangeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
9736 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9737 AAValueConstantRangeImpl::StateType,
9744 if (std::optional<ConstantRange>
Range = CI->getRange())
9745 intersectKnown(*
Range);
9748 AAValueConstantRangeImpl::initialize(
A);
9752 void trackStatistics()
const override {
9756struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating {
9757 AAValueConstantRangeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
9758 : AAValueConstantRangeFloating(IRP,
A) {}
9762 return ChangeStatus::UNCHANGED;
9766 void trackStatistics()
const override {
9775struct AAPotentialConstantValuesImpl : AAPotentialConstantValues {
9778 AAPotentialConstantValuesImpl(
const IRPosition &IRP, Attributor &
A)
9779 : AAPotentialConstantValues(IRP,
A) {}
9783 if (
A.hasSimplificationCallback(getIRPosition()))
9784 indicatePessimisticFixpoint();
9786 AAPotentialConstantValues::initialize(
A);
9789 bool fillSetWithConstantValues(Attributor &
A,
const IRPosition &IRP, SetTy &S,
9790 bool &ContainsUndef,
bool ForSelf) {
9792 bool UsedAssumedInformation =
false;
9794 UsedAssumedInformation)) {
9801 auto *PotentialValuesAA =
A.getAAFor<AAPotentialConstantValues>(
9802 *
this, IRP, DepClassTy::REQUIRED);
9803 if (!PotentialValuesAA || !PotentialValuesAA->getState().isValidState())
9805 ContainsUndef = PotentialValuesAA->getState().undefIsContained();
9806 S = PotentialValuesAA->getState().getAssumedSet();
9813 ContainsUndef =
false;
9814 for (
auto &It : Values) {
9816 ContainsUndef =
true;
9822 S.insert(CI->getValue());
9824 ContainsUndef &= S.empty();
9830 const std::string getAsStr(Attributor *
A)
const override {
9832 llvm::raw_string_ostream OS(Str);
9839 return indicatePessimisticFixpoint();
9843struct AAPotentialConstantValuesArgument final
9844 : AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9845 AAPotentialConstantValuesImpl,
9846 PotentialConstantIntValuesState> {
9847 using Base = AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9848 AAPotentialConstantValuesImpl,
9850 AAPotentialConstantValuesArgument(
const IRPosition &IRP, Attributor &
A)
9854 void trackStatistics()
const override {
9859struct AAPotentialConstantValuesReturned
9860 : AAReturnedFromReturnedValues<AAPotentialConstantValues,
9861 AAPotentialConstantValuesImpl> {
9862 using Base = AAReturnedFromReturnedValues<AAPotentialConstantValues,
9863 AAPotentialConstantValuesImpl>;
9864 AAPotentialConstantValuesReturned(
const IRPosition &IRP, Attributor &
A)
9868 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9869 indicatePessimisticFixpoint();
9870 Base::initialize(
A);
9874 void trackStatistics()
const override {
9879struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl {
9880 AAPotentialConstantValuesFloating(
const IRPosition &IRP, Attributor &
A)
9881 : AAPotentialConstantValuesImpl(IRP,
A) {}
9885 AAPotentialConstantValuesImpl::initialize(
A);
9889 Value &
V = getAssociatedValue();
9892 unionAssumed(
C->getValue());
9893 indicateOptimisticFixpoint();
9898 unionAssumedWithUndef();
9899 indicateOptimisticFixpoint();
9909 indicatePessimisticFixpoint();
9912 << getAssociatedValue() <<
"\n");
9915 static bool calculateICmpInst(
const ICmpInst *ICI,
const APInt &
LHS,
9920 static APInt calculateCastInst(
const CastInst *CI,
const APInt &Src,
9921 uint32_t ResultBitWidth) {
9926 case Instruction::Trunc:
9927 return Src.trunc(ResultBitWidth);
9928 case Instruction::SExt:
9929 return Src.sext(ResultBitWidth);
9930 case Instruction::ZExt:
9931 return Src.zext(ResultBitWidth);
9932 case Instruction::BitCast:
9937 static APInt calculateBinaryOperator(
const BinaryOperator *BinOp,
9938 const APInt &
LHS,
const APInt &
RHS,
9939 bool &SkipOperation,
bool &Unsupported) {
9946 switch (BinOpcode) {
9950 case Instruction::Add:
9952 case Instruction::Sub:
9954 case Instruction::Mul:
9956 case Instruction::UDiv:
9958 SkipOperation =
true;
9962 case Instruction::SDiv:
9964 SkipOperation =
true;
9968 case Instruction::URem:
9970 SkipOperation =
true;
9974 case Instruction::SRem:
9976 SkipOperation =
true;
9980 case Instruction::Shl:
9982 case Instruction::LShr:
9984 case Instruction::AShr:
9986 case Instruction::And:
9988 case Instruction::Or:
9990 case Instruction::Xor:
9995 bool calculateBinaryOperatorAndTakeUnion(
const BinaryOperator *BinOp,
9996 const APInt &
LHS,
const APInt &
RHS) {
9997 bool SkipOperation =
false;
10000 calculateBinaryOperator(BinOp,
LHS,
RHS, SkipOperation, Unsupported);
10004 if (!SkipOperation)
10005 unionAssumed(Result);
10006 return isValidState();
10009 ChangeStatus updateWithICmpInst(Attributor &
A, ICmpInst *ICI) {
10010 auto AssumedBefore = getAssumed();
10014 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10015 SetTy LHSAAPVS, RHSAAPVS;
10017 LHSContainsUndef,
false) ||
10019 RHSContainsUndef,
false))
10020 return indicatePessimisticFixpoint();
10023 bool MaybeTrue =
false, MaybeFalse =
false;
10025 if (LHSContainsUndef && RHSContainsUndef) {
10028 unionAssumedWithUndef();
10029 }
else if (LHSContainsUndef) {
10030 for (
const APInt &R : RHSAAPVS) {
10031 bool CmpResult = calculateICmpInst(ICI, Zero, R);
10032 MaybeTrue |= CmpResult;
10033 MaybeFalse |= !CmpResult;
10034 if (MaybeTrue & MaybeFalse)
10035 return indicatePessimisticFixpoint();
10037 }
else if (RHSContainsUndef) {
10038 for (
const APInt &L : LHSAAPVS) {
10039 bool CmpResult = calculateICmpInst(ICI, L, Zero);
10040 MaybeTrue |= CmpResult;
10041 MaybeFalse |= !CmpResult;
10042 if (MaybeTrue & MaybeFalse)
10043 return indicatePessimisticFixpoint();
10046 for (
const APInt &L : LHSAAPVS) {
10047 for (
const APInt &R : RHSAAPVS) {
10048 bool CmpResult = calculateICmpInst(ICI, L, R);
10049 MaybeTrue |= CmpResult;
10050 MaybeFalse |= !CmpResult;
10051 if (MaybeTrue & MaybeFalse)
10052 return indicatePessimisticFixpoint();
10057 unionAssumed(APInt( 1, 1));
10059 unionAssumed(APInt( 1, 0));
10060 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10061 : ChangeStatus::CHANGED;
10064 ChangeStatus updateWithSelectInst(Attributor &
A, SelectInst *SI) {
10065 auto AssumedBefore = getAssumed();
10069 bool UsedAssumedInformation =
false;
10070 std::optional<Constant *>
C =
A.getAssumedConstant(
10071 *
SI->getCondition(), *
this, UsedAssumedInformation);
10074 bool OnlyLeft =
false, OnlyRight =
false;
10075 if (
C && *
C && (*C)->isOneValue())
10077 else if (
C && *
C && (*C)->isNullValue())
10080 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10081 SetTy LHSAAPVS, RHSAAPVS;
10084 LHSContainsUndef,
false))
10085 return indicatePessimisticFixpoint();
10089 RHSContainsUndef,
false))
10090 return indicatePessimisticFixpoint();
10092 if (OnlyLeft || OnlyRight) {
10094 auto *OpAA = OnlyLeft ? &LHSAAPVS : &RHSAAPVS;
10095 auto Undef = OnlyLeft ? LHSContainsUndef : RHSContainsUndef;
10098 unionAssumedWithUndef();
10100 for (
const auto &It : *OpAA)
10104 }
else if (LHSContainsUndef && RHSContainsUndef) {
10106 unionAssumedWithUndef();
10108 for (
const auto &It : LHSAAPVS)
10110 for (
const auto &It : RHSAAPVS)
10113 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10114 : ChangeStatus::CHANGED;
10117 ChangeStatus updateWithCastInst(Attributor &
A, CastInst *CI) {
10118 auto AssumedBefore = getAssumed();
10120 return indicatePessimisticFixpoint();
10125 bool SrcContainsUndef =
false;
10128 SrcContainsUndef,
false))
10129 return indicatePessimisticFixpoint();
10131 if (SrcContainsUndef)
10132 unionAssumedWithUndef();
10134 for (
const APInt &S : SrcPVS) {
10135 APInt
T = calculateCastInst(CI, S, ResultBitWidth);
10139 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10140 : ChangeStatus::CHANGED;
10143 ChangeStatus updateWithBinaryOperator(Attributor &
A, BinaryOperator *BinOp) {
10144 auto AssumedBefore = getAssumed();
10148 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10149 SetTy LHSAAPVS, RHSAAPVS;
10151 LHSContainsUndef,
false) ||
10153 RHSContainsUndef,
false))
10154 return indicatePessimisticFixpoint();
10159 if (LHSContainsUndef && RHSContainsUndef) {
10160 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))
10161 return indicatePessimisticFixpoint();
10162 }
else if (LHSContainsUndef) {
10163 for (
const APInt &R : RHSAAPVS) {
10164 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))
10165 return indicatePessimisticFixpoint();
10167 }
else if (RHSContainsUndef) {
10168 for (
const APInt &L : LHSAAPVS) {
10169 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
10170 return indicatePessimisticFixpoint();
10173 for (
const APInt &L : LHSAAPVS) {
10174 for (
const APInt &R : RHSAAPVS) {
10175 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
10176 return indicatePessimisticFixpoint();
10180 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10181 : ChangeStatus::CHANGED;
10184 ChangeStatus updateWithInstruction(Attributor &
A, Instruction *Inst) {
10185 auto AssumedBefore = getAssumed();
10187 bool ContainsUndef;
10189 ContainsUndef,
true))
10190 return indicatePessimisticFixpoint();
10191 if (ContainsUndef) {
10192 unionAssumedWithUndef();
10194 for (
const auto &It : Incoming)
10197 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10198 : ChangeStatus::CHANGED;
10203 Value &
V = getAssociatedValue();
10207 return updateWithICmpInst(
A, ICI);
10210 return updateWithSelectInst(
A, SI);
10213 return updateWithCastInst(
A, CI);
10216 return updateWithBinaryOperator(
A, BinOp);
10219 return updateWithInstruction(
A,
I);
10221 return indicatePessimisticFixpoint();
10225 void trackStatistics()
const override {
10230struct AAPotentialConstantValuesFunction : AAPotentialConstantValuesImpl {
10231 AAPotentialConstantValuesFunction(
const IRPosition &IRP, Attributor &
A)
10232 : AAPotentialConstantValuesImpl(IRP,
A) {}
10237 "AAPotentialConstantValues(Function|CallSite)::updateImpl will "
10242 void trackStatistics()
const override {
10247struct AAPotentialConstantValuesCallSite : AAPotentialConstantValuesFunction {
10248 AAPotentialConstantValuesCallSite(
const IRPosition &IRP, Attributor &
A)
10249 : AAPotentialConstantValuesFunction(IRP,
A) {}
10252 void trackStatistics()
const override {
10257struct AAPotentialConstantValuesCallSiteReturned
10258 : AACalleeToCallSite<AAPotentialConstantValues,
10259 AAPotentialConstantValuesImpl> {
10260 AAPotentialConstantValuesCallSiteReturned(
const IRPosition &IRP,
10262 : AACalleeToCallSite<AAPotentialConstantValues,
10263 AAPotentialConstantValuesImpl>(IRP,
A) {}
10266 void trackStatistics()
const override {
10271struct AAPotentialConstantValuesCallSiteArgument
10272 : AAPotentialConstantValuesFloating {
10273 AAPotentialConstantValuesCallSiteArgument(
const IRPosition &IRP,
10275 : AAPotentialConstantValuesFloating(IRP,
A) {}
10279 AAPotentialConstantValuesImpl::initialize(
A);
10280 if (isAtFixpoint())
10283 Value &
V = getAssociatedValue();
10286 unionAssumed(
C->getValue());
10287 indicateOptimisticFixpoint();
10292 unionAssumedWithUndef();
10293 indicateOptimisticFixpoint();
10300 Value &
V = getAssociatedValue();
10301 auto AssumedBefore = getAssumed();
10302 auto *AA =
A.getAAFor<AAPotentialConstantValues>(
10305 return indicatePessimisticFixpoint();
10306 const auto &S = AA->getAssumed();
10308 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10309 : ChangeStatus::CHANGED;
10313 void trackStatistics()
const override {
10322 bool IgnoreSubsumingPositions) {
10323 assert(ImpliedAttributeKind == Attribute::NoUndef &&
10324 "Unexpected attribute kind");
10325 if (
A.hasAttr(IRP, {Attribute::NoUndef}, IgnoreSubsumingPositions,
10326 Attribute::NoUndef))
10346 Value &V = getAssociatedValue();
10348 indicatePessimisticFixpoint();
10349 assert(!isImpliedByIR(
A, getIRPosition(), Attribute::NoUndef));
10353 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10354 AANoUndef::StateType &State) {
10355 const Value *UseV =
U->get();
10356 const DominatorTree *DT =
nullptr;
10357 AssumptionCache *AC =
nullptr;
10358 InformationCache &InfoCache =
A.getInfoCache();
10359 if (Function *
F = getAnchorScope()) {
10364 bool TrackUse =
false;
10373 const std::string getAsStr(Attributor *
A)
const override {
10374 return getAssumed() ?
"noundef" :
"may-undef-or-poison";
10381 bool UsedAssumedInformation =
false;
10382 if (
A.isAssumedDead(getIRPosition(),
nullptr,
nullptr,
10383 UsedAssumedInformation))
10384 return ChangeStatus::UNCHANGED;
10388 if (!
A.getAssumedSimplified(getIRPosition(), *
this, UsedAssumedInformation,
10391 return ChangeStatus::UNCHANGED;
10392 return AANoUndef::manifest(
A);
10396struct AANoUndefFloating :
public AANoUndefImpl {
10397 AANoUndefFloating(
const IRPosition &IRP, Attributor &
A)
10398 : AANoUndefImpl(IRP,
A) {}
10402 AANoUndefImpl::initialize(
A);
10403 if (!getState().isAtFixpoint() && getAnchorScope() &&
10404 !getAnchorScope()->isDeclaration())
10405 if (Instruction *CtxI = getCtxI())
10406 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10411 auto VisitValueCB = [&](
const IRPosition &IRP) ->
bool {
10412 bool IsKnownNoUndef;
10414 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoUndef);
10418 bool UsedAssumedInformation =
false;
10419 Value *AssociatedValue = &getAssociatedValue();
10421 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10426 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
10434 if (AVIRP == getIRPosition() || !VisitValueCB(AVIRP))
10435 return indicatePessimisticFixpoint();
10436 return ChangeStatus::UNCHANGED;
10439 for (
const auto &VAC : Values)
10441 return indicatePessimisticFixpoint();
10443 return ChangeStatus::UNCHANGED;
10450struct AANoUndefReturned final
10451 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl> {
10452 AANoUndefReturned(
const IRPosition &IRP, Attributor &
A)
10453 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10459struct AANoUndefArgument final
10460 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl> {
10461 AANoUndefArgument(
const IRPosition &IRP, Attributor &
A)
10462 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10468struct AANoUndefCallSiteArgument final : AANoUndefFloating {
10469 AANoUndefCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10470 : AANoUndefFloating(IRP,
A) {}
10476struct AANoUndefCallSiteReturned final
10477 : AACalleeToCallSite<AANoUndef, AANoUndefImpl> {
10478 AANoUndefCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10479 : AACalleeToCallSite<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10487struct AANoFPClassImpl : AANoFPClass {
10488 AANoFPClassImpl(
const IRPosition &IRP, Attributor &
A) : AANoFPClass(IRP,
A) {}
10491 const IRPosition &IRP = getIRPosition();
10495 indicateOptimisticFixpoint();
10500 A.getAttrs(getIRPosition(), {Attribute::NoFPClass},
Attrs,
false);
10501 for (
const auto &Attr : Attrs) {
10508 const DataLayout &
DL =
A.getDataLayout();
10509 InformationCache &InfoCache =
A.getInfoCache();
10511 const DominatorTree *DT =
nullptr;
10512 AssumptionCache *AC =
nullptr;
10513 const TargetLibraryInfo *TLI =
nullptr;
10517 if (!
F->isDeclaration()) {
10524 SimplifyQuery Q(
DL, TLI, DT, AC, CtxI);
10531 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10535 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10536 AANoFPClass::StateType &State) {
10547 if (
auto *NoFPAA =
A.getAAFor<AANoFPClass>(*
this, IRP, DepClassTy::NONE))
10548 State.addKnownBits(NoFPAA->getState().getKnown());
10552 const std::string getAsStr(Attributor *
A)
const override {
10553 std::string
Result =
"nofpclass";
10554 raw_string_ostream OS(Result);
10555 OS << getKnownNoFPClass() <<
'/' << getAssumedNoFPClass();
10559 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
10560 SmallVectorImpl<Attribute> &Attrs)
const override {
10561 Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));
10565struct AANoFPClassFloating :
public AANoFPClassImpl {
10566 AANoFPClassFloating(
const IRPosition &IRP, Attributor &
A)
10567 : AANoFPClassImpl(IRP,
A) {}
10572 bool UsedAssumedInformation =
false;
10573 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10575 Values.
push_back({getAssociatedValue(), getCtxI()});
10581 DepClassTy::REQUIRED);
10582 if (!AA ||
this == AA) {
10583 T.indicatePessimisticFixpoint();
10585 const AANoFPClass::StateType &S =
10586 static_cast<const AANoFPClass::StateType &
>(AA->
getState());
10589 return T.isValidState();
10592 for (
const auto &VAC : Values)
10594 return indicatePessimisticFixpoint();
10600 void trackStatistics()
const override {
10605struct AANoFPClassReturned final
10606 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10607 AANoFPClassImpl::StateType, false,
10608 Attribute::None, false> {
10609 AANoFPClassReturned(
const IRPosition &IRP, Attributor &
A)
10610 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10611 AANoFPClassImpl::StateType,
false,
10615 void trackStatistics()
const override {
10620struct AANoFPClassArgument final
10621 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {
10622 AANoFPClassArgument(
const IRPosition &IRP, Attributor &
A)
10623 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10629struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {
10630 AANoFPClassCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10631 : AANoFPClassFloating(IRP,
A) {}
10634 void trackStatistics()
const override {
10639struct AANoFPClassCallSiteReturned final
10640 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl> {
10641 AANoFPClassCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10642 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10645 void trackStatistics()
const override {
10650struct AACallEdgesImpl :
public AACallEdges {
10651 AACallEdgesImpl(
const IRPosition &IRP, Attributor &
A) : AACallEdges(IRP,
A) {}
10653 const SetVector<Function *> &getOptimisticEdges()
const override {
10654 return CalledFunctions;
10657 bool hasUnknownCallee()
const override {
return HasUnknownCallee; }
10659 bool hasNonAsmUnknownCallee()
const override {
10660 return HasUnknownCalleeNonAsm;
10663 const std::string getAsStr(Attributor *
A)
const override {
10664 return "CallEdges[" + std::to_string(HasUnknownCallee) +
"," +
10665 std::to_string(CalledFunctions.size()) +
"]";
10668 void trackStatistics()
const override {}
10671 void addCalledFunction(Function *Fn,
ChangeStatus &Change) {
10672 if (CalledFunctions.insert(Fn)) {
10673 Change = ChangeStatus::CHANGED;
10679 void setHasUnknownCallee(
bool NonAsm,
ChangeStatus &Change) {
10680 if (!HasUnknownCallee)
10681 Change = ChangeStatus::CHANGED;
10682 if (NonAsm && !HasUnknownCalleeNonAsm)
10683 Change = ChangeStatus::CHANGED;
10684 HasUnknownCalleeNonAsm |= NonAsm;
10685 HasUnknownCallee =
true;
10690 SetVector<Function *> CalledFunctions;
10693 bool HasUnknownCallee =
false;
10696 bool HasUnknownCalleeNonAsm =
false;
10699struct AACallEdgesCallSite :
public AACallEdgesImpl {
10700 AACallEdgesCallSite(
const IRPosition &IRP, Attributor &
A)
10701 : AACallEdgesImpl(IRP,
A) {}
10708 addCalledFunction(Fn, Change);
10710 LLVM_DEBUG(
dbgs() <<
"[AACallEdges] Unrecognized value: " << V <<
"\n");
10711 setHasUnknownCallee(
true, Change);
10722 VisitValue(*V, CtxI);
10726 bool UsedAssumedInformation =
false;
10732 for (
auto &VAC : Values)
10739 if (
IA->hasSideEffects() &&
10742 setHasUnknownCallee(
false, Change);
10748 if (
auto *IndirectCallAA =
A.getAAFor<AAIndirectCallInfo>(
10749 *
this, getIRPosition(), DepClassTy::OPTIONAL))
10750 if (IndirectCallAA->foreachCallee(
10751 [&](Function *Fn) { return VisitValue(*Fn, CB); }))
10760 for (
const Use *U : CallbackUses)
10761 ProcessCalledOperand(
U->get(), CB);
10767struct AACallEdgesFunction :
public AACallEdgesImpl {
10768 AACallEdgesFunction(
const IRPosition &IRP, Attributor &
A)
10769 : AACallEdgesImpl(IRP,
A) {}
10778 auto *CBEdges =
A.getAAFor<AACallEdges>(
10782 if (CBEdges->hasNonAsmUnknownCallee())
10783 setHasUnknownCallee(
true, Change);
10784 if (CBEdges->hasUnknownCallee())
10785 setHasUnknownCallee(
false, Change);
10787 for (Function *
F : CBEdges->getOptimisticEdges())
10788 addCalledFunction(
F, Change);
10794 bool UsedAssumedInformation =
false;
10795 if (!
A.checkForAllCallLikeInstructions(ProcessCallInst, *
this,
10796 UsedAssumedInformation,
10800 setHasUnknownCallee(
true, Change);
10809struct AAInterFnReachabilityFunction
10810 :
public CachedReachabilityAA<AAInterFnReachability, Function> {
10811 using Base = CachedReachabilityAA<AAInterFnReachability, Function>;
10812 AAInterFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
10815 bool instructionCanReach(
10816 Attributor &
A,
const Instruction &From,
const Function &To,
10819 auto *NonConstThis =
const_cast<AAInterFnReachabilityFunction *
>(
this);
10821 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
10822 RQITy::Reachable
Result;
10823 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
10824 return NonConstThis->isReachableImpl(
A, StackRQI,
10826 return Result == RQITy::Reachable::Yes;
10830 bool IsTemporaryRQI)
override {
10832 &RQI.From->getFunction()->getEntryBlock().front();
10833 if (EntryI != RQI.From &&
10834 !instructionCanReach(
A, *EntryI, *RQI.To,
nullptr))
10835 return rememberResult(
A, RQITy::Reachable::No, RQI,
false,
10838 auto CheckReachableCallBase = [&](CallBase *CB) {
10839 auto *CBEdges =
A.getAAFor<AACallEdges>(
10841 if (!CBEdges || !CBEdges->getState().isValidState())
10844 if (CBEdges->hasUnknownCallee())
10847 for (Function *Fn : CBEdges->getOptimisticEdges()) {
10858 if (Fn == getAnchorScope()) {
10859 if (EntryI == RQI.From)
10864 const AAInterFnReachability *InterFnReachability =
10866 DepClassTy::OPTIONAL);
10869 if (!InterFnReachability ||
10877 const auto *IntraFnReachability =
A.getAAFor<AAIntraFnReachability>(
10879 DepClassTy::OPTIONAL);
10887 return IntraFnReachability && !IntraFnReachability->isAssumedReachable(
10888 A, *RQI.From, CBInst, RQI.ExclusionSet);
10891 bool UsedExclusionSet =
true;
10892 bool UsedAssumedInformation =
false;
10893 if (!
A.checkForAllCallLikeInstructions(CheckCallBase, *
this,
10894 UsedAssumedInformation,
10896 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
10899 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
10903 void trackStatistics()
const override {}
10907template <
typename AAType>
10908static std::optional<Constant *>
10911 if (!Ty.isIntegerTy())
10919 std::optional<Constant *> COpt =
AA->getAssumedConstant(
A);
10921 if (!COpt.has_value()) {
10923 return std::nullopt;
10925 if (
auto *
C = *COpt) {
10936 std::optional<Value *> V;
10937 for (
auto &It : Values) {
10939 if (V.has_value() && !*V)
10942 if (!V.has_value())
10956 if (
A.hasSimplificationCallback(getIRPosition())) {
10957 indicatePessimisticFixpoint();
10960 Value *Stripped = getAssociatedValue().stripPointerCasts();
10962 addValue(
A, getState(), *Stripped, getCtxI(),
AA::AnyScope,
10964 indicateOptimisticFixpoint();
10967 AAPotentialValues::initialize(
A);
10971 const std::string getAsStr(Attributor *
A)
const override {
10973 llvm::raw_string_ostream OS(Str);
10978 template <
typename AAType>
10979 static std::optional<Value *> askOtherAA(Attributor &
A,
10980 const AbstractAttribute &AA,
10981 const IRPosition &IRP,
Type &Ty) {
10986 return std::nullopt;
10993 virtual void addValue(Attributor &
A, StateType &State,
Value &V,
10995 Function *AnchorScope)
const {
10999 for (
const auto &U : CB->
args()) {
11009 Type &Ty = *getAssociatedType();
11010 std::optional<Value *> SimpleV =
11011 askOtherAA<AAValueConstantRange>(
A, *
this, ValIRP, Ty);
11012 if (SimpleV.has_value() && !*SimpleV) {
11013 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
11014 *
this, ValIRP, DepClassTy::OPTIONAL);
11015 if (PotentialConstantsAA && PotentialConstantsAA->isValidState()) {
11016 for (
const auto &It : PotentialConstantsAA->getAssumedSet())
11017 State.unionAssumed({{*ConstantInt::get(&Ty, It),
nullptr}, S});
11018 if (PotentialConstantsAA->undefIsContained())
11023 if (!SimpleV.has_value())
11035 State.unionAssumed({{*VPtr, CtxI}, S});
11041 AA::ValueAndContext
I;
11045 return II.I ==
I &&
II.S == S;
11048 return std::tie(
I, S) < std::tie(
II.I,
II.S);
11052 bool recurseForValue(Attributor &
A,
const IRPosition &IRP,
AA::ValueScope S) {
11053 SmallMapVector<AA::ValueAndContext, int, 8> ValueScopeMap;
11058 bool UsedAssumedInformation =
false;
11060 if (!
A.getAssumedSimplifiedValues(IRP,
this, Values, CS,
11061 UsedAssumedInformation))
11064 for (
auto &It : Values)
11065 ValueScopeMap[It] += CS;
11067 for (
auto &It : ValueScopeMap)
11068 addValue(
A, getState(), *It.first.getValue(), It.first.getCtxI(),
11074 void giveUpOnIntraprocedural(Attributor &
A) {
11075 auto NewS = StateType::getBestState(getState());
11076 for (
const auto &It : getAssumedSet()) {
11079 addValue(
A, NewS, *It.first.getValue(), It.first.getCtxI(),
11082 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11090 getState() = StateType::getBestState(getState());
11091 getState().unionAssumed({{getAssociatedValue(), getCtxI()},
AA::AnyScope});
11092 AAPotentialValues::indicateOptimisticFixpoint();
11093 return ChangeStatus::CHANGED;
11098 return indicatePessimisticFixpoint();
11106 if (!getAssumedSimplifiedValues(
A, Values, S))
11108 Value &OldV = getAssociatedValue();
11111 Value *NewV = getSingleValue(
A, *
this, getIRPosition(), Values);
11112 if (!NewV || NewV == &OldV)
11117 if (
A.changeAfterManifest(getIRPosition(), *NewV))
11118 return ChangeStatus::CHANGED;
11120 return ChangeStatus::UNCHANGED;
11123 bool getAssumedSimplifiedValues(
11124 Attributor &
A, SmallVectorImpl<AA::ValueAndContext> &Values,
11125 AA::ValueScope S,
bool RecurseForSelectAndPHI =
false)
const override {
11126 if (!isValidState())
11128 bool UsedAssumedInformation =
false;
11129 for (
const auto &It : getAssumedSet())
11130 if (It.second & S) {
11131 if (RecurseForSelectAndPHI && (
isa<PHINode>(It.first.getValue()) ||
11133 if (
A.getAssumedSimplifiedValues(
11135 this, Values, S, UsedAssumedInformation))
11140 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11145struct AAPotentialValuesFloating : AAPotentialValuesImpl {
11146 AAPotentialValuesFloating(
const IRPosition &IRP, Attributor &
A)
11147 : AAPotentialValuesImpl(IRP,
A) {}
11151 auto AssumedBefore = getAssumed();
11153 genericValueTraversal(
A, &getAssociatedValue());
11155 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11156 : ChangeStatus::CHANGED;
11160 struct LivenessInfo {
11161 const AAIsDead *LivenessAA =
nullptr;
11162 bool AnyDead =
false;
11172 SmallVectorImpl<ItemInfo> &Worklist) {
11175 bool UsedAssumedInformation =
false;
11177 auto GetSimplifiedValues = [&](
Value &
V,
11179 if (!
A.getAssumedSimplifiedValues(
11183 Values.
push_back(AA::ValueAndContext{
V,
II.I.getCtxI()});
11185 return Values.
empty();
11187 if (GetSimplifiedValues(*
LHS, LHSValues))
11189 if (GetSimplifiedValues(*
RHS, RHSValues))
11194 InformationCache &InfoCache =
A.getInfoCache();
11201 F ?
A.getInfoCache().getTargetLibraryInfoForFunction(*
F) :
nullptr;
11206 const DataLayout &
DL =
A.getDataLayout();
11207 SimplifyQuery Q(
DL, TLI, DT, AC, CmpI);
11209 auto CheckPair = [&](
Value &LHSV,
Value &RHSV) {
11212 nullptr,
II.S, getAnchorScope());
11218 if (&LHSV == &RHSV &&
11220 Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
11222 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11229 if (TypedLHS && TypedRHS) {
11231 if (NewV && NewV != &Cmp) {
11232 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11244 if (!LHSIsNull && !RHSIsNull)
11250 assert((LHSIsNull || RHSIsNull) &&
11251 "Expected nullptr versus non-nullptr comparison at this point");
11254 unsigned PtrIdx = LHSIsNull;
11255 bool IsKnownNonNull;
11258 DepClassTy::REQUIRED, IsKnownNonNull);
11259 if (!IsAssumedNonNull)
11265 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11270 for (
auto &LHSValue : LHSValues)
11271 for (
auto &RHSValue : RHSValues)
11272 if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))
11277 bool handleSelectInst(Attributor &
A, SelectInst &SI, ItemInfo
II,
11278 SmallVectorImpl<ItemInfo> &Worklist) {
11280 bool UsedAssumedInformation =
false;
11282 std::optional<Constant *>
C =
11283 A.getAssumedConstant(*
SI.getCondition(), *
this, UsedAssumedInformation);
11284 bool NoValueYet = !
C.has_value();
11292 }
else if (&SI == &getAssociatedValue()) {
11297 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11299 if (!SimpleV.has_value())
11302 addValue(
A, getState(), **SimpleV, CtxI,
II.S, getAnchorScope());
11310 bool handleLoadInst(Attributor &
A, LoadInst &LI, ItemInfo
II,
11311 SmallVectorImpl<ItemInfo> &Worklist) {
11312 SmallSetVector<Value *, 4> PotentialCopies;
11313 SmallSetVector<Instruction *, 4> PotentialValueOrigins;
11314 bool UsedAssumedInformation =
false;
11316 PotentialValueOrigins, *
this,
11317 UsedAssumedInformation,
11319 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Failed to get potentially "
11320 "loaded values for load instruction "
11328 InformationCache &InfoCache =
A.getInfoCache();
11330 if (!
llvm::all_of(PotentialValueOrigins, [&](Instruction *
I) {
11334 return A.isAssumedDead(
SI->getOperandUse(0),
this,
11336 UsedAssumedInformation,
11338 return A.isAssumedDead(*
I,
this,
nullptr,
11339 UsedAssumedInformation,
11342 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Load is onl used by assumes "
11343 "and we cannot delete all the stores: "
11354 bool AllLocal = ScopeIsLocal;
11359 if (!DynamicallyUnique) {
11360 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Not all potentially loaded "
11361 "values are dynamically unique: "
11366 for (
auto *PotentialCopy : PotentialCopies) {
11368 Worklist.
push_back({{*PotentialCopy, CtxI},
II.S});
11373 if (!AllLocal && ScopeIsLocal)
11378 bool handlePHINode(
11379 Attributor &
A, PHINode &
PHI, ItemInfo
II,
11380 SmallVectorImpl<ItemInfo> &Worklist,
11381 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11382 auto GetLivenessInfo = [&](
const Function &
F) -> LivenessInfo & {
11383 LivenessInfo &LI = LivenessAAs[&
F];
11384 if (!LI.LivenessAA)
11390 if (&
PHI == &getAssociatedValue()) {
11391 LivenessInfo &LI = GetLivenessInfo(*
PHI.getFunction());
11393 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
11394 *
PHI.getFunction());
11398 for (
unsigned u = 0, e =
PHI.getNumIncomingValues(); u < e; u++) {
11400 if (LI.LivenessAA &&
11401 LI.LivenessAA->isEdgeDead(IncomingBB,
PHI.getParent())) {
11420 bool UsedAssumedInformation =
false;
11421 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11423 if (!SimpleV.has_value())
11427 addValue(
A, getState(), **SimpleV, &
PHI,
II.S, getAnchorScope());
11434 bool handleGenericInst(Attributor &
A, Instruction &
I, ItemInfo
II,
11435 SmallVectorImpl<ItemInfo> &Worklist) {
11436 bool SomeSimplified =
false;
11437 bool UsedAssumedInformation =
false;
11439 SmallVector<Value *, 8> NewOps(
I.getNumOperands());
11442 const auto &SimplifiedOp =
A.getAssumedSimplified(
11447 if (!SimplifiedOp.has_value())
11451 NewOps[Idx] = *SimplifiedOp;
11455 SomeSimplified |= (NewOps[Idx] !=
Op);
11461 if (!SomeSimplified)
11464 InformationCache &InfoCache =
A.getInfoCache();
11468 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
11471 const DataLayout &
DL =
I.getDataLayout();
11472 SimplifyQuery Q(
DL, TLI, DT, AC, &
I);
11474 if (!NewV || NewV == &
I)
11477 LLVM_DEBUG(
dbgs() <<
"Generic inst " <<
I <<
" assumed simplified to "
11484 Attributor &
A, Instruction &
I, ItemInfo
II,
11485 SmallVectorImpl<ItemInfo> &Worklist,
11486 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11489 CI->getPredicate(),
II, Worklist);
11491 switch (
I.getOpcode()) {
11492 case Instruction::Select:
11494 case Instruction::PHI:
11496 case Instruction::Load:
11499 return handleGenericInst(
A,
I,
II, Worklist);
11504 void genericValueTraversal(Attributor &
A,
Value *InitialV) {
11505 SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;
11507 SmallSet<ItemInfo, 16> Visited;
11526 LLVM_DEBUG(
dbgs() <<
"Generic value traversal reached iteration limit: "
11527 << Iteration <<
"!\n");
11528 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11534 Value *NewV =
nullptr;
11535 if (
V->getType()->isPointerTy()) {
11541 for (Argument &Arg :
Callee->args())
11548 if (NewV && NewV != V) {
11549 Worklist.
push_back({{*NewV, CtxI}, S});
11563 if (V == InitialV && CtxI == getCtxI()) {
11564 indicatePessimisticFixpoint();
11568 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11569 }
while (!Worklist.
empty());
11573 for (
auto &It : LivenessAAs)
11574 if (It.second.AnyDead)
11575 A.recordDependence(*It.second.LivenessAA, *
this, DepClassTy::OPTIONAL);
11579 void trackStatistics()
const override {
11584struct AAPotentialValuesArgument final : AAPotentialValuesImpl {
11585 using Base = AAPotentialValuesImpl;
11586 AAPotentialValuesArgument(
const IRPosition &IRP, Attributor &
A)
11593 indicatePessimisticFixpoint();
11598 auto AssumedBefore = getAssumed();
11600 unsigned ArgNo = getCalleeArgNo();
11602 bool UsedAssumedInformation =
false;
11604 auto CallSitePred = [&](AbstractCallSite ACS) {
11606 if (CSArgIRP.getPositionKind() == IRP_INVALID)
11609 if (!
A.getAssumedSimplifiedValues(CSArgIRP,
this, Values,
11611 UsedAssumedInformation))
11614 return isValidState();
11617 if (!
A.checkForAllCallSites(CallSitePred, *
this,
11619 UsedAssumedInformation))
11620 return indicatePessimisticFixpoint();
11622 Function *Fn = getAssociatedFunction();
11623 bool AnyNonLocal =
false;
11624 for (
auto &It : Values) {
11626 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11631 return indicatePessimisticFixpoint();
11635 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11641 AnyNonLocal =
true;
11643 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11645 giveUpOnIntraprocedural(
A);
11647 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11648 : ChangeStatus::CHANGED;
11652 void trackStatistics()
const override {
11657struct AAPotentialValuesReturned :
public AAPotentialValuesFloating {
11658 using Base = AAPotentialValuesFloating;
11659 AAPotentialValuesReturned(
const IRPosition &IRP, Attributor &
A)
11665 if (!
F ||
F->isDeclaration() ||
F->getReturnType()->isVoidTy()) {
11666 indicatePessimisticFixpoint();
11670 for (Argument &Arg :
F->args())
11673 ReturnedArg = &Arg;
11676 if (!
A.isFunctionIPOAmendable(*
F) ||
11677 A.hasSimplificationCallback(getIRPosition())) {
11679 indicatePessimisticFixpoint();
11681 indicateOptimisticFixpoint();
11687 auto AssumedBefore = getAssumed();
11688 bool UsedAssumedInformation =
false;
11691 Function *AnchorScope = getAnchorScope();
11697 UsedAssumedInformation,
11703 bool AllInterAreIntra =
false;
11706 llvm::all_of(Values, [&](
const AA::ValueAndContext &VAC) {
11710 for (
const AA::ValueAndContext &VAC : Values) {
11711 addValue(
A, getState(), *VAC.
getValue(),
11715 if (AllInterAreIntra)
11722 HandleReturnedValue(*ReturnedArg,
nullptr,
true);
11725 bool AddValues =
true;
11728 addValue(
A, getState(), *RetI.getOperand(0), &RetI,
AA::AnyScope,
11732 return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);
11735 if (!
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11736 UsedAssumedInformation,
11738 return indicatePessimisticFixpoint();
11741 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11742 : ChangeStatus::CHANGED;
11747 return ChangeStatus::UNCHANGED;
11749 if (!getAssumedSimplifiedValues(
A, Values, AA::ValueScope::Intraprocedural,
11751 return ChangeStatus::UNCHANGED;
11752 Value *NewVal = getSingleValue(
A, *
this, getIRPosition(), Values);
11754 return ChangeStatus::UNCHANGED;
11759 "Number of function with unique return");
11762 {Attribute::get(Arg->
getContext(), Attribute::Returned)});
11767 Value *RetOp = RetI.getOperand(0);
11771 if (
A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))
11772 Changed = ChangeStatus::CHANGED;
11775 bool UsedAssumedInformation =
false;
11776 (void)
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11777 UsedAssumedInformation,
11783 return AAPotentialValues::indicatePessimisticFixpoint();
11787 void trackStatistics()
const override{
11794struct AAPotentialValuesFunction : AAPotentialValuesImpl {
11795 AAPotentialValuesFunction(
const IRPosition &IRP, Attributor &
A)
11796 : AAPotentialValuesImpl(IRP,
A) {}
11805 void trackStatistics()
const override {
11810struct AAPotentialValuesCallSite : AAPotentialValuesFunction {
11811 AAPotentialValuesCallSite(
const IRPosition &IRP, Attributor &
A)
11812 : AAPotentialValuesFunction(IRP,
A) {}
11815 void trackStatistics()
const override {
11820struct AAPotentialValuesCallSiteReturned : AAPotentialValuesImpl {
11821 AAPotentialValuesCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
11822 : AAPotentialValuesImpl(IRP,
A) {}
11826 auto AssumedBefore = getAssumed();
11830 return indicatePessimisticFixpoint();
11832 bool UsedAssumedInformation =
false;
11836 UsedAssumedInformation))
11837 return indicatePessimisticFixpoint();
11844 Values, S, UsedAssumedInformation))
11847 for (
auto &It : Values) {
11848 Value *
V = It.getValue();
11849 std::optional<Value *> CallerV =
A.translateArgumentToCallSiteContent(
11850 V, *CB, *
this, UsedAssumedInformation);
11851 if (!CallerV.has_value()) {
11855 V = *CallerV ? *CallerV :
V;
11861 giveUpOnIntraprocedural(
A);
11864 addValue(
A, getState(), *V, CB, S, getAnchorScope());
11869 return indicatePessimisticFixpoint();
11871 return indicatePessimisticFixpoint();
11872 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11873 : ChangeStatus::CHANGED;
11877 return AAPotentialValues::indicatePessimisticFixpoint();
11881 void trackStatistics()
const override {
11886struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
11887 AAPotentialValuesCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
11888 : AAPotentialValuesFloating(IRP,
A) {}
11891 void trackStatistics()
const override {
11899struct AAAssumptionInfoImpl :
public AAAssumptionInfo {
11900 AAAssumptionInfoImpl(
const IRPosition &IRP, Attributor &
A,
11901 const DenseSet<StringRef> &Known)
11902 : AAAssumptionInfo(IRP,
A, Known) {}
11907 if (getKnown().isUniversal())
11908 return ChangeStatus::UNCHANGED;
11910 const IRPosition &IRP = getIRPosition();
11912 getAssumed().getSet().
end());
11914 return A.manifestAttrs(IRP,
11921 bool hasAssumption(
const StringRef Assumption)
const override {
11922 return isValidState() && setContains(Assumption);
11926 const std::string getAsStr(Attributor *
A)
const override {
11927 const SetContents &Known = getKnown();
11928 const SetContents &Assumed = getAssumed();
11932 const std::string KnownStr =
llvm::join(Set,
",");
11934 std::string AssumedStr =
"Universal";
11935 if (!Assumed.isUniversal()) {
11936 Set.assign(Assumed.getSet().begin(), Assumed.getSet().end());
11939 return "Known [" + KnownStr +
"]," +
" Assumed [" + AssumedStr +
"]";
11954struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {
11955 AAAssumptionInfoFunction(
const IRPosition &IRP, Attributor &
A)
11956 : AAAssumptionInfoImpl(IRP,
A,
11963 auto CallSitePred = [&](AbstractCallSite ACS) {
11964 const auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
11966 DepClassTy::REQUIRED);
11970 Changed |= getIntersection(AssumptionAA->getAssumed());
11971 return !getAssumed().empty() || !getKnown().empty();
11974 bool UsedAssumedInformation =
false;
11979 if (!
A.checkForAllCallSites(CallSitePred, *
this,
true,
11980 UsedAssumedInformation))
11981 return indicatePessimisticFixpoint();
11983 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11986 void trackStatistics()
const override {}
11990struct AAAssumptionInfoCallSite final : AAAssumptionInfoImpl {
11992 AAAssumptionInfoCallSite(
const IRPosition &IRP, Attributor &
A)
11993 : AAAssumptionInfoImpl(IRP,
A, getInitialAssumptions(IRP)) {}
11998 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
12004 auto *AssumptionAA =
12005 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
12007 return indicatePessimisticFixpoint();
12008 bool Changed = getIntersection(AssumptionAA->getAssumed());
12009 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12013 void trackStatistics()
const override {}
12018 DenseSet<StringRef> getInitialAssumptions(
const IRPosition &IRP) {
12025 return Assumptions;
12040struct AAUnderlyingObjectsImpl
12046 const std::string getAsStr(
Attributor *
A)
const override {
12047 if (!isValidState())
12048 return "<invalid>";
12051 OS <<
"underlying objects: inter " << InterAssumedUnderlyingObjects.size()
12052 <<
" objects, intra " << IntraAssumedUnderlyingObjects.size()
12054 if (!InterAssumedUnderlyingObjects.empty()) {
12055 OS <<
"inter objects:\n";
12056 for (
auto *Obj : InterAssumedUnderlyingObjects)
12057 OS << *Obj <<
'\n';
12059 if (!IntraAssumedUnderlyingObjects.empty()) {
12060 OS <<
"intra objects:\n";
12061 for (
auto *Obj : IntraAssumedUnderlyingObjects)
12062 OS << *
Obj <<
'\n';
12068 void trackStatistics()
const override {}
12072 auto &Ptr = getAssociatedValue();
12074 bool UsedAssumedInformation =
false;
12075 auto DoUpdate = [&](SmallSetVector<Value *, 8> &UnderlyingObjects,
12077 SmallPtrSet<Value *, 8> SeenObjects;
12081 Scope, UsedAssumedInformation))
12082 return UnderlyingObjects.
insert(&Ptr);
12086 for (
unsigned I = 0;
I < Values.
size(); ++
I) {
12087 auto &VAC = Values[
I];
12090 if (!SeenObjects.
insert(UO ? UO : Obj).second)
12092 if (UO && UO != Obj) {
12098 const auto *OtherAA =
A.getAAFor<AAUnderlyingObjects>(
12100 auto Pred = [&](
Value &
V) {
12108 if (!OtherAA || !OtherAA->forallUnderlyingObjects(Pred, Scope))
12110 "The forall call should not return false at this position");
12116 Changed |= handleIndirect(
A, *Obj, UnderlyingObjects, Scope,
12117 UsedAssumedInformation);
12123 for (
unsigned u = 0, e =
PHI->getNumIncomingValues(); u < e; u++) {
12125 handleIndirect(
A, *
PHI->getIncomingValue(u), UnderlyingObjects,
12126 Scope, UsedAssumedInformation);
12140 if (!UsedAssumedInformation)
12141 indicateOptimisticFixpoint();
12142 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12145 bool forallUnderlyingObjects(
12146 function_ref<
bool(
Value &)> Pred,
12148 if (!isValidState())
12149 return Pred(getAssociatedValue());
12152 ? IntraAssumedUnderlyingObjects
12153 : InterAssumedUnderlyingObjects;
12154 for (
Value *Obj : AssumedUnderlyingObjects)
12164 bool handleIndirect(Attributor &
A,
Value &V,
12165 SmallSetVector<Value *, 8> &UnderlyingObjects,
12168 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
12170 auto Pred = [&](
Value &
V) {
12174 if (!AA || !AA->forallUnderlyingObjects(Pred, Scope))
12176 "The forall call should not return false at this position");
12182 SmallSetVector<Value *, 8> IntraAssumedUnderlyingObjects;
12184 SmallSetVector<Value *, 8> InterAssumedUnderlyingObjects;
12187struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl {
12188 AAUnderlyingObjectsFloating(
const IRPosition &IRP, Attributor &
A)
12189 : AAUnderlyingObjectsImpl(IRP,
A) {}
12192struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl {
12193 AAUnderlyingObjectsArgument(
const IRPosition &IRP, Attributor &
A)
12194 : AAUnderlyingObjectsImpl(IRP,
A) {}
12197struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl {
12198 AAUnderlyingObjectsCallSite(
const IRPosition &IRP, Attributor &
A)
12199 : AAUnderlyingObjectsImpl(IRP,
A) {}
12202struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl {
12203 AAUnderlyingObjectsCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12204 : AAUnderlyingObjectsImpl(IRP,
A) {}
12207struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl {
12208 AAUnderlyingObjectsReturned(
const IRPosition &IRP, Attributor &
A)
12209 : AAUnderlyingObjectsImpl(IRP,
A) {}
12212struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl {
12213 AAUnderlyingObjectsCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12214 : AAUnderlyingObjectsImpl(IRP,
A) {}
12217struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {
12218 AAUnderlyingObjectsFunction(
const IRPosition &IRP, Attributor &
A)
12219 : AAUnderlyingObjectsImpl(IRP,
A) {}
12225struct AAGlobalValueInfoFloating :
public AAGlobalValueInfo {
12226 AAGlobalValueInfoFloating(
const IRPosition &IRP, Attributor &
A)
12227 : AAGlobalValueInfo(IRP,
A) {}
12232 bool checkUse(Attributor &
A,
const Use &U,
bool &Follow,
12233 SmallVectorImpl<const Value *> &Worklist) {
12240 LLVM_DEBUG(
dbgs() <<
"[AAGlobalValueInfo] Check use: " << *
U.get() <<
" in "
12241 << *UInst <<
"\n");
12244 int Idx = &
Cmp->getOperandUse(0) == &
U;
12247 return U == &getAnchorValue();
12252 auto CallSitePred = [&](AbstractCallSite ACS) {
12253 Worklist.
push_back(ACS.getInstruction());
12256 bool UsedAssumedInformation =
false;
12258 if (!
A.checkForAllCallSites(CallSitePred, *UInst->
getFunction(),
12260 UsedAssumedInformation))
12278 if (!Fn || !
A.isFunctionIPOAmendable(*Fn))
12287 unsigned NumUsesBefore =
Uses.size();
12289 SmallPtrSet<const Value *, 8> Visited;
12293 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
12301 return checkUse(
A, U, Follow, Worklist);
12303 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
12304 Uses.insert(&OldU);
12308 while (!Worklist.
empty()) {
12310 if (!Visited.
insert(V).second)
12312 if (!
A.checkForAllUses(UsePred, *
this, *V,
12314 DepClassTy::OPTIONAL,
12315 true, EquivalentUseCB)) {
12316 return indicatePessimisticFixpoint();
12320 return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED
12321 : ChangeStatus::CHANGED;
12324 bool isPotentialUse(
const Use &U)
const override {
12325 return !isValidState() ||
Uses.contains(&U);
12330 return ChangeStatus::UNCHANGED;
12334 const std::string getAsStr(Attributor *
A)
const override {
12335 return "[" + std::to_string(
Uses.size()) +
" uses]";
12338 void trackStatistics()
const override {
12344 SmallPtrSet<const Use *, 8>
Uses;
12350struct AAIndirectCallInfoCallSite :
public AAIndirectCallInfo {
12351 AAIndirectCallInfoCallSite(
const IRPosition &IRP, Attributor &
A)
12352 : AAIndirectCallInfo(IRP,
A) {}
12356 auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);
12357 if (!MD && !
A.isClosedWorldModule())
12361 for (
const auto &
Op : MD->operands())
12363 PotentialCallees.insert(Callee);
12364 }
else if (
A.isClosedWorldModule()) {
12366 A.getInfoCache().getIndirectlyCallableFunctions(
A);
12367 PotentialCallees.insert_range(IndirectlyCallableFunctions);
12370 if (PotentialCallees.empty())
12371 indicateOptimisticFixpoint();
12379 SmallSetVector<Function *, 4> AssumedCalleesNow;
12380 bool AllCalleesKnownNow = AllCalleesKnown;
12382 auto CheckPotentialCalleeUse = [&](
Function &PotentialCallee,
12383 bool &UsedAssumedInformation) {
12384 const auto *GIAA =
A.getAAFor<AAGlobalValueInfo>(
12386 if (!GIAA || GIAA->isPotentialUse(CalleeUse))
12388 UsedAssumedInformation = !GIAA->isAtFixpoint();
12392 auto AddPotentialCallees = [&]() {
12393 for (
auto *PotentialCallee : PotentialCallees) {
12394 bool UsedAssumedInformation =
false;
12395 if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))
12396 AssumedCalleesNow.
insert(PotentialCallee);
12402 bool UsedAssumedInformation =
false;
12405 AA::ValueScope::AnyScope,
12406 UsedAssumedInformation)) {
12407 if (PotentialCallees.empty())
12408 return indicatePessimisticFixpoint();
12409 AddPotentialCallees();
12414 auto CheckPotentialCallee = [&](
Function &Fn) {
12415 if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))
12418 auto &CachedResult = FilterResults[&Fn];
12419 if (CachedResult.has_value())
12420 return CachedResult.value();
12422 bool UsedAssumedInformation =
false;
12423 if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {
12424 if (!UsedAssumedInformation)
12425 CachedResult =
false;
12434 for (
int I = NumCBArgs;
I < NumFnArgs; ++
I) {
12435 bool IsKnown =
false;
12438 DepClassTy::OPTIONAL, IsKnown)) {
12440 CachedResult =
false;
12445 CachedResult =
true;
12451 for (
auto &VAC : Values) {
12459 if (CheckPotentialCallee(*VACFn))
12460 AssumedCalleesNow.
insert(VACFn);
12463 if (!PotentialCallees.empty()) {
12464 AddPotentialCallees();
12467 AllCalleesKnownNow =
false;
12470 if (AssumedCalleesNow == AssumedCallees &&
12471 AllCalleesKnown == AllCalleesKnownNow)
12472 return ChangeStatus::UNCHANGED;
12474 std::swap(AssumedCallees, AssumedCalleesNow);
12475 AllCalleesKnown = AllCalleesKnownNow;
12476 return ChangeStatus::CHANGED;
12482 if (!AllCalleesKnown && AssumedCallees.empty())
12483 return ChangeStatus::UNCHANGED;
12486 bool UsedAssumedInformation =
false;
12487 if (
A.isAssumedDead(*CB,
this,
nullptr,
12488 UsedAssumedInformation))
12489 return ChangeStatus::UNCHANGED;
12493 if (
FP->getType()->getPointerAddressSpace())
12494 FP =
new AddrSpaceCastInst(
FP, PointerType::get(
FP->getContext(), 0),
12504 if (AssumedCallees.empty()) {
12505 assert(AllCalleesKnown &&
12506 "Expected all callees to be known if there are none.");
12507 A.changeToUnreachableAfterManifest(CB);
12508 return ChangeStatus::CHANGED;
12512 if (AllCalleesKnown && AssumedCallees.size() == 1) {
12513 auto *NewCallee = AssumedCallees.front();
12516 NumIndirectCallsPromoted++;
12517 return ChangeStatus::CHANGED;
12524 A.deleteAfterManifest(*CB);
12525 return ChangeStatus::CHANGED;
12535 bool SpecializedForAnyCallees =
false;
12536 bool SpecializedForAllCallees = AllCalleesKnown;
12537 ICmpInst *LastCmp =
nullptr;
12540 for (Function *NewCallee : AssumedCallees) {
12541 if (!
A.shouldSpecializeCallSiteForCallee(*
this, *CB, *NewCallee,
12542 AssumedCallees.size())) {
12543 SkippedAssumedCallees.
push_back(NewCallee);
12544 SpecializedForAllCallees =
false;
12547 SpecializedForAnyCallees =
true;
12553 A.registerManifestAddedBasicBlock(*ThenTI->
getParent());
12554 A.registerManifestAddedBasicBlock(*IP->getParent());
12560 A.registerManifestAddedBasicBlock(*ElseBB);
12562 SplitTI->replaceUsesOfWith(CBBB, ElseBB);
12567 CastInst *RetBC =
nullptr;
12568 CallInst *NewCall =
nullptr;
12573 NumIndirectCallsPromoted++;
12581 auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {
12582 if (!AllCalleesKnown)
12583 return ChangeStatus::UNCHANGED;
12584 MDBuilder MDB(IndirectCB.getContext());
12585 MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);
12586 IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);
12587 return ChangeStatus::CHANGED;
12590 if (!SpecializedForAnyCallees)
12591 return AttachCalleeMetadata(*CB);
12594 if (SpecializedForAllCallees) {
12597 new UnreachableInst(IP->getContext(), IP);
12598 IP->eraseFromParent();
12601 CBClone->setName(CB->
getName());
12602 CBClone->insertBefore(*IP->getParent(), IP);
12603 NewCalls.
push_back({CBClone,
nullptr});
12604 AttachCalleeMetadata(*CBClone);
12611 CB->
getParent()->getFirstInsertionPt());
12612 for (
auto &It : NewCalls) {
12613 CallBase *NewCall = It.first;
12614 Instruction *CallRet = It.second ? It.second : It.first;
12626 A.deleteAfterManifest(*CB);
12627 Changed = ChangeStatus::CHANGED;
12633 const std::string getAsStr(Attributor *
A)
const override {
12634 return std::string(AllCalleesKnown ?
"eliminate" :
"specialize") +
12635 " indirect call site with " + std::to_string(AssumedCallees.size()) +
12639 void trackStatistics()
const override {
12640 if (AllCalleesKnown) {
12642 Eliminated, CallSites,
12643 "Number of indirect call sites eliminated via specialization")
12646 "Number of indirect call sites specialized")
12650 bool foreachCallee(function_ref<
bool(Function *)> CB)
const override {
12651 return isValidState() && AllCalleesKnown &&
all_of(AssumedCallees, CB);
12656 DenseMap<Function *, std::optional<bool>> FilterResults;
12660 SmallSetVector<Function *, 4> PotentialCallees;
12664 SmallSetVector<Function *, 4> AssumedCallees;
12668 bool AllCalleesKnown =
true;
12675struct AAInvariantLoadPointerImpl
12676 :
public StateWrapper<BitIntegerState<uint8_t, 15>,
12677 AAInvariantLoadPointer> {
12681 IS_NOALIAS = 1 << 0,
12684 IS_NOEFFECT = 1 << 1,
12686 IS_LOCALLY_INVARIANT = 1 << 2,
12688 IS_LOCALLY_CONSTRAINED = 1 << 3,
12690 IS_BEST_STATE = IS_NOALIAS | IS_NOEFFECT | IS_LOCALLY_INVARIANT |
12691 IS_LOCALLY_CONSTRAINED,
12693 static_assert(getBestState() == IS_BEST_STATE,
"Unexpected best state");
12696 StateWrapper<BitIntegerState<uint8_t, 15>, AAInvariantLoadPointer>;
12700 AAInvariantLoadPointerImpl(
const IRPosition &IRP, Attributor &
A)
12703 bool isKnownInvariant()
const final {
12704 return isKnownLocallyInvariant() && isKnown(IS_LOCALLY_CONSTRAINED);
12707 bool isKnownLocallyInvariant()
const final {
12708 if (isKnown(IS_LOCALLY_INVARIANT))
12710 return isKnown(IS_NOALIAS | IS_NOEFFECT);
12713 bool isAssumedInvariant()
const final {
12714 return isAssumedLocallyInvariant() && isAssumed(IS_LOCALLY_CONSTRAINED);
12717 bool isAssumedLocallyInvariant()
const final {
12718 if (isAssumed(IS_LOCALLY_INVARIANT))
12720 return isAssumed(IS_NOALIAS | IS_NOEFFECT);
12727 if (requiresNoAlias() && !isAssumed(IS_NOALIAS))
12728 return indicatePessimisticFixpoint();
12732 Changed |= updateLocalInvariance(
A);
12738 if (!isKnownInvariant())
12739 return ChangeStatus::UNCHANGED;
12742 const Value *Ptr = &getAssociatedValue();
12743 const auto TagInvariantLoads = [&](
const Use &
U,
bool &) {
12744 if (
U.get() != Ptr)
12752 if (!
A.isRunOn(
I->getFunction()))
12755 if (
I->hasMetadata(LLVMContext::MD_invariant_load))
12759 LI->setMetadata(LLVMContext::MD_invariant_load,
12761 Changed = ChangeStatus::CHANGED;
12766 (void)
A.checkForAllUses(TagInvariantLoads, *
this, *Ptr);
12771 const std::string getAsStr(Attributor *)
const override {
12772 if (isKnownInvariant())
12773 return "load-invariant pointer";
12774 return "non-invariant pointer";
12778 void trackStatistics()
const override {}
12782 bool requiresNoAlias()
const {
12783 switch (getPositionKind()) {
12789 case IRP_CALL_SITE:
12791 case IRP_CALL_SITE_RETURNED: {
12796 case IRP_ARGUMENT: {
12797 const Function *
F = getAssociatedFunction();
12798 assert(
F &&
"no associated function for argument");
12804 bool isExternal()
const {
12805 const Function *
F = getAssociatedFunction();
12809 getPositionKind() != IRP_CALL_SITE_RETURNED;
12813 if (isKnown(IS_NOALIAS) || !isAssumed(IS_NOALIAS))
12814 return ChangeStatus::UNCHANGED;
12817 if (
const auto *ANoAlias =
A.getOrCreateAAFor<AANoAlias>(
12818 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12819 if (ANoAlias->isKnownNoAlias()) {
12820 addKnownBits(IS_NOALIAS);
12821 return ChangeStatus::CHANGED;
12824 if (!ANoAlias->isAssumedNoAlias()) {
12825 removeAssumedBits(IS_NOALIAS);
12826 return ChangeStatus::CHANGED;
12829 return ChangeStatus::UNCHANGED;
12834 if (
const Argument *Arg = getAssociatedArgument()) {
12836 addKnownBits(IS_NOALIAS);
12837 return ChangeStatus::UNCHANGED;
12842 removeAssumedBits(IS_NOALIAS);
12843 return ChangeStatus::CHANGED;
12846 return ChangeStatus::UNCHANGED;
12850 if (isKnown(IS_NOEFFECT) || !isAssumed(IS_NOEFFECT))
12851 return ChangeStatus::UNCHANGED;
12853 if (!getAssociatedFunction())
12854 return indicatePessimisticFixpoint();
12857 return indicatePessimisticFixpoint();
12859 const auto HasNoEffectLoads = [&](
const Use &
U,
bool &) {
12861 return !LI || !LI->mayHaveSideEffects();
12863 if (!
A.checkForAllUses(HasNoEffectLoads, *
this, getAssociatedValue()))
12864 return indicatePessimisticFixpoint();
12866 if (
const auto *AMemoryBehavior =
A.getOrCreateAAFor<AAMemoryBehavior>(
12867 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12870 if (!AMemoryBehavior->isAssumedReadOnly())
12871 return indicatePessimisticFixpoint();
12873 if (AMemoryBehavior->isKnownReadOnly()) {
12874 addKnownBits(IS_NOEFFECT);
12875 return ChangeStatus::UNCHANGED;
12878 return ChangeStatus::UNCHANGED;
12881 if (
const Argument *Arg = getAssociatedArgument()) {
12883 addKnownBits(IS_NOEFFECT);
12884 return ChangeStatus::UNCHANGED;
12889 return indicatePessimisticFixpoint();
12892 return ChangeStatus::UNCHANGED;
12896 if (isKnown(IS_LOCALLY_INVARIANT) || !isAssumed(IS_LOCALLY_INVARIANT))
12897 return ChangeStatus::UNCHANGED;
12900 const auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
12901 getIRPosition(),
this, DepClassTy::REQUIRED);
12903 return ChangeStatus::UNCHANGED;
12905 bool UsedAssumedInformation =
false;
12906 const auto IsLocallyInvariantLoadIfPointer = [&](
const Value &
V) {
12907 if (!
V.getType()->isPointerTy())
12909 const auto *IsInvariantLoadPointer =
12911 DepClassTy::REQUIRED);
12913 if (!IsInvariantLoadPointer)
12916 if (IsInvariantLoadPointer->isKnownLocallyInvariant())
12918 if (!IsInvariantLoadPointer->isAssumedLocallyInvariant())
12921 UsedAssumedInformation =
true;
12924 if (!AUO->forallUnderlyingObjects(IsLocallyInvariantLoadIfPointer))
12925 return indicatePessimisticFixpoint();
12931 if (!IsLocallyInvariantLoadIfPointer(*Arg))
12932 return indicatePessimisticFixpoint();
12937 if (!UsedAssumedInformation) {
12939 addKnownBits(IS_LOCALLY_INVARIANT);
12940 return ChangeStatus::CHANGED;
12943 return ChangeStatus::UNCHANGED;
12947struct AAInvariantLoadPointerFloating final : AAInvariantLoadPointerImpl {
12948 AAInvariantLoadPointerFloating(
const IRPosition &IRP, Attributor &
A)
12949 : AAInvariantLoadPointerImpl(IRP,
A) {}
12952struct AAInvariantLoadPointerReturned final : AAInvariantLoadPointerImpl {
12953 AAInvariantLoadPointerReturned(
const IRPosition &IRP, Attributor &
A)
12954 : AAInvariantLoadPointerImpl(IRP,
A) {}
12957 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12961struct AAInvariantLoadPointerCallSiteReturned final
12962 : AAInvariantLoadPointerImpl {
12963 AAInvariantLoadPointerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12964 : AAInvariantLoadPointerImpl(IRP,
A) {}
12967 const Function *
F = getAssociatedFunction();
12968 assert(
F &&
"no associated function for return from call");
12970 if (!
F->isDeclaration() && !
F->isIntrinsic())
12971 return AAInvariantLoadPointerImpl::initialize(
A);
12976 return AAInvariantLoadPointerImpl::initialize(
A);
12978 if (
F->onlyReadsMemory() &&
F->hasNoSync())
12979 return AAInvariantLoadPointerImpl::initialize(
A);
12983 indicatePessimisticFixpoint();
12987struct AAInvariantLoadPointerArgument final : AAInvariantLoadPointerImpl {
12988 AAInvariantLoadPointerArgument(
const IRPosition &IRP, Attributor &
A)
12989 : AAInvariantLoadPointerImpl(IRP,
A) {}
12992 const Function *
F = getAssociatedFunction();
12993 assert(
F &&
"no associated function for argument");
12996 addKnownBits(IS_LOCALLY_CONSTRAINED);
13000 if (!
F->hasLocalLinkage())
13001 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
13005struct AAInvariantLoadPointerCallSiteArgument final
13006 : AAInvariantLoadPointerImpl {
13007 AAInvariantLoadPointerCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13008 : AAInvariantLoadPointerImpl(IRP,
A) {}
13015template <
typename InstType>
13016static bool makeChange(Attributor &
A, InstType *MemInst,
const Use &U,
13017 Value *OriginalValue, PointerType *NewPtrTy,
13018 bool UseOriginalValue) {
13019 if (
U.getOperandNo() != InstType::getPointerOperandIndex())
13022 if (MemInst->isVolatile()) {
13023 auto *
TTI =
A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(
13024 *MemInst->getFunction());
13025 unsigned NewAS = NewPtrTy->getPointerAddressSpace();
13030 if (UseOriginalValue) {
13031 A.changeUseAfterManifest(
const_cast<Use &
>(U), *OriginalValue);
13035 Instruction *CastInst =
new AddrSpaceCastInst(OriginalValue, NewPtrTy);
13037 A.changeUseAfterManifest(
const_cast<Use &
>(U), *CastInst);
13041struct AAAddressSpaceImpl :
public AAAddressSpace {
13042 AAAddressSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13043 : AAAddressSpace(IRP,
A) {}
13046 assert(isValidState() &&
"the AA is invalid");
13047 return AssumedAddressSpace;
13052 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13053 "Associated value is not a pointer");
13055 if (!
A.getInfoCache().getFlatAddressSpace().has_value()) {
13056 indicatePessimisticFixpoint();
13060 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13061 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13062 if (AS != FlatAS) {
13063 [[maybe_unused]]
bool R = takeAddressSpace(AS);
13064 assert(R &&
"The take should happen");
13065 indicateOptimisticFixpoint();
13070 uint32_t OldAddressSpace = AssumedAddressSpace;
13071 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13073 auto CheckAddressSpace = [&](
Value &
Obj) {
13079 unsigned ObjAS =
Obj.getType()->getPointerAddressSpace();
13080 if (ObjAS != FlatAS)
13081 return takeAddressSpace(ObjAS);
13095 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(*F);
13097 if (AssumedAS != ~0U)
13098 return takeAddressSpace(AssumedAS);
13102 return takeAddressSpace(FlatAS);
13105 auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(getIRPosition(),
this,
13106 DepClassTy::REQUIRED);
13107 if (!AUO->forallUnderlyingObjects(CheckAddressSpace))
13108 return indicatePessimisticFixpoint();
13110 return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED
13111 : ChangeStatus::CHANGED;
13118 if (NewAS == InvalidAddressSpace ||
13120 return ChangeStatus::UNCHANGED;
13122 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13124 Value *AssociatedValue = &getAssociatedValue();
13125 Value *OriginalValue = peelAddrspacecast(AssociatedValue, FlatAS);
13128 PointerType::get(getAssociatedType()->
getContext(), NewAS);
13129 bool UseOriginalValue =
13134 auto Pred = [&](
const Use &
U,
bool &) {
13135 if (
U.get() != AssociatedValue)
13146 makeChange(
A, LI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13149 makeChange(
A, SI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13152 makeChange(
A, RMW, U, OriginalValue, NewPtrTy, UseOriginalValue);
13155 makeChange(
A, CmpX, U, OriginalValue, NewPtrTy, UseOriginalValue);
13162 (void)
A.checkForAllUses(Pred, *
this, getAssociatedValue(),
13165 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13169 const std::string getAsStr(Attributor *
A)
const override {
13170 if (!isValidState())
13171 return "addrspace(<invalid>)";
13172 return "addrspace(" +
13173 (AssumedAddressSpace == InvalidAddressSpace
13175 : std::to_string(AssumedAddressSpace)) +
13180 uint32_t AssumedAddressSpace = InvalidAddressSpace;
13182 bool takeAddressSpace(uint32_t AS) {
13183 if (AssumedAddressSpace == InvalidAddressSpace) {
13184 AssumedAddressSpace = AS;
13187 return AssumedAddressSpace == AS;
13190 static Value *peelAddrspacecast(
Value *V,
unsigned FlatAS) {
13192 assert(
I->getSrcAddressSpace() != FlatAS &&
13193 "there should not be flat AS -> non-flat AS");
13194 return I->getPointerOperand();
13197 if (
C->getOpcode() == Instruction::AddrSpaceCast) {
13198 assert(
C->getOperand(0)->getType()->getPointerAddressSpace() !=
13200 "there should not be flat AS -> non-flat AS X");
13201 return C->getOperand(0);
13207struct AAAddressSpaceFloating final : AAAddressSpaceImpl {
13208 AAAddressSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13209 : AAAddressSpaceImpl(IRP,
A) {}
13211 void trackStatistics()
const override {
13216struct AAAddressSpaceReturned final : AAAddressSpaceImpl {
13217 AAAddressSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13218 : AAAddressSpaceImpl(IRP,
A) {}
13224 (void)indicatePessimisticFixpoint();
13227 void trackStatistics()
const override {
13232struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl {
13233 AAAddressSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13234 : AAAddressSpaceImpl(IRP,
A) {}
13236 void trackStatistics()
const override {
13241struct AAAddressSpaceArgument final : AAAddressSpaceImpl {
13242 AAAddressSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13243 : AAAddressSpaceImpl(IRP,
A) {}
13248struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl {
13249 AAAddressSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13250 : AAAddressSpaceImpl(IRP,
A) {}
13256 (void)indicatePessimisticFixpoint();
13259 void trackStatistics()
const override {
13274struct AANoAliasAddrSpaceImpl :
public AANoAliasAddrSpace {
13275 AANoAliasAddrSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13276 : AANoAliasAddrSpace(IRP,
A) {}
13279 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13280 "Associated value is not a pointer");
13284 std::optional<unsigned> FlatAS =
A.getInfoCache().getFlatAddressSpace();
13285 if (!FlatAS.has_value()) {
13286 indicatePessimisticFixpoint();
13292 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13293 if (AS != *FlatAS) {
13295 indicateOptimisticFixpoint();
13300 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13301 uint32_t OldAssumed = getAssumed();
13303 auto CheckAddressSpace = [&](
Value &
Obj) {
13307 unsigned AS =
Obj.getType()->getPointerAddressSpace();
13311 removeAS(
Obj.getType()->getPointerAddressSpace());
13315 const AAUnderlyingObjects *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
13316 getIRPosition(),
this, DepClassTy::REQUIRED);
13318 return indicatePessimisticFixpoint();
13320 return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
13321 : ChangeStatus::CHANGED;
13326 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13328 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13329 if (AS != FlatAS ||
Map.empty())
13330 return ChangeStatus::UNCHANGED;
13332 LLVMContext &Ctx = getAssociatedValue().getContext();
13333 MDNode *NoAliasASNode =
nullptr;
13334 MDBuilder MDB(Ctx);
13336 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13339 unsigned Upper =
I.stop();
13340 unsigned Lower =
I.start();
13341 if (!NoAliasASNode) {
13342 NoAliasASNode = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13345 MDNode *ASRange = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13349 Value *AssociatedValue = &getAssociatedValue();
13352 auto AddNoAliasAttr = [&](
const Use &
U,
bool &) {
13353 if (
U.get() != AssociatedValue)
13356 if (!Inst || Inst->
hasMetadata(LLVMContext::MD_noalias_addrspace))
13363 Inst->
setMetadata(LLVMContext::MD_noalias_addrspace, NoAliasASNode);
13367 (void)
A.checkForAllUses(AddNoAliasAttr, *
this, *AssociatedValue,
13369 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13373 const std::string getAsStr(Attributor *
A)
const override {
13374 if (!isValidState())
13375 return "<invalid>";
13377 raw_string_ostream OS(Str);
13378 OS <<
"CanNotBeAddrSpace(";
13379 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13380 unsigned Upper =
I.stop();
13381 unsigned Lower =
I.start();
13382 OS <<
' ' <<
'[' <<
Upper <<
',' <<
Lower + 1 <<
')';
13389 void removeAS(
unsigned AS) {
13390 RangeMap::iterator
I =
Map.find(AS);
13392 if (
I !=
Map.end()) {
13393 unsigned Upper =
I.stop();
13394 unsigned Lower =
I.start();
13398 if (AS != ~((
unsigned)0) && AS + 1 <=
Upper)
13400 if (AS != 0 &&
Lower <= AS - 1)
13405 void resetASRanges(Attributor &
A) {
13407 Map.insert(0,
A.getInfoCache().getMaxAddrSpace(),
true);
13411struct AANoAliasAddrSpaceFloating final : AANoAliasAddrSpaceImpl {
13412 AANoAliasAddrSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13413 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13415 void trackStatistics()
const override {
13420struct AANoAliasAddrSpaceReturned final : AANoAliasAddrSpaceImpl {
13421 AANoAliasAddrSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13422 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13424 void trackStatistics()
const override {
13429struct AANoAliasAddrSpaceCallSiteReturned final : AANoAliasAddrSpaceImpl {
13430 AANoAliasAddrSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13431 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13433 void trackStatistics()
const override {
13438struct AANoAliasAddrSpaceArgument final : AANoAliasAddrSpaceImpl {
13439 AANoAliasAddrSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13440 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13442 void trackStatistics()
const override {
13447struct AANoAliasAddrSpaceCallSiteArgument final : AANoAliasAddrSpaceImpl {
13448 AANoAliasAddrSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13449 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13451 void trackStatistics()
const override {
13458struct AAAllocationInfoImpl :
public AAAllocationInfo {
13459 AAAllocationInfoImpl(
const IRPosition &IRP, Attributor &
A)
13460 : AAAllocationInfo(IRP,
A) {}
13462 std::optional<TypeSize> getAllocatedSize()
const override {
13463 assert(isValidState() &&
"the AA is invalid");
13464 return AssumedAllocatedSize;
13467 std::optional<TypeSize> findInitialAllocationSize(Instruction *
I,
13468 const DataLayout &
DL) {
13471 switch (
I->getOpcode()) {
13472 case Instruction::Alloca: {
13477 return std::nullopt;
13483 const IRPosition &IRP = getIRPosition();
13488 return indicatePessimisticFixpoint();
13490 bool IsKnownNoCapture;
13492 A,
this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture))
13493 return indicatePessimisticFixpoint();
13495 const AAPointerInfo *PI =
13496 A.getOrCreateAAFor<AAPointerInfo>(IRP, *
this, DepClassTy::REQUIRED);
13499 return indicatePessimisticFixpoint();
13502 return indicatePessimisticFixpoint();
13504 const DataLayout &
DL =
A.getDataLayout();
13505 const auto AllocationSize = findInitialAllocationSize(
I,
DL);
13508 if (!AllocationSize)
13509 return indicatePessimisticFixpoint();
13513 if (*AllocationSize == 0)
13514 return indicatePessimisticFixpoint();
13520 return indicatePessimisticFixpoint();
13522 if (BinSize == 0) {
13523 auto NewAllocationSize = std::make_optional<TypeSize>(0,
false);
13524 if (!changeAllocationSize(NewAllocationSize))
13525 return ChangeStatus::UNCHANGED;
13526 return ChangeStatus::CHANGED;
13530 const auto &It = PI->
begin();
13533 if (It->first.Offset != 0)
13534 return indicatePessimisticFixpoint();
13536 uint64_t SizeOfBin = It->first.Offset + It->first.Size;
13538 if (SizeOfBin >= *AllocationSize)
13539 return indicatePessimisticFixpoint();
13541 auto NewAllocationSize = std::make_optional<TypeSize>(SizeOfBin * 8,
false);
13543 if (!changeAllocationSize(NewAllocationSize))
13544 return ChangeStatus::UNCHANGED;
13546 return ChangeStatus::CHANGED;
13552 assert(isValidState() &&
13553 "Manifest should only be called if the state is valid.");
13557 auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
13559 unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
13561 switch (
I->getOpcode()) {
13563 case Instruction::Alloca: {
13567 Type *CharType = Type::getInt8Ty(
I->getContext());
13569 auto *NumBytesToValue =
13570 ConstantInt::get(
I->getContext(), APInt(32, NumBytesToAllocate));
13573 insertPt = std::next(insertPt);
13574 AllocaInst *NewAllocaInst =
13579 return ChangeStatus::CHANGED;
13587 return ChangeStatus::UNCHANGED;
13591 const std::string getAsStr(Attributor *
A)
const override {
13592 if (!isValidState())
13593 return "allocationinfo(<invalid>)";
13594 return "allocationinfo(" +
13595 (AssumedAllocatedSize == HasNoAllocationSize
13597 : std::to_string(AssumedAllocatedSize->getFixedValue())) +
13602 std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
13606 bool changeAllocationSize(std::optional<TypeSize>
Size) {
13607 if (AssumedAllocatedSize == HasNoAllocationSize ||
13608 AssumedAllocatedSize !=
Size) {
13609 AssumedAllocatedSize =
Size;
13616struct AAAllocationInfoFloating : AAAllocationInfoImpl {
13617 AAAllocationInfoFloating(
const IRPosition &IRP, Attributor &
A)
13618 : AAAllocationInfoImpl(IRP,
A) {}
13620 void trackStatistics()
const override {
13625struct AAAllocationInfoReturned : AAAllocationInfoImpl {
13626 AAAllocationInfoReturned(
const IRPosition &IRP, Attributor &
A)
13627 : AAAllocationInfoImpl(IRP,
A) {}
13633 (void)indicatePessimisticFixpoint();
13636 void trackStatistics()
const override {
13641struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl {
13642 AAAllocationInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13643 : AAAllocationInfoImpl(IRP,
A) {}
13645 void trackStatistics()
const override {
13650struct AAAllocationInfoArgument : AAAllocationInfoImpl {
13651 AAAllocationInfoArgument(
const IRPosition &IRP, Attributor &
A)
13652 : AAAllocationInfoImpl(IRP,
A) {}
13654 void trackStatistics()
const override {
13659struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl {
13660 AAAllocationInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13661 : AAAllocationInfoImpl(IRP,
A) {}
13666 (void)indicatePessimisticFixpoint();
13669 void trackStatistics()
const override {
13718#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \
13719 case IRPosition::PK: \
13720 llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");
13722#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \
13723 case IRPosition::PK: \
13724 AA = new (A.Allocator) CLASS##SUFFIX(IRP, A); \
13728#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13729 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13730 CLASS *AA = nullptr; \
13731 switch (IRP.getPositionKind()) { \
13732 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13733 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13734 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13735 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13736 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13737 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13738 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13739 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13744#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13745 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13746 CLASS *AA = nullptr; \
13747 switch (IRP.getPositionKind()) { \
13748 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13749 SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \
13750 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13751 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13752 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13753 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13754 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13755 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13760#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS) \
13761 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13762 CLASS *AA = nullptr; \
13763 switch (IRP.getPositionKind()) { \
13764 SWITCH_PK_CREATE(CLASS, IRP, POS, SUFFIX) \
13766 llvm_unreachable("Cannot create " #CLASS " for position otherthan " #POS \
13772#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13773 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13774 CLASS *AA = nullptr; \
13775 switch (IRP.getPositionKind()) { \
13776 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13777 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13778 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13779 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13780 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13781 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13782 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13783 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13788#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13789 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13790 CLASS *AA = nullptr; \
13791 switch (IRP.getPositionKind()) { \
13792 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13793 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13794 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13795 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13796 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13797 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13798 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13799 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13804#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13805 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13806 CLASS *AA = nullptr; \
13807 switch (IRP.getPositionKind()) { \
13808 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13809 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13810 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13811 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13812 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13813 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13814 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13815 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13867#undef CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION
13868#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
13869#undef CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION
13870#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
13871#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
13872#undef CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION
13873#undef SWITCH_PK_CREATE
13874#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.
LLVM_ABI 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.
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 isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(const CallBase *Call, bool MustPreserveOffset)
{launder,strip}.invariant.group returns pointer that aliases its argument, and it only captures point...
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.
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.
bool capturesAnyProvenance(CaptureComponents CC)
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
CaptureComponents ResultCC
Components captured by the return value of the user of this Use.
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.