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())
673 if (Br->isConditional())
692 while (!BrInsts.
empty()) {
694 StateType ParentState;
698 ParentState.indicateOptimisticFixpoint();
701 StateType ChildState;
702 size_t BeforeSize =
Uses.size();
704 followUsesInContext(
AA,
A, *Explorer,
I,
Uses, ChildState);
707 for (
auto It =
Uses.begin() + BeforeSize; It !=
Uses.end();)
710 ParentState &= ChildState;
787 R.indicatePessimisticFixpoint();
804 BS.indicateOptimisticFixpoint();
810 BS.indicatePessimisticFixpoint();
880 template <
typename F>
887 if (!
Range.mayOverlap(ItRange))
889 bool IsExact =
Range == ItRange && !
Range.offsetOrSizeAreUnknown();
890 for (
auto Index : It.getSecond()) {
900 template <
typename F>
911 for (
unsigned Index : LocalList->getSecond()) {
914 if (
Range.offsetAndSizeAreUnknown())
930 RemoteI = RemoteI ? RemoteI : &
I;
934 bool AccExists =
false;
936 for (
auto Index : LocalList) {
938 if (
A.getLocalInst() == &
I) {
947 <<
"[AAPointerInfo] Inserting access in new offset bins\n";);
949 for (
auto Key : ToAdd) {
956 AccessList.emplace_back(&
I, RemoteI, Ranges, Content, Kind, Ty);
958 "New Access should have been at AccIndex");
959 LocalList.push_back(AccIndex);
968 auto Before = Current;
970 if (Current == Before)
973 auto &ExistingRanges = Before.getRanges();
974 auto &NewRanges = Current.getRanges();
981 <<
"[AAPointerInfo] Removing access from old offset bins\n";);
988 "Expected bin to actually contain the Access.");
1010struct AAPointerInfoImpl
1011 :
public StateWrapper<AA::PointerInfo::State, AAPointerInfo> {
1016 const std::string getAsStr(
Attributor *
A)
const override {
1017 return std::string(
"PointerInfo ") +
1018 (isValidState() ? (std::string(
"#") +
1019 std::to_string(OffsetBins.size()) +
" bins")
1024 [](int64_t O) {
return std::to_string(O); }),
1032 return AAPointerInfo::manifest(
A);
1035 const_bin_iterator
begin()
const override {
return State::begin(); }
1036 const_bin_iterator
end()
const override {
return State::end(); }
1037 int64_t numOffsetBins()
const override {
return State::numOffsetBins(); }
1038 bool reachesReturn()
const override {
1039 return !ReturnedOffsets.isUnassigned();
1041 void addReturnedOffsetsTo(OffsetInfo &OI)
const override {
1042 if (ReturnedOffsets.isUnknown()) {
1047 OffsetInfo MergedOI;
1048 for (
auto Offset : ReturnedOffsets) {
1049 OffsetInfo TmpOI = OI;
1051 MergedOI.merge(TmpOI);
1053 OI = std::move(MergedOI);
1056 ChangeStatus setReachesReturn(
const OffsetInfo &ReachedReturnedOffsets) {
1057 if (ReturnedOffsets.isUnknown())
1058 return ChangeStatus::UNCHANGED;
1059 if (ReachedReturnedOffsets.isUnknown()) {
1060 ReturnedOffsets.setUnknown();
1061 return ChangeStatus::CHANGED;
1063 if (ReturnedOffsets.merge(ReachedReturnedOffsets))
1064 return ChangeStatus::CHANGED;
1065 return ChangeStatus::UNCHANGED;
1068 bool forallInterferingAccesses(
1070 function_ref<
bool(
const AAPointerInfo::Access &,
bool)> CB)
1072 return State::forallInterferingAccesses(
Range, CB);
1075 bool forallInterferingAccesses(
1076 Attributor &
A,
const AbstractAttribute &QueryingAA, Instruction &
I,
1077 bool FindInterferingWrites,
bool FindInterferingReads,
1078 function_ref<
bool(
const Access &,
bool)> UserCB,
bool &HasBeenWrittenTo,
1080 function_ref<
bool(
const Access &)> SkipCB)
const override {
1081 HasBeenWrittenTo =
false;
1083 SmallPtrSet<const Access *, 8> DominatingWrites;
1091 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
1093 bool AllInSameNoSyncFn = IsAssumedNoSync;
1094 bool InstIsExecutedByInitialThreadOnly =
1095 ExecDomainAA && ExecDomainAA->isExecutedByInitialThreadOnly(
I);
1102 bool InstIsExecutedInAlignedRegion =
1103 FindInterferingReads && ExecDomainAA &&
1104 ExecDomainAA->isExecutedInAlignedRegion(
A,
I);
1106 if (InstIsExecutedInAlignedRegion || InstIsExecutedByInitialThreadOnly)
1107 A.recordDependence(*ExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1109 InformationCache &InfoCache =
A.getInfoCache();
1110 bool IsThreadLocalObj =
1119 auto CanIgnoreThreadingForInst = [&](
const Instruction &
I) ->
bool {
1120 if (IsThreadLocalObj || AllInSameNoSyncFn)
1122 const auto *FnExecDomainAA =
1123 I.getFunction() == &
Scope
1125 :
A.lookupAAFor<AAExecutionDomain>(
1128 if (!FnExecDomainAA)
1130 if (InstIsExecutedInAlignedRegion ||
1131 (FindInterferingWrites &&
1132 FnExecDomainAA->isExecutedInAlignedRegion(
A,
I))) {
1133 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1136 if (InstIsExecutedByInitialThreadOnly &&
1137 FnExecDomainAA->isExecutedByInitialThreadOnly(
I)) {
1138 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1147 auto CanIgnoreThreading = [&](
const Access &Acc) ->
bool {
1148 return CanIgnoreThreadingForInst(*Acc.getRemoteInst()) ||
1149 (Acc.getRemoteInst() != Acc.getLocalInst() &&
1150 CanIgnoreThreadingForInst(*Acc.getLocalInst()));
1154 bool IsKnownNoRecurse;
1162 bool InstInKernel =
A.getInfoCache().isKernel(Scope);
1163 bool ObjHasKernelLifetime =
false;
1164 const bool UseDominanceReasoning =
1165 FindInterferingWrites && IsKnownNoRecurse;
1166 const DominatorTree *DT =
1176 case AA::GPUAddressSpace::Shared:
1177 case AA::GPUAddressSpace::Constant:
1178 case AA::GPUAddressSpace::Local:
1190 std::function<bool(
const Function &)> IsLiveInCalleeCB;
1195 const Function *AIFn = AI->getFunction();
1196 ObjHasKernelLifetime =
A.getInfoCache().isKernel(*AIFn);
1197 bool IsKnownNoRecurse;
1200 IsKnownNoRecurse)) {
1201 IsLiveInCalleeCB = [AIFn](
const Function &Fn) {
return AIFn != &Fn; };
1206 ObjHasKernelLifetime = HasKernelLifetime(GV, *GV->getParent());
1207 if (ObjHasKernelLifetime)
1208 IsLiveInCalleeCB = [&
A](
const Function &Fn) {
1209 return !
A.getInfoCache().isKernel(Fn);
1217 auto AccessCB = [&](
const Access &Acc,
bool Exact) {
1218 Function *AccScope = Acc.getRemoteInst()->getFunction();
1219 bool AccInSameScope = AccScope == &
Scope;
1223 if (InstInKernel && ObjHasKernelLifetime && !AccInSameScope &&
1224 A.getInfoCache().isKernel(*AccScope))
1227 if (Exact && Acc.isMustAccess() && Acc.getRemoteInst() != &
I) {
1228 if (Acc.isWrite() || (
isa<LoadInst>(
I) && Acc.isWriteOrAssumption()))
1229 ExclusionSet.
insert(Acc.getRemoteInst());
1232 if ((!FindInterferingWrites || !Acc.isWriteOrAssumption()) &&
1233 (!FindInterferingReads || !Acc.isRead()))
1236 bool Dominates = FindInterferingWrites && DT && Exact &&
1237 Acc.isMustAccess() && AccInSameScope &&
1240 DominatingWrites.
insert(&Acc);
1244 AllInSameNoSyncFn &= Acc.getRemoteInst()->getFunction() == &
Scope;
1246 InterferingAccesses.
push_back({&Acc, Exact});
1249 if (!State::forallInterferingAccesses(
I, AccessCB,
Range))
1252 HasBeenWrittenTo = !DominatingWrites.
empty();
1256 for (
const Access *Acc : DominatingWrites) {
1257 if (!LeastDominatingWriteInst) {
1258 LeastDominatingWriteInst = Acc->getRemoteInst();
1259 }
else if (DT->
dominates(LeastDominatingWriteInst,
1260 Acc->getRemoteInst())) {
1261 LeastDominatingWriteInst = Acc->getRemoteInst();
1266 auto CanSkipAccess = [&](
const Access &Acc,
bool Exact) {
1267 if (SkipCB && SkipCB(Acc))
1269 if (!CanIgnoreThreading(Acc))
1275 bool ReadChecked = !FindInterferingReads;
1276 bool WriteChecked = !FindInterferingWrites;
1282 &ExclusionSet, IsLiveInCalleeCB))
1287 if (!WriteChecked) {
1289 &ExclusionSet, IsLiveInCalleeCB))
1290 WriteChecked =
true;
1304 if (!WriteChecked && HasBeenWrittenTo &&
1305 Acc.getRemoteInst()->getFunction() != &Scope) {
1307 const auto *FnReachabilityAA =
A.getAAFor<AAInterFnReachability>(
1309 if (FnReachabilityAA) {
1315 if (!FnReachabilityAA->instructionCanReach(
1316 A, *LeastDominatingWriteInst,
1317 *Acc.getRemoteInst()->getFunction(), &ExclusionSet))
1318 WriteChecked =
true;
1325 if (ReadChecked && WriteChecked)
1328 if (!DT || !UseDominanceReasoning)
1330 if (!DominatingWrites.count(&Acc))
1332 return LeastDominatingWriteInst != Acc.getRemoteInst();
1337 for (
auto &It : InterferingAccesses) {
1338 if ((!AllInSameNoSyncFn && !IsThreadLocalObj && !ExecDomainAA) ||
1339 !CanSkipAccess(*It.first, It.second)) {
1340 if (!UserCB(*It.first, It.second))
1348 const AAPointerInfo &OtherAA,
1350 using namespace AA::PointerInfo;
1352 return indicatePessimisticFixpoint();
1355 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1356 bool IsByval = OtherAAImpl.getAssociatedArgument()->hasByValAttr();
1357 Changed |= setReachesReturn(OtherAAImpl.ReturnedOffsets);
1360 const auto &State = OtherAAImpl.getState();
1361 for (
const auto &It : State) {
1362 for (
auto Index : It.getSecond()) {
1363 const auto &RAcc = State.getAccess(Index);
1364 if (IsByval && !RAcc.isRead())
1366 bool UsedAssumedInformation =
false;
1368 auto Content =
A.translateArgumentToCallSiteContent(
1369 RAcc.getContent(), CB, *
this, UsedAssumedInformation);
1370 AK =
AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW));
1371 AK =
AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST));
1373 Changed |= addAccess(
A, RAcc.getRanges(), CB, Content, AK,
1374 RAcc.getType(), RAcc.getRemoteInst());
1380 ChangeStatus translateAndAddState(Attributor &
A,
const AAPointerInfo &OtherAA,
1381 const OffsetInfo &Offsets, CallBase &CB,
1383 using namespace AA::PointerInfo;
1385 return indicatePessimisticFixpoint();
1387 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1391 const auto &State = OtherAAImpl.getState();
1392 for (
const auto &It : State) {
1393 for (
auto Index : It.getSecond()) {
1394 const auto &RAcc = State.getAccess(Index);
1395 if (!IsMustAcc && RAcc.isAssumption())
1397 for (
auto Offset : Offsets) {
1401 if (!NewRanges.isUnknown()) {
1402 NewRanges.addToAllOffsets(Offset);
1407 Changed |= addAccess(
A, NewRanges, CB, RAcc.getContent(), AK,
1408 RAcc.getType(), RAcc.getRemoteInst());
1417 void trackPointerInfoStatistics(
const IRPosition &IRP)
const {}
1420 void dumpState(raw_ostream &O) {
1421 for (
auto &It : OffsetBins) {
1422 O <<
"[" << It.first.Offset <<
"-" << It.first.Offset + It.first.Size
1423 <<
"] : " << It.getSecond().size() <<
"\n";
1424 for (
auto AccIndex : It.getSecond()) {
1425 auto &Acc = AccessList[AccIndex];
1426 O <<
" - " << Acc.getKind() <<
" - " << *Acc.getLocalInst() <<
"\n";
1427 if (Acc.getLocalInst() != Acc.getRemoteInst())
1428 O <<
" --> " << *Acc.getRemoteInst()
1430 if (!Acc.isWrittenValueYetUndetermined()) {
1432 O <<
" - c: func " << Acc.getWrittenValue()->getName()
1434 else if (Acc.getWrittenValue())
1435 O <<
" - c: " << *Acc.getWrittenValue() <<
"\n";
1437 O <<
" - c: <unknown>\n";
1444struct AAPointerInfoFloating :
public AAPointerInfoImpl {
1446 AAPointerInfoFloating(
const IRPosition &IRP, Attributor &
A)
1447 : AAPointerInfoImpl(IRP,
A) {}
1450 bool handleAccess(Attributor &
A, Instruction &
I,
1451 std::optional<Value *> Content,
AccessKind Kind,
1454 using namespace AA::PointerInfo;
1456 const DataLayout &
DL =
A.getDataLayout();
1457 TypeSize AccessSize =
DL.getTypeStoreSize(&Ty);
1466 if (!VT || VT->getElementCount().isScalable() ||
1468 (*Content)->getType() != VT ||
1469 DL.getTypeStoreSize(VT->getElementType()).isScalable()) {
1480 int64_t ElementSize =
DL.getTypeStoreSize(ElementType).getFixedValue();
1485 for (
int i = 0, e = VT->getElementCount().getFixedValue(); i != e; ++i) {
1487 ConstContent, ConstantInt::get(
Int32Ty, i));
1494 for (
auto &ElementOffset : ElementOffsets)
1495 ElementOffset += ElementSize;
1508 bool collectConstantsForGEP(Attributor &
A,
const DataLayout &
DL,
1509 OffsetInfo &UsrOI,
const OffsetInfo &PtrOI,
1510 const GEPOperator *
GEP);
1513 void trackStatistics()
const override {
1514 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1518bool AAPointerInfoFloating::collectConstantsForGEP(Attributor &
A,
1519 const DataLayout &
DL,
1521 const OffsetInfo &PtrOI,
1522 const GEPOperator *
GEP) {
1523 unsigned BitWidth =
DL.getIndexTypeSizeInBits(
GEP->getType());
1524 SmallMapVector<Value *, APInt, 4> VariableOffsets;
1527 assert(!UsrOI.isUnknown() && !PtrOI.isUnknown() &&
1528 "Don't look for constant values if the offset has already been "
1529 "determined to be unknown.");
1531 if (!
GEP->collectOffset(
DL,
BitWidth, VariableOffsets, ConstantOffset)) {
1537 << (VariableOffsets.
empty() ?
"" :
"not") <<
" constant "
1541 Union.addToAll(ConstantOffset.getSExtValue());
1546 for (
const auto &VI : VariableOffsets) {
1547 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
1549 if (!PotentialConstantsAA || !PotentialConstantsAA->isValidState()) {
1555 if (PotentialConstantsAA->undefIsContained())
1562 auto &AssumedSet = PotentialConstantsAA->getAssumedSet();
1563 if (AssumedSet.empty())
1567 for (
const auto &ConstOffset : AssumedSet) {
1568 auto CopyPerOffset =
Union;
1569 CopyPerOffset.addToAll(ConstOffset.getSExtValue() *
1570 VI.second.getZExtValue());
1571 Product.merge(CopyPerOffset);
1576 UsrOI = std::move(Union);
1580ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &
A) {
1581 using namespace AA::PointerInfo;
1583 const DataLayout &
DL =
A.getDataLayout();
1584 Value &AssociatedValue = getAssociatedValue();
1586 DenseMap<Value *, OffsetInfo> OffsetInfoMap;
1587 OffsetInfoMap[&AssociatedValue].
insert(0);
1589 auto HandlePassthroughUser = [&](
Value *Usr,
Value *CurPtr,
bool &Follow) {
1600 "CurPtr does not exist in the map!");
1602 auto &UsrOI = OffsetInfoMap[Usr];
1603 auto &PtrOI = OffsetInfoMap[CurPtr];
1604 assert(!PtrOI.isUnassigned() &&
1605 "Cannot pass through if the input Ptr was not visited!");
1611 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
1613 User *Usr =
U.getUser();
1614 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Analyze " << *CurPtr <<
" in " << *Usr
1617 "The current pointer offset should have been seeded!");
1618 assert(!OffsetInfoMap[CurPtr].isUnassigned() &&
1619 "Current pointer should be assigned");
1623 return HandlePassthroughUser(Usr, CurPtr, Follow);
1625 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled constant user " << *CE
1633 auto &UsrOI = OffsetInfoMap[Usr];
1634 auto &PtrOI = OffsetInfoMap[CurPtr];
1636 if (UsrOI.isUnknown())
1639 if (PtrOI.isUnknown()) {
1645 Follow = collectConstantsForGEP(
A,
DL, UsrOI, PtrOI,
GEP);
1651 return HandlePassthroughUser(Usr, CurPtr, Follow);
1656 if (RI->getFunction() == getAssociatedFunction()) {
1657 auto &PtrOI = OffsetInfoMap[CurPtr];
1658 Changed |= setReachesReturn(PtrOI);
1671 auto &UsrOI = PhiIt->second;
1672 auto &PtrOI = OffsetInfoMap[CurPtr];
1676 if (PtrOI.isUnknown()) {
1677 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand offset unknown "
1678 << *CurPtr <<
" in " << *
PHI <<
"\n");
1679 Follow = !UsrOI.isUnknown();
1685 if (UsrOI == PtrOI) {
1686 assert(!PtrOI.isUnassigned() &&
1687 "Cannot assign if the current Ptr was not visited!");
1688 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant (so far)");
1698 auto It = OffsetInfoMap.
find(CurPtrBase);
1699 if (It == OffsetInfoMap.
end()) {
1700 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand is too complex "
1701 << *CurPtr <<
" in " << *
PHI
1702 <<
" (base: " << *CurPtrBase <<
")\n");
1716 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
1717 *
PHI->getFunction());
1719 auto BaseOI = It->getSecond();
1720 BaseOI.addToAll(
Offset.getZExtValue());
1721 if (IsFirstPHIUser || BaseOI == UsrOI) {
1722 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant " << *CurPtr
1723 <<
" in " << *Usr <<
"\n");
1724 return HandlePassthroughUser(Usr, CurPtr, Follow);
1728 dbgs() <<
"[AAPointerInfo] PHI operand pointer offset mismatch "
1729 << *CurPtr <<
" in " << *
PHI <<
"\n");
1748 if (!handleAccess(
A, *LoadI,
nullptr, AK,
1749 OffsetInfoMap[CurPtr].Offsets,
Changed,
1755 return II->isAssumeLikeIntrinsic();
1766 }
while (FromI && FromI != ToI);
1771 auto IsValidAssume = [&](IntrinsicInst &IntrI) {
1772 if (IntrI.getIntrinsicID() != Intrinsic::assume)
1775 if (IntrI.getParent() == BB) {
1776 if (IsImpactedInRange(LoadI->getNextNode(), &IntrI))
1782 if ((*PredIt) != BB)
1787 if (SuccBB == IntrBB)
1793 if (IsImpactedInRange(LoadI->getNextNode(), BB->
getTerminator()))
1795 if (IsImpactedInRange(&IntrBB->
front(), &IntrI))
1801 std::pair<Value *, IntrinsicInst *> Assumption;
1802 for (
const Use &LoadU : LoadI->uses()) {
1804 if (!CmpI->isEquality() || !CmpI->isTrueWhenEqual())
1806 for (
const Use &CmpU : CmpI->uses()) {
1808 if (!IsValidAssume(*IntrI))
1810 int Idx = CmpI->getOperandUse(0) == LoadU;
1811 Assumption = {CmpI->getOperand(Idx), IntrI};
1816 if (Assumption.first)
1821 if (!Assumption.first || !Assumption.second)
1825 << *Assumption.second <<
": " << *LoadI
1826 <<
" == " << *Assumption.first <<
"\n");
1827 bool UsedAssumedInformation =
false;
1828 std::optional<Value *> Content =
nullptr;
1829 if (Assumption.first)
1831 A.getAssumedSimplified(*Assumption.first, *
this,
1833 return handleAccess(
1834 A, *Assumption.second, Content, AccessKind::AK_ASSUMPTION,
1835 OffsetInfoMap[CurPtr].Offsets,
Changed, *LoadI->getType());
1840 for (
auto *OtherOp : OtherOps) {
1841 if (OtherOp == CurPtr) {
1844 <<
"[AAPointerInfo] Escaping use in store like instruction " <<
I
1856 bool UsedAssumedInformation =
false;
1857 std::optional<Value *> Content =
nullptr;
1859 Content =
A.getAssumedSimplified(
1861 return handleAccess(
A,
I, Content, AK, OffsetInfoMap[CurPtr].Offsets,
1866 return HandleStoreLike(*StoreI, StoreI->getValueOperand(),
1867 *StoreI->getValueOperand()->getType(),
1868 {StoreI->getValueOperand()}, AccessKind::AK_W);
1870 return HandleStoreLike(*RMWI,
nullptr, *RMWI->getValOperand()->getType(),
1871 {RMWI->getValOperand()}, AccessKind::AK_RW);
1873 return HandleStoreLike(
1874 *CXI,
nullptr, *CXI->getNewValOperand()->getType(),
1875 {CXI->getCompareOperand(), CXI->getNewValOperand()},
1882 A.getInfoCache().getTargetLibraryInfoForFunction(*CB->
getFunction());
1887 const auto *CSArgPI =
A.getAAFor<AAPointerInfo>(
1893 Changed = translateAndAddState(
A, *CSArgPI, OffsetInfoMap[CurPtr], *CB,
1896 if (!CSArgPI->reachesReturn())
1897 return isValidState();
1900 if (!Callee ||
Callee->arg_size() <= ArgNo)
1902 bool UsedAssumedInformation =
false;
1903 auto ReturnedValue =
A.getAssumedSimplified(
1908 auto *Arg =
Callee->getArg(ArgNo);
1909 if (ReturnedArg && Arg != ReturnedArg)
1911 bool IsRetMustAcc = IsArgMustAcc && (ReturnedArg == Arg);
1912 const auto *CSRetPI =
A.getAAFor<AAPointerInfo>(
1916 OffsetInfo OI = OffsetInfoMap[CurPtr];
1917 CSArgPI->addReturnedOffsetsTo(OI);
1919 translateAndAddState(
A, *CSRetPI, OI, *CB, IsRetMustAcc) |
Changed;
1920 return isValidState();
1922 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Call user not handled " << *CB
1927 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] User not handled " << *Usr <<
"\n");
1930 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
1931 assert(OffsetInfoMap.
count(OldU) &&
"Old use should be known already!");
1932 assert(!OffsetInfoMap[OldU].isUnassigned() &&
"Old use should be assinged");
1933 if (OffsetInfoMap.
count(NewU)) {
1935 if (!(OffsetInfoMap[NewU] == OffsetInfoMap[OldU])) {
1936 dbgs() <<
"[AAPointerInfo] Equivalent use callback failed: "
1937 << OffsetInfoMap[NewU] <<
" vs " << OffsetInfoMap[OldU]
1941 return OffsetInfoMap[NewU] == OffsetInfoMap[OldU];
1944 return HandlePassthroughUser(NewU.get(), OldU.
get(), Unused);
1946 if (!
A.checkForAllUses(UsePred, *
this, AssociatedValue,
1948 true, EquivalentUseCB)) {
1949 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Check for all uses failed, abort!\n");
1950 return indicatePessimisticFixpoint();
1954 dbgs() <<
"Accesses by bin after update:\n";
1961struct AAPointerInfoReturned final : AAPointerInfoImpl {
1962 AAPointerInfoReturned(
const IRPosition &IRP, Attributor &
A)
1963 : AAPointerInfoImpl(IRP,
A) {}
1967 return indicatePessimisticFixpoint();
1971 void trackStatistics()
const override {
1972 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1976struct AAPointerInfoArgument final : AAPointerInfoFloating {
1977 AAPointerInfoArgument(
const IRPosition &IRP, Attributor &
A)
1978 : AAPointerInfoFloating(IRP,
A) {}
1981 void trackStatistics()
const override {
1982 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1986struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
1987 AAPointerInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
1988 : AAPointerInfoFloating(IRP,
A) {}
1992 using namespace AA::PointerInfo;
1998 if (
auto Length =
MI->getLengthInBytes())
1999 LengthVal =
Length->getSExtValue();
2000 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
2003 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled memory intrinsic "
2005 return indicatePessimisticFixpoint();
2008 ArgNo == 0 ? AccessKind::AK_MUST_WRITE : AccessKind::AK_MUST_READ;
2010 Changed | addAccess(
A, {0, LengthVal}, *
MI,
nullptr,
Kind,
nullptr);
2013 dbgs() <<
"Accesses by bin after update:\n";
2024 Argument *Arg = getAssociatedArgument();
2028 A.getAAFor<AAPointerInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
2029 if (ArgAA && ArgAA->getState().isValidState())
2030 return translateAndAddStateFromCallee(
A, *ArgAA,
2033 return indicatePessimisticFixpoint();
2036 bool IsKnownNoCapture;
2038 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNoCapture))
2039 return indicatePessimisticFixpoint();
2041 bool IsKnown =
false;
2043 return ChangeStatus::UNCHANGED;
2046 ReadOnly ? AccessKind::AK_MAY_READ : AccessKind::AK_MAY_READ_WRITE;
2052 void trackStatistics()
const override {
2053 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2057struct AAPointerInfoCallSiteReturned final : AAPointerInfoFloating {
2058 AAPointerInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2059 : AAPointerInfoFloating(IRP,
A) {}
2062 void trackStatistics()
const override {
2063 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2071struct AANoUnwindImpl : AANoUnwind {
2072 AANoUnwindImpl(
const IRPosition &IRP, Attributor &
A) : AANoUnwind(IRP,
A) {}
2078 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2082 const std::string getAsStr(Attributor *
A)
const override {
2083 return getAssumed() ?
"nounwind" :
"may-unwind";
2089 (unsigned)Instruction::Invoke, (
unsigned)Instruction::CallBr,
2090 (unsigned)Instruction::Call, (
unsigned)Instruction::CleanupRet,
2091 (unsigned)Instruction::CatchSwitch, (
unsigned)Instruction::Resume};
2094 if (!
I.mayThrow(
true))
2098 bool IsKnownNoUnwind;
2106 bool UsedAssumedInformation =
false;
2107 if (!
A.checkForAllInstructions(CheckForNoUnwind, *
this, Opcodes,
2108 UsedAssumedInformation))
2109 return indicatePessimisticFixpoint();
2111 return ChangeStatus::UNCHANGED;
2115struct AANoUnwindFunction final :
public AANoUnwindImpl {
2116 AANoUnwindFunction(
const IRPosition &IRP, Attributor &
A)
2117 : AANoUnwindImpl(IRP,
A) {}
2124struct AANoUnwindCallSite final
2125 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl> {
2126 AANoUnwindCallSite(
const IRPosition &IRP, Attributor &
A)
2127 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl>(IRP,
A) {}
2138 case Intrinsic::nvvm_barrier_cta_sync_aligned_all:
2139 case Intrinsic::nvvm_barrier_cta_sync_aligned_count:
2140 case Intrinsic::nvvm_barrier0_and:
2141 case Intrinsic::nvvm_barrier0_or:
2142 case Intrinsic::nvvm_barrier0_popc:
2144 case Intrinsic::amdgcn_s_barrier:
2145 if (ExecutedAligned)
2168 switch (
I->getOpcode()) {
2169 case Instruction::AtomicRMW:
2172 case Instruction::Store:
2175 case Instruction::Load:
2180 "New atomic operations need to be known in the attributor.");
2192 return !
MI->isVolatile();
2208 const std::string getAsStr(Attributor *
A)
const override {
2209 return getAssumed() ?
"nosync" :
"may-sync";
2225 if (
I.mayReadOrWriteMemory())
2239 bool UsedAssumedInformation =
false;
2240 if (!
A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *
this,
2241 UsedAssumedInformation) ||
2242 !
A.checkForAllCallLikeInstructions(CheckForNoSync, *
this,
2243 UsedAssumedInformation))
2244 return indicatePessimisticFixpoint();
2249struct AANoSyncFunction final :
public AANoSyncImpl {
2250 AANoSyncFunction(
const IRPosition &IRP, Attributor &
A)
2251 : AANoSyncImpl(IRP,
A) {}
2258struct AANoSyncCallSite final : AACalleeToCallSite<AANoSync, AANoSyncImpl> {
2259 AANoSyncCallSite(
const IRPosition &IRP, Attributor &
A)
2260 : AACalleeToCallSite<AANoSync, AANoSyncImpl>(IRP,
A) {}
2270struct AANoFreeImpl :
public AANoFree {
2271 AANoFreeImpl(
const IRPosition &IRP, Attributor &
A) : AANoFree(IRP,
A) {}
2277 DepClassTy::NONE, IsKnown));
2287 DepClassTy::REQUIRED, IsKnown);
2290 bool UsedAssumedInformation =
false;
2291 if (!
A.checkForAllCallLikeInstructions(CheckForNoFree, *
this,
2292 UsedAssumedInformation))
2293 return indicatePessimisticFixpoint();
2294 return ChangeStatus::UNCHANGED;
2298 const std::string getAsStr(Attributor *
A)
const override {
2299 return getAssumed() ?
"nofree" :
"may-free";
2303struct AANoFreeFunction final :
public AANoFreeImpl {
2304 AANoFreeFunction(
const IRPosition &IRP, Attributor &
A)
2305 : AANoFreeImpl(IRP,
A) {}
2312struct AANoFreeCallSite final : AACalleeToCallSite<AANoFree, AANoFreeImpl> {
2313 AANoFreeCallSite(
const IRPosition &IRP, Attributor &
A)
2314 : AACalleeToCallSite<AANoFree, AANoFreeImpl>(IRP,
A) {}
2321struct AANoFreeFloating : AANoFreeImpl {
2322 AANoFreeFloating(
const IRPosition &IRP, Attributor &
A)
2323 : AANoFreeImpl(IRP,
A) {}
2330 const IRPosition &IRP = getIRPosition();
2335 DepClassTy::OPTIONAL, IsKnown))
2336 return ChangeStatus::UNCHANGED;
2338 Value &AssociatedValue = getIRPosition().getAssociatedValue();
2339 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
2351 DepClassTy::REQUIRED, IsKnown);
2368 if (!
A.checkForAllUses(Pred, *
this, AssociatedValue))
2369 return indicatePessimisticFixpoint();
2371 return ChangeStatus::UNCHANGED;
2376struct AANoFreeArgument final : AANoFreeFloating {
2377 AANoFreeArgument(
const IRPosition &IRP, Attributor &
A)
2378 : AANoFreeFloating(IRP,
A) {}
2385struct AANoFreeCallSiteArgument final : AANoFreeFloating {
2386 AANoFreeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2387 : AANoFreeFloating(IRP,
A) {}
2395 Argument *Arg = getAssociatedArgument();
2397 return indicatePessimisticFixpoint();
2401 DepClassTy::REQUIRED, IsKnown))
2402 return ChangeStatus::UNCHANGED;
2403 return indicatePessimisticFixpoint();
2411struct AANoFreeReturned final : AANoFreeFloating {
2412 AANoFreeReturned(
const IRPosition &IRP, Attributor &
A)
2413 : AANoFreeFloating(IRP,
A) {
2428 void trackStatistics()
const override {}
2432struct AANoFreeCallSiteReturned final : AANoFreeFloating {
2433 AANoFreeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2434 : AANoFreeFloating(IRP,
A) {}
2437 return ChangeStatus::UNCHANGED;
2448 bool IgnoreSubsumingPositions) {
2450 AttrKinds.
push_back(Attribute::NonNull);
2453 AttrKinds.
push_back(Attribute::Dereferenceable);
2454 if (
A.hasAttr(IRP, AttrKinds, IgnoreSubsumingPositions, Attribute::NonNull))
2461 if (!Fn->isDeclaration()) {
2471 bool UsedAssumedInformation =
false;
2472 if (!
A.checkForAllInstructions(
2474 Worklist.push_back({*cast<ReturnInst>(I).getReturnValue(), &I});
2478 UsedAssumedInformation,
false,
true))
2490 Attribute::NonNull)});
2495static int64_t getKnownNonNullAndDerefBytesForUse(
2496 Attributor &
A,
const AbstractAttribute &QueryingAA,
Value &AssociatedValue,
2497 const Use *U,
const Instruction *
I,
bool &IsNonNull,
bool &TrackUse) {
2500 const Value *UseV =
U->get();
2521 const DataLayout &
DL =
A.getInfoCache().getDL();
2525 U, {Attribute::NonNull, Attribute::Dereferenceable})) {
2542 bool IsKnownNonNull;
2545 IsNonNull |= IsKnownNonNull;
2548 return DerefAA ? DerefAA->getKnownDereferenceableBytes() : 0;
2552 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
2553 Loc->Size.isScalable() ||
I->isVolatile())
2559 if (
Base &&
Base == &AssociatedValue) {
2560 int64_t DerefBytes = Loc->Size.getValue() +
Offset;
2562 return std::max(int64_t(0), DerefBytes);
2569 int64_t DerefBytes = Loc->Size.getValue();
2571 return std::max(int64_t(0), DerefBytes);
2577struct AANonNullImpl : AANonNull {
2578 AANonNullImpl(
const IRPosition &IRP, Attributor &
A) : AANonNull(IRP,
A) {}
2582 Value &
V = *getAssociatedValue().stripPointerCasts();
2584 indicatePessimisticFixpoint();
2588 if (Instruction *CtxI = getCtxI())
2589 followUsesInMBEC(*
this,
A, getState(), *CtxI);
2593 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
2594 AANonNull::StateType &State) {
2595 bool IsNonNull =
false;
2596 bool TrackUse =
false;
2597 getKnownNonNullAndDerefBytesForUse(
A, *
this, getAssociatedValue(), U,
I,
2598 IsNonNull, TrackUse);
2599 State.setKnown(IsNonNull);
2604 const std::string getAsStr(Attributor *
A)
const override {
2605 return getAssumed() ?
"nonnull" :
"may-null";
2610struct AANonNullFloating :
public AANonNullImpl {
2611 AANonNullFloating(
const IRPosition &IRP, Attributor &
A)
2612 : AANonNullImpl(IRP,
A) {}
2616 auto CheckIRP = [&](
const IRPosition &IRP) {
2617 bool IsKnownNonNull;
2619 A, *
this, IRP, DepClassTy::OPTIONAL, IsKnownNonNull);
2623 bool UsedAssumedInformation =
false;
2624 Value *AssociatedValue = &getAssociatedValue();
2626 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
2631 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
2637 return AA::hasAssumedIRAttr<Attribute::NonNull>(
2638 A, this, IRPosition::value(*Op), DepClassTy::OPTIONAL,
2641 return ChangeStatus::UNCHANGED;
2645 DepClassTy::OPTIONAL, IsKnown) &&
2648 DepClassTy::OPTIONAL, IsKnown))
2649 return ChangeStatus::UNCHANGED;
2656 if (AVIRP == getIRPosition() || !CheckIRP(AVIRP))
2657 return indicatePessimisticFixpoint();
2658 return ChangeStatus::UNCHANGED;
2661 for (
const auto &VAC : Values)
2663 return indicatePessimisticFixpoint();
2665 return ChangeStatus::UNCHANGED;
2673struct AANonNullReturned final
2674 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2675 false, AANonNull::IRAttributeKind, false> {
2676 AANonNullReturned(
const IRPosition &IRP, Attributor &
A)
2677 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2682 const std::string getAsStr(Attributor *
A)
const override {
2683 return getAssumed() ?
"nonnull" :
"may-null";
2691struct AANonNullArgument final
2692 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
2693 AANonNullArgument(
const IRPosition &IRP, Attributor &
A)
2694 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP,
A) {}
2700struct AANonNullCallSiteArgument final : AANonNullFloating {
2701 AANonNullCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2702 : AANonNullFloating(IRP,
A) {}
2709struct AANonNullCallSiteReturned final
2710 : AACalleeToCallSite<AANonNull, AANonNullImpl> {
2711 AANonNullCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2712 : AACalleeToCallSite<AANonNull, AANonNullImpl>(IRP,
A) {}
2721struct AAMustProgressImpl :
public AAMustProgress {
2722 AAMustProgressImpl(
const IRPosition &IRP, Attributor &
A)
2723 : AAMustProgress(IRP,
A) {}
2729 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2734 const std::string getAsStr(Attributor *
A)
const override {
2735 return getAssumed() ?
"mustprogress" :
"may-not-progress";
2739struct AAMustProgressFunction final : AAMustProgressImpl {
2740 AAMustProgressFunction(
const IRPosition &IRP, Attributor &
A)
2741 : AAMustProgressImpl(IRP,
A) {}
2747 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnown)) {
2749 return indicateOptimisticFixpoint();
2750 return ChangeStatus::UNCHANGED;
2753 auto CheckForMustProgress = [&](AbstractCallSite ACS) {
2755 bool IsKnownMustProgress;
2757 A,
this, IPos, DepClassTy::REQUIRED, IsKnownMustProgress,
2761 bool AllCallSitesKnown =
true;
2762 if (!
A.checkForAllCallSites(CheckForMustProgress, *
this,
2765 return indicatePessimisticFixpoint();
2767 return ChangeStatus::UNCHANGED;
2771 void trackStatistics()
const override {
2777struct AAMustProgressCallSite final : AAMustProgressImpl {
2778 AAMustProgressCallSite(
const IRPosition &IRP, Attributor &
A)
2779 : AAMustProgressImpl(IRP,
A) {}
2788 bool IsKnownMustProgress;
2790 A,
this, FnPos, DepClassTy::REQUIRED, IsKnownMustProgress))
2791 return indicatePessimisticFixpoint();
2792 return ChangeStatus::UNCHANGED;
2796 void trackStatistics()
const override {
2805struct AANoRecurseImpl :
public AANoRecurse {
2806 AANoRecurseImpl(
const IRPosition &IRP, Attributor &
A) : AANoRecurse(IRP,
A) {}
2812 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2817 const std::string getAsStr(Attributor *
A)
const override {
2818 return getAssumed() ?
"norecurse" :
"may-recurse";
2822struct AANoRecurseFunction final : AANoRecurseImpl {
2823 AANoRecurseFunction(
const IRPosition &IRP, Attributor &
A)
2824 : AANoRecurseImpl(IRP,
A) {}
2830 auto CallSitePred = [&](AbstractCallSite ACS) {
2831 bool IsKnownNoRecurse;
2835 DepClassTy::NONE, IsKnownNoRecurse))
2837 return IsKnownNoRecurse;
2839 bool UsedAssumedInformation =
false;
2840 if (
A.checkForAllCallSites(CallSitePred, *
this,
true,
2841 UsedAssumedInformation)) {
2847 if (!UsedAssumedInformation)
2848 indicateOptimisticFixpoint();
2849 return ChangeStatus::UNCHANGED;
2852 const AAInterFnReachability *EdgeReachability =
2853 A.getAAFor<AAInterFnReachability>(*
this, getIRPosition(),
2854 DepClassTy::REQUIRED);
2855 if (EdgeReachability && EdgeReachability->
canReach(
A, *getAnchorScope()))
2856 return indicatePessimisticFixpoint();
2857 return ChangeStatus::UNCHANGED;
2864struct AANoRecurseCallSite final
2865 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl> {
2866 AANoRecurseCallSite(
const IRPosition &IRP, Attributor &
A)
2867 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl>(IRP,
A) {}
2877struct AANonConvergentImpl :
public AANonConvergent {
2878 AANonConvergentImpl(
const IRPosition &IRP, Attributor &
A)
2879 : AANonConvergent(IRP,
A) {}
2882 const std::string getAsStr(Attributor *
A)
const override {
2883 return getAssumed() ?
"non-convergent" :
"may-be-convergent";
2887struct AANonConvergentFunction final : AANonConvergentImpl {
2888 AANonConvergentFunction(
const IRPosition &IRP, Attributor &
A)
2889 : AANonConvergentImpl(IRP,
A) {}
2895 auto CalleeIsNotConvergent = [&](
Instruction &Inst) {
2898 if (!Callee ||
Callee->isIntrinsic()) {
2901 if (
Callee->isDeclaration()) {
2902 return !
Callee->hasFnAttribute(Attribute::Convergent);
2904 const auto *ConvergentAA =
A.getAAFor<AANonConvergent>(
2906 return ConvergentAA && ConvergentAA->isAssumedNotConvergent();
2909 bool UsedAssumedInformation =
false;
2910 if (!
A.checkForAllCallLikeInstructions(CalleeIsNotConvergent, *
this,
2911 UsedAssumedInformation)) {
2912 return indicatePessimisticFixpoint();
2914 return ChangeStatus::UNCHANGED;
2918 if (isKnownNotConvergent() &&
2919 A.hasAttr(getIRPosition(), Attribute::Convergent)) {
2920 A.removeAttrs(getIRPosition(), {Attribute::Convergent});
2921 return ChangeStatus::CHANGED;
2923 return ChangeStatus::UNCHANGED;
2933struct AAUndefinedBehaviorImpl :
public AAUndefinedBehavior {
2934 AAUndefinedBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
2935 : AAUndefinedBehavior(IRP,
A) {}
2940 const size_t UBPrevSize = KnownUBInsts.size();
2941 const size_t NoUBPrevSize = AssumedNoUBInsts.size();
2945 if (
I.isVolatile() &&
I.mayWriteToMemory())
2949 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
2958 "Expected pointer operand of memory accessing instruction");
2962 std::optional<Value *> SimplifiedPtrOp =
2963 stopOnUndefOrAssumed(
A, PtrOp, &
I);
2964 if (!SimplifiedPtrOp || !*SimplifiedPtrOp)
2966 const Value *PtrOpVal = *SimplifiedPtrOp;
2972 AssumedNoUBInsts.insert(&
I);
2984 AssumedNoUBInsts.insert(&
I);
2986 KnownUBInsts.insert(&
I);
2995 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3002 if (BrInst->isUnconditional())
3007 std::optional<Value *> SimplifiedCond =
3008 stopOnUndefOrAssumed(
A, BrInst->getCondition(), BrInst);
3009 if (!SimplifiedCond || !*SimplifiedCond)
3011 AssumedNoUBInsts.insert(&
I);
3019 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3028 for (
unsigned idx = 0; idx < CB.
arg_size(); idx++) {
3034 if (idx >=
Callee->arg_size())
3046 bool IsKnownNoUndef;
3048 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNoUndef);
3049 if (!IsKnownNoUndef)
3051 bool UsedAssumedInformation =
false;
3052 std::optional<Value *> SimplifiedVal =
3055 if (UsedAssumedInformation)
3057 if (SimplifiedVal && !*SimplifiedVal)
3060 KnownUBInsts.insert(&
I);
3066 bool IsKnownNonNull;
3068 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNonNull);
3070 KnownUBInsts.insert(&
I);
3079 std::optional<Value *> SimplifiedRetValue =
3080 stopOnUndefOrAssumed(
A, RI.getReturnValue(), &
I);
3081 if (!SimplifiedRetValue || !*SimplifiedRetValue)
3099 bool IsKnownNonNull;
3104 KnownUBInsts.insert(&
I);
3110 bool UsedAssumedInformation =
false;
3111 A.checkForAllInstructions(InspectMemAccessInstForUB, *
this,
3112 {Instruction::Load, Instruction::Store,
3113 Instruction::AtomicCmpXchg,
3114 Instruction::AtomicRMW},
3115 UsedAssumedInformation,
3117 A.checkForAllInstructions(InspectBrInstForUB, *
this, {Instruction::Br},
3118 UsedAssumedInformation,
3120 A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *
this,
3121 UsedAssumedInformation);
3125 if (!getAnchorScope()->getReturnType()->isVoidTy()) {
3127 if (!
A.isAssumedDead(ReturnIRP,
this,
nullptr, UsedAssumedInformation)) {
3128 bool IsKnownNoUndef;
3130 A,
this, ReturnIRP, DepClassTy::NONE, IsKnownNoUndef);
3132 A.checkForAllInstructions(InspectReturnInstForUB, *
this,
3133 {Instruction::Ret}, UsedAssumedInformation,
3138 if (NoUBPrevSize != AssumedNoUBInsts.size() ||
3139 UBPrevSize != KnownUBInsts.size())
3140 return ChangeStatus::CHANGED;
3141 return ChangeStatus::UNCHANGED;
3144 bool isKnownToCauseUB(Instruction *
I)
const override {
3145 return KnownUBInsts.count(
I);
3148 bool isAssumedToCauseUB(Instruction *
I)
const override {
3155 switch (
I->getOpcode()) {
3156 case Instruction::Load:
3157 case Instruction::Store:
3158 case Instruction::AtomicCmpXchg:
3159 case Instruction::AtomicRMW:
3160 return !AssumedNoUBInsts.count(
I);
3161 case Instruction::Br: {
3163 if (BrInst->isUnconditional())
3165 return !AssumedNoUBInsts.count(
I);
3174 if (KnownUBInsts.empty())
3175 return ChangeStatus::UNCHANGED;
3176 for (Instruction *
I : KnownUBInsts)
3177 A.changeToUnreachableAfterManifest(
I);
3178 return ChangeStatus::CHANGED;
3182 const std::string getAsStr(Attributor *
A)
const override {
3183 return getAssumed() ?
"undefined-behavior" :
"no-ub";
3211 SmallPtrSet<Instruction *, 8> KnownUBInsts;
3215 SmallPtrSet<Instruction *, 8> AssumedNoUBInsts;
3226 std::optional<Value *> stopOnUndefOrAssumed(Attributor &
A,
Value *V,
3228 bool UsedAssumedInformation =
false;
3229 std::optional<Value *> SimplifiedV =
3232 if (!UsedAssumedInformation) {
3237 KnownUBInsts.insert(
I);
3238 return std::nullopt;
3245 KnownUBInsts.insert(
I);
3246 return std::nullopt;
3252struct AAUndefinedBehaviorFunction final : AAUndefinedBehaviorImpl {
3253 AAUndefinedBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
3254 : AAUndefinedBehaviorImpl(IRP,
A) {}
3257 void trackStatistics()
const override {
3258 STATS_DECL(UndefinedBehaviorInstruction, Instruction,
3259 "Number of instructions known to have UB");
3261 KnownUBInsts.size();
3272static bool mayContainUnboundedCycle(Function &
F, Attributor &
A) {
3273 ScalarEvolution *SE =
3274 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
F);
3275 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
F);
3281 for (scc_iterator<Function *> SCCI =
scc_begin(&
F); !SCCI.isAtEnd(); ++SCCI)
3282 if (SCCI.hasCycle())
3292 for (
auto *L : LI->getLoopsInPreorder()) {
3299struct AAWillReturnImpl :
public AAWillReturn {
3300 AAWillReturnImpl(
const IRPosition &IRP, Attributor &
A)
3301 : AAWillReturn(IRP,
A) {}
3307 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
3312 bool isImpliedByMustprogressAndReadonly(Attributor &
A,
bool KnownOnly) {
3313 if (!
A.hasAttr(getIRPosition(), {Attribute::MustProgress}))
3318 return IsKnown || !KnownOnly;
3324 if (isImpliedByMustprogressAndReadonly(
A,
false))
3325 return ChangeStatus::UNCHANGED;
3331 A,
this, IPos, DepClassTy::REQUIRED, IsKnown)) {
3337 bool IsKnownNoRecurse;
3339 A,
this, IPos, DepClassTy::REQUIRED, IsKnownNoRecurse);
3342 bool UsedAssumedInformation =
false;
3343 if (!
A.checkForAllCallLikeInstructions(CheckForWillReturn, *
this,
3344 UsedAssumedInformation))
3345 return indicatePessimisticFixpoint();
3347 return ChangeStatus::UNCHANGED;
3351 const std::string getAsStr(Attributor *
A)
const override {
3352 return getAssumed() ?
"willreturn" :
"may-noreturn";
3356struct AAWillReturnFunction final : AAWillReturnImpl {
3357 AAWillReturnFunction(
const IRPosition &IRP, Attributor &
A)
3358 : AAWillReturnImpl(IRP,
A) {}
3362 AAWillReturnImpl::initialize(
A);
3365 assert(
F &&
"Did expect an anchor function");
3366 if (
F->isDeclaration() || mayContainUnboundedCycle(*
F,
A))
3367 indicatePessimisticFixpoint();
3375struct AAWillReturnCallSite final
3376 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl> {
3377 AAWillReturnCallSite(
const IRPosition &IRP, Attributor &
A)
3378 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl>(IRP,
A) {}
3382 if (isImpliedByMustprogressAndReadonly(
A,
false))
3383 return ChangeStatus::UNCHANGED;
3385 return AACalleeToCallSite::updateImpl(
A);
3407 const ToTy *
To =
nullptr;
3434 if (!ES || ES->
empty()) {
3435 ExclusionSet = nullptr;
3436 }
else if (MakeUnique) {
3437 ExclusionSet =
A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ES);
3462 if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))
3464 return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);
3468#define DefineKeys(ToTy) \
3470 ReachabilityQueryInfo<ToTy> \
3471 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::EmptyKey = \
3472 ReachabilityQueryInfo<ToTy>( \
3473 DenseMapInfo<const Instruction *>::getEmptyKey(), \
3474 DenseMapInfo<const ToTy *>::getEmptyKey()); \
3476 ReachabilityQueryInfo<ToTy> \
3477 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::TombstoneKey = \
3478 ReachabilityQueryInfo<ToTy>( \
3479 DenseMapInfo<const Instruction *>::getTombstoneKey(), \
3480 DenseMapInfo<const ToTy *>::getTombstoneKey());
3489template <
typename BaseTy,
typename ToTy>
3490struct CachedReachabilityAA :
public BaseTy {
3491 using RQITy = ReachabilityQueryInfo<ToTy>;
3493 CachedReachabilityAA(
const IRPosition &IRP, Attributor &
A) : BaseTy(IRP,
A) {}
3496 bool isQueryAA()
const override {
return true; }
3501 for (
unsigned u = 0,
e = QueryVector.size();
u <
e; ++
u) {
3502 RQITy *RQI = QueryVector[
u];
3503 if (RQI->Result == RQITy::Reachable::No &&
3505 Changed = ChangeStatus::CHANGED;
3511 bool IsTemporaryRQI) = 0;
3513 bool rememberResult(Attributor &
A,
typename RQITy::Reachable
Result,
3514 RQITy &RQI,
bool UsedExclusionSet,
bool IsTemporaryRQI) {
3519 QueryCache.erase(&RQI);
3525 if (
Result == RQITy::Reachable::Yes || !UsedExclusionSet) {
3526 RQITy PlainRQI(RQI.From, RQI.To);
3527 if (!QueryCache.count(&PlainRQI)) {
3528 RQITy *RQIPtr =
new (
A.Allocator) RQITy(RQI.From, RQI.To);
3530 QueryVector.push_back(RQIPtr);
3531 QueryCache.insert(RQIPtr);
3536 if (IsTemporaryRQI &&
Result != RQITy::Reachable::Yes && UsedExclusionSet) {
3537 assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&
3538 "Did not expect empty set!");
3539 RQITy *RQIPtr =
new (
A.Allocator)
3540 RQITy(
A, *RQI.From, *RQI.To, RQI.ExclusionSet,
true);
3541 assert(RQIPtr->Result == RQITy::Reachable::No &&
"Already reachable?");
3543 assert(!QueryCache.count(RQIPtr));
3544 QueryVector.push_back(RQIPtr);
3545 QueryCache.insert(RQIPtr);
3548 if (
Result == RQITy::Reachable::No && IsTemporaryRQI)
3549 A.registerForUpdate(*
this);
3550 return Result == RQITy::Reachable::Yes;
3553 const std::string getAsStr(Attributor *
A)
const override {
3555 return "#queries(" + std::to_string(QueryVector.size()) +
")";
3558 bool checkQueryCache(Attributor &
A, RQITy &StackRQI,
3559 typename RQITy::Reachable &
Result) {
3560 if (!this->getState().isValidState()) {
3561 Result = RQITy::Reachable::Yes;
3567 if (StackRQI.ExclusionSet) {
3568 RQITy PlainRQI(StackRQI.From, StackRQI.To);
3569 auto It = QueryCache.find(&PlainRQI);
3570 if (It != QueryCache.end() && (*It)->Result == RQITy::Reachable::No) {
3571 Result = RQITy::Reachable::No;
3576 auto It = QueryCache.find(&StackRQI);
3577 if (It != QueryCache.end()) {
3584 QueryCache.insert(&StackRQI);
3590 DenseSet<RQITy *> QueryCache;
3593struct AAIntraFnReachabilityFunction final
3594 :
public CachedReachabilityAA<AAIntraFnReachability, Instruction> {
3595 using Base = CachedReachabilityAA<AAIntraFnReachability, Instruction>;
3596 AAIntraFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
3598 DT =
A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(
3602 bool isAssumedReachable(
3603 Attributor &
A,
const Instruction &From,
const Instruction &To,
3605 auto *NonConstThis =
const_cast<AAIntraFnReachabilityFunction *
>(
this);
3609 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
3611 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
3612 return NonConstThis->isReachableImpl(
A, StackRQI,
3614 return Result == RQITy::Reachable::Yes;
3621 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3624 [&](
const auto &DeadEdge) {
3625 return LivenessAA->isEdgeDead(DeadEdge.first,
3629 return LivenessAA->isAssumedDead(BB);
3631 return ChangeStatus::UNCHANGED;
3635 return Base::updateImpl(
A);
3639 bool IsTemporaryRQI)
override {
3641 bool UsedExclusionSet =
false;
3646 while (IP && IP != &To) {
3647 if (ExclusionSet && IP != Origin && ExclusionSet->
count(IP)) {
3648 UsedExclusionSet =
true;
3656 const BasicBlock *FromBB = RQI.From->getParent();
3657 const BasicBlock *ToBB = RQI.To->getParent();
3659 "Not an intra-procedural query!");
3663 if (FromBB == ToBB &&
3664 WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
3665 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3670 if (!WillReachInBlock(ToBB->
front(), *RQI.To, RQI.ExclusionSet))
3671 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3675 SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
3676 if (RQI.ExclusionSet)
3677 for (
auto *
I : *RQI.ExclusionSet)
3678 if (
I->getFunction() == Fn)
3679 ExclusionBlocks.
insert(
I->getParent());
3682 if (ExclusionBlocks.
count(FromBB) &&
3685 return rememberResult(
A, RQITy::Reachable::No, RQI,
true, IsTemporaryRQI);
3688 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3689 if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {
3690 DeadBlocks.insert(ToBB);
3691 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3695 SmallPtrSet<const BasicBlock *, 16> Visited;
3699 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> LocalDeadEdges;
3700 while (!Worklist.
empty()) {
3702 if (!Visited.
insert(BB).second)
3704 for (
const BasicBlock *SuccBB :
successors(BB)) {
3705 if (LivenessAA && LivenessAA->isEdgeDead(BB, SuccBB)) {
3706 LocalDeadEdges.
insert({BB, SuccBB});
3711 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3714 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3717 if (ExclusionBlocks.
count(SuccBB)) {
3718 UsedExclusionSet =
true;
3725 DeadEdges.insert_range(LocalDeadEdges);
3726 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3731 void trackStatistics()
const override {}
3736 DenseSet<const BasicBlock *> DeadBlocks;
3740 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> DeadEdges;
3743 const DominatorTree *DT =
nullptr;
3751 bool IgnoreSubsumingPositions) {
3752 assert(ImpliedAttributeKind == Attribute::NoAlias &&
3753 "Unexpected attribute kind");
3759 IgnoreSubsumingPositions =
true;
3770 if (
A.hasAttr(IRP, {Attribute::ByVal, Attribute::NoAlias},
3771 IgnoreSubsumingPositions, Attribute::NoAlias))
3781 "Noalias is a pointer attribute");
3784 const std::string getAsStr(
Attributor *
A)
const override {
3785 return getAssumed() ?
"noalias" :
"may-alias";
3790struct AANoAliasFloating final : AANoAliasImpl {
3791 AANoAliasFloating(
const IRPosition &IRP, Attributor &
A)
3792 : AANoAliasImpl(IRP,
A) {}
3797 return indicatePessimisticFixpoint();
3801 void trackStatistics()
const override {
3807struct AANoAliasArgument final
3808 : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> {
3809 using Base = AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>;
3810 AANoAliasArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
3823 DepClassTy::OPTIONAL, IsKnownNoSycn))
3824 return Base::updateImpl(
A);
3829 return Base::updateImpl(
A);
3833 bool UsedAssumedInformation =
false;
3834 if (
A.checkForAllCallSites(
3835 [](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *
this,
3836 true, UsedAssumedInformation))
3837 return Base::updateImpl(
A);
3845 return indicatePessimisticFixpoint();
3852struct AANoAliasCallSiteArgument final : AANoAliasImpl {
3853 AANoAliasCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
3854 : AANoAliasImpl(IRP,
A) {}
3858 bool mayAliasWithArgument(Attributor &
A, AAResults *&AAR,
3859 const AAMemoryBehavior &MemBehaviorAA,
3860 const CallBase &CB,
unsigned OtherArgNo) {
3862 if (this->getCalleeArgNo() == (
int)OtherArgNo)
3870 auto *CBArgMemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
3874 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadNone()) {
3875 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3882 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadOnly() &&
3884 A.recordDependence(MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3885 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3891 AAR =
A.getInfoCache().getAnalysisResultForFunction<AAManager>(
3895 bool IsAliasing = !AAR || !AAR->
isNoAlias(&getAssociatedValue(), ArgOp);
3897 "callsite arguments: "
3898 << getAssociatedValue() <<
" " << *ArgOp <<
" => "
3899 << (IsAliasing ?
"" :
"no-") <<
"alias \n");
3904 bool isKnownNoAliasDueToNoAliasPreservation(
3905 Attributor &
A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA) {
3918 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
3934 bool IsKnownNoCapture;
3937 DepClassTy::OPTIONAL, IsKnownNoCapture))
3943 A, *UserI, *getCtxI(), *
this,
nullptr,
3944 [ScopeFn](
const Function &Fn) {
return &Fn != ScopeFn; }))
3959 LLVM_DEBUG(
dbgs() <<
"[AANoAliasCSArg] Unknown user: " << *UserI <<
"\n");
3963 bool IsKnownNoCapture;
3964 const AANoCapture *NoCaptureAA =
nullptr;
3966 A,
this, VIRP, DepClassTy::NONE, IsKnownNoCapture,
false, &NoCaptureAA);
3967 if (!IsAssumedNoCapture &&
3969 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue())) {
3971 dbgs() <<
"[AANoAliasCSArg] " << getAssociatedValue()
3972 <<
" cannot be noalias as it is potentially captured\n");
3977 A.recordDependence(*NoCaptureAA, *
this, DepClassTy::OPTIONAL);
3983 for (
unsigned OtherArgNo = 0; OtherArgNo < CB.
arg_size(); OtherArgNo++)
3984 if (mayAliasWithArgument(
A, AAR, MemBehaviorAA, CB, OtherArgNo))
3994 auto *MemBehaviorAA =
3995 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
3997 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3998 return ChangeStatus::UNCHANGED;
4001 bool IsKnownNoAlias;
4004 A,
this, VIRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
4006 <<
" is not no-alias at the definition\n");
4007 return indicatePessimisticFixpoint();
4010 AAResults *AAR =
nullptr;
4011 if (MemBehaviorAA &&
4012 isKnownNoAliasDueToNoAliasPreservation(
A, AAR, *MemBehaviorAA)) {
4014 dbgs() <<
"[AANoAlias] No-Alias deduced via no-alias preservation\n");
4015 return ChangeStatus::UNCHANGED;
4018 return indicatePessimisticFixpoint();
4026struct AANoAliasReturned final : AANoAliasImpl {
4027 AANoAliasReturned(
const IRPosition &IRP, Attributor &
A)
4028 : AANoAliasImpl(IRP,
A) {}
4033 auto CheckReturnValue = [&](
Value &RV) ->
bool {
4044 bool IsKnownNoAlias;
4046 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoAlias))
4049 bool IsKnownNoCapture;
4050 const AANoCapture *NoCaptureAA =
nullptr;
4052 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
4054 return IsAssumedNoCapture ||
4058 if (!
A.checkForAllReturnedValues(CheckReturnValue, *
this))
4059 return indicatePessimisticFixpoint();
4061 return ChangeStatus::UNCHANGED;
4069struct AANoAliasCallSiteReturned final
4070 : AACalleeToCallSite<AANoAlias, AANoAliasImpl> {
4071 AANoAliasCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4072 : AACalleeToCallSite<AANoAlias, AANoAliasImpl>(IRP,
A) {}
4082struct AAIsDeadValueImpl :
public AAIsDead {
4083 AAIsDeadValueImpl(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4086 bool isAssumedDead()
const override {
return isAssumed(IS_DEAD); }
4089 bool isKnownDead()
const override {
return isKnown(IS_DEAD); }
4092 bool isAssumedDead(
const BasicBlock *BB)
const override {
return false; }
4095 bool isKnownDead(
const BasicBlock *BB)
const override {
return false; }
4098 bool isAssumedDead(
const Instruction *
I)
const override {
4099 return I == getCtxI() && isAssumedDead();
4103 bool isKnownDead(
const Instruction *
I)
const override {
4104 return isAssumedDead(
I) && isKnownDead();
4108 const std::string getAsStr(Attributor *
A)
const override {
4109 return isAssumedDead() ?
"assumed-dead" :
"assumed-live";
4113 bool areAllUsesAssumedDead(Attributor &
A,
Value &V) {
4115 if (
V.getType()->isVoidTy() ||
V.use_empty())
4121 if (!
A.isRunOn(*
I->getFunction()))
4123 bool UsedAssumedInformation =
false;
4124 std::optional<Constant *>
C =
4125 A.getAssumedConstant(V, *
this, UsedAssumedInformation);
4130 auto UsePred = [&](
const Use &
U,
bool &Follow) {
return false; };
4135 return A.checkForAllUses(UsePred, *
this, V,
false,
4136 DepClassTy::REQUIRED,
4141 bool isAssumedSideEffectFree(Attributor &
A, Instruction *
I) {
4151 bool IsKnownNoUnwind;
4153 A,
this, CallIRP, DepClassTy::OPTIONAL, IsKnownNoUnwind))
4161struct AAIsDeadFloating :
public AAIsDeadValueImpl {
4162 AAIsDeadFloating(
const IRPosition &IRP, Attributor &
A)
4163 : AAIsDeadValueImpl(IRP,
A) {}
4167 AAIsDeadValueImpl::initialize(
A);
4170 indicatePessimisticFixpoint();
4175 if (!isAssumedSideEffectFree(
A,
I)) {
4177 indicatePessimisticFixpoint();
4179 removeAssumedBits(HAS_NO_EFFECT);
4183 bool isDeadFence(Attributor &
A, FenceInst &FI) {
4184 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
4186 if (!ExecDomainAA || !ExecDomainAA->isNoOpFence(FI))
4188 A.recordDependence(*ExecDomainAA, *
this, DepClassTy::OPTIONAL);
4192 bool isDeadStore(Attributor &
A, StoreInst &SI,
4193 SmallSetVector<Instruction *, 8> *AssumeOnlyInst =
nullptr) {
4195 if (
SI.isVolatile())
4201 bool UsedAssumedInformation =
false;
4202 if (!AssumeOnlyInst) {
4203 PotentialCopies.clear();
4205 UsedAssumedInformation)) {
4208 <<
"[AAIsDead] Could not determine potential copies of store!\n");
4212 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Store has " << PotentialCopies.size()
4213 <<
" potential copies.\n");
4215 InformationCache &InfoCache =
A.getInfoCache();
4218 UsedAssumedInformation))
4222 auto &UserI = cast<Instruction>(*U.getUser());
4223 if (InfoCache.isOnlyUsedByAssume(UserI)) {
4225 AssumeOnlyInst->insert(&UserI);
4228 return A.isAssumedDead(U,
this,
nullptr, UsedAssumedInformation);
4234 <<
" is assumed live!\n");
4240 const std::string getAsStr(Attributor *
A)
const override {
4244 return "assumed-dead-store";
4247 return "assumed-dead-fence";
4248 return AAIsDeadValueImpl::getAsStr(
A);
4255 if (!isDeadStore(
A, *SI))
4256 return indicatePessimisticFixpoint();
4258 if (!isDeadFence(
A, *FI))
4259 return indicatePessimisticFixpoint();
4261 if (!isAssumedSideEffectFree(
A,
I))
4262 return indicatePessimisticFixpoint();
4263 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4264 return indicatePessimisticFixpoint();
4269 bool isRemovableStore()
const override {
4270 return isAssumed(IS_REMOVABLE) &&
isa<StoreInst>(&getAssociatedValue());
4275 Value &
V = getAssociatedValue();
4282 SmallSetVector<Instruction *, 8> AssumeOnlyInst;
4283 bool IsDead = isDeadStore(
A, *SI, &AssumeOnlyInst);
4286 A.deleteAfterManifest(*
I);
4287 for (
size_t i = 0; i < AssumeOnlyInst.
size(); ++i) {
4289 for (
auto *Usr : AOI->
users())
4291 A.deleteAfterManifest(*AOI);
4297 A.deleteAfterManifest(*FI);
4301 A.deleteAfterManifest(*
I);
4309 void trackStatistics()
const override {
4315 SmallSetVector<Value *, 4> PotentialCopies;
4318struct AAIsDeadArgument :
public AAIsDeadFloating {
4319 AAIsDeadArgument(
const IRPosition &IRP, Attributor &
A)
4320 : AAIsDeadFloating(IRP,
A) {}
4324 Argument &Arg = *getAssociatedArgument();
4325 if (
A.isValidFunctionSignatureRewrite(Arg, {}))
4326 if (
A.registerFunctionSignatureRewrite(
4330 return ChangeStatus::CHANGED;
4332 return ChangeStatus::UNCHANGED;
4339struct AAIsDeadCallSiteArgument :
public AAIsDeadValueImpl {
4340 AAIsDeadCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
4341 : AAIsDeadValueImpl(IRP,
A) {}
4345 AAIsDeadValueImpl::initialize(
A);
4347 indicatePessimisticFixpoint();
4356 Argument *Arg = getAssociatedArgument();
4358 return indicatePessimisticFixpoint();
4360 auto *ArgAA =
A.getAAFor<AAIsDead>(*
this, ArgPos, DepClassTy::REQUIRED);
4362 return indicatePessimisticFixpoint();
4371 "Expected undef values to be filtered out!");
4373 if (
A.changeUseAfterManifest(U, UV))
4374 return ChangeStatus::CHANGED;
4375 return ChangeStatus::UNCHANGED;
4382struct AAIsDeadCallSiteReturned :
public AAIsDeadFloating {
4383 AAIsDeadCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4384 : AAIsDeadFloating(IRP,
A) {}
4387 bool isAssumedDead()
const override {
4388 return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;
4393 AAIsDeadFloating::initialize(
A);
4395 indicatePessimisticFixpoint();
4400 IsAssumedSideEffectFree = isAssumedSideEffectFree(
A, getCtxI());
4406 if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(
A, getCtxI())) {
4407 IsAssumedSideEffectFree =
false;
4408 Changed = ChangeStatus::CHANGED;
4410 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4411 return indicatePessimisticFixpoint();
4416 void trackStatistics()
const override {
4417 if (IsAssumedSideEffectFree)
4424 const std::string getAsStr(Attributor *
A)
const override {
4425 return isAssumedDead()
4427 : (getAssumed() ?
"assumed-dead-users" :
"assumed-live");
4431 bool IsAssumedSideEffectFree =
true;
4434struct AAIsDeadReturned :
public AAIsDeadValueImpl {
4435 AAIsDeadReturned(
const IRPosition &IRP, Attributor &
A)
4436 : AAIsDeadValueImpl(IRP,
A) {}
4441 bool UsedAssumedInformation =
false;
4442 A.checkForAllInstructions([](Instruction &) {
return true; }, *
this,
4443 {Instruction::Ret}, UsedAssumedInformation);
4445 auto PredForCallSite = [&](AbstractCallSite ACS) {
4446 if (ACS.isCallbackCall() || !ACS.getInstruction())
4448 return areAllUsesAssumedDead(
A, *ACS.getInstruction());
4451 if (!
A.checkForAllCallSites(PredForCallSite, *
this,
true,
4452 UsedAssumedInformation))
4453 return indicatePessimisticFixpoint();
4455 return ChangeStatus::UNCHANGED;
4461 bool AnyChange =
false;
4462 UndefValue &UV = *
UndefValue::get(getAssociatedFunction()->getReturnType());
4469 bool UsedAssumedInformation =
false;
4470 A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
4471 UsedAssumedInformation);
4472 return AnyChange ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
4479struct AAIsDeadFunction :
public AAIsDead {
4480 AAIsDeadFunction(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4485 assert(
F &&
"Did expect an anchor function");
4486 if (!isAssumedDeadInternalFunction(
A)) {
4487 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4488 assumeLive(
A,
F->getEntryBlock());
4492 bool isAssumedDeadInternalFunction(Attributor &
A) {
4493 if (!getAnchorScope()->hasLocalLinkage())
4495 bool UsedAssumedInformation =
false;
4496 return A.checkForAllCallSites([](AbstractCallSite) {
return false; }, *
this,
4497 true, UsedAssumedInformation);
4501 const std::string getAsStr(Attributor *
A)
const override {
4502 return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) +
"/" +
4503 std::to_string(getAnchorScope()->
size()) +
"][#TBEP " +
4504 std::to_string(ToBeExploredFrom.size()) +
"][#KDE " +
4505 std::to_string(KnownDeadEnds.size()) +
"]";
4510 assert(getState().isValidState() &&
4511 "Attempted to manifest an invalid state!");
4516 if (AssumedLiveBlocks.empty()) {
4517 A.deleteAfterManifest(
F);
4518 return ChangeStatus::CHANGED;
4524 bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(
F);
4526 KnownDeadEnds.set_union(ToBeExploredFrom);
4527 for (
const Instruction *DeadEndI : KnownDeadEnds) {
4531 bool IsKnownNoReturn;
4539 A.registerInvokeWithDeadSuccessor(
const_cast<InvokeInst &
>(*
II));
4541 A.changeToUnreachableAfterManifest(
4542 const_cast<Instruction *
>(DeadEndI->getNextNode()));
4543 HasChanged = ChangeStatus::CHANGED;
4546 STATS_DECL(AAIsDead, BasicBlock,
"Number of dead basic blocks deleted.");
4547 for (BasicBlock &BB :
F)
4548 if (!AssumedLiveBlocks.count(&BB)) {
4549 A.deleteAfterManifest(BB);
4551 HasChanged = ChangeStatus::CHANGED;
4560 bool isEdgeDead(
const BasicBlock *From,
const BasicBlock *To)
const override {
4563 "Used AAIsDead of the wrong function");
4564 return isValidState() && !AssumedLiveEdges.count(std::make_pair(From, To));
4568 void trackStatistics()
const override {}
4571 bool isAssumedDead()
const override {
return false; }
4574 bool isKnownDead()
const override {
return false; }
4577 bool isAssumedDead(
const BasicBlock *BB)
const override {
4579 "BB must be in the same anchor scope function.");
4583 return !AssumedLiveBlocks.count(BB);
4587 bool isKnownDead(
const BasicBlock *BB)
const override {
4588 return getKnown() && isAssumedDead(BB);
4592 bool isAssumedDead(
const Instruction *
I)
const override {
4593 assert(
I->getParent()->getParent() == getAnchorScope() &&
4594 "Instruction must be in the same anchor scope function.");
4601 if (!AssumedLiveBlocks.count(
I->getParent()))
4607 if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))
4615 bool isKnownDead(
const Instruction *
I)
const override {
4616 return getKnown() && isAssumedDead(
I);
4621 bool assumeLive(Attributor &
A,
const BasicBlock &BB) {
4622 if (!AssumedLiveBlocks.insert(&BB).second)
4629 for (
const Instruction &
I : BB)
4632 if (
F->hasLocalLinkage())
4633 A.markLiveInternalFunction(*
F);
4639 SmallSetVector<const Instruction *, 8> ToBeExploredFrom;
4642 SmallSetVector<const Instruction *, 8> KnownDeadEnds;
4645 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> AssumedLiveEdges;
4648 DenseSet<const BasicBlock *> AssumedLiveBlocks;
4652identifyAliveSuccessors(Attributor &
A,
const CallBase &CB,
4653 AbstractAttribute &AA,
4654 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4657 bool IsKnownNoReturn;
4660 return !IsKnownNoReturn;
4669identifyAliveSuccessors(Attributor &
A,
const InvokeInst &
II,
4670 AbstractAttribute &AA,
4671 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4672 bool UsedAssumedInformation =
4678 if (AAIsDeadFunction::mayCatchAsynchronousExceptions(*
II.getFunction())) {
4679 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4683 bool IsKnownNoUnwind;
4686 UsedAssumedInformation |= !IsKnownNoUnwind;
4688 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4691 return UsedAssumedInformation;
4695identifyAliveSuccessors(Attributor &
A,
const BranchInst &BI,
4696 AbstractAttribute &AA,
4697 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4698 bool UsedAssumedInformation =
false;
4702 std::optional<Constant *>
C =
4703 A.getAssumedConstant(*BI.
getCondition(), AA, UsedAssumedInformation);
4713 UsedAssumedInformation =
false;
4716 return UsedAssumedInformation;
4720identifyAliveSuccessors(Attributor &
A,
const SwitchInst &SI,
4721 AbstractAttribute &AA,
4722 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4723 bool UsedAssumedInformation =
false;
4727 UsedAssumedInformation)) {
4729 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4734 if (Values.
empty() ||
4735 (Values.
size() == 1 &&
4738 return UsedAssumedInformation;
4741 Type &Ty = *
SI.getCondition()->getType();
4742 SmallPtrSet<ConstantInt *, 8>
Constants;
4743 auto CheckForConstantInt = [&](
Value *
V) {
4751 if (!
all_of(Values, [&](AA::ValueAndContext &VAC) {
4752 return CheckForConstantInt(VAC.
getValue());
4754 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4756 return UsedAssumedInformation;
4759 unsigned MatchedCases = 0;
4760 for (
const auto &CaseIt :
SI.cases()) {
4761 if (
Constants.count(CaseIt.getCaseValue())) {
4763 AliveSuccessors.
push_back(&CaseIt.getCaseSuccessor()->front());
4770 AliveSuccessors.
push_back(&
SI.getDefaultDest()->front());
4771 return UsedAssumedInformation;
4777 if (AssumedLiveBlocks.empty()) {
4778 if (isAssumedDeadInternalFunction(
A))
4782 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4783 assumeLive(
A,
F->getEntryBlock());
4787 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Live [" << AssumedLiveBlocks.size() <<
"/"
4788 << getAnchorScope()->
size() <<
"] BBs and "
4789 << ToBeExploredFrom.size() <<
" exploration points and "
4790 << KnownDeadEnds.size() <<
" known dead ends\n");
4795 ToBeExploredFrom.end());
4796 decltype(ToBeExploredFrom) NewToBeExploredFrom;
4799 while (!Worklist.
empty()) {
4806 I =
I->getNextNode();
4808 AliveSuccessors.
clear();
4810 bool UsedAssumedInformation =
false;
4811 switch (
I->getOpcode()) {
4815 "Expected non-terminators to be handled already!");
4816 for (
const BasicBlock *SuccBB :
successors(
I->getParent()))
4819 case Instruction::Call:
4821 *
this, AliveSuccessors);
4823 case Instruction::Invoke:
4825 *
this, AliveSuccessors);
4827 case Instruction::Br:
4829 *
this, AliveSuccessors);
4831 case Instruction::Switch:
4833 *
this, AliveSuccessors);
4837 if (UsedAssumedInformation) {
4838 NewToBeExploredFrom.insert(
I);
4839 }
else if (AliveSuccessors.
empty() ||
4840 (
I->isTerminator() &&
4841 AliveSuccessors.
size() <
I->getNumSuccessors())) {
4842 if (KnownDeadEnds.insert(
I))
4847 << AliveSuccessors.
size() <<
" UsedAssumedInformation: "
4848 << UsedAssumedInformation <<
"\n");
4850 for (
const Instruction *AliveSuccessor : AliveSuccessors) {
4851 if (!
I->isTerminator()) {
4852 assert(AliveSuccessors.size() == 1 &&
4853 "Non-terminator expected to have a single successor!");
4857 auto Edge = std::make_pair(
I->getParent(), AliveSuccessor->getParent());
4858 if (AssumedLiveEdges.insert(
Edge).second)
4860 if (assumeLive(
A, *AliveSuccessor->getParent()))
4867 if (NewToBeExploredFrom.size() != ToBeExploredFrom.size() ||
4868 llvm::any_of(NewToBeExploredFrom, [&](
const Instruction *
I) {
4869 return !ToBeExploredFrom.count(I);
4872 ToBeExploredFrom = std::move(NewToBeExploredFrom);
4881 if (ToBeExploredFrom.empty() &&
4882 getAnchorScope()->
size() == AssumedLiveBlocks.size() &&
4883 llvm::all_of(KnownDeadEnds, [](
const Instruction *DeadEndI) {
4884 return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;
4886 return indicatePessimisticFixpoint();
4891struct AAIsDeadCallSite final : AAIsDeadFunction {
4892 AAIsDeadCallSite(
const IRPosition &IRP, Attributor &
A)
4893 : AAIsDeadFunction(IRP,
A) {}
4902 "supported for call sites yet!");
4907 return indicatePessimisticFixpoint();
4911 void trackStatistics()
const override {}
4918struct AADereferenceableImpl : AADereferenceable {
4919 AADereferenceableImpl(
const IRPosition &IRP, Attributor &
A)
4920 : AADereferenceable(IRP,
A) {}
4921 using StateType = DerefState;
4925 Value &
V = *getAssociatedValue().stripPointerCasts();
4927 A.getAttrs(getIRPosition(),
4928 {Attribute::Dereferenceable, Attribute::DereferenceableOrNull},
4931 takeKnownDerefBytesMaximum(Attr.getValueAsInt());
4934 bool IsKnownNonNull;
4936 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNonNull);
4938 bool CanBeNull, CanBeFreed;
4939 takeKnownDerefBytesMaximum(
V.getPointerDereferenceableBytes(
4940 A.getDataLayout(), CanBeNull, CanBeFreed));
4942 if (Instruction *CtxI = getCtxI())
4943 followUsesInMBEC(*
this,
A, getState(), *CtxI);
4948 StateType &getState()
override {
return *
this; }
4949 const StateType &getState()
const override {
return *
this; }
4953 void addAccessedBytesForUse(Attributor &
A,
const Use *U,
const Instruction *
I,
4954 DerefState &State) {
4955 const Value *UseV =
U->get();
4960 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
I->isVolatile())
4965 Loc->Ptr,
Offset,
A.getDataLayout(),
true);
4966 if (
Base &&
Base == &getAssociatedValue())
4967 State.addAccessedBytes(
Offset, Loc->Size.getValue());
4971 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
4972 AADereferenceable::StateType &State) {
4973 bool IsNonNull =
false;
4974 bool TrackUse =
false;
4975 int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
4976 A, *
this, getAssociatedValue(), U,
I, IsNonNull, TrackUse);
4977 LLVM_DEBUG(
dbgs() <<
"[AADereferenceable] Deref bytes: " << DerefBytes
4978 <<
" for instruction " << *
I <<
"\n");
4980 addAccessedBytesForUse(
A, U,
I, State);
4981 State.takeKnownDerefBytesMaximum(DerefBytes);
4988 bool IsKnownNonNull;
4990 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
4991 if (IsAssumedNonNull &&
4992 A.hasAttr(getIRPosition(), Attribute::DereferenceableOrNull)) {
4993 A.removeAttrs(getIRPosition(), {Attribute::DereferenceableOrNull});
4994 return ChangeStatus::CHANGED;
4999 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5000 SmallVectorImpl<Attribute> &Attrs)
const override {
5002 bool IsKnownNonNull;
5004 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5005 if (IsAssumedNonNull)
5006 Attrs.emplace_back(Attribute::getWithDereferenceableBytes(
5007 Ctx, getAssumedDereferenceableBytes()));
5009 Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes(
5010 Ctx, getAssumedDereferenceableBytes()));
5014 const std::string getAsStr(Attributor *
A)
const override {
5015 if (!getAssumedDereferenceableBytes())
5016 return "unknown-dereferenceable";
5017 bool IsKnownNonNull;
5018 bool IsAssumedNonNull =
false;
5021 *
A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5022 return std::string(
"dereferenceable") +
5023 (IsAssumedNonNull ?
"" :
"_or_null") +
5024 (isAssumedGlobal() ?
"_globally" :
"") +
"<" +
5025 std::to_string(getKnownDereferenceableBytes()) +
"-" +
5026 std::to_string(getAssumedDereferenceableBytes()) +
">" +
5027 (!
A ?
" [non-null is unknown]" :
"");
5032struct AADereferenceableFloating : AADereferenceableImpl {
5033 AADereferenceableFloating(
const IRPosition &IRP, Attributor &
A)
5034 : AADereferenceableImpl(IRP,
A) {}
5039 bool UsedAssumedInformation =
false;
5041 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5043 Values.
push_back({getAssociatedValue(), getCtxI()});
5046 Stripped = Values.
size() != 1 ||
5047 Values.
front().getValue() != &getAssociatedValue();
5050 const DataLayout &
DL =
A.getDataLayout();
5053 auto VisitValueCB = [&](
const Value &
V) ->
bool {
5055 DL.getIndexSizeInBits(
V.getType()->getPointerAddressSpace());
5056 APInt
Offset(IdxWidth, 0);
5061 const auto *AA =
A.getAAFor<AADereferenceable>(
5063 int64_t DerefBytes = 0;
5064 if (!AA || (!Stripped &&
this == AA)) {
5067 bool CanBeNull, CanBeFreed;
5069 Base->getPointerDereferenceableBytes(
DL, CanBeNull, CanBeFreed);
5070 T.GlobalState.indicatePessimisticFixpoint();
5073 DerefBytes =
DS.DerefBytesState.getAssumed();
5074 T.GlobalState &=
DS.GlobalState;
5080 int64_t OffsetSExt =
Offset.getSExtValue();
5084 T.takeAssumedDerefBytesMinimum(
5085 std::max(int64_t(0), DerefBytes - OffsetSExt));
5090 T.takeKnownDerefBytesMaximum(
5091 std::max(int64_t(0), DerefBytes - OffsetSExt));
5092 T.indicatePessimisticFixpoint();
5093 }
else if (OffsetSExt > 0) {
5099 T.indicatePessimisticFixpoint();
5103 return T.isValidState();
5106 for (
const auto &VAC : Values)
5107 if (!VisitValueCB(*VAC.
getValue()))
5108 return indicatePessimisticFixpoint();
5114 void trackStatistics()
const override {
5120struct AADereferenceableReturned final
5121 : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl> {
5123 AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl>;
5124 AADereferenceableReturned(
const IRPosition &IRP, Attributor &
A)
5128 void trackStatistics()
const override {
5134struct AADereferenceableArgument final
5135 : AAArgumentFromCallSiteArguments<AADereferenceable,
5136 AADereferenceableImpl> {
5138 AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl>;
5139 AADereferenceableArgument(
const IRPosition &IRP, Attributor &
A)
5143 void trackStatistics()
const override {
5149struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {
5150 AADereferenceableCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5151 : AADereferenceableFloating(IRP,
A) {}
5154 void trackStatistics()
const override {
5160struct AADereferenceableCallSiteReturned final
5161 : AACalleeToCallSite<AADereferenceable, AADereferenceableImpl> {
5162 using Base = AACalleeToCallSite<AADereferenceable, AADereferenceableImpl>;
5163 AADereferenceableCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5167 void trackStatistics()
const override {
5177static unsigned getKnownAlignForUse(Attributor &
A, AAAlign &QueryingAA,
5178 Value &AssociatedValue,
const Use *U,
5179 const Instruction *
I,
bool &TrackUse) {
5188 if (
GEP->hasAllConstantIndices())
5193 switch (
II->getIntrinsicID()) {
5194 case Intrinsic::ptrmask: {
5196 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5198 const auto *AlignAA =
A.getAAFor<AAAlign>(
5200 if (ConstVals && ConstVals->isValidState() && ConstVals->isAtFixpoint()) {
5201 unsigned ShiftValue = std::min(ConstVals->getAssumedMinTrailingZeros(),
5203 Align ConstAlign(UINT64_C(1) << ShiftValue);
5204 if (ConstAlign >= AlignAA->getKnownAlign())
5205 return Align(1).value();
5208 return AlignAA->getKnownAlign().
value();
5226 MA = MaybeAlign(AlignAA->getKnownAlign());
5229 const DataLayout &
DL =
A.getDataLayout();
5230 const Value *UseV =
U->get();
5232 if (
SI->getPointerOperand() == UseV)
5233 MA =
SI->getAlign();
5235 if (LI->getPointerOperand() == UseV)
5236 MA = LI->getAlign();
5238 if (AI->getPointerOperand() == UseV)
5239 MA = AI->getAlign();
5241 if (AI->getPointerOperand() == UseV)
5242 MA = AI->getAlign();
5248 unsigned Alignment = MA->value();
5252 if (
Base == &AssociatedValue) {
5257 uint32_t
gcd = std::gcd(uint32_t(
abs((int32_t)
Offset)), Alignment);
5265struct AAAlignImpl : AAAlign {
5266 AAAlignImpl(
const IRPosition &IRP, Attributor &
A) : AAAlign(IRP,
A) {}
5271 A.getAttrs(getIRPosition(), {Attribute::Alignment},
Attrs);
5273 takeKnownMaximum(Attr.getValueAsInt());
5275 Value &
V = *getAssociatedValue().stripPointerCasts();
5276 takeKnownMaximum(
V.getPointerAlignment(
A.getDataLayout()).value());
5278 if (Instruction *CtxI = getCtxI())
5279 followUsesInMBEC(*
this,
A, getState(), *CtxI);
5287 Value &AssociatedValue = getAssociatedValue();
5289 return ChangeStatus::UNCHANGED;
5291 for (
const Use &U : AssociatedValue.
uses()) {
5293 if (
SI->getPointerOperand() == &AssociatedValue)
5294 if (
SI->getAlign() < getAssumedAlign()) {
5296 "Number of times alignment added to a store");
5297 SI->setAlignment(getAssumedAlign());
5298 InstrChanged = ChangeStatus::CHANGED;
5301 if (LI->getPointerOperand() == &AssociatedValue)
5302 if (LI->getAlign() < getAssumedAlign()) {
5303 LI->setAlignment(getAssumedAlign());
5305 "Number of times alignment added to a load");
5306 InstrChanged = ChangeStatus::CHANGED;
5309 if (RMW->getPointerOperand() == &AssociatedValue) {
5310 if (RMW->getAlign() < getAssumedAlign()) {
5312 "Number of times alignment added to atomicrmw");
5314 RMW->setAlignment(getAssumedAlign());
5315 InstrChanged = ChangeStatus::CHANGED;
5319 if (CAS->getPointerOperand() == &AssociatedValue) {
5320 if (CAS->getAlign() < getAssumedAlign()) {
5322 "Number of times alignment added to cmpxchg");
5323 CAS->setAlignment(getAssumedAlign());
5324 InstrChanged = ChangeStatus::CHANGED;
5332 Align InheritAlign =
5333 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5334 if (InheritAlign >= getAssumedAlign())
5335 return InstrChanged;
5336 return Changed | InstrChanged;
5344 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5345 SmallVectorImpl<Attribute> &Attrs)
const override {
5346 if (getAssumedAlign() > 1)
5348 Attribute::getWithAlignment(Ctx,
Align(getAssumedAlign())));
5352 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5353 AAAlign::StateType &State) {
5354 bool TrackUse =
false;
5356 unsigned int KnownAlign =
5357 getKnownAlignForUse(
A, *
this, getAssociatedValue(), U,
I, TrackUse);
5358 State.takeKnownMaximum(KnownAlign);
5364 const std::string getAsStr(Attributor *
A)
const override {
5365 return "align<" + std::to_string(getKnownAlign().value()) +
"-" +
5366 std::to_string(getAssumedAlign().value()) +
">";
5371struct AAAlignFloating : AAAlignImpl {
5372 AAAlignFloating(
const IRPosition &IRP, Attributor &
A) : AAAlignImpl(IRP,
A) {}
5376 const DataLayout &
DL =
A.getDataLayout();
5379 bool UsedAssumedInformation =
false;
5381 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5383 Values.
push_back({getAssociatedValue(), getCtxI()});
5386 Stripped = Values.
size() != 1 ||
5387 Values.
front().getValue() != &getAssociatedValue();
5391 auto VisitValueCB = [&](
Value &
V) ->
bool {
5395 DepClassTy::REQUIRED);
5396 if (!AA || (!Stripped &&
this == AA)) {
5398 unsigned Alignment = 1;
5411 Alignment =
V.getPointerAlignment(
DL).value();
5414 T.takeKnownMaximum(Alignment);
5415 T.indicatePessimisticFixpoint();
5418 const AAAlign::StateType &
DS = AA->
getState();
5421 return T.isValidState();
5424 for (
const auto &VAC : Values) {
5425 if (!VisitValueCB(*VAC.
getValue()))
5426 return indicatePessimisticFixpoint();
5439struct AAAlignReturned final
5440 : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {
5441 using Base = AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>;
5442 AAAlignReturned(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5449struct AAAlignArgument final
5450 : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {
5451 using Base = AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>;
5452 AAAlignArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5459 if (
A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))
5460 return ChangeStatus::UNCHANGED;
5461 return Base::manifest(
A);
5468struct AAAlignCallSiteArgument final : AAAlignFloating {
5469 AAAlignCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5470 : AAAlignFloating(IRP,
A) {}
5477 if (Argument *Arg = getAssociatedArgument())
5478 if (
A.getInfoCache().isInvolvedInMustTailCall(*Arg))
5479 return ChangeStatus::UNCHANGED;
5481 Align InheritAlign =
5482 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5483 if (InheritAlign >= getAssumedAlign())
5484 Changed = ChangeStatus::UNCHANGED;
5491 if (Argument *Arg = getAssociatedArgument()) {
5494 const auto *ArgAlignAA =
A.getAAFor<AAAlign>(
5497 takeKnownMaximum(ArgAlignAA->getKnownAlign().value());
5507struct AAAlignCallSiteReturned final
5508 : AACalleeToCallSite<AAAlign, AAAlignImpl> {
5509 using Base = AACalleeToCallSite<AAAlign, AAAlignImpl>;
5510 AAAlignCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5516 switch (
II->getIntrinsicID()) {
5517 case Intrinsic::ptrmask: {
5521 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5523 if (ConstVals && ConstVals->isValidState()) {
5524 unsigned ShiftValue =
5525 std::min(ConstVals->getAssumedMinTrailingZeros(),
5526 Value::MaxAlignmentExponent);
5527 Alignment =
Align(UINT64_C(1) << ShiftValue);
5531 const auto *AlignAA =
5533 DepClassTy::REQUIRED);
5535 Alignment = std::max(AlignAA->getAssumedAlign(), Alignment);
5542 std::min(this->getAssumedAlign(), Alignment).value());
5549 return Base::updateImpl(
A);
5558struct AANoReturnImpl :
public AANoReturn {
5559 AANoReturnImpl(
const IRPosition &IRP, Attributor &
A) : AANoReturn(IRP,
A) {}
5565 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
5570 const std::string getAsStr(Attributor *
A)
const override {
5571 return getAssumed() ?
"noreturn" :
"may-return";
5576 auto CheckForNoReturn = [](
Instruction &) {
return false; };
5577 bool UsedAssumedInformation =
false;
5578 if (!
A.checkForAllInstructions(CheckForNoReturn, *
this,
5579 {(unsigned)Instruction::Ret},
5580 UsedAssumedInformation))
5581 return indicatePessimisticFixpoint();
5582 return ChangeStatus::UNCHANGED;
5586struct AANoReturnFunction final : AANoReturnImpl {
5587 AANoReturnFunction(
const IRPosition &IRP, Attributor &
A)
5588 : AANoReturnImpl(IRP,
A) {}
5595struct AANoReturnCallSite final
5596 : AACalleeToCallSite<AANoReturn, AANoReturnImpl> {
5597 AANoReturnCallSite(
const IRPosition &IRP, Attributor &
A)
5598 : AACalleeToCallSite<AANoReturn, AANoReturnImpl>(IRP,
A) {}
5609struct AAInstanceInfoImpl :
public AAInstanceInfo {
5610 AAInstanceInfoImpl(
const IRPosition &IRP, Attributor &
A)
5611 : AAInstanceInfo(IRP,
A) {}
5615 Value &
V = getAssociatedValue();
5617 if (
C->isThreadDependent())
5618 indicatePessimisticFixpoint();
5620 indicateOptimisticFixpoint();
5626 indicateOptimisticFixpoint();
5631 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
5634 indicatePessimisticFixpoint();
5644 Value &
V = getAssociatedValue();
5647 Scope =
I->getFunction();
5650 if (!
Scope->hasLocalLinkage())
5654 return indicateOptimisticFixpoint();
5656 bool IsKnownNoRecurse;
5662 auto UsePred = [&](
const Use &
U,
bool &Follow) {
5677 if (!Callee || !
Callee->hasLocalLinkage())
5681 const auto *ArgInstanceInfoAA =
A.getAAFor<AAInstanceInfo>(
5683 DepClassTy::OPTIONAL);
5684 if (!ArgInstanceInfoAA ||
5685 !ArgInstanceInfoAA->isAssumedUniqueForAnalysis())
5690 A, *CB, *Scope, *
this,
nullptr,
5691 [Scope](
const Function &Fn) {
return &Fn !=
Scope; }))
5698 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
5700 auto *Ptr =
SI->getPointerOperand()->stripPointerCasts();
5708 if (!
A.checkForAllUses(UsePred, *
this, V,
true,
5709 DepClassTy::OPTIONAL,
5710 true, EquivalentUseCB))
5711 return indicatePessimisticFixpoint();
5717 const std::string getAsStr(Attributor *
A)
const override {
5718 return isAssumedUniqueForAnalysis() ?
"<unique [fAa]>" :
"<unknown>";
5722 void trackStatistics()
const override {}
5726struct AAInstanceInfoFloating : AAInstanceInfoImpl {
5727 AAInstanceInfoFloating(
const IRPosition &IRP, Attributor &
A)
5728 : AAInstanceInfoImpl(IRP,
A) {}
5732struct AAInstanceInfoArgument final : AAInstanceInfoFloating {
5733 AAInstanceInfoArgument(
const IRPosition &IRP, Attributor &
A)
5734 : AAInstanceInfoFloating(IRP,
A) {}
5738struct AAInstanceInfoCallSiteArgument final : AAInstanceInfoImpl {
5739 AAInstanceInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5740 : AAInstanceInfoImpl(IRP,
A) {}
5748 Argument *Arg = getAssociatedArgument();
5750 return indicatePessimisticFixpoint();
5753 A.getAAFor<AAInstanceInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
5755 return indicatePessimisticFixpoint();
5761struct AAInstanceInfoReturned final : AAInstanceInfoImpl {
5762 AAInstanceInfoReturned(
const IRPosition &IRP, Attributor &
A)
5763 : AAInstanceInfoImpl(IRP,
A) {
5779struct AAInstanceInfoCallSiteReturned final : AAInstanceInfoFloating {
5780 AAInstanceInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5781 : AAInstanceInfoFloating(IRP,
A) {}
5788 bool IgnoreSubsumingPositions) {
5789 assert(ImpliedAttributeKind == Attribute::Captures &&
5790 "Unexpected attribute kind");
5800 V.getType()->getPointerAddressSpace() == 0)) {
5805 A.getAttrs(IRP, {Attribute::Captures}, Attrs,
5815 {Attribute::Captures, Attribute::ByVal}, Attrs,
5852 bool ReadOnly =
F.onlyReadsMemory();
5853 bool NoThrow =
F.doesNotThrow();
5854 bool IsVoidReturn =
F.getReturnType()->isVoidTy();
5855 if (ReadOnly && NoThrow && IsVoidReturn) {
5868 if (NoThrow && IsVoidReturn)
5873 if (!NoThrow || ArgNo < 0 ||
5874 !
F.getAttributes().hasAttrSomewhere(Attribute::Returned))
5877 for (
unsigned U = 0, E =
F.arg_size(); U < E; ++U)
5878 if (
F.hasParamAttribute(U, Attribute::Returned)) {
5879 if (U ==
unsigned(ArgNo))
5906 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5907 SmallVectorImpl<Attribute> &Attrs)
const override {
5908 if (!isAssumedNoCaptureMaybeReturned())
5911 if (isArgumentPosition()) {
5912 if (isAssumedNoCapture())
5913 Attrs.emplace_back(Attribute::get(Ctx, Attribute::Captures));
5915 Attrs.emplace_back(Attribute::get(Ctx,
"no-capture-maybe-returned"));
5920 const std::string getAsStr(Attributor *
A)
const override {
5921 if (isKnownNoCapture())
5922 return "known not-captured";
5923 if (isAssumedNoCapture())
5924 return "assumed not-captured";
5925 if (isKnownNoCaptureMaybeReturned())
5926 return "known not-captured-maybe-returned";
5927 if (isAssumedNoCaptureMaybeReturned())
5928 return "assumed not-captured-maybe-returned";
5929 return "assumed-captured";
5934 bool checkUse(Attributor &
A, AANoCapture::StateType &State,
const Use &U,
5937 LLVM_DEBUG(
dbgs() <<
"[AANoCapture] Check use: " << *
U.get() <<
" in "
5943 return isCapturedIn(State,
true,
true,
5950 return isCapturedIn(State,
true,
true,
5956 return isCapturedIn(State,
false,
false,
5958 return isCapturedIn(State,
true,
true,
5966 return isCapturedIn(State,
true,
true,
5973 bool IsKnownNoCapture;
5974 const AANoCapture *ArgNoCaptureAA =
nullptr;
5976 A,
this, CSArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
5978 if (IsAssumedNoCapture)
5979 return isCapturedIn(State,
false,
false,
5983 return isCapturedIn(State,
false,
false,
5988 return isCapturedIn(State,
true,
true,
5995 static bool isCapturedIn(AANoCapture::StateType &State,
bool CapturedInMem,
5996 bool CapturedInInt,
bool CapturedInRet) {
5997 LLVM_DEBUG(
dbgs() <<
" - captures [Mem " << CapturedInMem <<
"|Int "
5998 << CapturedInInt <<
"|Ret " << CapturedInRet <<
"]\n");
6010 const IRPosition &IRP = getIRPosition();
6014 return indicatePessimisticFixpoint();
6021 return indicatePessimisticFixpoint();
6029 T.addKnownBits(NOT_CAPTURED_IN_MEM);
6031 addKnownBits(NOT_CAPTURED_IN_MEM);
6038 auto CheckReturnedArgs = [&](
bool &UsedAssumedInformation) {
6042 UsedAssumedInformation))
6044 bool SeenConstant =
false;
6045 for (
const AA::ValueAndContext &VAC : Values) {
6049 SeenConstant =
true;
6051 VAC.
getValue() == getAssociatedArgument())
6057 bool IsKnownNoUnwind;
6060 bool IsVoidTy =
F->getReturnType()->isVoidTy();
6061 bool UsedAssumedInformation =
false;
6062 if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {
6063 T.addKnownBits(NOT_CAPTURED_IN_RET);
6064 if (
T.isKnown(NOT_CAPTURED_IN_MEM))
6066 if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {
6067 addKnownBits(NOT_CAPTURED_IN_RET);
6068 if (isKnown(NOT_CAPTURED_IN_MEM))
6069 return indicateOptimisticFixpoint();
6074 auto UseCheck = [&](
const Use &
U,
bool &Follow) ->
bool {
6083 return checkUse(
A,
T, U, Follow);
6086 if (!
A.checkForAllUses(UseCheck, *
this, *V))
6087 return indicatePessimisticFixpoint();
6090 auto Assumed = S.getAssumed();
6091 S.intersectAssumedBits(
T.getAssumed());
6092 if (!isAssumedNoCaptureMaybeReturned())
6093 return indicatePessimisticFixpoint();
6099struct AANoCaptureArgument final : AANoCaptureImpl {
6100 AANoCaptureArgument(
const IRPosition &IRP, Attributor &
A)
6101 : AANoCaptureImpl(IRP,
A) {}
6108struct AANoCaptureCallSiteArgument final : AANoCaptureImpl {
6109 AANoCaptureCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6110 : AANoCaptureImpl(IRP,
A) {}
6118 Argument *Arg = getAssociatedArgument();
6120 return indicatePessimisticFixpoint();
6122 bool IsKnownNoCapture;
6123 const AANoCapture *ArgAA =
nullptr;
6125 A,
this, ArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6127 return ChangeStatus::UNCHANGED;
6129 return indicatePessimisticFixpoint();
6134 void trackStatistics()
const override {
6140struct AANoCaptureFloating final : AANoCaptureImpl {
6141 AANoCaptureFloating(
const IRPosition &IRP, Attributor &
A)
6142 : AANoCaptureImpl(IRP,
A) {}
6145 void trackStatistics()
const override {
6151struct AANoCaptureReturned final : AANoCaptureImpl {
6152 AANoCaptureReturned(
const IRPosition &IRP, Attributor &
A)
6153 : AANoCaptureImpl(IRP,
A) {
6168 void trackStatistics()
const override {}
6172struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {
6173 AANoCaptureCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6174 : AANoCaptureImpl(IRP,
A) {}
6180 determineFunctionCaptureCapabilities(getIRPosition(), *
F, *
this);
6184 void trackStatistics()
const override {
6201 dbgs() <<
"[ValueSimplify] is assumed to be "
6204 dbgs() <<
"[ValueSimplify] is assumed to be <none>\n";
6216 if (getAssociatedValue().
getType()->isVoidTy())
6217 indicatePessimisticFixpoint();
6218 if (
A.hasSimplificationCallback(getIRPosition()))
6219 indicatePessimisticFixpoint();
6223 const std::string getAsStr(Attributor *
A)
const override {
6225 dbgs() <<
"SAV: " << (bool)SimplifiedAssociatedValue <<
" ";
6226 if (SimplifiedAssociatedValue && *SimplifiedAssociatedValue)
6227 dbgs() <<
"SAV: " << **SimplifiedAssociatedValue <<
" ";
6229 return isValidState() ? (isAtFixpoint() ?
"simplified" :
"maybe-simple")
6234 void trackStatistics()
const override {}
6237 std::optional<Value *>
6238 getAssumedSimplifiedValue(Attributor &
A)
const override {
6239 return SimplifiedAssociatedValue;
6246 static Value *ensureType(Attributor &
A,
Value &V,
Type &Ty, Instruction *CtxI,
6250 if (CtxI &&
V.getType()->canLosslesslyBitCastTo(&Ty))
6252 : BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6261 static Value *reproduceInst(Attributor &
A,
6262 const AbstractAttribute &QueryingAA,
6263 Instruction &
I,
Type &Ty, Instruction *CtxI,
6265 assert(CtxI &&
"Cannot reproduce an instruction without context!");
6266 if (
Check && (
I.mayReadFromMemory() ||
6271 Value *NewOp = reproduceValue(
A, QueryingAA, *
Op, Ty, CtxI,
Check, VMap);
6273 assert(
Check &&
"Manifest of new value unexpectedly failed!");
6295 static Value *reproduceValue(Attributor &
A,
6296 const AbstractAttribute &QueryingAA,
Value &V,
6297 Type &Ty, Instruction *CtxI,
bool Check,
6299 if (
const auto &NewV = VMap.
lookup(&V))
6301 bool UsedAssumedInformation =
false;
6302 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
6304 if (!SimpleV.has_value())
6308 EffectiveV = *SimpleV;
6313 return ensureType(
A, *EffectiveV, Ty, CtxI,
Check);
6315 if (
Value *NewV = reproduceInst(
A, QueryingAA, *
I, Ty, CtxI,
Check, VMap))
6316 return ensureType(
A, *NewV, Ty, CtxI,
Check);
6322 Value *manifestReplacementValue(Attributor &
A, Instruction *CtxI)
const {
6323 Value *NewV = SimplifiedAssociatedValue
6324 ? *SimplifiedAssociatedValue
6326 if (NewV && NewV != &getAssociatedValue()) {
6330 if (reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6332 return reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6340 bool checkAndUpdate(Attributor &
A,
const AbstractAttribute &QueryingAA,
6341 const IRPosition &IRP,
bool Simplify =
true) {
6342 bool UsedAssumedInformation =
false;
6345 QueryingValueSimplified =
A.getAssumedSimplified(
6347 return unionAssumed(QueryingValueSimplified);
6351 template <
typename AAType>
bool askSimplifiedValueFor(Attributor &
A) {
6352 if (!getAssociatedValue().
getType()->isIntegerTy())
6357 A.getAAFor<AAType>(*
this, getIRPosition(), DepClassTy::NONE);
6361 std::optional<Constant *> COpt = AA->getAssumedConstant(
A);
6364 SimplifiedAssociatedValue = std::nullopt;
6365 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6368 if (
auto *
C = *COpt) {
6369 SimplifiedAssociatedValue =
C;
6370 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6376 bool askSimplifiedValueForOtherAAs(Attributor &
A) {
6377 if (askSimplifiedValueFor<AAValueConstantRange>(
A))
6379 if (askSimplifiedValueFor<AAPotentialConstantValues>(
A))
6387 for (
auto &U : getAssociatedValue().uses()) {
6392 IP =
PHI->getIncomingBlock(U)->getTerminator();
6393 if (
auto *NewV = manifestReplacementValue(
A, IP)) {
6395 <<
" -> " << *NewV <<
" :: " << *
this <<
"\n");
6396 if (
A.changeUseAfterManifest(U, *NewV))
6397 Changed = ChangeStatus::CHANGED;
6401 return Changed | AAValueSimplify::manifest(
A);
6406 SimplifiedAssociatedValue = &getAssociatedValue();
6407 return AAValueSimplify::indicatePessimisticFixpoint();
6411struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
6412 AAValueSimplifyArgument(
const IRPosition &IRP, Attributor &
A)
6413 : AAValueSimplifyImpl(IRP,
A) {}
6416 AAValueSimplifyImpl::initialize(
A);
6417 if (
A.hasAttr(getIRPosition(),
6418 {Attribute::InAlloca, Attribute::Preallocated,
6419 Attribute::StructRet, Attribute::Nest, Attribute::ByVal},
6421 indicatePessimisticFixpoint();
6428 Argument *Arg = getAssociatedArgument();
6434 return indicatePessimisticFixpoint();
6437 auto Before = SimplifiedAssociatedValue;
6439 auto PredForCallSite = [&](AbstractCallSite ACS) {
6440 const IRPosition &ACSArgPos =
6451 bool UsedAssumedInformation =
false;
6452 std::optional<Constant *> SimpleArgOp =
6453 A.getAssumedConstant(ACSArgPos, *
this, UsedAssumedInformation);
6460 return unionAssumed(*SimpleArgOp);
6465 bool UsedAssumedInformation =
false;
6466 if (hasCallBaseContext() &&
6467 getCallBaseContext()->getCalledOperand() == Arg->
getParent())
6469 AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
6471 Success =
A.checkForAllCallSites(PredForCallSite, *
this,
true,
6472 UsedAssumedInformation);
6475 if (!askSimplifiedValueForOtherAAs(
A))
6476 return indicatePessimisticFixpoint();
6479 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6480 : ChangeStatus ::CHANGED;
6484 void trackStatistics()
const override {
6489struct AAValueSimplifyReturned : AAValueSimplifyImpl {
6490 AAValueSimplifyReturned(
const IRPosition &IRP, Attributor &
A)
6491 : AAValueSimplifyImpl(IRP,
A) {}
6494 std::optional<Value *>
6495 getAssumedSimplifiedValue(Attributor &
A)
const override {
6496 if (!isValidState())
6498 return SimplifiedAssociatedValue;
6503 auto Before = SimplifiedAssociatedValue;
6507 return checkAndUpdate(
6512 bool UsedAssumedInformation =
false;
6513 if (!
A.checkForAllInstructions(ReturnInstCB, *
this, {Instruction::Ret},
6514 UsedAssumedInformation))
6515 if (!askSimplifiedValueForOtherAAs(
A))
6516 return indicatePessimisticFixpoint();
6519 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6520 : ChangeStatus ::CHANGED;
6526 return ChangeStatus::UNCHANGED;
6530 void trackStatistics()
const override {
6535struct AAValueSimplifyFloating : AAValueSimplifyImpl {
6536 AAValueSimplifyFloating(
const IRPosition &IRP, Attributor &
A)
6537 : AAValueSimplifyImpl(IRP,
A) {}
6541 AAValueSimplifyImpl::initialize(
A);
6542 Value &
V = getAnchorValue();
6546 indicatePessimisticFixpoint();
6551 auto Before = SimplifiedAssociatedValue;
6552 if (!askSimplifiedValueForOtherAAs(
A))
6553 return indicatePessimisticFixpoint();
6556 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6557 : ChangeStatus ::CHANGED;
6561 void trackStatistics()
const override {
6566struct AAValueSimplifyFunction : AAValueSimplifyImpl {
6567 AAValueSimplifyFunction(
const IRPosition &IRP, Attributor &
A)
6568 : AAValueSimplifyImpl(IRP,
A) {}
6572 SimplifiedAssociatedValue =
nullptr;
6573 indicateOptimisticFixpoint();
6578 "AAValueSimplify(Function|CallSite)::updateImpl will not be called");
6581 void trackStatistics()
const override {
6586struct AAValueSimplifyCallSite : AAValueSimplifyFunction {
6587 AAValueSimplifyCallSite(
const IRPosition &IRP, Attributor &
A)
6588 : AAValueSimplifyFunction(IRP,
A) {}
6590 void trackStatistics()
const override {
6595struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl {
6596 AAValueSimplifyCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6597 : AAValueSimplifyImpl(IRP,
A) {}
6600 AAValueSimplifyImpl::initialize(
A);
6601 Function *Fn = getAssociatedFunction();
6602 assert(Fn &&
"Did expect an associted function");
6603 for (Argument &Arg : Fn->
args()) {
6608 checkAndUpdate(
A, *
this, IRP))
6609 indicateOptimisticFixpoint();
6611 indicatePessimisticFixpoint();
6619 return indicatePessimisticFixpoint();
6622 void trackStatistics()
const override {
6627struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
6628 AAValueSimplifyCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6629 : AAValueSimplifyFloating(IRP,
A) {}
6635 auto *FloatAA =
A.lookupAAFor<AAValueSimplify>(
6637 if (FloatAA && FloatAA->getState().isValidState())
6640 if (
auto *NewV = manifestReplacementValue(
A, getCtxI())) {
6642 ->getArgOperandUse(getCallSiteArgNo());
6643 if (
A.changeUseAfterManifest(U, *NewV))
6644 Changed = ChangeStatus::CHANGED;
6647 return Changed | AAValueSimplify::manifest(
A);
6650 void trackStatistics()
const override {
6658struct AAHeapToStackFunction final :
public AAHeapToStack {
6660 struct AllocationInfo {
6665 LibFunc LibraryFunctionId = NotLibFunc;
6672 } Status = STACK_DUE_TO_USE;
6676 bool HasPotentiallyFreeingUnknownUses =
false;
6680 bool MoveAllocaIntoEntry =
true;
6683 SmallSetVector<CallBase *, 1> PotentialFreeCalls{};
6686 struct DeallocationInfo {
6694 bool MightFreeUnknownObjects =
false;
6697 SmallSetVector<CallBase *, 1> PotentialAllocationCalls{};
6700 AAHeapToStackFunction(
const IRPosition &IRP, Attributor &
A)
6701 : AAHeapToStack(IRP,
A) {}
6703 ~AAHeapToStackFunction()
override {
6706 for (
auto &It : AllocationInfos)
6707 It.second->~AllocationInfo();
6708 for (
auto &It : DeallocationInfos)
6709 It.second->~DeallocationInfo();
6713 AAHeapToStack::initialize(
A);
6716 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6723 DeallocationInfos[CB] =
new (
A.Allocator) DeallocationInfo{CB, FreedOp};
6730 auto *I8Ty = Type::getInt8Ty(CB->
getParent()->getContext());
6732 AllocationInfo *AI =
new (
A.Allocator) AllocationInfo{CB};
6733 AllocationInfos[CB] = AI;
6735 TLI->getLibFunc(*CB, AI->LibraryFunctionId);
6741 bool UsedAssumedInformation =
false;
6742 bool Success =
A.checkForAllCallLikeInstructions(
6743 AllocationIdentifierCB, *
this, UsedAssumedInformation,
6747 assert(
Success &&
"Did not expect the call base visit callback to fail!");
6750 [](
const IRPosition &,
const AbstractAttribute *,
6751 bool &) -> std::optional<Value *> {
return nullptr; };
6752 for (
const auto &It : AllocationInfos)
6755 for (
const auto &It : DeallocationInfos)
6760 const std::string getAsStr(Attributor *
A)
const override {
6761 unsigned NumH2SMallocs = 0, NumInvalidMallocs = 0;
6762 for (
const auto &It : AllocationInfos) {
6763 if (It.second->Status == AllocationInfo::INVALID)
6764 ++NumInvalidMallocs;
6768 return "[H2S] Mallocs Good/Bad: " + std::to_string(NumH2SMallocs) +
"/" +
6769 std::to_string(NumInvalidMallocs);
6773 void trackStatistics()
const override {
6775 MallocCalls, Function,
6776 "Number of malloc/calloc/aligned_alloc calls converted to allocas");
6777 for (
const auto &It : AllocationInfos)
6778 if (It.second->Status != AllocationInfo::INVALID)
6782 bool isAssumedHeapToStack(
const CallBase &CB)
const override {
6784 if (AllocationInfo *AI =
6785 AllocationInfos.lookup(
const_cast<CallBase *
>(&CB)))
6786 return AI->Status != AllocationInfo::INVALID;
6790 bool isAssumedHeapToStackRemovedFree(CallBase &CB)
const override {
6791 if (!isValidState())
6794 for (
const auto &It : AllocationInfos) {
6795 AllocationInfo &AI = *It.second;
6796 if (AI.Status == AllocationInfo::INVALID)
6799 if (AI.PotentialFreeCalls.count(&CB))
6807 assert(getState().isValidState() &&
6808 "Attempted to manifest an invalid state!");
6812 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6814 for (
auto &It : AllocationInfos) {
6815 AllocationInfo &AI = *It.second;
6816 if (AI.Status == AllocationInfo::INVALID)
6819 for (CallBase *FreeCall : AI.PotentialFreeCalls) {
6820 LLVM_DEBUG(
dbgs() <<
"H2S: Removing free call: " << *FreeCall <<
"\n");
6821 A.deleteAfterManifest(*FreeCall);
6822 HasChanged = ChangeStatus::CHANGED;
6825 LLVM_DEBUG(
dbgs() <<
"H2S: Removing malloc-like call: " << *AI.CB
6828 auto Remark = [&](OptimizationRemark
OR) {
6829 LibFunc IsAllocShared;
6830 if (TLI->getLibFunc(*AI.CB, IsAllocShared))
6831 if (IsAllocShared == LibFunc___kmpc_alloc_shared)
6832 return OR <<
"Moving globalized variable to the stack.";
6833 return OR <<
"Moving memory allocation from the heap to the stack.";
6835 if (AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared)
6836 A.emitRemark<OptimizationRemark>(AI.CB,
"OMP110",
Remark);
6838 A.emitRemark<OptimizationRemark>(AI.CB,
"HeapToStack",
Remark);
6840 const DataLayout &
DL =
A.getInfoCache().getDL();
6842 std::optional<APInt> SizeAPI =
getSize(
A, *
this, AI);
6844 Size = ConstantInt::get(AI.CB->getContext(), *SizeAPI);
6846 LLVMContext &Ctx = AI.CB->getContext();
6847 ObjectSizeOpts Opts;
6848 ObjectSizeOffsetEvaluator Eval(
DL, TLI, Ctx, Opts);
6849 SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);
6856 ?
F->getEntryBlock().begin()
6857 : AI.CB->getIterator();
6860 if (MaybeAlign RetAlign = AI.CB->getRetAlign())
6861 Alignment = std::max(Alignment, *RetAlign);
6863 std::optional<APInt> AlignmentAPI = getAPInt(
A, *
this, *Align);
6864 assert(AlignmentAPI && AlignmentAPI->getZExtValue() > 0 &&
6865 "Expected an alignment during manifest!");
6867 std::max(Alignment,
assumeAligned(AlignmentAPI->getZExtValue()));
6871 unsigned AS =
DL.getAllocaAddrSpace();
6873 new AllocaInst(Type::getInt8Ty(
F->getContext()), AS,
Size, Alignment,
6874 AI.CB->getName() +
".h2s", IP);
6876 if (Alloca->
getType() != AI.CB->getType())
6877 Alloca = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6878 Alloca, AI.CB->getType(),
"malloc_cast", AI.CB->getIterator());
6880 auto *I8Ty = Type::getInt8Ty(
F->getContext());
6883 "Must be able to materialize initial memory state of allocation");
6888 auto *NBB =
II->getNormalDest();
6890 A.deleteAfterManifest(*AI.CB);
6892 A.deleteAfterManifest(*AI.CB);
6901 Builder.CreateMemSet(Alloca, InitVal,
Size, std::nullopt);
6903 HasChanged = ChangeStatus::CHANGED;
6909 std::optional<APInt> getAPInt(Attributor &
A,
const AbstractAttribute &AA,
6911 bool UsedAssumedInformation =
false;
6912 std::optional<Constant *> SimpleV =
6913 A.getAssumedConstant(V, AA, UsedAssumedInformation);
6915 return APInt(64, 0);
6917 return CI->getValue();
6918 return std::nullopt;
6921 std::optional<APInt>
getSize(Attributor &
A,
const AbstractAttribute &AA,
6922 AllocationInfo &AI) {
6923 auto Mapper = [&](
const Value *
V) ->
const Value * {
6924 bool UsedAssumedInformation =
false;
6925 if (std::optional<Constant *> SimpleV =
6926 A.getAssumedConstant(*V, AA, UsedAssumedInformation))
6933 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6939 MapVector<CallBase *, AllocationInfo *> AllocationInfos;
6943 MapVector<CallBase *, DeallocationInfo *> DeallocationInfos;
6948ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &
A) {
6951 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6953 const auto *LivenessAA =
6956 MustBeExecutedContextExplorer *Explorer =
6957 A.getInfoCache().getMustBeExecutedContextExplorer();
6959 bool StackIsAccessibleByOtherThreads =
6960 A.getInfoCache().stackIsAccessibleByOtherThreads();
6963 A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(*F);
6964 std::optional<bool> MayContainIrreducibleControl;
6966 if (&
F->getEntryBlock() == &BB)
6968 if (!MayContainIrreducibleControl.has_value())
6970 if (*MayContainIrreducibleControl)
6979 bool HasUpdatedFrees =
false;
6981 auto UpdateFrees = [&]() {
6982 HasUpdatedFrees =
true;
6984 for (
auto &It : DeallocationInfos) {
6985 DeallocationInfo &DI = *It.second;
6988 if (DI.MightFreeUnknownObjects)
6992 bool UsedAssumedInformation =
false;
6993 if (
A.isAssumedDead(*DI.CB,
this, LivenessAA, UsedAssumedInformation,
7000 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown underlying object for free!\n");
7001 DI.MightFreeUnknownObjects =
true;
7014 DI.MightFreeUnknownObjects =
true;
7018 AllocationInfo *AI = AllocationInfos.lookup(ObjCB);
7020 LLVM_DEBUG(
dbgs() <<
"[H2S] Free of a non-allocation object: " << *Obj
7022 DI.MightFreeUnknownObjects =
true;
7026 DI.PotentialAllocationCalls.insert(ObjCB);
7030 auto FreeCheck = [&](AllocationInfo &AI) {
7034 if (!StackIsAccessibleByOtherThreads) {
7039 dbgs() <<
"[H2S] found an escaping use, stack is not accessible by "
7040 "other threads and function is not nosync:\n");
7044 if (!HasUpdatedFrees)
7048 if (AI.PotentialFreeCalls.size() != 1) {
7050 << AI.PotentialFreeCalls.size() <<
"\n");
7053 CallBase *UniqueFree = *AI.PotentialFreeCalls.begin();
7054 DeallocationInfo *DI = DeallocationInfos.lookup(UniqueFree);
7057 dbgs() <<
"[H2S] unique free call was not known as deallocation call "
7058 << *UniqueFree <<
"\n");
7061 if (DI->MightFreeUnknownObjects) {
7063 dbgs() <<
"[H2S] unique free call might free unknown allocations\n");
7066 if (DI->PotentialAllocationCalls.empty())
7068 if (DI->PotentialAllocationCalls.size() > 1) {
7070 << DI->PotentialAllocationCalls.size()
7071 <<
" different allocations\n");
7074 if (*DI->PotentialAllocationCalls.begin() != AI.CB) {
7077 <<
"[H2S] unique free call not known to free this allocation but "
7078 << **DI->PotentialAllocationCalls.begin() <<
"\n");
7083 if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared) {
7085 if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
7086 LLVM_DEBUG(
dbgs() <<
"[H2S] unique free call might not be executed "
7087 "with the allocation "
7088 << *UniqueFree <<
"\n");
7095 auto UsesCheck = [&](AllocationInfo &AI) {
7096 bool ValidUsesOnly =
true;
7098 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
7103 if (
SI->getValueOperand() ==
U.get()) {
7105 <<
"[H2S] escaping store to memory: " << *UserI <<
"\n");
7106 ValidUsesOnly =
false;
7115 if (DeallocationInfos.count(CB)) {
7116 AI.PotentialFreeCalls.insert(CB);
7123 bool IsKnownNoCapture;
7132 if (!IsAssumedNoCapture ||
7133 (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared &&
7134 !IsAssumedNoFree)) {
7135 AI.HasPotentiallyFreeingUnknownUses |= !IsAssumedNoFree;
7138 auto Remark = [&](OptimizationRemarkMissed ORM) {
7140 <<
"Could not move globalized variable to the stack. "
7141 "Variable is potentially captured in call. Mark "
7142 "parameter as `__attribute__((noescape))` to override.";
7145 if (ValidUsesOnly &&
7146 AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared)
7147 A.emitRemark<OptimizationRemarkMissed>(CB,
"OMP113",
Remark);
7150 ValidUsesOnly =
false;
7163 ValidUsesOnly =
false;
7166 if (!
A.checkForAllUses(Pred, *
this, *AI.CB,
false,
7168 [&](
const Use &OldU,
const Use &NewU) {
7169 auto *SI = dyn_cast<StoreInst>(OldU.getUser());
7170 return !SI || StackIsAccessibleByOtherThreads ||
7171 AA::isAssumedThreadLocalObject(
7172 A, *SI->getPointerOperand(), *this);
7175 return ValidUsesOnly;
7180 for (
auto &It : AllocationInfos) {
7181 AllocationInfo &AI = *It.second;
7182 if (AI.Status == AllocationInfo::INVALID)
7186 std::optional<APInt> APAlign = getAPInt(
A, *
this, *Align);
7190 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown allocation alignment: " << *AI.CB
7192 AI.Status = AllocationInfo::INVALID;
7197 !APAlign->isPowerOf2()) {
7198 LLVM_DEBUG(
dbgs() <<
"[H2S] Invalid allocation alignment: " << APAlign
7200 AI.Status = AllocationInfo::INVALID;
7207 if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared &&
7212 dbgs() <<
"[H2S] Unknown allocation size: " << *AI.CB <<
"\n";
7214 dbgs() <<
"[H2S] Allocation size too large: " << *AI.CB <<
" vs. "
7218 AI.Status = AllocationInfo::INVALID;
7224 switch (AI.Status) {
7225 case AllocationInfo::STACK_DUE_TO_USE:
7228 AI.Status = AllocationInfo::STACK_DUE_TO_FREE;
7230 case AllocationInfo::STACK_DUE_TO_FREE:
7233 AI.Status = AllocationInfo::INVALID;
7236 case AllocationInfo::INVALID:
7243 bool IsGlobalizedLocal =
7244 AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared;
7245 if (AI.MoveAllocaIntoEntry &&
7246 (!
Size.has_value() ||
7247 (!IsGlobalizedLocal && IsInLoop(*AI.CB->getParent()))))
7248 AI.MoveAllocaIntoEntry =
false;
7257struct AAPrivatizablePtrImpl :
public AAPrivatizablePtr {
7258 AAPrivatizablePtrImpl(
const IRPosition &IRP, Attributor &
A)
7259 : AAPrivatizablePtr(IRP,
A), PrivatizableType(std::nullopt) {}
7262 AAPrivatizablePtr::indicatePessimisticFixpoint();
7263 PrivatizableType =
nullptr;
7264 return ChangeStatus::CHANGED;
7270 virtual std::optional<Type *> identifyPrivatizableType(Attributor &
A) = 0;
7274 std::optional<Type *> combineTypes(std::optional<Type *> T0,
7275 std::optional<Type *>
T1) {
7285 std::optional<Type *> getPrivatizableType()
const override {
7286 return PrivatizableType;
7289 const std::string getAsStr(Attributor *
A)
const override {
7290 return isAssumedPrivatizablePtr() ?
"[priv]" :
"[no-priv]";
7294 std::optional<Type *> PrivatizableType;
7299struct AAPrivatizablePtrArgument final :
public AAPrivatizablePtrImpl {
7300 AAPrivatizablePtrArgument(
const IRPosition &IRP, Attributor &
A)
7301 : AAPrivatizablePtrImpl(IRP,
A) {}
7304 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7307 bool UsedAssumedInformation =
false;
7309 A.getAttrs(getIRPosition(), {Attribute::ByVal},
Attrs,
7311 if (!
Attrs.empty() &&
7312 A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *
this,
7313 true, UsedAssumedInformation))
7314 return Attrs[0].getValueAsType();
7316 std::optional<Type *> Ty;
7317 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
7325 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7334 A.getAAFor<AAPrivatizablePtr>(*
this, ACSArgPos, DepClassTy::REQUIRED);
7337 std::optional<Type *> CSTy = PrivCSArgAA->getPrivatizableType();
7340 dbgs() <<
"[AAPrivatizablePtr] ACSPos: " << ACSArgPos <<
", CSTy: ";
7344 dbgs() <<
"<nullptr>";
7349 Ty = combineTypes(Ty, CSTy);
7352 dbgs() <<
" : New Type: ";
7354 (*Ty)->print(
dbgs());
7356 dbgs() <<
"<nullptr>";
7365 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7366 UsedAssumedInformation))
7373 PrivatizableType = identifyPrivatizableType(
A);
7374 if (!PrivatizableType)
7375 return ChangeStatus::UNCHANGED;
7376 if (!*PrivatizableType)
7377 return indicatePessimisticFixpoint();
7382 DepClassTy::OPTIONAL);
7385 if (!
A.hasAttr(getIRPosition(), Attribute::ByVal) &&
7388 return indicatePessimisticFixpoint();
7394 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7398 Function &Fn = *getIRPosition().getAnchorScope();
7400 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(Fn);
7402 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Missing TTI for function "
7404 return indicatePessimisticFixpoint();
7407 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7414 bool UsedAssumedInformation =
false;
7415 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7416 UsedAssumedInformation)) {
7418 dbgs() <<
"[AAPrivatizablePtr] ABI incompatibility detected for "
7420 return indicatePessimisticFixpoint();
7424 Argument *Arg = getAssociatedArgument();
7425 if (!
A.isValidFunctionSignatureRewrite(*Arg, ReplacementTypes)) {
7427 return indicatePessimisticFixpoint();
7434 auto IsCompatiblePrivArgOfCallback = [&](CallBase &CB) {
7437 for (
const Use *U : CallbackUses) {
7438 AbstractCallSite CBACS(U);
7439 assert(CBACS && CBACS.isCallbackCall());
7440 for (Argument &CBArg : CBACS.getCalledFunction()->args()) {
7441 int CBArgNo = CBACS.getCallArgOperandNo(CBArg);
7445 <<
"[AAPrivatizablePtr] Argument " << *Arg
7446 <<
"check if can be privatized in the context of its parent ("
7448 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7450 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7451 <<
")\n[AAPrivatizablePtr] " << CBArg <<
" : "
7452 << CBACS.getCallArgOperand(CBArg) <<
" vs "
7454 <<
"[AAPrivatizablePtr] " << CBArg <<
" : "
7455 << CBACS.getCallArgOperandNo(CBArg) <<
" vs " << ArgNo <<
"\n";
7458 if (CBArgNo !=
int(ArgNo))
7460 const auto *CBArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7462 if (CBArgPrivAA && CBArgPrivAA->isValidState()) {
7463 auto CBArgPrivTy = CBArgPrivAA->getPrivatizableType();
7466 if (*CBArgPrivTy == PrivatizableType)
7471 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7472 <<
" cannot be privatized in the context of its parent ("
7474 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7476 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7477 <<
").\n[AAPrivatizablePtr] for which the argument "
7478 "privatization is not compatible.\n";
7488 auto IsCompatiblePrivArgOfDirectCS = [&](AbstractCallSite ACS) {
7492 "Expected a direct call operand for callback call operand");
7497 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7498 <<
" check if be privatized in the context of its parent ("
7500 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7502 << DCArgNo <<
"@" << DCCallee->
getName() <<
").\n";
7505 if (
unsigned(DCArgNo) < DCCallee->
arg_size()) {
7506 const auto *DCArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7508 DepClassTy::REQUIRED);
7509 if (DCArgPrivAA && DCArgPrivAA->isValidState()) {
7510 auto DCArgPrivTy = DCArgPrivAA->getPrivatizableType();
7513 if (*DCArgPrivTy == PrivatizableType)
7519 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7520 <<
" cannot be privatized in the context of its parent ("
7522 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7525 <<
").\n[AAPrivatizablePtr] for which the argument "
7526 "privatization is not compatible.\n";
7534 auto IsCompatiblePrivArgOfOtherCallSite = [&](AbstractCallSite ACS) {
7538 return IsCompatiblePrivArgOfDirectCS(ACS);
7542 if (!
A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *
this,
true,
7543 UsedAssumedInformation))
7544 return indicatePessimisticFixpoint();
7546 return ChangeStatus::UNCHANGED;
7552 identifyReplacementTypes(
Type *PrivType,
7553 SmallVectorImpl<Type *> &ReplacementTypes) {
7556 assert(PrivType &&
"Expected privatizable type!");
7560 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++)
7561 ReplacementTypes.
push_back(PrivStructType->getElementType(u));
7563 ReplacementTypes.
append(PrivArrayType->getNumElements(),
7564 PrivArrayType->getElementType());
7573 static void createInitialization(
Type *PrivType,
Value &
Base, Function &
F,
7575 assert(PrivType &&
"Expected privatizable type!");
7578 const DataLayout &
DL =
F.getDataLayout();
7582 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7583 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7586 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7589 Type *PointeeTy = PrivArrayType->getElementType();
7590 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7591 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7593 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7596 new StoreInst(
F.getArg(ArgNo), &
Base, IP);
7602 void createReplacementValues(Align Alignment,
Type *PrivType,
7604 SmallVectorImpl<Value *> &ReplacementValues) {
7606 assert(PrivType &&
"Expected privatizable type!");
7614 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7615 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7616 Type *PointeeTy = PrivStructType->getElementType(u);
7619 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7620 L->setAlignment(Alignment);
7624 Type *PointeeTy = PrivArrayType->getElementType();
7625 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7626 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7628 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7629 L->setAlignment(Alignment);
7634 L->setAlignment(Alignment);
7641 if (!PrivatizableType)
7642 return ChangeStatus::UNCHANGED;
7643 assert(*PrivatizableType &&
"Expected privatizable type!");
7649 bool UsedAssumedInformation =
false;
7650 if (!
A.checkForAllInstructions(
7651 [&](Instruction &
I) {
7652 CallInst &CI = cast<CallInst>(I);
7653 if (CI.isTailCall())
7654 TailCalls.push_back(&CI);
7657 *
this, {Instruction::Call}, UsedAssumedInformation))
7658 return ChangeStatus::UNCHANGED;
7660 Argument *Arg = getAssociatedArgument();
7663 const auto *AlignAA =
7670 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7672 BasicBlock &EntryBB = ReplacementFn.getEntryBlock();
7674 const DataLayout &
DL = IP->getDataLayout();
7675 unsigned AS =
DL.getAllocaAddrSpace();
7676 Instruction *AI =
new AllocaInst(*PrivatizableType, AS,
7677 Arg->
getName() +
".priv", IP);
7678 createInitialization(*PrivatizableType, *AI, ReplacementFn,
7679 ArgIt->getArgNo(), IP);
7682 AI = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
7686 for (CallInst *CI : TailCalls)
7687 CI->setTailCall(
false);
7694 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7695 AbstractCallSite ACS, SmallVectorImpl<Value *> &NewArgOperands) {
7698 createReplacementValues(
7699 AlignAA ? AlignAA->getAssumedAlign() :
Align(0),
7700 *PrivatizableType, ACS,
7708 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7711 if (
A.registerFunctionSignatureRewrite(*Arg, ReplacementTypes,
7712 std::move(FnRepairCB),
7713 std::move(ACSRepairCB)))
7714 return ChangeStatus::CHANGED;
7715 return ChangeStatus::UNCHANGED;
7719 void trackStatistics()
const override {
7724struct AAPrivatizablePtrFloating :
public AAPrivatizablePtrImpl {
7725 AAPrivatizablePtrFloating(
const IRPosition &IRP, Attributor &
A)
7726 : AAPrivatizablePtrImpl(IRP,
A) {}
7731 indicatePessimisticFixpoint();
7736 "updateImpl will not be called");
7740 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7743 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] No underlying object found!\n");
7750 return AI->getAllocatedType();
7752 auto *PrivArgAA =
A.getAAFor<AAPrivatizablePtr>(
7754 if (PrivArgAA && PrivArgAA->isAssumedPrivatizablePtr())
7755 return PrivArgAA->getPrivatizableType();
7758 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Underlying object neither valid "
7759 "alloca nor privatizable argument: "
7765 void trackStatistics()
const override {
7770struct AAPrivatizablePtrCallSiteArgument final
7771 :
public AAPrivatizablePtrFloating {
7772 AAPrivatizablePtrCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
7773 : AAPrivatizablePtrFloating(IRP,
A) {}
7777 if (
A.hasAttr(getIRPosition(), Attribute::ByVal))
7778 indicateOptimisticFixpoint();
7783 PrivatizableType = identifyPrivatizableType(
A);
7784 if (!PrivatizableType)
7785 return ChangeStatus::UNCHANGED;
7786 if (!*PrivatizableType)
7787 return indicatePessimisticFixpoint();
7789 const IRPosition &IRP = getIRPosition();
7790 bool IsKnownNoCapture;
7792 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoCapture);
7793 if (!IsAssumedNoCapture) {
7794 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might be captured!\n");
7795 return indicatePessimisticFixpoint();
7798 bool IsKnownNoAlias;
7800 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
7801 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might alias!\n");
7802 return indicatePessimisticFixpoint();
7807 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer is written!\n");
7808 return indicatePessimisticFixpoint();
7811 return ChangeStatus::UNCHANGED;
7815 void trackStatistics()
const override {
7820struct AAPrivatizablePtrCallSiteReturned final
7821 :
public AAPrivatizablePtrFloating {
7822 AAPrivatizablePtrCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
7823 : AAPrivatizablePtrFloating(IRP,
A) {}
7828 indicatePessimisticFixpoint();
7832 void trackStatistics()
const override {
7837struct AAPrivatizablePtrReturned final :
public AAPrivatizablePtrFloating {
7838 AAPrivatizablePtrReturned(
const IRPosition &IRP, Attributor &
A)
7839 : AAPrivatizablePtrFloating(IRP,
A) {}
7844 indicatePessimisticFixpoint();
7848 void trackStatistics()
const override {
7858struct AAMemoryBehaviorImpl :
public AAMemoryBehavior {
7859 AAMemoryBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
7860 : AAMemoryBehavior(IRP,
A) {}
7864 intersectAssumedBits(BEST_STATE);
7865 getKnownStateFromValue(
A, getIRPosition(), getState());
7866 AAMemoryBehavior::initialize(
A);
7870 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
7871 BitIntegerState &State,
7872 bool IgnoreSubsumingPositions =
false) {
7874 A.getAttrs(IRP, AttrKinds, Attrs, IgnoreSubsumingPositions);
7876 switch (Attr.getKindAsEnum()) {
7877 case Attribute::ReadNone:
7880 case Attribute::ReadOnly:
7883 case Attribute::WriteOnly:
7892 if (!
I->mayReadFromMemory())
7894 if (!
I->mayWriteToMemory())
7900 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
7901 SmallVectorImpl<Attribute> &Attrs)
const override {
7904 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));
7906 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));
7907 else if (isAssumedWriteOnly())
7908 Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));
7914 const IRPosition &IRP = getIRPosition();
7916 if (
A.hasAttr(IRP, Attribute::ReadNone,
7918 return ChangeStatus::UNCHANGED;
7927 return ChangeStatus::UNCHANGED;
7930 A.removeAttrs(IRP, AttrKinds);
7933 A.removeAttrs(IRP, Attribute::Writable);
7940 const std::string getAsStr(Attributor *
A)
const override {
7945 if (isAssumedWriteOnly())
7947 return "may-read/write";
7951 static const Attribute::AttrKind AttrKinds[3];
7955 Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};
7958struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {
7959 AAMemoryBehaviorFloating(
const IRPosition &IRP, Attributor &
A)
7960 : AAMemoryBehaviorImpl(IRP,
A) {}
7966 void trackStatistics()
const override {
7971 else if (isAssumedWriteOnly())
7978 bool followUsersOfUseIn(Attributor &
A,
const Use &U,
7979 const Instruction *UserI);
7982 void analyzeUseIn(Attributor &
A,
const Use &U,
const Instruction *UserI);
7986struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
7987 AAMemoryBehaviorArgument(
const IRPosition &IRP, Attributor &
A)
7988 : AAMemoryBehaviorFloating(IRP,
A) {}
7992 intersectAssumedBits(BEST_STATE);
7993 const IRPosition &IRP = getIRPosition();
7997 bool HasByVal =
A.hasAttr(IRP, {Attribute::ByVal},
7999 getKnownStateFromValue(
A, IRP, getState(),
8006 return ChangeStatus::UNCHANGED;
8010 if (
A.hasAttr(getIRPosition(),
8011 {Attribute::InAlloca, Attribute::Preallocated})) {
8012 removeKnownBits(NO_WRITES);
8013 removeAssumedBits(NO_WRITES);
8015 A.removeAttrs(getIRPosition(), AttrKinds);
8016 return AAMemoryBehaviorFloating::manifest(
A);
8020 void trackStatistics()
const override {
8025 else if (isAssumedWriteOnly())
8030struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {
8031 AAMemoryBehaviorCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
8032 : AAMemoryBehaviorArgument(IRP,
A) {}
8038 Argument *Arg = getAssociatedArgument();
8040 indicatePessimisticFixpoint();
8044 addKnownBits(NO_WRITES);
8045 removeKnownBits(NO_READS);
8046 removeAssumedBits(NO_READS);
8048 AAMemoryBehaviorArgument::initialize(
A);
8049 if (getAssociatedFunction()->isDeclaration())
8050 indicatePessimisticFixpoint();
8059 Argument *Arg = getAssociatedArgument();
8062 A.getAAFor<AAMemoryBehavior>(*
this, ArgPos, DepClassTy::REQUIRED);
8064 return indicatePessimisticFixpoint();
8069 void trackStatistics()
const override {
8074 else if (isAssumedWriteOnly())
8080struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {
8081 AAMemoryBehaviorCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
8082 : AAMemoryBehaviorFloating(IRP,
A) {}
8086 AAMemoryBehaviorImpl::initialize(
A);
8091 return ChangeStatus::UNCHANGED;
8095 void trackStatistics()
const override {}
8099struct AAMemoryBehaviorFunction final :
public AAMemoryBehaviorImpl {
8100 AAMemoryBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
8101 : AAMemoryBehaviorImpl(IRP,
A) {}
8117 else if (isAssumedWriteOnly())
8120 A.removeAttrs(getIRPosition(), AttrKinds);
8123 for (Argument &Arg :
F.args())
8125 return A.manifestAttrs(getIRPosition(),
8126 Attribute::getWithMemoryEffects(
F.getContext(), ME));
8130 void trackStatistics()
const override {
8135 else if (isAssumedWriteOnly())
8141struct AAMemoryBehaviorCallSite final
8142 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl> {
8143 AAMemoryBehaviorCallSite(
const IRPosition &IRP, Attributor &
A)
8144 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl>(IRP,
A) {}
8155 else if (isAssumedWriteOnly())
8158 A.removeAttrs(getIRPosition(), AttrKinds);
8161 for (Use &U : CB.
args())
8163 Attribute::Writable);
8164 return A.manifestAttrs(
8165 getIRPosition(), Attribute::getWithMemoryEffects(CB.
getContext(), ME));
8169 void trackStatistics()
const override {
8174 else if (isAssumedWriteOnly())
8179ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &
A) {
8182 auto AssumedState = getAssumed();
8189 const auto *MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
8191 if (MemBehaviorAA) {
8192 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8193 return !isAtFixpoint();
8198 if (
I.mayReadFromMemory())
8199 removeAssumedBits(NO_READS);
8200 if (
I.mayWriteToMemory())
8201 removeAssumedBits(NO_WRITES);
8202 return !isAtFixpoint();
8205 bool UsedAssumedInformation =
false;
8206 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8207 UsedAssumedInformation))
8208 return indicatePessimisticFixpoint();
8214ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &
A) {
8216 const IRPosition &IRP = getIRPosition();
8227 const auto *FnMemAA =
8230 FnMemAssumedState = FnMemAA->getAssumed();
8231 S.addKnownBits(FnMemAA->getKnown());
8232 if ((S.getAssumed() & FnMemAA->getAssumed()) == S.getAssumed())
8238 auto AssumedState = S.getAssumed();
8244 bool IsKnownNoCapture;
8245 const AANoCapture *ArgNoCaptureAA =
nullptr;
8250 if (!IsAssumedNoCapture &&
8252 S.intersectAssumedBits(FnMemAssumedState);
8258 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
8260 LLVM_DEBUG(
dbgs() <<
"[AAMemoryBehavior] Use: " << *U <<
" in " << *UserI
8268 Follow = followUsersOfUseIn(
A, U, UserI);
8272 analyzeUseIn(
A, U, UserI);
8274 return !isAtFixpoint();
8277 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue()))
8278 return indicatePessimisticFixpoint();
8284bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &
A,
const Use &U,
8285 const Instruction *UserI) {
8303 if (
U.get()->getType()->isPointerTy()) {
8305 bool IsKnownNoCapture;
8314void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &
A,
const Use &U,
8315 const Instruction *UserI) {
8322 case Instruction::Load:
8324 removeAssumedBits(NO_READS);
8327 case Instruction::Store:
8332 removeAssumedBits(NO_WRITES);
8334 indicatePessimisticFixpoint();
8337 case Instruction::Call:
8338 case Instruction::CallBr:
8339 case Instruction::Invoke: {
8346 indicatePessimisticFixpoint();
8353 removeAssumedBits(NO_READS);
8360 if (
U.get()->getType()->isPointerTy())
8364 const auto *MemBehaviorAA =
8370 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8378 removeAssumedBits(NO_READS);
8380 removeAssumedBits(NO_WRITES);
8392 return "all memory";
8395 std::string S =
"memory:";
8401 S +=
"internal global,";
8403 S +=
"external global,";
8407 S +=
"inaccessible,";
8421 AccessKind2Accesses.fill(
nullptr);
8424 ~AAMemoryLocationImpl()
override {
8427 for (AccessSet *AS : AccessKind2Accesses)
8434 intersectAssumedBits(BEST_STATE);
8435 getKnownStateFromValue(
A, getIRPosition(), getState());
8436 AAMemoryLocation::initialize(
A);
8440 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
8441 BitIntegerState &State,
8442 bool IgnoreSubsumingPositions =
false) {
8451 bool UseArgMemOnly =
true;
8453 if (AnchorFn &&
A.isRunOn(*AnchorFn))
8457 A.getAttrs(IRP, {Attribute::Memory},
Attrs, IgnoreSubsumingPositions);
8466 State.
addKnownBits(inverseLocation(NO_INACCESSIBLE_MEM,
true,
true));
8471 State.
addKnownBits(inverseLocation(NO_ARGUMENT_MEM,
true,
true));
8475 A.manifestAttrs(IRP,
8476 Attribute::getWithMemoryEffects(
8485 NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM,
true,
true));
8489 A.manifestAttrs(IRP,
8490 Attribute::getWithMemoryEffects(
8500 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
8501 SmallVectorImpl<Attribute> &Attrs)
const override {
8508 else if (isAssumedInaccessibleMemOnly())
8509 Attrs.push_back(Attribute::getWithMemoryEffects(
8511 else if (isAssumedArgMemOnly())
8514 else if (isAssumedInaccessibleOrArgMemOnly())
8515 Attrs.push_back(Attribute::getWithMemoryEffects(
8525 const IRPosition &IRP = getIRPosition();
8529 if (DeducedAttrs.
size() != 1)
8530 return ChangeStatus::UNCHANGED;
8533 return A.manifestAttrs(IRP, Attribute::getWithMemoryEffects(
8538 bool checkForAllAccessesToMemoryKind(
8540 MemoryLocationsKind)>
8542 MemoryLocationsKind RequestedMLK)
const override {
8543 if (!isValidState())
8546 MemoryLocationsKind AssumedMLK = getAssumedNotAccessedLocation();
8547 if (AssumedMLK == NO_LOCATIONS)
8551 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS;
8552 CurMLK *= 2, ++Idx) {
8553 if (CurMLK & RequestedMLK)
8556 if (
const AccessSet *
Accesses = AccessKind2Accesses[Idx])
8557 for (
const AccessInfo &AI : *
Accesses)
8558 if (!Pred(AI.I, AI.Ptr, AI.Kind, CurMLK))
8571 MemoryLocationsKind KnownMLK = getKnown();
8573 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2)
8574 if (!(CurMLK & KnownMLK))
8575 updateStateAndAccessesMap(getState(), CurMLK,
I,
nullptr,
Changed,
8576 getAccessKindFromInst(
I));
8577 return AAMemoryLocation::indicatePessimisticFixpoint();
8597 bool operator()(
const AccessInfo &
LHS,
const AccessInfo &
RHS)
const {
8601 return LHS.Ptr <
RHS.Ptr;
8602 if (
LHS.Kind !=
RHS.Kind)
8603 return LHS.Kind <
RHS.Kind;
8610 using AccessSet = SmallSet<AccessInfo, 2, AccessInfo>;
8611 std::array<AccessSet *, llvm::ConstantLog2<VALID_STATE>()>
8612 AccessKind2Accesses;
8617 categorizeArgumentPointerLocations(Attributor &
A, CallBase &CB,
8618 AAMemoryLocation::StateType &AccessedLocs,
8623 categorizeAccessedLocations(Attributor &
A, Instruction &
I,
bool &
Changed);
8626 AccessKind getAccessKindFromInst(
const Instruction *
I) {
8629 AK =
I->mayReadFromMemory() ? READ :
NONE;
8638 void updateStateAndAccessesMap(AAMemoryLocation::StateType &State,
8639 MemoryLocationsKind MLK,
const Instruction *
I,
8648 if (MLK == NO_UNKOWN_MEM)
8650 State.removeAssumedBits(MLK);
8655 void categorizePtrValue(Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8656 AAMemoryLocation::StateType &State,
bool &
Changed,
8657 unsigned AccessAS = 0);
8663void AAMemoryLocationImpl::categorizePtrValue(
8664 Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8666 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize pointer locations for "
8671 unsigned ObjectAS =
Obj.getType()->getPointerAddressSpace();
8673 MemoryLocationsKind MLK = NO_LOCATIONS;
8692 MLK = NO_ARGUMENT_MEM;
8698 if (GVar->isConstant())
8701 if (GV->hasLocalLinkage())
8702 MLK = NO_GLOBAL_INTERNAL_MEM;
8704 MLK = NO_GLOBAL_EXTERNAL_MEM;
8712 bool IsKnownNoAlias;
8716 MLK = NO_MALLOCED_MEM;
8718 MLK = NO_UNKOWN_MEM;
8720 MLK = NO_UNKOWN_MEM;
8723 assert(MLK != NO_LOCATIONS &&
"No location specified!");
8724 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Ptr value can be categorized: "
8725 << Obj <<
" -> " << getMemoryLocationsAsStr(MLK) <<
"\n");
8727 getAccessKindFromInst(&
I));
8732 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
8736 dbgs() <<
"[AAMemoryLocation] Pointer locations not categorized\n");
8737 updateStateAndAccessesMap(
State, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8738 getAccessKindFromInst(&
I));
8743 dbgs() <<
"[AAMemoryLocation] Accessed locations with pointer locations: "
8747void AAMemoryLocationImpl::categorizeArgumentPointerLocations(
8750 for (
unsigned ArgNo = 0,
E = CB.
arg_size(); ArgNo <
E; ++ArgNo) {
8759 const auto *ArgOpMemLocationAA =
8762 if (ArgOpMemLocationAA && ArgOpMemLocationAA->isAssumedReadNone())
8767 categorizePtrValue(
A, CB, *ArgOp, AccessedLocs,
Changed);
8772AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &
A, Instruction &
I,
8774 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize accessed locations for "
8778 AccessedLocs.intersectAssumedBits(NO_LOCATIONS);
8783 const auto *CBMemLocationAA =
A.getAAFor<AAMemoryLocation>(
8786 <<
" [" << CBMemLocationAA <<
"]\n");
8787 if (!CBMemLocationAA) {
8788 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
8789 Changed, getAccessKindFromInst(&
I));
8790 return NO_UNKOWN_MEM;
8793 if (CBMemLocationAA->isAssumedReadNone())
8794 return NO_LOCATIONS;
8796 if (CBMemLocationAA->isAssumedInaccessibleMemOnly()) {
8797 updateStateAndAccessesMap(AccessedLocs, NO_INACCESSIBLE_MEM, &
I,
nullptr,
8798 Changed, getAccessKindFromInst(&
I));
8799 return AccessedLocs.getAssumed();
8802 uint32_t CBAssumedNotAccessedLocs =
8803 CBMemLocationAA->getAssumedNotAccessedLocation();
8806 uint32_t CBAssumedNotAccessedLocsNoArgMem =
8807 CBAssumedNotAccessedLocs | NO_ARGUMENT_MEM | NO_GLOBAL_MEM;
8809 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2) {
8810 if (CBAssumedNotAccessedLocsNoArgMem & CurMLK)
8812 updateStateAndAccessesMap(AccessedLocs, CurMLK, &
I,
nullptr,
Changed,
8813 getAccessKindFromInst(&
I));
8818 bool HasGlobalAccesses = ((~CBAssumedNotAccessedLocs) & NO_GLOBAL_MEM);
8819 if (HasGlobalAccesses) {
8822 updateStateAndAccessesMap(AccessedLocs, MLK, &
I, Ptr,
Changed,
8823 getAccessKindFromInst(&
I));
8826 if (!CBMemLocationAA->checkForAllAccessesToMemoryKind(
8827 AccessPred, inverseLocation(NO_GLOBAL_MEM,
false,
false)))
8828 return AccessedLocs.getWorstState();
8832 dbgs() <<
"[AAMemoryLocation] Accessed state before argument handling: "
8833 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8836 bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM);
8838 categorizeArgumentPointerLocations(
A, *CB, AccessedLocs,
Changed);
8841 dbgs() <<
"[AAMemoryLocation] Accessed state after argument handling: "
8842 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8844 return AccessedLocs.getAssumed();
8849 dbgs() <<
"[AAMemoryLocation] Categorize memory access with pointer: "
8850 <<
I <<
" [" << *Ptr <<
"]\n");
8851 categorizePtrValue(
A,
I, *Ptr, AccessedLocs,
Changed,
8852 Ptr->getType()->getPointerAddressSpace());
8853 return AccessedLocs.getAssumed();
8856 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Failed to categorize instruction: "
8858 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8859 getAccessKindFromInst(&
I));
8860 return AccessedLocs.getAssumed();
8864struct AAMemoryLocationFunction final :
public AAMemoryLocationImpl {
8865 AAMemoryLocationFunction(
const IRPosition &IRP, Attributor &
A)
8866 : AAMemoryLocationImpl(IRP,
A) {}
8871 const auto *MemBehaviorAA =
8872 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
8875 return indicateOptimisticFixpoint();
8877 "AAMemoryLocation was not read-none but AAMemoryBehavior was!");
8878 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
8879 return ChangeStatus::UNCHANGED;
8883 auto AssumedState = getAssumed();
8887 MemoryLocationsKind MLK = categorizeAccessedLocations(
A,
I,
Changed);
8888 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Accessed locations for " <<
I
8889 <<
": " << getMemoryLocationsAsStr(MLK) <<
"\n");
8890 removeAssumedBits(inverseLocation(MLK,
false,
false));
8893 return getAssumedNotAccessedLocation() != VALID_STATE;
8896 bool UsedAssumedInformation =
false;
8897 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8898 UsedAssumedInformation))
8899 return indicatePessimisticFixpoint();
8901 Changed |= AssumedState != getAssumed();
8902 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8906 void trackStatistics()
const override {
8909 else if (isAssumedArgMemOnly())
8911 else if (isAssumedInaccessibleMemOnly())
8913 else if (isAssumedInaccessibleOrArgMemOnly())
8919struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {
8920 AAMemoryLocationCallSite(
const IRPosition &IRP, Attributor &
A)
8921 : AAMemoryLocationImpl(IRP,
A) {}
8932 A.getAAFor<AAMemoryLocation>(*
this, FnPos, DepClassTy::REQUIRED);
8934 return indicatePessimisticFixpoint();
8938 updateStateAndAccessesMap(getState(), MLK,
I, Ptr,
Changed,
8939 getAccessKindFromInst(
I));
8942 if (!FnAA->checkForAllAccessesToMemoryKind(AccessPred, ALL_LOCATIONS))
8943 return indicatePessimisticFixpoint();
8944 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8948 void trackStatistics()
const override {
8958struct AADenormalFPMathImpl :
public AADenormalFPMath {
8959 AADenormalFPMathImpl(
const IRPosition &IRP, Attributor &
A)
8960 : AADenormalFPMath(IRP,
A) {}
8962 const std::string getAsStr(Attributor *
A)
const override {
8963 std::string Str(
"AADenormalFPMath[");
8964 raw_string_ostream OS(Str);
8966 DenormalState Known = getKnown();
8967 if (Known.Mode.isValid())
8968 OS <<
"denormal-fp-math=" << Known.Mode;
8972 if (Known.ModeF32.isValid())
8973 OS <<
" denormal-fp-math-f32=" << Known.ModeF32;
8979struct AADenormalFPMathFunction final : AADenormalFPMathImpl {
8980 AADenormalFPMathFunction(
const IRPosition &IRP, Attributor &
A)
8981 : AADenormalFPMathImpl(IRP,
A) {}
8985 DenormalMode
Mode =
F->getDenormalModeRaw();
8986 DenormalMode ModeF32 =
F->getDenormalModeF32Raw();
8993 Known = DenormalState{
Mode, ModeF32};
9001 auto CheckCallSite = [=, &Change, &
A](AbstractCallSite CS) {
9004 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
9006 const auto *CallerInfo =
A.getAAFor<AADenormalFPMath>(
9012 CallerInfo->getState());
9016 bool AllCallSitesKnown =
true;
9017 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
9018 return indicatePessimisticFixpoint();
9020 if (Change == ChangeStatus::CHANGED && isModeFixed())
9026 LLVMContext &Ctx = getAssociatedFunction()->getContext();
9031 AttrToRemove.
push_back(
"denormal-fp-math");
9034 Attribute::get(Ctx,
"denormal-fp-math", Known.Mode.str()));
9037 if (Known.ModeF32 != Known.Mode) {
9039 Attribute::get(Ctx,
"denormal-fp-math-f32", Known.ModeF32.str()));
9041 AttrToRemove.
push_back(
"denormal-fp-math-f32");
9044 auto &IRP = getIRPosition();
9047 return A.removeAttrs(IRP, AttrToRemove) |
9048 A.manifestAttrs(IRP, AttrToAdd,
true);
9051 void trackStatistics()
const override {
9060struct AAValueConstantRangeImpl : AAValueConstantRange {
9061 using StateType = IntegerRangeState;
9062 AAValueConstantRangeImpl(
const IRPosition &IRP, Attributor &
A)
9063 : AAValueConstantRange(IRP,
A) {}
9067 if (
A.hasSimplificationCallback(getIRPosition())) {
9068 indicatePessimisticFixpoint();
9073 intersectKnown(getConstantRangeFromSCEV(
A, getCtxI()));
9076 intersectKnown(getConstantRangeFromLVI(
A, getCtxI()));
9080 const std::string getAsStr(Attributor *
A)
const override {
9082 llvm::raw_string_ostream OS(Str);
9084 getKnown().print(OS);
9086 getAssumed().print(OS);
9093 const SCEV *getSCEV(Attributor &
A,
const Instruction *
I =
nullptr)
const {
9094 if (!getAnchorScope())
9097 ScalarEvolution *SE =
9098 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9101 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
9107 const SCEV *S = SE->
getSCEV(&getAssociatedValue());
9116 ConstantRange getConstantRangeFromSCEV(Attributor &
A,
9117 const Instruction *
I =
nullptr)
const {
9118 if (!getAnchorScope())
9121 ScalarEvolution *SE =
9122 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9125 const SCEV *S = getSCEV(
A,
I);
9135 getConstantRangeFromLVI(Attributor &
A,
9136 const Instruction *CtxI =
nullptr)
const {
9137 if (!getAnchorScope())
9140 LazyValueInfo *LVI =
9141 A.getInfoCache().getAnalysisResultForFunction<LazyValueAnalysis>(
9156 bool isValidCtxInstructionForOutsideAnalysis(Attributor &
A,
9157 const Instruction *CtxI,
9158 bool AllowAACtxI)
const {
9159 if (!CtxI || (!AllowAACtxI && CtxI == getCtxI()))
9171 InformationCache &InfoCache =
A.getInfoCache();
9172 const DominatorTree *DT =
9183 getKnownConstantRange(Attributor &
A,
9184 const Instruction *CtxI =
nullptr)
const override {
9185 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9189 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9190 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9191 return getKnown().intersectWith(SCEVR).intersectWith(LVIR);
9196 getAssumedConstantRange(Attributor &
A,
9197 const Instruction *CtxI =
nullptr)
const override {
9202 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9204 return getAssumed();
9206 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9207 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9208 return getAssumed().intersectWith(SCEVR).intersectWith(LVIR);
9213 getMDNodeForConstantRange(
Type *Ty, LLVMContext &Ctx,
9214 const ConstantRange &AssumedConstantRange) {
9216 Ty, AssumedConstantRange.
getLower())),
9218 Ty, AssumedConstantRange.
getUpper()))};
9223 static bool isBetterRange(
const ConstantRange &Assumed,
9224 const Instruction &
I) {
9228 std::optional<ConstantRange> Known;
9232 }
else if (MDNode *KnownRanges =
I.getMetadata(LLVMContext::MD_range)) {
9238 if (KnownRanges->getNumOperands() > 2)
9241 ConstantInt *
Lower =
9243 ConstantInt *
Upper =
9246 Known.emplace(
Lower->getValue(),
Upper->getValue());
9248 return !Known || (*Known != Assumed && Known->contains(Assumed));
9253 setRangeMetadataIfisBetterRange(Instruction *
I,
9254 const ConstantRange &AssumedConstantRange) {
9255 if (isBetterRange(AssumedConstantRange, *
I)) {
9256 I->setMetadata(LLVMContext::MD_range,
9257 getMDNodeForConstantRange(
I->getType(),
I->getContext(),
9258 AssumedConstantRange));
9265 setRangeRetAttrIfisBetterRange(Attributor &
A,
const IRPosition &IRP,
9267 const ConstantRange &AssumedConstantRange) {
9268 if (isBetterRange(AssumedConstantRange, *
I)) {
9269 A.manifestAttrs(IRP,
9270 Attribute::get(
I->getContext(), Attribute::Range,
9271 AssumedConstantRange),
9281 ConstantRange AssumedConstantRange = getAssumedConstantRange(
A);
9284 auto &
V = getAssociatedValue();
9288 assert(
I == getCtxI() &&
"Should not annotate an instruction which is "
9289 "not the context instruction");
9291 if (setRangeMetadataIfisBetterRange(
I, AssumedConstantRange))
9292 Changed = ChangeStatus::CHANGED;
9294 if (setRangeRetAttrIfisBetterRange(
A, getIRPosition(),
I,
9295 AssumedConstantRange))
9296 Changed = ChangeStatus::CHANGED;
9304struct AAValueConstantRangeArgument final
9305 : AAArgumentFromCallSiteArguments<
9306 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9308 using Base = AAArgumentFromCallSiteArguments<
9309 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9311 AAValueConstantRangeArgument(
const IRPosition &IRP, Attributor &
A)
9315 void trackStatistics()
const override {
9320struct AAValueConstantRangeReturned
9321 : AAReturnedFromReturnedValues<AAValueConstantRange,
9322 AAValueConstantRangeImpl,
9323 AAValueConstantRangeImpl::StateType,
9326 AAReturnedFromReturnedValues<AAValueConstantRange,
9327 AAValueConstantRangeImpl,
9328 AAValueConstantRangeImpl::StateType,
9330 AAValueConstantRangeReturned(
const IRPosition &IRP, Attributor &
A)
9335 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9336 indicatePessimisticFixpoint();
9340 void trackStatistics()
const override {
9345struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
9346 AAValueConstantRangeFloating(
const IRPosition &IRP, Attributor &
A)
9347 : AAValueConstantRangeImpl(IRP,
A) {}
9351 AAValueConstantRangeImpl::initialize(
A);
9355 Value &
V = getAssociatedValue();
9358 unionAssumed(ConstantRange(
C->getValue()));
9359 indicateOptimisticFixpoint();
9365 unionAssumed(ConstantRange(APInt(
getBitWidth(), 0)));
9366 indicateOptimisticFixpoint();
9378 if (
auto *RangeMD = LI->getMetadata(LLVMContext::MD_range)) {
9389 indicatePessimisticFixpoint();
9392 << getAssociatedValue() <<
"\n");
9395 bool calculateBinaryOperator(
9396 Attributor &
A, BinaryOperator *BinOp, IntegerRangeState &
T,
9397 const Instruction *CtxI,
9398 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9403 bool UsedAssumedInformation =
false;
9404 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9407 if (!SimplifiedLHS.has_value())
9409 if (!*SimplifiedLHS)
9411 LHS = *SimplifiedLHS;
9413 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9416 if (!SimplifiedRHS.has_value())
9418 if (!*SimplifiedRHS)
9420 RHS = *SimplifiedRHS;
9426 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9428 DepClassTy::REQUIRED);
9432 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9434 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9436 DepClassTy::REQUIRED);
9440 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9442 auto AssumedRange = LHSAARange.binaryOp(BinOp->
getOpcode(), RHSAARange);
9444 T.unionAssumed(AssumedRange);
9448 return T.isValidState();
9451 bool calculateCastInst(
9452 Attributor &
A, CastInst *CastI, IntegerRangeState &
T,
9453 const Instruction *CtxI,
9454 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9460 bool UsedAssumedInformation =
false;
9461 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9464 if (!SimplifiedOpV.has_value())
9466 if (!*SimplifiedOpV)
9468 OpV = *SimplifiedOpV;
9473 auto *OpAA =
A.getAAFor<AAValueConstantRange>(
9475 DepClassTy::REQUIRED);
9479 T.unionAssumed(OpAA->getAssumed().castOp(CastI->
getOpcode(),
9481 return T.isValidState();
9485 calculateCmpInst(Attributor &
A, CmpInst *CmpI, IntegerRangeState &
T,
9486 const Instruction *CtxI,
9487 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9492 bool UsedAssumedInformation =
false;
9493 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9496 if (!SimplifiedLHS.has_value())
9498 if (!*SimplifiedLHS)
9500 LHS = *SimplifiedLHS;
9502 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9505 if (!SimplifiedRHS.has_value())
9507 if (!*SimplifiedRHS)
9509 RHS = *SimplifiedRHS;
9515 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9517 DepClassTy::REQUIRED);
9521 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9523 DepClassTy::REQUIRED);
9527 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9528 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9531 if (LHSAARange.isEmptySet() || RHSAARange.isEmptySet())
9534 bool MustTrue =
false, MustFalse =
false;
9536 auto AllowedRegion =
9539 if (AllowedRegion.intersectWith(LHSAARange).isEmptySet())
9545 assert((!MustTrue || !MustFalse) &&
9546 "Either MustTrue or MustFalse should be false!");
9549 T.unionAssumed(ConstantRange(APInt( 1, 1)));
9551 T.unionAssumed(ConstantRange(APInt( 1, 0)));
9553 T.unionAssumed(ConstantRange( 1,
true));
9555 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] " << *CmpI <<
" after "
9556 << (MustTrue ?
"true" : (MustFalse ?
"false" :
"unknown"))
9557 <<
": " <<
T <<
"\n\t" << *LHSAA <<
"\t<op>\n\t"
9561 return T.isValidState();
9573 bool UsedAssumedInformation =
false;
9574 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9577 if (!SimplifiedOpV.has_value())
9579 if (!*SimplifiedOpV)
9581 Value *VPtr = *SimplifiedOpV;
9584 const auto *AA =
A.getAAFor<AAValueConstantRange>(
9586 DepClassTy::REQUIRED);
9590 T.unionAssumed(AA->getAssumedConstantRange(
A, CtxI));
9594 return T.isValidState();
9599 if (!calculateBinaryOperator(
A, BinOp,
T, CtxI, QuerriedAAs))
9602 if (!calculateCmpInst(
A, CmpI,
T, CtxI, QuerriedAAs))
9605 if (!calculateCastInst(
A, CastI,
T, CtxI, QuerriedAAs))
9611 T.indicatePessimisticFixpoint();
9618 for (
const AAValueConstantRange *QueriedAA : QuerriedAAs) {
9619 if (QueriedAA !=
this)
9622 if (
T.getAssumed() == getState().getAssumed())
9624 T.indicatePessimisticFixpoint();
9627 return T.isValidState();
9630 if (!VisitValueCB(getAssociatedValue(), getCtxI()))
9631 return indicatePessimisticFixpoint();
9636 return ChangeStatus::UNCHANGED;
9637 if (++NumChanges > MaxNumChanges) {
9638 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] performed " << NumChanges
9639 <<
" but only " << MaxNumChanges
9640 <<
" are allowed to avoid cyclic reasoning.");
9641 return indicatePessimisticFixpoint();
9643 return ChangeStatus::CHANGED;
9647 void trackStatistics()
const override {
9656 static constexpr int MaxNumChanges = 5;
9659struct AAValueConstantRangeFunction : AAValueConstantRangeImpl {
9660 AAValueConstantRangeFunction(
const IRPosition &IRP, Attributor &
A)
9661 : AAValueConstantRangeImpl(IRP,
A) {}
9665 llvm_unreachable(
"AAValueConstantRange(Function|CallSite)::updateImpl will "
9673struct AAValueConstantRangeCallSite : AAValueConstantRangeFunction {
9674 AAValueConstantRangeCallSite(
const IRPosition &IRP, Attributor &
A)
9675 : AAValueConstantRangeFunction(IRP,
A) {}
9681struct AAValueConstantRangeCallSiteReturned
9682 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9683 AAValueConstantRangeImpl::StateType,
9685 AAValueConstantRangeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
9686 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9687 AAValueConstantRangeImpl::StateType,
9694 if (std::optional<ConstantRange>
Range = CI->getRange())
9695 intersectKnown(*
Range);
9698 AAValueConstantRangeImpl::initialize(
A);
9702 void trackStatistics()
const override {
9706struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating {
9707 AAValueConstantRangeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
9708 : AAValueConstantRangeFloating(IRP,
A) {}
9712 return ChangeStatus::UNCHANGED;
9716 void trackStatistics()
const override {
9725struct AAPotentialConstantValuesImpl : AAPotentialConstantValues {
9728 AAPotentialConstantValuesImpl(
const IRPosition &IRP, Attributor &
A)
9729 : AAPotentialConstantValues(IRP,
A) {}
9733 if (
A.hasSimplificationCallback(getIRPosition()))
9734 indicatePessimisticFixpoint();
9736 AAPotentialConstantValues::initialize(
A);
9739 bool fillSetWithConstantValues(Attributor &
A,
const IRPosition &IRP, SetTy &S,
9740 bool &ContainsUndef,
bool ForSelf) {
9742 bool UsedAssumedInformation =
false;
9744 UsedAssumedInformation)) {
9751 auto *PotentialValuesAA =
A.getAAFor<AAPotentialConstantValues>(
9752 *
this, IRP, DepClassTy::REQUIRED);
9753 if (!PotentialValuesAA || !PotentialValuesAA->getState().isValidState())
9755 ContainsUndef = PotentialValuesAA->getState().undefIsContained();
9756 S = PotentialValuesAA->getState().getAssumedSet();
9763 ContainsUndef =
false;
9764 for (
auto &It : Values) {
9766 ContainsUndef =
true;
9772 S.insert(CI->getValue());
9774 ContainsUndef &= S.empty();
9780 const std::string getAsStr(Attributor *
A)
const override {
9782 llvm::raw_string_ostream OS(Str);
9789 return indicatePessimisticFixpoint();
9793struct AAPotentialConstantValuesArgument final
9794 : AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9795 AAPotentialConstantValuesImpl,
9796 PotentialConstantIntValuesState> {
9797 using Base = AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9798 AAPotentialConstantValuesImpl,
9800 AAPotentialConstantValuesArgument(
const IRPosition &IRP, Attributor &
A)
9804 void trackStatistics()
const override {
9809struct AAPotentialConstantValuesReturned
9810 : AAReturnedFromReturnedValues<AAPotentialConstantValues,
9811 AAPotentialConstantValuesImpl> {
9812 using Base = AAReturnedFromReturnedValues<AAPotentialConstantValues,
9813 AAPotentialConstantValuesImpl>;
9814 AAPotentialConstantValuesReturned(
const IRPosition &IRP, Attributor &
A)
9818 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9819 indicatePessimisticFixpoint();
9820 Base::initialize(
A);
9824 void trackStatistics()
const override {
9829struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl {
9830 AAPotentialConstantValuesFloating(
const IRPosition &IRP, Attributor &
A)
9831 : AAPotentialConstantValuesImpl(IRP,
A) {}
9835 AAPotentialConstantValuesImpl::initialize(
A);
9839 Value &
V = getAssociatedValue();
9842 unionAssumed(
C->getValue());
9843 indicateOptimisticFixpoint();
9848 unionAssumedWithUndef();
9849 indicateOptimisticFixpoint();
9859 indicatePessimisticFixpoint();
9862 << getAssociatedValue() <<
"\n");
9865 static bool calculateICmpInst(
const ICmpInst *ICI,
const APInt &
LHS,
9870 static APInt calculateCastInst(
const CastInst *CI,
const APInt &Src,
9871 uint32_t ResultBitWidth) {
9876 case Instruction::Trunc:
9877 return Src.trunc(ResultBitWidth);
9878 case Instruction::SExt:
9879 return Src.sext(ResultBitWidth);
9880 case Instruction::ZExt:
9881 return Src.zext(ResultBitWidth);
9882 case Instruction::BitCast:
9887 static APInt calculateBinaryOperator(
const BinaryOperator *BinOp,
9888 const APInt &
LHS,
const APInt &
RHS,
9889 bool &SkipOperation,
bool &Unsupported) {
9896 switch (BinOpcode) {
9900 case Instruction::Add:
9902 case Instruction::Sub:
9904 case Instruction::Mul:
9906 case Instruction::UDiv:
9908 SkipOperation =
true;
9912 case Instruction::SDiv:
9914 SkipOperation =
true;
9918 case Instruction::URem:
9920 SkipOperation =
true;
9924 case Instruction::SRem:
9926 SkipOperation =
true;
9930 case Instruction::Shl:
9932 case Instruction::LShr:
9934 case Instruction::AShr:
9936 case Instruction::And:
9938 case Instruction::Or:
9940 case Instruction::Xor:
9945 bool calculateBinaryOperatorAndTakeUnion(
const BinaryOperator *BinOp,
9946 const APInt &
LHS,
const APInt &
RHS) {
9947 bool SkipOperation =
false;
9950 calculateBinaryOperator(BinOp,
LHS,
RHS, SkipOperation, Unsupported);
9955 unionAssumed(Result);
9956 return isValidState();
9959 ChangeStatus updateWithICmpInst(Attributor &
A, ICmpInst *ICI) {
9960 auto AssumedBefore = getAssumed();
9964 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
9965 SetTy LHSAAPVS, RHSAAPVS;
9967 LHSContainsUndef,
false) ||
9969 RHSContainsUndef,
false))
9970 return indicatePessimisticFixpoint();
9973 bool MaybeTrue =
false, MaybeFalse =
false;
9975 if (LHSContainsUndef && RHSContainsUndef) {
9978 unionAssumedWithUndef();
9979 }
else if (LHSContainsUndef) {
9980 for (
const APInt &R : RHSAAPVS) {
9981 bool CmpResult = calculateICmpInst(ICI, Zero, R);
9982 MaybeTrue |= CmpResult;
9983 MaybeFalse |= !CmpResult;
9984 if (MaybeTrue & MaybeFalse)
9985 return indicatePessimisticFixpoint();
9987 }
else if (RHSContainsUndef) {
9988 for (
const APInt &L : LHSAAPVS) {
9989 bool CmpResult = calculateICmpInst(ICI, L, Zero);
9990 MaybeTrue |= CmpResult;
9991 MaybeFalse |= !CmpResult;
9992 if (MaybeTrue & MaybeFalse)
9993 return indicatePessimisticFixpoint();
9996 for (
const APInt &L : LHSAAPVS) {
9997 for (
const APInt &R : RHSAAPVS) {
9998 bool CmpResult = calculateICmpInst(ICI, L, R);
9999 MaybeTrue |= CmpResult;
10000 MaybeFalse |= !CmpResult;
10001 if (MaybeTrue & MaybeFalse)
10002 return indicatePessimisticFixpoint();
10007 unionAssumed(APInt( 1, 1));
10009 unionAssumed(APInt( 1, 0));
10010 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10011 : ChangeStatus::CHANGED;
10014 ChangeStatus updateWithSelectInst(Attributor &
A, SelectInst *SI) {
10015 auto AssumedBefore = getAssumed();
10019 bool UsedAssumedInformation =
false;
10020 std::optional<Constant *>
C =
A.getAssumedConstant(
10021 *
SI->getCondition(), *
this, UsedAssumedInformation);
10024 bool OnlyLeft =
false, OnlyRight =
false;
10025 if (
C && *
C && (*C)->isOneValue())
10027 else if (
C && *
C && (*C)->isZeroValue())
10030 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10031 SetTy LHSAAPVS, RHSAAPVS;
10034 LHSContainsUndef,
false))
10035 return indicatePessimisticFixpoint();
10039 RHSContainsUndef,
false))
10040 return indicatePessimisticFixpoint();
10042 if (OnlyLeft || OnlyRight) {
10044 auto *OpAA = OnlyLeft ? &LHSAAPVS : &RHSAAPVS;
10045 auto Undef = OnlyLeft ? LHSContainsUndef : RHSContainsUndef;
10048 unionAssumedWithUndef();
10050 for (
const auto &It : *OpAA)
10054 }
else if (LHSContainsUndef && RHSContainsUndef) {
10056 unionAssumedWithUndef();
10058 for (
const auto &It : LHSAAPVS)
10060 for (
const auto &It : RHSAAPVS)
10063 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10064 : ChangeStatus::CHANGED;
10067 ChangeStatus updateWithCastInst(Attributor &
A, CastInst *CI) {
10068 auto AssumedBefore = getAssumed();
10070 return indicatePessimisticFixpoint();
10075 bool SrcContainsUndef =
false;
10078 SrcContainsUndef,
false))
10079 return indicatePessimisticFixpoint();
10081 if (SrcContainsUndef)
10082 unionAssumedWithUndef();
10084 for (
const APInt &S : SrcPVS) {
10085 APInt
T = calculateCastInst(CI, S, ResultBitWidth);
10089 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10090 : ChangeStatus::CHANGED;
10093 ChangeStatus updateWithBinaryOperator(Attributor &
A, BinaryOperator *BinOp) {
10094 auto AssumedBefore = getAssumed();
10098 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10099 SetTy LHSAAPVS, RHSAAPVS;
10101 LHSContainsUndef,
false) ||
10103 RHSContainsUndef,
false))
10104 return indicatePessimisticFixpoint();
10109 if (LHSContainsUndef && RHSContainsUndef) {
10110 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))
10111 return indicatePessimisticFixpoint();
10112 }
else if (LHSContainsUndef) {
10113 for (
const APInt &R : RHSAAPVS) {
10114 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))
10115 return indicatePessimisticFixpoint();
10117 }
else if (RHSContainsUndef) {
10118 for (
const APInt &L : LHSAAPVS) {
10119 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
10120 return indicatePessimisticFixpoint();
10123 for (
const APInt &L : LHSAAPVS) {
10124 for (
const APInt &R : RHSAAPVS) {
10125 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
10126 return indicatePessimisticFixpoint();
10130 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10131 : ChangeStatus::CHANGED;
10134 ChangeStatus updateWithInstruction(Attributor &
A, Instruction *Inst) {
10135 auto AssumedBefore = getAssumed();
10137 bool ContainsUndef;
10139 ContainsUndef,
true))
10140 return indicatePessimisticFixpoint();
10141 if (ContainsUndef) {
10142 unionAssumedWithUndef();
10144 for (
const auto &It : Incoming)
10147 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10148 : ChangeStatus::CHANGED;
10153 Value &
V = getAssociatedValue();
10157 return updateWithICmpInst(
A, ICI);
10160 return updateWithSelectInst(
A, SI);
10163 return updateWithCastInst(
A, CI);
10166 return updateWithBinaryOperator(
A, BinOp);
10169 return updateWithInstruction(
A,
I);
10171 return indicatePessimisticFixpoint();
10175 void trackStatistics()
const override {
10180struct AAPotentialConstantValuesFunction : AAPotentialConstantValuesImpl {
10181 AAPotentialConstantValuesFunction(
const IRPosition &IRP, Attributor &
A)
10182 : AAPotentialConstantValuesImpl(IRP,
A) {}
10187 "AAPotentialConstantValues(Function|CallSite)::updateImpl will "
10192 void trackStatistics()
const override {
10197struct AAPotentialConstantValuesCallSite : AAPotentialConstantValuesFunction {
10198 AAPotentialConstantValuesCallSite(
const IRPosition &IRP, Attributor &
A)
10199 : AAPotentialConstantValuesFunction(IRP,
A) {}
10202 void trackStatistics()
const override {
10207struct AAPotentialConstantValuesCallSiteReturned
10208 : AACalleeToCallSite<AAPotentialConstantValues,
10209 AAPotentialConstantValuesImpl> {
10210 AAPotentialConstantValuesCallSiteReturned(
const IRPosition &IRP,
10212 : AACalleeToCallSite<AAPotentialConstantValues,
10213 AAPotentialConstantValuesImpl>(IRP,
A) {}
10216 void trackStatistics()
const override {
10221struct AAPotentialConstantValuesCallSiteArgument
10222 : AAPotentialConstantValuesFloating {
10223 AAPotentialConstantValuesCallSiteArgument(
const IRPosition &IRP,
10225 : AAPotentialConstantValuesFloating(IRP,
A) {}
10229 AAPotentialConstantValuesImpl::initialize(
A);
10230 if (isAtFixpoint())
10233 Value &
V = getAssociatedValue();
10236 unionAssumed(
C->getValue());
10237 indicateOptimisticFixpoint();
10242 unionAssumedWithUndef();
10243 indicateOptimisticFixpoint();
10250 Value &
V = getAssociatedValue();
10251 auto AssumedBefore = getAssumed();
10252 auto *AA =
A.getAAFor<AAPotentialConstantValues>(
10255 return indicatePessimisticFixpoint();
10256 const auto &S = AA->getAssumed();
10258 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10259 : ChangeStatus::CHANGED;
10263 void trackStatistics()
const override {
10272 bool IgnoreSubsumingPositions) {
10273 assert(ImpliedAttributeKind == Attribute::NoUndef &&
10274 "Unexpected attribute kind");
10275 if (
A.hasAttr(IRP, {Attribute::NoUndef}, IgnoreSubsumingPositions,
10276 Attribute::NoUndef))
10296 Value &V = getAssociatedValue();
10298 indicatePessimisticFixpoint();
10299 assert(!isImpliedByIR(
A, getIRPosition(), Attribute::NoUndef));
10303 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10304 AANoUndef::StateType &State) {
10305 const Value *UseV =
U->get();
10306 const DominatorTree *DT =
nullptr;
10307 AssumptionCache *AC =
nullptr;
10308 InformationCache &InfoCache =
A.getInfoCache();
10309 if (Function *
F = getAnchorScope()) {
10314 bool TrackUse =
false;
10323 const std::string getAsStr(Attributor *
A)
const override {
10324 return getAssumed() ?
"noundef" :
"may-undef-or-poison";
10331 bool UsedAssumedInformation =
false;
10332 if (
A.isAssumedDead(getIRPosition(),
nullptr,
nullptr,
10333 UsedAssumedInformation))
10334 return ChangeStatus::UNCHANGED;
10338 if (!
A.getAssumedSimplified(getIRPosition(), *
this, UsedAssumedInformation,
10341 return ChangeStatus::UNCHANGED;
10342 return AANoUndef::manifest(
A);
10346struct AANoUndefFloating :
public AANoUndefImpl {
10347 AANoUndefFloating(
const IRPosition &IRP, Attributor &
A)
10348 : AANoUndefImpl(IRP,
A) {}
10352 AANoUndefImpl::initialize(
A);
10353 if (!getState().isAtFixpoint() && getAnchorScope() &&
10354 !getAnchorScope()->isDeclaration())
10355 if (Instruction *CtxI = getCtxI())
10356 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10361 auto VisitValueCB = [&](
const IRPosition &IRP) ->
bool {
10362 bool IsKnownNoUndef;
10364 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoUndef);
10368 bool UsedAssumedInformation =
false;
10369 Value *AssociatedValue = &getAssociatedValue();
10371 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10376 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
10384 if (AVIRP == getIRPosition() || !VisitValueCB(AVIRP))
10385 return indicatePessimisticFixpoint();
10386 return ChangeStatus::UNCHANGED;
10389 for (
const auto &VAC : Values)
10391 return indicatePessimisticFixpoint();
10393 return ChangeStatus::UNCHANGED;
10400struct AANoUndefReturned final
10401 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl> {
10402 AANoUndefReturned(
const IRPosition &IRP, Attributor &
A)
10403 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10409struct AANoUndefArgument final
10410 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl> {
10411 AANoUndefArgument(
const IRPosition &IRP, Attributor &
A)
10412 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10418struct AANoUndefCallSiteArgument final : AANoUndefFloating {
10419 AANoUndefCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10420 : AANoUndefFloating(IRP,
A) {}
10426struct AANoUndefCallSiteReturned final
10427 : AACalleeToCallSite<AANoUndef, AANoUndefImpl> {
10428 AANoUndefCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10429 : AACalleeToCallSite<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10437struct AANoFPClassImpl : AANoFPClass {
10438 AANoFPClassImpl(
const IRPosition &IRP, Attributor &
A) : AANoFPClass(IRP,
A) {}
10441 const IRPosition &IRP = getIRPosition();
10445 indicateOptimisticFixpoint();
10450 A.getAttrs(getIRPosition(), {Attribute::NoFPClass},
Attrs,
false);
10451 for (
const auto &Attr : Attrs) {
10455 const DataLayout &
DL =
A.getDataLayout();
10461 if (Instruction *CtxI = getCtxI())
10462 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10466 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10467 AANoFPClass::StateType &State) {
10478 if (
auto *NoFPAA =
A.getAAFor<AANoFPClass>(*
this, IRP, DepClassTy::NONE))
10479 State.addKnownBits(NoFPAA->getState().getKnown());
10483 const std::string getAsStr(Attributor *
A)
const override {
10484 std::string
Result =
"nofpclass";
10485 raw_string_ostream OS(Result);
10486 OS << getKnownNoFPClass() <<
'/' << getAssumedNoFPClass();
10490 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
10491 SmallVectorImpl<Attribute> &Attrs)
const override {
10492 Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));
10496struct AANoFPClassFloating :
public AANoFPClassImpl {
10497 AANoFPClassFloating(
const IRPosition &IRP, Attributor &
A)
10498 : AANoFPClassImpl(IRP,
A) {}
10503 bool UsedAssumedInformation =
false;
10504 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10506 Values.
push_back({getAssociatedValue(), getCtxI()});
10512 DepClassTy::REQUIRED);
10513 if (!AA ||
this == AA) {
10514 T.indicatePessimisticFixpoint();
10516 const AANoFPClass::StateType &S =
10517 static_cast<const AANoFPClass::StateType &
>(AA->
getState());
10520 return T.isValidState();
10523 for (
const auto &VAC : Values)
10525 return indicatePessimisticFixpoint();
10531 void trackStatistics()
const override {
10536struct AANoFPClassReturned final
10537 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10538 AANoFPClassImpl::StateType, false,
10539 Attribute::None, false> {
10540 AANoFPClassReturned(
const IRPosition &IRP, Attributor &
A)
10541 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10542 AANoFPClassImpl::StateType,
false,
10546 void trackStatistics()
const override {
10551struct AANoFPClassArgument final
10552 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {
10553 AANoFPClassArgument(
const IRPosition &IRP, Attributor &
A)
10554 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10560struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {
10561 AANoFPClassCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10562 : AANoFPClassFloating(IRP,
A) {}
10565 void trackStatistics()
const override {
10570struct AANoFPClassCallSiteReturned final
10571 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl> {
10572 AANoFPClassCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10573 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10576 void trackStatistics()
const override {
10581struct AACallEdgesImpl :
public AACallEdges {
10582 AACallEdgesImpl(
const IRPosition &IRP, Attributor &
A) : AACallEdges(IRP,
A) {}
10584 const SetVector<Function *> &getOptimisticEdges()
const override {
10585 return CalledFunctions;
10588 bool hasUnknownCallee()
const override {
return HasUnknownCallee; }
10590 bool hasNonAsmUnknownCallee()
const override {
10591 return HasUnknownCalleeNonAsm;
10594 const std::string getAsStr(Attributor *
A)
const override {
10595 return "CallEdges[" + std::to_string(HasUnknownCallee) +
"," +
10596 std::to_string(CalledFunctions.size()) +
"]";
10599 void trackStatistics()
const override {}
10602 void addCalledFunction(Function *Fn,
ChangeStatus &Change) {
10603 if (CalledFunctions.insert(Fn)) {
10604 Change = ChangeStatus::CHANGED;
10610 void setHasUnknownCallee(
bool NonAsm,
ChangeStatus &Change) {
10611 if (!HasUnknownCallee)
10612 Change = ChangeStatus::CHANGED;
10613 if (NonAsm && !HasUnknownCalleeNonAsm)
10614 Change = ChangeStatus::CHANGED;
10615 HasUnknownCalleeNonAsm |= NonAsm;
10616 HasUnknownCallee =
true;
10621 SetVector<Function *> CalledFunctions;
10624 bool HasUnknownCallee =
false;
10627 bool HasUnknownCalleeNonAsm =
false;
10630struct AACallEdgesCallSite :
public AACallEdgesImpl {
10631 AACallEdgesCallSite(
const IRPosition &IRP, Attributor &
A)
10632 : AACallEdgesImpl(IRP,
A) {}
10639 addCalledFunction(Fn, Change);
10641 LLVM_DEBUG(
dbgs() <<
"[AACallEdges] Unrecognized value: " << V <<
"\n");
10642 setHasUnknownCallee(
true, Change);
10653 VisitValue(*V, CtxI);
10657 bool UsedAssumedInformation =
false;
10663 for (
auto &VAC : Values)
10670 if (
IA->hasSideEffects() &&
10673 setHasUnknownCallee(
false, Change);
10679 if (
auto *IndirectCallAA =
A.getAAFor<AAIndirectCallInfo>(
10680 *
this, getIRPosition(), DepClassTy::OPTIONAL))
10681 if (IndirectCallAA->foreachCallee(
10682 [&](Function *Fn) { return VisitValue(*Fn, CB); }))
10691 for (
const Use *U : CallbackUses)
10692 ProcessCalledOperand(
U->get(), CB);
10698struct AACallEdgesFunction :
public AACallEdgesImpl {
10699 AACallEdgesFunction(
const IRPosition &IRP, Attributor &
A)
10700 : AACallEdgesImpl(IRP,
A) {}
10709 auto *CBEdges =
A.getAAFor<AACallEdges>(
10713 if (CBEdges->hasNonAsmUnknownCallee())
10714 setHasUnknownCallee(
true, Change);
10715 if (CBEdges->hasUnknownCallee())
10716 setHasUnknownCallee(
false, Change);
10718 for (Function *
F : CBEdges->getOptimisticEdges())
10719 addCalledFunction(
F, Change);
10725 bool UsedAssumedInformation =
false;
10726 if (!
A.checkForAllCallLikeInstructions(ProcessCallInst, *
this,
10727 UsedAssumedInformation,
10731 setHasUnknownCallee(
true, Change);
10740struct AAInterFnReachabilityFunction
10741 :
public CachedReachabilityAA<AAInterFnReachability, Function> {
10742 using Base = CachedReachabilityAA<AAInterFnReachability, Function>;
10743 AAInterFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
10746 bool instructionCanReach(
10747 Attributor &
A,
const Instruction &From,
const Function &To,
10750 auto *NonConstThis =
const_cast<AAInterFnReachabilityFunction *
>(
this);
10752 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
10753 RQITy::Reachable
Result;
10754 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
10755 return NonConstThis->isReachableImpl(
A, StackRQI,
10757 return Result == RQITy::Reachable::Yes;
10761 bool IsTemporaryRQI)
override {
10763 &RQI.From->getFunction()->getEntryBlock().front();
10764 if (EntryI != RQI.From &&
10765 !instructionCanReach(
A, *EntryI, *RQI.To,
nullptr))
10766 return rememberResult(
A, RQITy::Reachable::No, RQI,
false,
10769 auto CheckReachableCallBase = [&](CallBase *CB) {
10770 auto *CBEdges =
A.getAAFor<AACallEdges>(
10772 if (!CBEdges || !CBEdges->getState().isValidState())
10775 if (CBEdges->hasUnknownCallee())
10778 for (Function *Fn : CBEdges->getOptimisticEdges()) {
10789 if (Fn == getAnchorScope()) {
10790 if (EntryI == RQI.From)
10795 const AAInterFnReachability *InterFnReachability =
10797 DepClassTy::OPTIONAL);
10800 if (!InterFnReachability ||
10808 const auto *IntraFnReachability =
A.getAAFor<AAIntraFnReachability>(
10810 DepClassTy::OPTIONAL);
10818 return IntraFnReachability && !IntraFnReachability->isAssumedReachable(
10819 A, *RQI.From, CBInst, RQI.ExclusionSet);
10822 bool UsedExclusionSet =
true;
10823 bool UsedAssumedInformation =
false;
10824 if (!
A.checkForAllCallLikeInstructions(CheckCallBase, *
this,
10825 UsedAssumedInformation,
10827 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
10830 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
10834 void trackStatistics()
const override {}
10838template <
typename AAType>
10839static std::optional<Constant *>
10842 if (!Ty.isIntegerTy())
10850 std::optional<Constant *> COpt =
AA->getAssumedConstant(
A);
10852 if (!COpt.has_value()) {
10854 return std::nullopt;
10856 if (
auto *
C = *COpt) {
10867 std::optional<Value *> V;
10868 for (
auto &It : Values) {
10870 if (V.has_value() && !*V)
10873 if (!V.has_value())
10887 if (
A.hasSimplificationCallback(getIRPosition())) {
10888 indicatePessimisticFixpoint();
10891 Value *Stripped = getAssociatedValue().stripPointerCasts();
10893 addValue(
A, getState(), *Stripped, getCtxI(),
AA::AnyScope,
10895 indicateOptimisticFixpoint();
10898 AAPotentialValues::initialize(
A);
10902 const std::string getAsStr(Attributor *
A)
const override {
10904 llvm::raw_string_ostream OS(Str);
10909 template <
typename AAType>
10910 static std::optional<Value *> askOtherAA(Attributor &
A,
10911 const AbstractAttribute &AA,
10912 const IRPosition &IRP,
Type &Ty) {
10917 return std::nullopt;
10924 virtual void addValue(Attributor &
A, StateType &State,
Value &V,
10926 Function *AnchorScope)
const {
10930 for (
const auto &U : CB->
args()) {
10940 Type &Ty = *getAssociatedType();
10941 std::optional<Value *> SimpleV =
10942 askOtherAA<AAValueConstantRange>(
A, *
this, ValIRP, Ty);
10943 if (SimpleV.has_value() && !*SimpleV) {
10944 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
10945 *
this, ValIRP, DepClassTy::OPTIONAL);
10946 if (PotentialConstantsAA && PotentialConstantsAA->isValidState()) {
10947 for (
const auto &It : PotentialConstantsAA->getAssumedSet())
10948 State.unionAssumed({{*ConstantInt::get(&Ty, It),
nullptr}, S});
10949 if (PotentialConstantsAA->undefIsContained())
10954 if (!SimpleV.has_value())
10966 State.unionAssumed({{*VPtr, CtxI}, S});
10972 AA::ValueAndContext
I;
10976 return II.I ==
I &&
II.S == S;
10979 return std::tie(
I, S) < std::tie(
II.I,
II.S);
10983 bool recurseForValue(Attributor &
A,
const IRPosition &IRP,
AA::ValueScope S) {
10984 SmallMapVector<AA::ValueAndContext, int, 8> ValueScopeMap;
10989 bool UsedAssumedInformation =
false;
10991 if (!
A.getAssumedSimplifiedValues(IRP,
this, Values, CS,
10992 UsedAssumedInformation))
10995 for (
auto &It : Values)
10996 ValueScopeMap[It] += CS;
10998 for (
auto &It : ValueScopeMap)
10999 addValue(
A, getState(), *It.first.getValue(), It.first.getCtxI(),
11005 void giveUpOnIntraprocedural(Attributor &
A) {
11006 auto NewS = StateType::getBestState(getState());
11007 for (
const auto &It : getAssumedSet()) {
11010 addValue(
A, NewS, *It.first.getValue(), It.first.getCtxI(),
11013 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11021 getState() = StateType::getBestState(getState());
11022 getState().unionAssumed({{getAssociatedValue(), getCtxI()},
AA::AnyScope});
11023 AAPotentialValues::indicateOptimisticFixpoint();
11024 return ChangeStatus::CHANGED;
11029 return indicatePessimisticFixpoint();
11037 if (!getAssumedSimplifiedValues(
A, Values, S))
11039 Value &OldV = getAssociatedValue();
11042 Value *NewV = getSingleValue(
A, *
this, getIRPosition(), Values);
11043 if (!NewV || NewV == &OldV)
11048 if (
A.changeAfterManifest(getIRPosition(), *NewV))
11049 return ChangeStatus::CHANGED;
11051 return ChangeStatus::UNCHANGED;
11054 bool getAssumedSimplifiedValues(
11055 Attributor &
A, SmallVectorImpl<AA::ValueAndContext> &Values,
11056 AA::ValueScope S,
bool RecurseForSelectAndPHI =
false)
const override {
11057 if (!isValidState())
11059 bool UsedAssumedInformation =
false;
11060 for (
const auto &It : getAssumedSet())
11061 if (It.second & S) {
11062 if (RecurseForSelectAndPHI && (
isa<PHINode>(It.first.getValue()) ||
11064 if (
A.getAssumedSimplifiedValues(
11066 this, Values, S, UsedAssumedInformation))
11071 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11076struct AAPotentialValuesFloating : AAPotentialValuesImpl {
11077 AAPotentialValuesFloating(
const IRPosition &IRP, Attributor &
A)
11078 : AAPotentialValuesImpl(IRP,
A) {}
11082 auto AssumedBefore = getAssumed();
11084 genericValueTraversal(
A, &getAssociatedValue());
11086 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11087 : ChangeStatus::CHANGED;
11091 struct LivenessInfo {
11092 const AAIsDead *LivenessAA =
nullptr;
11093 bool AnyDead =
false;
11103 SmallVectorImpl<ItemInfo> &Worklist) {
11106 bool UsedAssumedInformation =
false;
11108 auto GetSimplifiedValues = [&](
Value &
V,
11110 if (!
A.getAssumedSimplifiedValues(
11114 Values.
push_back(AA::ValueAndContext{
V,
II.I.getCtxI()});
11116 return Values.
empty();
11118 if (GetSimplifiedValues(*
LHS, LHSValues))
11120 if (GetSimplifiedValues(*
RHS, RHSValues))
11125 InformationCache &InfoCache =
A.getInfoCache();
11132 F ?
A.getInfoCache().getTargetLibraryInfoForFunction(*
F) :
nullptr;
11137 const DataLayout &
DL =
A.getDataLayout();
11138 SimplifyQuery Q(
DL, TLI, DT, AC, CmpI);
11140 auto CheckPair = [&](
Value &LHSV,
Value &RHSV) {
11143 nullptr,
II.S, getAnchorScope());
11149 if (&LHSV == &RHSV &&
11151 Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
11153 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11160 if (TypedLHS && TypedRHS) {
11162 if (NewV && NewV != &Cmp) {
11163 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11175 if (!LHSIsNull && !RHSIsNull)
11181 assert((LHSIsNull || RHSIsNull) &&
11182 "Expected nullptr versus non-nullptr comparison at this point");
11185 unsigned PtrIdx = LHSIsNull;
11186 bool IsKnownNonNull;
11189 DepClassTy::REQUIRED, IsKnownNonNull);
11190 if (!IsAssumedNonNull)
11196 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11201 for (
auto &LHSValue : LHSValues)
11202 for (
auto &RHSValue : RHSValues)
11203 if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))
11208 bool handleSelectInst(Attributor &
A, SelectInst &SI, ItemInfo
II,
11209 SmallVectorImpl<ItemInfo> &Worklist) {
11211 bool UsedAssumedInformation =
false;
11213 std::optional<Constant *>
C =
11214 A.getAssumedConstant(*
SI.getCondition(), *
this, UsedAssumedInformation);
11215 bool NoValueYet = !
C.has_value();
11223 }
else if (&SI == &getAssociatedValue()) {
11228 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11230 if (!SimpleV.has_value())
11233 addValue(
A, getState(), **SimpleV, CtxI,
II.S, getAnchorScope());
11241 bool handleLoadInst(Attributor &
A, LoadInst &LI, ItemInfo
II,
11242 SmallVectorImpl<ItemInfo> &Worklist) {
11243 SmallSetVector<Value *, 4> PotentialCopies;
11244 SmallSetVector<Instruction *, 4> PotentialValueOrigins;
11245 bool UsedAssumedInformation =
false;
11247 PotentialValueOrigins, *
this,
11248 UsedAssumedInformation,
11250 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Failed to get potentially "
11251 "loaded values for load instruction "
11259 InformationCache &InfoCache =
A.getInfoCache();
11261 if (!
llvm::all_of(PotentialValueOrigins, [&](Instruction *
I) {
11265 return A.isAssumedDead(
SI->getOperandUse(0),
this,
11267 UsedAssumedInformation,
11269 return A.isAssumedDead(*
I,
this,
nullptr,
11270 UsedAssumedInformation,
11273 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Load is onl used by assumes "
11274 "and we cannot delete all the stores: "
11285 bool AllLocal = ScopeIsLocal;
11290 if (!DynamicallyUnique) {
11291 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Not all potentially loaded "
11292 "values are dynamically unique: "
11297 for (
auto *PotentialCopy : PotentialCopies) {
11299 Worklist.
push_back({{*PotentialCopy, CtxI},
II.S});
11304 if (!AllLocal && ScopeIsLocal)
11309 bool handlePHINode(
11310 Attributor &
A, PHINode &
PHI, ItemInfo
II,
11311 SmallVectorImpl<ItemInfo> &Worklist,
11312 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11313 auto GetLivenessInfo = [&](
const Function &
F) -> LivenessInfo & {
11314 LivenessInfo &LI = LivenessAAs[&
F];
11315 if (!LI.LivenessAA)
11321 if (&
PHI == &getAssociatedValue()) {
11322 LivenessInfo &LI = GetLivenessInfo(*
PHI.getFunction());
11324 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
11325 *
PHI.getFunction());
11329 for (
unsigned u = 0, e =
PHI.getNumIncomingValues(); u < e; u++) {
11331 if (LI.LivenessAA &&
11332 LI.LivenessAA->isEdgeDead(IncomingBB,
PHI.getParent())) {
11351 bool UsedAssumedInformation =
false;
11352 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11354 if (!SimpleV.has_value())
11358 addValue(
A, getState(), **SimpleV, &
PHI,
II.S, getAnchorScope());
11365 bool handleGenericInst(Attributor &
A, Instruction &
I, ItemInfo
II,
11366 SmallVectorImpl<ItemInfo> &Worklist) {
11367 bool SomeSimplified =
false;
11368 bool UsedAssumedInformation =
false;
11370 SmallVector<Value *, 8> NewOps(
I.getNumOperands());
11373 const auto &SimplifiedOp =
A.getAssumedSimplified(
11378 if (!SimplifiedOp.has_value())
11382 NewOps[Idx] = *SimplifiedOp;
11386 SomeSimplified |= (NewOps[Idx] !=
Op);
11392 if (!SomeSimplified)
11395 InformationCache &InfoCache =
A.getInfoCache();
11399 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
11402 const DataLayout &
DL =
I.getDataLayout();
11403 SimplifyQuery Q(
DL, TLI, DT, AC, &
I);
11405 if (!NewV || NewV == &
I)
11408 LLVM_DEBUG(
dbgs() <<
"Generic inst " <<
I <<
" assumed simplified to "
11415 Attributor &
A, Instruction &
I, ItemInfo
II,
11416 SmallVectorImpl<ItemInfo> &Worklist,
11417 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11420 CI->getPredicate(),
II, Worklist);
11422 switch (
I.getOpcode()) {
11423 case Instruction::Select:
11425 case Instruction::PHI:
11427 case Instruction::Load:
11430 return handleGenericInst(
A,
I,
II, Worklist);
11435 void genericValueTraversal(Attributor &
A,
Value *InitialV) {
11436 SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;
11438 SmallSet<ItemInfo, 16> Visited;
11457 LLVM_DEBUG(
dbgs() <<
"Generic value traversal reached iteration limit: "
11458 << Iteration <<
"!\n");
11459 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11465 Value *NewV =
nullptr;
11466 if (
V->getType()->isPointerTy()) {
11472 for (Argument &Arg :
Callee->args())
11479 if (NewV && NewV != V) {
11480 Worklist.
push_back({{*NewV, CtxI}, S});
11494 if (V == InitialV && CtxI == getCtxI()) {
11495 indicatePessimisticFixpoint();
11499 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11500 }
while (!Worklist.
empty());
11504 for (
auto &It : LivenessAAs)
11505 if (It.second.AnyDead)
11506 A.recordDependence(*It.second.LivenessAA, *
this, DepClassTy::OPTIONAL);
11510 void trackStatistics()
const override {
11515struct AAPotentialValuesArgument final : AAPotentialValuesImpl {
11516 using Base = AAPotentialValuesImpl;
11517 AAPotentialValuesArgument(
const IRPosition &IRP, Attributor &
A)
11524 indicatePessimisticFixpoint();
11529 auto AssumedBefore = getAssumed();
11531 unsigned ArgNo = getCalleeArgNo();
11533 bool UsedAssumedInformation =
false;
11535 auto CallSitePred = [&](AbstractCallSite ACS) {
11537 if (CSArgIRP.getPositionKind() == IRP_INVALID)
11540 if (!
A.getAssumedSimplifiedValues(CSArgIRP,
this, Values,
11542 UsedAssumedInformation))
11545 return isValidState();
11548 if (!
A.checkForAllCallSites(CallSitePred, *
this,
11550 UsedAssumedInformation))
11551 return indicatePessimisticFixpoint();
11553 Function *Fn = getAssociatedFunction();
11554 bool AnyNonLocal =
false;
11555 for (
auto &It : Values) {
11557 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11562 return indicatePessimisticFixpoint();
11566 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11572 AnyNonLocal =
true;
11574 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11576 giveUpOnIntraprocedural(
A);
11578 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11579 : ChangeStatus::CHANGED;
11583 void trackStatistics()
const override {
11588struct AAPotentialValuesReturned :
public AAPotentialValuesFloating {
11589 using Base = AAPotentialValuesFloating;
11590 AAPotentialValuesReturned(
const IRPosition &IRP, Attributor &
A)
11596 if (!
F ||
F->isDeclaration() ||
F->getReturnType()->isVoidTy()) {
11597 indicatePessimisticFixpoint();
11601 for (Argument &Arg :
F->args())
11604 ReturnedArg = &Arg;
11607 if (!
A.isFunctionIPOAmendable(*
F) ||
11608 A.hasSimplificationCallback(getIRPosition())) {
11610 indicatePessimisticFixpoint();
11612 indicateOptimisticFixpoint();
11618 auto AssumedBefore = getAssumed();
11619 bool UsedAssumedInformation =
false;
11622 Function *AnchorScope = getAnchorScope();
11628 UsedAssumedInformation,
11634 bool AllInterAreIntra =
false;
11637 llvm::all_of(Values, [&](
const AA::ValueAndContext &VAC) {
11641 for (
const AA::ValueAndContext &VAC : Values) {
11642 addValue(
A, getState(), *VAC.
getValue(),
11646 if (AllInterAreIntra)
11653 HandleReturnedValue(*ReturnedArg,
nullptr,
true);
11656 bool AddValues =
true;
11659 addValue(
A, getState(), *RetI.getOperand(0), &RetI,
AA::AnyScope,
11663 return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);
11666 if (!
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11667 UsedAssumedInformation,
11669 return indicatePessimisticFixpoint();
11672 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11673 : ChangeStatus::CHANGED;
11678 return ChangeStatus::UNCHANGED;
11680 if (!getAssumedSimplifiedValues(
A, Values, AA::ValueScope::Intraprocedural,
11682 return ChangeStatus::UNCHANGED;
11683 Value *NewVal = getSingleValue(
A, *
this, getIRPosition(), Values);
11685 return ChangeStatus::UNCHANGED;
11690 "Number of function with unique return");
11693 {Attribute::get(Arg->
getContext(), Attribute::Returned)});
11698 Value *RetOp = RetI.getOperand(0);
11702 if (
A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))
11703 Changed = ChangeStatus::CHANGED;
11706 bool UsedAssumedInformation =
false;
11707 (void)
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11708 UsedAssumedInformation,
11714 return AAPotentialValues::indicatePessimisticFixpoint();
11718 void trackStatistics()
const override{
11725struct AAPotentialValuesFunction : AAPotentialValuesImpl {
11726 AAPotentialValuesFunction(
const IRPosition &IRP, Attributor &
A)
11727 : AAPotentialValuesImpl(IRP,
A) {}
11736 void trackStatistics()
const override {
11741struct AAPotentialValuesCallSite : AAPotentialValuesFunction {
11742 AAPotentialValuesCallSite(
const IRPosition &IRP, Attributor &
A)
11743 : AAPotentialValuesFunction(IRP,
A) {}
11746 void trackStatistics()
const override {
11751struct AAPotentialValuesCallSiteReturned : AAPotentialValuesImpl {
11752 AAPotentialValuesCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
11753 : AAPotentialValuesImpl(IRP,
A) {}
11757 auto AssumedBefore = getAssumed();
11761 return indicatePessimisticFixpoint();
11763 bool UsedAssumedInformation =
false;
11767 UsedAssumedInformation))
11768 return indicatePessimisticFixpoint();
11775 Values, S, UsedAssumedInformation))
11778 for (
auto &It : Values) {
11779 Value *
V = It.getValue();
11780 std::optional<Value *> CallerV =
A.translateArgumentToCallSiteContent(
11781 V, *CB, *
this, UsedAssumedInformation);
11782 if (!CallerV.has_value()) {
11786 V = *CallerV ? *CallerV :
V;
11792 giveUpOnIntraprocedural(
A);
11795 addValue(
A, getState(), *V, CB, S, getAnchorScope());
11800 return indicatePessimisticFixpoint();
11802 return indicatePessimisticFixpoint();
11803 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11804 : ChangeStatus::CHANGED;
11808 return AAPotentialValues::indicatePessimisticFixpoint();
11812 void trackStatistics()
const override {
11817struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
11818 AAPotentialValuesCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
11819 : AAPotentialValuesFloating(IRP,
A) {}
11822 void trackStatistics()
const override {
11830struct AAAssumptionInfoImpl :
public AAAssumptionInfo {
11831 AAAssumptionInfoImpl(
const IRPosition &IRP, Attributor &
A,
11832 const DenseSet<StringRef> &Known)
11833 : AAAssumptionInfo(IRP,
A, Known) {}
11838 if (getKnown().isUniversal())
11839 return ChangeStatus::UNCHANGED;
11841 const IRPosition &IRP = getIRPosition();
11843 getAssumed().getSet().
end());
11845 return A.manifestAttrs(IRP,
11852 bool hasAssumption(
const StringRef Assumption)
const override {
11853 return isValidState() && setContains(Assumption);
11857 const std::string getAsStr(Attributor *
A)
const override {
11858 const SetContents &Known = getKnown();
11859 const SetContents &Assumed = getAssumed();
11863 const std::string KnownStr =
llvm::join(Set,
",");
11865 std::string AssumedStr =
"Universal";
11866 if (!Assumed.isUniversal()) {
11867 Set.assign(Assumed.getSet().begin(), Assumed.getSet().end());
11870 return "Known [" + KnownStr +
"]," +
" Assumed [" + AssumedStr +
"]";
11885struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {
11886 AAAssumptionInfoFunction(
const IRPosition &IRP, Attributor &
A)
11887 : AAAssumptionInfoImpl(IRP,
A,
11894 auto CallSitePred = [&](AbstractCallSite ACS) {
11895 const auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
11897 DepClassTy::REQUIRED);
11901 Changed |= getIntersection(AssumptionAA->getAssumed());
11902 return !getAssumed().empty() || !getKnown().empty();
11905 bool UsedAssumedInformation =
false;
11910 if (!
A.checkForAllCallSites(CallSitePred, *
this,
true,
11911 UsedAssumedInformation))
11912 return indicatePessimisticFixpoint();
11914 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11917 void trackStatistics()
const override {}
11921struct AAAssumptionInfoCallSite final : AAAssumptionInfoImpl {
11923 AAAssumptionInfoCallSite(
const IRPosition &IRP, Attributor &
A)
11924 : AAAssumptionInfoImpl(IRP,
A, getInitialAssumptions(IRP)) {}
11929 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11935 auto *AssumptionAA =
11936 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11938 return indicatePessimisticFixpoint();
11939 bool Changed = getIntersection(AssumptionAA->getAssumed());
11940 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11944 void trackStatistics()
const override {}
11949 DenseSet<StringRef> getInitialAssumptions(
const IRPosition &IRP) {
11956 return Assumptions;
11971struct AAUnderlyingObjectsImpl
11977 const std::string getAsStr(
Attributor *
A)
const override {
11978 if (!isValidState())
11979 return "<invalid>";
11982 OS <<
"underlying objects: inter " << InterAssumedUnderlyingObjects.size()
11983 <<
" objects, intra " << IntraAssumedUnderlyingObjects.size()
11985 if (!InterAssumedUnderlyingObjects.empty()) {
11986 OS <<
"inter objects:\n";
11987 for (
auto *Obj : InterAssumedUnderlyingObjects)
11988 OS << *Obj <<
'\n';
11990 if (!IntraAssumedUnderlyingObjects.empty()) {
11991 OS <<
"intra objects:\n";
11992 for (
auto *Obj : IntraAssumedUnderlyingObjects)
11993 OS << *
Obj <<
'\n';
11999 void trackStatistics()
const override {}
12003 auto &Ptr = getAssociatedValue();
12005 bool UsedAssumedInformation =
false;
12006 auto DoUpdate = [&](SmallSetVector<Value *, 8> &UnderlyingObjects,
12008 SmallPtrSet<Value *, 8> SeenObjects;
12012 Scope, UsedAssumedInformation))
12013 return UnderlyingObjects.
insert(&Ptr);
12017 for (
unsigned I = 0;
I < Values.
size(); ++
I) {
12018 auto &VAC = Values[
I];
12021 if (!SeenObjects.
insert(UO ? UO : Obj).second)
12023 if (UO && UO != Obj) {
12029 const auto *OtherAA =
A.getAAFor<AAUnderlyingObjects>(
12031 auto Pred = [&](
Value &
V) {
12039 if (!OtherAA || !OtherAA->forallUnderlyingObjects(Pred, Scope))
12041 "The forall call should not return false at this position");
12047 Changed |= handleIndirect(
A, *Obj, UnderlyingObjects, Scope,
12048 UsedAssumedInformation);
12054 for (
unsigned u = 0, e =
PHI->getNumIncomingValues(); u < e; u++) {
12056 handleIndirect(
A, *
PHI->getIncomingValue(u), UnderlyingObjects,
12057 Scope, UsedAssumedInformation);
12071 if (!UsedAssumedInformation)
12072 indicateOptimisticFixpoint();
12073 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12076 bool forallUnderlyingObjects(
12077 function_ref<
bool(
Value &)> Pred,
12079 if (!isValidState())
12080 return Pred(getAssociatedValue());
12083 ? IntraAssumedUnderlyingObjects
12084 : InterAssumedUnderlyingObjects;
12085 for (
Value *Obj : AssumedUnderlyingObjects)
12095 bool handleIndirect(Attributor &
A,
Value &V,
12096 SmallSetVector<Value *, 8> &UnderlyingObjects,
12099 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
12101 auto Pred = [&](
Value &
V) {
12105 if (!AA || !AA->forallUnderlyingObjects(Pred, Scope))
12107 "The forall call should not return false at this position");
12113 SmallSetVector<Value *, 8> IntraAssumedUnderlyingObjects;
12115 SmallSetVector<Value *, 8> InterAssumedUnderlyingObjects;
12118struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl {
12119 AAUnderlyingObjectsFloating(
const IRPosition &IRP, Attributor &
A)
12120 : AAUnderlyingObjectsImpl(IRP,
A) {}
12123struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl {
12124 AAUnderlyingObjectsArgument(
const IRPosition &IRP, Attributor &
A)
12125 : AAUnderlyingObjectsImpl(IRP,
A) {}
12128struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl {
12129 AAUnderlyingObjectsCallSite(
const IRPosition &IRP, Attributor &
A)
12130 : AAUnderlyingObjectsImpl(IRP,
A) {}
12133struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl {
12134 AAUnderlyingObjectsCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12135 : AAUnderlyingObjectsImpl(IRP,
A) {}
12138struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl {
12139 AAUnderlyingObjectsReturned(
const IRPosition &IRP, Attributor &
A)
12140 : AAUnderlyingObjectsImpl(IRP,
A) {}
12143struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl {
12144 AAUnderlyingObjectsCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12145 : AAUnderlyingObjectsImpl(IRP,
A) {}
12148struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {
12149 AAUnderlyingObjectsFunction(
const IRPosition &IRP, Attributor &
A)
12150 : AAUnderlyingObjectsImpl(IRP,
A) {}
12156struct AAGlobalValueInfoFloating :
public AAGlobalValueInfo {
12157 AAGlobalValueInfoFloating(
const IRPosition &IRP, Attributor &
A)
12158 : AAGlobalValueInfo(IRP,
A) {}
12163 bool checkUse(Attributor &
A,
const Use &U,
bool &Follow,
12164 SmallVectorImpl<const Value *> &Worklist) {
12171 LLVM_DEBUG(
dbgs() <<
"[AAGlobalValueInfo] Check use: " << *
U.get() <<
" in "
12172 << *UInst <<
"\n");
12175 int Idx = &
Cmp->getOperandUse(0) == &
U;
12178 return U == &getAnchorValue();
12183 auto CallSitePred = [&](AbstractCallSite ACS) {
12184 Worklist.
push_back(ACS.getInstruction());
12187 bool UsedAssumedInformation =
false;
12189 if (!
A.checkForAllCallSites(CallSitePred, *UInst->
getFunction(),
12191 UsedAssumedInformation))
12209 if (!Fn || !
A.isFunctionIPOAmendable(*Fn))
12218 unsigned NumUsesBefore =
Uses.size();
12220 SmallPtrSet<const Value *, 8> Visited;
12224 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
12232 return checkUse(
A, U, Follow, Worklist);
12234 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
12235 Uses.insert(&OldU);
12239 while (!Worklist.
empty()) {
12241 if (!Visited.
insert(V).second)
12243 if (!
A.checkForAllUses(UsePred, *
this, *V,
12245 DepClassTy::OPTIONAL,
12246 true, EquivalentUseCB)) {
12247 return indicatePessimisticFixpoint();
12251 return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED
12252 : ChangeStatus::CHANGED;
12255 bool isPotentialUse(
const Use &U)
const override {
12256 return !isValidState() ||
Uses.contains(&U);
12261 return ChangeStatus::UNCHANGED;
12265 const std::string getAsStr(Attributor *
A)
const override {
12266 return "[" + std::to_string(
Uses.size()) +
" uses]";
12269 void trackStatistics()
const override {
12275 SmallPtrSet<const Use *, 8>
Uses;
12281struct AAIndirectCallInfoCallSite :
public AAIndirectCallInfo {
12282 AAIndirectCallInfoCallSite(
const IRPosition &IRP, Attributor &
A)
12283 : AAIndirectCallInfo(IRP,
A) {}
12287 auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);
12288 if (!MD && !
A.isClosedWorldModule())
12292 for (
const auto &
Op : MD->operands())
12294 PotentialCallees.insert(Callee);
12295 }
else if (
A.isClosedWorldModule()) {
12297 A.getInfoCache().getIndirectlyCallableFunctions(
A);
12298 PotentialCallees.insert_range(IndirectlyCallableFunctions);
12301 if (PotentialCallees.empty())
12302 indicateOptimisticFixpoint();
12310 SmallSetVector<Function *, 4> AssumedCalleesNow;
12311 bool AllCalleesKnownNow = AllCalleesKnown;
12313 auto CheckPotentialCalleeUse = [&](
Function &PotentialCallee,
12314 bool &UsedAssumedInformation) {
12315 const auto *GIAA =
A.getAAFor<AAGlobalValueInfo>(
12317 if (!GIAA || GIAA->isPotentialUse(CalleeUse))
12319 UsedAssumedInformation = !GIAA->isAtFixpoint();
12323 auto AddPotentialCallees = [&]() {
12324 for (
auto *PotentialCallee : PotentialCallees) {
12325 bool UsedAssumedInformation =
false;
12326 if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))
12327 AssumedCalleesNow.
insert(PotentialCallee);
12333 bool UsedAssumedInformation =
false;
12336 AA::ValueScope::AnyScope,
12337 UsedAssumedInformation)) {
12338 if (PotentialCallees.empty())
12339 return indicatePessimisticFixpoint();
12340 AddPotentialCallees();
12345 auto CheckPotentialCallee = [&](
Function &Fn) {
12346 if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))
12349 auto &CachedResult = FilterResults[&Fn];
12350 if (CachedResult.has_value())
12351 return CachedResult.value();
12353 bool UsedAssumedInformation =
false;
12354 if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {
12355 if (!UsedAssumedInformation)
12356 CachedResult =
false;
12365 for (
int I = NumCBArgs;
I < NumFnArgs; ++
I) {
12366 bool IsKnown =
false;
12369 DepClassTy::OPTIONAL, IsKnown)) {
12371 CachedResult =
false;
12376 CachedResult =
true;
12382 for (
auto &VAC : Values) {
12390 if (CheckPotentialCallee(*VACFn))
12391 AssumedCalleesNow.
insert(VACFn);
12394 if (!PotentialCallees.empty()) {
12395 AddPotentialCallees();
12398 AllCalleesKnownNow =
false;
12401 if (AssumedCalleesNow == AssumedCallees &&
12402 AllCalleesKnown == AllCalleesKnownNow)
12403 return ChangeStatus::UNCHANGED;
12405 std::swap(AssumedCallees, AssumedCalleesNow);
12406 AllCalleesKnown = AllCalleesKnownNow;
12407 return ChangeStatus::CHANGED;
12413 if (!AllCalleesKnown && AssumedCallees.empty())
12414 return ChangeStatus::UNCHANGED;
12417 bool UsedAssumedInformation =
false;
12418 if (
A.isAssumedDead(*CB,
this,
nullptr,
12419 UsedAssumedInformation))
12420 return ChangeStatus::UNCHANGED;
12424 if (
FP->getType()->getPointerAddressSpace())
12425 FP =
new AddrSpaceCastInst(
FP, PointerType::get(
FP->getContext(), 0),
12435 if (AssumedCallees.empty()) {
12436 assert(AllCalleesKnown &&
12437 "Expected all callees to be known if there are none.");
12438 A.changeToUnreachableAfterManifest(CB);
12439 return ChangeStatus::CHANGED;
12443 if (AllCalleesKnown && AssumedCallees.size() == 1) {
12444 auto *NewCallee = AssumedCallees.front();
12447 NumIndirectCallsPromoted++;
12448 return ChangeStatus::CHANGED;
12455 A.deleteAfterManifest(*CB);
12456 return ChangeStatus::CHANGED;
12466 bool SpecializedForAnyCallees =
false;
12467 bool SpecializedForAllCallees = AllCalleesKnown;
12468 ICmpInst *LastCmp =
nullptr;
12471 for (Function *NewCallee : AssumedCallees) {
12472 if (!
A.shouldSpecializeCallSiteForCallee(*
this, *CB, *NewCallee,
12473 AssumedCallees.size())) {
12474 SkippedAssumedCallees.
push_back(NewCallee);
12475 SpecializedForAllCallees =
false;
12478 SpecializedForAnyCallees =
true;
12484 A.registerManifestAddedBasicBlock(*ThenTI->
getParent());
12485 A.registerManifestAddedBasicBlock(*IP->getParent());
12491 A.registerManifestAddedBasicBlock(*ElseBB);
12493 SplitTI->replaceUsesOfWith(CBBB, ElseBB);
12498 CastInst *RetBC =
nullptr;
12499 CallInst *NewCall =
nullptr;
12504 NumIndirectCallsPromoted++;
12512 auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {
12513 if (!AllCalleesKnown)
12514 return ChangeStatus::UNCHANGED;
12515 MDBuilder MDB(IndirectCB.getContext());
12516 MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);
12517 IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);
12518 return ChangeStatus::CHANGED;
12521 if (!SpecializedForAnyCallees)
12522 return AttachCalleeMetadata(*CB);
12525 if (SpecializedForAllCallees) {
12528 new UnreachableInst(IP->getContext(), IP);
12529 IP->eraseFromParent();
12532 CBClone->setName(CB->
getName());
12533 CBClone->insertBefore(*IP->getParent(), IP);
12534 NewCalls.
push_back({CBClone,
nullptr});
12535 AttachCalleeMetadata(*CBClone);
12542 CB->
getParent()->getFirstInsertionPt());
12543 for (
auto &It : NewCalls) {
12544 CallBase *NewCall = It.first;
12545 Instruction *CallRet = It.second ? It.second : It.first;
12557 A.deleteAfterManifest(*CB);
12558 Changed = ChangeStatus::CHANGED;
12564 const std::string getAsStr(Attributor *
A)
const override {
12565 return std::string(AllCalleesKnown ?
"eliminate" :
"specialize") +
12566 " indirect call site with " + std::to_string(AssumedCallees.size()) +
12570 void trackStatistics()
const override {
12571 if (AllCalleesKnown) {
12573 Eliminated, CallSites,
12574 "Number of indirect call sites eliminated via specialization")
12577 "Number of indirect call sites specialized")
12581 bool foreachCallee(function_ref<
bool(Function *)> CB)
const override {
12582 return isValidState() && AllCalleesKnown &&
all_of(AssumedCallees, CB);
12587 DenseMap<Function *, std::optional<bool>> FilterResults;
12591 SmallSetVector<Function *, 4> PotentialCallees;
12595 SmallSetVector<Function *, 4> AssumedCallees;
12599 bool AllCalleesKnown =
true;
12606struct AAInvariantLoadPointerImpl
12607 :
public StateWrapper<BitIntegerState<uint8_t, 15>,
12608 AAInvariantLoadPointer> {
12612 IS_NOALIAS = 1 << 0,
12615 IS_NOEFFECT = 1 << 1,
12617 IS_LOCALLY_INVARIANT = 1 << 2,
12619 IS_LOCALLY_CONSTRAINED = 1 << 3,
12621 IS_BEST_STATE = IS_NOALIAS | IS_NOEFFECT | IS_LOCALLY_INVARIANT |
12622 IS_LOCALLY_CONSTRAINED,
12624 static_assert(getBestState() == IS_BEST_STATE,
"Unexpected best state");
12627 StateWrapper<BitIntegerState<uint8_t, 15>, AAInvariantLoadPointer>;
12631 AAInvariantLoadPointerImpl(
const IRPosition &IRP, Attributor &
A)
12634 bool isKnownInvariant()
const final {
12635 return isKnownLocallyInvariant() && isKnown(IS_LOCALLY_CONSTRAINED);
12638 bool isKnownLocallyInvariant()
const final {
12639 if (isKnown(IS_LOCALLY_INVARIANT))
12641 return isKnown(IS_NOALIAS | IS_NOEFFECT);
12644 bool isAssumedInvariant()
const final {
12645 return isAssumedLocallyInvariant() && isAssumed(IS_LOCALLY_CONSTRAINED);
12648 bool isAssumedLocallyInvariant()
const final {
12649 if (isAssumed(IS_LOCALLY_INVARIANT))
12651 return isAssumed(IS_NOALIAS | IS_NOEFFECT);
12658 if (requiresNoAlias() && !isAssumed(IS_NOALIAS))
12659 return indicatePessimisticFixpoint();
12663 Changed |= updateLocalInvariance(
A);
12669 if (!isKnownInvariant())
12670 return ChangeStatus::UNCHANGED;
12673 const Value *Ptr = &getAssociatedValue();
12674 const auto TagInvariantLoads = [&](
const Use &
U,
bool &) {
12675 if (
U.get() != Ptr)
12683 if (!
A.isRunOn(
I->getFunction()))
12686 if (
I->hasMetadata(LLVMContext::MD_invariant_load))
12690 LI->setMetadata(LLVMContext::MD_invariant_load,
12692 Changed = ChangeStatus::CHANGED;
12697 (void)
A.checkForAllUses(TagInvariantLoads, *
this, *Ptr);
12702 const std::string getAsStr(Attributor *)
const override {
12703 if (isKnownInvariant())
12704 return "load-invariant pointer";
12705 return "non-invariant pointer";
12709 void trackStatistics()
const override {}
12713 bool requiresNoAlias()
const {
12714 switch (getPositionKind()) {
12720 case IRP_CALL_SITE:
12722 case IRP_CALL_SITE_RETURNED: {
12727 case IRP_ARGUMENT: {
12728 const Function *
F = getAssociatedFunction();
12729 assert(
F &&
"no associated function for argument");
12735 bool isExternal()
const {
12736 const Function *
F = getAssociatedFunction();
12740 getPositionKind() != IRP_CALL_SITE_RETURNED;
12744 if (isKnown(IS_NOALIAS) || !isAssumed(IS_NOALIAS))
12745 return ChangeStatus::UNCHANGED;
12748 if (
const auto *ANoAlias =
A.getOrCreateAAFor<AANoAlias>(
12749 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12750 if (ANoAlias->isKnownNoAlias()) {
12751 addKnownBits(IS_NOALIAS);
12752 return ChangeStatus::CHANGED;
12755 if (!ANoAlias->isAssumedNoAlias()) {
12756 removeAssumedBits(IS_NOALIAS);
12757 return ChangeStatus::CHANGED;
12760 return ChangeStatus::UNCHANGED;
12765 if (
const Argument *Arg = getAssociatedArgument()) {
12767 addKnownBits(IS_NOALIAS);
12768 return ChangeStatus::UNCHANGED;
12773 removeAssumedBits(IS_NOALIAS);
12774 return ChangeStatus::CHANGED;
12777 return ChangeStatus::UNCHANGED;
12781 if (isKnown(IS_NOEFFECT) || !isAssumed(IS_NOEFFECT))
12782 return ChangeStatus::UNCHANGED;
12784 if (!getAssociatedFunction())
12785 return indicatePessimisticFixpoint();
12788 return indicatePessimisticFixpoint();
12790 const auto HasNoEffectLoads = [&](
const Use &
U,
bool &) {
12792 return !LI || !LI->mayHaveSideEffects();
12794 if (!
A.checkForAllUses(HasNoEffectLoads, *
this, getAssociatedValue()))
12795 return indicatePessimisticFixpoint();
12797 if (
const auto *AMemoryBehavior =
A.getOrCreateAAFor<AAMemoryBehavior>(
12798 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12801 if (!AMemoryBehavior->isAssumedReadOnly())
12802 return indicatePessimisticFixpoint();
12804 if (AMemoryBehavior->isKnownReadOnly()) {
12805 addKnownBits(IS_NOEFFECT);
12806 return ChangeStatus::UNCHANGED;
12809 return ChangeStatus::UNCHANGED;
12812 if (
const Argument *Arg = getAssociatedArgument()) {
12814 addKnownBits(IS_NOEFFECT);
12815 return ChangeStatus::UNCHANGED;
12820 return indicatePessimisticFixpoint();
12823 return ChangeStatus::UNCHANGED;
12827 if (isKnown(IS_LOCALLY_INVARIANT) || !isAssumed(IS_LOCALLY_INVARIANT))
12828 return ChangeStatus::UNCHANGED;
12831 const auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
12832 getIRPosition(),
this, DepClassTy::REQUIRED);
12834 return ChangeStatus::UNCHANGED;
12836 bool UsedAssumedInformation =
false;
12837 const auto IsLocallyInvariantLoadIfPointer = [&](
const Value &
V) {
12838 if (!
V.getType()->isPointerTy())
12840 const auto *IsInvariantLoadPointer =
12842 DepClassTy::REQUIRED);
12844 if (!IsInvariantLoadPointer)
12847 if (IsInvariantLoadPointer->isKnownLocallyInvariant())
12849 if (!IsInvariantLoadPointer->isAssumedLocallyInvariant())
12852 UsedAssumedInformation =
true;
12855 if (!AUO->forallUnderlyingObjects(IsLocallyInvariantLoadIfPointer))
12856 return indicatePessimisticFixpoint();
12862 if (!IsLocallyInvariantLoadIfPointer(*Arg))
12863 return indicatePessimisticFixpoint();
12868 if (!UsedAssumedInformation) {
12870 addKnownBits(IS_LOCALLY_INVARIANT);
12871 return ChangeStatus::CHANGED;
12874 return ChangeStatus::UNCHANGED;
12878struct AAInvariantLoadPointerFloating final : AAInvariantLoadPointerImpl {
12879 AAInvariantLoadPointerFloating(
const IRPosition &IRP, Attributor &
A)
12880 : AAInvariantLoadPointerImpl(IRP,
A) {}
12883struct AAInvariantLoadPointerReturned final : AAInvariantLoadPointerImpl {
12884 AAInvariantLoadPointerReturned(
const IRPosition &IRP, Attributor &
A)
12885 : AAInvariantLoadPointerImpl(IRP,
A) {}
12888 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12892struct AAInvariantLoadPointerCallSiteReturned final
12893 : AAInvariantLoadPointerImpl {
12894 AAInvariantLoadPointerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12895 : AAInvariantLoadPointerImpl(IRP,
A) {}
12898 const Function *
F = getAssociatedFunction();
12899 assert(
F &&
"no associated function for return from call");
12901 if (!
F->isDeclaration() && !
F->isIntrinsic())
12902 return AAInvariantLoadPointerImpl::initialize(
A);
12907 return AAInvariantLoadPointerImpl::initialize(
A);
12909 if (
F->onlyReadsMemory() &&
F->hasNoSync())
12910 return AAInvariantLoadPointerImpl::initialize(
A);
12914 indicatePessimisticFixpoint();
12918struct AAInvariantLoadPointerArgument final : AAInvariantLoadPointerImpl {
12919 AAInvariantLoadPointerArgument(
const IRPosition &IRP, Attributor &
A)
12920 : AAInvariantLoadPointerImpl(IRP,
A) {}
12923 const Function *
F = getAssociatedFunction();
12924 assert(
F &&
"no associated function for argument");
12927 addKnownBits(IS_LOCALLY_CONSTRAINED);
12931 if (!
F->hasLocalLinkage())
12932 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12936struct AAInvariantLoadPointerCallSiteArgument final
12937 : AAInvariantLoadPointerImpl {
12938 AAInvariantLoadPointerCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12939 : AAInvariantLoadPointerImpl(IRP,
A) {}
12946template <
typename InstType>
12947static bool makeChange(Attributor &
A, InstType *MemInst,
const Use &U,
12948 Value *OriginalValue, PointerType *NewPtrTy,
12949 bool UseOriginalValue) {
12950 if (
U.getOperandNo() != InstType::getPointerOperandIndex())
12953 if (MemInst->isVolatile()) {
12954 auto *
TTI =
A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(
12955 *MemInst->getFunction());
12956 unsigned NewAS = NewPtrTy->getPointerAddressSpace();
12961 if (UseOriginalValue) {
12962 A.changeUseAfterManifest(
const_cast<Use &
>(U), *OriginalValue);
12966 Instruction *CastInst =
new AddrSpaceCastInst(OriginalValue, NewPtrTy);
12968 A.changeUseAfterManifest(
const_cast<Use &
>(U), *CastInst);
12972struct AAAddressSpaceImpl :
public AAAddressSpace {
12973 AAAddressSpaceImpl(
const IRPosition &IRP, Attributor &
A)
12974 : AAAddressSpace(IRP,
A) {}
12977 assert(isValidState() &&
"the AA is invalid");
12978 return AssumedAddressSpace;
12983 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
12984 "Associated value is not a pointer");
12986 if (!
A.getInfoCache().getFlatAddressSpace().has_value()) {
12987 indicatePessimisticFixpoint();
12991 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
12992 unsigned AS = getAssociatedType()->getPointerAddressSpace();
12993 if (AS != FlatAS) {
12994 [[maybe_unused]]
bool R = takeAddressSpace(AS);
12995 assert(R &&
"The take should happen");
12996 indicateOptimisticFixpoint();
13001 uint32_t OldAddressSpace = AssumedAddressSpace;
13002 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13004 auto CheckAddressSpace = [&](
Value &
Obj) {
13010 unsigned ObjAS =
Obj.getType()->getPointerAddressSpace();
13011 if (ObjAS != FlatAS)
13012 return takeAddressSpace(ObjAS);
13026 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(*F);
13028 if (AssumedAS != ~0U)
13029 return takeAddressSpace(AssumedAS);
13033 return takeAddressSpace(FlatAS);
13036 auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(getIRPosition(),
this,
13037 DepClassTy::REQUIRED);
13038 if (!AUO->forallUnderlyingObjects(CheckAddressSpace))
13039 return indicatePessimisticFixpoint();
13041 return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED
13042 : ChangeStatus::CHANGED;
13049 if (NewAS == InvalidAddressSpace ||
13051 return ChangeStatus::UNCHANGED;
13053 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13055 Value *AssociatedValue = &getAssociatedValue();
13056 Value *OriginalValue = peelAddrspacecast(AssociatedValue, FlatAS);
13059 PointerType::get(getAssociatedType()->
getContext(), NewAS);
13060 bool UseOriginalValue =
13065 auto Pred = [&](
const Use &
U,
bool &) {
13066 if (
U.get() != AssociatedValue)
13077 makeChange(
A, LI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13080 makeChange(
A, SI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13083 makeChange(
A, RMW, U, OriginalValue, NewPtrTy, UseOriginalValue);
13086 makeChange(
A, CmpX, U, OriginalValue, NewPtrTy, UseOriginalValue);
13093 (void)
A.checkForAllUses(Pred, *
this, getAssociatedValue(),
13096 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13100 const std::string getAsStr(Attributor *
A)
const override {
13101 if (!isValidState())
13102 return "addrspace(<invalid>)";
13103 return "addrspace(" +
13104 (AssumedAddressSpace == InvalidAddressSpace
13106 : std::to_string(AssumedAddressSpace)) +
13111 uint32_t AssumedAddressSpace = InvalidAddressSpace;
13113 bool takeAddressSpace(uint32_t AS) {
13114 if (AssumedAddressSpace == InvalidAddressSpace) {
13115 AssumedAddressSpace = AS;
13118 return AssumedAddressSpace == AS;
13121 static Value *peelAddrspacecast(
Value *V,
unsigned FlatAS) {
13123 assert(
I->getSrcAddressSpace() != FlatAS &&
13124 "there should not be flat AS -> non-flat AS");
13125 return I->getPointerOperand();
13128 if (
C->getOpcode() == Instruction::AddrSpaceCast) {
13129 assert(
C->getOperand(0)->getType()->getPointerAddressSpace() !=
13131 "there should not be flat AS -> non-flat AS X");
13132 return C->getOperand(0);
13138struct AAAddressSpaceFloating final : AAAddressSpaceImpl {
13139 AAAddressSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13140 : AAAddressSpaceImpl(IRP,
A) {}
13142 void trackStatistics()
const override {
13147struct AAAddressSpaceReturned final : AAAddressSpaceImpl {
13148 AAAddressSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13149 : AAAddressSpaceImpl(IRP,
A) {}
13155 (void)indicatePessimisticFixpoint();
13158 void trackStatistics()
const override {
13163struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl {
13164 AAAddressSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13165 : AAAddressSpaceImpl(IRP,
A) {}
13167 void trackStatistics()
const override {
13172struct AAAddressSpaceArgument final : AAAddressSpaceImpl {
13173 AAAddressSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13174 : AAAddressSpaceImpl(IRP,
A) {}
13179struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl {
13180 AAAddressSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13181 : AAAddressSpaceImpl(IRP,
A) {}
13187 (void)indicatePessimisticFixpoint();
13190 void trackStatistics()
const override {
13205struct AANoAliasAddrSpaceImpl :
public AANoAliasAddrSpace {
13206 AANoAliasAddrSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13207 : AANoAliasAddrSpace(IRP,
A) {}
13210 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13211 "Associated value is not a pointer");
13215 std::optional<unsigned> FlatAS =
A.getInfoCache().getFlatAddressSpace();
13216 if (!FlatAS.has_value()) {
13217 indicatePessimisticFixpoint();
13223 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13224 if (AS != *FlatAS) {
13226 indicateOptimisticFixpoint();
13231 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13232 uint32_t OldAssumed = getAssumed();
13234 auto CheckAddressSpace = [&](
Value &
Obj) {
13238 unsigned AS =
Obj.getType()->getPointerAddressSpace();
13242 removeAS(
Obj.getType()->getPointerAddressSpace());
13246 const AAUnderlyingObjects *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
13247 getIRPosition(),
this, DepClassTy::REQUIRED);
13249 return indicatePessimisticFixpoint();
13251 return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
13252 : ChangeStatus::CHANGED;
13257 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13259 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13260 if (AS != FlatAS ||
Map.empty())
13261 return ChangeStatus::UNCHANGED;
13263 LLVMContext &Ctx = getAssociatedValue().getContext();
13264 MDNode *NoAliasASNode =
nullptr;
13265 MDBuilder MDB(Ctx);
13267 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13270 unsigned Upper =
I.stop();
13271 unsigned Lower =
I.start();
13272 if (!NoAliasASNode) {
13273 NoAliasASNode = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13276 MDNode *ASRange = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13280 Value *AssociatedValue = &getAssociatedValue();
13283 auto AddNoAliasAttr = [&](
const Use &
U,
bool &) {
13284 if (
U.get() != AssociatedValue)
13287 if (!Inst || Inst->
hasMetadata(LLVMContext::MD_noalias_addrspace))
13294 Inst->
setMetadata(LLVMContext::MD_noalias_addrspace, NoAliasASNode);
13298 (void)
A.checkForAllUses(AddNoAliasAttr, *
this, *AssociatedValue,
13300 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13304 const std::string getAsStr(Attributor *
A)
const override {
13305 if (!isValidState())
13306 return "<invalid>";
13308 raw_string_ostream OS(Str);
13309 OS <<
"CanNotBeAddrSpace(";
13310 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13311 unsigned Upper =
I.stop();
13312 unsigned Lower =
I.start();
13313 OS <<
' ' <<
'[' <<
Upper <<
',' <<
Lower + 1 <<
')';
13320 void removeAS(
unsigned AS) {
13321 RangeMap::iterator
I =
Map.find(AS);
13323 if (
I !=
Map.end()) {
13324 unsigned Upper =
I.stop();
13325 unsigned Lower =
I.start();
13329 if (AS != ~((
unsigned)0) && AS + 1 <=
Upper)
13331 if (AS != 0 &&
Lower <= AS - 1)
13336 void resetASRanges(Attributor &
A) {
13338 Map.insert(0,
A.getInfoCache().getMaxAddrSpace(),
true);
13342struct AANoAliasAddrSpaceFloating final : AANoAliasAddrSpaceImpl {
13343 AANoAliasAddrSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13344 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13346 void trackStatistics()
const override {
13351struct AANoAliasAddrSpaceReturned final : AANoAliasAddrSpaceImpl {
13352 AANoAliasAddrSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13353 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13355 void trackStatistics()
const override {
13360struct AANoAliasAddrSpaceCallSiteReturned final : AANoAliasAddrSpaceImpl {
13361 AANoAliasAddrSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13362 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13364 void trackStatistics()
const override {
13369struct AANoAliasAddrSpaceArgument final : AANoAliasAddrSpaceImpl {
13370 AANoAliasAddrSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13371 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13373 void trackStatistics()
const override {
13378struct AANoAliasAddrSpaceCallSiteArgument final : AANoAliasAddrSpaceImpl {
13379 AANoAliasAddrSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13380 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13382 void trackStatistics()
const override {
13389struct AAAllocationInfoImpl :
public AAAllocationInfo {
13390 AAAllocationInfoImpl(
const IRPosition &IRP, Attributor &
A)
13391 : AAAllocationInfo(IRP,
A) {}
13393 std::optional<TypeSize> getAllocatedSize()
const override {
13394 assert(isValidState() &&
"the AA is invalid");
13395 return AssumedAllocatedSize;
13398 std::optional<TypeSize> findInitialAllocationSize(Instruction *
I,
13399 const DataLayout &
DL) {
13402 switch (
I->getOpcode()) {
13403 case Instruction::Alloca: {
13408 return std::nullopt;
13414 const IRPosition &IRP = getIRPosition();
13419 return indicatePessimisticFixpoint();
13421 bool IsKnownNoCapture;
13423 A,
this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture))
13424 return indicatePessimisticFixpoint();
13426 const AAPointerInfo *PI =
13427 A.getOrCreateAAFor<AAPointerInfo>(IRP, *
this, DepClassTy::REQUIRED);
13430 return indicatePessimisticFixpoint();
13433 return indicatePessimisticFixpoint();
13435 const DataLayout &
DL =
A.getDataLayout();
13436 const auto AllocationSize = findInitialAllocationSize(
I,
DL);
13439 if (!AllocationSize)
13440 return indicatePessimisticFixpoint();
13444 if (*AllocationSize == 0)
13445 return indicatePessimisticFixpoint();
13451 return indicatePessimisticFixpoint();
13453 if (BinSize == 0) {
13454 auto NewAllocationSize = std::make_optional<TypeSize>(0,
false);
13455 if (!changeAllocationSize(NewAllocationSize))
13456 return ChangeStatus::UNCHANGED;
13457 return ChangeStatus::CHANGED;
13461 const auto &It = PI->
begin();
13464 if (It->first.Offset != 0)
13465 return indicatePessimisticFixpoint();
13467 uint64_t SizeOfBin = It->first.Offset + It->first.Size;
13469 if (SizeOfBin >= *AllocationSize)
13470 return indicatePessimisticFixpoint();
13472 auto NewAllocationSize = std::make_optional<TypeSize>(SizeOfBin * 8,
false);
13474 if (!changeAllocationSize(NewAllocationSize))
13475 return ChangeStatus::UNCHANGED;
13477 return ChangeStatus::CHANGED;
13483 assert(isValidState() &&
13484 "Manifest should only be called if the state is valid.");
13488 auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
13490 unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
13492 switch (
I->getOpcode()) {
13494 case Instruction::Alloca: {
13498 Type *CharType = Type::getInt8Ty(
I->getContext());
13500 auto *NumBytesToValue =
13501 ConstantInt::get(
I->getContext(), APInt(32, NumBytesToAllocate));
13504 insertPt = std::next(insertPt);
13505 AllocaInst *NewAllocaInst =
13510 return ChangeStatus::CHANGED;
13518 return ChangeStatus::UNCHANGED;
13522 const std::string getAsStr(Attributor *
A)
const override {
13523 if (!isValidState())
13524 return "allocationinfo(<invalid>)";
13525 return "allocationinfo(" +
13526 (AssumedAllocatedSize == HasNoAllocationSize
13528 : std::to_string(AssumedAllocatedSize->getFixedValue())) +
13533 std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
13537 bool changeAllocationSize(std::optional<TypeSize>
Size) {
13538 if (AssumedAllocatedSize == HasNoAllocationSize ||
13539 AssumedAllocatedSize !=
Size) {
13540 AssumedAllocatedSize =
Size;
13547struct AAAllocationInfoFloating : AAAllocationInfoImpl {
13548 AAAllocationInfoFloating(
const IRPosition &IRP, Attributor &
A)
13549 : AAAllocationInfoImpl(IRP,
A) {}
13551 void trackStatistics()
const override {
13556struct AAAllocationInfoReturned : AAAllocationInfoImpl {
13557 AAAllocationInfoReturned(
const IRPosition &IRP, Attributor &
A)
13558 : AAAllocationInfoImpl(IRP,
A) {}
13564 (void)indicatePessimisticFixpoint();
13567 void trackStatistics()
const override {
13572struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl {
13573 AAAllocationInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13574 : AAAllocationInfoImpl(IRP,
A) {}
13576 void trackStatistics()
const override {
13581struct AAAllocationInfoArgument : AAAllocationInfoImpl {
13582 AAAllocationInfoArgument(
const IRPosition &IRP, Attributor &
A)
13583 : AAAllocationInfoImpl(IRP,
A) {}
13585 void trackStatistics()
const override {
13590struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl {
13591 AAAllocationInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13592 : AAAllocationInfoImpl(IRP,
A) {}
13597 (void)indicatePessimisticFixpoint();
13600 void trackStatistics()
const override {
13649#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \
13650 case IRPosition::PK: \
13651 llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");
13653#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \
13654 case IRPosition::PK: \
13655 AA = new (A.Allocator) CLASS##SUFFIX(IRP, A); \
13659#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13660 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13661 CLASS *AA = nullptr; \
13662 switch (IRP.getPositionKind()) { \
13663 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13664 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13665 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13666 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13667 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13668 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13669 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13670 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13675#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13676 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13677 CLASS *AA = nullptr; \
13678 switch (IRP.getPositionKind()) { \
13679 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13680 SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \
13681 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13682 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13683 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13684 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13685 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13686 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13691#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS) \
13692 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13693 CLASS *AA = nullptr; \
13694 switch (IRP.getPositionKind()) { \
13695 SWITCH_PK_CREATE(CLASS, IRP, POS, SUFFIX) \
13697 llvm_unreachable("Cannot create " #CLASS " for position otherthan " #POS \
13703#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13704 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13705 CLASS *AA = nullptr; \
13706 switch (IRP.getPositionKind()) { \
13707 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13708 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13709 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13710 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13711 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13712 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13713 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13714 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13719#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13720 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13721 CLASS *AA = nullptr; \
13722 switch (IRP.getPositionKind()) { \
13723 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13724 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13725 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13726 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13727 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13728 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13729 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13730 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13735#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13736 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13737 CLASS *AA = nullptr; \
13738 switch (IRP.getPositionKind()) { \
13739 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13740 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13741 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13742 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13743 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13744 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13745 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13746 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13798#undef CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION
13799#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
13800#undef CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION
13801#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
13802#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
13803#undef CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION
13804#undef SWITCH_PK_CREATE
13805#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)
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)
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
dot regions Print regions of function to dot true view regions View regions of function(with no function bodies)"
Remove Loads Into Fake Uses
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
std::pair< BasicBlock *, BasicBlock * > Edge
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
This file defines generic set operations that may be used on set's of different types,...
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static SymbolRef::Type getType(const Symbol *Sym)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type.
static unsigned getSize(unsigned Kind)
LLVM_ABI AACallGraphNode * operator*() const
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A trivial helper function to check to see if the specified pointers are no-alias.
Class for arbitrary precision integers.
int64_t getSExtValue() const
Get sign extended value.
CallBase * getInstruction() const
Return the underlying instruction.
bool isCallbackCall() const
Return true if this ACS represents a callback call.
bool isDirectCall() const
Return true if this ACS represents a direct call.
static LLVM_ABI void getCallbackUses(const CallBase &CB, SmallVectorImpl< const Use * > &CallbackUses)
Add operand uses of CB that represent callback uses into CallbackUses.
int getCallArgOperandNo(Argument &Arg) const
Return the operand index of the underlying instruction associated with Arg.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
unsigned getAddressSpace() const
Return the address space for the allocation.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
This class represents an incoming formal argument to a Function.
LLVM_ABI bool hasNoAliasAttr() const
Return true if this argument has the noalias attribute.
LLVM_ABI bool onlyReadsMemory() const
Return true if this argument has the readonly or readnone attribute.
LLVM_ABI bool hasPointeeInMemoryValueAttr() const
Return true if this argument has the byval, sret, inalloca, preallocated, or byref attribute.
LLVM_ABI bool hasReturnedAttr() const
Return true if this argument has the returned attribute.
LLVM_ABI bool hasByValAttr() const
Return true if this argument has the byval attribute.
const Function * getParent() const
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
Functions, function parameters, and return types can have attributes to indicate how they should be t...
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
LLVM_ABI FPClassTest getNoFPClass() const
Return the FPClassTest for nofpclass.
LLVM_ABI Attribute::AttrKind getKindAsEnum() const
Return the attribute's kind as an enum (Attribute::AttrKind).
LLVM_ABI MemoryEffects getMemoryEffects() const
Returns memory effects.
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
static LLVM_ABI Attribute getWithCaptureInfo(LLVMContext &Context, CaptureInfo CI)
static bool isEnumAttrKind(AttrKind Kind)
LLVM_ABI CaptureInfo getCaptureInfo() const
Returns information from captures attribute.
LLVM Basic Block Representation.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Instruction & front() const
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
BinaryOps getOpcode() const
Conditional or Unconditional Branch instruction.
iterator_range< succ_op_iterator > successors()
unsigned getNumSuccessors() const
static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)
BasicBlock * getSuccessor(unsigned i) const
Value * getCondition() const
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
Value * getCalledOperand() const
const Use & getCalledOperandUse() const
const Use & getArgOperandUse(unsigned i) const
Wrappers for getting the Use of a call argument.
LLVM_ABI std::optional< ConstantRange > getRange() const
If this return value has a range attribute, return the value range of the argument.
Value * getArgOperand(unsigned i) const
bool isBundleOperand(unsigned Idx) const
Return true if the operand at index Idx is a bundle operand.
bool isConvergent() const
Determine if the invoke is convergent.
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static CaptureInfo none()
Create CaptureInfo that does not capture any components of the pointer.
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
LLVM_ABI bool isIntegerCast() const
There are several places where we need to know if a cast instruction only deals with integer source a...
Type * getDestTy() const
Return the destination type, as a convenience.
bool isEquality() const
Determine if this is an equals/not equals predicate.
bool isFalseWhenEqual() const
This is just a convenience.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
bool isTrueWhenEqual() const
This is just a convenience.
Predicate getPredicate() const
Return the predicate for this instruction.
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.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
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 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.
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.
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
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.
@ Undef
Value of the register doesn't matter.
@ 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.
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)
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)
GenericCycleInfo< SSAContext > CycleInfo
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-fp-math" and "denormal-fp-ma...
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 DenormalMode getDefault()
Return the assumed default mode for a function without denormal-fp-math.
static constexpr DenormalMode getInvalid()
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)
}
bool isValidState() const override
See AbstractState::isValidState(...)
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.