40#include "llvm/IR/IntrinsicsAMDGPU.h"
41#include "llvm/IR/IntrinsicsR600.h"
49#define DEBUG_TYPE "amdgpu-promote-alloca"
56 DisablePromoteAllocaToVector(
"disable-promote-alloca-to-vector",
57 cl::desc(
"Disable promote alloca to vector"),
61 DisablePromoteAllocaToLDS(
"disable-promote-alloca-to-lds",
62 cl::desc(
"Disable promote alloca to LDS"),
66 "amdgpu-promote-alloca-to-vector-limit",
67 cl::desc(
"Maximum byte size to consider promote alloca to vector"),
71 "amdgpu-promote-alloca-to-vector-max-regs",
73 "Maximum vector size (in 32b registers) to use when promoting alloca"),
79 "amdgpu-promote-alloca-to-vector-vgpr-ratio",
80 cl::desc(
"Ratio of VGPRs to budget for promoting alloca to vectors"),
84 LoopUserWeight(
"promote-alloca-vector-loop-user-weight",
85 cl::desc(
"The bonus weight of users of allocas within loop "
86 "when sorting profitable allocas"),
92struct GEPToVectorIndex {
100struct MemTransferInfo {
106struct AllocaAnalysis {
111 bool HaveSelectOrPHI =
false;
124 explicit AllocaAnalysis(
AllocaInst *Alloca) : Alloca(Alloca) {}
128class AMDGPUPromoteAllocaImpl {
139 unsigned VGPRBudgetRatio;
140 unsigned MaxVectorRegs;
142 bool IsAMDGCN =
false;
143 bool IsAMDHSA =
false;
145 std::pair<Value *, Value *> getLocalSizeYZ(
IRBuilder<> &Builder);
148 bool collectAllocaUses(AllocaAnalysis &
AA)
const;
154 bool binaryOpIsDerivedFromSameAlloca(
Value *Alloca,
Value *Val,
159 bool hasSufficientLocalMem(
const Function &
F);
162 void analyzePromoteToVector(AllocaAnalysis &
AA)
const;
163 void promoteAllocaToVector(AllocaAnalysis &
AA);
164 void analyzePromoteToLDS(AllocaAnalysis &
AA)
const;
165 bool tryPromoteAllocaToLDS(AllocaAnalysis &
AA,
bool SufficientLDS,
170 void scoreAlloca(AllocaAnalysis &
AA)
const;
172 void setFunctionLimits(
const Function &
F);
176 : TM(TM), LI(LI),
Mod(M),
DL(M.getDataLayout()) {
177 const Triple &TT = M.getTargetTriple();
178 IsAMDGCN = TT.isAMDGCN();
182 bool run(
Function &
F,
bool PromoteToLDS);
195 if (
auto *TPC = getAnalysisIfAvailable<TargetPassConfig>())
196 return AMDGPUPromoteAllocaImpl(
198 getAnalysis<LoopInfoWrapperPass>().getLoopInfo())
203 StringRef getPassName()
const override {
return "AMDGPU Promote Alloca"; }
212static unsigned getMaxVGPRs(
unsigned LDSBytes,
const TargetMachine &TM,
217 unsigned MaxVGPRs = ST.getMaxNumVGPRs(
218 ST.getWavesPerEU(ST.getFlatWorkGroupSizes(
F), LDSBytes,
F).first,
219 DynamicVGPRBlockSize);
224 if (!
F.hasFnAttribute(Attribute::AlwaysInline) &&
226 MaxVGPRs = std::min(MaxVGPRs, 32u);
232char AMDGPUPromoteAlloca::ID = 0;
235 "AMDGPU promote alloca to vector or LDS",
false,
false)
248 bool Changed = AMDGPUPromoteAllocaImpl(TM, *
F.getParent(), LI)
261 bool Changed = AMDGPUPromoteAllocaImpl(TM, *
F.getParent(), LI)
272 return new AMDGPUPromoteAlloca();
275bool AMDGPUPromoteAllocaImpl::collectAllocaUses(AllocaAnalysis &
AA)
const {
278 <<
" " << *Inst <<
"\n");
283 while (!WorkList.empty()) {
284 auto *Cur = WorkList.pop_back_val();
285 if (
find(
AA.Pointers, Cur) !=
AA.Pointers.end())
287 AA.Pointers.insert(Cur);
288 for (
auto &U : Cur->uses()) {
292 return RejectUser(Inst,
"pointer escapes via store");
295 AA.Uses.push_back(&U);
298 WorkList.push_back(Inst);
302 if (!binaryOpIsDerivedFromSameAlloca(
AA.Alloca, Cur,
SI, 1, 2))
303 return RejectUser(Inst,
"select from mixed objects");
304 WorkList.push_back(Inst);
305 AA.HaveSelectOrPHI =
true;
311 switch (
Phi->getNumIncomingValues()) {
315 if (!binaryOpIsDerivedFromSameAlloca(
AA.Alloca, Cur, Phi, 0, 1))
316 return RejectUser(Inst,
"phi from mixed objects");
319 return RejectUser(Inst,
"phi with too many operands");
322 WorkList.push_back(Inst);
323 AA.HaveSelectOrPHI =
true;
330void AMDGPUPromoteAllocaImpl::scoreAlloca(AllocaAnalysis &
AA)
const {
334 for (
auto *U :
AA.Uses) {
340 1 + (LoopUserWeight * LI.getLoopDepth(Inst->
getParent()));
341 LLVM_DEBUG(
dbgs() <<
" [+" << UserScore <<
"]:\t" << *Inst <<
"\n");
348void AMDGPUPromoteAllocaImpl::setFunctionLimits(
const Function &
F) {
352 const int R600MaxVectorRegs = 16;
353 MaxVectorRegs =
F.getFnAttributeAsParsedInteger(
354 "amdgpu-promote-alloca-to-vector-max-regs",
355 IsAMDGCN ? PromoteAllocaToVectorMaxRegs : R600MaxVectorRegs);
356 if (PromoteAllocaToVectorMaxRegs.getNumOccurrences())
357 MaxVectorRegs = PromoteAllocaToVectorMaxRegs;
358 VGPRBudgetRatio =
F.getFnAttributeAsParsedInteger(
359 "amdgpu-promote-alloca-to-vector-vgpr-ratio",
360 PromoteAllocaToVectorVGPRRatio);
361 if (PromoteAllocaToVectorVGPRRatio.getNumOccurrences())
362 VGPRBudgetRatio = PromoteAllocaToVectorVGPRRatio;
365bool AMDGPUPromoteAllocaImpl::run(
Function &
F,
bool PromoteToLDS) {
366 if (DisablePromoteAllocaToLDS && DisablePromoteAllocaToVector)
369 bool SufficientLDS = PromoteToLDS && hasSufficientLocalMem(
F);
370 MaxVGPRs = IsAMDGCN ? getMaxVGPRs(CurrentLocalMemUsage, TM,
F) : 128;
371 setFunctionLimits(
F);
373 unsigned VectorizationBudget =
374 (PromoteAllocaToVectorLimit ? PromoteAllocaToVectorLimit * 8
378 std::vector<AllocaAnalysis> Allocas;
383 if (!AI->isStaticAlloca() || AI->isArrayAllocation())
388 AllocaAnalysis
AA{AI};
389 if (collectAllocaUses(
AA)) {
390 analyzePromoteToVector(
AA);
392 analyzePromoteToLDS(
AA);
393 if (
AA.Vector.Ty ||
AA.LDS.Enable) {
395 Allocas.push_back(std::move(
AA));
402 [](
const auto &
A,
const auto &
B) {
return A.Score >
B.Score; });
406 dbgs() <<
"Sorted Worklist:\n";
407 for (
const auto &
AA : Allocas)
408 dbgs() <<
" " << *
AA.Alloca <<
"\n";
414 for (AllocaAnalysis &
AA : Allocas) {
416 std::optional<TypeSize>
Size =
AA.Alloca->getAllocationSize(
DL);
418 const unsigned AllocaCost =
Size->getFixedValue() * 8;
420 if (AllocaCost <= VectorizationBudget) {
421 promoteAllocaToVector(
AA);
423 assert((VectorizationBudget - AllocaCost) < VectorizationBudget &&
425 VectorizationBudget -= AllocaCost;
427 << VectorizationBudget <<
"\n");
431 << AllocaCost <<
", budget:" << VectorizationBudget
432 <<
"): " << *
AA.Alloca <<
"\n");
437 tryPromoteAllocaToLDS(
AA, SufficientLDS, DeferredIntrs))
440 finishDeferredAllocaToLDSPromotion(DeferredIntrs);
462 return I->getOperand(0) == AI &&
470 if (Ptr ==
AA.Alloca)
471 return B.getInt32(0);
474 auto I =
AA.Vector.GEPVectorIdx.find(
GEP);
475 assert(
I !=
AA.Vector.GEPVectorIdx.end() &&
"Must have entry for GEP!");
477 if (!
I->second.Full) {
478 Value *Result =
nullptr;
479 B.SetInsertPoint(
GEP);
481 if (
I->second.VarIndex) {
482 Result =
I->second.VarIndex;
483 Result =
B.CreateSExtOrTrunc(Result,
B.getInt32Ty());
485 if (
I->second.VarMul)
486 Result =
B.CreateMul(Result,
I->second.VarMul);
488 if (
I->second.VarShift)
489 Result =
B.CreateAShr(Result,
I->second.VarShift,
"",
true);
492 if (
I->second.ConstIndex) {
494 Result =
B.CreateAdd(Result,
I->second.ConstIndex);
496 Result =
I->second.ConstIndex;
500 Result =
B.getInt32(0);
502 I->second.Full = Result;
505 return I->second.Full;
508static std::optional<GEPToVectorIndex>
514 unsigned BW =
DL.getIndexTypeSizeInBits(
GEP->getType());
516 APInt ConstOffset(BW, 0);
537 if (!CurGEP->collectOffset(
DL, BW, VarOffsets, ConstOffset))
541 CurPtr = CurGEP->getPointerOperand();
544 assert(CurPtr == Alloca &&
"GEP not based on alloca");
546 int64_t VecElemSize =
DL.getTypeAllocSize(VecElemTy);
547 if (VarOffsets.
size() > 1)
553 if (ConstOffset.
srem(VecElemSize) != 0)
555 APInt IndexQuot = ConstOffset.
sdiv(VecElemSize);
557 GEPToVectorIndex Result;
559 if (!ConstOffset.
isZero())
560 Result.ConstIndex = ConstantInt::get(Ctx, IndexQuot.
sextOrTrunc(BW));
563 if (VarOffsets.
empty())
568 const auto &VarOffset = VarOffsets.
front();
569 auto ScaleOpt = VarOffset.second.tryZExtValue();
570 if (!ScaleOpt || *ScaleOpt == 0)
574 Result.VarIndex = VarOffset.first;
580 if (Scale >= (
uint64_t)VecElemSize) {
581 if (Scale % VecElemSize != 0)
586 uint64_t VarMul = Scale / VecElemSize;
589 Result.VarMul = ConstantInt::get(Ctx,
APInt(BW, VarMul));
591 if ((
uint64_t)VecElemSize % Scale != 0)
596 uint64_t Divisor = VecElemSize / Scale;
606 Result.VarShift = ConstantInt::get(Ctx,
APInt(BW,
Log2_64(Divisor)));
627 unsigned VecStoreSize,
628 unsigned ElementSize,
634 Builder.SetInsertPoint(Inst);
636 Type *VecEltTy =
AA.Vector.Ty->getElementType();
639 case Instruction::Load: {
640 Value *CurVal = GetCurVal();
646 TypeSize AccessSize =
DL.getTypeStoreSize(AccessTy);
648 if (CI->isNullValue() && AccessSize == VecStoreSize) {
650 Builder.CreateBitPreservingCastChain(
DL, CurVal, AccessTy));
656 TypeSize EltSize =
DL.getTypeStoreSize(VecEltTy);
658 "promotable access must cover a whole number of elements");
659 const unsigned NumLoadedElts = AccessSize / EltSize;
660 if (NumLoadedElts > 1) {
662 assert(
DL.getTypeStoreSize(SubVecTy) ==
DL.getTypeStoreSize(AccessTy));
671 TypeSize NumBits =
DL.getTypeStoreSize(SubVecTy) * 8u;
673 bool IsAlignedLoad = NumBits <= (LoadAlign * 8u);
675 bool IsProperlyDivisible = TotalNumElts % NumLoadedElts == 0;
678 IsProperlyDivisible && IsAlignedLoad) {
680 const unsigned NewNumElts =
681 DL.getTypeStoreSize(VectorTy) * 8u / NumBits;
682 const unsigned LShrAmt =
llvm::Log2_32(SubVecTy->getNumElements());
686 Builder.CreateBitPreservingCastChain(
DL, CurVal, BitCastTy);
687 Value *NewIdx = Builder.CreateLShr(
688 Index, ConstantInt::get(Index->getType(), LShrAmt));
689 Value *ExtVal = Builder.CreateExtractElement(BCVal, NewIdx);
691 Builder.CreateBitPreservingCastChain(
DL, ExtVal, AccessTy);
697 for (
unsigned K = 0;
K < NumLoadedElts; ++
K) {
699 Builder.CreateAdd(Index, ConstantInt::get(Index->getType(),
K));
700 SubVec = Builder.CreateInsertElement(
701 SubVec, Builder.CreateExtractElement(CurVal, CurIdx),
K);
705 Builder.CreateBitPreservingCastChain(
DL, SubVec, AccessTy));
710 Value *ExtractElement = Builder.CreateExtractElement(CurVal, Index);
711 if (AccessTy != VecEltTy)
712 ExtractElement = Builder.CreateBitOrPointerCast(ExtractElement, AccessTy);
717 case Instruction::Store: {
724 Value *Val =
SI->getValueOperand();
728 TypeSize AccessSize =
DL.getTypeStoreSize(AccessTy);
730 if (CI->isNullValue() && AccessSize == VecStoreSize) {
732 Builder.CreateBitPreservingCastChain(
DL, Val,
AA.Vector.Ty);
739 Result = Builder.CreateFreeze(Result);
745 TypeSize EltSize =
DL.getTypeStoreSize(VecEltTy);
747 "promotable access must cover a whole number of elements");
748 const unsigned NumWrittenElts = AccessSize / EltSize;
749 if (NumWrittenElts > 1) {
750 const unsigned NumVecElts =
AA.Vector.Ty->getNumElements();
752 assert(
DL.getTypeStoreSize(SubVecTy) ==
DL.getTypeStoreSize(AccessTy));
754 Val = Builder.CreateBitPreservingCastChain(
DL, Val, SubVecTy);
755 Value *CurVec = GetCurVal();
756 for (
unsigned K = 0, NumElts = std::min(NumWrittenElts, NumVecElts);
759 Builder.CreateAdd(Index, ConstantInt::get(Index->getType(),
K));
760 CurVec = Builder.CreateInsertElement(
761 CurVec, Builder.CreateExtractElement(Val,
K), CurIdx);
766 if (Val->
getType() != VecEltTy)
767 Val = Builder.CreateBitOrPointerCast(Val, VecEltTy);
768 return Builder.CreateInsertElement(GetCurVal(), Val, Index);
770 case Instruction::Call: {
774 unsigned NumCopied =
Length->getZExtValue() / ElementSize;
775 MemTransferInfo *TI = &
AA.Vector.TransferInfo[MTI];
780 for (
unsigned Idx = 0; Idx <
AA.Vector.Ty->getNumElements(); ++Idx) {
781 if (Idx >= DestBegin && Idx < DestBegin + NumCopied) {
782 Mask.push_back(SrcBegin < AA.Vector.Ty->getNumElements()
790 return Builder.CreateShuffleVector(GetCurVal(), Mask);
796 Value *Elt = MSI->getOperand(1);
797 const unsigned BytesPerElt =
DL.getTypeStoreSize(VecEltTy);
798 if (BytesPerElt > 1) {
799 Value *EltBytes = Builder.CreateVectorSplat(BytesPerElt, Elt);
805 Elt = Builder.CreateBitCast(EltBytes, PtrInt);
806 Elt = Builder.CreateIntToPtr(Elt, VecEltTy);
808 Elt = Builder.CreateBitCast(EltBytes, VecEltTy);
811 return Builder.CreateVectorSplat(
AA.Vector.Ty->getElementCount(), Elt);
815 if (Intr->getIntrinsicID() == Intrinsic::objectsize) {
816 Intr->replaceAllUsesWith(
817 Builder.getIntN(Intr->getType()->getIntegerBitWidth(),
818 DL.getTypeAllocSize(
AA.Vector.Ty)));
852 TypeSize AccTS =
DL.getTypeStoreSize(AccessTy);
857 if (AccTS * 8 ==
DL.getTypeSizeInBits(AccessTy) && AccTS > VecTS &&
869template <
typename InstContainer>
881 auto &BlockUses = UsesByBlock[BB];
884 if (BlockUses.empty())
888 if (BlockUses.size() == 1) {
895 if (!BlockUses.contains(&Inst))
916AMDGPUPromoteAllocaImpl::getVectorTypeForAlloca(
Type *AllocaTy)
const {
917 if (DisablePromoteAllocaToVector) {
927 NumElems *= ArrayTy->getNumElements();
928 ElemTy = ArrayTy->getElementType();
934 NumElems *= InnerVectorTy->getNumElements();
935 ElemTy = InnerVectorTy->getElementType();
939 unsigned ElementSize =
DL.getTypeSizeInBits(ElemTy) / 8;
940 if (ElementSize > 0) {
941 unsigned AllocaSize =
DL.getTypeStoreSize(AllocaTy);
946 if (NumElems * ElementSize != AllocaSize)
947 NumElems = AllocaSize / ElementSize;
948 if (NumElems > 0 && (AllocaSize % ElementSize) == 0)
958 const unsigned MaxElements =
959 (MaxVectorRegs * 32) /
DL.getTypeSizeInBits(VectorTy->getElementType());
961 if (VectorTy->getNumElements() > MaxElements ||
962 VectorTy->getNumElements() < 2) {
964 <<
" has an unsupported number of elements\n");
968 Type *VecEltTy = VectorTy->getElementType();
969 unsigned ElementSizeInBits =
DL.getTypeSizeInBits(VecEltTy);
970 if (ElementSizeInBits !=
DL.getTypeAllocSizeInBits(VecEltTy)) {
971 LLVM_DEBUG(
dbgs() <<
" Cannot convert to vector if the allocation size "
972 "does not match the type's size\n");
979void AMDGPUPromoteAllocaImpl::analyzePromoteToVector(AllocaAnalysis &
AA)
const {
980 if (
AA.HaveSelectOrPHI) {
981 LLVM_DEBUG(
dbgs() <<
" Cannot convert to vector due to select or phi\n");
985 Type *AllocaTy =
AA.Alloca->getAllocatedType();
986 AA.Vector.Ty = getVectorTypeForAlloca(AllocaTy);
992 <<
" " << *Inst <<
"\n");
993 AA.Vector.Ty =
nullptr;
996 Type *VecEltTy =
AA.Vector.Ty->getElementType();
997 unsigned ElementSize =
DL.getTypeSizeInBits(VecEltTy) / 8;
999 for (
auto *U :
AA.Uses) {
1008 return RejectUser(Inst,
"unsupported load/store as aggregate");
1015 return RejectUser(Inst,
"not a simple load or store");
1017 Ptr = Ptr->stripPointerCasts();
1020 if (Ptr ==
AA.Alloca &&
1021 DL.getTypeStoreSize(
AA.Alloca->getAllocatedType()) ==
1022 DL.getTypeStoreSize(AccessTy)) {
1023 AA.Vector.Worklist.push_back(Inst);
1028 return RejectUser(Inst,
"not a supported access type");
1030 AA.Vector.Worklist.push_back(Inst);
1039 return RejectUser(Inst,
"cannot compute vector index for GEP");
1041 AA.Vector.GEPVectorIdx[
GEP] = std::move(
Index.value());
1042 AA.Vector.UsersToRemove.push_back(Inst);
1048 AA.Vector.Worklist.push_back(Inst);
1053 if (TransferInst->isVolatile())
1054 return RejectUser(Inst,
"mem transfer inst is volatile");
1057 if (!Len || (
Len->getZExtValue() % ElementSize))
1058 return RejectUser(Inst,
"mem transfer inst length is non-constant or "
1059 "not a multiple of the vector element size");
1062 if (Ptr ==
AA.Alloca)
1063 return ConstantInt::get(Ptr->getContext(),
APInt(32, 0));
1066 const auto &GEPI =
AA.Vector.GEPVectorIdx.find(
GEP)->second;
1069 if (GEPI.ConstIndex)
1070 return GEPI.ConstIndex;
1071 return ConstantInt::get(Ptr->getContext(),
APInt(32, 0));
1074 MemTransferInfo *TI =
1075 &
AA.Vector.TransferInfo.try_emplace(TransferInst).first->second;
1076 unsigned OpNum =
U->getOperandNo();
1078 Value *Dest = TransferInst->getDest();
1081 return RejectUser(Inst,
"could not calculate constant dest index");
1082 TI->DestIndex =
Index;
1085 Value *Src = TransferInst->getSource();
1088 return RejectUser(Inst,
"could not calculate constant src index");
1089 TI->SrcIndex =
Index;
1095 if (Intr->getIntrinsicID() == Intrinsic::objectsize) {
1096 AA.Vector.Worklist.push_back(Inst);
1104 return RejectUser(Inst,
"assume-like intrinsic cannot have any users");
1105 AA.Vector.UsersToRemove.push_back(Inst);
1110 return isAssumeLikeIntrinsic(cast<Instruction>(U));
1112 AA.Vector.UsersToRemove.push_back(Inst);
1116 return RejectUser(Inst,
"unhandled alloca user");
1120 for (
const auto &Entry :
AA.Vector.TransferInfo) {
1121 const MemTransferInfo &TI =
Entry.second;
1122 if (!TI.SrcIndex || !TI.DestIndex)
1123 return RejectUser(
Entry.first,
1124 "mem transfer inst between different objects");
1125 AA.Vector.Worklist.push_back(
Entry.first);
1129void AMDGPUPromoteAllocaImpl::promoteAllocaToVector(AllocaAnalysis &
AA) {
1131 LLVM_DEBUG(
dbgs() <<
" type conversion: " << *
AA.Alloca->getAllocatedType()
1132 <<
" -> " << *
AA.Vector.Ty <<
'\n');
1133 const unsigned VecStoreSize =
DL.getTypeStoreSize(
AA.Vector.Ty);
1135 Type *VecEltTy =
AA.Vector.Ty->getElementType();
1136 const unsigned ElementSize =
DL.getTypeSizeInBits(VecEltTy) / 8;
1158 BasicBlock *BB = I->getParent();
1159 auto GetCurVal = [&]() -> Value * {
1160 if (Value *CurVal = Updater.FindValueForBlock(BB))
1163 if (!Placeholders.empty() && Placeholders.back()->getParent() == BB)
1164 return Placeholders.back();
1168 IRBuilder<> Builder(I);
1169 auto *Placeholder = cast<Instruction>(Builder.CreateFreeze(
1170 PoisonValue::get(AA.Vector.Ty),
"promotealloca.placeholder"));
1171 Placeholders.insert(Placeholder);
1172 return Placeholders.back();
1176 ElementSize, GetCurVal);
1190 Placeholder->replaceAllUsesWith(
1192 Placeholder->eraseFromParent();
1198 I->eraseFromParent();
1203 I->dropDroppableUses();
1205 I->eraseFromParent();
1210 AA.Alloca->eraseFromParent();
1213std::pair<Value *, Value *>
1214AMDGPUPromoteAllocaImpl::getLocalSizeYZ(
IRBuilder<> &Builder) {
1220 Intrinsic::r600_read_local_size_y, {});
1222 Intrinsic::r600_read_local_size_z, {});
1224 ST.makeLIDRangeMetadata(LocalSizeY);
1225 ST.makeLIDRangeMetadata(LocalSizeZ);
1227 return std::pair(LocalSizeY, LocalSizeZ);
1268 F.removeFnAttr(
"amdgpu-no-dispatch-ptr");
1285 LoadXY->
setMetadata(LLVMContext::MD_invariant_load, MD);
1286 LoadZU->
setMetadata(LLVMContext::MD_invariant_load, MD);
1287 ST.makeLIDRangeMetadata(LoadZU);
1292 return std::pair(
Y, LoadZU);
1304 IntrID = IsAMDGCN ? (
Intrinsic::ID)Intrinsic::amdgcn_workitem_id_x
1306 AttrName =
"amdgpu-no-workitem-id-x";
1309 IntrID = IsAMDGCN ? (
Intrinsic::ID)Intrinsic::amdgcn_workitem_id_y
1311 AttrName =
"amdgpu-no-workitem-id-y";
1315 IntrID = IsAMDGCN ? (
Intrinsic::ID)Intrinsic::amdgcn_workitem_id_z
1317 AttrName =
"amdgpu-no-workitem-id-z";
1325 ST.makeLIDRangeMetadata(CI);
1326 F->removeFnAttr(AttrName);
1336 switch (
II->getIntrinsicID()) {
1337 case Intrinsic::memcpy:
1338 case Intrinsic::memmove:
1339 case Intrinsic::memset:
1340 case Intrinsic::lifetime_start:
1341 case Intrinsic::lifetime_end:
1342 case Intrinsic::invariant_start:
1343 case Intrinsic::invariant_end:
1344 case Intrinsic::launder_invariant_group:
1345 case Intrinsic::strip_invariant_group:
1346 case Intrinsic::objectsize:
1353bool AMDGPUPromoteAllocaImpl::binaryOpIsDerivedFromSameAlloca(
1375 if (OtherObj != BaseAlloca) {
1377 dbgs() <<
"Found a binary instruction with another alloca object\n");
1384void AMDGPUPromoteAllocaImpl::analyzePromoteToLDS(AllocaAnalysis &
AA)
const {
1385 if (DisablePromoteAllocaToLDS) {
1393 const Function &ContainingFunction = *
AA.Alloca->getFunction();
1403 <<
" promote alloca to LDS not supported with calling convention.\n");
1414 if (
find(
AA.LDS.Worklist,
User) ==
AA.LDS.Worklist.end())
1415 AA.LDS.Worklist.push_back(
User);
1420 if (UseInst->
getOpcode() == Instruction::PtrToInt)
1424 if (LI->isVolatile())
1430 if (
SI->isVolatile())
1436 if (RMW->isVolatile())
1442 if (CAS->isVolatile())
1450 if (!binaryOpIsDerivedFromSameAlloca(
AA.Alloca,
Use->get(), ICmp, 0, 1))
1454 if (
find(
AA.LDS.Worklist,
User) ==
AA.LDS.Worklist.end())
1455 AA.LDS.Worklist.push_back(ICmp);
1462 if (!
GEP->isInBounds())
1475 if (
find(
AA.LDS.Worklist,
User) ==
AA.LDS.Worklist.end())
1476 AA.LDS.Worklist.push_back(
User);
1479 AA.LDS.Enable =
true;
1482bool AMDGPUPromoteAllocaImpl::hasSufficientLocalMem(
const Function &
F) {
1490 for (
Type *ParamTy : FTy->params()) {
1494 LLVM_DEBUG(
dbgs() <<
"Function has local memory argument. Promoting to "
1495 "local memory disabled.\n");
1500 LocalMemLimit =
ST.getAddressableLocalMemorySize();
1501 if (LocalMemLimit == 0)
1511 if (
Use->getFunction() == &
F)
1515 if (VisitedConstants.
insert(
C).second)
1527 if (visitUsers(&GV, &GV)) {
1535 while (!
Stack.empty()) {
1537 if (visitUsers(&GV,
C)) {
1557 LLVM_DEBUG(
dbgs() <<
"Function has a reference to externally allocated "
1558 "local memory. Promoting to local memory "
1573 CurrentLocalMemUsage = 0;
1579 for (
auto Alloc : AllocatedSizes) {
1580 CurrentLocalMemUsage =
alignTo(CurrentLocalMemUsage,
Alloc.second);
1581 CurrentLocalMemUsage +=
Alloc.first;
1584 unsigned MaxOccupancy =
1585 ST.getWavesPerEU(
ST.getFlatWorkGroupSizes(
F), CurrentLocalMemUsage,
F)
1589 unsigned MaxSizeWithWaveCount =
1590 ST.getMaxLocalMemSizeWithWaveCount(MaxOccupancy,
F);
1593 if (CurrentLocalMemUsage > MaxSizeWithWaveCount)
1596 LocalMemLimit = MaxSizeWithWaveCount;
1599 <<
" bytes of LDS\n"
1600 <<
" Rounding size to " << MaxSizeWithWaveCount
1601 <<
" with a maximum occupancy of " << MaxOccupancy <<
'\n'
1602 <<
" and " << (LocalMemLimit - CurrentLocalMemUsage)
1603 <<
" available for promotion\n");
1609bool AMDGPUPromoteAllocaImpl::tryPromoteAllocaToLDS(
1610 AllocaAnalysis &
AA,
bool SufficientLDS,
1620 const Function &ContainingFunction = *
AA.Alloca->getParent()->getParent();
1622 unsigned WorkGroupSize =
ST.getFlatWorkGroupSizes(ContainingFunction).second;
1632 uint32_t NewSize =
alignTo(CurrentLocalMemUsage, Alignment);
1633 std::optional<TypeSize> ElemSize =
AA.Alloca->getAllocationSize(
DL);
1634 if (!ElemSize || ElemSize->isScalable())
1636 TypeSize AllocSize = WorkGroupSize * *ElemSize;
1639 if (NewSize > LocalMemLimit) {
1641 <<
" bytes of local memory not available to promote\n");
1645 CurrentLocalMemUsage = NewSize;
1654 Twine(
F->getName()) +
Twine(
'.') +
AA.Alloca->getName(),
nullptr,
1659 Value *TCntY, *TCntZ;
1661 std::tie(TCntY, TCntZ) = getLocalSizeYZ(Builder);
1662 Value *TIdX = getWorkitemID(Builder, 0);
1663 Value *TIdY = getWorkitemID(Builder, 1);
1664 Value *TIdZ = getWorkitemID(Builder, 2);
1676 AA.Alloca->mutateType(
Offset->getType());
1677 AA.Alloca->replaceAllUsesWith(
Offset);
1678 AA.Alloca->eraseFromParent();
1682 for (
Value *V :
AA.LDS.Worklist) {
1704 assert(
V->getType()->isPtrOrPtrVectorTy());
1706 Type *NewTy =
V->getType()->getWithNewType(NewPtrTy);
1707 V->mutateType(NewTy);
1717 for (
unsigned I = 0,
E =
Phi->getNumIncomingValues();
I !=
E; ++
I) {
1719 Phi->getIncomingValue(
I)))
1730 case Intrinsic::lifetime_start:
1731 case Intrinsic::lifetime_end:
1735 case Intrinsic::memcpy:
1736 case Intrinsic::memmove:
1740 DeferredIntrs.
insert(Intr);
1742 case Intrinsic::memset: {
1750 case Intrinsic::invariant_start:
1751 case Intrinsic::invariant_end:
1752 case Intrinsic::launder_invariant_group:
1753 case Intrinsic::strip_invariant_group: {
1755 "pointer operand should already have been promoted");
1762 case Intrinsic::objectsize: {
1766 Intrinsic::objectsize,
1782void AMDGPUPromoteAllocaImpl::finishDeferredAllocaToLDSPromotion(
1789 assert(ID == Intrinsic::memcpy || ID == Intrinsic::memmove);
1793 ID,
MI->getRawDest(),
MI->getDestAlign(),
MI->getRawSource(),
1794 MI->getSourceAlign(),
MI->getLength(),
MI->isVolatile());
1796 for (
unsigned I = 0;
I != 2; ++
I) {
1798 B->addDereferenceableParamAttr(
I, Bytes);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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.
LLVMContext & getContext() const
All values hold a context through their type.
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
#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)
initializer< Ty > init(const Ty &Val)
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.
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 void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=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...
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.
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.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
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:...