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(SmallPtrSetImpl<AllocaInst *> &DeletedAllocas);
292 bool promoteAllocas();
306enum FragCalcResult { UseFrag, UseNoFrag,
Skip };
310 uint64_t NewStorageSliceOffsetInBits,
312 std::optional<DIExpression::FragmentInfo> StorageFragment,
313 std::optional<DIExpression::FragmentInfo> CurrentFragment,
317 if (StorageFragment) {
319 std::min(NewStorageSliceSizeInBits, StorageFragment->SizeInBits);
321 NewStorageSliceOffsetInBits + StorageFragment->OffsetInBits;
323 Target.SizeInBits = NewStorageSliceSizeInBits;
324 Target.OffsetInBits = NewStorageSliceOffsetInBits;
330 if (!CurrentFragment) {
331 if (
auto Size = Variable->getSizeInBits()) {
334 if (
Target == CurrentFragment)
341 if (!CurrentFragment || *CurrentFragment ==
Target)
347 if (
Target.startInBits() < CurrentFragment->startInBits() ||
348 Target.endInBits() > CurrentFragment->endInBits())
387 if (DVRAssignMarkerRange.empty())
393 LLVM_DEBUG(
dbgs() <<
" OldAllocaOffsetInBits: " << OldAllocaOffsetInBits
395 LLVM_DEBUG(
dbgs() <<
" SliceSizeInBits: " << SliceSizeInBits <<
"\n");
407 DVR->getExpression()->getFragmentInfo();
420 auto *Expr = DbgAssign->getExpression();
421 bool SetKillLocation =
false;
424 std::optional<DIExpression::FragmentInfo> BaseFragment;
427 if (R == BaseFragments.
end())
429 BaseFragment = R->second;
431 std::optional<DIExpression::FragmentInfo> CurrentFragment =
432 Expr->getFragmentInfo();
435 DbgAssign->getVariable(), OldAllocaOffsetInBits, SliceSizeInBits,
436 BaseFragment, CurrentFragment, NewFragment);
440 if (Result == UseFrag && !(NewFragment == CurrentFragment)) {
441 if (CurrentFragment) {
446 NewFragment.
OffsetInBits -= CurrentFragment->OffsetInBits;
459 SetKillLocation =
true;
467 Inst->
setMetadata(LLVMContext::MD_DIAssignID, NewID);
474 Inst, NewValue, DbgAssign->getVariable(), Expr, Dest,
478 NewAssign = DbgAssign;
497 Value && (DbgAssign->hasArgList() ||
498 !DbgAssign->getExpression()->isSingleLocationExpression());
515 if (NewAssign != DbgAssign) {
516 NewAssign->
moveBefore(DbgAssign->getIterator());
519 LLVM_DEBUG(
dbgs() <<
"Created new assign: " << *NewAssign <<
"\n");
522 for_each(DVRAssignMarkerRange, MigrateDbgAssign);
532 Twine getNameWithPrefix(
const Twine &Name)
const {
537 void SetNamePrefix(
const Twine &
P) { Prefix =
P.str(); }
539 void InsertHelper(Instruction *
I,
const Twine &Name,
564 PointerIntPair<Use *, 1, bool> UseAndIsSplittable;
570 : BeginOffset(BeginOffset), EndOffset(EndOffset),
571 UseAndIsSplittable(
U, IsSplittable) {}
573 uint64_t beginOffset()
const {
return BeginOffset; }
574 uint64_t endOffset()
const {
return EndOffset; }
576 bool isSplittable()
const {
return UseAndIsSplittable.getInt(); }
577 void makeUnsplittable() { UseAndIsSplittable.setInt(
false); }
579 Use *getUse()
const {
return UseAndIsSplittable.getPointer(); }
581 bool isDead()
const {
return getUse() ==
nullptr; }
582 void kill() { UseAndIsSplittable.setPointer(
nullptr); }
591 if (beginOffset() <
RHS.beginOffset())
593 if (beginOffset() >
RHS.beginOffset())
595 if (isSplittable() !=
RHS.isSplittable())
596 return !isSplittable();
597 if (endOffset() >
RHS.endOffset())
604 return LHS.beginOffset() < RHSOffset;
607 return LHSOffset <
RHS.beginOffset();
611 return isSplittable() ==
RHS.isSplittable() &&
612 beginOffset() ==
RHS.beginOffset() && endOffset() ==
RHS.endOffset();
627 AllocaSlices(
const DataLayout &
DL, AllocaInst &AI);
633 bool isEscaped()
const {
return PointerEscapingInstr; }
634 bool isEscapedReadOnly()
const {
return PointerEscapingInstrReadOnly; }
639 using range = iterator_range<iterator>;
641 iterator
begin() {
return Slices.begin(); }
642 iterator
end() {
return Slices.end(); }
646 const_iterator
begin()
const {
return Slices.begin(); }
647 const_iterator
end()
const {
return Slices.end(); }
651 void erase(iterator Start, iterator Stop) { Slices.erase(Start, Stop); }
659 int OldSize = Slices.size();
660 Slices.append(NewSlices.
begin(), NewSlices.
end());
661 auto SliceI = Slices.begin() + OldSize;
662 std::stable_sort(SliceI, Slices.end());
663 std::inplace_merge(Slices.begin(), SliceI, Slices.end());
672 ArrayRef<Instruction *> getDeadUsers()
const {
return DeadUsers; }
676 return DeadUseIfPromotable;
687#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
688 void print(raw_ostream &OS, const_iterator
I, StringRef Indent =
" ")
const;
689 void printSlice(raw_ostream &OS, const_iterator
I,
690 StringRef Indent =
" ")
const;
691 void printUse(raw_ostream &OS, const_iterator
I,
692 StringRef Indent =
" ")
const;
693 void print(raw_ostream &OS)
const;
694 void dump(const_iterator
I)
const;
701 friend class AllocaSlices::SliceBuilder;
703#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
731 SmallVector<Instruction *, 8> DeadUsers;
758 friend class AllocaSlices;
759 friend class AllocaSlices::partition_iterator;
761 using iterator = AllocaSlices::iterator;
765 uint64_t BeginOffset = 0, EndOffset = 0;
775 Partition(iterator SI) : SI(SI), SJ(SI) {}
781 uint64_t beginOffset()
const {
return BeginOffset; }
786 uint64_t endOffset()
const {
return EndOffset; }
792 assert(BeginOffset < EndOffset &&
"Partitions must span some bytes!");
793 return EndOffset - BeginOffset;
798 bool empty()
const {
return SI == SJ; }
809 iterator
begin()
const {
return SI; }
810 iterator
end()
const {
return SJ; }
842 AllocaSlices::iterator SE;
846 uint64_t MaxSplitSliceEndOffset = 0;
850 partition_iterator(AllocaSlices::iterator
SI, AllocaSlices::iterator SE)
862 assert((
P.SI != SE || !
P.SplitTails.empty()) &&
863 "Cannot advance past the end of the slices!");
866 if (!
P.SplitTails.empty()) {
867 if (
P.EndOffset >= MaxSplitSliceEndOffset) {
869 P.SplitTails.clear();
870 MaxSplitSliceEndOffset = 0;
876 [&](Slice *S) { return S->endOffset() <= P.EndOffset; });
879 return S->endOffset() == MaxSplitSliceEndOffset;
881 "Could not find the current max split slice offset!");
884 return S->endOffset() <= MaxSplitSliceEndOffset;
886 "Max split slice end offset is not actually the max!");
893 assert(P.SplitTails.empty() &&
"Failed to clear the split slices!");
903 if (S.isSplittable() && S.endOffset() > P.EndOffset) {
904 P.SplitTails.push_back(&S);
905 MaxSplitSliceEndOffset =
906 std::max(S.endOffset(), MaxSplitSliceEndOffset);
914 P.BeginOffset = P.EndOffset;
915 P.EndOffset = MaxSplitSliceEndOffset;
922 if (!P.SplitTails.empty() && P.SI->beginOffset() != P.EndOffset &&
923 !P.SI->isSplittable()) {
924 P.BeginOffset = P.EndOffset;
925 P.EndOffset = P.SI->beginOffset();
935 P.BeginOffset = P.SplitTails.empty() ? P.SI->beginOffset() : P.EndOffset;
936 P.EndOffset = P.SI->endOffset();
941 if (!P.SI->isSplittable()) {
944 assert(P.BeginOffset == P.SI->beginOffset());
948 while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) {
949 if (!P.SJ->isSplittable())
950 P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset());
962 assert(P.SI->isSplittable() &&
"Forming a splittable partition!");
965 while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset &&
966 P.SJ->isSplittable()) {
967 P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset());
974 if (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) {
975 assert(!P.SJ->isSplittable());
976 P.EndOffset = P.SJ->beginOffset();
983 "End iterators don't match between compared partition iterators!");
990 if (P.SI == RHS.P.SI && P.SplitTails.empty() == RHS.P.SplitTails.empty()) {
991 assert(P.SJ == RHS.P.SJ &&
992 "Same set of slices formed two different sized partitions!");
993 assert(P.SplitTails.size() == RHS.P.SplitTails.size() &&
994 "Same slice position with differently sized non-empty split "
1017 return make_range(partition_iterator(begin(), end()),
1018 partition_iterator(end(), end()));
1026 return SI.getOperand(1 + CI->isZero());
1027 if (
SI.getOperand(1) ==
SI.getOperand(2))
1028 return SI.getOperand(1);
1037 return PN->hasConstantValue();
1052 const uint64_t AllocSize;
1068 if (VisitedDeadInsts.
insert(&
I).second)
1073 bool IsSplittable =
false) {
1079 <<
" which has zero size or starts outside of the "
1080 << AllocSize <<
" byte alloca:\n"
1081 <<
" alloca: " << AS.AI <<
"\n"
1082 <<
" use: " <<
I <<
"\n");
1083 return markAsDead(
I);
1095 assert(AllocSize >= BeginOffset);
1096 if (
Size > AllocSize - BeginOffset) {
1098 <<
Offset <<
" to remain within the " << AllocSize
1099 <<
" byte alloca:\n"
1100 <<
" alloca: " << AS.AI <<
"\n"
1101 <<
" use: " <<
I <<
"\n");
1102 EndOffset = AllocSize;
1105 AS.Slices.push_back(Slice(BeginOffset, EndOffset, U, IsSplittable));
1108 void visitBitCastInst(BitCastInst &BC) {
1110 return markAsDead(BC);
1112 return Base::visitBitCastInst(BC);
1115 void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
1117 return markAsDead(ASC);
1119 return Base::visitAddrSpaceCastInst(ASC);
1122 void visitGetElementPtrInst(GetElementPtrInst &GEPI) {
1124 return markAsDead(GEPI);
1126 return Base::visitGetElementPtrInst(GEPI);
1129 void handleLoadOrStore(
Type *Ty, Instruction &
I,
const APInt &
Offset,
1140 void visitLoadInst(LoadInst &LI) {
1142 "All simple FCA loads should have been pre-split");
1147 return PI.setEscapedReadOnly(&LI);
1150 if (
Size.isScalable()) {
1153 return PI.setAborted(&LI);
1162 void visitStoreInst(StoreInst &SI) {
1163 Value *ValOp =
SI.getValueOperand();
1165 return PI.setEscapedAndAborted(&SI);
1167 return PI.setAborted(&SI);
1169 TypeSize StoreSize =
DL.getTypeStoreSize(ValOp->
getType());
1171 unsigned VScale =
SI.getFunction()->getVScaleValue();
1173 return PI.setAborted(&SI);
1189 <<
Offset <<
" which extends past the end of the "
1190 << AllocSize <<
" byte alloca:\n"
1191 <<
" alloca: " << AS.AI <<
"\n"
1192 <<
" use: " << SI <<
"\n");
1193 return markAsDead(SI);
1197 "All simple FCA stores should have been pre-split");
1201 void visitMemSetInst(MemSetInst &
II) {
1202 assert(
II.getRawDest() == *U &&
"Pointer use is not the destination?");
1205 (IsOffsetKnown &&
Offset.uge(AllocSize)))
1207 return markAsDead(
II);
1210 return PI.setAborted(&
II);
1214 : AllocSize -
Offset.getLimitedValue(),
1218 void visitMemTransferInst(MemTransferInst &
II) {
1222 return markAsDead(
II);
1226 if (VisitedDeadInsts.
count(&
II))
1230 return PI.setAborted(&
II);
1237 if (
Offset.uge(AllocSize)) {
1238 auto MTPI = MemTransferSliceMap.
find(&
II);
1239 if (MTPI != MemTransferSliceMap.
end())
1240 AS.Slices[MTPI->second].kill();
1241 return markAsDead(
II);
1249 if (*U ==
II.getRawDest() && *U ==
II.getRawSource()) {
1251 if (!
II.isVolatile())
1252 return markAsDead(
II);
1260 SmallDenseMap<Instruction *, unsigned>::iterator MTPI;
1261 std::tie(MTPI, Inserted) =
1262 MemTransferSliceMap.
insert(std::make_pair(&
II, AS.Slices.size()));
1263 unsigned PrevIdx = MTPI->second;
1265 Slice &PrevP = AS.Slices[PrevIdx];
1269 if (!
II.isVolatile() && PrevP.beginOffset() == RawOffset) {
1271 return markAsDead(
II);
1276 PrevP.makeUnsplittable();
1283 assert(AS.Slices[PrevIdx].getUse()->getUser() == &
II &&
1284 "Map index doesn't point back to a slice with this user.");
1290 void visitIntrinsicInst(IntrinsicInst &
II) {
1291 if (
II.isDroppable()) {
1292 AS.DeadUseIfPromotable.push_back(U);
1297 return PI.setAborted(&
II);
1299 if (
II.isLifetimeStartOrEnd()) {
1300 insertUse(
II,
Offset, AllocSize,
true);
1304 Base::visitIntrinsicInst(
II);
1312 SmallPtrSet<Instruction *, 4> Visited;
1322 std::tie(UsedI,
I) =
Uses.pop_back_val();
1325 TypeSize LoadSize =
DL.getTypeStoreSize(LI->
getType());
1337 TypeSize StoreSize =
DL.getTypeStoreSize(
Op->getType());
1347 if (!
GEP->hasAllZeroIndices())
1354 for (User *U :
I->users())
1357 }
while (!
Uses.empty());
1362 void visitPHINodeOrSelectInst(Instruction &
I) {
1365 return markAsDead(
I);
1371 return PI.setAborted(&
I);
1389 AS.DeadOperands.push_back(U);
1395 return PI.setAborted(&
I);
1401 if (Instruction *UnsafeI = hasUnsafePHIOrSelectUse(&
I,
Size))
1402 return PI.setAborted(UnsafeI);
1411 if (
Offset.uge(AllocSize)) {
1412 AS.DeadOperands.push_back(U);
1419 void visitPHINode(PHINode &PN) { visitPHINodeOrSelectInst(PN); }
1421 void visitSelectInst(SelectInst &SI) { visitPHINodeOrSelectInst(SI); }
1424 void visitInstruction(Instruction &
I) { PI.setAborted(&
I); }
1426 void visitCallBase(CallBase &CB) {
1432 PI.setEscapedReadOnly(&CB);
1436 Base::visitCallBase(CB);
1440AllocaSlices::AllocaSlices(
const DataLayout &
DL, AllocaInst &AI)
1442#
if !defined(
NDEBUG) || defined(LLVM_ENABLE_DUMP)
1445 PointerEscapingInstr(nullptr), PointerEscapingInstrReadOnly(nullptr) {
1447 SliceBuilder::PtrInfo PtrI =
PB.visitPtr(AI);
1448 if (PtrI.isEscaped() || PtrI.isAborted()) {
1451 PointerEscapingInstr = PtrI.getEscapingInst() ? PtrI.getEscapingInst()
1452 : PtrI.getAbortingInst();
1453 assert(PointerEscapingInstr &&
"Did not track a bad instruction");
1456 PointerEscapingInstrReadOnly = PtrI.getEscapedReadOnlyInst();
1458 llvm::erase_if(Slices, [](
const Slice &S) {
return S.isDead(); });
1465#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1467void AllocaSlices::print(raw_ostream &OS, const_iterator
I,
1468 StringRef Indent)
const {
1469 printSlice(OS,
I, Indent);
1471 printUse(OS,
I, Indent);
1474void AllocaSlices::printSlice(raw_ostream &OS, const_iterator
I,
1475 StringRef Indent)
const {
1476 OS << Indent <<
"[" <<
I->beginOffset() <<
"," <<
I->endOffset() <<
")"
1477 <<
" slice #" << (
I -
begin())
1478 << (
I->isSplittable() ?
" (splittable)" :
"");
1481void AllocaSlices::printUse(raw_ostream &OS, const_iterator
I,
1482 StringRef Indent)
const {
1483 OS << Indent <<
" used by: " << *
I->getUse()->getUser() <<
"\n";
1486void AllocaSlices::print(raw_ostream &OS)
const {
1487 if (PointerEscapingInstr) {
1488 OS <<
"Can't analyze slices for alloca: " << AI <<
"\n"
1489 <<
" A pointer to this alloca escaped by:\n"
1490 <<
" " << *PointerEscapingInstr <<
"\n";
1494 if (PointerEscapingInstrReadOnly)
1495 OS <<
"Escapes into ReadOnly: " << *PointerEscapingInstrReadOnly <<
"\n";
1497 OS <<
"Slices of alloca: " << AI <<
"\n";
1518 for (
User *U :
I.users()) {
1519 Type *UserTy =
nullptr;
1525 UserTy =
Store->getValueOperand()->getType();
1527 if (!UserTy || (Ty && Ty != UserTy))
1537static std::pair<Type *, IntegerType *>
1541 bool TyIsCommon =
true;
1546 for (AllocaSlices::const_iterator
I =
B;
I !=
E; ++
I) {
1547 Use *U =
I->getUse();
1550 if (
I->beginOffset() !=
B->beginOffset() ||
I->endOffset() != EndOffset)
1553 Type *UserTy =
nullptr;
1557 UserTy =
SI->getValueOperand()->getType();
1568 if (UserITy->getBitWidth() % 8 != 0 ||
1569 UserITy->getBitWidth() / 8 > (EndOffset -
B->beginOffset()))
1574 if (!ITy || ITy->
getBitWidth() < UserITy->getBitWidth())
1580 if (!UserTy || (Ty && Ty != UserTy))
1586 return {TyIsCommon ? Ty :
nullptr, ITy};
1616 Type *LoadType =
nullptr;
1629 if (LoadType != LI->
getType())
1638 if (BBI->mayWriteToMemory())
1641 MaxAlign = std::max(MaxAlign, LI->
getAlign());
1648 APInt(APWidth,
DL.getTypeStoreSize(LoadType).getFixedValue());
1691 if (!
SI ||
SI->getPointerOperand() != &PN)
1694 if (
SI->isVolatile())
1702 Value *StoredValue =
SI->getValueOperand();
1708 if (!SeenPreds.
insert(Pred).second)
1741 IRB.SetInsertPoint(&PN);
1743 PN.
getName() +
".sroa.speculated");
1773 IRB.SetInsertPoint(TI);
1776 LoadTy, InVal, Alignment,
1777 (PN.
getName() +
".sroa.speculate.load." + Pred->getName()));
1778 ++NumLoadsSpeculated;
1780 Load->setAAMetadata(AATags);
1782 InjectedLoads[Pred] =
Load;
1794 <<
" " <<
SI <<
"\n");
1802 if (!SeenPreds.
insert(Pred).second)
1812 bool CFGChanged =
false;
1814 for (
auto [Pred, InVal] : IncomingValues) {
1816 if (Pred->getTerminator()->getNumSuccessors() != 1) {
1818 assert(StoreBB &&
"store edge was not checked for splitting");
1825 ++NumStoresPredicated;
1829 SI.eraseFromParent();
1834SelectHandSpeculativity &
1835SelectHandSpeculativity::setAsSpeculatable(
bool isTrueVal) {
1843bool SelectHandSpeculativity::isSpeculatable(
bool isTrueVal)
const {
1848bool SelectHandSpeculativity::areAllSpeculatable()
const {
1849 return isSpeculatable(
true) &&
1850 isSpeculatable(
false);
1853bool SelectHandSpeculativity::areAnySpeculatable()
const {
1854 return isSpeculatable(
true) ||
1855 isSpeculatable(
false);
1857bool SelectHandSpeculativity::areNoneSpeculatable()
const {
1858 return !areAnySpeculatable();
1861static SelectHandSpeculativity
1864 SelectHandSpeculativity
Spec;
1870 Spec.setAsSpeculatable(
Value ==
SI.getTrueValue());
1871 else if (PreserveCFG)
1877std::optional<RewriteableMemOps>
1878SROA::isSafeSelectToSpeculateOrPredicate(SelectInst &SI,
bool PreserveCFG) {
1879 RewriteableMemOps
Ops;
1882 for (User *U :
SI.users()) {
1889 for (User *U :
Users) {
1892 if (
Store->isVolatile() || PreserveCFG)
1903 PossiblySpeculatableLoad
Load(LI);
1918 SelectHandSpeculativity Spec =
1920 if (PreserveCFG && !Spec.areAllSpeculatable())
1934 Value *TV =
SI.getTrueValue();
1935 Value *FV =
SI.getFalseValue();
1940 IRB.SetInsertPoint(&LI);
1944 LI.
getName() +
".sroa.speculate.cast.true");
1946 LI.
getName() +
".sroa.speculate.cast.false");
1950 LI.
getName() +
".sroa.speculate.load.true");
1953 LI.
getName() +
".sroa.speculate.load.false");
1954 NumLoadsSpeculated += 2;
1966 Value *V = IRB.CreateSelect(
SI.getCondition(), TL, FL,
1967 LI.
getName() +
".sroa.speculated", &
SI);
1973template <
typename T>
1975 SelectHandSpeculativity
Spec, IRBuilderTy &IRB,
1982 if (
Spec.areNoneSpeculatable())
1984 SI.getMetadata(LLVMContext::MD_prof), &DTU);
1987 SI.getMetadata(LLVMContext::MD_prof), &DTU,
1989 if (
Spec.isSpeculatable(
true))
1995 Tail->setName(Head->
getName() +
".cont");
2000 bool IsThen = SuccBB == HeadBI->getSuccessor(0);
2001 int SuccIdx = IsThen ? 0 : 1;
2002 auto *NewMemOpBB = SuccBB == Tail ? Head : SuccBB;
2003 auto &CondMemOp =
cast<T>(*
I.clone());
2004 if (NewMemOpBB != Head) {
2005 NewMemOpBB->setName(Head->
getName() + (IsThen ?
".then" :
".else"));
2007 ++NumLoadsPredicated;
2009 ++NumStoresPredicated;
2011 CondMemOp.dropUBImplyingAttrsAndMetadata();
2012 ++NumLoadsSpeculated;
2014 CondMemOp.insertBefore(NewMemOpBB->getTerminator()->getIterator());
2015 Value *Ptr =
SI.getOperand(1 + SuccIdx);
2018 IRB.SetInsertPoint(&CondMemOp);
2019 Ptr = IRB.CreateAddrSpaceCast(Ptr,
I.getPointerOperandType(),
2020 I.getName() + (IsThen ?
".then" :
".else") +
2022 CondMemOp.setOperand(
I.getPointerOperandIndex(), Ptr);
2024 CondMemOp.setName(
I.getName() + (IsThen ?
".then" :
".else") +
".val");
2032 I.replaceAllUsesWith(PN);
2037 SelectHandSpeculativity
Spec, IRBuilderTy &IRB,
2048 const RewriteableMemOps &
Ops,
2050 bool CFGChanged =
false;
2053 for (
const RewriteableMemOp &
Op :
Ops) {
2054 SelectHandSpeculativity
Spec;
2056 if (
auto *
const *US = std::get_if<UnspeculatableStore>(&
Op)) {
2059 auto PSL = std::get<PossiblySpeculatableLoad>(
Op);
2060 I = PSL.getPointer();
2061 Spec = PSL.getInt();
2063 if (
Spec.areAllSpeculatable()) {
2066 assert(DTU &&
"Should not get here when not allowed to modify the CFG!");
2070 I->eraseFromParent();
2075 SI.eraseFromParent();
2083 const Twine &NamePrefix) {
2085 Ptr = IRB.CreateInBoundsPtrAdd(Ptr, IRB.getInt(
Offset),
2086 NamePrefix +
"sroa_idx");
2087 return IRB.CreatePointerBitCastOrAddrSpaceCast(Ptr,
PointerTy,
2088 NamePrefix +
"sroa_cast");
2103 unsigned VScale = 0) {
2113 "We can't have the same bitwidth for different int types");
2117 TypeSize NewSize =
DL.getTypeSizeInBits(NewTy);
2118 TypeSize OldSize =
DL.getTypeSizeInBits(OldTy);
2145 if (NewSize != OldSize)
2161 return OldAS == NewAS ||
2162 (!
DL.isNonIntegralAddressSpace(OldAS) &&
2163 !
DL.isNonIntegralAddressSpace(NewAS) &&
2164 DL.getPointerSize(OldAS) ==
DL.getPointerSize(NewAS));
2170 return !
DL.isNonIntegralPointerType(NewTy);
2174 if (!
DL.isNonIntegralPointerType(OldTy))
2197 std::max(S.beginOffset(),
P.beginOffset()) -
P.beginOffset();
2198 uint64_t BeginIndex = BeginOffset / ElementSize;
2199 if (BeginIndex * ElementSize != BeginOffset ||
2202 uint64_t EndOffset = std::min(S.endOffset(),
P.endOffset()) -
P.beginOffset();
2203 uint64_t EndIndex = EndOffset / ElementSize;
2204 if (EndIndex * ElementSize != EndOffset ||
2208 assert(EndIndex > BeginIndex &&
"Empty vector!");
2209 uint64_t NumElements = EndIndex - BeginIndex;
2210 Type *SliceTy = (NumElements == 1)
2211 ? Ty->getElementType()
2217 Use *U = S.getUse();
2220 if (
MI->isVolatile())
2222 if (!S.isSplittable())
2230 if (!
II->isLifetimeStartOrEnd() && !
II->isDroppable())
2237 if (LTy->isStructTy())
2239 if (
P.beginOffset() > S.beginOffset() ||
P.endOffset() < S.endOffset()) {
2240 assert(LTy->isIntegerTy());
2246 if (
SI->isVolatile())
2248 Type *STy =
SI->getValueOperand()->getType();
2252 if (
P.beginOffset() > S.beginOffset() ||
P.endOffset() < S.endOffset()) {
2272 bool HaveCommonEltTy,
Type *CommonEltTy,
2273 bool HaveVecPtrTy,
bool HaveCommonVecPtrTy,
2274 VectorType *CommonVecPtrTy,
unsigned VScale) {
2276 if (CandidateTys.
empty())
2283 if (HaveVecPtrTy && !HaveCommonVecPtrTy)
2287 if (!HaveCommonEltTy && HaveVecPtrTy) {
2289 CandidateTys.
clear();
2291 }
else if (!HaveCommonEltTy && !HaveVecPtrTy) {
2294 if (!VTy->getElementType()->isIntegerTy())
2296 VTy->getContext(), VTy->getScalarSizeInBits())));
2303 assert(
DL.getTypeSizeInBits(RHSTy).getFixedValue() ==
2304 DL.getTypeSizeInBits(LHSTy).getFixedValue() &&
2305 "Cannot have vector types of different sizes!");
2306 assert(RHSTy->getElementType()->isIntegerTy() &&
2307 "All non-integer types eliminated!");
2308 assert(LHSTy->getElementType()->isIntegerTy() &&
2309 "All non-integer types eliminated!");
2315 assert(
DL.getTypeSizeInBits(RHSTy).getFixedValue() ==
2316 DL.getTypeSizeInBits(LHSTy).getFixedValue() &&
2317 "Cannot have vector types of different sizes!");
2318 assert(RHSTy->getElementType()->isIntegerTy() &&
2319 "All non-integer types eliminated!");
2320 assert(LHSTy->getElementType()->isIntegerTy() &&
2321 "All non-integer types eliminated!");
2325 llvm::sort(CandidateTys, RankVectorTypesComp);
2326 CandidateTys.erase(
llvm::unique(CandidateTys, RankVectorTypesEq),
2327 CandidateTys.end());
2333 assert(VTy->getElementType() == CommonEltTy &&
2334 "Unaccounted for element type!");
2335 assert(VTy == CandidateTys[0] &&
2336 "Different vector types with the same element type!");
2339 CandidateTys.resize(1);
2346 std::numeric_limits<unsigned short>::max();
2352 DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
2356 if (ElementSize % 8)
2358 assert((
DL.getTypeSizeInBits(VTy).getFixedValue() % 8) == 0 &&
2359 "vector size not a multiple of element size?");
2362 for (
const Slice &S :
P)
2366 for (
const Slice *S :
P.splitSliceTails())
2372 return VTy != CandidateTys.
end() ? *VTy :
nullptr;
2379 bool &HaveCommonEltTy,
Type *&CommonEltTy,
bool &HaveVecPtrTy,
2380 bool &HaveCommonVecPtrTy,
VectorType *&CommonVecPtrTy,
unsigned VScale) {
2382 CandidateTysCopy.
size() ? CandidateTysCopy[0] :
nullptr;
2385 for (
Type *Ty : OtherTys) {
2388 unsigned TypeSize =
DL.getTypeSizeInBits(Ty).getFixedValue();
2391 for (
VectorType *
const VTy : CandidateTysCopy) {
2393 assert(CandidateTysCopy[0] == OriginalElt &&
"Different Element");
2394 unsigned VectorSize =
DL.getTypeSizeInBits(VTy).getFixedValue();
2395 unsigned ElementSize =
2396 DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
2400 CheckCandidateType(NewVTy);
2406 P,
DL, CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
2407 HaveCommonVecPtrTy, CommonVecPtrTy, VScale);
2426 Type *CommonEltTy =
nullptr;
2428 bool HaveVecPtrTy =
false;
2429 bool HaveCommonEltTy =
true;
2430 bool HaveCommonVecPtrTy =
true;
2431 auto CheckCandidateType = [&](
Type *Ty) {
2434 if (!CandidateTys.
empty()) {
2436 if (
DL.getTypeSizeInBits(VTy).getFixedValue() !=
2437 DL.getTypeSizeInBits(V).getFixedValue()) {
2438 CandidateTys.
clear();
2443 Type *EltTy = VTy->getElementType();
2446 CommonEltTy = EltTy;
2447 else if (CommonEltTy != EltTy)
2448 HaveCommonEltTy =
false;
2451 HaveVecPtrTy =
true;
2452 if (!CommonVecPtrTy)
2453 CommonVecPtrTy = VTy;
2454 else if (CommonVecPtrTy != VTy)
2455 HaveCommonVecPtrTy =
false;
2461 for (
const Slice &S :
P) {
2466 Ty =
SI->getValueOperand()->getType();
2470 auto CandTy = Ty->getScalarType();
2471 if (CandTy->isPointerTy() && (S.beginOffset() !=
P.beginOffset() ||
2472 S.endOffset() !=
P.endOffset())) {
2479 if (S.beginOffset() ==
P.beginOffset() && S.endOffset() ==
P.endOffset())
2480 CheckCandidateType(Ty);
2485 LoadStoreTys, CandidateTysCopy, CheckCandidateType,
P,
DL,
2486 CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
2487 HaveCommonVecPtrTy, CommonVecPtrTy, VScale))
2490 CandidateTys.
clear();
2492 DeferredTys, CandidateTysCopy, CheckCandidateType,
P,
DL, CandidateTys,
2493 HaveCommonEltTy, CommonEltTy, HaveVecPtrTy, HaveCommonVecPtrTy,
2494 CommonVecPtrTy, VScale);
2505 bool &WholeAllocaOp) {
2508 uint64_t RelBegin = S.beginOffset() - AllocBeginOffset;
2509 uint64_t RelEnd = S.endOffset() - AllocBeginOffset;
2511 Use *U = S.getUse();
2518 if (
II->isLifetimeStartOrEnd() ||
II->isDroppable())
2536 if (S.beginOffset() < AllocBeginOffset)
2542 WholeAllocaOp =
true;
2544 if (ITy->getBitWidth() <
DL.getTypeStoreSizeInBits(ITy).getFixedValue())
2546 }
else if (RelBegin != 0 || RelEnd !=
Size ||
2553 Type *ValueTy =
SI->getValueOperand()->getType();
2554 if (
SI->isVolatile())
2557 TypeSize StoreSize =
DL.getTypeStoreSize(ValueTy);
2562 if (S.beginOffset() < AllocBeginOffset)
2568 WholeAllocaOp =
true;
2570 if (ITy->getBitWidth() <
DL.getTypeStoreSizeInBits(ITy).getFixedValue())
2572 }
else if (RelBegin != 0 || RelEnd !=
Size ||
2581 if (!S.isSplittable())
2598 uint64_t SizeInBits =
DL.getTypeSizeInBits(AllocaTy).getFixedValue();
2604 if (SizeInBits !=
DL.getTypeStoreSizeInBits(AllocaTy).getFixedValue())
2622 bool WholeAllocaOp =
P.empty() &&
DL.isLegalInteger(SizeInBits);
2624 for (
const Slice &S :
P)
2629 for (
const Slice *S :
P.splitSliceTails())
2634 return WholeAllocaOp;
2639 const Twine &Name) {
2643 DL.getTypeStoreSize(IntTy).getFixedValue() &&
2644 "Element extends past full value");
2646 if (
DL.isBigEndian())
2647 ShAmt = 8 * (
DL.getTypeStoreSize(IntTy).getFixedValue() -
2648 DL.getTypeStoreSize(Ty).getFixedValue() -
Offset);
2650 V = IRB.CreateLShr(V, ShAmt, Name +
".shift");
2653 assert(Ty->getBitWidth() <= IntTy->getBitWidth() &&
2654 "Cannot extract to a larger integer!");
2656 V = IRB.CreateTrunc(V, Ty, Name +
".trunc");
2666 assert(Ty->getBitWidth() <= IntTy->getBitWidth() &&
2667 "Cannot insert a larger integer!");
2670 V = IRB.CreateZExt(V, IntTy, Name +
".ext");
2674 DL.getTypeStoreSize(IntTy).getFixedValue() &&
2675 "Element store outside of alloca store");
2677 if (
DL.isBigEndian())
2678 ShAmt = 8 * (
DL.getTypeStoreSize(IntTy).getFixedValue() -
2679 DL.getTypeStoreSize(Ty).getFixedValue() -
Offset);
2681 V = IRB.CreateShl(V, ShAmt, Name +
".shift");
2685 if (ShAmt || Ty->getBitWidth() < IntTy->getBitWidth()) {
2686 APInt Mask = ~Ty->getMask().zext(IntTy->getBitWidth()).shl(ShAmt);
2687 Old = IRB.CreateAnd(Old, Mask, Name +
".mask");
2689 V = IRB.CreateOr(Old, V, Name +
".insert");
2696 unsigned EndIndex,
const Twine &Name) {
2698 unsigned NumElements = EndIndex - BeginIndex;
2699 assert(NumElements <= VecTy->getNumElements() &&
"Too many elements!");
2701 if (NumElements == VecTy->getNumElements())
2704 if (NumElements == 1) {
2705 V = IRB.CreateExtractElement(V, BeginIndex, Name +
".extract");
2711 V = IRB.CreateShuffleVector(V, Mask, Name +
".extract");
2717 unsigned BeginIndex,
const Twine &Name) {
2719 assert(VecTy &&
"Can only insert a vector into a vector");
2724 V = IRB.CreateInsertElement(Old, V, BeginIndex, Name +
".insert");
2732 assert(NumSubElements <= NumElements &&
"Too many elements!");
2733 if (NumSubElements == NumElements) {
2734 assert(V->getType() == VecTy &&
"Vector type mismatch");
2737 unsigned EndIndex = BeginIndex + NumSubElements;
2744 Mask.reserve(NumElements);
2745 for (
unsigned Idx = 0; Idx != NumElements; ++Idx)
2746 if (Idx >= BeginIndex && Idx < EndIndex)
2747 Mask.push_back(Idx - BeginIndex);
2750 V = IRB.CreateShuffleVector(V, Mask, Name +
".expand");
2754 for (
unsigned Idx = 0; Idx != NumElements; ++Idx)
2755 if (Idx >= BeginIndex && Idx < EndIndex)
2756 Mask.push_back(Idx);
2758 Mask.push_back(Idx + NumElements);
2759 V = IRB.CreateShuffleVector(V, Old, Mask, Name +
"blend");
2798 const char *DebugName) {
2799 Type *EltType = VecType->getElementType();
2800 if (EltType != NewAIEltTy) {
2802 unsigned TotalBits =
2803 VecType->getNumElements() *
DL.getTypeSizeInBits(EltType);
2804 unsigned NewNumElts = TotalBits /
DL.getTypeSizeInBits(NewAIEltTy);
2807 V = Builder.CreateBitCast(V, NewVecType);
2808 VecType = NewVecType;
2809 LLVM_DEBUG(
dbgs() <<
" bitcast " << DebugName <<
": " << *V <<
"\n");
2813 BitcastIfNeeded(V0, VecType0,
"V0");
2814 BitcastIfNeeded(
V1, VecType1,
"V1");
2816 unsigned NumElts0 = VecType0->getNumElements();
2817 unsigned NumElts1 = VecType1->getNumElements();
2821 if (NumElts0 == NumElts1) {
2822 for (
unsigned i = 0; i < NumElts0 + NumElts1; ++i)
2823 ShuffleMask.push_back(i);
2827 unsigned SmallSize = std::min(NumElts0, NumElts1);
2828 unsigned LargeSize = std::max(NumElts0, NumElts1);
2829 bool IsV0Smaller = NumElts0 < NumElts1;
2830 Value *&ExtendedVec = IsV0Smaller ? V0 :
V1;
2832 for (
unsigned i = 0; i < SmallSize; ++i)
2834 for (
unsigned i = SmallSize; i < LargeSize; ++i)
2836 ExtendedVec = Builder.CreateShuffleVector(
2838 LLVM_DEBUG(
dbgs() <<
" shufflevector: " << *ExtendedVec <<
"\n");
2839 for (
unsigned i = 0; i < NumElts0; ++i)
2840 ShuffleMask.push_back(i);
2841 for (
unsigned i = 0; i < NumElts1; ++i)
2842 ShuffleMask.push_back(LargeSize + i);
2845 return Builder.CreateShuffleVector(V0,
V1, ShuffleMask);
2856class AllocaSliceRewriter :
public InstVisitor<AllocaSliceRewriter, bool> {
2858 friend class InstVisitor<AllocaSliceRewriter, bool>;
2860 using Base = InstVisitor<AllocaSliceRewriter, bool>;
2862 const DataLayout &
DL;
2865 AllocaInst &OldAI, &NewAI;
2866 const uint64_t NewAllocaBeginOffset, NewAllocaEndOffset;
2895 uint64_t NewBeginOffset = 0, NewEndOffset = 0;
2898 bool IsSplittable =
false;
2899 bool IsSplit =
false;
2900 Use *OldUse =
nullptr;
2904 SmallSetVector<PHINode *, 8> &PHIUsers;
2905 SmallSetVector<SelectInst *, 8> &SelectUsers;
2913 Value *getPtrToNewAI(
unsigned AddrSpace,
bool IsVolatile) {
2917 Type *AccessTy = IRB.getPtrTy(AddrSpace);
2918 return IRB.CreateAddrSpaceCast(&NewAI, AccessTy);
2922 AllocaSliceRewriter(
const DataLayout &
DL, AllocaSlices &AS, SROA &
Pass,
2923 AllocaInst &OldAI, AllocaInst &NewAI,
Type *NewAllocaTy,
2925 uint64_t NewAllocaEndOffset,
bool IsIntegerPromotable,
2926 VectorType *PromotableVecTy,
2927 SmallSetVector<PHINode *, 8> &PHIUsers,
2928 SmallSetVector<SelectInst *, 8> &SelectUsers)
2929 :
DL(
DL), AS(AS),
Pass(
Pass), OldAI(OldAI), NewAI(NewAI),
2930 NewAllocaBeginOffset(NewAllocaBeginOffset),
2931 NewAllocaEndOffset(NewAllocaEndOffset), NewAllocaTy(NewAllocaTy),
2932 IntTy(IsIntegerPromotable
2935 DL.getTypeSizeInBits(NewAllocaTy).getFixedValue())
2937 VecTy(PromotableVecTy),
2938 ElementTy(VecTy ? VecTy->getElementType() : nullptr),
2939 ElementSize(VecTy ?
DL.getTypeSizeInBits(ElementTy).getFixedValue() / 8
2941 PHIUsers(PHIUsers), SelectUsers(SelectUsers),
2942 IRB(*NewAI.getModule(), ConstantFolder()) {
2944 assert((
DL.getTypeSizeInBits(ElementTy).getFixedValue() % 8) == 0 &&
2945 "Only multiple-of-8 sized vector elements are viable");
2948 assert((!IntTy && !VecTy) || (IntTy && !VecTy) || (!IntTy && VecTy));
2951 bool visit(AllocaSlices::const_iterator
I) {
2952 bool CanSROA =
true;
2953 BeginOffset =
I->beginOffset();
2954 EndOffset =
I->endOffset();
2955 IsSplittable =
I->isSplittable();
2957 BeginOffset < NewAllocaBeginOffset || EndOffset > NewAllocaEndOffset;
2958 LLVM_DEBUG(
dbgs() <<
" rewriting " << (IsSplit ?
"split " :
""));
2963 assert(BeginOffset < NewAllocaEndOffset);
2964 assert(EndOffset > NewAllocaBeginOffset);
2965 NewBeginOffset = std::max(BeginOffset, NewAllocaBeginOffset);
2966 NewEndOffset = std::min(EndOffset, NewAllocaEndOffset);
2968 SliceSize = NewEndOffset - NewBeginOffset;
2969 LLVM_DEBUG(
dbgs() <<
" Begin:(" << BeginOffset <<
", " << EndOffset
2970 <<
") NewBegin:(" << NewBeginOffset <<
", "
2971 << NewEndOffset <<
") NewAllocaBegin:("
2972 << NewAllocaBeginOffset <<
", " << NewAllocaEndOffset
2974 assert(IsSplit || NewBeginOffset == BeginOffset);
2975 OldUse =
I->getUse();
2979 IRB.SetInsertPoint(OldUserI);
2980 IRB.SetCurrentDebugLocation(OldUserI->
getDebugLoc());
2982 if (!IRB.getContext().shouldDiscardValueNames())
2983 IRB.getInserter().SetNamePrefix(Twine(NewAI.
getName()) +
"." +
2984 Twine(BeginOffset) +
".");
3046 std::optional<SmallVector<Value *, 4>>
3047 rewriteTreeStructuredMerge(Partition &
P) {
3049 if (
P.splitSliceTails().size() > 0)
3050 return std::nullopt;
3059 :
Store(
SI), BeginOffset(Begin), EndOffset(
End), StoredValue(Val) {}
3069 LoadInst *FullLoad =
nullptr;
3070 StoreInst *InitStore =
nullptr;
3074 Type *AllocatedEltTy =
3078 unsigned AllocatedEltTySize =
DL.getTypeSizeInBits(AllocatedEltTy);
3085 auto IsTypeValidForTreeStructuredMerge = [&](
Type *Ty) ->
bool {
3087 return FixedVecTy &&
3088 DL.getTypeSizeInBits(FixedVecTy->getElementType()) % 8 == 0 &&
3089 !FixedVecTy->getElementType()->isPointerTy();
3092 for (Slice &S :
P) {
3096 bool IsFullWidth = (S.beginOffset() == NewAllocaBeginOffset &&
3097 S.endOffset() == NewAllocaEndOffset);
3101 !IsTypeValidForTreeStructuredMerge(LI->
getType()))
3102 return std::nullopt;
3107 return std::nullopt;
3111 LoadInfos.
push_back({LI, S.beginOffset(), S.endOffset()});
3123 if (!
SI->isSimple() || !IsTypeValidForTreeStructuredMerge(
3124 SI->getValueOperand()->getType()))
3125 return std::nullopt;
3127 unsigned NumElts = StVecTy->getNumElements();
3128 unsigned EltSize =
DL.getTypeSizeInBits(StVecTy->getElementType());
3129 if (NumElts * EltSize % AllocatedEltTySize != 0)
3130 return std::nullopt;
3135 return std::nullopt;
3138 StoreInfos.
emplace_back(SI, S.beginOffset(), S.endOffset(),
3139 SI->getValueOperand());
3144 return std::nullopt;
3151 if (StoreInfos.
size() < 2)
3152 return std::nullopt;
3160 bool IsRMWPattern = InitStore && VecTy && !LoadInfos.
empty();
3161 bool IsStoresOnlyPattern = !InitStore && FullLoad && LoadInfos.
empty();
3162 if (!IsRMWPattern && !IsStoresOnlyPattern)
3163 return std::nullopt;
3167 BasicBlock *StoreBB = StoreInfos[0].Store->getParent();
3168 for (
auto &Info : StoreInfos)
3169 if (
Info.Store->getParent() != StoreBB)
3170 return std::nullopt;
3172 SmallVector<Value *, 4> DeletedValues;
3179 auto TreeMerge = [&](SmallVectorImpl<Value *> &Vals,
3182 while (Vals.
size() > 1) {
3183 SmallVector<Value *, 8>
Next;
3184 for (
unsigned I = 0,
E = Vals.
size();
I + 1 <
E;
I += 2) {
3190 if (Vals.
size() % 2 == 1)
3192 Vals = std::move(
Next);
3201 auto ReplaceFullLoad = [&](LoadInst *LoadToReplace,
Value *Merged) {
3203 Value *NewLoad = LoadBuilder.CreateAlignedLoad(
3204 Merged->getType(), &NewAI, getSliceAlign(),
3206 LoadToReplace->
getName() +
".sroa.new.load");
3208 NewLoad = LoadBuilder.CreateBitCast(NewLoad, LoadToReplace->
getType());
3213 if (IsStoresOnlyPattern) {
3216 llvm::sort(StoreInfos, [](
const StoreInfo &
A,
const StoreInfo &
B) {
3217 return A.BeginOffset <
B.BeginOffset;
3222 uint64_t Expected = NewAllocaBeginOffset;
3223 for (
auto &Info : StoreInfos) {
3224 if (
Info.BeginOffset != Expected)
3225 return std::nullopt;
3226 Expected =
Info.EndOffset;
3229 if (Expected != NewAllocaEndOffset)
3230 return std::nullopt;
3240 if (LoadBB == StoreBB) {
3241 for (
auto &Info : StoreInfos)
3242 if (!
Info.Store->comesBefore(FullLoad))
3243 return std::nullopt;
3247 dbgs() <<
"Tree structured merge rewrite (stores-only):\n";
3248 dbgs() <<
" Load: " << *FullLoad <<
"\n Ordered stores:\n";
3249 for (
auto [
I, Info] :
enumerate(StoreInfos)) {
3250 dbgs() <<
" [" <<
I <<
"] Range[" <<
Info.BeginOffset <<
", "
3251 <<
Info.EndOffset <<
") \tStore: " << *
Info.Store
3252 <<
"\tValue: " << *
Info.StoredValue <<
"\n";
3265 SmallVector<Value *, 8> Vals;
3266 for (
const auto &Info : StoreInfos) {
3271 Value *Merged = TreeMerge(Vals, Builder);
3272 Builder.CreateAlignedStore(Merged, &NewAI, getSliceAlign());
3275 ReplaceFullLoad(FullLoad, Merged);
3276 return DeletedValues;
3284 return std::nullopt;
3285 if (
any_of(LoadInfos, [&](
const LoadInfo &
I) {
3286 return I.Load->getParent() != StoreBB;
3288 return std::nullopt;
3304 Accesses.reserve(LoadInfos.
size() + StoreInfos.size());
3305 for (
const auto &L : LoadInfos)
3306 Accesses.push_back({
L.Load,
L.BeginOffset,
L.EndOffset,
false});
3307 for (
const auto &S : StoreInfos)
3308 Accesses.push_back({S.Store, S.BeginOffset, S.EndOffset,
true});
3310 return A.Inst->comesBefore(
B.Inst);
3318 return std::nullopt;
3324 if (FullLoad && FullLoad->
getParent() == StoreBB &&
3325 !
Accesses.back().Inst->comesBefore(FullLoad))
3326 return std::nullopt;
3337 using SliceRange = std::pair<uint64_t, uint64_t>;
3341 SortedRanges.
emplace_back(Acc.BeginOffset, Acc.EndOffset);
3345 uint64_t Expected = NewAllocaBeginOffset;
3346 for (
auto &
Range : SortedRanges) {
3347 if (
Range.first != Expected)
3348 return std::nullopt;
3349 Expected =
Range.second;
3351 if (Expected != NewAllocaEndOffset)
3352 return std::nullopt;
3355 dbgs() <<
"Tree structured merge rewrite (RMW):\n";
3356 dbgs() <<
" Init store: " << *InitStore <<
"\n";
3358 dbgs() <<
" Final load: " << *FullLoad <<
"\n";
3359 dbgs() <<
" Slice ranges (" << SortedRanges.size() <<
"):\n";
3360 for (
auto &
Range : SortedRanges)
3371 if (InitVec->
getType() != NewAllocaTy)
3372 InitVec = IRB.CreateBitCast(InitVec, NewAllocaTy,
"init.cast");
3373 DenseMap<SliceRange, Value *> SliceValues;
3374 for (
auto &
Range : SortedRanges) {
3375 unsigned BeginIdx = getIndex(
Range.first);
3376 unsigned EndIdx = getIndex(
Range.second);
3377 SliceValues[
Range] = IRB.CreateShuffleVector(
3393 SliceRange
Range{Acc.BeginOffset, Acc.EndOffset};
3396 if (
V->getType() != Acc.Inst->getType()) {
3398 V = IRB.CreateBitCast(V, Acc.Inst->getType());
3400 Acc.Inst->replaceAllUsesWith(V);
3417 SmallVector<Value *, 8> Vals;
3418 for (
auto &
Range : SortedRanges)
3420 Value *Merged = TreeMerge(Vals, Builder);
3421 Builder.CreateAlignedStore(Merged, &NewAI, getSliceAlign());
3426 ReplaceFullLoad(FullLoad, Merged);
3428 return DeletedValues;
3436 bool visitInstruction(Instruction &
I) {
3444 assert(IsSplit || BeginOffset == NewBeginOffset);
3447 StringRef OldName = OldPtr->
getName();
3449 size_t LastSROAPrefix = OldName.
rfind(
".sroa.");
3451 OldName = OldName.
substr(LastSROAPrefix + strlen(
".sroa."));
3456 OldName = OldName.
substr(IndexEnd + 1);
3460 OldName = OldName.
substr(OffsetEnd + 1);
3464 OldName = OldName.
substr(0, OldName.
find(
".sroa_"));
3476 Align getSliceAlign() {
3478 NewBeginOffset - NewAllocaBeginOffset);
3482 assert(VecTy &&
"Can only call getIndex when rewriting a vector");
3484 assert(RelOffset / ElementSize < UINT32_MAX &&
"Index out of bounds");
3485 uint32_t
Index = RelOffset / ElementSize;
3486 assert(Index * ElementSize == RelOffset);
3490 void deleteIfTriviallyDead(
Value *V) {
3493 Pass.DeadInsts.push_back(
I);
3496 Value *rewriteVectorizedLoadInst(LoadInst &LI) {
3497 unsigned BeginIndex = getIndex(NewBeginOffset);
3498 unsigned EndIndex = getIndex(NewEndOffset);
3499 assert(EndIndex > BeginIndex &&
"Empty vector!");
3502 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3504 Load->copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
3505 LLVMContext::MD_access_group});
3509 Value *rewriteIntegerLoad(LoadInst &LI) {
3510 assert(IntTy &&
"We cannot insert an integer to the alloca");
3513 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3514 V = IRB.CreateBitPreservingCastChain(
DL, V, IntTy);
3515 assert(NewBeginOffset >= NewAllocaBeginOffset &&
"Out of bounds offset");
3517 if (
Offset > 0 || NewEndOffset < NewAllocaEndOffset) {
3518 IntegerType *ExtractTy = Type::getIntNTy(LI.
getContext(), SliceSize * 8);
3527 "Can only handle an extract for an overly wide load");
3529 V = IRB.CreateZExt(V, LI.
getType());
3533 bool visitLoadInst(LoadInst &LI) {
3542 Type *TargetTy = IsSplit ? Type::getIntNTy(LI.
getContext(), SliceSize * 8)
3544 bool IsPtrAdjusted =
false;
3547 V = rewriteVectorizedLoadInst(LI);
3549 V = rewriteIntegerLoad(LI);
3550 }
else if (NewBeginOffset == NewAllocaBeginOffset &&
3551 NewEndOffset == NewAllocaEndOffset &&
3554 DL.getTypeStoreSize(TargetTy).getFixedValue() > SliceSize &&
3557 getPtrToNewAI(LI.getPointerAddressSpace(), LI.isVolatile());
3558 LoadInst *NewLI = IRB.CreateAlignedLoad(
3559 NewAllocaTy, NewPtr, NewAI.getAlign(), LI.isVolatile(), LI.getName());
3560 if (LI.isVolatile())
3561 NewLI->setAtomic(LI.getOrdering(), LI.getSyncScopeID());
3562 if (NewLI->isAtomic())
3563 NewLI->setAlignment(LI.getAlign());
3568 copyMetadataForLoad(*NewLI, LI);
3572 NewLI->setAAMetadata(AATags.adjustForAccess(
3573 NewBeginOffset - BeginOffset, NewLI->getType(), DL));
3581 if (auto *AITy = dyn_cast<IntegerType>(NewAllocaTy))
3582 if (auto *TITy = dyn_cast<IntegerType>(TargetTy))
3583 if (AITy->getBitWidth() < TITy->getBitWidth()) {
3584 V = IRB.CreateZExt(V, TITy,
"load.ext");
3585 if (DL.isBigEndian())
3586 V = IRB.CreateShl(V, TITy->getBitWidth() - AITy->getBitWidth(),
3590 Type *LTy = IRB.getPtrTy(AS);
3592 IRB.CreateAlignedLoad(TargetTy, getNewAllocaSlicePtr(IRB, LTy),
3597 NewBeginOffset - BeginOffset, NewLI->
getType(),
DL));
3601 NewLI->
copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
3602 LLVMContext::MD_access_group});
3605 IsPtrAdjusted =
true;
3607 V = IRB.CreateBitPreservingCastChain(
DL, V, TargetTy);
3612 "Only integer type loads and stores are split");
3613 assert(SliceSize <
DL.getTypeStoreSize(LI.
getType()).getFixedValue() &&
3614 "Split load isn't smaller than original load");
3616 "Non-byte-multiple bit width");
3622 LIIt.setHeadBit(
true);
3623 IRB.SetInsertPoint(LIIt);
3628 Value *Placeholder =
3634 Placeholder->replaceAllUsesWith(&LI);
3635 Placeholder->deleteValue();
3640 Pass.DeadInsts.push_back(&LI);
3641 deleteIfTriviallyDead(OldOp);
3646 bool rewriteVectorizedStoreInst(
Value *V, StoreInst &SI,
Value *OldOp,
3651 if (
V->getType() != VecTy) {
3652 unsigned BeginIndex = getIndex(NewBeginOffset);
3653 unsigned EndIndex = getIndex(NewEndOffset);
3654 assert(EndIndex > BeginIndex &&
"Empty vector!");
3655 unsigned NumElements = EndIndex - BeginIndex;
3657 "Too many elements!");
3658 Type *SliceTy = (NumElements == 1)
3660 : FixedVectorType::
get(ElementTy, NumElements);
3661 if (
V->getType() != SliceTy)
3662 V = IRB.CreateBitPreservingCastChain(
DL, V, SliceTy);
3666 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3669 StoreInst *
Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.
getAlign());
3670 Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3671 LLVMContext::MD_access_group});
3675 Pass.DeadInsts.push_back(&SI);
3684 bool rewriteIntegerStore(
Value *V, StoreInst &SI, AAMDNodes AATags) {
3685 assert(IntTy &&
"We cannot extract an integer from the alloca");
3687 if (
DL.getTypeSizeInBits(
V->getType()).getFixedValue() !=
3689 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3691 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3692 assert(BeginOffset >= NewAllocaBeginOffset &&
"Out of bounds offset");
3696 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3697 StoreInst *
Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.
getAlign());
3698 Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3699 LLVMContext::MD_access_group});
3706 Store->getValueOperand(),
DL);
3708 Pass.DeadInsts.push_back(&SI);
3713 bool visitStoreInst(StoreInst &SI) {
3715 Value *OldOp =
SI.getOperand(1);
3718 AAMDNodes AATags =
SI.getAAMetadata();
3723 if (
V->getType()->isPointerTy())
3725 Pass.PostPromotionWorklist.insert(AI);
3727 TypeSize StoreSize =
DL.getTypeStoreSize(
V->getType());
3730 assert(
V->getType()->isIntegerTy() &&
3731 "Only integer type loads and stores are split");
3732 assert(
DL.typeSizeEqualsStoreSize(
V->getType()) &&
3733 "Non-byte-multiple bit width");
3734 IntegerType *NarrowTy = Type::getIntNTy(
SI.getContext(), SliceSize * 8);
3740 return rewriteVectorizedStoreInst(V, SI, OldOp, AATags);
3741 if (IntTy &&
V->getType()->isIntegerTy())
3742 return rewriteIntegerStore(V, SI, AATags);
3745 if (NewBeginOffset == NewAllocaBeginOffset &&
3746 NewEndOffset == NewAllocaEndOffset &&
3748 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3750 getPtrToNewAI(
SI.getPointerAddressSpace(),
SI.isVolatile());
3753 IRB.CreateAlignedStore(V, NewPtr, NewAI.
getAlign(),
SI.isVolatile());
3755 unsigned AS =
SI.getPointerAddressSpace();
3756 Value *NewPtr = getNewAllocaSlicePtr(IRB, IRB.getPtrTy(AS));
3758 IRB.CreateAlignedStore(V, NewPtr, getSliceAlign(),
SI.isVolatile());
3760 NewSI->
copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3761 LLVMContext::MD_access_group});
3765 if (
SI.isVolatile())
3774 Pass.DeadInsts.push_back(&SI);
3775 deleteIfTriviallyDead(OldOp);
3793 assert(
Size > 0 &&
"Expected a positive number of bytes.");
3801 IRB.CreateZExt(V, SplatIntTy,
"zext"),
3811 V = IRB.CreateVectorSplat(NumElements, V,
"vsplat");
3816 bool visitMemSetInst(MemSetInst &
II) {
3820 AAMDNodes AATags =
II.getAAMetadata();
3826 assert(NewBeginOffset == BeginOffset);
3827 II.setDest(getNewAllocaSlicePtr(IRB, OldPtr->
getType()));
3828 II.setDestAlignment(getSliceAlign());
3833 "AT: Unexpected link to non-const GEP");
3834 deleteIfTriviallyDead(OldPtr);
3839 Pass.DeadInsts.push_back(&
II);
3843 const bool CanContinue = [&]() {
3846 if (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset)
3851 if (Len > std::numeric_limits<unsigned>::max())
3853 auto *Int8Ty = IntegerType::getInt8Ty(NewAI.
getContext());
3856 DL.isLegalInteger(
DL.getTypeSizeInBits(ScalarTy).getFixedValue());
3862 Type *SizeTy =
II.getLength()->getType();
3863 unsigned Sz = NewEndOffset - NewBeginOffset;
3866 getNewAllocaSlicePtr(IRB, OldPtr->
getType()),
II.getValue(),
Size,
3867 MaybeAlign(getSliceAlign()),
II.isVolatile()));
3873 New,
New->getRawDest(),
nullptr,
DL);
3888 assert(ElementTy == ScalarTy);
3890 unsigned BeginIndex = getIndex(NewBeginOffset);
3891 unsigned EndIndex = getIndex(NewEndOffset);
3892 assert(EndIndex > BeginIndex &&
"Empty vector!");
3893 unsigned NumElements = EndIndex - BeginIndex;
3895 "Too many elements!");
3898 II.getValue(),
DL.getTypeSizeInBits(ElementTy).getFixedValue() / 8);
3899 Splat = IRB.CreateBitPreservingCastChain(
DL,
Splat, ElementTy);
3900 if (NumElements > 1)
3903 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3912 V = getIntegerSplat(
II.getValue(),
Size);
3914 if (IntTy && (NewBeginOffset != NewAllocaBeginOffset ||
3915 NewEndOffset != NewAllocaEndOffset)) {
3916 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI,
3918 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3922 assert(
V->getType() == IntTy &&
3923 "Wrong type for an alloca wide integer!");
3925 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3928 assert(NewBeginOffset == NewAllocaBeginOffset);
3929 assert(NewEndOffset == NewAllocaEndOffset);
3931 V = getIntegerSplat(
II.getValue(),
3932 DL.getTypeSizeInBits(ScalarTy).getFixedValue() / 8);
3937 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3940 Value *NewPtr = getPtrToNewAI(
II.getDestAddressSpace(),
II.isVolatile());
3942 IRB.CreateAlignedStore(V, NewPtr, NewAI.
getAlign(),
II.isVolatile());
3943 New->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
3944 LLVMContext::MD_access_group});
3950 New,
New->getPointerOperand(), V,
DL);
3953 return !
II.isVolatile();
3956 bool visitMemTransferInst(MemTransferInst &
II) {
3962 AAMDNodes AATags =
II.getAAMetadata();
3964 bool IsDest = &
II.getRawDestUse() == OldUse;
3965 assert((IsDest &&
II.getRawDest() == OldPtr) ||
3966 (!IsDest &&
II.getRawSource() == OldPtr));
3968 Align SliceAlign = getSliceAlign();
3976 if (!IsSplittable) {
3977 Value *AdjustedPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
3982 DbgAssign->getAddress() ==
II.getDest())
3983 DbgAssign->replaceVariableLocationOp(
II.getDest(), AdjustedPtr);
3985 II.setDest(AdjustedPtr);
3986 II.setDestAlignment(SliceAlign);
3988 II.setSource(AdjustedPtr);
3989 II.setSourceAlignment(SliceAlign);
3993 deleteIfTriviallyDead(OldPtr);
4006 (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset ||
4007 SliceSize !=
DL.getTypeStoreSize(NewAllocaTy).getFixedValue() ||
4008 !
DL.typeSizeEqualsStoreSize(NewAllocaTy) ||
4014 if (EmitMemCpy && &OldAI == &NewAI) {
4016 assert(NewBeginOffset == BeginOffset);
4019 if (NewEndOffset != EndOffset)
4020 II.setLength(NewEndOffset - NewBeginOffset);
4024 Pass.DeadInsts.push_back(&
II);
4028 Value *OtherPtr = IsDest ?
II.getRawSource() :
II.getRawDest();
4029 if (AllocaInst *AI =
4031 assert(AI != &OldAI && AI != &NewAI &&
4032 "Splittable transfers cannot reach the same alloca on both ends.");
4033 Pass.Worklist.insert(AI);
4040 unsigned OffsetWidth =
DL.getIndexSizeInBits(OtherAS);
4041 APInt OtherOffset(OffsetWidth, NewBeginOffset - BeginOffset);
4043 (IsDest ?
II.getSourceAlign() :
II.getDestAlign()).valueOrOne();
4045 commonAlignment(OtherAlign, OtherOffset.zextOrTrunc(64).getZExtValue());
4053 Value *OurPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
4054 Type *SizeTy =
II.getLength()->getType();
4055 Constant *
Size = ConstantInt::get(SizeTy, NewEndOffset - NewBeginOffset);
4057 Value *DestPtr, *SrcPtr;
4058 MaybeAlign DestAlign, SrcAlign;
4062 DestAlign = SliceAlign;
4064 SrcAlign = OtherAlign;
4067 DestAlign = OtherAlign;
4069 SrcAlign = SliceAlign;
4071 CallInst *
New = IRB.CreateMemCpy(DestPtr, DestAlign, SrcPtr, SrcAlign,
4074 New->setAAMetadata(AATags.
shift(NewBeginOffset - BeginOffset));
4079 &
II, New, DestPtr,
nullptr,
DL);
4084 SliceSize * 8, &
II, New, DestPtr,
nullptr,
DL);
4090 bool IsWholeAlloca = NewBeginOffset == NewAllocaBeginOffset &&
4091 NewEndOffset == NewAllocaEndOffset;
4093 unsigned BeginIndex = VecTy ? getIndex(NewBeginOffset) : 0;
4094 unsigned EndIndex = VecTy ? getIndex(NewEndOffset) : 0;
4095 unsigned NumElements = EndIndex - BeginIndex;
4096 IntegerType *SubIntTy =
4097 IntTy ? Type::getIntNTy(IntTy->
getContext(),
Size * 8) : nullptr;
4102 if (VecTy && !IsWholeAlloca) {
4103 if (NumElements == 1)
4104 OtherTy = VecTy->getElementType();
4107 }
else if (IntTy && !IsWholeAlloca) {
4110 OtherTy = NewAllocaTy;
4115 MaybeAlign SrcAlign = OtherAlign;
4116 MaybeAlign DstAlign = SliceAlign;
4124 DstPtr = getPtrToNewAI(
II.getDestAddressSpace(),
II.isVolatile());
4128 SrcPtr = getPtrToNewAI(
II.getSourceAddressSpace(),
II.isVolatile());
4132 if (VecTy && !IsWholeAlloca && !IsDest) {
4134 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
4136 }
else if (IntTy && !IsWholeAlloca && !IsDest) {
4138 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
4139 Src = IRB.CreateBitPreservingCastChain(
DL, Src, IntTy);
4143 LoadInst *
Load = IRB.CreateAlignedLoad(OtherTy, SrcPtr, SrcAlign,
4144 II.isVolatile(),
"copyload");
4145 Load->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
4146 LLVMContext::MD_access_group});
4153 if (VecTy && !IsWholeAlloca && IsDest) {
4154 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
4157 }
else if (IntTy && !IsWholeAlloca && IsDest) {
4158 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
4160 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
4163 Src = IRB.CreateBitPreservingCastChain(
DL, Src, NewAllocaTy);
4167 IRB.CreateAlignedStore(Src, DstPtr, DstAlign,
II.isVolatile()));
4168 Store->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
4169 LLVMContext::MD_access_group});
4172 Src->getType(),
DL));
4187 return !
II.isVolatile();
4190 bool visitIntrinsicInst(IntrinsicInst &
II) {
4191 assert((
II.isLifetimeStartOrEnd() ||
II.isDroppable()) &&
4192 "Unexpected intrinsic!");
4196 Pass.DeadInsts.push_back(&
II);
4198 if (
II.isDroppable()) {
4199 assert(
II.getIntrinsicID() == Intrinsic::assume &&
"Expected assume");
4205 assert(
II.getArgOperand(0) == OldPtr);
4209 if (
II.getIntrinsicID() == Intrinsic::lifetime_start)
4210 New = IRB.CreateLifetimeStart(Ptr);
4212 New = IRB.CreateLifetimeEnd(Ptr);
4220 void fixLoadStoreAlign(Instruction &Root) {
4224 SmallPtrSet<Instruction *, 4> Visited;
4225 SmallVector<Instruction *, 4>
Uses;
4227 Uses.push_back(&Root);
4236 SI->setAlignment(std::min(
SI->getAlign(), getSliceAlign()));
4243 for (User *U :
I->users())
4246 }
while (!
Uses.empty());
4249 bool visitPHINode(PHINode &PN) {
4251 assert(BeginOffset >= NewAllocaBeginOffset &&
"PHIs are unsplittable");
4252 assert(EndOffset <= NewAllocaEndOffset &&
"PHIs are unsplittable");
4258 IRBuilderBase::InsertPointGuard Guard(IRB);
4260 IRB.SetInsertPoint(OldPtr->
getParent()->getFirstInsertionPt());
4262 IRB.SetInsertPoint(OldPtr);
4263 IRB.SetCurrentDebugLocation(OldPtr->
getDebugLoc());
4265 Value *NewPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
4270 deleteIfTriviallyDead(OldPtr);
4273 fixLoadStoreAlign(PN);
4282 bool visitSelectInst(SelectInst &SI) {
4284 assert((
SI.getTrueValue() == OldPtr ||
SI.getFalseValue() == OldPtr) &&
4285 "Pointer isn't an operand!");
4286 assert(BeginOffset >= NewAllocaBeginOffset &&
"Selects are unsplittable");
4287 assert(EndOffset <= NewAllocaEndOffset &&
"Selects are unsplittable");
4289 Value *NewPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
4291 if (
SI.getOperand(1) == OldPtr)
4292 SI.setOperand(1, NewPtr);
4293 if (
SI.getOperand(2) == OldPtr)
4294 SI.setOperand(2, NewPtr);
4297 deleteIfTriviallyDead(OldPtr);
4300 fixLoadStoreAlign(SI);
4315class AggLoadStoreRewriter :
public InstVisitor<AggLoadStoreRewriter, bool> {
4317 friend class InstVisitor<AggLoadStoreRewriter, bool>;
4323 SmallPtrSet<User *, 8> Visited;
4330 const DataLayout &
DL;
4335 AggLoadStoreRewriter(
const DataLayout &
DL, IRBuilderTy &IRB)
4336 :
DL(
DL), IRB(IRB) {}
4340 bool rewrite(Instruction &
I) {
4344 while (!
Queue.empty()) {
4345 U =
Queue.pop_back_val();
4354 void enqueueUsers(Instruction &
I) {
4355 for (Use &U :
I.uses())
4356 if (Visited.
insert(
U.getUser()).second)
4357 Queue.push_back(&U);
4361 bool visitInstruction(Instruction &
I) {
return false; }
4364 template <
typename Derived>
class OpSplitter {
4371 SmallVector<unsigned, 4> Indices;
4375 SmallVector<Value *, 4> GEPIndices;
4389 const DataLayout &
DL;
4393 OpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4394 Align BaseAlign,
const DataLayout &
DL, IRBuilderTy &IRB)
4395 : IRB(IRB), GEPIndices(1, IRB.getInt32(0)), Ptr(Ptr), BaseTy(BaseTy),
4396 BaseAlign(BaseAlign),
DL(
DL) {
4397 IRB.SetInsertPoint(InsertionPoint);
4414 void emitSplitOps(
Type *Ty,
Value *&Agg,
const Twine &Name) {
4416 unsigned Offset =
DL.getIndexedOffsetInType(BaseTy, GEPIndices);
4417 return static_cast<Derived *
>(
this)->emitFunc(
4422 unsigned OldSize = Indices.
size();
4424 for (
unsigned Idx = 0,
Size = ATy->getNumElements(); Idx !=
Size;
4426 assert(Indices.
size() == OldSize &&
"Did not return to the old size");
4428 GEPIndices.
push_back(IRB.getInt32(Idx));
4429 emitSplitOps(ATy->getElementType(), Agg, Name +
"." + Twine(Idx));
4437 unsigned OldSize = Indices.
size();
4439 for (
unsigned Idx = 0,
Size = STy->getNumElements(); Idx !=
Size;
4441 assert(Indices.
size() == OldSize &&
"Did not return to the old size");
4443 GEPIndices.
push_back(IRB.getInt32(Idx));
4444 emitSplitOps(STy->getElementType(Idx), Agg, Name +
"." + Twine(Idx));
4455 struct LoadOpSplitter :
public OpSplitter<LoadOpSplitter> {
4459 SmallVector<Value *, 4> Components;
4464 LoadOpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4465 AAMDNodes AATags, Align BaseAlign,
const DataLayout &
DL,
4467 : OpSplitter<LoadOpSplitter>(InsertionPoint, Ptr, BaseTy, BaseAlign,
DL,
4473 void emitFunc(
Type *Ty,
Value *&Agg, Align Alignment,
const Twine &Name) {
4477 IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name +
".gep");
4479 IRB.CreateAlignedLoad(Ty,
GEP, Alignment, Name +
".load");
4485 Load->setAAMetadata(
4491 Agg = IRB.CreateInsertValue(Agg,
Load, Indices, Name +
".insert");
4496 void recordFakeUses(LoadInst &LI) {
4497 for (Use &U : LI.
uses())
4499 if (
II->getIntrinsicID() == Intrinsic::fake_use)
4505 void emitFakeUses() {
4506 for (Instruction *
I : FakeUses) {
4507 IRB.SetInsertPoint(
I);
4508 for (
auto *V : Components)
4509 IRB.CreateIntrinsic(Intrinsic::fake_use, {
V});
4510 I->eraseFromParent();
4515 bool visitLoadInst(LoadInst &LI) {
4524 Splitter.recordFakeUses(LI);
4527 Splitter.emitFakeUses();
4534 struct StoreOpSplitter :
public OpSplitter<StoreOpSplitter> {
4535 StoreOpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4536 AAMDNodes AATags, StoreInst *AggStore, Align BaseAlign,
4537 const DataLayout &
DL, IRBuilderTy &IRB)
4538 : OpSplitter<StoreOpSplitter>(InsertionPoint, Ptr, BaseTy, BaseAlign,
4540 AATags(AATags), AggStore(AggStore) {}
4542 StoreInst *AggStore;
4545 void emitFunc(
Type *Ty,
Value *&Agg, Align Alignment,
const Twine &Name) {
4551 Value *ExtractValue =
4552 IRB.CreateExtractValue(Agg, Indices, Name +
".extract");
4553 Value *InBoundsGEP =
4554 IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name +
".gep");
4556 IRB.CreateAlignedStore(ExtractValue, InBoundsGEP, Alignment);
4573 DL.getTypeSizeInBits(
Store->getValueOperand()->getType());
4575 SizeInBits, AggStore,
Store,
4576 Store->getPointerOperand(),
Store->getValueOperand(),
4580 "AT: unexpected debug.assign linked to store through "
4587 bool visitStoreInst(StoreInst &SI) {
4588 if (!
SI.isSimple() ||
SI.getPointerOperand() != *U)
4591 if (
V->getType()->isSingleValueType())
4596 StoreOpSplitter Splitter(&SI, *U,
V->getType(),
SI.getAAMetadata(), &SI,
4598 Splitter.emitSplitOps(
V->getType(), V,
V->getName() +
".fca");
4603 SI.eraseFromParent();
4607 bool visitBitCastInst(BitCastInst &BC) {
4612 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
4622 bool unfoldGEPSelect(GetElementPtrInst &GEPI) {
4641 if (!ZI->getSrcTy()->isIntegerTy(1))
4654 dbgs() <<
" original: " << *Sel <<
"\n";
4655 dbgs() <<
" " << GEPI <<
"\n";);
4657 auto GetNewOps = [&](
Value *SelOp) {
4670 Cond =
SI->getCondition();
4671 True =
SI->getTrueValue();
4675 Cond = Sel->getOperand(0);
4676 True = ConstantInt::get(Sel->getType(), 1);
4677 False = ConstantInt::get(Sel->getType(), 0);
4682 IRB.SetInsertPoint(&GEPI);
4686 Value *NTrue = IRB.CreateGEP(Ty, TrueOps[0],
ArrayRef(TrueOps).drop_front(),
4687 True->getName() +
".sroa.gep", NW);
4690 IRB.CreateGEP(Ty, FalseOps[0],
ArrayRef(FalseOps).drop_front(),
4691 False->getName() +
".sroa.gep", NW);
4693 Value *NSel = MDFrom
4694 ? IRB.CreateSelect(
Cond, NTrue, NFalse,
4695 Sel->getName() +
".sroa.sel", MDFrom)
4696 : IRB.CreateSelectWithUnknownProfile(
4698 Sel->getName() +
".sroa.sel");
4699 Visited.
erase(&GEPI);
4704 enqueueUsers(*NSelI);
4707 dbgs() <<
" " << *NFalse <<
"\n";
4708 dbgs() <<
" " << *NSel <<
"\n";);
4717 bool unfoldGEPPhi(GetElementPtrInst &GEPI) {
4722 auto IsInvalidPointerOperand = [](
Value *
V) {
4726 return !AI->isStaticAlloca();
4730 if (
any_of(
Phi->operands(), IsInvalidPointerOperand))
4745 [](
Value *V) { return isa<ConstantInt>(V); }))
4758 dbgs() <<
" original: " << *
Phi <<
"\n";
4759 dbgs() <<
" " << GEPI <<
"\n";);
4761 auto GetNewOps = [&](
Value *PhiOp) {
4771 IRB.SetInsertPoint(Phi);
4772 PHINode *NewPhi = IRB.CreatePHI(GEPI.
getType(),
Phi->getNumIncomingValues(),
4773 Phi->getName() +
".sroa.phi");
4779 for (
unsigned I = 0,
E =
Phi->getNumIncomingValues();
I !=
E; ++
I) {
4788 IRB.CreateGEP(SourceTy, NewOps[0],
ArrayRef(NewOps).drop_front(),
4794 Visited.
erase(&GEPI);
4798 enqueueUsers(*NewPhi);
4804 dbgs() <<
"\n " << *NewPhi <<
'\n');
4809 bool visitGetElementPtrInst(GetElementPtrInst &GEPI) {
4810 if (unfoldGEPSelect(GEPI))
4813 if (unfoldGEPPhi(GEPI))
4820 bool visitPHINode(PHINode &PN) {
4825 bool visitSelectInst(SelectInst &SI) {
4839 if (Ty->isSingleValueType())
4842 uint64_t AllocSize =
DL.getTypeAllocSize(Ty).getFixedValue();
4847 InnerTy = ArrTy->getElementType();
4851 InnerTy = STy->getElementType(Index);
4856 if (AllocSize >
DL.getTypeAllocSize(InnerTy).getFixedValue() ||
4857 TypeSize >
DL.getTypeSizeInBits(InnerTy).getFixedValue())
4878 if (
Offset == 0 &&
DL.getTypeAllocSize(Ty).getFixedValue() ==
Size)
4880 if (
Offset >
DL.getTypeAllocSize(Ty).getFixedValue() ||
4881 (
DL.getTypeAllocSize(Ty).getFixedValue() -
Offset) <
Size)
4888 ElementTy = AT->getElementType();
4889 TyNumElements = AT->getNumElements();
4894 ElementTy = VT->getElementType();
4895 TyNumElements = VT->getNumElements();
4897 uint64_t ElementSize =
DL.getTypeAllocSize(ElementTy).getFixedValue();
4899 if (NumSkippedElements >= TyNumElements)
4901 Offset -= NumSkippedElements * ElementSize;
4913 if (
Size == ElementSize)
4917 if (NumElements * ElementSize !=
Size)
4941 uint64_t ElementSize =
DL.getTypeAllocSize(ElementTy).getFixedValue();
4942 if (
Offset >= ElementSize)
4953 if (
Size == ElementSize)
4960 if (Index == EndIndex)
4970 assert(Index < EndIndex);
4995 const std::vector<uint64_t> &Splits;
5002 std::vector<uint64_t> &Splits,
unsigned SliceSize)
5003 : IRB(IRB), DL(DL), Splits(Splits), SliceSize(SliceSize) {}
5013 Idx = IsEnd ?
SS.Splits.size() + 1 : 0;
5018 uint64_t NextOffset =
5019 Idx <
SS.Splits.size() ?
SS.Splits[
Idx] :
SS.SliceSize;
5035 Type *PartPtrTy = BasePtr->getType();
5037 LoadInst *PLoad = IRB.CreateAlignedLoad(
5041 PartPtrTy, BasePtr->getName() +
"."),
5044 PLoad->
copyMetadata(*SplitI, {LLVMContext::MD_mem_parallel_loop_access,
5045 LLVMContext::MD_access_group});
5051 Type *PartPtrTy = BasePtr->getType();
5053 StoreInst *PStore = IRB.CreateAlignedStore(
5057 PartPtrTy, BasePtr->getName() +
"."),
5060 PStore->
copyMetadata(*SplitI, {LLVMContext::MD_mem_parallel_loop_access,
5061 LLVMContext::MD_access_group,
5062 LLVMContext::MD_DIAssignID});
5072 unsigned PtrIdx = 0;
5076 PtrIdx =
SI->getPointerOperandIndex();
5083 &
I->getOperandUse(PtrIdx),
false);
5085 << S.endOffset() <<
"): " << *
I <<
"\n");
5096 InstructionSliceMap &SliceMap) {
5098 if (S.endOffset() - S.beginOffset() == 1)
5116 for (Slice *JS : SliceMap[J]) {
5117 if (S.beginOffset() > JS->beginOffset() &&
5118 S.beginOffset() < JS->endOffset())
5120 if (JS->beginOffset() > S.beginOffset() &&
5121 JS->beginOffset() < S.endOffset())
5152bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
5166 struct SplitOffsets {
5168 std::vector<uint64_t> Splits;
5170 SmallDenseMap<Instruction *, SplitOffsets, 8> SplitOffsetsMap;
5183 SmallPtrSet<LoadInst *, 8> UnsplittableLoads;
5185 LLVM_DEBUG(
dbgs() <<
" Searching for candidate loads and stores\n");
5186 for (
auto &
P : AS.partitions()) {
5187 InstructionSliceMap SliceMap;
5188 for (Slice &S :
P) {
5191 for (Slice &S :
P) {
5193 bool ExtendsPastPartitionEnd = S.endOffset() >
P.endOffset();
5195 if (!S.isSplittable() || (!ExtendsPastPartitionEnd && !CopyOverlap)) {
5200 UnsplittableLoads.
insert(LI);
5203 UnsplittableLoads.
insert(LI);
5206 assert(
P.endOffset() > S.beginOffset() &&
5207 "Empty or backwards partition!");
5216 auto IsLoadSimplyStored = [](LoadInst *LI) {
5217 for (User *LU : LI->
users()) {
5219 if (!SI || !
SI->isSimple())
5224 if (!IsLoadSimplyStored(LI)) {
5225 UnsplittableLoads.
insert(LI);
5231 if (S.getUse() != &
SI->getOperandUse(
SI->getPointerOperandIndex()))
5235 if (!StoredLoad || !StoredLoad->isSimple())
5237 assert(!
SI->isVolatile() &&
"Cannot split volatile stores!");
5247 auto &
Offsets = SplitOffsetsMap[
I];
5249 "Should not have splits the first time we see an instruction!");
5264 std::max(S.beginOffset(), CopyOverlap->beginOffset());
5265 uint64_t OverlapEnd = std::min(S.endOffset(), CopyOverlap->endOffset());
5266 uint64_t OverlapSize = OverlapEnd - OverlapStart;
5267 uint64_t SliceSize = S.endOffset() - S.beginOffset();
5268 uint64_t NonOverlapSize = SliceSize - OverlapSize;
5269 if (OverlapSize < NonOverlapSize) {
5274 Offsets.Splits.push_back(OverlapSize);
5275 Offsets.Splits.push_back(SliceSize - OverlapSize);
5276 }
else if (OverlapSize > NonOverlapSize) {
5279 for (
uint64_t Split = NonOverlapSize;
Split <= SliceSize / 2;
5280 Split += NonOverlapSize) {
5281 Offsets.Splits.push_back(Split);
5282 if (Split != SliceSize - Split) {
5283 Offsets.Splits.push_back(SliceSize - Split);
5291 Offsets.Splits.push_back(OverlapSize);
5294 Offsets.Splits.push_back(
P.endOffset() - S.beginOffset());
5303 llvm::erase_if(Stores, [&UnsplittableLoads, &SplitOffsetsMap](StoreInst *SI) {
5309 if (UnsplittableLoads.
count(LI))
5312 auto LoadOffsetsI = SplitOffsetsMap.
find(LI);
5313 if (LoadOffsetsI == SplitOffsetsMap.
end())
5315 auto &LoadOffsets = LoadOffsetsI->second;
5318 auto &StoreOffsets = SplitOffsetsMap[
SI];
5323 if (LoadOffsets.Splits == StoreOffsets.Splits)
5327 <<
" " << *LI <<
"\n"
5328 <<
" " << *SI <<
"\n");
5334 UnsplittableLoads.
insert(LI);
5343 return UnsplittableLoads.
count(LI);
5348 return UnsplittableLoads.
count(LI);
5358 IRBuilderTy IRB(&AI);
5365 SmallPtrSet<AllocaInst *, 4> ResplitPromotableAllocas;
5375 SmallDenseMap<LoadInst *, std::vector<LoadInst *>, 1> SplitLoadsMap;
5376 std::vector<LoadInst *> SplitLoads;
5377 const DataLayout &
DL = AI.getDataLayout();
5378 for (LoadInst *LI : Loads) {
5381 auto &
Offsets = SplitOffsetsMap[LI];
5382 unsigned SliceSize =
Offsets.S->endOffset() -
Offsets.S->beginOffset();
5384 "Load must have type size equal to store size");
5386 "Load must be >= slice size");
5389 assert(BaseOffset + SliceSize > BaseOffset &&
5390 "Cannot represent alloca access size using 64-bit integers!");
5393 IRB.SetInsertPoint(LI);
5397 SliceSplitter Splitter(IRB,
DL,
Offsets.Splits, SliceSize);
5398 for (
auto Part : Splitter) {
5399 LoadInst *PLoad = Splitter.createLoad(BasePtr, Part, LI);
5403 SplitLoads.push_back(PLoad);
5406 NewSlices.
push_back(Splitter.createSlice(PLoad, BaseOffset, Part));
5412 bool DeferredStores =
false;
5413 for (User *LU : LI->
users()) {
5415 if (!Stores.
empty() && SplitOffsetsMap.
count(SI)) {
5416 DeferredStores =
true;
5422 Value *StoreBasePtr =
SI->getPointerOperand();
5423 IRB.SetInsertPoint(SI);
5425 LLVM_DEBUG(
dbgs() <<
" Splitting store of load: " << *SI <<
"\n");
5427 for (
auto Part : Splitter) {
5428 LoadInst *PLoad = SplitLoads[Part.Idx];
5429 StoreInst *PStore = Splitter.createStore(PLoad, StoreBasePtr, Part, SI);
5440 ResplitPromotableAllocas.
insert(OtherAI);
5441 Worklist.insert(OtherAI);
5444 Worklist.insert(OtherAI);
5448 DeadInsts.push_back(SI);
5453 SplitLoadsMap.
insert(std::make_pair(LI, std::move(SplitLoads)));
5456 DeadInsts.push_back(LI);
5465 for (StoreInst *SI : Stores) {
5470 assert(StoreSize > 0 &&
"Cannot have a zero-sized integer store!");
5474 "Slice size should always match load size exactly!");
5476 assert(BaseOffset + StoreSize > BaseOffset &&
5477 "Cannot represent alloca access size using 64-bit integers!");
5485 auto SplitLoadsMapI = SplitLoadsMap.
find(LI);
5486 std::vector<LoadInst *> *SplitLoads =
nullptr;
5487 if (SplitLoadsMapI != SplitLoadsMap.
end()) {
5488 SplitLoads = &SplitLoadsMapI->second;
5490 "Too few split loads for the number of splits in the store!");
5495 SliceSplitter Splitter(IRB,
DL,
Offsets.Splits, StoreSize);
5496 for (
auto Part : Splitter) {
5500 PLoad = (*SplitLoads)[Part.Idx];
5502 IRB.SetInsertPoint(LI);
5503 PLoad = Splitter.createLoad(LoadBasePtr, Part, LI);
5507 IRB.SetInsertPoint(SI);
5508 StoreInst *PStore = Splitter.createStore(PLoad, StoreBasePtr, Part, SI);
5511 NewSlices.
push_back(Splitter.createSlice(PStore, BaseOffset, Part));
5524 assert(OtherAI != &AI &&
"We can't re-split our own alloca!");
5525 ResplitPromotableAllocas.
insert(OtherAI);
5526 Worklist.insert(OtherAI);
5529 assert(OtherAI != &AI &&
"We can't re-split our own alloca!");
5530 Worklist.insert(OtherAI);
5545 DeadInsts.push_back(LI);
5547 DeadInsts.push_back(SI);
5556 AS.insert(NewSlices);
5560 for (
auto I = AS.begin(),
E = AS.end();
I !=
E; ++
I)
5566 PromotableAllocas.set_subtract(ResplitPromotableAllocas);
5603 bool IsIntegralPointerTy =
5604 EltTy->
isPointerTy() && !
DL.isNonIntegralPointerType(EltTy);
5606 !IsIntegralPointerTy)
5613 if (
DL.getTypeSizeInBits(EltTy) !=
DL.getTypeAllocSizeInBits(EltTy))
5617 TypeSize StructSize =
DL.getStructLayout(STy)->getSizeInBytes();
5618 TypeSize VectorSize =
DL.getTypeStoreSize(VTy);
5621 if (StructSize != VectorSize)
5624 auto IsIgnorableOrMemIntrinsicSlice = [](
const Slice &S) {
5627 auto *U = S.getUse();
5631 for (
const Slice &S :
P)
5632 if (!IsIgnorableOrMemIntrinsicSlice(S))
5635 for (
const Slice *S :
P.splitSliceTails())
5636 if (!IsIgnorableOrMemIntrinsicSlice(*S))
5653static std::tuple<Type *, bool, VectorType *>
5657 VectorType *SelectedVecTy,
bool SelectedIntWidening) {
5659 dbgs() <<
"selectPartitionType path=" << Path
5664 dbgs() <<
"<unnamed>";
5665 dbgs() <<
" partition=[" <<
P.beginOffset() <<
"," <<
P.endOffset()
5666 <<
") size=" <<
P.size();
5668 dbgs() <<
" alloc-size=" << AllocSize->getKnownMinValue();
5670 dbgs() <<
" chosen=" << *SelectedTy;
5672 dbgs() <<
" vec=" << *SelectedVecTy;
5673 dbgs() <<
" intwiden=" << SelectedIntWidening <<
"\n";
5691 if (VecTy && VecTy->getElementType()->isFloatingPointTy() &&
5692 VecTy->getElementCount().getFixedValue() > 1) {
5693 LogSelection(
"direct-fp-vecty", VecTy, VecTy,
false);
5694 return {VecTy,
false, VecTy};
5699 auto [CommonUseTy, LargestIntTy] =
5702 TypeSize CommonUseSize =
DL.getTypeAllocSize(CommonUseTy);
5708 LogSelection(
"common-type-vecty", VecTy, VecTy,
false);
5709 return {VecTy,
false, VecTy};
5712 LogSelection(
"common-type", CommonUseTy,
nullptr, IntWiden);
5713 return {CommonUseTy, IntWiden,
nullptr};
5720 P.beginOffset(),
P.size())) {
5724 if (TypePartitionTy->isArrayTy() &&
5725 TypePartitionTy->getArrayElementType()->isIntegerTy() &&
5726 DL.isLegalInteger(
P.size() * 8))
5730 LogSelection(
"type-partition-int-widen", TypePartitionTy,
nullptr,
true);
5731 return {TypePartitionTy,
true,
nullptr};
5734 LogSelection(
"type-partition-vecty", VecTy, VecTy,
false);
5735 return {VecTy,
false, VecTy};
5740 DL.getTypeAllocSize(LargestIntTy).getFixedValue() >=
P.size() &&
5742 LogSelection(
"largest-int-int-widen", LargestIntTy,
nullptr,
true);
5743 return {LargestIntTy,
true,
nullptr};
5748 if (AggregateToVector) {
5751 LogSelection(
"struct-fallback-vecty", VTy,
nullptr,
false);
5752 return {VTy,
false,
nullptr};
5758 LogSelection(
"type-partition-fallback", TypePartitionTy,
nullptr,
false);
5759 return {TypePartitionTy,
false,
nullptr};
5764 DL.getTypeAllocSize(LargestIntTy).getFixedValue() >=
P.size()) {
5765 LogSelection(
"largest-int-fallback", LargestIntTy,
nullptr,
false);
5766 return {LargestIntTy,
false,
nullptr};
5770 if (
DL.isLegalInteger(
P.size() * 8)) {
5772 LogSelection(
"legal-int-fallback", IntTy,
nullptr,
false);
5773 return {IntTy,
false,
nullptr};
5778 LogSelection(
"byte-array-fallback", ArrayTy,
nullptr,
false);
5779 return {ArrayTy,
false,
nullptr};
5792std::pair<AllocaInst *, uint64_t>
5793SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS, Partition &
P) {
5794 const DataLayout &
DL = AI.getDataLayout();
5796 auto [PartitionTy, IsIntegerWideningViable, VecTy] =
5806 if (PartitionTy == AI.getAllocatedType() &&
P.beginOffset() == 0) {
5815 new AllocaInst(PartitionTy, AI.getAddressSpace(),
nullptr, Alignment,
5816 AI.getName() +
".sroa." + Twine(
P.begin() - AS.begin()),
5824 LLVM_DEBUG(
dbgs() <<
"Rewriting alloca partition " <<
"[" <<
P.beginOffset()
5825 <<
"," <<
P.endOffset() <<
") to: " << *NewAI <<
"\n");
5830 unsigned PPWOldSize = PostPromotionWorklist.size();
5831 unsigned NumUses = 0;
5832 SmallSetVector<PHINode *, 8> PHIUsers;
5833 SmallSetVector<SelectInst *, 8> SelectUsers;
5836 DL, AS, *
this, AI, *NewAI, PartitionTy,
P.beginOffset(),
P.endOffset(),
5837 IsIntegerWideningViable, VecTy, PHIUsers, SelectUsers);
5838 bool Promotable =
true;
5840 if (
auto DeletedValues =
Rewriter.rewriteTreeStructuredMerge(
P)) {
5841 NumUses += DeletedValues->
size() + 1;
5842 for (
Value *V : *DeletedValues)
5843 DeadInsts.push_back(V);
5845 for (Slice *S :
P.splitSliceTails()) {
5849 for (Slice &S :
P) {
5855 NumAllocaPartitionUses += NumUses;
5856 MaxUsesPerAllocaPartition.updateMax(NumUses);
5862 for (PHINode *
PHI : PHIUsers) {
5873 SelectUsers.
clear();
5878 NewSelectsToRewrite;
5880 for (SelectInst *Sel : SelectUsers) {
5881 std::optional<RewriteableMemOps>
Ops =
5882 isSafeSelectToSpeculateOrPredicate(*Sel, PreserveCFG);
5891 for (Use *U : AS.getDeadUsesIfPromotable()) {
5893 Value::dropDroppableUse(*U);
5896 DeadInsts.push_back(OldInst);
5898 if (NewSpeculatablePHIs.
empty() && NewPHIsWithStoreToRewrite.
empty() &&
5899 SelectUsers.empty()) {
5901 PromotableAllocas.insert(NewAI);
5906 SpeculatablePHIs.insert_range(NewSpeculatablePHIs);
5907 PHIsWithStoreToRewrite.insert_range(NewPHIsWithStoreToRewrite);
5908 SelectsToRewrite.reserve(SelectsToRewrite.size() +
5909 NewSelectsToRewrite.
size());
5911 std::make_move_iterator(NewSelectsToRewrite.
begin()),
5912 std::make_move_iterator(NewSelectsToRewrite.
end())))
5913 SelectsToRewrite.insert(std::move(KV));
5914 Worklist.insert(NewAI);
5918 while (PostPromotionWorklist.size() > PPWOldSize)
5919 PostPromotionWorklist.pop_back();
5924 return {
nullptr, 0};
5929 Worklist.insert(NewAI);
5932 return {NewAI,
DL.getTypeSizeInBits(PartitionTy).getFixedValue()};
5976 int64_t BitExtractOffset) {
5978 bool HasFragment =
false;
5979 bool HasBitExtract =
false;
5987 HasBitExtract =
true;
5988 int64_t ExtractOffsetInBits = Extract.getOffsetInBits();
5989 int64_t ExtractSizeInBits = Extract.getSizeInBits();
5998 assert(BitExtractOffset <= 0);
5999 int64_t AdjustedOffset = ExtractOffsetInBits + BitExtractOffset;
6005 if (AdjustedOffset < 0)
6008 Ops.push_back(
Op.getOp());
6009 Ops.push_back(std::max<int64_t>(0, AdjustedOffset));
6010 Ops.push_back(ExtractSizeInBits);
6013 Op.appendToVector(
Ops);
6018 if (HasFragment && HasBitExtract)
6021 if (!HasBitExtract) {
6040 std::optional<DIExpression::FragmentInfo> NewFragment,
6041 int64_t BitExtractAdjustment) {
6051 BitExtractAdjustment);
6052 if (!NewFragmentExpr)
6058 BeforeInst->
getParent()->insertDbgRecordBefore(DVR,
6071 BeforeInst->
getParent()->insertDbgRecordBefore(DVR,
6077 if (!NewAddr->
hasMetadata(LLVMContext::MD_DIAssignID)) {
6085 LLVM_DEBUG(
dbgs() <<
"Created new DVRAssign: " << *NewAssign <<
"\n");
6091bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
6092 if (AS.begin() == AS.end())
6095 unsigned NumPartitions = 0;
6097 const DataLayout &
DL = AI.getDataLayout();
6100 Changed |= presplitLoadsAndStores(AI, AS);
6108 bool IsSorted =
true;
6110 uint64_t AllocaSize = AI.getAllocationSize(
DL)->getFixedValue();
6118 SparseBitVector<> SplittableOffset;
6120 for (Slice &S : AS) {
6122 if (S.beginOffset() > CurBegin || S.endOffset() > CurEnd) {
6124 if (S.beginOffset() >= CurEnd) {
6125 SplittableOffset.
set(S.beginOffset());
6128 if (CurEnd > S.beginOffset() && CurEnd < S.endOffset()) {
6129 SplittableOffset.
reset(CurEnd);
6131 CurBegin = S.beginOffset();
6135 if (S.endOffset() > CurEnd) {
6136 CurEnd = S.endOffset();
6137 SplittableOffset.
set(CurEnd);
6142 for (Slice &S : AS) {
6143 if (!S.isSplittable())
6146 if ((S.beginOffset() > AllocaSize ||
6147 SplittableOffset.
test(S.beginOffset())) &&
6148 (S.endOffset() > AllocaSize || SplittableOffset.
test(S.endOffset())))
6153 S.makeUnsplittable();
6173 for (
auto &
P : AS.partitions()) {
6174 auto [NewAI, ActiveBits] = rewritePartition(AI, AS, P);
6178 uint64_t SizeOfByte = 8;
6180 uint64_t Size = std::min(ActiveBits, P.size() * SizeOfByte);
6181 Fragments.push_back(
6182 Fragment(NewAI, P.beginOffset() * SizeOfByte, Size));
6188 NumAllocaPartitions += NumPartitions;
6189 MaxPartitionsPerAlloca.updateMax(NumPartitions);
6193 auto MigrateOne = [&](DbgVariableRecord *DbgVariable) {
6198 const Value *DbgPtr = DbgVariable->getAddress();
6200 DbgVariable->getFragmentOrEntireVariable();
6203 int64_t CurrentExprOffsetInBytes = 0;
6204 SmallVector<uint64_t> PostOffsetOps;
6206 ->extractLeadingOffset(CurrentExprOffsetInBytes, PostOffsetOps))
6210 int64_t ExtractOffsetInBits = 0;
6213 ExtractOffsetInBits = Extract.getOffsetInBits();
6218 DIBuilder DIB(*AI.getModule(),
false);
6220 int64_t OffsetFromLocationInBits;
6221 std::optional<DIExpression::FragmentInfo> NewDbgFragment;
6227 CurrentExprOffsetInBytes * 8, ExtractOffsetInBits, VarFrag,
6228 NewDbgFragment, OffsetFromLocationInBits))
6234 if (NewDbgFragment && !NewDbgFragment->SizeInBits)
6239 if (!NewDbgFragment)
6240 NewDbgFragment = DbgVariable->getFragment();
6244 int64_t OffestFromNewAllocaInBits =
6245 OffsetFromLocationInBits - ExtractOffsetInBits;
6248 int64_t BitExtractOffset =
6249 std::min<int64_t>(0, OffestFromNewAllocaInBits);
6254 OffestFromNewAllocaInBits =
6255 std::max(int64_t(0), OffestFromNewAllocaInBits);
6261 DIExpression *NewExpr = DIExpression::get(AI.getContext(), PostOffsetOps);
6262 if (OffestFromNewAllocaInBits > 0) {
6263 int64_t OffsetInBytes = (OffestFromNewAllocaInBits + 7) / 8;
6269 auto RemoveOne = [DbgVariable](
auto *OldDII) {
6270 auto SameVariableFragment = [](
const auto *
LHS,
const auto *
RHS) {
6271 return LHS->getVariable() ==
RHS->getVariable() &&
6272 LHS->getDebugLoc()->getInlinedAt() ==
6273 RHS->getDebugLoc()->getInlinedAt();
6275 if (SameVariableFragment(OldDII, DbgVariable))
6276 OldDII->eraseFromParent();
6281 NewDbgFragment, BitExtractOffset);
6295void SROA::clobberUse(Use &U) {
6305 DeadInsts.push_back(OldI);
6327bool SROA::propagateStoredValuesToLoads(AllocaInst &AI, AllocaSlices &AS) {
6332 LLVM_DEBUG(
dbgs() <<
"Attempting to propagate values on " << AI <<
"\n");
6333 bool AllSameAndValid =
true;
6334 Type *PartitionType =
nullptr;
6335 SmallVector<Instruction *> Insts;
6339 auto Flush = [&]() {
6340 if (AllSameAndValid && !Insts.
empty()) {
6341 LLVM_DEBUG(
dbgs() <<
"Propagate values on slice [" << BeginOffset <<
", "
6342 << EndOffset <<
")\n");
6344 SSAUpdater
SSA(&NewPHIs);
6346 BasicLoadAndStorePromoter Promoter(Insts,
SSA, PartitionType);
6347 Promoter.run(Insts);
6349 AllSameAndValid =
true;
6350 PartitionType =
nullptr;
6354 for (Slice &S : AS) {
6358 dbgs() <<
"Ignoring slice: ";
6359 AS.print(
dbgs(), &S);
6363 if (S.beginOffset() >= EndOffset) {
6365 BeginOffset = S.beginOffset();
6366 EndOffset = S.endOffset();
6367 }
else if (S.beginOffset() != BeginOffset || S.endOffset() != EndOffset) {
6368 if (AllSameAndValid) {
6370 dbgs() <<
"Slice does not match range [" << BeginOffset <<
", "
6371 << EndOffset <<
")";
6372 AS.print(
dbgs(), &S);
6374 AllSameAndValid =
false;
6376 EndOffset = std::max(EndOffset, S.endOffset());
6383 if (!LI->
isSimple() || (PartitionType && UserTy != PartitionType))
6384 AllSameAndValid =
false;
6385 PartitionType = UserTy;
6388 Type *UserTy =
SI->getValueOperand()->getType();
6389 if (!
SI->isSimple() || (PartitionType && UserTy != PartitionType))
6390 AllSameAndValid =
false;
6391 PartitionType = UserTy;
6394 AllSameAndValid =
false;
6407std::pair<
bool ,
bool >
6408SROA::runOnAlloca(AllocaInst &AI) {
6410 bool CFGChanged =
false;
6413 ++NumAllocasAnalyzed;
6416 if (AI.use_empty()) {
6417 AI.eraseFromParent();
6421 const DataLayout &
DL = AI.getDataLayout();
6424 std::optional<TypeSize>
Size = AI.getAllocationSize(
DL);
6425 if (AI.isArrayAllocation() || !
Size ||
Size->isScalable() ||
Size->isZero())
6430 IRBuilderTy IRB(&AI);
6431 AggLoadStoreRewriter AggRewriter(
DL, IRB);
6432 Changed |= AggRewriter.rewrite(AI);
6435 AllocaSlices AS(
DL, AI);
6440 if (AS.isEscapedReadOnly()) {
6441 Changed |= propagateStoredValuesToLoads(AI, AS);
6446 for (Instruction *DeadUser : AS.getDeadUsers()) {
6448 for (Use &DeadOp : DeadUser->operands())
6455 DeadInsts.push_back(DeadUser);
6458 for (Use *DeadOp : AS.getDeadOperands()) {
6459 clobberUse(*DeadOp);
6464 if (AS.begin() == AS.end())
6467 Changed |= splitAlloca(AI, AS);
6470 while (!SpeculatablePHIs.empty())
6474 auto RemainingPHIsWithStoreToRewrite = PHIsWithStoreToRewrite.takeVector();
6475 while (!RemainingPHIsWithStoreToRewrite.empty()) {
6476 PHINode *PN = RemainingPHIsWithStoreToRewrite.pop_back_val();
6482 auto RemainingSelectsToRewrite = SelectsToRewrite.takeVector();
6483 while (!RemainingSelectsToRewrite.empty()) {
6484 const auto [
K,
V] = RemainingSelectsToRewrite.pop_back_val();
6501bool SROA::deleteDeadInstructions(
6502 SmallPtrSetImpl<AllocaInst *> &DeletedAllocas) {
6504 while (!DeadInsts.empty()) {
6514 DeletedAllocas.
insert(AI);
6516 OldDII->eraseFromParent();
6522 for (Use &Operand :
I->operands())
6527 DeadInsts.push_back(U);
6531 I->eraseFromParent();
6541bool SROA::promoteAllocas() {
6542 if (PromotableAllocas.empty())
6549 NumPromoted += PromotableAllocas.size();
6550 PromoteMemToReg(PromotableAllocas.getArrayRef(), DTU->getDomTree(), AC);
6553 PromotableAllocas.clear();
6557std::pair<
bool ,
bool > SROA::runSROA(
Function &
F) {
6560 const DataLayout &
DL =
F.getDataLayout();
6565 std::optional<TypeSize>
Size = AI->getAllocationSize(
DL);
6567 PromotableAllocas.insert(AI);
6569 Worklist.insert(AI);
6574 bool CFGChanged =
false;
6577 SmallPtrSet<AllocaInst *, 4> DeletedAllocas;
6580 while (!Worklist.empty()) {
6581 auto [IterationChanged, IterationCFGChanged] =
6582 runOnAlloca(*Worklist.pop_back_val());
6584 CFGChanged |= IterationCFGChanged;
6586 Changed |= deleteDeadInstructions(DeletedAllocas);
6590 if (!DeletedAllocas.
empty()) {
6591 Worklist.set_subtract(DeletedAllocas);
6592 PostPromotionWorklist.set_subtract(DeletedAllocas);
6593 PromotableAllocas.set_subtract(DeletedAllocas);
6594 DeletedAllocas.
clear();
6600 Worklist = PostPromotionWorklist;
6601 PostPromotionWorklist.clear();
6602 }
while (!Worklist.empty());
6604 assert((!CFGChanged ||
Changed) &&
"Can not only modify the CFG.");
6605 assert((!CFGChanged || !PreserveCFG) &&
6606 "Should not have modified the CFG when told to preserve it.");
6609 for (
auto &BB :
F) {
6622 SROA(&
F.getContext(), &DTU, &AC, Options).runSROA(
F);
6634 static_cast<PassInfoMixin<SROAPass> *
>(
this)->
printPipeline(
6635 OS, MapClassName2PassName);
6639 if (Options.AggregateToVector)
6640 OS <<
";aggregate-to-vector";
6661 if (skipFunction(
F))
6664 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
6666 getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
6672 void getAnalysisUsage(AnalysisUsage &AU)
const override {
6679 StringRef getPassName()
const override {
return "SROA"; }
6684char SROALegacyPass::ID = 0;
6689 AggregateToVector));
6693 "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.
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.