57#include "llvm/IR/IntrinsicsAMDGPU.h"
58#include "llvm/IR/IntrinsicsNVPTX.h"
85#define DEBUG_TYPE "attributor"
89 cl::desc(
"Manifest Attributor internal string attributes."),
101 "attributor-max-potential-values",
cl::Hidden,
102 cl::desc(
"Maximum number of potential values to be "
103 "tracked for each position."),
108 "attributor-max-potential-values-iterations",
cl::Hidden,
110 "Maximum number of iterations we keep dismantling potential values."),
113STATISTIC(NumAAs,
"Number of abstract attributes created");
114STATISTIC(NumIndirectCallsPromoted,
"Number of indirect calls promoted");
129#define BUILD_STAT_MSG_IR_ATTR(TYPE, NAME) \
130 ("Number of " #TYPE " marked '" #NAME "'")
131#define BUILD_STAT_NAME(NAME, TYPE) NumIR##TYPE##_##NAME
132#define STATS_DECL_(NAME, MSG) STATISTIC(NAME, MSG);
133#define STATS_DECL(NAME, TYPE, MSG) \
134 STATS_DECL_(BUILD_STAT_NAME(NAME, TYPE), MSG);
135#define STATS_TRACK(NAME, TYPE) ++(BUILD_STAT_NAME(NAME, TYPE));
136#define STATS_DECLTRACK(NAME, TYPE, MSG) \
137 {STATS_DECL(NAME, TYPE, MSG) STATS_TRACK(NAME, TYPE)}
138#define STATS_DECLTRACK_ARG_ATTR(NAME) \
139 STATS_DECLTRACK(NAME, Arguments, BUILD_STAT_MSG_IR_ATTR(arguments, NAME))
140#define STATS_DECLTRACK_CSARG_ATTR(NAME) \
141 STATS_DECLTRACK(NAME, CSArguments, \
142 BUILD_STAT_MSG_IR_ATTR(call site arguments, NAME))
143#define STATS_DECLTRACK_FN_ATTR(NAME) \
144 STATS_DECLTRACK(NAME, Function, BUILD_STAT_MSG_IR_ATTR(functions, NAME))
145#define STATS_DECLTRACK_CS_ATTR(NAME) \
146 STATS_DECLTRACK(NAME, CS, BUILD_STAT_MSG_IR_ATTR(call site, NAME))
147#define STATS_DECLTRACK_FNRET_ATTR(NAME) \
148 STATS_DECLTRACK(NAME, FunctionReturn, \
149 BUILD_STAT_MSG_IR_ATTR(function returns, NAME))
150#define STATS_DECLTRACK_CSRET_ATTR(NAME) \
151 STATS_DECLTRACK(NAME, CSReturn, \
152 BUILD_STAT_MSG_IR_ATTR(call site returns, NAME))
153#define STATS_DECLTRACK_FLOATING_ATTR(NAME) \
154 STATS_DECLTRACK(NAME, Floating, \
155 ("Number of floating values known to be '" #NAME "'"))
160#define PIPE_OPERATOR(CLASS) \
161 raw_ostream &operator<<(raw_ostream &OS, const CLASS &AA) { \
162 return OS << static_cast<const AbstractAttribute &>(AA); \
219 bool HeaderOnly,
CycleRef *CPtr =
nullptr) {
222 auto *BB =
I->getParent();
239 if (
DL.getTypeSizeInBits(Ty) !=
DL.getTypeAllocSizeInBits(Ty))
264 StartPos +=
DL.getTypeAllocSizeInBits(ElTy);
275 bool AllowVolatile) {
276 if (!AllowVolatile &&
I->isVolatile())
280 return LI->getPointerOperand();
284 return SI->getPointerOperand();
288 return CXI->getPointerOperand();
292 return RMWI->getPointerOperand();
314 bool GetMinOffset,
bool AllowNonInbounds,
315 bool UseAssumed =
false) {
317 auto AttributorAnalysis = [&](
Value &
V,
APInt &ROffset) ->
bool {
324 if (!ValueConstantRangeAA)
328 if (
Range.isFullSet())
334 ROffset =
Range.getSignedMin();
336 ROffset =
Range.getSignedMax();
347 const Value *Ptr, int64_t &BytesOffset,
352 true, AllowNonInbounds);
360template <
typename AAType,
typename StateType =
typename AAType::StateType,
362 bool RecurseForSelectAndPHI =
true>
364 Attributor &
A,
const AAType &QueryingAA, StateType &S,
366 LLVM_DEBUG(
dbgs() <<
"[Attributor] Clamp return value states for "
367 << QueryingAA <<
" into " << S <<
"\n");
369 assert((QueryingAA.getIRPosition().getPositionKind() ==
371 QueryingAA.getIRPosition().getPositionKind() ==
373 "Can only clamp returned value states for a function returned or call "
374 "site returned position!");
378 std::optional<StateType>
T;
381 auto CheckReturnValue = [&](
Value &RV) ->
bool {
395 <<
" AA: " <<
AA->getAsStr(&
A) <<
" @ " << RVPos <<
"\n");
396 const StateType &AAS =
AA->getState();
398 T = StateType::getBestState(AAS);
400 LLVM_DEBUG(
dbgs() <<
"[Attributor] AA State: " << AAS <<
" RV State: " <<
T
402 return T->isValidState();
405 if (!
A.checkForAllReturnedValues(CheckReturnValue, QueryingAA,
407 RecurseForSelectAndPHI))
408 S.indicatePessimisticFixpoint();
415template <
typename AAType,
typename BaseType,
416 typename StateType =
typename BaseType::StateType,
417 bool PropagateCallBaseContext =
false,
419 bool RecurseForSelectAndPHI =
true>
420struct AAReturnedFromReturnedValues :
public BaseType {
421 AAReturnedFromReturnedValues(
const IRPosition &IRP, Attributor &
A)
425 StateType S(StateType::getBestState(this->getState()));
427 RecurseForSelectAndPHI>(
429 PropagateCallBaseContext ? this->getCallBaseContext() : nullptr);
438template <
typename AAType,
typename StateType =
typename AAType::StateType,
440static void clampCallSiteArgumentStates(
Attributor &
A,
const AAType &QueryingAA,
442 LLVM_DEBUG(
dbgs() <<
"[Attributor] Clamp call site argument states for "
443 << QueryingAA <<
" into " << S <<
"\n");
445 assert(QueryingAA.getIRPosition().getPositionKind() ==
447 "Can only clamp call site argument states for an argument position!");
451 std::optional<StateType>
T;
454 unsigned ArgNo = QueryingAA.getIRPosition().getCallSiteArgNo();
474 LLVM_DEBUG(
dbgs() <<
"[Attributor] ACS: " << *ACS.getInstruction()
475 <<
" AA: " <<
AA->getAsStr(&
A) <<
" @" << ACSArgPos
477 const StateType &AAS =
AA->getState();
479 T = StateType::getBestState(AAS);
481 LLVM_DEBUG(
dbgs() <<
"[Attributor] AA State: " << AAS <<
" CSA State: " <<
T
483 return T->isValidState();
486 bool UsedAssumedInformation =
false;
487 if (!
A.checkForAllCallSites(CallSiteCheck, QueryingAA,
true,
488 UsedAssumedInformation))
489 S.indicatePessimisticFixpoint();
496template <
typename AAType,
typename BaseType,
497 typename StateType =
typename AAType::StateType,
499bool getArgumentStateFromCallBaseContext(
Attributor &
A,
503 "Expected an 'argument' position !");
509 assert(ArgNo >= 0 &&
"Invalid Arg No!");
523 const StateType &CBArgumentState =
524 static_cast<const StateType &
>(
AA->getState());
526 LLVM_DEBUG(
dbgs() <<
"[Attributor] Briding Call site context to argument"
527 <<
"Position:" << Pos <<
"CB Arg state:" << CBArgumentState
531 State ^= CBArgumentState;
536template <
typename AAType,
typename BaseType,
537 typename StateType =
typename AAType::StateType,
538 bool BridgeCallBaseContext =
false,
540struct AAArgumentFromCallSiteArguments :
public BaseType {
541 AAArgumentFromCallSiteArguments(
const IRPosition &IRP, Attributor &
A)
545 StateType S = StateType::getBestState(this->getState());
547 if (BridgeCallBaseContext) {
549 getArgumentStateFromCallBaseContext<AAType,
BaseType, StateType,
551 A, *
this, this->getIRPosition(), S);
555 clampCallSiteArgumentStates<AAType, StateType, IRAttributeKind>(
A, *
this,
565template <
typename AAType,
typename BaseType,
566 typename StateType =
typename BaseType::StateType,
567 bool IntroduceCallBaseContext =
false,
569struct AACalleeToCallSite :
public BaseType {
570 AACalleeToCallSite(
const IRPosition &IRP, Attributor &
A) :
BaseType(IRP,
A) {}
573 auto IRPKind = this->getIRPosition().getPositionKind();
576 "Can only wrap function returned positions for call site "
577 "returned positions!");
578 auto &S = this->getState();
581 if (IntroduceCallBaseContext)
582 LLVM_DEBUG(
dbgs() <<
"[Attributor] Introducing call base context:" << CB
587 for (
const Function *Callee : Callees) {
596 IntroduceCallBaseContext ? &CB :
nullptr)
598 *
Callee, IntroduceCallBaseContext ? &CB : nullptr);
600 if (Attribute::isEnumAttrKind(IRAttributeKind)) {
603 A,
this, FnPos, DepClassTy::REQUIRED, IsKnown))
609 A.getAAFor<AAType>(*
this, FnPos, DepClassTy::REQUIRED);
613 if (S.isAtFixpoint())
614 return S.isValidState();
618 if (!
A.checkForAllCallees(CalleePred, *
this, CB))
619 return S.indicatePessimisticFixpoint();
625template <
class AAType,
typename StateType =
typename AAType::StateType>
631 auto EIt = Explorer.
begin(CtxI), EEnd = Explorer.
end(CtxI);
632 for (
unsigned u = 0;
u <
Uses.size(); ++
u) {
636 if (Found &&
AA.followUseInMBEC(
A, U, UserI, State))
651template <
class AAType,
typename StateType =
typename AAType::StateType>
652static void followUsesInMBEC(AAType &
AA,
Attributor &
A, StateType &S,
654 const Value &Val =
AA.getIRPosition().getAssociatedValue();
659 A.getInfoCache().getMustBeExecutedContextExplorer();
665 for (
const Use &U : Val.
uses())
668 followUsesInContext<AAType>(
AA,
A, *Explorer, &CtxI,
Uses, S);
670 if (S.isAtFixpoint())
714 StateType ParentState;
718 ParentState.indicateOptimisticFixpoint();
720 for (
const BasicBlock *BB : Br->successors()) {
721 StateType ChildState;
723 size_t BeforeSize =
Uses.size();
724 followUsesInContext(
AA,
A, *Explorer, &BB->front(),
Uses, ChildState);
727 for (
auto It =
Uses.begin() + BeforeSize; It !=
Uses.end();)
730 ParentState &= ChildState;
781 R.indicatePessimisticFixpoint();
795 BS.indicateOptimisticFixpoint();
800 BS.indicatePessimisticFixpoint();
870 template <
typename F>
877 if (!
Range.mayOverlap(ItRange))
879 bool IsExact =
Range == ItRange && !
Range.offsetOrSizeAreUnknown();
880 for (
auto Index : It.getSecond()) {
890 template <
typename F>
901 for (
unsigned Index : LocalList->getSecond()) {
904 if (
Range.offsetAndSizeAreUnknown())
920 RemoteI = RemoteI ? RemoteI : &
I;
924 bool AccExists =
false;
926 for (
auto Index : LocalList) {
928 if (
A.getLocalInst() == &
I) {
937 <<
"[AAPointerInfo] Inserting access in new offset bins\n";);
939 for (
auto Key : ToAdd) {
946 AccessList.emplace_back(&
I, RemoteI, Ranges, Content, Kind, Ty);
948 "New Access should have been at AccIndex");
949 LocalList.push_back(AccIndex);
958 auto Before = Current;
960 if (Current == Before)
963 auto &ExistingRanges = Before.getRanges();
964 auto &NewRanges = Current.getRanges();
971 <<
"[AAPointerInfo] Removing access from old offset bins\n";);
978 "Expected bin to actually contain the Access.");
1000struct AAPointerInfoImpl
1001 :
public StateWrapper<AA::PointerInfo::State, AAPointerInfo> {
1005 const std::string getAsStr(
Attributor *
A)
const override {
1006 return std::string(
"PointerInfo ") +
1007 (isValidState() ? (std::string(
"#") +
1008 std::to_string(OffsetBins.size()) +
" bins")
1013 [](int64_t O) {
return std::to_string(O); }),
1020 return AAPointerInfo::manifest(
A);
1023 const_bin_iterator
begin()
const override {
return State::begin(); }
1024 const_bin_iterator
end()
const override {
return State::end(); }
1025 int64_t numOffsetBins()
const override {
return State::numOffsetBins(); }
1026 bool reachesReturn()
const override {
1027 return !ReturnedOffsets.isUnassigned();
1029 void addReturnedOffsetsTo(OffsetInfo &OI)
const override {
1030 if (ReturnedOffsets.isUnknown()) {
1035 OffsetInfo MergedOI;
1036 for (
auto Offset : ReturnedOffsets) {
1037 OffsetInfo TmpOI = OI;
1039 MergedOI.merge(TmpOI);
1041 OI = std::move(MergedOI);
1044 ChangeStatus setReachesReturn(
const OffsetInfo &ReachedReturnedOffsets) {
1045 if (ReturnedOffsets.isUnknown())
1046 return ChangeStatus::UNCHANGED;
1047 if (ReachedReturnedOffsets.isUnknown()) {
1048 ReturnedOffsets.setUnknown();
1049 return ChangeStatus::CHANGED;
1051 if (ReturnedOffsets.merge(ReachedReturnedOffsets))
1052 return ChangeStatus::CHANGED;
1053 return ChangeStatus::UNCHANGED;
1056 bool forallInterferingAccesses(
1058 function_ref<
bool(
const AAPointerInfo::Access &,
bool)> CB)
1060 return State::forallInterferingAccesses(
Range, CB);
1063 bool forallInterferingAccesses(
1064 Attributor &
A,
const AbstractAttribute &QueryingAA, Instruction &
I,
1065 bool FindInterferingWrites,
bool FindInterferingReads,
1066 function_ref<
bool(
const Access &,
bool)> UserCB,
bool &HasBeenWrittenTo,
1068 function_ref<
bool(
const Access &)> SkipCB)
const override {
1069 HasBeenWrittenTo =
false;
1071 SmallPtrSet<const Access *, 8> DominatingWrites;
1079 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
1081 bool AllInSameNoSyncFn = IsAssumedNoSync;
1082 bool InstIsExecutedByInitialThreadOnly =
1083 ExecDomainAA && ExecDomainAA->isExecutedByInitialThreadOnly(
I);
1090 bool InstIsExecutedInAlignedRegion =
1091 FindInterferingReads && ExecDomainAA &&
1092 ExecDomainAA->isExecutedInAlignedRegion(
A,
I);
1094 if (InstIsExecutedInAlignedRegion || InstIsExecutedByInitialThreadOnly)
1095 A.recordDependence(*ExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1097 InformationCache &InfoCache =
A.getInfoCache();
1098 bool IsThreadLocalObj =
1107 auto CanIgnoreThreadingForInst = [&](
const Instruction &
I) ->
bool {
1108 if (IsThreadLocalObj || AllInSameNoSyncFn)
1110 const auto *FnExecDomainAA =
1111 I.getFunction() == &
Scope
1113 :
A.lookupAAFor<AAExecutionDomain>(
1116 if (!FnExecDomainAA)
1118 if (InstIsExecutedInAlignedRegion ||
1119 (FindInterferingWrites &&
1120 FnExecDomainAA->isExecutedInAlignedRegion(
A,
I))) {
1121 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1124 if (InstIsExecutedByInitialThreadOnly &&
1125 FnExecDomainAA->isExecutedByInitialThreadOnly(
I)) {
1126 A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);
1135 auto CanIgnoreThreading = [&](
const Access &Acc) ->
bool {
1136 return CanIgnoreThreadingForInst(*Acc.getRemoteInst()) ||
1137 (Acc.getRemoteInst() != Acc.getLocalInst() &&
1138 CanIgnoreThreadingForInst(*Acc.getLocalInst()));
1142 bool IsKnownNoRecurse;
1150 bool InstInKernel =
A.getInfoCache().isKernel(Scope);
1151 bool ObjHasKernelLifetime =
false;
1152 const bool UseDominanceReasoning =
1153 FindInterferingWrites && IsKnownNoRecurse;
1154 const DominatorTree *DT =
1163 unsigned VAS =
V->getType()->getPointerAddressSpace();
1174 std::function<bool(
const Function &)> IsLiveInCalleeCB;
1179 const Function *AIFn = AI->getFunction();
1180 ObjHasKernelLifetime =
A.getInfoCache().isKernel(*AIFn);
1181 bool IsKnownNoRecurse;
1184 IsKnownNoRecurse)) {
1185 IsLiveInCalleeCB = [AIFn](
const Function &Fn) {
return AIFn != &Fn; };
1190 ObjHasKernelLifetime = HasKernelLifetime(GV, *GV->getParent());
1191 if (ObjHasKernelLifetime)
1192 IsLiveInCalleeCB = [&
A](
const Function &Fn) {
1193 return !
A.getInfoCache().isKernel(Fn);
1201 auto AccessCB = [&](
const Access &Acc,
bool Exact) {
1202 Function *AccScope = Acc.getRemoteInst()->getFunction();
1203 bool AccInSameScope = AccScope == &
Scope;
1207 if (InstInKernel && ObjHasKernelLifetime && !AccInSameScope &&
1208 A.getInfoCache().isKernel(*AccScope))
1211 if (Exact && Acc.isMustAccess() && Acc.getRemoteInst() != &
I) {
1212 if (Acc.isWrite() || (
isa<LoadInst>(
I) && Acc.isWriteOrAssumption()))
1213 ExclusionSet.
insert(Acc.getRemoteInst());
1216 if ((!FindInterferingWrites || !Acc.isWriteOrAssumption()) &&
1217 (!FindInterferingReads || !Acc.isRead()))
1220 bool Dominates = FindInterferingWrites && DT && Exact &&
1221 Acc.isMustAccess() && AccInSameScope &&
1224 DominatingWrites.
insert(&Acc);
1228 AllInSameNoSyncFn &= Acc.getRemoteInst()->getFunction() == &
Scope;
1230 InterferingAccesses.
push_back({&Acc, Exact});
1233 if (!State::forallInterferingAccesses(
I, AccessCB,
Range))
1236 HasBeenWrittenTo = !DominatingWrites.
empty();
1240 for (
const Access *Acc : DominatingWrites) {
1241 if (!LeastDominatingWriteInst) {
1242 LeastDominatingWriteInst = Acc->getRemoteInst();
1243 }
else if (DT->
dominates(LeastDominatingWriteInst,
1244 Acc->getRemoteInst())) {
1245 LeastDominatingWriteInst = Acc->getRemoteInst();
1250 auto CanSkipAccess = [&](
const Access &Acc,
bool Exact) {
1251 if (SkipCB && SkipCB(Acc))
1253 if (!CanIgnoreThreading(Acc))
1259 bool ReadChecked = !FindInterferingReads;
1260 bool WriteChecked = !FindInterferingWrites;
1266 &ExclusionSet, IsLiveInCalleeCB))
1271 if (!WriteChecked) {
1273 &ExclusionSet, IsLiveInCalleeCB))
1274 WriteChecked =
true;
1288 if (!WriteChecked && HasBeenWrittenTo &&
1289 Acc.getRemoteInst()->getFunction() != &Scope) {
1291 const auto *FnReachabilityAA =
A.getAAFor<AAInterFnReachability>(
1293 if (FnReachabilityAA) {
1299 if (!FnReachabilityAA->instructionCanReach(
1300 A, *LeastDominatingWriteInst,
1301 *Acc.getRemoteInst()->getFunction(), &ExclusionSet))
1302 WriteChecked =
true;
1309 if (ReadChecked && WriteChecked)
1312 if (!DT || !UseDominanceReasoning)
1314 if (!DominatingWrites.count(&Acc))
1316 return LeastDominatingWriteInst != Acc.getRemoteInst();
1321 for (
auto &It : InterferingAccesses) {
1322 if ((!AllInSameNoSyncFn && !IsThreadLocalObj && !ExecDomainAA) ||
1323 !CanSkipAccess(*It.first, It.second)) {
1324 if (!UserCB(*It.first, It.second))
1332 const AAPointerInfo &OtherAA,
1334 using namespace AA::PointerInfo;
1336 return indicatePessimisticFixpoint();
1339 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1340 bool IsByval = OtherAAImpl.getAssociatedArgument()->hasByValAttr();
1341 Changed |= setReachesReturn(OtherAAImpl.ReturnedOffsets);
1344 const auto &State = OtherAAImpl.getState();
1345 for (
const auto &It : State) {
1346 for (
auto Index : It.getSecond()) {
1347 const auto &RAcc = State.getAccess(Index);
1348 if (IsByval && !RAcc.isRead())
1350 bool UsedAssumedInformation =
false;
1352 auto Content =
A.translateArgumentToCallSiteContent(
1353 RAcc.getContent(), CB, *
this, UsedAssumedInformation);
1354 AK =
AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW));
1355 AK =
AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST));
1357 Changed |= addAccess(
A, RAcc.getRanges(), CB, Content, AK,
1358 RAcc.getType(), RAcc.getRemoteInst());
1364 ChangeStatus translateAndAddState(Attributor &
A,
const AAPointerInfo &OtherAA,
1365 const OffsetInfo &Offsets, CallBase &CB,
1367 using namespace AA::PointerInfo;
1369 return indicatePessimisticFixpoint();
1371 const auto &OtherAAImpl =
static_cast<const AAPointerInfoImpl &
>(OtherAA);
1375 const auto &State = OtherAAImpl.getState();
1376 for (
const auto &It : State) {
1377 for (
auto Index : It.getSecond()) {
1378 const auto &RAcc = State.getAccess(Index);
1379 if (!IsMustAcc && RAcc.isAssumption())
1381 for (
auto Offset : Offsets) {
1385 if (!NewRanges.isUnknown()) {
1386 NewRanges.addToAllOffsets(Offset);
1391 Changed |= addAccess(
A, NewRanges, CB, RAcc.getContent(), AK,
1392 RAcc.getType(), RAcc.getRemoteInst());
1400 void trackPointerInfoStatistics(
const IRPosition &IRP)
const {}
1403 void dumpState(raw_ostream &O) {
1404 for (
auto &It : OffsetBins) {
1405 O <<
"[" << It.first.Offset <<
"-" << It.first.Offset + It.first.Size
1406 <<
"] : " << It.getSecond().size() <<
"\n";
1407 for (
auto AccIndex : It.getSecond()) {
1408 auto &Acc = AccessList[AccIndex];
1409 O <<
" - " << Acc.getKind() <<
" - " << *Acc.getLocalInst() <<
"\n";
1410 if (Acc.getLocalInst() != Acc.getRemoteInst())
1411 O <<
" --> " << *Acc.getRemoteInst()
1413 if (!Acc.isWrittenValueYetUndetermined()) {
1415 O <<
" - c: func " << Acc.getWrittenValue()->getName()
1417 else if (Acc.getWrittenValue())
1418 O <<
" - c: " << *Acc.getWrittenValue() <<
"\n";
1420 O <<
" - c: <unknown>\n";
1427struct AAPointerInfoFloating :
public AAPointerInfoImpl {
1429 AAPointerInfoFloating(
const IRPosition &IRP, Attributor &
A)
1430 : AAPointerInfoImpl(IRP,
A) {}
1433 bool handleAccess(Attributor &
A, Instruction &
I,
1434 std::optional<Value *> Content,
AccessKind Kind,
1437 using namespace AA::PointerInfo;
1439 const DataLayout &
DL =
A.getDataLayout();
1440 TypeSize AccessSize =
DL.getTypeStoreSize(&Ty);
1449 if (!VT || VT->getElementCount().isScalable() ||
1451 (*Content)->getType() != VT ||
1452 DL.getTypeStoreSize(VT->getElementType()).isScalable()) {
1463 int64_t ElementSize =
DL.getTypeStoreSize(ElementType).getFixedValue();
1467 OffsetsSorted.end());
1469 for (
int i = 0, e = VT->getElementCount().getFixedValue(); i != e; ++i) {
1471 ConstContent, ConstantInt::get(Int32Ty, i));
1478 for (
auto &ElementOffset : ElementOffsets)
1479 ElementOffset += ElementSize;
1491 bool collectConstantsForGEP(Attributor &
A,
const DataLayout &
DL,
1492 OffsetInfo &UsrOI,
const OffsetInfo &PtrOI,
1493 const GEPOperator *
GEP);
1495 void trackStatistics()
const override {
1496 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1500bool AAPointerInfoFloating::collectConstantsForGEP(Attributor &
A,
1501 const DataLayout &
DL,
1503 const OffsetInfo &PtrOI,
1504 const GEPOperator *
GEP) {
1505 unsigned BitWidth =
DL.getIndexTypeSizeInBits(
GEP->getType());
1506 SmallMapVector<Value *, APInt, 4> VariableOffsets;
1509 assert(!UsrOI.isUnknown() && !PtrOI.isUnknown() &&
1510 "Don't look for constant values if the offset has already been "
1511 "determined to be unknown.");
1513 if (!
GEP->collectOffset(
DL,
BitWidth, VariableOffsets, ConstantOffset)) {
1519 << (VariableOffsets.
empty() ?
"" :
"not") <<
" constant "
1523 Union.addToAll(ConstantOffset.getSExtValue());
1528 for (
const auto &VI : VariableOffsets) {
1529 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
1531 if (!PotentialConstantsAA || !PotentialConstantsAA->isValidState()) {
1537 if (PotentialConstantsAA->undefIsContained())
1544 auto &AssumedSet = PotentialConstantsAA->getAssumedSet();
1545 if (AssumedSet.empty())
1549 for (
const auto &ConstOffset : AssumedSet) {
1550 auto CopyPerOffset =
Union;
1551 CopyPerOffset.addToAll(ConstOffset.getSExtValue() *
1552 VI.second.getZExtValue());
1553 Product.merge(CopyPerOffset);
1558 UsrOI = std::move(Union);
1562ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &
A) {
1563 using namespace AA::PointerInfo;
1565 const DataLayout &
DL =
A.getDataLayout();
1566 Value &AssociatedValue = getAssociatedValue();
1568 DenseMap<Value *, OffsetInfo> OffsetInfoMap;
1569 OffsetInfoMap[&AssociatedValue].
insert(0);
1571 auto HandlePassthroughUser = [&](
Value *Usr,
Value *CurPtr,
bool &Follow) {
1582 "CurPtr does not exist in the map!");
1584 auto &UsrOI = OffsetInfoMap[Usr];
1585 auto &PtrOI = OffsetInfoMap[CurPtr];
1586 assert(!PtrOI.isUnassigned() &&
1587 "Cannot pass through if the input Ptr was not visited!");
1593 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
1595 User *Usr =
U.getUser();
1596 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Analyze " << *CurPtr <<
" in " << *Usr
1599 "The current pointer offset should have been seeded!");
1600 assert(!OffsetInfoMap[CurPtr].isUnassigned() &&
1601 "Current pointer should be assigned");
1607 return HandlePassthroughUser(Usr, CurPtr, Follow);
1612 auto &UsrOI = OffsetInfoMap[Usr];
1613 auto &PtrOI = OffsetInfoMap[CurPtr];
1615 if (UsrOI.isUnknown())
1618 if (PtrOI.isUnknown()) {
1624 Follow = collectConstantsForGEP(
A,
DL, UsrOI, PtrOI,
GEP);
1628 return HandlePassthroughUser(Usr, CurPtr, Follow);
1633 if (RI->getFunction() == getAssociatedFunction()) {
1634 auto &PtrOI = OffsetInfoMap[CurPtr];
1635 Changed |= setReachesReturn(PtrOI);
1648 auto &UsrOI = PhiIt->second;
1649 auto &PtrOI = OffsetInfoMap[CurPtr];
1653 if (PtrOI.isUnknown()) {
1654 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand offset unknown "
1655 << *CurPtr <<
" in " << *
PHI <<
"\n");
1656 Follow = !UsrOI.isUnknown();
1662 if (UsrOI == PtrOI) {
1663 assert(!PtrOI.isUnassigned() &&
1664 "Cannot assign if the current Ptr was not visited!");
1665 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant (so far)");
1675 auto It = OffsetInfoMap.
find(CurPtrBase);
1676 if (It == OffsetInfoMap.
end()) {
1677 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI operand is too complex "
1678 << *CurPtr <<
" in " << *
PHI
1679 <<
" (base: " << *CurPtrBase <<
")\n");
1693 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
1694 *
PHI->getFunction());
1696 auto BaseOI = It->getSecond();
1697 BaseOI.addToAll(
Offset.getZExtValue());
1698 if (IsFirstPHIUser || BaseOI == UsrOI) {
1699 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] PHI is invariant " << *CurPtr
1700 <<
" in " << *Usr <<
"\n");
1701 return HandlePassthroughUser(Usr, CurPtr, Follow);
1705 dbgs() <<
"[AAPointerInfo] PHI operand pointer offset mismatch "
1706 << *CurPtr <<
" in " << *
PHI <<
"\n");
1725 if (!handleAccess(
A, *LoadI,
nullptr, AK,
1726 OffsetInfoMap[CurPtr].Offsets,
Changed,
1732 return II->isAssumeLikeIntrinsic();
1743 }
while (FromI && FromI != ToI);
1748 auto IsValidAssume = [&](IntrinsicInst &IntrI) {
1749 if (IntrI.getIntrinsicID() != Intrinsic::assume)
1752 if (IntrI.getParent() == BB) {
1753 if (IsImpactedInRange(LoadI->getNextNode(), &IntrI))
1759 if ((*PredIt) != BB)
1764 if (SuccBB == IntrBB)
1770 if (IsImpactedInRange(LoadI->getNextNode(), BB->
getTerminator()))
1772 if (IsImpactedInRange(&IntrBB->
front(), &IntrI))
1778 std::pair<Value *, IntrinsicInst *>
Assumption;
1779 for (
const Use &LoadU : LoadI->uses()) {
1781 if (!CmpI->isEquality() || !CmpI->isTrueWhenEqual())
1783 for (
const Use &CmpU : CmpI->uses()) {
1785 if (!IsValidAssume(*IntrI))
1787 int Idx = CmpI->getOperandUse(0) == LoadU;
1804 bool UsedAssumedInformation =
false;
1805 std::optional<Value *> Content =
nullptr;
1810 return handleAccess(
1811 A, *
Assumption.second, Content, AccessKind::AK_ASSUMPTION,
1812 OffsetInfoMap[CurPtr].Offsets,
Changed, *LoadI->getType());
1817 for (
auto *OtherOp : OtherOps) {
1818 if (OtherOp == CurPtr) {
1821 <<
"[AAPointerInfo] Escaping use in store like instruction " <<
I
1833 bool UsedAssumedInformation =
false;
1834 std::optional<Value *> Content =
nullptr;
1836 Content =
A.getAssumedSimplified(
1838 return handleAccess(
A,
I, Content, AK, OffsetInfoMap[CurPtr].Offsets,
1843 return HandleStoreLike(*StoreI, StoreI->getValueOperand(),
1844 *StoreI->getValueOperand()->getType(),
1845 {StoreI->getValueOperand()}, AccessKind::AK_W);
1847 return HandleStoreLike(*RMWI,
nullptr, *RMWI->getValOperand()->getType(),
1848 {RMWI->getValOperand()}, AccessKind::AK_RW);
1850 return HandleStoreLike(
1851 *CXI,
nullptr, *CXI->getNewValOperand()->getType(),
1852 {CXI->getCompareOperand(), CXI->getNewValOperand()},
1859 A.getInfoCache().getTargetLibraryInfoForFunction(*CB->
getFunction());
1864 const auto *CSArgPI =
A.getAAFor<AAPointerInfo>(
1870 Changed = translateAndAddState(
A, *CSArgPI, OffsetInfoMap[CurPtr], *CB,
1873 if (!CSArgPI->reachesReturn())
1874 return isValidState();
1877 if (!Callee ||
Callee->arg_size() <= ArgNo)
1879 bool UsedAssumedInformation =
false;
1880 auto ReturnedValue =
A.getAssumedSimplified(
1885 auto *Arg =
Callee->getArg(ArgNo);
1886 if (ReturnedArg && Arg != ReturnedArg)
1888 bool IsRetMustAcc = IsArgMustAcc && (ReturnedArg == Arg);
1889 const auto *CSRetPI =
A.getAAFor<AAPointerInfo>(
1893 OffsetInfo OI = OffsetInfoMap[CurPtr];
1894 CSArgPI->addReturnedOffsetsTo(OI);
1896 translateAndAddState(
A, *CSRetPI, OI, *CB, IsRetMustAcc) |
Changed;
1897 return isValidState();
1899 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Call user not handled " << *CB
1904 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] User not handled " << *Usr <<
"\n");
1907 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
1908 assert(OffsetInfoMap.
count(OldU) &&
"Old use should be known already!");
1909 assert(!OffsetInfoMap[OldU].isUnassigned() &&
"Old use should be assinged");
1910 if (OffsetInfoMap.
count(NewU)) {
1912 if (!(OffsetInfoMap[NewU] == OffsetInfoMap[OldU])) {
1913 dbgs() <<
"[AAPointerInfo] Equivalent use callback failed: "
1914 << OffsetInfoMap[NewU] <<
" vs " << OffsetInfoMap[OldU]
1918 return OffsetInfoMap[NewU] == OffsetInfoMap[OldU];
1921 return HandlePassthroughUser(NewU.get(), OldU.
get(), Unused);
1923 if (!
A.checkForAllUses(UsePred, *
this, AssociatedValue,
1925 true, EquivalentUseCB)) {
1926 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Check for all uses failed, abort!\n");
1927 return indicatePessimisticFixpoint();
1931 dbgs() <<
"Accesses by bin after update:\n";
1938struct AAPointerInfoReturned final : AAPointerInfoImpl {
1939 AAPointerInfoReturned(
const IRPosition &IRP, Attributor &
A)
1940 : AAPointerInfoImpl(IRP,
A) {}
1943 return indicatePessimisticFixpoint();
1946 void trackStatistics()
const override {
1947 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1951struct AAPointerInfoArgument final : AAPointerInfoFloating {
1952 AAPointerInfoArgument(
const IRPosition &IRP, Attributor &
A)
1953 : AAPointerInfoFloating(IRP,
A) {}
1955 void trackStatistics()
const override {
1956 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
1960struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
1961 AAPointerInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
1962 : AAPointerInfoFloating(IRP,
A) {}
1965 using namespace AA::PointerInfo;
1971 if (
auto Length =
MI->getLengthInBytes())
1972 LengthVal =
Length->getSExtValue();
1973 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
1976 LLVM_DEBUG(
dbgs() <<
"[AAPointerInfo] Unhandled memory intrinsic "
1978 return indicatePessimisticFixpoint();
1981 ArgNo == 0 ? AccessKind::AK_MUST_WRITE : AccessKind::AK_MUST_READ;
1983 Changed | addAccess(
A, {0, LengthVal}, *
MI,
nullptr,
Kind,
nullptr);
1986 dbgs() <<
"Accesses by bin after update:\n";
1997 Argument *Arg = getAssociatedArgument();
2001 A.getAAFor<AAPointerInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
2002 if (ArgAA && ArgAA->getState().isValidState())
2003 return translateAndAddStateFromCallee(
A, *ArgAA,
2006 return indicatePessimisticFixpoint();
2009 bool IsKnownNoCapture;
2011 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNoCapture))
2012 return indicatePessimisticFixpoint();
2014 bool IsKnown =
false;
2016 return ChangeStatus::UNCHANGED;
2019 ReadOnly ? AccessKind::AK_MAY_READ : AccessKind::AK_MAY_READ_WRITE;
2024 void trackStatistics()
const override {
2025 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2029struct AAPointerInfoCallSiteReturned final : AAPointerInfoFloating {
2030 AAPointerInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2031 : AAPointerInfoFloating(IRP,
A) {}
2033 void trackStatistics()
const override {
2034 AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());
2042struct AANoUnwindImpl : AANoUnwind {
2043 AANoUnwindImpl(
const IRPosition &IRP, Attributor &
A) : AANoUnwind(IRP,
A) {}
2048 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2052 const std::string getAsStr(Attributor *
A)
const override {
2053 return getAssumed() ?
"nounwind" :
"may-unwind";
2058 (unsigned)Instruction::Invoke, (
unsigned)Instruction::CallBr,
2059 (unsigned)Instruction::Call, (
unsigned)Instruction::CleanupRet,
2060 (unsigned)Instruction::CatchSwitch, (
unsigned)Instruction::Resume};
2063 if (!
I.mayThrow(
true))
2067 bool IsKnownNoUnwind;
2075 bool UsedAssumedInformation =
false;
2076 if (!
A.checkForAllInstructions(CheckForNoUnwind, *
this, Opcodes,
2077 UsedAssumedInformation))
2078 return indicatePessimisticFixpoint();
2080 return ChangeStatus::UNCHANGED;
2084struct AANoUnwindFunction final :
public AANoUnwindImpl {
2085 AANoUnwindFunction(
const IRPosition &IRP, Attributor &
A)
2086 : AANoUnwindImpl(IRP,
A) {}
2092struct AANoUnwindCallSite final
2093 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl> {
2094 AANoUnwindCallSite(
const IRPosition &IRP, Attributor &
A)
2095 : AACalleeToCallSite<AANoUnwind, AANoUnwindImpl>(IRP,
A) {}
2105 case Intrinsic::nvvm_barrier_cta_sync_aligned_all:
2106 case Intrinsic::nvvm_barrier_cta_sync_aligned_count:
2107 case Intrinsic::nvvm_barrier_cta_red_and_aligned_all:
2108 case Intrinsic::nvvm_barrier_cta_red_and_aligned_count:
2109 case Intrinsic::nvvm_barrier_cta_red_or_aligned_all:
2110 case Intrinsic::nvvm_barrier_cta_red_or_aligned_count:
2111 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_all:
2112 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_count:
2114 case Intrinsic::amdgcn_s_barrier:
2115 if (ExecutedAligned)
2138 switch (
I->getOpcode()) {
2139 case Instruction::AtomicRMW:
2142 case Instruction::Store:
2145 case Instruction::Load:
2150 "New atomic operations need to be known in the attributor.");
2168 const std::string getAsStr(Attributor *
A)
const override {
2169 return getAssumed() ?
"nosync" :
"may-sync";
2184 if (
I.mayReadOrWriteMemory())
2198 bool UsedAssumedInformation =
false;
2199 if (!
A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *
this,
2200 UsedAssumedInformation) ||
2201 !
A.checkForAllCallLikeInstructions(CheckForNoSync, *
this,
2202 UsedAssumedInformation))
2203 return indicatePessimisticFixpoint();
2208struct AANoSyncFunction final :
public AANoSyncImpl {
2209 AANoSyncFunction(
const IRPosition &IRP, Attributor &
A)
2210 : AANoSyncImpl(IRP,
A) {}
2216struct AANoSyncCallSite final : AACalleeToCallSite<AANoSync, AANoSyncImpl> {
2217 AANoSyncCallSite(
const IRPosition &IRP, Attributor &
A)
2218 : AACalleeToCallSite<AANoSync, AANoSyncImpl>(IRP,
A) {}
2227struct AANoFreeImpl :
public AANoFree {
2228 AANoFreeImpl(
const IRPosition &IRP, Attributor &
A) : AANoFree(IRP,
A) {}
2233 DepClassTy::NONE, IsKnown));
2250 bool UsedAssumedInformation =
false;
2251 if (!
A.checkForAllReadWriteInstructions(CheckForNoFree, *
this,
2252 UsedAssumedInformation) ||
2253 !
A.checkForAllCallLikeInstructions(CheckForNoFree, *
this,
2254 UsedAssumedInformation))
2255 return indicatePessimisticFixpoint();
2257 return ChangeStatus::UNCHANGED;
2260 const std::string getAsStr(Attributor *
A)
const override {
2261 return getAssumed() ?
"nofree" :
"may-free";
2265struct AANoFreeFunction final :
public AANoFreeImpl {
2266 AANoFreeFunction(
const IRPosition &IRP, Attributor &
A)
2267 : AANoFreeImpl(IRP,
A) {}
2273struct AANoFreeCallSite final : AACalleeToCallSite<AANoFree, AANoFreeImpl> {
2274 AANoFreeCallSite(
const IRPosition &IRP, Attributor &
A)
2275 : AACalleeToCallSite<AANoFree, AANoFreeImpl>(IRP,
A) {}
2281struct AANoFreeFloating : AANoFreeImpl {
2282 AANoFreeFloating(
const IRPosition &IRP, Attributor &
A)
2283 : AANoFreeImpl(IRP,
A) {}
2289 const IRPosition &IRP = getIRPosition();
2294 DepClassTy::OPTIONAL, IsKnown))
2295 return ChangeStatus::UNCHANGED;
2297 Value &AssociatedValue = getIRPosition().getAssociatedValue();
2298 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
2313 DepClassTy::REQUIRED, IsKnown))
2316 const AANoCapture *NoCaptureAA =
nullptr;
2319 DepClassTy::REQUIRED, IsKnown,
2320 false, &NoCaptureAA)) {
2345 if (!
A.checkForAllUses(
Pred, *
this, AssociatedValue))
2346 return indicatePessimisticFixpoint();
2348 return ChangeStatus::UNCHANGED;
2353struct AANoFreeArgument final : AANoFreeFloating {
2354 AANoFreeArgument(
const IRPosition &IRP, Attributor &
A)
2355 : AANoFreeFloating(IRP,
A) {}
2361struct AANoFreeCallSiteArgument final : AANoFreeFloating {
2362 AANoFreeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2363 : AANoFreeFloating(IRP,
A) {}
2370 Argument *Arg = getAssociatedArgument();
2372 return indicatePessimisticFixpoint();
2376 DepClassTy::REQUIRED, IsKnown))
2377 return ChangeStatus::UNCHANGED;
2378 return indicatePessimisticFixpoint();
2385struct AANoFreeReturned final : AANoFreeFloating {
2386 AANoFreeReturned(
const IRPosition &IRP, Attributor &
A)
2387 : AANoFreeFloating(IRP,
A) {
2399 void trackStatistics()
const override {}
2403struct AANoFreeCallSiteReturned final : AANoFreeFloating {
2404 AANoFreeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2405 : AANoFreeFloating(IRP,
A) {}
2408 return ChangeStatus::UNCHANGED;
2418 bool IgnoreSubsumingPositions) {
2420 AttrKinds.
push_back(Attribute::NonNull);
2423 AttrKinds.
push_back(Attribute::Dereferenceable);
2424 if (
A.hasAttr(IRP, AttrKinds, IgnoreSubsumingPositions, Attribute::NonNull))
2431 if (!Fn->isDeclaration()) {
2441 bool UsedAssumedInformation =
false;
2442 if (!
A.checkForAllInstructions(
2444 Worklist.push_back({*cast<ReturnInst>(I).getReturnValue(), &I});
2448 UsedAssumedInformation,
false,
true))
2460 Attribute::NonNull)});
2465static int64_t getKnownNonNullAndDerefBytesForUse(
2466 Attributor &
A,
const AbstractAttribute &QueryingAA,
Value &AssociatedValue,
2467 const Use *U,
const Instruction *
I,
bool &IsNonNull,
bool &TrackUse) {
2470 const Value *UseV =
U->get();
2491 const DataLayout &
DL =
A.getInfoCache().getDL();
2496 case BundleAttr::NonNull:
2499 case BundleAttr::Dereferenceable: {
2503 return CI->getZExtValue();
2520 bool IsKnownNonNull;
2523 IsNonNull |= IsKnownNonNull;
2526 return DerefAA ? DerefAA->getKnownDereferenceableBytes() : 0;
2530 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
2531 Loc->Size.isScalable() ||
I->isVolatile())
2537 if (
Base &&
Base == &AssociatedValue) {
2538 int64_t DerefBytes = Loc->Size.getValue() +
Offset;
2540 return std::max(int64_t(0), DerefBytes);
2547 int64_t DerefBytes = Loc->Size.getValue();
2549 return std::max(int64_t(0), DerefBytes);
2555struct AANonNullImpl : AANonNull {
2556 AANonNullImpl(
const IRPosition &IRP, Attributor &
A) : AANonNull(IRP,
A) {}
2559 Value &
V = *getAssociatedValue().stripPointerCasts();
2561 indicatePessimisticFixpoint();
2565 if (Instruction *CtxI = getCtxI())
2566 followUsesInMBEC(*
this,
A, getState(), *CtxI);
2570 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
2571 AANonNull::StateType &State) {
2572 bool IsNonNull =
false;
2573 bool TrackUse =
false;
2574 getKnownNonNullAndDerefBytesForUse(
A, *
this, getAssociatedValue(), U,
I,
2575 IsNonNull, TrackUse);
2576 State.setKnown(IsNonNull);
2580 const std::string getAsStr(Attributor *
A)
const override {
2581 return getAssumed() ?
"nonnull" :
"may-null";
2586struct AANonNullFloating :
public AANonNullImpl {
2587 AANonNullFloating(
const IRPosition &IRP, Attributor &
A)
2588 : AANonNullImpl(IRP,
A) {}
2591 auto CheckIRP = [&](
const IRPosition &IRP) {
2592 bool IsKnownNonNull;
2594 A, *
this, IRP, DepClassTy::OPTIONAL, IsKnownNonNull);
2598 bool UsedAssumedInformation =
false;
2599 Value *AssociatedValue = &getAssociatedValue();
2601 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
2606 Values.size() != 1 ||
Values.front().getValue() != AssociatedValue;
2612 return AA::hasAssumedIRAttr<Attribute::NonNull>(
2613 A, this, IRPosition::value(*Op), DepClassTy::OPTIONAL,
2616 return ChangeStatus::UNCHANGED;
2620 DepClassTy::OPTIONAL, IsKnown) &&
2623 DepClassTy::OPTIONAL, IsKnown))
2624 return ChangeStatus::UNCHANGED;
2631 if (AVIRP == getIRPosition() || !CheckIRP(AVIRP))
2632 return indicatePessimisticFixpoint();
2633 return ChangeStatus::UNCHANGED;
2636 for (
const auto &VAC :
Values)
2638 return indicatePessimisticFixpoint();
2640 return ChangeStatus::UNCHANGED;
2647struct AANonNullReturned final
2648 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2649 false, AANonNull::IRAttributeKind, false> {
2650 AANonNullReturned(
const IRPosition &IRP, Attributor &
A)
2651 : AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,
2655 const std::string getAsStr(Attributor *
A)
const override {
2656 return getAssumed() ?
"nonnull" :
"may-null";
2663struct AANonNullArgument final
2664 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
2665 AANonNullArgument(
const IRPosition &IRP, Attributor &
A)
2666 : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP,
A) {}
2671struct AANonNullCallSiteArgument final : AANonNullFloating {
2672 AANonNullCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
2673 : AANonNullFloating(IRP,
A) {}
2679struct AANonNullCallSiteReturned final
2680 : AACalleeToCallSite<AANonNull, AANonNullImpl> {
2681 AANonNullCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
2682 : AACalleeToCallSite<AANonNull, AANonNullImpl>(IRP,
A) {}
2690struct AAMustProgressImpl :
public AAMustProgress {
2691 AAMustProgressImpl(
const IRPosition &IRP, Attributor &
A)
2692 : AAMustProgress(IRP,
A) {}
2697 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2701 const std::string getAsStr(Attributor *
A)
const override {
2702 return getAssumed() ?
"mustprogress" :
"may-not-progress";
2706struct AAMustProgressFunction final : AAMustProgressImpl {
2707 AAMustProgressFunction(
const IRPosition &IRP, Attributor &
A)
2708 : AAMustProgressImpl(IRP,
A) {}
2713 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnown)) {
2715 return indicateOptimisticFixpoint();
2716 return ChangeStatus::UNCHANGED;
2719 auto CheckForMustProgress = [&](AbstractCallSite ACS) {
2721 bool IsKnownMustProgress;
2723 A,
this, IPos, DepClassTy::REQUIRED, IsKnownMustProgress,
2727 bool AllCallSitesKnown =
true;
2728 if (!
A.checkForAllCallSites(CheckForMustProgress, *
this,
2731 return indicatePessimisticFixpoint();
2733 return ChangeStatus::UNCHANGED;
2736 void trackStatistics()
const override {
2742struct AAMustProgressCallSite final : AAMustProgressImpl {
2743 AAMustProgressCallSite(
const IRPosition &IRP, Attributor &
A)
2744 : AAMustProgressImpl(IRP,
A) {}
2752 bool IsKnownMustProgress;
2754 A,
this, FnPos, DepClassTy::REQUIRED, IsKnownMustProgress))
2755 return indicatePessimisticFixpoint();
2756 return ChangeStatus::UNCHANGED;
2759 void trackStatistics()
const override {
2768struct AANoRecurseImpl :
public AANoRecurse {
2769 AANoRecurseImpl(
const IRPosition &IRP, Attributor &
A) : AANoRecurse(IRP,
A) {}
2774 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
2778 const std::string getAsStr(Attributor *
A)
const override {
2779 return getAssumed() ?
"norecurse" :
"may-recurse";
2783struct AANoRecurseFunction final : AANoRecurseImpl {
2784 AANoRecurseFunction(
const IRPosition &IRP, Attributor &
A)
2785 : AANoRecurseImpl(IRP,
A) {}
2790 auto CallSitePred = [&](AbstractCallSite ACS) {
2791 bool IsKnownNoRecurse;
2795 DepClassTy::NONE, IsKnownNoRecurse))
2797 return IsKnownNoRecurse;
2799 bool UsedAssumedInformation =
false;
2800 if (
A.checkForAllCallSites(CallSitePred, *
this,
true,
2801 UsedAssumedInformation)) {
2807 if (!UsedAssumedInformation)
2808 indicateOptimisticFixpoint();
2809 return ChangeStatus::UNCHANGED;
2812 const AAInterFnReachability *EdgeReachability =
2813 A.getAAFor<AAInterFnReachability>(*
this, getIRPosition(),
2814 DepClassTy::REQUIRED);
2815 if (EdgeReachability && EdgeReachability->
canReach(
A, *getAnchorScope()))
2816 return indicatePessimisticFixpoint();
2817 return ChangeStatus::UNCHANGED;
2824struct AANoRecurseCallSite final
2825 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl> {
2826 AANoRecurseCallSite(
const IRPosition &IRP, Attributor &
A)
2827 : AACalleeToCallSite<AANoRecurse, AANoRecurseImpl>(IRP,
A) {}
2836struct AANonConvergentImpl :
public AANonConvergent {
2837 AANonConvergentImpl(
const IRPosition &IRP, Attributor &
A)
2838 : AANonConvergent(IRP,
A) {}
2840 const std::string getAsStr(Attributor *
A)
const override {
2841 return getAssumed() ?
"non-convergent" :
"may-be-convergent";
2845struct AANonConvergentFunction final : AANonConvergentImpl {
2846 AANonConvergentFunction(
const IRPosition &IRP, Attributor &
A)
2847 : AANonConvergentImpl(IRP,
A) {}
2852 auto CalleeIsNotConvergent = [&](
Instruction &Inst) {
2855 if (!Callee ||
Callee->isIntrinsic()) {
2858 if (
Callee->isDeclaration()) {
2859 return !
Callee->hasFnAttribute(Attribute::Convergent);
2861 const auto *ConvergentAA =
A.getAAFor<AANonConvergent>(
2863 return ConvergentAA && ConvergentAA->isAssumedNotConvergent();
2866 bool UsedAssumedInformation =
false;
2867 if (!
A.checkForAllCallLikeInstructions(CalleeIsNotConvergent, *
this,
2868 UsedAssumedInformation)) {
2869 return indicatePessimisticFixpoint();
2871 return ChangeStatus::UNCHANGED;
2875 if (isKnownNotConvergent() &&
2876 A.hasAttr(getIRPosition(), Attribute::Convergent)) {
2877 A.removeAttrs(getIRPosition(), {Attribute::Convergent});
2878 return ChangeStatus::CHANGED;
2880 return ChangeStatus::UNCHANGED;
2890struct AAUndefinedBehaviorImpl :
public AAUndefinedBehavior {
2891 AAUndefinedBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
2892 : AAUndefinedBehavior(IRP,
A) {}
2898 UndefBranchCondition,
2900 NullReturnViolatesNonNull,
2902 NullArgViolatesNonNull,
2906 std::optional<unsigned> ArgNo;
2908 UBInfo(Kind K) :
K(
K), ArgNo(std::nullopt) {}
2910 UBInfo(Kind K, std::optional<unsigned> ArgNo) :
K(
K), ArgNo(ArgNo) {}
2914 const size_t UBPrevSize = KnownUBInsts.size();
2915 const size_t NoUBPrevSize = AssumedNoUBInsts.size();
2923 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
2932 "Expected pointer operand of memory accessing instruction");
2936 std::optional<Value *> SimplifiedPtrOp =
2937 stopOnUndefOrAssumed(
A, PtrOp, &
I, UBInfo::UndefPtrAccess);
2938 if (!SimplifiedPtrOp || !*SimplifiedPtrOp)
2940 const Value *PtrOpVal = *SimplifiedPtrOp;
2946 AssumedNoUBInsts.insert(&
I);
2958 AssumedNoUBInsts.insert(&
I);
2960 KnownUBInsts.try_emplace(&
I, UBInfo::NullPtrAccess);
2969 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
2977 std::optional<Value *> SimplifiedCond = stopOnUndefOrAssumed(
2978 A, BrInst->getCondition(), BrInst, UBInfo::UndefBranchCondition);
2979 if (!SimplifiedCond || !*SimplifiedCond)
2981 AssumedNoUBInsts.insert(&
I);
2989 if (AssumedNoUBInsts.count(&
I) || KnownUBInsts.count(&
I))
2998 for (
unsigned idx = 0; idx < CB.
arg_size(); idx++) {
3004 if (idx >=
Callee->arg_size())
3016 bool IsKnownNoUndef;
3018 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNoUndef);
3019 if (!IsKnownNoUndef)
3021 bool UsedAssumedInformation =
false;
3022 std::optional<Value *> SimplifiedVal =
3025 if (UsedAssumedInformation)
3027 if (SimplifiedVal && !*SimplifiedVal)
3030 KnownUBInsts.try_emplace(&
I, UBInfo(UBInfo::UndefCallArgument, idx));
3036 bool IsKnownNonNull;
3038 A,
this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNonNull);
3040 KnownUBInsts.try_emplace(&
I,
3041 UBInfo(UBInfo::NullArgViolatesNonNull, idx));
3050 std::optional<Value *> SimplifiedRetValue = stopOnUndefOrAssumed(
3051 A, RI.getReturnValue(), &
I, UBInfo::UndefReturnValue);
3052 if (!SimplifiedRetValue || !*SimplifiedRetValue)
3070 bool IsKnownNonNull;
3075 KnownUBInsts.try_emplace(&
I, UBInfo::NullReturnViolatesNonNull);
3081 bool UsedAssumedInformation =
false;
3082 A.checkForAllInstructions(InspectMemAccessInstForUB, *
this,
3083 {Instruction::Load, Instruction::Store,
3084 Instruction::AtomicCmpXchg,
3085 Instruction::AtomicRMW},
3086 UsedAssumedInformation,
3088 A.checkForAllInstructions(InspectBrInstForUB, *
this, {Instruction::CondBr},
3089 UsedAssumedInformation,
3091 A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *
this,
3092 UsedAssumedInformation);
3096 if (!getAnchorScope()->getReturnType()->isVoidTy()) {
3098 if (!
A.isAssumedDead(ReturnIRP,
this,
nullptr, UsedAssumedInformation)) {
3099 bool IsKnownNoUndef;
3101 A,
this, ReturnIRP, DepClassTy::NONE, IsKnownNoUndef);
3103 A.checkForAllInstructions(InspectReturnInstForUB, *
this,
3104 {Instruction::Ret}, UsedAssumedInformation,
3109 if (NoUBPrevSize != AssumedNoUBInsts.size() ||
3110 UBPrevSize != KnownUBInsts.size())
3111 return ChangeStatus::CHANGED;
3112 return ChangeStatus::UNCHANGED;
3115 bool isKnownToCauseUB(Instruction *
I)
const override {
3116 return KnownUBInsts.count(
I);
3119 bool isAssumedToCauseUB(Instruction *
I)
const override {
3126 switch (
I->getOpcode()) {
3127 case Instruction::Load:
3128 case Instruction::Store:
3129 case Instruction::AtomicCmpXchg:
3130 case Instruction::AtomicRMW:
3131 case Instruction::CondBr:
3132 return !AssumedNoUBInsts.count(
I);
3141 static void emitUBRemark(Attributor &
A, Instruction *
I,
const UBInfo &Info) {
3142 auto Remark = [&](OptimizationRemark
OR) {
3144 case UBInfo::NullPtrAccess:
3145 case UBInfo::UndefPtrAccess: {
3146 return OR <<
"Memory access through a pointer known to be "
3149 <<
" is undefined behavior; replacing with 'unreachable'.";
3151 case UBInfo::UndefBranchCondition:
3152 return OR <<
"Branch condition known to be "
3154 <<
" is undefined behavior; replacing with 'unreachable'.";
3155 case UBInfo::UndefReturnValue:
3156 case UBInfo::NullReturnViolatesNonNull:
3157 return OR <<
"Value returned known to be "
3160 <<
" is undefined behavior; replacing with 'unreachable'.";
3161 case UBInfo::UndefCallArgument:
3162 case UBInfo::NullArgViolatesNonNull: {
3163 bool IsUndef =
Info.K == UBInfo::UndefCallArgument;
3166 <<
" passed to parameter of ";
3171 return OR <<
" known to be "
3172 <<
ore::NV(
"Argument", IsUndef ?
"undef" :
"null")
3173 <<
" is undefined behavior; replacing with 'unreachable'.";
3178 A.emitRemark<OptimizationRemark>(
I,
"UndefinedBehavior",
Remark);
3182 if (KnownUBInsts.empty())
3183 return ChangeStatus::UNCHANGED;
3184 for (
const auto &[
I, Info] : KnownUBInsts) {
3185 emitUBRemark(
A,
I, Info);
3186 A.changeToUnreachableAfterManifest(
I);
3188 return ChangeStatus::CHANGED;
3191 const std::string getAsStr(Attributor *
A)
const override {
3192 return getAssumed() ?
"undefined-behavior" :
"no-ub";
3221 MapVector<Instruction *, UBInfo> KnownUBInsts;
3225 SmallPtrSet<Instruction *, 8> AssumedNoUBInsts;
3236 std::optional<Value *> stopOnUndefOrAssumed(Attributor &
A,
Value *
V,
3237 Instruction *
I, UBInfo::Kind K) {
3238 bool UsedAssumedInformation =
false;
3239 std::optional<Value *> SimplifiedV =
3242 if (!UsedAssumedInformation) {
3247 KnownUBInsts.try_emplace(
I, K);
3248 return std::nullopt;
3255 KnownUBInsts.try_emplace(
I, K);
3256 return std::nullopt;
3262struct AAUndefinedBehaviorFunction final : AAUndefinedBehaviorImpl {
3263 AAUndefinedBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
3264 : AAUndefinedBehaviorImpl(IRP,
A) {}
3266 void trackStatistics()
const override {
3267 STATS_DECL(UndefinedBehaviorInstruction, Instruction,
3268 "Number of instructions known to have UB");
3270 KnownUBInsts.size();
3281static bool mayContainUnboundedCycle(
Function &
F, Attributor &
A) {
3282 ScalarEvolution *SE =
3283 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
F);
3284 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
F);
3290 for (scc_iterator<Function *> SCCI =
scc_begin(&
F); !SCCI.isAtEnd(); ++SCCI)
3291 if (SCCI.hasCycle())
3301 for (
auto *L : LI->getLoopsInPreorder()) {
3308struct AAWillReturnImpl :
public AAWillReturn {
3309 AAWillReturnImpl(
const IRPosition &IRP, Attributor &
A)
3310 : AAWillReturn(IRP,
A) {}
3315 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
3320 bool isImpliedByMustprogressAndReadonly(Attributor &
A,
bool KnownOnly) {
3321 if (!
A.hasAttr(getIRPosition(), {Attribute::MustProgress}))
3326 return IsKnown || !KnownOnly;
3331 if (isImpliedByMustprogressAndReadonly(
A,
false))
3332 return ChangeStatus::UNCHANGED;
3338 A,
this, IPos, DepClassTy::REQUIRED, IsKnown)) {
3344 bool IsKnownNoRecurse;
3346 A,
this, IPos, DepClassTy::REQUIRED, IsKnownNoRecurse);
3349 bool UsedAssumedInformation =
false;
3350 if (!
A.checkForAllCallLikeInstructions(CheckForWillReturn, *
this,
3351 UsedAssumedInformation))
3352 return indicatePessimisticFixpoint();
3356 return !
I.isVolatile();
3358 if (!
A.checkForAllInstructions(CheckForVolatile, *
this,
3359 {Instruction::Load, Instruction::Store,
3360 Instruction::AtomicCmpXchg,
3361 Instruction::AtomicRMW},
3362 UsedAssumedInformation))
3363 return indicatePessimisticFixpoint();
3365 return ChangeStatus::UNCHANGED;
3368 const std::string getAsStr(Attributor *
A)
const override {
3369 return getAssumed() ?
"willreturn" :
"may-noreturn";
3373struct AAWillReturnFunction final : AAWillReturnImpl {
3374 AAWillReturnFunction(
const IRPosition &IRP, Attributor &
A)
3375 : AAWillReturnImpl(IRP,
A) {}
3378 AAWillReturnImpl::initialize(
A);
3381 assert(
F &&
"Did expect an anchor function");
3382 if (
F->isDeclaration() || mayContainUnboundedCycle(*
F,
A))
3383 indicatePessimisticFixpoint();
3390struct AAWillReturnCallSite final
3391 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl> {
3392 AAWillReturnCallSite(
const IRPosition &IRP, Attributor &
A)
3393 : AACalleeToCallSite<AAWillReturn, AAWillReturnImpl>(IRP,
A) {}
3396 if (isImpliedByMustprogressAndReadonly(
A,
false))
3397 return ChangeStatus::UNCHANGED;
3399 return AACalleeToCallSite::updateImpl(
A);
3420 const ToTy *
To =
nullptr;
3447 if (!ES || ES->
empty()) {
3448 ExclusionSet = nullptr;
3449 }
else if (MakeUnique) {
3450 ExclusionSet =
A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ES);
3468 if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))
3470 return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);
3478template <
typename BaseTy,
typename ToTy>
3479struct CachedReachabilityAA :
public BaseTy {
3480 using RQITy = ReachabilityQueryInfo<ToTy>;
3482 CachedReachabilityAA(
const IRPosition &IRP, Attributor &
A) : BaseTy(IRP,
A) {}
3484 bool isQueryAA()
const override {
return true; }
3488 for (
unsigned u = 0, e = QueryVector.size(); u < e; ++u) {
3489 RQITy *RQI = QueryVector[
u];
3490 if (RQI->Result == RQITy::Reachable::No &&
3492 Changed = ChangeStatus::CHANGED;
3498 bool IsTemporaryRQI) = 0;
3500 bool rememberResult(Attributor &
A,
typename RQITy::Reachable Result,
3501 RQITy &RQI,
bool UsedExclusionSet,
bool IsTemporaryRQI) {
3506 QueryCache.erase(&RQI);
3512 if (Result == RQITy::Reachable::Yes || !UsedExclusionSet) {
3513 RQITy PlainRQI(RQI.From, RQI.To);
3514 if (!QueryCache.count(&PlainRQI)) {
3515 RQITy *RQIPtr =
new (
A.Allocator) RQITy(RQI.From, RQI.To);
3517 QueryVector.push_back(RQIPtr);
3518 QueryCache.insert(RQIPtr);
3523 if (IsTemporaryRQI && Result != RQITy::Reachable::Yes && UsedExclusionSet) {
3524 assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&
3525 "Did not expect empty set!");
3526 RQITy *RQIPtr =
new (
A.Allocator)
3527 RQITy(
A, *RQI.From, *RQI.To, RQI.ExclusionSet,
true);
3528 assert(RQIPtr->Result == RQITy::Reachable::No &&
"Already reachable?");
3530 assert(!QueryCache.count(RQIPtr));
3531 QueryVector.push_back(RQIPtr);
3532 QueryCache.insert(RQIPtr);
3535 if (Result == RQITy::Reachable::No && IsTemporaryRQI)
3536 A.registerForUpdate(*
this);
3537 return Result == RQITy::Reachable::Yes;
3540 const std::string getAsStr(Attributor *
A)
const override {
3542 return "#queries(" + std::to_string(QueryVector.size()) +
")";
3545 bool checkQueryCache(Attributor &
A, RQITy &StackRQI,
3546 typename RQITy::Reachable &Result) {
3547 if (!this->getState().isValidState()) {
3548 Result = RQITy::Reachable::Yes;
3554 if (StackRQI.ExclusionSet) {
3555 RQITy PlainRQI(StackRQI.From, StackRQI.To);
3556 auto It = QueryCache.find(&PlainRQI);
3557 if (It != QueryCache.end() && (*It)->Result == RQITy::Reachable::No) {
3558 Result = RQITy::Reachable::No;
3563 auto It = QueryCache.find(&StackRQI);
3564 if (It != QueryCache.end()) {
3571 QueryCache.insert(&StackRQI);
3577 DenseSet<RQITy *> QueryCache;
3580struct AAIntraFnReachabilityFunction final
3581 :
public CachedReachabilityAA<AAIntraFnReachability, Instruction> {
3582 using Base = CachedReachabilityAA<AAIntraFnReachability, Instruction>;
3583 AAIntraFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
3585 DT =
A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(
3589 bool isAssumedReachable(
3590 Attributor &
A,
const Instruction &From,
const Instruction &To,
3592 auto *NonConstThis =
const_cast<AAIntraFnReachabilityFunction *
>(
this);
3596 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
3598 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
3599 return NonConstThis->isReachableImpl(
A, StackRQI,
3601 return Result == RQITy::Reachable::Yes;
3608 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3611 [&](
const auto &DeadEdge) {
3612 return LivenessAA->isEdgeDead(DeadEdge.first,
3616 return LivenessAA->isAssumedDead(BB);
3618 return ChangeStatus::UNCHANGED;
3622 return Base::updateImpl(
A);
3626 bool IsTemporaryRQI)
override {
3628 bool UsedExclusionSet =
false;
3633 while (IP && IP != &To) {
3634 if (ExclusionSet && IP != Origin && ExclusionSet->
count(IP)) {
3635 UsedExclusionSet =
true;
3643 const BasicBlock *FromBB = RQI.From->getParent();
3644 const BasicBlock *ToBB = RQI.To->getParent();
3646 "Not an intra-procedural query!");
3650 if (FromBB == ToBB &&
3651 WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
3652 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3657 if (!WillReachInBlock(ToBB->
front(), *RQI.To, RQI.ExclusionSet))
3658 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3662 SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
3663 if (RQI.ExclusionSet)
3664 for (
auto *
I : *RQI.ExclusionSet)
3665 if (
I->getFunction() == Fn)
3666 ExclusionBlocks.
insert(
I->getParent());
3669 if (ExclusionBlocks.
count(FromBB) &&
3672 return rememberResult(
A, RQITy::Reachable::No, RQI,
true, IsTemporaryRQI);
3675 A.getAAFor<AAIsDead>(*
this, getIRPosition(), DepClassTy::OPTIONAL);
3676 if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {
3677 DeadBlocks.insert(ToBB);
3678 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3682 SmallPtrSet<const BasicBlock *, 16> Visited;
3686 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> LocalDeadEdges;
3687 while (!Worklist.
empty()) {
3689 if (!Visited.
insert(BB).second)
3691 for (
const BasicBlock *SuccBB :
successors(BB)) {
3692 if (LivenessAA && LivenessAA->isEdgeDead(BB, SuccBB)) {
3693 LocalDeadEdges.
insert({BB, SuccBB});
3698 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3701 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
3704 if (ExclusionBlocks.
count(SuccBB)) {
3705 UsedExclusionSet =
true;
3712 DeadEdges.insert_range(LocalDeadEdges);
3713 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
3717 void trackStatistics()
const override {}
3722 DenseSet<const BasicBlock *> DeadBlocks;
3726 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> DeadEdges;
3729 const DominatorTree *DT =
nullptr;
3737 bool IgnoreSubsumingPositions) {
3738 assert(ImpliedAttributeKind == Attribute::NoAlias &&
3739 "Unexpected attribute kind");
3745 IgnoreSubsumingPositions =
true;
3756 if (
A.hasAttr(IRP, {Attribute::ByVal, Attribute::NoAlias},
3757 IgnoreSubsumingPositions, Attribute::NoAlias))
3767 "Noalias is a pointer attribute");
3770 const std::string getAsStr(
Attributor *
A)
const override {
3771 return getAssumed() ?
"noalias" :
"may-alias";
3776struct AANoAliasFloating final : AANoAliasImpl {
3777 AANoAliasFloating(
const IRPosition &IRP, Attributor &
A)
3778 : AANoAliasImpl(IRP,
A) {}
3782 return indicatePessimisticFixpoint();
3785 void trackStatistics()
const override {
3791struct AANoAliasArgument final
3792 : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> {
3793 using Base = AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>;
3794 AANoAliasArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
3806 DepClassTy::OPTIONAL, IsKnownNoSycn))
3807 return Base::updateImpl(
A);
3812 return Base::updateImpl(
A);
3816 bool UsedAssumedInformation =
false;
3817 if (
A.checkForAllCallSites(
3818 [](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *
this,
3819 true, UsedAssumedInformation))
3820 return Base::updateImpl(
A);
3828 return indicatePessimisticFixpoint();
3834struct AANoAliasCallSiteArgument final : AANoAliasImpl {
3835 AANoAliasCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
3836 : AANoAliasImpl(IRP,
A) {}
3840 bool mayAliasWithArgument(Attributor &
A, AAResults *&AAR,
3841 const AAMemoryBehavior &MemBehaviorAA,
3842 const CallBase &CB,
unsigned OtherArgNo) {
3844 if (this->getCallSiteArgNo() == (
int)OtherArgNo)
3852 auto *CBArgMemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
3856 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadNone()) {
3857 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3864 if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadOnly() &&
3866 A.recordDependence(MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3867 A.recordDependence(*CBArgMemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3873 AAR =
A.getInfoCache().getAnalysisResultForFunction<AAManager>(
3877 bool IsAliasing = !AAR || !AAR->
isNoAlias(&getAssociatedValue(), ArgOp);
3879 "callsite arguments: "
3880 << getAssociatedValue() <<
" " << *ArgOp <<
" => "
3881 << (IsAliasing ?
"" :
"no-") <<
"alias \n");
3886 bool isKnownNoAliasDueToNoAliasPreservation(
3887 Attributor &
A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA) {
3900 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
3916 bool IsKnownNoCapture;
3919 DepClassTy::OPTIONAL, IsKnownNoCapture))
3925 A, *UserI, *getCtxI(), *
this,
nullptr,
3926 [ScopeFn](
const Function &Fn) {
return &Fn != ScopeFn; }))
3941 LLVM_DEBUG(
dbgs() <<
"[AANoAliasCSArg] Unknown user: " << *UserI <<
"\n");
3945 bool IsKnownNoCapture;
3946 const AANoCapture *NoCaptureAA =
nullptr;
3948 A,
this, VIRP, DepClassTy::NONE, IsKnownNoCapture,
false, &NoCaptureAA);
3949 if (!IsAssumedNoCapture &&
3951 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue())) {
3953 dbgs() <<
"[AANoAliasCSArg] " << getAssociatedValue()
3954 <<
" cannot be noalias as it is potentially captured\n");
3959 A.recordDependence(*NoCaptureAA, *
this, DepClassTy::OPTIONAL);
3965 for (
unsigned OtherArgNo = 0; OtherArgNo < CB.
arg_size(); OtherArgNo++)
3966 if (mayAliasWithArgument(
A, AAR, MemBehaviorAA, CB, OtherArgNo))
3975 auto *MemBehaviorAA =
3976 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
3978 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
3979 return ChangeStatus::UNCHANGED;
3982 bool IsKnownNoAlias;
3985 A,
this, VIRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
3987 <<
" is not no-alias at the definition\n");
3988 return indicatePessimisticFixpoint();
3991 AAResults *AAR =
nullptr;
3992 if (MemBehaviorAA &&
3993 isKnownNoAliasDueToNoAliasPreservation(
A, AAR, *MemBehaviorAA)) {
3995 dbgs() <<
"[AANoAlias] No-Alias deduced via no-alias preservation\n");
3996 return ChangeStatus::UNCHANGED;
3999 return indicatePessimisticFixpoint();
4006struct AANoAliasReturned final : AANoAliasImpl {
4007 AANoAliasReturned(
const IRPosition &IRP, Attributor &
A)
4008 : AANoAliasImpl(IRP,
A) {}
4012 auto CheckReturnValue = [&](
Value &RV) ->
bool {
4023 bool IsKnownNoAlias;
4025 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoAlias))
4028 bool IsKnownNoCapture;
4029 const AANoCapture *NoCaptureAA =
nullptr;
4031 A,
this, RVPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
4033 return IsAssumedNoCapture ||
4037 if (!
A.checkForAllReturnedValues(CheckReturnValue, *
this))
4038 return indicatePessimisticFixpoint();
4040 return ChangeStatus::UNCHANGED;
4047struct AANoAliasCallSiteReturned final
4048 : AACalleeToCallSite<AANoAlias, AANoAliasImpl> {
4049 AANoAliasCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4050 : AACalleeToCallSite<AANoAlias, AANoAliasImpl>(IRP,
A) {}
4059struct AAIsDeadValueImpl :
public AAIsDead {
4060 AAIsDeadValueImpl(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4062 bool isAssumedDead()
const override {
return isAssumed(IS_DEAD); }
4064 bool isKnownDead()
const override {
return isKnown(IS_DEAD); }
4066 bool isAssumedDead(
const BasicBlock *BB)
const override {
return false; }
4068 bool isKnownDead(
const BasicBlock *BB)
const override {
return false; }
4070 bool isAssumedDead(
const Instruction *
I)
const override {
4071 return I == getCtxI() && isAssumedDead();
4074 bool isKnownDead(
const Instruction *
I)
const override {
4075 return isAssumedDead(
I) && isKnownDead();
4078 const std::string getAsStr(Attributor *
A)
const override {
4079 return isAssumedDead() ?
"assumed-dead" :
"assumed-live";
4083 bool areAllUsesAssumedDead(Attributor &
A,
Value &
V) {
4085 if (
V.getType()->isVoidTy() ||
V.use_empty())
4091 if (!
A.isRunOn(*
I->getFunction()))
4093 bool UsedAssumedInformation =
false;
4094 std::optional<Constant *>
C =
4095 A.getAssumedConstant(
V, *
this, UsedAssumedInformation);
4100 auto UsePred = [&](
const Use &
U,
bool &Follow) {
return false; };
4105 return A.checkForAllUses(UsePred, *
this,
V,
false,
4106 DepClassTy::REQUIRED,
4111 bool isAssumedSideEffectFree(Attributor &
A, Instruction *
I) {
4115 if (!
I->isTerminator() && !
I->mayHaveSideEffects())
4124 bool IsKnownNoUnwind;
4126 A,
this, CallIRP, DepClassTy::OPTIONAL, IsKnownNoUnwind))
4134struct AAIsDeadFloating :
public AAIsDeadValueImpl {
4135 AAIsDeadFloating(
const IRPosition &IRP, Attributor &
A)
4136 : AAIsDeadValueImpl(IRP,
A) {}
4139 AAIsDeadValueImpl::initialize(
A);
4142 indicatePessimisticFixpoint();
4147 if (!isAssumedSideEffectFree(
A,
I)) {
4149 indicatePessimisticFixpoint();
4151 removeAssumedBits(HAS_NO_EFFECT);
4155 bool isDeadFence(Attributor &
A, FenceInst &FI) {
4156 const auto *ExecDomainAA =
A.lookupAAFor<AAExecutionDomain>(
4158 if (!ExecDomainAA || !ExecDomainAA->isNoOpFence(FI))
4160 A.recordDependence(*ExecDomainAA, *
this, DepClassTy::OPTIONAL);
4164 bool isDeadStore(Attributor &
A, StoreInst &SI,
4165 SmallSetVector<Instruction *, 8> *AssumeOnlyInst =
nullptr) {
4167 if (
SI.isVolatile())
4173 bool UsedAssumedInformation =
false;
4174 if (!AssumeOnlyInst) {
4175 PotentialCopies.clear();
4177 UsedAssumedInformation)) {
4180 <<
"[AAIsDead] Could not determine potential copies of store!\n");
4184 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Store has " << PotentialCopies.size()
4185 <<
" potential copies.\n");
4187 InformationCache &InfoCache =
A.getInfoCache();
4190 UsedAssumedInformation))
4194 auto &UserI = cast<Instruction>(*U.getUser());
4195 if (InfoCache.isOnlyUsedByAssume(UserI)) {
4197 AssumeOnlyInst->insert(&UserI);
4200 return A.isAssumedDead(U,
this,
nullptr, UsedAssumedInformation);
4206 <<
" is assumed live!\n");
4211 const std::string getAsStr(Attributor *
A)
const override {
4215 return "assumed-dead-store";
4218 return "assumed-dead-fence";
4219 return AAIsDeadValueImpl::getAsStr(
A);
4225 if (!isDeadStore(
A, *SI))
4226 return indicatePessimisticFixpoint();
4228 if (!isDeadFence(
A, *FI))
4229 return indicatePessimisticFixpoint();
4231 if (!isAssumedSideEffectFree(
A,
I))
4232 return indicatePessimisticFixpoint();
4233 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4234 return indicatePessimisticFixpoint();
4239 bool isRemovableStore()
const override {
4240 return isAssumed(IS_REMOVABLE) &&
isa<StoreInst>(&getAssociatedValue());
4244 Value &
V = getAssociatedValue();
4251 SmallSetVector<Instruction *, 8> AssumeOnlyInst;
4252 bool IsDead = isDeadStore(
A, *SI, &AssumeOnlyInst);
4255 A.deleteAfterManifest(*
I);
4256 for (
size_t i = 0; i < AssumeOnlyInst.
size(); ++i) {
4258 for (
auto *Usr : AOI->
users())
4260 A.deleteAfterManifest(*AOI);
4266 A.deleteAfterManifest(*FI);
4269 if (isAssumedSideEffectFree(
A,
I) && !
I->isTerminator()) {
4270 A.deleteAfterManifest(*
I);
4277 void trackStatistics()
const override {
4283 SmallSetVector<Value *, 4> PotentialCopies;
4286struct AAIsDeadArgument :
public AAIsDeadFloating {
4287 AAIsDeadArgument(
const IRPosition &IRP, Attributor &
A)
4288 : AAIsDeadFloating(IRP,
A) {}
4291 Argument &Arg = *getAssociatedArgument();
4292 if (
A.isValidFunctionSignatureRewrite(Arg, {}))
4293 if (
A.registerFunctionSignatureRewrite(
4297 return ChangeStatus::CHANGED;
4299 return ChangeStatus::UNCHANGED;
4305struct AAIsDeadCallSiteArgument :
public AAIsDeadValueImpl {
4306 AAIsDeadCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
4307 : AAIsDeadValueImpl(IRP,
A) {}
4310 AAIsDeadValueImpl::initialize(
A);
4312 indicatePessimisticFixpoint();
4320 Argument *Arg = getAssociatedArgument();
4322 return indicatePessimisticFixpoint();
4324 auto *ArgAA =
A.getAAFor<AAIsDead>(*
this, ArgPos, DepClassTy::REQUIRED);
4326 return indicatePessimisticFixpoint();
4334 "Expected undef values to be filtered out!");
4336 if (
A.changeUseAfterManifest(U, UV))
4337 return ChangeStatus::CHANGED;
4338 return ChangeStatus::UNCHANGED;
4344struct AAIsDeadCallSiteReturned :
public AAIsDeadFloating {
4345 AAIsDeadCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
4346 : AAIsDeadFloating(IRP,
A) {}
4348 bool isAssumedDead()
const override {
4349 return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;
4353 AAIsDeadFloating::initialize(
A);
4355 indicatePessimisticFixpoint();
4360 IsAssumedSideEffectFree = isAssumedSideEffectFree(
A, getCtxI());
4365 if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(
A, getCtxI())) {
4366 IsAssumedSideEffectFree =
false;
4367 Changed = ChangeStatus::CHANGED;
4369 if (!areAllUsesAssumedDead(
A, getAssociatedValue()))
4370 return indicatePessimisticFixpoint();
4374 void trackStatistics()
const override {
4375 if (IsAssumedSideEffectFree)
4381 const std::string getAsStr(Attributor *
A)
const override {
4382 return isAssumedDead()
4384 : (getAssumed() ?
"assumed-dead-users" :
"assumed-live");
4388 bool IsAssumedSideEffectFree =
true;
4391struct AAIsDeadReturned :
public AAIsDeadValueImpl {
4392 AAIsDeadReturned(
const IRPosition &IRP, Attributor &
A)
4393 : AAIsDeadValueImpl(IRP,
A) {}
4397 bool UsedAssumedInformation =
false;
4398 A.checkForAllInstructions([](Instruction &) {
return true; }, *
this,
4399 {Instruction::Ret}, UsedAssumedInformation);
4401 auto PredForCallSite = [&](AbstractCallSite ACS) {
4402 if (ACS.isCallbackCall() || !ACS.getInstruction())
4404 return areAllUsesAssumedDead(
A, *ACS.getInstruction());
4407 if (!
A.checkForAllCallSites(PredForCallSite, *
this,
true,
4408 UsedAssumedInformation))
4409 return indicatePessimisticFixpoint();
4411 return ChangeStatus::UNCHANGED;
4416 bool AnyChange =
false;
4417 UndefValue &UV = *
UndefValue::get(getAssociatedFunction()->getReturnType());
4424 bool UsedAssumedInformation =
false;
4425 A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
4426 UsedAssumedInformation);
4427 return AnyChange ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
4433struct AAIsDeadFunction :
public AAIsDead {
4434 AAIsDeadFunction(
const IRPosition &IRP, Attributor &
A) : AAIsDead(IRP,
A) {}
4438 assert(
F &&
"Did expect an anchor function");
4439 if (!isAssumedDeadInternalFunction(
A)) {
4440 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4441 assumeLive(
A,
F->getEntryBlock());
4445 bool isAssumedDeadInternalFunction(Attributor &
A) {
4446 if (!getAnchorScope()->hasLocalLinkage())
4452 if (!
A.shouldUpdateAA<AAIsDead>(getIRPosition()))
4454 bool UsedAssumedInformation =
false;
4455 return A.checkForAllCallSites([](AbstractCallSite) {
return false; }, *
this,
4456 true, UsedAssumedInformation);
4459 const std::string getAsStr(Attributor *
A)
const override {
4460 return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) +
"/" +
4461 std::to_string(getAnchorScope()->
size()) +
"][#TBEP " +
4462 std::to_string(ToBeExploredFrom.size()) +
"][#KDE " +
4463 std::to_string(KnownDeadEnds.size()) +
"]";
4467 assert(getState().isValidState() &&
4468 "Attempted to manifest an invalid state!");
4473 if (AssumedLiveBlocks.empty()) {
4474 A.deleteAfterManifest(
F);
4475 return ChangeStatus::CHANGED;
4481 bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(
F);
4483 KnownDeadEnds.set_union(ToBeExploredFrom);
4484 for (
const Instruction *DeadEndI : KnownDeadEnds) {
4488 bool IsKnownNoReturn;
4496 A.registerInvokeWithDeadSuccessor(
const_cast<InvokeInst &
>(*
II));
4498 A.changeToUnreachableAfterManifest(
4499 const_cast<Instruction *
>(DeadEndI->getNextNode()));
4500 HasChanged = ChangeStatus::CHANGED;
4503 STATS_DECL(AAIsDead, BasicBlock,
"Number of dead basic blocks deleted.");
4504 for (BasicBlock &BB :
F)
4505 if (!AssumedLiveBlocks.count(&BB)) {
4506 A.deleteAfterManifest(BB);
4508 HasChanged = ChangeStatus::CHANGED;
4516 bool isEdgeDead(
const BasicBlock *From,
const BasicBlock *To)
const override {
4519 "Used AAIsDead of the wrong function");
4520 return isValidState() && !AssumedLiveEdges.count(std::make_pair(From, To));
4523 void trackStatistics()
const override {}
4526 bool isAssumedDead()
const override {
return false; }
4528 bool isKnownDead()
const override {
return false; }
4530 bool isAssumedDead(
const BasicBlock *BB)
const override {
4532 "BB must be in the same anchor scope function.");
4536 return !AssumedLiveBlocks.count(BB);
4539 bool isKnownDead(
const BasicBlock *BB)
const override {
4540 return getKnown() && isAssumedDead(BB);
4543 bool isAssumedDead(
const Instruction *
I)
const override {
4544 assert(
I->getParent()->getParent() == getAnchorScope() &&
4545 "Instruction must be in the same anchor scope function.");
4552 if (!AssumedLiveBlocks.count(
I->getParent()))
4558 if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))
4565 bool isKnownDead(
const Instruction *
I)
const override {
4566 return getKnown() && isAssumedDead(
I);
4571 bool assumeLive(Attributor &
A,
const BasicBlock &BB) {
4572 if (!AssumedLiveBlocks.insert(&BB).second)
4575 if (!
A.isDuringDeduction())
4582 for (
const Instruction &
I : BB)
4585 if (
F->hasLocalLinkage()) {
4587 dbgs() <<
"[AAIsDead] Seeding live internal callee ";
4588 F->printAsOperand(
dbgs(),
false);
4590 BB.getParent()->printAsOperand(
dbgs(),
false);
4593 A.markLiveInternalFunction(*
F);
4600 SmallSetVector<const Instruction *, 8> ToBeExploredFrom;
4603 SmallSetVector<const Instruction *, 8> KnownDeadEnds;
4606 DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> AssumedLiveEdges;
4609 DenseSet<const BasicBlock *> AssumedLiveBlocks;
4613identifyAliveSuccessors(Attributor &
A,
const CallBase &CB,
4614 AbstractAttribute &AA,
4615 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4618 bool IsKnownNoReturn;
4621 return !IsKnownNoReturn;
4630identifyAliveSuccessors(Attributor &
A,
const InvokeInst &
II,
4631 AbstractAttribute &AA,
4632 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4633 bool UsedAssumedInformation =
4639 if (AAIsDeadFunction::mayCatchAsynchronousExceptions(*
II.getFunction())) {
4640 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4644 bool IsKnownNoUnwind;
4647 UsedAssumedInformation |= !IsKnownNoUnwind;
4649 AliveSuccessors.
push_back(&
II.getUnwindDest()->front());
4652 return UsedAssumedInformation;
4656identifyAliveSuccessors(Attributor &,
const UncondBrInst &BI,
4657 AbstractAttribute &,
4658 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4664identifyAliveSuccessors(Attributor &
A,
const CondBrInst &BI,
4665 AbstractAttribute &AA,
4666 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4667 bool UsedAssumedInformation =
false;
4668 std::optional<Constant *>
C =
4669 A.getAssumedConstant(*BI.
getCondition(), AA, UsedAssumedInformation);
4679 UsedAssumedInformation =
false;
4681 return UsedAssumedInformation;
4685identifyAliveSuccessors(Attributor &
A,
const SwitchInst &SI,
4686 AbstractAttribute &AA,
4687 SmallVectorImpl<const Instruction *> &AliveSuccessors) {
4688 bool UsedAssumedInformation =
false;
4692 UsedAssumedInformation)) {
4694 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4703 return UsedAssumedInformation;
4706 Type &Ty = *
SI.getCondition()->getType();
4707 SmallPtrSet<ConstantInt *, 8>
Constants;
4708 auto CheckForConstantInt = [&](
Value *
V) {
4717 return CheckForConstantInt(VAC.
getValue());
4719 for (
const BasicBlock *SuccBB :
successors(
SI.getParent()))
4721 return UsedAssumedInformation;
4724 unsigned MatchedCases = 0;
4725 for (
const auto &CaseIt :
SI.cases()) {
4726 if (
Constants.count(CaseIt.getCaseValue())) {
4728 AliveSuccessors.
push_back(&CaseIt.getCaseSuccessor()->front());
4735 AliveSuccessors.
push_back(&
SI.getDefaultDest()->front());
4736 return UsedAssumedInformation;
4742 if (AssumedLiveBlocks.empty()) {
4743 if (isAssumedDeadInternalFunction(
A))
4747 ToBeExploredFrom.insert(&
F->getEntryBlock().front());
4748 assumeLive(
A,
F->getEntryBlock());
4752 LLVM_DEBUG(
dbgs() <<
"[AAIsDead] Live [" << AssumedLiveBlocks.size() <<
"/"
4753 << getAnchorScope()->
size() <<
"] BBs and "
4754 << ToBeExploredFrom.size() <<
" exploration points and "
4755 << KnownDeadEnds.size() <<
" known dead ends\n");
4760 ToBeExploredFrom.end());
4761 decltype(ToBeExploredFrom) NewToBeExploredFrom;
4764 while (!Worklist.
empty()) {
4771 I =
I->getNextNode();
4773 AliveSuccessors.
clear();
4775 bool UsedAssumedInformation =
false;
4776 switch (
I->getOpcode()) {
4780 "Expected non-terminators to be handled already!");
4781 for (
const BasicBlock *SuccBB :
successors(
I->getParent()))
4784 case Instruction::Call:
4786 *
this, AliveSuccessors);
4788 case Instruction::Invoke:
4790 *
this, AliveSuccessors);
4792 case Instruction::UncondBr:
4793 UsedAssumedInformation = identifyAliveSuccessors(
4796 case Instruction::CondBr:
4798 *
this, AliveSuccessors);
4800 case Instruction::Switch:
4802 *
this, AliveSuccessors);
4806 if (UsedAssumedInformation) {
4807 NewToBeExploredFrom.insert(
I);
4808 }
else if (AliveSuccessors.
empty() ||
4809 (
I->isTerminator() &&
4810 AliveSuccessors.
size() <
I->getNumSuccessors())) {
4811 if (KnownDeadEnds.insert(
I))
4816 << AliveSuccessors.
size() <<
" UsedAssumedInformation: "
4817 << UsedAssumedInformation <<
"\n");
4819 for (
const Instruction *AliveSuccessor : AliveSuccessors) {
4820 if (!
I->isTerminator()) {
4821 assert(AliveSuccessors.size() == 1 &&
4822 "Non-terminator expected to have a single successor!");
4826 auto Edge = std::make_pair(
I->getParent(), AliveSuccessor->getParent());
4827 if (AssumedLiveEdges.insert(
Edge).second)
4829 if (assumeLive(
A, *AliveSuccessor->getParent()))
4836 if (NewToBeExploredFrom.size() != ToBeExploredFrom.size() ||
4837 llvm::any_of(NewToBeExploredFrom, [&](
const Instruction *
I) {
4838 return !ToBeExploredFrom.count(I);
4841 ToBeExploredFrom = std::move(NewToBeExploredFrom);
4850 if (ToBeExploredFrom.empty() &&
4851 getAnchorScope()->
size() == AssumedLiveBlocks.size() &&
4852 llvm::all_of(KnownDeadEnds, [](
const Instruction *DeadEndI) {
4853 return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;
4855 return indicatePessimisticFixpoint();
4860struct AAIsDeadCallSite final : AAIsDeadFunction {
4861 AAIsDeadCallSite(
const IRPosition &IRP, Attributor &
A)
4862 : AAIsDeadFunction(IRP,
A) {}
4870 "supported for call sites yet!");
4874 return indicatePessimisticFixpoint();
4877 void trackStatistics()
const override {}
4884struct AADereferenceableImpl : AADereferenceable {
4885 AADereferenceableImpl(
const IRPosition &IRP, Attributor &
A)
4886 : AADereferenceable(IRP,
A) {}
4887 using StateType = DerefState;
4890 Value &
V = *getAssociatedValue().stripPointerCasts();
4892 A.getAttrs(getIRPosition(),
4893 {Attribute::Dereferenceable, Attribute::DereferenceableOrNull},
4896 takeKnownDerefBytesMaximum(Attr.getValueAsInt());
4899 bool IsKnownNonNull;
4901 A,
this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNonNull);
4904 takeKnownDerefBytesMaximum(
V.getPointerDereferenceableBytes(
4905 A.getDataLayout(), CanBeNull,
nullptr));
4907 if (Instruction *CtxI = getCtxI())
4908 followUsesInMBEC(*
this,
A, getState(), *CtxI);
4911 StateType &getState()
override {
return *
this; }
4912 const StateType &getState()
const override {
return *
this; }
4915 void addAccessedBytesForUse(Attributor &
A,
const Use *U,
const Instruction *
I,
4916 DerefState &State) {
4917 const Value *UseV =
U->get();
4922 if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||
I->isVolatile())
4927 Loc->Ptr,
Offset,
A.getDataLayout(),
true);
4928 if (
Base &&
Base == &getAssociatedValue())
4929 State.addAccessedBytes(
Offset, Loc->Size.getValue());
4933 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
4934 AADereferenceable::StateType &State) {
4935 bool IsNonNull =
false;
4936 bool TrackUse =
false;
4937 int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(
4938 A, *
this, getAssociatedValue(), U,
I, IsNonNull, TrackUse);
4939 LLVM_DEBUG(
dbgs() <<
"[AADereferenceable] Deref bytes: " << DerefBytes
4940 <<
" for instruction " << *
I <<
"\n");
4942 addAccessedBytesForUse(
A, U,
I, State);
4943 State.takeKnownDerefBytesMaximum(DerefBytes);
4949 bool IsKnownNonNull;
4951 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
4952 if (IsAssumedNonNull &&
4953 A.hasAttr(getIRPosition(), Attribute::DereferenceableOrNull)) {
4954 A.removeAttrs(getIRPosition(), {Attribute::DereferenceableOrNull});
4955 return ChangeStatus::CHANGED;
4960 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
4961 SmallVectorImpl<Attribute> &Attrs)
const override {
4963 bool IsKnownNonNull;
4965 A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
4966 if (IsAssumedNonNull)
4967 Attrs.emplace_back(Attribute::getWithDereferenceableBytes(
4968 Ctx, getAssumedDereferenceableBytes()));
4970 Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes(
4971 Ctx, getAssumedDereferenceableBytes()));
4974 const std::string getAsStr(Attributor *
A)
const override {
4975 if (!getAssumedDereferenceableBytes())
4976 return "unknown-dereferenceable";
4977 bool IsKnownNonNull;
4978 bool IsAssumedNonNull =
false;
4981 *
A,
this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);
4982 return std::string(
"dereferenceable") +
4983 (IsAssumedNonNull ?
"" :
"_or_null") +
4984 (isAssumedGlobal() ?
"_globally" :
"") +
"<" +
4985 std::to_string(getKnownDereferenceableBytes()) +
"-" +
4986 std::to_string(getAssumedDereferenceableBytes()) +
">" +
4987 (!
A ?
" [non-null is unknown]" :
"");
4992struct AADereferenceableFloating : AADereferenceableImpl {
4993 AADereferenceableFloating(
const IRPosition &IRP, Attributor &
A)
4994 : AADereferenceableImpl(IRP,
A) {}
4998 bool UsedAssumedInformation =
false;
5000 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
5002 Values.push_back({getAssociatedValue(), getCtxI()});
5005 Stripped =
Values.size() != 1 ||
5006 Values.front().getValue() != &getAssociatedValue();
5009 const DataLayout &
DL =
A.getDataLayout();
5012 auto VisitValueCB = [&](
const Value &
V) ->
bool {
5014 DL.getIndexSizeInBits(
V.getType()->getPointerAddressSpace());
5015 APInt
Offset(IdxWidth, 0);
5020 const auto *AA =
A.getAAFor<AADereferenceable>(
5022 int64_t DerefBytes = 0;
5023 if (!AA || (!Stripped &&
this == AA)) {
5027 DerefBytes =
Base->getPointerDereferenceableBytes(
5028 DL, CanBeNull,
nullptr);
5029 T.GlobalState.indicatePessimisticFixpoint();
5032 DerefBytes =
DS.DerefBytesState.getAssumed();
5033 T.GlobalState &=
DS.GlobalState;
5039 int64_t OffsetSExt =
Offset.getSExtValue();
5043 T.takeAssumedDerefBytesMinimum(
5044 std::max(int64_t(0), DerefBytes - OffsetSExt));
5049 T.takeKnownDerefBytesMaximum(
5050 std::max(int64_t(0), DerefBytes - OffsetSExt));
5051 T.indicatePessimisticFixpoint();
5052 }
else if (OffsetSExt > 0) {
5058 T.indicatePessimisticFixpoint();
5062 return T.isValidState();
5065 for (
const auto &VAC :
Values)
5066 if (!VisitValueCB(*VAC.
getValue()))
5067 return indicatePessimisticFixpoint();
5072 void trackStatistics()
const override {
5078struct AADereferenceableReturned final
5079 : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl> {
5081 AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl>;
5082 AADereferenceableReturned(
const IRPosition &IRP, Attributor &
A)
5085 void trackStatistics()
const override {
5091struct AADereferenceableArgument final
5092 : AAArgumentFromCallSiteArguments<AADereferenceable,
5093 AADereferenceableImpl> {
5095 AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl>;
5096 AADereferenceableArgument(
const IRPosition &IRP, Attributor &
A)
5099 void trackStatistics()
const override {
5105struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {
5106 AADereferenceableCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5107 : AADereferenceableFloating(IRP,
A) {}
5109 void trackStatistics()
const override {
5115struct AADereferenceableCallSiteReturned final
5116 : AACalleeToCallSite<AADereferenceable, AADereferenceableImpl> {
5117 using Base = AACalleeToCallSite<AADereferenceable, AADereferenceableImpl>;
5118 AADereferenceableCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5121 void trackStatistics()
const override {
5131static unsigned getKnownAlignForUse(Attributor &
A, AAAlign &QueryingAA,
5132 Value &AssociatedValue,
const Use *U,
5133 const Instruction *
I,
bool &TrackUse) {
5142 if (
GEP->hasAllConstantIndices())
5147 switch (
II->getIntrinsicID()) {
5148 case Intrinsic::ptrmask: {
5150 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5152 const auto *AlignAA =
A.getAAFor<AAAlign>(
5154 if (ConstVals && ConstVals->isValidState() && ConstVals->isAtFixpoint()) {
5155 unsigned ShiftValue = std::min(ConstVals->getAssumedMinTrailingZeros(),
5158 if (ConstAlign >= AlignAA->getKnownAlign())
5159 return Align(1).value();
5162 return AlignAA->getKnownAlign().
value();
5165 case Intrinsic::amdgcn_make_buffer_rsrc: {
5166 const auto *AlignAA =
A.getAAFor<AAAlign>(
5169 return AlignAA->getKnownAlign().
value();
5187 MA = MaybeAlign(AlignAA->getKnownAlign());
5190 const DataLayout &
DL =
A.getDataLayout();
5191 const Value *UseV =
U->get();
5193 if (
SI->getPointerOperand() == UseV)
5194 MA =
SI->getAlign();
5196 if (LI->getPointerOperand() == UseV)
5197 MA = LI->getAlign();
5199 if (AI->getPointerOperand() == UseV)
5200 MA = AI->getAlign();
5202 if (AI->getPointerOperand() == UseV)
5203 MA = AI->getAlign();
5213 if (
Base == &AssociatedValue) {
5218 uint32_t
gcd = std::gcd(uint32_t(
abs((int32_t)
Offset)), Alignment);
5226struct AAAlignImpl : AAAlign {
5227 AAAlignImpl(
const IRPosition &IRP, Attributor &
A) : AAAlign(IRP,
A) {}
5231 A.getAttrs(getIRPosition(), {Attribute::Alignment},
Attrs);
5233 takeKnownMaximum(Attr.getValueAsInt());
5235 Value &
V = *getAssociatedValue().stripPointerCasts();
5236 takeKnownMaximum(
V.getPointerAlignment(
A.getDataLayout()).value());
5238 if (Instruction *CtxI = getCtxI())
5239 followUsesInMBEC(*
this,
A, getState(), *CtxI);
5246 Value &AssociatedValue = getAssociatedValue();
5248 return ChangeStatus::UNCHANGED;
5250 for (
const Use &U : AssociatedValue.
uses()) {
5252 if (
SI->getPointerOperand() == &AssociatedValue)
5253 if (
SI->getAlign() < getAssumedAlign()) {
5255 "Number of times alignment added to a store");
5256 SI->setAlignment(getAssumedAlign());
5257 InstrChanged = ChangeStatus::CHANGED;
5260 if (LI->getPointerOperand() == &AssociatedValue)
5261 if (LI->getAlign() < getAssumedAlign()) {
5262 LI->setAlignment(getAssumedAlign());
5264 "Number of times alignment added to a load");
5265 InstrChanged = ChangeStatus::CHANGED;
5268 if (RMW->getPointerOperand() == &AssociatedValue) {
5269 if (RMW->getAlign() < getAssumedAlign()) {
5271 "Number of times alignment added to atomicrmw");
5273 RMW->setAlignment(getAssumedAlign());
5274 InstrChanged = ChangeStatus::CHANGED;
5278 if (CAS->getPointerOperand() == &AssociatedValue) {
5279 if (CAS->getAlign() < getAssumedAlign()) {
5281 "Number of times alignment added to cmpxchg");
5282 CAS->setAlignment(getAssumedAlign());
5283 InstrChanged = ChangeStatus::CHANGED;
5291 Align InheritAlign =
5292 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5293 if (InheritAlign >= getAssumedAlign())
5294 return InstrChanged;
5295 return Changed | InstrChanged;
5302 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5303 SmallVectorImpl<Attribute> &Attrs)
const override {
5304 if (getAssumedAlign() > 1)
5306 Attribute::getWithAlignment(Ctx,
Align(getAssumedAlign())));
5310 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
5311 AAAlign::StateType &State) {
5312 bool TrackUse =
false;
5314 unsigned int KnownAlign =
5315 getKnownAlignForUse(
A, *
this, getAssociatedValue(), U,
I, TrackUse);
5316 State.takeKnownMaximum(KnownAlign);
5321 const std::string getAsStr(Attributor *
A)
const override {
5322 return "align<" + std::to_string(getKnownAlign().value()) +
"-" +
5323 std::to_string(getAssumedAlign().value()) +
">";
5328struct AAAlignFloating : AAAlignImpl {
5329 AAAlignFloating(
const IRPosition &IRP, Attributor &
A) : AAAlignImpl(IRP,
A) {}
5332 const DataLayout &
DL =
A.getDataLayout();
5335 bool UsedAssumedInformation =
false;
5337 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
5339 Values.push_back({getAssociatedValue(), getCtxI()});
5342 Stripped =
Values.size() != 1 ||
5343 Values.front().getValue() != &getAssociatedValue();
5347 auto VisitValueCB = [&](
Value &
V) ->
bool {
5351 DepClassTy::REQUIRED);
5352 if (!AA || (!Stripped &&
this == AA)) {
5370 T.takeKnownMaximum(Alignment);
5371 T.indicatePessimisticFixpoint();
5374 const AAAlign::StateType &
DS = AA->
getState();
5377 return T.isValidState();
5380 for (
const auto &VAC :
Values) {
5381 if (!VisitValueCB(*VAC.
getValue()))
5382 return indicatePessimisticFixpoint();
5394struct AAAlignReturned final
5395 : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {
5396 using Base = AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>;
5397 AAAlignReturned(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5403struct AAAlignArgument final
5404 : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {
5405 using Base = AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>;
5406 AAAlignArgument(
const IRPosition &IRP, Attributor &
A) :
Base(IRP,
A) {}
5412 if (
A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))
5413 return ChangeStatus::UNCHANGED;
5414 return Base::manifest(
A);
5420struct AAAlignCallSiteArgument final : AAAlignFloating {
5421 AAAlignCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5422 : AAAlignFloating(IRP,
A) {}
5428 if (Argument *Arg = getAssociatedArgument())
5429 if (
A.getInfoCache().isInvolvedInMustTailCall(*Arg))
5430 return ChangeStatus::UNCHANGED;
5432 Align InheritAlign =
5433 getAssociatedValue().getPointerAlignment(
A.getDataLayout());
5434 if (InheritAlign >= getAssumedAlign())
5435 Changed = ChangeStatus::UNCHANGED;
5441 if (Argument *Arg = getAssociatedArgument()) {
5444 const auto *ArgAlignAA =
A.getAAFor<AAAlign>(
5447 takeKnownMaximum(ArgAlignAA->getKnownAlign().value());
5456struct AAAlignCallSiteReturned final
5457 : AACalleeToCallSite<AAAlign, AAAlignImpl> {
5458 using Base = AACalleeToCallSite<AAAlign, AAAlignImpl>;
5459 AAAlignCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5465 switch (
II->getIntrinsicID()) {
5466 case Intrinsic::ptrmask: {
5470 const auto *ConstVals =
A.getAAFor<AAPotentialConstantValues>(
5472 if (ConstVals && ConstVals->isValidState()) {
5473 unsigned ShiftValue =
5474 std::min(ConstVals->getAssumedMinTrailingZeros(),
5475 Value::MaxAlignmentExponent);
5480 const auto *AlignAA =
5482 DepClassTy::REQUIRED);
5484 Alignment = std::max(AlignAA->getAssumedAlign(), Alignment);
5491 std::min(this->getAssumedAlign(), Alignment).value());
5497 case Intrinsic::amdgcn_make_buffer_rsrc: {
5498 const auto *AlignAA =
5500 DepClassTy::REQUIRED);
5503 this->getState(), AlignAA->getAssumedAlign().
value());
5510 return Base::updateImpl(
A);
5518struct AANoReturnImpl :
public AANoReturn {
5519 AANoReturnImpl(
const IRPosition &IRP, Attributor &
A) : AANoReturn(IRP,
A) {}
5524 A,
nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));
5528 const std::string getAsStr(Attributor *
A)
const override {
5529 return getAssumed() ?
"noreturn" :
"may-return";
5533 auto CheckForNoReturn = [](
Instruction &) {
return false; };
5534 bool UsedAssumedInformation =
false;
5535 if (!
A.checkForAllInstructions(CheckForNoReturn, *
this,
5536 {(unsigned)Instruction::Ret},
5537 UsedAssumedInformation))
5538 return indicatePessimisticFixpoint();
5539 return ChangeStatus::UNCHANGED;
5543struct AANoReturnFunction final : AANoReturnImpl {
5544 AANoReturnFunction(
const IRPosition &IRP, Attributor &
A)
5545 : AANoReturnImpl(IRP,
A) {}
5551struct AANoReturnCallSite final
5552 : AACalleeToCallSite<AANoReturn, AANoReturnImpl> {
5553 AANoReturnCallSite(
const IRPosition &IRP, Attributor &
A)
5554 : AACalleeToCallSite<AANoReturn, AANoReturnImpl>(IRP,
A) {}
5564struct AAInstanceInfoImpl :
public AAInstanceInfo {
5565 AAInstanceInfoImpl(
const IRPosition &IRP, Attributor &
A)
5566 : AAInstanceInfo(IRP,
A) {}
5569 Value &
V = getAssociatedValue();
5571 if (
C->isThreadDependent())
5572 indicatePessimisticFixpoint();
5574 indicateOptimisticFixpoint();
5580 indicateOptimisticFixpoint();
5585 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
5588 indicatePessimisticFixpoint();
5597 Value &
V = getAssociatedValue();
5600 Scope =
I->getFunction();
5603 if (!
Scope->hasLocalLinkage())
5607 return indicateOptimisticFixpoint();
5609 bool IsKnownNoRecurse;
5615 auto UsePred = [&](
const Use &
U,
bool &Follow) {
5630 if (!Callee || !
Callee->hasLocalLinkage())
5634 const auto *ArgInstanceInfoAA =
A.getAAFor<AAInstanceInfo>(
5636 DepClassTy::OPTIONAL);
5637 if (!ArgInstanceInfoAA ||
5638 !ArgInstanceInfoAA->isAssumedUniqueForAnalysis())
5643 A, *CB, *Scope, *
this,
nullptr,
5651 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
5653 auto *Ptr =
SI->getPointerOperand()->stripPointerCasts();
5661 if (!
A.checkForAllUses(UsePred, *
this,
V,
true,
5662 DepClassTy::OPTIONAL,
5663 true, EquivalentUseCB))
5664 return indicatePessimisticFixpoint();
5669 const std::string getAsStr(Attributor *
A)
const override {
5670 return isAssumedUniqueForAnalysis() ?
"<unique [fAa]>" :
"<unknown>";
5673 void trackStatistics()
const override {}
5677struct AAInstanceInfoFloating : AAInstanceInfoImpl {
5678 AAInstanceInfoFloating(
const IRPosition &IRP, Attributor &
A)
5679 : AAInstanceInfoImpl(IRP,
A) {}
5683struct AAInstanceInfoArgument final : AAInstanceInfoFloating {
5684 AAInstanceInfoArgument(
const IRPosition &IRP, Attributor &
A)
5685 : AAInstanceInfoFloating(IRP,
A) {}
5689struct AAInstanceInfoCallSiteArgument final : AAInstanceInfoImpl {
5690 AAInstanceInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
5691 : AAInstanceInfoImpl(IRP,
A) {}
5698 Argument *Arg = getAssociatedArgument();
5700 return indicatePessimisticFixpoint();
5703 A.getAAFor<AAInstanceInfo>(*
this, ArgPos, DepClassTy::REQUIRED);
5705 return indicatePessimisticFixpoint();
5711struct AAInstanceInfoReturned final : AAInstanceInfoImpl {
5712 AAInstanceInfoReturned(
const IRPosition &IRP, Attributor &
A)
5713 : AAInstanceInfoImpl(IRP,
A) {
5727struct AAInstanceInfoCallSiteReturned final : AAInstanceInfoFloating {
5728 AAInstanceInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
5729 : AAInstanceInfoFloating(IRP,
A) {}
5736 bool IgnoreSubsumingPositions) {
5737 assert(ImpliedAttributeKind == Attribute::Captures &&
5738 "Unexpected attribute kind");
5752 A.getAttrs(IRP, {Attribute::Captures}, Attrs,
5762 {Attribute::Captures, Attribute::ByVal}, Attrs,
5801 bool NoThrow =
F.doesNotThrow();
5802 bool WillReturn =
F.willReturn();
5803 bool IsVoidReturn =
F.getReturnType()->isVoidTy();
5804 if (
ReadOnly && NoThrow && WillReturn && IsVoidReturn) {
5817 if (NoThrow && IsVoidReturn)
5822 if (!NoThrow || ArgNo < 0 ||
5823 !
F.getAttributes().hasAttrSomewhere(Attribute::Returned))
5826 for (
unsigned U = 0, E =
F.arg_size(); U < E; ++U)
5827 if (
F.hasParamAttribute(U, Attribute::Returned)) {
5828 if (U ==
unsigned(ArgNo))
5852 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
5853 SmallVectorImpl<Attribute> &Attrs)
const override {
5854 if (!isAssumedNoCaptureMaybeReturned())
5857 if (isArgumentPosition()) {
5858 if (isAssumedNoCapture())
5859 Attrs.emplace_back(Attribute::get(Ctx, Attribute::Captures));
5861 Attrs.emplace_back(Attribute::get(Ctx,
"no-capture-maybe-returned"));
5865 const std::string getAsStr(Attributor *
A)
const override {
5866 if (isKnownNoCapture())
5867 return "known not-captured";
5868 if (isAssumedNoCapture())
5869 return "assumed not-captured";
5870 if (isKnownNoCaptureMaybeReturned())
5871 return "known not-captured-maybe-returned";
5872 if (isAssumedNoCaptureMaybeReturned())
5873 return "assumed not-captured-maybe-returned";
5874 return "assumed-captured";
5879 bool checkUse(Attributor &
A, AANoCapture::StateType &State,
const Use &U,
5882 LLVM_DEBUG(
dbgs() <<
"[AANoCapture] Check use: " << *
U.get() <<
" in "
5888 return isCapturedIn(State,
true,
true,
5895 return isCapturedIn(State,
true,
true,
5901 return isCapturedIn(State,
false,
false,
5903 return isCapturedIn(State,
true,
true,
5911 return isCapturedIn(State,
true,
true,
5918 bool IsKnownNoCapture;
5919 const AANoCapture *ArgNoCaptureAA =
nullptr;
5921 A,
this, CSArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
5923 if (IsAssumedNoCapture)
5924 return isCapturedIn(State,
false,
false,
5928 return isCapturedIn(State,
false,
false,
5933 return isCapturedIn(State,
true,
true,
5940 static bool isCapturedIn(AANoCapture::StateType &State,
bool CapturedInMem,
5941 bool CapturedInInt,
bool CapturedInRet) {
5942 LLVM_DEBUG(
dbgs() <<
" - captures [Mem " << CapturedInMem <<
"|Int "
5943 << CapturedInInt <<
"|Ret " << CapturedInRet <<
"]\n");
5955 const IRPosition &IRP = getIRPosition();
5959 return indicatePessimisticFixpoint();
5966 return indicatePessimisticFixpoint();
5974 T.addKnownBits(NOT_CAPTURED_IN_MEM);
5976 addKnownBits(NOT_CAPTURED_IN_MEM);
5983 auto CheckReturnedArgs = [&](
bool &UsedAssumedInformation) {
5987 UsedAssumedInformation))
5989 bool SeenConstant =
false;
5990 for (
const AA::ValueAndContext &VAC :
Values) {
5994 SeenConstant =
true;
5996 VAC.
getValue() == getAssociatedArgument())
6002 bool IsKnownNoUnwind;
6005 bool IsVoidTy =
F->getReturnType()->isVoidTy();
6006 bool UsedAssumedInformation =
false;
6007 if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {
6008 T.addKnownBits(NOT_CAPTURED_IN_RET);
6011 bool IsKnownWillReturn;
6014 if (IsAssumedWillReturn &&
T.isKnown(NOT_CAPTURED_IN_MEM))
6016 if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {
6017 addKnownBits(NOT_CAPTURED_IN_RET);
6018 if (IsKnownWillReturn && isKnown(NOT_CAPTURED_IN_MEM))
6019 return indicateOptimisticFixpoint();
6024 auto UseCheck = [&](
const Use &
U,
bool &Follow) ->
bool {
6033 return checkUse(
A,
T, U, Follow);
6036 if (!
A.checkForAllUses(UseCheck, *
this, *
V))
6037 return indicatePessimisticFixpoint();
6040 auto Assumed = S.getAssumed();
6041 S.intersectAssumedBits(
T.getAssumed());
6042 if (!isAssumedNoCaptureMaybeReturned())
6043 return indicatePessimisticFixpoint();
6049struct AANoCaptureArgument final : AANoCaptureImpl {
6050 AANoCaptureArgument(
const IRPosition &IRP, Attributor &
A)
6051 : AANoCaptureImpl(IRP,
A) {}
6057struct AANoCaptureCallSiteArgument final : AANoCaptureImpl {
6058 AANoCaptureCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6059 : AANoCaptureImpl(IRP,
A) {}
6066 Argument *Arg = getAssociatedArgument();
6068 return indicatePessimisticFixpoint();
6070 bool IsKnownNoCapture;
6071 const AANoCapture *ArgAA =
nullptr;
6073 A,
this, ArgPos, DepClassTy::REQUIRED, IsKnownNoCapture,
false,
6075 return ChangeStatus::UNCHANGED;
6077 return indicatePessimisticFixpoint();
6081 void trackStatistics()
const override {
6087struct AANoCaptureFloating final : AANoCaptureImpl {
6088 AANoCaptureFloating(
const IRPosition &IRP, Attributor &
A)
6089 : AANoCaptureImpl(IRP,
A) {}
6091 void trackStatistics()
const override {
6097struct AANoCaptureReturned final : AANoCaptureImpl {
6098 AANoCaptureReturned(
const IRPosition &IRP, Attributor &
A)
6099 : AANoCaptureImpl(IRP,
A) {
6111 void trackStatistics()
const override {}
6115struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {
6116 AANoCaptureCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6117 : AANoCaptureImpl(IRP,
A) {}
6122 determineFunctionCaptureCapabilities(getIRPosition(), *
F, *
this);
6125 void trackStatistics()
const override {
6142 dbgs() <<
"[ValueSimplify] is assumed to be "
6145 dbgs() <<
"[ValueSimplify] is assumed to be <none>\n";
6156 if (getAssociatedValue().
getType()->isVoidTy())
6157 indicatePessimisticFixpoint();
6158 if (
A.hasSimplificationCallback(getIRPosition()))
6159 indicatePessimisticFixpoint();
6162 const std::string getAsStr(Attributor *
A)
const override {
6164 dbgs() <<
"SAV: " << (bool)SimplifiedAssociatedValue <<
" ";
6165 if (SimplifiedAssociatedValue && *SimplifiedAssociatedValue)
6166 dbgs() <<
"SAV: " << **SimplifiedAssociatedValue <<
" ";
6168 return isValidState() ? (isAtFixpoint() ?
"simplified" :
"maybe-simple")
6172 void trackStatistics()
const override {}
6174 std::optional<Value *>
6175 getAssumedSimplifiedValue(Attributor &
A)
const override {
6176 return SimplifiedAssociatedValue;
6183 static Value *ensureType(Attributor &
A,
Value &
V,
Type &Ty, Instruction *CtxI,
6187 if (CtxI &&
V.getType()->canLosslesslyBitCastTo(&Ty))
6189 : BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6198 static Value *reproduceInst(Attributor &
A,
6199 const AbstractAttribute &QueryingAA,
6200 Instruction &
I,
Type &Ty, Instruction *CtxI,
6202 assert(CtxI &&
"Cannot reproduce an instruction without context!");
6203 if (
Check && (
I.mayReadFromMemory() ||
6208 Value *NewOp = reproduceValue(
A, QueryingAA, *
Op, Ty, CtxI,
Check, VMap);
6210 assert(
Check &&
"Manifest of new value unexpectedly failed!");
6232 static Value *reproduceValue(Attributor &
A,
6233 const AbstractAttribute &QueryingAA,
Value &
V,
6234 Type &Ty, Instruction *CtxI,
bool Check,
6236 if (
const auto &NewV = VMap.
lookup(&
V))
6238 bool UsedAssumedInformation =
false;
6239 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
6241 if (!SimpleV.has_value())
6245 EffectiveV = *SimpleV;
6250 return ensureType(
A, *EffectiveV, Ty, CtxI,
Check);
6252 if (
Value *NewV = reproduceInst(
A, QueryingAA, *
I, Ty, CtxI,
Check, VMap))
6253 return ensureType(
A, *NewV, Ty, CtxI,
Check);
6259 Value *manifestReplacementValue(Attributor &
A, Instruction *CtxI)
const {
6260 Value *NewV = SimplifiedAssociatedValue
6261 ? *SimplifiedAssociatedValue
6263 if (NewV && NewV != &getAssociatedValue()) {
6267 if (reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6269 return reproduceValue(
A, *
this, *NewV, *getAssociatedType(), CtxI,
6277 bool checkAndUpdate(Attributor &
A,
const AbstractAttribute &QueryingAA,
6278 const IRPosition &IRP,
bool Simplify =
true) {
6279 bool UsedAssumedInformation =
false;
6282 QueryingValueSimplified =
A.getAssumedSimplified(
6284 return unionAssumed(QueryingValueSimplified);
6288 template <
typename AAType>
bool askSimplifiedValueFor(Attributor &
A) {
6289 if (!getAssociatedValue().
getType()->isIntegerTy())
6294 A.getAAFor<AAType>(*
this, getIRPosition(), DepClassTy::NONE);
6298 std::optional<Constant *> COpt = AA->getAssumedConstant(
A);
6301 SimplifiedAssociatedValue = std::nullopt;
6302 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6305 if (
auto *
C = *COpt) {
6306 SimplifiedAssociatedValue =
C;
6307 A.recordDependence(*AA, *
this, DepClassTy::OPTIONAL);
6313 bool askSimplifiedValueForOtherAAs(Attributor &
A) {
6314 if (askSimplifiedValueFor<AAValueConstantRange>(
A))
6316 if (askSimplifiedValueFor<AAPotentialConstantValues>(
A))
6323 for (
auto &U : getAssociatedValue().uses()) {
6328 IP =
PHI->getIncomingBlock(U)->getTerminator();
6329 if (
auto *NewV = manifestReplacementValue(
A, IP)) {
6331 <<
" -> " << *NewV <<
" :: " << *
this <<
"\n");
6332 if (
A.changeUseAfterManifest(U, *NewV))
6333 Changed = ChangeStatus::CHANGED;
6337 return Changed | AAValueSimplify::manifest(
A);
6341 SimplifiedAssociatedValue = &getAssociatedValue();
6342 return AAValueSimplify::indicatePessimisticFixpoint();
6346struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
6347 AAValueSimplifyArgument(
const IRPosition &IRP, Attributor &
A)
6348 : AAValueSimplifyImpl(IRP,
A) {}
6351 AAValueSimplifyImpl::initialize(
A);
6352 if (
A.hasAttr(getIRPosition(),
6353 {Attribute::InAlloca, Attribute::Preallocated,
6354 Attribute::StructRet, Attribute::Nest, Attribute::ByVal},
6356 indicatePessimisticFixpoint();
6362 Argument *Arg = getAssociatedArgument();
6368 return indicatePessimisticFixpoint();
6371 auto Before = SimplifiedAssociatedValue;
6373 auto PredForCallSite = [&](AbstractCallSite ACS) {
6374 const IRPosition &ACSArgPos =
6385 bool UsedAssumedInformation =
false;
6386 std::optional<Constant *> SimpleArgOp =
6387 A.getAssumedConstant(ACSArgPos, *
this, UsedAssumedInformation);
6394 return unionAssumed(*SimpleArgOp);
6399 bool UsedAssumedInformation =
false;
6400 if (hasCallBaseContext() &&
6401 getCallBaseContext()->getCalledOperand() == Arg->
getParent())
6403 AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
6405 Success =
A.checkForAllCallSites(PredForCallSite, *
this,
true,
6406 UsedAssumedInformation);
6409 if (!askSimplifiedValueForOtherAAs(
A))
6410 return indicatePessimisticFixpoint();
6413 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6414 : ChangeStatus ::CHANGED;
6417 void trackStatistics()
const override {
6422struct AAValueSimplifyReturned : AAValueSimplifyImpl {
6423 AAValueSimplifyReturned(
const IRPosition &IRP, Attributor &
A)
6424 : AAValueSimplifyImpl(IRP,
A) {}
6426 std::optional<Value *>
6427 getAssumedSimplifiedValue(Attributor &
A)
const override {
6428 if (!isValidState())
6430 return SimplifiedAssociatedValue;
6434 auto Before = SimplifiedAssociatedValue;
6438 return checkAndUpdate(
6443 bool UsedAssumedInformation =
false;
6444 if (!
A.checkForAllInstructions(ReturnInstCB, *
this, {Instruction::Ret},
6445 UsedAssumedInformation))
6446 if (!askSimplifiedValueForOtherAAs(
A))
6447 return indicatePessimisticFixpoint();
6450 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6451 : ChangeStatus ::CHANGED;
6457 return ChangeStatus::UNCHANGED;
6460 void trackStatistics()
const override {
6465struct AAValueSimplifyFloating : AAValueSimplifyImpl {
6466 AAValueSimplifyFloating(
const IRPosition &IRP, Attributor &
A)
6467 : AAValueSimplifyImpl(IRP,
A) {}
6470 AAValueSimplifyImpl::initialize(
A);
6471 Value &
V = getAnchorValue();
6475 indicatePessimisticFixpoint();
6479 auto Before = SimplifiedAssociatedValue;
6480 if (!askSimplifiedValueForOtherAAs(
A))
6481 return indicatePessimisticFixpoint();
6484 return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED
6485 : ChangeStatus ::CHANGED;
6488 void trackStatistics()
const override {
6493struct AAValueSimplifyFunction : AAValueSimplifyImpl {
6494 AAValueSimplifyFunction(
const IRPosition &IRP, Attributor &
A)
6495 : AAValueSimplifyImpl(IRP,
A) {}
6498 SimplifiedAssociatedValue =
nullptr;
6499 indicateOptimisticFixpoint();
6503 "AAValueSimplify(Function|CallSite)::updateImpl will not be called");
6505 void trackStatistics()
const override {
6510struct AAValueSimplifyCallSite : AAValueSimplifyFunction {
6511 AAValueSimplifyCallSite(
const IRPosition &IRP, Attributor &
A)
6512 : AAValueSimplifyFunction(IRP,
A) {}
6513 void trackStatistics()
const override {
6518struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl {
6519 AAValueSimplifyCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
6520 : AAValueSimplifyImpl(IRP,
A) {}
6523 AAValueSimplifyImpl::initialize(
A);
6524 Function *Fn = getAssociatedFunction();
6525 assert(Fn &&
"Did expect an associted function");
6526 for (Argument &Arg : Fn->
args()) {
6531 checkAndUpdate(
A, *
this, IRP))
6532 indicateOptimisticFixpoint();
6534 indicatePessimisticFixpoint();
6541 return indicatePessimisticFixpoint();
6544 void trackStatistics()
const override {
6549struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
6550 AAValueSimplifyCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
6551 : AAValueSimplifyFloating(IRP,
A) {}
6556 auto *FloatAA =
A.lookupAAFor<AAValueSimplify>(
6558 if (FloatAA && FloatAA->getState().isValidState())
6561 if (
auto *NewV = manifestReplacementValue(
A, getCtxI())) {
6563 ->getArgOperandUse(getCallSiteArgNo());
6564 if (
A.changeUseAfterManifest(U, *NewV))
6565 Changed = ChangeStatus::CHANGED;
6568 return Changed | AAValueSimplify::manifest(
A);
6571 void trackStatistics()
const override {
6582 bool UsedAssumedInformation =
false;
6583 return A.checkForAllInstructions(
6586 if (CI.isTailCall() && !CI.isMustTailCall())
6590 QueryingAA, {Instruction::Call}, UsedAssumedInformation);
6595struct AAHeapToStackFunction final :
public AAHeapToStack {
6597 static bool isGlobalizedLocal(
const CallBase &CB) {
6599 return A.
isValid() &&
A.getValueAsString() ==
"__kmpc_alloc_shared";
6602 struct AllocationInfo {
6607 bool IsGlobalizedLocal =
false;
6614 } Status = STACK_DUE_TO_USE;
6618 bool HasPotentiallyFreeingUnknownUses =
false;
6622 bool MoveAllocaIntoEntry =
true;
6625 SmallSetVector<CallBase *, 1> PotentialFreeCalls{};
6628 struct DeallocationInfo {
6636 bool MightFreeUnknownObjects =
false;
6639 SmallSetVector<CallBase *, 1> PotentialAllocationCalls{};
6642 AAHeapToStackFunction(
const IRPosition &IRP, Attributor &
A)
6643 : AAHeapToStack(IRP,
A) {}
6645 ~AAHeapToStackFunction()
override {
6648 for (
auto &It : AllocationInfos)
6649 It.second->~AllocationInfo();
6650 for (
auto &It : DeallocationInfos)
6651 It.second->~DeallocationInfo();
6655 AAHeapToStack::initialize(
A);
6658 const auto *
TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6665 DeallocationInfos[CB] =
new (
A.Allocator) DeallocationInfo{CB, FreedOp};
6672 auto *I8Ty = Type::getInt8Ty(CB->
getParent()->getContext());
6674 AllocationInfo *AI =
new (
A.Allocator) AllocationInfo{CB};
6675 AllocationInfos[CB] = AI;
6676 AI->IsGlobalizedLocal = isGlobalizedLocal(*CB);
6682 bool UsedAssumedInformation =
false;
6683 bool Success =
A.checkForAllCallLikeInstructions(
6684 AllocationIdentifierCB, *
this, UsedAssumedInformation,
6688 assert(
Success &&
"Did not expect the call base visit callback to fail!");
6691 [](
const IRPosition &,
const AbstractAttribute *,
6692 bool &) -> std::optional<Value *> {
return nullptr; };
6693 for (
const auto &It : AllocationInfos)
6696 for (
const auto &It : DeallocationInfos)
6701 const std::string getAsStr(Attributor *
A)
const override {
6702 unsigned NumH2SMallocs = 0, NumInvalidMallocs = 0;
6703 for (
const auto &It : AllocationInfos) {
6704 if (It.second->Status == AllocationInfo::INVALID)
6705 ++NumInvalidMallocs;
6709 return "[H2S] Mallocs Good/Bad: " + std::to_string(NumH2SMallocs) +
"/" +
6710 std::to_string(NumInvalidMallocs);
6713 void trackStatistics()
const override {
6716 "Number of malloc/calloc/aligned_alloc calls converted to allocas");
6717 for (
const auto &It : AllocationInfos)
6718 if (It.second->Status != AllocationInfo::INVALID)
6722 bool isAssumedHeapToStack(
const CallBase &CB)
const override {
6724 if (AllocationInfo *AI =
6725 AllocationInfos.lookup(
const_cast<CallBase *
>(&CB)))
6726 return AI->Status != AllocationInfo::INVALID;
6730 bool isAssumedHeapToStackRemovedFree(CallBase &CB)
const override {
6731 if (!isValidState())
6734 for (
const auto &It : AllocationInfos) {
6735 AllocationInfo &AI = *It.second;
6736 if (AI.Status == AllocationInfo::INVALID)
6739 if (AI.PotentialFreeCalls.count(&CB))
6747 assert(getState().isValidState() &&
6748 "Attempted to manifest an invalid state!");
6752 const auto *
TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6756 if (
any_of(AllocationInfos,
6757 [](
const std::pair<CallBase *, AllocationInfo *> &It) {
6758 return It.second->Status != AllocationInfo::INVALID;
6761 return ChangeStatus::UNCHANGED;
6763 for (
auto &It : AllocationInfos) {
6764 AllocationInfo &AI = *It.second;
6765 if (AI.Status == AllocationInfo::INVALID)
6768 for (CallBase *FreeCall : AI.PotentialFreeCalls) {
6769 LLVM_DEBUG(
dbgs() <<
"H2S: Removing free call: " << *FreeCall <<
"\n");
6770 A.deleteAfterManifest(*FreeCall);
6771 HasChanged = ChangeStatus::CHANGED;
6774 LLVM_DEBUG(
dbgs() <<
"H2S: Removing malloc-like call: " << *AI.CB
6777 auto Remark = [&](OptimizationRemark
OR) {
6778 if (AI.IsGlobalizedLocal)
6779 return OR <<
"Moving globalized variable to the stack.";
6780 return OR <<
"Moving memory allocation from the heap to the stack.";
6782 if (AI.IsGlobalizedLocal)
6783 A.emitRemark<OptimizationRemark>(AI.CB,
"OMP110",
Remark);
6785 A.emitRemark<OptimizationRemark>(AI.CB,
"HeapToStack",
Remark);
6787 const DataLayout &
DL =
A.getInfoCache().getDL();
6789 std::optional<APInt> SizeAPI =
getSize(
A, *
this, AI);
6791 Size = ConstantInt::get(AI.CB->getContext(), *SizeAPI);
6793 ObjectSizeOpts Opts;
6794 ObjectSizeOffsetEvaluator Eval(*AI.CB->getModule(),
TLI, Opts);
6795 SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);
6802 ?
F->getEntryBlock().begin()
6803 : AI.CB->getIterator();
6806 if (MaybeAlign RetAlign = AI.CB->getRetAlign())
6807 Alignment = std::max(Alignment, *RetAlign);
6809 std::optional<APInt> AlignmentAPI = getAPInt(
A, *
this, *Align);
6810 assert(AlignmentAPI && AlignmentAPI->getZExtValue() > 0 &&
6811 "Expected an alignment during manifest!");
6813 std::max(Alignment,
assumeAligned(AlignmentAPI->getZExtValue()));
6817 unsigned AS =
DL.getAllocaAddrSpace();
6819 new AllocaInst(Type::getInt8Ty(
F->getContext()), AS,
Size, Alignment,
6820 AI.CB->getName() +
".h2s", IP);
6822 if (Alloca->
getType() != AI.CB->getType())
6823 Alloca = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
6824 Alloca, AI.CB->getType(),
"malloc_cast", AI.CB->getIterator());
6826 auto *I8Ty = Type::getInt8Ty(
F->getContext());
6829 "Must be able to materialize initial memory state of allocation");
6834 auto *NBB =
II->getNormalDest();
6836 A.deleteAfterManifest(*AI.CB);
6838 A.deleteAfterManifest(*AI.CB);
6847 Builder.CreateMemSet(Alloca, InitVal,
Size, std::nullopt);
6849 HasChanged = ChangeStatus::CHANGED;
6852 for (CallInst *CI : TailCalls)
6853 CI->setTailCall(
false);
6858 std::optional<APInt> getAPInt(Attributor &
A,
const AbstractAttribute &AA,
6860 bool UsedAssumedInformation =
false;
6861 std::optional<Constant *> SimpleV =
6862 A.getAssumedConstant(
V, AA, UsedAssumedInformation);
6864 return APInt(64, 0);
6866 return CI->getValue();
6867 return std::nullopt;
6870 std::optional<APInt>
getSize(Attributor &
A,
const AbstractAttribute &AA,
6871 AllocationInfo &AI) {
6873 bool UsedAssumedInformation =
false;
6874 if (std::optional<Constant *> SimpleV =
6875 A.getAssumedConstant(*
V, AA, UsedAssumedInformation))
6882 const auto *
TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6888 MapVector<CallBase *, AllocationInfo *> AllocationInfos;
6892 MapVector<CallBase *, DeallocationInfo *> DeallocationInfos;
6897ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &
A) {
6900 const auto *
TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
6902 const auto *LivenessAA =
6905 MustBeExecutedContextExplorer *Explorer =
6906 A.getInfoCache().getMustBeExecutedContextExplorer();
6908 bool StackIsAccessibleByOtherThreads =
6909 A.getInfoCache().stackIsAccessibleByOtherThreads();
6912 A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(*F);
6913 std::optional<bool> MayContainIrreducibleControl;
6915 if (&
F->getEntryBlock() == &BB)
6917 if (!MayContainIrreducibleControl.has_value())
6919 if (*MayContainIrreducibleControl)
6928 bool HasUpdatedFrees =
false;
6930 auto UpdateFrees = [&]() {
6931 HasUpdatedFrees =
true;
6933 for (
auto &It : DeallocationInfos) {
6934 DeallocationInfo &DI = *It.second;
6937 if (DI.MightFreeUnknownObjects)
6941 bool UsedAssumedInformation =
false;
6942 if (
A.isAssumedDead(*DI.CB,
this, LivenessAA, UsedAssumedInformation,
6949 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown underlying object for free!\n");
6950 DI.MightFreeUnknownObjects =
true;
6963 DI.MightFreeUnknownObjects =
true;
6967 AllocationInfo *AI = AllocationInfos.lookup(ObjCB);
6969 LLVM_DEBUG(
dbgs() <<
"[H2S] Free of a non-allocation object: " << *Obj
6971 DI.MightFreeUnknownObjects =
true;
6975 DI.PotentialAllocationCalls.insert(ObjCB);
6979 auto FreeCheck = [&](AllocationInfo &AI) {
6983 if (!StackIsAccessibleByOtherThreads) {
6988 dbgs() <<
"[H2S] found an escaping use, stack is not accessible by "
6989 "other threads and function is not nosync:\n");
6993 if (!HasUpdatedFrees)
6997 if (AI.PotentialFreeCalls.size() != 1) {
6999 << AI.PotentialFreeCalls.size() <<
"\n");
7002 CallBase *UniqueFree = *AI.PotentialFreeCalls.begin();
7003 DeallocationInfo *DI = DeallocationInfos.lookup(UniqueFree);
7006 dbgs() <<
"[H2S] unique free call was not known as deallocation call "
7007 << *UniqueFree <<
"\n");
7010 if (DI->MightFreeUnknownObjects) {
7012 dbgs() <<
"[H2S] unique free call might free unknown allocations\n");
7015 if (DI->PotentialAllocationCalls.empty())
7017 if (DI->PotentialAllocationCalls.size() > 1) {
7019 << DI->PotentialAllocationCalls.size()
7020 <<
" different allocations\n");
7023 if (*DI->PotentialAllocationCalls.begin() != AI.CB) {
7026 <<
"[H2S] unique free call not known to free this allocation but "
7027 << **DI->PotentialAllocationCalls.begin() <<
"\n");
7032 if (!AI.IsGlobalizedLocal) {
7034 if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
7035 LLVM_DEBUG(
dbgs() <<
"[H2S] unique free call might not be executed "
7036 "with the allocation "
7037 << *UniqueFree <<
"\n");
7044 auto UsesCheck = [&](AllocationInfo &AI) {
7045 bool ValidUsesOnly =
true;
7047 auto Pred = [&](
const Use &
U,
bool &Follow) ->
bool {
7052 if (
SI->getValueOperand() ==
U.get()) {
7054 <<
"[H2S] escaping store to memory: " << *UserI <<
"\n");
7055 ValidUsesOnly =
false;
7066 ValidUsesOnly =
false;
7072 if (DeallocationInfos.count(CB)) {
7073 AI.PotentialFreeCalls.insert(CB);
7080 bool IsKnownNoCapture;
7089 if (!IsAssumedNoCapture ||
7090 (!AI.IsGlobalizedLocal && !IsAssumedNoFree)) {
7091 AI.HasPotentiallyFreeingUnknownUses |= !IsAssumedNoFree;
7094 auto Remark = [&](OptimizationRemarkMissed ORM) {
7096 <<
"Could not move globalized variable to the stack. "
7097 "Variable is potentially captured in call. Mark "
7098 "parameter as `__attribute__((noescape))` to override.";
7101 if (ValidUsesOnly && AI.IsGlobalizedLocal)
7102 A.emitRemark<OptimizationRemarkMissed>(CB,
"OMP113",
Remark);
7105 ValidUsesOnly =
false;
7118 ValidUsesOnly =
false;
7121 if (!
A.checkForAllUses(
Pred, *
this, *AI.CB,
false,
7123 [&](
const Use &OldU,
const Use &NewU) {
7124 auto *SI = dyn_cast<StoreInst>(OldU.getUser());
7125 return !SI || StackIsAccessibleByOtherThreads ||
7126 AA::isAssumedThreadLocalObject(
7127 A, *SI->getPointerOperand(), *this);
7130 return ValidUsesOnly;
7135 for (
auto &It : AllocationInfos) {
7136 AllocationInfo &AI = *It.second;
7137 if (AI.Status == AllocationInfo::INVALID)
7141 std::optional<APInt> APAlign = getAPInt(
A, *
this, *Align);
7145 LLVM_DEBUG(
dbgs() <<
"[H2S] Unknown allocation alignment: " << *AI.CB
7147 AI.Status = AllocationInfo::INVALID;
7152 !APAlign->isPowerOf2()) {
7153 LLVM_DEBUG(
dbgs() <<
"[H2S] Invalid allocation alignment: " << APAlign
7155 AI.Status = AllocationInfo::INVALID;
7166 dbgs() <<
"[H2S] Unknown allocation size: " << *AI.CB <<
"\n";
7168 dbgs() <<
"[H2S] Allocation size too large: " << *AI.CB <<
" vs. "
7172 AI.Status = AllocationInfo::INVALID;
7178 switch (AI.Status) {
7179 case AllocationInfo::STACK_DUE_TO_USE:
7182 AI.Status = AllocationInfo::STACK_DUE_TO_FREE;
7184 case AllocationInfo::STACK_DUE_TO_FREE:
7187 AI.Status = AllocationInfo::INVALID;
7190 case AllocationInfo::INVALID:
7197 bool IsGlobalizedLocal = AI.IsGlobalizedLocal;
7198 if (AI.MoveAllocaIntoEntry &&
7199 (!
Size.has_value() ||
7200 (!IsGlobalizedLocal && IsInLoop(*AI.CB->getParent()))))
7201 AI.MoveAllocaIntoEntry =
false;
7210struct AAPrivatizablePtrImpl :
public AAPrivatizablePtr {
7211 AAPrivatizablePtrImpl(
const IRPosition &IRP, Attributor &
A)
7212 : AAPrivatizablePtr(IRP,
A), PrivatizableType(std::nullopt) {}
7215 AAPrivatizablePtr::indicatePessimisticFixpoint();
7216 PrivatizableType =
nullptr;
7217 return ChangeStatus::CHANGED;
7223 virtual std::optional<Type *> identifyPrivatizableType(Attributor &
A) = 0;
7227 std::optional<Type *> combineTypes(std::optional<Type *> T0,
7228 std::optional<Type *>
T1) {
7238 std::optional<Type *> getPrivatizableType()
const override {
7239 return PrivatizableType;
7242 const std::string getAsStr(Attributor *
A)
const override {
7243 return isAssumedPrivatizablePtr() ?
"[priv]" :
"[no-priv]";
7247 std::optional<Type *> PrivatizableType;
7252struct AAPrivatizablePtrArgument final :
public AAPrivatizablePtrImpl {
7253 AAPrivatizablePtrArgument(
const IRPosition &IRP, Attributor &
A)
7254 : AAPrivatizablePtrImpl(IRP,
A) {}
7256 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7259 bool UsedAssumedInformation =
false;
7261 A.getAttrs(getIRPosition(), {Attribute::ByVal},
Attrs,
7263 if (!
Attrs.empty() &&
7264 A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *
this,
7265 true, UsedAssumedInformation))
7266 return Attrs[0].getValueAsType();
7268 std::optional<Type *> Ty;
7269 unsigned ArgNo = getIRPosition().getCallSiteArgNo();
7277 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7286 A.getAAFor<AAPrivatizablePtr>(*
this, ACSArgPos, DepClassTy::REQUIRED);
7289 std::optional<Type *> CSTy = PrivCSArgAA->getPrivatizableType();
7292 dbgs() <<
"[AAPrivatizablePtr] ACSPos: " << ACSArgPos <<
", CSTy: ";
7296 dbgs() <<
"<nullptr>";
7301 Ty = combineTypes(Ty, CSTy);
7304 dbgs() <<
" : New Type: ";
7306 (*Ty)->print(
dbgs());
7308 dbgs() <<
"<nullptr>";
7317 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7318 UsedAssumedInformation))
7324 PrivatizableType = identifyPrivatizableType(
A);
7325 if (!PrivatizableType)
7326 return ChangeStatus::UNCHANGED;
7327 if (!*PrivatizableType)
7328 return indicatePessimisticFixpoint();
7333 DepClassTy::OPTIONAL);
7336 if (!
A.hasAttr(getIRPosition(), Attribute::ByVal) &&
7339 return indicatePessimisticFixpoint();
7345 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7349 Function &Fn = *getIRPosition().getAnchorScope();
7351 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(Fn);
7353 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Missing TTI for function "
7355 return indicatePessimisticFixpoint();
7358 auto CallSiteCheck = [&](AbstractCallSite ACS) {
7365 bool UsedAssumedInformation =
false;
7366 if (!
A.checkForAllCallSites(CallSiteCheck, *
this,
true,
7367 UsedAssumedInformation)) {
7369 dbgs() <<
"[AAPrivatizablePtr] ABI incompatibility detected for "
7371 return indicatePessimisticFixpoint();
7375 Argument *Arg = getAssociatedArgument();
7376 if (!
A.isValidFunctionSignatureRewrite(*Arg, ReplacementTypes)) {
7378 return indicatePessimisticFixpoint();
7385 auto IsCompatiblePrivArgOfCallback = [&](CallBase &CB) {
7388 for (
const Use *U : CallbackUses) {
7389 AbstractCallSite CBACS(U);
7390 assert(CBACS && CBACS.isCallbackCall());
7391 for (Argument &CBArg : CBACS.getCalledFunction()->args()) {
7392 int CBArgNo = CBACS.getCallArgOperandNo(CBArg);
7396 <<
"[AAPrivatizablePtr] Argument " << *Arg
7397 <<
"check if can be privatized in the context of its parent ("
7399 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7401 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7402 <<
")\n[AAPrivatizablePtr] " << CBArg <<
" : "
7403 << CBACS.getCallArgOperand(CBArg) <<
" vs "
7405 <<
"[AAPrivatizablePtr] " << CBArg <<
" : "
7406 << CBACS.getCallArgOperandNo(CBArg) <<
" vs " << ArgNo <<
"\n";
7409 if (CBArgNo !=
int(ArgNo))
7411 const auto *CBArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7413 if (CBArgPrivAA && CBArgPrivAA->isValidState()) {
7414 auto CBArgPrivTy = CBArgPrivAA->getPrivatizableType();
7417 if (*CBArgPrivTy == PrivatizableType)
7422 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7423 <<
" cannot be privatized in the context of its parent ("
7425 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7427 << CBArgNo <<
"@" << CBACS.getCalledFunction()->getName()
7428 <<
").\n[AAPrivatizablePtr] for which the argument "
7429 "privatization is not compatible.\n";
7439 auto IsCompatiblePrivArgOfDirectCS = [&](AbstractCallSite ACS) {
7443 "Expected a direct call operand for callback call operand");
7448 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7449 <<
" check if be privatized in the context of its parent ("
7451 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7453 << DCArgNo <<
"@" << DCCallee->
getName() <<
").\n";
7456 if (
unsigned(DCArgNo) < DCCallee->
arg_size()) {
7457 const auto *DCArgPrivAA =
A.getAAFor<AAPrivatizablePtr>(
7459 DepClassTy::REQUIRED);
7460 if (DCArgPrivAA && DCArgPrivAA->isValidState()) {
7461 auto DCArgPrivTy = DCArgPrivAA->getPrivatizableType();
7464 if (*DCArgPrivTy == PrivatizableType)
7470 dbgs() <<
"[AAPrivatizablePtr] Argument " << *Arg
7471 <<
" cannot be privatized in the context of its parent ("
7473 <<
")\n[AAPrivatizablePtr] because it is an argument in a "
7476 <<
").\n[AAPrivatizablePtr] for which the argument "
7477 "privatization is not compatible.\n";
7485 auto IsCompatiblePrivArgOfOtherCallSite = [&](AbstractCallSite ACS) {
7489 return IsCompatiblePrivArgOfDirectCS(ACS);
7493 if (!
A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *
this,
true,
7494 UsedAssumedInformation))
7495 return indicatePessimisticFixpoint();
7497 return ChangeStatus::UNCHANGED;
7503 identifyReplacementTypes(
Type *PrivType,
7504 SmallVectorImpl<Type *> &ReplacementTypes) {
7507 assert(PrivType &&
"Expected privatizable type!");
7511 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++)
7512 ReplacementTypes.
push_back(PrivStructType->getElementType(u));
7514 ReplacementTypes.
append(PrivArrayType->getNumElements(),
7515 PrivArrayType->getElementType());
7526 assert(PrivType &&
"Expected privatizable type!");
7529 const DataLayout &
DL =
F.getDataLayout();
7533 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7534 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7537 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7540 Type *PointeeTy = PrivArrayType->getElementType();
7541 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7542 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7544 new StoreInst(
F.getArg(ArgNo + u), Ptr, IP);
7547 new StoreInst(
F.getArg(ArgNo), &
Base, IP);
7553 void createReplacementValues(Align Alignment,
Type *PrivType,
7555 SmallVectorImpl<Value *> &ReplacementValues) {
7557 assert(PrivType &&
"Expected privatizable type!");
7565 const StructLayout *PrivStructLayout =
DL.getStructLayout(PrivStructType);
7566 for (
unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {
7567 Type *PointeeTy = PrivStructType->getElementType(u);
7570 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7571 L->setAlignment(Alignment);
7575 Type *PointeeTy = PrivArrayType->getElementType();
7576 uint64_t PointeeTySize =
DL.getTypeStoreSize(PointeeTy);
7577 for (
unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {
7579 LoadInst *
L =
new LoadInst(PointeeTy, Ptr,
"", IP->
getIterator());
7580 L->setAlignment(Alignment);
7585 L->setAlignment(Alignment);
7591 if (!PrivatizableType)
7592 return ChangeStatus::UNCHANGED;
7593 assert(*PrivatizableType &&
"Expected privatizable type!");
7595 Argument *Arg = getAssociatedArgument();
7598 const auto *AlignAA =
7605 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7607 BasicBlock &EntryBB = ReplacementFn.getEntryBlock();
7609 const DataLayout &
DL = IP->getDataLayout();
7610 unsigned AS =
DL.getAllocaAddrSpace();
7611 Instruction *AI =
new AllocaInst(*PrivatizableType, AS,
7612 Arg->
getName() +
".priv", IP);
7613 createInitialization(*PrivatizableType, *AI, ReplacementFn,
7614 ArgIt->getArgNo(), IP);
7617 AI = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(
7625 if (CI && CI->isTailCall() && !CI->isMustTailCall())
7626 CI->setTailCall(
false);
7634 [=](
const Attributor::ArgumentReplacementInfo &ARI,
7635 AbstractCallSite ACS, SmallVectorImpl<Value *> &NewArgOperands) {
7638 createReplacementValues(
7639 AlignAA ? AlignAA->getAssumedAlign() :
Align(0),
7640 *PrivatizableType, ACS,
7648 identifyReplacementTypes(*PrivatizableType, ReplacementTypes);
7651 if (
A.registerFunctionSignatureRewrite(*Arg, ReplacementTypes,
7652 std::move(FnRepairCB),
7653 std::move(ACSRepairCB)))
7654 return ChangeStatus::CHANGED;
7655 return ChangeStatus::UNCHANGED;
7658 void trackStatistics()
const override {
7663struct AAPrivatizablePtrFloating :
public AAPrivatizablePtrImpl {
7664 AAPrivatizablePtrFloating(
const IRPosition &IRP, Attributor &
A)
7665 : AAPrivatizablePtrImpl(IRP,
A) {}
7669 indicatePessimisticFixpoint();
7674 "updateImpl will not be called");
7677 std::optional<Type *> identifyPrivatizableType(Attributor &
A)
override {
7680 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] No underlying object found!\n");
7687 return AI->getAllocatedType();
7689 auto *PrivArgAA =
A.getAAFor<AAPrivatizablePtr>(
7691 if (PrivArgAA && PrivArgAA->isAssumedPrivatizablePtr())
7692 return PrivArgAA->getPrivatizableType();
7695 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] Underlying object neither valid "
7696 "alloca nor privatizable argument: "
7701 void trackStatistics()
const override {
7706struct AAPrivatizablePtrCallSiteArgument final
7707 :
public AAPrivatizablePtrFloating {
7708 AAPrivatizablePtrCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
7709 : AAPrivatizablePtrFloating(IRP,
A) {}
7712 if (
A.hasAttr(getIRPosition(), Attribute::ByVal))
7713 indicateOptimisticFixpoint();
7717 PrivatizableType = identifyPrivatizableType(
A);
7718 if (!PrivatizableType)
7719 return ChangeStatus::UNCHANGED;
7720 if (!*PrivatizableType)
7721 return indicatePessimisticFixpoint();
7723 const IRPosition &IRP = getIRPosition();
7724 bool IsKnownNoCapture;
7726 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoCapture);
7727 if (!IsAssumedNoCapture) {
7728 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might be captured!\n");
7729 return indicatePessimisticFixpoint();
7732 bool IsKnownNoAlias;
7734 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {
7735 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer might alias!\n");
7736 return indicatePessimisticFixpoint();
7741 LLVM_DEBUG(
dbgs() <<
"[AAPrivatizablePtr] pointer is written!\n");
7742 return indicatePessimisticFixpoint();
7745 return ChangeStatus::UNCHANGED;
7748 void trackStatistics()
const override {
7753struct AAPrivatizablePtrCallSiteReturned final
7754 :
public AAPrivatizablePtrFloating {
7755 AAPrivatizablePtrCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
7756 : AAPrivatizablePtrFloating(IRP,
A) {}
7760 indicatePessimisticFixpoint();
7763 void trackStatistics()
const override {
7768struct AAPrivatizablePtrReturned final :
public AAPrivatizablePtrFloating {
7769 AAPrivatizablePtrReturned(
const IRPosition &IRP, Attributor &
A)
7770 : AAPrivatizablePtrFloating(IRP,
A) {}
7774 indicatePessimisticFixpoint();
7777 void trackStatistics()
const override {
7787struct AAMemoryBehaviorImpl :
public AAMemoryBehavior {
7788 AAMemoryBehaviorImpl(
const IRPosition &IRP, Attributor &
A)
7789 : AAMemoryBehavior(IRP,
A) {}
7792 intersectAssumedBits(BEST_STATE);
7793 getKnownStateFromValue(
A, getIRPosition(), getState());
7794 AAMemoryBehavior::initialize(
A);
7798 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
7799 BitIntegerState &State,
7800 bool IgnoreSubsumingPositions =
false) {
7802 A.getAttrs(IRP, AttrKinds, Attrs, IgnoreSubsumingPositions);
7804 switch (Attr.getKindAsEnum()) {
7805 case Attribute::ReadNone:
7808 case Attribute::ReadOnly:
7811 case Attribute::WriteOnly:
7835 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
7836 SmallVectorImpl<Attribute> &Attrs)
const override {
7839 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));
7841 Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));
7842 else if (isAssumedWriteOnly())
7843 Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));
7848 const IRPosition &IRP = getIRPosition();
7850 if (
A.hasAttr(IRP, Attribute::ReadNone,
7852 return ChangeStatus::UNCHANGED;
7861 return ChangeStatus::UNCHANGED;
7864 A.removeAttrs(IRP, AttrKinds);
7867 A.removeAttrs(IRP, Attribute::Writable);
7873 const std::string getAsStr(Attributor *
A)
const override {
7878 if (isAssumedWriteOnly())
7880 return "may-read/write";
7884 static const Attribute::AttrKind AttrKinds[3];
7888 Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};
7891struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {
7892 AAMemoryBehaviorFloating(
const IRPosition &IRP, Attributor &
A)
7893 : AAMemoryBehaviorImpl(IRP,
A) {}
7897 void trackStatistics()
const override {
7902 else if (isAssumedWriteOnly())
7909 bool followUsersOfUseIn(Attributor &
A,
const Use &U,
7910 const Instruction *UserI);
7913 void analyzeUseIn(Attributor &
A,
const Use &U,
const Instruction *UserI);
7917struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {
7918 AAMemoryBehaviorArgument(
const IRPosition &IRP, Attributor &
A)
7919 : AAMemoryBehaviorFloating(IRP,
A) {}
7922 intersectAssumedBits(BEST_STATE);
7923 const IRPosition &IRP = getIRPosition();
7927 bool HasByVal =
A.hasAttr(IRP, {Attribute::ByVal},
7929 getKnownStateFromValue(
A, IRP, getState(),
7936 return ChangeStatus::UNCHANGED;
7940 if (
A.hasAttr(getIRPosition(),
7941 {Attribute::InAlloca, Attribute::Preallocated})) {
7942 removeKnownBits(NO_WRITES);
7943 removeAssumedBits(NO_WRITES);
7945 A.removeAttrs(getIRPosition(), AttrKinds);
7946 return AAMemoryBehaviorFloating::manifest(
A);
7949 void trackStatistics()
const override {
7954 else if (isAssumedWriteOnly())
7959struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {
7960 AAMemoryBehaviorCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
7961 : AAMemoryBehaviorArgument(IRP,
A) {}
7966 Argument *Arg = getAssociatedArgument();
7968 indicatePessimisticFixpoint();
7972 addKnownBits(NO_WRITES);
7973 removeKnownBits(NO_READS);
7974 removeAssumedBits(NO_READS);
7976 AAMemoryBehaviorArgument::initialize(
A);
7977 if (getAssociatedFunction()->isDeclaration())
7978 indicatePessimisticFixpoint();
7986 Argument *Arg = getAssociatedArgument();
7989 A.getAAFor<AAMemoryBehavior>(*
this, ArgPos, DepClassTy::REQUIRED);
7991 return indicatePessimisticFixpoint();
7995 void trackStatistics()
const override {
8000 else if (isAssumedWriteOnly())
8006struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {
8007 AAMemoryBehaviorCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
8008 : AAMemoryBehaviorFloating(IRP,
A) {}
8011 AAMemoryBehaviorImpl::initialize(
A);
8015 return ChangeStatus::UNCHANGED;
8018 void trackStatistics()
const override {}
8022struct AAMemoryBehaviorFunction final :
public AAMemoryBehaviorImpl {
8023 AAMemoryBehaviorFunction(
const IRPosition &IRP, Attributor &
A)
8024 : AAMemoryBehaviorImpl(IRP,
A) {}
8038 else if (isAssumedWriteOnly())
8041 A.removeAttrs(getIRPosition(), AttrKinds);
8044 for (Argument &Arg :
F.args())
8046 return A.manifestAttrs(getIRPosition(),
8047 Attribute::getWithMemoryEffects(
F.getContext(), ME));
8050 void trackStatistics()
const override {
8055 else if (isAssumedWriteOnly())
8061struct AAMemoryBehaviorCallSite final
8062 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl> {
8063 AAMemoryBehaviorCallSite(
const IRPosition &IRP, Attributor &
A)
8064 : AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl>(IRP,
A) {}
8074 else if (isAssumedWriteOnly())
8077 A.removeAttrs(getIRPosition(), AttrKinds);
8080 for (Use &U : CB.
args())
8082 Attribute::Writable);
8083 return A.manifestAttrs(
8084 getIRPosition(), Attribute::getWithMemoryEffects(CB.
getContext(), ME));
8087 void trackStatistics()
const override {
8092 else if (isAssumedWriteOnly())
8097ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &
A) {
8100 auto AssumedState = getAssumed();
8107 const auto *MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(
8109 if (MemBehaviorAA) {
8110 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8111 return !isAtFixpoint();
8116 if (
I.mayReadFromMemory())
8117 removeAssumedBits(NO_READS);
8118 if (
I.mayWriteToMemory())
8119 removeAssumedBits(NO_WRITES);
8120 return !isAtFixpoint();
8123 bool UsedAssumedInformation =
false;
8124 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8125 UsedAssumedInformation))
8126 return indicatePessimisticFixpoint();
8132ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &
A) {
8134 const IRPosition &IRP = getIRPosition();
8145 const auto *FnMemAA =
8148 FnMemAssumedState = FnMemAA->getAssumed();
8149 S.addKnownBits(FnMemAA->getKnown());
8150 if ((S.getAssumed() & FnMemAA->getAssumed()) == S.getAssumed())
8156 auto AssumedState = S.getAssumed();
8162 bool IsKnownNoCapture;
8163 const AANoCapture *ArgNoCaptureAA =
nullptr;
8168 if (!IsAssumedNoCapture &&
8170 S.intersectAssumedBits(FnMemAssumedState);
8176 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
8178 LLVM_DEBUG(
dbgs() <<
"[AAMemoryBehavior] Use: " << *U <<
" in " << *UserI
8186 Follow = followUsersOfUseIn(
A, U, UserI);
8190 analyzeUseIn(
A, U, UserI);
8192 return !isAtFixpoint();
8195 if (!
A.checkForAllUses(UsePred, *
this, getAssociatedValue()))
8196 return indicatePessimisticFixpoint();
8202bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &
A,
const Use &U,
8203 const Instruction *UserI) {
8221 if (
U.get()->getType()->isPointerTy()) {
8223 bool IsKnownNoCapture;
8232void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &
A,
const Use &U,
8233 const Instruction *UserI) {
8240 case Instruction::Load:
8242 removeAssumedBits(NO_READS);
8245 case Instruction::Store:
8250 removeAssumedBits(NO_WRITES);
8252 indicatePessimisticFixpoint();
8255 case Instruction::Call:
8256 case Instruction::CallBr:
8257 case Instruction::Invoke: {
8264 indicatePessimisticFixpoint();
8271 removeAssumedBits(NO_READS);
8278 if (
U.get()->getType()->isPointerTy())
8282 const auto *MemBehaviorAA =
8288 intersectAssumedBits(MemBehaviorAA->
getAssumed());
8296 removeAssumedBits(NO_READS);
8298 removeAssumedBits(NO_WRITES);
8310 return "all memory";
8313 std::string S =
"memory:";
8319 S +=
"internal global,";
8321 S +=
"external global,";
8325 S +=
"inaccessible,";
8339 AccessKind2Accesses.fill(
nullptr);
8342 ~AAMemoryLocationImpl()
override {
8345 for (AccessSet *AS : AccessKind2Accesses)
8351 intersectAssumedBits(BEST_STATE);
8352 getKnownStateFromValue(
A, getIRPosition(), getState());
8353 AAMemoryLocation::initialize(
A);
8357 static void getKnownStateFromValue(Attributor &
A,
const IRPosition &IRP,
8358 BitIntegerState &State,
8359 bool IgnoreSubsumingPositions =
false) {
8368 bool UseArgMemOnly =
true;
8370 if (AnchorFn &&
A.isRunOn(*AnchorFn))
8374 A.getAttrs(IRP, {Attribute::Memory},
Attrs, IgnoreSubsumingPositions);
8383 State.
addKnownBits(inverseLocation(NO_INACCESSIBLE_MEM,
true,
true));
8388 State.
addKnownBits(inverseLocation(NO_ARGUMENT_MEM,
true,
true));
8392 A.manifestAttrs(IRP,
8393 Attribute::getWithMemoryEffects(
8402 NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM,
true,
true));
8406 A.manifestAttrs(IRP,
8407 Attribute::getWithMemoryEffects(
8416 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
8417 SmallVectorImpl<Attribute> &Attrs)
const override {
8424 else if (isAssumedInaccessibleMemOnly())
8425 Attrs.push_back(Attribute::getWithMemoryEffects(
8427 else if (isAssumedArgMemOnly())
8430 else if (isAssumedInaccessibleOrArgMemOnly())
8431 Attrs.push_back(Attribute::getWithMemoryEffects(
8440 const IRPosition &IRP = getIRPosition();
8444 if (DeducedAttrs.
size() != 1)
8445 return ChangeStatus::UNCHANGED;
8448 return A.manifestAttrs(IRP, Attribute::getWithMemoryEffects(
8452 bool checkForAllAccessesToMemoryKind(
8454 MemoryLocationsKind)>
8456 MemoryLocationsKind RequestedMLK)
const override {
8457 if (!isValidState())
8460 MemoryLocationsKind AssumedMLK = getAssumedNotAccessedLocation();
8461 if (AssumedMLK == NO_LOCATIONS)
8465 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS;
8466 CurMLK *= 2, ++
Idx) {
8467 if (CurMLK & RequestedMLK)
8470 if (
const AccessSet *
Accesses = AccessKind2Accesses[Idx])
8471 for (
const AccessInfo &AI : *
Accesses)
8472 if (!
Pred(AI.I, AI.Ptr, AI.Kind, CurMLK))
8485 MemoryLocationsKind KnownMLK = getKnown();
8487 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2)
8488 if (!(CurMLK & KnownMLK))
8489 updateStateAndAccessesMap(getState(), CurMLK,
I,
nullptr,
Changed,
8490 getAccessKindFromInst(
I));
8491 return AAMemoryLocation::indicatePessimisticFixpoint();
8511 bool operator()(
const AccessInfo &
LHS,
const AccessInfo &
RHS)
const {
8515 return LHS.Ptr <
RHS.Ptr;
8516 if (
LHS.Kind !=
RHS.Kind)
8517 return LHS.Kind <
RHS.Kind;
8524 using AccessSet = SmallSet<AccessInfo, 2, AccessInfo>;
8525 std::array<AccessSet *, llvm::ConstantLog2<VALID_STATE>()>
8526 AccessKind2Accesses;
8531 categorizeArgumentPointerLocations(Attributor &
A, CallBase &CB,
8532 AAMemoryLocation::StateType &AccessedLocs,
8537 categorizeAccessedLocations(Attributor &
A, Instruction &
I,
bool &
Changed);
8540 AccessKind getAccessKindFromInst(
const Instruction *
I) {
8543 AK =
I->mayReadFromMemory() ? READ :
NONE;
8552 void updateStateAndAccessesMap(AAMemoryLocation::StateType &State,
8553 MemoryLocationsKind MLK,
const Instruction *
I,
8562 if (MLK == NO_UNKOWN_MEM)
8564 State.removeAssumedBits(MLK);
8569 void categorizePtrValue(Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8570 AAMemoryLocation::StateType &State,
bool &
Changed,
8571 unsigned AccessAS = 0);
8577void AAMemoryLocationImpl::categorizePtrValue(
8578 Attributor &
A,
const Instruction &
I,
const Value &Ptr,
8580 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize pointer locations for "
8585 unsigned ObjectAS =
Obj.getType()->getPointerAddressSpace();
8587 MemoryLocationsKind MLK = NO_LOCATIONS;
8607 MLK = NO_ARGUMENT_MEM;
8613 if (GVar->isConstant())
8616 if (GV->hasLocalLinkage())
8617 MLK = NO_GLOBAL_INTERNAL_MEM;
8619 MLK = NO_GLOBAL_EXTERNAL_MEM;
8628 bool IsKnownNoAlias;
8632 MLK = NO_MALLOCED_MEM;
8634 MLK = NO_UNKOWN_MEM;
8636 MLK = NO_UNKOWN_MEM;
8639 assert(MLK != NO_LOCATIONS &&
"No location specified!");
8640 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Ptr value can be categorized: "
8641 << Obj <<
" -> " << getMemoryLocationsAsStr(MLK) <<
"\n");
8643 getAccessKindFromInst(&
I));
8648 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
8652 dbgs() <<
"[AAMemoryLocation] Pointer locations not categorized\n");
8653 updateStateAndAccessesMap(
State, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8654 getAccessKindFromInst(&
I));
8659 dbgs() <<
"[AAMemoryLocation] Accessed locations with pointer locations: "
8663void AAMemoryLocationImpl::categorizeArgumentPointerLocations(
8666 for (
unsigned ArgNo = 0,
E = CB.
arg_size(); ArgNo <
E; ++ArgNo) {
8675 const auto *ArgOpMemLocationAA =
8678 if (ArgOpMemLocationAA && ArgOpMemLocationAA->isAssumedReadNone())
8683 categorizePtrValue(
A, CB, *ArgOp, AccessedLocs,
Changed);
8688AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &
A, Instruction &
I,
8690 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Categorize accessed locations for "
8694 AccessedLocs.intersectAssumedBits(NO_LOCATIONS);
8699 const auto *CBMemLocationAA =
A.getAAFor<AAMemoryLocation>(
8702 <<
" [" << CBMemLocationAA <<
"]\n");
8703 if (!CBMemLocationAA) {
8704 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
8705 Changed, getAccessKindFromInst(&
I));
8706 return NO_UNKOWN_MEM;
8709 if (CBMemLocationAA->isAssumedReadNone())
8710 return NO_LOCATIONS;
8712 if (CBMemLocationAA->isAssumedInaccessibleMemOnly()) {
8713 updateStateAndAccessesMap(AccessedLocs, NO_INACCESSIBLE_MEM, &
I,
nullptr,
8714 Changed, getAccessKindFromInst(&
I));
8715 return AccessedLocs.getAssumed();
8718 uint32_t CBAssumedNotAccessedLocs =
8719 CBMemLocationAA->getAssumedNotAccessedLocation();
8722 uint32_t CBAssumedNotAccessedLocsNoArgMem =
8723 CBAssumedNotAccessedLocs | NO_ARGUMENT_MEM | NO_GLOBAL_MEM;
8725 for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2) {
8726 if (CBAssumedNotAccessedLocsNoArgMem & CurMLK)
8728 updateStateAndAccessesMap(AccessedLocs, CurMLK, &
I,
nullptr,
Changed,
8729 getAccessKindFromInst(&
I));
8734 bool HasGlobalAccesses = ((~CBAssumedNotAccessedLocs) & NO_GLOBAL_MEM);
8735 if (HasGlobalAccesses) {
8738 updateStateAndAccessesMap(AccessedLocs, MLK, &
I, Ptr,
Changed,
8739 getAccessKindFromInst(&
I));
8742 if (!CBMemLocationAA->checkForAllAccessesToMemoryKind(
8743 AccessPred, inverseLocation(NO_GLOBAL_MEM,
false,
false)))
8744 return AccessedLocs.getWorstState();
8748 dbgs() <<
"[AAMemoryLocation] Accessed state before argument handling: "
8749 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8752 bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM);
8754 categorizeArgumentPointerLocations(
A, *CB, AccessedLocs,
Changed);
8757 dbgs() <<
"[AAMemoryLocation] Accessed state after argument handling: "
8758 << getMemoryLocationsAsStr(AccessedLocs.getAssumed()) <<
"\n");
8760 return AccessedLocs.getAssumed();
8765 dbgs() <<
"[AAMemoryLocation] Categorize memory access with pointer: "
8766 <<
I <<
" [" << *Ptr <<
"]\n");
8767 categorizePtrValue(
A,
I, *Ptr, AccessedLocs,
Changed,
8768 Ptr->getType()->getPointerAddressSpace());
8769 return AccessedLocs.getAssumed();
8772 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Failed to categorize instruction: "
8774 updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &
I,
nullptr,
Changed,
8775 getAccessKindFromInst(&
I));
8776 return AccessedLocs.getAssumed();
8780struct AAMemoryLocationFunction final :
public AAMemoryLocationImpl {
8781 AAMemoryLocationFunction(
const IRPosition &IRP, Attributor &
A)
8782 : AAMemoryLocationImpl(IRP,
A) {}
8786 const auto *MemBehaviorAA =
8787 A.getAAFor<AAMemoryBehavior>(*
this, getIRPosition(), DepClassTy::NONE);
8790 return indicateOptimisticFixpoint();
8792 "AAMemoryLocation was not read-none but AAMemoryBehavior was!");
8793 A.recordDependence(*MemBehaviorAA, *
this, DepClassTy::OPTIONAL);
8794 return ChangeStatus::UNCHANGED;
8798 auto AssumedState = getAssumed();
8802 MemoryLocationsKind MLK = categorizeAccessedLocations(
A,
I,
Changed);
8803 LLVM_DEBUG(
dbgs() <<
"[AAMemoryLocation] Accessed locations for " <<
I
8804 <<
": " << getMemoryLocationsAsStr(MLK) <<
"\n");
8805 removeAssumedBits(inverseLocation(MLK,
false,
false));
8808 return getAssumedNotAccessedLocation() != VALID_STATE;
8811 bool UsedAssumedInformation =
false;
8812 if (!
A.checkForAllReadWriteInstructions(CheckRWInst, *
this,
8813 UsedAssumedInformation))
8814 return indicatePessimisticFixpoint();
8816 Changed |= AssumedState != getAssumed();
8817 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8820 void trackStatistics()
const override {
8823 else if (isAssumedArgMemOnly())
8825 else if (isAssumedInaccessibleMemOnly())
8827 else if (isAssumedInaccessibleOrArgMemOnly())
8833struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {
8834 AAMemoryLocationCallSite(
const IRPosition &IRP, Attributor &
A)
8835 : AAMemoryLocationImpl(IRP,
A) {}
8845 A.getAAFor<AAMemoryLocation>(*
this, FnPos, DepClassTy::REQUIRED);
8847 return indicatePessimisticFixpoint();
8851 updateStateAndAccessesMap(getState(), MLK,
I, Ptr,
Changed,
8852 getAccessKindFromInst(
I));
8855 if (!FnAA->checkForAllAccessesToMemoryKind(AccessPred, ALL_LOCATIONS))
8856 return indicatePessimisticFixpoint();
8857 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
8860 void trackStatistics()
const override {
8870struct AADenormalFPMathImpl :
public AADenormalFPMath {
8871 AADenormalFPMathImpl(
const IRPosition &IRP, Attributor &
A)
8872 : AADenormalFPMath(IRP,
A) {}
8874 const std::string getAsStr(Attributor *
A)
const override {
8875 std::string Str(
"AADenormalFPMath[");
8876 raw_string_ostream OS(Str);
8878 DenormalState
Known = getKnown();
8879 if (
Known.Mode.isValid())
8880 OS <<
"denormal-fp-math=" <<
Known.Mode;
8884 if (
Known.ModeF32.isValid())
8885 OS <<
" denormal-fp-math-f32=" <<
Known.ModeF32;
8891struct AADenormalFPMathFunction final : AADenormalFPMathImpl {
8892 AADenormalFPMathFunction(
const IRPosition &IRP, Attributor &
A)
8893 : AADenormalFPMathImpl(IRP,
A) {}
8897 DenormalFPEnv DenormEnv =
F->getDenormalFPEnv();
8907 auto CheckCallSite = [=, &Change, &
A](AbstractCallSite CS) {
8910 <<
"->" << getAssociatedFunction()->
getName() <<
'\n');
8912 const auto *CallerInfo =
A.getAAFor<AADenormalFPMath>(
8918 CallerInfo->getState());
8922 bool AllCallSitesKnown =
true;
8923 if (!
A.checkForAllCallSites(CheckCallSite, *
this,
true, AllCallSitesKnown))
8924 return indicatePessimisticFixpoint();
8926 if (Change == ChangeStatus::CHANGED && isModeFixed())
8932 LLVMContext &Ctx = getAssociatedFunction()->getContext();
8938 DenormalFPEnv KnownEnv(
Known.Mode,
Known.ModeF32);
8941 AttrToRemove.
push_back(Attribute::DenormalFPEnv);
8944 Ctx, Attribute::DenormalFPEnv,
8945 DenormalFPEnv(
Known.Mode,
Known.ModeF32).toIntValue()));
8948 auto &IRP = getIRPosition();
8951 return A.removeAttrs(IRP, AttrToRemove) |
8952 A.manifestAttrs(IRP, AttrToAdd,
true);
8955 void trackStatistics()
const override {
8964struct AAValueConstantRangeImpl : AAValueConstantRange {
8965 using StateType = IntegerRangeState;
8966 AAValueConstantRangeImpl(
const IRPosition &IRP, Attributor &
A)
8967 : AAValueConstantRange(IRP,
A) {}
8970 if (
A.hasSimplificationCallback(getIRPosition())) {
8971 indicatePessimisticFixpoint();
8976 intersectKnown(getConstantRangeFromSCEV(
A, getCtxI()));
8979 intersectKnown(getConstantRangeFromLVI(
A, getCtxI()));
8982 const std::string getAsStr(Attributor *
A)
const override {
8984 llvm::raw_string_ostream OS(Str);
8986 getKnown().print(OS);
8988 getAssumed().print(OS);
8995 const SCEV *getSCEV(Attributor &
A,
const Instruction *
I =
nullptr)
const {
8996 if (!getAnchorScope())
8999 ScalarEvolution *SE =
9000 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9003 LoopInfo *LI =
A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(
9009 const SCEV *S = SE->
getSCEV(&getAssociatedValue());
9018 ConstantRange getConstantRangeFromSCEV(Attributor &
A,
9019 const Instruction *
I =
nullptr)
const {
9020 if (!getAnchorScope())
9023 ScalarEvolution *SE =
9024 A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(
9027 const SCEV *S = getSCEV(
A,
I);
9037 getConstantRangeFromLVI(Attributor &
A,
9038 const Instruction *CtxI =
nullptr)
const {
9039 if (!getAnchorScope())
9042 LazyValueInfo *LVI =
9043 A.getInfoCache().getAnalysisResultForFunction<LazyValueAnalysis>(
9058 bool isValidCtxInstructionForOutsideAnalysis(Attributor &
A,
9059 const Instruction *CtxI,
9060 bool AllowAACtxI)
const {
9061 if (!CtxI || (!AllowAACtxI && CtxI == getCtxI()))
9073 InformationCache &InfoCache =
A.getInfoCache();
9074 const DominatorTree *DT =
9084 getAssumedConstantRange(Attributor &
A,
9085 const Instruction *CtxI =
nullptr)
const override {
9090 if (!isValidCtxInstructionForOutsideAnalysis(
A, CtxI,
9092 return getAssumed();
9094 ConstantRange LVIR = getConstantRangeFromLVI(
A, CtxI);
9095 ConstantRange SCEVR = getConstantRangeFromSCEV(
A, CtxI);
9096 return getAssumed().intersectWith(SCEVR).intersectWith(LVIR);
9101 getMDNodeForConstantRange(
Type *Ty, LLVMContext &Ctx,
9102 const ConstantRange &AssumedConstantRange) {
9104 Ty, AssumedConstantRange.
getLower())),
9106 Ty, AssumedConstantRange.
getUpper()))};
9111 static bool isBetterRange(
const ConstantRange &Assumed,
9112 const Instruction &
I) {
9116 std::optional<ConstantRange>
Known;
9120 }
else if (MDNode *KnownRanges =
I.getMetadata(LLVMContext::MD_range)) {
9126 if (KnownRanges->getNumOperands() > 2)
9129 ConstantInt *
Lower =
9131 ConstantInt *
Upper =
9141 setRangeMetadataIfisBetterRange(Instruction *
I,
9142 const ConstantRange &AssumedConstantRange) {
9143 if (isBetterRange(AssumedConstantRange, *
I)) {
9144 I->setMetadata(LLVMContext::MD_range,
9145 getMDNodeForConstantRange(
I->getType(),
I->getContext(),
9146 AssumedConstantRange));
9153 setRangeRetAttrIfisBetterRange(Attributor &
A,
const IRPosition &IRP,
9155 const ConstantRange &AssumedConstantRange) {
9156 if (isBetterRange(AssumedConstantRange, *
I)) {
9157 A.manifestAttrs(IRP,
9158 Attribute::get(
I->getContext(), Attribute::Range,
9159 AssumedConstantRange),
9168 ConstantRange AssumedConstantRange = getAssumedConstantRange(
A);
9171 auto &
V = getAssociatedValue();
9175 assert(
I == getCtxI() &&
"Should not annotate an instruction which is "
9176 "not the context instruction");
9178 if (setRangeMetadataIfisBetterRange(
I, AssumedConstantRange))
9179 Changed = ChangeStatus::CHANGED;
9181 if (setRangeRetAttrIfisBetterRange(
A, getIRPosition(),
I,
9182 AssumedConstantRange))
9183 Changed = ChangeStatus::CHANGED;
9191struct AAValueConstantRangeArgument final
9192 : AAArgumentFromCallSiteArguments<
9193 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9195 using Base = AAArgumentFromCallSiteArguments<
9196 AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,
9198 AAValueConstantRangeArgument(
const IRPosition &IRP, Attributor &
A)
9201 void trackStatistics()
const override {
9206struct AAValueConstantRangeReturned
9207 : AAReturnedFromReturnedValues<AAValueConstantRange,
9208 AAValueConstantRangeImpl,
9209 AAValueConstantRangeImpl::StateType,
9212 AAReturnedFromReturnedValues<AAValueConstantRange,
9213 AAValueConstantRangeImpl,
9214 AAValueConstantRangeImpl::StateType,
9216 AAValueConstantRangeReturned(
const IRPosition &IRP, Attributor &
A)
9220 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9221 indicatePessimisticFixpoint();
9224 void trackStatistics()
const override {
9229struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
9230 AAValueConstantRangeFloating(
const IRPosition &IRP, Attributor &
A)
9231 : AAValueConstantRangeImpl(IRP,
A) {}
9234 AAValueConstantRangeImpl::initialize(
A);
9238 Value &
V = getAssociatedValue();
9241 unionAssumed(ConstantRange(
C->getValue()));
9242 indicateOptimisticFixpoint();
9248 unionAssumed(ConstantRange(APInt(
getBitWidth(), 0)));
9249 indicateOptimisticFixpoint();
9261 if (
auto *RangeMD = LI->getMetadata(LLVMContext::MD_range)) {
9272 indicatePessimisticFixpoint();
9275 << getAssociatedValue() <<
"\n");
9278 bool calculateBinaryOperator(
9279 Attributor &
A, BinaryOperator *BinOp, IntegerRangeState &
T,
9280 const Instruction *CtxI,
9281 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9286 bool UsedAssumedInformation =
false;
9287 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9290 if (!SimplifiedLHS.has_value())
9292 if (!*SimplifiedLHS)
9294 LHS = *SimplifiedLHS;
9296 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9299 if (!SimplifiedRHS.has_value())
9301 if (!*SimplifiedRHS)
9303 RHS = *SimplifiedRHS;
9309 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9311 DepClassTy::REQUIRED);
9315 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9317 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9319 DepClassTy::REQUIRED);
9323 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9325 auto AssumedRange = LHSAARange.binaryOp(BinOp->
getOpcode(), RHSAARange);
9327 T.unionAssumed(AssumedRange);
9331 return T.isValidState();
9334 bool calculateCastInst(
9335 Attributor &
A, CastInst *CastI, IntegerRangeState &
T,
9336 const Instruction *CtxI,
9337 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9343 bool UsedAssumedInformation =
false;
9344 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9347 if (!SimplifiedOpV.has_value())
9349 if (!*SimplifiedOpV)
9351 OpV = *SimplifiedOpV;
9356 auto *OpAA =
A.getAAFor<AAValueConstantRange>(
9358 DepClassTy::REQUIRED);
9362 T.unionAssumed(OpAA->getAssumed().castOp(CastI->
getOpcode(),
9364 return T.isValidState();
9368 calculateCmpInst(Attributor &
A, CmpInst *CmpI, IntegerRangeState &
T,
9369 const Instruction *CtxI,
9370 SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {
9375 bool UsedAssumedInformation =
false;
9376 const auto &SimplifiedLHS =
A.getAssumedSimplified(
9379 if (!SimplifiedLHS.has_value())
9381 if (!*SimplifiedLHS)
9383 LHS = *SimplifiedLHS;
9385 const auto &SimplifiedRHS =
A.getAssumedSimplified(
9388 if (!SimplifiedRHS.has_value())
9390 if (!*SimplifiedRHS)
9392 RHS = *SimplifiedRHS;
9398 auto *LHSAA =
A.getAAFor<AAValueConstantRange>(
9400 DepClassTy::REQUIRED);
9404 auto *RHSAA =
A.getAAFor<AAValueConstantRange>(
9406 DepClassTy::REQUIRED);
9410 auto LHSAARange = LHSAA->getAssumedConstantRange(
A, CtxI);
9411 auto RHSAARange = RHSAA->getAssumedConstantRange(
A, CtxI);
9414 if (LHSAARange.isEmptySet() || RHSAARange.isEmptySet())
9417 bool MustTrue =
false, MustFalse =
false;
9419 auto AllowedRegion =
9422 if (AllowedRegion.intersectWith(LHSAARange).isEmptySet())
9428 assert((!MustTrue || !MustFalse) &&
9429 "Either MustTrue or MustFalse should be false!");
9432 T.unionAssumed(ConstantRange(APInt( 1, 1)));
9434 T.unionAssumed(ConstantRange(APInt( 1, 0)));
9436 T.unionAssumed(ConstantRange( 1,
true));
9438 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] " << *CmpI <<
" after "
9439 << (MustTrue ?
"true" : (MustFalse ?
"false" :
"unknown"))
9440 <<
": " <<
T <<
"\n\t" << *LHSAA <<
"\t<op>\n\t"
9444 return T.isValidState();
9455 bool UsedAssumedInformation =
false;
9456 const auto &SimplifiedOpV =
A.getAssumedSimplified(
9459 if (!SimplifiedOpV.has_value())
9461 if (!*SimplifiedOpV)
9463 Value *VPtr = *SimplifiedOpV;
9466 const auto *AA =
A.getAAFor<AAValueConstantRange>(
9468 DepClassTy::REQUIRED);
9472 T.unionAssumed(AA->getAssumedConstantRange(
A, CtxI));
9476 return T.isValidState();
9481 if (!calculateBinaryOperator(
A, BinOp,
T, CtxI, QuerriedAAs))
9484 if (!calculateCmpInst(
A, CmpI,
T, CtxI, QuerriedAAs))
9487 if (!calculateCastInst(
A, CastI,
T, CtxI, QuerriedAAs))
9493 T.indicatePessimisticFixpoint();
9500 for (
const AAValueConstantRange *QueriedAA : QuerriedAAs) {
9501 if (QueriedAA !=
this)
9504 if (
T.getAssumed() == getState().getAssumed())
9506 T.indicatePessimisticFixpoint();
9509 return T.isValidState();
9512 if (!VisitValueCB(getAssociatedValue(), getCtxI()))
9513 return indicatePessimisticFixpoint();
9518 return ChangeStatus::UNCHANGED;
9519 if (++NumChanges > MaxNumChanges) {
9520 LLVM_DEBUG(
dbgs() <<
"[AAValueConstantRange] performed " << NumChanges
9521 <<
" but only " << MaxNumChanges
9522 <<
" are allowed to avoid cyclic reasoning.");
9523 return indicatePessimisticFixpoint();
9525 return ChangeStatus::CHANGED;
9528 void trackStatistics()
const override {
9537 static constexpr int MaxNumChanges = 5;
9540struct AAValueConstantRangeFunction : AAValueConstantRangeImpl {
9541 AAValueConstantRangeFunction(
const IRPosition &IRP, Attributor &
A)
9542 : AAValueConstantRangeImpl(IRP,
A) {}
9545 llvm_unreachable(
"AAValueConstantRange(Function|CallSite)::updateImpl will "
9552struct AAValueConstantRangeCallSite : AAValueConstantRangeFunction {
9553 AAValueConstantRangeCallSite(
const IRPosition &IRP, Attributor &
A)
9554 : AAValueConstantRangeFunction(IRP,
A) {}
9559struct AAValueConstantRangeCallSiteReturned
9560 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9561 AAValueConstantRangeImpl::StateType,
9563 AAValueConstantRangeCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
9564 : AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,
9565 AAValueConstantRangeImpl::StateType,
9571 if (std::optional<ConstantRange>
Range = CI->getRange())
9572 intersectKnown(*
Range);
9575 AAValueConstantRangeImpl::initialize(
A);
9578 void trackStatistics()
const override {
9582struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating {
9583 AAValueConstantRangeCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
9584 : AAValueConstantRangeFloating(IRP,
A) {}
9587 return ChangeStatus::UNCHANGED;
9590 void trackStatistics()
const override {
9599struct AAPotentialConstantValuesImpl : AAPotentialConstantValues {
9602 AAPotentialConstantValuesImpl(
const IRPosition &IRP, Attributor &
A)
9603 : AAPotentialConstantValues(IRP,
A) {}
9606 if (
A.hasSimplificationCallback(getIRPosition()))
9607 indicatePessimisticFixpoint();
9609 AAPotentialConstantValues::initialize(
A);
9612 bool fillSetWithConstantValues(Attributor &
A,
const IRPosition &IRP, SetTy &S,
9613 bool &ContainsUndef,
bool ForSelf) {
9615 bool UsedAssumedInformation =
false;
9617 UsedAssumedInformation)) {
9624 auto *PotentialValuesAA =
A.getAAFor<AAPotentialConstantValues>(
9625 *
this, IRP, DepClassTy::REQUIRED);
9626 if (!PotentialValuesAA || !PotentialValuesAA->getState().isValidState())
9628 ContainsUndef = PotentialValuesAA->getState().undefIsContained();
9629 S = PotentialValuesAA->getState().getAssumedSet();
9636 ContainsUndef =
false;
9637 for (
auto &It :
Values) {
9639 ContainsUndef =
true;
9645 S.insert(CI->getValue());
9647 ContainsUndef &= S.empty();
9652 const std::string getAsStr(Attributor *
A)
const override {
9654 llvm::raw_string_ostream OS(Str);
9660 return indicatePessimisticFixpoint();
9664struct AAPotentialConstantValuesArgument final
9665 : AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9666 AAPotentialConstantValuesImpl,
9667 PotentialConstantIntValuesState> {
9668 using Base = AAArgumentFromCallSiteArguments<AAPotentialConstantValues,
9669 AAPotentialConstantValuesImpl,
9671 AAPotentialConstantValuesArgument(
const IRPosition &IRP, Attributor &
A)
9674 void trackStatistics()
const override {
9679struct AAPotentialConstantValuesReturned
9680 : AAReturnedFromReturnedValues<AAPotentialConstantValues,
9681 AAPotentialConstantValuesImpl> {
9682 using Base = AAReturnedFromReturnedValues<AAPotentialConstantValues,
9683 AAPotentialConstantValuesImpl>;
9684 AAPotentialConstantValuesReturned(
const IRPosition &IRP, Attributor &
A)
9688 if (!
A.isFunctionIPOAmendable(*getAssociatedFunction()))
9689 indicatePessimisticFixpoint();
9690 Base::initialize(
A);
9693 void trackStatistics()
const override {
9698struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl {
9699 AAPotentialConstantValuesFloating(
const IRPosition &IRP, Attributor &
A)
9700 : AAPotentialConstantValuesImpl(IRP,
A) {}
9703 AAPotentialConstantValuesImpl::initialize(
A);
9707 Value &
V = getAssociatedValue();
9710 unionAssumed(
C->getValue());
9711 indicateOptimisticFixpoint();
9716 unionAssumedWithUndef();
9717 indicateOptimisticFixpoint();
9727 indicatePessimisticFixpoint();
9730 << getAssociatedValue() <<
"\n");
9733 static bool calculateICmpInst(
const ICmpInst *ICI,
const APInt &
LHS,
9738 static APInt calculateCastInst(
const CastInst *CI,
const APInt &Src,
9739 uint32_t ResultBitWidth) {
9744 case Instruction::Trunc:
9745 return Src.trunc(ResultBitWidth);
9746 case Instruction::SExt:
9747 return Src.sext(ResultBitWidth);
9748 case Instruction::ZExt:
9749 return Src.zext(ResultBitWidth);
9750 case Instruction::BitCast:
9755 static APInt calculateBinaryOperator(
const BinaryOperator *BinOp,
9756 const APInt &
LHS,
const APInt &
RHS,
9757 bool &SkipOperation,
bool &Unsupported) {
9764 switch (BinOpcode) {
9768 case Instruction::Add:
9770 case Instruction::Sub:
9772 case Instruction::Mul:
9774 case Instruction::UDiv:
9776 SkipOperation =
true;
9780 case Instruction::SDiv:
9782 SkipOperation =
true;
9786 case Instruction::URem:
9788 SkipOperation =
true;
9792 case Instruction::SRem:
9794 SkipOperation =
true;
9798 case Instruction::Shl:
9800 case Instruction::LShr:
9802 case Instruction::AShr:
9804 case Instruction::And:
9806 case Instruction::Or:
9808 case Instruction::Xor:
9813 bool calculateBinaryOperatorAndTakeUnion(
const BinaryOperator *BinOp,
9814 const APInt &
LHS,
const APInt &
RHS) {
9815 bool SkipOperation =
false;
9818 calculateBinaryOperator(BinOp,
LHS,
RHS, SkipOperation, Unsupported);
9823 unionAssumed(Result);
9824 return isValidState();
9827 ChangeStatus updateWithICmpInst(Attributor &
A, ICmpInst *ICI) {
9828 auto AssumedBefore = getAssumed();
9832 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
9833 SetTy LHSAAPVS, RHSAAPVS;
9835 LHSContainsUndef,
false) ||
9837 RHSContainsUndef,
false))
9838 return indicatePessimisticFixpoint();
9841 bool MaybeTrue =
false, MaybeFalse =
false;
9843 if (LHSContainsUndef && RHSContainsUndef) {
9846 unionAssumedWithUndef();
9847 }
else if (LHSContainsUndef) {
9848 for (
const APInt &R : RHSAAPVS) {
9849 bool CmpResult = calculateICmpInst(ICI,
Zero, R);
9850 MaybeTrue |= CmpResult;
9851 MaybeFalse |= !CmpResult;
9852 if (MaybeTrue & MaybeFalse)
9853 return indicatePessimisticFixpoint();
9855 }
else if (RHSContainsUndef) {
9856 for (
const APInt &L : LHSAAPVS) {
9857 bool CmpResult = calculateICmpInst(ICI, L,
Zero);
9858 MaybeTrue |= CmpResult;
9859 MaybeFalse |= !CmpResult;
9860 if (MaybeTrue & MaybeFalse)
9861 return indicatePessimisticFixpoint();
9864 for (
const APInt &L : LHSAAPVS) {
9865 for (
const APInt &R : RHSAAPVS) {
9866 bool CmpResult = calculateICmpInst(ICI, L, R);
9867 MaybeTrue |= CmpResult;
9868 MaybeFalse |= !CmpResult;
9869 if (MaybeTrue & MaybeFalse)
9870 return indicatePessimisticFixpoint();
9875 unionAssumed(APInt( 1, 1));
9877 unionAssumed(APInt( 1, 0));
9878 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
9879 : ChangeStatus::CHANGED;
9882 ChangeStatus updateWithSelectInst(Attributor &
A, SelectInst *SI) {
9883 auto AssumedBefore = getAssumed();
9887 bool UsedAssumedInformation =
false;
9888 std::optional<Constant *>
C =
A.getAssumedConstant(
9889 *
SI->getCondition(), *
this, UsedAssumedInformation);
9892 bool OnlyLeft =
false, OnlyRight =
false;
9893 if (
C && *
C && (*C)->isOneValue())
9895 else if (
C && *
C && (*C)->isNullValue())
9898 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
9899 SetTy LHSAAPVS, RHSAAPVS;
9902 LHSContainsUndef,
false))
9903 return indicatePessimisticFixpoint();
9907 RHSContainsUndef,
false))
9908 return indicatePessimisticFixpoint();
9910 if (OnlyLeft || OnlyRight) {
9912 auto *OpAA = OnlyLeft ? &LHSAAPVS : &RHSAAPVS;
9913 auto Undef = OnlyLeft ? LHSContainsUndef : RHSContainsUndef;
9916 unionAssumedWithUndef();
9918 for (
const auto &It : *OpAA)
9922 }
else if (LHSContainsUndef && RHSContainsUndef) {
9924 unionAssumedWithUndef();
9926 for (
const auto &It : LHSAAPVS)
9928 for (
const auto &It : RHSAAPVS)
9931 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
9932 : ChangeStatus::CHANGED;
9935 ChangeStatus updateWithCastInst(Attributor &
A, CastInst *CI) {
9936 auto AssumedBefore = getAssumed();
9938 return indicatePessimisticFixpoint();
9943 bool SrcContainsUndef =
false;
9946 SrcContainsUndef,
false))
9947 return indicatePessimisticFixpoint();
9949 if (SrcContainsUndef)
9950 unionAssumedWithUndef();
9952 for (
const APInt &S : SrcPVS) {
9953 APInt
T = calculateCastInst(CI, S, ResultBitWidth);
9957 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
9958 : ChangeStatus::CHANGED;
9961 ChangeStatus updateWithBinaryOperator(Attributor &
A, BinaryOperator *BinOp) {
9962 auto AssumedBefore = getAssumed();
9966 bool LHSContainsUndef =
false, RHSContainsUndef =
false;
9967 SetTy LHSAAPVS, RHSAAPVS;
9969 LHSContainsUndef,
false) ||
9971 RHSContainsUndef,
false))
9972 return indicatePessimisticFixpoint();
9977 if (LHSContainsUndef && RHSContainsUndef) {
9978 if (!calculateBinaryOperatorAndTakeUnion(BinOp,
Zero,
Zero))
9979 return indicatePessimisticFixpoint();
9980 }
else if (LHSContainsUndef) {
9981 for (
const APInt &R : RHSAAPVS) {
9982 if (!calculateBinaryOperatorAndTakeUnion(BinOp,
Zero, R))
9983 return indicatePessimisticFixpoint();
9985 }
else if (RHSContainsUndef) {
9986 for (
const APInt &L : LHSAAPVS) {
9987 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L,
Zero))
9988 return indicatePessimisticFixpoint();
9991 for (
const APInt &L : LHSAAPVS) {
9992 for (
const APInt &R : RHSAAPVS) {
9993 if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
9994 return indicatePessimisticFixpoint();
9998 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
9999 : ChangeStatus::CHANGED;
10002 ChangeStatus updateWithInstruction(Attributor &
A, Instruction *Inst) {
10003 auto AssumedBefore = getAssumed();
10005 bool ContainsUndef;
10007 ContainsUndef,
true))
10008 return indicatePessimisticFixpoint();
10009 if (ContainsUndef) {
10010 unionAssumedWithUndef();
10012 for (
const auto &It : Incoming)
10015 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10016 : ChangeStatus::CHANGED;
10020 Value &
V = getAssociatedValue();
10024 return updateWithICmpInst(
A, ICI);
10027 return updateWithSelectInst(
A, SI);
10030 return updateWithCastInst(
A, CI);
10033 return updateWithBinaryOperator(
A, BinOp);
10036 return updateWithInstruction(
A,
I);
10038 return indicatePessimisticFixpoint();
10041 void trackStatistics()
const override {
10046struct AAPotentialConstantValuesFunction : AAPotentialConstantValuesImpl {
10047 AAPotentialConstantValuesFunction(
const IRPosition &IRP, Attributor &
A)
10048 : AAPotentialConstantValuesImpl(IRP,
A) {}
10052 "AAPotentialConstantValues(Function|CallSite)::updateImpl will "
10056 void trackStatistics()
const override {
10061struct AAPotentialConstantValuesCallSite : AAPotentialConstantValuesFunction {
10062 AAPotentialConstantValuesCallSite(
const IRPosition &IRP, Attributor &
A)
10063 : AAPotentialConstantValuesFunction(IRP,
A) {}
10065 void trackStatistics()
const override {
10070struct AAPotentialConstantValuesCallSiteReturned
10071 : AACalleeToCallSite<AAPotentialConstantValues,
10072 AAPotentialConstantValuesImpl> {
10073 AAPotentialConstantValuesCallSiteReturned(
const IRPosition &IRP,
10075 : AACalleeToCallSite<AAPotentialConstantValues,
10076 AAPotentialConstantValuesImpl>(IRP,
A) {}
10078 void trackStatistics()
const override {
10083struct AAPotentialConstantValuesCallSiteArgument
10084 : AAPotentialConstantValuesFloating {
10085 AAPotentialConstantValuesCallSiteArgument(
const IRPosition &IRP,
10087 : AAPotentialConstantValuesFloating(IRP,
A) {}
10090 AAPotentialConstantValuesImpl::initialize(
A);
10091 if (isAtFixpoint())
10094 Value &
V = getAssociatedValue();
10097 unionAssumed(
C->getValue());
10098 indicateOptimisticFixpoint();
10103 unionAssumedWithUndef();
10104 indicateOptimisticFixpoint();
10110 Value &
V = getAssociatedValue();
10111 auto AssumedBefore = getAssumed();
10112 auto *AA =
A.getAAFor<AAPotentialConstantValues>(
10115 return indicatePessimisticFixpoint();
10116 const auto &S = AA->getAssumed();
10118 return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
10119 : ChangeStatus::CHANGED;
10122 void trackStatistics()
const override {
10131 bool IgnoreSubsumingPositions) {
10132 assert(ImpliedAttributeKind == Attribute::NoUndef &&
10133 "Unexpected attribute kind");
10134 if (
A.hasAttr(IRP, {Attribute::NoUndef}, IgnoreSubsumingPositions,
10135 Attribute::NoUndef))
10154 Value &
V = getAssociatedValue();
10156 indicatePessimisticFixpoint();
10157 assert(!isImpliedByIR(
A, getIRPosition(), Attribute::NoUndef));
10161 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10162 AANoUndef::StateType &State) {
10163 const Value *UseV =
U->get();
10164 const DominatorTree *DT =
nullptr;
10165 AssumptionCache *AC =
nullptr;
10166 InformationCache &InfoCache =
A.getInfoCache();
10172 bool TrackUse =
false;
10180 const std::string getAsStr(Attributor *
A)
const override {
10181 return getAssumed() ?
"noundef" :
"may-undef-or-poison";
10188 bool UsedAssumedInformation =
false;
10189 if (
A.isAssumedDead(getIRPosition(),
nullptr,
nullptr,
10190 UsedAssumedInformation))
10191 return ChangeStatus::UNCHANGED;
10195 if (!
A.getAssumedSimplified(getIRPosition(), *
this, UsedAssumedInformation,
10198 return ChangeStatus::UNCHANGED;
10199 return AANoUndef::manifest(
A);
10203struct AANoUndefFloating :
public AANoUndefImpl {
10204 AANoUndefFloating(
const IRPosition &IRP, Attributor &
A)
10205 : AANoUndefImpl(IRP,
A) {}
10208 AANoUndefImpl::initialize(
A);
10209 if (!getState().isAtFixpoint() && getAnchorScope() &&
10210 !getAnchorScope()->isDeclaration())
10211 if (Instruction *CtxI = getCtxI())
10212 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10216 auto VisitValueCB = [&](
const IRPosition &IRP) ->
bool {
10217 bool IsKnownNoUndef;
10219 A,
this, IRP, DepClassTy::REQUIRED, IsKnownNoUndef);
10223 bool UsedAssumedInformation =
false;
10224 Value *AssociatedValue = &getAssociatedValue();
10226 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
10231 Values.size() != 1 ||
Values.front().getValue() != AssociatedValue;
10239 if (AVIRP == getIRPosition() || !VisitValueCB(AVIRP))
10240 return indicatePessimisticFixpoint();
10241 return ChangeStatus::UNCHANGED;
10244 for (
const auto &VAC :
Values)
10246 return indicatePessimisticFixpoint();
10248 return ChangeStatus::UNCHANGED;
10254struct AANoUndefReturned final
10255 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl> {
10256 AANoUndefReturned(
const IRPosition &IRP, Attributor &
A)
10257 : AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10260 AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>::initialize(
A);
10261 if (isAtFixpoint())
10266 AttributeMask AM = AttributeFuncs::getPoisonGeneratingAttributes();
10267 AttributeSet RetAttrs =
10268 getAssociatedFunction()->getAttributes().getRetAttrs();
10270 indicatePessimisticFixpoint();
10276struct AANoUndefArgument final
10277 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl> {
10278 AANoUndefArgument(
const IRPosition &IRP, Attributor &
A)
10279 : AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10284struct AANoUndefCallSiteArgument final : AANoUndefFloating {
10285 AANoUndefCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10286 : AANoUndefFloating(IRP,
A) {}
10291struct AANoUndefCallSiteReturned final
10292 : AACalleeToCallSite<AANoUndef, AANoUndefImpl> {
10293 AANoUndefCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10294 : AACalleeToCallSite<AANoUndef, AANoUndefImpl>(IRP,
A) {}
10301struct AANoFPClassImpl : AANoFPClass {
10302 AANoFPClassImpl(
const IRPosition &IRP, Attributor &
A) : AANoFPClass(IRP,
A) {}
10305 const IRPosition &IRP = getIRPosition();
10309 indicateOptimisticFixpoint();
10314 A.getAttrs(getIRPosition(), {Attribute::NoFPClass},
Attrs,
false);
10315 for (
const auto &Attr : Attrs) {
10322 const DataLayout &
DL =
A.getDataLayout();
10323 InformationCache &InfoCache =
A.getInfoCache();
10325 const DominatorTree *DT =
nullptr;
10326 AssumptionCache *AC =
nullptr;
10327 const TargetLibraryInfo *
TLI =
nullptr;
10331 if (!
F->isDeclaration()) {
10338 SimplifyQuery Q(
DL,
TLI, DT, AC, CtxI);
10345 followUsesInMBEC(*
this,
A, getState(), *CtxI);
10349 bool followUseInMBEC(Attributor &
A,
const Use *U,
const Instruction *
I,
10350 AANoFPClass::StateType &State) {
10361 if (
auto *NoFPAA =
A.getAAFor<AANoFPClass>(*
this, IRP, DepClassTy::NONE))
10362 State.addKnownBits(NoFPAA->getState().getKnown());
10366 const std::string getAsStr(Attributor *
A)
const override {
10367 std::string
Result =
"nofpclass";
10368 raw_string_ostream OS(Result);
10369 OS << getKnownNoFPClass() <<
'/' << getAssumedNoFPClass();
10373 void getDeducedAttributes(Attributor &
A, LLVMContext &Ctx,
10374 SmallVectorImpl<Attribute> &Attrs)
const override {
10375 Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));
10379struct AANoFPClassFloating :
public AANoFPClassImpl {
10380 AANoFPClassFloating(
const IRPosition &IRP, Attributor &
A)
10381 : AANoFPClassImpl(IRP,
A) {}
10385 bool UsedAssumedInformation =
false;
10386 if (!
A.getAssumedSimplifiedValues(getIRPosition(), *
this,
Values,
10388 Values.push_back({getAssociatedValue(), getCtxI()});
10394 DepClassTy::REQUIRED);
10395 if (!AA ||
this == AA) {
10396 T.indicatePessimisticFixpoint();
10398 const AANoFPClass::StateType &S =
10399 static_cast<const AANoFPClass::StateType &
>(AA->
getState());
10402 return T.isValidState();
10405 for (
const auto &VAC :
Values)
10407 return indicatePessimisticFixpoint();
10412 void trackStatistics()
const override {
10417struct AANoFPClassReturned final
10418 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10419 AANoFPClassImpl::StateType, false,
10420 Attribute::None, false> {
10421 AANoFPClassReturned(
const IRPosition &IRP, Attributor &
A)
10422 : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10423 AANoFPClassImpl::StateType,
false,
10426 void trackStatistics()
const override {
10431struct AANoFPClassArgument final
10432 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {
10433 AANoFPClassArgument(
const IRPosition &IRP, Attributor &
A)
10434 : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10439struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {
10440 AANoFPClassCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
10441 : AANoFPClassFloating(IRP,
A) {}
10443 void trackStatistics()
const override {
10448struct AANoFPClassCallSiteReturned final
10449 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl> {
10450 AANoFPClassCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
10451 : AACalleeToCallSite<AANoFPClass, AANoFPClassImpl>(IRP,
A) {}
10453 void trackStatistics()
const override {
10458struct AACallEdgesImpl :
public AACallEdges {
10459 AACallEdgesImpl(
const IRPosition &IRP, Attributor &
A) : AACallEdges(IRP,
A) {}
10461 const SetVector<Function *> &getOptimisticEdges()
const override {
10462 return CalledFunctions;
10465 bool hasUnknownCallee()
const override {
return HasUnknownCallee; }
10467 bool hasNonAsmUnknownCallee()
const override {
10468 return HasUnknownCalleeNonAsm;
10471 const std::string getAsStr(Attributor *
A)
const override {
10472 return "CallEdges[" + std::to_string(HasUnknownCallee) +
"," +
10473 std::to_string(CalledFunctions.size()) +
"]";
10476 void trackStatistics()
const override {}
10481 static Function *getOnlyCallee(
const CallBase &CB) {
10483 if (Callee && !
Callee->hasMetadata(LLVMContext::MD_callback))
10489 if (CalledFunctions.insert(Fn)) {
10490 Change = ChangeStatus::CHANGED;
10496 void setHasUnknownCallee(
bool NonAsm,
ChangeStatus &Change) {
10497 if (!HasUnknownCallee)
10498 Change = ChangeStatus::CHANGED;
10499 if (NonAsm && !HasUnknownCalleeNonAsm)
10500 Change = ChangeStatus::CHANGED;
10501 HasUnknownCalleeNonAsm |= NonAsm;
10502 HasUnknownCallee =
true;
10507 SetVector<Function *> CalledFunctions;
10510 bool HasUnknownCallee =
false;
10513 bool HasUnknownCalleeNonAsm =
false;
10516struct AACallEdgesCallSite :
public AACallEdgesImpl {
10517 AACallEdgesCallSite(
const IRPosition &IRP, Attributor &
A)
10518 : AACallEdgesImpl(IRP,
A) {}
10524 addCalledFunction(Callee, Change);
10525 indicateOptimisticFixpoint();
10534 addCalledFunction(Fn, Change);
10536 LLVM_DEBUG(
dbgs() <<
"[AACallEdges] Unrecognized value: " <<
V <<
"\n");
10537 setHasUnknownCallee(
true, Change);
10548 VisitValue(*
V, CtxI);
10552 bool UsedAssumedInformation =
false;
10556 Values.push_back({*
V, CtxI});
10558 for (
auto &VAC :
Values)
10565 if (
IA->hasSideEffects() &&
10568 setHasUnknownCallee(
false, Change);
10574 if (
auto *IndirectCallAA =
A.getAAFor<AAIndirectCallInfo>(
10575 *
this, getIRPosition(), DepClassTy::OPTIONAL))
10576 if (IndirectCallAA->foreachCallee(
10577 [&](
Function *Fn) { return VisitValue(*Fn, CB); }))
10586 for (
const Use *U : CallbackUses)
10587 ProcessCalledOperand(
U->get(), CB);
10593struct AACallEdgesFunction :
public AACallEdgesImpl {
10594 AACallEdgesFunction(
const IRPosition &IRP, Attributor &
A)
10595 : AACallEdgesImpl(IRP,
A) {}
10599 bool AllCallsDirect =
true;
10606 if (
Function *Callee = getOnlyCallee(CB)) {
10607 addCalledFunction(Callee, Change);
10611 AllCallsDirect =
false;
10612 auto *CBEdges =
A.getAAFor<AACallEdges>(
10616 if (CBEdges->hasNonAsmUnknownCallee())
10617 setHasUnknownCallee(
true, Change);
10618 if (CBEdges->hasUnknownCallee())
10619 setHasUnknownCallee(
false, Change);
10621 for (
Function *
F : CBEdges->getOptimisticEdges())
10622 addCalledFunction(
F, Change);
10628 bool UsedAssumedInformation =
false;
10629 if (!
A.checkForAllCallLikeInstructions(ProcessCallInst, *
this,
10630 UsedAssumedInformation,
10634 setHasUnknownCallee(
true, Change);
10638 if (AllCallsDirect && !UsedAssumedInformation)
10639 indicateOptimisticFixpoint();
10647struct AAInterFnReachabilityFunction
10648 :
public CachedReachabilityAA<AAInterFnReachability, Function> {
10649 using Base = CachedReachabilityAA<AAInterFnReachability, Function>;
10650 AAInterFnReachabilityFunction(
const IRPosition &IRP, Attributor &
A)
10653 bool instructionCanReach(
10654 Attributor &
A,
const Instruction &From,
const Function &To,
10657 auto *NonConstThis =
const_cast<AAInterFnReachabilityFunction *
>(
this);
10659 RQITy StackRQI(
A, From, To, ExclusionSet,
false);
10660 RQITy::Reachable
Result;
10661 if (!NonConstThis->checkQueryCache(
A, StackRQI, Result))
10662 return NonConstThis->isReachableImpl(
A, StackRQI,
10664 return Result == RQITy::Reachable::Yes;
10668 bool IsTemporaryRQI)
override {
10670 &RQI.From->getFunction()->getEntryBlock().front();
10671 if (EntryI != RQI.From &&
10672 !instructionCanReach(
A, *EntryI, *RQI.To,
nullptr))
10673 return rememberResult(
A, RQITy::Reachable::No, RQI,
false,
10676 auto CheckReachableCallBase = [&](CallBase *CB) {
10677 auto *CBEdges =
A.getAAFor<AACallEdges>(
10679 if (!CBEdges || !CBEdges->getState().isValidState())
10682 if (CBEdges->hasUnknownCallee())
10685 for (
Function *Fn : CBEdges->getOptimisticEdges()) {
10696 if (Fn == getAnchorScope()) {
10697 if (EntryI == RQI.From)
10702 const AAInterFnReachability *InterFnReachability =
10704 DepClassTy::OPTIONAL);
10707 if (!InterFnReachability ||
10715 const auto *IntraFnReachability =
A.getAAFor<AAIntraFnReachability>(
10717 DepClassTy::OPTIONAL);
10725 return IntraFnReachability && !IntraFnReachability->isAssumedReachable(
10726 A, *RQI.From, CBInst, RQI.ExclusionSet);
10729 bool UsedExclusionSet =
true;
10730 bool UsedAssumedInformation =
false;
10731 if (!
A.checkForAllCallLikeInstructions(CheckCallBase, *
this,
10732 UsedAssumedInformation,
10734 return rememberResult(
A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,
10737 return rememberResult(
A, RQITy::Reachable::No, RQI, UsedExclusionSet,
10741 void trackStatistics()
const override {}
10745template <
typename AAType>
10746static std::optional<Constant *>
10749 if (!Ty.isIntegerTy())
10757 std::optional<Constant *> COpt =
AA->getAssumedConstant(
A);
10759 if (!COpt.has_value()) {
10761 return std::nullopt;
10763 if (
auto *
C = *COpt) {
10774 std::optional<Value *> V;
10775 for (
auto &It :
Values) {
10777 if (V.has_value() && !*V)
10780 if (!V.has_value())
10793 if (
A.hasSimplificationCallback(getIRPosition())) {
10794 indicatePessimisticFixpoint();
10797 Value *Stripped = getAssociatedValue().stripPointerCasts();
10799 addValue(
A, getState(), *Stripped, getCtxI(),
AA::AnyScope,
10801 indicateOptimisticFixpoint();
10804 AAPotentialValues::initialize(
A);
10807 const std::string getAsStr(Attributor *
A)
const override {
10809 llvm::raw_string_ostream OS(Str);
10814 template <
typename AAType>
10815 static std::optional<Value *> askOtherAA(Attributor &
A,
10816 const AbstractAttribute &AA,
10817 const IRPosition &IRP,
Type &Ty) {
10822 return std::nullopt;
10829 virtual void addValue(Attributor &
A, StateType &State,
Value &
V,
10835 for (
const auto &U : CB->
args()) {
10845 Type &Ty = *getAssociatedType();
10846 std::optional<Value *> SimpleV =
10847 askOtherAA<AAValueConstantRange>(
A, *
this, ValIRP, Ty);
10848 if (SimpleV.has_value() && !*SimpleV) {
10849 auto *PotentialConstantsAA =
A.getAAFor<AAPotentialConstantValues>(
10850 *
this, ValIRP, DepClassTy::OPTIONAL);
10851 if (PotentialConstantsAA && PotentialConstantsAA->isValidState()) {
10852 for (
const auto &It : PotentialConstantsAA->getAssumedSet())
10853 State.unionAssumed({{*ConstantInt::get(&Ty, It),
nullptr}, S});
10854 if (PotentialConstantsAA->undefIsContained())
10859 if (!SimpleV.has_value())
10871 State.unionAssumed({{*VPtr, CtxI}, S});
10877 AA::ValueAndContext
I;
10881 return II.I ==
I &&
II.S == S;
10884 return std::tie(
I, S) < std::tie(
II.I,
II.S);
10888 bool recurseForValue(Attributor &
A,
const IRPosition &IRP,
AA::ValueScope S) {
10889 SmallMapVector<AA::ValueAndContext, int, 8> ValueScopeMap;
10894 bool UsedAssumedInformation =
false;
10896 if (!
A.getAssumedSimplifiedValues(IRP,
this,
Values, CS,
10897 UsedAssumedInformation))
10901 ValueScopeMap[It] += CS;
10903 for (
auto &It : ValueScopeMap)
10904 addValue(
A, getState(), *It.first.getValue(), It.first.getCtxI(),
10910 void giveUpOnIntraprocedural(Attributor &
A) {
10911 auto NewS = StateType::getBestState(getState());
10912 for (
const auto &It : getAssumedSet()) {
10915 addValue(
A, NewS, *It.first.getValue(), It.first.getCtxI(),
10918 assert(!undefIsContained() &&
"Undef should be an explicit value!");
10925 getState() = StateType::getBestState(getState());
10926 getState().unionAssumed({{getAssociatedValue(), getCtxI()},
AA::AnyScope});
10927 AAPotentialValues::indicateOptimisticFixpoint();
10928 return ChangeStatus::CHANGED;
10932 return indicatePessimisticFixpoint();
10939 if (!getAssumedSimplifiedValues(
A,
Values, S))
10941 Value &OldV = getAssociatedValue();
10944 Value *NewV = getSingleValue(
A, *
this, getIRPosition(),
Values);
10945 if (!NewV || NewV == &OldV)
10950 if (
A.changeAfterManifest(getIRPosition(), *NewV))
10951 return ChangeStatus::CHANGED;
10953 return ChangeStatus::UNCHANGED;
10956 bool getAssumedSimplifiedValues(
10957 Attributor &
A, SmallVectorImpl<AA::ValueAndContext> &
Values,
10958 AA::ValueScope S,
bool RecurseForSelectAndPHI =
false)
const override {
10959 if (!isValidState())
10961 bool UsedAssumedInformation =
false;
10962 for (
const auto &It : getAssumedSet())
10963 if (It.second & S) {
10964 if (RecurseForSelectAndPHI && (
isa<PHINode>(It.first.getValue()) ||
10966 if (
A.getAssumedSimplifiedValues(
10968 this,
Values, S, UsedAssumedInformation))
10971 Values.push_back(It.first);
10973 assert(!undefIsContained() &&
"Undef should be an explicit value!");
10978struct AAPotentialValuesFloating : AAPotentialValuesImpl {
10979 AAPotentialValuesFloating(
const IRPosition &IRP, Attributor &
A)
10980 : AAPotentialValuesImpl(IRP,
A) {}
10983 auto AssumedBefore = getAssumed();
10985 genericValueTraversal(
A, &getAssociatedValue());
10987 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
10988 : ChangeStatus::CHANGED;
10992 struct LivenessInfo {
10993 const AAIsDead *LivenessAA =
nullptr;
10994 bool AnyDead =
false;
11004 SmallVectorImpl<ItemInfo> &Worklist) {
11007 bool UsedAssumedInformation =
false;
11009 auto GetSimplifiedValues = [&](
Value &
V,
11011 if (!
A.getAssumedSimplifiedValues(
11015 Values.push_back(AA::ValueAndContext{
V,
II.I.getCtxI()});
11019 if (GetSimplifiedValues(*
LHS, LHSValues))
11021 if (GetSimplifiedValues(*
RHS, RHSValues))
11026 InformationCache &InfoCache =
A.getInfoCache();
11033 F ?
A.getInfoCache().getTargetLibraryInfoForFunction(*
F) :
nullptr;
11038 const DataLayout &
DL =
A.getDataLayout();
11039 SimplifyQuery Q(
DL,
TLI, DT, AC, CmpI);
11041 auto CheckPair = [&](
Value &LHSV,
Value &RHSV) {
11044 nullptr,
II.S, getAnchorScope());
11050 if (&LHSV == &RHSV &&
11052 Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),
11054 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11061 if (TypedLHS && TypedRHS) {
11063 if (NewV && NewV != &Cmp) {
11064 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11076 if (!LHSIsNull && !RHSIsNull)
11082 assert((LHSIsNull || RHSIsNull) &&
11083 "Expected nullptr versus non-nullptr comparison at this point");
11086 unsigned PtrIdx = LHSIsNull;
11087 bool IsKnownNonNull;
11090 DepClassTy::REQUIRED, IsKnownNonNull);
11091 if (!IsAssumedNonNull)
11097 addValue(
A, getState(), *NewV,
nullptr,
II.S,
11102 for (
auto &LHSValue : LHSValues)
11103 for (
auto &RHSValue : RHSValues)
11104 if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))
11109 bool handleSelectInst(Attributor &
A, SelectInst &SI, ItemInfo
II,
11110 SmallVectorImpl<ItemInfo> &Worklist) {
11112 bool UsedAssumedInformation =
false;
11114 std::optional<Constant *>
C =
11115 A.getAssumedConstant(*
SI.getCondition(), *
this, UsedAssumedInformation);
11116 bool NoValueYet = !
C.has_value();
11124 }
else if (&SI == &getAssociatedValue()) {
11129 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11131 if (!SimpleV.has_value())
11134 addValue(
A, getState(), **SimpleV, CtxI,
II.S, getAnchorScope());
11142 bool handleLoadInst(Attributor &
A, LoadInst &LI, ItemInfo
II,
11143 SmallVectorImpl<ItemInfo> &Worklist) {
11144 SmallSetVector<Value *, 4> PotentialCopies;
11145 SmallSetVector<Instruction *, 4> PotentialValueOrigins;
11146 bool UsedAssumedInformation =
false;
11148 PotentialValueOrigins, *
this,
11149 UsedAssumedInformation,
11151 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Failed to get potentially "
11152 "loaded values for load instruction "
11160 InformationCache &InfoCache =
A.getInfoCache();
11162 if (!
llvm::all_of(PotentialValueOrigins, [&](Instruction *
I) {
11166 return A.isAssumedDead(
SI->getOperandUse(0),
this,
11168 UsedAssumedInformation,
11170 return A.isAssumedDead(*
I,
this,
nullptr,
11171 UsedAssumedInformation,
11174 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Load is onl used by assumes "
11175 "and we cannot delete all the stores: "
11186 bool AllLocal = ScopeIsLocal;
11191 if (!DynamicallyUnique) {
11192 LLVM_DEBUG(
dbgs() <<
"[AAPotentialValues] Not all potentially loaded "
11193 "values are dynamically unique: "
11198 for (
auto *PotentialCopy : PotentialCopies) {
11200 Worklist.
push_back({{*PotentialCopy, CtxI},
II.S});
11205 if (!AllLocal && ScopeIsLocal)
11210 bool handlePHINode(
11211 Attributor &
A, PHINode &
PHI, ItemInfo
II,
11212 SmallVectorImpl<ItemInfo> &Worklist,
11213 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11214 auto GetLivenessInfo = [&](
const Function &
F) -> LivenessInfo & {
11215 LivenessInfo &LI = LivenessAAs[&
F];
11216 if (!LI.LivenessAA)
11222 if (&
PHI == &getAssociatedValue()) {
11223 LivenessInfo &LI = GetLivenessInfo(*
PHI.getFunction());
11225 A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(
11226 *
PHI.getFunction());
11230 for (
unsigned u = 0, e =
PHI.getNumIncomingValues(); u < e; u++) {
11232 if (LI.LivenessAA &&
11233 LI.LivenessAA->isEdgeDead(IncomingBB,
PHI.getParent())) {
11252 bool UsedAssumedInformation =
false;
11253 std::optional<Value *> SimpleV =
A.getAssumedSimplified(
11255 if (!SimpleV.has_value())
11259 addValue(
A, getState(), **SimpleV, &
PHI,
II.S, getAnchorScope());
11266 bool handleGenericInst(Attributor &
A, Instruction &
I, ItemInfo
II,
11267 SmallVectorImpl<ItemInfo> &Worklist) {
11268 bool SomeSimplified =
false;
11269 bool UsedAssumedInformation =
false;
11271 SmallVector<Value *, 8> NewOps(
I.getNumOperands());
11274 const auto &SimplifiedOp =
A.getAssumedSimplified(
11279 if (!SimplifiedOp.has_value())
11283 NewOps[
Idx] = *SimplifiedOp;
11287 SomeSimplified |= (NewOps[
Idx] !=
Op);
11293 if (!SomeSimplified)
11296 InformationCache &InfoCache =
A.getInfoCache();
11300 const auto *
TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*
F);
11303 const DataLayout &
DL =
I.getDataLayout();
11304 SimplifyQuery Q(
DL,
TLI, DT, AC, &
I);
11306 if (!NewV || NewV == &
I)
11309 LLVM_DEBUG(
dbgs() <<
"Generic inst " <<
I <<
" assumed simplified to "
11316 Attributor &
A, Instruction &
I, ItemInfo
II,
11317 SmallVectorImpl<ItemInfo> &Worklist,
11318 SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {
11321 CI->getPredicate(),
II, Worklist);
11323 switch (
I.getOpcode()) {
11324 case Instruction::Select:
11326 case Instruction::PHI:
11328 case Instruction::Load:
11331 return handleGenericInst(
A,
I,
II, Worklist);
11336 void genericValueTraversal(Attributor &
A,
Value *InitialV) {
11337 SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;
11339 SmallSet<ItemInfo, 16> Visited;
11358 LLVM_DEBUG(
dbgs() <<
"Generic value traversal reached iteration limit: "
11359 << Iteration <<
"!\n");
11360 addValue(
A, getState(), *
V, CtxI, S, getAnchorScope());
11366 Value *NewV =
nullptr;
11367 if (
V->getType()->isPointerTy()) {
11373 for (Argument &Arg :
Callee->args())
11380 if (NewV && NewV !=
V) {
11381 Worklist.
push_back({{*NewV, CtxI}, S});
11395 if (
V == InitialV && CtxI == getCtxI()) {
11396 indicatePessimisticFixpoint();
11400 addValue(
A, getState(), *
V, CtxI, S, getAnchorScope());
11401 }
while (!Worklist.
empty());
11405 for (
auto &It : LivenessAAs)
11406 if (It.second.AnyDead)
11407 A.recordDependence(*It.second.LivenessAA, *
this, DepClassTy::OPTIONAL);
11410 void trackStatistics()
const override {
11415struct AAPotentialValuesArgument final : AAPotentialValuesImpl {
11416 using Base = AAPotentialValuesImpl;
11417 AAPotentialValuesArgument(
const IRPosition &IRP, Attributor &
A)
11423 indicatePessimisticFixpoint();
11427 auto AssumedBefore = getAssumed();
11429 unsigned ArgNo = getCalleeArgNo();
11431 bool UsedAssumedInformation =
false;
11433 auto CallSitePred = [&](AbstractCallSite ACS) {
11435 if (CSArgIRP.getPositionKind() == IRP_INVALID)
11438 if (!
A.getAssumedSimplifiedValues(CSArgIRP,
this,
Values,
11440 UsedAssumedInformation))
11443 return isValidState();
11446 if (!
A.checkForAllCallSites(CallSitePred, *
this,
11448 UsedAssumedInformation))
11449 return indicatePessimisticFixpoint();
11451 Function *Fn = getAssociatedFunction();
11452 bool AnyNonLocal =
false;
11453 for (
auto &It :
Values) {
11455 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11460 return indicatePessimisticFixpoint();
11464 addValue(
A, getState(), *It.getValue(), It.getCtxI(),
AA::AnyScope,
11470 AnyNonLocal =
true;
11472 assert(!undefIsContained() &&
"Undef should be an explicit value!");
11474 giveUpOnIntraprocedural(
A);
11476 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11477 : ChangeStatus::CHANGED;
11480 void trackStatistics()
const override {
11485struct AAPotentialValuesReturned :
public AAPotentialValuesFloating {
11486 using Base = AAPotentialValuesFloating;
11487 AAPotentialValuesReturned(
const IRPosition &IRP, Attributor &
A)
11492 if (!
F ||
F->isDeclaration() ||
F->getReturnType()->isVoidTy()) {
11493 indicatePessimisticFixpoint();
11497 for (Argument &Arg :
F->args())
11500 ReturnedArg = &Arg;
11503 if (!
A.isFunctionIPOAmendable(*
F) ||
11504 A.hasSimplificationCallback(getIRPosition())) {
11506 indicatePessimisticFixpoint();
11508 indicateOptimisticFixpoint();
11513 auto AssumedBefore = getAssumed();
11514 bool UsedAssumedInformation =
false;
11517 Function *AnchorScope = getAnchorScope();
11523 UsedAssumedInformation,
11529 bool AllInterAreIntra =
false;
11536 for (
const AA::ValueAndContext &VAC :
Values) {
11537 addValue(
A, getState(), *VAC.
getValue(),
11541 if (AllInterAreIntra)
11548 HandleReturnedValue(*ReturnedArg,
nullptr,
true);
11551 bool AddValues =
true;
11554 addValue(
A, getState(), *RetI.getOperand(0), &RetI,
AA::AnyScope,
11558 return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);
11561 if (!
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11562 UsedAssumedInformation,
11564 return indicatePessimisticFixpoint();
11567 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11568 : ChangeStatus::CHANGED;
11573 return ChangeStatus::UNCHANGED;
11575 if (!getAssumedSimplifiedValues(
A,
Values, AA::ValueScope::Intraprocedural,
11577 return ChangeStatus::UNCHANGED;
11578 Value *NewVal = getSingleValue(
A, *
this, getIRPosition(),
Values);
11580 return ChangeStatus::UNCHANGED;
11585 "Number of function with unique return");
11588 {Attribute::get(Arg->
getContext(), Attribute::Returned)});
11593 Value *RetOp = RetI.getOperand(0);
11597 if (
A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))
11598 Changed = ChangeStatus::CHANGED;
11601 bool UsedAssumedInformation =
false;
11602 (void)
A.checkForAllInstructions(RetInstPred, *
this, {Instruction::Ret},
11603 UsedAssumedInformation,
11609 return AAPotentialValues::indicatePessimisticFixpoint();
11612 void trackStatistics()
const override{
11619struct AAPotentialValuesFunction : AAPotentialValuesImpl {
11620 AAPotentialValuesFunction(
const IRPosition &IRP, Attributor &
A)
11621 : AAPotentialValuesImpl(IRP,
A) {}
11628 void trackStatistics()
const override {
11633struct AAPotentialValuesCallSite : AAPotentialValuesFunction {
11634 AAPotentialValuesCallSite(
const IRPosition &IRP, Attributor &
A)
11635 : AAPotentialValuesFunction(IRP,
A) {}
11637 void trackStatistics()
const override {
11642struct AAPotentialValuesCallSiteReturned : AAPotentialValuesImpl {
11643 AAPotentialValuesCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
11644 : AAPotentialValuesImpl(IRP,
A) {}
11647 auto AssumedBefore = getAssumed();
11651 return indicatePessimisticFixpoint();
11653 bool UsedAssumedInformation =
false;
11657 UsedAssumedInformation))
11658 return indicatePessimisticFixpoint();
11665 Values, S, UsedAssumedInformation))
11668 for (
auto &It :
Values) {
11669 Value *
V = It.getValue();
11670 std::optional<Value *> CallerV =
A.translateArgumentToCallSiteContent(
11671 V, *CB, *
this, UsedAssumedInformation);
11672 if (!CallerV.has_value()) {
11676 V = *CallerV ? *CallerV :
V;
11682 giveUpOnIntraprocedural(
A);
11685 addValue(
A, getState(), *
V, CB, S, getAnchorScope());
11690 return indicatePessimisticFixpoint();
11692 return indicatePessimisticFixpoint();
11693 return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED
11694 : ChangeStatus::CHANGED;
11698 return AAPotentialValues::indicatePessimisticFixpoint();
11701 void trackStatistics()
const override {
11706struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
11707 AAPotentialValuesCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
11708 : AAPotentialValuesFloating(IRP,
A) {}
11710 void trackStatistics()
const override {
11718struct AAAssumptionInfoImpl :
public AAAssumptionInfo {
11719 AAAssumptionInfoImpl(
const IRPosition &IRP, Attributor &
A,
11720 const DenseSet<StringRef> &
Known)
11721 : AAAssumptionInfo(IRP,
A,
Known) {}
11725 if (getKnown().isUniversal())
11726 return ChangeStatus::UNCHANGED;
11728 const IRPosition &IRP = getIRPosition();
11730 getAssumed().getSet().
end());
11732 return A.manifestAttrs(IRP,
11739 bool hasAssumption(
const StringRef Assumption)
const override {
11740 return isValidState() && setContains(Assumption);
11743 const std::string getAsStr(Attributor *
A)
const override {
11744 const SetContents &
Known = getKnown();
11745 const SetContents &Assumed = getAssumed();
11749 const std::string KnownStr =
llvm::join(Set,
",");
11751 std::string AssumedStr =
"Universal";
11752 if (!Assumed.isUniversal()) {
11753 Set.assign(Assumed.getSet().begin(), Assumed.getSet().end());
11756 return "Known [" + KnownStr +
"]," +
" Assumed [" + AssumedStr +
"]";
11771struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {
11772 AAAssumptionInfoFunction(
const IRPosition &IRP, Attributor &
A)
11773 : AAAssumptionInfoImpl(IRP,
A,
11779 auto CallSitePred = [&](AbstractCallSite ACS) {
11780 const auto *AssumptionAA =
A.getAAFor<AAAssumptionInfo>(
11782 DepClassTy::REQUIRED);
11786 Changed |= getIntersection(AssumptionAA->getAssumed());
11787 return !getAssumed().empty() || !getKnown().empty();
11790 bool UsedAssumedInformation =
false;
11795 if (!
A.checkForAllCallSites(CallSitePred, *
this,
true,
11796 UsedAssumedInformation))
11797 return indicatePessimisticFixpoint();
11799 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11802 void trackStatistics()
const override {}
11806struct AAAssumptionInfoCallSite final : AAAssumptionInfoImpl {
11808 AAAssumptionInfoCallSite(
const IRPosition &IRP, Attributor &
A)
11809 : AAAssumptionInfoImpl(IRP,
A, getInitialAssumptions(IRP)) {}
11813 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11818 auto *AssumptionAA =
11819 A.getAAFor<AAAssumptionInfo>(*
this, FnPos, DepClassTy::REQUIRED);
11821 return indicatePessimisticFixpoint();
11822 bool Changed = getIntersection(AssumptionAA->getAssumed());
11823 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11826 void trackStatistics()
const override {}
11831 DenseSet<StringRef> getInitialAssumptions(
const IRPosition &IRP) {
11838 return Assumptions;
11853struct AAUnderlyingObjectsImpl
11858 const std::string getAsStr(
Attributor *
A)
const override {
11859 if (!isValidState())
11860 return "<invalid>";
11863 OS <<
"underlying objects: inter " << InterAssumedUnderlyingObjects.size()
11864 <<
" objects, intra " << IntraAssumedUnderlyingObjects.size()
11866 if (!InterAssumedUnderlyingObjects.empty()) {
11867 OS <<
"inter objects:\n";
11868 for (
auto *Obj : InterAssumedUnderlyingObjects)
11869 OS << *Obj <<
'\n';
11871 if (!IntraAssumedUnderlyingObjects.empty()) {
11872 OS <<
"intra objects:\n";
11873 for (
auto *Obj : IntraAssumedUnderlyingObjects)
11874 OS << *
Obj <<
'\n';
11879 void trackStatistics()
const override {}
11882 auto &Ptr = getAssociatedValue();
11884 bool UsedAssumedInformation =
false;
11885 auto DoUpdate = [&](SmallSetVector<Value *, 8> &UnderlyingObjects,
11887 SmallPtrSet<Value *, 8> SeenObjects;
11891 Scope, UsedAssumedInformation))
11892 return UnderlyingObjects.
insert(&Ptr);
11896 for (
unsigned I = 0;
I <
Values.size(); ++
I) {
11900 if (!SeenObjects.
insert(UO ? UO : Obj).second)
11902 if (UO && UO != Obj) {
11908 const auto *OtherAA =
A.getAAFor<AAUnderlyingObjects>(
11914 Values.emplace_back(
V,
nullptr);
11918 if (!OtherAA || !OtherAA->forallUnderlyingObjects(
Pred, Scope))
11920 "The forall call should not return false at this position");
11926 Changed |= handleIndirect(
A, *Obj, UnderlyingObjects, Scope,
11927 UsedAssumedInformation);
11933 for (
unsigned u = 0, e =
PHI->getNumIncomingValues(); u < e; u++) {
11935 handleIndirect(
A, *
PHI->getIncomingValue(u), UnderlyingObjects,
11936 Scope, UsedAssumedInformation);
11950 if (!UsedAssumedInformation)
11951 indicateOptimisticFixpoint();
11952 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
11955 bool forallUnderlyingObjects(
11958 if (!isValidState())
11959 return Pred(getAssociatedValue());
11962 ? IntraAssumedUnderlyingObjects
11963 : InterAssumedUnderlyingObjects;
11964 for (
Value *Obj : AssumedUnderlyingObjects)
11974 bool handleIndirect(Attributor &
A,
Value &
V,
11975 SmallSetVector<Value *, 8> &UnderlyingObjects,
11978 const auto *AA =
A.getAAFor<AAUnderlyingObjects>(
11984 if (!AA || !AA->forallUnderlyingObjects(
Pred, Scope))
11986 "The forall call should not return false at this position");
11992 SmallSetVector<Value *, 8> IntraAssumedUnderlyingObjects;
11994 SmallSetVector<Value *, 8> InterAssumedUnderlyingObjects;
11997struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl {
11998 AAUnderlyingObjectsFloating(
const IRPosition &IRP, Attributor &
A)
11999 : AAUnderlyingObjectsImpl(IRP,
A) {}
12002struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl {
12003 AAUnderlyingObjectsArgument(
const IRPosition &IRP, Attributor &
A)
12004 : AAUnderlyingObjectsImpl(IRP,
A) {}
12007struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl {
12008 AAUnderlyingObjectsCallSite(
const IRPosition &IRP, Attributor &
A)
12009 : AAUnderlyingObjectsImpl(IRP,
A) {}
12012struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl {
12013 AAUnderlyingObjectsCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12014 : AAUnderlyingObjectsImpl(IRP,
A) {}
12017struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl {
12018 AAUnderlyingObjectsReturned(
const IRPosition &IRP, Attributor &
A)
12019 : AAUnderlyingObjectsImpl(IRP,
A) {}
12022struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl {
12023 AAUnderlyingObjectsCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12024 : AAUnderlyingObjectsImpl(IRP,
A) {}
12027struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {
12028 AAUnderlyingObjectsFunction(
const IRPosition &IRP, Attributor &
A)
12029 : AAUnderlyingObjectsImpl(IRP,
A) {}
12035struct AAGlobalValueInfoFloating :
public AAGlobalValueInfo {
12036 AAGlobalValueInfoFloating(
const IRPosition &IRP, Attributor &
A)
12037 : AAGlobalValueInfo(IRP,
A) {}
12041 bool checkUse(Attributor &
A,
const Use &U,
bool &Follow,
12042 SmallVectorImpl<const Value *> &Worklist) {
12048 if (!GV->hasLocalLinkage() && !
A.isClosedWorldModule())
12054 LLVM_DEBUG(
dbgs() <<
"[AAGlobalValueInfo] Check use: " << *
U.get() <<
" in "
12055 << *UInst <<
"\n");
12058 int Idx = &
Cmp->getOperandUse(0) == &
U;
12061 return U == &getAnchorValue();
12066 auto CallSitePred = [&](AbstractCallSite ACS) {
12067 Worklist.
push_back(ACS.getInstruction());
12070 bool UsedAssumedInformation =
false;
12072 if (!
A.checkForAllCallSites(CallSitePred, *UInst->
getFunction(),
12074 UsedAssumedInformation))
12092 if (!Fn || !
A.isFunctionIPOAmendable(*Fn))
12101 unsigned NumUsesBefore =
Uses.size();
12103 SmallPtrSet<const Value *, 8> Visited;
12107 auto UsePred = [&](
const Use &
U,
bool &Follow) ->
bool {
12115 return checkUse(
A, U, Follow, Worklist);
12117 auto EquivalentUseCB = [&](
const Use &OldU,
const Use &NewU) {
12118 Uses.insert(&OldU);
12122 while (!Worklist.
empty()) {
12124 if (!Visited.
insert(
V).second)
12126 if (!
A.checkForAllUses(UsePred, *
this, *
V,
12128 DepClassTy::OPTIONAL,
12129 true, EquivalentUseCB)) {
12130 return indicatePessimisticFixpoint();
12134 return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED
12135 : ChangeStatus::CHANGED;
12138 bool isPotentialUse(
const Use &U)
const override {
12139 return !isValidState() ||
Uses.contains(&U);
12143 return ChangeStatus::UNCHANGED;
12146 const std::string getAsStr(Attributor *
A)
const override {
12147 return "[" + std::to_string(
Uses.size()) +
" uses]";
12150 void trackStatistics()
const override {
12156 SmallPtrSet<const Use *, 8>
Uses;
12162struct AAIndirectCallInfoCallSite :
public AAIndirectCallInfo {
12163 AAIndirectCallInfoCallSite(
const IRPosition &IRP, Attributor &
A)
12164 : AAIndirectCallInfo(IRP,
A) {}
12167 auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);
12168 if (!MD && !
A.isClosedWorldModule())
12172 for (
const auto &
Op : MD->operands())
12174 PotentialCallees.insert(Callee);
12175 }
else if (
A.isClosedWorldModule()) {
12177 A.getInfoCache().getIndirectlyCallableFunctions(
A);
12178 PotentialCallees.insert_range(IndirectlyCallableFunctions);
12181 if (PotentialCallees.empty())
12182 indicateOptimisticFixpoint();
12190 SmallSetVector<Function *, 4> AssumedCalleesNow;
12191 bool AllCalleesKnownNow = AllCalleesKnown;
12193 auto CheckPotentialCalleeUse = [&](
Function &PotentialCallee,
12194 bool &UsedAssumedInformation) {
12195 const auto *GIAA =
A.getAAFor<AAGlobalValueInfo>(
12197 if (!GIAA || GIAA->isPotentialUse(CalleeUse))
12199 UsedAssumedInformation = !GIAA->isAtFixpoint();
12203 auto AddPotentialCallees = [&]() {
12204 for (
auto *PotentialCallee : PotentialCallees) {
12205 bool UsedAssumedInformation =
false;
12206 if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))
12207 AssumedCalleesNow.
insert(PotentialCallee);
12213 bool UsedAssumedInformation =
false;
12216 AA::ValueScope::AnyScope,
12217 UsedAssumedInformation)) {
12218 if (PotentialCallees.empty())
12219 return indicatePessimisticFixpoint();
12220 AddPotentialCallees();
12225 auto CheckPotentialCallee = [&](
Function &Fn) {
12226 if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))
12229 auto &CachedResult = FilterResults[&Fn];
12230 if (CachedResult.has_value())
12231 return CachedResult.value();
12233 bool UsedAssumedInformation =
false;
12234 if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {
12235 if (!UsedAssumedInformation)
12236 CachedResult =
false;
12245 for (
int I = NumCBArgs;
I < NumFnArgs; ++
I) {
12246 bool IsKnown =
false;
12249 DepClassTy::OPTIONAL, IsKnown)) {
12251 CachedResult =
false;
12256 CachedResult =
true;
12262 for (
auto &VAC :
Values) {
12270 if (CheckPotentialCallee(*VACFn))
12271 AssumedCalleesNow.
insert(VACFn);
12274 if (!PotentialCallees.empty()) {
12275 AddPotentialCallees();
12278 AllCalleesKnownNow =
false;
12281 if (AssumedCalleesNow == AssumedCallees &&
12282 AllCalleesKnown == AllCalleesKnownNow)
12283 return ChangeStatus::UNCHANGED;
12285 std::swap(AssumedCallees, AssumedCalleesNow);
12286 AllCalleesKnown = AllCalleesKnownNow;
12287 return ChangeStatus::CHANGED;
12292 if (!AllCalleesKnown && AssumedCallees.empty())
12293 return ChangeStatus::UNCHANGED;
12296 bool UsedAssumedInformation =
false;
12297 if (
A.isAssumedDead(*CB,
this,
nullptr,
12298 UsedAssumedInformation))
12299 return ChangeStatus::UNCHANGED;
12304 if (
FP->getType()->getPointerAddressSpace() != ProgramAS)
12305 FP =
new AddrSpaceCastInst(
12306 FP, PointerType::get(
FP->getContext(), ProgramAS),
12307 FP->getName() +
".as" + Twine(ProgramAS), CB->
getIterator());
12316 if (AssumedCallees.empty()) {
12317 assert(AllCalleesKnown &&
12318 "Expected all callees to be known if there are none.");
12319 A.changeToUnreachableAfterManifest(CB);
12320 return ChangeStatus::CHANGED;
12324 if (AllCalleesKnown && AssumedCallees.size() == 1) {
12325 auto *NewCallee = AssumedCallees.front();
12328 NumIndirectCallsPromoted++;
12329 return ChangeStatus::CHANGED;
12336 A.deleteAfterManifest(*CB);
12337 return ChangeStatus::CHANGED;
12347 bool SpecializedForAnyCallees =
false;
12348 bool SpecializedForAllCallees = AllCalleesKnown;
12349 ICmpInst *LastCmp =
nullptr;
12352 for (
Function *NewCallee : AssumedCallees) {
12353 if (!
A.shouldSpecializeCallSiteForCallee(*
this, *CB, *NewCallee,
12354 AssumedCallees.size())) {
12355 SkippedAssumedCallees.
push_back(NewCallee);
12356 SpecializedForAllCallees =
false;
12359 SpecializedForAnyCallees =
true;
12365 A.registerManifestAddedBasicBlock(*ThenTI->
getParent());
12366 A.registerManifestAddedBasicBlock(*IP->getParent());
12372 A.registerManifestAddedBasicBlock(*ElseBB);
12374 SplitTI->replaceUsesOfWith(CBBB, ElseBB);
12379 CastInst *RetBC =
nullptr;
12380 CallInst *NewCall =
nullptr;
12385 NumIndirectCallsPromoted++;
12393 auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {
12394 if (!AllCalleesKnown)
12395 return ChangeStatus::UNCHANGED;
12396 MDBuilder MDB(IndirectCB.getContext());
12397 MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);
12398 IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);
12399 return ChangeStatus::CHANGED;
12402 if (!SpecializedForAnyCallees)
12403 return AttachCalleeMetadata(*CB);
12406 if (SpecializedForAllCallees) {
12409 new UnreachableInst(IP->getContext(), IP);
12410 IP->eraseFromParent();
12413 CBClone->setName(CB->
getName());
12414 CBClone->insertBefore(*IP->getParent(), IP);
12415 NewCalls.
push_back({CBClone,
nullptr});
12416 AttachCalleeMetadata(*CBClone);
12423 CB->
getParent()->getFirstInsertionPt());
12424 for (
auto &It : NewCalls) {
12425 CallBase *NewCall = It.first;
12426 Instruction *CallRet = It.second ? It.second : It.first;
12438 A.deleteAfterManifest(*CB);
12439 Changed = ChangeStatus::CHANGED;
12444 const std::string getAsStr(Attributor *
A)
const override {
12445 return std::string(AllCalleesKnown ?
"eliminate" :
"specialize") +
12446 " indirect call site with " + std::to_string(AssumedCallees.size()) +
12450 void trackStatistics()
const override {
12451 if (AllCalleesKnown) {
12453 Eliminated, CallSites,
12454 "Number of indirect call sites eliminated via specialization")
12457 "Number of indirect call sites specialized")
12461 bool foreachCallee(function_ref<
bool(
Function *)> CB)
const override {
12462 return isValidState() && AllCalleesKnown &&
all_of(AssumedCallees, CB);
12467 DenseMap<Function *, std::optional<bool>> FilterResults;
12471 SmallSetVector<Function *, 4> PotentialCallees;
12475 SmallSetVector<Function *, 4> AssumedCallees;
12479 bool AllCalleesKnown =
true;
12486struct AAInvariantLoadPointerImpl
12487 :
public StateWrapper<BitIntegerState<uint8_t, 15>,
12488 AAInvariantLoadPointer> {
12492 IS_NOALIAS = 1 << 0,
12495 IS_NOEFFECT = 1 << 1,
12497 IS_LOCALLY_INVARIANT = 1 << 2,
12499 IS_LOCALLY_CONSTRAINED = 1 << 3,
12501 IS_BEST_STATE = IS_NOALIAS | IS_NOEFFECT | IS_LOCALLY_INVARIANT |
12502 IS_LOCALLY_CONSTRAINED,
12504 static_assert(getBestState() == IS_BEST_STATE,
"Unexpected best state");
12507 StateWrapper<BitIntegerState<uint8_t, 15>, AAInvariantLoadPointer>;
12511 AAInvariantLoadPointerImpl(
const IRPosition &IRP, Attributor &
A)
12514 bool isKnownInvariant()
const final {
12515 return isKnownLocallyInvariant() && isKnown(IS_LOCALLY_CONSTRAINED);
12518 bool isKnownLocallyInvariant()
const final {
12519 if (isKnown(IS_LOCALLY_INVARIANT))
12521 return isKnown(IS_NOALIAS | IS_NOEFFECT);
12524 bool isAssumedInvariant()
const final {
12525 return isAssumedLocallyInvariant() && isAssumed(IS_LOCALLY_CONSTRAINED);
12528 bool isAssumedLocallyInvariant()
const final {
12529 if (isAssumed(IS_LOCALLY_INVARIANT))
12531 return isAssumed(IS_NOALIAS | IS_NOEFFECT);
12538 if (requiresNoAlias() && !isAssumed(IS_NOALIAS))
12539 return indicatePessimisticFixpoint();
12543 Changed |= updateLocalInvariance(
A);
12549 if (!isKnownInvariant())
12550 return ChangeStatus::UNCHANGED;
12553 const Value *Ptr = &getAssociatedValue();
12554 const auto TagInvariantLoads = [&](
const Use &
U,
bool &) {
12555 if (
U.get() != Ptr)
12563 if (!
A.isRunOn(
I->getFunction()))
12566 if (
I->hasMetadata(LLVMContext::MD_invariant_load))
12570 LI->setMetadata(LLVMContext::MD_invariant_load,
12572 Changed = ChangeStatus::CHANGED;
12577 (void)
A.checkForAllUses(TagInvariantLoads, *
this, *Ptr);
12581 const std::string getAsStr(Attributor *)
const override {
12582 if (isKnownInvariant())
12583 return "load-invariant pointer";
12584 return "non-invariant pointer";
12587 void trackStatistics()
const override {}
12591 bool requiresNoAlias()
const {
12592 switch (getPositionKind()) {
12598 case IRP_CALL_SITE:
12600 case IRP_CALL_SITE_RETURNED: {
12605 case IRP_ARGUMENT: {
12606 const Function *
F = getAssociatedFunction();
12607 assert(
F &&
"no associated function for argument");
12613 bool isExternal()
const {
12614 const Function *
F = getAssociatedFunction();
12618 getPositionKind() != IRP_CALL_SITE_RETURNED;
12622 if (isKnown(IS_NOALIAS) || !isAssumed(IS_NOALIAS))
12623 return ChangeStatus::UNCHANGED;
12626 if (
const auto *ANoAlias =
A.getOrCreateAAFor<AANoAlias>(
12627 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12628 if (ANoAlias->isKnownNoAlias()) {
12629 addKnownBits(IS_NOALIAS);
12630 return ChangeStatus::CHANGED;
12633 if (!ANoAlias->isAssumedNoAlias()) {
12634 removeAssumedBits(IS_NOALIAS);
12635 return ChangeStatus::CHANGED;
12638 return ChangeStatus::UNCHANGED;
12643 if (
const Argument *Arg = getAssociatedArgument()) {
12645 addKnownBits(IS_NOALIAS);
12646 return ChangeStatus::UNCHANGED;
12651 removeAssumedBits(IS_NOALIAS);
12652 return ChangeStatus::CHANGED;
12655 return ChangeStatus::UNCHANGED;
12659 if (isKnown(IS_NOEFFECT) || !isAssumed(IS_NOEFFECT))
12660 return ChangeStatus::UNCHANGED;
12662 if (!getAssociatedFunction())
12663 return indicatePessimisticFixpoint();
12666 return indicatePessimisticFixpoint();
12668 const auto HasNoEffectLoads = [&](
const Use &
U,
bool &) {
12670 return !LI || !LI->mayHaveSideEffects();
12672 if (!
A.checkForAllUses(HasNoEffectLoads, *
this, getAssociatedValue()))
12673 return indicatePessimisticFixpoint();
12675 if (
const auto *AMemoryBehavior =
A.getOrCreateAAFor<AAMemoryBehavior>(
12676 getIRPosition(),
this, DepClassTy::REQUIRED)) {
12679 if (!AMemoryBehavior->isAssumedReadOnly())
12680 return indicatePessimisticFixpoint();
12682 if (AMemoryBehavior->isKnownReadOnly()) {
12683 addKnownBits(IS_NOEFFECT);
12684 return ChangeStatus::UNCHANGED;
12687 return ChangeStatus::UNCHANGED;
12690 if (
const Argument *Arg = getAssociatedArgument()) {
12692 addKnownBits(IS_NOEFFECT);
12693 return ChangeStatus::UNCHANGED;
12698 return indicatePessimisticFixpoint();
12701 return ChangeStatus::UNCHANGED;
12705 if (isKnown(IS_LOCALLY_INVARIANT) || !isAssumed(IS_LOCALLY_INVARIANT))
12706 return ChangeStatus::UNCHANGED;
12709 const auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
12710 getIRPosition(),
this, DepClassTy::REQUIRED);
12712 return ChangeStatus::UNCHANGED;
12714 bool UsedAssumedInformation =
false;
12715 const auto IsLocallyInvariantLoadIfPointer = [&](
const Value &
V) {
12716 if (!
V.getType()->isPointerTy())
12718 const auto *IsInvariantLoadPointer =
12720 DepClassTy::REQUIRED);
12722 if (!IsInvariantLoadPointer)
12725 if (IsInvariantLoadPointer->isKnownLocallyInvariant())
12727 if (!IsInvariantLoadPointer->isAssumedLocallyInvariant())
12730 UsedAssumedInformation =
true;
12733 if (!AUO->forallUnderlyingObjects(IsLocallyInvariantLoadIfPointer))
12734 return indicatePessimisticFixpoint();
12740 if (!IsLocallyInvariantLoadIfPointer(*Arg))
12741 return indicatePessimisticFixpoint();
12746 if (!UsedAssumedInformation) {
12748 addKnownBits(IS_LOCALLY_INVARIANT);
12749 return ChangeStatus::CHANGED;
12752 return ChangeStatus::UNCHANGED;
12756struct AAInvariantLoadPointerFloating final : AAInvariantLoadPointerImpl {
12757 AAInvariantLoadPointerFloating(
const IRPosition &IRP, Attributor &
A)
12758 : AAInvariantLoadPointerImpl(IRP,
A) {}
12761struct AAInvariantLoadPointerReturned final : AAInvariantLoadPointerImpl {
12762 AAInvariantLoadPointerReturned(
const IRPosition &IRP, Attributor &
A)
12763 : AAInvariantLoadPointerImpl(IRP,
A) {}
12766 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12770struct AAInvariantLoadPointerCallSiteReturned final
12771 : AAInvariantLoadPointerImpl {
12772 AAInvariantLoadPointerCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
12773 : AAInvariantLoadPointerImpl(IRP,
A) {}
12777 const Function *
F = getAssociatedFunction();
12779 indicatePessimisticFixpoint();
12783 if (!
F->isDeclaration() && !
F->isIntrinsic())
12784 return AAInvariantLoadPointerImpl::initialize(
A);
12789 return AAInvariantLoadPointerImpl::initialize(
A);
12791 if (
F->onlyReadsMemory() &&
F->hasNoSync())
12792 return AAInvariantLoadPointerImpl::initialize(
A);
12796 indicatePessimisticFixpoint();
12800struct AAInvariantLoadPointerArgument final : AAInvariantLoadPointerImpl {
12801 AAInvariantLoadPointerArgument(
const IRPosition &IRP, Attributor &
A)
12802 : AAInvariantLoadPointerImpl(IRP,
A) {}
12805 const Function *
F = getAssociatedFunction();
12806 assert(
F &&
"no associated function for argument");
12809 addKnownBits(IS_LOCALLY_CONSTRAINED);
12813 if (!
F->hasLocalLinkage())
12814 removeAssumedBits(IS_LOCALLY_CONSTRAINED);
12818struct AAInvariantLoadPointerCallSiteArgument final
12819 : AAInvariantLoadPointerImpl {
12820 AAInvariantLoadPointerCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
12821 : AAInvariantLoadPointerImpl(IRP,
A) {}
12828template <
typename InstType>
12829static bool makeChange(Attributor &
A, InstType *MemInst,
const Use &U,
12830 Value *OriginalValue, PointerType *NewPtrTy,
12831 bool UseOriginalValue) {
12832 if (
U.getOperandNo() != InstType::getPointerOperandIndex())
12835 if (MemInst->isVolatile()) {
12836 auto *
TTI =
A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(
12837 *MemInst->getFunction());
12838 unsigned NewAS = NewPtrTy->getPointerAddressSpace();
12843 if (UseOriginalValue) {
12844 A.changeUseAfterManifest(
const_cast<Use &
>(U), *OriginalValue);
12848 Instruction *CastInst =
new AddrSpaceCastInst(OriginalValue, NewPtrTy);
12850 A.changeUseAfterManifest(
const_cast<Use &
>(U), *CastInst);
12854struct AAAddressSpaceImpl :
public AAAddressSpace {
12855 AAAddressSpaceImpl(
const IRPosition &IRP, Attributor &
A)
12856 : AAAddressSpace(IRP,
A) {}
12859 assert(isValidState() &&
"the AA is invalid");
12860 return AssumedAddressSpace;
12864 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
12865 "Associated value is not a pointer");
12867 if (!
A.getInfoCache().getFlatAddressSpace().has_value()) {
12868 indicatePessimisticFixpoint();
12872 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
12873 unsigned AS = getAssociatedType()->getPointerAddressSpace();
12874 if (AS != FlatAS) {
12875 [[maybe_unused]]
bool R = takeAddressSpace(AS);
12876 assert(R &&
"The take should happen");
12877 indicateOptimisticFixpoint();
12882 uint32_t OldAddressSpace = AssumedAddressSpace;
12883 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
12885 auto CheckAddressSpace = [&](
Value &
Obj) {
12891 unsigned ObjAS =
Obj.getType()->getPointerAddressSpace();
12892 if (ObjAS != FlatAS)
12893 return takeAddressSpace(ObjAS);
12907 A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(*F);
12909 if (AssumedAS != ~0U)
12910 return takeAddressSpace(AssumedAS);
12914 return takeAddressSpace(FlatAS);
12917 auto *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(getIRPosition(),
this,
12918 DepClassTy::REQUIRED);
12919 if (!AUO->forallUnderlyingObjects(CheckAddressSpace))
12920 return indicatePessimisticFixpoint();
12922 return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED
12923 : ChangeStatus::CHANGED;
12929 if (NewAS == InvalidAddressSpace ||
12931 return ChangeStatus::UNCHANGED;
12933 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
12935 Value *AssociatedValue = &getAssociatedValue();
12936 Value *OriginalValue = peelAddrspacecast(AssociatedValue, FlatAS);
12939 PointerType::get(getAssociatedType()->
getContext(), NewAS);
12940 bool UseOriginalValue =
12945 auto Pred = [&](
const Use &
U,
bool &) {
12946 if (
U.get() != AssociatedValue)
12957 makeChange(
A, LI, U, OriginalValue, NewPtrTy, UseOriginalValue);
12960 makeChange(
A, SI, U, OriginalValue, NewPtrTy, UseOriginalValue);
12963 makeChange(
A, RMW, U, OriginalValue, NewPtrTy, UseOriginalValue);
12966 makeChange(
A, CmpX, U, OriginalValue, NewPtrTy, UseOriginalValue);
12973 (void)
A.checkForAllUses(
Pred, *
this, getAssociatedValue(),
12976 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
12979 const std::string getAsStr(Attributor *
A)
const override {
12980 if (!isValidState())
12981 return "addrspace(<invalid>)";
12982 return "addrspace(" +
12983 (AssumedAddressSpace == InvalidAddressSpace
12985 : std::to_string(AssumedAddressSpace)) +
12990 uint32_t AssumedAddressSpace = InvalidAddressSpace;
12992 bool takeAddressSpace(uint32_t AS) {
12993 if (AssumedAddressSpace == InvalidAddressSpace) {
12994 AssumedAddressSpace = AS;
12997 return AssumedAddressSpace == AS;
13000 static Value *peelAddrspacecast(
Value *
V,
unsigned FlatAS) {
13002 assert(
I->getSrcAddressSpace() != FlatAS &&
13003 "there should not be flat AS -> non-flat AS");
13004 return I->getPointerOperand();
13007 if (
C->getOpcode() == Instruction::AddrSpaceCast) {
13008 assert(
C->getOperand(0)->getType()->getPointerAddressSpace() !=
13010 "there should not be flat AS -> non-flat AS X");
13011 return C->getOperand(0);
13017struct AAAddressSpaceFloating final : AAAddressSpaceImpl {
13018 AAAddressSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13019 : AAAddressSpaceImpl(IRP,
A) {}
13021 void trackStatistics()
const override {
13026struct AAAddressSpaceReturned final : AAAddressSpaceImpl {
13027 AAAddressSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13028 : AAAddressSpaceImpl(IRP,
A) {}
13033 (void)indicatePessimisticFixpoint();
13036 void trackStatistics()
const override {
13041struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl {
13042 AAAddressSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13043 : AAAddressSpaceImpl(IRP,
A) {}
13045 void trackStatistics()
const override {
13050struct AAAddressSpaceArgument final : AAAddressSpaceImpl {
13051 AAAddressSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13052 : AAAddressSpaceImpl(IRP,
A) {}
13057struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl {
13058 AAAddressSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13059 : AAAddressSpaceImpl(IRP,
A) {}
13064 (void)indicatePessimisticFixpoint();
13067 void trackStatistics()
const override {
13082struct AANoAliasAddrSpaceImpl :
public AANoAliasAddrSpace {
13083 AANoAliasAddrSpaceImpl(
const IRPosition &IRP, Attributor &
A)
13084 : AANoAliasAddrSpace(IRP,
A) {}
13087 assert(getAssociatedType()->isPtrOrPtrVectorTy() &&
13088 "Associated value is not a pointer");
13092 std::optional<unsigned> FlatAS =
A.getInfoCache().getFlatAddressSpace();
13093 if (!FlatAS.has_value()) {
13094 indicatePessimisticFixpoint();
13100 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13101 if (AS != *FlatAS) {
13103 indicateOptimisticFixpoint();
13108 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13109 uint32_t OldAssumed = getAssumed();
13111 auto CheckAddressSpace = [&](
Value &
Obj) {
13115 unsigned AS =
Obj.getType()->getPointerAddressSpace();
13119 removeAS(
Obj.getType()->getPointerAddressSpace());
13123 const AAUnderlyingObjects *AUO =
A.getOrCreateAAFor<AAUnderlyingObjects>(
13124 getIRPosition(),
this, DepClassTy::REQUIRED);
13126 return indicatePessimisticFixpoint();
13128 return OldAssumed == getAssumed() ? ChangeStatus::UNCHANGED
13129 : ChangeStatus::CHANGED;
13133 unsigned FlatAS =
A.getInfoCache().getFlatAddressSpace().value();
13135 unsigned AS = getAssociatedType()->getPointerAddressSpace();
13136 if (AS != FlatAS ||
Map.empty())
13137 return ChangeStatus::UNCHANGED;
13139 LLVMContext &Ctx = getAssociatedValue().getContext();
13140 MDNode *NoAliasASNode =
nullptr;
13141 MDBuilder MDB(Ctx);
13143 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13146 unsigned Upper =
I.stop();
13147 unsigned Lower =
I.start();
13148 if (!NoAliasASNode) {
13149 NoAliasASNode = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13152 MDNode *ASRange = MDB.createRange(APInt(32,
Lower), APInt(32,
Upper + 1));
13156 Value *AssociatedValue = &getAssociatedValue();
13159 auto AddNoAliasAttr = [&](
const Use &
U,
bool &) {
13160 if (
U.get() != AssociatedValue)
13163 if (!Inst || Inst->
hasMetadata(LLVMContext::MD_noalias_addrspace))
13170 Inst->
setMetadata(LLVMContext::MD_noalias_addrspace, NoAliasASNode);
13174 (void)
A.checkForAllUses(AddNoAliasAttr, *
this, *AssociatedValue,
13176 return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
13179 const std::string getAsStr(Attributor *
A)
const override {
13180 if (!isValidState())
13181 return "<invalid>";
13183 raw_string_ostream OS(Str);
13184 OS <<
"CanNotBeAddrSpace(";
13185 for (RangeMap::const_iterator
I =
Map.begin();
I !=
Map.end();
I++) {
13186 unsigned Upper =
I.stop();
13187 unsigned Lower =
I.start();
13188 OS <<
' ' <<
'[' <<
Upper <<
',' <<
Lower + 1 <<
')';
13195 void removeAS(
unsigned AS) {
13196 RangeMap::iterator
I =
Map.find(AS);
13198 if (
I !=
Map.end()) {
13199 unsigned Upper =
I.stop();
13200 unsigned Lower =
I.start();
13204 if (AS != ~((
unsigned)0) && AS + 1 <=
Upper)
13206 if (AS != 0 &&
Lower <= AS - 1)
13211 void resetASRanges(Attributor &
A) {
13213 Map.insert(0,
A.getInfoCache().getMaxAddrSpace(),
true);
13217struct AANoAliasAddrSpaceFloating final : AANoAliasAddrSpaceImpl {
13218 AANoAliasAddrSpaceFloating(
const IRPosition &IRP, Attributor &
A)
13219 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13221 void trackStatistics()
const override {
13226struct AANoAliasAddrSpaceReturned final : AANoAliasAddrSpaceImpl {
13227 AANoAliasAddrSpaceReturned(
const IRPosition &IRP, Attributor &
A)
13228 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13230 void trackStatistics()
const override {
13235struct AANoAliasAddrSpaceCallSiteReturned final : AANoAliasAddrSpaceImpl {
13236 AANoAliasAddrSpaceCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13237 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13239 void trackStatistics()
const override {
13244struct AANoAliasAddrSpaceArgument final : AANoAliasAddrSpaceImpl {
13245 AANoAliasAddrSpaceArgument(
const IRPosition &IRP, Attributor &
A)
13246 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13248 void trackStatistics()
const override {
13253struct AANoAliasAddrSpaceCallSiteArgument final : AANoAliasAddrSpaceImpl {
13254 AANoAliasAddrSpaceCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13255 : AANoAliasAddrSpaceImpl(IRP,
A) {}
13257 void trackStatistics()
const override {
13264struct AAAllocationInfoImpl :
public AAAllocationInfo {
13265 AAAllocationInfoImpl(
const IRPosition &IRP, Attributor &
A)
13266 : AAAllocationInfo(IRP,
A) {}
13268 std::optional<TypeSize> getAllocatedSize()
const override {
13269 assert(isValidState() &&
"the AA is invalid");
13270 return AssumedAllocatedSize;
13273 std::optional<TypeSize> findInitialAllocationSize(Instruction *
I,
13274 const DataLayout &
DL) {
13277 switch (
I->getOpcode()) {
13278 case Instruction::Alloca: {
13283 return std::nullopt;
13289 const IRPosition &IRP = getIRPosition();
13294 return indicatePessimisticFixpoint();
13296 bool IsKnownNoCapture;
13298 A,
this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture))
13299 return indicatePessimisticFixpoint();
13301 const AAPointerInfo *PI =
13302 A.getOrCreateAAFor<AAPointerInfo>(IRP, *
this, DepClassTy::REQUIRED);
13305 return indicatePessimisticFixpoint();
13308 return indicatePessimisticFixpoint();
13310 const DataLayout &
DL =
A.getDataLayout();
13311 const auto AllocationSize = findInitialAllocationSize(
I,
DL);
13314 if (!AllocationSize)
13315 return indicatePessimisticFixpoint();
13319 if (*AllocationSize == 0)
13320 return indicatePessimisticFixpoint();
13326 return indicatePessimisticFixpoint();
13328 if (BinSize == 0) {
13329 auto NewAllocationSize = std::make_optional<TypeSize>(0,
false);
13330 if (!changeAllocationSize(NewAllocationSize))
13331 return ChangeStatus::UNCHANGED;
13332 return ChangeStatus::CHANGED;
13336 const auto &It = PI->
begin();
13339 if (It->first.Offset != 0)
13340 return indicatePessimisticFixpoint();
13342 uint64_t SizeOfBin = It->first.Offset + It->first.Size;
13344 if (SizeOfBin >= *AllocationSize)
13345 return indicatePessimisticFixpoint();
13347 auto NewAllocationSize = std::make_optional<TypeSize>(SizeOfBin * 8,
false);
13349 if (!changeAllocationSize(NewAllocationSize))
13350 return ChangeStatus::UNCHANGED;
13352 return ChangeStatus::CHANGED;
13357 assert(isValidState() &&
13358 "Manifest should only be called if the state is valid.");
13362 auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
13364 unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
13366 switch (
I->getOpcode()) {
13368 case Instruction::Alloca: {
13372 Type *CharType = Type::getInt8Ty(
I->getContext());
13374 auto *NumBytesToValue =
13375 ConstantInt::get(
I->getContext(), APInt(32, NumBytesToAllocate));
13378 insertPt = std::next(insertPt);
13379 AllocaInst *NewAllocaInst =
13384 return ChangeStatus::CHANGED;
13392 return ChangeStatus::UNCHANGED;
13395 const std::string getAsStr(Attributor *
A)
const override {
13396 if (!isValidState())
13397 return "allocationinfo(<invalid>)";
13398 return "allocationinfo(" +
13399 (AssumedAllocatedSize == HasNoAllocationSize
13401 : std::to_string(AssumedAllocatedSize->getFixedValue())) +
13406 std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
13410 bool changeAllocationSize(std::optional<TypeSize>
Size) {
13411 if (AssumedAllocatedSize == HasNoAllocationSize ||
13412 AssumedAllocatedSize !=
Size) {
13413 AssumedAllocatedSize =
Size;
13420struct AAAllocationInfoFloating : AAAllocationInfoImpl {
13421 AAAllocationInfoFloating(
const IRPosition &IRP, Attributor &
A)
13422 : AAAllocationInfoImpl(IRP,
A) {}
13424 void trackStatistics()
const override {
13429struct AAAllocationInfoReturned : AAAllocationInfoImpl {
13430 AAAllocationInfoReturned(
const IRPosition &IRP, Attributor &
A)
13431 : AAAllocationInfoImpl(IRP,
A) {}
13436 (void)indicatePessimisticFixpoint();
13439 void trackStatistics()
const override {
13444struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl {
13445 AAAllocationInfoCallSiteReturned(
const IRPosition &IRP, Attributor &
A)
13446 : AAAllocationInfoImpl(IRP,
A) {}
13448 void trackStatistics()
const override {
13453struct AAAllocationInfoArgument : AAAllocationInfoImpl {
13454 AAAllocationInfoArgument(
const IRPosition &IRP, Attributor &
A)
13455 : AAAllocationInfoImpl(IRP,
A) {}
13457 void trackStatistics()
const override {
13462struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl {
13463 AAAllocationInfoCallSiteArgument(
const IRPosition &IRP, Attributor &
A)
13464 : AAAllocationInfoImpl(IRP,
A) {}
13468 (void)indicatePessimisticFixpoint();
13471 void trackStatistics()
const override {
13520#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \
13521 case IRPosition::PK: \
13522 llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");
13524#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \
13525 case IRPosition::PK: \
13526 AA = new (A.Allocator) CLASS##SUFFIX(IRP, A); \
13530#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13531 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13532 CLASS *AA = nullptr; \
13533 switch (IRP.getPositionKind()) { \
13534 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13535 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13536 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13537 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13538 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13539 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13540 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13541 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13546#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13547 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13548 CLASS *AA = nullptr; \
13549 switch (IRP.getPositionKind()) { \
13550 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13551 SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \
13552 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13553 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13554 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13555 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13556 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13557 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13562#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS) \
13563 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13564 CLASS *AA = nullptr; \
13565 switch (IRP.getPositionKind()) { \
13566 SWITCH_PK_CREATE(CLASS, IRP, POS, SUFFIX) \
13568 llvm_unreachable("Cannot create " #CLASS " for position otherthan " #POS \
13574#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13575 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13576 CLASS *AA = nullptr; \
13577 switch (IRP.getPositionKind()) { \
13578 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13579 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13580 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13581 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13582 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13583 SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
13584 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13585 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13590#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13591 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13592 CLASS *AA = nullptr; \
13593 switch (IRP.getPositionKind()) { \
13594 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13595 SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
13596 SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
13597 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13598 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
13599 SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
13600 SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
13601 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13606#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
13607 CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
13608 CLASS *AA = nullptr; \
13609 switch (IRP.getPositionKind()) { \
13610 SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
13611 SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
13612 SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
13613 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
13614 SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
13615 SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
13616 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
13617 SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
13669#undef CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION
13670#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
13671#undef CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION
13672#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
13673#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION
13674#undef CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION
13675#undef SWITCH_PK_CREATE
13676#undef SWITCH_PK_INV
const TargetLowering & TLI
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
Expand Atomic instructions
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 bool collectTailCalls(Attributor &A, const AbstractAttribute &QueryingAA, SmallVectorImpl< CallInst * > &TailCalls)
Collect the non-musttail tail calls in the function of QueryingAA.
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)
#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)
static bool mayBeInCycle(const CycleInfo *CI, const Instruction *I, bool HeaderOnly, CycleRef *CPtr=nullptr)
#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)
bpf unwind BPF Unwind Lower
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool isReachableImpl(SmallVectorImpl< BasicBlock * > &Worklist, const StopSetT &StopSet, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet, const DominatorTree *DT, const LoopInfo *LI, const CycleInfo *CI)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file declares an analysis pass that computes CycleInfo for LLVM IR, specialized from GenericCycl...
static uint64_t align(uint64_t Size)
DXIL Forward Handle Accesses
This file defines DenseMapInfo traits for DenseMap.
This file defines the DenseMap class.
static Value * getCondition(Instruction *I)
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
static unsigned getAddressSpace(const Value *V, unsigned MaxLookup)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
static StringRef getName(Value *V)
dot regions Print regions of function to dot true view regions View regions of function(with no function bodies)"
Remove Loads Into Fake Uses
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
std::pair< BasicBlock *, BasicBlock * > Edge
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
This file defines generic set operations that may be used on set's of different types,...
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static SymbolRef::Type getType(const Symbol *Sym)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type.
static unsigned getSize(unsigned Kind)
LLVM_ABI AACallGraphNode * operator*() const
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A trivial helper function to check to see if the specified pointers are no-alias.
Class for arbitrary precision integers.
int64_t getSExtValue() const
Get sign extended value.
CallBase * getInstruction() const
Return the underlying instruction.
bool isCallbackCall() const
Return true if this ACS represents a callback call.
bool isDirectCall() const
Return true if this ACS represents a direct call.
static LLVM_ABI void getCallbackUses(const CallBase &CB, SmallVectorImpl< const Use * > &CallbackUses)
Add operand uses of CB that represent callback uses into CallbackUses.
int getCallArgOperandNo(Argument &Arg) const
Return the operand index of the underlying instruction associated with Arg.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
unsigned getAddressSpace() const
Return the address space for the allocation.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
This class represents an incoming formal argument to a Function.
LLVM_ABI bool hasNoAliasAttr() const
Return true if this argument has the noalias attribute.
LLVM_ABI bool onlyReadsMemory() const
Return true if this argument has the readonly or readnone attribute.
LLVM_ABI bool hasPointeeInMemoryValueAttr() const
Return true if this argument has the byval, sret, inalloca, preallocated, or byref attribute.
LLVM_ABI bool hasReturnedAttr() const
Return true if this argument has the returned attribute.
LLVM_ABI bool hasByValAttr() const
Return true if this argument has the byval attribute.
const Function * getParent() const
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
bool contains(Attribute::AttrKind A) const
Return true if the builder has the specified attribute.
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.
static LLVM_ABI Attribute getWithCaptureInfo(LLVMContext &Context, CaptureInfo CI)
static bool isEnumAttrKind(AttrKind Kind)
bool isValid() const
Return true if the attribute is any kind of attribute.
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
LLVM_ABI CaptureInfo getCaptureInfo() const
Returns information from captures attribute.
LLVM Basic Block Representation.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Instruction & front() const
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
BinaryOps getOpcode() const
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
LLVM_ABI MemoryEffects getMemoryEffects() const
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
Value * getCalledOperand() const
const Use & getCalledOperandUse() const
Attribute getFnAttr(StringRef Kind) const
Get the attribute of a given kind for the function.
const Use & getArgOperandUse(unsigned i) const
Wrappers for getting the Use of a call argument.
OperandBundleUse getOperandBundleForOperand(unsigned OpIdx) const
Return the operand bundle for the operand at index OpIdx.
LLVM_ABI std::optional< ConstantRange > getRange() const
If this return value has a range attribute, return the value range of the argument.
Value * getArgOperand(unsigned i) const
bool isBundleOperand(unsigned Idx) const
Return true if the operand at index Idx is a bundle operand.
bool isConvergent() const
Determine if the invoke is convergent.
FunctionType * getFunctionType() const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static CaptureInfo none()
Create CaptureInfo that does not capture any components of the pointer.
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
LLVM_ABI bool isIntegerCast() const
There are several places where we need to know if a cast instruction only deals with integer source a...
Type * getDestTy() const
Return the destination type, as a convenience.
bool isEquality() const
Determine if this is an equals/not equals predicate.
bool isFalseWhenEqual() const
This is just a convenience.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
bool isTrueWhenEqual() const
This is just a convenience.
Predicate getPredicate() const
Return the predicate for this instruction.
Conditional Branch instruction.
Value * getCondition() const
BasicBlock * getSuccessor(unsigned i) const
static LLVM_ABI Constant * getExtractElement(Constant *Vec, Constant *Idx, Type *OnlyIfReducedTy=nullptr)
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
This class represents a range of values.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
LLVM_ABI bool isEmptySet() const
Return true if this set contains no members.
bool isSingleElement() const
Return true if this set contains exactly one member.
static LLVM_ABI ConstantRange makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other)
Produce the smallest range such that all values that may satisfy the given predicate with any value c...
const APInt & getUpper() const
Return the upper value for this range.
LLVM_ABI bool contains(const APInt &Val) const
Return true if the specified value is in the set.
Opaque handle to a cycle within a GenericCycleInfo that wraps the cycle's preorder index.
A parsed version of the target data layout string in and methods for querying it.
unsigned getProgramAddressSpace() const
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
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.
BlockT * getHeader(CycleRef C) const
CycleRef getCycle(const BlockT *Block) const
Find the innermost cycle containing 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
PointerType * getType() const
Global values are always pointers.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
Value * CreatePtrAddWithSignedOffset(Value *Ptr, int64_t Offset, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
Create a ptradd with a signed constant offset.
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.
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.
iterator_range< user_iterator > users()
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.
LLVM_ABI bool mayReadOrWriteMemory() const LLVM_READONLY
Return true if this instruction may read or write memory.
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.
FPClassTest getKnownFPClasses() const
Floating-point classes the value could be one of.
This is an important class for using LLVM in a threaded context.
LLVM_ABI ConstantRange getConstantRange(Value *V, Instruction *CtxI, 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 SCEVUse getSCEVAtScope(const SCEV *S, const Loop *L)
Return a SCEV expression for the specified value at the specified scope in the program.
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI unsigned getSmallConstantMaxTripCount(const Loop *L, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Returns the upper bound of the loop trip count as a normal unsigned value.
ConstantRange getUnsignedRange(const SCEV *S)
Determine the unsigned range for a particular SCEV.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
TypeSize getElementOffset(unsigned Idx) const
TypeSize getSizeInBits() const
TypeSize getElementOffsetInBits(unsigned Idx) const
Class to represent struct types.
unsigned getNumElements() const
Random access to the elements.
Type * getElementType(unsigned N) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isPointerTy() const
True if this is an instance of PointerType.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
bool isPtrOrPtrVectorTy() const
Return true if this is a pointer type or a vector of pointer types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
bool isVoidTy() const
Return true if this is 'void'.
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
BasicBlock * getSuccessor(unsigned i=0) const
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
User * getUser() const
Returns the User that contains this Use.
const Use & getOperandUse(unsigned i) const
LLVM_ABI bool isDroppable() const
A droppable user is a user for which uses can be dropped without affecting correctness and should be ...
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
unsigned getNumOperands() const
ValueT lookup(const KeyT &Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
static constexpr uint64_t MaximumAlignment
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
LLVM_ABI const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr, bool LookThroughIntToPtr=false) const
Accumulate the constant offset this value has compared to a base pointer.
static constexpr unsigned MaxAlignmentExponent
The maximum alignment for instructions.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
constexpr ScalarTy getFixedValue() const
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
SetVector< Function * >::iterator I
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
LLVM_ABI bool isAssumedReadNone(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readnone.
LLVM_ABI bool isAssumedReadOnly(Attributor &A, const IRPosition &IRP, const AbstractAttribute &QueryingAA, bool &IsKnown)
Return true if IRP is readonly.
raw_ostream & operator<<(raw_ostream &OS, const RangeTy &R)
LLVM_ABI std::optional< Value * > combineOptionalValuesInAAValueLatice(const std::optional< Value * > &A, const std::optional< Value * > &B, Type *Ty)
Return the combination of A and B such that the result is a possible value of both.
LLVM_ABI bool isValidAtPosition(const ValueAndContext &VAC, InformationCache &InfoCache)
Return true if the value of VAC is a valid at the position of VAC, that is a constant,...
LLVM_ABI bool isAssumedThreadLocalObject(Attributor &A, Value &Obj, const AbstractAttribute &QueryingAA)
Return true if Obj is assumed to be a thread local object.
LLVM_ABI bool isGPUConstantAddressSpace(const Module &M, unsigned AS)
Check if the given address space AS corresponds to a GPU constant address space for the target triple...
LLVM_ABI bool isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA, const Value &V, bool ForAnalysisOnly=true)
Return true if V is dynamically unique, that is, there are no two "instances" of V at runtime with di...
LLVM_ABI bool getPotentialCopiesOfStoredValue(Attributor &A, StoreInst &SI, SmallSetVector< Value *, 4 > &PotentialCopies, const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, bool OnlyExact=false)
Collect all potential values of the one stored by SI into PotentialCopies.
LLVM_ABI bool isGPUSharedAddressSpace(const Module &M, unsigned AS)
Check if the given address space AS corresponds to a GPU shared address space for the target triple i...
LLVM_ABI bool isGPULocalAddressSpace(const Module &M, unsigned AS)
Check if the given address space AS corresponds to a GPU local/private address space for the target t...
SmallPtrSet< Instruction *, 4 > InstExclusionSetTy
LLVM_ABI bool isGPU(const Module &M)
Return true iff M target a GPU (and we can use GPU AS reasoning).
ValueScope
Flags to distinguish intra-procedural queries from potentially inter-procedural queries.
LLVM_ABI bool isValidInScope(const Value &V, const Function *Scope)
Return true if V is a valid value in Scope, that is a constant or an instruction/argument of Scope.
LLVM_ABI bool isPotentiallyReachable(Attributor &A, const Instruction &FromI, const Instruction &ToI, const AbstractAttribute &QueryingAA, const AA::InstExclusionSetTy *ExclusionSet=nullptr, std::function< bool(const Function &F)> GoBackwardsCB=nullptr)
Return true if ToI is potentially reachable from FromI without running into any instruction in Exclus...
LLVM_ABI bool isNoSyncInst(Attributor &A, const Instruction &I, const AbstractAttribute &QueryingAA)
Return true if I is a nosync instruction.
bool hasAssumedIRAttr(Attributor &A, const AbstractAttribute *QueryingAA, const IRPosition &IRP, DepClassTy DepClass, bool &IsKnown, bool IgnoreSubsumingPositions=false, const AAType **AAPtr=nullptr)
Helper to avoid creating an AA for IR Attributes that might already be set.
LLVM_ABI bool getPotentiallyLoadedValues(Attributor &A, LoadInst &LI, SmallSetVector< Value *, 4 > &PotentialValues, SmallSetVector< Instruction *, 4 > &PotentialValueOrigins, const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, bool OnlyExact=false)
Collect all potential values LI could read into PotentialValues.
LLVM_ABI Value * getWithType(Value &V, Type &Ty)
Try to convert V to type Ty without introducing new instructions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ BasicBlock
Various leaf nodes.
@ Unsupported
This operation is completely unsupported on the target.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
@ Valid
The data is already valid.
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
unsigned combineHashValue(unsigned a, unsigned b)
Simplistic combination of 32-bit hash values into 32-bit hash values.
ElementType
The element type of an SRV or UAV resource.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
@ User
could "use" a pointer
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
bool operator<(int64_t V1, const APSInt &V2)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt gcd(const DynamicAPInt &A, const DynamicAPInt &B)
LLVM_ABI KnownFPClass computeKnownFPClass(const Value *V, const APInt &DemandedElts, FPClassTest InterestedClasses, const SimplifyQuery &SQ, unsigned Depth=0)
Determine which floating-point classes are valid for V, and return them in KnownFPClass bit sets.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI bool isLegalToPromote(const CallBase &CB, Function *Callee, const char **FailureReason=nullptr)
Return true if the given indirect call site can be made to call Callee.
LLVM_ABI Constant * getInitialValueOfAllocation(const Value *V, const TargetLibraryInfo *TLI, Type *Ty)
If this is a call to an allocation function that initializes memory to a fixed value,...
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
RelativeUniformCounterPtr Values
BundleAttr getBundleAttrFromOBU(OperandBundleUse OBU)
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
auto pred_end(const MachineBasicBlock *BB)
unsigned getPointerAddressSpace(const Type *T)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
LLVM_ABI bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI)
Return true if this is a call to an allocation function that does not have side effects that we are r...
APFloat abs(APFloat X)
Returns the absolute value of the argument.
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
LLVM_ABI raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
LLVM_ABI Value * getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI)
Gets the alignment argument for an aligned_alloc-like function, using either built-in knowledge based...
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
LLVM_ABI Value * simplifyInstructionWithOperands(Instruction *I, ArrayRef< Value * > NewOps, const SimplifyQuery &Q)
Like simplifyInstruction but the operands of I are replaced with NewOps.
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
LLVM_ABI bool isNoAliasCall(const Value *V)
Return true if this pointer is returned by a noalias function.
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
LLVM_ABI bool isSafeToSpeculativelyExecute(const Instruction *I, const Instruction *CtxI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr, bool UseVariableInfo=true, bool IgnoreUBImplyingAttrs=true)
Return true if the instruction does not have any effects besides calculating the result and does not ...
bool isa_and_nonnull(const Y &Val)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI ConstantRange getConstantRangeFromMetadata(const MDNode &RangeMD)
Parse out a conservative ConstantRange from !range metadata.
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI Value * simplifyInstruction(Instruction *I, const SimplifyQuery &Q)
See if we can compute a simplified version of this instruction.
auto dyn_cast_or_null(const Y &Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
PotentialValuesState< std::pair< AA::ValueAndContext, AA::ValueScope > > PotentialLLVMValuesState
bool isModSet(const ModRefInfo MRI)
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)
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
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.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth, bool MustPreserveProvenance=false)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
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.
@ 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.
ModRefInfo
Flags indicating whether a memory access modifies or references memory.
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.
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)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
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.
LLVM_ABI bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(const CallBase *Call, bool MustPreserveOffset, bool MustPreserveProvenance=false)
launder.invariant.group and similar intrinsics return a pointer that aliases their argument,...
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.
bool capturesNothing(CaptureComponents CC)
LLVM_ABI AssumeDereferenceableInfo getAssumeDereferenceableInfo(OperandBundleUse)
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
bool capturesAnyProvenance(CaptureComponents CC)
constexpr StringRef AssumptionAttrKey
The key we use for assumption attributes.
constexpr bool isCallableCC(CallingConv::ID CC)
bool isRefSet(const ModRefInfo MRI)
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
Return if this abstract state is fixed, thus does not need to be updated if information changes as it...
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
Indicate that the abstract state should converge to the optimistic state.
State & operator=(const State &R)
ChangeStatus indicatePessimisticFixpoint() override
Indicate that the abstract state should converge to the pessimistic state.
const State & getAssumed() const
static State getBestState(const State &SIS)
Return the best possible representable state.
bool isValidState() const override
Return if this abstract state is in a valid state.
----------------—AAIntraFnReachability Attribute-----------------------—
ReachabilityQueryInfo(const ReachabilityQueryInfo &RQI)
unsigned Hash
Precomputed hash for this RQI.
const Instruction * From
Start here,.
Reachable Result
and remember if it worked:
ReachabilityQueryInfo(const Instruction *From, const ToTy *To)
ReachabilityQueryInfo(Attributor &A, const Instruction &From, const ToTy &To, const AA::InstExclusionSetTy *ES, bool MakeUnique)
Constructor replacement to ensure unique and stable sets are used for the cache.
const ToTy * To
reach this place,
const AA::InstExclusionSetTy * ExclusionSet
without going through any of these instructions,
unsigned computeHashValue() const
An abstract interface for address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all align attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
Align getKnownAlign() const
Return known alignment.
static LLVM_ABI const char ID
An abstract attribute for getting assumption information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract state for querying live call edges.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for specializing "dynamic" components of denormal_fpenv to a known denormal mod...
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all dereferenceable attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for llvm::GlobalValue information interference.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for indirect call information interference.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface to track if a value leaves it's defining function instance.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract Attribute for computing reachability between functions.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool canReach(Attributor &A, const Function &Fn) const
If the function represented by this possition can reach Fn.
virtual bool instructionCanReach(Attributor &A, const Instruction &Inst, const Function &Fn, const AA::InstExclusionSetTy *ExclusionSet=nullptr) const =0
Can Inst reach Fn.
An abstract interface to determine reachability of point A to B.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for identifying pointers from which loads can be marked invariant.
static LLVM_ABI const char ID
Unique ID (due to the unique address).
An abstract interface for liveness abstract attribute.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for memory access kind related attributes (readnone/readonly/writeonly).
bool isAssumedReadOnly() const
Return true if we assume that the underlying value is not accessed (=written) in its respective scope...
bool isKnownReadNone() const
Return true if we know that the underlying value is not read or accessed in its respective scope.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
bool isAssumedReadNone() const
Return true if we assume that the underlying value is not read or accessed in its respective scope.
An abstract interface for all memory location attributes (readnone/argmemonly/inaccessiblememonly/ina...
static LLVM_ABI std::string getMemoryLocationsAsStr(MemoryLocationsKind MLK)
Return the locations encoded by MLK as a readable string.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
StateType::base_t MemoryLocationsKind
An abstract interface for all nonnull attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for potential address space information.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract interface for all noalias attributes.
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
---------------------— NoAlias Argument Attribute ---------------------—
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)
--------------------— Variable Capturing ------------------------------—
static LLVM_ABI void determineFunctionCaptureCapabilities(const IRPosition &IRP, const Function &F, BitIntegerState &State)
Update State according to the capture capabilities of F for position IRP.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for nofree.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An abstract attribute for norecurse.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
An AbstractAttribute for noreturn.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isAlignedBarrier(const CallBase &CB, bool ExecutedAligned)
Helper function to determine if CB is an aligned (GPU) barrier.
static LLVM_ABI bool isNonRelaxedAtomic(const Instruction *I)
Helper function used to determine whether an instruction is non-relaxed atomic.
An abstract interface for all noundef attributes.
static LLVM_ABI const char ID
Unique ID (due to the unique address)
static LLVM_ABI bool isImpliedByIR(Attributor &A, const IRPosition &IRP, Attribute::AttrKind ImpliedAttributeKind, bool IgnoreSubsumingPositions=false)
---------------------— NoUndef Attribute ------------------------------—
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)
---------------------— NonNull Argument Attribute ---------------------—
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.
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
static constexpr Align fromLog2(unsigned Log2Value)
Returns an alignment of 1 << Log2Value bytes.
std::function< void( const ArgumentReplacementInfo &, Function &, Function::arg_iterator)> CalleeRepairCBTy
Callee repair callback type.
const Argument & getReplacedArg() const
std::function< void(const ArgumentReplacementInfo &, AbstractCallSite, SmallVectorImpl< Value * > &)> ACSRepairCBTy
Abstract call site (ACS) repair callback type.
The fixpoint analysis framework that orchestrates the attribute deduction.
std::function< std::optional< Value * >( const IRPosition &, const AbstractAttribute *, bool &)> SimplifictionCallbackTy
Register CB as a simplification callback.
Specialization of the integer state for a bit-wise encoding.
BitIntegerState & addKnownBits(base_t Bits)
Add the bits in BitsEncoding to the "known bits".
Simple wrapper for a single bit (boolean) state.
static constexpr DenormalFPEnv getDefault()
static unsigned getHashValue(const Access &A)
AAPointerInfo::Access Access
static bool isEqual(const Access &LHS, const Access &RHS)
static bool isEqual(const AA::RangeTy &A, const AA::RangeTy B)
static unsigned getHashValue(const AA::RangeTy &Range)
DenseMapInfo< std::pair< const Instruction *, const ToTy * > > PairDMI
static bool isEqual(const ReachabilityQueryInfo< ToTy > *LHS, const ReachabilityQueryInfo< ToTy > *RHS)
DenseMapInfo< const AA::InstExclusionSetTy * > InstSetDMI
static unsigned getHashValue(const ReachabilityQueryInfo< ToTy > *RQI)
An information struct used to provide DenseMap with the various necessary components for a given valu...
State for dereferenceable attribute.
IncIntegerState DerefBytesState
State representing for dereferenceable bytes.
ChangeStatus manifest(Attributor &A) override
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.
Kind
The positions we distinguish in the IR.
@ 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...
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
bool isPassthrough() const
CaptureComponents ResultCC
Components captured by the return value of the user of this Use.
LLVM_ABI bool unionAssumed(std::optional< Value * > Other)
Merge Other into the currently assumed simplified value.
std::optional< Value * > SimplifiedAssociatedValue
An assumed simplified value.
Type * Ty
The type of the original value.