41#include "llvm/IR/IntrinsicsAMDGPU.h"
42#include "llvm/IR/IntrinsicsR600.h"
50#define DEBUG_TYPE "amdgpu-promote-alloca"
59struct GEPToVectorIndex {
67struct MemTransferInfo {
73struct AllocaAnalysis {
78 bool HaveSelectOrPHI =
false;
91 explicit AllocaAnalysis(
AllocaInst *Alloca) : Alloca(Alloca) {}
95class AMDGPUPromoteAllocaImpl {
97 const AMDGPUOptions &CLOpts;
107 unsigned VGPRBudgetRatio;
108 unsigned MaxVectorRegs;
110 bool IsAMDGCN =
false;
111 bool IsAMDHSA =
false;
113 std::pair<Value *, Value *> getLocalSizeYZ(
IRBuilder<> &Builder);
116 bool collectAllocaUses(AllocaAnalysis &
AA)
const;
122 bool binaryOpIsDerivedFromSameAlloca(
Value *Alloca,
Value *Val,
127 bool hasSufficientLocalMem(
const Function &
F);
130 void analyzePromoteToVector(AllocaAnalysis &
AA)
const;
131 void promoteAllocaToVector(AllocaAnalysis &
AA);
132 void analyzePromoteToLDS(AllocaAnalysis &
AA)
const;
133 bool tryPromoteAllocaToLDS(AllocaAnalysis &
AA,
bool SufficientLDS,
138 void scoreAlloca(AllocaAnalysis &
AA)
const;
140 void setFunctionLimits(
const Function &
F);
145 TM(TM), LI(LI),
Mod(M),
DL(M.getDataLayout()) {
146 const Triple &TT = M.getTargetTriple();
147 IsAMDGCN = TT.isAMDGCN();
151 bool run(
Function &
F,
bool PromoteToLDS);
164 if (
auto *TPC = getAnalysisIfAvailable<TargetPassConfig>())
165 return AMDGPUPromoteAllocaImpl(
167 getAnalysis<LoopInfoWrapperPass>().getLoopInfo())
172 StringRef getPassName()
const override {
return "AMDGPU Promote Alloca"; }
181static unsigned getMaxVGPRs(
unsigned LDSBytes,
const TargetMachine &TM,
186 unsigned MaxVGPRs = ST.getMaxNumVGPRs(
187 ST.getWavesPerEU(ST.getFlatWorkGroupSizes(
F), LDSBytes,
F).first,
188 DynamicVGPRBlockSize);
191 if (DynamicVGPRBlockSize != 0 &&
193 MaxVGPRs = std::min(MaxVGPRs, DynamicVGPRBlockSize);
198 if (!
F.hasFnAttribute(Attribute::AlwaysInline) &&
200 MaxVGPRs = std::min(MaxVGPRs, 32u);
206char AMDGPUPromoteAlloca::ID = 0;
209 "AMDGPU promote alloca to vector or LDS",
false,
false)
222 bool Changed = AMDGPUPromoteAllocaImpl(TM, *
F.getParent(), LI)
235 bool Changed = AMDGPUPromoteAllocaImpl(TM, *
F.getParent(), LI)
246 return new AMDGPUPromoteAlloca();
249bool AMDGPUPromoteAllocaImpl::collectAllocaUses(AllocaAnalysis &
AA)
const {
252 <<
" " << *Inst <<
"\n");
257 while (!WorkList.empty()) {
258 auto *Cur = WorkList.pop_back_val();
259 if (
find(
AA.Pointers, Cur) !=
AA.Pointers.end())
261 AA.Pointers.insert(Cur);
262 for (
auto &U : Cur->uses()) {
266 return RejectUser(Inst,
"pointer escapes via store");
269 AA.Uses.push_back(&U);
272 WorkList.push_back(Inst);
276 if (!binaryOpIsDerivedFromSameAlloca(
AA.Alloca, Cur,
SI, 1, 2))
277 return RejectUser(Inst,
"select from mixed objects");
278 WorkList.push_back(Inst);
279 AA.HaveSelectOrPHI =
true;
285 switch (
Phi->getNumIncomingValues()) {
289 if (!binaryOpIsDerivedFromSameAlloca(
AA.Alloca, Cur, Phi, 0, 1))
290 return RejectUser(Inst,
"phi from mixed objects");
293 return RejectUser(Inst,
"phi with too many operands");
296 WorkList.push_back(Inst);
297 AA.HaveSelectOrPHI =
true;
304void AMDGPUPromoteAllocaImpl::scoreAlloca(AllocaAnalysis &
AA)
const {
308 for (
auto *U :
AA.Uses) {
313 unsigned UserScore = 1 + (CLOpts.promote_alloca_vector_loop_user_weight *
315 LLVM_DEBUG(
dbgs() <<
" [+" << UserScore <<
"]:\t" << *Inst <<
"\n");
322void AMDGPUPromoteAllocaImpl::setFunctionLimits(
const Function &
F) {
326 const int R600MaxVectorRegs = 16;
327 MaxVectorRegs = CLOpts.promote_alloca_to_vector_max_regs.value_or(
328 F.getFnAttributeAsParsedInteger(
329 "amdgpu-promote-alloca-to-vector-max-regs",
330 IsAMDGCN ? 32 : R600MaxVectorRegs));
331 VGPRBudgetRatio = CLOpts.promote_alloca_to_vector_vgpr_ratio.value_or(
332 F.getFnAttributeAsParsedInteger(
333 "amdgpu-promote-alloca-to-vector-vgpr-ratio", 4));
336bool AMDGPUPromoteAllocaImpl::run(
Function &
F,
bool PromoteToLDS) {
337 if (!CLOpts.promote_alloca_to_lds && !CLOpts.promote_alloca_to_vector)
340 bool SufficientLDS = PromoteToLDS && hasSufficientLocalMem(
F);
341 MaxVGPRs = IsAMDGCN ? getMaxVGPRs(CurrentLocalMemUsage, TM,
F) : 128;
342 setFunctionLimits(
F);
344 unsigned VectorizationBudget =
345 (CLOpts.promote_alloca_to_vector_limit
346 ? CLOpts.promote_alloca_to_vector_limit * 8
350 std::vector<AllocaAnalysis> Allocas;
355 if (!AI->isStaticAlloca() || AI->isArrayAllocation())
360 AllocaAnalysis
AA{AI};
361 if (collectAllocaUses(
AA)) {
362 analyzePromoteToVector(
AA);
364 analyzePromoteToLDS(
AA);
365 if (
AA.Vector.Ty ||
AA.LDS.Enable) {
367 Allocas.push_back(std::move(
AA));
374 [](
const auto &
A,
const auto &
B) {
return A.Score >
B.Score; });
378 dbgs() <<
"Sorted Worklist:\n";
379 for (
const auto &
AA : Allocas)
380 dbgs() <<
" " << *
AA.Alloca <<
"\n";
386 for (AllocaAnalysis &
AA : Allocas) {
388 std::optional<TypeSize>
Size =
AA.Alloca->getAllocationSize(
DL);
390 const unsigned AllocaCost =
Size->getFixedValue() * 8;
392 if (AllocaCost <= VectorizationBudget) {
393 promoteAllocaToVector(
AA);
395 assert((VectorizationBudget - AllocaCost) < VectorizationBudget &&
397 VectorizationBudget -= AllocaCost;
399 << VectorizationBudget <<
"\n");
403 << AllocaCost <<
", budget:" << VectorizationBudget
404 <<
"): " << *
AA.Alloca <<
"\n");
409 tryPromoteAllocaToLDS(
AA, SufficientLDS, DeferredIntrs))
412 finishDeferredAllocaToLDSPromotion(DeferredIntrs);
434 return I->getOperand(0) == AI &&
442 if (Ptr ==
AA.Alloca)
443 return B.getInt32(0);
446 auto I =
AA.Vector.GEPVectorIdx.find(
GEP);
447 assert(
I !=
AA.Vector.GEPVectorIdx.end() &&
"Must have entry for GEP!");
449 if (!
I->second.Full) {
450 Value *Result =
nullptr;
451 B.SetInsertPoint(
GEP);
453 if (
I->second.VarIndex) {
454 Result =
I->second.VarIndex;
455 Result =
B.CreateSExtOrTrunc(Result,
B.getInt32Ty());
457 if (
I->second.VarMul)
458 Result =
B.CreateMul(Result,
I->second.VarMul);
460 if (
I->second.VarShift)
461 Result =
B.CreateAShr(Result,
I->second.VarShift,
"",
true);
464 if (
I->second.ConstIndex) {
466 Result =
B.CreateAdd(Result,
I->second.ConstIndex);
468 Result =
I->second.ConstIndex;
472 Result =
B.getInt32(0);
474 I->second.Full = Result;
477 return I->second.Full;
480static std::optional<GEPToVectorIndex>
486 unsigned BW =
DL.getIndexTypeSizeInBits(
GEP->getType());
488 APInt ConstOffset(BW, 0);
509 if (!CurGEP->collectOffset(
DL, BW, VarOffsets, ConstOffset))
513 CurPtr = CurGEP->getPointerOperand();
516 assert(CurPtr == Alloca &&
"GEP not based on alloca");
518 int64_t VecElemSize =
DL.getTypeAllocSize(VecElemTy);
519 if (VarOffsets.
size() > 1)
525 if (ConstOffset.
srem(VecElemSize) != 0)
527 APInt IndexQuot = ConstOffset.
sdiv(VecElemSize);
529 GEPToVectorIndex Result;
531 if (!ConstOffset.
isZero())
532 Result.ConstIndex = ConstantInt::get(Ctx, IndexQuot.
sextOrTrunc(BW));
535 if (VarOffsets.
empty())
540 const auto &VarOffset = VarOffsets.
front();
541 auto ScaleOpt = VarOffset.second.tryZExtValue();
542 if (!ScaleOpt || *ScaleOpt == 0)
546 Result.VarIndex = VarOffset.first;
552 if (Scale >= (
uint64_t)VecElemSize) {
553 if (Scale % VecElemSize != 0)
558 uint64_t VarMul = Scale / VecElemSize;
561 Result.VarMul = ConstantInt::get(Ctx,
APInt(BW, VarMul));
563 if ((
uint64_t)VecElemSize % Scale != 0)
568 uint64_t Divisor = VecElemSize / Scale;
578 Result.VarShift = ConstantInt::get(Ctx,
APInt(BW,
Log2_64(Divisor)));
599 unsigned VecStoreSize,
600 unsigned ElementSize,
607 Type *VecEltTy =
AA.Vector.Ty->getElementType();
610 case Instruction::Load: {
611 Value *CurVal = GetCurVal();
617 TypeSize AccessSize =
DL.getTypeStoreSize(AccessTy);
619 if (CI->isNullValue() && AccessSize == VecStoreSize) {
621 Builder.CreateBitPreservingCastChain(
DL, CurVal, AccessTy));
627 TypeSize EltSize =
DL.getTypeStoreSize(VecEltTy);
629 "promotable access must cover a whole number of elements");
630 const unsigned NumLoadedElts = AccessSize / EltSize;
631 if (NumLoadedElts > 1) {
644 bool IsAlignedLoad = NumBits <= (LoadAlign * 8u);
646 bool IsProperlyDivisible = TotalNumElts % NumLoadedElts == 0;
649 IsProperlyDivisible && IsAlignedLoad) {
651 const unsigned NewNumElts =
652 DL.getTypeStoreSize(VectorTy) * 8u / NumBits;
657 Builder.CreateBitPreservingCastChain(
DL, CurVal, BitCastTy);
658 Value *NewIdx = Builder.CreateLShr(
659 Index, ConstantInt::get(Index->getType(), LShrAmt));
660 Value *ExtVal = Builder.CreateExtractElement(BCVal, NewIdx);
662 Builder.CreateBitPreservingCastChain(
DL, ExtVal, AccessTy);
668 for (
unsigned K = 0;
K < NumLoadedElts; ++
K) {
670 Builder.CreateAdd(Index, ConstantInt::get(Index->getType(),
K));
671 SubVec = Builder.CreateInsertElement(
672 SubVec, Builder.CreateExtractElement(CurVal, CurIdx),
K);
676 Builder.CreateBitPreservingCastChain(
DL, SubVec, AccessTy));
681 Value *ExtractElement = Builder.CreateExtractElement(CurVal, Index);
682 if (AccessTy != VecEltTy)
683 ExtractElement = Builder.CreateBitOrPointerCast(ExtractElement, AccessTy);
688 case Instruction::Store: {
695 Value *Val =
SI->getValueOperand();
699 TypeSize AccessSize =
DL.getTypeStoreSize(AccessTy);
701 if (CI->isNullValue() && AccessSize == VecStoreSize) {
703 Builder.CreateBitPreservingCastChain(
DL, Val,
AA.Vector.Ty);
710 Result = Builder.CreateFreeze(Result);
716 TypeSize EltSize =
DL.getTypeStoreSize(VecEltTy);
718 "promotable access must cover a whole number of elements");
719 const unsigned NumWrittenElts = AccessSize / EltSize;
720 if (NumWrittenElts > 1) {
721 const unsigned NumVecElts =
AA.Vector.Ty->getNumElements();
725 Val = Builder.CreateBitPreservingCastChain(
DL, Val,
SubVecTy);
726 Value *CurVec = GetCurVal();
727 for (
unsigned K = 0, NumElts = std::min(NumWrittenElts, NumVecElts);
730 Builder.CreateAdd(Index, ConstantInt::get(Index->getType(),
K));
731 CurVec = Builder.CreateInsertElement(
732 CurVec, Builder.CreateExtractElement(Val,
K), CurIdx);
737 if (Val->
getType() != VecEltTy)
738 Val = Builder.CreateBitOrPointerCast(Val, VecEltTy);
739 return Builder.CreateInsertElement(GetCurVal(), Val, Index);
741 case Instruction::Call: {
745 unsigned NumCopied =
Length->getZExtValue() / ElementSize;
746 MemTransferInfo *TI = &
AA.Vector.TransferInfo[MTI];
751 for (
unsigned Idx = 0; Idx <
AA.Vector.Ty->getNumElements(); ++Idx) {
752 if (Idx >= DestBegin && Idx < DestBegin + NumCopied) {
753 Mask.push_back(SrcBegin < AA.Vector.Ty->getNumElements()
761 return Builder.CreateShuffleVector(GetCurVal(), Mask);
767 Value *Elt = MSI->getOperand(1);
768 const unsigned BytesPerElt =
DL.getTypeStoreSize(VecEltTy);
769 if (BytesPerElt > 1) {
770 Value *EltBytes = Builder.CreateVectorSplat(BytesPerElt, Elt);
776 Elt = Builder.CreateBitCast(EltBytes, PtrInt);
777 Elt = Builder.CreateIntToPtr(Elt, VecEltTy);
779 Elt = Builder.CreateBitCast(EltBytes, VecEltTy);
782 return Builder.CreateVectorSplat(
AA.Vector.Ty->getElementCount(), Elt);
786 if (Intr->getIntrinsicID() == Intrinsic::objectsize) {
787 Intr->replaceAllUsesWith(
788 Builder.getIntN(Intr->getType()->getIntegerBitWidth(),
789 DL.getTypeAllocSize(
AA.Vector.Ty)));
823 TypeSize AccTS =
DL.getTypeStoreSize(AccessTy);
828 if (AccTS * 8 ==
DL.getTypeSizeInBits(AccessTy) && AccTS > VecTS &&
840template <
typename InstContainer>
852 auto &BlockUses = UsesByBlock[BB];
855 if (BlockUses.empty())
859 if (BlockUses.size() == 1) {
866 if (!BlockUses.contains(&Inst))
891 NumElems *= ArrayTy->getNumElements();
892 Ty = ArrayTy->getElementType();
897 if (!StructTy || !StructTy->containsHomogeneousTypes())
900 NumElems *= StructTy->getNumElements();
901 Ty = StructTy->getElementType(0);
908AMDGPUPromoteAllocaImpl::getVectorTypeForAlloca(
Type *AllocaTy)
const {
909 if (!CLOpts.promote_alloca_to_vector) {
922 NumElems *= InnerVectorTy->getNumElements();
923 ElemTy = InnerVectorTy->getElementType();
927 unsigned ElementSize =
DL.getTypeSizeInBits(ElemTy) / 8;
928 if (ElementSize > 0) {
929 unsigned AllocaSize =
DL.getTypeStoreSize(AllocaTy);
934 if (NumElems * ElementSize != AllocaSize)
935 NumElems = AllocaSize / ElementSize;
936 if (NumElems > 0 && (AllocaSize % ElementSize) == 0)
946 const unsigned MaxElements =
947 (MaxVectorRegs * 32) /
DL.getTypeSizeInBits(VectorTy->getElementType());
949 if (VectorTy->getNumElements() > MaxElements ||
950 VectorTy->getNumElements() < 2) {
952 <<
" has an unsupported number of elements\n");
956 Type *VecEltTy = VectorTy->getElementType();
957 unsigned ElementSizeInBits =
DL.getTypeSizeInBits(VecEltTy);
958 if (ElementSizeInBits !=
DL.getTypeAllocSizeInBits(VecEltTy)) {
959 LLVM_DEBUG(
dbgs() <<
" Cannot convert to vector if the allocation size "
960 "does not match the type's size\n");
967void AMDGPUPromoteAllocaImpl::analyzePromoteToVector(AllocaAnalysis &
AA)
const {
968 if (
AA.HaveSelectOrPHI) {
969 LLVM_DEBUG(
dbgs() <<
" Cannot convert to vector due to select or phi\n");
973 Type *AllocaTy =
AA.Alloca->getAllocatedType();
974 AA.Vector.Ty = getVectorTypeForAlloca(AllocaTy);
980 <<
" " << *Inst <<
"\n");
981 AA.Vector.Ty =
nullptr;
984 Type *VecEltTy =
AA.Vector.Ty->getElementType();
985 unsigned ElementSize =
DL.getTypeSizeInBits(VecEltTy) / 8;
987 for (
auto *U :
AA.Uses) {
996 return RejectUser(Inst,
"unsupported load/store as aggregate");
1003 return RejectUser(Inst,
"not a simple load or store");
1005 Ptr = Ptr->stripPointerCasts();
1008 if (Ptr ==
AA.Alloca &&
1009 DL.getTypeStoreSize(
AA.Alloca->getAllocatedType()) ==
1010 DL.getTypeStoreSize(AccessTy)) {
1011 AA.Vector.Worklist.push_back(Inst);
1016 return RejectUser(Inst,
"not a supported access type");
1018 AA.Vector.Worklist.push_back(Inst);
1027 return RejectUser(Inst,
"cannot compute vector index for GEP");
1029 AA.Vector.GEPVectorIdx[
GEP] = std::move(
Index.value());
1030 AA.Vector.UsersToRemove.push_back(Inst);
1036 AA.Vector.Worklist.push_back(Inst);
1041 if (TransferInst->isVolatile())
1042 return RejectUser(Inst,
"mem transfer inst is volatile");
1045 if (!Len || (
Len->getZExtValue() % ElementSize))
1046 return RejectUser(Inst,
"mem transfer inst length is non-constant or "
1047 "not a multiple of the vector element size");
1050 if (Ptr ==
AA.Alloca)
1051 return ConstantInt::get(Ptr->getContext(),
APInt(32, 0));
1054 const auto &GEPI =
AA.Vector.GEPVectorIdx.find(
GEP)->second;
1057 if (GEPI.ConstIndex)
1058 return GEPI.ConstIndex;
1059 return ConstantInt::get(Ptr->getContext(),
APInt(32, 0));
1062 MemTransferInfo *TI =
1063 &
AA.Vector.TransferInfo.try_emplace(TransferInst).first->second;
1064 unsigned OpNum =
U->getOperandNo();
1066 Value *Dest = TransferInst->getDest();
1069 return RejectUser(Inst,
"could not calculate constant dest index");
1070 TI->DestIndex =
Index;
1073 Value *Src = TransferInst->getSource();
1076 return RejectUser(Inst,
"could not calculate constant src index");
1077 TI->SrcIndex =
Index;
1083 if (Intr->getIntrinsicID() == Intrinsic::objectsize) {
1084 AA.Vector.Worklist.push_back(Inst);
1092 return RejectUser(Inst,
"assume-like intrinsic cannot have any users");
1093 AA.Vector.UsersToRemove.push_back(Inst);
1098 return isAssumeLikeIntrinsic(cast<Instruction>(U));
1100 AA.Vector.UsersToRemove.push_back(Inst);
1104 return RejectUser(Inst,
"unhandled alloca user");
1108 for (
const auto &Entry :
AA.Vector.TransferInfo) {
1109 const MemTransferInfo &TI =
Entry.second;
1110 if (!TI.SrcIndex || !TI.DestIndex)
1111 return RejectUser(
Entry.first,
1112 "mem transfer inst between different objects");
1113 AA.Vector.Worklist.push_back(
Entry.first);
1117void AMDGPUPromoteAllocaImpl::promoteAllocaToVector(AllocaAnalysis &
AA) {
1119 LLVM_DEBUG(
dbgs() <<
" type conversion: " << *
AA.Alloca->getAllocatedType()
1120 <<
" -> " << *
AA.Vector.Ty <<
'\n');
1121 const unsigned VecStoreSize =
DL.getTypeStoreSize(
AA.Vector.Ty);
1123 Type *VecEltTy =
AA.Vector.Ty->getElementType();
1124 const unsigned ElementSize =
DL.getTypeSizeInBits(VecEltTy) / 8;
1146 BasicBlock *BB = I->getParent();
1147 auto GetCurVal = [&]() -> Value * {
1148 if (Value *CurVal = Updater.FindValueForBlock(BB))
1151 if (!Placeholders.empty() && Placeholders.back()->getParent() == BB)
1152 return Placeholders.back();
1156 IRBuilder<> Builder(I);
1157 auto *Placeholder = cast<Instruction>(Builder.CreateFreeze(
1158 PoisonValue::get(AA.Vector.Ty),
"promotealloca.placeholder"));
1159 Placeholders.insert(Placeholder);
1160 return Placeholders.back();
1164 ElementSize, GetCurVal);
1178 Placeholder->replaceAllUsesWith(
1180 Placeholder->eraseFromParent();
1186 I->eraseFromParent();
1191 I->dropDroppableUses();
1193 I->eraseFromParent();
1198 AA.Alloca->eraseFromParent();
1201std::pair<Value *, Value *>
1202AMDGPUPromoteAllocaImpl::getLocalSizeYZ(
IRBuilder<> &Builder) {
1208 Intrinsic::r600_read_local_size_y, {});
1210 Intrinsic::r600_read_local_size_z, {});
1212 ST.makeLIDRangeMetadata(LocalSizeY);
1213 ST.makeLIDRangeMetadata(LocalSizeZ);
1215 return std::pair(LocalSizeY, LocalSizeZ);
1256 F.removeFnAttr(
"amdgpu-no-dispatch-ptr");
1273 LoadXY->
setMetadata(LLVMContext::MD_invariant_load, MD);
1274 LoadZU->
setMetadata(LLVMContext::MD_invariant_load, MD);
1275 ST.makeLIDRangeMetadata(LoadZU);
1280 return std::pair(
Y, LoadZU);
1292 IntrID = IsAMDGCN ? (
Intrinsic::ID)Intrinsic::amdgcn_workitem_id_x
1294 AttrName =
"amdgpu-no-workitem-id-x";
1297 IntrID = IsAMDGCN ? (
Intrinsic::ID)Intrinsic::amdgcn_workitem_id_y
1299 AttrName =
"amdgpu-no-workitem-id-y";
1303 IntrID = IsAMDGCN ? (
Intrinsic::ID)Intrinsic::amdgcn_workitem_id_z
1305 AttrName =
"amdgpu-no-workitem-id-z";
1313 ST.makeLIDRangeMetadata(CI);
1314 F->removeFnAttr(AttrName);
1324 switch (
II->getIntrinsicID()) {
1325 case Intrinsic::memcpy:
1326 case Intrinsic::memmove:
1327 case Intrinsic::memset:
1328 case Intrinsic::lifetime_start:
1329 case Intrinsic::lifetime_end:
1330 case Intrinsic::invariant_start:
1331 case Intrinsic::invariant_end:
1332 case Intrinsic::launder_invariant_group:
1333 case Intrinsic::objectsize:
1340bool AMDGPUPromoteAllocaImpl::binaryOpIsDerivedFromSameAlloca(
1362 if (OtherObj != BaseAlloca) {
1364 dbgs() <<
"Found a binary instruction with another alloca object\n");
1371void AMDGPUPromoteAllocaImpl::analyzePromoteToLDS(AllocaAnalysis &
AA)
const {
1372 if (!CLOpts.promote_alloca_to_lds) {
1380 const Function &ContainingFunction = *
AA.Alloca->getFunction();
1390 <<
" promote alloca to LDS not supported with calling convention.\n");
1401 if (
find(
AA.LDS.Worklist,
User) ==
AA.LDS.Worklist.end())
1402 AA.LDS.Worklist.push_back(
User);
1407 if (UseInst->
getOpcode() == Instruction::PtrToInt)
1411 if (LI->isVolatile())
1417 if (
SI->isVolatile())
1423 if (RMW->isVolatile())
1429 if (CAS->isVolatile())
1437 if (!binaryOpIsDerivedFromSameAlloca(
AA.Alloca,
Use->get(), ICmp, 0, 1))
1441 if (
find(
AA.LDS.Worklist,
User) ==
AA.LDS.Worklist.end())
1442 AA.LDS.Worklist.push_back(ICmp);
1449 if (!
GEP->isInBounds())
1462 if (
find(
AA.LDS.Worklist,
User) ==
AA.LDS.Worklist.end())
1463 AA.LDS.Worklist.push_back(
User);
1466 AA.LDS.Enable =
true;
1469bool AMDGPUPromoteAllocaImpl::hasSufficientLocalMem(
const Function &
F) {
1477 for (
Type *ParamTy : FTy->params()) {
1481 LLVM_DEBUG(
dbgs() <<
"Function has local memory argument. Promoting to "
1482 "local memory disabled.\n");
1487 LocalMemLimit =
ST.getAddressableLocalMemorySize();
1488 if (LocalMemLimit == 0)
1498 if (
Use->getFunction() == &
F)
1502 if (VisitedConstants.
insert(
C).second)
1514 if (visitUsers(&GV, &GV)) {
1522 while (!
Stack.empty()) {
1524 if (visitUsers(&GV,
C)) {
1544 LLVM_DEBUG(
dbgs() <<
"Function has a reference to externally allocated "
1545 "local memory. Promoting to local memory "
1560 CurrentLocalMemUsage = 0;
1566 for (
auto Alloc : AllocatedSizes) {
1567 CurrentLocalMemUsage =
alignTo(CurrentLocalMemUsage,
Alloc.second);
1568 CurrentLocalMemUsage +=
Alloc.first;
1571 unsigned MaxOccupancy =
1572 ST.getWavesPerEU(
ST.getFlatWorkGroupSizes(
F), CurrentLocalMemUsage,
F)
1576 unsigned MaxSizeWithWaveCount =
1577 ST.getMaxLocalMemSizeWithWaveCount(MaxOccupancy,
F);
1580 if (CurrentLocalMemUsage > MaxSizeWithWaveCount)
1583 LocalMemLimit = MaxSizeWithWaveCount;
1586 <<
" bytes of LDS\n"
1587 <<
" Rounding size to " << MaxSizeWithWaveCount
1588 <<
" with a maximum occupancy of " << MaxOccupancy <<
'\n'
1589 <<
" and " << (LocalMemLimit - CurrentLocalMemUsage)
1590 <<
" available for promotion\n");
1596bool AMDGPUPromoteAllocaImpl::tryPromoteAllocaToLDS(
1597 AllocaAnalysis &
AA,
bool SufficientLDS,
1607 const Function &ContainingFunction = *
AA.Alloca->getParent()->getParent();
1609 unsigned WorkGroupSize =
ST.getFlatWorkGroupSizes(ContainingFunction).second;
1619 uint32_t NewSize =
alignTo(CurrentLocalMemUsage, Alignment);
1620 std::optional<TypeSize> ElemSize =
AA.Alloca->getAllocationSize(
DL);
1621 if (!ElemSize || ElemSize->isScalable())
1623 TypeSize AllocSize = WorkGroupSize * *ElemSize;
1626 if (NewSize > LocalMemLimit) {
1628 <<
" bytes of local memory not available to promote\n");
1632 CurrentLocalMemUsage = NewSize;
1641 Twine(
F->getName()) +
Twine(
'.') +
AA.Alloca->getName(),
nullptr,
1646 Value *TCntY, *TCntZ;
1648 std::tie(TCntY, TCntZ) = getLocalSizeYZ(Builder);
1649 Value *TIdX = getWorkitemID(Builder, 0);
1650 Value *TIdY = getWorkitemID(Builder, 1);
1651 Value *TIdZ = getWorkitemID(Builder, 2);
1663 AA.Alloca->mutateType(
Offset->getType());
1664 AA.Alloca->replaceAllUsesWith(
Offset);
1665 AA.Alloca->eraseFromParent();
1691 assert(
V->getType()->isPtrOrPtrVectorTy());
1694 V->mutateType(NewTy);
1704 for (
unsigned I = 0,
E =
Phi->getNumIncomingValues();
I !=
E; ++
I) {
1706 Phi->getIncomingValue(
I)))
1717 case Intrinsic::lifetime_start:
1718 case Intrinsic::lifetime_end:
1722 case Intrinsic::memcpy:
1723 case Intrinsic::memmove:
1727 DeferredIntrs.
insert(Intr);
1729 case Intrinsic::memset: {
1737 case Intrinsic::invariant_start:
1738 case Intrinsic::invariant_end:
1739 case Intrinsic::launder_invariant_group: {
1741 "pointer operand should already have been promoted");
1748 case Intrinsic::objectsize: {
1752 Intrinsic::objectsize,
1768void AMDGPUPromoteAllocaImpl::finishDeferredAllocaToLDSPromotion(
1775 assert(ID == Intrinsic::memcpy || ID == Intrinsic::memmove);
1779 ID,
MI->getRawDest(),
MI->getDestAlign(),
MI->getRawSource(),
1780 MI->getSourceAlign(),
MI->getLength(),
MI->isVolatile());
1782 for (
unsigned I = 0;
I != 2; ++
I) {
1784 B->addDereferenceableParamAttr(
I, Bytes);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool runOnFunction(Function &F, bool PostInlining)
AMD GCN specific subclass of TargetSubtarget.
uint64_t IntrinsicInst * II
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Remove Loads Into Fake Uses
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
Target-Independent Code Generator Pass Configuration Options pass.
static const AMDGPUSubtarget & get(const MachineFunction &MF)
Class for arbitrary precision integers.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt sdiv(const APInt &RHS) const
Signed division function for APInt.
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
LLVM_ABI APInt srem(const APInt &RHS) const
Function for signed remainder operation.
an instruction to allocate memory on the stack
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
An instruction that atomically checks whether a specified value is in a memory location,...
an instruction that atomically reads a memory location, combines it with another value,...
LLVM Basic Block Representation.
const Function * getParent() const
Return the enclosing method, or null if none.
InstListType::iterator iterator
Instruction iterators...
Represents analyses that only rely on functions' control flow.
uint64_t getParamDereferenceableBytes(unsigned i) const
Extract the number of dereferenceable bytes for a call or parameter (0=unknown).
void addDereferenceableRetAttr(uint64_t Bytes)
adds the dereferenceable attribute to the list of attributes.
void addRetAttr(Attribute::AttrKind Kind)
Adds the attribute to the return value.
Value * getArgOperand(unsigned i) const
unsigned arg_size() const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI bool isBitOrNoopPointerCastable(Type *SrcTy, Type *DestTy, const DataLayout &DL)
Check whether a bitcast, inttoptr, or ptrtoint cast between these types is valid and a no-op.
This is the shared class of boolean and integer constants.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
This is an important base class in LLVM.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Implements a dense probed hash-table based set.
Class to represent fixed width SIMD vectors.
unsigned getNumElements() const
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
FunctionPass class - This class is used to implement most global optimizations.
Class to represent function types.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Type * getReturnType() const
Returns the type of the ret val.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
bool hasExternalLinkage() const
void setUnnamedAddr(UnnamedAddr Val)
unsigned getAddressSpace() const
@ InternalLinkage
Rename collisions when linking (static functions).
Type * getValueType() const
MaybeAlign getAlign() const
Returns the alignment of the given variable.
LLVM_ABI uint64_t getGlobalSize(const DataLayout &DL) const
Get the size of this global variable in bytes.
void setAlignment(Align Align)
Sets the alignment attribute of the GlobalVariable.
This instruction compares its operands according to the predicate given to the constructor.
LLVM_ABI CallInst * CreateIntrinsicWithoutFolding(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={})
Create a call to intrinsic ID with Args, mangled using OverloadTypes.
LoadInst * CreateAlignedLoad(Type *Ty, Value *Ptr, MaybeAlign Align, const char *Name)
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
BasicBlock * GetInsertBlock() const
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
CallInst * CreateMemSet(Value *Ptr, Value *Val, uint64_t Size, MaybeAlign Align, bool isVolatile=false, const AAMDNodes &AAInfo=AAMDNodes())
Create and insert a memset to the specified pointer and the specified value.
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateConstInBoundsGEP1_64(Type *Ty, Value *Ptr, uint64_t Idx0, const Twine &Name="")
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
LLVM_ABI CallInst * CreateMemTransferInst(Intrinsic::ID IntrID, Value *Dst, MaybeAlign DstAlign, Value *Src, MaybeAlign SrcAlign, Value *Size, bool isVolatile=false, const AAMDNodes &AAInfo=AAMDNodes())
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
InstSimplifyFolder - Use InstructionSimplify to fold operations to existing values.
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 InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
iterator_range< user_iterator > users()
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
Class to represent integer types.
A wrapper class for inspecting calls to intrinsic functions.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
Analysis pass that exposes the LoopInfo for a function.
The legacy pass manager's analysis pass to compute loop information.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
This class implements a map that also provides access to all stored values in a deterministic order.
std::pair< KeyT, ValueT > & front()
Value * getLength() const
Value * getRawDest() const
MaybeAlign getDestAlign() const
This class wraps the llvm.memset and llvm.memset.inline intrinsics.
This class wraps the llvm.memcpy/memmove intrinsics.
A Module instance is used to store all the information related to an LLVM module.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Class to represent pointers.
static LLVM_ABI PointerType * get(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
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.
Helper class for SSA formation on a set of values defined in multiple blocks.
LLVM_ABI void Initialize(Type *Ty, StringRef Name)
Reset this object to get ready for a new set of SSA updates with type 'Ty'.
LLVM_ABI Value * GetValueInMiddleOfBlock(BasicBlock *BB)
Construct SSA form, materializing a value that is live in the middle of the specified block.
LLVM_ABI void AddAvailableValue(BasicBlock *BB, Value *V)
Indicate that a rewritten value is available in the specified block with the specified value.
This class represents the LLVM 'select' instruction.
A vector that has set insertion semantics.
bool contains(const_arg_type key) const
Check if the SetVector contains the given key.
bool insert(const value_type &X)
Insert a new element into the SetVector.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static unsigned getPointerOperandIndex()
Represent a constant reference to a string, i.e.
Primary interface to the complete machine description for the target machine.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
Triple - Helper class for working with autoconf configuration names.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
bool isArrayTy() const
True if this is an instance of ArrayType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
bool isAggregateType() const
Return true if the type is an aggregate type.
LLVM_ABI Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
A Use represents the edge between a Value definition and its users.
void setOperand(unsigned i, Value *Val)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
void mutateType(Type *Ty)
Mutate the type of this Value to be of the specified type.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
Type * getElementType() const
Value handle that is nullable, but tries to track the Value.
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
constexpr ScalarTy getFixedValue() const
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
@ LOCAL_ADDRESS
Address space for local memory.
LLVM_READNONE constexpr bool isEntryFunctionCC(CallingConv::ID CC)
unsigned getDynamicVGPRBlockSize(const Function &F)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
@ SPIR_KERNEL
Used for SPIR kernel functions.
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
bool match(Val *V, const Pattern &P)
NodeAddr< PhiNode * > Phi
This is an optimization pass for GlobalISel generic memory operations.
void stable_sort(R &&Range)
auto find(R &&Range, const T &Val)
Provide wrappers to std::find 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.
LLVM_ABI bool isAssumeLikeIntrinsic(const Instruction *I)
Return true if it is an intrinsic that cannot be speculated but also cannot trap.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Determine which bits of V are known to be either zero or one and return them in the KnownZero/KnownOn...
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
auto reverse(ContainerTy &&C)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth, bool MustPreserveProvenance=false)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
constexpr int PoisonMaskElem
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
FunctionPass * createAMDGPUPromoteAlloca()
@ Mod
The access may modify the value stored in memory.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
char & AMDGPUPromoteAllocaID
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
This struct is a compact representation of a valid (non-zero power of two) alignment.
unsigned countMinTrailingZeros() const
Returns the minimum number of trailing zero bits.
A MapVector that performs no allocations if smaller than a certain size.
Function object to check whether the second component of a container supported by std::get (like std:...