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 =
1187 case AA::GPUAddressSpace::Shared:
1188 case AA::GPUAddressSpace::Constant:
1189 case AA::GPUAddressSpace::Local:
1201 std::function<bool(
const Function &)> IsLiveInCalleeCB;
1206 const Function *AIFn = AI->getFunction();
1207 ObjHasKernelLifetime =
A.getInfoCache().isKernel(*AIFn);
1208 bool IsKnownNoRecurse;
1211 IsKnownNoRecurse)) {
1212 IsLiveInCalleeCB = [AIFn](
const Function &Fn) {
return AIFn != &Fn; };
1217 ObjHasKernelLifetime = HasKernelLifetime(GV, *GV->getParent());
1218 if (ObjHasKernelLifetime)
1219 IsLiveInCalleeCB = [&
A](
const Function &Fn) {
1220 return !
A.getInfoCache().isKernel(Fn);
1228 auto AccessCB = [&](
const Access &Acc,
bool Exact) {
1229 Function *AccScope = Acc.getRemoteInst()->getFunction();
1230 bool AccInSameScope = AccScope == &
Scope;
1234 if (InstInKernel && ObjHasKernelLifetime && !AccInSameScope &&
1235 A.getInfoCache().isKernel(*AccScope))
1238 if (Exact && Acc.isMustAccess() && Acc.getRemoteInst() != &
I) {
1239 if (Acc.isWrite() || (
isa<LoadInst>(
I) && Acc.isWriteOrAssumption()))
1240 ExclusionSet.
insert(Acc.getRemoteInst());
1243 if ((!FindInterferingWrites || !Acc.isWriteOrAssumption()) &&
1244 (!FindInterferingReads || !Acc.isRead()))
1247 bool Dominates = FindInterferingWrites && DT && Exact &&
1248 Acc.isMustAccess() && AccInSameScope &&
1251 DominatingWrites.
insert(&Acc);
1255 AllInSameNoSyncFn &= Acc.getRemoteInst()->getFunction() == &
Scope;
1257 InterferingAccesses.
push_back({&Acc, Exact});
1260 if (!State::forallInterferingAccesses(
I, AccessCB,
Range))
1263 HasBeenWrittenTo = !DominatingWrites.
empty();
1267 for (
const Access *Acc : DominatingWrites) {
1268 if (!LeastDominatingWriteInst) {
1269 LeastDominatingWriteInst = Acc->getRemoteInst();
1270 }
else if (DT->
dominates(LeastDominatingWriteInst,
1271 Acc->getRemoteInst())) {
1272 LeastDominatingWriteInst = Acc->getRemoteInst();
1277 auto CanSkipAccess = [&](
const Access &Acc,
bool Exact) {
1278 if (SkipCB && SkipCB(Acc))
1280 if (!CanIgnoreThreading(Acc))
1286 bool ReadChecked = !FindInterferingReads;
1287 bool WriteChecked = !FindInterferingWrites;
1293 &ExclusionSet, IsLiveInCalleeCB))
1298 if (!WriteChecked) {
1300 &ExclusionSet, IsLiveInCalleeCB))
1301 WriteChecked =
true;
1315 if (!WriteChecked && HasBeenWrittenTo &&
1316 Acc.getRemoteInst()->getFunction() != &Scope) {
1318 const auto *FnReachabilityAA =
A.getAAFor<AAInterFnReachability>(
1320 if (FnReachabilityAA) {
1326 if (!FnReachabilityAA->instructionCanReach(
1327 A, *LeastDominatingWriteInst,
1328 *Acc.getRemoteInst()->getFunction(), &ExclusionSet))
1329 WriteChecked =
true;
1336 if (ReadChecked && WriteChecked)
1339 if (!DT || !UseDominanceReasoning)
1341 if (!DominatingWrites.count(&Acc))
1343 return LeastDominatingWriteInst != Acc.getRemoteInst();
1348 for (
auto &It : InterferingAccesses) {
1349 if ((!AllInSameNoSyncFn && !IsThreadLocalObj && !ExecDomainAA) ||
1350 !CanSkipAccess(*It.first, It.second)) {
1351 if (!UserCB(*It.first, It.second))
1359 const AAPointerInfo &OtherAA,
1361 using namespace AA::PointerInfo;
1363 return indicatePessimisticFixpoint();
1366 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1367 bool IsByval = OtherAAImpl.getAssociatedArgument()->hasByValAttr();
1368 Changed |= setReachesReturn(OtherAAImpl.ReturnedOffsets);
1371 const auto &State = OtherAAImpl.getState();
1372 for (
const auto &It : State) {
1373 for (
auto Index : It.getSecond()) {
1374 const auto &RAcc = State.getAccess(Index);
1375 if (IsByval && !RAcc.isRead())
1377 bool UsedAssumedInformation =
false;
1379 auto Content =
A.translateArgumentToCallSiteContent(
1380 RAcc.getContent(), CB, *
this, UsedAssumedInformation);
1381 AK =
AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW));
1382 AK =
AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST));
1384 Changed |= addAccess(
A, RAcc.getRanges(), CB, Content, AK,
1385 RAcc.getType(), RAcc.getRemoteInst());
1391 ChangeStatus translateAndAddState(Attributor &
A,
const AAPointerInfo &OtherAA,
1392 const OffsetInfo &Offsets, CallBase &CB,
1394 using namespace AA::PointerInfo;
1396 return indicatePessimisticFixpoint();
1398 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1402 const auto &State = OtherAAImpl.getState();
1403 for (
const auto &It : State) {
1404 for (
auto Index : It.getSecond()) {
1405 const auto &RAcc = State.getAccess(Index);
1406 if (!IsMustAcc && RAcc.isAssumption())
1408 for (
auto Offset : Offsets) {
1412 if (!NewRanges.isUnknown()) {
1413 NewRanges.addToAllOffsets(Offset);
1418 Changed |= addAccess(
A, NewRanges, CB, RAcc.getContent(), AK,
1419 RAcc.getType(), RAcc.getRemoteInst());
1428 void trackPointerInfoStatistics(
const IRPosition &IRP)
const {}
1431 void dumpState(raw_ostream &O) {
1432 for (
auto &It : OffsetBins) {
1433 O <<
"[" << It.first.Offset <<
"-" << It.first.Offset + It.first.Size
1434 <<
"] : " << It.getSecond().size() <<
"\n";
1435 for (
auto AccIndex : It.getSecond()) {
1436 auto &Acc = AccessList[AccIndex];
1437 O <<
" - " << Acc.getKind() <<
" - " << *Acc.getLocalInst() <<
"\n";
1438 if (Acc.getLocalInst() != Acc.getRemoteInst())
1439 O <<
" --> " << *Acc.getRemoteInst()
1441 if (!Acc.isWrittenValueYetUndetermined()) {
1443 O <<
" - c: func " << Acc.getWrittenValue()->getName()
1445 else if (Acc.getWrittenValue())
1446 O <<
" - c: " << *Acc.getWrittenValue() <<
"\n";
1448 O <<
" - c: <unknown>\n";
1455struct AAPointerInfoFloating :
public AAPointerInfoImpl {
1457 AAPointerInfoFloating(
const IRPosition &IRP, Attributor &
A)
1458 : AAPointerInfoImpl(IRP,
A) {}
1461 bool handleAccess(Attributor &
A, Instruction &
I,
1462 std::optional<Value *> Content,
AccessKind Kind,
1465 using namespace AA::PointerInfo;
1467 const DataLayout &
DL =
A.getDataLayout();
1468 TypeSize AccessSize =
DL.getTypeStoreSize(&Ty);
1477 if (!VT || VT->getElementCount().isScalable() ||
1479 (*Content)->getType() != VT ||
1480 DL.getTypeStoreSize(VT->getElementType()).isScalable()) {
1491 int64_t ElementSize =
DL.getTypeStoreSize(ElementType).getFixedValue();
1496 for (
int i = 0, e = VT->getElementCount().getFixedValue(); i != e; ++i) {
1498 ConstContent, ConstantInt::get(
Int32Ty, i));
1505 for (
auto &ElementOffset : ElementOffsets)
1506 ElementOffset += ElementSize;
1519 bool collectConstantsForGEP(Attributor &
A,
const DataLayout &
DL,
1520 OffsetInfo &UsrOI,
const OffsetInfo &PtrOI,
1521 const GEPOperator *
GEP);
1524 void trackStatistics()
const override {
1525 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1529bool AAPointerInfoFloating::collectConstantsForGEP(Attributor &
A,
1530 const DataLayout &
DL,
1532 const OffsetInfo &PtrOI,
1533 const GEPOperator *
GEP) {
1534 unsigned BitWidth =
DL.getIndexTypeSizeInBits(
GEP->getType());
1535 SmallMapVector<Value *, APInt, 4> VariableOffsets;
1538 assert(!UsrOI.isUnknown() && !PtrOI.isUnknown() &&
1539 "Don't look for constant values if the offset has already been "
1540 "determined to be unknown.");
1542 if (!
GEP->collectOffset(
DL,
BitWidth, VariableOffsets, ConstantOffset)) {
1548 << (VariableOffsets.
empty() ?
"" :
"not") <<
" constant "
1552 Union.addToAll(ConstantOffset.getSExtValue());
1557 for (
const auto &VI : VariableOffsets) {
1558 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
1560 if (!PotentialConstantsAA || !PotentialConstantsAA->isValidState()) {
1566 if (PotentialConstantsAA->undefIsContained())
1573 auto &AssumedSet = PotentialConstantsAA->getAssumedSet();
1574 if (AssumedSet.empty())
1578 for (
const auto &ConstOffset : AssumedSet) {
1579 auto CopyPerOffset =
Union;
1580 CopyPerOffset.addToAll(ConstOffset.getSExtValue() *
1581 VI.second.getZExtValue());
1582 Product.merge(CopyPerOffset);
1587 UsrOI = std::move(Union);
1591ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &
A) {
1592 using namespace AA::PointerInfo;
1594 const DataLayout &
DL =
A.getDataLayout();
1595 Value &AssociatedValue = getAssociatedValue();
1597 DenseMap<Value *, OffsetInfo> OffsetInfoMap;
1598 OffsetInfoMap[&AssociatedValue].
insert(0);
1600 auto HandlePassthroughUser = [&](
Value *Usr,
Value *CurPtr,
bool &Follow) {
1611 "CurPtr does not exist in the map!");
1613 auto &UsrOI = OffsetInfoMap[Usr];
1614 auto &PtrOI = OffsetInfoMap[CurPtr];
1615 assert(!PtrOI.isUnassigned() &&
1616 "Cannot pass through if the input Ptr was not visited!");
1622 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
1624 User *Usr =
U.getUser();
1625 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Analyze " << *CurPtr <<
" in " << *Usr
1628 "The current pointer offset should have been seeded!");
1629 assert(!OffsetInfoMap[CurPtr].isUnassigned() &&
1630 "Current pointer should be assigned");
1634 return HandlePassthroughUser(Usr, CurPtr, Follow);
1636 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled constant user " << *CE
1644 auto &UsrOI = OffsetInfoMap[Usr];
1645 auto &PtrOI = OffsetInfoMap[CurPtr];
1647 if (UsrOI.isUnknown())
1650 if (PtrOI.isUnknown()) {
1656 Follow = collectConstantsForGEP(
A,
DL, UsrOI, PtrOI,
GEP);
1662 return HandlePassthroughUser(Usr, CurPtr, Follow);
1667 if (RI->getFunction() == getAssociatedFunction()) {
1668 auto &PtrOI = OffsetInfoMap[CurPtr];
1669 Changed |= setReachesReturn(PtrOI);
1682 auto &UsrOI = PhiIt->second;
1683 auto &PtrOI = OffsetInfoMap[CurPtr];
1687 if (PtrOI.isUnknown()) {
1688 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand offset unknown "
1689 << *CurPtr <<
" in " << *
PHI <<
"\n");
1690 Follow = !UsrOI.isUnknown();
1696 if (UsrOI == PtrOI) {
1697 assert(!PtrOI.isUnassigned() &&
1698 "Cannot assign if the current Ptr was not visited!");
1699 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant (so far)");
1709 auto It = OffsetInfoMap.
find(CurPtrBase);
1710 if (It == OffsetInfoMap.
end()) {
1711 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand is too complex "
1712 << *CurPtr <<
" in " << *
PHI
1713 <<
" (base: " << *CurPtrBase <<
")\n");
1727 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
1728 *
PHI->getFunction());
1730 auto BaseOI = It->getSecond();
1731 BaseOI.addToAll(
Offset.getZExtValue());
1732 if (IsFirstPHIUser || BaseOI == UsrOI) {
1733 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant " << *CurPtr
1734 <<
" in " << *Usr <<
"\n");
1735 return HandlePassthroughUser(Usr, CurPtr, Follow);
1739 dbgs() <<
"[AAPointerInfo] PHI operand pointer offset mismatch "
1740 << *CurPtr <<
" in " << *
PHI <<
"\n");
1759 if (!handleAccess(
A, *LoadI,
nullptr, AK,
1760 OffsetInfoMap[CurPtr].Offsets,
Changed,
1766 return II->isAssumeLikeIntrinsic();
1777 }
while (FromI && FromI != ToI);
1782 auto IsValidAssume = [&](IntrinsicInst &IntrI) {
1783 if (IntrI.getIntrinsicID() != Intrinsic::assume)
1786 if (IntrI.getParent() == BB) {
1787 if (IsImpactedInRange(LoadI->getNextNode(), &IntrI))
1793 if ((*PredIt) != BB)
1798 if (SuccBB == IntrBB)
1804 if (IsImpactedInRange(LoadI->getNextNode(), BB->
getTerminator()))
1806 if (IsImpactedInRange(&IntrBB->
front(), &IntrI))
1812 std::pair<Value *, IntrinsicInst *> Assumption;
1813 for (
const Use &LoadU : LoadI->uses()) {
1815 if (!CmpI->isEquality() || !CmpI->isTrueWhenEqual())
1817 for (
const Use &CmpU : CmpI->uses()) {
1819 if (!IsValidAssume(*IntrI))
1821 int Idx = CmpI->getOperandUse(0) == LoadU;
1822 Assumption = {CmpI->getOperand(Idx), IntrI};
1827 if (Assumption.first)
1832 if (!Assumption.first || !Assumption.second)
1836 << *Assumption.second <<
": " << *LoadI
1837 <<
" == " << *Assumption.first <<
"\n");
1838 bool UsedAssumedInformation =
false;
1839 std::optional<Value *> Content =
nullptr;
1840 if (Assumption.first)
1842 A.getAssumedSimplified(*Assumption.first, *
this,
1844 return handleAccess(
1845 A, *Assumption.second, Content, AccessKind::AK_ASSUMPTION,
1846 OffsetInfoMap[CurPtr].Offsets,
Changed, *LoadI->getType());
1851 for (
auto *OtherOp : OtherOps) {
1852 if (OtherOp == CurPtr) {
1855 <<
"[AAPointerInfo] Escaping use in store like instruction " <<
I
1867 bool UsedAssumedInformation =
false;
1868 std::optional<Value *> Content =
nullptr;
1870 Content =
A.getAssumedSimplified(
1872 return handleAccess(
A,
I, Content, AK, OffsetInfoMap[CurPtr].Offsets,
1877 return HandleStoreLike(*StoreI, StoreI->getValueOperand(),
1878 *StoreI->getValueOperand()->getType(),
1879 {StoreI->getValueOperand()}, AccessKind::AK_W);
1881 return HandleStoreLike(*RMWI,
nullptr, *RMWI->getValOperand()->getType(),
1882 {RMWI->getValOperand()}, AccessKind::AK_RW);
1884 return HandleStoreLike(
1885 *CXI,
nullptr, *CXI->getNewValOperand()->getType(),
1886 {CXI->getCompareOperand(), CXI->getNewValOperand()},
1893 A.getInfoCache().getTargetLibraryInfoForFunction(*CB->
getFunction());
1898 const auto *CSArgPI =
A.getAAFor<AAPointerInfo>(
1904 Changed = translateAndAddState(
A, *CSArgPI, OffsetInfoMap[CurPtr], *CB,
1907 if (!CSArgPI->reachesReturn())
1908 return isValidState();
1911 if (!Callee ||
Callee->arg_size() <= ArgNo)
1913 bool UsedAssumedInformation =
false;
1914 auto ReturnedValue =
A.getAssumedSimplified(
1919 auto *Arg =
Callee->getArg(ArgNo);
1920 if (ReturnedArg && Arg != ReturnedArg)
1922 bool IsRetMustAcc = IsArgMustAcc && (ReturnedArg == Arg);
1923 const auto *CSRetPI =
A.getAAFor<AAPointerInfo>(
1927 OffsetInfo OI = OffsetInfoMap[CurPtr];
1928 CSArgPI->addReturnedOffsetsTo(OI);
1930 translateAndAddState(
A, *CSRetPI, OI, *CB, IsRetMustAcc) |
Changed;
1931 return isValidState();
1933 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Call user not handled " << *CB
1938 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] User not handled " << *Usr <<
"\n");
1941 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
1942 assert(OffsetInfoMap.
count(OldU) &&
"Old use should be known already!");
1943 assert(!OffsetInfoMap[OldU].isUnassigned() &&
"Old use should be assinged");
1944 if (OffsetInfoMap.
count(NewU)) {
1946 if (!(OffsetInfoMap[NewU] == OffsetInfoMap[OldU])) {
1947 dbgs() <<
"[AAPointerInfo] Equivalent use callback failed: "
1948 << OffsetInfoMap[NewU] <<
" vs " << OffsetInfoMap[OldU]
1952 return OffsetInfoMap[NewU] == OffsetInfoMap[OldU];
1955 return HandlePassthroughUser(NewU.get(), OldU.
get(), Unused);
1957 if (!
A.checkForAllUses(UsePred, *
this, AssociatedValue,
1959 true, EquivalentUseCB)) {
1960 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Check for all uses failed, abort!\n");
1961 return indicatePessimisticFixpoint();
1965 dbgs() <<
"Accesses by bin after update:\n";
1972struct AAPointerInfoReturned final : AAPointerInfoImpl {
1973 AAPointerInfoReturned(
const IRPosition &IRP, Attributor &
A)
1974 : AAPointerInfoImpl(IRP,
A) {}
1978 return indicatePessimisticFixpoint();
1982 void trackStatistics()
const override {
1983 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1987struct AAPointerInfoArgument final : AAPointerInfoFloating {
1988 AAPointerInfoArgument(
const IRPosition &IRP, Attributor &
A)
1989 : AAPointerInfoFloating(IRP,
A) {}
1992 void trackStatistics()
const override {
1993 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1997struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
1998 AAPointerInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
1999 : AAPointerInfoFloating(IRP,
A) {}
2003 using namespace AA::PointerInfo;
2009 if (
auto Length =
MI->getLengthInBytes())
2010 LengthVal =
Length->getSExtValue();
2011 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
2014 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled memory intrinsic "
2016 return indicatePessimisticFixpoint();
2019 ArgNo == 0 ? AccessKind::AK_MUST_WRITE : AccessKind::AK_MUST_READ;
2021 Changed | addAccess(
A, {0, LengthVal}, *
MI,
nullptr,
Kind,
nullptr);
2024 dbgs() <<
"Accesses by bin after update:\n";
2035 Argument *Arg = getAssociatedArgument();
2039 A.getAAFor<AAPointerInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
2040 if (ArgAA && ArgAA->getState().isValidState())
2041 return translateAndAddStateFromCallee(
A, *ArgAA,
2044 return indicatePessimisticFixpoint();
2047 bool IsKnownNoCapture;
2049 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNoCapture))
2050 return indicatePessimisticFixpoint();
2052 bool IsKnown =
false;
2054 return ChangeStatus::UNCHANGED;
2057 ReadOnly ? AccessKind::AK_MAY_READ : AccessKind::AK_MAY_READ_WRITE;
2063 void trackStatistics()
const override {
2064 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2068struct AAPointerInfoCallSiteReturned final : AAPointerInfoFloating {
2069 AAPointerInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2070 : AAPointerInfoFloating(IRP,
A) {}
2073 void trackStatistics()
const override {
2074 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2082struct AANoUnwindImpl : AANoUnwind {
2083 AANoUnwindImpl(
const IRPosition &IRP, Attributor &
A) : AANoUnwind(IRP,
A) {}
2089 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2093 const std::string getAsStr(Attributor *
A)
const override {
2094 return getAssumed() ?
"nounwind" :
"may-unwind";
2100 (unsigned)Instruction::Invoke, (
unsigned)Instruction::CallBr,
2101 (unsigned)Instruction::Call, (
unsigned)Instruction::CleanupRet,
2102 (unsigned)Instruction::CatchSwitch, (
unsigned)Instruction::Resume};
2105 if (!
I.mayThrow(
true))
2109 bool IsKnownNoUnwind;
2117 bool UsedAssumedInformation =
false;
2118 if (!
A.checkForAllInstructions(CheckForNoUnwind, *
this, Opcodes,
2119 UsedAssumedInformation))
2120 return indicatePessimisticFixpoint();
2122 return ChangeStatus::UNCHANGED;
2126struct AANoUnwindFunction final :
public AANoUnwindImpl {
2127 AANoUnwindFunction(
const IRPosition &IRP, Attributor &
A)
2128 : AANoUnwindImpl(IRP,
A) {}
2135struct AANoUnwindCallSite final
2136 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl> {
2137 AANoUnwindCallSite(
const IRPosition &IRP, Attributor &
A)
2138 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl>(IRP,
A) {}
2149 case Intrinsic::nvvm_barrier_cta_sync_aligned_all:
2150 case Intrinsic::nvvm_barrier_cta_sync_aligned_count:
2151 case Intrinsic::nvvm_barrier_cta_red_and_aligned_all:
2152 case Intrinsic::nvvm_barrier_cta_red_and_aligned_count:
2153 case Intrinsic::nvvm_barrier_cta_red_or_aligned_all:
2154 case Intrinsic::nvvm_barrier_cta_red_or_aligned_count:
2155 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_all:
2156 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_count:
2158 case Intrinsic::amdgcn_s_barrier:
2159 if (ExecutedAligned)
2182 switch (
I->getOpcode()) {
2183 case Instruction::AtomicRMW:
2186 case Instruction::Store:
2189 case Instruction::Load:
2194 "New atomic operations need to be known in the attributor.");
2206 return !
MI->isVolatile();
2222 const std::string getAsStr(Attributor *
A)
const override {
2223 return getAssumed() ?
"nosync" :
"may-sync";
2239 if (
I.mayReadOrWriteMemory())
2253 bool UsedAssumedInformation =
false;
2254 if (!
A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *
this,
2255 UsedAssumedInformation) ||
2256 !
A.checkForAllCallLikeInstructions(CheckForNoSync, *
this,
2257 UsedAssumedInformation))
2258 return indicatePessimisticFixpoint();
2263struct AANoSyncFunction final :
public AANoSyncImpl {
2264 AANoSyncFunction(
const IRPosition &IRP, Attributor &
A)
2265 : AANoSyncImpl(IRP,
A) {}
2272struct AANoSyncCallSite final : AACalleeToCallSite<AANoSync, AANoSyncImpl> {
2273 AANoSyncCallSite(
const IRPosition &IRP, Attributor &
A)
2274 : AACalleeToCallSite<AANoSync, AANoSyncImpl>(IRP,
A) {}
2284struct AANoFreeImpl :
public AANoFree {
2285 AANoFreeImpl(
const IRPosition &IRP, Attributor &
A) : AANoFree(IRP,
A) {}
2291 DepClassTy::NONE, IsKnown));
2301 DepClassTy::REQUIRED, IsKnown);
2304 bool UsedAssumedInformation =
false;
2305 if (!
A.checkForAllCallLikeInstructions(CheckForNoFree, *
this,
2306 UsedAssumedInformation))
2307 return indicatePessimisticFixpoint();
2308 return ChangeStatus::UNCHANGED;
2312 const std::string getAsStr(Attributor *
A)
const override {
2313 return getAssumed() ?
"nofree" :
"may-free";
2317struct AANoFreeFunction final :
public AANoFreeImpl {
2318 AANoFreeFunction(
const IRPosition &IRP, Attributor &
A)
2319 : AANoFreeImpl(IRP,
A) {}
2326struct AANoFreeCallSite final : AACalleeToCallSite<AANoFree, AANoFreeImpl> {
2327 AANoFreeCallSite(
const IRPosition &IRP, Attributor &
A)
2328 : AACalleeToCallSite<AANoFree, AANoFreeImpl>(IRP,
A) {}
2335struct AANoFreeFloating : AANoFreeImpl {
2336 AANoFreeFloating(
const IRPosition &IRP, Attributor &
A)
2337 : AANoFreeImpl(IRP,
A) {}
2344 const IRPosition &IRP = getIRPosition();
2349 DepClassTy::OPTIONAL, IsKnown))
2350 return ChangeStatus::UNCHANGED;
2352 Value &AssociatedValue = getIRPosition().getAssociatedValue();
2353 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
2365 DepClassTy::REQUIRED, IsKnown);
2382 if (!
A.checkForAllUses(Pred, *
this, AssociatedValue))
2383 return indicatePessimisticFixpoint();
2385 return ChangeStatus::UNCHANGED;
2390struct AANoFreeArgument final : AANoFreeFloating {
2391 AANoFreeArgument(
const IRPosition &IRP, Attributor &
A)
2392 : AANoFreeFloating(IRP,
A) {}
2399struct AANoFreeCallSiteArgument final : AANoFreeFloating {
2400 AANoFreeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2401 : AANoFreeFloating(IRP,
A) {}
2409 Argument *Arg = getAssociatedArgument();
2411 return indicatePessimisticFixpoint();
2415 DepClassTy::REQUIRED, IsKnown))
2416 return ChangeStatus::UNCHANGED;
2417 return indicatePessimisticFixpoint();
2425struct AANoFreeReturned final : AANoFreeFloating {
2426 AANoFreeReturned(
const IRPosition &IRP, Attributor &
A)
2427 : AANoFreeFloating(IRP,
A) {
2442 void trackStatistics()
const override {}
2446struct AANoFreeCallSiteReturned final : AANoFreeFloating {
2447 AANoFreeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2448 : AANoFreeFloating(IRP,
A) {}
2451 return ChangeStatus::UNCHANGED;
2462 bool IgnoreSubsumingPositions) {
2464 AttrKinds.
push_back(Attribute::NonNull);
2467 AttrKinds.
push_back(Attribute::Dereferenceable);
2468 if (
A.hasAttr(IRP, AttrKinds, IgnoreSubsumingPositions, Attribute::NonNull))
2475 if (!Fn->isDeclaration()) {
2485 bool UsedAssumedInformation =
false;
2486 if (!
A.checkForAllInstructions(
2488 Worklist.push_back({*cast<ReturnInst>(I).getReturnValue(), &I});
2492 UsedAssumedInformation,
false,
true))
2504 Attribute::NonNull)});
2509static int64_t getKnownNonNullAndDerefBytesForUse(
2510 Attributor &
A,
const AbstractAttribute &QueryingAA,
Value &AssociatedValue,
2511 const Use *U,
const Instruction *
I,
bool &IsNonNull,
bool &TrackUse) {
2514 const Value *UseV =
U->get();
2535 const DataLayout &
DL =
A.getInfoCache().getDL();
2539 U, {Attribute::NonNull, Attribute::Dereferenceable})) {
2556 bool IsKnownNonNull;
2559 IsNonNull |= IsKnownNonNull;
2562 return DerefAA ? DerefAA->getKnownDereferenceableBytes() : 0;
2566 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
2567 Loc->Size.isScalable() ||
I->isVolatile())
2573 if (
Base &&
Base == &AssociatedValue) {
2574 int64_t DerefBytes = Loc->Size.getValue() +
Offset;
2576 return std::max(int64_t(0), DerefBytes);
2583 int64_t DerefBytes = Loc->Size.getValue();
2585 return std::max(int64_t(0), DerefBytes);
2591struct AANonNullImpl : AANonNull {
2592 AANonNullImpl(
const IRPosition &IRP, Attributor &
A) : AANonNull(IRP,
A) {}
2596 Value &
V = *getAssociatedValue().stripPointerCasts();
2598 indicatePessimisticFixpoint();
2602 if (Instruction *CtxI = getCtxI())
2603 followUsesInMBEC(*
this,
A, getState(), *CtxI);
2607 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
2608 AANonNull::StateType &State) {
2609 bool IsNonNull =
false;
2610 bool TrackUse =
false;
2611 getKnownNonNullAndDerefBytesForUse(
A, *
this, getAssociatedValue(), U,
I,
2612 IsNonNull, TrackUse);
2613 State.setKnown(IsNonNull);
2618 const std::string getAsStr(Attributor *
A)
const override {
2619 return getAssumed() ?
"nonnull" :
"may-null";
2624struct AANonNullFloating :
public AANonNullImpl {
2625 AANonNullFloating(
const IRPosition &IRP, Attributor &
A)
2626 : AANonNullImpl(IRP,
A) {}
2630 auto CheckIRP = [&](
const IRPosition &IRP) {
2631 bool IsKnownNonNull;
2633 A, *
this, IRP, DepClassTy::OPTIONAL, IsKnownNonNull);
2637 bool UsedAssumedInformation =
false;
2638 Value *AssociatedValue = &getAssociatedValue();
2640 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
2645 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
2651 return AA::hasAssumedIRAttr<Attribute::NonNull>(
2652 A, this, IRPosition::value(*Op), DepClassTy::OPTIONAL,
2655 return ChangeStatus::UNCHANGED;
2659 DepClassTy::OPTIONAL, IsKnown) &&
2662 DepClassTy::OPTIONAL, IsKnown))
2663 return ChangeStatus::UNCHANGED;
2670 if (AVIRP == getIRPosition() || !CheckIRP(AVIRP))
2671 return indicatePessimisticFixpoint();
2672 return ChangeStatus::UNCHANGED;
2675 for (
const auto &VAC : Values)
2677 return indicatePessimisticFixpoint();
2679 return ChangeStatus::UNCHANGED;
2687struct AANonNullReturned final
2688 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2689 false, AANonNull::IRAttributeKind, false> {
2690 AANonNullReturned(
const IRPosition &IRP, Attributor &
A)
2691 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2696 const std::string getAsStr(Attributor *
A)
const override {
2697 return getAssumed() ?
"nonnull" :
"may-null";
2705struct AANonNullArgument final
2706 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
2707 AANonNullArgument(
const IRPosition &IRP, Attributor &
A)
2708 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP,
A) {}
2714struct AANonNullCallSiteArgument final : AANonNullFloating {
2715 AANonNullCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2716 : AANonNullFloating(IRP,
A) {}
2723struct AANonNullCallSiteReturned final
2724 : AACalleeToCallSite<AANonNull, AANonNullImpl> {
2725 AANonNullCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2726 : AACalleeToCallSite<AANonNull, AANonNullImpl>(IRP,
A) {}
2735struct AAMustProgressImpl :
public AAMustProgress {
2736 AAMustProgressImpl(
const IRPosition &IRP, Attributor &
A)
2737 : AAMustProgress(IRP,
A) {}
2743 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2748 const std::string getAsStr(Attributor *
A)
const override {
2749 return getAssumed() ?
"mustprogress" :
"may-not-progress";
2753struct AAMustProgressFunction final : AAMustProgressImpl {
2754 AAMustProgressFunction(
const IRPosition &IRP, Attributor &
A)
2755 : AAMustProgressImpl(IRP,
A) {}
2761 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnown)) {
2763 return indicateOptimisticFixpoint();
2764 return ChangeStatus::UNCHANGED;
2767 auto CheckForMustProgress = [&](AbstractCallSite ACS) {
2769 bool IsKnownMustProgress;
2771 A,
this, IPos, DepClassTy::REQUIRED, IsKnownMustProgress,
2775 bool AllCallSitesKnown =
true;
2776 if (!
A.checkForAllCallSites(CheckForMustProgress, *
this,
2779 return indicatePessimisticFixpoint();
2781 return ChangeStatus::UNCHANGED;
2785 void trackStatistics()
const override {
2791struct AAMustProgressCallSite final : AAMustProgressImpl {
2792 AAMustProgressCallSite(
const IRPosition &IRP, Attributor &
A)
2793 : AAMustProgressImpl(IRP,
A) {}
2802 bool IsKnownMustProgress;
2804 A,
this, FnPos, DepClassTy::REQUIRED, IsKnownMustProgress))
2805 return indicatePessimisticFixpoint();
2806 return ChangeStatus::UNCHANGED;
2810 void trackStatistics()
const override {
2819struct AANoRecurseImpl :
public AANoRecurse {
2820 AANoRecurseImpl(
const IRPosition &IRP, Attributor &
A) : AANoRecurse(IRP,
A) {}
2826 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2831 const std::string getAsStr(Attributor *
A)
const override {
2832 return getAssumed() ?
"norecurse" :
"may-recurse";
2836struct AANoRecurseFunction final : AANoRecurseImpl {
2837 AANoRecurseFunction(
const IRPosition &IRP, Attributor &
A)
2838 : AANoRecurseImpl(IRP,
A) {}
2844 auto CallSitePred = [&](AbstractCallSite ACS) {
2845 bool IsKnownNoRecurse;
2849 DepClassTy::NONE, IsKnownNoRecurse))
2851 return IsKnownNoRecurse;
2853 bool UsedAssumedInformation =
false;
2854 if (
A.checkForAllCallSites(CallSitePred, *
this,
true,
2855 UsedAssumedInformation)) {
2861 if (!UsedAssumedInformation)
2862 indicateOptimisticFixpoint();
2863 return ChangeStatus::UNCHANGED;
2866 const AAInterFnReachability *EdgeReachability =
2867 A.getAAFor<AAInterFnReachability>(*
this, getIRPosition(),
2868 DepClassTy::REQUIRED);
2869 if (EdgeReachability && EdgeReachability->
canReach(
A, *getAnchorScope()))
2870 return indicatePessimisticFixpoint();
2871 return ChangeStatus::UNCHANGED;
2878struct AANoRecurseCallSite final
2879 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl> {
2880 AANoRecurseCallSite(
const IRPosition &IRP, Attributor &
A)
2881 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl>(IRP,
A) {}
2891struct AANonConvergentImpl :
public AANonConvergent {
2892 AANonConvergentImpl(
const IRPosition &IRP, Attributor &
A)
2893 : AANonConvergent(IRP,
A) {}
2896 const std::string getAsStr(Attributor *
A)
const override {
2897 return getAssumed() ?
"non-convergent" :
"may-be-convergent";
2901struct AANonConvergentFunction final : AANonConvergentImpl {
2902 AANonConvergentFunction(
const IRPosition &IRP, Attributor &
A)
2903 : AANonConvergentImpl(IRP,
A) {}
2909 auto CalleeIsNotConvergent = [&](
Instruction &Inst) {
2912 if (!Callee ||
Callee->isIntrinsic()) {
2915 if (
Callee->isDeclaration()) {
2916 return !
Callee->hasFnAttribute(Attribute::Convergent);
2918 const auto *ConvergentAA =
A.getAAFor<AANonConvergent>(
2920 return ConvergentAA && ConvergentAA->isAssumedNotConvergent();
2923 bool UsedAssumedInformation =
false;
2924 if (!
A.checkForAllCallLikeInstructions(CalleeIsNotConvergent, *
this,
2925 UsedAssumedInformation)) {
2926 return indicatePessimisticFixpoint();
2928 return ChangeStatus::UNCHANGED;
2932 if (isKnownNotConvergent() &&
2933 A.hasAttr(getIRPosition(), Attribute::Convergent)) {
2934 A.removeAttrs(getIRPosition(), {Attribute::Convergent});
2935 return ChangeStatus::CHANGED;
2937 return ChangeStatus::UNCHANGED;
2947struct AAUndefinedBehaviorImpl :
public AAUndefinedBehavior {
2948 AAUndefinedBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
2949 : AAUndefinedBehavior(IRP,
A) {}
2954 const size_t UBPrevSize = KnownUBInsts.size();
2955 const size_t NoUBPrevSize = AssumedNoUBInsts.size();
2959 if (
I.isVolatile() &&
I.mayWriteToMemory())
2963 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
2972 "Expected pointer operand of memory accessing instruction");
2976 std::optional<Value *> SimplifiedPtrOp =
2977 stopOnUndefOrAssumed(
A, PtrOp, &
I);
2978 if (!SimplifiedPtrOp || !*SimplifiedPtrOp)
2980 const Value *PtrOpVal = *SimplifiedPtrOp;
2986 AssumedNoUBInsts.insert(&
I);
2998 AssumedNoUBInsts.insert(&
I);
3000 KnownUBInsts.insert(&
I);
3009 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3017 std::optional<Value *> SimplifiedCond =
3018 stopOnUndefOrAssumed(
A, BrInst->getCondition(), BrInst);
3019 if (!SimplifiedCond || !*SimplifiedCond)
3021 AssumedNoUBInsts.insert(&
I);
3029 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3038 for (
unsigned idx = 0; idx < CB.
arg_size(); idx++) {
3044 if (idx >=
Callee->arg_size())
3056 bool IsKnownNoUndef;
3058 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNoUndef);
3059 if (!IsKnownNoUndef)
3061 bool UsedAssumedInformation =
false;
3062 std::optional<Value *> SimplifiedVal =
3065 if (UsedAssumedInformation)
3067 if (SimplifiedVal && !*SimplifiedVal)
3070 KnownUBInsts.insert(&
I);
3076 bool IsKnownNonNull;
3078 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNonNull);
3080 KnownUBInsts.insert(&
I);
3089 std::optional<Value *> SimplifiedRetValue =
3090 stopOnUndefOrAssumed(
A, RI.getReturnValue(), &
I);
3091 if (!SimplifiedRetValue || !*SimplifiedRetValue)
3109 bool IsKnownNonNull;
3114 KnownUBInsts.insert(&
I);
3120 bool UsedAssumedInformation =
false;
3121 A.checkForAllInstructions(InspectMemAccessInstForUB, *
this,
3122 {Instruction::Load, Instruction::Store,
3123 Instruction::AtomicCmpXchg,
3124 Instruction::AtomicRMW},
3125 UsedAssumedInformation,
3127 A.checkForAllInstructions(InspectBrInstForUB, *
this, {Instruction::CondBr},
3128 UsedAssumedInformation,
3130 A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *
this,
3131 UsedAssumedInformation);
3135 if (!getAnchorScope()->getReturnType()->isVoidTy()) {
3137 if (!
A.isAssumedDead(ReturnIRP,
this,
nullptr, UsedAssumedInformation)) {
3138 bool IsKnownNoUndef;
3140 A,
this, ReturnIRP, DepClassTy::NONE, IsKnownNoUndef);
3142 A.checkForAllInstructions(InspectReturnInstForUB, *
this,
3143 {Instruction::Ret}, UsedAssumedInformation,
3148 if (NoUBPrevSize != AssumedNoUBInsts.size() ||
3149 UBPrevSize != KnownUBInsts.size())
3150 return ChangeStatus::CHANGED;
3151 return ChangeStatus::UNCHANGED;
3154 bool isKnownToCauseUB(Instruction *
I)
const override {
3155 return KnownUBInsts.count(
I);
3158 bool isAssumedToCauseUB(Instruction *
I)
const override {
3165 switch (
I->getOpcode()) {
3166 case Instruction::Load:
3167 case Instruction::Store:
3168 case Instruction::AtomicCmpXchg:
3169 case Instruction::AtomicRMW:
3170 case Instruction::CondBr:
3171 return !AssumedNoUBInsts.count(
I);
3179 if (KnownUBInsts.empty())
3180 return ChangeStatus::UNCHANGED;
3181 for (Instruction *
I : KnownUBInsts)
3182 A.changeToUnreachableAfterManifest(
I);
3183 return ChangeStatus::CHANGED;
3187 const std::string getAsStr(Attributor *
A)
const override {
3188 return getAssumed() ?
"undefined-behavior" :
"no-ub";
3216 SmallPtrSet<Instruction *, 8> KnownUBInsts;
3220 SmallPtrSet<Instruction *, 8> AssumedNoUBInsts;
3231 std::optional<Value *> stopOnUndefOrAssumed(Attributor &
A,
Value *V,
3233 bool UsedAssumedInformation =
false;
3234 std::optional<Value *> SimplifiedV =
3237 if (!UsedAssumedInformation) {
3242 KnownUBInsts.insert(
I);
3243 return std::nullopt;
3250 KnownUBInsts.insert(
I);
3251 return std::nullopt;
3257struct AAUndefinedBehaviorFunction final : AAUndefinedBehaviorImpl {
3258 AAUndefinedBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
3259 : AAUndefinedBehaviorImpl(IRP,
A) {}
3262 void trackStatistics()
const override {
3263 STATS_DECL(UndefinedBehaviorInstruction, Instruction,
3264 "Number of instructions known to have UB");
3266 KnownUBInsts.size();
3277static bool mayContainUnboundedCycle(Function &
F, Attributor &
A) {
3278 ScalarEvolution *SE =
3279 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
F);
3280 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
F);
3286 for (scc_iterator<Function *> SCCI =
scc_begin(&
F); !SCCI.isAtEnd(); ++SCCI)
3287 if (SCCI.hasCycle())
3297 for (
auto *L : LI->getLoopsInPreorder()) {
3304struct AAWillReturnImpl :
public AAWillReturn {
3305 AAWillReturnImpl(
const IRPosition &IRP, Attributor &
A)
3306 : AAWillReturn(IRP,
A) {}
3312 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
3317 bool isImpliedByMustprogressAndReadonly(Attributor &
A,
bool KnownOnly) {
3318 if (!
A.hasAttr(getIRPosition(), {Attribute::MustProgress}))
3323 return IsKnown || !KnownOnly;
3329 if (isImpliedByMustprogressAndReadonly(
A,
false))
3330 return ChangeStatus::UNCHANGED;
3336 A,
this, IPos, DepClassTy::REQUIRED, IsKnown)) {
3342 bool IsKnownNoRecurse;
3344 A,
this, IPos, DepClassTy::REQUIRED, IsKnownNoRecurse);
3347 bool UsedAssumedInformation =
false;
3348 if (!
A.checkForAllCallLikeInstructions(CheckForWillReturn, *
this,
3349 UsedAssumedInformation))
3350 return indicatePessimisticFixpoint();
3352 return ChangeStatus::UNCHANGED;
3356 const std::string getAsStr(Attributor *
A)
const override {
3357 return getAssumed() ?
"willreturn" :
"may-noreturn";
3361struct AAWillReturnFunction final : AAWillReturnImpl {
3362 AAWillReturnFunction(
const IRPosition &IRP, Attributor &
A)
3363 : AAWillReturnImpl(IRP,
A) {}
3367 AAWillReturnImpl::initialize(
A);
3370 assert(
F &&
"Did expect an anchor function");
3371 if (
F->isDeclaration() || mayContainUnboundedCycle(*
F,
A))
3372 indicatePessimisticFixpoint();
3380struct AAWillReturnCallSite final
3381 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl> {
3382 AAWillReturnCallSite(
const IRPosition &IRP, Attributor &
A)
3383 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl>(IRP,
A) {}
3387 if (isImpliedByMustprogressAndReadonly(
A,
false))
3388 return ChangeStatus::UNCHANGED;
3390 return AACalleeToCallSite::updateImpl(
A);
3412 const ToTy *
To =
nullptr;
3439 if (!ES || ES->
empty()) {
3440 ExclusionSet = nullptr;
3441 }
else if (MakeUnique) {
3442 ExclusionSet =
A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ES);
3467 if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))
3469 return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);
3473#define DefineKeys(ToTy) \
3475 ReachabilityQueryInfo<ToTy> \
3476 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::EmptyKey = \
3477 ReachabilityQueryInfo<ToTy>( \
3478 DenseMapInfo<const Instruction *>::getEmptyKey(), \
3479 DenseMapInfo<const ToTy *>::getEmptyKey()); \
3481 ReachabilityQueryInfo<ToTy> \
3482 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::TombstoneKey = \
3483 ReachabilityQueryInfo<ToTy>( \
3484 DenseMapInfo<const Instruction *>::getTombstoneKey(), \
3485 DenseMapInfo<const ToTy *>::getTombstoneKey());
3494template <
typename BaseTy,
typename ToTy>
3495struct CachedReachabilityAA :
public BaseTy {
3496 using RQITy = ReachabilityQueryInfo<ToTy>;
3498 CachedReachabilityAA(
const IRPosition &IRP, Attributor &
A) : BaseTy(IRP,
A) {}
3501 bool isQueryAA()
const override {
return true; }
3506 for (
unsigned u = 0,
e = QueryVector.size();
u <
e; ++
u) {
3507 RQITy *RQI = QueryVector[
u];
3508 if (RQI->Result == RQITy::Reachable::No &&
3510 Changed = ChangeStatus::CHANGED;
3516 bool IsTemporaryRQI) = 0;
3518 bool rememberResult(Attributor &
A,
typename RQITy::Reachable
Result,
3519 RQITy &RQI,
bool UsedExclusionSet,
bool IsTemporaryRQI) {
3524 QueryCache.erase(&RQI);
3530 if (
Result == RQITy::Reachable::Yes || !UsedExclusionSet) {
3531 RQITy PlainRQI(RQI.From, RQI.To);
3532 if (!QueryCache.count(&PlainRQI)) {
3533 RQITy *RQIPtr =
new (
A.Allocator) RQITy(RQI.From, RQI.To);
3535 QueryVector.push_back(RQIPtr);
3536 QueryCache.insert(RQIPtr);
3541 if (IsTemporaryRQI &&
Result != RQITy::Reachable::Yes && UsedExclusionSet) {
3542 assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&
3543 "Did not expect empty set!");
3544 RQITy *RQIPtr =
new (
A.Allocator)
3545 RQITy(
A, *RQI.From, *RQI.To, RQI.ExclusionSet,
true);
3546 assert(RQIPtr->Result == RQITy::Reachable::No &&
"Already reachable?");
3548 assert(!QueryCache.count(RQIPtr));
3549 QueryVector.push_back(RQIPtr);
3550 QueryCache.insert(RQIPtr);
3553 if (
Result == RQITy::Reachable::No && IsTemporaryRQI)
3554 A.registerForUpdate(*
this);
3555 return Result == RQITy::Reachable::Yes;
3558 const std::string getAsStr(Attributor *
A)
const override {
3560 return "#queries(" + std::to_string(QueryVector.size()) +
")";
3563 bool checkQueryCache(Attributor &
A, RQITy &StackRQI,
3564 typename RQITy::Reachable &
Result) {
3565 if (!this->getState().isValidState()) {
3566 Result = RQITy::Reachable::Yes;
3572 if (StackRQI.ExclusionSet) {
3573 RQITy PlainRQI(StackRQI.From, StackRQI.To);
3574 auto It = QueryCache.find(&PlainRQI);
3575 if (It != QueryCache.end() && (*It)->Result == RQITy::Reachable::No) {
3576 Result = RQITy::Reachable::No;
3581 auto It = QueryCache.find(&StackRQI);
3582 if (It != QueryCache.end()) {
3589 QueryCache.insert(&StackRQI);
3595 DenseSet<RQITy *> QueryCache;
3598struct AAIntraFnReachabilityFunction final
3599 :
public CachedReachabilityAA<AAIntraFnReachability, Instruction> {
3600 using Base = CachedReachabilityAA<AAIntraFnReachability, Instruction>;
3601 AAIntraFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
3603 DT =
A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(
3607 bool isAssumedReachable(
3608 Attributor &
A,
const Instruction &From,
const Instruction &To,
3610 auto *NonConstThis =
const_cast<AAIntraFnReachabilityFunction *
>(
this);
3614 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
3616 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
3617 return NonConstThis->isReachableImpl(
A, StackRQI,
3619 return Result == RQITy::Reachable::Yes;
3626 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3629 [&](
const auto &DeadEdge) {
3630 return LivenessAA->isEdgeDead(DeadEdge.first,
3634 return LivenessAA->isAssumedDead(BB);
3636 return ChangeStatus::UNCHANGED;
3640 return Base::updateImpl(
A);
3644 bool IsTemporaryRQI)
override {
3646 bool UsedExclusionSet =
false;
3651 while (IP && IP != &To) {
3652 if (ExclusionSet && IP != Origin && ExclusionSet->
count(IP)) {
3653 UsedExclusionSet =
true;
3661 const BasicBlock *FromBB = RQI.From->getParent();
3662 const BasicBlock *ToBB = RQI.To->getParent();
3664 "Not an intra-procedural query!");
3668 if (FromBB == ToBB &&
3669 WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
3670 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3675 if (!WillReachInBlock(ToBB->
front(), *RQI.To, RQI.ExclusionSet))
3676 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3680 SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
3681 if (RQI.ExclusionSet)
3682 for (
auto *
I : *RQI.ExclusionSet)
3683 if (
I->getFunction() == Fn)
3684 ExclusionBlocks.
insert(
I->getParent());
3687 if (ExclusionBlocks.
count(FromBB) &&
3690 return rememberResult(
A, RQITy::Reachable::No, RQI,
true, IsTemporaryRQI);
3693 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3694 if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {
3695 DeadBlocks.insert(ToBB);
3696 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3700 SmallPtrSet<const BasicBlock *, 16> Visited;
3704 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> LocalDeadEdges;
3705 while (!Worklist.
empty()) {
3707 if (!Visited.
insert(BB).second)
3709 for (
const BasicBlock *SuccBB :
successors(BB)) {
3710 if (LivenessAA && LivenessAA->isEdgeDead(BB, SuccBB)) {
3711 LocalDeadEdges.
insert({BB, SuccBB});
3716 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3719 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3722 if (ExclusionBlocks.
count(SuccBB)) {
3723 UsedExclusionSet =
true;
3730 DeadEdges.insert_range(LocalDeadEdges);
3731 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3736 void trackStatistics()
const override {}
3741 DenseSet<const BasicBlock *> DeadBlocks;
3745 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> DeadEdges;
3748 const DominatorTree *DT =
nullptr;
3756 bool IgnoreSubsumingPositions) {
3757 assert(ImpliedAttributeKind == Attribute::NoAlias &&
3758 "Unexpected attribute kind");
3764 IgnoreSubsumingPositions =
true;
3775 if (
A.hasAttr(IRP, {Attribute::ByVal, Attribute::NoAlias},
3776 IgnoreSubsumingPositions, Attribute::NoAlias))
3786 "Noalias is a pointer attribute");
3789 const std::string getAsStr(
Attributor *
A)
const override {
3790 return getAssumed() ?
"noalias" :
"may-alias";
3795struct AANoAliasFloating final : AANoAliasImpl {
3796 AANoAliasFloating(
const IRPosition &IRP, Attributor &
A)
3797 : AANoAliasImpl(IRP,
A) {}
3802 return indicatePessimisticFixpoint();
3806 void trackStatistics()
const override {
3812struct AANoAliasArgument final
3813 : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> {
3814 using Base = AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>;
3815 AANoAliasArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
3828 DepClassTy::OPTIONAL, IsKnownNoSycn))
3829 return Base::updateImpl(
A);
3834 return Base::updateImpl(
A);
3838 bool UsedAssumedInformation =
false;
3839 if (
A.checkForAllCallSites(
3840 [](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *
this,
3841 true, UsedAssumedInformation))
3842 return Base::updateImpl(
A);
3850 return indicatePessimisticFixpoint();
3857struct AANoAliasCallSiteArgument final : AANoAliasImpl {
3858 AANoAliasCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
3859 : AANoAliasImpl(IRP,
A) {}
3863 bool mayAliasWithArgument(Attributor &
A, AAResults *&AAR,
3864 const AAMemoryBehavior &MemBehaviorAA,
3865 const CallBase &CB,
unsigned OtherArgNo) {
3867 if (this->getCalleeArgNo() == (
int)OtherArgNo)
3875 auto *CBArgMemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
3879 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadNone()) {
3880 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3887 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadOnly() &&
3889 A.recordDependence(MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3890 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3896 AAR =
A.getInfoCache().getAnalysisResultForFunction<AAManager>(
3900 bool IsAliasing = !AAR || !AAR->
isNoAlias(&getAssociatedValue(), ArgOp);
3902 "callsite arguments: "
3903 << getAssociatedValue() <<
" " << *ArgOp <<
" => "
3904 << (IsAliasing ?
"" :
"no-") <<
"alias \n");
3909 bool isKnownNoAliasDueToNoAliasPreservation(
3910 Attributor &
A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA) {
3923 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
3939 bool IsKnownNoCapture;
3942 DepClassTy::OPTIONAL, IsKnownNoCapture))
3948 A, *UserI, *getCtxI(), *
this,
nullptr,
3949 [ScopeFn](
const Function &Fn) {
return &Fn != ScopeFn; }))
3964 LLVM_DEBUG(
dbgs() <<
"[AANoAliasCSArg] Unknown user: " << *UserI <<
"\n");
3968 bool IsKnownNoCapture;
3969 const AANoCapture *NoCaptureAA =
nullptr;
3971 A,
this, VIRP, DepClassTy::NONE, IsKnownNoCapture,
false, &NoCaptureAA);
3972 if (!IsAssumedNoCapture &&
3974 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue())) {
3976 dbgs() <<
"[AANoAliasCSArg] " << getAssociatedValue()
3977 <<
" cannot be noalias as it is potentially captured\n");
3982 A.recordDependence(*NoCaptureAA, *
this, DepClassTy::OPTIONAL);
3988 for (
unsigned OtherArgNo = 0; OtherArgNo < CB.
arg_size(); OtherArgNo++)
3989 if (mayAliasWithArgument(
A, AAR, MemBehaviorAA, CB, OtherArgNo))
3999 auto *MemBehaviorAA =
4000 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
4002 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
4003 return ChangeStatus::UNCHANGED;
4006 bool IsKnownNoAlias;
4009 A,
this, VIRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
4011 <<
" is not no-alias at the definition\n");
4012 return indicatePessimisticFixpoint();
4015 AAResults *AAR =
nullptr;
4016 if (MemBehaviorAA &&
4017 isKnownNoAliasDueToNoAliasPreservation(
A, AAR, *MemBehaviorAA)) {
4019 dbgs() <<
"[AANoAlias] No-Alias deduced via no-alias preservation\n");
4020 return ChangeStatus::UNCHANGED;
4023 return indicatePessimisticFixpoint();
4031struct AANoAliasReturned final : AANoAliasImpl {
4032 AANoAliasReturned(
const IRPosition &IRP, Attributor &
A)
4033 : AANoAliasImpl(IRP,
A) {}
4038 auto CheckReturnValue = [&](
Value &RV) ->
bool {
4049 bool IsKnownNoAlias;
4051 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoAlias))
4054 bool IsKnownNoCapture;
4055 const AANoCapture *NoCaptureAA =
nullptr;
4057 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
4059 return IsAssumedNoCapture ||
4063 if (!
A.checkForAllReturnedValues(CheckReturnValue, *
this))
4064 return indicatePessimisticFixpoint();
4066 return ChangeStatus::UNCHANGED;
4074struct AANoAliasCallSiteReturned final
4075 : AACalleeToCallSite<AANoAlias, AANoAliasImpl> {
4076 AANoAliasCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4077 : AACalleeToCallSite<AANoAlias, AANoAliasImpl>(IRP,
A) {}
4087struct AAIsDeadValueImpl :
public AAIsDead {
4088 AAIsDeadValueImpl(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4091 bool isAssumedDead()
const override {
return isAssumed(IS_DEAD); }
4094 bool isKnownDead()
const override {
return isKnown(IS_DEAD); }
4097 bool isAssumedDead(
const BasicBlock *BB)
const override {
return false; }
4100 bool isKnownDead(
const BasicBlock *BB)
const override {
return false; }
4103 bool isAssumedDead(
const Instruction *
I)
const override {
4104 return I == getCtxI() && isAssumedDead();
4108 bool isKnownDead(
const Instruction *
I)
const override {
4109 return isAssumedDead(
I) && isKnownDead();
4113 const std::string getAsStr(Attributor *
A)
const override {
4114 return isAssumedDead() ?
"assumed-dead" :
"assumed-live";
4118 bool areAllUsesAssumedDead(Attributor &
A,
Value &V) {
4120 if (
V.getType()->isVoidTy() ||
V.use_empty())
4126 if (!
A.isRunOn(*
I->getFunction()))
4128 bool UsedAssumedInformation =
false;
4129 std::optional<Constant *>
C =
4130 A.getAssumedConstant(V, *
this, UsedAssumedInformation);
4135 auto UsePred = [&](
const Use &
U,
bool &Follow) {
return false; };
4140 return A.checkForAllUses(UsePred, *
this, V,
false,
4141 DepClassTy::REQUIRED,
4146 bool isAssumedSideEffectFree(Attributor &
A, Instruction *
I) {
4156 bool IsKnownNoUnwind;
4158 A,
this, CallIRP, DepClassTy::OPTIONAL, IsKnownNoUnwind))
4166struct AAIsDeadFloating :
public AAIsDeadValueImpl {
4167 AAIsDeadFloating(
const IRPosition &IRP, Attributor &
A)
4168 : AAIsDeadValueImpl(IRP,
A) {}
4172 AAIsDeadValueImpl::initialize(
A);
4175 indicatePessimisticFixpoint();
4180 if (!isAssumedSideEffectFree(
A,
I)) {
4182 indicatePessimisticFixpoint();
4184 removeAssumedBits(HAS_NO_EFFECT);
4188 bool isDeadFence(Attributor &
A, FenceInst &FI) {
4189 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
4191 if (!ExecDomainAA || !ExecDomainAA->isNoOpFence(FI))
4193 A.recordDependence(*ExecDomainAA, *
this, DepClassTy::OPTIONAL);
4197 bool isDeadStore(Attributor &
A, StoreInst &SI,
4198 SmallSetVector<Instruction *, 8> *AssumeOnlyInst =
nullptr) {
4200 if (
SI.isVolatile())
4206 bool UsedAssumedInformation =
false;
4207 if (!AssumeOnlyInst) {
4208 PotentialCopies.clear();
4210 UsedAssumedInformation)) {
4213 <<
"[AAIsDead] Could not determine potential copies of store!\n");
4217 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Store has " << PotentialCopies.size()
4218 <<
" potential copies.\n");
4220 InformationCache &InfoCache =
A.getInfoCache();
4223 UsedAssumedInformation))
4227 auto &UserI = cast<Instruction>(*U.getUser());
4228 if (InfoCache.isOnlyUsedByAssume(UserI)) {
4230 AssumeOnlyInst->insert(&UserI);
4233 return A.isAssumedDead(U,
this,
nullptr, UsedAssumedInformation);
4239 <<
" is assumed live!\n");
4245 const std::string getAsStr(Attributor *
A)
const override {
4249 return "assumed-dead-store";
4252 return "assumed-dead-fence";
4253 return AAIsDeadValueImpl::getAsStr(
A);
4260 if (!isDeadStore(
A, *SI))
4261 return indicatePessimisticFixpoint();
4263 if (!isDeadFence(
A, *FI))
4264 return indicatePessimisticFixpoint();
4266 if (!isAssumedSideEffectFree(
A,
I))
4267 return indicatePessimisticFixpoint();
4268 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4269 return indicatePessimisticFixpoint();
4274 bool isRemovableStore()
const override {
4275 return isAssumed(IS_REMOVABLE) &&
isa<StoreInst>(&getAssociatedValue());
4280 Value &
V = getAssociatedValue();
4287 SmallSetVector<Instruction *, 8> AssumeOnlyInst;
4288 bool IsDead = isDeadStore(
A, *SI, &AssumeOnlyInst);
4291 A.deleteAfterManifest(*
I);
4292 for (
size_t i = 0; i < AssumeOnlyInst.
size(); ++i) {
4294 for (
auto *Usr : AOI->
users())
4296 A.deleteAfterManifest(*AOI);
4302 A.deleteAfterManifest(*FI);
4306 A.deleteAfterManifest(*
I);
4314 void trackStatistics()
const override {
4320 SmallSetVector<Value *, 4> PotentialCopies;
4323struct AAIsDeadArgument :
public AAIsDeadFloating {
4324 AAIsDeadArgument(
const IRPosition &IRP, Attributor &
A)
4325 : AAIsDeadFloating(IRP,
A) {}
4329 Argument &Arg = *getAssociatedArgument();
4330 if (
A.isValidFunctionSignatureRewrite(Arg, {}))
4331 if (
A.registerFunctionSignatureRewrite(
4335 return ChangeStatus::CHANGED;
4337 return ChangeStatus::UNCHANGED;
4344struct AAIsDeadCallSiteArgument :
public AAIsDeadValueImpl {
4345 AAIsDeadCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
4346 : AAIsDeadValueImpl(IRP,
A) {}
4350 AAIsDeadValueImpl::initialize(
A);
4352 indicatePessimisticFixpoint();
4361 Argument *Arg = getAssociatedArgument();
4363 return indicatePessimisticFixpoint();
4365 auto *ArgAA =
A.getAAFor<AAIsDead>(*
this, ArgPos, DepClassTy::REQUIRED);
4367 return indicatePessimisticFixpoint();
4376 "Expected undef values to be filtered out!");
4378 if (
A.changeUseAfterManifest(U, UV))
4379 return ChangeStatus::CHANGED;
4380 return ChangeStatus::UNCHANGED;
4387struct AAIsDeadCallSiteReturned :
public AAIsDeadFloating {
4388 AAIsDeadCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4389 : AAIsDeadFloating(IRP,
A) {}
4392 bool isAssumedDead()
const override {
4393 return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;
4398 AAIsDeadFloating::initialize(
A);
4400 indicatePessimisticFixpoint();
4405 IsAssumedSideEffectFree = isAssumedSideEffectFree(
A, getCtxI());
4411 if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(
A, getCtxI())) {
4412 IsAssumedSideEffectFree =
false;
4413 Changed = ChangeStatus::CHANGED;
4415 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4416 return indicatePessimisticFixpoint();
4421 void trackStatistics()
const override {
4422 if (IsAssumedSideEffectFree)
4429 const std::string getAsStr(Attributor *
A)
const override {
4430 return isAssumedDead()
4432 : (getAssumed() ?
"assumed-dead-users" :
"assumed-live");
4436 bool IsAssumedSideEffectFree =
true;
4439struct AAIsDeadReturned :
public AAIsDeadValueImpl {
4440 AAIsDeadReturned(
const IRPosition &IRP, Attributor &
A)
4441 : AAIsDeadValueImpl(IRP,
A) {}
4446 bool UsedAssumedInformation =
false;
4447 A.checkForAllInstructions([](Instruction &) {
return true; }, *
this,
4448 {Instruction::Ret}, UsedAssumedInformation);
4450 auto PredForCallSite = [&](AbstractCallSite ACS) {
4451 if (ACS.isCallbackCall() || !ACS.getInstruction())
4453 return areAllUsesAssumedDead(
A, *ACS.getInstruction());
4456 if (!
A.checkForAllCallSites(PredForCallSite, *
this,
true,
4457 UsedAssumedInformation))
4458 return indicatePessimisticFixpoint();
4460 return ChangeStatus::UNCHANGED;
4466 bool AnyChange =
false;
4467 UndefValue &UV = *
UndefValue::get(getAssociatedFunction()->getReturnType());
4474 bool UsedAssumedInformation =
false;
4475 A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
4476 UsedAssumedInformation);
4477 return AnyChange ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
4484struct AAIsDeadFunction :
public AAIsDead {
4485 AAIsDeadFunction(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4490 assert(
F &&
"Did expect an anchor function");
4491 if (!isAssumedDeadInternalFunction(
A)) {
4492 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4493 assumeLive(
A,
F->getEntryBlock());
4497 bool isAssumedDeadInternalFunction(Attributor &
A) {
4498 if (!getAnchorScope()->hasLocalLinkage())
4500 bool UsedAssumedInformation =
false;
4501 return A.checkForAllCallSites([](AbstractCallSite) {
return false; }, *
this,
4502 true, UsedAssumedInformation);
4506 const std::string getAsStr(Attributor *
A)
const override {
4507 return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) +
"/" +
4508 std::to_string(getAnchorScope()->
size()) +
"][#TBEP " +
4509 std::to_string(ToBeExploredFrom.size()) +
"][#KDE " +
4510 std::to_string(KnownDeadEnds.size()) +
"]";
4515 assert(getState().isValidState() &&
4516 "Attempted to manifest an invalid state!");
4521 if (AssumedLiveBlocks.empty()) {
4522 A.deleteAfterManifest(
F);
4523 return ChangeStatus::CHANGED;
4529 bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(
F);
4531 KnownDeadEnds.set_union(ToBeExploredFrom);
4532 for (
const Instruction *DeadEndI : KnownDeadEnds) {
4536 bool IsKnownNoReturn;
4544 A.registerInvokeWithDeadSuccessor(
const_cast<InvokeInst &
>(*
II));
4546 A.changeToUnreachableAfterManifest(
4547 const_cast<Instruction *
>(DeadEndI->getNextNode()));
4548 HasChanged = ChangeStatus::CHANGED;
4551 STATS_DECL(AAIsDead, BasicBlock,
"Number of dead basic blocks deleted.");
4552 for (BasicBlock &BB :
F)
4553 if (!AssumedLiveBlocks.count(&BB)) {
4554 A.deleteAfterManifest(BB);
4556 HasChanged = ChangeStatus::CHANGED;
4565 bool isEdgeDead(
const BasicBlock *From,
const BasicBlock *To)
const override {
4568 "Used AAIsDead of the wrong function");
4569 return isValidState() && !AssumedLiveEdges.count(std::make_pair(From, To));
4573 void trackStatistics()
const override {}
4576 bool isAssumedDead()
const override {
return false; }
4579 bool isKnownDead()
const override {
return false; }
4582 bool isAssumedDead(
const BasicBlock *BB)
const override {
4584 "BB must be in the same anchor scope function.");
4588 return !AssumedLiveBlocks.count(BB);
4592 bool isKnownDead(
const BasicBlock *BB)
const override {
4593 return getKnown() && isAssumedDead(BB);
4597 bool isAssumedDead(
const Instruction *
I)
const override {
4598 assert(
I->getParent()->getParent() == getAnchorScope() &&
4599 "Instruction must be in the same anchor scope function.");
4606 if (!AssumedLiveBlocks.count(
I->getParent()))
4612 if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))
4620 bool isKnownDead(
const Instruction *
I)
const override {
4621 return getKnown() && isAssumedDead(
I);
4626 bool assumeLive(Attributor &
A,
const BasicBlock &BB) {
4627 if (!AssumedLiveBlocks.insert(&BB).second)
4634 for (
const Instruction &
I : BB)
4637 if (
F->hasLocalLinkage())
4638 A.markLiveInternalFunction(*
F);
4644 SmallSetVector<const Instruction *, 8> ToBeExploredFrom;
4647 SmallSetVector<const Instruction *, 8> KnownDeadEnds;
4650 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> AssumedLiveEdges;
4653 DenseSet<const BasicBlock *> AssumedLiveBlocks;
4657identifyAliveSuccessors(Attributor &
A,
const CallBase &CB,
4658 AbstractAttribute &AA,
4659 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4662 bool IsKnownNoReturn;
4665 return !IsKnownNoReturn;
4674identifyAliveSuccessors(Attributor &
A,
const InvokeInst &
II,
4675 AbstractAttribute &AA,
4676 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4677 bool UsedAssumedInformation =
4683 if (AAIsDeadFunction::mayCatchAsynchronousExceptions(*
II.getFunction())) {
4684 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4688 bool IsKnownNoUnwind;
4691 UsedAssumedInformation |= !IsKnownNoUnwind;
4693 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4696 return UsedAssumedInformation;
4700identifyAliveSuccessors(Attributor &,
const UncondBrInst &BI,
4701 AbstractAttribute &,
4702 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4708identifyAliveSuccessors(Attributor &
A,
const CondBrInst &BI,
4709 AbstractAttribute &AA,
4710 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4711 bool UsedAssumedInformation =
false;
4712 std::optional<Constant *>
C =
4713 A.getAssumedConstant(*BI.
getCondition(), AA, UsedAssumedInformation);
4723 UsedAssumedInformation =
false;
4725 return UsedAssumedInformation;
4729identifyAliveSuccessors(Attributor &
A,
const SwitchInst &SI,
4730 AbstractAttribute &AA,
4731 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4732 bool UsedAssumedInformation =
false;
4736 UsedAssumedInformation)) {
4738 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4743 if (Values.
empty() ||
4744 (Values.
size() == 1 &&
4747 return UsedAssumedInformation;
4750 Type &Ty = *
SI.getCondition()->getType();
4751 SmallPtrSet<ConstantInt *, 8>
Constants;
4752 auto CheckForConstantInt = [&](
Value *
V) {
4760 if (!
all_of(Values, [&](AA::ValueAndContext &VAC) {
4761 return CheckForConstantInt(VAC.
getValue());
4763 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4765 return UsedAssumedInformation;
4768 unsigned MatchedCases = 0;
4769 for (
const auto &CaseIt :
SI.cases()) {
4770 if (
Constants.count(CaseIt.getCaseValue())) {
4772 AliveSuccessors.
push_back(&CaseIt.getCaseSuccessor()->front());
4779 AliveSuccessors.
push_back(&
SI.getDefaultDest()->front());
4780 return UsedAssumedInformation;
4786 if (AssumedLiveBlocks.empty()) {
4787 if (isAssumedDeadInternalFunction(
A))
4791 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4792 assumeLive(
A,
F->getEntryBlock());
4796 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Live [" << AssumedLiveBlocks.size() <<
"/"
4797 << getAnchorScope()->
size() <<
"] BBs and "
4798 << ToBeExploredFrom.size() <<
" exploration points and "
4799 << KnownDeadEnds.size() <<
" known dead ends\n");
4804 ToBeExploredFrom.end());
4805 decltype(ToBeExploredFrom) NewToBeExploredFrom;
4808 while (!Worklist.
empty()) {
4815 I =
I->getNextNode();
4817 AliveSuccessors.
clear();
4819 bool UsedAssumedInformation =
false;
4820 switch (
I->getOpcode()) {
4824 "Expected non-terminators to be handled already!");
4825 for (
const BasicBlock *SuccBB :
successors(
I->getParent()))
4828 case Instruction::Call:
4830 *
this, AliveSuccessors);
4832 case Instruction::Invoke:
4834 *
this, AliveSuccessors);
4836 case Instruction::UncondBr:
4837 UsedAssumedInformation = identifyAliveSuccessors(
4840 case Instruction::CondBr:
4842 *
this, AliveSuccessors);
4844 case Instruction::Switch:
4846 *
this, AliveSuccessors);
4850 if (UsedAssumedInformation) {
4851 NewToBeExploredFrom.insert(
I);
4852 }
else if (AliveSuccessors.
empty() ||
4853 (
I->isTerminator() &&
4854 AliveSuccessors.
size() <
I->getNumSuccessors())) {
4855 if (KnownDeadEnds.insert(
I))
4860 << AliveSuccessors.
size() <<
" UsedAssumedInformation: "
4861 << UsedAssumedInformation <<
"\n");
4863 for (
const Instruction *AliveSuccessor : AliveSuccessors) {
4864 if (!
I->isTerminator()) {
4865 assert(AliveSuccessors.size() == 1 &&
4866 "Non-terminator expected to have a single successor!");
4870 auto Edge = std::make_pair(
I->getParent(), AliveSuccessor->getParent());
4871 if (AssumedLiveEdges.insert(
Edge).second)
4873 if (assumeLive(
A, *AliveSuccessor->getParent()))
4880 if (NewToBeExploredFrom.size() != ToBeExploredFrom.size() ||
4881 llvm::any_of(NewToBeExploredFrom, [&](
const Instruction *
I) {
4882 return !ToBeExploredFrom.count(I);
4885 ToBeExploredFrom = std::move(NewToBeExploredFrom);
4894 if (ToBeExploredFrom.empty() &&
4895 getAnchorScope()->
size() == AssumedLiveBlocks.size() &&
4896 llvm::all_of(KnownDeadEnds, [](
const Instruction *DeadEndI) {
4897 return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;
4899 return indicatePessimisticFixpoint();
4904struct AAIsDeadCallSite final : AAIsDeadFunction {
4905 AAIsDeadCallSite(
const IRPosition &IRP, Attributor &
A)
4906 : AAIsDeadFunction(IRP,
A) {}
4915 "supported for call sites yet!");
4920 return indicatePessimisticFixpoint();
4924 void trackStatistics()
const override {}
4931struct AADereferenceableImpl : AADereferenceable {
4932 AADereferenceableImpl(
const IRPosition &IRP, Attributor &
A)
4933 : AADereferenceable(IRP,
A) {}
4934 using StateType = DerefState;
4938 Value &
V = *getAssociatedValue().stripPointerCasts();
4940 A.getAttrs(getIRPosition(),
4941 {Attribute::Dereferenceable, Attribute::DereferenceableOrNull},
4944 takeKnownDerefBytesMaximum(Attr.getValueAsInt());
4947 bool IsKnownNonNull;
4949 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNonNull);
4951 bool CanBeNull, CanBeFreed;
4952 takeKnownDerefBytesMaximum(
V.getPointerDereferenceableBytes(
4953 A.getDataLayout(), CanBeNull, CanBeFreed));
4955 if (Instruction *CtxI = getCtxI())
4956 followUsesInMBEC(*
this,
A, getState(), *CtxI);
4961 StateType &getState()
override {
return *
this; }
4962 const StateType &getState()
const override {
return *
this; }
4966 void addAccessedBytesForUse(Attributor &
A,
const Use *U,
const Instruction *
I,
4967 DerefState &State) {
4968 const Value *UseV =
U->get();
4973 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
I->isVolatile())
4978 Loc->Ptr,
Offset,
A.getDataLayout(),
true);
4979 if (
Base &&
Base == &getAssociatedValue())
4980 State.addAccessedBytes(
Offset, Loc->Size.getValue());
4984 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
4985 AADereferenceable::StateType &State) {
4986 bool IsNonNull =
false;
4987 bool TrackUse =
false;
4988 int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
4989 A, *
this, getAssociatedValue(), U,
I, IsNonNull, TrackUse);
4990 LLVM_DEBUG(
dbgs() <<
"[AADereferenceable] Deref bytes: " << DerefBytes
4991 <<
" for instruction " << *
I <<
"\n");
4993 addAccessedBytesForUse(
A, U,
I, State);
4994 State.takeKnownDerefBytesMaximum(DerefBytes);
5001 bool IsKnownNonNull;
5003 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5004 if (IsAssumedNonNull &&
5005 A.hasAttr(getIRPosition(), Attribute::DereferenceableOrNull)) {
5006 A.removeAttrs(getIRPosition(), {Attribute::DereferenceableOrNull});
5007 return ChangeStatus::CHANGED;
5012 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5013 SmallVectorImpl<Attribute> &Attrs)
const override {
5015 bool IsKnownNonNull;
5017 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5018 if (IsAssumedNonNull)
5019 Attrs.emplace_back(Attribute::getWithDereferenceableBytes(
5020 Ctx, getAssumedDereferenceableBytes()));
5022 Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes(
5023 Ctx, getAssumedDereferenceableBytes()));
5027 const std::string getAsStr(Attributor *
A)
const override {
5028 if (!getAssumedDereferenceableBytes())
5029 return "unknown-dereferenceable";
5030 bool IsKnownNonNull;
5031 bool IsAssumedNonNull =
false;
5034 *
A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5035 return std::string(
"dereferenceable") +
5036 (IsAssumedNonNull ?
"" :
"_or_null") +
5037 (isAssumedGlobal() ?
"_globally" :
"") +
"<" +
5038 std::to_string(getKnownDereferenceableBytes()) +
"-" +
5039 std::to_string(getAssumedDereferenceableBytes()) +
">" +
5040 (!
A ?
" [non-null is unknown]" :
"");
5045struct AADereferenceableFloating : AADereferenceableImpl {
5046 AADereferenceableFloating(
const IRPosition &IRP, Attributor &
A)
5047 : AADereferenceableImpl(IRP,
A) {}
5052 bool UsedAssumedInformation =
false;
5054 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5056 Values.
push_back({getAssociatedValue(), getCtxI()});
5059 Stripped = Values.
size() != 1 ||
5060 Values.
front().getValue() != &getAssociatedValue();
5063 const DataLayout &
DL =
A.getDataLayout();
5066 auto VisitValueCB = [&](
const Value &
V) ->
bool {
5068 DL.getIndexSizeInBits(
V.getType()->getPointerAddressSpace());
5069 APInt
Offset(IdxWidth, 0);
5074 const auto *AA =
A.getAAFor<AADereferenceable>(
5076 int64_t DerefBytes = 0;
5077 if (!AA || (!Stripped &&
this == AA)) {
5080 bool CanBeNull, CanBeFreed;
5082 Base->getPointerDereferenceableBytes(
DL, CanBeNull, CanBeFreed);
5083 T.GlobalState.indicatePessimisticFixpoint();
5086 DerefBytes =
DS.DerefBytesState.getAssumed();
5087 T.GlobalState &=
DS.GlobalState;
5093 int64_t OffsetSExt =
Offset.getSExtValue();
5097 T.takeAssumedDerefBytesMinimum(
5098 std::max(int64_t(0), DerefBytes - OffsetSExt));
5103 T.takeKnownDerefBytesMaximum(
5104 std::max(int64_t(0), DerefBytes - OffsetSExt));
5105 T.indicatePessimisticFixpoint();
5106 }
else if (OffsetSExt > 0) {
5112 T.indicatePessimisticFixpoint();
5116 return T.isValidState();
5119 for (
const auto &VAC : Values)
5120 if (!VisitValueCB(*VAC.
getValue()))
5121 return indicatePessimisticFixpoint();
5127 void trackStatistics()
const override {
5133struct AADereferenceableReturned final
5134 : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl> {
5136 AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl>;
5137 AADereferenceableReturned(
const IRPosition &IRP, Attributor &
A)
5141 void trackStatistics()
const override {
5147struct AADereferenceableArgument final
5148 : AAArgumentFromCallSiteArguments<AADereferenceable,
5149 AADereferenceableImpl> {
5151 AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl>;
5152 AADereferenceableArgument(
const IRPosition &IRP, Attributor &
A)
5156 void trackStatistics()
const override {
5162struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {
5163 AADereferenceableCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5164 : AADereferenceableFloating(IRP,
A) {}
5167 void trackStatistics()
const override {
5173struct AADereferenceableCallSiteReturned final
5174 : AACalleeToCallSite<AADereferenceable, AADereferenceableImpl> {
5175 using Base = AACalleeToCallSite<AADereferenceable, AADereferenceableImpl>;
5176 AADereferenceableCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5180 void trackStatistics()
const override {
5190static unsigned getKnownAlignForUse(Attributor &
A, AAAlign &QueryingAA,
5191 Value &AssociatedValue,
const Use *U,
5192 const Instruction *
I,
bool &TrackUse) {
5201 if (
GEP->hasAllConstantIndices())
5206 switch (
II->getIntrinsicID()) {
5207 case Intrinsic::ptrmask: {
5209 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5211 const auto *AlignAA =
A.getAAFor<AAAlign>(
5213 if (ConstVals && ConstVals->isValidState() && ConstVals->isAtFixpoint()) {
5214 unsigned ShiftValue = std::min(ConstVals->getAssumedMinTrailingZeros(),
5216 Align ConstAlign(UINT64_C(1) << ShiftValue);
5217 if (ConstAlign >= AlignAA->getKnownAlign())
5218 return Align(1).value();
5221 return AlignAA->getKnownAlign().
value();
5224 case Intrinsic::amdgcn_make_buffer_rsrc: {
5225 const auto *AlignAA =
A.getAAFor<AAAlign>(
5228 return AlignAA->getKnownAlign().
value();
5246 MA = MaybeAlign(AlignAA->getKnownAlign());
5249 const DataLayout &
DL =
A.getDataLayout();
5250 const Value *UseV =
U->get();
5252 if (
SI->getPointerOperand() == UseV)
5253 MA =
SI->getAlign();
5255 if (LI->getPointerOperand() == UseV)
5256 MA = LI->getAlign();
5258 if (AI->getPointerOperand() == UseV)
5259 MA = AI->getAlign();
5261 if (AI->getPointerOperand() == UseV)
5262 MA = AI->getAlign();
5268 unsigned Alignment = MA->value();
5272 if (
Base == &AssociatedValue) {
5277 uint32_t
gcd = std::gcd(uint32_t(
abs((int32_t)
Offset)), Alignment);
5285struct AAAlignImpl : AAAlign {
5286 AAAlignImpl(
const IRPosition &IRP, Attributor &
A) : AAAlign(IRP,
A) {}
5291 A.getAttrs(getIRPosition(), {Attribute::Alignment},
Attrs);
5293 takeKnownMaximum(Attr.getValueAsInt());
5295 Value &
V = *getAssociatedValue().stripPointerCasts();
5296 takeKnownMaximum(
V.getPointerAlignment(
A.getDataLayout()).value());
5298 if (Instruction *CtxI = getCtxI())
5299 followUsesInMBEC(*
this,
A, getState(), *CtxI);
5307 Value &AssociatedValue = getAssociatedValue();
5309 return ChangeStatus::UNCHANGED;
5311 for (
const Use &U : AssociatedValue.
uses()) {
5313 if (
SI->getPointerOperand() == &AssociatedValue)
5314 if (
SI->getAlign() < getAssumedAlign()) {
5316 "Number of times alignment added to a store");
5317 SI->setAlignment(getAssumedAlign());
5318 InstrChanged = ChangeStatus::CHANGED;
5321 if (LI->getPointerOperand() == &AssociatedValue)
5322 if (LI->getAlign() < getAssumedAlign()) {
5323 LI->setAlignment(getAssumedAlign());
5325 "Number of times alignment added to a load");
5326 InstrChanged = ChangeStatus::CHANGED;
5329 if (RMW->getPointerOperand() == &AssociatedValue) {
5330 if (RMW->getAlign() < getAssumedAlign()) {
5332 "Number of times alignment added to atomicrmw");
5334 RMW->setAlignment(getAssumedAlign());
5335 InstrChanged = ChangeStatus::CHANGED;
5339 if (CAS->getPointerOperand() == &AssociatedValue) {
5340 if (CAS->getAlign() < getAssumedAlign()) {
5342 "Number of times alignment added to cmpxchg");
5343 CAS->setAlignment(getAssumedAlign());
5344 InstrChanged = ChangeStatus::CHANGED;
5352 Align InheritAlign =
5353 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5354 if (InheritAlign >= getAssumedAlign())
5355 return InstrChanged;
5356 return Changed | InstrChanged;
5364 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5365 SmallVectorImpl<Attribute> &Attrs)
const override {
5366 if (getAssumedAlign() > 1)
5368 Attribute::getWithAlignment(Ctx,
Align(getAssumedAlign())));
5372 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5373 AAAlign::StateType &State) {
5374 bool TrackUse =
false;
5376 unsigned int KnownAlign =
5377 getKnownAlignForUse(
A, *
this, getAssociatedValue(), U,
I, TrackUse);
5378 State.takeKnownMaximum(KnownAlign);
5384 const std::string getAsStr(Attributor *
A)
const override {
5385 return "align<" + std::to_string(getKnownAlign().value()) +
"-" +
5386 std::to_string(getAssumedAlign().value()) +
">";
5391struct AAAlignFloating : AAAlignImpl {
5392 AAAlignFloating(
const IRPosition &IRP, Attributor &
A) : AAAlignImpl(IRP,
A) {}
5396 const DataLayout &
DL =
A.getDataLayout();
5399 bool UsedAssumedInformation =
false;
5401 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5403 Values.
push_back({getAssociatedValue(), getCtxI()});
5406 Stripped = Values.
size() != 1 ||
5407 Values.
front().getValue() != &getAssociatedValue();
5411 auto VisitValueCB = [&](
Value &
V) ->
bool {
5415 DepClassTy::REQUIRED);
5416 if (!AA || (!Stripped &&
this == AA)) {
5418 unsigned Alignment = 1;
5431 Alignment =
V.getPointerAlignment(
DL).value();
5434 T.takeKnownMaximum(Alignment);
5435 T.indicatePessimisticFixpoint();
5438 const AAAlign::StateType &
DS = AA->
getState();
5441 return T.isValidState();
5444 for (
const auto &VAC : Values) {
5445 if (!VisitValueCB(*VAC.
getValue()))
5446 return indicatePessimisticFixpoint();
5459struct AAAlignReturned final
5460 : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {
5461 using Base = AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>;
5462 AAAlignReturned(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5469struct AAAlignArgument final
5470 : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {
5471 using Base = AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>;
5472 AAAlignArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5479 if (
A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))
5480 return ChangeStatus::UNCHANGED;
5481 return Base::manifest(
A);
5488struct AAAlignCallSiteArgument final : AAAlignFloating {
5489 AAAlignCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5490 : AAAlignFloating(IRP,
A) {}
5497 if (Argument *Arg = getAssociatedArgument())
5498 if (
A.getInfoCache().isInvolvedInMustTailCall(*Arg))
5499 return ChangeStatus::UNCHANGED;
5501 Align InheritAlign =
5502 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5503 if (InheritAlign >= getAssumedAlign())
5504 Changed = ChangeStatus::UNCHANGED;
5511 if (Argument *Arg = getAssociatedArgument()) {
5514 const auto *ArgAlignAA =
A.getAAFor<AAAlign>(
5517 takeKnownMaximum(ArgAlignAA->getKnownAlign().value());
5527struct AAAlignCallSiteReturned final
5528 : AACalleeToCallSite<AAAlign, AAAlignImpl> {
5529 using Base = AACalleeToCallSite<AAAlign, AAAlignImpl>;
5530 AAAlignCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5536 switch (
II->getIntrinsicID()) {
5537 case Intrinsic::ptrmask: {
5541 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5543 if (ConstVals && ConstVals->isValidState()) {
5544 unsigned ShiftValue =
5545 std::min(ConstVals->getAssumedMinTrailingZeros(),
5546 Value::MaxAlignmentExponent);
5547 Alignment =
Align(UINT64_C(1) << ShiftValue);
5551 const auto *AlignAA =
5553 DepClassTy::REQUIRED);
5555 Alignment = std::max(AlignAA->getAssumedAlign(), Alignment);
5562 std::min(this->getAssumedAlign(), Alignment).value());
5568 case Intrinsic::amdgcn_make_buffer_rsrc: {
5569 const auto *AlignAA =
5571 DepClassTy::REQUIRED);
5574 this->getState(), AlignAA->getAssumedAlign().
value());
5581 return Base::updateImpl(
A);
5590struct AANoReturnImpl :
public AANoReturn {
5591 AANoReturnImpl(
const IRPosition &IRP, Attributor &
A) : AANoReturn(IRP,
A) {}
5597 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
5602 const std::string getAsStr(Attributor *
A)
const override {
5603 return getAssumed() ?
"noreturn" :
"may-return";
5608 auto CheckForNoReturn = [](
Instruction &) {
return false; };
5609 bool UsedAssumedInformation =
false;
5610 if (!
A.checkForAllInstructions(CheckForNoReturn, *
this,
5611 {(unsigned)Instruction::Ret},
5612 UsedAssumedInformation))
5613 return indicatePessimisticFixpoint();
5614 return ChangeStatus::UNCHANGED;
5618struct AANoReturnFunction final : AANoReturnImpl {
5619 AANoReturnFunction(
const IRPosition &IRP, Attributor &
A)
5620 : AANoReturnImpl(IRP,
A) {}
5627struct AANoReturnCallSite final
5628 : AACalleeToCallSite<AANoReturn, AANoReturnImpl> {
5629 AANoReturnCallSite(
const IRPosition &IRP, Attributor &
A)
5630 : AACalleeToCallSite<AANoReturn, AANoReturnImpl>(IRP,
A) {}
5641struct AAInstanceInfoImpl :
public AAInstanceInfo {
5642 AAInstanceInfoImpl(
const IRPosition &IRP, Attributor &
A)
5643 : AAInstanceInfo(IRP,
A) {}
5647 Value &
V = getAssociatedValue();
5649 if (
C->isThreadDependent())
5650 indicatePessimisticFixpoint();
5652 indicateOptimisticFixpoint();
5658 indicateOptimisticFixpoint();
5663 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
5666 indicatePessimisticFixpoint();
5676 Value &
V = getAssociatedValue();
5679 Scope =
I->getFunction();
5682 if (!
Scope->hasLocalLinkage())
5686 return indicateOptimisticFixpoint();
5688 bool IsKnownNoRecurse;
5694 auto UsePred = [&](
const Use &
U,
bool &Follow) {
5709 if (!Callee || !
Callee->hasLocalLinkage())
5713 const auto *ArgInstanceInfoAA =
A.getAAFor<AAInstanceInfo>(
5715 DepClassTy::OPTIONAL);
5716 if (!ArgInstanceInfoAA ||
5717 !ArgInstanceInfoAA->isAssumedUniqueForAnalysis())
5722 A, *CB, *Scope, *
this,
nullptr,
5723 [Scope](
const Function &Fn) {
return &Fn !=
Scope; }))
5730 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
5732 auto *Ptr =
SI->getPointerOperand()->stripPointerCasts();
5740 if (!
A.checkForAllUses(UsePred, *
this, V,
true,
5741 DepClassTy::OPTIONAL,
5742 true, EquivalentUseCB))
5743 return indicatePessimisticFixpoint();
5749 const std::string getAsStr(Attributor *
A)
const override {
5750 return isAssumedUniqueForAnalysis() ?
"<unique [fAa]>" :
"<unknown>";
5754 void trackStatistics()
const override {}
5758struct AAInstanceInfoFloating : AAInstanceInfoImpl {
5759 AAInstanceInfoFloating(
const IRPosition &IRP, Attributor &
A)
5760 : AAInstanceInfoImpl(IRP,
A) {}
5764struct AAInstanceInfoArgument final : AAInstanceInfoFloating {
5765 AAInstanceInfoArgument(
const IRPosition &IRP, Attributor &
A)
5766 : AAInstanceInfoFloating(IRP,
A) {}
5770struct AAInstanceInfoCallSiteArgument final : AAInstanceInfoImpl {
5771 AAInstanceInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5772 : AAInstanceInfoImpl(IRP,
A) {}
5780 Argument *Arg = getAssociatedArgument();
5782 return indicatePessimisticFixpoint();
5785 A.getAAFor<AAInstanceInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
5787 return indicatePessimisticFixpoint();
5793struct AAInstanceInfoReturned final : AAInstanceInfoImpl {
5794 AAInstanceInfoReturned(
const IRPosition &IRP, Attributor &
A)
5795 : AAInstanceInfoImpl(IRP,
A) {
5811struct AAInstanceInfoCallSiteReturned final : AAInstanceInfoFloating {
5812 AAInstanceInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5813 : AAInstanceInfoFloating(IRP,
A) {}
5820 bool IgnoreSubsumingPositions) {
5821 assert(ImpliedAttributeKind == Attribute::Captures &&
5822 "Unexpected attribute kind");
5832 V.getType()->getPointerAddressSpace() == 0)) {
5837 A.getAttrs(IRP, {Attribute::Captures}, Attrs,
5847 {Attribute::Captures, Attribute::ByVal}, Attrs,
5885 bool NoThrow =
F.doesNotThrow();
5886 bool IsVoidReturn =
F.getReturnType()->isVoidTy();
5887 if (
ReadOnly && NoThrow && IsVoidReturn) {
5900 if (NoThrow && IsVoidReturn)
5905 if (!NoThrow || ArgNo < 0 ||
5906 !
F.getAttributes().hasAttrSomewhere(Attribute::Returned))
5909 for (
unsigned U = 0, E =
F.arg_size(); U < E; ++U)
5910 if (
F.hasParamAttribute(U, Attribute::Returned)) {
5911 if (U ==
unsigned(ArgNo))
5938 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5939 SmallVectorImpl<Attribute> &Attrs)
const override {
5940 if (!isAssumedNoCaptureMaybeReturned())
5943 if (isArgumentPosition()) {
5944 if (isAssumedNoCapture())
5945 Attrs.emplace_back(Attribute::get(Ctx, Attribute::Captures));
5947 Attrs.emplace_back(Attribute::get(Ctx,
"no-capture-maybe-returned"));
5952 const std::string getAsStr(Attributor *
A)
const override {
5953 if (isKnownNoCapture())
5954 return "known not-captured";
5955 if (isAssumedNoCapture())
5956 return "assumed not-captured";
5957 if (isKnownNoCaptureMaybeReturned())
5958 return "known not-captured-maybe-returned";
5959 if (isAssumedNoCaptureMaybeReturned())
5960 return "assumed not-captured-maybe-returned";
5961 return "assumed-captured";
5966 bool checkUse(Attributor &
A, AANoCapture::StateType &State,
const Use &U,
5969 LLVM_DEBUG(
dbgs() <<
"[AANoCapture] Check use: " << *
U.get() <<
" in "
5975 return isCapturedIn(State,
true,
true,
5982 return isCapturedIn(State,
true,
true,
5988 return isCapturedIn(State,
false,
false,
5990 return isCapturedIn(State,
true,
true,
5998 return isCapturedIn(State,
true,
true,
6005 bool IsKnownNoCapture;
6006 const AANoCapture *ArgNoCaptureAA =
nullptr;
6008 A,
this, CSArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6010 if (IsAssumedNoCapture)
6011 return isCapturedIn(State,
false,
false,
6015 return isCapturedIn(State,
false,
false,
6020 return isCapturedIn(State,
true,
true,
6027 static bool isCapturedIn(AANoCapture::StateType &State,
bool CapturedInMem,
6028 bool CapturedInInt,
bool CapturedInRet) {
6029 LLVM_DEBUG(
dbgs() <<
" - captures [Mem " << CapturedInMem <<
"|Int "
6030 << CapturedInInt <<
"|Ret " << CapturedInRet <<
"]\n");
6042 const IRPosition &IRP = getIRPosition();
6046 return indicatePessimisticFixpoint();
6053 return indicatePessimisticFixpoint();
6061 T.addKnownBits(NOT_CAPTURED_IN_MEM);
6063 addKnownBits(NOT_CAPTURED_IN_MEM);
6070 auto CheckReturnedArgs = [&](
bool &UsedAssumedInformation) {
6074 UsedAssumedInformation))
6076 bool SeenConstant =
false;
6077 for (
const AA::ValueAndContext &VAC : Values) {
6081 SeenConstant =
true;
6083 VAC.
getValue() == getAssociatedArgument())
6089 bool IsKnownNoUnwind;
6092 bool IsVoidTy =
F->getReturnType()->isVoidTy();
6093 bool UsedAssumedInformation =
false;
6094 if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {
6095 T.addKnownBits(NOT_CAPTURED_IN_RET);
6096 if (
T.isKnown(NOT_CAPTURED_IN_MEM))
6098 if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {
6099 addKnownBits(NOT_CAPTURED_IN_RET);
6100 if (isKnown(NOT_CAPTURED_IN_MEM))
6101 return indicateOptimisticFixpoint();
6106 auto UseCheck = [&](
const Use &
U,
bool &Follow) ->
bool {
6115 return checkUse(
A,
T, U, Follow);
6118 if (!
A.checkForAllUses(UseCheck, *
this, *V))
6119 return indicatePessimisticFixpoint();
6122 auto Assumed = S.getAssumed();
6123 S.intersectAssumedBits(
T.getAssumed());
6124 if (!isAssumedNoCaptureMaybeReturned())
6125 return indicatePessimisticFixpoint();
6131struct AANoCaptureArgument final : AANoCaptureImpl {
6132 AANoCaptureArgument(
const IRPosition &IRP, Attributor &
A)
6133 : AANoCaptureImpl(IRP,
A) {}
6140struct AANoCaptureCallSiteArgument final : AANoCaptureImpl {
6141 AANoCaptureCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6142 : AANoCaptureImpl(IRP,
A) {}
6150 Argument *Arg = getAssociatedArgument();
6152 return indicatePessimisticFixpoint();
6154 bool IsKnownNoCapture;
6155 const AANoCapture *ArgAA =
nullptr;
6157 A,
this, ArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6159 return ChangeStatus::UNCHANGED;
6161 return indicatePessimisticFixpoint();
6166 void trackStatistics()
const override {
6172struct AANoCaptureFloating final : AANoCaptureImpl {
6173 AANoCaptureFloating(
const IRPosition &IRP, Attributor &
A)
6174 : AANoCaptureImpl(IRP,
A) {}
6177 void trackStatistics()
const override {
6183struct AANoCaptureReturned final : AANoCaptureImpl {
6184 AANoCaptureReturned(
const IRPosition &IRP, Attributor &
A)
6185 : AANoCaptureImpl(IRP,
A) {
6200 void trackStatistics()
const override {}
6204struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {
6205 AANoCaptureCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6206 : AANoCaptureImpl(IRP,
A) {}
6212 determineFunctionCaptureCapabilities(getIRPosition(), *
F, *
this);
6216 void trackStatistics()
const override {
6233 dbgs() <<
"[ValueSimplify] is assumed to be "
6236 dbgs() <<
"[ValueSimplify] is assumed to be <none>\n";
6248 if (getAssociatedValue().
getType()->isVoidTy())
6249 indicatePessimisticFixpoint();
6250 if (
A.hasSimplificationCallback(getIRPosition()))
6251 indicatePessimisticFixpoint();
6255 const std::string getAsStr(Attributor *
A)
const override {
6257 dbgs() <<
"SAV: " << (bool)SimplifiedAssociatedValue <<
" ";
6258 if (SimplifiedAssociatedValue && *SimplifiedAssociatedValue)
6259 dbgs() <<
"SAV: " << **SimplifiedAssociatedValue <<
" ";
6261 return isValidState() ? (isAtFixpoint() ?
"simplified" :
"maybe-simple")
6266 void trackStatistics()
const override {}
6269 std::optional<Value *>
6270 getAssumedSimplifiedValue(Attributor &
A)
const override {
6271 return SimplifiedAssociatedValue;
6278 static Value *ensureType(Attributor &
A,
Value &V,
Type &Ty, Instruction *CtxI,
6282 if (CtxI &&
V.getType()->canLosslesslyBitCastTo(&Ty))
6284 : BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6293 static Value *reproduceInst(Attributor &
A,
6294 const AbstractAttribute &QueryingAA,
6295 Instruction &
I,
Type &Ty, Instruction *CtxI,
6297 assert(CtxI &&
"Cannot reproduce an instruction without context!");
6298 if (
Check && (
I.mayReadFromMemory() ||
6303 Value *NewOp = reproduceValue(
A, QueryingAA, *
Op, Ty, CtxI,
Check, VMap);
6305 assert(
Check &&
"Manifest of new value unexpectedly failed!");
6327 static Value *reproduceValue(Attributor &
A,
6328 const AbstractAttribute &QueryingAA,
Value &V,
6329 Type &Ty, Instruction *CtxI,
bool Check,
6331 if (
const auto &NewV = VMap.
lookup(&V))
6333 bool UsedAssumedInformation =
false;
6334 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
6336 if (!SimpleV.has_value())
6340 EffectiveV = *SimpleV;
6345 return ensureType(
A, *EffectiveV, Ty, CtxI,
Check);
6347 if (
Value *NewV = reproduceInst(
A, QueryingAA, *
I, Ty, CtxI,
Check, VMap))
6348 return ensureType(
A, *NewV, Ty, CtxI,
Check);
6354 Value *manifestReplacementValue(Attributor &
A, Instruction *CtxI)
const {
6355 Value *NewV = SimplifiedAssociatedValue
6356 ? *SimplifiedAssociatedValue
6358 if (NewV && NewV != &getAssociatedValue()) {
6362 if (reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6364 return reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6372 bool checkAndUpdate(Attributor &
A,
const AbstractAttribute &QueryingAA,
6373 const IRPosition &IRP,
bool Simplify =
true) {
6374 bool UsedAssumedInformation =
false;
6377 QueryingValueSimplified =
A.getAssumedSimplified(
6379 return unionAssumed(QueryingValueSimplified);
6383 template <
typename AAType>
bool askSimplifiedValueFor(Attributor &
A) {
6384 if (!getAssociatedValue().
getType()->isIntegerTy())
6389 A.getAAFor<AAType>(*
this, getIRPosition(), DepClassTy::NONE);
6393 std::optional<Constant *> COpt = AA->getAssumedConstant(
A);
6396 SimplifiedAssociatedValue = std::nullopt;
6397 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6400 if (
auto *
C = *COpt) {
6401 SimplifiedAssociatedValue =
C;
6402 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6408 bool askSimplifiedValueForOtherAAs(Attributor &
A) {
6409 if (askSimplifiedValueFor<AAValueConstantRange>(
A))
6411 if (askSimplifiedValueFor<AAPotentialConstantValues>(
A))
6419 for (
auto &U : getAssociatedValue().uses()) {
6424 IP =
PHI->getIncomingBlock(U)->getTerminator();
6425 if (
auto *NewV = manifestReplacementValue(
A, IP)) {
6427 <<
" -> " << *NewV <<
" :: " << *
this <<
"\n");
6428 if (
A.changeUseAfterManifest(U, *NewV))
6429 Changed = ChangeStatus::CHANGED;
6433 return Changed | AAValueSimplify::manifest(
A);
6438 SimplifiedAssociatedValue = &getAssociatedValue();
6439 return AAValueSimplify::indicatePessimisticFixpoint();
6443struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
6444 AAValueSimplifyArgument(
const IRPosition &IRP, Attributor &
A)
6445 : AAValueSimplifyImpl(IRP,
A) {}
6448 AAValueSimplifyImpl::initialize(
A);
6449 if (
A.hasAttr(getIRPosition(),
6450 {Attribute::InAlloca, Attribute::Preallocated,
6451 Attribute::StructRet, Attribute::Nest, Attribute::ByVal},
6453 indicatePessimisticFixpoint();
6460 Argument *Arg = getAssociatedArgument();
6466 return indicatePessimisticFixpoint();
6469 auto Before = SimplifiedAssociatedValue;
6471 auto PredForCallSite = [&](AbstractCallSite ACS) {
6472 const IRPosition &ACSArgPos =
6483 bool UsedAssumedInformation =
false;
6484 std::optional<Constant *> SimpleArgOp =
6485 A.getAssumedConstant(ACSArgPos, *
this, UsedAssumedInformation);
6492 return unionAssumed(*SimpleArgOp);
6497 bool UsedAssumedInformation =
false;
6498 if (hasCallBaseContext() &&
6499 getCallBaseContext()->getCalledOperand() == Arg->
getParent())
6501 AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
6503 Success =
A.checkForAllCallSites(PredForCallSite, *
this,
true,
6504 UsedAssumedInformation);
6507 if (!askSimplifiedValueForOtherAAs(
A))
6508 return indicatePessimisticFixpoint();
6511 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6512 : ChangeStatus ::CHANGED;
6516 void trackStatistics()
const override {
6521struct AAValueSimplifyReturned : AAValueSimplifyImpl {
6522 AAValueSimplifyReturned(
const IRPosition &IRP, Attributor &
A)
6523 : AAValueSimplifyImpl(IRP,
A) {}
6526 std::optional<Value *>
6527 getAssumedSimplifiedValue(Attributor &
A)
const override {
6528 if (!isValidState())
6530 return SimplifiedAssociatedValue;
6535 auto Before = SimplifiedAssociatedValue;
6539 return checkAndUpdate(
6544 bool UsedAssumedInformation =
false;
6545 if (!
A.checkForAllInstructions(ReturnInstCB, *
this, {Instruction::Ret},
6546 UsedAssumedInformation))
6547 if (!askSimplifiedValueForOtherAAs(
A))
6548 return indicatePessimisticFixpoint();
6551 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6552 : ChangeStatus ::CHANGED;
6558 return ChangeStatus::UNCHANGED;
6562 void trackStatistics()
const override {
6567struct AAValueSimplifyFloating : AAValueSimplifyImpl {
6568 AAValueSimplifyFloating(
const IRPosition &IRP, Attributor &
A)
6569 : AAValueSimplifyImpl(IRP,
A) {}
6573 AAValueSimplifyImpl::initialize(
A);
6574 Value &
V = getAnchorValue();
6578 indicatePessimisticFixpoint();
6583 auto Before = SimplifiedAssociatedValue;
6584 if (!askSimplifiedValueForOtherAAs(
A))
6585 return indicatePessimisticFixpoint();
6588 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6589 : ChangeStatus ::CHANGED;
6593 void trackStatistics()
const override {
6598struct AAValueSimplifyFunction : AAValueSimplifyImpl {
6599 AAValueSimplifyFunction(
const IRPosition &IRP, Attributor &
A)
6600 : AAValueSimplifyImpl(IRP,
A) {}
6604 SimplifiedAssociatedValue =
nullptr;
6605 indicateOptimisticFixpoint();
6610 "AAValueSimplify(Function|CallSite)::updateImpl will not be called");
6613 void trackStatistics()
const override {
6618struct AAValueSimplifyCallSite : AAValueSimplifyFunction {
6619 AAValueSimplifyCallSite(
const IRPosition &IRP, Attributor &
A)
6620 : AAValueSimplifyFunction(IRP,
A) {}
6622 void trackStatistics()
const override {
6627struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl {
6628 AAValueSimplifyCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6629 : AAValueSimplifyImpl(IRP,
A) {}
6632 AAValueSimplifyImpl::initialize(
A);
6633 Function *Fn = getAssociatedFunction();
6634 assert(Fn &&
"Did expect an associted function");
6635 for (Argument &Arg : Fn->
args()) {
6640 checkAndUpdate(
A, *
this, IRP))
6641 indicateOptimisticFixpoint();
6643 indicatePessimisticFixpoint();
6651 return indicatePessimisticFixpoint();
6654 void trackStatistics()
const override {
6659struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
6660 AAValueSimplifyCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6661 : AAValueSimplifyFloating(IRP,
A) {}
6667 auto *FloatAA =
A.lookupAAFor<AAValueSimplify>(
6669 if (FloatAA && FloatAA->getState().isValidState())
6672 if (
auto *NewV = manifestReplacementValue(
A, getCtxI())) {
6674 ->getArgOperandUse(getCallSiteArgNo());
6675 if (
A.changeUseAfterManifest(U, *NewV))
6676 Changed = ChangeStatus::CHANGED;
6679 return Changed | AAValueSimplify::manifest(
A);
6682 void trackStatistics()
const override {
6690struct AAHeapToStackFunction final :
public AAHeapToStack {
6692 struct AllocationInfo {
6697 LibFunc LibraryFunctionId = NotLibFunc;
6704 } Status = STACK_DUE_TO_USE;
6708 bool HasPotentiallyFreeingUnknownUses =
false;
6712 bool MoveAllocaIntoEntry =
true;
6715 SmallSetVector<CallBase *, 1> PotentialFreeCalls{};
6718 struct DeallocationInfo {
6726 bool MightFreeUnknownObjects =
false;
6729 SmallSetVector<CallBase *, 1> PotentialAllocationCalls{};
6732 AAHeapToStackFunction(
const IRPosition &IRP, Attributor &
A)
6733 : AAHeapToStack(IRP,
A) {}
6735 ~AAHeapToStackFunction()
override {
6738 for (
auto &It : AllocationInfos)
6739 It.second->~AllocationInfo();
6740 for (
auto &It : DeallocationInfos)
6741 It.second->~DeallocationInfo();
6745 AAHeapToStack::initialize(
A);
6748 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6755 DeallocationInfos[CB] =
new (
A.Allocator) DeallocationInfo{CB, FreedOp};
6762 auto *I8Ty = Type::getInt8Ty(CB->
getParent()->getContext());
6764 AllocationInfo *AI =
new (
A.Allocator) AllocationInfo{CB};
6765 AllocationInfos[CB] = AI;
6767 TLI->getLibFunc(*CB, AI->LibraryFunctionId);
6773 bool UsedAssumedInformation =
false;
6774 bool Success =
A.checkForAllCallLikeInstructions(
6775 AllocationIdentifierCB, *
this, UsedAssumedInformation,
6779 assert(
Success &&
"Did not expect the call base visit callback to fail!");
6782 [](
const IRPosition &,
const AbstractAttribute *,
6783 bool &) -> std::optional<Value *> {
return nullptr; };
6784 for (
const auto &It : AllocationInfos)
6787 for (
const auto &It : DeallocationInfos)
6792 const std::string getAsStr(Attributor *
A)
const override {
6793 unsigned NumH2SMallocs = 0, NumInvalidMallocs = 0;
6794 for (
const auto &It : AllocationInfos) {
6795 if (It.second->Status == AllocationInfo::INVALID)
6796 ++NumInvalidMallocs;
6800 return "[H2S] Mallocs Good/Bad: " + std::to_string(NumH2SMallocs) +
"/" +
6801 std::to_string(NumInvalidMallocs);
6805 void trackStatistics()
const override {
6807 MallocCalls, Function,
6808 "Number of malloc/calloc/aligned_alloc calls converted to allocas");
6809 for (
const auto &It : AllocationInfos)
6810 if (It.second->Status != AllocationInfo::INVALID)
6814 bool isAssumedHeapToStack(
const CallBase &CB)
const override {
6816 if (AllocationInfo *AI =
6817 AllocationInfos.lookup(
const_cast<CallBase *
>(&CB)))
6818 return AI->Status != AllocationInfo::INVALID;
6822 bool isAssumedHeapToStackRemovedFree(CallBase &CB)
const override {
6823 if (!isValidState())
6826 for (
const auto &It : AllocationInfos) {
6827 AllocationInfo &AI = *It.second;
6828 if (AI.Status == AllocationInfo::INVALID)
6831 if (AI.PotentialFreeCalls.count(&CB))
6839 assert(getState().isValidState() &&
6840 "Attempted to manifest an invalid state!");
6844 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6846 for (
auto &It : AllocationInfos) {
6847 AllocationInfo &AI = *It.second;
6848 if (AI.Status == AllocationInfo::INVALID)
6851 for (CallBase *FreeCall : AI.PotentialFreeCalls) {
6852 LLVM_DEBUG(
dbgs() <<
"H2S: Removing free call: " << *FreeCall <<
"\n");
6853 A.deleteAfterManifest(*FreeCall);
6854 HasChanged = ChangeStatus::CHANGED;
6857 LLVM_DEBUG(
dbgs() <<
"H2S: Removing malloc-like call: " << *AI.CB
6860 auto Remark = [&](OptimizationRemark
OR) {
6861 LibFunc IsAllocShared;
6862 if (TLI->getLibFunc(*AI.CB, IsAllocShared))
6863 if (IsAllocShared == LibFunc___kmpc_alloc_shared)
6864 return OR <<
"Moving globalized variable to the stack.";
6865 return OR <<
"Moving memory allocation from the heap to the stack.";
6867 if (AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared)
6868 A.emitRemark<OptimizationRemark>(AI.CB,
"OMP110",
Remark);
6870 A.emitRemark<OptimizationRemark>(AI.CB,
"HeapToStack",
Remark);
6872 const DataLayout &
DL =
A.getInfoCache().getDL();
6874 std::optional<APInt> SizeAPI =
getSize(
A, *
this, AI);
6876 Size = ConstantInt::get(AI.CB->getContext(), *SizeAPI);
6878 LLVMContext &Ctx = AI.CB->getContext();
6879 ObjectSizeOpts Opts;
6880 ObjectSizeOffsetEvaluator Eval(
DL, TLI, Ctx, Opts);
6881 SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);
6888 ?
F->getEntryBlock().begin()
6889 : AI.CB->getIterator();
6892 if (MaybeAlign RetAlign = AI.CB->getRetAlign())
6893 Alignment = std::max(Alignment, *RetAlign);
6895 std::optional<APInt> AlignmentAPI = getAPInt(
A, *
this, *Align);
6896 assert(AlignmentAPI && AlignmentAPI->getZExtValue() > 0 &&
6897 "Expected an alignment during manifest!");
6899 std::max(Alignment,
assumeAligned(AlignmentAPI->getZExtValue()));
6903 unsigned AS =
DL.getAllocaAddrSpace();
6905 new AllocaInst(Type::getInt8Ty(
F->getContext()), AS,
Size, Alignment,
6906 AI.CB->getName() +
".h2s", IP);
6908 if (Alloca->
getType() != AI.CB->getType())
6909 Alloca = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6910 Alloca, AI.CB->getType(),
"malloc_cast", AI.CB->getIterator());
6912 auto *I8Ty = Type::getInt8Ty(
F->getContext());
6915 "Must be able to materialize initial memory state of allocation");
6920 auto *NBB =
II->getNormalDest();
6922 A.deleteAfterManifest(*AI.CB);
6924 A.deleteAfterManifest(*AI.CB);
6933 Builder.CreateMemSet(Alloca, InitVal,
Size, std::nullopt);
6935 HasChanged = ChangeStatus::CHANGED;
6941 std::optional<APInt> getAPInt(Attributor &
A,
const AbstractAttribute &AA,
6943 bool UsedAssumedInformation =
false;
6944 std::optional<Constant *> SimpleV =
6945 A.getAssumedConstant(V, AA, UsedAssumedInformation);
6947 return APInt(64, 0);
6949 return CI->getValue();
6950 return std::nullopt;
6953 std::optional<APInt>
getSize(Attributor &
A,
const AbstractAttribute &AA,
6954 AllocationInfo &AI) {
6955 auto Mapper = [&](
const Value *
V) ->
const Value * {
6956 bool UsedAssumedInformation =
false;
6957 if (std::optional<Constant *> SimpleV =
6958 A.getAssumedConstant(*V, AA, UsedAssumedInformation))
6965 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6971 MapVector<CallBase *, AllocationInfo *> AllocationInfos;
6975 MapVector<CallBase *, DeallocationInfo *> DeallocationInfos;
6980ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &
A) {
6983 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6985 const auto *LivenessAA =
6988 MustBeExecutedContextExplorer *Explorer =
6989 A.getInfoCache().getMustBeExecutedContextExplorer();
6991 bool StackIsAccessibleByOtherThreads =
6992 A.getInfoCache().stackIsAccessibleByOtherThreads();
6995 A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(*F);
6996 std::optional<bool> MayContainIrreducibleControl;
6998 if (&
F->getEntryBlock() == &BB)
7000 if (!MayContainIrreducibleControl.has_value())
7002 if (*MayContainIrreducibleControl)
7011 bool HasUpdatedFrees =
false;
7013 auto UpdateFrees = [&]() {
7014 HasUpdatedFrees =
true;
7016 for (
auto &It : DeallocationInfos) {
7017 DeallocationInfo &DI = *It.second;
7020 if (DI.MightFreeUnknownObjects)
7024 bool UsedAssumedInformation =
false;
7025 if (
A.isAssumedDead(*DI.CB,
this, LivenessAA, UsedAssumedInformation,
7032 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown underlying object for free!\n");
7033 DI.MightFreeUnknownObjects =
true;
7046 DI.MightFreeUnknownObjects =
true;
7050 AllocationInfo *AI = AllocationInfos.lookup(ObjCB);
7052 LLVM_DEBUG(
dbgs() <<
"[H2S] Free of a non-allocation object: " << *Obj
7054 DI.MightFreeUnknownObjects =
true;
7058 DI.PotentialAllocationCalls.insert(ObjCB);
7062 auto FreeCheck = [&](AllocationInfo &AI) {
7066 if (!StackIsAccessibleByOtherThreads) {
7071 dbgs() <<
"[H2S] found an escaping use, stack is not accessible by "
7072 "other threads and function is not nosync:\n");
7076 if (!HasUpdatedFrees)
7080 if (AI.PotentialFreeCalls.size() != 1) {
7082 << AI.PotentialFreeCalls.size() <<
"\n");
7085 CallBase *UniqueFree = *AI.PotentialFreeCalls.begin();
7086 DeallocationInfo *DI = DeallocationInfos.lookup(UniqueFree);
7089 dbgs() <<
"[H2S] unique free call was not known as deallocation call "
7090 << *UniqueFree <<
"\n");
7093 if (DI->MightFreeUnknownObjects) {
7095 dbgs() <<
"[H2S] unique free call might free unknown allocations\n");
7098 if (DI->PotentialAllocationCalls.empty())
7100 if (DI->PotentialAllocationCalls.size() > 1) {
7102 << DI->PotentialAllocationCalls.size()
7103 <<
" different allocations\n");
7106 if (*DI->PotentialAllocationCalls.begin() != AI.CB) {
7109 <<
"[H2S] unique free call not known to free this allocation but "
7110 << **DI->PotentialAllocationCalls.begin() <<
"\n");
7115 if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared) {
7117 if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
7118 LLVM_DEBUG(
dbgs() <<
"[H2S] unique free call might not be executed "
7119 "with the allocation "
7120 << *UniqueFree <<
"\n");
7127 auto UsesCheck = [&](AllocationInfo &AI) {
7128 bool ValidUsesOnly =
true;
7130 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
7135 if (
SI->getValueOperand() ==
U.get()) {
7137 <<
"[H2S] escaping store to memory: " << *UserI <<
"\n");
7138 ValidUsesOnly =
false;
7147 if (DeallocationInfos.count(CB)) {
7148 AI.PotentialFreeCalls.insert(CB);
7155 bool IsKnownNoCapture;
7164 if (!IsAssumedNoCapture ||
7165 (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared &&
7166 !IsAssumedNoFree)) {
7167 AI.HasPotentiallyFreeingUnknownUses |= !IsAssumedNoFree;
7170 auto Remark = [&](OptimizationRemarkMissed ORM) {
7172 <<
"Could not move globalized variable to the stack. "
7173 "Variable is potentially captured in call. Mark "
7174 "parameter as `__attribute__((noescape))` to override.";
7177 if (ValidUsesOnly &&
7178 AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared)
7179 A.emitRemark<OptimizationRemarkMissed>(CB,
"OMP113",
Remark);
7182 ValidUsesOnly =
false;
7195 ValidUsesOnly =
false;
7198 if (!
A.checkForAllUses(Pred, *
this, *AI.CB,
false,
7200 [&](
const Use &OldU,
const Use &NewU) {
7201 auto *SI = dyn_cast<StoreInst>(OldU.getUser());
7202 return !SI || StackIsAccessibleByOtherThreads ||
7203 AA::isAssumedThreadLocalObject(
7204 A, *SI->getPointerOperand(), *this);
7207 return ValidUsesOnly;
7212 for (
auto &It : AllocationInfos) {
7213 AllocationInfo &AI = *It.second;
7214 if (AI.Status == AllocationInfo::INVALID)
7218 std::optional<APInt> APAlign = getAPInt(
A, *
this, *Align);
7222 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown allocation alignment: " << *AI.CB
7224 AI.Status = AllocationInfo::INVALID;
7229 !APAlign->isPowerOf2()) {
7230 LLVM_DEBUG(
dbgs() <<
"[H2S] Invalid allocation alignment: " << APAlign
7232 AI.Status = AllocationInfo::INVALID;
7239 if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared &&
7244 dbgs() <<
"[H2S] Unknown allocation size: " << *AI.CB <<
"\n";
7246 dbgs() <<
"[H2S] Allocation size too large: " << *AI.CB <<
" vs. "
7250 AI.Status = AllocationInfo::INVALID;
7256 switch (AI.Status) {
7257 case AllocationInfo::STACK_DUE_TO_USE:
7260 AI.Status = AllocationInfo::STACK_DUE_TO_FREE;
7262 case AllocationInfo::STACK_DUE_TO_FREE:
7265 AI.Status = AllocationInfo::INVALID;
7268 case AllocationInfo::INVALID:
7275 bool IsGlobalizedLocal =
7276 AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared;
7277 if (AI.MoveAllocaIntoEntry &&
7278 (!
Size.has_value() ||
7279 (!IsGlobalizedLocal && IsInLoop(*AI.CB->getParent()))))
7280 AI.MoveAllocaIntoEntry =
false;
7289struct AAPrivatizablePtrImpl :
public AAPrivatizablePtr {
7290 AAPrivatizablePtrImpl(
const IRPosition &IRP, Attributor &
A)
7291 : AAPrivatizablePtr(IRP,
A), PrivatizableType(std::nullopt) {}
7294 AAPrivatizablePtr::indicatePessimisticFixpoint();
7295 PrivatizableType =
nullptr;
7296 return ChangeStatus::CHANGED;
7302 virtual std::optional<Type *> identifyPrivatizableType(Attributor &
A) = 0;
7306 std::optional<Type *> combineTypes(std::optional<Type *> T0,
7307 std::optional<Type *>
T1) {
7317 std::optional<Type *> getPrivatizableType()
const override {
7318 return PrivatizableType;
7321 const std::string getAsStr(Attributor *
A)
const override {
7322 return isAssumedPrivatizablePtr() ?
"[priv]" :
"[no-priv]";
7326 std::optional<Type *> PrivatizableType;
7331struct AAPrivatizablePtrArgument final :
public AAPrivatizablePtrImpl {
7332 AAPrivatizablePtrArgument(
const IRPosition &IRP, Attributor &
A)
7333 : AAPrivatizablePtrImpl(IRP,
A) {}
7336 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7339 bool UsedAssumedInformation =
false;
7341 A.getAttrs(getIRPosition(), {Attribute::ByVal},
Attrs,
7343 if (!
Attrs.empty() &&
7344 A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *
this,
7345 true, UsedAssumedInformation))
7346 return Attrs[0].getValueAsType();
7348 std::optional<Type *> Ty;
7349 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
7357 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7366 A.getAAFor<AAPrivatizablePtr>(*
this, ACSArgPos, DepClassTy::REQUIRED);
7369 std::optional<Type *> CSTy = PrivCSArgAA->getPrivatizableType();
7372 dbgs() <<
"[AAPrivatizablePtr] ACSPos: " << ACSArgPos <<
", CSTy: ";
7376 dbgs() <<
"<nullptr>";
7381 Ty = combineTypes(Ty, CSTy);
7384 dbgs() <<
" : New Type: ";
7386 (*Ty)->print(
dbgs());
7388 dbgs() <<
"<nullptr>";
7397 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7398 UsedAssumedInformation))
7405 PrivatizableType = identifyPrivatizableType(
A);
7406 if (!PrivatizableType)
7407 return ChangeStatus::UNCHANGED;
7408 if (!*PrivatizableType)
7409 return indicatePessimisticFixpoint();
7414 DepClassTy::OPTIONAL);
7417 if (!
A.hasAttr(getIRPosition(), Attribute::ByVal) &&
7420 return indicatePessimisticFixpoint();
7426 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7430 Function &Fn = *getIRPosition().getAnchorScope();
7432 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(Fn);
7434 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Missing TTI for function "
7436 return indicatePessimisticFixpoint();
7439 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7446 bool UsedAssumedInformation =
false;
7447 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7448 UsedAssumedInformation)) {
7450 dbgs() <<
"[AAPrivatizablePtr] ABI incompatibility detected for "
7452 return indicatePessimisticFixpoint();
7456 Argument *Arg = getAssociatedArgument();
7457 if (!
A.isValidFunctionSignatureRewrite(*Arg, ReplacementTypes)) {
7459 return indicatePessimisticFixpoint();
7466 auto IsCompatiblePrivArgOfCallback = [&](CallBase &CB) {
7469 for (
const Use *U : CallbackUses) {
7470 AbstractCallSite CBACS(U);
7471 assert(CBACS && CBACS.isCallbackCall());
7472 for (Argument &CBArg : CBACS.getCalledFunction()->args()) {
7473 int CBArgNo = CBACS.getCallArgOperandNo(CBArg);
7477 <<
"[AAPrivatizablePtr] Argument " << *Arg
7478 <<
"check if can be privatized in the context of its parent ("
7480 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7482 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7483 <<
")\n[AAPrivatizablePtr] " << CBArg <<
" : "
7484 << CBACS.getCallArgOperand(CBArg) <<
" vs "
7486 <<
"[AAPrivatizablePtr] " << CBArg <<
" : "
7487 << CBACS.getCallArgOperandNo(CBArg) <<
" vs " << ArgNo <<
"\n";
7490 if (CBArgNo !=
int(ArgNo))
7492 const auto *CBArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7494 if (CBArgPrivAA && CBArgPrivAA->isValidState()) {
7495 auto CBArgPrivTy = CBArgPrivAA->getPrivatizableType();
7498 if (*CBArgPrivTy == PrivatizableType)
7503 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7504 <<
" cannot be privatized in the context of its parent ("
7506 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7508 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7509 <<
").\n[AAPrivatizablePtr] for which the argument "
7510 "privatization is not compatible.\n";
7520 auto IsCompatiblePrivArgOfDirectCS = [&](AbstractCallSite ACS) {
7524 "Expected a direct call operand for callback call operand");
7529 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7530 <<
" check if be privatized in the context of its parent ("
7532 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7534 << DCArgNo <<
"@" << DCCallee->
getName() <<
").\n";
7537 if (
unsigned(DCArgNo) < DCCallee->
arg_size()) {
7538 const auto *DCArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7540 DepClassTy::REQUIRED);
7541 if (DCArgPrivAA && DCArgPrivAA->isValidState()) {
7542 auto DCArgPrivTy = DCArgPrivAA->getPrivatizableType();
7545 if (*DCArgPrivTy == PrivatizableType)
7551 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7552 <<
" cannot be privatized in the context of its parent ("
7554 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7557 <<
").\n[AAPrivatizablePtr] for which the argument "
7558 "privatization is not compatible.\n";
7566 auto IsCompatiblePrivArgOfOtherCallSite = [&](AbstractCallSite ACS) {
7570 return IsCompatiblePrivArgOfDirectCS(ACS);
7574 if (!
A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *
this,
true,
7575 UsedAssumedInformation))
7576 return indicatePessimisticFixpoint();
7578 return ChangeStatus::UNCHANGED;
7584 identifyReplacementTypes(
Type *PrivType,
7585 SmallVectorImpl<Type *> &ReplacementTypes) {
7588 assert(PrivType &&
"Expected privatizable type!");
7592 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++)
7593 ReplacementTypes.
push_back(PrivStructType->getElementType(u));
7595 ReplacementTypes.
append(PrivArrayType->getNumElements(),
7596 PrivArrayType->getElementType());
7605 static void createInitialization(
Type *PrivType,
Value &
Base, Function &
F,
7607 assert(PrivType &&
"Expected privatizable type!");
7610 const DataLayout &
DL =
F.getDataLayout();
7614 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7615 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7618 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7621 Type *PointeeTy = PrivArrayType->getElementType();
7622 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7623 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7625 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7628 new StoreInst(
F.getArg(ArgNo), &
Base, IP);
7634 void createReplacementValues(Align Alignment,
Type *PrivType,
7636 SmallVectorImpl<Value *> &ReplacementValues) {
7638 assert(PrivType &&
"Expected privatizable type!");
7646 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7647 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7648 Type *PointeeTy = PrivStructType->getElementType(u);
7651 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7652 L->setAlignment(Alignment);
7656 Type *PointeeTy = PrivArrayType->getElementType();
7657 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7658 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7660 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7661 L->setAlignment(Alignment);
7666 L->setAlignment(Alignment);
7673 if (!PrivatizableType)
7674 return ChangeStatus::UNCHANGED;
7675 assert(*PrivatizableType &&
"Expected privatizable type!");
7681 bool UsedAssumedInformation =
false;
7682 if (!
A.checkForAllInstructions(
7683 [&](Instruction &
I) {
7684 CallInst &CI = cast<CallInst>(I);
7685 if (CI.isTailCall())
7686 TailCalls.push_back(&CI);
7689 *
this, {Instruction::Call}, UsedAssumedInformation))
7690 return ChangeStatus::UNCHANGED;
7692 Argument *Arg = getAssociatedArgument();
7695 const auto *AlignAA =
7702 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7704 BasicBlock &EntryBB = ReplacementFn.getEntryBlock();
7706 const DataLayout &
DL = IP->getDataLayout();
7707 unsigned AS =
DL.getAllocaAddrSpace();
7708 Instruction *AI =
new AllocaInst(*PrivatizableType, AS,
7709 Arg->
getName() +
".priv", IP);
7710 createInitialization(*PrivatizableType, *AI, ReplacementFn,
7711 ArgIt->getArgNo(), IP);
7714 AI = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
7718 for (CallInst *CI : TailCalls)
7719 CI->setTailCall(
false);
7726 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7727 AbstractCallSite ACS, SmallVectorImpl<Value *> &NewArgOperands) {
7730 createReplacementValues(
7731 AlignAA ? AlignAA->getAssumedAlign() :
Align(0),
7732 *PrivatizableType, ACS,
7740 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7743 if (
A.registerFunctionSignatureRewrite(*Arg, ReplacementTypes,
7744 std::move(FnRepairCB),
7745 std::move(ACSRepairCB)))
7746 return ChangeStatus::CHANGED;
7747 return ChangeStatus::UNCHANGED;
7751 void trackStatistics()
const override {
7756struct AAPrivatizablePtrFloating :
public AAPrivatizablePtrImpl {
7757 AAPrivatizablePtrFloating(
const IRPosition &IRP, Attributor &
A)
7758 : AAPrivatizablePtrImpl(IRP,
A) {}
7763 indicatePessimisticFixpoint();
7768 "updateImpl will not be called");
7772 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7775 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] No underlying object found!\n");
7782 return AI->getAllocatedType();
7784 auto *PrivArgAA =
A.getAAFor<AAPrivatizablePtr>(
7786 if (PrivArgAA && PrivArgAA->isAssumedPrivatizablePtr())
7787 return PrivArgAA->getPrivatizableType();
7790 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Underlying object neither valid "
7791 "alloca nor privatizable argument: "
7797 void trackStatistics()
const override {
7802struct AAPrivatizablePtrCallSiteArgument final
7803 :
public AAPrivatizablePtrFloating {
7804 AAPrivatizablePtrCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
7805 : AAPrivatizablePtrFloating(IRP,
A) {}
7809 if (
A.hasAttr(getIRPosition(), Attribute::ByVal))
7810 indicateOptimisticFixpoint();
7815 PrivatizableType = identifyPrivatizableType(
A);
7816 if (!PrivatizableType)
7817 return ChangeStatus::UNCHANGED;
7818 if (!*PrivatizableType)
7819 return indicatePessimisticFixpoint();
7821 const IRPosition &IRP = getIRPosition();
7822 bool IsKnownNoCapture;
7824 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoCapture);
7825 if (!IsAssumedNoCapture) {
7826 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might be captured!\n");
7827 return indicatePessimisticFixpoint();
7830 bool IsKnownNoAlias;
7832 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
7833 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might alias!\n");
7834 return indicatePessimisticFixpoint();
7839 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer is written!\n");
7840 return indicatePessimisticFixpoint();
7843 return ChangeStatus::UNCHANGED;
7847 void trackStatistics()
const override {
7852struct AAPrivatizablePtrCallSiteReturned final
7853 :
public AAPrivatizablePtrFloating {
7854 AAPrivatizablePtrCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
7855 : AAPrivatizablePtrFloating(IRP,
A) {}
7860 indicatePessimisticFixpoint();
7864 void trackStatistics()
const override {
7869struct AAPrivatizablePtrReturned final :
public AAPrivatizablePtrFloating {
7870 AAPrivatizablePtrReturned(
const IRPosition &IRP, Attributor &
A)
7871 : AAPrivatizablePtrFloating(IRP,
A) {}
7876 indicatePessimisticFixpoint();
7880 void trackStatistics()
const override {
7890struct AAMemoryBehaviorImpl :
public AAMemoryBehavior {
7891 AAMemoryBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
7892 : AAMemoryBehavior(IRP,
A) {}
7896 intersectAssumedBits(BEST_STATE);
7897 getKnownStateFromValue(
A, getIRPosition(), getState());
7898 AAMemoryBehavior::initialize(
A);
7902 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
7903 BitIntegerState &State,
7904 bool IgnoreSubsumingPositions =
false) {
7906 A.getAttrs(IRP, AttrKinds, Attrs, IgnoreSubsumingPositions);
7908 switch (Attr.getKindAsEnum()) {
7909 case Attribute::ReadNone:
7912 case Attribute::ReadOnly:
7915 case Attribute::WriteOnly:
7924 if (!
I->mayReadFromMemory())
7926 if (!
I->mayWriteToMemory())
7932 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
7933 SmallVectorImpl<Attribute> &Attrs)
const override {
7936 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));
7938 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));
7939 else if (isAssumedWriteOnly())
7940 Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));
7946 const IRPosition &IRP = getIRPosition();
7948 if (
A.hasAttr(IRP, Attribute::ReadNone,
7950 return ChangeStatus::UNCHANGED;
7959 return ChangeStatus::UNCHANGED;
7962 A.removeAttrs(IRP, AttrKinds);
7965 A.removeAttrs(IRP, Attribute::Writable);
7972 const std::string getAsStr(Attributor *
A)
const override {
7977 if (isAssumedWriteOnly())
7979 return "may-read/write";
7983 static const Attribute::AttrKind AttrKinds[3];
7987 Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};
7990struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {
7991 AAMemoryBehaviorFloating(
const IRPosition &IRP, Attributor &
A)
7992 : AAMemoryBehaviorImpl(IRP,
A) {}
7998 void trackStatistics()
const override {
8003 else if (isAssumedWriteOnly())
8010 bool followUsersOfUseIn(Attributor &
A,
const Use &U,
8011 const Instruction *UserI);
8014 void analyzeUseIn(Attributor &
A,
const Use &U,
const Instruction *UserI);
8018struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
8019 AAMemoryBehaviorArgument(
const IRPosition &IRP, Attributor &
A)
8020 : AAMemoryBehaviorFloating(IRP,
A) {}
8024 intersectAssumedBits(BEST_STATE);
8025 const IRPosition &IRP = getIRPosition();
8029 bool HasByVal =
A.hasAttr(IRP, {Attribute::ByVal},
8031 getKnownStateFromValue(
A, IRP, getState(),
8038 return ChangeStatus::UNCHANGED;
8042 if (
A.hasAttr(getIRPosition(),
8043 {Attribute::InAlloca, Attribute::Preallocated})) {
8044 removeKnownBits(NO_WRITES);
8045 removeAssumedBits(NO_WRITES);
8047 A.removeAttrs(getIRPosition(), AttrKinds);
8048 return AAMemoryBehaviorFloating::manifest(
A);
8052 void trackStatistics()
const override {
8057 else if (isAssumedWriteOnly())
8062struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {
8063 AAMemoryBehaviorCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
8064 : AAMemoryBehaviorArgument(IRP,
A) {}
8070 Argument *Arg = getAssociatedArgument();
8072 indicatePessimisticFixpoint();
8076 addKnownBits(NO_WRITES);
8077 removeKnownBits(NO_READS);
8078 removeAssumedBits(NO_READS);
8080 AAMemoryBehaviorArgument::initialize(
A);
8081 if (getAssociatedFunction()->isDeclaration())
8082 indicatePessimisticFixpoint();
8091 Argument *Arg = getAssociatedArgument();
8094 A.getAAFor<AAMemoryBehavior>(*
this, ArgPos, DepClassTy::REQUIRED);
8096 return indicatePessimisticFixpoint();
8101 void trackStatistics()
const override {
8106 else if (isAssumedWriteOnly())
8112struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {
8113 AAMemoryBehaviorCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
8114 : AAMemoryBehaviorFloating(IRP,
A) {}
8118 AAMemoryBehaviorImpl::initialize(
A);
8123 return ChangeStatus::UNCHANGED;
8127 void trackStatistics()
const override {}
8131struct AAMemoryBehaviorFunction final :
public AAMemoryBehaviorImpl {
8132 AAMemoryBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
8133 : AAMemoryBehaviorImpl(IRP,
A) {}
8149 else if (isAssumedWriteOnly())
8152 A.removeAttrs(getIRPosition(), AttrKinds);
8155 for (Argument &Arg :
F.args())
8157 return A.manifestAttrs(getIRPosition(),
8158 Attribute::getWithMemoryEffects(
F.getContext(), ME));
8162 void trackStatistics()
const override {
8167 else if (isAssumedWriteOnly())
8173struct AAMemoryBehaviorCallSite final
8174 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl> {
8175 AAMemoryBehaviorCallSite(
const IRPosition &IRP, Attributor &
A)
8176 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl>(IRP,
A) {}
8187 else if (isAssumedWriteOnly())
8190 A.removeAttrs(getIRPosition(), AttrKinds);
8193 for (Use &U : CB.
args())
8195 Attribute::Writable);
8196 return A.manifestAttrs(
8197 getIRPosition(), Attribute::getWithMemoryEffects(CB.
getContext(), ME));
8201 void trackStatistics()
const override {
8206 else if (isAssumedWriteOnly())
8211ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &
A) {
8214 auto AssumedState = getAssumed();
8221 const auto *MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
8223 if (MemBehaviorAA) {
8224 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8225 return !isAtFixpoint();
8230 if (
I.mayReadFromMemory())
8231 removeAssumedBits(NO_READS);
8232 if (
I.mayWriteToMemory())
8233 removeAssumedBits(NO_WRITES);
8234 return !isAtFixpoint();
8237 bool UsedAssumedInformation =
false;
8238 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8239 UsedAssumedInformation))
8240 return indicatePessimisticFixpoint();
8246ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &
A) {
8248 const IRPosition &IRP = getIRPosition();
8259 const auto *FnMemAA =
8262 FnMemAssumedState = FnMemAA->getAssumed();
8263 S.addKnownBits(FnMemAA->getKnown());
8264 if ((S.getAssumed() & FnMemAA->getAssumed()) == S.getAssumed())
8270 auto AssumedState = S.getAssumed();
8276 bool IsKnownNoCapture;
8277 const AANoCapture *ArgNoCaptureAA =
nullptr;
8282 if (!IsAssumedNoCapture &&
8284 S.intersectAssumedBits(FnMemAssumedState);
8290 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
8292 LLVM_DEBUG(
dbgs() <<
"[AAMemoryBehavior] Use: " << *U <<
" in " << *UserI
8300 Follow = followUsersOfUseIn(
A, U, UserI);
8304 analyzeUseIn(
A, U, UserI);
8306 return !isAtFixpoint();
8309 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue()))
8310 return indicatePessimisticFixpoint();
8316bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &
A,
const Use &U,
8317 const Instruction *UserI) {
8335 if (
U.get()->getType()->isPointerTy()) {
8337 bool IsKnownNoCapture;
8346void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &
A,
const Use &U,
8347 const Instruction *UserI) {
8354 case Instruction::Load:
8356 removeAssumedBits(NO_READS);
8359 case Instruction::Store:
8364 removeAssumedBits(NO_WRITES);
8366 indicatePessimisticFixpoint();
8369 case Instruction::Call:
8370 case Instruction::CallBr:
8371 case Instruction::Invoke: {
8378 indicatePessimisticFixpoint();
8385 removeAssumedBits(NO_READS);
8392 if (
U.get()->getType()->isPointerTy())
8396 const auto *MemBehaviorAA =
8402 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8410 removeAssumedBits(NO_READS);
8412 removeAssumedBits(NO_WRITES);
8424 return "all memory";
8427 std::string S =
"memory:";
8433 S +=
"internal global,";
8435 S +=
"external global,";
8439 S +=
"inaccessible,";
8453 AccessKind2Accesses.fill(
nullptr);
8456 ~AAMemoryLocationImpl()
override {
8459 for (AccessSet *AS : AccessKind2Accesses)
8466 intersectAssumedBits(BEST_STATE);
8467 getKnownStateFromValue(
A, getIRPosition(), getState());
8468 AAMemoryLocation::initialize(
A);
8472 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
8473 BitIntegerState &State,
8474 bool IgnoreSubsumingPositions =
false) {
8483 bool UseArgMemOnly =
true;
8485 if (AnchorFn &&
A.isRunOn(*AnchorFn))
8489 A.getAttrs(IRP, {Attribute::Memory},
Attrs, IgnoreSubsumingPositions);
8498 State.
addKnownBits(inverseLocation(NO_INACCESSIBLE_MEM,
true,
true));
8503 State.
addKnownBits(inverseLocation(NO_ARGUMENT_MEM,
true,
true));
8507 A.manifestAttrs(IRP,
8508 Attribute::getWithMemoryEffects(
8517 NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM,
true,
true));
8521 A.manifestAttrs(IRP,
8522 Attribute::getWithMemoryEffects(
8532 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
8533 SmallVectorImpl<Attribute> &Attrs)
const override {
8540 else if (isAssumedInaccessibleMemOnly())
8541 Attrs.push_back(Attribute::getWithMemoryEffects(
8543 else if (isAssumedArgMemOnly())
8546 else if (isAssumedInaccessibleOrArgMemOnly())
8547 Attrs.push_back(Attribute::getWithMemoryEffects(
8557 const IRPosition &IRP = getIRPosition();
8561 if (DeducedAttrs.
size() != 1)
8562 return ChangeStatus::UNCHANGED;
8565 return A.manifestAttrs(IRP, Attribute::getWithMemoryEffects(
8570 bool checkForAllAccessesToMemoryKind(
8572 MemoryLocationsKind)>
8574 MemoryLocationsKind RequestedMLK)
const override {
8575 if (!isValidState())
8578 MemoryLocationsKind AssumedMLK = getAssumedNotAccessedLocation();
8579 if (AssumedMLK == NO_LOCATIONS)
8583 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS;
8584 CurMLK *= 2, ++Idx) {
8585 if (CurMLK & RequestedMLK)
8588 if (
const AccessSet *
Accesses = AccessKind2Accesses[Idx])
8589 for (
const AccessInfo &AI : *
Accesses)
8590 if (!Pred(AI.I, AI.Ptr, AI.Kind, CurMLK))
8603 MemoryLocationsKind KnownMLK = getKnown();
8605 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2)
8606 if (!(CurMLK & KnownMLK))
8607 updateStateAndAccessesMap(getState(), CurMLK,
I,
nullptr,
Changed,
8608 getAccessKindFromInst(
I));
8609 return AAMemoryLocation::indicatePessimisticFixpoint();
8629 bool operator()(
const AccessInfo &
LHS,
const AccessInfo &
RHS)
const {
8633 return LHS.Ptr <
RHS.Ptr;
8634 if (
LHS.Kind !=
RHS.Kind)
8635 return LHS.Kind <
RHS.Kind;
8642 using AccessSet = SmallSet<AccessInfo, 2, AccessInfo>;
8643 std::array<AccessSet *, llvm::ConstantLog2<VALID_STATE>()>
8644 AccessKind2Accesses;
8649 categorizeArgumentPointerLocations(Attributor &
A, CallBase &CB,
8650 AAMemoryLocation::StateType &AccessedLocs,
8655 categorizeAccessedLocations(Attributor &
A, Instruction &
I,
bool &
Changed);
8658 AccessKind getAccessKindFromInst(
const Instruction *
I) {
8661 AK =
I->mayReadFromMemory() ? READ :
NONE;
8670 void updateStateAndAccessesMap(AAMemoryLocation::StateType &State,
8671 MemoryLocationsKind MLK,
const Instruction *
I,
8680 if (MLK == NO_UNKOWN_MEM)
8682 State.removeAssumedBits(MLK);
8687 void categorizePtrValue(Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8688 AAMemoryLocation::StateType &State,
bool &
Changed,
8689 unsigned AccessAS = 0);
8695void AAMemoryLocationImpl::categorizePtrValue(
8696 Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8698 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize pointer locations for "
8703 unsigned ObjectAS =
Obj.getType()->getPointerAddressSpace();
8705 MemoryLocationsKind MLK = NO_LOCATIONS;
8724 MLK = NO_ARGUMENT_MEM;
8730 if (GVar->isConstant())
8733 if (GV->hasLocalLinkage())
8734 MLK = NO_GLOBAL_INTERNAL_MEM;
8736 MLK = NO_GLOBAL_EXTERNAL_MEM;
8744 bool IsKnownNoAlias;
8748 MLK = NO_MALLOCED_MEM;
8750 MLK = NO_UNKOWN_MEM;
8752 MLK = NO_UNKOWN_MEM;
8755 assert(MLK != NO_LOCATIONS &&
"No location specified!");
8756 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Ptr value can be categorized: "
8757 << Obj <<
" -> " << getMemoryLocationsAsStr(MLK) <<
"\n");
8759 getAccessKindFromInst(&
I));
8764 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
8768 dbgs() <<
"[AAMemoryLocation] Pointer locations not categorized\n");
8769 updateStateAndAccessesMap(
State, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8770 getAccessKindFromInst(&
I));
8775 dbgs() <<
"[AAMemoryLocation] Accessed locations with pointer locations: "
8779void AAMemoryLocationImpl::categorizeArgumentPointerLocations(
8782 for (
unsigned ArgNo = 0,
E = CB.
arg_size(); ArgNo <
E; ++ArgNo) {
8791 const auto *ArgOpMemLocationAA =
8794 if (ArgOpMemLocationAA && ArgOpMemLocationAA->isAssumedReadNone())
8799 categorizePtrValue(
A, CB, *ArgOp, AccessedLocs,
Changed);
8804AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &
A, Instruction &
I,
8806 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize accessed locations for "
8810 AccessedLocs.intersectAssumedBits(NO_LOCATIONS);
8815 const auto *CBMemLocationAA =
A.getAAFor<AAMemoryLocation>(
8818 <<
" [" << CBMemLocationAA <<
"]\n");
8819 if (!CBMemLocationAA) {
8820 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
8821 Changed, getAccessKindFromInst(&
I));
8822 return NO_UNKOWN_MEM;
8825 if (CBMemLocationAA->isAssumedReadNone())
8826 return NO_LOCATIONS;
8828 if (CBMemLocationAA->isAssumedInaccessibleMemOnly()) {
8829 updateStateAndAccessesMap(AccessedLocs, NO_INACCESSIBLE_MEM, &
I,
nullptr,
8830 Changed, getAccessKindFromInst(&
I));
8831 return AccessedLocs.getAssumed();
8834 uint32_t CBAssumedNotAccessedLocs =
8835 CBMemLocationAA->getAssumedNotAccessedLocation();
8838 uint32_t CBAssumedNotAccessedLocsNoArgMem =
8839 CBAssumedNotAccessedLocs | NO_ARGUMENT_MEM | NO_GLOBAL_MEM;
8841 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2) {
8842 if (CBAssumedNotAccessedLocsNoArgMem & CurMLK)
8844 updateStateAndAccessesMap(AccessedLocs, CurMLK, &
I,
nullptr,
Changed,
8845 getAccessKindFromInst(&
I));
8850 bool HasGlobalAccesses = ((~CBAssumedNotAccessedLocs) & NO_GLOBAL_MEM);
8851 if (HasGlobalAccesses) {
8854 updateStateAndAccessesMap(AccessedLocs, MLK, &
I, Ptr,
Changed,
8855 getAccessKindFromInst(&
I));
8858 if (!CBMemLocationAA->checkForAllAccessesToMemoryKind(
8859 AccessPred, inverseLocation(NO_GLOBAL_MEM,
false,
false)))
8860 return AccessedLocs.getWorstState();
8864 dbgs() <<
"[AAMemoryLocation] Accessed state before argument handling: "
8865 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8868 bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM);
8870 categorizeArgumentPointerLocations(
A, *CB, AccessedLocs,
Changed);
8873 dbgs() <<
"[AAMemoryLocation] Accessed state after argument handling: "
8874 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8876 return AccessedLocs.getAssumed();
8881 dbgs() <<
"[AAMemoryLocation] Categorize memory access with pointer: "
8882 <<
I <<
" [" << *Ptr <<
"]\n");
8883 categorizePtrValue(
A,
I, *Ptr, AccessedLocs,
Changed,
8884 Ptr->getType()->getPointerAddressSpace());
8885 return AccessedLocs.getAssumed();
8888 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Failed to categorize instruction: "
8890 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8891 getAccessKindFromInst(&
I));
8892 return AccessedLocs.getAssumed();
8896struct AAMemoryLocationFunction final :
public AAMemoryLocationImpl {
8897 AAMemoryLocationFunction(
const IRPosition &IRP, Attributor &
A)
8898 : AAMemoryLocationImpl(IRP,
A) {}
8903 const auto *MemBehaviorAA =
8904 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
8907 return indicateOptimisticFixpoint();
8909 "AAMemoryLocation was not read-none but AAMemoryBehavior was!");
8910 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
8911 return ChangeStatus::UNCHANGED;
8915 auto AssumedState = getAssumed();
8919 MemoryLocationsKind MLK = categorizeAccessedLocations(
A,
I,
Changed);
8920 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Accessed locations for " <<
I
8921 <<
": " << getMemoryLocationsAsStr(MLK) <<
"\n");
8922 removeAssumedBits(inverseLocation(MLK,
false,
false));
8925 return getAssumedNotAccessedLocation() != VALID_STATE;
8928 bool UsedAssumedInformation =
false;
8929 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8930 UsedAssumedInformation))
8931 return indicatePessimisticFixpoint();
8933 Changed |= AssumedState != getAssumed();
8934 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8938 void trackStatistics()
const override {
8941 else if (isAssumedArgMemOnly())
8943 else if (isAssumedInaccessibleMemOnly())
8945 else if (isAssumedInaccessibleOrArgMemOnly())
8951struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {
8952 AAMemoryLocationCallSite(
const IRPosition &IRP, Attributor &
A)
8953 : AAMemoryLocationImpl(IRP,
A) {}
8964 A.getAAFor<AAMemoryLocation>(*
this, FnPos, DepClassTy::REQUIRED);
8966 return indicatePessimisticFixpoint();
8970 updateStateAndAccessesMap(getState(), MLK,
I, Ptr,
Changed,
8971 getAccessKindFromInst(
I));
8974 if (!FnAA->checkForAllAccessesToMemoryKind(AccessPred, ALL_LOCATIONS))
8975 return indicatePessimisticFixpoint();
8976 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8980 void trackStatistics()
const override {
8990struct AADenormalFPMathImpl :
public AADenormalFPMath {
8991 AADenormalFPMathImpl(
const IRPosition &IRP, Attributor &
A)
8992 : AADenormalFPMath(IRP,
A) {}
8994 const std::string getAsStr(Attributor *
A)
const override {
8995 std::string Str(
"AADenormalFPMath[");
8996 raw_string_ostream OS(Str);
8998 DenormalState Known = getKnown();
8999 if (Known.Mode.isValid())
9000 OS <<
"denormal-fp-math=" << Known.Mode;
9004 if (Known.ModeF32.isValid())
9005 OS <<
" denormal-fp-math-f32=" << Known.ModeF32;
9011struct AADenormalFPMathFunction final : AADenormalFPMathImpl {
9012 AADenormalFPMathFunction(
const IRPosition &IRP, Attributor &
A)
9013 : AADenormalFPMathImpl(IRP,
A) {}
9017 DenormalFPEnv DenormEnv =
F->getDenormalFPEnv();
9027 auto CheckCallSite = [=, &Change, &
A](AbstractCallSite CS) {
9030 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
9032 const auto *CallerInfo =
A.getAAFor<AADenormalFPMath>(
9038 CallerInfo->getState());
9042 bool AllCallSitesKnown =
true;
9043 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
9044 return indicatePessimisticFixpoint();
9046 if (Change == ChangeStatus::CHANGED && isModeFixed())
9052 LLVMContext &Ctx = getAssociatedFunction()->getContext();
9058 DenormalFPEnv KnownEnv(Known.Mode, Known.ModeF32);
9061 AttrToRemove.
push_back(Attribute::DenormalFPEnv);
9064 Ctx, Attribute::DenormalFPEnv,
9065 DenormalFPEnv(Known.Mode, Known.ModeF32).toIntValue()));
9068 auto &IRP = getIRPosition();
9071 return A.removeAttrs(IRP, AttrToRemove) |
9072 A.manifestAttrs(IRP, AttrToAdd,
true);
9075 void trackStatistics()
const override {
9084struct AAValueConstantRangeImpl : AAValueConstantRange {
9085 using StateType = IntegerRangeState;
9086 AAValueConstantRangeImpl(
const IRPosition &IRP, Attributor &
A)
9087 : AAValueConstantRange(IRP,
A) {}
9091 if (
A.hasSimplificationCallback(getIRPosition())) {
9092 indicatePessimisticFixpoint();
9097 intersectKnown(getConstantRangeFromSCEV(
A, getCtxI()));
9100 intersectKnown(getConstantRangeFromLVI(
A, getCtxI()));
9104 const std::string getAsStr(Attributor *
A)
const override {
9106 llvm::raw_string_ostream OS(Str);
9108 getKnown().print(OS);
9110 getAssumed().print(OS);
9117 const SCEV *getSCEV(Attributor &
A,
const Instruction *
I =
nullptr)
const {
9118 if (!getAnchorScope())
9121 ScalarEvolution *SE =
9122 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9125 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
9131 const SCEV *S = SE->
getSCEV(&getAssociatedValue());
9140 ConstantRange getConstantRangeFromSCEV(Attributor &
A,
9141 const Instruction *
I =
nullptr)
const {
9142 if (!getAnchorScope())
9145 ScalarEvolution *SE =
9146 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9149 const SCEV *S = getSCEV(
A,
I);
9159 getConstantRangeFromLVI(Attributor &
A,
9160 const Instruction *CtxI =
nullptr)
const {
9161 if (!getAnchorScope())
9164 LazyValueInfo *LVI =
9165 A.getInfoCache().getAnalysisResultForFunction<LazyValueAnalysis>(
9180 bool isValidCtxInstructionForOutsideAnalysis(Attributor &
A,
9181 const Instruction *CtxI,
9182 bool AllowAACtxI)
const {
9183 if (!CtxI || (!AllowAACtxI && CtxI == getCtxI()))
9195 InformationCache &InfoCache =
A.getInfoCache();
9196 const DominatorTree *DT =
9207 getKnownConstantRange(Attributor &
A,
9208 const Instruction *CtxI =
nullptr)
const override {
9209 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9213 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9214 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9215 return getKnown().intersectWith(SCEVR).intersectWith(LVIR);
9220 getAssumedConstantRange(Attributor &
A,
9221 const Instruction *CtxI =
nullptr)
const override {
9226 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9228 return getAssumed();
9230 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9231 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9232 return getAssumed().intersectWith(SCEVR).intersectWith(LVIR);
9237 getMDNodeForConstantRange(
Type *Ty, LLVMContext &Ctx,
9238 const ConstantRange &AssumedConstantRange) {
9240 Ty, AssumedConstantRange.
getLower())),
9242 Ty, AssumedConstantRange.
getUpper()))};
9247 static bool isBetterRange(
const ConstantRange &Assumed,
9248 const Instruction &
I) {
9252 std::optional<ConstantRange> Known;
9256 }
else if (MDNode *KnownRanges =
I.getMetadata(LLVMContext::MD_range)) {
9262 if (KnownRanges->getNumOperands() > 2)
9265 ConstantInt *
Lower =
9267 ConstantInt *
Upper =
9270 Known.emplace(
Lower->getValue(),
Upper->getValue());
9272 return !Known || (*Known != Assumed && Known->contains(Assumed));
9277 setRangeMetadataIfisBetterRange(Instruction *
I,
9278 const ConstantRange &AssumedConstantRange) {
9279 if (isBetterRange(AssumedConstantRange, *
I)) {
9280 I->setMetadata(LLVMContext::MD_range,
9281 getMDNodeForConstantRange(
I->getType(),
I->getContext(),
9282 AssumedConstantRange));
9289 setRangeRetAttrIfisBetterRange(Attributor &
A,
const IRPosition &IRP,
9291 const ConstantRange &AssumedConstantRange) {
9292 if (isBetterRange(AssumedConstantRange, *
I)) {
9293 A.manifestAttrs(IRP,
9294 Attribute::get(
I->getContext(), Attribute::Range,
9295 AssumedConstantRange),
9305 ConstantRange AssumedConstantRange = getAssumedConstantRange(
A);
9308 auto &
V = getAssociatedValue();
9312 assert(
I == getCtxI() &&
"Should not annotate an instruction which is "
9313 "not the context instruction");
9315 if (setRangeMetadataIfisBetterRange(
I, AssumedConstantRange))
9316 Changed = ChangeStatus::CHANGED;
9318 if (setRangeRetAttrIfisBetterRange(
A, getIRPosition(),
I,
9319 AssumedConstantRange))
9320 Changed = ChangeStatus::CHANGED;
9328struct AAValueConstantRangeArgument final
9329 : AAArgumentFromCallSiteArguments<
9330 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9332 using Base = AAArgumentFromCallSiteArguments<
9333 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9335 AAValueConstantRangeArgument(
const IRPosition &IRP, Attributor &
A)
9339 void trackStatistics()
const override {
9344struct AAValueConstantRangeReturned
9345 : AAReturnedFromReturnedValues<AAValueConstantRange,
9346 AAValueConstantRangeImpl,
9347 AAValueConstantRangeImpl::StateType,
9350 AAReturnedFromReturnedValues<AAValueConstantRange,
9351 AAValueConstantRangeImpl,
9352 AAValueConstantRangeImpl::StateType,
9354 AAValueConstantRangeReturned(
const IRPosition &IRP, Attributor &
A)
9359 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9360 indicatePessimisticFixpoint();
9364 void trackStatistics()
const override {
9369struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
9370 AAValueConstantRangeFloating(
const IRPosition &IRP, Attributor &
A)
9371 : AAValueConstantRangeImpl(IRP,
A) {}
9375 AAValueConstantRangeImpl::initialize(
A);
9379 Value &
V = getAssociatedValue();
9382 unionAssumed(ConstantRange(
C->getValue()));
9383 indicateOptimisticFixpoint();
9389 unionAssumed(ConstantRange(APInt(
getBitWidth(), 0)));
9390 indicateOptimisticFixpoint();
9402 if (
auto *RangeMD = LI->getMetadata(LLVMContext::MD_range)) {
9413 indicatePessimisticFixpoint();
9416 << getAssociatedValue() <<
"\n");
9419 bool calculateBinaryOperator(
9420 Attributor &
A, BinaryOperator *BinOp, IntegerRangeState &
T,
9421 const Instruction *CtxI,
9422 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9427 bool UsedAssumedInformation =
false;
9428 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9431 if (!SimplifiedLHS.has_value())
9433 if (!*SimplifiedLHS)
9435 LHS = *SimplifiedLHS;
9437 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9440 if (!SimplifiedRHS.has_value())
9442 if (!*SimplifiedRHS)
9444 RHS = *SimplifiedRHS;
9450 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9452 DepClassTy::REQUIRED);
9456 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9458 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9460 DepClassTy::REQUIRED);
9464 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9466 auto AssumedRange = LHSAARange.binaryOp(BinOp->
getOpcode(), RHSAARange);
9468 T.unionAssumed(AssumedRange);
9472 return T.isValidState();
9475 bool calculateCastInst(
9476 Attributor &
A, CastInst *CastI, IntegerRangeState &
T,
9477 const Instruction *CtxI,
9478 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9484 bool UsedAssumedInformation =
false;
9485 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9488 if (!SimplifiedOpV.has_value())
9490 if (!*SimplifiedOpV)
9492 OpV = *SimplifiedOpV;
9497 auto *OpAA =
A.getAAFor<AAValueConstantRange>(
9499 DepClassTy::REQUIRED);
9503 T.unionAssumed(OpAA->getAssumed().castOp(CastI->
getOpcode(),
9505 return T.isValidState();
9509 calculateCmpInst(Attributor &
A, CmpInst *CmpI, IntegerRangeState &
T,
9510 const Instruction *CtxI,
9511 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9516 bool UsedAssumedInformation =
false;
9517 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9520 if (!SimplifiedLHS.has_value())
9522 if (!*SimplifiedLHS)
9524 LHS = *SimplifiedLHS;
9526 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9529 if (!SimplifiedRHS.has_value())
9531 if (!*SimplifiedRHS)
9533 RHS = *SimplifiedRHS;
9539 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9541 DepClassTy::REQUIRED);
9545 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9547 DepClassTy::REQUIRED);
9551 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9552 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9555 if (LHSAARange.isEmptySet() || RHSAARange.isEmptySet())
9558 bool MustTrue =
false, MustFalse =
false;
9560 auto AllowedRegion =
9563 if (AllowedRegion.intersectWith(LHSAARange).isEmptySet())
9569 assert((!MustTrue || !MustFalse) &&
9570 "Either MustTrue or MustFalse should be false!");
9573 T.unionAssumed(ConstantRange(APInt( 1, 1)));
9575 T.unionAssumed(ConstantRange(APInt( 1, 0)));
9577 T.unionAssumed(ConstantRange( 1,
true));
9579 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] " << *CmpI <<
" after "
9580 << (MustTrue ?
"true" : (MustFalse ?
"false" :
"unknown"))
9581 <<
": " <<
T <<
"\n\t" << *LHSAA <<
"\t<op>\n\t"
9585 return T.isValidState();
9597 bool UsedAssumedInformation =
false;
9598 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9601 if (!SimplifiedOpV.has_value())
9603 if (!*SimplifiedOpV)
9605 Value *VPtr = *SimplifiedOpV;
9608 const auto *AA =
A.getAAFor<AAValueConstantRange>(
9610 DepClassTy::REQUIRED);
9614 T.unionAssumed(AA->getAssumedConstantRange(
A, CtxI));
9618 return T.isValidState();
9623 if (!calculateBinaryOperator(
A, BinOp,
T, CtxI, QuerriedAAs))
9626 if (!calculateCmpInst(
A, CmpI,
T, CtxI, QuerriedAAs))
9629 if (!calculateCastInst(
A, CastI,
T, CtxI, QuerriedAAs))
9635 T.indicatePessimisticFixpoint();
9642 for (
const AAValueConstantRange *QueriedAA : QuerriedAAs) {
9643 if (QueriedAA !=
this)
9646 if (
T.getAssumed() == getState().getAssumed())
9648 T.indicatePessimisticFixpoint();
9651 return T.isValidState();
9654 if (!VisitValueCB(getAssociatedValue(), getCtxI()))
9655 return indicatePessimisticFixpoint();
9660 return ChangeStatus::UNCHANGED;
9661 if (++NumChanges > MaxNumChanges) {
9662 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] performed " << NumChanges
9663 <<
" but only " << MaxNumChanges
9664 <<
" are allowed to avoid cyclic reasoning.");
9665 return indicatePessimisticFixpoint();
9667 return ChangeStatus::CHANGED;
9671 void trackStatistics()
const override {
9680 static constexpr int MaxNumChanges = 5;
9683struct AAValueConstantRangeFunction : AAValueConstantRangeImpl {
9684 AAValueConstantRangeFunction(
const IRPosition &IRP, Attributor &
A)
9685 : AAValueConstantRangeImpl(IRP,
A) {}
9689 llvm_unreachable(
"AAValueConstantRange(Function|CallSite)::updateImpl will "
9697struct AAValueConstantRangeCallSite : AAValueConstantRangeFunction {
9698 AAValueConstantRangeCallSite(
const IRPosition &IRP, Attributor &
A)
9699 : AAValueConstantRangeFunction(IRP,
A) {}
9705struct AAValueConstantRangeCallSiteReturned
9706 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9707 AAValueConstantRangeImpl::StateType,
9709 AAValueConstantRangeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
9710 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9711 AAValueConstantRangeImpl::StateType,
9718 if (std::optional<ConstantRange>
Range = CI->getRange())
9719 intersectKnown(*
Range);
9722 AAValueConstantRangeImpl::initialize(
A);
9726 void trackStatistics()
const override {
9730struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating {
9731 AAValueConstantRangeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
9732 : AAValueConstantRangeFloating(IRP,
A) {}
9736 return ChangeStatus::UNCHANGED;
9740 void trackStatistics()
const override {
9749struct AAPotentialConstantValuesImpl : AAPotentialConstantValues {
9752 AAPotentialConstantValuesImpl(
const IRPosition &IRP, Attributor &
A)
9753 : AAPotentialConstantValues(IRP,
A) {}
9757 if (
A.hasSimplificationCallback(getIRPosition()))
9758 indicatePessimisticFixpoint();
9760 AAPotentialConstantValues::initialize(
A);
9763 bool fillSetWithConstantValues(Attributor &
A,
const IRPosition &IRP, SetTy &S,
9764 bool &ContainsUndef,
bool ForSelf) {
9766 bool UsedAssumedInformation =
false;
9768 UsedAssumedInformation)) {
9775 auto *PotentialValuesAA =
A.getAAFor<AAPotentialConstantValues>(
9776 *
this, IRP, DepClassTy::REQUIRED);
9777 if (!PotentialValuesAA || !PotentialValuesAA->getState().isValidState())
9779 ContainsUndef = PotentialValuesAA->getState().undefIsContained();
9780 S = PotentialValuesAA->getState().getAssumedSet();
9787 ContainsUndef =
false;
9788 for (
auto &It : Values) {
9790 ContainsUndef =
true;
9796 S.insert(CI->getValue());
9798 ContainsUndef &= S.empty();
9804 const std::string getAsStr(Attributor *
A)
const override {
9806 llvm::raw_string_ostream OS(Str);
9813 return indicatePessimisticFixpoint();
9817struct AAPotentialConstantValuesArgument final
9818 : AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9819 AAPotentialConstantValuesImpl,
9820 PotentialConstantIntValuesState> {
9821 using Base = AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9822 AAPotentialConstantValuesImpl,
9824 AAPotentialConstantValuesArgument(
const IRPosition &IRP, Attributor &
A)
9828 void trackStatistics()
const override {
9833struct AAPotentialConstantValuesReturned
9834 : AAReturnedFromReturnedValues<AAPotentialConstantValues,
9835 AAPotentialConstantValuesImpl> {
9836 using Base = AAReturnedFromReturnedValues<AAPotentialConstantValues,
9837 AAPotentialConstantValuesImpl>;
9838 AAPotentialConstantValuesReturned(
const IRPosition &IRP, Attributor &
A)
9842 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9843 indicatePessimisticFixpoint();
9844 Base::initialize(
A);
9848 void trackStatistics()
const override {
9853struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl {
9854 AAPotentialConstantValuesFloating(
const IRPosition &IRP, Attributor &
A)
9855 : AAPotentialConstantValuesImpl(IRP,
A) {}
9859 AAPotentialConstantValuesImpl::initialize(
A);
9863 Value &
V = getAssociatedValue();
9866 unionAssumed(
C->getValue());
9867 indicateOptimisticFixpoint();
9872 unionAssumedWithUndef();
9873 indicateOptimisticFixpoint();
9883 indicatePessimisticFixpoint();
9886 << getAssociatedValue() <<
"\n");
9889 static bool calculateICmpInst(
const ICmpInst *ICI,
const APInt &
LHS,
9894 static APInt calculateCastInst(
const CastInst *CI,
const APInt &Src,
9895 uint32_t ResultBitWidth) {
9900 case Instruction::Trunc:
9901 return Src.trunc(ResultBitWidth);
9902 case Instruction::SExt:
9903 return Src.sext(ResultBitWidth);
9904 case Instruction::ZExt:
9905 return Src.zext(ResultBitWidth);
9906 case Instruction::BitCast:
9911 static APInt calculateBinaryOperator(
const BinaryOperator *BinOp,
9912 const APInt &
LHS,
const APInt &
RHS,
9913 bool &SkipOperation,
bool &Unsupported) {
9920 switch (BinOpcode) {
9924 case Instruction::Add:
9926 case Instruction::Sub:
9928 case Instruction::Mul:
9930 case Instruction::UDiv:
9932 SkipOperation =
true;
9936 case Instruction::SDiv:
9938 SkipOperation =
true;
9942 case Instruction::URem:
9944 SkipOperation =
true;
9948 case Instruction::SRem:
9950 SkipOperation =
true;
9954 case Instruction::Shl:
9956 case Instruction::LShr:
9958 case Instruction::AShr:
9960 case Instruction::And:
9962 case Instruction::Or:
9964 case Instruction::Xor:
9969 bool calculateBinaryOperatorAndTakeUnion(
const BinaryOperator *BinOp,
9970 const APInt &
LHS,
const APInt &
RHS) {
9971 bool SkipOperation =
false;
9974 calculateBinaryOperator(BinOp,
LHS,
RHS, SkipOperation, Unsupported);
9979 unionAssumed(Result);
9980 return isValidState();
9983 ChangeStatus updateWithICmpInst(Attributor &
A, ICmpInst *ICI) {
9984 auto AssumedBefore = getAssumed();
9988 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
9989 SetTy LHSAAPVS, RHSAAPVS;
9991 LHSContainsUndef,
false) ||
9993 RHSContainsUndef,
false))
9994 return indicatePessimisticFixpoint();
9997 bool MaybeTrue =
false, MaybeFalse =
false;
9999 if (LHSContainsUndef && RHSContainsUndef) {
10002 unionAssumedWithUndef();
10003 }
else if (LHSContainsUndef) {
10004 for (
const APInt &R : RHSAAPVS) {
10005 bool CmpResult = calculateICmpInst(ICI, Zero, R);
10006 MaybeTrue |= CmpResult;
10007 MaybeFalse |= !CmpResult;
10008 if (MaybeTrue & MaybeFalse)
10009 return indicatePessimisticFixpoint();
10011 }
else if (RHSContainsUndef) {
10012 for (
const APInt &L : LHSAAPVS) {
10013 bool CmpResult = calculateICmpInst(ICI, L, Zero);
10014 MaybeTrue |= CmpResult;
10015 MaybeFalse |= !CmpResult;
10016 if (MaybeTrue & MaybeFalse)
10017 return indicatePessimisticFixpoint();
10020 for (
const APInt &L : LHSAAPVS) {
10021 for (
const APInt &R : RHSAAPVS) {
10022 bool CmpResult = calculateICmpInst(ICI, L, R);
10023 MaybeTrue |= CmpResult;
10024 MaybeFalse |= !CmpResult;
10025 if (MaybeTrue & MaybeFalse)
10026 return indicatePessimisticFixpoint();
10031 unionAssumed(APInt( 1, 1));
10033 unionAssumed(APInt( 1, 0));
10034 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10035 : ChangeStatus::CHANGED;
10038 ChangeStatus updateWithSelectInst(Attributor &
A, SelectInst *SI) {
10039 auto AssumedBefore = getAssumed();
10043 bool UsedAssumedInformation =
false;
10044 std::optional<Constant *>
C =
A.getAssumedConstant(
10045 *
SI->getCondition(), *
this, UsedAssumedInformation);
10048 bool OnlyLeft =
false, OnlyRight =
false;
10049 if (
C && *
C && (*C)->isOneValue())
10051 else if (
C && *
C && (*C)->isNullValue())
10054 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10055 SetTy LHSAAPVS, RHSAAPVS;
10058 LHSContainsUndef,
false))
10059 return indicatePessimisticFixpoint();
10063 RHSContainsUndef,
false))
10064 return indicatePessimisticFixpoint();
10066 if (OnlyLeft || OnlyRight) {
10068 auto *OpAA = OnlyLeft ? &LHSAAPVS : &RHSAAPVS;
10069 auto Undef = OnlyLeft ? LHSContainsUndef : RHSContainsUndef;
10072 unionAssumedWithUndef();
10074 for (
const auto &It : *OpAA)
10078 }
else if (LHSContainsUndef && RHSContainsUndef) {
10080 unionAssumedWithUndef();
10082 for (
const auto &It : LHSAAPVS)
10084 for (
const auto &It : RHSAAPVS)
10087 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10088 : ChangeStatus::CHANGED;
10091 ChangeStatus updateWithCastInst(Attributor &
A, CastInst *CI) {
10092 auto AssumedBefore = getAssumed();
10094 return indicatePessimisticFixpoint();
10099 bool SrcContainsUndef =
false;
10102 SrcContainsUndef,
false))
10103 return indicatePessimisticFixpoint();
10105 if (SrcContainsUndef)
10106 unionAssumedWithUndef();
10108 for (
const APInt &S : SrcPVS) {
10109 APInt
T = calculateCastInst(CI, S, ResultBitWidth);
10113 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10114 : ChangeStatus::CHANGED;
10117 ChangeStatus updateWithBinaryOperator(Attributor &
A, BinaryOperator *BinOp) {
10118 auto AssumedBefore = getAssumed();
10122 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10123 SetTy LHSAAPVS, RHSAAPVS;
10125 LHSContainsUndef,
false) ||
10127 RHSContainsUndef,
false))
10128 return indicatePessimisticFixpoint();
10133 if (LHSContainsUndef && RHSContainsUndef) {
10134 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))
10135 return indicatePessimisticFixpoint();
10136 }
else if (LHSContainsUndef) {
10137 for (
const APInt &R : RHSAAPVS) {
10138 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))
10139 return indicatePessimisticFixpoint();
10141 }
else if (RHSContainsUndef) {
10142 for (
const APInt &L : LHSAAPVS) {
10143 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
10144 return indicatePessimisticFixpoint();
10147 for (
const APInt &L : LHSAAPVS) {
10148 for (
const APInt &R : RHSAAPVS) {
10149 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
10150 return indicatePessimisticFixpoint();
10154 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10155 : ChangeStatus::CHANGED;
10158 ChangeStatus updateWithInstruction(Attributor &
A, Instruction *Inst) {
10159 auto AssumedBefore = getAssumed();
10161 bool ContainsUndef;
10163 ContainsUndef,
true))
10164 return indicatePessimisticFixpoint();
10165 if (ContainsUndef) {
10166 unionAssumedWithUndef();
10168 for (
const auto &It : Incoming)
10171 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10172 : ChangeStatus::CHANGED;
10177 Value &
V = getAssociatedValue();
10181 return updateWithICmpInst(
A, ICI);
10184 return updateWithSelectInst(
A, SI);
10187 return updateWithCastInst(
A, CI);
10190 return updateWithBinaryOperator(
A, BinOp);
10193 return updateWithInstruction(
A,
I);
10195 return indicatePessimisticFixpoint();
10199 void trackStatistics()
const override {
10204struct AAPotentialConstantValuesFunction : AAPotentialConstantValuesImpl {
10205 AAPotentialConstantValuesFunction(
const IRPosition &IRP, Attributor &
A)
10206 : AAPotentialConstantValuesImpl(IRP,
A) {}
10211 "AAPotentialConstantValues(Function|CallSite)::updateImpl will "
10216 void trackStatistics()
const override {
10221struct AAPotentialConstantValuesCallSite : AAPotentialConstantValuesFunction {
10222 AAPotentialConstantValuesCallSite(
const IRPosition &IRP, Attributor &
A)
10223 : AAPotentialConstantValuesFunction(IRP,
A) {}
10226 void trackStatistics()
const override {
10231struct AAPotentialConstantValuesCallSiteReturned
10232 : AACalleeToCallSite<AAPotentialConstantValues,
10233 AAPotentialConstantValuesImpl> {
10234 AAPotentialConstantValuesCallSiteReturned(
const IRPosition &IRP,
10236 : AACalleeToCallSite<AAPotentialConstantValues,
10237 AAPotentialConstantValuesImpl>(IRP,
A) {}
10240 void trackStatistics()
const override {
10245struct AAPotentialConstantValuesCallSiteArgument
10246 : AAPotentialConstantValuesFloating {
10247 AAPotentialConstantValuesCallSiteArgument(
const IRPosition &IRP,
10249 : AAPotentialConstantValuesFloating(IRP,
A) {}
10253 AAPotentialConstantValuesImpl::initialize(
A);
10254 if (isAtFixpoint())
10257 Value &
V = getAssociatedValue();
10260 unionAssumed(
C->getValue());
10261 indicateOptimisticFixpoint();
10266 unionAssumedWithUndef();
10267 indicateOptimisticFixpoint();
10274 Value &
V = getAssociatedValue();
10275 auto AssumedBefore = getAssumed();
10276 auto *AA =
A.getAAFor<AAPotentialConstantValues>(
10279 return indicatePessimisticFixpoint();
10280 const auto &S = AA->getAssumed();
10282 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10283 : ChangeStatus::CHANGED;
10287 void trackStatistics()
const override {
10296 bool IgnoreSubsumingPositions) {
10297 assert(ImpliedAttributeKind == Attribute::NoUndef &&
10298 "Unexpected attribute kind");
10299 if (
A.hasAttr(IRP, {Attribute::NoUndef}, IgnoreSubsumingPositions,
10300 Attribute::NoUndef))
10320 Value &V = getAssociatedValue();
10322 indicatePessimisticFixpoint();
10323 assert(!isImpliedByIR(
A, getIRPosition(), Attribute::NoUndef));
10327 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10328 AANoUndef::StateType &State) {
10329 const Value *UseV =
U->get();
10330 const DominatorTree *DT =
nullptr;
10331 AssumptionCache *AC =
nullptr;
10332 InformationCache &InfoCache =
A.getInfoCache();
10333 if (Function *
F = getAnchorScope()) {
10338 bool TrackUse =
false;
10347 const std::string getAsStr(Attributor *
A)
const override {
10348 return getAssumed() ?
"noundef" :
"may-undef-or-poison";
10355 bool UsedAssumedInformation =
false;
10356 if (
A.isAssumedDead(getIRPosition(),
nullptr,
nullptr,
10357 UsedAssumedInformation))
10358 return ChangeStatus::UNCHANGED;
10362 if (!
A.getAssumedSimplified(getIRPosition(), *
this, UsedAssumedInformation,
10365 return ChangeStatus::UNCHANGED;
10366 return AANoUndef::manifest(
A);
10370struct AANoUndefFloating :
public AANoUndefImpl {
10371 AANoUndefFloating(
const IRPosition &IRP, Attributor &
A)
10372 : AANoUndefImpl(IRP,
A) {}
10376 AANoUndefImpl::initialize(
A);
10377 if (!getState().isAtFixpoint() && getAnchorScope() &&
10378 !getAnchorScope()->isDeclaration())
10379 if (Instruction *CtxI = getCtxI())
10380 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10385 auto VisitValueCB = [&](
const IRPosition &IRP) ->
bool {
10386 bool IsKnownNoUndef;
10388 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoUndef);
10392 bool UsedAssumedInformation =
false;
10393 Value *AssociatedValue = &getAssociatedValue();
10395 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10400 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
10408 if (AVIRP == getIRPosition() || !VisitValueCB(AVIRP))
10409 return indicatePessimisticFixpoint();
10410 return ChangeStatus::UNCHANGED;
10413 for (
const auto &VAC : Values)
10415 return indicatePessimisticFixpoint();
10417 return ChangeStatus::UNCHANGED;
10424struct AANoUndefReturned final
10425 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl> {
10426 AANoUndefReturned(
const IRPosition &IRP, Attributor &
A)
10427 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10433struct AANoUndefArgument final
10434 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl> {
10435 AANoUndefArgument(
const IRPosition &IRP, Attributor &
A)
10436 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10442struct AANoUndefCallSiteArgument final : AANoUndefFloating {
10443 AANoUndefCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10444 : AANoUndefFloating(IRP,
A) {}
10450struct AANoUndefCallSiteReturned final
10451 : AACalleeToCallSite<AANoUndef, AANoUndefImpl> {
10452 AANoUndefCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10453 : AACalleeToCallSite<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10461struct AANoFPClassImpl : AANoFPClass {
10462 AANoFPClassImpl(
const IRPosition &IRP, Attributor &
A) : AANoFPClass(IRP,
A) {}
10465 const IRPosition &IRP = getIRPosition();
10469 indicateOptimisticFixpoint();
10474 A.getAttrs(getIRPosition(), {Attribute::NoFPClass},
Attrs,
false);
10475 for (
const auto &Attr : Attrs) {
10482 const DataLayout &
DL =
A.getDataLayout();
10483 InformationCache &InfoCache =
A.getInfoCache();
10485 const DominatorTree *DT =
nullptr;
10486 AssumptionCache *AC =
nullptr;
10487 const TargetLibraryInfo *TLI =
nullptr;
10491 if (!
F->isDeclaration()) {
10498 SimplifyQuery Q(
DL, TLI, DT, AC, CtxI);
10505 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10509 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10510 AANoFPClass::StateType &State) {
10521 if (
auto *NoFPAA =
A.getAAFor<AANoFPClass>(*
this, IRP, DepClassTy::NONE))
10522 State.addKnownBits(NoFPAA->getState().getKnown());
10526 const std::string getAsStr(Attributor *
A)
const override {
10527 std::string
Result =
"nofpclass";
10528 raw_string_ostream OS(Result);
10529 OS << getKnownNoFPClass() <<
'/' << getAssumedNoFPClass();
10533 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
10534 SmallVectorImpl<Attribute> &Attrs)
const override {
10535 Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));
10539struct AANoFPClassFloating :
public AANoFPClassImpl {
10540 AANoFPClassFloating(
const IRPosition &IRP, Attributor &
A)
10541 : AANoFPClassImpl(IRP,
A) {}
10546 bool UsedAssumedInformation =
false;
10547 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10549 Values.
push_back({getAssociatedValue(), getCtxI()});
10555 DepClassTy::REQUIRED);
10556 if (!AA ||
this == AA) {
10557 T.indicatePessimisticFixpoint();
10559 const AANoFPClass::StateType &S =
10560 static_cast<const AANoFPClass::StateType &
>(AA->
getState());
10563 return T.isValidState();
10566 for (
const auto &VAC : Values)
10568 return indicatePessimisticFixpoint();
10574 void trackStatistics()
const override {
10579struct AANoFPClassReturned final
10580 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10581 AANoFPClassImpl::StateType, false,
10582 Attribute::None, false> {
10583 AANoFPClassReturned(
const IRPosition &IRP, Attributor &
A)
10584 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10585 AANoFPClassImpl::StateType,
false,
10589 void trackStatistics()
const override {
10594struct AANoFPClassArgument final
10595 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {
10596 AANoFPClassArgument(
const IRPosition &IRP, Attributor &
A)
10597 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10603struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {
10604 AANoFPClassCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10605 : AANoFPClassFloating(IRP,
A) {}
10608 void trackStatistics()
const override {
10613struct AANoFPClassCallSiteReturned final
10614 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl> {
10615 AANoFPClassCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10616 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10619 void trackStatistics()
const override {
10624struct AACallEdgesImpl :
public AACallEdges {
10625 AACallEdgesImpl(
const IRPosition &IRP, Attributor &
A) : AACallEdges(IRP,
A) {}
10627 const SetVector<Function *> &getOptimisticEdges()
const override {
10628 return CalledFunctions;
10631 bool hasUnknownCallee()
const override {
return HasUnknownCallee; }
10633 bool hasNonAsmUnknownCallee()
const override {
10634 return HasUnknownCalleeNonAsm;
10637 const std::string getAsStr(Attributor *
A)
const override {
10638 return "CallEdges[" + std::to_string(HasUnknownCallee) +
"," +
10639 std::to_string(CalledFunctions.size()) +
"]";
10642 void trackStatistics()
const override {}
10645 void addCalledFunction(Function *Fn,
ChangeStatus &Change) {
10646 if (CalledFunctions.insert(Fn)) {
10647 Change = ChangeStatus::CHANGED;
10653 void setHasUnknownCallee(
bool NonAsm,
ChangeStatus &Change) {
10654 if (!HasUnknownCallee)
10655 Change = ChangeStatus::CHANGED;
10656 if (NonAsm && !HasUnknownCalleeNonAsm)
10657 Change = ChangeStatus::CHANGED;
10658 HasUnknownCalleeNonAsm |= NonAsm;
10659 HasUnknownCallee =
true;
10664 SetVector<Function *> CalledFunctions;
10667 bool HasUnknownCallee =
false;
10670 bool HasUnknownCalleeNonAsm =
false;
10673struct AACallEdgesCallSite :
public AACallEdgesImpl {
10674 AACallEdgesCallSite(
const IRPosition &IRP, Attributor &
A)
10675 : AACallEdgesImpl(IRP,
A) {}
10682 addCalledFunction(Fn, Change);
10684 LLVM_DEBUG(
dbgs() <<
"[AACallEdges] Unrecognized value: " << V <<
"\n");
10685 setHasUnknownCallee(
true, Change);
10696 VisitValue(*V, CtxI);
10700 bool UsedAssumedInformation =
false;
10706 for (
auto &VAC : Values)
10713 if (
IA->hasSideEffects() &&
10716 setHasUnknownCallee(
false, Change);
10722 if (
auto *IndirectCallAA =
A.getAAFor<AAIndirectCallInfo>(
10723 *
this, getIRPosition(), DepClassTy::OPTIONAL))
10724 if (IndirectCallAA->foreachCallee(
10725 [&](Function *Fn) { return VisitValue(*Fn, CB); }))
10734 for (
const Use *U : CallbackUses)
10735 ProcessCalledOperand(
U->get(), CB);
10741struct AACallEdgesFunction :
public AACallEdgesImpl {
10742 AACallEdgesFunction(
const IRPosition &IRP, Attributor &
A)
10743 : AACallEdgesImpl(IRP,
A) {}
10752 auto *CBEdges =
A.getAAFor<AACallEdges>(
10756 if (CBEdges->hasNonAsmUnknownCallee())
10757 setHasUnknownCallee(
true, Change);
10758 if (CBEdges->hasUnknownCallee())
10759 setHasUnknownCallee(
false, Change);
10761 for (Function *
F : CBEdges->getOptimisticEdges())
10762 addCalledFunction(
F, Change);
10768 bool UsedAssumedInformation =
false;
10769 if (!
A.checkForAllCallLikeInstructions(ProcessCallInst, *
this,
10770 UsedAssumedInformation,
10774 setHasUnknownCallee(
true, Change);
10783struct AAInterFnReachabilityFunction
10784 :
public CachedReachabilityAA<AAInterFnReachability, Function> {
10785 using Base = CachedReachabilityAA<AAInterFnReachability, Function>;
10786 AAInterFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
10789 bool instructionCanReach(
10790 Attributor &
A,
const Instruction &From,
const Function &To,
10793 auto *NonConstThis =
const_cast<AAInterFnReachabilityFunction *
>(
this);
10795 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
10796 RQITy::Reachable
Result;
10797 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
10798 return NonConstThis->isReachableImpl(
A, StackRQI,
10800 return Result == RQITy::Reachable::Yes;
10804 bool IsTemporaryRQI)
override {
10806 &RQI.From->getFunction()->getEntryBlock().front();
10807 if (EntryI != RQI.From &&
10808 !instructionCanReach(
A, *EntryI, *RQI.To,
nullptr))
10809 return rememberResult(
A, RQITy::Reachable::No, RQI,
false,
10812 auto CheckReachableCallBase = [&](CallBase *CB) {
10813 auto *CBEdges =
A.getAAFor<AACallEdges>(
10815 if (!CBEdges || !CBEdges->getState().isValidState())
10818 if (CBEdges->hasUnknownCallee())
10821 for (Function *Fn : CBEdges->getOptimisticEdges()) {
10832 if (Fn == getAnchorScope()) {
10833 if (EntryI == RQI.From)
10838 const AAInterFnReachability *InterFnReachability =
10840 DepClassTy::OPTIONAL);
10843 if (!InterFnReachability ||
10851 const auto *IntraFnReachability =
A.getAAFor<AAIntraFnReachability>(
10853 DepClassTy::OPTIONAL);
10861 return IntraFnReachability && !IntraFnReachability->isAssumedReachable(
10862 A, *RQI.From, CBInst, RQI.ExclusionSet);
10865 bool UsedExclusionSet =
true;
10866 bool UsedAssumedInformation =
false;
10867 if (!
A.checkForAllCallLikeInstructions(CheckCallBase, *
this,
10868 UsedAssumedInformation,
10870 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
10873 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
10877 void trackStatistics()
const override {}
10881template <
typename AAType>
10882static std::optional<Constant *>
10885 if (!Ty.isIntegerTy())
10893 std::optional<Constant *> COpt =
AA->getAssumedConstant(
A);
10895 if (!COpt.has_value()) {
10897 return std::nullopt;
10899 if (
auto *
C = *COpt) {
10910 std::optional<Value *> V;
10911 for (
auto &It : Values) {
10913 if (V.has_value() && !*V)
10916 if (!V.has_value())
10930 if (
A.hasSimplificationCallback(getIRPosition())) {
10931 indicatePessimisticFixpoint();
10934 Value *Stripped = getAssociatedValue().stripPointerCasts();
10936 addValue(
A, getState(), *Stripped, getCtxI(),
AA::AnyScope,
10938 indicateOptimisticFixpoint();
10941 AAPotentialValues::initialize(
A);
10945 const std::string getAsStr(Attributor *
A)
const override {
10947 llvm::raw_string_ostream OS(Str);
10952 template <
typename AAType>
10953 static std::optional<Value *> askOtherAA(Attributor &
A,
10954 const AbstractAttribute &AA,
10955 const IRPosition &IRP,
Type &Ty) {
10960 return std::nullopt;
10967 virtual void addValue(Attributor &
A, StateType &State,
Value &V,
10969 Function *AnchorScope)
const {
10973 for (
const auto &U : CB->
args()) {
10983 Type &Ty = *getAssociatedType();
10984 std::optional<Value *> SimpleV =
10985 askOtherAA<AAValueConstantRange>(
A, *
this, ValIRP, Ty);
10986 if (SimpleV.has_value() && !*SimpleV) {
10987 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
10988 *
this, ValIRP, DepClassTy::OPTIONAL);
10989 if (PotentialConstantsAA && PotentialConstantsAA->isValidState()) {
10990 for (
const auto &It : PotentialConstantsAA->getAssumedSet())
10991 State.unionAssumed({{*ConstantInt::get(&Ty, It),
nullptr}, S});
10992 if (PotentialConstantsAA->undefIsContained())
10997 if (!SimpleV.has_value())
11009 State.unionAssumed({{*VPtr, CtxI}, S});
11015 AA::ValueAndContext
I;
11019 return II.I ==
I &&
II.S == S;
11022 return std::tie(
I, S) < std::tie(
II.I,
II.S);
11026 bool recurseForValue(Attributor &
A,
const IRPosition &IRP,
AA::ValueScope S) {
11027 SmallMapVector<AA::ValueAndContext, int, 8> ValueScopeMap;
11032 bool UsedAssumedInformation =
false;
11034 if (!
A.getAssumedSimplifiedValues(IRP,
this, Values, CS,
11035 UsedAssumedInformation))
11038 for (
auto &It : Values)
11039 ValueScopeMap[It] += CS;
11041 for (
auto &It : ValueScopeMap)
11042 addValue(
A, getState(), *It.first.getValue(), It.first.getCtxI(),
11048 void giveUpOnIntraprocedural(Attributor &
A) {
11049 auto NewS = StateType::getBestState(getState());
11050 for (
const auto &It : getAssumedSet()) {
11053 addValue(
A, NewS, *It.first.getValue(), It.first.getCtxI(),
11056 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11064 getState() = StateType::getBestState(getState());
11065 getState().unionAssumed({{getAssociatedValue(), getCtxI()},
AA::AnyScope});
11066 AAPotentialValues::indicateOptimisticFixpoint();
11067 return ChangeStatus::CHANGED;
11072 return indicatePessimisticFixpoint();
11080 if (!getAssumedSimplifiedValues(
A, Values, S))
11082 Value &OldV = getAssociatedValue();
11085 Value *NewV = getSingleValue(
A, *
this, getIRPosition(), Values);
11086 if (!NewV || NewV == &OldV)
11091 if (
A.changeAfterManifest(getIRPosition(), *NewV))
11092 return ChangeStatus::CHANGED;
11094 return ChangeStatus::UNCHANGED;
11097 bool getAssumedSimplifiedValues(
11098 Attributor &
A, SmallVectorImpl<AA::ValueAndContext> &Values,
11099 AA::ValueScope S,
bool RecurseForSelectAndPHI =
false)
const override {
11100 if (!isValidState())
11102 bool UsedAssumedInformation =
false;
11103 for (
const auto &It : getAssumedSet())
11104 if (It.second & S) {
11105 if (RecurseForSelectAndPHI && (
isa<PHINode>(It.first.getValue()) ||
11107 if (
A.getAssumedSimplifiedValues(
11109 this, Values, S, UsedAssumedInformation))
11114 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11119struct AAPotentialValuesFloating : AAPotentialValuesImpl {
11120 AAPotentialValuesFloating(
const IRPosition &IRP, Attributor &
A)
11121 : AAPotentialValuesImpl(IRP,
A) {}
11125 auto AssumedBefore = getAssumed();
11127 genericValueTraversal(
A, &getAssociatedValue());
11129 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11130 : ChangeStatus::CHANGED;
11134 struct LivenessInfo {
11135 const AAIsDead *LivenessAA =
nullptr;
11136 bool AnyDead =
false;
11146 SmallVectorImpl<ItemInfo> &Worklist) {
11149 bool UsedAssumedInformation =
false;
11151 auto GetSimplifiedValues = [&](
Value &
V,
11153 if (!
A.getAssumedSimplifiedValues(
11157 Values.
push_back(AA::ValueAndContext{
V,
II.I.getCtxI()});
11159 return Values.
empty();
11161 if (GetSimplifiedValues(*
LHS, LHSValues))
11163 if (GetSimplifiedValues(*
RHS, RHSValues))
11168 InformationCache &InfoCache =
A.getInfoCache();
11175 F ?
A.getInfoCache().getTargetLibraryInfoForFunction(*
F) :
nullptr;
11180 const DataLayout &
DL =
A.getDataLayout();
11181 SimplifyQuery Q(
DL, TLI, DT, AC, CmpI);
11183 auto CheckPair = [&](
Value &LHSV,
Value &RHSV) {
11186 nullptr,
II.S, getAnchorScope());
11192 if (&LHSV == &RHSV &&
11194 Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
11196 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11203 if (TypedLHS && TypedRHS) {
11205 if (NewV && NewV != &Cmp) {
11206 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11218 if (!LHSIsNull && !RHSIsNull)
11224 assert((LHSIsNull || RHSIsNull) &&
11225 "Expected nullptr versus non-nullptr comparison at this point");
11228 unsigned PtrIdx = LHSIsNull;
11229 bool IsKnownNonNull;
11232 DepClassTy::REQUIRED, IsKnownNonNull);
11233 if (!IsAssumedNonNull)
11239 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11244 for (
auto &LHSValue : LHSValues)
11245 for (
auto &RHSValue : RHSValues)
11246 if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))
11251 bool handleSelectInst(Attributor &
A, SelectInst &SI, ItemInfo
II,
11252 SmallVectorImpl<ItemInfo> &Worklist) {
11254 bool UsedAssumedInformation =
false;
11256 std::optional<Constant *>
C =
11257 A.getAssumedConstant(*
SI.getCondition(), *
this, UsedAssumedInformation);
11258 bool NoValueYet = !
C.has_value();
11266 }
else if (&SI == &getAssociatedValue()) {
11271 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11273 if (!SimpleV.has_value())
11276 addValue(
A, getState(), **SimpleV, CtxI,
II.S, getAnchorScope());
11284 bool handleLoadInst(Attributor &
A, LoadInst &LI, ItemInfo
II,
11285 SmallVectorImpl<ItemInfo> &Worklist) {
11286 SmallSetVector<Value *, 4> PotentialCopies;
11287 SmallSetVector<Instruction *, 4> PotentialValueOrigins;
11288 bool UsedAssumedInformation =
false;
11290 PotentialValueOrigins, *
this,
11291 UsedAssumedInformation,
11293 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Failed to get potentially "
11294 "loaded values for load instruction "
11302 InformationCache &InfoCache =
A.getInfoCache();
11304 if (!
llvm::all_of(PotentialValueOrigins, [&](Instruction *
I) {
11308 return A.isAssumedDead(
SI->getOperandUse(0),
this,
11310 UsedAssumedInformation,
11312 return A.isAssumedDead(*
I,
this,
nullptr,
11313 UsedAssumedInformation,
11316 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Load is onl used by assumes "
11317 "and we cannot delete all the stores: "
11328 bool AllLocal = ScopeIsLocal;
11333 if (!DynamicallyUnique) {
11334 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Not all potentially loaded "
11335 "values are dynamically unique: "
11340 for (
auto *PotentialCopy : PotentialCopies) {
11342 Worklist.
push_back({{*PotentialCopy, CtxI},
II.S});
11347 if (!AllLocal && ScopeIsLocal)
11352 bool handlePHINode(
11353 Attributor &
A, PHINode &
PHI, ItemInfo
II,
11354 SmallVectorImpl<ItemInfo> &Worklist,
11355 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11356 auto GetLivenessInfo = [&](
const Function &
F) -> LivenessInfo & {
11357 LivenessInfo &LI = LivenessAAs[&
F];
11358 if (!LI.LivenessAA)
11364 if (&
PHI == &getAssociatedValue()) {
11365 LivenessInfo &LI = GetLivenessInfo(*
PHI.getFunction());
11367 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
11368 *
PHI.getFunction());
11372 for (
unsigned u = 0, e =
PHI.getNumIncomingValues(); u < e; u++) {
11374 if (LI.LivenessAA &&
11375 LI.LivenessAA->isEdgeDead(IncomingBB,
PHI.getParent())) {
11394 bool UsedAssumedInformation =
false;
11395 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11397 if (!SimpleV.has_value())
11401 addValue(
A, getState(), **SimpleV, &
PHI,
II.S, getAnchorScope());
11408 bool handleGenericInst(Attributor &
A, Instruction &
I, ItemInfo
II,
11409 SmallVectorImpl<ItemInfo> &Worklist) {
11410 bool SomeSimplified =
false;
11411 bool UsedAssumedInformation =
false;
11413 SmallVector<Value *, 8> NewOps(
I.getNumOperands());
11416 const auto &SimplifiedOp =
A.getAssumedSimplified(
11421 if (!SimplifiedOp.has_value())
11425 NewOps[Idx] = *SimplifiedOp;
11429 SomeSimplified |= (NewOps[Idx] !=
Op);
11435 if (!SomeSimplified)
11438 InformationCache &InfoCache =
A.getInfoCache();
11442 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
11445 const DataLayout &
DL =
I.getDataLayout();
11446 SimplifyQuery Q(
DL, TLI, DT, AC, &
I);
11448 if (!NewV || NewV == &
I)
11451 LLVM_DEBUG(
dbgs() <<
"Generic inst " <<
I <<
" assumed simplified to "
11458 Attributor &
A, Instruction &
I, ItemInfo
II,
11459 SmallVectorImpl<ItemInfo> &Worklist,
11460 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11463 CI->getPredicate(),
II, Worklist);
11465 switch (
I.getOpcode()) {
11466 case Instruction::Select:
11468 case Instruction::PHI:
11470 case Instruction::Load:
11473 return handleGenericInst(
A,
I,
II, Worklist);
11478 void genericValueTraversal(Attributor &
A,
Value *InitialV) {
11479 SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;
11481 SmallSet<ItemInfo, 16> Visited;
11500 LLVM_DEBUG(
dbgs() <<
"Generic value traversal reached iteration limit: "
11501 << Iteration <<
"!\n");
11502 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11508 Value *NewV =
nullptr;
11509 if (
V->getType()->isPointerTy()) {
11515 for (Argument &Arg :
Callee->args())
11522 if (NewV && NewV != V) {
11523 Worklist.
push_back({{*NewV, CtxI}, S});
11537 if (V == InitialV && CtxI == getCtxI()) {
11538 indicatePessimisticFixpoint();
11542 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11543 }
while (!Worklist.
empty());
11547 for (
auto &It : LivenessAAs)
11548 if (It.second.AnyDead)
11549 A.recordDependence(*It.second.LivenessAA, *
this, DepClassTy::OPTIONAL);
11553 void trackStatistics()
const override {
11558struct AAPotentialValuesArgument final : AAPotentialValuesImpl {
11559 using Base = AAPotentialValuesImpl;
11560 AAPotentialValuesArgument(
const IRPosition &IRP, Attributor &
A)
11567 indicatePessimisticFixpoint();
11572 auto AssumedBefore = getAssumed();
11574 unsigned ArgNo = getCalleeArgNo();
11576 bool UsedAssumedInformation =
false;
11578 auto CallSitePred = [&](AbstractCallSite ACS) {
11580 if (CSArgIRP.getPositionKind() == IRP_INVALID)
11583 if (!
A.getAssumedSimplifiedValues(CSArgIRP,
this, Values,
11585 UsedAssumedInformation))
11588 return isValidState();
11591 if (!
A.checkForAllCallSites(CallSitePred, *
this,
11593 UsedAssumedInformation))
11594 return indicatePessimisticFixpoint();
11596 Function *Fn = getAssociatedFunction();
11597 bool AnyNonLocal =
false;
11598 for (
auto &It : Values) {
11600 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11605 return indicatePessimisticFixpoint();
11609 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11615 AnyNonLocal =
true;
11617 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11619 giveUpOnIntraprocedural(
A);
11621 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11622 : ChangeStatus::CHANGED;
11626 void trackStatistics()
const override {
11631struct AAPotentialValuesReturned :
public AAPotentialValuesFloating {
11632 using Base = AAPotentialValuesFloating;
11633 AAPotentialValuesReturned(
const IRPosition &IRP, Attributor &
A)
11639 if (!
F ||
F->isDeclaration() ||
F->getReturnType()->isVoidTy()) {
11640 indicatePessimisticFixpoint();
11644 for (Argument &Arg :
F->args())
11647 ReturnedArg = &Arg;
11650 if (!
A.isFunctionIPOAmendable(*
F) ||
11651 A.hasSimplificationCallback(getIRPosition())) {
11653 indicatePessimisticFixpoint();
11655 indicateOptimisticFixpoint();
11661 auto AssumedBefore = getAssumed();
11662 bool UsedAssumedInformation =
false;
11665 Function *AnchorScope = getAnchorScope();
11671 UsedAssumedInformation,
11677 bool AllInterAreIntra =
false;
11680 llvm::all_of(Values, [&](
const AA::ValueAndContext &VAC) {
11684 for (
const AA::ValueAndContext &VAC : Values) {
11685 addValue(
A, getState(), *VAC.
getValue(),
11689 if (AllInterAreIntra)
11696 HandleReturnedValue(*ReturnedArg,
nullptr,
true);
11699 bool AddValues =
true;
11702 addValue(
A, getState(), *RetI.getOperand(0), &RetI,
AA::AnyScope,
11706 return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);
11709 if (!
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11710 UsedAssumedInformation,
11712 return indicatePessimisticFixpoint();
11715 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11716 : ChangeStatus::CHANGED;
11721 return ChangeStatus::UNCHANGED;
11723 if (!getAssumedSimplifiedValues(
A, Values, AA::ValueScope::Intraprocedural,
11725 return ChangeStatus::UNCHANGED;
11726 Value *NewVal = getSingleValue(
A, *
this, getIRPosition(), Values);
11728 return ChangeStatus::UNCHANGED;
11733 "Number of function with unique return");
11736 {Attribute::get(Arg->
getContext(), Attribute::Returned)});
11741 Value *RetOp = RetI.getOperand(0);
11745 if (
A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))
11746 Changed = ChangeStatus::CHANGED;
11749 bool UsedAssumedInformation =
false;
11750 (void)
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11751 UsedAssumedInformation,
11757 return AAPotentialValues::indicatePessimisticFixpoint();
11761 void trackStatistics()
const override{
11768struct AAPotentialValuesFunction : AAPotentialValuesImpl {
11769 AAPotentialValuesFunction(
const IRPosition &IRP, Attributor &
A)
11770 : AAPotentialValuesImpl(IRP,
A) {}
11779 void trackStatistics()
const override {
11784struct AAPotentialValuesCallSite : AAPotentialValuesFunction {
11785 AAPotentialValuesCallSite(
const IRPosition &IRP, Attributor &
A)
11786 : AAPotentialValuesFunction(IRP,
A) {}
11789 void trackStatistics()
const override {
11794struct AAPotentialValuesCallSiteReturned : AAPotentialValuesImpl {
11795 AAPotentialValuesCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
11796 : AAPotentialValuesImpl(IRP,
A) {}
11800 auto AssumedBefore = getAssumed();
11804 return indicatePessimisticFixpoint();
11806 bool UsedAssumedInformation =
false;
11810 UsedAssumedInformation))
11811 return indicatePessimisticFixpoint();
11818 Values, S, UsedAssumedInformation))
11821 for (
auto &It : Values) {
11822 Value *
V = It.getValue();
11823 std::optional<Value *> CallerV =
A.translateArgumentToCallSiteContent(
11824 V, *CB, *
this, UsedAssumedInformation);
11825 if (!CallerV.has_value()) {
11829 V = *CallerV ? *CallerV :
V;
11835 giveUpOnIntraprocedural(
A);
11838 addValue(
A, getState(), *V, CB, S, getAnchorScope());
11843 return indicatePessimisticFixpoint();
11845 return indicatePessimisticFixpoint();
11846 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11847 : ChangeStatus::CHANGED;
11851 return AAPotentialValues::indicatePessimisticFixpoint();
11855 void trackStatistics()
const override {
11860struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
11861 AAPotentialValuesCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
11862 : AAPotentialValuesFloating(IRP,
A) {}
11865 void trackStatistics()
const override {
11873struct AAAssumptionInfoImpl :
public AAAssumptionInfo {
11874 AAAssumptionInfoImpl(
const IRPosition &IRP, Attributor &
A,
11875 const DenseSet<StringRef> &Known)
11876 : AAAssumptionInfo(IRP,
A, Known) {}
11881 if (getKnown().isUniversal())
11882 return ChangeStatus::UNCHANGED;
11884 const IRPosition &IRP = getIRPosition();
11886 getAssumed().getSet().
end());
11888 return A.manifestAttrs(IRP,
11895 bool hasAssumption(
const StringRef Assumption)
const override {
11896 return isValidState() && setContains(Assumption);
11900 const std::string getAsStr(Attributor *
A)
const override {
11901 const SetContents &Known = getKnown();
11902 const SetContents &Assumed = getAssumed();
11906 const std::string KnownStr =
llvm::join(Set,
",");
11908 std::string AssumedStr =
"Universal";
11909 if (!Assumed.isUniversal()) {
11910 Set.assign(Assumed.getSet().begin(), Assumed.getSet().end());
11913 return "Known [" + KnownStr +
"]," +
" Assumed [" + AssumedStr +
"]";
11928struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {
11929 AAAssumptionInfoFunction(
const IRPosition &IRP, Attributor &
A)
11930 : AAAssumptionInfoImpl(IRP,
A,
11937 auto CallSitePred = [&](AbstractCallSite ACS) {
11938 const auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
11940 DepClassTy::REQUIRED);
11944 Changed |= getIntersection(AssumptionAA->getAssumed());
11945 return !getAssumed().empty() || !getKnown().empty();
11948 bool UsedAssumedInformation =
false;
11953 if (!
A.checkForAllCallSites(CallSitePred, *
this,
true,
11954 UsedAssumedInformation))
11955 return indicatePessimisticFixpoint();
11957 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11960 void trackStatistics()
const override {}
11964struct AAAssumptionInfoCallSite final : AAAssumptionInfoImpl {
11966 AAAssumptionInfoCallSite(
const IRPosition &IRP, Attributor &
A)
11967 : AAAssumptionInfoImpl(IRP,
A, getInitialAssumptions(IRP)) {}
11972 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11978 auto *AssumptionAA =
11979 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11981 return indicatePessimisticFixpoint();
11982 bool Changed = getIntersection(AssumptionAA->getAssumed());
11983 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11987 void trackStatistics()
const override {}
11992 DenseSet<StringRef> getInitialAssumptions(
const IRPosition &IRP) {
11999 return Assumptions;
12014struct AAUnderlyingObjectsImpl
12020 const std::string getAsStr(
Attributor *
A)
const override {
12021 if (!isValidState())
12022 return "<invalid>";
12025 OS <<
"underlying objects: inter " << InterAssumedUnderlyingObjects.size()
12026 <<
" objects, intra " << IntraAssumedUnderlyingObjects.size()
12028 if (!InterAssumedUnderlyingObjects.empty()) {
12029 OS <<
"inter objects:\n";
12030 for (
auto *Obj : InterAssumedUnderlyingObjects)
12031 OS << *Obj <<
'\n';
12033 if (!IntraAssumedUnderlyingObjects.empty()) {
12034 OS <<
"intra objects:\n";
12035 for (
auto *Obj : IntraAssumedUnderlyingObjects)
12036 OS << *
Obj <<
'\n';
12042 void trackStatistics()
const override {}
12046 auto &Ptr = getAssociatedValue();
12048 bool UsedAssumedInformation =
false;
12049 auto DoUpdate = [&](SmallSetVector<Value *, 8> &UnderlyingObjects,
12051 SmallPtrSet<Value *, 8> SeenObjects;
12055 Scope, UsedAssumedInformation))
12056 return UnderlyingObjects.
insert(&Ptr);
12060 for (
unsigned I = 0;
I < Values.
size(); ++
I) {
12061 auto &VAC = Values[
I];
12064 if (!SeenObjects.
insert(UO ? UO : Obj).second)
12066 if (UO && UO != Obj) {
12072 const auto *OtherAA =
A.getAAFor<AAUnderlyingObjects>(
12074 auto Pred = [&](
Value &
V) {
12082 if (!OtherAA || !OtherAA->forallUnderlyingObjects(Pred, Scope))
12084 "The forall call should not return false at this position");
12090 Changed |= handleIndirect(
A, *Obj, UnderlyingObjects, Scope,
12091 UsedAssumedInformation);
12097 for (
unsigned u = 0, e =
PHI->getNumIncomingValues(); u < e; u++) {
12099 handleIndirect(
A, *
PHI->getIncomingValue(u), UnderlyingObjects,
12100 Scope, UsedAssumedInformation);
12114 if (!UsedAssumedInformation)
12115 indicateOptimisticFixpoint();
12116 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12119 bool forallUnderlyingObjects(
12120 function_ref<
bool(
Value &)> Pred,
12122 if (!isValidState())
12123 return Pred(getAssociatedValue());
12126 ? IntraAssumedUnderlyingObjects
12127 : InterAssumedUnderlyingObjects;
12128 for (
Value *Obj : AssumedUnderlyingObjects)
12138 bool handleIndirect(Attributor &
A,
Value &V,
12139 SmallSetVector<Value *, 8> &UnderlyingObjects,
12142 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
12144 auto Pred = [&](
Value &
V) {
12148 if (!AA || !AA->forallUnderlyingObjects(Pred, Scope))
12150 "The forall call should not return false at this position");
12156 SmallSetVector<Value *, 8> IntraAssumedUnderlyingObjects;
12158 SmallSetVector<Value *, 8> InterAssumedUnderlyingObjects;
12161struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl {
12162 AAUnderlyingObjectsFloating(
const IRPosition &IRP, Attributor &
A)
12163 : AAUnderlyingObjectsImpl(IRP,
A) {}
12166struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl {
12167 AAUnderlyingObjectsArgument(
const IRPosition &IRP, Attributor &
A)
12168 : AAUnderlyingObjectsImpl(IRP,
A) {}
12171struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl {
12172 AAUnderlyingObjectsCallSite(
const IRPosition &IRP, Attributor &
A)
12173 : AAUnderlyingObjectsImpl(IRP,
A) {}
12176struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl {
12177 AAUnderlyingObjectsCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12178 : AAUnderlyingObjectsImpl(IRP,
A) {}
12181struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl {
12182 AAUnderlyingObjectsReturned(
const IRPosition &IRP, Attributor &
A)
12183 : AAUnderlyingObjectsImpl(IRP,
A) {}
12186struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl {
12187 AAUnderlyingObjectsCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12188 : AAUnderlyingObjectsImpl(IRP,
A) {}
12191struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {
12192 AAUnderlyingObjectsFunction(
const IRPosition &IRP, Attributor &
A)
12193 : AAUnderlyingObjectsImpl(IRP,
A) {}
12199struct AAGlobalValueInfoFloating :
public AAGlobalValueInfo {
12200 AAGlobalValueInfoFloating(
const IRPosition &IRP, Attributor &
A)
12201 : AAGlobalValueInfo(IRP,
A) {}
12206 bool checkUse(Attributor &
A,
const Use &U,
bool &Follow,
12207 SmallVectorImpl<const Value *> &Worklist) {
12214 LLVM_DEBUG(
dbgs() <<
"[AAGlobalValueInfo] Check use: " << *
U.get() <<
" in "
12215 << *UInst <<
"\n");
12218 int Idx = &
Cmp->getOperandUse(0) == &
U;
12221 return U == &getAnchorValue();
12226 auto CallSitePred = [&](AbstractCallSite ACS) {
12227 Worklist.
push_back(ACS.getInstruction());
12230 bool UsedAssumedInformation =
false;
12232 if (!
A.checkForAllCallSites(CallSitePred, *UInst->
getFunction(),
12234 UsedAssumedInformation))
12252 if (!Fn || !
A.isFunctionIPOAmendable(*Fn))
12261 unsigned NumUsesBefore =
Uses.size();
12263 SmallPtrSet<const Value *, 8> Visited;
12267 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
12275 return checkUse(
A, U, Follow, Worklist);
12277 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
12278 Uses.insert(&OldU);
12282 while (!Worklist.
empty()) {
12284 if (!Visited.
insert(V).second)
12286 if (!
A.checkForAllUses(UsePred, *
this, *V,
12288 DepClassTy::OPTIONAL,
12289 true, EquivalentUseCB)) {
12290 return indicatePessimisticFixpoint();
12294 return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED
12295 : ChangeStatus::CHANGED;
12298 bool isPotentialUse(
const Use &U)
const override {
12299 return !isValidState() ||
Uses.contains(&U);
12304 return ChangeStatus::UNCHANGED;
12308 const std::string getAsStr(Attributor *
A)
const override {
12309 return "[" + std::to_string(
Uses.size()) +
" uses]";
12312 void trackStatistics()
const override {
12318 SmallPtrSet<const Use *, 8>
Uses;
12324struct AAIndirectCallInfoCallSite :
public AAIndirectCallInfo {
12325 AAIndirectCallInfoCallSite(
const IRPosition &IRP, Attributor &
A)
12326 : AAIndirectCallInfo(IRP,
A) {}
12330 auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);
12331 if (!MD && !
A.isClosedWorldModule())
12335 for (
const auto &
Op : MD->operands())
12337 PotentialCallees.insert(Callee);
12338 }
else if (
A.isClosedWorldModule()) {
12340 A.getInfoCache().getIndirectlyCallableFunctions(
A);
12341 PotentialCallees.insert_range(IndirectlyCallableFunctions);
12344 if (PotentialCallees.empty())
12345 indicateOptimisticFixpoint();
12353 SmallSetVector<Function *, 4> AssumedCalleesNow;
12354 bool AllCalleesKnownNow = AllCalleesKnown;
12356 auto CheckPotentialCalleeUse = [&](
Function &PotentialCallee,
12357 bool &UsedAssumedInformation) {
12358 const auto *GIAA =
A.getAAFor<AAGlobalValueInfo>(
12360 if (!GIAA || GIAA->isPotentialUse(CalleeUse))
12362 UsedAssumedInformation = !GIAA->isAtFixpoint();
12366 auto AddPotentialCallees = [&]() {
12367 for (
auto *PotentialCallee : PotentialCallees) {
12368 bool UsedAssumedInformation =
false;
12369 if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))
12370 AssumedCalleesNow.
insert(PotentialCallee);
12376 bool UsedAssumedInformation =
false;
12379 AA::ValueScope::AnyScope,
12380 UsedAssumedInformation)) {
12381 if (PotentialCallees.empty())
12382 return indicatePessimisticFixpoint();
12383 AddPotentialCallees();
12388 auto CheckPotentialCallee = [&](
Function &Fn) {
12389 if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))
12392 auto &CachedResult = FilterResults[&Fn];
12393 if (CachedResult.has_value())
12394 return CachedResult.value();
12396 bool UsedAssumedInformation =
false;
12397 if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {
12398 if (!UsedAssumedInformation)
12399 CachedResult =
false;
12408 for (
int I = NumCBArgs;
I < NumFnArgs; ++
I) {
12409 bool IsKnown =
false;
12412 DepClassTy::OPTIONAL, IsKnown)) {
12414 CachedResult =
false;
12419 CachedResult =
true;
12425 for (
auto &VAC : Values) {
12433 if (CheckPotentialCallee(*VACFn))
12434 AssumedCalleesNow.
insert(VACFn);
12437 if (!PotentialCallees.empty()) {
12438 AddPotentialCallees();
12441 AllCalleesKnownNow =
false;
12444 if (AssumedCalleesNow == AssumedCallees &&
12445 AllCalleesKnown == AllCalleesKnownNow)
12446 return ChangeStatus::UNCHANGED;
12448 std::swap(AssumedCallees, AssumedCalleesNow);
12449 AllCalleesKnown = AllCalleesKnownNow;
12450 return ChangeStatus::CHANGED;
12456 if (!AllCalleesKnown && AssumedCallees.empty())
12457 return ChangeStatus::UNCHANGED;
12460 bool UsedAssumedInformation =
false;
12461 if (
A.isAssumedDead(*CB,
this,
nullptr,
12462 UsedAssumedInformation))
12463 return ChangeStatus::UNCHANGED;
12467 if (
FP->getType()->getPointerAddressSpace())
12468 FP =
new AddrSpaceCastInst(
FP, PointerType::get(
FP->getContext(), 0),
12478 if (AssumedCallees.empty()) {
12479 assert(AllCalleesKnown &&
12480 "Expected all callees to be known if there are none.");
12481 A.changeToUnreachableAfterManifest(CB);
12482 return ChangeStatus::CHANGED;
12486 if (AllCalleesKnown && AssumedCallees.size() == 1) {
12487 auto *NewCallee = AssumedCallees.front();
12490 NumIndirectCallsPromoted++;
12491 return ChangeStatus::CHANGED;
12498 A.deleteAfterManifest(*CB);
12499 return ChangeStatus::CHANGED;
12509 bool SpecializedForAnyCallees =
false;
12510 bool SpecializedForAllCallees = AllCalleesKnown;
12511 ICmpInst *LastCmp =
nullptr;
12514 for (Function *NewCallee : AssumedCallees) {
12515 if (!
A.shouldSpecializeCallSiteForCallee(*
this, *CB, *NewCallee,
12516 AssumedCallees.size())) {
12517 SkippedAssumedCallees.
push_back(NewCallee);
12518 SpecializedForAllCallees =
false;
12521 SpecializedForAnyCallees =
true;
12527 A.registerManifestAddedBasicBlock(*ThenTI->
getParent());
12528 A.registerManifestAddedBasicBlock(*IP->getParent());
12534 A.registerManifestAddedBasicBlock(*ElseBB);
12536 SplitTI->replaceUsesOfWith(CBBB, ElseBB);
12541 CastInst *RetBC =
nullptr;
12542 CallInst *NewCall =
nullptr;
12547 NumIndirectCallsPromoted++;
12555 auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {
12556 if (!AllCalleesKnown)
12557 return ChangeStatus::UNCHANGED;
12558 MDBuilder MDB(IndirectCB.getContext());
12559 MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);
12560 IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);
12561 return ChangeStatus::CHANGED;
12564 if (!SpecializedForAnyCallees)
12565 return AttachCalleeMetadata(*CB);
12568 if (SpecializedForAllCallees) {
12571 new UnreachableInst(IP->getContext(), IP);
12572 IP->eraseFromParent();
12575 CBClone->setName(CB->
getName());
12576 CBClone->insertBefore(*IP->getParent(), IP);
12577 NewCalls.
push_back({CBClone,
nullptr});
12578 AttachCalleeMetadata(*CBClone);
12585 CB->
getParent()->getFirstInsertionPt());
12586 for (
auto &It : NewCalls) {
12587 CallBase *NewCall = It.first;
12588 Instruction *CallRet = It.second ? It.second : It.first;
12600 A.deleteAfterManifest(*CB);
12601 Changed = ChangeStatus::CHANGED;
12607 const std::string getAsStr(Attributor *
A)
const override {
12608 return std::string(AllCalleesKnown ?
"eliminate" :
"specialize") +
12609 " indirect call site with " + std::to_string(AssumedCallees.size()) +
12613 void trackStatistics()
const override {
12614 if (AllCalleesKnown) {
12616 Eliminated, CallSites,
12617 "Number of indirect call sites eliminated via specialization")
12620 "Number of indirect call sites specialized")
12624 bool foreachCallee(function_ref<
bool(Function *)> CB)
const override {
12625 return isValidState() && AllCalleesKnown &&
all_of(AssumedCallees, CB);
12630 DenseMap<Function *, std::optional<bool>> FilterResults;
12634 SmallSetVector<Function *, 4> PotentialCallees;
12638 SmallSetVector<Function *, 4> AssumedCallees;
12642 bool AllCalleesKnown =
true;
12649struct AAInvariantLoadPointerImpl
12650 :
public StateWrapper<BitIntegerState<uint8_t, 15>,
12651 AAInvariantLoadPointer> {
12655 IS_NOALIAS = 1 << 0,
12658 IS_NOEFFECT = 1 << 1,
12660 IS_LOCALLY_INVARIANT = 1 << 2,
12662 IS_LOCALLY_CONSTRAINED = 1 << 3,
12664 IS_BEST_STATE = IS_NOALIAS | IS_NOEFFECT | IS_LOCALLY_INVARIANT |
12665 IS_LOCALLY_CONSTRAINED,
12667 static_assert(getBestState() == IS_BEST_STATE,
"Unexpected best state");
12670 StateWrapper<BitIntegerState<uint8_t, 15>, AAInvariantLoadPointer>;
12674 AAInvariantLoadPointerImpl(
const IRPosition &IRP, Attributor &
A)
12677 bool isKnownInvariant()
const final {
12678 return isKnownLocallyInvariant() && isKnown(IS_LOCALLY_CONSTRAINED);
12681 bool isKnownLocallyInvariant()
const final {
12682 if (isKnown(IS_LOCALLY_INVARIANT))
12684 return isKnown(IS_NOALIAS | IS_NOEFFECT);
12687 bool isAssumedInvariant()
const final {
12688 return isAssumedLocallyInvariant() && isAssumed(IS_LOCALLY_CONSTRAINED);
12691 bool isAssumedLocallyInvariant()
const final {
12692 if (isAssumed(IS_LOCALLY_INVARIANT))
12694 return isAssumed(IS_NOALIAS | IS_NOEFFECT);
12701 if (requiresNoAlias() && !isAssumed(IS_NOALIAS))
12702 return indicatePessimisticFixpoint();
12706 Changed |= updateLocalInvariance(
A);
12712 if (!isKnownInvariant())
12713 return ChangeStatus::UNCHANGED;
12716 const Value *Ptr = &getAssociatedValue();
12717 const auto TagInvariantLoads = [&](
const Use &
U,
bool &) {
12718 if (
U.get() != Ptr)
12726 if (!
A.isRunOn(
I->getFunction()))
12729 if (
I->hasMetadata(LLVMContext::MD_invariant_load))
12733 LI->setMetadata(LLVMContext::MD_invariant_load,
12735 Changed = ChangeStatus::CHANGED;
12740 (void)
A.checkForAllUses(TagInvariantLoads, *
this, *Ptr);
12745 const std::string getAsStr(Attributor *)
const override {
12746 if (isKnownInvariant())
12747 return "load-invariant pointer";
12748 return "non-invariant pointer";
12752 void trackStatistics()
const override {}
12756 bool requiresNoAlias()
const {
12757 switch (getPositionKind()) {
12763 case IRP_CALL_SITE:
12765 case IRP_CALL_SITE_RETURNED: {
12770 case IRP_ARGUMENT: {
12771 const Function *
F = getAssociatedFunction();
12772 assert(
F &&
"no associated function for argument");
12778 bool isExternal()
const {
12779 const Function *
F = getAssociatedFunction();
12783 getPositionKind() != IRP_CALL_SITE_RETURNED;
12787 if (isKnown(IS_NOALIAS) || !isAssumed(IS_NOALIAS))
12788 return ChangeStatus::UNCHANGED;
12791 if (
const auto *ANoAlias =
A.getOrCreateAAFor<AANoAlias>(
12792 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12793 if (ANoAlias->isKnownNoAlias()) {
12794 addKnownBits(IS_NOALIAS);
12795 return ChangeStatus::CHANGED;
12798 if (!ANoAlias->isAssumedNoAlias()) {
12799 removeAssumedBits(IS_NOALIAS);
12800 return ChangeStatus::CHANGED;
12803 return ChangeStatus::UNCHANGED;
12808 if (
const Argument *Arg = getAssociatedArgument()) {
12810 addKnownBits(IS_NOALIAS);
12811 return ChangeStatus::UNCHANGED;
12816 removeAssumedBits(IS_NOALIAS);
12817 return ChangeStatus::CHANGED;
12820 return ChangeStatus::UNCHANGED;
12824 if (isKnown(IS_NOEFFECT) || !isAssumed(IS_NOEFFECT))
12825 return ChangeStatus::UNCHANGED;
12827 if (!getAssociatedFunction())
12828 return indicatePessimisticFixpoint();
12831 return indicatePessimisticFixpoint();
12833 const auto HasNoEffectLoads = [&](
const Use &
U,
bool &) {
12835 return !LI || !LI->mayHaveSideEffects();
12837 if (!
A.checkForAllUses(HasNoEffectLoads, *
this, getAssociatedValue()))
12838 return indicatePessimisticFixpoint();
12840 if (
const auto *AMemoryBehavior =
A.getOrCreateAAFor<AAMemoryBehavior>(
12841 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12844 if (!AMemoryBehavior->isAssumedReadOnly())
12845 return indicatePessimisticFixpoint();
12847 if (AMemoryBehavior->isKnownReadOnly()) {
12848 addKnownBits(IS_NOEFFECT);
12849 return ChangeStatus::UNCHANGED;
12852 return ChangeStatus::UNCHANGED;
12855 if (
const Argument *Arg = getAssociatedArgument()) {
12857 addKnownBits(IS_NOEFFECT);
12858 return ChangeStatus::UNCHANGED;
12863 return indicatePessimisticFixpoint();
12866 return ChangeStatus::UNCHANGED;
12870 if (isKnown(IS_LOCALLY_INVARIANT) || !isAssumed(IS_LOCALLY_INVARIANT))
12871 return ChangeStatus::UNCHANGED;
12874 const auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
12875 getIRPosition(),
this, DepClassTy::REQUIRED);
12877 return ChangeStatus::UNCHANGED;
12879 bool UsedAssumedInformation =
false;
12880 const auto IsLocallyInvariantLoadIfPointer = [&](
const Value &
V) {
12881 if (!
V.getType()->isPointerTy())
12883 const auto *IsInvariantLoadPointer =
12885 DepClassTy::REQUIRED);
12887 if (!IsInvariantLoadPointer)
12890 if (IsInvariantLoadPointer->isKnownLocallyInvariant())
12892 if (!IsInvariantLoadPointer->isAssumedLocallyInvariant())
12895 UsedAssumedInformation =
true;
12898 if (!AUO->forallUnderlyingObjects(IsLocallyInvariantLoadIfPointer))
12899 return indicatePessimisticFixpoint();
12905 if (!IsLocallyInvariantLoadIfPointer(*Arg))
12906 return indicatePessimisticFixpoint();
12911 if (!UsedAssumedInformation) {
12913 addKnownBits(IS_LOCALLY_INVARIANT);
12914 return ChangeStatus::CHANGED;
12917 return ChangeStatus::UNCHANGED;
12921struct AAInvariantLoadPointerFloating final : AAInvariantLoadPointerImpl {
12922 AAInvariantLoadPointerFloating(
const IRPosition &IRP, Attributor &
A)
12923 : AAInvariantLoadPointerImpl(IRP,
A) {}
12926struct AAInvariantLoadPointerReturned final : AAInvariantLoadPointerImpl {
12927 AAInvariantLoadPointerReturned(
const IRPosition &IRP, Attributor &
A)
12928 : AAInvariantLoadPointerImpl(IRP,
A) {}
12931 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12935struct AAInvariantLoadPointerCallSiteReturned final
12936 : AAInvariantLoadPointerImpl {
12937 AAInvariantLoadPointerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12938 : AAInvariantLoadPointerImpl(IRP,
A) {}
12941 const Function *
F = getAssociatedFunction();
12942 assert(
F &&
"no associated function for return from call");
12944 if (!
F->isDeclaration() && !
F->isIntrinsic())
12945 return AAInvariantLoadPointerImpl::initialize(
A);
12950 return AAInvariantLoadPointerImpl::initialize(
A);
12952 if (
F->onlyReadsMemory() &&
F->hasNoSync())
12953 return AAInvariantLoadPointerImpl::initialize(
A);
12957 indicatePessimisticFixpoint();
12961struct AAInvariantLoadPointerArgument final : AAInvariantLoadPointerImpl {
12962 AAInvariantLoadPointerArgument(
const IRPosition &IRP, Attributor &
A)
12963 : AAInvariantLoadPointerImpl(IRP,
A) {}
12966 const Function *
F = getAssociatedFunction();
12967 assert(
F &&
"no associated function for argument");
12970 addKnownBits(IS_LOCALLY_CONSTRAINED);
12974 if (!
F->hasLocalLinkage())
12975 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12979struct AAInvariantLoadPointerCallSiteArgument final
12980 : AAInvariantLoadPointerImpl {
12981 AAInvariantLoadPointerCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12982 : AAInvariantLoadPointerImpl(IRP,
A) {}
12989template <
typename InstType>
12990static bool makeChange(Attributor &
A, InstType *MemInst,
const Use &U,
12991 Value *OriginalValue, PointerType *NewPtrTy,
12992 bool UseOriginalValue) {
12993 if (
U.getOperandNo() != InstType::getPointerOperandIndex())
12996 if (MemInst->isVolatile()) {
12997 auto *
TTI =
A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(
12998 *MemInst->getFunction());
12999 unsigned NewAS = NewPtrTy->getPointerAddressSpace();
13004 if (UseOriginalValue) {
13005 A.changeUseAfterManifest(
const_cast<Use &
>(U), *OriginalValue);
13009 Instruction *CastInst =
new AddrSpaceCastInst(OriginalValue, NewPtrTy);
13011 A.changeUseAfterManifest(
const_cast<Use &
>(U), *CastInst);
13015struct AAAddressSpaceImpl :
public AAAddressSpace {
13016 AAAddressSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13017 : AAAddressSpace(IRP,
A) {}
13020 assert(isValidState() &&
"the AA is invalid");
13021 return AssumedAddressSpace;
13026 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13027 "Associated value is not a pointer");
13029 if (!
A.getInfoCache().getFlatAddressSpace().has_value()) {
13030 indicatePessimisticFixpoint();
13034 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13035 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13036 if (AS != FlatAS) {
13037 [[maybe_unused]]
bool R = takeAddressSpace(AS);
13038 assert(R &&
"The take should happen");
13039 indicateOptimisticFixpoint();
13044 uint32_t OldAddressSpace = AssumedAddressSpace;
13045 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13047 auto CheckAddressSpace = [&](
Value &
Obj) {
13053 unsigned ObjAS =
Obj.getType()->getPointerAddressSpace();
13054 if (ObjAS != FlatAS)
13055 return takeAddressSpace(ObjAS);
13069 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(*F);
13071 if (AssumedAS != ~0U)
13072 return takeAddressSpace(AssumedAS);
13076 return takeAddressSpace(FlatAS);
13079 auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(getIRPosition(),
this,
13080 DepClassTy::REQUIRED);
13081 if (!AUO->forallUnderlyingObjects(CheckAddressSpace))
13082 return indicatePessimisticFixpoint();
13084 return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED
13085 : ChangeStatus::CHANGED;
13092 if (NewAS == InvalidAddressSpace ||
13094 return ChangeStatus::UNCHANGED;
13096 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13098 Value *AssociatedValue = &getAssociatedValue();
13099 Value *OriginalValue = peelAddrspacecast(AssociatedValue, FlatAS);
13102 PointerType::get(getAssociatedType()->
getContext(), NewAS);
13103 bool UseOriginalValue =
13108 auto Pred = [&](
const Use &
U,
bool &) {
13109 if (
U.get() != AssociatedValue)
13120 makeChange(
A, LI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13123 makeChange(
A, SI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13126 makeChange(
A, RMW, U, OriginalValue, NewPtrTy, UseOriginalValue);
13129 makeChange(
A, CmpX, U, OriginalValue, NewPtrTy, UseOriginalValue);
13136 (void)
A.checkForAllUses(Pred, *
this, getAssociatedValue(),
13139 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13143 const std::string getAsStr(Attributor *
A)
const override {
13144 if (!isValidState())
13145 return "addrspace(<invalid>)";
13146 return "addrspace(" +
13147 (AssumedAddressSpace == InvalidAddressSpace
13149 : std::to_string(AssumedAddressSpace)) +
13154 uint32_t AssumedAddressSpace = InvalidAddressSpace;
13156 bool takeAddressSpace(uint32_t AS) {
13157 if (AssumedAddressSpace == InvalidAddressSpace) {
13158 AssumedAddressSpace = AS;
13161 return AssumedAddressSpace == AS;
13164 static Value *peelAddrspacecast(
Value *V,
unsigned FlatAS) {
13166 assert(
I->getSrcAddressSpace() != FlatAS &&
13167 "there should not be flat AS -> non-flat AS");
13168 return I->getPointerOperand();
13171 if (
C->getOpcode() == Instruction::AddrSpaceCast) {
13172 assert(
C->getOperand(0)->getType()->getPointerAddressSpace() !=
13174 "there should not be flat AS -> non-flat AS X");
13175 return C->getOperand(0);
13181struct AAAddressSpaceFloating final : AAAddressSpaceImpl {
13182 AAAddressSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13183 : AAAddressSpaceImpl(IRP,
A) {}
13185 void trackStatistics()
const override {
13190struct AAAddressSpaceReturned final : AAAddressSpaceImpl {
13191 AAAddressSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13192 : AAAddressSpaceImpl(IRP,
A) {}
13198 (void)indicatePessimisticFixpoint();
13201 void trackStatistics()
const override {
13206struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl {
13207 AAAddressSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13208 : AAAddressSpaceImpl(IRP,
A) {}
13210 void trackStatistics()
const override {
13215struct AAAddressSpaceArgument final : AAAddressSpaceImpl {
13216 AAAddressSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13217 : AAAddressSpaceImpl(IRP,
A) {}
13222struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl {
13223 AAAddressSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13224 : AAAddressSpaceImpl(IRP,
A) {}
13230 (void)indicatePessimisticFixpoint();
13233 void trackStatistics()
const override {
13248struct AANoAliasAddrSpaceImpl :
public AANoAliasAddrSpace {
13249 AANoAliasAddrSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13250 : AANoAliasAddrSpace(IRP,
A) {}
13253 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13254 "Associated value is not a pointer");
13258 std::optional<unsigned> FlatAS =
A.getInfoCache().getFlatAddressSpace();
13259 if (!FlatAS.has_value()) {
13260 indicatePessimisticFixpoint();
13266 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13267 if (AS != *FlatAS) {
13269 indicateOptimisticFixpoint();
13274 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13275 uint32_t OldAssumed = getAssumed();
13277 auto CheckAddressSpace = [&](
Value &
Obj) {
13281 unsigned AS =
Obj.getType()->getPointerAddressSpace();
13285 removeAS(
Obj.getType()->getPointerAddressSpace());
13289 const AAUnderlyingObjects *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
13290 getIRPosition(),
this, DepClassTy::REQUIRED);
13292 return indicatePessimisticFixpoint();
13294 return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
13295 : ChangeStatus::CHANGED;
13300 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13302 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13303 if (AS != FlatAS ||
Map.empty())
13304 return ChangeStatus::UNCHANGED;
13306 LLVMContext &Ctx = getAssociatedValue().getContext();
13307 MDNode *NoAliasASNode =
nullptr;
13308 MDBuilder MDB(Ctx);
13310 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13313 unsigned Upper =
I.stop();
13314 unsigned Lower =
I.start();
13315 if (!NoAliasASNode) {
13316 NoAliasASNode = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13319 MDNode *ASRange = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13323 Value *AssociatedValue = &getAssociatedValue();
13326 auto AddNoAliasAttr = [&](
const Use &
U,
bool &) {
13327 if (
U.get() != AssociatedValue)
13330 if (!Inst || Inst->
hasMetadata(LLVMContext::MD_noalias_addrspace))
13337 Inst->
setMetadata(LLVMContext::MD_noalias_addrspace, NoAliasASNode);
13341 (void)
A.checkForAllUses(AddNoAliasAttr, *
this, *AssociatedValue,
13343 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13347 const std::string getAsStr(Attributor *
A)
const override {
13348 if (!isValidState())
13349 return "<invalid>";
13351 raw_string_ostream OS(Str);
13352 OS <<
"CanNotBeAddrSpace(";
13353 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13354 unsigned Upper =
I.stop();
13355 unsigned Lower =
I.start();
13356 OS <<
' ' <<
'[' <<
Upper <<
',' <<
Lower + 1 <<
')';
13363 void removeAS(
unsigned AS) {
13364 RangeMap::iterator
I =
Map.find(AS);
13366 if (
I !=
Map.end()) {
13367 unsigned Upper =
I.stop();
13368 unsigned Lower =
I.start();
13372 if (AS != ~((
unsigned)0) && AS + 1 <=
Upper)
13374 if (AS != 0 &&
Lower <= AS - 1)
13379 void resetASRanges(Attributor &
A) {
13381 Map.insert(0,
A.getInfoCache().getMaxAddrSpace(),
true);
13385struct AANoAliasAddrSpaceFloating final : AANoAliasAddrSpaceImpl {
13386 AANoAliasAddrSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13387 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13389 void trackStatistics()
const override {
13394struct AANoAliasAddrSpaceReturned final : AANoAliasAddrSpaceImpl {
13395 AANoAliasAddrSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13396 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13398 void trackStatistics()
const override {
13403struct AANoAliasAddrSpaceCallSiteReturned final : AANoAliasAddrSpaceImpl {
13404 AANoAliasAddrSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13405 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13407 void trackStatistics()
const override {
13412struct AANoAliasAddrSpaceArgument final : AANoAliasAddrSpaceImpl {
13413 AANoAliasAddrSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13414 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13416 void trackStatistics()
const override {
13421struct AANoAliasAddrSpaceCallSiteArgument final : AANoAliasAddrSpaceImpl {
13422 AANoAliasAddrSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13423 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13425 void trackStatistics()
const override {
13432struct AAAllocationInfoImpl :
public AAAllocationInfo {
13433 AAAllocationInfoImpl(
const IRPosition &IRP, Attributor &
A)
13434 : AAAllocationInfo(IRP,
A) {}
13436 std::optional<TypeSize> getAllocatedSize()
const override {
13437 assert(isValidState() &&
"the AA is invalid");
13438 return AssumedAllocatedSize;
13441 std::optional<TypeSize> findInitialAllocationSize(Instruction *
I,
13442 const DataLayout &
DL) {
13445 switch (
I->getOpcode()) {
13446 case Instruction::Alloca: {
13451 return std::nullopt;
13457 const IRPosition &IRP = getIRPosition();
13462 return indicatePessimisticFixpoint();
13464 bool IsKnownNoCapture;
13466 A,
this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture))
13467 return indicatePessimisticFixpoint();
13469 const AAPointerInfo *PI =
13470 A.getOrCreateAAFor<AAPointerInfo>(IRP, *
this, DepClassTy::REQUIRED);
13473 return indicatePessimisticFixpoint();
13476 return indicatePessimisticFixpoint();
13478 const DataLayout &
DL =
A.getDataLayout();
13479 const auto AllocationSize = findInitialAllocationSize(
I,
DL);
13482 if (!AllocationSize)
13483 return indicatePessimisticFixpoint();
13487 if (*AllocationSize == 0)
13488 return indicatePessimisticFixpoint();
13494 return indicatePessimisticFixpoint();
13496 if (BinSize == 0) {
13497 auto NewAllocationSize = std::make_optional<TypeSize>(0,
false);
13498 if (!changeAllocationSize(NewAllocationSize))
13499 return ChangeStatus::UNCHANGED;
13500 return ChangeStatus::CHANGED;
13504 const auto &It = PI->
begin();
13507 if (It->first.Offset != 0)
13508 return indicatePessimisticFixpoint();
13510 uint64_t SizeOfBin = It->first.Offset + It->first.Size;
13512 if (SizeOfBin >= *AllocationSize)
13513 return indicatePessimisticFixpoint();
13515 auto NewAllocationSize = std::make_optional<TypeSize>(SizeOfBin * 8,
false);
13517 if (!changeAllocationSize(NewAllocationSize))
13518 return ChangeStatus::UNCHANGED;
13520 return ChangeStatus::CHANGED;
13526 assert(isValidState() &&
13527 "Manifest should only be called if the state is valid.");
13531 auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
13533 unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
13535 switch (
I->getOpcode()) {
13537 case Instruction::Alloca: {
13541 Type *CharType = Type::getInt8Ty(
I->getContext());
13543 auto *NumBytesToValue =
13544 ConstantInt::get(
I->getContext(), APInt(32, NumBytesToAllocate));
13547 insertPt = std::next(insertPt);
13548 AllocaInst *NewAllocaInst =
13553 return ChangeStatus::CHANGED;
13561 return ChangeStatus::UNCHANGED;
13565 const std::string getAsStr(Attributor *
A)
const override {
13566 if (!isValidState())
13567 return "allocationinfo(<invalid>)";
13568 return "allocationinfo(" +
13569 (AssumedAllocatedSize == HasNoAllocationSize
13571 : std::to_string(AssumedAllocatedSize->getFixedValue())) +
13576 std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
13580 bool changeAllocationSize(std::optional<TypeSize>
Size) {
13581 if (AssumedAllocatedSize == HasNoAllocationSize ||
13582 AssumedAllocatedSize !=
Size) {
13583 AssumedAllocatedSize =
Size;
13590struct AAAllocationInfoFloating : AAAllocationInfoImpl {
13591 AAAllocationInfoFloating(
const IRPosition &IRP, Attributor &
A)
13592 : AAAllocationInfoImpl(IRP,
A) {}
13594 void trackStatistics()
const override {
13599struct AAAllocationInfoReturned : AAAllocationInfoImpl {
13600 AAAllocationInfoReturned(
const IRPosition &IRP, Attributor &
A)
13601 : AAAllocationInfoImpl(IRP,
A) {}
13607 (void)indicatePessimisticFixpoint();
13610 void trackStatistics()
const override {
13615struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl {
13616 AAAllocationInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13617 : AAAllocationInfoImpl(IRP,
A) {}
13619 void trackStatistics()
const override {
13624struct AAAllocationInfoArgument : AAAllocationInfoImpl {
13625 AAAllocationInfoArgument(
const IRPosition &IRP, Attributor &
A)
13626 : AAAllocationInfoImpl(IRP,
A) {}
13628 void trackStatistics()
const override {
13633struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl {
13634 AAAllocationInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13635 : AAAllocationInfoImpl(IRP,
A) {}
13640 (void)indicatePessimisticFixpoint();
13643 void trackStatistics()
const override {
13692#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \
13693 case IRPosition::PK: \
13694 llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");
13696#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \
13697 case IRPosition::PK: \
13698 AA = new (A.Allocator) CLASS##SUFFIX(IRP, A); \
13702#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13703 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13704 CLASS *AA = nullptr; \
13705 switch (IRP.getPositionKind()) { \
13706 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13707 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13708 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13709 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13710 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13711 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13712 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13713 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13718#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13719 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13720 CLASS *AA = nullptr; \
13721 switch (IRP.getPositionKind()) { \
13722 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13723 SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \
13724 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13725 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13726 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13727 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13728 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13729 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13734#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS) \
13735 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13736 CLASS *AA = nullptr; \
13737 switch (IRP.getPositionKind()) { \
13738 SWITCH_PK_CREATE(CLASS, IRP, POS, SUFFIX) \
13740 llvm_unreachable("Cannot create " #CLASS " for position otherthan " #POS \
13746#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13747 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13748 CLASS *AA = nullptr; \
13749 switch (IRP.getPositionKind()) { \
13750 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13751 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13752 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13753 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13754 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13755 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13756 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13757 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13762#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13763 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13764 CLASS *AA = nullptr; \
13765 switch (IRP.getPositionKind()) { \
13766 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13767 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13768 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13769 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13770 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13771 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13772 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13773 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13778#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13779 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13780 CLASS *AA = nullptr; \
13781 switch (IRP.getPositionKind()) { \
13782 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13783 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13784 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13785 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13786 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13787 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13788 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13789 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13841#undef CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION
13842#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
13843#undef CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION
13844#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
13845#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
13846#undef CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION
13847#undef SWITCH_PK_CREATE
13848#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)
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 if the block is well formed or null if the block is not well forme...
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
const Use & getArgOperandUse(unsigned i) const
Wrappers for getting the Use of a call argument.
LLVM_ABI std::optional< ConstantRange > getRange() const
If this return value has a range attribute, return the value range of the argument.
Value * getArgOperand(unsigned i) const
bool isBundleOperand(unsigned Idx) const
Return true if the operand at index Idx is a bundle operand.
bool isConvergent() const
Determine if the invoke is convergent.
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static CaptureInfo none()
Create CaptureInfo that does not capture any components of the pointer.
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
LLVM_ABI bool isIntegerCast() const
There are several places where we need to know if a cast instruction only deals with integer source a...
Type * getDestTy() const
Return the destination type, as a convenience.
bool isEquality() const
Determine if this is an equals/not equals predicate.
bool isFalseWhenEqual() const
This is just a convenience.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
bool isTrueWhenEqual() const
This is just a convenience.
Predicate getPredicate() const
Return the predicate for this instruction.
Conditional Branch instruction.
Value * getCondition() const
BasicBlock * getSuccessor(unsigned i) const
static LLVM_ABI Constant * getExtractElement(Constant *Vec, Constant *Idx, Type *OnlyIfReducedTy=nullptr)
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
This class represents a range of values.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
LLVM_ABI bool isEmptySet() const
Return true if this set contains no members.
bool isSingleElement() const
Return true if this set contains exactly one member.
static LLVM_ABI ConstantRange makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other)
Produce the smallest range such that all values that may satisfy the given predicate with any value c...
const APInt & getUpper() const
Return the upper value for this range.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
const BasicBlock & getEntryBlock() const
iterator_range< arg_iterator > args()
const Function & getFunction() const
Argument * getArg(unsigned i) const
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
CycleT * getCycle(const BlockT *Block) const
Find the innermost cycle containing a given block.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasLocalLinkage() const
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
Value * CreatePtrAdd(Value *Ptr, Value *Offset, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI bool isLifetimeStartOrEnd() const LLVM_READONLY
Return true if the instruction is a llvm.lifetime.start or llvm.lifetime.end marker.
bool mayReadOrWriteMemory() const
Return true if this instruction may read or write memory.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
bool hasMetadata() const
Return true if this instruction has any metadata attached to it.
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI BasicBlock * getSuccessor(unsigned Idx) const LLVM_READONLY
Return the specified successor. This instruction must be a terminator.
LLVM_ABI bool mayHaveSideEffects() const LLVM_READONLY
Return true if the instruction may have side effects.
bool isTerminator() const
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This is an important class for using LLVM in a threaded context.
ConstantRange getConstantRange(Value *V, Instruction *CxtI, bool UndefAllowed)
Return the ConstantRange constraint that is known to hold for the specified value at the specified in...
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static LLVM_ABI MDNode * getMostGenericRange(MDNode *A, MDNode *B)
static MemoryEffectsBase readOnly()
bool doesNotAccessMemory() const
Whether this function accesses no memory.
static MemoryEffectsBase argMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase inaccessibleMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
bool onlyAccessesInaccessibleMem() const
Whether this function only (at most) accesses inaccessible memory.
ModRefInfo getModRef(Location Loc) const
Get ModRefInfo for the given Location.
bool onlyAccessesArgPointees() const
Whether this function only (at most) accesses argument memory.
bool onlyReadsMemory() const
Whether this function only (at most) reads memory.
static MemoryEffectsBase writeOnly()
static MemoryEffectsBase inaccessibleOrArgMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase none()
bool onlyAccessesInaccessibleOrArgMem() const
Whether this function only (at most) accesses argument and inaccessible memory.
static MemoryEffectsBase unknown()
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static SizeOffsetValue unknown()
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Value * getReturnValue() const
Convenience accessor. Returns null if there is no return value.
LLVM_ABI const SCEV * getSCEVAtScope(const SCEV *S, const Loop *L)
Return a SCEV expression for the specified value at the specified scope in the program.
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI unsigned getSmallConstantMaxTripCount(const Loop *L, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Returns the upper bound of the loop trip count as a normal unsigned value.
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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 *IfTrue, 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 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.
SmallPtrSet< Instruction *, 4 > InstExclusionSetTy
LLVM_ABI bool isGPU(const Module &M)
Return true iff M target a GPU (and we can use GPU AS reasoning).
ValueScope
Flags to distinguish intra-procedural queries from potentially inter-procedural queries.
LLVM_ABI bool isValidInScope(const Value &V, const Function *Scope)
Return true if V is a valid value in Scope, that is a constant or an instruction/argument of Scope.
LLVM_ABI bool isPotentiallyReachable(Attributor &A, const Instruction &FromI, const Instruction &ToI, const AbstractAttribute &QueryingAA, const AA::InstExclusionSetTy *ExclusionSet=nullptr, std::function< bool(const Function &F)> GoBackwardsCB=nullptr)
Return true if ToI is potentially reachable from FromI without running into any instruction in Exclus...
LLVM_ABI bool isNoSyncInst(Attributor &A, const Instruction &I, const AbstractAttribute &QueryingAA)
Return true if I is a nosync instruction.
bool hasAssumedIRAttr(Attributor &A, const AbstractAttribute *QueryingAA, const IRPosition &IRP, DepClassTy DepClass, bool &IsKnown, bool IgnoreSubsumingPositions=false, const AAType **AAPtr=nullptr)
Helper to avoid creating an AA for IR Attributes that might already be set.
LLVM_ABI bool getPotentiallyLoadedValues(Attributor &A, LoadInst &LI, SmallSetVector< Value *, 4 > &PotentialValues, SmallSetVector< Instruction *, 4 > &PotentialValueOrigins, const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, bool OnlyExact=false)
Collect all potential values LI could read into PotentialValues.
LLVM_ABI Value * getWithType(Value &V, Type &Ty)
Try to convert V to type Ty without introducing new instructions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
@ Unsupported
This operation is completely unsupported on the target.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
@ CE
Windows NT (Windows on ARM)
@ Valid
The data is already valid.
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
unsigned combineHashValue(unsigned a, unsigned b)
Simplistic combination of 32-bit hash values into 32-bit hash values.
ElementType
The element type of an SRV or UAV resource.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
@ User
could "use" a pointer
NodeAddr< UseNode * > Use
Context & getContext() const
friend class Instruction
Iterator for Instructions in a `BasicBlock.
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
bool operator<(int64_t V1, const APSInt &V2)
FunctionAddr VTableAddr Value
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt gcd(const DynamicAPInt &A, const DynamicAPInt &B)
LLVM_ABI KnownFPClass computeKnownFPClass(const Value *V, const APInt &DemandedElts, FPClassTest InterestedClasses, const SimplifyQuery &SQ, unsigned Depth=0)
Determine which floating-point classes are valid for V, and return them in KnownFPClass bit sets.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI bool isLegalToPromote(const CallBase &CB, Function *Callee, const char **FailureReason=nullptr)
Return true if the given indirect call site can be made to call Callee.
LLVM_ABI Constant * getInitialValueOfAllocation(const Value *V, const TargetLibraryInfo *TLI, Type *Ty)
If this is a call to an allocation function that initializes memory to a fixed value,...
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
@ Undef
Value of the register doesn't matter.
auto pred_end(const MachineBasicBlock *BB)
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
auto successors(const MachineBasicBlock *BB)
LLVM_ABI bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI)
Return true if this is a call to an allocation function that does not have side effects that we are r...
APFloat abs(APFloat X)
Returns the absolute value of the argument.
LLVM_ABI raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
LLVM_ABI Value * getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI)
Gets the alignment argument for an aligned_alloc-like function, using either built-in knowledge based...
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
LLVM_ABI Value * simplifyInstructionWithOperands(Instruction *I, ArrayRef< Value * > NewOps, const SimplifyQuery &Q)
Like simplifyInstruction but the operands of I are replaced with NewOps.
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
LLVM_ABI bool isNoAliasCall(const Value *V)
Return true if this pointer is returned by a noalias function.
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
LLVM_ABI bool isSafeToSpeculativelyExecute(const Instruction *I, const Instruction *CtxI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr, bool UseVariableInfo=true, bool IgnoreUBImplyingAttrs=true)
Return true if the instruction does not have any effects besides calculating the result and does not ...
bool isa_and_nonnull(const Y &Val)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI ConstantRange getConstantRangeFromMetadata(const MDNode &RangeMD)
Parse out a conservative ConstantRange from !range metadata.
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
LLVM_ABI Value * simplifyInstruction(Instruction *I, const SimplifyQuery &Q)
See if we can compute a simplified version of this instruction.
auto dyn_cast_or_null(const Y &Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(const CallBase *Call, bool MustPreserveNullness)
{launder,strip}.invariant.group returns pointer that aliases its argument, and it only captures point...
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
PotentialValuesState< std::pair< AA::ValueAndContext, AA::ValueScope > > PotentialLLVMValuesState
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI bool NullPointerIsDefined(const Function *F, unsigned AS=0)
Check whether null pointer dereferencing is considered undefined behavior for a given function or an ...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
LLVM_ABI bool wouldInstructionBeTriviallyDead(const Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction would have no side effects if it was not used.
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI CallBase & promoteCall(CallBase &CB, Function *Callee, CastInst **RetBitCast=nullptr)
Promote the given indirect call site to unconditionally call Callee.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI bool hasAssumption(const Function &F, const KnownAssumptionString &AssumptionStr)
Return true if F has the assumption AssumptionStr attached.
LLVM_ABI RetainedKnowledge getKnowledgeFromUse(const Use *U, ArrayRef< Attribute::AttrKind > AttrKinds)
Return a valid Knowledge associated to the Use U if its Attribute kind is in AttrKinds.
@ Success
The lock was released successfully.
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth=0)
Return true if the given value is known to be non-zero when defined.
AtomicOrdering
Atomic ordering for LLVM's memory model.
PotentialValuesState< APInt > PotentialConstantIntValuesState
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
InterleavedRange< Range > interleaved_array(const Range &R, StringRef Separator=", ")
Output range R as an array of interleaved elements.
ChangeStatus clampStateAndIndicateChange< DerefState >(DerefState &S, const DerefState &R)
void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, RemapFlags Flags=RF_None, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr, const MetadataPredicate *IdentityMD=nullptr)
Convert the instruction operands from referencing the current values into those specified by VM.
DWARFExpression::Operation Op
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI Value * getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI)
If this if a call to a free function, return the freed operand.
ChangeStatus clampStateAndIndicateChange(StateType &S, const StateType &R)
Helper function to clamp a state S of type StateType with the information in R and indicate/return if...
constexpr unsigned BitWidth
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
auto pred_begin(const MachineBasicBlock *BB)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
LLVM_ABI std::optional< APInt > getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, function_ref< const Value *(const Value *)> Mapper=[](const Value *V) { return V;})
Return the size of the requested allocation.
LLVM_ABI DenseSet< StringRef > getAssumptions(const Function &F)
Return the set of all assumptions for the function F.
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
LLVM_ABI Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
@ OPTIONAL
The target may be valid if the source is not.
@ NONE
Do not track a dependence between source and target.
@ REQUIRED
The target cannot be valid if the source is not.
LLVM_ABI UseCaptureInfo DetermineUseCaptureKind(const Use &U, const Value *Base)
Determine what kind of capture behaviour U may exhibit.
LLVM_ABI Value * simplifyCmpInst(CmpPredicate Predicate, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a CmpInst, fold the result or return null.
LLVM_ABI bool mayContainIrreducibleControl(const Function &F, const LoopInfo *LI)
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool capturesNothing(CaptureComponents CC)
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
constexpr StringRef AssumptionAttrKey
The key we use for assumption attributes.
constexpr bool isCallableCC(CallingConv::ID CC)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
A type to track pointer/struct usage and accesses for AAPointerInfo.
bool forallInterferingAccesses(AA::RangeTy Range, F CB) const
See AAPointerInfo::forallInterferingAccesses.
AAPointerInfo::const_bin_iterator end() const
ChangeStatus addAccess(Attributor &A, const AAPointerInfo::RangeList &Ranges, Instruction &I, std::optional< Value * > Content, AAPointerInfo::AccessKind Kind, Type *Ty, Instruction *RemoteI=nullptr)
Add a new Access to the state at offset Offset and with size Size.
DenseMap< const Instruction *, SmallVector< unsigned > > RemoteIMap
AAPointerInfo::const_bin_iterator begin() const
AAPointerInfo::OffsetInfo ReturnedOffsets
Flag to determine if the underlying pointer is reaching a return statement in the associated function...
State & operator=(State &&R)
State(State &&SIS)=default
const AAPointerInfo::Access & getAccess(unsigned Index) const
SmallVector< AAPointerInfo::Access > AccessList
bool isAtFixpoint() const override
See AbstractState::isAtFixpoint().
bool forallInterferingAccesses(Instruction &I, F CB, AA::RangeTy &Range) const
See AAPointerInfo::forallInterferingAccesses.
static State getWorstState(const State &SIS)
Return the worst possible representable state.
int64_t numOffsetBins() const
AAPointerInfo::OffsetBinsTy OffsetBins
ChangeStatus indicateOptimisticFixpoint() override
See AbstractState::indicateOptimisticFixpoint().
State & operator=(const State &R)
ChangeStatus indicatePessimisticFixpoint() override
See AbstractState::indicatePessimisticFixpoint().
const State & getAssumed() const
static State getBestState(const State &SIS)
Return the best possible representable state.
bool isValidState() const override
See AbstractState::isValidState().
----------------—AAIntraFnReachability Attribute-----------------------—
ReachabilityQueryInfo(const ReachabilityQueryInfo &RQI)
unsigned Hash
Precomputed hash for this RQI.
const Instruction * From
Start here,.
Reachable Result
and remember if it worked:
ReachabilityQueryInfo(const Instruction *From, const ToTy *To)
ReachabilityQueryInfo(Attributor &A, const Instruction &From, const ToTy &To, const AA::InstExclusionSetTy *ES, bool MakeUnique)
Constructor replacement to ensure unique and stable sets are used for the cache.
const ToTy * To
reach this place,
const AA::InstExclusionSetTy * ExclusionSet
without going through any of these instructions,
unsigned computeHashValue() const
An abstract interface for address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all align attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Align getKnownAlign() const
Return known alignment.
static LLVM_ABI const char ID
An abstract attribute for getting assumption information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract state for querying live call edges.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for specializing "dynamic" components of denormal_fpenv to a known denormal mod...
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all dereferenceable attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for llvm::GlobalValue information interference.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for indirect call information interference.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface to track if a value leaves it's defining function instance.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for computing reachability between functions.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool canReach(Attributor &A, const Function &Fn) const
If the function represented by this possition can reach Fn.
virtual bool instructionCanReach(Attributor &A, const Instruction &Inst, const Function &Fn, const AA::InstExclusionSetTy *ExclusionSet=nullptr) const =0
Can Inst reach Fn.
An abstract interface to determine reachability of point A to B.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for identifying pointers from which loads can be marked invariant.
static LLVM_ABI const char ID
Unique ID (due to the unique address).
An abstract interface for liveness abstract attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for memory access kind related attributes (readnone/readonly/writeonly).
bool isAssumedReadOnly() const
Return true if we assume that the underlying value is not accessed (=written) in its respective scope...
bool isKnownReadNone() const
Return true if we know that the underlying value is not read or accessed in its respective scope.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool isAssumedReadNone() const
Return true if we assume that the underlying value is not read or accessed in its respective scope.
An abstract interface for all memory location attributes (readnone/argmemonly/inaccessiblememonly/ina...
static LLVM_ABI std::string getMemoryLocationsAsStr(MemoryLocationsKind MLK)
Return the locations encoded by MLK as a readable string.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
StateType::base_t MemoryLocationsKind
An abstract interface for all nonnull attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for potential address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all noalias attributes.
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all nocapture attributes.
@ NO_CAPTURE_MAYBE_RETURNED
If we do not capture the value in memory or through integers we can only communicate it back as a der...
@ NO_CAPTURE
If we do not capture the value in memory, through integers, or as a derived pointer we know it is not...
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool isAssumedNoCaptureMaybeReturned() const
Return true if we assume that the underlying value is not captured in its respective scope but we all...
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI void determineFunctionCaptureCapabilities(const IRPosition &IRP, const Function &F, BitIntegerState &State)
Update State according to the capture capabilities of F for position IRP.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for nofree.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for norecurse.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for noreturn.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isAlignedBarrier(const CallBase &CB, bool ExecutedAligned)
Helper function to determine if CB is an aligned (GPU) barrier.
static LLVM_ABI bool isNonRelaxedAtomic(const Instruction *I)
Helper function used to determine whether an instruction is non-relaxed atomic.
static LLVM_ABI bool isNoSyncIntrinsic(const Instruction *I)
Helper function specific for intrinsics which are potentially volatile.
An abstract interface for all noundef attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for determining the necessity of the convergent attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all nonnull attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See AbstractAttribute::isImpliedByIR(...).
A helper containing a list of offsets computed for a Use.
A container for a list of ranges.
static void set_difference(const RangeList &L, const RangeList &R, RangeList &D)
Copy ranges from L that are not in R, into D.
An abstract interface for struct information.
virtual bool reachesReturn() const =0
OffsetBinsTy::const_iterator const_bin_iterator
virtual const_bin_iterator begin() const =0
DenseMap< AA::RangeTy, SmallSet< unsigned, 4 > > OffsetBinsTy
static LLVM_ABI const char ID
Unique ID (due to the unique address)
virtual int64_t numOffsetBins() const =0
An abstract interface for potential values analysis.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI Value * getSingleValue(Attributor &A, const AbstractAttribute &AA, const IRPosition &IRP, SmallVectorImpl< AA::ValueAndContext > &Values)
Extract the single value in Values if any.
An abstract interface for privatizability.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for undefined behavior.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for getting all assumption underlying objects.
virtual bool forallUnderlyingObjects(function_ref< bool(Value &)> Pred, AA::ValueScope Scope=AA::Interprocedural) const =0
Check Pred on all underlying objects in Scope collected so far.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for range value analysis.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for value simplify abstract attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for willreturn.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Helper to represent an access offset and size, with logic to deal with uncertainty and check for over...
static constexpr int64_t Unknown
static RangeTy getUnknown()
const Instruction * getCtxI() const
Base struct for all "concrete attribute" deductions.
void print(raw_ostream &OS) const
Helper functions, for debug purposes only.
virtual StateType & getState()=0
Return the internal abstract state for inspection.
An interface to query the internal state of an abstract attribute.
virtual bool isAtFixpoint() const =0
Return if this abstract state is fixed, thus does not need to be updated if information changes as it...
virtual bool isValidState() const =0
Return if this abstract state is in a valid state.
Helper for AA::PointerInfo::Access DenseMap/Set usage ignoring everythign but the instruction.
static unsigned getHashValue(const Access &A)
AAPointerInfo::Access Access
static Access getTombstoneKey()
DenseMapInfo< Instruction * > Base
static bool isEqual(const Access &LHS, const Access &RHS)
static Access getEmptyKey()
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
std::function< void( const ArgumentReplacementInfo &, Function &, Function::arg_iterator)> CalleeRepairCBTy
Callee repair callback type.
const Argument & getReplacedArg() const
std::function< void(const ArgumentReplacementInfo &, AbstractCallSite, SmallVectorImpl< Value * > &)> ACSRepairCBTy
Abstract call site (ACS) repair callback type.
The fixpoint analysis framework that orchestrates the attribute deduction.
std::function< std::optional< Value * >( const IRPosition &, const AbstractAttribute *, bool &)> SimplifictionCallbackTy
Register CB as a simplification callback.
Specialization of the integer state for a bit-wise encoding.
BitIntegerState & addKnownBits(base_t Bits)
Add the bits in BitsEncoding to the "known bits".
Simple wrapper for a single bit (boolean) state.
static constexpr DenormalFPEnv getDefault()
static Access getTombstoneKey()
static unsigned getHashValue(const Access &A)
static Access getEmptyKey()
AAPointerInfo::Access Access
static bool isEqual(const Access &LHS, const Access &RHS)
static bool isEqual(const AA::RangeTy &A, const AA::RangeTy B)
static AA::RangeTy getTombstoneKey()
static unsigned getHashValue(const AA::RangeTy &Range)
static AA::RangeTy getEmptyKey()
static ReachabilityQueryInfo< ToTy > EmptyKey
static ReachabilityQueryInfo< ToTy > TombstoneKey
static ReachabilityQueryInfo< ToTy > * getEmptyKey()
DenseMapInfo< std::pair< const Instruction *, const ToTy * > > PairDMI
static ReachabilityQueryInfo< ToTy > * getTombstoneKey()
static bool isEqual(const ReachabilityQueryInfo< ToTy > *LHS, const ReachabilityQueryInfo< ToTy > *RHS)
DenseMapInfo< const AA::InstExclusionSetTy * > InstSetDMI
static unsigned getHashValue(const ReachabilityQueryInfo< ToTy > *RQI)
An information struct used to provide DenseMap with the various necessary components for a given valu...
State for dereferenceable attribute.
IncIntegerState DerefBytesState
State representing for dereferenceable bytes.
ChangeStatus manifest(Attributor &A) override
See AbstractAttribute::manifest(...).
Helper to describe and deal with positions in the LLVM-IR.
Function * getAssociatedFunction() const
Return the associated function, if any.
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
static const IRPosition returned(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the returned value of F.
LLVM_ABI Argument * getAssociatedArgument() const
Return the associated argument, if any.
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
int getCalleeArgNo() const
Return the callee argument number of the associated value if it is an argument or call site argument,...
static const IRPosition inst(const Instruction &I, const CallBaseContext *CBContext=nullptr)
Create a position describing the instruction I.
static const IRPosition callsite_argument(const CallBase &CB, unsigned ArgNo)
Create a position describing the argument of CB at position ArgNo.
@ IRP_ARGUMENT
An attribute for a function argument.
@ IRP_RETURNED
An attribute for the function return value.
@ IRP_CALL_SITE
An attribute for a call site (function scope).
@ IRP_CALL_SITE_RETURNED
An attribute for a call site return value.
@ IRP_FUNCTION
An attribute for a function (scope).
@ IRP_CALL_SITE_ARGUMENT
An attribute for a call site argument.
@ IRP_INVALID
An invalid position.
Instruction * getCtxI() const
Return the context instruction, if any.
static const IRPosition argument(const Argument &Arg, const CallBaseContext *CBContext=nullptr)
Create a position describing the argument Arg.
Type * getAssociatedType() const
Return the type this abstract attribute is associated with.
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
const CallBaseContext * getCallBaseContext() const
Get the call base context from the position.
Value & getAssociatedValue() const
Return the value this abstract attribute is associated with.
Value & getAnchorValue() const
Return the value this abstract attribute is anchored with.
int getCallSiteArgNo() const
Return the call site argument number of the associated value if it is an argument or call site argume...
static const IRPosition function_scope(const IRPosition &IRP, const CallBaseContext *CBContext=nullptr)
Create a position with function scope matching the "context" of IRP.
Kind getPositionKind() const
Return the associated position kind.
bool isArgumentPosition() const
Return true if the position is an argument or call site argument.
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
Function * getAnchorScope() const
Return the Function surrounding the anchor value.
ConstantRange getKnown() const
Return the known state encoding.
ConstantRange getAssumed() const
Return the assumed state encoding.
base_t getAssumed() const
Return the assumed state encoding.
static constexpr base_t getWorstState()
Helper that allows to insert a new assumption string in the known assumption set by creating a (stati...
FPClassTest KnownFPClasses
Floating-point classes the value could be one of.
A "must be executed context" for a given program point PP is the set of instructions,...
iterator & end()
Return an universal end iterator.
bool findInContextOf(const Instruction *I, const Instruction *PP)
Helper to look for I in the context of PP.
iterator & begin(const Instruction *PP)
Return an iterator to explore the context around PP.
bool checkForAllContext(const Instruction *PP, function_ref< bool(const Instruction *)> Pred)
}
static unsigned MaxPotentialValues
Helper to tie a abstract state implementation to an abstract attribute.
StateType & getState() override
See AbstractAttribute::getState(...).
bool isPassthrough() const
LLVM_ABI bool unionAssumed(std::optional< Value * > Other)
Merge Other into the currently assumed simplified value.
std::optional< Value * > SimplifiedAssociatedValue
An assumed simplified value.
Type * Ty
The type of the original value.