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();
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();
3354 return !
I.isVolatile();
3356 if (!
A.checkForAllInstructions(CheckForVolatile, *
this,
3357 {Instruction::Load, Instruction::Store,
3358 Instruction::AtomicCmpXchg,
3359 Instruction::AtomicRMW},
3360 UsedAssumedInformation))
3361 return indicatePessimisticFixpoint();
3363 return ChangeStatus::UNCHANGED;
3367 const std::string getAsStr(Attributor *
A)
const override {
3368 return getAssumed() ?
"willreturn" :
"may-noreturn";
3372struct AAWillReturnFunction final : AAWillReturnImpl {
3373 AAWillReturnFunction(
const IRPosition &IRP, Attributor &
A)
3374 : AAWillReturnImpl(IRP,
A) {}
3378 AAWillReturnImpl::initialize(
A);
3381 assert(
F &&
"Did expect an anchor function");
3382 if (
F->isDeclaration() || mayContainUnboundedCycle(*
F,
A))
3383 indicatePessimisticFixpoint();
3391struct AAWillReturnCallSite final
3392 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl> {
3393 AAWillReturnCallSite(
const IRPosition &IRP, Attributor &
A)
3394 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl>(IRP,
A) {}
3398 if (isImpliedByMustprogressAndReadonly(
A,
false))
3399 return ChangeStatus::UNCHANGED;
3401 return AACalleeToCallSite::updateImpl(
A);
3423 const ToTy *
To =
nullptr;
3450 if (!ES || ES->
empty()) {
3451 ExclusionSet = nullptr;
3452 }
else if (MakeUnique) {
3453 ExclusionSet =
A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ES);
3478 if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))
3480 return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);
3484#define DefineKeys(ToTy) \
3486 ReachabilityQueryInfo<ToTy> \
3487 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::EmptyKey = \
3488 ReachabilityQueryInfo<ToTy>( \
3489 DenseMapInfo<const Instruction *>::getEmptyKey(), \
3490 DenseMapInfo<const ToTy *>::getEmptyKey()); \
3492 ReachabilityQueryInfo<ToTy> \
3493 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::TombstoneKey = \
3494 ReachabilityQueryInfo<ToTy>( \
3495 DenseMapInfo<const Instruction *>::getTombstoneKey(), \
3496 DenseMapInfo<const ToTy *>::getTombstoneKey());
3505template <
typename BaseTy,
typename ToTy>
3506struct CachedReachabilityAA :
public BaseTy {
3507 using RQITy = ReachabilityQueryInfo<ToTy>;
3509 CachedReachabilityAA(
const IRPosition &IRP, Attributor &
A) : BaseTy(IRP,
A) {}
3512 bool isQueryAA()
const override {
return true; }
3517 for (
unsigned u = 0,
e = QueryVector.size();
u <
e; ++
u) {
3518 RQITy *RQI = QueryVector[
u];
3519 if (RQI->Result == RQITy::Reachable::No &&
3521 Changed = ChangeStatus::CHANGED;
3527 bool IsTemporaryRQI) = 0;
3529 bool rememberResult(Attributor &
A,
typename RQITy::Reachable
Result,
3530 RQITy &RQI,
bool UsedExclusionSet,
bool IsTemporaryRQI) {
3535 QueryCache.erase(&RQI);
3541 if (
Result == RQITy::Reachable::Yes || !UsedExclusionSet) {
3542 RQITy PlainRQI(RQI.From, RQI.To);
3543 if (!QueryCache.count(&PlainRQI)) {
3544 RQITy *RQIPtr =
new (
A.Allocator) RQITy(RQI.From, RQI.To);
3546 QueryVector.push_back(RQIPtr);
3547 QueryCache.insert(RQIPtr);
3552 if (IsTemporaryRQI &&
Result != RQITy::Reachable::Yes && UsedExclusionSet) {
3553 assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&
3554 "Did not expect empty set!");
3555 RQITy *RQIPtr =
new (
A.Allocator)
3556 RQITy(
A, *RQI.From, *RQI.To, RQI.ExclusionSet,
true);
3557 assert(RQIPtr->Result == RQITy::Reachable::No &&
"Already reachable?");
3559 assert(!QueryCache.count(RQIPtr));
3560 QueryVector.push_back(RQIPtr);
3561 QueryCache.insert(RQIPtr);
3564 if (
Result == RQITy::Reachable::No && IsTemporaryRQI)
3565 A.registerForUpdate(*
this);
3566 return Result == RQITy::Reachable::Yes;
3569 const std::string getAsStr(Attributor *
A)
const override {
3571 return "#queries(" + std::to_string(QueryVector.size()) +
")";
3574 bool checkQueryCache(Attributor &
A, RQITy &StackRQI,
3575 typename RQITy::Reachable &
Result) {
3576 if (!this->getState().isValidState()) {
3577 Result = RQITy::Reachable::Yes;
3583 if (StackRQI.ExclusionSet) {
3584 RQITy PlainRQI(StackRQI.From, StackRQI.To);
3585 auto It = QueryCache.find(&PlainRQI);
3586 if (It != QueryCache.end() && (*It)->Result == RQITy::Reachable::No) {
3587 Result = RQITy::Reachable::No;
3592 auto It = QueryCache.find(&StackRQI);
3593 if (It != QueryCache.end()) {
3600 QueryCache.insert(&StackRQI);
3606 DenseSet<RQITy *> QueryCache;
3609struct AAIntraFnReachabilityFunction final
3610 :
public CachedReachabilityAA<AAIntraFnReachability, Instruction> {
3611 using Base = CachedReachabilityAA<AAIntraFnReachability, Instruction>;
3612 AAIntraFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
3614 DT =
A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(
3618 bool isAssumedReachable(
3619 Attributor &
A,
const Instruction &From,
const Instruction &To,
3621 auto *NonConstThis =
const_cast<AAIntraFnReachabilityFunction *
>(
this);
3625 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
3627 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
3628 return NonConstThis->isReachableImpl(
A, StackRQI,
3630 return Result == RQITy::Reachable::Yes;
3637 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3640 [&](
const auto &DeadEdge) {
3641 return LivenessAA->isEdgeDead(DeadEdge.first,
3645 return LivenessAA->isAssumedDead(BB);
3647 return ChangeStatus::UNCHANGED;
3651 return Base::updateImpl(
A);
3655 bool IsTemporaryRQI)
override {
3657 bool UsedExclusionSet =
false;
3662 while (IP && IP != &To) {
3663 if (ExclusionSet && IP != Origin && ExclusionSet->
count(IP)) {
3664 UsedExclusionSet =
true;
3672 const BasicBlock *FromBB = RQI.From->getParent();
3673 const BasicBlock *ToBB = RQI.To->getParent();
3675 "Not an intra-procedural query!");
3679 if (FromBB == ToBB &&
3680 WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
3681 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3686 if (!WillReachInBlock(ToBB->
front(), *RQI.To, RQI.ExclusionSet))
3687 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3691 SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
3692 if (RQI.ExclusionSet)
3693 for (
auto *
I : *RQI.ExclusionSet)
3694 if (
I->getFunction() == Fn)
3695 ExclusionBlocks.
insert(
I->getParent());
3698 if (ExclusionBlocks.
count(FromBB) &&
3701 return rememberResult(
A, RQITy::Reachable::No, RQI,
true, IsTemporaryRQI);
3704 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3705 if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {
3706 DeadBlocks.insert(ToBB);
3707 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3711 SmallPtrSet<const BasicBlock *, 16> Visited;
3715 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> LocalDeadEdges;
3716 while (!Worklist.
empty()) {
3718 if (!Visited.
insert(BB).second)
3720 for (
const BasicBlock *SuccBB :
successors(BB)) {
3721 if (LivenessAA && LivenessAA->isEdgeDead(BB, SuccBB)) {
3722 LocalDeadEdges.
insert({BB, SuccBB});
3727 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3730 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3733 if (ExclusionBlocks.
count(SuccBB)) {
3734 UsedExclusionSet =
true;
3741 DeadEdges.insert_range(LocalDeadEdges);
3742 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3747 void trackStatistics()
const override {}
3752 DenseSet<const BasicBlock *> DeadBlocks;
3756 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> DeadEdges;
3759 const DominatorTree *DT =
nullptr;
3767 bool IgnoreSubsumingPositions) {
3768 assert(ImpliedAttributeKind == Attribute::NoAlias &&
3769 "Unexpected attribute kind");
3775 IgnoreSubsumingPositions =
true;
3786 if (
A.hasAttr(IRP, {Attribute::ByVal, Attribute::NoAlias},
3787 IgnoreSubsumingPositions, Attribute::NoAlias))
3797 "Noalias is a pointer attribute");
3800 const std::string getAsStr(
Attributor *
A)
const override {
3801 return getAssumed() ?
"noalias" :
"may-alias";
3806struct AANoAliasFloating final : AANoAliasImpl {
3807 AANoAliasFloating(
const IRPosition &IRP, Attributor &
A)
3808 : AANoAliasImpl(IRP,
A) {}
3813 return indicatePessimisticFixpoint();
3817 void trackStatistics()
const override {
3823struct AANoAliasArgument final
3824 : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> {
3825 using Base = AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>;
3826 AANoAliasArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
3839 DepClassTy::OPTIONAL, IsKnownNoSycn))
3840 return Base::updateImpl(
A);
3845 return Base::updateImpl(
A);
3849 bool UsedAssumedInformation =
false;
3850 if (
A.checkForAllCallSites(
3851 [](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *
this,
3852 true, UsedAssumedInformation))
3853 return Base::updateImpl(
A);
3861 return indicatePessimisticFixpoint();
3868struct AANoAliasCallSiteArgument final : AANoAliasImpl {
3869 AANoAliasCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
3870 : AANoAliasImpl(IRP,
A) {}
3874 bool mayAliasWithArgument(Attributor &
A, AAResults *&AAR,
3875 const AAMemoryBehavior &MemBehaviorAA,
3876 const CallBase &CB,
unsigned OtherArgNo) {
3878 if (this->getCalleeArgNo() == (
int)OtherArgNo)
3886 auto *CBArgMemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
3890 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadNone()) {
3891 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3898 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadOnly() &&
3900 A.recordDependence(MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3901 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3907 AAR =
A.getInfoCache().getAnalysisResultForFunction<AAManager>(
3911 bool IsAliasing = !AAR || !AAR->
isNoAlias(&getAssociatedValue(), ArgOp);
3913 "callsite arguments: "
3914 << getAssociatedValue() <<
" " << *ArgOp <<
" => "
3915 << (IsAliasing ?
"" :
"no-") <<
"alias \n");
3920 bool isKnownNoAliasDueToNoAliasPreservation(
3921 Attributor &
A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA) {
3934 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
3950 bool IsKnownNoCapture;
3953 DepClassTy::OPTIONAL, IsKnownNoCapture))
3959 A, *UserI, *getCtxI(), *
this,
nullptr,
3960 [ScopeFn](
const Function &Fn) {
return &Fn != ScopeFn; }))
3975 LLVM_DEBUG(
dbgs() <<
"[AANoAliasCSArg] Unknown user: " << *UserI <<
"\n");
3979 bool IsKnownNoCapture;
3980 const AANoCapture *NoCaptureAA =
nullptr;
3982 A,
this, VIRP, DepClassTy::NONE, IsKnownNoCapture,
false, &NoCaptureAA);
3983 if (!IsAssumedNoCapture &&
3985 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue())) {
3987 dbgs() <<
"[AANoAliasCSArg] " << getAssociatedValue()
3988 <<
" cannot be noalias as it is potentially captured\n");
3993 A.recordDependence(*NoCaptureAA, *
this, DepClassTy::OPTIONAL);
3999 for (
unsigned OtherArgNo = 0; OtherArgNo < CB.
arg_size(); OtherArgNo++)
4000 if (mayAliasWithArgument(
A, AAR, MemBehaviorAA, CB, OtherArgNo))
4010 auto *MemBehaviorAA =
4011 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
4013 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
4014 return ChangeStatus::UNCHANGED;
4017 bool IsKnownNoAlias;
4020 A,
this, VIRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
4022 <<
" is not no-alias at the definition\n");
4023 return indicatePessimisticFixpoint();
4026 AAResults *AAR =
nullptr;
4027 if (MemBehaviorAA &&
4028 isKnownNoAliasDueToNoAliasPreservation(
A, AAR, *MemBehaviorAA)) {
4030 dbgs() <<
"[AANoAlias] No-Alias deduced via no-alias preservation\n");
4031 return ChangeStatus::UNCHANGED;
4034 return indicatePessimisticFixpoint();
4042struct AANoAliasReturned final : AANoAliasImpl {
4043 AANoAliasReturned(
const IRPosition &IRP, Attributor &
A)
4044 : AANoAliasImpl(IRP,
A) {}
4049 auto CheckReturnValue = [&](
Value &RV) ->
bool {
4060 bool IsKnownNoAlias;
4062 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoAlias))
4065 bool IsKnownNoCapture;
4066 const AANoCapture *NoCaptureAA =
nullptr;
4068 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
4070 return IsAssumedNoCapture ||
4074 if (!
A.checkForAllReturnedValues(CheckReturnValue, *
this))
4075 return indicatePessimisticFixpoint();
4077 return ChangeStatus::UNCHANGED;
4085struct AANoAliasCallSiteReturned final
4086 : AACalleeToCallSite<AANoAlias, AANoAliasImpl> {
4087 AANoAliasCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4088 : AACalleeToCallSite<AANoAlias, AANoAliasImpl>(IRP,
A) {}
4098struct AAIsDeadValueImpl :
public AAIsDead {
4099 AAIsDeadValueImpl(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4102 bool isAssumedDead()
const override {
return isAssumed(IS_DEAD); }
4105 bool isKnownDead()
const override {
return isKnown(IS_DEAD); }
4108 bool isAssumedDead(
const BasicBlock *BB)
const override {
return false; }
4111 bool isKnownDead(
const BasicBlock *BB)
const override {
return false; }
4114 bool isAssumedDead(
const Instruction *
I)
const override {
4115 return I == getCtxI() && isAssumedDead();
4119 bool isKnownDead(
const Instruction *
I)
const override {
4120 return isAssumedDead(
I) && isKnownDead();
4124 const std::string getAsStr(Attributor *
A)
const override {
4125 return isAssumedDead() ?
"assumed-dead" :
"assumed-live";
4129 bool areAllUsesAssumedDead(Attributor &
A,
Value &V) {
4131 if (
V.getType()->isVoidTy() ||
V.use_empty())
4137 if (!
A.isRunOn(*
I->getFunction()))
4139 bool UsedAssumedInformation =
false;
4140 std::optional<Constant *>
C =
4141 A.getAssumedConstant(V, *
this, UsedAssumedInformation);
4146 auto UsePred = [&](
const Use &
U,
bool &Follow) {
return false; };
4151 return A.checkForAllUses(UsePred, *
this, V,
false,
4152 DepClassTy::REQUIRED,
4157 bool isAssumedSideEffectFree(Attributor &
A, Instruction *
I) {
4161 if (!
I->isTerminator() && !
I->mayHaveSideEffects())
4170 bool IsKnownNoUnwind;
4172 A,
this, CallIRP, DepClassTy::OPTIONAL, IsKnownNoUnwind))
4180struct AAIsDeadFloating :
public AAIsDeadValueImpl {
4181 AAIsDeadFloating(
const IRPosition &IRP, Attributor &
A)
4182 : AAIsDeadValueImpl(IRP,
A) {}
4186 AAIsDeadValueImpl::initialize(
A);
4189 indicatePessimisticFixpoint();
4194 if (!isAssumedSideEffectFree(
A,
I)) {
4196 indicatePessimisticFixpoint();
4198 removeAssumedBits(HAS_NO_EFFECT);
4202 bool isDeadFence(Attributor &
A, FenceInst &FI) {
4203 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
4205 if (!ExecDomainAA || !ExecDomainAA->isNoOpFence(FI))
4207 A.recordDependence(*ExecDomainAA, *
this, DepClassTy::OPTIONAL);
4211 bool isDeadStore(Attributor &
A, StoreInst &SI,
4212 SmallSetVector<Instruction *, 8> *AssumeOnlyInst =
nullptr) {
4214 if (
SI.isVolatile())
4220 bool UsedAssumedInformation =
false;
4221 if (!AssumeOnlyInst) {
4222 PotentialCopies.clear();
4224 UsedAssumedInformation)) {
4227 <<
"[AAIsDead] Could not determine potential copies of store!\n");
4231 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Store has " << PotentialCopies.size()
4232 <<
" potential copies.\n");
4234 InformationCache &InfoCache =
A.getInfoCache();
4237 UsedAssumedInformation))
4241 auto &UserI = cast<Instruction>(*U.getUser());
4242 if (InfoCache.isOnlyUsedByAssume(UserI)) {
4244 AssumeOnlyInst->insert(&UserI);
4247 return A.isAssumedDead(U,
this,
nullptr, UsedAssumedInformation);
4253 <<
" is assumed live!\n");
4259 const std::string getAsStr(Attributor *
A)
const override {
4263 return "assumed-dead-store";
4266 return "assumed-dead-fence";
4267 return AAIsDeadValueImpl::getAsStr(
A);
4274 if (!isDeadStore(
A, *SI))
4275 return indicatePessimisticFixpoint();
4277 if (!isDeadFence(
A, *FI))
4278 return indicatePessimisticFixpoint();
4280 if (!isAssumedSideEffectFree(
A,
I))
4281 return indicatePessimisticFixpoint();
4282 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4283 return indicatePessimisticFixpoint();
4288 bool isRemovableStore()
const override {
4289 return isAssumed(IS_REMOVABLE) &&
isa<StoreInst>(&getAssociatedValue());
4294 Value &
V = getAssociatedValue();
4301 SmallSetVector<Instruction *, 8> AssumeOnlyInst;
4302 bool IsDead = isDeadStore(
A, *SI, &AssumeOnlyInst);
4305 A.deleteAfterManifest(*
I);
4306 for (
size_t i = 0; i < AssumeOnlyInst.
size(); ++i) {
4308 for (
auto *Usr : AOI->
users())
4310 A.deleteAfterManifest(*AOI);
4316 A.deleteAfterManifest(*FI);
4320 A.deleteAfterManifest(*
I);
4328 void trackStatistics()
const override {
4334 SmallSetVector<Value *, 4> PotentialCopies;
4337struct AAIsDeadArgument :
public AAIsDeadFloating {
4338 AAIsDeadArgument(
const IRPosition &IRP, Attributor &
A)
4339 : AAIsDeadFloating(IRP,
A) {}
4343 Argument &Arg = *getAssociatedArgument();
4344 if (
A.isValidFunctionSignatureRewrite(Arg, {}))
4345 if (
A.registerFunctionSignatureRewrite(
4349 return ChangeStatus::CHANGED;
4351 return ChangeStatus::UNCHANGED;
4358struct AAIsDeadCallSiteArgument :
public AAIsDeadValueImpl {
4359 AAIsDeadCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
4360 : AAIsDeadValueImpl(IRP,
A) {}
4364 AAIsDeadValueImpl::initialize(
A);
4366 indicatePessimisticFixpoint();
4375 Argument *Arg = getAssociatedArgument();
4377 return indicatePessimisticFixpoint();
4379 auto *ArgAA =
A.getAAFor<AAIsDead>(*
this, ArgPos, DepClassTy::REQUIRED);
4381 return indicatePessimisticFixpoint();
4390 "Expected undef values to be filtered out!");
4392 if (
A.changeUseAfterManifest(U, UV))
4393 return ChangeStatus::CHANGED;
4394 return ChangeStatus::UNCHANGED;
4401struct AAIsDeadCallSiteReturned :
public AAIsDeadFloating {
4402 AAIsDeadCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4403 : AAIsDeadFloating(IRP,
A) {}
4406 bool isAssumedDead()
const override {
4407 return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;
4412 AAIsDeadFloating::initialize(
A);
4414 indicatePessimisticFixpoint();
4419 IsAssumedSideEffectFree = isAssumedSideEffectFree(
A, getCtxI());
4425 if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(
A, getCtxI())) {
4426 IsAssumedSideEffectFree =
false;
4427 Changed = ChangeStatus::CHANGED;
4429 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4430 return indicatePessimisticFixpoint();
4435 void trackStatistics()
const override {
4436 if (IsAssumedSideEffectFree)
4443 const std::string getAsStr(Attributor *
A)
const override {
4444 return isAssumedDead()
4446 : (getAssumed() ?
"assumed-dead-users" :
"assumed-live");
4450 bool IsAssumedSideEffectFree =
true;
4453struct AAIsDeadReturned :
public AAIsDeadValueImpl {
4454 AAIsDeadReturned(
const IRPosition &IRP, Attributor &
A)
4455 : AAIsDeadValueImpl(IRP,
A) {}
4460 bool UsedAssumedInformation =
false;
4461 A.checkForAllInstructions([](Instruction &) {
return true; }, *
this,
4462 {Instruction::Ret}, UsedAssumedInformation);
4464 auto PredForCallSite = [&](AbstractCallSite ACS) {
4465 if (ACS.isCallbackCall() || !ACS.getInstruction())
4467 return areAllUsesAssumedDead(
A, *ACS.getInstruction());
4470 if (!
A.checkForAllCallSites(PredForCallSite, *
this,
true,
4471 UsedAssumedInformation))
4472 return indicatePessimisticFixpoint();
4474 return ChangeStatus::UNCHANGED;
4480 bool AnyChange =
false;
4481 UndefValue &UV = *
UndefValue::get(getAssociatedFunction()->getReturnType());
4488 bool UsedAssumedInformation =
false;
4489 A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
4490 UsedAssumedInformation);
4491 return AnyChange ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
4498struct AAIsDeadFunction :
public AAIsDead {
4499 AAIsDeadFunction(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4504 assert(
F &&
"Did expect an anchor function");
4505 if (!isAssumedDeadInternalFunction(
A)) {
4506 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4507 assumeLive(
A,
F->getEntryBlock());
4511 bool isAssumedDeadInternalFunction(Attributor &
A) {
4512 if (!getAnchorScope()->hasLocalLinkage())
4514 bool UsedAssumedInformation =
false;
4515 return A.checkForAllCallSites([](AbstractCallSite) {
return false; }, *
this,
4516 true, UsedAssumedInformation);
4520 const std::string getAsStr(Attributor *
A)
const override {
4521 return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) +
"/" +
4522 std::to_string(getAnchorScope()->
size()) +
"][#TBEP " +
4523 std::to_string(ToBeExploredFrom.size()) +
"][#KDE " +
4524 std::to_string(KnownDeadEnds.size()) +
"]";
4529 assert(getState().isValidState() &&
4530 "Attempted to manifest an invalid state!");
4535 if (AssumedLiveBlocks.empty()) {
4536 A.deleteAfterManifest(
F);
4537 return ChangeStatus::CHANGED;
4543 bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(
F);
4545 KnownDeadEnds.set_union(ToBeExploredFrom);
4546 for (
const Instruction *DeadEndI : KnownDeadEnds) {
4550 bool IsKnownNoReturn;
4558 A.registerInvokeWithDeadSuccessor(
const_cast<InvokeInst &
>(*
II));
4560 A.changeToUnreachableAfterManifest(
4561 const_cast<Instruction *
>(DeadEndI->getNextNode()));
4562 HasChanged = ChangeStatus::CHANGED;
4565 STATS_DECL(AAIsDead, BasicBlock,
"Number of dead basic blocks deleted.");
4566 for (BasicBlock &BB :
F)
4567 if (!AssumedLiveBlocks.count(&BB)) {
4568 A.deleteAfterManifest(BB);
4570 HasChanged = ChangeStatus::CHANGED;
4579 bool isEdgeDead(
const BasicBlock *From,
const BasicBlock *To)
const override {
4582 "Used AAIsDead of the wrong function");
4583 return isValidState() && !AssumedLiveEdges.count(std::make_pair(From, To));
4587 void trackStatistics()
const override {}
4590 bool isAssumedDead()
const override {
return false; }
4593 bool isKnownDead()
const override {
return false; }
4596 bool isAssumedDead(
const BasicBlock *BB)
const override {
4598 "BB must be in the same anchor scope function.");
4602 return !AssumedLiveBlocks.count(BB);
4606 bool isKnownDead(
const BasicBlock *BB)
const override {
4607 return getKnown() && isAssumedDead(BB);
4611 bool isAssumedDead(
const Instruction *
I)
const override {
4612 assert(
I->getParent()->getParent() == getAnchorScope() &&
4613 "Instruction must be in the same anchor scope function.");
4620 if (!AssumedLiveBlocks.count(
I->getParent()))
4626 if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))
4634 bool isKnownDead(
const Instruction *
I)
const override {
4635 return getKnown() && isAssumedDead(
I);
4640 bool assumeLive(Attributor &
A,
const BasicBlock &BB) {
4641 if (!AssumedLiveBlocks.insert(&BB).second)
4648 for (
const Instruction &
I : BB)
4651 if (
F->hasLocalLinkage())
4652 A.markLiveInternalFunction(*
F);
4658 SmallSetVector<const Instruction *, 8> ToBeExploredFrom;
4661 SmallSetVector<const Instruction *, 8> KnownDeadEnds;
4664 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> AssumedLiveEdges;
4667 DenseSet<const BasicBlock *> AssumedLiveBlocks;
4671identifyAliveSuccessors(Attributor &
A,
const CallBase &CB,
4672 AbstractAttribute &AA,
4673 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4676 bool IsKnownNoReturn;
4679 return !IsKnownNoReturn;
4688identifyAliveSuccessors(Attributor &
A,
const InvokeInst &
II,
4689 AbstractAttribute &AA,
4690 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4691 bool UsedAssumedInformation =
4697 if (AAIsDeadFunction::mayCatchAsynchronousExceptions(*
II.getFunction())) {
4698 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4702 bool IsKnownNoUnwind;
4705 UsedAssumedInformation |= !IsKnownNoUnwind;
4707 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4710 return UsedAssumedInformation;
4714identifyAliveSuccessors(Attributor &,
const UncondBrInst &BI,
4715 AbstractAttribute &,
4716 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4722identifyAliveSuccessors(Attributor &
A,
const CondBrInst &BI,
4723 AbstractAttribute &AA,
4724 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4725 bool UsedAssumedInformation =
false;
4726 std::optional<Constant *>
C =
4727 A.getAssumedConstant(*BI.
getCondition(), AA, UsedAssumedInformation);
4737 UsedAssumedInformation =
false;
4739 return UsedAssumedInformation;
4743identifyAliveSuccessors(Attributor &
A,
const SwitchInst &SI,
4744 AbstractAttribute &AA,
4745 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4746 bool UsedAssumedInformation =
false;
4750 UsedAssumedInformation)) {
4752 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4757 if (Values.
empty() ||
4758 (Values.
size() == 1 &&
4761 return UsedAssumedInformation;
4764 Type &Ty = *
SI.getCondition()->getType();
4765 SmallPtrSet<ConstantInt *, 8>
Constants;
4766 auto CheckForConstantInt = [&](
Value *
V) {
4774 if (!
all_of(Values, [&](AA::ValueAndContext &VAC) {
4775 return CheckForConstantInt(VAC.
getValue());
4777 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4779 return UsedAssumedInformation;
4782 unsigned MatchedCases = 0;
4783 for (
const auto &CaseIt :
SI.cases()) {
4784 if (
Constants.count(CaseIt.getCaseValue())) {
4786 AliveSuccessors.
push_back(&CaseIt.getCaseSuccessor()->front());
4793 AliveSuccessors.
push_back(&
SI.getDefaultDest()->front());
4794 return UsedAssumedInformation;
4800 if (AssumedLiveBlocks.empty()) {
4801 if (isAssumedDeadInternalFunction(
A))
4805 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4806 assumeLive(
A,
F->getEntryBlock());
4810 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Live [" << AssumedLiveBlocks.size() <<
"/"
4811 << getAnchorScope()->
size() <<
"] BBs and "
4812 << ToBeExploredFrom.size() <<
" exploration points and "
4813 << KnownDeadEnds.size() <<
" known dead ends\n");
4818 ToBeExploredFrom.end());
4819 decltype(ToBeExploredFrom) NewToBeExploredFrom;
4822 while (!Worklist.
empty()) {
4829 I =
I->getNextNode();
4831 AliveSuccessors.
clear();
4833 bool UsedAssumedInformation =
false;
4834 switch (
I->getOpcode()) {
4838 "Expected non-terminators to be handled already!");
4839 for (
const BasicBlock *SuccBB :
successors(
I->getParent()))
4842 case Instruction::Call:
4844 *
this, AliveSuccessors);
4846 case Instruction::Invoke:
4848 *
this, AliveSuccessors);
4850 case Instruction::UncondBr:
4851 UsedAssumedInformation = identifyAliveSuccessors(
4854 case Instruction::CondBr:
4856 *
this, AliveSuccessors);
4858 case Instruction::Switch:
4860 *
this, AliveSuccessors);
4864 if (UsedAssumedInformation) {
4865 NewToBeExploredFrom.insert(
I);
4866 }
else if (AliveSuccessors.
empty() ||
4867 (
I->isTerminator() &&
4868 AliveSuccessors.
size() <
I->getNumSuccessors())) {
4869 if (KnownDeadEnds.insert(
I))
4874 << AliveSuccessors.
size() <<
" UsedAssumedInformation: "
4875 << UsedAssumedInformation <<
"\n");
4877 for (
const Instruction *AliveSuccessor : AliveSuccessors) {
4878 if (!
I->isTerminator()) {
4879 assert(AliveSuccessors.size() == 1 &&
4880 "Non-terminator expected to have a single successor!");
4884 auto Edge = std::make_pair(
I->getParent(), AliveSuccessor->getParent());
4885 if (AssumedLiveEdges.insert(
Edge).second)
4887 if (assumeLive(
A, *AliveSuccessor->getParent()))
4894 if (NewToBeExploredFrom.size() != ToBeExploredFrom.size() ||
4895 llvm::any_of(NewToBeExploredFrom, [&](
const Instruction *
I) {
4896 return !ToBeExploredFrom.count(I);
4899 ToBeExploredFrom = std::move(NewToBeExploredFrom);
4908 if (ToBeExploredFrom.empty() &&
4909 getAnchorScope()->
size() == AssumedLiveBlocks.size() &&
4910 llvm::all_of(KnownDeadEnds, [](
const Instruction *DeadEndI) {
4911 return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;
4913 return indicatePessimisticFixpoint();
4918struct AAIsDeadCallSite final : AAIsDeadFunction {
4919 AAIsDeadCallSite(
const IRPosition &IRP, Attributor &
A)
4920 : AAIsDeadFunction(IRP,
A) {}
4929 "supported for call sites yet!");
4934 return indicatePessimisticFixpoint();
4938 void trackStatistics()
const override {}
4945struct AADereferenceableImpl : AADereferenceable {
4946 AADereferenceableImpl(
const IRPosition &IRP, Attributor &
A)
4947 : AADereferenceable(IRP,
A) {}
4948 using StateType = DerefState;
4952 Value &
V = *getAssociatedValue().stripPointerCasts();
4954 A.getAttrs(getIRPosition(),
4955 {Attribute::Dereferenceable, Attribute::DereferenceableOrNull},
4958 takeKnownDerefBytesMaximum(Attr.getValueAsInt());
4961 bool IsKnownNonNull;
4963 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNonNull);
4965 bool CanBeNull, CanBeFreed;
4966 takeKnownDerefBytesMaximum(
V.getPointerDereferenceableBytes(
4967 A.getDataLayout(), CanBeNull, CanBeFreed));
4969 if (Instruction *CtxI = getCtxI())
4970 followUsesInMBEC(*
this,
A, getState(), *CtxI);
4975 StateType &getState()
override {
return *
this; }
4976 const StateType &getState()
const override {
return *
this; }
4980 void addAccessedBytesForUse(Attributor &
A,
const Use *U,
const Instruction *
I,
4981 DerefState &State) {
4982 const Value *UseV =
U->get();
4987 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
I->isVolatile())
4992 Loc->Ptr,
Offset,
A.getDataLayout(),
true);
4993 if (
Base &&
Base == &getAssociatedValue())
4994 State.addAccessedBytes(
Offset, Loc->Size.getValue());
4998 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
4999 AADereferenceable::StateType &State) {
5000 bool IsNonNull =
false;
5001 bool TrackUse =
false;
5002 int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
5003 A, *
this, getAssociatedValue(), U,
I, IsNonNull, TrackUse);
5004 LLVM_DEBUG(
dbgs() <<
"[AADereferenceable] Deref bytes: " << DerefBytes
5005 <<
" for instruction " << *
I <<
"\n");
5007 addAccessedBytesForUse(
A, U,
I, State);
5008 State.takeKnownDerefBytesMaximum(DerefBytes);
5015 bool IsKnownNonNull;
5017 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5018 if (IsAssumedNonNull &&
5019 A.hasAttr(getIRPosition(), Attribute::DereferenceableOrNull)) {
5020 A.removeAttrs(getIRPosition(), {Attribute::DereferenceableOrNull});
5021 return ChangeStatus::CHANGED;
5026 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5027 SmallVectorImpl<Attribute> &Attrs)
const override {
5029 bool IsKnownNonNull;
5031 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5032 if (IsAssumedNonNull)
5033 Attrs.emplace_back(Attribute::getWithDereferenceableBytes(
5034 Ctx, getAssumedDereferenceableBytes()));
5036 Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes(
5037 Ctx, getAssumedDereferenceableBytes()));
5041 const std::string getAsStr(Attributor *
A)
const override {
5042 if (!getAssumedDereferenceableBytes())
5043 return "unknown-dereferenceable";
5044 bool IsKnownNonNull;
5045 bool IsAssumedNonNull =
false;
5048 *
A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5049 return std::string(
"dereferenceable") +
5050 (IsAssumedNonNull ?
"" :
"_or_null") +
5051 (isAssumedGlobal() ?
"_globally" :
"") +
"<" +
5052 std::to_string(getKnownDereferenceableBytes()) +
"-" +
5053 std::to_string(getAssumedDereferenceableBytes()) +
">" +
5054 (!
A ?
" [non-null is unknown]" :
"");
5059struct AADereferenceableFloating : AADereferenceableImpl {
5060 AADereferenceableFloating(
const IRPosition &IRP, Attributor &
A)
5061 : AADereferenceableImpl(IRP,
A) {}
5066 bool UsedAssumedInformation =
false;
5068 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5070 Values.
push_back({getAssociatedValue(), getCtxI()});
5073 Stripped = Values.
size() != 1 ||
5074 Values.
front().getValue() != &getAssociatedValue();
5077 const DataLayout &
DL =
A.getDataLayout();
5080 auto VisitValueCB = [&](
const Value &
V) ->
bool {
5082 DL.getIndexSizeInBits(
V.getType()->getPointerAddressSpace());
5083 APInt
Offset(IdxWidth, 0);
5088 const auto *AA =
A.getAAFor<AADereferenceable>(
5090 int64_t DerefBytes = 0;
5091 if (!AA || (!Stripped &&
this == AA)) {
5094 bool CanBeNull, CanBeFreed;
5096 Base->getPointerDereferenceableBytes(
DL, CanBeNull, CanBeFreed);
5097 T.GlobalState.indicatePessimisticFixpoint();
5100 DerefBytes =
DS.DerefBytesState.getAssumed();
5101 T.GlobalState &=
DS.GlobalState;
5107 int64_t OffsetSExt =
Offset.getSExtValue();
5111 T.takeAssumedDerefBytesMinimum(
5112 std::max(int64_t(0), DerefBytes - OffsetSExt));
5117 T.takeKnownDerefBytesMaximum(
5118 std::max(int64_t(0), DerefBytes - OffsetSExt));
5119 T.indicatePessimisticFixpoint();
5120 }
else if (OffsetSExt > 0) {
5126 T.indicatePessimisticFixpoint();
5130 return T.isValidState();
5133 for (
const auto &VAC : Values)
5134 if (!VisitValueCB(*VAC.
getValue()))
5135 return indicatePessimisticFixpoint();
5141 void trackStatistics()
const override {
5147struct AADereferenceableReturned final
5148 : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl> {
5150 AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl>;
5151 AADereferenceableReturned(
const IRPosition &IRP, Attributor &
A)
5155 void trackStatistics()
const override {
5161struct AADereferenceableArgument final
5162 : AAArgumentFromCallSiteArguments<AADereferenceable,
5163 AADereferenceableImpl> {
5165 AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl>;
5166 AADereferenceableArgument(
const IRPosition &IRP, Attributor &
A)
5170 void trackStatistics()
const override {
5176struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {
5177 AADereferenceableCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5178 : AADereferenceableFloating(IRP,
A) {}
5181 void trackStatistics()
const override {
5187struct AADereferenceableCallSiteReturned final
5188 : AACalleeToCallSite<AADereferenceable, AADereferenceableImpl> {
5189 using Base = AACalleeToCallSite<AADereferenceable, AADereferenceableImpl>;
5190 AADereferenceableCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5194 void trackStatistics()
const override {
5204static unsigned getKnownAlignForUse(Attributor &
A, AAAlign &QueryingAA,
5205 Value &AssociatedValue,
const Use *U,
5206 const Instruction *
I,
bool &TrackUse) {
5215 if (
GEP->hasAllConstantIndices())
5220 switch (
II->getIntrinsicID()) {
5221 case Intrinsic::ptrmask: {
5223 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5225 const auto *AlignAA =
A.getAAFor<AAAlign>(
5227 if (ConstVals && ConstVals->isValidState() && ConstVals->isAtFixpoint()) {
5228 unsigned ShiftValue = std::min(ConstVals->getAssumedMinTrailingZeros(),
5230 Align ConstAlign(UINT64_C(1) << ShiftValue);
5231 if (ConstAlign >= AlignAA->getKnownAlign())
5232 return Align(1).value();
5235 return AlignAA->getKnownAlign().
value();
5238 case Intrinsic::amdgcn_make_buffer_rsrc: {
5239 const auto *AlignAA =
A.getAAFor<AAAlign>(
5242 return AlignAA->getKnownAlign().
value();
5260 MA = MaybeAlign(AlignAA->getKnownAlign());
5263 const DataLayout &
DL =
A.getDataLayout();
5264 const Value *UseV =
U->get();
5266 if (
SI->getPointerOperand() == UseV)
5267 MA =
SI->getAlign();
5269 if (LI->getPointerOperand() == UseV)
5270 MA = LI->getAlign();
5272 if (AI->getPointerOperand() == UseV)
5273 MA = AI->getAlign();
5275 if (AI->getPointerOperand() == UseV)
5276 MA = AI->getAlign();
5282 unsigned Alignment = MA->value();
5286 if (
Base == &AssociatedValue) {
5291 uint32_t
gcd = std::gcd(uint32_t(
abs((int32_t)
Offset)), Alignment);
5299struct AAAlignImpl : AAAlign {
5300 AAAlignImpl(
const IRPosition &IRP, Attributor &
A) : AAAlign(IRP,
A) {}
5305 A.getAttrs(getIRPosition(), {Attribute::Alignment},
Attrs);
5307 takeKnownMaximum(Attr.getValueAsInt());
5309 Value &
V = *getAssociatedValue().stripPointerCasts();
5310 takeKnownMaximum(
V.getPointerAlignment(
A.getDataLayout()).value());
5312 if (Instruction *CtxI = getCtxI())
5313 followUsesInMBEC(*
this,
A, getState(), *CtxI);
5321 Value &AssociatedValue = getAssociatedValue();
5323 return ChangeStatus::UNCHANGED;
5325 for (
const Use &U : AssociatedValue.
uses()) {
5327 if (
SI->getPointerOperand() == &AssociatedValue)
5328 if (
SI->getAlign() < getAssumedAlign()) {
5330 "Number of times alignment added to a store");
5331 SI->setAlignment(getAssumedAlign());
5332 InstrChanged = ChangeStatus::CHANGED;
5335 if (LI->getPointerOperand() == &AssociatedValue)
5336 if (LI->getAlign() < getAssumedAlign()) {
5337 LI->setAlignment(getAssumedAlign());
5339 "Number of times alignment added to a load");
5340 InstrChanged = ChangeStatus::CHANGED;
5343 if (RMW->getPointerOperand() == &AssociatedValue) {
5344 if (RMW->getAlign() < getAssumedAlign()) {
5346 "Number of times alignment added to atomicrmw");
5348 RMW->setAlignment(getAssumedAlign());
5349 InstrChanged = ChangeStatus::CHANGED;
5353 if (CAS->getPointerOperand() == &AssociatedValue) {
5354 if (CAS->getAlign() < getAssumedAlign()) {
5356 "Number of times alignment added to cmpxchg");
5357 CAS->setAlignment(getAssumedAlign());
5358 InstrChanged = ChangeStatus::CHANGED;
5366 Align InheritAlign =
5367 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5368 if (InheritAlign >= getAssumedAlign())
5369 return InstrChanged;
5370 return Changed | InstrChanged;
5378 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5379 SmallVectorImpl<Attribute> &Attrs)
const override {
5380 if (getAssumedAlign() > 1)
5382 Attribute::getWithAlignment(Ctx,
Align(getAssumedAlign())));
5386 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5387 AAAlign::StateType &State) {
5388 bool TrackUse =
false;
5390 unsigned int KnownAlign =
5391 getKnownAlignForUse(
A, *
this, getAssociatedValue(), U,
I, TrackUse);
5392 State.takeKnownMaximum(KnownAlign);
5398 const std::string getAsStr(Attributor *
A)
const override {
5399 return "align<" + std::to_string(getKnownAlign().value()) +
"-" +
5400 std::to_string(getAssumedAlign().value()) +
">";
5405struct AAAlignFloating : AAAlignImpl {
5406 AAAlignFloating(
const IRPosition &IRP, Attributor &
A) : AAAlignImpl(IRP,
A) {}
5410 const DataLayout &
DL =
A.getDataLayout();
5413 bool UsedAssumedInformation =
false;
5415 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5417 Values.
push_back({getAssociatedValue(), getCtxI()});
5420 Stripped = Values.
size() != 1 ||
5421 Values.
front().getValue() != &getAssociatedValue();
5425 auto VisitValueCB = [&](
Value &
V) ->
bool {
5429 DepClassTy::REQUIRED);
5430 if (!AA || (!Stripped &&
this == AA)) {
5432 unsigned Alignment = 1;
5445 Alignment =
V.getPointerAlignment(
DL).value();
5448 T.takeKnownMaximum(Alignment);
5449 T.indicatePessimisticFixpoint();
5452 const AAAlign::StateType &
DS = AA->
getState();
5455 return T.isValidState();
5458 for (
const auto &VAC : Values) {
5459 if (!VisitValueCB(*VAC.
getValue()))
5460 return indicatePessimisticFixpoint();
5473struct AAAlignReturned final
5474 : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {
5475 using Base = AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>;
5476 AAAlignReturned(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5483struct AAAlignArgument final
5484 : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {
5485 using Base = AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>;
5486 AAAlignArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5493 if (
A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))
5494 return ChangeStatus::UNCHANGED;
5495 return Base::manifest(
A);
5502struct AAAlignCallSiteArgument final : AAAlignFloating {
5503 AAAlignCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5504 : AAAlignFloating(IRP,
A) {}
5511 if (Argument *Arg = getAssociatedArgument())
5512 if (
A.getInfoCache().isInvolvedInMustTailCall(*Arg))
5513 return ChangeStatus::UNCHANGED;
5515 Align InheritAlign =
5516 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5517 if (InheritAlign >= getAssumedAlign())
5518 Changed = ChangeStatus::UNCHANGED;
5525 if (Argument *Arg = getAssociatedArgument()) {
5528 const auto *ArgAlignAA =
A.getAAFor<AAAlign>(
5531 takeKnownMaximum(ArgAlignAA->getKnownAlign().value());
5541struct AAAlignCallSiteReturned final
5542 : AACalleeToCallSite<AAAlign, AAAlignImpl> {
5543 using Base = AACalleeToCallSite<AAAlign, AAAlignImpl>;
5544 AAAlignCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5550 switch (
II->getIntrinsicID()) {
5551 case Intrinsic::ptrmask: {
5555 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5557 if (ConstVals && ConstVals->isValidState()) {
5558 unsigned ShiftValue =
5559 std::min(ConstVals->getAssumedMinTrailingZeros(),
5560 Value::MaxAlignmentExponent);
5561 Alignment =
Align(UINT64_C(1) << ShiftValue);
5565 const auto *AlignAA =
5567 DepClassTy::REQUIRED);
5569 Alignment = std::max(AlignAA->getAssumedAlign(), Alignment);
5576 std::min(this->getAssumedAlign(), Alignment).value());
5582 case Intrinsic::amdgcn_make_buffer_rsrc: {
5583 const auto *AlignAA =
5585 DepClassTy::REQUIRED);
5588 this->getState(), AlignAA->getAssumedAlign().
value());
5595 return Base::updateImpl(
A);
5604struct AANoReturnImpl :
public AANoReturn {
5605 AANoReturnImpl(
const IRPosition &IRP, Attributor &
A) : AANoReturn(IRP,
A) {}
5611 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
5616 const std::string getAsStr(Attributor *
A)
const override {
5617 return getAssumed() ?
"noreturn" :
"may-return";
5622 auto CheckForNoReturn = [](
Instruction &) {
return false; };
5623 bool UsedAssumedInformation =
false;
5624 if (!
A.checkForAllInstructions(CheckForNoReturn, *
this,
5625 {(unsigned)Instruction::Ret},
5626 UsedAssumedInformation))
5627 return indicatePessimisticFixpoint();
5628 return ChangeStatus::UNCHANGED;
5632struct AANoReturnFunction final : AANoReturnImpl {
5633 AANoReturnFunction(
const IRPosition &IRP, Attributor &
A)
5634 : AANoReturnImpl(IRP,
A) {}
5641struct AANoReturnCallSite final
5642 : AACalleeToCallSite<AANoReturn, AANoReturnImpl> {
5643 AANoReturnCallSite(
const IRPosition &IRP, Attributor &
A)
5644 : AACalleeToCallSite<AANoReturn, AANoReturnImpl>(IRP,
A) {}
5655struct AAInstanceInfoImpl :
public AAInstanceInfo {
5656 AAInstanceInfoImpl(
const IRPosition &IRP, Attributor &
A)
5657 : AAInstanceInfo(IRP,
A) {}
5661 Value &
V = getAssociatedValue();
5663 if (
C->isThreadDependent())
5664 indicatePessimisticFixpoint();
5666 indicateOptimisticFixpoint();
5672 indicateOptimisticFixpoint();
5677 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
5680 indicatePessimisticFixpoint();
5690 Value &
V = getAssociatedValue();
5693 Scope =
I->getFunction();
5696 if (!
Scope->hasLocalLinkage())
5700 return indicateOptimisticFixpoint();
5702 bool IsKnownNoRecurse;
5708 auto UsePred = [&](
const Use &
U,
bool &Follow) {
5723 if (!Callee || !
Callee->hasLocalLinkage())
5727 const auto *ArgInstanceInfoAA =
A.getAAFor<AAInstanceInfo>(
5729 DepClassTy::OPTIONAL);
5730 if (!ArgInstanceInfoAA ||
5731 !ArgInstanceInfoAA->isAssumedUniqueForAnalysis())
5736 A, *CB, *Scope, *
this,
nullptr,
5737 [Scope](
const Function &Fn) {
return &Fn !=
Scope; }))
5744 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
5746 auto *Ptr =
SI->getPointerOperand()->stripPointerCasts();
5754 if (!
A.checkForAllUses(UsePred, *
this, V,
true,
5755 DepClassTy::OPTIONAL,
5756 true, EquivalentUseCB))
5757 return indicatePessimisticFixpoint();
5763 const std::string getAsStr(Attributor *
A)
const override {
5764 return isAssumedUniqueForAnalysis() ?
"<unique [fAa]>" :
"<unknown>";
5768 void trackStatistics()
const override {}
5772struct AAInstanceInfoFloating : AAInstanceInfoImpl {
5773 AAInstanceInfoFloating(
const IRPosition &IRP, Attributor &
A)
5774 : AAInstanceInfoImpl(IRP,
A) {}
5778struct AAInstanceInfoArgument final : AAInstanceInfoFloating {
5779 AAInstanceInfoArgument(
const IRPosition &IRP, Attributor &
A)
5780 : AAInstanceInfoFloating(IRP,
A) {}
5784struct AAInstanceInfoCallSiteArgument final : AAInstanceInfoImpl {
5785 AAInstanceInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5786 : AAInstanceInfoImpl(IRP,
A) {}
5794 Argument *Arg = getAssociatedArgument();
5796 return indicatePessimisticFixpoint();
5799 A.getAAFor<AAInstanceInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
5801 return indicatePessimisticFixpoint();
5807struct AAInstanceInfoReturned final : AAInstanceInfoImpl {
5808 AAInstanceInfoReturned(
const IRPosition &IRP, Attributor &
A)
5809 : AAInstanceInfoImpl(IRP,
A) {
5825struct AAInstanceInfoCallSiteReturned final : AAInstanceInfoFloating {
5826 AAInstanceInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5827 : AAInstanceInfoFloating(IRP,
A) {}
5834 bool IgnoreSubsumingPositions) {
5835 assert(ImpliedAttributeKind == Attribute::Captures &&
5836 "Unexpected attribute kind");
5846 V.getType()->getPointerAddressSpace() == 0)) {
5851 A.getAttrs(IRP, {Attribute::Captures}, Attrs,
5861 {Attribute::Captures, Attribute::ByVal}, Attrs,
5899 bool NoThrow =
F.doesNotThrow();
5900 bool IsVoidReturn =
F.getReturnType()->isVoidTy();
5901 if (
ReadOnly && NoThrow && IsVoidReturn) {
5914 if (NoThrow && IsVoidReturn)
5919 if (!NoThrow || ArgNo < 0 ||
5920 !
F.getAttributes().hasAttrSomewhere(Attribute::Returned))
5923 for (
unsigned U = 0, E =
F.arg_size(); U < E; ++U)
5924 if (
F.hasParamAttribute(U, Attribute::Returned)) {
5925 if (U ==
unsigned(ArgNo))
5952 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5953 SmallVectorImpl<Attribute> &Attrs)
const override {
5954 if (!isAssumedNoCaptureMaybeReturned())
5957 if (isArgumentPosition()) {
5958 if (isAssumedNoCapture())
5959 Attrs.emplace_back(Attribute::get(Ctx, Attribute::Captures));
5961 Attrs.emplace_back(Attribute::get(Ctx,
"no-capture-maybe-returned"));
5966 const std::string getAsStr(Attributor *
A)
const override {
5967 if (isKnownNoCapture())
5968 return "known not-captured";
5969 if (isAssumedNoCapture())
5970 return "assumed not-captured";
5971 if (isKnownNoCaptureMaybeReturned())
5972 return "known not-captured-maybe-returned";
5973 if (isAssumedNoCaptureMaybeReturned())
5974 return "assumed not-captured-maybe-returned";
5975 return "assumed-captured";
5980 bool checkUse(Attributor &
A, AANoCapture::StateType &State,
const Use &U,
5983 LLVM_DEBUG(
dbgs() <<
"[AANoCapture] Check use: " << *
U.get() <<
" in "
5989 return isCapturedIn(State,
true,
true,
5996 return isCapturedIn(State,
true,
true,
6002 return isCapturedIn(State,
false,
false,
6004 return isCapturedIn(State,
true,
true,
6012 return isCapturedIn(State,
true,
true,
6019 bool IsKnownNoCapture;
6020 const AANoCapture *ArgNoCaptureAA =
nullptr;
6022 A,
this, CSArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6024 if (IsAssumedNoCapture)
6025 return isCapturedIn(State,
false,
false,
6029 return isCapturedIn(State,
false,
false,
6034 return isCapturedIn(State,
true,
true,
6041 static bool isCapturedIn(AANoCapture::StateType &State,
bool CapturedInMem,
6042 bool CapturedInInt,
bool CapturedInRet) {
6043 LLVM_DEBUG(
dbgs() <<
" - captures [Mem " << CapturedInMem <<
"|Int "
6044 << CapturedInInt <<
"|Ret " << CapturedInRet <<
"]\n");
6056 const IRPosition &IRP = getIRPosition();
6060 return indicatePessimisticFixpoint();
6067 return indicatePessimisticFixpoint();
6075 T.addKnownBits(NOT_CAPTURED_IN_MEM);
6077 addKnownBits(NOT_CAPTURED_IN_MEM);
6084 auto CheckReturnedArgs = [&](
bool &UsedAssumedInformation) {
6088 UsedAssumedInformation))
6090 bool SeenConstant =
false;
6091 for (
const AA::ValueAndContext &VAC : Values) {
6095 SeenConstant =
true;
6097 VAC.
getValue() == getAssociatedArgument())
6103 bool IsKnownNoUnwind;
6106 bool IsVoidTy =
F->getReturnType()->isVoidTy();
6107 bool UsedAssumedInformation =
false;
6108 if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {
6109 T.addKnownBits(NOT_CAPTURED_IN_RET);
6110 if (
T.isKnown(NOT_CAPTURED_IN_MEM))
6112 if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {
6113 addKnownBits(NOT_CAPTURED_IN_RET);
6114 if (isKnown(NOT_CAPTURED_IN_MEM))
6115 return indicateOptimisticFixpoint();
6120 auto UseCheck = [&](
const Use &
U,
bool &Follow) ->
bool {
6129 return checkUse(
A,
T, U, Follow);
6132 if (!
A.checkForAllUses(UseCheck, *
this, *V))
6133 return indicatePessimisticFixpoint();
6136 auto Assumed = S.getAssumed();
6137 S.intersectAssumedBits(
T.getAssumed());
6138 if (!isAssumedNoCaptureMaybeReturned())
6139 return indicatePessimisticFixpoint();
6145struct AANoCaptureArgument final : AANoCaptureImpl {
6146 AANoCaptureArgument(
const IRPosition &IRP, Attributor &
A)
6147 : AANoCaptureImpl(IRP,
A) {}
6154struct AANoCaptureCallSiteArgument final : AANoCaptureImpl {
6155 AANoCaptureCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6156 : AANoCaptureImpl(IRP,
A) {}
6164 Argument *Arg = getAssociatedArgument();
6166 return indicatePessimisticFixpoint();
6168 bool IsKnownNoCapture;
6169 const AANoCapture *ArgAA =
nullptr;
6171 A,
this, ArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6173 return ChangeStatus::UNCHANGED;
6175 return indicatePessimisticFixpoint();
6180 void trackStatistics()
const override {
6186struct AANoCaptureFloating final : AANoCaptureImpl {
6187 AANoCaptureFloating(
const IRPosition &IRP, Attributor &
A)
6188 : AANoCaptureImpl(IRP,
A) {}
6191 void trackStatistics()
const override {
6197struct AANoCaptureReturned final : AANoCaptureImpl {
6198 AANoCaptureReturned(
const IRPosition &IRP, Attributor &
A)
6199 : AANoCaptureImpl(IRP,
A) {
6214 void trackStatistics()
const override {}
6218struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {
6219 AANoCaptureCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6220 : AANoCaptureImpl(IRP,
A) {}
6226 determineFunctionCaptureCapabilities(getIRPosition(), *
F, *
this);
6230 void trackStatistics()
const override {
6247 dbgs() <<
"[ValueSimplify] is assumed to be "
6250 dbgs() <<
"[ValueSimplify] is assumed to be <none>\n";
6262 if (getAssociatedValue().
getType()->isVoidTy())
6263 indicatePessimisticFixpoint();
6264 if (
A.hasSimplificationCallback(getIRPosition()))
6265 indicatePessimisticFixpoint();
6269 const std::string getAsStr(Attributor *
A)
const override {
6271 dbgs() <<
"SAV: " << (bool)SimplifiedAssociatedValue <<
" ";
6272 if (SimplifiedAssociatedValue && *SimplifiedAssociatedValue)
6273 dbgs() <<
"SAV: " << **SimplifiedAssociatedValue <<
" ";
6275 return isValidState() ? (isAtFixpoint() ?
"simplified" :
"maybe-simple")
6280 void trackStatistics()
const override {}
6283 std::optional<Value *>
6284 getAssumedSimplifiedValue(Attributor &
A)
const override {
6285 return SimplifiedAssociatedValue;
6292 static Value *ensureType(Attributor &
A,
Value &V,
Type &Ty, Instruction *CtxI,
6296 if (CtxI &&
V.getType()->canLosslesslyBitCastTo(&Ty))
6298 : BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6307 static Value *reproduceInst(Attributor &
A,
6308 const AbstractAttribute &QueryingAA,
6309 Instruction &
I,
Type &Ty, Instruction *CtxI,
6311 assert(CtxI &&
"Cannot reproduce an instruction without context!");
6312 if (
Check && (
I.mayReadFromMemory() ||
6317 Value *NewOp = reproduceValue(
A, QueryingAA, *
Op, Ty, CtxI,
Check, VMap);
6319 assert(
Check &&
"Manifest of new value unexpectedly failed!");
6341 static Value *reproduceValue(Attributor &
A,
6342 const AbstractAttribute &QueryingAA,
Value &V,
6343 Type &Ty, Instruction *CtxI,
bool Check,
6345 if (
const auto &NewV = VMap.
lookup(&V))
6347 bool UsedAssumedInformation =
false;
6348 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
6350 if (!SimpleV.has_value())
6354 EffectiveV = *SimpleV;
6359 return ensureType(
A, *EffectiveV, Ty, CtxI,
Check);
6361 if (
Value *NewV = reproduceInst(
A, QueryingAA, *
I, Ty, CtxI,
Check, VMap))
6362 return ensureType(
A, *NewV, Ty, CtxI,
Check);
6368 Value *manifestReplacementValue(Attributor &
A, Instruction *CtxI)
const {
6369 Value *NewV = SimplifiedAssociatedValue
6370 ? *SimplifiedAssociatedValue
6372 if (NewV && NewV != &getAssociatedValue()) {
6376 if (reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6378 return reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6386 bool checkAndUpdate(Attributor &
A,
const AbstractAttribute &QueryingAA,
6387 const IRPosition &IRP,
bool Simplify =
true) {
6388 bool UsedAssumedInformation =
false;
6391 QueryingValueSimplified =
A.getAssumedSimplified(
6393 return unionAssumed(QueryingValueSimplified);
6397 template <
typename AAType>
bool askSimplifiedValueFor(Attributor &
A) {
6398 if (!getAssociatedValue().
getType()->isIntegerTy())
6403 A.getAAFor<AAType>(*
this, getIRPosition(), DepClassTy::NONE);
6407 std::optional<Constant *> COpt = AA->getAssumedConstant(
A);
6410 SimplifiedAssociatedValue = std::nullopt;
6411 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6414 if (
auto *
C = *COpt) {
6415 SimplifiedAssociatedValue =
C;
6416 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6422 bool askSimplifiedValueForOtherAAs(Attributor &
A) {
6423 if (askSimplifiedValueFor<AAValueConstantRange>(
A))
6425 if (askSimplifiedValueFor<AAPotentialConstantValues>(
A))
6433 for (
auto &U : getAssociatedValue().uses()) {
6438 IP =
PHI->getIncomingBlock(U)->getTerminator();
6439 if (
auto *NewV = manifestReplacementValue(
A, IP)) {
6441 <<
" -> " << *NewV <<
" :: " << *
this <<
"\n");
6442 if (
A.changeUseAfterManifest(U, *NewV))
6443 Changed = ChangeStatus::CHANGED;
6447 return Changed | AAValueSimplify::manifest(
A);
6452 SimplifiedAssociatedValue = &getAssociatedValue();
6453 return AAValueSimplify::indicatePessimisticFixpoint();
6457struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
6458 AAValueSimplifyArgument(
const IRPosition &IRP, Attributor &
A)
6459 : AAValueSimplifyImpl(IRP,
A) {}
6462 AAValueSimplifyImpl::initialize(
A);
6463 if (
A.hasAttr(getIRPosition(),
6464 {Attribute::InAlloca, Attribute::Preallocated,
6465 Attribute::StructRet, Attribute::Nest, Attribute::ByVal},
6467 indicatePessimisticFixpoint();
6474 Argument *Arg = getAssociatedArgument();
6480 return indicatePessimisticFixpoint();
6483 auto Before = SimplifiedAssociatedValue;
6485 auto PredForCallSite = [&](AbstractCallSite ACS) {
6486 const IRPosition &ACSArgPos =
6497 bool UsedAssumedInformation =
false;
6498 std::optional<Constant *> SimpleArgOp =
6499 A.getAssumedConstant(ACSArgPos, *
this, UsedAssumedInformation);
6506 return unionAssumed(*SimpleArgOp);
6511 bool UsedAssumedInformation =
false;
6512 if (hasCallBaseContext() &&
6513 getCallBaseContext()->getCalledOperand() == Arg->
getParent())
6515 AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
6517 Success =
A.checkForAllCallSites(PredForCallSite, *
this,
true,
6518 UsedAssumedInformation);
6521 if (!askSimplifiedValueForOtherAAs(
A))
6522 return indicatePessimisticFixpoint();
6525 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6526 : ChangeStatus ::CHANGED;
6530 void trackStatistics()
const override {
6535struct AAValueSimplifyReturned : AAValueSimplifyImpl {
6536 AAValueSimplifyReturned(
const IRPosition &IRP, Attributor &
A)
6537 : AAValueSimplifyImpl(IRP,
A) {}
6540 std::optional<Value *>
6541 getAssumedSimplifiedValue(Attributor &
A)
const override {
6542 if (!isValidState())
6544 return SimplifiedAssociatedValue;
6549 auto Before = SimplifiedAssociatedValue;
6553 return checkAndUpdate(
6558 bool UsedAssumedInformation =
false;
6559 if (!
A.checkForAllInstructions(ReturnInstCB, *
this, {Instruction::Ret},
6560 UsedAssumedInformation))
6561 if (!askSimplifiedValueForOtherAAs(
A))
6562 return indicatePessimisticFixpoint();
6565 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6566 : ChangeStatus ::CHANGED;
6572 return ChangeStatus::UNCHANGED;
6576 void trackStatistics()
const override {
6581struct AAValueSimplifyFloating : AAValueSimplifyImpl {
6582 AAValueSimplifyFloating(
const IRPosition &IRP, Attributor &
A)
6583 : AAValueSimplifyImpl(IRP,
A) {}
6587 AAValueSimplifyImpl::initialize(
A);
6588 Value &
V = getAnchorValue();
6592 indicatePessimisticFixpoint();
6597 auto Before = SimplifiedAssociatedValue;
6598 if (!askSimplifiedValueForOtherAAs(
A))
6599 return indicatePessimisticFixpoint();
6602 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6603 : ChangeStatus ::CHANGED;
6607 void trackStatistics()
const override {
6612struct AAValueSimplifyFunction : AAValueSimplifyImpl {
6613 AAValueSimplifyFunction(
const IRPosition &IRP, Attributor &
A)
6614 : AAValueSimplifyImpl(IRP,
A) {}
6618 SimplifiedAssociatedValue =
nullptr;
6619 indicateOptimisticFixpoint();
6624 "AAValueSimplify(Function|CallSite)::updateImpl will not be called");
6627 void trackStatistics()
const override {
6632struct AAValueSimplifyCallSite : AAValueSimplifyFunction {
6633 AAValueSimplifyCallSite(
const IRPosition &IRP, Attributor &
A)
6634 : AAValueSimplifyFunction(IRP,
A) {}
6636 void trackStatistics()
const override {
6641struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl {
6642 AAValueSimplifyCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6643 : AAValueSimplifyImpl(IRP,
A) {}
6646 AAValueSimplifyImpl::initialize(
A);
6647 Function *Fn = getAssociatedFunction();
6648 assert(Fn &&
"Did expect an associted function");
6649 for (Argument &Arg : Fn->
args()) {
6654 checkAndUpdate(
A, *
this, IRP))
6655 indicateOptimisticFixpoint();
6657 indicatePessimisticFixpoint();
6665 return indicatePessimisticFixpoint();
6668 void trackStatistics()
const override {
6673struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
6674 AAValueSimplifyCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6675 : AAValueSimplifyFloating(IRP,
A) {}
6681 auto *FloatAA =
A.lookupAAFor<AAValueSimplify>(
6683 if (FloatAA && FloatAA->getState().isValidState())
6686 if (
auto *NewV = manifestReplacementValue(
A, getCtxI())) {
6688 ->getArgOperandUse(getCallSiteArgNo());
6689 if (
A.changeUseAfterManifest(U, *NewV))
6690 Changed = ChangeStatus::CHANGED;
6693 return Changed | AAValueSimplify::manifest(
A);
6696 void trackStatistics()
const override {
6704struct AAHeapToStackFunction final :
public AAHeapToStack {
6706 static bool isGlobalizedLocal(
const CallBase &CB) {
6708 return A.
isValid() &&
A.getValueAsString() ==
"__kmpc_alloc_shared";
6711 struct AllocationInfo {
6716 bool IsGlobalizedLocal =
false;
6723 } Status = STACK_DUE_TO_USE;
6727 bool HasPotentiallyFreeingUnknownUses =
false;
6731 bool MoveAllocaIntoEntry =
true;
6734 SmallSetVector<CallBase *, 1> PotentialFreeCalls{};
6737 struct DeallocationInfo {
6745 bool MightFreeUnknownObjects =
false;
6748 SmallSetVector<CallBase *, 1> PotentialAllocationCalls{};
6751 AAHeapToStackFunction(
const IRPosition &IRP, Attributor &
A)
6752 : AAHeapToStack(IRP,
A) {}
6754 ~AAHeapToStackFunction()
override {
6757 for (
auto &It : AllocationInfos)
6758 It.second->~AllocationInfo();
6759 for (
auto &It : DeallocationInfos)
6760 It.second->~DeallocationInfo();
6764 AAHeapToStack::initialize(
A);
6767 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6774 DeallocationInfos[CB] =
new (
A.Allocator) DeallocationInfo{CB, FreedOp};
6781 auto *I8Ty = Type::getInt8Ty(CB->
getParent()->getContext());
6783 AllocationInfo *AI =
new (
A.Allocator) AllocationInfo{CB};
6784 AllocationInfos[CB] = AI;
6785 AI->IsGlobalizedLocal = isGlobalizedLocal(*CB);
6791 bool UsedAssumedInformation =
false;
6792 bool Success =
A.checkForAllCallLikeInstructions(
6793 AllocationIdentifierCB, *
this, UsedAssumedInformation,
6797 assert(
Success &&
"Did not expect the call base visit callback to fail!");
6800 [](
const IRPosition &,
const AbstractAttribute *,
6801 bool &) -> std::optional<Value *> {
return nullptr; };
6802 for (
const auto &It : AllocationInfos)
6805 for (
const auto &It : DeallocationInfos)
6810 const std::string getAsStr(Attributor *
A)
const override {
6811 unsigned NumH2SMallocs = 0, NumInvalidMallocs = 0;
6812 for (
const auto &It : AllocationInfos) {
6813 if (It.second->Status == AllocationInfo::INVALID)
6814 ++NumInvalidMallocs;
6818 return "[H2S] Mallocs Good/Bad: " + std::to_string(NumH2SMallocs) +
"/" +
6819 std::to_string(NumInvalidMallocs);
6823 void trackStatistics()
const override {
6825 MallocCalls, Function,
6826 "Number of malloc/calloc/aligned_alloc calls converted to allocas");
6827 for (
const auto &It : AllocationInfos)
6828 if (It.second->Status != AllocationInfo::INVALID)
6832 bool isAssumedHeapToStack(
const CallBase &CB)
const override {
6834 if (AllocationInfo *AI =
6835 AllocationInfos.lookup(
const_cast<CallBase *
>(&CB)))
6836 return AI->Status != AllocationInfo::INVALID;
6840 bool isAssumedHeapToStackRemovedFree(CallBase &CB)
const override {
6841 if (!isValidState())
6844 for (
const auto &It : AllocationInfos) {
6845 AllocationInfo &AI = *It.second;
6846 if (AI.Status == AllocationInfo::INVALID)
6849 if (AI.PotentialFreeCalls.count(&CB))
6857 assert(getState().isValidState() &&
6858 "Attempted to manifest an invalid state!");
6862 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6864 for (
auto &It : AllocationInfos) {
6865 AllocationInfo &AI = *It.second;
6866 if (AI.Status == AllocationInfo::INVALID)
6869 for (CallBase *FreeCall : AI.PotentialFreeCalls) {
6870 LLVM_DEBUG(
dbgs() <<
"H2S: Removing free call: " << *FreeCall <<
"\n");
6871 A.deleteAfterManifest(*FreeCall);
6872 HasChanged = ChangeStatus::CHANGED;
6875 LLVM_DEBUG(
dbgs() <<
"H2S: Removing malloc-like call: " << *AI.CB
6878 auto Remark = [&](OptimizationRemark
OR) {
6879 if (AI.IsGlobalizedLocal)
6880 return OR <<
"Moving globalized variable to the stack.";
6881 return OR <<
"Moving memory allocation from the heap to the stack.";
6883 if (AI.IsGlobalizedLocal)
6884 A.emitRemark<OptimizationRemark>(AI.CB,
"OMP110",
Remark);
6886 A.emitRemark<OptimizationRemark>(AI.CB,
"HeapToStack",
Remark);
6888 const DataLayout &
DL =
A.getInfoCache().getDL();
6890 std::optional<APInt> SizeAPI =
getSize(
A, *
this, AI);
6892 Size = ConstantInt::get(AI.CB->getContext(), *SizeAPI);
6894 LLVMContext &Ctx = AI.CB->getContext();
6895 ObjectSizeOpts Opts;
6896 ObjectSizeOffsetEvaluator Eval(
DL, TLI, Ctx, Opts);
6897 SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);
6904 ?
F->getEntryBlock().begin()
6905 : AI.CB->getIterator();
6908 if (MaybeAlign RetAlign = AI.CB->getRetAlign())
6909 Alignment = std::max(Alignment, *RetAlign);
6911 std::optional<APInt> AlignmentAPI = getAPInt(
A, *
this, *Align);
6912 assert(AlignmentAPI && AlignmentAPI->getZExtValue() > 0 &&
6913 "Expected an alignment during manifest!");
6915 std::max(Alignment,
assumeAligned(AlignmentAPI->getZExtValue()));
6919 unsigned AS =
DL.getAllocaAddrSpace();
6921 new AllocaInst(Type::getInt8Ty(
F->getContext()), AS,
Size, Alignment,
6922 AI.CB->getName() +
".h2s", IP);
6924 if (Alloca->
getType() != AI.CB->getType())
6925 Alloca = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6926 Alloca, AI.CB->getType(),
"malloc_cast", AI.CB->getIterator());
6928 auto *I8Ty = Type::getInt8Ty(
F->getContext());
6931 "Must be able to materialize initial memory state of allocation");
6936 auto *NBB =
II->getNormalDest();
6938 A.deleteAfterManifest(*AI.CB);
6940 A.deleteAfterManifest(*AI.CB);
6949 Builder.CreateMemSet(Alloca, InitVal,
Size, std::nullopt);
6951 HasChanged = ChangeStatus::CHANGED;
6957 std::optional<APInt> getAPInt(Attributor &
A,
const AbstractAttribute &AA,
6959 bool UsedAssumedInformation =
false;
6960 std::optional<Constant *> SimpleV =
6961 A.getAssumedConstant(V, AA, UsedAssumedInformation);
6963 return APInt(64, 0);
6965 return CI->getValue();
6966 return std::nullopt;
6969 std::optional<APInt>
getSize(Attributor &
A,
const AbstractAttribute &AA,
6970 AllocationInfo &AI) {
6971 auto Mapper = [&](
const Value *
V) ->
const Value * {
6972 bool UsedAssumedInformation =
false;
6973 if (std::optional<Constant *> SimpleV =
6974 A.getAssumedConstant(*V, AA, UsedAssumedInformation))
6981 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6987 MapVector<CallBase *, AllocationInfo *> AllocationInfos;
6991 MapVector<CallBase *, DeallocationInfo *> DeallocationInfos;
6996ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &
A) {
6999 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
7001 const auto *LivenessAA =
7004 MustBeExecutedContextExplorer *Explorer =
7005 A.getInfoCache().getMustBeExecutedContextExplorer();
7007 bool StackIsAccessibleByOtherThreads =
7008 A.getInfoCache().stackIsAccessibleByOtherThreads();
7011 A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(*F);
7012 std::optional<bool> MayContainIrreducibleControl;
7014 if (&
F->getEntryBlock() == &BB)
7016 if (!MayContainIrreducibleControl.has_value())
7018 if (*MayContainIrreducibleControl)
7027 bool HasUpdatedFrees =
false;
7029 auto UpdateFrees = [&]() {
7030 HasUpdatedFrees =
true;
7032 for (
auto &It : DeallocationInfos) {
7033 DeallocationInfo &DI = *It.second;
7036 if (DI.MightFreeUnknownObjects)
7040 bool UsedAssumedInformation =
false;
7041 if (
A.isAssumedDead(*DI.CB,
this, LivenessAA, UsedAssumedInformation,
7048 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown underlying object for free!\n");
7049 DI.MightFreeUnknownObjects =
true;
7062 DI.MightFreeUnknownObjects =
true;
7066 AllocationInfo *AI = AllocationInfos.lookup(ObjCB);
7068 LLVM_DEBUG(
dbgs() <<
"[H2S] Free of a non-allocation object: " << *Obj
7070 DI.MightFreeUnknownObjects =
true;
7074 DI.PotentialAllocationCalls.insert(ObjCB);
7078 auto FreeCheck = [&](AllocationInfo &AI) {
7082 if (!StackIsAccessibleByOtherThreads) {
7087 dbgs() <<
"[H2S] found an escaping use, stack is not accessible by "
7088 "other threads and function is not nosync:\n");
7092 if (!HasUpdatedFrees)
7096 if (AI.PotentialFreeCalls.size() != 1) {
7098 << AI.PotentialFreeCalls.size() <<
"\n");
7101 CallBase *UniqueFree = *AI.PotentialFreeCalls.begin();
7102 DeallocationInfo *DI = DeallocationInfos.lookup(UniqueFree);
7105 dbgs() <<
"[H2S] unique free call was not known as deallocation call "
7106 << *UniqueFree <<
"\n");
7109 if (DI->MightFreeUnknownObjects) {
7111 dbgs() <<
"[H2S] unique free call might free unknown allocations\n");
7114 if (DI->PotentialAllocationCalls.empty())
7116 if (DI->PotentialAllocationCalls.size() > 1) {
7118 << DI->PotentialAllocationCalls.size()
7119 <<
" different allocations\n");
7122 if (*DI->PotentialAllocationCalls.begin() != AI.CB) {
7125 <<
"[H2S] unique free call not known to free this allocation but "
7126 << **DI->PotentialAllocationCalls.begin() <<
"\n");
7131 if (!AI.IsGlobalizedLocal) {
7133 if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
7134 LLVM_DEBUG(
dbgs() <<
"[H2S] unique free call might not be executed "
7135 "with the allocation "
7136 << *UniqueFree <<
"\n");
7143 auto UsesCheck = [&](AllocationInfo &AI) {
7144 bool ValidUsesOnly =
true;
7146 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
7151 if (
SI->getValueOperand() ==
U.get()) {
7153 <<
"[H2S] escaping store to memory: " << *UserI <<
"\n");
7154 ValidUsesOnly =
false;
7163 if (DeallocationInfos.count(CB)) {
7164 AI.PotentialFreeCalls.insert(CB);
7171 bool IsKnownNoCapture;
7180 if (!IsAssumedNoCapture ||
7181 (!AI.IsGlobalizedLocal && !IsAssumedNoFree)) {
7182 AI.HasPotentiallyFreeingUnknownUses |= !IsAssumedNoFree;
7185 auto Remark = [&](OptimizationRemarkMissed ORM) {
7187 <<
"Could not move globalized variable to the stack. "
7188 "Variable is potentially captured in call. Mark "
7189 "parameter as `__attribute__((noescape))` to override.";
7192 if (ValidUsesOnly && AI.IsGlobalizedLocal)
7193 A.emitRemark<OptimizationRemarkMissed>(CB,
"OMP113",
Remark);
7196 ValidUsesOnly =
false;
7209 ValidUsesOnly =
false;
7212 if (!
A.checkForAllUses(Pred, *
this, *AI.CB,
false,
7214 [&](
const Use &OldU,
const Use &NewU) {
7215 auto *SI = dyn_cast<StoreInst>(OldU.getUser());
7216 return !SI || StackIsAccessibleByOtherThreads ||
7217 AA::isAssumedThreadLocalObject(
7218 A, *SI->getPointerOperand(), *this);
7221 return ValidUsesOnly;
7226 for (
auto &It : AllocationInfos) {
7227 AllocationInfo &AI = *It.second;
7228 if (AI.Status == AllocationInfo::INVALID)
7232 std::optional<APInt> APAlign = getAPInt(
A, *
this, *Align);
7236 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown allocation alignment: " << *AI.CB
7238 AI.Status = AllocationInfo::INVALID;
7243 !APAlign->isPowerOf2()) {
7244 LLVM_DEBUG(
dbgs() <<
"[H2S] Invalid allocation alignment: " << APAlign
7246 AI.Status = AllocationInfo::INVALID;
7257 dbgs() <<
"[H2S] Unknown allocation size: " << *AI.CB <<
"\n";
7259 dbgs() <<
"[H2S] Allocation size too large: " << *AI.CB <<
" vs. "
7263 AI.Status = AllocationInfo::INVALID;
7269 switch (AI.Status) {
7270 case AllocationInfo::STACK_DUE_TO_USE:
7273 AI.Status = AllocationInfo::STACK_DUE_TO_FREE;
7275 case AllocationInfo::STACK_DUE_TO_FREE:
7278 AI.Status = AllocationInfo::INVALID;
7281 case AllocationInfo::INVALID:
7288 bool IsGlobalizedLocal = AI.IsGlobalizedLocal;
7289 if (AI.MoveAllocaIntoEntry &&
7290 (!
Size.has_value() ||
7291 (!IsGlobalizedLocal && IsInLoop(*AI.CB->getParent()))))
7292 AI.MoveAllocaIntoEntry =
false;
7301struct AAPrivatizablePtrImpl :
public AAPrivatizablePtr {
7302 AAPrivatizablePtrImpl(
const IRPosition &IRP, Attributor &
A)
7303 : AAPrivatizablePtr(IRP,
A), PrivatizableType(std::nullopt) {}
7306 AAPrivatizablePtr::indicatePessimisticFixpoint();
7307 PrivatizableType =
nullptr;
7308 return ChangeStatus::CHANGED;
7314 virtual std::optional<Type *> identifyPrivatizableType(Attributor &
A) = 0;
7318 std::optional<Type *> combineTypes(std::optional<Type *> T0,
7319 std::optional<Type *>
T1) {
7329 std::optional<Type *> getPrivatizableType()
const override {
7330 return PrivatizableType;
7333 const std::string getAsStr(Attributor *
A)
const override {
7334 return isAssumedPrivatizablePtr() ?
"[priv]" :
"[no-priv]";
7338 std::optional<Type *> PrivatizableType;
7343struct AAPrivatizablePtrArgument final :
public AAPrivatizablePtrImpl {
7344 AAPrivatizablePtrArgument(
const IRPosition &IRP, Attributor &
A)
7345 : AAPrivatizablePtrImpl(IRP,
A) {}
7348 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7351 bool UsedAssumedInformation =
false;
7353 A.getAttrs(getIRPosition(), {Attribute::ByVal},
Attrs,
7355 if (!
Attrs.empty() &&
7356 A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *
this,
7357 true, UsedAssumedInformation))
7358 return Attrs[0].getValueAsType();
7360 std::optional<Type *> Ty;
7361 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
7369 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7378 A.getAAFor<AAPrivatizablePtr>(*
this, ACSArgPos, DepClassTy::REQUIRED);
7381 std::optional<Type *> CSTy = PrivCSArgAA->getPrivatizableType();
7384 dbgs() <<
"[AAPrivatizablePtr] ACSPos: " << ACSArgPos <<
", CSTy: ";
7388 dbgs() <<
"<nullptr>";
7393 Ty = combineTypes(Ty, CSTy);
7396 dbgs() <<
" : New Type: ";
7398 (*Ty)->print(
dbgs());
7400 dbgs() <<
"<nullptr>";
7409 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7410 UsedAssumedInformation))
7417 PrivatizableType = identifyPrivatizableType(
A);
7418 if (!PrivatizableType)
7419 return ChangeStatus::UNCHANGED;
7420 if (!*PrivatizableType)
7421 return indicatePessimisticFixpoint();
7426 DepClassTy::OPTIONAL);
7429 if (!
A.hasAttr(getIRPosition(), Attribute::ByVal) &&
7432 return indicatePessimisticFixpoint();
7438 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7442 Function &Fn = *getIRPosition().getAnchorScope();
7444 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(Fn);
7446 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Missing TTI for function "
7448 return indicatePessimisticFixpoint();
7451 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7458 bool UsedAssumedInformation =
false;
7459 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7460 UsedAssumedInformation)) {
7462 dbgs() <<
"[AAPrivatizablePtr] ABI incompatibility detected for "
7464 return indicatePessimisticFixpoint();
7468 Argument *Arg = getAssociatedArgument();
7469 if (!
A.isValidFunctionSignatureRewrite(*Arg, ReplacementTypes)) {
7471 return indicatePessimisticFixpoint();
7478 auto IsCompatiblePrivArgOfCallback = [&](CallBase &CB) {
7481 for (
const Use *U : CallbackUses) {
7482 AbstractCallSite CBACS(U);
7483 assert(CBACS && CBACS.isCallbackCall());
7484 for (Argument &CBArg : CBACS.getCalledFunction()->args()) {
7485 int CBArgNo = CBACS.getCallArgOperandNo(CBArg);
7489 <<
"[AAPrivatizablePtr] Argument " << *Arg
7490 <<
"check if can be privatized in the context of its parent ("
7492 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7494 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7495 <<
")\n[AAPrivatizablePtr] " << CBArg <<
" : "
7496 << CBACS.getCallArgOperand(CBArg) <<
" vs "
7498 <<
"[AAPrivatizablePtr] " << CBArg <<
" : "
7499 << CBACS.getCallArgOperandNo(CBArg) <<
" vs " << ArgNo <<
"\n";
7502 if (CBArgNo !=
int(ArgNo))
7504 const auto *CBArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7506 if (CBArgPrivAA && CBArgPrivAA->isValidState()) {
7507 auto CBArgPrivTy = CBArgPrivAA->getPrivatizableType();
7510 if (*CBArgPrivTy == PrivatizableType)
7515 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7516 <<
" cannot be privatized in the context of its parent ("
7518 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7520 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7521 <<
").\n[AAPrivatizablePtr] for which the argument "
7522 "privatization is not compatible.\n";
7532 auto IsCompatiblePrivArgOfDirectCS = [&](AbstractCallSite ACS) {
7536 "Expected a direct call operand for callback call operand");
7541 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7542 <<
" check if be privatized in the context of its parent ("
7544 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7546 << DCArgNo <<
"@" << DCCallee->
getName() <<
").\n";
7549 if (
unsigned(DCArgNo) < DCCallee->
arg_size()) {
7550 const auto *DCArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7552 DepClassTy::REQUIRED);
7553 if (DCArgPrivAA && DCArgPrivAA->isValidState()) {
7554 auto DCArgPrivTy = DCArgPrivAA->getPrivatizableType();
7557 if (*DCArgPrivTy == PrivatizableType)
7563 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7564 <<
" cannot be privatized in the context of its parent ("
7566 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7569 <<
").\n[AAPrivatizablePtr] for which the argument "
7570 "privatization is not compatible.\n";
7578 auto IsCompatiblePrivArgOfOtherCallSite = [&](AbstractCallSite ACS) {
7582 return IsCompatiblePrivArgOfDirectCS(ACS);
7586 if (!
A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *
this,
true,
7587 UsedAssumedInformation))
7588 return indicatePessimisticFixpoint();
7590 return ChangeStatus::UNCHANGED;
7596 identifyReplacementTypes(
Type *PrivType,
7597 SmallVectorImpl<Type *> &ReplacementTypes) {
7600 assert(PrivType &&
"Expected privatizable type!");
7604 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++)
7605 ReplacementTypes.
push_back(PrivStructType->getElementType(u));
7607 ReplacementTypes.
append(PrivArrayType->getNumElements(),
7608 PrivArrayType->getElementType());
7617 static void createInitialization(
Type *PrivType,
Value &
Base, Function &
F,
7619 assert(PrivType &&
"Expected privatizable type!");
7622 const DataLayout &
DL =
F.getDataLayout();
7626 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7627 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7630 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7633 Type *PointeeTy = PrivArrayType->getElementType();
7634 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7635 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7637 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7640 new StoreInst(
F.getArg(ArgNo), &
Base, IP);
7646 void createReplacementValues(Align Alignment,
Type *PrivType,
7648 SmallVectorImpl<Value *> &ReplacementValues) {
7650 assert(PrivType &&
"Expected privatizable type!");
7658 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7659 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7660 Type *PointeeTy = PrivStructType->getElementType(u);
7663 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7664 L->setAlignment(Alignment);
7668 Type *PointeeTy = PrivArrayType->getElementType();
7669 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7670 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7672 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7673 L->setAlignment(Alignment);
7678 L->setAlignment(Alignment);
7685 if (!PrivatizableType)
7686 return ChangeStatus::UNCHANGED;
7687 assert(*PrivatizableType &&
"Expected privatizable type!");
7693 bool UsedAssumedInformation =
false;
7694 if (!
A.checkForAllInstructions(
7695 [&](Instruction &
I) {
7696 CallInst &CI = cast<CallInst>(I);
7697 if (CI.isTailCall())
7698 TailCalls.push_back(&CI);
7701 *
this, {Instruction::Call}, UsedAssumedInformation))
7702 return ChangeStatus::UNCHANGED;
7704 Argument *Arg = getAssociatedArgument();
7707 const auto *AlignAA =
7714 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7716 BasicBlock &EntryBB = ReplacementFn.getEntryBlock();
7718 const DataLayout &
DL = IP->getDataLayout();
7719 unsigned AS =
DL.getAllocaAddrSpace();
7720 Instruction *AI =
new AllocaInst(*PrivatizableType, AS,
7721 Arg->
getName() +
".priv", IP);
7722 createInitialization(*PrivatizableType, *AI, ReplacementFn,
7723 ArgIt->getArgNo(), IP);
7726 AI = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
7730 for (CallInst *CI : TailCalls)
7731 CI->setTailCall(
false);
7738 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7739 AbstractCallSite ACS, SmallVectorImpl<Value *> &NewArgOperands) {
7742 createReplacementValues(
7743 AlignAA ? AlignAA->getAssumedAlign() :
Align(0),
7744 *PrivatizableType, ACS,
7752 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7755 if (
A.registerFunctionSignatureRewrite(*Arg, ReplacementTypes,
7756 std::move(FnRepairCB),
7757 std::move(ACSRepairCB)))
7758 return ChangeStatus::CHANGED;
7759 return ChangeStatus::UNCHANGED;
7763 void trackStatistics()
const override {
7768struct AAPrivatizablePtrFloating :
public AAPrivatizablePtrImpl {
7769 AAPrivatizablePtrFloating(
const IRPosition &IRP, Attributor &
A)
7770 : AAPrivatizablePtrImpl(IRP,
A) {}
7775 indicatePessimisticFixpoint();
7780 "updateImpl will not be called");
7784 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7787 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] No underlying object found!\n");
7794 return AI->getAllocatedType();
7796 auto *PrivArgAA =
A.getAAFor<AAPrivatizablePtr>(
7798 if (PrivArgAA && PrivArgAA->isAssumedPrivatizablePtr())
7799 return PrivArgAA->getPrivatizableType();
7802 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Underlying object neither valid "
7803 "alloca nor privatizable argument: "
7809 void trackStatistics()
const override {
7814struct AAPrivatizablePtrCallSiteArgument final
7815 :
public AAPrivatizablePtrFloating {
7816 AAPrivatizablePtrCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
7817 : AAPrivatizablePtrFloating(IRP,
A) {}
7821 if (
A.hasAttr(getIRPosition(), Attribute::ByVal))
7822 indicateOptimisticFixpoint();
7827 PrivatizableType = identifyPrivatizableType(
A);
7828 if (!PrivatizableType)
7829 return ChangeStatus::UNCHANGED;
7830 if (!*PrivatizableType)
7831 return indicatePessimisticFixpoint();
7833 const IRPosition &IRP = getIRPosition();
7834 bool IsKnownNoCapture;
7836 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoCapture);
7837 if (!IsAssumedNoCapture) {
7838 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might be captured!\n");
7839 return indicatePessimisticFixpoint();
7842 bool IsKnownNoAlias;
7844 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
7845 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might alias!\n");
7846 return indicatePessimisticFixpoint();
7851 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer is written!\n");
7852 return indicatePessimisticFixpoint();
7855 return ChangeStatus::UNCHANGED;
7859 void trackStatistics()
const override {
7864struct AAPrivatizablePtrCallSiteReturned final
7865 :
public AAPrivatizablePtrFloating {
7866 AAPrivatizablePtrCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
7867 : AAPrivatizablePtrFloating(IRP,
A) {}
7872 indicatePessimisticFixpoint();
7876 void trackStatistics()
const override {
7881struct AAPrivatizablePtrReturned final :
public AAPrivatizablePtrFloating {
7882 AAPrivatizablePtrReturned(
const IRPosition &IRP, Attributor &
A)
7883 : AAPrivatizablePtrFloating(IRP,
A) {}
7888 indicatePessimisticFixpoint();
7892 void trackStatistics()
const override {
7902struct AAMemoryBehaviorImpl :
public AAMemoryBehavior {
7903 AAMemoryBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
7904 : AAMemoryBehavior(IRP,
A) {}
7908 intersectAssumedBits(BEST_STATE);
7909 getKnownStateFromValue(
A, getIRPosition(), getState());
7910 AAMemoryBehavior::initialize(
A);
7914 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
7915 BitIntegerState &State,
7916 bool IgnoreSubsumingPositions =
false) {
7918 A.getAttrs(IRP, AttrKinds, Attrs, IgnoreSubsumingPositions);
7920 switch (Attr.getKindAsEnum()) {
7921 case Attribute::ReadNone:
7924 case Attribute::ReadOnly:
7927 case Attribute::WriteOnly:
7936 if (!
I->mayReadFromMemory())
7938 if (!
I->mayWriteToMemory())
7944 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
7945 SmallVectorImpl<Attribute> &Attrs)
const override {
7948 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));
7950 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));
7951 else if (isAssumedWriteOnly())
7952 Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));
7958 const IRPosition &IRP = getIRPosition();
7960 if (
A.hasAttr(IRP, Attribute::ReadNone,
7962 return ChangeStatus::UNCHANGED;
7971 return ChangeStatus::UNCHANGED;
7974 A.removeAttrs(IRP, AttrKinds);
7977 A.removeAttrs(IRP, Attribute::Writable);
7984 const std::string getAsStr(Attributor *
A)
const override {
7989 if (isAssumedWriteOnly())
7991 return "may-read/write";
7995 static const Attribute::AttrKind AttrKinds[3];
7999 Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};
8002struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {
8003 AAMemoryBehaviorFloating(
const IRPosition &IRP, Attributor &
A)
8004 : AAMemoryBehaviorImpl(IRP,
A) {}
8010 void trackStatistics()
const override {
8015 else if (isAssumedWriteOnly())
8022 bool followUsersOfUseIn(Attributor &
A,
const Use &U,
8023 const Instruction *UserI);
8026 void analyzeUseIn(Attributor &
A,
const Use &U,
const Instruction *UserI);
8030struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
8031 AAMemoryBehaviorArgument(
const IRPosition &IRP, Attributor &
A)
8032 : AAMemoryBehaviorFloating(IRP,
A) {}
8036 intersectAssumedBits(BEST_STATE);
8037 const IRPosition &IRP = getIRPosition();
8041 bool HasByVal =
A.hasAttr(IRP, {Attribute::ByVal},
8043 getKnownStateFromValue(
A, IRP, getState(),
8050 return ChangeStatus::UNCHANGED;
8054 if (
A.hasAttr(getIRPosition(),
8055 {Attribute::InAlloca, Attribute::Preallocated})) {
8056 removeKnownBits(NO_WRITES);
8057 removeAssumedBits(NO_WRITES);
8059 A.removeAttrs(getIRPosition(), AttrKinds);
8060 return AAMemoryBehaviorFloating::manifest(
A);
8064 void trackStatistics()
const override {
8069 else if (isAssumedWriteOnly())
8074struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {
8075 AAMemoryBehaviorCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
8076 : AAMemoryBehaviorArgument(IRP,
A) {}
8082 Argument *Arg = getAssociatedArgument();
8084 indicatePessimisticFixpoint();
8088 addKnownBits(NO_WRITES);
8089 removeKnownBits(NO_READS);
8090 removeAssumedBits(NO_READS);
8092 AAMemoryBehaviorArgument::initialize(
A);
8093 if (getAssociatedFunction()->isDeclaration())
8094 indicatePessimisticFixpoint();
8103 Argument *Arg = getAssociatedArgument();
8106 A.getAAFor<AAMemoryBehavior>(*
this, ArgPos, DepClassTy::REQUIRED);
8108 return indicatePessimisticFixpoint();
8113 void trackStatistics()
const override {
8118 else if (isAssumedWriteOnly())
8124struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {
8125 AAMemoryBehaviorCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
8126 : AAMemoryBehaviorFloating(IRP,
A) {}
8130 AAMemoryBehaviorImpl::initialize(
A);
8135 return ChangeStatus::UNCHANGED;
8139 void trackStatistics()
const override {}
8143struct AAMemoryBehaviorFunction final :
public AAMemoryBehaviorImpl {
8144 AAMemoryBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
8145 : AAMemoryBehaviorImpl(IRP,
A) {}
8161 else if (isAssumedWriteOnly())
8164 A.removeAttrs(getIRPosition(), AttrKinds);
8167 for (Argument &Arg :
F.args())
8169 return A.manifestAttrs(getIRPosition(),
8170 Attribute::getWithMemoryEffects(
F.getContext(), ME));
8174 void trackStatistics()
const override {
8179 else if (isAssumedWriteOnly())
8185struct AAMemoryBehaviorCallSite final
8186 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl> {
8187 AAMemoryBehaviorCallSite(
const IRPosition &IRP, Attributor &
A)
8188 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl>(IRP,
A) {}
8199 else if (isAssumedWriteOnly())
8202 A.removeAttrs(getIRPosition(), AttrKinds);
8205 for (Use &U : CB.
args())
8207 Attribute::Writable);
8208 return A.manifestAttrs(
8209 getIRPosition(), Attribute::getWithMemoryEffects(CB.
getContext(), ME));
8213 void trackStatistics()
const override {
8218 else if (isAssumedWriteOnly())
8223ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &
A) {
8226 auto AssumedState = getAssumed();
8233 const auto *MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
8235 if (MemBehaviorAA) {
8236 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8237 return !isAtFixpoint();
8242 if (
I.mayReadFromMemory())
8243 removeAssumedBits(NO_READS);
8244 if (
I.mayWriteToMemory())
8245 removeAssumedBits(NO_WRITES);
8246 return !isAtFixpoint();
8249 bool UsedAssumedInformation =
false;
8250 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8251 UsedAssumedInformation))
8252 return indicatePessimisticFixpoint();
8258ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &
A) {
8260 const IRPosition &IRP = getIRPosition();
8271 const auto *FnMemAA =
8274 FnMemAssumedState = FnMemAA->getAssumed();
8275 S.addKnownBits(FnMemAA->getKnown());
8276 if ((S.getAssumed() & FnMemAA->getAssumed()) == S.getAssumed())
8282 auto AssumedState = S.getAssumed();
8288 bool IsKnownNoCapture;
8289 const AANoCapture *ArgNoCaptureAA =
nullptr;
8294 if (!IsAssumedNoCapture &&
8296 S.intersectAssumedBits(FnMemAssumedState);
8302 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
8304 LLVM_DEBUG(
dbgs() <<
"[AAMemoryBehavior] Use: " << *U <<
" in " << *UserI
8312 Follow = followUsersOfUseIn(
A, U, UserI);
8316 analyzeUseIn(
A, U, UserI);
8318 return !isAtFixpoint();
8321 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue()))
8322 return indicatePessimisticFixpoint();
8328bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &
A,
const Use &U,
8329 const Instruction *UserI) {
8347 if (
U.get()->getType()->isPointerTy()) {
8349 bool IsKnownNoCapture;
8358void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &
A,
const Use &U,
8359 const Instruction *UserI) {
8366 case Instruction::Load:
8368 removeAssumedBits(NO_READS);
8371 case Instruction::Store:
8376 removeAssumedBits(NO_WRITES);
8378 indicatePessimisticFixpoint();
8381 case Instruction::Call:
8382 case Instruction::CallBr:
8383 case Instruction::Invoke: {
8390 indicatePessimisticFixpoint();
8397 removeAssumedBits(NO_READS);
8404 if (
U.get()->getType()->isPointerTy())
8408 const auto *MemBehaviorAA =
8414 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8422 removeAssumedBits(NO_READS);
8424 removeAssumedBits(NO_WRITES);
8436 return "all memory";
8439 std::string S =
"memory:";
8445 S +=
"internal global,";
8447 S +=
"external global,";
8451 S +=
"inaccessible,";
8465 AccessKind2Accesses.fill(
nullptr);
8468 ~AAMemoryLocationImpl()
override {
8471 for (AccessSet *AS : AccessKind2Accesses)
8478 intersectAssumedBits(BEST_STATE);
8479 getKnownStateFromValue(
A, getIRPosition(), getState());
8480 AAMemoryLocation::initialize(
A);
8484 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
8485 BitIntegerState &State,
8486 bool IgnoreSubsumingPositions =
false) {
8495 bool UseArgMemOnly =
true;
8497 if (AnchorFn &&
A.isRunOn(*AnchorFn))
8501 A.getAttrs(IRP, {Attribute::Memory},
Attrs, IgnoreSubsumingPositions);
8510 State.
addKnownBits(inverseLocation(NO_INACCESSIBLE_MEM,
true,
true));
8515 State.
addKnownBits(inverseLocation(NO_ARGUMENT_MEM,
true,
true));
8519 A.manifestAttrs(IRP,
8520 Attribute::getWithMemoryEffects(
8529 NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM,
true,
true));
8533 A.manifestAttrs(IRP,
8534 Attribute::getWithMemoryEffects(
8544 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
8545 SmallVectorImpl<Attribute> &Attrs)
const override {
8552 else if (isAssumedInaccessibleMemOnly())
8553 Attrs.push_back(Attribute::getWithMemoryEffects(
8555 else if (isAssumedArgMemOnly())
8558 else if (isAssumedInaccessibleOrArgMemOnly())
8559 Attrs.push_back(Attribute::getWithMemoryEffects(
8569 const IRPosition &IRP = getIRPosition();
8573 if (DeducedAttrs.
size() != 1)
8574 return ChangeStatus::UNCHANGED;
8577 return A.manifestAttrs(IRP, Attribute::getWithMemoryEffects(
8582 bool checkForAllAccessesToMemoryKind(
8584 MemoryLocationsKind)>
8586 MemoryLocationsKind RequestedMLK)
const override {
8587 if (!isValidState())
8590 MemoryLocationsKind AssumedMLK = getAssumedNotAccessedLocation();
8591 if (AssumedMLK == NO_LOCATIONS)
8595 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS;
8596 CurMLK *= 2, ++Idx) {
8597 if (CurMLK & RequestedMLK)
8600 if (
const AccessSet *
Accesses = AccessKind2Accesses[Idx])
8601 for (
const AccessInfo &AI : *
Accesses)
8602 if (!Pred(AI.I, AI.Ptr, AI.Kind, CurMLK))
8615 MemoryLocationsKind KnownMLK = getKnown();
8617 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2)
8618 if (!(CurMLK & KnownMLK))
8619 updateStateAndAccessesMap(getState(), CurMLK,
I,
nullptr,
Changed,
8620 getAccessKindFromInst(
I));
8621 return AAMemoryLocation::indicatePessimisticFixpoint();
8641 bool operator()(
const AccessInfo &
LHS,
const AccessInfo &
RHS)
const {
8645 return LHS.Ptr <
RHS.Ptr;
8646 if (
LHS.Kind !=
RHS.Kind)
8647 return LHS.Kind <
RHS.Kind;
8654 using AccessSet = SmallSet<AccessInfo, 2, AccessInfo>;
8655 std::array<AccessSet *, llvm::ConstantLog2<VALID_STATE>()>
8656 AccessKind2Accesses;
8661 categorizeArgumentPointerLocations(Attributor &
A, CallBase &CB,
8662 AAMemoryLocation::StateType &AccessedLocs,
8667 categorizeAccessedLocations(Attributor &
A, Instruction &
I,
bool &
Changed);
8670 AccessKind getAccessKindFromInst(
const Instruction *
I) {
8673 AK =
I->mayReadFromMemory() ? READ :
NONE;
8682 void updateStateAndAccessesMap(AAMemoryLocation::StateType &State,
8683 MemoryLocationsKind MLK,
const Instruction *
I,
8692 if (MLK == NO_UNKOWN_MEM)
8694 State.removeAssumedBits(MLK);
8699 void categorizePtrValue(Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8700 AAMemoryLocation::StateType &State,
bool &
Changed,
8701 unsigned AccessAS = 0);
8707void AAMemoryLocationImpl::categorizePtrValue(
8708 Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8710 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize pointer locations for "
8715 unsigned ObjectAS =
Obj.getType()->getPointerAddressSpace();
8717 MemoryLocationsKind MLK = NO_LOCATIONS;
8736 MLK = NO_ARGUMENT_MEM;
8742 if (GVar->isConstant())
8745 if (GV->hasLocalLinkage())
8746 MLK = NO_GLOBAL_INTERNAL_MEM;
8748 MLK = NO_GLOBAL_EXTERNAL_MEM;
8756 bool IsKnownNoAlias;
8760 MLK = NO_MALLOCED_MEM;
8762 MLK = NO_UNKOWN_MEM;
8764 MLK = NO_UNKOWN_MEM;
8767 assert(MLK != NO_LOCATIONS &&
"No location specified!");
8768 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Ptr value can be categorized: "
8769 << Obj <<
" -> " << getMemoryLocationsAsStr(MLK) <<
"\n");
8771 getAccessKindFromInst(&
I));
8776 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
8780 dbgs() <<
"[AAMemoryLocation] Pointer locations not categorized\n");
8781 updateStateAndAccessesMap(
State, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8782 getAccessKindFromInst(&
I));
8787 dbgs() <<
"[AAMemoryLocation] Accessed locations with pointer locations: "
8791void AAMemoryLocationImpl::categorizeArgumentPointerLocations(
8794 for (
unsigned ArgNo = 0,
E = CB.
arg_size(); ArgNo <
E; ++ArgNo) {
8803 const auto *ArgOpMemLocationAA =
8806 if (ArgOpMemLocationAA && ArgOpMemLocationAA->isAssumedReadNone())
8811 categorizePtrValue(
A, CB, *ArgOp, AccessedLocs,
Changed);
8816AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &
A, Instruction &
I,
8818 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize accessed locations for "
8822 AccessedLocs.intersectAssumedBits(NO_LOCATIONS);
8827 const auto *CBMemLocationAA =
A.getAAFor<AAMemoryLocation>(
8830 <<
" [" << CBMemLocationAA <<
"]\n");
8831 if (!CBMemLocationAA) {
8832 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
8833 Changed, getAccessKindFromInst(&
I));
8834 return NO_UNKOWN_MEM;
8837 if (CBMemLocationAA->isAssumedReadNone())
8838 return NO_LOCATIONS;
8840 if (CBMemLocationAA->isAssumedInaccessibleMemOnly()) {
8841 updateStateAndAccessesMap(AccessedLocs, NO_INACCESSIBLE_MEM, &
I,
nullptr,
8842 Changed, getAccessKindFromInst(&
I));
8843 return AccessedLocs.getAssumed();
8846 uint32_t CBAssumedNotAccessedLocs =
8847 CBMemLocationAA->getAssumedNotAccessedLocation();
8850 uint32_t CBAssumedNotAccessedLocsNoArgMem =
8851 CBAssumedNotAccessedLocs | NO_ARGUMENT_MEM | NO_GLOBAL_MEM;
8853 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2) {
8854 if (CBAssumedNotAccessedLocsNoArgMem & CurMLK)
8856 updateStateAndAccessesMap(AccessedLocs, CurMLK, &
I,
nullptr,
Changed,
8857 getAccessKindFromInst(&
I));
8862 bool HasGlobalAccesses = ((~CBAssumedNotAccessedLocs) & NO_GLOBAL_MEM);
8863 if (HasGlobalAccesses) {
8866 updateStateAndAccessesMap(AccessedLocs, MLK, &
I, Ptr,
Changed,
8867 getAccessKindFromInst(&
I));
8870 if (!CBMemLocationAA->checkForAllAccessesToMemoryKind(
8871 AccessPred, inverseLocation(NO_GLOBAL_MEM,
false,
false)))
8872 return AccessedLocs.getWorstState();
8876 dbgs() <<
"[AAMemoryLocation] Accessed state before argument handling: "
8877 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8880 bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM);
8882 categorizeArgumentPointerLocations(
A, *CB, AccessedLocs,
Changed);
8885 dbgs() <<
"[AAMemoryLocation] Accessed state after argument handling: "
8886 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8888 return AccessedLocs.getAssumed();
8893 dbgs() <<
"[AAMemoryLocation] Categorize memory access with pointer: "
8894 <<
I <<
" [" << *Ptr <<
"]\n");
8895 categorizePtrValue(
A,
I, *Ptr, AccessedLocs,
Changed,
8896 Ptr->getType()->getPointerAddressSpace());
8897 return AccessedLocs.getAssumed();
8900 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Failed to categorize instruction: "
8902 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8903 getAccessKindFromInst(&
I));
8904 return AccessedLocs.getAssumed();
8908struct AAMemoryLocationFunction final :
public AAMemoryLocationImpl {
8909 AAMemoryLocationFunction(
const IRPosition &IRP, Attributor &
A)
8910 : AAMemoryLocationImpl(IRP,
A) {}
8915 const auto *MemBehaviorAA =
8916 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
8919 return indicateOptimisticFixpoint();
8921 "AAMemoryLocation was not read-none but AAMemoryBehavior was!");
8922 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
8923 return ChangeStatus::UNCHANGED;
8927 auto AssumedState = getAssumed();
8931 MemoryLocationsKind MLK = categorizeAccessedLocations(
A,
I,
Changed);
8932 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Accessed locations for " <<
I
8933 <<
": " << getMemoryLocationsAsStr(MLK) <<
"\n");
8934 removeAssumedBits(inverseLocation(MLK,
false,
false));
8937 return getAssumedNotAccessedLocation() != VALID_STATE;
8940 bool UsedAssumedInformation =
false;
8941 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8942 UsedAssumedInformation))
8943 return indicatePessimisticFixpoint();
8945 Changed |= AssumedState != getAssumed();
8946 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8950 void trackStatistics()
const override {
8953 else if (isAssumedArgMemOnly())
8955 else if (isAssumedInaccessibleMemOnly())
8957 else if (isAssumedInaccessibleOrArgMemOnly())
8963struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {
8964 AAMemoryLocationCallSite(
const IRPosition &IRP, Attributor &
A)
8965 : AAMemoryLocationImpl(IRP,
A) {}
8976 A.getAAFor<AAMemoryLocation>(*
this, FnPos, DepClassTy::REQUIRED);
8978 return indicatePessimisticFixpoint();
8982 updateStateAndAccessesMap(getState(), MLK,
I, Ptr,
Changed,
8983 getAccessKindFromInst(
I));
8986 if (!FnAA->checkForAllAccessesToMemoryKind(AccessPred, ALL_LOCATIONS))
8987 return indicatePessimisticFixpoint();
8988 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8992 void trackStatistics()
const override {
9002struct AADenormalFPMathImpl :
public AADenormalFPMath {
9003 AADenormalFPMathImpl(
const IRPosition &IRP, Attributor &
A)
9004 : AADenormalFPMath(IRP,
A) {}
9006 const std::string getAsStr(Attributor *
A)
const override {
9007 std::string Str(
"AADenormalFPMath[");
9008 raw_string_ostream OS(Str);
9010 DenormalState Known = getKnown();
9011 if (Known.Mode.isValid())
9012 OS <<
"denormal-fp-math=" << Known.Mode;
9016 if (Known.ModeF32.isValid())
9017 OS <<
" denormal-fp-math-f32=" << Known.ModeF32;
9023struct AADenormalFPMathFunction final : AADenormalFPMathImpl {
9024 AADenormalFPMathFunction(
const IRPosition &IRP, Attributor &
A)
9025 : AADenormalFPMathImpl(IRP,
A) {}
9029 DenormalFPEnv DenormEnv =
F->getDenormalFPEnv();
9039 auto CheckCallSite = [=, &Change, &
A](AbstractCallSite CS) {
9042 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
9044 const auto *CallerInfo =
A.getAAFor<AADenormalFPMath>(
9050 CallerInfo->getState());
9054 bool AllCallSitesKnown =
true;
9055 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
9056 return indicatePessimisticFixpoint();
9058 if (Change == ChangeStatus::CHANGED && isModeFixed())
9064 LLVMContext &Ctx = getAssociatedFunction()->getContext();
9070 DenormalFPEnv KnownEnv(Known.Mode, Known.ModeF32);
9073 AttrToRemove.
push_back(Attribute::DenormalFPEnv);
9076 Ctx, Attribute::DenormalFPEnv,
9077 DenormalFPEnv(Known.Mode, Known.ModeF32).toIntValue()));
9080 auto &IRP = getIRPosition();
9083 return A.removeAttrs(IRP, AttrToRemove) |
9084 A.manifestAttrs(IRP, AttrToAdd,
true);
9087 void trackStatistics()
const override {
9096struct AAValueConstantRangeImpl : AAValueConstantRange {
9097 using StateType = IntegerRangeState;
9098 AAValueConstantRangeImpl(
const IRPosition &IRP, Attributor &
A)
9099 : AAValueConstantRange(IRP,
A) {}
9103 if (
A.hasSimplificationCallback(getIRPosition())) {
9104 indicatePessimisticFixpoint();
9109 intersectKnown(getConstantRangeFromSCEV(
A, getCtxI()));
9112 intersectKnown(getConstantRangeFromLVI(
A, getCtxI()));
9116 const std::string getAsStr(Attributor *
A)
const override {
9118 llvm::raw_string_ostream OS(Str);
9120 getKnown().print(OS);
9122 getAssumed().print(OS);
9129 const SCEV *getSCEV(Attributor &
A,
const Instruction *
I =
nullptr)
const {
9130 if (!getAnchorScope())
9133 ScalarEvolution *SE =
9134 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9137 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
9143 const SCEV *S = SE->
getSCEV(&getAssociatedValue());
9152 ConstantRange getConstantRangeFromSCEV(Attributor &
A,
9153 const Instruction *
I =
nullptr)
const {
9154 if (!getAnchorScope())
9157 ScalarEvolution *SE =
9158 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9161 const SCEV *S = getSCEV(
A,
I);
9171 getConstantRangeFromLVI(Attributor &
A,
9172 const Instruction *CtxI =
nullptr)
const {
9173 if (!getAnchorScope())
9176 LazyValueInfo *LVI =
9177 A.getInfoCache().getAnalysisResultForFunction<LazyValueAnalysis>(
9192 bool isValidCtxInstructionForOutsideAnalysis(Attributor &
A,
9193 const Instruction *CtxI,
9194 bool AllowAACtxI)
const {
9195 if (!CtxI || (!AllowAACtxI && CtxI == getCtxI()))
9207 InformationCache &InfoCache =
A.getInfoCache();
9208 const DominatorTree *DT =
9219 getKnownConstantRange(Attributor &
A,
9220 const Instruction *CtxI =
nullptr)
const override {
9221 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9225 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9226 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9227 return getKnown().intersectWith(SCEVR).intersectWith(LVIR);
9232 getAssumedConstantRange(Attributor &
A,
9233 const Instruction *CtxI =
nullptr)
const override {
9238 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9240 return getAssumed();
9242 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9243 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9244 return getAssumed().intersectWith(SCEVR).intersectWith(LVIR);
9249 getMDNodeForConstantRange(
Type *Ty, LLVMContext &Ctx,
9250 const ConstantRange &AssumedConstantRange) {
9252 Ty, AssumedConstantRange.
getLower())),
9254 Ty, AssumedConstantRange.
getUpper()))};
9259 static bool isBetterRange(
const ConstantRange &Assumed,
9260 const Instruction &
I) {
9264 std::optional<ConstantRange> Known;
9268 }
else if (MDNode *KnownRanges =
I.getMetadata(LLVMContext::MD_range)) {
9274 if (KnownRanges->getNumOperands() > 2)
9277 ConstantInt *
Lower =
9279 ConstantInt *
Upper =
9282 Known.emplace(
Lower->getValue(),
Upper->getValue());
9284 return !Known || (*Known != Assumed && Known->contains(Assumed));
9289 setRangeMetadataIfisBetterRange(Instruction *
I,
9290 const ConstantRange &AssumedConstantRange) {
9291 if (isBetterRange(AssumedConstantRange, *
I)) {
9292 I->setMetadata(LLVMContext::MD_range,
9293 getMDNodeForConstantRange(
I->getType(),
I->getContext(),
9294 AssumedConstantRange));
9301 setRangeRetAttrIfisBetterRange(Attributor &
A,
const IRPosition &IRP,
9303 const ConstantRange &AssumedConstantRange) {
9304 if (isBetterRange(AssumedConstantRange, *
I)) {
9305 A.manifestAttrs(IRP,
9306 Attribute::get(
I->getContext(), Attribute::Range,
9307 AssumedConstantRange),
9317 ConstantRange AssumedConstantRange = getAssumedConstantRange(
A);
9320 auto &
V = getAssociatedValue();
9324 assert(
I == getCtxI() &&
"Should not annotate an instruction which is "
9325 "not the context instruction");
9327 if (setRangeMetadataIfisBetterRange(
I, AssumedConstantRange))
9328 Changed = ChangeStatus::CHANGED;
9330 if (setRangeRetAttrIfisBetterRange(
A, getIRPosition(),
I,
9331 AssumedConstantRange))
9332 Changed = ChangeStatus::CHANGED;
9340struct AAValueConstantRangeArgument final
9341 : AAArgumentFromCallSiteArguments<
9342 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9344 using Base = AAArgumentFromCallSiteArguments<
9345 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9347 AAValueConstantRangeArgument(
const IRPosition &IRP, Attributor &
A)
9351 void trackStatistics()
const override {
9356struct AAValueConstantRangeReturned
9357 : AAReturnedFromReturnedValues<AAValueConstantRange,
9358 AAValueConstantRangeImpl,
9359 AAValueConstantRangeImpl::StateType,
9362 AAReturnedFromReturnedValues<AAValueConstantRange,
9363 AAValueConstantRangeImpl,
9364 AAValueConstantRangeImpl::StateType,
9366 AAValueConstantRangeReturned(
const IRPosition &IRP, Attributor &
A)
9371 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9372 indicatePessimisticFixpoint();
9376 void trackStatistics()
const override {
9381struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
9382 AAValueConstantRangeFloating(
const IRPosition &IRP, Attributor &
A)
9383 : AAValueConstantRangeImpl(IRP,
A) {}
9387 AAValueConstantRangeImpl::initialize(
A);
9391 Value &
V = getAssociatedValue();
9394 unionAssumed(ConstantRange(
C->getValue()));
9395 indicateOptimisticFixpoint();
9401 unionAssumed(ConstantRange(APInt(
getBitWidth(), 0)));
9402 indicateOptimisticFixpoint();
9414 if (
auto *RangeMD = LI->getMetadata(LLVMContext::MD_range)) {
9425 indicatePessimisticFixpoint();
9428 << getAssociatedValue() <<
"\n");
9431 bool calculateBinaryOperator(
9432 Attributor &
A, BinaryOperator *BinOp, IntegerRangeState &
T,
9433 const Instruction *CtxI,
9434 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9439 bool UsedAssumedInformation =
false;
9440 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9443 if (!SimplifiedLHS.has_value())
9445 if (!*SimplifiedLHS)
9447 LHS = *SimplifiedLHS;
9449 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9452 if (!SimplifiedRHS.has_value())
9454 if (!*SimplifiedRHS)
9456 RHS = *SimplifiedRHS;
9462 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9464 DepClassTy::REQUIRED);
9468 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9470 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9472 DepClassTy::REQUIRED);
9476 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9478 auto AssumedRange = LHSAARange.binaryOp(BinOp->
getOpcode(), RHSAARange);
9480 T.unionAssumed(AssumedRange);
9484 return T.isValidState();
9487 bool calculateCastInst(
9488 Attributor &
A, CastInst *CastI, IntegerRangeState &
T,
9489 const Instruction *CtxI,
9490 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9496 bool UsedAssumedInformation =
false;
9497 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9500 if (!SimplifiedOpV.has_value())
9502 if (!*SimplifiedOpV)
9504 OpV = *SimplifiedOpV;
9509 auto *OpAA =
A.getAAFor<AAValueConstantRange>(
9511 DepClassTy::REQUIRED);
9515 T.unionAssumed(OpAA->getAssumed().castOp(CastI->
getOpcode(),
9517 return T.isValidState();
9521 calculateCmpInst(Attributor &
A, CmpInst *CmpI, IntegerRangeState &
T,
9522 const Instruction *CtxI,
9523 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9528 bool UsedAssumedInformation =
false;
9529 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9532 if (!SimplifiedLHS.has_value())
9534 if (!*SimplifiedLHS)
9536 LHS = *SimplifiedLHS;
9538 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9541 if (!SimplifiedRHS.has_value())
9543 if (!*SimplifiedRHS)
9545 RHS = *SimplifiedRHS;
9551 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9553 DepClassTy::REQUIRED);
9557 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9559 DepClassTy::REQUIRED);
9563 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9564 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9567 if (LHSAARange.isEmptySet() || RHSAARange.isEmptySet())
9570 bool MustTrue =
false, MustFalse =
false;
9572 auto AllowedRegion =
9575 if (AllowedRegion.intersectWith(LHSAARange).isEmptySet())
9581 assert((!MustTrue || !MustFalse) &&
9582 "Either MustTrue or MustFalse should be false!");
9585 T.unionAssumed(ConstantRange(APInt( 1, 1)));
9587 T.unionAssumed(ConstantRange(APInt( 1, 0)));
9589 T.unionAssumed(ConstantRange( 1,
true));
9591 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] " << *CmpI <<
" after "
9592 << (MustTrue ?
"true" : (MustFalse ?
"false" :
"unknown"))
9593 <<
": " <<
T <<
"\n\t" << *LHSAA <<
"\t<op>\n\t"
9597 return T.isValidState();
9609 bool UsedAssumedInformation =
false;
9610 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9613 if (!SimplifiedOpV.has_value())
9615 if (!*SimplifiedOpV)
9617 Value *VPtr = *SimplifiedOpV;
9620 const auto *AA =
A.getAAFor<AAValueConstantRange>(
9622 DepClassTy::REQUIRED);
9626 T.unionAssumed(AA->getAssumedConstantRange(
A, CtxI));
9630 return T.isValidState();
9635 if (!calculateBinaryOperator(
A, BinOp,
T, CtxI, QuerriedAAs))
9638 if (!calculateCmpInst(
A, CmpI,
T, CtxI, QuerriedAAs))
9641 if (!calculateCastInst(
A, CastI,
T, CtxI, QuerriedAAs))
9647 T.indicatePessimisticFixpoint();
9654 for (
const AAValueConstantRange *QueriedAA : QuerriedAAs) {
9655 if (QueriedAA !=
this)
9658 if (
T.getAssumed() == getState().getAssumed())
9660 T.indicatePessimisticFixpoint();
9663 return T.isValidState();
9666 if (!VisitValueCB(getAssociatedValue(), getCtxI()))
9667 return indicatePessimisticFixpoint();
9672 return ChangeStatus::UNCHANGED;
9673 if (++NumChanges > MaxNumChanges) {
9674 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] performed " << NumChanges
9675 <<
" but only " << MaxNumChanges
9676 <<
" are allowed to avoid cyclic reasoning.");
9677 return indicatePessimisticFixpoint();
9679 return ChangeStatus::CHANGED;
9683 void trackStatistics()
const override {
9692 static constexpr int MaxNumChanges = 5;
9695struct AAValueConstantRangeFunction : AAValueConstantRangeImpl {
9696 AAValueConstantRangeFunction(
const IRPosition &IRP, Attributor &
A)
9697 : AAValueConstantRangeImpl(IRP,
A) {}
9701 llvm_unreachable(
"AAValueConstantRange(Function|CallSite)::updateImpl will "
9709struct AAValueConstantRangeCallSite : AAValueConstantRangeFunction {
9710 AAValueConstantRangeCallSite(
const IRPosition &IRP, Attributor &
A)
9711 : AAValueConstantRangeFunction(IRP,
A) {}
9717struct AAValueConstantRangeCallSiteReturned
9718 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9719 AAValueConstantRangeImpl::StateType,
9721 AAValueConstantRangeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
9722 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9723 AAValueConstantRangeImpl::StateType,
9730 if (std::optional<ConstantRange>
Range = CI->getRange())
9731 intersectKnown(*
Range);
9734 AAValueConstantRangeImpl::initialize(
A);
9738 void trackStatistics()
const override {
9742struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating {
9743 AAValueConstantRangeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
9744 : AAValueConstantRangeFloating(IRP,
A) {}
9748 return ChangeStatus::UNCHANGED;
9752 void trackStatistics()
const override {
9761struct AAPotentialConstantValuesImpl : AAPotentialConstantValues {
9764 AAPotentialConstantValuesImpl(
const IRPosition &IRP, Attributor &
A)
9765 : AAPotentialConstantValues(IRP,
A) {}
9769 if (
A.hasSimplificationCallback(getIRPosition()))
9770 indicatePessimisticFixpoint();
9772 AAPotentialConstantValues::initialize(
A);
9775 bool fillSetWithConstantValues(Attributor &
A,
const IRPosition &IRP, SetTy &S,
9776 bool &ContainsUndef,
bool ForSelf) {
9778 bool UsedAssumedInformation =
false;
9780 UsedAssumedInformation)) {
9787 auto *PotentialValuesAA =
A.getAAFor<AAPotentialConstantValues>(
9788 *
this, IRP, DepClassTy::REQUIRED);
9789 if (!PotentialValuesAA || !PotentialValuesAA->getState().isValidState())
9791 ContainsUndef = PotentialValuesAA->getState().undefIsContained();
9792 S = PotentialValuesAA->getState().getAssumedSet();
9799 ContainsUndef =
false;
9800 for (
auto &It : Values) {
9802 ContainsUndef =
true;
9808 S.insert(CI->getValue());
9810 ContainsUndef &= S.empty();
9816 const std::string getAsStr(Attributor *
A)
const override {
9818 llvm::raw_string_ostream OS(Str);
9825 return indicatePessimisticFixpoint();
9829struct AAPotentialConstantValuesArgument final
9830 : AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9831 AAPotentialConstantValuesImpl,
9832 PotentialConstantIntValuesState> {
9833 using Base = AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9834 AAPotentialConstantValuesImpl,
9836 AAPotentialConstantValuesArgument(
const IRPosition &IRP, Attributor &
A)
9840 void trackStatistics()
const override {
9845struct AAPotentialConstantValuesReturned
9846 : AAReturnedFromReturnedValues<AAPotentialConstantValues,
9847 AAPotentialConstantValuesImpl> {
9848 using Base = AAReturnedFromReturnedValues<AAPotentialConstantValues,
9849 AAPotentialConstantValuesImpl>;
9850 AAPotentialConstantValuesReturned(
const IRPosition &IRP, Attributor &
A)
9854 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9855 indicatePessimisticFixpoint();
9856 Base::initialize(
A);
9860 void trackStatistics()
const override {
9865struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl {
9866 AAPotentialConstantValuesFloating(
const IRPosition &IRP, Attributor &
A)
9867 : AAPotentialConstantValuesImpl(IRP,
A) {}
9871 AAPotentialConstantValuesImpl::initialize(
A);
9875 Value &
V = getAssociatedValue();
9878 unionAssumed(
C->getValue());
9879 indicateOptimisticFixpoint();
9884 unionAssumedWithUndef();
9885 indicateOptimisticFixpoint();
9895 indicatePessimisticFixpoint();
9898 << getAssociatedValue() <<
"\n");
9901 static bool calculateICmpInst(
const ICmpInst *ICI,
const APInt &
LHS,
9906 static APInt calculateCastInst(
const CastInst *CI,
const APInt &Src,
9907 uint32_t ResultBitWidth) {
9912 case Instruction::Trunc:
9913 return Src.trunc(ResultBitWidth);
9914 case Instruction::SExt:
9915 return Src.sext(ResultBitWidth);
9916 case Instruction::ZExt:
9917 return Src.zext(ResultBitWidth);
9918 case Instruction::BitCast:
9923 static APInt calculateBinaryOperator(
const BinaryOperator *BinOp,
9924 const APInt &
LHS,
const APInt &
RHS,
9925 bool &SkipOperation,
bool &Unsupported) {
9932 switch (BinOpcode) {
9936 case Instruction::Add:
9938 case Instruction::Sub:
9940 case Instruction::Mul:
9942 case Instruction::UDiv:
9944 SkipOperation =
true;
9948 case Instruction::SDiv:
9950 SkipOperation =
true;
9954 case Instruction::URem:
9956 SkipOperation =
true;
9960 case Instruction::SRem:
9962 SkipOperation =
true;
9966 case Instruction::Shl:
9968 case Instruction::LShr:
9970 case Instruction::AShr:
9972 case Instruction::And:
9974 case Instruction::Or:
9976 case Instruction::Xor:
9981 bool calculateBinaryOperatorAndTakeUnion(
const BinaryOperator *BinOp,
9982 const APInt &
LHS,
const APInt &
RHS) {
9983 bool SkipOperation =
false;
9986 calculateBinaryOperator(BinOp,
LHS,
RHS, SkipOperation, Unsupported);
9991 unionAssumed(Result);
9992 return isValidState();
9995 ChangeStatus updateWithICmpInst(Attributor &
A, ICmpInst *ICI) {
9996 auto AssumedBefore = getAssumed();
10000 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10001 SetTy LHSAAPVS, RHSAAPVS;
10003 LHSContainsUndef,
false) ||
10005 RHSContainsUndef,
false))
10006 return indicatePessimisticFixpoint();
10009 bool MaybeTrue =
false, MaybeFalse =
false;
10011 if (LHSContainsUndef && RHSContainsUndef) {
10014 unionAssumedWithUndef();
10015 }
else if (LHSContainsUndef) {
10016 for (
const APInt &R : RHSAAPVS) {
10017 bool CmpResult = calculateICmpInst(ICI, Zero, R);
10018 MaybeTrue |= CmpResult;
10019 MaybeFalse |= !CmpResult;
10020 if (MaybeTrue & MaybeFalse)
10021 return indicatePessimisticFixpoint();
10023 }
else if (RHSContainsUndef) {
10024 for (
const APInt &L : LHSAAPVS) {
10025 bool CmpResult = calculateICmpInst(ICI, L, Zero);
10026 MaybeTrue |= CmpResult;
10027 MaybeFalse |= !CmpResult;
10028 if (MaybeTrue & MaybeFalse)
10029 return indicatePessimisticFixpoint();
10032 for (
const APInt &L : LHSAAPVS) {
10033 for (
const APInt &R : RHSAAPVS) {
10034 bool CmpResult = calculateICmpInst(ICI, L, R);
10035 MaybeTrue |= CmpResult;
10036 MaybeFalse |= !CmpResult;
10037 if (MaybeTrue & MaybeFalse)
10038 return indicatePessimisticFixpoint();
10043 unionAssumed(APInt( 1, 1));
10045 unionAssumed(APInt( 1, 0));
10046 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10047 : ChangeStatus::CHANGED;
10050 ChangeStatus updateWithSelectInst(Attributor &
A, SelectInst *SI) {
10051 auto AssumedBefore = getAssumed();
10055 bool UsedAssumedInformation =
false;
10056 std::optional<Constant *>
C =
A.getAssumedConstant(
10057 *
SI->getCondition(), *
this, UsedAssumedInformation);
10060 bool OnlyLeft =
false, OnlyRight =
false;
10061 if (
C && *
C && (*C)->isOneValue())
10063 else if (
C && *
C && (*C)->isNullValue())
10066 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10067 SetTy LHSAAPVS, RHSAAPVS;
10070 LHSContainsUndef,
false))
10071 return indicatePessimisticFixpoint();
10075 RHSContainsUndef,
false))
10076 return indicatePessimisticFixpoint();
10078 if (OnlyLeft || OnlyRight) {
10080 auto *OpAA = OnlyLeft ? &LHSAAPVS : &RHSAAPVS;
10081 auto Undef = OnlyLeft ? LHSContainsUndef : RHSContainsUndef;
10084 unionAssumedWithUndef();
10086 for (
const auto &It : *OpAA)
10090 }
else if (LHSContainsUndef && RHSContainsUndef) {
10092 unionAssumedWithUndef();
10094 for (
const auto &It : LHSAAPVS)
10096 for (
const auto &It : RHSAAPVS)
10099 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10100 : ChangeStatus::CHANGED;
10103 ChangeStatus updateWithCastInst(Attributor &
A, CastInst *CI) {
10104 auto AssumedBefore = getAssumed();
10106 return indicatePessimisticFixpoint();
10111 bool SrcContainsUndef =
false;
10114 SrcContainsUndef,
false))
10115 return indicatePessimisticFixpoint();
10117 if (SrcContainsUndef)
10118 unionAssumedWithUndef();
10120 for (
const APInt &S : SrcPVS) {
10121 APInt
T = calculateCastInst(CI, S, ResultBitWidth);
10125 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10126 : ChangeStatus::CHANGED;
10129 ChangeStatus updateWithBinaryOperator(Attributor &
A, BinaryOperator *BinOp) {
10130 auto AssumedBefore = getAssumed();
10134 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10135 SetTy LHSAAPVS, RHSAAPVS;
10137 LHSContainsUndef,
false) ||
10139 RHSContainsUndef,
false))
10140 return indicatePessimisticFixpoint();
10145 if (LHSContainsUndef && RHSContainsUndef) {
10146 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))
10147 return indicatePessimisticFixpoint();
10148 }
else if (LHSContainsUndef) {
10149 for (
const APInt &R : RHSAAPVS) {
10150 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))
10151 return indicatePessimisticFixpoint();
10153 }
else if (RHSContainsUndef) {
10154 for (
const APInt &L : LHSAAPVS) {
10155 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
10156 return indicatePessimisticFixpoint();
10159 for (
const APInt &L : LHSAAPVS) {
10160 for (
const APInt &R : RHSAAPVS) {
10161 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
10162 return indicatePessimisticFixpoint();
10166 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10167 : ChangeStatus::CHANGED;
10170 ChangeStatus updateWithInstruction(Attributor &
A, Instruction *Inst) {
10171 auto AssumedBefore = getAssumed();
10173 bool ContainsUndef;
10175 ContainsUndef,
true))
10176 return indicatePessimisticFixpoint();
10177 if (ContainsUndef) {
10178 unionAssumedWithUndef();
10180 for (
const auto &It : Incoming)
10183 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10184 : ChangeStatus::CHANGED;
10189 Value &
V = getAssociatedValue();
10193 return updateWithICmpInst(
A, ICI);
10196 return updateWithSelectInst(
A, SI);
10199 return updateWithCastInst(
A, CI);
10202 return updateWithBinaryOperator(
A, BinOp);
10205 return updateWithInstruction(
A,
I);
10207 return indicatePessimisticFixpoint();
10211 void trackStatistics()
const override {
10216struct AAPotentialConstantValuesFunction : AAPotentialConstantValuesImpl {
10217 AAPotentialConstantValuesFunction(
const IRPosition &IRP, Attributor &
A)
10218 : AAPotentialConstantValuesImpl(IRP,
A) {}
10223 "AAPotentialConstantValues(Function|CallSite)::updateImpl will "
10228 void trackStatistics()
const override {
10233struct AAPotentialConstantValuesCallSite : AAPotentialConstantValuesFunction {
10234 AAPotentialConstantValuesCallSite(
const IRPosition &IRP, Attributor &
A)
10235 : AAPotentialConstantValuesFunction(IRP,
A) {}
10238 void trackStatistics()
const override {
10243struct AAPotentialConstantValuesCallSiteReturned
10244 : AACalleeToCallSite<AAPotentialConstantValues,
10245 AAPotentialConstantValuesImpl> {
10246 AAPotentialConstantValuesCallSiteReturned(
const IRPosition &IRP,
10248 : AACalleeToCallSite<AAPotentialConstantValues,
10249 AAPotentialConstantValuesImpl>(IRP,
A) {}
10252 void trackStatistics()
const override {
10257struct AAPotentialConstantValuesCallSiteArgument
10258 : AAPotentialConstantValuesFloating {
10259 AAPotentialConstantValuesCallSiteArgument(
const IRPosition &IRP,
10261 : AAPotentialConstantValuesFloating(IRP,
A) {}
10265 AAPotentialConstantValuesImpl::initialize(
A);
10266 if (isAtFixpoint())
10269 Value &
V = getAssociatedValue();
10272 unionAssumed(
C->getValue());
10273 indicateOptimisticFixpoint();
10278 unionAssumedWithUndef();
10279 indicateOptimisticFixpoint();
10286 Value &
V = getAssociatedValue();
10287 auto AssumedBefore = getAssumed();
10288 auto *AA =
A.getAAFor<AAPotentialConstantValues>(
10291 return indicatePessimisticFixpoint();
10292 const auto &S = AA->getAssumed();
10294 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10295 : ChangeStatus::CHANGED;
10299 void trackStatistics()
const override {
10308 bool IgnoreSubsumingPositions) {
10309 assert(ImpliedAttributeKind == Attribute::NoUndef &&
10310 "Unexpected attribute kind");
10311 if (
A.hasAttr(IRP, {Attribute::NoUndef}, IgnoreSubsumingPositions,
10312 Attribute::NoUndef))
10332 Value &V = getAssociatedValue();
10334 indicatePessimisticFixpoint();
10335 assert(!isImpliedByIR(
A, getIRPosition(), Attribute::NoUndef));
10339 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10340 AANoUndef::StateType &State) {
10341 const Value *UseV =
U->get();
10342 const DominatorTree *DT =
nullptr;
10343 AssumptionCache *AC =
nullptr;
10344 InformationCache &InfoCache =
A.getInfoCache();
10345 if (Function *
F = getAnchorScope()) {
10350 bool TrackUse =
false;
10359 const std::string getAsStr(Attributor *
A)
const override {
10360 return getAssumed() ?
"noundef" :
"may-undef-or-poison";
10367 bool UsedAssumedInformation =
false;
10368 if (
A.isAssumedDead(getIRPosition(),
nullptr,
nullptr,
10369 UsedAssumedInformation))
10370 return ChangeStatus::UNCHANGED;
10374 if (!
A.getAssumedSimplified(getIRPosition(), *
this, UsedAssumedInformation,
10377 return ChangeStatus::UNCHANGED;
10378 return AANoUndef::manifest(
A);
10382struct AANoUndefFloating :
public AANoUndefImpl {
10383 AANoUndefFloating(
const IRPosition &IRP, Attributor &
A)
10384 : AANoUndefImpl(IRP,
A) {}
10388 AANoUndefImpl::initialize(
A);
10389 if (!getState().isAtFixpoint() && getAnchorScope() &&
10390 !getAnchorScope()->isDeclaration())
10391 if (Instruction *CtxI = getCtxI())
10392 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10397 auto VisitValueCB = [&](
const IRPosition &IRP) ->
bool {
10398 bool IsKnownNoUndef;
10400 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoUndef);
10404 bool UsedAssumedInformation =
false;
10405 Value *AssociatedValue = &getAssociatedValue();
10407 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10412 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
10420 if (AVIRP == getIRPosition() || !VisitValueCB(AVIRP))
10421 return indicatePessimisticFixpoint();
10422 return ChangeStatus::UNCHANGED;
10425 for (
const auto &VAC : Values)
10427 return indicatePessimisticFixpoint();
10429 return ChangeStatus::UNCHANGED;
10436struct AANoUndefReturned final
10437 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl> {
10438 AANoUndefReturned(
const IRPosition &IRP, Attributor &
A)
10439 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10445struct AANoUndefArgument final
10446 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl> {
10447 AANoUndefArgument(
const IRPosition &IRP, Attributor &
A)
10448 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10454struct AANoUndefCallSiteArgument final : AANoUndefFloating {
10455 AANoUndefCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10456 : AANoUndefFloating(IRP,
A) {}
10462struct AANoUndefCallSiteReturned final
10463 : AACalleeToCallSite<AANoUndef, AANoUndefImpl> {
10464 AANoUndefCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10465 : AACalleeToCallSite<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10473struct AANoFPClassImpl : AANoFPClass {
10474 AANoFPClassImpl(
const IRPosition &IRP, Attributor &
A) : AANoFPClass(IRP,
A) {}
10477 const IRPosition &IRP = getIRPosition();
10481 indicateOptimisticFixpoint();
10486 A.getAttrs(getIRPosition(), {Attribute::NoFPClass},
Attrs,
false);
10487 for (
const auto &Attr : Attrs) {
10494 const DataLayout &
DL =
A.getDataLayout();
10495 InformationCache &InfoCache =
A.getInfoCache();
10497 const DominatorTree *DT =
nullptr;
10498 AssumptionCache *AC =
nullptr;
10499 const TargetLibraryInfo *TLI =
nullptr;
10503 if (!
F->isDeclaration()) {
10510 SimplifyQuery Q(
DL, TLI, DT, AC, CtxI);
10517 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10521 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10522 AANoFPClass::StateType &State) {
10533 if (
auto *NoFPAA =
A.getAAFor<AANoFPClass>(*
this, IRP, DepClassTy::NONE))
10534 State.addKnownBits(NoFPAA->getState().getKnown());
10538 const std::string getAsStr(Attributor *
A)
const override {
10539 std::string
Result =
"nofpclass";
10540 raw_string_ostream OS(Result);
10541 OS << getKnownNoFPClass() <<
'/' << getAssumedNoFPClass();
10545 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
10546 SmallVectorImpl<Attribute> &Attrs)
const override {
10547 Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));
10551struct AANoFPClassFloating :
public AANoFPClassImpl {
10552 AANoFPClassFloating(
const IRPosition &IRP, Attributor &
A)
10553 : AANoFPClassImpl(IRP,
A) {}
10558 bool UsedAssumedInformation =
false;
10559 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10561 Values.
push_back({getAssociatedValue(), getCtxI()});
10567 DepClassTy::REQUIRED);
10568 if (!AA ||
this == AA) {
10569 T.indicatePessimisticFixpoint();
10571 const AANoFPClass::StateType &S =
10572 static_cast<const AANoFPClass::StateType &
>(AA->
getState());
10575 return T.isValidState();
10578 for (
const auto &VAC : Values)
10580 return indicatePessimisticFixpoint();
10586 void trackStatistics()
const override {
10591struct AANoFPClassReturned final
10592 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10593 AANoFPClassImpl::StateType, false,
10594 Attribute::None, false> {
10595 AANoFPClassReturned(
const IRPosition &IRP, Attributor &
A)
10596 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10597 AANoFPClassImpl::StateType,
false,
10601 void trackStatistics()
const override {
10606struct AANoFPClassArgument final
10607 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {
10608 AANoFPClassArgument(
const IRPosition &IRP, Attributor &
A)
10609 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10615struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {
10616 AANoFPClassCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10617 : AANoFPClassFloating(IRP,
A) {}
10620 void trackStatistics()
const override {
10625struct AANoFPClassCallSiteReturned final
10626 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl> {
10627 AANoFPClassCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10628 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10631 void trackStatistics()
const override {
10636struct AACallEdgesImpl :
public AACallEdges {
10637 AACallEdgesImpl(
const IRPosition &IRP, Attributor &
A) : AACallEdges(IRP,
A) {}
10639 const SetVector<Function *> &getOptimisticEdges()
const override {
10640 return CalledFunctions;
10643 bool hasUnknownCallee()
const override {
return HasUnknownCallee; }
10645 bool hasNonAsmUnknownCallee()
const override {
10646 return HasUnknownCalleeNonAsm;
10649 const std::string getAsStr(Attributor *
A)
const override {
10650 return "CallEdges[" + std::to_string(HasUnknownCallee) +
"," +
10651 std::to_string(CalledFunctions.size()) +
"]";
10654 void trackStatistics()
const override {}
10657 void addCalledFunction(Function *Fn,
ChangeStatus &Change) {
10658 if (CalledFunctions.insert(Fn)) {
10659 Change = ChangeStatus::CHANGED;
10665 void setHasUnknownCallee(
bool NonAsm,
ChangeStatus &Change) {
10666 if (!HasUnknownCallee)
10667 Change = ChangeStatus::CHANGED;
10668 if (NonAsm && !HasUnknownCalleeNonAsm)
10669 Change = ChangeStatus::CHANGED;
10670 HasUnknownCalleeNonAsm |= NonAsm;
10671 HasUnknownCallee =
true;
10676 SetVector<Function *> CalledFunctions;
10679 bool HasUnknownCallee =
false;
10682 bool HasUnknownCalleeNonAsm =
false;
10685struct AACallEdgesCallSite :
public AACallEdgesImpl {
10686 AACallEdgesCallSite(
const IRPosition &IRP, Attributor &
A)
10687 : AACallEdgesImpl(IRP,
A) {}
10694 addCalledFunction(Fn, Change);
10696 LLVM_DEBUG(
dbgs() <<
"[AACallEdges] Unrecognized value: " << V <<
"\n");
10697 setHasUnknownCallee(
true, Change);
10708 VisitValue(*V, CtxI);
10712 bool UsedAssumedInformation =
false;
10718 for (
auto &VAC : Values)
10725 if (
IA->hasSideEffects() &&
10728 setHasUnknownCallee(
false, Change);
10734 if (
auto *IndirectCallAA =
A.getAAFor<AAIndirectCallInfo>(
10735 *
this, getIRPosition(), DepClassTy::OPTIONAL))
10736 if (IndirectCallAA->foreachCallee(
10737 [&](Function *Fn) { return VisitValue(*Fn, CB); }))
10746 for (
const Use *U : CallbackUses)
10747 ProcessCalledOperand(
U->get(), CB);
10753struct AACallEdgesFunction :
public AACallEdgesImpl {
10754 AACallEdgesFunction(
const IRPosition &IRP, Attributor &
A)
10755 : AACallEdgesImpl(IRP,
A) {}
10764 auto *CBEdges =
A.getAAFor<AACallEdges>(
10768 if (CBEdges->hasNonAsmUnknownCallee())
10769 setHasUnknownCallee(
true, Change);
10770 if (CBEdges->hasUnknownCallee())
10771 setHasUnknownCallee(
false, Change);
10773 for (Function *
F : CBEdges->getOptimisticEdges())
10774 addCalledFunction(
F, Change);
10780 bool UsedAssumedInformation =
false;
10781 if (!
A.checkForAllCallLikeInstructions(ProcessCallInst, *
this,
10782 UsedAssumedInformation,
10786 setHasUnknownCallee(
true, Change);
10795struct AAInterFnReachabilityFunction
10796 :
public CachedReachabilityAA<AAInterFnReachability, Function> {
10797 using Base = CachedReachabilityAA<AAInterFnReachability, Function>;
10798 AAInterFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
10801 bool instructionCanReach(
10802 Attributor &
A,
const Instruction &From,
const Function &To,
10805 auto *NonConstThis =
const_cast<AAInterFnReachabilityFunction *
>(
this);
10807 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
10808 RQITy::Reachable
Result;
10809 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
10810 return NonConstThis->isReachableImpl(
A, StackRQI,
10812 return Result == RQITy::Reachable::Yes;
10816 bool IsTemporaryRQI)
override {
10818 &RQI.From->getFunction()->getEntryBlock().front();
10819 if (EntryI != RQI.From &&
10820 !instructionCanReach(
A, *EntryI, *RQI.To,
nullptr))
10821 return rememberResult(
A, RQITy::Reachable::No, RQI,
false,
10824 auto CheckReachableCallBase = [&](CallBase *CB) {
10825 auto *CBEdges =
A.getAAFor<AACallEdges>(
10827 if (!CBEdges || !CBEdges->getState().isValidState())
10830 if (CBEdges->hasUnknownCallee())
10833 for (Function *Fn : CBEdges->getOptimisticEdges()) {
10844 if (Fn == getAnchorScope()) {
10845 if (EntryI == RQI.From)
10850 const AAInterFnReachability *InterFnReachability =
10852 DepClassTy::OPTIONAL);
10855 if (!InterFnReachability ||
10863 const auto *IntraFnReachability =
A.getAAFor<AAIntraFnReachability>(
10865 DepClassTy::OPTIONAL);
10873 return IntraFnReachability && !IntraFnReachability->isAssumedReachable(
10874 A, *RQI.From, CBInst, RQI.ExclusionSet);
10877 bool UsedExclusionSet =
true;
10878 bool UsedAssumedInformation =
false;
10879 if (!
A.checkForAllCallLikeInstructions(CheckCallBase, *
this,
10880 UsedAssumedInformation,
10882 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
10885 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
10889 void trackStatistics()
const override {}
10893template <
typename AAType>
10894static std::optional<Constant *>
10897 if (!Ty.isIntegerTy())
10905 std::optional<Constant *> COpt =
AA->getAssumedConstant(
A);
10907 if (!COpt.has_value()) {
10909 return std::nullopt;
10911 if (
auto *
C = *COpt) {
10922 std::optional<Value *> V;
10923 for (
auto &It : Values) {
10925 if (V.has_value() && !*V)
10928 if (!V.has_value())
10942 if (
A.hasSimplificationCallback(getIRPosition())) {
10943 indicatePessimisticFixpoint();
10946 Value *Stripped = getAssociatedValue().stripPointerCasts();
10948 addValue(
A, getState(), *Stripped, getCtxI(),
AA::AnyScope,
10950 indicateOptimisticFixpoint();
10953 AAPotentialValues::initialize(
A);
10957 const std::string getAsStr(Attributor *
A)
const override {
10959 llvm::raw_string_ostream OS(Str);
10964 template <
typename AAType>
10965 static std::optional<Value *> askOtherAA(Attributor &
A,
10966 const AbstractAttribute &AA,
10967 const IRPosition &IRP,
Type &Ty) {
10972 return std::nullopt;
10979 virtual void addValue(Attributor &
A, StateType &State,
Value &V,
10981 Function *AnchorScope)
const {
10985 for (
const auto &U : CB->
args()) {
10995 Type &Ty = *getAssociatedType();
10996 std::optional<Value *> SimpleV =
10997 askOtherAA<AAValueConstantRange>(
A, *
this, ValIRP, Ty);
10998 if (SimpleV.has_value() && !*SimpleV) {
10999 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
11000 *
this, ValIRP, DepClassTy::OPTIONAL);
11001 if (PotentialConstantsAA && PotentialConstantsAA->isValidState()) {
11002 for (
const auto &It : PotentialConstantsAA->getAssumedSet())
11003 State.unionAssumed({{*ConstantInt::get(&Ty, It),
nullptr}, S});
11004 if (PotentialConstantsAA->undefIsContained())
11009 if (!SimpleV.has_value())
11021 State.unionAssumed({{*VPtr, CtxI}, S});
11027 AA::ValueAndContext
I;
11031 return II.I ==
I &&
II.S == S;
11034 return std::tie(
I, S) < std::tie(
II.I,
II.S);
11038 bool recurseForValue(Attributor &
A,
const IRPosition &IRP,
AA::ValueScope S) {
11039 SmallMapVector<AA::ValueAndContext, int, 8> ValueScopeMap;
11044 bool UsedAssumedInformation =
false;
11046 if (!
A.getAssumedSimplifiedValues(IRP,
this, Values, CS,
11047 UsedAssumedInformation))
11050 for (
auto &It : Values)
11051 ValueScopeMap[It] += CS;
11053 for (
auto &It : ValueScopeMap)
11054 addValue(
A, getState(), *It.first.getValue(), It.first.getCtxI(),
11060 void giveUpOnIntraprocedural(Attributor &
A) {
11061 auto NewS = StateType::getBestState(getState());
11062 for (
const auto &It : getAssumedSet()) {
11065 addValue(
A, NewS, *It.first.getValue(), It.first.getCtxI(),
11068 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11076 getState() = StateType::getBestState(getState());
11077 getState().unionAssumed({{getAssociatedValue(), getCtxI()},
AA::AnyScope});
11078 AAPotentialValues::indicateOptimisticFixpoint();
11079 return ChangeStatus::CHANGED;
11084 return indicatePessimisticFixpoint();
11092 if (!getAssumedSimplifiedValues(
A, Values, S))
11094 Value &OldV = getAssociatedValue();
11097 Value *NewV = getSingleValue(
A, *
this, getIRPosition(), Values);
11098 if (!NewV || NewV == &OldV)
11103 if (
A.changeAfterManifest(getIRPosition(), *NewV))
11104 return ChangeStatus::CHANGED;
11106 return ChangeStatus::UNCHANGED;
11109 bool getAssumedSimplifiedValues(
11110 Attributor &
A, SmallVectorImpl<AA::ValueAndContext> &Values,
11111 AA::ValueScope S,
bool RecurseForSelectAndPHI =
false)
const override {
11112 if (!isValidState())
11114 bool UsedAssumedInformation =
false;
11115 for (
const auto &It : getAssumedSet())
11116 if (It.second & S) {
11117 if (RecurseForSelectAndPHI && (
isa<PHINode>(It.first.getValue()) ||
11119 if (
A.getAssumedSimplifiedValues(
11121 this, Values, S, UsedAssumedInformation))
11126 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11131struct AAPotentialValuesFloating : AAPotentialValuesImpl {
11132 AAPotentialValuesFloating(
const IRPosition &IRP, Attributor &
A)
11133 : AAPotentialValuesImpl(IRP,
A) {}
11137 auto AssumedBefore = getAssumed();
11139 genericValueTraversal(
A, &getAssociatedValue());
11141 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11142 : ChangeStatus::CHANGED;
11146 struct LivenessInfo {
11147 const AAIsDead *LivenessAA =
nullptr;
11148 bool AnyDead =
false;
11158 SmallVectorImpl<ItemInfo> &Worklist) {
11161 bool UsedAssumedInformation =
false;
11163 auto GetSimplifiedValues = [&](
Value &
V,
11165 if (!
A.getAssumedSimplifiedValues(
11169 Values.
push_back(AA::ValueAndContext{
V,
II.I.getCtxI()});
11171 return Values.
empty();
11173 if (GetSimplifiedValues(*
LHS, LHSValues))
11175 if (GetSimplifiedValues(*
RHS, RHSValues))
11180 InformationCache &InfoCache =
A.getInfoCache();
11187 F ?
A.getInfoCache().getTargetLibraryInfoForFunction(*
F) :
nullptr;
11192 const DataLayout &
DL =
A.getDataLayout();
11193 SimplifyQuery Q(
DL, TLI, DT, AC, CmpI);
11195 auto CheckPair = [&](
Value &LHSV,
Value &RHSV) {
11198 nullptr,
II.S, getAnchorScope());
11204 if (&LHSV == &RHSV &&
11206 Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
11208 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11215 if (TypedLHS && TypedRHS) {
11217 if (NewV && NewV != &Cmp) {
11218 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11230 if (!LHSIsNull && !RHSIsNull)
11236 assert((LHSIsNull || RHSIsNull) &&
11237 "Expected nullptr versus non-nullptr comparison at this point");
11240 unsigned PtrIdx = LHSIsNull;
11241 bool IsKnownNonNull;
11244 DepClassTy::REQUIRED, IsKnownNonNull);
11245 if (!IsAssumedNonNull)
11251 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11256 for (
auto &LHSValue : LHSValues)
11257 for (
auto &RHSValue : RHSValues)
11258 if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))
11263 bool handleSelectInst(Attributor &
A, SelectInst &SI, ItemInfo
II,
11264 SmallVectorImpl<ItemInfo> &Worklist) {
11266 bool UsedAssumedInformation =
false;
11268 std::optional<Constant *>
C =
11269 A.getAssumedConstant(*
SI.getCondition(), *
this, UsedAssumedInformation);
11270 bool NoValueYet = !
C.has_value();
11278 }
else if (&SI == &getAssociatedValue()) {
11283 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11285 if (!SimpleV.has_value())
11288 addValue(
A, getState(), **SimpleV, CtxI,
II.S, getAnchorScope());
11296 bool handleLoadInst(Attributor &
A, LoadInst &LI, ItemInfo
II,
11297 SmallVectorImpl<ItemInfo> &Worklist) {
11298 SmallSetVector<Value *, 4> PotentialCopies;
11299 SmallSetVector<Instruction *, 4> PotentialValueOrigins;
11300 bool UsedAssumedInformation =
false;
11302 PotentialValueOrigins, *
this,
11303 UsedAssumedInformation,
11305 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Failed to get potentially "
11306 "loaded values for load instruction "
11314 InformationCache &InfoCache =
A.getInfoCache();
11316 if (!
llvm::all_of(PotentialValueOrigins, [&](Instruction *
I) {
11320 return A.isAssumedDead(
SI->getOperandUse(0),
this,
11322 UsedAssumedInformation,
11324 return A.isAssumedDead(*
I,
this,
nullptr,
11325 UsedAssumedInformation,
11328 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Load is onl used by assumes "
11329 "and we cannot delete all the stores: "
11340 bool AllLocal = ScopeIsLocal;
11345 if (!DynamicallyUnique) {
11346 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Not all potentially loaded "
11347 "values are dynamically unique: "
11352 for (
auto *PotentialCopy : PotentialCopies) {
11354 Worklist.
push_back({{*PotentialCopy, CtxI},
II.S});
11359 if (!AllLocal && ScopeIsLocal)
11364 bool handlePHINode(
11365 Attributor &
A, PHINode &
PHI, ItemInfo
II,
11366 SmallVectorImpl<ItemInfo> &Worklist,
11367 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11368 auto GetLivenessInfo = [&](
const Function &
F) -> LivenessInfo & {
11369 LivenessInfo &LI = LivenessAAs[&
F];
11370 if (!LI.LivenessAA)
11376 if (&
PHI == &getAssociatedValue()) {
11377 LivenessInfo &LI = GetLivenessInfo(*
PHI.getFunction());
11379 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
11380 *
PHI.getFunction());
11384 for (
unsigned u = 0, e =
PHI.getNumIncomingValues(); u < e; u++) {
11386 if (LI.LivenessAA &&
11387 LI.LivenessAA->isEdgeDead(IncomingBB,
PHI.getParent())) {
11406 bool UsedAssumedInformation =
false;
11407 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11409 if (!SimpleV.has_value())
11413 addValue(
A, getState(), **SimpleV, &
PHI,
II.S, getAnchorScope());
11420 bool handleGenericInst(Attributor &
A, Instruction &
I, ItemInfo
II,
11421 SmallVectorImpl<ItemInfo> &Worklist) {
11422 bool SomeSimplified =
false;
11423 bool UsedAssumedInformation =
false;
11425 SmallVector<Value *, 8> NewOps(
I.getNumOperands());
11428 const auto &SimplifiedOp =
A.getAssumedSimplified(
11433 if (!SimplifiedOp.has_value())
11437 NewOps[Idx] = *SimplifiedOp;
11441 SomeSimplified |= (NewOps[Idx] !=
Op);
11447 if (!SomeSimplified)
11450 InformationCache &InfoCache =
A.getInfoCache();
11454 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
11457 const DataLayout &
DL =
I.getDataLayout();
11458 SimplifyQuery Q(
DL, TLI, DT, AC, &
I);
11460 if (!NewV || NewV == &
I)
11463 LLVM_DEBUG(
dbgs() <<
"Generic inst " <<
I <<
" assumed simplified to "
11470 Attributor &
A, Instruction &
I, ItemInfo
II,
11471 SmallVectorImpl<ItemInfo> &Worklist,
11472 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11475 CI->getPredicate(),
II, Worklist);
11477 switch (
I.getOpcode()) {
11478 case Instruction::Select:
11480 case Instruction::PHI:
11482 case Instruction::Load:
11485 return handleGenericInst(
A,
I,
II, Worklist);
11490 void genericValueTraversal(Attributor &
A,
Value *InitialV) {
11491 SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;
11493 SmallSet<ItemInfo, 16> Visited;
11512 LLVM_DEBUG(
dbgs() <<
"Generic value traversal reached iteration limit: "
11513 << Iteration <<
"!\n");
11514 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11520 Value *NewV =
nullptr;
11521 if (
V->getType()->isPointerTy()) {
11527 for (Argument &Arg :
Callee->args())
11534 if (NewV && NewV != V) {
11535 Worklist.
push_back({{*NewV, CtxI}, S});
11549 if (V == InitialV && CtxI == getCtxI()) {
11550 indicatePessimisticFixpoint();
11554 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11555 }
while (!Worklist.
empty());
11559 for (
auto &It : LivenessAAs)
11560 if (It.second.AnyDead)
11561 A.recordDependence(*It.second.LivenessAA, *
this, DepClassTy::OPTIONAL);
11565 void trackStatistics()
const override {
11570struct AAPotentialValuesArgument final : AAPotentialValuesImpl {
11571 using Base = AAPotentialValuesImpl;
11572 AAPotentialValuesArgument(
const IRPosition &IRP, Attributor &
A)
11579 indicatePessimisticFixpoint();
11584 auto AssumedBefore = getAssumed();
11586 unsigned ArgNo = getCalleeArgNo();
11588 bool UsedAssumedInformation =
false;
11590 auto CallSitePred = [&](AbstractCallSite ACS) {
11592 if (CSArgIRP.getPositionKind() == IRP_INVALID)
11595 if (!
A.getAssumedSimplifiedValues(CSArgIRP,
this, Values,
11597 UsedAssumedInformation))
11600 return isValidState();
11603 if (!
A.checkForAllCallSites(CallSitePred, *
this,
11605 UsedAssumedInformation))
11606 return indicatePessimisticFixpoint();
11608 Function *Fn = getAssociatedFunction();
11609 bool AnyNonLocal =
false;
11610 for (
auto &It : Values) {
11612 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11617 return indicatePessimisticFixpoint();
11621 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11627 AnyNonLocal =
true;
11629 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11631 giveUpOnIntraprocedural(
A);
11633 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11634 : ChangeStatus::CHANGED;
11638 void trackStatistics()
const override {
11643struct AAPotentialValuesReturned :
public AAPotentialValuesFloating {
11644 using Base = AAPotentialValuesFloating;
11645 AAPotentialValuesReturned(
const IRPosition &IRP, Attributor &
A)
11651 if (!
F ||
F->isDeclaration() ||
F->getReturnType()->isVoidTy()) {
11652 indicatePessimisticFixpoint();
11656 for (Argument &Arg :
F->args())
11659 ReturnedArg = &Arg;
11662 if (!
A.isFunctionIPOAmendable(*
F) ||
11663 A.hasSimplificationCallback(getIRPosition())) {
11665 indicatePessimisticFixpoint();
11667 indicateOptimisticFixpoint();
11673 auto AssumedBefore = getAssumed();
11674 bool UsedAssumedInformation =
false;
11677 Function *AnchorScope = getAnchorScope();
11683 UsedAssumedInformation,
11689 bool AllInterAreIntra =
false;
11692 llvm::all_of(Values, [&](
const AA::ValueAndContext &VAC) {
11696 for (
const AA::ValueAndContext &VAC : Values) {
11697 addValue(
A, getState(), *VAC.
getValue(),
11701 if (AllInterAreIntra)
11708 HandleReturnedValue(*ReturnedArg,
nullptr,
true);
11711 bool AddValues =
true;
11714 addValue(
A, getState(), *RetI.getOperand(0), &RetI,
AA::AnyScope,
11718 return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);
11721 if (!
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11722 UsedAssumedInformation,
11724 return indicatePessimisticFixpoint();
11727 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11728 : ChangeStatus::CHANGED;
11733 return ChangeStatus::UNCHANGED;
11735 if (!getAssumedSimplifiedValues(
A, Values, AA::ValueScope::Intraprocedural,
11737 return ChangeStatus::UNCHANGED;
11738 Value *NewVal = getSingleValue(
A, *
this, getIRPosition(), Values);
11740 return ChangeStatus::UNCHANGED;
11745 "Number of function with unique return");
11748 {Attribute::get(Arg->
getContext(), Attribute::Returned)});
11753 Value *RetOp = RetI.getOperand(0);
11757 if (
A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))
11758 Changed = ChangeStatus::CHANGED;
11761 bool UsedAssumedInformation =
false;
11762 (void)
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11763 UsedAssumedInformation,
11769 return AAPotentialValues::indicatePessimisticFixpoint();
11773 void trackStatistics()
const override{
11780struct AAPotentialValuesFunction : AAPotentialValuesImpl {
11781 AAPotentialValuesFunction(
const IRPosition &IRP, Attributor &
A)
11782 : AAPotentialValuesImpl(IRP,
A) {}
11791 void trackStatistics()
const override {
11796struct AAPotentialValuesCallSite : AAPotentialValuesFunction {
11797 AAPotentialValuesCallSite(
const IRPosition &IRP, Attributor &
A)
11798 : AAPotentialValuesFunction(IRP,
A) {}
11801 void trackStatistics()
const override {
11806struct AAPotentialValuesCallSiteReturned : AAPotentialValuesImpl {
11807 AAPotentialValuesCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
11808 : AAPotentialValuesImpl(IRP,
A) {}
11812 auto AssumedBefore = getAssumed();
11816 return indicatePessimisticFixpoint();
11818 bool UsedAssumedInformation =
false;
11822 UsedAssumedInformation))
11823 return indicatePessimisticFixpoint();
11830 Values, S, UsedAssumedInformation))
11833 for (
auto &It : Values) {
11834 Value *
V = It.getValue();
11835 std::optional<Value *> CallerV =
A.translateArgumentToCallSiteContent(
11836 V, *CB, *
this, UsedAssumedInformation);
11837 if (!CallerV.has_value()) {
11841 V = *CallerV ? *CallerV :
V;
11847 giveUpOnIntraprocedural(
A);
11850 addValue(
A, getState(), *V, CB, S, getAnchorScope());
11855 return indicatePessimisticFixpoint();
11857 return indicatePessimisticFixpoint();
11858 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11859 : ChangeStatus::CHANGED;
11863 return AAPotentialValues::indicatePessimisticFixpoint();
11867 void trackStatistics()
const override {
11872struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
11873 AAPotentialValuesCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
11874 : AAPotentialValuesFloating(IRP,
A) {}
11877 void trackStatistics()
const override {
11885struct AAAssumptionInfoImpl :
public AAAssumptionInfo {
11886 AAAssumptionInfoImpl(
const IRPosition &IRP, Attributor &
A,
11887 const DenseSet<StringRef> &Known)
11888 : AAAssumptionInfo(IRP,
A, Known) {}
11893 if (getKnown().isUniversal())
11894 return ChangeStatus::UNCHANGED;
11896 const IRPosition &IRP = getIRPosition();
11898 getAssumed().getSet().
end());
11900 return A.manifestAttrs(IRP,
11907 bool hasAssumption(
const StringRef Assumption)
const override {
11908 return isValidState() && setContains(Assumption);
11912 const std::string getAsStr(Attributor *
A)
const override {
11913 const SetContents &Known = getKnown();
11914 const SetContents &Assumed = getAssumed();
11918 const std::string KnownStr =
llvm::join(Set,
",");
11920 std::string AssumedStr =
"Universal";
11921 if (!Assumed.isUniversal()) {
11922 Set.assign(Assumed.getSet().begin(), Assumed.getSet().end());
11925 return "Known [" + KnownStr +
"]," +
" Assumed [" + AssumedStr +
"]";
11940struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {
11941 AAAssumptionInfoFunction(
const IRPosition &IRP, Attributor &
A)
11942 : AAAssumptionInfoImpl(IRP,
A,
11949 auto CallSitePred = [&](AbstractCallSite ACS) {
11950 const auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
11952 DepClassTy::REQUIRED);
11956 Changed |= getIntersection(AssumptionAA->getAssumed());
11957 return !getAssumed().empty() || !getKnown().empty();
11960 bool UsedAssumedInformation =
false;
11965 if (!
A.checkForAllCallSites(CallSitePred, *
this,
true,
11966 UsedAssumedInformation))
11967 return indicatePessimisticFixpoint();
11969 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11972 void trackStatistics()
const override {}
11976struct AAAssumptionInfoCallSite final : AAAssumptionInfoImpl {
11978 AAAssumptionInfoCallSite(
const IRPosition &IRP, Attributor &
A)
11979 : AAAssumptionInfoImpl(IRP,
A, getInitialAssumptions(IRP)) {}
11984 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11990 auto *AssumptionAA =
11991 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11993 return indicatePessimisticFixpoint();
11994 bool Changed = getIntersection(AssumptionAA->getAssumed());
11995 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11999 void trackStatistics()
const override {}
12004 DenseSet<StringRef> getInitialAssumptions(
const IRPosition &IRP) {
12011 return Assumptions;
12026struct AAUnderlyingObjectsImpl
12032 const std::string getAsStr(
Attributor *
A)
const override {
12033 if (!isValidState())
12034 return "<invalid>";
12037 OS <<
"underlying objects: inter " << InterAssumedUnderlyingObjects.size()
12038 <<
" objects, intra " << IntraAssumedUnderlyingObjects.size()
12040 if (!InterAssumedUnderlyingObjects.empty()) {
12041 OS <<
"inter objects:\n";
12042 for (
auto *Obj : InterAssumedUnderlyingObjects)
12043 OS << *Obj <<
'\n';
12045 if (!IntraAssumedUnderlyingObjects.empty()) {
12046 OS <<
"intra objects:\n";
12047 for (
auto *Obj : IntraAssumedUnderlyingObjects)
12048 OS << *
Obj <<
'\n';
12054 void trackStatistics()
const override {}
12058 auto &Ptr = getAssociatedValue();
12060 bool UsedAssumedInformation =
false;
12061 auto DoUpdate = [&](SmallSetVector<Value *, 8> &UnderlyingObjects,
12063 SmallPtrSet<Value *, 8> SeenObjects;
12067 Scope, UsedAssumedInformation))
12068 return UnderlyingObjects.
insert(&Ptr);
12072 for (
unsigned I = 0;
I < Values.
size(); ++
I) {
12073 auto &VAC = Values[
I];
12076 if (!SeenObjects.
insert(UO ? UO : Obj).second)
12078 if (UO && UO != Obj) {
12084 const auto *OtherAA =
A.getAAFor<AAUnderlyingObjects>(
12086 auto Pred = [&](
Value &
V) {
12094 if (!OtherAA || !OtherAA->forallUnderlyingObjects(Pred, Scope))
12096 "The forall call should not return false at this position");
12102 Changed |= handleIndirect(
A, *Obj, UnderlyingObjects, Scope,
12103 UsedAssumedInformation);
12109 for (
unsigned u = 0, e =
PHI->getNumIncomingValues(); u < e; u++) {
12111 handleIndirect(
A, *
PHI->getIncomingValue(u), UnderlyingObjects,
12112 Scope, UsedAssumedInformation);
12126 if (!UsedAssumedInformation)
12127 indicateOptimisticFixpoint();
12128 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12131 bool forallUnderlyingObjects(
12132 function_ref<
bool(
Value &)> Pred,
12134 if (!isValidState())
12135 return Pred(getAssociatedValue());
12138 ? IntraAssumedUnderlyingObjects
12139 : InterAssumedUnderlyingObjects;
12140 for (
Value *Obj : AssumedUnderlyingObjects)
12150 bool handleIndirect(Attributor &
A,
Value &V,
12151 SmallSetVector<Value *, 8> &UnderlyingObjects,
12154 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
12156 auto Pred = [&](
Value &
V) {
12160 if (!AA || !AA->forallUnderlyingObjects(Pred, Scope))
12162 "The forall call should not return false at this position");
12168 SmallSetVector<Value *, 8> IntraAssumedUnderlyingObjects;
12170 SmallSetVector<Value *, 8> InterAssumedUnderlyingObjects;
12173struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl {
12174 AAUnderlyingObjectsFloating(
const IRPosition &IRP, Attributor &
A)
12175 : AAUnderlyingObjectsImpl(IRP,
A) {}
12178struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl {
12179 AAUnderlyingObjectsArgument(
const IRPosition &IRP, Attributor &
A)
12180 : AAUnderlyingObjectsImpl(IRP,
A) {}
12183struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl {
12184 AAUnderlyingObjectsCallSite(
const IRPosition &IRP, Attributor &
A)
12185 : AAUnderlyingObjectsImpl(IRP,
A) {}
12188struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl {
12189 AAUnderlyingObjectsCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12190 : AAUnderlyingObjectsImpl(IRP,
A) {}
12193struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl {
12194 AAUnderlyingObjectsReturned(
const IRPosition &IRP, Attributor &
A)
12195 : AAUnderlyingObjectsImpl(IRP,
A) {}
12198struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl {
12199 AAUnderlyingObjectsCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12200 : AAUnderlyingObjectsImpl(IRP,
A) {}
12203struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {
12204 AAUnderlyingObjectsFunction(
const IRPosition &IRP, Attributor &
A)
12205 : AAUnderlyingObjectsImpl(IRP,
A) {}
12211struct AAGlobalValueInfoFloating :
public AAGlobalValueInfo {
12212 AAGlobalValueInfoFloating(
const IRPosition &IRP, Attributor &
A)
12213 : AAGlobalValueInfo(IRP,
A) {}
12218 bool checkUse(Attributor &
A,
const Use &U,
bool &Follow,
12219 SmallVectorImpl<const Value *> &Worklist) {
12226 LLVM_DEBUG(
dbgs() <<
"[AAGlobalValueInfo] Check use: " << *
U.get() <<
" in "
12227 << *UInst <<
"\n");
12230 int Idx = &
Cmp->getOperandUse(0) == &
U;
12233 return U == &getAnchorValue();
12238 auto CallSitePred = [&](AbstractCallSite ACS) {
12239 Worklist.
push_back(ACS.getInstruction());
12242 bool UsedAssumedInformation =
false;
12244 if (!
A.checkForAllCallSites(CallSitePred, *UInst->
getFunction(),
12246 UsedAssumedInformation))
12264 if (!Fn || !
A.isFunctionIPOAmendable(*Fn))
12273 unsigned NumUsesBefore =
Uses.size();
12275 SmallPtrSet<const Value *, 8> Visited;
12279 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
12287 return checkUse(
A, U, Follow, Worklist);
12289 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
12290 Uses.insert(&OldU);
12294 while (!Worklist.
empty()) {
12296 if (!Visited.
insert(V).second)
12298 if (!
A.checkForAllUses(UsePred, *
this, *V,
12300 DepClassTy::OPTIONAL,
12301 true, EquivalentUseCB)) {
12302 return indicatePessimisticFixpoint();
12306 return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED
12307 : ChangeStatus::CHANGED;
12310 bool isPotentialUse(
const Use &U)
const override {
12311 return !isValidState() ||
Uses.contains(&U);
12316 return ChangeStatus::UNCHANGED;
12320 const std::string getAsStr(Attributor *
A)
const override {
12321 return "[" + std::to_string(
Uses.size()) +
" uses]";
12324 void trackStatistics()
const override {
12330 SmallPtrSet<const Use *, 8>
Uses;
12336struct AAIndirectCallInfoCallSite :
public AAIndirectCallInfo {
12337 AAIndirectCallInfoCallSite(
const IRPosition &IRP, Attributor &
A)
12338 : AAIndirectCallInfo(IRP,
A) {}
12342 auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);
12343 if (!MD && !
A.isClosedWorldModule())
12347 for (
const auto &
Op : MD->operands())
12349 PotentialCallees.insert(Callee);
12350 }
else if (
A.isClosedWorldModule()) {
12352 A.getInfoCache().getIndirectlyCallableFunctions(
A);
12353 PotentialCallees.insert_range(IndirectlyCallableFunctions);
12356 if (PotentialCallees.empty())
12357 indicateOptimisticFixpoint();
12365 SmallSetVector<Function *, 4> AssumedCalleesNow;
12366 bool AllCalleesKnownNow = AllCalleesKnown;
12368 auto CheckPotentialCalleeUse = [&](
Function &PotentialCallee,
12369 bool &UsedAssumedInformation) {
12370 const auto *GIAA =
A.getAAFor<AAGlobalValueInfo>(
12372 if (!GIAA || GIAA->isPotentialUse(CalleeUse))
12374 UsedAssumedInformation = !GIAA->isAtFixpoint();
12378 auto AddPotentialCallees = [&]() {
12379 for (
auto *PotentialCallee : PotentialCallees) {
12380 bool UsedAssumedInformation =
false;
12381 if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))
12382 AssumedCalleesNow.
insert(PotentialCallee);
12388 bool UsedAssumedInformation =
false;
12391 AA::ValueScope::AnyScope,
12392 UsedAssumedInformation)) {
12393 if (PotentialCallees.empty())
12394 return indicatePessimisticFixpoint();
12395 AddPotentialCallees();
12400 auto CheckPotentialCallee = [&](
Function &Fn) {
12401 if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))
12404 auto &CachedResult = FilterResults[&Fn];
12405 if (CachedResult.has_value())
12406 return CachedResult.value();
12408 bool UsedAssumedInformation =
false;
12409 if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {
12410 if (!UsedAssumedInformation)
12411 CachedResult =
false;
12420 for (
int I = NumCBArgs;
I < NumFnArgs; ++
I) {
12421 bool IsKnown =
false;
12424 DepClassTy::OPTIONAL, IsKnown)) {
12426 CachedResult =
false;
12431 CachedResult =
true;
12437 for (
auto &VAC : Values) {
12445 if (CheckPotentialCallee(*VACFn))
12446 AssumedCalleesNow.
insert(VACFn);
12449 if (!PotentialCallees.empty()) {
12450 AddPotentialCallees();
12453 AllCalleesKnownNow =
false;
12456 if (AssumedCalleesNow == AssumedCallees &&
12457 AllCalleesKnown == AllCalleesKnownNow)
12458 return ChangeStatus::UNCHANGED;
12460 std::swap(AssumedCallees, AssumedCalleesNow);
12461 AllCalleesKnown = AllCalleesKnownNow;
12462 return ChangeStatus::CHANGED;
12468 if (!AllCalleesKnown && AssumedCallees.empty())
12469 return ChangeStatus::UNCHANGED;
12472 bool UsedAssumedInformation =
false;
12473 if (
A.isAssumedDead(*CB,
this,
nullptr,
12474 UsedAssumedInformation))
12475 return ChangeStatus::UNCHANGED;
12479 if (
FP->getType()->getPointerAddressSpace())
12480 FP =
new AddrSpaceCastInst(
FP, PointerType::get(
FP->getContext(), 0),
12490 if (AssumedCallees.empty()) {
12491 assert(AllCalleesKnown &&
12492 "Expected all callees to be known if there are none.");
12493 A.changeToUnreachableAfterManifest(CB);
12494 return ChangeStatus::CHANGED;
12498 if (AllCalleesKnown && AssumedCallees.size() == 1) {
12499 auto *NewCallee = AssumedCallees.front();
12502 NumIndirectCallsPromoted++;
12503 return ChangeStatus::CHANGED;
12510 A.deleteAfterManifest(*CB);
12511 return ChangeStatus::CHANGED;
12521 bool SpecializedForAnyCallees =
false;
12522 bool SpecializedForAllCallees = AllCalleesKnown;
12523 ICmpInst *LastCmp =
nullptr;
12526 for (Function *NewCallee : AssumedCallees) {
12527 if (!
A.shouldSpecializeCallSiteForCallee(*
this, *CB, *NewCallee,
12528 AssumedCallees.size())) {
12529 SkippedAssumedCallees.
push_back(NewCallee);
12530 SpecializedForAllCallees =
false;
12533 SpecializedForAnyCallees =
true;
12539 A.registerManifestAddedBasicBlock(*ThenTI->
getParent());
12540 A.registerManifestAddedBasicBlock(*IP->getParent());
12546 A.registerManifestAddedBasicBlock(*ElseBB);
12548 SplitTI->replaceUsesOfWith(CBBB, ElseBB);
12553 CastInst *RetBC =
nullptr;
12554 CallInst *NewCall =
nullptr;
12559 NumIndirectCallsPromoted++;
12567 auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {
12568 if (!AllCalleesKnown)
12569 return ChangeStatus::UNCHANGED;
12570 MDBuilder MDB(IndirectCB.getContext());
12571 MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);
12572 IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);
12573 return ChangeStatus::CHANGED;
12576 if (!SpecializedForAnyCallees)
12577 return AttachCalleeMetadata(*CB);
12580 if (SpecializedForAllCallees) {
12583 new UnreachableInst(IP->getContext(), IP);
12584 IP->eraseFromParent();
12587 CBClone->setName(CB->
getName());
12588 CBClone->insertBefore(*IP->getParent(), IP);
12589 NewCalls.
push_back({CBClone,
nullptr});
12590 AttachCalleeMetadata(*CBClone);
12597 CB->
getParent()->getFirstInsertionPt());
12598 for (
auto &It : NewCalls) {
12599 CallBase *NewCall = It.first;
12600 Instruction *CallRet = It.second ? It.second : It.first;
12612 A.deleteAfterManifest(*CB);
12613 Changed = ChangeStatus::CHANGED;
12619 const std::string getAsStr(Attributor *
A)
const override {
12620 return std::string(AllCalleesKnown ?
"eliminate" :
"specialize") +
12621 " indirect call site with " + std::to_string(AssumedCallees.size()) +
12625 void trackStatistics()
const override {
12626 if (AllCalleesKnown) {
12628 Eliminated, CallSites,
12629 "Number of indirect call sites eliminated via specialization")
12632 "Number of indirect call sites specialized")
12636 bool foreachCallee(function_ref<
bool(Function *)> CB)
const override {
12637 return isValidState() && AllCalleesKnown &&
all_of(AssumedCallees, CB);
12642 DenseMap<Function *, std::optional<bool>> FilterResults;
12646 SmallSetVector<Function *, 4> PotentialCallees;
12650 SmallSetVector<Function *, 4> AssumedCallees;
12654 bool AllCalleesKnown =
true;
12661struct AAInvariantLoadPointerImpl
12662 :
public StateWrapper<BitIntegerState<uint8_t, 15>,
12663 AAInvariantLoadPointer> {
12667 IS_NOALIAS = 1 << 0,
12670 IS_NOEFFECT = 1 << 1,
12672 IS_LOCALLY_INVARIANT = 1 << 2,
12674 IS_LOCALLY_CONSTRAINED = 1 << 3,
12676 IS_BEST_STATE = IS_NOALIAS | IS_NOEFFECT | IS_LOCALLY_INVARIANT |
12677 IS_LOCALLY_CONSTRAINED,
12679 static_assert(getBestState() == IS_BEST_STATE,
"Unexpected best state");
12682 StateWrapper<BitIntegerState<uint8_t, 15>, AAInvariantLoadPointer>;
12686 AAInvariantLoadPointerImpl(
const IRPosition &IRP, Attributor &
A)
12689 bool isKnownInvariant()
const final {
12690 return isKnownLocallyInvariant() && isKnown(IS_LOCALLY_CONSTRAINED);
12693 bool isKnownLocallyInvariant()
const final {
12694 if (isKnown(IS_LOCALLY_INVARIANT))
12696 return isKnown(IS_NOALIAS | IS_NOEFFECT);
12699 bool isAssumedInvariant()
const final {
12700 return isAssumedLocallyInvariant() && isAssumed(IS_LOCALLY_CONSTRAINED);
12703 bool isAssumedLocallyInvariant()
const final {
12704 if (isAssumed(IS_LOCALLY_INVARIANT))
12706 return isAssumed(IS_NOALIAS | IS_NOEFFECT);
12713 if (requiresNoAlias() && !isAssumed(IS_NOALIAS))
12714 return indicatePessimisticFixpoint();
12718 Changed |= updateLocalInvariance(
A);
12724 if (!isKnownInvariant())
12725 return ChangeStatus::UNCHANGED;
12728 const Value *Ptr = &getAssociatedValue();
12729 const auto TagInvariantLoads = [&](
const Use &
U,
bool &) {
12730 if (
U.get() != Ptr)
12738 if (!
A.isRunOn(
I->getFunction()))
12741 if (
I->hasMetadata(LLVMContext::MD_invariant_load))
12745 LI->setMetadata(LLVMContext::MD_invariant_load,
12747 Changed = ChangeStatus::CHANGED;
12752 (void)
A.checkForAllUses(TagInvariantLoads, *
this, *Ptr);
12757 const std::string getAsStr(Attributor *)
const override {
12758 if (isKnownInvariant())
12759 return "load-invariant pointer";
12760 return "non-invariant pointer";
12764 void trackStatistics()
const override {}
12768 bool requiresNoAlias()
const {
12769 switch (getPositionKind()) {
12775 case IRP_CALL_SITE:
12777 case IRP_CALL_SITE_RETURNED: {
12782 case IRP_ARGUMENT: {
12783 const Function *
F = getAssociatedFunction();
12784 assert(
F &&
"no associated function for argument");
12790 bool isExternal()
const {
12791 const Function *
F = getAssociatedFunction();
12795 getPositionKind() != IRP_CALL_SITE_RETURNED;
12799 if (isKnown(IS_NOALIAS) || !isAssumed(IS_NOALIAS))
12800 return ChangeStatus::UNCHANGED;
12803 if (
const auto *ANoAlias =
A.getOrCreateAAFor<AANoAlias>(
12804 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12805 if (ANoAlias->isKnownNoAlias()) {
12806 addKnownBits(IS_NOALIAS);
12807 return ChangeStatus::CHANGED;
12810 if (!ANoAlias->isAssumedNoAlias()) {
12811 removeAssumedBits(IS_NOALIAS);
12812 return ChangeStatus::CHANGED;
12815 return ChangeStatus::UNCHANGED;
12820 if (
const Argument *Arg = getAssociatedArgument()) {
12822 addKnownBits(IS_NOALIAS);
12823 return ChangeStatus::UNCHANGED;
12828 removeAssumedBits(IS_NOALIAS);
12829 return ChangeStatus::CHANGED;
12832 return ChangeStatus::UNCHANGED;
12836 if (isKnown(IS_NOEFFECT) || !isAssumed(IS_NOEFFECT))
12837 return ChangeStatus::UNCHANGED;
12839 if (!getAssociatedFunction())
12840 return indicatePessimisticFixpoint();
12843 return indicatePessimisticFixpoint();
12845 const auto HasNoEffectLoads = [&](
const Use &
U,
bool &) {
12847 return !LI || !LI->mayHaveSideEffects();
12849 if (!
A.checkForAllUses(HasNoEffectLoads, *
this, getAssociatedValue()))
12850 return indicatePessimisticFixpoint();
12852 if (
const auto *AMemoryBehavior =
A.getOrCreateAAFor<AAMemoryBehavior>(
12853 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12856 if (!AMemoryBehavior->isAssumedReadOnly())
12857 return indicatePessimisticFixpoint();
12859 if (AMemoryBehavior->isKnownReadOnly()) {
12860 addKnownBits(IS_NOEFFECT);
12861 return ChangeStatus::UNCHANGED;
12864 return ChangeStatus::UNCHANGED;
12867 if (
const Argument *Arg = getAssociatedArgument()) {
12869 addKnownBits(IS_NOEFFECT);
12870 return ChangeStatus::UNCHANGED;
12875 return indicatePessimisticFixpoint();
12878 return ChangeStatus::UNCHANGED;
12882 if (isKnown(IS_LOCALLY_INVARIANT) || !isAssumed(IS_LOCALLY_INVARIANT))
12883 return ChangeStatus::UNCHANGED;
12886 const auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
12887 getIRPosition(),
this, DepClassTy::REQUIRED);
12889 return ChangeStatus::UNCHANGED;
12891 bool UsedAssumedInformation =
false;
12892 const auto IsLocallyInvariantLoadIfPointer = [&](
const Value &
V) {
12893 if (!
V.getType()->isPointerTy())
12895 const auto *IsInvariantLoadPointer =
12897 DepClassTy::REQUIRED);
12899 if (!IsInvariantLoadPointer)
12902 if (IsInvariantLoadPointer->isKnownLocallyInvariant())
12904 if (!IsInvariantLoadPointer->isAssumedLocallyInvariant())
12907 UsedAssumedInformation =
true;
12910 if (!AUO->forallUnderlyingObjects(IsLocallyInvariantLoadIfPointer))
12911 return indicatePessimisticFixpoint();
12917 if (!IsLocallyInvariantLoadIfPointer(*Arg))
12918 return indicatePessimisticFixpoint();
12923 if (!UsedAssumedInformation) {
12925 addKnownBits(IS_LOCALLY_INVARIANT);
12926 return ChangeStatus::CHANGED;
12929 return ChangeStatus::UNCHANGED;
12933struct AAInvariantLoadPointerFloating final : AAInvariantLoadPointerImpl {
12934 AAInvariantLoadPointerFloating(
const IRPosition &IRP, Attributor &
A)
12935 : AAInvariantLoadPointerImpl(IRP,
A) {}
12938struct AAInvariantLoadPointerReturned final : AAInvariantLoadPointerImpl {
12939 AAInvariantLoadPointerReturned(
const IRPosition &IRP, Attributor &
A)
12940 : AAInvariantLoadPointerImpl(IRP,
A) {}
12943 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12947struct AAInvariantLoadPointerCallSiteReturned final
12948 : AAInvariantLoadPointerImpl {
12949 AAInvariantLoadPointerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12950 : AAInvariantLoadPointerImpl(IRP,
A) {}
12953 const Function *
F = getAssociatedFunction();
12954 assert(
F &&
"no associated function for return from call");
12956 if (!
F->isDeclaration() && !
F->isIntrinsic())
12957 return AAInvariantLoadPointerImpl::initialize(
A);
12962 return AAInvariantLoadPointerImpl::initialize(
A);
12964 if (
F->onlyReadsMemory() &&
F->hasNoSync())
12965 return AAInvariantLoadPointerImpl::initialize(
A);
12969 indicatePessimisticFixpoint();
12973struct AAInvariantLoadPointerArgument final : AAInvariantLoadPointerImpl {
12974 AAInvariantLoadPointerArgument(
const IRPosition &IRP, Attributor &
A)
12975 : AAInvariantLoadPointerImpl(IRP,
A) {}
12978 const Function *
F = getAssociatedFunction();
12979 assert(
F &&
"no associated function for argument");
12982 addKnownBits(IS_LOCALLY_CONSTRAINED);
12986 if (!
F->hasLocalLinkage())
12987 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12991struct AAInvariantLoadPointerCallSiteArgument final
12992 : AAInvariantLoadPointerImpl {
12993 AAInvariantLoadPointerCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12994 : AAInvariantLoadPointerImpl(IRP,
A) {}
13001template <
typename InstType>
13002static bool makeChange(Attributor &
A, InstType *MemInst,
const Use &U,
13003 Value *OriginalValue, PointerType *NewPtrTy,
13004 bool UseOriginalValue) {
13005 if (
U.getOperandNo() != InstType::getPointerOperandIndex())
13008 if (MemInst->isVolatile()) {
13009 auto *
TTI =
A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(
13010 *MemInst->getFunction());
13011 unsigned NewAS = NewPtrTy->getPointerAddressSpace();
13016 if (UseOriginalValue) {
13017 A.changeUseAfterManifest(
const_cast<Use &
>(U), *OriginalValue);
13021 Instruction *CastInst =
new AddrSpaceCastInst(OriginalValue, NewPtrTy);
13023 A.changeUseAfterManifest(
const_cast<Use &
>(U), *CastInst);
13027struct AAAddressSpaceImpl :
public AAAddressSpace {
13028 AAAddressSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13029 : AAAddressSpace(IRP,
A) {}
13032 assert(isValidState() &&
"the AA is invalid");
13033 return AssumedAddressSpace;
13038 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13039 "Associated value is not a pointer");
13041 if (!
A.getInfoCache().getFlatAddressSpace().has_value()) {
13042 indicatePessimisticFixpoint();
13046 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13047 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13048 if (AS != FlatAS) {
13049 [[maybe_unused]]
bool R = takeAddressSpace(AS);
13050 assert(R &&
"The take should happen");
13051 indicateOptimisticFixpoint();
13056 uint32_t OldAddressSpace = AssumedAddressSpace;
13057 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13059 auto CheckAddressSpace = [&](
Value &
Obj) {
13065 unsigned ObjAS =
Obj.getType()->getPointerAddressSpace();
13066 if (ObjAS != FlatAS)
13067 return takeAddressSpace(ObjAS);
13081 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(*F);
13083 if (AssumedAS != ~0U)
13084 return takeAddressSpace(AssumedAS);
13088 return takeAddressSpace(FlatAS);
13091 auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(getIRPosition(),
this,
13092 DepClassTy::REQUIRED);
13093 if (!AUO->forallUnderlyingObjects(CheckAddressSpace))
13094 return indicatePessimisticFixpoint();
13096 return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED
13097 : ChangeStatus::CHANGED;
13104 if (NewAS == InvalidAddressSpace ||
13106 return ChangeStatus::UNCHANGED;
13108 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13110 Value *AssociatedValue = &getAssociatedValue();
13111 Value *OriginalValue = peelAddrspacecast(AssociatedValue, FlatAS);
13114 PointerType::get(getAssociatedType()->
getContext(), NewAS);
13115 bool UseOriginalValue =
13120 auto Pred = [&](
const Use &
U,
bool &) {
13121 if (
U.get() != AssociatedValue)
13132 makeChange(
A, LI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13135 makeChange(
A, SI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13138 makeChange(
A, RMW, U, OriginalValue, NewPtrTy, UseOriginalValue);
13141 makeChange(
A, CmpX, U, OriginalValue, NewPtrTy, UseOriginalValue);
13148 (void)
A.checkForAllUses(Pred, *
this, getAssociatedValue(),
13151 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13155 const std::string getAsStr(Attributor *
A)
const override {
13156 if (!isValidState())
13157 return "addrspace(<invalid>)";
13158 return "addrspace(" +
13159 (AssumedAddressSpace == InvalidAddressSpace
13161 : std::to_string(AssumedAddressSpace)) +
13166 uint32_t AssumedAddressSpace = InvalidAddressSpace;
13168 bool takeAddressSpace(uint32_t AS) {
13169 if (AssumedAddressSpace == InvalidAddressSpace) {
13170 AssumedAddressSpace = AS;
13173 return AssumedAddressSpace == AS;
13176 static Value *peelAddrspacecast(
Value *V,
unsigned FlatAS) {
13178 assert(
I->getSrcAddressSpace() != FlatAS &&
13179 "there should not be flat AS -> non-flat AS");
13180 return I->getPointerOperand();
13183 if (
C->getOpcode() == Instruction::AddrSpaceCast) {
13184 assert(
C->getOperand(0)->getType()->getPointerAddressSpace() !=
13186 "there should not be flat AS -> non-flat AS X");
13187 return C->getOperand(0);
13193struct AAAddressSpaceFloating final : AAAddressSpaceImpl {
13194 AAAddressSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13195 : AAAddressSpaceImpl(IRP,
A) {}
13197 void trackStatistics()
const override {
13202struct AAAddressSpaceReturned final : AAAddressSpaceImpl {
13203 AAAddressSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13204 : AAAddressSpaceImpl(IRP,
A) {}
13210 (void)indicatePessimisticFixpoint();
13213 void trackStatistics()
const override {
13218struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl {
13219 AAAddressSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13220 : AAAddressSpaceImpl(IRP,
A) {}
13222 void trackStatistics()
const override {
13227struct AAAddressSpaceArgument final : AAAddressSpaceImpl {
13228 AAAddressSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13229 : AAAddressSpaceImpl(IRP,
A) {}
13234struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl {
13235 AAAddressSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13236 : AAAddressSpaceImpl(IRP,
A) {}
13242 (void)indicatePessimisticFixpoint();
13245 void trackStatistics()
const override {
13260struct AANoAliasAddrSpaceImpl :
public AANoAliasAddrSpace {
13261 AANoAliasAddrSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13262 : AANoAliasAddrSpace(IRP,
A) {}
13265 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13266 "Associated value is not a pointer");
13270 std::optional<unsigned> FlatAS =
A.getInfoCache().getFlatAddressSpace();
13271 if (!FlatAS.has_value()) {
13272 indicatePessimisticFixpoint();
13278 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13279 if (AS != *FlatAS) {
13281 indicateOptimisticFixpoint();
13286 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13287 uint32_t OldAssumed = getAssumed();
13289 auto CheckAddressSpace = [&](
Value &
Obj) {
13293 unsigned AS =
Obj.getType()->getPointerAddressSpace();
13297 removeAS(
Obj.getType()->getPointerAddressSpace());
13301 const AAUnderlyingObjects *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
13302 getIRPosition(),
this, DepClassTy::REQUIRED);
13304 return indicatePessimisticFixpoint();
13306 return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
13307 : ChangeStatus::CHANGED;
13312 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13314 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13315 if (AS != FlatAS ||
Map.empty())
13316 return ChangeStatus::UNCHANGED;
13318 LLVMContext &Ctx = getAssociatedValue().getContext();
13319 MDNode *NoAliasASNode =
nullptr;
13320 MDBuilder MDB(Ctx);
13322 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13325 unsigned Upper =
I.stop();
13326 unsigned Lower =
I.start();
13327 if (!NoAliasASNode) {
13328 NoAliasASNode = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13331 MDNode *ASRange = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13335 Value *AssociatedValue = &getAssociatedValue();
13338 auto AddNoAliasAttr = [&](
const Use &
U,
bool &) {
13339 if (
U.get() != AssociatedValue)
13342 if (!Inst || Inst->
hasMetadata(LLVMContext::MD_noalias_addrspace))
13349 Inst->
setMetadata(LLVMContext::MD_noalias_addrspace, NoAliasASNode);
13353 (void)
A.checkForAllUses(AddNoAliasAttr, *
this, *AssociatedValue,
13355 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13359 const std::string getAsStr(Attributor *
A)
const override {
13360 if (!isValidState())
13361 return "<invalid>";
13363 raw_string_ostream OS(Str);
13364 OS <<
"CanNotBeAddrSpace(";
13365 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13366 unsigned Upper =
I.stop();
13367 unsigned Lower =
I.start();
13368 OS <<
' ' <<
'[' <<
Upper <<
',' <<
Lower + 1 <<
')';
13375 void removeAS(
unsigned AS) {
13376 RangeMap::iterator
I =
Map.find(AS);
13378 if (
I !=
Map.end()) {
13379 unsigned Upper =
I.stop();
13380 unsigned Lower =
I.start();
13384 if (AS != ~((
unsigned)0) && AS + 1 <=
Upper)
13386 if (AS != 0 &&
Lower <= AS - 1)
13391 void resetASRanges(Attributor &
A) {
13393 Map.insert(0,
A.getInfoCache().getMaxAddrSpace(),
true);
13397struct AANoAliasAddrSpaceFloating final : AANoAliasAddrSpaceImpl {
13398 AANoAliasAddrSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13399 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13401 void trackStatistics()
const override {
13406struct AANoAliasAddrSpaceReturned final : AANoAliasAddrSpaceImpl {
13407 AANoAliasAddrSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13408 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13410 void trackStatistics()
const override {
13415struct AANoAliasAddrSpaceCallSiteReturned final : AANoAliasAddrSpaceImpl {
13416 AANoAliasAddrSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13417 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13419 void trackStatistics()
const override {
13424struct AANoAliasAddrSpaceArgument final : AANoAliasAddrSpaceImpl {
13425 AANoAliasAddrSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13426 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13428 void trackStatistics()
const override {
13433struct AANoAliasAddrSpaceCallSiteArgument final : AANoAliasAddrSpaceImpl {
13434 AANoAliasAddrSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13435 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13437 void trackStatistics()
const override {
13444struct AAAllocationInfoImpl :
public AAAllocationInfo {
13445 AAAllocationInfoImpl(
const IRPosition &IRP, Attributor &
A)
13446 : AAAllocationInfo(IRP,
A) {}
13448 std::optional<TypeSize> getAllocatedSize()
const override {
13449 assert(isValidState() &&
"the AA is invalid");
13450 return AssumedAllocatedSize;
13453 std::optional<TypeSize> findInitialAllocationSize(Instruction *
I,
13454 const DataLayout &
DL) {
13457 switch (
I->getOpcode()) {
13458 case Instruction::Alloca: {
13463 return std::nullopt;
13469 const IRPosition &IRP = getIRPosition();
13474 return indicatePessimisticFixpoint();
13476 bool IsKnownNoCapture;
13478 A,
this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture))
13479 return indicatePessimisticFixpoint();
13481 const AAPointerInfo *PI =
13482 A.getOrCreateAAFor<AAPointerInfo>(IRP, *
this, DepClassTy::REQUIRED);
13485 return indicatePessimisticFixpoint();
13488 return indicatePessimisticFixpoint();
13490 const DataLayout &
DL =
A.getDataLayout();
13491 const auto AllocationSize = findInitialAllocationSize(
I,
DL);
13494 if (!AllocationSize)
13495 return indicatePessimisticFixpoint();
13499 if (*AllocationSize == 0)
13500 return indicatePessimisticFixpoint();
13506 return indicatePessimisticFixpoint();
13508 if (BinSize == 0) {
13509 auto NewAllocationSize = std::make_optional<TypeSize>(0,
false);
13510 if (!changeAllocationSize(NewAllocationSize))
13511 return ChangeStatus::UNCHANGED;
13512 return ChangeStatus::CHANGED;
13516 const auto &It = PI->
begin();
13519 if (It->first.Offset != 0)
13520 return indicatePessimisticFixpoint();
13522 uint64_t SizeOfBin = It->first.Offset + It->first.Size;
13524 if (SizeOfBin >= *AllocationSize)
13525 return indicatePessimisticFixpoint();
13527 auto NewAllocationSize = std::make_optional<TypeSize>(SizeOfBin * 8,
false);
13529 if (!changeAllocationSize(NewAllocationSize))
13530 return ChangeStatus::UNCHANGED;
13532 return ChangeStatus::CHANGED;
13538 assert(isValidState() &&
13539 "Manifest should only be called if the state is valid.");
13543 auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
13545 unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
13547 switch (
I->getOpcode()) {
13549 case Instruction::Alloca: {
13553 Type *CharType = Type::getInt8Ty(
I->getContext());
13555 auto *NumBytesToValue =
13556 ConstantInt::get(
I->getContext(), APInt(32, NumBytesToAllocate));
13559 insertPt = std::next(insertPt);
13560 AllocaInst *NewAllocaInst =
13565 return ChangeStatus::CHANGED;
13573 return ChangeStatus::UNCHANGED;
13577 const std::string getAsStr(Attributor *
A)
const override {
13578 if (!isValidState())
13579 return "allocationinfo(<invalid>)";
13580 return "allocationinfo(" +
13581 (AssumedAllocatedSize == HasNoAllocationSize
13583 : std::to_string(AssumedAllocatedSize->getFixedValue())) +
13588 std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
13592 bool changeAllocationSize(std::optional<TypeSize>
Size) {
13593 if (AssumedAllocatedSize == HasNoAllocationSize ||
13594 AssumedAllocatedSize !=
Size) {
13595 AssumedAllocatedSize =
Size;
13602struct AAAllocationInfoFloating : AAAllocationInfoImpl {
13603 AAAllocationInfoFloating(
const IRPosition &IRP, Attributor &
A)
13604 : AAAllocationInfoImpl(IRP,
A) {}
13606 void trackStatistics()
const override {
13611struct AAAllocationInfoReturned : AAAllocationInfoImpl {
13612 AAAllocationInfoReturned(
const IRPosition &IRP, Attributor &
A)
13613 : AAAllocationInfoImpl(IRP,
A) {}
13619 (void)indicatePessimisticFixpoint();
13622 void trackStatistics()
const override {
13627struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl {
13628 AAAllocationInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13629 : AAAllocationInfoImpl(IRP,
A) {}
13631 void trackStatistics()
const override {
13636struct AAAllocationInfoArgument : AAAllocationInfoImpl {
13637 AAAllocationInfoArgument(
const IRPosition &IRP, Attributor &
A)
13638 : AAAllocationInfoImpl(IRP,
A) {}
13640 void trackStatistics()
const override {
13645struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl {
13646 AAAllocationInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13647 : AAAllocationInfoImpl(IRP,
A) {}
13652 (void)indicatePessimisticFixpoint();
13655 void trackStatistics()
const override {
13704#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \
13705 case IRPosition::PK: \
13706 llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");
13708#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \
13709 case IRPosition::PK: \
13710 AA = new (A.Allocator) CLASS##SUFFIX(IRP, A); \
13714#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13715 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13716 CLASS *AA = nullptr; \
13717 switch (IRP.getPositionKind()) { \
13718 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13719 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13720 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13721 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13722 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13723 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13724 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13725 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13730#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13731 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13732 CLASS *AA = nullptr; \
13733 switch (IRP.getPositionKind()) { \
13734 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13735 SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \
13736 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13737 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13738 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13739 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13740 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13741 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13746#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS) \
13747 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13748 CLASS *AA = nullptr; \
13749 switch (IRP.getPositionKind()) { \
13750 SWITCH_PK_CREATE(CLASS, IRP, POS, SUFFIX) \
13752 llvm_unreachable("Cannot create " #CLASS " for position otherthan " #POS \
13758#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13759 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13760 CLASS *AA = nullptr; \
13761 switch (IRP.getPositionKind()) { \
13762 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13763 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13764 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13765 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13766 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13767 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13768 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13769 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13774#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13775 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13776 CLASS *AA = nullptr; \
13777 switch (IRP.getPositionKind()) { \
13778 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13779 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13780 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13781 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13782 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13783 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13784 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13785 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13790#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13791 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13792 CLASS *AA = nullptr; \
13793 switch (IRP.getPositionKind()) { \
13794 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13795 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13796 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13797 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13798 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13799 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13800 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13801 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13853#undef CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION
13854#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
13855#undef CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION
13856#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
13857#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
13858#undef CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION
13859#undef SWITCH_PK_CREATE
13860#undef SWITCH_PK_INV
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file implements a class to represent arbitrary precision integral constant values and operations...
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis false
This file contains the simple types necessary to represent the attributes associated with functions a...
#define STATS_DECLTRACK(NAME, TYPE, MSG)
static std::optional< Constant * > askForAssumedConstant(Attributor &A, const AbstractAttribute &QueryingAA, const IRPosition &IRP, Type &Ty)
static cl::opt< unsigned, true > MaxPotentialValues("attributor-max-potential-values", cl::Hidden, cl::desc("Maximum number of potential values to be " "tracked for each position."), cl::location(llvm::PotentialConstantIntValuesState::MaxPotentialValues), cl::init(7))
static void clampReturnedValueStates(Attributor &A, const AAType &QueryingAA, StateType &S, const IRPosition::CallBaseContext *CBContext=nullptr)
Clamp the information known for all returned values of a function (identified by QueryingAA) into S.
#define STATS_DECLTRACK_FN_ATTR(NAME)
#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static cl::opt< int > MaxPotentialValuesIterations("attributor-max-potential-values-iterations", cl::Hidden, cl::desc("Maximum number of iterations we keep dismantling potential values."), cl::init(64))
#define STATS_DECLTRACK_CS_ATTR(NAME)
#define PIPE_OPERATOR(CLASS)
static bool mayBeInCycle(const CycleInfo *CI, const Instruction *I, bool HeaderOnly, Cycle **CPtr=nullptr)
#define STATS_DECLTRACK_ARG_ATTR(NAME)
static const Value * stripAndAccumulateOffsets(Attributor &A, const AbstractAttribute &QueryingAA, const Value *Val, const DataLayout &DL, APInt &Offset, bool GetMinOffset, bool AllowNonInbounds, bool UseAssumed=false)
#define STATS_DECLTRACK_CSRET_ATTR(NAME)
static cl::opt< bool > ManifestInternal("attributor-manifest-internal", cl::Hidden, cl::desc("Manifest Attributor internal string attributes."), cl::init(false))
static Value * constructPointer(Value *Ptr, int64_t Offset, IRBuilder< NoFolder > &IRB)
Helper function to create a pointer based on Ptr, and advanced by Offset bytes.
#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
#define BUILD_STAT_NAME(NAME, TYPE)
static bool isDenselyPacked(Type *Ty, const DataLayout &DL)
Checks if a type could have padding bytes.
#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static const Value * getMinimalBaseOfPointer(Attributor &A, const AbstractAttribute &QueryingAA, const Value *Ptr, int64_t &BytesOffset, const DataLayout &DL, bool AllowNonInbounds=false)
#define STATS_DECLTRACK_FNRET_ATTR(NAME)
#define STATS_DECLTRACK_CSARG_ATTR(NAME)
#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS)
#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static cl::opt< int > MaxHeapToStackSize("max-heap-to-stack-size", cl::init(128), cl::Hidden)
#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
#define STATS_DECLTRACK_FLOATING_ATTR(NAME)
#define STATS_DECL(NAME, TYPE, MSG)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool isReachableImpl(SmallVectorImpl< BasicBlock * > &Worklist, const StopSetT &StopSet, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet, const DominatorTree *DT, const LoopInfo *LI, const CycleInfo *CI)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file declares an analysis pass that computes CycleInfo for LLVM IR, specialized from GenericCycl...
DXIL Forward Handle Accesses
This file defines DenseMapInfo traits for DenseMap.
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
static unsigned getAddressSpace(const Value *V, unsigned MaxLookup)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
static StringRef getName(Value *V)
dot regions Print regions of function to dot true view regions View regions of function(with no function bodies)"
Remove Loads Into Fake Uses
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
std::pair< BasicBlock *, BasicBlock * > Edge
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
This file defines generic set operations that may be used on set's of different types,...
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static SymbolRef::Type getType(const Symbol *Sym)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type.
static unsigned getSize(unsigned Kind)
LLVM_ABI AACallGraphNode * operator*() const
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A trivial helper function to check to see if the specified pointers are no-alias.
Class for arbitrary precision integers.
int64_t getSExtValue() const
Get sign extended value.
CallBase * getInstruction() const
Return the underlying instruction.
bool isCallbackCall() const
Return true if this ACS represents a callback call.
bool isDirectCall() const
Return true if this ACS represents a direct call.
static LLVM_ABI void getCallbackUses(const CallBase &CB, SmallVectorImpl< const Use * > &CallbackUses)
Add operand uses of CB that represent callback uses into CallbackUses.
int getCallArgOperandNo(Argument &Arg) const
Return the operand index of the underlying instruction associated with Arg.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
unsigned getAddressSpace() const
Return the address space for the allocation.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
This class represents an incoming formal argument to a Function.
LLVM_ABI bool hasNoAliasAttr() const
Return true if this argument has the noalias attribute.
LLVM_ABI bool onlyReadsMemory() const
Return true if this argument has the readonly or readnone attribute.
LLVM_ABI bool hasPointeeInMemoryValueAttr() const
Return true if this argument has the byval, sret, inalloca, preallocated, or byref attribute.
LLVM_ABI bool hasReturnedAttr() const
Return true if this argument has the returned attribute.
LLVM_ABI bool hasByValAttr() const
Return true if this argument has the byval attribute.
const Function * getParent() const
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
Functions, function parameters, and return types can have attributes to indicate how they should be t...
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
LLVM_ABI FPClassTest getNoFPClass() const
Return the FPClassTest for nofpclass.
LLVM_ABI Attribute::AttrKind getKindAsEnum() const
Return the attribute's kind as an enum (Attribute::AttrKind).
LLVM_ABI MemoryEffects getMemoryEffects() const
Returns memory effects.
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
static LLVM_ABI Attribute getWithCaptureInfo(LLVMContext &Context, CaptureInfo CI)
static bool isEnumAttrKind(AttrKind Kind)
bool isValid() const
Return true if the attribute is any kind of attribute.
LLVM_ABI CaptureInfo getCaptureInfo() const
Returns information from captures attribute.
LLVM Basic Block Representation.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Instruction & front() const
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
BinaryOps getOpcode() const
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
Value * getCalledOperand() const
const Use & getCalledOperandUse() const
Attribute getFnAttr(StringRef Kind) const
Get the attribute of a given kind for the function.
const Use & getArgOperandUse(unsigned i) const
Wrappers for getting the Use of a call argument.
LLVM_ABI std::optional< ConstantRange > getRange() const
If this return value has a range attribute, return the value range of the argument.
Value * getArgOperand(unsigned i) const
bool isBundleOperand(unsigned Idx) const
Return true if the operand at index Idx is a bundle operand.
bool isConvergent() const
Determine if the invoke is convergent.
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static CaptureInfo none()
Create CaptureInfo that does not capture any components of the pointer.
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
LLVM_ABI bool isIntegerCast() const
There are several places where we need to know if a cast instruction only deals with integer source a...
Type * getDestTy() const
Return the destination type, as a convenience.
bool isEquality() const
Determine if this is an equals/not equals predicate.
bool isFalseWhenEqual() const
This is just a convenience.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
bool isTrueWhenEqual() const
This is just a convenience.
Predicate getPredicate() const
Return the predicate for this instruction.
Conditional Branch instruction.
Value * getCondition() const
BasicBlock * getSuccessor(unsigned i) const
static LLVM_ABI Constant * getExtractElement(Constant *Vec, Constant *Idx, Type *OnlyIfReducedTy=nullptr)
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
This class represents a range of values.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
LLVM_ABI bool isEmptySet() const
Return true if this set contains no members.
bool isSingleElement() const
Return true if this set contains exactly one member.
static LLVM_ABI ConstantRange makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other)
Produce the smallest range such that all values that may satisfy the given predicate with any value c...
const APInt & getUpper() const
Return the upper value for this range.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
const BasicBlock & getEntryBlock() const
iterator_range< arg_iterator > args()
const Function & getFunction() const
Argument * getArg(unsigned i) const
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
CycleT * getCycle(const BlockT *Block) const
Find the innermost cycle containing a given block.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasLocalLinkage() const
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
Value * CreatePtrAdd(Value *Ptr, Value *Offset, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI bool isLifetimeStartOrEnd() const LLVM_READONLY
Return true if the instruction is a llvm.lifetime.start or llvm.lifetime.end marker.
bool mayReadOrWriteMemory() const
Return true if this instruction may read or write memory.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
bool hasMetadata() const
Return true if this instruction has any metadata attached to it.
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI BasicBlock * getSuccessor(unsigned Idx) const LLVM_READONLY
Return the specified successor. This instruction must be a terminator.
LLVM_ABI bool mayHaveSideEffects() const LLVM_READONLY
Return true if the instruction may have side effects.
bool isTerminator() const
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This is an important class for using LLVM in a threaded context.
ConstantRange getConstantRange(Value *V, Instruction *CxtI, bool UndefAllowed)
Return the ConstantRange constraint that is known to hold for the specified value at the specified in...
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static LLVM_ABI MDNode * getMostGenericRange(MDNode *A, MDNode *B)
static MemoryEffectsBase readOnly()
bool doesNotAccessMemory() const
Whether this function accesses no memory.
static MemoryEffectsBase argMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase inaccessibleMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
bool onlyAccessesInaccessibleMem() const
Whether this function only (at most) accesses inaccessible memory.
ModRefInfo getModRef(Location Loc) const
Get ModRefInfo for the given Location.
bool onlyAccessesArgPointees() const
Whether this function only (at most) accesses argument memory.
bool onlyReadsMemory() const
Whether this function only (at most) reads memory.
static MemoryEffectsBase writeOnly()
static MemoryEffectsBase inaccessibleOrArgMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase none()
bool onlyAccessesInaccessibleOrArgMem() const
Whether this function only (at most) accesses argument and inaccessible memory.
static MemoryEffectsBase unknown()
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static SizeOffsetValue unknown()
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Value * getReturnValue() const
Convenience accessor. Returns null if there is no return value.
LLVM_ABI const SCEV * getSCEVAtScope(const SCEV *S, const Loop *L)
Return a SCEV expression for the specified value at the specified scope in the program.
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI unsigned getSmallConstantMaxTripCount(const Loop *L, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Returns the upper bound of the loop trip count as a normal unsigned value.
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
TypeSize getElementOffset(unsigned Idx) const
TypeSize getElementOffsetInBits(unsigned Idx) const
Class to represent struct types.
unsigned getNumElements() const
Random access to the elements.
Type * getElementType(unsigned N) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isPointerTy() const
True if this is an instance of PointerType.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
bool isPtrOrPtrVectorTy() const
Return true if this is a pointer type or a vector of pointer types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
bool isVoidTy() const
Return true if this is 'void'.
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
BasicBlock * getSuccessor(unsigned i=0) const
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
User * getUser() const
Returns the User that contains this Use.
const Use & getOperandUse(unsigned i) const
LLVM_ABI bool isDroppable() const
A droppable user is a user for which uses can be dropped without affecting correctness and should be ...
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
unsigned getNumOperands() const
ValueT lookup(const KeyT &Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
static constexpr uint64_t MaximumAlignment
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
LLVM_ABI const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr, bool LookThroughIntToPtr=false) const
Accumulate the constant offset this value has compared to a base pointer.
static constexpr unsigned MaxAlignmentExponent
The maximum alignment for instructions.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
constexpr ScalarTy getFixedValue() const
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
SetVector< Function * >::iterator I
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
LLVM_ABI bool isAssumedReadNone(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readnone.
LLVM_ABI bool isAssumedReadOnly(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readonly.
raw_ostream & operator<<(raw_ostream &OS, const RangeTy &R)
LLVM_ABI std::optional< Value * > combineOptionalValuesInAAValueLatice(const std::optional< Value * > &A, const std::optional< Value * > &B, Type *Ty)
Return the combination of A and B such that the result is a possible value of both.
LLVM_ABI bool isValidAtPosition(const ValueAndContext &VAC, InformationCache &InfoCache)
Return true if the value of VAC is a valid at the position of VAC, that is a constant,...
LLVM_ABI bool isAssumedThreadLocalObject(Attributor &A, Value &Obj, const AbstractAttribute &QueryingAA)
Return true if Obj is assumed to be a thread local object.
LLVM_ABI bool 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.