102#define DEBUG_TYPE "sroa"
104STATISTIC(NumAllocasAnalyzed,
"Number of allocas analyzed for replacement");
105STATISTIC(NumAllocaPartitions,
"Number of alloca partitions formed");
106STATISTIC(MaxPartitionsPerAlloca,
"Maximum number of partitions per alloca");
107STATISTIC(NumAllocaPartitionUses,
"Number of alloca partition uses rewritten");
108STATISTIC(MaxUsesPerAllocaPartition,
"Maximum number of uses of a partition");
109STATISTIC(NumNewAllocas,
"Number of new, smaller allocas introduced");
110STATISTIC(NumPromoted,
"Number of allocas promoted to SSA values");
111STATISTIC(NumLoadsSpeculated,
"Number of loads speculated to allow promotion");
113 "Number of loads rewritten into predicated loads to allow promotion");
116 "Number of stores rewritten into predicated stores to allow promotion");
118STATISTIC(NumVectorized,
"Number of vectorized aggregates");
122class AllocaSliceRewriter;
127class SelectHandSpeculativity {
128 unsigned char Storage = 0;
132 SelectHandSpeculativity() =
default;
133 SelectHandSpeculativity &setAsSpeculatable(
bool isTrueVal);
134 bool isSpeculatable(
bool isTrueVal)
const;
135 bool areAllSpeculatable()
const;
136 bool areAnySpeculatable()
const;
137 bool areNoneSpeculatable()
const;
139 explicit operator intptr_t()
const {
return static_cast<intptr_t
>(Storage); }
140 explicit SelectHandSpeculativity(intptr_t Storage_) : Storage(Storage_) {}
142static_assert(
sizeof(SelectHandSpeculativity) ==
sizeof(
unsigned char));
144using PossiblySpeculatableLoad =
147using RewriteableMemOp =
148 std::variant<PossiblySpeculatableLoad, UnspeculatableStore>;
150using InstructionSliceMap =
172 LLVMContext *
const C;
173 DomTreeUpdater *
const DTU;
174 AssumptionCache *
const AC;
175 const bool PreserveCFG;
176 const bool AggregateToVector;
185 SmallSetVector<AllocaInst *, 16> Worklist;
200 SmallSetVector<AllocaInst *, 16> PostPromotionWorklist;
203 SetVector<AllocaInst *, SmallVector<AllocaInst *>,
204 SmallPtrSet<AllocaInst *, 16>, 16>
212 SmallSetVector<PHINode *, 8> SpeculatablePHIs;
219 SmallSetVector<PHINode *, 8> PHIsWithStoreToRewrite;
223 SmallMapVector<SelectInst *, RewriteableMemOps, 8> SelectsToRewrite;
268 static std::optional<RewriteableMemOps>
269 isSafeSelectToSpeculateOrPredicate(SelectInst &SI,
bool PreserveCFG);
272 SROA(LLVMContext *C, DomTreeUpdater *DTU, AssumptionCache *AC,
274 : C(C), DTU(DTU), AC(AC),
275 PreserveCFG(
Options.
CFG == SROAOptions::PreserveCFG),
276 AggregateToVector(
Options.AggregateToVector) {}
279 std::pair<
bool ,
bool > runSROA(
Function &
F);
282 friend class AllocaSliceRewriter;
284 bool presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS);
285 std::pair<AllocaInst *, uint64_t>
286 rewritePartition(AllocaInst &AI, AllocaSlices &AS, Partition &
P);
287 bool splitAlloca(AllocaInst &AI, AllocaSlices &AS);
288 bool propagateStoredValuesToLoads(AllocaInst &AI, AllocaSlices &AS);
289 std::pair<
bool ,
bool > runOnAlloca(AllocaInst &AI);
290 void clobberUse(Use &U);
291 bool deleteDeadInstructions(AllocaInst *AI,
292 SmallPtrSetImpl<AllocaInst *> &DeletedAllocas);
293 bool promoteAllocas();
307enum FragCalcResult { UseFrag, UseNoFrag,
Skip };
311 uint64_t NewStorageSliceOffsetInBits,
313 std::optional<DIExpression::FragmentInfo> StorageFragment,
314 std::optional<DIExpression::FragmentInfo> CurrentFragment,
318 if (StorageFragment) {
320 std::min(NewStorageSliceSizeInBits, StorageFragment->SizeInBits);
322 NewStorageSliceOffsetInBits + StorageFragment->OffsetInBits;
324 Target.SizeInBits = NewStorageSliceSizeInBits;
325 Target.OffsetInBits = NewStorageSliceOffsetInBits;
331 if (!CurrentFragment) {
332 if (
auto Size = Variable->getSizeInBits()) {
335 if (
Target == CurrentFragment)
342 if (!CurrentFragment || *CurrentFragment ==
Target)
348 if (
Target.startInBits() < CurrentFragment->startInBits() ||
349 Target.endInBits() > CurrentFragment->endInBits())
388 if (DVRAssignMarkerRange.empty())
394 LLVM_DEBUG(
dbgs() <<
" OldAllocaOffsetInBits: " << OldAllocaOffsetInBits
396 LLVM_DEBUG(
dbgs() <<
" SliceSizeInBits: " << SliceSizeInBits <<
"\n");
408 DVR->getExpression()->getFragmentInfo();
421 auto *Expr = DbgAssign->getExpression();
422 bool SetKillLocation =
false;
425 std::optional<DIExpression::FragmentInfo> BaseFragment;
428 if (R == BaseFragments.
end())
430 BaseFragment = R->second;
432 std::optional<DIExpression::FragmentInfo> CurrentFragment =
433 Expr->getFragmentInfo();
436 DbgAssign->getVariable(), OldAllocaOffsetInBits, SliceSizeInBits,
437 BaseFragment, CurrentFragment, NewFragment);
441 if (Result == UseFrag && !(NewFragment == CurrentFragment)) {
442 if (CurrentFragment) {
447 NewFragment.
OffsetInBits -= CurrentFragment->OffsetInBits;
460 SetKillLocation =
true;
468 Inst->
setMetadata(LLVMContext::MD_DIAssignID, NewID);
475 Inst, NewValue, DbgAssign->getVariable(), Expr, Dest,
479 NewAssign = DbgAssign;
498 Value && (DbgAssign->hasArgList() ||
499 !DbgAssign->getExpression()->isSingleLocationExpression());
516 if (NewAssign != DbgAssign) {
517 NewAssign->
moveBefore(DbgAssign->getIterator());
520 LLVM_DEBUG(
dbgs() <<
"Created new assign: " << *NewAssign <<
"\n");
523 for_each(DVRAssignMarkerRange, MigrateDbgAssign);
533 Twine getNameWithPrefix(
const Twine &Name)
const {
538 void SetNamePrefix(
const Twine &
P) { Prefix =
P.str(); }
540 void InsertHelper(Instruction *
I,
const Twine &Name,
565 PointerIntPair<Use *, 1, bool> UseAndIsSplittable;
571 : BeginOffset(BeginOffset), EndOffset(EndOffset),
572 UseAndIsSplittable(
U, IsSplittable) {}
574 uint64_t beginOffset()
const {
return BeginOffset; }
575 uint64_t endOffset()
const {
return EndOffset; }
577 bool isSplittable()
const {
return UseAndIsSplittable.getInt(); }
578 void makeUnsplittable() { UseAndIsSplittable.setInt(
false); }
580 Use *getUse()
const {
return UseAndIsSplittable.getPointer(); }
582 bool isDead()
const {
return getUse() ==
nullptr; }
583 void kill() { UseAndIsSplittable.setPointer(
nullptr); }
592 if (beginOffset() <
RHS.beginOffset())
594 if (beginOffset() >
RHS.beginOffset())
596 if (isSplittable() !=
RHS.isSplittable())
597 return !isSplittable();
598 if (endOffset() >
RHS.endOffset())
605 return LHS.beginOffset() < RHSOffset;
608 return LHSOffset <
RHS.beginOffset();
612 return isSplittable() ==
RHS.isSplittable() &&
613 beginOffset() ==
RHS.beginOffset() && endOffset() ==
RHS.endOffset();
628 AllocaSlices(
const DataLayout &
DL, AllocaInst &AI);
634 bool isEscaped()
const {
return PointerEscapingInstr; }
635 bool isEscapedReadOnly()
const {
return PointerEscapingInstrReadOnly; }
640 using range = iterator_range<iterator>;
642 iterator
begin() {
return Slices.begin(); }
643 iterator
end() {
return Slices.end(); }
647 const_iterator
begin()
const {
return Slices.begin(); }
648 const_iterator
end()
const {
return Slices.end(); }
652 void erase(iterator Start, iterator Stop) { Slices.erase(Start, Stop); }
660 int OldSize = Slices.size();
661 Slices.append(NewSlices.
begin(), NewSlices.
end());
662 auto SliceI = Slices.begin() + OldSize;
663 std::stable_sort(SliceI, Slices.end());
664 std::inplace_merge(Slices.begin(), SliceI, Slices.end());
673 ArrayRef<Instruction *> getDeadUsers()
const {
return DeadUsers; }
677 return DeadUseIfPromotable;
688#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
689 void print(raw_ostream &OS, const_iterator
I, StringRef Indent =
" ")
const;
690 void printSlice(raw_ostream &OS, const_iterator
I,
691 StringRef Indent =
" ")
const;
692 void printUse(raw_ostream &OS, const_iterator
I,
693 StringRef Indent =
" ")
const;
694 void print(raw_ostream &OS)
const;
695 void dump(const_iterator
I)
const;
702 friend class AllocaSlices::SliceBuilder;
704#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
732 SmallVector<Instruction *, 8> DeadUsers;
759 friend class AllocaSlices;
760 friend class AllocaSlices::partition_iterator;
762 using iterator = AllocaSlices::iterator;
766 uint64_t BeginOffset = 0, EndOffset = 0;
776 Partition(iterator SI) : SI(SI), SJ(SI) {}
782 uint64_t beginOffset()
const {
return BeginOffset; }
787 uint64_t endOffset()
const {
return EndOffset; }
793 assert(BeginOffset < EndOffset &&
"Partitions must span some bytes!");
794 return EndOffset - BeginOffset;
799 bool empty()
const {
return SI == SJ; }
810 iterator
begin()
const {
return SI; }
811 iterator
end()
const {
return SJ; }
843 AllocaSlices::iterator SE;
847 uint64_t MaxSplitSliceEndOffset = 0;
851 partition_iterator(AllocaSlices::iterator
SI, AllocaSlices::iterator SE)
863 assert((
P.SI != SE || !
P.SplitTails.empty()) &&
864 "Cannot advance past the end of the slices!");
867 if (!
P.SplitTails.empty()) {
868 if (
P.EndOffset >= MaxSplitSliceEndOffset) {
870 P.SplitTails.clear();
871 MaxSplitSliceEndOffset = 0;
877 [&](Slice *S) { return S->endOffset() <= P.EndOffset; });
880 return S->endOffset() == MaxSplitSliceEndOffset;
882 "Could not find the current max split slice offset!");
885 return S->endOffset() <= MaxSplitSliceEndOffset;
887 "Max split slice end offset is not actually the max!");
894 assert(P.SplitTails.empty() &&
"Failed to clear the split slices!");
904 if (S.isSplittable() && S.endOffset() > P.EndOffset) {
905 P.SplitTails.push_back(&S);
906 MaxSplitSliceEndOffset =
907 std::max(S.endOffset(), MaxSplitSliceEndOffset);
915 P.BeginOffset = P.EndOffset;
916 P.EndOffset = MaxSplitSliceEndOffset;
923 if (!P.SplitTails.empty() && P.SI->beginOffset() != P.EndOffset &&
924 !P.SI->isSplittable()) {
925 P.BeginOffset = P.EndOffset;
926 P.EndOffset = P.SI->beginOffset();
936 P.BeginOffset = P.SplitTails.empty() ? P.SI->beginOffset() : P.EndOffset;
937 P.EndOffset = P.SI->endOffset();
942 if (!P.SI->isSplittable()) {
945 assert(P.BeginOffset == P.SI->beginOffset());
949 while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) {
950 if (!P.SJ->isSplittable())
951 P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset());
963 assert(P.SI->isSplittable() &&
"Forming a splittable partition!");
966 while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset &&
967 P.SJ->isSplittable()) {
968 P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset());
975 if (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) {
976 assert(!P.SJ->isSplittable());
977 P.EndOffset = P.SJ->beginOffset();
984 "End iterators don't match between compared partition iterators!");
991 if (P.SI == RHS.P.SI && P.SplitTails.empty() == RHS.P.SplitTails.empty()) {
992 assert(P.SJ == RHS.P.SJ &&
993 "Same set of slices formed two different sized partitions!");
994 assert(P.SplitTails.size() == RHS.P.SplitTails.size() &&
995 "Same slice position with differently sized non-empty split "
1018 return make_range(partition_iterator(begin(), end()),
1019 partition_iterator(end(), end()));
1027 return SI.getOperand(1 + CI->isZero());
1028 if (
SI.getOperand(1) ==
SI.getOperand(2))
1029 return SI.getOperand(1);
1038 return PN->hasConstantValue();
1053 const uint64_t AllocSize;
1069 if (VisitedDeadInsts.
insert(&
I).second)
1074 bool IsSplittable =
false) {
1080 <<
" which has zero size or starts outside of the "
1081 << AllocSize <<
" byte alloca:\n"
1082 <<
" alloca: " << AS.AI <<
"\n"
1083 <<
" use: " <<
I <<
"\n");
1084 return markAsDead(
I);
1096 assert(AllocSize >= BeginOffset);
1097 if (
Size > AllocSize - BeginOffset) {
1099 <<
Offset <<
" to remain within the " << AllocSize
1100 <<
" byte alloca:\n"
1101 <<
" alloca: " << AS.AI <<
"\n"
1102 <<
" use: " <<
I <<
"\n");
1103 EndOffset = AllocSize;
1106 AS.Slices.push_back(Slice(BeginOffset, EndOffset, U, IsSplittable));
1109 void visitBitCastInst(BitCastInst &BC) {
1111 return markAsDead(BC);
1113 return Base::visitBitCastInst(BC);
1116 void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
1118 return markAsDead(ASC);
1120 return Base::visitAddrSpaceCastInst(ASC);
1123 void visitGetElementPtrInst(GetElementPtrInst &GEPI) {
1125 return markAsDead(GEPI);
1127 return Base::visitGetElementPtrInst(GEPI);
1130 void handleLoadOrStore(
Type *Ty, Instruction &
I,
const APInt &
Offset,
1141 void visitLoadInst(LoadInst &LI) {
1143 "All simple FCA loads should have been pre-split");
1148 return PI.setEscapedReadOnly(&LI);
1151 if (
Size.isScalable()) {
1154 return PI.setAborted(&LI);
1163 void visitStoreInst(StoreInst &SI) {
1164 Value *ValOp =
SI.getValueOperand();
1166 return PI.setEscapedAndAborted(&SI);
1168 return PI.setAborted(&SI);
1170 TypeSize StoreSize =
DL.getTypeStoreSize(ValOp->
getType());
1172 unsigned VScale =
SI.getFunction()->getVScaleValue();
1174 return PI.setAborted(&SI);
1190 <<
Offset <<
" which extends past the end of the "
1191 << AllocSize <<
" byte alloca:\n"
1192 <<
" alloca: " << AS.AI <<
"\n"
1193 <<
" use: " << SI <<
"\n");
1194 return markAsDead(SI);
1198 "All simple FCA stores should have been pre-split");
1202 void visitMemSetInst(MemSetInst &
II) {
1203 assert(
II.getRawDest() == *U &&
"Pointer use is not the destination?");
1206 (IsOffsetKnown &&
Offset.uge(AllocSize)))
1208 return markAsDead(
II);
1211 return PI.setAborted(&
II);
1215 : AllocSize -
Offset.getLimitedValue(),
1219 void visitMemTransferInst(MemTransferInst &
II) {
1223 return markAsDead(
II);
1227 if (VisitedDeadInsts.
count(&
II))
1231 return PI.setAborted(&
II);
1238 if (
Offset.uge(AllocSize)) {
1239 auto MTPI = MemTransferSliceMap.
find(&
II);
1240 if (MTPI != MemTransferSliceMap.
end())
1241 AS.Slices[MTPI->second].kill();
1242 return markAsDead(
II);
1250 if (*U ==
II.getRawDest() && *U ==
II.getRawSource()) {
1252 if (!
II.isVolatile())
1253 return markAsDead(
II);
1261 SmallDenseMap<Instruction *, unsigned>::iterator MTPI;
1262 std::tie(MTPI, Inserted) =
1263 MemTransferSliceMap.
insert(std::make_pair(&
II, AS.Slices.size()));
1264 unsigned PrevIdx = MTPI->second;
1266 Slice &PrevP = AS.Slices[PrevIdx];
1270 if (!
II.isVolatile() && PrevP.beginOffset() == RawOffset) {
1272 return markAsDead(
II);
1277 PrevP.makeUnsplittable();
1284 assert(AS.Slices[PrevIdx].getUse()->getUser() == &
II &&
1285 "Map index doesn't point back to a slice with this user.");
1291 void visitIntrinsicInst(IntrinsicInst &
II) {
1292 if (
II.isDroppable()) {
1293 AS.DeadUseIfPromotable.push_back(U);
1298 return PI.setAborted(&
II);
1300 if (
II.isLifetimeStartOrEnd()) {
1301 insertUse(
II,
Offset, AllocSize,
true);
1305 Base::visitIntrinsicInst(
II);
1313 SmallPtrSet<Instruction *, 4> Visited;
1323 std::tie(UsedI,
I) =
Uses.pop_back_val();
1326 TypeSize LoadSize =
DL.getTypeStoreSize(LI->
getType());
1338 TypeSize StoreSize =
DL.getTypeStoreSize(
Op->getType());
1348 if (!
GEP->hasAllZeroIndices())
1355 for (User *U :
I->users())
1358 }
while (!
Uses.empty());
1363 void visitPHINodeOrSelectInst(Instruction &
I) {
1366 return markAsDead(
I);
1372 return PI.setAborted(&
I);
1390 AS.DeadOperands.push_back(U);
1396 return PI.setAborted(&
I);
1402 if (Instruction *UnsafeI = hasUnsafePHIOrSelectUse(&
I,
Size))
1403 return PI.setAborted(UnsafeI);
1412 if (
Offset.uge(AllocSize)) {
1413 AS.DeadOperands.push_back(U);
1420 void visitPHINode(PHINode &PN) { visitPHINodeOrSelectInst(PN); }
1422 void visitSelectInst(SelectInst &SI) { visitPHINodeOrSelectInst(SI); }
1425 void visitInstruction(Instruction &
I) { PI.setAborted(&
I); }
1427 void visitCallBase(CallBase &CB) {
1433 PI.setEscapedReadOnly(&CB);
1437 Base::visitCallBase(CB);
1441AllocaSlices::AllocaSlices(
const DataLayout &
DL, AllocaInst &AI)
1443#
if !defined(
NDEBUG) || defined(LLVM_ENABLE_DUMP)
1446 PointerEscapingInstr(nullptr), PointerEscapingInstrReadOnly(nullptr) {
1448 SliceBuilder::PtrInfo PtrI =
PB.visitPtr(AI);
1449 if (PtrI.isEscaped() || PtrI.isAborted()) {
1452 PointerEscapingInstr = PtrI.getEscapingInst() ? PtrI.getEscapingInst()
1453 : PtrI.getAbortingInst();
1454 assert(PointerEscapingInstr &&
"Did not track a bad instruction");
1457 PointerEscapingInstrReadOnly = PtrI.getEscapedReadOnlyInst();
1459 llvm::erase_if(Slices, [](
const Slice &S) {
return S.isDead(); });
1466#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1468void AllocaSlices::print(raw_ostream &OS, const_iterator
I,
1469 StringRef Indent)
const {
1470 printSlice(OS,
I, Indent);
1472 printUse(OS,
I, Indent);
1475void AllocaSlices::printSlice(raw_ostream &OS, const_iterator
I,
1476 StringRef Indent)
const {
1477 OS << Indent <<
"[" <<
I->beginOffset() <<
"," <<
I->endOffset() <<
")"
1478 <<
" slice #" << (
I -
begin())
1479 << (
I->isSplittable() ?
" (splittable)" :
"");
1482void AllocaSlices::printUse(raw_ostream &OS, const_iterator
I,
1483 StringRef Indent)
const {
1484 OS << Indent <<
" used by: " << *
I->getUse()->getUser() <<
"\n";
1487void AllocaSlices::print(raw_ostream &OS)
const {
1488 if (PointerEscapingInstr) {
1489 OS <<
"Can't analyze slices for alloca: " << AI <<
"\n"
1490 <<
" A pointer to this alloca escaped by:\n"
1491 <<
" " << *PointerEscapingInstr <<
"\n";
1495 if (PointerEscapingInstrReadOnly)
1496 OS <<
"Escapes into ReadOnly: " << *PointerEscapingInstrReadOnly <<
"\n";
1498 OS <<
"Slices of alloca: " << AI <<
"\n";
1519 for (
User *U :
I.users()) {
1520 Type *UserTy =
nullptr;
1526 UserTy =
Store->getValueOperand()->getType();
1528 if (!UserTy || (Ty && Ty != UserTy))
1538static std::pair<Type *, IntegerType *>
1542 bool TyIsCommon =
true;
1547 for (AllocaSlices::const_iterator
I =
B;
I !=
E; ++
I) {
1548 Use *U =
I->getUse();
1551 if (
I->beginOffset() !=
B->beginOffset() ||
I->endOffset() != EndOffset)
1554 Type *UserTy =
nullptr;
1558 UserTy =
SI->getValueOperand()->getType();
1569 if (UserITy->getBitWidth() % 8 != 0 ||
1570 UserITy->getBitWidth() / 8 > (EndOffset -
B->beginOffset()))
1575 if (!ITy || ITy->
getBitWidth() < UserITy->getBitWidth())
1581 if (!UserTy || (Ty && Ty != UserTy))
1587 return {TyIsCommon ? Ty :
nullptr, ITy};
1617 Type *LoadType =
nullptr;
1630 if (LoadType != LI->
getType())
1639 if (BBI->mayWriteToMemory())
1642 MaxAlign = std::max(MaxAlign, LI->
getAlign());
1649 APInt(APWidth,
DL.getTypeStoreSize(LoadType).getFixedValue());
1692 if (!
SI ||
SI->getPointerOperand() != &PN)
1695 if (
SI->isVolatile())
1703 Value *StoredValue =
SI->getValueOperand();
1742 IRB.SetInsertPoint(&PN);
1744 PN.
getName() +
".sroa.speculated");
1774 IRB.SetInsertPoint(TI);
1777 LoadTy, InVal, Alignment,
1778 (PN.
getName() +
".sroa.speculate.load." +
Pred->getName()));
1779 ++NumLoadsSpeculated;
1781 Load->setAAMetadata(AATags);
1795 <<
" " <<
SI <<
"\n");
1813 bool CFGChanged =
false;
1815 for (
auto [
Pred, InVal] : IncomingValues) {
1817 if (
Pred->getTerminator()->getNumSuccessors() != 1) {
1819 assert(StoreBB &&
"store edge was not checked for splitting");
1826 ++NumStoresPredicated;
1830 SI.eraseFromParent();
1835SelectHandSpeculativity &
1836SelectHandSpeculativity::setAsSpeculatable(
bool isTrueVal) {
1844bool SelectHandSpeculativity::isSpeculatable(
bool isTrueVal)
const {
1849bool SelectHandSpeculativity::areAllSpeculatable()
const {
1850 return isSpeculatable(
true) &&
1851 isSpeculatable(
false);
1854bool SelectHandSpeculativity::areAnySpeculatable()
const {
1855 return isSpeculatable(
true) ||
1856 isSpeculatable(
false);
1858bool SelectHandSpeculativity::areNoneSpeculatable()
const {
1859 return !areAnySpeculatable();
1862static SelectHandSpeculativity
1865 SelectHandSpeculativity
Spec;
1871 Spec.setAsSpeculatable(
Value ==
SI.getTrueValue());
1872 else if (PreserveCFG)
1878std::optional<RewriteableMemOps>
1879SROA::isSafeSelectToSpeculateOrPredicate(SelectInst &SI,
bool PreserveCFG) {
1880 RewriteableMemOps
Ops;
1883 for (User *U :
SI.users()) {
1890 for (User *U :
Users) {
1893 if (
Store->isVolatile() || PreserveCFG)
1904 PossiblySpeculatableLoad
Load(LI);
1919 SelectHandSpeculativity Spec =
1921 if (PreserveCFG && !Spec.areAllSpeculatable())
1935 Value *TV =
SI.getTrueValue();
1936 Value *FV =
SI.getFalseValue();
1941 IRB.SetInsertPoint(&LI);
1945 LI.
getName() +
".sroa.speculate.cast.true");
1947 LI.
getName() +
".sroa.speculate.cast.false");
1951 LI.
getName() +
".sroa.speculate.load.true");
1954 LI.
getName() +
".sroa.speculate.load.false");
1955 NumLoadsSpeculated += 2;
1967 Value *
V = IRB.CreateSelect(
SI.getCondition(), TL, FL,
1968 LI.
getName() +
".sroa.speculated", &
SI);
1974template <
typename T>
1976 SelectHandSpeculativity
Spec, IRBuilderTy &IRB,
1983 if (
Spec.areNoneSpeculatable())
1985 SI.getMetadata(LLVMContext::MD_prof), &DTU);
1988 SI.getMetadata(LLVMContext::MD_prof), &DTU,
1990 if (
Spec.isSpeculatable(
true))
1996 Tail->setName(Head->
getName() +
".cont");
2001 bool IsThen = SuccBB == HeadBI->getSuccessor(0);
2002 int SuccIdx = IsThen ? 0 : 1;
2003 auto *NewMemOpBB = SuccBB == Tail ? Head : SuccBB;
2004 auto &CondMemOp =
cast<T>(*
I.clone());
2005 if (NewMemOpBB != Head) {
2006 NewMemOpBB->setName(Head->
getName() + (IsThen ?
".then" :
".else"));
2008 ++NumLoadsPredicated;
2010 ++NumStoresPredicated;
2012 CondMemOp.dropUBImplyingAttrsAndMetadata();
2013 ++NumLoadsSpeculated;
2015 CondMemOp.insertBefore(NewMemOpBB->getTerminator()->getIterator());
2016 Value *Ptr =
SI.getOperand(1 + SuccIdx);
2019 IRB.SetInsertPoint(&CondMemOp);
2020 Ptr = IRB.CreateAddrSpaceCast(Ptr,
I.getPointerOperandType(),
2021 I.getName() + (IsThen ?
".then" :
".else") +
2023 CondMemOp.setOperand(
I.getPointerOperandIndex(), Ptr);
2025 CondMemOp.setName(
I.getName() + (IsThen ?
".then" :
".else") +
".val");
2033 I.replaceAllUsesWith(PN);
2038 SelectHandSpeculativity
Spec, IRBuilderTy &IRB,
2049 const RewriteableMemOps &
Ops,
2051 bool CFGChanged =
false;
2054 for (
const RewriteableMemOp &
Op :
Ops) {
2055 SelectHandSpeculativity
Spec;
2057 if (
auto *
const *US = std::get_if<UnspeculatableStore>(&
Op)) {
2060 auto PSL = std::get<PossiblySpeculatableLoad>(
Op);
2061 I = PSL.getPointer();
2062 Spec = PSL.getInt();
2064 if (
Spec.areAllSpeculatable()) {
2067 assert(DTU &&
"Should not get here when not allowed to modify the CFG!");
2071 I->eraseFromParent();
2076 SI.eraseFromParent();
2084 const Twine &NamePrefix) {
2086 Ptr = IRB.CreateInBoundsPtrAdd(Ptr, IRB.getInt(
Offset),
2087 NamePrefix +
"sroa_idx");
2088 return IRB.CreatePointerBitCastOrAddrSpaceCast(Ptr,
PointerTy,
2089 NamePrefix +
"sroa_cast");
2104 unsigned VScale = 0) {
2114 "We can't have the same bitwidth for different int types");
2118 TypeSize NewSize =
DL.getTypeSizeInBits(NewTy);
2119 TypeSize OldSize =
DL.getTypeSizeInBits(OldTy);
2146 if (NewSize != OldSize)
2162 return OldAS == NewAS ||
2163 (!
DL.isNonIntegralAddressSpace(OldAS) &&
2164 !
DL.isNonIntegralAddressSpace(NewAS) &&
2165 DL.getPointerSize(OldAS) ==
DL.getPointerSize(NewAS));
2171 return !
DL.isNonIntegralPointerType(NewTy);
2175 if (!
DL.isNonIntegralPointerType(OldTy))
2198 std::max(S.beginOffset(),
P.beginOffset()) -
P.beginOffset();
2199 uint64_t BeginIndex = BeginOffset / ElementSize;
2200 if (BeginIndex * ElementSize != BeginOffset ||
2203 uint64_t EndOffset = std::min(S.endOffset(),
P.endOffset()) -
P.beginOffset();
2204 uint64_t EndIndex = EndOffset / ElementSize;
2205 if (EndIndex * ElementSize != EndOffset ||
2209 assert(EndIndex > BeginIndex &&
"Empty vector!");
2210 uint64_t NumElements = EndIndex - BeginIndex;
2211 Type *SliceTy = (NumElements == 1)
2212 ? Ty->getElementType()
2218 Use *U = S.getUse();
2221 if (
MI->isVolatile())
2223 if (!S.isSplittable())
2231 if (!
II->isLifetimeStartOrEnd() && !
II->isDroppable())
2238 if (LTy->isStructTy())
2240 if (
P.beginOffset() > S.beginOffset() ||
P.endOffset() < S.endOffset()) {
2241 assert(LTy->isIntegerTy());
2247 if (
SI->isVolatile())
2249 Type *STy =
SI->getValueOperand()->getType();
2253 if (
P.beginOffset() > S.beginOffset() ||
P.endOffset() < S.endOffset()) {
2273 bool HaveCommonEltTy,
Type *CommonEltTy,
2274 bool HaveVecPtrTy,
bool HaveCommonVecPtrTy,
2275 VectorType *CommonVecPtrTy,
unsigned VScale) {
2277 if (CandidateTys.
empty())
2284 if (HaveVecPtrTy && !HaveCommonVecPtrTy)
2288 if (!HaveCommonEltTy && HaveVecPtrTy) {
2290 CandidateTys.
clear();
2292 }
else if (!HaveCommonEltTy && !HaveVecPtrTy) {
2295 if (!VTy->getElementType()->isIntegerTy())
2297 VTy->getContext(), VTy->getScalarSizeInBits())));
2304 assert(
DL.getTypeSizeInBits(RHSTy).getFixedValue() ==
2305 DL.getTypeSizeInBits(LHSTy).getFixedValue() &&
2306 "Cannot have vector types of different sizes!");
2307 assert(RHSTy->getElementType()->isIntegerTy() &&
2308 "All non-integer types eliminated!");
2309 assert(LHSTy->getElementType()->isIntegerTy() &&
2310 "All non-integer types eliminated!");
2316 assert(
DL.getTypeSizeInBits(RHSTy).getFixedValue() ==
2317 DL.getTypeSizeInBits(LHSTy).getFixedValue() &&
2318 "Cannot have vector types of different sizes!");
2319 assert(RHSTy->getElementType()->isIntegerTy() &&
2320 "All non-integer types eliminated!");
2321 assert(LHSTy->getElementType()->isIntegerTy() &&
2322 "All non-integer types eliminated!");
2326 llvm::sort(CandidateTys, RankVectorTypesComp);
2327 CandidateTys.erase(
llvm::unique(CandidateTys, RankVectorTypesEq),
2328 CandidateTys.end());
2334 assert(VTy->getElementType() == CommonEltTy &&
2335 "Unaccounted for element type!");
2336 assert(VTy == CandidateTys[0] &&
2337 "Different vector types with the same element type!");
2340 CandidateTys.resize(1);
2347 std::numeric_limits<unsigned short>::max();
2353 DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
2357 if (ElementSize % 8)
2359 assert((
DL.getTypeSizeInBits(VTy).getFixedValue() % 8) == 0 &&
2360 "vector size not a multiple of element size?");
2363 for (
const Slice &S :
P)
2367 for (
const Slice *S :
P.splitSliceTails())
2373 return VTy != CandidateTys.
end() ? *VTy :
nullptr;
2380 bool &HaveCommonEltTy,
Type *&CommonEltTy,
bool &HaveVecPtrTy,
2381 bool &HaveCommonVecPtrTy,
VectorType *&CommonVecPtrTy,
unsigned VScale) {
2383 CandidateTysCopy.
size() ? CandidateTysCopy[0] :
nullptr;
2386 for (
Type *Ty : OtherTys) {
2389 unsigned TypeSize =
DL.getTypeSizeInBits(Ty).getFixedValue();
2392 for (
VectorType *
const VTy : CandidateTysCopy) {
2394 assert(CandidateTysCopy[0] == OriginalElt &&
"Different Element");
2395 unsigned VectorSize =
DL.getTypeSizeInBits(VTy).getFixedValue();
2396 unsigned ElementSize =
2397 DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
2401 CheckCandidateType(NewVTy);
2407 P,
DL, CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
2408 HaveCommonVecPtrTy, CommonVecPtrTy, VScale);
2427 Type *CommonEltTy =
nullptr;
2429 bool HaveVecPtrTy =
false;
2430 bool HaveCommonEltTy =
true;
2431 bool HaveCommonVecPtrTy =
true;
2432 auto CheckCandidateType = [&](
Type *Ty) {
2435 if (!CandidateTys.
empty()) {
2437 if (
DL.getTypeSizeInBits(VTy).getFixedValue() !=
2438 DL.getTypeSizeInBits(
V).getFixedValue()) {
2439 CandidateTys.
clear();
2444 Type *EltTy = VTy->getElementType();
2447 CommonEltTy = EltTy;
2448 else if (CommonEltTy != EltTy)
2449 HaveCommonEltTy =
false;
2452 HaveVecPtrTy =
true;
2453 if (!CommonVecPtrTy)
2454 CommonVecPtrTy = VTy;
2455 else if (CommonVecPtrTy != VTy)
2456 HaveCommonVecPtrTy =
false;
2462 for (
const Slice &S :
P) {
2467 Ty =
SI->getValueOperand()->getType();
2471 auto CandTy = Ty->getScalarType();
2472 if (CandTy->isPointerTy() && (S.beginOffset() !=
P.beginOffset() ||
2473 S.endOffset() !=
P.endOffset())) {
2480 if (S.beginOffset() ==
P.beginOffset() && S.endOffset() ==
P.endOffset())
2481 CheckCandidateType(Ty);
2486 LoadStoreTys, CandidateTysCopy, CheckCandidateType,
P,
DL,
2487 CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
2488 HaveCommonVecPtrTy, CommonVecPtrTy, VScale))
2491 CandidateTys.
clear();
2493 DeferredTys, CandidateTysCopy, CheckCandidateType,
P,
DL, CandidateTys,
2494 HaveCommonEltTy, CommonEltTy, HaveVecPtrTy, HaveCommonVecPtrTy,
2495 CommonVecPtrTy, VScale);
2506 bool &WholeAllocaOp) {
2509 uint64_t RelBegin = S.beginOffset() - AllocBeginOffset;
2510 uint64_t RelEnd = S.endOffset() - AllocBeginOffset;
2512 Use *U = S.getUse();
2519 if (
II->isLifetimeStartOrEnd() ||
II->isDroppable())
2537 if (S.beginOffset() < AllocBeginOffset)
2543 WholeAllocaOp =
true;
2545 if (ITy->getBitWidth() <
DL.getTypeStoreSizeInBits(ITy).getFixedValue())
2547 }
else if (RelBegin != 0 || RelEnd !=
Size ||
2554 Type *ValueTy =
SI->getValueOperand()->getType();
2555 if (
SI->isVolatile())
2558 TypeSize StoreSize =
DL.getTypeStoreSize(ValueTy);
2563 if (S.beginOffset() < AllocBeginOffset)
2569 WholeAllocaOp =
true;
2571 if (ITy->getBitWidth() <
DL.getTypeStoreSizeInBits(ITy).getFixedValue())
2573 }
else if (RelBegin != 0 || RelEnd !=
Size ||
2582 if (!S.isSplittable())
2599 uint64_t SizeInBits =
DL.getTypeSizeInBits(AllocaTy).getFixedValue();
2605 if (SizeInBits !=
DL.getTypeStoreSizeInBits(AllocaTy).getFixedValue())
2623 bool WholeAllocaOp =
P.empty() &&
DL.isLegalInteger(SizeInBits);
2625 for (
const Slice &S :
P)
2630 for (
const Slice *S :
P.splitSliceTails())
2635 return WholeAllocaOp;
2640 const Twine &Name) {
2644 DL.getTypeStoreSize(IntTy).getFixedValue() &&
2645 "Element extends past full value");
2647 if (
DL.isBigEndian())
2648 ShAmt = 8 * (
DL.getTypeStoreSize(IntTy).getFixedValue() -
2649 DL.getTypeStoreSize(Ty).getFixedValue() -
Offset);
2651 V = IRB.CreateLShr(
V, ShAmt, Name +
".shift");
2654 assert(Ty->getBitWidth() <= IntTy->getBitWidth() &&
2655 "Cannot extract to a larger integer!");
2657 V = IRB.CreateTrunc(
V, Ty, Name +
".trunc");
2667 assert(Ty->getBitWidth() <= IntTy->getBitWidth() &&
2668 "Cannot insert a larger integer!");
2671 V = IRB.CreateZExt(
V, IntTy, Name +
".ext");
2675 DL.getTypeStoreSize(IntTy).getFixedValue() &&
2676 "Element store outside of alloca store");
2678 if (
DL.isBigEndian())
2679 ShAmt = 8 * (
DL.getTypeStoreSize(IntTy).getFixedValue() -
2680 DL.getTypeStoreSize(Ty).getFixedValue() -
Offset);
2682 V = IRB.CreateShl(
V, ShAmt, Name +
".shift");
2686 if (ShAmt || Ty->getBitWidth() < IntTy->getBitWidth()) {
2687 APInt Mask = ~Ty->getMask().zext(IntTy->getBitWidth()).shl(ShAmt);
2688 Old = IRB.CreateAnd(Old, Mask, Name +
".mask");
2690 V = IRB.CreateOr(Old,
V, Name +
".insert");
2697 unsigned EndIndex,
const Twine &Name) {
2699 unsigned NumElements = EndIndex - BeginIndex;
2700 assert(NumElements <= VecTy->getNumElements() &&
"Too many elements!");
2702 if (NumElements == VecTy->getNumElements())
2705 if (NumElements == 1) {
2706 V = IRB.CreateExtractElement(
V, BeginIndex, Name +
".extract");
2712 V = IRB.CreateShuffleVector(
V, Mask, Name +
".extract");
2718 unsigned BeginIndex,
const Twine &Name) {
2720 assert(VecTy &&
"Can only insert a vector into a vector");
2725 V = IRB.CreateInsertElement(Old,
V, BeginIndex, Name +
".insert");
2733 assert(NumSubElements <= NumElements &&
"Too many elements!");
2734 if (NumSubElements == NumElements) {
2735 assert(
V->getType() == VecTy &&
"Vector type mismatch");
2738 unsigned EndIndex = BeginIndex + NumSubElements;
2745 Mask.reserve(NumElements);
2746 for (
unsigned Idx = 0; Idx != NumElements; ++Idx)
2747 if (Idx >= BeginIndex && Idx < EndIndex)
2748 Mask.push_back(Idx - BeginIndex);
2751 V = IRB.CreateShuffleVector(
V, Mask, Name +
".expand");
2755 for (
unsigned Idx = 0; Idx != NumElements; ++Idx)
2756 if (Idx >= BeginIndex && Idx < EndIndex)
2757 Mask.push_back(Idx);
2759 Mask.push_back(Idx + NumElements);
2760 V = IRB.CreateShuffleVector(
V, Old, Mask, Name +
"blend");
2799 const char *DebugName) {
2800 Type *EltType = VecType->getElementType();
2801 if (EltType != NewAIEltTy) {
2803 unsigned TotalBits =
2804 VecType->getNumElements() *
DL.getTypeSizeInBits(EltType);
2805 unsigned NewNumElts = TotalBits /
DL.getTypeSizeInBits(NewAIEltTy);
2808 V = Builder.CreateBitCast(
V, NewVecType);
2809 VecType = NewVecType;
2814 BitcastIfNeeded(V0, VecType0,
"V0");
2815 BitcastIfNeeded(
V1, VecType1,
"V1");
2817 unsigned NumElts0 = VecType0->getNumElements();
2818 unsigned NumElts1 = VecType1->getNumElements();
2822 if (NumElts0 == NumElts1) {
2823 for (
unsigned i = 0; i < NumElts0 + NumElts1; ++i)
2824 ShuffleMask.push_back(i);
2828 unsigned SmallSize = std::min(NumElts0, NumElts1);
2829 unsigned LargeSize = std::max(NumElts0, NumElts1);
2830 bool IsV0Smaller = NumElts0 < NumElts1;
2831 Value *&ExtendedVec = IsV0Smaller ? V0 :
V1;
2833 for (
unsigned i = 0; i < SmallSize; ++i)
2835 for (
unsigned i = SmallSize; i < LargeSize; ++i)
2837 ExtendedVec = Builder.CreateShuffleVector(
2839 LLVM_DEBUG(
dbgs() <<
" shufflevector: " << *ExtendedVec <<
"\n");
2840 for (
unsigned i = 0; i < NumElts0; ++i)
2841 ShuffleMask.push_back(i);
2842 for (
unsigned i = 0; i < NumElts1; ++i)
2843 ShuffleMask.push_back(LargeSize + i);
2846 return Builder.CreateShuffleVector(V0,
V1, ShuffleMask);
2857class AllocaSliceRewriter :
public InstVisitor<AllocaSliceRewriter, bool> {
2859 friend class InstVisitor<AllocaSliceRewriter, bool>;
2861 using Base = InstVisitor<AllocaSliceRewriter, bool>;
2863 const DataLayout &
DL;
2866 AllocaInst &OldAI, &NewAI;
2867 const uint64_t NewAllocaBeginOffset, NewAllocaEndOffset;
2896 uint64_t NewBeginOffset = 0, NewEndOffset = 0;
2899 bool IsSplittable =
false;
2900 bool IsSplit =
false;
2901 Use *OldUse =
nullptr;
2905 SmallSetVector<PHINode *, 8> &PHIUsers;
2906 SmallSetVector<SelectInst *, 8> &SelectUsers;
2914 Value *getPtrToNewAI(
unsigned AddrSpace,
bool IsVolatile) {
2918 Type *AccessTy = IRB.getPtrTy(AddrSpace);
2919 return IRB.CreateAddrSpaceCast(&NewAI, AccessTy);
2923 AllocaSliceRewriter(
const DataLayout &
DL, AllocaSlices &AS, SROA &
Pass,
2924 AllocaInst &OldAI, AllocaInst &NewAI,
Type *NewAllocaTy,
2926 uint64_t NewAllocaEndOffset,
bool IsIntegerPromotable,
2927 VectorType *PromotableVecTy,
2928 SmallSetVector<PHINode *, 8> &PHIUsers,
2929 SmallSetVector<SelectInst *, 8> &SelectUsers)
2930 :
DL(
DL), AS(AS),
Pass(
Pass), OldAI(OldAI), NewAI(NewAI),
2931 NewAllocaBeginOffset(NewAllocaBeginOffset),
2932 NewAllocaEndOffset(NewAllocaEndOffset), NewAllocaTy(NewAllocaTy),
2933 IntTy(IsIntegerPromotable
2936 DL.getTypeSizeInBits(NewAllocaTy).getFixedValue())
2938 VecTy(PromotableVecTy),
2939 ElementTy(VecTy ? VecTy->getElementType() : nullptr),
2940 ElementSize(VecTy ?
DL.getTypeSizeInBits(ElementTy).getFixedValue() / 8
2942 PHIUsers(PHIUsers), SelectUsers(SelectUsers),
2943 IRB(*NewAI.getModule(), ConstantFolder()) {
2945 assert((
DL.getTypeSizeInBits(ElementTy).getFixedValue() % 8) == 0 &&
2946 "Only multiple-of-8 sized vector elements are viable");
2949 assert((!IntTy && !VecTy) || (IntTy && !VecTy) || (!IntTy && VecTy));
2952 bool visit(AllocaSlices::const_iterator
I) {
2953 bool CanSROA =
true;
2954 BeginOffset =
I->beginOffset();
2955 EndOffset =
I->endOffset();
2956 IsSplittable =
I->isSplittable();
2958 BeginOffset < NewAllocaBeginOffset || EndOffset > NewAllocaEndOffset;
2959 LLVM_DEBUG(
dbgs() <<
" rewriting " << (IsSplit ?
"split " :
""));
2964 assert(BeginOffset < NewAllocaEndOffset);
2965 assert(EndOffset > NewAllocaBeginOffset);
2966 NewBeginOffset = std::max(BeginOffset, NewAllocaBeginOffset);
2967 NewEndOffset = std::min(EndOffset, NewAllocaEndOffset);
2969 SliceSize = NewEndOffset - NewBeginOffset;
2970 LLVM_DEBUG(
dbgs() <<
" Begin:(" << BeginOffset <<
", " << EndOffset
2971 <<
") NewBegin:(" << NewBeginOffset <<
", "
2972 << NewEndOffset <<
") NewAllocaBegin:("
2973 << NewAllocaBeginOffset <<
", " << NewAllocaEndOffset
2975 assert(IsSplit || NewBeginOffset == BeginOffset);
2976 OldUse =
I->getUse();
2980 IRB.SetInsertPoint(OldUserI);
2981 IRB.SetCurrentDebugLocation(OldUserI->
getDebugLoc());
2983 if (!IRB.getContext().shouldDiscardValueNames())
2984 IRB.getInserter().SetNamePrefix(Twine(NewAI.
getName()) +
"." +
2985 Twine(BeginOffset) +
".");
3047 std::optional<SmallVector<Value *, 4>>
3048 rewriteTreeStructuredMerge(Partition &
P) {
3050 if (
P.splitSliceTails().size() > 0)
3051 return std::nullopt;
3060 :
Store(
SI), BeginOffset(Begin), EndOffset(
End), StoredValue(Val) {}
3070 LoadInst *FullLoad =
nullptr;
3071 StoreInst *InitStore =
nullptr;
3075 Type *AllocatedEltTy =
3079 unsigned AllocatedEltTySize =
DL.getTypeSizeInBits(AllocatedEltTy);
3086 auto IsTypeValidForTreeStructuredMerge = [&](
Type *Ty) ->
bool {
3088 return FixedVecTy &&
3089 DL.getTypeSizeInBits(FixedVecTy->getElementType()) % 8 == 0 &&
3090 !FixedVecTy->getElementType()->isPointerTy();
3093 for (Slice &S :
P) {
3097 bool IsFullWidth = (S.beginOffset() == NewAllocaBeginOffset &&
3098 S.endOffset() == NewAllocaEndOffset);
3102 !IsTypeValidForTreeStructuredMerge(LI->
getType()))
3103 return std::nullopt;
3108 return std::nullopt;
3112 LoadInfos.
push_back({LI, S.beginOffset(), S.endOffset()});
3124 if (!
SI->isSimple() || !IsTypeValidForTreeStructuredMerge(
3125 SI->getValueOperand()->getType()))
3126 return std::nullopt;
3128 unsigned NumElts = StVecTy->getNumElements();
3129 unsigned EltSize =
DL.getTypeSizeInBits(StVecTy->getElementType());
3130 if (NumElts * EltSize % AllocatedEltTySize != 0)
3131 return std::nullopt;
3136 return std::nullopt;
3139 StoreInfos.
emplace_back(SI, S.beginOffset(), S.endOffset(),
3140 SI->getValueOperand());
3145 return std::nullopt;
3152 if (StoreInfos.
size() < 2)
3153 return std::nullopt;
3161 bool IsRMWPattern = InitStore && VecTy && !LoadInfos.
empty();
3162 bool IsStoresOnlyPattern = !InitStore && FullLoad && LoadInfos.
empty();
3163 if (!IsRMWPattern && !IsStoresOnlyPattern)
3164 return std::nullopt;
3168 BasicBlock *StoreBB = StoreInfos[0].Store->getParent();
3169 for (
auto &Info : StoreInfos)
3170 if (
Info.Store->getParent() != StoreBB)
3171 return std::nullopt;
3173 SmallVector<Value *, 4> DeletedValues;
3180 auto TreeMerge = [&](SmallVectorImpl<Value *> &Vals,
3183 while (Vals.
size() > 1) {
3184 SmallVector<Value *, 8>
Next;
3185 for (
unsigned I = 0,
E = Vals.
size();
I + 1 <
E;
I += 2) {
3191 if (Vals.
size() % 2 == 1)
3193 Vals = std::move(
Next);
3202 auto ReplaceFullLoad = [&](LoadInst *LoadToReplace,
Value *Merged) {
3204 Value *NewLoad = LoadBuilder.CreateAlignedLoad(
3205 Merged->getType(), &NewAI, getSliceAlign(),
3207 LoadToReplace->
getName() +
".sroa.new.load");
3209 NewLoad = LoadBuilder.CreateBitCast(NewLoad, LoadToReplace->
getType());
3214 if (IsStoresOnlyPattern) {
3217 llvm::sort(StoreInfos, [](
const StoreInfo &
A,
const StoreInfo &
B) {
3218 return A.BeginOffset <
B.BeginOffset;
3223 uint64_t Expected = NewAllocaBeginOffset;
3224 for (
auto &Info : StoreInfos) {
3225 if (
Info.BeginOffset != Expected)
3226 return std::nullopt;
3227 Expected =
Info.EndOffset;
3230 if (Expected != NewAllocaEndOffset)
3231 return std::nullopt;
3241 if (LoadBB == StoreBB) {
3242 for (
auto &Info : StoreInfos)
3243 if (!
Info.Store->comesBefore(FullLoad))
3244 return std::nullopt;
3248 dbgs() <<
"Tree structured merge rewrite (stores-only):\n";
3249 dbgs() <<
" Load: " << *FullLoad <<
"\n Ordered stores:\n";
3250 for (
auto [
I, Info] :
enumerate(StoreInfos)) {
3251 dbgs() <<
" [" <<
I <<
"] Range[" <<
Info.BeginOffset <<
", "
3252 <<
Info.EndOffset <<
") \tStore: " << *
Info.Store
3253 <<
"\tValue: " << *
Info.StoredValue <<
"\n";
3266 SmallVector<Value *, 8> Vals;
3267 for (
const auto &Info : StoreInfos) {
3272 Value *Merged = TreeMerge(Vals, Builder);
3273 Builder.CreateAlignedStore(Merged, &NewAI, getSliceAlign());
3276 ReplaceFullLoad(FullLoad, Merged);
3277 return DeletedValues;
3285 return std::nullopt;
3286 if (
any_of(LoadInfos, [&](
const LoadInfo &
I) {
3287 return I.Load->getParent() != StoreBB;
3289 return std::nullopt;
3305 Accesses.reserve(LoadInfos.
size() + StoreInfos.size());
3306 for (
const auto &L : LoadInfos)
3307 Accesses.push_back({
L.Load,
L.BeginOffset,
L.EndOffset,
false});
3308 for (
const auto &S : StoreInfos)
3309 Accesses.push_back({S.Store, S.BeginOffset, S.EndOffset,
true});
3311 return A.Inst->comesBefore(
B.Inst);
3319 return std::nullopt;
3325 if (FullLoad && FullLoad->
getParent() == StoreBB &&
3326 !
Accesses.back().Inst->comesBefore(FullLoad))
3327 return std::nullopt;
3338 using SliceRange = std::pair<uint64_t, uint64_t>;
3342 SortedRanges.
emplace_back(Acc.BeginOffset, Acc.EndOffset);
3346 uint64_t Expected = NewAllocaBeginOffset;
3347 for (
auto &
Range : SortedRanges) {
3348 if (
Range.first != Expected)
3349 return std::nullopt;
3350 Expected =
Range.second;
3352 if (Expected != NewAllocaEndOffset)
3353 return std::nullopt;
3356 dbgs() <<
"Tree structured merge rewrite (RMW):\n";
3357 dbgs() <<
" Init store: " << *InitStore <<
"\n";
3359 dbgs() <<
" Final load: " << *FullLoad <<
"\n";
3360 dbgs() <<
" Slice ranges (" << SortedRanges.size() <<
"):\n";
3361 for (
auto &
Range : SortedRanges)
3372 if (InitVec->
getType() != NewAllocaTy)
3373 InitVec = IRB.CreateBitCast(InitVec, NewAllocaTy,
"init.cast");
3374 DenseMap<SliceRange, Value *> SliceValues;
3375 for (
auto &
Range : SortedRanges) {
3376 unsigned BeginIdx = getIndex(
Range.first);
3377 unsigned EndIdx = getIndex(
Range.second);
3378 SliceValues[
Range] = IRB.CreateShuffleVector(
3394 SliceRange
Range{Acc.BeginOffset, Acc.EndOffset};
3397 if (
V->getType() != Acc.Inst->getType()) {
3399 V = IRB.CreateBitCast(
V, Acc.Inst->getType());
3401 Acc.Inst->replaceAllUsesWith(
V);
3418 SmallVector<Value *, 8> Vals;
3419 for (
auto &
Range : SortedRanges)
3421 Value *Merged = TreeMerge(Vals, Builder);
3422 Builder.CreateAlignedStore(Merged, &NewAI, getSliceAlign());
3427 ReplaceFullLoad(FullLoad, Merged);
3429 return DeletedValues;
3437 bool visitInstruction(Instruction &
I) {
3445 assert(IsSplit || BeginOffset == NewBeginOffset);
3448 StringRef OldName = OldPtr->
getName();
3450 size_t LastSROAPrefix = OldName.
rfind(
".sroa.");
3452 OldName = OldName.
substr(LastSROAPrefix + strlen(
".sroa."));
3457 OldName = OldName.
substr(IndexEnd + 1);
3461 OldName = OldName.
substr(OffsetEnd + 1);
3465 OldName = OldName.
substr(0, OldName.
find(
".sroa_"));
3470 Twine(OldName) +
".");
3478 Align getSliceAlign() {
3480 NewBeginOffset - NewAllocaBeginOffset);
3484 assert(VecTy &&
"Can only call getIndex when rewriting a vector");
3486 assert(RelOffset / ElementSize < UINT32_MAX &&
"Index out of bounds");
3487 uint32_t
Index = RelOffset / ElementSize;
3488 assert(Index * ElementSize == RelOffset);
3492 void deleteIfTriviallyDead(
Value *
V) {
3495 Pass.DeadInsts.push_back(
I);
3498 Value *rewriteVectorizedLoadInst(LoadInst &LI) {
3499 unsigned BeginIndex = getIndex(NewBeginOffset);
3500 unsigned EndIndex = getIndex(NewEndOffset);
3501 assert(EndIndex > BeginIndex &&
"Empty vector!");
3504 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3506 Load->copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
3507 LLVMContext::MD_access_group});
3511 Value *rewriteIntegerLoad(LoadInst &LI) {
3512 assert(IntTy &&
"We cannot insert an integer to the alloca");
3515 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3516 V = IRB.CreateBitPreservingCastChain(
DL,
V, IntTy);
3517 assert(NewBeginOffset >= NewAllocaBeginOffset &&
"Out of bounds offset");
3519 if (
Offset > 0 || NewEndOffset < NewAllocaEndOffset) {
3520 IntegerType *ExtractTy = Type::getIntNTy(LI.
getContext(), SliceSize * 8);
3529 "Can only handle an extract for an overly wide load");
3535 bool visitLoadInst(LoadInst &LI) {
3544 Type *TargetTy = IsSplit ? Type::getIntNTy(LI.
getContext(), SliceSize * 8)
3546 bool IsPtrAdjusted =
false;
3549 V = rewriteVectorizedLoadInst(LI);
3551 V = rewriteIntegerLoad(LI);
3552 }
else if (NewBeginOffset == NewAllocaBeginOffset &&
3553 NewEndOffset == NewAllocaEndOffset &&
3556 DL.getTypeStoreSize(TargetTy).getFixedValue() > SliceSize &&
3559 getPtrToNewAI(LI.getPointerAddressSpace(), LI.isVolatile());
3560 LoadInst *NewLI = IRB.CreateAlignedLoad(
3561 NewAllocaTy, NewPtr, NewAI.getAlign(), LI.isVolatile(), LI.getName());
3562 if (LI.isVolatile())
3563 NewLI->setAtomic(LI.getOrdering(), LI.getSyncScopeID());
3564 if (NewLI->isAtomic())
3565 NewLI->setAlignment(LI.getAlign());
3570 copyMetadataForLoad(*NewLI, LI);
3574 NewLI->setAAMetadata(AATags.adjustForAccess(
3575 NewBeginOffset - BeginOffset, NewLI->getType(), DL));
3583 if (auto *AITy = dyn_cast<IntegerType>(NewAllocaTy))
3584 if (auto *TITy = dyn_cast<IntegerType>(TargetTy))
3585 if (AITy->getBitWidth() < TITy->getBitWidth()) {
3586 V = IRB.CreateZExt(V, TITy,
"load.ext");
3587 if (DL.isBigEndian())
3588 V = IRB.CreateShl(V, TITy->getBitWidth() - AITy->getBitWidth(),
3592 Type *LTy = IRB.getPtrTy(AS);
3594 IRB.CreateAlignedLoad(TargetTy, getNewAllocaSlicePtr(IRB, LTy),
3599 NewBeginOffset - BeginOffset, NewLI->
getType(),
DL));
3603 NewLI->
copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
3604 LLVMContext::MD_access_group});
3607 IsPtrAdjusted =
true;
3609 V = IRB.CreateBitPreservingCastChain(
DL,
V, TargetTy);
3614 "Only integer type loads and stores are split");
3615 assert(SliceSize <
DL.getTypeStoreSize(LI.
getType()).getFixedValue() &&
3616 "Split load isn't smaller than original load");
3618 "Non-byte-multiple bit width");
3624 LIIt.setHeadBit(
true);
3625 IRB.SetInsertPoint(LIIt);
3630 Value *Placeholder =
3636 Placeholder->replaceAllUsesWith(&LI);
3637 Placeholder->deleteValue();
3642 Pass.DeadInsts.push_back(&LI);
3643 deleteIfTriviallyDead(OldOp);
3648 bool rewriteVectorizedStoreInst(
Value *
V, StoreInst &SI,
Value *OldOp,
3653 if (
V->getType() != VecTy) {
3654 unsigned BeginIndex = getIndex(NewBeginOffset);
3655 unsigned EndIndex = getIndex(NewEndOffset);
3656 assert(EndIndex > BeginIndex &&
"Empty vector!");
3657 unsigned NumElements = EndIndex - BeginIndex;
3659 "Too many elements!");
3660 Type *SliceTy = (NumElements == 1)
3662 : FixedVectorType::
get(ElementTy, NumElements);
3663 if (
V->getType() != SliceTy)
3664 V = IRB.CreateBitPreservingCastChain(
DL,
V, SliceTy);
3668 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3671 StoreInst *
Store = IRB.CreateAlignedStore(
V, &NewAI, NewAI.
getAlign());
3672 Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3673 LLVMContext::MD_access_group});
3677 Pass.DeadInsts.push_back(&SI);
3686 bool rewriteIntegerStore(
Value *
V, StoreInst &SI, AAMDNodes AATags) {
3687 assert(IntTy &&
"We cannot extract an integer from the alloca");
3689 if (
DL.getTypeSizeInBits(
V->getType()).getFixedValue() !=
3691 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3693 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3694 assert(BeginOffset >= NewAllocaBeginOffset &&
"Out of bounds offset");
3698 V = IRB.CreateBitPreservingCastChain(
DL,
V, NewAllocaTy);
3699 StoreInst *
Store = IRB.CreateAlignedStore(
V, &NewAI, NewAI.
getAlign());
3700 Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3701 LLVMContext::MD_access_group});
3708 Store->getValueOperand(),
DL);
3710 Pass.DeadInsts.push_back(&SI);
3715 bool visitStoreInst(StoreInst &SI) {
3717 Value *OldOp =
SI.getOperand(1);
3720 AAMDNodes AATags =
SI.getAAMetadata();
3725 if (
V->getType()->isPointerTy())
3727 Pass.PostPromotionWorklist.insert(AI);
3729 TypeSize StoreSize =
DL.getTypeStoreSize(
V->getType());
3732 assert(
V->getType()->isIntegerTy() &&
3733 "Only integer type loads and stores are split");
3734 assert(
DL.typeSizeEqualsStoreSize(
V->getType()) &&
3735 "Non-byte-multiple bit width");
3736 IntegerType *NarrowTy = Type::getIntNTy(
SI.getContext(), SliceSize * 8);
3742 return rewriteVectorizedStoreInst(
V, SI, OldOp, AATags);
3743 if (IntTy &&
V->getType()->isIntegerTy())
3744 return rewriteIntegerStore(
V, SI, AATags);
3747 if (NewBeginOffset == NewAllocaBeginOffset &&
3748 NewEndOffset == NewAllocaEndOffset &&
3750 V = IRB.CreateBitPreservingCastChain(
DL,
V, NewAllocaTy);
3752 getPtrToNewAI(
SI.getPointerAddressSpace(),
SI.isVolatile());
3755 IRB.CreateAlignedStore(
V, NewPtr, NewAI.
getAlign(),
SI.isVolatile());
3757 unsigned AS =
SI.getPointerAddressSpace();
3758 Value *NewPtr = getNewAllocaSlicePtr(IRB, IRB.getPtrTy(AS));
3760 IRB.CreateAlignedStore(
V, NewPtr, getSliceAlign(),
SI.isVolatile());
3762 NewSI->
copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3763 LLVMContext::MD_access_group});
3767 if (
SI.isVolatile())
3776 Pass.DeadInsts.push_back(&SI);
3777 deleteIfTriviallyDead(OldOp);
3795 assert(
Size > 0 &&
"Expected a positive number of bytes.");
3803 IRB.CreateZExt(
V, SplatIntTy,
"zext"),
3813 V = IRB.CreateVectorSplat(NumElements,
V,
"vsplat");
3818 bool visitMemSetInst(MemSetInst &
II) {
3822 AAMDNodes AATags =
II.getAAMetadata();
3828 assert(NewBeginOffset == BeginOffset);
3829 II.setDest(getNewAllocaSlicePtr(IRB, OldPtr->
getType()));
3830 II.setDestAlignment(getSliceAlign());
3835 "AT: Unexpected link to non-const GEP");
3836 deleteIfTriviallyDead(OldPtr);
3841 Pass.DeadInsts.push_back(&
II);
3845 const bool CanContinue = [&]() {
3848 if (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset)
3853 if (Len > std::numeric_limits<unsigned>::max())
3855 auto *Int8Ty = IntegerType::getInt8Ty(NewAI.
getContext());
3858 DL.isLegalInteger(
DL.getTypeSizeInBits(ScalarTy).getFixedValue());
3864 Type *SizeTy =
II.getLength()->getType();
3865 unsigned Sz = NewEndOffset - NewBeginOffset;
3868 getNewAllocaSlicePtr(IRB, OldPtr->
getType()),
II.getValue(),
Size,
3869 MaybeAlign(getSliceAlign()),
II.isVolatile()));
3875 New,
New->getRawDest(),
nullptr,
DL);
3890 assert(ElementTy == ScalarTy);
3892 unsigned BeginIndex = getIndex(NewBeginOffset);
3893 unsigned EndIndex = getIndex(NewEndOffset);
3894 assert(EndIndex > BeginIndex &&
"Empty vector!");
3895 unsigned NumElements = EndIndex - BeginIndex;
3897 "Too many elements!");
3900 II.getValue(),
DL.getTypeSizeInBits(ElementTy).getFixedValue() / 8);
3901 Splat = IRB.CreateBitPreservingCastChain(
DL,
Splat, ElementTy);
3902 if (NumElements > 1)
3905 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3914 V = getIntegerSplat(
II.getValue(),
Size);
3916 if (IntTy && (NewBeginOffset != NewAllocaBeginOffset ||
3917 NewEndOffset != NewAllocaEndOffset)) {
3918 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI,
3920 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3924 assert(
V->getType() == IntTy &&
3925 "Wrong type for an alloca wide integer!");
3927 V = IRB.CreateBitPreservingCastChain(
DL,
V, NewAllocaTy);
3930 assert(NewBeginOffset == NewAllocaBeginOffset);
3931 assert(NewEndOffset == NewAllocaEndOffset);
3933 V = getIntegerSplat(
II.getValue(),
3934 DL.getTypeSizeInBits(ScalarTy).getFixedValue() / 8);
3939 V = IRB.CreateBitPreservingCastChain(
DL,
V, NewAllocaTy);
3942 Value *NewPtr = getPtrToNewAI(
II.getDestAddressSpace(),
II.isVolatile());
3944 IRB.CreateAlignedStore(
V, NewPtr, NewAI.
getAlign(),
II.isVolatile());
3945 New->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
3946 LLVMContext::MD_access_group});
3952 New,
New->getPointerOperand(),
V,
DL);
3955 return !
II.isVolatile();
3958 bool visitMemTransferInst(MemTransferInst &
II) {
3964 AAMDNodes AATags =
II.getAAMetadata();
3966 bool IsDest = &
II.getRawDestUse() == OldUse;
3967 assert((IsDest &&
II.getRawDest() == OldPtr) ||
3968 (!IsDest &&
II.getRawSource() == OldPtr));
3970 Align SliceAlign = getSliceAlign();
3978 if (!IsSplittable) {
3979 Value *AdjustedPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
3984 DbgAssign->getAddress() ==
II.getDest())
3985 DbgAssign->replaceVariableLocationOp(
II.getDest(), AdjustedPtr);
3987 II.setDest(AdjustedPtr);
3988 II.setDestAlignment(SliceAlign);
3990 II.setSource(AdjustedPtr);
3991 II.setSourceAlignment(SliceAlign);
3995 deleteIfTriviallyDead(OldPtr);
4008 (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset ||
4009 SliceSize !=
DL.getTypeStoreSize(NewAllocaTy).getFixedValue() ||
4010 !
DL.typeSizeEqualsStoreSize(NewAllocaTy) ||
4016 if (EmitMemCpy && &OldAI == &NewAI) {
4018 assert(NewBeginOffset == BeginOffset);
4021 if (NewEndOffset != EndOffset)
4022 II.setLength(NewEndOffset - NewBeginOffset);
4026 Pass.DeadInsts.push_back(&
II);
4030 Value *OtherPtr = IsDest ?
II.getRawSource() :
II.getRawDest();
4031 if (AllocaInst *AI =
4033 assert(AI != &OldAI && AI != &NewAI &&
4034 "Splittable transfers cannot reach the same alloca on both ends.");
4035 Pass.Worklist.insert(AI);
4042 unsigned OffsetWidth =
DL.getIndexSizeInBits(OtherAS);
4043 APInt OtherOffset(OffsetWidth, NewBeginOffset - BeginOffset);
4045 (IsDest ?
II.getSourceAlign() :
II.getDestAlign()).valueOrOne();
4047 commonAlignment(OtherAlign, OtherOffset.zextOrTrunc(64).getZExtValue());
4055 Value *OurPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
4056 Type *SizeTy =
II.getLength()->getType();
4057 Constant *
Size = ConstantInt::get(SizeTy, NewEndOffset - NewBeginOffset);
4059 Value *DestPtr, *SrcPtr;
4060 MaybeAlign DestAlign, SrcAlign;
4064 DestAlign = SliceAlign;
4066 SrcAlign = OtherAlign;
4069 DestAlign = OtherAlign;
4071 SrcAlign = SliceAlign;
4073 CallInst *
New = IRB.CreateMemCpy(DestPtr, DestAlign, SrcPtr, SrcAlign,
4076 New->setAAMetadata(AATags.
shift(NewBeginOffset - BeginOffset));
4081 &
II, New, DestPtr,
nullptr,
DL);
4086 SliceSize * 8, &
II, New, DestPtr,
nullptr,
DL);
4092 bool IsWholeAlloca = NewBeginOffset == NewAllocaBeginOffset &&
4093 NewEndOffset == NewAllocaEndOffset;
4095 unsigned BeginIndex = VecTy ? getIndex(NewBeginOffset) : 0;
4096 unsigned EndIndex = VecTy ? getIndex(NewEndOffset) : 0;
4097 unsigned NumElements = EndIndex - BeginIndex;
4098 IntegerType *SubIntTy =
4099 IntTy ? Type::getIntNTy(IntTy->
getContext(),
Size * 8) : nullptr;
4104 if (VecTy && !IsWholeAlloca) {
4105 if (NumElements == 1)
4106 OtherTy = VecTy->getElementType();
4109 }
else if (IntTy && !IsWholeAlloca) {
4112 OtherTy = NewAllocaTy;
4117 MaybeAlign SrcAlign = OtherAlign;
4118 MaybeAlign DstAlign = SliceAlign;
4126 DstPtr = getPtrToNewAI(
II.getDestAddressSpace(),
II.isVolatile());
4130 SrcPtr = getPtrToNewAI(
II.getSourceAddressSpace(),
II.isVolatile());
4134 if (VecTy && !IsWholeAlloca && !IsDest) {
4136 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
4138 }
else if (IntTy && !IsWholeAlloca && !IsDest) {
4140 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
4141 Src = IRB.CreateBitPreservingCastChain(
DL, Src, IntTy);
4145 LoadInst *
Load = IRB.CreateAlignedLoad(OtherTy, SrcPtr, SrcAlign,
4146 II.isVolatile(),
"copyload");
4147 Load->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
4148 LLVMContext::MD_access_group});
4155 if (VecTy && !IsWholeAlloca && IsDest) {
4156 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
4159 }
else if (IntTy && !IsWholeAlloca && IsDest) {
4160 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
4162 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
4165 Src = IRB.CreateBitPreservingCastChain(
DL, Src, NewAllocaTy);
4169 IRB.CreateAlignedStore(Src, DstPtr, DstAlign,
II.isVolatile()));
4170 Store->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
4171 LLVMContext::MD_access_group});
4174 Src->getType(),
DL));
4189 return !
II.isVolatile();
4192 bool visitIntrinsicInst(IntrinsicInst &
II) {
4193 assert((
II.isLifetimeStartOrEnd() ||
II.isDroppable()) &&
4194 "Unexpected intrinsic!");
4198 Pass.DeadInsts.push_back(&
II);
4200 if (
II.isDroppable()) {
4201 assert(
II.getIntrinsicID() == Intrinsic::assume &&
"Expected assume");
4207 assert(
II.getArgOperand(0) == OldPtr);
4211 if (
II.getIntrinsicID() == Intrinsic::lifetime_start)
4212 New = IRB.CreateLifetimeStart(Ptr);
4214 New = IRB.CreateLifetimeEnd(Ptr);
4222 void fixLoadStoreAlign(Instruction &Root) {
4226 SmallPtrSet<Instruction *, 4> Visited;
4227 SmallVector<Instruction *, 4>
Uses;
4229 Uses.push_back(&Root);
4238 SI->setAlignment(std::min(
SI->getAlign(), getSliceAlign()));
4245 for (User *U :
I->users())
4248 }
while (!
Uses.empty());
4251 bool visitPHINode(PHINode &PN) {
4253 assert(BeginOffset >= NewAllocaBeginOffset &&
"PHIs are unsplittable");
4254 assert(EndOffset <= NewAllocaEndOffset &&
"PHIs are unsplittable");
4260 IRBuilderBase::InsertPointGuard Guard(IRB);
4262 IRB.SetInsertPoint(OldPtr->
getParent()->getFirstInsertionPt());
4264 IRB.SetInsertPoint(OldPtr);
4265 IRB.SetCurrentDebugLocation(OldPtr->
getDebugLoc());
4267 Value *NewPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
4272 deleteIfTriviallyDead(OldPtr);
4275 fixLoadStoreAlign(PN);
4284 bool visitSelectInst(SelectInst &SI) {
4286 assert((
SI.getTrueValue() == OldPtr ||
SI.getFalseValue() == OldPtr) &&
4287 "Pointer isn't an operand!");
4288 assert(BeginOffset >= NewAllocaBeginOffset &&
"Selects are unsplittable");
4289 assert(EndOffset <= NewAllocaEndOffset &&
"Selects are unsplittable");
4291 Value *NewPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
4293 if (
SI.getOperand(1) == OldPtr)
4294 SI.setOperand(1, NewPtr);
4295 if (
SI.getOperand(2) == OldPtr)
4296 SI.setOperand(2, NewPtr);
4299 deleteIfTriviallyDead(OldPtr);
4302 fixLoadStoreAlign(SI);
4317class AggLoadStoreRewriter :
public InstVisitor<AggLoadStoreRewriter, bool> {
4319 friend class InstVisitor<AggLoadStoreRewriter, bool>;
4325 SmallPtrSet<User *, 8> Visited;
4332 const DataLayout &
DL;
4337 AggLoadStoreRewriter(
const DataLayout &
DL, IRBuilderTy &IRB)
4338 :
DL(
DL), IRB(IRB) {}
4342 bool rewrite(Instruction &
I) {
4346 while (!
Queue.empty()) {
4347 U =
Queue.pop_back_val();
4356 void enqueueUsers(Instruction &
I) {
4357 for (Use &U :
I.uses())
4358 if (Visited.
insert(
U.getUser()).second)
4359 Queue.push_back(&U);
4363 bool visitInstruction(Instruction &
I) {
return false; }
4366 template <
typename Derived>
class OpSplitter {
4373 SmallVector<unsigned, 4> Indices;
4377 SmallVector<Value *, 4> GEPIndices;
4391 const DataLayout &
DL;
4395 OpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4396 Align BaseAlign,
const DataLayout &
DL, IRBuilderTy &IRB)
4397 : IRB(IRB), GEPIndices(1, IRB.getInt32(0)), Ptr(Ptr), BaseTy(BaseTy),
4398 BaseAlign(BaseAlign),
DL(
DL) {
4399 IRB.SetInsertPoint(InsertionPoint);
4416 void emitSplitOps(
Type *Ty,
Value *&Agg,
const Twine &Name) {
4418 unsigned Offset =
DL.getIndexedOffsetInType(BaseTy, GEPIndices);
4419 return static_cast<Derived *
>(
this)->emitFunc(
4424 unsigned OldSize = Indices.
size();
4426 for (
unsigned Idx = 0,
Size = ATy->getNumElements(); Idx !=
Size;
4428 assert(Indices.
size() == OldSize &&
"Did not return to the old size");
4430 GEPIndices.
push_back(IRB.getInt32(Idx));
4431 emitSplitOps(ATy->getElementType(), Agg, Name +
"." + Twine(Idx));
4439 unsigned OldSize = Indices.
size();
4441 for (
unsigned Idx = 0,
Size = STy->getNumElements(); Idx !=
Size;
4443 assert(Indices.
size() == OldSize &&
"Did not return to the old size");
4445 GEPIndices.
push_back(IRB.getInt32(Idx));
4446 emitSplitOps(STy->getElementType(Idx), Agg, Name +
"." + Twine(Idx));
4457 struct LoadOpSplitter :
public OpSplitter<LoadOpSplitter> {
4461 SmallVector<Value *, 4> Components;
4466 LoadOpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4467 AAMDNodes AATags, Align BaseAlign,
const DataLayout &
DL,
4469 : OpSplitter<LoadOpSplitter>(InsertionPoint, Ptr, BaseTy, BaseAlign,
DL,
4475 void emitFunc(
Type *Ty,
Value *&Agg, Align Alignment,
const Twine &Name) {
4479 IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name +
".gep");
4481 IRB.CreateAlignedLoad(Ty,
GEP, Alignment, Name +
".load");
4487 Load->setAAMetadata(
4493 Agg = IRB.CreateInsertValue(Agg,
Load, Indices, Name +
".insert");
4498 void recordFakeUses(LoadInst &LI) {
4499 for (Use &U : LI.
uses())
4501 if (
II->getIntrinsicID() == Intrinsic::fake_use)
4507 void emitFakeUses() {
4508 for (Instruction *
I : FakeUses) {
4509 IRB.SetInsertPoint(
I);
4510 for (
auto *
V : Components)
4511 IRB.CreateIntrinsic(Intrinsic::fake_use, {
V});
4512 I->eraseFromParent();
4517 bool visitLoadInst(LoadInst &LI) {
4526 Splitter.recordFakeUses(LI);
4529 Splitter.emitFakeUses();
4536 struct StoreOpSplitter :
public OpSplitter<StoreOpSplitter> {
4537 StoreOpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4538 AAMDNodes AATags, StoreInst *AggStore, Align BaseAlign,
4539 const DataLayout &
DL, IRBuilderTy &IRB)
4540 : OpSplitter<StoreOpSplitter>(InsertionPoint, Ptr, BaseTy, BaseAlign,
4542 AATags(AATags), AggStore(AggStore) {}
4544 StoreInst *AggStore;
4547 void emitFunc(
Type *Ty,
Value *&Agg, Align Alignment,
const Twine &Name) {
4553 Value *ExtractValue =
4554 IRB.CreateExtractValue(Agg, Indices, Name +
".extract");
4555 Value *InBoundsGEP =
4556 IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name +
".gep");
4558 IRB.CreateAlignedStore(ExtractValue, InBoundsGEP, Alignment);
4575 DL.getTypeSizeInBits(
Store->getValueOperand()->getType());
4577 SizeInBits, AggStore,
Store,
4578 Store->getPointerOperand(),
Store->getValueOperand(),
4582 "AT: unexpected debug.assign linked to store through "
4589 bool visitStoreInst(StoreInst &SI) {
4590 if (!
SI.isSimple() ||
SI.getPointerOperand() != *U)
4593 if (
V->getType()->isSingleValueType())
4598 StoreOpSplitter Splitter(&SI, *U,
V->getType(),
SI.getAAMetadata(), &SI,
4600 Splitter.emitSplitOps(
V->getType(),
V,
V->getName() +
".fca");
4605 SI.eraseFromParent();
4609 bool visitBitCastInst(BitCastInst &BC) {
4614 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
4624 bool unfoldGEPSelect(GetElementPtrInst &GEPI) {
4643 if (!ZI->getSrcTy()->isIntegerTy(1))
4656 dbgs() <<
" original: " << *Sel <<
"\n";
4657 dbgs() <<
" " << GEPI <<
"\n";);
4659 auto GetNewOps = [&](
Value *SelOp) {
4672 Cond =
SI->getCondition();
4673 True =
SI->getTrueValue();
4677 Cond = Sel->getOperand(0);
4678 True = ConstantInt::get(Sel->getType(), 1);
4679 False = ConstantInt::get(Sel->getType(), 0);
4684 IRB.SetInsertPoint(&GEPI);
4688 Value *NTrue = IRB.CreateGEP(Ty, TrueOps[0],
ArrayRef(TrueOps).drop_front(),
4689 True->getName() +
".sroa.gep", NW);
4692 IRB.CreateGEP(Ty, FalseOps[0],
ArrayRef(FalseOps).drop_front(),
4693 False->getName() +
".sroa.gep", NW);
4695 Value *NSel = MDFrom
4696 ? IRB.CreateSelect(
Cond, NTrue, NFalse,
4697 Sel->getName() +
".sroa.sel", MDFrom)
4698 : IRB.CreateSelectWithUnknownProfile(
4700 Sel->getName() +
".sroa.sel");
4701 Visited.
erase(&GEPI);
4706 enqueueUsers(*NSelI);
4709 dbgs() <<
" " << *NFalse <<
"\n";
4710 dbgs() <<
" " << *NSel <<
"\n";);
4719 bool unfoldGEPPhi(GetElementPtrInst &GEPI) {
4724 auto IsInvalidPointerOperand = [](
Value *
V) {
4728 return !AI->isStaticAlloca();
4732 if (
any_of(
Phi->operands(), IsInvalidPointerOperand))
4747 [](
Value *
V) { return isa<ConstantInt>(V); }))
4760 dbgs() <<
" original: " << *
Phi <<
"\n";
4761 dbgs() <<
" " << GEPI <<
"\n";);
4763 auto GetNewOps = [&](
Value *PhiOp) {
4773 IRB.SetInsertPoint(Phi);
4774 PHINode *NewPhi = IRB.CreatePHI(GEPI.
getType(),
Phi->getNumIncomingValues(),
4775 Phi->getName() +
".sroa.phi");
4781 for (
unsigned I = 0,
E =
Phi->getNumIncomingValues();
I !=
E; ++
I) {
4790 IRB.CreateGEP(SourceTy, NewOps[0],
ArrayRef(NewOps).drop_front(),
4796 Visited.
erase(&GEPI);
4800 enqueueUsers(*NewPhi);
4806 dbgs() <<
"\n " << *NewPhi <<
'\n');
4811 bool visitGetElementPtrInst(GetElementPtrInst &GEPI) {
4812 if (unfoldGEPSelect(GEPI))
4815 if (unfoldGEPPhi(GEPI))
4822 bool visitPHINode(PHINode &PN) {
4827 bool visitSelectInst(SelectInst &SI) {
4841 if (Ty->isSingleValueType())
4844 uint64_t AllocSize =
DL.getTypeAllocSize(Ty).getFixedValue();
4849 InnerTy = ArrTy->getElementType();
4853 InnerTy = STy->getElementType(Index);
4858 if (AllocSize >
DL.getTypeAllocSize(InnerTy).getFixedValue() ||
4859 TypeSize >
DL.getTypeSizeInBits(InnerTy).getFixedValue())
4880 if (
Offset == 0 &&
DL.getTypeAllocSize(Ty).getFixedValue() ==
Size)
4882 if (
Offset >
DL.getTypeAllocSize(Ty).getFixedValue() ||
4883 (
DL.getTypeAllocSize(Ty).getFixedValue() -
Offset) <
Size)
4890 ElementTy = AT->getElementType();
4891 TyNumElements = AT->getNumElements();
4896 ElementTy = VT->getElementType();
4897 TyNumElements = VT->getNumElements();
4899 uint64_t ElementSize =
DL.getTypeAllocSize(ElementTy).getFixedValue();
4901 if (NumSkippedElements >= TyNumElements)
4903 Offset -= NumSkippedElements * ElementSize;
4915 if (
Size == ElementSize)
4919 if (NumElements * ElementSize !=
Size)
4943 uint64_t ElementSize =
DL.getTypeAllocSize(ElementTy).getFixedValue();
4944 if (
Offset >= ElementSize)
4955 if (
Size == ElementSize)
4962 if (Index == EndIndex)
4972 assert(Index < EndIndex);
4997 const std::vector<uint64_t> &Splits;
5004 std::vector<uint64_t> &Splits,
unsigned SliceSize)
5005 : IRB(IRB), DL(DL), Splits(Splits), SliceSize(SliceSize) {}
5015 Idx = IsEnd ?
SS.Splits.size() + 1 : 0;
5020 uint64_t NextOffset =
5021 Idx <
SS.Splits.size() ?
SS.Splits[
Idx] :
SS.SliceSize;
5037 Type *PartPtrTy = BasePtr->getType();
5039 LoadInst *PLoad = IRB.CreateAlignedLoad(
5043 PartPtrTy, BasePtr->getName() +
"."),
5046 PLoad->
copyMetadata(*SplitI, {LLVMContext::MD_mem_parallel_loop_access,
5047 LLVMContext::MD_access_group});
5053 Type *PartPtrTy = BasePtr->getType();
5055 StoreInst *PStore = IRB.CreateAlignedStore(
5059 PartPtrTy, BasePtr->getName() +
"."),
5062 PStore->
copyMetadata(*SplitI, {LLVMContext::MD_mem_parallel_loop_access,
5063 LLVMContext::MD_access_group,
5064 LLVMContext::MD_DIAssignID});
5074 unsigned PtrIdx = 0;
5078 PtrIdx =
SI->getPointerOperandIndex();
5085 &
I->getOperandUse(PtrIdx),
false);
5087 << S.endOffset() <<
"): " << *
I <<
"\n");
5098 InstructionSliceMap &SliceMap) {
5100 if (S.endOffset() - S.beginOffset() == 1)
5118 for (Slice *JS : SliceMap[J]) {
5119 if (S.beginOffset() > JS->beginOffset() &&
5120 S.beginOffset() < JS->endOffset())
5122 if (JS->beginOffset() > S.beginOffset() &&
5123 JS->beginOffset() < S.endOffset())
5154bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
5168 struct SplitOffsets {
5170 std::vector<uint64_t> Splits;
5172 SmallDenseMap<Instruction *, SplitOffsets, 8> SplitOffsetsMap;
5185 SmallPtrSet<LoadInst *, 8> UnsplittableLoads;
5187 LLVM_DEBUG(
dbgs() <<
" Searching for candidate loads and stores\n");
5188 for (
auto &
P : AS.partitions()) {
5189 InstructionSliceMap SliceMap;
5190 for (Slice &S :
P) {
5193 for (Slice &S :
P) {
5195 bool ExtendsPastPartitionEnd = S.endOffset() >
P.endOffset();
5197 if (!S.isSplittable() || (!ExtendsPastPartitionEnd && !CopyOverlap)) {
5202 UnsplittableLoads.
insert(LI);
5205 UnsplittableLoads.
insert(LI);
5208 assert(
P.endOffset() > S.beginOffset() &&
5209 "Empty or backwards partition!");
5218 auto IsLoadSimplyStored = [](LoadInst *LI) {
5219 for (User *LU : LI->
users()) {
5221 if (!SI || !
SI->isSimple())
5226 if (!IsLoadSimplyStored(LI)) {
5227 UnsplittableLoads.
insert(LI);
5233 if (S.getUse() != &
SI->getOperandUse(
SI->getPointerOperandIndex()))
5237 if (!StoredLoad || !StoredLoad->isSimple())
5239 assert(!
SI->isVolatile() &&
"Cannot split volatile stores!");
5249 auto &
Offsets = SplitOffsetsMap[
I];
5251 "Should not have splits the first time we see an instruction!");
5266 std::max(S.beginOffset(), CopyOverlap->beginOffset());
5267 uint64_t OverlapEnd = std::min(S.endOffset(), CopyOverlap->endOffset());
5268 uint64_t OverlapSize = OverlapEnd - OverlapStart;
5269 uint64_t SliceSize = S.endOffset() - S.beginOffset();
5270 uint64_t NonOverlapSize = SliceSize - OverlapSize;
5271 if (OverlapSize < NonOverlapSize) {
5276 Offsets.Splits.push_back(OverlapSize);
5277 Offsets.Splits.push_back(SliceSize - OverlapSize);
5278 }
else if (OverlapSize > NonOverlapSize) {
5281 for (
uint64_t Split = NonOverlapSize;
Split <= SliceSize / 2;
5282 Split += NonOverlapSize) {
5283 Offsets.Splits.push_back(Split);
5284 if (Split != SliceSize - Split) {
5285 Offsets.Splits.push_back(SliceSize - Split);
5293 Offsets.Splits.push_back(OverlapSize);
5296 Offsets.Splits.push_back(
P.endOffset() - S.beginOffset());
5305 llvm::erase_if(Stores, [&UnsplittableLoads, &SplitOffsetsMap](StoreInst *SI) {
5311 if (UnsplittableLoads.
count(LI))
5314 auto LoadOffsetsI = SplitOffsetsMap.
find(LI);
5315 if (LoadOffsetsI == SplitOffsetsMap.
end())
5317 auto &LoadOffsets = LoadOffsetsI->second;
5320 auto &StoreOffsets = SplitOffsetsMap[
SI];
5325 if (LoadOffsets.Splits == StoreOffsets.Splits)
5329 <<
" " << *LI <<
"\n"
5330 <<
" " << *SI <<
"\n");
5336 UnsplittableLoads.
insert(LI);
5345 return UnsplittableLoads.
count(LI);
5350 return UnsplittableLoads.
count(LI);
5360 IRBuilderTy IRB(&AI);
5361 IRB.disableGEPCanonicalization();
5368 SmallPtrSet<AllocaInst *, 4> ResplitPromotableAllocas;
5378 SmallDenseMap<LoadInst *, std::vector<LoadInst *>, 1> SplitLoadsMap;
5379 std::vector<LoadInst *> SplitLoads;
5380 const DataLayout &
DL = AI.getDataLayout();
5381 for (LoadInst *LI : Loads) {
5384 auto &
Offsets = SplitOffsetsMap[LI];
5385 unsigned SliceSize =
Offsets.S->endOffset() -
Offsets.S->beginOffset();
5387 "Load must have type size equal to store size");
5389 "Load must be >= slice size");
5392 assert(BaseOffset + SliceSize > BaseOffset &&
5393 "Cannot represent alloca access size using 64-bit integers!");
5396 IRB.SetInsertPoint(LI);
5400 SliceSplitter Splitter(IRB,
DL,
Offsets.Splits, SliceSize);
5401 for (
auto Part : Splitter) {
5402 LoadInst *PLoad = Splitter.createLoad(BasePtr, Part, LI);
5406 SplitLoads.push_back(PLoad);
5409 NewSlices.
push_back(Splitter.createSlice(PLoad, BaseOffset, Part));
5415 bool DeferredStores =
false;
5416 for (User *LU : LI->
users()) {
5418 if (!Stores.
empty() && SplitOffsetsMap.
count(SI)) {
5419 DeferredStores =
true;
5425 Value *StoreBasePtr =
SI->getPointerOperand();
5426 IRB.SetInsertPoint(SI);
5428 LLVM_DEBUG(
dbgs() <<
" Splitting store of load: " << *SI <<
"\n");
5430 for (
auto Part : Splitter) {
5431 LoadInst *PLoad = SplitLoads[Part.Idx];
5432 StoreInst *PStore = Splitter.createStore(PLoad, StoreBasePtr, Part, SI);
5443 ResplitPromotableAllocas.
insert(OtherAI);
5444 Worklist.insert(OtherAI);
5447 Worklist.insert(OtherAI);
5451 DeadInsts.push_back(SI);
5456 SplitLoadsMap.
insert(std::make_pair(LI, std::move(SplitLoads)));
5459 DeadInsts.push_back(LI);
5468 for (StoreInst *SI : Stores) {
5473 assert(StoreSize > 0 &&
"Cannot have a zero-sized integer store!");
5477 "Slice size should always match load size exactly!");
5479 assert(BaseOffset + StoreSize > BaseOffset &&
5480 "Cannot represent alloca access size using 64-bit integers!");
5488 auto SplitLoadsMapI = SplitLoadsMap.
find(LI);
5489 std::vector<LoadInst *> *SplitLoads =
nullptr;
5490 if (SplitLoadsMapI != SplitLoadsMap.
end()) {
5491 SplitLoads = &SplitLoadsMapI->second;
5493 "Too few split loads for the number of splits in the store!");
5498 SliceSplitter Splitter(IRB,
DL,
Offsets.Splits, StoreSize);
5499 for (
auto Part : Splitter) {
5503 PLoad = (*SplitLoads)[Part.Idx];
5505 IRB.SetInsertPoint(LI);
5506 PLoad = Splitter.createLoad(LoadBasePtr, Part, LI);
5510 IRB.SetInsertPoint(SI);
5511 StoreInst *PStore = Splitter.createStore(PLoad, StoreBasePtr, Part, SI);
5514 NewSlices.
push_back(Splitter.createSlice(PStore, BaseOffset, Part));
5527 assert(OtherAI != &AI &&
"We can't re-split our own alloca!");
5528 ResplitPromotableAllocas.
insert(OtherAI);
5529 Worklist.insert(OtherAI);
5532 assert(StrippedAI != &AI &&
"We can't re-split our own alloca!");
5533 Worklist.insert(StrippedAI);
5548 DeadInsts.push_back(LI);
5550 DeadInsts.push_back(SI);
5559 AS.insert(NewSlices);
5563 for (
auto I = AS.begin(),
E = AS.end();
I !=
E; ++
I)
5569 PromotableAllocas.set_subtract(ResplitPromotableAllocas);
5606 bool IsIntegralPointerTy =
5607 EltTy->
isPointerTy() && !
DL.isNonIntegralPointerType(EltTy);
5609 !IsIntegralPointerTy)
5616 if (
DL.getTypeSizeInBits(EltTy) !=
DL.getTypeAllocSizeInBits(EltTy))
5620 TypeSize StructSize =
DL.getStructLayout(STy)->getSizeInBytes();
5621 TypeSize VectorSize =
DL.getTypeStoreSize(VTy);
5624 if (StructSize != VectorSize)
5627 auto IsIgnorableOrMemIntrinsicSlice = [](
const Slice &S) {
5630 auto *U = S.getUse();
5634 for (
const Slice &S :
P)
5635 if (!IsIgnorableOrMemIntrinsicSlice(S))
5638 for (
const Slice *S :
P.splitSliceTails())
5639 if (!IsIgnorableOrMemIntrinsicSlice(*S))
5656static std::tuple<Type *, bool, VectorType *>
5660 VectorType *SelectedVecTy,
bool SelectedIntWidening) {
5662 dbgs() <<
"selectPartitionType path=" << Path
5667 dbgs() <<
"<unnamed>";
5668 dbgs() <<
" partition=[" <<
P.beginOffset() <<
"," <<
P.endOffset()
5669 <<
") size=" <<
P.size();
5671 dbgs() <<
" alloc-size=" << AllocSize->getKnownMinValue();
5673 dbgs() <<
" chosen=" << *SelectedTy;
5675 dbgs() <<
" vec=" << *SelectedVecTy;
5676 dbgs() <<
" intwiden=" << SelectedIntWidening <<
"\n";
5694 if (VecTy && VecTy->getElementType()->isFloatingPointTy() &&
5695 VecTy->getElementCount().getFixedValue() > 1) {
5696 LogSelection(
"direct-fp-vecty", VecTy, VecTy,
false);
5697 return {VecTy,
false, VecTy};
5702 auto [CommonUseTy, LargestIntTy] =
5705 TypeSize CommonUseSize =
DL.getTypeAllocSize(CommonUseTy);
5711 LogSelection(
"common-type-vecty", VecTy, VecTy,
false);
5712 return {VecTy,
false, VecTy};
5715 LogSelection(
"common-type", CommonUseTy,
nullptr, IntWiden);
5716 return {CommonUseTy, IntWiden,
nullptr};
5723 P.beginOffset(),
P.size())) {
5727 if (TypePartitionTy->isArrayTy() &&
5728 TypePartitionTy->getArrayElementType()->isIntegerTy() &&
5729 DL.isLegalInteger(
P.size() * 8))
5733 LogSelection(
"type-partition-int-widen", TypePartitionTy,
nullptr,
true);
5734 return {TypePartitionTy,
true,
nullptr};
5737 LogSelection(
"type-partition-vecty", VecTy, VecTy,
false);
5738 return {VecTy,
false, VecTy};
5743 DL.getTypeAllocSize(LargestIntTy).getFixedValue() >=
P.size() &&
5745 LogSelection(
"largest-int-int-widen", LargestIntTy,
nullptr,
true);
5746 return {LargestIntTy,
true,
nullptr};
5751 if (AggregateToVector) {
5754 LogSelection(
"struct-fallback-vecty", VTy,
nullptr,
false);
5755 return {VTy,
false,
nullptr};
5761 LogSelection(
"type-partition-fallback", TypePartitionTy,
nullptr,
false);
5762 return {TypePartitionTy,
false,
nullptr};
5767 DL.getTypeAllocSize(LargestIntTy).getFixedValue() >=
P.size()) {
5768 LogSelection(
"largest-int-fallback", LargestIntTy,
nullptr,
false);
5769 return {LargestIntTy,
false,
nullptr};
5773 if (
DL.isLegalInteger(
P.size() * 8)) {
5775 LogSelection(
"legal-int-fallback", IntTy,
nullptr,
false);
5776 return {IntTy,
false,
nullptr};
5781 LogSelection(
"byte-array-fallback", ArrayTy,
nullptr,
false);
5782 return {ArrayTy,
false,
nullptr};
5795std::pair<AllocaInst *, uint64_t>
5796SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS, Partition &
P) {
5797 const DataLayout &
DL = AI.getDataLayout();
5799 auto [PartitionTy, IsIntegerWideningViable, VecTy] =
5809 if (PartitionTy == AI.getAllocatedType() &&
P.beginOffset() == 0) {
5818 new AllocaInst(PartitionTy, AI.getAddressSpace(),
nullptr, Alignment,
5819 AI.getName() +
".sroa." + Twine(
P.begin() - AS.begin()),
5827 LLVM_DEBUG(
dbgs() <<
"Rewriting alloca partition " <<
"[" <<
P.beginOffset()
5828 <<
"," <<
P.endOffset() <<
") to: " << *NewAI <<
"\n");
5833 unsigned PPWOldSize = PostPromotionWorklist.size();
5834 unsigned NumUses = 0;
5835 SmallSetVector<PHINode *, 8> PHIUsers;
5836 SmallSetVector<SelectInst *, 8> SelectUsers;
5839 DL, AS, *
this, AI, *NewAI, PartitionTy,
P.beginOffset(),
P.endOffset(),
5840 IsIntegerWideningViable, VecTy, PHIUsers, SelectUsers);
5841 bool Promotable =
true;
5843 if (
auto DeletedValues =
Rewriter.rewriteTreeStructuredMerge(
P)) {
5844 NumUses += DeletedValues->
size() + 1;
5845 for (
Value *
V : *DeletedValues)
5846 DeadInsts.push_back(
V);
5848 for (Slice *S :
P.splitSliceTails()) {
5852 for (Slice &S :
P) {
5858 NumAllocaPartitionUses += NumUses;
5859 MaxUsesPerAllocaPartition.updateMax(NumUses);
5865 for (PHINode *
PHI : PHIUsers) {
5876 SelectUsers.
clear();
5881 NewSelectsToRewrite;
5883 for (SelectInst *Sel : SelectUsers) {
5884 std::optional<RewriteableMemOps>
Ops =
5885 isSafeSelectToSpeculateOrPredicate(*Sel, PreserveCFG);
5894 for (Use *U : AS.getDeadUsesIfPromotable()) {
5896 Value::dropDroppableUse(*U);
5899 DeadInsts.push_back(OldInst);
5901 if (NewSpeculatablePHIs.
empty() && NewPHIsWithStoreToRewrite.
empty() &&
5902 SelectUsers.empty()) {
5904 PromotableAllocas.insert(NewAI);
5909 SpeculatablePHIs.insert_range(NewSpeculatablePHIs);
5910 PHIsWithStoreToRewrite.insert_range(NewPHIsWithStoreToRewrite);
5911 SelectsToRewrite.reserve(SelectsToRewrite.size() +
5912 NewSelectsToRewrite.
size());
5914 std::make_move_iterator(NewSelectsToRewrite.
begin()),
5915 std::make_move_iterator(NewSelectsToRewrite.
end())))
5916 SelectsToRewrite.insert(std::move(KV));
5917 Worklist.insert(NewAI);
5921 while (PostPromotionWorklist.size() > PPWOldSize)
5922 PostPromotionWorklist.pop_back();
5927 return {
nullptr, 0};
5932 Worklist.insert(NewAI);
5935 return {NewAI,
DL.getTypeSizeInBits(PartitionTy).getFixedValue()};
5979 int64_t BitExtractOffset) {
5981 bool HasFragment =
false;
5982 bool HasBitExtract =
false;
5990 HasBitExtract =
true;
5991 int64_t ExtractOffsetInBits = Extract.getOffsetInBits();
5992 int64_t ExtractSizeInBits = Extract.getSizeInBits();
6001 assert(BitExtractOffset <= 0);
6002 int64_t AdjustedOffset = ExtractOffsetInBits + BitExtractOffset;
6008 if (AdjustedOffset < 0)
6011 Ops.push_back(
Op.getOp());
6012 Ops.push_back(std::max<int64_t>(0, AdjustedOffset));
6013 Ops.push_back(ExtractSizeInBits);
6016 Op.appendToVector(
Ops);
6021 if (HasFragment && HasBitExtract)
6024 if (!HasBitExtract) {
6043 std::optional<DIExpression::FragmentInfo> NewFragment,
6044 int64_t BitExtractAdjustment) {
6054 BitExtractAdjustment);
6055 if (!NewFragmentExpr)
6061 BeforeInst->
getParent()->insertDbgRecordBefore(DVR,
6074 BeforeInst->
getParent()->insertDbgRecordBefore(DVR,
6080 if (!NewAddr->
hasMetadata(LLVMContext::MD_DIAssignID)) {
6088 LLVM_DEBUG(
dbgs() <<
"Created new DVRAssign: " << *NewAssign <<
"\n");
6094bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
6095 if (AS.begin() == AS.end())
6098 unsigned NumPartitions = 0;
6100 const DataLayout &
DL = AI.getDataLayout();
6103 Changed |= presplitLoadsAndStores(AI, AS);
6111 bool IsSorted =
true;
6113 uint64_t AllocaSize = AI.getAllocationSize(
DL)->getFixedValue();
6121 SparseBitVector<> SplittableOffset;
6123 for (Slice &S : AS) {
6125 if (S.beginOffset() > CurBegin || S.endOffset() > CurEnd) {
6127 if (S.beginOffset() >= CurEnd) {
6128 SplittableOffset.
set(S.beginOffset());
6131 if (CurEnd > S.beginOffset() && CurEnd < S.endOffset()) {
6132 SplittableOffset.
reset(CurEnd);
6134 CurBegin = S.beginOffset();
6138 if (S.endOffset() > CurEnd) {
6139 CurEnd = S.endOffset();
6140 SplittableOffset.
set(CurEnd);
6145 for (Slice &S : AS) {
6146 if (!S.isSplittable())
6149 if ((S.beginOffset() > AllocaSize ||
6150 SplittableOffset.
test(S.beginOffset())) &&
6151 (S.endOffset() > AllocaSize || SplittableOffset.
test(S.endOffset())))
6156 S.makeUnsplittable();
6176 for (
auto &
P : AS.partitions()) {
6177 auto [NewAI, ActiveBits] = rewritePartition(AI, AS, P);
6181 uint64_t SizeOfByte = 8;
6183 uint64_t Size = std::min(ActiveBits, P.size() * SizeOfByte);
6184 Fragments.push_back(
6185 Fragment(NewAI, P.beginOffset() * SizeOfByte, Size));
6191 NumAllocaPartitions += NumPartitions;
6192 MaxPartitionsPerAlloca.updateMax(NumPartitions);
6196 auto MigrateOne = [&](DbgVariableRecord *DbgVariable) {
6201 const Value *DbgPtr = DbgVariable->getAddress();
6203 DbgVariable->getFragmentOrEntireVariable();
6206 int64_t CurrentExprOffsetInBytes = 0;
6207 SmallVector<uint64_t> PostOffsetOps;
6209 ->extractLeadingOffset(CurrentExprOffsetInBytes, PostOffsetOps))
6213 int64_t ExtractOffsetInBits = 0;
6216 ExtractOffsetInBits = Extract.getOffsetInBits();
6221 DIBuilder DIB(*AI.getModule(),
false);
6223 int64_t OffsetFromLocationInBits;
6224 std::optional<DIExpression::FragmentInfo> NewDbgFragment;
6230 CurrentExprOffsetInBytes * 8, ExtractOffsetInBits, VarFrag,
6231 NewDbgFragment, OffsetFromLocationInBits))
6237 if (NewDbgFragment && !NewDbgFragment->SizeInBits)
6242 if (!NewDbgFragment)
6243 NewDbgFragment = DbgVariable->getFragment();
6247 int64_t OffestFromNewAllocaInBits =
6248 OffsetFromLocationInBits - ExtractOffsetInBits;
6251 int64_t BitExtractOffset =
6252 std::min<int64_t>(0, OffestFromNewAllocaInBits);
6257 OffestFromNewAllocaInBits =
6258 std::max(int64_t(0), OffestFromNewAllocaInBits);
6264 DIExpression *NewExpr = DIExpression::get(AI.getContext(), PostOffsetOps);
6265 if (OffestFromNewAllocaInBits > 0) {
6266 int64_t OffsetInBytes = (OffestFromNewAllocaInBits + 7) / 8;
6272 auto RemoveOne = [DbgVariable](
auto *OldDII) {
6273 auto SameVariableFragment = [](
const auto *
LHS,
const auto *
RHS) {
6274 return LHS->getVariable() ==
RHS->getVariable() &&
6275 LHS->getDebugLoc()->getInlinedAt() ==
6276 RHS->getDebugLoc()->getInlinedAt();
6278 if (SameVariableFragment(OldDII, DbgVariable))
6279 OldDII->eraseFromParent();
6284 NewDbgFragment, BitExtractOffset);
6298void SROA::clobberUse(Use &U) {
6308 DeadInsts.push_back(OldI);
6330bool SROA::propagateStoredValuesToLoads(AllocaInst &AI, AllocaSlices &AS) {
6335 LLVM_DEBUG(
dbgs() <<
"Attempting to propagate values on " << AI <<
"\n");
6336 bool AllSameAndValid =
true;
6337 Type *PartitionType =
nullptr;
6338 SmallVector<Instruction *> Insts;
6342 auto Flush = [&]() {
6343 if (AllSameAndValid && !Insts.
empty()) {
6344 LLVM_DEBUG(
dbgs() <<
"Propagate values on slice [" << BeginOffset <<
", "
6345 << EndOffset <<
")\n");
6347 SSAUpdater
SSA(&NewPHIs);
6349 BasicLoadAndStorePromoter Promoter(Insts,
SSA, PartitionType);
6350 Promoter.run(Insts);
6352 AllSameAndValid =
true;
6353 PartitionType =
nullptr;
6357 for (Slice &S : AS) {
6361 dbgs() <<
"Ignoring slice: ";
6362 AS.print(
dbgs(), &S);
6366 if (S.beginOffset() >= EndOffset) {
6368 BeginOffset = S.beginOffset();
6369 EndOffset = S.endOffset();
6370 }
else if (S.beginOffset() != BeginOffset || S.endOffset() != EndOffset) {
6371 if (AllSameAndValid) {
6373 dbgs() <<
"Slice does not match range [" << BeginOffset <<
", "
6374 << EndOffset <<
")";
6375 AS.print(
dbgs(), &S);
6377 AllSameAndValid =
false;
6379 EndOffset = std::max(EndOffset, S.endOffset());
6386 if (!LI->
isSimple() || (PartitionType && UserTy != PartitionType))
6387 AllSameAndValid =
false;
6388 PartitionType = UserTy;
6391 Type *UserTy =
SI->getValueOperand()->getType();
6392 if (!
SI->isSimple() || (PartitionType && UserTy != PartitionType))
6393 AllSameAndValid =
false;
6394 PartitionType = UserTy;
6397 AllSameAndValid =
false;
6410std::pair<
bool ,
bool >
6411SROA::runOnAlloca(AllocaInst &AI) {
6413 bool CFGChanged =
false;
6416 ++NumAllocasAnalyzed;
6419 if (AI.use_empty()) {
6420 DeadInsts.push_back(&AI);
6424 const DataLayout &
DL = AI.getDataLayout();
6427 std::optional<TypeSize>
Size = AI.getAllocationSize(
DL);
6428 if (AI.isArrayAllocation() || !
Size ||
Size->isScalable() ||
Size->isZero())
6433 IRBuilderTy IRB(&AI);
6434 IRB.disableGEPCanonicalization();
6435 AggLoadStoreRewriter AggRewriter(
DL, IRB);
6436 Changed |= AggRewriter.rewrite(AI);
6439 AllocaSlices AS(
DL, AI);
6444 if (AS.isEscapedReadOnly()) {
6445 Changed |= propagateStoredValuesToLoads(AI, AS);
6450 for (Instruction *DeadUser : AS.getDeadUsers()) {
6452 for (Use &DeadOp : DeadUser->operands())
6459 DeadInsts.push_back(DeadUser);
6462 for (Use *DeadOp : AS.getDeadOperands()) {
6463 clobberUse(*DeadOp);
6468 if (AS.begin() == AS.end())
6471 Changed |= splitAlloca(AI, AS);
6474 while (!SpeculatablePHIs.empty())
6478 auto RemainingPHIsWithStoreToRewrite = PHIsWithStoreToRewrite.takeVector();
6479 while (!RemainingPHIsWithStoreToRewrite.empty()) {
6480 PHINode *PN = RemainingPHIsWithStoreToRewrite.pop_back_val();
6486 auto RemainingSelectsToRewrite = SelectsToRewrite.takeVector();
6487 while (!RemainingSelectsToRewrite.empty()) {
6488 const auto [
K,
V] = RemainingSelectsToRewrite.pop_back_val();
6505bool SROA::deleteDeadInstructions(
6506 AllocaInst *AI, SmallPtrSetImpl<AllocaInst *> &DeletedAllocas) {
6508 while (!DeadInsts.empty()) {
6518 DeletedAllocas.
insert(AI);
6520 OldDII->eraseFromParent();
6526 for (Use &Operand :
I->operands())
6531 DeadInsts.push_back(U);
6535 I->eraseFromParent();
6539 if (!DeletedAllocas.
contains(AI) && AI->hasNUndroppableUses(0)) {
6540 DeletedAllocas.
insert(AI);
6541 AI->dropDroppableUses();
6543 OldDII->eraseFromParent();
6545 AI->eraseFromParent();
6556bool SROA::promoteAllocas() {
6557 if (PromotableAllocas.empty())
6564 NumPromoted += PromotableAllocas.size();
6565 PromoteMemToReg(PromotableAllocas.getArrayRef(), DTU->getDomTree(), AC);
6568 PromotableAllocas.clear();
6572std::pair<
bool ,
bool > SROA::runSROA(
Function &
F) {
6575 const DataLayout &
DL =
F.getDataLayout();
6580 std::optional<TypeSize>
Size = AI->getAllocationSize(
DL);
6582 PromotableAllocas.insert(AI);
6584 Worklist.insert(AI);
6589 bool CFGChanged =
false;
6592 SmallPtrSet<AllocaInst *, 4> DeletedAllocas;
6595 while (!Worklist.empty()) {
6596 AllocaInst *AI = Worklist.pop_back_val();
6597 auto [IterationChanged, IterationCFGChanged] = runOnAlloca(*AI);
6599 CFGChanged |= IterationCFGChanged;
6601 Changed |= deleteDeadInstructions(AI, DeletedAllocas);
6605 if (!DeletedAllocas.
empty()) {
6606 Worklist.set_subtract(DeletedAllocas);
6607 PostPromotionWorklist.set_subtract(DeletedAllocas);
6608 PromotableAllocas.set_subtract(DeletedAllocas);
6609 DeletedAllocas.
clear();
6615 Worklist = PostPromotionWorklist;
6616 PostPromotionWorklist.clear();
6617 }
while (!Worklist.empty());
6619 assert((!CFGChanged ||
Changed) &&
"Can not only modify the CFG.");
6620 assert((!CFGChanged || !PreserveCFG) &&
6621 "Should not have modified the CFG when told to preserve it.");
6624 for (
auto &BB :
F) {
6637 SROA(&
F.getContext(), &DTU, &AC, Options).runSROA(
F);
6649 static_cast<PassInfoMixin<SROAPass> *
>(
this)->
printPipeline(
6650 OS, MapClassName2PassName);
6654 if (Options.AggregateToVector)
6655 OS <<
";aggregate-to-vector";
6676 if (skipFunction(
F))
6679 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
6681 getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
6687 void getAnalysisUsage(AnalysisUsage &AU)
const override {
6694 StringRef getPassName()
const override {
return "SROA"; }
6699char SROALegacyPass::ID = 0;
6704 AggregateToVector));
6708 "Scalar Replacement Of Aggregates",
false,
false)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
DXIL Forward Handle Accesses
This file defines the DenseMap class.
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.
This defines the Use class.
iv Induction Variable Users
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
print mir2vec MIR2Vec Vocabulary Printer Pass
This file implements a map that provides insertion order iteration.
static std::optional< AllocFnsTy > getAllocationSize(const CallBase *CB, const TargetLibraryInfo *TLI)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
PassBuilder PB(Mod->getContext(), Machine, PassOpts->PTO, std::nullopt, &PIC)
#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 defines the PointerIntPair class.
This file provides a collection of visitors which walk the (instruction) uses of a pointer.
SmallVector< MachineOperand, 4 > Cond
Remove Loads Into Fake Uses
bool isDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
static void migrateDebugInfo(AllocaInst *OldAlloca, bool IsSplit, uint64_t OldAllocaOffsetInBits, uint64_t SliceSizeInBits, Instruction *OldInst, Instruction *Inst, Value *Dest, Value *Value, const DataLayout &DL)
Find linked dbg.assign and generate a new one with the correct FragmentInfo.
static VectorType * isVectorPromotionViable(Partition &P, const DataLayout &DL, unsigned VScale)
Test whether the given alloca partitioning and range of slices can be promoted to a vector.
static Align getAdjustedAlignment(Instruction *I, uint64_t Offset)
Compute the adjusted alignment for a load or store from an offset.
static VectorType * checkVectorTypesForPromotion(Partition &P, const DataLayout &DL, SmallVectorImpl< VectorType * > &CandidateTys, bool HaveCommonEltTy, Type *CommonEltTy, bool HaveVecPtrTy, bool HaveCommonVecPtrTy, VectorType *CommonVecPtrTy, unsigned VScale)
Test whether any vector type in CandidateTys is viable for promotion.
static std::pair< Type *, IntegerType * > findCommonType(AllocaSlices::const_iterator B, AllocaSlices::const_iterator E, uint64_t EndOffset)
Walk the range of a partitioning looking for a common type to cover this sequence of slices.
static Type * stripAggregateTypeWrapping(const DataLayout &DL, Type *Ty)
Strip aggregate type wrapping.
static void rewriteMemOpOfSelect(SelectInst &SI, T &I, SelectHandSpeculativity Spec, IRBuilderTy &IRB, DomTreeUpdater &DTU)
static FragCalcResult calculateFragment(DILocalVariable *Variable, uint64_t NewStorageSliceOffsetInBits, uint64_t NewStorageSliceSizeInBits, std::optional< DIExpression::FragmentInfo > StorageFragment, std::optional< DIExpression::FragmentInfo > CurrentFragment, DIExpression::FragmentInfo &Target)
static DIExpression * createOrReplaceFragment(const DIExpression *Expr, DIExpression::FragmentInfo Frag, int64_t BitExtractOffset)
Create or replace an existing fragment in a DIExpression with Frag.
static Value * insertInteger(const DataLayout &DL, IRBuilderTy &IRB, Value *Old, Value *V, uint64_t Offset, const Twine &Name)
static bool isVectorPromotionViableForSlice(Partition &P, const Slice &S, VectorType *Ty, uint64_t ElementSize, const DataLayout &DL, unsigned VScale)
Test whether the given slice use can be promoted to a vector.
static Value * getAdjustedPtr(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr, APInt Offset, Type *PointerTy, const Twine &NamePrefix)
Compute an adjusted pointer from Ptr by Offset bytes where the resulting pointer has PointerTy.
static bool isIntegerWideningViableForSlice(const Slice &S, uint64_t AllocBeginOffset, Type *AllocaTy, const DataLayout &DL, bool &WholeAllocaOp)
Test whether a slice of an alloca is valid for integer widening.
static bool rewritePHINodeStore(PHINode &PN, StoreInst &SI, DomTreeUpdater &DTU, SmallSetVector< AllocaInst *, 16 > &Worklist)
Move a store through a pointer PHI onto each of the PHI's incoming edges.
static Value * extractVector(IRBuilderTy &IRB, Value *V, unsigned BeginIndex, unsigned EndIndex, const Twine &Name)
static Value * foldPHINodeOrSelectInst(Instruction &I)
A helper that folds a PHI node or a select.
static bool rewriteSelectInstMemOps(SelectInst &SI, const RewriteableMemOps &Ops, IRBuilderTy &IRB, DomTreeUpdater *DTU)
static Slice * findOverlappingCopySlice(Slice &S, InstructionSliceMap &SliceMap)
Try to find a slice in the map that partially overlaps with S, i.e.
static Value * foldSelectInst(SelectInst &SI)
bool isKillAddress(const DbgVariableRecord *DVR)
static Value * insertVector(IRBuilderTy &IRB, Value *Old, Value *V, unsigned BeginIndex, const Twine &Name)
static bool isIntegerWideningViable(Partition &P, Type *AllocaTy, const DataLayout &DL)
Test whether the given alloca partition's integer operations can be widened to promotable ones.
static void speculatePHINodeLoads(IRBuilderTy &IRB, PHINode &PN)
static VectorType * createAndCheckVectorTypesForPromotion(SetVector< Type * > &OtherTys, ArrayRef< VectorType * > CandidateTysCopy, function_ref< void(Type *)> CheckCandidateType, Partition &P, const DataLayout &DL, SmallVectorImpl< VectorType * > &CandidateTys, bool &HaveCommonEltTy, Type *&CommonEltTy, bool &HaveVecPtrTy, bool &HaveCommonVecPtrTy, VectorType *&CommonVecPtrTy, unsigned VScale)
static DebugVariable getAggregateVariable(DbgVariableRecord *DVR)
static std::tuple< Type *, bool, VectorType * > selectPartitionType(Partition &P, const DataLayout &DL, AllocaInst &AI, LLVMContext &C, bool AggregateToVector)
Select a partition type for an alloca partition.
static bool isSafePHIToSpeculate(PHINode &PN)
PHI instructions that use an alloca and are subsequently loaded can be rewritten to load both input p...
static FixedVectorType * tryCanonicalizeStructToVector(StructType *STy, Partition &P, const DataLayout &DL)
Try to canonicalize a homogeneous struct partition to a vector type.
static Value * extractInteger(const DataLayout &DL, IRBuilderTy &IRB, Value *V, IntegerType *Ty, uint64_t Offset, const Twine &Name)
static void insertNewDbgInst(DIBuilder &DIB, DbgVariableRecord *Orig, AllocaInst *NewAddr, DIExpression *NewAddrExpr, Instruction *BeforeInst, std::optional< DIExpression::FragmentInfo > NewFragment, int64_t BitExtractAdjustment)
Insert a new DbgRecord.
static void speculateSelectInstLoads(SelectInst &SI, LoadInst &LI, IRBuilderTy &IRB)
static Value * mergeTwoVectors(Value *V0, Value *V1, const DataLayout &DL, Type *NewAIEltTy, IRBuilder<> &Builder)
This function takes two vector values and combines them into a single vector by concatenating their e...
const DIExpression * getAddressExpression(const DbgVariableRecord *DVR)
static Type * getTypePartition(const DataLayout &DL, Type *Ty, uint64_t Offset, uint64_t Size)
Try to find a partition of the aggregate type passed in for a given offset and size.
static bool canConvertValue(const DataLayout &DL, Type *OldTy, Type *NewTy, unsigned VScale=0)
Test whether we can convert a value from the old to the new type.
static SelectHandSpeculativity isSafeLoadOfSelectToSpeculate(LoadInst &LI, SelectInst &SI, bool PreserveCFG)
static StoreInst * getPHIStoreToRewrite(PHINode &PN, bool PreserveCFG, DominatorTree &DT)
Check whether a single store through PN can be moved onto each incoming edge.
static Type * findCommonTypeThroughPHIOrSelect(Instruction &I)
Find a common load/store type used through a pointer PHI or select.
This file provides the interface for LLVM's Scalar Replacement of Aggregates pass.
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 SparseBitVector 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 unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type.
virt reg Virtual Register Rewriter
Builder for the alloca slices.
SliceBuilder(const DataLayout &DL, AllocaInst &AI, AllocaSlices &AS)
An iterator over partitions of the alloca's slices.
bool operator==(const partition_iterator &RHS) const
friend class AllocaSlices
partition_iterator & operator++()
SliceSplitter(IRBuilderTy &IRB, const DataLayout &DL, std::vector< uint64_t > &Splits, unsigned SliceSize)
StoreInst * createStore(Value *StoreVal, Value *BasePtr, Iterator &It, Instruction *SplitI)
Slice createSlice(Instruction *I, uint64_t BaseOffset, Iterator &It)
LoadInst * createLoad(Value *BasePtr, Iterator &It, Instruction *SplitI)
Class for arbitrary precision integers.
an instruction to allocate memory on the stack
LLVM_ABI bool isStaticAlloca() const
Return true if this alloca is in the entry block of the function and is a constant size.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
PointerType * getType() const
Overload to return most specific pointer type.
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
A function analysis which provides an AssumptionCache.
An immutable pass that tracks lazily created AssumptionCache objects.
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
LLVM_ABI InstListType::const_iterator getFirstNonPHIOrPseudoProbe() const
Returns an iterator to the first instruction in this block that is not a PHINode or a pseudo operatio...
InstListType::iterator iterator
Instruction iterators...
LLVM_ABI bool canSplitPredecessors() const
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Represents analyses that only rely on functions' control flow.
LLVM_ABI CaptureInfo getCaptureInfo(unsigned OpNo) const
Return which pointer components this operand may capture.
bool onlyReadsMemory(unsigned OpNo) const
bool isDataOperand(const Use *U) const
This is the shared class of boolean and integer constants.
static LLVM_ABI Constant * getAllOnesValue(Type *Ty)
static DIAssignID * getDistinct(LLVMContext &Context)
LLVM_ABI DbgRecord * insertDbgAssign(Instruction *LinkedInstr, Value *Val, DILocalVariable *SrcVar, DIExpression *ValExpr, Value *Addr, DIExpression *AddrExpr, const DILocation *DL)
Insert a new dbg_assign record.
iterator_range< expr_op_iterator > expr_ops() const
DbgVariableFragmentInfo FragmentInfo
LLVM_ABI bool startsWithDeref() const
Return whether the first element a DW_OP_deref.
static LLVM_ABI bool calculateFragmentIntersect(const DataLayout &DL, const Value *SliceStart, uint64_t SliceOffsetInBits, uint64_t SliceSizeInBits, const Value *DbgPtr, int64_t DbgPtrOffsetInBits, int64_t DbgExtractOffsetInBits, DIExpression::FragmentInfo VarFrag, std::optional< DIExpression::FragmentInfo > &Result, int64_t &OffsetFromLocationInBits)
Computes a fragment, bit-extract operation if needed, and new constant offset to describe a part of a...
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...
static LLVM_ABI DIExpression * prepend(const DIExpression *Expr, uint8_t Flags, int64_t Offset=0)
Prepend DIExpr with a deref and offset operation and optionally turn it into a stack value or/and an ...
A parsed version of the target data layout string in and methods for querying it.
LLVM_ABI void moveBefore(DbgRecord *MoveBefore)
DebugLoc getDebugLoc() const
void setDebugLoc(DebugLoc Loc)
Record of a variable value-assignment, aka a non instruction representation of the dbg....
LLVM_ABI void setKillAddress()
Kill the address component.
LLVM_ABI bool isKillLocation() const
LocationType getType() const
LLVM_ABI bool isKillAddress() const
Check whether this kills the address component.
LLVM_ABI void replaceVariableLocationOp(Value *OldValue, Value *NewValue, bool AllowEmpty=false)
Value * getValue(unsigned OpIdx=0) const
static LLVM_ABI DbgVariableRecord * createLinkedDVRAssign(Instruction *LinkedInstr, Value *Val, DILocalVariable *Variable, DIExpression *Expression, Value *Address, DIExpression *AddressExpression, const DILocation *DI)
LLVM_ABI void setAssignId(DIAssignID *New)
DIExpression * getExpression() const
static LLVM_ABI DbgVariableRecord * createDVRDeclare(Value *Address, DILocalVariable *DV, DIExpression *Expr, const DILocation *DI)
static LLVM_ABI DbgVariableRecord * createDbgVariableRecord(Value *Location, DILocalVariable *DV, DIExpression *Expr, const DILocation *DI)
DILocalVariable * getVariable() const
LLVM_ABI void setKillLocation()
bool isDbgDeclare() const
void setAddress(Value *V)
DIExpression * getAddressExpression() const
LLVM_ABI DILocation * getInlinedAt() const
Identifies a unique instance of a variable.
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)
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Analysis pass which computes a DominatorTree.
Legacy 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.
Class to represent fixed width SIMD vectors.
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
FunctionPass class - This class is used to implement most global optimizations.
unsigned getVScaleValue() const
Return the value for vscale based on the vscale_range attribute or 0 when unknown.
const BasicBlock & getEntryBlock() const
LLVM_ABI bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset, function_ref< bool(Value &, APInt &)> ExternalAnalysis=nullptr) const
Accumulate the constant address offset of this GEP if possible.
Value * getPointerOperand()
iterator_range< op_iterator > indices()
Type * getSourceElementType() const
LLVM_ABI GEPNoWrapFlags getNoWrapFlags() const
Get the nowrap flags for the GEP instruction.
This provides the default implementation of the IRBuilder 'InsertHelper' method that is called whenev...
void InsertHelper(Instruction *I, const Twine &Name, BasicBlock::iterator InsertPt) const
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Base class for instruction visitors.
LLVM_ABI unsigned getNumSuccessors() const LLVM_READONLY
Return the number of successors that this instruction has.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI void setAAMetadata(const AAMDNodes &N)
Sets the AA metadata on this instruction from the AAMDNodes structure.
bool hasMetadata() const
Return true if this instruction has any metadata attached to it.
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.
Instruction * user_back()
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
LLVM_ABI bool mayHaveSideEffects() const LLVM_READONLY
Return true if the instruction may have side effects.
LLVM_ABI bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
iterator_range< user_iterator > users()
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
user_iterator user_begin()
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 void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Class to represent integer types.
@ MAX_INT_BITS
Maximum number of bits that can be specified.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
unsigned getPointerAddressSpace() const
Returns the address space of the pointer operand.
void setAlignment(Align Align)
Value * getPointerOperand()
bool isVolatile() const
Return true if this is a load from a volatile memory location.
void setAtomic(AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System)
Sets the ordering constraint and the synchronization scope ID of this load instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this load instruction.
Type * getPointerOperandType() const
static unsigned getPointerOperandIndex()
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this load instruction.
Align getAlign() const
Return the alignment of the access that is being performed.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
LLVMContext & getContext() const
This is the common base class for memset/memcpy/memmove.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
op_range incoming_values()
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
int getBasicBlockIndex(const BasicBlock *BB) const
Return the first index of the specified basic block in the value list for this PHI.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
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 PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
PointerIntPair - This class implements a pair of a pointer and small integer.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
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.
PtrUseVisitor(const DataLayout &DL)
LLVM_ABI SROAPass(SROAOptions Options)
If PreserveCFG is set, then the pass is not allowed to modify CFG in any way, even if it would update...
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Run the pass over the function.
LLVM_ABI void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)
Helper class for SSA formation on a set of values defined in multiple blocks.
This class represents the LLVM 'select' instruction.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
void clear()
Completely clear 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.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
iterator erase(const_iterator CI)
typename SuperClass::const_iterator const_iterator
typename SuperClass::iterator iterator
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool test(unsigned Idx) const
An instruction for storing to memory.
void setAlignment(Align Align)
Value * getValueOperand()
static unsigned getPointerOperandIndex()
Value * getPointerOperand()
void setAtomic(AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System)
Sets the ordering constraint and the synchronization scope ID of this store instruction.
Represent a constant reference to a string, i.e.
static constexpr size_t npos
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
size_t rfind(char C, size_t From=npos) const
Search for the last character C in the string.
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
LLVM_ABI size_t find_first_not_of(char C, size_t From=0) const
Find the first character in the string that is not C or npos if not found.
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
TypeSize getSizeInBytes() const
LLVM_ABI unsigned getElementContainingOffset(uint64_t FixedOffset) const
Given a valid byte offset into the structure, returns the structure index that contains it.
TypeSize getElementOffset(unsigned Idx) const
TypeSize getSizeInBits() const
Class to represent struct types.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
element_iterator element_end() const
ArrayRef< Type * > elements() const
element_iterator element_begin() const
unsigned getNumElements() const
Random access to the elements.
Type * getElementType(unsigned N) const
Type::subtype_iterator element_iterator
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
static constexpr TypeSize getFixed(ScalarTy ExactSize)
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 isSingleValueType() const
Return true if the type is a valid type for a register in codegen.
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
bool isStructTy() const
True if this is an instance of StructType.
bool isTargetExtTy() const
Return true if this is a target extension type.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
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.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
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.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI bool hasOneUser() const
Return true if there is exactly one user of this value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
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 * stripInBoundsOffsets(function_ref< void(const Value *)> Func=[](const Value *) {}) const
Strip off pointer casts and inbounds GEPs.
LLVM_ABI void dropDroppableUsesIn(User &Usr)
Remove every use of this value in User that can safely be removed.
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.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
static VectorType * getWithSizeAndScalar(VectorType *SizeTy, Type *EltTy)
This static method attempts to construct a VectorType with the same size-in-bits as SizeTy but with a...
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
constexpr ScalarTy getFixedValue() const
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
constexpr bool isFixed() const
Returns true if the quantity is not scaled by vscale.
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
CRTP base class which implements the entire standard iterator facade in terms of a minimal subset of ...
A range adaptor for a pair of iterators.
This class implements an extremely fast bulk output stream that can only output to a stream.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char IsVolatile[]
Key for Kernel::Arg::Metadata::mIsVolatile.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
@ BasicBlock
Various leaf nodes.
SmallVector< DbgVariableRecord * > getDVRAssignmentMarkers(const Instruction *Inst)
Return a range of dbg_assign records for which Inst performs the assignment they encode.
LLVM_ABI void deleteAssignmentMarkers(const Instruction *Inst)
Delete the llvm.dbg.assign intrinsics linked to Inst.
@ DW_OP_LLVM_fragment
Only used in LLVM metadata.
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
LLVM_ABI iterator begin() const
unsigned getNumElements(Type *Ty)
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
bool operator<(int64_t V1, const APSInt &V2)
void stable_sort(R &&Range)
LLVM_ABI bool RemoveRedundantDbgInstrs(BasicBlock *BB)
Try to remove redundant dbg.value instructions from given basic block.
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
unsigned getLoadStoreAddressSpace(const Value *I)
A helper function that returns the address space of the pointer operand of load or store instruction.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
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.
LLVM_ABI void PromoteMemToReg(ArrayRef< AllocaInst * > Allocas, DominatorTree &DT, AssumptionCache *AC=nullptr)
Promote the specified list of alloca instructions into scalar registers, inserting PHI nodes as appro...
LLVM_ABI bool isAssumeLikeIntrinsic(const Instruction *I)
Return true if it is an intrinsic that cannot be speculated but also cannot trap.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
bool operator!=(uint64_t V1, const APInt &V2)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
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...
Align getLoadStoreAlignment(const Value *I)
A helper function that returns the alignment of load or store instruction.
const ScalarOptions & getScalarOptions(const LLVMContext &C)
auto unique(Range &&R, Predicate P)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI bool isAllocaPromotable(const AllocaInst *AI)
Return true if this alloca is legal for promotion.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
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.
bool capturesFullProvenance(CaptureComponents CC)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI void SplitBlockAndInsertIfThenElse(Value *Cond, BasicBlock::iterator SplitBefore, Instruction **ThenTerm, Instruction **ElseTerm, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr)
SplitBlockAndInsertIfThenElse is similar to SplitBlockAndInsertIfThen, but also creates the ElseBlock...
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 void initializeSROALegacyPassPass(PassRegistry &)
SmallVector< ValueTypeFromRangeType< R >, Size > to_vector(R &&Range)
Given a range of type R, iterate the entire range and return a SmallVector with elements of the vecto...
LLVM_ABI TinyPtrVector< DbgVariableRecord * > findDVRValues(Value *V)
As above, for DVRValues.
LLVM_ABI void llvm_unreachable_internal(const char *msg=nullptr, const char *file=nullptr, unsigned line=0)
This function calls abort(), and prints the optional message to stderr.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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...
constexpr int PoisonMaskElem
iterator_range(Container &&) -> iterator_range< llvm::detail::IterOfRange< Container > >
LLVM_ABI BasicBlock * SplitBlockPredecessors(BasicBlock *BB, ArrayRef< BasicBlock * > Preds, const char *Suffix, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, bool PreserveLCSSA=false)
This method introduces at least one new basic block into the function and moves some of the predecess...
LLVM_ABI bool isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &Size, const SimplifyQuery &SQ, bool IgnoreFree=false)
Return true if we know that executing a load from this value cannot trap.
LLVM_ABI bool isAssignmentTrackingEnabled(const Module &M)
Return true if assignment tracking is enabled for module M.
DWARFExpression::Operation Op
LLVM_ABI Align tryEnforceAlignment(Value *V, Align PrefAlign, const DataLayout &DL)
If the specified pointer points to an object that we control, try to modify the object's alignment to...
LLVM_ABI FunctionPass * createSROAPass(bool PreserveCFG=true, bool AggregateToVector=false)
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
LLVM_ABI TinyPtrVector< DbgVariableRecord * > findDVRDeclares(Value *V)
Finds dbg.declare records declaring local variables as living in the memory that 'V' points to.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
LLVM_ABI std::optional< Register > getVectorSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI)
bool all_equal(std::initializer_list< T > Values)
Returns true if all Values in the initializer lists are equal or the list.
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 ...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
@ End
Run the machine verifier once, at the end of the pipeline.
LLVM_ABI llvm::SmallVector< int, 16 > createSequentialMask(unsigned Start, unsigned NumInts, unsigned NumUndefs)
Create a sequential shuffle mask.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
An iterator which iterates over the sub-slices that we want to split the slice into.
bool operator==(const Iterator &Other) const
const Iterator & operator*() const
uint64_t getOffset() const
Iterator(SliceSplitter &SS, bool IsEnd)
A collection of metadata nodes that might be associated with a memory access used by the alias-analys...
AAMDNodes shift(size_t Offset) const
Create a new AAMDNode that describes this AAMDNode after applying a constant offset to the start of t...
LLVM_ABI AAMDNodes adjustForAccess(unsigned AccessSize)
Create a new AAMDNode for accessing AccessSize bytes of this AAMDNode.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Describes an element of a Bitfield.
static Bitfield::Type get(StorageType Packed)
Unpacks the field from the Packed value.
static void set(StorageType &Packed, typename Bitfield::Type Value)
Sets the typed value in the provided Packed value.