47#include "llvm/Config/llvm-config.h"
103#define DEBUG_TYPE "sroa"
105STATISTIC(NumAllocasAnalyzed,
"Number of allocas analyzed for replacement");
106STATISTIC(NumAllocaPartitions,
"Number of alloca partitions formed");
107STATISTIC(MaxPartitionsPerAlloca,
"Maximum number of partitions per alloca");
108STATISTIC(NumAllocaPartitionUses,
"Number of alloca partition uses rewritten");
109STATISTIC(MaxUsesPerAllocaPartition,
"Maximum number of uses of a partition");
110STATISTIC(NumNewAllocas,
"Number of new, smaller allocas introduced");
111STATISTIC(NumPromoted,
"Number of allocas promoted to SSA values");
112STATISTIC(NumLoadsSpeculated,
"Number of loads speculated to allow promotion");
114 "Number of loads rewritten into predicated loads to allow promotion");
117 "Number of stores rewritten into predicated loads to allow promotion");
119STATISTIC(NumVectorized,
"Number of vectorized aggregates");
130class AllocaSliceRewriter;
134class SelectHandSpeculativity {
135 unsigned char Storage = 0;
139 SelectHandSpeculativity() =
default;
140 SelectHandSpeculativity &setAsSpeculatable(
bool isTrueVal);
141 bool isSpeculatable(
bool isTrueVal)
const;
142 bool areAllSpeculatable()
const;
143 bool areAnySpeculatable()
const;
144 bool areNoneSpeculatable()
const;
146 explicit operator intptr_t()
const {
return static_cast<intptr_t
>(Storage); }
147 explicit SelectHandSpeculativity(intptr_t Storage_) : Storage(Storage_) {}
149static_assert(
sizeof(SelectHandSpeculativity) ==
sizeof(
unsigned char));
151using PossiblySpeculatableLoad =
154using RewriteableMemOp =
155 std::variant<PossiblySpeculatableLoad, UnspeculatableStore>;
177 LLVMContext *
const C;
178 DomTreeUpdater *
const DTU;
179 AssumptionCache *
const AC;
180 const bool PreserveCFG;
181 const bool AggregateToVector;
190 SmallSetVector<AllocaInst *, 16> Worklist;
205 SmallSetVector<AllocaInst *, 16> PostPromotionWorklist;
208 SetVector<AllocaInst *, SmallVector<AllocaInst *>,
209 SmallPtrSet<AllocaInst *, 16>, 16>
217 SmallSetVector<PHINode *, 8> SpeculatablePHIs;
221 SmallMapVector<SelectInst *, RewriteableMemOps, 8> SelectsToRewrite;
239 static std::optional<RewriteableMemOps>
240 isSafeSelectToSpeculate(SelectInst &SI,
bool PreserveCFG);
243 SROA(LLVMContext *C, DomTreeUpdater *DTU, AssumptionCache *AC,
245 : C(C), DTU(DTU), AC(AC),
246 PreserveCFG(
Options.
CFG == SROAOptions::PreserveCFG),
247 AggregateToVector(
Options.AggregateToVector) {}
250 std::pair<
bool ,
bool > runSROA(Function &
F);
253 friend class AllocaSliceRewriter;
255 bool presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS);
256 std::pair<AllocaInst *, uint64_t>
257 rewritePartition(AllocaInst &AI, AllocaSlices &AS, Partition &
P);
258 bool splitAlloca(AllocaInst &AI, AllocaSlices &AS);
259 bool propagateStoredValuesToLoads(AllocaInst &AI, AllocaSlices &AS);
260 std::pair<
bool ,
bool > runOnAlloca(AllocaInst &AI);
261 void clobberUse(Use &U);
262 bool deleteDeadInstructions(SmallPtrSetImpl<AllocaInst *> &DeletedAllocas);
263 bool promoteAllocas();
277enum FragCalcResult { UseFrag, UseNoFrag,
Skip };
281 uint64_t NewStorageSliceOffsetInBits,
283 std::optional<DIExpression::FragmentInfo> StorageFragment,
284 std::optional<DIExpression::FragmentInfo> CurrentFragment,
288 if (StorageFragment) {
290 std::min(NewStorageSliceSizeInBits, StorageFragment->SizeInBits);
292 NewStorageSliceOffsetInBits + StorageFragment->OffsetInBits;
294 Target.SizeInBits = NewStorageSliceSizeInBits;
295 Target.OffsetInBits = NewStorageSliceOffsetInBits;
301 if (!CurrentFragment) {
302 if (
auto Size = Variable->getSizeInBits()) {
305 if (
Target == CurrentFragment)
312 if (!CurrentFragment || *CurrentFragment ==
Target)
318 if (
Target.startInBits() < CurrentFragment->startInBits() ||
319 Target.endInBits() > CurrentFragment->endInBits())
358 if (DVRAssignMarkerRange.empty())
364 LLVM_DEBUG(
dbgs() <<
" OldAllocaOffsetInBits: " << OldAllocaOffsetInBits
366 LLVM_DEBUG(
dbgs() <<
" SliceSizeInBits: " << SliceSizeInBits <<
"\n");
378 DVR->getExpression()->getFragmentInfo();
391 auto *Expr = DbgAssign->getExpression();
392 bool SetKillLocation =
false;
395 std::optional<DIExpression::FragmentInfo> BaseFragment;
398 if (R == BaseFragments.
end())
400 BaseFragment = R->second;
402 std::optional<DIExpression::FragmentInfo> CurrentFragment =
403 Expr->getFragmentInfo();
406 DbgAssign->getVariable(), OldAllocaOffsetInBits, SliceSizeInBits,
407 BaseFragment, CurrentFragment, NewFragment);
411 if (Result == UseFrag && !(NewFragment == CurrentFragment)) {
412 if (CurrentFragment) {
417 NewFragment.
OffsetInBits -= CurrentFragment->OffsetInBits;
430 SetKillLocation =
true;
438 Inst->
setMetadata(LLVMContext::MD_DIAssignID, NewID);
447 DbgAssign->getDebugLoc())));
450 NewAssign = DbgAssign;
469 Value && (DbgAssign->hasArgList() ||
470 !DbgAssign->getExpression()->isSingleLocationExpression());
487 if (NewAssign != DbgAssign) {
488 NewAssign->
moveBefore(DbgAssign->getIterator());
491 LLVM_DEBUG(
dbgs() <<
"Created new assign: " << *NewAssign <<
"\n");
494 for_each(DVRAssignMarkerRange, MigrateDbgAssign);
504 Twine getNameWithPrefix(
const Twine &Name)
const {
509 void SetNamePrefix(
const Twine &
P) { Prefix =
P.str(); }
511 void InsertHelper(Instruction *
I,
const Twine &Name,
529 uint64_t BeginOffset = 0;
532 uint64_t EndOffset = 0;
536 PointerIntPair<Use *, 1, bool> UseAndIsSplittable;
541 Slice(uint64_t BeginOffset, uint64_t EndOffset, Use *U,
bool IsSplittable)
542 : BeginOffset(BeginOffset), EndOffset(EndOffset),
543 UseAndIsSplittable(
U, IsSplittable) {}
545 uint64_t beginOffset()
const {
return BeginOffset; }
546 uint64_t endOffset()
const {
return EndOffset; }
548 bool isSplittable()
const {
return UseAndIsSplittable.getInt(); }
549 void makeUnsplittable() { UseAndIsSplittable.setInt(
false); }
551 Use *getUse()
const {
return UseAndIsSplittable.getPointer(); }
553 bool isDead()
const {
return getUse() ==
nullptr; }
554 void kill() { UseAndIsSplittable.setPointer(
nullptr); }
563 if (beginOffset() <
RHS.beginOffset())
565 if (beginOffset() >
RHS.beginOffset())
567 if (isSplittable() !=
RHS.isSplittable())
568 return !isSplittable();
569 if (endOffset() >
RHS.endOffset())
575 [[maybe_unused]]
friend bool operator<(
const Slice &
LHS, uint64_t RHSOffset) {
576 return LHS.beginOffset() < RHSOffset;
578 [[maybe_unused]]
friend bool operator<(uint64_t LHSOffset,
const Slice &
RHS) {
579 return LHSOffset <
RHS.beginOffset();
583 return isSplittable() ==
RHS.isSplittable() &&
584 beginOffset() ==
RHS.beginOffset() && endOffset() ==
RHS.endOffset();
599 AllocaSlices(
const DataLayout &
DL, AllocaInst &AI);
605 bool isEscaped()
const {
return PointerEscapingInstr; }
606 bool isEscapedReadOnly()
const {
return PointerEscapingInstrReadOnly; }
611 using range = iterator_range<iterator>;
613 iterator
begin() {
return Slices.begin(); }
614 iterator
end() {
return Slices.end(); }
617 using const_range = iterator_range<const_iterator>;
619 const_iterator
begin()
const {
return Slices.begin(); }
620 const_iterator
end()
const {
return Slices.end(); }
624 void erase(iterator Start, iterator Stop) { Slices.erase(Start, Stop); }
632 int OldSize = Slices.size();
633 Slices.append(NewSlices.
begin(), NewSlices.
end());
634 auto SliceI = Slices.begin() + OldSize;
635 std::stable_sort(SliceI, Slices.end());
636 std::inplace_merge(Slices.begin(), SliceI, Slices.end());
649 return DeadUseIfPromotable;
660#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
661 void print(raw_ostream &OS, const_iterator
I, StringRef Indent =
" ")
const;
662 void printSlice(raw_ostream &OS, const_iterator
I,
663 StringRef Indent =
" ")
const;
664 void printUse(raw_ostream &OS, const_iterator
I,
665 StringRef Indent =
" ")
const;
666 void print(raw_ostream &OS)
const;
667 void dump(const_iterator
I)
const;
672 template <
typename DerivedT,
typename RetT =
void>
class BuilderBase;
675 friend class AllocaSlices::SliceBuilder;
677#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
705 SmallVector<Instruction *, 8> DeadUsers;
732 friend class AllocaSlices;
733 friend class AllocaSlices::partition_iterator;
735 using iterator = AllocaSlices::iterator;
739 uint64_t BeginOffset = 0, EndOffset = 0;
749 Partition(iterator SI) : SI(SI), SJ(SI) {}
755 uint64_t beginOffset()
const {
return BeginOffset; }
760 uint64_t endOffset()
const {
return EndOffset; }
765 uint64_t
size()
const {
766 assert(BeginOffset < EndOffset &&
"Partitions must span some bytes!");
767 return EndOffset - BeginOffset;
772 bool empty()
const {
return SI == SJ; }
783 iterator
begin()
const {
return SI; }
784 iterator
end()
const {
return SJ; }
816 AllocaSlices::iterator SE;
820 uint64_t MaxSplitSliceEndOffset = 0;
824 partition_iterator(AllocaSlices::iterator
SI, AllocaSlices::iterator SE)
836 assert((
P.SI != SE || !
P.SplitTails.empty()) &&
837 "Cannot advance past the end of the slices!");
840 if (!
P.SplitTails.empty()) {
841 if (
P.EndOffset >= MaxSplitSliceEndOffset) {
843 P.SplitTails.clear();
844 MaxSplitSliceEndOffset = 0;
850 [&](Slice *S) { return S->endOffset() <= P.EndOffset; });
853 return S->endOffset() == MaxSplitSliceEndOffset;
855 "Could not find the current max split slice offset!");
858 return S->endOffset() <= MaxSplitSliceEndOffset;
860 "Max split slice end offset is not actually the max!");
867 assert(P.SplitTails.empty() &&
"Failed to clear the split slices!");
877 if (S.isSplittable() && S.endOffset() > P.EndOffset) {
878 P.SplitTails.push_back(&S);
879 MaxSplitSliceEndOffset =
880 std::max(S.endOffset(), MaxSplitSliceEndOffset);
888 P.BeginOffset = P.EndOffset;
889 P.EndOffset = MaxSplitSliceEndOffset;
896 if (!P.SplitTails.empty() && P.SI->beginOffset() != P.EndOffset &&
897 !P.SI->isSplittable()) {
898 P.BeginOffset = P.EndOffset;
899 P.EndOffset = P.SI->beginOffset();
909 P.BeginOffset = P.SplitTails.empty() ? P.SI->beginOffset() : P.EndOffset;
910 P.EndOffset = P.SI->endOffset();
915 if (!P.SI->isSplittable()) {
918 assert(P.BeginOffset == P.SI->beginOffset());
922 while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) {
923 if (!P.SJ->isSplittable())
924 P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset());
936 assert(P.SI->isSplittable() &&
"Forming a splittable partition!");
939 while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset &&
940 P.SJ->isSplittable()) {
941 P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset());
948 if (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) {
949 assert(!P.SJ->isSplittable());
950 P.EndOffset = P.SJ->beginOffset();
957 "End iterators don't match between compared partition iterators!");
964 if (P.SI == RHS.P.SI && P.SplitTails.empty() == RHS.P.SplitTails.empty()) {
965 assert(P.SJ == RHS.P.SJ &&
966 "Same set of slices formed two different sized partitions!");
967 assert(P.SplitTails.size() == RHS.P.SplitTails.size() &&
968 "Same slice position with differently sized non-empty split "
991 return make_range(partition_iterator(begin(), end()),
992 partition_iterator(end(), end()));
1000 return SI.getOperand(1 + CI->isZero());
1001 if (
SI.getOperand(1) ==
SI.getOperand(2))
1002 return SI.getOperand(1);
1011 return PN->hasConstantValue();
1042 if (VisitedDeadInsts.
insert(&
I).second)
1047 bool IsSplittable =
false) {
1053 <<
" which has zero size or starts outside of the "
1054 << AllocSize <<
" byte alloca:\n"
1055 <<
" alloca: " << AS.AI <<
"\n"
1056 <<
" use: " <<
I <<
"\n");
1057 return markAsDead(
I);
1060 uint64_t BeginOffset =
Offset.getZExtValue();
1061 uint64_t EndOffset = BeginOffset +
Size;
1069 assert(AllocSize >= BeginOffset);
1070 if (
Size > AllocSize - BeginOffset) {
1072 <<
Offset <<
" to remain within the " << AllocSize
1073 <<
" byte alloca:\n"
1074 <<
" alloca: " << AS.AI <<
"\n"
1075 <<
" use: " <<
I <<
"\n");
1076 EndOffset = AllocSize;
1079 AS.Slices.push_back(Slice(BeginOffset, EndOffset, U, IsSplittable));
1082 void visitBitCastInst(BitCastInst &BC) {
1084 return markAsDead(BC);
1086 return Base::visitBitCastInst(BC);
1089 void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
1091 return markAsDead(ASC);
1093 return Base::visitAddrSpaceCastInst(ASC);
1096 void visitGetElementPtrInst(GetElementPtrInst &GEPI) {
1098 return markAsDead(GEPI);
1100 return Base::visitGetElementPtrInst(GEPI);
1103 void handleLoadOrStore(
Type *Ty, Instruction &
I,
const APInt &
Offset,
1104 uint64_t
Size,
bool IsVolatile) {
1114 void visitLoadInst(LoadInst &LI) {
1116 "All simple FCA loads should have been pre-split");
1121 return PI.setEscapedReadOnly(&LI);
1124 if (
Size.isScalable()) {
1127 return PI.setAborted(&LI);
1136 void visitStoreInst(StoreInst &SI) {
1137 Value *ValOp =
SI.getValueOperand();
1139 return PI.setEscapedAndAborted(&SI);
1141 return PI.setAborted(&SI);
1143 TypeSize StoreSize =
DL.getTypeStoreSize(ValOp->
getType());
1145 unsigned VScale =
SI.getFunction()->getVScaleValue();
1147 return PI.setAborted(&SI);
1163 <<
Offset <<
" which extends past the end of the "
1164 << AllocSize <<
" byte alloca:\n"
1165 <<
" alloca: " << AS.AI <<
"\n"
1166 <<
" use: " << SI <<
"\n");
1167 return markAsDead(SI);
1171 "All simple FCA stores should have been pre-split");
1175 void visitMemSetInst(MemSetInst &
II) {
1176 assert(
II.getRawDest() == *U &&
"Pointer use is not the destination?");
1179 (IsOffsetKnown &&
Offset.uge(AllocSize)))
1181 return markAsDead(
II);
1184 return PI.setAborted(&
II);
1188 : AllocSize -
Offset.getLimitedValue(),
1192 void visitMemTransferInst(MemTransferInst &
II) {
1196 return markAsDead(
II);
1200 if (VisitedDeadInsts.
count(&
II))
1204 return PI.setAborted(&
II);
1211 if (
Offset.uge(AllocSize)) {
1212 auto MTPI = MemTransferSliceMap.
find(&
II);
1213 if (MTPI != MemTransferSliceMap.
end())
1214 AS.Slices[MTPI->second].kill();
1215 return markAsDead(
II);
1218 uint64_t RawOffset =
Offset.getLimitedValue();
1219 uint64_t
Size =
Length ?
Length->getLimitedValue() : AllocSize - RawOffset;
1223 if (*U ==
II.getRawDest() && *U ==
II.getRawSource()) {
1225 if (!
II.isVolatile())
1226 return markAsDead(
II);
1234 SmallDenseMap<Instruction *, unsigned>::iterator MTPI;
1235 std::tie(MTPI, Inserted) =
1236 MemTransferSliceMap.
insert(std::make_pair(&
II, AS.Slices.size()));
1237 unsigned PrevIdx = MTPI->second;
1239 Slice &PrevP = AS.Slices[PrevIdx];
1243 if (!
II.isVolatile() && PrevP.beginOffset() == RawOffset) {
1245 return markAsDead(
II);
1250 PrevP.makeUnsplittable();
1257 assert(AS.Slices[PrevIdx].getUse()->getUser() == &
II &&
1258 "Map index doesn't point back to a slice with this user.");
1264 void visitIntrinsicInst(IntrinsicInst &
II) {
1265 if (
II.isDroppable()) {
1266 AS.DeadUseIfPromotable.push_back(U);
1271 return PI.setAborted(&
II);
1273 if (
II.isLifetimeStartOrEnd()) {
1274 insertUse(
II,
Offset, AllocSize,
true);
1278 Base::visitIntrinsicInst(
II);
1281 Instruction *hasUnsafePHIOrSelectUse(Instruction *Root, uint64_t &
Size) {
1286 SmallPtrSet<Instruction *, 4> Visited;
1296 std::tie(UsedI,
I) =
Uses.pop_back_val();
1299 TypeSize LoadSize =
DL.getTypeStoreSize(LI->
getType());
1311 TypeSize StoreSize =
DL.getTypeStoreSize(
Op->getType());
1321 if (!
GEP->hasAllZeroIndices())
1328 for (User *U :
I->users())
1331 }
while (!
Uses.empty());
1336 void visitPHINodeOrSelectInst(Instruction &
I) {
1339 return markAsDead(
I);
1345 return PI.setAborted(&
I);
1363 AS.DeadOperands.push_back(U);
1369 return PI.setAborted(&
I);
1372 uint64_t &
Size = PHIOrSelectSizes[&
I];
1375 if (Instruction *UnsafeI = hasUnsafePHIOrSelectUse(&
I,
Size))
1376 return PI.setAborted(UnsafeI);
1385 if (
Offset.uge(AllocSize)) {
1386 AS.DeadOperands.push_back(U);
1393 void visitPHINode(PHINode &PN) { visitPHINodeOrSelectInst(PN); }
1395 void visitSelectInst(SelectInst &SI) { visitPHINodeOrSelectInst(SI); }
1398 void visitInstruction(Instruction &
I) { PI.setAborted(&
I); }
1400 void visitCallBase(CallBase &CB) {
1406 PI.setEscapedReadOnly(&CB);
1410 Base::visitCallBase(CB);
1414AllocaSlices::AllocaSlices(
const DataLayout &
DL, AllocaInst &AI)
1416#
if !defined(
NDEBUG) || defined(LLVM_ENABLE_DUMP)
1419 PointerEscapingInstr(nullptr), PointerEscapingInstrReadOnly(nullptr) {
1421 SliceBuilder::PtrInfo PtrI =
PB.visitPtr(AI);
1422 if (PtrI.isEscaped() || PtrI.isAborted()) {
1425 PointerEscapingInstr = PtrI.getEscapingInst() ? PtrI.getEscapingInst()
1426 : PtrI.getAbortingInst();
1427 assert(PointerEscapingInstr &&
"Did not track a bad instruction");
1430 PointerEscapingInstrReadOnly = PtrI.getEscapedReadOnlyInst();
1432 llvm::erase_if(Slices, [](
const Slice &S) {
return S.isDead(); });
1439#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1441void AllocaSlices::print(raw_ostream &OS, const_iterator
I,
1442 StringRef Indent)
const {
1443 printSlice(OS,
I, Indent);
1445 printUse(OS,
I, Indent);
1448void AllocaSlices::printSlice(raw_ostream &OS, const_iterator
I,
1449 StringRef Indent)
const {
1450 OS << Indent <<
"[" <<
I->beginOffset() <<
"," <<
I->endOffset() <<
")"
1451 <<
" slice #" << (
I -
begin())
1452 << (
I->isSplittable() ?
" (splittable)" :
"");
1455void AllocaSlices::printUse(raw_ostream &OS, const_iterator
I,
1456 StringRef Indent)
const {
1457 OS << Indent <<
" used by: " << *
I->getUse()->getUser() <<
"\n";
1460void AllocaSlices::print(raw_ostream &OS)
const {
1461 if (PointerEscapingInstr) {
1462 OS <<
"Can't analyze slices for alloca: " << AI <<
"\n"
1463 <<
" A pointer to this alloca escaped by:\n"
1464 <<
" " << *PointerEscapingInstr <<
"\n";
1468 if (PointerEscapingInstrReadOnly)
1469 OS <<
"Escapes into ReadOnly: " << *PointerEscapingInstrReadOnly <<
"\n";
1471 OS <<
"Slices of alloca: " << AI <<
"\n";
1485static std::pair<Type *, IntegerType *>
1489 bool TyIsCommon =
true;
1494 for (AllocaSlices::const_iterator
I =
B;
I !=
E; ++
I) {
1495 Use *U =
I->getUse();
1498 if (
I->beginOffset() !=
B->beginOffset() ||
I->endOffset() != EndOffset)
1501 Type *UserTy =
nullptr;
1505 UserTy =
SI->getValueOperand()->getType();
1513 if (UserITy->getBitWidth() % 8 != 0 ||
1514 UserITy->getBitWidth() / 8 > (EndOffset -
B->beginOffset()))
1519 if (!ITy || ITy->
getBitWidth() < UserITy->getBitWidth())
1525 if (!UserTy || (Ty && Ty != UserTy))
1531 return {TyIsCommon ? Ty :
nullptr, ITy};
1562 Type *LoadType =
nullptr;
1575 if (LoadType != LI->
getType())
1584 if (BBI->mayWriteToMemory())
1587 MaxAlign = std::max(MaxAlign, LI->
getAlign());
1594 APInt(APWidth,
DL.getTypeStoreSize(LoadType).getFixedValue());
1631 IRB.SetInsertPoint(&PN);
1633 PN.
getName() +
".sroa.speculated");
1663 IRB.SetInsertPoint(TI);
1665 LoadInst *Load = IRB.CreateAlignedLoad(
1666 LoadTy, InVal, Alignment,
1667 (PN.
getName() +
".sroa.speculate.load." + Pred->getName()));
1668 ++NumLoadsSpeculated;
1670 Load->setAAMetadata(AATags);
1672 InjectedLoads[Pred] = Load;
1679SelectHandSpeculativity &
1680SelectHandSpeculativity::setAsSpeculatable(
bool isTrueVal) {
1688bool SelectHandSpeculativity::isSpeculatable(
bool isTrueVal)
const {
1693bool SelectHandSpeculativity::areAllSpeculatable()
const {
1694 return isSpeculatable(
true) &&
1695 isSpeculatable(
false);
1698bool SelectHandSpeculativity::areAnySpeculatable()
const {
1699 return isSpeculatable(
true) ||
1700 isSpeculatable(
false);
1702bool SelectHandSpeculativity::areNoneSpeculatable()
const {
1703 return !areAnySpeculatable();
1706static SelectHandSpeculativity
1709 SelectHandSpeculativity
Spec;
1715 Spec.setAsSpeculatable(
Value ==
SI.getTrueValue());
1716 else if (PreserveCFG)
1722std::optional<RewriteableMemOps>
1723SROA::isSafeSelectToSpeculate(SelectInst &SI,
bool PreserveCFG) {
1724 RewriteableMemOps
Ops;
1726 for (User *U :
SI.users()) {
1734 if (
Store->isVolatile() || PreserveCFG)
1736 Ops.emplace_back(Store);
1747 PossiblySpeculatableLoad
Load(LI);
1753 Ops.emplace_back(Load);
1757 SelectHandSpeculativity Spec =
1759 if (PreserveCFG && !Spec.areAllSpeculatable())
1763 Ops.emplace_back(Load);
1773 Value *TV =
SI.getTrueValue();
1774 Value *FV =
SI.getFalseValue();
1779 IRB.SetInsertPoint(&LI);
1783 LI.
getName() +
".sroa.speculate.load.true");
1786 LI.
getName() +
".sroa.speculate.load.false");
1787 NumLoadsSpeculated += 2;
1799 Value *V = IRB.CreateSelect(
SI.getCondition(), TL, FL,
1800 LI.
getName() +
".sroa.speculated",
1807template <
typename T>
1809 SelectHandSpeculativity
Spec,
1816 if (
Spec.areNoneSpeculatable())
1818 SI.getMetadata(LLVMContext::MD_prof), &DTU);
1821 SI.getMetadata(LLVMContext::MD_prof), &DTU,
1823 if (
Spec.isSpeculatable(
true))
1834 bool IsThen = SuccBB == HeadBI->getSuccessor(0);
1835 int SuccIdx = IsThen ? 0 : 1;
1836 auto *NewMemOpBB = SuccBB ==
Tail ? Head : SuccBB;
1837 auto &CondMemOp =
cast<T>(*
I.clone());
1838 if (NewMemOpBB != Head) {
1839 NewMemOpBB->setName(Head->
getName() + (IsThen ?
".then" :
".else"));
1841 ++NumLoadsPredicated;
1843 ++NumStoresPredicated;
1845 CondMemOp.dropUBImplyingAttrsAndMetadata();
1846 ++NumLoadsSpeculated;
1848 CondMemOp.insertBefore(NewMemOpBB->getTerminator()->getIterator());
1849 Value *Ptr =
SI.getOperand(1 + SuccIdx);
1850 CondMemOp.setOperand(
I.getPointerOperandIndex(), Ptr);
1852 CondMemOp.setName(
I.getName() + (IsThen ?
".then" :
".else") +
".val");
1860 I.replaceAllUsesWith(PN);
1865 SelectHandSpeculativity
Spec,
1876 const RewriteableMemOps &
Ops,
1878 bool CFGChanged =
false;
1881 for (
const RewriteableMemOp &
Op :
Ops) {
1882 SelectHandSpeculativity
Spec;
1884 if (
auto *
const *US = std::get_if<UnspeculatableStore>(&
Op)) {
1887 auto PSL = std::get<PossiblySpeculatableLoad>(
Op);
1888 I = PSL.getPointer();
1889 Spec = PSL.getInt();
1891 if (
Spec.areAllSpeculatable()) {
1894 assert(DTU &&
"Should not get here when not allowed to modify the CFG!");
1898 I->eraseFromParent();
1903 SI.eraseFromParent();
1911 const Twine &NamePrefix) {
1913 Ptr = IRB.CreateInBoundsPtrAdd(Ptr, IRB.getInt(
Offset),
1914 NamePrefix +
"sroa_idx");
1915 return IRB.CreatePointerBitCastOrAddrSpaceCast(Ptr,
PointerTy,
1916 NamePrefix +
"sroa_cast");
1931 unsigned VScale = 0) {
1941 "We can't have the same bitwidth for different int types");
1945 TypeSize NewSize =
DL.getTypeSizeInBits(NewTy);
1946 TypeSize OldSize =
DL.getTypeSizeInBits(OldTy);
1973 if (NewSize != OldSize)
1989 return OldAS == NewAS ||
1990 (!
DL.isNonIntegralAddressSpace(OldAS) &&
1991 !
DL.isNonIntegralAddressSpace(NewAS) &&
1992 DL.getPointerSize(OldAS) ==
DL.getPointerSize(NewAS));
1998 return !
DL.isNonIntegralPointerType(NewTy);
2002 if (!
DL.isNonIntegralPointerType(OldTy))
2025 std::max(S.beginOffset(),
P.beginOffset()) -
P.beginOffset();
2026 uint64_t BeginIndex = BeginOffset / ElementSize;
2027 if (BeginIndex * ElementSize != BeginOffset ||
2030 uint64_t EndOffset = std::min(S.endOffset(),
P.endOffset()) -
P.beginOffset();
2031 uint64_t EndIndex = EndOffset / ElementSize;
2032 if (EndIndex * ElementSize != EndOffset ||
2036 assert(EndIndex > BeginIndex &&
"Empty vector!");
2037 uint64_t NumElements = EndIndex - BeginIndex;
2038 Type *SliceTy = (NumElements == 1)
2039 ? Ty->getElementType()
2045 Use *U = S.getUse();
2048 if (
MI->isVolatile())
2050 if (!S.isSplittable())
2053 if (!
II->isLifetimeStartOrEnd() && !
II->isDroppable())
2060 if (LTy->isStructTy())
2062 if (
P.beginOffset() > S.beginOffset() ||
P.endOffset() < S.endOffset()) {
2063 assert(LTy->isIntegerTy());
2069 if (
SI->isVolatile())
2071 Type *STy =
SI->getValueOperand()->getType();
2075 if (
P.beginOffset() > S.beginOffset() ||
P.endOffset() < S.endOffset()) {
2095 bool HaveCommonEltTy,
Type *CommonEltTy,
2096 bool HaveVecPtrTy,
bool HaveCommonVecPtrTy,
2097 VectorType *CommonVecPtrTy,
unsigned VScale) {
2099 if (CandidateTys.
empty())
2106 if (HaveVecPtrTy && !HaveCommonVecPtrTy)
2110 if (!HaveCommonEltTy && HaveVecPtrTy) {
2112 CandidateTys.
clear();
2114 }
else if (!HaveCommonEltTy && !HaveVecPtrTy) {
2117 if (!VTy->getElementType()->isIntegerTy())
2119 VTy->getContext(), VTy->getScalarSizeInBits())));
2126 assert(
DL.getTypeSizeInBits(RHSTy).getFixedValue() ==
2127 DL.getTypeSizeInBits(LHSTy).getFixedValue() &&
2128 "Cannot have vector types of different sizes!");
2129 assert(RHSTy->getElementType()->isIntegerTy() &&
2130 "All non-integer types eliminated!");
2131 assert(LHSTy->getElementType()->isIntegerTy() &&
2132 "All non-integer types eliminated!");
2138 assert(
DL.getTypeSizeInBits(RHSTy).getFixedValue() ==
2139 DL.getTypeSizeInBits(LHSTy).getFixedValue() &&
2140 "Cannot have vector types of different sizes!");
2141 assert(RHSTy->getElementType()->isIntegerTy() &&
2142 "All non-integer types eliminated!");
2143 assert(LHSTy->getElementType()->isIntegerTy() &&
2144 "All non-integer types eliminated!");
2148 llvm::sort(CandidateTys, RankVectorTypesComp);
2149 CandidateTys.erase(
llvm::unique(CandidateTys, RankVectorTypesEq),
2150 CandidateTys.end());
2156 assert(VTy->getElementType() == CommonEltTy &&
2157 "Unaccounted for element type!");
2158 assert(VTy == CandidateTys[0] &&
2159 "Different vector types with the same element type!");
2162 CandidateTys.resize(1);
2169 std::numeric_limits<unsigned short>::max();
2175 DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
2179 if (ElementSize % 8)
2181 assert((
DL.getTypeSizeInBits(VTy).getFixedValue() % 8) == 0 &&
2182 "vector size not a multiple of element size?");
2185 for (
const Slice &S :
P)
2189 for (
const Slice *S :
P.splitSliceTails())
2195 return VTy != CandidateTys.
end() ? *VTy :
nullptr;
2202 bool &HaveCommonEltTy,
Type *&CommonEltTy,
bool &HaveVecPtrTy,
2203 bool &HaveCommonVecPtrTy,
VectorType *&CommonVecPtrTy,
unsigned VScale) {
2205 CandidateTysCopy.
size() ? CandidateTysCopy[0] :
nullptr;
2208 for (
Type *Ty : OtherTys) {
2211 unsigned TypeSize =
DL.getTypeSizeInBits(Ty).getFixedValue();
2214 for (
VectorType *
const VTy : CandidateTysCopy) {
2216 assert(CandidateTysCopy[0] == OriginalElt &&
"Different Element");
2217 unsigned VectorSize =
DL.getTypeSizeInBits(VTy).getFixedValue();
2218 unsigned ElementSize =
2219 DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
2223 CheckCandidateType(NewVTy);
2229 P,
DL, CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
2230 HaveCommonVecPtrTy, CommonVecPtrTy, VScale);
2249 Type *CommonEltTy =
nullptr;
2251 bool HaveVecPtrTy =
false;
2252 bool HaveCommonEltTy =
true;
2253 bool HaveCommonVecPtrTy =
true;
2254 auto CheckCandidateType = [&](
Type *Ty) {
2257 if (!CandidateTys.
empty()) {
2259 if (
DL.getTypeSizeInBits(VTy).getFixedValue() !=
2260 DL.getTypeSizeInBits(V).getFixedValue()) {
2261 CandidateTys.
clear();
2266 Type *EltTy = VTy->getElementType();
2269 CommonEltTy = EltTy;
2270 else if (CommonEltTy != EltTy)
2271 HaveCommonEltTy =
false;
2274 HaveVecPtrTy =
true;
2275 if (!CommonVecPtrTy)
2276 CommonVecPtrTy = VTy;
2277 else if (CommonVecPtrTy != VTy)
2278 HaveCommonVecPtrTy =
false;
2284 for (
const Slice &S :
P) {
2289 Ty =
SI->getValueOperand()->getType();
2293 auto CandTy = Ty->getScalarType();
2294 if (CandTy->isPointerTy() && (S.beginOffset() !=
P.beginOffset() ||
2295 S.endOffset() !=
P.endOffset())) {
2302 if (S.beginOffset() ==
P.beginOffset() && S.endOffset() ==
P.endOffset())
2303 CheckCandidateType(Ty);
2308 LoadStoreTys, CandidateTysCopy, CheckCandidateType,
P,
DL,
2309 CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
2310 HaveCommonVecPtrTy, CommonVecPtrTy, VScale))
2313 CandidateTys.
clear();
2315 DeferredTys, CandidateTysCopy, CheckCandidateType,
P,
DL, CandidateTys,
2316 HaveCommonEltTy, CommonEltTy, HaveVecPtrTy, HaveCommonVecPtrTy,
2317 CommonVecPtrTy, VScale);
2328 bool &WholeAllocaOp) {
2331 uint64_t RelBegin = S.beginOffset() - AllocBeginOffset;
2332 uint64_t RelEnd = S.endOffset() - AllocBeginOffset;
2334 Use *U = S.getUse();
2341 if (
II->isLifetimeStartOrEnd() ||
II->isDroppable())
2359 if (S.beginOffset() < AllocBeginOffset)
2365 WholeAllocaOp =
true;
2367 if (ITy->getBitWidth() <
DL.getTypeStoreSizeInBits(ITy).getFixedValue())
2369 }
else if (RelBegin != 0 || RelEnd !=
Size ||
2376 Type *ValueTy =
SI->getValueOperand()->getType();
2377 if (
SI->isVolatile())
2380 TypeSize StoreSize =
DL.getTypeStoreSize(ValueTy);
2385 if (S.beginOffset() < AllocBeginOffset)
2391 WholeAllocaOp =
true;
2393 if (ITy->getBitWidth() <
DL.getTypeStoreSizeInBits(ITy).getFixedValue())
2395 }
else if (RelBegin != 0 || RelEnd !=
Size ||
2404 if (!S.isSplittable())
2421 uint64_t SizeInBits =
DL.getTypeSizeInBits(AllocaTy).getFixedValue();
2427 if (SizeInBits !=
DL.getTypeStoreSizeInBits(AllocaTy).getFixedValue())
2445 bool WholeAllocaOp =
P.empty() &&
DL.isLegalInteger(SizeInBits);
2447 for (
const Slice &S :
P)
2452 for (
const Slice *S :
P.splitSliceTails())
2457 return WholeAllocaOp;
2462 const Twine &Name) {
2466 DL.getTypeStoreSize(IntTy).getFixedValue() &&
2467 "Element extends past full value");
2469 if (
DL.isBigEndian())
2470 ShAmt = 8 * (
DL.getTypeStoreSize(IntTy).getFixedValue() -
2471 DL.getTypeStoreSize(Ty).getFixedValue() -
Offset);
2473 V = IRB.CreateLShr(V, ShAmt, Name +
".shift");
2476 assert(Ty->getBitWidth() <= IntTy->getBitWidth() &&
2477 "Cannot extract to a larger integer!");
2479 V = IRB.CreateTrunc(V, Ty, Name +
".trunc");
2489 assert(Ty->getBitWidth() <= IntTy->getBitWidth() &&
2490 "Cannot insert a larger integer!");
2493 V = IRB.CreateZExt(V, IntTy, Name +
".ext");
2497 DL.getTypeStoreSize(IntTy).getFixedValue() &&
2498 "Element store outside of alloca store");
2500 if (
DL.isBigEndian())
2501 ShAmt = 8 * (
DL.getTypeStoreSize(IntTy).getFixedValue() -
2502 DL.getTypeStoreSize(Ty).getFixedValue() -
Offset);
2504 V = IRB.CreateShl(V, ShAmt, Name +
".shift");
2508 if (ShAmt || Ty->getBitWidth() < IntTy->getBitWidth()) {
2509 APInt Mask = ~Ty->getMask().zext(IntTy->getBitWidth()).shl(ShAmt);
2510 Old = IRB.CreateAnd(Old, Mask, Name +
".mask");
2512 V = IRB.CreateOr(Old, V, Name +
".insert");
2519 unsigned EndIndex,
const Twine &Name) {
2521 unsigned NumElements = EndIndex - BeginIndex;
2524 if (NumElements == VecTy->getNumElements())
2527 if (NumElements == 1) {
2528 V = IRB.CreateExtractElement(V, IRB.getInt32(BeginIndex),
2535 V = IRB.CreateShuffleVector(V, Mask, Name +
".extract");
2541 unsigned BeginIndex,
const Twine &Name) {
2543 assert(VecTy &&
"Can only insert a vector into a vector");
2548 V = IRB.CreateInsertElement(Old, V, IRB.getInt32(BeginIndex),
2557 assert(NumSubElements <= NumElements &&
"Too many elements!");
2558 if (NumSubElements == NumElements) {
2559 assert(V->getType() == VecTy &&
"Vector type mismatch");
2562 unsigned EndIndex = BeginIndex + NumSubElements;
2569 Mask.reserve(NumElements);
2570 for (
unsigned Idx = 0; Idx != NumElements; ++Idx)
2571 if (Idx >= BeginIndex && Idx < EndIndex)
2572 Mask.push_back(Idx - BeginIndex);
2575 V = IRB.CreateShuffleVector(V, Mask, Name +
".expand");
2579 for (
unsigned Idx = 0; Idx != NumElements; ++Idx)
2580 if (Idx >= BeginIndex && Idx < EndIndex)
2581 Mask.push_back(Idx);
2583 Mask.push_back(Idx + NumElements);
2584 V = IRB.CreateShuffleVector(V, Old, Mask, Name +
"blend");
2623 const char *DebugName) {
2624 Type *EltType = VecType->getElementType();
2625 if (EltType != NewAIEltTy) {
2627 unsigned TotalBits =
2628 VecType->getNumElements() *
DL.getTypeSizeInBits(EltType);
2629 unsigned NewNumElts = TotalBits /
DL.getTypeSizeInBits(NewAIEltTy);
2632 V = Builder.CreateBitCast(V, NewVecType);
2633 VecType = NewVecType;
2634 LLVM_DEBUG(
dbgs() <<
" bitcast " << DebugName <<
": " << *V <<
"\n");
2638 BitcastIfNeeded(V0, VecType0,
"V0");
2639 BitcastIfNeeded(V1, VecType1,
"V1");
2641 unsigned NumElts0 = VecType0->getNumElements();
2642 unsigned NumElts1 = VecType1->getNumElements();
2646 if (NumElts0 == NumElts1) {
2647 for (
unsigned i = 0; i < NumElts0 + NumElts1; ++i)
2648 ShuffleMask.push_back(i);
2652 unsigned SmallSize = std::min(NumElts0, NumElts1);
2653 unsigned LargeSize = std::max(NumElts0, NumElts1);
2654 bool IsV0Smaller = NumElts0 < NumElts1;
2655 Value *&ExtendedVec = IsV0Smaller ? V0 : V1;
2657 for (
unsigned i = 0; i < SmallSize; ++i)
2659 for (
unsigned i = SmallSize; i < LargeSize; ++i)
2661 ExtendedVec = Builder.CreateShuffleVector(
2663 LLVM_DEBUG(
dbgs() <<
" shufflevector: " << *ExtendedVec <<
"\n");
2664 for (
unsigned i = 0; i < NumElts0; ++i)
2665 ShuffleMask.push_back(i);
2666 for (
unsigned i = 0; i < NumElts1; ++i)
2667 ShuffleMask.push_back(LargeSize + i);
2670 return Builder.CreateShuffleVector(V0, V1, ShuffleMask);
2681class AllocaSliceRewriter :
public InstVisitor<AllocaSliceRewriter, bool> {
2683 friend class InstVisitor<AllocaSliceRewriter, bool>;
2685 using Base = InstVisitor<AllocaSliceRewriter, bool>;
2687 const DataLayout &
DL;
2690 AllocaInst &OldAI, &NewAI;
2691 const uint64_t NewAllocaBeginOffset, NewAllocaEndOffset;
2711 uint64_t ElementSize;
2715 uint64_t BeginOffset = 0;
2716 uint64_t EndOffset = 0;
2720 uint64_t NewBeginOffset = 0, NewEndOffset = 0;
2722 uint64_t SliceSize = 0;
2723 bool IsSplittable =
false;
2724 bool IsSplit =
false;
2725 Use *OldUse =
nullptr;
2729 SmallSetVector<PHINode *, 8> &PHIUsers;
2730 SmallSetVector<SelectInst *, 8> &SelectUsers;
2738 Value *getPtrToNewAI(
unsigned AddrSpace,
bool IsVolatile) {
2742 Type *AccessTy = IRB.getPtrTy(AddrSpace);
2743 return IRB.CreateAddrSpaceCast(&NewAI, AccessTy);
2747 AllocaSliceRewriter(
const DataLayout &
DL, AllocaSlices &AS, SROA &
Pass,
2748 AllocaInst &OldAI, AllocaInst &NewAI,
Type *NewAllocaTy,
2749 uint64_t NewAllocaBeginOffset,
2750 uint64_t NewAllocaEndOffset,
bool IsIntegerPromotable,
2751 VectorType *PromotableVecTy,
2752 SmallSetVector<PHINode *, 8> &PHIUsers,
2753 SmallSetVector<SelectInst *, 8> &SelectUsers)
2754 :
DL(
DL), AS(AS),
Pass(
Pass), OldAI(OldAI), NewAI(NewAI),
2755 NewAllocaBeginOffset(NewAllocaBeginOffset),
2756 NewAllocaEndOffset(NewAllocaEndOffset), NewAllocaTy(NewAllocaTy),
2757 IntTy(IsIntegerPromotable
2760 DL.getTypeSizeInBits(NewAllocaTy).getFixedValue())
2762 VecTy(PromotableVecTy),
2763 ElementTy(VecTy ? VecTy->getElementType() : nullptr),
2764 ElementSize(VecTy ?
DL.getTypeSizeInBits(ElementTy).getFixedValue() / 8
2766 PHIUsers(PHIUsers), SelectUsers(SelectUsers),
2769 assert((
DL.getTypeSizeInBits(ElementTy).getFixedValue() % 8) == 0 &&
2770 "Only multiple-of-8 sized vector elements are viable");
2773 assert((!IntTy && !VecTy) || (IntTy && !VecTy) || (!IntTy && VecTy));
2776 bool visit(AllocaSlices::const_iterator
I) {
2777 bool CanSROA =
true;
2778 BeginOffset =
I->beginOffset();
2779 EndOffset =
I->endOffset();
2780 IsSplittable =
I->isSplittable();
2782 BeginOffset < NewAllocaBeginOffset || EndOffset > NewAllocaEndOffset;
2783 LLVM_DEBUG(
dbgs() <<
" rewriting " << (IsSplit ?
"split " :
""));
2788 assert(BeginOffset < NewAllocaEndOffset);
2789 assert(EndOffset > NewAllocaBeginOffset);
2790 NewBeginOffset = std::max(BeginOffset, NewAllocaBeginOffset);
2791 NewEndOffset = std::min(EndOffset, NewAllocaEndOffset);
2793 SliceSize = NewEndOffset - NewBeginOffset;
2794 LLVM_DEBUG(
dbgs() <<
" Begin:(" << BeginOffset <<
", " << EndOffset
2795 <<
") NewBegin:(" << NewBeginOffset <<
", "
2796 << NewEndOffset <<
") NewAllocaBegin:("
2797 << NewAllocaBeginOffset <<
", " << NewAllocaEndOffset
2799 assert(IsSplit || NewBeginOffset == BeginOffset);
2800 OldUse =
I->getUse();
2804 IRB.SetInsertPoint(OldUserI);
2805 IRB.SetCurrentDebugLocation(OldUserI->
getDebugLoc());
2807 if (!IRB.getContext().shouldDiscardValueNames())
2808 IRB.getInserter().SetNamePrefix(Twine(NewAI.
getName()) +
"." +
2809 Twine(BeginOffset) +
".");
2855 std::optional<SmallVector<Value *, 4>>
2856 rewriteTreeStructuredMerge(Partition &
P) {
2858 if (
P.splitSliceTails().size() > 0)
2859 return std::nullopt;
2861 SmallVector<Value *, 4> DeletedValues;
2862 LoadInst *TheLoad =
nullptr;
2867 uint64_t BeginOffset;
2870 StoreInfo(StoreInst *SI, uint64_t Begin, uint64_t End,
Value *Val)
2871 :
Store(
SI), BeginOffset(Begin), EndOffset(End), StoredValue(Val) {}
2878 Type *AllocatedEltTy =
2882 unsigned AllocatedEltTySize =
DL.getTypeSizeInBits(AllocatedEltTy);
2889 auto IsTypeValidForTreeStructuredMerge = [&](
Type *Ty) ->
bool {
2891 return FixedVecTy &&
2892 DL.getTypeSizeInBits(FixedVecTy->getElementType()) % 8 == 0 &&
2893 !FixedVecTy->getElementType()->isPointerTy();
2896 for (Slice &S :
P) {
2904 if (TheLoad || !IsTypeValidForTreeStructuredMerge(LI->
getType()) ||
2905 S.beginOffset() != NewAllocaBeginOffset ||
2906 S.endOffset() != NewAllocaEndOffset || LI->
isVolatile())
2907 return std::nullopt;
2915 if (!IsTypeValidForTreeStructuredMerge(
2916 SI->getValueOperand()->getType()) ||
2918 return std::nullopt;
2920 unsigned NumElts = VecTy->getNumElements();
2921 unsigned EltSize =
DL.getTypeSizeInBits(VecTy->getElementType());
2922 if (NumElts * EltSize % AllocatedEltTySize != 0)
2923 return std::nullopt;
2924 StoreInfos.
emplace_back(SI, S.beginOffset(), S.endOffset(),
2925 SI->getValueOperand());
2929 return std::nullopt;
2934 return std::nullopt;
2937 if (StoreInfos.
size() < 2)
2938 return std::nullopt;
2942 llvm::sort(StoreInfos, [](
const StoreInfo &
A,
const StoreInfo &
B) {
2943 return A.BeginOffset <
B.BeginOffset;
2947 uint64_t ExpectedStart = NewAllocaBeginOffset;
2948 for (
auto &StoreInfo : StoreInfos) {
2949 uint64_t BeginOff = StoreInfo.BeginOffset;
2950 uint64_t EndOff = StoreInfo.EndOffset;
2953 if (BeginOff != ExpectedStart)
2954 return std::nullopt;
2956 ExpectedStart = EndOff;
2959 if (ExpectedStart != NewAllocaEndOffset)
2960 return std::nullopt;
2971 BasicBlock *StoreBB = StoreInfos[0].Store->getParent();
2973 for (
auto &StoreInfo : StoreInfos) {
2974 if (StoreInfo.Store->getParent() != StoreBB)
2975 return std::nullopt;
2976 if (LoadBB == StoreBB && !StoreInfo.Store->comesBefore(TheLoad))
2977 return std::nullopt;
2983 dbgs() <<
"Tree structured merge rewrite:\n Load: " << *TheLoad
2984 <<
"\n Ordered stores:\n";
2985 for (
auto [i, Info] :
enumerate(StoreInfos))
2986 dbgs() <<
" [" << i <<
"] Range[" <<
Info.BeginOffset <<
", "
2987 <<
Info.EndOffset <<
") \tStore: " << *
Info.Store
2988 <<
"\tValue: " << *
Info.StoredValue <<
"\n";
2993 std::queue<Value *> VecElements;
3002 for (
const auto &Info : StoreInfos) {
3004 VecElements.push(
Info.StoredValue);
3008 while (VecElements.size() > 1) {
3009 const auto NumElts = VecElements.size();
3010 for ([[maybe_unused]]
const auto _ :
llvm::seq(NumElts / 2)) {
3011 Value *V0 = VecElements.front();
3013 Value *V1 = VecElements.front();
3017 VecElements.push(Merged);
3019 if (NumElts % 2 == 1) {
3020 Value *
V = VecElements.front();
3022 VecElements.push(V);
3027 Value *MergedValue = VecElements.front();
3028 Builder.CreateAlignedStore(MergedValue, &NewAI, getSliceAlign());
3033 TheLoad->
getName() +
".sroa.new.load"));
3036 return DeletedValues;
3044 bool visitInstruction(Instruction &
I) {
3052 assert(IsSplit || BeginOffset == NewBeginOffset);
3053 uint64_t
Offset = NewBeginOffset - NewAllocaBeginOffset;
3055 StringRef OldName = OldPtr->
getName();
3057 size_t LastSROAPrefix = OldName.
rfind(
".sroa.");
3059 OldName = OldName.
substr(LastSROAPrefix + strlen(
".sroa."));
3064 OldName = OldName.
substr(IndexEnd + 1);
3068 OldName = OldName.
substr(OffsetEnd + 1);
3072 OldName = OldName.
substr(0, OldName.
find(
".sroa_"));
3084 Align getSliceAlign() {
3086 NewBeginOffset - NewAllocaBeginOffset);
3089 unsigned getIndex(uint64_t
Offset) {
3090 assert(VecTy &&
"Can only call getIndex when rewriting a vector");
3091 uint64_t RelOffset =
Offset - NewAllocaBeginOffset;
3092 assert(RelOffset / ElementSize < UINT32_MAX &&
"Index out of bounds");
3093 uint32_t
Index = RelOffset / ElementSize;
3094 assert(Index * ElementSize == RelOffset);
3098 void deleteIfTriviallyDead(
Value *V) {
3101 Pass.DeadInsts.push_back(
I);
3104 Value *rewriteVectorizedLoadInst(LoadInst &LI) {
3105 unsigned BeginIndex = getIndex(NewBeginOffset);
3106 unsigned EndIndex = getIndex(NewEndOffset);
3107 assert(EndIndex > BeginIndex &&
"Empty vector!");
3110 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3112 Load->copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
3113 LLVMContext::MD_access_group});
3114 return extractVector(IRB, Load, BeginIndex, EndIndex,
"vec");
3117 Value *rewriteIntegerLoad(LoadInst &LI) {
3118 assert(IntTy &&
"We cannot insert an integer to the alloca");
3121 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3122 V = IRB.CreateBitPreservingCastChain(
DL, V, IntTy);
3123 assert(NewBeginOffset >= NewAllocaBeginOffset &&
"Out of bounds offset");
3124 uint64_t
Offset = NewBeginOffset - NewAllocaBeginOffset;
3125 if (
Offset > 0 || NewEndOffset < NewAllocaEndOffset) {
3126 IntegerType *ExtractTy = Type::getIntNTy(LI.
getContext(), SliceSize * 8);
3135 "Can only handle an extract for an overly wide load");
3137 V = IRB.CreateZExt(V, LI.
getType());
3141 bool visitLoadInst(LoadInst &LI) {
3150 Type *TargetTy = IsSplit ? Type::getIntNTy(LI.
getContext(), SliceSize * 8)
3152 bool IsPtrAdjusted =
false;
3155 V = rewriteVectorizedLoadInst(LI);
3157 V = rewriteIntegerLoad(LI);
3158 }
else if (NewBeginOffset == NewAllocaBeginOffset &&
3159 NewEndOffset == NewAllocaEndOffset &&
3162 DL.getTypeStoreSize(TargetTy).getFixedValue() > SliceSize &&
3165 getPtrToNewAI(LI.getPointerAddressSpace(), LI.isVolatile());
3166 LoadInst *NewLI = IRB.CreateAlignedLoad(
3167 NewAllocaTy, NewPtr, NewAI.getAlign(), LI.isVolatile(), LI.getName());
3168 if (LI.isVolatile())
3169 NewLI->setAtomic(LI.getOrdering(), LI.getSyncScopeID());
3170 if (NewLI->isAtomic())
3171 NewLI->setAlignment(LI.getAlign());
3176 copyMetadataForLoad(*NewLI, LI);
3180 NewLI->setAAMetadata(AATags.adjustForAccess(
3181 NewBeginOffset - BeginOffset, NewLI->getType(), DL));
3189 if (auto *AITy = dyn_cast<IntegerType>(NewAllocaTy))
3190 if (auto *TITy = dyn_cast<IntegerType>(TargetTy))
3191 if (AITy->getBitWidth() < TITy->getBitWidth()) {
3192 V = IRB.CreateZExt(V, TITy,
"load.ext");
3193 if (DL.isBigEndian())
3194 V = IRB.CreateShl(V, TITy->getBitWidth() - AITy->getBitWidth(),
3198 Type *LTy = IRB.getPtrTy(AS);
3200 IRB.CreateAlignedLoad(TargetTy, getNewAllocaSlicePtr(IRB, LTy),
3205 NewBeginOffset - BeginOffset, NewLI->
getType(),
DL));
3209 NewLI->
copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
3210 LLVMContext::MD_access_group});
3213 IsPtrAdjusted =
true;
3215 V = IRB.CreateBitPreservingCastChain(
DL, V, TargetTy);
3220 "Only integer type loads and stores are split");
3221 assert(SliceSize <
DL.getTypeStoreSize(LI.
getType()).getFixedValue() &&
3222 "Split load isn't smaller than original load");
3224 "Non-byte-multiple bit width");
3230 LIIt.setHeadBit(
true);
3231 IRB.SetInsertPoint(LI.
getParent(), LIIt);
3236 Value *Placeholder =
3242 Placeholder->replaceAllUsesWith(&LI);
3243 Placeholder->deleteValue();
3248 Pass.DeadInsts.push_back(&LI);
3249 deleteIfTriviallyDead(OldOp);
3254 bool rewriteVectorizedStoreInst(
Value *V, StoreInst &SI,
Value *OldOp,
3259 if (
V->getType() != VecTy) {
3260 unsigned BeginIndex = getIndex(NewBeginOffset);
3261 unsigned EndIndex = getIndex(NewEndOffset);
3262 assert(EndIndex > BeginIndex &&
"Empty vector!");
3263 unsigned NumElements = EndIndex - BeginIndex;
3265 "Too many elements!");
3266 Type *SliceTy = (NumElements == 1)
3268 : FixedVectorType::
get(ElementTy, NumElements);
3269 if (
V->getType() != SliceTy)
3270 V = IRB.CreateBitPreservingCastChain(
DL, V, SliceTy);
3274 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3277 StoreInst *
Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.
getAlign());
3278 Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3279 LLVMContext::MD_access_group});
3283 Pass.DeadInsts.push_back(&SI);
3287 Store,
Store->getPointerOperand(), OrigV,
DL);
3292 bool rewriteIntegerStore(
Value *V, StoreInst &SI, AAMDNodes AATags) {
3293 assert(IntTy &&
"We cannot extract an integer from the alloca");
3295 if (
DL.getTypeSizeInBits(
V->getType()).getFixedValue() !=
3297 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3299 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3300 assert(BeginOffset >= NewAllocaBeginOffset &&
"Out of bounds offset");
3301 uint64_t
Offset = BeginOffset - NewAllocaBeginOffset;
3304 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3305 StoreInst *
Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.
getAlign());
3306 Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3307 LLVMContext::MD_access_group});
3313 Store,
Store->getPointerOperand(),
3314 Store->getValueOperand(),
DL);
3316 Pass.DeadInsts.push_back(&SI);
3321 bool visitStoreInst(StoreInst &SI) {
3323 Value *OldOp =
SI.getOperand(1);
3326 AAMDNodes AATags =
SI.getAAMetadata();
3331 if (
V->getType()->isPointerTy())
3333 Pass.PostPromotionWorklist.insert(AI);
3335 TypeSize StoreSize =
DL.getTypeStoreSize(
V->getType());
3338 assert(
V->getType()->isIntegerTy() &&
3339 "Only integer type loads and stores are split");
3340 assert(
DL.typeSizeEqualsStoreSize(
V->getType()) &&
3341 "Non-byte-multiple bit width");
3342 IntegerType *NarrowTy = Type::getIntNTy(
SI.getContext(), SliceSize * 8);
3348 return rewriteVectorizedStoreInst(V, SI, OldOp, AATags);
3349 if (IntTy &&
V->getType()->isIntegerTy())
3350 return rewriteIntegerStore(V, SI, AATags);
3353 if (NewBeginOffset == NewAllocaBeginOffset &&
3354 NewEndOffset == NewAllocaEndOffset &&
3356 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3358 getPtrToNewAI(
SI.getPointerAddressSpace(),
SI.isVolatile());
3361 IRB.CreateAlignedStore(V, NewPtr, NewAI.
getAlign(),
SI.isVolatile());
3363 unsigned AS =
SI.getPointerAddressSpace();
3364 Value *NewPtr = getNewAllocaSlicePtr(IRB, IRB.getPtrTy(AS));
3366 IRB.CreateAlignedStore(V, NewPtr, getSliceAlign(),
SI.isVolatile());
3368 NewSI->
copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
3369 LLVMContext::MD_access_group});
3373 if (
SI.isVolatile())
3382 Pass.DeadInsts.push_back(&SI);
3383 deleteIfTriviallyDead(OldOp);
3401 assert(
Size > 0 &&
"Expected a positive number of bytes.");
3409 IRB.CreateZExt(V, SplatIntTy,
"zext"),
3419 V = IRB.CreateVectorSplat(NumElements, V,
"vsplat");
3424 bool visitMemSetInst(MemSetInst &
II) {
3428 AAMDNodes AATags =
II.getAAMetadata();
3434 assert(NewBeginOffset == BeginOffset);
3435 II.setDest(getNewAllocaSlicePtr(IRB, OldPtr->
getType()));
3436 II.setDestAlignment(getSliceAlign());
3441 "AT: Unexpected link to non-const GEP");
3442 deleteIfTriviallyDead(OldPtr);
3447 Pass.DeadInsts.push_back(&
II);
3451 const bool CanContinue = [&]() {
3454 if (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset)
3458 const uint64_t
Len =
C->getLimitedValue();
3459 if (Len > std::numeric_limits<unsigned>::max())
3461 auto *Int8Ty = IntegerType::getInt8Ty(NewAI.
getContext());
3464 DL.isLegalInteger(
DL.getTypeSizeInBits(ScalarTy).getFixedValue());
3470 Type *SizeTy =
II.getLength()->getType();
3471 unsigned Sz = NewEndOffset - NewBeginOffset;
3474 getNewAllocaSlicePtr(IRB, OldPtr->
getType()),
II.getValue(),
Size,
3475 MaybeAlign(getSliceAlign()),
II.isVolatile()));
3481 New,
New->getRawDest(),
nullptr,
DL);
3496 assert(ElementTy == ScalarTy);
3498 unsigned BeginIndex = getIndex(NewBeginOffset);
3499 unsigned EndIndex = getIndex(NewEndOffset);
3500 assert(EndIndex > BeginIndex &&
"Empty vector!");
3501 unsigned NumElements = EndIndex - BeginIndex;
3503 "Too many elements!");
3506 II.getValue(),
DL.getTypeSizeInBits(ElementTy).getFixedValue() / 8);
3507 Splat = IRB.CreateBitPreservingCastChain(
DL,
Splat, ElementTy);
3508 if (NumElements > 1)
3511 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3519 uint64_t
Size = NewEndOffset - NewBeginOffset;
3520 V = getIntegerSplat(
II.getValue(),
Size);
3522 if (IntTy && (NewBeginOffset != NewAllocaBeginOffset ||
3523 NewEndOffset != NewAllocaEndOffset)) {
3524 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI,
3526 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3527 uint64_t
Offset = NewBeginOffset - NewAllocaBeginOffset;
3530 assert(
V->getType() == IntTy &&
3531 "Wrong type for an alloca wide integer!");
3533 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3536 assert(NewBeginOffset == NewAllocaBeginOffset);
3537 assert(NewEndOffset == NewAllocaEndOffset);
3539 V = getIntegerSplat(
II.getValue(),
3540 DL.getTypeSizeInBits(ScalarTy).getFixedValue() / 8);
3545 V = IRB.CreateBitPreservingCastChain(
DL, V, NewAllocaTy);
3548 Value *NewPtr = getPtrToNewAI(
II.getDestAddressSpace(),
II.isVolatile());
3550 IRB.CreateAlignedStore(V, NewPtr, NewAI.
getAlign(),
II.isVolatile());
3551 New->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
3552 LLVMContext::MD_access_group});
3558 New,
New->getPointerOperand(), V,
DL);
3561 return !
II.isVolatile();
3564 bool visitMemTransferInst(MemTransferInst &
II) {
3570 AAMDNodes AATags =
II.getAAMetadata();
3572 bool IsDest = &
II.getRawDestUse() == OldUse;
3573 assert((IsDest &&
II.getRawDest() == OldPtr) ||
3574 (!IsDest &&
II.getRawSource() == OldPtr));
3576 Align SliceAlign = getSliceAlign();
3584 if (!IsSplittable) {
3585 Value *AdjustedPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
3590 DbgAssign->getAddress() ==
II.getDest())
3591 DbgAssign->replaceVariableLocationOp(
II.getDest(), AdjustedPtr);
3593 II.setDest(AdjustedPtr);
3594 II.setDestAlignment(SliceAlign);
3596 II.setSource(AdjustedPtr);
3597 II.setSourceAlignment(SliceAlign);
3601 deleteIfTriviallyDead(OldPtr);
3614 (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset ||
3615 SliceSize !=
DL.getTypeStoreSize(NewAllocaTy).getFixedValue() ||
3616 !
DL.typeSizeEqualsStoreSize(NewAllocaTy) ||
3622 if (EmitMemCpy && &OldAI == &NewAI) {
3624 assert(NewBeginOffset == BeginOffset);
3627 if (NewEndOffset != EndOffset)
3628 II.setLength(NewEndOffset - NewBeginOffset);
3632 Pass.DeadInsts.push_back(&
II);
3636 Value *OtherPtr = IsDest ?
II.getRawSource() :
II.getRawDest();
3637 if (AllocaInst *AI =
3639 assert(AI != &OldAI && AI != &NewAI &&
3640 "Splittable transfers cannot reach the same alloca on both ends.");
3641 Pass.Worklist.insert(AI);
3648 unsigned OffsetWidth =
DL.getIndexSizeInBits(OtherAS);
3649 APInt OtherOffset(OffsetWidth, NewBeginOffset - BeginOffset);
3651 (IsDest ?
II.getSourceAlign() :
II.getDestAlign()).valueOrOne();
3653 commonAlignment(OtherAlign, OtherOffset.zextOrTrunc(64).getZExtValue());
3661 Value *OurPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
3662 Type *SizeTy =
II.getLength()->getType();
3663 Constant *
Size = ConstantInt::get(SizeTy, NewEndOffset - NewBeginOffset);
3665 Value *DestPtr, *SrcPtr;
3666 MaybeAlign DestAlign, SrcAlign;
3670 DestAlign = SliceAlign;
3672 SrcAlign = OtherAlign;
3675 DestAlign = OtherAlign;
3677 SrcAlign = SliceAlign;
3679 CallInst *
New = IRB.CreateMemCpy(DestPtr, DestAlign, SrcPtr, SrcAlign,
3682 New->setAAMetadata(AATags.
shift(NewBeginOffset - BeginOffset));
3687 &
II, New, DestPtr,
nullptr,
DL);
3692 SliceSize * 8, &
II, New, DestPtr,
nullptr,
DL);
3698 bool IsWholeAlloca = NewBeginOffset == NewAllocaBeginOffset &&
3699 NewEndOffset == NewAllocaEndOffset;
3700 uint64_t
Size = NewEndOffset - NewBeginOffset;
3701 unsigned BeginIndex = VecTy ? getIndex(NewBeginOffset) : 0;
3702 unsigned EndIndex = VecTy ? getIndex(NewEndOffset) : 0;
3703 unsigned NumElements = EndIndex - BeginIndex;
3704 IntegerType *SubIntTy =
3705 IntTy ? Type::getIntNTy(IntTy->
getContext(),
Size * 8) : nullptr;
3710 if (VecTy && !IsWholeAlloca) {
3711 if (NumElements == 1)
3712 OtherTy = VecTy->getElementType();
3715 }
else if (IntTy && !IsWholeAlloca) {
3718 OtherTy = NewAllocaTy;
3723 MaybeAlign SrcAlign = OtherAlign;
3724 MaybeAlign DstAlign = SliceAlign;
3732 DstPtr = getPtrToNewAI(
II.getDestAddressSpace(),
II.isVolatile());
3736 SrcPtr = getPtrToNewAI(
II.getSourceAddressSpace(),
II.isVolatile());
3740 if (VecTy && !IsWholeAlloca && !IsDest) {
3742 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3744 }
else if (IntTy && !IsWholeAlloca && !IsDest) {
3746 IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
"load");
3747 Src = IRB.CreateBitPreservingCastChain(
DL, Src, IntTy);
3748 uint64_t
Offset = NewBeginOffset - NewAllocaBeginOffset;
3751 LoadInst *
Load = IRB.CreateAlignedLoad(OtherTy, SrcPtr, SrcAlign,
3752 II.isVolatile(),
"copyload");
3753 Load->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
3754 LLVMContext::MD_access_group});
3761 if (VecTy && !IsWholeAlloca && IsDest) {
3762 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3765 }
else if (IntTy && !IsWholeAlloca && IsDest) {
3766 Value *Old = IRB.CreateAlignedLoad(NewAllocaTy, &NewAI, NewAI.
getAlign(),
3768 Old = IRB.CreateBitPreservingCastChain(
DL, Old, IntTy);
3769 uint64_t
Offset = NewBeginOffset - NewAllocaBeginOffset;
3771 Src = IRB.CreateBitPreservingCastChain(
DL, Src, NewAllocaTy);
3775 IRB.CreateAlignedStore(Src, DstPtr, DstAlign,
II.isVolatile()));
3776 Store->copyMetadata(
II, {LLVMContext::MD_mem_parallel_loop_access,
3777 LLVMContext::MD_access_group});
3780 Src->getType(),
DL));
3786 Store, DstPtr, Src,
DL);
3791 &
II, Store, DstPtr, Src,
DL);
3795 return !
II.isVolatile();
3798 bool visitIntrinsicInst(IntrinsicInst &
II) {
3799 assert((
II.isLifetimeStartOrEnd() ||
II.isDroppable()) &&
3800 "Unexpected intrinsic!");
3804 Pass.DeadInsts.push_back(&
II);
3806 if (
II.isDroppable()) {
3807 assert(
II.getIntrinsicID() == Intrinsic::assume &&
"Expected assume");
3813 assert(
II.getArgOperand(0) == OldPtr);
3817 if (
II.getIntrinsicID() == Intrinsic::lifetime_start)
3818 New = IRB.CreateLifetimeStart(Ptr);
3820 New = IRB.CreateLifetimeEnd(Ptr);
3828 void fixLoadStoreAlign(Instruction &Root) {
3832 SmallPtrSet<Instruction *, 4> Visited;
3833 SmallVector<Instruction *, 4>
Uses;
3835 Uses.push_back(&Root);
3844 SI->setAlignment(std::min(
SI->getAlign(), getSliceAlign()));
3851 for (User *U :
I->users())
3854 }
while (!
Uses.empty());
3857 bool visitPHINode(PHINode &PN) {
3859 assert(BeginOffset >= NewAllocaBeginOffset &&
"PHIs are unsplittable");
3860 assert(EndOffset <= NewAllocaEndOffset &&
"PHIs are unsplittable");
3866 IRBuilderBase::InsertPointGuard Guard(IRB);
3869 OldPtr->
getParent()->getFirstInsertionPt());
3871 IRB.SetInsertPoint(OldPtr);
3872 IRB.SetCurrentDebugLocation(OldPtr->
getDebugLoc());
3874 Value *NewPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
3879 deleteIfTriviallyDead(OldPtr);
3882 fixLoadStoreAlign(PN);
3891 bool visitSelectInst(SelectInst &SI) {
3893 assert((
SI.getTrueValue() == OldPtr ||
SI.getFalseValue() == OldPtr) &&
3894 "Pointer isn't an operand!");
3895 assert(BeginOffset >= NewAllocaBeginOffset &&
"Selects are unsplittable");
3896 assert(EndOffset <= NewAllocaEndOffset &&
"Selects are unsplittable");
3898 Value *NewPtr = getNewAllocaSlicePtr(IRB, OldPtr->
getType());
3900 if (
SI.getOperand(1) == OldPtr)
3901 SI.setOperand(1, NewPtr);
3902 if (
SI.getOperand(2) == OldPtr)
3903 SI.setOperand(2, NewPtr);
3906 deleteIfTriviallyDead(OldPtr);
3909 fixLoadStoreAlign(SI);
3924class AggLoadStoreRewriter :
public InstVisitor<AggLoadStoreRewriter, bool> {
3926 friend class InstVisitor<AggLoadStoreRewriter, bool>;
3932 SmallPtrSet<User *, 8> Visited;
3939 const DataLayout &
DL;
3944 AggLoadStoreRewriter(
const DataLayout &
DL, IRBuilderTy &IRB)
3945 :
DL(
DL), IRB(IRB) {}
3949 bool rewrite(Instruction &
I) {
3953 while (!
Queue.empty()) {
3954 U =
Queue.pop_back_val();
3963 void enqueueUsers(Instruction &
I) {
3964 for (Use &U :
I.uses())
3965 if (Visited.
insert(
U.getUser()).second)
3966 Queue.push_back(&U);
3970 bool visitInstruction(Instruction &
I) {
return false; }
3973 template <
typename Derived>
class OpSplitter {
3980 SmallVector<unsigned, 4> Indices;
3984 SmallVector<Value *, 4> GEPIndices;
3998 const DataLayout &
DL;
4002 OpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4003 Align BaseAlign,
const DataLayout &
DL, IRBuilderTy &IRB)
4004 : IRB(IRB), GEPIndices(1, IRB.getInt32(0)), Ptr(Ptr), BaseTy(BaseTy),
4005 BaseAlign(BaseAlign),
DL(
DL) {
4006 IRB.SetInsertPoint(InsertionPoint);
4023 void emitSplitOps(
Type *Ty,
Value *&Agg,
const Twine &Name) {
4025 unsigned Offset =
DL.getIndexedOffsetInType(BaseTy, GEPIndices);
4026 return static_cast<Derived *
>(
this)->emitFunc(
4031 unsigned OldSize = Indices.
size();
4033 for (
unsigned Idx = 0,
Size = ATy->getNumElements(); Idx !=
Size;
4035 assert(Indices.
size() == OldSize &&
"Did not return to the old size");
4037 GEPIndices.
push_back(IRB.getInt32(Idx));
4038 emitSplitOps(ATy->getElementType(), Agg, Name +
"." + Twine(Idx));
4046 unsigned OldSize = Indices.
size();
4048 for (
unsigned Idx = 0,
Size = STy->getNumElements(); Idx !=
Size;
4050 assert(Indices.
size() == OldSize &&
"Did not return to the old size");
4052 GEPIndices.
push_back(IRB.getInt32(Idx));
4053 emitSplitOps(STy->getElementType(Idx), Agg, Name +
"." + Twine(Idx));
4064 struct LoadOpSplitter :
public OpSplitter<LoadOpSplitter> {
4068 SmallVector<Value *, 4> Components;
4073 LoadOpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4074 AAMDNodes AATags, Align BaseAlign,
const DataLayout &
DL,
4076 : OpSplitter<LoadOpSplitter>(InsertionPoint, Ptr, BaseTy, BaseAlign,
DL,
4082 void emitFunc(
Type *Ty,
Value *&Agg, Align Alignment,
const Twine &Name) {
4086 IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name +
".gep");
4088 IRB.CreateAlignedLoad(Ty,
GEP, Alignment, Name +
".load");
4094 Load->setAAMetadata(
4100 Agg = IRB.CreateInsertValue(Agg, Load, Indices, Name +
".insert");
4105 void recordFakeUses(LoadInst &LI) {
4106 for (Use &U : LI.
uses())
4108 if (
II->getIntrinsicID() == Intrinsic::fake_use)
4114 void emitFakeUses() {
4115 for (Instruction *
I : FakeUses) {
4116 IRB.SetInsertPoint(
I);
4117 for (
auto *V : Components)
4118 IRB.CreateIntrinsic(Intrinsic::fake_use, {
V});
4119 I->eraseFromParent();
4124 bool visitLoadInst(LoadInst &LI) {
4133 Splitter.recordFakeUses(LI);
4136 Splitter.emitFakeUses();
4143 struct StoreOpSplitter :
public OpSplitter<StoreOpSplitter> {
4144 StoreOpSplitter(Instruction *InsertionPoint,
Value *Ptr,
Type *BaseTy,
4145 AAMDNodes AATags, StoreInst *AggStore, Align BaseAlign,
4146 const DataLayout &
DL, IRBuilderTy &IRB)
4147 : OpSplitter<StoreOpSplitter>(InsertionPoint, Ptr, BaseTy, BaseAlign,
4149 AATags(AATags), AggStore(AggStore) {}
4151 StoreInst *AggStore;
4154 void emitFunc(
Type *Ty,
Value *&Agg, Align Alignment,
const Twine &Name) {
4160 Value *ExtractValue =
4161 IRB.CreateExtractValue(Agg, Indices, Name +
".extract");
4162 Value *InBoundsGEP =
4163 IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name +
".gep");
4165 IRB.CreateAlignedStore(ExtractValue, InBoundsGEP, Alignment);
4181 uint64_t SizeInBits =
4182 DL.getTypeSizeInBits(
Store->getValueOperand()->getType());
4184 SizeInBits, AggStore, Store,
4185 Store->getPointerOperand(),
Store->getValueOperand(),
4189 "AT: unexpected debug.assign linked to store through "
4196 bool visitStoreInst(StoreInst &SI) {
4197 if (!
SI.isSimple() ||
SI.getPointerOperand() != *U)
4200 if (
V->getType()->isSingleValueType())
4205 StoreOpSplitter Splitter(&SI, *U,
V->getType(),
SI.getAAMetadata(), &SI,
4207 Splitter.emitSplitOps(
V->getType(), V,
V->getName() +
".fca");
4212 SI.eraseFromParent();
4216 bool visitBitCastInst(BitCastInst &BC) {
4221 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
4231 bool unfoldGEPSelect(GetElementPtrInst &GEPI) {
4250 if (!ZI->getSrcTy()->isIntegerTy(1))
4263 dbgs() <<
" original: " << *Sel <<
"\n";
4264 dbgs() <<
" " << GEPI <<
"\n";);
4266 auto GetNewOps = [&](
Value *SelOp) {
4279 Cond =
SI->getCondition();
4280 True =
SI->getTrueValue();
4281 False =
SI->getFalseValue();
4285 Cond = Sel->getOperand(0);
4286 True = ConstantInt::get(Sel->getType(), 1);
4287 False = ConstantInt::get(Sel->getType(), 0);
4292 IRB.SetInsertPoint(&GEPI);
4296 Value *NTrue = IRB.CreateGEP(Ty, TrueOps[0],
ArrayRef(TrueOps).drop_front(),
4297 True->
getName() +
".sroa.gep", NW);
4300 IRB.CreateGEP(Ty, FalseOps[0],
ArrayRef(FalseOps).drop_front(),
4301 False->
getName() +
".sroa.gep", NW);
4303 Value *NSel = MDFrom
4304 ? IRB.CreateSelect(
Cond, NTrue, NFalse,
4305 Sel->getName() +
".sroa.sel", MDFrom)
4306 : IRB.CreateSelectWithUnknownProfile(
4308 Sel->getName() +
".sroa.sel");
4309 Visited.
erase(&GEPI);
4314 enqueueUsers(*NSelI);
4317 dbgs() <<
" " << *NFalse <<
"\n";
4318 dbgs() <<
" " << *NSel <<
"\n";);
4327 bool unfoldGEPPhi(GetElementPtrInst &GEPI) {
4332 auto IsInvalidPointerOperand = [](
Value *
V) {
4336 return !AI->isStaticAlloca();
4340 if (
any_of(
Phi->operands(), IsInvalidPointerOperand))
4355 [](
Value *V) { return isa<ConstantInt>(V); }))
4368 dbgs() <<
" original: " << *
Phi <<
"\n";
4369 dbgs() <<
" " << GEPI <<
"\n";);
4371 auto GetNewOps = [&](
Value *PhiOp) {
4381 IRB.SetInsertPoint(Phi);
4382 PHINode *NewPhi = IRB.CreatePHI(GEPI.
getType(),
Phi->getNumIncomingValues(),
4383 Phi->getName() +
".sroa.phi");
4389 for (
unsigned I = 0,
E =
Phi->getNumIncomingValues();
I !=
E; ++
I) {
4398 IRB.CreateGEP(SourceTy, NewOps[0],
ArrayRef(NewOps).drop_front(),
4404 Visited.
erase(&GEPI);
4408 enqueueUsers(*NewPhi);
4414 dbgs() <<
"\n " << *NewPhi <<
'\n');
4419 bool visitGetElementPtrInst(GetElementPtrInst &GEPI) {
4420 if (unfoldGEPSelect(GEPI))
4423 if (unfoldGEPPhi(GEPI))
4430 bool visitPHINode(PHINode &PN) {
4435 bool visitSelectInst(SelectInst &SI) {
4449 if (Ty->isSingleValueType())
4452 uint64_t AllocSize =
DL.getTypeAllocSize(Ty).getFixedValue();
4457 InnerTy = ArrTy->getElementType();
4461 InnerTy = STy->getElementType(Index);
4466 if (AllocSize >
DL.getTypeAllocSize(InnerTy).getFixedValue() ||
4467 TypeSize >
DL.getTypeSizeInBits(InnerTy).getFixedValue())
4488 if (
Offset == 0 &&
DL.getTypeAllocSize(Ty).getFixedValue() ==
Size)
4490 if (
Offset >
DL.getTypeAllocSize(Ty).getFixedValue() ||
4491 (
DL.getTypeAllocSize(Ty).getFixedValue() -
Offset) <
Size)
4498 ElementTy = AT->getElementType();
4499 TyNumElements = AT->getNumElements();
4504 ElementTy = VT->getElementType();
4505 TyNumElements = VT->getNumElements();
4507 uint64_t ElementSize =
DL.getTypeAllocSize(ElementTy).getFixedValue();
4509 if (NumSkippedElements >= TyNumElements)
4511 Offset -= NumSkippedElements * ElementSize;
4523 if (
Size == ElementSize)
4527 if (NumElements * ElementSize !=
Size)
4551 uint64_t ElementSize =
DL.getTypeAllocSize(ElementTy).getFixedValue();
4552 if (
Offset >= ElementSize)
4563 if (
Size == ElementSize)
4570 if (Index == EndIndex)
4580 assert(Index < EndIndex);
4619bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
4633 struct SplitOffsets {
4635 std::vector<uint64_t> Splits;
4637 SmallDenseMap<Instruction *, SplitOffsets, 8> SplitOffsetsMap;
4650 SmallPtrSet<LoadInst *, 8> UnsplittableLoads;
4652 LLVM_DEBUG(
dbgs() <<
" Searching for candidate loads and stores\n");
4653 for (
auto &
P : AS.partitions()) {
4654 for (Slice &S :
P) {
4656 if (!S.isSplittable() || S.endOffset() <=
P.endOffset()) {
4661 UnsplittableLoads.
insert(LI);
4664 UnsplittableLoads.
insert(LI);
4667 assert(
P.endOffset() > S.beginOffset() &&
4668 "Empty or backwards partition!");
4677 auto IsLoadSimplyStored = [](LoadInst *LI) {
4678 for (User *LU : LI->
users()) {
4680 if (!SI || !
SI->isSimple())
4685 if (!IsLoadSimplyStored(LI)) {
4686 UnsplittableLoads.
insert(LI);
4692 if (S.getUse() != &
SI->getOperandUse(
SI->getPointerOperandIndex()))
4696 if (!StoredLoad || !StoredLoad->isSimple())
4698 assert(!
SI->isVolatile() &&
"Cannot split volatile stores!");
4708 auto &
Offsets = SplitOffsetsMap[
I];
4710 "Should not have splits the first time we see an instruction!");
4712 Offsets.Splits.push_back(
P.endOffset() - S.beginOffset());
4717 for (Slice *S :
P.splitSliceTails()) {
4718 auto SplitOffsetsMapI =
4720 if (SplitOffsetsMapI == SplitOffsetsMap.
end())
4722 auto &
Offsets = SplitOffsetsMapI->second;
4726 "Cannot have an empty set of splits on the second partition!");
4728 P.beginOffset() -
Offsets.S->beginOffset() &&
4729 "Previous split does not end where this one begins!");
4733 if (S->endOffset() >
P.endOffset())
4742 llvm::erase_if(Stores, [&UnsplittableLoads, &SplitOffsetsMap](StoreInst *SI) {
4748 if (UnsplittableLoads.
count(LI))
4751 auto LoadOffsetsI = SplitOffsetsMap.
find(LI);
4752 if (LoadOffsetsI == SplitOffsetsMap.
end())
4754 auto &LoadOffsets = LoadOffsetsI->second;
4757 auto &StoreOffsets = SplitOffsetsMap[
SI];
4762 if (LoadOffsets.Splits == StoreOffsets.Splits)
4766 <<
" " << *LI <<
"\n"
4767 <<
" " << *SI <<
"\n");
4773 UnsplittableLoads.
insert(LI);
4782 return UnsplittableLoads.
count(LI);
4787 return UnsplittableLoads.
count(LI);
4797 IRBuilderTy IRB(&AI);
4804 SmallPtrSet<AllocaInst *, 4> ResplitPromotableAllocas;
4814 SmallDenseMap<LoadInst *, std::vector<LoadInst *>, 1> SplitLoadsMap;
4815 std::vector<LoadInst *> SplitLoads;
4816 const DataLayout &
DL = AI.getDataLayout();
4817 for (LoadInst *LI : Loads) {
4820 auto &
Offsets = SplitOffsetsMap[LI];
4821 unsigned SliceSize =
Offsets.S->endOffset() -
Offsets.S->beginOffset();
4823 "Load must have type size equal to store size");
4825 "Load must be >= slice size");
4827 uint64_t BaseOffset =
Offsets.S->beginOffset();
4828 assert(BaseOffset + SliceSize > BaseOffset &&
4829 "Cannot represent alloca access size using 64-bit integers!");
4832 IRB.SetInsertPoint(LI);
4836 uint64_t PartOffset = 0, PartSize =
Offsets.Splits.front();
4839 auto *PartTy = Type::getIntNTy(LI->
getContext(), PartSize * 8);
4842 LoadInst *PLoad = IRB.CreateAlignedLoad(
4845 APInt(
DL.getIndexSizeInBits(AS), PartOffset),
4846 PartPtrTy,
BasePtr->getName() +
"."),
4849 PLoad->
copyMetadata(*LI, {LLVMContext::MD_mem_parallel_loop_access,
4850 LLVMContext::MD_access_group});
4854 SplitLoads.push_back(PLoad);
4858 Slice(BaseOffset + PartOffset, BaseOffset + PartOffset + PartSize,
4862 <<
", " << NewSlices.
back().endOffset()
4863 <<
"): " << *PLoad <<
"\n");
4870 PartOffset =
Offsets.Splits[Idx];
4872 PartSize = (Idx <
Size ?
Offsets.Splits[Idx] : SliceSize) - PartOffset;
4878 bool DeferredStores =
false;
4879 for (User *LU : LI->
users()) {
4881 if (!Stores.
empty() && SplitOffsetsMap.
count(SI)) {
4882 DeferredStores =
true;
4888 Value *StoreBasePtr =
SI->getPointerOperand();
4889 IRB.SetInsertPoint(SI);
4890 AAMDNodes AATags =
SI->getAAMetadata();
4892 LLVM_DEBUG(
dbgs() <<
" Splitting store of load: " << *SI <<
"\n");
4894 for (
int Idx = 0,
Size = SplitLoads.size(); Idx <
Size; ++Idx) {
4895 LoadInst *PLoad = SplitLoads[Idx];
4896 uint64_t PartOffset = Idx == 0 ? 0 :
Offsets.Splits[Idx - 1];
4897 auto *PartPtrTy =
SI->getPointerOperandType();
4899 auto AS =
SI->getPointerAddressSpace();
4900 StoreInst *PStore = IRB.CreateAlignedStore(
4903 APInt(
DL.getIndexSizeInBits(AS), PartOffset),
4904 PartPtrTy, StoreBasePtr->
getName() +
"."),
4907 PStore->
copyMetadata(*SI, {LLVMContext::MD_mem_parallel_loop_access,
4908 LLVMContext::MD_access_group,
4909 LLVMContext::MD_DIAssignID});
4914 LLVM_DEBUG(
dbgs() <<
" +" << PartOffset <<
":" << *PStore <<
"\n");
4922 ResplitPromotableAllocas.
insert(OtherAI);
4923 Worklist.insert(OtherAI);
4926 Worklist.insert(OtherAI);
4930 DeadInsts.push_back(SI);
4935 SplitLoadsMap.
insert(std::make_pair(LI, std::move(SplitLoads)));
4938 DeadInsts.push_back(LI);
4947 for (StoreInst *SI : Stores) {
4952 assert(StoreSize > 0 &&
"Cannot have a zero-sized integer store!");
4956 "Slice size should always match load size exactly!");
4957 uint64_t BaseOffset =
Offsets.S->beginOffset();
4958 assert(BaseOffset + StoreSize > BaseOffset &&
4959 "Cannot represent alloca access size using 64-bit integers!");
4967 auto SplitLoadsMapI = SplitLoadsMap.
find(LI);
4968 std::vector<LoadInst *> *SplitLoads =
nullptr;
4969 if (SplitLoadsMapI != SplitLoadsMap.
end()) {
4970 SplitLoads = &SplitLoadsMapI->second;
4972 "Too few split loads for the number of splits in the store!");
4977 uint64_t PartOffset = 0, PartSize =
Offsets.Splits.front();
4980 auto *PartTy = Type::getIntNTy(Ty->
getContext(), PartSize * 8);
4982 auto *StorePartPtrTy =
SI->getPointerOperandType();
4987 PLoad = (*SplitLoads)[Idx];
4989 IRB.SetInsertPoint(LI);
4991 PLoad = IRB.CreateAlignedLoad(
4994 APInt(
DL.getIndexSizeInBits(AS), PartOffset),
4995 LoadPartPtrTy, LoadBasePtr->
getName() +
"."),
4998 PLoad->
copyMetadata(*LI, {LLVMContext::MD_mem_parallel_loop_access,
4999 LLVMContext::MD_access_group});
5003 IRB.SetInsertPoint(SI);
5004 auto AS =
SI->getPointerAddressSpace();
5005 StoreInst *PStore = IRB.CreateAlignedStore(
5008 APInt(
DL.getIndexSizeInBits(AS), PartOffset),
5009 StorePartPtrTy, StoreBasePtr->
getName() +
"."),
5012 PStore->
copyMetadata(*SI, {LLVMContext::MD_mem_parallel_loop_access,
5013 LLVMContext::MD_access_group});
5017 Slice(BaseOffset + PartOffset, BaseOffset + PartOffset + PartSize,
5021 <<
", " << NewSlices.
back().endOffset()
5022 <<
"): " << *PStore <<
"\n");
5032 PartOffset =
Offsets.Splits[Idx];
5034 PartSize = (Idx <
Size ?
Offsets.Splits[Idx] : StoreSize) - PartOffset;
5044 assert(OtherAI != &AI &&
"We can't re-split our own alloca!");
5045 ResplitPromotableAllocas.
insert(OtherAI);
5046 Worklist.insert(OtherAI);
5049 assert(OtherAI != &AI &&
"We can't re-split our own alloca!");
5050 Worklist.insert(OtherAI);
5065 DeadInsts.push_back(LI);
5067 DeadInsts.push_back(SI);
5076 AS.insert(NewSlices);
5080 for (
auto I = AS.begin(),
E = AS.end();
I !=
E; ++
I)
5086 PromotableAllocas.set_subtract(ResplitPromotableAllocas);
5122 bool IsIntegralPointerTy =
5123 EltTy->
isPointerTy() && !
DL.isNonIntegralPointerType(EltTy);
5125 !IsIntegralPointerTy)
5129 TypeSize StructSize =
DL.getStructLayout(STy)->getSizeInBytes();
5130 TypeSize VectorSize =
DL.getTypeAllocSize(VTy);
5131 if (StructSize != VectorSize)
5134 for (
const Slice &S :
P) {
5137 auto *U = S.getUse();
5141 User *Usr = U->getUser();
5163static std::tuple<Type *, bool, VectorType *>
5167 VectorType *SelectedVecTy,
bool SelectedIntWidening) {
5169 dbgs() <<
"selectPartitionType path=" << Path
5174 dbgs() <<
"<unnamed>";
5175 dbgs() <<
" partition=[" <<
P.beginOffset() <<
"," <<
P.endOffset()
5176 <<
") size=" <<
P.size();
5178 dbgs() <<
" alloc-size=" << AllocSize->getKnownMinValue();
5180 dbgs() <<
" chosen=" << *SelectedTy;
5182 dbgs() <<
" vec=" << *SelectedVecTy;
5183 dbgs() <<
" intwiden=" << SelectedIntWidening <<
"\n";
5201 if (VecTy && VecTy->getElementType()->isFloatingPointTy() &&
5202 VecTy->getElementCount().getFixedValue() > 1) {
5203 LogSelection(
"direct-fp-vecty", VecTy, VecTy,
false);
5204 return {VecTy,
false, VecTy};
5209 auto [CommonUseTy, LargestIntTy] =
5212 TypeSize CommonUseSize =
DL.getTypeAllocSize(CommonUseTy);
5218 LogSelection(
"common-type-vecty", VecTy, VecTy,
false);
5219 return {VecTy,
false, VecTy};
5222 LogSelection(
"common-type", CommonUseTy,
nullptr, IntWiden);
5223 return {CommonUseTy, IntWiden,
nullptr};
5230 P.beginOffset(),
P.size())) {
5234 if (TypePartitionTy->isArrayTy() &&
5235 TypePartitionTy->getArrayElementType()->isIntegerTy() &&
5236 DL.isLegalInteger(
P.size() * 8))
5240 LogSelection(
"type-partition-int-widen", TypePartitionTy,
nullptr,
true);
5241 return {TypePartitionTy,
true,
nullptr};
5244 LogSelection(
"type-partition-vecty", VecTy, VecTy,
false);
5245 return {VecTy,
false, VecTy};
5250 DL.getTypeAllocSize(LargestIntTy).getFixedValue() >=
P.size() &&
5252 LogSelection(
"largest-int-int-widen", LargestIntTy,
nullptr,
true);
5253 return {LargestIntTy,
true,
nullptr};
5258 if (AggregateToVector) {
5261 LogSelection(
"struct-fallback-vecty", VTy,
nullptr,
false);
5262 return {VTy,
false,
nullptr};
5268 LogSelection(
"type-partition-fallback", TypePartitionTy,
nullptr,
false);
5269 return {TypePartitionTy,
false,
nullptr};
5274 DL.getTypeAllocSize(LargestIntTy).getFixedValue() >=
P.size()) {
5275 LogSelection(
"largest-int-fallback", LargestIntTy,
nullptr,
false);
5276 return {LargestIntTy,
false,
nullptr};
5280 if (
DL.isLegalInteger(
P.size() * 8)) {
5282 LogSelection(
"legal-int-fallback", IntTy,
nullptr,
false);
5283 return {IntTy,
false,
nullptr};
5288 LogSelection(
"byte-array-fallback", ArrayTy,
nullptr,
false);
5289 return {ArrayTy,
false,
nullptr};
5302std::pair<AllocaInst *, uint64_t>
5303SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS, Partition &
P) {
5304 const DataLayout &
DL = AI.getDataLayout();
5306 auto [PartitionTy, IsIntegerWideningViable, VecTy] =
5316 if (PartitionTy == AI.getAllocatedType() &&
P.beginOffset() == 0) {
5326 const bool IsUnconstrained = Alignment <=
DL.getABITypeAlign(PartitionTy);
5327 NewAI =
new AllocaInst(
5328 PartitionTy, AI.getAddressSpace(),
nullptr,
5329 IsUnconstrained ?
DL.getPrefTypeAlign(PartitionTy) : Alignment,
5330 AI.
getName() +
".sroa." + Twine(
P.begin() - AS.begin()),
5337 LLVM_DEBUG(
dbgs() <<
"Rewriting alloca partition " <<
"[" <<
P.beginOffset()
5338 <<
"," <<
P.endOffset() <<
") to: " << *NewAI <<
"\n");
5343 unsigned PPWOldSize = PostPromotionWorklist.size();
5344 unsigned NumUses = 0;
5345 SmallSetVector<PHINode *, 8> PHIUsers;
5346 SmallSetVector<SelectInst *, 8> SelectUsers;
5349 DL, AS, *
this, AI, *NewAI, PartitionTy,
P.beginOffset(),
P.endOffset(),
5350 IsIntegerWideningViable, VecTy, PHIUsers, SelectUsers);
5351 bool Promotable =
true;
5353 if (
auto DeletedValues =
Rewriter.rewriteTreeStructuredMerge(
P)) {
5354 NumUses += DeletedValues->
size() + 1;
5355 for (
Value *V : *DeletedValues)
5356 DeadInsts.push_back(V);
5358 for (Slice *S :
P.splitSliceTails()) {
5362 for (Slice &S :
P) {
5368 NumAllocaPartitionUses += NumUses;
5369 MaxUsesPerAllocaPartition.updateMax(NumUses);
5373 for (PHINode *
PHI : PHIUsers)
5377 SelectUsers.
clear();
5382 NewSelectsToRewrite;
5384 for (SelectInst *Sel : SelectUsers) {
5385 std::optional<RewriteableMemOps>
Ops =
5386 isSafeSelectToSpeculate(*Sel, PreserveCFG);
5390 SelectUsers.clear();
5391 NewSelectsToRewrite.
clear();
5398 for (Use *U : AS.getDeadUsesIfPromotable()) {
5400 Value::dropDroppableUse(*U);
5403 DeadInsts.push_back(OldInst);
5405 if (PHIUsers.empty() && SelectUsers.empty()) {
5407 PromotableAllocas.insert(NewAI);
5412 SpeculatablePHIs.insert_range(PHIUsers);
5413 SelectsToRewrite.reserve(SelectsToRewrite.size() +
5414 NewSelectsToRewrite.
size());
5416 std::make_move_iterator(NewSelectsToRewrite.
begin()),
5417 std::make_move_iterator(NewSelectsToRewrite.
end())))
5418 SelectsToRewrite.insert(std::move(KV));
5419 Worklist.insert(NewAI);
5423 while (PostPromotionWorklist.size() > PPWOldSize)
5424 PostPromotionWorklist.pop_back();
5429 return {
nullptr, 0};
5434 Worklist.insert(NewAI);
5437 return {NewAI,
DL.getTypeSizeInBits(PartitionTy).getFixedValue()};
5481 int64_t BitExtractOffset) {
5483 bool HasFragment =
false;
5484 bool HasBitExtract =
false;
5493 HasBitExtract =
true;
5494 int64_t ExtractOffsetInBits =
Op.getArg(0);
5495 int64_t ExtractSizeInBits =
Op.getArg(1);
5504 assert(BitExtractOffset <= 0);
5505 int64_t AdjustedOffset = ExtractOffsetInBits + BitExtractOffset;
5511 if (AdjustedOffset < 0)
5514 Ops.push_back(
Op.getOp());
5515 Ops.push_back(std::max<int64_t>(0, AdjustedOffset));
5516 Ops.push_back(ExtractSizeInBits);
5519 Op.appendToVector(
Ops);
5524 if (HasFragment && HasBitExtract)
5527 if (!HasBitExtract) {
5546 std::optional<DIExpression::FragmentInfo> NewFragment,
5547 int64_t BitExtractAdjustment) {
5557 BitExtractAdjustment);
5558 if (!NewFragmentExpr)
5564 BeforeInst->
getParent()->insertDbgRecordBefore(DVR,
5577 BeforeInst->
getParent()->insertDbgRecordBefore(DVR,
5583 if (!NewAddr->
hasMetadata(LLVMContext::MD_DIAssignID)) {
5591 LLVM_DEBUG(
dbgs() <<
"Created new DVRAssign: " << *NewAssign <<
"\n");
5597bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
5598 if (AS.begin() == AS.end())
5601 unsigned NumPartitions = 0;
5603 const DataLayout &
DL = AI.getModule()->getDataLayout();
5606 Changed |= presplitLoadsAndStores(AI, AS);
5614 bool IsSorted =
true;
5616 uint64_t AllocaSize = AI.getAllocationSize(
DL)->getFixedValue();
5617 const uint64_t MaxBitVectorSize = 1024;
5618 if (AllocaSize <= MaxBitVectorSize) {
5621 SmallBitVector SplittableOffset(AllocaSize + 1,
true);
5623 for (
unsigned O = S.beginOffset() + 1;
5624 O < S.endOffset() && O < AllocaSize; O++)
5625 SplittableOffset.reset(O);
5627 for (Slice &S : AS) {
5628 if (!S.isSplittable())
5631 if ((S.beginOffset() > AllocaSize || SplittableOffset[S.beginOffset()]) &&
5632 (S.endOffset() > AllocaSize || SplittableOffset[S.endOffset()]))
5637 S.makeUnsplittable();
5644 for (Slice &S : AS) {
5645 if (!S.isSplittable())
5648 if (S.beginOffset() == 0 && S.endOffset() >= AllocaSize)
5653 S.makeUnsplittable();
5668 Fragment(AllocaInst *AI, uint64_t O, uint64_t S)
5674 for (
auto &
P : AS.partitions()) {
5675 auto [NewAI, ActiveBits] = rewritePartition(AI, AS, P);
5679 uint64_t SizeOfByte = 8;
5681 uint64_t Size = std::min(ActiveBits, P.size() * SizeOfByte);
5682 Fragments.push_back(
5683 Fragment(NewAI, P.beginOffset() * SizeOfByte, Size));
5689 NumAllocaPartitions += NumPartitions;
5690 MaxPartitionsPerAlloca.updateMax(NumPartitions);
5694 auto MigrateOne = [&](DbgVariableRecord *DbgVariable) {
5699 const Value *DbgPtr = DbgVariable->getAddress();
5701 DbgVariable->getFragmentOrEntireVariable();
5704 int64_t CurrentExprOffsetInBytes = 0;
5705 SmallVector<uint64_t> PostOffsetOps;
5707 ->extractLeadingOffset(CurrentExprOffsetInBytes, PostOffsetOps))
5711 int64_t ExtractOffsetInBits = 0;
5715 ExtractOffsetInBits =
Op.getArg(0);
5720 DIBuilder DIB(*AI.getModule(),
false);
5721 for (
auto Fragment : Fragments) {
5722 int64_t OffsetFromLocationInBits;
5723 std::optional<DIExpression::FragmentInfo> NewDbgFragment;
5728 DL, &AI, Fragment.Offset, Fragment.Size, DbgPtr,
5729 CurrentExprOffsetInBytes * 8, ExtractOffsetInBits, VarFrag,
5730 NewDbgFragment, OffsetFromLocationInBits))
5736 if (NewDbgFragment && !NewDbgFragment->SizeInBits)
5741 if (!NewDbgFragment)
5742 NewDbgFragment = DbgVariable->getFragment();
5746 int64_t OffestFromNewAllocaInBits =
5747 OffsetFromLocationInBits - ExtractOffsetInBits;
5750 int64_t BitExtractOffset =
5751 std::min<int64_t>(0, OffestFromNewAllocaInBits);
5756 OffestFromNewAllocaInBits =
5757 std::max(int64_t(0), OffestFromNewAllocaInBits);
5763 DIExpression *NewExpr = DIExpression::get(AI.getContext(), PostOffsetOps);
5764 if (OffestFromNewAllocaInBits > 0) {
5765 int64_t OffsetInBytes = (OffestFromNewAllocaInBits + 7) / 8;
5771 auto RemoveOne = [DbgVariable](
auto *OldDII) {
5772 auto SameVariableFragment = [](
const auto *
LHS,
const auto *
RHS) {
5773 return LHS->getVariable() ==
RHS->getVariable() &&
5774 LHS->getDebugLoc()->getInlinedAt() ==
5775 RHS->getDebugLoc()->getInlinedAt();
5777 if (SameVariableFragment(OldDII, DbgVariable))
5778 OldDII->eraseFromParent();
5783 NewDbgFragment, BitExtractOffset);
5797void SROA::clobberUse(Use &U) {
5807 DeadInsts.push_back(OldI);
5829bool SROA::propagateStoredValuesToLoads(AllocaInst &AI, AllocaSlices &AS) {
5834 LLVM_DEBUG(
dbgs() <<
"Attempting to propagate values on " << AI <<
"\n");
5835 bool AllSameAndValid =
true;
5836 Type *PartitionType =
nullptr;
5838 uint64_t BeginOffset = 0;
5839 uint64_t EndOffset = 0;
5841 auto Flush = [&]() {
5842 if (AllSameAndValid && !Insts.
empty()) {
5843 LLVM_DEBUG(
dbgs() <<
"Propagate values on slice [" << BeginOffset <<
", "
5844 << EndOffset <<
")\n");
5846 SSAUpdater
SSA(&NewPHIs);
5848 BasicLoadAndStorePromoter Promoter(Insts,
SSA, PartitionType);
5849 Promoter.run(Insts);
5851 AllSameAndValid =
true;
5852 PartitionType =
nullptr;
5856 for (Slice &S : AS) {
5860 dbgs() <<
"Ignoring slice: ";
5861 AS.print(
dbgs(), &S);
5865 if (S.beginOffset() >= EndOffset) {
5867 BeginOffset = S.beginOffset();
5868 EndOffset = S.endOffset();
5869 }
else if (S.beginOffset() != BeginOffset || S.endOffset() != EndOffset) {
5870 if (AllSameAndValid) {
5872 dbgs() <<
"Slice does not match range [" << BeginOffset <<
", "
5873 << EndOffset <<
")";
5874 AS.print(
dbgs(), &S);
5876 AllSameAndValid =
false;
5878 EndOffset = std::max(EndOffset, S.endOffset());
5885 if (!LI->
isSimple() || (PartitionType && UserTy != PartitionType))
5886 AllSameAndValid =
false;
5887 PartitionType = UserTy;
5890 Type *UserTy =
SI->getValueOperand()->getType();
5891 if (!
SI->isSimple() || (PartitionType && UserTy != PartitionType))
5892 AllSameAndValid =
false;
5893 PartitionType = UserTy;
5896 AllSameAndValid =
false;
5909std::pair<
bool ,
bool >
5910SROA::runOnAlloca(AllocaInst &AI) {
5912 bool CFGChanged =
false;
5915 ++NumAllocasAnalyzed;
5918 if (AI.use_empty()) {
5919 AI.eraseFromParent();
5923 const DataLayout &
DL = AI.getDataLayout();
5926 std::optional<TypeSize>
Size = AI.getAllocationSize(
DL);
5927 if (AI.isArrayAllocation() || !
Size ||
Size->isScalable() ||
Size->isZero())
5932 IRBuilderTy IRB(&AI);
5933 AggLoadStoreRewriter AggRewriter(
DL, IRB);
5934 Changed |= AggRewriter.rewrite(AI);
5937 AllocaSlices AS(
DL, AI);
5942 if (AS.isEscapedReadOnly()) {
5943 Changed |= propagateStoredValuesToLoads(AI, AS);
5948 for (Instruction *DeadUser : AS.getDeadUsers()) {
5950 for (Use &DeadOp : DeadUser->operands())
5957 DeadInsts.push_back(DeadUser);
5960 for (Use *DeadOp : AS.getDeadOperands()) {
5961 clobberUse(*DeadOp);
5966 if (AS.begin() == AS.end())
5969 Changed |= splitAlloca(AI, AS);
5972 while (!SpeculatablePHIs.empty())
5976 auto RemainingSelectsToRewrite = SelectsToRewrite.takeVector();
5977 while (!RemainingSelectsToRewrite.empty()) {
5978 const auto [
K,
V] = RemainingSelectsToRewrite.pop_back_val();
5995bool SROA::deleteDeadInstructions(
5996 SmallPtrSetImpl<AllocaInst *> &DeletedAllocas) {
5998 while (!DeadInsts.empty()) {
6008 DeletedAllocas.
insert(AI);
6010 OldDII->eraseFromParent();
6016 for (Use &Operand :
I->operands())
6021 DeadInsts.push_back(U);
6025 I->eraseFromParent();
6035bool SROA::promoteAllocas() {
6036 if (PromotableAllocas.empty())
6043 NumPromoted += PromotableAllocas.size();
6044 PromoteMemToReg(PromotableAllocas.getArrayRef(), DTU->getDomTree(), AC);
6047 PromotableAllocas.clear();
6051std::pair<
bool ,
bool > SROA::runSROA(Function &
F) {
6054 const DataLayout &
DL =
F.getDataLayout();
6059 std::optional<TypeSize>
Size = AI->getAllocationSize(
DL);
6061 PromotableAllocas.insert(AI);
6063 Worklist.insert(AI);
6068 bool CFGChanged =
false;
6071 SmallPtrSet<AllocaInst *, 4> DeletedAllocas;
6074 while (!Worklist.empty()) {
6075 auto [IterationChanged, IterationCFGChanged] =
6076 runOnAlloca(*Worklist.pop_back_val());
6078 CFGChanged |= IterationCFGChanged;
6080 Changed |= deleteDeadInstructions(DeletedAllocas);
6084 if (!DeletedAllocas.
empty()) {
6085 Worklist.set_subtract(DeletedAllocas);
6086 PostPromotionWorklist.set_subtract(DeletedAllocas);
6087 PromotableAllocas.set_subtract(DeletedAllocas);
6088 DeletedAllocas.
clear();
6094 Worklist = PostPromotionWorklist;
6095 PostPromotionWorklist.clear();
6096 }
while (!Worklist.empty());
6098 assert((!CFGChanged ||
Changed) &&
"Can not only modify the CFG.");
6099 assert((!CFGChanged || !PreserveCFG) &&
6100 "Should not have modified the CFG when told to preserve it.");
6103 for (
auto &BB :
F) {
6116 SROA(&
F.getContext(), &DTU, &AC, Options).runSROA(
F);
6129 OS, MapClassName2PassName);
6133 if (Options.AggregateToVector)
6134 OS <<
";aggregate-to-vector";
6155 if (skipFunction(
F))
6158 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
6160 getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
6166 void getAnalysisUsage(AnalysisUsage &AU)
const override {
6173 StringRef getPassName()
const override {
return "SROA"; }
6178char SROALegacyPass::ID = 0;
6183 AggregateToVector));
6187 "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< 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...
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)
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
static unsigned getNumElements(Type *Ty)
bool isDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
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 DbgInstPtr insertDbgAssign(Instruction *LinkedInstr, Value *Val, DILocalVariable *SrcVar, DIExpression *ValExpr, Value *Addr, DIExpression *AddrExpr, const DILocation *DL)
Insert a new llvm.dbg.assign intrinsic call.
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 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)
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()
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
@ C
The default llvm calling convention, compatible with C.
@ 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_extract_bits_zext
Only used in LLVM metadata.
@ DW_OP_LLVM_fragment
Only used in LLVM metadata.
@ DW_OP_LLVM_extract_bits_sext
Only used in LLVM metadata.
@ User
could "use" a pointer
NodeAddr< PhiNode * > Phi
NodeAddr< UseNode * > Use
Context & getContext() const
friend class Instruction
Iterator for Instructions in a `BasicBlock.
LLVM_ABI iterator begin() const
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)
FunctionAddr VTableAddr Value
void stable_sort(R &&Range)
LLVM_ABI bool RemoveRedundantDbgInstrs(BasicBlock *BB)
Try to remove redundant dbg.value instructions from given basic block.
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)
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.
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 bool isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &Size, const DataLayout &DL, Instruction *ScanFrom, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr)
Return true if we know that executing a load from this value cannot trap.
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.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
LLVM_ABI TinyPtrVector< DbgVariableRecord * > findDVRDeclares(Value *V)
Finds dbg.declare records declaring local variables as living in the memory that 'V' points to.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
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 ...
auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
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.
A CRTP mix-in to automatically provide informational APIs needed for passes.