55#include "llvm/IR/IntrinsicsAMDGPU.h"
56#include "llvm/IR/IntrinsicsNVPTX.h"
83#define DEBUG_TYPE "attributor"
87 cl::desc(
"Manifest Attributor internal string attributes."),
100 cl::desc(
"Maximum number of potential values to be "
101 "tracked for each position."),
106 "attributor-max-potential-values-iterations",
cl::Hidden,
108 "Maximum number of iterations we keep dismantling potential values."),
111STATISTIC(NumAAs,
"Number of abstract attributes created");
112STATISTIC(NumIndirectCallsPromoted,
"Number of indirect calls promoted");
127#define BUILD_STAT_MSG_IR_ATTR(TYPE, NAME) \
128 ("Number of " #TYPE " marked '" #NAME "'")
129#define BUILD_STAT_NAME(NAME, TYPE) NumIR##TYPE##_##NAME
130#define STATS_DECL_(NAME, MSG) STATISTIC(NAME, MSG);
131#define STATS_DECL(NAME, TYPE, MSG) \
132 STATS_DECL_(BUILD_STAT_NAME(NAME, TYPE), MSG);
133#define STATS_TRACK(NAME, TYPE) ++(BUILD_STAT_NAME(NAME, TYPE));
134#define STATS_DECLTRACK(NAME, TYPE, MSG) \
135 {STATS_DECL(NAME, TYPE, MSG) STATS_TRACK(NAME, TYPE)}
136#define STATS_DECLTRACK_ARG_ATTR(NAME) \
137 STATS_DECLTRACK(NAME, Arguments, BUILD_STAT_MSG_IR_ATTR(arguments, NAME))
138#define STATS_DECLTRACK_CSARG_ATTR(NAME) \
139 STATS_DECLTRACK(NAME, CSArguments, \
140 BUILD_STAT_MSG_IR_ATTR(call site arguments, NAME))
141#define STATS_DECLTRACK_FN_ATTR(NAME) \
142 STATS_DECLTRACK(NAME, Function, BUILD_STAT_MSG_IR_ATTR(functions, NAME))
143#define STATS_DECLTRACK_CS_ATTR(NAME) \
144 STATS_DECLTRACK(NAME, CS, BUILD_STAT_MSG_IR_ATTR(call site, NAME))
145#define STATS_DECLTRACK_FNRET_ATTR(NAME) \
146 STATS_DECLTRACK(NAME, FunctionReturn, \
147 BUILD_STAT_MSG_IR_ATTR(function returns, NAME))
148#define STATS_DECLTRACK_CSRET_ATTR(NAME) \
149 STATS_DECLTRACK(NAME, CSReturn, \
150 BUILD_STAT_MSG_IR_ATTR(call site returns, NAME))
151#define STATS_DECLTRACK_FLOATING_ATTR(NAME) \
152 STATS_DECLTRACK(NAME, Floating, \
153 ("Number of floating values known to be '" #NAME "'"))
158#define PIPE_OPERATOR(CLASS) \
159 raw_ostream &operator<<(raw_ostream &OS, const CLASS &AA) { \
160 return OS << static_cast<const AbstractAttribute &>(AA); \
217 bool HeaderOnly,
Cycle **CPtr =
nullptr) {
220 auto *BB =
I->getParent();
226 return !HeaderOnly || BB ==
C->getHeader();
237 if (
DL.getTypeSizeInBits(Ty) !=
DL.getTypeAllocSizeInBits(Ty))
262 StartPos +=
DL.getTypeAllocSizeInBits(ElTy);
272 bool AllowVolatile) {
273 if (!AllowVolatile &&
I->isVolatile())
277 return LI->getPointerOperand();
281 return SI->getPointerOperand();
285 return CXI->getPointerOperand();
289 return RMWI->getPointerOperand();
311 bool GetMinOffset,
bool AllowNonInbounds,
312 bool UseAssumed =
false) {
314 auto AttributorAnalysis = [&](
Value &V,
APInt &ROffset) ->
bool {
321 if (!ValueConstantRangeAA)
325 if (
Range.isFullSet())
331 ROffset =
Range.getSignedMin();
333 ROffset =
Range.getSignedMax();
344 const Value *Ptr, int64_t &BytesOffset,
349 true, AllowNonInbounds);
357template <
typename AAType,
typename StateType =
typename AAType::StateType,
359 bool RecurseForSelectAndPHI =
true>
361 Attributor &
A,
const AAType &QueryingAA, StateType &S,
363 LLVM_DEBUG(
dbgs() <<
"[Attributor] Clamp return value states for "
364 << QueryingAA <<
" into " << S <<
"\n");
366 assert((QueryingAA.getIRPosition().getPositionKind() ==
368 QueryingAA.getIRPosition().getPositionKind() ==
370 "Can only clamp returned value states for a function returned or call "
371 "site returned position!");
375 std::optional<StateType>
T;
378 auto CheckReturnValue = [&](
Value &RV) ->
bool {
392 <<
" AA: " <<
AA->getAsStr(&
A) <<
" @ " << RVPos <<
"\n");
393 const StateType &AAS =
AA->getState();
395 T = StateType::getBestState(AAS);
397 LLVM_DEBUG(
dbgs() <<
"[Attributor] AA State: " << AAS <<
" RV State: " <<
T
399 return T->isValidState();
402 if (!
A.checkForAllReturnedValues(CheckReturnValue, QueryingAA,
404 RecurseForSelectAndPHI))
405 S.indicatePessimisticFixpoint();
412template <
typename AAType,
typename BaseType,
413 typename StateType =
typename BaseType::StateType,
414 bool PropagateCallBaseContext =
false,
416 bool RecurseForSelectAndPHI =
true>
417struct AAReturnedFromReturnedValues :
public BaseType {
418 AAReturnedFromReturnedValues(
const IRPosition &IRP, Attributor &
A)
423 StateType S(StateType::getBestState(this->getState()));
425 RecurseForSelectAndPHI>(
427 PropagateCallBaseContext ? this->getCallBaseContext() : nullptr);
436template <
typename AAType,
typename StateType =
typename AAType::StateType,
438static void clampCallSiteArgumentStates(
Attributor &
A,
const AAType &QueryingAA,
440 LLVM_DEBUG(
dbgs() <<
"[Attributor] Clamp call site argument states for "
441 << QueryingAA <<
" into " << S <<
"\n");
443 assert(QueryingAA.getIRPosition().getPositionKind() ==
445 "Can only clamp call site argument states for an argument position!");
449 std::optional<StateType>
T;
452 unsigned ArgNo = QueryingAA.getIRPosition().getCallSiteArgNo();
472 LLVM_DEBUG(
dbgs() <<
"[Attributor] ACS: " << *ACS.getInstruction()
473 <<
" AA: " <<
AA->getAsStr(&
A) <<
" @" << ACSArgPos
475 const StateType &AAS =
AA->getState();
477 T = StateType::getBestState(AAS);
479 LLVM_DEBUG(
dbgs() <<
"[Attributor] AA State: " << AAS <<
" CSA State: " <<
T
481 return T->isValidState();
484 bool UsedAssumedInformation =
false;
485 if (!
A.checkForAllCallSites(CallSiteCheck, QueryingAA,
true,
486 UsedAssumedInformation))
487 S.indicatePessimisticFixpoint();
494template <
typename AAType,
typename BaseType,
495 typename StateType =
typename AAType::StateType,
497bool getArgumentStateFromCallBaseContext(
Attributor &
A,
501 "Expected an 'argument' position !");
507 assert(ArgNo >= 0 &&
"Invalid Arg No!");
521 const StateType &CBArgumentState =
522 static_cast<const StateType &
>(
AA->getState());
524 LLVM_DEBUG(
dbgs() <<
"[Attributor] Briding Call site context to argument"
525 <<
"Position:" << Pos <<
"CB Arg state:" << CBArgumentState
529 State ^= CBArgumentState;
534template <
typename AAType,
typename BaseType,
535 typename StateType =
typename AAType::StateType,
536 bool BridgeCallBaseContext =
false,
538struct AAArgumentFromCallSiteArguments :
public BaseType {
539 AAArgumentFromCallSiteArguments(
const IRPosition &IRP, Attributor &
A)
544 StateType S = StateType::getBestState(this->getState());
546 if (BridgeCallBaseContext) {
548 getArgumentStateFromCallBaseContext<AAType,
BaseType, StateType,
550 A, *
this, this->getIRPosition(), S);
554 clampCallSiteArgumentStates<AAType, StateType, IRAttributeKind>(
A, *
this,
564template <
typename AAType,
typename BaseType,
565 typename StateType =
typename BaseType::StateType,
566 bool IntroduceCallBaseContext =
false,
568struct AACalleeToCallSite :
public BaseType {
569 AACalleeToCallSite(
const IRPosition &IRP, Attributor &
A) :
BaseType(IRP,
A) {}
573 auto IRPKind = this->getIRPosition().getPositionKind();
576 "Can only wrap function returned positions for call site "
577 "returned positions!");
578 auto &S = this->getState();
581 if (IntroduceCallBaseContext)
582 LLVM_DEBUG(
dbgs() <<
"[Attributor] Introducing call base context:" << CB
587 for (
const Function *Callee : Callees) {
591 IntroduceCallBaseContext ? &CB :
nullptr)
593 *
Callee, IntroduceCallBaseContext ? &CB : nullptr);
595 if (Attribute::isEnumAttrKind(IRAttributeKind)) {
598 A,
this, FnPos, DepClassTy::REQUIRED, IsKnown))
604 A.getAAFor<AAType>(*
this, FnPos, DepClassTy::REQUIRED);
608 if (S.isAtFixpoint())
609 return S.isValidState();
613 if (!
A.checkForAllCallees(CalleePred, *
this, CB))
614 return S.indicatePessimisticFixpoint();
620template <
class AAType,
typename StateType =
typename AAType::StateType>
626 auto EIt = Explorer.
begin(CtxI), EEnd = Explorer.
end(CtxI);
627 for (
unsigned u = 0;
u <
Uses.size(); ++
u) {
631 if (Found &&
AA.followUseInMBEC(
A, U, UserI, State))
646template <
class AAType,
typename StateType =
typename AAType::StateType>
647static void followUsesInMBEC(AAType &
AA,
Attributor &
A, StateType &S,
649 const Value &Val =
AA.getIRPosition().getAssociatedValue();
654 A.getInfoCache().getMustBeExecutedContextExplorer();
660 for (
const Use &U : Val.
uses())
663 followUsesInContext<AAType>(
AA,
A, *Explorer, &CtxI,
Uses, S);
665 if (S.isAtFixpoint())
709 StateType ParentState;
713 ParentState.indicateOptimisticFixpoint();
715 for (
const BasicBlock *BB : Br->successors()) {
716 StateType ChildState;
718 size_t BeforeSize =
Uses.size();
719 followUsesInContext(
AA,
A, *Explorer, &BB->front(),
Uses, ChildState);
722 for (
auto It =
Uses.begin() + BeforeSize; It !=
Uses.end();)
725 ParentState &= ChildState;
785 R.indicatePessimisticFixpoint();
802 BS.indicateOptimisticFixpoint();
808 BS.indicatePessimisticFixpoint();
878 template <
typename F>
885 if (!
Range.mayOverlap(ItRange))
887 bool IsExact =
Range == ItRange && !
Range.offsetOrSizeAreUnknown();
888 for (
auto Index : It.getSecond()) {
898 template <
typename F>
909 for (
unsigned Index : LocalList->getSecond()) {
912 if (
Range.offsetAndSizeAreUnknown())
928 RemoteI = RemoteI ? RemoteI : &
I;
932 bool AccExists =
false;
934 for (
auto Index : LocalList) {
936 if (
A.getLocalInst() == &
I) {
945 <<
"[AAPointerInfo] Inserting access in new offset bins\n";);
947 for (
auto Key : ToAdd) {
954 AccessList.emplace_back(&
I, RemoteI, Ranges, Content, Kind, Ty);
956 "New Access should have been at AccIndex");
957 LocalList.push_back(AccIndex);
966 auto Before = Current;
968 if (Current == Before)
971 auto &ExistingRanges = Before.getRanges();
972 auto &NewRanges = Current.getRanges();
979 <<
"[AAPointerInfo] Removing access from old offset bins\n";);
986 "Expected bin to actually contain the Access.");
1008struct AAPointerInfoImpl
1009 :
public StateWrapper<AA::PointerInfo::State, AAPointerInfo> {
1014 const std::string getAsStr(
Attributor *
A)
const override {
1015 return std::string(
"PointerInfo ") +
1016 (isValidState() ? (std::string(
"#") +
1017 std::to_string(OffsetBins.size()) +
" bins")
1022 [](int64_t O) {
return std::to_string(O); }),
1030 return AAPointerInfo::manifest(
A);
1033 const_bin_iterator
begin()
const override {
return State::begin(); }
1034 const_bin_iterator
end()
const override {
return State::end(); }
1035 int64_t numOffsetBins()
const override {
return State::numOffsetBins(); }
1036 bool reachesReturn()
const override {
1037 return !ReturnedOffsets.isUnassigned();
1039 void addReturnedOffsetsTo(OffsetInfo &OI)
const override {
1040 if (ReturnedOffsets.isUnknown()) {
1045 OffsetInfo MergedOI;
1046 for (
auto Offset : ReturnedOffsets) {
1047 OffsetInfo TmpOI = OI;
1049 MergedOI.merge(TmpOI);
1051 OI = std::move(MergedOI);
1054 ChangeStatus setReachesReturn(
const OffsetInfo &ReachedReturnedOffsets) {
1055 if (ReturnedOffsets.isUnknown())
1056 return ChangeStatus::UNCHANGED;
1057 if (ReachedReturnedOffsets.isUnknown()) {
1058 ReturnedOffsets.setUnknown();
1059 return ChangeStatus::CHANGED;
1061 if (ReturnedOffsets.merge(ReachedReturnedOffsets))
1062 return ChangeStatus::CHANGED;
1063 return ChangeStatus::UNCHANGED;
1066 bool forallInterferingAccesses(
1068 function_ref<
bool(
const AAPointerInfo::Access &,
bool)> CB)
1070 return State::forallInterferingAccesses(
Range, CB);
1073 bool forallInterferingAccesses(
1074 Attributor &
A,
const AbstractAttribute &QueryingAA, Instruction &
I,
1075 bool FindInterferingWrites,
bool FindInterferingReads,
1076 function_ref<
bool(
const Access &,
bool)> UserCB,
bool &HasBeenWrittenTo,
1078 function_ref<
bool(
const Access &)> SkipCB)
const override {
1079 HasBeenWrittenTo =
false;
1081 SmallPtrSet<const Access *, 8> DominatingWrites;
1089 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
1091 bool AllInSameNoSyncFn = IsAssumedNoSync;
1092 bool InstIsExecutedByInitialThreadOnly =
1093 ExecDomainAA && ExecDomainAA->isExecutedByInitialThreadOnly(
I);
1100 bool InstIsExecutedInAlignedRegion =
1101 FindInterferingReads && ExecDomainAA &&
1102 ExecDomainAA->isExecutedInAlignedRegion(
A,
I);
1104 if (InstIsExecutedInAlignedRegion || InstIsExecutedByInitialThreadOnly)
1105 A.recordDependence(*ExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1107 InformationCache &InfoCache =
A.getInfoCache();
1108 bool IsThreadLocalObj =
1117 auto CanIgnoreThreadingForInst = [&](
const Instruction &
I) ->
bool {
1118 if (IsThreadLocalObj || AllInSameNoSyncFn)
1120 const auto *FnExecDomainAA =
1121 I.getFunction() == &
Scope
1123 :
A.lookupAAFor<AAExecutionDomain>(
1126 if (!FnExecDomainAA)
1128 if (InstIsExecutedInAlignedRegion ||
1129 (FindInterferingWrites &&
1130 FnExecDomainAA->isExecutedInAlignedRegion(
A,
I))) {
1131 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1134 if (InstIsExecutedByInitialThreadOnly &&
1135 FnExecDomainAA->isExecutedByInitialThreadOnly(
I)) {
1136 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1145 auto CanIgnoreThreading = [&](
const Access &Acc) ->
bool {
1146 return CanIgnoreThreadingForInst(*Acc.getRemoteInst()) ||
1147 (Acc.getRemoteInst() != Acc.getLocalInst() &&
1148 CanIgnoreThreadingForInst(*Acc.getLocalInst()));
1152 bool IsKnownNoRecurse;
1160 bool InstInKernel =
A.getInfoCache().isKernel(Scope);
1161 bool ObjHasKernelLifetime =
false;
1162 const bool UseDominanceReasoning =
1163 FindInterferingWrites && IsKnownNoRecurse;
1164 const DominatorTree *DT =
1173 unsigned VAS =
V->getType()->getPointerAddressSpace();
1184 std::function<bool(
const Function &)> IsLiveInCalleeCB;
1189 const Function *AIFn = AI->getFunction();
1190 ObjHasKernelLifetime =
A.getInfoCache().isKernel(*AIFn);
1191 bool IsKnownNoRecurse;
1194 IsKnownNoRecurse)) {
1195 IsLiveInCalleeCB = [AIFn](
const Function &Fn) {
return AIFn != &Fn; };
1200 ObjHasKernelLifetime = HasKernelLifetime(GV, *GV->getParent());
1201 if (ObjHasKernelLifetime)
1202 IsLiveInCalleeCB = [&
A](
const Function &Fn) {
1203 return !
A.getInfoCache().isKernel(Fn);
1211 auto AccessCB = [&](
const Access &Acc,
bool Exact) {
1212 Function *AccScope = Acc.getRemoteInst()->getFunction();
1213 bool AccInSameScope = AccScope == &
Scope;
1217 if (InstInKernel && ObjHasKernelLifetime && !AccInSameScope &&
1218 A.getInfoCache().isKernel(*AccScope))
1221 if (Exact && Acc.isMustAccess() && Acc.getRemoteInst() != &
I) {
1222 if (Acc.isWrite() || (
isa<LoadInst>(
I) && Acc.isWriteOrAssumption()))
1223 ExclusionSet.
insert(Acc.getRemoteInst());
1226 if ((!FindInterferingWrites || !Acc.isWriteOrAssumption()) &&
1227 (!FindInterferingReads || !Acc.isRead()))
1230 bool Dominates = FindInterferingWrites && DT && Exact &&
1231 Acc.isMustAccess() && AccInSameScope &&
1234 DominatingWrites.
insert(&Acc);
1238 AllInSameNoSyncFn &= Acc.getRemoteInst()->getFunction() == &
Scope;
1240 InterferingAccesses.
push_back({&Acc, Exact});
1243 if (!State::forallInterferingAccesses(
I, AccessCB,
Range))
1246 HasBeenWrittenTo = !DominatingWrites.
empty();
1250 for (
const Access *Acc : DominatingWrites) {
1251 if (!LeastDominatingWriteInst) {
1252 LeastDominatingWriteInst = Acc->getRemoteInst();
1253 }
else if (DT->
dominates(LeastDominatingWriteInst,
1254 Acc->getRemoteInst())) {
1255 LeastDominatingWriteInst = Acc->getRemoteInst();
1260 auto CanSkipAccess = [&](
const Access &Acc,
bool Exact) {
1261 if (SkipCB && SkipCB(Acc))
1263 if (!CanIgnoreThreading(Acc))
1269 bool ReadChecked = !FindInterferingReads;
1270 bool WriteChecked = !FindInterferingWrites;
1276 &ExclusionSet, IsLiveInCalleeCB))
1281 if (!WriteChecked) {
1283 &ExclusionSet, IsLiveInCalleeCB))
1284 WriteChecked =
true;
1298 if (!WriteChecked && HasBeenWrittenTo &&
1299 Acc.getRemoteInst()->getFunction() != &Scope) {
1301 const auto *FnReachabilityAA =
A.getAAFor<AAInterFnReachability>(
1303 if (FnReachabilityAA) {
1309 if (!FnReachabilityAA->instructionCanReach(
1310 A, *LeastDominatingWriteInst,
1311 *Acc.getRemoteInst()->getFunction(), &ExclusionSet))
1312 WriteChecked =
true;
1319 if (ReadChecked && WriteChecked)
1322 if (!DT || !UseDominanceReasoning)
1324 if (!DominatingWrites.count(&Acc))
1326 return LeastDominatingWriteInst != Acc.getRemoteInst();
1331 for (
auto &It : InterferingAccesses) {
1332 if ((!AllInSameNoSyncFn && !IsThreadLocalObj && !ExecDomainAA) ||
1333 !CanSkipAccess(*It.first, It.second)) {
1334 if (!UserCB(*It.first, It.second))
1342 const AAPointerInfo &OtherAA,
1344 using namespace AA::PointerInfo;
1346 return indicatePessimisticFixpoint();
1349 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1350 bool IsByval = OtherAAImpl.getAssociatedArgument()->hasByValAttr();
1351 Changed |= setReachesReturn(OtherAAImpl.ReturnedOffsets);
1354 const auto &State = OtherAAImpl.getState();
1355 for (
const auto &It : State) {
1356 for (
auto Index : It.getSecond()) {
1357 const auto &RAcc = State.getAccess(Index);
1358 if (IsByval && !RAcc.isRead())
1360 bool UsedAssumedInformation =
false;
1362 auto Content =
A.translateArgumentToCallSiteContent(
1363 RAcc.getContent(), CB, *
this, UsedAssumedInformation);
1364 AK =
AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW));
1365 AK =
AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST));
1367 Changed |= addAccess(
A, RAcc.getRanges(), CB, Content, AK,
1368 RAcc.getType(), RAcc.getRemoteInst());
1374 ChangeStatus translateAndAddState(Attributor &
A,
const AAPointerInfo &OtherAA,
1375 const OffsetInfo &Offsets, CallBase &CB,
1377 using namespace AA::PointerInfo;
1379 return indicatePessimisticFixpoint();
1381 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1385 const auto &State = OtherAAImpl.getState();
1386 for (
const auto &It : State) {
1387 for (
auto Index : It.getSecond()) {
1388 const auto &RAcc = State.getAccess(Index);
1389 if (!IsMustAcc && RAcc.isAssumption())
1391 for (
auto Offset : Offsets) {
1395 if (!NewRanges.isUnknown()) {
1396 NewRanges.addToAllOffsets(Offset);
1401 Changed |= addAccess(
A, NewRanges, CB, RAcc.getContent(), AK,
1402 RAcc.getType(), RAcc.getRemoteInst());
1411 void trackPointerInfoStatistics(
const IRPosition &IRP)
const {}
1414 void dumpState(raw_ostream &O) {
1415 for (
auto &It : OffsetBins) {
1416 O <<
"[" << It.first.Offset <<
"-" << It.first.Offset + It.first.Size
1417 <<
"] : " << It.getSecond().size() <<
"\n";
1418 for (
auto AccIndex : It.getSecond()) {
1419 auto &Acc = AccessList[AccIndex];
1420 O <<
" - " << Acc.getKind() <<
" - " << *Acc.getLocalInst() <<
"\n";
1421 if (Acc.getLocalInst() != Acc.getRemoteInst())
1422 O <<
" --> " << *Acc.getRemoteInst()
1424 if (!Acc.isWrittenValueYetUndetermined()) {
1426 O <<
" - c: func " << Acc.getWrittenValue()->getName()
1428 else if (Acc.getWrittenValue())
1429 O <<
" - c: " << *Acc.getWrittenValue() <<
"\n";
1431 O <<
" - c: <unknown>\n";
1438struct AAPointerInfoFloating :
public AAPointerInfoImpl {
1440 AAPointerInfoFloating(
const IRPosition &IRP, Attributor &
A)
1441 : AAPointerInfoImpl(IRP,
A) {}
1444 bool handleAccess(Attributor &
A, Instruction &
I,
1445 std::optional<Value *> Content,
AccessKind Kind,
1448 using namespace AA::PointerInfo;
1450 const DataLayout &
DL =
A.getDataLayout();
1451 TypeSize AccessSize =
DL.getTypeStoreSize(&Ty);
1460 if (!VT || VT->getElementCount().isScalable() ||
1462 (*Content)->getType() != VT ||
1463 DL.getTypeStoreSize(VT->getElementType()).isScalable()) {
1474 int64_t ElementSize =
DL.getTypeStoreSize(ElementType).getFixedValue();
1479 for (
int i = 0, e = VT->getElementCount().getFixedValue(); i != e; ++i) {
1481 ConstContent, ConstantInt::get(Int32Ty, i));
1488 for (
auto &ElementOffset : ElementOffsets)
1489 ElementOffset += ElementSize;
1502 bool collectConstantsForGEP(Attributor &
A,
const DataLayout &
DL,
1503 OffsetInfo &UsrOI,
const OffsetInfo &PtrOI,
1504 const GEPOperator *
GEP);
1507 void trackStatistics()
const override {
1508 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1512bool AAPointerInfoFloating::collectConstantsForGEP(Attributor &
A,
1513 const DataLayout &
DL,
1515 const OffsetInfo &PtrOI,
1516 const GEPOperator *
GEP) {
1517 unsigned BitWidth =
DL.getIndexTypeSizeInBits(
GEP->getType());
1518 SmallMapVector<Value *, APInt, 4> VariableOffsets;
1521 assert(!UsrOI.isUnknown() && !PtrOI.isUnknown() &&
1522 "Don't look for constant values if the offset has already been "
1523 "determined to be unknown.");
1525 if (!
GEP->collectOffset(
DL,
BitWidth, VariableOffsets, ConstantOffset)) {
1531 << (VariableOffsets.
empty() ?
"" :
"not") <<
" constant "
1535 Union.addToAll(ConstantOffset.getSExtValue());
1540 for (
const auto &VI : VariableOffsets) {
1541 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
1543 if (!PotentialConstantsAA || !PotentialConstantsAA->isValidState()) {
1549 if (PotentialConstantsAA->undefIsContained())
1556 auto &AssumedSet = PotentialConstantsAA->getAssumedSet();
1557 if (AssumedSet.empty())
1561 for (
const auto &ConstOffset : AssumedSet) {
1562 auto CopyPerOffset =
Union;
1563 CopyPerOffset.addToAll(ConstOffset.getSExtValue() *
1564 VI.second.getZExtValue());
1565 Product.merge(CopyPerOffset);
1570 UsrOI = std::move(Union);
1574ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &
A) {
1575 using namespace AA::PointerInfo;
1577 const DataLayout &
DL =
A.getDataLayout();
1578 Value &AssociatedValue = getAssociatedValue();
1580 DenseMap<Value *, OffsetInfo> OffsetInfoMap;
1581 OffsetInfoMap[&AssociatedValue].
insert(0);
1583 auto HandlePassthroughUser = [&](
Value *Usr,
Value *CurPtr,
bool &Follow) {
1594 "CurPtr does not exist in the map!");
1596 auto &UsrOI = OffsetInfoMap[Usr];
1597 auto &PtrOI = OffsetInfoMap[CurPtr];
1598 assert(!PtrOI.isUnassigned() &&
1599 "Cannot pass through if the input Ptr was not visited!");
1605 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
1607 User *Usr =
U.getUser();
1608 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Analyze " << *CurPtr <<
" in " << *Usr
1611 "The current pointer offset should have been seeded!");
1612 assert(!OffsetInfoMap[CurPtr].isUnassigned() &&
1613 "Current pointer should be assigned");
1617 return HandlePassthroughUser(Usr, CurPtr, Follow);
1619 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled constant user " << *CE
1627 auto &UsrOI = OffsetInfoMap[Usr];
1628 auto &PtrOI = OffsetInfoMap[CurPtr];
1630 if (UsrOI.isUnknown())
1633 if (PtrOI.isUnknown()) {
1639 Follow = collectConstantsForGEP(
A,
DL, UsrOI, PtrOI,
GEP);
1645 return HandlePassthroughUser(Usr, CurPtr, Follow);
1650 if (RI->getFunction() == getAssociatedFunction()) {
1651 auto &PtrOI = OffsetInfoMap[CurPtr];
1652 Changed |= setReachesReturn(PtrOI);
1665 auto &UsrOI = PhiIt->second;
1666 auto &PtrOI = OffsetInfoMap[CurPtr];
1670 if (PtrOI.isUnknown()) {
1671 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand offset unknown "
1672 << *CurPtr <<
" in " << *
PHI <<
"\n");
1673 Follow = !UsrOI.isUnknown();
1679 if (UsrOI == PtrOI) {
1680 assert(!PtrOI.isUnassigned() &&
1681 "Cannot assign if the current Ptr was not visited!");
1682 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant (so far)");
1692 auto It = OffsetInfoMap.
find(CurPtrBase);
1693 if (It == OffsetInfoMap.
end()) {
1694 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand is too complex "
1695 << *CurPtr <<
" in " << *
PHI
1696 <<
" (base: " << *CurPtrBase <<
")\n");
1710 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
1711 *
PHI->getFunction());
1713 auto BaseOI = It->getSecond();
1714 BaseOI.addToAll(
Offset.getZExtValue());
1715 if (IsFirstPHIUser || BaseOI == UsrOI) {
1716 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant " << *CurPtr
1717 <<
" in " << *Usr <<
"\n");
1718 return HandlePassthroughUser(Usr, CurPtr, Follow);
1722 dbgs() <<
"[AAPointerInfo] PHI operand pointer offset mismatch "
1723 << *CurPtr <<
" in " << *
PHI <<
"\n");
1742 if (!handleAccess(
A, *LoadI,
nullptr, AK,
1743 OffsetInfoMap[CurPtr].Offsets,
Changed,
1749 return II->isAssumeLikeIntrinsic();
1760 }
while (FromI && FromI != ToI);
1765 auto IsValidAssume = [&](IntrinsicInst &IntrI) {
1766 if (IntrI.getIntrinsicID() != Intrinsic::assume)
1769 if (IntrI.getParent() == BB) {
1770 if (IsImpactedInRange(LoadI->getNextNode(), &IntrI))
1776 if ((*PredIt) != BB)
1781 if (SuccBB == IntrBB)
1787 if (IsImpactedInRange(LoadI->getNextNode(), BB->
getTerminator()))
1789 if (IsImpactedInRange(&IntrBB->
front(), &IntrI))
1795 std::pair<Value *, IntrinsicInst *> Assumption;
1796 for (
const Use &LoadU : LoadI->uses()) {
1798 if (!CmpI->isEquality() || !CmpI->isTrueWhenEqual())
1800 for (
const Use &CmpU : CmpI->uses()) {
1802 if (!IsValidAssume(*IntrI))
1804 int Idx = CmpI->getOperandUse(0) == LoadU;
1805 Assumption = {CmpI->getOperand(Idx), IntrI};
1810 if (Assumption.first)
1815 if (!Assumption.first || !Assumption.second)
1819 << *Assumption.second <<
": " << *LoadI
1820 <<
" == " << *Assumption.first <<
"\n");
1821 bool UsedAssumedInformation =
false;
1822 std::optional<Value *> Content =
nullptr;
1823 if (Assumption.first)
1825 A.getAssumedSimplified(*Assumption.first, *
this,
1827 return handleAccess(
1828 A, *Assumption.second, Content, AccessKind::AK_ASSUMPTION,
1829 OffsetInfoMap[CurPtr].Offsets,
Changed, *LoadI->getType());
1834 for (
auto *OtherOp : OtherOps) {
1835 if (OtherOp == CurPtr) {
1838 <<
"[AAPointerInfo] Escaping use in store like instruction " <<
I
1850 bool UsedAssumedInformation =
false;
1851 std::optional<Value *> Content =
nullptr;
1853 Content =
A.getAssumedSimplified(
1855 return handleAccess(
A,
I, Content, AK, OffsetInfoMap[CurPtr].Offsets,
1860 return HandleStoreLike(*StoreI, StoreI->getValueOperand(),
1861 *StoreI->getValueOperand()->getType(),
1862 {StoreI->getValueOperand()}, AccessKind::AK_W);
1864 return HandleStoreLike(*RMWI,
nullptr, *RMWI->getValOperand()->getType(),
1865 {RMWI->getValOperand()}, AccessKind::AK_RW);
1867 return HandleStoreLike(
1868 *CXI,
nullptr, *CXI->getNewValOperand()->getType(),
1869 {CXI->getCompareOperand(), CXI->getNewValOperand()},
1876 A.getInfoCache().getTargetLibraryInfoForFunction(*CB->
getFunction());
1881 const auto *CSArgPI =
A.getAAFor<AAPointerInfo>(
1887 Changed = translateAndAddState(
A, *CSArgPI, OffsetInfoMap[CurPtr], *CB,
1890 if (!CSArgPI->reachesReturn())
1891 return isValidState();
1894 if (!Callee ||
Callee->arg_size() <= ArgNo)
1896 bool UsedAssumedInformation =
false;
1897 auto ReturnedValue =
A.getAssumedSimplified(
1902 auto *Arg =
Callee->getArg(ArgNo);
1903 if (ReturnedArg && Arg != ReturnedArg)
1905 bool IsRetMustAcc = IsArgMustAcc && (ReturnedArg == Arg);
1906 const auto *CSRetPI =
A.getAAFor<AAPointerInfo>(
1910 OffsetInfo OI = OffsetInfoMap[CurPtr];
1911 CSArgPI->addReturnedOffsetsTo(OI);
1913 translateAndAddState(
A, *CSRetPI, OI, *CB, IsRetMustAcc) |
Changed;
1914 return isValidState();
1916 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Call user not handled " << *CB
1921 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] User not handled " << *Usr <<
"\n");
1924 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
1925 assert(OffsetInfoMap.
count(OldU) &&
"Old use should be known already!");
1926 assert(!OffsetInfoMap[OldU].isUnassigned() &&
"Old use should be assinged");
1927 if (OffsetInfoMap.
count(NewU)) {
1929 if (!(OffsetInfoMap[NewU] == OffsetInfoMap[OldU])) {
1930 dbgs() <<
"[AAPointerInfo] Equivalent use callback failed: "
1931 << OffsetInfoMap[NewU] <<
" vs " << OffsetInfoMap[OldU]
1935 return OffsetInfoMap[NewU] == OffsetInfoMap[OldU];
1938 return HandlePassthroughUser(NewU.get(), OldU.
get(), Unused);
1940 if (!
A.checkForAllUses(UsePred, *
this, AssociatedValue,
1942 true, EquivalentUseCB)) {
1943 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Check for all uses failed, abort!\n");
1944 return indicatePessimisticFixpoint();
1948 dbgs() <<
"Accesses by bin after update:\n";
1955struct AAPointerInfoReturned final : AAPointerInfoImpl {
1956 AAPointerInfoReturned(
const IRPosition &IRP, Attributor &
A)
1957 : AAPointerInfoImpl(IRP,
A) {}
1961 return indicatePessimisticFixpoint();
1965 void trackStatistics()
const override {
1966 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1970struct AAPointerInfoArgument final : AAPointerInfoFloating {
1971 AAPointerInfoArgument(
const IRPosition &IRP, Attributor &
A)
1972 : AAPointerInfoFloating(IRP,
A) {}
1975 void trackStatistics()
const override {
1976 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1980struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
1981 AAPointerInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
1982 : AAPointerInfoFloating(IRP,
A) {}
1986 using namespace AA::PointerInfo;
1992 if (
auto Length =
MI->getLengthInBytes())
1993 LengthVal =
Length->getSExtValue();
1994 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
1997 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled memory intrinsic "
1999 return indicatePessimisticFixpoint();
2002 ArgNo == 0 ? AccessKind::AK_MUST_WRITE : AccessKind::AK_MUST_READ;
2004 Changed | addAccess(
A, {0, LengthVal}, *
MI,
nullptr,
Kind,
nullptr);
2007 dbgs() <<
"Accesses by bin after update:\n";
2018 Argument *Arg = getAssociatedArgument();
2022 A.getAAFor<AAPointerInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
2023 if (ArgAA && ArgAA->getState().isValidState())
2024 return translateAndAddStateFromCallee(
A, *ArgAA,
2027 return indicatePessimisticFixpoint();
2030 bool IsKnownNoCapture;
2032 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNoCapture))
2033 return indicatePessimisticFixpoint();
2035 bool IsKnown =
false;
2037 return ChangeStatus::UNCHANGED;
2040 ReadOnly ? AccessKind::AK_MAY_READ : AccessKind::AK_MAY_READ_WRITE;
2046 void trackStatistics()
const override {
2047 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2051struct AAPointerInfoCallSiteReturned final : AAPointerInfoFloating {
2052 AAPointerInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2053 : AAPointerInfoFloating(IRP,
A) {}
2056 void trackStatistics()
const override {
2057 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2065struct AANoUnwindImpl : AANoUnwind {
2066 AANoUnwindImpl(
const IRPosition &IRP, Attributor &
A) : AANoUnwind(IRP,
A) {}
2072 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2076 const std::string getAsStr(Attributor *
A)
const override {
2077 return getAssumed() ?
"nounwind" :
"may-unwind";
2083 (unsigned)Instruction::Invoke, (
unsigned)Instruction::CallBr,
2084 (unsigned)Instruction::Call, (
unsigned)Instruction::CleanupRet,
2085 (unsigned)Instruction::CatchSwitch, (
unsigned)Instruction::Resume};
2088 if (!
I.mayThrow(
true))
2092 bool IsKnownNoUnwind;
2100 bool UsedAssumedInformation =
false;
2101 if (!
A.checkForAllInstructions(CheckForNoUnwind, *
this, Opcodes,
2102 UsedAssumedInformation))
2103 return indicatePessimisticFixpoint();
2105 return ChangeStatus::UNCHANGED;
2109struct AANoUnwindFunction final :
public AANoUnwindImpl {
2110 AANoUnwindFunction(
const IRPosition &IRP, Attributor &
A)
2111 : AANoUnwindImpl(IRP,
A) {}
2118struct AANoUnwindCallSite final
2119 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl> {
2120 AANoUnwindCallSite(
const IRPosition &IRP, Attributor &
A)
2121 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl>(IRP,
A) {}
2132 case Intrinsic::nvvm_barrier_cta_sync_aligned_all:
2133 case Intrinsic::nvvm_barrier_cta_sync_aligned_count:
2134 case Intrinsic::nvvm_barrier_cta_red_and_aligned_all:
2135 case Intrinsic::nvvm_barrier_cta_red_and_aligned_count:
2136 case Intrinsic::nvvm_barrier_cta_red_or_aligned_all:
2137 case Intrinsic::nvvm_barrier_cta_red_or_aligned_count:
2138 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_all:
2139 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_count:
2141 case Intrinsic::amdgcn_s_barrier:
2142 if (ExecutedAligned)
2165 switch (
I->getOpcode()) {
2166 case Instruction::AtomicRMW:
2169 case Instruction::Store:
2172 case Instruction::Load:
2177 "New atomic operations need to be known in the attributor.");
2196 const std::string getAsStr(Attributor *
A)
const override {
2197 return getAssumed() ?
"nosync" :
"may-sync";
2213 if (
I.mayReadOrWriteMemory())
2227 bool UsedAssumedInformation =
false;
2228 if (!
A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *
this,
2229 UsedAssumedInformation) ||
2230 !
A.checkForAllCallLikeInstructions(CheckForNoSync, *
this,
2231 UsedAssumedInformation))
2232 return indicatePessimisticFixpoint();
2237struct AANoSyncFunction final :
public AANoSyncImpl {
2238 AANoSyncFunction(
const IRPosition &IRP, Attributor &
A)
2239 : AANoSyncImpl(IRP,
A) {}
2246struct AANoSyncCallSite final : AACalleeToCallSite<AANoSync, AANoSyncImpl> {
2247 AANoSyncCallSite(
const IRPosition &IRP, Attributor &
A)
2248 : AACalleeToCallSite<AANoSync, AANoSyncImpl>(IRP,
A) {}
2258struct AANoFreeImpl :
public AANoFree {
2259 AANoFreeImpl(
const IRPosition &IRP, Attributor &
A) : AANoFree(IRP,
A) {}
2265 DepClassTy::NONE, IsKnown));
2283 bool UsedAssumedInformation =
false;
2284 if (!
A.checkForAllReadWriteInstructions(CheckForNoFree, *
this,
2285 UsedAssumedInformation) ||
2286 !
A.checkForAllCallLikeInstructions(CheckForNoFree, *
this,
2287 UsedAssumedInformation))
2288 return indicatePessimisticFixpoint();
2290 return ChangeStatus::UNCHANGED;
2294 const std::string getAsStr(Attributor *
A)
const override {
2295 return getAssumed() ?
"nofree" :
"may-free";
2299struct AANoFreeFunction final :
public AANoFreeImpl {
2300 AANoFreeFunction(
const IRPosition &IRP, Attributor &
A)
2301 : AANoFreeImpl(IRP,
A) {}
2308struct AANoFreeCallSite final : AACalleeToCallSite<AANoFree, AANoFreeImpl> {
2309 AANoFreeCallSite(
const IRPosition &IRP, Attributor &
A)
2310 : AACalleeToCallSite<AANoFree, AANoFreeImpl>(IRP,
A) {}
2317struct AANoFreeFloating : AANoFreeImpl {
2318 AANoFreeFloating(
const IRPosition &IRP, Attributor &
A)
2319 : AANoFreeImpl(IRP,
A) {}
2326 const IRPosition &IRP = getIRPosition();
2331 DepClassTy::OPTIONAL, IsKnown))
2332 return ChangeStatus::UNCHANGED;
2334 Value &AssociatedValue = getIRPosition().getAssociatedValue();
2335 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
2350 DepClassTy::REQUIRED, IsKnown))
2353 const AANoCapture *NoCaptureAA =
nullptr;
2356 DepClassTy::REQUIRED, IsKnown,
2357 false, &NoCaptureAA)) {
2382 if (!
A.checkForAllUses(Pred, *
this, AssociatedValue))
2383 return indicatePessimisticFixpoint();
2385 return ChangeStatus::UNCHANGED;
2390struct AANoFreeArgument final : AANoFreeFloating {
2391 AANoFreeArgument(
const IRPosition &IRP, Attributor &
A)
2392 : AANoFreeFloating(IRP,
A) {}
2399struct AANoFreeCallSiteArgument final : AANoFreeFloating {
2400 AANoFreeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2401 : AANoFreeFloating(IRP,
A) {}
2409 Argument *Arg = getAssociatedArgument();
2411 return indicatePessimisticFixpoint();
2415 DepClassTy::REQUIRED, IsKnown))
2416 return ChangeStatus::UNCHANGED;
2417 return indicatePessimisticFixpoint();
2425struct AANoFreeReturned final : AANoFreeFloating {
2426 AANoFreeReturned(
const IRPosition &IRP, Attributor &
A)
2427 : AANoFreeFloating(IRP,
A) {
2442 void trackStatistics()
const override {}
2446struct AANoFreeCallSiteReturned final : AANoFreeFloating {
2447 AANoFreeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2448 : AANoFreeFloating(IRP,
A) {}
2451 return ChangeStatus::UNCHANGED;
2462 bool IgnoreSubsumingPositions) {
2464 AttrKinds.
push_back(Attribute::NonNull);
2467 AttrKinds.
push_back(Attribute::Dereferenceable);
2468 if (
A.hasAttr(IRP, AttrKinds, IgnoreSubsumingPositions, Attribute::NonNull))
2475 if (!Fn->isDeclaration()) {
2485 bool UsedAssumedInformation =
false;
2486 if (!
A.checkForAllInstructions(
2488 Worklist.push_back({*cast<ReturnInst>(I).getReturnValue(), &I});
2492 UsedAssumedInformation,
false,
true))
2504 Attribute::NonNull)});
2509static int64_t getKnownNonNullAndDerefBytesForUse(
2510 Attributor &
A,
const AbstractAttribute &QueryingAA,
Value &AssociatedValue,
2511 const Use *U,
const Instruction *
I,
bool &IsNonNull,
bool &TrackUse) {
2514 const Value *UseV =
U->get();
2535 const DataLayout &
DL =
A.getInfoCache().getDL();
2539 U, {Attribute::NonNull, Attribute::Dereferenceable})) {
2556 bool IsKnownNonNull;
2559 IsNonNull |= IsKnownNonNull;
2562 return DerefAA ? DerefAA->getKnownDereferenceableBytes() : 0;
2566 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
2567 Loc->Size.isScalable() ||
I->isVolatile())
2573 if (
Base &&
Base == &AssociatedValue) {
2574 int64_t DerefBytes = Loc->Size.getValue() +
Offset;
2576 return std::max(int64_t(0), DerefBytes);
2583 int64_t DerefBytes = Loc->Size.getValue();
2585 return std::max(int64_t(0), DerefBytes);
2591struct AANonNullImpl : AANonNull {
2592 AANonNullImpl(
const IRPosition &IRP, Attributor &
A) : AANonNull(IRP,
A) {}
2596 Value &
V = *getAssociatedValue().stripPointerCasts();
2598 indicatePessimisticFixpoint();
2602 if (Instruction *CtxI = getCtxI())
2603 followUsesInMBEC(*
this,
A, getState(), *CtxI);
2607 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
2608 AANonNull::StateType &State) {
2609 bool IsNonNull =
false;
2610 bool TrackUse =
false;
2611 getKnownNonNullAndDerefBytesForUse(
A, *
this, getAssociatedValue(), U,
I,
2612 IsNonNull, TrackUse);
2613 State.setKnown(IsNonNull);
2618 const std::string getAsStr(Attributor *
A)
const override {
2619 return getAssumed() ?
"nonnull" :
"may-null";
2624struct AANonNullFloating :
public AANonNullImpl {
2625 AANonNullFloating(
const IRPosition &IRP, Attributor &
A)
2626 : AANonNullImpl(IRP,
A) {}
2630 auto CheckIRP = [&](
const IRPosition &IRP) {
2631 bool IsKnownNonNull;
2633 A, *
this, IRP, DepClassTy::OPTIONAL, IsKnownNonNull);
2637 bool UsedAssumedInformation =
false;
2638 Value *AssociatedValue = &getAssociatedValue();
2640 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
2645 Values.size() != 1 ||
Values.front().getValue() != AssociatedValue;
2651 return AA::hasAssumedIRAttr<Attribute::NonNull>(
2652 A, this, IRPosition::value(*Op), DepClassTy::OPTIONAL,
2655 return ChangeStatus::UNCHANGED;
2659 DepClassTy::OPTIONAL, IsKnown) &&
2662 DepClassTy::OPTIONAL, IsKnown))
2663 return ChangeStatus::UNCHANGED;
2670 if (AVIRP == getIRPosition() || !CheckIRP(AVIRP))
2671 return indicatePessimisticFixpoint();
2672 return ChangeStatus::UNCHANGED;
2675 for (
const auto &VAC :
Values)
2677 return indicatePessimisticFixpoint();
2679 return ChangeStatus::UNCHANGED;
2687struct AANonNullReturned final
2688 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2689 false, AANonNull::IRAttributeKind, false> {
2690 AANonNullReturned(
const IRPosition &IRP, Attributor &
A)
2691 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2696 const std::string getAsStr(Attributor *
A)
const override {
2697 return getAssumed() ?
"nonnull" :
"may-null";
2705struct AANonNullArgument final
2706 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
2707 AANonNullArgument(
const IRPosition &IRP, Attributor &
A)
2708 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP,
A) {}
2714struct AANonNullCallSiteArgument final : AANonNullFloating {
2715 AANonNullCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2716 : AANonNullFloating(IRP,
A) {}
2723struct AANonNullCallSiteReturned final
2724 : AACalleeToCallSite<AANonNull, AANonNullImpl> {
2725 AANonNullCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2726 : AACalleeToCallSite<AANonNull, AANonNullImpl>(IRP,
A) {}
2735struct AAMustProgressImpl :
public AAMustProgress {
2736 AAMustProgressImpl(
const IRPosition &IRP, Attributor &
A)
2737 : AAMustProgress(IRP,
A) {}
2743 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2748 const std::string getAsStr(Attributor *
A)
const override {
2749 return getAssumed() ?
"mustprogress" :
"may-not-progress";
2753struct AAMustProgressFunction final : AAMustProgressImpl {
2754 AAMustProgressFunction(
const IRPosition &IRP, Attributor &
A)
2755 : AAMustProgressImpl(IRP,
A) {}
2761 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnown)) {
2763 return indicateOptimisticFixpoint();
2764 return ChangeStatus::UNCHANGED;
2767 auto CheckForMustProgress = [&](AbstractCallSite ACS) {
2769 bool IsKnownMustProgress;
2771 A,
this, IPos, DepClassTy::REQUIRED, IsKnownMustProgress,
2775 bool AllCallSitesKnown =
true;
2776 if (!
A.checkForAllCallSites(CheckForMustProgress, *
this,
2779 return indicatePessimisticFixpoint();
2781 return ChangeStatus::UNCHANGED;
2785 void trackStatistics()
const override {
2791struct AAMustProgressCallSite final : AAMustProgressImpl {
2792 AAMustProgressCallSite(
const IRPosition &IRP, Attributor &
A)
2793 : AAMustProgressImpl(IRP,
A) {}
2802 bool IsKnownMustProgress;
2804 A,
this, FnPos, DepClassTy::REQUIRED, IsKnownMustProgress))
2805 return indicatePessimisticFixpoint();
2806 return ChangeStatus::UNCHANGED;
2810 void trackStatistics()
const override {
2819struct AANoRecurseImpl :
public AANoRecurse {
2820 AANoRecurseImpl(
const IRPosition &IRP, Attributor &
A) : AANoRecurse(IRP,
A) {}
2826 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2831 const std::string getAsStr(Attributor *
A)
const override {
2832 return getAssumed() ?
"norecurse" :
"may-recurse";
2836struct AANoRecurseFunction final : AANoRecurseImpl {
2837 AANoRecurseFunction(
const IRPosition &IRP, Attributor &
A)
2838 : AANoRecurseImpl(IRP,
A) {}
2844 auto CallSitePred = [&](AbstractCallSite ACS) {
2845 bool IsKnownNoRecurse;
2849 DepClassTy::NONE, IsKnownNoRecurse))
2851 return IsKnownNoRecurse;
2853 bool UsedAssumedInformation =
false;
2854 if (
A.checkForAllCallSites(CallSitePred, *
this,
true,
2855 UsedAssumedInformation)) {
2861 if (!UsedAssumedInformation)
2862 indicateOptimisticFixpoint();
2863 return ChangeStatus::UNCHANGED;
2866 const AAInterFnReachability *EdgeReachability =
2867 A.getAAFor<AAInterFnReachability>(*
this, getIRPosition(),
2868 DepClassTy::REQUIRED);
2869 if (EdgeReachability && EdgeReachability->
canReach(
A, *getAnchorScope()))
2870 return indicatePessimisticFixpoint();
2871 return ChangeStatus::UNCHANGED;
2878struct AANoRecurseCallSite final
2879 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl> {
2880 AANoRecurseCallSite(
const IRPosition &IRP, Attributor &
A)
2881 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl>(IRP,
A) {}
2891struct AANonConvergentImpl :
public AANonConvergent {
2892 AANonConvergentImpl(
const IRPosition &IRP, Attributor &
A)
2893 : AANonConvergent(IRP,
A) {}
2896 const std::string getAsStr(Attributor *
A)
const override {
2897 return getAssumed() ?
"non-convergent" :
"may-be-convergent";
2901struct AANonConvergentFunction final : AANonConvergentImpl {
2902 AANonConvergentFunction(
const IRPosition &IRP, Attributor &
A)
2903 : AANonConvergentImpl(IRP,
A) {}
2909 auto CalleeIsNotConvergent = [&](
Instruction &Inst) {
2912 if (!Callee ||
Callee->isIntrinsic()) {
2915 if (
Callee->isDeclaration()) {
2916 return !
Callee->hasFnAttribute(Attribute::Convergent);
2918 const auto *ConvergentAA =
A.getAAFor<AANonConvergent>(
2920 return ConvergentAA && ConvergentAA->isAssumedNotConvergent();
2923 bool UsedAssumedInformation =
false;
2924 if (!
A.checkForAllCallLikeInstructions(CalleeIsNotConvergent, *
this,
2925 UsedAssumedInformation)) {
2926 return indicatePessimisticFixpoint();
2928 return ChangeStatus::UNCHANGED;
2932 if (isKnownNotConvergent() &&
2933 A.hasAttr(getIRPosition(), Attribute::Convergent)) {
2934 A.removeAttrs(getIRPosition(), {Attribute::Convergent});
2935 return ChangeStatus::CHANGED;
2937 return ChangeStatus::UNCHANGED;
2947struct AAUndefinedBehaviorImpl :
public AAUndefinedBehavior {
2948 AAUndefinedBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
2949 : AAUndefinedBehavior(IRP,
A) {}
2955 UndefBranchCondition,
2957 NullReturnViolatesNonNull,
2959 NullArgViolatesNonNull,
2963 std::optional<unsigned> ArgNo;
2965 UBInfo(Kind K) :
K(
K), ArgNo(std::nullopt) {}
2967 UBInfo(Kind K, std::optional<unsigned> ArgNo) :
K(
K), ArgNo(ArgNo) {}
2973 const size_t UBPrevSize = KnownUBInsts.size();
2974 const size_t NoUBPrevSize = AssumedNoUBInsts.size();
2982 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
2991 "Expected pointer operand of memory accessing instruction");
2995 std::optional<Value *> SimplifiedPtrOp =
2996 stopOnUndefOrAssumed(
A, PtrOp, &
I, UBInfo::UndefPtrAccess);
2997 if (!SimplifiedPtrOp || !*SimplifiedPtrOp)
2999 const Value *PtrOpVal = *SimplifiedPtrOp;
3005 AssumedNoUBInsts.insert(&
I);
3017 AssumedNoUBInsts.insert(&
I);
3019 KnownUBInsts.try_emplace(&
I, UBInfo::NullPtrAccess);
3028 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3036 std::optional<Value *> SimplifiedCond = stopOnUndefOrAssumed(
3037 A, BrInst->getCondition(), BrInst, UBInfo::UndefBranchCondition);
3038 if (!SimplifiedCond || !*SimplifiedCond)
3040 AssumedNoUBInsts.insert(&
I);
3048 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3057 for (
unsigned idx = 0; idx < CB.
arg_size(); idx++) {
3063 if (idx >=
Callee->arg_size())
3075 bool IsKnownNoUndef;
3077 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNoUndef);
3078 if (!IsKnownNoUndef)
3080 bool UsedAssumedInformation =
false;
3081 std::optional<Value *> SimplifiedVal =
3084 if (UsedAssumedInformation)
3086 if (SimplifiedVal && !*SimplifiedVal)
3089 KnownUBInsts.try_emplace(&
I, UBInfo(UBInfo::UndefCallArgument, idx));
3095 bool IsKnownNonNull;
3097 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNonNull);
3099 KnownUBInsts.try_emplace(&
I,
3100 UBInfo(UBInfo::NullArgViolatesNonNull, idx));
3109 std::optional<Value *> SimplifiedRetValue = stopOnUndefOrAssumed(
3110 A, RI.getReturnValue(), &
I, UBInfo::UndefReturnValue);
3111 if (!SimplifiedRetValue || !*SimplifiedRetValue)
3129 bool IsKnownNonNull;
3134 KnownUBInsts.try_emplace(&
I, UBInfo::NullReturnViolatesNonNull);
3140 bool UsedAssumedInformation =
false;
3141 A.checkForAllInstructions(InspectMemAccessInstForUB, *
this,
3142 {Instruction::Load, Instruction::Store,
3143 Instruction::AtomicCmpXchg,
3144 Instruction::AtomicRMW},
3145 UsedAssumedInformation,
3147 A.checkForAllInstructions(InspectBrInstForUB, *
this, {Instruction::CondBr},
3148 UsedAssumedInformation,
3150 A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *
this,
3151 UsedAssumedInformation);
3155 if (!getAnchorScope()->getReturnType()->isVoidTy()) {
3157 if (!
A.isAssumedDead(ReturnIRP,
this,
nullptr, UsedAssumedInformation)) {
3158 bool IsKnownNoUndef;
3160 A,
this, ReturnIRP, DepClassTy::NONE, IsKnownNoUndef);
3162 A.checkForAllInstructions(InspectReturnInstForUB, *
this,
3163 {Instruction::Ret}, UsedAssumedInformation,
3168 if (NoUBPrevSize != AssumedNoUBInsts.size() ||
3169 UBPrevSize != KnownUBInsts.size())
3170 return ChangeStatus::CHANGED;
3171 return ChangeStatus::UNCHANGED;
3174 bool isKnownToCauseUB(Instruction *
I)
const override {
3175 return KnownUBInsts.count(
I);
3178 bool isAssumedToCauseUB(Instruction *
I)
const override {
3185 switch (
I->getOpcode()) {
3186 case Instruction::Load:
3187 case Instruction::Store:
3188 case Instruction::AtomicCmpXchg:
3189 case Instruction::AtomicRMW:
3190 case Instruction::CondBr:
3191 return !AssumedNoUBInsts.count(
I);
3200 static void emitUBRemark(Attributor &
A, Instruction *
I,
const UBInfo &Info) {
3201 auto Remark = [&](OptimizationRemark
OR) {
3203 case UBInfo::NullPtrAccess:
3204 case UBInfo::UndefPtrAccess: {
3205 return OR <<
"Memory access through a pointer known to be "
3208 <<
" is undefined behavior; replacing with 'unreachable'.";
3210 case UBInfo::UndefBranchCondition:
3211 return OR <<
"Branch condition known to be "
3213 <<
" is undefined behavior; replacing with 'unreachable'.";
3214 case UBInfo::UndefReturnValue:
3215 case UBInfo::NullReturnViolatesNonNull:
3216 return OR <<
"Value returned known to be "
3219 <<
" is undefined behavior; replacing with 'unreachable'.";
3220 case UBInfo::UndefCallArgument:
3221 case UBInfo::NullArgViolatesNonNull: {
3222 bool IsUndef =
Info.K == UBInfo::UndefCallArgument;
3225 <<
" passed to parameter of ";
3230 return OR <<
" known to be "
3231 <<
ore::NV(
"Argument", IsUndef ?
"undef" :
"null")
3232 <<
" is undefined behavior; replacing with 'unreachable'.";
3237 A.emitRemark<OptimizationRemark>(
I,
"UndefinedBehavior",
Remark);
3241 if (KnownUBInsts.empty())
3242 return ChangeStatus::UNCHANGED;
3243 for (
const auto &[
I, Info] : KnownUBInsts) {
3244 emitUBRemark(
A,
I, Info);
3245 A.changeToUnreachableAfterManifest(
I);
3247 return ChangeStatus::CHANGED;
3251 const std::string getAsStr(Attributor *
A)
const override {
3252 return getAssumed() ?
"undefined-behavior" :
"no-ub";
3281 MapVector<Instruction *, UBInfo> KnownUBInsts;
3285 SmallPtrSet<Instruction *, 8> AssumedNoUBInsts;
3296 std::optional<Value *> stopOnUndefOrAssumed(Attributor &
A,
Value *V,
3297 Instruction *
I, UBInfo::Kind K) {
3298 bool UsedAssumedInformation =
false;
3299 std::optional<Value *> SimplifiedV =
3302 if (!UsedAssumedInformation) {
3307 KnownUBInsts.try_emplace(
I, K);
3308 return std::nullopt;
3315 KnownUBInsts.try_emplace(
I, K);
3316 return std::nullopt;
3322struct AAUndefinedBehaviorFunction final : AAUndefinedBehaviorImpl {
3323 AAUndefinedBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
3324 : AAUndefinedBehaviorImpl(IRP,
A) {}
3327 void trackStatistics()
const override {
3328 STATS_DECL(UndefinedBehaviorInstruction, Instruction,
3329 "Number of instructions known to have UB");
3331 KnownUBInsts.size();
3342static bool mayContainUnboundedCycle(Function &
F, Attributor &
A) {
3343 ScalarEvolution *SE =
3344 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
F);
3345 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
F);
3351 for (scc_iterator<Function *> SCCI =
scc_begin(&
F); !SCCI.isAtEnd(); ++SCCI)
3352 if (SCCI.hasCycle())
3362 for (
auto *L : LI->getLoopsInPreorder()) {
3369struct AAWillReturnImpl :
public AAWillReturn {
3370 AAWillReturnImpl(
const IRPosition &IRP, Attributor &
A)
3371 : AAWillReturn(IRP,
A) {}
3377 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
3382 bool isImpliedByMustprogressAndReadonly(Attributor &
A,
bool KnownOnly) {
3383 if (!
A.hasAttr(getIRPosition(), {Attribute::MustProgress}))
3388 return IsKnown || !KnownOnly;
3394 if (isImpliedByMustprogressAndReadonly(
A,
false))
3395 return ChangeStatus::UNCHANGED;
3401 A,
this, IPos, DepClassTy::REQUIRED, IsKnown)) {
3407 bool IsKnownNoRecurse;
3409 A,
this, IPos, DepClassTy::REQUIRED, IsKnownNoRecurse);
3412 bool UsedAssumedInformation =
false;
3413 if (!
A.checkForAllCallLikeInstructions(CheckForWillReturn, *
this,
3414 UsedAssumedInformation))
3415 return indicatePessimisticFixpoint();
3419 return !
I.isVolatile();
3421 if (!
A.checkForAllInstructions(CheckForVolatile, *
this,
3422 {Instruction::Load, Instruction::Store,
3423 Instruction::AtomicCmpXchg,
3424 Instruction::AtomicRMW},
3425 UsedAssumedInformation))
3426 return indicatePessimisticFixpoint();
3428 return ChangeStatus::UNCHANGED;
3432 const std::string getAsStr(Attributor *
A)
const override {
3433 return getAssumed() ?
"willreturn" :
"may-noreturn";
3437struct AAWillReturnFunction final : AAWillReturnImpl {
3438 AAWillReturnFunction(
const IRPosition &IRP, Attributor &
A)
3439 : AAWillReturnImpl(IRP,
A) {}
3443 AAWillReturnImpl::initialize(
A);
3446 assert(
F &&
"Did expect an anchor function");
3447 if (
F->isDeclaration() || mayContainUnboundedCycle(*
F,
A))
3448 indicatePessimisticFixpoint();
3456struct AAWillReturnCallSite final
3457 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl> {
3458 AAWillReturnCallSite(
const IRPosition &IRP, Attributor &
A)
3459 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl>(IRP,
A) {}
3463 if (isImpliedByMustprogressAndReadonly(
A,
false))
3464 return ChangeStatus::UNCHANGED;
3466 return AACalleeToCallSite::updateImpl(
A);
3488 const ToTy *
To =
nullptr;
3515 if (!ES || ES->
empty()) {
3516 ExclusionSet = nullptr;
3517 }
else if (MakeUnique) {
3518 ExclusionSet =
A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ES);
3536 if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))
3538 return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);
3546template <
typename BaseTy,
typename ToTy>
3547struct CachedReachabilityAA :
public BaseTy {
3548 using RQITy = ReachabilityQueryInfo<ToTy>;
3550 CachedReachabilityAA(
const IRPosition &IRP, Attributor &
A) : BaseTy(IRP,
A) {}
3553 bool isQueryAA()
const override {
return true; }
3558 for (
unsigned u = 0, e = QueryVector.size(); u < e; ++u) {
3559 RQITy *RQI = QueryVector[
u];
3560 if (RQI->Result == RQITy::Reachable::No &&
3562 Changed = ChangeStatus::CHANGED;
3568 bool IsTemporaryRQI) = 0;
3570 bool rememberResult(Attributor &
A,
typename RQITy::Reachable Result,
3571 RQITy &RQI,
bool UsedExclusionSet,
bool IsTemporaryRQI) {
3576 QueryCache.erase(&RQI);
3582 if (Result == RQITy::Reachable::Yes || !UsedExclusionSet) {
3583 RQITy PlainRQI(RQI.From, RQI.To);
3584 if (!QueryCache.count(&PlainRQI)) {
3585 RQITy *RQIPtr =
new (
A.Allocator) RQITy(RQI.From, RQI.To);
3587 QueryVector.push_back(RQIPtr);
3588 QueryCache.insert(RQIPtr);
3593 if (IsTemporaryRQI && Result != RQITy::Reachable::Yes && UsedExclusionSet) {
3594 assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&
3595 "Did not expect empty set!");
3596 RQITy *RQIPtr =
new (
A.Allocator)
3597 RQITy(
A, *RQI.From, *RQI.To, RQI.ExclusionSet,
true);
3598 assert(RQIPtr->Result == RQITy::Reachable::No &&
"Already reachable?");
3600 assert(!QueryCache.count(RQIPtr));
3601 QueryVector.push_back(RQIPtr);
3602 QueryCache.insert(RQIPtr);
3605 if (Result == RQITy::Reachable::No && IsTemporaryRQI)
3606 A.registerForUpdate(*
this);
3607 return Result == RQITy::Reachable::Yes;
3610 const std::string getAsStr(Attributor *
A)
const override {
3612 return "#queries(" + std::to_string(QueryVector.size()) +
")";
3615 bool checkQueryCache(Attributor &
A, RQITy &StackRQI,
3616 typename RQITy::Reachable &Result) {
3617 if (!this->getState().isValidState()) {
3618 Result = RQITy::Reachable::Yes;
3624 if (StackRQI.ExclusionSet) {
3625 RQITy PlainRQI(StackRQI.From, StackRQI.To);
3626 auto It = QueryCache.find(&PlainRQI);
3627 if (It != QueryCache.end() && (*It)->Result == RQITy::Reachable::No) {
3628 Result = RQITy::Reachable::No;
3633 auto It = QueryCache.find(&StackRQI);
3634 if (It != QueryCache.end()) {
3641 QueryCache.insert(&StackRQI);
3647 DenseSet<RQITy *> QueryCache;
3650struct AAIntraFnReachabilityFunction final
3651 :
public CachedReachabilityAA<AAIntraFnReachability, Instruction> {
3652 using Base = CachedReachabilityAA<AAIntraFnReachability, Instruction>;
3653 AAIntraFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
3655 DT =
A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(
3659 bool isAssumedReachable(
3660 Attributor &
A,
const Instruction &From,
const Instruction &To,
3662 auto *NonConstThis =
const_cast<AAIntraFnReachabilityFunction *
>(
this);
3666 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
3668 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
3669 return NonConstThis->isReachableImpl(
A, StackRQI,
3671 return Result == RQITy::Reachable::Yes;
3678 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3681 [&](
const auto &DeadEdge) {
3682 return LivenessAA->isEdgeDead(DeadEdge.first,
3686 return LivenessAA->isAssumedDead(BB);
3688 return ChangeStatus::UNCHANGED;
3692 return Base::updateImpl(
A);
3696 bool IsTemporaryRQI)
override {
3698 bool UsedExclusionSet =
false;
3703 while (IP && IP != &To) {
3704 if (ExclusionSet && IP != Origin && ExclusionSet->
count(IP)) {
3705 UsedExclusionSet =
true;
3713 const BasicBlock *FromBB = RQI.From->getParent();
3714 const BasicBlock *ToBB = RQI.To->getParent();
3716 "Not an intra-procedural query!");
3720 if (FromBB == ToBB &&
3721 WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
3722 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3727 if (!WillReachInBlock(ToBB->
front(), *RQI.To, RQI.ExclusionSet))
3728 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3732 SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
3733 if (RQI.ExclusionSet)
3734 for (
auto *
I : *RQI.ExclusionSet)
3735 if (
I->getFunction() == Fn)
3736 ExclusionBlocks.
insert(
I->getParent());
3739 if (ExclusionBlocks.
count(FromBB) &&
3742 return rememberResult(
A, RQITy::Reachable::No, RQI,
true, IsTemporaryRQI);
3745 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3746 if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {
3747 DeadBlocks.insert(ToBB);
3748 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3752 SmallPtrSet<const BasicBlock *, 16> Visited;
3756 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> LocalDeadEdges;
3757 while (!Worklist.
empty()) {
3759 if (!Visited.
insert(BB).second)
3761 for (
const BasicBlock *SuccBB :
successors(BB)) {
3762 if (LivenessAA && LivenessAA->isEdgeDead(BB, SuccBB)) {
3763 LocalDeadEdges.
insert({BB, SuccBB});
3768 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3771 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3774 if (ExclusionBlocks.
count(SuccBB)) {
3775 UsedExclusionSet =
true;
3782 DeadEdges.insert_range(LocalDeadEdges);
3783 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3788 void trackStatistics()
const override {}
3793 DenseSet<const BasicBlock *> DeadBlocks;
3797 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> DeadEdges;
3800 const DominatorTree *DT =
nullptr;
3808 bool IgnoreSubsumingPositions) {
3809 assert(ImpliedAttributeKind == Attribute::NoAlias &&
3810 "Unexpected attribute kind");
3816 IgnoreSubsumingPositions =
true;
3827 if (
A.hasAttr(IRP, {Attribute::ByVal, Attribute::NoAlias},
3828 IgnoreSubsumingPositions, Attribute::NoAlias))
3838 "Noalias is a pointer attribute");
3841 const std::string getAsStr(
Attributor *
A)
const override {
3842 return getAssumed() ?
"noalias" :
"may-alias";
3847struct AANoAliasFloating final : AANoAliasImpl {
3848 AANoAliasFloating(
const IRPosition &IRP, Attributor &
A)
3849 : AANoAliasImpl(IRP,
A) {}
3854 return indicatePessimisticFixpoint();
3858 void trackStatistics()
const override {
3864struct AANoAliasArgument final
3865 : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> {
3866 using Base = AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>;
3867 AANoAliasArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
3880 DepClassTy::OPTIONAL, IsKnownNoSycn))
3881 return Base::updateImpl(
A);
3886 return Base::updateImpl(
A);
3890 bool UsedAssumedInformation =
false;
3891 if (
A.checkForAllCallSites(
3892 [](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *
this,
3893 true, UsedAssumedInformation))
3894 return Base::updateImpl(
A);
3902 return indicatePessimisticFixpoint();
3909struct AANoAliasCallSiteArgument final : AANoAliasImpl {
3910 AANoAliasCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
3911 : AANoAliasImpl(IRP,
A) {}
3915 bool mayAliasWithArgument(Attributor &
A, AAResults *&AAR,
3916 const AAMemoryBehavior &MemBehaviorAA,
3917 const CallBase &CB,
unsigned OtherArgNo) {
3919 if (this->getCalleeArgNo() == (
int)OtherArgNo)
3927 auto *CBArgMemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
3931 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadNone()) {
3932 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3939 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadOnly() &&
3941 A.recordDependence(MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3942 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3948 AAR =
A.getInfoCache().getAnalysisResultForFunction<AAManager>(
3952 bool IsAliasing = !AAR || !AAR->
isNoAlias(&getAssociatedValue(), ArgOp);
3954 "callsite arguments: "
3955 << getAssociatedValue() <<
" " << *ArgOp <<
" => "
3956 << (IsAliasing ?
"" :
"no-") <<
"alias \n");
3961 bool isKnownNoAliasDueToNoAliasPreservation(
3962 Attributor &
A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA) {
3975 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
3991 bool IsKnownNoCapture;
3994 DepClassTy::OPTIONAL, IsKnownNoCapture))
4000 A, *UserI, *getCtxI(), *
this,
nullptr,
4001 [ScopeFn](
const Function &Fn) {
return &Fn != ScopeFn; }))
4016 LLVM_DEBUG(
dbgs() <<
"[AANoAliasCSArg] Unknown user: " << *UserI <<
"\n");
4020 bool IsKnownNoCapture;
4021 const AANoCapture *NoCaptureAA =
nullptr;
4023 A,
this, VIRP, DepClassTy::NONE, IsKnownNoCapture,
false, &NoCaptureAA);
4024 if (!IsAssumedNoCapture &&
4026 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue())) {
4028 dbgs() <<
"[AANoAliasCSArg] " << getAssociatedValue()
4029 <<
" cannot be noalias as it is potentially captured\n");
4034 A.recordDependence(*NoCaptureAA, *
this, DepClassTy::OPTIONAL);
4040 for (
unsigned OtherArgNo = 0; OtherArgNo < CB.
arg_size(); OtherArgNo++)
4041 if (mayAliasWithArgument(
A, AAR, MemBehaviorAA, CB, OtherArgNo))
4051 auto *MemBehaviorAA =
4052 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
4054 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
4055 return ChangeStatus::UNCHANGED;
4058 bool IsKnownNoAlias;
4061 A,
this, VIRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
4063 <<
" is not no-alias at the definition\n");
4064 return indicatePessimisticFixpoint();
4067 AAResults *AAR =
nullptr;
4068 if (MemBehaviorAA &&
4069 isKnownNoAliasDueToNoAliasPreservation(
A, AAR, *MemBehaviorAA)) {
4071 dbgs() <<
"[AANoAlias] No-Alias deduced via no-alias preservation\n");
4072 return ChangeStatus::UNCHANGED;
4075 return indicatePessimisticFixpoint();
4083struct AANoAliasReturned final : AANoAliasImpl {
4084 AANoAliasReturned(
const IRPosition &IRP, Attributor &
A)
4085 : AANoAliasImpl(IRP,
A) {}
4090 auto CheckReturnValue = [&](
Value &RV) ->
bool {
4101 bool IsKnownNoAlias;
4103 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoAlias))
4106 bool IsKnownNoCapture;
4107 const AANoCapture *NoCaptureAA =
nullptr;
4109 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
4111 return IsAssumedNoCapture ||
4115 if (!
A.checkForAllReturnedValues(CheckReturnValue, *
this))
4116 return indicatePessimisticFixpoint();
4118 return ChangeStatus::UNCHANGED;
4126struct AANoAliasCallSiteReturned final
4127 : AACalleeToCallSite<AANoAlias, AANoAliasImpl> {
4128 AANoAliasCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4129 : AACalleeToCallSite<AANoAlias, AANoAliasImpl>(IRP,
A) {}
4139struct AAIsDeadValueImpl :
public AAIsDead {
4140 AAIsDeadValueImpl(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4143 bool isAssumedDead()
const override {
return isAssumed(IS_DEAD); }
4146 bool isKnownDead()
const override {
return isKnown(IS_DEAD); }
4149 bool isAssumedDead(
const BasicBlock *BB)
const override {
return false; }
4152 bool isKnownDead(
const BasicBlock *BB)
const override {
return false; }
4155 bool isAssumedDead(
const Instruction *
I)
const override {
4156 return I == getCtxI() && isAssumedDead();
4160 bool isKnownDead(
const Instruction *
I)
const override {
4161 return isAssumedDead(
I) && isKnownDead();
4165 const std::string getAsStr(Attributor *
A)
const override {
4166 return isAssumedDead() ?
"assumed-dead" :
"assumed-live";
4170 bool areAllUsesAssumedDead(Attributor &
A,
Value &V) {
4172 if (
V.getType()->isVoidTy() ||
V.use_empty())
4178 if (!
A.isRunOn(*
I->getFunction()))
4180 bool UsedAssumedInformation =
false;
4181 std::optional<Constant *>
C =
4182 A.getAssumedConstant(V, *
this, UsedAssumedInformation);
4187 auto UsePred = [&](
const Use &
U,
bool &Follow) {
return false; };
4192 return A.checkForAllUses(UsePred, *
this, V,
false,
4193 DepClassTy::REQUIRED,
4198 bool isAssumedSideEffectFree(Attributor &
A, Instruction *
I) {
4202 if (!
I->isTerminator() && !
I->mayHaveSideEffects())
4211 bool IsKnownNoUnwind;
4213 A,
this, CallIRP, DepClassTy::OPTIONAL, IsKnownNoUnwind))
4221struct AAIsDeadFloating :
public AAIsDeadValueImpl {
4222 AAIsDeadFloating(
const IRPosition &IRP, Attributor &
A)
4223 : AAIsDeadValueImpl(IRP,
A) {}
4227 AAIsDeadValueImpl::initialize(
A);
4230 indicatePessimisticFixpoint();
4235 if (!isAssumedSideEffectFree(
A,
I)) {
4237 indicatePessimisticFixpoint();
4239 removeAssumedBits(HAS_NO_EFFECT);
4243 bool isDeadFence(Attributor &
A, FenceInst &FI) {
4244 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
4246 if (!ExecDomainAA || !ExecDomainAA->isNoOpFence(FI))
4248 A.recordDependence(*ExecDomainAA, *
this, DepClassTy::OPTIONAL);
4252 bool isDeadStore(Attributor &
A, StoreInst &SI,
4253 SmallSetVector<Instruction *, 8> *AssumeOnlyInst =
nullptr) {
4255 if (
SI.isVolatile())
4261 bool UsedAssumedInformation =
false;
4262 if (!AssumeOnlyInst) {
4263 PotentialCopies.clear();
4265 UsedAssumedInformation)) {
4268 <<
"[AAIsDead] Could not determine potential copies of store!\n");
4272 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Store has " << PotentialCopies.size()
4273 <<
" potential copies.\n");
4275 InformationCache &InfoCache =
A.getInfoCache();
4278 UsedAssumedInformation))
4282 auto &UserI = cast<Instruction>(*U.getUser());
4283 if (InfoCache.isOnlyUsedByAssume(UserI)) {
4285 AssumeOnlyInst->insert(&UserI);
4288 return A.isAssumedDead(U,
this,
nullptr, UsedAssumedInformation);
4294 <<
" is assumed live!\n");
4300 const std::string getAsStr(Attributor *
A)
const override {
4304 return "assumed-dead-store";
4307 return "assumed-dead-fence";
4308 return AAIsDeadValueImpl::getAsStr(
A);
4315 if (!isDeadStore(
A, *SI))
4316 return indicatePessimisticFixpoint();
4318 if (!isDeadFence(
A, *FI))
4319 return indicatePessimisticFixpoint();
4321 if (!isAssumedSideEffectFree(
A,
I))
4322 return indicatePessimisticFixpoint();
4323 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4324 return indicatePessimisticFixpoint();
4329 bool isRemovableStore()
const override {
4330 return isAssumed(IS_REMOVABLE) &&
isa<StoreInst>(&getAssociatedValue());
4335 Value &
V = getAssociatedValue();
4342 SmallSetVector<Instruction *, 8> AssumeOnlyInst;
4343 bool IsDead = isDeadStore(
A, *SI, &AssumeOnlyInst);
4346 A.deleteAfterManifest(*
I);
4347 for (
size_t i = 0; i < AssumeOnlyInst.
size(); ++i) {
4349 for (
auto *Usr : AOI->
users())
4351 A.deleteAfterManifest(*AOI);
4357 A.deleteAfterManifest(*FI);
4360 if (isAssumedSideEffectFree(
A,
I) && !
I->isTerminator()) {
4361 A.deleteAfterManifest(*
I);
4369 void trackStatistics()
const override {
4375 SmallSetVector<Value *, 4> PotentialCopies;
4378struct AAIsDeadArgument :
public AAIsDeadFloating {
4379 AAIsDeadArgument(
const IRPosition &IRP, Attributor &
A)
4380 : AAIsDeadFloating(IRP,
A) {}
4384 Argument &Arg = *getAssociatedArgument();
4385 if (
A.isValidFunctionSignatureRewrite(Arg, {}))
4386 if (
A.registerFunctionSignatureRewrite(
4390 return ChangeStatus::CHANGED;
4392 return ChangeStatus::UNCHANGED;
4399struct AAIsDeadCallSiteArgument :
public AAIsDeadValueImpl {
4400 AAIsDeadCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
4401 : AAIsDeadValueImpl(IRP,
A) {}
4405 AAIsDeadValueImpl::initialize(
A);
4407 indicatePessimisticFixpoint();
4416 Argument *Arg = getAssociatedArgument();
4418 return indicatePessimisticFixpoint();
4420 auto *ArgAA =
A.getAAFor<AAIsDead>(*
this, ArgPos, DepClassTy::REQUIRED);
4422 return indicatePessimisticFixpoint();
4431 "Expected undef values to be filtered out!");
4433 if (
A.changeUseAfterManifest(U, UV))
4434 return ChangeStatus::CHANGED;
4435 return ChangeStatus::UNCHANGED;
4442struct AAIsDeadCallSiteReturned :
public AAIsDeadFloating {
4443 AAIsDeadCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4444 : AAIsDeadFloating(IRP,
A) {}
4447 bool isAssumedDead()
const override {
4448 return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;
4453 AAIsDeadFloating::initialize(
A);
4455 indicatePessimisticFixpoint();
4460 IsAssumedSideEffectFree = isAssumedSideEffectFree(
A, getCtxI());
4466 if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(
A, getCtxI())) {
4467 IsAssumedSideEffectFree =
false;
4468 Changed = ChangeStatus::CHANGED;
4470 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4471 return indicatePessimisticFixpoint();
4476 void trackStatistics()
const override {
4477 if (IsAssumedSideEffectFree)
4484 const std::string getAsStr(Attributor *
A)
const override {
4485 return isAssumedDead()
4487 : (getAssumed() ?
"assumed-dead-users" :
"assumed-live");
4491 bool IsAssumedSideEffectFree =
true;
4494struct AAIsDeadReturned :
public AAIsDeadValueImpl {
4495 AAIsDeadReturned(
const IRPosition &IRP, Attributor &
A)
4496 : AAIsDeadValueImpl(IRP,
A) {}
4501 bool UsedAssumedInformation =
false;
4502 A.checkForAllInstructions([](Instruction &) {
return true; }, *
this,
4503 {Instruction::Ret}, UsedAssumedInformation);
4505 auto PredForCallSite = [&](AbstractCallSite ACS) {
4506 if (ACS.isCallbackCall() || !ACS.getInstruction())
4508 return areAllUsesAssumedDead(
A, *ACS.getInstruction());
4511 if (!
A.checkForAllCallSites(PredForCallSite, *
this,
true,
4512 UsedAssumedInformation))
4513 return indicatePessimisticFixpoint();
4515 return ChangeStatus::UNCHANGED;
4521 bool AnyChange =
false;
4522 UndefValue &UV = *
UndefValue::get(getAssociatedFunction()->getReturnType());
4529 bool UsedAssumedInformation =
false;
4530 A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
4531 UsedAssumedInformation);
4532 return AnyChange ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
4539struct AAIsDeadFunction :
public AAIsDead {
4540 AAIsDeadFunction(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4545 assert(
F &&
"Did expect an anchor function");
4546 if (!isAssumedDeadInternalFunction(
A)) {
4547 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4548 assumeLive(
A,
F->getEntryBlock());
4552 bool isAssumedDeadInternalFunction(Attributor &
A) {
4553 if (!getAnchorScope()->hasLocalLinkage())
4555 bool UsedAssumedInformation =
false;
4556 return A.checkForAllCallSites([](AbstractCallSite) {
return false; }, *
this,
4557 true, UsedAssumedInformation);
4561 const std::string getAsStr(Attributor *
A)
const override {
4562 return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) +
"/" +
4563 std::to_string(getAnchorScope()->
size()) +
"][#TBEP " +
4564 std::to_string(ToBeExploredFrom.size()) +
"][#KDE " +
4565 std::to_string(KnownDeadEnds.size()) +
"]";
4570 assert(getState().isValidState() &&
4571 "Attempted to manifest an invalid state!");
4576 if (AssumedLiveBlocks.empty()) {
4577 A.deleteAfterManifest(
F);
4578 return ChangeStatus::CHANGED;
4584 bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(
F);
4586 KnownDeadEnds.set_union(ToBeExploredFrom);
4587 for (
const Instruction *DeadEndI : KnownDeadEnds) {
4591 bool IsKnownNoReturn;
4599 A.registerInvokeWithDeadSuccessor(
const_cast<InvokeInst &
>(*
II));
4601 A.changeToUnreachableAfterManifest(
4602 const_cast<Instruction *
>(DeadEndI->getNextNode()));
4603 HasChanged = ChangeStatus::CHANGED;
4606 STATS_DECL(AAIsDead, BasicBlock,
"Number of dead basic blocks deleted.");
4607 for (BasicBlock &BB :
F)
4608 if (!AssumedLiveBlocks.count(&BB)) {
4609 A.deleteAfterManifest(BB);
4611 HasChanged = ChangeStatus::CHANGED;
4620 bool isEdgeDead(
const BasicBlock *From,
const BasicBlock *To)
const override {
4623 "Used AAIsDead of the wrong function");
4624 return isValidState() && !AssumedLiveEdges.count(std::make_pair(From, To));
4628 void trackStatistics()
const override {}
4631 bool isAssumedDead()
const override {
return false; }
4634 bool isKnownDead()
const override {
return false; }
4637 bool isAssumedDead(
const BasicBlock *BB)
const override {
4639 "BB must be in the same anchor scope function.");
4643 return !AssumedLiveBlocks.count(BB);
4647 bool isKnownDead(
const BasicBlock *BB)
const override {
4648 return getKnown() && isAssumedDead(BB);
4652 bool isAssumedDead(
const Instruction *
I)
const override {
4653 assert(
I->getParent()->getParent() == getAnchorScope() &&
4654 "Instruction must be in the same anchor scope function.");
4661 if (!AssumedLiveBlocks.count(
I->getParent()))
4667 if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))
4675 bool isKnownDead(
const Instruction *
I)
const override {
4676 return getKnown() && isAssumedDead(
I);
4681 bool assumeLive(Attributor &
A,
const BasicBlock &BB) {
4682 if (!AssumedLiveBlocks.insert(&BB).second)
4689 for (
const Instruction &
I : BB)
4692 if (
F->hasLocalLinkage())
4693 A.markLiveInternalFunction(*
F);
4699 SmallSetVector<const Instruction *, 8> ToBeExploredFrom;
4702 SmallSetVector<const Instruction *, 8> KnownDeadEnds;
4705 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> AssumedLiveEdges;
4708 DenseSet<const BasicBlock *> AssumedLiveBlocks;
4712identifyAliveSuccessors(Attributor &
A,
const CallBase &CB,
4713 AbstractAttribute &AA,
4714 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4717 bool IsKnownNoReturn;
4720 return !IsKnownNoReturn;
4729identifyAliveSuccessors(Attributor &
A,
const InvokeInst &
II,
4730 AbstractAttribute &AA,
4731 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4732 bool UsedAssumedInformation =
4738 if (AAIsDeadFunction::mayCatchAsynchronousExceptions(*
II.getFunction())) {
4739 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4743 bool IsKnownNoUnwind;
4746 UsedAssumedInformation |= !IsKnownNoUnwind;
4748 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4751 return UsedAssumedInformation;
4755identifyAliveSuccessors(Attributor &,
const UncondBrInst &BI,
4756 AbstractAttribute &,
4757 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4763identifyAliveSuccessors(Attributor &
A,
const CondBrInst &BI,
4764 AbstractAttribute &AA,
4765 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4766 bool UsedAssumedInformation =
false;
4767 std::optional<Constant *>
C =
4768 A.getAssumedConstant(*BI.
getCondition(), AA, UsedAssumedInformation);
4778 UsedAssumedInformation =
false;
4780 return UsedAssumedInformation;
4784identifyAliveSuccessors(Attributor &
A,
const SwitchInst &SI,
4785 AbstractAttribute &AA,
4786 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4787 bool UsedAssumedInformation =
false;
4791 UsedAssumedInformation)) {
4793 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4802 return UsedAssumedInformation;
4805 Type &Ty = *
SI.getCondition()->getType();
4806 SmallPtrSet<ConstantInt *, 8>
Constants;
4807 auto CheckForConstantInt = [&](
Value *
V) {
4816 return CheckForConstantInt(VAC.
getValue());
4818 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4820 return UsedAssumedInformation;
4823 unsigned MatchedCases = 0;
4824 for (
const auto &CaseIt :
SI.cases()) {
4825 if (
Constants.count(CaseIt.getCaseValue())) {
4827 AliveSuccessors.
push_back(&CaseIt.getCaseSuccessor()->front());
4834 AliveSuccessors.
push_back(&
SI.getDefaultDest()->front());
4835 return UsedAssumedInformation;
4841 if (AssumedLiveBlocks.empty()) {
4842 if (isAssumedDeadInternalFunction(
A))
4846 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4847 assumeLive(
A,
F->getEntryBlock());
4851 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Live [" << AssumedLiveBlocks.size() <<
"/"
4852 << getAnchorScope()->
size() <<
"] BBs and "
4853 << ToBeExploredFrom.size() <<
" exploration points and "
4854 << KnownDeadEnds.size() <<
" known dead ends\n");
4859 ToBeExploredFrom.end());
4860 decltype(ToBeExploredFrom) NewToBeExploredFrom;
4863 while (!Worklist.
empty()) {
4870 I =
I->getNextNode();
4872 AliveSuccessors.
clear();
4874 bool UsedAssumedInformation =
false;
4875 switch (
I->getOpcode()) {
4879 "Expected non-terminators to be handled already!");
4880 for (
const BasicBlock *SuccBB :
successors(
I->getParent()))
4883 case Instruction::Call:
4885 *
this, AliveSuccessors);
4887 case Instruction::Invoke:
4889 *
this, AliveSuccessors);
4891 case Instruction::UncondBr:
4892 UsedAssumedInformation = identifyAliveSuccessors(
4895 case Instruction::CondBr:
4897 *
this, AliveSuccessors);
4899 case Instruction::Switch:
4901 *
this, AliveSuccessors);
4905 if (UsedAssumedInformation) {
4906 NewToBeExploredFrom.insert(
I);
4907 }
else if (AliveSuccessors.
empty() ||
4908 (
I->isTerminator() &&
4909 AliveSuccessors.
size() <
I->getNumSuccessors())) {
4910 if (KnownDeadEnds.insert(
I))
4915 << AliveSuccessors.
size() <<
" UsedAssumedInformation: "
4916 << UsedAssumedInformation <<
"\n");
4918 for (
const Instruction *AliveSuccessor : AliveSuccessors) {
4919 if (!
I->isTerminator()) {
4920 assert(AliveSuccessors.size() == 1 &&
4921 "Non-terminator expected to have a single successor!");
4925 auto Edge = std::make_pair(
I->getParent(), AliveSuccessor->getParent());
4926 if (AssumedLiveEdges.insert(
Edge).second)
4928 if (assumeLive(
A, *AliveSuccessor->getParent()))
4935 if (NewToBeExploredFrom.size() != ToBeExploredFrom.size() ||
4936 llvm::any_of(NewToBeExploredFrom, [&](
const Instruction *
I) {
4937 return !ToBeExploredFrom.count(I);
4940 ToBeExploredFrom = std::move(NewToBeExploredFrom);
4949 if (ToBeExploredFrom.empty() &&
4950 getAnchorScope()->
size() == AssumedLiveBlocks.size() &&
4951 llvm::all_of(KnownDeadEnds, [](
const Instruction *DeadEndI) {
4952 return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;
4954 return indicatePessimisticFixpoint();
4959struct AAIsDeadCallSite final : AAIsDeadFunction {
4960 AAIsDeadCallSite(
const IRPosition &IRP, Attributor &
A)
4961 : AAIsDeadFunction(IRP,
A) {}
4970 "supported for call sites yet!");
4975 return indicatePessimisticFixpoint();
4979 void trackStatistics()
const override {}
4986struct AADereferenceableImpl : AADereferenceable {
4987 AADereferenceableImpl(
const IRPosition &IRP, Attributor &
A)
4988 : AADereferenceable(IRP,
A) {}
4989 using StateType = DerefState;
4993 Value &
V = *getAssociatedValue().stripPointerCasts();
4995 A.getAttrs(getIRPosition(),
4996 {Attribute::Dereferenceable, Attribute::DereferenceableOrNull},
4999 takeKnownDerefBytesMaximum(Attr.getValueAsInt());
5002 bool IsKnownNonNull;
5004 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNonNull);
5007 takeKnownDerefBytesMaximum(
V.getPointerDereferenceableBytes(
5008 A.getDataLayout(), CanBeNull,
nullptr));
5010 if (Instruction *CtxI = getCtxI())
5011 followUsesInMBEC(*
this,
A, getState(), *CtxI);
5016 StateType &getState()
override {
return *
this; }
5017 const StateType &getState()
const override {
return *
this; }
5021 void addAccessedBytesForUse(Attributor &
A,
const Use *U,
const Instruction *
I,
5022 DerefState &State) {
5023 const Value *UseV =
U->get();
5028 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
I->isVolatile())
5033 Loc->Ptr,
Offset,
A.getDataLayout(),
true);
5034 if (
Base &&
Base == &getAssociatedValue())
5035 State.addAccessedBytes(
Offset, Loc->Size.getValue());
5039 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5040 AADereferenceable::StateType &State) {
5041 bool IsNonNull =
false;
5042 bool TrackUse =
false;
5043 int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
5044 A, *
this, getAssociatedValue(), U,
I, IsNonNull, TrackUse);
5045 LLVM_DEBUG(
dbgs() <<
"[AADereferenceable] Deref bytes: " << DerefBytes
5046 <<
" for instruction " << *
I <<
"\n");
5048 addAccessedBytesForUse(
A, U,
I, State);
5049 State.takeKnownDerefBytesMaximum(DerefBytes);
5056 bool IsKnownNonNull;
5058 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5059 if (IsAssumedNonNull &&
5060 A.hasAttr(getIRPosition(), Attribute::DereferenceableOrNull)) {
5061 A.removeAttrs(getIRPosition(), {Attribute::DereferenceableOrNull});
5062 return ChangeStatus::CHANGED;
5067 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5068 SmallVectorImpl<Attribute> &Attrs)
const override {
5070 bool IsKnownNonNull;
5072 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5073 if (IsAssumedNonNull)
5074 Attrs.emplace_back(Attribute::getWithDereferenceableBytes(
5075 Ctx, getAssumedDereferenceableBytes()));
5077 Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes(
5078 Ctx, getAssumedDereferenceableBytes()));
5082 const std::string getAsStr(Attributor *
A)
const override {
5083 if (!getAssumedDereferenceableBytes())
5084 return "unknown-dereferenceable";
5085 bool IsKnownNonNull;
5086 bool IsAssumedNonNull =
false;
5089 *
A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5090 return std::string(
"dereferenceable") +
5091 (IsAssumedNonNull ?
"" :
"_or_null") +
5092 (isAssumedGlobal() ?
"_globally" :
"") +
"<" +
5093 std::to_string(getKnownDereferenceableBytes()) +
"-" +
5094 std::to_string(getAssumedDereferenceableBytes()) +
">" +
5095 (!
A ?
" [non-null is unknown]" :
"");
5100struct AADereferenceableFloating : AADereferenceableImpl {
5101 AADereferenceableFloating(
const IRPosition &IRP, Attributor &
A)
5102 : AADereferenceableImpl(IRP,
A) {}
5107 bool UsedAssumedInformation =
false;
5109 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
5111 Values.push_back({getAssociatedValue(), getCtxI()});
5114 Stripped =
Values.size() != 1 ||
5115 Values.front().getValue() != &getAssociatedValue();
5118 const DataLayout &
DL =
A.getDataLayout();
5121 auto VisitValueCB = [&](
const Value &
V) ->
bool {
5123 DL.getIndexSizeInBits(
V.getType()->getPointerAddressSpace());
5124 APInt
Offset(IdxWidth, 0);
5129 const auto *AA =
A.getAAFor<AADereferenceable>(
5131 int64_t DerefBytes = 0;
5132 if (!AA || (!Stripped &&
this == AA)) {
5136 DerefBytes =
Base->getPointerDereferenceableBytes(
5137 DL, CanBeNull,
nullptr);
5138 T.GlobalState.indicatePessimisticFixpoint();
5141 DerefBytes =
DS.DerefBytesState.getAssumed();
5142 T.GlobalState &=
DS.GlobalState;
5148 int64_t OffsetSExt =
Offset.getSExtValue();
5152 T.takeAssumedDerefBytesMinimum(
5153 std::max(int64_t(0), DerefBytes - OffsetSExt));
5158 T.takeKnownDerefBytesMaximum(
5159 std::max(int64_t(0), DerefBytes - OffsetSExt));
5160 T.indicatePessimisticFixpoint();
5161 }
else if (OffsetSExt > 0) {
5167 T.indicatePessimisticFixpoint();
5171 return T.isValidState();
5174 for (
const auto &VAC :
Values)
5175 if (!VisitValueCB(*VAC.
getValue()))
5176 return indicatePessimisticFixpoint();
5182 void trackStatistics()
const override {
5188struct AADereferenceableReturned final
5189 : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl> {
5191 AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl>;
5192 AADereferenceableReturned(
const IRPosition &IRP, Attributor &
A)
5196 void trackStatistics()
const override {
5202struct AADereferenceableArgument final
5203 : AAArgumentFromCallSiteArguments<AADereferenceable,
5204 AADereferenceableImpl> {
5206 AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl>;
5207 AADereferenceableArgument(
const IRPosition &IRP, Attributor &
A)
5211 void trackStatistics()
const override {
5217struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {
5218 AADereferenceableCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5219 : AADereferenceableFloating(IRP,
A) {}
5222 void trackStatistics()
const override {
5228struct AADereferenceableCallSiteReturned final
5229 : AACalleeToCallSite<AADereferenceable, AADereferenceableImpl> {
5230 using Base = AACalleeToCallSite<AADereferenceable, AADereferenceableImpl>;
5231 AADereferenceableCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5235 void trackStatistics()
const override {
5245static unsigned getKnownAlignForUse(Attributor &
A, AAAlign &QueryingAA,
5246 Value &AssociatedValue,
const Use *U,
5247 const Instruction *
I,
bool &TrackUse) {
5256 if (
GEP->hasAllConstantIndices())
5261 switch (
II->getIntrinsicID()) {
5262 case Intrinsic::ptrmask: {
5264 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5266 const auto *AlignAA =
A.getAAFor<AAAlign>(
5268 if (ConstVals && ConstVals->isValidState() && ConstVals->isAtFixpoint()) {
5269 unsigned ShiftValue = std::min(ConstVals->getAssumedMinTrailingZeros(),
5271 Align ConstAlign(UINT64_C(1) << ShiftValue);
5272 if (ConstAlign >= AlignAA->getKnownAlign())
5273 return Align(1).value();
5276 return AlignAA->getKnownAlign().
value();
5279 case Intrinsic::amdgcn_make_buffer_rsrc: {
5280 const auto *AlignAA =
A.getAAFor<AAAlign>(
5283 return AlignAA->getKnownAlign().
value();
5301 MA = MaybeAlign(AlignAA->getKnownAlign());
5304 const DataLayout &
DL =
A.getDataLayout();
5305 const Value *UseV =
U->get();
5307 if (
SI->getPointerOperand() == UseV)
5308 MA =
SI->getAlign();
5310 if (LI->getPointerOperand() == UseV)
5311 MA = LI->getAlign();
5313 if (AI->getPointerOperand() == UseV)
5314 MA = AI->getAlign();
5316 if (AI->getPointerOperand() == UseV)
5317 MA = AI->getAlign();
5323 unsigned Alignment = MA->value();
5327 if (
Base == &AssociatedValue) {
5332 uint32_t
gcd = std::gcd(uint32_t(
abs((int32_t)
Offset)), Alignment);
5340struct AAAlignImpl : AAAlign {
5341 AAAlignImpl(
const IRPosition &IRP, Attributor &
A) : AAAlign(IRP,
A) {}
5346 A.getAttrs(getIRPosition(), {Attribute::Alignment},
Attrs);
5348 takeKnownMaximum(Attr.getValueAsInt());
5350 Value &
V = *getAssociatedValue().stripPointerCasts();
5351 takeKnownMaximum(
V.getPointerAlignment(
A.getDataLayout()).value());
5353 if (Instruction *CtxI = getCtxI())
5354 followUsesInMBEC(*
this,
A, getState(), *CtxI);
5362 Value &AssociatedValue = getAssociatedValue();
5364 return ChangeStatus::UNCHANGED;
5366 for (
const Use &U : AssociatedValue.
uses()) {
5368 if (
SI->getPointerOperand() == &AssociatedValue)
5369 if (
SI->getAlign() < getAssumedAlign()) {
5371 "Number of times alignment added to a store");
5372 SI->setAlignment(getAssumedAlign());
5373 InstrChanged = ChangeStatus::CHANGED;
5376 if (LI->getPointerOperand() == &AssociatedValue)
5377 if (LI->getAlign() < getAssumedAlign()) {
5378 LI->setAlignment(getAssumedAlign());
5380 "Number of times alignment added to a load");
5381 InstrChanged = ChangeStatus::CHANGED;
5384 if (RMW->getPointerOperand() == &AssociatedValue) {
5385 if (RMW->getAlign() < getAssumedAlign()) {
5387 "Number of times alignment added to atomicrmw");
5389 RMW->setAlignment(getAssumedAlign());
5390 InstrChanged = ChangeStatus::CHANGED;
5394 if (CAS->getPointerOperand() == &AssociatedValue) {
5395 if (CAS->getAlign() < getAssumedAlign()) {
5397 "Number of times alignment added to cmpxchg");
5398 CAS->setAlignment(getAssumedAlign());
5399 InstrChanged = ChangeStatus::CHANGED;
5407 Align InheritAlign =
5408 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5409 if (InheritAlign >= getAssumedAlign())
5410 return InstrChanged;
5411 return Changed | InstrChanged;
5419 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5420 SmallVectorImpl<Attribute> &Attrs)
const override {
5421 if (getAssumedAlign() > 1)
5423 Attribute::getWithAlignment(Ctx,
Align(getAssumedAlign())));
5427 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5428 AAAlign::StateType &State) {
5429 bool TrackUse =
false;
5431 unsigned int KnownAlign =
5432 getKnownAlignForUse(
A, *
this, getAssociatedValue(), U,
I, TrackUse);
5433 State.takeKnownMaximum(KnownAlign);
5439 const std::string getAsStr(Attributor *
A)
const override {
5440 return "align<" + std::to_string(getKnownAlign().value()) +
"-" +
5441 std::to_string(getAssumedAlign().value()) +
">";
5446struct AAAlignFloating : AAAlignImpl {
5447 AAAlignFloating(
const IRPosition &IRP, Attributor &
A) : AAAlignImpl(IRP,
A) {}
5451 const DataLayout &
DL =
A.getDataLayout();
5454 bool UsedAssumedInformation =
false;
5456 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
5458 Values.push_back({getAssociatedValue(), getCtxI()});
5461 Stripped =
Values.size() != 1 ||
5462 Values.front().getValue() != &getAssociatedValue();
5466 auto VisitValueCB = [&](
Value &
V) ->
bool {
5470 DepClassTy::REQUIRED);
5471 if (!AA || (!Stripped &&
this == AA)) {
5473 unsigned Alignment = 1;
5486 Alignment =
V.getPointerAlignment(
DL).value();
5489 T.takeKnownMaximum(Alignment);
5490 T.indicatePessimisticFixpoint();
5493 const AAAlign::StateType &
DS = AA->
getState();
5496 return T.isValidState();
5499 for (
const auto &VAC :
Values) {
5500 if (!VisitValueCB(*VAC.
getValue()))
5501 return indicatePessimisticFixpoint();
5514struct AAAlignReturned final
5515 : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {
5516 using Base = AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>;
5517 AAAlignReturned(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5524struct AAAlignArgument final
5525 : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {
5526 using Base = AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>;
5527 AAAlignArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5534 if (
A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))
5535 return ChangeStatus::UNCHANGED;
5536 return Base::manifest(
A);
5543struct AAAlignCallSiteArgument final : AAAlignFloating {
5544 AAAlignCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5545 : AAAlignFloating(IRP,
A) {}
5552 if (Argument *Arg = getAssociatedArgument())
5553 if (
A.getInfoCache().isInvolvedInMustTailCall(*Arg))
5554 return ChangeStatus::UNCHANGED;
5556 Align InheritAlign =
5557 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5558 if (InheritAlign >= getAssumedAlign())
5559 Changed = ChangeStatus::UNCHANGED;
5566 if (Argument *Arg = getAssociatedArgument()) {
5569 const auto *ArgAlignAA =
A.getAAFor<AAAlign>(
5572 takeKnownMaximum(ArgAlignAA->getKnownAlign().value());
5582struct AAAlignCallSiteReturned final
5583 : AACalleeToCallSite<AAAlign, AAAlignImpl> {
5584 using Base = AACalleeToCallSite<AAAlign, AAAlignImpl>;
5585 AAAlignCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5591 switch (
II->getIntrinsicID()) {
5592 case Intrinsic::ptrmask: {
5596 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5598 if (ConstVals && ConstVals->isValidState()) {
5599 unsigned ShiftValue =
5600 std::min(ConstVals->getAssumedMinTrailingZeros(),
5601 Value::MaxAlignmentExponent);
5602 Alignment =
Align(UINT64_C(1) << ShiftValue);
5606 const auto *AlignAA =
5608 DepClassTy::REQUIRED);
5610 Alignment = std::max(AlignAA->getAssumedAlign(), Alignment);
5617 std::min(this->getAssumedAlign(), Alignment).value());
5623 case Intrinsic::amdgcn_make_buffer_rsrc: {
5624 const auto *AlignAA =
5626 DepClassTy::REQUIRED);
5629 this->getState(), AlignAA->getAssumedAlign().
value());
5636 return Base::updateImpl(
A);
5645struct AANoReturnImpl :
public AANoReturn {
5646 AANoReturnImpl(
const IRPosition &IRP, Attributor &
A) : AANoReturn(IRP,
A) {}
5652 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
5657 const std::string getAsStr(Attributor *
A)
const override {
5658 return getAssumed() ?
"noreturn" :
"may-return";
5663 auto CheckForNoReturn = [](
Instruction &) {
return false; };
5664 bool UsedAssumedInformation =
false;
5665 if (!
A.checkForAllInstructions(CheckForNoReturn, *
this,
5666 {(unsigned)Instruction::Ret},
5667 UsedAssumedInformation))
5668 return indicatePessimisticFixpoint();
5669 return ChangeStatus::UNCHANGED;
5673struct AANoReturnFunction final : AANoReturnImpl {
5674 AANoReturnFunction(
const IRPosition &IRP, Attributor &
A)
5675 : AANoReturnImpl(IRP,
A) {}
5682struct AANoReturnCallSite final
5683 : AACalleeToCallSite<AANoReturn, AANoReturnImpl> {
5684 AANoReturnCallSite(
const IRPosition &IRP, Attributor &
A)
5685 : AACalleeToCallSite<AANoReturn, AANoReturnImpl>(IRP,
A) {}
5696struct AAInstanceInfoImpl :
public AAInstanceInfo {
5697 AAInstanceInfoImpl(
const IRPosition &IRP, Attributor &
A)
5698 : AAInstanceInfo(IRP,
A) {}
5702 Value &
V = getAssociatedValue();
5704 if (
C->isThreadDependent())
5705 indicatePessimisticFixpoint();
5707 indicateOptimisticFixpoint();
5713 indicateOptimisticFixpoint();
5718 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
5721 indicatePessimisticFixpoint();
5731 Value &
V = getAssociatedValue();
5734 Scope =
I->getFunction();
5737 if (!
Scope->hasLocalLinkage())
5741 return indicateOptimisticFixpoint();
5743 bool IsKnownNoRecurse;
5749 auto UsePred = [&](
const Use &
U,
bool &Follow) {
5764 if (!Callee || !
Callee->hasLocalLinkage())
5768 const auto *ArgInstanceInfoAA =
A.getAAFor<AAInstanceInfo>(
5770 DepClassTy::OPTIONAL);
5771 if (!ArgInstanceInfoAA ||
5772 !ArgInstanceInfoAA->isAssumedUniqueForAnalysis())
5777 A, *CB, *Scope, *
this,
nullptr,
5778 [Scope](
const Function &Fn) {
return &Fn !=
Scope; }))
5785 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
5787 auto *Ptr =
SI->getPointerOperand()->stripPointerCasts();
5795 if (!
A.checkForAllUses(UsePred, *
this, V,
true,
5796 DepClassTy::OPTIONAL,
5797 true, EquivalentUseCB))
5798 return indicatePessimisticFixpoint();
5804 const std::string getAsStr(Attributor *
A)
const override {
5805 return isAssumedUniqueForAnalysis() ?
"<unique [fAa]>" :
"<unknown>";
5809 void trackStatistics()
const override {}
5813struct AAInstanceInfoFloating : AAInstanceInfoImpl {
5814 AAInstanceInfoFloating(
const IRPosition &IRP, Attributor &
A)
5815 : AAInstanceInfoImpl(IRP,
A) {}
5819struct AAInstanceInfoArgument final : AAInstanceInfoFloating {
5820 AAInstanceInfoArgument(
const IRPosition &IRP, Attributor &
A)
5821 : AAInstanceInfoFloating(IRP,
A) {}
5825struct AAInstanceInfoCallSiteArgument final : AAInstanceInfoImpl {
5826 AAInstanceInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5827 : AAInstanceInfoImpl(IRP,
A) {}
5835 Argument *Arg = getAssociatedArgument();
5837 return indicatePessimisticFixpoint();
5840 A.getAAFor<AAInstanceInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
5842 return indicatePessimisticFixpoint();
5848struct AAInstanceInfoReturned final : AAInstanceInfoImpl {
5849 AAInstanceInfoReturned(
const IRPosition &IRP, Attributor &
A)
5850 : AAInstanceInfoImpl(IRP,
A) {
5866struct AAInstanceInfoCallSiteReturned final : AAInstanceInfoFloating {
5867 AAInstanceInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5868 : AAInstanceInfoFloating(IRP,
A) {}
5875 bool IgnoreSubsumingPositions) {
5876 assert(ImpliedAttributeKind == Attribute::Captures &&
5877 "Unexpected attribute kind");
5887 V.getType()->getPointerAddressSpace() == 0)) {
5892 A.getAttrs(IRP, {Attribute::Captures}, Attrs,
5902 {Attribute::Captures, Attribute::ByVal}, Attrs,
5940 bool NoThrow =
F.doesNotThrow();
5941 bool IsVoidReturn =
F.getReturnType()->isVoidTy();
5942 if (
ReadOnly && NoThrow && IsVoidReturn) {
5955 if (NoThrow && IsVoidReturn)
5960 if (!NoThrow || ArgNo < 0 ||
5961 !
F.getAttributes().hasAttrSomewhere(Attribute::Returned))
5964 for (
unsigned U = 0, E =
F.arg_size(); U < E; ++U)
5965 if (
F.hasParamAttribute(U, Attribute::Returned)) {
5966 if (U ==
unsigned(ArgNo))
5993 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5994 SmallVectorImpl<Attribute> &Attrs)
const override {
5995 if (!isAssumedNoCaptureMaybeReturned())
5998 if (isArgumentPosition()) {
5999 if (isAssumedNoCapture())
6000 Attrs.emplace_back(Attribute::get(Ctx, Attribute::Captures));
6002 Attrs.emplace_back(Attribute::get(Ctx,
"no-capture-maybe-returned"));
6007 const std::string getAsStr(Attributor *
A)
const override {
6008 if (isKnownNoCapture())
6009 return "known not-captured";
6010 if (isAssumedNoCapture())
6011 return "assumed not-captured";
6012 if (isKnownNoCaptureMaybeReturned())
6013 return "known not-captured-maybe-returned";
6014 if (isAssumedNoCaptureMaybeReturned())
6015 return "assumed not-captured-maybe-returned";
6016 return "assumed-captured";
6021 bool checkUse(Attributor &
A, AANoCapture::StateType &State,
const Use &U,
6024 LLVM_DEBUG(
dbgs() <<
"[AANoCapture] Check use: " << *
U.get() <<
" in "
6030 return isCapturedIn(State,
true,
true,
6037 return isCapturedIn(State,
true,
true,
6043 return isCapturedIn(State,
false,
false,
6045 return isCapturedIn(State,
true,
true,
6053 return isCapturedIn(State,
true,
true,
6060 bool IsKnownNoCapture;
6061 const AANoCapture *ArgNoCaptureAA =
nullptr;
6063 A,
this, CSArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6065 if (IsAssumedNoCapture)
6066 return isCapturedIn(State,
false,
false,
6070 return isCapturedIn(State,
false,
false,
6075 return isCapturedIn(State,
true,
true,
6082 static bool isCapturedIn(AANoCapture::StateType &State,
bool CapturedInMem,
6083 bool CapturedInInt,
bool CapturedInRet) {
6084 LLVM_DEBUG(
dbgs() <<
" - captures [Mem " << CapturedInMem <<
"|Int "
6085 << CapturedInInt <<
"|Ret " << CapturedInRet <<
"]\n");
6097 const IRPosition &IRP = getIRPosition();
6101 return indicatePessimisticFixpoint();
6108 return indicatePessimisticFixpoint();
6116 T.addKnownBits(NOT_CAPTURED_IN_MEM);
6118 addKnownBits(NOT_CAPTURED_IN_MEM);
6125 auto CheckReturnedArgs = [&](
bool &UsedAssumedInformation) {
6129 UsedAssumedInformation))
6131 bool SeenConstant =
false;
6132 for (
const AA::ValueAndContext &VAC :
Values) {
6136 SeenConstant =
true;
6138 VAC.
getValue() == getAssociatedArgument())
6144 bool IsKnownNoUnwind;
6147 bool IsVoidTy =
F->getReturnType()->isVoidTy();
6148 bool UsedAssumedInformation =
false;
6149 if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {
6150 T.addKnownBits(NOT_CAPTURED_IN_RET);
6151 if (
T.isKnown(NOT_CAPTURED_IN_MEM))
6153 if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {
6154 addKnownBits(NOT_CAPTURED_IN_RET);
6155 if (isKnown(NOT_CAPTURED_IN_MEM))
6156 return indicateOptimisticFixpoint();
6161 auto UseCheck = [&](
const Use &
U,
bool &Follow) ->
bool {
6170 return checkUse(
A,
T, U, Follow);
6173 if (!
A.checkForAllUses(UseCheck, *
this, *V))
6174 return indicatePessimisticFixpoint();
6177 auto Assumed = S.getAssumed();
6178 S.intersectAssumedBits(
T.getAssumed());
6179 if (!isAssumedNoCaptureMaybeReturned())
6180 return indicatePessimisticFixpoint();
6186struct AANoCaptureArgument final : AANoCaptureImpl {
6187 AANoCaptureArgument(
const IRPosition &IRP, Attributor &
A)
6188 : AANoCaptureImpl(IRP,
A) {}
6195struct AANoCaptureCallSiteArgument final : AANoCaptureImpl {
6196 AANoCaptureCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6197 : AANoCaptureImpl(IRP,
A) {}
6205 Argument *Arg = getAssociatedArgument();
6207 return indicatePessimisticFixpoint();
6209 bool IsKnownNoCapture;
6210 const AANoCapture *ArgAA =
nullptr;
6212 A,
this, ArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6214 return ChangeStatus::UNCHANGED;
6216 return indicatePessimisticFixpoint();
6221 void trackStatistics()
const override {
6227struct AANoCaptureFloating final : AANoCaptureImpl {
6228 AANoCaptureFloating(
const IRPosition &IRP, Attributor &
A)
6229 : AANoCaptureImpl(IRP,
A) {}
6232 void trackStatistics()
const override {
6238struct AANoCaptureReturned final : AANoCaptureImpl {
6239 AANoCaptureReturned(
const IRPosition &IRP, Attributor &
A)
6240 : AANoCaptureImpl(IRP,
A) {
6255 void trackStatistics()
const override {}
6259struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {
6260 AANoCaptureCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6261 : AANoCaptureImpl(IRP,
A) {}
6267 determineFunctionCaptureCapabilities(getIRPosition(), *
F, *
this);
6271 void trackStatistics()
const override {
6288 dbgs() <<
"[ValueSimplify] is assumed to be "
6291 dbgs() <<
"[ValueSimplify] is assumed to be <none>\n";
6303 if (getAssociatedValue().
getType()->isVoidTy())
6304 indicatePessimisticFixpoint();
6305 if (
A.hasSimplificationCallback(getIRPosition()))
6306 indicatePessimisticFixpoint();
6310 const std::string getAsStr(Attributor *
A)
const override {
6312 dbgs() <<
"SAV: " << (bool)SimplifiedAssociatedValue <<
" ";
6313 if (SimplifiedAssociatedValue && *SimplifiedAssociatedValue)
6314 dbgs() <<
"SAV: " << **SimplifiedAssociatedValue <<
" ";
6316 return isValidState() ? (isAtFixpoint() ?
"simplified" :
"maybe-simple")
6321 void trackStatistics()
const override {}
6324 std::optional<Value *>
6325 getAssumedSimplifiedValue(Attributor &
A)
const override {
6326 return SimplifiedAssociatedValue;
6333 static Value *ensureType(Attributor &
A,
Value &V,
Type &Ty, Instruction *CtxI,
6337 if (CtxI &&
V.getType()->canLosslesslyBitCastTo(&Ty))
6339 : BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6348 static Value *reproduceInst(Attributor &
A,
6349 const AbstractAttribute &QueryingAA,
6350 Instruction &
I,
Type &Ty, Instruction *CtxI,
6352 assert(CtxI &&
"Cannot reproduce an instruction without context!");
6353 if (
Check && (
I.mayReadFromMemory() ||
6358 Value *NewOp = reproduceValue(
A, QueryingAA, *
Op, Ty, CtxI,
Check, VMap);
6360 assert(
Check &&
"Manifest of new value unexpectedly failed!");
6382 static Value *reproduceValue(Attributor &
A,
6383 const AbstractAttribute &QueryingAA,
Value &V,
6384 Type &Ty, Instruction *CtxI,
bool Check,
6386 if (
const auto &NewV = VMap.
lookup(&V))
6388 bool UsedAssumedInformation =
false;
6389 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
6391 if (!SimpleV.has_value())
6395 EffectiveV = *SimpleV;
6400 return ensureType(
A, *EffectiveV, Ty, CtxI,
Check);
6402 if (
Value *NewV = reproduceInst(
A, QueryingAA, *
I, Ty, CtxI,
Check, VMap))
6403 return ensureType(
A, *NewV, Ty, CtxI,
Check);
6409 Value *manifestReplacementValue(Attributor &
A, Instruction *CtxI)
const {
6410 Value *NewV = SimplifiedAssociatedValue
6411 ? *SimplifiedAssociatedValue
6413 if (NewV && NewV != &getAssociatedValue()) {
6417 if (reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6419 return reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6427 bool checkAndUpdate(Attributor &
A,
const AbstractAttribute &QueryingAA,
6428 const IRPosition &IRP,
bool Simplify =
true) {
6429 bool UsedAssumedInformation =
false;
6432 QueryingValueSimplified =
A.getAssumedSimplified(
6434 return unionAssumed(QueryingValueSimplified);
6438 template <
typename AAType>
bool askSimplifiedValueFor(Attributor &
A) {
6439 if (!getAssociatedValue().
getType()->isIntegerTy())
6444 A.getAAFor<AAType>(*
this, getIRPosition(), DepClassTy::NONE);
6448 std::optional<Constant *> COpt = AA->getAssumedConstant(
A);
6451 SimplifiedAssociatedValue = std::nullopt;
6452 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6455 if (
auto *
C = *COpt) {
6456 SimplifiedAssociatedValue =
C;
6457 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6463 bool askSimplifiedValueForOtherAAs(Attributor &
A) {
6464 if (askSimplifiedValueFor<AAValueConstantRange>(
A))
6466 if (askSimplifiedValueFor<AAPotentialConstantValues>(
A))
6474 for (
auto &U : getAssociatedValue().uses()) {
6479 IP =
PHI->getIncomingBlock(U)->getTerminator();
6480 if (
auto *NewV = manifestReplacementValue(
A, IP)) {
6482 <<
" -> " << *NewV <<
" :: " << *
this <<
"\n");
6483 if (
A.changeUseAfterManifest(U, *NewV))
6484 Changed = ChangeStatus::CHANGED;
6488 return Changed | AAValueSimplify::manifest(
A);
6493 SimplifiedAssociatedValue = &getAssociatedValue();
6494 return AAValueSimplify::indicatePessimisticFixpoint();
6498struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
6499 AAValueSimplifyArgument(
const IRPosition &IRP, Attributor &
A)
6500 : AAValueSimplifyImpl(IRP,
A) {}
6503 AAValueSimplifyImpl::initialize(
A);
6504 if (
A.hasAttr(getIRPosition(),
6505 {Attribute::InAlloca, Attribute::Preallocated,
6506 Attribute::StructRet, Attribute::Nest, Attribute::ByVal},
6508 indicatePessimisticFixpoint();
6515 Argument *Arg = getAssociatedArgument();
6521 return indicatePessimisticFixpoint();
6524 auto Before = SimplifiedAssociatedValue;
6526 auto PredForCallSite = [&](AbstractCallSite ACS) {
6527 const IRPosition &ACSArgPos =
6538 bool UsedAssumedInformation =
false;
6539 std::optional<Constant *> SimpleArgOp =
6540 A.getAssumedConstant(ACSArgPos, *
this, UsedAssumedInformation);
6547 return unionAssumed(*SimpleArgOp);
6552 bool UsedAssumedInformation =
false;
6553 if (hasCallBaseContext() &&
6554 getCallBaseContext()->getCalledOperand() == Arg->
getParent())
6556 AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
6558 Success =
A.checkForAllCallSites(PredForCallSite, *
this,
true,
6559 UsedAssumedInformation);
6562 if (!askSimplifiedValueForOtherAAs(
A))
6563 return indicatePessimisticFixpoint();
6566 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6567 : ChangeStatus ::CHANGED;
6571 void trackStatistics()
const override {
6576struct AAValueSimplifyReturned : AAValueSimplifyImpl {
6577 AAValueSimplifyReturned(
const IRPosition &IRP, Attributor &
A)
6578 : AAValueSimplifyImpl(IRP,
A) {}
6581 std::optional<Value *>
6582 getAssumedSimplifiedValue(Attributor &
A)
const override {
6583 if (!isValidState())
6585 return SimplifiedAssociatedValue;
6590 auto Before = SimplifiedAssociatedValue;
6594 return checkAndUpdate(
6599 bool UsedAssumedInformation =
false;
6600 if (!
A.checkForAllInstructions(ReturnInstCB, *
this, {Instruction::Ret},
6601 UsedAssumedInformation))
6602 if (!askSimplifiedValueForOtherAAs(
A))
6603 return indicatePessimisticFixpoint();
6606 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6607 : ChangeStatus ::CHANGED;
6613 return ChangeStatus::UNCHANGED;
6617 void trackStatistics()
const override {
6622struct AAValueSimplifyFloating : AAValueSimplifyImpl {
6623 AAValueSimplifyFloating(
const IRPosition &IRP, Attributor &
A)
6624 : AAValueSimplifyImpl(IRP,
A) {}
6628 AAValueSimplifyImpl::initialize(
A);
6629 Value &
V = getAnchorValue();
6633 indicatePessimisticFixpoint();
6638 auto Before = SimplifiedAssociatedValue;
6639 if (!askSimplifiedValueForOtherAAs(
A))
6640 return indicatePessimisticFixpoint();
6643 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6644 : ChangeStatus ::CHANGED;
6648 void trackStatistics()
const override {
6653struct AAValueSimplifyFunction : AAValueSimplifyImpl {
6654 AAValueSimplifyFunction(
const IRPosition &IRP, Attributor &
A)
6655 : AAValueSimplifyImpl(IRP,
A) {}
6659 SimplifiedAssociatedValue =
nullptr;
6660 indicateOptimisticFixpoint();
6665 "AAValueSimplify(Function|CallSite)::updateImpl will not be called");
6668 void trackStatistics()
const override {
6673struct AAValueSimplifyCallSite : AAValueSimplifyFunction {
6674 AAValueSimplifyCallSite(
const IRPosition &IRP, Attributor &
A)
6675 : AAValueSimplifyFunction(IRP,
A) {}
6677 void trackStatistics()
const override {
6682struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl {
6683 AAValueSimplifyCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6684 : AAValueSimplifyImpl(IRP,
A) {}
6687 AAValueSimplifyImpl::initialize(
A);
6688 Function *Fn = getAssociatedFunction();
6689 assert(Fn &&
"Did expect an associted function");
6690 for (Argument &Arg : Fn->
args()) {
6695 checkAndUpdate(
A, *
this, IRP))
6696 indicateOptimisticFixpoint();
6698 indicatePessimisticFixpoint();
6706 return indicatePessimisticFixpoint();
6709 void trackStatistics()
const override {
6714struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
6715 AAValueSimplifyCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6716 : AAValueSimplifyFloating(IRP,
A) {}
6722 auto *FloatAA =
A.lookupAAFor<AAValueSimplify>(
6724 if (FloatAA && FloatAA->getState().isValidState())
6727 if (
auto *NewV = manifestReplacementValue(
A, getCtxI())) {
6729 ->getArgOperandUse(getCallSiteArgNo());
6730 if (
A.changeUseAfterManifest(U, *NewV))
6731 Changed = ChangeStatus::CHANGED;
6734 return Changed | AAValueSimplify::manifest(
A);
6737 void trackStatistics()
const override {
6745struct AAHeapToStackFunction final :
public AAHeapToStack {
6747 static bool isGlobalizedLocal(
const CallBase &CB) {
6749 return A.
isValid() &&
A.getValueAsString() ==
"__kmpc_alloc_shared";
6752 struct AllocationInfo {
6757 bool IsGlobalizedLocal =
false;
6764 } Status = STACK_DUE_TO_USE;
6768 bool HasPotentiallyFreeingUnknownUses =
false;
6772 bool MoveAllocaIntoEntry =
true;
6775 SmallSetVector<CallBase *, 1> PotentialFreeCalls{};
6778 struct DeallocationInfo {
6786 bool MightFreeUnknownObjects =
false;
6789 SmallSetVector<CallBase *, 1> PotentialAllocationCalls{};
6792 AAHeapToStackFunction(
const IRPosition &IRP, Attributor &
A)
6793 : AAHeapToStack(IRP,
A) {}
6795 ~AAHeapToStackFunction()
override {
6798 for (
auto &It : AllocationInfos)
6799 It.second->~AllocationInfo();
6800 for (
auto &It : DeallocationInfos)
6801 It.second->~DeallocationInfo();
6805 AAHeapToStack::initialize(
A);
6808 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6815 DeallocationInfos[CB] =
new (
A.Allocator) DeallocationInfo{CB, FreedOp};
6822 auto *I8Ty = Type::getInt8Ty(CB->
getParent()->getContext());
6824 AllocationInfo *AI =
new (
A.Allocator) AllocationInfo{CB};
6825 AllocationInfos[CB] = AI;
6826 AI->IsGlobalizedLocal = isGlobalizedLocal(*CB);
6832 bool UsedAssumedInformation =
false;
6833 bool Success =
A.checkForAllCallLikeInstructions(
6834 AllocationIdentifierCB, *
this, UsedAssumedInformation,
6838 assert(
Success &&
"Did not expect the call base visit callback to fail!");
6841 [](
const IRPosition &,
const AbstractAttribute *,
6842 bool &) -> std::optional<Value *> {
return nullptr; };
6843 for (
const auto &It : AllocationInfos)
6846 for (
const auto &It : DeallocationInfos)
6851 const std::string getAsStr(Attributor *
A)
const override {
6852 unsigned NumH2SMallocs = 0, NumInvalidMallocs = 0;
6853 for (
const auto &It : AllocationInfos) {
6854 if (It.second->Status == AllocationInfo::INVALID)
6855 ++NumInvalidMallocs;
6859 return "[H2S] Mallocs Good/Bad: " + std::to_string(NumH2SMallocs) +
"/" +
6860 std::to_string(NumInvalidMallocs);
6864 void trackStatistics()
const override {
6866 MallocCalls, Function,
6867 "Number of malloc/calloc/aligned_alloc calls converted to allocas");
6868 for (
const auto &It : AllocationInfos)
6869 if (It.second->Status != AllocationInfo::INVALID)
6873 bool isAssumedHeapToStack(
const CallBase &CB)
const override {
6875 if (AllocationInfo *AI =
6876 AllocationInfos.lookup(
const_cast<CallBase *
>(&CB)))
6877 return AI->Status != AllocationInfo::INVALID;
6881 bool isAssumedHeapToStackRemovedFree(CallBase &CB)
const override {
6882 if (!isValidState())
6885 for (
const auto &It : AllocationInfos) {
6886 AllocationInfo &AI = *It.second;
6887 if (AI.Status == AllocationInfo::INVALID)
6890 if (AI.PotentialFreeCalls.count(&CB))
6898 assert(getState().isValidState() &&
6899 "Attempted to manifest an invalid state!");
6903 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6905 for (
auto &It : AllocationInfos) {
6906 AllocationInfo &AI = *It.second;
6907 if (AI.Status == AllocationInfo::INVALID)
6910 for (CallBase *FreeCall : AI.PotentialFreeCalls) {
6911 LLVM_DEBUG(
dbgs() <<
"H2S: Removing free call: " << *FreeCall <<
"\n");
6912 A.deleteAfterManifest(*FreeCall);
6913 HasChanged = ChangeStatus::CHANGED;
6916 LLVM_DEBUG(
dbgs() <<
"H2S: Removing malloc-like call: " << *AI.CB
6919 auto Remark = [&](OptimizationRemark
OR) {
6920 if (AI.IsGlobalizedLocal)
6921 return OR <<
"Moving globalized variable to the stack.";
6922 return OR <<
"Moving memory allocation from the heap to the stack.";
6924 if (AI.IsGlobalizedLocal)
6925 A.emitRemark<OptimizationRemark>(AI.CB,
"OMP110",
Remark);
6927 A.emitRemark<OptimizationRemark>(AI.CB,
"HeapToStack",
Remark);
6929 const DataLayout &
DL =
A.getInfoCache().getDL();
6931 std::optional<APInt> SizeAPI =
getSize(
A, *
this, AI);
6933 Size = ConstantInt::get(AI.CB->getContext(), *SizeAPI);
6935 LLVMContext &Ctx = AI.CB->getContext();
6936 ObjectSizeOpts Opts;
6937 ObjectSizeOffsetEvaluator Eval(
DL, TLI, Ctx, Opts);
6938 SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);
6945 ?
F->getEntryBlock().begin()
6946 : AI.CB->getIterator();
6949 if (MaybeAlign RetAlign = AI.CB->getRetAlign())
6950 Alignment = std::max(Alignment, *RetAlign);
6952 std::optional<APInt> AlignmentAPI = getAPInt(
A, *
this, *Align);
6953 assert(AlignmentAPI && AlignmentAPI->getZExtValue() > 0 &&
6954 "Expected an alignment during manifest!");
6956 std::max(Alignment,
assumeAligned(AlignmentAPI->getZExtValue()));
6960 unsigned AS =
DL.getAllocaAddrSpace();
6962 new AllocaInst(Type::getInt8Ty(
F->getContext()), AS,
Size, Alignment,
6963 AI.CB->getName() +
".h2s", IP);
6965 if (Alloca->
getType() != AI.CB->getType())
6966 Alloca = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6967 Alloca, AI.CB->getType(),
"malloc_cast", AI.CB->getIterator());
6969 auto *I8Ty = Type::getInt8Ty(
F->getContext());
6972 "Must be able to materialize initial memory state of allocation");
6977 auto *NBB =
II->getNormalDest();
6979 A.deleteAfterManifest(*AI.CB);
6981 A.deleteAfterManifest(*AI.CB);
6990 Builder.CreateMemSet(Alloca, InitVal,
Size, std::nullopt);
6992 HasChanged = ChangeStatus::CHANGED;
6998 std::optional<APInt> getAPInt(Attributor &
A,
const AbstractAttribute &AA,
7000 bool UsedAssumedInformation =
false;
7001 std::optional<Constant *> SimpleV =
7002 A.getAssumedConstant(V, AA, UsedAssumedInformation);
7004 return APInt(64, 0);
7006 return CI->getValue();
7007 return std::nullopt;
7010 std::optional<APInt>
getSize(Attributor &
A,
const AbstractAttribute &AA,
7011 AllocationInfo &AI) {
7012 auto Mapper = [&](
const Value *
V) ->
const Value * {
7013 bool UsedAssumedInformation =
false;
7014 if (std::optional<Constant *> SimpleV =
7015 A.getAssumedConstant(*V, AA, UsedAssumedInformation))
7022 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
7028 MapVector<CallBase *, AllocationInfo *> AllocationInfos;
7032 MapVector<CallBase *, DeallocationInfo *> DeallocationInfos;
7037ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &
A) {
7040 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
7042 const auto *LivenessAA =
7045 MustBeExecutedContextExplorer *Explorer =
7046 A.getInfoCache().getMustBeExecutedContextExplorer();
7048 bool StackIsAccessibleByOtherThreads =
7049 A.getInfoCache().stackIsAccessibleByOtherThreads();
7052 A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(*F);
7053 std::optional<bool> MayContainIrreducibleControl;
7055 if (&
F->getEntryBlock() == &BB)
7057 if (!MayContainIrreducibleControl.has_value())
7059 if (*MayContainIrreducibleControl)
7068 bool HasUpdatedFrees =
false;
7070 auto UpdateFrees = [&]() {
7071 HasUpdatedFrees =
true;
7073 for (
auto &It : DeallocationInfos) {
7074 DeallocationInfo &DI = *It.second;
7077 if (DI.MightFreeUnknownObjects)
7081 bool UsedAssumedInformation =
false;
7082 if (
A.isAssumedDead(*DI.CB,
this, LivenessAA, UsedAssumedInformation,
7089 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown underlying object for free!\n");
7090 DI.MightFreeUnknownObjects =
true;
7103 DI.MightFreeUnknownObjects =
true;
7107 AllocationInfo *AI = AllocationInfos.lookup(ObjCB);
7109 LLVM_DEBUG(
dbgs() <<
"[H2S] Free of a non-allocation object: " << *Obj
7111 DI.MightFreeUnknownObjects =
true;
7115 DI.PotentialAllocationCalls.insert(ObjCB);
7119 auto FreeCheck = [&](AllocationInfo &AI) {
7123 if (!StackIsAccessibleByOtherThreads) {
7128 dbgs() <<
"[H2S] found an escaping use, stack is not accessible by "
7129 "other threads and function is not nosync:\n");
7133 if (!HasUpdatedFrees)
7137 if (AI.PotentialFreeCalls.size() != 1) {
7139 << AI.PotentialFreeCalls.size() <<
"\n");
7142 CallBase *UniqueFree = *AI.PotentialFreeCalls.begin();
7143 DeallocationInfo *DI = DeallocationInfos.lookup(UniqueFree);
7146 dbgs() <<
"[H2S] unique free call was not known as deallocation call "
7147 << *UniqueFree <<
"\n");
7150 if (DI->MightFreeUnknownObjects) {
7152 dbgs() <<
"[H2S] unique free call might free unknown allocations\n");
7155 if (DI->PotentialAllocationCalls.empty())
7157 if (DI->PotentialAllocationCalls.size() > 1) {
7159 << DI->PotentialAllocationCalls.size()
7160 <<
" different allocations\n");
7163 if (*DI->PotentialAllocationCalls.begin() != AI.CB) {
7166 <<
"[H2S] unique free call not known to free this allocation but "
7167 << **DI->PotentialAllocationCalls.begin() <<
"\n");
7172 if (!AI.IsGlobalizedLocal) {
7174 if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
7175 LLVM_DEBUG(
dbgs() <<
"[H2S] unique free call might not be executed "
7176 "with the allocation "
7177 << *UniqueFree <<
"\n");
7184 auto UsesCheck = [&](AllocationInfo &AI) {
7185 bool ValidUsesOnly =
true;
7187 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
7192 if (
SI->getValueOperand() ==
U.get()) {
7194 <<
"[H2S] escaping store to memory: " << *UserI <<
"\n");
7195 ValidUsesOnly =
false;
7204 if (DeallocationInfos.count(CB)) {
7205 AI.PotentialFreeCalls.insert(CB);
7212 bool IsKnownNoCapture;
7221 if (!IsAssumedNoCapture ||
7222 (!AI.IsGlobalizedLocal && !IsAssumedNoFree)) {
7223 AI.HasPotentiallyFreeingUnknownUses |= !IsAssumedNoFree;
7226 auto Remark = [&](OptimizationRemarkMissed ORM) {
7228 <<
"Could not move globalized variable to the stack. "
7229 "Variable is potentially captured in call. Mark "
7230 "parameter as `__attribute__((noescape))` to override.";
7233 if (ValidUsesOnly && AI.IsGlobalizedLocal)
7234 A.emitRemark<OptimizationRemarkMissed>(CB,
"OMP113",
Remark);
7237 ValidUsesOnly =
false;
7250 ValidUsesOnly =
false;
7253 if (!
A.checkForAllUses(Pred, *
this, *AI.CB,
false,
7255 [&](
const Use &OldU,
const Use &NewU) {
7256 auto *SI = dyn_cast<StoreInst>(OldU.getUser());
7257 return !SI || StackIsAccessibleByOtherThreads ||
7258 AA::isAssumedThreadLocalObject(
7259 A, *SI->getPointerOperand(), *this);
7262 return ValidUsesOnly;
7267 for (
auto &It : AllocationInfos) {
7268 AllocationInfo &AI = *It.second;
7269 if (AI.Status == AllocationInfo::INVALID)
7273 std::optional<APInt> APAlign = getAPInt(
A, *
this, *Align);
7277 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown allocation alignment: " << *AI.CB
7279 AI.Status = AllocationInfo::INVALID;
7284 !APAlign->isPowerOf2()) {
7285 LLVM_DEBUG(
dbgs() <<
"[H2S] Invalid allocation alignment: " << APAlign
7287 AI.Status = AllocationInfo::INVALID;
7298 dbgs() <<
"[H2S] Unknown allocation size: " << *AI.CB <<
"\n";
7300 dbgs() <<
"[H2S] Allocation size too large: " << *AI.CB <<
" vs. "
7304 AI.Status = AllocationInfo::INVALID;
7310 switch (AI.Status) {
7311 case AllocationInfo::STACK_DUE_TO_USE:
7314 AI.Status = AllocationInfo::STACK_DUE_TO_FREE;
7316 case AllocationInfo::STACK_DUE_TO_FREE:
7319 AI.Status = AllocationInfo::INVALID;
7322 case AllocationInfo::INVALID:
7329 bool IsGlobalizedLocal = AI.IsGlobalizedLocal;
7330 if (AI.MoveAllocaIntoEntry &&
7331 (!
Size.has_value() ||
7332 (!IsGlobalizedLocal && IsInLoop(*AI.CB->getParent()))))
7333 AI.MoveAllocaIntoEntry =
false;
7342struct AAPrivatizablePtrImpl :
public AAPrivatizablePtr {
7343 AAPrivatizablePtrImpl(
const IRPosition &IRP, Attributor &
A)
7344 : AAPrivatizablePtr(IRP,
A), PrivatizableType(std::nullopt) {}
7347 AAPrivatizablePtr::indicatePessimisticFixpoint();
7348 PrivatizableType =
nullptr;
7349 return ChangeStatus::CHANGED;
7355 virtual std::optional<Type *> identifyPrivatizableType(Attributor &
A) = 0;
7359 std::optional<Type *> combineTypes(std::optional<Type *> T0,
7360 std::optional<Type *>
T1) {
7370 std::optional<Type *> getPrivatizableType()
const override {
7371 return PrivatizableType;
7374 const std::string getAsStr(Attributor *
A)
const override {
7375 return isAssumedPrivatizablePtr() ?
"[priv]" :
"[no-priv]";
7379 std::optional<Type *> PrivatizableType;
7384struct AAPrivatizablePtrArgument final :
public AAPrivatizablePtrImpl {
7385 AAPrivatizablePtrArgument(
const IRPosition &IRP, Attributor &
A)
7386 : AAPrivatizablePtrImpl(IRP,
A) {}
7389 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7392 bool UsedAssumedInformation =
false;
7394 A.getAttrs(getIRPosition(), {Attribute::ByVal},
Attrs,
7396 if (!
Attrs.empty() &&
7397 A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *
this,
7398 true, UsedAssumedInformation))
7399 return Attrs[0].getValueAsType();
7401 std::optional<Type *> Ty;
7402 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
7410 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7419 A.getAAFor<AAPrivatizablePtr>(*
this, ACSArgPos, DepClassTy::REQUIRED);
7422 std::optional<Type *> CSTy = PrivCSArgAA->getPrivatizableType();
7425 dbgs() <<
"[AAPrivatizablePtr] ACSPos: " << ACSArgPos <<
", CSTy: ";
7429 dbgs() <<
"<nullptr>";
7434 Ty = combineTypes(Ty, CSTy);
7437 dbgs() <<
" : New Type: ";
7439 (*Ty)->print(
dbgs());
7441 dbgs() <<
"<nullptr>";
7450 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7451 UsedAssumedInformation))
7458 PrivatizableType = identifyPrivatizableType(
A);
7459 if (!PrivatizableType)
7460 return ChangeStatus::UNCHANGED;
7461 if (!*PrivatizableType)
7462 return indicatePessimisticFixpoint();
7467 DepClassTy::OPTIONAL);
7470 if (!
A.hasAttr(getIRPosition(), Attribute::ByVal) &&
7473 return indicatePessimisticFixpoint();
7479 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7483 Function &Fn = *getIRPosition().getAnchorScope();
7485 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(Fn);
7487 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Missing TTI for function "
7489 return indicatePessimisticFixpoint();
7492 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7499 bool UsedAssumedInformation =
false;
7500 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7501 UsedAssumedInformation)) {
7503 dbgs() <<
"[AAPrivatizablePtr] ABI incompatibility detected for "
7505 return indicatePessimisticFixpoint();
7509 Argument *Arg = getAssociatedArgument();
7510 if (!
A.isValidFunctionSignatureRewrite(*Arg, ReplacementTypes)) {
7512 return indicatePessimisticFixpoint();
7519 auto IsCompatiblePrivArgOfCallback = [&](CallBase &CB) {
7522 for (
const Use *U : CallbackUses) {
7523 AbstractCallSite CBACS(U);
7524 assert(CBACS && CBACS.isCallbackCall());
7525 for (Argument &CBArg : CBACS.getCalledFunction()->args()) {
7526 int CBArgNo = CBACS.getCallArgOperandNo(CBArg);
7530 <<
"[AAPrivatizablePtr] Argument " << *Arg
7531 <<
"check if can be privatized in the context of its parent ("
7533 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7535 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7536 <<
")\n[AAPrivatizablePtr] " << CBArg <<
" : "
7537 << CBACS.getCallArgOperand(CBArg) <<
" vs "
7539 <<
"[AAPrivatizablePtr] " << CBArg <<
" : "
7540 << CBACS.getCallArgOperandNo(CBArg) <<
" vs " << ArgNo <<
"\n";
7543 if (CBArgNo !=
int(ArgNo))
7545 const auto *CBArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7547 if (CBArgPrivAA && CBArgPrivAA->isValidState()) {
7548 auto CBArgPrivTy = CBArgPrivAA->getPrivatizableType();
7551 if (*CBArgPrivTy == PrivatizableType)
7556 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7557 <<
" cannot be privatized in the context of its parent ("
7559 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7561 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7562 <<
").\n[AAPrivatizablePtr] for which the argument "
7563 "privatization is not compatible.\n";
7573 auto IsCompatiblePrivArgOfDirectCS = [&](AbstractCallSite ACS) {
7577 "Expected a direct call operand for callback call operand");
7582 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7583 <<
" check if be privatized in the context of its parent ("
7585 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7587 << DCArgNo <<
"@" << DCCallee->
getName() <<
").\n";
7590 if (
unsigned(DCArgNo) < DCCallee->
arg_size()) {
7591 const auto *DCArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7593 DepClassTy::REQUIRED);
7594 if (DCArgPrivAA && DCArgPrivAA->isValidState()) {
7595 auto DCArgPrivTy = DCArgPrivAA->getPrivatizableType();
7598 if (*DCArgPrivTy == PrivatizableType)
7604 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7605 <<
" cannot be privatized in the context of its parent ("
7607 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7610 <<
").\n[AAPrivatizablePtr] for which the argument "
7611 "privatization is not compatible.\n";
7619 auto IsCompatiblePrivArgOfOtherCallSite = [&](AbstractCallSite ACS) {
7623 return IsCompatiblePrivArgOfDirectCS(ACS);
7627 if (!
A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *
this,
true,
7628 UsedAssumedInformation))
7629 return indicatePessimisticFixpoint();
7631 return ChangeStatus::UNCHANGED;
7637 identifyReplacementTypes(
Type *PrivType,
7638 SmallVectorImpl<Type *> &ReplacementTypes) {
7641 assert(PrivType &&
"Expected privatizable type!");
7645 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++)
7646 ReplacementTypes.
push_back(PrivStructType->getElementType(u));
7648 ReplacementTypes.
append(PrivArrayType->getNumElements(),
7649 PrivArrayType->getElementType());
7658 static void createInitialization(
Type *PrivType,
Value &
Base, Function &
F,
7660 assert(PrivType &&
"Expected privatizable type!");
7663 const DataLayout &
DL =
F.getDataLayout();
7667 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7668 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7671 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7674 Type *PointeeTy = PrivArrayType->getElementType();
7675 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7676 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7678 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7681 new StoreInst(
F.getArg(ArgNo), &
Base, IP);
7687 void createReplacementValues(Align Alignment,
Type *PrivType,
7689 SmallVectorImpl<Value *> &ReplacementValues) {
7691 assert(PrivType &&
"Expected privatizable type!");
7699 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7700 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7701 Type *PointeeTy = PrivStructType->getElementType(u);
7704 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7705 L->setAlignment(Alignment);
7709 Type *PointeeTy = PrivArrayType->getElementType();
7710 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7711 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7713 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7714 L->setAlignment(Alignment);
7719 L->setAlignment(Alignment);
7726 if (!PrivatizableType)
7727 return ChangeStatus::UNCHANGED;
7728 assert(*PrivatizableType &&
"Expected privatizable type!");
7734 bool UsedAssumedInformation =
false;
7735 if (!
A.checkForAllInstructions(
7736 [&](Instruction &
I) {
7737 CallInst &CI = cast<CallInst>(I);
7738 if (CI.isTailCall())
7739 TailCalls.push_back(&CI);
7742 *
this, {Instruction::Call}, UsedAssumedInformation))
7743 return ChangeStatus::UNCHANGED;
7745 Argument *Arg = getAssociatedArgument();
7748 const auto *AlignAA =
7755 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7757 BasicBlock &EntryBB = ReplacementFn.getEntryBlock();
7759 const DataLayout &
DL = IP->getDataLayout();
7760 unsigned AS =
DL.getAllocaAddrSpace();
7761 Instruction *AI =
new AllocaInst(*PrivatizableType, AS,
7762 Arg->
getName() +
".priv", IP);
7763 createInitialization(*PrivatizableType, *AI, ReplacementFn,
7764 ArgIt->getArgNo(), IP);
7767 AI = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
7771 for (CallInst *CI : TailCalls)
7772 CI->setTailCall(
false);
7779 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7780 AbstractCallSite ACS, SmallVectorImpl<Value *> &NewArgOperands) {
7783 createReplacementValues(
7784 AlignAA ? AlignAA->getAssumedAlign() :
Align(0),
7785 *PrivatizableType, ACS,
7793 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7796 if (
A.registerFunctionSignatureRewrite(*Arg, ReplacementTypes,
7797 std::move(FnRepairCB),
7798 std::move(ACSRepairCB)))
7799 return ChangeStatus::CHANGED;
7800 return ChangeStatus::UNCHANGED;
7804 void trackStatistics()
const override {
7809struct AAPrivatizablePtrFloating :
public AAPrivatizablePtrImpl {
7810 AAPrivatizablePtrFloating(
const IRPosition &IRP, Attributor &
A)
7811 : AAPrivatizablePtrImpl(IRP,
A) {}
7816 indicatePessimisticFixpoint();
7821 "updateImpl will not be called");
7825 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7828 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] No underlying object found!\n");
7835 return AI->getAllocatedType();
7837 auto *PrivArgAA =
A.getAAFor<AAPrivatizablePtr>(
7839 if (PrivArgAA && PrivArgAA->isAssumedPrivatizablePtr())
7840 return PrivArgAA->getPrivatizableType();
7843 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Underlying object neither valid "
7844 "alloca nor privatizable argument: "
7850 void trackStatistics()
const override {
7855struct AAPrivatizablePtrCallSiteArgument final
7856 :
public AAPrivatizablePtrFloating {
7857 AAPrivatizablePtrCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
7858 : AAPrivatizablePtrFloating(IRP,
A) {}
7862 if (
A.hasAttr(getIRPosition(), Attribute::ByVal))
7863 indicateOptimisticFixpoint();
7868 PrivatizableType = identifyPrivatizableType(
A);
7869 if (!PrivatizableType)
7870 return ChangeStatus::UNCHANGED;
7871 if (!*PrivatizableType)
7872 return indicatePessimisticFixpoint();
7874 const IRPosition &IRP = getIRPosition();
7875 bool IsKnownNoCapture;
7877 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoCapture);
7878 if (!IsAssumedNoCapture) {
7879 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might be captured!\n");
7880 return indicatePessimisticFixpoint();
7883 bool IsKnownNoAlias;
7885 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
7886 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might alias!\n");
7887 return indicatePessimisticFixpoint();
7892 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer is written!\n");
7893 return indicatePessimisticFixpoint();
7896 return ChangeStatus::UNCHANGED;
7900 void trackStatistics()
const override {
7905struct AAPrivatizablePtrCallSiteReturned final
7906 :
public AAPrivatizablePtrFloating {
7907 AAPrivatizablePtrCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
7908 : AAPrivatizablePtrFloating(IRP,
A) {}
7913 indicatePessimisticFixpoint();
7917 void trackStatistics()
const override {
7922struct AAPrivatizablePtrReturned final :
public AAPrivatizablePtrFloating {
7923 AAPrivatizablePtrReturned(
const IRPosition &IRP, Attributor &
A)
7924 : AAPrivatizablePtrFloating(IRP,
A) {}
7929 indicatePessimisticFixpoint();
7933 void trackStatistics()
const override {
7943struct AAMemoryBehaviorImpl :
public AAMemoryBehavior {
7944 AAMemoryBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
7945 : AAMemoryBehavior(IRP,
A) {}
7949 intersectAssumedBits(BEST_STATE);
7950 getKnownStateFromValue(
A, getIRPosition(), getState());
7951 AAMemoryBehavior::initialize(
A);
7955 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
7956 BitIntegerState &State,
7957 bool IgnoreSubsumingPositions =
false) {
7959 A.getAttrs(IRP, AttrKinds, Attrs, IgnoreSubsumingPositions);
7961 switch (Attr.getKindAsEnum()) {
7962 case Attribute::ReadNone:
7965 case Attribute::ReadOnly:
7968 case Attribute::WriteOnly:
7977 if (!
I->mayReadFromMemory())
7979 if (!
I->mayWriteToMemory())
7985 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
7986 SmallVectorImpl<Attribute> &Attrs)
const override {
7989 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));
7991 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));
7992 else if (isAssumedWriteOnly())
7993 Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));
7999 const IRPosition &IRP = getIRPosition();
8001 if (
A.hasAttr(IRP, Attribute::ReadNone,
8003 return ChangeStatus::UNCHANGED;
8012 return ChangeStatus::UNCHANGED;
8015 A.removeAttrs(IRP, AttrKinds);
8018 A.removeAttrs(IRP, Attribute::Writable);
8025 const std::string getAsStr(Attributor *
A)
const override {
8030 if (isAssumedWriteOnly())
8032 return "may-read/write";
8036 static const Attribute::AttrKind AttrKinds[3];
8040 Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};
8043struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {
8044 AAMemoryBehaviorFloating(
const IRPosition &IRP, Attributor &
A)
8045 : AAMemoryBehaviorImpl(IRP,
A) {}
8051 void trackStatistics()
const override {
8056 else if (isAssumedWriteOnly())
8063 bool followUsersOfUseIn(Attributor &
A,
const Use &U,
8064 const Instruction *UserI);
8067 void analyzeUseIn(Attributor &
A,
const Use &U,
const Instruction *UserI);
8071struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
8072 AAMemoryBehaviorArgument(
const IRPosition &IRP, Attributor &
A)
8073 : AAMemoryBehaviorFloating(IRP,
A) {}
8077 intersectAssumedBits(BEST_STATE);
8078 const IRPosition &IRP = getIRPosition();
8082 bool HasByVal =
A.hasAttr(IRP, {Attribute::ByVal},
8084 getKnownStateFromValue(
A, IRP, getState(),
8091 return ChangeStatus::UNCHANGED;
8095 if (
A.hasAttr(getIRPosition(),
8096 {Attribute::InAlloca, Attribute::Preallocated})) {
8097 removeKnownBits(NO_WRITES);
8098 removeAssumedBits(NO_WRITES);
8100 A.removeAttrs(getIRPosition(), AttrKinds);
8101 return AAMemoryBehaviorFloating::manifest(
A);
8105 void trackStatistics()
const override {
8110 else if (isAssumedWriteOnly())
8115struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {
8116 AAMemoryBehaviorCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
8117 : AAMemoryBehaviorArgument(IRP,
A) {}
8123 Argument *Arg = getAssociatedArgument();
8125 indicatePessimisticFixpoint();
8129 addKnownBits(NO_WRITES);
8130 removeKnownBits(NO_READS);
8131 removeAssumedBits(NO_READS);
8133 AAMemoryBehaviorArgument::initialize(
A);
8134 if (getAssociatedFunction()->isDeclaration())
8135 indicatePessimisticFixpoint();
8144 Argument *Arg = getAssociatedArgument();
8147 A.getAAFor<AAMemoryBehavior>(*
this, ArgPos, DepClassTy::REQUIRED);
8149 return indicatePessimisticFixpoint();
8154 void trackStatistics()
const override {
8159 else if (isAssumedWriteOnly())
8165struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {
8166 AAMemoryBehaviorCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
8167 : AAMemoryBehaviorFloating(IRP,
A) {}
8171 AAMemoryBehaviorImpl::initialize(
A);
8176 return ChangeStatus::UNCHANGED;
8180 void trackStatistics()
const override {}
8184struct AAMemoryBehaviorFunction final :
public AAMemoryBehaviorImpl {
8185 AAMemoryBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
8186 : AAMemoryBehaviorImpl(IRP,
A) {}
8202 else if (isAssumedWriteOnly())
8205 A.removeAttrs(getIRPosition(), AttrKinds);
8208 for (Argument &Arg :
F.args())
8210 return A.manifestAttrs(getIRPosition(),
8211 Attribute::getWithMemoryEffects(
F.getContext(), ME));
8215 void trackStatistics()
const override {
8220 else if (isAssumedWriteOnly())
8226struct AAMemoryBehaviorCallSite final
8227 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl> {
8228 AAMemoryBehaviorCallSite(
const IRPosition &IRP, Attributor &
A)
8229 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl>(IRP,
A) {}
8240 else if (isAssumedWriteOnly())
8243 A.removeAttrs(getIRPosition(), AttrKinds);
8246 for (Use &U : CB.
args())
8248 Attribute::Writable);
8249 return A.manifestAttrs(
8250 getIRPosition(), Attribute::getWithMemoryEffects(CB.
getContext(), ME));
8254 void trackStatistics()
const override {
8259 else if (isAssumedWriteOnly())
8264ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &
A) {
8267 auto AssumedState = getAssumed();
8274 const auto *MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
8276 if (MemBehaviorAA) {
8277 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8278 return !isAtFixpoint();
8283 if (
I.mayReadFromMemory())
8284 removeAssumedBits(NO_READS);
8285 if (
I.mayWriteToMemory())
8286 removeAssumedBits(NO_WRITES);
8287 return !isAtFixpoint();
8290 bool UsedAssumedInformation =
false;
8291 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8292 UsedAssumedInformation))
8293 return indicatePessimisticFixpoint();
8299ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &
A) {
8301 const IRPosition &IRP = getIRPosition();
8312 const auto *FnMemAA =
8315 FnMemAssumedState = FnMemAA->getAssumed();
8316 S.addKnownBits(FnMemAA->getKnown());
8317 if ((S.getAssumed() & FnMemAA->getAssumed()) == S.getAssumed())
8323 auto AssumedState = S.getAssumed();
8329 bool IsKnownNoCapture;
8330 const AANoCapture *ArgNoCaptureAA =
nullptr;
8335 if (!IsAssumedNoCapture &&
8337 S.intersectAssumedBits(FnMemAssumedState);
8343 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
8345 LLVM_DEBUG(
dbgs() <<
"[AAMemoryBehavior] Use: " << *U <<
" in " << *UserI
8353 Follow = followUsersOfUseIn(
A, U, UserI);
8357 analyzeUseIn(
A, U, UserI);
8359 return !isAtFixpoint();
8362 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue()))
8363 return indicatePessimisticFixpoint();
8369bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &
A,
const Use &U,
8370 const Instruction *UserI) {
8388 if (
U.get()->getType()->isPointerTy()) {
8390 bool IsKnownNoCapture;
8399void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &
A,
const Use &U,
8400 const Instruction *UserI) {
8407 case Instruction::Load:
8409 removeAssumedBits(NO_READS);
8412 case Instruction::Store:
8417 removeAssumedBits(NO_WRITES);
8419 indicatePessimisticFixpoint();
8422 case Instruction::Call:
8423 case Instruction::CallBr:
8424 case Instruction::Invoke: {
8431 indicatePessimisticFixpoint();
8438 removeAssumedBits(NO_READS);
8445 if (
U.get()->getType()->isPointerTy())
8449 const auto *MemBehaviorAA =
8455 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8463 removeAssumedBits(NO_READS);
8465 removeAssumedBits(NO_WRITES);
8477 return "all memory";
8480 std::string S =
"memory:";
8486 S +=
"internal global,";
8488 S +=
"external global,";
8492 S +=
"inaccessible,";
8506 AccessKind2Accesses.fill(
nullptr);
8509 ~AAMemoryLocationImpl()
override {
8512 for (AccessSet *AS : AccessKind2Accesses)
8519 intersectAssumedBits(BEST_STATE);
8520 getKnownStateFromValue(
A, getIRPosition(), getState());
8521 AAMemoryLocation::initialize(
A);
8525 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
8526 BitIntegerState &State,
8527 bool IgnoreSubsumingPositions =
false) {
8536 bool UseArgMemOnly =
true;
8538 if (AnchorFn &&
A.isRunOn(*AnchorFn))
8542 A.getAttrs(IRP, {Attribute::Memory},
Attrs, IgnoreSubsumingPositions);
8551 State.
addKnownBits(inverseLocation(NO_INACCESSIBLE_MEM,
true,
true));
8556 State.
addKnownBits(inverseLocation(NO_ARGUMENT_MEM,
true,
true));
8560 A.manifestAttrs(IRP,
8561 Attribute::getWithMemoryEffects(
8570 NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM,
true,
true));
8574 A.manifestAttrs(IRP,
8575 Attribute::getWithMemoryEffects(
8585 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
8586 SmallVectorImpl<Attribute> &Attrs)
const override {
8593 else if (isAssumedInaccessibleMemOnly())
8594 Attrs.push_back(Attribute::getWithMemoryEffects(
8596 else if (isAssumedArgMemOnly())
8599 else if (isAssumedInaccessibleOrArgMemOnly())
8600 Attrs.push_back(Attribute::getWithMemoryEffects(
8610 const IRPosition &IRP = getIRPosition();
8614 if (DeducedAttrs.
size() != 1)
8615 return ChangeStatus::UNCHANGED;
8618 return A.manifestAttrs(IRP, Attribute::getWithMemoryEffects(
8623 bool checkForAllAccessesToMemoryKind(
8625 MemoryLocationsKind)>
8627 MemoryLocationsKind RequestedMLK)
const override {
8628 if (!isValidState())
8631 MemoryLocationsKind AssumedMLK = getAssumedNotAccessedLocation();
8632 if (AssumedMLK == NO_LOCATIONS)
8636 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS;
8637 CurMLK *= 2, ++Idx) {
8638 if (CurMLK & RequestedMLK)
8641 if (
const AccessSet *
Accesses = AccessKind2Accesses[Idx])
8642 for (
const AccessInfo &AI : *
Accesses)
8643 if (!Pred(AI.I, AI.Ptr, AI.Kind, CurMLK))
8656 MemoryLocationsKind KnownMLK = getKnown();
8658 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2)
8659 if (!(CurMLK & KnownMLK))
8660 updateStateAndAccessesMap(getState(), CurMLK,
I,
nullptr,
Changed,
8661 getAccessKindFromInst(
I));
8662 return AAMemoryLocation::indicatePessimisticFixpoint();
8682 bool operator()(
const AccessInfo &
LHS,
const AccessInfo &
RHS)
const {
8686 return LHS.Ptr <
RHS.Ptr;
8687 if (
LHS.Kind !=
RHS.Kind)
8688 return LHS.Kind <
RHS.Kind;
8695 using AccessSet = SmallSet<AccessInfo, 2, AccessInfo>;
8696 std::array<AccessSet *, llvm::ConstantLog2<VALID_STATE>()>
8697 AccessKind2Accesses;
8702 categorizeArgumentPointerLocations(Attributor &
A, CallBase &CB,
8703 AAMemoryLocation::StateType &AccessedLocs,
8708 categorizeAccessedLocations(Attributor &
A, Instruction &
I,
bool &
Changed);
8711 AccessKind getAccessKindFromInst(
const Instruction *
I) {
8714 AK =
I->mayReadFromMemory() ? READ :
NONE;
8723 void updateStateAndAccessesMap(AAMemoryLocation::StateType &State,
8724 MemoryLocationsKind MLK,
const Instruction *
I,
8733 if (MLK == NO_UNKOWN_MEM)
8735 State.removeAssumedBits(MLK);
8740 void categorizePtrValue(Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8741 AAMemoryLocation::StateType &State,
bool &
Changed,
8742 unsigned AccessAS = 0);
8748void AAMemoryLocationImpl::categorizePtrValue(
8749 Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8751 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize pointer locations for "
8756 unsigned ObjectAS =
Obj.getType()->getPointerAddressSpace();
8758 MemoryLocationsKind MLK = NO_LOCATIONS;
8778 MLK = NO_ARGUMENT_MEM;
8784 if (GVar->isConstant())
8787 if (GV->hasLocalLinkage())
8788 MLK = NO_GLOBAL_INTERNAL_MEM;
8790 MLK = NO_GLOBAL_EXTERNAL_MEM;
8798 bool IsKnownNoAlias;
8802 MLK = NO_MALLOCED_MEM;
8804 MLK = NO_UNKOWN_MEM;
8806 MLK = NO_UNKOWN_MEM;
8809 assert(MLK != NO_LOCATIONS &&
"No location specified!");
8810 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Ptr value can be categorized: "
8811 << Obj <<
" -> " << getMemoryLocationsAsStr(MLK) <<
"\n");
8813 getAccessKindFromInst(&
I));
8818 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
8822 dbgs() <<
"[AAMemoryLocation] Pointer locations not categorized\n");
8823 updateStateAndAccessesMap(
State, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8824 getAccessKindFromInst(&
I));
8829 dbgs() <<
"[AAMemoryLocation] Accessed locations with pointer locations: "
8833void AAMemoryLocationImpl::categorizeArgumentPointerLocations(
8836 for (
unsigned ArgNo = 0,
E = CB.
arg_size(); ArgNo <
E; ++ArgNo) {
8845 const auto *ArgOpMemLocationAA =
8848 if (ArgOpMemLocationAA && ArgOpMemLocationAA->isAssumedReadNone())
8853 categorizePtrValue(
A, CB, *ArgOp, AccessedLocs,
Changed);
8858AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &
A, Instruction &
I,
8860 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize accessed locations for "
8864 AccessedLocs.intersectAssumedBits(NO_LOCATIONS);
8869 const auto *CBMemLocationAA =
A.getAAFor<AAMemoryLocation>(
8872 <<
" [" << CBMemLocationAA <<
"]\n");
8873 if (!CBMemLocationAA) {
8874 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
8875 Changed, getAccessKindFromInst(&
I));
8876 return NO_UNKOWN_MEM;
8879 if (CBMemLocationAA->isAssumedReadNone())
8880 return NO_LOCATIONS;
8882 if (CBMemLocationAA->isAssumedInaccessibleMemOnly()) {
8883 updateStateAndAccessesMap(AccessedLocs, NO_INACCESSIBLE_MEM, &
I,
nullptr,
8884 Changed, getAccessKindFromInst(&
I));
8885 return AccessedLocs.getAssumed();
8888 uint32_t CBAssumedNotAccessedLocs =
8889 CBMemLocationAA->getAssumedNotAccessedLocation();
8892 uint32_t CBAssumedNotAccessedLocsNoArgMem =
8893 CBAssumedNotAccessedLocs | NO_ARGUMENT_MEM | NO_GLOBAL_MEM;
8895 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2) {
8896 if (CBAssumedNotAccessedLocsNoArgMem & CurMLK)
8898 updateStateAndAccessesMap(AccessedLocs, CurMLK, &
I,
nullptr,
Changed,
8899 getAccessKindFromInst(&
I));
8904 bool HasGlobalAccesses = ((~CBAssumedNotAccessedLocs) & NO_GLOBAL_MEM);
8905 if (HasGlobalAccesses) {
8908 updateStateAndAccessesMap(AccessedLocs, MLK, &
I, Ptr,
Changed,
8909 getAccessKindFromInst(&
I));
8912 if (!CBMemLocationAA->checkForAllAccessesToMemoryKind(
8913 AccessPred, inverseLocation(NO_GLOBAL_MEM,
false,
false)))
8914 return AccessedLocs.getWorstState();
8918 dbgs() <<
"[AAMemoryLocation] Accessed state before argument handling: "
8919 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8922 bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM);
8924 categorizeArgumentPointerLocations(
A, *CB, AccessedLocs,
Changed);
8927 dbgs() <<
"[AAMemoryLocation] Accessed state after argument handling: "
8928 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8930 return AccessedLocs.getAssumed();
8935 dbgs() <<
"[AAMemoryLocation] Categorize memory access with pointer: "
8936 <<
I <<
" [" << *Ptr <<
"]\n");
8937 categorizePtrValue(
A,
I, *Ptr, AccessedLocs,
Changed,
8938 Ptr->getType()->getPointerAddressSpace());
8939 return AccessedLocs.getAssumed();
8942 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Failed to categorize instruction: "
8944 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8945 getAccessKindFromInst(&
I));
8946 return AccessedLocs.getAssumed();
8950struct AAMemoryLocationFunction final :
public AAMemoryLocationImpl {
8951 AAMemoryLocationFunction(
const IRPosition &IRP, Attributor &
A)
8952 : AAMemoryLocationImpl(IRP,
A) {}
8957 const auto *MemBehaviorAA =
8958 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
8961 return indicateOptimisticFixpoint();
8963 "AAMemoryLocation was not read-none but AAMemoryBehavior was!");
8964 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
8965 return ChangeStatus::UNCHANGED;
8969 auto AssumedState = getAssumed();
8973 MemoryLocationsKind MLK = categorizeAccessedLocations(
A,
I,
Changed);
8974 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Accessed locations for " <<
I
8975 <<
": " << getMemoryLocationsAsStr(MLK) <<
"\n");
8976 removeAssumedBits(inverseLocation(MLK,
false,
false));
8979 return getAssumedNotAccessedLocation() != VALID_STATE;
8982 bool UsedAssumedInformation =
false;
8983 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8984 UsedAssumedInformation))
8985 return indicatePessimisticFixpoint();
8987 Changed |= AssumedState != getAssumed();
8988 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8992 void trackStatistics()
const override {
8995 else if (isAssumedArgMemOnly())
8997 else if (isAssumedInaccessibleMemOnly())
8999 else if (isAssumedInaccessibleOrArgMemOnly())
9005struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {
9006 AAMemoryLocationCallSite(
const IRPosition &IRP, Attributor &
A)
9007 : AAMemoryLocationImpl(IRP,
A) {}
9018 A.getAAFor<AAMemoryLocation>(*
this, FnPos, DepClassTy::REQUIRED);
9020 return indicatePessimisticFixpoint();
9024 updateStateAndAccessesMap(getState(), MLK,
I, Ptr,
Changed,
9025 getAccessKindFromInst(
I));
9028 if (!FnAA->checkForAllAccessesToMemoryKind(AccessPred, ALL_LOCATIONS))
9029 return indicatePessimisticFixpoint();
9030 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
9034 void trackStatistics()
const override {
9044struct AADenormalFPMathImpl :
public AADenormalFPMath {
9045 AADenormalFPMathImpl(
const IRPosition &IRP, Attributor &
A)
9046 : AADenormalFPMath(IRP,
A) {}
9048 const std::string getAsStr(Attributor *
A)
const override {
9049 std::string Str(
"AADenormalFPMath[");
9050 raw_string_ostream OS(Str);
9052 DenormalState
Known = getKnown();
9053 if (
Known.Mode.isValid())
9054 OS <<
"denormal-fp-math=" <<
Known.Mode;
9058 if (
Known.ModeF32.isValid())
9059 OS <<
" denormal-fp-math-f32=" <<
Known.ModeF32;
9065struct AADenormalFPMathFunction final : AADenormalFPMathImpl {
9066 AADenormalFPMathFunction(
const IRPosition &IRP, Attributor &
A)
9067 : AADenormalFPMathImpl(IRP,
A) {}
9071 DenormalFPEnv DenormEnv =
F->getDenormalFPEnv();
9081 auto CheckCallSite = [=, &Change, &
A](AbstractCallSite CS) {
9084 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
9086 const auto *CallerInfo =
A.getAAFor<AADenormalFPMath>(
9092 CallerInfo->getState());
9096 bool AllCallSitesKnown =
true;
9097 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
9098 return indicatePessimisticFixpoint();
9100 if (Change == ChangeStatus::CHANGED && isModeFixed())
9106 LLVMContext &Ctx = getAssociatedFunction()->getContext();
9112 DenormalFPEnv KnownEnv(
Known.Mode,
Known.ModeF32);
9115 AttrToRemove.
push_back(Attribute::DenormalFPEnv);
9118 Ctx, Attribute::DenormalFPEnv,
9119 DenormalFPEnv(
Known.Mode,
Known.ModeF32).toIntValue()));
9122 auto &IRP = getIRPosition();
9125 return A.removeAttrs(IRP, AttrToRemove) |
9126 A.manifestAttrs(IRP, AttrToAdd,
true);
9129 void trackStatistics()
const override {
9138struct AAValueConstantRangeImpl : AAValueConstantRange {
9139 using StateType = IntegerRangeState;
9140 AAValueConstantRangeImpl(
const IRPosition &IRP, Attributor &
A)
9141 : AAValueConstantRange(IRP,
A) {}
9145 if (
A.hasSimplificationCallback(getIRPosition())) {
9146 indicatePessimisticFixpoint();
9151 intersectKnown(getConstantRangeFromSCEV(
A, getCtxI()));
9154 intersectKnown(getConstantRangeFromLVI(
A, getCtxI()));
9158 const std::string getAsStr(Attributor *
A)
const override {
9160 llvm::raw_string_ostream OS(Str);
9162 getKnown().print(OS);
9164 getAssumed().print(OS);
9171 const SCEV *getSCEV(Attributor &
A,
const Instruction *
I =
nullptr)
const {
9172 if (!getAnchorScope())
9175 ScalarEvolution *SE =
9176 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9179 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
9185 const SCEV *S = SE->
getSCEV(&getAssociatedValue());
9194 ConstantRange getConstantRangeFromSCEV(Attributor &
A,
9195 const Instruction *
I =
nullptr)
const {
9196 if (!getAnchorScope())
9199 ScalarEvolution *SE =
9200 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9203 const SCEV *S = getSCEV(
A,
I);
9213 getConstantRangeFromLVI(Attributor &
A,
9214 const Instruction *CtxI =
nullptr)
const {
9215 if (!getAnchorScope())
9218 LazyValueInfo *LVI =
9219 A.getInfoCache().getAnalysisResultForFunction<LazyValueAnalysis>(
9234 bool isValidCtxInstructionForOutsideAnalysis(Attributor &
A,
9235 const Instruction *CtxI,
9236 bool AllowAACtxI)
const {
9237 if (!CtxI || (!AllowAACtxI && CtxI == getCtxI()))
9249 InformationCache &InfoCache =
A.getInfoCache();
9250 const DominatorTree *DT =
9261 getKnownConstantRange(Attributor &
A,
9262 const Instruction *CtxI =
nullptr)
const override {
9263 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9267 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9268 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9269 return getKnown().intersectWith(SCEVR).intersectWith(LVIR);
9274 getAssumedConstantRange(Attributor &
A,
9275 const Instruction *CtxI =
nullptr)
const override {
9280 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9282 return getAssumed();
9284 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9285 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9286 return getAssumed().intersectWith(SCEVR).intersectWith(LVIR);
9291 getMDNodeForConstantRange(
Type *Ty, LLVMContext &Ctx,
9292 const ConstantRange &AssumedConstantRange) {
9294 Ty, AssumedConstantRange.
getLower())),
9296 Ty, AssumedConstantRange.
getUpper()))};
9301 static bool isBetterRange(
const ConstantRange &Assumed,
9302 const Instruction &
I) {
9306 std::optional<ConstantRange>
Known;
9310 }
else if (MDNode *KnownRanges =
I.getMetadata(LLVMContext::MD_range)) {
9316 if (KnownRanges->getNumOperands() > 2)
9319 ConstantInt *
Lower =
9321 ConstantInt *
Upper =
9331 setRangeMetadataIfisBetterRange(Instruction *
I,
9332 const ConstantRange &AssumedConstantRange) {
9333 if (isBetterRange(AssumedConstantRange, *
I)) {
9334 I->setMetadata(LLVMContext::MD_range,
9335 getMDNodeForConstantRange(
I->getType(),
I->getContext(),
9336 AssumedConstantRange));
9343 setRangeRetAttrIfisBetterRange(Attributor &
A,
const IRPosition &IRP,
9345 const ConstantRange &AssumedConstantRange) {
9346 if (isBetterRange(AssumedConstantRange, *
I)) {
9347 A.manifestAttrs(IRP,
9348 Attribute::get(
I->getContext(), Attribute::Range,
9349 AssumedConstantRange),
9359 ConstantRange AssumedConstantRange = getAssumedConstantRange(
A);
9362 auto &
V = getAssociatedValue();
9366 assert(
I == getCtxI() &&
"Should not annotate an instruction which is "
9367 "not the context instruction");
9369 if (setRangeMetadataIfisBetterRange(
I, AssumedConstantRange))
9370 Changed = ChangeStatus::CHANGED;
9372 if (setRangeRetAttrIfisBetterRange(
A, getIRPosition(),
I,
9373 AssumedConstantRange))
9374 Changed = ChangeStatus::CHANGED;
9382struct AAValueConstantRangeArgument final
9383 : AAArgumentFromCallSiteArguments<
9384 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9386 using Base = AAArgumentFromCallSiteArguments<
9387 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9389 AAValueConstantRangeArgument(
const IRPosition &IRP, Attributor &
A)
9393 void trackStatistics()
const override {
9398struct AAValueConstantRangeReturned
9399 : AAReturnedFromReturnedValues<AAValueConstantRange,
9400 AAValueConstantRangeImpl,
9401 AAValueConstantRangeImpl::StateType,
9404 AAReturnedFromReturnedValues<AAValueConstantRange,
9405 AAValueConstantRangeImpl,
9406 AAValueConstantRangeImpl::StateType,
9408 AAValueConstantRangeReturned(
const IRPosition &IRP, Attributor &
A)
9413 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9414 indicatePessimisticFixpoint();
9418 void trackStatistics()
const override {
9423struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
9424 AAValueConstantRangeFloating(
const IRPosition &IRP, Attributor &
A)
9425 : AAValueConstantRangeImpl(IRP,
A) {}
9429 AAValueConstantRangeImpl::initialize(
A);
9433 Value &
V = getAssociatedValue();
9436 unionAssumed(ConstantRange(
C->getValue()));
9437 indicateOptimisticFixpoint();
9443 unionAssumed(ConstantRange(APInt(
getBitWidth(), 0)));
9444 indicateOptimisticFixpoint();
9456 if (
auto *RangeMD = LI->getMetadata(LLVMContext::MD_range)) {
9467 indicatePessimisticFixpoint();
9470 << getAssociatedValue() <<
"\n");
9473 bool calculateBinaryOperator(
9474 Attributor &
A, BinaryOperator *BinOp, IntegerRangeState &
T,
9475 const Instruction *CtxI,
9476 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9481 bool UsedAssumedInformation =
false;
9482 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9485 if (!SimplifiedLHS.has_value())
9487 if (!*SimplifiedLHS)
9489 LHS = *SimplifiedLHS;
9491 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9494 if (!SimplifiedRHS.has_value())
9496 if (!*SimplifiedRHS)
9498 RHS = *SimplifiedRHS;
9504 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9506 DepClassTy::REQUIRED);
9510 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9512 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9514 DepClassTy::REQUIRED);
9518 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9520 auto AssumedRange = LHSAARange.binaryOp(BinOp->
getOpcode(), RHSAARange);
9522 T.unionAssumed(AssumedRange);
9526 return T.isValidState();
9529 bool calculateCastInst(
9530 Attributor &
A, CastInst *CastI, IntegerRangeState &
T,
9531 const Instruction *CtxI,
9532 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9538 bool UsedAssumedInformation =
false;
9539 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9542 if (!SimplifiedOpV.has_value())
9544 if (!*SimplifiedOpV)
9546 OpV = *SimplifiedOpV;
9551 auto *OpAA =
A.getAAFor<AAValueConstantRange>(
9553 DepClassTy::REQUIRED);
9557 T.unionAssumed(OpAA->getAssumed().castOp(CastI->
getOpcode(),
9559 return T.isValidState();
9563 calculateCmpInst(Attributor &
A, CmpInst *CmpI, IntegerRangeState &
T,
9564 const Instruction *CtxI,
9565 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9570 bool UsedAssumedInformation =
false;
9571 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9574 if (!SimplifiedLHS.has_value())
9576 if (!*SimplifiedLHS)
9578 LHS = *SimplifiedLHS;
9580 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9583 if (!SimplifiedRHS.has_value())
9585 if (!*SimplifiedRHS)
9587 RHS = *SimplifiedRHS;
9593 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9595 DepClassTy::REQUIRED);
9599 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9601 DepClassTy::REQUIRED);
9605 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9606 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9609 if (LHSAARange.isEmptySet() || RHSAARange.isEmptySet())
9612 bool MustTrue =
false, MustFalse =
false;
9614 auto AllowedRegion =
9617 if (AllowedRegion.intersectWith(LHSAARange).isEmptySet())
9623 assert((!MustTrue || !MustFalse) &&
9624 "Either MustTrue or MustFalse should be false!");
9627 T.unionAssumed(ConstantRange(APInt( 1, 1)));
9629 T.unionAssumed(ConstantRange(APInt( 1, 0)));
9631 T.unionAssumed(ConstantRange( 1,
true));
9633 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] " << *CmpI <<
" after "
9634 << (MustTrue ?
"true" : (MustFalse ?
"false" :
"unknown"))
9635 <<
": " <<
T <<
"\n\t" << *LHSAA <<
"\t<op>\n\t"
9639 return T.isValidState();
9651 bool UsedAssumedInformation =
false;
9652 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9655 if (!SimplifiedOpV.has_value())
9657 if (!*SimplifiedOpV)
9659 Value *VPtr = *SimplifiedOpV;
9662 const auto *AA =
A.getAAFor<AAValueConstantRange>(
9664 DepClassTy::REQUIRED);
9668 T.unionAssumed(AA->getAssumedConstantRange(
A, CtxI));
9672 return T.isValidState();
9677 if (!calculateBinaryOperator(
A, BinOp,
T, CtxI, QuerriedAAs))
9680 if (!calculateCmpInst(
A, CmpI,
T, CtxI, QuerriedAAs))
9683 if (!calculateCastInst(
A, CastI,
T, CtxI, QuerriedAAs))
9689 T.indicatePessimisticFixpoint();
9696 for (
const AAValueConstantRange *QueriedAA : QuerriedAAs) {
9697 if (QueriedAA !=
this)
9700 if (
T.getAssumed() == getState().getAssumed())
9702 T.indicatePessimisticFixpoint();
9705 return T.isValidState();
9708 if (!VisitValueCB(getAssociatedValue(), getCtxI()))
9709 return indicatePessimisticFixpoint();
9714 return ChangeStatus::UNCHANGED;
9715 if (++NumChanges > MaxNumChanges) {
9716 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] performed " << NumChanges
9717 <<
" but only " << MaxNumChanges
9718 <<
" are allowed to avoid cyclic reasoning.");
9719 return indicatePessimisticFixpoint();
9721 return ChangeStatus::CHANGED;
9725 void trackStatistics()
const override {
9734 static constexpr int MaxNumChanges = 5;
9737struct AAValueConstantRangeFunction : AAValueConstantRangeImpl {
9738 AAValueConstantRangeFunction(
const IRPosition &IRP, Attributor &
A)
9739 : AAValueConstantRangeImpl(IRP,
A) {}
9743 llvm_unreachable(
"AAValueConstantRange(Function|CallSite)::updateImpl will "
9751struct AAValueConstantRangeCallSite : AAValueConstantRangeFunction {
9752 AAValueConstantRangeCallSite(
const IRPosition &IRP, Attributor &
A)
9753 : AAValueConstantRangeFunction(IRP,
A) {}
9759struct AAValueConstantRangeCallSiteReturned
9760 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9761 AAValueConstantRangeImpl::StateType,
9763 AAValueConstantRangeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
9764 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9765 AAValueConstantRangeImpl::StateType,
9772 if (std::optional<ConstantRange>
Range = CI->getRange())
9773 intersectKnown(*
Range);
9776 AAValueConstantRangeImpl::initialize(
A);
9780 void trackStatistics()
const override {
9784struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating {
9785 AAValueConstantRangeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
9786 : AAValueConstantRangeFloating(IRP,
A) {}
9790 return ChangeStatus::UNCHANGED;
9794 void trackStatistics()
const override {
9803struct AAPotentialConstantValuesImpl : AAPotentialConstantValues {
9806 AAPotentialConstantValuesImpl(
const IRPosition &IRP, Attributor &
A)
9807 : AAPotentialConstantValues(IRP,
A) {}
9811 if (
A.hasSimplificationCallback(getIRPosition()))
9812 indicatePessimisticFixpoint();
9814 AAPotentialConstantValues::initialize(
A);
9817 bool fillSetWithConstantValues(Attributor &
A,
const IRPosition &IRP, SetTy &S,
9818 bool &ContainsUndef,
bool ForSelf) {
9820 bool UsedAssumedInformation =
false;
9822 UsedAssumedInformation)) {
9829 auto *PotentialValuesAA =
A.getAAFor<AAPotentialConstantValues>(
9830 *
this, IRP, DepClassTy::REQUIRED);
9831 if (!PotentialValuesAA || !PotentialValuesAA->getState().isValidState())
9833 ContainsUndef = PotentialValuesAA->getState().undefIsContained();
9834 S = PotentialValuesAA->getState().getAssumedSet();
9841 ContainsUndef =
false;
9842 for (
auto &It :
Values) {
9844 ContainsUndef =
true;
9850 S.insert(CI->getValue());
9852 ContainsUndef &= S.empty();
9858 const std::string getAsStr(Attributor *
A)
const override {
9860 llvm::raw_string_ostream OS(Str);
9867 return indicatePessimisticFixpoint();
9871struct AAPotentialConstantValuesArgument final
9872 : AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9873 AAPotentialConstantValuesImpl,
9874 PotentialConstantIntValuesState> {
9875 using Base = AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9876 AAPotentialConstantValuesImpl,
9878 AAPotentialConstantValuesArgument(
const IRPosition &IRP, Attributor &
A)
9882 void trackStatistics()
const override {
9887struct AAPotentialConstantValuesReturned
9888 : AAReturnedFromReturnedValues<AAPotentialConstantValues,
9889 AAPotentialConstantValuesImpl> {
9890 using Base = AAReturnedFromReturnedValues<AAPotentialConstantValues,
9891 AAPotentialConstantValuesImpl>;
9892 AAPotentialConstantValuesReturned(
const IRPosition &IRP, Attributor &
A)
9896 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9897 indicatePessimisticFixpoint();
9898 Base::initialize(
A);
9902 void trackStatistics()
const override {
9907struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl {
9908 AAPotentialConstantValuesFloating(
const IRPosition &IRP, Attributor &
A)
9909 : AAPotentialConstantValuesImpl(IRP,
A) {}
9913 AAPotentialConstantValuesImpl::initialize(
A);
9917 Value &
V = getAssociatedValue();
9920 unionAssumed(
C->getValue());
9921 indicateOptimisticFixpoint();
9926 unionAssumedWithUndef();
9927 indicateOptimisticFixpoint();
9937 indicatePessimisticFixpoint();
9940 << getAssociatedValue() <<
"\n");
9943 static bool calculateICmpInst(
const ICmpInst *ICI,
const APInt &
LHS,
9948 static APInt calculateCastInst(
const CastInst *CI,
const APInt &Src,
9949 uint32_t ResultBitWidth) {
9954 case Instruction::Trunc:
9955 return Src.trunc(ResultBitWidth);
9956 case Instruction::SExt:
9957 return Src.sext(ResultBitWidth);
9958 case Instruction::ZExt:
9959 return Src.zext(ResultBitWidth);
9960 case Instruction::BitCast:
9965 static APInt calculateBinaryOperator(
const BinaryOperator *BinOp,
9966 const APInt &
LHS,
const APInt &
RHS,
9967 bool &SkipOperation,
bool &Unsupported) {
9974 switch (BinOpcode) {
9978 case Instruction::Add:
9980 case Instruction::Sub:
9982 case Instruction::Mul:
9984 case Instruction::UDiv:
9986 SkipOperation =
true;
9990 case Instruction::SDiv:
9992 SkipOperation =
true;
9996 case Instruction::URem:
9998 SkipOperation =
true;
10002 case Instruction::SRem:
10003 if (
RHS.isZero()) {
10004 SkipOperation =
true;
10008 case Instruction::Shl:
10010 case Instruction::LShr:
10012 case Instruction::AShr:
10014 case Instruction::And:
10016 case Instruction::Or:
10018 case Instruction::Xor:
10023 bool calculateBinaryOperatorAndTakeUnion(
const BinaryOperator *BinOp,
10024 const APInt &
LHS,
const APInt &
RHS) {
10025 bool SkipOperation =
false;
10028 calculateBinaryOperator(BinOp,
LHS,
RHS, SkipOperation, Unsupported);
10032 if (!SkipOperation)
10033 unionAssumed(Result);
10034 return isValidState();
10037 ChangeStatus updateWithICmpInst(Attributor &
A, ICmpInst *ICI) {
10038 auto AssumedBefore = getAssumed();
10042 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10043 SetTy LHSAAPVS, RHSAAPVS;
10045 LHSContainsUndef,
false) ||
10047 RHSContainsUndef,
false))
10048 return indicatePessimisticFixpoint();
10051 bool MaybeTrue =
false, MaybeFalse =
false;
10053 if (LHSContainsUndef && RHSContainsUndef) {
10056 unionAssumedWithUndef();
10057 }
else if (LHSContainsUndef) {
10058 for (
const APInt &R : RHSAAPVS) {
10059 bool CmpResult = calculateICmpInst(ICI, Zero, R);
10060 MaybeTrue |= CmpResult;
10061 MaybeFalse |= !CmpResult;
10062 if (MaybeTrue & MaybeFalse)
10063 return indicatePessimisticFixpoint();
10065 }
else if (RHSContainsUndef) {
10066 for (
const APInt &L : LHSAAPVS) {
10067 bool CmpResult = calculateICmpInst(ICI, L, Zero);
10068 MaybeTrue |= CmpResult;
10069 MaybeFalse |= !CmpResult;
10070 if (MaybeTrue & MaybeFalse)
10071 return indicatePessimisticFixpoint();
10074 for (
const APInt &L : LHSAAPVS) {
10075 for (
const APInt &R : RHSAAPVS) {
10076 bool CmpResult = calculateICmpInst(ICI, L, R);
10077 MaybeTrue |= CmpResult;
10078 MaybeFalse |= !CmpResult;
10079 if (MaybeTrue & MaybeFalse)
10080 return indicatePessimisticFixpoint();
10085 unionAssumed(APInt( 1, 1));
10087 unionAssumed(APInt( 1, 0));
10088 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10089 : ChangeStatus::CHANGED;
10092 ChangeStatus updateWithSelectInst(Attributor &
A, SelectInst *SI) {
10093 auto AssumedBefore = getAssumed();
10097 bool UsedAssumedInformation =
false;
10098 std::optional<Constant *>
C =
A.getAssumedConstant(
10099 *
SI->getCondition(), *
this, UsedAssumedInformation);
10102 bool OnlyLeft =
false, OnlyRight =
false;
10103 if (
C && *
C && (*C)->isOneValue())
10105 else if (
C && *
C && (*C)->isNullValue())
10108 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10109 SetTy LHSAAPVS, RHSAAPVS;
10112 LHSContainsUndef,
false))
10113 return indicatePessimisticFixpoint();
10117 RHSContainsUndef,
false))
10118 return indicatePessimisticFixpoint();
10120 if (OnlyLeft || OnlyRight) {
10122 auto *OpAA = OnlyLeft ? &LHSAAPVS : &RHSAAPVS;
10123 auto Undef = OnlyLeft ? LHSContainsUndef : RHSContainsUndef;
10126 unionAssumedWithUndef();
10128 for (
const auto &It : *OpAA)
10132 }
else if (LHSContainsUndef && RHSContainsUndef) {
10134 unionAssumedWithUndef();
10136 for (
const auto &It : LHSAAPVS)
10138 for (
const auto &It : RHSAAPVS)
10141 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10142 : ChangeStatus::CHANGED;
10145 ChangeStatus updateWithCastInst(Attributor &
A, CastInst *CI) {
10146 auto AssumedBefore = getAssumed();
10148 return indicatePessimisticFixpoint();
10153 bool SrcContainsUndef =
false;
10156 SrcContainsUndef,
false))
10157 return indicatePessimisticFixpoint();
10159 if (SrcContainsUndef)
10160 unionAssumedWithUndef();
10162 for (
const APInt &S : SrcPVS) {
10163 APInt
T = calculateCastInst(CI, S, ResultBitWidth);
10167 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10168 : ChangeStatus::CHANGED;
10171 ChangeStatus updateWithBinaryOperator(Attributor &
A, BinaryOperator *BinOp) {
10172 auto AssumedBefore = getAssumed();
10176 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10177 SetTy LHSAAPVS, RHSAAPVS;
10179 LHSContainsUndef,
false) ||
10181 RHSContainsUndef,
false))
10182 return indicatePessimisticFixpoint();
10187 if (LHSContainsUndef && RHSContainsUndef) {
10188 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))
10189 return indicatePessimisticFixpoint();
10190 }
else if (LHSContainsUndef) {
10191 for (
const APInt &R : RHSAAPVS) {
10192 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))
10193 return indicatePessimisticFixpoint();
10195 }
else if (RHSContainsUndef) {
10196 for (
const APInt &L : LHSAAPVS) {
10197 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
10198 return indicatePessimisticFixpoint();
10201 for (
const APInt &L : LHSAAPVS) {
10202 for (
const APInt &R : RHSAAPVS) {
10203 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
10204 return indicatePessimisticFixpoint();
10208 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10209 : ChangeStatus::CHANGED;
10212 ChangeStatus updateWithInstruction(Attributor &
A, Instruction *Inst) {
10213 auto AssumedBefore = getAssumed();
10215 bool ContainsUndef;
10217 ContainsUndef,
true))
10218 return indicatePessimisticFixpoint();
10219 if (ContainsUndef) {
10220 unionAssumedWithUndef();
10222 for (
const auto &It : Incoming)
10225 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10226 : ChangeStatus::CHANGED;
10231 Value &
V = getAssociatedValue();
10235 return updateWithICmpInst(
A, ICI);
10238 return updateWithSelectInst(
A, SI);
10241 return updateWithCastInst(
A, CI);
10244 return updateWithBinaryOperator(
A, BinOp);
10247 return updateWithInstruction(
A,
I);
10249 return indicatePessimisticFixpoint();
10253 void trackStatistics()
const override {
10258struct AAPotentialConstantValuesFunction : AAPotentialConstantValuesImpl {
10259 AAPotentialConstantValuesFunction(
const IRPosition &IRP, Attributor &
A)
10260 : AAPotentialConstantValuesImpl(IRP,
A) {}
10265 "AAPotentialConstantValues(Function|CallSite)::updateImpl will "
10270 void trackStatistics()
const override {
10275struct AAPotentialConstantValuesCallSite : AAPotentialConstantValuesFunction {
10276 AAPotentialConstantValuesCallSite(
const IRPosition &IRP, Attributor &
A)
10277 : AAPotentialConstantValuesFunction(IRP,
A) {}
10280 void trackStatistics()
const override {
10285struct AAPotentialConstantValuesCallSiteReturned
10286 : AACalleeToCallSite<AAPotentialConstantValues,
10287 AAPotentialConstantValuesImpl> {
10288 AAPotentialConstantValuesCallSiteReturned(
const IRPosition &IRP,
10290 : AACalleeToCallSite<AAPotentialConstantValues,
10291 AAPotentialConstantValuesImpl>(IRP,
A) {}
10294 void trackStatistics()
const override {
10299struct AAPotentialConstantValuesCallSiteArgument
10300 : AAPotentialConstantValuesFloating {
10301 AAPotentialConstantValuesCallSiteArgument(
const IRPosition &IRP,
10303 : AAPotentialConstantValuesFloating(IRP,
A) {}
10307 AAPotentialConstantValuesImpl::initialize(
A);
10308 if (isAtFixpoint())
10311 Value &
V = getAssociatedValue();
10314 unionAssumed(
C->getValue());
10315 indicateOptimisticFixpoint();
10320 unionAssumedWithUndef();
10321 indicateOptimisticFixpoint();
10328 Value &
V = getAssociatedValue();
10329 auto AssumedBefore = getAssumed();
10330 auto *AA =
A.getAAFor<AAPotentialConstantValues>(
10333 return indicatePessimisticFixpoint();
10334 const auto &S = AA->getAssumed();
10336 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10337 : ChangeStatus::CHANGED;
10341 void trackStatistics()
const override {
10350 bool IgnoreSubsumingPositions) {
10351 assert(ImpliedAttributeKind == Attribute::NoUndef &&
10352 "Unexpected attribute kind");
10353 if (
A.hasAttr(IRP, {Attribute::NoUndef}, IgnoreSubsumingPositions,
10354 Attribute::NoUndef))
10374 Value &V = getAssociatedValue();
10376 indicatePessimisticFixpoint();
10377 assert(!isImpliedByIR(
A, getIRPosition(), Attribute::NoUndef));
10381 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10382 AANoUndef::StateType &State) {
10383 const Value *UseV =
U->get();
10384 const DominatorTree *DT =
nullptr;
10385 AssumptionCache *AC =
nullptr;
10386 InformationCache &InfoCache =
A.getInfoCache();
10387 if (Function *
F = getAnchorScope()) {
10392 bool TrackUse =
false;
10401 const std::string getAsStr(Attributor *
A)
const override {
10402 return getAssumed() ?
"noundef" :
"may-undef-or-poison";
10409 bool UsedAssumedInformation =
false;
10410 if (
A.isAssumedDead(getIRPosition(),
nullptr,
nullptr,
10411 UsedAssumedInformation))
10412 return ChangeStatus::UNCHANGED;
10416 if (!
A.getAssumedSimplified(getIRPosition(), *
this, UsedAssumedInformation,
10419 return ChangeStatus::UNCHANGED;
10420 return AANoUndef::manifest(
A);
10424struct AANoUndefFloating :
public AANoUndefImpl {
10425 AANoUndefFloating(
const IRPosition &IRP, Attributor &
A)
10426 : AANoUndefImpl(IRP,
A) {}
10430 AANoUndefImpl::initialize(
A);
10431 if (!getState().isAtFixpoint() && getAnchorScope() &&
10432 !getAnchorScope()->isDeclaration())
10433 if (Instruction *CtxI = getCtxI())
10434 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10439 auto VisitValueCB = [&](
const IRPosition &IRP) ->
bool {
10440 bool IsKnownNoUndef;
10442 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoUndef);
10446 bool UsedAssumedInformation =
false;
10447 Value *AssociatedValue = &getAssociatedValue();
10449 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
10454 Values.size() != 1 ||
Values.front().getValue() != AssociatedValue;
10462 if (AVIRP == getIRPosition() || !VisitValueCB(AVIRP))
10463 return indicatePessimisticFixpoint();
10464 return ChangeStatus::UNCHANGED;
10467 for (
const auto &VAC :
Values)
10469 return indicatePessimisticFixpoint();
10471 return ChangeStatus::UNCHANGED;
10478struct AANoUndefReturned final
10479 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl> {
10480 AANoUndefReturned(
const IRPosition &IRP, Attributor &
A)
10481 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10487struct AANoUndefArgument final
10488 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl> {
10489 AANoUndefArgument(
const IRPosition &IRP, Attributor &
A)
10490 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10496struct AANoUndefCallSiteArgument final : AANoUndefFloating {
10497 AANoUndefCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10498 : AANoUndefFloating(IRP,
A) {}
10504struct AANoUndefCallSiteReturned final
10505 : AACalleeToCallSite<AANoUndef, AANoUndefImpl> {
10506 AANoUndefCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10507 : AACalleeToCallSite<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10515struct AANoFPClassImpl : AANoFPClass {
10516 AANoFPClassImpl(
const IRPosition &IRP, Attributor &
A) : AANoFPClass(IRP,
A) {}
10519 const IRPosition &IRP = getIRPosition();
10523 indicateOptimisticFixpoint();
10528 A.getAttrs(getIRPosition(), {Attribute::NoFPClass},
Attrs,
false);
10529 for (
const auto &Attr : Attrs) {
10536 const DataLayout &
DL =
A.getDataLayout();
10537 InformationCache &InfoCache =
A.getInfoCache();
10539 const DominatorTree *DT =
nullptr;
10540 AssumptionCache *AC =
nullptr;
10541 const TargetLibraryInfo *TLI =
nullptr;
10545 if (!
F->isDeclaration()) {
10552 SimplifyQuery Q(
DL, TLI, DT, AC, CtxI);
10559 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10563 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10564 AANoFPClass::StateType &State) {
10575 if (
auto *NoFPAA =
A.getAAFor<AANoFPClass>(*
this, IRP, DepClassTy::NONE))
10576 State.addKnownBits(NoFPAA->getState().getKnown());
10580 const std::string getAsStr(Attributor *
A)
const override {
10581 std::string
Result =
"nofpclass";
10582 raw_string_ostream OS(Result);
10583 OS << getKnownNoFPClass() <<
'/' << getAssumedNoFPClass();
10587 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
10588 SmallVectorImpl<Attribute> &Attrs)
const override {
10589 Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));
10593struct AANoFPClassFloating :
public AANoFPClassImpl {
10594 AANoFPClassFloating(
const IRPosition &IRP, Attributor &
A)
10595 : AANoFPClassImpl(IRP,
A) {}
10600 bool UsedAssumedInformation =
false;
10601 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
10603 Values.push_back({getAssociatedValue(), getCtxI()});
10609 DepClassTy::REQUIRED);
10610 if (!AA ||
this == AA) {
10611 T.indicatePessimisticFixpoint();
10613 const AANoFPClass::StateType &S =
10614 static_cast<const AANoFPClass::StateType &
>(AA->
getState());
10617 return T.isValidState();
10620 for (
const auto &VAC :
Values)
10622 return indicatePessimisticFixpoint();
10628 void trackStatistics()
const override {
10633struct AANoFPClassReturned final
10634 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10635 AANoFPClassImpl::StateType, false,
10636 Attribute::None, false> {
10637 AANoFPClassReturned(
const IRPosition &IRP, Attributor &
A)
10638 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10639 AANoFPClassImpl::StateType,
false,
10643 void trackStatistics()
const override {
10648struct AANoFPClassArgument final
10649 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {
10650 AANoFPClassArgument(
const IRPosition &IRP, Attributor &
A)
10651 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10657struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {
10658 AANoFPClassCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10659 : AANoFPClassFloating(IRP,
A) {}
10662 void trackStatistics()
const override {
10667struct AANoFPClassCallSiteReturned final
10668 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl> {
10669 AANoFPClassCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10670 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10673 void trackStatistics()
const override {
10678struct AACallEdgesImpl :
public AACallEdges {
10679 AACallEdgesImpl(
const IRPosition &IRP, Attributor &
A) : AACallEdges(IRP,
A) {}
10681 const SetVector<Function *> &getOptimisticEdges()
const override {
10682 return CalledFunctions;
10685 bool hasUnknownCallee()
const override {
return HasUnknownCallee; }
10687 bool hasNonAsmUnknownCallee()
const override {
10688 return HasUnknownCalleeNonAsm;
10691 const std::string getAsStr(Attributor *
A)
const override {
10692 return "CallEdges[" + std::to_string(HasUnknownCallee) +
"," +
10693 std::to_string(CalledFunctions.size()) +
"]";
10696 void trackStatistics()
const override {}
10699 void addCalledFunction(Function *Fn,
ChangeStatus &Change) {
10700 if (CalledFunctions.insert(Fn)) {
10701 Change = ChangeStatus::CHANGED;
10707 void setHasUnknownCallee(
bool NonAsm,
ChangeStatus &Change) {
10708 if (!HasUnknownCallee)
10709 Change = ChangeStatus::CHANGED;
10710 if (NonAsm && !HasUnknownCalleeNonAsm)
10711 Change = ChangeStatus::CHANGED;
10712 HasUnknownCalleeNonAsm |= NonAsm;
10713 HasUnknownCallee =
true;
10718 SetVector<Function *> CalledFunctions;
10721 bool HasUnknownCallee =
false;
10724 bool HasUnknownCalleeNonAsm =
false;
10727struct AACallEdgesCallSite :
public AACallEdgesImpl {
10728 AACallEdgesCallSite(
const IRPosition &IRP, Attributor &
A)
10729 : AACallEdgesImpl(IRP,
A) {}
10736 addCalledFunction(Fn, Change);
10738 LLVM_DEBUG(
dbgs() <<
"[AACallEdges] Unrecognized value: " << V <<
"\n");
10739 setHasUnknownCallee(
true, Change);
10750 VisitValue(*V, CtxI);
10754 bool UsedAssumedInformation =
false;
10758 Values.push_back({*
V, CtxI});
10760 for (
auto &VAC :
Values)
10767 if (
IA->hasSideEffects() &&
10770 setHasUnknownCallee(
false, Change);
10776 if (
auto *IndirectCallAA =
A.getAAFor<AAIndirectCallInfo>(
10777 *
this, getIRPosition(), DepClassTy::OPTIONAL))
10778 if (IndirectCallAA->foreachCallee(
10779 [&](Function *Fn) { return VisitValue(*Fn, CB); }))
10788 for (
const Use *U : CallbackUses)
10789 ProcessCalledOperand(
U->get(), CB);
10795struct AACallEdgesFunction :
public AACallEdgesImpl {
10796 AACallEdgesFunction(
const IRPosition &IRP, Attributor &
A)
10797 : AACallEdgesImpl(IRP,
A) {}
10806 auto *CBEdges =
A.getAAFor<AACallEdges>(
10810 if (CBEdges->hasNonAsmUnknownCallee())
10811 setHasUnknownCallee(
true, Change);
10812 if (CBEdges->hasUnknownCallee())
10813 setHasUnknownCallee(
false, Change);
10815 for (Function *
F : CBEdges->getOptimisticEdges())
10816 addCalledFunction(
F, Change);
10822 bool UsedAssumedInformation =
false;
10823 if (!
A.checkForAllCallLikeInstructions(ProcessCallInst, *
this,
10824 UsedAssumedInformation,
10828 setHasUnknownCallee(
true, Change);
10837struct AAInterFnReachabilityFunction
10838 :
public CachedReachabilityAA<AAInterFnReachability, Function> {
10839 using Base = CachedReachabilityAA<AAInterFnReachability, Function>;
10840 AAInterFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
10843 bool instructionCanReach(
10844 Attributor &
A,
const Instruction &From,
const Function &To,
10847 auto *NonConstThis =
const_cast<AAInterFnReachabilityFunction *
>(
this);
10849 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
10850 RQITy::Reachable
Result;
10851 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
10852 return NonConstThis->isReachableImpl(
A, StackRQI,
10854 return Result == RQITy::Reachable::Yes;
10858 bool IsTemporaryRQI)
override {
10860 &RQI.From->getFunction()->getEntryBlock().front();
10861 if (EntryI != RQI.From &&
10862 !instructionCanReach(
A, *EntryI, *RQI.To,
nullptr))
10863 return rememberResult(
A, RQITy::Reachable::No, RQI,
false,
10866 auto CheckReachableCallBase = [&](CallBase *CB) {
10867 auto *CBEdges =
A.getAAFor<AACallEdges>(
10869 if (!CBEdges || !CBEdges->getState().isValidState())
10872 if (CBEdges->hasUnknownCallee())
10875 for (Function *Fn : CBEdges->getOptimisticEdges()) {
10886 if (Fn == getAnchorScope()) {
10887 if (EntryI == RQI.From)
10892 const AAInterFnReachability *InterFnReachability =
10894 DepClassTy::OPTIONAL);
10897 if (!InterFnReachability ||
10905 const auto *IntraFnReachability =
A.getAAFor<AAIntraFnReachability>(
10907 DepClassTy::OPTIONAL);
10915 return IntraFnReachability && !IntraFnReachability->isAssumedReachable(
10916 A, *RQI.From, CBInst, RQI.ExclusionSet);
10919 bool UsedExclusionSet =
true;
10920 bool UsedAssumedInformation =
false;
10921 if (!
A.checkForAllCallLikeInstructions(CheckCallBase, *
this,
10922 UsedAssumedInformation,
10924 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
10927 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
10931 void trackStatistics()
const override {}
10935template <
typename AAType>
10936static std::optional<Constant *>
10939 if (!Ty.isIntegerTy())
10947 std::optional<Constant *> COpt =
AA->getAssumedConstant(
A);
10949 if (!COpt.has_value()) {
10951 return std::nullopt;
10953 if (
auto *
C = *COpt) {
10964 std::optional<Value *> V;
10965 for (
auto &It :
Values) {
10967 if (V.has_value() && !*V)
10970 if (!V.has_value())
10984 if (
A.hasSimplificationCallback(getIRPosition())) {
10985 indicatePessimisticFixpoint();
10988 Value *Stripped = getAssociatedValue().stripPointerCasts();
10990 addValue(
A, getState(), *Stripped, getCtxI(),
AA::AnyScope,
10992 indicateOptimisticFixpoint();
10995 AAPotentialValues::initialize(
A);
10999 const std::string getAsStr(Attributor *
A)
const override {
11001 llvm::raw_string_ostream OS(Str);
11006 template <
typename AAType>
11007 static std::optional<Value *> askOtherAA(Attributor &
A,
11008 const AbstractAttribute &AA,
11009 const IRPosition &IRP,
Type &Ty) {
11014 return std::nullopt;
11021 virtual void addValue(Attributor &
A, StateType &State,
Value &V,
11023 Function *AnchorScope)
const {
11027 for (
const auto &U : CB->
args()) {
11037 Type &Ty = *getAssociatedType();
11038 std::optional<Value *> SimpleV =
11039 askOtherAA<AAValueConstantRange>(
A, *
this, ValIRP, Ty);
11040 if (SimpleV.has_value() && !*SimpleV) {
11041 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
11042 *
this, ValIRP, DepClassTy::OPTIONAL);
11043 if (PotentialConstantsAA && PotentialConstantsAA->isValidState()) {
11044 for (
const auto &It : PotentialConstantsAA->getAssumedSet())
11045 State.unionAssumed({{*ConstantInt::get(&Ty, It),
nullptr}, S});
11046 if (PotentialConstantsAA->undefIsContained())
11051 if (!SimpleV.has_value())
11063 State.unionAssumed({{*VPtr, CtxI}, S});
11069 AA::ValueAndContext
I;
11073 return II.I ==
I &&
II.S == S;
11076 return std::tie(
I, S) < std::tie(
II.I,
II.S);
11080 bool recurseForValue(Attributor &
A,
const IRPosition &IRP,
AA::ValueScope S) {
11081 SmallMapVector<AA::ValueAndContext, int, 8> ValueScopeMap;
11086 bool UsedAssumedInformation =
false;
11088 if (!
A.getAssumedSimplifiedValues(IRP,
this,
Values, CS,
11089 UsedAssumedInformation))
11093 ValueScopeMap[It] += CS;
11095 for (
auto &It : ValueScopeMap)
11096 addValue(
A, getState(), *It.first.getValue(), It.first.getCtxI(),
11102 void giveUpOnIntraprocedural(Attributor &
A) {
11103 auto NewS = StateType::getBestState(getState());
11104 for (
const auto &It : getAssumedSet()) {
11107 addValue(
A, NewS, *It.first.getValue(), It.first.getCtxI(),
11110 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11118 getState() = StateType::getBestState(getState());
11119 getState().unionAssumed({{getAssociatedValue(), getCtxI()},
AA::AnyScope});
11120 AAPotentialValues::indicateOptimisticFixpoint();
11121 return ChangeStatus::CHANGED;
11126 return indicatePessimisticFixpoint();
11134 if (!getAssumedSimplifiedValues(
A,
Values, S))
11136 Value &OldV = getAssociatedValue();
11139 Value *NewV = getSingleValue(
A, *
this, getIRPosition(),
Values);
11140 if (!NewV || NewV == &OldV)
11145 if (
A.changeAfterManifest(getIRPosition(), *NewV))
11146 return ChangeStatus::CHANGED;
11148 return ChangeStatus::UNCHANGED;
11151 bool getAssumedSimplifiedValues(
11152 Attributor &
A, SmallVectorImpl<AA::ValueAndContext> &
Values,
11153 AA::ValueScope S,
bool RecurseForSelectAndPHI =
false)
const override {
11154 if (!isValidState())
11156 bool UsedAssumedInformation =
false;
11157 for (
const auto &It : getAssumedSet())
11158 if (It.second & S) {
11159 if (RecurseForSelectAndPHI && (
isa<PHINode>(It.first.getValue()) ||
11161 if (
A.getAssumedSimplifiedValues(
11163 this,
Values, S, UsedAssumedInformation))
11166 Values.push_back(It.first);
11168 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11173struct AAPotentialValuesFloating : AAPotentialValuesImpl {
11174 AAPotentialValuesFloating(
const IRPosition &IRP, Attributor &
A)
11175 : AAPotentialValuesImpl(IRP,
A) {}
11179 auto AssumedBefore = getAssumed();
11181 genericValueTraversal(
A, &getAssociatedValue());
11183 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11184 : ChangeStatus::CHANGED;
11188 struct LivenessInfo {
11189 const AAIsDead *LivenessAA =
nullptr;
11190 bool AnyDead =
false;
11200 SmallVectorImpl<ItemInfo> &Worklist) {
11203 bool UsedAssumedInformation =
false;
11205 auto GetSimplifiedValues = [&](
Value &
V,
11207 if (!
A.getAssumedSimplifiedValues(
11211 Values.push_back(AA::ValueAndContext{
V,
II.I.getCtxI()});
11215 if (GetSimplifiedValues(*
LHS, LHSValues))
11217 if (GetSimplifiedValues(*
RHS, RHSValues))
11222 InformationCache &InfoCache =
A.getInfoCache();
11229 F ?
A.getInfoCache().getTargetLibraryInfoForFunction(*
F) :
nullptr;
11234 const DataLayout &
DL =
A.getDataLayout();
11235 SimplifyQuery Q(
DL, TLI, DT, AC, CmpI);
11237 auto CheckPair = [&](
Value &LHSV,
Value &RHSV) {
11240 nullptr,
II.S, getAnchorScope());
11246 if (&LHSV == &RHSV &&
11248 Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
11250 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11257 if (TypedLHS && TypedRHS) {
11259 if (NewV && NewV != &Cmp) {
11260 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11272 if (!LHSIsNull && !RHSIsNull)
11278 assert((LHSIsNull || RHSIsNull) &&
11279 "Expected nullptr versus non-nullptr comparison at this point");
11282 unsigned PtrIdx = LHSIsNull;
11283 bool IsKnownNonNull;
11286 DepClassTy::REQUIRED, IsKnownNonNull);
11287 if (!IsAssumedNonNull)
11293 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11298 for (
auto &LHSValue : LHSValues)
11299 for (
auto &RHSValue : RHSValues)
11300 if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))
11305 bool handleSelectInst(Attributor &
A, SelectInst &SI, ItemInfo
II,
11306 SmallVectorImpl<ItemInfo> &Worklist) {
11308 bool UsedAssumedInformation =
false;
11310 std::optional<Constant *>
C =
11311 A.getAssumedConstant(*
SI.getCondition(), *
this, UsedAssumedInformation);
11312 bool NoValueYet = !
C.has_value();
11320 }
else if (&SI == &getAssociatedValue()) {
11325 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11327 if (!SimpleV.has_value())
11330 addValue(
A, getState(), **SimpleV, CtxI,
II.S, getAnchorScope());
11338 bool handleLoadInst(Attributor &
A, LoadInst &LI, ItemInfo
II,
11339 SmallVectorImpl<ItemInfo> &Worklist) {
11340 SmallSetVector<Value *, 4> PotentialCopies;
11341 SmallSetVector<Instruction *, 4> PotentialValueOrigins;
11342 bool UsedAssumedInformation =
false;
11344 PotentialValueOrigins, *
this,
11345 UsedAssumedInformation,
11347 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Failed to get potentially "
11348 "loaded values for load instruction "
11356 InformationCache &InfoCache =
A.getInfoCache();
11358 if (!
llvm::all_of(PotentialValueOrigins, [&](Instruction *
I) {
11362 return A.isAssumedDead(
SI->getOperandUse(0),
this,
11364 UsedAssumedInformation,
11366 return A.isAssumedDead(*
I,
this,
nullptr,
11367 UsedAssumedInformation,
11370 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Load is onl used by assumes "
11371 "and we cannot delete all the stores: "
11382 bool AllLocal = ScopeIsLocal;
11387 if (!DynamicallyUnique) {
11388 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Not all potentially loaded "
11389 "values are dynamically unique: "
11394 for (
auto *PotentialCopy : PotentialCopies) {
11396 Worklist.
push_back({{*PotentialCopy, CtxI},
II.S});
11401 if (!AllLocal && ScopeIsLocal)
11406 bool handlePHINode(
11407 Attributor &
A, PHINode &
PHI, ItemInfo
II,
11408 SmallVectorImpl<ItemInfo> &Worklist,
11409 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11410 auto GetLivenessInfo = [&](
const Function &
F) -> LivenessInfo & {
11411 LivenessInfo &LI = LivenessAAs[&
F];
11412 if (!LI.LivenessAA)
11418 if (&
PHI == &getAssociatedValue()) {
11419 LivenessInfo &LI = GetLivenessInfo(*
PHI.getFunction());
11421 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
11422 *
PHI.getFunction());
11426 for (
unsigned u = 0, e =
PHI.getNumIncomingValues(); u < e; u++) {
11428 if (LI.LivenessAA &&
11429 LI.LivenessAA->isEdgeDead(IncomingBB,
PHI.getParent())) {
11448 bool UsedAssumedInformation =
false;
11449 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11451 if (!SimpleV.has_value())
11455 addValue(
A, getState(), **SimpleV, &
PHI,
II.S, getAnchorScope());
11462 bool handleGenericInst(Attributor &
A, Instruction &
I, ItemInfo
II,
11463 SmallVectorImpl<ItemInfo> &Worklist) {
11464 bool SomeSimplified =
false;
11465 bool UsedAssumedInformation =
false;
11467 SmallVector<Value *, 8> NewOps(
I.getNumOperands());
11470 const auto &SimplifiedOp =
A.getAssumedSimplified(
11475 if (!SimplifiedOp.has_value())
11479 NewOps[Idx] = *SimplifiedOp;
11483 SomeSimplified |= (NewOps[Idx] !=
Op);
11489 if (!SomeSimplified)
11492 InformationCache &InfoCache =
A.getInfoCache();
11496 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
11499 const DataLayout &
DL =
I.getDataLayout();
11500 SimplifyQuery Q(
DL, TLI, DT, AC, &
I);
11502 if (!NewV || NewV == &
I)
11505 LLVM_DEBUG(
dbgs() <<
"Generic inst " <<
I <<
" assumed simplified to "
11512 Attributor &
A, Instruction &
I, ItemInfo
II,
11513 SmallVectorImpl<ItemInfo> &Worklist,
11514 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11517 CI->getPredicate(),
II, Worklist);
11519 switch (
I.getOpcode()) {
11520 case Instruction::Select:
11522 case Instruction::PHI:
11524 case Instruction::Load:
11527 return handleGenericInst(
A,
I,
II, Worklist);
11532 void genericValueTraversal(Attributor &
A,
Value *InitialV) {
11533 SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;
11535 SmallSet<ItemInfo, 16> Visited;
11554 LLVM_DEBUG(
dbgs() <<
"Generic value traversal reached iteration limit: "
11555 << Iteration <<
"!\n");
11556 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11562 Value *NewV =
nullptr;
11563 if (
V->getType()->isPointerTy()) {
11569 for (Argument &Arg :
Callee->args())
11576 if (NewV && NewV != V) {
11577 Worklist.
push_back({{*NewV, CtxI}, S});
11591 if (V == InitialV && CtxI == getCtxI()) {
11592 indicatePessimisticFixpoint();
11596 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11597 }
while (!Worklist.
empty());
11601 for (
auto &It : LivenessAAs)
11602 if (It.second.AnyDead)
11603 A.recordDependence(*It.second.LivenessAA, *
this, DepClassTy::OPTIONAL);
11607 void trackStatistics()
const override {
11612struct AAPotentialValuesArgument final : AAPotentialValuesImpl {
11613 using Base = AAPotentialValuesImpl;
11614 AAPotentialValuesArgument(
const IRPosition &IRP, Attributor &
A)
11621 indicatePessimisticFixpoint();
11626 auto AssumedBefore = getAssumed();
11628 unsigned ArgNo = getCalleeArgNo();
11630 bool UsedAssumedInformation =
false;
11632 auto CallSitePred = [&](AbstractCallSite ACS) {
11634 if (CSArgIRP.getPositionKind() == IRP_INVALID)
11637 if (!
A.getAssumedSimplifiedValues(CSArgIRP,
this,
Values,
11639 UsedAssumedInformation))
11642 return isValidState();
11645 if (!
A.checkForAllCallSites(CallSitePred, *
this,
11647 UsedAssumedInformation))
11648 return indicatePessimisticFixpoint();
11650 Function *Fn = getAssociatedFunction();
11651 bool AnyNonLocal =
false;
11652 for (
auto &It :
Values) {
11654 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11659 return indicatePessimisticFixpoint();
11663 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11669 AnyNonLocal =
true;
11671 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11673 giveUpOnIntraprocedural(
A);
11675 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11676 : ChangeStatus::CHANGED;
11680 void trackStatistics()
const override {
11685struct AAPotentialValuesReturned :
public AAPotentialValuesFloating {
11686 using Base = AAPotentialValuesFloating;
11687 AAPotentialValuesReturned(
const IRPosition &IRP, Attributor &
A)
11693 if (!
F ||
F->isDeclaration() ||
F->getReturnType()->isVoidTy()) {
11694 indicatePessimisticFixpoint();
11698 for (Argument &Arg :
F->args())
11701 ReturnedArg = &Arg;
11704 if (!
A.isFunctionIPOAmendable(*
F) ||
11705 A.hasSimplificationCallback(getIRPosition())) {
11707 indicatePessimisticFixpoint();
11709 indicateOptimisticFixpoint();
11715 auto AssumedBefore = getAssumed();
11716 bool UsedAssumedInformation =
false;
11719 Function *AnchorScope = getAnchorScope();
11725 UsedAssumedInformation,
11731 bool AllInterAreIntra =
false;
11738 for (
const AA::ValueAndContext &VAC :
Values) {
11739 addValue(
A, getState(), *VAC.
getValue(),
11743 if (AllInterAreIntra)
11750 HandleReturnedValue(*ReturnedArg,
nullptr,
true);
11753 bool AddValues =
true;
11756 addValue(
A, getState(), *RetI.getOperand(0), &RetI,
AA::AnyScope,
11760 return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);
11763 if (!
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11764 UsedAssumedInformation,
11766 return indicatePessimisticFixpoint();
11769 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11770 : ChangeStatus::CHANGED;
11775 return ChangeStatus::UNCHANGED;
11777 if (!getAssumedSimplifiedValues(
A,
Values, AA::ValueScope::Intraprocedural,
11779 return ChangeStatus::UNCHANGED;
11780 Value *NewVal = getSingleValue(
A, *
this, getIRPosition(),
Values);
11782 return ChangeStatus::UNCHANGED;
11787 "Number of function with unique return");
11790 {Attribute::get(Arg->
getContext(), Attribute::Returned)});
11795 Value *RetOp = RetI.getOperand(0);
11799 if (
A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))
11800 Changed = ChangeStatus::CHANGED;
11803 bool UsedAssumedInformation =
false;
11804 (void)
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11805 UsedAssumedInformation,
11811 return AAPotentialValues::indicatePessimisticFixpoint();
11815 void trackStatistics()
const override{
11822struct AAPotentialValuesFunction : AAPotentialValuesImpl {
11823 AAPotentialValuesFunction(
const IRPosition &IRP, Attributor &
A)
11824 : AAPotentialValuesImpl(IRP,
A) {}
11833 void trackStatistics()
const override {
11838struct AAPotentialValuesCallSite : AAPotentialValuesFunction {
11839 AAPotentialValuesCallSite(
const IRPosition &IRP, Attributor &
A)
11840 : AAPotentialValuesFunction(IRP,
A) {}
11843 void trackStatistics()
const override {
11848struct AAPotentialValuesCallSiteReturned : AAPotentialValuesImpl {
11849 AAPotentialValuesCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
11850 : AAPotentialValuesImpl(IRP,
A) {}
11854 auto AssumedBefore = getAssumed();
11858 return indicatePessimisticFixpoint();
11860 bool UsedAssumedInformation =
false;
11864 UsedAssumedInformation))
11865 return indicatePessimisticFixpoint();
11872 Values, S, UsedAssumedInformation))
11875 for (
auto &It :
Values) {
11876 Value *
V = It.getValue();
11877 std::optional<Value *> CallerV =
A.translateArgumentToCallSiteContent(
11878 V, *CB, *
this, UsedAssumedInformation);
11879 if (!CallerV.has_value()) {
11883 V = *CallerV ? *CallerV :
V;
11889 giveUpOnIntraprocedural(
A);
11892 addValue(
A, getState(), *V, CB, S, getAnchorScope());
11897 return indicatePessimisticFixpoint();
11899 return indicatePessimisticFixpoint();
11900 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11901 : ChangeStatus::CHANGED;
11905 return AAPotentialValues::indicatePessimisticFixpoint();
11909 void trackStatistics()
const override {
11914struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
11915 AAPotentialValuesCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
11916 : AAPotentialValuesFloating(IRP,
A) {}
11919 void trackStatistics()
const override {
11927struct AAAssumptionInfoImpl :
public AAAssumptionInfo {
11928 AAAssumptionInfoImpl(
const IRPosition &IRP, Attributor &
A,
11929 const DenseSet<StringRef> &
Known)
11930 : AAAssumptionInfo(IRP,
A,
Known) {}
11935 if (getKnown().isUniversal())
11936 return ChangeStatus::UNCHANGED;
11938 const IRPosition &IRP = getIRPosition();
11940 getAssumed().getSet().
end());
11942 return A.manifestAttrs(IRP,
11949 bool hasAssumption(
const StringRef Assumption)
const override {
11950 return isValidState() && setContains(Assumption);
11954 const std::string getAsStr(Attributor *
A)
const override {
11955 const SetContents &
Known = getKnown();
11956 const SetContents &Assumed = getAssumed();
11960 const std::string KnownStr =
llvm::join(Set,
",");
11962 std::string AssumedStr =
"Universal";
11963 if (!Assumed.isUniversal()) {
11964 Set.assign(Assumed.getSet().begin(), Assumed.getSet().end());
11967 return "Known [" + KnownStr +
"]," +
" Assumed [" + AssumedStr +
"]";
11982struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {
11983 AAAssumptionInfoFunction(
const IRPosition &IRP, Attributor &
A)
11984 : AAAssumptionInfoImpl(IRP,
A,
11991 auto CallSitePred = [&](AbstractCallSite ACS) {
11992 const auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
11994 DepClassTy::REQUIRED);
11998 Changed |= getIntersection(AssumptionAA->getAssumed());
11999 return !getAssumed().empty() || !getKnown().empty();
12002 bool UsedAssumedInformation =
false;
12007 if (!
A.checkForAllCallSites(CallSitePred, *
this,
true,
12008 UsedAssumedInformation))
12009 return indicatePessimisticFixpoint();
12011 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12014 void trackStatistics()
const override {}
12018struct AAAssumptionInfoCallSite final : AAAssumptionInfoImpl {
12020 AAAssumptionInfoCallSite(
const IRPosition &IRP, Attributor &
A)
12021 : AAAssumptionInfoImpl(IRP,
A, getInitialAssumptions(IRP)) {}
12026 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
12032 auto *AssumptionAA =
12033 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
12035 return indicatePessimisticFixpoint();
12036 bool Changed = getIntersection(AssumptionAA->getAssumed());
12037 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12041 void trackStatistics()
const override {}
12046 DenseSet<StringRef> getInitialAssumptions(
const IRPosition &IRP) {
12053 return Assumptions;
12068struct AAUnderlyingObjectsImpl
12074 const std::string getAsStr(
Attributor *
A)
const override {
12075 if (!isValidState())
12076 return "<invalid>";
12079 OS <<
"underlying objects: inter " << InterAssumedUnderlyingObjects.size()
12080 <<
" objects, intra " << IntraAssumedUnderlyingObjects.size()
12082 if (!InterAssumedUnderlyingObjects.empty()) {
12083 OS <<
"inter objects:\n";
12084 for (
auto *Obj : InterAssumedUnderlyingObjects)
12085 OS << *Obj <<
'\n';
12087 if (!IntraAssumedUnderlyingObjects.empty()) {
12088 OS <<
"intra objects:\n";
12089 for (
auto *Obj : IntraAssumedUnderlyingObjects)
12090 OS << *
Obj <<
'\n';
12096 void trackStatistics()
const override {}
12100 auto &Ptr = getAssociatedValue();
12102 bool UsedAssumedInformation =
false;
12103 auto DoUpdate = [&](SmallSetVector<Value *, 8> &UnderlyingObjects,
12105 SmallPtrSet<Value *, 8> SeenObjects;
12109 Scope, UsedAssumedInformation))
12110 return UnderlyingObjects.
insert(&Ptr);
12114 for (
unsigned I = 0;
I <
Values.size(); ++
I) {
12118 if (!SeenObjects.
insert(UO ? UO : Obj).second)
12120 if (UO && UO != Obj) {
12126 const auto *OtherAA =
A.getAAFor<AAUnderlyingObjects>(
12128 auto Pred = [&](
Value &
V) {
12132 Values.emplace_back(V,
nullptr);
12136 if (!OtherAA || !OtherAA->forallUnderlyingObjects(Pred, Scope))
12138 "The forall call should not return false at this position");
12144 Changed |= handleIndirect(
A, *Obj, UnderlyingObjects, Scope,
12145 UsedAssumedInformation);
12151 for (
unsigned u = 0, e =
PHI->getNumIncomingValues(); u < e; u++) {
12153 handleIndirect(
A, *
PHI->getIncomingValue(u), UnderlyingObjects,
12154 Scope, UsedAssumedInformation);
12168 if (!UsedAssumedInformation)
12169 indicateOptimisticFixpoint();
12170 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12173 bool forallUnderlyingObjects(
12174 function_ref<
bool(
Value &)> Pred,
12176 if (!isValidState())
12177 return Pred(getAssociatedValue());
12180 ? IntraAssumedUnderlyingObjects
12181 : InterAssumedUnderlyingObjects;
12182 for (
Value *Obj : AssumedUnderlyingObjects)
12192 bool handleIndirect(Attributor &
A,
Value &V,
12193 SmallSetVector<Value *, 8> &UnderlyingObjects,
12196 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
12198 auto Pred = [&](
Value &
V) {
12202 if (!AA || !AA->forallUnderlyingObjects(Pred, Scope))
12204 "The forall call should not return false at this position");
12210 SmallSetVector<Value *, 8> IntraAssumedUnderlyingObjects;
12212 SmallSetVector<Value *, 8> InterAssumedUnderlyingObjects;
12215struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl {
12216 AAUnderlyingObjectsFloating(
const IRPosition &IRP, Attributor &
A)
12217 : AAUnderlyingObjectsImpl(IRP,
A) {}
12220struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl {
12221 AAUnderlyingObjectsArgument(
const IRPosition &IRP, Attributor &
A)
12222 : AAUnderlyingObjectsImpl(IRP,
A) {}
12225struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl {
12226 AAUnderlyingObjectsCallSite(
const IRPosition &IRP, Attributor &
A)
12227 : AAUnderlyingObjectsImpl(IRP,
A) {}
12230struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl {
12231 AAUnderlyingObjectsCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12232 : AAUnderlyingObjectsImpl(IRP,
A) {}
12235struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl {
12236 AAUnderlyingObjectsReturned(
const IRPosition &IRP, Attributor &
A)
12237 : AAUnderlyingObjectsImpl(IRP,
A) {}
12240struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl {
12241 AAUnderlyingObjectsCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12242 : AAUnderlyingObjectsImpl(IRP,
A) {}
12245struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {
12246 AAUnderlyingObjectsFunction(
const IRPosition &IRP, Attributor &
A)
12247 : AAUnderlyingObjectsImpl(IRP,
A) {}
12253struct AAGlobalValueInfoFloating :
public AAGlobalValueInfo {
12254 AAGlobalValueInfoFloating(
const IRPosition &IRP, Attributor &
A)
12255 : AAGlobalValueInfo(IRP,
A) {}
12260 bool checkUse(Attributor &
A,
const Use &U,
bool &Follow,
12261 SmallVectorImpl<const Value *> &Worklist) {
12268 LLVM_DEBUG(
dbgs() <<
"[AAGlobalValueInfo] Check use: " << *
U.get() <<
" in "
12269 << *UInst <<
"\n");
12272 int Idx = &
Cmp->getOperandUse(0) == &
U;
12275 return U == &getAnchorValue();
12280 auto CallSitePred = [&](AbstractCallSite ACS) {
12281 Worklist.
push_back(ACS.getInstruction());
12284 bool UsedAssumedInformation =
false;
12286 if (!
A.checkForAllCallSites(CallSitePred, *UInst->
getFunction(),
12288 UsedAssumedInformation))
12306 if (!Fn || !
A.isFunctionIPOAmendable(*Fn))
12315 unsigned NumUsesBefore =
Uses.size();
12317 SmallPtrSet<const Value *, 8> Visited;
12321 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
12329 return checkUse(
A, U, Follow, Worklist);
12331 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
12332 Uses.insert(&OldU);
12336 while (!Worklist.
empty()) {
12338 if (!Visited.
insert(V).second)
12340 if (!
A.checkForAllUses(UsePred, *
this, *V,
12342 DepClassTy::OPTIONAL,
12343 true, EquivalentUseCB)) {
12344 return indicatePessimisticFixpoint();
12348 return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED
12349 : ChangeStatus::CHANGED;
12352 bool isPotentialUse(
const Use &U)
const override {
12353 return !isValidState() ||
Uses.contains(&U);
12358 return ChangeStatus::UNCHANGED;
12362 const std::string getAsStr(Attributor *
A)
const override {
12363 return "[" + std::to_string(
Uses.size()) +
" uses]";
12366 void trackStatistics()
const override {
12372 SmallPtrSet<const Use *, 8>
Uses;
12378struct AAIndirectCallInfoCallSite :
public AAIndirectCallInfo {
12379 AAIndirectCallInfoCallSite(
const IRPosition &IRP, Attributor &
A)
12380 : AAIndirectCallInfo(IRP,
A) {}
12384 auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);
12385 if (!MD && !
A.isClosedWorldModule())
12389 for (
const auto &
Op : MD->operands())
12391 PotentialCallees.insert(Callee);
12392 }
else if (
A.isClosedWorldModule()) {
12394 A.getInfoCache().getIndirectlyCallableFunctions(
A);
12395 PotentialCallees.insert_range(IndirectlyCallableFunctions);
12398 if (PotentialCallees.empty())
12399 indicateOptimisticFixpoint();
12407 SmallSetVector<Function *, 4> AssumedCalleesNow;
12408 bool AllCalleesKnownNow = AllCalleesKnown;
12410 auto CheckPotentialCalleeUse = [&](
Function &PotentialCallee,
12411 bool &UsedAssumedInformation) {
12412 const auto *GIAA =
A.getAAFor<AAGlobalValueInfo>(
12414 if (!GIAA || GIAA->isPotentialUse(CalleeUse))
12416 UsedAssumedInformation = !GIAA->isAtFixpoint();
12420 auto AddPotentialCallees = [&]() {
12421 for (
auto *PotentialCallee : PotentialCallees) {
12422 bool UsedAssumedInformation =
false;
12423 if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))
12424 AssumedCalleesNow.
insert(PotentialCallee);
12430 bool UsedAssumedInformation =
false;
12433 AA::ValueScope::AnyScope,
12434 UsedAssumedInformation)) {
12435 if (PotentialCallees.empty())
12436 return indicatePessimisticFixpoint();
12437 AddPotentialCallees();
12442 auto CheckPotentialCallee = [&](
Function &Fn) {
12443 if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))
12446 auto &CachedResult = FilterResults[&Fn];
12447 if (CachedResult.has_value())
12448 return CachedResult.value();
12450 bool UsedAssumedInformation =
false;
12451 if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {
12452 if (!UsedAssumedInformation)
12453 CachedResult =
false;
12462 for (
int I = NumCBArgs;
I < NumFnArgs; ++
I) {
12463 bool IsKnown =
false;
12466 DepClassTy::OPTIONAL, IsKnown)) {
12468 CachedResult =
false;
12473 CachedResult =
true;
12479 for (
auto &VAC :
Values) {
12487 if (CheckPotentialCallee(*VACFn))
12488 AssumedCalleesNow.
insert(VACFn);
12491 if (!PotentialCallees.empty()) {
12492 AddPotentialCallees();
12495 AllCalleesKnownNow =
false;
12498 if (AssumedCalleesNow == AssumedCallees &&
12499 AllCalleesKnown == AllCalleesKnownNow)
12500 return ChangeStatus::UNCHANGED;
12502 std::swap(AssumedCallees, AssumedCalleesNow);
12503 AllCalleesKnown = AllCalleesKnownNow;
12504 return ChangeStatus::CHANGED;
12510 if (!AllCalleesKnown && AssumedCallees.empty())
12511 return ChangeStatus::UNCHANGED;
12514 bool UsedAssumedInformation =
false;
12515 if (
A.isAssumedDead(*CB,
this,
nullptr,
12516 UsedAssumedInformation))
12517 return ChangeStatus::UNCHANGED;
12521 if (
FP->getType()->getPointerAddressSpace())
12522 FP =
new AddrSpaceCastInst(
FP, PointerType::get(
FP->getContext(), 0),
12532 if (AssumedCallees.empty()) {
12533 assert(AllCalleesKnown &&
12534 "Expected all callees to be known if there are none.");
12535 A.changeToUnreachableAfterManifest(CB);
12536 return ChangeStatus::CHANGED;
12540 if (AllCalleesKnown && AssumedCallees.size() == 1) {
12541 auto *NewCallee = AssumedCallees.front();
12544 NumIndirectCallsPromoted++;
12545 return ChangeStatus::CHANGED;
12552 A.deleteAfterManifest(*CB);
12553 return ChangeStatus::CHANGED;
12563 bool SpecializedForAnyCallees =
false;
12564 bool SpecializedForAllCallees = AllCalleesKnown;
12565 ICmpInst *LastCmp =
nullptr;
12568 for (Function *NewCallee : AssumedCallees) {
12569 if (!
A.shouldSpecializeCallSiteForCallee(*
this, *CB, *NewCallee,
12570 AssumedCallees.size())) {
12571 SkippedAssumedCallees.
push_back(NewCallee);
12572 SpecializedForAllCallees =
false;
12575 SpecializedForAnyCallees =
true;
12581 A.registerManifestAddedBasicBlock(*ThenTI->
getParent());
12582 A.registerManifestAddedBasicBlock(*IP->getParent());
12588 A.registerManifestAddedBasicBlock(*ElseBB);
12590 SplitTI->replaceUsesOfWith(CBBB, ElseBB);
12595 CastInst *RetBC =
nullptr;
12596 CallInst *NewCall =
nullptr;
12601 NumIndirectCallsPromoted++;
12609 auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {
12610 if (!AllCalleesKnown)
12611 return ChangeStatus::UNCHANGED;
12612 MDBuilder MDB(IndirectCB.getContext());
12613 MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);
12614 IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);
12615 return ChangeStatus::CHANGED;
12618 if (!SpecializedForAnyCallees)
12619 return AttachCalleeMetadata(*CB);
12622 if (SpecializedForAllCallees) {
12625 new UnreachableInst(IP->getContext(), IP);
12626 IP->eraseFromParent();
12629 CBClone->setName(CB->
getName());
12630 CBClone->insertBefore(*IP->getParent(), IP);
12631 NewCalls.
push_back({CBClone,
nullptr});
12632 AttachCalleeMetadata(*CBClone);
12639 CB->
getParent()->getFirstInsertionPt());
12640 for (
auto &It : NewCalls) {
12641 CallBase *NewCall = It.first;
12642 Instruction *CallRet = It.second ? It.second : It.first;
12654 A.deleteAfterManifest(*CB);
12655 Changed = ChangeStatus::CHANGED;
12661 const std::string getAsStr(Attributor *
A)
const override {
12662 return std::string(AllCalleesKnown ?
"eliminate" :
"specialize") +
12663 " indirect call site with " + std::to_string(AssumedCallees.size()) +
12667 void trackStatistics()
const override {
12668 if (AllCalleesKnown) {
12670 Eliminated, CallSites,
12671 "Number of indirect call sites eliminated via specialization")
12674 "Number of indirect call sites specialized")
12678 bool foreachCallee(function_ref<
bool(Function *)> CB)
const override {
12679 return isValidState() && AllCalleesKnown &&
all_of(AssumedCallees, CB);
12684 DenseMap<Function *, std::optional<bool>> FilterResults;
12688 SmallSetVector<Function *, 4> PotentialCallees;
12692 SmallSetVector<Function *, 4> AssumedCallees;
12696 bool AllCalleesKnown =
true;
12703struct AAInvariantLoadPointerImpl
12704 :
public StateWrapper<BitIntegerState<uint8_t, 15>,
12705 AAInvariantLoadPointer> {
12709 IS_NOALIAS = 1 << 0,
12712 IS_NOEFFECT = 1 << 1,
12714 IS_LOCALLY_INVARIANT = 1 << 2,
12716 IS_LOCALLY_CONSTRAINED = 1 << 3,
12718 IS_BEST_STATE = IS_NOALIAS | IS_NOEFFECT | IS_LOCALLY_INVARIANT |
12719 IS_LOCALLY_CONSTRAINED,
12721 static_assert(getBestState() == IS_BEST_STATE,
"Unexpected best state");
12724 StateWrapper<BitIntegerState<uint8_t, 15>, AAInvariantLoadPointer>;
12728 AAInvariantLoadPointerImpl(
const IRPosition &IRP, Attributor &
A)
12731 bool isKnownInvariant()
const final {
12732 return isKnownLocallyInvariant() && isKnown(IS_LOCALLY_CONSTRAINED);
12735 bool isKnownLocallyInvariant()
const final {
12736 if (isKnown(IS_LOCALLY_INVARIANT))
12738 return isKnown(IS_NOALIAS | IS_NOEFFECT);
12741 bool isAssumedInvariant()
const final {
12742 return isAssumedLocallyInvariant() && isAssumed(IS_LOCALLY_CONSTRAINED);
12745 bool isAssumedLocallyInvariant()
const final {
12746 if (isAssumed(IS_LOCALLY_INVARIANT))
12748 return isAssumed(IS_NOALIAS | IS_NOEFFECT);
12755 if (requiresNoAlias() && !isAssumed(IS_NOALIAS))
12756 return indicatePessimisticFixpoint();
12760 Changed |= updateLocalInvariance(
A);
12766 if (!isKnownInvariant())
12767 return ChangeStatus::UNCHANGED;
12770 const Value *Ptr = &getAssociatedValue();
12771 const auto TagInvariantLoads = [&](
const Use &
U,
bool &) {
12772 if (
U.get() != Ptr)
12780 if (!
A.isRunOn(
I->getFunction()))
12783 if (
I->hasMetadata(LLVMContext::MD_invariant_load))
12787 LI->setMetadata(LLVMContext::MD_invariant_load,
12789 Changed = ChangeStatus::CHANGED;
12794 (void)
A.checkForAllUses(TagInvariantLoads, *
this, *Ptr);
12799 const std::string getAsStr(Attributor *)
const override {
12800 if (isKnownInvariant())
12801 return "load-invariant pointer";
12802 return "non-invariant pointer";
12806 void trackStatistics()
const override {}
12810 bool requiresNoAlias()
const {
12811 switch (getPositionKind()) {
12817 case IRP_CALL_SITE:
12819 case IRP_CALL_SITE_RETURNED: {
12824 case IRP_ARGUMENT: {
12825 const Function *
F = getAssociatedFunction();
12826 assert(
F &&
"no associated function for argument");
12832 bool isExternal()
const {
12833 const Function *
F = getAssociatedFunction();
12837 getPositionKind() != IRP_CALL_SITE_RETURNED;
12841 if (isKnown(IS_NOALIAS) || !isAssumed(IS_NOALIAS))
12842 return ChangeStatus::UNCHANGED;
12845 if (
const auto *ANoAlias =
A.getOrCreateAAFor<AANoAlias>(
12846 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12847 if (ANoAlias->isKnownNoAlias()) {
12848 addKnownBits(IS_NOALIAS);
12849 return ChangeStatus::CHANGED;
12852 if (!ANoAlias->isAssumedNoAlias()) {
12853 removeAssumedBits(IS_NOALIAS);
12854 return ChangeStatus::CHANGED;
12857 return ChangeStatus::UNCHANGED;
12862 if (
const Argument *Arg = getAssociatedArgument()) {
12864 addKnownBits(IS_NOALIAS);
12865 return ChangeStatus::UNCHANGED;
12870 removeAssumedBits(IS_NOALIAS);
12871 return ChangeStatus::CHANGED;
12874 return ChangeStatus::UNCHANGED;
12878 if (isKnown(IS_NOEFFECT) || !isAssumed(IS_NOEFFECT))
12879 return ChangeStatus::UNCHANGED;
12881 if (!getAssociatedFunction())
12882 return indicatePessimisticFixpoint();
12885 return indicatePessimisticFixpoint();
12887 const auto HasNoEffectLoads = [&](
const Use &
U,
bool &) {
12889 return !LI || !LI->mayHaveSideEffects();
12891 if (!
A.checkForAllUses(HasNoEffectLoads, *
this, getAssociatedValue()))
12892 return indicatePessimisticFixpoint();
12894 if (
const auto *AMemoryBehavior =
A.getOrCreateAAFor<AAMemoryBehavior>(
12895 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12898 if (!AMemoryBehavior->isAssumedReadOnly())
12899 return indicatePessimisticFixpoint();
12901 if (AMemoryBehavior->isKnownReadOnly()) {
12902 addKnownBits(IS_NOEFFECT);
12903 return ChangeStatus::UNCHANGED;
12906 return ChangeStatus::UNCHANGED;
12909 if (
const Argument *Arg = getAssociatedArgument()) {
12911 addKnownBits(IS_NOEFFECT);
12912 return ChangeStatus::UNCHANGED;
12917 return indicatePessimisticFixpoint();
12920 return ChangeStatus::UNCHANGED;
12924 if (isKnown(IS_LOCALLY_INVARIANT) || !isAssumed(IS_LOCALLY_INVARIANT))
12925 return ChangeStatus::UNCHANGED;
12928 const auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
12929 getIRPosition(),
this, DepClassTy::REQUIRED);
12931 return ChangeStatus::UNCHANGED;
12933 bool UsedAssumedInformation =
false;
12934 const auto IsLocallyInvariantLoadIfPointer = [&](
const Value &
V) {
12935 if (!
V.getType()->isPointerTy())
12937 const auto *IsInvariantLoadPointer =
12939 DepClassTy::REQUIRED);
12941 if (!IsInvariantLoadPointer)
12944 if (IsInvariantLoadPointer->isKnownLocallyInvariant())
12946 if (!IsInvariantLoadPointer->isAssumedLocallyInvariant())
12949 UsedAssumedInformation =
true;
12952 if (!AUO->forallUnderlyingObjects(IsLocallyInvariantLoadIfPointer))
12953 return indicatePessimisticFixpoint();
12959 if (!IsLocallyInvariantLoadIfPointer(*Arg))
12960 return indicatePessimisticFixpoint();
12965 if (!UsedAssumedInformation) {
12967 addKnownBits(IS_LOCALLY_INVARIANT);
12968 return ChangeStatus::CHANGED;
12971 return ChangeStatus::UNCHANGED;
12975struct AAInvariantLoadPointerFloating final : AAInvariantLoadPointerImpl {
12976 AAInvariantLoadPointerFloating(
const IRPosition &IRP, Attributor &
A)
12977 : AAInvariantLoadPointerImpl(IRP,
A) {}
12980struct AAInvariantLoadPointerReturned final : AAInvariantLoadPointerImpl {
12981 AAInvariantLoadPointerReturned(
const IRPosition &IRP, Attributor &
A)
12982 : AAInvariantLoadPointerImpl(IRP,
A) {}
12985 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12989struct AAInvariantLoadPointerCallSiteReturned final
12990 : AAInvariantLoadPointerImpl {
12991 AAInvariantLoadPointerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12992 : AAInvariantLoadPointerImpl(IRP,
A) {}
12995 const Function *
F = getAssociatedFunction();
12996 assert(
F &&
"no associated function for return from call");
12998 if (!
F->isDeclaration() && !
F->isIntrinsic())
12999 return AAInvariantLoadPointerImpl::initialize(
A);
13004 return AAInvariantLoadPointerImpl::initialize(
A);
13006 if (
F->onlyReadsMemory() &&
F->hasNoSync())
13007 return AAInvariantLoadPointerImpl::initialize(
A);
13011 indicatePessimisticFixpoint();
13015struct AAInvariantLoadPointerArgument final : AAInvariantLoadPointerImpl {
13016 AAInvariantLoadPointerArgument(
const IRPosition &IRP, Attributor &
A)
13017 : AAInvariantLoadPointerImpl(IRP,
A) {}
13020 const Function *
F = getAssociatedFunction();
13021 assert(
F &&
"no associated function for argument");
13024 addKnownBits(IS_LOCALLY_CONSTRAINED);
13028 if (!
F->hasLocalLinkage())
13029 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
13033struct AAInvariantLoadPointerCallSiteArgument final
13034 : AAInvariantLoadPointerImpl {
13035 AAInvariantLoadPointerCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13036 : AAInvariantLoadPointerImpl(IRP,
A) {}
13043template <
typename InstType>
13044static bool makeChange(Attributor &
A, InstType *MemInst,
const Use &U,
13045 Value *OriginalValue, PointerType *NewPtrTy,
13046 bool UseOriginalValue) {
13047 if (
U.getOperandNo() != InstType::getPointerOperandIndex())
13050 if (MemInst->isVolatile()) {
13051 auto *
TTI =
A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(
13052 *MemInst->getFunction());
13053 unsigned NewAS = NewPtrTy->getPointerAddressSpace();
13058 if (UseOriginalValue) {
13059 A.changeUseAfterManifest(
const_cast<Use &
>(U), *OriginalValue);
13063 Instruction *CastInst =
new AddrSpaceCastInst(OriginalValue, NewPtrTy);
13065 A.changeUseAfterManifest(
const_cast<Use &
>(U), *CastInst);
13069struct AAAddressSpaceImpl :
public AAAddressSpace {
13070 AAAddressSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13071 : AAAddressSpace(IRP,
A) {}
13074 assert(isValidState() &&
"the AA is invalid");
13075 return AssumedAddressSpace;
13080 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13081 "Associated value is not a pointer");
13083 if (!
A.getInfoCache().getFlatAddressSpace().has_value()) {
13084 indicatePessimisticFixpoint();
13088 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13089 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13090 if (AS != FlatAS) {
13091 [[maybe_unused]]
bool R = takeAddressSpace(AS);
13092 assert(R &&
"The take should happen");
13093 indicateOptimisticFixpoint();
13098 uint32_t OldAddressSpace = AssumedAddressSpace;
13099 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13101 auto CheckAddressSpace = [&](
Value &
Obj) {
13107 unsigned ObjAS =
Obj.getType()->getPointerAddressSpace();
13108 if (ObjAS != FlatAS)
13109 return takeAddressSpace(ObjAS);
13123 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(*F);
13125 if (AssumedAS != ~0U)
13126 return takeAddressSpace(AssumedAS);
13130 return takeAddressSpace(FlatAS);
13133 auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(getIRPosition(),
this,
13134 DepClassTy::REQUIRED);
13135 if (!AUO->forallUnderlyingObjects(CheckAddressSpace))
13136 return indicatePessimisticFixpoint();
13138 return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED
13139 : ChangeStatus::CHANGED;
13146 if (NewAS == InvalidAddressSpace ||
13148 return ChangeStatus::UNCHANGED;
13150 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13152 Value *AssociatedValue = &getAssociatedValue();
13153 Value *OriginalValue = peelAddrspacecast(AssociatedValue, FlatAS);
13156 PointerType::get(getAssociatedType()->
getContext(), NewAS);
13157 bool UseOriginalValue =
13162 auto Pred = [&](
const Use &
U,
bool &) {
13163 if (
U.get() != AssociatedValue)
13174 makeChange(
A, LI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13177 makeChange(
A, SI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13180 makeChange(
A, RMW, U, OriginalValue, NewPtrTy, UseOriginalValue);
13183 makeChange(
A, CmpX, U, OriginalValue, NewPtrTy, UseOriginalValue);
13190 (void)
A.checkForAllUses(Pred, *
this, getAssociatedValue(),
13193 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13197 const std::string getAsStr(Attributor *
A)
const override {
13198 if (!isValidState())
13199 return "addrspace(<invalid>)";
13200 return "addrspace(" +
13201 (AssumedAddressSpace == InvalidAddressSpace
13203 : std::to_string(AssumedAddressSpace)) +
13208 uint32_t AssumedAddressSpace = InvalidAddressSpace;
13210 bool takeAddressSpace(uint32_t AS) {
13211 if (AssumedAddressSpace == InvalidAddressSpace) {
13212 AssumedAddressSpace = AS;
13215 return AssumedAddressSpace == AS;
13218 static Value *peelAddrspacecast(
Value *V,
unsigned FlatAS) {
13220 assert(
I->getSrcAddressSpace() != FlatAS &&
13221 "there should not be flat AS -> non-flat AS");
13222 return I->getPointerOperand();
13225 if (
C->getOpcode() == Instruction::AddrSpaceCast) {
13226 assert(
C->getOperand(0)->getType()->getPointerAddressSpace() !=
13228 "there should not be flat AS -> non-flat AS X");
13229 return C->getOperand(0);
13235struct AAAddressSpaceFloating final : AAAddressSpaceImpl {
13236 AAAddressSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13237 : AAAddressSpaceImpl(IRP,
A) {}
13239 void trackStatistics()
const override {
13244struct AAAddressSpaceReturned final : AAAddressSpaceImpl {
13245 AAAddressSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13246 : AAAddressSpaceImpl(IRP,
A) {}
13252 (void)indicatePessimisticFixpoint();
13255 void trackStatistics()
const override {
13260struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl {
13261 AAAddressSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13262 : AAAddressSpaceImpl(IRP,
A) {}
13264 void trackStatistics()
const override {
13269struct AAAddressSpaceArgument final : AAAddressSpaceImpl {
13270 AAAddressSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13271 : AAAddressSpaceImpl(IRP,
A) {}
13276struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl {
13277 AAAddressSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13278 : AAAddressSpaceImpl(IRP,
A) {}
13284 (void)indicatePessimisticFixpoint();
13287 void trackStatistics()
const override {
13302struct AANoAliasAddrSpaceImpl :
public AANoAliasAddrSpace {
13303 AANoAliasAddrSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13304 : AANoAliasAddrSpace(IRP,
A) {}
13307 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13308 "Associated value is not a pointer");
13312 std::optional<unsigned> FlatAS =
A.getInfoCache().getFlatAddressSpace();
13313 if (!FlatAS.has_value()) {
13314 indicatePessimisticFixpoint();
13320 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13321 if (AS != *FlatAS) {
13323 indicateOptimisticFixpoint();
13328 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13329 uint32_t OldAssumed = getAssumed();
13331 auto CheckAddressSpace = [&](
Value &
Obj) {
13335 unsigned AS =
Obj.getType()->getPointerAddressSpace();
13339 removeAS(
Obj.getType()->getPointerAddressSpace());
13343 const AAUnderlyingObjects *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
13344 getIRPosition(),
this, DepClassTy::REQUIRED);
13346 return indicatePessimisticFixpoint();
13348 return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
13349 : ChangeStatus::CHANGED;
13354 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13356 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13357 if (AS != FlatAS ||
Map.empty())
13358 return ChangeStatus::UNCHANGED;
13360 LLVMContext &Ctx = getAssociatedValue().getContext();
13361 MDNode *NoAliasASNode =
nullptr;
13362 MDBuilder MDB(Ctx);
13364 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13367 unsigned Upper =
I.stop();
13368 unsigned Lower =
I.start();
13369 if (!NoAliasASNode) {
13370 NoAliasASNode = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13373 MDNode *ASRange = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13377 Value *AssociatedValue = &getAssociatedValue();
13380 auto AddNoAliasAttr = [&](
const Use &
U,
bool &) {
13381 if (
U.get() != AssociatedValue)
13384 if (!Inst || Inst->
hasMetadata(LLVMContext::MD_noalias_addrspace))
13391 Inst->
setMetadata(LLVMContext::MD_noalias_addrspace, NoAliasASNode);
13395 (void)
A.checkForAllUses(AddNoAliasAttr, *
this, *AssociatedValue,
13397 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13401 const std::string getAsStr(Attributor *
A)
const override {
13402 if (!isValidState())
13403 return "<invalid>";
13405 raw_string_ostream OS(Str);
13406 OS <<
"CanNotBeAddrSpace(";
13407 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13408 unsigned Upper =
I.stop();
13409 unsigned Lower =
I.start();
13410 OS <<
' ' <<
'[' <<
Upper <<
',' <<
Lower + 1 <<
')';
13417 void removeAS(
unsigned AS) {
13418 RangeMap::iterator
I =
Map.find(AS);
13420 if (
I !=
Map.end()) {
13421 unsigned Upper =
I.stop();
13422 unsigned Lower =
I.start();
13426 if (AS != ~((
unsigned)0) && AS + 1 <=
Upper)
13428 if (AS != 0 &&
Lower <= AS - 1)
13433 void resetASRanges(Attributor &
A) {
13435 Map.insert(0,
A.getInfoCache().getMaxAddrSpace(),
true);
13439struct AANoAliasAddrSpaceFloating final : AANoAliasAddrSpaceImpl {
13440 AANoAliasAddrSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13441 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13443 void trackStatistics()
const override {
13448struct AANoAliasAddrSpaceReturned final : AANoAliasAddrSpaceImpl {
13449 AANoAliasAddrSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13450 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13452 void trackStatistics()
const override {
13457struct AANoAliasAddrSpaceCallSiteReturned final : AANoAliasAddrSpaceImpl {
13458 AANoAliasAddrSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13459 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13461 void trackStatistics()
const override {
13466struct AANoAliasAddrSpaceArgument final : AANoAliasAddrSpaceImpl {
13467 AANoAliasAddrSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13468 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13470 void trackStatistics()
const override {
13475struct AANoAliasAddrSpaceCallSiteArgument final : AANoAliasAddrSpaceImpl {
13476 AANoAliasAddrSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13477 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13479 void trackStatistics()
const override {
13486struct AAAllocationInfoImpl :
public AAAllocationInfo {
13487 AAAllocationInfoImpl(
const IRPosition &IRP, Attributor &
A)
13488 : AAAllocationInfo(IRP,
A) {}
13490 std::optional<TypeSize> getAllocatedSize()
const override {
13491 assert(isValidState() &&
"the AA is invalid");
13492 return AssumedAllocatedSize;
13495 std::optional<TypeSize> findInitialAllocationSize(Instruction *
I,
13496 const DataLayout &
DL) {
13499 switch (
I->getOpcode()) {
13500 case Instruction::Alloca: {
13505 return std::nullopt;
13511 const IRPosition &IRP = getIRPosition();
13516 return indicatePessimisticFixpoint();
13518 bool IsKnownNoCapture;
13520 A,
this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture))
13521 return indicatePessimisticFixpoint();
13523 const AAPointerInfo *PI =
13524 A.getOrCreateAAFor<AAPointerInfo>(IRP, *
this, DepClassTy::REQUIRED);
13527 return indicatePessimisticFixpoint();
13530 return indicatePessimisticFixpoint();
13532 const DataLayout &
DL =
A.getDataLayout();
13533 const auto AllocationSize = findInitialAllocationSize(
I,
DL);
13536 if (!AllocationSize)
13537 return indicatePessimisticFixpoint();
13541 if (*AllocationSize == 0)
13542 return indicatePessimisticFixpoint();
13548 return indicatePessimisticFixpoint();
13550 if (BinSize == 0) {
13551 auto NewAllocationSize = std::make_optional<TypeSize>(0,
false);
13552 if (!changeAllocationSize(NewAllocationSize))
13553 return ChangeStatus::UNCHANGED;
13554 return ChangeStatus::CHANGED;
13558 const auto &It = PI->
begin();
13561 if (It->first.Offset != 0)
13562 return indicatePessimisticFixpoint();
13564 uint64_t SizeOfBin = It->first.Offset + It->first.Size;
13566 if (SizeOfBin >= *AllocationSize)
13567 return indicatePessimisticFixpoint();
13569 auto NewAllocationSize = std::make_optional<TypeSize>(SizeOfBin * 8,
false);
13571 if (!changeAllocationSize(NewAllocationSize))
13572 return ChangeStatus::UNCHANGED;
13574 return ChangeStatus::CHANGED;
13580 assert(isValidState() &&
13581 "Manifest should only be called if the state is valid.");
13585 auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
13587 unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
13589 switch (
I->getOpcode()) {
13591 case Instruction::Alloca: {
13595 Type *CharType = Type::getInt8Ty(
I->getContext());
13597 auto *NumBytesToValue =
13598 ConstantInt::get(
I->getContext(), APInt(32, NumBytesToAllocate));
13601 insertPt = std::next(insertPt);
13602 AllocaInst *NewAllocaInst =
13607 return ChangeStatus::CHANGED;
13615 return ChangeStatus::UNCHANGED;
13619 const std::string getAsStr(Attributor *
A)
const override {
13620 if (!isValidState())
13621 return "allocationinfo(<invalid>)";
13622 return "allocationinfo(" +
13623 (AssumedAllocatedSize == HasNoAllocationSize
13625 : std::to_string(AssumedAllocatedSize->getFixedValue())) +
13630 std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
13634 bool changeAllocationSize(std::optional<TypeSize>
Size) {
13635 if (AssumedAllocatedSize == HasNoAllocationSize ||
13636 AssumedAllocatedSize !=
Size) {
13637 AssumedAllocatedSize =
Size;
13644struct AAAllocationInfoFloating : AAAllocationInfoImpl {
13645 AAAllocationInfoFloating(
const IRPosition &IRP, Attributor &
A)
13646 : AAAllocationInfoImpl(IRP,
A) {}
13648 void trackStatistics()
const override {
13653struct AAAllocationInfoReturned : AAAllocationInfoImpl {
13654 AAAllocationInfoReturned(
const IRPosition &IRP, Attributor &
A)
13655 : AAAllocationInfoImpl(IRP,
A) {}
13661 (void)indicatePessimisticFixpoint();
13664 void trackStatistics()
const override {
13669struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl {
13670 AAAllocationInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13671 : AAAllocationInfoImpl(IRP,
A) {}
13673 void trackStatistics()
const override {
13678struct AAAllocationInfoArgument : AAAllocationInfoImpl {
13679 AAAllocationInfoArgument(
const IRPosition &IRP, Attributor &
A)
13680 : AAAllocationInfoImpl(IRP,
A) {}
13682 void trackStatistics()
const override {
13687struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl {
13688 AAAllocationInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13689 : AAAllocationInfoImpl(IRP,
A) {}
13694 (void)indicatePessimisticFixpoint();
13697 void trackStatistics()
const override {
13746#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \
13747 case IRPosition::PK: \
13748 llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");
13750#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \
13751 case IRPosition::PK: \
13752 AA = new (A.Allocator) CLASS##SUFFIX(IRP, A); \
13756#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13757 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13758 CLASS *AA = nullptr; \
13759 switch (IRP.getPositionKind()) { \
13760 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13761 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13762 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13763 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13764 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13765 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13766 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13767 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13772#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13773 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13774 CLASS *AA = nullptr; \
13775 switch (IRP.getPositionKind()) { \
13776 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13777 SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \
13778 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13779 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13780 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13781 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13782 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13783 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13788#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS) \
13789 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13790 CLASS *AA = nullptr; \
13791 switch (IRP.getPositionKind()) { \
13792 SWITCH_PK_CREATE(CLASS, IRP, POS, SUFFIX) \
13794 llvm_unreachable("Cannot create " #CLASS " for position otherthan " #POS \
13800#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13801 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13802 CLASS *AA = nullptr; \
13803 switch (IRP.getPositionKind()) { \
13804 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13805 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13806 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13807 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13808 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13809 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13810 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13811 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13816#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13817 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13818 CLASS *AA = nullptr; \
13819 switch (IRP.getPositionKind()) { \
13820 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13821 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13822 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13823 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13824 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13825 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13826 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13827 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13832#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13833 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13834 CLASS *AA = nullptr; \
13835 switch (IRP.getPositionKind()) { \
13836 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13837 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13838 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13839 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13840 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13841 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13842 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13843 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13895#undef CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION
13896#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
13897#undef CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION
13898#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
13899#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
13900#undef CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION
13901#undef SWITCH_PK_CREATE
13902#undef SWITCH_PK_INV
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file implements a class to represent arbitrary precision integral constant values and operations...
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis false
This file contains the simple types necessary to represent the attributes associated with functions a...
#define STATS_DECLTRACK(NAME, TYPE, MSG)
static std::optional< Constant * > askForAssumedConstant(Attributor &A, const AbstractAttribute &QueryingAA, const IRPosition &IRP, Type &Ty)
static cl::opt< unsigned, true > MaxPotentialValues("attributor-max-potential-values", cl::Hidden, cl::desc("Maximum number of potential values to be " "tracked for each position."), cl::location(llvm::PotentialConstantIntValuesState::MaxPotentialValues), cl::init(7))
static void clampReturnedValueStates(Attributor &A, const AAType &QueryingAA, StateType &S, const IRPosition::CallBaseContext *CBContext=nullptr)
Clamp the information known for all returned values of a function (identified by QueryingAA) into S.
#define STATS_DECLTRACK_FN_ATTR(NAME)
#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static cl::opt< int > MaxPotentialValuesIterations("attributor-max-potential-values-iterations", cl::Hidden, cl::desc("Maximum number of iterations we keep dismantling potential values."), cl::init(64))
#define STATS_DECLTRACK_CS_ATTR(NAME)
#define PIPE_OPERATOR(CLASS)
static bool mayBeInCycle(const CycleInfo *CI, const Instruction *I, bool HeaderOnly, Cycle **CPtr=nullptr)
#define STATS_DECLTRACK_ARG_ATTR(NAME)
static const Value * stripAndAccumulateOffsets(Attributor &A, const AbstractAttribute &QueryingAA, const Value *Val, const DataLayout &DL, APInt &Offset, bool GetMinOffset, bool AllowNonInbounds, bool UseAssumed=false)
#define STATS_DECLTRACK_CSRET_ATTR(NAME)
static cl::opt< bool > ManifestInternal("attributor-manifest-internal", cl::Hidden, cl::desc("Manifest Attributor internal string attributes."), cl::init(false))
static Value * constructPointer(Value *Ptr, int64_t Offset, IRBuilder< NoFolder > &IRB)
Helper function to create a pointer based on Ptr, and advanced by Offset bytes.
#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
#define BUILD_STAT_NAME(NAME, TYPE)
static bool isDenselyPacked(Type *Ty, const DataLayout &DL)
Checks if a type could have padding bytes.
#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static const Value * getMinimalBaseOfPointer(Attributor &A, const AbstractAttribute &QueryingAA, const Value *Ptr, int64_t &BytesOffset, const DataLayout &DL, bool AllowNonInbounds=false)
#define STATS_DECLTRACK_FNRET_ATTR(NAME)
#define STATS_DECLTRACK_CSARG_ATTR(NAME)
#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS)
#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static cl::opt< int > MaxHeapToStackSize("max-heap-to-stack-size", cl::init(128), cl::Hidden)
#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
#define STATS_DECLTRACK_FLOATING_ATTR(NAME)
#define STATS_DECL(NAME, TYPE, MSG)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool isReachableImpl(SmallVectorImpl< BasicBlock * > &Worklist, const StopSetT &StopSet, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet, const DominatorTree *DT, const LoopInfo *LI, const CycleInfo *CI)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file declares an analysis pass that computes CycleInfo for LLVM IR, specialized from GenericCycl...
static uint64_t align(uint64_t Size)
DXIL Forward Handle Accesses
This file defines DenseMapInfo traits for DenseMap.
This file defines the DenseMap class.
static Value * getCondition(Instruction *I)
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
static unsigned getAddressSpace(const Value *V, unsigned MaxLookup)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
static StringRef getName(Value *V)
dot regions Print regions of function to dot true view regions View regions of function(with no function bodies)"
Remove Loads Into Fake Uses
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
std::pair< BasicBlock *, BasicBlock * > Edge
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
This file defines generic set operations that may be used on set's of different types,...
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static SymbolRef::Type getType(const Symbol *Sym)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type.
static unsigned getSize(unsigned Kind)
LLVM_ABI AACallGraphNode * operator*() const
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A trivial helper function to check to see if the specified pointers are no-alias.
Class for arbitrary precision integers.
int64_t getSExtValue() const
Get sign extended value.
CallBase * getInstruction() const
Return the underlying instruction.
bool isCallbackCall() const
Return true if this ACS represents a callback call.
bool isDirectCall() const
Return true if this ACS represents a direct call.
static LLVM_ABI void getCallbackUses(const CallBase &CB, SmallVectorImpl< const Use * > &CallbackUses)
Add operand uses of CB that represent callback uses into CallbackUses.
int getCallArgOperandNo(Argument &Arg) const
Return the operand index of the underlying instruction associated with Arg.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
unsigned getAddressSpace() const
Return the address space for the allocation.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
This class represents an incoming formal argument to a Function.
LLVM_ABI bool hasNoAliasAttr() const
Return true if this argument has the noalias attribute.
LLVM_ABI bool onlyReadsMemory() const
Return true if this argument has the readonly or readnone attribute.
LLVM_ABI bool hasPointeeInMemoryValueAttr() const
Return true if this argument has the byval, sret, inalloca, preallocated, or byref attribute.
LLVM_ABI bool hasReturnedAttr() const
Return true if this argument has the returned attribute.
LLVM_ABI bool hasByValAttr() const
Return true if this argument has the byval attribute.
const Function * getParent() const
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
Functions, function parameters, and return types can have attributes to indicate how they should be t...
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
LLVM_ABI FPClassTest getNoFPClass() const
Return the FPClassTest for nofpclass.
LLVM_ABI Attribute::AttrKind getKindAsEnum() const
Return the attribute's kind as an enum (Attribute::AttrKind).
LLVM_ABI MemoryEffects getMemoryEffects() const
Returns memory effects.
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
static LLVM_ABI Attribute getWithCaptureInfo(LLVMContext &Context, CaptureInfo CI)
static bool isEnumAttrKind(AttrKind Kind)
bool isValid() const
Return true if the attribute is any kind of attribute.
LLVM_ABI CaptureInfo getCaptureInfo() const
Returns information from captures attribute.
LLVM Basic Block Representation.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Instruction & front() const
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
BinaryOps getOpcode() const
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
Value * getCalledOperand() const
const Use & getCalledOperandUse() const
Attribute getFnAttr(StringRef Kind) const
Get the attribute of a given kind for the function.
const Use & getArgOperandUse(unsigned i) const
Wrappers for getting the Use of a call argument.
LLVM_ABI std::optional< ConstantRange > getRange() const
If this return value has a range attribute, return the value range of the argument.
Value * getArgOperand(unsigned i) const
bool isBundleOperand(unsigned Idx) const
Return true if the operand at index Idx is a bundle operand.
bool isConvergent() const
Determine if the invoke is convergent.
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static CaptureInfo none()
Create CaptureInfo that does not capture any components of the pointer.
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
LLVM_ABI bool isIntegerCast() const
There are several places where we need to know if a cast instruction only deals with integer source a...
Type * getDestTy() const
Return the destination type, as a convenience.
bool isEquality() const
Determine if this is an equals/not equals predicate.
bool isFalseWhenEqual() const
This is just a convenience.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
bool isTrueWhenEqual() const
This is just a convenience.
Predicate getPredicate() const
Return the predicate for this instruction.
Conditional Branch instruction.
Value * getCondition() const
BasicBlock * getSuccessor(unsigned i) const
static LLVM_ABI Constant * getExtractElement(Constant *Vec, Constant *Idx, Type *OnlyIfReducedTy=nullptr)
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
This class represents a range of values.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
LLVM_ABI bool isEmptySet() const
Return true if this set contains no members.
bool isSingleElement() const
Return true if this set contains exactly one member.
static LLVM_ABI ConstantRange makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other)
Produce the smallest range such that all values that may satisfy the given predicate with any value c...
const APInt & getUpper() const
Return the upper value for this range.
LLVM_ABI bool contains(const APInt &Val) const
Return true if the specified value is in the set.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
const BasicBlock & getEntryBlock() const
iterator_range< arg_iterator > args()
const Function & getFunction() const
Argument * getArg(unsigned i) const
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
CycleT * getCycle(const BlockT *Block) const
Find the innermost cycle containing a given block.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasLocalLinkage() const
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
Value * CreatePtrAdd(Value *Ptr, Value *Offset, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI bool isLifetimeStartOrEnd() const LLVM_READONLY
Return true if the instruction is a llvm.lifetime.start or llvm.lifetime.end marker.
bool mayReadOrWriteMemory() const
Return true if this instruction may read or write memory.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
bool hasMetadata() const
Return true if this instruction has any metadata attached to it.
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI BasicBlock * getSuccessor(unsigned Idx) const LLVM_READONLY
Return the specified successor. This instruction must be a terminator.
LLVM_ABI bool mayHaveSideEffects() const LLVM_READONLY
Return true if the instruction may have side effects.
bool isTerminator() const
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This is an important class for using LLVM in a threaded context.
LLVM_ABI ConstantRange getConstantRange(Value *V, Instruction *CxtI, bool UndefAllowed)
Return the ConstantRange constraint that is known to hold for the specified value at the specified in...
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static LLVM_ABI MDNode * getMostGenericRange(MDNode *A, MDNode *B)
static MemoryEffectsBase readOnly()
bool doesNotAccessMemory() const
Whether this function accesses no memory.
static MemoryEffectsBase argMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase inaccessibleMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
bool onlyAccessesInaccessibleMem() const
Whether this function only (at most) accesses inaccessible memory.
ModRefInfo getModRef(Location Loc) const
Get ModRefInfo for the given Location.
bool onlyAccessesArgPointees() const
Whether this function only (at most) accesses argument memory.
bool onlyReadsMemory() const
Whether this function only (at most) reads memory.
static MemoryEffectsBase writeOnly()
static MemoryEffectsBase inaccessibleOrArgMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase none()
bool onlyAccessesInaccessibleOrArgMem() const
Whether this function only (at most) accesses argument and inaccessible memory.
static MemoryEffectsBase unknown()
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static SizeOffsetValue unknown()
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Value * getReturnValue() const
Convenience accessor. Returns null if there is no return value.
LLVM_ABI const SCEV * getSCEVAtScope(const SCEV *S, const Loop *L)
Return a SCEV expression for the specified value at the specified scope in the program.
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI unsigned getSmallConstantMaxTripCount(const Loop *L, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Returns the upper bound of the loop trip count as a normal unsigned value.
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
TypeSize getElementOffset(unsigned Idx) const
TypeSize getElementOffsetInBits(unsigned Idx) const
Class to represent struct types.
unsigned getNumElements() const
Random access to the elements.
Type * getElementType(unsigned N) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isPointerTy() const
True if this is an instance of PointerType.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
bool isPtrOrPtrVectorTy() const
Return true if this is a pointer type or a vector of pointer types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
bool isVoidTy() const
Return true if this is 'void'.
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
BasicBlock * getSuccessor(unsigned i=0) const
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
User * getUser() const
Returns the User that contains this Use.
const Use & getOperandUse(unsigned i) const
LLVM_ABI bool isDroppable() const
A droppable user is a user for which uses can be dropped without affecting correctness and should be ...
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
unsigned getNumOperands() const
ValueT lookup(const KeyT &Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
static constexpr uint64_t MaximumAlignment
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
LLVM_ABI const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr, bool LookThroughIntToPtr=false) const
Accumulate the constant offset this value has compared to a base pointer.
static constexpr unsigned MaxAlignmentExponent
The maximum alignment for instructions.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
constexpr ScalarTy getFixedValue() const
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
SetVector< Function * >::iterator I
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
LLVM_ABI bool isAssumedReadNone(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readnone.
LLVM_ABI bool isAssumedReadOnly(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readonly.
raw_ostream & operator<<(raw_ostream &OS, const RangeTy &R)
LLVM_ABI std::optional< Value * > combineOptionalValuesInAAValueLatice(const std::optional< Value * > &A, const std::optional< Value * > &B, Type *Ty)
Return the combination of A and B such that the result is a possible value of both.
LLVM_ABI bool isValidAtPosition(const ValueAndContext &VAC, InformationCache &InfoCache)
Return true if the value of VAC is a valid at the position of VAC, that is a constant,...
LLVM_ABI bool isAssumedThreadLocalObject(Attributor &A, Value &Obj, const AbstractAttribute &QueryingAA)
Return true if Obj is assumed to be a thread local object.
LLVM_ABI bool isGPUConstantAddressSpace(const Module &M, unsigned AS)
Check if the given address space AS corresponds to a GPU constant address space for the target triple...
LLVM_ABI bool isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA, const Value &V, bool ForAnalysisOnly=true)
Return true if V is dynamically unique, that is, there are no two "instances" of V at runtime with di...
LLVM_ABI bool getPotentialCopiesOfStoredValue(Attributor &A, StoreInst &SI, SmallSetVector< Value *, 4 > &PotentialCopies, const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, bool OnlyExact=false)
Collect all potential values of the one stored by SI into PotentialCopies.
LLVM_ABI bool isGPUSharedAddressSpace(const Module &M, unsigned AS)
Check if the given address space AS corresponds to a GPU shared address space for the target triple i...
LLVM_ABI bool isGPULocalAddressSpace(const Module &M, unsigned AS)
Check if the given address space AS corresponds to a GPU local/private address space for the target t...
SmallPtrSet< Instruction *, 4 > InstExclusionSetTy
LLVM_ABI bool isGPU(const Module &M)
Return true iff M target a GPU (and we can use GPU AS reasoning).
ValueScope
Flags to distinguish intra-procedural queries from potentially inter-procedural queries.
LLVM_ABI bool isValidInScope(const Value &V, const Function *Scope)
Return true if V is a valid value in Scope, that is a constant or an instruction/argument of Scope.
LLVM_ABI bool isPotentiallyReachable(Attributor &A, const Instruction &FromI, const Instruction &ToI, const AbstractAttribute &QueryingAA, const AA::InstExclusionSetTy *ExclusionSet=nullptr, std::function< bool(const Function &F)> GoBackwardsCB=nullptr)
Return true if ToI is potentially reachable from FromI without running into any instruction in Exclus...
LLVM_ABI bool isNoSyncInst(Attributor &A, const Instruction &I, const AbstractAttribute &QueryingAA)
Return true if I is a nosync instruction.
bool hasAssumedIRAttr(Attributor &A, const AbstractAttribute *QueryingAA, const IRPosition &IRP, DepClassTy DepClass, bool &IsKnown, bool IgnoreSubsumingPositions=false, const AAType **AAPtr=nullptr)
Helper to avoid creating an AA for IR Attributes that might already be set.
LLVM_ABI bool getPotentiallyLoadedValues(Attributor &A, LoadInst &LI, SmallSetVector< Value *, 4 > &PotentialValues, SmallSetVector< Instruction *, 4 > &PotentialValueOrigins, const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, bool OnlyExact=false)
Collect all potential values LI could read into PotentialValues.
LLVM_ABI Value * getWithType(Value &V, Type &Ty)
Try to convert V to type Ty without introducing new instructions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
@ Unsupported
This operation is completely unsupported on the target.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
@ CE
Windows NT (Windows on ARM)
@ Valid
The data is already valid.
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
unsigned combineHashValue(unsigned a, unsigned b)
Simplistic combination of 32-bit hash values into 32-bit hash values.
ElementType
The element type of an SRV or UAV resource.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
@ User
could "use" a pointer
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< UseNode * > Use
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)
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.
RelativeUniformCounterPtr Values
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
auto pred_end(const MachineBasicBlock *BB)
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
LLVM_ABI bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI)
Return true if this is a call to an allocation function that does not have side effects that we are r...
APFloat abs(APFloat X)
Returns the absolute value of the argument.
LLVM_ABI raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
LLVM_ABI Value * getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI)
Gets the alignment argument for an aligned_alloc-like function, using either built-in knowledge based...
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
LLVM_ABI Value * simplifyInstructionWithOperands(Instruction *I, ArrayRef< Value * > NewOps, const SimplifyQuery &Q)
Like simplifyInstruction but the operands of I are replaced with NewOps.
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
LLVM_ABI bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(const CallBase *Call, bool MustPreserveOffset)
{launder,strip}.invariant.group returns pointer that aliases its argument, and it only captures point...
LLVM_ABI bool isNoAliasCall(const Value *V)
Return true if this pointer is returned by a noalias function.
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
LLVM_ABI bool isSafeToSpeculativelyExecute(const Instruction *I, const Instruction *CtxI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr, bool UseVariableInfo=true, bool IgnoreUBImplyingAttrs=true)
Return true if the instruction does not have any effects besides calculating the result and does not ...
bool isa_and_nonnull(const Y &Val)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI ConstantRange getConstantRangeFromMetadata(const MDNode &RangeMD)
Parse out a conservative ConstantRange from !range metadata.
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI Value * simplifyInstruction(Instruction *I, const SimplifyQuery &Q)
See if we can compute a simplified version of this instruction.
auto dyn_cast_or_null(const Y &Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
PotentialValuesState< std::pair< AA::ValueAndContext, AA::ValueScope > > PotentialLLVMValuesState
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI bool NullPointerIsDefined(const Function *F, unsigned AS=0)
Check whether null pointer dereferencing is considered undefined behavior for a given function or an ...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
LLVM_ABI bool wouldInstructionBeTriviallyDead(const Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction would have no side effects if it was not used.
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI CallBase & promoteCall(CallBase &CB, Function *Callee, CastInst **RetBitCast=nullptr)
Promote the given indirect call site to unconditionally call Callee.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI bool hasAssumption(const Function &F, const KnownAssumptionString &AssumptionStr)
Return true if F has the assumption AssumptionStr attached.
LLVM_ABI RetainedKnowledge getKnowledgeFromUse(const Use *U, ArrayRef< Attribute::AttrKind > AttrKinds)
Return a valid Knowledge associated to the Use U if its Attribute kind is in AttrKinds.
@ Success
The lock was released successfully.
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth=0)
Return true if the given value is known to be non-zero when defined.
AtomicOrdering
Atomic ordering for LLVM's memory model.
PotentialValuesState< APInt > PotentialConstantIntValuesState
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
InterleavedRange< Range > interleaved_array(const Range &R, StringRef Separator=", ")
Output range R as an array of interleaved elements.
ChangeStatus clampStateAndIndicateChange< DerefState >(DerefState &S, const DerefState &R)
void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, RemapFlags Flags=RF_None, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr, const MetadataPredicate *IdentityMD=nullptr)
Convert the instruction operands from referencing the current values into those specified by VM.
DWARFExpression::Operation Op
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI Value * getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI)
If this if a call to a free function, return the freed operand.
ChangeStatus clampStateAndIndicateChange(StateType &S, const StateType &R)
Helper function to clamp a state S of type StateType with the information in R and indicate/return if...
constexpr unsigned BitWidth
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
auto pred_begin(const MachineBasicBlock *BB)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
LLVM_ABI std::optional< APInt > getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, function_ref< const Value *(const Value *)> Mapper=[](const Value *V) { return V;})
Return the size of the requested allocation.
LLVM_ABI DenseSet< StringRef > getAssumptions(const Function &F)
Return the set of all assumptions for the function F.
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
LLVM_ABI Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
@ OPTIONAL
The target may be valid if the source is not.
@ NONE
Do not track a dependence between source and target.
@ REQUIRED
The target cannot be valid if the source is not.
LLVM_ABI UseCaptureInfo DetermineUseCaptureKind(const Use &U, const Value *Base)
Determine what kind of capture behaviour U may exhibit.
LLVM_ABI Value * simplifyCmpInst(CmpPredicate Predicate, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a CmpInst, fold the result or return null.
LLVM_ABI bool mayContainIrreducibleControl(const Function &F, const LoopInfo *LI)
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool capturesNothing(CaptureComponents CC)
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
bool capturesAnyProvenance(CaptureComponents CC)
constexpr StringRef AssumptionAttrKey
The key we use for assumption attributes.
constexpr bool isCallableCC(CallingConv::ID CC)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
A type to track pointer/struct usage and accesses for AAPointerInfo.
bool forallInterferingAccesses(AA::RangeTy Range, F CB) const
See AAPointerInfo::forallInterferingAccesses.
AAPointerInfo::const_bin_iterator end() const
ChangeStatus addAccess(Attributor &A, const AAPointerInfo::RangeList &Ranges, Instruction &I, std::optional< Value * > Content, AAPointerInfo::AccessKind Kind, Type *Ty, Instruction *RemoteI=nullptr)
Add a new Access to the state at offset Offset and with size Size.
DenseMap< const Instruction *, SmallVector< unsigned > > RemoteIMap
AAPointerInfo::const_bin_iterator begin() const
AAPointerInfo::OffsetInfo ReturnedOffsets
Flag to determine if the underlying pointer is reaching a return statement in the associated function...
State & operator=(State &&R)
State(State &&SIS)=default
const AAPointerInfo::Access & getAccess(unsigned Index) const
SmallVector< AAPointerInfo::Access > AccessList
bool isAtFixpoint() const override
See AbstractState::isAtFixpoint().
bool forallInterferingAccesses(Instruction &I, F CB, AA::RangeTy &Range) const
See AAPointerInfo::forallInterferingAccesses.
static State getWorstState(const State &SIS)
Return the worst possible representable state.
int64_t numOffsetBins() const
AAPointerInfo::OffsetBinsTy OffsetBins
ChangeStatus indicateOptimisticFixpoint() override
See AbstractState::indicateOptimisticFixpoint().
State & operator=(const State &R)
ChangeStatus indicatePessimisticFixpoint() override
See AbstractState::indicatePessimisticFixpoint().
const State & getAssumed() const
static State getBestState(const State &SIS)
Return the best possible representable state.
bool isValidState() const override
See AbstractState::isValidState().
----------------—AAIntraFnReachability Attribute-----------------------—
ReachabilityQueryInfo(const ReachabilityQueryInfo &RQI)
unsigned Hash
Precomputed hash for this RQI.
const Instruction * From
Start here,.
Reachable Result
and remember if it worked:
ReachabilityQueryInfo(const Instruction *From, const ToTy *To)
ReachabilityQueryInfo(Attributor &A, const Instruction &From, const ToTy &To, const AA::InstExclusionSetTy *ES, bool MakeUnique)
Constructor replacement to ensure unique and stable sets are used for the cache.
const ToTy * To
reach this place,
const AA::InstExclusionSetTy * ExclusionSet
without going through any of these instructions,
unsigned computeHashValue() const
An abstract interface for address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all align attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Align getKnownAlign() const
Return known alignment.
static LLVM_ABI const char ID
An abstract attribute for getting assumption information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract state for querying live call edges.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for specializing "dynamic" components of denormal_fpenv to a known denormal mod...
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all dereferenceable attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for llvm::GlobalValue information interference.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for indirect call information interference.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface to track if a value leaves it's defining function instance.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for computing reachability between functions.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool canReach(Attributor &A, const Function &Fn) const
If the function represented by this possition can reach Fn.
virtual bool instructionCanReach(Attributor &A, const Instruction &Inst, const Function &Fn, const AA::InstExclusionSetTy *ExclusionSet=nullptr) const =0
Can Inst reach Fn.
An abstract interface to determine reachability of point A to B.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for identifying pointers from which loads can be marked invariant.
static LLVM_ABI const char ID
Unique ID (due to the unique address).
An abstract interface for liveness abstract attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for memory access kind related attributes (readnone/readonly/writeonly).
bool isAssumedReadOnly() const
Return true if we assume that the underlying value is not accessed (=written) in its respective scope...
bool isKnownReadNone() const
Return true if we know that the underlying value is not read or accessed in its respective scope.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool isAssumedReadNone() const
Return true if we assume that the underlying value is not read or accessed in its respective scope.
An abstract interface for all memory location attributes (readnone/argmemonly/inaccessiblememonly/ina...
static LLVM_ABI std::string getMemoryLocationsAsStr(MemoryLocationsKind MLK)
Return the locations encoded by MLK as a readable string.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
StateType::base_t MemoryLocationsKind
An abstract interface for all nonnull attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for potential address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all noalias attributes.
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all nocapture attributes.
@ NO_CAPTURE_MAYBE_RETURNED
If we do not capture the value in memory or through integers we can only communicate it back as a der...
@ NO_CAPTURE
If we do not capture the value in memory, through integers, or as a derived pointer we know it is not...
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool isAssumedNoCaptureMaybeReturned() const
Return true if we assume that the underlying value is not captured in its respective scope but we all...
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI void determineFunctionCaptureCapabilities(const IRPosition &IRP, const Function &F, BitIntegerState &State)
Update State according to the capture capabilities of F for position IRP.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for nofree.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for norecurse.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for noreturn.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isAlignedBarrier(const CallBase &CB, bool ExecutedAligned)
Helper function to determine if CB is an aligned (GPU) barrier.
static LLVM_ABI bool isNonRelaxedAtomic(const Instruction *I)
Helper function used to determine whether an instruction is non-relaxed atomic.
An abstract interface for all noundef attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for determining the necessity of the convergent attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all nonnull attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See AbstractAttribute::isImpliedByIR(...).
A helper containing a list of offsets computed for a Use.
A container for a list of ranges.
static void set_difference(const RangeList &L, const RangeList &R, RangeList &D)
Copy ranges from L that are not in R, into D.
An abstract interface for struct information.
virtual bool reachesReturn() const =0
OffsetBinsTy::const_iterator const_bin_iterator
virtual const_bin_iterator begin() const =0
DenseMap< AA::RangeTy, SmallSet< unsigned, 4 > > OffsetBinsTy
static LLVM_ABI const char ID
Unique ID (due to the unique address)
virtual int64_t numOffsetBins() const =0
An abstract interface for potential values analysis.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI Value * getSingleValue(Attributor &A, const AbstractAttribute &AA, const IRPosition &IRP, SmallVectorImpl< AA::ValueAndContext > &Values)
Extract the single value in Values if any.
An abstract interface for privatizability.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for undefined behavior.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for getting all assumption underlying objects.
virtual bool forallUnderlyingObjects(function_ref< bool(Value &)> Pred, AA::ValueScope Scope=AA::Interprocedural) const =0
Check Pred on all underlying objects in Scope collected so far.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for range value analysis.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for value simplify abstract attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for willreturn.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Helper to represent an access offset and size, with logic to deal with uncertainty and check for over...
static constexpr int64_t Unknown
static RangeTy getUnknown()
const Instruction * getCtxI() const
Base struct for all "concrete attribute" deductions.
void print(raw_ostream &OS) const
Helper functions, for debug purposes only.
virtual StateType & getState()=0
Return the internal abstract state for inspection.
An interface to query the internal state of an abstract attribute.
virtual bool isAtFixpoint() const =0
Return if this abstract state is fixed, thus does not need to be updated if information changes as it...
virtual bool isValidState() const =0
Return if this abstract state is in a valid state.
Helper for AA::PointerInfo::Access DenseMap/Set usage ignoring everythign but the instruction.
static unsigned getHashValue(const Access &A)
AAPointerInfo::Access Access
DenseMapInfo< Instruction * > Base
static bool isEqual(const Access &LHS, const Access &RHS)
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
std::function< void( const ArgumentReplacementInfo &, Function &, Function::arg_iterator)> CalleeRepairCBTy
Callee repair callback type.
const Argument & getReplacedArg() const
std::function< void(const ArgumentReplacementInfo &, AbstractCallSite, SmallVectorImpl< Value * > &)> ACSRepairCBTy
Abstract call site (ACS) repair callback type.
The fixpoint analysis framework that orchestrates the attribute deduction.
std::function< std::optional< Value * >( const IRPosition &, const AbstractAttribute *, bool &)> SimplifictionCallbackTy
Register CB as a simplification callback.
Specialization of the integer state for a bit-wise encoding.
BitIntegerState & addKnownBits(base_t Bits)
Add the bits in BitsEncoding to the "known bits".
Simple wrapper for a single bit (boolean) state.
static constexpr DenormalFPEnv getDefault()
static unsigned getHashValue(const Access &A)
AAPointerInfo::Access Access
static bool isEqual(const Access &LHS, const Access &RHS)
static bool isEqual(const AA::RangeTy &A, const AA::RangeTy B)
static unsigned getHashValue(const AA::RangeTy &Range)
DenseMapInfo< std::pair< const Instruction *, const ToTy * > > PairDMI
static bool isEqual(const ReachabilityQueryInfo< ToTy > *LHS, const ReachabilityQueryInfo< ToTy > *RHS)
DenseMapInfo< const AA::InstExclusionSetTy * > InstSetDMI
static unsigned getHashValue(const ReachabilityQueryInfo< ToTy > *RQI)
An information struct used to provide DenseMap with the various necessary components for a given valu...
State for dereferenceable attribute.
IncIntegerState DerefBytesState
State representing for dereferenceable bytes.
ChangeStatus manifest(Attributor &A) override
See AbstractAttribute::manifest(...).
Helper to describe and deal with positions in the LLVM-IR.
Function * getAssociatedFunction() const
Return the associated function, if any.
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
static const IRPosition returned(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the returned value of F.
LLVM_ABI Argument * getAssociatedArgument() const
Return the associated argument, if any.
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
int getCalleeArgNo() const
Return the callee argument number of the associated value if it is an argument or call site argument,...
static const IRPosition inst(const Instruction &I, const CallBaseContext *CBContext=nullptr)
Create a position describing the instruction I.
static const IRPosition callsite_argument(const CallBase &CB, unsigned ArgNo)
Create a position describing the argument of CB at position ArgNo.
@ IRP_ARGUMENT
An attribute for a function argument.
@ IRP_RETURNED
An attribute for the function return value.
@ IRP_CALL_SITE
An attribute for a call site (function scope).
@ IRP_CALL_SITE_RETURNED
An attribute for a call site return value.
@ IRP_FUNCTION
An attribute for a function (scope).
@ IRP_CALL_SITE_ARGUMENT
An attribute for a call site argument.
@ IRP_INVALID
An invalid position.
Instruction * getCtxI() const
Return the context instruction, if any.
static const IRPosition argument(const Argument &Arg, const CallBaseContext *CBContext=nullptr)
Create a position describing the argument Arg.
Type * getAssociatedType() const
Return the type this abstract attribute is associated with.
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
const CallBaseContext * getCallBaseContext() const
Get the call base context from the position.
Value & getAssociatedValue() const
Return the value this abstract attribute is associated with.
Value & getAnchorValue() const
Return the value this abstract attribute is anchored with.
int getCallSiteArgNo() const
Return the call site argument number of the associated value if it is an argument or call site argume...
static const IRPosition function_scope(const IRPosition &IRP, const CallBaseContext *CBContext=nullptr)
Create a position with function scope matching the "context" of IRP.
Kind getPositionKind() const
Return the associated position kind.
bool isArgumentPosition() const
Return true if the position is an argument or call site argument.
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
Function * getAnchorScope() const
Return the Function surrounding the anchor value.
ConstantRange getKnown() const
Return the known state encoding.
ConstantRange getAssumed() const
Return the assumed state encoding.
base_t getAssumed() const
Return the assumed state encoding.
static constexpr base_t getWorstState()
Helper that allows to insert a new assumption string in the known assumption set by creating a (stati...
FPClassTest KnownFPClasses
Floating-point classes the value could be one of.
A "must be executed context" for a given program point PP is the set of instructions,...
iterator & end()
Return an universal end iterator.
bool findInContextOf(const Instruction *I, const Instruction *PP)
Helper to look for I in the context of PP.
iterator & begin(const Instruction *PP)
Return an iterator to explore the context around PP.
bool checkForAllContext(const Instruction *PP, function_ref< bool(const Instruction *)> Pred)
}
static unsigned MaxPotentialValues
Helper to tie a abstract state implementation to an abstract attribute.
StateType & getState() override
See AbstractAttribute::getState(...).
bool isPassthrough() const
CaptureComponents ResultCC
Components captured by the return value of the user of this Use.
LLVM_ABI bool unionAssumed(std::optional< Value * > Other)
Merge Other into the currently assumed simplified value.
std::optional< Value * > SimplifiedAssociatedValue
An assumed simplified value.
Type * Ty
The type of the original value.