54#include "llvm/IR/IntrinsicsAMDGPU.h"
55#include "llvm/IR/IntrinsicsNVPTX.h"
82#define DEBUG_TYPE "attributor"
86 cl::desc(
"Manifest Attributor internal string attributes."),
99 cl::desc(
"Maximum number of potential values to be "
100 "tracked for each position."),
105 "attributor-max-potential-values-iterations",
cl::Hidden,
107 "Maximum number of iterations we keep dismantling potential values."),
110STATISTIC(NumAAs,
"Number of abstract attributes created");
111STATISTIC(NumIndirectCallsPromoted,
"Number of indirect calls promoted");
126#define BUILD_STAT_MSG_IR_ATTR(TYPE, NAME) \
127 ("Number of " #TYPE " marked '" #NAME "'")
128#define BUILD_STAT_NAME(NAME, TYPE) NumIR##TYPE##_##NAME
129#define STATS_DECL_(NAME, MSG) STATISTIC(NAME, MSG);
130#define STATS_DECL(NAME, TYPE, MSG) \
131 STATS_DECL_(BUILD_STAT_NAME(NAME, TYPE), MSG);
132#define STATS_TRACK(NAME, TYPE) ++(BUILD_STAT_NAME(NAME, TYPE));
133#define STATS_DECLTRACK(NAME, TYPE, MSG) \
134 {STATS_DECL(NAME, TYPE, MSG) STATS_TRACK(NAME, TYPE)}
135#define STATS_DECLTRACK_ARG_ATTR(NAME) \
136 STATS_DECLTRACK(NAME, Arguments, BUILD_STAT_MSG_IR_ATTR(arguments, NAME))
137#define STATS_DECLTRACK_CSARG_ATTR(NAME) \
138 STATS_DECLTRACK(NAME, CSArguments, \
139 BUILD_STAT_MSG_IR_ATTR(call site arguments, NAME))
140#define STATS_DECLTRACK_FN_ATTR(NAME) \
141 STATS_DECLTRACK(NAME, Function, BUILD_STAT_MSG_IR_ATTR(functions, NAME))
142#define STATS_DECLTRACK_CS_ATTR(NAME) \
143 STATS_DECLTRACK(NAME, CS, BUILD_STAT_MSG_IR_ATTR(call site, NAME))
144#define STATS_DECLTRACK_FNRET_ATTR(NAME) \
145 STATS_DECLTRACK(NAME, FunctionReturn, \
146 BUILD_STAT_MSG_IR_ATTR(function returns, NAME))
147#define STATS_DECLTRACK_CSRET_ATTR(NAME) \
148 STATS_DECLTRACK(NAME, CSReturn, \
149 BUILD_STAT_MSG_IR_ATTR(call site returns, NAME))
150#define STATS_DECLTRACK_FLOATING_ATTR(NAME) \
151 STATS_DECLTRACK(NAME, Floating, \
152 ("Number of floating values known to be '" #NAME "'"))
157#define PIPE_OPERATOR(CLASS) \
158 raw_ostream &operator<<(raw_ostream &OS, const CLASS &AA) { \
159 return OS << static_cast<const AbstractAttribute &>(AA); \
216 bool HeaderOnly,
Cycle **CPtr =
nullptr) {
219 auto *BB =
I->getParent();
225 return !HeaderOnly || BB ==
C->getHeader();
236 if (
DL.getTypeSizeInBits(Ty) !=
DL.getTypeAllocSizeInBits(Ty))
261 StartPos +=
DL.getTypeAllocSizeInBits(ElTy);
271 bool AllowVolatile) {
272 if (!AllowVolatile &&
I->isVolatile())
276 return LI->getPointerOperand();
280 return SI->getPointerOperand();
284 return CXI->getPointerOperand();
288 return RMWI->getPointerOperand();
310 bool GetMinOffset,
bool AllowNonInbounds,
311 bool UseAssumed =
false) {
313 auto AttributorAnalysis = [&](
Value &V,
APInt &ROffset) ->
bool {
320 if (!ValueConstantRangeAA)
324 if (
Range.isFullSet())
330 ROffset =
Range.getSignedMin();
332 ROffset =
Range.getSignedMax();
343 const Value *Ptr, int64_t &BytesOffset,
348 true, AllowNonInbounds);
356template <
typename AAType,
typename StateType =
typename AAType::StateType,
358 bool RecurseForSelectAndPHI =
true>
360 Attributor &
A,
const AAType &QueryingAA, StateType &S,
362 LLVM_DEBUG(
dbgs() <<
"[Attributor] Clamp return value states for "
363 << QueryingAA <<
" into " << S <<
"\n");
365 assert((QueryingAA.getIRPosition().getPositionKind() ==
367 QueryingAA.getIRPosition().getPositionKind() ==
369 "Can only clamp returned value states for a function returned or call "
370 "site returned position!");
374 std::optional<StateType>
T;
377 auto CheckReturnValue = [&](
Value &RV) ->
bool {
391 <<
" AA: " <<
AA->getAsStr(&
A) <<
" @ " << RVPos <<
"\n");
392 const StateType &AAS =
AA->getState();
394 T = StateType::getBestState(AAS);
396 LLVM_DEBUG(
dbgs() <<
"[Attributor] AA State: " << AAS <<
" RV State: " <<
T
398 return T->isValidState();
401 if (!
A.checkForAllReturnedValues(CheckReturnValue, QueryingAA,
403 RecurseForSelectAndPHI))
404 S.indicatePessimisticFixpoint();
411template <
typename AAType,
typename BaseType,
412 typename StateType =
typename BaseType::StateType,
413 bool PropagateCallBaseContext =
false,
415 bool RecurseForSelectAndPHI =
true>
416struct AAReturnedFromReturnedValues :
public BaseType {
417 AAReturnedFromReturnedValues(
const IRPosition &IRP, Attributor &
A)
422 StateType S(StateType::getBestState(this->getState()));
424 RecurseForSelectAndPHI>(
426 PropagateCallBaseContext ? this->getCallBaseContext() : nullptr);
435template <
typename AAType,
typename StateType =
typename AAType::StateType,
437static void clampCallSiteArgumentStates(
Attributor &
A,
const AAType &QueryingAA,
439 LLVM_DEBUG(
dbgs() <<
"[Attributor] Clamp call site argument states for "
440 << QueryingAA <<
" into " << S <<
"\n");
442 assert(QueryingAA.getIRPosition().getPositionKind() ==
444 "Can only clamp call site argument states for an argument position!");
448 std::optional<StateType>
T;
451 unsigned ArgNo = QueryingAA.getIRPosition().getCallSiteArgNo();
471 LLVM_DEBUG(
dbgs() <<
"[Attributor] ACS: " << *ACS.getInstruction()
472 <<
" AA: " <<
AA->getAsStr(&
A) <<
" @" << ACSArgPos
474 const StateType &AAS =
AA->getState();
476 T = StateType::getBestState(AAS);
478 LLVM_DEBUG(
dbgs() <<
"[Attributor] AA State: " << AAS <<
" CSA State: " <<
T
480 return T->isValidState();
483 bool UsedAssumedInformation =
false;
484 if (!
A.checkForAllCallSites(CallSiteCheck, QueryingAA,
true,
485 UsedAssumedInformation))
486 S.indicatePessimisticFixpoint();
493template <
typename AAType,
typename BaseType,
494 typename StateType =
typename AAType::StateType,
496bool getArgumentStateFromCallBaseContext(
Attributor &
A,
500 "Expected an 'argument' position !");
506 assert(ArgNo >= 0 &&
"Invalid Arg No!");
520 const StateType &CBArgumentState =
521 static_cast<const StateType &
>(
AA->getState());
523 LLVM_DEBUG(
dbgs() <<
"[Attributor] Briding Call site context to argument"
524 <<
"Position:" << Pos <<
"CB Arg state:" << CBArgumentState
528 State ^= CBArgumentState;
533template <
typename AAType,
typename BaseType,
534 typename StateType =
typename AAType::StateType,
535 bool BridgeCallBaseContext =
false,
537struct AAArgumentFromCallSiteArguments :
public BaseType {
538 AAArgumentFromCallSiteArguments(
const IRPosition &IRP, Attributor &
A)
543 StateType S = StateType::getBestState(this->getState());
545 if (BridgeCallBaseContext) {
547 getArgumentStateFromCallBaseContext<AAType,
BaseType, StateType,
549 A, *
this, this->getIRPosition(), S);
553 clampCallSiteArgumentStates<AAType, StateType, IRAttributeKind>(
A, *
this,
563template <
typename AAType,
typename BaseType,
564 typename StateType =
typename BaseType::StateType,
565 bool IntroduceCallBaseContext =
false,
567struct AACalleeToCallSite :
public BaseType {
568 AACalleeToCallSite(
const IRPosition &IRP, Attributor &
A) :
BaseType(IRP,
A) {}
572 auto IRPKind = this->getIRPosition().getPositionKind();
575 "Can only wrap function returned positions for call site "
576 "returned positions!");
577 auto &S = this->getState();
580 if (IntroduceCallBaseContext)
581 LLVM_DEBUG(
dbgs() <<
"[Attributor] Introducing call base context:" << CB
586 for (
const Function *Callee : Callees) {
590 IntroduceCallBaseContext ? &CB :
nullptr)
592 *
Callee, IntroduceCallBaseContext ? &CB : nullptr);
594 if (Attribute::isEnumAttrKind(IRAttributeKind)) {
597 A,
this, FnPos, DepClassTy::REQUIRED, IsKnown))
603 A.getAAFor<AAType>(*
this, FnPos, DepClassTy::REQUIRED);
607 if (S.isAtFixpoint())
608 return S.isValidState();
612 if (!
A.checkForAllCallees(CalleePred, *
this, CB))
613 return S.indicatePessimisticFixpoint();
619template <
class AAType,
typename StateType =
typename AAType::StateType>
625 auto EIt = Explorer.
begin(CtxI), EEnd = Explorer.
end(CtxI);
626 for (
unsigned u = 0;
u <
Uses.size(); ++
u) {
630 if (Found &&
AA.followUseInMBEC(
A, U, UserI, State))
645template <
class AAType,
typename StateType =
typename AAType::StateType>
646static void followUsesInMBEC(AAType &
AA,
Attributor &
A, StateType &S,
648 const Value &Val =
AA.getIRPosition().getAssociatedValue();
653 A.getInfoCache().getMustBeExecutedContextExplorer();
659 for (
const Use &U : Val.
uses())
662 followUsesInContext<AAType>(
AA,
A, *Explorer, &CtxI,
Uses, S);
664 if (S.isAtFixpoint())
670 if (Br->isConditional())
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;
799 R.indicatePessimisticFixpoint();
816 BS.indicateOptimisticFixpoint();
822 BS.indicatePessimisticFixpoint();
892 template <
typename F>
899 if (!
Range.mayOverlap(ItRange))
901 bool IsExact =
Range == ItRange && !
Range.offsetOrSizeAreUnknown();
902 for (
auto Index : It.getSecond()) {
912 template <
typename F>
923 for (
unsigned Index : LocalList->getSecond()) {
926 if (
Range.offsetAndSizeAreUnknown())
942 RemoteI = RemoteI ? RemoteI : &
I;
946 bool AccExists =
false;
948 for (
auto Index : LocalList) {
950 if (
A.getLocalInst() == &
I) {
959 <<
"[AAPointerInfo] Inserting access in new offset bins\n";);
961 for (
auto Key : ToAdd) {
968 AccessList.emplace_back(&
I, RemoteI, Ranges, Content, Kind, Ty);
970 "New Access should have been at AccIndex");
971 LocalList.push_back(AccIndex);
980 auto Before = Current;
982 if (Current == Before)
985 auto &ExistingRanges = Before.getRanges();
986 auto &NewRanges = Current.getRanges();
993 <<
"[AAPointerInfo] Removing access from old offset bins\n";);
1000 "Expected bin to actually contain the Access.");
1001 Bin.erase(AccIndex);
1022struct AAPointerInfoImpl
1023 :
public StateWrapper<AA::PointerInfo::State, AAPointerInfo> {
1028 const std::string getAsStr(
Attributor *
A)
const override {
1029 return std::string(
"PointerInfo ") +
1030 (isValidState() ? (std::string(
"#") +
1031 std::to_string(OffsetBins.size()) +
" bins")
1036 [](int64_t O) {
return std::to_string(O); }),
1044 return AAPointerInfo::manifest(
A);
1047 const_bin_iterator
begin()
const override {
return State::begin(); }
1048 const_bin_iterator
end()
const override {
return State::end(); }
1049 int64_t numOffsetBins()
const override {
return State::numOffsetBins(); }
1050 bool reachesReturn()
const override {
1051 return !ReturnedOffsets.isUnassigned();
1053 void addReturnedOffsetsTo(OffsetInfo &OI)
const override {
1054 if (ReturnedOffsets.isUnknown()) {
1059 OffsetInfo MergedOI;
1060 for (
auto Offset : ReturnedOffsets) {
1061 OffsetInfo TmpOI = OI;
1063 MergedOI.merge(TmpOI);
1065 OI = std::move(MergedOI);
1068 ChangeStatus setReachesReturn(
const OffsetInfo &ReachedReturnedOffsets) {
1069 if (ReturnedOffsets.isUnknown())
1070 return ChangeStatus::UNCHANGED;
1071 if (ReachedReturnedOffsets.isUnknown()) {
1072 ReturnedOffsets.setUnknown();
1073 return ChangeStatus::CHANGED;
1075 if (ReturnedOffsets.merge(ReachedReturnedOffsets))
1076 return ChangeStatus::CHANGED;
1077 return ChangeStatus::UNCHANGED;
1080 bool forallInterferingAccesses(
1082 function_ref<
bool(
const AAPointerInfo::Access &,
bool)> CB)
1084 return State::forallInterferingAccesses(
Range, CB);
1087 bool forallInterferingAccesses(
1088 Attributor &
A,
const AbstractAttribute &QueryingAA, Instruction &
I,
1089 bool FindInterferingWrites,
bool FindInterferingReads,
1090 function_ref<
bool(
const Access &,
bool)> UserCB,
bool &HasBeenWrittenTo,
1092 function_ref<
bool(
const Access &)> SkipCB)
const override {
1093 HasBeenWrittenTo =
false;
1095 SmallPtrSet<const Access *, 8> DominatingWrites;
1103 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
1105 bool AllInSameNoSyncFn = IsAssumedNoSync;
1106 bool InstIsExecutedByInitialThreadOnly =
1107 ExecDomainAA && ExecDomainAA->isExecutedByInitialThreadOnly(
I);
1114 bool InstIsExecutedInAlignedRegion =
1115 FindInterferingReads && ExecDomainAA &&
1116 ExecDomainAA->isExecutedInAlignedRegion(
A,
I);
1118 if (InstIsExecutedInAlignedRegion || InstIsExecutedByInitialThreadOnly)
1119 A.recordDependence(*ExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1121 InformationCache &InfoCache =
A.getInfoCache();
1122 bool IsThreadLocalObj =
1131 auto CanIgnoreThreadingForInst = [&](
const Instruction &
I) ->
bool {
1132 if (IsThreadLocalObj || AllInSameNoSyncFn)
1134 const auto *FnExecDomainAA =
1135 I.getFunction() == &
Scope
1137 :
A.lookupAAFor<AAExecutionDomain>(
1140 if (!FnExecDomainAA)
1142 if (InstIsExecutedInAlignedRegion ||
1143 (FindInterferingWrites &&
1144 FnExecDomainAA->isExecutedInAlignedRegion(
A,
I))) {
1145 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1148 if (InstIsExecutedByInitialThreadOnly &&
1149 FnExecDomainAA->isExecutedByInitialThreadOnly(
I)) {
1150 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1159 auto CanIgnoreThreading = [&](
const Access &Acc) ->
bool {
1160 return CanIgnoreThreadingForInst(*Acc.getRemoteInst()) ||
1161 (Acc.getRemoteInst() != Acc.getLocalInst() &&
1162 CanIgnoreThreadingForInst(*Acc.getLocalInst()));
1166 bool IsKnownNoRecurse;
1174 bool InstInKernel =
A.getInfoCache().isKernel(Scope);
1175 bool ObjHasKernelLifetime =
false;
1176 const bool UseDominanceReasoning =
1177 FindInterferingWrites && IsKnownNoRecurse;
1178 const DominatorTree *DT =
1188 case AA::GPUAddressSpace::Shared:
1189 case AA::GPUAddressSpace::Constant:
1190 case AA::GPUAddressSpace::Local:
1202 std::function<bool(
const Function &)> IsLiveInCalleeCB;
1207 const Function *AIFn = AI->getFunction();
1208 ObjHasKernelLifetime =
A.getInfoCache().isKernel(*AIFn);
1209 bool IsKnownNoRecurse;
1212 IsKnownNoRecurse)) {
1213 IsLiveInCalleeCB = [AIFn](
const Function &Fn) {
return AIFn != &Fn; };
1218 ObjHasKernelLifetime = HasKernelLifetime(GV, *GV->getParent());
1219 if (ObjHasKernelLifetime)
1220 IsLiveInCalleeCB = [&
A](
const Function &Fn) {
1221 return !
A.getInfoCache().isKernel(Fn);
1229 auto AccessCB = [&](
const Access &Acc,
bool Exact) {
1230 Function *AccScope = Acc.getRemoteInst()->getFunction();
1231 bool AccInSameScope = AccScope == &
Scope;
1235 if (InstInKernel && ObjHasKernelLifetime && !AccInSameScope &&
1236 A.getInfoCache().isKernel(*AccScope))
1239 if (Exact && Acc.isMustAccess() && Acc.getRemoteInst() != &
I) {
1240 if (Acc.isWrite() || (
isa<LoadInst>(
I) && Acc.isWriteOrAssumption()))
1241 ExclusionSet.
insert(Acc.getRemoteInst());
1244 if ((!FindInterferingWrites || !Acc.isWriteOrAssumption()) &&
1245 (!FindInterferingReads || !Acc.isRead()))
1248 bool Dominates = FindInterferingWrites && DT && Exact &&
1249 Acc.isMustAccess() && AccInSameScope &&
1252 DominatingWrites.
insert(&Acc);
1256 AllInSameNoSyncFn &= Acc.getRemoteInst()->getFunction() == &
Scope;
1258 InterferingAccesses.
push_back({&Acc, Exact});
1261 if (!State::forallInterferingAccesses(
I, AccessCB,
Range))
1264 HasBeenWrittenTo = !DominatingWrites.
empty();
1268 for (
const Access *Acc : DominatingWrites) {
1269 if (!LeastDominatingWriteInst) {
1270 LeastDominatingWriteInst = Acc->getRemoteInst();
1271 }
else if (DT->
dominates(LeastDominatingWriteInst,
1272 Acc->getRemoteInst())) {
1273 LeastDominatingWriteInst = Acc->getRemoteInst();
1278 auto CanSkipAccess = [&](
const Access &Acc,
bool Exact) {
1279 if (SkipCB && SkipCB(Acc))
1281 if (!CanIgnoreThreading(Acc))
1287 bool ReadChecked = !FindInterferingReads;
1288 bool WriteChecked = !FindInterferingWrites;
1294 &ExclusionSet, IsLiveInCalleeCB))
1299 if (!WriteChecked) {
1301 &ExclusionSet, IsLiveInCalleeCB))
1302 WriteChecked =
true;
1316 if (!WriteChecked && HasBeenWrittenTo &&
1317 Acc.getRemoteInst()->getFunction() != &Scope) {
1319 const auto *FnReachabilityAA =
A.getAAFor<AAInterFnReachability>(
1321 if (FnReachabilityAA) {
1327 if (!FnReachabilityAA->instructionCanReach(
1328 A, *LeastDominatingWriteInst,
1329 *Acc.getRemoteInst()->getFunction(), &ExclusionSet))
1330 WriteChecked =
true;
1337 if (ReadChecked && WriteChecked)
1340 if (!DT || !UseDominanceReasoning)
1342 if (!DominatingWrites.count(&Acc))
1344 return LeastDominatingWriteInst != Acc.getRemoteInst();
1349 for (
auto &It : InterferingAccesses) {
1350 if ((!AllInSameNoSyncFn && !IsThreadLocalObj && !ExecDomainAA) ||
1351 !CanSkipAccess(*It.first, It.second)) {
1352 if (!UserCB(*It.first, It.second))
1360 const AAPointerInfo &OtherAA,
1362 using namespace AA::PointerInfo;
1364 return indicatePessimisticFixpoint();
1367 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1368 bool IsByval = OtherAAImpl.getAssociatedArgument()->hasByValAttr();
1369 Changed |= setReachesReturn(OtherAAImpl.ReturnedOffsets);
1372 const auto &State = OtherAAImpl.getState();
1373 for (
const auto &It : State) {
1374 for (
auto Index : It.getSecond()) {
1375 const auto &RAcc = State.getAccess(Index);
1376 if (IsByval && !RAcc.isRead())
1378 bool UsedAssumedInformation =
false;
1380 auto Content =
A.translateArgumentToCallSiteContent(
1381 RAcc.getContent(), CB, *
this, UsedAssumedInformation);
1382 AK =
AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW));
1383 AK =
AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST));
1385 Changed |= addAccess(
A, RAcc.getRanges(), CB, Content, AK,
1386 RAcc.getType(), RAcc.getRemoteInst());
1392 ChangeStatus translateAndAddState(Attributor &
A,
const AAPointerInfo &OtherAA,
1393 const OffsetInfo &Offsets, CallBase &CB,
1395 using namespace AA::PointerInfo;
1397 return indicatePessimisticFixpoint();
1399 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1403 const auto &State = OtherAAImpl.getState();
1404 for (
const auto &It : State) {
1405 for (
auto Index : It.getSecond()) {
1406 const auto &RAcc = State.getAccess(Index);
1407 if (!IsMustAcc && RAcc.isAssumption())
1409 for (
auto Offset : Offsets) {
1413 if (!NewRanges.isUnknown()) {
1414 NewRanges.addToAllOffsets(Offset);
1419 Changed |= addAccess(
A, NewRanges, CB, RAcc.getContent(), AK,
1420 RAcc.getType(), RAcc.getRemoteInst());
1429 void trackPointerInfoStatistics(
const IRPosition &IRP)
const {}
1432 void dumpState(raw_ostream &O) {
1433 for (
auto &It : OffsetBins) {
1434 O <<
"[" << It.first.Offset <<
"-" << It.first.Offset + It.first.Size
1435 <<
"] : " << It.getSecond().size() <<
"\n";
1436 for (
auto AccIndex : It.getSecond()) {
1437 auto &Acc = AccessList[AccIndex];
1438 O <<
" - " << Acc.getKind() <<
" - " << *Acc.getLocalInst() <<
"\n";
1439 if (Acc.getLocalInst() != Acc.getRemoteInst())
1440 O <<
" --> " << *Acc.getRemoteInst()
1442 if (!Acc.isWrittenValueYetUndetermined()) {
1444 O <<
" - c: func " << Acc.getWrittenValue()->getName()
1446 else if (Acc.getWrittenValue())
1447 O <<
" - c: " << *Acc.getWrittenValue() <<
"\n";
1449 O <<
" - c: <unknown>\n";
1456struct AAPointerInfoFloating :
public AAPointerInfoImpl {
1458 AAPointerInfoFloating(
const IRPosition &IRP, Attributor &
A)
1459 : AAPointerInfoImpl(IRP,
A) {}
1462 bool handleAccess(Attributor &
A, Instruction &
I,
1463 std::optional<Value *> Content,
AccessKind Kind,
1466 using namespace AA::PointerInfo;
1468 const DataLayout &
DL =
A.getDataLayout();
1469 TypeSize AccessSize =
DL.getTypeStoreSize(&Ty);
1478 if (!VT || VT->getElementCount().isScalable() ||
1480 (*Content)->getType() != VT ||
1481 DL.getTypeStoreSize(VT->getElementType()).isScalable()) {
1492 int64_t ElementSize =
DL.getTypeStoreSize(ElementType).getFixedValue();
1497 for (
int i = 0, e = VT->getElementCount().getFixedValue(); i != e; ++i) {
1499 ConstContent, ConstantInt::get(
Int32Ty, i));
1506 for (
auto &ElementOffset : ElementOffsets)
1507 ElementOffset += ElementSize;
1520 bool collectConstantsForGEP(Attributor &
A,
const DataLayout &
DL,
1521 OffsetInfo &UsrOI,
const OffsetInfo &PtrOI,
1522 const GEPOperator *
GEP);
1525 void trackStatistics()
const override {
1526 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1530bool AAPointerInfoFloating::collectConstantsForGEP(Attributor &
A,
1531 const DataLayout &
DL,
1533 const OffsetInfo &PtrOI,
1534 const GEPOperator *
GEP) {
1535 unsigned BitWidth =
DL.getIndexTypeSizeInBits(
GEP->getType());
1536 SmallMapVector<Value *, APInt, 4> VariableOffsets;
1539 assert(!UsrOI.isUnknown() && !PtrOI.isUnknown() &&
1540 "Don't look for constant values if the offset has already been "
1541 "determined to be unknown.");
1543 if (!
GEP->collectOffset(
DL,
BitWidth, VariableOffsets, ConstantOffset)) {
1549 << (VariableOffsets.
empty() ?
"" :
"not") <<
" constant "
1553 Union.addToAll(ConstantOffset.getSExtValue());
1558 for (
const auto &VI : VariableOffsets) {
1559 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
1561 if (!PotentialConstantsAA || !PotentialConstantsAA->isValidState()) {
1567 if (PotentialConstantsAA->undefIsContained())
1574 auto &AssumedSet = PotentialConstantsAA->getAssumedSet();
1575 if (AssumedSet.empty())
1579 for (
const auto &ConstOffset : AssumedSet) {
1580 auto CopyPerOffset =
Union;
1581 CopyPerOffset.addToAll(ConstOffset.getSExtValue() *
1582 VI.second.getZExtValue());
1583 Product.merge(CopyPerOffset);
1588 UsrOI = std::move(Union);
1592ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &
A) {
1593 using namespace AA::PointerInfo;
1595 const DataLayout &
DL =
A.getDataLayout();
1596 Value &AssociatedValue = getAssociatedValue();
1598 DenseMap<Value *, OffsetInfo> OffsetInfoMap;
1599 OffsetInfoMap[&AssociatedValue].
insert(0);
1601 auto HandlePassthroughUser = [&](
Value *Usr,
Value *CurPtr,
bool &Follow) {
1612 "CurPtr does not exist in the map!");
1614 auto &UsrOI = OffsetInfoMap[Usr];
1615 auto &PtrOI = OffsetInfoMap[CurPtr];
1616 assert(!PtrOI.isUnassigned() &&
1617 "Cannot pass through if the input Ptr was not visited!");
1623 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
1625 User *Usr =
U.getUser();
1626 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Analyze " << *CurPtr <<
" in " << *Usr
1629 "The current pointer offset should have been seeded!");
1630 assert(!OffsetInfoMap[CurPtr].isUnassigned() &&
1631 "Current pointer should be assigned");
1635 return HandlePassthroughUser(Usr, CurPtr, Follow);
1637 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled constant user " << *CE
1645 auto &UsrOI = OffsetInfoMap[Usr];
1646 auto &PtrOI = OffsetInfoMap[CurPtr];
1648 if (UsrOI.isUnknown())
1651 if (PtrOI.isUnknown()) {
1657 Follow = collectConstantsForGEP(
A,
DL, UsrOI, PtrOI,
GEP);
1663 return HandlePassthroughUser(Usr, CurPtr, Follow);
1668 if (RI->getFunction() == getAssociatedFunction()) {
1669 auto &PtrOI = OffsetInfoMap[CurPtr];
1670 Changed |= setReachesReturn(PtrOI);
1683 auto &UsrOI = PhiIt->second;
1684 auto &PtrOI = OffsetInfoMap[CurPtr];
1688 if (PtrOI.isUnknown()) {
1689 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand offset unknown "
1690 << *CurPtr <<
" in " << *
PHI <<
"\n");
1691 Follow = !UsrOI.isUnknown();
1697 if (UsrOI == PtrOI) {
1698 assert(!PtrOI.isUnassigned() &&
1699 "Cannot assign if the current Ptr was not visited!");
1700 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant (so far)");
1710 auto It = OffsetInfoMap.
find(CurPtrBase);
1711 if (It == OffsetInfoMap.
end()) {
1712 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand is too complex "
1713 << *CurPtr <<
" in " << *
PHI
1714 <<
" (base: " << *CurPtrBase <<
")\n");
1728 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
1729 *
PHI->getFunction());
1731 auto BaseOI = It->getSecond();
1732 BaseOI.addToAll(
Offset.getZExtValue());
1733 if (IsFirstPHIUser || BaseOI == UsrOI) {
1734 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant " << *CurPtr
1735 <<
" in " << *Usr <<
"\n");
1736 return HandlePassthroughUser(Usr, CurPtr, Follow);
1740 dbgs() <<
"[AAPointerInfo] PHI operand pointer offset mismatch "
1741 << *CurPtr <<
" in " << *
PHI <<
"\n");
1760 if (!handleAccess(
A, *LoadI,
nullptr, AK,
1761 OffsetInfoMap[CurPtr].Offsets,
Changed,
1767 return II->isAssumeLikeIntrinsic();
1778 }
while (FromI && FromI != ToI);
1783 auto IsValidAssume = [&](IntrinsicInst &IntrI) {
1784 if (IntrI.getIntrinsicID() != Intrinsic::assume)
1787 if (IntrI.getParent() == BB) {
1788 if (IsImpactedInRange(LoadI->getNextNode(), &IntrI))
1794 if ((*PredIt) != BB)
1799 if (SuccBB == IntrBB)
1805 if (IsImpactedInRange(LoadI->getNextNode(), BB->
getTerminator()))
1807 if (IsImpactedInRange(&IntrBB->
front(), &IntrI))
1813 std::pair<Value *, IntrinsicInst *> Assumption;
1814 for (
const Use &LoadU : LoadI->uses()) {
1816 if (!CmpI->isEquality() || !CmpI->isTrueWhenEqual())
1818 for (
const Use &CmpU : CmpI->uses()) {
1820 if (!IsValidAssume(*IntrI))
1822 int Idx = CmpI->getOperandUse(0) == LoadU;
1823 Assumption = {CmpI->getOperand(Idx), IntrI};
1828 if (Assumption.first)
1833 if (!Assumption.first || !Assumption.second)
1837 << *Assumption.second <<
": " << *LoadI
1838 <<
" == " << *Assumption.first <<
"\n");
1839 bool UsedAssumedInformation =
false;
1840 std::optional<Value *> Content =
nullptr;
1841 if (Assumption.first)
1843 A.getAssumedSimplified(*Assumption.first, *
this,
1845 return handleAccess(
1846 A, *Assumption.second, Content, AccessKind::AK_ASSUMPTION,
1847 OffsetInfoMap[CurPtr].Offsets,
Changed, *LoadI->getType());
1852 for (
auto *OtherOp : OtherOps) {
1853 if (OtherOp == CurPtr) {
1856 <<
"[AAPointerInfo] Escaping use in store like instruction " <<
I
1868 bool UsedAssumedInformation =
false;
1869 std::optional<Value *> Content =
nullptr;
1871 Content =
A.getAssumedSimplified(
1873 return handleAccess(
A,
I, Content, AK, OffsetInfoMap[CurPtr].Offsets,
1878 return HandleStoreLike(*StoreI, StoreI->getValueOperand(),
1879 *StoreI->getValueOperand()->getType(),
1880 {StoreI->getValueOperand()}, AccessKind::AK_W);
1882 return HandleStoreLike(*RMWI,
nullptr, *RMWI->getValOperand()->getType(),
1883 {RMWI->getValOperand()}, AccessKind::AK_RW);
1885 return HandleStoreLike(
1886 *CXI,
nullptr, *CXI->getNewValOperand()->getType(),
1887 {CXI->getCompareOperand(), CXI->getNewValOperand()},
1894 A.getInfoCache().getTargetLibraryInfoForFunction(*CB->
getFunction());
1899 const auto *CSArgPI =
A.getAAFor<AAPointerInfo>(
1905 Changed = translateAndAddState(
A, *CSArgPI, OffsetInfoMap[CurPtr], *CB,
1908 if (!CSArgPI->reachesReturn())
1909 return isValidState();
1912 if (!Callee ||
Callee->arg_size() <= ArgNo)
1914 bool UsedAssumedInformation =
false;
1915 auto ReturnedValue =
A.getAssumedSimplified(
1920 auto *Arg =
Callee->getArg(ArgNo);
1921 if (ReturnedArg && Arg != ReturnedArg)
1923 bool IsRetMustAcc = IsArgMustAcc && (ReturnedArg == Arg);
1924 const auto *CSRetPI =
A.getAAFor<AAPointerInfo>(
1928 OffsetInfo OI = OffsetInfoMap[CurPtr];
1929 CSArgPI->addReturnedOffsetsTo(OI);
1931 translateAndAddState(
A, *CSRetPI, OI, *CB, IsRetMustAcc) |
Changed;
1932 return isValidState();
1934 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Call user not handled " << *CB
1939 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] User not handled " << *Usr <<
"\n");
1942 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
1943 assert(OffsetInfoMap.
count(OldU) &&
"Old use should be known already!");
1944 assert(!OffsetInfoMap[OldU].isUnassigned() &&
"Old use should be assinged");
1945 if (OffsetInfoMap.
count(NewU)) {
1947 if (!(OffsetInfoMap[NewU] == OffsetInfoMap[OldU])) {
1948 dbgs() <<
"[AAPointerInfo] Equivalent use callback failed: "
1949 << OffsetInfoMap[NewU] <<
" vs " << OffsetInfoMap[OldU]
1953 return OffsetInfoMap[NewU] == OffsetInfoMap[OldU];
1956 return HandlePassthroughUser(NewU.get(), OldU.
get(), Unused);
1958 if (!
A.checkForAllUses(UsePred, *
this, AssociatedValue,
1960 true, EquivalentUseCB)) {
1961 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Check for all uses failed, abort!\n");
1962 return indicatePessimisticFixpoint();
1966 dbgs() <<
"Accesses by bin after update:\n";
1973struct AAPointerInfoReturned final : AAPointerInfoImpl {
1974 AAPointerInfoReturned(
const IRPosition &IRP, Attributor &
A)
1975 : AAPointerInfoImpl(IRP,
A) {}
1979 return indicatePessimisticFixpoint();
1983 void trackStatistics()
const override {
1984 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1988struct AAPointerInfoArgument final : AAPointerInfoFloating {
1989 AAPointerInfoArgument(
const IRPosition &IRP, Attributor &
A)
1990 : AAPointerInfoFloating(IRP,
A) {}
1993 void trackStatistics()
const override {
1994 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1998struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
1999 AAPointerInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2000 : AAPointerInfoFloating(IRP,
A) {}
2004 using namespace AA::PointerInfo;
2010 if (
auto Length =
MI->getLengthInBytes())
2011 LengthVal =
Length->getSExtValue();
2012 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
2015 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled memory intrinsic "
2017 return indicatePessimisticFixpoint();
2020 ArgNo == 0 ? AccessKind::AK_MUST_WRITE : AccessKind::AK_MUST_READ;
2022 Changed | addAccess(
A, {0, LengthVal}, *
MI,
nullptr,
Kind,
nullptr);
2025 dbgs() <<
"Accesses by bin after update:\n";
2036 Argument *Arg = getAssociatedArgument();
2040 A.getAAFor<AAPointerInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
2041 if (ArgAA && ArgAA->getState().isValidState())
2042 return translateAndAddStateFromCallee(
A, *ArgAA,
2045 return indicatePessimisticFixpoint();
2048 bool IsKnownNoCapture;
2050 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNoCapture))
2051 return indicatePessimisticFixpoint();
2053 bool IsKnown =
false;
2055 return ChangeStatus::UNCHANGED;
2058 ReadOnly ? AccessKind::AK_MAY_READ : AccessKind::AK_MAY_READ_WRITE;
2064 void trackStatistics()
const override {
2065 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2069struct AAPointerInfoCallSiteReturned final : AAPointerInfoFloating {
2070 AAPointerInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2071 : AAPointerInfoFloating(IRP,
A) {}
2074 void trackStatistics()
const override {
2075 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2083struct AANoUnwindImpl : AANoUnwind {
2084 AANoUnwindImpl(
const IRPosition &IRP, Attributor &
A) : AANoUnwind(IRP,
A) {}
2090 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2094 const std::string getAsStr(Attributor *
A)
const override {
2095 return getAssumed() ?
"nounwind" :
"may-unwind";
2101 (unsigned)Instruction::Invoke, (
unsigned)Instruction::CallBr,
2102 (unsigned)Instruction::Call, (
unsigned)Instruction::CleanupRet,
2103 (unsigned)Instruction::CatchSwitch, (
unsigned)Instruction::Resume};
2106 if (!
I.mayThrow(
true))
2110 bool IsKnownNoUnwind;
2118 bool UsedAssumedInformation =
false;
2119 if (!
A.checkForAllInstructions(CheckForNoUnwind, *
this, Opcodes,
2120 UsedAssumedInformation))
2121 return indicatePessimisticFixpoint();
2123 return ChangeStatus::UNCHANGED;
2127struct AANoUnwindFunction final :
public AANoUnwindImpl {
2128 AANoUnwindFunction(
const IRPosition &IRP, Attributor &
A)
2129 : AANoUnwindImpl(IRP,
A) {}
2136struct AANoUnwindCallSite final
2137 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl> {
2138 AANoUnwindCallSite(
const IRPosition &IRP, Attributor &
A)
2139 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl>(IRP,
A) {}
2150 case Intrinsic::nvvm_barrier_cta_sync_aligned_all:
2151 case Intrinsic::nvvm_barrier_cta_sync_aligned_count:
2152 case Intrinsic::nvvm_barrier0_and:
2153 case Intrinsic::nvvm_barrier0_or:
2154 case Intrinsic::nvvm_barrier0_popc:
2156 case Intrinsic::amdgcn_s_barrier:
2157 if (ExecutedAligned)
2180 switch (
I->getOpcode()) {
2181 case Instruction::AtomicRMW:
2184 case Instruction::Store:
2187 case Instruction::Load:
2192 "New atomic operations need to be known in the attributor.");
2204 return !
MI->isVolatile();
2220 const std::string getAsStr(Attributor *
A)
const override {
2221 return getAssumed() ?
"nosync" :
"may-sync";
2237 if (
I.mayReadOrWriteMemory())
2251 bool UsedAssumedInformation =
false;
2252 if (!
A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *
this,
2253 UsedAssumedInformation) ||
2254 !
A.checkForAllCallLikeInstructions(CheckForNoSync, *
this,
2255 UsedAssumedInformation))
2256 return indicatePessimisticFixpoint();
2261struct AANoSyncFunction final :
public AANoSyncImpl {
2262 AANoSyncFunction(
const IRPosition &IRP, Attributor &
A)
2263 : AANoSyncImpl(IRP,
A) {}
2270struct AANoSyncCallSite final : AACalleeToCallSite<AANoSync, AANoSyncImpl> {
2271 AANoSyncCallSite(
const IRPosition &IRP, Attributor &
A)
2272 : AACalleeToCallSite<AANoSync, AANoSyncImpl>(IRP,
A) {}
2282struct AANoFreeImpl :
public AANoFree {
2283 AANoFreeImpl(
const IRPosition &IRP, Attributor &
A) : AANoFree(IRP,
A) {}
2289 DepClassTy::NONE, IsKnown));
2299 DepClassTy::REQUIRED, IsKnown);
2302 bool UsedAssumedInformation =
false;
2303 if (!
A.checkForAllCallLikeInstructions(CheckForNoFree, *
this,
2304 UsedAssumedInformation))
2305 return indicatePessimisticFixpoint();
2306 return ChangeStatus::UNCHANGED;
2310 const std::string getAsStr(Attributor *
A)
const override {
2311 return getAssumed() ?
"nofree" :
"may-free";
2315struct AANoFreeFunction final :
public AANoFreeImpl {
2316 AANoFreeFunction(
const IRPosition &IRP, Attributor &
A)
2317 : AANoFreeImpl(IRP,
A) {}
2324struct AANoFreeCallSite final : AACalleeToCallSite<AANoFree, AANoFreeImpl> {
2325 AANoFreeCallSite(
const IRPosition &IRP, Attributor &
A)
2326 : AACalleeToCallSite<AANoFree, AANoFreeImpl>(IRP,
A) {}
2333struct AANoFreeFloating : AANoFreeImpl {
2334 AANoFreeFloating(
const IRPosition &IRP, Attributor &
A)
2335 : AANoFreeImpl(IRP,
A) {}
2342 const IRPosition &IRP = getIRPosition();
2347 DepClassTy::OPTIONAL, IsKnown))
2348 return ChangeStatus::UNCHANGED;
2350 Value &AssociatedValue = getIRPosition().getAssociatedValue();
2351 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
2363 DepClassTy::REQUIRED, IsKnown);
2380 if (!
A.checkForAllUses(Pred, *
this, AssociatedValue))
2381 return indicatePessimisticFixpoint();
2383 return ChangeStatus::UNCHANGED;
2388struct AANoFreeArgument final : AANoFreeFloating {
2389 AANoFreeArgument(
const IRPosition &IRP, Attributor &
A)
2390 : AANoFreeFloating(IRP,
A) {}
2397struct AANoFreeCallSiteArgument final : AANoFreeFloating {
2398 AANoFreeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2399 : AANoFreeFloating(IRP,
A) {}
2407 Argument *Arg = getAssociatedArgument();
2409 return indicatePessimisticFixpoint();
2413 DepClassTy::REQUIRED, IsKnown))
2414 return ChangeStatus::UNCHANGED;
2415 return indicatePessimisticFixpoint();
2423struct AANoFreeReturned final : AANoFreeFloating {
2424 AANoFreeReturned(
const IRPosition &IRP, Attributor &
A)
2425 : AANoFreeFloating(IRP,
A) {
2440 void trackStatistics()
const override {}
2444struct AANoFreeCallSiteReturned final : AANoFreeFloating {
2445 AANoFreeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2446 : AANoFreeFloating(IRP,
A) {}
2449 return ChangeStatus::UNCHANGED;
2460 bool IgnoreSubsumingPositions) {
2462 AttrKinds.
push_back(Attribute::NonNull);
2465 AttrKinds.
push_back(Attribute::Dereferenceable);
2466 if (
A.hasAttr(IRP, AttrKinds, IgnoreSubsumingPositions, Attribute::NonNull))
2473 if (!Fn->isDeclaration()) {
2483 bool UsedAssumedInformation =
false;
2484 if (!
A.checkForAllInstructions(
2486 Worklist.push_back({*cast<ReturnInst>(I).getReturnValue(), &I});
2490 UsedAssumedInformation,
false,
true))
2502 Attribute::NonNull)});
2507static int64_t getKnownNonNullAndDerefBytesForUse(
2508 Attributor &
A,
const AbstractAttribute &QueryingAA,
Value &AssociatedValue,
2509 const Use *U,
const Instruction *
I,
bool &IsNonNull,
bool &TrackUse) {
2512 const Value *UseV =
U->get();
2533 const DataLayout &
DL =
A.getInfoCache().getDL();
2537 U, {Attribute::NonNull, Attribute::Dereferenceable})) {
2554 bool IsKnownNonNull;
2557 IsNonNull |= IsKnownNonNull;
2560 return DerefAA ? DerefAA->getKnownDereferenceableBytes() : 0;
2564 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
2565 Loc->Size.isScalable() ||
I->isVolatile())
2571 if (
Base &&
Base == &AssociatedValue) {
2572 int64_t DerefBytes = Loc->Size.getValue() +
Offset;
2574 return std::max(int64_t(0), DerefBytes);
2581 int64_t DerefBytes = Loc->Size.getValue();
2583 return std::max(int64_t(0), DerefBytes);
2589struct AANonNullImpl : AANonNull {
2590 AANonNullImpl(
const IRPosition &IRP, Attributor &
A) : AANonNull(IRP,
A) {}
2594 Value &
V = *getAssociatedValue().stripPointerCasts();
2596 indicatePessimisticFixpoint();
2600 if (Instruction *CtxI = getCtxI())
2601 followUsesInMBEC(*
this,
A, getState(), *CtxI);
2605 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
2606 AANonNull::StateType &State) {
2607 bool IsNonNull =
false;
2608 bool TrackUse =
false;
2609 getKnownNonNullAndDerefBytesForUse(
A, *
this, getAssociatedValue(), U,
I,
2610 IsNonNull, TrackUse);
2611 State.setKnown(IsNonNull);
2616 const std::string getAsStr(Attributor *
A)
const override {
2617 return getAssumed() ?
"nonnull" :
"may-null";
2622struct AANonNullFloating :
public AANonNullImpl {
2623 AANonNullFloating(
const IRPosition &IRP, Attributor &
A)
2624 : AANonNullImpl(IRP,
A) {}
2628 auto CheckIRP = [&](
const IRPosition &IRP) {
2629 bool IsKnownNonNull;
2631 A, *
this, IRP, DepClassTy::OPTIONAL, IsKnownNonNull);
2635 bool UsedAssumedInformation =
false;
2636 Value *AssociatedValue = &getAssociatedValue();
2638 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
2643 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
2649 return AA::hasAssumedIRAttr<Attribute::NonNull>(
2650 A, this, IRPosition::value(*Op), DepClassTy::OPTIONAL,
2653 return ChangeStatus::UNCHANGED;
2657 DepClassTy::OPTIONAL, IsKnown) &&
2660 DepClassTy::OPTIONAL, IsKnown))
2661 return ChangeStatus::UNCHANGED;
2668 if (AVIRP == getIRPosition() || !CheckIRP(AVIRP))
2669 return indicatePessimisticFixpoint();
2670 return ChangeStatus::UNCHANGED;
2673 for (
const auto &VAC : Values)
2675 return indicatePessimisticFixpoint();
2677 return ChangeStatus::UNCHANGED;
2685struct AANonNullReturned final
2686 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2687 false, AANonNull::IRAttributeKind, false> {
2688 AANonNullReturned(
const IRPosition &IRP, Attributor &
A)
2689 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2694 const std::string getAsStr(Attributor *
A)
const override {
2695 return getAssumed() ?
"nonnull" :
"may-null";
2703struct AANonNullArgument final
2704 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
2705 AANonNullArgument(
const IRPosition &IRP, Attributor &
A)
2706 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP,
A) {}
2712struct AANonNullCallSiteArgument final : AANonNullFloating {
2713 AANonNullCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2714 : AANonNullFloating(IRP,
A) {}
2721struct AANonNullCallSiteReturned final
2722 : AACalleeToCallSite<AANonNull, AANonNullImpl> {
2723 AANonNullCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2724 : AACalleeToCallSite<AANonNull, AANonNullImpl>(IRP,
A) {}
2733struct AAMustProgressImpl :
public AAMustProgress {
2734 AAMustProgressImpl(
const IRPosition &IRP, Attributor &
A)
2735 : AAMustProgress(IRP,
A) {}
2741 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2746 const std::string getAsStr(Attributor *
A)
const override {
2747 return getAssumed() ?
"mustprogress" :
"may-not-progress";
2751struct AAMustProgressFunction final : AAMustProgressImpl {
2752 AAMustProgressFunction(
const IRPosition &IRP, Attributor &
A)
2753 : AAMustProgressImpl(IRP,
A) {}
2759 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnown)) {
2761 return indicateOptimisticFixpoint();
2762 return ChangeStatus::UNCHANGED;
2765 auto CheckForMustProgress = [&](AbstractCallSite ACS) {
2767 bool IsKnownMustProgress;
2769 A,
this, IPos, DepClassTy::REQUIRED, IsKnownMustProgress,
2773 bool AllCallSitesKnown =
true;
2774 if (!
A.checkForAllCallSites(CheckForMustProgress, *
this,
2777 return indicatePessimisticFixpoint();
2779 return ChangeStatus::UNCHANGED;
2783 void trackStatistics()
const override {
2789struct AAMustProgressCallSite final : AAMustProgressImpl {
2790 AAMustProgressCallSite(
const IRPosition &IRP, Attributor &
A)
2791 : AAMustProgressImpl(IRP,
A) {}
2800 bool IsKnownMustProgress;
2802 A,
this, FnPos, DepClassTy::REQUIRED, IsKnownMustProgress))
2803 return indicatePessimisticFixpoint();
2804 return ChangeStatus::UNCHANGED;
2808 void trackStatistics()
const override {
2817struct AANoRecurseImpl :
public AANoRecurse {
2818 AANoRecurseImpl(
const IRPosition &IRP, Attributor &
A) : AANoRecurse(IRP,
A) {}
2824 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2829 const std::string getAsStr(Attributor *
A)
const override {
2830 return getAssumed() ?
"norecurse" :
"may-recurse";
2834struct AANoRecurseFunction final : AANoRecurseImpl {
2835 AANoRecurseFunction(
const IRPosition &IRP, Attributor &
A)
2836 : AANoRecurseImpl(IRP,
A) {}
2842 auto CallSitePred = [&](AbstractCallSite ACS) {
2843 bool IsKnownNoRecurse;
2847 DepClassTy::NONE, IsKnownNoRecurse))
2849 return IsKnownNoRecurse;
2851 bool UsedAssumedInformation =
false;
2852 if (
A.checkForAllCallSites(CallSitePred, *
this,
true,
2853 UsedAssumedInformation)) {
2859 if (!UsedAssumedInformation)
2860 indicateOptimisticFixpoint();
2861 return ChangeStatus::UNCHANGED;
2864 const AAInterFnReachability *EdgeReachability =
2865 A.getAAFor<AAInterFnReachability>(*
this, getIRPosition(),
2866 DepClassTy::REQUIRED);
2867 if (EdgeReachability && EdgeReachability->
canReach(
A, *getAnchorScope()))
2868 return indicatePessimisticFixpoint();
2869 return ChangeStatus::UNCHANGED;
2876struct AANoRecurseCallSite final
2877 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl> {
2878 AANoRecurseCallSite(
const IRPosition &IRP, Attributor &
A)
2879 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl>(IRP,
A) {}
2889struct AANonConvergentImpl :
public AANonConvergent {
2890 AANonConvergentImpl(
const IRPosition &IRP, Attributor &
A)
2891 : AANonConvergent(IRP,
A) {}
2894 const std::string getAsStr(Attributor *
A)
const override {
2895 return getAssumed() ?
"non-convergent" :
"may-be-convergent";
2899struct AANonConvergentFunction final : AANonConvergentImpl {
2900 AANonConvergentFunction(
const IRPosition &IRP, Attributor &
A)
2901 : AANonConvergentImpl(IRP,
A) {}
2907 auto CalleeIsNotConvergent = [&](
Instruction &Inst) {
2910 if (!Callee ||
Callee->isIntrinsic()) {
2913 if (
Callee->isDeclaration()) {
2914 return !
Callee->hasFnAttribute(Attribute::Convergent);
2916 const auto *ConvergentAA =
A.getAAFor<AANonConvergent>(
2918 return ConvergentAA && ConvergentAA->isAssumedNotConvergent();
2921 bool UsedAssumedInformation =
false;
2922 if (!
A.checkForAllCallLikeInstructions(CalleeIsNotConvergent, *
this,
2923 UsedAssumedInformation)) {
2924 return indicatePessimisticFixpoint();
2926 return ChangeStatus::UNCHANGED;
2930 if (isKnownNotConvergent() &&
2931 A.hasAttr(getIRPosition(), Attribute::Convergent)) {
2932 A.removeAttrs(getIRPosition(), {Attribute::Convergent});
2933 return ChangeStatus::CHANGED;
2935 return ChangeStatus::UNCHANGED;
2945struct AAUndefinedBehaviorImpl :
public AAUndefinedBehavior {
2946 AAUndefinedBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
2947 : AAUndefinedBehavior(IRP,
A) {}
2952 const size_t UBPrevSize = KnownUBInsts.size();
2953 const size_t NoUBPrevSize = AssumedNoUBInsts.size();
2957 if (
I.isVolatile() &&
I.mayWriteToMemory())
2961 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
2970 "Expected pointer operand of memory accessing instruction");
2974 std::optional<Value *> SimplifiedPtrOp =
2975 stopOnUndefOrAssumed(
A, PtrOp, &
I);
2976 if (!SimplifiedPtrOp || !*SimplifiedPtrOp)
2978 const Value *PtrOpVal = *SimplifiedPtrOp;
2984 AssumedNoUBInsts.insert(&
I);
2996 AssumedNoUBInsts.insert(&
I);
2998 KnownUBInsts.insert(&
I);
3007 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3014 if (BrInst->isUnconditional())
3019 std::optional<Value *> SimplifiedCond =
3020 stopOnUndefOrAssumed(
A, BrInst->getCondition(), BrInst);
3021 if (!SimplifiedCond || !*SimplifiedCond)
3023 AssumedNoUBInsts.insert(&
I);
3031 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
3040 for (
unsigned idx = 0; idx < CB.
arg_size(); idx++) {
3046 if (idx >=
Callee->arg_size())
3058 bool IsKnownNoUndef;
3060 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNoUndef);
3061 if (!IsKnownNoUndef)
3063 bool UsedAssumedInformation =
false;
3064 std::optional<Value *> SimplifiedVal =
3067 if (UsedAssumedInformation)
3069 if (SimplifiedVal && !*SimplifiedVal)
3072 KnownUBInsts.insert(&
I);
3078 bool IsKnownNonNull;
3080 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNonNull);
3082 KnownUBInsts.insert(&
I);
3091 std::optional<Value *> SimplifiedRetValue =
3092 stopOnUndefOrAssumed(
A, RI.getReturnValue(), &
I);
3093 if (!SimplifiedRetValue || !*SimplifiedRetValue)
3111 bool IsKnownNonNull;
3116 KnownUBInsts.insert(&
I);
3122 bool UsedAssumedInformation =
false;
3123 A.checkForAllInstructions(InspectMemAccessInstForUB, *
this,
3124 {Instruction::Load, Instruction::Store,
3125 Instruction::AtomicCmpXchg,
3126 Instruction::AtomicRMW},
3127 UsedAssumedInformation,
3129 A.checkForAllInstructions(InspectBrInstForUB, *
this, {Instruction::Br},
3130 UsedAssumedInformation,
3132 A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *
this,
3133 UsedAssumedInformation);
3137 if (!getAnchorScope()->getReturnType()->isVoidTy()) {
3139 if (!
A.isAssumedDead(ReturnIRP,
this,
nullptr, UsedAssumedInformation)) {
3140 bool IsKnownNoUndef;
3142 A,
this, ReturnIRP, DepClassTy::NONE, IsKnownNoUndef);
3144 A.checkForAllInstructions(InspectReturnInstForUB, *
this,
3145 {Instruction::Ret}, UsedAssumedInformation,
3150 if (NoUBPrevSize != AssumedNoUBInsts.size() ||
3151 UBPrevSize != KnownUBInsts.size())
3152 return ChangeStatus::CHANGED;
3153 return ChangeStatus::UNCHANGED;
3156 bool isKnownToCauseUB(Instruction *
I)
const override {
3157 return KnownUBInsts.count(
I);
3160 bool isAssumedToCauseUB(Instruction *
I)
const override {
3167 switch (
I->getOpcode()) {
3168 case Instruction::Load:
3169 case Instruction::Store:
3170 case Instruction::AtomicCmpXchg:
3171 case Instruction::AtomicRMW:
3172 return !AssumedNoUBInsts.count(
I);
3173 case Instruction::Br: {
3175 if (BrInst->isUnconditional())
3177 return !AssumedNoUBInsts.count(
I);
3186 if (KnownUBInsts.empty())
3187 return ChangeStatus::UNCHANGED;
3188 for (Instruction *
I : KnownUBInsts)
3189 A.changeToUnreachableAfterManifest(
I);
3190 return ChangeStatus::CHANGED;
3194 const std::string getAsStr(Attributor *
A)
const override {
3195 return getAssumed() ?
"undefined-behavior" :
"no-ub";
3223 SmallPtrSet<Instruction *, 8> KnownUBInsts;
3227 SmallPtrSet<Instruction *, 8> AssumedNoUBInsts;
3238 std::optional<Value *> stopOnUndefOrAssumed(Attributor &
A,
Value *V,
3240 bool UsedAssumedInformation =
false;
3241 std::optional<Value *> SimplifiedV =
3244 if (!UsedAssumedInformation) {
3249 KnownUBInsts.insert(
I);
3250 return std::nullopt;
3257 KnownUBInsts.insert(
I);
3258 return std::nullopt;
3264struct AAUndefinedBehaviorFunction final : AAUndefinedBehaviorImpl {
3265 AAUndefinedBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
3266 : AAUndefinedBehaviorImpl(IRP,
A) {}
3269 void trackStatistics()
const override {
3270 STATS_DECL(UndefinedBehaviorInstruction, Instruction,
3271 "Number of instructions known to have UB");
3273 KnownUBInsts.size();
3284static bool mayContainUnboundedCycle(Function &
F, Attributor &
A) {
3285 ScalarEvolution *SE =
3286 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
F);
3287 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
F);
3293 for (scc_iterator<Function *> SCCI =
scc_begin(&
F); !SCCI.isAtEnd(); ++SCCI)
3294 if (SCCI.hasCycle())
3304 for (
auto *L : LI->getLoopsInPreorder()) {
3311struct AAWillReturnImpl :
public AAWillReturn {
3312 AAWillReturnImpl(
const IRPosition &IRP, Attributor &
A)
3313 : AAWillReturn(IRP,
A) {}
3319 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
3324 bool isImpliedByMustprogressAndReadonly(Attributor &
A,
bool KnownOnly) {
3325 if (!
A.hasAttr(getIRPosition(), {Attribute::MustProgress}))
3330 return IsKnown || !KnownOnly;
3336 if (isImpliedByMustprogressAndReadonly(
A,
false))
3337 return ChangeStatus::UNCHANGED;
3343 A,
this, IPos, DepClassTy::REQUIRED, IsKnown)) {
3349 bool IsKnownNoRecurse;
3351 A,
this, IPos, DepClassTy::REQUIRED, IsKnownNoRecurse);
3354 bool UsedAssumedInformation =
false;
3355 if (!
A.checkForAllCallLikeInstructions(CheckForWillReturn, *
this,
3356 UsedAssumedInformation))
3357 return indicatePessimisticFixpoint();
3359 return ChangeStatus::UNCHANGED;
3363 const std::string getAsStr(Attributor *
A)
const override {
3364 return getAssumed() ?
"willreturn" :
"may-noreturn";
3368struct AAWillReturnFunction final : AAWillReturnImpl {
3369 AAWillReturnFunction(
const IRPosition &IRP, Attributor &
A)
3370 : AAWillReturnImpl(IRP,
A) {}
3374 AAWillReturnImpl::initialize(
A);
3377 assert(
F &&
"Did expect an anchor function");
3378 if (
F->isDeclaration() || mayContainUnboundedCycle(*
F,
A))
3379 indicatePessimisticFixpoint();
3387struct AAWillReturnCallSite final
3388 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl> {
3389 AAWillReturnCallSite(
const IRPosition &IRP, Attributor &
A)
3390 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl>(IRP,
A) {}
3394 if (isImpliedByMustprogressAndReadonly(
A,
false))
3395 return ChangeStatus::UNCHANGED;
3397 return AACalleeToCallSite::updateImpl(
A);
3419 const ToTy *
To =
nullptr;
3446 if (!ES || ES->
empty()) {
3447 ExclusionSet = nullptr;
3448 }
else if (MakeUnique) {
3449 ExclusionSet =
A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ES);
3474 if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))
3476 return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);
3480#define DefineKeys(ToTy) \
3482 ReachabilityQueryInfo<ToTy> \
3483 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::EmptyKey = \
3484 ReachabilityQueryInfo<ToTy>( \
3485 DenseMapInfo<const Instruction *>::getEmptyKey(), \
3486 DenseMapInfo<const ToTy *>::getEmptyKey()); \
3488 ReachabilityQueryInfo<ToTy> \
3489 DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::TombstoneKey = \
3490 ReachabilityQueryInfo<ToTy>( \
3491 DenseMapInfo<const Instruction *>::getTombstoneKey(), \
3492 DenseMapInfo<const ToTy *>::getTombstoneKey());
3501template <
typename BaseTy,
typename ToTy>
3502struct CachedReachabilityAA :
public BaseTy {
3503 using RQITy = ReachabilityQueryInfo<ToTy>;
3505 CachedReachabilityAA(
const IRPosition &IRP, Attributor &
A) : BaseTy(IRP,
A) {}
3508 bool isQueryAA()
const override {
return true; }
3513 for (
unsigned u = 0,
e = QueryVector.size();
u <
e; ++
u) {
3514 RQITy *RQI = QueryVector[
u];
3515 if (RQI->Result == RQITy::Reachable::No &&
3517 Changed = ChangeStatus::CHANGED;
3523 bool IsTemporaryRQI) = 0;
3525 bool rememberResult(Attributor &
A,
typename RQITy::Reachable
Result,
3526 RQITy &RQI,
bool UsedExclusionSet,
bool IsTemporaryRQI) {
3531 QueryCache.erase(&RQI);
3537 if (
Result == RQITy::Reachable::Yes || !UsedExclusionSet) {
3538 RQITy PlainRQI(RQI.From, RQI.To);
3539 if (!QueryCache.count(&PlainRQI)) {
3540 RQITy *RQIPtr =
new (
A.Allocator) RQITy(RQI.From, RQI.To);
3542 QueryVector.push_back(RQIPtr);
3543 QueryCache.insert(RQIPtr);
3548 if (IsTemporaryRQI &&
Result != RQITy::Reachable::Yes && UsedExclusionSet) {
3549 assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&
3550 "Did not expect empty set!");
3551 RQITy *RQIPtr =
new (
A.Allocator)
3552 RQITy(
A, *RQI.From, *RQI.To, RQI.ExclusionSet,
true);
3553 assert(RQIPtr->Result == RQITy::Reachable::No &&
"Already reachable?");
3555 assert(!QueryCache.count(RQIPtr));
3556 QueryVector.push_back(RQIPtr);
3557 QueryCache.insert(RQIPtr);
3560 if (
Result == RQITy::Reachable::No && IsTemporaryRQI)
3561 A.registerForUpdate(*
this);
3562 return Result == RQITy::Reachable::Yes;
3565 const std::string getAsStr(Attributor *
A)
const override {
3567 return "#queries(" + std::to_string(QueryVector.size()) +
")";
3570 bool checkQueryCache(Attributor &
A, RQITy &StackRQI,
3571 typename RQITy::Reachable &
Result) {
3572 if (!this->getState().isValidState()) {
3573 Result = RQITy::Reachable::Yes;
3579 if (StackRQI.ExclusionSet) {
3580 RQITy PlainRQI(StackRQI.From, StackRQI.To);
3581 auto It = QueryCache.find(&PlainRQI);
3582 if (It != QueryCache.end() && (*It)->Result == RQITy::Reachable::No) {
3583 Result = RQITy::Reachable::No;
3588 auto It = QueryCache.find(&StackRQI);
3589 if (It != QueryCache.end()) {
3596 QueryCache.insert(&StackRQI);
3602 DenseSet<RQITy *> QueryCache;
3605struct AAIntraFnReachabilityFunction final
3606 :
public CachedReachabilityAA<AAIntraFnReachability, Instruction> {
3607 using Base = CachedReachabilityAA<AAIntraFnReachability, Instruction>;
3608 AAIntraFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
3610 DT =
A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(
3614 bool isAssumedReachable(
3615 Attributor &
A,
const Instruction &From,
const Instruction &To,
3617 auto *NonConstThis =
const_cast<AAIntraFnReachabilityFunction *
>(
this);
3621 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
3623 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
3624 return NonConstThis->isReachableImpl(
A, StackRQI,
3626 return Result == RQITy::Reachable::Yes;
3633 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3636 [&](
const auto &DeadEdge) {
3637 return LivenessAA->isEdgeDead(DeadEdge.first,
3641 return LivenessAA->isAssumedDead(BB);
3643 return ChangeStatus::UNCHANGED;
3647 return Base::updateImpl(
A);
3651 bool IsTemporaryRQI)
override {
3653 bool UsedExclusionSet =
false;
3658 while (IP && IP != &To) {
3659 if (ExclusionSet && IP != Origin && ExclusionSet->
count(IP)) {
3660 UsedExclusionSet =
true;
3668 const BasicBlock *FromBB = RQI.From->getParent();
3669 const BasicBlock *ToBB = RQI.To->getParent();
3671 "Not an intra-procedural query!");
3675 if (FromBB == ToBB &&
3676 WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
3677 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3682 if (!WillReachInBlock(ToBB->
front(), *RQI.To, RQI.ExclusionSet))
3683 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3687 SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
3688 if (RQI.ExclusionSet)
3689 for (
auto *
I : *RQI.ExclusionSet)
3690 if (
I->getFunction() == Fn)
3691 ExclusionBlocks.
insert(
I->getParent());
3694 if (ExclusionBlocks.
count(FromBB) &&
3697 return rememberResult(
A, RQITy::Reachable::No, RQI,
true, IsTemporaryRQI);
3700 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3701 if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {
3702 DeadBlocks.insert(ToBB);
3703 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3707 SmallPtrSet<const BasicBlock *, 16> Visited;
3711 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> LocalDeadEdges;
3712 while (!Worklist.
empty()) {
3714 if (!Visited.
insert(BB).second)
3716 for (
const BasicBlock *SuccBB :
successors(BB)) {
3717 if (LivenessAA && LivenessAA->isEdgeDead(BB, SuccBB)) {
3718 LocalDeadEdges.
insert({BB, SuccBB});
3723 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3726 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3729 if (ExclusionBlocks.
count(SuccBB)) {
3730 UsedExclusionSet =
true;
3737 DeadEdges.insert_range(LocalDeadEdges);
3738 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3743 void trackStatistics()
const override {}
3748 DenseSet<const BasicBlock *> DeadBlocks;
3752 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> DeadEdges;
3755 const DominatorTree *DT =
nullptr;
3763 bool IgnoreSubsumingPositions) {
3764 assert(ImpliedAttributeKind == Attribute::NoAlias &&
3765 "Unexpected attribute kind");
3771 IgnoreSubsumingPositions =
true;
3782 if (
A.hasAttr(IRP, {Attribute::ByVal, Attribute::NoAlias},
3783 IgnoreSubsumingPositions, Attribute::NoAlias))
3793 "Noalias is a pointer attribute");
3796 const std::string getAsStr(
Attributor *
A)
const override {
3797 return getAssumed() ?
"noalias" :
"may-alias";
3802struct AANoAliasFloating final : AANoAliasImpl {
3803 AANoAliasFloating(
const IRPosition &IRP, Attributor &
A)
3804 : AANoAliasImpl(IRP,
A) {}
3809 return indicatePessimisticFixpoint();
3813 void trackStatistics()
const override {
3819struct AANoAliasArgument final
3820 : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> {
3821 using Base = AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>;
3822 AANoAliasArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
3835 DepClassTy::OPTIONAL, IsKnownNoSycn))
3836 return Base::updateImpl(
A);
3841 return Base::updateImpl(
A);
3845 bool UsedAssumedInformation =
false;
3846 if (
A.checkForAllCallSites(
3847 [](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *
this,
3848 true, UsedAssumedInformation))
3849 return Base::updateImpl(
A);
3857 return indicatePessimisticFixpoint();
3864struct AANoAliasCallSiteArgument final : AANoAliasImpl {
3865 AANoAliasCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
3866 : AANoAliasImpl(IRP,
A) {}
3870 bool mayAliasWithArgument(Attributor &
A, AAResults *&AAR,
3871 const AAMemoryBehavior &MemBehaviorAA,
3872 const CallBase &CB,
unsigned OtherArgNo) {
3874 if (this->getCalleeArgNo() == (
int)OtherArgNo)
3882 auto *CBArgMemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
3886 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadNone()) {
3887 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3894 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadOnly() &&
3896 A.recordDependence(MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3897 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3903 AAR =
A.getInfoCache().getAnalysisResultForFunction<AAManager>(
3907 bool IsAliasing = !AAR || !AAR->
isNoAlias(&getAssociatedValue(), ArgOp);
3909 "callsite arguments: "
3910 << getAssociatedValue() <<
" " << *ArgOp <<
" => "
3911 << (IsAliasing ?
"" :
"no-") <<
"alias \n");
3916 bool isKnownNoAliasDueToNoAliasPreservation(
3917 Attributor &
A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA) {
3930 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
3946 bool IsKnownNoCapture;
3949 DepClassTy::OPTIONAL, IsKnownNoCapture))
3955 A, *UserI, *getCtxI(), *
this,
nullptr,
3956 [ScopeFn](
const Function &Fn) {
return &Fn != ScopeFn; }))
3971 LLVM_DEBUG(
dbgs() <<
"[AANoAliasCSArg] Unknown user: " << *UserI <<
"\n");
3975 bool IsKnownNoCapture;
3976 const AANoCapture *NoCaptureAA =
nullptr;
3978 A,
this, VIRP, DepClassTy::NONE, IsKnownNoCapture,
false, &NoCaptureAA);
3979 if (!IsAssumedNoCapture &&
3981 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue())) {
3983 dbgs() <<
"[AANoAliasCSArg] " << getAssociatedValue()
3984 <<
" cannot be noalias as it is potentially captured\n");
3989 A.recordDependence(*NoCaptureAA, *
this, DepClassTy::OPTIONAL);
3995 for (
unsigned OtherArgNo = 0; OtherArgNo < CB.
arg_size(); OtherArgNo++)
3996 if (mayAliasWithArgument(
A, AAR, MemBehaviorAA, CB, OtherArgNo))
4006 auto *MemBehaviorAA =
4007 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
4009 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
4010 return ChangeStatus::UNCHANGED;
4013 bool IsKnownNoAlias;
4016 A,
this, VIRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
4018 <<
" is not no-alias at the definition\n");
4019 return indicatePessimisticFixpoint();
4022 AAResults *AAR =
nullptr;
4023 if (MemBehaviorAA &&
4024 isKnownNoAliasDueToNoAliasPreservation(
A, AAR, *MemBehaviorAA)) {
4026 dbgs() <<
"[AANoAlias] No-Alias deduced via no-alias preservation\n");
4027 return ChangeStatus::UNCHANGED;
4030 return indicatePessimisticFixpoint();
4038struct AANoAliasReturned final : AANoAliasImpl {
4039 AANoAliasReturned(
const IRPosition &IRP, Attributor &
A)
4040 : AANoAliasImpl(IRP,
A) {}
4045 auto CheckReturnValue = [&](
Value &RV) ->
bool {
4056 bool IsKnownNoAlias;
4058 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoAlias))
4061 bool IsKnownNoCapture;
4062 const AANoCapture *NoCaptureAA =
nullptr;
4064 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
4066 return IsAssumedNoCapture ||
4070 if (!
A.checkForAllReturnedValues(CheckReturnValue, *
this))
4071 return indicatePessimisticFixpoint();
4073 return ChangeStatus::UNCHANGED;
4081struct AANoAliasCallSiteReturned final
4082 : AACalleeToCallSite<AANoAlias, AANoAliasImpl> {
4083 AANoAliasCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4084 : AACalleeToCallSite<AANoAlias, AANoAliasImpl>(IRP,
A) {}
4094struct AAIsDeadValueImpl :
public AAIsDead {
4095 AAIsDeadValueImpl(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4098 bool isAssumedDead()
const override {
return isAssumed(IS_DEAD); }
4101 bool isKnownDead()
const override {
return isKnown(IS_DEAD); }
4104 bool isAssumedDead(
const BasicBlock *BB)
const override {
return false; }
4107 bool isKnownDead(
const BasicBlock *BB)
const override {
return false; }
4110 bool isAssumedDead(
const Instruction *
I)
const override {
4111 return I == getCtxI() && isAssumedDead();
4115 bool isKnownDead(
const Instruction *
I)
const override {
4116 return isAssumedDead(
I) && isKnownDead();
4120 const std::string getAsStr(Attributor *
A)
const override {
4121 return isAssumedDead() ?
"assumed-dead" :
"assumed-live";
4125 bool areAllUsesAssumedDead(Attributor &
A,
Value &V) {
4127 if (
V.getType()->isVoidTy() ||
V.use_empty())
4133 if (!
A.isRunOn(*
I->getFunction()))
4135 bool UsedAssumedInformation =
false;
4136 std::optional<Constant *>
C =
4137 A.getAssumedConstant(V, *
this, UsedAssumedInformation);
4142 auto UsePred = [&](
const Use &
U,
bool &Follow) {
return false; };
4147 return A.checkForAllUses(UsePred, *
this, V,
false,
4148 DepClassTy::REQUIRED,
4153 bool isAssumedSideEffectFree(Attributor &
A, Instruction *
I) {
4163 bool IsKnownNoUnwind;
4165 A,
this, CallIRP, DepClassTy::OPTIONAL, IsKnownNoUnwind))
4173struct AAIsDeadFloating :
public AAIsDeadValueImpl {
4174 AAIsDeadFloating(
const IRPosition &IRP, Attributor &
A)
4175 : AAIsDeadValueImpl(IRP,
A) {}
4179 AAIsDeadValueImpl::initialize(
A);
4182 indicatePessimisticFixpoint();
4187 if (!isAssumedSideEffectFree(
A,
I)) {
4189 indicatePessimisticFixpoint();
4191 removeAssumedBits(HAS_NO_EFFECT);
4195 bool isDeadFence(Attributor &
A, FenceInst &FI) {
4196 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
4198 if (!ExecDomainAA || !ExecDomainAA->isNoOpFence(FI))
4200 A.recordDependence(*ExecDomainAA, *
this, DepClassTy::OPTIONAL);
4204 bool isDeadStore(Attributor &
A, StoreInst &SI,
4205 SmallSetVector<Instruction *, 8> *AssumeOnlyInst =
nullptr) {
4207 if (
SI.isVolatile())
4213 bool UsedAssumedInformation =
false;
4214 if (!AssumeOnlyInst) {
4215 PotentialCopies.clear();
4217 UsedAssumedInformation)) {
4220 <<
"[AAIsDead] Could not determine potential copies of store!\n");
4224 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Store has " << PotentialCopies.size()
4225 <<
" potential copies.\n");
4227 InformationCache &InfoCache =
A.getInfoCache();
4230 UsedAssumedInformation))
4234 auto &UserI = cast<Instruction>(*U.getUser());
4235 if (InfoCache.isOnlyUsedByAssume(UserI)) {
4237 AssumeOnlyInst->insert(&UserI);
4240 return A.isAssumedDead(U,
this,
nullptr, UsedAssumedInformation);
4246 <<
" is assumed live!\n");
4252 const std::string getAsStr(Attributor *
A)
const override {
4256 return "assumed-dead-store";
4259 return "assumed-dead-fence";
4260 return AAIsDeadValueImpl::getAsStr(
A);
4267 if (!isDeadStore(
A, *SI))
4268 return indicatePessimisticFixpoint();
4270 if (!isDeadFence(
A, *FI))
4271 return indicatePessimisticFixpoint();
4273 if (!isAssumedSideEffectFree(
A,
I))
4274 return indicatePessimisticFixpoint();
4275 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4276 return indicatePessimisticFixpoint();
4281 bool isRemovableStore()
const override {
4282 return isAssumed(IS_REMOVABLE) &&
isa<StoreInst>(&getAssociatedValue());
4287 Value &
V = getAssociatedValue();
4294 SmallSetVector<Instruction *, 8> AssumeOnlyInst;
4295 bool IsDead = isDeadStore(
A, *SI, &AssumeOnlyInst);
4298 A.deleteAfterManifest(*
I);
4299 for (
size_t i = 0; i < AssumeOnlyInst.
size(); ++i) {
4301 for (
auto *Usr : AOI->
users())
4303 A.deleteAfterManifest(*AOI);
4309 A.deleteAfterManifest(*FI);
4313 A.deleteAfterManifest(*
I);
4321 void trackStatistics()
const override {
4327 SmallSetVector<Value *, 4> PotentialCopies;
4330struct AAIsDeadArgument :
public AAIsDeadFloating {
4331 AAIsDeadArgument(
const IRPosition &IRP, Attributor &
A)
4332 : AAIsDeadFloating(IRP,
A) {}
4336 Argument &Arg = *getAssociatedArgument();
4337 if (
A.isValidFunctionSignatureRewrite(Arg, {}))
4338 if (
A.registerFunctionSignatureRewrite(
4342 return ChangeStatus::CHANGED;
4344 return ChangeStatus::UNCHANGED;
4351struct AAIsDeadCallSiteArgument :
public AAIsDeadValueImpl {
4352 AAIsDeadCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
4353 : AAIsDeadValueImpl(IRP,
A) {}
4357 AAIsDeadValueImpl::initialize(
A);
4359 indicatePessimisticFixpoint();
4368 Argument *Arg = getAssociatedArgument();
4370 return indicatePessimisticFixpoint();
4372 auto *ArgAA =
A.getAAFor<AAIsDead>(*
this, ArgPos, DepClassTy::REQUIRED);
4374 return indicatePessimisticFixpoint();
4383 "Expected undef values to be filtered out!");
4385 if (
A.changeUseAfterManifest(U, UV))
4386 return ChangeStatus::CHANGED;
4387 return ChangeStatus::UNCHANGED;
4394struct AAIsDeadCallSiteReturned :
public AAIsDeadFloating {
4395 AAIsDeadCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4396 : AAIsDeadFloating(IRP,
A) {}
4399 bool isAssumedDead()
const override {
4400 return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;
4405 AAIsDeadFloating::initialize(
A);
4407 indicatePessimisticFixpoint();
4412 IsAssumedSideEffectFree = isAssumedSideEffectFree(
A, getCtxI());
4418 if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(
A, getCtxI())) {
4419 IsAssumedSideEffectFree =
false;
4420 Changed = ChangeStatus::CHANGED;
4422 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4423 return indicatePessimisticFixpoint();
4428 void trackStatistics()
const override {
4429 if (IsAssumedSideEffectFree)
4436 const std::string getAsStr(Attributor *
A)
const override {
4437 return isAssumedDead()
4439 : (getAssumed() ?
"assumed-dead-users" :
"assumed-live");
4443 bool IsAssumedSideEffectFree =
true;
4446struct AAIsDeadReturned :
public AAIsDeadValueImpl {
4447 AAIsDeadReturned(
const IRPosition &IRP, Attributor &
A)
4448 : AAIsDeadValueImpl(IRP,
A) {}
4453 bool UsedAssumedInformation =
false;
4454 A.checkForAllInstructions([](Instruction &) {
return true; }, *
this,
4455 {Instruction::Ret}, UsedAssumedInformation);
4457 auto PredForCallSite = [&](AbstractCallSite ACS) {
4458 if (ACS.isCallbackCall() || !ACS.getInstruction())
4460 return areAllUsesAssumedDead(
A, *ACS.getInstruction());
4463 if (!
A.checkForAllCallSites(PredForCallSite, *
this,
true,
4464 UsedAssumedInformation))
4465 return indicatePessimisticFixpoint();
4467 return ChangeStatus::UNCHANGED;
4473 bool AnyChange =
false;
4474 UndefValue &UV = *
UndefValue::get(getAssociatedFunction()->getReturnType());
4481 bool UsedAssumedInformation =
false;
4482 A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
4483 UsedAssumedInformation);
4484 return AnyChange ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
4491struct AAIsDeadFunction :
public AAIsDead {
4492 AAIsDeadFunction(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4497 assert(
F &&
"Did expect an anchor function");
4498 if (!isAssumedDeadInternalFunction(
A)) {
4499 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4500 assumeLive(
A,
F->getEntryBlock());
4504 bool isAssumedDeadInternalFunction(Attributor &
A) {
4505 if (!getAnchorScope()->hasLocalLinkage())
4507 bool UsedAssumedInformation =
false;
4508 return A.checkForAllCallSites([](AbstractCallSite) {
return false; }, *
this,
4509 true, UsedAssumedInformation);
4513 const std::string getAsStr(Attributor *
A)
const override {
4514 return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) +
"/" +
4515 std::to_string(getAnchorScope()->
size()) +
"][#TBEP " +
4516 std::to_string(ToBeExploredFrom.size()) +
"][#KDE " +
4517 std::to_string(KnownDeadEnds.size()) +
"]";
4522 assert(getState().isValidState() &&
4523 "Attempted to manifest an invalid state!");
4528 if (AssumedLiveBlocks.empty()) {
4529 A.deleteAfterManifest(
F);
4530 return ChangeStatus::CHANGED;
4536 bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(
F);
4538 KnownDeadEnds.set_union(ToBeExploredFrom);
4539 for (
const Instruction *DeadEndI : KnownDeadEnds) {
4543 bool IsKnownNoReturn;
4551 A.registerInvokeWithDeadSuccessor(
const_cast<InvokeInst &
>(*
II));
4553 A.changeToUnreachableAfterManifest(
4554 const_cast<Instruction *
>(DeadEndI->getNextNode()));
4555 HasChanged = ChangeStatus::CHANGED;
4558 STATS_DECL(AAIsDead, BasicBlock,
"Number of dead basic blocks deleted.");
4559 for (BasicBlock &BB :
F)
4560 if (!AssumedLiveBlocks.count(&BB)) {
4561 A.deleteAfterManifest(BB);
4563 HasChanged = ChangeStatus::CHANGED;
4572 bool isEdgeDead(
const BasicBlock *From,
const BasicBlock *To)
const override {
4575 "Used AAIsDead of the wrong function");
4576 return isValidState() && !AssumedLiveEdges.count(std::make_pair(From, To));
4580 void trackStatistics()
const override {}
4583 bool isAssumedDead()
const override {
return false; }
4586 bool isKnownDead()
const override {
return false; }
4589 bool isAssumedDead(
const BasicBlock *BB)
const override {
4591 "BB must be in the same anchor scope function.");
4595 return !AssumedLiveBlocks.count(BB);
4599 bool isKnownDead(
const BasicBlock *BB)
const override {
4600 return getKnown() && isAssumedDead(BB);
4604 bool isAssumedDead(
const Instruction *
I)
const override {
4605 assert(
I->getParent()->getParent() == getAnchorScope() &&
4606 "Instruction must be in the same anchor scope function.");
4613 if (!AssumedLiveBlocks.count(
I->getParent()))
4619 if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))
4627 bool isKnownDead(
const Instruction *
I)
const override {
4628 return getKnown() && isAssumedDead(
I);
4633 bool assumeLive(Attributor &
A,
const BasicBlock &BB) {
4634 if (!AssumedLiveBlocks.insert(&BB).second)
4641 for (
const Instruction &
I : BB)
4644 if (
F->hasLocalLinkage())
4645 A.markLiveInternalFunction(*
F);
4651 SmallSetVector<const Instruction *, 8> ToBeExploredFrom;
4654 SmallSetVector<const Instruction *, 8> KnownDeadEnds;
4657 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> AssumedLiveEdges;
4660 DenseSet<const BasicBlock *> AssumedLiveBlocks;
4664identifyAliveSuccessors(Attributor &
A,
const CallBase &CB,
4665 AbstractAttribute &AA,
4666 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4669 bool IsKnownNoReturn;
4672 return !IsKnownNoReturn;
4681identifyAliveSuccessors(Attributor &
A,
const InvokeInst &
II,
4682 AbstractAttribute &AA,
4683 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4684 bool UsedAssumedInformation =
4690 if (AAIsDeadFunction::mayCatchAsynchronousExceptions(*
II.getFunction())) {
4691 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4695 bool IsKnownNoUnwind;
4698 UsedAssumedInformation |= !IsKnownNoUnwind;
4700 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4703 return UsedAssumedInformation;
4707identifyAliveSuccessors(Attributor &
A,
const BranchInst &BI,
4708 AbstractAttribute &AA,
4709 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4710 bool UsedAssumedInformation =
false;
4714 std::optional<Constant *>
C =
4715 A.getAssumedConstant(*BI.
getCondition(), AA, UsedAssumedInformation);
4725 UsedAssumedInformation =
false;
4728 return UsedAssumedInformation;
4732identifyAliveSuccessors(Attributor &
A,
const SwitchInst &SI,
4733 AbstractAttribute &AA,
4734 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4735 bool UsedAssumedInformation =
false;
4739 UsedAssumedInformation)) {
4741 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4746 if (Values.
empty() ||
4747 (Values.
size() == 1 &&
4750 return UsedAssumedInformation;
4753 Type &Ty = *
SI.getCondition()->getType();
4754 SmallPtrSet<ConstantInt *, 8>
Constants;
4755 auto CheckForConstantInt = [&](
Value *
V) {
4763 if (!
all_of(Values, [&](AA::ValueAndContext &VAC) {
4764 return CheckForConstantInt(VAC.
getValue());
4766 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4768 return UsedAssumedInformation;
4771 unsigned MatchedCases = 0;
4772 for (
const auto &CaseIt :
SI.cases()) {
4773 if (
Constants.count(CaseIt.getCaseValue())) {
4775 AliveSuccessors.
push_back(&CaseIt.getCaseSuccessor()->front());
4782 AliveSuccessors.
push_back(&
SI.getDefaultDest()->front());
4783 return UsedAssumedInformation;
4789 if (AssumedLiveBlocks.empty()) {
4790 if (isAssumedDeadInternalFunction(
A))
4794 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4795 assumeLive(
A,
F->getEntryBlock());
4799 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Live [" << AssumedLiveBlocks.size() <<
"/"
4800 << getAnchorScope()->
size() <<
"] BBs and "
4801 << ToBeExploredFrom.size() <<
" exploration points and "
4802 << KnownDeadEnds.size() <<
" known dead ends\n");
4807 ToBeExploredFrom.end());
4808 decltype(ToBeExploredFrom) NewToBeExploredFrom;
4811 while (!Worklist.
empty()) {
4818 I =
I->getNextNode();
4820 AliveSuccessors.
clear();
4822 bool UsedAssumedInformation =
false;
4823 switch (
I->getOpcode()) {
4827 "Expected non-terminators to be handled already!");
4828 for (
const BasicBlock *SuccBB :
successors(
I->getParent()))
4831 case Instruction::Call:
4833 *
this, AliveSuccessors);
4835 case Instruction::Invoke:
4837 *
this, AliveSuccessors);
4839 case Instruction::Br:
4841 *
this, AliveSuccessors);
4843 case Instruction::Switch:
4845 *
this, AliveSuccessors);
4849 if (UsedAssumedInformation) {
4850 NewToBeExploredFrom.insert(
I);
4851 }
else if (AliveSuccessors.
empty() ||
4852 (
I->isTerminator() &&
4853 AliveSuccessors.
size() <
I->getNumSuccessors())) {
4854 if (KnownDeadEnds.insert(
I))
4859 << AliveSuccessors.
size() <<
" UsedAssumedInformation: "
4860 << UsedAssumedInformation <<
"\n");
4862 for (
const Instruction *AliveSuccessor : AliveSuccessors) {
4863 if (!
I->isTerminator()) {
4864 assert(AliveSuccessors.size() == 1 &&
4865 "Non-terminator expected to have a single successor!");
4869 auto Edge = std::make_pair(
I->getParent(), AliveSuccessor->getParent());
4870 if (AssumedLiveEdges.insert(
Edge).second)
4872 if (assumeLive(
A, *AliveSuccessor->getParent()))
4879 if (NewToBeExploredFrom.size() != ToBeExploredFrom.size() ||
4880 llvm::any_of(NewToBeExploredFrom, [&](
const Instruction *
I) {
4881 return !ToBeExploredFrom.count(I);
4884 ToBeExploredFrom = std::move(NewToBeExploredFrom);
4893 if (ToBeExploredFrom.empty() &&
4894 getAnchorScope()->
size() == AssumedLiveBlocks.size() &&
4895 llvm::all_of(KnownDeadEnds, [](
const Instruction *DeadEndI) {
4896 return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;
4898 return indicatePessimisticFixpoint();
4903struct AAIsDeadCallSite final : AAIsDeadFunction {
4904 AAIsDeadCallSite(
const IRPosition &IRP, Attributor &
A)
4905 : AAIsDeadFunction(IRP,
A) {}
4914 "supported for call sites yet!");
4919 return indicatePessimisticFixpoint();
4923 void trackStatistics()
const override {}
4930struct AADereferenceableImpl : AADereferenceable {
4931 AADereferenceableImpl(
const IRPosition &IRP, Attributor &
A)
4932 : AADereferenceable(IRP,
A) {}
4933 using StateType = DerefState;
4937 Value &
V = *getAssociatedValue().stripPointerCasts();
4939 A.getAttrs(getIRPosition(),
4940 {Attribute::Dereferenceable, Attribute::DereferenceableOrNull},
4943 takeKnownDerefBytesMaximum(Attr.getValueAsInt());
4946 bool IsKnownNonNull;
4948 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNonNull);
4950 bool CanBeNull, CanBeFreed;
4951 takeKnownDerefBytesMaximum(
V.getPointerDereferenceableBytes(
4952 A.getDataLayout(), CanBeNull, CanBeFreed));
4954 if (Instruction *CtxI = getCtxI())
4955 followUsesInMBEC(*
this,
A, getState(), *CtxI);
4960 StateType &getState()
override {
return *
this; }
4961 const StateType &getState()
const override {
return *
this; }
4965 void addAccessedBytesForUse(Attributor &
A,
const Use *U,
const Instruction *
I,
4966 DerefState &State) {
4967 const Value *UseV =
U->get();
4972 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
I->isVolatile())
4977 Loc->Ptr,
Offset,
A.getDataLayout(),
true);
4978 if (
Base &&
Base == &getAssociatedValue())
4979 State.addAccessedBytes(
Offset, Loc->Size.getValue());
4983 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
4984 AADereferenceable::StateType &State) {
4985 bool IsNonNull =
false;
4986 bool TrackUse =
false;
4987 int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
4988 A, *
this, getAssociatedValue(), U,
I, IsNonNull, TrackUse);
4989 LLVM_DEBUG(
dbgs() <<
"[AADereferenceable] Deref bytes: " << DerefBytes
4990 <<
" for instruction " << *
I <<
"\n");
4992 addAccessedBytesForUse(
A, U,
I, State);
4993 State.takeKnownDerefBytesMaximum(DerefBytes);
5000 bool IsKnownNonNull;
5002 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5003 if (IsAssumedNonNull &&
5004 A.hasAttr(getIRPosition(), Attribute::DereferenceableOrNull)) {
5005 A.removeAttrs(getIRPosition(), {Attribute::DereferenceableOrNull});
5006 return ChangeStatus::CHANGED;
5011 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5012 SmallVectorImpl<Attribute> &Attrs)
const override {
5014 bool IsKnownNonNull;
5016 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5017 if (IsAssumedNonNull)
5018 Attrs.emplace_back(Attribute::getWithDereferenceableBytes(
5019 Ctx, getAssumedDereferenceableBytes()));
5021 Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes(
5022 Ctx, getAssumedDereferenceableBytes()));
5026 const std::string getAsStr(Attributor *
A)
const override {
5027 if (!getAssumedDereferenceableBytes())
5028 return "unknown-dereferenceable";
5029 bool IsKnownNonNull;
5030 bool IsAssumedNonNull =
false;
5033 *
A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
5034 return std::string(
"dereferenceable") +
5035 (IsAssumedNonNull ?
"" :
"_or_null") +
5036 (isAssumedGlobal() ?
"_globally" :
"") +
"<" +
5037 std::to_string(getKnownDereferenceableBytes()) +
"-" +
5038 std::to_string(getAssumedDereferenceableBytes()) +
">" +
5039 (!
A ?
" [non-null is unknown]" :
"");
5044struct AADereferenceableFloating : AADereferenceableImpl {
5045 AADereferenceableFloating(
const IRPosition &IRP, Attributor &
A)
5046 : AADereferenceableImpl(IRP,
A) {}
5051 bool UsedAssumedInformation =
false;
5053 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5055 Values.
push_back({getAssociatedValue(), getCtxI()});
5058 Stripped = Values.
size() != 1 ||
5059 Values.
front().getValue() != &getAssociatedValue();
5062 const DataLayout &
DL =
A.getDataLayout();
5065 auto VisitValueCB = [&](
const Value &
V) ->
bool {
5067 DL.getIndexSizeInBits(
V.getType()->getPointerAddressSpace());
5068 APInt
Offset(IdxWidth, 0);
5073 const auto *AA =
A.getAAFor<AADereferenceable>(
5075 int64_t DerefBytes = 0;
5076 if (!AA || (!Stripped &&
this == AA)) {
5079 bool CanBeNull, CanBeFreed;
5081 Base->getPointerDereferenceableBytes(
DL, CanBeNull, CanBeFreed);
5082 T.GlobalState.indicatePessimisticFixpoint();
5085 DerefBytes =
DS.DerefBytesState.getAssumed();
5086 T.GlobalState &=
DS.GlobalState;
5092 int64_t OffsetSExt =
Offset.getSExtValue();
5096 T.takeAssumedDerefBytesMinimum(
5097 std::max(int64_t(0), DerefBytes - OffsetSExt));
5102 T.takeKnownDerefBytesMaximum(
5103 std::max(int64_t(0), DerefBytes - OffsetSExt));
5104 T.indicatePessimisticFixpoint();
5105 }
else if (OffsetSExt > 0) {
5111 T.indicatePessimisticFixpoint();
5115 return T.isValidState();
5118 for (
const auto &VAC : Values)
5119 if (!VisitValueCB(*VAC.
getValue()))
5120 return indicatePessimisticFixpoint();
5126 void trackStatistics()
const override {
5132struct AADereferenceableReturned final
5133 : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl> {
5135 AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl>;
5136 AADereferenceableReturned(
const IRPosition &IRP, Attributor &
A)
5140 void trackStatistics()
const override {
5146struct AADereferenceableArgument final
5147 : AAArgumentFromCallSiteArguments<AADereferenceable,
5148 AADereferenceableImpl> {
5150 AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl>;
5151 AADereferenceableArgument(
const IRPosition &IRP, Attributor &
A)
5155 void trackStatistics()
const override {
5161struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {
5162 AADereferenceableCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5163 : AADereferenceableFloating(IRP,
A) {}
5166 void trackStatistics()
const override {
5172struct AADereferenceableCallSiteReturned final
5173 : AACalleeToCallSite<AADereferenceable, AADereferenceableImpl> {
5174 using Base = AACalleeToCallSite<AADereferenceable, AADereferenceableImpl>;
5175 AADereferenceableCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5179 void trackStatistics()
const override {
5189static unsigned getKnownAlignForUse(Attributor &
A, AAAlign &QueryingAA,
5190 Value &AssociatedValue,
const Use *U,
5191 const Instruction *
I,
bool &TrackUse) {
5200 if (
GEP->hasAllConstantIndices())
5205 switch (
II->getIntrinsicID()) {
5206 case Intrinsic::ptrmask: {
5208 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5210 const auto *AlignAA =
A.getAAFor<AAAlign>(
5212 if (ConstVals && ConstVals->isValidState() && ConstVals->isAtFixpoint()) {
5213 unsigned ShiftValue = std::min(ConstVals->getAssumedMinTrailingZeros(),
5215 Align ConstAlign(UINT64_C(1) << ShiftValue);
5216 if (ConstAlign >= AlignAA->getKnownAlign())
5217 return Align(1).value();
5220 return AlignAA->getKnownAlign().
value();
5223 case Intrinsic::amdgcn_make_buffer_rsrc: {
5224 const auto *AlignAA =
A.getAAFor<AAAlign>(
5227 return AlignAA->getKnownAlign().
value();
5245 MA = MaybeAlign(AlignAA->getKnownAlign());
5248 const DataLayout &
DL =
A.getDataLayout();
5249 const Value *UseV =
U->get();
5251 if (
SI->getPointerOperand() == UseV)
5252 MA =
SI->getAlign();
5254 if (LI->getPointerOperand() == UseV)
5255 MA = LI->getAlign();
5257 if (AI->getPointerOperand() == UseV)
5258 MA = AI->getAlign();
5260 if (AI->getPointerOperand() == UseV)
5261 MA = AI->getAlign();
5267 unsigned Alignment = MA->value();
5271 if (
Base == &AssociatedValue) {
5276 uint32_t
gcd = std::gcd(uint32_t(
abs((int32_t)
Offset)), Alignment);
5284struct AAAlignImpl : AAAlign {
5285 AAAlignImpl(
const IRPosition &IRP, Attributor &
A) : AAAlign(IRP,
A) {}
5290 A.getAttrs(getIRPosition(), {Attribute::Alignment},
Attrs);
5292 takeKnownMaximum(Attr.getValueAsInt());
5294 Value &
V = *getAssociatedValue().stripPointerCasts();
5295 takeKnownMaximum(
V.getPointerAlignment(
A.getDataLayout()).value());
5297 if (Instruction *CtxI = getCtxI())
5298 followUsesInMBEC(*
this,
A, getState(), *CtxI);
5306 Value &AssociatedValue = getAssociatedValue();
5308 return ChangeStatus::UNCHANGED;
5310 for (
const Use &U : AssociatedValue.
uses()) {
5312 if (
SI->getPointerOperand() == &AssociatedValue)
5313 if (
SI->getAlign() < getAssumedAlign()) {
5315 "Number of times alignment added to a store");
5316 SI->setAlignment(getAssumedAlign());
5317 InstrChanged = ChangeStatus::CHANGED;
5320 if (LI->getPointerOperand() == &AssociatedValue)
5321 if (LI->getAlign() < getAssumedAlign()) {
5322 LI->setAlignment(getAssumedAlign());
5324 "Number of times alignment added to a load");
5325 InstrChanged = ChangeStatus::CHANGED;
5328 if (RMW->getPointerOperand() == &AssociatedValue) {
5329 if (RMW->getAlign() < getAssumedAlign()) {
5331 "Number of times alignment added to atomicrmw");
5333 RMW->setAlignment(getAssumedAlign());
5334 InstrChanged = ChangeStatus::CHANGED;
5338 if (CAS->getPointerOperand() == &AssociatedValue) {
5339 if (CAS->getAlign() < getAssumedAlign()) {
5341 "Number of times alignment added to cmpxchg");
5342 CAS->setAlignment(getAssumedAlign());
5343 InstrChanged = ChangeStatus::CHANGED;
5351 Align InheritAlign =
5352 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5353 if (InheritAlign >= getAssumedAlign())
5354 return InstrChanged;
5355 return Changed | InstrChanged;
5363 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5364 SmallVectorImpl<Attribute> &Attrs)
const override {
5365 if (getAssumedAlign() > 1)
5367 Attribute::getWithAlignment(Ctx,
Align(getAssumedAlign())));
5371 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5372 AAAlign::StateType &State) {
5373 bool TrackUse =
false;
5375 unsigned int KnownAlign =
5376 getKnownAlignForUse(
A, *
this, getAssociatedValue(), U,
I, TrackUse);
5377 State.takeKnownMaximum(KnownAlign);
5383 const std::string getAsStr(Attributor *
A)
const override {
5384 return "align<" + std::to_string(getKnownAlign().value()) +
"-" +
5385 std::to_string(getAssumedAlign().value()) +
">";
5390struct AAAlignFloating : AAAlignImpl {
5391 AAAlignFloating(
const IRPosition &IRP, Attributor &
A) : AAAlignImpl(IRP,
A) {}
5395 const DataLayout &
DL =
A.getDataLayout();
5398 bool UsedAssumedInformation =
false;
5400 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
5402 Values.
push_back({getAssociatedValue(), getCtxI()});
5405 Stripped = Values.
size() != 1 ||
5406 Values.
front().getValue() != &getAssociatedValue();
5410 auto VisitValueCB = [&](
Value &
V) ->
bool {
5414 DepClassTy::REQUIRED);
5415 if (!AA || (!Stripped &&
this == AA)) {
5417 unsigned Alignment = 1;
5430 Alignment =
V.getPointerAlignment(
DL).value();
5433 T.takeKnownMaximum(Alignment);
5434 T.indicatePessimisticFixpoint();
5437 const AAAlign::StateType &
DS = AA->
getState();
5440 return T.isValidState();
5443 for (
const auto &VAC : Values) {
5444 if (!VisitValueCB(*VAC.
getValue()))
5445 return indicatePessimisticFixpoint();
5458struct AAAlignReturned final
5459 : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {
5460 using Base = AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>;
5461 AAAlignReturned(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5468struct AAAlignArgument final
5469 : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {
5470 using Base = AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>;
5471 AAAlignArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5478 if (
A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))
5479 return ChangeStatus::UNCHANGED;
5480 return Base::manifest(
A);
5487struct AAAlignCallSiteArgument final : AAAlignFloating {
5488 AAAlignCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5489 : AAAlignFloating(IRP,
A) {}
5496 if (Argument *Arg = getAssociatedArgument())
5497 if (
A.getInfoCache().isInvolvedInMustTailCall(*Arg))
5498 return ChangeStatus::UNCHANGED;
5500 Align InheritAlign =
5501 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5502 if (InheritAlign >= getAssumedAlign())
5503 Changed = ChangeStatus::UNCHANGED;
5510 if (Argument *Arg = getAssociatedArgument()) {
5513 const auto *ArgAlignAA =
A.getAAFor<AAAlign>(
5516 takeKnownMaximum(ArgAlignAA->getKnownAlign().value());
5526struct AAAlignCallSiteReturned final
5527 : AACalleeToCallSite<AAAlign, AAAlignImpl> {
5528 using Base = AACalleeToCallSite<AAAlign, AAAlignImpl>;
5529 AAAlignCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5535 switch (
II->getIntrinsicID()) {
5536 case Intrinsic::ptrmask: {
5540 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5542 if (ConstVals && ConstVals->isValidState()) {
5543 unsigned ShiftValue =
5544 std::min(ConstVals->getAssumedMinTrailingZeros(),
5545 Value::MaxAlignmentExponent);
5546 Alignment =
Align(UINT64_C(1) << ShiftValue);
5550 const auto *AlignAA =
5552 DepClassTy::REQUIRED);
5554 Alignment = std::max(AlignAA->getAssumedAlign(), Alignment);
5561 std::min(this->getAssumedAlign(), Alignment).value());
5567 case Intrinsic::amdgcn_make_buffer_rsrc: {
5568 const auto *AlignAA =
5570 DepClassTy::REQUIRED);
5573 this->getState(), AlignAA->getAssumedAlign().
value());
5580 return Base::updateImpl(
A);
5589struct AANoReturnImpl :
public AANoReturn {
5590 AANoReturnImpl(
const IRPosition &IRP, Attributor &
A) : AANoReturn(IRP,
A) {}
5596 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
5601 const std::string getAsStr(Attributor *
A)
const override {
5602 return getAssumed() ?
"noreturn" :
"may-return";
5607 auto CheckForNoReturn = [](
Instruction &) {
return false; };
5608 bool UsedAssumedInformation =
false;
5609 if (!
A.checkForAllInstructions(CheckForNoReturn, *
this,
5610 {(unsigned)Instruction::Ret},
5611 UsedAssumedInformation))
5612 return indicatePessimisticFixpoint();
5613 return ChangeStatus::UNCHANGED;
5617struct AANoReturnFunction final : AANoReturnImpl {
5618 AANoReturnFunction(
const IRPosition &IRP, Attributor &
A)
5619 : AANoReturnImpl(IRP,
A) {}
5626struct AANoReturnCallSite final
5627 : AACalleeToCallSite<AANoReturn, AANoReturnImpl> {
5628 AANoReturnCallSite(
const IRPosition &IRP, Attributor &
A)
5629 : AACalleeToCallSite<AANoReturn, AANoReturnImpl>(IRP,
A) {}
5640struct AAInstanceInfoImpl :
public AAInstanceInfo {
5641 AAInstanceInfoImpl(
const IRPosition &IRP, Attributor &
A)
5642 : AAInstanceInfo(IRP,
A) {}
5646 Value &
V = getAssociatedValue();
5648 if (
C->isThreadDependent())
5649 indicatePessimisticFixpoint();
5651 indicateOptimisticFixpoint();
5657 indicateOptimisticFixpoint();
5662 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
5665 indicatePessimisticFixpoint();
5675 Value &
V = getAssociatedValue();
5678 Scope =
I->getFunction();
5681 if (!
Scope->hasLocalLinkage())
5685 return indicateOptimisticFixpoint();
5687 bool IsKnownNoRecurse;
5693 auto UsePred = [&](
const Use &
U,
bool &Follow) {
5708 if (!Callee || !
Callee->hasLocalLinkage())
5712 const auto *ArgInstanceInfoAA =
A.getAAFor<AAInstanceInfo>(
5714 DepClassTy::OPTIONAL);
5715 if (!ArgInstanceInfoAA ||
5716 !ArgInstanceInfoAA->isAssumedUniqueForAnalysis())
5721 A, *CB, *Scope, *
this,
nullptr,
5722 [Scope](
const Function &Fn) {
return &Fn !=
Scope; }))
5729 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
5731 auto *Ptr =
SI->getPointerOperand()->stripPointerCasts();
5739 if (!
A.checkForAllUses(UsePred, *
this, V,
true,
5740 DepClassTy::OPTIONAL,
5741 true, EquivalentUseCB))
5742 return indicatePessimisticFixpoint();
5748 const std::string getAsStr(Attributor *
A)
const override {
5749 return isAssumedUniqueForAnalysis() ?
"<unique [fAa]>" :
"<unknown>";
5753 void trackStatistics()
const override {}
5757struct AAInstanceInfoFloating : AAInstanceInfoImpl {
5758 AAInstanceInfoFloating(
const IRPosition &IRP, Attributor &
A)
5759 : AAInstanceInfoImpl(IRP,
A) {}
5763struct AAInstanceInfoArgument final : AAInstanceInfoFloating {
5764 AAInstanceInfoArgument(
const IRPosition &IRP, Attributor &
A)
5765 : AAInstanceInfoFloating(IRP,
A) {}
5769struct AAInstanceInfoCallSiteArgument final : AAInstanceInfoImpl {
5770 AAInstanceInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5771 : AAInstanceInfoImpl(IRP,
A) {}
5779 Argument *Arg = getAssociatedArgument();
5781 return indicatePessimisticFixpoint();
5784 A.getAAFor<AAInstanceInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
5786 return indicatePessimisticFixpoint();
5792struct AAInstanceInfoReturned final : AAInstanceInfoImpl {
5793 AAInstanceInfoReturned(
const IRPosition &IRP, Attributor &
A)
5794 : AAInstanceInfoImpl(IRP,
A) {
5810struct AAInstanceInfoCallSiteReturned final : AAInstanceInfoFloating {
5811 AAInstanceInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5812 : AAInstanceInfoFloating(IRP,
A) {}
5819 bool IgnoreSubsumingPositions) {
5820 assert(ImpliedAttributeKind == Attribute::Captures &&
5821 "Unexpected attribute kind");
5831 V.getType()->getPointerAddressSpace() == 0)) {
5836 A.getAttrs(IRP, {Attribute::Captures}, Attrs,
5846 {Attribute::Captures, Attribute::ByVal}, Attrs,
5883 bool ReadOnly =
F.onlyReadsMemory();
5884 bool NoThrow =
F.doesNotThrow();
5885 bool IsVoidReturn =
F.getReturnType()->isVoidTy();
5886 if (ReadOnly && NoThrow && IsVoidReturn) {
5899 if (NoThrow && IsVoidReturn)
5904 if (!NoThrow || ArgNo < 0 ||
5905 !
F.getAttributes().hasAttrSomewhere(Attribute::Returned))
5908 for (
unsigned U = 0, E =
F.arg_size(); U < E; ++U)
5909 if (
F.hasParamAttribute(U, Attribute::Returned)) {
5910 if (U ==
unsigned(ArgNo))
5937 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5938 SmallVectorImpl<Attribute> &Attrs)
const override {
5939 if (!isAssumedNoCaptureMaybeReturned())
5942 if (isArgumentPosition()) {
5943 if (isAssumedNoCapture())
5944 Attrs.emplace_back(Attribute::get(Ctx, Attribute::Captures));
5946 Attrs.emplace_back(Attribute::get(Ctx,
"no-capture-maybe-returned"));
5951 const std::string getAsStr(Attributor *
A)
const override {
5952 if (isKnownNoCapture())
5953 return "known not-captured";
5954 if (isAssumedNoCapture())
5955 return "assumed not-captured";
5956 if (isKnownNoCaptureMaybeReturned())
5957 return "known not-captured-maybe-returned";
5958 if (isAssumedNoCaptureMaybeReturned())
5959 return "assumed not-captured-maybe-returned";
5960 return "assumed-captured";
5965 bool checkUse(Attributor &
A, AANoCapture::StateType &State,
const Use &U,
5968 LLVM_DEBUG(
dbgs() <<
"[AANoCapture] Check use: " << *
U.get() <<
" in "
5974 return isCapturedIn(State,
true,
true,
5981 return isCapturedIn(State,
true,
true,
5987 return isCapturedIn(State,
false,
false,
5989 return isCapturedIn(State,
true,
true,
5997 return isCapturedIn(State,
true,
true,
6004 bool IsKnownNoCapture;
6005 const AANoCapture *ArgNoCaptureAA =
nullptr;
6007 A,
this, CSArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6009 if (IsAssumedNoCapture)
6010 return isCapturedIn(State,
false,
false,
6014 return isCapturedIn(State,
false,
false,
6019 return isCapturedIn(State,
true,
true,
6026 static bool isCapturedIn(AANoCapture::StateType &State,
bool CapturedInMem,
6027 bool CapturedInInt,
bool CapturedInRet) {
6028 LLVM_DEBUG(
dbgs() <<
" - captures [Mem " << CapturedInMem <<
"|Int "
6029 << CapturedInInt <<
"|Ret " << CapturedInRet <<
"]\n");
6041 const IRPosition &IRP = getIRPosition();
6045 return indicatePessimisticFixpoint();
6052 return indicatePessimisticFixpoint();
6060 T.addKnownBits(NOT_CAPTURED_IN_MEM);
6062 addKnownBits(NOT_CAPTURED_IN_MEM);
6069 auto CheckReturnedArgs = [&](
bool &UsedAssumedInformation) {
6073 UsedAssumedInformation))
6075 bool SeenConstant =
false;
6076 for (
const AA::ValueAndContext &VAC : Values) {
6080 SeenConstant =
true;
6082 VAC.
getValue() == getAssociatedArgument())
6088 bool IsKnownNoUnwind;
6091 bool IsVoidTy =
F->getReturnType()->isVoidTy();
6092 bool UsedAssumedInformation =
false;
6093 if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {
6094 T.addKnownBits(NOT_CAPTURED_IN_RET);
6095 if (
T.isKnown(NOT_CAPTURED_IN_MEM))
6097 if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {
6098 addKnownBits(NOT_CAPTURED_IN_RET);
6099 if (isKnown(NOT_CAPTURED_IN_MEM))
6100 return indicateOptimisticFixpoint();
6105 auto UseCheck = [&](
const Use &
U,
bool &Follow) ->
bool {
6114 return checkUse(
A,
T, U, Follow);
6117 if (!
A.checkForAllUses(UseCheck, *
this, *V))
6118 return indicatePessimisticFixpoint();
6121 auto Assumed = S.getAssumed();
6122 S.intersectAssumedBits(
T.getAssumed());
6123 if (!isAssumedNoCaptureMaybeReturned())
6124 return indicatePessimisticFixpoint();
6130struct AANoCaptureArgument final : AANoCaptureImpl {
6131 AANoCaptureArgument(
const IRPosition &IRP, Attributor &
A)
6132 : AANoCaptureImpl(IRP,
A) {}
6139struct AANoCaptureCallSiteArgument final : AANoCaptureImpl {
6140 AANoCaptureCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6141 : AANoCaptureImpl(IRP,
A) {}
6149 Argument *Arg = getAssociatedArgument();
6151 return indicatePessimisticFixpoint();
6153 bool IsKnownNoCapture;
6154 const AANoCapture *ArgAA =
nullptr;
6156 A,
this, ArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6158 return ChangeStatus::UNCHANGED;
6160 return indicatePessimisticFixpoint();
6165 void trackStatistics()
const override {
6171struct AANoCaptureFloating final : AANoCaptureImpl {
6172 AANoCaptureFloating(
const IRPosition &IRP, Attributor &
A)
6173 : AANoCaptureImpl(IRP,
A) {}
6176 void trackStatistics()
const override {
6182struct AANoCaptureReturned final : AANoCaptureImpl {
6183 AANoCaptureReturned(
const IRPosition &IRP, Attributor &
A)
6184 : AANoCaptureImpl(IRP,
A) {
6199 void trackStatistics()
const override {}
6203struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {
6204 AANoCaptureCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6205 : AANoCaptureImpl(IRP,
A) {}
6211 determineFunctionCaptureCapabilities(getIRPosition(), *
F, *
this);
6215 void trackStatistics()
const override {
6232 dbgs() <<
"[ValueSimplify] is assumed to be "
6235 dbgs() <<
"[ValueSimplify] is assumed to be <none>\n";
6247 if (getAssociatedValue().
getType()->isVoidTy())
6248 indicatePessimisticFixpoint();
6249 if (
A.hasSimplificationCallback(getIRPosition()))
6250 indicatePessimisticFixpoint();
6254 const std::string getAsStr(Attributor *
A)
const override {
6256 dbgs() <<
"SAV: " << (bool)SimplifiedAssociatedValue <<
" ";
6257 if (SimplifiedAssociatedValue && *SimplifiedAssociatedValue)
6258 dbgs() <<
"SAV: " << **SimplifiedAssociatedValue <<
" ";
6260 return isValidState() ? (isAtFixpoint() ?
"simplified" :
"maybe-simple")
6265 void trackStatistics()
const override {}
6268 std::optional<Value *>
6269 getAssumedSimplifiedValue(Attributor &
A)
const override {
6270 return SimplifiedAssociatedValue;
6277 static Value *ensureType(Attributor &
A,
Value &V,
Type &Ty, Instruction *CtxI,
6281 if (CtxI &&
V.getType()->canLosslesslyBitCastTo(&Ty))
6283 : BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6292 static Value *reproduceInst(Attributor &
A,
6293 const AbstractAttribute &QueryingAA,
6294 Instruction &
I,
Type &Ty, Instruction *CtxI,
6296 assert(CtxI &&
"Cannot reproduce an instruction without context!");
6297 if (
Check && (
I.mayReadFromMemory() ||
6302 Value *NewOp = reproduceValue(
A, QueryingAA, *
Op, Ty, CtxI,
Check, VMap);
6304 assert(
Check &&
"Manifest of new value unexpectedly failed!");
6326 static Value *reproduceValue(Attributor &
A,
6327 const AbstractAttribute &QueryingAA,
Value &V,
6328 Type &Ty, Instruction *CtxI,
bool Check,
6330 if (
const auto &NewV = VMap.
lookup(&V))
6332 bool UsedAssumedInformation =
false;
6333 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
6335 if (!SimpleV.has_value())
6339 EffectiveV = *SimpleV;
6344 return ensureType(
A, *EffectiveV, Ty, CtxI,
Check);
6346 if (
Value *NewV = reproduceInst(
A, QueryingAA, *
I, Ty, CtxI,
Check, VMap))
6347 return ensureType(
A, *NewV, Ty, CtxI,
Check);
6353 Value *manifestReplacementValue(Attributor &
A, Instruction *CtxI)
const {
6354 Value *NewV = SimplifiedAssociatedValue
6355 ? *SimplifiedAssociatedValue
6357 if (NewV && NewV != &getAssociatedValue()) {
6361 if (reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6363 return reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6371 bool checkAndUpdate(Attributor &
A,
const AbstractAttribute &QueryingAA,
6372 const IRPosition &IRP,
bool Simplify =
true) {
6373 bool UsedAssumedInformation =
false;
6376 QueryingValueSimplified =
A.getAssumedSimplified(
6378 return unionAssumed(QueryingValueSimplified);
6382 template <
typename AAType>
bool askSimplifiedValueFor(Attributor &
A) {
6383 if (!getAssociatedValue().
getType()->isIntegerTy())
6388 A.getAAFor<AAType>(*
this, getIRPosition(), DepClassTy::NONE);
6392 std::optional<Constant *> COpt = AA->getAssumedConstant(
A);
6395 SimplifiedAssociatedValue = std::nullopt;
6396 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6399 if (
auto *
C = *COpt) {
6400 SimplifiedAssociatedValue =
C;
6401 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6407 bool askSimplifiedValueForOtherAAs(Attributor &
A) {
6408 if (askSimplifiedValueFor<AAValueConstantRange>(
A))
6410 if (askSimplifiedValueFor<AAPotentialConstantValues>(
A))
6418 for (
auto &U : getAssociatedValue().uses()) {
6423 IP =
PHI->getIncomingBlock(U)->getTerminator();
6424 if (
auto *NewV = manifestReplacementValue(
A, IP)) {
6426 <<
" -> " << *NewV <<
" :: " << *
this <<
"\n");
6427 if (
A.changeUseAfterManifest(U, *NewV))
6428 Changed = ChangeStatus::CHANGED;
6432 return Changed | AAValueSimplify::manifest(
A);
6437 SimplifiedAssociatedValue = &getAssociatedValue();
6438 return AAValueSimplify::indicatePessimisticFixpoint();
6442struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
6443 AAValueSimplifyArgument(
const IRPosition &IRP, Attributor &
A)
6444 : AAValueSimplifyImpl(IRP,
A) {}
6447 AAValueSimplifyImpl::initialize(
A);
6448 if (
A.hasAttr(getIRPosition(),
6449 {Attribute::InAlloca, Attribute::Preallocated,
6450 Attribute::StructRet, Attribute::Nest, Attribute::ByVal},
6452 indicatePessimisticFixpoint();
6459 Argument *Arg = getAssociatedArgument();
6465 return indicatePessimisticFixpoint();
6468 auto Before = SimplifiedAssociatedValue;
6470 auto PredForCallSite = [&](AbstractCallSite ACS) {
6471 const IRPosition &ACSArgPos =
6482 bool UsedAssumedInformation =
false;
6483 std::optional<Constant *> SimpleArgOp =
6484 A.getAssumedConstant(ACSArgPos, *
this, UsedAssumedInformation);
6491 return unionAssumed(*SimpleArgOp);
6496 bool UsedAssumedInformation =
false;
6497 if (hasCallBaseContext() &&
6498 getCallBaseContext()->getCalledOperand() == Arg->
getParent())
6500 AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
6502 Success =
A.checkForAllCallSites(PredForCallSite, *
this,
true,
6503 UsedAssumedInformation);
6506 if (!askSimplifiedValueForOtherAAs(
A))
6507 return indicatePessimisticFixpoint();
6510 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6511 : ChangeStatus ::CHANGED;
6515 void trackStatistics()
const override {
6520struct AAValueSimplifyReturned : AAValueSimplifyImpl {
6521 AAValueSimplifyReturned(
const IRPosition &IRP, Attributor &
A)
6522 : AAValueSimplifyImpl(IRP,
A) {}
6525 std::optional<Value *>
6526 getAssumedSimplifiedValue(Attributor &
A)
const override {
6527 if (!isValidState())
6529 return SimplifiedAssociatedValue;
6534 auto Before = SimplifiedAssociatedValue;
6538 return checkAndUpdate(
6543 bool UsedAssumedInformation =
false;
6544 if (!
A.checkForAllInstructions(ReturnInstCB, *
this, {Instruction::Ret},
6545 UsedAssumedInformation))
6546 if (!askSimplifiedValueForOtherAAs(
A))
6547 return indicatePessimisticFixpoint();
6550 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6551 : ChangeStatus ::CHANGED;
6557 return ChangeStatus::UNCHANGED;
6561 void trackStatistics()
const override {
6566struct AAValueSimplifyFloating : AAValueSimplifyImpl {
6567 AAValueSimplifyFloating(
const IRPosition &IRP, Attributor &
A)
6568 : AAValueSimplifyImpl(IRP,
A) {}
6572 AAValueSimplifyImpl::initialize(
A);
6573 Value &
V = getAnchorValue();
6577 indicatePessimisticFixpoint();
6582 auto Before = SimplifiedAssociatedValue;
6583 if (!askSimplifiedValueForOtherAAs(
A))
6584 return indicatePessimisticFixpoint();
6587 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6588 : ChangeStatus ::CHANGED;
6592 void trackStatistics()
const override {
6597struct AAValueSimplifyFunction : AAValueSimplifyImpl {
6598 AAValueSimplifyFunction(
const IRPosition &IRP, Attributor &
A)
6599 : AAValueSimplifyImpl(IRP,
A) {}
6603 SimplifiedAssociatedValue =
nullptr;
6604 indicateOptimisticFixpoint();
6609 "AAValueSimplify(Function|CallSite)::updateImpl will not be called");
6612 void trackStatistics()
const override {
6617struct AAValueSimplifyCallSite : AAValueSimplifyFunction {
6618 AAValueSimplifyCallSite(
const IRPosition &IRP, Attributor &
A)
6619 : AAValueSimplifyFunction(IRP,
A) {}
6621 void trackStatistics()
const override {
6626struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl {
6627 AAValueSimplifyCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6628 : AAValueSimplifyImpl(IRP,
A) {}
6631 AAValueSimplifyImpl::initialize(
A);
6632 Function *Fn = getAssociatedFunction();
6633 assert(Fn &&
"Did expect an associted function");
6634 for (Argument &Arg : Fn->
args()) {
6639 checkAndUpdate(
A, *
this, IRP))
6640 indicateOptimisticFixpoint();
6642 indicatePessimisticFixpoint();
6650 return indicatePessimisticFixpoint();
6653 void trackStatistics()
const override {
6658struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
6659 AAValueSimplifyCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6660 : AAValueSimplifyFloating(IRP,
A) {}
6666 auto *FloatAA =
A.lookupAAFor<AAValueSimplify>(
6668 if (FloatAA && FloatAA->getState().isValidState())
6671 if (
auto *NewV = manifestReplacementValue(
A, getCtxI())) {
6673 ->getArgOperandUse(getCallSiteArgNo());
6674 if (
A.changeUseAfterManifest(U, *NewV))
6675 Changed = ChangeStatus::CHANGED;
6678 return Changed | AAValueSimplify::manifest(
A);
6681 void trackStatistics()
const override {
6689struct AAHeapToStackFunction final :
public AAHeapToStack {
6691 struct AllocationInfo {
6696 LibFunc LibraryFunctionId = NotLibFunc;
6703 } Status = STACK_DUE_TO_USE;
6707 bool HasPotentiallyFreeingUnknownUses =
false;
6711 bool MoveAllocaIntoEntry =
true;
6714 SmallSetVector<CallBase *, 1> PotentialFreeCalls{};
6717 struct DeallocationInfo {
6725 bool MightFreeUnknownObjects =
false;
6728 SmallSetVector<CallBase *, 1> PotentialAllocationCalls{};
6731 AAHeapToStackFunction(
const IRPosition &IRP, Attributor &
A)
6732 : AAHeapToStack(IRP,
A) {}
6734 ~AAHeapToStackFunction()
override {
6737 for (
auto &It : AllocationInfos)
6738 It.second->~AllocationInfo();
6739 for (
auto &It : DeallocationInfos)
6740 It.second->~DeallocationInfo();
6744 AAHeapToStack::initialize(
A);
6747 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6754 DeallocationInfos[CB] =
new (
A.Allocator) DeallocationInfo{CB, FreedOp};
6761 auto *I8Ty = Type::getInt8Ty(CB->
getParent()->getContext());
6763 AllocationInfo *AI =
new (
A.Allocator) AllocationInfo{CB};
6764 AllocationInfos[CB] = AI;
6766 TLI->getLibFunc(*CB, AI->LibraryFunctionId);
6772 bool UsedAssumedInformation =
false;
6773 bool Success =
A.checkForAllCallLikeInstructions(
6774 AllocationIdentifierCB, *
this, UsedAssumedInformation,
6778 assert(
Success &&
"Did not expect the call base visit callback to fail!");
6781 [](
const IRPosition &,
const AbstractAttribute *,
6782 bool &) -> std::optional<Value *> {
return nullptr; };
6783 for (
const auto &It : AllocationInfos)
6786 for (
const auto &It : DeallocationInfos)
6791 const std::string getAsStr(Attributor *
A)
const override {
6792 unsigned NumH2SMallocs = 0, NumInvalidMallocs = 0;
6793 for (
const auto &It : AllocationInfos) {
6794 if (It.second->Status == AllocationInfo::INVALID)
6795 ++NumInvalidMallocs;
6799 return "[H2S] Mallocs Good/Bad: " + std::to_string(NumH2SMallocs) +
"/" +
6800 std::to_string(NumInvalidMallocs);
6804 void trackStatistics()
const override {
6806 MallocCalls, Function,
6807 "Number of malloc/calloc/aligned_alloc calls converted to allocas");
6808 for (
const auto &It : AllocationInfos)
6809 if (It.second->Status != AllocationInfo::INVALID)
6813 bool isAssumedHeapToStack(
const CallBase &CB)
const override {
6815 if (AllocationInfo *AI =
6816 AllocationInfos.lookup(
const_cast<CallBase *
>(&CB)))
6817 return AI->Status != AllocationInfo::INVALID;
6821 bool isAssumedHeapToStackRemovedFree(CallBase &CB)
const override {
6822 if (!isValidState())
6825 for (
const auto &It : AllocationInfos) {
6826 AllocationInfo &AI = *It.second;
6827 if (AI.Status == AllocationInfo::INVALID)
6830 if (AI.PotentialFreeCalls.count(&CB))
6838 assert(getState().isValidState() &&
6839 "Attempted to manifest an invalid state!");
6843 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6845 for (
auto &It : AllocationInfos) {
6846 AllocationInfo &AI = *It.second;
6847 if (AI.Status == AllocationInfo::INVALID)
6850 for (CallBase *FreeCall : AI.PotentialFreeCalls) {
6851 LLVM_DEBUG(
dbgs() <<
"H2S: Removing free call: " << *FreeCall <<
"\n");
6852 A.deleteAfterManifest(*FreeCall);
6853 HasChanged = ChangeStatus::CHANGED;
6856 LLVM_DEBUG(
dbgs() <<
"H2S: Removing malloc-like call: " << *AI.CB
6859 auto Remark = [&](OptimizationRemark
OR) {
6860 LibFunc IsAllocShared;
6861 if (TLI->getLibFunc(*AI.CB, IsAllocShared))
6862 if (IsAllocShared == LibFunc___kmpc_alloc_shared)
6863 return OR <<
"Moving globalized variable to the stack.";
6864 return OR <<
"Moving memory allocation from the heap to the stack.";
6866 if (AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared)
6867 A.emitRemark<OptimizationRemark>(AI.CB,
"OMP110",
Remark);
6869 A.emitRemark<OptimizationRemark>(AI.CB,
"HeapToStack",
Remark);
6871 const DataLayout &
DL =
A.getInfoCache().getDL();
6873 std::optional<APInt> SizeAPI =
getSize(
A, *
this, AI);
6875 Size = ConstantInt::get(AI.CB->getContext(), *SizeAPI);
6877 LLVMContext &Ctx = AI.CB->getContext();
6878 ObjectSizeOpts Opts;
6879 ObjectSizeOffsetEvaluator Eval(
DL, TLI, Ctx, Opts);
6880 SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);
6887 ?
F->getEntryBlock().begin()
6888 : AI.CB->getIterator();
6891 if (MaybeAlign RetAlign = AI.CB->getRetAlign())
6892 Alignment = std::max(Alignment, *RetAlign);
6894 std::optional<APInt> AlignmentAPI = getAPInt(
A, *
this, *Align);
6895 assert(AlignmentAPI && AlignmentAPI->getZExtValue() > 0 &&
6896 "Expected an alignment during manifest!");
6898 std::max(Alignment,
assumeAligned(AlignmentAPI->getZExtValue()));
6902 unsigned AS =
DL.getAllocaAddrSpace();
6904 new AllocaInst(Type::getInt8Ty(
F->getContext()), AS,
Size, Alignment,
6905 AI.CB->getName() +
".h2s", IP);
6907 if (Alloca->
getType() != AI.CB->getType())
6908 Alloca = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6909 Alloca, AI.CB->getType(),
"malloc_cast", AI.CB->getIterator());
6911 auto *I8Ty = Type::getInt8Ty(
F->getContext());
6914 "Must be able to materialize initial memory state of allocation");
6919 auto *NBB =
II->getNormalDest();
6921 A.deleteAfterManifest(*AI.CB);
6923 A.deleteAfterManifest(*AI.CB);
6932 Builder.CreateMemSet(Alloca, InitVal,
Size, std::nullopt);
6934 HasChanged = ChangeStatus::CHANGED;
6940 std::optional<APInt> getAPInt(Attributor &
A,
const AbstractAttribute &AA,
6942 bool UsedAssumedInformation =
false;
6943 std::optional<Constant *> SimpleV =
6944 A.getAssumedConstant(V, AA, UsedAssumedInformation);
6946 return APInt(64, 0);
6948 return CI->getValue();
6949 return std::nullopt;
6952 std::optional<APInt>
getSize(Attributor &
A,
const AbstractAttribute &AA,
6953 AllocationInfo &AI) {
6954 auto Mapper = [&](
const Value *
V) ->
const Value * {
6955 bool UsedAssumedInformation =
false;
6956 if (std::optional<Constant *> SimpleV =
6957 A.getAssumedConstant(*V, AA, UsedAssumedInformation))
6964 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6970 MapVector<CallBase *, AllocationInfo *> AllocationInfos;
6974 MapVector<CallBase *, DeallocationInfo *> DeallocationInfos;
6979ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &
A) {
6982 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6984 const auto *LivenessAA =
6987 MustBeExecutedContextExplorer *Explorer =
6988 A.getInfoCache().getMustBeExecutedContextExplorer();
6990 bool StackIsAccessibleByOtherThreads =
6991 A.getInfoCache().stackIsAccessibleByOtherThreads();
6994 A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(*F);
6995 std::optional<bool> MayContainIrreducibleControl;
6997 if (&
F->getEntryBlock() == &BB)
6999 if (!MayContainIrreducibleControl.has_value())
7001 if (*MayContainIrreducibleControl)
7010 bool HasUpdatedFrees =
false;
7012 auto UpdateFrees = [&]() {
7013 HasUpdatedFrees =
true;
7015 for (
auto &It : DeallocationInfos) {
7016 DeallocationInfo &DI = *It.second;
7019 if (DI.MightFreeUnknownObjects)
7023 bool UsedAssumedInformation =
false;
7024 if (
A.isAssumedDead(*DI.CB,
this, LivenessAA, UsedAssumedInformation,
7031 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown underlying object for free!\n");
7032 DI.MightFreeUnknownObjects =
true;
7045 DI.MightFreeUnknownObjects =
true;
7049 AllocationInfo *AI = AllocationInfos.lookup(ObjCB);
7051 LLVM_DEBUG(
dbgs() <<
"[H2S] Free of a non-allocation object: " << *Obj
7053 DI.MightFreeUnknownObjects =
true;
7057 DI.PotentialAllocationCalls.insert(ObjCB);
7061 auto FreeCheck = [&](AllocationInfo &AI) {
7065 if (!StackIsAccessibleByOtherThreads) {
7070 dbgs() <<
"[H2S] found an escaping use, stack is not accessible by "
7071 "other threads and function is not nosync:\n");
7075 if (!HasUpdatedFrees)
7079 if (AI.PotentialFreeCalls.size() != 1) {
7081 << AI.PotentialFreeCalls.size() <<
"\n");
7084 CallBase *UniqueFree = *AI.PotentialFreeCalls.begin();
7085 DeallocationInfo *DI = DeallocationInfos.lookup(UniqueFree);
7088 dbgs() <<
"[H2S] unique free call was not known as deallocation call "
7089 << *UniqueFree <<
"\n");
7092 if (DI->MightFreeUnknownObjects) {
7094 dbgs() <<
"[H2S] unique free call might free unknown allocations\n");
7097 if (DI->PotentialAllocationCalls.empty())
7099 if (DI->PotentialAllocationCalls.size() > 1) {
7101 << DI->PotentialAllocationCalls.size()
7102 <<
" different allocations\n");
7105 if (*DI->PotentialAllocationCalls.begin() != AI.CB) {
7108 <<
"[H2S] unique free call not known to free this allocation but "
7109 << **DI->PotentialAllocationCalls.begin() <<
"\n");
7114 if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared) {
7116 if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
7117 LLVM_DEBUG(
dbgs() <<
"[H2S] unique free call might not be executed "
7118 "with the allocation "
7119 << *UniqueFree <<
"\n");
7126 auto UsesCheck = [&](AllocationInfo &AI) {
7127 bool ValidUsesOnly =
true;
7129 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
7134 if (
SI->getValueOperand() ==
U.get()) {
7136 <<
"[H2S] escaping store to memory: " << *UserI <<
"\n");
7137 ValidUsesOnly =
false;
7146 if (DeallocationInfos.count(CB)) {
7147 AI.PotentialFreeCalls.insert(CB);
7154 bool IsKnownNoCapture;
7163 if (!IsAssumedNoCapture ||
7164 (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared &&
7165 !IsAssumedNoFree)) {
7166 AI.HasPotentiallyFreeingUnknownUses |= !IsAssumedNoFree;
7169 auto Remark = [&](OptimizationRemarkMissed ORM) {
7171 <<
"Could not move globalized variable to the stack. "
7172 "Variable is potentially captured in call. Mark "
7173 "parameter as `__attribute__((noescape))` to override.";
7176 if (ValidUsesOnly &&
7177 AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared)
7178 A.emitRemark<OptimizationRemarkMissed>(CB,
"OMP113",
Remark);
7181 ValidUsesOnly =
false;
7194 ValidUsesOnly =
false;
7197 if (!
A.checkForAllUses(Pred, *
this, *AI.CB,
false,
7199 [&](
const Use &OldU,
const Use &NewU) {
7200 auto *SI = dyn_cast<StoreInst>(OldU.getUser());
7201 return !SI || StackIsAccessibleByOtherThreads ||
7202 AA::isAssumedThreadLocalObject(
7203 A, *SI->getPointerOperand(), *this);
7206 return ValidUsesOnly;
7211 for (
auto &It : AllocationInfos) {
7212 AllocationInfo &AI = *It.second;
7213 if (AI.Status == AllocationInfo::INVALID)
7217 std::optional<APInt> APAlign = getAPInt(
A, *
this, *Align);
7221 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown allocation alignment: " << *AI.CB
7223 AI.Status = AllocationInfo::INVALID;
7228 !APAlign->isPowerOf2()) {
7229 LLVM_DEBUG(
dbgs() <<
"[H2S] Invalid allocation alignment: " << APAlign
7231 AI.Status = AllocationInfo::INVALID;
7238 if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared &&
7243 dbgs() <<
"[H2S] Unknown allocation size: " << *AI.CB <<
"\n";
7245 dbgs() <<
"[H2S] Allocation size too large: " << *AI.CB <<
" vs. "
7249 AI.Status = AllocationInfo::INVALID;
7255 switch (AI.Status) {
7256 case AllocationInfo::STACK_DUE_TO_USE:
7259 AI.Status = AllocationInfo::STACK_DUE_TO_FREE;
7261 case AllocationInfo::STACK_DUE_TO_FREE:
7264 AI.Status = AllocationInfo::INVALID;
7267 case AllocationInfo::INVALID:
7274 bool IsGlobalizedLocal =
7275 AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared;
7276 if (AI.MoveAllocaIntoEntry &&
7277 (!
Size.has_value() ||
7278 (!IsGlobalizedLocal && IsInLoop(*AI.CB->getParent()))))
7279 AI.MoveAllocaIntoEntry =
false;
7288struct AAPrivatizablePtrImpl :
public AAPrivatizablePtr {
7289 AAPrivatizablePtrImpl(
const IRPosition &IRP, Attributor &
A)
7290 : AAPrivatizablePtr(IRP,
A), PrivatizableType(std::nullopt) {}
7293 AAPrivatizablePtr::indicatePessimisticFixpoint();
7294 PrivatizableType =
nullptr;
7295 return ChangeStatus::CHANGED;
7301 virtual std::optional<Type *> identifyPrivatizableType(Attributor &
A) = 0;
7305 std::optional<Type *> combineTypes(std::optional<Type *> T0,
7306 std::optional<Type *>
T1) {
7316 std::optional<Type *> getPrivatizableType()
const override {
7317 return PrivatizableType;
7320 const std::string getAsStr(Attributor *
A)
const override {
7321 return isAssumedPrivatizablePtr() ?
"[priv]" :
"[no-priv]";
7325 std::optional<Type *> PrivatizableType;
7330struct AAPrivatizablePtrArgument final :
public AAPrivatizablePtrImpl {
7331 AAPrivatizablePtrArgument(
const IRPosition &IRP, Attributor &
A)
7332 : AAPrivatizablePtrImpl(IRP,
A) {}
7335 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7338 bool UsedAssumedInformation =
false;
7340 A.getAttrs(getIRPosition(), {Attribute::ByVal},
Attrs,
7342 if (!
Attrs.empty() &&
7343 A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *
this,
7344 true, UsedAssumedInformation))
7345 return Attrs[0].getValueAsType();
7347 std::optional<Type *> Ty;
7348 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
7356 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7365 A.getAAFor<AAPrivatizablePtr>(*
this, ACSArgPos, DepClassTy::REQUIRED);
7368 std::optional<Type *> CSTy = PrivCSArgAA->getPrivatizableType();
7371 dbgs() <<
"[AAPrivatizablePtr] ACSPos: " << ACSArgPos <<
", CSTy: ";
7375 dbgs() <<
"<nullptr>";
7380 Ty = combineTypes(Ty, CSTy);
7383 dbgs() <<
" : New Type: ";
7385 (*Ty)->print(
dbgs());
7387 dbgs() <<
"<nullptr>";
7396 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7397 UsedAssumedInformation))
7404 PrivatizableType = identifyPrivatizableType(
A);
7405 if (!PrivatizableType)
7406 return ChangeStatus::UNCHANGED;
7407 if (!*PrivatizableType)
7408 return indicatePessimisticFixpoint();
7413 DepClassTy::OPTIONAL);
7416 if (!
A.hasAttr(getIRPosition(), Attribute::ByVal) &&
7419 return indicatePessimisticFixpoint();
7425 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7429 Function &Fn = *getIRPosition().getAnchorScope();
7431 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(Fn);
7433 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Missing TTI for function "
7435 return indicatePessimisticFixpoint();
7438 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7445 bool UsedAssumedInformation =
false;
7446 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7447 UsedAssumedInformation)) {
7449 dbgs() <<
"[AAPrivatizablePtr] ABI incompatibility detected for "
7451 return indicatePessimisticFixpoint();
7455 Argument *Arg = getAssociatedArgument();
7456 if (!
A.isValidFunctionSignatureRewrite(*Arg, ReplacementTypes)) {
7458 return indicatePessimisticFixpoint();
7465 auto IsCompatiblePrivArgOfCallback = [&](CallBase &CB) {
7468 for (
const Use *U : CallbackUses) {
7469 AbstractCallSite CBACS(U);
7470 assert(CBACS && CBACS.isCallbackCall());
7471 for (Argument &CBArg : CBACS.getCalledFunction()->args()) {
7472 int CBArgNo = CBACS.getCallArgOperandNo(CBArg);
7476 <<
"[AAPrivatizablePtr] Argument " << *Arg
7477 <<
"check if can be privatized in the context of its parent ("
7479 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7481 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7482 <<
")\n[AAPrivatizablePtr] " << CBArg <<
" : "
7483 << CBACS.getCallArgOperand(CBArg) <<
" vs "
7485 <<
"[AAPrivatizablePtr] " << CBArg <<
" : "
7486 << CBACS.getCallArgOperandNo(CBArg) <<
" vs " << ArgNo <<
"\n";
7489 if (CBArgNo !=
int(ArgNo))
7491 const auto *CBArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7493 if (CBArgPrivAA && CBArgPrivAA->isValidState()) {
7494 auto CBArgPrivTy = CBArgPrivAA->getPrivatizableType();
7497 if (*CBArgPrivTy == PrivatizableType)
7502 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7503 <<
" cannot be privatized in the context of its parent ("
7505 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7507 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7508 <<
").\n[AAPrivatizablePtr] for which the argument "
7509 "privatization is not compatible.\n";
7519 auto IsCompatiblePrivArgOfDirectCS = [&](AbstractCallSite ACS) {
7523 "Expected a direct call operand for callback call operand");
7528 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7529 <<
" check if be privatized in the context of its parent ("
7531 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7533 << DCArgNo <<
"@" << DCCallee->
getName() <<
").\n";
7536 if (
unsigned(DCArgNo) < DCCallee->
arg_size()) {
7537 const auto *DCArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7539 DepClassTy::REQUIRED);
7540 if (DCArgPrivAA && DCArgPrivAA->isValidState()) {
7541 auto DCArgPrivTy = DCArgPrivAA->getPrivatizableType();
7544 if (*DCArgPrivTy == PrivatizableType)
7550 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7551 <<
" cannot be privatized in the context of its parent ("
7553 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7556 <<
").\n[AAPrivatizablePtr] for which the argument "
7557 "privatization is not compatible.\n";
7565 auto IsCompatiblePrivArgOfOtherCallSite = [&](AbstractCallSite ACS) {
7569 return IsCompatiblePrivArgOfDirectCS(ACS);
7573 if (!
A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *
this,
true,
7574 UsedAssumedInformation))
7575 return indicatePessimisticFixpoint();
7577 return ChangeStatus::UNCHANGED;
7583 identifyReplacementTypes(
Type *PrivType,
7584 SmallVectorImpl<Type *> &ReplacementTypes) {
7587 assert(PrivType &&
"Expected privatizable type!");
7591 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++)
7592 ReplacementTypes.
push_back(PrivStructType->getElementType(u));
7594 ReplacementTypes.
append(PrivArrayType->getNumElements(),
7595 PrivArrayType->getElementType());
7604 static void createInitialization(
Type *PrivType,
Value &
Base, Function &
F,
7606 assert(PrivType &&
"Expected privatizable type!");
7609 const DataLayout &
DL =
F.getDataLayout();
7613 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7614 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7617 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7620 Type *PointeeTy = PrivArrayType->getElementType();
7621 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7622 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7624 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7627 new StoreInst(
F.getArg(ArgNo), &
Base, IP);
7633 void createReplacementValues(Align Alignment,
Type *PrivType,
7635 SmallVectorImpl<Value *> &ReplacementValues) {
7637 assert(PrivType &&
"Expected privatizable type!");
7645 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7646 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7647 Type *PointeeTy = PrivStructType->getElementType(u);
7650 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7651 L->setAlignment(Alignment);
7655 Type *PointeeTy = PrivArrayType->getElementType();
7656 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7657 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7659 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7660 L->setAlignment(Alignment);
7665 L->setAlignment(Alignment);
7672 if (!PrivatizableType)
7673 return ChangeStatus::UNCHANGED;
7674 assert(*PrivatizableType &&
"Expected privatizable type!");
7680 bool UsedAssumedInformation =
false;
7681 if (!
A.checkForAllInstructions(
7682 [&](Instruction &
I) {
7683 CallInst &CI = cast<CallInst>(I);
7684 if (CI.isTailCall())
7685 TailCalls.push_back(&CI);
7688 *
this, {Instruction::Call}, UsedAssumedInformation))
7689 return ChangeStatus::UNCHANGED;
7691 Argument *Arg = getAssociatedArgument();
7694 const auto *AlignAA =
7701 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7703 BasicBlock &EntryBB = ReplacementFn.getEntryBlock();
7705 const DataLayout &
DL = IP->getDataLayout();
7706 unsigned AS =
DL.getAllocaAddrSpace();
7707 Instruction *AI =
new AllocaInst(*PrivatizableType, AS,
7708 Arg->
getName() +
".priv", IP);
7709 createInitialization(*PrivatizableType, *AI, ReplacementFn,
7710 ArgIt->getArgNo(), IP);
7713 AI = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
7717 for (CallInst *CI : TailCalls)
7718 CI->setTailCall(
false);
7725 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7726 AbstractCallSite ACS, SmallVectorImpl<Value *> &NewArgOperands) {
7729 createReplacementValues(
7730 AlignAA ? AlignAA->getAssumedAlign() :
Align(0),
7731 *PrivatizableType, ACS,
7739 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7742 if (
A.registerFunctionSignatureRewrite(*Arg, ReplacementTypes,
7743 std::move(FnRepairCB),
7744 std::move(ACSRepairCB)))
7745 return ChangeStatus::CHANGED;
7746 return ChangeStatus::UNCHANGED;
7750 void trackStatistics()
const override {
7755struct AAPrivatizablePtrFloating :
public AAPrivatizablePtrImpl {
7756 AAPrivatizablePtrFloating(
const IRPosition &IRP, Attributor &
A)
7757 : AAPrivatizablePtrImpl(IRP,
A) {}
7762 indicatePessimisticFixpoint();
7767 "updateImpl will not be called");
7771 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7774 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] No underlying object found!\n");
7781 return AI->getAllocatedType();
7783 auto *PrivArgAA =
A.getAAFor<AAPrivatizablePtr>(
7785 if (PrivArgAA && PrivArgAA->isAssumedPrivatizablePtr())
7786 return PrivArgAA->getPrivatizableType();
7789 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Underlying object neither valid "
7790 "alloca nor privatizable argument: "
7796 void trackStatistics()
const override {
7801struct AAPrivatizablePtrCallSiteArgument final
7802 :
public AAPrivatizablePtrFloating {
7803 AAPrivatizablePtrCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
7804 : AAPrivatizablePtrFloating(IRP,
A) {}
7808 if (
A.hasAttr(getIRPosition(), Attribute::ByVal))
7809 indicateOptimisticFixpoint();
7814 PrivatizableType = identifyPrivatizableType(
A);
7815 if (!PrivatizableType)
7816 return ChangeStatus::UNCHANGED;
7817 if (!*PrivatizableType)
7818 return indicatePessimisticFixpoint();
7820 const IRPosition &IRP = getIRPosition();
7821 bool IsKnownNoCapture;
7823 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoCapture);
7824 if (!IsAssumedNoCapture) {
7825 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might be captured!\n");
7826 return indicatePessimisticFixpoint();
7829 bool IsKnownNoAlias;
7831 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
7832 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might alias!\n");
7833 return indicatePessimisticFixpoint();
7838 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer is written!\n");
7839 return indicatePessimisticFixpoint();
7842 return ChangeStatus::UNCHANGED;
7846 void trackStatistics()
const override {
7851struct AAPrivatizablePtrCallSiteReturned final
7852 :
public AAPrivatizablePtrFloating {
7853 AAPrivatizablePtrCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
7854 : AAPrivatizablePtrFloating(IRP,
A) {}
7859 indicatePessimisticFixpoint();
7863 void trackStatistics()
const override {
7868struct AAPrivatizablePtrReturned final :
public AAPrivatizablePtrFloating {
7869 AAPrivatizablePtrReturned(
const IRPosition &IRP, Attributor &
A)
7870 : AAPrivatizablePtrFloating(IRP,
A) {}
7875 indicatePessimisticFixpoint();
7879 void trackStatistics()
const override {
7889struct AAMemoryBehaviorImpl :
public AAMemoryBehavior {
7890 AAMemoryBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
7891 : AAMemoryBehavior(IRP,
A) {}
7895 intersectAssumedBits(BEST_STATE);
7896 getKnownStateFromValue(
A, getIRPosition(), getState());
7897 AAMemoryBehavior::initialize(
A);
7901 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
7902 BitIntegerState &State,
7903 bool IgnoreSubsumingPositions =
false) {
7905 A.getAttrs(IRP, AttrKinds, Attrs, IgnoreSubsumingPositions);
7907 switch (Attr.getKindAsEnum()) {
7908 case Attribute::ReadNone:
7911 case Attribute::ReadOnly:
7914 case Attribute::WriteOnly:
7923 if (!
I->mayReadFromMemory())
7925 if (!
I->mayWriteToMemory())
7931 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
7932 SmallVectorImpl<Attribute> &Attrs)
const override {
7935 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));
7937 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));
7938 else if (isAssumedWriteOnly())
7939 Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));
7945 const IRPosition &IRP = getIRPosition();
7947 if (
A.hasAttr(IRP, Attribute::ReadNone,
7949 return ChangeStatus::UNCHANGED;
7958 return ChangeStatus::UNCHANGED;
7961 A.removeAttrs(IRP, AttrKinds);
7964 A.removeAttrs(IRP, Attribute::Writable);
7971 const std::string getAsStr(Attributor *
A)
const override {
7976 if (isAssumedWriteOnly())
7978 return "may-read/write";
7982 static const Attribute::AttrKind AttrKinds[3];
7986 Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};
7989struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {
7990 AAMemoryBehaviorFloating(
const IRPosition &IRP, Attributor &
A)
7991 : AAMemoryBehaviorImpl(IRP,
A) {}
7997 void trackStatistics()
const override {
8002 else if (isAssumedWriteOnly())
8009 bool followUsersOfUseIn(Attributor &
A,
const Use &U,
8010 const Instruction *UserI);
8013 void analyzeUseIn(Attributor &
A,
const Use &U,
const Instruction *UserI);
8017struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
8018 AAMemoryBehaviorArgument(
const IRPosition &IRP, Attributor &
A)
8019 : AAMemoryBehaviorFloating(IRP,
A) {}
8023 intersectAssumedBits(BEST_STATE);
8024 const IRPosition &IRP = getIRPosition();
8028 bool HasByVal =
A.hasAttr(IRP, {Attribute::ByVal},
8030 getKnownStateFromValue(
A, IRP, getState(),
8037 return ChangeStatus::UNCHANGED;
8041 if (
A.hasAttr(getIRPosition(),
8042 {Attribute::InAlloca, Attribute::Preallocated})) {
8043 removeKnownBits(NO_WRITES);
8044 removeAssumedBits(NO_WRITES);
8046 A.removeAttrs(getIRPosition(), AttrKinds);
8047 return AAMemoryBehaviorFloating::manifest(
A);
8051 void trackStatistics()
const override {
8056 else if (isAssumedWriteOnly())
8061struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {
8062 AAMemoryBehaviorCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
8063 : AAMemoryBehaviorArgument(IRP,
A) {}
8069 Argument *Arg = getAssociatedArgument();
8071 indicatePessimisticFixpoint();
8075 addKnownBits(NO_WRITES);
8076 removeKnownBits(NO_READS);
8077 removeAssumedBits(NO_READS);
8079 AAMemoryBehaviorArgument::initialize(
A);
8080 if (getAssociatedFunction()->isDeclaration())
8081 indicatePessimisticFixpoint();
8090 Argument *Arg = getAssociatedArgument();
8093 A.getAAFor<AAMemoryBehavior>(*
this, ArgPos, DepClassTy::REQUIRED);
8095 return indicatePessimisticFixpoint();
8100 void trackStatistics()
const override {
8105 else if (isAssumedWriteOnly())
8111struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {
8112 AAMemoryBehaviorCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
8113 : AAMemoryBehaviorFloating(IRP,
A) {}
8117 AAMemoryBehaviorImpl::initialize(
A);
8122 return ChangeStatus::UNCHANGED;
8126 void trackStatistics()
const override {}
8130struct AAMemoryBehaviorFunction final :
public AAMemoryBehaviorImpl {
8131 AAMemoryBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
8132 : AAMemoryBehaviorImpl(IRP,
A) {}
8148 else if (isAssumedWriteOnly())
8151 A.removeAttrs(getIRPosition(), AttrKinds);
8154 for (Argument &Arg :
F.args())
8156 return A.manifestAttrs(getIRPosition(),
8157 Attribute::getWithMemoryEffects(
F.getContext(), ME));
8161 void trackStatistics()
const override {
8166 else if (isAssumedWriteOnly())
8172struct AAMemoryBehaviorCallSite final
8173 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl> {
8174 AAMemoryBehaviorCallSite(
const IRPosition &IRP, Attributor &
A)
8175 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl>(IRP,
A) {}
8186 else if (isAssumedWriteOnly())
8189 A.removeAttrs(getIRPosition(), AttrKinds);
8192 for (Use &U : CB.
args())
8194 Attribute::Writable);
8195 return A.manifestAttrs(
8196 getIRPosition(), Attribute::getWithMemoryEffects(CB.
getContext(), ME));
8200 void trackStatistics()
const override {
8205 else if (isAssumedWriteOnly())
8210ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &
A) {
8213 auto AssumedState = getAssumed();
8220 const auto *MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
8222 if (MemBehaviorAA) {
8223 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8224 return !isAtFixpoint();
8229 if (
I.mayReadFromMemory())
8230 removeAssumedBits(NO_READS);
8231 if (
I.mayWriteToMemory())
8232 removeAssumedBits(NO_WRITES);
8233 return !isAtFixpoint();
8236 bool UsedAssumedInformation =
false;
8237 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8238 UsedAssumedInformation))
8239 return indicatePessimisticFixpoint();
8245ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &
A) {
8247 const IRPosition &IRP = getIRPosition();
8258 const auto *FnMemAA =
8261 FnMemAssumedState = FnMemAA->getAssumed();
8262 S.addKnownBits(FnMemAA->getKnown());
8263 if ((S.getAssumed() & FnMemAA->getAssumed()) == S.getAssumed())
8269 auto AssumedState = S.getAssumed();
8275 bool IsKnownNoCapture;
8276 const AANoCapture *ArgNoCaptureAA =
nullptr;
8281 if (!IsAssumedNoCapture &&
8283 S.intersectAssumedBits(FnMemAssumedState);
8289 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
8291 LLVM_DEBUG(
dbgs() <<
"[AAMemoryBehavior] Use: " << *U <<
" in " << *UserI
8299 Follow = followUsersOfUseIn(
A, U, UserI);
8303 analyzeUseIn(
A, U, UserI);
8305 return !isAtFixpoint();
8308 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue()))
8309 return indicatePessimisticFixpoint();
8315bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &
A,
const Use &U,
8316 const Instruction *UserI) {
8334 if (
U.get()->getType()->isPointerTy()) {
8336 bool IsKnownNoCapture;
8345void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &
A,
const Use &U,
8346 const Instruction *UserI) {
8353 case Instruction::Load:
8355 removeAssumedBits(NO_READS);
8358 case Instruction::Store:
8363 removeAssumedBits(NO_WRITES);
8365 indicatePessimisticFixpoint();
8368 case Instruction::Call:
8369 case Instruction::CallBr:
8370 case Instruction::Invoke: {
8377 indicatePessimisticFixpoint();
8384 removeAssumedBits(NO_READS);
8391 if (
U.get()->getType()->isPointerTy())
8395 const auto *MemBehaviorAA =
8401 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8409 removeAssumedBits(NO_READS);
8411 removeAssumedBits(NO_WRITES);
8423 return "all memory";
8426 std::string S =
"memory:";
8432 S +=
"internal global,";
8434 S +=
"external global,";
8438 S +=
"inaccessible,";
8452 AccessKind2Accesses.fill(
nullptr);
8455 ~AAMemoryLocationImpl()
override {
8458 for (AccessSet *AS : AccessKind2Accesses)
8465 intersectAssumedBits(BEST_STATE);
8466 getKnownStateFromValue(
A, getIRPosition(), getState());
8467 AAMemoryLocation::initialize(
A);
8471 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
8472 BitIntegerState &State,
8473 bool IgnoreSubsumingPositions =
false) {
8482 bool UseArgMemOnly =
true;
8484 if (AnchorFn &&
A.isRunOn(*AnchorFn))
8488 A.getAttrs(IRP, {Attribute::Memory},
Attrs, IgnoreSubsumingPositions);
8497 State.
addKnownBits(inverseLocation(NO_INACCESSIBLE_MEM,
true,
true));
8502 State.
addKnownBits(inverseLocation(NO_ARGUMENT_MEM,
true,
true));
8506 A.manifestAttrs(IRP,
8507 Attribute::getWithMemoryEffects(
8516 NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM,
true,
true));
8520 A.manifestAttrs(IRP,
8521 Attribute::getWithMemoryEffects(
8531 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
8532 SmallVectorImpl<Attribute> &Attrs)
const override {
8539 else if (isAssumedInaccessibleMemOnly())
8540 Attrs.push_back(Attribute::getWithMemoryEffects(
8542 else if (isAssumedArgMemOnly())
8545 else if (isAssumedInaccessibleOrArgMemOnly())
8546 Attrs.push_back(Attribute::getWithMemoryEffects(
8556 const IRPosition &IRP = getIRPosition();
8560 if (DeducedAttrs.
size() != 1)
8561 return ChangeStatus::UNCHANGED;
8564 return A.manifestAttrs(IRP, Attribute::getWithMemoryEffects(
8569 bool checkForAllAccessesToMemoryKind(
8571 MemoryLocationsKind)>
8573 MemoryLocationsKind RequestedMLK)
const override {
8574 if (!isValidState())
8577 MemoryLocationsKind AssumedMLK = getAssumedNotAccessedLocation();
8578 if (AssumedMLK == NO_LOCATIONS)
8582 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS;
8583 CurMLK *= 2, ++Idx) {
8584 if (CurMLK & RequestedMLK)
8587 if (
const AccessSet *
Accesses = AccessKind2Accesses[Idx])
8588 for (
const AccessInfo &AI : *
Accesses)
8589 if (!Pred(AI.I, AI.Ptr, AI.Kind, CurMLK))
8602 MemoryLocationsKind KnownMLK = getKnown();
8604 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2)
8605 if (!(CurMLK & KnownMLK))
8606 updateStateAndAccessesMap(getState(), CurMLK,
I,
nullptr,
Changed,
8607 getAccessKindFromInst(
I));
8608 return AAMemoryLocation::indicatePessimisticFixpoint();
8628 bool operator()(
const AccessInfo &
LHS,
const AccessInfo &
RHS)
const {
8632 return LHS.Ptr <
RHS.Ptr;
8633 if (
LHS.Kind !=
RHS.Kind)
8634 return LHS.Kind <
RHS.Kind;
8641 using AccessSet = SmallSet<AccessInfo, 2, AccessInfo>;
8642 std::array<AccessSet *, llvm::ConstantLog2<VALID_STATE>()>
8643 AccessKind2Accesses;
8648 categorizeArgumentPointerLocations(Attributor &
A, CallBase &CB,
8649 AAMemoryLocation::StateType &AccessedLocs,
8654 categorizeAccessedLocations(Attributor &
A, Instruction &
I,
bool &
Changed);
8657 AccessKind getAccessKindFromInst(
const Instruction *
I) {
8660 AK =
I->mayReadFromMemory() ? READ :
NONE;
8669 void updateStateAndAccessesMap(AAMemoryLocation::StateType &State,
8670 MemoryLocationsKind MLK,
const Instruction *
I,
8679 if (MLK == NO_UNKOWN_MEM)
8681 State.removeAssumedBits(MLK);
8686 void categorizePtrValue(Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8687 AAMemoryLocation::StateType &State,
bool &
Changed,
8688 unsigned AccessAS = 0);
8694void AAMemoryLocationImpl::categorizePtrValue(
8695 Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8697 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize pointer locations for "
8702 unsigned ObjectAS =
Obj.getType()->getPointerAddressSpace();
8704 MemoryLocationsKind MLK = NO_LOCATIONS;
8723 MLK = NO_ARGUMENT_MEM;
8729 if (GVar->isConstant())
8732 if (GV->hasLocalLinkage())
8733 MLK = NO_GLOBAL_INTERNAL_MEM;
8735 MLK = NO_GLOBAL_EXTERNAL_MEM;
8743 bool IsKnownNoAlias;
8747 MLK = NO_MALLOCED_MEM;
8749 MLK = NO_UNKOWN_MEM;
8751 MLK = NO_UNKOWN_MEM;
8754 assert(MLK != NO_LOCATIONS &&
"No location specified!");
8755 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Ptr value can be categorized: "
8756 << Obj <<
" -> " << getMemoryLocationsAsStr(MLK) <<
"\n");
8758 getAccessKindFromInst(&
I));
8763 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
8767 dbgs() <<
"[AAMemoryLocation] Pointer locations not categorized\n");
8768 updateStateAndAccessesMap(
State, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8769 getAccessKindFromInst(&
I));
8774 dbgs() <<
"[AAMemoryLocation] Accessed locations with pointer locations: "
8778void AAMemoryLocationImpl::categorizeArgumentPointerLocations(
8781 for (
unsigned ArgNo = 0,
E = CB.
arg_size(); ArgNo <
E; ++ArgNo) {
8790 const auto *ArgOpMemLocationAA =
8793 if (ArgOpMemLocationAA && ArgOpMemLocationAA->isAssumedReadNone())
8798 categorizePtrValue(
A, CB, *ArgOp, AccessedLocs,
Changed);
8803AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &
A, Instruction &
I,
8805 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize accessed locations for "
8809 AccessedLocs.intersectAssumedBits(NO_LOCATIONS);
8814 const auto *CBMemLocationAA =
A.getAAFor<AAMemoryLocation>(
8817 <<
" [" << CBMemLocationAA <<
"]\n");
8818 if (!CBMemLocationAA) {
8819 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
8820 Changed, getAccessKindFromInst(&
I));
8821 return NO_UNKOWN_MEM;
8824 if (CBMemLocationAA->isAssumedReadNone())
8825 return NO_LOCATIONS;
8827 if (CBMemLocationAA->isAssumedInaccessibleMemOnly()) {
8828 updateStateAndAccessesMap(AccessedLocs, NO_INACCESSIBLE_MEM, &
I,
nullptr,
8829 Changed, getAccessKindFromInst(&
I));
8830 return AccessedLocs.getAssumed();
8833 uint32_t CBAssumedNotAccessedLocs =
8834 CBMemLocationAA->getAssumedNotAccessedLocation();
8837 uint32_t CBAssumedNotAccessedLocsNoArgMem =
8838 CBAssumedNotAccessedLocs | NO_ARGUMENT_MEM | NO_GLOBAL_MEM;
8840 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2) {
8841 if (CBAssumedNotAccessedLocsNoArgMem & CurMLK)
8843 updateStateAndAccessesMap(AccessedLocs, CurMLK, &
I,
nullptr,
Changed,
8844 getAccessKindFromInst(&
I));
8849 bool HasGlobalAccesses = ((~CBAssumedNotAccessedLocs) & NO_GLOBAL_MEM);
8850 if (HasGlobalAccesses) {
8853 updateStateAndAccessesMap(AccessedLocs, MLK, &
I, Ptr,
Changed,
8854 getAccessKindFromInst(&
I));
8857 if (!CBMemLocationAA->checkForAllAccessesToMemoryKind(
8858 AccessPred, inverseLocation(NO_GLOBAL_MEM,
false,
false)))
8859 return AccessedLocs.getWorstState();
8863 dbgs() <<
"[AAMemoryLocation] Accessed state before argument handling: "
8864 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8867 bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM);
8869 categorizeArgumentPointerLocations(
A, *CB, AccessedLocs,
Changed);
8872 dbgs() <<
"[AAMemoryLocation] Accessed state after argument handling: "
8873 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8875 return AccessedLocs.getAssumed();
8880 dbgs() <<
"[AAMemoryLocation] Categorize memory access with pointer: "
8881 <<
I <<
" [" << *Ptr <<
"]\n");
8882 categorizePtrValue(
A,
I, *Ptr, AccessedLocs,
Changed,
8883 Ptr->getType()->getPointerAddressSpace());
8884 return AccessedLocs.getAssumed();
8887 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Failed to categorize instruction: "
8889 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8890 getAccessKindFromInst(&
I));
8891 return AccessedLocs.getAssumed();
8895struct AAMemoryLocationFunction final :
public AAMemoryLocationImpl {
8896 AAMemoryLocationFunction(
const IRPosition &IRP, Attributor &
A)
8897 : AAMemoryLocationImpl(IRP,
A) {}
8902 const auto *MemBehaviorAA =
8903 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
8906 return indicateOptimisticFixpoint();
8908 "AAMemoryLocation was not read-none but AAMemoryBehavior was!");
8909 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
8910 return ChangeStatus::UNCHANGED;
8914 auto AssumedState = getAssumed();
8918 MemoryLocationsKind MLK = categorizeAccessedLocations(
A,
I,
Changed);
8919 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Accessed locations for " <<
I
8920 <<
": " << getMemoryLocationsAsStr(MLK) <<
"\n");
8921 removeAssumedBits(inverseLocation(MLK,
false,
false));
8924 return getAssumedNotAccessedLocation() != VALID_STATE;
8927 bool UsedAssumedInformation =
false;
8928 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8929 UsedAssumedInformation))
8930 return indicatePessimisticFixpoint();
8932 Changed |= AssumedState != getAssumed();
8933 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8937 void trackStatistics()
const override {
8940 else if (isAssumedArgMemOnly())
8942 else if (isAssumedInaccessibleMemOnly())
8944 else if (isAssumedInaccessibleOrArgMemOnly())
8950struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {
8951 AAMemoryLocationCallSite(
const IRPosition &IRP, Attributor &
A)
8952 : AAMemoryLocationImpl(IRP,
A) {}
8963 A.getAAFor<AAMemoryLocation>(*
this, FnPos, DepClassTy::REQUIRED);
8965 return indicatePessimisticFixpoint();
8969 updateStateAndAccessesMap(getState(), MLK,
I, Ptr,
Changed,
8970 getAccessKindFromInst(
I));
8973 if (!FnAA->checkForAllAccessesToMemoryKind(AccessPred, ALL_LOCATIONS))
8974 return indicatePessimisticFixpoint();
8975 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8979 void trackStatistics()
const override {
8989struct AADenormalFPMathImpl :
public AADenormalFPMath {
8990 AADenormalFPMathImpl(
const IRPosition &IRP, Attributor &
A)
8991 : AADenormalFPMath(IRP,
A) {}
8993 const std::string getAsStr(Attributor *
A)
const override {
8994 std::string Str(
"AADenormalFPMath[");
8995 raw_string_ostream OS(Str);
8997 DenormalState Known = getKnown();
8998 if (Known.Mode.isValid())
8999 OS <<
"denormal-fp-math=" << Known.Mode;
9003 if (Known.ModeF32.isValid())
9004 OS <<
" denormal-fp-math-f32=" << Known.ModeF32;
9010struct AADenormalFPMathFunction final : AADenormalFPMathImpl {
9011 AADenormalFPMathFunction(
const IRPosition &IRP, Attributor &
A)
9012 : AADenormalFPMathImpl(IRP,
A) {}
9016 DenormalMode
Mode =
F->getDenormalModeRaw();
9017 DenormalMode ModeF32 =
F->getDenormalModeF32Raw();
9024 Known = DenormalState{
Mode, ModeF32};
9032 auto CheckCallSite = [=, &Change, &
A](AbstractCallSite CS) {
9035 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
9037 const auto *CallerInfo =
A.getAAFor<AADenormalFPMath>(
9043 CallerInfo->getState());
9047 bool AllCallSitesKnown =
true;
9048 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
9049 return indicatePessimisticFixpoint();
9051 if (Change == ChangeStatus::CHANGED && isModeFixed())
9057 LLVMContext &Ctx = getAssociatedFunction()->getContext();
9062 AttrToRemove.
push_back(
"denormal-fp-math");
9065 Attribute::get(Ctx,
"denormal-fp-math", Known.Mode.str()));
9068 if (Known.ModeF32 != Known.Mode) {
9070 Attribute::get(Ctx,
"denormal-fp-math-f32", Known.ModeF32.str()));
9072 AttrToRemove.
push_back(
"denormal-fp-math-f32");
9075 auto &IRP = getIRPosition();
9078 return A.removeAttrs(IRP, AttrToRemove) |
9079 A.manifestAttrs(IRP, AttrToAdd,
true);
9082 void trackStatistics()
const override {
9091struct AAValueConstantRangeImpl : AAValueConstantRange {
9092 using StateType = IntegerRangeState;
9093 AAValueConstantRangeImpl(
const IRPosition &IRP, Attributor &
A)
9094 : AAValueConstantRange(IRP,
A) {}
9098 if (
A.hasSimplificationCallback(getIRPosition())) {
9099 indicatePessimisticFixpoint();
9104 intersectKnown(getConstantRangeFromSCEV(
A, getCtxI()));
9107 intersectKnown(getConstantRangeFromLVI(
A, getCtxI()));
9111 const std::string getAsStr(Attributor *
A)
const override {
9113 llvm::raw_string_ostream OS(Str);
9115 getKnown().print(OS);
9117 getAssumed().print(OS);
9124 const SCEV *getSCEV(Attributor &
A,
const Instruction *
I =
nullptr)
const {
9125 if (!getAnchorScope())
9128 ScalarEvolution *SE =
9129 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9132 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
9138 const SCEV *S = SE->
getSCEV(&getAssociatedValue());
9147 ConstantRange getConstantRangeFromSCEV(Attributor &
A,
9148 const Instruction *
I =
nullptr)
const {
9149 if (!getAnchorScope())
9152 ScalarEvolution *SE =
9153 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9156 const SCEV *S = getSCEV(
A,
I);
9166 getConstantRangeFromLVI(Attributor &
A,
9167 const Instruction *CtxI =
nullptr)
const {
9168 if (!getAnchorScope())
9171 LazyValueInfo *LVI =
9172 A.getInfoCache().getAnalysisResultForFunction<LazyValueAnalysis>(
9187 bool isValidCtxInstructionForOutsideAnalysis(Attributor &
A,
9188 const Instruction *CtxI,
9189 bool AllowAACtxI)
const {
9190 if (!CtxI || (!AllowAACtxI && CtxI == getCtxI()))
9202 InformationCache &InfoCache =
A.getInfoCache();
9203 const DominatorTree *DT =
9214 getKnownConstantRange(Attributor &
A,
9215 const Instruction *CtxI =
nullptr)
const override {
9216 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9220 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9221 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9222 return getKnown().intersectWith(SCEVR).intersectWith(LVIR);
9227 getAssumedConstantRange(Attributor &
A,
9228 const Instruction *CtxI =
nullptr)
const override {
9233 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9235 return getAssumed();
9237 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9238 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9239 return getAssumed().intersectWith(SCEVR).intersectWith(LVIR);
9244 getMDNodeForConstantRange(
Type *Ty, LLVMContext &Ctx,
9245 const ConstantRange &AssumedConstantRange) {
9247 Ty, AssumedConstantRange.
getLower())),
9249 Ty, AssumedConstantRange.
getUpper()))};
9254 static bool isBetterRange(
const ConstantRange &Assumed,
9255 const Instruction &
I) {
9259 std::optional<ConstantRange> Known;
9263 }
else if (MDNode *KnownRanges =
I.getMetadata(LLVMContext::MD_range)) {
9269 if (KnownRanges->getNumOperands() > 2)
9272 ConstantInt *
Lower =
9274 ConstantInt *
Upper =
9277 Known.emplace(
Lower->getValue(),
Upper->getValue());
9279 return !Known || (*Known != Assumed && Known->contains(Assumed));
9284 setRangeMetadataIfisBetterRange(Instruction *
I,
9285 const ConstantRange &AssumedConstantRange) {
9286 if (isBetterRange(AssumedConstantRange, *
I)) {
9287 I->setMetadata(LLVMContext::MD_range,
9288 getMDNodeForConstantRange(
I->getType(),
I->getContext(),
9289 AssumedConstantRange));
9296 setRangeRetAttrIfisBetterRange(Attributor &
A,
const IRPosition &IRP,
9298 const ConstantRange &AssumedConstantRange) {
9299 if (isBetterRange(AssumedConstantRange, *
I)) {
9300 A.manifestAttrs(IRP,
9301 Attribute::get(
I->getContext(), Attribute::Range,
9302 AssumedConstantRange),
9312 ConstantRange AssumedConstantRange = getAssumedConstantRange(
A);
9315 auto &
V = getAssociatedValue();
9319 assert(
I == getCtxI() &&
"Should not annotate an instruction which is "
9320 "not the context instruction");
9322 if (setRangeMetadataIfisBetterRange(
I, AssumedConstantRange))
9323 Changed = ChangeStatus::CHANGED;
9325 if (setRangeRetAttrIfisBetterRange(
A, getIRPosition(),
I,
9326 AssumedConstantRange))
9327 Changed = ChangeStatus::CHANGED;
9335struct AAValueConstantRangeArgument final
9336 : AAArgumentFromCallSiteArguments<
9337 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9339 using Base = AAArgumentFromCallSiteArguments<
9340 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9342 AAValueConstantRangeArgument(
const IRPosition &IRP, Attributor &
A)
9346 void trackStatistics()
const override {
9351struct AAValueConstantRangeReturned
9352 : AAReturnedFromReturnedValues<AAValueConstantRange,
9353 AAValueConstantRangeImpl,
9354 AAValueConstantRangeImpl::StateType,
9357 AAReturnedFromReturnedValues<AAValueConstantRange,
9358 AAValueConstantRangeImpl,
9359 AAValueConstantRangeImpl::StateType,
9361 AAValueConstantRangeReturned(
const IRPosition &IRP, Attributor &
A)
9366 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9367 indicatePessimisticFixpoint();
9371 void trackStatistics()
const override {
9376struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
9377 AAValueConstantRangeFloating(
const IRPosition &IRP, Attributor &
A)
9378 : AAValueConstantRangeImpl(IRP,
A) {}
9382 AAValueConstantRangeImpl::initialize(
A);
9386 Value &
V = getAssociatedValue();
9389 unionAssumed(ConstantRange(
C->getValue()));
9390 indicateOptimisticFixpoint();
9396 unionAssumed(ConstantRange(APInt(
getBitWidth(), 0)));
9397 indicateOptimisticFixpoint();
9409 if (
auto *RangeMD = LI->getMetadata(LLVMContext::MD_range)) {
9420 indicatePessimisticFixpoint();
9423 << getAssociatedValue() <<
"\n");
9426 bool calculateBinaryOperator(
9427 Attributor &
A, BinaryOperator *BinOp, IntegerRangeState &
T,
9428 const Instruction *CtxI,
9429 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9434 bool UsedAssumedInformation =
false;
9435 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9438 if (!SimplifiedLHS.has_value())
9440 if (!*SimplifiedLHS)
9442 LHS = *SimplifiedLHS;
9444 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9447 if (!SimplifiedRHS.has_value())
9449 if (!*SimplifiedRHS)
9451 RHS = *SimplifiedRHS;
9457 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9459 DepClassTy::REQUIRED);
9463 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9465 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9467 DepClassTy::REQUIRED);
9471 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9473 auto AssumedRange = LHSAARange.binaryOp(BinOp->
getOpcode(), RHSAARange);
9475 T.unionAssumed(AssumedRange);
9479 return T.isValidState();
9482 bool calculateCastInst(
9483 Attributor &
A, CastInst *CastI, IntegerRangeState &
T,
9484 const Instruction *CtxI,
9485 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9491 bool UsedAssumedInformation =
false;
9492 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9495 if (!SimplifiedOpV.has_value())
9497 if (!*SimplifiedOpV)
9499 OpV = *SimplifiedOpV;
9504 auto *OpAA =
A.getAAFor<AAValueConstantRange>(
9506 DepClassTy::REQUIRED);
9510 T.unionAssumed(OpAA->getAssumed().castOp(CastI->
getOpcode(),
9512 return T.isValidState();
9516 calculateCmpInst(Attributor &
A, CmpInst *CmpI, IntegerRangeState &
T,
9517 const Instruction *CtxI,
9518 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9523 bool UsedAssumedInformation =
false;
9524 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9527 if (!SimplifiedLHS.has_value())
9529 if (!*SimplifiedLHS)
9531 LHS = *SimplifiedLHS;
9533 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9536 if (!SimplifiedRHS.has_value())
9538 if (!*SimplifiedRHS)
9540 RHS = *SimplifiedRHS;
9546 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9548 DepClassTy::REQUIRED);
9552 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9554 DepClassTy::REQUIRED);
9558 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9559 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9562 if (LHSAARange.isEmptySet() || RHSAARange.isEmptySet())
9565 bool MustTrue =
false, MustFalse =
false;
9567 auto AllowedRegion =
9570 if (AllowedRegion.intersectWith(LHSAARange).isEmptySet())
9576 assert((!MustTrue || !MustFalse) &&
9577 "Either MustTrue or MustFalse should be false!");
9580 T.unionAssumed(ConstantRange(APInt( 1, 1)));
9582 T.unionAssumed(ConstantRange(APInt( 1, 0)));
9584 T.unionAssumed(ConstantRange( 1,
true));
9586 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] " << *CmpI <<
" after "
9587 << (MustTrue ?
"true" : (MustFalse ?
"false" :
"unknown"))
9588 <<
": " <<
T <<
"\n\t" << *LHSAA <<
"\t<op>\n\t"
9592 return T.isValidState();
9604 bool UsedAssumedInformation =
false;
9605 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9608 if (!SimplifiedOpV.has_value())
9610 if (!*SimplifiedOpV)
9612 Value *VPtr = *SimplifiedOpV;
9615 const auto *AA =
A.getAAFor<AAValueConstantRange>(
9617 DepClassTy::REQUIRED);
9621 T.unionAssumed(AA->getAssumedConstantRange(
A, CtxI));
9625 return T.isValidState();
9630 if (!calculateBinaryOperator(
A, BinOp,
T, CtxI, QuerriedAAs))
9633 if (!calculateCmpInst(
A, CmpI,
T, CtxI, QuerriedAAs))
9636 if (!calculateCastInst(
A, CastI,
T, CtxI, QuerriedAAs))
9642 T.indicatePessimisticFixpoint();
9649 for (
const AAValueConstantRange *QueriedAA : QuerriedAAs) {
9650 if (QueriedAA !=
this)
9653 if (
T.getAssumed() == getState().getAssumed())
9655 T.indicatePessimisticFixpoint();
9658 return T.isValidState();
9661 if (!VisitValueCB(getAssociatedValue(), getCtxI()))
9662 return indicatePessimisticFixpoint();
9667 return ChangeStatus::UNCHANGED;
9668 if (++NumChanges > MaxNumChanges) {
9669 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] performed " << NumChanges
9670 <<
" but only " << MaxNumChanges
9671 <<
" are allowed to avoid cyclic reasoning.");
9672 return indicatePessimisticFixpoint();
9674 return ChangeStatus::CHANGED;
9678 void trackStatistics()
const override {
9687 static constexpr int MaxNumChanges = 5;
9690struct AAValueConstantRangeFunction : AAValueConstantRangeImpl {
9691 AAValueConstantRangeFunction(
const IRPosition &IRP, Attributor &
A)
9692 : AAValueConstantRangeImpl(IRP,
A) {}
9696 llvm_unreachable(
"AAValueConstantRange(Function|CallSite)::updateImpl will "
9704struct AAValueConstantRangeCallSite : AAValueConstantRangeFunction {
9705 AAValueConstantRangeCallSite(
const IRPosition &IRP, Attributor &
A)
9706 : AAValueConstantRangeFunction(IRP,
A) {}
9712struct AAValueConstantRangeCallSiteReturned
9713 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9714 AAValueConstantRangeImpl::StateType,
9716 AAValueConstantRangeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
9717 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9718 AAValueConstantRangeImpl::StateType,
9725 if (std::optional<ConstantRange>
Range = CI->getRange())
9726 intersectKnown(*
Range);
9729 AAValueConstantRangeImpl::initialize(
A);
9733 void trackStatistics()
const override {
9737struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating {
9738 AAValueConstantRangeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
9739 : AAValueConstantRangeFloating(IRP,
A) {}
9743 return ChangeStatus::UNCHANGED;
9747 void trackStatistics()
const override {
9756struct AAPotentialConstantValuesImpl : AAPotentialConstantValues {
9759 AAPotentialConstantValuesImpl(
const IRPosition &IRP, Attributor &
A)
9760 : AAPotentialConstantValues(IRP,
A) {}
9764 if (
A.hasSimplificationCallback(getIRPosition()))
9765 indicatePessimisticFixpoint();
9767 AAPotentialConstantValues::initialize(
A);
9770 bool fillSetWithConstantValues(Attributor &
A,
const IRPosition &IRP, SetTy &S,
9771 bool &ContainsUndef,
bool ForSelf) {
9773 bool UsedAssumedInformation =
false;
9775 UsedAssumedInformation)) {
9782 auto *PotentialValuesAA =
A.getAAFor<AAPotentialConstantValues>(
9783 *
this, IRP, DepClassTy::REQUIRED);
9784 if (!PotentialValuesAA || !PotentialValuesAA->getState().isValidState())
9786 ContainsUndef = PotentialValuesAA->getState().undefIsContained();
9787 S = PotentialValuesAA->getState().getAssumedSet();
9794 ContainsUndef =
false;
9795 for (
auto &It : Values) {
9797 ContainsUndef =
true;
9803 S.insert(CI->getValue());
9805 ContainsUndef &= S.empty();
9811 const std::string getAsStr(Attributor *
A)
const override {
9813 llvm::raw_string_ostream OS(Str);
9820 return indicatePessimisticFixpoint();
9824struct AAPotentialConstantValuesArgument final
9825 : AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9826 AAPotentialConstantValuesImpl,
9827 PotentialConstantIntValuesState> {
9828 using Base = AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9829 AAPotentialConstantValuesImpl,
9831 AAPotentialConstantValuesArgument(
const IRPosition &IRP, Attributor &
A)
9835 void trackStatistics()
const override {
9840struct AAPotentialConstantValuesReturned
9841 : AAReturnedFromReturnedValues<AAPotentialConstantValues,
9842 AAPotentialConstantValuesImpl> {
9843 using Base = AAReturnedFromReturnedValues<AAPotentialConstantValues,
9844 AAPotentialConstantValuesImpl>;
9845 AAPotentialConstantValuesReturned(
const IRPosition &IRP, Attributor &
A)
9849 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9850 indicatePessimisticFixpoint();
9851 Base::initialize(
A);
9855 void trackStatistics()
const override {
9860struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl {
9861 AAPotentialConstantValuesFloating(
const IRPosition &IRP, Attributor &
A)
9862 : AAPotentialConstantValuesImpl(IRP,
A) {}
9866 AAPotentialConstantValuesImpl::initialize(
A);
9870 Value &
V = getAssociatedValue();
9873 unionAssumed(
C->getValue());
9874 indicateOptimisticFixpoint();
9879 unionAssumedWithUndef();
9880 indicateOptimisticFixpoint();
9890 indicatePessimisticFixpoint();
9893 << getAssociatedValue() <<
"\n");
9896 static bool calculateICmpInst(
const ICmpInst *ICI,
const APInt &
LHS,
9901 static APInt calculateCastInst(
const CastInst *CI,
const APInt &Src,
9902 uint32_t ResultBitWidth) {
9907 case Instruction::Trunc:
9908 return Src.trunc(ResultBitWidth);
9909 case Instruction::SExt:
9910 return Src.sext(ResultBitWidth);
9911 case Instruction::ZExt:
9912 return Src.zext(ResultBitWidth);
9913 case Instruction::BitCast:
9918 static APInt calculateBinaryOperator(
const BinaryOperator *BinOp,
9919 const APInt &
LHS,
const APInt &
RHS,
9920 bool &SkipOperation,
bool &Unsupported) {
9927 switch (BinOpcode) {
9931 case Instruction::Add:
9933 case Instruction::Sub:
9935 case Instruction::Mul:
9937 case Instruction::UDiv:
9939 SkipOperation =
true;
9943 case Instruction::SDiv:
9945 SkipOperation =
true;
9949 case Instruction::URem:
9951 SkipOperation =
true;
9955 case Instruction::SRem:
9957 SkipOperation =
true;
9961 case Instruction::Shl:
9963 case Instruction::LShr:
9965 case Instruction::AShr:
9967 case Instruction::And:
9969 case Instruction::Or:
9971 case Instruction::Xor:
9976 bool calculateBinaryOperatorAndTakeUnion(
const BinaryOperator *BinOp,
9977 const APInt &
LHS,
const APInt &
RHS) {
9978 bool SkipOperation =
false;
9981 calculateBinaryOperator(BinOp,
LHS,
RHS, SkipOperation, Unsupported);
9986 unionAssumed(Result);
9987 return isValidState();
9990 ChangeStatus updateWithICmpInst(Attributor &
A, ICmpInst *ICI) {
9991 auto AssumedBefore = getAssumed();
9995 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
9996 SetTy LHSAAPVS, RHSAAPVS;
9998 LHSContainsUndef,
false) ||
10000 RHSContainsUndef,
false))
10001 return indicatePessimisticFixpoint();
10004 bool MaybeTrue =
false, MaybeFalse =
false;
10006 if (LHSContainsUndef && RHSContainsUndef) {
10009 unionAssumedWithUndef();
10010 }
else if (LHSContainsUndef) {
10011 for (
const APInt &R : RHSAAPVS) {
10012 bool CmpResult = calculateICmpInst(ICI, Zero, R);
10013 MaybeTrue |= CmpResult;
10014 MaybeFalse |= !CmpResult;
10015 if (MaybeTrue & MaybeFalse)
10016 return indicatePessimisticFixpoint();
10018 }
else if (RHSContainsUndef) {
10019 for (
const APInt &L : LHSAAPVS) {
10020 bool CmpResult = calculateICmpInst(ICI, L, Zero);
10021 MaybeTrue |= CmpResult;
10022 MaybeFalse |= !CmpResult;
10023 if (MaybeTrue & MaybeFalse)
10024 return indicatePessimisticFixpoint();
10027 for (
const APInt &L : LHSAAPVS) {
10028 for (
const APInt &R : RHSAAPVS) {
10029 bool CmpResult = calculateICmpInst(ICI, L, R);
10030 MaybeTrue |= CmpResult;
10031 MaybeFalse |= !CmpResult;
10032 if (MaybeTrue & MaybeFalse)
10033 return indicatePessimisticFixpoint();
10038 unionAssumed(APInt( 1, 1));
10040 unionAssumed(APInt( 1, 0));
10041 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10042 : ChangeStatus::CHANGED;
10045 ChangeStatus updateWithSelectInst(Attributor &
A, SelectInst *SI) {
10046 auto AssumedBefore = getAssumed();
10050 bool UsedAssumedInformation =
false;
10051 std::optional<Constant *>
C =
A.getAssumedConstant(
10052 *
SI->getCondition(), *
this, UsedAssumedInformation);
10055 bool OnlyLeft =
false, OnlyRight =
false;
10056 if (
C && *
C && (*C)->isOneValue())
10058 else if (
C && *
C && (*C)->isZeroValue())
10061 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10062 SetTy LHSAAPVS, RHSAAPVS;
10065 LHSContainsUndef,
false))
10066 return indicatePessimisticFixpoint();
10070 RHSContainsUndef,
false))
10071 return indicatePessimisticFixpoint();
10073 if (OnlyLeft || OnlyRight) {
10075 auto *OpAA = OnlyLeft ? &LHSAAPVS : &RHSAAPVS;
10076 auto Undef = OnlyLeft ? LHSContainsUndef : RHSContainsUndef;
10079 unionAssumedWithUndef();
10081 for (
const auto &It : *OpAA)
10085 }
else if (LHSContainsUndef && RHSContainsUndef) {
10087 unionAssumedWithUndef();
10089 for (
const auto &It : LHSAAPVS)
10091 for (
const auto &It : RHSAAPVS)
10094 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10095 : ChangeStatus::CHANGED;
10098 ChangeStatus updateWithCastInst(Attributor &
A, CastInst *CI) {
10099 auto AssumedBefore = getAssumed();
10101 return indicatePessimisticFixpoint();
10106 bool SrcContainsUndef =
false;
10109 SrcContainsUndef,
false))
10110 return indicatePessimisticFixpoint();
10112 if (SrcContainsUndef)
10113 unionAssumedWithUndef();
10115 for (
const APInt &S : SrcPVS) {
10116 APInt
T = calculateCastInst(CI, S, ResultBitWidth);
10120 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10121 : ChangeStatus::CHANGED;
10124 ChangeStatus updateWithBinaryOperator(Attributor &
A, BinaryOperator *BinOp) {
10125 auto AssumedBefore = getAssumed();
10129 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
10130 SetTy LHSAAPVS, RHSAAPVS;
10132 LHSContainsUndef,
false) ||
10134 RHSContainsUndef,
false))
10135 return indicatePessimisticFixpoint();
10140 if (LHSContainsUndef && RHSContainsUndef) {
10141 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))
10142 return indicatePessimisticFixpoint();
10143 }
else if (LHSContainsUndef) {
10144 for (
const APInt &R : RHSAAPVS) {
10145 if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))
10146 return indicatePessimisticFixpoint();
10148 }
else if (RHSContainsUndef) {
10149 for (
const APInt &L : LHSAAPVS) {
10150 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
10151 return indicatePessimisticFixpoint();
10154 for (
const APInt &L : LHSAAPVS) {
10155 for (
const APInt &R : RHSAAPVS) {
10156 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
10157 return indicatePessimisticFixpoint();
10161 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10162 : ChangeStatus::CHANGED;
10165 ChangeStatus updateWithInstruction(Attributor &
A, Instruction *Inst) {
10166 auto AssumedBefore = getAssumed();
10168 bool ContainsUndef;
10170 ContainsUndef,
true))
10171 return indicatePessimisticFixpoint();
10172 if (ContainsUndef) {
10173 unionAssumedWithUndef();
10175 for (
const auto &It : Incoming)
10178 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10179 : ChangeStatus::CHANGED;
10184 Value &
V = getAssociatedValue();
10188 return updateWithICmpInst(
A, ICI);
10191 return updateWithSelectInst(
A, SI);
10194 return updateWithCastInst(
A, CI);
10197 return updateWithBinaryOperator(
A, BinOp);
10200 return updateWithInstruction(
A,
I);
10202 return indicatePessimisticFixpoint();
10206 void trackStatistics()
const override {
10211struct AAPotentialConstantValuesFunction : AAPotentialConstantValuesImpl {
10212 AAPotentialConstantValuesFunction(
const IRPosition &IRP, Attributor &
A)
10213 : AAPotentialConstantValuesImpl(IRP,
A) {}
10218 "AAPotentialConstantValues(Function|CallSite)::updateImpl will "
10223 void trackStatistics()
const override {
10228struct AAPotentialConstantValuesCallSite : AAPotentialConstantValuesFunction {
10229 AAPotentialConstantValuesCallSite(
const IRPosition &IRP, Attributor &
A)
10230 : AAPotentialConstantValuesFunction(IRP,
A) {}
10233 void trackStatistics()
const override {
10238struct AAPotentialConstantValuesCallSiteReturned
10239 : AACalleeToCallSite<AAPotentialConstantValues,
10240 AAPotentialConstantValuesImpl> {
10241 AAPotentialConstantValuesCallSiteReturned(
const IRPosition &IRP,
10243 : AACalleeToCallSite<AAPotentialConstantValues,
10244 AAPotentialConstantValuesImpl>(IRP,
A) {}
10247 void trackStatistics()
const override {
10252struct AAPotentialConstantValuesCallSiteArgument
10253 : AAPotentialConstantValuesFloating {
10254 AAPotentialConstantValuesCallSiteArgument(
const IRPosition &IRP,
10256 : AAPotentialConstantValuesFloating(IRP,
A) {}
10260 AAPotentialConstantValuesImpl::initialize(
A);
10261 if (isAtFixpoint())
10264 Value &
V = getAssociatedValue();
10267 unionAssumed(
C->getValue());
10268 indicateOptimisticFixpoint();
10273 unionAssumedWithUndef();
10274 indicateOptimisticFixpoint();
10281 Value &
V = getAssociatedValue();
10282 auto AssumedBefore = getAssumed();
10283 auto *AA =
A.getAAFor<AAPotentialConstantValues>(
10286 return indicatePessimisticFixpoint();
10287 const auto &S = AA->getAssumed();
10289 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10290 : ChangeStatus::CHANGED;
10294 void trackStatistics()
const override {
10303 bool IgnoreSubsumingPositions) {
10304 assert(ImpliedAttributeKind == Attribute::NoUndef &&
10305 "Unexpected attribute kind");
10306 if (
A.hasAttr(IRP, {Attribute::NoUndef}, IgnoreSubsumingPositions,
10307 Attribute::NoUndef))
10327 Value &V = getAssociatedValue();
10329 indicatePessimisticFixpoint();
10330 assert(!isImpliedByIR(
A, getIRPosition(), Attribute::NoUndef));
10334 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10335 AANoUndef::StateType &State) {
10336 const Value *UseV =
U->get();
10337 const DominatorTree *DT =
nullptr;
10338 AssumptionCache *AC =
nullptr;
10339 InformationCache &InfoCache =
A.getInfoCache();
10340 if (Function *
F = getAnchorScope()) {
10345 bool TrackUse =
false;
10354 const std::string getAsStr(Attributor *
A)
const override {
10355 return getAssumed() ?
"noundef" :
"may-undef-or-poison";
10362 bool UsedAssumedInformation =
false;
10363 if (
A.isAssumedDead(getIRPosition(),
nullptr,
nullptr,
10364 UsedAssumedInformation))
10365 return ChangeStatus::UNCHANGED;
10369 if (!
A.getAssumedSimplified(getIRPosition(), *
this, UsedAssumedInformation,
10372 return ChangeStatus::UNCHANGED;
10373 return AANoUndef::manifest(
A);
10377struct AANoUndefFloating :
public AANoUndefImpl {
10378 AANoUndefFloating(
const IRPosition &IRP, Attributor &
A)
10379 : AANoUndefImpl(IRP,
A) {}
10383 AANoUndefImpl::initialize(
A);
10384 if (!getState().isAtFixpoint() && getAnchorScope() &&
10385 !getAnchorScope()->isDeclaration())
10386 if (Instruction *CtxI = getCtxI())
10387 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10392 auto VisitValueCB = [&](
const IRPosition &IRP) ->
bool {
10393 bool IsKnownNoUndef;
10395 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoUndef);
10399 bool UsedAssumedInformation =
false;
10400 Value *AssociatedValue = &getAssociatedValue();
10402 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10407 Values.
size() != 1 || Values.
front().getValue() != AssociatedValue;
10415 if (AVIRP == getIRPosition() || !VisitValueCB(AVIRP))
10416 return indicatePessimisticFixpoint();
10417 return ChangeStatus::UNCHANGED;
10420 for (
const auto &VAC : Values)
10422 return indicatePessimisticFixpoint();
10424 return ChangeStatus::UNCHANGED;
10431struct AANoUndefReturned final
10432 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl> {
10433 AANoUndefReturned(
const IRPosition &IRP, Attributor &
A)
10434 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10440struct AANoUndefArgument final
10441 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl> {
10442 AANoUndefArgument(
const IRPosition &IRP, Attributor &
A)
10443 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10449struct AANoUndefCallSiteArgument final : AANoUndefFloating {
10450 AANoUndefCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10451 : AANoUndefFloating(IRP,
A) {}
10457struct AANoUndefCallSiteReturned final
10458 : AACalleeToCallSite<AANoUndef, AANoUndefImpl> {
10459 AANoUndefCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10460 : AACalleeToCallSite<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10468struct AANoFPClassImpl : AANoFPClass {
10469 AANoFPClassImpl(
const IRPosition &IRP, Attributor &
A) : AANoFPClass(IRP,
A) {}
10472 const IRPosition &IRP = getIRPosition();
10476 indicateOptimisticFixpoint();
10481 A.getAttrs(getIRPosition(), {Attribute::NoFPClass},
Attrs,
false);
10482 for (
const auto &Attr : Attrs) {
10486 const DataLayout &
DL =
A.getDataLayout();
10492 if (Instruction *CtxI = getCtxI())
10493 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10497 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10498 AANoFPClass::StateType &State) {
10509 if (
auto *NoFPAA =
A.getAAFor<AANoFPClass>(*
this, IRP, DepClassTy::NONE))
10510 State.addKnownBits(NoFPAA->getState().getKnown());
10514 const std::string getAsStr(Attributor *
A)
const override {
10515 std::string
Result =
"nofpclass";
10516 raw_string_ostream OS(Result);
10517 OS << getKnownNoFPClass() <<
'/' << getAssumedNoFPClass();
10521 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
10522 SmallVectorImpl<Attribute> &Attrs)
const override {
10523 Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));
10527struct AANoFPClassFloating :
public AANoFPClassImpl {
10528 AANoFPClassFloating(
const IRPosition &IRP, Attributor &
A)
10529 : AANoFPClassImpl(IRP,
A) {}
10534 bool UsedAssumedInformation =
false;
10535 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this, Values,
10537 Values.
push_back({getAssociatedValue(), getCtxI()});
10543 DepClassTy::REQUIRED);
10544 if (!AA ||
this == AA) {
10545 T.indicatePessimisticFixpoint();
10547 const AANoFPClass::StateType &S =
10548 static_cast<const AANoFPClass::StateType &
>(AA->
getState());
10551 return T.isValidState();
10554 for (
const auto &VAC : Values)
10556 return indicatePessimisticFixpoint();
10562 void trackStatistics()
const override {
10567struct AANoFPClassReturned final
10568 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10569 AANoFPClassImpl::StateType, false,
10570 Attribute::None, false> {
10571 AANoFPClassReturned(
const IRPosition &IRP, Attributor &
A)
10572 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10573 AANoFPClassImpl::StateType,
false,
10577 void trackStatistics()
const override {
10582struct AANoFPClassArgument final
10583 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {
10584 AANoFPClassArgument(
const IRPosition &IRP, Attributor &
A)
10585 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10591struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {
10592 AANoFPClassCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10593 : AANoFPClassFloating(IRP,
A) {}
10596 void trackStatistics()
const override {
10601struct AANoFPClassCallSiteReturned final
10602 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl> {
10603 AANoFPClassCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10604 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10607 void trackStatistics()
const override {
10612struct AACallEdgesImpl :
public AACallEdges {
10613 AACallEdgesImpl(
const IRPosition &IRP, Attributor &
A) : AACallEdges(IRP,
A) {}
10615 const SetVector<Function *> &getOptimisticEdges()
const override {
10616 return CalledFunctions;
10619 bool hasUnknownCallee()
const override {
return HasUnknownCallee; }
10621 bool hasNonAsmUnknownCallee()
const override {
10622 return HasUnknownCalleeNonAsm;
10625 const std::string getAsStr(Attributor *
A)
const override {
10626 return "CallEdges[" + std::to_string(HasUnknownCallee) +
"," +
10627 std::to_string(CalledFunctions.size()) +
"]";
10630 void trackStatistics()
const override {}
10633 void addCalledFunction(Function *Fn,
ChangeStatus &Change) {
10634 if (CalledFunctions.insert(Fn)) {
10635 Change = ChangeStatus::CHANGED;
10641 void setHasUnknownCallee(
bool NonAsm,
ChangeStatus &Change) {
10642 if (!HasUnknownCallee)
10643 Change = ChangeStatus::CHANGED;
10644 if (NonAsm && !HasUnknownCalleeNonAsm)
10645 Change = ChangeStatus::CHANGED;
10646 HasUnknownCalleeNonAsm |= NonAsm;
10647 HasUnknownCallee =
true;
10652 SetVector<Function *> CalledFunctions;
10655 bool HasUnknownCallee =
false;
10658 bool HasUnknownCalleeNonAsm =
false;
10661struct AACallEdgesCallSite :
public AACallEdgesImpl {
10662 AACallEdgesCallSite(
const IRPosition &IRP, Attributor &
A)
10663 : AACallEdgesImpl(IRP,
A) {}
10670 addCalledFunction(Fn, Change);
10672 LLVM_DEBUG(
dbgs() <<
"[AACallEdges] Unrecognized value: " << V <<
"\n");
10673 setHasUnknownCallee(
true, Change);
10684 VisitValue(*V, CtxI);
10688 bool UsedAssumedInformation =
false;
10694 for (
auto &VAC : Values)
10701 if (
IA->hasSideEffects() &&
10704 setHasUnknownCallee(
false, Change);
10710 if (
auto *IndirectCallAA =
A.getAAFor<AAIndirectCallInfo>(
10711 *
this, getIRPosition(), DepClassTy::OPTIONAL))
10712 if (IndirectCallAA->foreachCallee(
10713 [&](Function *Fn) { return VisitValue(*Fn, CB); }))
10722 for (
const Use *U : CallbackUses)
10723 ProcessCalledOperand(
U->get(), CB);
10729struct AACallEdgesFunction :
public AACallEdgesImpl {
10730 AACallEdgesFunction(
const IRPosition &IRP, Attributor &
A)
10731 : AACallEdgesImpl(IRP,
A) {}
10740 auto *CBEdges =
A.getAAFor<AACallEdges>(
10744 if (CBEdges->hasNonAsmUnknownCallee())
10745 setHasUnknownCallee(
true, Change);
10746 if (CBEdges->hasUnknownCallee())
10747 setHasUnknownCallee(
false, Change);
10749 for (Function *
F : CBEdges->getOptimisticEdges())
10750 addCalledFunction(
F, Change);
10756 bool UsedAssumedInformation =
false;
10757 if (!
A.checkForAllCallLikeInstructions(ProcessCallInst, *
this,
10758 UsedAssumedInformation,
10762 setHasUnknownCallee(
true, Change);
10771struct AAInterFnReachabilityFunction
10772 :
public CachedReachabilityAA<AAInterFnReachability, Function> {
10773 using Base = CachedReachabilityAA<AAInterFnReachability, Function>;
10774 AAInterFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
10777 bool instructionCanReach(
10778 Attributor &
A,
const Instruction &From,
const Function &To,
10781 auto *NonConstThis =
const_cast<AAInterFnReachabilityFunction *
>(
this);
10783 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
10784 RQITy::Reachable
Result;
10785 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
10786 return NonConstThis->isReachableImpl(
A, StackRQI,
10788 return Result == RQITy::Reachable::Yes;
10792 bool IsTemporaryRQI)
override {
10794 &RQI.From->getFunction()->getEntryBlock().front();
10795 if (EntryI != RQI.From &&
10796 !instructionCanReach(
A, *EntryI, *RQI.To,
nullptr))
10797 return rememberResult(
A, RQITy::Reachable::No, RQI,
false,
10800 auto CheckReachableCallBase = [&](CallBase *CB) {
10801 auto *CBEdges =
A.getAAFor<AACallEdges>(
10803 if (!CBEdges || !CBEdges->getState().isValidState())
10806 if (CBEdges->hasUnknownCallee())
10809 for (Function *Fn : CBEdges->getOptimisticEdges()) {
10820 if (Fn == getAnchorScope()) {
10821 if (EntryI == RQI.From)
10826 const AAInterFnReachability *InterFnReachability =
10828 DepClassTy::OPTIONAL);
10831 if (!InterFnReachability ||
10839 const auto *IntraFnReachability =
A.getAAFor<AAIntraFnReachability>(
10841 DepClassTy::OPTIONAL);
10849 return IntraFnReachability && !IntraFnReachability->isAssumedReachable(
10850 A, *RQI.From, CBInst, RQI.ExclusionSet);
10853 bool UsedExclusionSet =
true;
10854 bool UsedAssumedInformation =
false;
10855 if (!
A.checkForAllCallLikeInstructions(CheckCallBase, *
this,
10856 UsedAssumedInformation,
10858 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
10861 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
10865 void trackStatistics()
const override {}
10869template <
typename AAType>
10870static std::optional<Constant *>
10873 if (!Ty.isIntegerTy())
10881 std::optional<Constant *> COpt =
AA->getAssumedConstant(
A);
10883 if (!COpt.has_value()) {
10885 return std::nullopt;
10887 if (
auto *
C = *COpt) {
10898 std::optional<Value *> V;
10899 for (
auto &It : Values) {
10901 if (V.has_value() && !*V)
10904 if (!V.has_value())
10918 if (
A.hasSimplificationCallback(getIRPosition())) {
10919 indicatePessimisticFixpoint();
10922 Value *Stripped = getAssociatedValue().stripPointerCasts();
10924 addValue(
A, getState(), *Stripped, getCtxI(),
AA::AnyScope,
10926 indicateOptimisticFixpoint();
10929 AAPotentialValues::initialize(
A);
10933 const std::string getAsStr(Attributor *
A)
const override {
10935 llvm::raw_string_ostream OS(Str);
10940 template <
typename AAType>
10941 static std::optional<Value *> askOtherAA(Attributor &
A,
10942 const AbstractAttribute &AA,
10943 const IRPosition &IRP,
Type &Ty) {
10948 return std::nullopt;
10955 virtual void addValue(Attributor &
A, StateType &State,
Value &V,
10957 Function *AnchorScope)
const {
10961 for (
const auto &U : CB->
args()) {
10971 Type &Ty = *getAssociatedType();
10972 std::optional<Value *> SimpleV =
10973 askOtherAA<AAValueConstantRange>(
A, *
this, ValIRP, Ty);
10974 if (SimpleV.has_value() && !*SimpleV) {
10975 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
10976 *
this, ValIRP, DepClassTy::OPTIONAL);
10977 if (PotentialConstantsAA && PotentialConstantsAA->isValidState()) {
10978 for (
const auto &It : PotentialConstantsAA->getAssumedSet())
10979 State.unionAssumed({{*ConstantInt::get(&Ty, It),
nullptr}, S});
10980 if (PotentialConstantsAA->undefIsContained())
10985 if (!SimpleV.has_value())
10997 State.unionAssumed({{*VPtr, CtxI}, S});
11003 AA::ValueAndContext
I;
11007 return II.I ==
I &&
II.S == S;
11010 return std::tie(
I, S) < std::tie(
II.I,
II.S);
11014 bool recurseForValue(Attributor &
A,
const IRPosition &IRP,
AA::ValueScope S) {
11015 SmallMapVector<AA::ValueAndContext, int, 8> ValueScopeMap;
11020 bool UsedAssumedInformation =
false;
11022 if (!
A.getAssumedSimplifiedValues(IRP,
this, Values, CS,
11023 UsedAssumedInformation))
11026 for (
auto &It : Values)
11027 ValueScopeMap[It] += CS;
11029 for (
auto &It : ValueScopeMap)
11030 addValue(
A, getState(), *It.first.getValue(), It.first.getCtxI(),
11036 void giveUpOnIntraprocedural(Attributor &
A) {
11037 auto NewS = StateType::getBestState(getState());
11038 for (
const auto &It : getAssumedSet()) {
11041 addValue(
A, NewS, *It.first.getValue(), It.first.getCtxI(),
11044 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11052 getState() = StateType::getBestState(getState());
11053 getState().unionAssumed({{getAssociatedValue(), getCtxI()},
AA::AnyScope});
11054 AAPotentialValues::indicateOptimisticFixpoint();
11055 return ChangeStatus::CHANGED;
11060 return indicatePessimisticFixpoint();
11068 if (!getAssumedSimplifiedValues(
A, Values, S))
11070 Value &OldV = getAssociatedValue();
11073 Value *NewV = getSingleValue(
A, *
this, getIRPosition(), Values);
11074 if (!NewV || NewV == &OldV)
11079 if (
A.changeAfterManifest(getIRPosition(), *NewV))
11080 return ChangeStatus::CHANGED;
11082 return ChangeStatus::UNCHANGED;
11085 bool getAssumedSimplifiedValues(
11086 Attributor &
A, SmallVectorImpl<AA::ValueAndContext> &Values,
11087 AA::ValueScope S,
bool RecurseForSelectAndPHI =
false)
const override {
11088 if (!isValidState())
11090 bool UsedAssumedInformation =
false;
11091 for (
const auto &It : getAssumedSet())
11092 if (It.second & S) {
11093 if (RecurseForSelectAndPHI && (
isa<PHINode>(It.first.getValue()) ||
11095 if (
A.getAssumedSimplifiedValues(
11097 this, Values, S, UsedAssumedInformation))
11102 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11107struct AAPotentialValuesFloating : AAPotentialValuesImpl {
11108 AAPotentialValuesFloating(
const IRPosition &IRP, Attributor &
A)
11109 : AAPotentialValuesImpl(IRP,
A) {}
11113 auto AssumedBefore = getAssumed();
11115 genericValueTraversal(
A, &getAssociatedValue());
11117 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11118 : ChangeStatus::CHANGED;
11122 struct LivenessInfo {
11123 const AAIsDead *LivenessAA =
nullptr;
11124 bool AnyDead =
false;
11134 SmallVectorImpl<ItemInfo> &Worklist) {
11137 bool UsedAssumedInformation =
false;
11139 auto GetSimplifiedValues = [&](
Value &
V,
11141 if (!
A.getAssumedSimplifiedValues(
11145 Values.
push_back(AA::ValueAndContext{
V,
II.I.getCtxI()});
11147 return Values.
empty();
11149 if (GetSimplifiedValues(*
LHS, LHSValues))
11151 if (GetSimplifiedValues(*
RHS, RHSValues))
11156 InformationCache &InfoCache =
A.getInfoCache();
11163 F ?
A.getInfoCache().getTargetLibraryInfoForFunction(*
F) :
nullptr;
11168 const DataLayout &
DL =
A.getDataLayout();
11169 SimplifyQuery Q(
DL, TLI, DT, AC, CmpI);
11171 auto CheckPair = [&](
Value &LHSV,
Value &RHSV) {
11174 nullptr,
II.S, getAnchorScope());
11180 if (&LHSV == &RHSV &&
11182 Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
11184 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11191 if (TypedLHS && TypedRHS) {
11193 if (NewV && NewV != &Cmp) {
11194 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11206 if (!LHSIsNull && !RHSIsNull)
11212 assert((LHSIsNull || RHSIsNull) &&
11213 "Expected nullptr versus non-nullptr comparison at this point");
11216 unsigned PtrIdx = LHSIsNull;
11217 bool IsKnownNonNull;
11220 DepClassTy::REQUIRED, IsKnownNonNull);
11221 if (!IsAssumedNonNull)
11227 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11232 for (
auto &LHSValue : LHSValues)
11233 for (
auto &RHSValue : RHSValues)
11234 if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))
11239 bool handleSelectInst(Attributor &
A, SelectInst &SI, ItemInfo
II,
11240 SmallVectorImpl<ItemInfo> &Worklist) {
11242 bool UsedAssumedInformation =
false;
11244 std::optional<Constant *>
C =
11245 A.getAssumedConstant(*
SI.getCondition(), *
this, UsedAssumedInformation);
11246 bool NoValueYet = !
C.has_value();
11254 }
else if (&SI == &getAssociatedValue()) {
11259 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11261 if (!SimpleV.has_value())
11264 addValue(
A, getState(), **SimpleV, CtxI,
II.S, getAnchorScope());
11272 bool handleLoadInst(Attributor &
A, LoadInst &LI, ItemInfo
II,
11273 SmallVectorImpl<ItemInfo> &Worklist) {
11274 SmallSetVector<Value *, 4> PotentialCopies;
11275 SmallSetVector<Instruction *, 4> PotentialValueOrigins;
11276 bool UsedAssumedInformation =
false;
11278 PotentialValueOrigins, *
this,
11279 UsedAssumedInformation,
11281 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Failed to get potentially "
11282 "loaded values for load instruction "
11290 InformationCache &InfoCache =
A.getInfoCache();
11292 if (!
llvm::all_of(PotentialValueOrigins, [&](Instruction *
I) {
11296 return A.isAssumedDead(
SI->getOperandUse(0),
this,
11298 UsedAssumedInformation,
11300 return A.isAssumedDead(*
I,
this,
nullptr,
11301 UsedAssumedInformation,
11304 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Load is onl used by assumes "
11305 "and we cannot delete all the stores: "
11316 bool AllLocal = ScopeIsLocal;
11321 if (!DynamicallyUnique) {
11322 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Not all potentially loaded "
11323 "values are dynamically unique: "
11328 for (
auto *PotentialCopy : PotentialCopies) {
11330 Worklist.
push_back({{*PotentialCopy, CtxI},
II.S});
11335 if (!AllLocal && ScopeIsLocal)
11340 bool handlePHINode(
11341 Attributor &
A, PHINode &
PHI, ItemInfo
II,
11342 SmallVectorImpl<ItemInfo> &Worklist,
11343 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11344 auto GetLivenessInfo = [&](
const Function &
F) -> LivenessInfo & {
11345 LivenessInfo &LI = LivenessAAs[&
F];
11346 if (!LI.LivenessAA)
11352 if (&
PHI == &getAssociatedValue()) {
11353 LivenessInfo &LI = GetLivenessInfo(*
PHI.getFunction());
11355 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
11356 *
PHI.getFunction());
11360 for (
unsigned u = 0, e =
PHI.getNumIncomingValues(); u < e; u++) {
11362 if (LI.LivenessAA &&
11363 LI.LivenessAA->isEdgeDead(IncomingBB,
PHI.getParent())) {
11382 bool UsedAssumedInformation =
false;
11383 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11385 if (!SimpleV.has_value())
11389 addValue(
A, getState(), **SimpleV, &
PHI,
II.S, getAnchorScope());
11396 bool handleGenericInst(Attributor &
A, Instruction &
I, ItemInfo
II,
11397 SmallVectorImpl<ItemInfo> &Worklist) {
11398 bool SomeSimplified =
false;
11399 bool UsedAssumedInformation =
false;
11401 SmallVector<Value *, 8> NewOps(
I.getNumOperands());
11404 const auto &SimplifiedOp =
A.getAssumedSimplified(
11409 if (!SimplifiedOp.has_value())
11413 NewOps[Idx] = *SimplifiedOp;
11417 SomeSimplified |= (NewOps[Idx] !=
Op);
11423 if (!SomeSimplified)
11426 InformationCache &InfoCache =
A.getInfoCache();
11430 const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
11433 const DataLayout &
DL =
I.getDataLayout();
11434 SimplifyQuery Q(
DL, TLI, DT, AC, &
I);
11436 if (!NewV || NewV == &
I)
11439 LLVM_DEBUG(
dbgs() <<
"Generic inst " <<
I <<
" assumed simplified to "
11446 Attributor &
A, Instruction &
I, ItemInfo
II,
11447 SmallVectorImpl<ItemInfo> &Worklist,
11448 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11451 CI->getPredicate(),
II, Worklist);
11453 switch (
I.getOpcode()) {
11454 case Instruction::Select:
11456 case Instruction::PHI:
11458 case Instruction::Load:
11461 return handleGenericInst(
A,
I,
II, Worklist);
11466 void genericValueTraversal(Attributor &
A,
Value *InitialV) {
11467 SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;
11469 SmallSet<ItemInfo, 16> Visited;
11488 LLVM_DEBUG(
dbgs() <<
"Generic value traversal reached iteration limit: "
11489 << Iteration <<
"!\n");
11490 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11496 Value *NewV =
nullptr;
11497 if (
V->getType()->isPointerTy()) {
11503 for (Argument &Arg :
Callee->args())
11510 if (NewV && NewV != V) {
11511 Worklist.
push_back({{*NewV, CtxI}, S});
11525 if (V == InitialV && CtxI == getCtxI()) {
11526 indicatePessimisticFixpoint();
11530 addValue(
A, getState(), *V, CtxI, S, getAnchorScope());
11531 }
while (!Worklist.
empty());
11535 for (
auto &It : LivenessAAs)
11536 if (It.second.AnyDead)
11537 A.recordDependence(*It.second.LivenessAA, *
this, DepClassTy::OPTIONAL);
11541 void trackStatistics()
const override {
11546struct AAPotentialValuesArgument final : AAPotentialValuesImpl {
11547 using Base = AAPotentialValuesImpl;
11548 AAPotentialValuesArgument(
const IRPosition &IRP, Attributor &
A)
11555 indicatePessimisticFixpoint();
11560 auto AssumedBefore = getAssumed();
11562 unsigned ArgNo = getCalleeArgNo();
11564 bool UsedAssumedInformation =
false;
11566 auto CallSitePred = [&](AbstractCallSite ACS) {
11568 if (CSArgIRP.getPositionKind() == IRP_INVALID)
11571 if (!
A.getAssumedSimplifiedValues(CSArgIRP,
this, Values,
11573 UsedAssumedInformation))
11576 return isValidState();
11579 if (!
A.checkForAllCallSites(CallSitePred, *
this,
11581 UsedAssumedInformation))
11582 return indicatePessimisticFixpoint();
11584 Function *Fn = getAssociatedFunction();
11585 bool AnyNonLocal =
false;
11586 for (
auto &It : Values) {
11588 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11593 return indicatePessimisticFixpoint();
11597 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11603 AnyNonLocal =
true;
11605 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11607 giveUpOnIntraprocedural(
A);
11609 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11610 : ChangeStatus::CHANGED;
11614 void trackStatistics()
const override {
11619struct AAPotentialValuesReturned :
public AAPotentialValuesFloating {
11620 using Base = AAPotentialValuesFloating;
11621 AAPotentialValuesReturned(
const IRPosition &IRP, Attributor &
A)
11627 if (!
F ||
F->isDeclaration() ||
F->getReturnType()->isVoidTy()) {
11628 indicatePessimisticFixpoint();
11632 for (Argument &Arg :
F->args())
11635 ReturnedArg = &Arg;
11638 if (!
A.isFunctionIPOAmendable(*
F) ||
11639 A.hasSimplificationCallback(getIRPosition())) {
11641 indicatePessimisticFixpoint();
11643 indicateOptimisticFixpoint();
11649 auto AssumedBefore = getAssumed();
11650 bool UsedAssumedInformation =
false;
11653 Function *AnchorScope = getAnchorScope();
11659 UsedAssumedInformation,
11665 bool AllInterAreIntra =
false;
11668 llvm::all_of(Values, [&](
const AA::ValueAndContext &VAC) {
11672 for (
const AA::ValueAndContext &VAC : Values) {
11673 addValue(
A, getState(), *VAC.
getValue(),
11677 if (AllInterAreIntra)
11684 HandleReturnedValue(*ReturnedArg,
nullptr,
true);
11687 bool AddValues =
true;
11690 addValue(
A, getState(), *RetI.getOperand(0), &RetI,
AA::AnyScope,
11694 return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);
11697 if (!
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11698 UsedAssumedInformation,
11700 return indicatePessimisticFixpoint();
11703 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11704 : ChangeStatus::CHANGED;
11709 return ChangeStatus::UNCHANGED;
11711 if (!getAssumedSimplifiedValues(
A, Values, AA::ValueScope::Intraprocedural,
11713 return ChangeStatus::UNCHANGED;
11714 Value *NewVal = getSingleValue(
A, *
this, getIRPosition(), Values);
11716 return ChangeStatus::UNCHANGED;
11721 "Number of function with unique return");
11724 {Attribute::get(Arg->
getContext(), Attribute::Returned)});
11729 Value *RetOp = RetI.getOperand(0);
11733 if (
A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))
11734 Changed = ChangeStatus::CHANGED;
11737 bool UsedAssumedInformation =
false;
11738 (void)
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11739 UsedAssumedInformation,
11745 return AAPotentialValues::indicatePessimisticFixpoint();
11749 void trackStatistics()
const override{
11756struct AAPotentialValuesFunction : AAPotentialValuesImpl {
11757 AAPotentialValuesFunction(
const IRPosition &IRP, Attributor &
A)
11758 : AAPotentialValuesImpl(IRP,
A) {}
11767 void trackStatistics()
const override {
11772struct AAPotentialValuesCallSite : AAPotentialValuesFunction {
11773 AAPotentialValuesCallSite(
const IRPosition &IRP, Attributor &
A)
11774 : AAPotentialValuesFunction(IRP,
A) {}
11777 void trackStatistics()
const override {
11782struct AAPotentialValuesCallSiteReturned : AAPotentialValuesImpl {
11783 AAPotentialValuesCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
11784 : AAPotentialValuesImpl(IRP,
A) {}
11788 auto AssumedBefore = getAssumed();
11792 return indicatePessimisticFixpoint();
11794 bool UsedAssumedInformation =
false;
11798 UsedAssumedInformation))
11799 return indicatePessimisticFixpoint();
11806 Values, S, UsedAssumedInformation))
11809 for (
auto &It : Values) {
11810 Value *
V = It.getValue();
11811 std::optional<Value *> CallerV =
A.translateArgumentToCallSiteContent(
11812 V, *CB, *
this, UsedAssumedInformation);
11813 if (!CallerV.has_value()) {
11817 V = *CallerV ? *CallerV :
V;
11823 giveUpOnIntraprocedural(
A);
11826 addValue(
A, getState(), *V, CB, S, getAnchorScope());
11831 return indicatePessimisticFixpoint();
11833 return indicatePessimisticFixpoint();
11834 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11835 : ChangeStatus::CHANGED;
11839 return AAPotentialValues::indicatePessimisticFixpoint();
11843 void trackStatistics()
const override {
11848struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
11849 AAPotentialValuesCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
11850 : AAPotentialValuesFloating(IRP,
A) {}
11853 void trackStatistics()
const override {
11861struct AAAssumptionInfoImpl :
public AAAssumptionInfo {
11862 AAAssumptionInfoImpl(
const IRPosition &IRP, Attributor &
A,
11863 const DenseSet<StringRef> &Known)
11864 : AAAssumptionInfo(IRP,
A, Known) {}
11869 if (getKnown().isUniversal())
11870 return ChangeStatus::UNCHANGED;
11872 const IRPosition &IRP = getIRPosition();
11874 getAssumed().getSet().
end());
11876 return A.manifestAttrs(IRP,
11883 bool hasAssumption(
const StringRef Assumption)
const override {
11884 return isValidState() && setContains(Assumption);
11888 const std::string getAsStr(Attributor *
A)
const override {
11889 const SetContents &Known = getKnown();
11890 const SetContents &Assumed = getAssumed();
11894 const std::string KnownStr =
llvm::join(Set,
",");
11896 std::string AssumedStr =
"Universal";
11897 if (!Assumed.isUniversal()) {
11898 Set.assign(Assumed.getSet().begin(), Assumed.getSet().end());
11901 return "Known [" + KnownStr +
"]," +
" Assumed [" + AssumedStr +
"]";
11916struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {
11917 AAAssumptionInfoFunction(
const IRPosition &IRP, Attributor &
A)
11918 : AAAssumptionInfoImpl(IRP,
A,
11925 auto CallSitePred = [&](AbstractCallSite ACS) {
11926 const auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
11928 DepClassTy::REQUIRED);
11932 Changed |= getIntersection(AssumptionAA->getAssumed());
11933 return !getAssumed().empty() || !getKnown().empty();
11936 bool UsedAssumedInformation =
false;
11941 if (!
A.checkForAllCallSites(CallSitePred, *
this,
true,
11942 UsedAssumedInformation))
11943 return indicatePessimisticFixpoint();
11945 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11948 void trackStatistics()
const override {}
11952struct AAAssumptionInfoCallSite final : AAAssumptionInfoImpl {
11954 AAAssumptionInfoCallSite(
const IRPosition &IRP, Attributor &
A)
11955 : AAAssumptionInfoImpl(IRP,
A, getInitialAssumptions(IRP)) {}
11960 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11966 auto *AssumptionAA =
11967 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11969 return indicatePessimisticFixpoint();
11970 bool Changed = getIntersection(AssumptionAA->getAssumed());
11971 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11975 void trackStatistics()
const override {}
11980 DenseSet<StringRef> getInitialAssumptions(
const IRPosition &IRP) {
11987 return Assumptions;
12002struct AAUnderlyingObjectsImpl
12008 const std::string getAsStr(
Attributor *
A)
const override {
12009 if (!isValidState())
12010 return "<invalid>";
12013 OS <<
"underlying objects: inter " << InterAssumedUnderlyingObjects.size()
12014 <<
" objects, intra " << IntraAssumedUnderlyingObjects.size()
12016 if (!InterAssumedUnderlyingObjects.empty()) {
12017 OS <<
"inter objects:\n";
12018 for (
auto *Obj : InterAssumedUnderlyingObjects)
12019 OS << *Obj <<
'\n';
12021 if (!IntraAssumedUnderlyingObjects.empty()) {
12022 OS <<
"intra objects:\n";
12023 for (
auto *Obj : IntraAssumedUnderlyingObjects)
12024 OS << *
Obj <<
'\n';
12030 void trackStatistics()
const override {}
12034 auto &Ptr = getAssociatedValue();
12036 bool UsedAssumedInformation =
false;
12037 auto DoUpdate = [&](SmallSetVector<Value *, 8> &UnderlyingObjects,
12039 SmallPtrSet<Value *, 8> SeenObjects;
12043 Scope, UsedAssumedInformation))
12044 return UnderlyingObjects.
insert(&Ptr);
12048 for (
unsigned I = 0;
I < Values.
size(); ++
I) {
12049 auto &VAC = Values[
I];
12052 if (!SeenObjects.
insert(UO ? UO : Obj).second)
12054 if (UO && UO != Obj) {
12060 const auto *OtherAA =
A.getAAFor<AAUnderlyingObjects>(
12062 auto Pred = [&](
Value &
V) {
12070 if (!OtherAA || !OtherAA->forallUnderlyingObjects(Pred, Scope))
12072 "The forall call should not return false at this position");
12078 Changed |= handleIndirect(
A, *Obj, UnderlyingObjects, Scope,
12079 UsedAssumedInformation);
12085 for (
unsigned u = 0, e =
PHI->getNumIncomingValues(); u < e; u++) {
12087 handleIndirect(
A, *
PHI->getIncomingValue(u), UnderlyingObjects,
12088 Scope, UsedAssumedInformation);
12102 if (!UsedAssumedInformation)
12103 indicateOptimisticFixpoint();
12104 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12107 bool forallUnderlyingObjects(
12108 function_ref<
bool(
Value &)> Pred,
12110 if (!isValidState())
12111 return Pred(getAssociatedValue());
12114 ? IntraAssumedUnderlyingObjects
12115 : InterAssumedUnderlyingObjects;
12116 for (
Value *Obj : AssumedUnderlyingObjects)
12126 bool handleIndirect(Attributor &
A,
Value &V,
12127 SmallSetVector<Value *, 8> &UnderlyingObjects,
12130 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
12132 auto Pred = [&](
Value &
V) {
12136 if (!AA || !AA->forallUnderlyingObjects(Pred, Scope))
12138 "The forall call should not return false at this position");
12144 SmallSetVector<Value *, 8> IntraAssumedUnderlyingObjects;
12146 SmallSetVector<Value *, 8> InterAssumedUnderlyingObjects;
12149struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl {
12150 AAUnderlyingObjectsFloating(
const IRPosition &IRP, Attributor &
A)
12151 : AAUnderlyingObjectsImpl(IRP,
A) {}
12154struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl {
12155 AAUnderlyingObjectsArgument(
const IRPosition &IRP, Attributor &
A)
12156 : AAUnderlyingObjectsImpl(IRP,
A) {}
12159struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl {
12160 AAUnderlyingObjectsCallSite(
const IRPosition &IRP, Attributor &
A)
12161 : AAUnderlyingObjectsImpl(IRP,
A) {}
12164struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl {
12165 AAUnderlyingObjectsCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12166 : AAUnderlyingObjectsImpl(IRP,
A) {}
12169struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl {
12170 AAUnderlyingObjectsReturned(
const IRPosition &IRP, Attributor &
A)
12171 : AAUnderlyingObjectsImpl(IRP,
A) {}
12174struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl {
12175 AAUnderlyingObjectsCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12176 : AAUnderlyingObjectsImpl(IRP,
A) {}
12179struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {
12180 AAUnderlyingObjectsFunction(
const IRPosition &IRP, Attributor &
A)
12181 : AAUnderlyingObjectsImpl(IRP,
A) {}
12187struct AAGlobalValueInfoFloating :
public AAGlobalValueInfo {
12188 AAGlobalValueInfoFloating(
const IRPosition &IRP, Attributor &
A)
12189 : AAGlobalValueInfo(IRP,
A) {}
12194 bool checkUse(Attributor &
A,
const Use &U,
bool &Follow,
12195 SmallVectorImpl<const Value *> &Worklist) {
12202 LLVM_DEBUG(
dbgs() <<
"[AAGlobalValueInfo] Check use: " << *
U.get() <<
" in "
12203 << *UInst <<
"\n");
12206 int Idx = &
Cmp->getOperandUse(0) == &
U;
12209 return U == &getAnchorValue();
12214 auto CallSitePred = [&](AbstractCallSite ACS) {
12215 Worklist.
push_back(ACS.getInstruction());
12218 bool UsedAssumedInformation =
false;
12220 if (!
A.checkForAllCallSites(CallSitePred, *UInst->
getFunction(),
12222 UsedAssumedInformation))
12240 if (!Fn || !
A.isFunctionIPOAmendable(*Fn))
12249 unsigned NumUsesBefore =
Uses.size();
12251 SmallPtrSet<const Value *, 8> Visited;
12255 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
12263 return checkUse(
A, U, Follow, Worklist);
12265 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
12266 Uses.insert(&OldU);
12270 while (!Worklist.
empty()) {
12272 if (!Visited.
insert(V).second)
12274 if (!
A.checkForAllUses(UsePred, *
this, *V,
12276 DepClassTy::OPTIONAL,
12277 true, EquivalentUseCB)) {
12278 return indicatePessimisticFixpoint();
12282 return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED
12283 : ChangeStatus::CHANGED;
12286 bool isPotentialUse(
const Use &U)
const override {
12287 return !isValidState() ||
Uses.contains(&U);
12292 return ChangeStatus::UNCHANGED;
12296 const std::string getAsStr(Attributor *
A)
const override {
12297 return "[" + std::to_string(
Uses.size()) +
" uses]";
12300 void trackStatistics()
const override {
12306 SmallPtrSet<const Use *, 8>
Uses;
12312struct AAIndirectCallInfoCallSite :
public AAIndirectCallInfo {
12313 AAIndirectCallInfoCallSite(
const IRPosition &IRP, Attributor &
A)
12314 : AAIndirectCallInfo(IRP,
A) {}
12318 auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);
12319 if (!MD && !
A.isClosedWorldModule())
12323 for (
const auto &
Op : MD->operands())
12325 PotentialCallees.insert(Callee);
12326 }
else if (
A.isClosedWorldModule()) {
12328 A.getInfoCache().getIndirectlyCallableFunctions(
A);
12329 PotentialCallees.insert_range(IndirectlyCallableFunctions);
12332 if (PotentialCallees.empty())
12333 indicateOptimisticFixpoint();
12341 SmallSetVector<Function *, 4> AssumedCalleesNow;
12342 bool AllCalleesKnownNow = AllCalleesKnown;
12344 auto CheckPotentialCalleeUse = [&](
Function &PotentialCallee,
12345 bool &UsedAssumedInformation) {
12346 const auto *GIAA =
A.getAAFor<AAGlobalValueInfo>(
12348 if (!GIAA || GIAA->isPotentialUse(CalleeUse))
12350 UsedAssumedInformation = !GIAA->isAtFixpoint();
12354 auto AddPotentialCallees = [&]() {
12355 for (
auto *PotentialCallee : PotentialCallees) {
12356 bool UsedAssumedInformation =
false;
12357 if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))
12358 AssumedCalleesNow.
insert(PotentialCallee);
12364 bool UsedAssumedInformation =
false;
12367 AA::ValueScope::AnyScope,
12368 UsedAssumedInformation)) {
12369 if (PotentialCallees.empty())
12370 return indicatePessimisticFixpoint();
12371 AddPotentialCallees();
12376 auto CheckPotentialCallee = [&](
Function &Fn) {
12377 if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))
12380 auto &CachedResult = FilterResults[&Fn];
12381 if (CachedResult.has_value())
12382 return CachedResult.value();
12384 bool UsedAssumedInformation =
false;
12385 if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {
12386 if (!UsedAssumedInformation)
12387 CachedResult =
false;
12396 for (
int I = NumCBArgs;
I < NumFnArgs; ++
I) {
12397 bool IsKnown =
false;
12400 DepClassTy::OPTIONAL, IsKnown)) {
12402 CachedResult =
false;
12407 CachedResult =
true;
12413 for (
auto &VAC : Values) {
12421 if (CheckPotentialCallee(*VACFn))
12422 AssumedCalleesNow.
insert(VACFn);
12425 if (!PotentialCallees.empty()) {
12426 AddPotentialCallees();
12429 AllCalleesKnownNow =
false;
12432 if (AssumedCalleesNow == AssumedCallees &&
12433 AllCalleesKnown == AllCalleesKnownNow)
12434 return ChangeStatus::UNCHANGED;
12436 std::swap(AssumedCallees, AssumedCalleesNow);
12437 AllCalleesKnown = AllCalleesKnownNow;
12438 return ChangeStatus::CHANGED;
12444 if (!AllCalleesKnown && AssumedCallees.empty())
12445 return ChangeStatus::UNCHANGED;
12448 bool UsedAssumedInformation =
false;
12449 if (
A.isAssumedDead(*CB,
this,
nullptr,
12450 UsedAssumedInformation))
12451 return ChangeStatus::UNCHANGED;
12455 if (
FP->getType()->getPointerAddressSpace())
12456 FP =
new AddrSpaceCastInst(
FP, PointerType::get(
FP->getContext(), 0),
12466 if (AssumedCallees.empty()) {
12467 assert(AllCalleesKnown &&
12468 "Expected all callees to be known if there are none.");
12469 A.changeToUnreachableAfterManifest(CB);
12470 return ChangeStatus::CHANGED;
12474 if (AllCalleesKnown && AssumedCallees.size() == 1) {
12475 auto *NewCallee = AssumedCallees.front();
12478 NumIndirectCallsPromoted++;
12479 return ChangeStatus::CHANGED;
12486 A.deleteAfterManifest(*CB);
12487 return ChangeStatus::CHANGED;
12497 bool SpecializedForAnyCallees =
false;
12498 bool SpecializedForAllCallees = AllCalleesKnown;
12499 ICmpInst *LastCmp =
nullptr;
12502 for (Function *NewCallee : AssumedCallees) {
12503 if (!
A.shouldSpecializeCallSiteForCallee(*
this, *CB, *NewCallee,
12504 AssumedCallees.size())) {
12505 SkippedAssumedCallees.
push_back(NewCallee);
12506 SpecializedForAllCallees =
false;
12509 SpecializedForAnyCallees =
true;
12515 A.registerManifestAddedBasicBlock(*ThenTI->
getParent());
12516 A.registerManifestAddedBasicBlock(*IP->getParent());
12522 A.registerManifestAddedBasicBlock(*ElseBB);
12524 SplitTI->replaceUsesOfWith(CBBB, ElseBB);
12529 CastInst *RetBC =
nullptr;
12530 CallInst *NewCall =
nullptr;
12535 NumIndirectCallsPromoted++;
12543 auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {
12544 if (!AllCalleesKnown)
12545 return ChangeStatus::UNCHANGED;
12546 MDBuilder MDB(IndirectCB.getContext());
12547 MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);
12548 IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);
12549 return ChangeStatus::CHANGED;
12552 if (!SpecializedForAnyCallees)
12553 return AttachCalleeMetadata(*CB);
12556 if (SpecializedForAllCallees) {
12559 new UnreachableInst(IP->getContext(), IP);
12560 IP->eraseFromParent();
12563 CBClone->setName(CB->
getName());
12564 CBClone->insertBefore(*IP->getParent(), IP);
12565 NewCalls.
push_back({CBClone,
nullptr});
12566 AttachCalleeMetadata(*CBClone);
12573 CB->
getParent()->getFirstInsertionPt());
12574 for (
auto &It : NewCalls) {
12575 CallBase *NewCall = It.first;
12576 Instruction *CallRet = It.second ? It.second : It.first;
12588 A.deleteAfterManifest(*CB);
12589 Changed = ChangeStatus::CHANGED;
12595 const std::string getAsStr(Attributor *
A)
const override {
12596 return std::string(AllCalleesKnown ?
"eliminate" :
"specialize") +
12597 " indirect call site with " + std::to_string(AssumedCallees.size()) +
12601 void trackStatistics()
const override {
12602 if (AllCalleesKnown) {
12604 Eliminated, CallSites,
12605 "Number of indirect call sites eliminated via specialization")
12608 "Number of indirect call sites specialized")
12612 bool foreachCallee(function_ref<
bool(Function *)> CB)
const override {
12613 return isValidState() && AllCalleesKnown &&
all_of(AssumedCallees, CB);
12618 DenseMap<Function *, std::optional<bool>> FilterResults;
12622 SmallSetVector<Function *, 4> PotentialCallees;
12626 SmallSetVector<Function *, 4> AssumedCallees;
12630 bool AllCalleesKnown =
true;
12637struct AAInvariantLoadPointerImpl
12638 :
public StateWrapper<BitIntegerState<uint8_t, 15>,
12639 AAInvariantLoadPointer> {
12643 IS_NOALIAS = 1 << 0,
12646 IS_NOEFFECT = 1 << 1,
12648 IS_LOCALLY_INVARIANT = 1 << 2,
12650 IS_LOCALLY_CONSTRAINED = 1 << 3,
12652 IS_BEST_STATE = IS_NOALIAS | IS_NOEFFECT | IS_LOCALLY_INVARIANT |
12653 IS_LOCALLY_CONSTRAINED,
12655 static_assert(getBestState() == IS_BEST_STATE,
"Unexpected best state");
12658 StateWrapper<BitIntegerState<uint8_t, 15>, AAInvariantLoadPointer>;
12662 AAInvariantLoadPointerImpl(
const IRPosition &IRP, Attributor &
A)
12665 bool isKnownInvariant()
const final {
12666 return isKnownLocallyInvariant() && isKnown(IS_LOCALLY_CONSTRAINED);
12669 bool isKnownLocallyInvariant()
const final {
12670 if (isKnown(IS_LOCALLY_INVARIANT))
12672 return isKnown(IS_NOALIAS | IS_NOEFFECT);
12675 bool isAssumedInvariant()
const final {
12676 return isAssumedLocallyInvariant() && isAssumed(IS_LOCALLY_CONSTRAINED);
12679 bool isAssumedLocallyInvariant()
const final {
12680 if (isAssumed(IS_LOCALLY_INVARIANT))
12682 return isAssumed(IS_NOALIAS | IS_NOEFFECT);
12689 if (requiresNoAlias() && !isAssumed(IS_NOALIAS))
12690 return indicatePessimisticFixpoint();
12694 Changed |= updateLocalInvariance(
A);
12700 if (!isKnownInvariant())
12701 return ChangeStatus::UNCHANGED;
12704 const Value *Ptr = &getAssociatedValue();
12705 const auto TagInvariantLoads = [&](
const Use &
U,
bool &) {
12706 if (
U.get() != Ptr)
12714 if (!
A.isRunOn(
I->getFunction()))
12717 if (
I->hasMetadata(LLVMContext::MD_invariant_load))
12721 LI->setMetadata(LLVMContext::MD_invariant_load,
12723 Changed = ChangeStatus::CHANGED;
12728 (void)
A.checkForAllUses(TagInvariantLoads, *
this, *Ptr);
12733 const std::string getAsStr(Attributor *)
const override {
12734 if (isKnownInvariant())
12735 return "load-invariant pointer";
12736 return "non-invariant pointer";
12740 void trackStatistics()
const override {}
12744 bool requiresNoAlias()
const {
12745 switch (getPositionKind()) {
12751 case IRP_CALL_SITE:
12753 case IRP_CALL_SITE_RETURNED: {
12758 case IRP_ARGUMENT: {
12759 const Function *
F = getAssociatedFunction();
12760 assert(
F &&
"no associated function for argument");
12766 bool isExternal()
const {
12767 const Function *
F = getAssociatedFunction();
12771 getPositionKind() != IRP_CALL_SITE_RETURNED;
12775 if (isKnown(IS_NOALIAS) || !isAssumed(IS_NOALIAS))
12776 return ChangeStatus::UNCHANGED;
12779 if (
const auto *ANoAlias =
A.getOrCreateAAFor<AANoAlias>(
12780 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12781 if (ANoAlias->isKnownNoAlias()) {
12782 addKnownBits(IS_NOALIAS);
12783 return ChangeStatus::CHANGED;
12786 if (!ANoAlias->isAssumedNoAlias()) {
12787 removeAssumedBits(IS_NOALIAS);
12788 return ChangeStatus::CHANGED;
12791 return ChangeStatus::UNCHANGED;
12796 if (
const Argument *Arg = getAssociatedArgument()) {
12798 addKnownBits(IS_NOALIAS);
12799 return ChangeStatus::UNCHANGED;
12804 removeAssumedBits(IS_NOALIAS);
12805 return ChangeStatus::CHANGED;
12808 return ChangeStatus::UNCHANGED;
12812 if (isKnown(IS_NOEFFECT) || !isAssumed(IS_NOEFFECT))
12813 return ChangeStatus::UNCHANGED;
12815 if (!getAssociatedFunction())
12816 return indicatePessimisticFixpoint();
12819 return indicatePessimisticFixpoint();
12821 const auto HasNoEffectLoads = [&](
const Use &
U,
bool &) {
12823 return !LI || !LI->mayHaveSideEffects();
12825 if (!
A.checkForAllUses(HasNoEffectLoads, *
this, getAssociatedValue()))
12826 return indicatePessimisticFixpoint();
12828 if (
const auto *AMemoryBehavior =
A.getOrCreateAAFor<AAMemoryBehavior>(
12829 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12832 if (!AMemoryBehavior->isAssumedReadOnly())
12833 return indicatePessimisticFixpoint();
12835 if (AMemoryBehavior->isKnownReadOnly()) {
12836 addKnownBits(IS_NOEFFECT);
12837 return ChangeStatus::UNCHANGED;
12840 return ChangeStatus::UNCHANGED;
12843 if (
const Argument *Arg = getAssociatedArgument()) {
12845 addKnownBits(IS_NOEFFECT);
12846 return ChangeStatus::UNCHANGED;
12851 return indicatePessimisticFixpoint();
12854 return ChangeStatus::UNCHANGED;
12858 if (isKnown(IS_LOCALLY_INVARIANT) || !isAssumed(IS_LOCALLY_INVARIANT))
12859 return ChangeStatus::UNCHANGED;
12862 const auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
12863 getIRPosition(),
this, DepClassTy::REQUIRED);
12865 return ChangeStatus::UNCHANGED;
12867 bool UsedAssumedInformation =
false;
12868 const auto IsLocallyInvariantLoadIfPointer = [&](
const Value &
V) {
12869 if (!
V.getType()->isPointerTy())
12871 const auto *IsInvariantLoadPointer =
12873 DepClassTy::REQUIRED);
12875 if (!IsInvariantLoadPointer)
12878 if (IsInvariantLoadPointer->isKnownLocallyInvariant())
12880 if (!IsInvariantLoadPointer->isAssumedLocallyInvariant())
12883 UsedAssumedInformation =
true;
12886 if (!AUO->forallUnderlyingObjects(IsLocallyInvariantLoadIfPointer))
12887 return indicatePessimisticFixpoint();
12893 if (!IsLocallyInvariantLoadIfPointer(*Arg))
12894 return indicatePessimisticFixpoint();
12899 if (!UsedAssumedInformation) {
12901 addKnownBits(IS_LOCALLY_INVARIANT);
12902 return ChangeStatus::CHANGED;
12905 return ChangeStatus::UNCHANGED;
12909struct AAInvariantLoadPointerFloating final : AAInvariantLoadPointerImpl {
12910 AAInvariantLoadPointerFloating(
const IRPosition &IRP, Attributor &
A)
12911 : AAInvariantLoadPointerImpl(IRP,
A) {}
12914struct AAInvariantLoadPointerReturned final : AAInvariantLoadPointerImpl {
12915 AAInvariantLoadPointerReturned(
const IRPosition &IRP, Attributor &
A)
12916 : AAInvariantLoadPointerImpl(IRP,
A) {}
12919 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12923struct AAInvariantLoadPointerCallSiteReturned final
12924 : AAInvariantLoadPointerImpl {
12925 AAInvariantLoadPointerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12926 : AAInvariantLoadPointerImpl(IRP,
A) {}
12929 const Function *
F = getAssociatedFunction();
12930 assert(
F &&
"no associated function for return from call");
12932 if (!
F->isDeclaration() && !
F->isIntrinsic())
12933 return AAInvariantLoadPointerImpl::initialize(
A);
12938 return AAInvariantLoadPointerImpl::initialize(
A);
12940 if (
F->onlyReadsMemory() &&
F->hasNoSync())
12941 return AAInvariantLoadPointerImpl::initialize(
A);
12945 indicatePessimisticFixpoint();
12949struct AAInvariantLoadPointerArgument final : AAInvariantLoadPointerImpl {
12950 AAInvariantLoadPointerArgument(
const IRPosition &IRP, Attributor &
A)
12951 : AAInvariantLoadPointerImpl(IRP,
A) {}
12954 const Function *
F = getAssociatedFunction();
12955 assert(
F &&
"no associated function for argument");
12958 addKnownBits(IS_LOCALLY_CONSTRAINED);
12962 if (!
F->hasLocalLinkage())
12963 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12967struct AAInvariantLoadPointerCallSiteArgument final
12968 : AAInvariantLoadPointerImpl {
12969 AAInvariantLoadPointerCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12970 : AAInvariantLoadPointerImpl(IRP,
A) {}
12977template <
typename InstType>
12978static bool makeChange(Attributor &
A, InstType *MemInst,
const Use &U,
12979 Value *OriginalValue, PointerType *NewPtrTy,
12980 bool UseOriginalValue) {
12981 if (
U.getOperandNo() != InstType::getPointerOperandIndex())
12984 if (MemInst->isVolatile()) {
12985 auto *
TTI =
A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(
12986 *MemInst->getFunction());
12987 unsigned NewAS = NewPtrTy->getPointerAddressSpace();
12992 if (UseOriginalValue) {
12993 A.changeUseAfterManifest(
const_cast<Use &
>(U), *OriginalValue);
12997 Instruction *CastInst =
new AddrSpaceCastInst(OriginalValue, NewPtrTy);
12999 A.changeUseAfterManifest(
const_cast<Use &
>(U), *CastInst);
13003struct AAAddressSpaceImpl :
public AAAddressSpace {
13004 AAAddressSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13005 : AAAddressSpace(IRP,
A) {}
13008 assert(isValidState() &&
"the AA is invalid");
13009 return AssumedAddressSpace;
13014 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13015 "Associated value is not a pointer");
13017 if (!
A.getInfoCache().getFlatAddressSpace().has_value()) {
13018 indicatePessimisticFixpoint();
13022 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13023 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13024 if (AS != FlatAS) {
13025 [[maybe_unused]]
bool R = takeAddressSpace(AS);
13026 assert(R &&
"The take should happen");
13027 indicateOptimisticFixpoint();
13032 uint32_t OldAddressSpace = AssumedAddressSpace;
13033 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13035 auto CheckAddressSpace = [&](
Value &
Obj) {
13041 unsigned ObjAS =
Obj.getType()->getPointerAddressSpace();
13042 if (ObjAS != FlatAS)
13043 return takeAddressSpace(ObjAS);
13057 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(*F);
13059 if (AssumedAS != ~0U)
13060 return takeAddressSpace(AssumedAS);
13064 return takeAddressSpace(FlatAS);
13067 auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(getIRPosition(),
this,
13068 DepClassTy::REQUIRED);
13069 if (!AUO->forallUnderlyingObjects(CheckAddressSpace))
13070 return indicatePessimisticFixpoint();
13072 return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED
13073 : ChangeStatus::CHANGED;
13080 if (NewAS == InvalidAddressSpace ||
13082 return ChangeStatus::UNCHANGED;
13084 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13086 Value *AssociatedValue = &getAssociatedValue();
13087 Value *OriginalValue = peelAddrspacecast(AssociatedValue, FlatAS);
13090 PointerType::get(getAssociatedType()->
getContext(), NewAS);
13091 bool UseOriginalValue =
13096 auto Pred = [&](
const Use &
U,
bool &) {
13097 if (
U.get() != AssociatedValue)
13108 makeChange(
A, LI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13111 makeChange(
A, SI, U, OriginalValue, NewPtrTy, UseOriginalValue);
13114 makeChange(
A, RMW, U, OriginalValue, NewPtrTy, UseOriginalValue);
13117 makeChange(
A, CmpX, U, OriginalValue, NewPtrTy, UseOriginalValue);
13124 (void)
A.checkForAllUses(Pred, *
this, getAssociatedValue(),
13127 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13131 const std::string getAsStr(Attributor *
A)
const override {
13132 if (!isValidState())
13133 return "addrspace(<invalid>)";
13134 return "addrspace(" +
13135 (AssumedAddressSpace == InvalidAddressSpace
13137 : std::to_string(AssumedAddressSpace)) +
13142 uint32_t AssumedAddressSpace = InvalidAddressSpace;
13144 bool takeAddressSpace(uint32_t AS) {
13145 if (AssumedAddressSpace == InvalidAddressSpace) {
13146 AssumedAddressSpace = AS;
13149 return AssumedAddressSpace == AS;
13152 static Value *peelAddrspacecast(
Value *V,
unsigned FlatAS) {
13154 assert(
I->getSrcAddressSpace() != FlatAS &&
13155 "there should not be flat AS -> non-flat AS");
13156 return I->getPointerOperand();
13159 if (
C->getOpcode() == Instruction::AddrSpaceCast) {
13160 assert(
C->getOperand(0)->getType()->getPointerAddressSpace() !=
13162 "there should not be flat AS -> non-flat AS X");
13163 return C->getOperand(0);
13169struct AAAddressSpaceFloating final : AAAddressSpaceImpl {
13170 AAAddressSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13171 : AAAddressSpaceImpl(IRP,
A) {}
13173 void trackStatistics()
const override {
13178struct AAAddressSpaceReturned final : AAAddressSpaceImpl {
13179 AAAddressSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13180 : AAAddressSpaceImpl(IRP,
A) {}
13186 (void)indicatePessimisticFixpoint();
13189 void trackStatistics()
const override {
13194struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl {
13195 AAAddressSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13196 : AAAddressSpaceImpl(IRP,
A) {}
13198 void trackStatistics()
const override {
13203struct AAAddressSpaceArgument final : AAAddressSpaceImpl {
13204 AAAddressSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13205 : AAAddressSpaceImpl(IRP,
A) {}
13210struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl {
13211 AAAddressSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13212 : AAAddressSpaceImpl(IRP,
A) {}
13218 (void)indicatePessimisticFixpoint();
13221 void trackStatistics()
const override {
13236struct AANoAliasAddrSpaceImpl :
public AANoAliasAddrSpace {
13237 AANoAliasAddrSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13238 : AANoAliasAddrSpace(IRP,
A) {}
13241 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13242 "Associated value is not a pointer");
13246 std::optional<unsigned> FlatAS =
A.getInfoCache().getFlatAddressSpace();
13247 if (!FlatAS.has_value()) {
13248 indicatePessimisticFixpoint();
13254 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13255 if (AS != *FlatAS) {
13257 indicateOptimisticFixpoint();
13262 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13263 uint32_t OldAssumed = getAssumed();
13265 auto CheckAddressSpace = [&](
Value &
Obj) {
13269 unsigned AS =
Obj.getType()->getPointerAddressSpace();
13273 removeAS(
Obj.getType()->getPointerAddressSpace());
13277 const AAUnderlyingObjects *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
13278 getIRPosition(),
this, DepClassTy::REQUIRED);
13280 return indicatePessimisticFixpoint();
13282 return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
13283 : ChangeStatus::CHANGED;
13288 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13290 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13291 if (AS != FlatAS ||
Map.empty())
13292 return ChangeStatus::UNCHANGED;
13294 LLVMContext &Ctx = getAssociatedValue().getContext();
13295 MDNode *NoAliasASNode =
nullptr;
13296 MDBuilder MDB(Ctx);
13298 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13301 unsigned Upper =
I.stop();
13302 unsigned Lower =
I.start();
13303 if (!NoAliasASNode) {
13304 NoAliasASNode = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13307 MDNode *ASRange = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13311 Value *AssociatedValue = &getAssociatedValue();
13314 auto AddNoAliasAttr = [&](
const Use &
U,
bool &) {
13315 if (
U.get() != AssociatedValue)
13318 if (!Inst || Inst->
hasMetadata(LLVMContext::MD_noalias_addrspace))
13325 Inst->
setMetadata(LLVMContext::MD_noalias_addrspace, NoAliasASNode);
13329 (void)
A.checkForAllUses(AddNoAliasAttr, *
this, *AssociatedValue,
13331 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13335 const std::string getAsStr(Attributor *
A)
const override {
13336 if (!isValidState())
13337 return "<invalid>";
13339 raw_string_ostream OS(Str);
13340 OS <<
"CanNotBeAddrSpace(";
13341 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13342 unsigned Upper =
I.stop();
13343 unsigned Lower =
I.start();
13344 OS <<
' ' <<
'[' <<
Upper <<
',' <<
Lower + 1 <<
')';
13351 void removeAS(
unsigned AS) {
13352 RangeMap::iterator
I =
Map.find(AS);
13354 if (
I !=
Map.end()) {
13355 unsigned Upper =
I.stop();
13356 unsigned Lower =
I.start();
13360 if (AS != ~((
unsigned)0) && AS + 1 <=
Upper)
13362 if (AS != 0 &&
Lower <= AS - 1)
13367 void resetASRanges(Attributor &
A) {
13369 Map.insert(0,
A.getInfoCache().getMaxAddrSpace(),
true);
13373struct AANoAliasAddrSpaceFloating final : AANoAliasAddrSpaceImpl {
13374 AANoAliasAddrSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13375 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13377 void trackStatistics()
const override {
13382struct AANoAliasAddrSpaceReturned final : AANoAliasAddrSpaceImpl {
13383 AANoAliasAddrSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13384 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13386 void trackStatistics()
const override {
13391struct AANoAliasAddrSpaceCallSiteReturned final : AANoAliasAddrSpaceImpl {
13392 AANoAliasAddrSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13393 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13395 void trackStatistics()
const override {
13400struct AANoAliasAddrSpaceArgument final : AANoAliasAddrSpaceImpl {
13401 AANoAliasAddrSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13402 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13404 void trackStatistics()
const override {
13409struct AANoAliasAddrSpaceCallSiteArgument final : AANoAliasAddrSpaceImpl {
13410 AANoAliasAddrSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13411 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13413 void trackStatistics()
const override {
13420struct AAAllocationInfoImpl :
public AAAllocationInfo {
13421 AAAllocationInfoImpl(
const IRPosition &IRP, Attributor &
A)
13422 : AAAllocationInfo(IRP,
A) {}
13424 std::optional<TypeSize> getAllocatedSize()
const override {
13425 assert(isValidState() &&
"the AA is invalid");
13426 return AssumedAllocatedSize;
13429 std::optional<TypeSize> findInitialAllocationSize(Instruction *
I,
13430 const DataLayout &
DL) {
13433 switch (
I->getOpcode()) {
13434 case Instruction::Alloca: {
13439 return std::nullopt;
13445 const IRPosition &IRP = getIRPosition();
13450 return indicatePessimisticFixpoint();
13452 bool IsKnownNoCapture;
13454 A,
this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture))
13455 return indicatePessimisticFixpoint();
13457 const AAPointerInfo *PI =
13458 A.getOrCreateAAFor<AAPointerInfo>(IRP, *
this, DepClassTy::REQUIRED);
13461 return indicatePessimisticFixpoint();
13464 return indicatePessimisticFixpoint();
13466 const DataLayout &
DL =
A.getDataLayout();
13467 const auto AllocationSize = findInitialAllocationSize(
I,
DL);
13470 if (!AllocationSize)
13471 return indicatePessimisticFixpoint();
13475 if (*AllocationSize == 0)
13476 return indicatePessimisticFixpoint();
13482 return indicatePessimisticFixpoint();
13484 if (BinSize == 0) {
13485 auto NewAllocationSize = std::make_optional<TypeSize>(0,
false);
13486 if (!changeAllocationSize(NewAllocationSize))
13487 return ChangeStatus::UNCHANGED;
13488 return ChangeStatus::CHANGED;
13492 const auto &It = PI->
begin();
13495 if (It->first.Offset != 0)
13496 return indicatePessimisticFixpoint();
13498 uint64_t SizeOfBin = It->first.Offset + It->first.Size;
13500 if (SizeOfBin >= *AllocationSize)
13501 return indicatePessimisticFixpoint();
13503 auto NewAllocationSize = std::make_optional<TypeSize>(SizeOfBin * 8,
false);
13505 if (!changeAllocationSize(NewAllocationSize))
13506 return ChangeStatus::UNCHANGED;
13508 return ChangeStatus::CHANGED;
13514 assert(isValidState() &&
13515 "Manifest should only be called if the state is valid.");
13519 auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
13521 unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
13523 switch (
I->getOpcode()) {
13525 case Instruction::Alloca: {
13529 Type *CharType = Type::getInt8Ty(
I->getContext());
13531 auto *NumBytesToValue =
13532 ConstantInt::get(
I->getContext(), APInt(32, NumBytesToAllocate));
13535 insertPt = std::next(insertPt);
13536 AllocaInst *NewAllocaInst =
13541 return ChangeStatus::CHANGED;
13549 return ChangeStatus::UNCHANGED;
13553 const std::string getAsStr(Attributor *
A)
const override {
13554 if (!isValidState())
13555 return "allocationinfo(<invalid>)";
13556 return "allocationinfo(" +
13557 (AssumedAllocatedSize == HasNoAllocationSize
13559 : std::to_string(AssumedAllocatedSize->getFixedValue())) +
13564 std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
13568 bool changeAllocationSize(std::optional<TypeSize>
Size) {
13569 if (AssumedAllocatedSize == HasNoAllocationSize ||
13570 AssumedAllocatedSize !=
Size) {
13571 AssumedAllocatedSize =
Size;
13578struct AAAllocationInfoFloating : AAAllocationInfoImpl {
13579 AAAllocationInfoFloating(
const IRPosition &IRP, Attributor &
A)
13580 : AAAllocationInfoImpl(IRP,
A) {}
13582 void trackStatistics()
const override {
13587struct AAAllocationInfoReturned : AAAllocationInfoImpl {
13588 AAAllocationInfoReturned(
const IRPosition &IRP, Attributor &
A)
13589 : AAAllocationInfoImpl(IRP,
A) {}
13595 (void)indicatePessimisticFixpoint();
13598 void trackStatistics()
const override {
13603struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl {
13604 AAAllocationInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13605 : AAAllocationInfoImpl(IRP,
A) {}
13607 void trackStatistics()
const override {
13612struct AAAllocationInfoArgument : AAAllocationInfoImpl {
13613 AAAllocationInfoArgument(
const IRPosition &IRP, Attributor &
A)
13614 : AAAllocationInfoImpl(IRP,
A) {}
13616 void trackStatistics()
const override {
13621struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl {
13622 AAAllocationInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13623 : AAAllocationInfoImpl(IRP,
A) {}
13628 (void)indicatePessimisticFixpoint();
13631 void trackStatistics()
const override {
13680#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \
13681 case IRPosition::PK: \
13682 llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");
13684#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \
13685 case IRPosition::PK: \
13686 AA = new (A.Allocator) CLASS##SUFFIX(IRP, A); \
13690#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13691 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13692 CLASS *AA = nullptr; \
13693 switch (IRP.getPositionKind()) { \
13694 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13695 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13696 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13697 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13698 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13699 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13700 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13701 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13706#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13707 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13708 CLASS *AA = nullptr; \
13709 switch (IRP.getPositionKind()) { \
13710 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13711 SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \
13712 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13713 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13714 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13715 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13716 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13717 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13722#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS) \
13723 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13724 CLASS *AA = nullptr; \
13725 switch (IRP.getPositionKind()) { \
13726 SWITCH_PK_CREATE(CLASS, IRP, POS, SUFFIX) \
13728 llvm_unreachable("Cannot create " #CLASS " for position otherthan " #POS \
13734#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13735 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13736 CLASS *AA = nullptr; \
13737 switch (IRP.getPositionKind()) { \
13738 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13739 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13740 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13741 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13742 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13743 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13744 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13745 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13750#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13751 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13752 CLASS *AA = nullptr; \
13753 switch (IRP.getPositionKind()) { \
13754 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13755 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13756 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13757 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13758 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13759 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13760 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13761 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13766#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13767 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13768 CLASS *AA = nullptr; \
13769 switch (IRP.getPositionKind()) { \
13770 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13771 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13772 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13773 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13774 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13775 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13776 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13777 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13829#undef CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION
13830#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
13831#undef CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION
13832#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
13833#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
13834#undef CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION
13835#undef SWITCH_PK_CREATE
13836#undef SWITCH_PK_INV
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file implements a class to represent arbitrary precision integral constant values and operations...
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis false
This file contains the simple types necessary to represent the attributes associated with functions a...
#define STATS_DECLTRACK(NAME, TYPE, MSG)
static std::optional< Constant * > askForAssumedConstant(Attributor &A, const AbstractAttribute &QueryingAA, const IRPosition &IRP, Type &Ty)
static cl::opt< unsigned, true > MaxPotentialValues("attributor-max-potential-values", cl::Hidden, cl::desc("Maximum number of potential values to be " "tracked for each position."), cl::location(llvm::PotentialConstantIntValuesState::MaxPotentialValues), cl::init(7))
static void clampReturnedValueStates(Attributor &A, const AAType &QueryingAA, StateType &S, const IRPosition::CallBaseContext *CBContext=nullptr)
Clamp the information known for all returned values of a function (identified by QueryingAA) into S.
#define STATS_DECLTRACK_FN_ATTR(NAME)
#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static cl::opt< int > MaxPotentialValuesIterations("attributor-max-potential-values-iterations", cl::Hidden, cl::desc("Maximum number of iterations we keep dismantling potential values."), cl::init(64))
#define STATS_DECLTRACK_CS_ATTR(NAME)
#define PIPE_OPERATOR(CLASS)
static bool mayBeInCycle(const CycleInfo *CI, const Instruction *I, bool HeaderOnly, Cycle **CPtr=nullptr)
#define STATS_DECLTRACK_ARG_ATTR(NAME)
static const Value * stripAndAccumulateOffsets(Attributor &A, const AbstractAttribute &QueryingAA, const Value *Val, const DataLayout &DL, APInt &Offset, bool GetMinOffset, bool AllowNonInbounds, bool UseAssumed=false)
#define STATS_DECLTRACK_CSRET_ATTR(NAME)
static cl::opt< bool > ManifestInternal("attributor-manifest-internal", cl::Hidden, cl::desc("Manifest Attributor internal string attributes."), cl::init(false))
static Value * constructPointer(Value *Ptr, int64_t Offset, IRBuilder< NoFolder > &IRB)
Helper function to create a pointer based on Ptr, and advanced by Offset bytes.
#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
#define BUILD_STAT_NAME(NAME, TYPE)
static bool isDenselyPacked(Type *Ty, const DataLayout &DL)
Checks if a type could have padding bytes.
#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static const Value * getMinimalBaseOfPointer(Attributor &A, const AbstractAttribute &QueryingAA, const Value *Ptr, int64_t &BytesOffset, const DataLayout &DL, bool AllowNonInbounds=false)
#define STATS_DECLTRACK_FNRET_ATTR(NAME)
#define STATS_DECLTRACK_CSARG_ATTR(NAME)
#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS)
#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
static cl::opt< int > MaxHeapToStackSize("max-heap-to-stack-size", cl::init(128), cl::Hidden)
#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)
#define STATS_DECLTRACK_FLOATING_ATTR(NAME)
#define STATS_DECL(NAME, TYPE, MSG)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool isReachableImpl(SmallVectorImpl< BasicBlock * > &Worklist, const StopSetT &StopSet, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet, const DominatorTree *DT, const LoopInfo *LI)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file declares an analysis pass that computes CycleInfo for LLVM IR, specialized from GenericCycl...
DXIL Forward Handle Accesses
This file defines DenseMapInfo traits for DenseMap.
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
static unsigned getAddressSpace(const Value *V, unsigned MaxLookup)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
static StringRef getName(Value *V)
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
dot regions Print regions of function to dot true view regions View regions of function(with no function bodies)"
Remove Loads Into Fake Uses
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
std::pair< BasicBlock *, BasicBlock * > Edge
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
This file defines generic set operations that may be used on set's of different types,...
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static SymbolRef::Type getType(const Symbol *Sym)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type.
static unsigned getSize(unsigned Kind)
LLVM_ABI AACallGraphNode * operator*() const
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A trivial helper function to check to see if the specified pointers are no-alias.
Class for arbitrary precision integers.
int64_t getSExtValue() const
Get sign extended value.
CallBase * getInstruction() const
Return the underlying instruction.
bool isCallbackCall() const
Return true if this ACS represents a callback call.
bool isDirectCall() const
Return true if this ACS represents a direct call.
static LLVM_ABI void getCallbackUses(const CallBase &CB, SmallVectorImpl< const Use * > &CallbackUses)
Add operand uses of CB that represent callback uses into CallbackUses.
int getCallArgOperandNo(Argument &Arg) const
Return the operand index of the underlying instruction associated with Arg.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
unsigned getAddressSpace() const
Return the address space for the allocation.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
This class represents an incoming formal argument to a Function.
LLVM_ABI bool hasNoAliasAttr() const
Return true if this argument has the noalias attribute.
LLVM_ABI bool onlyReadsMemory() const
Return true if this argument has the readonly or readnone attribute.
LLVM_ABI bool hasPointeeInMemoryValueAttr() const
Return true if this argument has the byval, sret, inalloca, preallocated, or byref attribute.
LLVM_ABI bool hasReturnedAttr() const
Return true if this argument has the returned attribute.
LLVM_ABI bool hasByValAttr() const
Return true if this argument has the byval attribute.
const Function * getParent() const
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
Functions, function parameters, and return types can have attributes to indicate how they should be t...
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
LLVM_ABI FPClassTest getNoFPClass() const
Return the FPClassTest for nofpclass.
LLVM_ABI Attribute::AttrKind getKindAsEnum() const
Return the attribute's kind as an enum (Attribute::AttrKind).
LLVM_ABI MemoryEffects getMemoryEffects() const
Returns memory effects.
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
static LLVM_ABI Attribute getWithCaptureInfo(LLVMContext &Context, CaptureInfo CI)
static bool isEnumAttrKind(AttrKind Kind)
LLVM_ABI CaptureInfo getCaptureInfo() const
Returns information from captures attribute.
LLVM Basic Block Representation.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Instruction & front() const
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
BinaryOps getOpcode() const
Conditional or Unconditional Branch instruction.
unsigned getNumSuccessors() const
static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)
BasicBlock * getSuccessor(unsigned i) const
Value * getCondition() const
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
Value * getCalledOperand() const
const Use & getCalledOperandUse() const
const Use & getArgOperandUse(unsigned i) const
Wrappers for getting the Use of a call argument.
LLVM_ABI std::optional< ConstantRange > getRange() const
If this return value has a range attribute, return the value range of the argument.
Value * getArgOperand(unsigned i) const
bool isBundleOperand(unsigned Idx) const
Return true if the operand at index Idx is a bundle operand.
bool isConvergent() const
Determine if the invoke is convergent.
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static CaptureInfo none()
Create CaptureInfo that does not capture any components of the pointer.
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
LLVM_ABI bool isIntegerCast() const
There are several places where we need to know if a cast instruction only deals with integer source a...
Type * getDestTy() const
Return the destination type, as a convenience.
bool isEquality() const
Determine if this is an equals/not equals predicate.
bool isFalseWhenEqual() const
This is just a convenience.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
bool isTrueWhenEqual() const
This is just a convenience.
Predicate getPredicate() const
Return the predicate for this instruction.
static LLVM_ABI Constant * getExtractElement(Constant *Vec, Constant *Idx, Type *OnlyIfReducedTy=nullptr)
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
This class represents a range of values.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
LLVM_ABI bool isEmptySet() const
Return true if this set contains no members.
bool isSingleElement() const
Return true if this set contains exactly one member.
static LLVM_ABI ConstantRange makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other)
Produce the smallest range such that all values that may satisfy the given predicate with any value c...
const APInt & getUpper() const
Return the upper value for this range.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
const BasicBlock & getEntryBlock() const
iterator_range< arg_iterator > args()
const Function & getFunction() const
Argument * getArg(unsigned i) const
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
CycleT * getCycle(const BlockT *Block) const
Find the innermost cycle containing a given block.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasLocalLinkage() const
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
Value * CreatePtrAdd(Value *Ptr, Value *Offset, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI bool isLifetimeStartOrEnd() const LLVM_READONLY
Return true if the instruction is a llvm.lifetime.start or llvm.lifetime.end marker.
bool mayReadOrWriteMemory() const
Return true if this instruction may read or write memory.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
bool hasMetadata() const
Return true if this instruction has any metadata attached to it.
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI BasicBlock * getSuccessor(unsigned Idx) const LLVM_READONLY
Return the specified successor. This instruction must be a terminator.
LLVM_ABI bool mayHaveSideEffects() const LLVM_READONLY
Return true if the instruction may have side effects.
bool isTerminator() const
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This is an important class for using LLVM in a threaded context.
ConstantRange getConstantRange(Value *V, Instruction *CxtI, bool UndefAllowed)
Return the ConstantRange constraint that is known to hold for the specified value at the specified in...
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static LLVM_ABI MDNode * getMostGenericRange(MDNode *A, MDNode *B)
static MemoryEffectsBase readOnly()
bool doesNotAccessMemory() const
Whether this function accesses no memory.
static MemoryEffectsBase argMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase inaccessibleMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
bool onlyAccessesInaccessibleMem() const
Whether this function only (at most) accesses inaccessible memory.
ModRefInfo getModRef(Location Loc) const
Get ModRefInfo for the given Location.
bool onlyAccessesArgPointees() const
Whether this function only (at most) accesses argument memory.
bool onlyReadsMemory() const
Whether this function only (at most) reads memory.
static MemoryEffectsBase writeOnly()
static MemoryEffectsBase inaccessibleOrArgMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
static MemoryEffectsBase none()
bool onlyAccessesInaccessibleOrArgMem() const
Whether this function only (at most) accesses argument and inaccessible memory.
static MemoryEffectsBase unknown()
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static SizeOffsetValue unknown()
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Value * getReturnValue() const
Convenience accessor. Returns null if there is no return value.
LLVM_ABI const SCEV * getSCEVAtScope(const SCEV *S, const Loop *L)
Return a SCEV expression for the specified value at the specified scope in the program.
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI unsigned getSmallConstantMaxTripCount(const Loop *L, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Returns the upper bound of the loop trip count as a normal unsigned value.
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
TypeSize getElementOffset(unsigned Idx) const
TypeSize getElementOffsetInBits(unsigned Idx) const
Class to represent struct types.
unsigned getNumElements() const
Random access to the elements.
Type * getElementType(unsigned N) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isPointerTy() const
True if this is an instance of PointerType.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
bool isPtrOrPtrVectorTy() const
Return true if this is a pointer type or a vector of pointer types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
bool isVoidTy() const
Return true if this is 'void'.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
User * getUser() const
Returns the User that contains this Use.
const Use & getOperandUse(unsigned i) const
LLVM_ABI bool isDroppable() const
A droppable user is a user for which uses can be dropped without affecting correctness and should be ...
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
unsigned getNumOperands() const
ValueT lookup(const KeyT &Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
static constexpr uint64_t MaximumAlignment
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVM_ABI const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr, bool LookThroughIntToPtr=false) const
Accumulate the constant offset this value has compared to a base pointer.
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
static constexpr unsigned MaxAlignmentExponent
The maximum alignment for instructions.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
constexpr ScalarTy getFixedValue() const
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
SetVector< Function * >::iterator I
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
LLVM_ABI bool isAssumedReadNone(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readnone.
LLVM_ABI bool isAssumedReadOnly(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readonly.
raw_ostream & operator<<(raw_ostream &OS, const RangeTy &R)
LLVM_ABI std::optional< Value * > combineOptionalValuesInAAValueLatice(const std::optional< Value * > &A, const std::optional< Value * > &B, Type *Ty)
Return the combination of A and B such that the result is a possible value of both.
LLVM_ABI bool isValidAtPosition(const ValueAndContext &VAC, InformationCache &InfoCache)
Return true if the value of VAC is a valid at the position of VAC, that is a constant,...
LLVM_ABI bool isAssumedThreadLocalObject(Attributor &A, Value &Obj, const AbstractAttribute &QueryingAA)
Return true if Obj is assumed to be a thread local object.
LLVM_ABI bool isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA, const Value &V, bool ForAnalysisOnly=true)
Return true if V is dynamically unique, that is, there are no two "instances" of V at runtime with di...
LLVM_ABI bool getPotentialCopiesOfStoredValue(Attributor &A, StoreInst &SI, SmallSetVector< Value *, 4 > &PotentialCopies, const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, bool OnlyExact=false)
Collect all potential values of the one stored by SI into PotentialCopies.
SmallPtrSet< Instruction *, 4 > InstExclusionSetTy
LLVM_ABI bool isGPU(const Module &M)
Return true iff M target a GPU (and we can use GPU AS reasoning).
ValueScope
Flags to distinguish intra-procedural queries from potentially inter-procedural queries.
LLVM_ABI bool isValidInScope(const Value &V, const Function *Scope)
Return true if V is a valid value in Scope, that is a constant or an instruction/argument of Scope.
LLVM_ABI bool isPotentiallyReachable(Attributor &A, const Instruction &FromI, const Instruction &ToI, const AbstractAttribute &QueryingAA, const AA::InstExclusionSetTy *ExclusionSet=nullptr, std::function< bool(const Function &F)> GoBackwardsCB=nullptr)
Return true if ToI is potentially reachable from FromI without running into any instruction in Exclus...
LLVM_ABI bool isNoSyncInst(Attributor &A, const Instruction &I, const AbstractAttribute &QueryingAA)
Return true if I is a nosync instruction.
bool hasAssumedIRAttr(Attributor &A, const AbstractAttribute *QueryingAA, const IRPosition &IRP, DepClassTy DepClass, bool &IsKnown, bool IgnoreSubsumingPositions=false, const AAType **AAPtr=nullptr)
Helper to avoid creating an AA for IR Attributes that might already be set.
LLVM_ABI bool getPotentiallyLoadedValues(Attributor &A, LoadInst &LI, SmallSetVector< Value *, 4 > &PotentialValues, SmallSetVector< Instruction *, 4 > &PotentialValueOrigins, const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, bool OnlyExact=false)
Collect all potential values LI could read into PotentialValues.
LLVM_ABI Value * getWithType(Value &V, Type &Ty)
Try to convert V to type Ty without introducing new instructions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
@ Unsupported
This operation is completely unsupported on the target.
@ Undef
Value of the register doesn't matter.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
@ CE
Windows NT (Windows on ARM)
@ Valid
The data is already valid.
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
unsigned combineHashValue(unsigned a, unsigned b)
Simplistic combination of 32-bit hash values into 32-bit hash values.
ElementType
The element type of an SRV or UAV resource.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
@ User
could "use" a pointer
NodeAddr< UseNode * > Use
Context & getContext() const
friend class Instruction
Iterator for Instructions in a `BasicBlock.
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
bool operator<(int64_t V1, const APSInt &V2)
FunctionAddr VTableAddr Value
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt gcd(const DynamicAPInt &A, const DynamicAPInt &B)
LLVM_ABI KnownFPClass computeKnownFPClass(const Value *V, const APInt &DemandedElts, FPClassTest InterestedClasses, const SimplifyQuery &SQ, unsigned Depth=0)
Determine which floating-point classes are valid for V, and return them in KnownFPClass bit sets.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI bool isLegalToPromote(const CallBase &CB, Function *Callee, const char **FailureReason=nullptr)
Return true if the given indirect call site can be made to call Callee.
LLVM_ABI Constant * getInitialValueOfAllocation(const Value *V, const TargetLibraryInfo *TLI, Type *Ty)
If this is a call to an allocation function that initializes memory to a fixed value,...
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
auto pred_end(const MachineBasicBlock *BB)
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
auto successors(const MachineBasicBlock *BB)
LLVM_ABI bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI)
Return true if this is a call to an allocation function that does not have side effects that we are r...
APFloat abs(APFloat X)
Returns the absolute value of the argument.
LLVM_ABI raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
LLVM_ABI Value * getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI)
Gets the alignment argument for an aligned_alloc-like function, using either built-in knowledge based...
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
LLVM_ABI Value * simplifyInstructionWithOperands(Instruction *I, ArrayRef< Value * > NewOps, const SimplifyQuery &Q)
Like simplifyInstruction but the operands of I are replaced with NewOps.
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
LLVM_ABI bool isNoAliasCall(const Value *V)
Return true if this pointer is returned by a noalias function.
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
LLVM_ABI bool isSafeToSpeculativelyExecute(const Instruction *I, const Instruction *CtxI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr, bool UseVariableInfo=true, bool IgnoreUBImplyingAttrs=true)
Return true if the instruction does not have any effects besides calculating the result and does not ...
bool isa_and_nonnull(const Y &Val)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI ConstantRange getConstantRangeFromMetadata(const MDNode &RangeMD)
Parse out a conservative ConstantRange from !range metadata.
auto map_range(ContainerTy &&C, FuncTy F)
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
LLVM_ABI Value * simplifyInstruction(Instruction *I, const SimplifyQuery &Q)
See if we can compute a simplified version of this instruction.
auto dyn_cast_or_null(const Y &Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(const CallBase *Call, bool MustPreserveNullness)
{launder,strip}.invariant.group returns pointer that aliases its argument, and it only captures point...
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
PotentialValuesState< std::pair< AA::ValueAndContext, AA::ValueScope > > PotentialLLVMValuesState
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI bool NullPointerIsDefined(const Function *F, unsigned AS=0)
Check whether null pointer dereferencing is considered undefined behavior for a given function or an ...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isPointerTy(const Type *T)
LLVM_ABI bool wouldInstructionBeTriviallyDead(const Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction would have no side effects if it was not used.
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI CallBase & promoteCall(CallBase &CB, Function *Callee, CastInst **RetBitCast=nullptr)
Promote the given indirect call site to unconditionally call Callee.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI bool hasAssumption(const Function &F, const KnownAssumptionString &AssumptionStr)
Return true if F has the assumption AssumptionStr attached.
LLVM_ABI RetainedKnowledge getKnowledgeFromUse(const Use *U, ArrayRef< Attribute::AttrKind > AttrKinds)
Return a valid Knowledge associated to the Use U if its Attribute kind is in AttrKinds.
@ Success
The lock was released successfully.
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth=0)
Return true if the given value is known to be non-zero when defined.
AtomicOrdering
Atomic ordering for LLVM's memory model.
PotentialValuesState< APInt > PotentialConstantIntValuesState
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
InterleavedRange< Range > interleaved_array(const Range &R, StringRef Separator=", ")
Output range R as an array of interleaved elements.
ChangeStatus clampStateAndIndicateChange< DerefState >(DerefState &S, const DerefState &R)
void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, RemapFlags Flags=RF_None, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr, const MetadataPredicate *IdentityMD=nullptr)
Convert the instruction operands from referencing the current values into those specified by VM.
DWARFExpression::Operation Op
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI Value * getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI)
If this if a call to a free function, return the freed operand.
ChangeStatus clampStateAndIndicateChange(StateType &S, const StateType &R)
Helper function to clamp a state S of type StateType with the information in R and indicate/return if...
constexpr unsigned BitWidth
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
auto pred_begin(const MachineBasicBlock *BB)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
LLVM_ABI std::optional< APInt > getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, function_ref< const Value *(const Value *)> Mapper=[](const Value *V) { return V;})
Return the size of the requested allocation.
LLVM_ABI DenseSet< StringRef > getAssumptions(const Function &F)
Return the set of all assumptions for the function F.
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
LLVM_ABI Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
@ OPTIONAL
The target may be valid if the source is not.
@ NONE
Do not track a dependence between source and target.
@ REQUIRED
The target cannot be valid if the source is not.
LLVM_ABI UseCaptureInfo DetermineUseCaptureKind(const Use &U, const Value *Base)
Determine what kind of capture behaviour U may exhibit.
LLVM_ABI Value * simplifyCmpInst(CmpPredicate Predicate, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a CmpInst, fold the result or return null.
LLVM_ABI bool mayContainIrreducibleControl(const Function &F, const LoopInfo *LI)
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool capturesNothing(CaptureComponents CC)
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
constexpr StringRef AssumptionAttrKey
The key we use for assumption attributes.
constexpr bool isCallableCC(CallingConv::ID CC)
GenericCycleInfo< SSAContext > CycleInfo
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
A type to track pointer/struct usage and accesses for AAPointerInfo.
bool forallInterferingAccesses(AA::RangeTy Range, F CB) const
See AAPointerInfo::forallInterferingAccesses.
AAPointerInfo::const_bin_iterator end() const
ChangeStatus addAccess(Attributor &A, const AAPointerInfo::RangeList &Ranges, Instruction &I, std::optional< Value * > Content, AAPointerInfo::AccessKind Kind, Type *Ty, Instruction *RemoteI=nullptr)
Add a new Access to the state at offset Offset and with size Size.
DenseMap< const Instruction *, SmallVector< unsigned > > RemoteIMap
AAPointerInfo::const_bin_iterator begin() const
AAPointerInfo::OffsetInfo ReturnedOffsets
Flag to determine if the underlying pointer is reaching a return statement in the associated function...
State & operator=(State &&R)
State(State &&SIS)=default
const AAPointerInfo::Access & getAccess(unsigned Index) const
SmallVector< AAPointerInfo::Access > AccessList
bool isAtFixpoint() const override
See AbstractState::isAtFixpoint().
bool forallInterferingAccesses(Instruction &I, F CB, AA::RangeTy &Range) const
See AAPointerInfo::forallInterferingAccesses.
static State getWorstState(const State &SIS)
Return the worst possible representable state.
int64_t numOffsetBins() const
AAPointerInfo::OffsetBinsTy OffsetBins
ChangeStatus indicateOptimisticFixpoint() override
See AbstractState::indicateOptimisticFixpoint().
State & operator=(const State &R)
ChangeStatus indicatePessimisticFixpoint() override
See AbstractState::indicatePessimisticFixpoint().
const State & getAssumed() const
static State getBestState(const State &SIS)
Return the best possible representable state.
bool isValidState() const override
See AbstractState::isValidState().
----------------—AAIntraFnReachability Attribute-----------------------—
ReachabilityQueryInfo(const ReachabilityQueryInfo &RQI)
unsigned Hash
Precomputed hash for this RQI.
const Instruction * From
Start here,.
Reachable Result
and remember if it worked:
ReachabilityQueryInfo(const Instruction *From, const ToTy *To)
ReachabilityQueryInfo(Attributor &A, const Instruction &From, const ToTy &To, const AA::InstExclusionSetTy *ES, bool MakeUnique)
Constructor replacement to ensure unique and stable sets are used for the cache.
const ToTy * To
reach this place,
const AA::InstExclusionSetTy * ExclusionSet
without going through any of these instructions,
unsigned computeHashValue() const
An abstract interface for address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all align attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Align getKnownAlign() const
Return known alignment.
static LLVM_ABI const char ID
An abstract attribute for getting assumption information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract state for querying live call edges.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for specializing "dynamic" components of "denormal-fp-math" and "denormal-fp-ma...
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all dereferenceable attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for llvm::GlobalValue information interference.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for indirect call information interference.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface to track if a value leaves it's defining function instance.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for computing reachability between functions.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool canReach(Attributor &A, const Function &Fn) const
If the function represented by this possition can reach Fn.
virtual bool instructionCanReach(Attributor &A, const Instruction &Inst, const Function &Fn, const AA::InstExclusionSetTy *ExclusionSet=nullptr) const =0
Can Inst reach Fn.
An abstract interface to determine reachability of point A to B.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for identifying pointers from which loads can be marked invariant.
static LLVM_ABI const char ID
Unique ID (due to the unique address).
An abstract interface for liveness abstract attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for memory access kind related attributes (readnone/readonly/writeonly).
bool isAssumedReadOnly() const
Return true if we assume that the underlying value is not accessed (=written) in its respective scope...
bool isKnownReadNone() const
Return true if we know that the underlying value is not read or accessed in its respective scope.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool isAssumedReadNone() const
Return true if we assume that the underlying value is not read or accessed in its respective scope.
An abstract interface for all memory location attributes (readnone/argmemonly/inaccessiblememonly/ina...
static LLVM_ABI std::string getMemoryLocationsAsStr(MemoryLocationsKind MLK)
Return the locations encoded by MLK as a readable string.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
StateType::base_t MemoryLocationsKind
An abstract interface for all nonnull attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for potential address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all noalias attributes.
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all nocapture attributes.
@ NO_CAPTURE_MAYBE_RETURNED
If we do not capture the value in memory or through integers we can only communicate it back as a der...
@ NO_CAPTURE
If we do not capture the value in memory, through integers, or as a derived pointer we know it is not...
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool isAssumedNoCaptureMaybeReturned() const
Return true if we assume that the underlying value is not captured in its respective scope but we all...
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI void determineFunctionCaptureCapabilities(const IRPosition &IRP, const Function &F, BitIntegerState &State)
Update State according to the capture capabilities of F for position IRP.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for nofree.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for norecurse.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for noreturn.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isAlignedBarrier(const CallBase &CB, bool ExecutedAligned)
Helper function to determine if CB is an aligned (GPU) barrier.
static LLVM_ABI bool isNonRelaxedAtomic(const Instruction *I)
Helper function used to determine whether an instruction is non-relaxed atomic.
static LLVM_ABI bool isNoSyncIntrinsic(const Instruction *I)
Helper function specific for intrinsics which are potentially volatile.
An abstract interface for all noundef attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See IRAttribute::isImpliedByIR.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for determining the necessity of the convergent attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all nonnull attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
See AbstractAttribute::isImpliedByIR(...).
A helper containing a list of offsets computed for a Use.
A container for a list of ranges.
static void set_difference(const RangeList &L, const RangeList &R, RangeList &D)
Copy ranges from L that are not in R, into D.
An abstract interface for struct information.
virtual bool reachesReturn() const =0
OffsetBinsTy::const_iterator const_bin_iterator
virtual const_bin_iterator begin() const =0
DenseMap< AA::RangeTy, SmallSet< unsigned, 4 > > OffsetBinsTy
static LLVM_ABI const char ID
Unique ID (due to the unique address)
virtual int64_t numOffsetBins() const =0
An abstract interface for potential values analysis.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI Value * getSingleValue(Attributor &A, const AbstractAttribute &AA, const IRPosition &IRP, SmallVectorImpl< AA::ValueAndContext > &Values)
Extract the single value in Values if any.
An abstract interface for privatizability.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for undefined behavior.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for getting all assumption underlying objects.
virtual bool forallUnderlyingObjects(function_ref< bool(Value &)> Pred, AA::ValueScope Scope=AA::Interprocedural) const =0
Check Pred on all underlying objects in Scope collected so far.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for range value analysis.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for value simplify abstract attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for willreturn.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Helper to represent an access offset and size, with logic to deal with uncertainty and check for over...
static constexpr int64_t Unknown
static RangeTy getUnknown()
const Instruction * getCtxI() const
Base struct for all "concrete attribute" deductions.
void print(raw_ostream &OS) const
Helper functions, for debug purposes only.
virtual StateType & getState()=0
Return the internal abstract state for inspection.
An interface to query the internal state of an abstract attribute.
virtual bool isAtFixpoint() const =0
Return if this abstract state is fixed, thus does not need to be updated if information changes as it...
virtual bool isValidState() const =0
Return if this abstract state is in a valid state.
Helper for AA::PointerInfo::Access DenseMap/Set usage ignoring everythign but the instruction.
static unsigned getHashValue(const Access &A)
AAPointerInfo::Access Access
static Access getTombstoneKey()
DenseMapInfo< Instruction * > Base
static bool isEqual(const Access &LHS, const Access &RHS)
static Access getEmptyKey()
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
std::function< void( const ArgumentReplacementInfo &, Function &, Function::arg_iterator)> CalleeRepairCBTy
Callee repair callback type.
const Argument & getReplacedArg() const
std::function< void(const ArgumentReplacementInfo &, AbstractCallSite, SmallVectorImpl< Value * > &)> ACSRepairCBTy
Abstract call site (ACS) repair callback type.
The fixpoint analysis framework that orchestrates the attribute deduction.
std::function< std::optional< Value * >( const IRPosition &, const AbstractAttribute *, bool &)> SimplifictionCallbackTy
Register CB as a simplification callback.
Specialization of the integer state for a bit-wise encoding.
BitIntegerState & addKnownBits(base_t Bits)
Add the bits in BitsEncoding to the "known bits".
Simple wrapper for a single bit (boolean) state.
static constexpr DenormalMode getDefault()
Return the assumed default mode for a function without denormal-fp-math.
static constexpr DenormalMode getInvalid()
static Access getTombstoneKey()
static unsigned getHashValue(const Access &A)
static Access getEmptyKey()
AAPointerInfo::Access Access
static bool isEqual(const Access &LHS, const Access &RHS)
static bool isEqual(const AA::RangeTy &A, const AA::RangeTy B)
static AA::RangeTy getTombstoneKey()
static unsigned getHashValue(const AA::RangeTy &Range)
static AA::RangeTy getEmptyKey()
static ReachabilityQueryInfo< ToTy > EmptyKey
static ReachabilityQueryInfo< ToTy > TombstoneKey
static ReachabilityQueryInfo< ToTy > * getEmptyKey()
DenseMapInfo< std::pair< const Instruction *, const ToTy * > > PairDMI
static ReachabilityQueryInfo< ToTy > * getTombstoneKey()
static bool isEqual(const ReachabilityQueryInfo< ToTy > *LHS, const ReachabilityQueryInfo< ToTy > *RHS)
DenseMapInfo< const AA::InstExclusionSetTy * > InstSetDMI
static unsigned getHashValue(const ReachabilityQueryInfo< ToTy > *RQI)
An information struct used to provide DenseMap with the various necessary components for a given valu...
State for dereferenceable attribute.
IncIntegerState DerefBytesState
State representing for dereferenceable bytes.
ChangeStatus manifest(Attributor &A) override
See AbstractAttribute::manifest(...).
Helper to describe and deal with positions in the LLVM-IR.
Function * getAssociatedFunction() const
Return the associated function, if any.
static const IRPosition callsite_returned(const CallBase &CB)
Create a position describing the returned value of CB.
static const IRPosition returned(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the returned value of F.
LLVM_ABI Argument * getAssociatedArgument() const
Return the associated argument, if any.
static const IRPosition value(const Value &V, const CallBaseContext *CBContext=nullptr)
Create a position describing the value of V.
int getCalleeArgNo() const
Return the callee argument number of the associated value if it is an argument or call site argument,...
static const IRPosition inst(const Instruction &I, const CallBaseContext *CBContext=nullptr)
Create a position describing the instruction I.
static const IRPosition callsite_argument(const CallBase &CB, unsigned ArgNo)
Create a position describing the argument of CB at position ArgNo.
@ IRP_ARGUMENT
An attribute for a function argument.
@ IRP_RETURNED
An attribute for the function return value.
@ IRP_CALL_SITE
An attribute for a call site (function scope).
@ IRP_CALL_SITE_RETURNED
An attribute for a call site return value.
@ IRP_FUNCTION
An attribute for a function (scope).
@ IRP_CALL_SITE_ARGUMENT
An attribute for a call site argument.
@ IRP_INVALID
An invalid position.
Instruction * getCtxI() const
Return the context instruction, if any.
static const IRPosition argument(const Argument &Arg, const CallBaseContext *CBContext=nullptr)
Create a position describing the argument Arg.
Type * getAssociatedType() const
Return the type this abstract attribute is associated with.
static const IRPosition function(const Function &F, const CallBaseContext *CBContext=nullptr)
Create a position describing the function scope of F.
const CallBaseContext * getCallBaseContext() const
Get the call base context from the position.
Value & getAssociatedValue() const
Return the value this abstract attribute is associated with.
Value & getAnchorValue() const
Return the value this abstract attribute is anchored with.
int getCallSiteArgNo() const
Return the call site argument number of the associated value if it is an argument or call site argume...
static const IRPosition function_scope(const IRPosition &IRP, const CallBaseContext *CBContext=nullptr)
Create a position with function scope matching the "context" of IRP.
Kind getPositionKind() const
Return the associated position kind.
bool isArgumentPosition() const
Return true if the position is an argument or call site argument.
static const IRPosition callsite_function(const CallBase &CB)
Create a position describing the function scope of CB.
Function * getAnchorScope() const
Return the Function surrounding the anchor value.
ConstantRange getKnown() const
Return the known state encoding.
ConstantRange getAssumed() const
Return the assumed state encoding.
base_t getAssumed() const
Return the assumed state encoding.
static constexpr base_t getWorstState()
Helper that allows to insert a new assumption string in the known assumption set by creating a (stati...
FPClassTest KnownFPClasses
Floating-point classes the value could be one of.
A "must be executed context" for a given program point PP is the set of instructions,...
iterator & end()
Return an universal end iterator.
bool findInContextOf(const Instruction *I, const Instruction *PP)
Helper to look for I in the context of PP.
iterator & begin(const Instruction *PP)
Return an iterator to explore the context around PP.
bool checkForAllContext(const Instruction *PP, function_ref< bool(const Instruction *)> Pred)
}
static unsigned MaxPotentialValues
Helper to tie a abstract state implementation to an abstract attribute.
StateType & getState() override
See AbstractAttribute::getState(...).
bool isPassthrough() const
LLVM_ABI bool unionAssumed(std::optional< Value * > Other)
Merge Other into the currently assumed simplified value.
std::optional< Value * > SimplifiedAssociatedValue
An assumed simplified value.
Type * Ty
The type of the original value.