98#define DEBUG_TYPE "dse"
100STATISTIC(NumRemainingStores,
"Number of stores remaining after DSE");
101STATISTIC(NumRedundantStores,
"Number of redundant stores deleted");
103STATISTIC(NumFastOther,
"Number of other instrs removed");
104STATISTIC(NumCompletePartials,
"Number of stores dead by later partials");
105STATISTIC(NumModifiedStores,
"Number of stores modified");
110 "Number of times a valid candidate is returned from getDomMemoryDef");
112 "Number iterations check for reads in getDomMemoryDef");
115 "Controls which MemoryDefs are eliminated.");
131 switch (
II->getIntrinsicID()) {
132 default:
return false;
133 case Intrinsic::memset:
134 case Intrinsic::memcpy:
135 case Intrinsic::memcpy_element_unordered_atomic:
136 case Intrinsic::memset_element_unordered_atomic:
171enum OverwriteResult {
175 OW_PartialEarlierWithFullLater,
191 if (KillingII ==
nullptr || DeadII ==
nullptr)
193 if (KillingII->getIntrinsicID() != DeadII->getIntrinsicID())
196 switch (KillingII->getIntrinsicID()) {
197 case Intrinsic::masked_store:
198 case Intrinsic::vp_store: {
200 auto *KillingTy = KillingII->getArgOperand(0)->getType();
201 auto *DeadTy = DeadII->getArgOperand(0)->getType();
202 if (
DL.getTypeSizeInBits(KillingTy) !=
DL.getTypeSizeInBits(DeadTy))
209 Value *KillingPtr = KillingII->getArgOperand(1);
210 Value *DeadPtr = DeadII->getArgOperand(1);
211 if (KillingPtr != DeadPtr && !
AA.isMustAlias(KillingPtr, DeadPtr))
213 if (KillingII->getIntrinsicID() == Intrinsic::masked_store) {
216 if (KillingII->getArgOperand(2) != DeadII->getArgOperand(2))
218 }
else if (KillingII->getIntrinsicID() == Intrinsic::vp_store) {
221 if (KillingII->getArgOperand(2) != DeadII->getArgOperand(2))
224 if (KillingII->getArgOperand(3) != DeadII->getArgOperand(3))
247 int64_t KillingOff, int64_t DeadOff,
257 if (Opts.enable_dse_partial_overwrite_tracking &&
258 KillingOff < int64_t(DeadOff + DeadSize) &&
259 int64_t(KillingOff + KillingSize) >= DeadOff) {
262 auto &IM = IOL[DeadI];
263 LLVM_DEBUG(
dbgs() <<
"DSE: Partial overwrite: DeadLoc [" << DeadOff <<
", "
264 << int64_t(DeadOff + DeadSize) <<
") KillingLoc ["
265 << KillingOff <<
", " << int64_t(KillingOff + KillingSize)
272 int64_t KillingIntStart = KillingOff;
273 int64_t KillingIntEnd = KillingOff + KillingSize;
277 auto ILI = IM.lower_bound(KillingIntStart);
278 if (ILI != IM.end() && ILI->second <= KillingIntEnd) {
282 KillingIntStart = std::min(KillingIntStart, ILI->second);
283 KillingIntEnd = std::max(KillingIntEnd, ILI->first);
292 while (ILI != IM.end() && ILI->second <= KillingIntEnd) {
293 assert(ILI->second > KillingIntStart &&
"Unexpected interval");
294 KillingIntEnd = std::max(KillingIntEnd, ILI->first);
299 IM[KillingIntEnd] = KillingIntStart;
302 if (ILI->second <= DeadOff && ILI->first >= int64_t(DeadOff + DeadSize)) {
303 LLVM_DEBUG(
dbgs() <<
"DSE: Full overwrite from partials: DeadLoc ["
304 << DeadOff <<
", " << int64_t(DeadOff + DeadSize)
305 <<
") Composite KillingLoc [" << ILI->second <<
", "
306 << ILI->first <<
")\n");
307 ++NumCompletePartials;
314 if (Opts.enable_dse_partial_store_merging && KillingOff >= DeadOff &&
315 int64_t(DeadOff + DeadSize) > KillingOff &&
316 uint64_t(KillingOff - DeadOff) + KillingSize <= DeadSize) {
317 LLVM_DEBUG(
dbgs() <<
"DSE: Partial overwrite a dead load [" << DeadOff
318 <<
", " << int64_t(DeadOff + DeadSize)
319 <<
") by a killing store [" << KillingOff <<
", "
320 << int64_t(KillingOff + KillingSize) <<
")\n");
322 return OW_PartialEarlierWithFullLater;
334 if (!Opts.enable_dse_partial_overwrite_tracking &&
335 (KillingOff > DeadOff && KillingOff < int64_t(DeadOff + DeadSize) &&
336 int64_t(KillingOff + KillingSize) >= int64_t(DeadOff + DeadSize)))
348 if (!Opts.enable_dse_partial_overwrite_tracking &&
349 (KillingOff <= DeadOff && int64_t(KillingOff + KillingSize) > DeadOff)) {
350 assert(int64_t(KillingOff + KillingSize) < int64_t(DeadOff + DeadSize) &&
351 "Expect to be handled as OW_Complete");
371 using BlockAddressPair = std::pair<BasicBlock *, PHITransAddr>;
388 auto *MemLocPtr =
const_cast<Value *
>(MemLoc.
Ptr);
393 bool isFirstBlock =
true;
396 while (!WorkList.
empty()) {
408 assert(
B == SecondBB &&
"first block is not the store block");
410 isFirstBlock =
false;
416 for (; BI != EI; ++BI) {
418 if (
I->mayWriteToMemory() &&
I != SecondI)
424 "Should not hit the entry block because SI must be dominated by LI");
434 auto Inserted = Visited.
insert(std::make_pair(Pred, TranslatedPtr));
435 if (!Inserted.second) {
438 if (TranslatedPtr != Inserted.first->second)
443 WorkList.
push_back(std::make_pair(Pred, PredAddr));
452 bool IsOverwriteEnd) {
454 uint64_t DeadSliceSizeInBits = OldSizeInBits - NewSizeInBits;
461 uint64_t DeadSliceOffsetInBits = IsOverwriteEnd ? NewSizeInBits : 0;
462 auto SetDeadFragExpr = [](
auto *Assign,
466 uint64_t RelativeOffset = DeadFragment.OffsetInBits -
467 Assign->getExpression()
472 Assign->getExpression(), RelativeOffset, DeadFragment.SizeInBits)) {
473 Assign->setExpression(*
NewExpr);
480 DeadFragment.SizeInBits);
481 Assign->setExpression(Expr);
482 Assign->setKillLocation();
489 auto GetDeadLink = [&Ctx, &LinkToNothing]() {
492 return LinkToNothing;
498 std::optional<DIExpression::FragmentInfo> NewFragment;
500 DeadSliceSizeInBits, Assign,
507 Assign->setKillAddress();
508 Assign->setAssignId(GetDeadLink());
512 if (NewFragment->SizeInBits == 0)
516 auto *NewAssign =
static_cast<decltype(Assign)
>(Assign->clone());
517 NewAssign->insertAfter(Assign->getIterator());
518 NewAssign->setAssignId(GetDeadLink());
520 SetDeadFragExpr(NewAssign, *NewFragment);
521 NewAssign->setKillAddress();
535 for (
auto &Attr : OldAttrs) {
536 if (Attr.hasKindAsEnum()) {
537 switch (Attr.getKindAsEnum()) {
540 case Attribute::Alignment:
542 if (
isAligned(Attr.getAlignment().valueOrOne(), PtrOffset))
545 case Attribute::Dereferenceable:
546 case Attribute::DereferenceableOrNull:
550 case Attribute::NonNull:
551 case Attribute::NoUndef:
559 Intrinsic->removeParamAttrs(ArgNo, AttrsToRemove);
563 uint64_t &DeadSize, int64_t KillingStart,
564 uint64_t KillingSize,
bool IsOverwriteEnd) {
566 Align PrefAlign = DeadIntrinsic->getDestAlign().valueOrOne();
582 int64_t ToRemoveStart = 0;
586 if (IsOverwriteEnd) {
591 ToRemoveStart = KillingStart +
Off;
592 if (DeadSize <=
uint64_t(ToRemoveStart - DeadStart))
594 ToRemoveSize = DeadSize -
uint64_t(ToRemoveStart - DeadStart);
596 ToRemoveStart = DeadStart;
598 "Not overlapping accesses?");
599 ToRemoveSize = KillingSize -
uint64_t(DeadStart - KillingStart);
604 if (ToRemoveSize <= (PrefAlign.
value() -
Off))
606 ToRemoveSize -= PrefAlign.
value() -
Off;
609 "Should preserve selected alignment");
612 assert(ToRemoveSize > 0 &&
"Shouldn't reach here if nothing to remove");
613 assert(DeadSize > ToRemoveSize &&
"Can't remove more than original size");
615 uint64_t NewSize = DeadSize - ToRemoveSize;
616 if (DeadIntrinsic->isAtomic()) {
619 const uint32_t ElementSize = DeadIntrinsic->getElementSizeInBytes();
620 if (0 != NewSize % ElementSize)
625 << (IsOverwriteEnd ?
"END" :
"BEGIN") <<
": " << *DeadI
626 <<
"\n KILLER [" << ToRemoveStart <<
", "
627 << int64_t(ToRemoveStart + ToRemoveSize) <<
")\n");
629 DeadIntrinsic->setLength(NewSize);
630 DeadIntrinsic->setDestAlignment(PrefAlign);
632 Value *OrigDest = DeadIntrinsic->getRawDest();
633 if (!IsOverwriteEnd) {
634 Value *Indices[1] = {
635 ConstantInt::get(DeadIntrinsic->getLength()->getType(), ToRemoveSize)};
639 NewDestGEP->
setDebugLoc(DeadIntrinsic->getDebugLoc());
640 DeadIntrinsic->setDest(NewDestGEP);
649 DeadStart += ToRemoveSize;
656 int64_t &DeadStart,
uint64_t &DeadSize) {
661 int64_t KillingStart = OII->second;
662 uint64_t KillingSize = OII->first - KillingStart;
664 assert(OII->first - KillingStart >= 0 &&
"Size expected to be positive");
666 if (KillingStart > DeadStart &&
669 (
uint64_t)(KillingStart - DeadStart) < DeadSize &&
672 KillingSize >= DeadSize - (
uint64_t)(KillingStart - DeadStart)) {
673 if (
tryToShorten(DeadI, DeadStart, DeadSize, KillingStart, KillingSize,
684 int64_t &DeadStart,
uint64_t &DeadSize) {
689 int64_t KillingStart = OII->second;
690 uint64_t KillingSize = OII->first - KillingStart;
692 assert(OII->first - KillingStart >= 0 &&
"Size expected to be positive");
694 if (KillingStart <= DeadStart &&
697 KillingSize > (
uint64_t)(DeadStart - KillingStart)) {
700 assert(KillingSize - (
uint64_t)(DeadStart - KillingStart) < DeadSize &&
701 "Should have been handled as OW_Complete");
702 if (
tryToShorten(DeadI, DeadStart, DeadSize, KillingStart, KillingSize,
713 int64_t KillingOffset, int64_t DeadOffset,
757 unsigned BitOffsetDiff = (KillingOffset - DeadOffset) * 8;
758 unsigned LShiftAmount =
759 DL.isBigEndian() ? DeadValue.
getBitWidth() - BitOffsetDiff - KillingBits
762 LShiftAmount + KillingBits);
765 APInt Merged = (DeadValue & ~Mask) | (KillingValue << LShiftAmount);
767 <<
"\n Killing: " << *KillingI
768 <<
"\n Merged Value: " << Merged <<
'\n');
775 switch (
II->getIntrinsicID()) {
776 case Intrinsic::lifetime_start:
777 case Intrinsic::lifetime_end:
778 case Intrinsic::invariant_end:
779 case Intrinsic::launder_invariant_group:
780 case Intrinsic::assume:
795 if (CB->onlyAccessesInaccessibleMemory())
800 if (DI->
mayThrow() && !DefVisibleToCaller)
822struct MemoryLocationWrapper {
823 MemoryLocationWrapper(MemoryLocation MemLoc, MemoryDef *MemDef,
824 bool DefByInitializesAttr)
825 : MemLoc(MemLoc), MemDef(MemDef),
826 DefByInitializesAttr(DefByInitializesAttr) {
827 assert(MemLoc.Ptr &&
"MemLoc should be not null");
829 DefInst = MemDef->getMemoryInst();
832 MemoryLocation MemLoc;
833 const Value *UnderlyingObject;
836 bool DefByInitializesAttr =
false;
841struct MemoryDefWrapper {
842 MemoryDefWrapper(MemoryDef *MemDef,
843 ArrayRef<std::pair<MemoryLocation, bool>> MemLocations) {
845 for (
auto &[MemLoc, DefByInitializesAttr] : MemLocations)
846 DefinedLocations.push_back(
847 MemoryLocationWrapper(MemLoc, MemDef, DefByInitializesAttr));
853struct ArgumentInitInfo {
855 bool IsDeadOrInvisibleOnUnwind;
856 ConstantRangeList Inits;
871 bool CallHasNoUnwindAttr) {
877 for (
const auto &Arg : Args) {
878 if (!CallHasNoUnwindAttr && !Arg.IsDeadOrInvisibleOnUnwind)
880 if (Arg.Inits.empty())
885 for (
auto &Arg : Args.drop_front())
886 IntersectedIntervals = IntersectedIntervals.
intersectWith(Arg.Inits);
888 return IntersectedIntervals;
894 const ScalarOptions &Opts;
897 EarliestEscapeAnalysis EA;
906 BatchAAResults BatchAA;
910 PostDominatorTree &PDT;
911 const TargetLibraryInfo &TLI;
912 const DataLayout &DL;
918 SmallPtrSet<MemoryAccess *, 4> SkipStores;
920 DenseMap<const Value *, bool> CapturedBeforeReturn;
923 DenseMap<const Value *, bool> InvisibleToCallerAfterRet;
924 DenseMap<const Value *, uint64_t> InvisibleToCallerAfterRetBounded;
926 SmallPtrSet<BasicBlock *, 16> ThrowingBlocks;
929 SmallPtrSet<BasicBlock *, 16> CoroEndBlocks;
932 DenseMap<BasicBlock *, unsigned> PostOrderNumbers;
936 MapVector<BasicBlock *, InstOverlapIntervalsTy> IOLs;
940 bool AnyUnreachableExit;
945 bool ShouldIterateEndOfFunctionDSE;
948 SmallVector<Instruction *> ToRemove;
952 MemorySSA &MSSA, DominatorTree &DT, PostDominatorTree &PDT,
953 const TargetLibraryInfo &TLI,
const CycleInfo &CI);
954 DSEState(
const DSEState &) =
delete;
955 DSEState &operator=(
const DSEState &) =
delete;
957 LocationSize strengthenLocationSize(
const Instruction *
I,
958 LocationSize
Size)
const;
968 OverwriteResult isOverwrite(
const Instruction *KillingI,
969 const Instruction *DeadI,
970 const MemoryLocation &KillingLoc,
971 const MemoryLocation &DeadLoc,
972 int64_t &KillingOff, int64_t &DeadOff);
974 bool isInvisibleToCallerAfterRet(
const Value *V,
const Value *Ptr,
975 const LocationSize StoreSize);
977 bool isInvisibleToCallerOnUnwind(
const Value *V);
979 std::optional<MemoryLocation> getLocForWrite(Instruction *
I)
const;
984 getLocForInst(Instruction *
I,
bool ConsiderInitializesAttr);
988 bool isRemovable(Instruction *
I);
992 bool isCompleteOverwrite(
const MemoryLocation &DefLoc, Instruction *DefInst,
993 Instruction *UseInst);
996 bool isWriteAtEndOfFunction(MemoryDef *Def,
const MemoryLocation &DefLoc);
1001 std::optional<std::pair<MemoryLocation, bool>>
1002 getLocForTerminator(Instruction *
I)
const;
1006 bool isMemTerminatorInst(Instruction *
I)
const;
1010 bool isMemTerminator(
const MemoryLocation &Loc, Instruction *AccessI,
1011 Instruction *MaybeTerm);
1014 bool isReadClobber(
const MemoryLocation &DefLoc, Instruction *UseInst);
1021 bool isGuaranteedLoopIndependent(
const Instruction *Current,
1022 const Instruction *KillingDef,
1023 const MemoryLocation &CurrentLoc);
1028 bool isGuaranteedLoopInvariant(
const Value *Ptr);
1036 std::optional<MemoryAccess *>
1037 getDomMemoryDef(MemoryDef *KillingDef, MemoryAccess *StartAccess,
1038 const MemoryLocation &KillingLoc,
const Value *KillingUndObj,
1039 unsigned &ScanLimit,
unsigned &WalkerStepLimit,
1040 bool IsMemTerm,
unsigned &PartialLimit,
1041 bool IsInitializesAttrMemLoc);
1047 SmallPtrSetImpl<MemoryAccess *> *
Deleted =
nullptr);
1053 bool mayThrowBetween(Instruction *KillingI, Instruction *DeadI,
1054 const Value *KillingUndObj);
1061 bool isDSEBarrier(
const Value *KillingUndObj, Instruction *DeadI);
1065 bool eliminateDeadWritesAtEndOfFunction();
1069 bool tryFoldIntoCalloc(MemoryDef *Def,
const Value *DefUO);
1073 bool storeIsNoop(MemoryDef *Def,
const Value *DefUO);
1079 bool eliminateRedundantStoresOfExistingValues();
1084 bool eliminateRedundantStoresViaDominatingConditions();
1099 std::pair<bool, bool>
1100 eliminateDeadDefs(
const MemoryLocationWrapper &KillingLocWrapper);
1104 bool eliminateDeadDefs(
const MemoryDefWrapper &KillingDefWrapper);
1114 if (Visited.
insert(MA).second)
1131 : Opts(Opts),
F(
F),
AA(
AA), EA(DT, nullptr, &CI), BatchAA(
AA, &EA),
1132 MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI),
DL(
F.getDataLayout()), CI(CI) {
1137 PostOrderNumbers[BB] = PO++;
1140 if (
I.mayThrow() && !MA)
1141 ThrowingBlocks.insert(
I.getParent());
1143 if (CEI->isFallthrough())
1144 CoroEndBlocks.insert(
I.getParent());
1148 if (MD && MemDefs.size() < Opts.dse_memoryssa_defs_per_block_limit &&
1149 (getLocForWrite(&
I) || isMemTerminatorInst(&
I) ||
1150 (Opts.enable_dse_initializes_attr_improvement &&
1152 MemDefs.push_back(MD);
1159 if (AI.hasPassPointeeByValueCopyAttr()) {
1160 InvisibleToCallerAfterRet.insert({&AI, true});
1164 if (!AI.getType()->isPointerTy())
1168 if (Info.coversAllReachableMemory())
1169 InvisibleToCallerAfterRet.insert({&AI, true});
1170 else if (
uint64_t DeadBytes = Info.getNumberOfDeadBytes())
1171 InvisibleToCallerAfterRetBounded.insert({&AI, DeadBytes});
1175 return isa<UnreachableInst>(E->getTerminator());
1183 if (TLI.
has(
F) && (
F == LibFunc_memset_chk ||
F == LibFunc_memcpy_chk)) {
1199OverwriteResult DSEState::isOverwrite(
const Instruction *KillingI,
1200 const Instruction *DeadI,
1201 const MemoryLocation &KillingLoc,
1202 const MemoryLocation &DeadLoc,
1203 int64_t &KillingOff, int64_t &DeadOff) {
1207 if (!isGuaranteedLoopIndependent(DeadI, KillingI, DeadLoc))
1210 LocationSize KillingLocSize =
1211 strengthenLocationSize(KillingI, KillingLoc.
Size);
1219 if (DeadUndObj == KillingUndObj && KillingLocSize.
isPrecise() &&
1221 std::optional<TypeSize> KillingUndObjSize =
1223 if (KillingUndObjSize && *KillingUndObjSize == KillingLocSize.
getValue())
1234 if (KillingMemI && DeadMemI) {
1235 const Value *KillingV = KillingMemI->getLength();
1236 const Value *DeadV = DeadMemI->getLength();
1237 if (KillingV == DeadV && BatchAA.
isMustAlias(DeadLoc, KillingLoc))
1246 const TypeSize KillingSize = KillingLocSize.
getValue();
1255 auto CheckAA = [&]() {
1257 AliasResult AAR = BatchAA.
alias(KillingLoc, DeadLoc);
1263 if (KillingSize >= DeadSize)
1286 if (DeadUndObj != KillingUndObj)
1290 unsigned IdxWidth =
DL.getIndexTypeSizeInBits(DeadPtr->
getType());
1291 if (IdxWidth !=
DL.getIndexTypeSizeInBits(KillingPtr->
getType()))
1299 APInt DeadBaseOff(IdxWidth, 0);
1300 APInt KillingBaseOff(IdxWidth, 0);
1302 DL, DeadBaseOff,
true);
1304 DL, KillingBaseOff,
true);
1308 if (DeadBasePtr != KillingBasePtr)
1324 if (KillingSize == 0)
1328 APInt Delta = DeadBaseOff - KillingBaseOff;
1329 if (Delta.
ult(KillingSize)) {
1336 return OW_MaybePartial;
1340 if ((-Delta).ult(DeadSize)) {
1341 KillingOff = (-Delta).getZExtValue();
1342 return OW_MaybePartial;
1349bool DSEState::isInvisibleToCallerAfterRet(
const Value *V,
const Value *Ptr,
1350 const LocationSize StoreSize) {
1354 auto IBounded = InvisibleToCallerAfterRetBounded.find(V);
1355 if (IBounded != InvisibleToCallerAfterRetBounded.end()) {
1356 int64_t ValueOffset;
1357 [[maybe_unused]]
const Value *BaseValue =
1367 ValueOffset + StoreSize.
getValue() <= IBounded->second &&
1371 auto I = InvisibleToCallerAfterRet.insert({
V,
false});
1372 if (
I.second && isInvisibleToCallerOnUnwind(V) &&
isNoAliasCall(V))
1375 return I.first->second;
1378bool DSEState::isInvisibleToCallerOnUnwind(
const Value *V) {
1379 bool RequiresNoCaptureBeforeUnwind;
1382 if (!RequiresNoCaptureBeforeUnwind)
1385 auto I = CapturedBeforeReturn.insert({
V,
true});
1393 return !
I.first->second;
1396std::optional<MemoryLocation> DSEState::getLocForWrite(Instruction *
I)
const {
1397 if (!
I->mayWriteToMemory())
1398 return std::nullopt;
1407DSEState::getLocForInst(Instruction *
I,
bool ConsiderInitializesAttr) {
1409 if (isMemTerminatorInst(
I)) {
1410 if (
auto Loc = getLocForTerminator(
I))
1411 Locations.push_back(std::make_pair(Loc->first,
false));
1415 if (
auto Loc = getLocForWrite(
I))
1416 Locations.push_back(std::make_pair(*Loc,
false));
1418 if (ConsiderInitializesAttr) {
1419 for (
auto &MemLoc : getInitializesArgMemLoc(
I)) {
1420 Locations.push_back(std::make_pair(MemLoc,
true));
1426bool DSEState::isRemovable(Instruction *
I) {
1427 assert(getLocForWrite(
I) &&
"Must have analyzable write");
1431 return SI->isUnordered();
1436 return !
MI->isVolatile();
1440 if (CB->isLifetimeStartOrEnd())
1443 return CB->use_empty() && CB->willReturn() && CB->doesNotThrow() &&
1444 !CB->isTerminator();
1450bool DSEState::isCompleteOverwrite(
const MemoryLocation &DefLoc,
1451 Instruction *DefInst, Instruction *UseInst) {
1459 if (CB->onlyAccessesInaccessibleMemory())
1462 int64_t InstWriteOffset, DepWriteOffset;
1463 if (
auto CC = getLocForWrite(UseInst))
1464 return isOverwrite(UseInst, DefInst, *
CC, DefLoc, InstWriteOffset,
1465 DepWriteOffset) == OW_Complete;
1469bool DSEState::isWriteAtEndOfFunction(MemoryDef *Def,
1470 const MemoryLocation &DefLoc) {
1472 << *
Def->getMemoryInst()
1473 <<
") is at the end the function \n");
1475 SmallPtrSet<MemoryAccess *, 8> Visited;
1478 for (
unsigned I = 0;
I < WorkList.
size();
I++) {
1479 if (WorkList.
size() >= Opts.dse_memoryssa_scanlimit) {
1484 MemoryAccess *UseAccess = WorkList[
I];
1489 if (!isGuaranteedLoopInvariant(DefLoc.
Ptr))
1498 if (isReadClobber(DefLoc, UseInst)) {
1499 LLVM_DEBUG(
dbgs() <<
" ... hit read clobber " << *UseInst <<
".\n");
1509std::optional<std::pair<MemoryLocation, bool>>
1510DSEState::getLocForTerminator(Instruction *
I)
const {
1512 if (CB->getIntrinsicID() == Intrinsic::lifetime_end)
1519 return std::nullopt;
1522bool DSEState::isMemTerminatorInst(Instruction *
I)
const {
1524 return CB && (CB->getIntrinsicID() == Intrinsic::lifetime_end ||
1528bool DSEState::isMemTerminator(
const MemoryLocation &Loc, Instruction *AccessI,
1529 Instruction *MaybeTerm) {
1530 std::optional<std::pair<MemoryLocation, bool>> MaybeTermLoc =
1531 getLocForTerminator(MaybeTerm);
1542 auto TermLoc = MaybeTermLoc->first;
1543 if (MaybeTermLoc->second) {
1547 int64_t InstWriteOffset = 0;
1548 int64_t DepWriteOffset = 0;
1549 return isOverwrite(MaybeTerm, AccessI, TermLoc, Loc, InstWriteOffset,
1550 DepWriteOffset) == OW_Complete;
1553bool DSEState::isReadClobber(
const MemoryLocation &DefLoc,
1554 Instruction *UseInst) {
1567 if (CB->onlyAccessesInaccessibleMemory())
1573bool DSEState::isGuaranteedLoopIndependent(
const Instruction *Current,
1574 const Instruction *KillingDef,
1575 const MemoryLocation &CurrentLoc) {
1586 return isGuaranteedLoopInvariant(CurrentLoc.
Ptr);
1589bool DSEState::isGuaranteedLoopInvariant(
const Value *Ptr) {
1592 if (
GEP->hasAllConstantIndices())
1596 return I->getParent()->isEntryBlock() || !CI.
getCycle(
I->getParent());
1601std::optional<MemoryAccess *> DSEState::getDomMemoryDef(
1602 MemoryDef *KillingDef, MemoryAccess *StartAccess,
1603 const MemoryLocation &KillingLoc,
const Value *KillingUndObj,
1604 unsigned &ScanLimit,
unsigned &WalkerStepLimit,
bool IsMemTerm,
1605 unsigned &PartialLimit,
bool IsInitializesAttrMemLoc) {
1606 if (ScanLimit == 0 || WalkerStepLimit == 0) {
1608 return std::nullopt;
1611 MemoryAccess *Current = StartAccess;
1620 bool CanOptimize = Opts.dse_optimize_memoryssa &&
1625 std::optional<MemoryLocation> CurrentLoc;
1628 dbgs() <<
" visiting " << *Current;
1641 return std::nullopt;
1647 ? Opts.dse_memoryssa_samebb_cost
1648 : Opts.dse_memoryssa_otherbb_cost;
1649 if (WalkerStepLimit <= StepCost) {
1651 return std::nullopt;
1653 WalkerStepLimit -= StepCost;
1667 if (
canSkipDef(CurrentDef, !isInvisibleToCallerOnUnwind(KillingUndObj))) {
1668 CanOptimize =
false;
1674 if (mayThrowBetween(KillingI, CurrentI, KillingUndObj)) {
1676 return std::nullopt;
1681 if (isDSEBarrier(KillingUndObj, CurrentI)) {
1683 return std::nullopt;
1691 return std::nullopt;
1694 if (
any_of(Current->
uses(), [
this, &KillingLoc, StartAccess](Use &U) {
1695 if (auto *UseOrDef = dyn_cast<MemoryUseOrDef>(U.getUser()))
1696 return !MSSA.dominates(StartAccess, UseOrDef) &&
1697 isReadClobber(KillingLoc, UseOrDef->getMemoryInst());
1701 return std::nullopt;
1706 CurrentLoc = getLocForWrite(CurrentI);
1707 if (!CurrentLoc || !isRemovable(CurrentI)) {
1708 CanOptimize =
false;
1715 if (!isGuaranteedLoopIndependent(CurrentI, KillingI, *CurrentLoc)) {
1717 CanOptimize =
false;
1725 if (!isMemTerminator(*CurrentLoc, CurrentI, KillingI)) {
1726 CanOptimize =
false;
1730 int64_t KillingOffset = 0;
1731 int64_t DeadOffset = 0;
1732 auto OR = isOverwrite(KillingI, CurrentI, KillingLoc, *CurrentLoc,
1733 KillingOffset, DeadOffset);
1739 (OR == OW_Complete || OR == OW_MaybePartial))
1745 CanOptimize =
false;
1750 if (OR == OW_Unknown || OR == OW_None)
1752 else if (OR == OW_MaybePartial) {
1757 if (PartialLimit <= 1) {
1758 WalkerStepLimit -= 1;
1759 LLVM_DEBUG(
dbgs() <<
" ... reached partial limit ... continue with "
1773 SmallPtrSet<Instruction *, 16> KillingDefs;
1775 MemoryAccess *MaybeDeadAccess = Current;
1776 MemoryLocation MaybeDeadLoc = *CurrentLoc;
1778 LLVM_DEBUG(
dbgs() <<
" Checking for reads of " << *MaybeDeadAccess <<
" ("
1779 << *MaybeDeadI <<
")\n");
1782 SmallPtrSet<MemoryAccess *, 32> Visited;
1786 for (
unsigned I = 0;
I < WorkList.
size();
I++) {
1787 MemoryAccess *UseAccess = WorkList[
I];
1791 if (ScanLimit < (WorkList.
size() -
I)) {
1793 return std::nullopt;
1796 NumDomMemDefChecks++;
1799 if (
any_of(KillingDefs, [
this, UseAccess](Instruction *KI) {
1802 LLVM_DEBUG(
dbgs() <<
" ... skipping, dominated by killing block\n");
1813 if (
any_of(KillingDefs, [
this, UseInst](Instruction *KI) {
1816 LLVM_DEBUG(
dbgs() <<
" ... skipping, dominated by killing def\n");
1822 if (isMemTerminator(MaybeDeadLoc, MaybeDeadI, UseInst)) {
1825 <<
" ... skipping, memterminator invalidates following accesses\n");
1835 if (UseInst->
mayThrow() && !isInvisibleToCallerOnUnwind(KillingUndObj)) {
1837 return std::nullopt;
1844 bool IsKillingDefFromInitAttr =
false;
1845 if (IsInitializesAttrMemLoc) {
1846 if (KillingI == UseInst &&
1848 IsKillingDefFromInitAttr =
true;
1851 if (isReadClobber(MaybeDeadLoc, UseInst) && !IsKillingDefFromInitAttr) {
1853 return std::nullopt;
1859 if (MaybeDeadAccess == UseAccess &&
1860 !isGuaranteedLoopInvariant(MaybeDeadLoc.
Ptr)) {
1861 LLVM_DEBUG(
dbgs() <<
" ... found not loop invariant self access\n");
1862 return std::nullopt;
1868 if (KillingDef == UseAccess || MaybeDeadAccess == UseAccess) {
1884 if (isCompleteOverwrite(MaybeDeadLoc, MaybeDeadI, UseInst)) {
1886 if (PostOrderNumbers.
find(MaybeKillingBlock)->second <
1887 PostOrderNumbers.
find(MaybeDeadAccess->
getBlock())->second) {
1888 if (!isInvisibleToCallerAfterRet(KillingUndObj, KillingLoc.
Ptr,
1891 <<
" ... found killing def " << *UseInst <<
"\n");
1892 KillingDefs.
insert(UseInst);
1896 <<
" ... found preceeding def " << *UseInst <<
"\n");
1897 return std::nullopt;
1907 if (!isInvisibleToCallerAfterRet(KillingUndObj, KillingLoc.
Ptr,
1909 SmallPtrSet<BasicBlock *, 16> KillingBlocks;
1910 for (Instruction *KD : KillingDefs)
1911 KillingBlocks.
insert(KD->getParent());
1913 "Expected at least a single killing block");
1927 if (!AnyUnreachableExit)
1928 return std::nullopt;
1932 CommonPred =
nullptr;
1936 if (KillingBlocks.
count(CommonPred))
1937 return {MaybeDeadAccess};
1939 SetVector<BasicBlock *> WorkList;
1943 WorkList.
insert(CommonPred);
1945 for (BasicBlock *R : PDT.
roots()) {
1950 for (BasicBlock *R : CoroEndBlocks)
1957 for (
unsigned I = 0;
I < WorkList.
size();
I++) {
1960 if (KillingBlocks.
count(Current))
1962 if (Current == MaybeDeadAccess->
getBlock())
1963 return std::nullopt;
1972 if (WorkList.
size() >= Opts.dse_memoryssa_path_check_limit)
1973 return std::nullopt;
1980 return {MaybeDeadAccess};
1983void DSEState::deleteDeadInstruction(Instruction *SI,
1984 SmallPtrSetImpl<MemoryAccess *> *
Deleted) {
1985 MemorySSAUpdater Updater(&MSSA);
1990 while (!NowDeadInsts.
empty()) {
2004 SkipStores.insert(MD);
2008 if (
SI->getValueOperand()->getType()->isPointerTy()) {
2010 if (CapturedBeforeReturn.erase(UO))
2011 ShouldIterateEndOfFunctionDSE =
true;
2012 InvisibleToCallerAfterRet.erase(UO);
2013 InvisibleToCallerAfterRetBounded.erase(UO);
2018 Updater.removeMemoryAccess(MA);
2022 if (
I != IOLs.end())
2023 I->second.erase(DeadInst);
2025 for (Use &O : DeadInst->
operands())
2045bool DSEState::mayThrowBetween(Instruction *KillingI, Instruction *DeadI,
2046 const Value *KillingUndObj) {
2050 if (KillingUndObj && isInvisibleToCallerOnUnwind(KillingUndObj))
2054 return ThrowingBlocks.count(KillingI->
getParent());
2055 return !ThrowingBlocks.empty();
2058bool DSEState::isDSEBarrier(
const Value *KillingUndObj, Instruction *DeadI) {
2061 if (DeadI->
mayThrow() && !isInvisibleToCallerOnUnwind(KillingUndObj))
2081bool DSEState::eliminateDeadWritesAtEndOfFunction() {
2082 bool MadeChange =
false;
2084 dbgs() <<
"Trying to eliminate MemoryDefs at the end of the function\n");
2086 ShouldIterateEndOfFunctionDSE =
false;
2088 if (SkipStores.contains(Def))
2092 auto DefLoc = getLocForWrite(DefI);
2093 if (!DefLoc || !isRemovable(DefI)) {
2095 "instruction not removable.\n");
2105 if (!isInvisibleToCallerAfterRet(UO, DefLoc->
Ptr, DefLoc->
Size))
2108 if (isWriteAtEndOfFunction(Def, *DefLoc)) {
2110 LLVM_DEBUG(
dbgs() <<
" ... MemoryDef is not accessed until the end "
2111 "of the function\n");
2117 }
while (ShouldIterateEndOfFunctionDSE);
2121bool DSEState::eliminateRedundantStoresViaDominatingConditions() {
2122 bool MadeChange =
false;
2123 LLVM_DEBUG(
dbgs() <<
"Trying to eliminate MemoryDefs whose value being "
2124 "written is implied by a dominating condition\n");
2126 using ConditionInfo = std::pair<Value *, Value *>;
2127 using ScopedHTType = ScopedHashTable<ConditionInfo, Instruction *>;
2131 ScopedHTType ActiveConditions;
2132 auto GetDominatingCondition = [&](
BasicBlock *BB)
2133 -> std::optional<std::tuple<ConditionInfo, Instruction *, BasicBlock *>> {
2136 return std::nullopt;
2141 if (BI->getSuccessor(0) == BI->getSuccessor(1))
2142 return std::nullopt;
2146 Value *StorePtr, *StoreVal;
2147 if (!
match(BI->getCondition(),
2151 return std::nullopt;
2157 return std::nullopt;
2159 unsigned ImpliedSuccIdx = Pred == ICmpInst::ICMP_EQ ? 0 : 1;
2160 BasicBlock *ImpliedSucc = BI->getSuccessor(ImpliedSuccIdx);
2161 return {{ConditionInfo(StorePtr, StoreVal), ICmpL, ImpliedSucc}};
2165 if (
Depth > Opts.dse_max_dom_cond_depth)
2171 for (MemoryDef &Def :
2174 if (!SI || !
SI->isUnordered())
2178 {
SI->getPointerOperand(),
SI->getValueOperand()});
2186 MemoryAccess *ClobberingAccess =
2188 if (MSSA.
dominates(ClobberingAccess, LoadAccess)) {
2190 <<
"Removing No-Op Store:\n DEAD: " << *SI <<
'\n');
2192 NumRedundantStores++;
2199 auto MaybeCondition = GetDominatingCondition(BB);
2203 ScopedHTType::ScopeTy
Scope(ActiveConditions);
2204 if (MaybeCondition) {
2205 const auto &[
Cond, LI, ImpliedSucc] = *MaybeCondition;
2206 if (DT.
dominates(BasicBlockEdge(BB, ImpliedSucc), Child->getBlock())) {
2210 ActiveConditions.insert(
Cond, LI);
2217 Self(Child,
Depth + 1, Self);
2227bool DSEState::tryFoldIntoCalloc(MemoryDef *Def,
const Value *DefUO) {
2234 if (!StoredConstant || !StoredConstant->
isNullValue())
2237 if (!isRemovable(DefI))
2241 if (
F.hasFnAttribute(Attribute::SanitizeMemory) ||
2242 F.hasFnAttribute(Attribute::SanitizeAddress) ||
2243 F.hasFnAttribute(Attribute::SanitizeHWAddress) ||
F.getName() ==
"calloc")
2248 auto *InnerCallee =
Malloc->getCalledFunction();
2252 StringRef ZeroedVariantName;
2253 if (Func != LibFunc_malloc || !TLI.
has(Func)) {
2258 if (ZeroedVariantName.
empty())
2267 auto shouldCreateCalloc = [](CallInst *
Malloc, CallInst *Memset) {
2270 auto *MallocBB =
Malloc->getParent(), *MemsetBB = Memset->getParent();
2271 if (MallocBB == MemsetBB)
2273 auto *Ptr = Memset->getArgOperand(0);
2274 auto *TI = MallocBB->getTerminator();
2280 if (MemsetBB != FalseBB)
2291 assert(Func == LibFunc_malloc || !ZeroedVariantName.
empty());
2292 Value *Calloc =
nullptr;
2293 if (!ZeroedVariantName.
empty()) {
2294 LLVMContext &Ctx =
Malloc->getContext();
2295 AttributeList
Attrs = InnerCallee->getAttributes();
2297 Attrs.getFnAttr(Attribute::AllocKind).getAllocKind() |
2298 AllocFnKind::Zeroed;
2301 Attrs.addFnAttribute(Ctx, Attribute::getWithAllocKind(Ctx, AllocKind))
2302 .removeFnAttribute(Ctx,
"alloc-variant-zeroed");
2303 FunctionCallee ZeroedVariant =
Malloc->getModule()->getOrInsertFunction(
2304 ZeroedVariantName, InnerCallee->getFunctionType(), Attrs);
2306 ->setCallingConv(
Malloc->getCallingConv());
2309 CallInst *CI = IRB.CreateCall(ZeroedVariant, Args, ZeroedVariantName);
2313 Type *SizeTTy =
Malloc->getArgOperand(0)->getType();
2314 Calloc =
emitCalloc(ConstantInt::get(SizeTTy, 1),
Malloc->getArgOperand(0),
2315 IRB, TLI,
Malloc->getType()->getPointerAddressSpace());
2320 if (MDNode *MD =
Malloc->getMetadata(LLVMContext::MD_alloc_token))
2323 MemorySSAUpdater Updater(&MSSA);
2325 nullptr, MallocDef);
2327 Updater.insertDef(NewAccessMD,
true);
2328 Malloc->replaceAllUsesWith(Calloc);
2333bool DSEState::storeIsNoop(MemoryDef *Def,
const Value *DefUO) {
2337 Constant *StoredConstant =
nullptr;
2345 if (!isRemovable(DefI))
2348 if (StoredConstant) {
2353 if (InitC && InitC == StoredConstant)
2362 if (LoadI->getPointerOperand() ==
Store->getOperand(1)) {
2366 if (LoadAccess ==
Def->getDefiningAccess())
2372 SetVector<MemoryAccess *> ToCheck;
2373 MemoryAccess *Current =
2381 for (
unsigned I = 1;
I < ToCheck.
size(); ++
I) {
2382 Current = ToCheck[
I];
2385 for (
auto &Use : PhiAccess->incoming_values())
2397 if (LoadAccess != Current)
2409 for (
auto OI : IOL) {
2411 MemoryLocation Loc = *getLocForWrite(DeadI);
2412 assert(isRemovable(DeadI) &&
"Expect only removable instruction");
2415 int64_t DeadStart = 0;
2419 if (IntervalMap.empty())
2426bool DSEState::eliminateRedundantStoresOfExistingValues() {
2427 bool MadeChange =
false;
2428 LLVM_DEBUG(
dbgs() <<
"Trying to eliminate MemoryDefs that write the "
2429 "already existing value\n");
2430 for (
auto *Def : MemDefs) {
2435 auto MaybeDefLoc = getLocForWrite(DefInst);
2436 if (!MaybeDefLoc || !isRemovable(DefInst))
2439 MemoryDef *UpperDef;
2443 if (
Def->isOptimized())
2451 auto IsRedundantStore = [&]() {
2459 auto UpperLoc = getLocForWrite(UpperInst);
2462 int64_t InstWriteOffset = 0;
2463 int64_t DepWriteOffset = 0;
2464 auto OR = isOverwrite(UpperInst, DefInst, *UpperLoc, *MaybeDefLoc,
2465 InstWriteOffset, DepWriteOffset);
2467 return StoredByte && StoredByte == MemSetI->getOperand(1) &&
2474 if (!IsRedundantStore() || isReadClobber(*MaybeDefLoc, DefInst))
2476 LLVM_DEBUG(
dbgs() <<
"DSE: Remove No-Op Store:\n DEAD: " << *DefInst
2479 NumRedundantStores++;
2486DSEState::getInitializesArgMemLoc(
const Instruction *
I) {
2492 SmallMapVector<Value *, SmallVector<ArgumentInitInfo, 2>, 2>
Arguments;
2498 ConstantRangeList Inits;
2510 Inits = ConstantRangeList();
2518 bool IsDeadOrInvisibleOnUnwind =
2521 ArgumentInitInfo InitInfo{
Idx, IsDeadOrInvisibleOnUnwind, Inits};
2522 bool FoundAliasing =
false;
2523 for (
auto &[Arg, AliasList] :
Arguments) {
2529 FoundAliasing =
true;
2530 AliasList.push_back(InitInfo);
2535 FoundAliasing =
true;
2536 AliasList.push_back(ArgumentInitInfo{
Idx, IsDeadOrInvisibleOnUnwind,
2537 ConstantRangeList()});
2546 auto IntersectedRanges =
2548 if (IntersectedRanges.empty())
2551 for (
const auto &Arg : Args) {
2552 for (
const auto &
Range : IntersectedRanges) {
2566std::pair<bool, bool>
2567DSEState::eliminateDeadDefs(
const MemoryLocationWrapper &KillingLocWrapper) {
2569 bool DeletedKillingLoc =
false;
2570 unsigned ScanLimit = Opts.dse_memoryssa_scanlimit;
2571 unsigned WalkerStepLimit = Opts.dse_memoryssa_walklimit;
2572 unsigned PartialLimit = Opts.dse_memoryssa_partial_store_limit;
2575 SmallSetVector<MemoryAccess *, 8> ToCheck;
2579 SmallPtrSet<MemoryAccess *, 8>
Deleted;
2580 [[maybe_unused]]
unsigned OrigNumSkipStores = SkipStores.size();
2585 for (
unsigned I = 0;
I < ToCheck.
size();
I++) {
2586 MemoryAccess *Current = ToCheck[
I];
2587 if (
Deleted.contains(Current))
2589 std::optional<MemoryAccess *> MaybeDeadAccess = getDomMemoryDef(
2590 KillingLocWrapper.MemDef, Current, KillingLocWrapper.MemLoc,
2591 KillingLocWrapper.UnderlyingObject, ScanLimit, WalkerStepLimit,
2592 isMemTerminatorInst(KillingLocWrapper.DefInst), PartialLimit,
2593 KillingLocWrapper.DefByInitializesAttr);
2595 if (!MaybeDeadAccess) {
2599 MemoryAccess *DeadAccess = *MaybeDeadAccess;
2600 LLVM_DEBUG(
dbgs() <<
" Checking if we can kill " << *DeadAccess);
2602 LLVM_DEBUG(
dbgs() <<
"\n ... adding incoming values to worklist\n");
2611 if (PostOrderNumbers[IncomingBlock] > PostOrderNumbers[PhiBlock])
2612 ToCheck.
insert(IncomingAccess);
2623 MemoryDefWrapper DeadDefWrapper(
2627 assert(DeadDefWrapper.DefinedLocations.size() == 1);
2628 MemoryLocationWrapper &DeadLocWrapper =
2629 DeadDefWrapper.DefinedLocations.front();
2632 NumGetDomMemoryDefPassed++;
2636 if (isMemTerminatorInst(KillingLocWrapper.DefInst)) {
2637 if (KillingLocWrapper.UnderlyingObject != DeadLocWrapper.UnderlyingObject)
2640 << *DeadLocWrapper.DefInst <<
"\n KILLER: "
2641 << *KillingLocWrapper.DefInst <<
'\n');
2647 int64_t KillingOffset = 0;
2648 int64_t DeadOffset = 0;
2649 OverwriteResult
OR =
2650 isOverwrite(KillingLocWrapper.DefInst, DeadLocWrapper.DefInst,
2651 KillingLocWrapper.MemLoc, DeadLocWrapper.MemLoc,
2652 KillingOffset, DeadOffset);
2653 if (OR == OW_MaybePartial) {
2654 auto &IOL = IOLs[DeadLocWrapper.DefInst->
getParent()];
2656 DeadLocWrapper.MemLoc, KillingOffset,
2657 DeadOffset, DeadLocWrapper.DefInst, IOL);
2659 if (Opts.enable_dse_partial_store_merging &&
2660 OR == OW_PartialEarlierWithFullLater) {
2666 if (DeadSI && KillingSI && DT.
dominates(DeadSI, KillingSI)) {
2668 KillingSI, DeadSI, KillingOffset, DeadOffset,
DL, BatchAA,
2672 DeadSI->setOperand(0, Merged);
2673 ++NumModifiedStores;
2675 DeletedKillingLoc =
true;
2680 auto I = IOLs.find(DeadSI->getParent());
2681 if (
I != IOLs.end())
2682 I->second.erase(DeadSI);
2687 if (OR == OW_Complete) {
2689 << *DeadLocWrapper.DefInst <<
"\n KILLER: "
2690 << *KillingLocWrapper.DefInst <<
'\n');
2698 assert(SkipStores.size() - OrigNumSkipStores ==
Deleted.size() &&
2699 "SkipStores and Deleted out of sync?");
2701 return {
Changed, DeletedKillingLoc};
2704bool DSEState::eliminateDeadDefs(
const MemoryDefWrapper &KillingDefWrapper) {
2705 if (KillingDefWrapper.DefinedLocations.empty()) {
2706 LLVM_DEBUG(
dbgs() <<
"Failed to find analyzable write location for "
2707 << *KillingDefWrapper.DefInst <<
"\n");
2711 bool MadeChange =
false;
2712 for (
auto &KillingLocWrapper : KillingDefWrapper.DefinedLocations) {
2714 << *KillingLocWrapper.MemDef <<
" ("
2715 << *KillingLocWrapper.DefInst <<
")\n");
2716 auto [
Changed, DeletedKillingLoc] = eliminateDeadDefs(KillingLocWrapper);
2720 if (!DeletedKillingLoc && storeIsNoop(KillingLocWrapper.MemDef,
2721 KillingLocWrapper.UnderlyingObject)) {
2723 << *KillingLocWrapper.DefInst <<
'\n');
2725 NumRedundantStores++;
2730 if (!DeletedKillingLoc &&
2731 tryFoldIntoCalloc(KillingLocWrapper.MemDef,
2732 KillingLocWrapper.UnderlyingObject)) {
2733 LLVM_DEBUG(
dbgs() <<
"DSE: Remove memset after forming calloc:\n"
2734 <<
" DEAD: " << *KillingLocWrapper.DefInst <<
'\n');
2748 bool MadeChange =
false;
2749 DSEState State(Opts,
F,
AA, MSSA, DT, PDT, TLI, CI);
2751 for (
unsigned I = 0;
I < State.MemDefs.size();
I++) {
2753 if (State.SkipStores.count(KillingDef))
2756 MemoryDefWrapper KillingDefWrapper(
2759 Opts.enable_dse_initializes_attr_improvement));
2760 MadeChange |= State.eliminateDeadDefs(KillingDefWrapper);
2763 if (Opts.enable_dse_partial_overwrite_tracking)
2764 for (
auto &KV : State.IOLs)
2765 MadeChange |= State.removePartiallyOverlappedStores(KV.second);
2767 MadeChange |= State.eliminateRedundantStoresOfExistingValues();
2768 MadeChange |= State.eliminateDeadWritesAtEndOfFunction();
2769 MadeChange |= State.eliminateRedundantStoresViaDominatingConditions();
2771 while (!State.ToRemove.empty()) {
2772 Instruction *DeadInst = State.ToRemove.pop_back_val();
2792#ifdef LLVM_ENABLE_STATS
2819 if (skipFunction(
F))
2822 AliasAnalysis &
AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
2823 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
2825 getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
2826 MemorySSA &MSSA = getAnalysis<MemorySSAWrapperPass>().getMSSA();
2828 getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
2829 CycleInfo &CI = getAnalysis<CycleInfoWrapperPass>().getResult();
2833#ifdef LLVM_ENABLE_STATS
2842 void getAnalysisUsage(AnalysisUsage &AU)
const override {
2858char DSELegacyPass::ID = 0;
2875 return new DSELegacyPass();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Lower Kernel Arguments
This file implements a class to represent arbitrary precision integral constant values and operations...
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file declares an analysis pass that computes CycleInfo for LLVM IR, specialized from GenericCycl...
DXIL Forward Handle Accesses
static void shortenAssignment(Instruction *Inst, Value *OriginalDest, uint64_t OldSizeInBits, uint64_t NewSizeInBits, bool IsOverwriteEnd)
static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, PostDominatorTree &PDT, const TargetLibraryInfo &TLI, const CycleInfo &CI)
MapVector< Instruction *, OverlapIntervalsTy > InstOverlapIntervalsTy
static bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller)
static bool isShortenableAtTheEnd(Instruction *I)
Returns true if the end of this instruction can be safely shortened in length.
static bool isNoopIntrinsic(Instruction *I)
static ConstantRangeList getIntersectedInitRangeList(ArrayRef< ArgumentInitInfo > Args, bool CallHasNoUnwindAttr)
static bool tryToShortenBegin(Instruction *DeadI, OverlapIntervalsTy &IntervalMap, int64_t &DeadStart, uint64_t &DeadSize)
std::map< int64_t, int64_t > OverlapIntervalsTy
static void pushMemUses(MemoryAccess *Acc, SmallVectorImpl< MemoryAccess * > &WorkList, SmallPtrSetImpl< MemoryAccess * > &Visited)
static bool isShortenableAtTheBeginning(Instruction *I)
Returns true if the beginning of this instruction can be safely shortened in length.
static Constant * tryToMergePartialOverlappingStores(StoreInst *KillingI, StoreInst *DeadI, int64_t KillingOffset, int64_t DeadOffset, const DataLayout &DL, BatchAAResults &AA, DominatorTree *DT)
static OverwriteResult isPartialOverwrite(const ScalarOptions &Opts, const MemoryLocation &KillingLoc, const MemoryLocation &DeadLoc, int64_t KillingOff, int64_t DeadOff, Instruction *DeadI, InstOverlapIntervalsTy &IOL)
Return 'OW_Complete' if a store to the 'KillingLoc' location completely overwrites a store to the 'De...
static bool memoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI, BatchAAResults &AA, const DataLayout &DL, DominatorTree *DT)
Returns true if the memory which is accessed by the second instruction is not modified between the fi...
static OverwriteResult isMaskedStoreOverwrite(const Instruction *KillingI, const Instruction *DeadI, BatchAAResults &AA)
Check if two instruction are masked stores that completely overwrite one another.
static bool tryToShorten(Instruction *DeadI, int64_t &DeadStart, uint64_t &DeadSize, int64_t KillingStart, uint64_t KillingSize, bool IsOverwriteEnd)
static bool isFuncLocalAndNotCaptured(Value *Arg, const CallBase *CB, EarliestEscapeAnalysis &EA)
static std::optional< TypeSize > getPointerSize(const Value *V, const DataLayout &DL, const TargetLibraryInfo &TLI, const Function *F)
static bool tryToShortenEnd(Instruction *DeadI, OverlapIntervalsTy &IntervalMap, int64_t &DeadStart, uint64_t &DeadSize)
static void adjustArgAttributes(AnyMemIntrinsic *Intrinsic, unsigned ArgNo, uint64_t PtrOffset)
Update the attributes given that a memory access is updated (the dereferenced pointer could be moved ...
static bool hasInitializesAttr(Instruction *I)
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
This file defines the DenseMap class.
early cse Early CSE w MemorySSA
static bool runOnFunction(Function &F, bool PostInlining)
This is the interface for a simple mod/ref and alias analysis over globals.
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
static void deleteDeadInstruction(Instruction *I)
This file implements a map that provides insertion order iteration.
This file provides utility analysis objects describing memory locations.
This file exposes an interface to building/using memory SSA to walk memory instructions using a use/d...
Contains a collection of routines for determining if a given instruction is guaranteed to execute if ...
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
SmallVector< MachineOperand, 4 > Cond
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 bool VisitNode(MachineDomTreeNode *Node, Register TLSBaseAddrReg)
A manager for alias analyses.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit)
Get a value with a block of bits set.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
int64_t getSExtValue() const
Get sign extended value.
@ NoAlias
The two locations do not alias at all.
@ PartialAlias
The two locations alias, but only due to a partial overlap.
@ MustAlias
The two locations precisely alias each other.
constexpr int32_t getOffset() const
constexpr bool hasOffset() const
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
This class represents an incoming formal argument to a Function.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
An immutable pass that tracks lazily created AssumptionCache objects.
This class stores enough information to efficiently remove some attributes from an existing AttrBuild...
AttributeMask & addAttribute(Attribute::AttrKind Val)
Add an attribute to the mask.
This class holds the attributes for a particular argument, parameter, function, or return value.
LLVM_ABI ArrayRef< ConstantRange > getValueAsConstantRangeList() const
Return the attribute's value as a ConstantRange array.
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
bool isValid() const
Return true if the attribute is any kind of attribute.
LLVM Basic Block Representation.
const Function * getParent() const
Return the enclosing method, or null if none.
InstListType::iterator iterator
Instruction iterators...
This class is a wrapper over an AAResults, and it is intended to be used only when there are no IR ch...
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
bool isMustAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
ModRefInfo getModRefInfo(const Instruction *I, const std::optional< MemoryLocation > &OptLoc)
Represents analyses that only rely on functions' control flow.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
LLVM_ABI bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Determine whether the argument or parameter has the given attribute.
Attribute getParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Get the attribute of a given kind from a given arg.
bool isByValArgument(unsigned ArgNo) const
Determine whether this argument is passed by value.
LLVM_ABI bool onlyAccessesInaccessibleMemOrArgMem() const
Determine if the function may only access memory that is either inaccessible from the IR or pointed t...
bool doesNotThrow() const
Determine if the call cannot unwind.
Value * getArgOperand(unsigned i) const
LLVM_ABI Value * getArgOperandWithAttribute(Attribute::AttrKind Kind) const
If one of the arguments has the specified attribute, returns its operand value.
unsigned arg_size() const
This class represents a list of constant ranges.
bool empty() const
Return true if this list contains no members.
LLVM_ABI ConstantRangeList intersectWith(const ConstantRangeList &CRL) const
Return the range list that results from the intersection of this ConstantRangeList with another Const...
const APInt & getLower() const
Return the lower value for this range.
const APInt & getUpper() const
Return the upper value for this range.
This is an important base class in LLVM.
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
Analysis pass which computes a CycleInfo.
Legacy analysis pass which computes a CycleInfo.
static DIAssignID * getDistinct(LLVMContext &Context)
DbgVariableFragmentInfo FragmentInfo
static LLVM_ABI std::optional< DIExpression * > createFragmentExpression(const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits)
Create a DIExpression to describe one part of an aggregate variable that is fragmented across multipl...
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
A parsed version of the target data layout string in and methods for querying it.
Record of a variable value-assignment, aka a non instruction representation of the dbg....
static bool shouldExecute(CounterInfo &Counter)
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Analysis pass which computes a DominatorTree.
DomTreeNodeBase< NodeT > * getRootNode()
getRootNode - This returns the entry node for the CFG of the function.
NodeT * findNearestCommonDominator(NodeT *A, NodeT *B) const
Find nearest common dominator basic block for basic block A and B.
iterator_range< root_iterator > roots()
bool properlyDominates(const DomTreeNodeBase< NodeT > *A, const DomTreeNodeBase< NodeT > *B) const
properlyDominates - Returns true iff A dominates B and A != B.
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
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.
Context-sensitive CaptureAnalysis provider, which computes and caches the earliest common dominator c...
void removeInstruction(Instruction *I)
CaptureComponents getCapturesBefore(const Value *Object, const Instruction *I, bool OrAt, bool ReturnCaptures) override
Return how Object may be captured before instruction I, considering only provenance captures.
FunctionPass class - This class is used to implement most global optimizations.
const BasicBlock & getEntryBlock() const
CycleRef getCycle(const BlockT *Block) const
Find the innermost cycle containing Block.
static GetElementPtrInst * CreateInBounds(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Create an "inbounds" getelementptr.
Legacy wrapper pass to provide the GlobalsAAResult object.
bool isEquality() const
Return true if this predicate is either EQ or NE.
LLVM_ABI bool mayThrow(bool IncludePhaseOneUnwind=false) const LLVM_READONLY
Return true if this instruction may throw an exception.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
LLVM_ABI bool isAtomic() const LLVM_READONLY
Return true if this instruction has an AtomicOrdering of unordered or higher.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI bool isIdenticalToWhenDefined(const Instruction *I, bool IntersectAttrs=false) const LLVM_READONLY
This is like isIdenticalTo, except that it ignores the SubclassOptionalData flags,...
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
LLVM_ABI AAMDNodes getAAMetadata() const
Returns the AA metadata for this instruction.
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.
const_iterator begin() const
bool empty() const
empty - Return true when no intervals are mapped.
const_iterator end() const
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
static LocationSize precise(uint64_t Value)
TypeSize getValue() const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
This class implements a map that also provides access to all stored values in a deterministic order.
Value * getLength() const
BasicBlock * getBlock() const
Represents a read-write access to memory, whether it is a must-alias, or a may-alias.
void setOptimized(MemoryAccess *MA)
A wrapper analysis pass for the legacy pass manager that exposes a MemoryDepnedenceResults instance.
Representation for a specific memory location.
static LLVM_ABI MemoryLocation get(const LoadInst *LI)
Return a location with information about the memory reference by the given instruction.
LocationSize Size
The maximum size of the location, in address-units, or UnknownSize if the size is not known.
static MemoryLocation getBeforeOrAfter(const Value *Ptr, const AAMDNodes &AATags=AAMDNodes())
Return a location that may access any location before or after Ptr, while remaining within the underl...
static MemoryLocation getAfter(const Value *Ptr, const AAMDNodes &AATags=AAMDNodes())
Return a location that may access any location after Ptr, while remaining within the underlying objec...
MemoryLocation getWithNewPtr(const Value *NewPtr) const
const Value * Ptr
The address of the start of the location.
static LLVM_ABI MemoryLocation getForDest(const MemIntrinsic *MI)
Return a location representing the destination of a memory set or transfer.
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static LLVM_ABI MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx, const TargetLibraryInfo *TLI)
Return a location representing a particular argument of a call.
An analysis that produces MemorySSA for a function.
MemoryAccess * getClobberingMemoryAccess(const Instruction *I, BatchAAResults &AA)
Given a memory Mod/Ref/ModRef'ing instruction, calling this will give you the nearest dominating Memo...
Legacy analysis pass which computes MemorySSA.
Encapsulates MemorySSA, including all data associated with memory accesses.
DefsList * getBlockDefs(const BasicBlock *BB) const
Return the list of MemoryDef's and MemoryPhi's for a given basic block.
LLVM_ABI MemorySSAWalker * getSkipSelfWalker()
LLVM_ABI bool dominates(const MemoryAccess *A, const MemoryAccess *B) const
Given two memory accesses in potentially different blocks, determine whether MemoryAccess A dominates...
LLVM_ABI MemorySSAWalker * getWalker()
MemoryUseOrDef * getMemoryAccess(const Instruction *I) const
Given a memory Mod/Ref'ing instruction, get the MemorySSA access associated with it.
bool isLiveOnEntryDef(const MemoryAccess *MA) const
Return true if MA represents the live on entry value.
MemoryAccess * getDefiningAccess() const
Get the access that produces the memory state used by this Use.
Instruction * getMemoryInst() const
Get the instruction that this MemoryUse represents.
PHITransAddr - An address value which tracks and handles phi translation.
LLVM_ABI Value * translateValue(BasicBlock *CurBB, BasicBlock *PredBB, const DominatorTree *DT, bool MustDominate)
translateValue - PHI translate the current address up the CFG from CurBB to Pred, updating our state ...
LLVM_ABI bool isPotentiallyPHITranslatable() const
isPotentiallyPHITranslatable - If this needs PHI translation, return true if we have some hope of doi...
bool needsPHITranslationFromBlock(BasicBlock *BB) const
needsPHITranslationFromBlock - Return true if moving from the specified BasicBlock to its predecessor...
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Analysis pass which computes a PostDominatorTree.
PostDominatorTree Class - Concrete subclass of DominatorTree that is used to compute the post-dominat...
LLVM_ABI bool dominates(const Instruction *I1, const Instruction *I2) const
Return true if I1 dominates I2.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
size_type size() const
Determine the number of elements in the SetVector.
void insert_range(Range &&R)
bool insert(const value_type &X)
Insert a new element into the SetVector.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
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.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this store instruction.
Value * getValueOperand()
constexpr bool empty() const
Check if the string is empty.
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
bool has(LibFunc F) const
Tests whether a library function is available.
LibFunc getLibFunc(StringRef funcName) const
Searches for a particular function name.
static constexpr TypeSize getFixed(ScalarTy ExactSize)
bool isPointerTy() const
True if this is an instance of PointerType.
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this 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.
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
iterator_range< use_iterator > uses()
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
const ParentTy * getParent() const
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ BasicBlock
Various leaf nodes.
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
bool match(Val *V, const Pattern &P)
match_bind< Instruction > m_Instruction(Instruction *&I)
Match an instruction, capturing it if we match.
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
CmpClass_match< LHS, RHS, ICmpInst, true > m_c_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
Matches an ICmp with a predicate over LHS and RHS in either order.
auto m_Value()
Match an arbitrary value and ignore it.
SpecificCmpClass_match< LHS, RHS, ICmpInst > m_SpecificICmp(CmpPredicate MatchPred, const LHS &L, const RHS &R)
OneOps_match< OpTy, Instruction::Load > m_Load(const OpTy &Op)
Matches LoadInst.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
brc_match< Cond_t, match_bind< BasicBlock >, match_bind< BasicBlock > > m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F)
SmallVector< DbgVariableRecord * > getDVRAssignmentMarkers(const Instruction *Inst)
Return a range of dbg_assign records for which Inst performs the assignment they encode.
LLVM_ABI bool calculateFragmentIntersect(const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, uint64_t SliceSizeInBits, const DbgVariableRecord *DVRAssign, std::optional< DIExpression::FragmentInfo > &Result)
Calculate the fragment of the variable in DAI covered from (Dest + SliceOffsetInBits) to to (Dest + S...
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
NodeAddr< DefNode * > Def
NodeAddr< NodeBase * > Node
NodeAddr< FuncNode * > Func
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
LLVM_ABI void initializeDSELegacyPassPass(PassRegistry &)
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,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
bool isAligned(Align Lhs, uint64_t SizeInBytes)
Checks that SizeInBytes is a multiple of the alignment.
LLVM_ABI void salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI)
Assuming the instruction MI is going to be deleted, attempt to salvage debug users of MI by writing t...
@ Store
The extracted value is stored (ExtractElement only).
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.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
LLVM_ABI bool isNoAliasCall(const Value *V)
Return true if this pointer is returned by a noalias function.
const ScalarOptions & getScalarOptions(const LLVMContext &C)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
DomTreeNodeBase< BasicBlock > DomTreeNode
auto make_isa_range(RangeT &&Range)
Return a range over Range containing only elements for which isa<T> holds, casting each of them to T.
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.
LLVM_ABI bool isInstructionTriviallyDead(Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction is not used, and the instruction will return.
LLVM_ABI bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, const TargetLibraryInfo *TLI, ObjectSizeOpts Opts={})
Compute the size of the object pointed by Ptr.
auto reverse(ContainerTy &&C)
LLVM_ABI bool canReplacePointersIfEqual(const Value *From, const Value *To, const DataLayout &DL)
Returns true if a pointer value From can be replaced with another pointer value \To if they are deeme...
bool isModSet(const ModRefInfo MRI)
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.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
LLVM_ABI bool AreStatisticsEnabled()
Check if statistics are enabled.
LLVM_ABI bool isNotVisibleOnUnwind(const Value *Object, bool &RequiresNoCaptureBeforeUnwind)
Return true if Object memory is not visible after an unwind, in the sense that program semantics cann...
LLVM_ABI Value * emitCalloc(Value *Num, Value *Size, IRBuilderBase &B, const TargetLibraryInfo &TLI, unsigned AddrSpace)
Emit a call to the calloc function.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto post_order(const T &G)
Post-order traversal of a graph.
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...
uint64_t offsetToAlignment(uint64_t Value, Align Alignment)
Returns the offset to the next integer (mod 2**64) that is greater than or equal to Value and is a mu...
LLVM_ABI bool salvageKnowledge(Instruction *I, AssumptionCache *AC=nullptr, DominatorTree *DT=nullptr)
Calls BuildAssumeFromInst and if the resulting llvm.assume is valid insert if before I.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
LLVM_ABI bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, unsigned MaxUsesToExplore=0)
PointerMayBeCaptured - Return true if this pointer value may be captured by the enclosing function (w...
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.
LLVM_ABI bool isIdentifiedFunctionLocal(const Value *V)
Return true if V is umabigously identified at the function-level.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI FunctionPass * createDeadStoreEliminationPass()
LLVM_ABI Value * isBytewiseValue(Value *V, const DataLayout &DL)
If the specified value can be set by repeating the same byte in memory, return the i8 value that it i...
auto predecessors(const MachineBasicBlock *BB)
bool capturesAnything(CaptureComponents CC)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
@ End
Run the machine verifier once, at the end of the pipeline.
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
bool capturesNothing(CaptureComponents CC)
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
bool isStrongerThan(AtomicOrdering AO, AtomicOrdering Other)
Returns true if ao is stronger than other as defined by the AtomicOrdering lattice,...
bool isRefSet(const ModRefInfo MRI)
This struct is a compact representation of a valid (non-zero power of two) alignment.
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Various options to control the behavior of getObjectSize.
bool NullIsUnknownSize
If this is true, null pointers in address space 0 will be treated as though they can't be evaluated.