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 loads to allow promotion");
118STATISTIC(NumVectorized,
"Number of vectorized aggregates");
129class AllocaSliceRewriter;
133class SelectHandSpeculativity {
134 unsigned char Storage = 0;
138 SelectHandSpeculativity() =
default;
139 SelectHandSpeculativity &setAsSpeculatable(
bool isTrueVal);
140 bool isSpeculatable(
bool isTrueVal)
const;
141 bool areAllSpeculatable()
const;
142 bool areAnySpeculatable()
const;
143 bool areNoneSpeculatable()
const;
145 explicit operator intptr_t()
const {
return static_cast<intptr_t
>(Storage); }
146 explicit SelectHandSpeculativity(intptr_t Storage_) : Storage(Storage_) {}
148static_assert(
sizeof(SelectHandSpeculativity) ==
sizeof(
unsigned char));
150using PossiblySpeculatableLoad =
153using RewriteableMemOp =
154 std::variant<PossiblySpeculatableLoad, UnspeculatableStore>;
176 LLVMContext *
const C;
177 DomTreeUpdater *
const DTU;
178 AssumptionCache *
const AC;
179 const bool PreserveCFG;
180 const bool AggregateToVector;
189 SmallSetVector<AllocaInst *, 16> Worklist;
204 SmallSetVector<AllocaInst *, 16> PostPromotionWorklist;
207 SetVector<AllocaInst *, SmallVector<AllocaInst *>,
208 SmallPtrSet<AllocaInst *, 16>, 16>
216 SmallSetVector<PHINode *, 8> SpeculatablePHIs;
220 SmallMapVector<SelectInst *, RewriteableMemOps, 8> SelectsToRewrite;
238 static std::optional<RewriteableMemOps>
239 isSafeSelectToSpeculate(SelectInst &SI,
bool PreserveCFG);
242 SROA(LLVMContext *C, DomTreeUpdater *DTU, AssumptionCache *AC,
244 : C(C), DTU(DTU), AC(AC),
245 PreserveCFG(
Options.
CFG == SROAOptions::PreserveCFG),
246 AggregateToVector(
Options.AggregateToVector) {}
249 std::pair<
bool ,
bool > runSROA(
Function &
F);
252 friend class AllocaSliceRewriter;
254 bool presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS);
255 std::pair<AllocaInst *, uint64_t>
256 rewritePartition(AllocaInst &AI, AllocaSlices &AS, Partition &
P);
257 bool splitAlloca(AllocaInst &AI, AllocaSlices &AS);
258 bool propagateStoredValuesToLoads(AllocaInst &AI, AllocaSlices &AS);
259 std::pair<
bool ,
bool > runOnAlloca(AllocaInst &AI);
260 void clobberUse(Use &U);
261 bool deleteDeadInstructions(SmallPtrSetImpl<AllocaInst *> &DeletedAllocas);
262 bool promoteAllocas();
276enum FragCalcResult { UseFrag, UseNoFrag,
Skip };
280 uint64_t NewStorageSliceOffsetInBits,
282 std::optional<DIExpression::FragmentInfo> StorageFragment,
283 std::optional<DIExpression::FragmentInfo> CurrentFragment,
287 if (StorageFragment) {
289 std::min(NewStorageSliceSizeInBits, StorageFragment->SizeInBits);
291 NewStorageSliceOffsetInBits + StorageFragment->OffsetInBits;
293 Target.SizeInBits = NewStorageSliceSizeInBits;
294 Target.OffsetInBits = NewStorageSliceOffsetInBits;
300 if (!CurrentFragment) {
301 if (
auto Size = Variable->getSizeInBits()) {
304 if (
Target == CurrentFragment)
311 if (!CurrentFragment || *CurrentFragment ==
Target)
317 if (
Target.startInBits() < CurrentFragment->startInBits() ||
318 Target.endInBits() > CurrentFragment->endInBits())
357 if (DVRAssignMarkerRange.empty())
363 LLVM_DEBUG(
dbgs() <<
" OldAllocaOffsetInBits: " << OldAllocaOffsetInBits
365 LLVM_DEBUG(
dbgs() <<
" SliceSizeInBits: " << SliceSizeInBits <<
"\n");
377 DVR->getExpression()->getFragmentInfo();
390 auto *Expr = DbgAssign->getExpression();
391 bool SetKillLocation =
false;
394 std::optional<DIExpression::FragmentInfo> BaseFragment;
397 if (R == BaseFragments.
end())
399 BaseFragment = R->second;
401 std::optional<DIExpression::FragmentInfo> CurrentFragment =
402 Expr->getFragmentInfo();
405 DbgAssign->getVariable(), OldAllocaOffsetInBits, SliceSizeInBits,
406 BaseFragment, CurrentFragment, NewFragment);
410 if (Result == UseFrag && !(NewFragment == CurrentFragment)) {
411 if (CurrentFragment) {
416 NewFragment.
OffsetInBits -= CurrentFragment->OffsetInBits;
429 SetKillLocation =
true;
437 Inst->
setMetadata(LLVMContext::MD_DIAssignID, NewID);
444 Inst, NewValue, DbgAssign->getVariable(), Expr, Dest,
448 NewAssign = DbgAssign;
467 Value && (DbgAssign->hasArgList() ||
468 !DbgAssign->getExpression()->isSingleLocationExpression());
485 if (NewAssign != DbgAssign) {
486 NewAssign->
moveBefore(DbgAssign->getIterator());
489 LLVM_DEBUG(
dbgs() <<
"Created new assign: " << *NewAssign <<
"\n");
492 for_each(DVRAssignMarkerRange, MigrateDbgAssign);
502 Twine getNameWithPrefix(
const Twine &Name)
const {
507 void SetNamePrefix(
const Twine &
P) { Prefix =
P.str(); }
509 void InsertHelper(Instruction *
I,
const Twine &Name,
534 PointerIntPair<Use *, 1, bool> UseAndIsSplittable;
540 : BeginOffset(BeginOffset), EndOffset(EndOffset),
541 UseAndIsSplittable(
U, IsSplittable) {}
543 uint64_t beginOffset()
const {
return BeginOffset; }
544 uint64_t endOffset()
const {
return EndOffset; }
546 bool isSplittable()
const {
return UseAndIsSplittable.getInt(); }
547 void makeUnsplittable() { UseAndIsSplittable.setInt(
false); }
549 Use *getUse()
const {
return UseAndIsSplittable.getPointer(); }
551 bool isDead()
const {
return getUse() ==
nullptr; }
552 void kill() { UseAndIsSplittable.setPointer(
nullptr); }
561 if (beginOffset() <
RHS.beginOffset())
563 if (beginOffset() >
RHS.beginOffset())
565 if (isSplittable() !=
RHS.isSplittable())
566 return !isSplittable();
567 if (endOffset() >
RHS.endOffset())
574 return LHS.beginOffset() < RHSOffset;
577 return LHSOffset <
RHS.beginOffset();
581 return isSplittable() ==
RHS.isSplittable() &&
582 beginOffset() ==
RHS.beginOffset() && endOffset() ==
RHS.endOffset();
597 AllocaSlices(
const DataLayout &
DL, AllocaInst &AI);
603 bool isEscaped()
const {
return PointerEscapingInstr; }
604 bool isEscapedReadOnly()
const {
return PointerEscapingInstrReadOnly; }
609 using range = iterator_range<iterator>;
611 iterator
begin() {
return Slices.begin(); }
612 iterator
end() {
return Slices.end(); }
615 using const_range = iterator_range<const_iterator>;
617 const_iterator
begin()
const {
return Slices.begin(); }
618 const_iterator
end()
const {
return Slices.end(); }
622 void erase(iterator Start, iterator Stop) { Slices.erase(Start, Stop); }
630 int OldSize = Slices.size();
631 Slices.append(NewSlices.
begin(), NewSlices.
end());
632 auto SliceI = Slices.begin() + OldSize;
633 std::stable_sort(SliceI, Slices.end());
634 std::inplace_merge(Slices.begin(), SliceI, Slices.end());
647 return DeadUseIfPromotable;
658#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
659 void print(raw_ostream &OS, const_iterator
I, StringRef Indent =
" ")
const;
660 void printSlice(raw_ostream &OS, const_iterator
I,
661 StringRef Indent =
" ")
const;
662 void printUse(raw_ostream &OS, const_iterator
I,
663 StringRef Indent =
" ")
const;
664 void print(raw_ostream &OS)
const;
665 void dump(const_iterator
I)
const;
670 template <
typename DerivedT,
typename RetT =
void>
class BuilderBase;
673 friend class AllocaSlices::SliceBuilder;
675#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
703 SmallVector<Instruction *, 8> DeadUsers;
730 friend class AllocaSlices;
731 friend class AllocaSlices::partition_iterator;
733 using iterator = AllocaSlices::iterator;
737 uint64_t BeginOffset = 0, EndOffset = 0;
747 Partition(iterator SI) : SI(SI), SJ(SI) {}
753 uint64_t beginOffset()
const {
return BeginOffset; }
758 uint64_t endOffset()
const {
return EndOffset; }
764 assert(BeginOffset < EndOffset &&
"Partitions must span some bytes!");
765 return EndOffset - BeginOffset;
770 bool empty()
const {
return SI == SJ; }
781 iterator
begin()
const {
return SI; }
782 iterator
end()
const {
return SJ; }
814 AllocaSlices::iterator SE;
818 uint64_t MaxSplitSliceEndOffset = 0;
822 partition_iterator(AllocaSlices::iterator
SI, AllocaSlices::iterator SE)
834 assert((
P.SI != SE || !
P.SplitTails.empty()) &&
835 "Cannot advance past the end of the slices!");
838 if (!
P.SplitTails.empty()) {
839 if (
P.EndOffset >= MaxSplitSliceEndOffset) {
841 P.SplitTails.clear();
842 MaxSplitSliceEndOffset = 0;
848 [&](Slice *S) { return S->endOffset() <= P.EndOffset; });
851 return S->endOffset() == MaxSplitSliceEndOffset;
853 "Could not find the current max split slice offset!");
856 return S->endOffset() <= MaxSplitSliceEndOffset;
858 "Max split slice end offset is not actually the max!");
865 assert(P.SplitTails.empty() &&
"Failed to clear the split slices!");
875 if (S.isSplittable() && S.endOffset() > P.EndOffset) {
876 P.SplitTails.push_back(&S);
877 MaxSplitSliceEndOffset =
878 std::max(S.endOffset(), MaxSplitSliceEndOffset);
886 P.BeginOffset = P.EndOffset;
887 P.EndOffset = MaxSplitSliceEndOffset;
894 if (!P.SplitTails.empty() && P.SI->beginOffset() != P.EndOffset &&
895 !P.SI->isSplittable()) {
896 P.BeginOffset = P.EndOffset;
897 P.EndOffset = P.SI->beginOffset();
907 P.BeginOffset = P.SplitTails.empty() ? P.SI->beginOffset() : P.EndOffset;
908 P.EndOffset = P.SI->endOffset();
913 if (!P.SI->isSplittable()) {
916 assert(P.BeginOffset == P.SI->beginOffset());
920 while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) {
921 if (!P.SJ->isSplittable())
922 P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset());
934 assert(P.SI->isSplittable() &&
"Forming a splittable partition!");
937 while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset &&
938 P.SJ->isSplittable()) {
939 P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset());
946 if (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) {
947 assert(!P.SJ->isSplittable());
948 P.EndOffset = P.SJ->beginOffset();
955 "End iterators don't match between compared partition iterators!");
962 if (P.SI == RHS.P.SI && P.SplitTails.empty() == RHS.P.SplitTails.empty()) {
963 assert(P.SJ == RHS.P.SJ &&
964 "Same set of slices formed two different sized partitions!");
965 assert(P.SplitTails.size() == RHS.P.SplitTails.size() &&
966 "Same slice position with differently sized non-empty split "
989 return make_range(partition_iterator(begin(), end()),
990 partition_iterator(end(), end()));
998 return SI.getOperand(1 + CI->isZero());
999 if (
SI.getOperand(1) ==
SI.getOperand(2))
1000 return SI.getOperand(1);
1009 return PN->hasConstantValue();
1024 const uint64_t AllocSize;
1040 if (VisitedDeadInsts.
insert(&
I).second)
1045 bool IsSplittable =
false) {
1051 <<
" which has zero size or starts outside of the "
1052 << AllocSize <<
" byte alloca:\n"
1053 <<
" alloca: " << AS.AI <<
"\n"
1054 <<
" use: " <<
I <<
"\n");
1055 return markAsDead(
I);
1067 assert(AllocSize >= BeginOffset);
1068 if (
Size > AllocSize - BeginOffset) {
1070 <<
Offset <<
" to remain within the " << AllocSize
1071 <<
" byte alloca:\n"
1072 <<
" alloca: " << AS.AI <<
"\n"
1073 <<
" use: " <<
I <<
"\n");
1074 EndOffset = AllocSize;
1077 AS.Slices.push_back(Slice(BeginOffset, EndOffset, U, IsSplittable));
1080 void visitBitCastInst(BitCastInst &BC) {
1082 return markAsDead(BC);
1084 return Base::visitBitCastInst(BC);
1087 void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
1089 return markAsDead(ASC);
1091 return Base::visitAddrSpaceCastInst(ASC);
1094 void visitGetElementPtrInst(GetElementPtrInst &GEPI) {
1096 return markAsDead(GEPI);
1098 return Base::visitGetElementPtrInst(GEPI);
1101 void handleLoadOrStore(
Type *Ty, Instruction &
I,
const APInt &
Offset,
1112 void visitLoadInst(LoadInst &LI) {
1114 "All simple FCA loads should have been pre-split");
1119 return PI.setEscapedReadOnly(&LI);
1122 if (
Size.isScalable()) {
1125 return PI.setAborted(&LI);
1134 void visitStoreInst(StoreInst &SI) {
1135 Value *ValOp =
SI.getValueOperand();
1137 return PI.setEscapedAndAborted(&SI);
1139 return PI.setAborted(&SI);
1141 TypeSize StoreSize =
DL.getTypeStoreSize(ValOp->
getType());
1143 unsigned VScale =
SI.getFunction()->getVScaleValue();
1145 return PI.setAborted(&SI);
1161 <<
Offset <<
" which extends past the end of the "
1162 << AllocSize <<
" byte alloca:\n"
1163 <<
" alloca: " << AS.AI <<
"\n"
1164 <<
" use: " << SI <<
"\n");
1165 return markAsDead(SI);
1169 "All simple FCA stores should have been pre-split");
1173 void visitMemSetInst(MemSetInst &
II) {
1174 assert(
II.getRawDest() == *U &&
"Pointer use is not the destination?");
1177 (IsOffsetKnown &&
Offset.uge(AllocSize)))
1179 return markAsDead(
II);
1182 return PI.setAborted(&
II);
1186 : AllocSize -
Offset.getLimitedValue(),
1190 void visitMemTransferInst(MemTransferInst &
II) {
1194 return markAsDead(
II);
1198 if (VisitedDeadInsts.
count(&
II))
1202 return PI.setAborted(&
II);
1209 if (
Offset.uge(AllocSize)) {
1210 auto MTPI = MemTransferSliceMap.
find(&
II);
1211 if (MTPI != MemTransferSliceMap.
end())
1212 AS.Slices[MTPI->second].kill();
1213 return markAsDead(
II);
1221 if (*U ==
II.getRawDest() && *U ==
II.getRawSource()) {
1223 if (!
II.isVolatile())
1224 return markAsDead(
II);
1232 SmallDenseMap<Instruction *, unsigned>::iterator MTPI;
1233 std::tie(MTPI, Inserted) =
1234 MemTransferSliceMap.
insert(std::make_pair(&
II, AS.Slices.size()));
1235 unsigned PrevIdx = MTPI->second;
1237 Slice &PrevP = AS.Slices[PrevIdx];
1241 if (!
II.isVolatile() && PrevP.beginOffset() == RawOffset) {
1243 return markAsDead(
II);
1248 PrevP.makeUnsplittable();
1255 assert(AS.Slices[PrevIdx].getUse()->getUser() == &
II &&
1256 "Map index doesn't point back to a slice with this user.");
1262 void visitIntrinsicInst(IntrinsicInst &
II) {
1263 if (
II.isDroppable()) {
1264 AS.DeadUseIfPromotable.push_back(U);
1269 return PI.setAborted(&
II);
1271 if (
II.isLifetimeStartOrEnd()) {
1272 insertUse(
II,
Offset, AllocSize,
true);
1276 Base::visitIntrinsicInst(
II);
1284 SmallPtrSet<Instruction *, 4> Visited;
1294 std::tie(UsedI,
I) =
Uses.pop_back_val();
1297 TypeSize LoadSize =
DL.getTypeStoreSize(LI->
getType());
1309 TypeSize StoreSize =
DL.getTypeStoreSize(
Op->getType());
1319 if (!
GEP->hasAllZeroIndices())
1326 for (User *U :
I->users())
1329 }
while (!
Uses.empty());
1334 void visitPHINodeOrSelectInst(Instruction &
I) {
1337 return markAsDead(
I);
1343 return PI.setAborted(&
I);
1361 AS.DeadOperands.push_back(U);
1367 return PI.setAborted(&
I);
1373 if (Instruction *UnsafeI = hasUnsafePHIOrSelectUse(&
I,
Size))
1374 return PI.setAborted(UnsafeI);
1383 if (
Offset.uge(AllocSize)) {
1384 AS.DeadOperands.push_back(U);
1391 void visitPHINode(PHINode &PN) { visitPHINodeOrSelectInst(PN); }
1393 void visitSelectInst(SelectInst &SI) { visitPHINodeOrSelectInst(SI); }
1396 void visitInstruction(Instruction &
I) { PI.setAborted(&
I); }
1398 void visitCallBase(CallBase &CB) {
1404 PI.setEscapedReadOnly(&CB);
1408 Base::visitCallBase(CB);
1412AllocaSlices::AllocaSlices(
const DataLayout &
DL, AllocaInst &AI)
1414#
if !defined(
NDEBUG) || defined(LLVM_ENABLE_DUMP)
1417 PointerEscapingInstr(nullptr), PointerEscapingInstrReadOnly(nullptr) {
1419 SliceBuilder::PtrInfo PtrI =
PB.visitPtr(AI);
1420 if (PtrI.isEscaped() || PtrI.isAborted()) {
1423 PointerEscapingInstr = PtrI.getEscapingInst() ? PtrI.getEscapingInst()
1424 : PtrI.getAbortingInst();
1425 assert(PointerEscapingInstr &&
"Did not track a bad instruction");
1428 PointerEscapingInstrReadOnly = PtrI.getEscapedReadOnlyInst();
1430 llvm::erase_if(Slices, [](
const Slice &S) {
return S.isDead(); });
1437#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1439void AllocaSlices::print(raw_ostream &OS, const_iterator
I,
1440 StringRef Indent)
const {
1441 printSlice(OS,
I, Indent);
1443 printUse(OS,
I, Indent);
1446void AllocaSlices::printSlice(raw_ostream &OS, const_iterator
I,
1447 StringRef Indent)
const {
1448 OS << Indent <<
"[" <<
I->beginOffset() <<
"," <<
I->endOffset() <<
")"
1449 <<
" slice #" << (
I -
begin())
1450 << (
I->isSplittable() ?
" (splittable)" :
"");
1453void AllocaSlices::printUse(raw_ostream &OS, const_iterator
I,
1454 StringRef Indent)
const {
1455 OS << Indent <<
" used by: " << *
I->getUse()->getUser() <<
"\n";
1458void AllocaSlices::print(raw_ostream &OS)
const {
1459 if (PointerEscapingInstr) {
1460 OS <<
"Can't analyze slices for alloca: " << AI <<
"\n"
1461 <<
" A pointer to this alloca escaped by:\n"
1462 <<
" " << *PointerEscapingInstr <<
"\n";
1466 if (PointerEscapingInstrReadOnly)
1467 OS <<
"Escapes into ReadOnly: " << *PointerEscapingInstrReadOnly <<
"\n";
1469 OS <<
"Slices of alloca: " << AI <<
"\n";
1483static std::pair<Type *, IntegerType *>
1487 bool TyIsCommon =
true;
1492 for (AllocaSlices::const_iterator
I =
B;
I !=
E; ++
I) {
1493 Use *U =
I->getUse();
1496 if (
I->beginOffset() !=
B->beginOffset() ||
I->endOffset() != EndOffset)
1499 Type *UserTy =
nullptr;
1503 UserTy =
SI->getValueOperand()->getType();
1511 if (UserITy->getBitWidth() % 8 != 0 ||
1512 UserITy->getBitWidth() / 8 > (EndOffset -
B->beginOffset()))
1517 if (!ITy || ITy->
getBitWidth() < UserITy->getBitWidth())
1523 if (!UserTy || (Ty && Ty != UserTy))
1529 return {TyIsCommon ? Ty :
nullptr, ITy};
1560 Type *LoadType =
nullptr;
1573 if (LoadType != LI->
getType())
1582 if (BBI->mayWriteToMemory())
1585 MaxAlign = std::max(MaxAlign, LI->
getAlign());
1592 APInt(APWidth,
DL.getTypeStoreSize(LoadType).getFixedValue());
1630 IRB.SetInsertPoint(&PN);
1632 PN.
getName() +
".sroa.speculated");
1662 IRB.SetInsertPoint(TI);
1665 LoadTy, InVal, Alignment,
1666 (PN.
getName() +
".sroa.speculate.load." + Pred->getName()));
1667 ++NumLoadsSpeculated;
1669 Load->setAAMetadata(AATags);
1671 InjectedLoads[Pred] =
Load;
1678SelectHandSpeculativity &
1679SelectHandSpeculativity::setAsSpeculatable(
bool isTrueVal) {
1687bool SelectHandSpeculativity::isSpeculatable(
bool isTrueVal)
const {
1692bool SelectHandSpeculativity::areAllSpeculatable()
const {
1693 return isSpeculatable(
true) &&
1694 isSpeculatable(
false);
1697bool SelectHandSpeculativity::areAnySpeculatable()
const {
1698 return isSpeculatable(
true) ||
1699 isSpeculatable(
false);
1701bool SelectHandSpeculativity::areNoneSpeculatable()
const {
1702 return !areAnySpeculatable();
1705static SelectHandSpeculativity
1708 SelectHandSpeculativity
Spec;
1714 Spec.setAsSpeculatable(
Value ==
SI.getTrueValue());
1715 else if (PreserveCFG)
1721std::optional<RewriteableMemOps>
1722SROA::isSafeSelectToSpeculate(SelectInst &SI,
bool PreserveCFG) {
1723 RewriteableMemOps
Ops;
1725 for (User *U :
SI.users()) {
1733 if (
Store->isVolatile() || PreserveCFG)
1746 PossiblySpeculatableLoad
Load(LI);
1756 SelectHandSpeculativity Spec =
1758 if (PreserveCFG && !Spec.areAllSpeculatable())
1772 Value *TV =
SI.getTrueValue();
1773 Value *FV =
SI.getFalseValue();
1778 IRB.SetInsertPoint(&LI);
1782 LI.
getName() +
".sroa.speculate.load.true");
1785 LI.
getName() +
".sroa.speculate.load.false");
1786 NumLoadsSpeculated += 2;
1798 Value *V = IRB.CreateSelect(
SI.getCondition(), TL, FL,
1799 LI.
getName() +
".sroa.speculated",
1806template <
typename T>
1808 SelectHandSpeculativity
Spec,
1815 if (
Spec.areNoneSpeculatable())
1817 SI.getMetadata(LLVMContext::MD_prof), &DTU);
1820 SI.getMetadata(LLVMContext::MD_prof), &DTU,
1822 if (
Spec.isSpeculatable(
true))
1828 Tail->setName(Head->
getName() +
".cont");
1833 bool IsThen = SuccBB == HeadBI->getSuccessor(0);
1834 int SuccIdx = IsThen ? 0 : 1;
1835 auto *NewMemOpBB = SuccBB == Tail ? Head : SuccBB;
1836 auto &CondMemOp =
cast<T>(*
I.clone());
1837 if (NewMemOpBB != Head) {
1838 NewMemOpBB->setName(Head->
getName() + (IsThen ?
".then" :
".else"));
1840 ++NumLoadsPredicated;
1842 ++NumStoresPredicated;
1844 CondMemOp.dropUBImplyingAttrsAndMetadata();
1845 ++NumLoadsSpeculated;
1847 CondMemOp.insertBefore(NewMemOpBB->getTerminator()->getIterator());
1848 Value *Ptr =
SI.getOperand(1 + SuccIdx);
1849 CondMemOp.setOperand(
I.getPointerOperandIndex(), Ptr);
1851 CondMemOp.setName(
I.getName() + (IsThen ?
".then" :
".else") +
".val");
1859 I.replaceAllUsesWith(PN);
1864 SelectHandSpeculativity
Spec,
1875 const RewriteableMemOps &
Ops,
1877 bool CFGChanged =
false;
1880 for (
const RewriteableMemOp &
Op :
Ops) {
1881 SelectHandSpeculativity
Spec;
1883 if (
auto *
const *US = std::get_if<UnspeculatableStore>(&
Op)) {
1886 auto PSL = std::get<PossiblySpeculatableLoad>(
Op);
1887 I = PSL.getPointer();
1888 Spec = PSL.getInt();
1890 if (
Spec.areAllSpeculatable()) {
1893 assert(DTU &&
"Should not get here when not allowed to modify the CFG!");
1897 I->eraseFromParent();
1902 SI.eraseFromParent();
1910 const Twine &NamePrefix) {
1912 Ptr = IRB.CreateInBoundsPtrAdd(Ptr, IRB.getInt(
Offset),
1913 NamePrefix +
"sroa_idx");
1914 return IRB.CreatePointerBitCastOrAddrSpaceCast(Ptr,
PointerTy,
1915 NamePrefix +
"sroa_cast");
1930 unsigned VScale = 0) {
1940 "We can't have the same bitwidth for different int types");
1944 TypeSize NewSize =
DL.getTypeSizeInBits(NewTy);
1945 TypeSize OldSize =
DL.getTypeSizeInBits(OldTy);
1972 if (NewSize != OldSize)
1988 return OldAS == NewAS ||
1989 (!
DL.isNonIntegralAddressSpace(OldAS) &&
1990 !
DL.isNonIntegralAddressSpace(NewAS) &&
1991 DL.getPointerSize(OldAS) ==
DL.getPointerSize(NewAS));
1997 return !
DL.isNonIntegralPointerType(NewTy);
2001 if (!
DL.isNonIntegralPointerType(OldTy))
2024 std::max(S.beginOffset(),
P.beginOffset()) -
P.beginOffset();
2025 uint64_t BeginIndex = BeginOffset / ElementSize;
2026 if (BeginIndex * ElementSize != BeginOffset ||
2029 uint64_t EndOffset = std::min(S.endOffset(),
P.endOffset()) -
P.beginOffset();
2030 uint64_t EndIndex = EndOffset / ElementSize;
2031 if (EndIndex * ElementSize != EndOffset ||
2035 assert(EndIndex > BeginIndex &&
"Empty vector!");
2036 uint64_t NumElements = EndIndex - BeginIndex;
2037 Type *SliceTy = (NumElements == 1)
2038 ? Ty->getElementType()
2044 Use *U = S.getUse();
2047 if (
MI->isVolatile())
2049 if (!S.isSplittable())
2057 if (!
II->isLifetimeStartOrEnd() && !
II->isDroppable())
2064 if (LTy->isStructTy())
2066 if (
P.beginOffset() > S.beginOffset() ||
P.endOffset() < S.endOffset()) {
2067 assert(LTy->isIntegerTy());
2073 if (
SI->isVolatile())
2075 Type *STy =
SI->getValueOperand()->getType();
2079 if (
P.beginOffset() > S.beginOffset() ||
P.endOffset() < S.endOffset()) {
2099 bool HaveCommonEltTy,
Type *CommonEltTy,
2100 bool HaveVecPtrTy,
bool HaveCommonVecPtrTy,
2101 VectorType *CommonVecPtrTy,
unsigned VScale) {
2103 if (CandidateTys.
empty())
2110 if (HaveVecPtrTy && !HaveCommonVecPtrTy)
2114 if (!HaveCommonEltTy && HaveVecPtrTy) {
2116 CandidateTys.
clear();
2118 }
else if (!HaveCommonEltTy && !HaveVecPtrTy) {
2121 if (!VTy->getElementType()->isIntegerTy())
2123 VTy->getContext(), VTy->getScalarSizeInBits())));
2130 assert(
DL.getTypeSizeInBits(RHSTy).getFixedValue() ==
2131 DL.getTypeSizeInBits(LHSTy).getFixedValue() &&
2132 "Cannot have vector types of different sizes!");
2133 assert(RHSTy->getElementType()->isIntegerTy() &&
2134 "All non-integer types eliminated!");
2135 assert(LHSTy->getElementType()->isIntegerTy() &&
2136 "All non-integer types eliminated!");
2142 assert(
DL.getTypeSizeInBits(RHSTy).getFixedValue() ==
2143 DL.getTypeSizeInBits(LHSTy).getFixedValue() &&
2144 "Cannot have vector types of different sizes!");
2145 assert(RHSTy->getElementType()->isIntegerTy() &&
2146 "All non-integer types eliminated!");
2147 assert(LHSTy->getElementType()->isIntegerTy() &&
2148 "All non-integer types eliminated!");
2152 llvm::sort(CandidateTys, RankVectorTypesComp);
2153 CandidateTys.erase(
llvm::unique(CandidateTys, RankVectorTypesEq),
2154 CandidateTys.end());
2160 assert(VTy->getElementType() == CommonEltTy &&
2161 "Unaccounted for element type!");
2162 assert(VTy == CandidateTys[0] &&
2163 "Different vector types with the same element type!");
2166 CandidateTys.resize(1);
2173 std::numeric_limits<unsigned short>::max();
2179 DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
2183 if (ElementSize % 8)
2185 assert((
DL.getTypeSizeInBits(VTy).getFixedValue() % 8) == 0 &&
2186 "vector size not a multiple of element size?");
2189 for (
const Slice &S :
P)
2193 for (
const Slice *S :
P.splitSliceTails())
2199 return VTy != CandidateTys.
end() ? *VTy :
nullptr;
2206 bool &HaveCommonEltTy,
Type *&CommonEltTy,
bool &HaveVecPtrTy,
2207 bool &HaveCommonVecPtrTy,
VectorType *&CommonVecPtrTy,
unsigned VScale) {
2209 CandidateTysCopy.
size() ? CandidateTysCopy[0] :
nullptr;
2212 for (
Type *Ty : OtherTys) {
2215 unsigned TypeSize =
DL.getTypeSizeInBits(Ty).getFixedValue();
2218 for (
VectorType *
const VTy : CandidateTysCopy) {
2220 assert(CandidateTysCopy[0] == OriginalElt &&
"Different Element");
2221 unsigned VectorSize =
DL.getTypeSizeInBits(VTy).getFixedValue();
2222 unsigned ElementSize =
2223 DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
2227 CheckCandidateType(NewVTy);
2233 P,
DL, CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
2234 HaveCommonVecPtrTy, CommonVecPtrTy, VScale);
2253 Type *CommonEltTy =
nullptr;
2255 bool HaveVecPtrTy =
false;
2256 bool HaveCommonEltTy =
true;
2257 bool HaveCommonVecPtrTy =
true;
2258 auto CheckCandidateType = [&](
Type *Ty) {
2261 if (!CandidateTys.
empty()) {
2263 if (
DL.getTypeSizeInBits(VTy).getFixedValue() !=
2264 DL.getTypeSizeInBits(V).getFixedValue()) {
2265 CandidateTys.
clear();
2270 Type *EltTy = VTy->getElementType();
2273 CommonEltTy = EltTy;
2274 else if (CommonEltTy != EltTy)
2275 HaveCommonEltTy =
false;
2278 HaveVecPtrTy =
true;
2279 if (!CommonVecPtrTy)
2280 CommonVecPtrTy = VTy;
2281 else if (CommonVecPtrTy != VTy)
2282 HaveCommonVecPtrTy =
false;
2288 for (
const Slice &S :
P) {
2293 Ty =
SI->getValueOperand()->getType();
2297 auto CandTy = Ty->getScalarType();
2298 if (CandTy->isPointerTy() && (S.beginOffset() !=
P.beginOffset() ||
2299 S.endOffset() !=
P.endOffset())) {
2306 if (S.beginOffset() ==
P.beginOffset() && S.endOffset() ==
P.endOffset())
2307 CheckCandidateType(Ty);
2312 LoadStoreTys, CandidateTysCopy, CheckCandidateType,
P,
DL,
2313 CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
2314 HaveCommonVecPtrTy, CommonVecPtrTy, VScale))
2317 CandidateTys.
clear();
2319 DeferredTys, CandidateTysCopy, CheckCandidateType,
P,
DL, CandidateTys,
2320 HaveCommonEltTy, CommonEltTy, HaveVecPtrTy, HaveCommonVecPtrTy,
2321 CommonVecPtrTy, VScale);
2332 bool &WholeAllocaOp) {
2335 uint64_t RelBegin = S.beginOffset() - AllocBeginOffset;
2336 uint64_t RelEnd = S.endOffset() - AllocBeginOffset;
2338 Use *U = S.getUse();
2345 if (
II->isLifetimeStartOrEnd() ||
II->isDroppable())
2363 if (S.beginOffset() < AllocBeginOffset)
2369 WholeAllocaOp =
true;
2371 if (ITy->getBitWidth() <
DL.getTypeStoreSizeInBits(ITy).getFixedValue())
2373 }
else if (RelBegin != 0 || RelEnd !=
Size ||
2380 Type *ValueTy =
SI->getValueOperand()->getType();
2381 if (
SI->isVolatile())
2384 TypeSize StoreSize =
DL.getTypeStoreSize(ValueTy);
2389 if (S.beginOffset() < AllocBeginOffset)
2395 WholeAllocaOp =
true;
2397 if (ITy->getBitWidth() <
DL.getTypeStoreSizeInBits(ITy).getFixedValue())
2399 }
else if (RelBegin != 0 || RelEnd !=
Size ||
2408 if (!S.isSplittable())
2425 uint64_t SizeInBits =
DL.getTypeSizeInBits(AllocaTy).getFixedValue();
2431 if (SizeInBits !=
DL.getTypeStoreSizeInBits(AllocaTy).getFixedValue())
2449 bool WholeAllocaOp =
P.empty() &&
DL.isLegalInteger(SizeInBits);
2451 for (
const Slice &S :
P)
2456 for (
const Slice *S :
P.splitSliceTails())
2461 return WholeAllocaOp;
2466 const Twine &Name) {
2470 DL.getTypeStoreSize(IntTy).getFixedValue() &&
2471 "Element extends past full value");
2473 if (
DL.isBigEndian())
2474 ShAmt = 8 * (
DL.getTypeStoreSize(IntTy).getFixedValue() -
2475 DL.getTypeStoreSize(Ty).getFixedValue() -
Offset);
2477 V = IRB.CreateLShr(V, ShAmt, Name +
".shift");
2480 assert(Ty->getBitWidth() <= IntTy->getBitWidth() &&
2481 "Cannot extract to a larger integer!");
2483 V = IRB.CreateTrunc(V, Ty, Name +
".trunc");
2493 assert(Ty->getBitWidth() <= IntTy->getBitWidth() &&
2494 "Cannot insert a larger integer!");
2497 V = IRB.CreateZExt(V, IntTy, Name +
".ext");
2501 DL.getTypeStoreSize(IntTy).getFixedValue() &&
2502 "Element store outside of alloca store");
2504 if (
DL.isBigEndian())
2505 ShAmt = 8 * (
DL.getTypeStoreSize(IntTy).getFixedValue() -
2506 DL.getTypeStoreSize(Ty).getFixedValue() -
Offset);
2508 V = IRB.CreateShl(V, ShAmt, Name +
".shift");
2512 if (ShAmt || Ty->getBitWidth() < IntTy->getBitWidth()) {
2513 APInt Mask = ~Ty->getMask().zext(IntTy->getBitWidth()).shl(ShAmt);
2514 Old = IRB.CreateAnd(Old, Mask, Name +
".mask");
2516 V = IRB.CreateOr(Old, V, Name +
".insert");
2523 unsigned EndIndex,
const Twine &Name) {
2525 unsigned NumElements = EndIndex - BeginIndex;
2526 assert(NumElements <= VecTy->getNumElements() &&
"Too many elements!");
2528 if (NumElements == VecTy->getNumElements())
2531 if (NumElements == 1) {
2532 V = IRB.CreateExtractElement(V, BeginIndex, Name +
".extract");
2538 V = IRB.CreateShuffleVector(V, Mask, Name +
".extract");
2544 unsigned BeginIndex,
const Twine &Name) {
2546 assert(VecTy &&
"Can only insert a vector into a vector");
2551 V = IRB.CreateInsertElement(Old, V, BeginIndex, Name +
".insert");
2559 assert(NumSubElements <= NumElements &&
"Too many elements!");
2560 if (NumSubElements == NumElements) {
2561 assert(V->getType() == VecTy &&
"Vector type mismatch");
2564 unsigned EndIndex = BeginIndex + NumSubElements;
2571 Mask.reserve(NumElements);
2572 for (
unsigned Idx = 0; Idx != NumElements; ++Idx)
2573 if (Idx >= BeginIndex && Idx < EndIndex)
2574 Mask.push_back(Idx - BeginIndex);
2577 V = IRB.CreateShuffleVector(V, Mask, Name +
".expand");
2581 for (
unsigned Idx = 0; Idx != NumElements; ++Idx)
2582 if (Idx >= BeginIndex && Idx < EndIndex)
2583 Mask.push_back(Idx);
2585 Mask.push_back(Idx + NumElements);
2586 V = IRB.CreateShuffleVector(V, Old, Mask, Name +
"blend");
2625 const char *DebugName) {
2626 Type *EltType = VecType->getElementType();
2627 if (EltType != NewAIEltTy) {
2629 unsigned TotalBits =
2630 VecType->getNumElements() *
DL.getTypeSizeInBits(EltType);
2631 unsigned NewNumElts = TotalBits /
DL.getTypeSizeInBits(NewAIEltTy);
2634 V = Builder.CreateBitCast(V, NewVecType);
2635 VecType = NewVecType;
2636 LLVM_DEBUG(
dbgs() <<
" bitcast " << DebugName <<
": " << *V <<
"\n");
2640 BitcastIfNeeded(V0, VecType0,
"V0");
2641 BitcastIfNeeded(
V1, VecType1,
"V1");
2643 unsigned NumElts0 = VecType0->getNumElements();
2644 unsigned NumElts1 = VecType1->getNumElements();
2648 if (NumElts0 == NumElts1) {
2649 for (
unsigned i = 0; i < NumElts0 + NumElts1; ++i)
2650 ShuffleMask.push_back(i);
2654 unsigned SmallSize = std::min(NumElts0, NumElts1);
2655 unsigned LargeSize = std::max(NumElts0, NumElts1);
2656 bool IsV0Smaller = NumElts0 < NumElts1;
2657 Value *&ExtendedVec = IsV0Smaller ? V0 :
V1;
2659 for (
unsigned i = 0; i < SmallSize; ++i)
2661 for (
unsigned i = SmallSize; i < LargeSize; ++i)
2663 ExtendedVec = Builder.CreateShuffleVector(
2665 LLVM_DEBUG(
dbgs() <<
" shufflevector: " << *ExtendedVec <<
"\n");
2666 for (
unsigned i = 0; i < NumElts0; ++i)
2667 ShuffleMask.push_back(i);
2668 for (
unsigned i = 0; i < NumElts1; ++i)
2669 ShuffleMask.push_back(LargeSize + i);
2672 return Builder.CreateShuffleVector(V0,
V1, ShuffleMask);
2683class AllocaSliceRewriter :
public InstVisitor<AllocaSliceRewriter, bool> {
2685 friend class InstVisitor<AllocaSliceRewriter, bool>;
2687 using Base = InstVisitor<AllocaSliceRewriter, bool>;
2689 const DataLayout &
DL;
2692 AllocaInst &OldAI, &NewAI;
2693 const uint64_t NewAllocaBeginOffset, NewAllocaEndOffset;
2722 uint64_t NewBeginOffset = 0, NewEndOffset = 0;
2725 bool IsSplittable =
false;
2726 bool IsSplit =
false;
2727 Use *OldUse =
nullptr;
2731 SmallSetVector<PHINode *, 8> &PHIUsers;
2732 SmallSetVector<SelectInst *, 8> &SelectUsers;
2740 Value *getPtrToNewAI(
unsigned AddrSpace,
bool IsVolatile) {
2744 Type *AccessTy = IRB.getPtrTy(AddrSpace);
2745 return IRB.CreateAddrSpaceCast(&NewAI, AccessTy);
2749 AllocaSliceRewriter(
const DataLayout &
DL, AllocaSlices &AS, SROA &
Pass,
2750 AllocaInst &OldAI, AllocaInst &NewAI,
Type *NewAllocaTy,
2752 uint64_t NewAllocaEndOffset,
bool IsIntegerPromotable,
2753 VectorType *PromotableVecTy,
2754 SmallSetVector<PHINode *, 8> &PHIUsers,
2755 SmallSetVector<SelectInst *, 8> &SelectUsers)
2756 :
DL(
DL), AS(AS),
Pass(
Pass), OldAI(OldAI), NewAI(NewAI),
2757 NewAllocaBeginOffset(NewAllocaBeginOffset),
2758 NewAllocaEndOffset(NewAllocaEndOffset), NewAllocaTy(NewAllocaTy),
2759 IntTy(IsIntegerPromotable
2762 DL.getTypeSizeInBits(NewAllocaTy).getFixedValue())
2764 VecTy(PromotableVecTy),
2765 ElementTy(VecTy ? VecTy->getElementType() : nullptr),
2766 ElementSize(VecTy ?
DL.getTypeSizeInBits(ElementTy).getFixedValue() / 8
2768 PHIUsers(PHIUsers), SelectUsers(SelectUsers),
2771 assert((
DL.getTypeSizeInBits(ElementTy).getFixedValue() % 8) == 0 &&
2772 "Only multiple-of-8 sized vector elements are viable");
2775 assert((!IntTy && !VecTy) || (IntTy && !VecTy) || (!IntTy && VecTy));
2778 bool visit(AllocaSlices::const_iterator
I) {
2779 bool CanSROA =
true;
2780 BeginOffset =
I->beginOffset();
2781 EndOffset =
I->endOffset();
2782 IsSplittable =
I->isSplittable();
2784 BeginOffset < NewAllocaBeginOffset || EndOffset > NewAllocaEndOffset;
2785 LLVM_DEBUG(
dbgs() <<
" rewriting " << (IsSplit ?
"split " :
""));
2790 assert(BeginOffset < NewAllocaEndOffset);
2791 assert(EndOffset > NewAllocaBeginOffset);
2792 NewBeginOffset = std::max(BeginOffset, NewAllocaBeginOffset);
2793 NewEndOffset = std::min(EndOffset, NewAllocaEndOffset);
2795 SliceSize = NewEndOffset - NewBeginOffset;
2796 LLVM_DEBUG(
dbgs() <<
" Begin:(" << BeginOffset <<
", " << EndOffset
2797 <<
") NewBegin:(" << NewBeginOffset <<
", "
2798 << NewEndOffset <<
") NewAllocaBegin:("
2799 << NewAllocaBeginOffset <<
", " << NewAllocaEndOffset
2801 assert(IsSplit || NewBeginOffset == BeginOffset);
2802 OldUse =
I->getUse();
2806 IRB.SetInsertPoint(OldUserI);
2807 IRB.SetCurrentDebugLocation(OldUserI->
getDebugLoc());
2809 if (!IRB.getContext().shouldDiscardValueNames())
2810 IRB.getInserter().SetNamePrefix(Twine(NewAI.
getName()) +
"." +
2811 Twine(BeginOffset) +
".");
2873 std::optional<SmallVector<Value *, 4>>
2874 rewriteTreeStructuredMerge(Partition &
P) {
2876 if (
P.splitSliceTails().size() > 0)
2877 return std::nullopt;
2886 :
Store(
SI), BeginOffset(Begin), EndOffset(End), StoredValue(Val) {}
2896 LoadInst *FullLoad =
nullptr;
2897 StoreInst *InitStore =
nullptr;
2901 Type *AllocatedEltTy =
2905 unsigned AllocatedEltTySize =
DL.getTypeSizeInBits(AllocatedEltTy);
2912 auto IsTypeValidForTreeStructuredMerge = [&](
Type *Ty) ->
bool {
2914 return FixedVecTy &&
2915 DL.getTypeSizeInBits(FixedVecTy->getElementType()) % 8 == 0 &&
2916 !FixedVecTy->getElementType()->isPointerTy();
2919 for (Slice &S :
P) {
2923 bool IsFullWidth = (S.beginOffset() == NewAllocaBeginOffset &&
2924 S.endOffset() == NewAllocaEndOffset);
2928 !IsTypeValidForTreeStructuredMerge(LI->
getType()))
2929 return std::nullopt;
2934 return std::nullopt;
2938 LoadInfos.
push_back({LI, S.beginOffset(), S.endOffset()});
2950 if (!
SI->isSimple() || !IsTypeValidForTreeStructuredMerge(
2951 SI->getValueOperand()->getType()))
2952 return std::nullopt;
2954 unsigned NumElts = StVecTy->getNumElements();
2955 unsigned EltSize =
DL.getTypeSizeInBits(StVecTy->getElementType());
2956 if (NumElts * EltSize % AllocatedEltTySize != 0)
2957 return std::nullopt;
2962 return std::nullopt;
2965 StoreInfos.
emplace_back(SI, S.beginOffset(), S.endOffset(),
2966 SI->getValueOperand());
2971 return std::nullopt;
2978 if (StoreInfos.
size() < 2)
2979 return std::nullopt;
2987 bool IsRMWPattern = InitStore && VecTy && !LoadInfos.
empty();
2988 bool IsStoresOnlyPattern = !InitStore && FullLoad && LoadInfos.
empty();
2989 if (!IsRMWPattern && !IsStoresOnlyPattern)
2990 return std::nullopt;
2994 BasicBlock *StoreBB = StoreInfos[0].Store->getParent();
2995 for (
auto &Info : StoreInfos)
2996 if (
Info.Store->getParent() != StoreBB)
2997 return std::nullopt;
2999 SmallVector<Value *, 4> DeletedValues;
3006 auto TreeMerge = [&](SmallVectorImpl<Value *> &Vals,
3009 while (Vals.
size() > 1) {
3010 SmallVector<Value *, 8>
Next;
3011 for (
unsigned I = 0,
E = Vals.
size();
I + 1 <
E;
I += 2) {
3017 if (Vals.
size() % 2 == 1)
3019 Vals = std::move(
Next);
3028 auto ReplaceFullLoad = [&](LoadInst *LoadToReplace,
Value *Merged) {
3030 Value *NewLoad = LoadBuilder.CreateAlignedLoad(
3031 Merged->getType(), &NewAI, getSliceAlign(),
3033 LoadToReplace->
getName() +
".sroa.new.load");
3035 NewLoad = LoadBuilder.CreateBitCast(NewLoad, LoadToReplace->
getType());
3040 if (IsStoresOnlyPattern) {
3043 llvm::sort(StoreInfos, [](
const StoreInfo &
A,
const StoreInfo &
B) {
3044 return A.BeginOffset <
B.BeginOffset;
3049 uint64_t Expected = NewAllocaBeginOffset;
3050 for (
auto &Info : StoreInfos) {
3051 if (
Info.BeginOffset != Expected)
3052 return std::nullopt;
3053 Expected =
Info.EndOffset;
3056 if (Expected != NewAllocaEndOffset)
3057 return std::nullopt;
3067 if (LoadBB == StoreBB) {
3068 for (
auto &Info : StoreInfos)
3069 if (!
Info.Store->comesBefore(FullLoad))
3070 return std::nullopt;
3074 dbgs() <<
"Tree structured merge rewrite (stores-only):\n";
3075 dbgs() <<
" Load: " << *FullLoad <<
"\n Ordered stores:\n";
3076 for (
auto [
I, Info] :
enumerate(StoreInfos)) {
3077 dbgs() <<
" [" <<
I <<
"] Range[" <<
Info.BeginOffset <<
", "
3078 <<
Info.EndOffset <<
") \tStore: " << *
Info.Store
3079 <<
"\tValue: " << *
Info.StoredValue <<
"\n";
3092 SmallVector<Value *, 8> Vals;
3093 for (
const auto &Info : StoreInfos) {
3098 Value *Merged = TreeMerge(Vals, Builder);
3099 Builder.CreateAlignedStore(Merged, &NewAI, getSliceAlign());
3102 ReplaceFullLoad(FullLoad, Merged);
3103 return DeletedValues;
3111 return std::nullopt;
3112 if (
any_of(LoadInfos, [&](
const LoadInfo &
I) {
3113 return I.Load->getParent() != StoreBB;
3115 return std::nullopt;
3131 Accesses.reserve(LoadInfos.
size() + StoreInfos.size());
3132 for (
const auto &L : LoadInfos)
3133 Accesses.push_back({
L.Load,
L.BeginOffset,
L.EndOffset,
false});
3134 for (
const auto &S : StoreInfos)
3135 Accesses.push_back({S.Store, S.BeginOffset, S.EndOffset,
true});
3137 return A.Inst->comesBefore(
B.Inst);
3145 return std::nullopt;
3151 if (FullLoad && FullLoad->
getParent() == StoreBB &&
3152 !
Accesses.back().Inst->comesBefore(FullLoad))
3153 return std::nullopt;
3164 using SliceRange = std::pair<uint64_t, uint64_t>;
3168 SortedRanges.
emplace_back(Acc.BeginOffset, Acc.EndOffset);
3172 uint64_t Expected = NewAllocaBeginOffset;
3173 for (
auto &
Range : SortedRanges) {
3174 if (
Range.first != Expected)
3175 return std::nullopt;
3176 Expected =
Range.second;
3178 if (Expected != NewAllocaEndOffset)
3179 return std::nullopt;
3182 dbgs() <<
"Tree structured merge rewrite (RMW):\n";
3183 dbgs() <<
" Init store: " << *InitStore <<
"\n";
3185 dbgs() <<
" Final load: " << *FullLoad <<
"\n";
3186 dbgs() <<
" Slice ranges (" << SortedRanges.size() <<
"):\n";
3187 for (
auto &
Range : SortedRanges)
3198 if (InitVec->
getType() != NewAllocaTy)
3199 InitVec = IRB.CreateBitCast(InitVec, NewAllocaTy,
"init.cast");
3200 DenseMap<SliceRange, Value *> SliceValues;
3201 for (
auto &
Range : SortedRanges) {
3202 unsigned BeginIdx = getIndex(
Range.first);
3203 unsigned EndIdx = getIndex(
Range.second);
3204 SliceValues[
Range] = IRB.CreateShuffleVector(
3220 SliceRange
Range{Acc.BeginOffset, Acc.EndOffset};
3223 if (
V->getType() != Acc.Inst->getType()) {
3225 V = IRB.CreateBitCast(V, Acc.Inst->getType());
3227 Acc.Inst->replaceAllUsesWith(V);
3244 SmallVector<Value *, 8> Vals;
3245 for (
auto &
Range : SortedRanges)
3247 Value *Merged = TreeMerge(Vals, Builder);
3248 Builder.CreateAlignedStore(Merged, &NewAI, getSliceAlign());
3253 ReplaceFullLoad(FullLoad, Merged);
3255 return DeletedValues;
3263 bool visitInstruction(Instruction &
I) {
3271 assert(IsSplit || BeginOffset == NewBeginOffset);
3274 StringRef OldName = OldPtr->
getName();
3276 size_t LastSROAPrefix = OldName.
rfind(
".sroa.");
3278 OldName = OldName.
substr(LastSROAPrefix + strlen(
".sroa."));
3283 OldName = OldName.
substr(IndexEnd + 1);
3287 OldName = OldName.
substr(OffsetEnd + 1);
3291 OldName = OldName.
substr(0, OldName.
find(
".sroa_"));
3303 Align getSliceAlign() {
3305 NewBeginOffset - NewAllocaBeginOffset);
3309 assert(VecTy &&
"Can only call getIndex when rewriting a vector");
3311 assert(RelOffset / ElementSize < UINT32_MAX &&
"Index out of bounds");
3312 uint32_t
Index = RelOffset / ElementSize;
3313 assert(Index * ElementSize == RelOffset);
3317 void deleteIfTriviallyDead(
Value *V) {
3320 Pass.DeadInsts.push_back(
I);
3323 Value *rewriteVectorizedLoadInst(LoadInst &LI) {
3324 unsigned BeginIndex = getIndex(NewBeginOffset);
3325 unsigned EndIndex = getIndex(NewEndOffset);
3326 assert(EndIndex > BeginIndex &&
"Empty vector!");
3329 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3331 Load->copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
3332 LLVMContext::MD_access_group});
3336 Value *rewriteIntegerLoad(LoadInst &LI) {
3337 assert(IntTy &&
"We cannot insert an integer to the alloca");
3340 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3341 V = IRB.CreateBitPreservingCastChain(
DL, V, IntTy);
3342 assert(NewBeginOffset >= NewAllocaBeginOffset &&
"Out of bounds offset");
3344 if (
Offset > 0 || NewEndOffset < NewAllocaEndOffset) {
3345 IntegerType *ExtractTy = Type::getIntNTy(LI.
getContext(), SliceSize * 8);
3354 "Can only handle an extract for an overly wide load");
3356 V = IRB.CreateZExt(V, LI.
getType());
3360 bool visitLoadInst(LoadInst &LI) {
3369 Type *TargetTy = IsSplit ? Type::getIntNTy(LI.
getContext(), SliceSize * 8)
3371 bool IsPtrAdjusted =
false;
3374 V = rewriteVectorizedLoadInst(LI);
3376 V = rewriteIntegerLoad(LI);
3377 }
else if (NewBeginOffset == NewAllocaBeginOffset &&
3378 NewEndOffset == NewAllocaEndOffset &&
3381 DL.getTypeStoreSize(TargetTy).getFixedValue() > SliceSize &&
3384 getPtrToNewAI(LI.getPointerAddressSpace(), LI.isVolatile());
3385 LoadInst *NewLI = IRB.CreateAlignedLoad(
3386 NewAllocaTy, NewPtr, NewAI.getAlign(), LI.isVolatile(), LI.getName());
3387 if (LI.isVolatile())
3388 NewLI->setAtomic(LI.getOrdering(), LI.getSyncScopeID());
3389 if (NewLI->isAtomic())
3390 NewLI->setAlignment(LI.getAlign());
3395 copyMetadataForLoad(*NewLI, LI);
3399 NewLI->setAAMetadata(AATags.adjustForAccess(
3400 NewBeginOffset - BeginOffset, NewLI->getType(), DL));
3408 if (auto *AITy = dyn_cast<IntegerType>(NewAllocaTy))
3409 if (auto *TITy = dyn_cast<IntegerType>(TargetTy))
3410 if (AITy->getBitWidth() < TITy->getBitWidth()) {
3411 V = IRB.CreateZExt(V, TITy,
"load.ext");
3412 if (DL.isBigEndian())
3413 V = IRB.CreateShl(V, TITy->getBitWidth() - AITy->getBitWidth(),
3417 Type *LTy = IRB.getPtrTy(AS);
3419 IRB.CreateAlignedLoad(TargetTy, getNewAllocaSlicePtr(IRB, LTy),
3424 NewBeginOffset - BeginOffset, NewLI->
getType(),
DL));
3428 NewLI->
copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
3429 LLVMContext::MD_access_group});
3432 IsPtrAdjusted =
true;
3434 V = IRB.CreateBitPreservingCastChain(
DL, V, TargetTy);
3439 "Only integer type loads and stores are split");
3440 assert(SliceSize <
DL.getTypeStoreSize(LI.
getType()).getFixedValue() &&
3441 "Split load isn't smaller than original load");
3443 "Non-byte-multiple bit width");
3449 LIIt.setHeadBit(
true);
3450 IRB.SetInsertPoint(LI.
getParent(), LIIt);
3455 Value *Placeholder =
3461 Placeholder->replaceAllUsesWith(&LI);
3462 Placeholder->deleteValue();
3467 Pass.DeadInsts.push_back(&LI);
3468 deleteIfTriviallyDead(OldOp);
3473 bool rewriteVectorizedStoreInst(
Value *V, StoreInst &SI,
Value *OldOp,
3478 if (
V->getType() != VecTy) {
3479 unsigned BeginIndex = getIndex(NewBeginOffset);
3480 unsigned EndIndex = getIndex(NewEndOffset);
3481 assert(EndIndex > BeginIndex &&
"Empty vector!");
3482 unsigned NumElements = EndIndex - BeginIndex;
3484 "Too many elements!");
3485 Type *SliceTy = (NumElements == 1)
3487 : FixedVectorType::
get(ElementTy, NumElements);
3488 if (
V->getType() != SliceTy)
3489 V = IRB.CreateBitPreservingCastChain(
DL, V, SliceTy);
3493 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3496 StoreInst *
Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.
getAlign());
3497 Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3498 LLVMContext::MD_access_group});
3502 Pass.DeadInsts.push_back(&SI);
3511 bool rewriteIntegerStore(
Value *V, StoreInst &SI, AAMDNodes AATags) {
3512 assert(IntTy &&
"We cannot extract an integer from the alloca");
3514 if (
DL.getTypeSizeInBits(
V->getType()).getFixedValue() !=
3516 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3518 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3519 assert(BeginOffset >= NewAllocaBeginOffset &&
"Out of bounds offset");
3523 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3524 StoreInst *
Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.
getAlign());
3525 Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3526 LLVMContext::MD_access_group});
3533 Store->getValueOperand(),
DL);
3535 Pass.DeadInsts.push_back(&SI);
3540 bool visitStoreInst(StoreInst &SI) {
3542 Value *OldOp =
SI.getOperand(1);
3545 AAMDNodes AATags =
SI.getAAMetadata();
3550 if (
V->getType()->isPointerTy())
3552 Pass.PostPromotionWorklist.insert(AI);
3554 TypeSize StoreSize =
DL.getTypeStoreSize(
V->getType());
3557 assert(
V->getType()->isIntegerTy() &&
3558 "Only integer type loads and stores are split");
3559 assert(
DL.typeSizeEqualsStoreSize(
V->getType()) &&
3560 "Non-byte-multiple bit width");
3561 IntegerType *NarrowTy = Type::getIntNTy(
SI.getContext(), SliceSize * 8);
3567 return rewriteVectorizedStoreInst(V, SI, OldOp, AATags);
3568 if (IntTy &&
V->getType()->isIntegerTy())
3569 return rewriteIntegerStore(V, SI, AATags);
3572 if (NewBeginOffset == NewAllocaBeginOffset &&
3573 NewEndOffset == NewAllocaEndOffset &&
3575 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3577 getPtrToNewAI(
SI.getPointerAddressSpace(),
SI.isVolatile());
3580 IRB.CreateAlignedStore(V, NewPtr, NewAI.
getAlign(),
SI.isVolatile());
3582 unsigned AS =
SI.getPointerAddressSpace();
3583 Value *NewPtr = getNewAllocaSlicePtr(IRB, IRB.getPtrTy(AS));
3585 IRB.CreateAlignedStore(V, NewPtr, getSliceAlign(),
SI.isVolatile());
3587 NewSI->
copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3588 LLVMContext::MD_access_group});
3592 if (
SI.isVolatile())
3601 Pass.DeadInsts.push_back(&SI);
3602 deleteIfTriviallyDead(OldOp);
3620 assert(
Size > 0 &&
"Expected a positive number of bytes.");
3628 IRB.CreateZExt(V, SplatIntTy,
"zext"),
3638 V = IRB.CreateVectorSplat(NumElements, V,
"vsplat");
3643 bool visitMemSetInst(MemSetInst &
II) {
3647 AAMDNodes AATags =
II.getAAMetadata();
3653 assert(NewBeginOffset == BeginOffset);
3654 II.setDest(getNewAllocaSlicePtr(IRB, OldPtr->
getType()));
3655 II.setDestAlignment(getSliceAlign());
3660 "AT: Unexpected link to non-const GEP");
3661 deleteIfTriviallyDead(OldPtr);
3666 Pass.DeadInsts.push_back(&
II);
3670 const bool CanContinue = [&]() {
3673 if (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset)
3678 if (Len > std::numeric_limits<unsigned>::max())
3680 auto *Int8Ty = IntegerType::getInt8Ty(NewAI.
getContext());
3683 DL.isLegalInteger(
DL.getTypeSizeInBits(ScalarTy).getFixedValue());
3689 Type *SizeTy =
II.getLength()->getType();
3690 unsigned Sz = NewEndOffset - NewBeginOffset;
3693 getNewAllocaSlicePtr(IRB, OldPtr->
getType()),
II.getValue(),
Size,
3694 MaybeAlign(getSliceAlign()),
II.isVolatile()));
3700 New,
New->getRawDest(),
nullptr,
DL);
3715 assert(ElementTy == ScalarTy);
3717 unsigned BeginIndex = getIndex(NewBeginOffset);
3718 unsigned EndIndex = getIndex(NewEndOffset);
3719 assert(EndIndex > BeginIndex &&
"Empty vector!");
3720 unsigned NumElements = EndIndex - BeginIndex;
3722 "Too many elements!");
3725 II.getValue(),
DL.getTypeSizeInBits(ElementTy).getFixedValue() / 8);
3726 Splat = IRB.CreateBitPreservingCastChain(
DL,
Splat, ElementTy);
3727 if (NumElements > 1)
3730 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3739 V = getIntegerSplat(
II.getValue(),
Size);
3741 if (IntTy && (NewBeginOffset != NewAllocaBeginOffset ||
3742 NewEndOffset != NewAllocaEndOffset)) {
3743 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI,
3745 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3749 assert(
V->getType() == IntTy &&
3750 "Wrong type for an alloca wide integer!");
3752 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3755 assert(NewBeginOffset == NewAllocaBeginOffset);
3756 assert(NewEndOffset == NewAllocaEndOffset);
3758 V = getIntegerSplat(
II.getValue(),
3759 DL.getTypeSizeInBits(ScalarTy).getFixedValue() / 8);
3764 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3767 Value *NewPtr = getPtrToNewAI(
II.getDestAddressSpace(),
II.isVolatile());
3769 IRB.CreateAlignedStore(V, NewPtr, NewAI.
getAlign(),
II.isVolatile());
3770 New->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
3771 LLVMContext::MD_access_group});
3777 New,
New->getPointerOperand(), V,
DL);
3780 return !
II.isVolatile();
3783 bool visitMemTransferInst(MemTransferInst &
II) {
3789 AAMDNodes AATags =
II.getAAMetadata();
3791 bool IsDest = &
II.getRawDestUse() == OldUse;
3792 assert((IsDest &&
II.getRawDest() == OldPtr) ||
3793 (!IsDest &&
II.getRawSource() == OldPtr));
3795 Align SliceAlign = getSliceAlign();
3803 if (!IsSplittable) {
3804 Value *AdjustedPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
3809 DbgAssign->getAddress() ==
II.getDest())
3810 DbgAssign->replaceVariableLocationOp(
II.getDest(), AdjustedPtr);
3812 II.setDest(AdjustedPtr);
3813 II.setDestAlignment(SliceAlign);
3815 II.setSource(AdjustedPtr);
3816 II.setSourceAlignment(SliceAlign);
3820 deleteIfTriviallyDead(OldPtr);
3833 (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset ||
3834 SliceSize !=
DL.getTypeStoreSize(NewAllocaTy).getFixedValue() ||
3835 !
DL.typeSizeEqualsStoreSize(NewAllocaTy) ||
3841 if (EmitMemCpy && &OldAI == &NewAI) {
3843 assert(NewBeginOffset == BeginOffset);
3846 if (NewEndOffset != EndOffset)
3847 II.setLength(NewEndOffset - NewBeginOffset);
3851 Pass.DeadInsts.push_back(&
II);
3855 Value *OtherPtr = IsDest ?
II.getRawSource() :
II.getRawDest();
3856 if (AllocaInst *AI =
3858 assert(AI != &OldAI && AI != &NewAI &&
3859 "Splittable transfers cannot reach the same alloca on both ends.");
3860 Pass.Worklist.insert(AI);
3867 unsigned OffsetWidth =
DL.getIndexSizeInBits(OtherAS);
3868 APInt OtherOffset(OffsetWidth, NewBeginOffset - BeginOffset);
3870 (IsDest ?
II.getSourceAlign() :
II.getDestAlign()).valueOrOne();
3872 commonAlignment(OtherAlign, OtherOffset.zextOrTrunc(64).getZExtValue());
3880 Value *OurPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
3881 Type *SizeTy =
II.getLength()->getType();
3882 Constant *
Size = ConstantInt::get(SizeTy, NewEndOffset - NewBeginOffset);
3884 Value *DestPtr, *SrcPtr;
3885 MaybeAlign DestAlign, SrcAlign;
3889 DestAlign = SliceAlign;
3891 SrcAlign = OtherAlign;
3894 DestAlign = OtherAlign;
3896 SrcAlign = SliceAlign;
3898 CallInst *
New = IRB.CreateMemCpy(DestPtr, DestAlign, SrcPtr, SrcAlign,
3901 New->setAAMetadata(AATags.
shift(NewBeginOffset - BeginOffset));
3906 &
II, New, DestPtr,
nullptr,
DL);
3911 SliceSize * 8, &
II, New, DestPtr,
nullptr,
DL);
3917 bool IsWholeAlloca = NewBeginOffset == NewAllocaBeginOffset &&
3918 NewEndOffset == NewAllocaEndOffset;
3920 unsigned BeginIndex = VecTy ? getIndex(NewBeginOffset) : 0;
3921 unsigned EndIndex = VecTy ? getIndex(NewEndOffset) : 0;
3922 unsigned NumElements = EndIndex - BeginIndex;
3923 IntegerType *SubIntTy =
3924 IntTy ? Type::getIntNTy(IntTy->
getContext(),
Size * 8) : nullptr;
3929 if (VecTy && !IsWholeAlloca) {
3930 if (NumElements == 1)
3931 OtherTy = VecTy->getElementType();
3934 }
else if (IntTy && !IsWholeAlloca) {
3937 OtherTy = NewAllocaTy;
3942 MaybeAlign SrcAlign = OtherAlign;
3943 MaybeAlign DstAlign = SliceAlign;
3951 DstPtr = getPtrToNewAI(
II.getDestAddressSpace(),
II.isVolatile());
3955 SrcPtr = getPtrToNewAI(
II.getSourceAddressSpace(),
II.isVolatile());
3959 if (VecTy && !IsWholeAlloca && !IsDest) {
3961 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3963 }
else if (IntTy && !IsWholeAlloca && !IsDest) {
3965 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3966 Src = IRB.CreateBitPreservingCastChain(
DL, Src, IntTy);
3970 LoadInst *
Load = IRB.CreateAlignedLoad(OtherTy, SrcPtr, SrcAlign,
3971 II.isVolatile(),
"copyload");
3972 Load->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
3973 LLVMContext::MD_access_group});
3980 if (VecTy && !IsWholeAlloca && IsDest) {
3981 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3984 }
else if (IntTy && !IsWholeAlloca && IsDest) {
3985 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3987 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3990 Src = IRB.CreateBitPreservingCastChain(
DL, Src, NewAllocaTy);
3994 IRB.CreateAlignedStore(Src, DstPtr, DstAlign,
II.isVolatile()));
3995 Store->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
3996 LLVMContext::MD_access_group});
3999 Src->getType(),
DL));
4014 return !
II.isVolatile();
4017 bool visitIntrinsicInst(IntrinsicInst &
II) {
4018 assert((
II.isLifetimeStartOrEnd() ||
II.isDroppable()) &&
4019 "Unexpected intrinsic!");
4023 Pass.DeadInsts.push_back(&
II);
4025 if (
II.isDroppable()) {
4026 assert(
II.getIntrinsicID() == Intrinsic::assume &&
"Expected assume");
4032 assert(
II.getArgOperand(0) == OldPtr);
4036 if (
II.getIntrinsicID() == Intrinsic::lifetime_start)
4037 New = IRB.CreateLifetimeStart(Ptr);
4039 New = IRB.CreateLifetimeEnd(Ptr);
4047 void fixLoadStoreAlign(Instruction &Root) {
4051 SmallPtrSet<Instruction *, 4> Visited;
4052 SmallVector<Instruction *, 4>
Uses;
4054 Uses.push_back(&Root);
4063 SI->setAlignment(std::min(
SI->getAlign(), getSliceAlign()));
4070 for (User *U :
I->users())
4073 }
while (!
Uses.empty());
4076 bool visitPHINode(PHINode &PN) {
4078 assert(BeginOffset >= NewAllocaBeginOffset &&
"PHIs are unsplittable");
4079 assert(EndOffset <= NewAllocaEndOffset &&
"PHIs are unsplittable");
4085 IRBuilderBase::InsertPointGuard Guard(IRB);
4088 OldPtr->
getParent()->getFirstInsertionPt());
4090 IRB.SetInsertPoint(OldPtr);
4091 IRB.SetCurrentDebugLocation(OldPtr->
getDebugLoc());
4093 Value *NewPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
4098 deleteIfTriviallyDead(OldPtr);
4101 fixLoadStoreAlign(PN);
4110 bool visitSelectInst(SelectInst &SI) {
4112 assert((
SI.getTrueValue() == OldPtr ||
SI.getFalseValue() == OldPtr) &&
4113 "Pointer isn't an operand!");
4114 assert(BeginOffset >= NewAllocaBeginOffset &&
"Selects are unsplittable");
4115 assert(EndOffset <= NewAllocaEndOffset &&
"Selects are unsplittable");
4117 Value *NewPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
4119 if (
SI.getOperand(1) == OldPtr)
4120 SI.setOperand(1, NewPtr);
4121 if (
SI.getOperand(2) == OldPtr)
4122 SI.setOperand(2, NewPtr);
4125 deleteIfTriviallyDead(OldPtr);
4128 fixLoadStoreAlign(SI);
4143class AggLoadStoreRewriter :
public InstVisitor<AggLoadStoreRewriter, bool> {
4145 friend class InstVisitor<AggLoadStoreRewriter, bool>;
4151 SmallPtrSet<User *, 8> Visited;
4158 const DataLayout &
DL;
4163 AggLoadStoreRewriter(
const DataLayout &
DL, IRBuilderTy &IRB)
4164 :
DL(
DL), IRB(IRB) {}
4168 bool rewrite(Instruction &
I) {
4172 while (!
Queue.empty()) {
4173 U =
Queue.pop_back_val();
4182 void enqueueUsers(Instruction &
I) {
4183 for (Use &U :
I.uses())
4184 if (Visited.
insert(
U.getUser()).second)
4185 Queue.push_back(&U);
4189 bool visitInstruction(Instruction &
I) {
return false; }
4192 template <
typename Derived>
class OpSplitter {
4199 SmallVector<unsigned, 4> Indices;
4203 SmallVector<Value *, 4> GEPIndices;
4217 const DataLayout &
DL;
4221 OpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4222 Align BaseAlign,
const DataLayout &
DL, IRBuilderTy &IRB)
4223 : IRB(IRB), GEPIndices(1, IRB.getInt32(0)), Ptr(Ptr), BaseTy(BaseTy),
4224 BaseAlign(BaseAlign),
DL(
DL) {
4225 IRB.SetInsertPoint(InsertionPoint);
4242 void emitSplitOps(
Type *Ty,
Value *&Agg,
const Twine &Name) {
4244 unsigned Offset =
DL.getIndexedOffsetInType(BaseTy, GEPIndices);
4245 return static_cast<Derived *
>(
this)->emitFunc(
4250 unsigned OldSize = Indices.
size();
4252 for (
unsigned Idx = 0,
Size = ATy->getNumElements(); Idx !=
Size;
4254 assert(Indices.
size() == OldSize &&
"Did not return to the old size");
4256 GEPIndices.
push_back(IRB.getInt32(Idx));
4257 emitSplitOps(ATy->getElementType(), Agg, Name +
"." + Twine(Idx));
4265 unsigned OldSize = Indices.
size();
4267 for (
unsigned Idx = 0,
Size = STy->getNumElements(); Idx !=
Size;
4269 assert(Indices.
size() == OldSize &&
"Did not return to the old size");
4271 GEPIndices.
push_back(IRB.getInt32(Idx));
4272 emitSplitOps(STy->getElementType(Idx), Agg, Name +
"." + Twine(Idx));
4283 struct LoadOpSplitter :
public OpSplitter<LoadOpSplitter> {
4287 SmallVector<Value *, 4> Components;
4292 LoadOpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4293 AAMDNodes AATags, Align BaseAlign,
const DataLayout &
DL,
4295 : OpSplitter<LoadOpSplitter>(InsertionPoint, Ptr, BaseTy, BaseAlign,
DL,
4301 void emitFunc(
Type *Ty,
Value *&Agg, Align Alignment,
const Twine &Name) {
4305 IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name +
".gep");
4307 IRB.CreateAlignedLoad(Ty,
GEP, Alignment, Name +
".load");
4313 Load->setAAMetadata(
4319 Agg = IRB.CreateInsertValue(Agg,
Load, Indices, Name +
".insert");
4324 void recordFakeUses(LoadInst &LI) {
4325 for (Use &U : LI.
uses())
4327 if (
II->getIntrinsicID() == Intrinsic::fake_use)
4333 void emitFakeUses() {
4334 for (Instruction *
I : FakeUses) {
4335 IRB.SetInsertPoint(
I);
4336 for (
auto *V : Components)
4337 IRB.CreateIntrinsic(Intrinsic::fake_use, {
V});
4338 I->eraseFromParent();
4343 bool visitLoadInst(LoadInst &LI) {
4352 Splitter.recordFakeUses(LI);
4355 Splitter.emitFakeUses();
4362 struct StoreOpSplitter :
public OpSplitter<StoreOpSplitter> {
4363 StoreOpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4364 AAMDNodes AATags, StoreInst *AggStore, Align BaseAlign,
4365 const DataLayout &
DL, IRBuilderTy &IRB)
4366 : OpSplitter<StoreOpSplitter>(InsertionPoint, Ptr, BaseTy, BaseAlign,
4368 AATags(AATags), AggStore(AggStore) {}
4370 StoreInst *AggStore;
4373 void emitFunc(
Type *Ty,
Value *&Agg, Align Alignment,
const Twine &Name) {
4379 Value *ExtractValue =
4380 IRB.CreateExtractValue(Agg, Indices, Name +
".extract");
4381 Value *InBoundsGEP =
4382 IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name +
".gep");
4384 IRB.CreateAlignedStore(ExtractValue, InBoundsGEP, Alignment);
4401 DL.getTypeSizeInBits(
Store->getValueOperand()->getType());
4403 SizeInBits, AggStore,
Store,
4404 Store->getPointerOperand(),
Store->getValueOperand(),
4408 "AT: unexpected debug.assign linked to store through "
4415 bool visitStoreInst(StoreInst &SI) {
4416 if (!
SI.isSimple() ||
SI.getPointerOperand() != *U)
4419 if (
V->getType()->isSingleValueType())
4424 StoreOpSplitter Splitter(&SI, *U,
V->getType(),
SI.getAAMetadata(), &SI,
4426 Splitter.emitSplitOps(
V->getType(), V,
V->getName() +
".fca");
4431 SI.eraseFromParent();
4435 bool visitBitCastInst(BitCastInst &BC) {
4440 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
4450 bool unfoldGEPSelect(GetElementPtrInst &GEPI) {
4469 if (!ZI->getSrcTy()->isIntegerTy(1))
4482 dbgs() <<
" original: " << *Sel <<
"\n";
4483 dbgs() <<
" " << GEPI <<
"\n";);
4485 auto GetNewOps = [&](
Value *SelOp) {
4498 Cond =
SI->getCondition();
4499 True =
SI->getTrueValue();
4500 False =
SI->getFalseValue();
4504 Cond = Sel->getOperand(0);
4505 True = ConstantInt::get(Sel->getType(), 1);
4506 False = ConstantInt::get(Sel->getType(), 0);
4511 IRB.SetInsertPoint(&GEPI);
4515 Value *NTrue = IRB.CreateGEP(Ty, TrueOps[0],
ArrayRef(TrueOps).drop_front(),
4516 True->
getName() +
".sroa.gep", NW);
4519 IRB.CreateGEP(Ty, FalseOps[0],
ArrayRef(FalseOps).drop_front(),
4520 False->
getName() +
".sroa.gep", NW);
4522 Value *NSel = MDFrom
4523 ? IRB.CreateSelect(
Cond, NTrue, NFalse,
4524 Sel->getName() +
".sroa.sel", MDFrom)
4525 : IRB.CreateSelectWithUnknownProfile(
4527 Sel->getName() +
".sroa.sel");
4528 Visited.
erase(&GEPI);
4533 enqueueUsers(*NSelI);
4536 dbgs() <<
" " << *NFalse <<
"\n";
4537 dbgs() <<
" " << *NSel <<
"\n";);
4546 bool unfoldGEPPhi(GetElementPtrInst &GEPI) {
4551 auto IsInvalidPointerOperand = [](
Value *
V) {
4555 return !AI->isStaticAlloca();
4559 if (
any_of(
Phi->operands(), IsInvalidPointerOperand))
4574 [](
Value *V) { return isa<ConstantInt>(V); }))
4587 dbgs() <<
" original: " << *
Phi <<
"\n";
4588 dbgs() <<
" " << GEPI <<
"\n";);
4590 auto GetNewOps = [&](
Value *PhiOp) {
4600 IRB.SetInsertPoint(Phi);
4601 PHINode *NewPhi = IRB.CreatePHI(GEPI.
getType(),
Phi->getNumIncomingValues(),
4602 Phi->getName() +
".sroa.phi");
4608 for (
unsigned I = 0,
E =
Phi->getNumIncomingValues();
I !=
E; ++
I) {
4617 IRB.CreateGEP(SourceTy, NewOps[0],
ArrayRef(NewOps).drop_front(),
4623 Visited.
erase(&GEPI);
4627 enqueueUsers(*NewPhi);
4633 dbgs() <<
"\n " << *NewPhi <<
'\n');
4638 bool visitGetElementPtrInst(GetElementPtrInst &GEPI) {
4639 if (unfoldGEPSelect(GEPI))
4642 if (unfoldGEPPhi(GEPI))
4649 bool visitPHINode(PHINode &PN) {
4654 bool visitSelectInst(SelectInst &SI) {
4668 if (Ty->isSingleValueType())
4671 uint64_t AllocSize =
DL.getTypeAllocSize(Ty).getFixedValue();
4676 InnerTy = ArrTy->getElementType();
4680 InnerTy = STy->getElementType(Index);
4685 if (AllocSize >
DL.getTypeAllocSize(InnerTy).getFixedValue() ||
4686 TypeSize >
DL.getTypeSizeInBits(InnerTy).getFixedValue())
4707 if (
Offset == 0 &&
DL.getTypeAllocSize(Ty).getFixedValue() ==
Size)
4709 if (
Offset >
DL.getTypeAllocSize(Ty).getFixedValue() ||
4710 (
DL.getTypeAllocSize(Ty).getFixedValue() -
Offset) <
Size)
4717 ElementTy = AT->getElementType();
4718 TyNumElements = AT->getNumElements();
4723 ElementTy = VT->getElementType();
4724 TyNumElements = VT->getNumElements();
4726 uint64_t ElementSize =
DL.getTypeAllocSize(ElementTy).getFixedValue();
4728 if (NumSkippedElements >= TyNumElements)
4730 Offset -= NumSkippedElements * ElementSize;
4742 if (
Size == ElementSize)
4746 if (NumElements * ElementSize !=
Size)
4770 uint64_t ElementSize =
DL.getTypeAllocSize(ElementTy).getFixedValue();
4771 if (
Offset >= ElementSize)
4782 if (
Size == ElementSize)
4789 if (Index == EndIndex)
4799 assert(Index < EndIndex);
4838bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
4852 struct SplitOffsets {
4854 std::vector<uint64_t> Splits;
4856 SmallDenseMap<Instruction *, SplitOffsets, 8> SplitOffsetsMap;
4869 SmallPtrSet<LoadInst *, 8> UnsplittableLoads;
4871 LLVM_DEBUG(
dbgs() <<
" Searching for candidate loads and stores\n");
4872 for (
auto &
P : AS.partitions()) {
4873 for (Slice &S :
P) {
4875 if (!S.isSplittable() || S.endOffset() <=
P.endOffset()) {
4880 UnsplittableLoads.
insert(LI);
4883 UnsplittableLoads.
insert(LI);
4886 assert(
P.endOffset() > S.beginOffset() &&
4887 "Empty or backwards partition!");
4896 auto IsLoadSimplyStored = [](LoadInst *LI) {
4897 for (User *LU : LI->
users()) {
4899 if (!SI || !
SI->isSimple())
4904 if (!IsLoadSimplyStored(LI)) {
4905 UnsplittableLoads.
insert(LI);
4911 if (S.getUse() != &
SI->getOperandUse(
SI->getPointerOperandIndex()))
4915 if (!StoredLoad || !StoredLoad->isSimple())
4917 assert(!
SI->isVolatile() &&
"Cannot split volatile stores!");
4927 auto &
Offsets = SplitOffsetsMap[
I];
4929 "Should not have splits the first time we see an instruction!");
4931 Offsets.Splits.push_back(
P.endOffset() - S.beginOffset());
4936 for (Slice *S :
P.splitSliceTails()) {
4937 auto SplitOffsetsMapI =
4939 if (SplitOffsetsMapI == SplitOffsetsMap.
end())
4941 auto &
Offsets = SplitOffsetsMapI->second;
4945 "Cannot have an empty set of splits on the second partition!");
4947 P.beginOffset() -
Offsets.S->beginOffset() &&
4948 "Previous split does not end where this one begins!");
4952 if (S->endOffset() >
P.endOffset())
4961 llvm::erase_if(Stores, [&UnsplittableLoads, &SplitOffsetsMap](StoreInst *SI) {
4967 if (UnsplittableLoads.
count(LI))
4970 auto LoadOffsetsI = SplitOffsetsMap.
find(LI);
4971 if (LoadOffsetsI == SplitOffsetsMap.
end())
4973 auto &LoadOffsets = LoadOffsetsI->second;
4976 auto &StoreOffsets = SplitOffsetsMap[
SI];
4981 if (LoadOffsets.Splits == StoreOffsets.Splits)
4985 <<
" " << *LI <<
"\n"
4986 <<
" " << *SI <<
"\n");
4992 UnsplittableLoads.
insert(LI);
5001 return UnsplittableLoads.
count(LI);
5006 return UnsplittableLoads.
count(LI);
5016 IRBuilderTy IRB(&AI);
5023 SmallPtrSet<AllocaInst *, 4> ResplitPromotableAllocas;
5033 SmallDenseMap<LoadInst *, std::vector<LoadInst *>, 1> SplitLoadsMap;
5034 std::vector<LoadInst *> SplitLoads;
5035 const DataLayout &
DL = AI.getDataLayout();
5036 for (LoadInst *LI : Loads) {
5039 auto &
Offsets = SplitOffsetsMap[LI];
5040 unsigned SliceSize =
Offsets.S->endOffset() -
Offsets.S->beginOffset();
5042 "Load must have type size equal to store size");
5044 "Load must be >= slice size");
5047 assert(BaseOffset + SliceSize > BaseOffset &&
5048 "Cannot represent alloca access size using 64-bit integers!");
5051 IRB.SetInsertPoint(LI);
5058 auto *PartTy = Type::getIntNTy(LI->
getContext(), PartSize * 8);
5061 LoadInst *PLoad = IRB.CreateAlignedLoad(
5064 APInt(
DL.getIndexSizeInBits(AS), PartOffset),
5065 PartPtrTy,
BasePtr->getName() +
"."),
5068 PLoad->
copyMetadata(*LI, {LLVMContext::MD_mem_parallel_loop_access,
5069 LLVMContext::MD_access_group});
5073 SplitLoads.push_back(PLoad);
5077 Slice(BaseOffset + PartOffset, BaseOffset + PartOffset + PartSize,
5081 <<
", " << NewSlices.
back().endOffset()
5082 <<
"): " << *PLoad <<
"\n");
5089 PartOffset =
Offsets.Splits[Idx];
5091 PartSize = (Idx <
Size ?
Offsets.Splits[Idx] : SliceSize) - PartOffset;
5097 bool DeferredStores =
false;
5098 for (User *LU : LI->
users()) {
5100 if (!Stores.
empty() && SplitOffsetsMap.
count(SI)) {
5101 DeferredStores =
true;
5107 Value *StoreBasePtr =
SI->getPointerOperand();
5108 IRB.SetInsertPoint(SI);
5109 AAMDNodes AATags =
SI->getAAMetadata();
5111 LLVM_DEBUG(
dbgs() <<
" Splitting store of load: " << *SI <<
"\n");
5113 for (
int Idx = 0,
Size = SplitLoads.size(); Idx <
Size; ++Idx) {
5114 LoadInst *PLoad = SplitLoads[Idx];
5116 auto *PartPtrTy =
SI->getPointerOperandType();
5118 auto AS =
SI->getPointerAddressSpace();
5119 StoreInst *PStore = IRB.CreateAlignedStore(
5122 APInt(
DL.getIndexSizeInBits(AS), PartOffset),
5123 PartPtrTy, StoreBasePtr->
getName() +
"."),
5126 PStore->
copyMetadata(*SI, {LLVMContext::MD_mem_parallel_loop_access,
5127 LLVMContext::MD_access_group,
5128 LLVMContext::MD_DIAssignID});
5133 LLVM_DEBUG(
dbgs() <<
" +" << PartOffset <<
":" << *PStore <<
"\n");
5141 ResplitPromotableAllocas.
insert(OtherAI);
5142 Worklist.insert(OtherAI);
5145 Worklist.insert(OtherAI);
5149 DeadInsts.push_back(SI);
5154 SplitLoadsMap.
insert(std::make_pair(LI, std::move(SplitLoads)));
5157 DeadInsts.push_back(LI);
5166 for (StoreInst *SI : Stores) {
5171 assert(StoreSize > 0 &&
"Cannot have a zero-sized integer store!");
5175 "Slice size should always match load size exactly!");
5177 assert(BaseOffset + StoreSize > BaseOffset &&
5178 "Cannot represent alloca access size using 64-bit integers!");
5186 auto SplitLoadsMapI = SplitLoadsMap.
find(LI);
5187 std::vector<LoadInst *> *SplitLoads =
nullptr;
5188 if (SplitLoadsMapI != SplitLoadsMap.
end()) {
5189 SplitLoads = &SplitLoadsMapI->second;
5191 "Too few split loads for the number of splits in the store!");
5199 auto *PartTy = Type::getIntNTy(Ty->
getContext(), PartSize * 8);
5201 auto *StorePartPtrTy =
SI->getPointerOperandType();
5206 PLoad = (*SplitLoads)[Idx];
5208 IRB.SetInsertPoint(LI);
5210 PLoad = IRB.CreateAlignedLoad(
5213 APInt(
DL.getIndexSizeInBits(AS), PartOffset),
5214 LoadPartPtrTy, LoadBasePtr->
getName() +
"."),
5217 PLoad->
copyMetadata(*LI, {LLVMContext::MD_mem_parallel_loop_access,
5218 LLVMContext::MD_access_group});
5222 IRB.SetInsertPoint(SI);
5223 auto AS =
SI->getPointerAddressSpace();
5224 StoreInst *PStore = IRB.CreateAlignedStore(
5227 APInt(
DL.getIndexSizeInBits(AS), PartOffset),
5228 StorePartPtrTy, StoreBasePtr->
getName() +
"."),
5231 PStore->
copyMetadata(*SI, {LLVMContext::MD_mem_parallel_loop_access,
5232 LLVMContext::MD_access_group});
5236 Slice(BaseOffset + PartOffset, BaseOffset + PartOffset + PartSize,
5240 <<
", " << NewSlices.
back().endOffset()
5241 <<
"): " << *PStore <<
"\n");
5251 PartOffset =
Offsets.Splits[Idx];
5253 PartSize = (Idx <
Size ?
Offsets.Splits[Idx] : StoreSize) - PartOffset;
5263 assert(OtherAI != &AI &&
"We can't re-split our own alloca!");
5264 ResplitPromotableAllocas.
insert(OtherAI);
5265 Worklist.insert(OtherAI);
5268 assert(OtherAI != &AI &&
"We can't re-split our own alloca!");
5269 Worklist.insert(OtherAI);
5284 DeadInsts.push_back(LI);
5286 DeadInsts.push_back(SI);
5295 AS.insert(NewSlices);
5299 for (
auto I = AS.begin(),
E = AS.end();
I !=
E; ++
I)
5305 PromotableAllocas.set_subtract(ResplitPromotableAllocas);
5342 bool IsIntegralPointerTy =
5343 EltTy->
isPointerTy() && !
DL.isNonIntegralPointerType(EltTy);
5345 !IsIntegralPointerTy)
5352 if (
DL.getTypeSizeInBits(EltTy) !=
DL.getTypeAllocSizeInBits(EltTy))
5356 TypeSize StructSize =
DL.getStructLayout(STy)->getSizeInBytes();
5357 TypeSize VectorSize =
DL.getTypeStoreSize(VTy);
5360 if (StructSize != VectorSize)
5363 auto IsIgnorableOrMemIntrinsicSlice = [](
const Slice &S) {
5366 auto *U = S.getUse();
5370 User *Usr = U->getUser();
5377 for (
const Slice &S :
P)
5378 if (!IsIgnorableOrMemIntrinsicSlice(S))
5381 for (
const Slice *S :
P.splitSliceTails())
5382 if (!IsIgnorableOrMemIntrinsicSlice(*S))
5399static std::tuple<Type *, bool, VectorType *>
5403 VectorType *SelectedVecTy,
bool SelectedIntWidening) {
5405 dbgs() <<
"selectPartitionType path=" << Path
5410 dbgs() <<
"<unnamed>";
5411 dbgs() <<
" partition=[" <<
P.beginOffset() <<
"," <<
P.endOffset()
5412 <<
") size=" <<
P.size();
5414 dbgs() <<
" alloc-size=" << AllocSize->getKnownMinValue();
5416 dbgs() <<
" chosen=" << *SelectedTy;
5418 dbgs() <<
" vec=" << *SelectedVecTy;
5419 dbgs() <<
" intwiden=" << SelectedIntWidening <<
"\n";
5437 if (VecTy && VecTy->getElementType()->isFloatingPointTy() &&
5438 VecTy->getElementCount().getFixedValue() > 1) {
5439 LogSelection(
"direct-fp-vecty", VecTy, VecTy,
false);
5440 return {VecTy,
false, VecTy};
5445 auto [CommonUseTy, LargestIntTy] =
5448 TypeSize CommonUseSize =
DL.getTypeAllocSize(CommonUseTy);
5454 LogSelection(
"common-type-vecty", VecTy, VecTy,
false);
5455 return {VecTy,
false, VecTy};
5458 LogSelection(
"common-type", CommonUseTy,
nullptr, IntWiden);
5459 return {CommonUseTy, IntWiden,
nullptr};
5466 P.beginOffset(),
P.size())) {
5470 if (TypePartitionTy->isArrayTy() &&
5471 TypePartitionTy->getArrayElementType()->isIntegerTy() &&
5472 DL.isLegalInteger(
P.size() * 8))
5476 LogSelection(
"type-partition-int-widen", TypePartitionTy,
nullptr,
true);
5477 return {TypePartitionTy,
true,
nullptr};
5480 LogSelection(
"type-partition-vecty", VecTy, VecTy,
false);
5481 return {VecTy,
false, VecTy};
5486 DL.getTypeAllocSize(LargestIntTy).getFixedValue() >=
P.size() &&
5488 LogSelection(
"largest-int-int-widen", LargestIntTy,
nullptr,
true);
5489 return {LargestIntTy,
true,
nullptr};
5494 if (AggregateToVector) {
5497 LogSelection(
"struct-fallback-vecty", VTy,
nullptr,
false);
5498 return {VTy,
false,
nullptr};
5504 LogSelection(
"type-partition-fallback", TypePartitionTy,
nullptr,
false);
5505 return {TypePartitionTy,
false,
nullptr};
5510 DL.getTypeAllocSize(LargestIntTy).getFixedValue() >=
P.size()) {
5511 LogSelection(
"largest-int-fallback", LargestIntTy,
nullptr,
false);
5512 return {LargestIntTy,
false,
nullptr};
5516 if (
DL.isLegalInteger(
P.size() * 8)) {
5518 LogSelection(
"legal-int-fallback", IntTy,
nullptr,
false);
5519 return {IntTy,
false,
nullptr};
5524 LogSelection(
"byte-array-fallback", ArrayTy,
nullptr,
false);
5525 return {ArrayTy,
false,
nullptr};
5538std::pair<AllocaInst *, uint64_t>
5539SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS, Partition &
P) {
5540 const DataLayout &
DL = AI.getDataLayout();
5542 auto [PartitionTy, IsIntegerWideningViable, VecTy] =
5552 if (PartitionTy == AI.getAllocatedType() &&
P.beginOffset() == 0) {
5562 const bool IsUnconstrained =
Alignment <=
DL.getABITypeAlign(PartitionTy);
5563 NewAI =
new AllocaInst(
5564 PartitionTy, AI.getAddressSpace(),
nullptr,
5565 IsUnconstrained ?
DL.getPrefTypeAlign(PartitionTy) : Alignment,
5566 AI.
getName() +
".sroa." + Twine(
P.begin() - AS.begin()),
5573 LLVM_DEBUG(
dbgs() <<
"Rewriting alloca partition " <<
"[" <<
P.beginOffset()
5574 <<
"," <<
P.endOffset() <<
") to: " << *NewAI <<
"\n");
5579 unsigned PPWOldSize = PostPromotionWorklist.size();
5580 unsigned NumUses = 0;
5581 SmallSetVector<PHINode *, 8> PHIUsers;
5582 SmallSetVector<SelectInst *, 8> SelectUsers;
5585 DL, AS, *
this, AI, *NewAI, PartitionTy,
P.beginOffset(),
P.endOffset(),
5586 IsIntegerWideningViable, VecTy, PHIUsers, SelectUsers);
5587 bool Promotable =
true;
5589 if (
auto DeletedValues =
Rewriter.rewriteTreeStructuredMerge(
P)) {
5590 NumUses += DeletedValues->
size() + 1;
5591 for (
Value *V : *DeletedValues)
5592 DeadInsts.push_back(V);
5594 for (Slice *S :
P.splitSliceTails()) {
5598 for (Slice &S :
P) {
5604 NumAllocaPartitionUses += NumUses;
5605 MaxUsesPerAllocaPartition.updateMax(NumUses);
5609 for (PHINode *
PHI : PHIUsers)
5613 SelectUsers.
clear();
5618 NewSelectsToRewrite;
5620 for (SelectInst *Sel : SelectUsers) {
5621 std::optional<RewriteableMemOps>
Ops =
5622 isSafeSelectToSpeculate(*Sel, PreserveCFG);
5626 SelectUsers.clear();
5627 NewSelectsToRewrite.
clear();
5634 for (Use *U : AS.getDeadUsesIfPromotable()) {
5636 Value::dropDroppableUse(*U);
5639 DeadInsts.push_back(OldInst);
5641 if (PHIUsers.empty() && SelectUsers.empty()) {
5643 PromotableAllocas.insert(NewAI);
5648 SpeculatablePHIs.insert_range(PHIUsers);
5649 SelectsToRewrite.reserve(SelectsToRewrite.size() +
5650 NewSelectsToRewrite.
size());
5652 std::make_move_iterator(NewSelectsToRewrite.
begin()),
5653 std::make_move_iterator(NewSelectsToRewrite.
end())))
5654 SelectsToRewrite.insert(std::move(KV));
5655 Worklist.insert(NewAI);
5659 while (PostPromotionWorklist.size() > PPWOldSize)
5660 PostPromotionWorklist.pop_back();
5665 return {
nullptr, 0};
5670 Worklist.insert(NewAI);
5673 return {NewAI,
DL.getTypeSizeInBits(PartitionTy).getFixedValue()};
5717 int64_t BitExtractOffset) {
5719 bool HasFragment =
false;
5720 bool HasBitExtract =
false;
5728 HasBitExtract =
true;
5729 int64_t ExtractOffsetInBits = Extract.getOffsetInBits();
5730 int64_t ExtractSizeInBits = Extract.getSizeInBits();
5739 assert(BitExtractOffset <= 0);
5740 int64_t AdjustedOffset = ExtractOffsetInBits + BitExtractOffset;
5746 if (AdjustedOffset < 0)
5749 Ops.push_back(
Op.getOp());
5750 Ops.push_back(std::max<int64_t>(0, AdjustedOffset));
5751 Ops.push_back(ExtractSizeInBits);
5754 Op.appendToVector(
Ops);
5759 if (HasFragment && HasBitExtract)
5762 if (!HasBitExtract) {
5781 std::optional<DIExpression::FragmentInfo> NewFragment,
5782 int64_t BitExtractAdjustment) {
5792 BitExtractAdjustment);
5793 if (!NewFragmentExpr)
5799 BeforeInst->
getParent()->insertDbgRecordBefore(DVR,
5812 BeforeInst->
getParent()->insertDbgRecordBefore(DVR,
5818 if (!NewAddr->
hasMetadata(LLVMContext::MD_DIAssignID)) {
5826 LLVM_DEBUG(
dbgs() <<
"Created new DVRAssign: " << *NewAssign <<
"\n");
5832bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
5833 if (AS.begin() == AS.end())
5836 unsigned NumPartitions = 0;
5838 const DataLayout &
DL = AI.getModule()->getDataLayout();
5841 Changed |= presplitLoadsAndStores(AI, AS);
5849 bool IsSorted =
true;
5851 uint64_t AllocaSize = AI.getAllocationSize(
DL)->getFixedValue();
5852 const uint64_t MaxBitVectorSize = 1024;
5853 if (AllocaSize <= MaxBitVectorSize) {
5856 SmallBitVector SplittableOffset(AllocaSize + 1,
true);
5858 for (
unsigned O = S.beginOffset() + 1;
5859 O < S.endOffset() && O < AllocaSize; O++)
5860 SplittableOffset.reset(O);
5862 for (Slice &S : AS) {
5863 if (!S.isSplittable())
5866 if ((S.beginOffset() > AllocaSize || SplittableOffset[S.beginOffset()]) &&
5867 (S.endOffset() > AllocaSize || SplittableOffset[S.endOffset()]))
5872 S.makeUnsplittable();
5879 for (Slice &S : AS) {
5880 if (!S.isSplittable())
5883 if (S.beginOffset() == 0 && S.endOffset() >= AllocaSize)
5888 S.makeUnsplittable();
5909 for (
auto &
P : AS.partitions()) {
5910 auto [NewAI, ActiveBits] = rewritePartition(AI, AS, P);
5914 uint64_t SizeOfByte = 8;
5916 uint64_t Size = std::min(ActiveBits, P.size() * SizeOfByte);
5917 Fragments.push_back(
5918 Fragment(NewAI, P.beginOffset() * SizeOfByte, Size));
5924 NumAllocaPartitions += NumPartitions;
5925 MaxPartitionsPerAlloca.updateMax(NumPartitions);
5929 auto MigrateOne = [&](DbgVariableRecord *DbgVariable) {
5934 const Value *DbgPtr = DbgVariable->getAddress();
5936 DbgVariable->getFragmentOrEntireVariable();
5939 int64_t CurrentExprOffsetInBytes = 0;
5940 SmallVector<uint64_t> PostOffsetOps;
5942 ->extractLeadingOffset(CurrentExprOffsetInBytes, PostOffsetOps))
5946 int64_t ExtractOffsetInBits = 0;
5949 ExtractOffsetInBits = Extract.getOffsetInBits();
5954 DIBuilder DIB(*AI.getModule(),
false);
5955 for (
auto Fragment : Fragments) {
5956 int64_t OffsetFromLocationInBits;
5957 std::optional<DIExpression::FragmentInfo> NewDbgFragment;
5962 DL, &AI, Fragment.Offset, Fragment.Size, DbgPtr,
5963 CurrentExprOffsetInBytes * 8, ExtractOffsetInBits, VarFrag,
5964 NewDbgFragment, OffsetFromLocationInBits))
5970 if (NewDbgFragment && !NewDbgFragment->SizeInBits)
5975 if (!NewDbgFragment)
5976 NewDbgFragment = DbgVariable->getFragment();
5980 int64_t OffestFromNewAllocaInBits =
5981 OffsetFromLocationInBits - ExtractOffsetInBits;
5984 int64_t BitExtractOffset =
5985 std::min<int64_t>(0, OffestFromNewAllocaInBits);
5990 OffestFromNewAllocaInBits =
5991 std::max(int64_t(0), OffestFromNewAllocaInBits);
5997 DIExpression *NewExpr = DIExpression::get(AI.getContext(), PostOffsetOps);
5998 if (OffestFromNewAllocaInBits > 0) {
5999 int64_t OffsetInBytes = (OffestFromNewAllocaInBits + 7) / 8;
6005 auto RemoveOne = [DbgVariable](
auto *OldDII) {
6006 auto SameVariableFragment = [](
const auto *
LHS,
const auto *
RHS) {
6007 return LHS->getVariable() ==
RHS->getVariable() &&
6008 LHS->getDebugLoc()->getInlinedAt() ==
6009 RHS->getDebugLoc()->getInlinedAt();
6011 if (SameVariableFragment(OldDII, DbgVariable))
6012 OldDII->eraseFromParent();
6017 NewDbgFragment, BitExtractOffset);
6031void SROA::clobberUse(Use &U) {
6041 DeadInsts.push_back(OldI);
6063bool SROA::propagateStoredValuesToLoads(AllocaInst &AI, AllocaSlices &AS) {
6068 LLVM_DEBUG(
dbgs() <<
"Attempting to propagate values on " << AI <<
"\n");
6069 bool AllSameAndValid =
true;
6070 Type *PartitionType =
nullptr;
6071 SmallVector<Instruction *> Insts;
6075 auto Flush = [&]() {
6076 if (AllSameAndValid && !Insts.
empty()) {
6077 LLVM_DEBUG(
dbgs() <<
"Propagate values on slice [" << BeginOffset <<
", "
6078 << EndOffset <<
")\n");
6080 SSAUpdater
SSA(&NewPHIs);
6082 BasicLoadAndStorePromoter Promoter(Insts,
SSA, PartitionType);
6083 Promoter.run(Insts);
6085 AllSameAndValid =
true;
6086 PartitionType =
nullptr;
6090 for (Slice &S : AS) {
6094 dbgs() <<
"Ignoring slice: ";
6095 AS.print(
dbgs(), &S);
6099 if (S.beginOffset() >= EndOffset) {
6101 BeginOffset = S.beginOffset();
6102 EndOffset = S.endOffset();
6103 }
else if (S.beginOffset() != BeginOffset || S.endOffset() != EndOffset) {
6104 if (AllSameAndValid) {
6106 dbgs() <<
"Slice does not match range [" << BeginOffset <<
", "
6107 << EndOffset <<
")";
6108 AS.print(
dbgs(), &S);
6110 AllSameAndValid =
false;
6112 EndOffset = std::max(EndOffset, S.endOffset());
6119 if (!LI->
isSimple() || (PartitionType && UserTy != PartitionType))
6120 AllSameAndValid =
false;
6121 PartitionType = UserTy;
6124 Type *UserTy =
SI->getValueOperand()->getType();
6125 if (!
SI->isSimple() || (PartitionType && UserTy != PartitionType))
6126 AllSameAndValid =
false;
6127 PartitionType = UserTy;
6130 AllSameAndValid =
false;
6143std::pair<
bool ,
bool >
6144SROA::runOnAlloca(AllocaInst &AI) {
6146 bool CFGChanged =
false;
6149 ++NumAllocasAnalyzed;
6152 if (AI.use_empty()) {
6153 AI.eraseFromParent();
6157 const DataLayout &
DL = AI.getDataLayout();
6160 std::optional<TypeSize>
Size = AI.getAllocationSize(
DL);
6161 if (AI.isArrayAllocation() || !
Size ||
Size->isScalable() ||
Size->isZero())
6166 IRBuilderTy IRB(&AI);
6167 AggLoadStoreRewriter AggRewriter(
DL, IRB);
6168 Changed |= AggRewriter.rewrite(AI);
6171 AllocaSlices AS(
DL, AI);
6176 if (AS.isEscapedReadOnly()) {
6177 Changed |= propagateStoredValuesToLoads(AI, AS);
6182 for (Instruction *DeadUser : AS.getDeadUsers()) {
6184 for (Use &DeadOp : DeadUser->operands())
6191 DeadInsts.push_back(DeadUser);
6194 for (Use *DeadOp : AS.getDeadOperands()) {
6195 clobberUse(*DeadOp);
6200 if (AS.begin() == AS.end())
6203 Changed |= splitAlloca(AI, AS);
6206 while (!SpeculatablePHIs.empty())
6210 auto RemainingSelectsToRewrite = SelectsToRewrite.takeVector();
6211 while (!RemainingSelectsToRewrite.empty()) {
6212 const auto [
K,
V] = RemainingSelectsToRewrite.pop_back_val();
6229bool SROA::deleteDeadInstructions(
6230 SmallPtrSetImpl<AllocaInst *> &DeletedAllocas) {
6232 while (!DeadInsts.empty()) {
6242 DeletedAllocas.
insert(AI);
6244 OldDII->eraseFromParent();
6250 for (Use &Operand :
I->operands())
6255 DeadInsts.push_back(U);
6259 I->eraseFromParent();
6269bool SROA::promoteAllocas() {
6270 if (PromotableAllocas.empty())
6277 NumPromoted += PromotableAllocas.size();
6278 PromoteMemToReg(PromotableAllocas.getArrayRef(), DTU->getDomTree(), AC);
6281 PromotableAllocas.clear();
6285std::pair<
bool ,
bool > SROA::runSROA(
Function &
F) {
6288 const DataLayout &
DL =
F.getDataLayout();
6293 std::optional<TypeSize>
Size = AI->getAllocationSize(
DL);
6295 PromotableAllocas.insert(AI);
6297 Worklist.insert(AI);
6302 bool CFGChanged =
false;
6305 SmallPtrSet<AllocaInst *, 4> DeletedAllocas;
6308 while (!Worklist.empty()) {
6309 auto [IterationChanged, IterationCFGChanged] =
6310 runOnAlloca(*Worklist.pop_back_val());
6312 CFGChanged |= IterationCFGChanged;
6314 Changed |= deleteDeadInstructions(DeletedAllocas);
6318 if (!DeletedAllocas.
empty()) {
6319 Worklist.set_subtract(DeletedAllocas);
6320 PostPromotionWorklist.set_subtract(DeletedAllocas);
6321 PromotableAllocas.set_subtract(DeletedAllocas);
6322 DeletedAllocas.
clear();
6328 Worklist = PostPromotionWorklist;
6329 PostPromotionWorklist.clear();
6330 }
while (!Worklist.empty());
6332 assert((!CFGChanged ||
Changed) &&
"Can not only modify the CFG.");
6333 assert((!CFGChanged || !PreserveCFG) &&
6334 "Should not have modified the CFG when told to preserve it.");
6337 for (
auto &BB :
F) {
6350 SROA(&
F.getContext(), &DTU, &AC, Options).runSROA(
F);
6362 static_cast<PassInfoMixin<SROAPass> *
>(
this)->
printPipeline(
6363 OS, MapClassName2PassName);
6367 if (Options.AggregateToVector)
6368 OS <<
";aggregate-to-vector";
6389 if (skipFunction(
F))
6392 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
6394 getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
6400 void getAnalysisUsage(AnalysisUsage &AU)
const override {
6407 StringRef getPassName()
const override {
return "SROA"; }
6412char SROALegacyPass::ID = 0;
6417 AggregateToVector));
6421 "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.
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(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.
const SmallVectorImpl< MachineOperand > & 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 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 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 void rewriteMemOpOfSelect(SelectInst &SI, T &I, SelectHandSpeculativity Spec, DomTreeUpdater &DTU)
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)
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 implements the SmallBitVector class.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static SymbolRef::Type getType(const Symbol *Sym)
static unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type.
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++()
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.
InstListType::iterator iterator
Instruction iterators...
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.
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.
iterator find(const_arg_type_t< KeyT > Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
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.
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...
virtual 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()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
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...
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
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
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
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.
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.
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.
const Use & getOperandUse(unsigned i) const
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
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.
iterator_range< user_iterator > users()
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.
initializer< Ty > init(const Ty &Val)
@ 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.
static cl::opt< bool > SROASkipMem2Reg("sroa-skip-mem2reg", cl::init(false), cl::Hidden)
Disable running mem2reg during SROA in order to test or debug SROA.
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.
LLVM_ABI cl::opt< bool > ProfcheckDisableMetadataFixes
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.
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.
LLVM_ABI std::optional< RegOrConstant > getVectorSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI)
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.
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)
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.
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...
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 > >
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
LLVM_ABI bool isAssignmentTrackingEnabled(const Module &M)
Return true if assignment tracking is enabled for module M.
DWARFExpression::Operation Op
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.
LLVM_ABI bool isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &Size, const SimplifyQuery &SQ)
Return true if we know that executing a load from this value cannot trap.
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
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.
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.
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.